From 73782055237ee8948b26935348e8ca2b8a71a95a Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Tue, 10 Sep 2019 21:57:06 +0300 Subject: [PATCH 001/268] Expand .apng and .webp support for get_image_suffix Add get_image_suffix for all .gif's so that all animated pieces can be .webp or .apng instead Expand on .webp .apng support and clean up the code somewhat --- include/aoapplication.h | 2 +- src/aocharmovie.cpp | 11 ++++----- src/aomovie.cpp | 14 ++++++------ src/aoscene.cpp | 45 ++++++++++++++++++++++++------------- src/courtroom.cpp | 11 ++++++--- src/text_file_functions.cpp | 5 +++-- 6 files changed, 52 insertions(+), 36 deletions(-) diff --git a/include/aoapplication.h b/include/aoapplication.h index 5475eb7..68e82ce 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -219,7 +219,7 @@ public: //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, fall back to a gif. + // Can we use APNG for this? If not, WEBP? If not, fall back to gif. QString get_image_suffix(QString path_to_check); //Returns the value of p_search_line within target_tag and terminator_tag diff --git a/src/aocharmovie.cpp b/src/aocharmovie.cpp index 5748723..eacf853 100644 --- a/src/aocharmovie.cpp +++ b/src/aocharmovie.cpp @@ -19,16 +19,13 @@ AOCharMovie::AOCharMovie(QWidget *p_parent, AOApplication *p_ao_app) : QLabel(p_ void AOCharMovie::play(QString p_char, QString p_emote, QString emote_prefix) { - QString original_path = ao_app->get_character_path(p_char, emote_prefix + p_emote + ".gif"); + QString original_path = ao_app->get_image_suffix(ao_app->get_character_path(p_char, emote_prefix + p_emote)); QString alt_path = ao_app->get_character_path(p_char, p_emote + ".png"); - QString apng_path = ao_app->get_character_path(p_char, emote_prefix + p_emote + ".apng"); - QString placeholder_path = ao_app->get_theme_path("placeholder.gif"); - QString placeholder_default_path = ao_app->get_default_theme_path("placeholder.gif"); + QString placeholder_path = ao_app->get_image_suffix(ao_app->get_theme_path("placeholder")); + QString placeholder_default_path = ao_app->get_image_suffix(ao_app->get_default_theme_path("placeholder")); QString gif_path; - if (file_exists(apng_path)) - gif_path = apng_path; - else if (file_exists(original_path)) + if (file_exists(original_path)) gif_path = original_path; else if (file_exists(alt_path)) gif_path = alt_path; diff --git a/src/aomovie.cpp b/src/aomovie.cpp index edf5bdb..71a5a76 100644 --- a/src/aomovie.cpp +++ b/src/aomovie.cpp @@ -32,12 +32,12 @@ void AOMovie::play(QString p_gif, QString p_char, QString p_custom_theme) else custom_path = ao_app->get_image_suffix(ao_app->get_character_path(p_char, p_gif + "_bubble")); - QString misc_path = ao_app->get_base_path() + "misc/" + p_custom_theme + "/" + p_gif + "_bubble.gif"; - QString custom_theme_path = ao_app->get_custom_theme_path(p_custom_theme, p_gif + ".gif"); - QString theme_path = ao_app->get_theme_path(p_gif + ".gif"); - QString default_theme_path = ao_app->get_default_theme_path(p_gif + ".gif"); - QString placeholder_path = ao_app->get_theme_path("placeholder.gif"); - QString default_placeholder_path = ao_app->get_default_theme_path("placeholder.gif"); + QString misc_path = ao_app->get_image_suffix(ao_app->get_base_path() + "misc/" + p_custom_theme + "/" + p_gif + "_bubble"); + QString custom_theme_path = ao_app->get_image_suffix(ao_app->get_custom_theme_path(p_custom_theme, p_gif)); + QString theme_path = ao_app->get_image_suffix(ao_app->get_theme_path(p_gif)); + QString default_theme_path = ao_app->get_image_suffix(ao_app->get_default_theme_path(p_gif)); + QString placeholder_path = ao_app->get_image_suffix(ao_app->get_theme_path("placeholder")); + QString default_placeholder_path =ao_app->get_image_suffix( ao_app->get_default_theme_path("placeholder")); if (file_exists(custom_path)) gif_path = custom_path; @@ -70,7 +70,7 @@ void AOMovie::stop() void AOMovie::frame_change(int n_frame) { - if (n_frame == (m_movie->frameCount() - 1) && play_once) + if (n_frame >= (m_movie->frameCount() - 1) && play_once) { //we need this or else the last frame wont show delay(m_movie->nextFrameDelay()); diff --git a/src/aoscene.cpp b/src/aoscene.cpp index 344522b..6d2dc89 100644 --- a/src/aoscene.cpp +++ b/src/aoscene.cpp @@ -12,8 +12,8 @@ AOScene::AOScene(QWidget *parent, AOApplication *p_ao_app) : QLabel(parent) void AOScene::set_image(QString p_image) { QString background_path = ao_app->get_background_path(p_image + ".png"); - QString animated_background_path = ao_app->get_background_path(p_image + ".gif"); QString default_path = ao_app->get_default_background_path(p_image + ".png"); + QString animated_background_path = ao_app->get_image_suffix(ao_app->get_background_path(p_image)); QPixmap background(background_path); QPixmap default_bg(default_path); @@ -34,13 +34,9 @@ void AOScene::set_image(QString p_image) m_movie->start(); } else if (file_exists(background_path)) - { this->setPixmap(background.scaled(w, h)); - } else - { this->setPixmap(default_bg.scaled(w, h)); - } } void AOScene::set_legacy_desk(QString p_image) @@ -48,16 +44,12 @@ void AOScene::set_legacy_desk(QString p_image) //vanilla desks vary in both width and height. in order to make that work with viewport rescaling, //some INTENSE math is needed. - QString desk_path = ao_app->get_background_path(p_image); - QString default_path = ao_app->get_default_background_path(p_image); + QString desk_path = ao_app->get_background_path(p_image + ".png"); + QString animated_desk_path = ao_app->get_image_suffix(ao_app->get_background_path(p_image)); + QString default_path = ao_app->get_image_suffix(ao_app->get_default_background_path(p_image)); QPixmap f_desk; - if (file_exists(desk_path)) - f_desk.load(desk_path); - else - f_desk.load(default_path); - int vp_width = m_parent->width(); int vp_height = m_parent->height(); @@ -69,8 +61,29 @@ void AOScene::set_legacy_desk(QString p_image) //int final_w = w_modifier * f_desk.width(); int final_h = static_cast(h_modifier * f_desk.height()); - //this->resize(final_w, final_h); - //this->setPixmap(f_desk.scaled(final_w, final_h)); - this->resize(vp_width, final_h); - this->setPixmap(f_desk.scaled(vp_width, final_h)); + this->clear(); + this->setMovie(nullptr); + + m_movie->stop(); + m_movie->setFileName(animated_desk_path); + + m_movie->setScaledSize(QSize(vp_width, vp_height)); + + if (m_movie->isValid()) + { + this->setMovie(m_movie); + m_movie->start(); + } + else + { + if (file_exists(desk_path)) + f_desk.load(desk_path); + else + f_desk.load(default_path); + + //this->resize(final_w, final_h); + //this->setPixmap(f_desk.scaled(final_w, final_h)); + this->resize(vp_width, final_h); + this->setPixmap(f_desk.scaled(vp_width, final_h)); + } } diff --git a/src/courtroom.cpp b/src/courtroom.cpp index a171416..cc69a1e 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -909,7 +909,8 @@ void Courtroom::enter_courtroom(int p_cid) if (ao_app->custom_objection_enabled && (file_exists(ao_app->get_character_path(current_char, "custom.gif")) || - file_exists(ao_app->get_character_path(current_char, "custom.apng"))) && + file_exists(ao_app->get_character_path(current_char, "custom.apng")) || + file_exists(ao_app->get_character_path(current_char, "custom.webp"))) && file_exists(ao_app->get_character_path(current_char, "custom.wav"))) ui_custom_objection->show(); else @@ -2409,13 +2410,17 @@ void Courtroom::set_scene() f_desk_image = "prohelperdesk"; } else if (f_side == "jur" && (file_exists(ao_app->get_background_path("jurystand.png")) || - file_exists(ao_app->get_background_path("jurystand.gif")))) + file_exists(ao_app->get_background_path("jurystand.gif")) || + file_exists(ao_app->get_background_path("jurystand.apng")) || + file_exists(ao_app->get_background_path("jurystand.webp")))) { f_background = "jurystand"; f_desk_image = "jurydesk"; } else if (f_side == "sea" && (file_exists(ao_app->get_background_path("seancestand.png")) || - file_exists(ao_app->get_background_path("seancestand.gif")))) + file_exists(ao_app->get_background_path("seancestand.gif")) || + file_exists(ao_app->get_background_path("seancestand.apng")) || + file_exists(ao_app->get_background_path("seancestand.webp")))) { f_background = "seancestand"; f_desk_image = "seancedesk"; diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index 5a34ac8..904e212 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -385,11 +385,12 @@ QString AOApplication::get_sfx_suffix(QString sound_to_check) QString AOApplication::get_image_suffix(QString path_to_check) { + QString webp_check = path_to_check + ".webp"; QString apng_check = path_to_check + ".apng"; + if (file_exists(webp_check)) + return webp_check; if (file_exists(apng_check)) - { return apng_check; - } return path_to_check + ".gif"; } From 7e2ec58c7eb62077733f354764d0b729fe0e0a93 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Tue, 10 Sep 2019 23:26:03 +0300 Subject: [PATCH 002/268] Prevent the animated background/foreground from restarting itself if the image is the exact same as the currently playing one --- include/aoscene.h | 1 + src/aoscene.cpp | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/include/aoscene.h b/include/aoscene.h index b58c0fd..ddbefe0 100644 --- a/include/aoscene.h +++ b/include/aoscene.h @@ -21,6 +21,7 @@ private: QWidget *m_parent; QMovie *m_movie; AOApplication *ao_app; + QString last_image; }; diff --git a/src/aoscene.cpp b/src/aoscene.cpp index 6d2dc89..0f4e745 100644 --- a/src/aoscene.cpp +++ b/src/aoscene.cpp @@ -7,6 +7,7 @@ AOScene::AOScene(QWidget *parent, AOApplication *p_ao_app) : QLabel(parent) m_parent = parent; ao_app = p_ao_app; m_movie = new QMovie(this); + last_image = ""; } void AOScene::set_image(QString p_image) @@ -15,6 +16,9 @@ void AOScene::set_image(QString p_image) QString default_path = ao_app->get_default_background_path(p_image + ".png"); QString animated_background_path = ao_app->get_image_suffix(ao_app->get_background_path(p_image)); + if (file_exists(animated_background_path) && animated_background_path == last_image) + return; + QPixmap background(background_path); QPixmap default_bg(default_path); @@ -32,11 +36,16 @@ void AOScene::set_image(QString p_image) { this->setMovie(m_movie); m_movie->start(); + last_image = animated_background_path; } else if (file_exists(background_path)) + { this->setPixmap(background.scaled(w, h)); + } else + { this->setPixmap(default_bg.scaled(w, h)); + } } void AOScene::set_legacy_desk(QString p_image) @@ -48,6 +57,9 @@ void AOScene::set_legacy_desk(QString p_image) QString animated_desk_path = ao_app->get_image_suffix(ao_app->get_background_path(p_image)); QString default_path = ao_app->get_image_suffix(ao_app->get_default_background_path(p_image)); + if (file_exists(animated_desk_path) && animated_desk_path == last_image) + return; + QPixmap f_desk; int vp_width = m_parent->width(); @@ -73,6 +85,7 @@ void AOScene::set_legacy_desk(QString p_image) { this->setMovie(m_movie); m_movie->start(); + last_image = animated_desk_path; } else { From 3b415f5a7005fd0b42ba7ccbb9a8836746a72d41 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Thu, 12 Sep 2019 15:40:19 +0300 Subject: [PATCH 003/268] Expand get_image_suffix to fall back on .png last Reorganize the file_exists checks to be an array iterator instead for much less code duplication and easier ordering of priority Reorganize desk and set_image loading on AOScene class, resolve issues with last_image setting to prevent animations from being restarted when characters talk on the same pos in succession Apply get_image_suffix for seancestand and jurystand searches TODO: At the moment, if you feed a .png shout, it will send the "Done" signal on the first frame (frame 0), not showing you the .png image at all. The shout code should be reorganized to allow static images to be displayed for exactly 720ms - the standard AA objection length. Usage of the timer similarly to the realizationflash.png might be possible. --- include/aoapplication.h | 2 +- src/aocharmovie.cpp | 31 +++++++++++----------- src/aomovie.cpp | 47 +++++++++++++------------------- src/aoscene.cpp | 53 +++++++++++++------------------------ src/courtroom.cpp | 18 ++++--------- src/text_file_functions.cpp | 14 +++++----- 6 files changed, 66 insertions(+), 99 deletions(-) diff --git a/include/aoapplication.h b/include/aoapplication.h index 68e82ce..19924e4 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -219,7 +219,7 @@ public: //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, fall back to gif. + // 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); //Returns the value of p_search_line within target_tag and terminator_tag diff --git a/src/aocharmovie.cpp b/src/aocharmovie.cpp index eacf853..883530b 100644 --- a/src/aocharmovie.cpp +++ b/src/aocharmovie.cpp @@ -19,25 +19,26 @@ AOCharMovie::AOCharMovie(QWidget *p_parent, AOApplication *p_ao_app) : QLabel(p_ void AOCharMovie::play(QString p_char, QString p_emote, QString emote_prefix) { - QString original_path = ao_app->get_image_suffix(ao_app->get_character_path(p_char, emote_prefix + p_emote)); - QString alt_path = ao_app->get_character_path(p_char, p_emote + ".png"); - QString placeholder_path = ao_app->get_image_suffix(ao_app->get_theme_path("placeholder")); - QString placeholder_default_path = ao_app->get_image_suffix(ao_app->get_default_theme_path("placeholder")); - QString gif_path; + QString emote_path; + QList pathlist; + pathlist << ao_app->get_image_suffix(ao_app->get_character_path(p_char, emote_prefix + p_emote)) <get_character_path(p_char, p_emote + ".png") << //Non-animated path if emote_prefix fails + 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 - if (file_exists(original_path)) - gif_path = original_path; - else if (file_exists(alt_path)) - gif_path = alt_path; - else if (file_exists(placeholder_path)) - gif_path = placeholder_path; - else - gif_path = placeholder_default_path; + for (QString path : pathlist) + { + if (file_exists(path)) + { + emote_path = path; + break; + } + } m_movie->stop(); - m_movie->setFileName(gif_path); + m_movie->setFileName(emote_path); - QImageReader *reader = new QImageReader(gif_path); + QImageReader *reader = new QImageReader(emote_path); movie_frames.clear(); QImage f_image = reader->read(); diff --git a/src/aomovie.cpp b/src/aomovie.cpp index 71a5a76..a378a3d 100644 --- a/src/aomovie.cpp +++ b/src/aomovie.cpp @@ -24,39 +24,30 @@ void AOMovie::play(QString p_gif, QString p_char, QString p_custom_theme) { m_movie->stop(); - QString gif_path; - - QString custom_path; + QString shout_path; + QList pathlist; if (p_gif == "custom") - custom_path = ao_app->get_image_suffix(ao_app->get_character_path(p_char, p_gif)); + pathlist << ao_app->get_image_suffix(ao_app->get_character_path(p_char, p_gif)); else - custom_path = ao_app->get_image_suffix(ao_app->get_character_path(p_char, p_gif + "_bubble")); + pathlist << ao_app->get_image_suffix(ao_app->get_character_path(p_char, p_gif + "_bubble")); - QString misc_path = ao_app->get_image_suffix(ao_app->get_base_path() + "misc/" + p_custom_theme + "/" + p_gif + "_bubble"); - QString custom_theme_path = ao_app->get_image_suffix(ao_app->get_custom_theme_path(p_custom_theme, p_gif)); - QString theme_path = ao_app->get_image_suffix(ao_app->get_theme_path(p_gif)); - QString default_theme_path = ao_app->get_image_suffix(ao_app->get_default_theme_path(p_gif)); - QString placeholder_path = ao_app->get_image_suffix(ao_app->get_theme_path("placeholder")); - QString default_placeholder_path =ao_app->get_image_suffix( ao_app->get_default_theme_path("placeholder")); + pathlist << ao_app->get_image_suffix(ao_app->get_base_path() + "misc/" + p_custom_theme + "/" + p_gif + "_bubble") << //Misc path + ao_app->get_image_suffix(ao_app->get_custom_theme_path(p_custom_theme, p_gif)) << //Custom theme path + ao_app->get_image_suffix(ao_app->get_theme_path(p_gif)) << //Theme path + ao_app->get_image_suffix(ao_app->get_default_theme_path(p_gif)) << //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 - if (file_exists(custom_path)) - gif_path = custom_path; - else if (file_exists(misc_path)) - gif_path = misc_path; - else if (file_exists(custom_theme_path)) - gif_path = custom_theme_path; - else if (file_exists(theme_path)) - gif_path = theme_path; - else if (file_exists(default_theme_path)) - gif_path = default_theme_path; - else if (file_exists(placeholder_path)) - gif_path = placeholder_path; - else if (file_exists(default_placeholder_path)) - gif_path = default_placeholder_path; - else - gif_path = ""; + for (QString path : pathlist) + { + if (file_exists(path)) + { + shout_path = path; + break; + } + } - m_movie->setFileName(gif_path); + m_movie->setFileName(shout_path); this->show(); m_movie->start(); diff --git a/src/aoscene.cpp b/src/aoscene.cpp index 0f4e745..c931425 100644 --- a/src/aoscene.cpp +++ b/src/aoscene.cpp @@ -12,16 +12,13 @@ AOScene::AOScene(QWidget *parent, AOApplication *p_ao_app) : QLabel(parent) void AOScene::set_image(QString p_image) { - QString background_path = ao_app->get_background_path(p_image + ".png"); - QString default_path = ao_app->get_default_background_path(p_image + ".png"); - QString animated_background_path = ao_app->get_image_suffix(ao_app->get_background_path(p_image)); + QString background_path = ao_app->get_image_suffix(ao_app->get_background_path(p_image)); + if (!file_exists(background_path)) + background_path = ao_app->get_image_suffix(ao_app->get_default_background_path(p_image)); //Default path - if (file_exists(animated_background_path) && animated_background_path == last_image) + if (file_exists(background_path) && background_path == last_image) return; - QPixmap background(background_path); - QPixmap default_bg(default_path); - int w = this->width(); int h = this->height(); @@ -29,74 +26,60 @@ void AOScene::set_image(QString p_image) this->setMovie(nullptr); m_movie->stop(); - m_movie->setFileName(animated_background_path); + m_movie->setFileName(background_path); m_movie->setScaledSize(QSize(w, h)); if (m_movie->isValid()) { this->setMovie(m_movie); m_movie->start(); - last_image = animated_background_path; - } - else if (file_exists(background_path)) - { - this->setPixmap(background.scaled(w, h)); } else { - this->setPixmap(default_bg.scaled(w, h)); + QPixmap background(background_path); + this->setPixmap(background.scaled(w, h)); } + last_image = background_path; } void AOScene::set_legacy_desk(QString p_image) { - //vanilla desks vary in both width and height. in order to make that work with viewport rescaling, - //some INTENSE math is needed. - QString desk_path = ao_app->get_background_path(p_image + ".png"); - QString animated_desk_path = ao_app->get_image_suffix(ao_app->get_background_path(p_image)); - QString default_path = ao_app->get_image_suffix(ao_app->get_default_background_path(p_image)); + QString desk_path = ao_app->get_image_suffix(ao_app->get_background_path(p_image)); + if (!file_exists(desk_path)) + desk_path = ao_app->get_image_suffix(ao_app->get_default_background_path(p_image)); //Default path - if (file_exists(animated_desk_path) && animated_desk_path == last_image) + if (file_exists(desk_path) && desk_path == last_image) return; - QPixmap f_desk; + QPixmap f_desk(desk_path); + //vanilla desks vary in both width and height. in order to make that work with viewport rescaling, + //some INTENSE math is needed. int vp_width = m_parent->width(); int vp_height = m_parent->height(); - //double y_modifier = 147 / 192; - //double w_modifier = vp_width / 256; double h_modifier = vp_height / 192; - //int final_y = y_modifier * vp_height; - //int final_w = w_modifier * f_desk.width(); int final_h = static_cast(h_modifier * f_desk.height()); this->clear(); this->setMovie(nullptr); m_movie->stop(); - m_movie->setFileName(animated_desk_path); + m_movie->setFileName(desk_path); - m_movie->setScaledSize(QSize(vp_width, vp_height)); + m_movie->setScaledSize(QSize(vp_width, final_h)); if (m_movie->isValid()) { this->setMovie(m_movie); m_movie->start(); - last_image = animated_desk_path; } else { - if (file_exists(desk_path)) - f_desk.load(desk_path); - else - f_desk.load(default_path); - - //this->resize(final_w, final_h); - //this->setPixmap(f_desk.scaled(final_w, final_h)); this->resize(vp_width, final_h); this->setPixmap(f_desk.scaled(vp_width, final_h)); } + last_image = desk_path; } diff --git a/src/courtroom.cpp b/src/courtroom.cpp index cc69a1e..cc4410d 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -908,10 +908,8 @@ void Courtroom::enter_courtroom(int p_cid) } if (ao_app->custom_objection_enabled && - (file_exists(ao_app->get_character_path(current_char, "custom.gif")) || - file_exists(ao_app->get_character_path(current_char, "custom.apng")) || - file_exists(ao_app->get_character_path(current_char, "custom.webp"))) && - file_exists(ao_app->get_character_path(current_char, "custom.wav"))) + (file_exists(ao_app->get_image_suffix(ao_app->get_character_path(current_char, "custom"))) && + file_exists(ao_app->get_character_path(current_char, "custom.wav")))) ui_custom_objection->show(); else ui_custom_objection->hide(); @@ -2378,6 +2376,7 @@ void Courtroom::set_scene() QString f_desk_mod = m_chatmessage[DESK_MOD]; QString f_side = m_chatmessage[SIDE]; + //This thing desperately needs to be made into an array iteration. if (f_side == "def") { f_background = "defenseempty"; @@ -2409,18 +2408,12 @@ void Courtroom::set_scene() f_background = "prohelperstand"; f_desk_image = "prohelperdesk"; } - else if (f_side == "jur" && (file_exists(ao_app->get_background_path("jurystand.png")) || - file_exists(ao_app->get_background_path("jurystand.gif")) || - file_exists(ao_app->get_background_path("jurystand.apng")) || - file_exists(ao_app->get_background_path("jurystand.webp")))) + else if (f_side == "jur" && (file_exists(ao_app->get_image_suffix(ao_app->get_background_path("jurystand"))))) { f_background = "jurystand"; f_desk_image = "jurydesk"; } - else if (f_side == "sea" && (file_exists(ao_app->get_background_path("seancestand.png")) || - file_exists(ao_app->get_background_path("seancestand.gif")) || - file_exists(ao_app->get_background_path("seancestand.apng")) || - file_exists(ao_app->get_background_path("seancestand.webp")))) + else if (f_side == "sea" && (file_exists(ao_app->get_image_suffix(ao_app->get_background_path("seancestand"))))) { f_background = "seancestand"; f_desk_image = "seancedesk"; @@ -2436,7 +2429,6 @@ void Courtroom::set_scene() ui_vp_background->set_image(f_background); ui_vp_desk->set_image(f_desk_image); ui_vp_legacy_desk->set_legacy_desk(f_desk_image); - if (f_desk_mod == "0" || (f_desk_mod != "1" && (f_side == "jud" || f_side == "hld" || diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index 904e212..afe7a67 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -385,13 +385,13 @@ QString AOApplication::get_sfx_suffix(QString sound_to_check) QString AOApplication::get_image_suffix(QString path_to_check) { - QString webp_check = path_to_check + ".webp"; - QString apng_check = path_to_check + ".apng"; - if (file_exists(webp_check)) - return webp_check; - if (file_exists(apng_check)) - return apng_check; - return path_to_check + ".gif"; + 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"; } From 2a899b14762be4084e4cd65e42918c1f43f5e4da Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Thu, 12 Sep 2019 18:28:08 +0300 Subject: [PATCH 004/268] Allow AOMovie to have timers that take priority over the animated image frame count Set it up so feeding the timer value when playing the AOMovie would use the timer but only in cases where a non-animated image is used Update shouts and wtce to pass the 'duration' argument which will be used if the image used is non-animated. Otherwise, prioritize the animated image duration. --- include/aomovie.h | 5 ++++- src/aomovie.cpp | 36 +++++++++++++++++++++++++++--------- src/courtroom.cpp | 16 ++++++++-------- 3 files changed, 39 insertions(+), 18 deletions(-) diff --git a/include/aomovie.h b/include/aomovie.h index 1f278bf..33b3158 100644 --- a/include/aomovie.h +++ b/include/aomovie.h @@ -15,13 +15,15 @@ public: AOMovie(QWidget *p_parent, AOApplication *p_ao_app); void set_play_once(bool p_play_once); - void play(QString p_gif, QString p_char = "", QString p_custom_theme = ""); + void start_timer(int delay); + void play(QString p_gif, QString p_char = "", QString p_custom_theme = "", int duration = 0); void combo_resize(int w, int h); void stop(); private: QMovie *m_movie; AOApplication *ao_app; + QTimer *timer; bool play_once = true; signals: @@ -29,6 +31,7 @@ signals: private slots: void frame_change(int n_frame); + void timer_done(); }; #endif // AOMOVIE_H diff --git a/src/aomovie.cpp b/src/aomovie.cpp index a378a3d..2598bb7 100644 --- a/src/aomovie.cpp +++ b/src/aomovie.cpp @@ -12,7 +12,11 @@ AOMovie::AOMovie(QWidget *p_parent, AOApplication *p_ao_app) : QLabel(p_parent) this->setMovie(m_movie); + timer = new QTimer(this); + timer->setSingleShot(true); + connect(m_movie, SIGNAL(frameChanged(int)), this, SLOT(frame_change(int))); + connect(timer, SIGNAL(timeout()), this, SLOT(timer_done())); } void AOMovie::set_play_once(bool p_play_once) @@ -20,7 +24,12 @@ void AOMovie::set_play_once(bool p_play_once) play_once = p_play_once; } -void AOMovie::play(QString p_gif, QString p_char, QString p_custom_theme) +void AOMovie::start_timer(int delay) +{ + timer->start(delay); +} + +void AOMovie::play(QString p_gif, QString p_char, QString p_custom_theme, int duration) { m_movie->stop(); @@ -51,6 +60,8 @@ void AOMovie::play(QString p_gif, QString p_char, QString p_custom_theme) this->show(); m_movie->start(); + if (m_movie->frameCount() == 0 && duration > 0) + this->start_timer(duration); } void AOMovie::stop() @@ -61,16 +72,23 @@ void AOMovie::stop() void AOMovie::frame_change(int n_frame) { - if (n_frame >= (m_movie->frameCount() - 1) && play_once) - { - //we need this or else the last frame wont show - delay(m_movie->nextFrameDelay()); + //If it's a "static movie" (only one frame - png image), we can't change frames - ignore this function (use timer instead). + //If the frame didn't reach the last frame or the movie is continuous, don't stop the movie. + if (m_movie->frameCount() == 0 || n_frame < (m_movie->frameCount() - 1) || !play_once) + return; + //we need this or else the last frame wont show + delay(m_movie->nextFrameDelay()); - this->stop(); + this->stop(); - //signal connected to courtroom object, let it figure out what to do - done(); - } + //signal connected to courtroom object, let it figure out what to do + done(); +} + +void AOMovie::timer_done() +{ + this->stop(); + done(); } void AOMovie::combo_resize(int w, int h) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index cc4410d..50ba2db 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1349,20 +1349,20 @@ void Courtroom::handle_chatmessage(QStringList *p_contents) switch (objection_mod) { case 1: - ui_vp_objection->play("holdit", f_char, f_custom_theme); + ui_vp_objection->play("holdit", f_char, f_custom_theme, 724); objection_player->play("holdit.wav", f_char, f_custom_theme); break; case 2: - ui_vp_objection->play("objection", f_char, f_custom_theme); + ui_vp_objection->play("objection", f_char, f_custom_theme, 724); objection_player->play("objection.wav", f_char, f_custom_theme); break; case 3: - ui_vp_objection->play("takethat", f_char, f_custom_theme); + ui_vp_objection->play("takethat", f_char, f_custom_theme, 724); objection_player->play("takethat.wav", f_char, f_custom_theme); break; //case 4 is AO2 only case 4: - ui_vp_objection->play("custom", f_char, f_custom_theme); + ui_vp_objection->play("custom", f_char, f_custom_theme, 724); objection_player->play("custom.wav", f_char, f_custom_theme); break; default: @@ -2571,7 +2571,7 @@ void Courtroom::handle_wtce(QString p_wtce, int variant) if (p_wtce == "testimony1") { sfx_player->play(ao_app->get_sfx("witness_testimony")); - ui_vp_wtce->play("witnesstestimony"); + ui_vp_wtce->play("witnesstestimony", "", "", 1500); testimony_in_progress = true; show_testimony(); } @@ -2579,7 +2579,7 @@ void Courtroom::handle_wtce(QString p_wtce, int variant) else if (p_wtce == "testimony2") { sfx_player->play(ao_app->get_sfx("cross_examination")); - ui_vp_wtce->play("crossexamination"); + ui_vp_wtce->play("crossexamination", "", "", 1500); testimony_in_progress = false; } else if (p_wtce == "judgeruling") @@ -2587,12 +2587,12 @@ void Courtroom::handle_wtce(QString p_wtce, int variant) if (variant == 0) { sfx_player->play(ao_app->get_sfx("not_guilty")); - ui_vp_wtce->play("notguilty"); + ui_vp_wtce->play("notguilty", "", "", 3000); testimony_in_progress = false; } else if (variant == 1) { sfx_player->play(ao_app->get_sfx("guilty")); - ui_vp_wtce->play("guilty"); + ui_vp_wtce->play("guilty", "", "", 3000); testimony_in_progress = false; } } From 932f430b683dffb0b965c32cd2247e2b6361dd0e Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Thu, 12 Sep 2019 19:03:42 +0300 Subject: [PATCH 005/268] Remove unecessary hard-coded timers for the witness testimony .png Make the witness testimony use AOMovie instead of AOImage Remove pointless "testimony_in_progress" variable CONTROVERSIAL: Make the witness testimony indicator be position-ignorant so as to reduce the amount of hardcoding and allow broader usage of the witness testimony system (For example, Danganronpa investigation indicator, etc.) - This should not affect how the testimony indicator is received currently, as witness testimony usually requires the entire rest of the court to shut up until the cross-examination either way. --- include/courtroom.h | 15 +------------ src/courtroom.cpp | 54 ++++++++------------------------------------- 2 files changed, 10 insertions(+), 59 deletions(-) diff --git a/include/courtroom.h b/include/courtroom.h index f0b6996..e053e23 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -309,11 +309,6 @@ private: //keeps track of how long realization is visible(it's just a white square and should be visible less than a second) QTimer *realization_timer; - //times how long the blinking testimony should be shown(green one in the corner) - QTimer *testimony_show_timer; - //times how long the blinking testimony should be hidden - QTimer *testimony_hide_timer; - //every time point in char.inis times this equals the final time const int time_mod = 40; @@ -323,14 +318,6 @@ private: QString previous_ic_message = ""; - bool testimony_in_progress = false; - - //in milliseconds - const int testimony_show_time = 1500; - - //in milliseconds - const int testimony_hide_time = 500; - //char id, muted or not QMap mute_map; @@ -407,8 +394,8 @@ private: AOImage *ui_vp_chatbox; QLabel *ui_vp_showname; QTextEdit *ui_vp_message; - AOImage *ui_vp_testimony; AOImage *ui_vp_realization; + AOMovie *ui_vp_testimony; AOMovie *ui_vp_wtce; AOMovie *ui_vp_objection; diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 50ba2db..4c42b9a 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -58,12 +58,6 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() realization_timer = new QTimer(this); realization_timer->setSingleShot(true); - testimony_show_timer = new QTimer(this); - testimony_show_timer->setSingleShot(true); - - testimony_hide_timer = new QTimer(this); - testimony_hide_timer->setSingleShot(true); - music_player = new AOMusicPlayer(this, ao_app); music_player->set_volume(0); @@ -101,7 +95,8 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_vp_message->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); ui_vp_message->setReadOnly(true); - ui_vp_testimony = new AOImage(this, ao_app); + ui_vp_testimony = new AOMovie(this, ao_app); + ui_vp_testimony->set_play_once(false); ui_vp_realization = new AOImage(this, ao_app); ui_vp_wtce = new AOMovie(this, ao_app); ui_vp_objection = new AOMovie(this, ao_app); @@ -280,9 +275,6 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() connect(realization_timer, SIGNAL(timeout()), this, SLOT(realization_done())); - connect(testimony_show_timer, SIGNAL(timeout()), this, SLOT(hide_testimony())); - connect(testimony_hide_timer, SIGNAL(timeout()), this, SLOT(show_testimony())); - connect(ui_emote_left, SIGNAL(clicked()), this, SLOT(on_emote_left_clicked())); connect(ui_emote_right, SIGNAL(clicked()), this, SLOT(on_emote_right_clicked())); @@ -492,9 +484,7 @@ void Courtroom::set_widgets() "color: white"); ui_vp_testimony->move(ui_viewport->x(), ui_viewport->y()); - ui_vp_testimony->resize(ui_viewport->width(), ui_viewport->height()); - ui_vp_testimony->set_image("testimony.png"); - ui_vp_testimony->hide(); + ui_vp_testimony->combo_resize(ui_viewport->width(), ui_viewport->height()); ui_vp_realization->move(ui_viewport->x(), ui_viewport->y()); ui_vp_realization->resize(ui_viewport->width(), ui_viewport->height()); @@ -824,8 +814,7 @@ void Courtroom::done_received() void Courtroom::set_background(QString p_background) { - testimony_in_progress = false; - + ui_vp_testimony->stop(); current_background = p_background; is_ao2_bg = file_exists(ao_app->get_background_path("defensedesk.png")) && @@ -932,7 +921,7 @@ void Courtroom::enter_courtroom(int p_cid) objection_player->set_volume(ui_sfx_slider->value()); blip_player->set_volume(ui_blip_slider->value()); - testimony_in_progress = false; + ui_vp_testimony->stop(); set_widgets(); @@ -2334,27 +2323,6 @@ void Courtroom::chat_tick() } } - -void Courtroom::show_testimony() -{ - if (!testimony_in_progress || m_chatmessage[SIDE] != "wit") - return; - - ui_vp_testimony->show(); - - testimony_show_timer->start(testimony_show_time); -} - -void Courtroom::hide_testimony() -{ - ui_vp_testimony->hide(); - - if (!testimony_in_progress) - return; - - testimony_hide_timer->start(testimony_hide_time); -} - void Courtroom::play_sfx() { QString sfx_name = m_chatmessage[SFX_NAME]; @@ -2367,9 +2335,6 @@ void Courtroom::play_sfx() void Courtroom::set_scene() { - if (testimony_in_progress) - show_testimony(); - //witness is default if pos is invalid QString f_background = "witnessempty"; QString f_desk_image = "stand"; @@ -2572,15 +2537,14 @@ void Courtroom::handle_wtce(QString p_wtce, int variant) { sfx_player->play(ao_app->get_sfx("witness_testimony")); ui_vp_wtce->play("witnesstestimony", "", "", 1500); - testimony_in_progress = true; - show_testimony(); + ui_vp_testimony->play("testimony"); } //cross examination else if (p_wtce == "testimony2") { sfx_player->play(ao_app->get_sfx("cross_examination")); ui_vp_wtce->play("crossexamination", "", "", 1500); - testimony_in_progress = false; + ui_vp_testimony->stop(); } else if (p_wtce == "judgeruling") { @@ -2588,12 +2552,12 @@ void Courtroom::handle_wtce(QString p_wtce, int variant) { sfx_player->play(ao_app->get_sfx("not_guilty")); ui_vp_wtce->play("notguilty", "", "", 3000); - testimony_in_progress = false; + ui_vp_testimony->stop(); } else if (variant == 1) { sfx_player->play(ao_app->get_sfx("guilty")); ui_vp_wtce->play("guilty", "", "", 3000); - testimony_in_progress = false; + ui_vp_testimony->stop(); } } } From bb98f79083648243216f665852a7d2326af11be0 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Thu, 12 Sep 2019 19:37:44 +0300 Subject: [PATCH 006/268] Fix compilation error Allow realization flashes to be animated images by making them AOMovies Eploit the newly added 'duration' system for realization AOMovie --- include/courtroom.h | 10 +--------- src/courtroom.cpp | 18 +++--------------- src/text_file_functions.cpp | 2 +- 3 files changed, 5 insertions(+), 25 deletions(-) diff --git a/include/courtroom.h b/include/courtroom.h index e053e23..fe870b4 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -306,9 +306,6 @@ private: //delay before sfx plays QTimer *sfx_delay_timer; - //keeps track of how long realization is visible(it's just a white square and should be visible less than a second) - QTimer *realization_timer; - //every time point in char.inis times this equals the final time const int time_mod = 40; @@ -394,7 +391,7 @@ private: AOImage *ui_vp_chatbox; QLabel *ui_vp_showname; QTextEdit *ui_vp_message; - AOImage *ui_vp_realization; + AOMovie *ui_vp_realization; AOMovie *ui_vp_testimony; AOMovie *ui_vp_wtce; AOMovie *ui_vp_objection; @@ -538,11 +535,6 @@ public slots: void objection_done(); void preanim_done(); - void realization_done(); - - void show_testimony(); - void hide_testimony(); - void mod_called(QString p_ip); void case_called(QString msg, bool def, bool pro, bool jud, bool jur, bool steno); diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 4c42b9a..0482687 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -55,9 +55,6 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() sfx_delay_timer = new QTimer(this); sfx_delay_timer->setSingleShot(true); - realization_timer = new QTimer(this); - realization_timer->setSingleShot(true); - music_player = new AOMusicPlayer(this, ao_app); music_player->set_volume(0); @@ -97,7 +94,7 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_vp_testimony = new AOMovie(this, ao_app); ui_vp_testimony->set_play_once(false); - ui_vp_realization = new AOImage(this, ao_app); + ui_vp_realization = new AOMovie(this, ao_app); ui_vp_wtce = new AOMovie(this, ao_app); ui_vp_objection = new AOMovie(this, ao_app); @@ -273,8 +270,6 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() connect(chat_tick_timer, SIGNAL(timeout()), this, SLOT(chat_tick())); - connect(realization_timer, SIGNAL(timeout()), this, SLOT(realization_done())); - connect(ui_emote_left, SIGNAL(clicked()), this, SLOT(on_emote_left_clicked())); connect(ui_emote_right, SIGNAL(clicked()), this, SLOT(on_emote_right_clicked())); @@ -487,9 +482,7 @@ void Courtroom::set_widgets() ui_vp_testimony->combo_resize(ui_viewport->width(), ui_viewport->height()); ui_vp_realization->move(ui_viewport->x(), ui_viewport->y()); - ui_vp_realization->resize(ui_viewport->width(), ui_viewport->height()); - ui_vp_realization->set_image("realizationflash.png"); - ui_vp_realization->hide(); + ui_vp_realization->combo_resize(ui_viewport->width(), ui_viewport->height()); ui_vp_wtce->move(ui_viewport->x(), ui_viewport->y()); ui_vp_wtce->combo_resize(ui_viewport->width(), ui_viewport->height()); @@ -1971,10 +1964,6 @@ void Courtroom::preanim_done() handle_chatmessage_3(); } -void Courtroom::realization_done() -{ - ui_vp_realization->hide(); -} void Courtroom::start_chat_ticking() { @@ -1984,8 +1973,7 @@ void Courtroom::start_chat_ticking() if (m_chatmessage[REALIZATION] == "1") { - realization_timer->start(60); - ui_vp_realization->show(); + ui_vp_realization->play("realizationflash", "", "", 60); sfx_player->play(ao_app->get_custom_realization(m_chatmessage[CHAR_NAME])); } diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index afe7a67..837e7e8 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -593,7 +593,7 @@ QString AOApplication::get_custom_realization(QString p_char) if (f_result == "") return get_sfx("realization"); - else return f_result; + else return get_sfx_suffix(f_result); } bool AOApplication::get_blank_blip() From e76a83ddfe8f6fe16ee7e2a91d3ac30e89f80345 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Thu, 12 Sep 2019 18:28:08 +0300 Subject: [PATCH 007/268] Allow AOMovie to have timers that take priority over the animated image frame count Set it up so feeding the timer value when playing the AOMovie would use the timer but only in cases where a non-animated image is used Update shouts and wtce to pass the 'duration' argument which will be used if the image used is non-animated. Otherwise, prioritize the animated image duration. --- include/aomovie.h | 5 ++- src/aomovie.cpp | 83 ++++++++++++++++++++++++++--------------------- src/courtroom.cpp | 16 ++++----- 3 files changed, 58 insertions(+), 46 deletions(-) diff --git a/include/aomovie.h b/include/aomovie.h index 1f278bf..33b3158 100644 --- a/include/aomovie.h +++ b/include/aomovie.h @@ -15,13 +15,15 @@ public: AOMovie(QWidget *p_parent, AOApplication *p_ao_app); void set_play_once(bool p_play_once); - void play(QString p_gif, QString p_char = "", QString p_custom_theme = ""); + void start_timer(int delay); + void play(QString p_gif, QString p_char = "", QString p_custom_theme = "", int duration = 0); void combo_resize(int w, int h); void stop(); private: QMovie *m_movie; AOApplication *ao_app; + QTimer *timer; bool play_once = true; signals: @@ -29,6 +31,7 @@ signals: private slots: void frame_change(int n_frame); + void timer_done(); }; #endif // AOMOVIE_H diff --git a/src/aomovie.cpp b/src/aomovie.cpp index edf5bdb..2598bb7 100644 --- a/src/aomovie.cpp +++ b/src/aomovie.cpp @@ -12,7 +12,11 @@ AOMovie::AOMovie(QWidget *p_parent, AOApplication *p_ao_app) : QLabel(p_parent) this->setMovie(m_movie); + timer = new QTimer(this); + timer->setSingleShot(true); + connect(m_movie, SIGNAL(frameChanged(int)), this, SLOT(frame_change(int))); + connect(timer, SIGNAL(timeout()), this, SLOT(timer_done())); } void AOMovie::set_play_once(bool p_play_once) @@ -20,46 +24,44 @@ void AOMovie::set_play_once(bool p_play_once) play_once = p_play_once; } -void AOMovie::play(QString p_gif, QString p_char, QString p_custom_theme) +void AOMovie::start_timer(int delay) +{ + timer->start(delay); +} + +void AOMovie::play(QString p_gif, QString p_char, QString p_custom_theme, int duration) { m_movie->stop(); - QString gif_path; - - QString custom_path; + QString shout_path; + QList pathlist; if (p_gif == "custom") - custom_path = ao_app->get_image_suffix(ao_app->get_character_path(p_char, p_gif)); + pathlist << ao_app->get_image_suffix(ao_app->get_character_path(p_char, p_gif)); else - custom_path = ao_app->get_image_suffix(ao_app->get_character_path(p_char, p_gif + "_bubble")); + pathlist << ao_app->get_image_suffix(ao_app->get_character_path(p_char, p_gif + "_bubble")); - QString misc_path = ao_app->get_base_path() + "misc/" + p_custom_theme + "/" + p_gif + "_bubble.gif"; - QString custom_theme_path = ao_app->get_custom_theme_path(p_custom_theme, p_gif + ".gif"); - QString theme_path = ao_app->get_theme_path(p_gif + ".gif"); - QString default_theme_path = ao_app->get_default_theme_path(p_gif + ".gif"); - QString placeholder_path = ao_app->get_theme_path("placeholder.gif"); - QString default_placeholder_path = ao_app->get_default_theme_path("placeholder.gif"); + pathlist << ao_app->get_image_suffix(ao_app->get_base_path() + "misc/" + p_custom_theme + "/" + p_gif + "_bubble") << //Misc path + ao_app->get_image_suffix(ao_app->get_custom_theme_path(p_custom_theme, p_gif)) << //Custom theme path + ao_app->get_image_suffix(ao_app->get_theme_path(p_gif)) << //Theme path + ao_app->get_image_suffix(ao_app->get_default_theme_path(p_gif)) << //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 - if (file_exists(custom_path)) - gif_path = custom_path; - else if (file_exists(misc_path)) - gif_path = misc_path; - else if (file_exists(custom_theme_path)) - gif_path = custom_theme_path; - else if (file_exists(theme_path)) - gif_path = theme_path; - else if (file_exists(default_theme_path)) - gif_path = default_theme_path; - else if (file_exists(placeholder_path)) - gif_path = placeholder_path; - else if (file_exists(default_placeholder_path)) - gif_path = default_placeholder_path; - else - gif_path = ""; + for (QString path : pathlist) + { + if (file_exists(path)) + { + shout_path = path; + break; + } + } - m_movie->setFileName(gif_path); + m_movie->setFileName(shout_path); this->show(); m_movie->start(); + if (m_movie->frameCount() == 0 && duration > 0) + this->start_timer(duration); } void AOMovie::stop() @@ -70,16 +72,23 @@ void AOMovie::stop() void AOMovie::frame_change(int n_frame) { - if (n_frame == (m_movie->frameCount() - 1) && play_once) - { - //we need this or else the last frame wont show - delay(m_movie->nextFrameDelay()); + //If it's a "static movie" (only one frame - png image), we can't change frames - ignore this function (use timer instead). + //If the frame didn't reach the last frame or the movie is continuous, don't stop the movie. + if (m_movie->frameCount() == 0 || n_frame < (m_movie->frameCount() - 1) || !play_once) + return; + //we need this or else the last frame wont show + delay(m_movie->nextFrameDelay()); - this->stop(); + this->stop(); - //signal connected to courtroom object, let it figure out what to do - done(); - } + //signal connected to courtroom object, let it figure out what to do + done(); +} + +void AOMovie::timer_done() +{ + this->stop(); + done(); } void AOMovie::combo_resize(int w, int h) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index a171416..1440978 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1350,20 +1350,20 @@ void Courtroom::handle_chatmessage(QStringList *p_contents) switch (objection_mod) { case 1: - ui_vp_objection->play("holdit", f_char, f_custom_theme); + ui_vp_objection->play("holdit", f_char, f_custom_theme, 724); objection_player->play("holdit.wav", f_char, f_custom_theme); break; case 2: - ui_vp_objection->play("objection", f_char, f_custom_theme); + ui_vp_objection->play("objection", f_char, f_custom_theme, 724); objection_player->play("objection.wav", f_char, f_custom_theme); break; case 3: - ui_vp_objection->play("takethat", f_char, f_custom_theme); + ui_vp_objection->play("takethat", f_char, f_custom_theme, 724); objection_player->play("takethat.wav", f_char, f_custom_theme); break; //case 4 is AO2 only case 4: - ui_vp_objection->play("custom", f_char, f_custom_theme); + ui_vp_objection->play("custom", f_char, f_custom_theme, 724); objection_player->play("custom.wav", f_char, f_custom_theme); break; default: @@ -2574,7 +2574,7 @@ void Courtroom::handle_wtce(QString p_wtce, int variant) if (p_wtce == "testimony1") { sfx_player->play(ao_app->get_sfx("witness_testimony")); - ui_vp_wtce->play("witnesstestimony"); + ui_vp_wtce->play("witnesstestimony", "", "", 1500); testimony_in_progress = true; show_testimony(); } @@ -2582,7 +2582,7 @@ void Courtroom::handle_wtce(QString p_wtce, int variant) else if (p_wtce == "testimony2") { sfx_player->play(ao_app->get_sfx("cross_examination")); - ui_vp_wtce->play("crossexamination"); + ui_vp_wtce->play("crossexamination", "", "", 1500); testimony_in_progress = false; } else if (p_wtce == "judgeruling") @@ -2590,12 +2590,12 @@ void Courtroom::handle_wtce(QString p_wtce, int variant) if (variant == 0) { sfx_player->play(ao_app->get_sfx("not_guilty")); - ui_vp_wtce->play("notguilty"); + ui_vp_wtce->play("notguilty", "", "", 3000); testimony_in_progress = false; } else if (variant == 1) { sfx_player->play(ao_app->get_sfx("guilty")); - ui_vp_wtce->play("guilty"); + ui_vp_wtce->play("guilty", "", "", 3000); testimony_in_progress = false; } } From 5a31516a36e0f13211db807a48214f11ccef827d Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Thu, 12 Sep 2019 19:03:42 +0300 Subject: [PATCH 008/268] Remove unecessary hard-coded timers for the witness testimony .png Make the witness testimony use AOMovie instead of AOImage Remove pointless "testimony_in_progress" variable CONTROVERSIAL: Make the witness testimony indicator be position-ignorant so as to reduce the amount of hardcoding and allow broader usage of the witness testimony system (For example, Danganronpa investigation indicator, etc.) - This should not affect how the testimony indicator is received currently, as witness testimony usually requires the entire rest of the court to shut up until the cross-examination either way. (cherry picked from commit 932f430b683dffb0b965c32cd2247e2b6361dd0e) --- include/courtroom.h | 15 +------------ src/courtroom.cpp | 54 ++++++++------------------------------------- 2 files changed, 10 insertions(+), 59 deletions(-) diff --git a/include/courtroom.h b/include/courtroom.h index f0b6996..e053e23 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -309,11 +309,6 @@ private: //keeps track of how long realization is visible(it's just a white square and should be visible less than a second) QTimer *realization_timer; - //times how long the blinking testimony should be shown(green one in the corner) - QTimer *testimony_show_timer; - //times how long the blinking testimony should be hidden - QTimer *testimony_hide_timer; - //every time point in char.inis times this equals the final time const int time_mod = 40; @@ -323,14 +318,6 @@ private: QString previous_ic_message = ""; - bool testimony_in_progress = false; - - //in milliseconds - const int testimony_show_time = 1500; - - //in milliseconds - const int testimony_hide_time = 500; - //char id, muted or not QMap mute_map; @@ -407,8 +394,8 @@ private: AOImage *ui_vp_chatbox; QLabel *ui_vp_showname; QTextEdit *ui_vp_message; - AOImage *ui_vp_testimony; AOImage *ui_vp_realization; + AOMovie *ui_vp_testimony; AOMovie *ui_vp_wtce; AOMovie *ui_vp_objection; diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 1440978..c82f6f2 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -58,12 +58,6 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() realization_timer = new QTimer(this); realization_timer->setSingleShot(true); - testimony_show_timer = new QTimer(this); - testimony_show_timer->setSingleShot(true); - - testimony_hide_timer = new QTimer(this); - testimony_hide_timer->setSingleShot(true); - music_player = new AOMusicPlayer(this, ao_app); music_player->set_volume(0); @@ -101,7 +95,8 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_vp_message->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); ui_vp_message->setReadOnly(true); - ui_vp_testimony = new AOImage(this, ao_app); + ui_vp_testimony = new AOMovie(this, ao_app); + ui_vp_testimony->set_play_once(false); ui_vp_realization = new AOImage(this, ao_app); ui_vp_wtce = new AOMovie(this, ao_app); ui_vp_objection = new AOMovie(this, ao_app); @@ -280,9 +275,6 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() connect(realization_timer, SIGNAL(timeout()), this, SLOT(realization_done())); - connect(testimony_show_timer, SIGNAL(timeout()), this, SLOT(hide_testimony())); - connect(testimony_hide_timer, SIGNAL(timeout()), this, SLOT(show_testimony())); - connect(ui_emote_left, SIGNAL(clicked()), this, SLOT(on_emote_left_clicked())); connect(ui_emote_right, SIGNAL(clicked()), this, SLOT(on_emote_right_clicked())); @@ -492,9 +484,7 @@ void Courtroom::set_widgets() "color: white"); ui_vp_testimony->move(ui_viewport->x(), ui_viewport->y()); - ui_vp_testimony->resize(ui_viewport->width(), ui_viewport->height()); - ui_vp_testimony->set_image("testimony.png"); - ui_vp_testimony->hide(); + ui_vp_testimony->combo_resize(ui_viewport->width(), ui_viewport->height()); ui_vp_realization->move(ui_viewport->x(), ui_viewport->y()); ui_vp_realization->resize(ui_viewport->width(), ui_viewport->height()); @@ -824,8 +814,7 @@ void Courtroom::done_received() void Courtroom::set_background(QString p_background) { - testimony_in_progress = false; - + ui_vp_testimony->stop(); current_background = p_background; is_ao2_bg = file_exists(ao_app->get_background_path("defensedesk.png")) && @@ -933,7 +922,7 @@ void Courtroom::enter_courtroom(int p_cid) objection_player->set_volume(ui_sfx_slider->value()); blip_player->set_volume(ui_blip_slider->value()); - testimony_in_progress = false; + ui_vp_testimony->stop(); set_widgets(); @@ -2335,27 +2324,6 @@ void Courtroom::chat_tick() } } - -void Courtroom::show_testimony() -{ - if (!testimony_in_progress || m_chatmessage[SIDE] != "wit") - return; - - ui_vp_testimony->show(); - - testimony_show_timer->start(testimony_show_time); -} - -void Courtroom::hide_testimony() -{ - ui_vp_testimony->hide(); - - if (!testimony_in_progress) - return; - - testimony_hide_timer->start(testimony_hide_time); -} - void Courtroom::play_sfx() { QString sfx_name = m_chatmessage[SFX_NAME]; @@ -2368,9 +2336,6 @@ void Courtroom::play_sfx() void Courtroom::set_scene() { - if (testimony_in_progress) - show_testimony(); - //witness is default if pos is invalid QString f_background = "witnessempty"; QString f_desk_image = "stand"; @@ -2575,15 +2540,14 @@ void Courtroom::handle_wtce(QString p_wtce, int variant) { sfx_player->play(ao_app->get_sfx("witness_testimony")); ui_vp_wtce->play("witnesstestimony", "", "", 1500); - testimony_in_progress = true; - show_testimony(); + ui_vp_testimony->play("testimony"); } //cross examination else if (p_wtce == "testimony2") { sfx_player->play(ao_app->get_sfx("cross_examination")); ui_vp_wtce->play("crossexamination", "", "", 1500); - testimony_in_progress = false; + ui_vp_testimony->stop(); } else if (p_wtce == "judgeruling") { @@ -2591,12 +2555,12 @@ void Courtroom::handle_wtce(QString p_wtce, int variant) { sfx_player->play(ao_app->get_sfx("not_guilty")); ui_vp_wtce->play("notguilty", "", "", 3000); - testimony_in_progress = false; + ui_vp_testimony->stop(); } else if (variant == 1) { sfx_player->play(ao_app->get_sfx("guilty")); ui_vp_wtce->play("guilty", "", "", 3000); - testimony_in_progress = false; + ui_vp_testimony->stop(); } } } From 3b3507df60673079482372b4da08eeabf9317a20 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Thu, 12 Sep 2019 19:37:44 +0300 Subject: [PATCH 009/268] Fix compilation error Allow realization flashes to be animated images by making them AOMovies Eploit the newly added 'duration' system for realization AOMovie (cherry picked from commit bb98f79083648243216f665852a7d2326af11be0) --- include/courtroom.h | 10 +--------- src/courtroom.cpp | 18 +++--------------- src/text_file_functions.cpp | 2 +- 3 files changed, 5 insertions(+), 25 deletions(-) diff --git a/include/courtroom.h b/include/courtroom.h index e053e23..fe870b4 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -306,9 +306,6 @@ private: //delay before sfx plays QTimer *sfx_delay_timer; - //keeps track of how long realization is visible(it's just a white square and should be visible less than a second) - QTimer *realization_timer; - //every time point in char.inis times this equals the final time const int time_mod = 40; @@ -394,7 +391,7 @@ private: AOImage *ui_vp_chatbox; QLabel *ui_vp_showname; QTextEdit *ui_vp_message; - AOImage *ui_vp_realization; + AOMovie *ui_vp_realization; AOMovie *ui_vp_testimony; AOMovie *ui_vp_wtce; AOMovie *ui_vp_objection; @@ -538,11 +535,6 @@ public slots: void objection_done(); void preanim_done(); - void realization_done(); - - void show_testimony(); - void hide_testimony(); - void mod_called(QString p_ip); void case_called(QString msg, bool def, bool pro, bool jud, bool jur, bool steno); diff --git a/src/courtroom.cpp b/src/courtroom.cpp index c82f6f2..5ae71f8 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -55,9 +55,6 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() sfx_delay_timer = new QTimer(this); sfx_delay_timer->setSingleShot(true); - realization_timer = new QTimer(this); - realization_timer->setSingleShot(true); - music_player = new AOMusicPlayer(this, ao_app); music_player->set_volume(0); @@ -97,7 +94,7 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_vp_testimony = new AOMovie(this, ao_app); ui_vp_testimony->set_play_once(false); - ui_vp_realization = new AOImage(this, ao_app); + ui_vp_realization = new AOMovie(this, ao_app); ui_vp_wtce = new AOMovie(this, ao_app); ui_vp_objection = new AOMovie(this, ao_app); @@ -273,8 +270,6 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() connect(chat_tick_timer, SIGNAL(timeout()), this, SLOT(chat_tick())); - connect(realization_timer, SIGNAL(timeout()), this, SLOT(realization_done())); - connect(ui_emote_left, SIGNAL(clicked()), this, SLOT(on_emote_left_clicked())); connect(ui_emote_right, SIGNAL(clicked()), this, SLOT(on_emote_right_clicked())); @@ -487,9 +482,7 @@ void Courtroom::set_widgets() ui_vp_testimony->combo_resize(ui_viewport->width(), ui_viewport->height()); ui_vp_realization->move(ui_viewport->x(), ui_viewport->y()); - ui_vp_realization->resize(ui_viewport->width(), ui_viewport->height()); - ui_vp_realization->set_image("realizationflash.png"); - ui_vp_realization->hide(); + ui_vp_realization->combo_resize(ui_viewport->width(), ui_viewport->height()); ui_vp_wtce->move(ui_viewport->x(), ui_viewport->y()); ui_vp_wtce->combo_resize(ui_viewport->width(), ui_viewport->height()); @@ -1972,10 +1965,6 @@ void Courtroom::preanim_done() handle_chatmessage_3(); } -void Courtroom::realization_done() -{ - ui_vp_realization->hide(); -} void Courtroom::start_chat_ticking() { @@ -1985,8 +1974,7 @@ void Courtroom::start_chat_ticking() if (m_chatmessage[REALIZATION] == "1") { - realization_timer->start(60); - ui_vp_realization->show(); + ui_vp_realization->play("realizationflash", "", "", 60); sfx_player->play(ao_app->get_custom_realization(m_chatmessage[CHAR_NAME])); } diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index 5a34ac8..8f6ee23 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -592,7 +592,7 @@ QString AOApplication::get_custom_realization(QString p_char) if (f_result == "") return get_sfx("realization"); - else return f_result; + else return get_sfx_suffix(f_result); } bool AOApplication::get_blank_blip() From 2a5cd56d5774265fb474d0767964c47272283da8 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Thu, 12 Sep 2019 22:55:24 +0300 Subject: [PATCH 010/268] Fixes Objections hiding the current character, instead of overlaying on top of it. (from goofball's 2.7 branch commit e6cb5bd2cf241d638941ad5b403ab5fd7490335c) --- src/courtroom.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index db97bb9..6e01ea7 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1288,7 +1288,6 @@ void Courtroom::handle_chatmessage(QStringList *p_contents) text_state = 0; anim_state = 0; ui_vp_objection->stop(); - ui_vp_player_char->stop(); chat_tick_timer->stop(); ui_vp_evidence_display->reset(); From 8a5bc8632eb69db751ded4d6034e5648208b9212 Mon Sep 17 00:00:00 2001 From: iamgoofball Date: Fri, 18 Jan 2019 19:08:56 -0800 Subject: [PATCH 011/268] Kill Music on Object option (todo: actual functionality, cherrypicked from Goofball's 2.7 branch) --- Attorney_Online.pro | 4 ++-- include/aoapplication.h | 3 +++ include/aooptionsdialog.h | 2 ++ src/aooptionsdialog.cpp | 12 ++++++++++++ src/text_file_functions.cpp | 6 ++++++ 5 files changed, 25 insertions(+), 2 deletions(-) diff --git a/Attorney_Online.pro b/Attorney_Online.pro index 32781a1..b747619 100644 --- a/Attorney_Online.pro +++ b/Attorney_Online.pro @@ -16,13 +16,13 @@ HEADERS += $$files($$PWD/include/*.h) LIBS += -L$$PWD/lib -#DEFINES += DISCORD +DEFINES += DISCORD contains(DEFINES, DISCORD) { LIBS += -ldiscord-rpc } -#DEFINES += BASSAUDIO +DEFINES += BASSAUDIO contains(DEFINES, BASSAUDIO) { LIBS += -lbass diff --git a/include/aoapplication.h b/include/aoapplication.h index 19924e4..94508ff 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -150,6 +150,9 @@ public: //Returns true if blank blips is enabled in config.ini and false otherwise bool get_blank_blip(); + //Returns true if kill music on object is enabled in the config.ini + bool get_objectmusic(); + //Returns the value of default_music in config.ini int get_default_music(); diff --git a/include/aooptionsdialog.h b/include/aooptionsdialog.h index 934d257..34ae2b7 100644 --- a/include/aooptionsdialog.h +++ b/include/aooptionsdialog.h @@ -88,6 +88,8 @@ private: QLabel *ui_bliprate_lbl; QCheckBox *ui_blank_blips_cb; QLabel *ui_blank_blips_lbl; + QLabel *ui_objectmusic_lbl; + QCheckBox *ui_objectmusic_cb; QDialogButtonBox *ui_settings_buttons; QWidget *ui_casing_tab; diff --git a/src/aooptionsdialog.cpp b/src/aooptionsdialog.cpp index 82507a1..c8263ad 100644 --- a/src/aooptionsdialog.cpp +++ b/src/aooptionsdialog.cpp @@ -334,6 +334,17 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi ui_audio_layout->setWidget(7, QFormLayout::FieldRole, ui_blank_blips_cb); + ui_objectmusic_lbl = new QLabel(ui_audio_widget); + ui_objectmusic_lbl->setText(tr("Kill Music On Objection:")); + ui_objectmusic_lbl->setToolTip(tr("If true, the game will stop music when someone objects, like in the actual games.")); + + ui_audio_layout->setWidget(9, QFormLayout::LabelRole, ui_objectmusic_lbl); + + ui_objectmusic_cb = new QCheckBox(ui_audio_widget); + ui_objectmusic_cb->setChecked(p_ao_app->get_objectmusic()); + + ui_audio_layout->setWidget(9, QFormLayout::FieldRole, ui_objectmusic_cb); + // The casing tab! ui_casing_tab = new QWidget(); ui_settings_tabs->addTab(ui_casing_tab, tr("Casing")); @@ -506,6 +517,7 @@ void AOOptionsDialog::save_pressed() configini->setValue("default_blip", ui_blips_volume_spinbox->value()); configini->setValue("blip_rate", ui_bliprate_spinbox->value()); configini->setValue("blank_blip", ui_blank_blips_cb->isChecked()); + configini->setValue("kill_music_on_object", ui_objectmusic_cb->isChecked()); configini->setValue("casing_enabled", ui_casing_enabled_cb->isChecked()); configini->setValue("casing_defence_enabled", ui_casing_def_cb->isChecked()); diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index 837e7e8..026de16 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -602,6 +602,12 @@ bool AOApplication::get_blank_blip() return result.startsWith("true"); } +bool AOApplication::get_objectmusic() +{ + QString result = configini->value("kill_music_on_object", "true").value(); + return result.startsWith("true"); +} + bool AOApplication::is_discord_enabled() { QString result = configini->value("discord", "true").value(); From ba41b070a208af9393abebd721fb1488fbedee57 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Fri, 13 Sep 2019 11:03:23 +0300 Subject: [PATCH 012/268] Cut music on objection if config is enabled for it (does not transmit networked message yet) --- src/courtroom.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 6e01ea7..276b0fa 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1336,6 +1336,8 @@ void Courtroom::handle_chatmessage(QStringList *p_contents) case 2: ui_vp_objection->play("objection", f_char, f_custom_theme, 724); objection_player->play("objection.wav", f_char, f_custom_theme); + if (ao_app->get_objectmusic()) + music_player->play(""); //I'd prefer if this sent a networked message instead so everyone would have their music cut when you object. break; case 3: ui_vp_objection->play("takethat", f_char, f_custom_theme, 724); From 455e020b19bb1801304cedd08b2675fe4bb30605 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Fri, 13 Sep 2019 11:13:50 +0300 Subject: [PATCH 013/268] Make log go downwards by default Rename kill_music_on_object to objection_stop_music for readability Update blip rate (faster overall, more accurate to the trilogy) - based on AOV values Update default blip rate to be "once every two symbols" --- include/aoapplication.h | 4 ++-- include/courtroom.h | 2 +- src/aooptionsdialog.cpp | 4 ++-- src/courtroom.cpp | 2 +- src/text_file_functions.cpp | 8 ++++---- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/include/aoapplication.h b/include/aoapplication.h index 94508ff..e6cb21d 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -150,8 +150,8 @@ public: //Returns true if blank blips is enabled in config.ini and false otherwise bool get_blank_blip(); - //Returns true if kill music on object is enabled in the config.ini - bool get_objectmusic(); + //Returns true if stop music on objection is enabled in the config.ini + bool objection_stop_music(); //Returns the value of default_music in config.ini int get_default_music(); diff --git a/include/courtroom.h b/include/courtroom.h index a3c4736..ed5199d 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -249,7 +249,7 @@ private: bool message_is_centered = false; int current_display_speed = 3; - int message_display_speed[7] = {30, 40, 50, 60, 75, 100, 120}; + int message_display_speed[7] = {10, 20, 30, 40, 50, 60, 75}; // This is for checking if the character should start talking again // when an inline blue text ends. diff --git a/src/aooptionsdialog.cpp b/src/aooptionsdialog.cpp index c8263ad..e86255b 100644 --- a/src/aooptionsdialog.cpp +++ b/src/aooptionsdialog.cpp @@ -341,7 +341,7 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi ui_audio_layout->setWidget(9, QFormLayout::LabelRole, ui_objectmusic_lbl); ui_objectmusic_cb = new QCheckBox(ui_audio_widget); - ui_objectmusic_cb->setChecked(p_ao_app->get_objectmusic()); + ui_objectmusic_cb->setChecked(p_ao_app->objection_stop_music()); ui_audio_layout->setWidget(9, QFormLayout::FieldRole, ui_objectmusic_cb); @@ -517,7 +517,7 @@ void AOOptionsDialog::save_pressed() configini->setValue("default_blip", ui_blips_volume_spinbox->value()); configini->setValue("blip_rate", ui_bliprate_spinbox->value()); configini->setValue("blank_blip", ui_blank_blips_cb->isChecked()); - configini->setValue("kill_music_on_object", ui_objectmusic_cb->isChecked()); + configini->setValue("objection_stop_music", ui_objectmusic_cb->isChecked()); configini->setValue("casing_enabled", ui_casing_enabled_cb->isChecked()); configini->setValue("casing_defence_enabled", ui_casing_def_cb->isChecked()); diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 276b0fa..cd51004 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1336,7 +1336,7 @@ void Courtroom::handle_chatmessage(QStringList *p_contents) case 2: ui_vp_objection->play("objection", f_char, f_custom_theme, 724); objection_player->play("objection.wav", f_char, f_custom_theme); - if (ao_app->get_objectmusic()) + if (ao_app->objection_stop_music()) music_player->play(""); //I'd prefer if this sent a networked message instead so everyone would have their music cut when you object. break; case 3: diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index 026de16..9a0cd2f 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -8,7 +8,7 @@ QString AOApplication::read_theme() int AOApplication::read_blip_rate() { - int result = configini->value("blip_rate", 1).toInt(); + int result = configini->value("blip_rate", 2).toInt(); if (result < 1) return 1; @@ -48,7 +48,7 @@ int AOApplication::get_max_log_size() bool AOApplication::get_log_goes_downwards() { - QString result = configini->value("log_goes_downwards", "false").value(); + QString result = configini->value("log_goes_downwards", "true").value(); return result.startsWith("true"); } @@ -602,9 +602,9 @@ bool AOApplication::get_blank_blip() return result.startsWith("true"); } -bool AOApplication::get_objectmusic() +bool AOApplication::objection_stop_music() { - QString result = configini->value("kill_music_on_object", "true").value(); + QString result = configini->value("objection_stop_music", "false").value(); return result.startsWith("true"); } From 5c69d10cd5fface32aea04cea1d288783d376179 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Fri, 13 Sep 2019 11:31:06 +0300 Subject: [PATCH 014/268] Add a tool tip to blip rate settings Adapt the blip rate to allow variable speed value array sizes --- include/aoapplication.h | 2 +- src/aooptionsdialog.cpp | 2 ++ src/courtroom.cpp | 7 +++---- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/include/aoapplication.h b/include/aoapplication.h index e6cb21d..4a3c669 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -144,7 +144,7 @@ public: //Returns the value of ooc_name in config.ini QString get_ooc_name(); - //Returns the blip rate from config.ini + //Returns the blip rate from config.ini (once per X symbols) int read_blip_rate(); //Returns true if blank blips is enabled in config.ini and false otherwise diff --git a/src/aooptionsdialog.cpp b/src/aooptionsdialog.cpp index e86255b..a918c0c 100644 --- a/src/aooptionsdialog.cpp +++ b/src/aooptionsdialog.cpp @@ -319,6 +319,8 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi ui_bliprate_spinbox = new QSpinBox(ui_audio_widget); ui_bliprate_spinbox->setValue(p_ao_app->read_blip_rate()); ui_bliprate_spinbox->setMinimum(1); + ui_bliprate_spinbox->setToolTip(tr("Play a blip sound \"once per every X symbols\", where " + "X is the blip rate.")); ui_audio_layout->setWidget(6, QFormLayout::FieldRole, ui_bliprate_spinbox); diff --git a/src/courtroom.cpp b/src/courtroom.cpp index cd51004..0faab3e 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -2275,13 +2275,11 @@ void Courtroom::chat_tick() if (f_character != ' ' || blank_blip) { - if (blip_pos % blip_rate == 0 && !formatting_char) { blip_pos = 0; blip_player->blip_tick(); } - ++blip_pos; } @@ -2289,14 +2287,15 @@ void Courtroom::chat_tick() // Restart the timer, but according to the newly set speeds, if there were any. // Keep the speed at bay. + int max_speed = sizeof(message_display_speed) / sizeof(message_display_speed[0]); //7 entries by default if (current_display_speed < 0) { current_display_speed = 0; } - if (current_display_speed > 6) + if (current_display_speed >= max_speed) { - current_display_speed = 6; + current_display_speed = max_speed-1; } // If we had a formatting char, we shouldn't wait so long again, as it won't appear! From 8027bbffadc63b269091567f2557b8cd81abee56 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Fri, 13 Sep 2019 11:37:06 +0300 Subject: [PATCH 015/268] Use brace constructors instead of << append operator for path lists --- src/aocharmovie.cpp | 10 ++++++---- src/aomovie.cpp | 24 ++++++++++++++---------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/aocharmovie.cpp b/src/aocharmovie.cpp index 883530b..23da710 100644 --- a/src/aocharmovie.cpp +++ b/src/aocharmovie.cpp @@ -21,10 +21,12 @@ void AOCharMovie::play(QString p_char, QString p_emote, QString emote_prefix) { QString emote_path; QList pathlist; - pathlist << ao_app->get_image_suffix(ao_app->get_character_path(p_char, emote_prefix + p_emote)) <get_character_path(p_char, p_emote + ".png") << //Non-animated path if emote_prefix fails - 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 + pathlist = { + ao_app->get_image_suffix(ao_app->get_character_path(p_char, emote_prefix + p_emote)), //Default path + ao_app->get_character_path(p_char, p_emote + ".png"), //Non-animated path if emote_prefix fails + 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 + }; for (QString path : pathlist) { diff --git a/src/aomovie.cpp b/src/aomovie.cpp index 2598bb7..726a515 100644 --- a/src/aomovie.cpp +++ b/src/aomovie.cpp @@ -35,17 +35,21 @@ void AOMovie::play(QString p_gif, QString p_char, QString p_custom_theme, int du QString shout_path; QList pathlist; - if (p_gif == "custom") - pathlist << ao_app->get_image_suffix(ao_app->get_character_path(p_char, p_gif)); - else - pathlist << ao_app->get_image_suffix(ao_app->get_character_path(p_char, p_gif + "_bubble")); - pathlist << ao_app->get_image_suffix(ao_app->get_base_path() + "misc/" + p_custom_theme + "/" + p_gif + "_bubble") << //Misc path - ao_app->get_image_suffix(ao_app->get_custom_theme_path(p_custom_theme, p_gif)) << //Custom theme path - ao_app->get_image_suffix(ao_app->get_theme_path(p_gif)) << //Theme path - ao_app->get_image_suffix(ao_app->get_default_theme_path(p_gif)) << //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 + pathlist = { + ao_app->get_image_suffix(ao_app->get_base_path() + "misc/" + p_custom_theme + "/" + p_gif + "_bubble"), //Misc path + ao_app->get_image_suffix(ao_app->get_custom_theme_path(p_custom_theme, p_gif)), //Custom theme path + ao_app->get_image_suffix(ao_app->get_theme_path(p_gif)), //Theme path + ao_app->get_image_suffix(ao_app->get_default_theme_path(p_gif)), //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 + }; + + //Add this at the beginning of the list - order matters. + if (p_gif == "custom") + pathlist.prepend(ao_app->get_image_suffix(ao_app->get_character_path(p_char, p_gif))); + else + pathlist.prepend(ao_app->get_image_suffix(ao_app->get_character_path(p_char, p_gif + "_bubble"))); for (QString path : pathlist) { From bb8edab5798be59476557c0eae2b6aa1f4257448 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Fri, 13 Sep 2019 11:41:59 +0300 Subject: [PATCH 016/268] Make shout, verdict and wtce default duration values into constants --- include/courtroom.h | 9 +++++++++ src/courtroom.cpp | 16 ++++++++-------- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/include/courtroom.h b/include/courtroom.h index ed5199d..b330337 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -311,6 +311,15 @@ private: //every time point in char.inis times this equals the final time const int time_mod = 40; + //the amount of time non-animated objection/hold it/takethat images stay onscreen for in ms + const int shout_stay_time = 724; + + //the amount of time non-animated guilty/not guilty images stay onscreen for in ms + const int verdict_stay_time = 3000; + + //the amount of time non-animated witness testimony/cross-examination images stay onscreen for in ms + const int wtce_stay_time = 1500; + static const int chatmessage_size = 23; QString m_chatmessage[chatmessage_size]; bool chatmessage_is_empty = false; diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 0faab3e..b1fd1c2 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1330,22 +1330,22 @@ void Courtroom::handle_chatmessage(QStringList *p_contents) switch (objection_mod) { case 1: - ui_vp_objection->play("holdit", f_char, f_custom_theme, 724); + ui_vp_objection->play("holdit", f_char, f_custom_theme, shout_stay_time); objection_player->play("holdit.wav", f_char, f_custom_theme); break; case 2: - ui_vp_objection->play("objection", f_char, f_custom_theme, 724); + ui_vp_objection->play("objection", f_char, f_custom_theme, shout_stay_time); objection_player->play("objection.wav", f_char, f_custom_theme); if (ao_app->objection_stop_music()) music_player->play(""); //I'd prefer if this sent a networked message instead so everyone would have their music cut when you object. break; case 3: - ui_vp_objection->play("takethat", f_char, f_custom_theme, 724); + ui_vp_objection->play("takethat", f_char, f_custom_theme, shout_stay_time); objection_player->play("takethat.wav", f_char, f_custom_theme); break; //case 4 is AO2 only case 4: - ui_vp_objection->play("custom", f_char, f_custom_theme, 724); + ui_vp_objection->play("custom", f_char, f_custom_theme, shout_stay_time); objection_player->play("custom.wav", f_char, f_custom_theme); break; default: @@ -2524,14 +2524,14 @@ void Courtroom::handle_wtce(QString p_wtce, int variant) if (p_wtce == "testimony1") { sfx_player->play(ao_app->get_sfx("witness_testimony")); - ui_vp_wtce->play("witnesstestimony", "", "", 1500); + ui_vp_wtce->play("witnesstestimony", "", "", wtce_stay_time); ui_vp_testimony->play("testimony"); } //cross examination else if (p_wtce == "testimony2") { sfx_player->play(ao_app->get_sfx("cross_examination")); - ui_vp_wtce->play("crossexamination", "", "", 1500); + ui_vp_wtce->play("crossexamination", "", "", wtce_stay_time); ui_vp_testimony->stop(); } else if (p_wtce == "judgeruling") @@ -2539,12 +2539,12 @@ void Courtroom::handle_wtce(QString p_wtce, int variant) if (variant == 0) { sfx_player->play(ao_app->get_sfx("not_guilty")); - ui_vp_wtce->play("notguilty", "", "", 3000); + ui_vp_wtce->play("notguilty", "", "", verdict_stay_time); ui_vp_testimony->stop(); } else if (variant == 1) { sfx_player->play(ao_app->get_sfx("guilty")); - ui_vp_wtce->play("guilty", "", "", 3000); + ui_vp_wtce->play("guilty", "", "", verdict_stay_time); ui_vp_testimony->stop(); } } From 9aa88b1d6e84538761a963249d8c8029314e26d7 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Fri, 13 Sep 2019 11:37:06 +0300 Subject: [PATCH 017/268] Use brace constructors instead of << append operator for path lists Rename gif_path into emote_path for charmovie.cpp Rename p_gif into p_image for aomovie.cpp --- src/aocharmovie.cpp | 48 ++++++++++++++++++++++----------------------- src/aomovie.cpp | 26 +++++++++++++----------- 2 files changed, 39 insertions(+), 35 deletions(-) diff --git a/src/aocharmovie.cpp b/src/aocharmovie.cpp index 5748723..90baa55 100644 --- a/src/aocharmovie.cpp +++ b/src/aocharmovie.cpp @@ -19,28 +19,28 @@ AOCharMovie::AOCharMovie(QWidget *p_parent, AOApplication *p_ao_app) : QLabel(p_ void AOCharMovie::play(QString p_char, QString p_emote, QString emote_prefix) { - QString original_path = ao_app->get_character_path(p_char, emote_prefix + p_emote + ".gif"); - QString alt_path = ao_app->get_character_path(p_char, p_emote + ".png"); - QString apng_path = ao_app->get_character_path(p_char, emote_prefix + p_emote + ".apng"); - QString placeholder_path = ao_app->get_theme_path("placeholder.gif"); - QString placeholder_default_path = ao_app->get_default_theme_path("placeholder.gif"); - QString gif_path; + QString emote_path; + QList pathlist; + pathlist = { + ao_app->get_image_suffix(ao_app->get_character_path(p_char, emote_prefix + p_emote)), //Default path + ao_app->get_character_path(p_char, p_emote + ".png"), //Non-animated path if emote_prefix fails + 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 + }; - if (file_exists(apng_path)) - gif_path = apng_path; - else if (file_exists(original_path)) - gif_path = original_path; - else if (file_exists(alt_path)) - gif_path = alt_path; - else if (file_exists(placeholder_path)) - gif_path = placeholder_path; - else - gif_path = placeholder_default_path; + for (QString path : pathlist) + { + if (file_exists(path)) + { + emote_path = path; + break; + } + } m_movie->stop(); - m_movie->setFileName(gif_path); + m_movie->setFileName(emote_path); - QImageReader *reader = new QImageReader(gif_path); + QImageReader *reader = new QImageReader(emote_path); movie_frames.clear(); QImage f_image = reader->read(); @@ -61,11 +61,11 @@ void AOCharMovie::play(QString p_char, QString p_emote, QString emote_prefix) void AOCharMovie::play_pre(QString p_char, QString p_emote, int duration) { - QString gif_path = ao_app->get_character_path(p_char, p_emote); + QString emote_path = ao_app->get_character_path(p_char, p_emote); m_movie->stop(); this->clear(); - m_movie->setFileName(gif_path); + m_movie->setFileName(emote_path); m_movie->jumpToFrame(0); int full_duration = duration * time_mod; @@ -116,11 +116,11 @@ void AOCharMovie::play_pre(QString p_char, QString p_emote, int duration) void AOCharMovie::play_talking(QString p_char, QString p_emote) { - QString gif_path = ao_app->get_character_path(p_char, "(b)" + p_emote); + QString emote_path = ao_app->get_character_path(p_char, "(b)" + p_emote); m_movie->stop(); this->clear(); - m_movie->setFileName(gif_path); + m_movie->setFileName(emote_path); play_once = false; m_movie->setSpeed(100); @@ -129,11 +129,11 @@ void AOCharMovie::play_talking(QString p_char, QString p_emote) void AOCharMovie::play_idle(QString p_char, QString p_emote) { - QString gif_path = ao_app->get_character_path(p_char, "(a)" + p_emote); + QString emote_path = ao_app->get_character_path(p_char, "(a)" + p_emote); m_movie->stop(); this->clear(); - m_movie->setFileName(gif_path); + m_movie->setFileName(emote_path); play_once = false; m_movie->setSpeed(100); diff --git a/src/aomovie.cpp b/src/aomovie.cpp index 2598bb7..851ae57 100644 --- a/src/aomovie.cpp +++ b/src/aomovie.cpp @@ -29,23 +29,27 @@ void AOMovie::start_timer(int delay) timer->start(delay); } -void AOMovie::play(QString p_gif, QString p_char, QString p_custom_theme, int duration) +void AOMovie::play(QString p_image, QString p_char, QString p_custom_theme, int duration) { m_movie->stop(); QString shout_path; QList pathlist; - if (p_gif == "custom") - pathlist << ao_app->get_image_suffix(ao_app->get_character_path(p_char, p_gif)); - else - pathlist << ao_app->get_image_suffix(ao_app->get_character_path(p_char, p_gif + "_bubble")); - pathlist << ao_app->get_image_suffix(ao_app->get_base_path() + "misc/" + p_custom_theme + "/" + p_gif + "_bubble") << //Misc path - ao_app->get_image_suffix(ao_app->get_custom_theme_path(p_custom_theme, p_gif)) << //Custom theme path - ao_app->get_image_suffix(ao_app->get_theme_path(p_gif)) << //Theme path - ao_app->get_image_suffix(ao_app->get_default_theme_path(p_gif)) << //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 + pathlist = { + ao_app->get_image_suffix(ao_app->get_base_path() + "misc/" + p_custom_theme + "/" + p_image + "_bubble"), //Misc path + ao_app->get_image_suffix(ao_app->get_custom_theme_path(p_custom_theme, p_image)), //Custom theme path + ao_app->get_image_suffix(ao_app->get_theme_path(p_image)), //Theme path + ao_app->get_image_suffix(ao_app->get_default_theme_path(p_image)), //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 + }; + + //Add this at the beginning of the list - order matters. + if (p_image == "custom") + pathlist.prepend(ao_app->get_image_suffix(ao_app->get_character_path(p_char, p_image))); + else + pathlist.prepend(ao_app->get_image_suffix(ao_app->get_character_path(p_char, p_image + "_bubble"))); for (QString path : pathlist) { From 86523bb101e73417e44eaae71e6cac5a11a70751 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Fri, 13 Sep 2019 11:56:22 +0300 Subject: [PATCH 018/268] Rename dubious "duration" to "default_duration" for play function in AOMovie class --- include/aomovie.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/aomovie.h b/include/aomovie.h index 33b3158..974559d 100644 --- a/include/aomovie.h +++ b/include/aomovie.h @@ -16,7 +16,7 @@ public: void set_play_once(bool p_play_once); void start_timer(int delay); - void play(QString p_gif, QString p_char = "", QString p_custom_theme = "", int duration = 0); + void play(QString p_gif, QString p_char = "", QString p_custom_theme = "", int default_duration = 0); void combo_resize(int w, int h); void stop(); From 040898feff5d15f7236afb5e41c3bcc47e703a2a Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Fri, 13 Sep 2019 15:11:30 +0300 Subject: [PATCH 019/268] Set up screenshake button ui Rewrite Goofball's doScreenshake() function to be much more modular and multi-purpose (also rename to do_screenshake() to match other functions) Add networking needed to make screenshake work. Works with AOV version of tsuserver3 (button screenshake only so far). Add get_theme_pos helper function, currently unused. --- include/aoapplication.h | 1 + include/courtroom.h | 15 +++- include/datatypes.h | 7 +- src/courtroom.cpp | 132 +++++++++++++++++++++++++++++++++++- src/packet_distribution.cpp | 3 + 5 files changed, 155 insertions(+), 3 deletions(-) diff --git a/include/aoapplication.h b/include/aoapplication.h index 4a3c669..8d998f4 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -78,6 +78,7 @@ public: bool arup_enabled = false; bool casing_alerts_enabled = false; bool modcall_reason_enabled = false; + bool looping_sfx_support_enabled = false; ///////////////loading info/////////////////// diff --git a/include/courtroom.h b/include/courtroom.h index b330337..682e12a 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -49,6 +49,9 @@ #include #include #include +#include +#include +#include #include @@ -124,6 +127,9 @@ public: //reads theme inis and sets size and pos based on the identifier void set_size_and_pos(QWidget *p_widget, QString p_identifier); + //reads theme inis and returns the size and pos as defined by it + QPoint get_theme_pos(QString p_identifier); + //sets status as taken on character with cid n_char and places proper shading on charselect void set_taken(int n_char, bool p_taken); @@ -213,6 +219,8 @@ public: void announce_case(QString title, bool def, bool pro, bool jud, bool jur, bool steno); void check_connection_received(); + void do_screenshake(); + void doRealization(); ~Courtroom(); @@ -231,6 +239,8 @@ private: bool first_message_sent = false; int maximumMessages = 0; + QParallelAnimationGroup *screenshake_animation_group; + // This is for inline message-colouring. enum INLINE_COLOURS { @@ -320,7 +330,7 @@ private: //the amount of time non-animated witness testimony/cross-examination images stay onscreen for in ms const int wtce_stay_time = 1500; - static const int chatmessage_size = 23; + static const int chatmessage_size = 28; QString m_chatmessage[chatmessage_size]; bool chatmessage_is_empty = false; @@ -346,6 +356,7 @@ private: int objection_state = 0; int realization_state = 0; + int screenshake_state = 0; int text_color = 0; bool is_presenting_evidence = false; @@ -472,6 +483,7 @@ private: AOButton *ui_custom_objection; AOButton *ui_realization; + AOButton *ui_screenshake; AOButton *ui_mute; AOButton *ui_defense_plus; @@ -595,6 +607,7 @@ private slots: void on_custom_objection_clicked(); void on_realization_clicked(); + void on_screenshake_clicked(); void on_mute_clicked(); void on_pair_clicked(); diff --git a/include/datatypes.h b/include/datatypes.h index aaa5de5..1b76f72 100644 --- a/include/datatypes.h +++ b/include/datatypes.h @@ -100,7 +100,12 @@ enum CHAT_MESSAGE SELF_OFFSET, OTHER_OFFSET, OTHER_FLIP, - NONINTERRUPTING_PRE + NONINTERRUPTING_PRE, + LOOPING_SFX, + SCREENSHAKE, + FRAME_SCREENSHAKE, + FRAME_REALIZATION, + FRAME_SFX }; enum COLOR diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 5ae71f8..04c2f86 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -211,6 +211,7 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_custom_objection = new AOButton(this, ao_app); ui_realization = new AOButton(this, ao_app); + ui_screenshake = new AOButton(this, ao_app); ui_mute = new AOButton(this, ao_app); ui_defense_plus = new AOButton(this, ao_app); @@ -291,6 +292,7 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() connect(ui_custom_objection, SIGNAL(clicked()), this, SLOT(on_custom_objection_clicked())); connect(ui_realization, SIGNAL(clicked()), this, SLOT(on_realization_clicked())); + connect(ui_screenshake, SIGNAL(clicked()), this, SLOT(on_screenshake_clicked())); connect(ui_mute, SIGNAL(clicked()), this, SLOT(on_mute_clicked())); @@ -625,6 +627,9 @@ void Courtroom::set_widgets() set_size_and_pos(ui_realization, "realization"); ui_realization->set_image("realization.png"); + set_size_and_pos(ui_screenshake, "screenshake"); + ui_screenshake->set_image("screenshake.png"); + set_size_and_pos(ui_mute, "mute_button"); ui_mute->set_image("mute.png"); @@ -784,6 +789,23 @@ void Courtroom::set_taken(int n_char, bool p_taken) char_list.replace(n_char, f_char); } +QPoint Courtroom::get_theme_pos(QString p_identifier) +{ + QString filename = "courtroom_design.ini"; + + pos_size_type design_ini_result = ao_app->get_element_dimensions(p_identifier, filename); + + if (design_ini_result.width < 0 || design_ini_result.height < 0) + { + qDebug() << "W: could not find \"" << p_identifier << "\" in " << filename; + return QPoint(0,0); + } + else + { + return QPoint(design_ini_result.x, design_ini_result.y); + } +} + void Courtroom::done_received() { m_cid = -1; @@ -1232,6 +1254,50 @@ void Courtroom::on_chat_return_pressed() } } + // If the server we're on supports Looping SFX and Screenshake, use it if the emote uses it. + if (ao_app->looping_sfx_support_enabled) + { + packet_contents.append("0"); //ao_app->get_sfx_looping(current_char, current_emote)); +// qDebug() << "Are we looping this? " << ao_app->get_sfx_looping(current_char, current_emote); + packet_contents.append(QString::number(screenshake_state)); + qDebug() << "Are we screen shaking this one? " << screenshake_state; + + QString frame_screenshake = ""; + QString frame_realization = ""; + QString frame_sfx = ""; + + QString preemote_sfx = ao_app->get_pre_emote(current_char, current_emote) + "^"; + QString preemote_shake = ao_app->get_pre_emote(current_char, current_emote) + "^"; + QString preemote_flash = ao_app->get_pre_emote(current_char, current_emote) + "^"; + + QString talkemote_sfx = "(b)" + ao_app->get_emote(current_char, current_emote) + "^"; + QString talkemote_shake = "(b)" + ao_app->get_emote(current_char, current_emote) + "^"; + QString talkemote_flash = "(b)" + ao_app->get_emote(current_char, current_emote) + "^"; + + QString idleemote_sfx = "(a)" + ao_app->get_emote(current_char, current_emote) + "^"; + QString idleemote_shake = "(a)" + ao_app->get_emote(current_char, current_emote) + "^"; + QString idleemote_flash = "(a)" + ao_app->get_emote(current_char, current_emote) + "^"; + + frame_screenshake += preemote_shake; + frame_screenshake += talkemote_shake; + frame_screenshake += idleemote_shake; + + frame_realization += preemote_flash; + frame_realization += talkemote_flash; + frame_realization += idleemote_flash; + + frame_sfx += preemote_sfx; + frame_sfx += talkemote_sfx; + frame_sfx += idleemote_sfx; + qDebug() << "Final strings:"; + qDebug() << frame_screenshake; + qDebug() << frame_realization; + qDebug() << frame_sfx; + + packet_contents.append(frame_screenshake); + packet_contents.append(frame_realization); + packet_contents.append(frame_sfx); + } ao_app->send_server_packet(new AOPacket("MS", packet_contents)); } @@ -1300,6 +1366,7 @@ void Courtroom::handle_chatmessage(QStringList *p_contents) ui_ic_chat_message->clear(); objection_state = 0; realization_state = 0; + screenshake_state = 0; is_presenting_evidence = false; ui_pre->setChecked(false); ui_hold_it->set_image("holdit.png"); @@ -1307,6 +1374,7 @@ void Courtroom::handle_chatmessage(QStringList *p_contents) ui_take_that->set_image("takethat.png"); ui_custom_objection->set_image("custom.png"); ui_realization->set_image("realization.png"); + ui_screenshake->set_image("screenshake.png"); ui_evidence_present->set_image("present_disabled.png"); } @@ -1565,7 +1633,6 @@ void Courtroom::handle_chatmessage_2() } } } - switch (emote_mod) { case 1: case 2: case 6: @@ -1582,6 +1649,48 @@ void Courtroom::handle_chatmessage_2() } } +void Courtroom::do_screenshake() +{ + if (screenshake_animation_group && screenshake_animation_group->state() == QAbstractAnimation::Running) + screenshake_animation_group->setCurrentTime(screenshake_animation_group->duration()); //Force it to finish and delete itself + + screenshake_animation_group = new QParallelAnimationGroup; + + QList affected_list = { + ui_vp_background, + ui_vp_player_char, + ui_vp_sideplayer_char, + ui_vp_chatbox, + }; + + //I would prefer if this was its own "shake" function to be honest. + foreach (QWidget* ui_element, affected_list) + { + QPropertyAnimation *screenshake_animation = new QPropertyAnimation(ui_element, "pos", this); + QPoint pos_default = QPoint(ui_element->x(), ui_element->y()); + + int duration = 300; //How long does the screenshake last + int frequency = 20; //How often in ms is there a "jolt" frame + int maxframes = duration/frequency; + int max_x = 7; //Max deviation from origin on x axis + int max_y = 7; //Max deviation from origin on y axis + screenshake_animation->setDuration(duration); + for (int frame=0; frame < maxframes; frame++) + { + double fraction = double(frame*frequency)/duration; + quint32 rng = QRandomGenerator::global()->generate(); + int rand_x = int(rng) % max_x; + int rand_y = int(rng+100) % max_y; + screenshake_animation->setKeyValueAt(fraction, QPoint(pos_default.x() + rand_x, pos_default.y() + rand_y)); + } + screenshake_animation->setEndValue(pos_default); + screenshake_animation->setEasingCurve(QEasingCurve::Linear); + screenshake_animation_group->addAnimation(screenshake_animation); + } + + screenshake_animation_group->start(QAbstractAnimation::DeletionPolicy::DeleteWhenStopped); +} + void Courtroom::handle_chatmessage_3() { start_chat_ticking(); @@ -1978,6 +2087,11 @@ void Courtroom::start_chat_ticking() sfx_player->play(ao_app->get_custom_realization(m_chatmessage[CHAR_NAME])); } + if (m_chatmessage[SCREENSHAKE] == "1") + { + this->do_screenshake(); + } + ui_vp_message->clear(); set_text_color(); rainbow_counter = 0; @@ -3184,6 +3298,22 @@ void Courtroom::on_realization_clicked() ui_ic_chat_message->setFocus(); } +void Courtroom::on_screenshake_clicked() +{ + if (screenshake_state == 0) + { + screenshake_state = 1; + ui_screenshake->set_image("screenshake_pressed.png"); + } + else + { + screenshake_state = 0; + ui_screenshake->set_image("screenshake.png"); + } + + ui_ic_chat_message->setFocus(); +} + void Courtroom::on_mute_clicked() { if (ui_mute_list->isHidden()) diff --git a/src/packet_distribution.cpp b/src/packet_distribution.cpp index cfd6d8c..420aea2 100644 --- a/src/packet_distribution.cpp +++ b/src/packet_distribution.cpp @@ -156,6 +156,7 @@ void AOApplication::server_packet_received(AOPacket *p_packet) arup_enabled = false; casing_alerts_enabled = false; modcall_reason_enabled = false; + looping_sfx_support_enabled = false; //workaround for tsuserver4 if (f_contents.at(0) == "NOENCRYPT") @@ -216,6 +217,8 @@ void AOApplication::server_packet_received(AOPacket *p_packet) casing_alerts_enabled = true; if (f_packet.contains("modcall_reason",Qt::CaseInsensitive)) modcall_reason_enabled = true; + if (f_packet.contains("looping_sfx",Qt::CaseInsensitive)) + looping_sfx_support_enabled = true; } else if (header == "PN") { From f1b31697130101ab493a2f2907e3974f3cf1fa58 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Fri, 13 Sep 2019 15:13:40 +0300 Subject: [PATCH 020/268] CONTROVERSIAL: Detach ui_vp_message from ui_vp_chatbox to prevent it from being affected by the screenshake. ui_vp_message still sets position relative to the chat box for now (as doing otherwise would break a lot of themes). --- src/courtroom.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 04c2f86..2e174f2 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -86,7 +86,7 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_vp_chatbox = new AOImage(this, ao_app); ui_vp_showname = new QLabel(ui_vp_chatbox); - ui_vp_message = new QTextEdit(ui_vp_chatbox); + ui_vp_message = new QTextEdit(this); ui_vp_message->setFrameStyle(QFrame::NoFrame); ui_vp_message->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); ui_vp_message->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); @@ -476,6 +476,8 @@ void Courtroom::set_widgets() set_size_and_pos(ui_vp_showname, "showname"); set_size_and_pos(ui_vp_message, "message"); + //We detached the text as parent from the chatbox so it doesn't get affected by the screenshake. +// ui_vp_message->move(ui_vp_message->x() + ui_vp_chatbox->x(), ui_vp_message->y() + ui_vp_chatbox->y()); ui_vp_message->setTextInteractionFlags(Qt::NoTextInteraction); ui_vp_message->setStyleSheet("background-color: rgba(0, 0, 0, 0);" "color: white"); From f9b3bd5bb5fdbb739e806d004af09443bdbb2aac Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Fri, 13 Sep 2019 17:57:30 +0300 Subject: [PATCH 021/268] forgot to actually uncomment the change, oops --- src/courtroom.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 2e174f2..41712d2 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -477,7 +477,7 @@ void Courtroom::set_widgets() set_size_and_pos(ui_vp_message, "message"); //We detached the text as parent from the chatbox so it doesn't get affected by the screenshake. -// ui_vp_message->move(ui_vp_message->x() + ui_vp_chatbox->x(), ui_vp_message->y() + ui_vp_chatbox->y()); + ui_vp_message->move(ui_vp_message->x() + ui_vp_chatbox->x(), ui_vp_message->y() + ui_vp_chatbox->y()); ui_vp_message->setTextInteractionFlags(Qt::NoTextInteraction); ui_vp_message->setStyleSheet("background-color: rgba(0, 0, 0, 0);" "color: white"); From 1139bf5cd0473817ba223ac8a9fe9d193575206a Mon Sep 17 00:00:00 2001 From: iamgoofball Date: Sat, 19 Jan 2019 21:01:19 -0800 Subject: [PATCH 022/268] Bass.dll functionality-based clientside music looping system by using channel loopable flags (no use of QTimer required) Implement Goofball's AOV loopable music server message where any value that's not -1 when the length of the handle_message packet is longer than 3 will not loop the music (still confused about this but w/e) --- include/aomusicplayer.h | 5 ++++- src/aomusicplayer.cpp | 26 +++++++++++++++++++++++--- src/courtroom.cpp | 18 +++++++++++++++++- 3 files changed, 44 insertions(+), 5 deletions(-) diff --git a/include/aomusicplayer.h b/include/aomusicplayer.h index b34267c..da47128 100644 --- a/include/aomusicplayer.h +++ b/include/aomusicplayer.h @@ -17,15 +17,18 @@ class AOMusicPlayer { public: AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app); - ~AOMusicPlayer(); + virtual ~AOMusicPlayer(); void play(QString p_song); + void stop(); void set_volume(int p_value); + void set_looping(bool toggle); private: QWidget *m_parent; AOApplication *ao_app; + bool m_looping = true; int m_volume = 0; HSTREAM m_stream; }; diff --git a/src/aomusicplayer.cpp b/src/aomusicplayer.cpp index 2791809..781a90c 100644 --- a/src/aomusicplayer.cpp +++ b/src/aomusicplayer.cpp @@ -17,22 +17,42 @@ void AOMusicPlayer::play(QString p_song) BASS_ChannelStop(m_stream); QString f_path = ao_app->get_music_path(p_song); - - m_stream = BASS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE); + unsigned int flags = BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE; + m_stream = BASS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, flags); this->set_volume(m_volume); - + this->set_looping(m_looping); if (ao_app->get_audio_output_device() != "default") BASS_ChannelSetDevice(m_stream, BASS_GetDevice()); BASS_ChannelPlay(m_stream, false); } +void AOMusicPlayer::stop() +{ + BASS_ChannelStop(m_stream); +} + void AOMusicPlayer::set_volume(int p_value) { m_volume = p_value; float volume = m_volume / 100.0f; BASS_ChannelSetAttribute(m_stream, BASS_ATTRIB_VOL, volume); } + +void AOMusicPlayer::set_looping(bool toggle) +{ + m_looping = toggle; + if (BASS_ChannelFlags(m_stream, 0, 0) & BASS_SAMPLE_LOOP) + { + if (m_looping == false) + BASS_ChannelFlags(m_stream, 0, BASS_SAMPLE_LOOP); // remove the LOOP flag + } + else + { + if (m_looping == true) + BASS_ChannelFlags(m_stream, BASS_SAMPLE_LOOP, BASS_SAMPLE_LOOP); // set the LOOP flag + } +} #elif defined(QTAUDIO) AOMusicPlayer::AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app) { diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 41712d2..06f5aa0 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -2616,7 +2616,23 @@ void Courtroom::handle_song(QStringList *p_contents) if (p_contents->length() > 2) { - str_show = p_contents->at(2); + if(p_contents->at(2) != "") + { + str_show = p_contents->at(2); + } + } + if (p_contents->length() > 3) + { + //I am really confused why "-1" is "loop this song" and why anything else passes as "don't loop" + //(if we even have this length) but alright + if(p_contents->at(3) != "-1") + { + music_player->set_looping(false); + } + else + { + music_player->set_looping(true); + } } if (!mute_map.value(n_char)) From 4645d9dd080964560477e48d99812bc494c1965b Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sat, 14 Sep 2019 00:46:46 +0300 Subject: [PATCH 023/268] Add a blip sound QElapsedTimer so blipsounds don't play more frequently than 60ms to preserve all of our ears. Adjust the message display speeds to feel more accurate to AA, with }}} speed displaying text instantly for that section --- include/aoblipplayer.h | 4 ++++ include/courtroom.h | 2 +- src/aoblipplayer.cpp | 4 ++++ src/courtroom.cpp | 28 +++++++++++----------------- 4 files changed, 20 insertions(+), 18 deletions(-) diff --git a/include/aoblipplayer.h b/include/aoblipplayer.h index 44ca48b..9a42837 100644 --- a/include/aoblipplayer.h +++ b/include/aoblipplayer.h @@ -11,6 +11,7 @@ #include #include +#include #include @@ -26,9 +27,12 @@ public: int m_cycle = 0; private: + const int max_blip_ms = 60; + QWidget *m_parent; AOApplication *ao_app; qreal m_volume; + QElapsedTimer delay; void set_volume_internal(qreal p_volume); diff --git a/include/courtroom.h b/include/courtroom.h index 682e12a..9c79a3e 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -259,7 +259,7 @@ private: bool message_is_centered = false; int current_display_speed = 3; - int message_display_speed[7] = {10, 20, 30, 40, 50, 60, 75}; + int message_display_speed[7] = {0, 10, 25, 40, 50, 70, 90}; // This is for checking if the character should start talking again // when an inline blue text ends. diff --git a/src/aoblipplayer.cpp b/src/aoblipplayer.cpp index 1c668ab..5f4dc6c 100644 --- a/src/aoblipplayer.cpp +++ b/src/aoblipplayer.cpp @@ -23,6 +23,10 @@ void AOBlipPlayer::set_blips(QString p_sfx) void AOBlipPlayer::blip_tick() { + if (delay.isValid() && delay.elapsed() < max_blip_ms) + return; + + delay.start(); int f_cycle = m_cycle++; if (m_cycle == 5) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 06f5aa0..1435b0d 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -2386,23 +2386,6 @@ void Courtroom::chat_tick() QScrollBar *scroll = ui_vp_message->verticalScrollBar(); scroll->setValue(scroll->maximum()); - if(blank_blip) - qDebug() << "blank_blip found true"; - - if (f_character != ' ' || blank_blip) - { - - if (blip_pos % blip_rate == 0 && !formatting_char) - { - blip_pos = 0; - blip_player->blip_tick(); - } - - ++blip_pos; - } - - tick_pos += f_char_length; - // Restart the timer, but according to the newly set speeds, if there were any. // Keep the speed at bay. if (current_display_speed < 0) @@ -2415,6 +2398,17 @@ void Courtroom::chat_tick() current_display_speed = 6; } + if (!formatting_char && (f_character != ' ' || blank_blip)) + { + if (blip_pos % blip_rate == 0) + { + blip_player->blip_tick(); + } + ++blip_pos; + } + + tick_pos += f_char_length; + // If we had a formatting char, we shouldn't wait so long again, as it won't appear! if (formatting_char) { From 4b452e968d07d4f49f1e6e3c86ba52c6d175033c Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sat, 14 Sep 2019 00:48:07 +0300 Subject: [PATCH 024/268] Fix the objection_stop_music option not doing anything Stop the animation for the side player char in pairing so as not to affect anything Remove the "DOOM" packet as anyone who has the source code can just remove it anyway --- src/courtroom.cpp | 3 +++ src/packet_distribution.cpp | 7 ------- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 1435b0d..3729c98 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1408,6 +1408,8 @@ void Courtroom::handle_chatmessage(QStringList *p_contents) case 2: ui_vp_objection->play("objection", f_char, f_custom_theme, 724); objection_player->play("objection.wav", f_char, f_custom_theme); + if(ao_app->objection_stop_music()) + music_player->stop(); break; case 3: ui_vp_objection->play("takethat", f_char, f_custom_theme, 724); @@ -1505,6 +1507,7 @@ void Courtroom::handle_chatmessage_2() { // If there is no second character, hide 'em, and center the first. ui_vp_sideplayer_char->hide(); + ui_vp_sideplayer_char->stop(); ui_vp_sideplayer_char->move(0,0); ui_vp_player_char->move(0,0); diff --git a/src/packet_distribution.cpp b/src/packet_distribution.cpp index 420aea2..6059edb 100644 --- a/src/packet_distribution.cpp +++ b/src/packet_distribution.cpp @@ -109,13 +109,6 @@ void AOApplication::ms_packet_received(AOPacket *p_packet) destruct_courtroom(); destruct_lobby(); } - else if (header == "DOOM") - { - call_notice(tr("You have been exiled from AO.\n" - "Have a nice day.")); - destruct_courtroom(); - destruct_lobby(); - } end: From b608f841003c461d914e6ace0c91a67b884a7b01 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sat, 14 Sep 2019 01:20:01 +0300 Subject: [PATCH 025/268] Resolve a segfault with screenshake, need to determine a better method to finish previous animation (if it exists) properly. --- src/courtroom.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 3729c98..32e39d0 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1656,21 +1656,24 @@ void Courtroom::handle_chatmessage_2() void Courtroom::do_screenshake() { - if (screenshake_animation_group && screenshake_animation_group->state() == QAbstractAnimation::Running) - screenshake_animation_group->setCurrentTime(screenshake_animation_group->duration()); //Force it to finish and delete itself +//Code below causes segfault, do not uncomment unless you know what you're doing. +// if (screenshake_animation_group != nullptr && screenshake_animation_group->state() == QAbstractAnimation::Running) +// screenshake_animation_group->setCurrentTime(screenshake_animation_group->duration()); //Force it to finish and delete itself screenshake_animation_group = new QParallelAnimationGroup; - QList affected_list = { + QList affected_list = { ui_vp_background, ui_vp_player_char, ui_vp_sideplayer_char, - ui_vp_chatbox, + ui_vp_chatbox }; + int i = 0; //I would prefer if this was its own "shake" function to be honest. foreach (QWidget* ui_element, affected_list) { + qDebug() << ++i; QPropertyAnimation *screenshake_animation = new QPropertyAnimation(ui_element, "pos", this); QPoint pos_default = QPoint(ui_element->x(), ui_element->y()); From f225df6f19aa68789ba702fa298db8675741a495 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sat, 14 Sep 2019 14:50:16 +0300 Subject: [PATCH 026/268] Fix objections hiding the character --- src/courtroom.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 32e39d0..477f395 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1357,7 +1357,6 @@ void Courtroom::handle_chatmessage(QStringList *p_contents) text_state = 0; anim_state = 0; ui_vp_objection->stop(); - ui_vp_player_char->stop(); chat_tick_timer->stop(); ui_vp_evidence_display->reset(); From 51c97ad51ce564ab400f5333eaad75b1fb2e5461 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sat, 14 Sep 2019 19:38:56 +0300 Subject: [PATCH 027/268] Allow [Time] to be blank for pre-anims to not be required to use it play_talking and play_idle reduced in useless code --- include/aocharmovie.h | 2 +- src/aocharmovie.cpp | 15 ++------------- src/courtroom.cpp | 3 +-- 3 files changed, 4 insertions(+), 16 deletions(-) diff --git a/include/aocharmovie.h b/include/aocharmovie.h index 7ef7da3..f54f510 100644 --- a/include/aocharmovie.h +++ b/include/aocharmovie.h @@ -36,7 +36,7 @@ private: QVector movie_frames; QTimer *preanim_timer; - const int time_mod = 62; + const int time_mod = 60; // These are the X and Y values before they are fixed based on the sprite's width. int x = 0; diff --git a/src/aocharmovie.cpp b/src/aocharmovie.cpp index 90baa55..ac12f63 100644 --- a/src/aocharmovie.cpp +++ b/src/aocharmovie.cpp @@ -75,6 +75,7 @@ void AOCharMovie::play_pre(QString p_char, QString p_emote, int duration) for (int n_frame = 0 ; n_frame < m_movie->frameCount() ; ++n_frame) { + qDebug() << "frame " << n_frame << " delay of " << m_movie->nextFrameDelay(); real_duration += m_movie->nextFrameDelay(); m_movie->jumpToFrame(n_frame + 1); } @@ -86,7 +87,7 @@ void AOCharMovie::play_pre(QString p_char, QString p_emote, int duration) double percentage_modifier = 100.0; - if (real_duration != 0 && duration != 0) + if (real_duration != 0 && duration > 0) { double modifier = full_duration / static_cast(real_duration); percentage_modifier = 100 / modifier; @@ -116,12 +117,6 @@ void AOCharMovie::play_pre(QString p_char, QString p_emote, int duration) void AOCharMovie::play_talking(QString p_char, QString p_emote) { - QString emote_path = ao_app->get_character_path(p_char, "(b)" + p_emote); - - m_movie->stop(); - this->clear(); - m_movie->setFileName(emote_path); - play_once = false; m_movie->setSpeed(100); play(p_char, p_emote, "(b)"); @@ -129,12 +124,6 @@ void AOCharMovie::play_talking(QString p_char, QString p_emote) void AOCharMovie::play_idle(QString p_char, QString p_emote) { - QString emote_path = ao_app->get_character_path(p_char, "(a)" + p_emote); - - m_movie->stop(); - this->clear(); - m_movie->setFileName(emote_path); - play_once = false; m_movie->setSpeed(100); play(p_char, p_emote, "(a)"); diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 477f395..47e3a0e 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -2049,8 +2049,7 @@ void Courtroom::play_preanim(bool noninterrupting) sfx_delay_timer->start(sfx_delay); QString anim_to_find = ao_app->get_image_suffix(ao_app->get_character_path(f_char, f_preanim)); - if (!file_exists(anim_to_find) || - preanim_duration < 0) + if (!file_exists(anim_to_find)) { if (noninterrupting) anim_state = 4; From ab30cca586a05506c3cfb502cee53957409242e8 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sat, 14 Sep 2019 19:50:46 +0300 Subject: [PATCH 028/268] Use a ticker and QImageReader instead of QMovie Issue: absolutely fucking broken, needs shittons of fixing or ditching. Might not be that efficient, anyway. --- include/aocharmovie.h | 16 ++-- src/aocharmovie.cpp | 175 +++++++++++++++++------------------------- 2 files changed, 82 insertions(+), 109 deletions(-) diff --git a/include/aocharmovie.h b/include/aocharmovie.h index f54f510..65ab79f 100644 --- a/include/aocharmovie.h +++ b/include/aocharmovie.h @@ -1,7 +1,7 @@ #ifndef AOCHARMOVIE_H #define AOCHARMOVIE_H -#include +#include #include #include #include @@ -21,20 +21,24 @@ public: void play_talking(QString p_char, QString p_emote); void play_idle(QString p_char, QString p_emote); - void set_flipped(bool p_flipped) {m_flipped = p_flipped;} + void set_frame(QImage image); void stop(); + void set_flipped(bool p_flipped) {m_flipped = p_flipped;} + void move(int ax, int ay); void combo_resize(int w, int h); + private: AOApplication *ao_app; - QMovie *m_movie; - QVector movie_frames; + QImageReader *m_reader; QTimer *preanim_timer; + QTimer *ticker; + QString last_path; const int time_mod = 60; @@ -50,8 +54,8 @@ signals: void done(); private slots: - void frame_change(int n_frame); - void timer_done(); + void preanim_done(); + void movie_ticker(); }; #endif // AOCHARMOVIE_H diff --git a/src/aocharmovie.cpp b/src/aocharmovie.cpp index ac12f63..8004a54 100644 --- a/src/aocharmovie.cpp +++ b/src/aocharmovie.cpp @@ -7,14 +7,15 @@ AOCharMovie::AOCharMovie(QWidget *p_parent, AOApplication *p_ao_app) : QLabel(p_parent) { ao_app = p_ao_app; - - m_movie = new QMovie(this); - preanim_timer = new QTimer(this); preanim_timer->setSingleShot(true); - connect(m_movie, SIGNAL(frameChanged(int)), this, SLOT(frame_change(int))); - connect(preanim_timer, SIGNAL(timeout()), this, SLOT(timer_done())); + ticker = new QTimer(this); + ticker->setSingleShot(true); + connect(ticker, SIGNAL(timeout()), this, SLOT(movie_ticker())); + +// connect(m_movie, SIGNAL(frameChanged(int)), this, SLOT(frame_change(int))); + connect(preanim_timer, SIGNAL(timeout()), this, SLOT(preanim_done())); } void AOCharMovie::play(QString p_char, QString p_emote, QString emote_prefix) @@ -37,126 +38,61 @@ void AOCharMovie::play(QString p_char, QString p_emote, QString emote_prefix) } } - m_movie->stop(); - m_movie->setFileName(emote_path); + this->clear(); + m_reader = new QImageReader(emote_path); - QImageReader *reader = new QImageReader(emote_path); - - movie_frames.clear(); - QImage f_image = reader->read(); - while (!f_image.isNull()) - { - if (m_flipped) - movie_frames.append(f_image.mirrored(true, false)); - else - movie_frames.append(f_image); - f_image = reader->read(); - } - - delete reader; + QImage f_image = m_reader->read(); +// while (!f_image.isNull()) +// { +// if (m_flipped) +// movie_frames.append(f_image.mirrored(true, false)); +// else +// movie_frames.append(f_image); +// f_image = reader->read(); +// } +// delete m_reader; this->show(); - m_movie->start(); + qDebug() << "Setting image to " << f_image; + this->set_frame(f_image); + if (m_reader->supportsAnimation()) + ticker->start(m_reader->nextImageDelay()); } void AOCharMovie::play_pre(QString p_char, QString p_emote, int duration) { - QString emote_path = ao_app->get_character_path(p_char, p_emote); - - m_movie->stop(); - this->clear(); - m_movie->setFileName(emote_path); - m_movie->jumpToFrame(0); - - int full_duration = duration * time_mod; - int real_duration = 0; - - play_once = false; - - for (int n_frame = 0 ; n_frame < m_movie->frameCount() ; ++n_frame) - { - qDebug() << "frame " << n_frame << " delay of " << m_movie->nextFrameDelay(); - real_duration += m_movie->nextFrameDelay(); - m_movie->jumpToFrame(n_frame + 1); - } - -#ifdef DEBUG_GIF - qDebug() << "full_duration: " << full_duration; - qDebug() << "real_duration: " << real_duration; -#endif - - double percentage_modifier = 100.0; - - if (real_duration != 0 && duration > 0) - { - double modifier = full_duration / static_cast(real_duration); - percentage_modifier = 100 / modifier; - - if (percentage_modifier > 100.0) - percentage_modifier = 100.0; - } - -#ifdef DEBUG_GIF - qDebug() << "% mod: " << percentage_modifier; -#endif - - if (full_duration == 0 || full_duration >= real_duration) - { - play_once = true; - } - else - { - play_once = false; - preanim_timer->start(full_duration); - } - - - m_movie->setSpeed(static_cast(percentage_modifier)); +// QString emote_path = ao_app->get_character_path(p_char, p_emote); + play_once = true; play(p_char, p_emote, ""); } void AOCharMovie::play_talking(QString p_char, QString p_emote) { play_once = false; - m_movie->setSpeed(100); play(p_char, p_emote, "(b)"); } void AOCharMovie::play_idle(QString p_char, QString p_emote) { play_once = false; - m_movie->setSpeed(100); play(p_char, p_emote, "(a)"); } void AOCharMovie::stop() { //for all intents and purposes, stopping is the same as hiding. at no point do we want a frozen gif to display - m_movie->stop(); + ticker->stop(); preanim_timer->stop(); this->hide(); } -void AOCharMovie::combo_resize(int w, int h) +void AOCharMovie::set_frame(QImage image) { - QSize f_size(w, h); - this->resize(f_size); - m_movie->setScaledSize(f_size); -} - -void AOCharMovie::move(int ax, int ay) -{ - x = ax; - y = ay; - QLabel::move(x, y); -} - -void AOCharMovie::frame_change(int n_frame) -{ - - if (movie_frames.size() > n_frame) - { - QPixmap f_pixmap = QPixmap::fromImage(movie_frames.at(n_frame)); + QPixmap f_pixmap; + if(m_flipped) + f_pixmap = QPixmap::fromImage(image.mirrored(true, false)); + else + f_pixmap = QPixmap::fromImage(image); auto aspect_ratio = Qt::KeepAspectRatio; if (f_pixmap.size().width() > f_pixmap.size().height()) @@ -168,17 +104,50 @@ void AOCharMovie::frame_change(int n_frame) this->setPixmap(f_pixmap.scaled(this->width(), this->height(), aspect_ratio, Qt::FastTransformation)); QLabel::move(x + (this->width() - this->pixmap()->width())/2, y); - } - - if (m_movie->frameCount() - 1 == n_frame && play_once) - { - preanim_timer->start(m_movie->nextFrameDelay()); - m_movie->stop(); - } } -void AOCharMovie::timer_done() +void AOCharMovie::combo_resize(int w, int h) { + QSize f_size(w, h); + this->resize(f_size); +// m_reader->setScaledSize(f_size); +} +void AOCharMovie::move(int ax, int ay) +{ + x = ax; + y = ay; + QLabel::move(x, y); +} + +void AOCharMovie::movie_ticker() +{ + if(m_reader->format() != "gif") + ticker->start(m_reader->nextImageDelay()); + if(m_reader->currentImageNumber() == -1) + { + if(play_once) + { + preanim_done(); + return; + } + else + m_reader->jumpToImage(0); //Loop back + } + QImage f_image = m_reader->read(); + if(f_image.isNull()) + { + qDebug() << "Animated image error on frame" << m_reader->currentImageNumber() << m_reader->errorString(); + stop(); + return; + } + this->set_frame(f_image); + qDebug() << m_reader->format() << "frame" << m_reader->nextImageDelay() << m_reader->currentImageNumber() << m_reader->imageCount(); + if(m_reader->format() == "gif") + ticker->start(m_reader->nextImageDelay()); +} + +void AOCharMovie::preanim_done() +{ done(); } From 14ced5ce156eec4974b424fc59e47da948aa080d Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sat, 14 Sep 2019 20:20:38 +0300 Subject: [PATCH 029/268] 2.7.2 way of animating charmovie.cpp ported over --- include/aocharmovie.h | 7 +++- src/aocharmovie.cpp | 76 +++++++++++++++++++++++++++---------------- 2 files changed, 54 insertions(+), 29 deletions(-) diff --git a/include/aocharmovie.h b/include/aocharmovie.h index f54f510..bc0e30a 100644 --- a/include/aocharmovie.h +++ b/include/aocharmovie.h @@ -29,12 +29,15 @@ public: void combo_resize(int w, int h); + void set_frame(QImage image); + private: AOApplication *ao_app; QMovie *m_movie; QVector movie_frames; QTimer *preanim_timer; + QTimer *ticker; const int time_mod = 60; @@ -46,11 +49,13 @@ private: bool play_once = true; + bool preprocess = false; + signals: void done(); private slots: - void frame_change(int n_frame); + void movie_ticker(); void timer_done(); }; diff --git a/src/aocharmovie.cpp b/src/aocharmovie.cpp index ac12f63..a0afc35 100644 --- a/src/aocharmovie.cpp +++ b/src/aocharmovie.cpp @@ -13,12 +13,16 @@ AOCharMovie::AOCharMovie(QWidget *p_parent, AOApplication *p_ao_app) : QLabel(p_ preanim_timer = new QTimer(this); preanim_timer->setSingleShot(true); - connect(m_movie, SIGNAL(frameChanged(int)), this, SLOT(frame_change(int))); + ticker = new QTimer(this); + ticker->setSingleShot(true); + connect(preanim_timer, SIGNAL(timeout()), this, SLOT(timer_done())); + connect(ticker, SIGNAL(timeout()), this, SLOT(movie_ticker())); } void AOCharMovie::play(QString p_char, QString p_emote, QString emote_prefix) { + preprocess = false; QString emote_path; QList pathlist; pathlist = { @@ -33,30 +37,22 @@ void AOCharMovie::play(QString p_char, QString p_emote, QString emote_prefix) if (file_exists(path)) { emote_path = path; + if (emote_path.endsWith(".apng")) + preprocess = true; break; } } + delete m_movie; + m_movie = new QMovie(this); m_movie->stop(); + this->clear(); m_movie->setFileName(emote_path); - - QImageReader *reader = new QImageReader(emote_path); - - movie_frames.clear(); - QImage f_image = reader->read(); - while (!f_image.isNull()) - { - if (m_flipped) - movie_frames.append(f_image.mirrored(true, false)); - else - movie_frames.append(f_image); - f_image = reader->read(); - } - - delete reader; - + m_movie->jumpToFrame(0); + this->set_frame(m_movie->currentImage()); + qDebug() << "playing file path: " << emote_path; this->show(); - m_movie->start(); + ticker->start(m_movie->nextFrameDelay()); } void AOCharMovie::play_pre(QString p_char, QString p_emote, int duration) @@ -151,12 +147,43 @@ void AOCharMovie::move(int ax, int ay) QLabel::move(x, y); } -void AOCharMovie::frame_change(int n_frame) +void AOCharMovie::movie_ticker() { + if(preprocess) + ticker->start(m_movie->nextFrameDelay()); - if (movie_frames.size() > n_frame) + if(m_movie->currentFrameNumber() == m_movie->frameCount() - 1) { - QPixmap f_pixmap = QPixmap::fromImage(movie_frames.at(n_frame)); + QString last_path = m_movie->fileName(); + delete m_movie; + m_movie = new QMovie(this); + m_movie->stop(); + this->clear(); + m_movie->setFileName(last_path); + m_movie->jumpToFrame(0); + if(play_once) + { + timer_done(); + } + } + else + { + m_movie->jumpToNextFrame(); + } + this->set_frame(m_movie->currentImage()); +// this->play_frame_sfx(); + if(!preprocess){ + ticker->start(m_movie->nextFrameDelay()); + } +} + +void AOCharMovie::set_frame(QImage image) +{ + QPixmap f_pixmap; + if(m_flipped) + f_pixmap = QPixmap::fromImage(image.mirrored(true, false)); + else + f_pixmap = QPixmap::fromImage(image); auto aspect_ratio = Qt::KeepAspectRatio; if (f_pixmap.size().width() > f_pixmap.size().height()) @@ -168,13 +195,6 @@ void AOCharMovie::frame_change(int n_frame) this->setPixmap(f_pixmap.scaled(this->width(), this->height(), aspect_ratio, Qt::FastTransformation)); QLabel::move(x + (this->width() - this->pixmap()->width())/2, y); - } - - if (m_movie->frameCount() - 1 == n_frame && play_once) - { - preanim_timer->start(m_movie->nextFrameDelay()); - m_movie->stop(); - } } void AOCharMovie::timer_done() From 938f1aeea15c6b68495bb1cb0a80467f4e8cf343 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sat, 14 Sep 2019 22:35:02 +0300 Subject: [PATCH 030/268] Optimize the heck out of animated images. There is no lag after the image is loaded now. HOWEVER, there's lag when the image is first loaded due to the aspect ratio and sizing (at least with .apng's). --- include/aocharmovie.h | 11 +++++-- src/aocharmovie.cpp | 72 +++++++++++++++++++++++-------------------- 2 files changed, 47 insertions(+), 36 deletions(-) diff --git a/include/aocharmovie.h b/include/aocharmovie.h index 65ab79f..0921bc5 100644 --- a/include/aocharmovie.h +++ b/include/aocharmovie.h @@ -6,6 +6,7 @@ #include #include #include +#include class AOApplication; @@ -21,7 +22,8 @@ public: void play_talking(QString p_char, QString p_emote); void play_idle(QString p_char, QString p_emote); - void set_frame(QImage image); + QPixmap get_pixmap(QImage image); + void set_frame(QPixmap f_pixmap); void stop(); @@ -35,19 +37,22 @@ public: private: AOApplication *ao_app; - QImageReader *m_reader; + QVector movie_frames; + QVector movie_delays; QTimer *preanim_timer; QTimer *ticker; QString last_path; + QElapsedTimer actual_time; const int time_mod = 60; // These are the X and Y values before they are fixed based on the sprite's width. int x = 0; int y = 0; - bool m_flipped = false; + int frame = 0; + bool m_flipped = false; bool play_once = true; signals: diff --git a/src/aocharmovie.cpp b/src/aocharmovie.cpp index 8004a54..2d370ec 100644 --- a/src/aocharmovie.cpp +++ b/src/aocharmovie.cpp @@ -11,7 +11,8 @@ AOCharMovie::AOCharMovie(QWidget *p_parent, AOApplication *p_ao_app) : QLabel(p_ preanim_timer->setSingleShot(true); ticker = new QTimer(this); - ticker->setSingleShot(true); + ticker->setTimerType(Qt::PreciseTimer); + ticker->setSingleShot(false); connect(ticker, SIGNAL(timeout()), this, SLOT(movie_ticker())); // connect(m_movie, SIGNAL(frameChanged(int)), this, SLOT(frame_change(int))); @@ -20,6 +21,7 @@ AOCharMovie::AOCharMovie(QWidget *p_parent, AOApplication *p_ao_app) : QLabel(p_ void AOCharMovie::play(QString p_char, QString p_emote, QString emote_prefix) { + actual_time.restart(); QString emote_path; QList pathlist; pathlist = { @@ -39,24 +41,29 @@ void AOCharMovie::play(QString p_char, QString p_emote, QString emote_prefix) } this->clear(); - m_reader = new QImageReader(emote_path); + ticker->stop(); + movie_frames.clear(); + movie_delays.clear(); + + QImageReader *m_reader = new QImageReader(emote_path); QImage f_image = m_reader->read(); -// while (!f_image.isNull()) -// { -// if (m_flipped) -// movie_frames.append(f_image.mirrored(true, false)); -// else -// movie_frames.append(f_image); -// f_image = reader->read(); -// } + while (!f_image.isNull()) + { + movie_frames.append(this->get_pixmap(f_image)); + movie_delays.append(m_reader->nextImageDelay()); + f_image = m_reader->read(); + } + + delete m_reader; -// delete m_reader; this->show(); - qDebug() << "Setting image to " << f_image; - this->set_frame(f_image); - if (m_reader->supportsAnimation()) - ticker->start(m_reader->nextImageDelay()); + qDebug() << "Setting image to " << emote_path << "Time taken to process image:" << actual_time.elapsed(); + frame = 0; + actual_time.restart(); + this->set_frame(movie_frames[frame]); + if (movie_frames.size() > 0) + ticker->start(movie_delays[frame]); } void AOCharMovie::play_pre(QString p_char, QString p_emote, int duration) @@ -86,7 +93,7 @@ void AOCharMovie::stop() this->hide(); } -void AOCharMovie::set_frame(QImage image) +QPixmap AOCharMovie::get_pixmap(QImage image) { QPixmap f_pixmap; if(m_flipped) @@ -99,10 +106,16 @@ void AOCharMovie::set_frame(QImage image) aspect_ratio = Qt::KeepAspectRatioByExpanding; if (f_pixmap.size().width() > this->size().width() || f_pixmap.size().height() > this->size().height()) - this->setPixmap(f_pixmap.scaled(this->width(), this->height(), aspect_ratio, Qt::SmoothTransformation)); + f_pixmap = f_pixmap.scaled(this->width(), this->height(), aspect_ratio, Qt::SmoothTransformation); else - this->setPixmap(f_pixmap.scaled(this->width(), this->height(), aspect_ratio, Qt::FastTransformation)); + f_pixmap = f_pixmap.scaled(this->width(), this->height(), aspect_ratio, Qt::FastTransformation); + return f_pixmap; +} + +void AOCharMovie::set_frame(QPixmap f_pixmap) +{ + this->setPixmap(f_pixmap); QLabel::move(x + (this->width() - this->pixmap()->width())/2, y); } @@ -122,29 +135,22 @@ void AOCharMovie::move(int ax, int ay) void AOCharMovie::movie_ticker() { - if(m_reader->format() != "gif") - ticker->start(m_reader->nextImageDelay()); - if(m_reader->currentImageNumber() == -1) + ++frame; + if(frame == movie_frames.size()) { if(play_once) { preanim_done(); + ticker->stop(); return; } else - m_reader->jumpToImage(0); //Loop back + frame = 0; } - QImage f_image = m_reader->read(); - if(f_image.isNull()) - { - qDebug() << "Animated image error on frame" << m_reader->currentImageNumber() << m_reader->errorString(); - stop(); - return; - } - this->set_frame(f_image); - qDebug() << m_reader->format() << "frame" << m_reader->nextImageDelay() << m_reader->currentImageNumber() << m_reader->imageCount(); - if(m_reader->format() == "gif") - ticker->start(m_reader->nextImageDelay()); +// qint64 difference = elapsed - movie_delays[frame]; + qDebug() << frame << movie_delays[frame] << "actual time taken from last frame:" << actual_time.restart(); + this->set_frame(movie_frames[frame]); + ticker->setInterval(movie_delays[frame]); } void AOCharMovie::preanim_done() From 37d192b4300efd1c2f3e35b2efb40e93ec99fa03 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sun, 15 Sep 2019 02:14:40 +0300 Subject: [PATCH 031/268] Load frames as they're needed instead of loading everything at once, and cache them for optimization. The cache is cleared when a new animation is played. Resolve an issue where if a preanim transitions into (a)idle it would get stuck on the first frame of that (removed the ticker->stop();) --- include/aocharmovie.h | 2 ++ src/aocharmovie.cpp | 50 ++++++++++++++++++++++++++++--------------- 2 files changed, 35 insertions(+), 17 deletions(-) diff --git a/include/aocharmovie.h b/include/aocharmovie.h index 0921bc5..c852bb3 100644 --- a/include/aocharmovie.h +++ b/include/aocharmovie.h @@ -42,6 +42,7 @@ private: QTimer *preanim_timer; QTimer *ticker; QString last_path; + QImageReader *m_reader = new QImageReader(); QElapsedTimer actual_time; const int time_mod = 60; @@ -51,6 +52,7 @@ private: int y = 0; int frame = 0; + int max_frames = 0; bool m_flipped = false; bool play_once = true; diff --git a/src/aocharmovie.cpp b/src/aocharmovie.cpp index 2d370ec..1251a20 100644 --- a/src/aocharmovie.cpp +++ b/src/aocharmovie.cpp @@ -21,7 +21,9 @@ AOCharMovie::AOCharMovie(QWidget *p_parent, AOApplication *p_ao_app) : QLabel(p_ void AOCharMovie::play(QString p_char, QString p_emote, QString emote_prefix) { +#ifdef DEBUG_CHARMOVIE actual_time.restart(); +#endif QString emote_path; QList pathlist; pathlist = { @@ -42,28 +44,31 @@ void AOCharMovie::play(QString p_char, QString p_emote, QString emote_prefix) this->clear(); ticker->stop(); + preanim_timer->stop(); movie_frames.clear(); movie_delays.clear(); - QImageReader *m_reader = new QImageReader(emote_path); - + m_reader->setFileName(emote_path); QImage f_image = m_reader->read(); - while (!f_image.isNull()) + int f_delay = m_reader->nextImageDelay(); + + frame = 0; + max_frames = m_reader->imageCount(); + +#ifdef DEBUG_CHARMOVIE + qDebug() << max_frames << "Setting image to " << emote_path << "Time taken to process image:" << actual_time.elapsed(); + + actual_time.restart(); +#endif + + this->set_frame(movie_frames[frame]); + this->show(); + if (max_frames > 1) { movie_frames.append(this->get_pixmap(f_image)); - movie_delays.append(m_reader->nextImageDelay()); - f_image = m_reader->read(); - } - - delete m_reader; - - this->show(); - qDebug() << "Setting image to " << emote_path << "Time taken to process image:" << actual_time.elapsed(); - frame = 0; - actual_time.restart(); - this->set_frame(movie_frames[frame]); - if (movie_frames.size() > 0) + movie_delays.append(f_delay); ticker->start(movie_delays[frame]); + } } void AOCharMovie::play_pre(QString p_char, QString p_emote, int duration) @@ -136,19 +141,30 @@ void AOCharMovie::move(int ax, int ay) void AOCharMovie::movie_ticker() { ++frame; - if(frame == movie_frames.size()) + if(frame == max_frames) { if(play_once) { preanim_done(); - ticker->stop(); return; } else frame = 0; } // qint64 difference = elapsed - movie_delays[frame]; + if(frame >= movie_frames.size()) + { + m_reader->jumpToImage(frame); + movie_frames.resize(frame + 1); + movie_frames[frame] = this->get_pixmap(m_reader->read()); + movie_delays.resize(frame + 1); + movie_delays[frame] = m_reader->nextImageDelay(); + } + +#ifdef DEBUG_CHARMOVIE qDebug() << frame << movie_delays[frame] << "actual time taken from last frame:" << actual_time.restart(); +#endif + this->set_frame(movie_frames[frame]); ticker->setInterval(movie_delays[frame]); } From 5419641c1ebe1e8749ad6e78b82c11cbd1bc13b7 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sun, 15 Sep 2019 02:17:20 +0300 Subject: [PATCH 032/268] Revert "2.7.2 way of animating charmovie.cpp ported over" This reverts commit 14ced5ce156eec4974b424fc59e47da948aa080d. --- include/aocharmovie.h | 7 +--- src/aocharmovie.cpp | 76 ++++++++++++++++--------------------------- 2 files changed, 29 insertions(+), 54 deletions(-) diff --git a/include/aocharmovie.h b/include/aocharmovie.h index bc0e30a..f54f510 100644 --- a/include/aocharmovie.h +++ b/include/aocharmovie.h @@ -29,15 +29,12 @@ public: void combo_resize(int w, int h); - void set_frame(QImage image); - private: AOApplication *ao_app; QMovie *m_movie; QVector movie_frames; QTimer *preanim_timer; - QTimer *ticker; const int time_mod = 60; @@ -49,13 +46,11 @@ private: bool play_once = true; - bool preprocess = false; - signals: void done(); private slots: - void movie_ticker(); + void frame_change(int n_frame); void timer_done(); }; diff --git a/src/aocharmovie.cpp b/src/aocharmovie.cpp index a0afc35..ac12f63 100644 --- a/src/aocharmovie.cpp +++ b/src/aocharmovie.cpp @@ -13,16 +13,12 @@ AOCharMovie::AOCharMovie(QWidget *p_parent, AOApplication *p_ao_app) : QLabel(p_ preanim_timer = new QTimer(this); preanim_timer->setSingleShot(true); - ticker = new QTimer(this); - ticker->setSingleShot(true); - + connect(m_movie, SIGNAL(frameChanged(int)), this, SLOT(frame_change(int))); connect(preanim_timer, SIGNAL(timeout()), this, SLOT(timer_done())); - connect(ticker, SIGNAL(timeout()), this, SLOT(movie_ticker())); } void AOCharMovie::play(QString p_char, QString p_emote, QString emote_prefix) { - preprocess = false; QString emote_path; QList pathlist; pathlist = { @@ -37,22 +33,30 @@ void AOCharMovie::play(QString p_char, QString p_emote, QString emote_prefix) if (file_exists(path)) { emote_path = path; - if (emote_path.endsWith(".apng")) - preprocess = true; break; } } - delete m_movie; - m_movie = new QMovie(this); m_movie->stop(); - this->clear(); m_movie->setFileName(emote_path); - m_movie->jumpToFrame(0); - this->set_frame(m_movie->currentImage()); - qDebug() << "playing file path: " << emote_path; + + QImageReader *reader = new QImageReader(emote_path); + + movie_frames.clear(); + QImage f_image = reader->read(); + while (!f_image.isNull()) + { + if (m_flipped) + movie_frames.append(f_image.mirrored(true, false)); + else + movie_frames.append(f_image); + f_image = reader->read(); + } + + delete reader; + this->show(); - ticker->start(m_movie->nextFrameDelay()); + m_movie->start(); } void AOCharMovie::play_pre(QString p_char, QString p_emote, int duration) @@ -147,43 +151,12 @@ void AOCharMovie::move(int ax, int ay) QLabel::move(x, y); } -void AOCharMovie::movie_ticker() +void AOCharMovie::frame_change(int n_frame) { - if(preprocess) - ticker->start(m_movie->nextFrameDelay()); - if(m_movie->currentFrameNumber() == m_movie->frameCount() - 1) + if (movie_frames.size() > n_frame) { - QString last_path = m_movie->fileName(); - delete m_movie; - m_movie = new QMovie(this); - m_movie->stop(); - this->clear(); - m_movie->setFileName(last_path); - m_movie->jumpToFrame(0); - if(play_once) - { - timer_done(); - } - } - else - { - m_movie->jumpToNextFrame(); - } - this->set_frame(m_movie->currentImage()); -// this->play_frame_sfx(); - if(!preprocess){ - ticker->start(m_movie->nextFrameDelay()); - } -} - -void AOCharMovie::set_frame(QImage image) -{ - QPixmap f_pixmap; - if(m_flipped) - f_pixmap = QPixmap::fromImage(image.mirrored(true, false)); - else - f_pixmap = QPixmap::fromImage(image); + QPixmap f_pixmap = QPixmap::fromImage(movie_frames.at(n_frame)); auto aspect_ratio = Qt::KeepAspectRatio; if (f_pixmap.size().width() > f_pixmap.size().height()) @@ -195,6 +168,13 @@ void AOCharMovie::set_frame(QImage image) this->setPixmap(f_pixmap.scaled(this->width(), this->height(), aspect_ratio, Qt::FastTransformation)); QLabel::move(x + (this->width() - this->pixmap()->width())/2, y); + } + + if (m_movie->frameCount() - 1 == n_frame && play_once) + { + preanim_timer->start(m_movie->nextFrameDelay()); + m_movie->stop(); + } } void AOCharMovie::timer_done() From 4db114007456f12c77f002cac4e26cd3f6917638 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sun, 15 Sep 2019 14:26:57 +0300 Subject: [PATCH 033/268] Add a bunch of cool refactors to support variable speed percentage Partially bring back the differing [Time] duration variable, however, the speed of the image will not be adjusted to accomodate it due to the need for using m_reader to read through every frame to determine the final full delay value (which tanks performance). Comment all the functions for the charmovie in aocharmovie.h --- include/aocharmovie.h | 26 +++++++++++++++++++++++- src/aocharmovie.cpp | 47 +++++++++++++++++++++++++++++-------------- 2 files changed, 57 insertions(+), 16 deletions(-) diff --git a/include/aocharmovie.h b/include/aocharmovie.h index c852bb3..b8b73b7 100644 --- a/include/aocharmovie.h +++ b/include/aocharmovie.h @@ -17,22 +17,44 @@ class AOCharMovie : public QLabel public: AOCharMovie(QWidget *p_parent, AOApplication *p_ao_app); - void play(QString p_char, QString p_emote, QString emote_prefix); + //Set the movie's image to provided paths, preparing for playback. + void load_image(QString p_char, QString p_emote, QString emote_prefix); + + //Start playback of the movie (if animated). + void play(); + + //Play a hat.gif - style preanimation void play_pre(QString p_char, QString p_emote, int duration); + + //Play a (b)normal.gif - style animation (talking) void play_talking(QString p_char, QString p_emote); + + //Play an (a)normal.gif - style animation (not talking) void play_idle(QString p_char, QString p_emote); + //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); + //Stop the movie, clearing the image void stop(); + //Set the m_flipped variable to true/false void set_flipped(bool p_flipped) {m_flipped = p_flipped;} + //Set the movie's playback speed (between 10% and 1000%) + void set_speed(int modifier) {speed = qMax(10, qMin(modifier, 1000));} + + //Move the label itself around void move(int ax, int ay); + //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); + //Return the frame delay adjusted for speed + int get_frame_delay(int delay); private: AOApplication *ao_app; @@ -54,6 +76,8 @@ private: int frame = 0; int max_frames = 0; + int speed = 100; + bool m_flipped = false; bool play_once = true; diff --git a/src/aocharmovie.cpp b/src/aocharmovie.cpp index 1251a20..0c389b1 100644 --- a/src/aocharmovie.cpp +++ b/src/aocharmovie.cpp @@ -19,7 +19,7 @@ AOCharMovie::AOCharMovie(QWidget *p_parent, AOApplication *p_ao_app) : QLabel(p_ connect(preanim_timer, SIGNAL(timeout()), this, SLOT(preanim_done())); } -void AOCharMovie::play(QString p_char, QString p_emote, QString emote_prefix) +void AOCharMovie::load_image(QString p_char, QString p_emote, QString emote_prefix) { #ifdef DEBUG_CHARMOVIE actual_time.restart(); @@ -49,45 +49,56 @@ void AOCharMovie::play(QString p_char, QString p_emote, QString emote_prefix) movie_delays.clear(); m_reader->setFileName(emote_path); - QImage f_image = m_reader->read(); + QPixmap f_pixmap = this->get_pixmap(m_reader->read()); int f_delay = m_reader->nextImageDelay(); frame = 0; max_frames = m_reader->imageCount(); + this->set_frame(f_pixmap); + this->show(); + if (max_frames > 1) + { + movie_frames.append(f_pixmap); + movie_delays.append(f_delay); + } #ifdef DEBUG_CHARMOVIE qDebug() << max_frames << "Setting image to " << emote_path << "Time taken to process image:" << actual_time.elapsed(); actual_time.restart(); #endif +} - this->set_frame(movie_frames[frame]); - this->show(); - if (max_frames > 1) - { - movie_frames.append(this->get_pixmap(f_image)); - movie_delays.append(f_delay); - ticker->start(movie_delays[frame]); - } +void AOCharMovie::play() +{ + if (max_frames <= 1) + return; + ticker->start(this->get_frame_delay(movie_delays[frame])); } void AOCharMovie::play_pre(QString p_char, QString p_emote, int duration) { -// QString emote_path = ao_app->get_character_path(p_char, p_emote); + load_image(p_char, p_emote, ""); + //As much as I'd like to screw around with [Time] durations modifying the animation speed, I don't think I can reliably do that, + //not without looping through all frames in the image at least - which causes lag. So for now it simply ends the preanimation early instead. play_once = true; - play(p_char, p_emote, ""); + if (duration > 0) //It's -1 if there's no definition in [Time] for it. In which case, it will let the animation run out in full. Duration 0 does the same. + preanim_timer->start(duration); //This timer will not fire if the animation finishes earlier than that + play(); } void AOCharMovie::play_talking(QString p_char, QString p_emote) { play_once = false; - play(p_char, p_emote, "(b)"); + load_image(p_char, p_emote, "(b)"); + play(); } void AOCharMovie::play_idle(QString p_char, QString p_emote) { play_once = false; - play(p_char, p_emote, "(a)"); + load_image(p_char, p_emote, "(a)"); + play(); } void AOCharMovie::stop() @@ -131,6 +142,11 @@ void AOCharMovie::combo_resize(int w, int h) // m_reader->setScaledSize(f_size); } +int AOCharMovie::get_frame_delay(int delay) +{ + return static_cast(double(delay) * double(speed/100)); +} + void AOCharMovie::move(int ax, int ay) { x = ax; @@ -166,10 +182,11 @@ void AOCharMovie::movie_ticker() #endif this->set_frame(movie_frames[frame]); - ticker->setInterval(movie_delays[frame]); + ticker->setInterval(this->get_frame_delay(movie_delays[frame])); } void AOCharMovie::preanim_done() { + preanim_timer->stop(); done(); } From a2f9df4042585ab0849b54e2bb0b9699f9064aed Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sun, 15 Sep 2019 17:44:02 +0300 Subject: [PATCH 034/268] Finally implement frame-specific effects such as screenshake, realization flash, sound effects, etc. Fix screenshake animation modifying the default positions of shook elements Fix aomovie sometimes not playing the last frame and causing lagspikes due to the delay() method --- include/aoapplication.h | 12 ++++ include/aocharmovie.h | 12 ++++ include/aomovie.h | 1 - include/courtroom.h | 7 ++- src/aocharmovie.cpp | 57 +++++++++++++++++++ src/aomovie.cpp | 16 ++---- src/courtroom.cpp | 108 ++++++++++++++++++++++++------------ src/text_file_functions.cpp | 36 ++++++++++++ 8 files changed, 197 insertions(+), 52 deletions(-) diff --git a/include/aoapplication.h b/include/aoapplication.h index 8d998f4..8164e16 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -271,6 +271,18 @@ public: //Returns the sfx of p_char's p_emote QString get_sfx_name(QString p_char, int p_emote); + //Returns if the sfx is defined as looping in char.ini + QString get_sfx_looping(QString p_char, QString p_sfx); + + //Returns if an emote has a frame specific SFX for it + QString get_sfx_frame(QString p_char, QString p_emote, int n_frame); + + //Returns if an emote has a frame specific SFX for it + QString get_flash_frame(QString p_char, QString p_emote, int n_frame); + + //Returns if an emote has a frame specific SFX for it + QString get_screenshake_frame(QString p_char, QString p_emote, int n_frame); + //Not in use int get_sfx_delay(QString p_char, int p_emote); diff --git a/include/aocharmovie.h b/include/aocharmovie.h index b8b73b7..5eaafaf 100644 --- a/include/aocharmovie.h +++ b/include/aocharmovie.h @@ -32,6 +32,9 @@ public: //Play an (a)normal.gif - style animation (not talking) void play_idle(QString p_char, QString p_emote); + //Play a frame-specific effect, if there's any defined for that specific frame. + void play_frame_effect(int frame); + //Retreive a pixmap adjused for mirroring/aspect ratio shenanigans from a provided QImage QPixmap get_pixmap(QImage image); @@ -61,6 +64,12 @@ private: QVector movie_frames; QVector movie_delays; + + //Effects such as sfx, screenshakes and realization flashes are stored in here. + //QString entry format: "sfx^[sfx_name]", "shake", "flash". + //The program uses the QVector index as reference. + QVector> movie_effects; + QTimer *preanim_timer; QTimer *ticker; QString last_path; @@ -83,6 +92,9 @@ private: signals: void done(); + void shake(); + void flash(); + void play_sfx(QString sfx); private slots: void preanim_done(); diff --git a/include/aomovie.h b/include/aomovie.h index 974559d..a5af735 100644 --- a/include/aomovie.h +++ b/include/aomovie.h @@ -15,7 +15,6 @@ public: AOMovie(QWidget *p_parent, AOApplication *p_ao_app); void set_play_once(bool p_play_once); - void start_timer(int delay); void play(QString p_gif, QString p_char = "", QString p_custom_theme = "", int default_duration = 0); void combo_resize(int w, int h); void stop(); diff --git a/include/courtroom.h b/include/courtroom.h index 9c79a3e..7fbde27 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -219,8 +219,6 @@ public: void announce_case(QString title, bool def, bool pro, bool jud, bool jur, bool steno); void check_connection_received(); - void do_screenshake(); - void doRealization(); ~Courtroom(); @@ -239,7 +237,7 @@ private: bool first_message_sent = false; int maximumMessages = 0; - QParallelAnimationGroup *screenshake_animation_group; + QParallelAnimationGroup *screenshake_animation_group = new QParallelAnimationGroup; // This is for inline message-colouring. @@ -557,6 +555,9 @@ private: public slots: void objection_done(); void preanim_done(); + void do_screenshake(); + void do_flash(); + void play_char_sfx(QString sfx_name); void mod_called(QString p_ip); diff --git a/src/aocharmovie.cpp b/src/aocharmovie.cpp index 0c389b1..efe2473 100644 --- a/src/aocharmovie.cpp +++ b/src/aocharmovie.cpp @@ -47,6 +47,7 @@ void AOCharMovie::load_image(QString p_char, QString p_emote, QString emote_pref preanim_timer->stop(); movie_frames.clear(); movie_delays.clear(); + movie_effects.clear(); m_reader->setFileName(emote_path); QPixmap f_pixmap = this->get_pixmap(m_reader->read()); @@ -62,6 +63,32 @@ void AOCharMovie::load_image(QString p_char, QString p_emote, QString emote_pref movie_frames.append(f_pixmap); movie_delays.append(f_delay); } + + movie_effects.resize(max_frames); + for (int e_frame = 0; e_frame < max_frames; ++e_frame) + { + qDebug() << p_char << p_emote << e_frame; + QString effect = ao_app->get_screenshake_frame(p_char, emote_prefix + p_emote, e_frame); + if (effect != "") + { + movie_effects[e_frame].append("shake"); + qDebug() << e_frame << "shake"; + } + + effect = ao_app->get_flash_frame(p_char, emote_prefix + p_emote, e_frame); + if (effect != "") + { + movie_effects[e_frame].append("flash"); + qDebug() << e_frame << "flash"; + } + + effect = ao_app->get_sfx_frame(p_char, emote_prefix + p_emote, e_frame); + if (effect != "") + { + movie_effects[e_frame].append("sfx^"+effect); + qDebug() << e_frame << effect; + } + } #ifdef DEBUG_CHARMOVIE qDebug() << max_frames << "Setting image to " << emote_path << "Time taken to process image:" << actual_time.elapsed(); @@ -71,6 +98,7 @@ void AOCharMovie::load_image(QString p_char, QString p_emote, QString emote_pref void AOCharMovie::play() { + play_frame_effect(frame); if (max_frames <= 1) return; ticker->start(this->get_frame_delay(movie_delays[frame])); @@ -101,6 +129,34 @@ void AOCharMovie::play_idle(QString p_char, QString p_emote) play(); } +void AOCharMovie::play_frame_effect(int frame) +{ + if(frame < max_frames) + { + foreach (QString effect, movie_effects[frame]) + { + if(effect == "shake") + { + shake(); + qDebug() << "Attempting to play shake on frame" << frame; + } + + if(effect == "flash") + { + flash(); + qDebug() << "Attempting to play flash on frame" << frame; + } + + if(effect.startsWith("sfx^")) + { + QString sfx = effect.section("^", 1); + play_sfx(sfx); + qDebug() << "Attempting to play sfx" << sfx << "on frame" << frame; + } + } + } +} + void AOCharMovie::stop() { //for all intents and purposes, stopping is the same as hiding. at no point do we want a frozen gif to display @@ -182,6 +238,7 @@ void AOCharMovie::movie_ticker() #endif this->set_frame(movie_frames[frame]); + play_frame_effect(frame); ticker->setInterval(this->get_frame_delay(movie_delays[frame])); } diff --git a/src/aomovie.cpp b/src/aomovie.cpp index 851ae57..7f7fb20 100644 --- a/src/aomovie.cpp +++ b/src/aomovie.cpp @@ -13,6 +13,7 @@ AOMovie::AOMovie(QWidget *p_parent, AOApplication *p_ao_app) : QLabel(p_parent) this->setMovie(m_movie); timer = new QTimer(this); + timer->setTimerType(Qt::PreciseTimer); timer->setSingleShot(true); connect(m_movie, SIGNAL(frameChanged(int)), this, SLOT(frame_change(int))); @@ -24,11 +25,6 @@ void AOMovie::set_play_once(bool p_play_once) play_once = p_play_once; } -void AOMovie::start_timer(int delay) -{ - timer->start(delay); -} - void AOMovie::play(QString p_image, QString p_char, QString p_custom_theme, int duration) { m_movie->stop(); @@ -65,7 +61,7 @@ void AOMovie::play(QString p_image, QString p_char, QString p_custom_theme, int this->show(); m_movie->start(); if (m_movie->frameCount() == 0 && duration > 0) - this->start_timer(duration); + timer->start(duration); } void AOMovie::stop() @@ -81,17 +77,13 @@ void AOMovie::frame_change(int n_frame) if (m_movie->frameCount() == 0 || n_frame < (m_movie->frameCount() - 1) || !play_once) return; //we need this or else the last frame wont show - delay(m_movie->nextFrameDelay()); - - this->stop(); - - //signal connected to courtroom object, let it figure out what to do - done(); + timer->start(m_movie->nextFrameDelay()); } void AOMovie::timer_done() { this->stop(); + //signal connected to courtroom object, let it figure out what to do done(); } diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 47e3a0e..30921d8 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -265,6 +265,9 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() connect(ui_vp_objection, SIGNAL(done()), this, SLOT(objection_done())); connect(ui_vp_player_char, SIGNAL(done()), this, SLOT(preanim_done())); + connect(ui_vp_player_char, SIGNAL(shake()), this, SLOT(do_screenshake())); + connect(ui_vp_player_char, SIGNAL(flash()), this, SLOT(do_flash())); + connect(ui_vp_player_char, SIGNAL(play_sfx(QString)), this, SLOT(play_char_sfx(QString))); connect(text_delay_timer, SIGNAL(timeout()), this, SLOT(start_chat_ticking())); connect(sfx_delay_timer, SIGNAL(timeout()), this, SLOT(play_sfx())); @@ -1655,47 +1658,58 @@ void Courtroom::handle_chatmessage_2() void Courtroom::do_screenshake() { -//Code below causes segfault, do not uncomment unless you know what you're doing. -// if (screenshake_animation_group != nullptr && screenshake_animation_group->state() == QAbstractAnimation::Running) -// screenshake_animation_group->setCurrentTime(screenshake_animation_group->duration()); //Force it to finish and delete itself + //This way, the animation is reset in such a way that last played screenshake would return to its "final frame" properly. + //This properly resets all UI elements without having to bother keeping track of "origin" positions. + //Works great wit the chat text being detached from the chat box! + screenshake_animation_group->setCurrentTime(screenshake_animation_group->duration()); + screenshake_animation_group->clear(); - screenshake_animation_group = new QParallelAnimationGroup; + QList affected_list = { + ui_vp_background, + ui_vp_player_char, + ui_vp_sideplayer_char, + ui_vp_chatbox + }; - QList affected_list = { - ui_vp_background, - ui_vp_player_char, - ui_vp_sideplayer_char, - ui_vp_chatbox - }; + int i = 0; + //I would prefer if this was its own "shake" function to be honest. + foreach (QWidget* ui_element, affected_list) + { + qDebug() << ++i; + QPropertyAnimation *screenshake_animation = new QPropertyAnimation(ui_element, "pos", this); + QPoint pos_default = QPoint(ui_element->x(), ui_element->y()); - int i = 0; - //I would prefer if this was its own "shake" function to be honest. - foreach (QWidget* ui_element, affected_list) + int duration = 300; //How long does the screenshake last + int frequency = 20; //How often in ms is there a "jolt" frame + int maxframes = duration/frequency; + int max_x = 7; //Max deviation from origin on x axis + int max_y = 7; //Max deviation from origin on y axis + screenshake_animation->setDuration(duration); + for (int frame=0; frame < maxframes; frame++) { - qDebug() << ++i; - QPropertyAnimation *screenshake_animation = new QPropertyAnimation(ui_element, "pos", this); - QPoint pos_default = QPoint(ui_element->x(), ui_element->y()); - - int duration = 300; //How long does the screenshake last - int frequency = 20; //How often in ms is there a "jolt" frame - int maxframes = duration/frequency; - int max_x = 7; //Max deviation from origin on x axis - int max_y = 7; //Max deviation from origin on y axis - screenshake_animation->setDuration(duration); - for (int frame=0; frame < maxframes; frame++) - { - double fraction = double(frame*frequency)/duration; - quint32 rng = QRandomGenerator::global()->generate(); - int rand_x = int(rng) % max_x; - int rand_y = int(rng+100) % max_y; - screenshake_animation->setKeyValueAt(fraction, QPoint(pos_default.x() + rand_x, pos_default.y() + rand_y)); - } - screenshake_animation->setEndValue(pos_default); - screenshake_animation->setEasingCurve(QEasingCurve::Linear); - screenshake_animation_group->addAnimation(screenshake_animation); + double fraction = double(frame*frequency)/duration; + quint32 rng = QRandomGenerator::global()->generate(); + int rand_x = int(rng) % max_x; + int rand_y = int(rng+100) % max_y; + screenshake_animation->setKeyValueAt(fraction, QPoint(pos_default.x() + rand_x, pos_default.y() + rand_y)); } + screenshake_animation->setEndValue(pos_default); + screenshake_animation->setEasingCurve(QEasingCurve::Linear); + screenshake_animation_group->addAnimation(screenshake_animation); + } - screenshake_animation_group->start(QAbstractAnimation::DeletionPolicy::DeleteWhenStopped); + screenshake_animation_group->start(); +} + +void Courtroom::do_flash() +{ + ui_vp_realization->play("realizationflash", "", "", 60); +} + +void Courtroom::play_char_sfx(QString sfx_name) +{ + sfx_player->play(ao_app->get_sfx_suffix(sfx_name)); + sfx_player->set_looping(ao_app->get_sfx_looping(current_char, sfx_name)!="0"); } void Courtroom::handle_chatmessage_3() @@ -1829,6 +1843,16 @@ QString Courtroom::filter_ic_text(QString p_text) p_text.remove(trick_check_pos,1); } + else if (f_character == "$" and !ic_next_is_not_special) + { + p_text.remove(trick_check_pos,1); + } + + else if (f_character == "@" and !ic_next_is_not_special) + { + p_text.remove(trick_check_pos,1); + } + // Orange inline colourisation. else if (f_character == "|" and !ic_next_is_not_special) { @@ -2089,7 +2113,7 @@ void Courtroom::start_chat_ticking() if (m_chatmessage[REALIZATION] == "1") { - ui_vp_realization->play("realizationflash", "", "", 60); + this->do_flash(); sfx_player->play(ao_app->get_custom_realization(m_chatmessage[CHAR_NAME])); } @@ -2208,6 +2232,18 @@ void Courtroom::chat_tick() formatting_char = true; } + else if (f_character == "@" and !next_character_is_not_special) + { + this->do_screenshake(); + formatting_char = true; + } + + else if (f_character == "$" and !next_character_is_not_special) + { + this->do_flash(); + formatting_char = true; + } + // Orange inline colourisation. else if (f_character == "|" and !next_character_is_not_special) { diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index 9a0cd2f..0944040 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -578,6 +578,42 @@ int AOApplication::get_sfx_delay(QString p_char, int p_emote) else return f_result.toInt(); } +QString AOApplication::get_sfx_looping(QString p_char, QString p_sfx) +{ + QString f_result = read_char_ini(p_char, p_sfx, "SoundL"); + + if (f_result == "") + return "0"; + else return f_result; +} + +QString AOApplication::get_sfx_frame(QString p_char, QString p_emote, int n_frame) +{ + QString f_result = read_char_ini(p_char, QString::number(n_frame), p_emote.append("_FrameSFX")); + + if (f_result == "") + return ""; + else return f_result; +} + +QString AOApplication::get_screenshake_frame(QString p_char, QString p_emote, int n_frame) +{ + QString f_result = read_char_ini(p_char, QString::number(n_frame), p_emote.append("_FrameScreenshake")); + + if (f_result == "") + return ""; + else return f_result; +} + +QString AOApplication::get_flash_frame(QString p_char, QString p_emote, int n_frame) +{ + QString f_result = read_char_ini(p_char, QString::number(n_frame), p_emote.append("_FrameRealization")); + + if (f_result == "") + return ""; + else return f_result; +} + int AOApplication::get_text_delay(QString p_char, QString p_emote) { QString f_result = read_char_ini(p_char, p_emote, "TextDelay"); From e94640b3493700a266619388d75dac5e56b3189a Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sun, 15 Sep 2019 17:44:47 +0300 Subject: [PATCH 035/268] Looping SFX system - Defined this way: [SoundL] sfx-roar = 1 --- include/aoapplication.h | 3 ++ include/aosfxplayer.h | 13 ++++--- src/aocharmovie.cpp | 14 ++++++++ src/aosfxplayer.cpp | 70 ++++++++++++++++++++++++++++++++----- src/courtroom.cpp | 5 ++- src/text_file_functions.cpp | 6 ++++ 6 files changed, 97 insertions(+), 14 deletions(-) diff --git a/include/aoapplication.h b/include/aoapplication.h index 8164e16..8885596 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -151,6 +151,9 @@ public: //Returns true if blank blips is enabled in config.ini and false otherwise bool get_blank_blip(); + //Returns true if looping sound effects are enabled in the config.ini + bool get_looping_sfx(); + //Returns true if stop music on objection is enabled in the config.ini bool objection_stop_music(); diff --git a/include/aosfxplayer.h b/include/aosfxplayer.h index 19d4bdf..112e3ec 100644 --- a/include/aosfxplayer.h +++ b/include/aosfxplayer.h @@ -18,19 +18,24 @@ class AOSfxPlayer public: AOSfxPlayer(QWidget *parent, AOApplication *p_ao_app); - void play(QString p_sfx, QString p_char = "", QString shout = ""); - void stop(); + void clear(); + void loop_clear(); + void play(QString p_sfx, QString p_char = "", QString shout = "", int channel=-1); + void stop(int channel=-1); void set_volume(qreal p_volume); - + void set_looping(bool toggle, int channel=-1); + int m_channel = 0; private: QWidget *m_parent; AOApplication *ao_app; qreal m_volume = 0; + bool m_looping = true; void set_volume_internal(qreal p_volume); #if defined(BASSAUDIO) - HSTREAM m_stream; + const int m_channelmax = 5; + HSTREAM m_stream_list[5]; #elif defined(QTAUDIO) QSoundEffect m_sfx; #endif diff --git a/src/aocharmovie.cpp b/src/aocharmovie.cpp index efe2473..d67cf98 100644 --- a/src/aocharmovie.cpp +++ b/src/aocharmovie.cpp @@ -67,26 +67,34 @@ void AOCharMovie::load_image(QString p_char, QString p_emote, QString emote_pref movie_effects.resize(max_frames); for (int e_frame = 0; e_frame < max_frames; ++e_frame) { +#ifdef DEBUG_CHARMOVIE qDebug() << p_char << p_emote << e_frame; +#endif QString effect = ao_app->get_screenshake_frame(p_char, emote_prefix + p_emote, e_frame); if (effect != "") { movie_effects[e_frame].append("shake"); +#ifdef DEBUG_CHARMOVIE qDebug() << e_frame << "shake"; +#endif } effect = ao_app->get_flash_frame(p_char, emote_prefix + p_emote, e_frame); if (effect != "") { movie_effects[e_frame].append("flash"); +#ifdef DEBUG_CHARMOVIE qDebug() << e_frame << "flash"; +#endif } effect = ao_app->get_sfx_frame(p_char, emote_prefix + p_emote, e_frame); if (effect != "") { movie_effects[e_frame].append("sfx^"+effect); +#ifdef DEBUG_CHARMOVIE qDebug() << e_frame << effect; +#endif } } #ifdef DEBUG_CHARMOVIE @@ -138,20 +146,26 @@ void AOCharMovie::play_frame_effect(int frame) if(effect == "shake") { shake(); +#ifdef DEBUG_CHARMOVIE qDebug() << "Attempting to play shake on frame" << frame; +#endif } if(effect == "flash") { flash(); +#ifdef DEBUG_CHARMOVIE qDebug() << "Attempting to play flash on frame" << frame; +#endif } if(effect.startsWith("sfx^")) { QString sfx = effect.section("^", 1); play_sfx(sfx); +#ifdef DEBUG_CHARMOVIE qDebug() << "Attempting to play sfx" << sfx << "on frame" << frame; +#endif } } } diff --git a/src/aosfxplayer.cpp b/src/aosfxplayer.cpp index ad8ced6..b9410c8 100644 --- a/src/aosfxplayer.cpp +++ b/src/aosfxplayer.cpp @@ -8,9 +8,35 @@ AOSfxPlayer::AOSfxPlayer(QWidget *parent, AOApplication *p_ao_app) ao_app = p_ao_app; } -void AOSfxPlayer::play(QString p_sfx, QString p_char, QString shout) +void AOSfxPlayer::clear() { - BASS_ChannelStop(m_stream); + for (int n_stream = 0 ; n_stream < m_channelmax ; ++n_stream) + { + BASS_ChannelStop(m_stream_list[n_stream]); + } + set_volume_internal(m_volume); +} + +void AOSfxPlayer::loop_clear() +{ + for (int n_stream = 0 ; n_stream < m_channelmax ; ++n_stream) + { + if((BASS_ChannelFlags(m_stream_list[n_stream], 0, 0)&BASS_SAMPLE_LOOP)) + BASS_ChannelStop(m_stream_list[n_stream]); + } + set_volume_internal(m_volume); +} + +void AOSfxPlayer::play(QString p_sfx, QString p_char, QString shout, int channel) +{ + if (channel == -1) + { + if (m_stream_list[channel] != NULL) + m_channel = (m_channel + 1) % m_channelmax; + channel = m_channel; + } + + BASS_ChannelStop(m_stream_list[channel]); QString misc_path = ""; QString char_path = ""; @@ -30,18 +56,22 @@ void AOSfxPlayer::play(QString p_sfx, QString p_char, QString shout) else f_path = sound_path; - m_stream = BASS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE); + m_stream_list[channel] = BASS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE); set_volume_internal(m_volume); if (ao_app->get_audio_output_device() != "default") - BASS_ChannelSetDevice(m_stream, BASS_GetDevice()); - BASS_ChannelPlay(m_stream, false); + BASS_ChannelSetDevice(m_stream_list[m_channel], BASS_GetDevice()); + BASS_ChannelPlay(m_stream_list[m_channel], false); } -void AOSfxPlayer::stop() +void AOSfxPlayer::stop(int channel) { - BASS_ChannelStop(m_stream); + if (channel == -1) + { + channel = m_channel; + } + BASS_ChannelStop(m_stream_list[channel]); } void AOSfxPlayer::set_volume(qreal p_value) @@ -52,8 +82,30 @@ void AOSfxPlayer::set_volume(qreal p_value) void AOSfxPlayer::set_volume_internal(qreal p_value) { - float volume = p_value; - BASS_ChannelSetAttribute(m_stream, BASS_ATTRIB_VOL, volume); + float volume = static_cast(p_value); + for (int n_stream = 0 ; n_stream < m_channelmax ; ++n_stream) + { + BASS_ChannelSetAttribute(m_stream_list[n_stream], BASS_ATTRIB_VOL, volume); + } +} + +void AOSfxPlayer::set_looping(bool toggle, int channel) +{ + if (channel == -1) + { + channel = m_channel; + } + m_looping = toggle; + if (BASS_ChannelFlags(m_stream_list[channel], 0, 0) & BASS_SAMPLE_LOOP) + { + if (m_looping == false) + BASS_ChannelFlags(m_stream_list[channel], 0, BASS_SAMPLE_LOOP); // remove the LOOP flag + } + else + { + if (m_looping == true) + BASS_ChannelFlags(m_stream_list[channel], BASS_SAMPLE_LOOP, BASS_SAMPLE_LOOP); // set the LOOP flag + } } #elif defined(QTAUDIO) //Using Qt's QSoundEffect class AOSfxPlayer::AOSfxPlayer(QWidget *parent, AOApplication *p_ao_app) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 30921d8..2aa82b5 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1425,7 +1425,7 @@ void Courtroom::handle_chatmessage(QStringList *p_contents) default: qDebug() << "W: Logic error in objection switch statement!"; } - + sfx_player->clear(); //Objection played! Cut all sfx. int emote_mod = m_chatmessage[EMOTE_MOD].toInt(); if (emote_mod == 0) @@ -1444,6 +1444,8 @@ void Courtroom::handle_chatmessage_2() { ui_vp_speedlines->stop(); ui_vp_player_char->stop(); + //Clear all looping sfx to prevent obnoxiousness + sfx_player->loop_clear(); if (m_chatmessage[SHOWNAME].isEmpty() || !ui_showname_enable->isChecked()) { @@ -2470,6 +2472,7 @@ void Courtroom::play_sfx() return; sfx_player->play(ao_app->get_sfx_suffix(sfx_name)); + sfx_player->set_looping(ao_app->get_sfx_looping(current_char, sfx_name)!="0"); } void Courtroom::set_scene() diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index 0944040..3d557c6 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -638,6 +638,12 @@ bool AOApplication::get_blank_blip() return result.startsWith("true"); } +bool AOApplication::get_looping_sfx() +{ + QString result = configini->value("looping_sfx", "true").value(); + return result.startsWith("true"); +} + bool AOApplication::objection_stop_music() { QString result = configini->value("objection_stop_music", "false").value(); From 661ec87646fe57a0081d49e428267b0dfe3f0d65 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sun, 15 Sep 2019 20:02:24 +0300 Subject: [PATCH 036/268] Implement networking for frame-specific effects data sending/parsing if the server supports it Reorganize charmovie.h a bit and make some functions private Add a new helper function "read_char_ini_tag" which returns a qstringlist of all key=value strings associated with the tag --- include/aoapplication.h | 3 + include/aocharmovie.h | 41 +++++++++----- src/aocharmovie.cpp | 109 +++++++++++++++++++++++++----------- src/courtroom.cpp | 65 ++++++++++----------- src/text_file_functions.cpp | 16 ++++++ 5 files changed, 153 insertions(+), 81 deletions(-) diff --git a/include/aoapplication.h b/include/aoapplication.h index 8885596..eb12b0c 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -232,6 +232,9 @@ public: //Returns the value of p_search_line within target_tag and terminator_tag QString read_char_ini(QString p_char, QString p_search_line, QString target_tag); + //Returns a QStringList of all key=value definitions on a given tag. + QStringList read_char_ini_tag(QString p_char, QString target_tag); + //Returns the side of the p_char character from that characters ini file QString get_char_side(QString p_char); diff --git a/include/aocharmovie.h b/include/aocharmovie.h index 5eaafaf..d066a39 100644 --- a/include/aocharmovie.h +++ b/include/aocharmovie.h @@ -17,12 +17,6 @@ class AOCharMovie : public QLabel public: AOCharMovie(QWidget *p_parent, AOApplication *p_ao_app); - //Set the movie's image to provided paths, preparing for playback. - void load_image(QString p_char, QString p_emote, QString emote_prefix); - - //Start playback of the movie (if animated). - void play(); - //Play a hat.gif - style preanimation void play_pre(QString p_char, QString p_emote, int duration); @@ -32,15 +26,6 @@ public: //Play an (a)normal.gif - style animation (not talking) void play_idle(QString p_char, QString p_emote); - //Play a frame-specific effect, if there's any defined for that specific frame. - void play_frame_effect(int frame); - - //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); - //Stop the movie, clearing the image void stop(); @@ -59,6 +44,8 @@ public: //Return the frame delay adjusted for speed int get_frame_delay(int delay); + QStringList network_strings; + private: AOApplication *ao_app; @@ -75,6 +62,9 @@ private: QString last_path; QImageReader *m_reader = new QImageReader(); + QString m_char; + QString m_emote; + QElapsedTimer actual_time; const int time_mod = 60; @@ -90,6 +80,27 @@ private: bool m_flipped = false; bool play_once = true; + //Set the movie's image to provided paths, preparing for playback. + void load_image(QString p_char, QString p_emote, QString emote_prefix); + + //Start playback of the movie (if animated). + void play(); + + //Play a frame-specific effect, if there's any defined for that specific frame. + void play_frame_effect(int frame); + + //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); + + //Initialize the frame-specific effects from the char.ini + void load_effects(); + + //Initialize the frame-specific effects from the provided network_strings, this is only initialized if network_strings has size more than 0. + void load_network_effects(); + signals: void done(); void shake(); diff --git a/src/aocharmovie.cpp b/src/aocharmovie.cpp index d67cf98..34c6c81 100644 --- a/src/aocharmovie.cpp +++ b/src/aocharmovie.cpp @@ -64,39 +64,13 @@ void AOCharMovie::load_image(QString p_char, QString p_emote, QString emote_pref movie_delays.append(f_delay); } - movie_effects.resize(max_frames); - for (int e_frame = 0; e_frame < max_frames; ++e_frame) - { -#ifdef DEBUG_CHARMOVIE - qDebug() << p_char << p_emote << e_frame; -#endif - QString effect = ao_app->get_screenshake_frame(p_char, emote_prefix + p_emote, e_frame); - if (effect != "") - { - movie_effects[e_frame].append("shake"); -#ifdef DEBUG_CHARMOVIE - qDebug() << e_frame << "shake"; -#endif - } + m_char = p_char; + m_emote = emote_prefix + p_emote; - effect = ao_app->get_flash_frame(p_char, emote_prefix + p_emote, e_frame); - if (effect != "") - { - movie_effects[e_frame].append("flash"); -#ifdef DEBUG_CHARMOVIE - qDebug() << e_frame << "flash"; -#endif - } - - effect = ao_app->get_sfx_frame(p_char, emote_prefix + p_emote, e_frame); - if (effect != "") - { - movie_effects[e_frame].append("sfx^"+effect); -#ifdef DEBUG_CHARMOVIE - qDebug() << e_frame << effect; -#endif - } - } + if (network_strings.size() > 0) //our FX overwritten by networked ones + this->load_network_effects(); + else //Use default ini FX + this->load_effects(); #ifdef DEBUG_CHARMOVIE qDebug() << max_frames << "Setting image to " << emote_path << "Time taken to process image:" << actual_time.elapsed(); @@ -104,6 +78,77 @@ void AOCharMovie::load_image(QString p_char, QString p_emote, QString emote_pref #endif } +void AOCharMovie::load_effects() +{ + movie_effects.clear(); + 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); + if (effect != "") + { + movie_effects[e_frame].append("shake"); + } + + effect = ao_app->get_flash_frame(m_char, m_emote, e_frame); + if (effect != "") + { + movie_effects[e_frame].append("flash"); + } + + effect = ao_app->get_sfx_frame(m_char, m_emote, e_frame); + if (effect != "") + { + movie_effects[e_frame].append("sfx^"+effect); + } + } +} + +void AOCharMovie::load_network_effects() +{ + movie_effects.clear(); + movie_effects.resize(max_frames); + //Order is important!!! + QStringList effects_list = {"shake", "flash", "sfx^"}; + + //Determines which list is smaller - effects_list or network_strings - and uses it as basis for the loop. + //This way, incomplete network_strings would still be parsed, and excess/unaccounted for networked information is omitted. + int effects_size = qMin(effects_list.size(), network_strings.size()); + + for (int i = 0; i < effects_size; ++i) + { + QString netstring = network_strings.at(i); + QStringList emote_splits = netstring.split("^"); + foreach (QString emote, emote_splits) + { + QStringList parsed = emote.split("|"); + if (parsed.size() <= 0 || parsed.at(0) != m_emote) + continue; + foreach (QString frame_data, parsed) + { + QStringList frame_split = frame_data.split("="); + if (frame_split.size() <= 1) //We might still be hanging at the emote itself (entry 0). + continue; + int f_frame = frame_split.at(0).toInt(); + if (f_frame >= max_frames) + { + qDebug() << "Warning: out of bounds" << effects_list[i] << "frame" << f_frame << "out of" << max_frames << "for" << m_char << m_emote; + continue; + } + QString f_data = frame_split.at(1); + if (f_data != "") + { + QString effect = effects_list[i]; + if (effect == "sfx^") //Currently the only frame result that feeds us data, let's yank it in. + effect += f_data; + qDebug() << effect << f_data << "frame" << f_frame << "for" << m_char << m_emote; + movie_effects[f_frame].append(effect); + } + } + } + } +} + void AOCharMovie::play() { play_frame_effect(frame); diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 2aa82b5..2e4fbb2 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1267,41 +1267,31 @@ void Courtroom::on_chat_return_pressed() packet_contents.append(QString::number(screenshake_state)); qDebug() << "Are we screen shaking this one? " << screenshake_state; - QString frame_screenshake = ""; - QString frame_realization = ""; - QString frame_sfx = ""; + 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"}; - QString preemote_sfx = ao_app->get_pre_emote(current_char, current_emote) + "^"; - QString preemote_shake = ao_app->get_pre_emote(current_char, current_emote) + "^"; - QString preemote_flash = ao_app->get_pre_emote(current_char, current_emote) + "^"; + foreach (QString f_effect, effects_to_check) + { + QString packet; + foreach (QString f_emote, emotes_to_check) + { + packet += f_emote; + QString sfx_frames = ao_app->read_char_ini_tag(current_char, f_emote.append(f_effect)).join("|"); + if (sfx_frames != "") + packet += "|" + sfx_frames; + packet += "^"; + } + qDebug() << f_effect << "packet" << packet; + packet_contents.append(packet); + } - QString talkemote_sfx = "(b)" + ao_app->get_emote(current_char, current_emote) + "^"; - QString talkemote_shake = "(b)" + ao_app->get_emote(current_char, current_emote) + "^"; - QString talkemote_flash = "(b)" + ao_app->get_emote(current_char, current_emote) + "^"; + //"roar|thing=thong^(b)roar^(a)roar^" - QString idleemote_sfx = "(a)" + ao_app->get_emote(current_char, current_emote) + "^"; - QString idleemote_shake = "(a)" + ao_app->get_emote(current_char, current_emote) + "^"; - QString idleemote_flash = "(a)" + ao_app->get_emote(current_char, current_emote) + "^"; - - frame_screenshake += preemote_shake; - frame_screenshake += talkemote_shake; - frame_screenshake += idleemote_shake; - - frame_realization += preemote_flash; - frame_realization += talkemote_flash; - frame_realization += idleemote_flash; - - frame_sfx += preemote_sfx; - frame_sfx += talkemote_sfx; - frame_sfx += idleemote_sfx; - qDebug() << "Final strings:"; - qDebug() << frame_screenshake; - qDebug() << frame_realization; - qDebug() << frame_sfx; - - packet_contents.append(frame_screenshake); - packet_contents.append(frame_realization); - packet_contents.append(frame_sfx); +// packet_contents.append(frame_screenshake); +// packet_contents.append(frame_realization); +// packet_contents.append(frame_sfx); } ao_app->send_server_packet(new AOPacket("MS", packet_contents)); } @@ -1447,6 +1437,15 @@ void Courtroom::handle_chatmessage_2() //Clear all looping sfx to prevent obnoxiousness sfx_player->loop_clear(); + if (!m_chatmessage[FRAME_SFX].isEmpty()) + { + //ORDER IS IMPORTANT!! + QStringList netstrings = {m_chatmessage[FRAME_SCREENSHAKE], m_chatmessage[FRAME_REALIZATION], m_chatmessage[FRAME_SFX]}; + ui_vp_player_char->network_strings = netstrings; + } + else + ui_vp_player_char->network_strings.clear(); + if (m_chatmessage[SHOWNAME].isEmpty() || !ui_showname_enable->isChecked()) { QString real_name = char_list.at(m_chatmessage[CHAR_ID].toInt()).name; @@ -1673,11 +1672,9 @@ void Courtroom::do_screenshake() ui_vp_chatbox }; - int i = 0; //I would prefer if this was its own "shake" function to be honest. foreach (QWidget* ui_element, affected_list) { - qDebug() << ++i; QPropertyAnimation *screenshake_animation = new QPropertyAnimation(ui_element, "pos", this); QPoint pos_default = QPoint(ui_element->x(), ui_element->y()); diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index 3d557c6..4c0885e 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -406,6 +406,22 @@ QString AOApplication::read_char_ini(QString p_char, QString p_search_line, QStr return value; } +//returns all the values of target_tag +QStringList AOApplication::read_char_ini_tag(QString p_char, QString target_tag) +{ + QStringList r_values; + QSettings settings(get_character_path(p_char, "char.ini"), QSettings::IniFormat); + settings.beginGroup(target_tag); + QStringList keys = settings.allKeys(); + foreach (QString key, keys) + { + QString value = settings.value(key).toString(); + r_values << key + "=" + value; + } + settings.endGroup(); + return r_values; +} + QString AOApplication::get_char_name(QString p_char) { QString f_result = read_char_ini(p_char, "name", "Options"); From ba28c244aa7591892abb2699cdc547ec431543a7 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sun, 15 Sep 2019 21:15:40 +0300 Subject: [PATCH 037/268] Add an opton to enable/disable screenshake + flashing Fix moderation guard button not doing what it's supposed to (enable/disable modcalls) Fix moderation guard button appearing with failed logins Fix the option to toggle looping sfx not doing anything --- include/aoapplication.h | 4 ++++ include/aooptionsdialog.h | 5 +++++ src/courtroom.cpp | 26 +++++++++++++++++--------- src/text_file_functions.cpp | 6 ++++++ 4 files changed, 32 insertions(+), 9 deletions(-) diff --git a/include/aoapplication.h b/include/aoapplication.h index eb12b0c..6bc86e6 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -170,6 +170,10 @@ public: // from the config.ini. bool is_discord_enabled(); + // Returns the value of whether shaking and flashing should be enabled. + // from the config.ini. + bool is_shake_flash_enabled(); + // Returns the value of the maximum amount of lines the IC chatlog // may contain, from config.ini. int get_max_log_size(); diff --git a/include/aooptionsdialog.h b/include/aooptionsdialog.h index 34ae2b7..0deb0a8 100644 --- a/include/aooptionsdialog.h +++ b/include/aooptionsdialog.h @@ -64,6 +64,9 @@ private: QLabel *ui_language_label; QComboBox *ui_language_combobox; + QLabel *ui_epilepsy_lbl; + QCheckBox *ui_epilepsy_cb; + QWidget *ui_callwords_tab; QWidget *ui_callwords_widget; QVBoxLayout *ui_callwords_layout; @@ -88,6 +91,8 @@ private: QLabel *ui_bliprate_lbl; QCheckBox *ui_blank_blips_cb; QLabel *ui_blank_blips_lbl; + QLabel *ui_loopsfx_lbl; + QCheckBox *ui_loopsfx_cb; QLabel *ui_objectmusic_lbl; QCheckBox *ui_objectmusic_cb; QDialogButtonBox *ui_settings_buttons; diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 2e4fbb2..d7d1ff5 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1081,6 +1081,11 @@ void Courtroom::append_server_chatmessage(QString p_name, QString p_message, QSt colour = ao_app->get_color("ooc_default_color", "courtroom_design.ini").name(); if (p_colour == "1") colour = ao_app->get_color("ooc_server_color", "courtroom_design.ini").name(); + if(p_message == "Logged in as a moderator.") + { + ui_guard->show(); + append_server_chatmessage("CLIENT", "You were granted the Disable Modcalls button.", "1"); + } ui_server_chatlog->append_chatmessage(p_name, p_message, colour); } @@ -1659,6 +1664,9 @@ void Courtroom::handle_chatmessage_2() void Courtroom::do_screenshake() { + if(!ao_app->is_shake_flash_enabled()) + return; + //This way, the animation is reset in such a way that last played screenshake would return to its "final frame" properly. //This properly resets all UI elements without having to bother keeping track of "origin" positions. //Works great wit the chat text being detached from the chat box! @@ -1702,13 +1710,17 @@ void Courtroom::do_screenshake() void Courtroom::do_flash() { + if(!ao_app->is_shake_flash_enabled()) + return; + ui_vp_realization->play("realizationflash", "", "", 60); } void Courtroom::play_char_sfx(QString sfx_name) { sfx_player->play(ao_app->get_sfx_suffix(sfx_name)); - sfx_player->set_looping(ao_app->get_sfx_looping(current_char, sfx_name)!="0"); + if(ao_app->get_looping_sfx()) + sfx_player->set_looping(ao_app->get_sfx_looping(current_char, sfx_name)!="0"); } void Courtroom::handle_chatmessage_3() @@ -2451,7 +2463,7 @@ void Courtroom::chat_tick() // If we had a formatting char, we shouldn't wait so long again, as it won't appear! if (formatting_char) { - chat_tick_timer->start(1); + chat_tick_timer->start(0); } else { @@ -2469,7 +2481,8 @@ void Courtroom::play_sfx() return; sfx_player->play(ao_app->get_sfx_suffix(sfx_name)); - sfx_player->set_looping(ao_app->get_sfx_looping(current_char, sfx_name)!="0"); + if(ao_app->get_looping_sfx()) + sfx_player->set_looping(ao_app->get_sfx_looping(current_char, sfx_name)!="0"); } void Courtroom::set_scene() @@ -2765,7 +2778,7 @@ void Courtroom::toggle_judge_buttons(bool is_on) void Courtroom::mod_called(QString p_ip) { ui_server_chatlog->append(p_ip); - if (ui_guard->isChecked()) + if (!ui_guard->isChecked()) { modcall_player->play(ao_app->get_sfx("mod_call")); ao_app->alert(this); @@ -2807,11 +2820,6 @@ void Courtroom::on_ooc_return_pressed() toggle_judge_buttons(false); } } - else if (ooc_message.startsWith("/login")) - { - ui_guard->show(); - append_server_chatmessage("CLIENT", tr("You were granted the Guard button."), "1"); - } else if (ooc_message.startsWith("/rainbow") && ao_app->yellow_text_enabled && !rainbow_appended) { //ui_text_color->addItem("Rainbow"); diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index 4c0885e..750df01 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -672,6 +672,12 @@ bool AOApplication::is_discord_enabled() return result.startsWith("true"); } +bool AOApplication::is_shake_flash_enabled() +{ + QString result = configini->value("shakeandflash", "true").value(); + return result.startsWith("true"); +} + bool AOApplication::get_casing_enabled() { QString result = configini->value("casing_enabled", "false").value(); From 6afce056618d17aa770b6aa51eea477468aad8ab Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sun, 15 Sep 2019 21:17:12 +0300 Subject: [PATCH 038/268] Adjust options dialog to use a "row" variable for adding new elements easier Add the "allow shake/flash" button Add the "enable looping SFX" button --- src/aooptionsdialog.cpp | 170 ++++++++++++++++++++++++++-------------- 1 file changed, 110 insertions(+), 60 deletions(-) diff --git a/src/aooptionsdialog.cpp b/src/aooptionsdialog.cpp index a918c0c..259f43e 100644 --- a/src/aooptionsdialog.cpp +++ b/src/aooptionsdialog.cpp @@ -46,14 +46,15 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi ui_gameplay_form->setFormAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop); ui_gameplay_form->setContentsMargins(0, 0, 0, 0); + int row = 0; + ui_theme_label = new QLabel(ui_form_layout_widget); ui_theme_label->setText(tr("Theme:")); ui_theme_label->setToolTip(tr("Sets the theme used in-game. If the new theme changes " "the lobby's look as well, you'll need to reload the " "lobby for the changes to take effect, such as by joining " "a server and leaving it.")); - ui_gameplay_form->setWidget(0, QFormLayout::LabelRole, ui_theme_label); - + ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_theme_label); ui_theme_combobox = new QComboBox(ui_form_layout_widget); // Fill the combobox with the names of the themes. @@ -67,14 +68,15 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi ui_theme_combobox->setCurrentIndex(ui_theme_combobox->count()-1); } - ui_gameplay_form->setWidget(0, QFormLayout::FieldRole, ui_theme_combobox); + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_theme_combobox); ui_theme_log_divider = new QFrame(ui_form_layout_widget); ui_theme_log_divider->setMidLineWidth(0); ui_theme_log_divider->setFrameShape(QFrame::HLine); ui_theme_log_divider->setFrameShadow(QFrame::Sunken); - ui_gameplay_form->setWidget(1, QFormLayout::FieldRole, ui_theme_log_divider); + row += 1; + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_theme_log_divider); ui_downwards_lbl = new QLabel(ui_form_layout_widget); ui_downwards_lbl->setText(tr("Log goes downwards:")); @@ -82,44 +84,48 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi "the bottom (like the OOC chatlog). The traditional " "(AO1) behaviour is equivalent to this being unticked.")); - ui_gameplay_form->setWidget(2, QFormLayout::LabelRole, ui_downwards_lbl); + row += 1; + ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_downwards_lbl); ui_downwards_cb = new QCheckBox(ui_form_layout_widget); ui_downwards_cb->setChecked(p_ao_app->get_log_goes_downwards()); - ui_gameplay_form->setWidget(2, QFormLayout::FieldRole, ui_downwards_cb); + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_downwards_cb); ui_length_lbl = new QLabel(ui_form_layout_widget); ui_length_lbl->setText(tr("Log length:")); ui_length_lbl->setToolTip(tr("The amount of messages the IC chatlog will keep before " "deleting older messages. A value of 0 or below counts as 'infinite'.")); - ui_gameplay_form->setWidget(3, QFormLayout::LabelRole, ui_length_lbl); + row += 1; + ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_length_lbl); ui_length_spinbox = new QSpinBox(ui_form_layout_widget); ui_length_spinbox->setMaximum(10000); ui_length_spinbox->setValue(p_ao_app->get_max_log_size()); - ui_gameplay_form->setWidget(3, QFormLayout::FieldRole, ui_length_spinbox); + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_length_spinbox); ui_log_names_divider = new QFrame(ui_form_layout_widget); ui_log_names_divider->setFrameShape(QFrame::HLine); ui_log_names_divider->setFrameShadow(QFrame::Sunken); - ui_gameplay_form->setWidget(4, QFormLayout::FieldRole, ui_log_names_divider); + row += 1; + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_log_names_divider); ui_username_lbl = new QLabel(ui_form_layout_widget); ui_username_lbl->setText(tr("Default username:")); ui_username_lbl->setToolTip(tr("Your OOC name will be automatically set to this value " "when you join a server.")); - ui_gameplay_form->setWidget(5, QFormLayout::LabelRole, ui_username_lbl); + row += 1; + ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_username_lbl); ui_username_textbox = new QLineEdit(ui_form_layout_widget); ui_username_textbox->setMaxLength(30); ui_username_textbox->setText(p_ao_app->get_default_username()); - ui_gameplay_form->setWidget(5, QFormLayout::FieldRole, ui_username_textbox); + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_username_textbox); ui_showname_lbl = new QLabel(ui_form_layout_widget); ui_showname_lbl->setText(tr("Custom shownames:")); @@ -127,31 +133,34 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi "tickbox, which in turn determines whether the client should " "display custom in-character names.")); - ui_gameplay_form->setWidget(6, QFormLayout::LabelRole, ui_showname_lbl); + row += 1; + ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_showname_lbl); ui_showname_cb = new QCheckBox(ui_form_layout_widget); ui_showname_cb->setChecked(p_ao_app->get_showname_enabled_by_default()); - ui_gameplay_form->setWidget(6, QFormLayout::FieldRole, ui_showname_cb); + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_showname_cb); ui_net_divider = new QFrame(ui_form_layout_widget); ui_net_divider->setFrameShape(QFrame::HLine); ui_net_divider->setFrameShadow(QFrame::Sunken); - ui_gameplay_form->setWidget(7, QFormLayout::FieldRole, ui_net_divider); + row += 1; + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_net_divider); ui_ms_lbl = new QLabel(ui_form_layout_widget); ui_ms_lbl->setText(tr("Backup MS:")); ui_ms_lbl->setToolTip(tr("If the built-in server lookups fail, the game will try the " "address given here and use it as a backup master server address.")); - ui_gameplay_form->setWidget(8, QFormLayout::LabelRole, ui_ms_lbl); + row += 1; + ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_ms_lbl); QSettings* configini = ao_app->configini; ui_ms_textbox = new QLineEdit(ui_form_layout_widget); ui_ms_textbox->setText(configini->value("master", "").value()); - ui_gameplay_form->setWidget(8, QFormLayout::FieldRole, ui_ms_textbox); + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_ms_textbox); ui_discord_lbl = new QLabel(ui_form_layout_widget); ui_discord_lbl->setText(tr("Discord:")); @@ -159,17 +168,19 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi "what character are you playing, and how long you have " "been playing for.")); - ui_gameplay_form->setWidget(9, QFormLayout::LabelRole, ui_discord_lbl); + row += 1; + ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_discord_lbl); ui_discord_cb = new QCheckBox(ui_form_layout_widget); ui_discord_cb->setChecked(ao_app->is_discord_enabled()); - ui_gameplay_form->setWidget(9, QFormLayout::FieldRole, ui_discord_cb); + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_discord_cb); + row += 1; ui_language_label = new QLabel(ui_form_layout_widget); ui_language_label->setText(tr("Language:")); ui_language_label->setToolTip(tr("Sets the language if you don't want to use your system language.")); - ui_gameplay_form->setWidget(10, QFormLayout::LabelRole, ui_language_label); + ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_language_label); ui_language_combobox = new QComboBox(ui_form_layout_widget); ui_language_combobox->addItem(configini->value("language", " ").value() + " - Keep current setting"); @@ -179,7 +190,19 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi ui_language_combobox->addItem("es - Español"); ui_language_combobox->addItem("jp - 日本語"); ui_language_combobox->addItem("ru - Русский"); - ui_gameplay_form->setWidget(10, QFormLayout::FieldRole, ui_language_combobox); + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_language_combobox); + + ui_epilepsy_lbl = new QLabel(ui_form_layout_widget); + ui_epilepsy_lbl->setText(tr("Allow Shake/Flash:")); + ui_epilepsy_lbl->setToolTip(tr("Allows screenshaking and flashing. Disable this if you have concerns or issues with photosensitivity and/or seizures.")); + + row += 1; + ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_epilepsy_lbl); + + ui_epilepsy_cb = new QCheckBox(ui_form_layout_widget); + ui_epilepsy_cb->setChecked(ao_app->is_shake_flash_enabled()); + + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_epilepsy_cb); // Here we start the callwords tab. ui_callwords_tab = new QWidget(); @@ -223,12 +246,13 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi ui_audio_layout->setLabelAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter); ui_audio_layout->setFormAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop); ui_audio_layout->setContentsMargins(0, 0, 0, 0); + row = 0; ui_audio_device_lbl = new QLabel(ui_audio_widget); ui_audio_device_lbl->setText(tr("Audio device:")); ui_audio_device_lbl->setToolTip(tr("Sets the audio device for all sounds.")); - ui_audio_layout->setWidget(0, QFormLayout::LabelRole, ui_audio_device_lbl); + ui_audio_layout->setWidget(row, QFormLayout::LabelRole, ui_audio_device_lbl); ui_audio_device_combobox = new QComboBox(ui_audio_widget); @@ -256,65 +280,70 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi ui_audio_device_combobox->setCurrentIndex(ui_audio_device_combobox->count()-1); } #endif - ui_audio_layout->setWidget(0, QFormLayout::FieldRole, ui_audio_device_combobox); + ui_audio_layout->setWidget(row, QFormLayout::FieldRole, ui_audio_device_combobox); ui_audio_volume_divider = new QFrame(ui_audio_widget); ui_audio_volume_divider->setFrameShape(QFrame::HLine); ui_audio_volume_divider->setFrameShadow(QFrame::Sunken); - ui_audio_layout->setWidget(1, QFormLayout::FieldRole, ui_audio_volume_divider); + row += 1; + ui_audio_layout->setWidget(row, QFormLayout::FieldRole, ui_audio_volume_divider); ui_music_volume_lbl = new QLabel(ui_audio_widget); ui_music_volume_lbl->setText(tr("Music:")); ui_music_volume_lbl->setToolTip(tr("Sets the music's default volume.")); - ui_audio_layout->setWidget(2, QFormLayout::LabelRole, ui_music_volume_lbl); + row += 1; + ui_audio_layout->setWidget(row, QFormLayout::LabelRole, ui_music_volume_lbl); ui_music_volume_spinbox = new QSpinBox(ui_audio_widget); ui_music_volume_spinbox->setValue(p_ao_app->get_default_music()); ui_music_volume_spinbox->setMaximum(100); ui_music_volume_spinbox->setSuffix("%"); - ui_audio_layout->setWidget(2, QFormLayout::FieldRole, ui_music_volume_spinbox); + ui_audio_layout->setWidget(row, QFormLayout::FieldRole, ui_music_volume_spinbox); ui_sfx_volume_lbl = new QLabel(ui_audio_widget); ui_sfx_volume_lbl->setText(tr("SFX:")); ui_sfx_volume_lbl->setToolTip(tr("Sets the SFX's default volume. " "Interjections and actual sound effects count as 'SFX'.")); - - ui_audio_layout->setWidget(3, QFormLayout::LabelRole, ui_sfx_volume_lbl); + row += 1; + ui_audio_layout->setWidget(row, QFormLayout::LabelRole, ui_sfx_volume_lbl); ui_sfx_volume_spinbox = new QSpinBox(ui_audio_widget); ui_sfx_volume_spinbox->setValue(p_ao_app->get_default_sfx()); ui_sfx_volume_spinbox->setMaximum(100); ui_sfx_volume_spinbox->setSuffix("%"); - ui_audio_layout->setWidget(3, QFormLayout::FieldRole, ui_sfx_volume_spinbox); + ui_audio_layout->setWidget(row, QFormLayout::FieldRole, ui_sfx_volume_spinbox); ui_blips_volume_lbl = new QLabel(ui_audio_widget); ui_blips_volume_lbl->setText(tr("Blips:")); ui_blips_volume_lbl->setToolTip(tr("Sets the volume of the blips, the talking sound effects.")); - ui_audio_layout->setWidget(4, QFormLayout::LabelRole, ui_blips_volume_lbl); + row += 1; + ui_audio_layout->setWidget(row, QFormLayout::LabelRole, ui_blips_volume_lbl); ui_blips_volume_spinbox = new QSpinBox(ui_audio_widget); ui_blips_volume_spinbox->setValue(p_ao_app->get_default_blip()); ui_blips_volume_spinbox->setMaximum(100); ui_blips_volume_spinbox->setSuffix("%"); - ui_audio_layout->setWidget(4, QFormLayout::FieldRole, ui_blips_volume_spinbox); + ui_audio_layout->setWidget(row, QFormLayout::FieldRole, ui_blips_volume_spinbox); ui_volume_blip_divider = new QFrame(ui_audio_widget); ui_volume_blip_divider->setFrameShape(QFrame::HLine); ui_volume_blip_divider->setFrameShadow(QFrame::Sunken); - ui_audio_layout->setWidget(5, QFormLayout::FieldRole, ui_volume_blip_divider); + row += 1; + ui_audio_layout->setWidget(row, QFormLayout::FieldRole, ui_volume_blip_divider); ui_bliprate_lbl = new QLabel(ui_audio_widget); ui_bliprate_lbl->setText(tr("Blip rate:")); ui_bliprate_lbl->setToolTip(tr("Sets the delay between playing the blip sounds.")); - ui_audio_layout->setWidget(6, QFormLayout::LabelRole, ui_bliprate_lbl); + row += 1; + ui_audio_layout->setWidget(row, QFormLayout::LabelRole, ui_bliprate_lbl); ui_bliprate_spinbox = new QSpinBox(ui_audio_widget); ui_bliprate_spinbox->setValue(p_ao_app->read_blip_rate()); @@ -322,30 +351,44 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi ui_bliprate_spinbox->setToolTip(tr("Play a blip sound \"once per every X symbols\", where " "X is the blip rate.")); - ui_audio_layout->setWidget(6, QFormLayout::FieldRole, ui_bliprate_spinbox); + ui_audio_layout->setWidget(row, QFormLayout::FieldRole, ui_bliprate_spinbox); ui_blank_blips_lbl = new QLabel(ui_audio_widget); ui_blank_blips_lbl->setText(tr("Blank blips:")); ui_blank_blips_lbl->setToolTip(tr("If true, the game will play a blip sound even " "when a space is 'being said'.")); - ui_audio_layout->setWidget(7, QFormLayout::LabelRole, ui_blank_blips_lbl); + row += 1; + ui_audio_layout->setWidget(row, QFormLayout::LabelRole, ui_blank_blips_lbl); ui_blank_blips_cb = new QCheckBox(ui_audio_widget); ui_blank_blips_cb->setChecked(p_ao_app->get_blank_blip()); - ui_audio_layout->setWidget(7, QFormLayout::FieldRole, ui_blank_blips_cb); + ui_audio_layout->setWidget(row, QFormLayout::FieldRole, ui_blank_blips_cb); + + ui_loopsfx_lbl = new QLabel(ui_audio_widget); + ui_loopsfx_lbl->setText(tr("Enable Looping SFX:")); + ui_loopsfx_lbl->setToolTip(tr("If true, the game will allow looping sound effects to play on preanimations.")); + + row += 1; + ui_audio_layout->setWidget(row, QFormLayout::LabelRole, ui_loopsfx_lbl); + + ui_loopsfx_cb = new QCheckBox(ui_audio_widget); + ui_loopsfx_cb->setChecked(p_ao_app->get_looping_sfx()); + + ui_audio_layout->setWidget(row, QFormLayout::FieldRole, ui_loopsfx_cb); ui_objectmusic_lbl = new QLabel(ui_audio_widget); ui_objectmusic_lbl->setText(tr("Kill Music On Objection:")); - ui_objectmusic_lbl->setToolTip(tr("If true, the game will stop music when someone objects, like in the actual games.")); + ui_objectmusic_lbl->setToolTip(tr("If true, AO2 will stop the music for you when you or someone else does 'Objection!'.")); - ui_audio_layout->setWidget(9, QFormLayout::LabelRole, ui_objectmusic_lbl); + row += 1; + ui_audio_layout->setWidget(row, QFormLayout::LabelRole, ui_objectmusic_lbl); ui_objectmusic_cb = new QCheckBox(ui_audio_widget); ui_objectmusic_cb->setChecked(p_ao_app->objection_stop_music()); - ui_audio_layout->setWidget(9, QFormLayout::FieldRole, ui_objectmusic_cb); + ui_audio_layout->setWidget(row, QFormLayout::FieldRole, ui_objectmusic_cb); // The casing tab! ui_casing_tab = new QWidget(); @@ -358,6 +401,7 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi ui_casing_layout->setLabelAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter); ui_casing_layout->setFormAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop); ui_casing_layout->setContentsMargins(0, 0, 0, 0); + row = 0; // -- SERVER SUPPORTS CASING @@ -368,119 +412,127 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi ui_casing_supported_lbl->setText(tr("This server does not support case alerts.")); ui_casing_supported_lbl->setToolTip(tr("Pretty self-explanatory.")); - ui_casing_layout->setWidget(0, QFormLayout::FieldRole, ui_casing_supported_lbl); + ui_casing_layout->setWidget(row, QFormLayout::FieldRole, ui_casing_supported_lbl); // -- CASE ANNOUNCEMENTS + row += 1; ui_casing_enabled_lbl = new QLabel(ui_casing_widget); ui_casing_enabled_lbl->setText(tr("Casing:")); ui_casing_enabled_lbl->setToolTip(tr("If checked, you will get alerts about case " "announcements.")); - ui_casing_layout->setWidget(1, QFormLayout::LabelRole, ui_casing_enabled_lbl); + ui_casing_layout->setWidget(row, QFormLayout::LabelRole, ui_casing_enabled_lbl); ui_casing_enabled_cb = new QCheckBox(ui_casing_widget); ui_casing_enabled_cb->setChecked(ao_app->get_casing_enabled()); - ui_casing_layout->setWidget(1, QFormLayout::FieldRole, ui_casing_enabled_cb); + ui_casing_layout->setWidget(row, QFormLayout::FieldRole, ui_casing_enabled_cb); // -- DEFENSE ANNOUNCEMENTS + row += 1; ui_casing_def_lbl = new QLabel(ui_casing_widget); ui_casing_def_lbl->setText(tr("Defense:")); ui_casing_def_lbl->setToolTip(tr("If checked, you will get alerts about case " "announcements if a defense spot is open.")); - ui_casing_layout->setWidget(2, QFormLayout::LabelRole, ui_casing_def_lbl); + ui_casing_layout->setWidget(row, QFormLayout::LabelRole, ui_casing_def_lbl); ui_casing_def_cb = new QCheckBox(ui_casing_widget); ui_casing_def_cb->setChecked(ao_app->get_casing_defence_enabled()); - ui_casing_layout->setWidget(2, QFormLayout::FieldRole, ui_casing_def_cb); + ui_casing_layout->setWidget(row, QFormLayout::FieldRole, ui_casing_def_cb); // -- PROSECUTOR ANNOUNCEMENTS + row += 1; ui_casing_pro_lbl = new QLabel(ui_casing_widget); ui_casing_pro_lbl->setText(tr("Prosecution:")); ui_casing_pro_lbl->setToolTip(tr("If checked, you will get alerts about case " "announcements if a prosecutor spot is open.")); - ui_casing_layout->setWidget(3, QFormLayout::LabelRole, ui_casing_pro_lbl); + ui_casing_layout->setWidget(row, QFormLayout::LabelRole, ui_casing_pro_lbl); ui_casing_pro_cb = new QCheckBox(ui_casing_widget); ui_casing_pro_cb->setChecked(ao_app->get_casing_prosecution_enabled()); - ui_casing_layout->setWidget(3, QFormLayout::FieldRole, ui_casing_pro_cb); + ui_casing_layout->setWidget(row, QFormLayout::FieldRole, ui_casing_pro_cb); // -- JUDGE ANNOUNCEMENTS + row += 1; ui_casing_jud_lbl = new QLabel(ui_casing_widget); ui_casing_jud_lbl->setText(tr("Judge:")); ui_casing_jud_lbl->setToolTip(tr("If checked, you will get alerts about case " "announcements if the judge spot is open.")); - ui_casing_layout->setWidget(4, QFormLayout::LabelRole, ui_casing_jud_lbl); + ui_casing_layout->setWidget(row, QFormLayout::LabelRole, ui_casing_jud_lbl); ui_casing_jud_cb = new QCheckBox(ui_casing_widget); ui_casing_jud_cb->setChecked(ao_app->get_casing_judge_enabled()); - ui_casing_layout->setWidget(4, QFormLayout::FieldRole, ui_casing_jud_cb); + ui_casing_layout->setWidget(row, QFormLayout::FieldRole, ui_casing_jud_cb); // -- JUROR ANNOUNCEMENTS + row += 1; ui_casing_jur_lbl = new QLabel(ui_casing_widget); ui_casing_jur_lbl->setText(tr("Juror:")); ui_casing_jur_lbl->setToolTip(tr("If checked, you will get alerts about case " "announcements if a juror spot is open.")); - ui_casing_layout->setWidget(5, QFormLayout::LabelRole, ui_casing_jur_lbl); + ui_casing_layout->setWidget(row, QFormLayout::LabelRole, ui_casing_jur_lbl); ui_casing_jur_cb = new QCheckBox(ui_casing_widget); ui_casing_jur_cb->setChecked(ao_app->get_casing_juror_enabled()); - ui_casing_layout->setWidget(5, QFormLayout::FieldRole, ui_casing_jur_cb); + ui_casing_layout->setWidget(row, QFormLayout::FieldRole, ui_casing_jur_cb); // -- STENO ANNOUNCEMENTS + row += 1; ui_casing_steno_lbl = new QLabel(ui_casing_widget); ui_casing_steno_lbl->setText(tr("Stenographer:")); ui_casing_steno_lbl->setToolTip(tr("If checked, you will get alerts about case " "announcements if a stenographer spot is open.")); - ui_casing_layout->setWidget(6, QFormLayout::LabelRole, ui_casing_steno_lbl); + ui_casing_layout->setWidget(row, QFormLayout::LabelRole, ui_casing_steno_lbl); ui_casing_steno_cb = new QCheckBox(ui_casing_widget); ui_casing_steno_cb->setChecked(ao_app->get_casing_steno_enabled()); - ui_casing_layout->setWidget(6, QFormLayout::FieldRole, ui_casing_steno_cb); + ui_casing_layout->setWidget(row, QFormLayout::FieldRole, ui_casing_steno_cb); // -- CM ANNOUNCEMENTS + row += 1; ui_casing_cm_lbl = new QLabel(ui_casing_widget); ui_casing_cm_lbl->setText(tr("CM:")); ui_casing_cm_lbl->setToolTip(tr("If checked, you will appear amongst the potential " "CMs on the server.")); - ui_casing_layout->setWidget(7, QFormLayout::LabelRole, ui_casing_cm_lbl); + ui_casing_layout->setWidget(row, QFormLayout::LabelRole, ui_casing_cm_lbl); ui_casing_cm_cb = new QCheckBox(ui_casing_widget); ui_casing_cm_cb->setChecked(ao_app->get_casing_cm_enabled()); - ui_casing_layout->setWidget(7, QFormLayout::FieldRole, ui_casing_cm_cb); + ui_casing_layout->setWidget(row, QFormLayout::FieldRole, ui_casing_cm_cb); // -- CM CASES ANNOUNCEMENTS + row += 1; ui_casing_cm_cases_lbl = new QLabel(ui_casing_widget); ui_casing_cm_cases_lbl->setText(tr("Hosting cases:")); ui_casing_cm_cases_lbl->setToolTip(tr("If you're a CM, enter what cases you are " "willing to host.")); - ui_casing_layout->setWidget(8, QFormLayout::LabelRole, ui_casing_cm_cases_lbl); + ui_casing_layout->setWidget(row, QFormLayout::LabelRole, ui_casing_cm_cases_lbl); ui_casing_cm_cases_textbox = new QLineEdit(ui_casing_widget); ui_casing_cm_cases_textbox->setText(ao_app->get_casing_can_host_cases()); - ui_casing_layout->setWidget(8, QFormLayout::FieldRole, ui_casing_cm_cases_textbox); + ui_casing_layout->setWidget(row, QFormLayout::FieldRole, ui_casing_cm_cases_textbox); // When we're done, we should continue the updates! setUpdatesEnabled(true); @@ -499,14 +551,11 @@ void AOOptionsDialog::save_pressed() configini->setValue("master", ui_ms_textbox->text()); configini->setValue("discord", ui_discord_cb->isChecked()); configini->setValue("language", ui_language_combobox->currentText().left(2)); + configini->setValue("shakeandflash", ui_epilepsy_cb->isChecked()); QFile* callwordsini = new QFile(ao_app->get_base_path() + "callwords.ini"); - if (!callwordsini->open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) - { - // Nevermind! - } - else + if (callwordsini->open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) { QTextStream out(callwordsini); out << ui_callwords_textbox->toPlainText(); @@ -519,6 +568,7 @@ void AOOptionsDialog::save_pressed() configini->setValue("default_blip", ui_blips_volume_spinbox->value()); configini->setValue("blip_rate", ui_bliprate_spinbox->value()); configini->setValue("blank_blip", ui_blank_blips_cb->isChecked()); + configini->setValue("looping_sfx", ui_loopsfx_cb->isChecked()); configini->setValue("objection_stop_music", ui_objectmusic_cb->isChecked()); configini->setValue("casing_enabled", ui_casing_enabled_cb->isChecked()); From 1b36be9dbc0cc665ddb69e1e1ee70267612b5d6c Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sun, 15 Sep 2019 21:39:39 +0300 Subject: [PATCH 039/268] Add an option for networking frame-specific effects I'm starting to realize the options menu/system needs a complete overhaul at this point. (Auto-generating options menu, anyone?) --- include/aoapplication.h | 4 +++ include/aooptionsdialog.h | 2 ++ src/aooptionsdialog.cpp | 51 +++++++++++++++++++++++-------------- src/courtroom.cpp | 11 +++++--- src/text_file_functions.cpp | 6 +++++ 5 files changed, 51 insertions(+), 23 deletions(-) diff --git a/include/aoapplication.h b/include/aoapplication.h index 6bc86e6..e63ab8e 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -174,6 +174,10 @@ public: // from the config.ini. bool is_shake_flash_enabled(); + // Returns the value of whether frame-specific effects defined in char.ini should be sent/received over the network. + // from the config.ini. + bool is_frame_network_enabled(); + // Returns the value of the maximum amount of lines the IC chatlog // may contain, from config.ini. int get_max_log_size(); diff --git a/include/aooptionsdialog.h b/include/aooptionsdialog.h index 0deb0a8..0322661 100644 --- a/include/aooptionsdialog.h +++ b/include/aooptionsdialog.h @@ -66,6 +66,8 @@ private: QLabel *ui_epilepsy_lbl; QCheckBox *ui_epilepsy_cb; + QLabel *ui_framenetwork_lbl; + QCheckBox *ui_framenetwork_cb; QWidget *ui_callwords_tab; QWidget *ui_callwords_widget; diff --git a/src/aooptionsdialog.cpp b/src/aooptionsdialog.cpp index 259f43e..7c52402 100644 --- a/src/aooptionsdialog.cpp +++ b/src/aooptionsdialog.cpp @@ -70,21 +70,21 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_theme_combobox); + row += 1; ui_theme_log_divider = new QFrame(ui_form_layout_widget); ui_theme_log_divider->setMidLineWidth(0); ui_theme_log_divider->setFrameShape(QFrame::HLine); ui_theme_log_divider->setFrameShadow(QFrame::Sunken); - row += 1; ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_theme_log_divider); + row += 1; ui_downwards_lbl = new QLabel(ui_form_layout_widget); ui_downwards_lbl->setText(tr("Log goes downwards:")); ui_downwards_lbl->setToolTip(tr("If ticked, new messages will appear at " "the bottom (like the OOC chatlog). The traditional " "(AO1) behaviour is equivalent to this being unticked.")); - row += 1; ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_downwards_lbl); ui_downwards_cb = new QCheckBox(ui_form_layout_widget); @@ -92,12 +92,12 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_downwards_cb); + row += 1; ui_length_lbl = new QLabel(ui_form_layout_widget); ui_length_lbl->setText(tr("Log length:")); ui_length_lbl->setToolTip(tr("The amount of messages the IC chatlog will keep before " "deleting older messages. A value of 0 or below counts as 'infinite'.")); - row += 1; ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_length_lbl); ui_length_spinbox = new QSpinBox(ui_form_layout_widget); @@ -106,19 +106,19 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_length_spinbox); + row += 1; ui_log_names_divider = new QFrame(ui_form_layout_widget); ui_log_names_divider->setFrameShape(QFrame::HLine); ui_log_names_divider->setFrameShadow(QFrame::Sunken); - row += 1; ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_log_names_divider); + row += 1; ui_username_lbl = new QLabel(ui_form_layout_widget); ui_username_lbl->setText(tr("Default username:")); ui_username_lbl->setToolTip(tr("Your OOC name will be automatically set to this value " "when you join a server.")); - row += 1; ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_username_lbl); ui_username_textbox = new QLineEdit(ui_form_layout_widget); @@ -127,13 +127,13 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_username_textbox); + row += 1; ui_showname_lbl = new QLabel(ui_form_layout_widget); ui_showname_lbl->setText(tr("Custom shownames:")); ui_showname_lbl->setToolTip(tr("Gives the default value for the in-game 'Custom shownames' " "tickbox, which in turn determines whether the client should " "display custom in-character names.")); - row += 1; ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_showname_lbl); ui_showname_cb = new QCheckBox(ui_form_layout_widget); @@ -141,19 +141,19 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_showname_cb); + row += 1; ui_net_divider = new QFrame(ui_form_layout_widget); ui_net_divider->setFrameShape(QFrame::HLine); ui_net_divider->setFrameShadow(QFrame::Sunken); - row += 1; ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_net_divider); + row += 1; ui_ms_lbl = new QLabel(ui_form_layout_widget); ui_ms_lbl->setText(tr("Backup MS:")); ui_ms_lbl->setToolTip(tr("If the built-in server lookups fail, the game will try the " "address given here and use it as a backup master server address.")); - row += 1; ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_ms_lbl); QSettings* configini = ao_app->configini; @@ -162,13 +162,13 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_ms_textbox); + row += 1; ui_discord_lbl = new QLabel(ui_form_layout_widget); ui_discord_lbl->setText(tr("Discord:")); ui_discord_lbl->setToolTip(tr("Allows others on Discord to see what server you are in, " "what character are you playing, and how long you have " "been playing for.")); - row += 1; ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_discord_lbl); ui_discord_cb = new QCheckBox(ui_form_layout_widget); @@ -192,11 +192,11 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi ui_language_combobox->addItem("ru - Русский"); ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_language_combobox); + row += 1; ui_epilepsy_lbl = new QLabel(ui_form_layout_widget); ui_epilepsy_lbl->setText(tr("Allow Shake/Flash:")); ui_epilepsy_lbl->setToolTip(tr("Allows screenshaking and flashing. Disable this if you have concerns or issues with photosensitivity and/or seizures.")); - row += 1; ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_epilepsy_lbl); ui_epilepsy_cb = new QCheckBox(ui_form_layout_widget); @@ -204,6 +204,18 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_epilepsy_cb); + row += 1; + ui_framenetwork_lbl = new QLabel(ui_form_layout_widget); + ui_framenetwork_lbl->setText(tr("Network Frame Effects:")); + ui_framenetwork_lbl->setToolTip(tr("Send screen-shaking, flashes and sounds as defined in the char.ini over the network. Only works for servers that support this functionality.")); + + ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_framenetwork_lbl); + + ui_framenetwork_cb = new QCheckBox(ui_form_layout_widget); + ui_framenetwork_cb->setChecked(ao_app->is_shake_flash_enabled()); + + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_framenetwork_cb); + // Here we start the callwords tab. ui_callwords_tab = new QWidget(); ui_settings_tabs->addTab(ui_callwords_tab, tr("Callwords")); @@ -282,18 +294,18 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi #endif ui_audio_layout->setWidget(row, QFormLayout::FieldRole, ui_audio_device_combobox); + row += 1; ui_audio_volume_divider = new QFrame(ui_audio_widget); ui_audio_volume_divider->setFrameShape(QFrame::HLine); ui_audio_volume_divider->setFrameShadow(QFrame::Sunken); - row += 1; ui_audio_layout->setWidget(row, QFormLayout::FieldRole, ui_audio_volume_divider); + row += 1; ui_music_volume_lbl = new QLabel(ui_audio_widget); ui_music_volume_lbl->setText(tr("Music:")); ui_music_volume_lbl->setToolTip(tr("Sets the music's default volume.")); - row += 1; ui_audio_layout->setWidget(row, QFormLayout::LabelRole, ui_music_volume_lbl); ui_music_volume_spinbox = new QSpinBox(ui_audio_widget); @@ -303,11 +315,11 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi ui_audio_layout->setWidget(row, QFormLayout::FieldRole, ui_music_volume_spinbox); + row += 1; ui_sfx_volume_lbl = new QLabel(ui_audio_widget); ui_sfx_volume_lbl->setText(tr("SFX:")); ui_sfx_volume_lbl->setToolTip(tr("Sets the SFX's default volume. " "Interjections and actual sound effects count as 'SFX'.")); - row += 1; ui_audio_layout->setWidget(row, QFormLayout::LabelRole, ui_sfx_volume_lbl); ui_sfx_volume_spinbox = new QSpinBox(ui_audio_widget); @@ -317,11 +329,11 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi ui_audio_layout->setWidget(row, QFormLayout::FieldRole, ui_sfx_volume_spinbox); + row += 1; ui_blips_volume_lbl = new QLabel(ui_audio_widget); ui_blips_volume_lbl->setText(tr("Blips:")); ui_blips_volume_lbl->setToolTip(tr("Sets the volume of the blips, the talking sound effects.")); - row += 1; ui_audio_layout->setWidget(row, QFormLayout::LabelRole, ui_blips_volume_lbl); ui_blips_volume_spinbox = new QSpinBox(ui_audio_widget); @@ -331,18 +343,18 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi ui_audio_layout->setWidget(row, QFormLayout::FieldRole, ui_blips_volume_spinbox); + row += 1; ui_volume_blip_divider = new QFrame(ui_audio_widget); ui_volume_blip_divider->setFrameShape(QFrame::HLine); ui_volume_blip_divider->setFrameShadow(QFrame::Sunken); - row += 1; ui_audio_layout->setWidget(row, QFormLayout::FieldRole, ui_volume_blip_divider); + row += 1; ui_bliprate_lbl = new QLabel(ui_audio_widget); ui_bliprate_lbl->setText(tr("Blip rate:")); ui_bliprate_lbl->setToolTip(tr("Sets the delay between playing the blip sounds.")); - row += 1; ui_audio_layout->setWidget(row, QFormLayout::LabelRole, ui_bliprate_lbl); ui_bliprate_spinbox = new QSpinBox(ui_audio_widget); @@ -353,12 +365,12 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi ui_audio_layout->setWidget(row, QFormLayout::FieldRole, ui_bliprate_spinbox); + row += 1; ui_blank_blips_lbl = new QLabel(ui_audio_widget); ui_blank_blips_lbl->setText(tr("Blank blips:")); ui_blank_blips_lbl->setToolTip(tr("If true, the game will play a blip sound even " "when a space is 'being said'.")); - row += 1; ui_audio_layout->setWidget(row, QFormLayout::LabelRole, ui_blank_blips_lbl); ui_blank_blips_cb = new QCheckBox(ui_audio_widget); @@ -366,11 +378,11 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi ui_audio_layout->setWidget(row, QFormLayout::FieldRole, ui_blank_blips_cb); + row += 1; ui_loopsfx_lbl = new QLabel(ui_audio_widget); ui_loopsfx_lbl->setText(tr("Enable Looping SFX:")); ui_loopsfx_lbl->setToolTip(tr("If true, the game will allow looping sound effects to play on preanimations.")); - row += 1; ui_audio_layout->setWidget(row, QFormLayout::LabelRole, ui_loopsfx_lbl); ui_loopsfx_cb = new QCheckBox(ui_audio_widget); @@ -378,11 +390,11 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi ui_audio_layout->setWidget(row, QFormLayout::FieldRole, ui_loopsfx_cb); + row += 1; ui_objectmusic_lbl = new QLabel(ui_audio_widget); ui_objectmusic_lbl->setText(tr("Kill Music On Objection:")); ui_objectmusic_lbl->setToolTip(tr("If true, AO2 will stop the music for you when you or someone else does 'Objection!'.")); - row += 1; ui_audio_layout->setWidget(row, QFormLayout::LabelRole, ui_objectmusic_lbl); ui_objectmusic_cb = new QCheckBox(ui_audio_widget); @@ -552,6 +564,7 @@ void AOOptionsDialog::save_pressed() configini->setValue("discord", ui_discord_cb->isChecked()); configini->setValue("language", ui_language_combobox->currentText().left(2)); configini->setValue("shakeandflash", ui_epilepsy_cb->isChecked()); + configini->setValue("framenetwork", ui_framenetwork_cb->isChecked()); QFile* callwordsini = new QFile(ao_app->get_base_path() + "callwords.ini"); diff --git a/src/courtroom.cpp b/src/courtroom.cpp index d7d1ff5..f54cc24 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1283,9 +1283,12 @@ void Courtroom::on_chat_return_pressed() foreach (QString f_emote, emotes_to_check) { packet += f_emote; - QString sfx_frames = ao_app->read_char_ini_tag(current_char, f_emote.append(f_effect)).join("|"); - if (sfx_frames != "") - packet += "|" + sfx_frames; + if (ao_app->is_frame_network_enabled()) + { + QString sfx_frames = ao_app->read_char_ini_tag(current_char, f_emote.append(f_effect)).join("|"); + if (sfx_frames != "") + packet += "|" + sfx_frames; + } packet += "^"; } qDebug() << f_effect << "packet" << packet; @@ -1442,7 +1445,7 @@ void Courtroom::handle_chatmessage_2() //Clear all looping sfx to prevent obnoxiousness sfx_player->loop_clear(); - if (!m_chatmessage[FRAME_SFX].isEmpty()) + if (!m_chatmessage[FRAME_SFX].isEmpty() && ao_app->is_frame_network_enabled()) { //ORDER IS IMPORTANT!! QStringList netstrings = {m_chatmessage[FRAME_SCREENSHAKE], m_chatmessage[FRAME_REALIZATION], m_chatmessage[FRAME_SFX]}; diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index 750df01..d286c03 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -678,6 +678,12 @@ bool AOApplication::is_shake_flash_enabled() return result.startsWith("true"); } +bool AOApplication::is_frame_network_enabled() +{ + QString result = configini->value("framenetwork", "true").value(); + return result.startsWith("true"); +} + bool AOApplication::get_casing_enabled() { QString result = configini->value("casing_enabled", "false").value(); From bf999f195a0be20519356644df1940cf18d905e7 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Mon, 16 Sep 2019 01:16:37 +0300 Subject: [PATCH 040/268] Add file reading, writing and appending functions that create folders if bool is true Fix server_address not being properly created in packet distribution Create a log file when you join a server in the logs//.log and update it every time there's a new chat entry minor refactor of chatlogpiece --- include/aoapplication.h | 12 +++++++ include/chatlogpiece.h | 4 +-- src/chatlogpiece.cpp | 15 ++++---- src/courtroom.cpp | 6 ++-- src/packet_distribution.cpp | 9 +++-- src/text_file_functions.cpp | 68 +++++++++++++++++++++++++++++++++++++ 6 files changed, 100 insertions(+), 14 deletions(-) diff --git a/include/aoapplication.h b/include/aoapplication.h index e63ab8e..24dc35c 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -201,6 +201,15 @@ public: //Returns the list of words in callwords.ini QStringList get_call_words(); + //Process a file and return its text as a QString + QString read_file(QString filename); + + //Write text to file. make_dir would auto-create the directory if it doesn't exist. + bool write_to_file(QString p_text, QString p_file, bool make_dir = false); + + //Append text to the end of the file. make_dir would auto-create the directory if it doesn't exist. + bool append_to_file(QString p_text, QString p_file, bool make_dir = false); + //Appends the argument string to serverlist.txt void write_to_serverlist_txt(QString p_line); @@ -337,6 +346,9 @@ public: // Get the message for the CM for casing alerts. QString get_casing_can_host_cases(); + //The file name of the log file in base/logs. + QString log_filename; + private: const int RELEASE = 2; const int MAJOR_VERSION = 6; diff --git a/include/chatlogpiece.h b/include/chatlogpiece.h index 34c5926..303c235 100644 --- a/include/chatlogpiece.h +++ b/include/chatlogpiece.h @@ -14,7 +14,7 @@ public: QString get_name(); QString get_showname(); QString get_message(); - bool get_is_song(); + bool is_song(); QDateTime get_datetime(); QString get_datetime_as_string(); @@ -25,7 +25,7 @@ private: QString showname; QString message; QDateTime datetime; - bool is_song; + bool p_is_song; }; #endif // CHATLOGPIECE_H diff --git a/src/chatlogpiece.cpp b/src/chatlogpiece.cpp index 6c861f0..eb7c188 100644 --- a/src/chatlogpiece.cpp +++ b/src/chatlogpiece.cpp @@ -5,7 +5,7 @@ chatlogpiece::chatlogpiece() name = "UNKNOWN"; showname = "UNKNOWN"; message = "UNKNOWN"; - is_song = false; + p_is_song = false; datetime = QDateTime::currentDateTime().toUTC(); } @@ -14,7 +14,7 @@ chatlogpiece::chatlogpiece(QString p_name, QString p_showname, QString p_message name = p_name; showname = p_showname; message = p_message; - is_song = p_song; + p_is_song = p_song; datetime = QDateTime::currentDateTime().toUTC(); } @@ -23,7 +23,7 @@ chatlogpiece::chatlogpiece(QString p_name, QString p_showname, QString p_message name = p_name; showname = p_showname; message = p_message; - is_song = p_song; + p_is_song = p_song; datetime = p_datetime.toUTC(); } @@ -47,9 +47,9 @@ QDateTime chatlogpiece::get_datetime() return datetime; } -bool chatlogpiece::get_is_song() +bool chatlogpiece::is_song() { - return is_song; + return p_is_song; } QString chatlogpiece::get_datetime_as_string() @@ -57,18 +57,17 @@ QString chatlogpiece::get_datetime_as_string() return datetime.toString(); } - QString chatlogpiece::get_full() { QString full = "["; full.append(get_datetime_as_string()); - full.append(" UTC] "); + full.append("] "); full.append(get_showname()); full.append(" ("); full.append(get_name()); full.append(")"); - if (is_song) + if (p_is_song) full.append(" has played a song: "); full.append(get_message()); diff --git a/src/courtroom.cpp b/src/courtroom.cpp index f54cc24..433041c 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1382,6 +1382,7 @@ void Courtroom::handle_chatmessage(QStringList *p_contents) chatlogpiece* temp = new chatlogpiece(ao_app->get_showname(char_list.at(f_char_id).name), f_showname, ": " + m_chatmessage[MESSAGE], false); ic_chatlog_history.append(*temp); + ao_app->append_to_file(temp->get_full(), ao_app->log_filename, true); while(ic_chatlog_history.size() > log_maximum_blocks && log_maximum_blocks > 0) { @@ -2689,6 +2690,7 @@ void Courtroom::handle_song(QStringList *p_contents) { chatlogpiece* temp = new chatlogpiece(str_char, str_show, f_song, true); ic_chatlog_history.append(*temp); + ao_app->append_to_file(temp->get_full(), ao_app->log_filename, true); while(ic_chatlog_history.size() > log_maximum_blocks && log_maximum_blocks > 0) { @@ -3638,14 +3640,14 @@ void Courtroom::on_showname_enable_clicked() foreach (chatlogpiece item, ic_chatlog_history) { if (ui_showname_enable->isChecked()) { - if (item.get_is_song()) + if (item.is_song()) append_ic_text(item.get_message(), item.get_showname(), true); else append_ic_text(item.get_message(), item.get_showname()); } else { - if (item.get_is_song()) + if (item.is_song()) append_ic_text(item.get_message(), item.get_name(), true); else append_ic_text(item.get_message(), item.get_name()); diff --git a/src/packet_distribution.cpp b/src/packet_distribution.cpp index 6059edb..72840f7 100644 --- a/src/packet_distribution.cpp +++ b/src/packet_distribution.cpp @@ -251,7 +251,8 @@ void AOApplication::server_packet_received(AOPacket *p_packet) 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, info.port); + server_address = QString("%1:%2").arg(info.ip, QString::number(info.port)); + qDebug() << server_address; window_title += ": " + server_name; } } @@ -260,7 +261,8 @@ void AOApplication::server_packet_received(AOPacket *p_packet) if (selected_server >= 0 && selected_server < favorite_list.size()) { auto info = favorite_list.at(selected_server); server_name = info.name; - server_address = info.ip + info.port; + server_address = QString("%1:%2").arg(info.ip, QString::number(info.port)); + qDebug() << server_address; window_title += ": " + server_name; } } @@ -280,6 +282,9 @@ void AOApplication::server_packet_received(AOPacket *p_packet) send_server_packet(f_packet); + //Remove any characters not accepted in folder names for the server_name here + this->log_filename = QDateTime::currentDateTime().toUTC().toString("'logs/" + server_name.remove(QRegExp("[\\\\/:*?\"<>|]")) + "/'ddd MMMM yyyy hh.mm.ss t'.log'"); + this->write_to_file("Joined server " + server_name + " on address " + server_address +" on " + QDateTime::currentDateTime().toUTC().toString(), log_filename, true); QCryptographicHash hash(QCryptographicHash::Algorithm::Sha256); hash.addData(server_address.toUtf8()); if (is_discord_enabled()) diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index d286c03..ae17ac5 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -95,6 +95,74 @@ QStringList AOApplication::get_call_words() return return_value; } +QString AOApplication::read_file(QString filename) +{ + QFile f_log(filename); + + if(!f_log.open(QIODevice::ReadOnly | QIODevice::Text)) + { + qDebug() << "Couldn't open" << filename; + return ""; + } + + QTextStream in(&f_log); + QString text = in.readAll(); + f_log.close(); + return text; +} + +bool AOApplication::write_to_file(QString p_text, QString p_file, bool make_dir) +{ + QString path = QFileInfo(p_file).path(); + if(make_dir) + { + //Create the dir if it doesn't exist yet + QDir dir(path); + if (!dir.exists()) + if (!dir.mkpath(".")) + return false; + } + + QFile f_log(p_file); + if(f_log.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) + { + QTextStream out(&f_log); + + out << p_text; + + f_log.flush(); + f_log.close(); + return true; + } + return false; +} + +bool AOApplication::append_to_file(QString p_text, QString p_file, bool make_dir) +{ + QString path = QFileInfo(p_file).path(); + //Create the dir if it doesn't exist yet + if(make_dir) + { + QDir dir(path); + if (!dir.exists()) + if (!dir.mkpath(".")) + return false; + } + + QFile f_log(p_file); + if(f_log.open(QIODevice::WriteOnly | QIODevice::Append)) + { + QTextStream out(&f_log); + + out << "\r\n" << p_text; + + f_log.flush(); + f_log.close(); + return true; + } + return false; +} + void AOApplication::write_to_serverlist_txt(QString p_line) { QFile serverlist_txt; From 2268df7b152ac6de774d4eb8afa7ae502026b543 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Mon, 16 Sep 2019 01:17:13 +0300 Subject: [PATCH 041/268] Update preanim_timer to follow the weird ass time_mod constant --- include/aocharmovie.h | 2 ++ src/aocharmovie.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/include/aocharmovie.h b/include/aocharmovie.h index d066a39..ec7b952 100644 --- a/include/aocharmovie.h +++ b/include/aocharmovie.h @@ -66,6 +66,8 @@ private: QString m_emote; QElapsedTimer actual_time; + + //it will forever be a mystery who thought this time_mod system would ever be a good idea with precision-based emotes const int time_mod = 60; // These are the X and Y values before they are fixed based on the sprite's width. diff --git a/src/aocharmovie.cpp b/src/aocharmovie.cpp index 34c6c81..b795847 100644 --- a/src/aocharmovie.cpp +++ b/src/aocharmovie.cpp @@ -164,7 +164,7 @@ void AOCharMovie::play_pre(QString p_char, QString p_emote, int duration) //not without looping through all frames in the image at least - which causes lag. So for now it simply ends the preanimation early instead. play_once = true; if (duration > 0) //It's -1 if there's no definition in [Time] for it. In which case, it will let the animation run out in full. Duration 0 does the same. - preanim_timer->start(duration); //This timer will not fire if the animation finishes earlier than that + preanim_timer->start(duration * time_mod); //This timer will not fire if the animation finishes earlier than that play(); } From 6785f357622363edf73cb55763b730bcb0542229 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Mon, 16 Sep 2019 01:20:03 +0300 Subject: [PATCH 042/268] Begin implementation of scroll bars in the options menu --- include/aooptionsdialog.h | 1 + src/aooptionsdialog.cpp | 10 ++++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/include/aooptionsdialog.h b/include/aooptionsdialog.h index 0322661..5198410 100644 --- a/include/aooptionsdialog.h +++ b/include/aooptionsdialog.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #include diff --git a/src/aooptionsdialog.cpp b/src/aooptionsdialog.cpp index 7c52402..b926782 100644 --- a/src/aooptionsdialog.cpp +++ b/src/aooptionsdialog.cpp @@ -12,7 +12,7 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi ui_settings_buttons = new QDialogButtonBox(this); - QSizePolicy sizePolicy1(QSizePolicy::Expanding, QSizePolicy::Fixed); + QSizePolicy sizePolicy1(QSizePolicy::Expanding, QSizePolicy::Maximum); sizePolicy1.setHorizontalStretch(0); sizePolicy1.setVerticalStretch(0); sizePolicy1.setHeightForWidth(ui_settings_buttons->sizePolicy().hasHeightForWidth()); @@ -37,9 +37,9 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi // First, we'll start with 'Gameplay'. ui_gameplay_tab = new QWidget(); ui_settings_tabs->addTab(ui_gameplay_tab, tr("Gameplay")); - ui_form_layout_widget = new QWidget(ui_gameplay_tab); ui_form_layout_widget->setGeometry(QRect(10, 10, 361, 211)); + ui_form_layout_widget->setSizePolicy(sizePolicy1); ui_gameplay_form = new QFormLayout(ui_form_layout_widget); ui_gameplay_form->setLabelAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter); @@ -216,6 +216,12 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_framenetwork_cb); + QScrollArea *scroll = new QScrollArea; + scroll->setWidget(ui_form_layout_widget); + ui_gameplay_tab->setLayout(new QVBoxLayout); + ui_gameplay_tab->layout()->addWidget(scroll); + ui_gameplay_tab->show(); + // Here we start the callwords tab. ui_callwords_tab = new QWidget(); ui_settings_tabs->addTab(ui_callwords_tab, tr("Callwords")); From 03ebad6bb6c922323b16b3ae6a701ddc34ba538b Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Mon, 16 Sep 2019 04:16:59 +0300 Subject: [PATCH 043/268] Add expanded style sheet support Allow lobby fonts to happen --- include/aoapplication.h | 3 ++ include/courtroom.h | 6 ++++ include/lobby.h | 4 +++ src/courtroom.cpp | 38 ++++++++++++++++++----- src/lobby.cpp | 62 +++++++++++++++++++++++++++++++++++++ src/text_file_functions.cpp | 39 +++++++++++++++++++++++ 6 files changed, 145 insertions(+), 7 deletions(-) diff --git a/include/aoapplication.h b/include/aoapplication.h index 24dc35c..fcee38f 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -252,6 +252,9 @@ public: //Returns a QStringList of all key=value definitions on a given tag. QStringList read_char_ini_tag(QString p_char, QString target_tag); + //Returns the text between target_tag and terminator_tag in p_file + QString get_stylesheet(QString target_tag, QString p_file); + //Returns the side of the p_char character from that characters ini file QString get_char_side(QString p_char); diff --git a/include/courtroom.h b/include/courtroom.h index 7fbde27..9d33a91 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -122,6 +122,12 @@ public: //helper function that calls above function on the relevant widgets void set_fonts(); + //sets dropdown menu stylesheet + void set_dropdown(QWidget *widget, QString target_tag); + + //helper funciton that call above function on the relevant widgets + void set_dropdowns(); + void set_window_title(QString p_title); //reads theme inis and sets size and pos based on the identifier diff --git a/include/lobby.h b/include/lobby.h index 4293ac3..e0cd03d 100644 --- a/include/lobby.h +++ b/include/lobby.h @@ -32,6 +32,10 @@ public: void append_chatmessage(QString f_name, QString f_message); void append_error(QString f_message); void set_player_count(int players_online, int max_players); + void set_stylesheet(QWidget *widget, QString target_tag); + void set_stylesheets(); + void set_fonts(); + void set_font(QWidget *widget, QString p_identifier); void set_loading_text(QString p_text); void show_loading_overlay(){ui_loading_background->show();} void hide_loading_overlay(){ui_loading_background->hide();} diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 433041c..c87da55 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -709,6 +709,8 @@ void Courtroom::set_widgets() ui_char_select_right->set_image("arrow_right.png"); set_size_and_pos(ui_spectator, "spectator"); + + set_dropdowns(); } void Courtroom::set_fonts() @@ -719,7 +721,7 @@ void Courtroom::set_fonts() set_font(ui_ms_chatlog, "ms_chatlog"); set_font(ui_server_chatlog, "server_chatlog"); set_font(ui_music_list, "music_list"); - set_font(ui_area_list, "music_list"); + set_font(ui_area_list, "area_list"); // Set color of labels and checkboxes const QString design_file = "courtroom_fonts.ini"; @@ -739,21 +741,43 @@ void Courtroom::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 fontt = ao_app->get_font_name(p_identifier + "_font", design_file); - widget->setFont(QFont(fontt, f_weight)); + QString font_name = ao_app->get_font_name(p_identifier + "_font", design_file); + widget->setFont(QFont(font_name, f_weight)); QColor f_color = ao_app->get_color(p_identifier + "_color", design_file); + int bold = ao_app->get_font_size(p_identifier + "_bold", design_file); // is the font bold or not? + + QString is_bold = ""; + if(bold == 1) is_bold = "bold"; + QString style_sheet_string = class_name + " { background-color: rgba(0, 0, 0, 0);\n" + - "color: rgba(" + - QString::number(f_color.red()) + ", " + - QString::number(f_color.green()) + ", " + - QString::number(f_color.blue()) + ", 255); }"; + "color: rgba(" + + QString::number(f_color.red()) + ", " + + QString::number(f_color.green()) + ", " + + QString::number(f_color.blue()) + ", 255);\n" + "font: " + is_bold + "; }"; widget->setStyleSheet(style_sheet_string); } +void Courtroom::set_dropdown(QWidget *widget, QString target_tag) +{ + QString f_file = "courtroom_stylesheets.css"; + QString style_sheet_string = ao_app->get_stylesheet(target_tag, f_file); + if (style_sheet_string != "") + widget->setStyleSheet(style_sheet_string); +} + +void Courtroom::set_dropdowns() +{ + set_dropdown(ui_text_color, "[TEXT COLOR]"); + set_dropdown(ui_pos_dropdown, "[POS DROPDOWN]"); + set_dropdown(ui_emote_dropdown, "[EMOTE DROPDOWN]"); + set_dropdown(ui_mute_list, "[MUTE LIST]"); +} + void Courtroom::set_window_title(QString p_title) { this->setWindowTitle(p_title); diff --git a/src/lobby.cpp b/src/lobby.cpp index 6f257ce..7df2cdc 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -153,6 +153,8 @@ void Lobby::set_widgets() ui_loading_background->hide(); + set_fonts(); + set_stylesheets(); } void Lobby::set_size_and_pos(QWidget *p_widget, QString p_identifier) @@ -173,6 +175,66 @@ void Lobby::set_size_and_pos(QWidget *p_widget, QString p_identifier) } } +void Lobby::set_fonts() +{ + set_font(ui_player_count, "player_count"); + set_font(ui_description, "description"); + set_font(ui_chatbox, "chatbox"); + set_font(ui_chatname, "chatname"); + set_font(ui_chatmessage, "chatmessage"); + set_font(ui_loading_text, "loading_text"); + set_font(ui_server_list, "server_list"); +} + +void Lobby::set_stylesheet(QWidget *widget, QString target_tag) +{ + QString f_file = "lobby_stylesheets.css"; + QString style_sheet_string = ao_app->get_stylesheet(target_tag, f_file); + if (style_sheet_string != "") + widget->setStyleSheet(style_sheet_string); +} + +void Lobby::set_stylesheets() +{ + set_stylesheet(ui_player_count, "[PLAYER COUNT]"); + set_stylesheet(ui_description, "[DESCRIPTION]"); + set_stylesheet(ui_chatbox, "[CHAT BOX]"); + set_stylesheet(ui_chatname, "[CHAT NAME]"); + set_stylesheet(ui_chatmessage, "[CHAT MESSAGE]"); + set_stylesheet(ui_loading_text, "[LOADING TEXT]"); + set_stylesheet(ui_server_list, "[SERVER LIST]"); +} + +void Lobby::set_font(QWidget *widget, QString p_identifier) +{ + QString design_file = "lobby_fonts.ini"; + 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("font_" + p_identifier, design_file); + QFont font(font_name, f_weight); + bool use = static_cast(ao_app->get_font_size("use_custom_fonts", design_file)); + if(use) + { + widget->setFont(font); + QColor f_color = ao_app->get_color(p_identifier + "_color", design_file); + bool bold = static_cast(ao_app->get_font_size(p_identifier + "_bold", design_file)); // is the font bold or not? + bool center = static_cast(ao_app->get_font_size(p_identifier + "_center", design_file)); // should it be centered? + QString is_bold = ""; + if(bold) is_bold = "bold"; + QString is_center = ""; + if(center) is_center = "qproperty-alignment: AlignCenter;"; + QString style_sheet_string = class_name + " { background-color: rgba(0, 0, 0, 0);\n" + + "color: rgba(" + + QString::number(f_color.red()) + ", " + + QString::number(f_color.green()) + ", " + + QString::number(f_color.blue()) + ", 255);\n" + + is_center + "\n" + + "font: " + is_bold + "; }"; + widget->setStyleSheet(style_sheet_string); + } + return; +} + void Lobby::set_loading_text(QString p_text) { ui_loading_text->clear(); diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index ae17ac5..ad82581 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -350,6 +350,45 @@ QColor AOApplication::get_color(QString p_identifier, QString p_file) return return_color; } +QString AOApplication::get_stylesheet(QString target_tag, QString p_file) +{ + QString design_ini_path = get_theme_path(p_file); + + QFile design_ini; + + design_ini.setFileName(design_ini_path); + + if(!design_ini.open(QIODevice::ReadOnly)) + return ""; + + QTextStream in(&design_ini); + + QString f_text; + + bool tag_found = false; + + while(!in.atEnd()) + { + QString line = in.readLine(); + + if (line.startsWith(target_tag, Qt::CaseInsensitive)) + { + tag_found = true; + continue; + } + + if(tag_found) + { + if((line.startsWith("[") && line.endsWith("]"))) + break; + f_text.append(line); + } + } + + design_ini.close(); + return f_text; +} + QColor AOApplication::get_chat_color(QString p_identifier, QString p_chat) { QColor return_color(255, 255, 255); From 9b39b7d6aa2beb8b5496a528c2351adf125c4601 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Mon, 16 Sep 2019 06:09:39 +0300 Subject: [PATCH 044/268] Allow char.ini to override the chat font and font size with chat_font = and chat_size = Scream at the coders that decided hard-coding fonts and colors was a good idea (gotta properly let the themes modify that later) Fix a lot of ui elements not properly respecting the themes and their colors add a set_qfont method for those situations that need it Allow the theme to change sender colors for ooc and ms chatlogs rename url parser variable to something more immediately apparent as to what it is for readability's sake --- include/aoapplication.h | 8 ++++++- include/aotextarea.h | 2 +- include/courtroom.h | 5 +++++ src/aotextarea.cpp | 4 ++-- src/courtroom.cpp | 44 +++++++++++++++++++++++++------------ src/evidence.cpp | 1 + src/lobby.cpp | 1 + src/text_file_functions.cpp | 16 ++++++++++++++ 8 files changed, 63 insertions(+), 18 deletions(-) diff --git a/include/aoapplication.h b/include/aoapplication.h index fcee38f..e4a5b7f 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -261,9 +261,15 @@ public: //Returns the showname from the ini of p_char QString get_showname(QString p_char); - //Returns the value of chat from the specific p_char's ini file + //Returns the value of chat image from the specific p_char's ini file QString get_chat(QString p_char); + //Returns the value of chat font from the specific p_char's ini file + QString get_chat_font(QString p_char); + + //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); diff --git a/include/aotextarea.h b/include/aotextarea.h index d44596b..266b722 100644 --- a/include/aotextarea.h +++ b/include/aotextarea.h @@ -16,7 +16,7 @@ public: void append_error(QString p_message); private: - const QRegExp omnis_dank_url_regex = QRegExp("\\b(https?://\\S+\\.\\S+)\\b"); + const QRegExp url_parser_regex = QRegExp("\\b(https?://\\S+\\.\\S+)\\b"); void auto_scroll(QTextCursor old_cursor, int scrollbar_value, bool is_scrolled_down); }; diff --git a/include/courtroom.h b/include/courtroom.h index 9d33a91..304dd64 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -117,8 +117,13 @@ public: //sets position of widgets based on theme ini files void set_widgets(); + //sets font size based on theme ini files void set_font(QWidget *widget, QString p_identifier); + + //actual operation of setting the font on a widget + void set_qfont(QWidget *widget, QFont font, QColor f_color = Qt::black, bool bold = false); + //helper function that calls above function on the relevant widgets void set_fonts(); diff --git a/src/aotextarea.cpp b/src/aotextarea.cpp index 5e14632..f9d21e6 100644 --- a/src/aotextarea.cpp +++ b/src/aotextarea.cpp @@ -18,7 +18,7 @@ void AOTextArea::append_chatmessage(QString p_name, QString p_message, QString p //cheap workarounds ahoy p_message += " "; - QString result = p_message.toHtmlEscaped().replace("\n", "
").replace(omnis_dank_url_regex, "\\1" ); + QString result = p_message.toHtmlEscaped().replace("\n", "
").replace(url_parser_regex, "\\1" ); this->insertHtml(result); @@ -36,7 +36,7 @@ void AOTextArea::append_error(QString p_message) this->append(""); p_message += " "; - QString result = p_message.replace("\n", "
").replace(omnis_dank_url_regex, "\\1" ); + QString result = p_message.replace("\n", "
").replace(url_parser_regex, "\\1" ); this->insertHtml("" + result + ""); diff --git a/src/courtroom.cpp b/src/courtroom.cpp index c87da55..d56719f 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -86,6 +86,7 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_vp_chatbox = new AOImage(this, ao_app); ui_vp_showname = new QLabel(ui_vp_chatbox); + ui_vp_showname->setAlignment(Qt::AlignHCenter); ui_vp_message = new QTextEdit(this); ui_vp_message->setFrameStyle(QFrame::NoFrame); ui_vp_message->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); @@ -482,8 +483,8 @@ void Courtroom::set_widgets() //We detached the text as parent from the chatbox so it doesn't get affected by the screenshake. ui_vp_message->move(ui_vp_message->x() + ui_vp_chatbox->x(), ui_vp_message->y() + ui_vp_chatbox->y()); ui_vp_message->setTextInteractionFlags(Qt::NoTextInteraction); - ui_vp_message->setStyleSheet("background-color: rgba(0, 0, 0, 0);" - "color: white"); +// ui_vp_message->setStyleSheet("background-color: rgba(0, 0, 0, 0);" +// "color: white"); ui_vp_testimony->move(ui_viewport->x(), ui_viewport->y()); ui_vp_testimony->combo_resize(ui_viewport->width(), ui_viewport->height()); @@ -514,8 +515,6 @@ void Courtroom::set_widgets() ui_pair_button->set_image("pair_button.png"); set_size_and_pos(ui_area_list, "music_list"); - ui_area_list->setStyleSheet("background-color: rgba(0, 0, 0, 0);"); - set_size_and_pos(ui_music_list, "music_list"); if (is_ao2_bg) @@ -739,18 +738,20 @@ void Courtroom::set_font(QWidget *widget, QString p_identifier) { QString design_file = "courtroom_fonts.ini"; 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); - - widget->setFont(QFont(font_name, f_weight)); - QColor f_color = ao_app->get_color(p_identifier + "_color", design_file); - int bold = ao_app->get_font_size(p_identifier + "_bold", design_file); // is the font bold or not? + bool bold = static_cast(ao_app->get_font_size(p_identifier + "_bold", design_file)); // is the font bold or not? + this->set_qfont(widget, QFont(font_name, f_weight), f_color, bold); +} + +void Courtroom::set_qfont(QWidget *widget, QFont font, QColor f_color, bool bold) +{ + QString class_name = widget->metaObject()->className(); + widget->setFont(font); QString is_bold = ""; - if(bold == 1) is_bold = "bold"; + if(bold) is_bold = "bold"; QString style_sheet_string = class_name + " { background-color: rgba(0, 0, 0, 0);\n" + "color: rgba(" + @@ -1094,7 +1095,7 @@ void Courtroom::list_areas() void Courtroom::append_ms_chatmessage(QString f_name, QString f_message) { - ui_ms_chatlog->append_chatmessage(f_name, f_message, ao_app->get_color("ooc_default_color", "courtroom_design.ini").name()); + ui_ms_chatlog->append_chatmessage(f_name, f_message, ao_app->get_color("ms_chatlog_sender_color", "courtroom_fonts.ini").name()); } void Courtroom::append_server_chatmessage(QString p_name, QString p_message, QString p_colour) @@ -1102,9 +1103,9 @@ void Courtroom::append_server_chatmessage(QString p_name, QString p_message, QSt QString colour = "#000000"; if (p_colour == "0") - colour = ao_app->get_color("ooc_default_color", "courtroom_design.ini").name(); + colour = ao_app->get_color("ms_chatlog_sender_color", "courtroom_fonts.ini").name(); if (p_colour == "1") - colour = ao_app->get_color("ooc_server_color", "courtroom_design.ini").name(); + colour = ao_app->get_color("server_chatlog_sender_color", "courtroom_fonts.ini").name(); if(p_message == "Logged in as a moderator.") { ui_guard->show(); @@ -1505,6 +1506,21 @@ void Courtroom::handle_chatmessage_2() ui_vp_chatbox->set_image_from_path(chatbox_path); } + QString design_file = "courtroom_fonts.ini"; + int f_weight = ao_app->get_font_size("message", design_file); + QString font_name = ao_app->get_font_name("message_font", design_file); + QColor f_color = ao_app->get_color("message_color", design_file); + bool bold = static_cast(ao_app->get_font_size("message_bold", design_file)); // is the font bold or not? + + QString chatfont = ao_app->get_chat_font(m_chatmessage[CHAR_NAME]); + if (chatfont != "") + font_name = chatfont; + + int chatsize = ao_app->get_chat_size(m_chatmessage[CHAR_NAME]); + if (chatsize != -1) + f_weight = chatsize; + this->set_qfont(ui_vp_message, QFont(font_name, f_weight), f_color, bold); + ui_vp_showname->setStyleSheet("QLabel { color : " + get_text_color("_showname").name() + "; }"); set_scene(); diff --git a/src/evidence.cpp b/src/evidence.cpp index 341bed0..7e29b25 100644 --- a/src/evidence.cpp +++ b/src/evidence.cpp @@ -7,6 +7,7 @@ void Courtroom::construct_evidence() //ui_evidence_name = new QLabel(ui_evidence); ui_evidence_name = new AOLineEdit(ui_evidence); ui_evidence_name->setAlignment(Qt::AlignCenter); + //WHY IS THIS FONT HARDCODED, WHAT IS WRONG WITH YOU ui_evidence_name->setFont(QFont("Arial", 14, QFont::Bold)); ui_evidence_name->setStyleSheet("background-color: rgba(0, 0, 0, 0);" "color: rgba(255, 128, 0, 255);"); diff --git a/src/lobby.cpp b/src/lobby.cpp index 7df2cdc..951ff9a 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -139,6 +139,7 @@ void Lobby::set_widgets() set_size_and_pos(ui_loading_text, "loading_label"); + //WHY IS THIS FONT HARDCODED, WHAT IS WRONG WITH YOU ui_loading_text->setFont(QFont("Arial", 20, QFont::Bold)); ui_loading_text->setReadOnly(true); ui_loading_text->setAlignment(Qt::AlignCenter); diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index ad82581..02c0b71 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -576,6 +576,22 @@ QString AOApplication::get_chat(QString p_char) return f_result; } +QString AOApplication::get_chat_font(QString p_char) +{ + QString f_result = read_char_ini(p_char, "chat_font", "Options"); + + return f_result; +} + +int AOApplication::get_chat_size(QString p_char) +{ + QString f_result = read_char_ini(p_char, "chat_size", "Options"); + + if (f_result == "") + return -1; + return f_result.toInt(); +} + QString AOApplication::get_char_shouts(QString p_char) { QString f_result = read_char_ini(p_char, "shouts", "Options"); From b037edc9d8360ee679cae8d5f6c4d138ede4482b Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Mon, 16 Sep 2019 18:11:19 +0300 Subject: [PATCH 045/268] Add additive text option where your messages are added to your previous one, fully networked and ready for the server Adjust some pointless static bool casts to be actual logic checks --- include/aoapplication.h | 1 + include/aocharmovie.h | 6 ++--- include/courtroom.h | 9 +++++-- include/datatypes.h | 3 ++- src/courtroom.cpp | 47 +++++++++++++++++++++++++++++-------- src/lobby.cpp | 6 ++--- src/packet_distribution.cpp | 3 +++ 7 files changed, 56 insertions(+), 19 deletions(-) diff --git a/include/aoapplication.h b/include/aoapplication.h index e4a5b7f..f499faf 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -79,6 +79,7 @@ public: bool casing_alerts_enabled = false; bool modcall_reason_enabled = false; bool looping_sfx_support_enabled = false; + bool additive_enabled = false; ///////////////loading info/////////////////// diff --git a/include/aocharmovie.h b/include/aocharmovie.h index ec7b952..adfa7b8 100644 --- a/include/aocharmovie.h +++ b/include/aocharmovie.h @@ -46,6 +46,9 @@ public: QStringList network_strings; + QString m_char; + QString m_emote; + private: AOApplication *ao_app; @@ -62,9 +65,6 @@ private: QString last_path; QImageReader *m_reader = new QImageReader(); - QString m_char; - QString m_emote; - QElapsedTimer actual_time; //it will forever be a mystery who thought this time_mod system would ever be a good idea with precision-based emotes diff --git a/include/courtroom.h b/include/courtroom.h index 304dd64..9b3c057 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -315,6 +315,9 @@ private: bool rainbow_appended = false; bool blank_blip = false; + //Whether or not is this message additive to the previous one + bool is_additive = false; + // Used for getting the current maximum blocks allowed in the IC chatlog. int log_maximum_blocks = 0; @@ -339,7 +342,7 @@ private: //the amount of time non-animated witness testimony/cross-examination images stay onscreen for in ms const int wtce_stay_time = 1500; - static const int chatmessage_size = 28; + static const int chatmessage_size = 29; QString m_chatmessage[chatmessage_size]; bool chatmessage_is_empty = false; @@ -484,6 +487,7 @@ private: QCheckBox *ui_pre; QCheckBox *ui_flip; + QCheckBox *ui_additive; QCheckBox *ui_guard; QCheckBox *ui_casing; @@ -601,7 +605,7 @@ private slots: void on_emote_dropdown_changed(int p_index); void on_pos_dropdown_changed(int p_index); - void on_evidence_name_edited(); + void on_evidence_name_edited(QString text); void on_evidence_image_name_edited(); void on_evidence_image_button_clicked(); void on_evidence_clicked(int p_id); @@ -653,6 +657,7 @@ private slots: void on_pre_clicked(); void on_flip_clicked(); + void on_additive_clicked(); void on_guard_clicked(); void on_showname_enable_clicked(); diff --git a/include/datatypes.h b/include/datatypes.h index 1b76f72..54e5c74 100644 --- a/include/datatypes.h +++ b/include/datatypes.h @@ -105,7 +105,8 @@ enum CHAT_MESSAGE SCREENSHAKE, FRAME_SCREENSHAKE, FRAME_REALIZATION, - FRAME_SFX + FRAME_SFX, + ADDITIVE }; enum COLOR diff --git a/src/courtroom.cpp b/src/courtroom.cpp index d56719f..59d37d3 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -197,6 +197,10 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_guard->setText(tr("Guard")); ui_guard->hide(); + ui_additive = new QCheckBox(this); + ui_additive->setText(tr("Additive")); + ui_additive->hide(); + ui_casing = new QCheckBox(this); ui_casing->setChecked(ao_app->get_casing_enabled()); ui_casing->setText(tr("Casing")); @@ -331,6 +335,7 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() connect(ui_pre, SIGNAL(clicked()), this, SLOT(on_pre_clicked())); connect(ui_flip, SIGNAL(clicked()), this, SLOT(on_flip_clicked())); + connect(ui_additive, SIGNAL(clicked()), this, SLOT(on_additive_clicked())); connect(ui_guard, SIGNAL(clicked()), this, SLOT(on_guard_clicked())); connect(ui_casing, SIGNAL(clicked()), this, SLOT(on_casing_clicked())); @@ -619,6 +624,8 @@ void Courtroom::set_widgets() set_size_and_pos(ui_pre_non_interrupt, "pre_no_interrupt"); set_size_and_pos(ui_flip, "flip"); + set_size_and_pos(ui_additive, "additive"); + set_size_and_pos(ui_guard, "guard"); set_size_and_pos(ui_casing, "casing"); @@ -741,7 +748,7 @@ void Courtroom::set_font(QWidget *widget, QString p_identifier) QString font_name = ao_app->get_font_name(p_identifier + "_font", design_file); QColor f_color = ao_app->get_color(p_identifier + "_color", design_file); - bool bold = static_cast(ao_app->get_font_size(p_identifier + "_bold", design_file)); // is the font bold or not? + bool bold = ao_app->get_font_size(p_identifier + "_bold", design_file) == 1; // is the font bold or not? this->set_qfont(widget, QFont(font_name, f_weight), f_color, bold); } @@ -954,6 +961,11 @@ void Courtroom::enter_courtroom(int p_cid) else ui_flip->hide(); + if (ao_app->additive_enabled) + ui_additive->show(); + else + ui_additive->hide(); + if (ao_app->casing_alerts_enabled) ui_casing->show(); else @@ -1319,13 +1331,13 @@ void Courtroom::on_chat_return_pressed() qDebug() << f_effect << "packet" << packet; packet_contents.append(packet); } - - //"roar|thing=thong^(b)roar^(a)roar^" - -// packet_contents.append(frame_screenshake); -// packet_contents.append(frame_realization); -// packet_contents.append(frame_sfx); } + + if (ao_app->additive_enabled) + { + packet_contents.append(ui_additive->isChecked() ? "1" : "0"); + } + ao_app->send_server_packet(new AOPacket("MS", packet_contents)); } @@ -1388,6 +1400,7 @@ void Courtroom::handle_chatmessage(QStringList *p_contents) chatmessage_is_empty = m_chatmessage[MESSAGE] == " " || m_chatmessage[MESSAGE] == ""; + is_additive = false; if (m_chatmessage[MESSAGE] == ui_ic_chat_message->text() && m_chatmessage[CHAR_ID].toInt() == m_cid) { ui_ic_chat_message->clear(); @@ -1403,6 +1416,10 @@ void Courtroom::handle_chatmessage(QStringList *p_contents) ui_realization->set_image("realization.png"); ui_screenshake->set_image("screenshake.png"); ui_evidence_present->set_image("present_disabled.png"); + + + if (ao_app->additive_enabled && ui_vp_player_char->m_char == m_chatmessage[CHAR_NAME]) + is_additive = m_chatmessage[ADDITIVE].toInt() == 1; } chatlogpiece* temp = new chatlogpiece(ao_app->get_showname(char_list.at(f_char_id).name), f_showname, ": " + m_chatmessage[MESSAGE], false); @@ -1493,7 +1510,7 @@ void Courtroom::handle_chatmessage_2() ui_vp_showname->setText(m_chatmessage[SHOWNAME]); } - ui_vp_message->clear(); + ui_vp_message->hide(); ui_vp_chatbox->hide(); QString chatbox = ao_app->get_chat(m_chatmessage[CHAR_NAME]); @@ -1510,7 +1527,7 @@ void Courtroom::handle_chatmessage_2() int f_weight = ao_app->get_font_size("message", design_file); QString font_name = ao_app->get_font_name("message_font", design_file); QColor f_color = ao_app->get_color("message_color", design_file); - bool bold = static_cast(ao_app->get_font_size("message_bold", design_file)); // is the font bold or not? + bool bold = ao_app->get_font_size("message_bold", design_file) == 1; // is the font bold or not? QString chatfont = ao_app->get_chat_font(m_chatmessage[CHAR_NAME]); if (chatfont != "") @@ -2177,7 +2194,6 @@ void Courtroom::start_chat_ticking() this->do_screenshake(); } - ui_vp_message->clear(); set_text_color(); rainbow_counter = 0; @@ -2196,6 +2212,12 @@ void Courtroom::start_chat_ticking() } ui_vp_chatbox->show(); + ui_vp_message->show(); + + if (!is_additive) + { + ui_vp_message->clear(); + } tick_pos = 0; blip_pos = 0; @@ -3667,6 +3689,11 @@ void Courtroom::on_flip_clicked() ui_ic_chat_message->setFocus(); } +void Courtroom::on_additive_clicked() +{ + ui_ic_chat_message->setFocus(); +} + void Courtroom::on_guard_clicked() { ui_ic_chat_message->setFocus(); diff --git a/src/lobby.cpp b/src/lobby.cpp index 951ff9a..758f0fb 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -213,13 +213,13 @@ void Lobby::set_font(QWidget *widget, QString p_identifier) QString class_name = widget->metaObject()->className(); QString font_name = ao_app->get_font_name("font_" + p_identifier, design_file); QFont font(font_name, f_weight); - bool use = static_cast(ao_app->get_font_size("use_custom_fonts", design_file)); + bool use = ao_app->get_font_size("use_custom_fonts", design_file) == 1; if(use) { widget->setFont(font); QColor f_color = ao_app->get_color(p_identifier + "_color", design_file); - bool bold = static_cast(ao_app->get_font_size(p_identifier + "_bold", design_file)); // is the font bold or not? - bool center = static_cast(ao_app->get_font_size(p_identifier + "_center", design_file)); // should it be centered? + bool bold = ao_app->get_font_size(p_identifier + "_bold", design_file) == 1; // is the font bold or not? + bool center = ao_app->get_font_size(p_identifier + "_center", design_file) == 1; // should it be centered? QString is_bold = ""; if(bold) is_bold = "bold"; QString is_center = ""; diff --git a/src/packet_distribution.cpp b/src/packet_distribution.cpp index 72840f7..ff43f27 100644 --- a/src/packet_distribution.cpp +++ b/src/packet_distribution.cpp @@ -150,6 +150,7 @@ void AOApplication::server_packet_received(AOPacket *p_packet) casing_alerts_enabled = false; modcall_reason_enabled = false; looping_sfx_support_enabled = false; + additive_enabled = false; //workaround for tsuserver4 if (f_contents.at(0) == "NOENCRYPT") @@ -212,6 +213,8 @@ void AOApplication::server_packet_received(AOPacket *p_packet) modcall_reason_enabled = true; if (f_packet.contains("looping_sfx",Qt::CaseInsensitive)) looping_sfx_support_enabled = true; + if (f_packet.contains("additive",Qt::CaseInsensitive)) + additive_enabled = true; } else if (header == "PN") { From b085be5a2a0512c432bc9fd58413a9d8f93d451e Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Mon, 16 Sep 2019 21:08:43 +0300 Subject: [PATCH 046/268] Add two new helper functions - get_design_element and get_static_image_suffix Modify all set_image calls to utilize said suffix helper function Dynamically change betweehn chatblank, chat, chatmed, chatbig based on the showname's length Use char.ini showname if showname is set to whitespace (doesn't yet check if char.ini showname is also whitespace) --- include/aoapplication.h | 6 + include/aoimage.h | 4 +- src/aobutton.cpp | 4 +- src/aocharbutton.cpp | 6 +- src/aoemotebutton.cpp | 2 +- src/aoevidencebutton.cpp | 4 +- src/aoimage.cpp | 33 +++--- src/charselect.cpp | 2 +- src/courtroom.cpp | 215 +++++++++++++++++++++--------------- src/emotes.cpp | 8 +- src/evidence.cpp | 9 +- src/lobby.cpp | 40 +++---- src/text_file_functions.cpp | 13 +++ 13 files changed, 202 insertions(+), 144 deletions(-) diff --git a/include/aoapplication.h b/include/aoapplication.h index f499faf..052ad08 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -226,6 +226,9 @@ public: //Returns the dimensions of widget with specified identifier from p_file pos_size_type get_element_dimensions(QString p_identifier, QString p_file); + //Returns the value to you + QString get_design_element(QString p_identifier, QString p_file); + //Returns the name of the font with p_identifier from p_file QString get_font_name(QString p_identifier, QString p_file); @@ -247,6 +250,9 @@ public: // 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); + //Returns the value of p_search_line within target_tag and terminator_tag QString read_char_ini(QString p_char, QString p_search_line, QString target_tag); diff --git a/include/aoimage.h b/include/aoimage.h index 4713be0..25c8e06 100644 --- a/include/aoimage.h +++ b/include/aoimage.h @@ -17,8 +17,8 @@ public: QWidget *m_parent; AOApplication *ao_app; - void set_image(QString p_image); - void set_image_from_path(QString p_path); + bool set_image(QString p_image); + bool set_chatbox(QString p_path); void set_size_and_pos(QString identifier); }; diff --git a/src/aobutton.cpp b/src/aobutton.cpp index 5be2e67..1459729 100644 --- a/src/aobutton.cpp +++ b/src/aobutton.cpp @@ -15,8 +15,8 @@ AOButton::~AOButton() void AOButton::set_image(QString p_image) { - QString image_path = ao_app->get_theme_path(p_image); - QString default_image_path = ao_app->get_default_theme_path(p_image); + 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->setStyleSheet("border-image:url(\"" + image_path + "\")"); diff --git a/src/aocharbutton.cpp b/src/aocharbutton.cpp index 7661027..d571b95 100644 --- a/src/aocharbutton.cpp +++ b/src/aocharbutton.cpp @@ -15,7 +15,7 @@ AOCharButton::AOCharButton(QWidget *parent, AOApplication *p_ao_app, int x_pos, ui_taken = new AOImage(this, ao_app); ui_taken->resize(60, 60); - ui_taken->set_image("char_taken.png"); + ui_taken->set_image("char_taken"); ui_taken->setAttribute(Qt::WA_TransparentForMouseEvents); ui_taken->hide(); @@ -28,7 +28,7 @@ AOCharButton::AOCharButton(QWidget *parent, AOApplication *p_ao_app, int x_pos, ui_selector = new AOImage(parent, ao_app); ui_selector->resize(62, 62); ui_selector->move(x_pos - 1, y_pos - 1); - ui_selector->set_image("char_selector.png"); + ui_selector->set_image("char_selector"); ui_selector->setAttribute(Qt::WA_TransparentForMouseEvents); ui_selector->hide(); } @@ -65,7 +65,7 @@ void AOCharButton::set_passworded() void AOCharButton::set_image(QString p_character) { - QString image_path = ao_app->get_character_path(p_character, "char_icon.png"); + QString image_path = ao_app->get_static_image_suffix(ao_app->get_character_path(p_character, "char_icon")); this->setText(""); diff --git a/src/aoemotebutton.cpp b/src/aoemotebutton.cpp index 9c1d388..ca4d694 100644 --- a/src/aoemotebutton.cpp +++ b/src/aoemotebutton.cpp @@ -16,7 +16,7 @@ AOEmoteButton::AOEmoteButton(QWidget *p_parent, AOApplication *p_ao_app, int p_x void AOEmoteButton::set_image(QString p_char, int p_emote, QString suffix) { QString emotion_number = QString::number(p_emote + 1); - QString image_path = ao_app->get_character_path(p_char, "emotions/button" + emotion_number + suffix); + QString image_path = ao_app->get_static_image_suffix(ao_app->get_character_path(p_char, "emotions/button" + emotion_number + suffix)); if (file_exists(image_path)) { diff --git a/src/aoevidencebutton.cpp b/src/aoevidencebutton.cpp index 15b598f..616f636 100644 --- a/src/aoevidencebutton.cpp +++ b/src/aoevidencebutton.cpp @@ -10,14 +10,14 @@ AOEvidenceButton::AOEvidenceButton(QWidget *p_parent, AOApplication *p_ao_app, i ui_selected = new AOImage(p_parent, ao_app); ui_selected->resize(70, 70); ui_selected->move(p_x, p_y); - ui_selected->set_image("evidence_selected.png"); + ui_selected->set_image("evidence_selected"); ui_selected->setAttribute(Qt::WA_TransparentForMouseEvents); ui_selected->hide(); ui_selector = new AOImage(p_parent, ao_app); ui_selector->resize(71, 71); ui_selector->move(p_x - 1, p_y - 1); - ui_selector->set_image("evidence_selector.png"); + ui_selector->set_image("evidence_selector"); ui_selector->setAttribute(Qt::WA_TransparentForMouseEvents); ui_selector->hide(); diff --git a/src/aoimage.cpp b/src/aoimage.cpp index 7bb56bb..17c2ea6 100644 --- a/src/aoimage.cpp +++ b/src/aoimage.cpp @@ -13,35 +13,40 @@ AOImage::~AOImage() } -void AOImage::set_image(QString p_image) +bool AOImage::set_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 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)); QString final_image_path; if (file_exists(theme_image_path)) final_image_path = theme_image_path; - else + 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); this->setPixmap(f_pixmap.scaled(this->width(), this->height(), Qt::IgnoreAspectRatio)); + return true; } -void AOImage::set_image_from_path(QString p_path) +bool AOImage::set_chatbox(QString p_path) { - QString default_path = ao_app->get_default_theme_path("chatmed.png"); + 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!"; + return false; + } - QString final_path; - - if (file_exists(p_path)) - final_path = p_path; - else - final_path = default_path; - - QPixmap f_pixmap(final_path); + QPixmap f_pixmap(p_path); this->setPixmap(f_pixmap.scaled(this->width(), this->height(), Qt::IgnoreAspectRatio)); + return true; } diff --git a/src/charselect.cpp b/src/charselect.cpp index 0cfb775..23b0513 100644 --- a/src/charselect.cpp +++ b/src/charselect.cpp @@ -71,7 +71,7 @@ void Courtroom::set_char_select() this->resize(f_charselect.width, f_charselect.height); ui_char_select_background->resize(f_charselect.width, f_charselect.height); - ui_char_select_background->set_image("charselect_background.png"); + ui_char_select_background->set_image("charselect_background"); filter_character_list(); diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 59d37d3..cfdc8fb 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -418,7 +418,7 @@ void Courtroom::set_widgets() ui_background->move(0, 0); ui_background->resize(m_courtroom_width, m_courtroom_height); - ui_background->set_image("courtroombackground.png"); + ui_background->set_image("courtroombackground"); set_size_and_pos(ui_viewport, "viewport"); @@ -517,7 +517,7 @@ void Courtroom::set_widgets() set_size_and_pos(ui_pair_offset_spinbox, "pair_offset_spinbox"); ui_pair_offset_spinbox->hide(); set_size_and_pos(ui_pair_button, "pair_button"); - ui_pair_button->set_image("pair_button.png"); + ui_pair_button->set_image("pair_button"); set_size_and_pos(ui_area_list, "music_list"); set_size_and_pos(ui_music_list, "music_list"); @@ -538,11 +538,11 @@ void Courtroom::set_widgets() ui_ic_chat_message->setStyleSheet("QLineEdit{background-color: rgba(100, 100, 100, 255);}"); ui_ic_chat_name->setStyleSheet("QLineEdit{background-color: rgba(180, 180, 180, 255);}"); - ui_vp_chatbox->set_image("chatmed.png"); + ui_vp_chatbox->set_image("chatblank"); ui_vp_chatbox->hide(); ui_muted->resize(ui_ic_chat_message->width(), ui_ic_chat_message->height()); - ui_muted->set_image("muted.png"); + ui_muted->set_image("muted"); set_size_and_pos(ui_ooc_chat_message, "ooc_chat_message"); ui_ooc_chat_message->setStyleSheet("background-color: rgba(0, 0, 0, 0);"); @@ -556,19 +556,19 @@ void Courtroom::set_widgets() set_size_and_pos(ui_emotes, "emotes"); set_size_and_pos(ui_emote_left, "emote_left"); - ui_emote_left->set_image("arrow_left.png"); + ui_emote_left->set_image("arrow_left"); set_size_and_pos(ui_emote_right, "emote_right"); - ui_emote_right->set_image("arrow_right.png"); + ui_emote_right->set_image("arrow_right."); set_size_and_pos(ui_emote_dropdown, "emote_dropdown"); set_size_and_pos(ui_pos_dropdown, "pos_dropdown"); set_size_and_pos(ui_defense_bar, "defense_bar"); - ui_defense_bar->set_image("defensebar" + QString::number(defense_bar_state) + ".png"); + ui_defense_bar->set_image("defensebar" + QString::number(defense_bar_state)); set_size_and_pos(ui_prosecution_bar, "prosecution_bar"); - ui_prosecution_bar->set_image("prosecutionbar" + QString::number(prosecution_bar_state) + ".png"); + ui_prosecution_bar->set_image("prosecutionbar" + QString::number(prosecution_bar_state)); set_size_and_pos(ui_music_label, "music_label"); ui_music_label->setText(tr("Music")); @@ -581,24 +581,24 @@ void Courtroom::set_widgets() ui_log_limit_label->setText(tr("Log limit")); set_size_and_pos(ui_hold_it, "hold_it"); - ui_hold_it->set_image("holdit.png"); + ui_hold_it->set_image("holdit"); set_size_and_pos(ui_objection, "objection"); - ui_objection->set_image("objection.png"); + ui_objection->set_image("objection"); set_size_and_pos(ui_take_that, "take_that"); - ui_take_that->set_image("takethat.png"); + ui_take_that->set_image("takethat"); set_size_and_pos(ui_ooc_toggle, "ooc_toggle"); ui_ooc_toggle->setText(tr("Server")); set_size_and_pos(ui_witness_testimony, "witness_testimony"); - ui_witness_testimony->set_image("witnesstestimony.png"); + ui_witness_testimony->set_image("witnesstestimony"); set_size_and_pos(ui_cross_examination, "cross_examination"); - ui_cross_examination->set_image("crossexamination.png"); + ui_cross_examination->set_image("crossexamination"); set_size_and_pos(ui_guilty, "guilty"); - ui_guilty->set_image("guilty.png"); + ui_guilty->set_image("guilty"); set_size_and_pos(ui_not_guilty, "not_guilty"); - ui_not_guilty->set_image("notguilty.png"); + ui_not_guilty->set_image("notguilty"); set_size_and_pos(ui_change_character, "change_character"); ui_change_character->setText(tr("Change character")); @@ -633,28 +633,28 @@ void Courtroom::set_widgets() set_size_and_pos(ui_showname_enable, "showname_enable"); set_size_and_pos(ui_custom_objection, "custom_objection"); - ui_custom_objection->set_image("custom.png"); + ui_custom_objection->set_image("custom"); set_size_and_pos(ui_realization, "realization"); - ui_realization->set_image("realization.png"); + ui_realization->set_image("realization"); set_size_and_pos(ui_screenshake, "screenshake"); - ui_screenshake->set_image("screenshake.png"); + ui_screenshake->set_image("screenshake"); set_size_and_pos(ui_mute, "mute_button"); - ui_mute->set_image("mute.png"); + ui_mute->set_image("mute"); set_size_and_pos(ui_defense_plus, "defense_plus"); - ui_defense_plus->set_image("defplus.png"); + ui_defense_plus->set_image("defplus"); set_size_and_pos(ui_defense_minus, "defense_minus"); - ui_defense_minus->set_image("defminus.png"); + ui_defense_minus->set_image("defminus"); set_size_and_pos(ui_prosecution_plus, "prosecution_plus"); - ui_prosecution_plus->set_image("proplus.png"); + ui_prosecution_plus->set_image("proplus"); set_size_and_pos(ui_prosecution_minus, "prosecution_minus"); - ui_prosecution_minus->set_image("prominus.png"); + ui_prosecution_minus->set_image("prominus"); set_size_and_pos(ui_text_color, "text_color"); @@ -665,40 +665,40 @@ void Courtroom::set_widgets() set_size_and_pos(ui_log_limit_spinbox, "log_limit_spinbox"); set_size_and_pos(ui_evidence_button, "evidence_button"); - ui_evidence_button->set_image("evidencebutton.png"); + ui_evidence_button->set_image("evidencebutton"); set_size_and_pos(ui_evidence, "evidence_background"); - ui_evidence->set_image("evidencebackground.png"); + ui_evidence->set_image("evidencebackground"); set_size_and_pos(ui_evidence_name, "evidence_name"); set_size_and_pos(ui_evidence_buttons, "evidence_buttons"); set_size_and_pos(ui_evidence_left, "evidence_left"); - ui_evidence_left->set_image("arrow_left.png"); + ui_evidence_left->set_image("arrow_left"); set_size_and_pos(ui_evidence_right, "evidence_right"); - ui_evidence_right->set_image("arrow_right.png"); + ui_evidence_right->set_image("arrow_right"); set_size_and_pos(ui_evidence_present, "evidence_present"); - ui_evidence_present->set_image("present_disabled.png"); + ui_evidence_present->set_image("present_disabled"); set_size_and_pos(ui_evidence_overlay, "evidence_overlay"); - ui_evidence_overlay->set_image("evidenceoverlay.png"); + ui_evidence_overlay->set_image("evidenceoverlay"); set_size_and_pos(ui_evidence_delete, "evidence_delete"); - ui_evidence_delete->set_image("deleteevidence.png"); + ui_evidence_delete->set_image("deleteevidence"); set_size_and_pos(ui_evidence_image_name, "evidence_image_name"); set_size_and_pos(ui_evidence_image_button, "evidence_image_button"); set_size_and_pos(ui_evidence_x, "evidence_x"); - ui_evidence_x->set_image("evidencex.png"); + ui_evidence_x->set_image("evidencex"); set_size_and_pos(ui_evidence_description, "evidence_description"); - ui_selector->set_image("char_selector.png"); + ui_selector->set_image("char_selector"); ui_selector->hide(); set_size_and_pos(ui_back_to_lobby, "back_to_lobby"); @@ -709,10 +709,10 @@ void Courtroom::set_widgets() set_size_and_pos(ui_char_buttons, "char_buttons"); set_size_and_pos(ui_char_select_left, "char_select_left"); - ui_char_select_left->set_image("arrow_left.png"); + ui_char_select_left->set_image("arrow_left"); set_size_and_pos(ui_char_select_right, "char_select_right"); - ui_char_select_right->set_image("arrow_right.png"); + ui_char_select_right->set_image("arrow_right"); set_size_and_pos(ui_spectator, "spectator"); @@ -869,9 +869,9 @@ void Courtroom::set_background(QString p_background) ui_vp_testimony->stop(); current_background = p_background; - is_ao2_bg = file_exists(ao_app->get_background_path("defensedesk.png")) && - file_exists(ao_app->get_background_path("prosecutiondesk.png")) && - file_exists(ao_app->get_background_path("stand.png")); + is_ao2_bg = file_exists(ao_app->get_static_image_suffix(ao_app->get_background_path("defensedesk"))) && + file_exists(ao_app->get_static_image_suffix(ao_app->get_background_path("prosecutiondesk"))) && + file_exists(ao_app->get_static_image_suffix(ao_app->get_background_path("stand"))); if (is_ao2_bg) { @@ -1386,6 +1386,9 @@ void Courtroom::handle_chatmessage(QStringList *p_contents) f_showname = m_chatmessage[SHOWNAME]; } + if(f_showname.trimmed().isEmpty()) //Pure whitespace showname, get outta here. + f_showname = m_chatmessage[CHAR_NAME]; + QString f_message = f_showname + ": " + m_chatmessage[MESSAGE] + '\n'; @@ -1409,13 +1412,13 @@ void Courtroom::handle_chatmessage(QStringList *p_contents) screenshake_state = 0; is_presenting_evidence = false; ui_pre->setChecked(false); - ui_hold_it->set_image("holdit.png"); - ui_objection->set_image("objection.png"); - ui_take_that->set_image("takethat.png"); - ui_custom_objection->set_image("custom.png"); - ui_realization->set_image("realization.png"); - ui_screenshake->set_image("screenshake.png"); - ui_evidence_present->set_image("present_disabled.png"); + ui_hold_it->set_image("holdit"); + ui_objection->set_image("objection"); + ui_take_that->set_image("takethat"); + ui_custom_objection->set_image("custom"); + ui_realization->set_image("realization"); + ui_screenshake->set_image("screenshake"); + ui_evidence_present->set_image("present_disabled"); if (ao_app->additive_enabled && ui_vp_player_char->m_char == m_chatmessage[CHAR_NAME]) @@ -1510,19 +1513,51 @@ void Courtroom::handle_chatmessage_2() ui_vp_showname->setText(m_chatmessage[SHOWNAME]); } + if(ui_vp_showname->text().trimmed().isEmpty()) //Whitespace showname + { + ui_vp_chatbox->set_image("chatblank"); + } + else //Aw yeah dude do some showname resizing magic + { + ui_vp_chatbox->set_image("chat"); + + QFontMetrics fm(ui_vp_showname->font()); + int fm_width=fm.horizontalAdvance(ui_vp_showname->text()); + + qDebug() << "showname shenanigans" << ui_vp_showname->width() << fm_width << ui_vp_showname->text(); + + QString chatbox_path = ao_app->get_theme_path("chat"); + QString chatbox = ao_app->get_chat(m_chatmessage[CHAR_NAME]); + qDebug() << chatbox; + if (chatbox != "") + { + chatbox_path = ao_app->get_base_path() + "misc/" + chatbox + "/chat"; + } + + pos_size_type default_width = ao_app->get_element_dimensions("showname", "courtroom_design.ini"); + int extra_width = ao_app->get_design_element("showname_extra_width", "courtroom_design.ini").toInt(); + qDebug() << extra_width; + + if(extra_width > 0) + { + qDebug() << default_width.width << chatbox_path; + + if (fm_width > default_width.width && ui_vp_chatbox->set_chatbox(chatbox_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_showname->resize(static_cast(default_width.width+(extra_width*2)), ui_vp_showname->height()); + } + } + else + ui_vp_showname->resize(default_width.width, ui_vp_showname->height()); + } + } + ui_vp_message->hide(); ui_vp_chatbox->hide(); - QString chatbox = ao_app->get_chat(m_chatmessage[CHAR_NAME]); - - if (chatbox == "") - ui_vp_chatbox->set_image("chatmed.png"); - else - { - QString chatbox_path = ao_app->get_base_path() + "misc/" + chatbox + "/chatbox.png"; - ui_vp_chatbox->set_image_from_path(chatbox_path); - } - QString design_file = "courtroom_fonts.ini"; int f_weight = ao_app->get_font_size("message", design_file); QString font_name = ao_app->get_font_name("message_font", design_file); @@ -2590,14 +2625,12 @@ void Courtroom::set_scene() f_background = "prohelperstand"; f_desk_image = "prohelperdesk"; } - else if (f_side == "jur" && (file_exists(ao_app->get_background_path("jurystand.png")) || - file_exists(ao_app->get_background_path("jurystand.gif")))) + else if (f_side == "jur" && file_exists(ao_app->get_image_suffix(ao_app->get_background_path("jurystand")))) { f_background = "jurystand"; f_desk_image = "jurydesk"; } - else if (f_side == "sea" && (file_exists(ao_app->get_background_path("seancestand.png")) || - file_exists(ao_app->get_background_path("seancestand.gif")))) + else if (f_side == "sea" && file_exists(ao_app->get_image_suffix(ao_app->get_background_path("seancestand")))) { f_background = "seancestand"; f_desk_image = "seancedesk"; @@ -2689,7 +2722,7 @@ void Courtroom::set_mute(bool p_muted, int p_cid) } ui_muted->resize(ui_ic_chat_message->width(), ui_ic_chat_message->height()); - ui_muted->set_image("muted.png"); + ui_muted->set_image("muted"); is_muted = p_muted; ui_ic_chat_message->setEnabled(!p_muted); @@ -2806,12 +2839,12 @@ void Courtroom::set_hp_bar(int p_bar, int p_state) if (p_bar == 1) { - ui_defense_bar->set_image("defensebar" + QString::number(p_state) + ".png"); + ui_defense_bar->set_image("defensebar" + QString::number(p_state)); defense_bar_state = p_state; } else if (p_bar == 2) { - ui_prosecution_bar->set_image("prosecutionbar" + QString::number(p_state) + ".png"); + ui_prosecution_bar->set_image("prosecutionbar" + QString::number(p_state)); prosecution_bar_state = p_state; } } @@ -3333,16 +3366,16 @@ void Courtroom::on_hold_it_clicked() { if (objection_state == 1) { - ui_hold_it->set_image("holdit.png"); + ui_hold_it->set_image("holdit"); objection_state = 0; } else { - ui_objection->set_image("objection.png"); - ui_take_that->set_image("takethat.png"); - ui_custom_objection->set_image("custom.png"); + ui_objection->set_image("objection"); + ui_take_that->set_image("takethat"); + ui_custom_objection->set_image("custom"); - ui_hold_it->set_image("holdit_selected.png"); + ui_hold_it->set_image("holdit_selected"); objection_state = 1; } @@ -3353,16 +3386,16 @@ void Courtroom::on_objection_clicked() { if (objection_state == 2) { - ui_objection->set_image("objection.png"); + ui_objection->set_image("objection"); objection_state = 0; } else { - ui_hold_it->set_image("holdit.png"); - ui_take_that->set_image("takethat.png"); - ui_custom_objection->set_image("custom.png"); + ui_hold_it->set_image("holdit"); + ui_take_that->set_image("takethat"); + ui_custom_objection->set_image("custom"); - ui_objection->set_image("objection_selected.png"); + ui_objection->set_image("objection_selected"); objection_state = 2; } @@ -3373,16 +3406,16 @@ void Courtroom::on_take_that_clicked() { if (objection_state == 3) { - ui_take_that->set_image("takethat.png"); + ui_take_that->set_image("takethat"); objection_state = 0; } else { - ui_objection->set_image("objection.png"); - ui_hold_it->set_image("holdit.png"); - ui_custom_objection->set_image("custom.png"); + ui_objection->set_image("objection"); + ui_hold_it->set_image("holdit"); + ui_custom_objection->set_image("custom"); - ui_take_that->set_image("takethat_selected.png"); + ui_take_that->set_image("takethat_selected"); objection_state = 3; } @@ -3393,16 +3426,16 @@ void Courtroom::on_custom_objection_clicked() { if (objection_state == 4) { - ui_custom_objection->set_image("custom.png"); + ui_custom_objection->set_image("custom"); objection_state = 0; } else { - ui_objection->set_image("objection.png"); - ui_take_that->set_image("takethat.png"); - ui_hold_it->set_image("holdit.png"); + ui_objection->set_image("objection"); + ui_take_that->set_image("takethat"); + ui_hold_it->set_image("holdit"); - ui_custom_objection->set_image("custom_selected.png"); + ui_custom_objection->set_image("custom_selected"); objection_state = 4; } @@ -3414,12 +3447,12 @@ void Courtroom::on_realization_clicked() if (realization_state == 0) { realization_state = 1; - ui_realization->set_image("realization_pressed.png"); + ui_realization->set_image("realization_pressed"); } else { realization_state = 0; - ui_realization->set_image("realization.png"); + ui_realization->set_image("realization"); } ui_ic_chat_message->setFocus(); @@ -3430,12 +3463,12 @@ void Courtroom::on_screenshake_clicked() if (screenshake_state == 0) { screenshake_state = 1; - ui_screenshake->set_image("screenshake_pressed.png"); + ui_screenshake->set_image("screenshake_pressed"); } else { screenshake_state = 0; - ui_screenshake->set_image("screenshake.png"); + ui_screenshake->set_image("screenshake"); } ui_ic_chat_message->setFocus(); @@ -3448,13 +3481,13 @@ void Courtroom::on_mute_clicked() ui_mute_list->show(); ui_pair_list->hide(); ui_pair_offset_spinbox->hide(); - ui_pair_button->set_image("pair_button.png"); - ui_mute->set_image("mute_pressed.png"); + ui_pair_button->set_image("pair_button"); + ui_mute->set_image("mute_pressed"); } else { ui_mute_list->hide(); - ui_mute->set_image("mute.png"); + ui_mute->set_image("mute"); } } @@ -3465,14 +3498,14 @@ void Courtroom::on_pair_clicked() ui_pair_list->show(); ui_pair_offset_spinbox->show(); ui_mute_list->hide(); - ui_mute->set_image("mute.png"); - ui_pair_button->set_image("pair_button_pressed.png"); + 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_button->set_image("pair_button.png"); + ui_pair_button->set_image("pair_button"); } } diff --git a/src/emotes.cpp b/src/emotes.cpp index b6a217e..daa8d6d 100644 --- a/src/emotes.cpp +++ b/src/emotes.cpp @@ -89,9 +89,9 @@ void Courtroom::set_emote_page() AOEmoteButton *f_emote = ui_emote_list.at(n_emote); if (n_real_emote == current_emote) - f_emote->set_image(current_char, n_real_emote, "_on.png"); + f_emote->set_image(current_char, n_real_emote, "_on"); else - f_emote->set_image(current_char, n_real_emote, "_off.png"); + f_emote->set_image(current_char, n_real_emote, "_off"); f_emote->show(); } @@ -119,14 +119,14 @@ void Courtroom::select_emote(int p_id) int max = (max_emotes_on_page - 1) + current_emote_page * max_emotes_on_page; if (current_emote >= min && current_emote <= max) - ui_emote_list.at(current_emote % max_emotes_on_page)->set_image(current_char, current_emote, "_off.png"); + ui_emote_list.at(current_emote % max_emotes_on_page)->set_image(current_char, current_emote, "_off"); int old_emote = current_emote; current_emote = p_id; if (current_emote >= min && current_emote <= max) - ui_emote_list.at(current_emote % max_emotes_on_page)->set_image(current_char, current_emote, "_on.png"); + ui_emote_list.at(current_emote % max_emotes_on_page)->set_image(current_char, current_emote, "_on"); int emote_mod = ao_app->get_emote_mod(current_char, current_emote); diff --git a/src/evidence.cpp b/src/evidence.cpp index 7e29b25..7580685 100644 --- a/src/evidence.cpp +++ b/src/evidence.cpp @@ -72,7 +72,7 @@ void Courtroom::construct_evidence() } } - connect(ui_evidence_name, SIGNAL(returnPressed()), this, SLOT(on_evidence_name_edited())); + connect(ui_evidence_name, SIGNAL(textEdited(QString)), this, SLOT(on_evidence_name_edited(QString))); connect(ui_evidence_left, SIGNAL(clicked()), this, SLOT(on_evidence_left_clicked())); connect(ui_evidence_right, SIGNAL(clicked()), this, SLOT(on_evidence_right_clicked())); connect(ui_evidence_present, SIGNAL(clicked()), this, SLOT(on_evidence_present_clicked())); @@ -153,7 +153,7 @@ void Courtroom::set_evidence_page() } } -void Courtroom::on_evidence_name_edited() +void Courtroom::on_evidence_name_edited(QString text) { if (current_evidence >= local_evidence_list.size()) return; @@ -163,6 +163,7 @@ void Courtroom::on_evidence_name_edited() evi_type f_evi = local_evidence_list.at(current_evidence); f_contents.append(QString::number(current_evidence)); + qDebug() << text; f_contents.append(ui_evidence_name->text()); f_contents.append(f_evi.description); f_contents.append(f_evi.image); @@ -297,9 +298,9 @@ void Courtroom::on_evidence_right_clicked() void Courtroom::on_evidence_present_clicked() { if (is_presenting_evidence) - ui_evidence_present->set_image("present_disabled.png"); + ui_evidence_present->set_image("present_disabled"); else - ui_evidence_present->set_image("present.png"); + ui_evidence_present->set_image("present"); is_presenting_evidence = !is_presenting_evidence; diff --git a/src/lobby.cpp b/src/lobby.cpp index 758f0fb..b8e3efd 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -84,28 +84,28 @@ void Lobby::set_widgets() } set_size_and_pos(ui_background, "lobby"); - ui_background->set_image("lobbybackground.png"); + ui_background->set_image("lobbybackground"); set_size_and_pos(ui_public_servers, "public_servers"); - ui_public_servers->set_image("publicservers_selected.png"); + ui_public_servers->set_image("publicservers_selected"); set_size_and_pos(ui_favorites, "favorites"); - ui_favorites->set_image("favorites.png"); + ui_favorites->set_image("favorites"); set_size_and_pos(ui_refresh, "refresh"); - ui_refresh->set_image("refresh.png"); + ui_refresh->set_image("refresh"); set_size_and_pos(ui_add_to_fav, "add_to_fav"); - ui_add_to_fav->set_image("addtofav.png"); + ui_add_to_fav->set_image("addtofav"); set_size_and_pos(ui_connect, "connect"); - ui_connect->set_image("connect.png"); + ui_connect->set_image("connect"); set_size_and_pos(ui_version, "version"); ui_version->setText(tr("Version: %1").arg(ao_app->get_version_string())); set_size_and_pos(ui_about, "about"); - ui_about->set_image("about.png"); + ui_about->set_image("about"); set_size_and_pos(ui_server_list, "server_list"); ui_server_list->setStyleSheet("background-color: rgba(0, 0, 0, 0);" @@ -135,7 +135,7 @@ void Lobby::set_widgets() "selection-background-color: rgba(0, 0, 0, 0);"); ui_loading_background->resize(this->width(), this->height()); - ui_loading_background->set_image("loadingbackground.png"); + ui_loading_background->set_image("loadingbackground"); set_size_and_pos(ui_loading_text, "loading_label"); @@ -262,8 +262,8 @@ void Lobby::set_loading_value(int p_value) void Lobby::on_public_servers_clicked() { - ui_public_servers->set_image("publicservers_selected.png"); - ui_favorites->set_image("favorites.png"); + ui_public_servers->set_image("publicservers_selected"); + ui_favorites->set_image("favorites"); list_servers(); @@ -272,8 +272,8 @@ void Lobby::on_public_servers_clicked() void Lobby::on_favorites_clicked() { - ui_favorites->set_image("favorites_selected.png"); - ui_public_servers->set_image("publicservers.png"); + ui_favorites->set_image("favorites_selected"); + ui_public_servers->set_image("publicservers"); ao_app->set_favorite_list(); //ao_app->favorite_list = read_serverlist_txt(); @@ -285,12 +285,12 @@ void Lobby::on_favorites_clicked() void Lobby::on_refresh_pressed() { - ui_refresh->set_image("refresh_pressed.png"); + ui_refresh->set_image("refresh_pressed"); } void Lobby::on_refresh_released() { - ui_refresh->set_image("refresh.png"); + ui_refresh->set_image("refresh"); AOPacket *f_packet = new AOPacket("ALL#%"); @@ -299,12 +299,12 @@ void Lobby::on_refresh_released() void Lobby::on_add_to_fav_pressed() { - ui_add_to_fav->set_image("addtofav_pressed.png"); + ui_add_to_fav->set_image("addtofav_pressed"); } void Lobby::on_add_to_fav_released() { - ui_add_to_fav->set_image("addtofav.png"); + ui_add_to_fav->set_image("addtofav"); //you cant add favorites from favorites m8 if (!public_servers_selected) @@ -315,12 +315,12 @@ void Lobby::on_add_to_fav_released() void Lobby::on_connect_pressed() { - ui_connect->set_image("connect_pressed.png"); + ui_connect->set_image("connect_pressed"); } void Lobby::on_connect_released() { - ui_connect->set_image("connect.png"); + ui_connect->set_image("connect"); AOPacket *f_packet; @@ -416,8 +416,8 @@ void Lobby::on_chatfield_return_pressed() void Lobby::list_servers() { public_servers_selected = true; - ui_favorites->set_image("favorites.png"); - ui_public_servers->set_image("publicservers_selected.png"); + ui_favorites->set_image("favorites"); + ui_public_servers->set_image("publicservers_selected"); ui_server_list->clear(); diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index 02c0b71..48ebeea 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -292,6 +292,15 @@ pos_size_type AOApplication::get_element_dimensions(QString p_identifier, QStrin return return_value; } +QString AOApplication::get_design_element(QString p_identifier, QString p_file) +{ + 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); + return f_result; +} QString AOApplication::get_font_name(QString p_identifier, QString p_file) { QString design_ini_path = get_theme_path(p_file); @@ -501,6 +510,10 @@ QString AOApplication::get_image_suffix(QString path_to_check) return path_to_check + ".png"; } +QString AOApplication::get_static_image_suffix(QString path_to_check) +{ + return path_to_check + ".png"; +} //returns whatever is to the right of "search_line =" within target_tag and terminator_tag, trimmed //returns the empty string if the search line couldnt be found From f3c7beab70aeb1e9b1446553c3cb57345a1e5eb7 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Mon, 16 Sep 2019 21:10:21 +0300 Subject: [PATCH 047/268] Chat arrow indicator to inform you if the current message stopped being processed Can be modified from the theme in chat_arrow of courtroom_design.ini Uses chat_arrow .png/.gif/etc. --- include/courtroom.h | 1 + src/courtroom.cpp | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/include/courtroom.h b/include/courtroom.h index 9b3c057..45a3dfd 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -424,6 +424,7 @@ private: AOEvidenceDisplay *ui_vp_evidence_display; AOImage *ui_vp_chatbox; QLabel *ui_vp_showname; + AOMovie *ui_vp_chat_arrow; QTextEdit *ui_vp_message; AOMovie *ui_vp_realization; AOMovie *ui_vp_testimony; diff --git a/src/courtroom.cpp b/src/courtroom.cpp index cfdc8fb..b2c98bc 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -87,6 +87,9 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_vp_chatbox = new AOImage(this, ao_app); ui_vp_showname = new QLabel(ui_vp_chatbox); ui_vp_showname->setAlignment(Qt::AlignHCenter); + ui_vp_chat_arrow = new AOMovie(ui_vp_chatbox, ao_app); + ui_vp_chat_arrow->set_play_once(false); + ui_vp_message = new QTextEdit(this); ui_vp_message->setFrameStyle(QFrame::NoFrame); ui_vp_message->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); @@ -491,6 +494,20 @@ void Courtroom::set_widgets() // ui_vp_message->setStyleSheet("background-color: rgba(0, 0, 0, 0);" // "color: white"); + ui_vp_chat_arrow->move(0, 0); + pos_size_type design_ini_result = ao_app->get_element_dimensions("chat_arrow", "courtroom_design.ini"); + + 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(); + } + else + { + ui_vp_chat_arrow->move(design_ini_result.x, design_ini_result.y); + ui_vp_chat_arrow->combo_resize(design_ini_result.width, design_ini_result.height); + } + ui_vp_testimony->move(ui_viewport->x(), ui_viewport->y()); ui_vp_testimony->combo_resize(ui_viewport->width(), ui_viewport->height()); @@ -1395,6 +1412,9 @@ void Courtroom::handle_chatmessage(QStringList *p_contents) if (f_message == previous_ic_message) return; + //Stop the chat arrow from animating + ui_vp_chat_arrow->stop(); + text_state = 0; anim_state = 0; ui_vp_objection->stop(); @@ -2302,6 +2322,7 @@ void Courtroom::chat_tick() anim_state = 3; ui_vp_player_char->play_idle(m_chatmessage[CHAR_NAME], m_chatmessage[EMOTE]); } + ui_vp_chat_arrow->play("chat_arrow"); //Chat stopped being processed, indicate that. } else From 13221319b889a48255f8409389ef41f37ee8ac98 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Mon, 16 Sep 2019 23:22:34 +0300 Subject: [PATCH 048/268] Change get_stylesheet to return text of a parsed stylesheet file, its functionality was transferred to get_tagged_stylesheet Remove some useless/unused ui elements Implement stylesheet for courtrooms in a way that lets the end user modify a lot of its elements Use get_image_suffix for evidence_appear images --- include/aoapplication.h | 6 ++- include/courtroom.h | 9 ++-- src/aoevidencedisplay.cpp | 11 ++--- src/courtroom.cpp | 95 +++++++++++-------------------------- src/lobby.cpp | 2 +- src/text_file_functions.cpp | 31 +++++++++++- 6 files changed, 72 insertions(+), 82 deletions(-) diff --git a/include/aoapplication.h b/include/aoapplication.h index 052ad08..c33130f 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -259,8 +259,12 @@ public: //Returns a QStringList of all key=value definitions on a given tag. QStringList read_char_ini_tag(QString p_char, QString target_tag); + //Returns the text between target_tag and terminator_tag in p_file - QString get_stylesheet(QString target_tag, QString p_file); + QString get_stylesheet(QString p_file); + + //Returns the text between target_tag and terminator_tag in p_file + QString get_tagged_stylesheet(QString target_tag, QString p_file); //Returns the side of the p_char character from that characters ini file QString get_char_side(QString p_char); diff --git a/include/courtroom.h b/include/courtroom.h index 45a3dfd..0a7002b 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -119,16 +119,16 @@ public: void set_widgets(); //sets font size based on theme ini files - void set_font(QWidget *widget, QString p_identifier); + void set_font(QWidget *widget, QString class_name, QString p_identifier); //actual operation of setting the font on a widget - void set_qfont(QWidget *widget, QFont font, QColor f_color = Qt::black, bool bold = false); + void set_qfont(QWidget *widget, QString class_name, QFont font, QColor f_color = Qt::black, bool bold = false); //helper function that calls above function on the relevant widgets void set_fonts(); //sets dropdown menu stylesheet - void set_dropdown(QWidget *widget, QString target_tag); + void set_dropdown(QWidget *widget); //helper funciton that call above function on the relevant widgets void set_dropdowns(); @@ -514,9 +514,6 @@ private: AOImage *ui_muted; - QSpinBox *ui_log_limit_spinbox; - QLabel *ui_log_limit_label; - AOButton *ui_evidence_button; AOImage *ui_evidence; AOLineEdit *ui_evidence_name; diff --git a/src/aoevidencedisplay.cpp b/src/aoevidencedisplay.cpp index 9ec105d..3fde05a 100644 --- a/src/aoevidencedisplay.cpp +++ b/src/aoevidencedisplay.cpp @@ -32,12 +32,12 @@ void AOEvidenceDisplay::show_evidence(QString p_evidence_image, bool is_left_sid if (is_left_side) { icon_identifier = "left_evidence_icon"; - gif_name = "evidence_appear_left.gif"; + gif_name = "evidence_appear_left"; } else { icon_identifier = "right_evidence_icon"; - gif_name = "evidence_appear_right.gif"; + gif_name = "evidence_appear_right"; } pos_size_type icon_dimensions = ao_app->get_element_dimensions(icon_identifier, "courtroom_design.ini"); @@ -47,8 +47,8 @@ void AOEvidenceDisplay::show_evidence(QString p_evidence_image, bool is_left_sid evidence_icon->setPixmap(f_pixmap.scaled(evidence_icon->width(), evidence_icon->height(), Qt::IgnoreAspectRatio)); - QString f_default_gif_path = ao_app->get_default_theme_path(gif_name); - QString f_gif_path = ao_app->get_theme_path(gif_name); + QString f_default_gif_path = ao_app->get_image_suffix(ao_app->get_default_theme_path(gif_name)); + QString f_gif_path = ao_app->get_image_suffix(ao_app->get_theme_path(gif_name)); if (file_exists(f_gif_path)) final_gif_path = f_gif_path; @@ -57,9 +57,6 @@ void AOEvidenceDisplay::show_evidence(QString p_evidence_image, bool is_left_sid evidence_movie->setFileName(final_gif_path); - if(evidence_movie->frameCount() < 1) - return; - this->setMovie(evidence_movie); evidence_movie->start(); diff --git a/src/courtroom.cpp b/src/courtroom.cpp index b2c98bc..6c8a9bd 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -84,7 +84,7 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_vp_evidence_display = new AOEvidenceDisplay(this, ao_app); - ui_vp_chatbox = new AOImage(this, ao_app); + ui_vp_chatbox = new AOImage(ui_viewport, ao_app); ui_vp_showname = new QLabel(ui_vp_chatbox); ui_vp_showname->setAlignment(Qt::AlignHCenter); ui_vp_chat_arrow = new AOMovie(ui_vp_chatbox, ao_app); @@ -170,8 +170,6 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_sfx_label = new QLabel(this); ui_blip_label = new QLabel(this); - ui_log_limit_label = new QLabel(this); - ui_hold_it = new AOButton(this, ao_app); ui_objection = new AOButton(this, ao_app); ui_take_that = new AOButton(this, ao_app); @@ -251,10 +249,6 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_blip_slider->setRange(0, 100); ui_blip_slider->setValue(ao_app->get_default_blip()); - ui_log_limit_spinbox = new QSpinBox(this); - ui_log_limit_spinbox->setRange(0, 10000); - ui_log_limit_spinbox->setValue(ao_app->get_max_log_size()); - ui_mute_list = new QListWidget(this); ui_pair_list = new QListWidget(this); @@ -318,8 +312,6 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() connect(ui_sfx_slider, SIGNAL(valueChanged(int)), this, SLOT(on_sfx_slider_moved(int))); connect(ui_blip_slider, SIGNAL(valueChanged(int)), this, SLOT(on_blip_slider_moved(int))); - connect(ui_log_limit_spinbox, SIGNAL(valueChanged(int)), this, SLOT(on_log_limit_changed(int))); - connect(ui_ooc_toggle, SIGNAL(clicked()), this, SLOT(on_ooc_toggle_clicked())); connect(ui_music_search, SIGNAL(textChanged(QString)), this, SLOT(on_music_search_edited(QString))); @@ -456,8 +448,6 @@ void Courtroom::set_widgets() // We also show the non-server-dependent client additions. // Once again, if the theme can't display it, set_move_and_pos will catch them. ui_settings->show(); - ui_log_limit_label->show(); - ui_log_limit_spinbox->show(); ui_vp_background->move(0, 0); ui_vp_background->resize(ui_viewport->width(), ui_viewport->height()); @@ -594,9 +584,6 @@ void Courtroom::set_widgets() set_size_and_pos(ui_blip_label, "blip_label"); ui_blip_label->setText(tr("Blips")); - set_size_and_pos(ui_log_limit_label, "log_limit_label"); - ui_log_limit_label->setText(tr("Log limit")); - set_size_and_pos(ui_hold_it, "hold_it"); ui_hold_it->set_image("holdit"); set_size_and_pos(ui_objection, "objection"); @@ -679,8 +666,6 @@ void Courtroom::set_widgets() set_size_and_pos(ui_sfx_slider, "sfx_slider"); set_size_and_pos(ui_blip_slider, "blip_slider"); - set_size_and_pos(ui_log_limit_spinbox, "log_limit_spinbox"); - set_size_and_pos(ui_evidence_button, "evidence_button"); ui_evidence_button->set_image("evidencebutton"); @@ -732,33 +717,22 @@ void Courtroom::set_widgets() ui_char_select_right->set_image("arrow_right"); set_size_and_pos(ui_spectator, "spectator"); - - set_dropdowns(); } void Courtroom::set_fonts() { - set_font(ui_vp_showname, "showname"); - set_font(ui_vp_message, "message"); - set_font(ui_ic_chatlog, "ic_chatlog"); - set_font(ui_ms_chatlog, "ms_chatlog"); - set_font(ui_server_chatlog, "server_chatlog"); - set_font(ui_music_list, "music_list"); - set_font(ui_area_list, "area_list"); + set_font(ui_vp_showname, "", "showname"); + set_font(ui_vp_message, "", "message"); + set_font(ui_ic_chatlog, "", "ic_chatlog"); + set_font(ui_ms_chatlog, "", "ms_chatlog"); + set_font(ui_server_chatlog, "", "server_chatlog"); + set_font(ui_music_list, "", "music_list"); + set_font(ui_area_list, "", "area_list"); - // Set color of labels and checkboxes - const QString design_file = "courtroom_fonts.ini"; - QColor f_color = ao_app->get_color("label_color", design_file); - QString color_string = "color: rgba(" + - QString::number(f_color.red()) + ", " + - QString::number(f_color.green()) + ", " + - QString::number(f_color.blue()) + ", 255); }"; - QString style_sheet_string = "QLabel {" + color_string + "}" - "QCheckBox {" + color_string + "}"; - setStyleSheet(style_sheet_string); + set_dropdowns(); } -void Courtroom::set_font(QWidget *widget, QString p_identifier) +void Courtroom::set_font(QWidget *widget, QString class_name, QString p_identifier) { QString design_file = "courtroom_fonts.ini"; int f_weight = ao_app->get_font_size(p_identifier, design_file); @@ -766,41 +740,41 @@ void Courtroom::set_font(QWidget *widget, QString p_identifier) QColor f_color = ao_app->get_color(p_identifier + "_color", design_file); bool bold = ao_app->get_font_size(p_identifier + "_bold", design_file) == 1; // is the font bold or not? - this->set_qfont(widget, QFont(font_name, f_weight), f_color, bold); + this->set_qfont(widget, class_name, QFont(font_name, f_weight), f_color, bold); } -void Courtroom::set_qfont(QWidget *widget, QFont font, QColor f_color, bool bold) +void Courtroom::set_qfont(QWidget *widget, QString class_name, QFont font, QColor f_color, bool bold) { - QString class_name = widget->metaObject()->className(); + if(class_name == "") + class_name = widget->metaObject()->className(); widget->setFont(font); QString is_bold = ""; - if(bold) is_bold = "bold"; + if(bold) is_bold = "font: bold;"; QString style_sheet_string = class_name + " { background-color: rgba(0, 0, 0, 0);\n" + "color: rgba(" + QString::number(f_color.red()) + ", " + QString::number(f_color.green()) + ", " + - QString::number(f_color.blue()) + ", 255);\n" - "font: " + is_bold + "; }"; - + QString::number(f_color.blue()) + ", 255);\n" + is_bold + "}"; widget->setStyleSheet(style_sheet_string); } -void Courtroom::set_dropdown(QWidget *widget, QString target_tag) +void Courtroom::set_dropdown(QWidget *widget) { QString f_file = "courtroom_stylesheets.css"; - QString style_sheet_string = ao_app->get_stylesheet(target_tag, f_file); + QString style_sheet_string = ao_app->get_stylesheet(f_file); if (style_sheet_string != "") widget->setStyleSheet(style_sheet_string); } void Courtroom::set_dropdowns() { - set_dropdown(ui_text_color, "[TEXT COLOR]"); - set_dropdown(ui_pos_dropdown, "[POS DROPDOWN]"); - set_dropdown(ui_emote_dropdown, "[EMOTE DROPDOWN]"); - set_dropdown(ui_mute_list, "[MUTE LIST]"); + set_dropdown(this); //EXPERIMENTAL - Read the style-sheet as-is for maximum memeage +// set_dropdown(ui_text_color, "[TEXT COLOR]"); +// set_dropdown(ui_pos_dropdown, "[POS DROPDOWN]"); +// set_dropdown(ui_emote_dropdown, "[EMOTE DROPDOWN]"); +// set_dropdown(ui_mute_list, "[MUTE LIST]"); } void Courtroom::set_window_title(QString p_title) @@ -903,7 +877,7 @@ void Courtroom::set_background(QString p_background) } void Courtroom::enter_courtroom(int p_cid) -{ +{ m_cid = p_cid; QString f_char; @@ -1322,9 +1296,7 @@ void Courtroom::on_chat_return_pressed() if (ao_app->looping_sfx_support_enabled) { packet_contents.append("0"); //ao_app->get_sfx_looping(current_char, current_emote)); -// qDebug() << "Are we looping this? " << ao_app->get_sfx_looping(current_char, current_emote); packet_contents.append(QString::number(screenshake_state)); - qDebug() << "Are we screen shaking this one? " << screenshake_state; QString pre_emote = ao_app->get_pre_emote(current_char, current_emote); QString emote = ao_app->get_emote(current_char, current_emote); @@ -1345,7 +1317,6 @@ void Courtroom::on_chat_return_pressed() } packet += "^"; } - qDebug() << f_effect << "packet" << packet; packet_contents.append(packet); } } @@ -1544,11 +1515,8 @@ void Courtroom::handle_chatmessage_2() QFontMetrics fm(ui_vp_showname->font()); int fm_width=fm.horizontalAdvance(ui_vp_showname->text()); - qDebug() << "showname shenanigans" << ui_vp_showname->width() << fm_width << ui_vp_showname->text(); - QString chatbox_path = ao_app->get_theme_path("chat"); QString chatbox = ao_app->get_chat(m_chatmessage[CHAR_NAME]); - qDebug() << chatbox; if (chatbox != "") { chatbox_path = ao_app->get_base_path() + "misc/" + chatbox + "/chat"; @@ -1556,12 +1524,9 @@ void Courtroom::handle_chatmessage_2() pos_size_type default_width = ao_app->get_element_dimensions("showname", "courtroom_design.ini"); int extra_width = ao_app->get_design_element("showname_extra_width", "courtroom_design.ini").toInt(); - qDebug() << extra_width; if(extra_width > 0) { - qDebug() << default_width.width << chatbox_path; - if (fm_width > default_width.width && ui_vp_chatbox->set_chatbox(chatbox_path + "med")) //This text be big. Let's do some shenanigans. { ui_vp_showname->resize(default_width.width+extra_width, ui_vp_showname->height()); @@ -1591,9 +1556,7 @@ void Courtroom::handle_chatmessage_2() int chatsize = ao_app->get_chat_size(m_chatmessage[CHAR_NAME]); if (chatsize != -1) f_weight = chatsize; - this->set_qfont(ui_vp_message, QFont(font_name, f_weight), f_color, bold); - - ui_vp_showname->setStyleSheet("QLabel { color : " + get_text_color("_showname").name() + "; }"); + this->set_qfont(ui_vp_message, "", QFont(font_name, f_weight), f_color, bold); set_scene(); set_text_color(); @@ -1866,7 +1829,7 @@ void Courtroom::handle_chatmessage_3() ui_vp_legacy_desk->hide(); // Since we're zooming, hide the second character, and centre the first. - ui_vp_sideplayer_char->hide(); + ui_vp_sideplayer_char->hide(); ui_vp_player_char->move(0,0); if (side == "pro" || @@ -2960,7 +2923,7 @@ void Courtroom::on_ooc_return_pressed() { ui_ooc_chat_message->clear(); ooc_message.remove(0,6); - + bool ok; int whom = ooc_message.toInt(&ok); if (ok) @@ -2989,7 +2952,7 @@ void Courtroom::on_ooc_return_pressed() { ui_ooc_chat_message->clear(); ooc_message.remove(0,8); - + bool ok; int off = ooc_message.toInt(&ok); if (ok) @@ -3651,7 +3614,7 @@ void Courtroom::on_change_character_clicked() } void Courtroom::on_reload_theme_clicked() -{ +{ ao_app->reload_theme(); //to update status on the background diff --git a/src/lobby.cpp b/src/lobby.cpp index b8e3efd..963ed44 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -190,7 +190,7 @@ void Lobby::set_fonts() void Lobby::set_stylesheet(QWidget *widget, QString target_tag) { QString f_file = "lobby_stylesheets.css"; - QString style_sheet_string = ao_app->get_stylesheet(target_tag, f_file); + QString style_sheet_string = ao_app->get_tagged_stylesheet(target_tag, f_file); if (style_sheet_string != "") widget->setStyleSheet(style_sheet_string); } diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index 48ebeea..a70fdc5 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -359,7 +359,36 @@ QColor AOApplication::get_color(QString p_identifier, QString p_file) return return_color; } -QString AOApplication::get_stylesheet(QString target_tag, 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); + + 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 ""; + } + + QTextStream in(&design_ini); + + QString f_text; + + while(!in.atEnd()) + { + f_text.append(in.readLine()); + } + + design_ini.close(); + return f_text; +} + +QString AOApplication::get_tagged_stylesheet(QString target_tag, QString p_file) { QString design_ini_path = get_theme_path(p_file); From 19ff6cd5f8a74188d65aa0a0ffaf2827f6471586 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Mon, 16 Sep 2019 23:53:32 +0300 Subject: [PATCH 049/268] Fix an incredibly obscure bug where if the viewport message is inside the viewport itself it would not let you scroll it up should the message be too long. --- src/courtroom.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 6c8a9bd..08ece88 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -2231,6 +2231,7 @@ void Courtroom::start_chat_ticking() ui_vp_chatbox->show(); ui_vp_message->show(); + ui_vp_message->raise(); //So you can scroll it if (!is_additive) { From 684e26cb776b143175590845c77813763927e759 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Mon, 16 Sep 2019 23:54:42 +0300 Subject: [PATCH 050/268] Change the way sideplayer/playerchar ordering works to be stackUnder instead of Raise so it doesn't break anything (like the chatbox) --- src/courtroom.cpp | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 08ece88..f01c178 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1635,16 +1635,12 @@ void Courtroom::handle_chatmessage_2() // The person more to the left is more in the front. if (hor2_offset >= hor_offset) { - ui_vp_sideplayer_char->raise(); - ui_vp_player_char->raise(); + ui_vp_sideplayer_char->stackUnder(ui_vp_player_char); } else { - ui_vp_player_char->raise(); - ui_vp_sideplayer_char->raise(); + ui_vp_player_char->stackUnder(ui_vp_sideplayer_char); } - ui_vp_desk->raise(); - ui_vp_legacy_desk->raise(); } else if (side == "pro") { @@ -1668,18 +1664,14 @@ void Courtroom::handle_chatmessage_2() ui_vp_sideplayer_char->move(ui_viewport->width() * hor2_offset / 100, ui_viewport->height() * vert2_offset / 100); // Finally, we reorder them based on who is more to the right. - if (hor2_offset <= hor_offset) + if (hor2_offset >= hor_offset) { - ui_vp_sideplayer_char->raise(); - ui_vp_player_char->raise(); + ui_vp_sideplayer_char->stackUnder(ui_vp_player_char); } else { - ui_vp_player_char->raise(); - ui_vp_sideplayer_char->raise(); + ui_vp_player_char->stackUnder(ui_vp_sideplayer_char); } - ui_vp_desk->raise(); - ui_vp_legacy_desk->raise(); } else { @@ -1696,16 +1688,12 @@ void Courtroom::handle_chatmessage_2() // The person more to the left is more in the front. if (hor2_offset >= hor_offset) { - ui_vp_sideplayer_char->raise(); - ui_vp_player_char->raise(); + ui_vp_sideplayer_char->stackUnder(ui_vp_player_char); } else { - ui_vp_player_char->raise(); - ui_vp_sideplayer_char->raise(); + ui_vp_player_char->stackUnder(ui_vp_sideplayer_char); } - ui_vp_desk->raise(); - ui_vp_legacy_desk->raise(); } // We should probably also play the other character's idle emote. if (ao_app->flipping_enabled && m_chatmessage[OTHER_FLIP].toInt() == 1) From 9695c621c23e3ebe1fded621c13eaea75bfc4372 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Tue, 17 Sep 2019 00:56:39 +0300 Subject: [PATCH 051/268] so this solution doesn't really work. It makes the chat message box appear over the character select screen. this bug only occurs when the chat box is initialized inside the viewport. Annoying as hell but at least it can be reproduced reliably. --- src/courtroom.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index f01c178..3f06b79 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -2219,7 +2219,6 @@ void Courtroom::start_chat_ticking() ui_vp_chatbox->show(); ui_vp_message->show(); - ui_vp_message->raise(); //So you can scroll it if (!is_additive) { From 6747bfdd5edee3693144c088ad1e732b5748fb8b Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Tue, 17 Sep 2019 03:31:18 +0300 Subject: [PATCH 052/268] Allow lobby server descriptions to parse links Fix bad reference to ui_emote_right image Fix chatbox being part of the viewport (gets cut off if it's outside) --- include/aotextarea.h | 1 + src/aotextarea.cpp | 6 ++++++ src/courtroom.cpp | 4 ++-- src/lobby.cpp | 3 ++- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/include/aotextarea.h b/include/aotextarea.h index 266b722..13b29c9 100644 --- a/include/aotextarea.h +++ b/include/aotextarea.h @@ -12,6 +12,7 @@ class AOTextArea : public QTextBrowser public: AOTextArea(QWidget *p_parent = nullptr); + void append_linked(QString p_message); void append_chatmessage(QString p_name, QString p_message, QString p_colour); void append_error(QString p_message); diff --git a/src/aotextarea.cpp b/src/aotextarea.cpp index f9d21e6..a34bb1a 100644 --- a/src/aotextarea.cpp +++ b/src/aotextarea.cpp @@ -5,6 +5,12 @@ AOTextArea::AOTextArea(QWidget *p_parent) : QTextBrowser(p_parent) } +void AOTextArea::append_linked(QString p_message) +{ + QString result = p_message.toHtmlEscaped().replace("\n", "
").replace(url_parser_regex, "\\1" ); + this->insertHtml(result); +} + void AOTextArea::append_chatmessage(QString p_name, QString p_message, QString p_colour) { const QTextCursor old_cursor = this->textCursor(); diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 3f06b79..a179fb8 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -84,7 +84,7 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_vp_evidence_display = new AOEvidenceDisplay(this, ao_app); - ui_vp_chatbox = new AOImage(ui_viewport, ao_app); + ui_vp_chatbox = new AOImage(this, ao_app); ui_vp_showname = new QLabel(ui_vp_chatbox); ui_vp_showname->setAlignment(Qt::AlignHCenter); ui_vp_chat_arrow = new AOMovie(ui_vp_chatbox, ao_app); @@ -566,7 +566,7 @@ void Courtroom::set_widgets() ui_emote_left->set_image("arrow_left"); set_size_and_pos(ui_emote_right, "emote_right"); - ui_emote_right->set_image("arrow_right."); + ui_emote_right->set_image("arrow_right"); set_size_and_pos(ui_emote_dropdown, "emote_dropdown"); set_size_and_pos(ui_pos_dropdown, "pos_dropdown"); diff --git a/src/lobby.cpp b/src/lobby.cpp index 963ed44..79f18e5 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -23,6 +23,7 @@ Lobby::Lobby(AOApplication *p_ao_app) : QMainWindow() ui_server_list = new QListWidget(this); ui_player_count = new QLabel(this); ui_description = new AOTextArea(this); + ui_description->setOpenExternalLinks(true); ui_chatbox = new AOTextArea(this); ui_chatbox->setOpenExternalLinks(true); ui_chatname = new QLineEdit(this); @@ -376,7 +377,7 @@ void Lobby::on_server_list_clicked(QModelIndex p_model) } ui_description->clear(); - ui_description->append(f_server.desc); + ui_description->append_linked(f_server.desc); ui_description->moveCursor(QTextCursor::Start); ui_description->ensureCursorVisible(); From 9d20cf03222add2ef04d4d2cc305458bdf00fcad Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Tue, 17 Sep 2019 18:51:40 +0300 Subject: [PATCH 053/268] Streamlined ini swapping so the user can set up multiple character folders associated with a character. This will save to the character folder's iniswaps.ini. You can click on the dropdown and edit the text inside to add an iniswap, and press the [X] button that'll appear next to it to remove the ini swap. Recode the enter_courtroom and add a new update_character feature - the two are now separate and responsible for different things. The courtroom will reload the whole theme and widgets while the character is only responsible for all ui elements related to the character. This drastically improves performance when switching characters using /switch or something Add a set_char_ini helper function that allows you to modify the character variables. For now only used to set name= field when iniswapping --- include/aoapplication.h | 5 ++ include/courtroom.h | 12 +++- src/charselect.cpp | 10 ++- src/courtroom.cpp | 120 +++++++++++++++++++++++++++++++----- src/packet_distribution.cpp | 2 +- src/text_file_functions.cpp | 21 +++++-- 6 files changed, 141 insertions(+), 29 deletions(-) diff --git a/include/aoapplication.h b/include/aoapplication.h index c33130f..f26c816 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -202,6 +202,9 @@ public: //Returns the list of words in callwords.ini QStringList get_call_words(); + //returns all of the file's lines in a QStringList + QStringList get_list_file(QString p_file); + //Process a file and return its text as a QString QString read_file(QString filename); @@ -259,6 +262,8 @@ public: //Returns a QStringList of all key=value definitions on a given tag. QStringList read_char_ini_tag(QString p_char, QString target_tag); + //Sets the char.ini p_search_line key under tag target_tag to value. + void set_char_ini(QString p_char, QString value, QString p_search_line, QString target_tag); //Returns the text between target_tag and terminator_tag in p_file QString get_stylesheet(QString p_file); diff --git a/include/courtroom.h b/include/courtroom.h index 0a7002b..91f1f9a 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -184,8 +184,11 @@ public: QString get_current_char() {return current_char;} QString get_current_background() {return current_background;} + //updates character to p_cid and updates necessary ui elements + void update_character(int p_cid); + //properly sets up some varibles: resets user state - void enter_courtroom(int p_cid); + void enter_courtroom(); //helper function that populates ui_music_list with the contents of music_list void list_music(); @@ -461,6 +464,9 @@ private: QComboBox *ui_emote_dropdown; QComboBox *ui_pos_dropdown; + QComboBox *ui_iniswap_dropdown; + AOButton *ui_iniswap_remove; + AOImage *ui_defense_bar; AOImage *ui_prosecution_bar; @@ -602,6 +608,10 @@ private slots: void on_emote_dropdown_changed(int p_index); void on_pos_dropdown_changed(int p_index); + void on_iniswap_dropdown_changed(int p_index); + + void set_iniswap_dropdown(); + void on_iniswap_remove_clicked(); void on_evidence_name_edited(QString text); void on_evidence_image_name_edited(); diff --git a/src/charselect.cpp b/src/charselect.cpp index 23b0513..972a17a 100644 --- a/src/charselect.cpp +++ b/src/charselect.cpp @@ -64,7 +64,7 @@ void Courtroom::set_char_select() if (f_charselect.width < 0 || f_charselect.height < 0) { - qDebug() << "W: did not find courtroom width or height in courtroom_design.ini!"; + qDebug() << "W: did not find char_select width or height in courtroom_design.ini!"; this->resize(714, 668); } else @@ -129,15 +129,13 @@ void Courtroom::char_clicked(int n_char) return; } - if (n_char == m_cid) - { - enter_courtroom(m_cid); - } - else + if (n_char != m_cid) { ao_app->send_server_packet(new AOPacket("PW#" + ui_char_password->text() + "#%")); ao_app->send_server_packet(new AOPacket("CC#" + QString::number(ao_app->s_pv) + "#" + QString::number(n_char) + "#" + get_hdid() + "#%")); } + update_character(n_char); + enter_courtroom(); ui_ic_chat_name->setPlaceholderText(char_list.at(n_char).name); } diff --git a/src/courtroom.cpp b/src/courtroom.cpp index a179fb8..2b8f218 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -163,6 +163,9 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_pos_dropdown->addItem("jur"); ui_pos_dropdown->addItem("sea"); + ui_iniswap_dropdown = new QComboBox(this); + ui_iniswap_remove = new AOButton(this, ao_app); + ui_defense_bar = new AOImage(this, ao_app); ui_prosecution_bar = new AOImage(this, ao_app); @@ -282,6 +285,9 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() connect(ui_emote_dropdown, SIGNAL(activated(int)), this, SLOT(on_emote_dropdown_changed(int))); connect(ui_pos_dropdown, SIGNAL(currentIndexChanged(int)), this, SLOT(on_pos_dropdown_changed(int))); + connect(ui_iniswap_dropdown, SIGNAL(activated(int)), this, SLOT(on_iniswap_dropdown_changed(int))); + connect(ui_iniswap_remove, SIGNAL(clicked()), this, SLOT(on_iniswap_remove_clicked())); + connect(ui_mute_list, SIGNAL(clicked(QModelIndex)), this, SLOT(on_mute_list_clicked(QModelIndex))); connect(ui_ic_chat_message, SIGNAL(returnPressed()), this, SLOT(on_chat_return_pressed())); @@ -571,6 +577,13 @@ void Courtroom::set_widgets() set_size_and_pos(ui_emote_dropdown, "emote_dropdown"); set_size_and_pos(ui_pos_dropdown, "pos_dropdown"); + set_size_and_pos(ui_iniswap_dropdown, "iniswap_dropdown"); + ui_iniswap_dropdown->setEditable(true); + ui_iniswap_dropdown->setInsertPolicy(QComboBox::InsertAtBottom); + set_size_and_pos(ui_iniswap_remove, "iniswap_remove"); +// ui_iniswap_remove->setText("X"); + ui_iniswap_remove->set_image("evidencex"); + set_size_and_pos(ui_defense_bar, "defense_bar"); ui_defense_bar->set_image("defensebar" + QString::number(defense_bar_state)); @@ -585,10 +598,15 @@ void Courtroom::set_widgets() ui_blip_label->setText(tr("Blips")); set_size_and_pos(ui_hold_it, "hold_it"); +// ui_hold_it->setText(tr("Hold It!")); ui_hold_it->set_image("holdit"); + set_size_and_pos(ui_objection, "objection"); +// ui_objection->setText(tr("Objection!")); ui_objection->set_image("objection"); + set_size_and_pos(ui_take_that, "take_that"); +// ui_take_that->setText(tr("Take That!")); ui_take_that->set_image("takethat"); set_size_and_pos(ui_ooc_toggle, "ooc_toggle"); @@ -876,8 +894,10 @@ void Courtroom::set_background(QString p_background) } } -void Courtroom::enter_courtroom(int p_cid) +void Courtroom::update_character(int p_cid) { + bool newchar = m_cid != p_cid; + m_cid = p_cid; QString f_char; @@ -909,11 +929,6 @@ void Courtroom::enter_courtroom(int p_cid) set_emote_page(); set_emote_dropdown(); - current_evidence_page = 0; - current_evidence = 0; - - set_evidence_page(); - QString side = ao_app->get_char_side(f_char); if (side == "jud") @@ -947,6 +962,21 @@ void Courtroom::enter_courtroom(int p_cid) else ui_custom_objection->hide(); + ui_char_select_background->hide(); + ui_ic_chat_message->setEnabled(m_cid != -1); + ui_ic_chat_message->setFocus(); + + if (newchar) + set_iniswap_dropdown(); +} + +void Courtroom::enter_courtroom() +{ + current_evidence_page = 0; + current_evidence = 0; + + set_evidence_page(); + if (ao_app->flipping_enabled) ui_flip->show(); else @@ -975,11 +1005,6 @@ void Courtroom::enter_courtroom(int p_cid) set_widgets(); //ui_server_chatlog->setHtml(ui_server_chatlog->toHtml()); - - ui_char_select_background->hide(); - - ui_ic_chat_message->setEnabled(m_cid != -1); - ui_ic_chat_message->setFocus(); } void Courtroom::list_music() @@ -3224,6 +3249,70 @@ void Courtroom::on_pos_dropdown_changed(int p_index) ao_app->send_server_packet(new AOPacket("CT#" + ui_ooc_chat_name->text() + "#/pos " + f_pos + "#%")); } +void Courtroom::set_iniswap_dropdown() +{ + ui_iniswap_dropdown->clear(); + if (m_cid == -1) + { + ui_iniswap_dropdown->hide(); + return; + } + QStringList iniswaps = ao_app->get_list_file(ao_app->get_character_path(char_list.at(m_cid).name, "iniswaps.ini")); + iniswaps.prepend(char_list.at(m_cid).name); + if (iniswaps.size() <= 0) + { + ui_iniswap_dropdown->hide(); + return; + } + ui_iniswap_dropdown->show(); + ui_iniswap_dropdown->addItems(iniswaps); + + for (int i = 0; i < iniswaps.size(); ++i) + { + if (iniswaps.at(i) == current_char) + { + ui_iniswap_dropdown->setCurrentIndex(i); + if (i != 0) + ui_iniswap_remove->show(); + else + ui_iniswap_remove->hide(); + break; + } + } +} + +void Courtroom::on_iniswap_dropdown_changed(int p_index) +{ + ui_ic_chat_message->setFocus(); + QString iniswap = ui_iniswap_dropdown->itemText(p_index); + ao_app->set_char_ini(char_list.at(m_cid).name, iniswap, "name", "Options"); + + QStringList swaplist; + for (int i = 0; i < ui_iniswap_dropdown->count(); ++i) + { + QString entry = ui_iniswap_dropdown->itemText(i); + if (!swaplist.contains(entry) && entry != char_list.at(m_cid).name) + swaplist.append(entry); + } + ao_app->write_to_file(swaplist.join("\n"), ao_app->get_character_path(char_list.at(m_cid).name, "iniswaps.ini")); + ui_iniswap_dropdown->setCurrentIndex(p_index); + update_character(m_cid); + if (p_index != 0) + ui_iniswap_remove->show(); + else + ui_iniswap_remove->hide(); +} + +void Courtroom::on_iniswap_remove_clicked() +{ + if (ui_iniswap_dropdown->itemText(ui_iniswap_dropdown->currentIndex()) != char_list.at(m_cid).name) + { + ui_iniswap_dropdown->removeItem(ui_iniswap_dropdown->currentIndex()); + on_iniswap_dropdown_changed(0); //Reset back to original + update_character(m_cid); + } +} + void Courtroom::on_mute_list_clicked(QModelIndex p_index) { QListWidgetItem *f_item = ui_mute_list->item(p_index.row()); @@ -3607,7 +3696,8 @@ void Courtroom::on_reload_theme_clicked() //to update status on the background set_background(current_background); - enter_courtroom(m_cid); + update_character(m_cid); + enter_courtroom(); anim_state = 4; text_state = 3; @@ -3633,11 +3723,7 @@ void Courtroom::on_char_select_right_clicked() void Courtroom::on_spectator_clicked() { - enter_courtroom(-1); - - ui_emotes->hide(); - - ui_char_select_background->hide(); + update_character(-1); } void Courtroom::on_call_mod_clicked() diff --git a/src/packet_distribution.cpp b/src/packet_distribution.cpp index ff43f27..9eea179 100644 --- a/src/packet_distribution.cpp +++ b/src/packet_distribution.cpp @@ -601,7 +601,7 @@ void AOApplication::server_packet_received(AOPacket *p_packet) goto end; if (courtroom_constructed) - w_courtroom->enter_courtroom(f_contents.at(2).toInt()); + w_courtroom->update_character(f_contents.at(2).toInt()); } else if (header == "MS") { diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index a70fdc5..f22bc74 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -74,17 +74,22 @@ QString AOApplication::get_audio_output_device() } QStringList AOApplication::get_call_words() +{ + return get_list_file(get_base_path() + "callwords.ini"); +} + +QStringList AOApplication::get_list_file(QString p_file) { QStringList return_value; - QFile callwords_ini; + QFile p_ini; - callwords_ini.setFileName(get_base_path() + "callwords.ini"); + p_ini.setFileName(p_file); - if (!callwords_ini.open(QIODevice::ReadOnly)) + if (!p_ini.open(QIODevice::ReadOnly)) return return_value; - QTextStream in(&callwords_ini); + QTextStream in(&p_ini); while (!in.atEnd()) { @@ -555,6 +560,14 @@ QString AOApplication::read_char_ini(QString p_char, QString p_search_line, QStr return value; } +void AOApplication::set_char_ini(QString p_char, QString value, QString p_search_line, QString target_tag) +{ + QSettings settings(get_character_path(p_char, "char.ini"), QSettings::IniFormat); + settings.beginGroup(target_tag); + settings.setValue(p_search_line, value); + settings.endGroup(); +} + //returns all the values of target_tag QStringList AOApplication::read_char_ini_tag(QString p_char, QString target_tag) { From 8409b71611d8c213fd7286359d4404f2a181e59b Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Tue, 17 Sep 2019 21:17:30 +0300 Subject: [PATCH 054/268] Tool tips! Tool tips for everyone! Change the way AOButton loads images into itself (stylesheet broke tooltips) --- src/aobutton.cpp | 16 +++++++++++-- src/courtroom.cpp | 60 +++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 70 insertions(+), 6 deletions(-) diff --git a/src/aobutton.cpp b/src/aobutton.cpp index 1459729..d80226f 100644 --- a/src/aobutton.cpp +++ b/src/aobutton.cpp @@ -19,8 +19,20 @@ void AOButton::set_image(QString 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->setStyleSheet("border-image:url(\"" + image_path + "\")"); + { + this->setIcon(QIcon(image_path)); + this->setIconSize(this->size()); + this->setStyleSheet("border:0px"); + this->setText(""); + } + else if (file_exists(default_image_path)) + { + this->setIcon(QIcon(default_image_path)); + this->setIconSize(this->size()); + this->setStyleSheet("border:0px"); + this->setText(""); + } else - this->setStyleSheet("border-image:url(\"" + default_image_path + "\")"); + return; } diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 2b8f218..a160703 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -527,10 +527,13 @@ void Courtroom::set_widgets() 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 percentage offset of your character's position from the center of the screen.")); 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"); set_size_and_pos(ui_music_list, "music_list"); @@ -556,12 +559,15 @@ void Courtroom::set_widgets() ui_muted->resize(ui_ic_chat_message->width(), ui_ic_chat_message->height()); ui_muted->set_image("muted"); + ui_muted->setToolTip(tr("Oops, you're muted!")); set_size_and_pos(ui_ooc_chat_message, "ooc_chat_message"); ui_ooc_chat_message->setStyleSheet("background-color: rgba(0, 0, 0, 0);"); + ui_ooc_chat_message->setToolTip(tr("Type your message to display in the server chat here.")); set_size_and_pos(ui_ooc_chat_name, "ooc_chat_name"); ui_ooc_chat_name->setStyleSheet("background-color: rgba(0, 0, 0, 0);"); + ui_ooc_chat_name->setToolTip(tr("Set your name to display in the server chat.")); //set_size_and_pos(ui_area_password, "area_password"); set_size_and_pos(ui_music_search, "music_search"); @@ -576,13 +582,18 @@ void Courtroom::set_widgets() set_size_and_pos(ui_emote_dropdown, "emote_dropdown"); set_size_and_pos(ui_pos_dropdown, "pos_dropdown"); + ui_pos_dropdown->setToolTip(tr("Set your character's supplementary background.")); set_size_and_pos(ui_iniswap_dropdown, "iniswap_dropdown"); ui_iniswap_dropdown->setEditable(true); ui_iniswap_dropdown->setInsertPolicy(QComboBox::InsertAtBottom); + ui_iniswap_dropdown->setToolTip(tr("Set an 'iniswap', or an alternative character folder to refer to from your current character." + "This information is saved to your base/characters//iniswaps.ini")); + set_size_and_pos(ui_iniswap_remove, "iniswap_remove"); -// ui_iniswap_remove->setText("X"); + ui_iniswap_remove->setText("X"); ui_iniswap_remove->set_image("evidencex"); + ui_iniswap_remove->setToolTip(tr("Remove the currently selected iniswap from the list and return to the original character folder.")); set_size_and_pos(ui_defense_bar, "defense_bar"); ui_defense_bar->set_image("defensebar" + QString::number(defense_bar_state)); @@ -598,19 +609,23 @@ void Courtroom::set_widgets() ui_blip_label->setText(tr("Blips")); set_size_and_pos(ui_hold_it, "hold_it"); -// ui_hold_it->setText(tr("Hold It!")); + ui_hold_it->setText(tr("Hold It!")); + ui_hold_it->setToolTip(tr("When this is turned on, your next in-character message will be a shout!")); ui_hold_it->set_image("holdit"); set_size_and_pos(ui_objection, "objection"); -// ui_objection->setText(tr("Objection!")); + ui_objection->setText(tr("Objection!")); + ui_objection->setToolTip(tr("When this is turned on, your next in-character message will be a shout!")); ui_objection->set_image("objection"); set_size_and_pos(ui_take_that, "take_that"); -// ui_take_that->setText(tr("Take That!")); + ui_take_that->setText(tr("Take That!")); + ui_take_that->setToolTip(tr("When this is turned on, your next in-character message will be a shout!")); ui_take_that->set_image("takethat"); set_size_and_pos(ui_ooc_toggle, "ooc_toggle"); ui_ooc_toggle->setText(tr("Server")); + ui_ooc_toggle->setToolTip(tr("Toggle between server chat and global AO2 chat.")); set_size_and_pos(ui_witness_testimony, "witness_testimony"); ui_witness_testimony->set_image("witnesstestimony"); @@ -618,67 +633,101 @@ void Courtroom::set_widgets() ui_cross_examination->set_image("crossexamination"); set_size_and_pos(ui_guilty, "guilty"); + ui_guilty->setText(tr("Guilty!")); ui_guilty->set_image("guilty"); + ui_guilty->setToolTip(tr("This will display the animation in the viewport as soon as it is pressed.")); set_size_and_pos(ui_not_guilty, "not_guilty"); ui_not_guilty->set_image("notguilty"); + ui_not_guilty->setToolTip(tr("This will display the animation in the viewport as soon as it is pressed.")); set_size_and_pos(ui_change_character, "change_character"); ui_change_character->setText(tr("Change character")); + ui_change_character->set_image("change_character"); + ui_change_character->setToolTip(tr("Bring up the Character Select Screen and change your character.")); set_size_and_pos(ui_reload_theme, "reload_theme"); ui_reload_theme->setText(tr("Reload theme")); + ui_reload_theme->set_image("reload_theme"); + ui_reload_theme->setToolTip(tr("Refresh the theme and update all of the ui elements to match.")); set_size_and_pos(ui_call_mod, "call_mod"); ui_call_mod->setText(tr("Call mod")); + ui_call_mod->set_image("call_mod"); + ui_call_mod->setToolTip(tr("Request the attention of the current server's moderator.")); set_size_and_pos(ui_settings, "settings"); ui_settings->setText(tr("Settings")); + ui_settings->set_image("settings"); + ui_settings->setToolTip(tr("Allows you to change various aspects of the client.")); set_size_and_pos(ui_announce_casing, "casing_button"); ui_announce_casing->setText(tr("Casing")); + ui_announce_casing->set_image("casing_button"); + ui_announce_casing->setToolTip(tr("uhhhhh")); set_size_and_pos(ui_switch_area_music, "switch_area_music"); ui_switch_area_music->setText(tr("A/M")); + ui_switch_area_music->set_image("switch_area_music"); + ui_switch_area_music->setToolTip(tr("Switch between Areas and Music lists")); set_size_and_pos(ui_pre, "pre"); ui_pre->setText(tr("Preanim")); + ui_pre->setToolTip(tr("Play a single-shot animation as defined by the emote when checked.")); set_size_and_pos(ui_pre_non_interrupt, "pre_no_interrupt"); + ui_pre_non_interrupt->setToolTip(tr("If preanim is checked, display the input text immediately as the animation plays concurrently.")); + set_size_and_pos(ui_flip, "flip"); + ui_flip->setToolTip(tr("Mirror your character's emotes when checked.")); set_size_and_pos(ui_additive, "additive"); + ui_additive->setToolTip(tr("Add text to your last spoken message when checked.")); set_size_and_pos(ui_guard, "guard"); + ui_additive->setToolTip(tr("Do not listen to mod calls when checked, preventing them from playing sounds or focusing attention on the window.")); set_size_and_pos(ui_casing, "casing"); + ui_casing->setToolTip(tr("((((((Case?))))))")); set_size_and_pos(ui_showname_enable, "showname_enable"); + ui_showname_enable->setToolTip(tr("Display customized shownames for all users when checked.")); set_size_and_pos(ui_custom_objection, "custom_objection"); + ui_custom_objection->setText(tr("Custom Shout!")); ui_custom_objection->set_image("custom"); + ui_custom_objection->setToolTip(tr("This will display the custom character-defined animation in the viewport as soon as it is pressed.")); set_size_and_pos(ui_realization, "realization"); ui_realization->set_image("realization"); + ui_realization->setToolTip(tr("Play realization sound and animation in the viewport on the next spoken message when checked.")); set_size_and_pos(ui_screenshake, "screenshake"); ui_screenshake->set_image("screenshake"); + ui_screenshake->setToolTip(tr("Shake the screen on next spoken message when checked.")); set_size_and_pos(ui_mute, "mute_button"); + ui_mute->setText("Mute"); ui_mute->set_image("mute"); + ui_mute->setToolTip(tr("Display the list of character folders you wish to mute.")); set_size_and_pos(ui_defense_plus, "defense_plus"); ui_defense_plus->set_image("defplus"); + ui_defense_plus->setToolTip(tr("Increase the health bar.")); set_size_and_pos(ui_defense_minus, "defense_minus"); ui_defense_minus->set_image("defminus"); + ui_defense_minus->setToolTip(tr("Decrease the health bar.")); set_size_and_pos(ui_prosecution_plus, "prosecution_plus"); ui_prosecution_plus->set_image("proplus"); + ui_prosecution_plus->setToolTip(tr("Increase the health bar.")); set_size_and_pos(ui_prosecution_minus, "prosecution_minus"); ui_prosecution_minus->set_image("prominus"); + ui_prosecution_minus->setToolTip(tr("Decrease the health bar.")); set_size_and_pos(ui_text_color, "text_color"); + ui_text_color->setToolTip(tr("Change the text color of the spoken message.")); set_size_and_pos(ui_music_slider, "music_slider"); set_size_and_pos(ui_sfx_slider, "sfx_slider"); @@ -686,6 +735,7 @@ void Courtroom::set_widgets() set_size_and_pos(ui_evidence_button, "evidence_button"); ui_evidence_button->set_image("evidencebutton"); + ui_evidence_button->setToolTip(tr("Bring up the Evidence screen.")); set_size_and_pos(ui_evidence, "evidence_background"); ui_evidence->set_image("evidencebackground"); @@ -723,6 +773,7 @@ void Courtroom::set_widgets() set_size_and_pos(ui_back_to_lobby, "back_to_lobby"); ui_back_to_lobby->setText(tr("Back to Lobby")); + ui_back_to_lobby->setToolTip(tr("Return back to the server list.")); set_size_and_pos(ui_char_password, "char_password"); @@ -735,6 +786,7 @@ void Courtroom::set_widgets() ui_char_select_right->set_image("arrow_right"); set_size_and_pos(ui_spectator, "spectator"); + ui_spectator->setToolTip(tr("Become a spectator. You won't be able to interact with the in-character screen.")); } void Courtroom::set_fonts() From e151964785301269500b96ecfd25dbdf227f55f8 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Tue, 17 Sep 2019 23:50:01 +0300 Subject: [PATCH 055/268] Add a sfx list that allows you to choose custom sfx from a list. Allows the same amount of customization as the iniswap list. It tries to read soundlist.ini in the character folder first. If it can't find it, it will fall back to the theme's character_soundlist.ini. It will only save the soundlist.ini if it differs from the character.soundlist.ini. There is currently no way to dynamically change sound delay atm but the function for it is there. Add more tooltips, my favorite! --- include/courtroom.h | 12 ++++- src/courtroom.cpp | 120 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 126 insertions(+), 6 deletions(-) diff --git a/include/courtroom.h b/include/courtroom.h index 91f1f9a..8d1588e 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -467,6 +467,9 @@ private: QComboBox *ui_iniswap_dropdown; AOButton *ui_iniswap_remove; + QComboBox *ui_sfx_dropdown; + AOButton *ui_sfx_remove; + AOImage *ui_defense_bar; AOImage *ui_prosecution_bar; @@ -608,11 +611,18 @@ private slots: void on_emote_dropdown_changed(int p_index); void on_pos_dropdown_changed(int p_index); - void on_iniswap_dropdown_changed(int p_index); + void on_iniswap_dropdown_changed(int p_index); void set_iniswap_dropdown(); void on_iniswap_remove_clicked(); + void on_sfx_dropdown_changed(int p_index); + void set_sfx_dropdown(); + void on_sfx_remove_clicked(); + + QString get_char_sfx(); + int get_char_sfx_delay(); + void on_evidence_name_edited(QString text); void on_evidence_image_name_edited(); void on_evidence_image_button_clicked(); diff --git a/src/courtroom.cpp b/src/courtroom.cpp index a160703..7ece780 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -166,6 +166,9 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_iniswap_dropdown = new QComboBox(this); ui_iniswap_remove = new AOButton(this, ao_app); + ui_sfx_dropdown = new QComboBox(this); + ui_sfx_remove = new AOButton(this, ao_app); + ui_defense_bar = new AOImage(this, ao_app); ui_prosecution_bar = new AOImage(this, ao_app); @@ -288,6 +291,9 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() connect(ui_iniswap_dropdown, SIGNAL(activated(int)), this, SLOT(on_iniswap_dropdown_changed(int))); connect(ui_iniswap_remove, SIGNAL(clicked()), this, SLOT(on_iniswap_remove_clicked())); + connect(ui_sfx_dropdown, SIGNAL(activated(int)), this, SLOT(on_sfx_dropdown_changed(int))); + connect(ui_sfx_remove, SIGNAL(clicked()), this, SLOT(on_sfx_remove_clicked())); + connect(ui_mute_list, SIGNAL(clicked(QModelIndex)), this, SLOT(on_mute_list_clicked(QModelIndex))); connect(ui_ic_chat_message, SIGNAL(returnPressed()), this, SLOT(on_chat_return_pressed())); @@ -587,7 +593,7 @@ void Courtroom::set_widgets() set_size_and_pos(ui_iniswap_dropdown, "iniswap_dropdown"); ui_iniswap_dropdown->setEditable(true); ui_iniswap_dropdown->setInsertPolicy(QComboBox::InsertAtBottom); - ui_iniswap_dropdown->setToolTip(tr("Set an 'iniswap', or an alternative character folder to refer to from your current character." + ui_iniswap_dropdown->setToolTip(tr("Set an 'iniswap', or an alternative character folder to refer to from your current character.\n" "This information is saved to your base/characters//iniswaps.ini")); set_size_and_pos(ui_iniswap_remove, "iniswap_remove"); @@ -595,6 +601,17 @@ void Courtroom::set_widgets() ui_iniswap_remove->set_image("evidencex"); ui_iniswap_remove->setToolTip(tr("Remove the currently selected iniswap from the list and return to the original character folder.")); + set_size_and_pos(ui_sfx_dropdown, "sfx_dropdown"); + ui_sfx_dropdown->setEditable(true); + ui_sfx_dropdown->setInsertPolicy(QComboBox::InsertAtBottom); + ui_sfx_dropdown->setToolTip(tr("Set an 'iniswap', or an alternative character folder to refer to from your current character.\n" + "This information is saved to your base/characters//iniswaps.ini")); + + set_size_and_pos(ui_sfx_remove, "sfx_remove"); + ui_sfx_remove->setText("X"); + ui_sfx_remove->set_image("evidencex"); + ui_sfx_remove->setToolTip(tr("Remove the currently selected iniswap from the list and return to the original character folder.")); + set_size_and_pos(ui_defense_bar, "defense_bar"); ui_defense_bar->set_image("defensebar" + QString::number(defense_bar_state)); @@ -629,8 +646,10 @@ void Courtroom::set_widgets() set_size_and_pos(ui_witness_testimony, "witness_testimony"); ui_witness_testimony->set_image("witnesstestimony"); + ui_witness_testimony->setToolTip(tr("This will display the animation in the viewport as soon as it is pressed.")); set_size_and_pos(ui_cross_examination, "cross_examination"); ui_cross_examination->set_image("crossexamination"); + ui_cross_examination->setToolTip(tr("This will display the animation in the viewport as soon as it is pressed.")); set_size_and_pos(ui_guilty, "guilty"); ui_guilty->setText(tr("Guilty!")); @@ -663,7 +682,7 @@ void Courtroom::set_widgets() set_size_and_pos(ui_announce_casing, "casing_button"); ui_announce_casing->setText(tr("Casing")); ui_announce_casing->set_image("casing_button"); - ui_announce_casing->setToolTip(tr("uhhhhh")); + ui_announce_casing->setToolTip(tr("An interface to help you announce a case (you have to be a CM first to be able to announce cases)")); set_size_and_pos(ui_switch_area_music, "switch_area_music"); ui_switch_area_music->setText(tr("A/M")); @@ -687,7 +706,8 @@ void Courtroom::set_widgets() ui_additive->setToolTip(tr("Do not listen to mod calls when checked, preventing them from playing sounds or focusing attention on the window.")); set_size_and_pos(ui_casing, "casing"); - ui_casing->setToolTip(tr("((((((Case?))))))")); + ui_casing->setToolTip(tr("Lets you receive case alerts when enabled.\n" + "(You can set your preferences in the Settings!)")); set_size_and_pos(ui_showname_enable, "showname_enable"); ui_showname_enable->setToolTip(tr("Display customized shownames for all users when checked.")); @@ -981,6 +1001,8 @@ void Courtroom::update_character(int p_cid) set_emote_page(); set_emote_dropdown(); + set_sfx_dropdown(); + QString side = ao_app->get_char_side(f_char); if (side == "jud") @@ -1253,7 +1275,7 @@ void Courtroom::on_chat_return_pressed() packet_contents.append(f_side); - packet_contents.append(ao_app->get_sfx_name(current_char, current_emote)); + packet_contents.append(get_char_sfx()); int f_emote_mod = ao_app->get_emote_mod(current_char, current_emote); @@ -1286,7 +1308,7 @@ void Courtroom::on_chat_return_pressed() packet_contents.append(QString::number(f_emote_mod)); packet_contents.append(QString::number(m_cid)); - packet_contents.append(QString::number(ao_app->get_sfx_delay(current_char, current_emote))); + packet_contents.append(QString::number(get_char_sfx_delay())); QString f_obj_state; @@ -3307,6 +3329,7 @@ void Courtroom::set_iniswap_dropdown() if (m_cid == -1) { ui_iniswap_dropdown->hide(); + ui_iniswap_remove->hide(); return; } QStringList iniswaps = ao_app->get_list_file(ao_app->get_character_path(char_list.at(m_cid).name, "iniswaps.ini")); @@ -3314,6 +3337,7 @@ void Courtroom::set_iniswap_dropdown() if (iniswaps.size() <= 0) { ui_iniswap_dropdown->hide(); + ui_iniswap_remove->hide(); return; } ui_iniswap_dropdown->show(); @@ -3365,6 +3389,92 @@ void Courtroom::on_iniswap_remove_clicked() } } +void Courtroom::set_sfx_dropdown() +{ + ui_sfx_dropdown->clear(); + if (m_cid == -1) + { + ui_sfx_dropdown->hide(); + ui_sfx_remove->hide(); + return; + } + QStringList soundlist = ao_app->get_list_file(ao_app->get_character_path(current_char, "soundlist.ini")); + + if (soundlist.size() <= 0) + { + soundlist = ao_app->get_list_file(ao_app->get_theme_path("character_soundlist.ini")); + if (soundlist.size() <= 0) + { + soundlist = ao_app->get_list_file(ao_app->get_default_theme_path("character_soundlist.ini")); + } + } + + soundlist.prepend("Default"); + if (soundlist.size() <= 0) + { + ui_sfx_dropdown->hide(); + ui_sfx_remove->hide(); + return; + } + ui_sfx_dropdown->show(); + ui_sfx_dropdown->addItems(soundlist); + ui_sfx_dropdown->setCurrentIndex(0); + ui_sfx_remove->hide(); +} + +void Courtroom::on_sfx_dropdown_changed(int p_index) +{ + ui_ic_chat_message->setFocus(); + + QStringList soundlist; + for (int i = 0; i < ui_sfx_dropdown->count(); ++i) + { + QString entry = ui_sfx_dropdown->itemText(i); + if (!soundlist.contains(entry) && entry != "Default") + soundlist.append(entry); + } + + QStringList defaultlist = ao_app->get_list_file(ao_app->get_theme_path("character_soundlist.ini")); + if (defaultlist.size() <= 0) + { + defaultlist = ao_app->get_list_file(ao_app->get_default_theme_path("character_soundlist.ini")); + } + + if (defaultlist.size() > 0 && defaultlist.toSet().subtract(soundlist.toSet()).size() > 0) //There's a difference from the default configuration + ao_app->write_to_file(soundlist.join("\n"), ao_app->get_character_path(current_char, "soundlist.ini")); //Create a new sound list + + ui_sfx_dropdown->setCurrentIndex(p_index); + if (p_index != 0) + ui_sfx_remove->show(); + else + ui_sfx_remove->hide(); +} + +void Courtroom::on_sfx_remove_clicked() +{ + if (ui_sfx_dropdown->itemText(ui_sfx_dropdown->currentIndex()) != "Default") + { + ui_sfx_dropdown->removeItem(ui_sfx_dropdown->currentIndex()); + on_sfx_dropdown_changed(0); //Reset back to original + } +} + +QString Courtroom::get_char_sfx() +{ + QString sfx = ui_sfx_dropdown->itemText(ui_sfx_dropdown->currentIndex()); + if (sfx != "" && sfx != "Default") + return sfx; + return ao_app->get_sfx_name(current_char, current_emote); +} + +int Courtroom::get_char_sfx_delay() +{ +// QString sfx = ui_sfx_dropdown->itemText(ui_sfx_dropdown->currentIndex()); +// if (sfx != "" && sfx != "Default") +// return 0; //todo: a way to define this + return ao_app->get_sfx_delay(current_char, current_emote); +} + void Courtroom::on_mute_list_clicked(QModelIndex p_index) { QListWidgetItem *f_item = ui_mute_list->item(p_index.row()); From 605e15bb8c0ad103fb0f75454d8912ba83ba7a17 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Wed, 18 Sep 2019 04:14:52 +0300 Subject: [PATCH 056/268] Implement effects system that reads your folder in theme/effects, or misc// Add an effect packet Allow aomovie to be fed a direct path Add some really terrible helper functions that shouldn't exist, sorry. --- include/aoapplication.h | 13 ++++++ include/aomovie.h | 2 +- include/courtroom.h | 12 ++++- include/datatypes.h | 3 +- src/aomovie.cpp | 32 ++++++++------ src/courtroom.cpp | 80 +++++++++++++++++++++++++++++++--- src/packet_distribution.cpp | 2 + src/text_file_functions.cpp | 87 +++++++++++++++++++++++++++++++++++++ 8 files changed, 208 insertions(+), 23 deletions(-) diff --git a/include/aoapplication.h b/include/aoapplication.h index f26c816..f8ce226 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -80,6 +80,7 @@ public: bool modcall_reason_enabled = false; bool looping_sfx_support_enabled = false; bool additive_enabled = false; + bool effects_enabled = false; ///////////////loading info/////////////////// @@ -298,6 +299,18 @@ public: //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_char_effects(QString p_char); + + //Get the theme's effects folder, read it and return the list of filenames in a string + QStringList get_effects(); + + //t + QString get_effect(QString effect, QString p_char); + + //Return the effect sound associated with the fx_name in the misc/effects//sounds.ini, or theme/effects/sounds.ini. + QString get_effect_sound(QString fx_name, QString p_char); + // Returns the custom realisation used by the character. QString get_custom_realization(QString p_char); diff --git a/include/aomovie.h b/include/aomovie.h index a5af735..ec28619 100644 --- a/include/aomovie.h +++ b/include/aomovie.h @@ -15,7 +15,7 @@ public: AOMovie(QWidget *p_parent, AOApplication *p_ao_app); void set_play_once(bool p_play_once); - void play(QString p_gif, QString p_char = "", QString p_custom_theme = "", int default_duration = 0); + void play(QString p_image, QString p_char = "", QString p_custom_theme = "", int default_duration = 0); void combo_resize(int w, int h); void stop(); diff --git a/include/courtroom.h b/include/courtroom.h index 8d1588e..6ba3d65 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -345,7 +345,7 @@ private: //the amount of time non-animated witness testimony/cross-examination images stay onscreen for in ms const int wtce_stay_time = 1500; - static const int chatmessage_size = 29; + static const int chatmessage_size = 30; QString m_chatmessage[chatmessage_size]; bool chatmessage_is_empty = false; @@ -375,6 +375,8 @@ private: int text_color = 0; bool is_presenting_evidence = false; + QString effect = ""; + int defense_bar_state = 0; int prosecution_bar_state = 0; @@ -429,7 +431,7 @@ private: QLabel *ui_vp_showname; AOMovie *ui_vp_chat_arrow; QTextEdit *ui_vp_message; - AOMovie *ui_vp_realization; + AOMovie *ui_vp_effect; AOMovie *ui_vp_testimony; AOMovie *ui_vp_wtce; AOMovie *ui_vp_objection; @@ -470,6 +472,8 @@ private: QComboBox *ui_sfx_dropdown; AOButton *ui_sfx_remove; + QComboBox *ui_effects_dropdown; + AOImage *ui_defense_bar; AOImage *ui_prosecution_bar; @@ -579,6 +583,7 @@ public slots: void preanim_done(); void do_screenshake(); void do_flash(); + void do_effect(QString fx_path, QString fx_sound, QString p_char); void play_char_sfx(QString sfx_name); void mod_called(QString p_ip); @@ -620,6 +625,9 @@ private slots: void set_sfx_dropdown(); void on_sfx_remove_clicked(); + void set_effects_dropdown(); + void on_effects_dropdown_changed(int p_index); + QString get_char_sfx(); int get_char_sfx_delay(); diff --git a/include/datatypes.h b/include/datatypes.h index 54e5c74..5426d98 100644 --- a/include/datatypes.h +++ b/include/datatypes.h @@ -106,7 +106,8 @@ enum CHAT_MESSAGE FRAME_SCREENSHAKE, FRAME_REALIZATION, FRAME_SFX, - ADDITIVE + ADDITIVE, + EFFECTS }; enum COLOR diff --git a/src/aomovie.cpp b/src/aomovie.cpp index 7f7fb20..fff8014 100644 --- a/src/aomovie.cpp +++ b/src/aomovie.cpp @@ -29,35 +29,41 @@ void AOMovie::play(QString p_image, QString p_char, QString p_custom_theme, int { m_movie->stop(); - QString shout_path; - QList pathlist; + QString shout_path = p_image; + if (!file_exists(p_image)) + { + QList pathlist; - pathlist = { + pathlist = { ao_app->get_image_suffix(ao_app->get_base_path() + "misc/" + p_custom_theme + "/" + p_image + "_bubble"), //Misc path ao_app->get_image_suffix(ao_app->get_custom_theme_path(p_custom_theme, p_image)), //Custom theme path ao_app->get_image_suffix(ao_app->get_theme_path(p_image)), //Theme path ao_app->get_image_suffix(ao_app->get_default_theme_path(p_image)), //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 - }; + }; - //Add this at the beginning of the list - order matters. - if (p_image == "custom") - pathlist.prepend(ao_app->get_image_suffix(ao_app->get_character_path(p_char, p_image))); - else - pathlist.prepend(ao_app->get_image_suffix(ao_app->get_character_path(p_char, p_image + "_bubble"))); + //Add this at the beginning of the list - order matters. + if (p_image == "custom") + pathlist.prepend(ao_app->get_image_suffix(ao_app->get_character_path(p_char, p_image))); + else + pathlist.prepend(ao_app->get_image_suffix(ao_app->get_character_path(p_char, p_image + "_bubble"))); - for (QString path : pathlist) - { + for (QString path : pathlist) + { if (file_exists(path)) { - shout_path = path; - break; + shout_path = path; + break; } + } } m_movie->setFileName(shout_path); + if (m_movie->loopCount() == 0) + play_once = true; + this->show(); m_movie->start(); if (m_movie->frameCount() == 0 && duration > 0) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 7ece780..f26c6dc 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -98,7 +98,7 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_vp_testimony = new AOMovie(this, ao_app); ui_vp_testimony->set_play_once(false); - ui_vp_realization = new AOMovie(this, ao_app); + ui_vp_effect = new AOMovie(this, ao_app); ui_vp_wtce = new AOMovie(this, ao_app); ui_vp_objection = new AOMovie(this, ao_app); @@ -169,6 +169,8 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_sfx_dropdown = new QComboBox(this); ui_sfx_remove = new AOButton(this, ao_app); + ui_effects_dropdown = new QComboBox(this); + ui_defense_bar = new AOImage(this, ao_app); ui_prosecution_bar = new AOImage(this, ao_app); @@ -294,6 +296,8 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() connect(ui_sfx_dropdown, SIGNAL(activated(int)), this, SLOT(on_sfx_dropdown_changed(int))); connect(ui_sfx_remove, SIGNAL(clicked()), this, SLOT(on_sfx_remove_clicked())); + connect(ui_effects_dropdown, SIGNAL(activated(int)), this, SLOT(on_effects_dropdown_changed(int))); + connect(ui_mute_list, SIGNAL(clicked(QModelIndex)), this, SLOT(on_mute_list_clicked(QModelIndex))); connect(ui_ic_chat_message, SIGNAL(returnPressed()), this, SLOT(on_chat_return_pressed())); @@ -513,8 +517,8 @@ void Courtroom::set_widgets() ui_vp_testimony->move(ui_viewport->x(), ui_viewport->y()); ui_vp_testimony->combo_resize(ui_viewport->width(), ui_viewport->height()); - ui_vp_realization->move(ui_viewport->x(), ui_viewport->y()); - ui_vp_realization->combo_resize(ui_viewport->width(), ui_viewport->height()); + ui_vp_effect->move(ui_viewport->x(), ui_viewport->y()); + ui_vp_effect->combo_resize(ui_viewport->width(), ui_viewport->height()); ui_vp_wtce->move(ui_viewport->x(), ui_viewport->y()); ui_vp_wtce->combo_resize(ui_viewport->width(), ui_viewport->height()); @@ -612,6 +616,12 @@ void Courtroom::set_widgets() ui_sfx_remove->set_image("evidencex"); ui_sfx_remove->setToolTip(tr("Remove the currently selected iniswap from the list and return to the original character folder.")); + set_size_and_pos(ui_effects_dropdown, "effects_dropdown"); + ui_effects_dropdown->setInsertPolicy(QComboBox::InsertAtBottom); + ui_effects_dropdown->setToolTip(tr("Choose an effect to play on your next spoken message.")); + ui_effects_dropdown->setIconSize(QSize(16, 16)); //Todo: don't do hardcoding hell - make it part of courtroom_design.ini + //Todo: actual list of effects + set_size_and_pos(ui_defense_bar, "defense_bar"); ui_defense_bar->set_image("defensebar" + QString::number(defense_bar_state)); @@ -1002,6 +1012,7 @@ void Courtroom::update_character(int p_cid) set_emote_dropdown(); set_sfx_dropdown(); + set_effects_dropdown(); QString side = ao_app->get_char_side(f_char); @@ -1424,6 +1435,12 @@ void Courtroom::on_chat_return_pressed() { packet_contents.append(ui_additive->isChecked() ? "1" : "0"); } + if (ao_app->effects_enabled) + { + QString fx_sound = ao_app->get_effect_sound(effect, current_char); + packet_contents.append(effect + "|" + fx_sound); + qDebug() << effect << fx_sound; + } ao_app->send_server_packet(new AOPacket("MS", packet_contents)); } @@ -1879,7 +1896,18 @@ void Courtroom::do_flash() if(!ao_app->is_shake_flash_enabled()) return; - ui_vp_realization->play("realizationflash", "", "", 60); + ui_vp_effect->play("realizationflash", "", "", 60); +} + +void Courtroom::do_effect(QString fx_name, QString fx_sound, QString p_char) +{ + if(!ao_app->is_shake_flash_enabled()) + return; + + ui_vp_effect->set_play_once(false); // The effects themselves dictate whether or not they're looping. Static effects will linger. + ui_vp_effect->play(ao_app->get_effect(fx_name, p_char)); // It will set_play_once to true if the filepath provided is not designed to loop more than once + if (fx_sound != "") + sfx_player->play(ao_app->get_sfx_suffix(fx_sound)); } void Courtroom::play_char_sfx(QString sfx_name) @@ -2288,7 +2316,18 @@ void Courtroom::start_chat_ticking() if (text_state != 0) return; - if (m_chatmessage[REALIZATION] == "1") + if (m_chatmessage[EFFECTS] != "") + { + QStringList fx_list = m_chatmessage[EFFECTS].split("|"); + qDebug() << m_chatmessage[EFFECTS] << fx_list; + QString fx = fx_list[0]; + QString fx_sound; + if (fx_list.length() > 1) + fx_sound = fx_list[1]; + + this->do_effect(fx, fx_sound, m_chatmessage[CHAR_NAME]); + } + else if (m_chatmessage[REALIZATION] == "1") { this->do_flash(); sfx_player->play(ao_app->get_custom_realization(m_chatmessage[CHAR_NAME])); @@ -3409,13 +3448,14 @@ void Courtroom::set_sfx_dropdown() } } - soundlist.prepend("Default"); if (soundlist.size() <= 0) { ui_sfx_dropdown->hide(); ui_sfx_remove->hide(); return; } + soundlist.prepend("Default"); + ui_sfx_dropdown->show(); ui_sfx_dropdown->addItems(soundlist); ui_sfx_dropdown->setCurrentIndex(0); @@ -3459,6 +3499,34 @@ void Courtroom::on_sfx_remove_clicked() } } +void Courtroom::set_effects_dropdown() +{ + ui_effects_dropdown->clear(); + if (m_cid == -1) + { + ui_effects_dropdown->hide(); + return; + } + QStringList effectslist = ao_app->get_effects() << ao_app->get_char_effects(current_char); + + if (effectslist.size() <= 0) + { + ui_effects_dropdown->hide(); + return; + } + effectslist.prepend("None"); + + ui_effects_dropdown->show(); + ui_effects_dropdown->addItems(effectslist); + ui_effects_dropdown->setCurrentIndex(0); +} + +void Courtroom::on_effects_dropdown_changed(int p_index) +{ + effect = ui_effects_dropdown->itemText(p_index); + ui_ic_chat_message->setFocus(); +} + QString Courtroom::get_char_sfx() { QString sfx = ui_sfx_dropdown->itemText(ui_sfx_dropdown->currentIndex()); diff --git a/src/packet_distribution.cpp b/src/packet_distribution.cpp index 9eea179..e483ef9 100644 --- a/src/packet_distribution.cpp +++ b/src/packet_distribution.cpp @@ -215,6 +215,8 @@ void AOApplication::server_packet_received(AOPacket *p_packet) looping_sfx_support_enabled = true; if (f_packet.contains("additive",Qt::CaseInsensitive)) additive_enabled = true; + if (f_packet.contains("effects",Qt::CaseInsensitive)) + effects_enabled = true; } else if (header == "PN") { diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index f22bc74..d478582 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -817,6 +817,93 @@ int AOApplication::get_text_delay(QString p_char, QString p_emote) else return f_result.toInt(); } +QStringList AOApplication::get_char_effects(QString p_char) +{ + QString p_effect = read_char_ini(p_char, "effects", "Options"); + QString p_path = get_base_path() + "misc/" + p_effect + "/"; + QStringList filters = QStringList() << "*.gif" << "*.webp" << "*.apng" << "*.png" << "*.GIF" << "*.WEBP" << "*.APNG" << "*.PNG"; + + QDir directory(p_path); + QStringList images = directory.entryList(filters, QDir::Files); + + QStringList effects; + foreach (QString effect, images) + { + effect = effect.left(effect.lastIndexOf(".")); + if (!effects.contains(effect)) //Do that juicy priority meme + effects.append(effect); + } + + return effects; +} + +QStringList AOApplication::get_effects() +{ + QString design_ini_path = get_theme_path("effects/"); + QString default_path = get_default_theme_path("effects/"); + QStringList filters = QStringList() << "*.gif" << "*.webp" << "*.apng" << "*.png" << "*.GIF" << "*.WEBP" << "*.APNG" << "*.PNG"; + + QDir directory(design_ini_path); + QStringList images = directory.entryList(filters, QDir::Files); + if (images.size() <= 0) + { + directory.cd(default_path); + images = directory.entryList(filters, QDir::Files); + } + + QStringList effects; + foreach (QString effect, images) + { + effect = effect.left(effect.lastIndexOf(".")); + if (!effects.contains(effect)) //Do that juicy priority meme + effects.append(effect); + } + + return effects; +} + +QString AOApplication::get_effect(QString effect, QString p_char) +{ + QString 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 ""; + } + } + } + + return p_path; +} + +QString AOApplication::get_effect_sound(QString fx_name, QString p_char) +{ + QString p_effect = read_char_ini(p_char, "effects", "Options"); + QString p_path = get_base_path() + "misc/effects/" + p_effect + "/effect_sounds.ini"; + QString design_ini_path = get_theme_path("effects/effect_sounds.ini"); + QString default_path = get_default_theme_path("effects/effect_sounds.ini"); + + QString f_result = read_design_ini(fx_name, p_path); + if (f_result == "") + { + f_result = read_design_ini(fx_name, design_ini_path); + if (f_result == "") + { + f_result = read_design_ini(fx_name, default_path); + } + } + return f_result; +} + QString AOApplication::get_custom_realization(QString p_char) { QString f_result = read_char_ini(p_char, "realization", "Options"); From ad057c6f7a71ffac53e8d5adbbd22ab17d3e0e98 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Wed, 18 Sep 2019 05:22:00 +0300 Subject: [PATCH 057/268] make icons for effects n shit they're grabbed from the effects/icons/*same name as effects* gotta be .png or w/e i need my sleep --- include/aoapplication.h | 2 +- src/courtroom.cpp | 41 ++++++++++++++++++++++++++++++---- src/text_file_functions.cpp | 44 +++++++++++++++++-------------------- 3 files changed, 58 insertions(+), 29 deletions(-) diff --git a/include/aoapplication.h b/include/aoapplication.h index f8ce226..78de2b8 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -303,7 +303,7 @@ public: QStringList get_char_effects(QString p_char); //Get the theme's effects folder, read it and return the list of filenames in a string - QStringList get_effects(); + QStringList get_effects(QString p_char); //t QString get_effect(QString effect, QString p_char); diff --git a/src/courtroom.cpp b/src/courtroom.cpp index f26c6dc..48aa637 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1439,7 +1439,8 @@ void Courtroom::on_chat_return_pressed() { QString fx_sound = ao_app->get_effect_sound(effect, current_char); packet_contents.append(effect + "|" + fx_sound); - qDebug() << effect << fx_sound; + ui_effects_dropdown->setCurrentIndex(0); + effect = ""; } ao_app->send_server_packet(new AOPacket("MS", packet_contents)); @@ -1902,10 +1903,14 @@ void Courtroom::do_flash() void Courtroom::do_effect(QString fx_name, QString fx_sound, QString p_char) { if(!ao_app->is_shake_flash_enabled()) - return; + return; + + QString effect = ao_app->get_effect(fx_name, p_char); + if (effect == "") + return; ui_vp_effect->set_play_once(false); // The effects themselves dictate whether or not they're looping. Static effects will linger. - ui_vp_effect->play(ao_app->get_effect(fx_name, p_char)); // It will set_play_once to true if the filepath provided is not designed to loop more than once + ui_vp_effect->play(effect); // It will set_play_once to true if the filepath provided is not designed to loop more than once if (fx_sound != "") sfx_player->play(ao_app->get_sfx_suffix(fx_sound)); } @@ -3507,17 +3512,45 @@ void Courtroom::set_effects_dropdown() ui_effects_dropdown->hide(); return; } - QStringList effectslist = ao_app->get_effects() << ao_app->get_char_effects(current_char); + QStringList effectslist = ao_app->get_effects(current_char); if (effectslist.size() <= 0) { ui_effects_dropdown->hide(); return; } + + effectslist.prepend("None"); ui_effects_dropdown->show(); ui_effects_dropdown->addItems(effectslist); + + //ICON-MAKING HELL + QString p_effect = ao_app->read_char_ini(current_char, "effects", "Options"); + 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/"); + 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); + qDebug() << iconpath << entry; + if (!file_exists(iconpath)) + { + iconpath = ao_app->get_static_image_suffix(theme_path + entry); + qDebug() << iconpath << entry; + if (!file_exists(iconpath)) + { + iconpath = ao_app->get_static_image_suffix(default_path + entry); + qDebug() << iconpath << entry; + if (!file_exists(iconpath)) + continue; + } + } + ui_effects_dropdown->setItemIcon(i, QIcon(iconpath)); + } + ui_effects_dropdown->setCurrentIndex(0); } diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index d478582..261b0ff 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -820,42 +820,38 @@ int AOApplication::get_text_delay(QString p_char, QString p_emote) QStringList AOApplication::get_char_effects(QString p_char) { QString p_effect = read_char_ini(p_char, "effects", "Options"); - QString p_path = get_base_path() + "misc/" + p_effect + "/"; - QStringList filters = QStringList() << "*.gif" << "*.webp" << "*.apng" << "*.png" << "*.GIF" << "*.WEBP" << "*.APNG" << "*.PNG"; + QString p_path = get_base_path() + "misc/" + p_effect + "/effects.ini"; - QDir directory(p_path); - QStringList images = directory.entryList(filters, QDir::Files); + QStringList lines = read_file(p_path).split("\n"); QStringList effects; - foreach (QString effect, images) + foreach (QString effect, lines) { - effect = effect.left(effect.lastIndexOf(".")); - if (!effects.contains(effect)) //Do that juicy priority meme + effect = effect.split("=")[0].trimmed(); + qDebug() << effect; + if (effect != "" && !effects.contains(effect)) effects.append(effect); } - return effects; } -QStringList AOApplication::get_effects() +QStringList AOApplication::get_effects(QString p_char) { - QString design_ini_path = get_theme_path("effects/"); - QString default_path = get_default_theme_path("effects/"); - QStringList filters = QStringList() << "*.gif" << "*.webp" << "*.apng" << "*.png" << "*.GIF" << "*.WEBP" << "*.APNG" << "*.PNG"; + QString p_path = get_theme_path("effects/effects.ini"); + QString default_path = get_default_theme_path("effects/effects.ini"); - QDir directory(design_ini_path); - QStringList images = directory.entryList(filters, QDir::Files); - if (images.size() <= 0) + if (!file_exists(p_path)) { - directory.cd(default_path); - images = directory.entryList(filters, QDir::Files); + p_path = default_path; } + QStringList lines = read_file(p_path).split("\n"); - QStringList effects; - foreach (QString effect, images) + QStringList effects = get_char_effects(p_char); + foreach (QString effect, lines) { - effect = effect.left(effect.lastIndexOf(".")); - if (!effects.contains(effect)) //Do that juicy priority meme + effect = effect.split("=")[0].trimmed(); + qDebug() << effect; + if (effect != "" && !effects.contains(effect)) effects.append(effect); } @@ -888,9 +884,9 @@ QString AOApplication::get_effect(QString effect, QString p_char) QString AOApplication::get_effect_sound(QString fx_name, QString p_char) { QString p_effect = read_char_ini(p_char, "effects", "Options"); - QString p_path = get_base_path() + "misc/effects/" + p_effect + "/effect_sounds.ini"; - QString design_ini_path = get_theme_path("effects/effect_sounds.ini"); - QString default_path = get_default_theme_path("effects/effect_sounds.ini"); + QString p_path = get_base_path() + "misc/effects/" + 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(fx_name, p_path); if (f_result == "") From 9b0f07d125e423471665be9fa2895621969bacaf Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Wed, 18 Sep 2019 05:24:40 +0300 Subject: [PATCH 058/268] Make effects stop when next message is received --- src/courtroom.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 48aa637..9083951 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1596,6 +1596,7 @@ void Courtroom::handle_chatmessage_2() { ui_vp_speedlines->stop(); ui_vp_player_char->stop(); + ui_vp_effect->stop(); //Clear all looping sfx to prevent obnoxiousness sfx_player->loop_clear(); From 2d329cdbd27c19d958275fbf1c6862135c96a395 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Wed, 18 Sep 2019 05:45:02 +0300 Subject: [PATCH 059/268] Bugfixes for the thing and how it orders things --- include/aoapplication.h | 2 +- src/text_file_functions.cpp | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/include/aoapplication.h b/include/aoapplication.h index 78de2b8..5fb6338 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -300,7 +300,7 @@ public: 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_char_effects(QString p_char); + 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); diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index 261b0ff..6c34c41 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -817,11 +817,15 @@ int AOApplication::get_text_delay(QString p_char, QString p_emote) else return f_result.toInt(); } -QStringList AOApplication::get_char_effects(QString p_char) +QStringList AOApplication::get_theme_effects() { - QString p_effect = read_char_ini(p_char, "effects", "Options"); - QString p_path = get_base_path() + "misc/" + p_effect + "/effects.ini"; + QString p_path = get_theme_path("effects/effects.ini"); + QString default_path = get_default_theme_path("effects/effects.ini"); + if (!file_exists(p_path)) + { + p_path = default_path; + } QStringList lines = read_file(p_path).split("\n"); QStringList effects; @@ -837,16 +841,12 @@ QStringList AOApplication::get_char_effects(QString p_char) 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_effect = read_char_ini(p_char, "effects", "Options"); + QString p_path = get_base_path() + "misc/" + p_effect + "/effects.ini"; - if (!file_exists(p_path)) - { - p_path = default_path; - } QStringList lines = read_file(p_path).split("\n"); - QStringList effects = get_char_effects(p_char); + QStringList effects = get_theme_effects(); foreach (QString effect, lines) { effect = effect.split("=")[0].trimmed(); @@ -861,7 +861,7 @@ QStringList AOApplication::get_effects(QString p_char) QString AOApplication::get_effect(QString effect, QString p_char) { QString p_effect = read_char_ini(p_char, "effects", "Options"); - QString p_path = get_image_suffix(get_base_path() + "misc/" + p_effect + effect); + 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)); From f8d3d5d8fdeda3d01595e02b7c616606be32f6aa Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Wed, 18 Sep 2019 14:28:26 +0300 Subject: [PATCH 060/268] Fix a bug with sound effect from misc/ folder not being read Make an "effects_icon_size" entry in courtroom_design.ini for scaling the buttons in the effects list --- src/courtroom.cpp | 7 +++++-- src/text_file_functions.cpp | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 9083951..bcf3a42 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -619,8 +619,11 @@ void Courtroom::set_widgets() set_size_and_pos(ui_effects_dropdown, "effects_dropdown"); ui_effects_dropdown->setInsertPolicy(QComboBox::InsertAtBottom); ui_effects_dropdown->setToolTip(tr("Choose an effect to play on your next spoken message.")); - ui_effects_dropdown->setIconSize(QSize(16, 16)); //Todo: don't do hardcoding hell - make it part of courtroom_design.ini - //Todo: actual list of effects + //Todo: recode this entire fucking system with these dumbass goddamn ini's why is everything so specifically coded for all these purposes + //is ABSTRACT CODING not a thing now huh what the FUCK why do I gotta do this pleASE FOR THE LOVE OF GOD SPARE ME FROM THIS FRESH HELL + //btw i still love coding. + QPoint p_point = ao_app->get_button_spacing("effects_icon_size", filename); + ui_effects_dropdown->setIconSize(QSize(p_point.x(), p_point.y())); set_size_and_pos(ui_defense_bar, "defense_bar"); ui_defense_bar->set_image("defensebar" + QString::number(defense_bar_state)); diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index 6c34c41..06caf29 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -884,7 +884,7 @@ QString AOApplication::get_effect(QString effect, QString p_char) QString AOApplication::get_effect_sound(QString fx_name, QString p_char) { QString p_effect = read_char_ini(p_char, "effects", "Options"); - QString p_path = get_base_path() + "misc/effects/" + p_effect + "/effects.ini"; + 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"); From 04daff7446061bb87bdf85ed080079041a75f142 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Wed, 18 Sep 2019 15:46:43 +0300 Subject: [PATCH 061/268] When the realization button is pressed, update the Effects thing too. --- include/courtroom.h | 1 + src/courtroom.cpp | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/include/courtroom.h b/include/courtroom.h index 6ba3d65..a980aba 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -627,6 +627,7 @@ private slots: void set_effects_dropdown(); void on_effects_dropdown_changed(int p_index); + bool effects_dropdown_find_and_set(QString effect); QString get_char_sfx(); int get_char_sfx_delay(); diff --git a/src/courtroom.cpp b/src/courtroom.cpp index bcf3a42..423c560 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -3564,6 +3564,20 @@ void Courtroom::on_effects_dropdown_changed(int p_index) ui_ic_chat_message->setFocus(); } +bool Courtroom::effects_dropdown_find_and_set(QString effect) +{ + for (int i = 0; i < ui_effects_dropdown->count(); ++i) + { + QString entry = ui_effects_dropdown->itemText(i); + if (entry == effect) + { + ui_effects_dropdown->setCurrentIndex(i); + return true; + } + } + return false; +} + QString Courtroom::get_char_sfx() { QString sfx = ui_sfx_dropdown->itemText(ui_sfx_dropdown->currentIndex()); @@ -3775,11 +3789,14 @@ void Courtroom::on_realization_clicked() if (realization_state == 0) { realization_state = 1; + effects_dropdown_find_and_set("realization"); ui_realization->set_image("realization_pressed"); } else { realization_state = 0; + ui_effects_dropdown->setCurrentIndex(0); + on_effects_dropdown_changed(ui_effects_dropdown->currentIndex()); ui_realization->set_image("realization"); } From 0fe94d5d9f0e175ba8355305cdfd6cd35e0a545f Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Wed, 18 Sep 2019 17:34:22 +0300 Subject: [PATCH 062/268] Evidence and emotes reloading when reload_theme is pressed Update evidence a bit and change the way it sets images to something much better and less confusing Update the hovering logic a bit so there's less weird occurences happening e.g. evidence button is deleted --- include/aoevidencebutton.h | 1 - include/courtroom.h | 6 ++++-- src/aoevidencebutton.cpp | 38 ++++++++++++++++++------------------- src/courtroom.cpp | 38 +++++++++++++++---------------------- src/emotes.cpp | 25 +++++++++++++++++++++++- src/evidence.cpp | 39 +++++++++++++++++++++++--------------- 6 files changed, 86 insertions(+), 61 deletions(-) diff --git a/include/aoevidencebutton.h b/include/aoevidencebutton.h index 80b747c..f7baa9f 100644 --- a/include/aoevidencebutton.h +++ b/include/aoevidencebutton.h @@ -15,7 +15,6 @@ class AOEvidenceButton : public QPushButton public: AOEvidenceButton(QWidget *p_parent, AOApplication *p_ao_app, int p_x, int p_y); - void reset(); void set_image(QString p_image); void set_theme_image(QString p_image); void set_id(int p_id) {m_id = p_id;} diff --git a/include/courtroom.h b/include/courtroom.h index a980aba..97f695c 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -571,11 +571,13 @@ private: void put_button_in_place(int starting, int chars_on_this_page); void filter_character_list(); - void construct_emotes(); + void initialize_emotes(); + void refresh_emotes(); void set_emote_page(); void set_emote_dropdown(); - void construct_evidence(); + void initialize_evidence(); + void refresh_evidence(); void set_evidence_page(); public slots: diff --git a/src/aoevidencebutton.cpp b/src/aoevidencebutton.cpp index 616f636..871b477 100644 --- a/src/aoevidencebutton.cpp +++ b/src/aoevidencebutton.cpp @@ -7,48 +7,49 @@ AOEvidenceButton::AOEvidenceButton(QWidget *p_parent, AOApplication *p_ao_app, i ao_app = p_ao_app; m_parent = p_parent; - ui_selected = new AOImage(p_parent, ao_app); + //HELLO AND WELCOME TO HARDCODE CENTRAL, MAY I TAKE YOUR FRESH ORDER OF PAIN AND SUFFERING + ui_selected = new AOImage(this, ao_app); ui_selected->resize(70, 70); - ui_selected->move(p_x, p_y); +// ui_selected->move(p_x, p_y); ui_selected->set_image("evidence_selected"); ui_selected->setAttribute(Qt::WA_TransparentForMouseEvents); ui_selected->hide(); - ui_selector = new AOImage(p_parent, ao_app); - ui_selector->resize(71, 71); - ui_selector->move(p_x - 1, p_y - 1); + ui_selector = new AOImage(this, ao_app); + ui_selector->resize(70, 70); +// ui_selector->move(p_x - 1, p_y - 1); ui_selector->set_image("evidence_selector"); ui_selector->setAttribute(Qt::WA_TransparentForMouseEvents); ui_selector->hide(); this->move(p_x, p_y); this->resize(70, 70); - this->setAcceptDrops(true); +// this->setAcceptDrops(true); connect(this, SIGNAL(clicked()), this, SLOT(on_clicked())); } -void AOEvidenceButton::reset() -{ - this->hide(); - ui_selected->hide(); - ui_selector->hide(); -} - void AOEvidenceButton::set_image(QString p_image) { QString image_path = ao_app->get_evidence_path(p_image); - - if (file_exists(image_path)) + qDebug() << image_path << p_image; + if (file_exists(p_image)) { this->setText(""); - this->setStyleSheet("border-image:url(\"" + image_path + "\")"); + this->setIcon(QIcon(p_image)); + } + else if (file_exists(image_path)) + { + this->setText(""); + this->setIcon(QIcon(image_path)); } else { this->setText(p_image); - this->setStyleSheet(""); + this->setIcon(QIcon()); } + this->setIconSize(this->size()); + this->setStyleSheet("border:0px"); } void AOEvidenceButton::set_theme_image(QString p_image) @@ -63,8 +64,7 @@ void AOEvidenceButton::set_theme_image(QString p_image) else final_image_path = default_image_path; - this->setText(""); - this->setStyleSheet("border-image:url(\"" + final_image_path + "\")"); + this->set_image(final_image_path); } void AOEvidenceButton::set_selected(bool p_selected) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 423c560..295f407 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -98,9 +98,13 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_vp_testimony = new AOMovie(this, ao_app); ui_vp_testimony->set_play_once(false); + ui_vp_testimony->setAttribute(Qt::WA_TransparentForMouseEvents); ui_vp_effect = new AOMovie(this, ao_app); + ui_vp_effect->setAttribute(Qt::WA_TransparentForMouseEvents); ui_vp_wtce = new AOMovie(this, ao_app); + ui_vp_wtce->setAttribute(Qt::WA_TransparentForMouseEvents); ui_vp_objection = new AOMovie(this, ao_app); + ui_vp_objection->setAttribute(Qt::WA_TransparentForMouseEvents); ui_ic_chatlog = new QTextEdit(this); ui_ic_chatlog->setReadOnly(true); @@ -147,12 +151,8 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_music_search->setFrame(false); ui_music_search->setPlaceholderText(tr("Search")); - construct_emotes(); + initialize_emotes(); - ui_emote_left = new AOButton(this, ao_app); - ui_emote_right = new AOButton(this, ao_app); - - ui_emote_dropdown = new QComboBox(this); ui_pos_dropdown = new QComboBox(this); ui_pos_dropdown->addItem("wit"); ui_pos_dropdown->addItem("def"); @@ -267,7 +267,7 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_evidence_button = new AOButton(this, ao_app); - construct_evidence(); + initialize_evidence(); construct_char_select(); @@ -284,10 +284,6 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() connect(chat_tick_timer, SIGNAL(timeout()), this, SLOT(chat_tick())); - connect(ui_emote_left, SIGNAL(clicked()), this, SLOT(on_emote_left_clicked())); - connect(ui_emote_right, SIGNAL(clicked()), this, SLOT(on_emote_right_clicked())); - - connect(ui_emote_dropdown, SIGNAL(activated(int)), this, SLOT(on_emote_dropdown_changed(int))); connect(ui_pos_dropdown, SIGNAL(currentIndexChanged(int)), this, SLOT(on_pos_dropdown_changed(int))); connect(ui_iniswap_dropdown, SIGNAL(activated(int)), this, SLOT(on_iniswap_dropdown_changed(int))); @@ -582,14 +578,6 @@ void Courtroom::set_widgets() //set_size_and_pos(ui_area_password, "area_password"); set_size_and_pos(ui_music_search, "music_search"); - set_size_and_pos(ui_emotes, "emotes"); - - set_size_and_pos(ui_emote_left, "emote_left"); - ui_emote_left->set_image("arrow_left"); - - set_size_and_pos(ui_emote_right, "emote_right"); - ui_emote_right->set_image("arrow_right"); - set_size_and_pos(ui_emote_dropdown, "emote_dropdown"); set_size_and_pos(ui_pos_dropdown, "pos_dropdown"); ui_pos_dropdown->setToolTip(tr("Set your character's supplementary background.")); @@ -820,6 +808,9 @@ void Courtroom::set_widgets() set_size_and_pos(ui_spectator, "spectator"); ui_spectator->setToolTip(tr("Become a spectator. You won't be able to interact with the in-character screen.")); + + refresh_evidence(); + refresh_emotes(); } void Courtroom::set_fonts() @@ -1060,6 +1051,8 @@ void Courtroom::update_character(int p_cid) void Courtroom::enter_courtroom() { + set_widgets(); + current_evidence_page = 0; current_evidence = 0; @@ -1089,9 +1082,6 @@ void Courtroom::enter_courtroom() blip_player->set_volume(ui_blip_slider->value()); ui_vp_testimony->stop(); - - set_widgets(); - //ui_server_chatlog->setHtml(ui_server_chatlog->toHtml()); } @@ -3789,7 +3779,9 @@ void Courtroom::on_realization_clicked() if (realization_state == 0) { realization_state = 1; - effects_dropdown_find_and_set("realization"); + if (effects_dropdown_find_and_set("realization")) + on_effects_dropdown_changed(ui_effects_dropdown->currentIndex()); + ui_realization->set_image("realization_pressed"); } else @@ -3980,8 +3972,8 @@ void Courtroom::on_reload_theme_clicked() //to update status on the background set_background(current_background); - update_character(m_cid); enter_courtroom(); + update_character(m_cid); anim_state = 4; text_state = 3; diff --git a/src/emotes.cpp b/src/emotes.cpp index daa8d6d..4ce2eb7 100644 --- a/src/emotes.cpp +++ b/src/emotes.cpp @@ -2,12 +2,35 @@ #include "aoemotebutton.h" -void Courtroom::construct_emotes() +void Courtroom::initialize_emotes() { ui_emotes = new QWidget(this); + ui_emote_left = new AOButton(this, ao_app); + ui_emote_right = new AOButton(this, ao_app); + + ui_emote_dropdown = new QComboBox(this); + + connect(ui_emote_left, SIGNAL(clicked()), this, SLOT(on_emote_left_clicked())); + connect(ui_emote_right, SIGNAL(clicked()), this, SLOT(on_emote_right_clicked())); + + connect(ui_emote_dropdown, SIGNAL(activated(int)), this, SLOT(on_emote_dropdown_changed(int))); +} + +void Courtroom::refresh_emotes() +{ + //Should properly refresh the emote list + qDeleteAll(ui_emote_list.begin(), ui_emote_list.end()); + ui_emote_list.clear(); + set_size_and_pos(ui_emotes, "emotes"); + set_size_and_pos(ui_emote_left, "emote_left"); + ui_emote_left->set_image("arrow_left"); + + set_size_and_pos(ui_emote_right, "emote_right"); + ui_emote_right->set_image("arrow_right"); + QPoint f_spacing = ao_app->get_button_spacing("emote_button_spacing", "courtroom_design.ini"); const int button_width = 40; diff --git a/src/evidence.cpp b/src/evidence.cpp index 7580685..d8f3743 100644 --- a/src/evidence.cpp +++ b/src/evidence.cpp @@ -1,6 +1,6 @@ #include "courtroom.h" -void Courtroom::construct_evidence() +void Courtroom::initialize_evidence() { ui_evidence = new AOImage(this, ao_app); @@ -30,6 +30,24 @@ void Courtroom::construct_evidence() ui_evidence_description->setStyleSheet("background-color: rgba(0, 0, 0, 0);" "color: white;"); + connect(ui_evidence_name, SIGNAL(textEdited(QString)), this, SLOT(on_evidence_name_edited(QString))); + connect(ui_evidence_left, SIGNAL(clicked()), this, SLOT(on_evidence_left_clicked())); + connect(ui_evidence_right, SIGNAL(clicked()), this, SLOT(on_evidence_right_clicked())); + connect(ui_evidence_present, SIGNAL(clicked()), this, SLOT(on_evidence_present_clicked())); + connect(ui_evidence_delete, SIGNAL(clicked()), this, SLOT(on_evidence_delete_clicked())); + connect(ui_evidence_image_name, SIGNAL(returnPressed()), this, SLOT(on_evidence_image_name_edited())); + connect(ui_evidence_image_button, SIGNAL(clicked()), this, SLOT(on_evidence_image_button_clicked())); + connect(ui_evidence_x, SIGNAL(clicked()), this, SLOT(on_evidence_x_clicked())); + + ui_evidence->hide(); +} + +void Courtroom::refresh_evidence() +{ + //Should properly refresh the evidence list + qDeleteAll(ui_evidence_list.begin(), ui_evidence_list.end()); + ui_evidence_list.clear(); + set_size_and_pos(ui_evidence, "evidence_background"); set_size_and_pos(ui_evidence_buttons, "evidence_buttons"); @@ -71,17 +89,6 @@ void Courtroom::construct_evidence() x_mod_count = 0; } } - - connect(ui_evidence_name, SIGNAL(textEdited(QString)), this, SLOT(on_evidence_name_edited(QString))); - connect(ui_evidence_left, SIGNAL(clicked()), this, SLOT(on_evidence_left_clicked())); - connect(ui_evidence_right, SIGNAL(clicked()), this, SLOT(on_evidence_right_clicked())); - connect(ui_evidence_present, SIGNAL(clicked()), this, SLOT(on_evidence_present_clicked())); - connect(ui_evidence_delete, SIGNAL(clicked()), this, SLOT(on_evidence_delete_clicked())); - connect(ui_evidence_image_name, SIGNAL(returnPressed()), this, SLOT(on_evidence_image_name_edited())); - connect(ui_evidence_image_button, SIGNAL(clicked()), this, SLOT(on_evidence_image_button_clicked())); - connect(ui_evidence_x, SIGNAL(clicked()), this, SLOT(on_evidence_x_clicked())); - - ui_evidence->hide(); } void Courtroom::set_evidence_list(QVector &p_evi_list) @@ -101,7 +108,7 @@ void Courtroom::set_evidence_page() for (AOEvidenceButton *i_button : ui_evidence_list) { - i_button->reset(); + i_button->hide(); } //to account for the "add evidence" button @@ -135,20 +142,22 @@ void Courtroom::set_evidence_page() AOEvidenceButton *f_evidence_button = ui_evidence_list.at(n_evidence_button); //ie. the add evidence button + f_evidence_button->set_selected(false); if (n_real_evidence == (total_evidence - 1)) + { f_evidence_button->set_theme_image("addevidence.png"); + } else if (n_real_evidence < (total_evidence - 1)) { f_evidence_button->set_image(local_evidence_list.at(n_real_evidence).image); if (n_real_evidence == current_evidence) f_evidence_button->set_selected(true); - else - f_evidence_button->set_selected(false); } else f_evidence_button->set_image(""); + f_evidence_button->show(); } } From cda7d430b3fa988258819012a5a96249aa553f1e Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Wed, 18 Sep 2019 19:43:11 +0300 Subject: [PATCH 063/268] use SetIcon for AOEmoteButton instead of stylesheets Fix aolineedit not sending the double_clicked signal Add tooltips for emotes that display the number and the emote_comment (name) Add similar tooltips to evidence buttons Resolve an issue where you could edit evidence name without double-clicking a piece of evidence first --- include/aoemotebutton.h | 5 ++--- src/aoemotebutton.cpp | 29 ++++++++++++++++++----------- src/aolineedit.cpp | 1 + src/emotes.cpp | 11 ++++++----- src/evidence.cpp | 19 ++++++++++++++++--- 5 files changed, 43 insertions(+), 22 deletions(-) diff --git a/include/aoemotebutton.h b/include/aoemotebutton.h index c99a73b..4c31014 100644 --- a/include/aoemotebutton.h +++ b/include/aoemotebutton.h @@ -13,9 +13,8 @@ class AOEmoteButton : public QPushButton public: AOEmoteButton(QWidget *p_parent, AOApplication *p_ao_app, int p_x, int p_y); - //void set_on(QString p_char, int p_emote); - //void set_off(QString p_char, int p_emote); - void set_image(QString p_char, int p_emote, QString suffix); + void set_image(QString p_image, QString p_emote_comment); + void set_char_image(QString p_char, int p_emote, QString suffix); void set_id(int p_id) {m_id = p_id;} int get_id() {return m_id;} diff --git a/src/aoemotebutton.cpp b/src/aoemotebutton.cpp index ca4d694..8d68712 100644 --- a/src/aoemotebutton.cpp +++ b/src/aoemotebutton.cpp @@ -13,21 +13,28 @@ AOEmoteButton::AOEmoteButton(QWidget *p_parent, AOApplication *p_ao_app, int p_x connect(this, SIGNAL(clicked()), this, SLOT(on_clicked())); } -void AOEmoteButton::set_image(QString p_char, int p_emote, QString suffix) +void AOEmoteButton::set_image(QString p_image, QString p_emote_comment) +{ + if (file_exists(p_image)) + { + this->setIcon(QIcon(p_image)); + this->setIconSize(this->size()); + this->setStyleSheet("border:0px"); + this->setText(""); + } + else + { + this->setText(p_emote_comment); + this->setStyleSheet("border-image:url(\"\")"); + } +} + +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(p_char, "emotions/button" + emotion_number + suffix)); - if (file_exists(image_path)) - { - this->setText(""); - this->setStyleSheet("border-image:url(\"" + image_path + "\")"); - } - else - { - this->setText(ao_app->get_emote_comment(p_char, p_emote)); - this->setStyleSheet("border-image:url(\"\")"); - } + this->set_image(image_path, ao_app->get_emote_comment(p_char, p_emote)); } void AOEmoteButton::on_clicked() diff --git a/src/aolineedit.cpp b/src/aolineedit.cpp index f6026e1..13f87f3 100644 --- a/src/aolineedit.cpp +++ b/src/aolineedit.cpp @@ -13,6 +13,7 @@ void AOLineEdit::mouseDoubleClickEvent(QMouseEvent *e) QLineEdit::mouseDoubleClickEvent(e); this->setReadOnly(false); + double_clicked(); } void AOLineEdit::on_enter_pressed() diff --git a/src/emotes.cpp b/src/emotes.cpp index 4ce2eb7..f6239ee 100644 --- a/src/emotes.cpp +++ b/src/emotes.cpp @@ -112,11 +112,12 @@ void Courtroom::set_emote_page() AOEmoteButton *f_emote = ui_emote_list.at(n_emote); if (n_real_emote == current_emote) - f_emote->set_image(current_char, n_real_emote, "_on"); + f_emote->set_char_image(current_char, n_real_emote, "_on"); else - f_emote->set_image(current_char, n_real_emote, "_off"); + f_emote->set_char_image(current_char, n_real_emote, "_off"); f_emote->show(); + f_emote->setToolTip(QString::number(n_real_emote+1) + ": " + ao_app->get_emote_comment(current_char, n_real_emote)); } } @@ -130,7 +131,7 @@ void Courtroom::set_emote_dropdown() for (int n = 0 ; n < total_emotes ; ++n) { - emote_list.append(ao_app->get_emote_comment(current_char, n)); + emote_list.append(QString::number(n+1) + ": " + ao_app->get_emote_comment(current_char, n)); } ui_emote_dropdown->addItems(emote_list); @@ -142,14 +143,14 @@ void Courtroom::select_emote(int p_id) int max = (max_emotes_on_page - 1) + current_emote_page * max_emotes_on_page; if (current_emote >= min && current_emote <= max) - ui_emote_list.at(current_emote % max_emotes_on_page)->set_image(current_char, current_emote, "_off"); + ui_emote_list.at(current_emote % max_emotes_on_page)->set_char_image(current_char, current_emote, "_off"); int old_emote = current_emote; current_emote = p_id; if (current_emote >= min && current_emote <= max) - ui_emote_list.at(current_emote % max_emotes_on_page)->set_image(current_char, current_emote, "_on"); + ui_emote_list.at(current_emote % max_emotes_on_page)->set_char_image(current_char, current_emote, "_on"); int emote_mod = ao_app->get_emote_mod(current_char, current_emote); diff --git a/src/evidence.cpp b/src/evidence.cpp index d8f3743..5e5bc9d 100644 --- a/src/evidence.cpp +++ b/src/evidence.cpp @@ -141,8 +141,8 @@ void Courtroom::set_evidence_page() int n_real_evidence = n_evidence_button + current_evidence_page * max_evidence_on_page; AOEvidenceButton *f_evidence_button = ui_evidence_list.at(n_evidence_button); - //ie. the add evidence button f_evidence_button->set_selected(false); + f_evidence_button->setToolTip(""); if (n_real_evidence == (total_evidence - 1)) { f_evidence_button->set_theme_image("addevidence.png"); @@ -153,11 +153,12 @@ void Courtroom::set_evidence_page() if (n_real_evidence == current_evidence) f_evidence_button->set_selected(true); + + f_evidence_button->setToolTip(QString::number(n_real_evidence+1) + ": " + local_evidence_list.at(n_real_evidence).name); } else f_evidence_button->set_image(""); - f_evidence_button->show(); } } @@ -180,6 +181,14 @@ void Courtroom::on_evidence_name_edited(QString text) ao_app->send_server_packet(new AOPacket("EE", f_contents)); } +void Courtroom::on_evidence_name_double_clicked() +{ + if (ui_evidence_overlay->isVisible()) + ui_evidence_name->setReadOnly(false); + else + ui_evidence_name->setReadOnly(true); +} + void Courtroom::on_evidence_image_name_edited() { if (current_evidence >= local_evidence_list.size()) @@ -243,7 +252,7 @@ void Courtroom::on_evidence_clicked(int p_id) current_evidence = f_real_id; - ui_ic_chat_message->setFocus(); +// ui_ic_chat_message->setFocus(); } @@ -319,6 +328,7 @@ void Courtroom::on_evidence_present_clicked() void Courtroom::on_evidence_delete_clicked() { ui_evidence_description->setReadOnly(true); + ui_evidence_name->setReadOnly(true); ui_evidence_overlay->hide(); ao_app->send_server_packet(new AOPacket("DE#" + QString::number(current_evidence) + "#%")); @@ -331,7 +341,10 @@ void Courtroom::on_evidence_delete_clicked() void Courtroom::on_evidence_x_clicked() { ui_evidence_description->setReadOnly(true); + ui_evidence_name->setReadOnly(true); ui_evidence_overlay->hide(); + ui_ic_chat_message->setFocus(); +} if (current_evidence >= local_evidence_list.size()) return; From a175a1884cd057cb01e53b66f56491f9ae0e80d5 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Wed, 18 Sep 2019 20:02:51 +0300 Subject: [PATCH 064/268] Concurrent evidence updating! Similar to the way Google Docs work, the evidence will be updated immediately as you make any changes to it. --- include/courtroom.h | 2 ++ src/evidence.cpp | 38 +++++++++++++++++++++++++++++--------- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/include/courtroom.h b/include/courtroom.h index 97f695c..d02c756 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -691,10 +691,12 @@ private slots: void on_showname_enable_clicked(); + void on_evidence_name_double_clicked(); void on_evidence_button_clicked(); void on_evidence_delete_clicked(); void on_evidence_x_clicked(); + void on_evidence_description_edited(); void on_back_to_lobby_clicked(); diff --git a/src/evidence.cpp b/src/evidence.cpp index 5e5bc9d..b2e8557 100644 --- a/src/evidence.cpp +++ b/src/evidence.cpp @@ -31,6 +31,7 @@ void Courtroom::initialize_evidence() "color: white;"); connect(ui_evidence_name, SIGNAL(textEdited(QString)), this, SLOT(on_evidence_name_edited(QString))); + connect(ui_evidence_name, SIGNAL(double_clicked()), this, SLOT(on_evidence_name_double_clicked())); connect(ui_evidence_left, SIGNAL(clicked()), this, SLOT(on_evidence_left_clicked())); connect(ui_evidence_right, SIGNAL(clicked()), this, SLOT(on_evidence_right_clicked())); connect(ui_evidence_present, SIGNAL(clicked()), this, SLOT(on_evidence_present_clicked())); @@ -38,6 +39,7 @@ void Courtroom::initialize_evidence() connect(ui_evidence_image_name, SIGNAL(returnPressed()), this, SLOT(on_evidence_image_name_edited())); connect(ui_evidence_image_button, SIGNAL(clicked()), this, SLOT(on_evidence_image_button_clicked())); connect(ui_evidence_x, SIGNAL(clicked()), this, SLOT(on_evidence_x_clicked())); + connect(ui_evidence_description, SIGNAL(textChanged()), this, SLOT(on_evidence_description_edited())); ui_evidence->hide(); } @@ -97,6 +99,19 @@ void Courtroom::set_evidence_list(QVector &p_evi_list) local_evidence_list = p_evi_list; set_evidence_page(); + + if (ui_evidence_overlay->isVisible())//Update the currently edited evidence for this user + { + if (current_evidence >= local_evidence_list.size()) + { + on_evidence_x_clicked(); + ui_evidence_name->setText(""); + } + else + { + on_evidence_double_clicked(current_evidence); + } + } } void Courtroom::set_evidence_page() @@ -267,14 +282,23 @@ void Courtroom::on_evidence_double_clicked(int p_id) evi_type f_evi = local_evidence_list.at(f_real_id); - ui_evidence_description->clear(); - ui_evidence_description->appendPlainText(f_evi.description); + QTextCursor cursor = ui_evidence_description->textCursor(); + int pos = cursor.position(); + + //ISSUE: Undo/redo history is completely inaccessible. :( + ui_evidence_description->blockSignals(true); + ui_evidence_description->setPlainText(f_evi.description); + ui_evidence_description->blockSignals(false); + + cursor.setPosition(pos); //Reset the cursor position back in place + ui_evidence_description->setTextCursor(cursor); ui_evidence_image_name->setText(f_evi.image); + ui_evidence_name->setText(f_evi.name); ui_evidence_overlay->show(); - ui_ic_chat_message->setFocus(); +// ui_ic_chat_message->setFocus(); } void Courtroom::on_evidence_hover(int p_id, bool p_state) @@ -346,9 +370,8 @@ void Courtroom::on_evidence_x_clicked() ui_ic_chat_message->setFocus(); } - if (current_evidence >= local_evidence_list.size()) - return; - +void Courtroom::on_evidence_description_edited() +{ QStringList f_contents; evi_type f_evi = local_evidence_list.at(current_evidence); @@ -359,7 +382,4 @@ void Courtroom::on_evidence_x_clicked() f_contents.append(f_evi.image); ao_app->send_server_packet(new AOPacket("EE", f_contents)); - - ui_ic_chat_message->setFocus(); } - From 38137657de4400306a3221b2478247576db8077e Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Wed, 18 Sep 2019 20:45:36 +0300 Subject: [PATCH 065/268] emote_button_size,evidence_button_size added to courtroom_design.ini evidence_name, evidence_image_name, evidence_description added to courtroom_fonts.ini --- src/emotes.cpp | 5 +++-- src/evidence.cpp | 13 +++++++------ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/emotes.cpp b/src/emotes.cpp index f6239ee..a08043c 100644 --- a/src/emotes.cpp +++ b/src/emotes.cpp @@ -32,12 +32,13 @@ void Courtroom::refresh_emotes() ui_emote_right->set_image("arrow_right"); QPoint f_spacing = ao_app->get_button_spacing("emote_button_spacing", "courtroom_design.ini"); + QPoint p_point = ao_app->get_button_spacing("emote_button_size", "courtroom_design.ini"); - const int button_width = 40; + const int button_width = p_point.x(); int x_spacing = f_spacing.x(); int x_mod_count = 0; - const int button_height = 40; + const int button_height = p_point.y(); int y_spacing = f_spacing.y(); int y_mod_count = 0; diff --git a/src/evidence.cpp b/src/evidence.cpp index b2e8557..523c410 100644 --- a/src/evidence.cpp +++ b/src/evidence.cpp @@ -7,10 +7,6 @@ void Courtroom::initialize_evidence() //ui_evidence_name = new QLabel(ui_evidence); ui_evidence_name = new AOLineEdit(ui_evidence); ui_evidence_name->setAlignment(Qt::AlignCenter); - //WHY IS THIS FONT HARDCODED, WHAT IS WRONG WITH YOU - ui_evidence_name->setFont(QFont("Arial", 14, QFont::Bold)); - ui_evidence_name->setStyleSheet("background-color: rgba(0, 0, 0, 0);" - "color: rgba(255, 128, 0, 255);"); ui_evidence_buttons = new QWidget(ui_evidence); @@ -46,6 +42,10 @@ void Courtroom::initialize_evidence() void Courtroom::refresh_evidence() { + set_font(ui_evidence_name, "", "evidence_name"); + set_font(ui_evidence_image_name, "", "evidence_image_name"); + set_font(ui_evidence_description, "", "evidence_description"); + //Should properly refresh the evidence list qDeleteAll(ui_evidence_list.begin(), ui_evidence_list.end()); ui_evidence_list.clear(); @@ -54,12 +54,13 @@ void Courtroom::refresh_evidence() set_size_and_pos(ui_evidence_buttons, "evidence_buttons"); QPoint f_spacing = ao_app->get_button_spacing("evidence_button_spacing", "courtroom_design.ini"); + QPoint p_point = ao_app->get_button_spacing("evidence_button_size", "courtroom_design.ini"); - const int button_width = 70; + const int button_width = p_point.x(); int x_spacing = f_spacing.x(); int x_mod_count = 0; - const int button_height = 70; + const int button_height = p_point.y(); int y_spacing = f_spacing.y(); int y_mod_count = 0; From df08ec4be6ff519f82e22a7485725128999ce174 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Wed, 18 Sep 2019 22:46:10 +0300 Subject: [PATCH 066/268] Get rid of some debug text --- src/courtroom.cpp | 5 +---- src/evidence.cpp | 1 - 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 295f407..fac564c 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -2318,7 +2318,7 @@ void Courtroom::start_chat_ticking() if (m_chatmessage[EFFECTS] != "") { QStringList fx_list = m_chatmessage[EFFECTS].split("|"); - qDebug() << m_chatmessage[EFFECTS] << fx_list; +// qDebug() << m_chatmessage[EFFECTS] << fx_list; QString fx = fx_list[0]; QString fx_sound; if (fx_list.length() > 1) @@ -3529,15 +3529,12 @@ void Courtroom::set_effects_dropdown() { QString entry = ui_effects_dropdown->itemText(i); QString iconpath = ao_app->get_static_image_suffix(custom_path + entry); - qDebug() << iconpath << entry; if (!file_exists(iconpath)) { iconpath = ao_app->get_static_image_suffix(theme_path + entry); - qDebug() << iconpath << entry; if (!file_exists(iconpath)) { iconpath = ao_app->get_static_image_suffix(default_path + entry); - qDebug() << iconpath << entry; if (!file_exists(iconpath)) continue; } diff --git a/src/evidence.cpp b/src/evidence.cpp index 523c410..727f4bf 100644 --- a/src/evidence.cpp +++ b/src/evidence.cpp @@ -189,7 +189,6 @@ void Courtroom::on_evidence_name_edited(QString text) evi_type f_evi = local_evidence_list.at(current_evidence); f_contents.append(QString::number(current_evidence)); - qDebug() << text; f_contents.append(ui_evidence_name->text()); f_contents.append(f_evi.description); f_contents.append(f_evi.image); From 3899dbe0bd82875214ebd676130692120f89a412 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Fri, 20 Sep 2019 05:30:07 +0300 Subject: [PATCH 067/268] I dunno what the fuck was I doing for the past 4 hours but I made crossfading music work. Music packets can receive channel to play the song in and the crossfading option too. --- include/aomusicplayer.h | 25 ++++++++--- src/aomusicplayer.cpp | 94 ++++++++++++++++++++++++++++++++--------- src/aosfxplayer.cpp | 2 +- src/courtroom.cpp | 37 +++++++++++++--- 4 files changed, 126 insertions(+), 32 deletions(-) diff --git a/include/aomusicplayer.h b/include/aomusicplayer.h index da47128..8ed0771 100644 --- a/include/aomusicplayer.h +++ b/include/aomusicplayer.h @@ -1,5 +1,6 @@ #ifndef AOMUSICPLAYER_H #define AOMUSICPLAYER_H +#include "file_functions.h" #if defined(BASSAUDIO) #include "bass.h" @@ -19,18 +20,30 @@ public: AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app); virtual ~AOMusicPlayer(); - void play(QString p_song); - void stop(); - void set_volume(int p_value); - void set_looping(bool toggle); + void play(QString p_song, int channel=0, bool crossfade=false); + void stop(int channel=0); + void set_volume(int p_value, int channel=0); + void set_looping(bool toggle, int channel=0); + + //These have to be public for the stupid sync thing +// QWORD loop_start = 0; +// QWORD loop_end = 0; private: QWidget *m_parent; AOApplication *ao_app; - bool m_looping = true; + bool m_looping = false; int m_volume = 0; - HSTREAM m_stream; + + const int m_channelmax = 4; + // Channel 0 = music + // Channel 1 = ambience + // Channel 2 = extra + // Channel 3 = extra + HSTREAM m_stream_list[4]; + +// HSYNC loop_sync; }; #elif defined(QTAUDIO) class AOMusicPlayer diff --git a/src/aomusicplayer.cpp b/src/aomusicplayer.cpp index 781a90c..f6bcb17 100644 --- a/src/aomusicplayer.cpp +++ b/src/aomusicplayer.cpp @@ -1,6 +1,6 @@ #include "aomusicplayer.h" -#if defined(BASSAUDIO) +#ifdef BASSAUDIO AOMusicPlayer::AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app) { m_parent = parent; @@ -9,48 +9,104 @@ AOMusicPlayer::AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app) AOMusicPlayer::~AOMusicPlayer() { - BASS_ChannelStop(m_stream); + for (int n_stream = 0 ; n_stream < m_channelmax ; ++n_stream) + { + BASS_ChannelStop(m_stream_list[n_stream]); + } } -void AOMusicPlayer::play(QString p_song) +void AOMusicPlayer::play(QString p_song, int channel, bool crossfade) { - BASS_ChannelStop(m_stream); - + channel = channel % m_channelmax; QString f_path = ao_app->get_music_path(p_song); - unsigned int flags = BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE; - m_stream = BASS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, flags); +// QString d_path = f_path + ".txt"; + +// if (file_exists(d_path)) //Contains loop/etc. information file +// { +// QStringList lines = ao_app->read_file(d_path).split("\n"); +// foreach (QString line, lines) +// { +// QStringList args = line.split("="); +// if (args.size() < 2) +// continue; +// QString arg = args[0].trimmed(); +// if (arg == "loop_start") +// loop_start = args[1].trimmed().toUInt(); +// else if (arg == "loop_end") +// loop_end = args[1].trimmed().toUInt(); +// } +// qDebug() << "Found data file for song" << p_song << loop_start << loop_end; +// } + + unsigned int flags = BASS_STREAM_PRESCAN | BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE; + DWORD newstream = BASS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, flags); - this->set_volume(m_volume); - this->set_looping(m_looping); if (ao_app->get_audio_output_device() != "default") - BASS_ChannelSetDevice(m_stream, BASS_GetDevice()); - BASS_ChannelPlay(m_stream, false); + BASS_ChannelSetDevice(m_stream_list[channel], BASS_GetDevice()); + + if (BASS_ChannelIsActive(m_stream_list[channel]) == BASS_ACTIVE_PLAYING && crossfade) + { + DWORD oldstream = m_stream_list[channel]; + + //Fade out the other sample and stop it + BASS_ChannelSlideAttribute(oldstream, BASS_ATTRIB_VOL|BASS_SLIDE_LOG, -1, 5000); + BASS_ChannelLock(oldstream, true); + //Mute the new sample + BASS_ChannelSetAttribute(newstream, BASS_ATTRIB_VOL, 0); + //Sync it with the new sample + BASS_ChannelSetPosition(newstream, BASS_ChannelGetPosition(oldstream, BASS_POS_BYTE), BASS_POS_BYTE); + //Start it + BASS_ChannelPlay(newstream, false); + //Fade in our sample + BASS_ChannelSlideAttribute(newstream, BASS_ATTRIB_VOL, static_cast(m_volume / 100.0f), 1000); + BASS_ChannelLock(oldstream, false); + m_stream_list[channel] = newstream; + } + else + { + BASS_ChannelStop(m_stream_list[channel]); + m_stream_list[channel] = newstream; + BASS_ChannelPlay(m_stream_list[channel], false); + this->set_volume(m_volume); + } + + this->set_looping(m_looping); //Have to do this here due to any crossfading-related changes, etc. } -void AOMusicPlayer::stop() +void AOMusicPlayer::stop(int channel) { - BASS_ChannelStop(m_stream); + BASS_ChannelStop(m_stream_list[channel]); } -void AOMusicPlayer::set_volume(int p_value) +void AOMusicPlayer::set_volume(int p_value, int channel) { m_volume = p_value; float volume = m_volume / 100.0f; - BASS_ChannelSetAttribute(m_stream, BASS_ATTRIB_VOL, volume); + BASS_ChannelSetAttribute(m_stream_list[channel], BASS_ATTRIB_VOL, volume); } -void AOMusicPlayer::set_looping(bool toggle) +//void CALLBACK loopProc(HSYNC handle, DWORD channel, DWORD data, void *user) +//{ +// AOMusicPlayer *self= static_cast(user); +// qDebug() << BASS_ChannelGetPosition(channel, BASS_POS_BYTE); +// BASS_ChannelSetPosition(channel, self->loop_start, BASS_POS_BYTE); +//} + +void AOMusicPlayer::set_looping(bool toggle, int channel) { m_looping = toggle; - if (BASS_ChannelFlags(m_stream, 0, 0) & BASS_SAMPLE_LOOP) + if (BASS_ChannelFlags(m_stream_list[channel], 0, 0) & BASS_SAMPLE_LOOP) { if (m_looping == false) - BASS_ChannelFlags(m_stream, 0, BASS_SAMPLE_LOOP); // remove the LOOP flag + BASS_ChannelFlags(m_stream_list[channel], 0, BASS_SAMPLE_LOOP); // remove the LOOP flag +// BASS_ChannelRemoveSync(m_stream_list[channel], loop_sync); } else { if (m_looping == true) - BASS_ChannelFlags(m_stream, BASS_SAMPLE_LOOP, BASS_SAMPLE_LOOP); // set the LOOP flag + BASS_ChannelFlags(m_stream_list[channel], BASS_SAMPLE_LOOP, BASS_SAMPLE_LOOP); // set the LOOP flag +// if (loop_end > 0 && loop_end < BASS_ChannelGetLength(m_stream_list[channel], BASS_POS_BYTE)) +// loop_sync = BASS_ChannelSetSync(m_stream_list[channel], BASS_SYNC_POS | BASS_SYNC_MIXTIME, loop_end, loopProc, this); } } #elif defined(QTAUDIO) diff --git a/src/aosfxplayer.cpp b/src/aosfxplayer.cpp index b9410c8..ca2b393 100644 --- a/src/aosfxplayer.cpp +++ b/src/aosfxplayer.cpp @@ -31,7 +31,7 @@ void AOSfxPlayer::play(QString p_sfx, QString p_char, QString shout, int channel { if (channel == -1) { - if (m_stream_list[channel] != NULL) + if (BASS_ChannelIsActive(m_stream_list[channel]) == BASS_ACTIVE_PLAYING) m_channel = (m_channel + 1) % m_channelmax; channel = m_channel; } diff --git a/src/courtroom.cpp b/src/courtroom.cpp index fac564c..4291468 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -2862,12 +2862,28 @@ void Courtroom::handle_song(QStringList *p_contents) if (n_char < 0 || n_char >= char_list.size()) { - music_player->play(f_song); + music_player->set_looping(true); + int channel = 0; + if (p_contents->length() > 3 && p_contents->at(3) != "-1") + music_player->set_looping(false); + + if (p_contents->length() > 4) //eyyy we want to change this song's CHANNEL huh + channel = p_contents->at(4).toInt(); //let the music player handle it if it's bigger than the channel list + + bool crossfade = false; + if (p_contents->length() > 5) //CROSSFADE!? Are you MAD? + { + qDebug() << p_contents->at(5); + crossfade = p_contents->at(5) == "1"; //let the music player handle it if it's bigger than the channel list + } + + music_player->play(f_song, channel, crossfade); } else { QString str_char = char_list.at(n_char).name; QString str_show = char_list.at(n_char).name; + music_player->set_looping(true); if (p_contents->length() > 2) { @@ -2884,11 +2900,14 @@ void Courtroom::handle_song(QStringList *p_contents) { music_player->set_looping(false); } - else - { - music_player->set_looping(true); - } } + int channel = 0; + if (p_contents->length() > 4) //eyyy we want to change this song's CHANNEL huh + channel = p_contents->at(4).toInt(); //let the music player handle it if it's bigger than the channel list + + bool crossfade = false; + if (p_contents->length() > 5) //CROSSFADE!? Are you MAD? + crossfade = p_contents->at(5) == "1"; //let the music player handle it if it's bigger than the channel list if (!mute_map.value(n_char)) { @@ -2902,7 +2921,7 @@ void Courtroom::handle_song(QStringList *p_contents) } append_ic_text(f_song_clear, str_show, true); - music_player->play(f_song); + music_player->play(f_song, channel, crossfade); } } } @@ -4055,6 +4074,12 @@ void Courtroom::on_flip_clicked() void Courtroom::on_additive_clicked() { + if (ui_additive->isChecked()) + { + ui_ic_chat_message->home(false); //move cursor to the start of the message + ui_ic_chat_message->insert(" "); //preface the message by whitespace + ui_ic_chat_message->end(false); //move cursor to the end of the message without selecting anything + } ui_ic_chat_message->setFocus(); } From d3f23708c43bc132c322b778b2aa8d31a68d1c0c Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Fri, 20 Sep 2019 15:54:45 +0300 Subject: [PATCH 068/268] Revert buttons using setIcon and use a better stylesheet method instead Fix evidence buttons and emote buttons being hardcoded size --- include/aoemotebutton.h | 2 +- include/aoevidencebutton.h | 2 +- src/aobutton.cpp | 10 ++++------ src/aocharbutton.cpp | 8 ++++++-- src/aoemotebutton.cpp | 12 ++++++------ src/aoevidencebutton.cpp | 21 ++++++++++----------- src/emotes.cpp | 2 +- src/evidence.cpp | 2 +- 8 files changed, 30 insertions(+), 29 deletions(-) diff --git a/include/aoemotebutton.h b/include/aoemotebutton.h index 4c31014..a13688b 100644 --- a/include/aoemotebutton.h +++ b/include/aoemotebutton.h @@ -11,7 +11,7 @@ class AOEmoteButton : public QPushButton Q_OBJECT public: - AOEmoteButton(QWidget *p_parent, AOApplication *p_ao_app, int p_x, int p_y); + AOEmoteButton(QWidget *p_parent, AOApplication *p_ao_app, int p_x, int p_y, int p_w, int p_h); void set_image(QString p_image, QString p_emote_comment); void set_char_image(QString p_char, int p_emote, QString suffix); diff --git a/include/aoevidencebutton.h b/include/aoevidencebutton.h index f7baa9f..53fa11f 100644 --- a/include/aoevidencebutton.h +++ b/include/aoevidencebutton.h @@ -13,7 +13,7 @@ class AOEvidenceButton : public QPushButton Q_OBJECT public: - AOEvidenceButton(QWidget *p_parent, AOApplication *p_ao_app, int p_x, int p_y); + AOEvidenceButton(QWidget *p_parent, AOApplication *p_ao_app, int p_x, int p_y, int p_w, int p_h); void set_image(QString p_image); void set_theme_image(QString p_image); diff --git a/src/aobutton.cpp b/src/aobutton.cpp index d80226f..9efe13d 100644 --- a/src/aobutton.cpp +++ b/src/aobutton.cpp @@ -20,17 +20,15 @@ void AOButton::set_image(QString p_image) if (file_exists(image_path)) { - this->setIcon(QIcon(image_path)); - this->setIconSize(this->size()); - this->setStyleSheet("border:0px"); 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; }"); } else if (file_exists(default_image_path)) { - this->setIcon(QIcon(default_image_path)); - this->setIconSize(this->size()); - this->setStyleSheet("border:0px"); this->setText(""); + this->setStyleSheet("QPushButton { border-image: url(\"" + default_image_path + "\"); }" + "QToolTip { background-image: url(); color: #000000; background-color: #ffffff; border: 0px; }"); } else return; diff --git a/src/aocharbutton.cpp b/src/aocharbutton.cpp index d571b95..6acad70 100644 --- a/src/aocharbutton.cpp +++ b/src/aocharbutton.cpp @@ -70,10 +70,14 @@ void AOCharButton::set_image(QString p_character) this->setText(""); if (file_exists(image_path)) - this->setStyleSheet("border-image:url(\"" + image_path + "\")"); + { + 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; }"); + } else { - this->setStyleSheet("border-image:url()"); + this->setStyleSheet("QPushButton { border-image: url(); }" + "QToolTip { background-image: url(); color: #000000; background-color: #ffffff; border: 0px; }"); this->setText(p_character); } } diff --git a/src/aoemotebutton.cpp b/src/aoemotebutton.cpp index 8d68712..e42bb73 100644 --- a/src/aoemotebutton.cpp +++ b/src/aoemotebutton.cpp @@ -2,13 +2,13 @@ #include "file_functions.h" -AOEmoteButton::AOEmoteButton(QWidget *p_parent, AOApplication *p_ao_app, int p_x, int p_y) : QPushButton(p_parent) +AOEmoteButton::AOEmoteButton(QWidget *p_parent, AOApplication *p_ao_app, int p_x, int p_y, int p_w, int p_h) : QPushButton(p_parent) { parent = p_parent; ao_app = p_ao_app; this->move(p_x, p_y); - this->resize(40, 40); + this->resize(p_w, p_h); connect(this, SIGNAL(clicked()), this, SLOT(on_clicked())); } @@ -17,15 +17,15 @@ void AOEmoteButton::set_image(QString p_image, QString p_emote_comment) { if (file_exists(p_image)) { - this->setIcon(QIcon(p_image)); - this->setIconSize(this->size()); - this->setStyleSheet("border:0px"); this->setText(""); + this->setStyleSheet("QPushButton { border-image: url(\"" + p_image + "\") 0 0 0 0 stretch stretch; }" + "QToolTip { color: #000000; background-color: #ffffff; border: 0px; }"); } else { this->setText(p_emote_comment); - this->setStyleSheet("border-image:url(\"\")"); + this->setStyleSheet("QPushButton { border-image: url(); }" + "QToolTip { background-image: url(); color: #000000; background-color: #ffffff; border: 0px; }"); } } diff --git a/src/aoevidencebutton.cpp b/src/aoevidencebutton.cpp index 871b477..61847f2 100644 --- a/src/aoevidencebutton.cpp +++ b/src/aoevidencebutton.cpp @@ -2,28 +2,27 @@ #include "file_functions.h" -AOEvidenceButton::AOEvidenceButton(QWidget *p_parent, AOApplication *p_ao_app, int p_x, int p_y) : QPushButton(p_parent) +AOEvidenceButton::AOEvidenceButton(QWidget *p_parent, AOApplication *p_ao_app, int p_x, int p_y, int p_w, int p_h) : QPushButton(p_parent) { ao_app = p_ao_app; m_parent = p_parent; - //HELLO AND WELCOME TO HARDCODE CENTRAL, MAY I TAKE YOUR FRESH ORDER OF PAIN AND SUFFERING ui_selected = new AOImage(this, ao_app); - ui_selected->resize(70, 70); + ui_selected->resize(p_w, p_h); // ui_selected->move(p_x, p_y); ui_selected->set_image("evidence_selected"); ui_selected->setAttribute(Qt::WA_TransparentForMouseEvents); ui_selected->hide(); ui_selector = new AOImage(this, ao_app); - ui_selector->resize(70, 70); + ui_selector->resize(p_w, p_h); // ui_selector->move(p_x - 1, p_y - 1); ui_selector->set_image("evidence_selector"); ui_selector->setAttribute(Qt::WA_TransparentForMouseEvents); ui_selector->hide(); this->move(p_x, p_y); - this->resize(70, 70); + this->resize(p_w, p_h); // this->setAcceptDrops(true); connect(this, SIGNAL(clicked()), this, SLOT(on_clicked())); @@ -32,24 +31,24 @@ AOEvidenceButton::AOEvidenceButton(QWidget *p_parent, AOApplication *p_ao_app, i void AOEvidenceButton::set_image(QString p_image) { QString image_path = ao_app->get_evidence_path(p_image); - qDebug() << image_path << p_image; if (file_exists(p_image)) { this->setText(""); - this->setIcon(QIcon(p_image)); + this->setStyleSheet("QPushButton { border-image: url(\"" + p_image + "\") 0 0 0 0 stretch stretch; }" + "QToolTip { color: #000000; background-color: #ffffff; border: 0px; }"); } else if (file_exists(image_path)) { this->setText(""); - this->setIcon(QIcon(image_path)); + this->setStyleSheet("QPushButton { border-image: url(\"" + image_path + "\") 0 0 0 0 stretch stretch; }" + "QToolTip { color: #000000; background-color: #ffffff; border: 0px; }"); } else { this->setText(p_image); - this->setIcon(QIcon()); + this->setStyleSheet("QPushButton { border-image: url(); }" + "QToolTip { background-image: url(); color: #000000; background-color: #ffffff; border: 0px; }"); } - this->setIconSize(this->size()); - this->setStyleSheet("border:0px"); } void AOEvidenceButton::set_theme_image(QString p_image) diff --git a/src/emotes.cpp b/src/emotes.cpp index a08043c..3e96824 100644 --- a/src/emotes.cpp +++ b/src/emotes.cpp @@ -52,7 +52,7 @@ void Courtroom::refresh_emotes() int x_pos = (button_width + x_spacing) * x_mod_count; int y_pos = (button_height + y_spacing) * y_mod_count; - AOEmoteButton *f_emote = new AOEmoteButton(ui_emotes, ao_app, x_pos, y_pos); + AOEmoteButton *f_emote = new AOEmoteButton(ui_emotes, ao_app, x_pos, y_pos, button_width, button_height); ui_emote_list.append(f_emote); diff --git a/src/evidence.cpp b/src/evidence.cpp index 727f4bf..b04a9d6 100644 --- a/src/evidence.cpp +++ b/src/evidence.cpp @@ -74,7 +74,7 @@ void Courtroom::refresh_evidence() int x_pos = (button_width + x_spacing) * x_mod_count; int y_pos = (button_height + y_spacing) * y_mod_count; - AOEvidenceButton *f_evidence = new AOEvidenceButton(ui_evidence_buttons, ao_app, x_pos, y_pos); + AOEvidenceButton *f_evidence = new AOEvidenceButton(ui_evidence_buttons, ao_app, x_pos, y_pos, button_width, button_height); ui_evidence_list.append(f_evidence); From 6dd0845f1c732e9c07afaaffb9163ba736a2ae25 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Fri, 20 Sep 2019 17:03:49 +0300 Subject: [PATCH 069/268] Better scaling algorithm for characters of variable size --- include/aocharmovie.h | 3 +++ src/aocharmovie.cpp | 23 ++++++++++++++++------- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/include/aocharmovie.h b/include/aocharmovie.h index adfa7b8..8aed1eb 100644 --- a/include/aocharmovie.h +++ b/include/aocharmovie.h @@ -73,6 +73,9 @@ private: // These are the X and Y values before they are fixed based on the sprite's width. int x = 0; int y = 0; + // These are the width and height values before they are fixed based on the sprite's width. + int f_w = 0; + int f_h = 0; int frame = 0; int max_frames = 0; diff --git a/src/aocharmovie.cpp b/src/aocharmovie.cpp index b795847..89d832d 100644 --- a/src/aocharmovie.cpp +++ b/src/aocharmovie.cpp @@ -232,14 +232,22 @@ QPixmap AOCharMovie::get_pixmap(QImage image) else f_pixmap = QPixmap::fromImage(image); auto aspect_ratio = Qt::KeepAspectRatio; + auto transform_mode = Qt::SmoothTransformation; - if (f_pixmap.size().width() > f_pixmap.size().height()) - aspect_ratio = Qt::KeepAspectRatioByExpanding; - - if (f_pixmap.size().width() > this->size().width() || f_pixmap.size().height() > this->size().height()) - f_pixmap = f_pixmap.scaled(this->width(), this->height(), aspect_ratio, Qt::SmoothTransformation); + if (f_pixmap.size().width() > this->size().width() && f_pixmap.size().height() <= this->size().height()) + { + f_pixmap = f_pixmap.scaledToHeight(this->height(), transform_mode); + } + else if (f_pixmap.size().height() > this->size().height()) + { + f_pixmap = f_pixmap.scaledToWidth(this->width(), transform_mode); + } else - f_pixmap = f_pixmap.scaled(this->width(), this->height(), aspect_ratio, Qt::FastTransformation); + { + f_pixmap = f_pixmap.scaled(this->width(), this->height(), aspect_ratio, transform_mode); + } + this->move((f_w - f_pixmap.width())/2, (f_h - f_pixmap.height())/2); + this->resize(f_pixmap.size()); return f_pixmap; } @@ -253,8 +261,9 @@ void AOCharMovie::set_frame(QPixmap f_pixmap) void AOCharMovie::combo_resize(int w, int h) { QSize f_size(w, h); + f_w = w; + f_h = h; this->resize(f_size); -// m_reader->setScaledSize(f_size); } int AOCharMovie::get_frame_delay(int delay) From 520c4f5947528d8c8b56fdc7e93428d06b77e50c Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Fri, 20 Sep 2019 17:04:44 +0300 Subject: [PATCH 070/268] *better-rer* character scaling algorithm --- src/aocharmovie.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/aocharmovie.cpp b/src/aocharmovie.cpp index 89d832d..d764d1a 100644 --- a/src/aocharmovie.cpp +++ b/src/aocharmovie.cpp @@ -234,19 +234,19 @@ QPixmap AOCharMovie::get_pixmap(QImage image) auto aspect_ratio = Qt::KeepAspectRatio; auto transform_mode = Qt::SmoothTransformation; - if (f_pixmap.size().width() > this->size().width() && f_pixmap.size().height() <= this->size().height()) + if (f_pixmap.size().width() > this->size().width() || f_pixmap.size().height() > this->size().height()) { f_pixmap = f_pixmap.scaledToHeight(this->height(), transform_mode); } - else if (f_pixmap.size().height() > this->size().height()) - { - f_pixmap = f_pixmap.scaledToWidth(this->width(), transform_mode); - } +// else if (f_pixmap.size().height() > this->size().height()) +// { +// f_pixmap = f_pixmap.scaledToWidth(this->width(), transform_mode); +// } else { f_pixmap = f_pixmap.scaled(this->width(), this->height(), aspect_ratio, transform_mode); } - this->move((f_w - f_pixmap.width())/2, (f_h - f_pixmap.height())/2); + this->move((f_w - f_pixmap.width())/2, (f_pixmap.height() - f_h)); //Always center horizontally, always put at the bottom vertically this->resize(f_pixmap.size()); return f_pixmap; From 3fd93ab34118cfb5041b1be77e50e14658627a82 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Fri, 20 Sep 2019 17:26:41 +0300 Subject: [PATCH 071/268] Make ui_additive_button insert a whitespace character at the start of the message when you use it (to make it so by default, the added message will have that space, but you can safely remove it if you need to) Support for aomovie to check inside the character folder for relevant stuff if p_char is provided --- src/aomovie.cpp | 19 +++++++------------ src/courtroom.cpp | 2 ++ 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/aomovie.cpp b/src/aomovie.cpp index fff8014..561f5ef 100644 --- a/src/aomovie.cpp +++ b/src/aomovie.cpp @@ -35,20 +35,15 @@ void AOMovie::play(QString p_image, QString p_char, QString p_custom_theme, int QList pathlist; pathlist = { - ao_app->get_image_suffix(ao_app->get_base_path() + "misc/" + p_custom_theme + "/" + p_image + "_bubble"), //Misc path - ao_app->get_image_suffix(ao_app->get_custom_theme_path(p_custom_theme, p_image)), //Custom theme path - ao_app->get_image_suffix(ao_app->get_theme_path(p_image)), //Theme path - ao_app->get_image_suffix(ao_app->get_default_theme_path(p_image)), //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 + ao_app->get_image_suffix(ao_app->get_character_path(p_char, p_image)), //Character folder + ao_app->get_image_suffix(ao_app->get_base_path() + "misc/" + p_custom_theme + "/" + p_image), //Misc path + ao_app->get_image_suffix(ao_app->get_custom_theme_path(p_custom_theme, p_image)), //Custom theme path + ao_app->get_image_suffix(ao_app->get_theme_path(p_image)), //Theme path + ao_app->get_image_suffix(ao_app->get_default_theme_path(p_image)), //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 }; - //Add this at the beginning of the list - order matters. - if (p_image == "custom") - pathlist.prepend(ao_app->get_image_suffix(ao_app->get_character_path(p_char, p_image))); - else - pathlist.prepend(ao_app->get_image_suffix(ao_app->get_character_path(p_char, p_image + "_bubble"))); - for (QString path : pathlist) { if (file_exists(path)) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 4291468..1797706 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1508,6 +1508,8 @@ void Courtroom::handle_chatmessage(QStringList *p_contents) if (m_chatmessage[MESSAGE] == ui_ic_chat_message->text() && m_chatmessage[CHAR_ID].toInt() == m_cid) { ui_ic_chat_message->clear(); + if (ui_additive->isChecked()) + ui_ic_chat_message->insert(" "); objection_state = 0; realization_state = 0; screenshake_state = 0; From 497901e8c361326770e88e8a01daa7891b6a16e1 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Fri, 20 Sep 2019 22:08:36 +0300 Subject: [PATCH 072/268] Allow realizationflash, prosecution_speedlines and defense_speedlines to be changed in a similar way shouts can be changed from the character, as well as misc folder, etc. Same for chat indicator Rename themes/ name of shouts from "objection.gif" to "objection_bubble.gif" naming convention for consistency Reorganize the default theme a bit as well as to support new elements Fix the background size not being updated properly due to bad order of reload theme Set up proper tooltips for sfx dropdown, iniswap dropdown, custom objection --- base/themes/default/chat.png | Bin 1529 -> 590 bytes base/themes/default/chatbig.png | Bin 80093 -> 584 bytes base/themes/default/chatmed.png | Bin 1669 -> 579 bytes base/themes/default/courtroom_design.ini | 194 +++++++++++++------- base/themes/default/courtroom_fonts.ini | 57 +++++- base/themes/default/courtroombackground.png | Bin 63046 -> 50139 bytes base/themes/default/holdit.gif | Bin 40518 -> 0 bytes base/themes/default/muted_old.png | Bin 5703 -> 0 bytes base/themes/default/objection.gif | Bin 44417 -> 0 bytes base/themes/default/takethat.gif | Bin 42063 -> 0 bytes src/courtroom.cpp | 40 ++-- 11 files changed, 202 insertions(+), 89 deletions(-) delete mode 100644 base/themes/default/holdit.gif delete mode 100644 base/themes/default/muted_old.png delete mode 100644 base/themes/default/objection.gif delete mode 100644 base/themes/default/takethat.gif diff --git a/base/themes/default/chat.png b/base/themes/default/chat.png index e11f8c8aaaa1b2c283b93acb5680737e8bf7eeec..47281a9618763259f1c1f312b66513a153b08e15 100644 GIT binary patch literal 590 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5GC0_Pq}(FCr$CCaILO_JVcj{Imp~3nx}&cn z1H;CC?mvmFKt5-IM`SSr1K&XqX529``z=tzV^0^ykczmsw+zc>JBT<0PIRr}zSk7X zICXDpj^b<;M#a8pZM~Lzd(WPcl$!OQYsSM*=Qruhe_dsE*kI4w=m&gbP0l+XkK#M!IF literal 1529 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 aS$6Bo)$!*aJ#v`9OzxW6`R;8GANUWu6Dm9a diff --git a/base/themes/default/chatmed.png b/base/themes/default/chatmed.png index d2fee4a6879146c729412059498912857e633b83..9c6f87fcf23e378ee13fabe2201cb3bd3456766a 100644 GIT binary patch literal 579 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5GC0_Pq}(FCr$CCaILO_JVcj{Imp~3nx}&cn z1H;CC?mvmFKt5-IM`SSr1K&XqX529``z=tz4Nn)xkczmsw-4qvJBTYryJM(G2=P>cW0}&RNra)^PkHO+*pSVav>Lr*BBLJ*)02Z}690P!c z1Q6o@0POPtSR36FNVp0B!oZ#Cd@!L;^@X!-V4Mn zMtM=u)t-)}XPercfjo@&#)`kA)fuZ;WTCp^hS!` zi?rZ1hMk+06N|z}WFTJ}NCJU8p*mbJbbnW@7UJzXhH$u$}UCbJkP7B=GFIZkI_#X7CJi^ zj<71jAsWI|R-5xc`Lxh)B$KDv>Ln2Rx_isR$#^ST;%()roR8(&y)jI9eGp-~aZS5C z9Y?_5a4M#d=QjOrSOdSQw~5%`yWkIb#IAba?1ZjlaMOh)@)3)Hu8!>d)y}BQ=>^UQ z#qjz3J*V{E#nwOg(2}Wze5!gfBTwiHy)AF+3Ja~SdbodusBN0^h09HmJ;}c|%Kx6= zZyOJ5L5MX|aDfqAtlUEE{vKdv*_uJ8L&1kX{CuIlxzq8&^M>+>to3UuA9lKrFDKV0 z7Q%#H0igV(R9=QCoIkLT+;p;Q@hjOwyO(LTE~m#;h7dWh?lGoJ4ovKaY~Tp|_6 z#UAQAZ{4lpw$43{wiTRk*v&{9)5t{u6?JbiKI`Z5`2bwPN@jM#S|oT1`@+HErZ*en zt8){h`V`cqCO-5ke-!``ub>RGHWBP|`(UABuI&N)$ipQG32I*JaWo26R3mA^A4l6t z5H90zYf7f?(dEs(IX3$J!wZB!{N-0&R^UlHsz~{_|7ACv@xa7z3GBSh=8S?9*UEYQ zokrwhKg`f1Bp^w-(ednGy;Bob>czwAS}Dw5VE6+2^vLOLtrLdka0Q*^(hPse-kVy` zEM&YejKPfggshrcS&n2vnHmiFKznc2PTNqAK@Wa1?*8KvjMjDv-9dVK8%i#=0iNC| zf77!P=vLekO$d2_iz<`ZtNMRh3xC&T=OD+63n$}A&CKx)adC>A@e;L24EiFOMfYbJ zV(_d-not^QO&iS*LbLpok{q89bb@7;Y94aTckA0h-pmOL#?va}mnmCzE5G|wqe}M5 zvyb7G`GM#27{;iQ_9{FoeUSZY-QjEggi6{jW|WK;hVTnkj0M*ud`f$bBODG5O+6hR z9$sW=H--I!;fl&w+IU5lrfU63)O^?8pAMpP_TCrBC+5~wyt$i6-m? zQXq-5VM$a7vcQ(6$7!833j3X})1DCf^M#b7%pP!02azS9dr_RkkxW9#)JPk!*E|_c zry8?3ts$UHAh_f0%V|9htgWqQWky7j2}r!XN=E`=|C;6lI2>Jr|61h#D;a^Hl`;#W z@5%jy_R=iea2~eaMFzQ5({0(*U;AD?-}9D1>^5sm;PqAVcpJs%7N?i%N}^113rr8z&GgBgI=$piCAJRfVfT~Ajaldk(?u7t%S5N9AN?6)I%^vir diff --git a/base/themes/default/courtroom_design.ini b/base/themes/default/courtroom_design.ini index eee7625..e53eb08 100644 --- a/base/themes/default/courtroom_design.ini +++ b/base/themes/default/courtroom_design.ini @@ -2,35 +2,14 @@ ; compress courtroombackground.png accordingly. courtroom = 0, 0, 714, 668 +; **COORDINATE SYSTEM RELATIVE TO "courtroom"** +; x/y coordinates 0,0 will start at top-left of the "courtroom" for everything below until specified otherwise. +; **** + ; IC Area. Changing 256, 192 will stretch or compress character gifs and the ; /bgs being used accordingly viewport = 0, 0, 256, 192 -; IC chatbox -chatbox = 0, 174, 256, 108 - -; IC chatbox if the current background's folder contains stand.png, -; defensedesk.png and prosecutiondesk.png -ao2_chatbox = 0, 174, 256, 108 - -; Textbox for custom IC name (the "showname") -showname = 6, 1, 256, 15 - -; IC message, positioned within the chatbox. Changing 250 affects how -; long text goes on before going onto the next line. Changing 89 affects -; how many lines you can see before the message starts scrolling, based on -; the formula of n = 25+(n-1)*16, where n is the number of lines to be -; displayed. (ie, set it to 25 for 1 line, 41 for 2, 57 for 3, 73 for 4, -; 89 for 5, 105 for 6... Less than 25 displays nothing) -message = 3, 18, 250, 89 - -; Where you type to make an IC chat message -ic_chat_message = 2, 283, 250, 23 - -; IC chat message if the current background's folder contains stand.png, -; defensedesk.png and prosecutiondesk.png -ao2_ic_chat_message = 2, 283, 250, 23 - ; IC chatlog ic_chatlog = 260, 0, 231, 319 @@ -50,14 +29,20 @@ ooc_chat_name = 492, 300, 85, 19 ; Toggle between Server and Master OOC chats ooc_toggle = 580, 300, 133, 19 +; The scrolling music name display +music_display = 490, 0, 224, 26 +; WARNING: music_name x/y coordinates relative to music_display! +music_name = 0, 0, 224, 26 + ; Where the jukebox is music_list = 490, 342, 224, 326 ; Jukebox search bar music_search = 490, 319, 100, 23 -found_song_color = 100, 255, 100 -missing_song_color = 255, 100, 100 +; Music list state colors +found_song_color = 144, 238, 144 +missing_song_color = 255, 125, 125 ; Labels and sliders for music/sfx/blips music_label = 282, 607, 41, 16 @@ -74,6 +59,7 @@ blip_slider = 326, 648, 140, 16 ; 49X, 49Y (ie. 490, 147 if you want 10 columns and 3 rows) emotes = 5, 342, 490, 98 emote_button_spacing = 9, 9 +emote_button_size = 40, 40 ; Page togglers for emotes emote_left = 5, 434, 60, 32 @@ -83,6 +69,22 @@ emote_right = 428, 434, 60, 32 ; display the full emote name or truncate it based on length emote_dropdown = 5, 470, 105, 20 +; Display the accessible iniswaps on this character (grabbed from iniswaps.ini) +iniswap_dropdown = 100, 442, 89, 20 +; The button to remove the current iniswap +iniswap_remove = 78, 442, 20, 20 + +; Display the accessible sfx on this character (grabbed from soundlist.ini). If none found, courtroom_soundlist.ini will be used. +sfx_dropdown = 220, 442, 89, 20 +; The button to remove the current iniswap +sfx_remove = 198, 442, 20, 20 + +; Display the list of overlay effects accessible +effects_dropdown = 330, 441, 89, 22 + +; The size of the icons for dropdown entries +effects_icon_size = 16, 16 + ; Hold it/Take That/Objection and the "BLING!" buttons hold_it = 10, 310, 76, 28 objection = 90, 310, 76, 28 @@ -93,7 +95,7 @@ realization = 5, 515, 42, 42 ; custom.gif and custom.wav in their folder, this button acts as another ; Objection/Take That/Hold It for that character that uses the custom animation ; and sfx. (Think Satorah! Such Insolence!, Gotcha!) -custom_objection = 340, 565, 76, 28 +custom_objection = 250, 310, 76, 28 ; Text color dropdown menu text_color = 115, 470, 80, 20 @@ -104,7 +106,10 @@ pos_dropdown = 200, 470, 80, 20 pre = 5, 490, 80, 21 ; Flip button -flip = 104, 490, 51, 21 +flip = 64, 490, 51, 21 + +; Additive button +Additive = 114, 490, 80, 21 ; Guard button guard = 200, 580, 61, 21 @@ -132,33 +137,12 @@ call_mod = 104, 637, 64, 23 ; Mute button mute_button = 150, 515, 42, 42 +; Screenshake +screenshake = 51, 515, 42, 42 + ; Where the Mute list pops up when you click Mute mute_list = 280, 469, 210, 198 -; ???? - if there was an Area button, where the area list would show up? -; area_list = 270, 494, 224, 174 - -; ???? - where a password box appears if an area is password locked? -; area_password = 266, 471, 224, 23 - -; >Evidence meme -evidence_button = 627, 322, 85, 18 -evidence_background = 0, 385, 490, 284 -evidence_name = 112, 4, 264, 19 -evidence_buttons = 28, 27, 430, 216 -evidence_button_spacing = 2, 3 -evidence_overlay = 24, 24, 439, 222 -evidence_delete = 78, 8, 70, 20 -evidence_image_name = 150, 8, 130, 20 -evidence_image_button = 280, 8, 60, 20 -evidence_x = 341, 8, 20, 20 -evidence_description = 78, 28, 281, 166 -evidence_left = 28, 0, 60, 24 -evidence_right = 400, 0, 60, 24 -evidence_present = 165, 247, 158, 41 -left_evidence_icon = 13, 13, 70, 70 -right_evidence_icon = 173, 13, 70, 70 - ; Character select widgets char_select = 0, 0, 714, 668 back_to_lobby = 5, 5, 91, 23 @@ -173,15 +157,6 @@ spectator = 317, 640, 80, 23 ; New in 2.6.0 ; ------------------------- -; The log limiter explaining label. This is simply a piece of text that -; explains what the spin box is for. -; log_limit_label = 190, 612, 50, 30 - -; The spinbox allows you to set the log limit ingame inbetween 1 and 10000, -; with the option to set it to 0 as well (which is considered 'infinite' by -; the log limiter). -; log_limit_spinbox = 168, 636, 70, 25 - ; This is an input field that allows you to change your in-character showname. ic_chat_name = 200, 534, 78, 23 @@ -228,12 +203,12 @@ pair_offset_spinbox = 280, 470, 210, 20 switch_area_music = 590, 319, 35, 23 ; These are colours for the various statuses an area can be in. -area_free_color = 54, 198, 68 -area_lfp_color = 255, 255, 0 -area_casing_color = 255, 166, 0 -area_recess_color = 255, 190, 30 -area_rp_color = 200, 52, 252 -area_gaming_color = 55, 255, 255 +area_free_color = 144, 238, 144 +area_lfp_color = 127, 255, 0 +area_casing_color = 255, 215, 0 +area_recess_color = 255, 246, 143 +area_rp_color = 135, 206, 255 +area_gaming_color = 171, 130, 255 area_locked_color = 165, 43, 43 ; These two are casing-related inputs. @@ -242,4 +217,85 @@ area_locked_color = 165, 43, 43 ; "casing_button" is an interface to help you announce a case (you have to be ; a CM first to be able to announce cases). casing = 200, 560, 80, 21 -casing_button = 173, 637, 60, 23 \ No newline at end of file +casing_button = 173, 637, 60, 23 + +; +; Chat system +; + +; IC chatbox +chatbox = 0, 178, 256, 104 + +; IC chatbox if the current background's folder contains stand.png, +; defensedesk.png and prosecutiondesk.png +ao2_chatbox = 0, 178, 256, 104 + +; **COORDINATE SYSTEM RELATIVE TO "chatbox"/"ao2_chatbox"** +; x/y coordinates 0,0 will start at top-left of the "chatbox"/"ao2_chatbox" for everything below until specified otherwise. +; **** + +; Textbox for custom IC name (the "showname"), width is the smallest size +showname = 1, 0, 46, 15 + +; The chatbox image used for smallest possible size is "chat". "chatblank" is used if the showname is whitespace-only. +; "chatmed" will be used if the showname size exceeds the width, at which point the showname will receive showname_extra_width. +; "chatbig" will be used if the showname size exceeds the "chatmed" width, at which point the showname will receive showname_extra_width again. +; Text any bigger than that will be cut off. If "chatmed" or "chatbig" are missing, showname will not be resized. +showname_extra_width = 24 + +; IC message, positioned within the chatbox. Changing 250 affects how +; long text goes on before going onto the next line. Changing 89 affects +; how many lines you can see before the message starts scrolling, based on +; Every line height is 25 if the font size is 10 and the Sans font is used. +; There's 4 pixels from X position until the symbol is displayed. +; the formula of n = 25+(n-1)*16, where n is the number of lines to be +; displayed. (ie, set it to 25 for 1 line, 41 for 2, 57 for 3, 73 for 4, +; 89 for 5, 105 for 6... Less than 25 displays nothing) +message = 10, 12, 242, 89 + +; A chat indicator alerting us the chat ticker isn't active (text is no longer being processed). +chat_arrow = 245, 84, 11, 9 + +; Where you type to make an IC chat message +ic_chat_message = 2, 283, 250, 23 + +; IC chat message if the current background's folder contains stand.png, +; defensedesk.png and prosecutiondesk.png +ao2_ic_chat_message = 2, 283, 250, 23 + +; +; Evidence system +; + +; **COORDINATE SYSTEM RELATIVE TO "viewport"** +; x/y coordinates 0,0 will start at top-left of the "viewport" for everything below until specified otherwise. +; **** +left_evidence_icon = 13, 13, 70, 70 +right_evidence_icon = 173, 13, 70, 70 + +; **COORDINATE SYSTEM RELATIVE TO "courtroom"** +; x/y coordinates 0,0 will start at top-left of the "courtroom" for everything below until specified otherwise. +; **** + +evidence_background = 0, 385, 490, 284 +; **COORDINATE SYSTEM RELATIVE TO "evidence_background"** +; x/y coordinates 0,0 will start at top-left of the "evidence_background" for everything below until specified otherwise. +; **** +evidence_buttons = 28, 27, 430, 216 +evidence_button_spacing = 2, 3 +evidence_button_size = 70, 70 +evidence_left = 28, 0, 60, 24 +evidence_right = 400, 0, 60, 24 +evidence_present = 165, 247, 158, 41 + +evidence_overlay = 24, 24, 439, 222 +; **COORDINATE SYSTEM RELATIVE TO "evidence_overlay"** +; x/y coordinates 0,0 will start at top-left of the "evidence_overlay" (which is parented to "evidence_background") for everything below until specified otherwise. +; **** +evidence_delete = 78, 8, 70, 20 +evidence_image_name = 150, 8, 130, 20 +evidence_image_button = 280, 8, 60, 20 +evidence_x = 341, 8, 20, 20 +evidence_button = 627, 322, 85, 18 +evidence_name = 112, 4, 264, 19 +evidence_description = 78, 28, 281, 166 \ No newline at end of file diff --git a/base/themes/default/courtroom_fonts.ini b/base/themes/default/courtroom_fonts.ini index 16e2f41..1fcba76 100644 --- a/base/themes/default/courtroom_fonts.ini +++ b/base/themes/default/courtroom_fonts.ini @@ -1,11 +1,56 @@ showname = 8 +showname_font = Sans +showname_color = 255, 255, 255 +showname_bold = 0 + message = 10 +message_font = Sans +message_color = 0, 0, 0 +message_bold = 0 + ic_chatlog = 10 -ms_chatlog = 10 -server_chatlog = 9 -music_list = 8 - +ic_chatlog_font = Sans ic_chatlog_color = 255, 255, 255 +ic_chatlog_bold = 0 -; Color for all labels and checkboxes -label_color = 255, 255, 255 +ms_chatlog = 8 +ms_chatlog_font = Sans +ms_chatlog_color = 0, 0, 0 +ms_chatlog_sender_color = 0, 0, 95 +ms_chatlog_bold = 0 + +server_chatlog = 8 +server_chatlog_font = Sans +server_chatlog_color = 0, 0, 0 +server_chatlog_sender_color = 95, 95, 0 +server_chatlog_bold = 0 + +music_list = 8 +music_list_font = Sans +music_list_color = 0, 0, 0 +music_list_bold = 0 + +music_name = 8 +music_name_font = Sans +music_name_color = 255, 255, 255 +music_name_bold = 0 + +area_list = 8 +area_list_font = Sans +area_list_color = 0, 0, 0 +area_list_bold = 0 + +evidence_name = 14 +evidence_name_font = Arial +evidence_name_color = 255, 128, 0 +evidence_name_bold = 1 + +evidence_image_name = 8 +evidence_image_name_font = Arial +evidence_image_name_color = 0, 0, 0 +evidence_image_name_bold = 0 + +evidence_description = 10 +evidence_description_font = Times New Roman +evidence_description_color = 255, 255, 255 +evidence_description_bold = 0 \ No newline at end of file diff --git a/base/themes/default/courtroombackground.png b/base/themes/default/courtroombackground.png index 5ad8d51aadaf2c1f03f720a839a0b137fc8c7385..f42797ca3a64f637994210d29b52b62c6aebc451 100644 GIT binary patch literal 50139 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 CP6M<6 literal 63046 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 Bgy;YO diff --git a/base/themes/default/holdit.gif b/base/themes/default/holdit.gif deleted file mode 100644 index 5f71ac66124c00ef6db1099d294ab0348a5f2dd4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 40518 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 JQUk%8{y$9L-@^a^ diff --git a/base/themes/default/objection.gif b/base/themes/default/objection.gif deleted file mode 100644 index 6aae2e5616779799e26fd164cbb9936ea1b693ea..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 44417 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 S9ZIyQ(W6L{DqU(S0suS3L(6FZ diff --git a/base/themes/default/takethat.gif b/base/themes/default/takethat.gif deleted file mode 100644 index dd0331022cdb819fba32fd9e2f526f19cb41f7ad..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 42063 zcmaI7by!@@vgkdyySux)LvVL@cXubaySvNa?h@SH-4b9RcyLI#dG|T{-0ypyyHEc! zt9z=dt83NjXXdx6rDdgf`Ah*|gMd~f02&&as;X*6M#f@9L?;Bq!omUw1bRgy1ONbr zs;Vgfh|j<6Z|C2Q>=QvrQbS!_R7H}VnH2);@A% YqyV2~!W#zn_94J}#!__Ld%` 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 alg;Jx`9i@6L^3TEi^WpO_7PxUeE$c+-ULMe diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 1797706..d58353f 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -579,6 +579,8 @@ void Courtroom::set_widgets() set_size_and_pos(ui_music_search, "music_search"); set_size_and_pos(ui_emote_dropdown, "emote_dropdown"); + ui_pos_dropdown->setToolTip(tr("Set your character's emote to play on your next message.")); + set_size_and_pos(ui_pos_dropdown, "pos_dropdown"); ui_pos_dropdown->setToolTip(tr("Set your character's supplementary background.")); @@ -586,7 +588,7 @@ void Courtroom::set_widgets() ui_iniswap_dropdown->setEditable(true); ui_iniswap_dropdown->setInsertPolicy(QComboBox::InsertAtBottom); ui_iniswap_dropdown->setToolTip(tr("Set an 'iniswap', or an alternative character folder to refer to from your current character.\n" - "This information is saved to your base/characters//iniswaps.ini")); + "Edit by typing and pressing Enter, [X] to remove. This saves to your base/characters//iniswaps.ini")); set_size_and_pos(ui_iniswap_remove, "iniswap_remove"); ui_iniswap_remove->setText("X"); @@ -596,8 +598,8 @@ void Courtroom::set_widgets() set_size_and_pos(ui_sfx_dropdown, "sfx_dropdown"); ui_sfx_dropdown->setEditable(true); ui_sfx_dropdown->setInsertPolicy(QComboBox::InsertAtBottom); - ui_sfx_dropdown->setToolTip(tr("Set an 'iniswap', or an alternative character folder to refer to from your current character.\n" - "This information is saved to your base/characters//iniswaps.ini")); + ui_sfx_dropdown->setToolTip(tr("Set a sound effect to play on your next 'Preanim'. Leaving it on Default will use the emote-defined sound (if any).\n" + "Edit by typing and pressing Enter, [X] to remove. This saves to your base/characters//sounds.ini")); set_size_and_pos(ui_sfx_remove, "sfx_remove"); ui_sfx_remove->setText("X"); @@ -606,7 +608,9 @@ void Courtroom::set_widgets() set_size_and_pos(ui_effects_dropdown, "effects_dropdown"); ui_effects_dropdown->setInsertPolicy(QComboBox::InsertAtBottom); - ui_effects_dropdown->setToolTip(tr("Choose an effect to play on your next spoken message.")); + ui_effects_dropdown->setToolTip(tr("Choose an effect to play on your next spoken message.\n" + "The effects are defined in your theme/effects/effects.ini. Your character can define custom effects by\n" + "char.ini [Options] category, effects = 'miscname' where it referes to misc//effects.ini to read the effects.")); //Todo: recode this entire fucking system with these dumbass goddamn ini's why is everything so specifically coded for all these purposes //is ABSTRACT CODING not a thing now huh what the FUCK why do I gotta do this pleASE FOR THE LOVE OF GOD SPARE ME FROM THIS FRESH HELL //btw i still love coding. @@ -716,7 +720,8 @@ void Courtroom::set_widgets() set_size_and_pos(ui_custom_objection, "custom_objection"); ui_custom_objection->setText(tr("Custom Shout!")); ui_custom_objection->set_image("custom"); - ui_custom_objection->setToolTip(tr("This will display the custom character-defined animation in the viewport as soon as it is pressed.")); + ui_custom_objection->setToolTip(tr("This will display the custom character-defined animation in the viewport as soon as it is pressed.\n" + "To make one, your character's folder must contain custom.[webp/apng/gif/png] and custom.wav")); set_size_and_pos(ui_realization, "realization"); ui_realization->set_image("realization"); @@ -1551,17 +1556,17 @@ void Courtroom::handle_chatmessage(QStringList *p_contents) switch (objection_mod) { case 1: - ui_vp_objection->play("holdit", f_char, f_custom_theme, 724); + ui_vp_objection->play("holdit_bubble", f_char, f_custom_theme, 724); objection_player->play("holdit.wav", f_char, f_custom_theme); break; case 2: - ui_vp_objection->play("objection", f_char, f_custom_theme, 724); + ui_vp_objection->play("objection_bubble", f_char, f_custom_theme, 724); objection_player->play("objection.wav", f_char, f_custom_theme); if(ao_app->objection_stop_music()) music_player->stop(); break; case 3: - ui_vp_objection->play("takethat", f_char, f_custom_theme, 724); + ui_vp_objection->play("takethat_bubble", f_char, f_custom_theme, 724); objection_player->play("takethat.wav", f_char, f_custom_theme); break; //case 4 is AO2 only @@ -1893,7 +1898,9 @@ void Courtroom::do_flash() if(!ao_app->is_shake_flash_enabled()) return; - ui_vp_effect->play("realizationflash", "", "", 60); + QString f_char = m_chatmessage[CHAR_NAME]; + QString f_custom_theme = ao_app->get_char_shouts(f_char); + ui_vp_effect->play("realizationflash", f_char, f_custom_theme, 60); } void Courtroom::do_effect(QString fx_name, QString fx_sound, QString p_char) @@ -1948,12 +1955,14 @@ void Courtroom::handle_chatmessage_3() ui_vp_sideplayer_char->hide(); ui_vp_player_char->move(0,0); + QString f_char = m_chatmessage[CHAR_NAME]; + QString f_custom_theme = ao_app->get_char_shouts(f_char); if (side == "pro" || side == "hlp" || side == "wit") - ui_vp_speedlines->play("prosecution_speedlines"); + ui_vp_speedlines->play("prosecution_speedlines", f_char, f_custom_theme); else - ui_vp_speedlines->play("defense_speedlines"); + ui_vp_speedlines->play("defense_speedlines", f_char, f_custom_theme); } @@ -2412,7 +2421,9 @@ void Courtroom::chat_tick() anim_state = 3; ui_vp_player_char->play_idle(m_chatmessage[CHAR_NAME], m_chatmessage[EMOTE]); } - ui_vp_chat_arrow->play("chat_arrow"); //Chat stopped being processed, indicate that. + QString f_char = m_chatmessage[CHAR_NAME]; + QString f_custom_theme = ao_app->get_char_shouts(f_char); + ui_vp_chat_arrow->play("chat_arrow", f_char, f_custom_theme); //Chat stopped being processed, indicate that. } else @@ -3988,13 +3999,14 @@ void Courtroom::on_reload_theme_clicked() { ao_app->reload_theme(); - //to update status on the background - set_background(current_background); enter_courtroom(); update_character(m_cid); anim_state = 4; text_state = 3; + + //to update status on the background + set_background(current_background); } void Courtroom::on_back_to_lobby_clicked() From 842b829bee8b840149c0042bb7adfc3bda6eec9d Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Fri, 20 Sep 2019 22:11:37 +0300 Subject: [PATCH 073/268] Tweak the ambience/crosfade layer to fade in regardless of another sample being there Fix music not being looped sometimes Prevent channel less than 0 from being passed Set up a new music display element with an attached music name, it displays a scrolling text of the currently playing music Fix music packet processing issues Make SFX slider responsible for all music channels besides 0 (actual music) scrolltext.cpp code recipe was taken from https://stackoverflow.com/questions/10651514/text-scrolling-marquee-in-qlabel - thanks to leemes for that one, I only adapted it for newer C++ version and tweaked some stuff. --- include/aomusicplayer.h | 12 ++-- include/courtroom.h | 4 ++ include/scrolltext.h | 50 +++++++++++++++ src/aomusicplayer.cpp | 38 +++++++++--- src/courtroom.cpp | 73 ++++++++++++++++------ src/scrolltext.cpp | 134 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 277 insertions(+), 34 deletions(-) create mode 100644 include/scrolltext.h create mode 100644 src/scrolltext.cpp diff --git a/include/aomusicplayer.h b/include/aomusicplayer.h index 8ed0771..8e0d239 100644 --- a/include/aomusicplayer.h +++ b/include/aomusicplayer.h @@ -19,16 +19,19 @@ class AOMusicPlayer public: AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app); virtual ~AOMusicPlayer(); - - void play(QString p_song, int channel=0, bool crossfade=false); - void stop(int channel=0); - void set_volume(int p_value, int channel=0); + void set_volume(int p_value, int channel=-1); void set_looping(bool toggle, int channel=0); + const int m_channelmax = 4; + //These have to be public for the stupid sync thing // QWORD loop_start = 0; // QWORD loop_end = 0; +public slots: + void play(QString p_song, int channel=0, bool crossfade=false); + void stop(int channel=0); + private: QWidget *m_parent; AOApplication *ao_app; @@ -36,7 +39,6 @@ private: bool m_looping = false; int m_volume = 0; - const int m_channelmax = 4; // Channel 0 = music // Channel 1 = ambience // Channel 2 = extra diff --git a/include/courtroom.h b/include/courtroom.h index d02c756..465b8ce 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -26,6 +26,7 @@ #include "datatypes.h" #include "debug_functions.h" #include "chatlogpiece.h" +#include "scrolltext.h" #include #include @@ -445,6 +446,9 @@ private: QListWidget *ui_area_list; QListWidget *ui_music_list; + ScrollText *ui_music_name; + AOMovie *ui_music_display; + AOButton *ui_pair_button; QListWidget *ui_pair_list; QSpinBox *ui_pair_offset_spinbox; diff --git a/include/scrolltext.h b/include/scrolltext.h new file mode 100644 index 0000000..cf791c0 --- /dev/null +++ b/include/scrolltext.h @@ -0,0 +1,50 @@ +#ifndef SCROLLTEXT_H +#define SCROLLTEXT_H + +#include +#include +#include +#include +#include + + +class ScrollText : public QWidget +{ + Q_OBJECT + Q_PROPERTY(QString text READ text WRITE setText) + Q_PROPERTY(QString separator READ separator WRITE setSeparator) + +public: + explicit ScrollText(QWidget *parent = nullptr); + +public slots: + QString text() const; + void setText(QString text); + + QString separator() const; + void setSeparator(QString separator); + + +protected: + virtual void paintEvent(QPaintEvent *); + virtual void resizeEvent(QResizeEvent *); + +private: + void updateText(); + QString _text; + QString _separator; + QStaticText staticText; + int singleTextWidth; + QSize wholeTextSize; + int leftMargin; + bool scrollEnabled; + int scrollPos; + QImage alphaChannel; + QImage buffer; + QTimer timer; + +private slots: + virtual void timer_timeout(); +}; + +#endif // SCROLLTEXT_H diff --git a/src/aomusicplayer.cpp b/src/aomusicplayer.cpp index f6bcb17..c845948 100644 --- a/src/aomusicplayer.cpp +++ b/src/aomusicplayer.cpp @@ -18,6 +18,8 @@ AOMusicPlayer::~AOMusicPlayer() void AOMusicPlayer::play(QString p_song, int channel, bool crossfade) { channel = channel % m_channelmax; + if (channel < 0) //wtf? + return; QString f_path = ao_app->get_music_path(p_song); // QString d_path = f_path + ".txt"; @@ -39,27 +41,33 @@ void AOMusicPlayer::play(QString p_song, int channel, bool crossfade) // } unsigned int flags = BASS_STREAM_PRESCAN | BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE; + if (m_looping) + flags |= BASS_SAMPLE_LOOP; DWORD newstream = BASS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, flags); if (ao_app->get_audio_output_device() != "default") BASS_ChannelSetDevice(m_stream_list[channel], BASS_GetDevice()); - if (BASS_ChannelIsActive(m_stream_list[channel]) == BASS_ACTIVE_PLAYING && crossfade) + if (crossfade) { DWORD oldstream = m_stream_list[channel]; - - //Fade out the other sample and stop it - BASS_ChannelSlideAttribute(oldstream, BASS_ATTRIB_VOL|BASS_SLIDE_LOG, -1, 5000); - BASS_ChannelLock(oldstream, true); //Mute the new sample BASS_ChannelSetAttribute(newstream, BASS_ATTRIB_VOL, 0); - //Sync it with the new sample - BASS_ChannelSetPosition(newstream, BASS_ChannelGetPosition(oldstream, BASS_POS_BYTE), BASS_POS_BYTE); + //Crossfade time + if (BASS_ChannelIsActive(oldstream) == BASS_ACTIVE_PLAYING) + { + //Fade out the other sample and stop it + BASS_ChannelSlideAttribute(oldstream, BASS_ATTRIB_VOL|BASS_SLIDE_LOG, -1, 5000); + BASS_ChannelLock(oldstream, true); + //Sync it with the new sample + BASS_ChannelSetPosition(newstream, BASS_ChannelGetPosition(oldstream, BASS_POS_BYTE), BASS_POS_BYTE); + BASS_ChannelLock(oldstream, false); + } //Start it BASS_ChannelPlay(newstream, false); //Fade in our sample BASS_ChannelSlideAttribute(newstream, BASS_ATTRIB_VOL, static_cast(m_volume / 100.0f), 1000); - BASS_ChannelLock(oldstream, false); + m_stream_list[channel] = newstream; } else @@ -67,7 +75,7 @@ void AOMusicPlayer::play(QString p_song, int channel, bool crossfade) BASS_ChannelStop(m_stream_list[channel]); m_stream_list[channel] = newstream; BASS_ChannelPlay(m_stream_list[channel], false); - this->set_volume(m_volume); + this->set_volume(m_volume, channel); } this->set_looping(m_looping); //Have to do this here due to any crossfading-related changes, etc. @@ -82,7 +90,17 @@ void AOMusicPlayer::set_volume(int p_value, int channel) { m_volume = p_value; float volume = m_volume / 100.0f; - BASS_ChannelSetAttribute(m_stream_list[channel], BASS_ATTRIB_VOL, volume); + if (channel < 0) + { + for (int n_stream = 0 ; n_stream < m_channelmax ; ++n_stream) + { + BASS_ChannelSetAttribute(m_stream_list[n_stream], BASS_ATTRIB_VOL, volume); + } + } + else + { + BASS_ChannelSetAttribute(m_stream_list[channel], BASS_ATTRIB_VOL, volume); + } } //void CALLBACK loopProc(HSYNC handle, DWORD channel, DWORD data, void *user) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index d58353f..fa35349 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -125,6 +125,14 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_area_list->hide(); ui_music_list = new QListWidget(this); + ui_music_display = new AOMovie(this, ao_app); + ui_music_display->set_play_once(false); + ui_music_display->setAttribute(Qt::WA_TransparentForMouseEvents); + + ui_music_name = new ScrollText(ui_music_display); + ui_music_name->setText(tr("None")); + ui_music_name->setAttribute(Qt::WA_TransparentForMouseEvents); + ui_ic_chat_name = new QLineEdit(this); ui_ic_chat_name->setFrame(false); ui_ic_chat_name->setPlaceholderText(tr("Showname")); @@ -544,6 +552,24 @@ void Courtroom::set_widgets() set_size_and_pos(ui_area_list, "music_list"); set_size_and_pos(ui_music_list, "music_list"); + set_size_and_pos(ui_music_name, "music_name"); + + ui_music_display->move(0, 0); + design_ini_result = ao_app->get_element_dimensions("music_display", "courtroom_design.ini"); + + if (design_ini_result.width < 0 || design_ini_result.height < 0) + { + qDebug() << "W: could not find \"music_name\" in courtroom_design.ini"; + ui_music_display->hide(); + } + else + { + ui_music_display->move(design_ini_result.x, design_ini_result.y); + ui_music_display->combo_resize(design_ini_result.width, design_ini_result.height); + } + + ui_music_display->play("music_display"); + if (is_ao2_bg) { set_size_and_pos(ui_ic_chat_message, "ao2_ic_chat_message"); @@ -827,6 +853,7 @@ void Courtroom::set_fonts() set_font(ui_server_chatlog, "", "server_chatlog"); set_font(ui_music_list, "", "music_list"); set_font(ui_area_list, "", "area_list"); + set_font(ui_music_name, "", "music_name"); set_dropdowns(); } @@ -1081,7 +1108,12 @@ void Courtroom::enter_courtroom() list_music(); list_areas(); - music_player->set_volume(ui_music_slider->value()); + music_player->set_volume(ui_music_slider->value(), 0); //set music + //Set the ambience and other misc. music layers + for (int i = 1; i < music_player->m_channelmax; ++i) + { + music_player->set_volume(ui_sfx_slider->value(), i); + } sfx_player->set_volume(ui_sfx_slider->value()); objection_player->set_volume(ui_sfx_slider->value()); blip_player->set_volume(ui_blip_slider->value()); @@ -1145,14 +1177,12 @@ void Courtroom::list_areas() for (int n_area = 0 ; n_area < area_list.size() ; ++n_area) { QString i_area = ""; - i_area.append("["); - i_area.append(QString::number(n_area)); - i_area.append("] "); - i_area.append(area_list.at(n_area)); if (ao_app->arup_enabled) { + i_area.prepend("[" + QString::number(n_area) + "] "); //Give it the index + i_area.append("\n "); i_area.append(arup_statuses.at(n_area)); @@ -2873,30 +2903,33 @@ void Courtroom::handle_song(QStringList *p_contents) f_song_clear = f_song_clear.left(f_song_clear.lastIndexOf(".")); int n_char = f_contents.at(1).toInt(); + bool looping = true; + int channel = 0; + bool crossfade = false; if (n_char < 0 || n_char >= char_list.size()) { - music_player->set_looping(true); int channel = 0; if (p_contents->length() > 3 && p_contents->at(3) != "-1") - music_player->set_looping(false); + looping = false; if (p_contents->length() > 4) //eyyy we want to change this song's CHANNEL huh channel = p_contents->at(4).toInt(); //let the music player handle it if it's bigger than the channel list - bool crossfade = false; if (p_contents->length() > 5) //CROSSFADE!? Are you MAD? { - qDebug() << p_contents->at(5); crossfade = p_contents->at(5) == "1"; //let the music player handle it if it's bigger than the channel list } + qDebug() << f_song << channel << p_contents->at(3) << looping; + music_player->set_looping(looping, channel); music_player->play(f_song, channel, crossfade); + if (channel == 0) + ui_music_name->setText(f_song); } else { QString str_char = char_list.at(n_char).name; QString str_show = char_list.at(n_char).name; - music_player->set_looping(true); if (p_contents->length() > 2) { @@ -2905,20 +2938,15 @@ void Courtroom::handle_song(QStringList *p_contents) str_show = p_contents->at(2); } } - if (p_contents->length() > 3) + if (p_contents->length() > 3 && p_contents->at(3) != "-1") { //I am really confused why "-1" is "loop this song" and why anything else passes as "don't loop" //(if we even have this length) but alright - if(p_contents->at(3) != "-1") - { - music_player->set_looping(false); - } + looping = false; } - int channel = 0; if (p_contents->length() > 4) //eyyy we want to change this song's CHANNEL huh channel = p_contents->at(4).toInt(); //let the music player handle it if it's bigger than the channel list - bool crossfade = false; if (p_contents->length() > 5) //CROSSFADE!? Are you MAD? crossfade = p_contents->at(5) == "1"; //let the music player handle it if it's bigger than the channel list @@ -2934,7 +2962,10 @@ void Courtroom::handle_song(QStringList *p_contents) } append_ic_text(f_song_clear, str_show, true); + music_player->set_looping(looping, channel); music_player->play(f_song, channel, crossfade); + if (channel == 0) + ui_music_name->setText(f_song); } } } @@ -3915,13 +3946,18 @@ void Courtroom::on_text_color_changed(int p_color) void Courtroom::on_music_slider_moved(int p_value) { - music_player->set_volume(p_value); + music_player->set_volume(p_value, 0); //Set volume on music layer ui_ic_chat_message->setFocus(); } void Courtroom::on_sfx_slider_moved(int p_value) { sfx_player->set_volume(p_value); + //Set the ambience and other misc. music layers + for (int i = 1; i < music_player->m_channelmax; ++i) + { + music_player->set_volume(p_value, i); + } objection_player->set_volume(p_value); ui_ic_chat_message->setFocus(); } @@ -3986,7 +4022,6 @@ void Courtroom::on_change_character_clicked() { music_player->set_volume(0); sfx_player->set_volume(0); - sfx_player->set_volume(0); blip_player->set_volume(0); set_char_select(); diff --git a/src/scrolltext.cpp b/src/scrolltext.cpp new file mode 100644 index 0000000..6cf075d --- /dev/null +++ b/src/scrolltext.cpp @@ -0,0 +1,134 @@ +#include "scrolltext.h" + + +ScrollText::ScrollText(QWidget *parent) : + QWidget(parent), scrollPos(0) +{ + staticText.setTextFormat(Qt::PlainText); + +// setFixedHeight(fontMetrics().height()*2); //The theme sets this + leftMargin = height() / 3; + + setSeparator(" --- "); + + connect(&timer, SIGNAL(timeout()), this, SLOT(timer_timeout())); + timer.setInterval(50); +} + +QString ScrollText::text() const +{ + return _text; +} + +void ScrollText::setText(QString text) +{ + _text = text; + updateText(); + update(); +} + +QString ScrollText::separator() const +{ + return _separator; +} + +void ScrollText::setSeparator(QString separator) +{ + _separator = separator; + updateText(); + update(); +} + +void ScrollText::updateText() +{ + timer.stop(); + + singleTextWidth = fontMetrics().horizontalAdvance(_text); + scrollEnabled = (singleTextWidth > width() - leftMargin*2); + + if(scrollEnabled) + { + scrollPos = -64; + staticText.setText(_text + _separator); + timer.start(); + } + else + staticText.setText(_text); + + staticText.prepare(QTransform(), font()); + wholeTextSize = QSize(fontMetrics().horizontalAdvance(staticText.text()), fontMetrics().height()); +} + +void ScrollText::paintEvent(QPaintEvent*) +{ + QPainter p(this); + + if(scrollEnabled) + { + buffer.fill(qRgba(0, 0, 0, 0)); + QPainter pb(&buffer); + pb.setPen(p.pen()); + pb.setFont(p.font()); + + int x = qMin(-scrollPos, 0) + leftMargin; + while(x < width()) + { + pb.drawStaticText(QPointF(x, (height() - wholeTextSize.height()) / 2), staticText); + x += wholeTextSize.width(); + } + + //Apply Alpha Channel + pb.setCompositionMode(QPainter::CompositionMode_DestinationIn); + pb.setClipRect(width() - 15, 0, 15, height()); + pb.drawImage(0, 0, alphaChannel); + pb.setClipRect(0, 0, 15, height()); + //initial situation: don't apply alpha channel in the left half of the image at all; apply it more and more until scrollPos gets positive + if(scrollPos < 0) + pb.setOpacity(static_cast((qMax(-8, scrollPos) + 8) / 8.0)); + pb.drawImage(0, 0, alphaChannel); + + //pb.end(); + p.drawImage(0, 0, buffer); + } + else + { + p.drawStaticText(QPointF(leftMargin, (height() - wholeTextSize.height()) / 2), staticText); + } +} + +void ScrollText::resizeEvent(QResizeEvent*) +{ + //When the widget is resized, we need to update the alpha channel. + + alphaChannel = QImage(size(), QImage::Format_ARGB32_Premultiplied); + buffer = QImage(size(), QImage::Format_ARGB32_Premultiplied); + + //Create Alpha Channel: + if(width() > 64) + { + //create first scanline + QRgb* scanline1 = reinterpret_cast(alphaChannel.scanLine(0)); + for(int x = 1; x < 16; ++x) + scanline1[x - 1] = scanline1[width() - x] = qRgba(0, 0, 0, x << 4); + for(int x = 15; x < width() - 15; ++x) + scanline1[x] = qRgb(0, 0, 0); + //copy scanline to the other ones + for(int y = 1; y < height(); ++y) + memcpy(alphaChannel.scanLine(y), scanline1, static_cast(width() * 4)); + } + else + alphaChannel.fill(qRgb(0, 0, 0)); + + + //Update scrolling state + bool newScrollEnabled = (singleTextWidth > width() - leftMargin); + if(newScrollEnabled != scrollEnabled) + updateText(); +} + +void ScrollText::timer_timeout() +{ + scrollPos = (scrollPos + 2) + % wholeTextSize.width(); + update(); +} From 2c265ebc0befebaef41c27a851d2ebff76bf0fec Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sat, 21 Sep 2019 00:23:01 +0300 Subject: [PATCH 074/268] Clear the screen and display the background in the correct position when background change func is called --- include/courtroom.h | 2 +- src/courtroom.cpp | 15 ++++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/include/courtroom.h b/include/courtroom.h index 465b8ce..e350db2 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -161,7 +161,7 @@ public: void set_pair_list(); //sets desk and bg based on pos in chatmessage - void set_scene(); + void set_scene(QString f_desk_mod, QString f_side); //sets text color based on text color in chatmessage void set_text_color(); diff --git a/src/courtroom.cpp b/src/courtroom.cpp index fa35349..c057461 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1000,6 +1000,14 @@ void Courtroom::set_background(QString p_background) set_size_and_pos(ui_vp_chatbox, "chatbox"); set_size_and_pos(ui_ic_chat_message, "ic_chat_message"); } + + ui_vp_speedlines->stop(); + ui_vp_player_char->stop(); + ui_vp_sideplayer_char->stop(); + ui_vp_effect->stop(); + ui_vp_message->hide(); + ui_vp_chatbox->hide(); + set_scene(ao_app->get_char_side(current_char), QString::number(ao_app->get_desk_mod(current_char, current_emote))); } void Courtroom::update_character(int p_cid) @@ -1706,7 +1714,7 @@ void Courtroom::handle_chatmessage_2() f_weight = chatsize; this->set_qfont(ui_vp_message, "", QFont(font_name, f_weight), f_color, bold); - set_scene(); + set_scene(m_chatmessage[DESK_MOD], m_chatmessage[SIDE]); set_text_color(); // Check if the message needs to be centered. @@ -1741,7 +1749,6 @@ void Courtroom::handle_chatmessage_2() if (m_chatmessage[OTHER_CHARID].isEmpty()) { // If there is no second character, hide 'em, and center the first. - ui_vp_sideplayer_char->hide(); ui_vp_sideplayer_char->stop(); ui_vp_sideplayer_char->move(0,0); @@ -2738,13 +2745,11 @@ void Courtroom::play_sfx() sfx_player->set_looping(ao_app->get_sfx_looping(current_char, sfx_name)!="0"); } -void Courtroom::set_scene() +void Courtroom::set_scene(QString f_desk_mod, QString f_side) { //witness is default if pos is invalid QString f_background = "witnessempty"; QString f_desk_image = "stand"; - QString f_desk_mod = m_chatmessage[DESK_MOD]; - QString f_side = m_chatmessage[SIDE]; if (f_side == "def") { From 398f37794facc239153a8c21e0630d2eb7850739 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Mon, 23 Sep 2019 15:48:35 +0300 Subject: [PATCH 075/268] Make music list a QTreeWidget instead for easier category searching, etc. Temporarily allow music suffix until I let the client perform a fileExists check similar to how images are handled (.mp3? play mp3, if not mp3, play .ogg, etc. etc.) --- include/courtroom.h | 6 ++-- src/courtroom.cpp | 71 +++++++++++++++++++++++++++++---------------- 2 files changed, 50 insertions(+), 27 deletions(-) diff --git a/include/courtroom.h b/include/courtroom.h index e350db2..59e97dd 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include #include #include @@ -444,7 +446,7 @@ private: QListWidget *ui_mute_list; QListWidget *ui_area_list; - QListWidget *ui_music_list; + QTreeWidget *ui_music_list; ScrollText *ui_music_name; AOMovie *ui_music_display; @@ -610,7 +612,7 @@ private slots: void on_ooc_return_pressed(); void on_music_search_edited(QString p_text); - void on_music_list_double_clicked(QModelIndex p_model); + void on_music_list_double_clicked(QTreeWidgetItem *p_item, int column); void on_area_list_double_clicked(QModelIndex p_model); void select_emote(int p_id); diff --git a/src/courtroom.cpp b/src/courtroom.cpp index c057461..0c963c8 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -123,7 +123,11 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_area_list = new QListWidget(this); ui_area_list->hide(); - ui_music_list = new QListWidget(this); + ui_music_list = new QTreeWidget(this); + ui_music_list->setColumnCount(1); + ui_music_list->setHeaderHidden(true); + ui_music_list->header()->setStretchLastSection(false); + ui_music_list->header()->setSectionResizeMode(QHeaderView::ResizeToContents); ui_music_display = new AOMovie(this, ao_app); ui_music_display->set_play_once(false); @@ -308,7 +312,7 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() connect(ui_ooc_chat_message, SIGNAL(returnPressed()), this, SLOT(on_ooc_return_pressed())); - connect(ui_music_list, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(on_music_list_double_clicked(QModelIndex))); + connect(ui_music_list, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this, SLOT(on_music_list_double_clicked(QTreeWidgetItem*, int))); connect(ui_area_list, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(on_area_list_double_clicked(QModelIndex))); connect(ui_hold_it, SIGNAL(clicked()), this, SLOT(on_hold_it_clicked())); @@ -1001,13 +1005,13 @@ void Courtroom::set_background(QString p_background) set_size_and_pos(ui_ic_chat_message, "ic_chat_message"); } - ui_vp_speedlines->stop(); - ui_vp_player_char->stop(); - ui_vp_sideplayer_char->stop(); - ui_vp_effect->stop(); - ui_vp_message->hide(); - ui_vp_chatbox->hide(); - set_scene(ao_app->get_char_side(current_char), QString::number(ao_app->get_desk_mod(current_char, current_emote))); +// ui_vp_speedlines->stop(); +// ui_vp_player_char->stop(); +// ui_vp_sideplayer_char->stop(); +// ui_vp_effect->stop(); +// ui_vp_message->hide(); +// ui_vp_chatbox->hide(); +// set_scene(ao_app->get_char_side(current_char), QString::number(ao_app->get_desk_mod(current_char, current_emote))); } void Courtroom::update_character(int p_cid) @@ -1142,26 +1146,43 @@ void Courtroom::list_music() int n_listed_songs = 0; + QTreeWidgetItem *parent = nullptr; for (int n_song = 0 ; n_song < music_list.size() ; ++n_song) { QString i_song = music_list.at(n_song); - QString i_song_listname = i_song; - i_song_listname = i_song_listname.left(i_song_listname.lastIndexOf(".")); + QString i_song_listname = i_song.left(i_song.lastIndexOf(".")); - if (i_song.toLower().contains(ui_music_search->text().toLower())) + QTreeWidgetItem *treeItem; + if (i_song_listname != i_song && parent != nullptr) //not a category, parent exists + treeItem = new QTreeWidgetItem(parent); + else + treeItem = new QTreeWidgetItem(ui_music_list); + treeItem->setText(0, i_song); + music_row_to_number.append(n_song); + + QString song_path = ao_app->get_music_path(i_song); + + if (file_exists(song_path)) + treeItem->setBackground(0, found_brush); + else + treeItem->setBackground(0, missing_brush); + + if (i_song_listname == i_song) //Not supposed to be a song to begin with - a category? + parent = treeItem; + ++n_listed_songs; + + if (ui_music_search->text() != "") + treeItem->setHidden(true); + } + + if (ui_music_search->text() != "") + { + QList clist = ui_music_list->findItems(ui_music_search->text(), Qt::MatchContains|Qt::MatchRecursive, 0); + foreach(QTreeWidgetItem* item, clist) { - ui_music_list->addItem(i_song_listname); - music_row_to_number.append(n_song); - - QString song_path = ao_app->get_music_path(i_song); - - if (file_exists(song_path)) - ui_music_list->item(n_listed_songs)->setBackground(found_brush); - else - ui_music_list->item(n_listed_songs)->setBackground(missing_brush); - - ++n_listed_songs; + item->setHidden(false); } + ui_music_list->expandAll(); } } @@ -3736,12 +3757,12 @@ void Courtroom::on_pair_list_clicked(QModelIndex p_index) } } -void Courtroom::on_music_list_double_clicked(QModelIndex p_model) +void Courtroom::on_music_list_double_clicked(QTreeWidgetItem *p_item, int column) { if (is_muted) return; - QString p_song = music_list.at(music_row_to_number.at(p_model.row())); + QString p_song = p_item->text(column); if (!ui_ic_chat_name->text().isEmpty() && ao_app->cccc_ic_support_enabled) { From d8857aa2e48c89a5002f8511ce566df9c557598e Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Tue, 24 Sep 2019 00:38:26 +0300 Subject: [PATCH 076/268] When the background is changed, display it in the correct position as dictated by the server packets Add a new "set pos" packet Udpate the pos dropdown according to the current pos --- include/courtroom.h | 4 +++ src/courtroom.cpp | 52 ++++++++++++++++++++++++++++++------- src/packet_distribution.cpp | 12 +++++++++ 3 files changed, 58 insertions(+), 10 deletions(-) diff --git a/include/courtroom.h b/include/courtroom.h index 59e97dd..26018e2 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -150,6 +150,9 @@ public: //sets the current background to argument. also does some checks to see if it's a legacy bg void set_background(QString p_background); + //sets the local character pos/side to use. + void set_side(QString p_side); + //sets the evidence list member variable to argument void set_evidence_list(QVector &p_evi_list); @@ -412,6 +415,7 @@ private: bool server_ooc = true; QString current_background = "default"; + QString current_side = ""; AOMusicPlayer *music_player; AOSfxPlayer *sfx_player; diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 0c963c8..8896335 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1005,15 +1005,44 @@ void Courtroom::set_background(QString p_background) set_size_and_pos(ui_ic_chat_message, "ic_chat_message"); } -// ui_vp_speedlines->stop(); -// ui_vp_player_char->stop(); -// ui_vp_sideplayer_char->stop(); -// ui_vp_effect->stop(); -// ui_vp_message->hide(); -// ui_vp_chatbox->hide(); -// set_scene(ao_app->get_char_side(current_char), QString::number(ao_app->get_desk_mod(current_char, current_emote))); + ui_vp_speedlines->stop(); + ui_vp_player_char->stop(); + ui_vp_sideplayer_char->stop(); + ui_vp_effect->stop(); + ui_vp_message->hide(); + ui_vp_chatbox->hide(); + set_scene(QString::number(ao_app->get_desk_mod(current_char, current_emote)), current_side); } +void Courtroom::set_side(QString p_side) +{ + if (p_side == "") + current_side = ao_app->get_char_side(current_char); + else + current_side = p_side; + + qDebug() << current_side; + for (int i = 0; i < ui_pos_dropdown->count(); ++i) + { + QString pos = ui_pos_dropdown->itemText(i); + if (pos == current_side) + { + //Block the signals to prevent setCurrentIndex from triggering a pos change + ui_pos_dropdown->blockSignals(true); + + //Set the index on dropdown ui element to let you know what pos you're on right now + ui_pos_dropdown->setCurrentIndex(i); + + //Unblock the signals so the element can be used for setting pos again + ui_pos_dropdown->blockSignals(false); + + //alright we dun, jobs done here boyos + break; + } + } +} + + void Courtroom::update_character(int p_cid) { bool newchar = m_cid != p_cid; @@ -1052,7 +1081,9 @@ void Courtroom::update_character(int p_cid) set_sfx_dropdown(); set_effects_dropdown(); - QString side = ao_app->get_char_side(f_char); + QString side = current_side; + if (side == "") + side = ao_app->get_char_side(current_char); if (side == "jud") { @@ -1320,7 +1351,9 @@ void Courtroom::on_chat_return_pressed() QStringList packet_contents; - QString f_side = ao_app->get_char_side(current_char); + QString f_side = current_side; + if (f_side == "") + f_side = ao_app->get_char_side(current_char); QString f_desk_mod = "chat"; @@ -2946,7 +2979,6 @@ void Courtroom::handle_song(QStringList *p_contents) crossfade = p_contents->at(5) == "1"; //let the music player handle it if it's bigger than the channel list } - qDebug() << f_song << channel << p_contents->at(3) << looping; music_player->set_looping(looping, channel); music_player->play(f_song, channel, crossfade); if (channel == 0) diff --git a/src/packet_distribution.cpp b/src/packet_distribution.cpp index e483ef9..7559840 100644 --- a/src/packet_distribution.cpp +++ b/src/packet_distribution.cpp @@ -594,7 +594,19 @@ void AOApplication::server_packet_received(AOPacket *p_packet) goto end; if (courtroom_constructed) + { + if (f_contents.size() >= 2) //We have a pos included in the background packet! + w_courtroom->set_side(f_contents.at(1)); w_courtroom->set_background(f_contents.at(0)); + } + } + else if (header == "SP") + { + if (f_contents.size() < 1) + goto end; + + if (courtroom_constructed) //We were sent a "set position" packet + w_courtroom->set_side(f_contents.at(0)); } //server accepting char request(CC) packet else if (header == "PV") From 1e4f8fc2ac9c1232563875bf83493915bfaaaa48 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Tue, 24 Sep 2019 00:59:12 +0300 Subject: [PATCH 077/268] Fix a bug with music search that didn't show the item's parent when it's being searched for --- src/courtroom.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 8896335..bdd1f77 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1211,7 +1211,9 @@ void Courtroom::list_music() QList clist = ui_music_list->findItems(ui_music_search->text(), Qt::MatchContains|Qt::MatchRecursive, 0); foreach(QTreeWidgetItem* item, clist) { - item->setHidden(false); + if (item->parent() != nullptr) //So the category shows up too + item->parent()->setHidden(false); + item->setHidden(false); } ui_music_list->expandAll(); } From 54ef2c3fe2925c165904c474fb5f821e1d577dd8 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Tue, 24 Sep 2019 01:16:21 +0300 Subject: [PATCH 078/268] Remove a useless theme folder --- base/themes/1.8/arrow_left.png | Bin 742 -> 0 bytes base/themes/1.8/arrow_right.png | Bin 730 -> 0 bytes base/themes/1.8/chatmed.png | Bin 505 -> 0 bytes base/themes/1.8/favorites.png | Bin 1682 -> 0 bytes base/themes/1.8/favorites_selected.png | Bin 2238 -> 0 bytes base/themes/1.8/holdit.png | Bin 1983 -> 0 bytes base/themes/1.8/holdit_selected.png | Bin 1835 -> 0 bytes base/themes/1.8/mute.png | Bin 4984 -> 0 bytes base/themes/1.8/mute_pressed.png | Bin 4725 -> 0 bytes base/themes/1.8/objection.png | Bin 2147 -> 0 bytes base/themes/1.8/objection_selected.png | Bin 1988 -> 0 bytes base/themes/1.8/publicservers.png | Bin 1836 -> 0 bytes base/themes/1.8/publicservers_selected.png | Bin 2399 -> 0 bytes base/themes/1.8/takethat.png | Bin 2057 -> 0 bytes base/themes/1.8/takethat_selected.png | Bin 1932 -> 0 bytes 15 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 base/themes/1.8/arrow_left.png delete mode 100644 base/themes/1.8/arrow_right.png delete mode 100644 base/themes/1.8/chatmed.png delete mode 100644 base/themes/1.8/favorites.png delete mode 100644 base/themes/1.8/favorites_selected.png delete mode 100644 base/themes/1.8/holdit.png delete mode 100644 base/themes/1.8/holdit_selected.png delete mode 100644 base/themes/1.8/mute.png delete mode 100644 base/themes/1.8/mute_pressed.png delete mode 100644 base/themes/1.8/objection.png delete mode 100644 base/themes/1.8/objection_selected.png delete mode 100644 base/themes/1.8/publicservers.png delete mode 100644 base/themes/1.8/publicservers_selected.png delete mode 100644 base/themes/1.8/takethat.png delete mode 100644 base/themes/1.8/takethat_selected.png diff --git a/base/themes/1.8/arrow_left.png b/base/themes/1.8/arrow_left.png deleted file mode 100644 index f1098c49b7fff15407ae2d9b96968898134fa106..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 742 zcmV004&&004{<008|>004nL003F*009yY002DZ000@zy2&Ck0003i zX+uL$P-t&-Z*ypGa3D!TLm+T+Z)Rz1WdHyu&tqUGmw1*$mUCju&;pFNf7oE5W5KI2_X9m zNPRk(&BOsV2f~&Cu}e}bK=v{?=ND8KWu|A8C>UB=S}HiEH; zLN@>a0RKruK~y+TV}ODG|Nm2jQ2&w~`A0CaUk8wkQH3ZnkMx=W=-sFbi_ zczb8r{~w<}VTfZjFj*Q^5iY!YVgrU4NH2zgFhj|~F#TWy(aS_~G2Ad100~fnA%KAa Y01A3evDIW@ApigX07*qoM6N<$f-AupwEzGB diff --git a/base/themes/1.8/arrow_right.png b/base/themes/1.8/arrow_right.png deleted file mode 100644 index 2b5ad70d1db7dbcde655f4298f0504d8bdc885d4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 730 zcmV<00ww*4P)004&&004{<008|>004nL003F*009yY002DZ000@zy2&Ck0003i zX+uL$P-t&-Z*ypGa3D!TLm+T+Z)Rz1WdHyu&tqUGmw1*$mUCju&;pFNf7oE5W5KI2_X9m zNPRk(&BOsV2f~&Cu}e}bK=v{?=ND8KWu|A8C>UB=S}HiEH; zLN@>a0P{&iK~y+TV}ODG|Nm2jQ2P7h9QoQL3)WY5ClHIe))e>LoS9KGA7AD5P0|G z!T+@t$r$o5OtOI>@bb>}|0@b2G1P!CSq6f@)2rwHFU|oN)(0~5GL6`swSJyZ-5EAkxB{s$LCM~w|A16 z^^&DA74DwcfFXtrgY;q;2s4x%4AT!b5WP$!7sCyM0gwPC7y=j=0IYycv5body#N3J M07*qoM6N<$f+-Xm6951J diff --git a/base/themes/1.8/chatmed.png b/base/themes/1.8/chatmed.png deleted file mode 100644 index 0c3bae1e16eba3d6c0d930ef025eda4dd88c2ae4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 505 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5{5aTvXzqQo_#Bsf2;hmB~Pm!Rs4C$ANAJpeYY*nM!ZhADAi2^x#APGmQf` zb;|2F4oJwyI~*2cWNc7iY%my7XoEeY0At3DZ~NFD6z!E)VwiJ()6dl3*$mq_7lvNRj2{{@G6?fzia^>FVdQ&MBb@07ERCb^rhX diff --git a/base/themes/1.8/favorites.png b/base/themes/1.8/favorites.png deleted file mode 100644 index 0eec611403af430dde0a157536cc357000c432a3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1682 zcmV;D25tF?P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02*{fSaefwW^{L9 za%BKeVQFr3E>1;MAa*k@H7+qQF!XYv000I7NklBTF5XTdw(g)fCrBIGa z1*Adjg?IR@Kju#M`I z`in1>Y4mA+Dn{ex$D~q0<6wP;G=?%weIi`SdKxp8p9}dZoM)O!)Y1BB?dqPOEpwABxP-03Z`1~}Uqz?}KjlPjObWy{7ML2t+pBS-eY?Ya#m)&OIN_CO!z zjCN^0jmrkPIk-L$f|;Hp@N0N)i8a9N=|gaHpxKhp^iw#~;)Am_Tj8$%U1v=C*E`}J zHw4@<5!?nt&HHUT^f~l3Rl@Lr4`9-_&U4Q1E_)>=edVtS>f6rBIjjxFD&B*^FFvy* zH1QOMLP5A(zZ0gb)_D%ysA5K%>8kSA1odr)=eIP6<>czRqEx%%THSUS4f$-3+?Q~z zCj|Gq8sI_aC!Qm3m<>}qSLpMglIN>y-xThjs)g&l$7~6W!az$cj0d;F3~pzykvGUx zZ-TTE8M{@nQcJ$nNv*DDt*&7>&hwRVy$#1Cvfifg0(uP{Y_{#tObj2n^>D6o6HMW2 zj@Qt__y(=4Bfk*VOXC~F*Csv3*=Lh_sb!Nf8E2zdv3^bUWJ-gNW3L%KxCusDgP714 zg$d0>o?>M^d{egz?j9`j99}4urh19gN;t+P?KE2(c`bdZB`c=kI@`S1x7EuSX}si0 z;||POEuK8?!;i}Ntt6od)iW|+q8dkrtvW>n8Q9ceN~rR>{Or;l&b=&{v&9T}I` z43FV8=lmP-b0|J?gVa3Af{VueeyV1%{jb01Kwq&}0;D^t8jh4j=p;{?v2i!c6syO{d4D&*iJO zH)-@(G2hgVvDM4C7fg3n!j0aLWryNxC_RraR(%Mw`1adtyIv9?L5(_%|)>(AX36Yv^E8051DK!tGq{IdWm9dI@W#ncA<`r`|`g zc6y9`wqkL;A8ESAE5-wxVW_FvvP0t$^^NH#$E>#wOe55SO6d~XGkc14!wH14ep17@bIg>&iKs{4_py; z$4pl>eBIq@{v4W$Jb^ykp;sGr!DMB*GroV@z(=7gE*;*fep{4Y_{*?EvoRQIYrwa{ zAH!7DdS~2q#H1^#-EqEdD~z-^;tpLXOlU4X4}JI{b)tR;e1{Wr#kX%8c%xl0-nbJ6 zTI|!kR<6?fbi+afbjEv6*jE|wN>;Kr c&dSRE0l)nv;^LoU7ytkO07*qoM6N<$f}brc^Z)<= diff --git a/base/themes/1.8/favorites_selected.png b/base/themes/1.8/favorites_selected.png deleted file mode 100644 index f6a2abf886559deca23a0a21d5e96fbfac55748f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2238 zcmV;v2toIWP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02*{fSaefwW^{L9 za%BKeVQFr3E>1;MAa*k@H7+qQF!XYv000OrNkl19@zgJl4b{8nWz07X+p=QY%htL$Y}+i4YJWW|I;@ zk*Sf0Py%6#Nka)Cg%HV`&0`I1e!uT|-20pR$m4_r z?KZVyQ#9&|^f*_MiLVReP`^_PM|lF8_v!J^Jt;VDHK1YtHu&X1Q_0SKY{scwdiwi^j58oUm$f(w2m#gGPMuR~=~W{PHoQf#y$Mhx3F9Xxsvv*+h5?_+}%#^&5aw z+WkC>U)XrCH^RBZxVl$9`_5}q-`Ie*AMCE zgT^R+|0aX<_mV!oG3j{2W37kyZmOj*I;|*Ft?a zS*M4#L`Tn`p1bdw5Zwr!ldQ=@psjmotfhVb56&OV#ps#s!1>J>J(&g9SDCJ-H2SHM!%9dZH``R}W>N=d&bS+P@l(A`M!0t-z%ZSE1DwgNwGcXevoXQ@I(x zez&V?Tv)&K-&q|8U6n!Z>HzErO0M&-gV=4c5-S8(n29fg`E7u#0<# zo-19CL3;|CcPz#Fg|lD|yF+p4g$iU;V-A~ki=bo6!`3&p2BElOT|nllN9uwH(6ZwN z4B3-#zBEB7=y$bSfiE}1Rh^AZQBR=Y#a}26f5GIC>Zcasb$;uhcGo2XT_!w>Zv88h2`Q=Z3hXXgH-k~lhGNONjx0cR9iRPDz!=IQ` zo*}0b$9bQ%-?zV%MjQ*|OZ8*O<@vZ0m|qM<#>(eq?ojd$rO)G}u%E#~KEIWQKQXC1 zgV*seqsLO(Kw~g}!ed!xEZ&!k@xEN1kFmLwA|ZVG*d03b-S~o@DbGVwMJ~=;4Ok!k zb8o?M*XV-bq# zC`m(CRW@3S;-HV13G-v*D@tMLNm0aclMGDHU@As9oasYdSY26+^!h5o5o=-9a&uBrrFD30d~nt&0z z9zEqRlTYFMVG6rbH8!e*Q7z`GNBn{r=r50f+n$J4Te48le--I{e-CXhj)rdGgV;b8 zrWQH38{|T(MdFjQaK##hp-*%;`xovG?XKAde6<7XDStUS%42b{EFKP9Dzr-?f=mMa`=pYb`9Ozu z+j?BJYH_VF8rO@Wan1S?F6S?Uvyyz_9y8)Xg#mxhPZtVG|Be1cVG8uddbIzNTY@7vq6&Vc)G zucEgy4Oc6(aCUd5^!}EUWm&jU_b&QA--0VuMzmGtp!4t+TtD^>F4`^VtjizYDQLIc zu6+7F+U;A>`}uZs*1V05Dl@KCn{dsZM{4yR8uywe7BgtKi-m;z7d7oQd%|)_;{X5v M07*qoM6N<$f+D0iQ2+n{ diff --git a/base/themes/1.8/holdit.png b/base/themes/1.8/holdit.png deleted file mode 100644 index 09d1d37020bb85d5d28e6d791980adf6c1fd552f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1983 zcmV;w2SE6VP)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00009 za7bBm000ic000ic0Tn1pfB*mh7<5HgbW?9;ba!ELWdLwtX>N2bZe?^JG%heMHD!e| zWdHyN5lKWrRA@uxn)^>wM-<0JE2&ihO%pXHYJw)l#Ay6Me=uq^{?b|>ty){FR$HyL z@qx6yiq#6f5V44$#W%GDk@8Y28t{Pv3t0Z9>G{mg+0I@rbQe(*y2;1AGiUBRzW2?(QBGuol+jmN>AV!6ue6V4_LPvaZ_E(J}PXAw$en z$0gy%nKMmuO-^}+g z$#u@GSv}ez81_zqKKEs2#%wF4toZjZrq=HqJ2uXy+`oR^6pEd-X#ZOTJgu`cl3G<& znd&4+{G+EKF8f$GBONkn22j@X?M>vu#*L=dvws(``$V2UH-}t1CVXJ}^d4=ugV&o`Zsh_xM)>+4e2=xoacy$|kPxnj;y=dnrfx2K$*iHpW@ z8;n_JSFJMl1A~+bVvD$TVS=$mUpPBkmu>6Y z!50ixdu`}{muK5He0a?El~?~jzylj^-HO=(4bVeG>pkrdu|{d0<=+hdCD@aO29xXA z@V>88QhM~Gtnk`a3JCVsjT@%w^l7tG%4>v|&VE4XY;TXdzbZf9>>fAH+!7nYW(hk+ zjf!hyP{{Mli=t zKfejw&z4mD_(vPY=M=YF+p$g9%(d5V5EV@{ih5bpvwFs?AYp>>bT4k*YV8Dn73`V7 zle@BOm)Yy;^xiVTpEP#LcoF4lSH9`W2zM(gzc5Uxo>utVZY+vpW(5mt5Tw1O#pWvh zL|7=tH`}Jg)d7OB0JaKcVvULvCYVhb1Qv`9R4@WNi7s>CK)^$oi!azG!Y}LA*>B3H z1x`t>$sg_ZbnEa1dsJB&t51Za1Ou{Roh1C=UE@W#IoE#(Ec#D@_@N?T^9AFzM6cOS zJ6w66tAp&xlkLK4i;K+(DU-X=CePVHGkRhd50Hdb#iJdGH}{{Cg8{+s34UIdD6cG- zazS7b8p8;{-%pv+t6=&{VUYzYgw^C&V-liJ%FdM-SZYLGUw%+44!#v z8w4X?<9@siL5Y`dO)$0_TdLvGrI=uBhte%utYG9)ECNBWAsBfV*S=sRv23#^uB=ej z1Q*XO-moDqB_VcxE6|RyNFRu|d}HT8z=l`xAQ_L8r0wa`&^7i&(t;h7SC0)cm`;{0 zh&T_*%j41twgc$~f@xb|LBtmo4De3B4d9g!tVf)Ryga+`hh9C9vS2?tZ=Rhi^Wt3+ z8)6|8p7>O-iEChOiIB8l5ELvd56c&rU{J6&fqFmo9rLb%WR-(}WK16LSPcU0->6_@$olJrgF_>m#n7HYyn0lpIg{*gj%}X{xR^FT1*8cAyUMHattmAcfKV zF&X+L*rVIGZJ=e~pkM@3egfhrmy-hCNRVYqkW~lY^%S1C5`6#kZGL?+Xbz~nu~QNd z>>C-7Cx&3W)N*XMKYM1qf@2>~+m@PY9@o{`i78?Iy$KMEOkV}d5&A6{Z{%Ud-stM+ zFvk}!Hg{!E^`!dJQfuSAk(>!y8XJ4u`?g?Pl7HdxKx*=$sVTH=U)WzSlJzh+w`Ps~ zQI4lY?xTVYcA_4ZHYU{A7i7))p7?(f46Uq(MIsSXTU(nHoLabcPG+XLQ&ADxW-x(9 z*2DNG%4qi;B`qz@erIHijg|xd#jo~PCw^QA_8l$%`{xM*`R4|Sp>s?({{SFz`ixcC RM#lgE002ovPDHLkV1kyyvZDY1 diff --git a/base/themes/1.8/holdit_selected.png b/base/themes/1.8/holdit_selected.png deleted file mode 100644 index 51586e748d67251f3c7e7bbe0b2485b8816bbd93..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1835 zcmV+`2h{k9P)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00009 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 Rv2_3d002ovPDHLkV1hJ7vETpz diff --git a/base/themes/1.8/takethat.png b/base/themes/1.8/takethat.png deleted file mode 100644 index 8ff2befe32fd104826f57b8778c921a643de878e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2057 zcmV+k2=@1hP)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00009 za7bBm000ic000ic0Tn1pfB*mh7<5HgbW?9;ba!ELWdLwtX>N2bZe?^JG%heMHD!e| zWdHyNTS-JgRA@u(n%h$pM-+zvuVqCRQpOjxykDxU(kk`E2OsoFlbDOSnHWvtC5ott zf)FDHf|yX=qJZe0TYpdye@E|mAApEv|eX@^lj2bm~(IjSBSB=GDS7M}!MPZ-5WEdSyS8bfbW1u8nl4E-W;=r%w;f8wlTe{ezzb#%KpVm><)SAQ}|w z`iT>E@NiG)6kL&%?}VUWJpWSIF@C(yW`7{qX{m=tgylaA*m!^)k8^@f&v?9RWPSam zk)8zU{}5|JMwW?|mYSwhr%X+LzS$&(q0DOt9t%w#tAtG>M)+_$s)7NXW-7-!JCpg% zXU`_vfW2eJnD)DOZ61Qv%CneIK5?SyXlqN>3v%!3Rr9fw`${Mj=zn)CmdLwy&1{ip z+7CFzRr1`JCaY)qqOsgk@gp%*<-uFf2JQ&uLR_d5_RO7Ys@ASGmntfJ9S`CPhPWGt z4>x<~&$oFON=nReCm-uO9B(Nb?aM6B0zpG76y_fs+W zyJsBFLad6VOU*tB+^Gb6(%o&2OPOZL%NITuPRgoe2QM&v-x09O0NxY+5XeKgwE|P` zkwAS0h42W5s0bPqjFtDwp+i1)NjViJXq$WblP}|S?I>t~7U&`|?P<|;8md^z&1lqo zAcpq|bo%(3HTJnH*jB0M*4a02o@tQh+EKieLF+w1-+G=0@k-MSsKrZf7fJ+z{Z;|N z@VqS&+uE9&eQlP_nq|vHFbXVPYv=?d_)X;X_ML zPmg`3g7L<8I}PuiF(Wyhbm@K;!Fc;DD(?zAgl;cQeHE-^!GdIazzfqhvAxktyD%j$ zmX{|5<3*p@w#{cJ3>8f@N_bhqvr_M~QlWy;xW<{bn>S6F1ad_DQBaXw!R`u7bJBPc z3yTWI^h9JpxQ9X>_Y)?V1Iw0K!OjcY$Bi>}Wo5R_s&(t^6lZ}TCL%U*5katxT>?9G zn5HTi0$!6C?T#rG3DNA?GqcYfd|x1#^(+Cwis#Hp24>zi0#ynf!Upf2vPXqqgjNAB zV|8W4yd;qCf>>pX7u)u}mNa#+!}P2cXtOdi)5f};0)kPGX}NRKq-2{2Rxo9X$u4I}|SuY&O+IDz1G+*5|K^asI$w$tUg3WgAfqJlAP$h$4D*~MEZ5A6c+YS-k+c27hw zX2ZE&*gSf4vK;l9?(7NKU%7(m76MPDJz|;r0)Xc%UMsl|8Bc!=Eb})D#y# zHI{T3v|zd!)K2~Cq{FZ~_vOp&pa|-$fGhxcW5-&1tj3r3@3+&AIH)TygZy6LWZ}LH zdro!0UXRBC0Xquy5E~I$?So@Uhd~Plu3%?`zn%Mw-c_fj3U+YiN_*C00Bl2|d3lx} zr%w#qEFc*5*r`M8@ngGLB_QKLY76uf;R>cfAG@3mG=^cDRa5QWZ)mXX@I8)| zS#7hG*^!;?8$-GbiC`RSSmNo74vMJ)4abfp)4*E~v%%Md!;;SwLYzNQ7Hui>;?T;Z5j16Q^u&{D{alf(AdL|zs5l97ND&u{m5v;bf^eMs0 zmn;djsUR3rRZjwV^4p|C%J#=gBN!kWv4%ss3I?1ExU$tius7w(6yq5i;{F69UKP!p zY0Gk=z#Fd~J{(%MKdfM!$ip(zg?NFB6VOk19SSR#F7EL~!M1+0VkKn@0jZ|=^TK|; z7_5iExuPN)%;9!zZD^Tv(a$n$5fF=g7}JzC!pgr$5+0VF8=CoF!4xW(I@KO;*st;Z z?XQ}e(6TQYw6Y%7)zxJhC5HS@YS74f82=;~>s=FM%U*?RPR{Fz`@nzkYyRNzw+lhr niTi*5JYgvR+#o%)j}h|^`=|ZHVemoH00000NkvXXu0mjfqw>jh diff --git a/base/themes/1.8/takethat_selected.png b/base/themes/1.8/takethat_selected.png deleted file mode 100644 index 3fe0a8cd13fa0244f7b9c87076b6f24cef43ba57..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1932 zcmV;72Xpv|P)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00009 za7bBm000ib000ib0l1NC?EnA(7<5HgbW?9;ba!ELWdLwtX>N2bZe?^JG%heMHD!e| zWdHyM-bqA3RA@u(nTb*xM-YYqV@a`N1GXub9hb|lA|xan!RD3$p>PUeWG)GFBjBBQ zf)q~@c&bT%qixmfG7>@vC*{gk{b+V)rhEFI?w;PIsn+ZK{JfRltE;Q#csya^@pyem zc%IdXL?T#+$n>_WB4Naq2NxF?E!M#My4u^@O`%ZuE`TjKKww&9uaalQt)jEDv+n}f zf=z*mjlJ61+A5NDAkTMlIg{<}H3LmeA?&WLmB;-o_p`5FnUmw=(EM6(d~jfjhlk$2 zdhmI0u)N03Mvx{s%ew02 znds>7_SJ*2V13|E0XAC0?{e8Nlq4D@E1$_&^?vfF8kzmX;9Qg(_iyMH9*=#bUXCdu64p157@AXpZ*wY#)TJ$+Hu|%+sefM0H*i zdz+i)cNxdVObA&2>B&i{Z)?j8$unICSmsyy+?*z-XYHhM+%ggGSPH-{sDfR=jDW>s z#HY?qv((>j*3;?G!lQ5rQ*tL?zO;Q`rl!oI(+}|8*}xN(FrMRSn{#s^*-_+|mP}g4 z;YqAN{ra`p-Po`j2O;f&C8XLVWX0OrI_$*!!h%(%!WF*?x&$c3 zh}H4&&|($j95;kq!kAC)=oR2ukaa4c4@1?cB)>BEwuAv!ADd6!B2Bo2u@0ZNYEBc< zDwiEX){hi@nzL|U4Eh`h$Fm?S{qCKalEht!u+!61vnXS>rEgf!FUZKLWQ`XPzP|{N zivh^g0|Vk1kM|x4n2%8qk1j}s&?sS?ygYL;F5{G#sBG?8&#>6*%2B`pT)>OuwCki1 zhQ88aJDauPGbLcri+z3exl7ovgs(eiO2TYQp6f#KQjFGna*Or60OTueV-OoddqjX< zJPP8_h0Y<#Z3o-iA)P4+E5?z#_yw*fK{9LLIrm=$)&m_GQNV?_PQ$aR6{W?aBU=Nx zb&wLqj+0pR`NXql<%R0eeH+5qeGU~oa8!VN+RRtN(5?Ca8>Tvu?aEUSlIt@wWx|lP zGBOg9z$N#q!b(Mpm_7>S%Pr;R6Jh#E+ELNb6j z5;iB=*pnwF{r>L zaj%3y1f(cogbjT>!|U)C>zM*PgnTtFhYmFnbMan0^J8mkc^vZzcf1R^E@4_i;Hl^% zm(kBN1Z`Xu<`OXtVo-l+FW$9wDw(zvf3|0_Ll1h~@Nz zWJqNLc&>y&6giCisA~Y^N7e;$$>cR#YQdce(_&B;WnVF>z*g=ODi}pl$6GLNC>FEw zIE^>tBx55WOiy5poD?v}-3(3Y3dU=jG6FdY=0P@d>;39+XTpF>*ot7^xz|Llp{az; zb$8pui~*D(*`XneX}Nb_kMJ%^28`t%U3?-!53(VGuOIY5Foh~#PQYMuvpL$`wQDS7 zGFCR@{!@gJTksy*7{uwPl|DI)lMcd|r`0$WI{hSMt-uu!##@9-7$ng~E^h~#!;sCX zsdD$_Ed@P%kK2^QoVS1XX`5~if-H!Dt3$ODx^{JvnnUfk8g zz^c?WBy+Ii{L`ZzKo}vUC4%NLboj=9OO!k;em4(mGzcNy`zUb9Yb5%wxtw?Gw+38U z4=YNAotGT)KPm%`tcUTZgjnz!Mk4V;solVT@rU8pdmYZd|L<)rm7r^kn|}bmL0ucw SUjQip0000 Date: Tue, 24 Sep 2019 04:15:06 +0300 Subject: [PATCH 079/268] Fix some tooltips Workaround for music list updates forcing the music list to collapse, prioritize expanding it instead. (ISSUE: does not fix the underlying problem of the music list inexplicably collapsing/expanding. Need to preserve info for that somewhere.) Fix additive chat not showing up for anyone that's not yourself (Todo: update server code to do the proper checking) --- src/courtroom.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index bdd1f77..3d131cd 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -609,7 +609,7 @@ void Courtroom::set_widgets() set_size_and_pos(ui_music_search, "music_search"); set_size_and_pos(ui_emote_dropdown, "emote_dropdown"); - ui_pos_dropdown->setToolTip(tr("Set your character's emote to play on your next message.")); + ui_emote_dropdown->setToolTip(tr("Set your character's emote to play on your next message.")); set_size_and_pos(ui_pos_dropdown, "pos_dropdown"); ui_pos_dropdown->setToolTip(tr("Set your character's supplementary background.")); @@ -629,7 +629,7 @@ void Courtroom::set_widgets() ui_sfx_dropdown->setEditable(true); ui_sfx_dropdown->setInsertPolicy(QComboBox::InsertAtBottom); ui_sfx_dropdown->setToolTip(tr("Set a sound effect to play on your next 'Preanim'. Leaving it on Default will use the emote-defined sound (if any).\n" - "Edit by typing and pressing Enter, [X] to remove. This saves to your base/characters//sounds.ini")); + "Edit by typing and pressing Enter, [X] to remove. This saves to your base/characters//soundlist.ini")); set_size_and_pos(ui_sfx_remove, "sfx_remove"); ui_sfx_remove->setText("X"); @@ -738,7 +738,7 @@ void Courtroom::set_widgets() ui_additive->setToolTip(tr("Add text to your last spoken message when checked.")); set_size_and_pos(ui_guard, "guard"); - ui_additive->setToolTip(tr("Do not listen to mod calls when checked, preventing them from playing sounds or focusing attention on the window.")); + ui_guard->setToolTip(tr("Do not listen to mod calls when checked, preventing them from playing sounds or focusing attention on the window.")); set_size_and_pos(ui_casing, "casing"); ui_casing->setToolTip(tr("Lets you receive case alerts when enabled.\n" @@ -1215,8 +1215,8 @@ void Courtroom::list_music() item->parent()->setHidden(false); item->setHidden(false); } - ui_music_list->expandAll(); } + ui_music_list->expandAll(); //Workaround, it needs to preserve the "expanded categories" due to list music being updated constantly by some servers } void Courtroom::list_areas() @@ -1603,7 +1603,7 @@ void Courtroom::handle_chatmessage(QStringList *p_contents) chatmessage_is_empty = m_chatmessage[MESSAGE] == " " || m_chatmessage[MESSAGE] == ""; - is_additive = false; + //Hey, our message showed up! Cool! if (m_chatmessage[MESSAGE] == ui_ic_chat_message->text() && m_chatmessage[CHAR_ID].toInt() == m_cid) { ui_ic_chat_message->clear(); @@ -1621,12 +1621,11 @@ void Courtroom::handle_chatmessage(QStringList *p_contents) ui_realization->set_image("realization"); ui_screenshake->set_image("screenshake"); ui_evidence_present->set_image("present_disabled"); - - - if (ao_app->additive_enabled && ui_vp_player_char->m_char == m_chatmessage[CHAR_NAME]) - is_additive = m_chatmessage[ADDITIVE].toInt() == 1; } + //Let the server handle actually checking if they're allowed to do this. + is_additive = m_chatmessage[ADDITIVE].toInt() == 1; + chatlogpiece* temp = new chatlogpiece(ao_app->get_showname(char_list.at(f_char_id).name), f_showname, ": " + m_chatmessage[MESSAGE], false); ic_chatlog_history.append(*temp); ao_app->append_to_file(temp->get_full(), ao_app->log_filename, true); From 9911aeb5e6741279715f05d76c054907c58b47de Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Tue, 24 Sep 2019 13:29:08 +0300 Subject: [PATCH 080/268] Fix an issue with AOCharmovie hanging on frame1 animations Fix an issue with the logger screwing up the server folder name string if character ' was used --- src/aocharmovie.cpp | 10 +++++++--- src/packet_distribution.cpp | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/aocharmovie.cpp b/src/aocharmovie.cpp index d764d1a..e8dc8fc 100644 --- a/src/aocharmovie.cpp +++ b/src/aocharmovie.cpp @@ -153,8 +153,12 @@ void AOCharMovie::play() { play_frame_effect(frame); if (max_frames <= 1) - return; - ticker->start(this->get_frame_delay(movie_delays[frame])); + { + play_once = true; + ticker->start(60); + } + else + ticker->start(this->get_frame_delay(movie_delays[frame])); } void AOCharMovie::play_pre(QString p_char, QString p_emote, int duration) @@ -281,7 +285,7 @@ void AOCharMovie::move(int ax, int ay) void AOCharMovie::movie_ticker() { ++frame; - if(frame == max_frames) + if(frame >= max_frames) { if(play_once) { diff --git a/src/packet_distribution.cpp b/src/packet_distribution.cpp index 7559840..3060530 100644 --- a/src/packet_distribution.cpp +++ b/src/packet_distribution.cpp @@ -288,7 +288,7 @@ void AOApplication::server_packet_received(AOPacket *p_packet) send_server_packet(f_packet); //Remove any characters not accepted in folder names for the server_name here - this->log_filename = QDateTime::currentDateTime().toUTC().toString("'logs/" + server_name.remove(QRegExp("[\\\\/:*?\"<>|]")) + "/'ddd MMMM yyyy hh.mm.ss t'.log'"); + this->log_filename = QDateTime::currentDateTime().toUTC().toString("'logs/" + server_name.remove(QRegExp("[\\\\/:*?\"<>|\']")) + "/'ddd MMMM yyyy hh.mm.ss t'.log'"); this->write_to_file("Joined server " + server_name + " on address " + server_address +" on " + QDateTime::currentDateTime().toUTC().toString(), log_filename, true); QCryptographicHash hash(QCryptographicHash::Algorithm::Sha256); hash.addData(server_address.toUtf8()); From 7097053723bab5cb91c312abaafeb69dc07dd4ac Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Tue, 24 Sep 2019 21:24:25 +0300 Subject: [PATCH 081/268] Change all instances of "colour" to "color" for consistency's sake Overhaul inline colors system to properly support additive text and further expansion Add two new colors - Gray and Blank, the latter being used for IC parsing. Instead of adding text symbol by symbol, reveal more of the already-rendered text instead so that it properly anticipates words that need to be on the newline. Changed the append_ic function slightly so it appends ": " to text only after it's no longer needed. Made gray color less inconsistent with everything else --- include/aoapplication.h | 2 +- include/aotextarea.h | 2 +- include/courtroom.h | 27 +- include/datatypes.h | 4 +- src/courtroom.cpp | 531 ++++++++++++------------------------ src/text_file_functions.cpp | 68 +++-- 6 files changed, 224 insertions(+), 410 deletions(-) diff --git a/include/aoapplication.h b/include/aoapplication.h index 5fb6338..fef299b 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -242,7 +242,7 @@ public: //Returns the color with p_identifier from p_file QColor get_color(QString p_identifier, QString p_file); - // Returns the colour from the misc folder. + // 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 diff --git a/include/aotextarea.h b/include/aotextarea.h index 13b29c9..643a8e3 100644 --- a/include/aotextarea.h +++ b/include/aotextarea.h @@ -13,7 +13,7 @@ public: AOTextArea(QWidget *p_parent = nullptr); void append_linked(QString p_message); - void append_chatmessage(QString p_name, QString p_message, QString p_colour); + void append_chatmessage(QString p_name, QString p_message, QString p_colur); void append_error(QString p_message); private: diff --git a/include/courtroom.h b/include/courtroom.h index 26018e2..5aad1cb 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -171,7 +171,7 @@ public: //sets text color based on text color in chatmessage void set_text_color(); - // And gets the colour, too! + // And gets the color, too! QColor get_text_color(QString color); //takes in serverD-formatted IP list as prints a converted version to server OOC @@ -202,7 +202,7 @@ public: //these are for OOC chat void append_ms_chatmessage(QString f_name, QString f_message); - void append_server_chatmessage(QString p_name, QString p_message, QString p_colour); + void append_server_chatmessage(QString p_name, QString p_message, QString p_color); //these functions handle chatmessages sequentially. //The process itself is very convoluted and merits separate documentation @@ -213,7 +213,7 @@ public: //This function filters out the common CC inline text trickery, for appending to //the IC chatlog. - QString filter_ic_text(QString p_text); + QString filter_ic_text(QString p_text, bool colorize = false, int pos = -1, int default_color = WHITE); //adds text to the IC chatlog. p_name first as bold then p_text then a newlin //this function keeps the chatlog scrolled to the top unless there's text selected @@ -259,18 +259,6 @@ private: QParallelAnimationGroup *screenshake_animation_group = new QParallelAnimationGroup; - // This is for inline message-colouring. - - enum INLINE_COLOURS { - INLINE_BLUE, - INLINE_GREEN, - INLINE_ORANGE, - INLINE_GREY - }; - - // A stack of inline colours. - std::stack inline_colour_stack; - bool next_character_is_not_special = false; // If true, write the // next character as it is. @@ -279,14 +267,6 @@ private: int current_display_speed = 3; int message_display_speed[7] = {0, 10, 25, 40, 50, 70, 90}; - // This is for checking if the character should start talking again - // when an inline blue text ends. - bool entire_message_is_blue = false; - - // And this is the inline 'talking checker'. Counts how 'deep' we are - // in inline blues. - int inline_blue_depth = 0; - // The character ID of the character this user wants to appear alongside with. int other_charid = -1; @@ -356,6 +336,7 @@ private: bool chatmessage_is_empty = false; QString previous_ic_message = ""; + QString additive_previous = ""; //char id, muted or not QMap mute_map; diff --git a/include/datatypes.h b/include/datatypes.h index 5426d98..1917482 100644 --- a/include/datatypes.h +++ b/include/datatypes.h @@ -120,7 +120,9 @@ enum COLOR YELLOW, RAINBOW, PINK, - CYAN + CYAN, + GRAY, + BLANK }; #endif // DATATYPES_H diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 3d131cd..48b8864 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1266,7 +1266,7 @@ void Courtroom::list_areas() if (ao_app->arup_enabled) { - // Colouring logic here. + // Coloring logic here. ui_area_list->item(n_listed_areas)->setBackground(free_brush); if (arup_locks.at(n_area) == "LOCKED") { @@ -1301,21 +1301,21 @@ void Courtroom::append_ms_chatmessage(QString f_name, QString f_message) ui_ms_chatlog->append_chatmessage(f_name, f_message, ao_app->get_color("ms_chatlog_sender_color", "courtroom_fonts.ini").name()); } -void Courtroom::append_server_chatmessage(QString p_name, QString p_message, QString p_colour) +void Courtroom::append_server_chatmessage(QString p_name, QString p_message, QString p_color) { - QString colour = "#000000"; + QString color = "#000000"; - if (p_colour == "0") - colour = ao_app->get_color("ms_chatlog_sender_color", "courtroom_fonts.ini").name(); - if (p_colour == "1") - colour = ao_app->get_color("server_chatlog_sender_color", "courtroom_fonts.ini").name(); + if (p_color == "0") + color = ao_app->get_color("ms_chatlog_sender_color", "courtroom_fonts.ini").name(); + if (p_color == "1") + color = ao_app->get_color("server_chatlog_sender_color", "courtroom_fonts.ini").name(); if(p_message == "Logged in as a moderator.") { ui_guard->show(); append_server_chatmessage("CLIENT", "You were granted the Disable Modcalls button.", "1"); } - ui_server_chatlog->append_chatmessage(p_name, p_message, colour); + ui_server_chatlog->append_chatmessage(p_name, p_message, color); } void Courtroom::on_chat_return_pressed() @@ -1635,7 +1635,7 @@ void Courtroom::handle_chatmessage(QStringList *p_contents) ic_chatlog_history.removeFirst(); } - append_ic_text(": " + m_chatmessage[MESSAGE], f_showname); + append_ic_text(m_chatmessage[MESSAGE], f_showname); previous_ic_message = f_message; @@ -2060,19 +2060,17 @@ void Courtroom::handle_chatmessage_3() int f_anim_state = 0; //BLUE is from an enum in datatypes.h - bool text_is_blue = m_chatmessage[TEXT_COLOR].toInt() == BLUE; + bool text_is_blue = m_chatmessage[TEXT_COLOR].toInt() == BLUE || m_chatmessage[TEXT_COLOR].toInt() == ORANGE; if (!text_is_blue && text_state == 1) { //talking f_anim_state = 2; - entire_message_is_blue = false; } else { //idle f_anim_state = 3; - entire_message_is_blue = true; } if (f_anim_state <= anim_state) @@ -2108,148 +2106,156 @@ void Courtroom::handle_chatmessage_3() } -QString Courtroom::filter_ic_text(QString p_text) +QString Courtroom::filter_ic_text(QString p_text, bool colorize, int pos, int default_color) { // Get rid of centering. - if(p_text.startsWith(": ~~")) - { - // Don't forget, the p_text part actually everything after the name! - // Hence why we check for ': ~~'. + if(p_text.startsWith("~~")) + p_text.remove(0,2); - // Let's remove those two tildes, then. - // : _ ~ ~ - // 0 1 2 3 - p_text.remove(2,2); + int check_pos = 0; + bool ic_next_is_not_special = false; + QString f_character = p_text.at(check_pos); + std::stack ic_color_stack; + + if (colorize) + { + ic_color_stack.push(static_cast(default_color)); + qDebug() << ic_color_stack.top(); + QString appendage = ""; + p_text.insert(check_pos, appendage); + check_pos += appendage.size(); + if (pos > -1) + pos += appendage.size(); } - // Get rid of the inline-colouring. - // I know, I know, excessive code duplication. - // Nobody looks in here, I'm fine. - int trick_check_pos = 0; - bool ic_next_is_not_special = false; - QString f_character = p_text.at(trick_check_pos); - std::stack ic_colour_stack; - while (trick_check_pos < p_text.size()) + while (check_pos < p_text.size()) { - f_character = p_text.at(trick_check_pos); + f_character = p_text.at(check_pos); + bool color_update = false; - // Escape character. - if (f_character == "\\" and !ic_next_is_not_special) + if (!ic_next_is_not_special) + { + if (f_character == "\\") { - ic_next_is_not_special = true; - p_text.remove(trick_check_pos,1); + ic_next_is_not_special = true; + p_text.remove(check_pos, 1); + check_pos -= 1; + pos -= 1; } - // Text speed modifier. - else if (f_character == "{" and !ic_next_is_not_special) + //Nothing related to colors here + else if (f_character == "{" || f_character == "}" || f_character == "@" || f_character == "$") { - p_text.remove(trick_check_pos,1); - } - else if (f_character == "}" and !ic_next_is_not_special) - { - p_text.remove(trick_check_pos,1); + p_text.remove(check_pos, 1); + check_pos -= 1; + pos -= 1; } - else if (f_character == "$" and !ic_next_is_not_special) + //Colors that destroy the character + else if (f_character == "`") { - p_text.remove(trick_check_pos,1); - } - - else if (f_character == "@" and !ic_next_is_not_special) - { - p_text.remove(trick_check_pos,1); - } - - // Orange inline colourisation. - else if (f_character == "|" and !ic_next_is_not_special) - { - if (!ic_colour_stack.empty()) - { - if (ic_colour_stack.top() == INLINE_ORANGE) - { - ic_colour_stack.pop(); - p_text.remove(trick_check_pos,1); - } - else - { - ic_colour_stack.push(INLINE_ORANGE); - p_text.remove(trick_check_pos,1); - } - } + if (colorize) + { + if (!ic_color_stack.empty() && ic_color_stack.top() == GREEN && default_color != GREEN) + ic_color_stack.pop(); //Cease our coloring else { - ic_colour_stack.push(INLINE_ORANGE); - p_text.remove(trick_check_pos,1); + ic_color_stack.push(GREEN); //Begin our coloring } + color_update = true; + } + else + p_text.remove(check_pos, 1); } - - // Blue inline colourisation. - else if (f_character == "(" and !ic_next_is_not_special) + else if (f_character == "|") { - ic_colour_stack.push(INLINE_BLUE); - trick_check_pos++; - } - else if (f_character == ")" and !ic_next_is_not_special - and !ic_colour_stack.empty()) - { - if (ic_colour_stack.top() == INLINE_BLUE) - { - ic_colour_stack.pop(); - trick_check_pos++; - } + if (colorize) + { + if (!ic_color_stack.empty() && ic_color_stack.top() == ORANGE && default_color != ORANGE) + ic_color_stack.pop(); //Cease our coloring else { - ic_next_is_not_special = true; + ic_color_stack.push(ORANGE); //Begin our coloring } + color_update = true; + } + else + p_text.remove(check_pos, 1); } - // Grey inline colourisation. - else if (f_character == "[" and !ic_next_is_not_special) + //Colors that don't destroy the character and use 2 chars for beginning/end + else if (colorize && f_character == "(") { - ic_colour_stack.push(INLINE_GREY); - trick_check_pos++; + ic_color_stack.push(BLUE); //Begin our coloring + color_update = true; } - else if (f_character == "]" and !ic_next_is_not_special - and !ic_colour_stack.empty()) + else if (colorize && f_character == ")" && ic_color_stack.top() == BLUE) { - if (ic_colour_stack.top() == INLINE_GREY) - { - ic_colour_stack.pop(); - trick_check_pos++; - } - else - { - ic_next_is_not_special = true; - } + ic_color_stack.pop(); //Cease our coloring + color_update = true; + } + else if (colorize && f_character == "[") + { + if (colorize) + ic_color_stack.push(GRAY); //Begin our coloring + color_update = true; + } + else if (colorize && f_character == "]" && ic_color_stack.top() == GRAY) + { + if (colorize) + ic_color_stack.pop(); //Cease our coloring + color_update = true; } - // Green inline colourisation. - else if (f_character == "`" and !ic_next_is_not_special) + //Parse the newest color stack + if (!ic_next_is_not_special && color_update && (pos <= -1 || check_pos < pos)) //Only color text if we haven't reached the "invisible threshold" { - if (!ic_colour_stack.empty()) - { - if (ic_colour_stack.top() == INLINE_GREEN) - { - ic_colour_stack.pop(); - p_text.remove(trick_check_pos,1); - } - else - { - ic_colour_stack.push(INLINE_GREEN); - p_text.remove(trick_check_pos,1); - } - } - else - { - ic_colour_stack.push(INLINE_GREEN); - p_text.remove(trick_check_pos,1); - } + QString appendage = ""; + + if (!ic_color_stack.empty()) + appendage += ""; + + if (f_character == "(" || f_character == "[") //Gotta capture them in the color too + p_text.insert(check_pos, appendage); + else if (f_character == ")" || f_character == "]") + p_text.insert(check_pos+1, appendage); + else + { + p_text.remove(check_pos, 1); + p_text.insert(check_pos, appendage); + check_pos -= 1; + pos -= 1; + } + check_pos += appendage.size(); + if (pos > -1) + pos += appendage.size(); } - else + } + else + ic_next_is_not_special = false; + + //Make all chars we're not supposed to see invisible + if (pos > -1 && check_pos == pos) + { + QString appendage = ""; + if (!ic_color_stack.empty()) { - trick_check_pos++; - ic_next_is_not_special = false; + //Clean it up, we're done here + while (!ic_color_stack.empty()) + ic_color_stack.pop(); + + appendage += ""; } + ic_color_stack.push(BLANK); + appendage += ""; + p_text.insert(check_pos, appendage); + } + check_pos += 1; + } + + if (!ic_color_stack.empty()) + { + p_text.append(""); } return p_text; @@ -2292,6 +2298,7 @@ void Courtroom::append_ic_text(QString p_text, QString p_name, bool is_songchang } else { + ui_ic_chatlog->textCursor().insertText(": ", normal); ui_ic_chatlog->textCursor().insertText(p_text, normal); } @@ -2302,7 +2309,6 @@ void Courtroom::append_ic_text(QString p_text, QString p_name, bool is_songchang ui_ic_chatlog->textCursor().select(QTextCursor::BlockUnderCursor); ui_ic_chatlog->textCursor().removeSelectedText(); ui_ic_chatlog->textCursor().deleteChar(); - //qDebug() << ui_ic_chatlog->document()->blockCount() << " < " << log_maximum_blocks; } if (old_cursor.hasSelection() || !is_scrolled_down) @@ -2333,6 +2339,7 @@ void Courtroom::append_ic_text(QString p_text, QString p_name, bool is_songchang } else { + ui_ic_chatlog->textCursor().insertText(": ", normal); ui_ic_chatlog->textCursor().insertText(p_text + '\n', normal); } @@ -2441,7 +2448,7 @@ void Courtroom::start_chat_ticking() } set_text_color(); - rainbow_counter = 0; +// rainbow_counter = 0; if (chatmessage_is_empty) { @@ -2452,10 +2459,10 @@ void Courtroom::start_chat_ticking() // At this point, we'd do well to clear the inline colour stack. // This stops it from flowing into next messages. - while (!inline_colour_stack.empty()) - { - inline_colour_stack.pop(); - } +// while (!inline_colour_stack.empty()) +// { +// inline_colour_stack.pop(); +// } ui_vp_chatbox->show(); ui_vp_message->show(); @@ -2463,15 +2470,12 @@ void Courtroom::start_chat_ticking() if (!is_additive) { ui_vp_message->clear(); + additive_previous = ""; } tick_pos = 0; blip_pos = 0; - // Just in case we somehow got inline blue text left over from a previous message, - // let's set it to false. - inline_blue_depth = 0; - // At the start of every new message, we set the text speed to the default. current_display_speed = 3; chat_tick_timer->start(message_display_speed[current_display_speed]); @@ -2486,11 +2490,10 @@ void Courtroom::start_chat_ticking() void Courtroom::chat_tick() { - //note: this is called fairly often(every 60 ms when char is talking) + //note: this is called fairly often //do not perform heavy operations here QString f_message = m_chatmessage[MESSAGE]; - f_message.remove(0, tick_pos); // Due to our new text speed system, we always need to stop the timer now. chat_tick_timer->stop(); @@ -2498,14 +2501,7 @@ void Courtroom::chat_tick() // Stops blips from playing when we have a formatting option. bool formatting_char = false; - // If previously, we have detected that the message is centered, now - // is the time to remove those two tildes at the start. - if (message_is_centered) - { - f_message.remove(0,2); - } - - if (f_message.size() == 0) + if (tick_pos >= f_message.size()) { text_state = 2; if (anim_state != 4) @@ -2516,239 +2512,78 @@ void Courtroom::chat_tick() QString f_char = m_chatmessage[CHAR_NAME]; QString f_custom_theme = ao_app->get_char_shouts(f_char); ui_vp_chat_arrow->play("chat_arrow", f_char, f_custom_theme); //Chat stopped being processed, indicate that. + additive_previous = additive_previous + filter_ic_text(f_message, true, -1, m_chatmessage[TEXT_COLOR].toInt()); } else { - QTextBoundaryFinder tbf(QTextBoundaryFinder::Grapheme, f_message); + QString f_rest = f_message; + f_rest.remove(0, tick_pos); + QTextBoundaryFinder tbf(QTextBoundaryFinder::Grapheme, f_rest); QString f_character; int f_char_length; tbf.toNextBoundary(); if (tbf.position() == -1) - f_character = f_message; + f_character = f_rest; else - f_character = f_message.left(tbf.position()); + f_character = f_rest.left(tbf.position()); f_char_length = f_character.length(); f_character = f_character.toHtmlEscaped(); - - if (f_character == " ") - ui_vp_message->insertPlainText(" "); - // Escape character. - else if (f_character == "\\" and !next_character_is_not_special) + if (!next_character_is_not_special) { - next_character_is_not_special = true; - formatting_char = true; - } + if (f_character == "\\") + { + next_character_is_not_special = true; + formatting_char = true; + } - // Text speed modifier. - else if (f_character == "{" and !next_character_is_not_special) - { - // ++, because it INCREASES delay! - current_display_speed++; - formatting_char = true; - } - else if (f_character == "}" and !next_character_is_not_special) - { - current_display_speed--; - formatting_char = true; - } + // Text speed modifier. + else if (f_character == "{") + { + // ++, because it INCREASES delay! + current_display_speed++; + formatting_char = true; + } + else if (f_character == "}") + { + current_display_speed--; + formatting_char = true; + } - else if (f_character == "@" and !next_character_is_not_special) - { - this->do_screenshake(); - formatting_char = true; - } + //Screenshake. + else if (f_character == "@") + { + this->do_screenshake(); + formatting_char = true; + } - else if (f_character == "$" and !next_character_is_not_special) - { - this->do_flash(); - formatting_char = true; - } + //Flash. + else if (f_character == "$") + { + this->do_flash(); + formatting_char = true; + } - // Orange inline colourisation. - else if (f_character == "|" and !next_character_is_not_special) - { - if (!inline_colour_stack.empty()) - { - if (inline_colour_stack.top() == INLINE_ORANGE) - { - inline_colour_stack.pop(); - } - else - { - inline_colour_stack.push(INLINE_ORANGE); - } - } - else - { - inline_colour_stack.push(INLINE_ORANGE); - } - formatting_char = true; - } - - // Blue inline colourisation. - else if (f_character == "(" and !next_character_is_not_special) - { - inline_colour_stack.push(INLINE_BLUE); - ui_vp_message->insertHtml("" + f_character + ""); - - // Increase how deep we are in inline blues. - inline_blue_depth++; - - // Here, we check if the entire message is blue. - // If it isn't, we stop talking. - if (!entire_message_is_blue and anim_state != 4) - { - QString f_char = m_chatmessage[CHAR_NAME]; - QString f_emote = m_chatmessage[EMOTE]; - ui_vp_player_char->play_idle(f_char, f_emote); - } - } - else if (f_character == ")" and !next_character_is_not_special - and !inline_colour_stack.empty()) - { - if (inline_colour_stack.top() == INLINE_BLUE) - { - inline_colour_stack.pop(); - ui_vp_message->insertHtml("" + f_character + ""); - - // Decrease how deep we are in inline blues. - // Just in case, we do a check if we're above zero, but we should be. - if (inline_blue_depth > 0) - { - inline_blue_depth--; - // Here, we check if the entire message is blue. - // If it isn't, we start talking if we have completely climbed out of inline blues. - if (!entire_message_is_blue) - { - // We should only go back to talking if we're out of inline blues, not during a non. int. pre, and not on the last character. - if (inline_blue_depth == 0 and anim_state != 4 and !(tick_pos+1 >= f_message.size())) - { - QString f_char = m_chatmessage[CHAR_NAME]; - QString f_emote = m_chatmessage[EMOTE]; - ui_vp_player_char->play_talking(f_char, f_emote); - } - } - } - } - else - { - next_character_is_not_special = true; - tick_pos -= f_char_length; - } - } - - // Grey inline colourisation. - else if (f_character == "[" and !next_character_is_not_special) - { - inline_colour_stack.push(INLINE_GREY); - ui_vp_message->insertHtml("" + f_character + ""); - } - else if (f_character == "]" and !next_character_is_not_special - and !inline_colour_stack.empty()) - { - if (inline_colour_stack.top() == INLINE_GREY) - { - inline_colour_stack.pop(); - ui_vp_message->insertHtml("" + f_character + ""); - } - else - { - next_character_is_not_special = true; - tick_pos -= f_char_length; - } - } - - // Green inline colourisation. - else if (f_character == "`" and !next_character_is_not_special) - { - if (!inline_colour_stack.empty()) - { - if (inline_colour_stack.top() == INLINE_GREEN) - { - inline_colour_stack.pop(); - formatting_char = true; - } - else - { - inline_colour_stack.push(INLINE_GREEN); - formatting_char = true; - } - } - else - { - inline_colour_stack.push(INLINE_GREEN); - formatting_char = true; - } + //Color memes + else if (f_character == "`" || f_character == "|") + { + formatting_char = true; + } } else - { next_character_is_not_special = false; - if (!inline_colour_stack.empty()) - { - switch (inline_colour_stack.top()) { - case INLINE_ORANGE: - ui_vp_message->insertHtml("" + f_character + ""); - break; - case INLINE_BLUE: - ui_vp_message->insertHtml("" + f_character + ""); - break; - case INLINE_GREEN: - ui_vp_message->insertHtml("" + f_character + ""); - break; - case INLINE_GREY: - ui_vp_message->insertHtml("" + f_character + ""); - break; - } - } - else - { - if (m_chatmessage[TEXT_COLOR].toInt() == RAINBOW) - { - QString html_color; - switch (rainbow_counter) - { - case 0: - html_color = get_text_color(QString::number(RED)).name(); - break; - case 1: - html_color = get_text_color(QString::number(ORANGE)).name(); - break; - case 2: - html_color = get_text_color(QString::number(YELLOW)).name(); - break; - case 3: - html_color = get_text_color(QString::number(GREEN)).name(); - break; - default: - html_color = get_text_color(QString::number(BLUE)).name(); - rainbow_counter = -1; - } + tick_pos += f_char_length; - ++rainbow_counter; - - ui_vp_message->insertHtml("" + f_character + ""); - } - else - ui_vp_message->insertHtml(f_character); - } - - if (message_is_centered) - { - ui_vp_message->setAlignment(Qt::AlignCenter); - } - else - { - ui_vp_message->setAlignment(Qt::AlignLeft); - } - } + //Do the colors, gradual showing, etc. in here + ui_vp_message->setHtml(additive_previous + filter_ic_text(f_message, true, tick_pos, m_chatmessage[TEXT_COLOR].toInt())); + //If the text overflows, make it snap to bottom QScrollBar *scroll = ui_vp_message->verticalScrollBar(); scroll->setValue(scroll->maximum()); @@ -2773,8 +2608,6 @@ void Courtroom::chat_tick() ++blip_pos; } - tick_pos += f_char_length; - // If we had a formatting char, we shouldn't wait so long again, as it won't appear! if (formatting_char) { diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index 06caf29..91782a8 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -436,42 +436,40 @@ QColor AOApplication::get_chat_color(QString p_identifier, QString p_chat) { QColor return_color(255, 255, 255); - if (p_identifier == "_inline_grey") - { - return_color = QColor(187, 187, 187); + switch (p_identifier.toInt()) { + case WHITE: + case GREEN: + return_color = QColor(0, 255, 0); + break; + case RED: + return_color = QColor(255, 0, 0); + break; + case ORANGE: + return_color = QColor(255, 165, 0); + break; + case BLUE: + return_color = QColor(45, 150, 255); + break; + case YELLOW: + return_color = QColor(255, 255, 0); + break; + case RAINBOW: // 6 is rainbow. + case PINK: + return_color = QColor(255, 192, 203); + break; + case CYAN: + return_color = QColor(0, 255, 255); + break; + case GRAY: + return_color = QColor(187, 187, 187); + break; + case BLANK: + return_color = QColor(0, 0, 0, 0); + break; + default: + return_color = QColor(255, 255, 255); + break; } - else - { - switch (p_identifier.toInt()) { - case 1: - return_color = QColor(0, 255, 0); - break; - case 2: - return_color = QColor(255, 0, 0); - break; - case 3: - return_color = QColor(255, 165, 0); - break; - case 4: - return_color = QColor(45, 150, 255); - break; - case 5: - return_color = QColor(255, 255, 0); - break; - case 7: - return_color = QColor(255, 192, 203); - break; - case 8: - return_color = QColor(0, 255, 255); - break; - case 0: - case 6: // 6 is rainbow. - default: - return_color = QColor(255, 255, 255); - break; - } - } - p_identifier = p_identifier.prepend("c"); QString design_ini_path = get_base_path() + "misc/" + p_chat + "/config.ini"; QString default_path = get_base_path() + "misc/default/config.ini"; From 923548c99746858846764e47fa96899e7c5ef2ab Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Wed, 25 Sep 2019 02:05:52 +0300 Subject: [PATCH 082/268] Hellcommit of doom and suffering Create two new helper functions - get_chat_markdown and remake read_char_ini_tag to be read_ini_tags for more general purpose Modify aolineedit to support preserving selection after unfocusing (building this for using dropdown list for setting colors), as well as remove the setReadOnly functionality and use it in signals instead Overhaul the color system to get rid of inline colors, allow full customization of colors and usage of configuration files for every facet of how a color functions (should we be talking, should we remove that markdown char, etc.) Complete overhaul of color markdowns system TODO: Make this thing not lag to hell, fix chat messages hogging the IC as the animation never ends apparently --- include/aoapplication.h | 5 +- include/aolineedit.h | 11 +- include/courtroom.h | 16 +- include/datatypes.h | 15 -- src/aolineedit.cpp | 14 +- src/courtroom.cpp | 341 +++++++++++++++++++----------------- src/evidence.cpp | 6 +- src/text_file_functions.cpp | 49 ++++-- 8 files changed, 234 insertions(+), 223 deletions(-) diff --git a/include/aoapplication.h b/include/aoapplication.h index fef299b..89bfaa2 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -242,6 +242,9 @@ public: //Returns the color with p_identifier from p_file QColor get_color(QString p_identifier, QString p_file); + // Returns the markdown symbol used for specified p_identifier such as colors + QString get_chat_markdown(QString p_identifier, QString p_file); + // Returns the color from the misc folder. QColor get_chat_color(QString p_identifier, QString p_chat); @@ -261,7 +264,7 @@ public: QString read_char_ini(QString p_char, QString p_search_line, QString target_tag); //Returns a QStringList of all key=value definitions on a given tag. - QStringList read_char_ini_tag(QString p_char, QString target_tag); + QStringList read_ini_tags(QString p_file, QString target_tag = ""); //Sets the char.ini p_search_line key under tag target_tag to value. void set_char_ini(QString p_char, QString value, QString p_search_line, QString target_tag); diff --git a/include/aolineedit.h b/include/aolineedit.h index ce17680..0952172 100644 --- a/include/aolineedit.h +++ b/include/aolineedit.h @@ -11,16 +11,17 @@ class AOLineEdit : public QLineEdit public: AOLineEdit(QWidget *parent); + void preserve_selection(bool toggle) {p_selection = toggle;} + +private: + bool p_selection = false; + protected: void mouseDoubleClickEvent(QMouseEvent *e); + void focusOutEvent(QFocusEvent *ev); signals: void double_clicked(); - -private slots: - void on_enter_pressed(); - - }; #endif // AOLINEEDIT_H diff --git a/include/courtroom.h b/include/courtroom.h index 5aad1cb..72dec04 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -168,12 +168,6 @@ public: //sets desk and bg based on pos in chatmessage void set_scene(QString f_desk_mod, QString f_side); - //sets text color based on text color in chatmessage - void set_text_color(); - - // And gets the color, too! - QColor get_text_color(QString color); - //takes in serverD-formatted IP list as prints a converted version to server OOC //admittedly poorly named void set_ip_list(QString p_list); @@ -213,7 +207,7 @@ public: //This function filters out the common CC inline text trickery, for appending to //the IC chatlog. - QString filter_ic_text(QString p_text, bool colorize = false, int pos = -1, int default_color = WHITE); + QString filter_ic_text(QString p_text, bool colorize = false, int pos = -1, int default_color = 0); //adds text to the IC chatlog. p_name first as bold then p_text then a newlin //this function keeps the chatlog scrolled to the top unless there's text selected @@ -360,6 +354,9 @@ private: int realization_state = 0; int screenshake_state = 0; int text_color = 0; + static const int max_colors = 12; //How many unique user colors are possible + QVector color_row_to_number; //Current color list indexes to real color references + bool is_presenting_evidence = false; QString effect = ""; @@ -440,7 +437,7 @@ private: QListWidget *ui_pair_list; QSpinBox *ui_pair_offset_spinbox; - QLineEdit *ui_ic_chat_message; + AOLineEdit *ui_ic_chat_message; QLineEdit *ui_ic_chat_name; QLineEdit *ui_ooc_chat_message; @@ -625,7 +622,7 @@ private slots: QString get_char_sfx(); int get_char_sfx_delay(); - void on_evidence_name_edited(QString text); + void on_evidence_name_edited(); void on_evidence_image_name_edited(); void on_evidence_image_button_clicked(); void on_evidence_clicked(int p_id); @@ -654,6 +651,7 @@ private slots: void on_prosecution_plus_clicked(); void on_text_color_changed(int p_color); + void set_text_color_dropdown(); void on_music_slider_moved(int p_value); void on_sfx_slider_moved(int p_value); diff --git a/include/datatypes.h b/include/datatypes.h index 1917482..835cf8f 100644 --- a/include/datatypes.h +++ b/include/datatypes.h @@ -110,19 +110,4 @@ enum CHAT_MESSAGE EFFECTS }; -enum COLOR -{ - WHITE = 0, - GREEN, - RED, - ORANGE, - BLUE, - YELLOW, - RAINBOW, - PINK, - CYAN, - GRAY, - BLANK -}; - #endif // DATATYPES_H diff --git a/src/aolineedit.cpp b/src/aolineedit.cpp index 13f87f3..e345de3 100644 --- a/src/aolineedit.cpp +++ b/src/aolineedit.cpp @@ -2,21 +2,19 @@ AOLineEdit::AOLineEdit(QWidget *parent) : QLineEdit(parent) { - this->setReadOnly(true); - this->setFrame(false); - - connect(this, SIGNAL(returnPressed()), this, SLOT(on_enter_pressed())); } void AOLineEdit::mouseDoubleClickEvent(QMouseEvent *e) { QLineEdit::mouseDoubleClickEvent(e); - this->setReadOnly(false); double_clicked(); } - -void AOLineEdit::on_enter_pressed() +void AOLineEdit::focusOutEvent(QFocusEvent *ev) { - this->setReadOnly(true); + int start = selectionStart(); + int end = selectionEnd(); + QLineEdit::focusOutEvent(ev); + if (p_selection && start != -1 && end != -1) + this->setSelection(start, end); } diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 48b8864..3ff1aa2 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -141,9 +141,10 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_ic_chat_name->setFrame(false); ui_ic_chat_name->setPlaceholderText(tr("Showname")); - ui_ic_chat_message = new QLineEdit(this); + ui_ic_chat_message = new AOLineEdit(this); ui_ic_chat_message->setFrame(false); ui_ic_chat_message->setPlaceholderText(tr("Message")); + ui_ic_chat_message->preserve_selection(true); ui_muted = new AOImage(ui_ic_chat_message, ao_app); ui_muted->hide(); @@ -247,15 +248,6 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_prosecution_minus = new AOButton(this, ao_app); ui_text_color = new QComboBox(this); - ui_text_color->addItem(tr("White")); - ui_text_color->addItem(tr("Green")); - ui_text_color->addItem(tr("Red")); - ui_text_color->addItem(tr("Orange")); - ui_text_color->addItem(tr("Blue")); - ui_text_color->addItem(tr("Yellow")); - ui_text_color->addItem(tr("Rainbow")); - ui_text_color->addItem(tr("Pink")); - ui_text_color->addItem(tr("Cyan")); ui_music_slider = new QSlider(Qt::Horizontal, this); ui_music_slider->setRange(0, 100); @@ -784,6 +776,7 @@ void Courtroom::set_widgets() set_size_and_pos(ui_text_color, "text_color"); ui_text_color->setToolTip(tr("Change the text color of the spoken message.")); + set_text_color_dropdown(); set_size_and_pos(ui_music_slider, "music_slider"); set_size_and_pos(ui_sfx_slider, "sfx_slider"); @@ -1513,7 +1506,7 @@ void Courtroom::on_chat_return_pressed() packet += f_emote; if (ao_app->is_frame_network_enabled()) { - QString sfx_frames = ao_app->read_char_ini_tag(current_char, f_emote.append(f_effect)).join("|"); + 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; } @@ -1770,7 +1763,6 @@ void Courtroom::handle_chatmessage_2() this->set_qfont(ui_vp_message, "", QFont(font_name, f_weight), f_color, bold); set_scene(m_chatmessage[DESK_MOD], m_chatmessage[SIDE]); - set_text_color(); // Check if the message needs to be centered. QString f_message = m_chatmessage[MESSAGE]; @@ -2058,38 +2050,6 @@ void Courtroom::handle_chatmessage_3() } - int f_anim_state = 0; - //BLUE is from an enum in datatypes.h - bool text_is_blue = m_chatmessage[TEXT_COLOR].toInt() == BLUE || m_chatmessage[TEXT_COLOR].toInt() == ORANGE; - - if (!text_is_blue && text_state == 1) - { - //talking - f_anim_state = 2; - } - else - { - //idle - f_anim_state = 3; - } - - if (f_anim_state <= anim_state) - return; - - ui_vp_player_char->stop(); - QString f_char = m_chatmessage[CHAR_NAME]; - QString f_emote = m_chatmessage[EMOTE]; - - if (f_anim_state == 2) { - ui_vp_player_char->play_talking(f_char, f_emote); - anim_state = 2; - } - else - { - ui_vp_player_char->play_idle(f_char, f_emote); - anim_state = 3; - } - QString f_message = m_chatmessage[MESSAGE]; QStringList call_words = ao_app->get_call_words(); @@ -2115,13 +2075,13 @@ QString Courtroom::filter_ic_text(QString p_text, bool colorize, int pos, int de int check_pos = 0; bool ic_next_is_not_special = false; QString f_character = p_text.at(check_pos); - std::stack ic_color_stack; + std::stack ic_color_stack; if (colorize) { - ic_color_stack.push(static_cast(default_color)); + ic_color_stack.push(default_color); qDebug() << ic_color_stack.top(); - QString appendage = ""; + QString appendage = "get_chat_color(QString::number(ic_color_stack.top()), m_chatmessage[CHAR_NAME]).name(QColor::HexRgb) +"\">"; p_text.insert(check_pos, appendage); check_pos += appendage.size(); if (pos > -1) @@ -2151,84 +2111,91 @@ QString Courtroom::filter_ic_text(QString p_text, bool colorize, int pos, int de pos -= 1; } - //Colors that destroy the character - else if (f_character == "`") + bool is_end = false; + bool remove = false; + //Parse markdown colors + for (int c = 0; c < max_colors; ++c) { - if (colorize) - { - if (!ic_color_stack.empty() && ic_color_stack.top() == GREEN && default_color != GREEN) - ic_color_stack.pop(); //Cease our coloring - else - { - ic_color_stack.push(GREEN); //Begin our coloring - } - color_update = true; - } - else - p_text.remove(check_pos, 1); - } - else if (f_character == "|") - { - if (colorize) - { - if (!ic_color_stack.empty() && ic_color_stack.top() == ORANGE && default_color != ORANGE) - ic_color_stack.pop(); //Cease our coloring - else - { - ic_color_stack.push(ORANGE); //Begin our coloring - } - color_update = true; - } - else - p_text.remove(check_pos, 1); - } + QString markdown_start = ao_app->get_chat_markdown("c" + QString::number(c) + "_start", m_chatmessage[CHAR_NAME]); + if (markdown_start.isEmpty()) //Not defined + continue; + QString markdown_end = ao_app->get_chat_markdown("c" + QString::number(c) + "_end", m_chatmessage[CHAR_NAME]); + bool markdown_remove = ao_app->get_chat_markdown("c" + QString::number(c) + "_remove", m_chatmessage[CHAR_NAME]) == "1"; - //Colors that don't destroy the character and use 2 chars for beginning/end - else if (colorize && f_character == "(") - { - ic_color_stack.push(BLUE); //Begin our coloring - color_update = true; + if (markdown_end.isEmpty() || markdown_end == markdown_start) //"toggle switch" type + { + if (f_character == markdown_start) + { + if (colorize) + { + if (!ic_color_stack.empty() && ic_color_stack.top() == c && default_color != c) + ic_color_stack.pop(); //Cease our coloring + else + { + ic_color_stack.push(c); //Begin our coloring + } + color_update = true; + } + remove = markdown_remove; + break; //Prevent it from looping forward for whatever reason + } + } + else if (f_character == markdown_start || (f_character == markdown_end && ic_color_stack.top() == c)) + { + if (colorize) + { + if (f_character == markdown_start) + { + ic_color_stack.push(c); //Begin our coloring + } + else if (f_character == markdown_end) + { + ic_color_stack.pop(); //Cease our coloring + is_end = true; + } + color_update = true; + } + remove = markdown_remove; + break; //Prevent it from looping forward for whatever reason + } } - else if (colorize && f_character == ")" && ic_color_stack.top() == BLUE) - { - ic_color_stack.pop(); //Cease our coloring - color_update = true; - } - else if (colorize && f_character == "[") - { - if (colorize) - ic_color_stack.push(GRAY); //Begin our coloring - color_update = true; - } - else if (colorize && f_character == "]" && ic_color_stack.top() == GRAY) - { - if (colorize) - ic_color_stack.pop(); //Cease our coloring - color_update = true; - } - //Parse the newest color stack - if (!ic_next_is_not_special && color_update && (pos <= -1 || check_pos < pos)) //Only color text if we haven't reached the "invisible threshold" + if (color_update) { - QString appendage = ""; - - if (!ic_color_stack.empty()) - appendage += ""; - - if (f_character == "(" || f_character == "[") //Gotta capture them in the color too - p_text.insert(check_pos, appendage); - else if (f_character == ")" || f_character == "]") - p_text.insert(check_pos+1, appendage); - else + if (!ic_next_is_not_special && (pos <= -1 || check_pos < pos)) //Only color text if we haven't reached the "invisible threshold" { - p_text.remove(check_pos, 1); - p_text.insert(check_pos, appendage); - check_pos -= 1; - pos -= 1; + QString appendage = ""; + + if (!ic_color_stack.empty()) + appendage += "get_chat_color(QString::number(ic_color_stack.top()), m_chatmessage[CHAR_NAME]).name(QColor::HexRgb) +"\">"; + + if (!is_end || remove) + { + if (remove) + p_text.remove(check_pos, 1); + + p_text.insert(check_pos, appendage); + + if (remove) + { + check_pos -= 1; + pos -= 1; + } + } + else + { + p_text.insert(check_pos+1, appendage); + } + check_pos += appendage.size(); + if (pos > -1) + pos += appendage.size(); } - check_pos += appendage.size(); - if (pos > -1) - pos += appendage.size(); + } + else if (remove) //Simple remove request + { + p_text.remove(check_pos, 1); + check_pos -= 1; + pos -= 1; } } else @@ -2246,8 +2213,8 @@ QString Courtroom::filter_ic_text(QString p_text, bool colorize, int pos, int de appendage += ""; } - ic_color_stack.push(BLANK); - appendage += ""; + ic_color_stack.push(-1); //Dummy colorstack push for maximum appendage + appendage += ""; p_text.insert(check_pos, appendage); } check_pos += 1; @@ -2447,9 +2414,6 @@ void Courtroom::start_chat_ticking() this->do_screenshake(); } - set_text_color(); -// rainbow_counter = 0; - if (chatmessage_is_empty) { //since the message is empty, it's technically done ticking @@ -2457,13 +2421,6 @@ void Courtroom::start_chat_ticking() return; } - // At this point, we'd do well to clear the inline colour stack. - // This stops it from flowing into next messages. -// while (!inline_colour_stack.empty()) -// { -// inline_colour_stack.pop(); -// } - ui_vp_chatbox->show(); ui_vp_message->show(); @@ -2486,6 +2443,22 @@ void Courtroom::start_chat_ticking() //means text is currently ticking text_state = 1; + + //If this color is talking + bool color_is_talking = ao_app->get_chat_markdown("c" + m_chatmessage[TEXT_COLOR] + "_talking", m_chatmessage[CHAR_NAME]) == "1"; + + if (color_is_talking && text_state == 1 && anim_state < 2) //Set it to talking as we're not on that already + { +// ui_vp_player_char->stop(); + ui_vp_player_char->play_talking(m_chatmessage[CHAR_NAME], m_chatmessage[EMOTE]); + anim_state = 2; + } + else if (anim_state < 3) //Set it to idle as we're not on that already + { +// ui_vp_player_char->stop(); + ui_vp_player_char->play_idle(m_chatmessage[CHAR_NAME], m_chatmessage[EMOTE]); + anim_state = 3; + } } void Courtroom::chat_tick() @@ -2500,6 +2473,7 @@ void Courtroom::chat_tick() // Stops blips from playing when we have a formatting option. bool formatting_char = false; + bool is_talking = ao_app->get_chat_markdown("c" + m_chatmessage[TEXT_COLOR] + "_talking", m_chatmessage[CHAR_NAME]) == "1"; if (tick_pos >= f_message.size()) { @@ -2568,11 +2542,25 @@ void Courtroom::chat_tick() this->do_flash(); formatting_char = true; } - - //Color memes - else if (f_character == "`" || f_character == "|") + else { - formatting_char = true; + //Parse markdown colors + for (int c = 0; c < max_colors; ++c) + { + QString markdown_start = ao_app->get_chat_markdown("c" + QString::number(c) + "_start", m_chatmessage[CHAR_NAME]); + if (markdown_start.isEmpty()) + continue; + QString markdown_end = ao_app->get_chat_markdown("c" + QString::number(c) + "_end", m_chatmessage[CHAR_NAME]); + bool markdown_remove = ao_app->get_chat_markdown("c" + QString::number(c) + "_remove", m_chatmessage[CHAR_NAME]) == "1"; + bool color_is_talking = ao_app->get_chat_markdown("c" + QString::number(c) + "_talking", m_chatmessage[CHAR_NAME]) == "1"; + + if (markdown_remove && (f_character == markdown_start || f_character == markdown_end)) + { + formatting_char = true; + is_talking = color_is_talking; + break; + } + } } } else @@ -2591,12 +2579,12 @@ void Courtroom::chat_tick() // Keep the speed at bay. if (current_display_speed < 0) { - current_display_speed = 0; + current_display_speed = 0; } if (current_display_speed > 6) { - current_display_speed = 6; + current_display_speed = 6; } if (!formatting_char && (f_character != ' ' || blank_blip)) @@ -2611,13 +2599,27 @@ void Courtroom::chat_tick() // If we had a formatting char, we shouldn't wait so long again, as it won't appear! if (formatting_char) { - chat_tick_timer->start(0); + chat_tick_timer->start(0); } else { - chat_tick_timer->start(message_display_speed[current_display_speed]); - } + //If this color is talking + if (is_talking && text_state == 1 && anim_state < 2) //Set it to talking as we're not on that already + { +// ui_vp_player_char->stop(); + ui_vp_player_char->play_talking(m_chatmessage[CHAR_NAME], m_chatmessage[EMOTE]); + anim_state = 2; + } + else if (anim_state < 3) //Set it to idle as we're not on that already + { +// ui_vp_player_char->stop(); + ui_vp_player_char->play_idle(m_chatmessage[CHAR_NAME], m_chatmessage[EMOTE]); + anim_state = 3; + } + //Continue ticking + chat_tick_timer->start(message_display_speed[current_display_speed]); + } } } @@ -2722,30 +2724,6 @@ void Courtroom::set_scene(QString f_desk_mod, QString f_side) } } -void Courtroom::set_text_color() -{ - QColor textcolor = ao_app->get_chat_color(m_chatmessage[TEXT_COLOR], ao_app->get_chat(m_chatmessage[CHAR_NAME])); - - ui_vp_message->setTextBackgroundColor(QColor(0,0,0,0)); - ui_vp_message->setTextColor(textcolor); - - QString style = "background-color: rgba(0, 0, 0, 0);"; - style.append("color: rgb("); - style.append(QString::number(textcolor.red())); - style.append(", "); - style.append(QString::number(textcolor.green())); - style.append(", "); - style.append(QString::number(textcolor.blue())); - style.append(")"); - - ui_vp_message->setStyleSheet(style); -} - -QColor Courtroom::get_text_color(QString color) -{ - return ao_app->get_chat_color(color, ao_app->get_chat(m_chatmessage[CHAR_NAME])); -} - void Courtroom::set_ip_list(QString p_list) { QString f_list = p_list.replace("|", ":").replace("*", "\n"); @@ -3830,9 +3808,44 @@ void Courtroom::on_prosecution_plus_clicked() ao_app->send_server_packet(new AOPacket("HP#2#" + QString::number(f_state) + "#%")); } +void Courtroom::set_text_color_dropdown() +{ + ui_text_color->clear(); + color_row_to_number.clear(); + + //Set the default color 0 + QString c0_name = ao_app->get_chat_markdown("c0_name", current_char); + if (c0_name.isEmpty()) + c0_name = tr("Default"); + ui_text_color->addItem(c0_name); + color_row_to_number.append(0); + + //Set the rest of the colors + for (int c = 1; c < max_colors; ++c) + { + QString color_name = ao_app->get_chat_markdown("c" + QString::number(c) + "_name", current_char); + if (color_name.isEmpty()) //Not defined + continue; + ui_text_color->addItem(color_name); + color_row_to_number.append(c); + } +} + void Courtroom::on_text_color_changed(int p_color) { - text_color = p_color; + if (ui_ic_chat_message->selectionStart() != -1) //We have a selection! + { + qDebug() << "Setting color to selection" << ui_ic_chat_message->selectionStart() << ui_ic_chat_message->selectionEnd(); + ui_ic_chat_message->end(false); + ui_text_color->setCurrentIndex(0); + } + else + { + if (p_color != -1 && p_color < color_row_to_number.size()) + text_color = color_row_to_number.at(p_color); + else + text_color = 0; + } ui_ic_chat_message->setFocus(); } diff --git a/src/evidence.cpp b/src/evidence.cpp index b04a9d6..dfbc675 100644 --- a/src/evidence.cpp +++ b/src/evidence.cpp @@ -26,7 +26,7 @@ void Courtroom::initialize_evidence() ui_evidence_description->setStyleSheet("background-color: rgba(0, 0, 0, 0);" "color: white;"); - connect(ui_evidence_name, SIGNAL(textEdited(QString)), this, SLOT(on_evidence_name_edited(QString))); + connect(ui_evidence_name, SIGNAL(returnPressed()), this, SLOT(on_evidence_name_edited())); connect(ui_evidence_name, SIGNAL(double_clicked()), this, SLOT(on_evidence_name_double_clicked())); connect(ui_evidence_left, SIGNAL(clicked()), this, SLOT(on_evidence_left_clicked())); connect(ui_evidence_right, SIGNAL(clicked()), this, SLOT(on_evidence_right_clicked())); @@ -179,8 +179,9 @@ void Courtroom::set_evidence_page() } } -void Courtroom::on_evidence_name_edited(QString text) +void Courtroom::on_evidence_name_edited() { + ui_evidence_name->setReadOnly(true); if (current_evidence >= local_evidence_list.size()) return; @@ -206,6 +207,7 @@ void Courtroom::on_evidence_name_double_clicked() void Courtroom::on_evidence_image_name_edited() { + ui_evidence_image_name->setReadOnly(true); if (current_evidence >= local_evidence_list.size()) return; diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index 91782a8..b976434 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -432,48 +432,57 @@ QString AOApplication::get_tagged_stylesheet(QString target_tag, QString p_file) return f_text; } +QString AOApplication::get_chat_markdown(QString p_identifier, QString p_chat) +{ + QString design_ini_path = get_base_path() + "misc/" + p_chat + "/config.ini"; + QString default_path = get_base_path() + "misc/default/config.ini"; + QString f_result = read_design_ini(p_identifier, design_ini_path); + + if (f_result == "") + f_result = read_design_ini(p_identifier, default_path); + + return f_result; +} + QColor AOApplication::get_chat_color(QString p_identifier, QString p_chat) { QColor return_color(255, 255, 255); switch (p_identifier.toInt()) { - case WHITE: - case GREEN: + case 0: //White + return_color = QColor(255, 255, 255); + break; + case 1: //Green return_color = QColor(0, 255, 0); break; - case RED: + case 2: //Red return_color = QColor(255, 0, 0); break; - case ORANGE: + case 3: //Orange return_color = QColor(255, 165, 0); break; - case BLUE: + case 4: //Blue return_color = QColor(45, 150, 255); break; - case YELLOW: + case 5: //Yellow return_color = QColor(255, 255, 0); break; - case RAINBOW: // 6 is rainbow. - case PINK: + case 6: //Pink return_color = QColor(255, 192, 203); break; - case CYAN: + case 7: //Cyan return_color = QColor(0, 255, 255); break; - case GRAY: + case 8: //Grey return_color = QColor(187, 187, 187); break; - case BLANK: - return_color = QColor(0, 0, 0, 0); - break; default: return_color = QColor(255, 255, 255); break; } - p_identifier = p_identifier.prepend("c"); QString design_ini_path = get_base_path() + "misc/" + p_chat + "/config.ini"; QString default_path = get_base_path() + "misc/default/config.ini"; - QString f_result = read_design_ini(p_identifier, design_ini_path); + QString f_result = read_design_ini("c" + p_identifier, design_ini_path); if (f_result == "") { @@ -567,18 +576,20 @@ void AOApplication::set_char_ini(QString p_char, QString value, QString p_search } //returns all the values of target_tag -QStringList AOApplication::read_char_ini_tag(QString p_char, QString target_tag) +QStringList AOApplication::read_ini_tags(QString p_path, QString target_tag) { QStringList r_values; - QSettings settings(get_character_path(p_char, "char.ini"), QSettings::IniFormat); - settings.beginGroup(target_tag); + QSettings settings(p_path, QSettings::IniFormat); + if (!target_tag.isEmpty()) + settings.beginGroup(target_tag); QStringList keys = settings.allKeys(); foreach (QString key, keys) { QString value = settings.value(key).toString(); r_values << key + "=" + value; } - settings.endGroup(); + if (!settings.group().isEmpty()) + settings.endGroup(); return r_values; } From a028b8496e6684f89efc3b8bf7946fb5901faa99 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Wed, 25 Sep 2019 03:39:32 +0300 Subject: [PATCH 083/268] Fix objections botching up single frame preanims, etc. --- src/aocharmovie.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/aocharmovie.cpp b/src/aocharmovie.cpp index e8dc8fc..5294b23 100644 --- a/src/aocharmovie.cpp +++ b/src/aocharmovie.cpp @@ -154,8 +154,8 @@ void AOCharMovie::play() play_frame_effect(frame); if (max_frames <= 1) { - play_once = true; - ticker->start(60); + if (play_once) + ticker->start(60); } else ticker->start(this->get_frame_delay(movie_delays[frame])); @@ -316,6 +316,7 @@ void AOCharMovie::movie_ticker() void AOCharMovie::preanim_done() { + ticker->stop(); preanim_timer->stop(); done(); } From b67f083506803c3cf075e8872cacb329b063e8b3 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Wed, 25 Sep 2019 03:40:44 +0300 Subject: [PATCH 084/268] Optimize color markdown stuff properly by creating lists and preloading things --- include/courtroom.h | 25 +++++++++++- src/courtroom.cpp | 95 +++++++++++++++++++++++++-------------------- 2 files changed, 76 insertions(+), 44 deletions(-) diff --git a/include/courtroom.h b/include/courtroom.h index 72dec04..d6bf451 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -354,8 +354,29 @@ private: int realization_state = 0; int screenshake_state = 0; int text_color = 0; - static const int max_colors = 12; //How many unique user colors are possible - QVector color_row_to_number; //Current color list indexes to real color references + + //How many unique user colors are possible + static const int max_colors = 12; + + //Text Color-related optimization: + //Current color list indexes to real color references + QVector color_row_to_number; + + //List of associated RGB colors for this color index + QVector color_rgb_list; + + //List of markdown start characters, their index is tied to the color index + QStringList color_markdown_start_list; + + //List of markdown end characters, their index is tied to the color index + QStringList color_markdown_end_list; + + //Whether or not we're supposed to remove this char during parsing + QVector color_markdown_remove_list; + + //Whether or not this color allows us to play the talking animation + QVector color_markdown_talking_list; + //Text Color-related optimization END bool is_presenting_evidence = false; diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 3ff1aa2..2ae611a 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1014,7 +1014,6 @@ void Courtroom::set_side(QString p_side) else current_side = p_side; - qDebug() << current_side; for (int i = 0; i < ui_pos_dropdown->count(); ++i) { QString pos = ui_pos_dropdown->itemText(i); @@ -2050,6 +2049,22 @@ void Courtroom::handle_chatmessage_3() } + //If this color is talking + bool color_is_talking = ao_app->get_chat_markdown("c" + m_chatmessage[TEXT_COLOR] + "_talking", m_chatmessage[CHAR_NAME]) == "1"; + + if (color_is_talking && text_state == 1 && anim_state < 2) //Set it to talking as we're not on that already + { + ui_vp_player_char->stop(); + ui_vp_player_char->play_talking(m_chatmessage[CHAR_NAME], m_chatmessage[EMOTE]); + anim_state = 2; + } + else if (anim_state < 3) //Set it to idle as we're not on that already + { + ui_vp_player_char->stop(); + ui_vp_player_char->play_idle(m_chatmessage[CHAR_NAME], m_chatmessage[EMOTE]); + anim_state = 3; + } + QString f_message = m_chatmessage[MESSAGE]; QStringList call_words = ao_app->get_call_words(); @@ -2080,8 +2095,7 @@ QString Courtroom::filter_ic_text(QString p_text, bool colorize, int pos, int de if (colorize) { ic_color_stack.push(default_color); - qDebug() << ic_color_stack.top(); - QString appendage = "get_chat_color(QString::number(ic_color_stack.top()), m_chatmessage[CHAR_NAME]).name(QColor::HexRgb) +"\">"; + QString appendage = ""; p_text.insert(check_pos, appendage); check_pos += appendage.size(); if (pos > -1) @@ -2116,11 +2130,13 @@ QString Courtroom::filter_ic_text(QString p_text, bool colorize, int pos, int de //Parse markdown colors for (int c = 0; c < max_colors; ++c) { - QString markdown_start = ao_app->get_chat_markdown("c" + QString::number(c) + "_start", m_chatmessage[CHAR_NAME]); + //Clear the stored optimization information + QString markdown_start = color_markdown_start_list.at(c); + QString markdown_end = color_markdown_end_list.at(c); + bool markdown_remove = color_markdown_remove_list.at(c); +// bool is_talking = color_markdown_talking_list.at(c); if (markdown_start.isEmpty()) //Not defined continue; - QString markdown_end = ao_app->get_chat_markdown("c" + QString::number(c) + "_end", m_chatmessage[CHAR_NAME]); - bool markdown_remove = ao_app->get_chat_markdown("c" + QString::number(c) + "_remove", m_chatmessage[CHAR_NAME]) == "1"; if (markdown_end.isEmpty() || markdown_end == markdown_start) //"toggle switch" type { @@ -2167,7 +2183,7 @@ QString Courtroom::filter_ic_text(QString p_text, bool colorize, int pos, int de QString appendage = ""; if (!ic_color_stack.empty()) - appendage += "get_chat_color(QString::number(ic_color_stack.top()), m_chatmessage[CHAR_NAME]).name(QColor::HexRgb) +"\">"; + appendage += ""; if (!is_end || remove) { @@ -2317,7 +2333,6 @@ void Courtroom::append_ic_text(QString p_text, QString p_name, bool is_songchang ui_ic_chatlog->textCursor().select(QTextCursor::BlockUnderCursor); ui_ic_chatlog->textCursor().removeSelectedText(); ui_ic_chatlog->textCursor().deletePreviousChar(); - //qDebug() << ui_ic_chatlog->document()->blockCount() << " < " << log_maximum_blocks; } if (old_cursor.hasSelection() || !is_scrolled_up) @@ -2395,7 +2410,6 @@ void Courtroom::start_chat_ticking() if (m_chatmessage[EFFECTS] != "") { QStringList fx_list = m_chatmessage[EFFECTS].split("|"); -// qDebug() << m_chatmessage[EFFECTS] << fx_list; QString fx = fx_list[0]; QString fx_sound; if (fx_list.length() > 1) @@ -2443,22 +2457,6 @@ void Courtroom::start_chat_ticking() //means text is currently ticking text_state = 1; - - //If this color is talking - bool color_is_talking = ao_app->get_chat_markdown("c" + m_chatmessage[TEXT_COLOR] + "_talking", m_chatmessage[CHAR_NAME]) == "1"; - - if (color_is_talking && text_state == 1 && anim_state < 2) //Set it to talking as we're not on that already - { -// ui_vp_player_char->stop(); - ui_vp_player_char->play_talking(m_chatmessage[CHAR_NAME], m_chatmessage[EMOTE]); - anim_state = 2; - } - else if (anim_state < 3) //Set it to idle as we're not on that already - { -// ui_vp_player_char->stop(); - ui_vp_player_char->play_idle(m_chatmessage[CHAR_NAME], m_chatmessage[EMOTE]); - anim_state = 3; - } } void Courtroom::chat_tick() @@ -2473,7 +2471,7 @@ void Courtroom::chat_tick() // Stops blips from playing when we have a formatting option. bool formatting_char = false; - bool is_talking = ao_app->get_chat_markdown("c" + m_chatmessage[TEXT_COLOR] + "_talking", m_chatmessage[CHAR_NAME]) == "1"; + bool is_talking = color_markdown_talking_list.at(m_chatmessage[TEXT_COLOR].toInt()); if (tick_pos >= f_message.size()) { @@ -2487,8 +2485,8 @@ void Courtroom::chat_tick() QString f_custom_theme = ao_app->get_char_shouts(f_char); ui_vp_chat_arrow->play("chat_arrow", f_char, f_custom_theme); //Chat stopped being processed, indicate that. additive_previous = additive_previous + filter_ic_text(f_message, true, -1, m_chatmessage[TEXT_COLOR].toInt()); + return; } - else { QString f_rest = f_message; @@ -2547,12 +2545,14 @@ void Courtroom::chat_tick() //Parse markdown colors for (int c = 0; c < max_colors; ++c) { - QString markdown_start = ao_app->get_chat_markdown("c" + QString::number(c) + "_start", m_chatmessage[CHAR_NAME]); + //Clear the stored optimization information +// color_rgb_list.at(c); + QString markdown_start = color_markdown_start_list.at(c); + QString markdown_end = color_markdown_end_list.at(c); + bool markdown_remove = color_markdown_remove_list.at(c); + bool color_is_talking = color_markdown_talking_list.at(c); if (markdown_start.isEmpty()) continue; - QString markdown_end = ao_app->get_chat_markdown("c" + QString::number(c) + "_end", m_chatmessage[CHAR_NAME]); - bool markdown_remove = ao_app->get_chat_markdown("c" + QString::number(c) + "_remove", m_chatmessage[CHAR_NAME]) == "1"; - bool color_is_talking = ao_app->get_chat_markdown("c" + QString::number(c) + "_talking", m_chatmessage[CHAR_NAME]) == "1"; if (markdown_remove && (f_character == markdown_start || f_character == markdown_end)) { @@ -2606,13 +2606,13 @@ void Courtroom::chat_tick() //If this color is talking if (is_talking && text_state == 1 && anim_state < 2) //Set it to talking as we're not on that already { -// ui_vp_player_char->stop(); + ui_vp_player_char->stop(); ui_vp_player_char->play_talking(m_chatmessage[CHAR_NAME], m_chatmessage[EMOTE]); anim_state = 2; } else if (anim_state < 3) //Set it to idle as we're not on that already { -// ui_vp_player_char->stop(); + ui_vp_player_char->stop(); ui_vp_player_char->play_idle(m_chatmessage[CHAR_NAME], m_chatmessage[EMOTE]); anim_state = 3; } @@ -3810,22 +3810,33 @@ void Courtroom::on_prosecution_plus_clicked() void Courtroom::set_text_color_dropdown() { + //Clear the lists ui_text_color->clear(); color_row_to_number.clear(); - //Set the default color 0 - QString c0_name = ao_app->get_chat_markdown("c0_name", current_char); - if (c0_name.isEmpty()) - c0_name = tr("Default"); - ui_text_color->addItem(c0_name); - color_row_to_number.append(0); + //Clear the stored optimization information + color_rgb_list.clear(); + color_markdown_start_list.clear(); + color_markdown_end_list.clear(); + color_markdown_remove_list.clear(); + color_markdown_talking_list.clear(); - //Set the rest of the colors - for (int c = 1; c < max_colors; ++c) + //Update markdown colors. TODO: make a loading function that only loads the config file once instead of several times + for (int c = 0; c < max_colors; ++c) { + color_rgb_list.append(ao_app->get_chat_color(QString::number(c), current_char)); + color_markdown_start_list.append(ao_app->get_chat_markdown("c" + QString::number(c) + "_start", current_char)); + color_markdown_end_list.append(ao_app->get_chat_markdown("c" + QString::number(c) + "_end", current_char)); + color_markdown_remove_list.append(ao_app->get_chat_markdown("c" + QString::number(c) + "_remove", current_char) == "1"); + color_markdown_talking_list.append(ao_app->get_chat_markdown("c" + QString::number(c) + "_talking", current_char) == "1"); + QString color_name = ao_app->get_chat_markdown("c" + QString::number(c) + "_name", current_char); if (color_name.isEmpty()) //Not defined - continue; + { + if (c > 0) + continue; + color_name = tr("Default"); + } ui_text_color->addItem(color_name); color_row_to_number.append(c); } From 0649884d3c9ceeef5515d621e9867dfc08df59ba Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Wed, 25 Sep 2019 04:45:45 +0300 Subject: [PATCH 085/268] Fix issue with ao line edit not correctly preserving selection Resolve a segfault with text formatting Implement ability to color text inline by selecting text and using the color dropdown TODO: allow html characters to be used for coloring text, oof --- src/aolineedit.cpp | 6 +++--- src/courtroom.cpp | 25 ++++++++++++++++++++----- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/aolineedit.cpp b/src/aolineedit.cpp index e345de3..56b571f 100644 --- a/src/aolineedit.cpp +++ b/src/aolineedit.cpp @@ -13,8 +13,8 @@ void AOLineEdit::mouseDoubleClickEvent(QMouseEvent *e) void AOLineEdit::focusOutEvent(QFocusEvent *ev) { int start = selectionStart(); - int end = selectionEnd(); + int len = selectionLength(); QLineEdit::focusOutEvent(ev); - if (p_selection && start != -1 && end != -1) - this->setSelection(start, end); + if (p_selection && start != -1 && len != -1) + this->setSelection(start, len); } diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 2ae611a..75ce54d 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -2156,7 +2156,7 @@ QString Courtroom::filter_ic_text(QString p_text, bool colorize, int pos, int de break; //Prevent it from looping forward for whatever reason } } - else if (f_character == markdown_start || (f_character == markdown_end && ic_color_stack.top() == c)) + else if (f_character == markdown_start || (f_character == markdown_end && !ic_color_stack.empty() && ic_color_stack.top() == c)) { if (colorize) { @@ -2547,8 +2547,8 @@ void Courtroom::chat_tick() { //Clear the stored optimization information // color_rgb_list.at(c); - QString markdown_start = color_markdown_start_list.at(c); - QString markdown_end = color_markdown_end_list.at(c); + QString markdown_start = color_markdown_start_list.at(c).toHtmlEscaped(); + QString markdown_end = color_markdown_end_list.at(c).toHtmlEscaped(); bool markdown_remove = color_markdown_remove_list.at(c); bool color_is_talking = color_markdown_talking_list.at(c); if (markdown_start.isEmpty()) @@ -3846,8 +3846,23 @@ void Courtroom::on_text_color_changed(int p_color) { if (ui_ic_chat_message->selectionStart() != -1) //We have a selection! { - qDebug() << "Setting color to selection" << ui_ic_chat_message->selectionStart() << ui_ic_chat_message->selectionEnd(); - ui_ic_chat_message->end(false); + int c = color_row_to_number.at(p_color); + QString markdown_start = color_markdown_start_list.at(c); + if (markdown_start.isEmpty()) + { + qDebug() << "W: Color list dropdown selected a non-existent markdown start character"; + return; + } + QString markdown_end = color_markdown_end_list.at(c); + if (markdown_end.isEmpty()) + markdown_end = markdown_start; + int start = ui_ic_chat_message->selectionStart(); + int end = ui_ic_chat_message->selectionEnd()+1; + ui_ic_chat_message->setCursorPosition(start); + ui_ic_chat_message->insert(markdown_start); + ui_ic_chat_message->setCursorPosition(end); + ui_ic_chat_message->insert(markdown_end); +// ui_ic_chat_message->end(false); ui_text_color->setCurrentIndex(0); } else From c38061a9904e9992d53f7cdf2ab9bf6e789cf0de Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Wed, 25 Sep 2019 04:58:38 +0300 Subject: [PATCH 086/268] help me jesus HTML gotta be like escaped n shit --- src/courtroom.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 75ce54d..ace957a 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -2102,6 +2102,8 @@ QString Courtroom::filter_ic_text(QString p_text, bool colorize, int pos, int de pos += appendage.size(); } + //Current issue: does not properly escape html stuff. + //Solution: probably parse p_text and export into a different string separately, perform some mumbo jumbo to properly adjust string indexes. while (check_pos < p_text.size()) { f_character = p_text.at(check_pos); From a3d1d5bf9d195969cf9a1cd55b59316dd262ab0b Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Fri, 27 Sep 2019 15:11:46 +0300 Subject: [PATCH 087/268] i did it i did the thing Final overhaul of filter_ic_text Fix spoken colors not being actually spoken Fix a message of ()()()() spamming idle/talking animations (instead it just does the idle animation until you feed it an actual character) Prevent spamming of play_idle and play_talking on the fastest text speed Properly escape html and construct a message that works with characters &, <, >, ", etc. for filter_ic_text Turn whitespace into html entities to prevent html from eating it up (alternative/better solution would be to erase excessive whitespace entirely but yaknow, some niche applications, whatever) Fix filter_ic_text not displaying the best string it could in ic logs (strip html, display newlines as \n, etc.) Scroll the scrollbar of the message box correctly according to some real wacky magic stuff I'm doing here. Let's hope there's no situations where it desyncs from the actual text. --- include/courtroom.h | 7 +- src/courtroom.cpp | 484 +++++++++++++++++++++++++------------------- 2 files changed, 280 insertions(+), 211 deletions(-) diff --git a/include/courtroom.h b/include/courtroom.h index d6bf451..476fd11 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -291,8 +291,10 @@ private: //int chat_tick_interval = 60; //which tick position(character in chat message) we are at int tick_pos = 0; + //the actual document tick pos we gotta worry about for making the text scroll better + int real_tick_pos = 0; //used to determine how often blips sound - int blip_pos = 0; + int blip_ticker = 0; int blip_rate = 1; int rainbow_counter = 0; bool rainbow_appended = false; @@ -342,6 +344,9 @@ private: //state of animation, 0 = objecting, 1 = preanim, 2 = talking, 3 = idle, 4 = noniterrupting preanim int anim_state = 3; + //whether or not current color is a talking one + bool color_is_talking = true; + //state of text ticking, 0 = not yet ticking, 1 = ticking in progress, 2 = ticking done int text_state = 2; diff --git a/src/courtroom.cpp b/src/courtroom.cpp index ace957a..327f4de 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -145,6 +145,7 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_ic_chat_message->setFrame(false); ui_ic_chat_message->setPlaceholderText(tr("Message")); ui_ic_chat_message->preserve_selection(true); + //todo: filter out \n from showing up as that commonly breaks the chatlog and can be spammed to hell ui_muted = new AOImage(ui_ic_chat_message, ao_app); ui_muted->hide(); @@ -1593,10 +1594,12 @@ void Courtroom::handle_chatmessage(QStringList *p_contents) chat_tick_timer->stop(); ui_vp_evidence_display->reset(); + m_chatmessage[MESSAGE].remove("\n"); //Remove undesired newline chars + chatmessage_is_empty = m_chatmessage[MESSAGE] == " " || m_chatmessage[MESSAGE] == ""; //Hey, our message showed up! Cool! - if (m_chatmessage[MESSAGE] == ui_ic_chat_message->text() && m_chatmessage[CHAR_ID].toInt() == m_cid) + if (m_chatmessage[MESSAGE] == ui_ic_chat_message->text().remove("\n") && m_chatmessage[CHAR_ID].toInt() == m_cid) { ui_ic_chat_message->clear(); if (ui_additive->isChecked()) @@ -2050,7 +2053,7 @@ void Courtroom::handle_chatmessage_3() } //If this color is talking - bool color_is_talking = ao_app->get_chat_markdown("c" + m_chatmessage[TEXT_COLOR] + "_talking", m_chatmessage[CHAR_NAME]) == "1"; + color_is_talking = color_markdown_talking_list.at(m_chatmessage[TEXT_COLOR].toInt()); if (color_is_talking && text_state == 1 && anim_state < 2) //Set it to talking as we're not on that already { @@ -2081,150 +2084,185 @@ void Courtroom::handle_chatmessage_3() } -QString Courtroom::filter_ic_text(QString p_text, bool colorize, int pos, int default_color) +QString Courtroom::filter_ic_text(QString p_text, bool html, int target_pos, int default_color) { // Get rid of centering. if(p_text.startsWith("~~")) p_text.remove(0,2); + p_text.remove("\n"); //Undesired newline chars, probably from copy-pasting it from a doc or something. + + QString p_text_escaped; + int check_pos = 0; + int check_pos_escaped = 0; bool ic_next_is_not_special = false; - QString f_character = p_text.at(check_pos); std::stack ic_color_stack; - if (colorize) + if (html) { ic_color_stack.push(default_color); QString appendage = ""; - p_text.insert(check_pos, appendage); - check_pos += appendage.size(); - if (pos > -1) - pos += appendage.size(); + p_text_escaped.insert(check_pos_escaped, appendage); + check_pos_escaped += appendage.size(); } //Current issue: does not properly escape html stuff. //Solution: probably parse p_text and export into a different string separately, perform some mumbo jumbo to properly adjust string indexes. while (check_pos < p_text.size()) { - f_character = p_text.at(check_pos); + QString f_rest = p_text.right(p_text.size() - check_pos); + QTextBoundaryFinder tbf(QTextBoundaryFinder::Grapheme, f_rest); + QString f_character; + int f_char_length; + + tbf.toNextBoundary(); + + if (tbf.position() == -1) + f_character = f_rest; + else + f_character = f_rest.left(tbf.position()); + +// if (f_character == "&") //oh shit it's probably an escaped html +// { +// //Skip escaped chars like you would graphemes +// QRegularExpression re("&([a-z0-9]+|#[0-9]{1,6}|#x[0-9a-f]{1,6});", QRegularExpression::CaseInsensitiveOption); +// QRegularExpressionMatch match = re.match(f_rest); +// if (match.hasMatch()) //OH SHIT IT IS, PANIC, PANIC +// { +// f_character = match.captured(0); //Phew, we solved the big problem here. +// } +// } + + f_character = f_character.toHtmlEscaped(); + + if (f_character == " " && html) //Whitespace, woah + f_character = " "; //Turn it into an HTML entity + f_char_length = f_character.length(); + bool color_update = false; + bool is_end = false; + bool skip = false; if (!ic_next_is_not_special) { if (f_character == "\\") { ic_next_is_not_special = true; - p_text.remove(check_pos, 1); - check_pos -= 1; - pos -= 1; + skip = true; } - //Nothing related to colors here else if (f_character == "{" || f_character == "}" || f_character == "@" || f_character == "$") { - p_text.remove(check_pos, 1); - check_pos -= 1; - pos -= 1; + skip = true; } - - bool is_end = false; - bool remove = false; //Parse markdown colors - for (int c = 0; c < max_colors; ++c) + else { - //Clear the stored optimization information - QString markdown_start = color_markdown_start_list.at(c); - QString markdown_end = color_markdown_end_list.at(c); - bool markdown_remove = color_markdown_remove_list.at(c); -// bool is_talking = color_markdown_talking_list.at(c); - if (markdown_start.isEmpty()) //Not defined - continue; - - if (markdown_end.isEmpty() || markdown_end == markdown_start) //"toggle switch" type + for (int c = 0; c < max_colors; ++c) { - if (f_character == markdown_start) + //Clear the stored optimization information + QString markdown_start = color_markdown_start_list.at(c).toHtmlEscaped(); + QString markdown_end = color_markdown_end_list.at(c).toHtmlEscaped(); + bool markdown_remove = color_markdown_remove_list.at(c); + if (markdown_start.isEmpty()) //Not defined + continue; + + if (markdown_end.isEmpty() || markdown_end == markdown_start) //"toggle switch" type { - if (colorize) + if (f_character == markdown_start) { - if (!ic_color_stack.empty() && ic_color_stack.top() == c && default_color != c) + if (html) + { + if (!ic_color_stack.empty() && ic_color_stack.top() == c && default_color != c) + { + ic_color_stack.pop(); //Cease our coloring + is_end = true; + } + else + { + ic_color_stack.push(c); //Begin our coloring + } + color_update = true; + } + skip = markdown_remove; + break; //Prevent it from looping forward for whatever reason + } + } + else if (f_character == markdown_start || (f_character == markdown_end && !ic_color_stack.empty() && ic_color_stack.top() == c)) + { + if (html) + { + if (f_character == markdown_end) + { ic_color_stack.pop(); //Cease our coloring - else + is_end = true; + } + else if (f_character == markdown_start) { ic_color_stack.push(c); //Begin our coloring } color_update = true; } - remove = markdown_remove; + skip = markdown_remove; break; //Prevent it from looping forward for whatever reason } } - else if (f_character == markdown_start || (f_character == markdown_end && !ic_color_stack.empty() && ic_color_stack.top() == c)) + //Parse the newest color stack + if (color_update && (target_pos <= -1 || check_pos < target_pos)) { - if (colorize) + if (!ic_next_is_not_special) { - if (f_character == markdown_start) + QString appendage = ""; + + if (!ic_color_stack.empty()) + appendage += ""; + + if (is_end && !skip) { - ic_color_stack.push(c); //Begin our coloring + p_text_escaped.insert(check_pos_escaped, f_character); //Add that char right now + check_pos_escaped += f_char_length; //So the closing char is captured too + skip = true; } - else if (f_character == markdown_end) - { - ic_color_stack.pop(); //Cease our coloring - is_end = true; - } - color_update = true; + p_text_escaped.insert(check_pos_escaped, appendage); + check_pos_escaped += appendage.size(); } - remove = markdown_remove; - break; //Prevent it from looping forward for whatever reason } } - //Parse the newest color stack - if (color_update) - { - if (!ic_next_is_not_special && (pos <= -1 || check_pos < pos)) //Only color text if we haven't reached the "invisible threshold" - { - QString appendage = ""; - - if (!ic_color_stack.empty()) - appendage += ""; - - if (!is_end || remove) - { - if (remove) - p_text.remove(check_pos, 1); - - p_text.insert(check_pos, appendage); - - if (remove) - { - check_pos -= 1; - pos -= 1; - } - } - else - { - p_text.insert(check_pos+1, appendage); - } - check_pos += appendage.size(); - if (pos > -1) - pos += appendage.size(); - } - } - else if (remove) //Simple remove request - { - p_text.remove(check_pos, 1); - check_pos -= 1; - pos -= 1; - } } else + { + if (f_character == "n") // \n, that's a line break son + { + QString appendage = "
"; + if (!html) + { + //actual newline commented out +// appendage = "\n"; +// size = 1; //yeah guess what \n is a "single character" apparently + appendage = "\\n "; //visual representation of a newline + } + p_text_escaped.insert(check_pos_escaped, appendage); + check_pos_escaped += appendage.size(); + skip = true; + } + ic_next_is_not_special = false; + } //Make all chars we're not supposed to see invisible - if (pos > -1 && check_pos == pos) + if (target_pos > -1 && check_pos == target_pos) { QString appendage = ""; if (!ic_color_stack.empty()) { + if (!is_end) //Was our last coloring char ending the color stack or nah + { + //God forgive me for my transgressions but I have refactored this whole thing about 25 times and having to refactor it + //again to more elegantly support this will finally make me go insane. + color_is_talking = color_markdown_talking_list.at(ic_color_stack.top()); + } + //Clean it up, we're done here while (!ic_color_stack.empty()) ic_color_stack.pop(); @@ -2233,17 +2271,23 @@ QString Courtroom::filter_ic_text(QString p_text, bool colorize, int pos, int de } ic_color_stack.push(-1); //Dummy colorstack push for maximum
appendage appendage += ""; - p_text.insert(check_pos, appendage); + p_text_escaped.insert(check_pos_escaped, appendage); + check_pos_escaped += appendage.size(); + } + if (!skip) + { + p_text_escaped.insert(check_pos_escaped, f_character); + check_pos_escaped += f_char_length; } check_pos += 1; } if (!ic_color_stack.empty()) { - p_text.append(""); + p_text_escaped.append("
"); } - return p_text; + return p_text_escaped; } void Courtroom::append_ic_text(QString p_text, QString p_name, bool is_songchange) @@ -2258,7 +2302,7 @@ void Courtroom::append_ic_text(QString p_text, QString p_name, bool is_songchang const int old_scrollbar_value = ui_ic_chatlog->verticalScrollBar()->value(); if (!is_songchange) - p_text = filter_ic_text(p_text); + p_text = filter_ic_text(p_text, false); if (log_goes_downwards) { @@ -2443,11 +2487,12 @@ void Courtroom::start_chat_ticking() if (!is_additive) { ui_vp_message->clear(); + real_tick_pos = 0; additive_previous = ""; } tick_pos = 0; - blip_pos = 0; + blip_ticker = 0; // At the start of every new message, we set the text speed to the default. current_display_speed = 3; @@ -2471,14 +2516,10 @@ void Courtroom::chat_tick() // Due to our new text speed system, we always need to stop the timer now. chat_tick_timer->stop(); - // Stops blips from playing when we have a formatting option. - bool formatting_char = false; - bool is_talking = color_markdown_talking_list.at(m_chatmessage[TEXT_COLOR].toInt()); - if (tick_pos >= f_message.size()) { text_state = 2; - if (anim_state != 4) + if (anim_state < 3) { anim_state = 3; ui_vp_player_char->play_idle(m_chatmessage[CHAR_NAME], m_chatmessage[EMOTE]); @@ -2487,141 +2528,164 @@ void Courtroom::chat_tick() QString f_custom_theme = ao_app->get_char_shouts(f_char); ui_vp_chat_arrow->play("chat_arrow", f_char, f_custom_theme); //Chat stopped being processed, indicate that. additive_previous = additive_previous + filter_ic_text(f_message, true, -1, m_chatmessage[TEXT_COLOR].toInt()); + real_tick_pos = ui_vp_message->toPlainText().size(); + + QScrollBar *scroll = ui_vp_message->verticalScrollBar(); + scroll->setValue(scroll->maximum()); return; } + + // Stops blips from playing when we have a formatting option. + bool formatting_char = false; + + QString f_rest = f_message; + f_rest.remove(0, tick_pos); + QTextBoundaryFinder tbf(QTextBoundaryFinder::Grapheme, f_rest); + QString f_character; + int f_char_length; + + tbf.toNextBoundary(); + + if (tbf.position() == -1) + f_character = f_rest; else + f_character = f_rest.left(tbf.position()); + + f_char_length = f_character.length(); + + // Escape character. + if (!next_character_is_not_special) { - QString f_rest = f_message; - f_rest.remove(0, tick_pos); - QTextBoundaryFinder tbf(QTextBoundaryFinder::Grapheme, f_rest); - QString f_character; - int f_char_length; - - tbf.toNextBoundary(); - - if (tbf.position() == -1) - f_character = f_rest; - else - f_character = f_rest.left(tbf.position()); - - f_char_length = f_character.length(); - f_character = f_character.toHtmlEscaped(); - - // Escape character. - if (!next_character_is_not_special) + if (f_character == "\\") { - if (f_character == "\\") - { - next_character_is_not_special = true; - formatting_char = true; - } + next_character_is_not_special = true; + formatting_char = true; + } - // Text speed modifier. - else if (f_character == "{") - { - // ++, because it INCREASES delay! - current_display_speed++; - formatting_char = true; - } - else if (f_character == "}") - { - current_display_speed--; - formatting_char = true; - } + // Text speed modifier. + else if (f_character == "{") + { + // ++, because it INCREASES delay! + current_display_speed++; + formatting_char = true; + } + else if (f_character == "}") + { + current_display_speed--; + formatting_char = true; + } - //Screenshake. - else if (f_character == "@") - { - this->do_screenshake(); - formatting_char = true; - } + //Screenshake. + else if (f_character == "@") + { + this->do_screenshake(); + formatting_char = true; + } - //Flash. - else if (f_character == "$") + //Flash. + else if (f_character == "$") + { + this->do_flash(); + formatting_char = true; + } + else + { + //Parse markdown colors + for (int c = 0; c < max_colors; ++c) { - this->do_flash(); - formatting_char = true; - } - else - { - //Parse markdown colors - for (int c = 0; c < max_colors; ++c) + QString markdown_start = color_markdown_start_list.at(c); + QString markdown_end = color_markdown_end_list.at(c); + bool markdown_remove = color_markdown_remove_list.at(c); + if (markdown_start.isEmpty()) + continue; + + if (f_character == markdown_start || f_character == markdown_end) { - //Clear the stored optimization information -// color_rgb_list.at(c); - QString markdown_start = color_markdown_start_list.at(c).toHtmlEscaped(); - QString markdown_end = color_markdown_end_list.at(c).toHtmlEscaped(); - bool markdown_remove = color_markdown_remove_list.at(c); - bool color_is_talking = color_markdown_talking_list.at(c); - if (markdown_start.isEmpty()) - continue; - - if (markdown_remove && (f_character == markdown_start || f_character == markdown_end)) - { + if (markdown_remove) formatting_char = true; - is_talking = color_is_talking; - break; - } + break; } } } - else - next_character_is_not_special = false; + } + else + { + if (f_character == "n") + formatting_char = true; //it's a newline + next_character_is_not_special = false; + } - tick_pos += f_char_length; + tick_pos += f_char_length; - //Do the colors, gradual showing, etc. in here - ui_vp_message->setHtml(additive_previous + filter_ic_text(f_message, true, tick_pos, m_chatmessage[TEXT_COLOR].toInt())); + //Do the colors, gradual showing, etc. in here + ui_vp_message->setHtml(additive_previous + filter_ic_text(f_message, true, tick_pos, m_chatmessage[TEXT_COLOR].toInt())); - //If the text overflows, make it snap to bottom - QScrollBar *scroll = ui_vp_message->verticalScrollBar(); - scroll->setValue(scroll->maximum()); + if (!formatting_char || f_character == "n") //NEWLINES (\n) COUNT AS A SINGLE CHARACTER. + { + //Make the cursor follow the message + QTextCursor cursor = ui_vp_message->textCursor(); + cursor.setPosition(real_tick_pos); + ui_vp_message->setTextCursor(cursor); + real_tick_pos += f_char_length; + } + ui_vp_message->ensureCursorVisible(); - // Restart the timer, but according to the newly set speeds, if there were any. - // Keep the speed at bay. - if (current_display_speed < 0) +// //Grab the currently displayed chars +// f_rest = f_message.left(tick_pos); +// f_rest.replace("\\n", "\n"); + +// QFontMetrics fm = fontMetrics(); +// QRect bounding_rect = fm.boundingRect(QRect(0,0,ui_vp_message->width(),ui_vp_message->height()), Qt::TextWordWrap, f_rest); + +// //If the text overflows, make it snap to bottom +// if (bounding_rect.height() > ui_vp_message->height()) +// { + +// QScrollBar *scroll = ui_vp_message->verticalScrollBar(); +// scroll->value(); +// scroll->setValue(scroll->maximum()); +// } + + // Keep the speed at bay. + if (current_display_speed < 0) + current_display_speed = 0; + else if (current_display_speed > 6) + current_display_speed = 6; + + //Blip player and real tick pos ticker + if (!formatting_char && (f_character != ' ' || blank_blip)) + { + if (blip_ticker % blip_rate == 0) { - current_display_speed = 0; + blip_player->blip_tick(); + } + ++blip_ticker; + } + + // If we had a formatting char, we shouldn't wait so long again, as it won't appear! + // Additionally, if the message_display_speed length is too short for us to do anything (play animations, etc.) then skip the trouble and don't bother. + if (formatting_char || message_display_speed[current_display_speed] <= 0) + { + chat_tick_timer->start(0); + } + else + { + //If this color is talking + if (color_is_talking && anim_state != 2 && anim_state < 4) //Set it to talking as we're not on that already (though we have to avoid interrupting a non-interrupted preanim) + { + ui_vp_player_char->stop(); + ui_vp_player_char->play_talking(m_chatmessage[CHAR_NAME], m_chatmessage[EMOTE]); + anim_state = 2; + } + else if (!color_is_talking && anim_state < 3 && anim_state != 3) //Set it to idle as we're not on that already + { + ui_vp_player_char->stop(); + ui_vp_player_char->play_idle(m_chatmessage[CHAR_NAME], m_chatmessage[EMOTE]); + anim_state = 3; } - if (current_display_speed > 6) - { - current_display_speed = 6; - } - - if (!formatting_char && (f_character != ' ' || blank_blip)) - { - if (blip_pos % blip_rate == 0) - { - blip_player->blip_tick(); - } - ++blip_pos; - } - - // If we had a formatting char, we shouldn't wait so long again, as it won't appear! - if (formatting_char) - { - chat_tick_timer->start(0); - } - else - { - //If this color is talking - if (is_talking && text_state == 1 && anim_state < 2) //Set it to talking as we're not on that already - { - ui_vp_player_char->stop(); - ui_vp_player_char->play_talking(m_chatmessage[CHAR_NAME], m_chatmessage[EMOTE]); - anim_state = 2; - } - else if (anim_state < 3) //Set it to idle as we're not on that already - { - ui_vp_player_char->stop(); - ui_vp_player_char->play_idle(m_chatmessage[CHAR_NAME], m_chatmessage[EMOTE]); - anim_state = 3; - } - - //Continue ticking - chat_tick_timer->start(message_display_speed[current_display_speed]); - } + //Continue ticking + chat_tick_timer->start(message_display_speed[current_display_speed]); } } From 1a3d3281a79856a19339292a281e5480f4825756 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Fri, 27 Sep 2019 15:12:09 +0300 Subject: [PATCH 088/268] Display the first character of the ic message right away instead of having a delay --- src/courtroom.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 327f4de..5ffef45 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -2496,7 +2496,7 @@ void Courtroom::start_chat_ticking() // At the start of every new message, we set the text speed to the default. current_display_speed = 3; - chat_tick_timer->start(message_display_speed[current_display_speed]); + chat_tick_timer->start(0); //Display the first char right away QString f_gender = ao_app->get_gender(m_chatmessage[CHAR_NAME]); From 3c27988423cb1d9f16aa6429c8f8f17febfdd734 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Fri, 27 Sep 2019 15:48:35 +0300 Subject: [PATCH 089/268] Fix ic chatlogs displaying escaped html --- src/courtroom.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 5ffef45..dba7167 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -2134,7 +2134,8 @@ QString Courtroom::filter_ic_text(QString p_text, bool html, int target_pos, int // } // } - f_character = f_character.toHtmlEscaped(); + if (html) + f_character = f_character.toHtmlEscaped(); if (f_character == " " && html) //Whitespace, woah f_character = " "; //Turn it into an HTML entity @@ -2162,8 +2163,13 @@ QString Courtroom::filter_ic_text(QString p_text, bool html, int target_pos, int for (int c = 0; c < max_colors; ++c) { //Clear the stored optimization information - QString markdown_start = color_markdown_start_list.at(c).toHtmlEscaped(); - QString markdown_end = color_markdown_end_list.at(c).toHtmlEscaped(); + QString markdown_start = color_markdown_start_list.at(c); + QString markdown_end = color_markdown_end_list.at(c); + if (html) + { + markdown_start = markdown_start.toHtmlEscaped(); + markdown_end = markdown_end.toHtmlEscaped(); + } bool markdown_remove = color_markdown_remove_list.at(c); if (markdown_start.isEmpty()) //Not defined continue; From 8c9275c497bbd868ee133dfad73bb1dd12519b41 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Fri, 27 Sep 2019 15:52:51 +0300 Subject: [PATCH 090/268] Add cute color icons to color dropdown ui Fix current_side not using the character's preferred one after changing character Add cool tool tip describing how to do cool select+color thing Fix chatlogpiece not appending ": " in the log files --- src/chatlogpiece.cpp | 2 ++ src/courtroom.cpp | 12 +++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/chatlogpiece.cpp b/src/chatlogpiece.cpp index eb7c188..dafc354 100644 --- a/src/chatlogpiece.cpp +++ b/src/chatlogpiece.cpp @@ -69,6 +69,8 @@ QString chatlogpiece::get_full() full.append(")"); if (p_is_song) full.append(" has played a song: "); + else + full.append(": "); full.append(get_message()); return full; diff --git a/src/courtroom.cpp b/src/courtroom.cpp index dba7167..e5185eb 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -776,7 +776,8 @@ void Courtroom::set_widgets() ui_prosecution_minus->setToolTip(tr("Decrease the health bar.")); set_size_and_pos(ui_text_color, "text_color"); - ui_text_color->setToolTip(tr("Change the text color of the spoken message.")); + ui_text_color->setToolTip(tr("Change the text color of the spoken message.\n" + "You can also select a part of your currently typed message and use the dropdown to change its color!")); set_text_color_dropdown(); set_size_and_pos(ui_music_slider, "music_slider"); @@ -1059,6 +1060,7 @@ void Courtroom::update_character(int p_cid) } current_char = f_char; + current_side = ""; current_emote_page = 0; current_emote = 0; @@ -1621,7 +1623,7 @@ void Courtroom::handle_chatmessage(QStringList *p_contents) //Let the server handle actually checking if they're allowed to do this. is_additive = m_chatmessage[ADDITIVE].toInt() == 1; - chatlogpiece* temp = new chatlogpiece(ao_app->get_showname(char_list.at(f_char_id).name), f_showname, ": " + m_chatmessage[MESSAGE], false); + chatlogpiece* temp = new chatlogpiece(ao_app->get_showname(char_list.at(f_char_id).name), f_showname, m_chatmessage[MESSAGE], false); ic_chatlog_history.append(*temp); ao_app->append_to_file(temp->get_full(), ao_app->log_filename, true); @@ -3896,7 +3898,8 @@ void Courtroom::set_text_color_dropdown() //Update markdown colors. TODO: make a loading function that only loads the config file once instead of several times for (int c = 0; c < max_colors; ++c) { - color_rgb_list.append(ao_app->get_chat_color(QString::number(c), current_char)); + QColor color = ao_app->get_chat_color(QString::number(c), current_char); + color_rgb_list.append(color); color_markdown_start_list.append(ao_app->get_chat_markdown("c" + QString::number(c) + "_start", current_char)); color_markdown_end_list.append(ao_app->get_chat_markdown("c" + QString::number(c) + "_end", current_char)); color_markdown_remove_list.append(ao_app->get_chat_markdown("c" + QString::number(c) + "_remove", current_char) == "1"); @@ -3910,6 +3913,9 @@ void Courtroom::set_text_color_dropdown() color_name = tr("Default"); } ui_text_color->addItem(color_name); + QPixmap pixmap(16,16); + pixmap.fill(color); + ui_text_color->setItemIcon(ui_text_color->count() - 1, QIcon(pixmap)); color_row_to_number.append(c); } } From d3a58770d3b923d488b5df090c8e98edf5bf0b2b Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sat, 28 Sep 2019 20:22:38 +0300 Subject: [PATCH 091/268] Overhaul the evidence system: You can now press the checkmark to save evidence. The checkmark only appears when your edited evidence differs from evidence on the server. You will now be alerted if you try to exit out of the evidence with unsaved changes (pressing "X") Fix double-clicking on image name not doing anything You will now be alerted if the evidence changed as you were editing it Add tooltips Make an evidence_close function that can be referred to from multiple places --- base/themes/default/courtroom_design.ini | 5 +- include/courtroom.h | 10 +- src/courtroom.cpp | 35 ---- src/evidence.cpp | 246 ++++++++++++++++++----- 4 files changed, 211 insertions(+), 85 deletions(-) diff --git a/base/themes/default/courtroom_design.ini b/base/themes/default/courtroom_design.ini index e53eb08..b9a27a3 100644 --- a/base/themes/default/courtroom_design.ini +++ b/base/themes/default/courtroom_design.ini @@ -293,9 +293,10 @@ evidence_overlay = 24, 24, 439, 222 ; x/y coordinates 0,0 will start at top-left of the "evidence_overlay" (which is parented to "evidence_background") for everything below until specified otherwise. ; **** evidence_delete = 78, 8, 70, 20 -evidence_image_name = 150, 8, 130, 20 -evidence_image_button = 280, 8, 60, 20 +evidence_image_name = 150, 8, 109, 20 +evidence_image_button = 259, 8, 60, 20 evidence_x = 341, 8, 20, 20 +evidence_ok = 320, 8, 20, 20 evidence_button = 627, 322, 85, 18 evidence_name = 112, 4, 264, 19 evidence_description = 78, 28, 281, 166 \ No newline at end of file diff --git a/include/courtroom.h b/include/courtroom.h index 476fd11..0fc56fe 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -54,6 +54,7 @@ #include #include #include +#include #include #include @@ -554,6 +555,7 @@ private: AOLineEdit *ui_evidence_image_name; AOButton *ui_evidence_image_button; AOButton *ui_evidence_x; + AOButton *ui_evidence_ok; AOTextEdit *ui_evidence_description; AOImage *ui_char_select_background; @@ -707,11 +709,17 @@ private slots: void on_showname_enable_clicked(); void on_evidence_name_double_clicked(); + void on_evidence_image_name_double_clicked(); void on_evidence_button_clicked(); void on_evidence_delete_clicked(); void on_evidence_x_clicked(); - void on_evidence_description_edited(); + void on_evidence_ok_clicked(); + + void on_evidence_edited(); + + void evidence_close(); + bool compare_evidence_changed(evi_type evi_a, evi_type evi_b); void on_back_to_lobby_clicked(); diff --git a/src/courtroom.cpp b/src/courtroom.cpp index e5185eb..428d98c 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -784,41 +784,6 @@ void Courtroom::set_widgets() set_size_and_pos(ui_sfx_slider, "sfx_slider"); set_size_and_pos(ui_blip_slider, "blip_slider"); - set_size_and_pos(ui_evidence_button, "evidence_button"); - ui_evidence_button->set_image("evidencebutton"); - ui_evidence_button->setToolTip(tr("Bring up the Evidence screen.")); - - set_size_and_pos(ui_evidence, "evidence_background"); - ui_evidence->set_image("evidencebackground"); - - set_size_and_pos(ui_evidence_name, "evidence_name"); - - set_size_and_pos(ui_evidence_buttons, "evidence_buttons"); - - set_size_and_pos(ui_evidence_left, "evidence_left"); - ui_evidence_left->set_image("arrow_left"); - - set_size_and_pos(ui_evidence_right, "evidence_right"); - ui_evidence_right->set_image("arrow_right"); - - set_size_and_pos(ui_evidence_present, "evidence_present"); - ui_evidence_present->set_image("present_disabled"); - - set_size_and_pos(ui_evidence_overlay, "evidence_overlay"); - ui_evidence_overlay->set_image("evidenceoverlay"); - - set_size_and_pos(ui_evidence_delete, "evidence_delete"); - ui_evidence_delete->set_image("deleteevidence"); - - set_size_and_pos(ui_evidence_image_name, "evidence_image_name"); - - set_size_and_pos(ui_evidence_image_button, "evidence_image_button"); - - set_size_and_pos(ui_evidence_x, "evidence_x"); - ui_evidence_x->set_image("evidencex"); - - set_size_and_pos(ui_evidence_description, "evidence_description"); - ui_selector->set_image("char_selector"); ui_selector->hide(); diff --git a/src/evidence.cpp b/src/evidence.cpp index dfbc675..6ee2b8e 100644 --- a/src/evidence.cpp +++ b/src/evidence.cpp @@ -7,24 +7,32 @@ void Courtroom::initialize_evidence() //ui_evidence_name = new QLabel(ui_evidence); ui_evidence_name = new AOLineEdit(ui_evidence); ui_evidence_name->setAlignment(Qt::AlignCenter); + ui_evidence_name->setFrame(false); ui_evidence_buttons = new QWidget(ui_evidence); ui_evidence_left = new AOButton(ui_evidence, ao_app); ui_evidence_right = new AOButton(ui_evidence, ao_app); ui_evidence_present = new AOButton(ui_evidence, ao_app); + ui_evidence_present->setToolTip(tr("Present this piece of evidence to everyone on your next spoken message")); ui_evidence_overlay = new AOImage(ui_evidence, ao_app); ui_evidence_delete = new AOButton(ui_evidence_overlay, ao_app); + ui_evidence_delete->setToolTip(tr("Destroy this piece of evidence")); ui_evidence_image_name = new AOLineEdit(ui_evidence_overlay); ui_evidence_image_button = new AOButton(ui_evidence_overlay, ao_app); ui_evidence_image_button->setText(tr("Choose...")); ui_evidence_x = new AOButton(ui_evidence_overlay, ao_app); + ui_evidence_x->setToolTip(tr("Close the evidence display/editing overlay")); + ui_evidence_ok = new AOButton(ui_evidence_overlay, ao_app); + ui_evidence_ok->setToolTip(tr("Save any changes made to this piece of evidence")); ui_evidence_description = new AOTextEdit(ui_evidence_overlay); ui_evidence_description->setStyleSheet("background-color: rgba(0, 0, 0, 0);" "color: white;"); + ui_evidence_description->setFrameStyle(QFrame::NoFrame); + ui_evidence_description->setToolTip("Double-click to edit. Press [X] to update your changes."); connect(ui_evidence_name, SIGNAL(returnPressed()), this, SLOT(on_evidence_name_edited())); connect(ui_evidence_name, SIGNAL(double_clicked()), this, SLOT(on_evidence_name_double_clicked())); @@ -33,9 +41,14 @@ void Courtroom::initialize_evidence() connect(ui_evidence_present, SIGNAL(clicked()), this, SLOT(on_evidence_present_clicked())); connect(ui_evidence_delete, SIGNAL(clicked()), this, SLOT(on_evidence_delete_clicked())); connect(ui_evidence_image_name, SIGNAL(returnPressed()), this, SLOT(on_evidence_image_name_edited())); + connect(ui_evidence_image_name, SIGNAL(double_clicked()), this, SLOT(on_evidence_image_name_double_clicked())); connect(ui_evidence_image_button, SIGNAL(clicked()), this, SLOT(on_evidence_image_button_clicked())); connect(ui_evidence_x, SIGNAL(clicked()), this, SLOT(on_evidence_x_clicked())); - connect(ui_evidence_description, SIGNAL(textChanged()), this, SLOT(on_evidence_description_edited())); + connect(ui_evidence_ok, SIGNAL(clicked()), this, SLOT(on_evidence_ok_clicked())); + + connect(ui_evidence_name, SIGNAL(textChanged(QString)), this, SLOT(on_evidence_edited())); + connect(ui_evidence_image_name, SIGNAL(textChanged(QString)), this, SLOT(on_evidence_edited())); + connect(ui_evidence_description, SIGNAL(textChanged()), this, SLOT(on_evidence_edited())); ui_evidence->hide(); } @@ -50,9 +63,44 @@ void Courtroom::refresh_evidence() qDeleteAll(ui_evidence_list.begin(), ui_evidence_list.end()); ui_evidence_list.clear(); + set_size_and_pos(ui_evidence_button, "evidence_button"); + ui_evidence_button->set_image("evidencebutton"); + ui_evidence_button->setToolTip(tr("Bring up the Evidence screen.")); + set_size_and_pos(ui_evidence, "evidence_background"); + ui_evidence->set_image("evidencebackground"); + + set_size_and_pos(ui_evidence_name, "evidence_name"); + set_size_and_pos(ui_evidence_buttons, "evidence_buttons"); + set_size_and_pos(ui_evidence_left, "evidence_left"); + ui_evidence_left->set_image("arrow_left"); + + set_size_and_pos(ui_evidence_right, "evidence_right"); + ui_evidence_right->set_image("arrow_right"); + + set_size_and_pos(ui_evidence_present, "evidence_present"); + ui_evidence_present->set_image("present"); + + set_size_and_pos(ui_evidence_overlay, "evidence_overlay"); + ui_evidence_overlay->set_image("evidenceoverlay"); + + set_size_and_pos(ui_evidence_delete, "evidence_delete"); + ui_evidence_delete->set_image("deleteevidence"); + + set_size_and_pos(ui_evidence_image_name, "evidence_image_name"); + + set_size_and_pos(ui_evidence_image_button, "evidence_image_button"); + + set_size_and_pos(ui_evidence_x, "evidence_x"); + ui_evidence_x->set_image("evidencex"); + + set_size_and_pos(ui_evidence_ok, "evidence_ok"); + ui_evidence_ok->set_image("evidenceok"); + + set_size_and_pos(ui_evidence_description, "evidence_description"); + QPoint f_spacing = ao_app->get_button_spacing("evidence_button_spacing", "courtroom_design.ini"); QPoint p_point = ao_app->get_button_spacing("evidence_button_size", "courtroom_design.ini"); @@ -96,6 +144,7 @@ void Courtroom::refresh_evidence() void Courtroom::set_evidence_list(QVector &p_evi_list) { + QVector old_list = local_evidence_list; local_evidence_list.clear(); local_evidence_list = p_evi_list; @@ -105,13 +154,38 @@ void Courtroom::set_evidence_list(QVector &p_evi_list) { if (current_evidence >= local_evidence_list.size()) { - on_evidence_x_clicked(); + evidence_close(); ui_evidence_name->setText(""); } - else + else if (ui_evidence_description->isReadOnly()) //We haven't double clicked to edit it or anything { on_evidence_double_clicked(current_evidence); } + //Todo: make a function that compares two pieces of evidence for any differences + else if (compare_evidence_changed(old_list.at(current_evidence), local_evidence_list.at(current_evidence))) + { + QMessageBox *msgBox = new QMessageBox; + + msgBox->setText("The piece of evidence you've been editing has changed."); + msgBox->setInformativeText("Do you wish to keep your changes?"); + msgBox->setDetailedText("Name: " + local_evidence_list.at(current_evidence).name + "\nImage: " + local_evidence_list.at(current_evidence).image + "\nDescription:\n" + local_evidence_list.at(current_evidence).description); + msgBox->setStandardButtons(QMessageBox::Yes | QMessageBox::No); + msgBox->setDefaultButton(QMessageBox::No); + //msgBox->setWindowModality(Qt::NonModal); + int ret = msgBox->exec(); + switch (ret) { + case QMessageBox::Yes: + // "Keep changes" + break; + case QMessageBox::No: + // "Discard changes and keep theirs" + on_evidence_double_clicked(current_evidence); + break; + default: + // should never be reached + break; + } + } } } @@ -185,24 +259,34 @@ void Courtroom::on_evidence_name_edited() if (current_evidence >= local_evidence_list.size()) return; - QStringList f_contents; +// Prefer pressing [X] to update the evidence. +// QStringList f_contents; - evi_type f_evi = local_evidence_list.at(current_evidence); +// evi_type f_evi = local_evidence_list.at(current_evidence); - f_contents.append(QString::number(current_evidence)); - f_contents.append(ui_evidence_name->text()); - f_contents.append(f_evi.description); - f_contents.append(f_evi.image); +// f_contents.append(QString::number(current_evidence)); +// f_contents.append(ui_evidence_name->text()); +// f_contents.append(f_evi.description); +// f_contents.append(f_evi.image); - ao_app->send_server_packet(new AOPacket("EE", f_contents)); +// ao_app->send_server_packet(new AOPacket("EE", f_contents)); } void Courtroom::on_evidence_name_double_clicked() { if (ui_evidence_overlay->isVisible()) + { ui_evidence_name->setReadOnly(false); + } else + { ui_evidence_name->setReadOnly(true); + } +} + +void Courtroom::on_evidence_image_name_double_clicked() +{ + ui_evidence_image_name->setReadOnly(false); } void Courtroom::on_evidence_image_name_edited() @@ -211,16 +295,16 @@ void Courtroom::on_evidence_image_name_edited() if (current_evidence >= local_evidence_list.size()) return; - QStringList f_contents; +// QStringList f_contents; - evi_type f_evi = local_evidence_list.at(current_evidence); +// evi_type f_evi = local_evidence_list.at(current_evidence); - f_contents.append(QString::number(current_evidence)); - f_contents.append(f_evi.name); - f_contents.append(f_evi.description); - f_contents.append(ui_evidence_image_name->text()); +// f_contents.append(QString::number(current_evidence)); +// f_contents.append(f_evi.name); +// f_contents.append(f_evi.description); +// f_contents.append(ui_evidence_image_name->text()); - ao_app->send_server_packet(new AOPacket("EE", f_contents)); +// ao_app->send_server_packet(new AOPacket("EE", f_contents)); } void Courtroom::on_evidence_image_button_clicked() @@ -284,23 +368,22 @@ void Courtroom::on_evidence_double_clicked(int p_id) evi_type f_evi = local_evidence_list.at(f_real_id); - QTextCursor cursor = ui_evidence_description->textCursor(); - int pos = cursor.position(); + ui_evidence_description->clear(); + ui_evidence_description->appendPlainText(f_evi.description); + ui_evidence_description->setReadOnly(true); + ui_evidence_description->setToolTip("Double-click to edit..."); - //ISSUE: Undo/redo history is completely inaccessible. :( - ui_evidence_description->blockSignals(true); - ui_evidence_description->setPlainText(f_evi.description); - ui_evidence_description->blockSignals(false); - - cursor.setPosition(pos); //Reset the cursor position back in place - ui_evidence_description->setTextCursor(cursor); - - ui_evidence_image_name->setText(f_evi.image); ui_evidence_name->setText(f_evi.name); + ui_evidence_name->setReadOnly(true); + ui_evidence_name->setToolTip("Double-click to edit..."); + ui_evidence_image_name->setText(f_evi.image); + ui_evidence_image_name->setReadOnly(true); + ui_evidence_image_name->setToolTip("Double-click to edit..."); ui_evidence_overlay->show(); + ui_evidence_ok->hide(); -// ui_ic_chat_message->setFocus(); + ui_ic_chat_message->setFocus(); } void Courtroom::on_evidence_hover(int p_id, bool p_state) @@ -342,9 +425,9 @@ void Courtroom::on_evidence_right_clicked() void Courtroom::on_evidence_present_clicked() { if (is_presenting_evidence) - ui_evidence_present->set_image("present_disabled"); - else ui_evidence_present->set_image("present"); + else + ui_evidence_present->set_image("present_disabled"); is_presenting_evidence = !is_presenting_evidence; @@ -353,10 +436,7 @@ void Courtroom::on_evidence_present_clicked() void Courtroom::on_evidence_delete_clicked() { - ui_evidence_description->setReadOnly(true); - ui_evidence_name->setReadOnly(true); - ui_evidence_overlay->hide(); - + evidence_close(); ao_app->send_server_packet(new AOPacket("DE#" + QString::number(current_evidence) + "#%")); current_evidence = 0; @@ -366,22 +446,94 @@ void Courtroom::on_evidence_delete_clicked() void Courtroom::on_evidence_x_clicked() { - ui_evidence_description->setReadOnly(true); + if (current_evidence >= local_evidence_list.size()) //Should never happen but you never know. + return; + + evi_type fake_evidence; + fake_evidence.name = ui_evidence_name->text(); + fake_evidence.description = ui_evidence_description->toPlainText(); + fake_evidence.image = ui_evidence_image_name->text(); + if (!compare_evidence_changed(fake_evidence, local_evidence_list.at(current_evidence))) + { + evidence_close(); + return; + } + QMessageBox *msgBox = new QMessageBox; + msgBox->setText("Evidence has been modified."); + msgBox->setInformativeText("Do you want to save your changes?"); + msgBox->setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); + msgBox->setDefaultButton(QMessageBox::Save); + int ret = msgBox->exec(); + switch (ret) { + case QMessageBox::Save: + evidence_close(); + on_evidence_ok_clicked(); + break; + case QMessageBox::Discard: + evidence_close(); + break; + case QMessageBox::Cancel: + // Cancel was clicked, do nothing + break; + default: + // should never be reached + break; + } +} + +void Courtroom::on_evidence_ok_clicked() +{ ui_evidence_name->setReadOnly(true); + ui_evidence_description->setReadOnly(true); + ui_evidence_image_name->setReadOnly(true); + if (current_evidence < local_evidence_list.size()) + { + evi_type f_evi = local_evidence_list.at(current_evidence); + + QStringList f_contents; + f_contents.append(QString::number(current_evidence)); + f_contents.append(ui_evidence_name->text()); + f_contents.append(ui_evidence_description->toPlainText()); + f_contents.append(ui_evidence_image_name->text()); + + ao_app->send_server_packet(new AOPacket("EE", f_contents)); + +// QMessageBox *msgBox = new QMessageBox; + +// msgBox->setText("You succesfully saved your changes."); +// msgBox->setStandardButtons(QMessageBox::Ok); +// msgBox->setDefaultButton(QMessageBox::Ok); +// msgBox->exec(); + } +} + +void Courtroom::on_evidence_edited() +{ + if (current_evidence >= local_evidence_list.size()) //Should never happen but you never know. + return; + evi_type fake_evidence; + fake_evidence.name = ui_evidence_name->text(); + fake_evidence.description = ui_evidence_description->toPlainText(); + fake_evidence.image = ui_evidence_image_name->text(); + if (compare_evidence_changed(fake_evidence, local_evidence_list.at(current_evidence))) + ui_evidence_ok->show(); + else + ui_evidence_ok->hide(); +} + +void Courtroom::evidence_close() +{ + ui_evidence_description->setReadOnly(true); + ui_evidence_description->setToolTip(""); + ui_evidence_name->setReadOnly(true); + ui_evidence_name->setToolTip(""); + ui_evidence_image_name->setReadOnly(true); + ui_evidence_image_name->setToolTip(""); ui_evidence_overlay->hide(); ui_ic_chat_message->setFocus(); } -void Courtroom::on_evidence_description_edited() +bool Courtroom::compare_evidence_changed(evi_type evi_a, evi_type evi_b) { - QStringList f_contents; - - evi_type f_evi = local_evidence_list.at(current_evidence); - - f_contents.append(QString::number(current_evidence)); - f_contents.append(f_evi.name); - f_contents.append(ui_evidence_description->toPlainText()); - f_contents.append(f_evi.image); - - ao_app->send_server_packet(new AOPacket("EE", f_contents)); + return evi_a.name != evi_b.name || evi_a.image != evi_b.image || evi_a.description != evi_b.description; } From 709ebb7e1872394731c2edb282a1ce73fdc353f9 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sat, 28 Sep 2019 20:43:19 +0300 Subject: [PATCH 092/268] Fix AOEvidenceDisplay not respecting the size of the viewport properly and breaking if a static image was used for evidence appearance Fix an issue with chat message being resized before the chat box is in reload theme --- include/aoevidencedisplay.h | 7 +++--- src/aoevidencedisplay.cpp | 45 +++++++++++++------------------------ src/courtroom.cpp | 22 +++++++++--------- 3 files changed, 30 insertions(+), 44 deletions(-) diff --git a/include/aoevidencedisplay.h b/include/aoevidencedisplay.h index 13ca00d..93455c0 100644 --- a/include/aoevidencedisplay.h +++ b/include/aoevidencedisplay.h @@ -3,9 +3,9 @@ #include "aoapplication.h" #include "aosfxplayer.h" +#include "aomovie.h" #include -#include #include class AOEvidenceDisplay : public QLabel @@ -18,15 +18,16 @@ public: void show_evidence(QString p_evidence_image, bool is_left_side, int p_volume); QLabel* get_evidence_icon(); void reset(); + void combo_resize(int w, int h); private: AOApplication *ao_app; - QMovie *evidence_movie; + AOMovie *evidence_movie; QLabel *evidence_icon; AOSfxPlayer *sfx_player; private slots: - void frame_change(int p_frame); + void show_done(); }; #endif // AOEVIDENCEDISPLAY_H diff --git a/src/aoevidencedisplay.cpp b/src/aoevidencedisplay.cpp index 3fde05a..fef072b 100644 --- a/src/aoevidencedisplay.cpp +++ b/src/aoevidencedisplay.cpp @@ -7,12 +7,12 @@ AOEvidenceDisplay::AOEvidenceDisplay(QWidget *p_parent, AOApplication *p_ao_app) : QLabel(p_parent) { ao_app = p_ao_app; - - evidence_movie = new QMovie(this); evidence_icon = new QLabel(this); sfx_player = new AOSfxPlayer(this, ao_app); - connect(evidence_movie, SIGNAL(frameChanged(int)), this, SLOT(frame_change(int))); + evidence_movie = new AOMovie(this, ao_app); + + connect(evidence_movie, SIGNAL(done()), this, SLOT(show_done())); } void AOEvidenceDisplay::show_evidence(QString p_evidence_image, bool is_left_side, int p_volume) @@ -47,36 +47,10 @@ void AOEvidenceDisplay::show_evidence(QString p_evidence_image, bool is_left_sid evidence_icon->setPixmap(f_pixmap.scaled(evidence_icon->width(), evidence_icon->height(), Qt::IgnoreAspectRatio)); - QString f_default_gif_path = ao_app->get_image_suffix(ao_app->get_default_theme_path(gif_name)); - QString f_gif_path = ao_app->get_image_suffix(ao_app->get_theme_path(gif_name)); - - if (file_exists(f_gif_path)) - final_gif_path = f_gif_path; - else - final_gif_path = f_default_gif_path; - - evidence_movie->setFileName(final_gif_path); - - this->setMovie(evidence_movie); - - evidence_movie->start(); + evidence_movie->play(gif_name); sfx_player->play(ao_app->get_sfx("evidence_present")); } -void AOEvidenceDisplay::frame_change(int p_frame) -{ - if (p_frame == (evidence_movie->frameCount() - 1)) - { - //we need this or else the last frame wont show - delay(evidence_movie->nextFrameDelay()); - - evidence_movie->stop(); - this->clear(); - - evidence_icon->show(); - } -} - void AOEvidenceDisplay::reset() { sfx_player->stop(); @@ -85,9 +59,20 @@ void AOEvidenceDisplay::reset() this->clear(); } +void AOEvidenceDisplay::show_done() +{ + evidence_icon->show(); +} + QLabel* AOEvidenceDisplay::get_evidence_icon() { return evidence_icon; } +void AOEvidenceDisplay::combo_resize(int w, int h) +{ + QSize f_size(w, h); + this->resize(f_size); + evidence_movie->combo_resize(w, h); +} diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 428d98c..6ea98f1 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -490,16 +490,7 @@ void Courtroom::set_widgets() ui_vp_legacy_desk->hide(); ui_vp_evidence_display->move(0, 0); - ui_vp_evidence_display->resize(ui_viewport->width(), ui_viewport->height()); - - set_size_and_pos(ui_vp_showname, "showname"); - - set_size_and_pos(ui_vp_message, "message"); - //We detached the text as parent from the chatbox so it doesn't get affected by the screenshake. - ui_vp_message->move(ui_vp_message->x() + ui_vp_chatbox->x(), ui_vp_message->y() + ui_vp_chatbox->y()); - ui_vp_message->setTextInteractionFlags(Qt::NoTextInteraction); -// ui_vp_message->setStyleSheet("background-color: rgba(0, 0, 0, 0);" -// "color: white"); + ui_vp_evidence_display->combo_resize(ui_viewport->width(), ui_viewport->height()); ui_vp_chat_arrow->move(0, 0); pos_size_type design_ini_result = ao_app->get_element_dimensions("chat_arrow", "courtroom_design.ini"); @@ -586,6 +577,15 @@ void Courtroom::set_widgets() ui_vp_chatbox->set_image("chatblank"); ui_vp_chatbox->hide(); + set_size_and_pos(ui_vp_showname, "showname"); + + set_size_and_pos(ui_vp_message, "message"); + //We detached the text as parent from the chatbox so it doesn't get affected by the screenshake. + ui_vp_message->move(ui_vp_message->x() + ui_vp_chatbox->x(), ui_vp_message->y() + ui_vp_chatbox->y()); + ui_vp_message->setTextInteractionFlags(Qt::NoTextInteraction); +// ui_vp_message->setStyleSheet("background-color: rgba(0, 0, 0, 0);" +// "color: white"); + ui_muted->resize(ui_ic_chat_message->width(), ui_ic_chat_message->height()); ui_muted->set_image("muted"); ui_muted->setToolTip(tr("Oops, you're muted!")); @@ -1582,7 +1582,7 @@ void Courtroom::handle_chatmessage(QStringList *p_contents) ui_custom_objection->set_image("custom"); ui_realization->set_image("realization"); ui_screenshake->set_image("screenshake"); - ui_evidence_present->set_image("present_disabled"); + ui_evidence_present->set_image("present"); } //Let the server handle actually checking if they're allowed to do this. From b0f11e53dff7187a147f01da2d8da5bf392cd38d Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sat, 28 Sep 2019 22:00:16 +0300 Subject: [PATCH 093/268] Strip out QRandomGenerator because it's "too new" of a module (linux build does not compile with it) Add QPluginLoader checks for qapng and qwebp --- include/courtroom.h | 2 +- src/courtroom.cpp | 4 +++- src/main.cpp | 8 ++++++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/include/courtroom.h b/include/courtroom.h index 0fc56fe..866a75f 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -55,7 +55,7 @@ #include #include #include -#include +//#include #include diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 6ea98f1..20f7dae 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -44,6 +44,8 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() } #endif + qsrand(static_cast(QDateTime::currentMSecsSinceEpoch() / 1000)); + keepalive_timer = new QTimer(this); keepalive_timer->start(60000); @@ -1933,7 +1935,7 @@ void Courtroom::do_screenshake() for (int frame=0; frame < maxframes; frame++) { double fraction = double(frame*frequency)/duration; - quint32 rng = QRandomGenerator::global()->generate(); + int rng = qrand();//QRandomGenerator::global()->generate(); int rand_x = int(rng) % max_x; int rand_y = int(rng+100) % max_y; screenshake_animation->setKeyValueAt(fraction, QPoint(pos_default.x() + rand_x, pos_default.y() + rand_y)); diff --git a/src/main.cpp b/src/main.cpp index 6c7b151..04b9df5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -22,6 +22,14 @@ int main(int argc, char *argv[]) QSettings *configini = main_app.configini; + QPluginLoader apngPlugin("imageformats/qapng"); + if (!apngPlugin.load()) + qCritical() << "QApng plugin could not be loaded"; + + QPluginLoader webpPlugin("imageformats/qwebp"); + if (!webpPlugin.load()) + qCritical() << "QWebp plugin could not be loaded"; + QString p_language = configini->value("language", QLocale::system().name()).toString(); if (p_language == " " || p_language == "") p_language = QLocale::system().name(); From 30c02221d282cb4d340aa38334f89e4825fa39d0 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sun, 29 Sep 2019 03:26:16 +0300 Subject: [PATCH 094/268] Make the client select a default font that resembles classic AA font the most (cleartype off, MS Sans) Create a better method to replace trailing whitespace with proper HTML representation Don't bother rendering the string character-by-character to prevent any latency happening with instant text speed --- src/aolineedit.cpp | 2 +- src/courtroom.cpp | 157 +++++++++++++++++------------------- src/main.cpp | 4 +- src/text_file_functions.cpp | 2 +- 4 files changed, 76 insertions(+), 89 deletions(-) diff --git a/src/aolineedit.cpp b/src/aolineedit.cpp index 56b571f..1c141c3 100644 --- a/src/aolineedit.cpp +++ b/src/aolineedit.cpp @@ -13,7 +13,7 @@ void AOLineEdit::mouseDoubleClickEvent(QMouseEvent *e) void AOLineEdit::focusOutEvent(QFocusEvent *ev) { int start = selectionStart(); - int len = selectionLength(); + int len = selectionEnd() - start; //We're not using selectionLength because Linux build doesn't run qt5.10 QLineEdit::focusOutEvent(ev); if (p_selection && start != -1 && len != -1) this->setSelection(start, len); diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 20f7dae..e0b1948 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1,5 +1,6 @@ #include "courtroom.h" + Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() { ao_app = p_ao_app; @@ -147,6 +148,7 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_ic_chat_message->setFrame(false); ui_ic_chat_message->setPlaceholderText(tr("Message")); ui_ic_chat_message->preserve_selection(true); +// ui_ic_chat_message->setValidator(new QRegExpValidator(QRegExp("^\\S+(?: \\S+)*$"), ui_ic_chat_message)); //todo: filter out \n from showing up as that commonly breaks the chatlog and can be spammed to hell ui_muted = new AOImage(ui_ic_chat_message, ao_app); @@ -585,19 +587,15 @@ void Courtroom::set_widgets() //We detached the text as parent from the chatbox so it doesn't get affected by the screenshake. ui_vp_message->move(ui_vp_message->x() + ui_vp_chatbox->x(), ui_vp_message->y() + ui_vp_chatbox->y()); ui_vp_message->setTextInteractionFlags(Qt::NoTextInteraction); -// ui_vp_message->setStyleSheet("background-color: rgba(0, 0, 0, 0);" -// "color: white"); ui_muted->resize(ui_ic_chat_message->width(), ui_ic_chat_message->height()); ui_muted->set_image("muted"); ui_muted->setToolTip(tr("Oops, you're muted!")); set_size_and_pos(ui_ooc_chat_message, "ooc_chat_message"); - ui_ooc_chat_message->setStyleSheet("background-color: rgba(0, 0, 0, 0);"); ui_ooc_chat_message->setToolTip(tr("Type your message to display in the server chat here.")); set_size_and_pos(ui_ooc_chat_name, "ooc_chat_name"); - ui_ooc_chat_name->setStyleSheet("background-color: rgba(0, 0, 0, 0);"); ui_ooc_chat_name->setToolTip(tr("Set your name to display in the server chat.")); //set_size_and_pos(ui_area_password, "area_password"); @@ -832,12 +830,21 @@ void Courtroom::set_font(QWidget *widget, QString class_name, QString p_identifi QColor f_color = ao_app->get_color(p_identifier + "_color", design_file); bool bold = ao_app->get_font_size(p_identifier + "_bold", design_file) == 1; // is the font bold or not? - this->set_qfont(widget, class_name, QFont(font_name, f_weight), f_color, bold); + + QFont font; + if (font_name.isEmpty()) + { + font = QFont(font_name, f_weight); + font.setStyleHint(QFont::SansSerif, QFont::NoAntialias); + } + else + font = QFont(font_name, f_weight); + this->set_qfont(widget, class_name, font, f_color, bold); } void Courtroom::set_qfont(QWidget *widget, QString class_name, QFont font, QColor f_color, bool bold) { - if(class_name == "") + if(class_name.isEmpty()) class_name = widget->metaObject()->className(); widget->setFont(font); @@ -1563,7 +1570,10 @@ void Courtroom::handle_chatmessage(QStringList *p_contents) chat_tick_timer->stop(); ui_vp_evidence_display->reset(); - m_chatmessage[MESSAGE].remove("\n"); //Remove undesired newline chars + //Remove undesired newline chars + m_chatmessage[MESSAGE].remove("\n"); + //Replace all trailing whitespace with a single space and remove all whitespace at the end of the string. + //m_chatmessage[MESSAGE] = m_chatmessage[MESSAGE].replace(QRegularExpression("^\\s+(?=\\s)|\\s+$|\\s+(?=\\s)"), ""); chatmessage_is_empty = m_chatmessage[MESSAGE] == " " || m_chatmessage[MESSAGE] == ""; @@ -1735,25 +1745,6 @@ void Courtroom::handle_chatmessage_2() set_scene(m_chatmessage[DESK_MOD], m_chatmessage[SIDE]); - // Check if the message needs to be centered. - QString f_message = m_chatmessage[MESSAGE]; - if (f_message.size() >= 2) - { - if (f_message.startsWith("~~")) - { - message_is_centered = true; - } - else - { - message_is_centered = false; - } - } - else - { - ui_vp_message->setAlignment(Qt::AlignLeft); - } - - int emote_mod = m_chatmessage[EMOTE_MOD].toInt(); if (ao_app->flipping_enabled && m_chatmessage[FLIP].toInt() == 1) @@ -2055,12 +2046,6 @@ void Courtroom::handle_chatmessage_3() QString Courtroom::filter_ic_text(QString p_text, bool html, int target_pos, int default_color) { - // Get rid of centering. - if(p_text.startsWith("~~")) - p_text.remove(0,2); - - p_text.remove("\n"); //Undesired newline chars, probably from copy-pasting it from a doc or something. - QString p_text_escaped; int check_pos = 0; @@ -2106,8 +2091,6 @@ QString Courtroom::filter_ic_text(QString p_text, bool html, int target_pos, int if (html) f_character = f_character.toHtmlEscaped(); - if (f_character == " " && html) //Whitespace, woah - f_character = " "; //Turn it into an HTML entity f_char_length = f_character.length(); bool color_update = false; @@ -2262,6 +2245,14 @@ QString Courtroom::filter_ic_text(QString p_text, bool html, int target_pos, int p_text_escaped.append("
"); } + if (html) + { + //Example: https://regex101.com/r/oL4nM9/37 - this replaces excessive/trailing/etc. whitespace with non-breaking space. + //I WOULD use white-space: pre; stylesheet tag, but for whataver reason it doesn't work no matter where I try it. + //If somoene else can get that piece of HTML memery to work, please do. + p_text_escaped.replace(QRegularExpression("^\\s|(?<=\\s)\\s"), " "); + } + return p_text_escaped; } @@ -2591,60 +2582,57 @@ void Courtroom::chat_tick() } tick_pos += f_char_length; - - //Do the colors, gradual showing, etc. in here - ui_vp_message->setHtml(additive_previous + filter_ic_text(f_message, true, tick_pos, m_chatmessage[TEXT_COLOR].toInt())); - - if (!formatting_char || f_character == "n") //NEWLINES (\n) COUNT AS A SINGLE CHARACTER. + if (formatting_char || (message_display_speed[current_display_speed] <= 0 && tick_pos < f_message.size())) { - //Make the cursor follow the message - QTextCursor cursor = ui_vp_message->textCursor(); - cursor.setPosition(real_tick_pos); - ui_vp_message->setTextCursor(cursor); - real_tick_pos += f_char_length; - } - ui_vp_message->ensureCursorVisible(); - -// //Grab the currently displayed chars -// f_rest = f_message.left(tick_pos); -// f_rest.replace("\\n", "\n"); - -// QFontMetrics fm = fontMetrics(); -// QRect bounding_rect = fm.boundingRect(QRect(0,0,ui_vp_message->width(),ui_vp_message->height()), Qt::TextWordWrap, f_rest); - -// //If the text overflows, make it snap to bottom -// if (bounding_rect.height() > ui_vp_message->height()) -// { - -// QScrollBar *scroll = ui_vp_message->verticalScrollBar(); -// scroll->value(); -// scroll->setValue(scroll->maximum()); -// } - - // Keep the speed at bay. - if (current_display_speed < 0) - current_display_speed = 0; - else if (current_display_speed > 6) - current_display_speed = 6; - - //Blip player and real tick pos ticker - if (!formatting_char && (f_character != ' ' || blank_blip)) - { - if (blip_ticker % blip_rate == 0) - { - blip_player->blip_tick(); - } - ++blip_ticker; - } - - // If we had a formatting char, we shouldn't wait so long again, as it won't appear! - // Additionally, if the message_display_speed length is too short for us to do anything (play animations, etc.) then skip the trouble and don't bother. - if (formatting_char || message_display_speed[current_display_speed] <= 0) - { - chat_tick_timer->start(0); + chat_tick_timer->start(0); //Don't bother rendering anything out as we're doing the SPEED. (there's latency otherwise) } else { + //Do the colors, gradual showing, etc. in here + ui_vp_message->setHtml(additive_previous + filter_ic_text(f_message, true, tick_pos, m_chatmessage[TEXT_COLOR].toInt())); + + if (!formatting_char || f_character == "n") //NEWLINES (\n) COUNT AS A SINGLE CHARACTER. + { + //Make the cursor follow the message + QTextCursor cursor = ui_vp_message->textCursor(); + cursor.setPosition(real_tick_pos); + ui_vp_message->setTextCursor(cursor); + real_tick_pos += f_char_length; + } + ui_vp_message->ensureCursorVisible(); + + // //Grab the currently displayed chars + // f_rest = f_message.left(tick_pos); + // f_rest.replace("\\n", "\n"); + + // QFontMetrics fm = fontMetrics(); + // QRect bounding_rect = fm.boundingRect(QRect(0,0,ui_vp_message->width(),ui_vp_message->height()), Qt::TextWordWrap, f_rest); + + // //If the text overflows, make it snap to bottom + // if (bounding_rect.height() > ui_vp_message->height()) + // { + + // QScrollBar *scroll = ui_vp_message->verticalScrollBar(); + // scroll->value(); + // scroll->setValue(scroll->maximum()); + // } + + // Keep the speed at bay. + if (current_display_speed < 0) + current_display_speed = 0; + else if (current_display_speed > 6) + current_display_speed = 6; + + //Blip player and real tick pos ticker + if (!formatting_char && (f_character != ' ' || blank_blip)) + { + if (blip_ticker % blip_rate == 0) + { + blip_player->blip_tick(); + } + ++blip_ticker; + } + //If this color is talking if (color_is_talking && anim_state != 2 && anim_state < 4) //Set it to talking as we're not on that already (though we have to avoid interrupting a non-interrupted preanim) { @@ -2658,7 +2646,6 @@ void Courtroom::chat_tick() ui_vp_player_char->play_idle(m_chatmessage[CHAR_NAME], m_chatmessage[EMOTE]); anim_state = 3; } - //Continue ticking chat_tick_timer->start(message_display_speed[current_display_speed]); } diff --git a/src/main.cpp b/src/main.cpp index 04b9df5..8d3f53b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -22,11 +22,11 @@ int main(int argc, char *argv[]) QSettings *configini = main_app.configini; - QPluginLoader apngPlugin("imageformats/qapng"); + QPluginLoader apngPlugin("qapng"); if (!apngPlugin.load()) qCritical() << "QApng plugin could not be loaded"; - QPluginLoader webpPlugin("imageformats/qwebp"); + QPluginLoader webpPlugin("qwebp"); if (!webpPlugin.load()) qCritical() << "QWebp plugin could not be loaded"; diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index b976434..2b86a1e 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -315,7 +315,7 @@ QString AOApplication::get_font_name(QString p_identifier, QString p_file) { f_result = read_design_ini(p_identifier, default_path); if (f_result == "") - return "Sans"; + return ""; } return f_result; } From d5cbb085db9cc61ddc007217d1217c343307322e Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sun, 29 Sep 2019 03:27:36 +0300 Subject: [PATCH 095/268] Update Bass.dll headers to newer version Remove a bunch of comments Add lqapng and lqwebp to try and get apng and webp support to fuckin load already --- Attorney_Online.pro | 2 ++ include/aomusicplayer.h | 2 -- include/bass.h | 20 +++++++++++++++----- src/courtroom.cpp | 16 ---------------- 4 files changed, 17 insertions(+), 23 deletions(-) diff --git a/Attorney_Online.pro b/Attorney_Online.pro index b747619..36b87d2 100644 --- a/Attorney_Online.pro +++ b/Attorney_Online.pro @@ -15,6 +15,8 @@ HEADERS += $$files($$PWD/include/*.h) LIBS += -L$$PWD/lib +LIBS += -lqapng +LIBS += -lqwebp DEFINES += DISCORD diff --git a/include/aomusicplayer.h b/include/aomusicplayer.h index 8e0d239..9ce7485 100644 --- a/include/aomusicplayer.h +++ b/include/aomusicplayer.h @@ -44,8 +44,6 @@ private: // Channel 2 = extra // Channel 3 = extra HSTREAM m_stream_list[4]; - -// HSYNC loop_sync; }; #elif defined(QTAUDIO) class AOMusicPlayer diff --git a/include/bass.h b/include/bass.h index 1c50903..388d406 100644 --- a/include/bass.h +++ b/include/bass.h @@ -1,6 +1,6 @@ /* BASS 2.4 C/C++ header file - Copyright (c) 1999-2018 Un4seen Developments Ltd. + Copyright (c) 1999-2019 Un4seen Developments Ltd. See the BASS.CHM file for more detailed documentation */ @@ -117,6 +117,7 @@ typedef DWORD HPLUGIN; // Plugin handle #define BASS_CONFIG_VERIFY 23 #define BASS_CONFIG_UPDATETHREADS 24 #define BASS_CONFIG_DEV_BUFFER 27 +#define BASS_CONFIG_REC_LOOPBACK 28 #define BASS_CONFIG_VISTA_TRUEPOS 30 #define BASS_CONFIG_IOS_MIXAUDIO 34 #define BASS_CONFIG_DEV_DEFAULT 36 @@ -141,11 +142,14 @@ typedef DWORD HPLUGIN; // Plugin handle #define BASS_CONFIG_AM_DISABLE 58 #define BASS_CONFIG_NET_PLAYLIST_DEPTH 59 #define BASS_CONFIG_NET_PREBUF_WAIT 60 +#define BASS_CONFIG_WASAPI_PERSIST 65 +#define BASS_CONFIG_REC_WASAPI 66 // BASS_SetConfigPtr options #define BASS_CONFIG_NET_AGENT 16 #define BASS_CONFIG_NET_PROXY 17 #define BASS_CONFIG_IOS_NOTIFY 46 +#define BASS_CONFIG_LIBSSL 64 // BASS_Init flags #define BASS_DEVICE_8BITS 1 // 8 bit @@ -507,6 +511,7 @@ RETURN : Number of bytes written. Set the BASS_STREAMPROC_END flag to end the st #define STREAMPROC_DUMMY (STREAMPROC*)0 // "dummy" stream #define STREAMPROC_PUSH (STREAMPROC*)-1 // push stream #define STREAMPROC_DEVICE (STREAMPROC*)-2 // device mix stream +#define STREAMPROC_DEVICE_3D (STREAMPROC*)-3 // device 3D mix stream // BASS_StreamCreateFileUser file systems #define STREAMFILE_NOBUFFER 0 @@ -561,6 +566,8 @@ user : The 'user' parameter value given when calling BASS_StreamCreateURL */ #define BASS_SYNC_MUSICINST 1 #define BASS_SYNC_MUSICFX 3 #define BASS_SYNC_OGG_CHANGE 12 +#define BASS_SYNC_DEV_FAIL 14 +#define BASS_SYNC_DEV_FORMAT 15 #define BASS_SYNC_MIXTIME 0x40000000 // flag: sync at mixtime, else at playtime #define BASS_SYNC_ONETIME 0x80000000 // flag: sync only once, else continuously @@ -593,10 +600,11 @@ user : The 'user' parameter value given when calling BASS_RecordStart RETURN : TRUE = continue recording, FALSE = stop */ // BASS_ChannelIsActive return values -#define BASS_ACTIVE_STOPPED 0 -#define BASS_ACTIVE_PLAYING 1 -#define BASS_ACTIVE_STALLED 2 -#define BASS_ACTIVE_PAUSED 3 +#define BASS_ACTIVE_STOPPED 0 +#define BASS_ACTIVE_PLAYING 1 +#define BASS_ACTIVE_STALLED 2 +#define BASS_ACTIVE_PAUSED 3 +#define BASS_ACTIVE_PAUSED_DEVICE 4 // Channel attributes #define BASS_ATTRIB_FREQ 1 @@ -641,6 +649,7 @@ RETURN : TRUE = continue recording, FALSE = stop */ #define BASS_DATA_FFT_NOWINDOW 0x20 // FFT flag: no Hanning window #define BASS_DATA_FFT_REMOVEDC 0x40 // FFT flag: pre-remove DC bias #define BASS_DATA_FFT_COMPLEX 0x80 // FFT flag: return complex data +#define BASS_DATA_FFT_NYQUIST 0x100 // FFT flag: return extra Nyquist value // BASS_ChannelGetLevelEx flags #define BASS_LEVEL_MONO 1 @@ -1006,6 +1015,7 @@ float BASSDEF(BASS_GetCPU)(); BOOL BASSDEF(BASS_Start)(); BOOL BASSDEF(BASS_Stop)(); BOOL BASSDEF(BASS_Pause)(); +BOOL BASSDEF(BASS_IsStarted)(); BOOL BASSDEF(BASS_SetVolume)(float volume); float BASSDEF(BASS_GetVolume)(); diff --git a/src/courtroom.cpp b/src/courtroom.cpp index e0b1948..5810428 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -2601,22 +2601,6 @@ void Courtroom::chat_tick() } ui_vp_message->ensureCursorVisible(); - // //Grab the currently displayed chars - // f_rest = f_message.left(tick_pos); - // f_rest.replace("\\n", "\n"); - - // QFontMetrics fm = fontMetrics(); - // QRect bounding_rect = fm.boundingRect(QRect(0,0,ui_vp_message->width(),ui_vp_message->height()), Qt::TextWordWrap, f_rest); - - // //If the text overflows, make it snap to bottom - // if (bounding_rect.height() > ui_vp_message->height()) - // { - - // QScrollBar *scroll = ui_vp_message->verticalScrollBar(); - // scroll->value(); - // scroll->setValue(scroll->maximum()); - // } - // Keep the speed at bay. if (current_display_speed < 0) current_display_speed = 0; From adc3cbfe5b1d047910816d51e39bd427fae68708 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sun, 29 Sep 2019 03:42:58 +0300 Subject: [PATCH 096/268] MMMYEAH THIS BIT REQUIRES ME TO UPDATE THE ACTUAL DOCKERFILE. --- Attorney_Online.pro | 2 -- 1 file changed, 2 deletions(-) diff --git a/Attorney_Online.pro b/Attorney_Online.pro index 36b87d2..b747619 100644 --- a/Attorney_Online.pro +++ b/Attorney_Online.pro @@ -15,8 +15,6 @@ HEADERS += $$files($$PWD/include/*.h) LIBS += -L$$PWD/lib -LIBS += -lqapng -LIBS += -lqwebp DEFINES += DISCORD From 1f72205716bae72a482521d0bf9336aad42cb418 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sun, 29 Sep 2019 04:43:28 +0300 Subject: [PATCH 097/268] Mysterious super-similar-to-AA font, please don't elude me. --- src/courtroom.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 5810428..ea1ebea 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -834,7 +834,7 @@ void Courtroom::set_font(QWidget *widget, QString class_name, QString p_identifi QFont font; if (font_name.isEmpty()) { - font = QFont(font_name, f_weight); + font = QFont("Arial", f_weight); font.setStyleHint(QFont::SansSerif, QFont::NoAntialias); } else From 9bf41a714b6a46559bba23ea4fa4e0ad432d6997 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sun, 29 Sep 2019 16:51:37 +0300 Subject: [PATCH 098/268] Bump up version numbers to 2.8.0 --- Attorney_Online.pro | 2 +- include/aoapplication.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Attorney_Online.pro b/Attorney_Online.pro index b747619..5daf73f 100644 --- a/Attorney_Online.pro +++ b/Attorney_Online.pro @@ -3,7 +3,7 @@ QT += core gui widgets network TARGET = Attorney_Online TEMPLATE = app -VERSION = 2.6.2.0 +VERSION = 2.8.0.0 INCLUDEPATH += $$PWD/include DESTDIR = $$PWD/bin diff --git a/include/aoapplication.h b/include/aoapplication.h index 89bfaa2..af1433f 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -392,8 +392,8 @@ public: private: const int RELEASE = 2; - const int MAJOR_VERSION = 6; - const int MINOR_VERSION = 2; + const int MAJOR_VERSION = 8; + const int MINOR_VERSION = 0; QString current_theme = "default"; From 4f738bfe34695db745d251e9461823b8835de201 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Tue, 1 Oct 2019 01:07:03 +0300 Subject: [PATCH 099/268] Fix some read_file errors on effect loading Make FM packet only fetch music, and new FA packet to fetch areas (this way you don't have to reload the entire music list just to get new areas) Fix a possible segfault with emote lists if emote list size is bad Hide casing button if server doesn't support casing Hide the remove buttons by default for iniswaps and sfx list so they're not clickable when they shouldn't be Prevent background from being displayed unless the server asked us to Fix some redundancy surrounding current_side Rework music list so list_music doesn't care about search bar and the hiding is actually done in the search function Implement text centering, rightening and justifying Fix text scrolling meme that happened with \n and skipped chars Fix the pos dropdown not actually caring if you selected jur and sea pos. Fix the pos dropdown sending like a million packets when scrolled through. Prevent characters from being incorrectly resized if a different-scaled character speaks Fix character select screen letting you choose characters that the server doesn't want us to be --- include/courtroom.h | 2 +- src/aocharmovie.cpp | 17 +-- src/charselect.cpp | 4 +- src/courtroom.cpp | 202 ++++++++++++++++++++++++++---------- src/emotes.cpp | 2 +- src/packet_distribution.cpp | 46 +++----- src/text_file_functions.cpp | 18 ++-- 7 files changed, 179 insertions(+), 112 deletions(-) diff --git a/include/courtroom.h b/include/courtroom.h index 866a75f..c680de0 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -149,7 +149,7 @@ public: void set_taken(int n_char, bool p_taken); //sets the current background to argument. also does some checks to see if it's a legacy bg - void set_background(QString p_background); + void set_background(QString p_background, bool display=false); //sets the local character pos/side to use. void set_side(QString p_side); diff --git a/src/aocharmovie.cpp b/src/aocharmovie.cpp index 5294b23..96e84d4 100644 --- a/src/aocharmovie.cpp +++ b/src/aocharmovie.cpp @@ -235,23 +235,12 @@ QPixmap AOCharMovie::get_pixmap(QImage image) f_pixmap = QPixmap::fromImage(image.mirrored(true, false)); else f_pixmap = QPixmap::fromImage(image); - auto aspect_ratio = Qt::KeepAspectRatio; +// auto aspect_ratio = Qt::KeepAspectRatio; auto transform_mode = Qt::SmoothTransformation; - if (f_pixmap.size().width() > this->size().width() || f_pixmap.size().height() > this->size().height()) - { - f_pixmap = f_pixmap.scaledToHeight(this->height(), transform_mode); - } -// else if (f_pixmap.size().height() > this->size().height()) -// { -// f_pixmap = f_pixmap.scaledToWidth(this->width(), transform_mode); -// } - else - { - f_pixmap = f_pixmap.scaled(this->width(), this->height(), aspect_ratio, transform_mode); - } - this->move((f_w - f_pixmap.width())/2, (f_pixmap.height() - f_h)); //Always center horizontally, always put at the bottom vertically + f_pixmap = f_pixmap.scaledToHeight(f_h, transform_mode); this->resize(f_pixmap.size()); + this->move((f_w - f_pixmap.width())/2, (f_h - f_pixmap.height())); //Always center horizontally, always put at the bottom vertically return f_pixmap; } diff --git a/src/charselect.cpp b/src/charselect.cpp index 972a17a..6739a1e 100644 --- a/src/charselect.cpp +++ b/src/charselect.cpp @@ -134,7 +134,9 @@ void Courtroom::char_clicked(int n_char) ao_app->send_server_packet(new AOPacket("PW#" + ui_char_password->text() + "#%")); ao_app->send_server_packet(new AOPacket("CC#" + QString::number(ao_app->s_pv) + "#" + QString::number(n_char) + "#" + get_hdid() + "#%")); } - update_character(n_char); + else + update_character(n_char); + enter_courtroom(); ui_ic_chat_name->setPlaceholderText(char_list.at(n_char).name); diff --git a/src/courtroom.cpp b/src/courtroom.cpp index ea1ebea..544e340 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -295,13 +295,13 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() connect(ui_pos_dropdown, SIGNAL(currentIndexChanged(int)), this, SLOT(on_pos_dropdown_changed(int))); - connect(ui_iniswap_dropdown, SIGNAL(activated(int)), this, SLOT(on_iniswap_dropdown_changed(int))); + connect(ui_iniswap_dropdown, SIGNAL(currentIndexChanged(int)), this, SLOT(on_iniswap_dropdown_changed(int))); connect(ui_iniswap_remove, SIGNAL(clicked()), this, SLOT(on_iniswap_remove_clicked())); - connect(ui_sfx_dropdown, SIGNAL(activated(int)), this, SLOT(on_sfx_dropdown_changed(int))); + connect(ui_sfx_dropdown, SIGNAL(currentIndexChanged(int)), this, SLOT(on_sfx_dropdown_changed(int))); connect(ui_sfx_remove, SIGNAL(clicked()), this, SLOT(on_sfx_remove_clicked())); - connect(ui_effects_dropdown, SIGNAL(activated(int)), this, SLOT(on_effects_dropdown_changed(int))); + connect(ui_effects_dropdown, SIGNAL(currentIndexChanged(int)), this, SLOT(on_effects_dropdown_changed(int))); connect(ui_mute_list, SIGNAL(clicked(QModelIndex)), this, SLOT(on_mute_list_clicked(QModelIndex))); @@ -460,10 +460,12 @@ void Courtroom::set_widgets() if (ao_app->casing_alerts_enabled) { ui_announce_casing->show(); + ui_casing->show(); } else { ui_announce_casing->hide(); + ui_casing->hide(); } // We also show the non-server-dependent client additions. @@ -617,6 +619,7 @@ void Courtroom::set_widgets() ui_iniswap_remove->setText("X"); ui_iniswap_remove->set_image("evidencex"); ui_iniswap_remove->setToolTip(tr("Remove the currently selected iniswap from the list and return to the original character folder.")); + ui_iniswap_remove->hide(); set_size_and_pos(ui_sfx_dropdown, "sfx_dropdown"); ui_sfx_dropdown->setEditable(true); @@ -628,6 +631,7 @@ void Courtroom::set_widgets() ui_sfx_remove->setText("X"); ui_sfx_remove->set_image("evidencex"); ui_sfx_remove->setToolTip(tr("Remove the currently selected iniswap from the list and return to the original character folder.")); + ui_sfx_remove->hide(); set_size_and_pos(ui_effects_dropdown, "effects_dropdown"); ui_effects_dropdown->setInsertPolicy(QComboBox::InsertAtBottom); @@ -805,7 +809,6 @@ void Courtroom::set_widgets() ui_spectator->setToolTip(tr("Become a spectator. You won't be able to interact with the in-character screen.")); refresh_evidence(); - refresh_emotes(); } void Courtroom::set_fonts() @@ -954,7 +957,7 @@ void Courtroom::done_received() ui_spectator->show(); } -void Courtroom::set_background(QString p_background) +void Courtroom::set_background(QString p_background, bool display) { ui_vp_testimony->stop(); current_background = p_background; @@ -974,13 +977,16 @@ void Courtroom::set_background(QString p_background) set_size_and_pos(ui_ic_chat_message, "ic_chat_message"); } - ui_vp_speedlines->stop(); - ui_vp_player_char->stop(); - ui_vp_sideplayer_char->stop(); - ui_vp_effect->stop(); - ui_vp_message->hide(); - ui_vp_chatbox->hide(); - set_scene(QString::number(ao_app->get_desk_mod(current_char, current_emote)), current_side); + if (display) + { + ui_vp_speedlines->stop(); + ui_vp_player_char->stop(); + ui_vp_sideplayer_char->stop(); + ui_vp_effect->stop(); + ui_vp_message->hide(); + ui_vp_chatbox->hide(); + set_scene(QString::number(ao_app->get_desk_mod(current_char, current_emote)), current_side); + } } void Courtroom::set_side(QString p_side) @@ -1034,7 +1040,7 @@ void Courtroom::update_character(int p_cid) } current_char = f_char; - current_side = ""; + current_side = ao_app->get_char_side(current_char); current_emote_page = 0; current_emote = 0; @@ -1044,17 +1050,18 @@ void Courtroom::update_character(int p_cid) else ui_emotes->show(); + refresh_emotes(); set_emote_page(); set_emote_dropdown(); set_sfx_dropdown(); set_effects_dropdown(); - QString side = current_side; - if (side == "") - side = ao_app->get_char_side(current_char); + qDebug() << "update_character called"; + if (newchar) //Avoid infinite loop of death and suffering + set_iniswap_dropdown(); - if (side == "jud") + if (current_side == "jud") { ui_witness_testimony->show(); ui_cross_examination->show(); @@ -1088,9 +1095,6 @@ void Courtroom::update_character(int p_cid) ui_char_select_background->hide(); ui_ic_chat_message->setEnabled(m_cid != -1); ui_ic_chat_message->setFocus(); - - if (newchar) - set_iniswap_dropdown(); } void Courtroom::enter_courtroom() @@ -1134,6 +1138,7 @@ void Courtroom::enter_courtroom() //ui_server_chatlog->setHtml(ui_server_chatlog->toHtml()); } +//Todo: multithread this due to some servers having large as hell music list void Courtroom::list_music() { ui_music_list->clear(); @@ -1170,24 +1175,12 @@ void Courtroom::list_music() if (i_song_listname == i_song) //Not supposed to be a song to begin with - a category? parent = treeItem; ++n_listed_songs; - - if (ui_music_search->text() != "") - treeItem->setHidden(true); } - if (ui_music_search->text() != "") - { - QList clist = ui_music_list->findItems(ui_music_search->text(), Qt::MatchContains|Qt::MatchRecursive, 0); - foreach(QTreeWidgetItem* item, clist) - { - if (item->parent() != nullptr) //So the category shows up too - item->parent()->setHidden(false); - item->setHidden(false); - } - } - ui_music_list->expandAll(); //Workaround, it needs to preserve the "expanded categories" due to list music being updated constantly by some servers + ui_music_list->expandAll(); //Needs to somehow remember which categories were expanded/collapsed if the music list didn't change since last time } +//Todo: multithread this due to some servers having large as hell area list void Courtroom::list_areas() { ui_area_list->clear(); @@ -1322,9 +1315,8 @@ void Courtroom::on_chat_return_pressed() QStringList packet_contents; - QString f_side = current_side; - if (f_side == "") - f_side = ao_app->get_char_side(current_char); + if (current_side == "") + current_side = ao_app->get_char_side(current_char); QString f_desk_mod = "chat"; @@ -1345,7 +1337,7 @@ void Courtroom::on_chat_return_pressed() packet_contents.append(ui_ic_chat_message->text()); - packet_contents.append(f_side); + packet_contents.append(current_side); packet_contents.append(get_char_sfx()); @@ -1500,7 +1492,9 @@ void Courtroom::on_chat_return_pressed() { QString fx_sound = ao_app->get_effect_sound(effect, current_char); packet_contents.append(effect + "|" + fx_sound); + ui_effects_dropdown->blockSignals(true); ui_effects_dropdown->setCurrentIndex(0); + ui_effects_dropdown->blockSignals(false); effect = ""; } @@ -2053,10 +2047,36 @@ QString Courtroom::filter_ic_text(QString p_text, bool html, int target_pos, int bool ic_next_is_not_special = false; std::stack ic_color_stack; + //Text alignment shenanigans. Could make a dropdown for this later, too! + QString align; + if (p_text.trimmed().startsWith("~~")) + { + p_text.remove(p_text.indexOf("~~"), 2); + target_pos -= 2; + align = "center"; + } + else if (p_text.trimmed().startsWith("~>")) + { + p_text.remove(p_text.indexOf("~>"), 2); + target_pos -= 2; + align = "right"; + } + else if (p_text.trimmed().startsWith("<>")) + { + p_text.remove(p_text.indexOf("<>"), 2); + target_pos -= 2; + align = "justify"; + } + + //If html is enabled, prepare this text to be all ready for it. if (html) { ic_color_stack.push(default_color); QString appendage = ""; + + if (!align.isEmpty()) + appendage.prepend("
"); + p_text_escaped.insert(check_pos_escaped, appendage); check_pos_escaped += appendage.size(); } @@ -2240,7 +2260,7 @@ QString Courtroom::filter_ic_text(QString p_text, bool html, int target_pos, int check_pos += 1; } - if (!ic_color_stack.empty()) + if (!ic_color_stack.empty() && html) { p_text_escaped.append(""); } @@ -2251,6 +2271,8 @@ QString Courtroom::filter_ic_text(QString p_text, bool html, int target_pos, int //I WOULD use white-space: pre; stylesheet tag, but for whataver reason it doesn't work no matter where I try it. //If somoene else can get that piece of HTML memery to work, please do. p_text_escaped.replace(QRegularExpression("^\\s|(?<=\\s)\\s"), " "); + if (!align.isEmpty()) + p_text_escaped.append("
"); } return p_text_escaped; @@ -2495,9 +2517,6 @@ void Courtroom::chat_tick() ui_vp_chat_arrow->play("chat_arrow", f_char, f_custom_theme); //Chat stopped being processed, indicate that. additive_previous = additive_previous + filter_ic_text(f_message, true, -1, m_chatmessage[TEXT_COLOR].toInt()); real_tick_pos = ui_vp_message->toPlainText().size(); - - QScrollBar *scroll = ui_vp_message->verticalScrollBar(); - scroll->setValue(scroll->maximum()); return; } @@ -2505,6 +2524,29 @@ void Courtroom::chat_tick() bool formatting_char = false; QString f_rest = f_message; + + //Alignment characters + if (tick_pos < 2) + { + if (f_rest.startsWith("~~")) + { + tick_pos = f_rest.indexOf("~~"); + f_rest.remove(tick_pos, 2); + tick_pos += 2; + } + else if (f_rest.startsWith("~>")) + { + tick_pos = f_rest.indexOf("~>"); + f_rest.remove(tick_pos, 2); + tick_pos += 2; + } + else if (f_rest.startsWith("<>")) + { + tick_pos = f_rest.indexOf("<>"); + f_rest.remove(tick_pos, 2); + tick_pos += 2; + } + } f_rest.remove(0, tick_pos); QTextBoundaryFinder tbf(QTextBoundaryFinder::Grapheme, f_rest); QString f_character; @@ -2518,6 +2560,7 @@ void Courtroom::chat_tick() f_character = f_rest.left(tbf.position()); f_char_length = f_character.length(); + tick_pos += f_char_length; // Escape character. if (!next_character_is_not_special) @@ -2581,24 +2624,25 @@ void Courtroom::chat_tick() next_character_is_not_special = false; } - tick_pos += f_char_length; if (formatting_char || (message_display_speed[current_display_speed] <= 0 && tick_pos < f_message.size())) { chat_tick_timer->start(0); //Don't bother rendering anything out as we're doing the SPEED. (there's latency otherwise) + if (!formatting_char || f_character == "n") + real_tick_pos += f_char_length; //Adjust the tick position for the scrollbar convenience } else { //Do the colors, gradual showing, etc. in here ui_vp_message->setHtml(additive_previous + filter_ic_text(f_message, true, tick_pos, m_chatmessage[TEXT_COLOR].toInt())); - if (!formatting_char || f_character == "n") //NEWLINES (\n) COUNT AS A SINGLE CHARACTER. - { - //Make the cursor follow the message - QTextCursor cursor = ui_vp_message->textCursor(); - cursor.setPosition(real_tick_pos); - ui_vp_message->setTextCursor(cursor); - real_tick_pos += f_char_length; - } + //This should always be done AFTER setHtml. Scroll the chat window with the text. + + //Make the cursor follow the message + QTextCursor cursor = ui_vp_message->textCursor(); + cursor.setPosition(real_tick_pos); + ui_vp_message->setTextCursor(cursor); + real_tick_pos += f_char_length; + ui_vp_message->ensureCursorVisible(); // Keep the speed at bay. @@ -3256,11 +3300,27 @@ void Courtroom::on_ooc_toggle_clicked() } } +//Todo: multithread this due to some servers having large as hell music list void Courtroom::on_music_search_edited(QString p_text) { - //preventing compiler warnings - p_text += "a"; - list_music(); + // Iterate through all QTreeWidgetItem items + QTreeWidgetItemIterator it(ui_music_list); + while (*it) + { + (*it)->setHidden(p_text != ""); + ++it; + } + + if (p_text != "") + { + QList clist = ui_music_list->findItems(ui_music_search->text(), Qt::MatchContains|Qt::MatchRecursive, 0); + foreach(QTreeWidgetItem* item, clist) + { + if (item->parent() != nullptr) //So the category shows up too + item->parent()->setHidden(false); + item->setHidden(false); + } + } list_areas(); } @@ -3268,7 +3328,7 @@ void Courtroom::on_pos_dropdown_changed(int p_index) { ui_ic_chat_message->setFocus(); - if (p_index < 0 || p_index > 5) + if (p_index < 0 || p_index > 7) return; toggle_judge_buttons(false); @@ -3296,18 +3356,27 @@ void Courtroom::on_pos_dropdown_changed(int p_index) case 5: f_pos = "hlp"; break; + case 6: + f_pos = "jur"; + break; + case 7: + f_pos = "sea"; + break; default: f_pos = ""; } - if (f_pos == "" || ui_ooc_chat_name->text() == "") + if (f_pos == "") return; - ao_app->send_server_packet(new AOPacket("CT#" + ui_ooc_chat_name->text() + "#/pos " + f_pos + "#%")); + //YEAH SENDING LIKE 20 PACKETS IF THE USER SCROLLS THROUGH, GREAT IDEA + //how about this instead + set_side(f_pos); } void Courtroom::set_iniswap_dropdown() { + ui_iniswap_dropdown->blockSignals(true); ui_iniswap_dropdown->clear(); if (m_cid == -1) { @@ -3338,6 +3407,7 @@ void Courtroom::set_iniswap_dropdown() break; } } + ui_iniswap_dropdown->blockSignals(false); } void Courtroom::on_iniswap_dropdown_changed(int p_index) @@ -3354,7 +3424,9 @@ void Courtroom::on_iniswap_dropdown_changed(int p_index) swaplist.append(entry); } ao_app->write_to_file(swaplist.join("\n"), ao_app->get_character_path(char_list.at(m_cid).name, "iniswaps.ini")); + ui_iniswap_dropdown->blockSignals(true); ui_iniswap_dropdown->setCurrentIndex(p_index); + ui_iniswap_dropdown->blockSignals(false); update_character(m_cid); if (p_index != 0) ui_iniswap_remove->show(); @@ -3364,6 +3436,11 @@ void Courtroom::on_iniswap_dropdown_changed(int p_index) void Courtroom::on_iniswap_remove_clicked() { + if (ui_iniswap_dropdown->count() <= 0) + { + ui_iniswap_remove->hide(); //We're not supposed to see it. Do this or the client will crash + return; + } if (ui_iniswap_dropdown->itemText(ui_iniswap_dropdown->currentIndex()) != char_list.at(m_cid).name) { ui_iniswap_dropdown->removeItem(ui_iniswap_dropdown->currentIndex()); @@ -3374,6 +3451,7 @@ void Courtroom::on_iniswap_remove_clicked() void Courtroom::set_sfx_dropdown() { + ui_sfx_dropdown->blockSignals(true); ui_sfx_dropdown->clear(); if (m_cid == -1) { @@ -3404,6 +3482,7 @@ void Courtroom::set_sfx_dropdown() ui_sfx_dropdown->addItems(soundlist); ui_sfx_dropdown->setCurrentIndex(0); ui_sfx_remove->hide(); + ui_sfx_dropdown->blockSignals(false); } void Courtroom::on_sfx_dropdown_changed(int p_index) @@ -3427,7 +3506,9 @@ void Courtroom::on_sfx_dropdown_changed(int p_index) if (defaultlist.size() > 0 && defaultlist.toSet().subtract(soundlist.toSet()).size() > 0) //There's a difference from the default configuration ao_app->write_to_file(soundlist.join("\n"), ao_app->get_character_path(current_char, "soundlist.ini")); //Create a new sound list + ui_sfx_dropdown->blockSignals(true); ui_sfx_dropdown->setCurrentIndex(p_index); + ui_sfx_dropdown->blockSignals(false); if (p_index != 0) ui_sfx_remove->show(); else @@ -3436,6 +3517,11 @@ void Courtroom::on_sfx_dropdown_changed(int p_index) void Courtroom::on_sfx_remove_clicked() { + if (ui_sfx_dropdown->count() <= 0) + { + ui_sfx_remove->hide(); //We're not supposed to see it. Do this or the client will crash + return; + } if (ui_sfx_dropdown->itemText(ui_sfx_dropdown->currentIndex()) != "Default") { ui_sfx_dropdown->removeItem(ui_sfx_dropdown->currentIndex()); @@ -3445,6 +3531,7 @@ void Courtroom::on_sfx_remove_clicked() void Courtroom::set_effects_dropdown() { + ui_effects_dropdown->blockSignals(true); ui_effects_dropdown->clear(); if (m_cid == -1) { @@ -3488,6 +3575,7 @@ void Courtroom::set_effects_dropdown() } ui_effects_dropdown->setCurrentIndex(0); + ui_effects_dropdown->blockSignals(false); } void Courtroom::on_effects_dropdown_changed(int p_index) diff --git a/src/emotes.cpp b/src/emotes.cpp index 3e96824..58e8594 100644 --- a/src/emotes.cpp +++ b/src/emotes.cpp @@ -107,7 +107,7 @@ void Courtroom::set_emote_page() if (current_emote_page > 0) ui_emote_left->show(); - for (int n_emote = 0 ; n_emote < emotes_on_page ; ++n_emote) + for (int n_emote = 0 ; n_emote < emotes_on_page && n_emote < ui_emote_list.size(); ++n_emote) { int n_real_emote = n_emote + current_emote_page * max_emotes_on_page; AOEmoteButton *f_emote = ui_emote_list.at(n_emote); diff --git a/src/packet_distribution.cpp b/src/packet_distribution.cpp index 3060530..097d251 100644 --- a/src/packet_distribution.cpp +++ b/src/packet_distribution.cpp @@ -531,46 +531,32 @@ void AOApplication::server_packet_received(AOPacket *p_packet) send_server_packet(new AOPacket("RD#%")); } - else if (header == "FM") + else if (header == "FM") //Fetch music ONLY { if (!courtroom_constructed) goto end; w_courtroom->clear_music(); - w_courtroom->clear_areas(); - - bool musics_time = false; - int areas = 0; for (int n_element = 0 ; n_element < f_contents.size() ; ++n_element) { - if (musics_time) - { - w_courtroom->append_music(f_contents.at(n_element)); - } - else - { - if (f_contents.at(n_element).endsWith(".wav") || - f_contents.at(n_element).endsWith(".mp3") || - f_contents.at(n_element).endsWith(".mp4") || - f_contents.at(n_element).endsWith(".ogg") || - f_contents.at(n_element).endsWith(".opus")) - { - musics_time = true; - w_courtroom->fix_last_area(); - w_courtroom->append_music(f_contents.at(n_element)); - areas--; -// qDebug() << "wtf!!" << f_contents.at(n_element); - } - else - { - w_courtroom->append_area(f_contents.at(n_element)); - areas++; - } - } + w_courtroom->append_music(f_contents.at(n_element)); } w_courtroom->list_music(); + } + else if (header == "FA") //Fetch areas ONLY + { + if (!courtroom_constructed) + goto end; + + w_courtroom->clear_areas(); + + for (int n_element = 0 ; n_element < f_contents.size() ; ++n_element) + { + w_courtroom->append_area(f_contents.at(n_element)); + } + w_courtroom->list_areas(); } else if (header == "DONE") @@ -597,7 +583,7 @@ void AOApplication::server_packet_received(AOPacket *p_packet) { if (f_contents.size() >= 2) //We have a pos included in the background packet! w_courtroom->set_side(f_contents.at(1)); - w_courtroom->set_background(f_contents.at(0)); + w_courtroom->set_background(f_contents.at(0), f_contents.size() >= 2); } } else if (header == "SP") diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index 2b86a1e..35e42b4 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -831,18 +831,19 @@ QStringList AOApplication::get_theme_effects() QString p_path = get_theme_path("effects/effects.ini"); QString default_path = get_default_theme_path("effects/effects.ini"); + 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"); - QStringList effects; + QStringList lines = read_file(p_path).split("\n"); foreach (QString effect, lines) { effect = effect.split("=")[0].trimmed(); - qDebug() << effect; - if (effect != "" && !effects.contains(effect)) + if (!effect.isEmpty() && !effects.contains(effect)) effects.append(effect); } return effects; @@ -853,14 +854,15 @@ 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 lines = read_file(p_path).split("\n"); - 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(); - qDebug() << effect; - if (effect != "" && !effects.contains(effect)) + if (!effect.isEmpty() && !effects.contains(effect)) effects.append(effect); } From 0eccf1ba2285bfc2ffe812cd0a2cdee778053171 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Tue, 1 Oct 2019 01:38:38 +0300 Subject: [PATCH 100/268] Make screenshakes work with preanim delays --- src/courtroom.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 544e340..ce26b23 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -2457,7 +2457,8 @@ void Courtroom::start_chat_ticking() sfx_player->play(ao_app->get_custom_realization(m_chatmessage[CHAR_NAME])); } - if (m_chatmessage[SCREENSHAKE] == "1") + int emote_mod = m_chatmessage[EMOTE_MOD].toInt(); //text meme bonanza + if ((emote_mod == 0 || emote_mod == 5) && m_chatmessage[SCREENSHAKE] == "1") { this->do_screenshake(); } @@ -2682,7 +2683,10 @@ void Courtroom::chat_tick() void Courtroom::play_sfx() { QString sfx_name = m_chatmessage[SFX_NAME]; - + if (m_chatmessage[SCREENSHAKE] == "1") //Screenshake dependant on preanim sfx delay meme + { + this->do_screenshake(); + } if (sfx_name == "1") return; From 292c425c7895afcd8a545afa40dffefea803aabc Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Tue, 1 Oct 2019 04:58:57 +0300 Subject: [PATCH 101/268] Fix music volume being weird due to m_volume being shared by ambience and music at the same time Fix version= being wrong --- Attorney_Online.pro | 2 +- include/aomusicplayer.h | 2 +- src/aomusicplayer.cpp | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Attorney_Online.pro b/Attorney_Online.pro index 5daf73f..5d3eda0 100644 --- a/Attorney_Online.pro +++ b/Attorney_Online.pro @@ -3,7 +3,7 @@ QT += core gui widgets network TARGET = Attorney_Online TEMPLATE = app -VERSION = 2.8.0.0 +VERSION = 2.8.0.2 INCLUDEPATH += $$PWD/include DESTDIR = $$PWD/bin diff --git a/include/aomusicplayer.h b/include/aomusicplayer.h index 9ce7485..15014af 100644 --- a/include/aomusicplayer.h +++ b/include/aomusicplayer.h @@ -37,7 +37,7 @@ private: AOApplication *ao_app; bool m_looping = false; - int m_volume = 0; + int m_volume[4] = {0, 0, 0, 0}; // Channel 0 = music // Channel 1 = ambience diff --git a/src/aomusicplayer.cpp b/src/aomusicplayer.cpp index c845948..b44e2e2 100644 --- a/src/aomusicplayer.cpp +++ b/src/aomusicplayer.cpp @@ -66,7 +66,7 @@ void AOMusicPlayer::play(QString p_song, int channel, bool crossfade) //Start it BASS_ChannelPlay(newstream, false); //Fade in our sample - BASS_ChannelSlideAttribute(newstream, BASS_ATTRIB_VOL, static_cast(m_volume / 100.0f), 1000); + BASS_ChannelSlideAttribute(newstream, BASS_ATTRIB_VOL, static_cast(m_volume[channel] / 100.0f), 1000); m_stream_list[channel] = newstream; } @@ -75,7 +75,7 @@ void AOMusicPlayer::play(QString p_song, int channel, bool crossfade) BASS_ChannelStop(m_stream_list[channel]); m_stream_list[channel] = newstream; BASS_ChannelPlay(m_stream_list[channel], false); - this->set_volume(m_volume, channel); + this->set_volume(m_volume[channel], channel); } this->set_looping(m_looping); //Have to do this here due to any crossfading-related changes, etc. @@ -88,8 +88,8 @@ void AOMusicPlayer::stop(int channel) void AOMusicPlayer::set_volume(int p_value, int channel) { - m_volume = p_value; - float volume = m_volume / 100.0f; + m_volume[channel] = p_value; + float volume = m_volume[channel] / 100.0f; if (channel < 0) { for (int n_stream = 0 ; n_stream < m_channelmax ; ++n_stream) From 4c23e159350eeb3d74faf7e814f2874787e02565 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Wed, 2 Oct 2019 01:20:00 +0300 Subject: [PATCH 102/268] Rewrite pairing character ordering logic to instead operate based on a user-accessible drpodown menu (it's a dropdown for the future when there's more options) Fix current charmovie breaking offsets Make pairing offsets applicable even without a pairing partner, making it a generic offset Fix the chat message hardcoding max colors to 8 (when it should be max_colors) Come up with a way to convey the ordering information without creating an extra new packet in a cool way (backwards compatibility AND less clutter!) More info on the evidence_x and evidence_ok tooltips Don't mute music when you switch to CSS anymore --- include/courtroom.h | 8 ++- src/aocharmovie.cpp | 2 +- src/courtroom.cpp | 152 +++++++++++++++++--------------------------- src/evidence.cpp | 5 +- 4 files changed, 69 insertions(+), 98 deletions(-) diff --git a/include/courtroom.h b/include/courtroom.h index c680de0..aeef3ca 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -266,7 +266,10 @@ private: int other_charid = -1; // The offset this user has given if they want to appear alongside someone. - int offset_with_pair = 0; + int char_offset = 0; + + // 0 = in front, 1 = behind + int pair_order = 0; QVector char_list; QVector evidence_list; @@ -464,6 +467,8 @@ private: QListWidget *ui_pair_list; QSpinBox *ui_pair_offset_spinbox; + QComboBox *ui_pair_order_dropdown; + AOLineEdit *ui_ic_chat_message; QLineEdit *ui_ic_chat_name; @@ -672,6 +677,7 @@ private slots: 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(); diff --git a/src/aocharmovie.cpp b/src/aocharmovie.cpp index 96e84d4..6f6c3a1 100644 --- a/src/aocharmovie.cpp +++ b/src/aocharmovie.cpp @@ -240,7 +240,7 @@ QPixmap AOCharMovie::get_pixmap(QImage image) f_pixmap = f_pixmap.scaledToHeight(f_h, transform_mode); this->resize(f_pixmap.size()); - this->move((f_w - f_pixmap.width())/2, (f_h - f_pixmap.height())); //Always center horizontally, always put at the bottom vertically + this->move(x + (f_w - f_pixmap.width())/2, y + (f_h - f_pixmap.height())); //Always center horizontally, always put at the bottom vertically return f_pixmap; } diff --git a/src/courtroom.cpp b/src/courtroom.cpp index ce26b23..978fbbe 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -272,6 +272,11 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_pair_offset_spinbox = new QSpinBox(this); ui_pair_offset_spinbox->setRange(-100,100); ui_pair_offset_spinbox->setSuffix(tr("% offset")); + + ui_pair_order_dropdown = new QComboBox(this); + ui_pair_order_dropdown->addItem("To front"); + ui_pair_order_dropdown->addItem("To behind"); + ui_pair_button = new AOButton(this, ao_app); ui_evidence_button = new AOButton(this, ao_app); @@ -360,6 +365,7 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() connect(ui_pair_button, SIGNAL(clicked()), this, SLOT(on_pair_clicked())); connect(ui_pair_list, SIGNAL(clicked(QModelIndex)), this, SLOT(on_pair_list_clicked(QModelIndex))); connect(ui_pair_offset_spinbox, SIGNAL(valueChanged(int)), this, SLOT(on_pair_offset_changed(int))); + connect(ui_pair_order_dropdown, SIGNAL(currentIndexChanged(int)), this, SLOT(on_pair_order_dropdown_changed(int))); connect(ui_evidence_button, SIGNAL(clicked()), this, SLOT(on_evidence_button_clicked())); @@ -536,9 +542,15 @@ void Courtroom::set_widgets() 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 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_offset_spinbox->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.")); @@ -1411,7 +1423,7 @@ void Courtroom::on_chat_return_pressed() if (text_color < 0) f_text_color = "0"; - else if (text_color > 8) + else if (text_color > max_colors) f_text_color = "0"; else f_text_color = QString::number(text_color); @@ -1435,14 +1447,17 @@ void Courtroom::on_chat_return_pressed() // Or a charid of -1 or lower, through some means. if (other_charid > -1 && other_charid != m_cid) { - packet_contents.append(QString::number(other_charid)); - packet_contents.append(QString::number(offset_with_pair)); + QString packet = QString::number(other_charid); + if (ao_app->effects_enabled) //Only servers with effects enabled will support pair reordering + packet += "^" + QString::number(pair_order); + packet_contents.append(packet); } else { packet_contents.append("-1"); - packet_contents.append("0"); } + //Send the offset as it's gonna be used regardless + packet_contents.append(QString::number(char_offset)); // Finally, we send over if we want our pres to not interrupt. if (ui_pre_non_interrupt->isChecked() && ui_pre->isChecked()) @@ -1751,16 +1766,14 @@ void Courtroom::handle_chatmessage_2() // Making the second character appear. if (m_chatmessage[OTHER_CHARID].isEmpty()) { - // If there is no second character, hide 'em, and center the first. + // If there is no second character, hide 'em ui_vp_sideplayer_char->stop(); ui_vp_sideplayer_char->move(0,0); - - ui_vp_player_char->move(0,0); } else { bool ok; - int got_other_charid = m_chatmessage[OTHER_CHARID].toInt(&ok); + int got_other_charid = m_chatmessage[OTHER_CHARID].split("^")[0].toInt(&ok); if (ok) { if (got_other_charid > -1) @@ -1768,91 +1781,27 @@ void Courtroom::handle_chatmessage_2() // If there is, show them! ui_vp_sideplayer_char->show(); - // Depending on where we are, we offset the characters, and reorder their stacking. - if (side == "def") + int other_offset = m_chatmessage[OTHER_OFFSET].toInt(); + ui_vp_sideplayer_char->move(ui_viewport->width() * other_offset / 100, 0); + qDebug() << "other offset" << other_offset; + + QStringList args = m_chatmessage[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? { - // We also move the character down depending on how far the are to the right. - int hor_offset = m_chatmessage[SELF_OFFSET].toInt(); - int vert_offset = 0; - if (hor_offset > 0) - { - vert_offset = hor_offset / 10; - } - ui_vp_player_char->move(ui_viewport->width() * hor_offset / 100, ui_viewport->height() * vert_offset / 100); - - // We do the same with the second character. - int hor2_offset = m_chatmessage[OTHER_OFFSET].toInt(); - int vert2_offset = 0; - if (hor2_offset > 0) - { - vert2_offset = hor2_offset / 10; - } - ui_vp_sideplayer_char->move(ui_viewport->width() * hor2_offset / 100, ui_viewport->height() * vert2_offset / 100); - - // Finally, we reorder them based on who is more to the left. - // The person more to the left is more in the front. - if (hor2_offset >= hor_offset) - { - ui_vp_sideplayer_char->stackUnder(ui_vp_player_char); - } - else - { - ui_vp_player_char->stackUnder(ui_vp_sideplayer_char); + //Change the order of appearance based on the pair order variable + int order = args.at(1).toInt(); + switch (order) { + case 0: + ui_vp_sideplayer_char->stackUnder(ui_vp_player_char); + break; + case 1: + ui_vp_player_char->stackUnder(ui_vp_sideplayer_char); + break; + default: + break; } } - else if (side == "pro") - { - // Almost the same thing happens here, but in reverse. - int hor_offset = m_chatmessage[SELF_OFFSET].toInt(); - int vert_offset = 0; - if (hor_offset < 0) - { - // We don't want to RAISE the char off the floor. - vert_offset = -1 * hor_offset / 10; - } - ui_vp_player_char->move(ui_viewport->width() * hor_offset / 100, ui_viewport->height() * vert_offset / 100); - // We do the same with the second character. - int hor2_offset = m_chatmessage[OTHER_OFFSET].toInt(); - int vert2_offset = 0; - if (hor2_offset < 0) - { - vert2_offset = -1 * hor2_offset / 10; - } - ui_vp_sideplayer_char->move(ui_viewport->width() * hor2_offset / 100, ui_viewport->height() * vert2_offset / 100); - - // Finally, we reorder them based on who is more to the right. - if (hor2_offset >= hor_offset) - { - ui_vp_sideplayer_char->stackUnder(ui_vp_player_char); - } - else - { - ui_vp_player_char->stackUnder(ui_vp_sideplayer_char); - } - } - else - { - // In every other case, the person more to the left is on top. - // These cases also don't move the characters down. - int hor_offset = m_chatmessage[SELF_OFFSET].toInt(); - ui_vp_player_char->move(ui_viewport->width() * hor_offset / 100, 0); - - // We do the same with the second character. - int hor2_offset = m_chatmessage[OTHER_OFFSET].toInt(); - ui_vp_sideplayer_char->move(ui_viewport->width() * hor2_offset / 100, 0); - - // Finally, we reorder them based on who is more to the left. - // The person more to the left is more in the front. - if (hor2_offset >= hor_offset) - { - ui_vp_sideplayer_char->stackUnder(ui_vp_player_char); - } - else - { - ui_vp_player_char->stackUnder(ui_vp_sideplayer_char); - } - } // We should probably also play the other character's idle emote. if (ao_app->flipping_enabled && m_chatmessage[OTHER_FLIP].toInt() == 1) ui_vp_sideplayer_char->set_flipped(true); @@ -1866,11 +1815,19 @@ void Courtroom::handle_chatmessage_2() // really is no second character, hide 'em, and center the first. ui_vp_sideplayer_char->hide(); ui_vp_sideplayer_char->move(0,0); - - ui_vp_player_char->move(0,0); } } } + //Set ourselves according to SELF_OFFSET + + bool ok; + int self_offset = m_chatmessage[SELF_OFFSET].toInt(&ok); + if (ok) + ui_vp_player_char->move(ui_viewport->width() * self_offset / 100, 0); + else + ui_vp_player_char->move(0, 0); + + qDebug() << "offset OK" << ok << "offset value" << self_offset; switch (emote_mod) { case 1: case 2: case 6: @@ -3077,7 +3034,7 @@ void Courtroom::on_ooc_return_pressed() { if (off >= -100 && off <= 100) { - offset_with_pair = off; + char_offset = off; QString msg = tr("You have set your offset to "); msg.append(QString::number(off)); msg.append("%."); @@ -3852,6 +3809,7 @@ void Courtroom::on_mute_clicked() ui_mute_list->show(); ui_pair_list->hide(); ui_pair_offset_spinbox->hide(); + ui_pair_order_dropdown->hide(); ui_pair_button->set_image("pair_button"); ui_mute->set_image("mute_pressed"); } @@ -3868,6 +3826,7 @@ void Courtroom::on_pair_clicked() { ui_pair_list->show(); ui_pair_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"); @@ -3876,10 +3835,16 @@ void Courtroom::on_pair_clicked() { ui_pair_list->hide(); ui_pair_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; @@ -4014,7 +3979,7 @@ void Courtroom::on_log_limit_changed(int value) void Courtroom::on_pair_offset_changed(int value) { - offset_with_pair = value; + char_offset = value; } void Courtroom::on_witness_testimony_clicked() @@ -4059,7 +4024,6 @@ void Courtroom::on_guilty_clicked() void Courtroom::on_change_character_clicked() { - music_player->set_volume(0); sfx_player->set_volume(0); blip_player->set_volume(0); diff --git a/src/evidence.cpp b/src/evidence.cpp index 6ee2b8e..58f3181 100644 --- a/src/evidence.cpp +++ b/src/evidence.cpp @@ -24,9 +24,10 @@ void Courtroom::initialize_evidence() ui_evidence_image_button = new AOButton(ui_evidence_overlay, ao_app); ui_evidence_image_button->setText(tr("Choose...")); ui_evidence_x = new AOButton(ui_evidence_overlay, ao_app); - ui_evidence_x->setToolTip(tr("Close the evidence display/editing overlay")); + ui_evidence_x->setToolTip(tr("Close the evidence display/editing overlay.\n" + "You will be prompted if there's any unsaved changes.")); ui_evidence_ok = new AOButton(ui_evidence_overlay, ao_app); - ui_evidence_ok->setToolTip(tr("Save any changes made to this piece of evidence")); + ui_evidence_ok->setToolTip(tr("Save any changes made to this piece of evidence and send them to server.")); ui_evidence_description = new AOTextEdit(ui_evidence_overlay); ui_evidence_description->setStyleSheet("background-color: rgba(0, 0, 0, 0);" From e3ddc41cc8362fc17e803708826293d389413fc7 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Wed, 2 Oct 2019 20:28:42 +0300 Subject: [PATCH 103/268] Add rightclick context menus to sfx dropdown, iniswap dropdown and effects dropdown to open the ini's and respective folders try to fix settings menu (I failed) --- include/courtroom.h | 12 +++++ src/aooptionsdialog.cpp | 4 +- src/courtroom.cpp | 108 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 123 insertions(+), 1 deletion(-) diff --git a/include/courtroom.h b/include/courtroom.h index aeef3ca..86a4ea7 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -55,6 +55,8 @@ #include #include #include +#include +#include //#include #include @@ -628,6 +630,9 @@ private slots: void on_music_search_edited(QString p_text); void on_music_list_double_clicked(QTreeWidgetItem *p_item, int column); + void on_music_list_context_menu_requested(const QPoint &pos); + void music_list_expand_all(); + void music_list_collapse_all(); void on_area_list_double_clicked(QModelIndex p_model); void select_emote(int p_id); @@ -642,13 +647,20 @@ private slots: void on_iniswap_dropdown_changed(int p_index); void set_iniswap_dropdown(); + void on_iniswap_context_menu_requested(const QPoint &pos); + void on_iniswap_edit_requested(); void on_iniswap_remove_clicked(); void on_sfx_dropdown_changed(int p_index); void set_sfx_dropdown(); + void on_sfx_context_menu_requested(const QPoint &pos); + void on_sfx_edit_requested(); void on_sfx_remove_clicked(); void set_effects_dropdown(); + void on_effects_context_menu_requested(const QPoint &pos); + void on_effects_edit_requested(); + void on_character_effects_edit_requested(); void on_effects_dropdown_changed(int p_index); bool effects_dropdown_find_and_set(QString effect); diff --git a/src/aooptionsdialog.cpp b/src/aooptionsdialog.cpp index b926782..37694e4 100644 --- a/src/aooptionsdialog.cpp +++ b/src/aooptionsdialog.cpp @@ -12,7 +12,7 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi ui_settings_buttons = new QDialogButtonBox(this); - QSizePolicy sizePolicy1(QSizePolicy::Expanding, QSizePolicy::Maximum); + QSizePolicy sizePolicy1(QSizePolicy::Expanding, QSizePolicy::MinimumExpanding); sizePolicy1.setHorizontalStretch(0); sizePolicy1.setVerticalStretch(0); sizePolicy1.setHeightForWidth(ui_settings_buttons->sizePolicy().hasHeightForWidth()); @@ -36,6 +36,7 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi // Let's add the tabs one by one. // First, we'll start with 'Gameplay'. ui_gameplay_tab = new QWidget(); + ui_gameplay_tab->setSizePolicy(sizePolicy1); ui_settings_tabs->addTab(ui_gameplay_tab, tr("Gameplay")); ui_form_layout_widget = new QWidget(ui_gameplay_tab); ui_form_layout_widget->setGeometry(QRect(10, 10, 361, 211)); @@ -45,6 +46,7 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi ui_gameplay_form->setLabelAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter); ui_gameplay_form->setFormAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop); ui_gameplay_form->setContentsMargins(0, 0, 0, 0); + ui_gameplay_form->setSpacing(2); int row = 0; diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 978fbbe..cc5965c 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -131,6 +131,7 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_music_list->setHeaderHidden(true); ui_music_list->header()->setStretchLastSection(false); ui_music_list->header()->setSectionResizeMode(QHeaderView::ResizeToContents); + ui_music_list->setContextMenuPolicy(Qt::CustomContextMenu); ui_music_display = new AOMovie(this, ao_app); ui_music_display->set_play_once(false); @@ -182,12 +183,15 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_pos_dropdown->addItem("sea"); ui_iniswap_dropdown = new QComboBox(this); + ui_iniswap_dropdown->setContextMenuPolicy(Qt::CustomContextMenu); ui_iniswap_remove = new AOButton(this, ao_app); ui_sfx_dropdown = new QComboBox(this); + ui_sfx_dropdown->setContextMenuPolicy(Qt::CustomContextMenu); ui_sfx_remove = new AOButton(this, ao_app); ui_effects_dropdown = new QComboBox(this); + ui_effects_dropdown->setContextMenuPolicy(Qt::CustomContextMenu); ui_defense_bar = new AOImage(this, ao_app); ui_prosecution_bar = new AOImage(this, ao_app); @@ -301,12 +305,15 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() connect(ui_pos_dropdown, SIGNAL(currentIndexChanged(int)), this, SLOT(on_pos_dropdown_changed(int))); connect(ui_iniswap_dropdown, SIGNAL(currentIndexChanged(int)), this, SLOT(on_iniswap_dropdown_changed(int))); + connect(ui_iniswap_dropdown, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(on_iniswap_context_menu_requested(QPoint))); connect(ui_iniswap_remove, SIGNAL(clicked()), this, SLOT(on_iniswap_remove_clicked())); connect(ui_sfx_dropdown, SIGNAL(currentIndexChanged(int)), this, SLOT(on_sfx_dropdown_changed(int))); + connect(ui_sfx_dropdown, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(on_sfx_context_menu_requested(QPoint))); connect(ui_sfx_remove, SIGNAL(clicked()), this, SLOT(on_sfx_remove_clicked())); connect(ui_effects_dropdown, SIGNAL(currentIndexChanged(int)), this, SLOT(on_effects_dropdown_changed(int))); + connect(ui_effects_dropdown, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(on_effects_context_menu_requested(QPoint))); connect(ui_mute_list, SIGNAL(clicked(QModelIndex)), this, SLOT(on_mute_list_clicked(QModelIndex))); @@ -315,6 +322,7 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() connect(ui_ooc_chat_message, SIGNAL(returnPressed()), this, SLOT(on_ooc_return_pressed())); connect(ui_music_list, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this, SLOT(on_music_list_double_clicked(QTreeWidgetItem*, int))); + connect(ui_music_list, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(on_music_list_context_menu_requested(QPoint))); connect(ui_area_list, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(on_area_list_double_clicked(QModelIndex))); connect(ui_hold_it, SIGNAL(clicked()), this, SLOT(on_hold_it_clicked())); @@ -3395,6 +3403,25 @@ void Courtroom::on_iniswap_dropdown_changed(int p_index) ui_iniswap_remove->hide(); } +void Courtroom::on_iniswap_context_menu_requested(const QPoint &pos) +{ + QMenu *menu = ui_iniswap_dropdown->lineEdit()->createStandardContextMenu(); + + menu->addSeparator(); + if (file_exists(ao_app->get_character_path(current_char, "char.ini"))) + menu->addAction(QString("Edit " + current_char + "/char.ini"), this, SLOT(on_iniswap_edit_requested())); + if (ui_iniswap_dropdown->itemText(ui_iniswap_dropdown->currentIndex()) != char_list.at(m_cid).name) + menu->addAction(QString("Remove " + current_char), this, SLOT(on_iniswap_remove_clicked())); + menu->popup(ui_iniswap_dropdown->mapToGlobal(pos)); +} +void Courtroom::on_iniswap_edit_requested() +{ + QString p_path = ao_app->get_character_path(current_char, "char.ini"); + if (!file_exists(p_path)) + return; + QDesktopServices::openUrl(QUrl(p_path)); +} + void Courtroom::on_iniswap_remove_clicked() { if (ui_iniswap_dropdown->count() <= 0) @@ -3476,6 +3503,37 @@ void Courtroom::on_sfx_dropdown_changed(int p_index) ui_sfx_remove->hide(); } +void Courtroom::on_sfx_context_menu_requested(const QPoint &pos) +{ + QMenu *menu = ui_sfx_dropdown->lineEdit()->createStandardContextMenu(); + + menu->addSeparator(); + if (file_exists(ao_app->get_character_path(current_char, "soundlist.ini"))) + menu->addAction(QString("Edit " + current_char + "/soundlist.ini"), this, SLOT(on_sfx_edit_requested())); + else + menu->addAction(QString("Edit theme's character_soundlist.ini"), this, SLOT(on_sfx_edit_requested())); + if (ui_sfx_dropdown->currentIndex() != 0) + menu->addAction(QString("Remove " + ui_sfx_dropdown->itemText(ui_sfx_dropdown->currentIndex())), this, SLOT(on_sfx_remove_clicked())); + menu->popup(ui_sfx_dropdown->mapToGlobal(pos)); +} +void Courtroom::on_sfx_edit_requested() +{ + QString p_path = ao_app->get_character_path(current_char, "soundlist.ini"); + if (!file_exists(p_path)) + { + p_path = ao_app->get_theme_path("character_soundlist.ini"); + if (!file_exists(p_path)) + { + p_path = ao_app->get_default_theme_path("character_soundlist.ini"); + if (!file_exists(p_path)) + { + return; + } + } + } + QDesktopServices::openUrl(QUrl(p_path)); +} + void Courtroom::on_sfx_remove_clicked() { if (ui_sfx_dropdown->count() <= 0) @@ -3539,6 +3597,38 @@ void Courtroom::set_effects_dropdown() ui_effects_dropdown->blockSignals(false); } +void Courtroom::on_effects_context_menu_requested(const QPoint &pos) +{ + QMenu *menu = new QMenu(); + + if (!ao_app->read_char_ini(current_char, "effects", "Options").isEmpty()) + menu->addAction(QString("Open misc/" + ao_app->read_char_ini(current_char, "effects", "Options") + " folder"), this, SLOT(on_character_effects_edit_requested())); + menu->addAction(QString("Open theme's effects folder"), this, SLOT(on_effects_edit_requested())); + menu->popup(ui_effects_dropdown->mapToGlobal(pos)); +} +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/"); + if (!dir_exists(p_path)) + { + return; + } + } + QDesktopServices::openUrl(QUrl(p_path)); +} +void Courtroom::on_character_effects_edit_requested() +{ + QString p_effect = ao_app->read_char_ini(current_char, "effects", "Options"); + QString p_path = ao_app->get_base_path() + "misc/" + p_effect + "/"; + if (!dir_exists(p_path)) + return; + + QDesktopServices::openUrl(QUrl(p_path)); +} + void Courtroom::on_effects_dropdown_changed(int p_index) { effect = ui_effects_dropdown->itemText(p_index); @@ -3679,6 +3769,24 @@ void Courtroom::on_music_list_double_clicked(QTreeWidgetItem *p_item, int column } } +void Courtroom::on_music_list_context_menu_requested(const QPoint &pos) +{ + QMenu *menu = new QMenu(); + + menu->addAction(QString("Expand All Categories"), this, SLOT(music_list_expand_all())); + menu->addAction(QString("Collapse All Categories"), this, SLOT(music_list_collapse_all())); + // menu->addSeparator(); + menu->popup(ui_music_list->mapToGlobal(pos)); +} +void Courtroom::music_list_expand_all() +{ + ui_music_list->expandAll(); +} +void Courtroom::music_list_collapse_all() +{ + ui_music_list->collapseAll(); +} + void Courtroom::on_area_list_double_clicked(QModelIndex p_model) { QString p_area = area_list.at(area_row_to_number.at(p_model.row())); From 6f5b3d24621bc938c246daffd7ab47afa095c4c2 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Thu, 3 Oct 2019 01:00:15 +0300 Subject: [PATCH 104/268] Add support for backgrounds outside of predefined positions, grabbing the overlay from X_overlay.png/.gif/.webp/etc. --- src/courtroom.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index cc5965c..794242f 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -2715,6 +2715,12 @@ void Courtroom::set_scene(QString f_desk_mod, QString f_side) f_desk_image = "estrado"; } + if (file_exists(ao_app->get_image_suffix(ao_app->get_background_path(f_side)))) //Unique pos path + { + f_background = f_side; + f_desk_image = f_side + "_overlay"; + } + ui_vp_background->set_image(f_background); ui_vp_desk->set_image(f_desk_image); ui_vp_legacy_desk->set_legacy_desk(f_desk_image); From 829604e8089736945e8121cd134c3c3fcbf28291 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Thu, 3 Oct 2019 15:44:18 +0300 Subject: [PATCH 105/268] Positional evidence implemented. Click a button to change between private/global evidence list. There's also a button to transfer evidence to global/private, context sensitive. TODO: Save/load private evidence list --- include/courtroom.h | 10 +++ src/evidence.cpp | 207 ++++++++++++++++++++++++++++++++++---------- 2 files changed, 173 insertions(+), 44 deletions(-) diff --git a/include/courtroom.h b/include/courtroom.h index 86a4ea7..9f3b659 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -411,6 +411,11 @@ private: int max_emotes_on_page = 10; QVector local_evidence_list; + QVector private_evidence_list; + QVector global_evidence_list; + + //false = use private_evidence_list + bool current_evidence_global = true; int current_evidence_page = 0; int current_evidence = 0; @@ -563,6 +568,8 @@ private: AOButton *ui_evidence_image_button; AOButton *ui_evidence_x; AOButton *ui_evidence_ok; + AOButton *ui_evidence_switch; + AOButton *ui_evidence_transfer; AOTextEdit *ui_evidence_description; AOImage *ui_char_select_background; @@ -733,10 +740,13 @@ private slots: void on_evidence_delete_clicked(); void on_evidence_x_clicked(); void on_evidence_ok_clicked(); + void on_evidence_switch_clicked(); + void on_evidence_transfer_clicked(); void on_evidence_edited(); void evidence_close(); + void evidence_switch(bool global); bool compare_evidence_changed(evi_type evi_a, evi_type evi_b); void on_back_to_lobby_clicked(); diff --git a/src/evidence.cpp b/src/evidence.cpp index 58f3181..82e496d 100644 --- a/src/evidence.cpp +++ b/src/evidence.cpp @@ -16,6 +16,9 @@ void Courtroom::initialize_evidence() ui_evidence_present = new AOButton(ui_evidence, ao_app); ui_evidence_present->setToolTip(tr("Present this piece of evidence to everyone on your next spoken message")); + ui_evidence_switch = new AOButton(ui_evidence, ao_app); + ui_evidence_transfer = new AOButton(ui_evidence, ao_app); + ui_evidence_overlay = new AOImage(ui_evidence, ao_app); ui_evidence_delete = new AOButton(ui_evidence_overlay, ao_app); @@ -40,6 +43,9 @@ void Courtroom::initialize_evidence() connect(ui_evidence_left, SIGNAL(clicked()), this, SLOT(on_evidence_left_clicked())); connect(ui_evidence_right, SIGNAL(clicked()), this, SLOT(on_evidence_right_clicked())); connect(ui_evidence_present, SIGNAL(clicked()), this, SLOT(on_evidence_present_clicked())); + connect(ui_evidence_switch, SIGNAL(clicked()), this, SLOT(on_evidence_switch_clicked())); + connect(ui_evidence_transfer, SIGNAL(clicked()), this, SLOT(on_evidence_transfer_clicked())); + connect(ui_evidence_delete, SIGNAL(clicked()), this, SLOT(on_evidence_delete_clicked())); connect(ui_evidence_image_name, SIGNAL(returnPressed()), this, SLOT(on_evidence_image_name_edited())); connect(ui_evidence_image_name, SIGNAL(double_clicked()), this, SLOT(on_evidence_image_name_double_clicked())); @@ -65,11 +71,14 @@ void Courtroom::refresh_evidence() ui_evidence_list.clear(); set_size_and_pos(ui_evidence_button, "evidence_button"); - ui_evidence_button->set_image("evidencebutton"); + ui_evidence_button->set_image("evidence_button"); ui_evidence_button->setToolTip(tr("Bring up the Evidence screen.")); set_size_and_pos(ui_evidence, "evidence_background"); - ui_evidence->set_image("evidencebackground"); + if (current_evidence_global) + ui_evidence->set_image("evidence_background"); + else + ui_evidence->set_image("evidence_background_private"); set_size_and_pos(ui_evidence_name, "evidence_name"); @@ -85,20 +94,47 @@ void Courtroom::refresh_evidence() ui_evidence_present->set_image("present"); set_size_and_pos(ui_evidence_overlay, "evidence_overlay"); - ui_evidence_overlay->set_image("evidenceoverlay"); + if (current_evidence_global) + ui_evidence_overlay->set_image("evidence_overlay"); + else + ui_evidence_overlay->set_image("evidence_overlay_private"); set_size_and_pos(ui_evidence_delete, "evidence_delete"); - ui_evidence_delete->set_image("deleteevidence"); + ui_evidence_delete->set_image("evidence_delete"); set_size_and_pos(ui_evidence_image_name, "evidence_image_name"); set_size_and_pos(ui_evidence_image_button, "evidence_image_button"); set_size_and_pos(ui_evidence_x, "evidence_x"); - ui_evidence_x->set_image("evidencex"); + ui_evidence_x->set_image("evidence_x"); set_size_and_pos(ui_evidence_ok, "evidence_ok"); - ui_evidence_ok->set_image("evidenceok"); + ui_evidence_ok->set_image("evidence_ok"); + + set_size_and_pos(ui_evidence_switch, "evidence_switch"); + if (current_evidence_global) + { + ui_evidence_switch->set_image("evidence_global"); + ui_evidence_switch->setToolTip(tr("Switch evidence to private inventory.")); + } + else + { + ui_evidence_switch->set_image("evidence_private"); + ui_evidence_switch->setToolTip(tr("Switch evidence to global inventory.")); + } + + set_size_and_pos(ui_evidence_transfer, "evidence_transfer"); + if (current_evidence_global) + { + ui_evidence_transfer->set_image("evidence_transfer"); + ui_evidence_transfer->setToolTip(tr("Transfer evidence to private inventory.")); + } + else + { + ui_evidence_transfer->set_image("evidence_transfer_private"); + ui_evidence_transfer->setToolTip(tr("Transfer evidence to global inventory.")); + } set_size_and_pos(ui_evidence_description, "evidence_description"); @@ -145,6 +181,10 @@ void Courtroom::refresh_evidence() void Courtroom::set_evidence_list(QVector &p_evi_list) { + global_evidence_list = p_evi_list; + if (!current_evidence_global) + return; //We're on private evidence editing, wait for user to do their thing + QVector old_list = local_evidence_list; local_evidence_list.clear(); local_evidence_list = p_evi_list; @@ -171,7 +211,7 @@ void Courtroom::set_evidence_list(QVector &p_evi_list) msgBox->setInformativeText("Do you wish to keep your changes?"); msgBox->setDetailedText("Name: " + local_evidence_list.at(current_evidence).name + "\nImage: " + local_evidence_list.at(current_evidence).image + "\nDescription:\n" + local_evidence_list.at(current_evidence).description); msgBox->setStandardButtons(QMessageBox::Yes | QMessageBox::No); - msgBox->setDefaultButton(QMessageBox::No); + msgBox->setDefaultButton(QMessageBox::LastButton); //msgBox->setWindowModality(Qt::NonModal); int ret = msgBox->exec(); switch (ret) { @@ -259,18 +299,6 @@ void Courtroom::on_evidence_name_edited() ui_evidence_name->setReadOnly(true); if (current_evidence >= local_evidence_list.size()) return; - -// Prefer pressing [X] to update the evidence. -// QStringList f_contents; - -// evi_type f_evi = local_evidence_list.at(current_evidence); - -// f_contents.append(QString::number(current_evidence)); -// f_contents.append(ui_evidence_name->text()); -// f_contents.append(f_evi.description); -// f_contents.append(f_evi.image); - -// ao_app->send_server_packet(new AOPacket("EE", f_contents)); } void Courtroom::on_evidence_name_double_clicked() @@ -295,17 +323,6 @@ void Courtroom::on_evidence_image_name_edited() ui_evidence_image_name->setReadOnly(true); if (current_evidence >= local_evidence_list.size()) return; - -// QStringList f_contents; - -// evi_type f_evi = local_evidence_list.at(current_evidence); - -// f_contents.append(QString::number(current_evidence)); -// f_contents.append(f_evi.name); -// f_contents.append(f_evi.description); -// f_contents.append(ui_evidence_image_name->text()); - -// ao_app->send_server_packet(new AOPacket("EE", f_contents)); } void Courtroom::on_evidence_image_button_clicked() @@ -339,7 +356,19 @@ void Courtroom::on_evidence_clicked(int p_id) if (f_real_id == local_evidence_list.size()) { - ao_app->send_server_packet(new AOPacket("PE###empty.png#%")); + if (current_evidence_global) + ao_app->send_server_packet(new AOPacket("PE###empty.png#%")); + else + { + evi_type f_evi; + f_evi.name = ""; + f_evi.description = ""; + f_evi.image = "empty.png"; + + local_evidence_list.append(f_evi); + private_evidence_list = local_evidence_list; + set_evidence_page(); + } return; } else if (f_real_id > local_evidence_list.size()) @@ -425,6 +454,12 @@ void Courtroom::on_evidence_right_clicked() void Courtroom::on_evidence_present_clicked() { + if (!current_evidence_global) + { + ui_evidence_present->hide(); + is_presenting_evidence = false; + return; //otherwise we get force-disconnected + } if (is_presenting_evidence) ui_evidence_present->set_image("present"); else @@ -438,7 +473,14 @@ void Courtroom::on_evidence_present_clicked() void Courtroom::on_evidence_delete_clicked() { evidence_close(); - ao_app->send_server_packet(new AOPacket("DE#" + QString::number(current_evidence) + "#%")); + if (current_evidence_global) + ao_app->send_server_packet(new AOPacket("DE#" + QString::number(current_evidence) + "#%")); + else + { + local_evidence_list.remove(current_evidence); + private_evidence_list = local_evidence_list; + set_evidence_page(); + } current_evidence = 0; @@ -488,24 +530,82 @@ void Courtroom::on_evidence_ok_clicked() ui_evidence_description->setReadOnly(true); ui_evidence_image_name->setReadOnly(true); if (current_evidence < local_evidence_list.size()) + { + evi_type f_evi = local_evidence_list.at(current_evidence); + if (current_evidence_global) + { + QStringList f_contents; + f_contents.append(QString::number(current_evidence)); + f_contents.append(ui_evidence_name->text()); + f_contents.append(ui_evidence_description->toPlainText()); + f_contents.append(ui_evidence_image_name->text()); + + ao_app->send_server_packet(new AOPacket("EE", f_contents)); + } + else + { + f_evi.name = ui_evidence_name->text(); + f_evi.description = ui_evidence_description->toPlainText(); + f_evi.image = ui_evidence_image_name->text(); + local_evidence_list.replace(current_evidence, f_evi); + private_evidence_list = local_evidence_list; + ui_evidence_ok->hide(); + set_evidence_page(); + } + } +} + +void Courtroom::on_evidence_switch_clicked() +{ + evidence_close(); + evidence_switch(!current_evidence_global); + if (current_evidence_global) + { + ui_evidence_switch->set_image("evidence_global"); + ui_evidence->set_image("evidence_background"); + ui_evidence_overlay->set_image("evidence_overlay"); + ui_evidence_transfer->set_image("evidence_transfer"); + ui_evidence_transfer->setToolTip(tr("Transfer evidence to private inventory.")); + ui_evidence_switch->setToolTip(tr("Current evidence is global. Click to switch to private.")); + } + else + { + ui_evidence_switch->set_image("evidence_private"); + ui_evidence->set_image("evidence_background_private"); + ui_evidence_overlay->set_image("evidence_overlay_private"); + ui_evidence_transfer->set_image("evidence_transfer_private"); + ui_evidence_transfer->setToolTip(tr("Transfer evidence to global inventory.")); + ui_evidence_switch->setToolTip(tr("Current evidence is private. Click to switch to global.")); + } +} + +void Courtroom::on_evidence_transfer_clicked() +{ + if (current_evidence >= local_evidence_list.size()) + return; + + if (!current_evidence_global) //Transfer private evidence to global { evi_type f_evi = local_evidence_list.at(current_evidence); QStringList f_contents; - f_contents.append(QString::number(current_evidence)); - f_contents.append(ui_evidence_name->text()); - f_contents.append(ui_evidence_description->toPlainText()); - f_contents.append(ui_evidence_image_name->text()); + f_contents.append(f_evi.name); + f_contents.append(f_evi.description); + f_contents.append(f_evi.image); - ao_app->send_server_packet(new AOPacket("EE", f_contents)); - -// QMessageBox *msgBox = new QMessageBox; - -// msgBox->setText("You succesfully saved your changes."); -// msgBox->setStandardButtons(QMessageBox::Ok); -// msgBox->setDefaultButton(QMessageBox::Ok); -// msgBox->exec(); + ao_app->send_server_packet(new AOPacket("PE", f_contents)); } + else //Transfer global evidence to private + { + evi_type f_evi = local_evidence_list.at(current_evidence); + private_evidence_list.append(f_evi); + } + + QMessageBox *msgBox = new QMessageBox; + msgBox->setText("Evidence has been transferred."); + msgBox->setStandardButtons(QMessageBox::Ok); + msgBox->setDefaultButton(QMessageBox::Ok); + msgBox->exec(); } void Courtroom::on_evidence_edited() @@ -534,6 +634,25 @@ void Courtroom::evidence_close() ui_ic_chat_message->setFocus(); } +void Courtroom::evidence_switch(bool global) +{ + current_evidence_global = global; + is_presenting_evidence = false; + ui_evidence_present->set_image("present"); + local_evidence_list.clear(); + if (current_evidence_global) + { + local_evidence_list = global_evidence_list; + ui_evidence_present->show(); + } + else + { + local_evidence_list = private_evidence_list; + ui_evidence_present->hide(); + } + set_evidence_page(); +} + bool Courtroom::compare_evidence_changed(evi_type evi_a, evi_type evi_b) { return evi_a.name != evi_b.name || evi_a.image != evi_b.image || evi_a.description != evi_b.description; From bdef10ace5e99ebd0ae09d0821cc2557b07defdd Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Thu, 3 Oct 2019 17:01:41 +0300 Subject: [PATCH 106/268] Remove /rainbow as clientside slash commands are cursed. I shall purge all clientside slash command memery soon... Fix /save_case iterating from last to first instead of first to last Implement private evidence saving/loading to and from an .ini file --- include/courtroom.h | 4 +++ src/courtroom.cpp | 10 +----- src/evidence.cpp | 84 ++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 88 insertions(+), 10 deletions(-) diff --git a/include/courtroom.h b/include/courtroom.h index 9f3b659..f72e106 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -570,6 +570,8 @@ private: AOButton *ui_evidence_ok; AOButton *ui_evidence_switch; AOButton *ui_evidence_transfer; + AOButton *ui_evidence_save; + AOButton *ui_evidence_load; AOTextEdit *ui_evidence_description; AOImage *ui_char_select_background; @@ -747,6 +749,8 @@ private slots: void evidence_close(); void evidence_switch(bool global); + void on_evidence_save_clicked(); + void on_evidence_load_clicked(); bool compare_evidence_changed(evi_type evi_a, evi_type evi_b); void on_back_to_lobby_clicked(); diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 794242f..e715c79 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -2993,14 +2993,6 @@ void Courtroom::on_ooc_return_pressed() toggle_judge_buttons(false); } } - else if (ooc_message.startsWith("/rainbow") && ao_app->yellow_text_enabled && !rainbow_appended) - { - //ui_text_color->addItem("Rainbow"); - ui_ooc_chat_message->clear(); - //rainbow_appended = true; - append_server_chatmessage("CLIENT", tr("This does nothing, but there you go."), "1"); - return; - } else if (ooc_message.startsWith("/settings")) { ui_ooc_chat_message->clear(); @@ -3221,7 +3213,7 @@ void Courtroom::on_ooc_return_pressed() casefile.setValue("doc", ""); casefile.setValue("status",command[2]); casefile.sync(); - for(int i = local_evidence_list.size() - 1; i >= 0; i--) + for(int i = 0; i < local_evidence_list.size(); i++) { QString clean_evidence_dsc = local_evidence_list[i].description.replace(QRegularExpression("..."), ""); clean_evidence_dsc = clean_evidence_dsc.replace(clean_evidence_dsc.lastIndexOf(">"), 1, ""); diff --git a/src/evidence.cpp b/src/evidence.cpp index 82e496d..77044c9 100644 --- a/src/evidence.cpp +++ b/src/evidence.cpp @@ -19,6 +19,11 @@ void Courtroom::initialize_evidence() ui_evidence_switch = new AOButton(ui_evidence, ao_app); ui_evidence_transfer = new AOButton(ui_evidence, ao_app); + ui_evidence_save = new AOButton(ui_evidence, ao_app); + ui_evidence_save->setToolTip(tr("Save evidence to an .ini file.")); + ui_evidence_load = new AOButton(ui_evidence, ao_app); + ui_evidence_save->setToolTip(tr("Load evidence from an .ini file.")); + ui_evidence_overlay = new AOImage(ui_evidence, ao_app); ui_evidence_delete = new AOButton(ui_evidence_overlay, ao_app); @@ -45,6 +50,8 @@ void Courtroom::initialize_evidence() connect(ui_evidence_present, SIGNAL(clicked()), this, SLOT(on_evidence_present_clicked())); connect(ui_evidence_switch, SIGNAL(clicked()), this, SLOT(on_evidence_switch_clicked())); connect(ui_evidence_transfer, SIGNAL(clicked()), this, SLOT(on_evidence_transfer_clicked())); + connect(ui_evidence_save, SIGNAL(clicked()), this, SLOT(on_evidence_save_clicked())); + connect(ui_evidence_load, SIGNAL(clicked()), this, SLOT(on_evidence_load_clicked())); connect(ui_evidence_delete, SIGNAL(clicked()), this, SLOT(on_evidence_delete_clicked())); connect(ui_evidence_image_name, SIGNAL(returnPressed()), this, SLOT(on_evidence_image_name_edited())); @@ -136,6 +143,20 @@ void Courtroom::refresh_evidence() ui_evidence_transfer->setToolTip(tr("Transfer evidence to global inventory.")); } + set_size_and_pos(ui_evidence_save, "evidence_save"); + ui_evidence_save->set_image("evidence_save"); + if (current_evidence_global) + ui_evidence_save->hide(); + else + ui_evidence_save->show(); + + set_size_and_pos(ui_evidence_load, "evidence_load"); + ui_evidence_load->set_image("evidence_load"); + if (current_evidence_global) + ui_evidence_load->hide(); + else + ui_evidence_load->show(); + set_size_and_pos(ui_evidence_description, "evidence_description"); QPoint f_spacing = ao_app->get_button_spacing("evidence_button_spacing", "courtroom_design.ini"); @@ -584,6 +605,7 @@ void Courtroom::on_evidence_transfer_clicked() if (current_evidence >= local_evidence_list.size()) return; + QString name; if (!current_evidence_global) //Transfer private evidence to global { evi_type f_evi = local_evidence_list.at(current_evidence); @@ -593,16 +615,18 @@ void Courtroom::on_evidence_transfer_clicked() f_contents.append(f_evi.description); f_contents.append(f_evi.image); + name = f_evi.name; ao_app->send_server_packet(new AOPacket("PE", f_contents)); } else //Transfer global evidence to private { evi_type f_evi = local_evidence_list.at(current_evidence); + name = f_evi.name; private_evidence_list.append(f_evi); } QMessageBox *msgBox = new QMessageBox; - msgBox->setText("Evidence has been transferred."); + msgBox->setText("\"" + name + "\" has been transferred."); msgBox->setStandardButtons(QMessageBox::Ok); msgBox->setDefaultButton(QMessageBox::Ok); msgBox->exec(); @@ -644,15 +668,73 @@ void Courtroom::evidence_switch(bool global) { local_evidence_list = global_evidence_list; ui_evidence_present->show(); + ui_evidence_save->hide(); + ui_evidence_load->hide(); } else { local_evidence_list = private_evidence_list; ui_evidence_present->hide(); + ui_evidence_save->show(); + ui_evidence_load->show(); } set_evidence_page(); } +void Courtroom::on_evidence_save_clicked() +{ + if (current_evidence_global) + return; //Don't allow saving/loading operations when in global inventory mode for now + + QString p_path = QFileDialog::getSaveFileName(this, tr("Save Inventory"), "base/inventories/", tr("Ini Files (*.ini)")); + if (p_path.isEmpty()) + return; + + evidence_close(); + ui_evidence_name->setText(""); + + QSettings inventory(p_path, QSettings::IniFormat); + inventory.clear(); + for(int i = 0; i < local_evidence_list.size(); i++) + { + inventory.beginGroup(QString::number(i)); + inventory.setValue("name",local_evidence_list[i].name); + inventory.setValue("description",local_evidence_list[i].description); + inventory.setValue("image",local_evidence_list[i].image); + inventory.endGroup(); + } + inventory.sync(); +} + +void Courtroom::on_evidence_load_clicked() +{ + if (current_evidence_global) + return; //Don't allow saving/loading operations when in global inventory mode for now + + QString p_path = QFileDialog::getOpenFileName(this, tr("Open Inventory"), "base/inventories/", tr("Ini Files (*.ini)")); + if (p_path.isEmpty()) + return; + + evidence_close(); + ui_evidence_name->setText(""); + + QSettings inventory(p_path, QSettings::IniFormat); + local_evidence_list.clear(); + foreach (QString evi, inventory.childGroups()) + { + if (evi == "General") + continue; + + evi_type f_evi; + f_evi.name = inventory.value(evi + "/name", "UNKNOWN").value(); + f_evi.description = inventory.value(evi + "/description", "UNKNOWN").value(); + f_evi.image = inventory.value(evi + "/image", "UNKNOWN.png").value(); + local_evidence_list.append(f_evi); + } + private_evidence_list = local_evidence_list; + set_evidence_page(); +} + bool Courtroom::compare_evidence_changed(evi_type evi_a, evi_type evi_b) { return evi_a.name != evi_b.name || evi_a.image != evi_b.image || evi_a.description != evi_b.description; From cfc3312840ed9053dd1a8a292f3d0c1f818dc3a7 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Thu, 3 Oct 2019 17:13:23 +0300 Subject: [PATCH 107/268] Inject wholesome --- src/lobby.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/lobby.cpp b/src/lobby.cpp index 79f18e5..4ca4f49 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -339,10 +339,18 @@ void Lobby::on_about_clicked() "https://github.com/AttorneyOnline/AO2-Client
" "

Major development:
" "OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter" + "

2.8 Major Release development:
" + "Crystalwarrior, Iamgoofball" + "

2.8 Quality Assurance:
" + "WillDean, Captain N, Mr M, Riel, Seimmet, Fury McFlurry," + "CedricDewitt, Chewable Tablets, Fantos, Futugaze," + "Geck, Minx, Pandae, Sierra, CrazyJC, CaseyMayCazy," + "GreenBowers, Robotic Overlord, Veritas, Gin-Gi" "

Special thanks:
" "Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), " "Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, " - "Noevain, Cronnicossy") + "Noevain, Cronnicossy, the AO2 community, server hosts, game masters," + "case makers, content creators and players!") .arg(ao_app->get_version_string()); QMessageBox::about(this, "About", msg); } From 9451822e0929643f638b3c79d4fd646df98b567a Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Thu, 3 Oct 2019 23:17:21 +0300 Subject: [PATCH 108/268] Fix move func making characters slowly move to the left every frame on animated chars which are sized differently from viewport Add a new get_qfont function Fix message box font being different from every other font due to incorrect font loading scheme Fix ui_evidence_save and ui_evidence_load tooltips being wrong --- include/courtroom.h | 3 +++ src/aocharmovie.cpp | 2 +- src/courtroom.cpp | 30 ++++++++++++++++++------------ src/evidence.cpp | 2 +- 4 files changed, 23 insertions(+), 14 deletions(-) diff --git a/include/courtroom.h b/include/courtroom.h index f72e106..e800415 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -127,6 +127,9 @@ public: //sets font size based on theme ini files void set_font(QWidget *widget, QString class_name, QString p_identifier); + //Get the properly constructed font + QFont get_qfont(QString font_name, int f_pointsize); + //actual operation of setting the font on a widget void set_qfont(QWidget *widget, QString class_name, QFont font, QColor f_color = Qt::black, bool bold = false); diff --git a/src/aocharmovie.cpp b/src/aocharmovie.cpp index 6f6c3a1..f8dc8d2 100644 --- a/src/aocharmovie.cpp +++ b/src/aocharmovie.cpp @@ -240,7 +240,7 @@ QPixmap AOCharMovie::get_pixmap(QImage image) f_pixmap = f_pixmap.scaledToHeight(f_h, transform_mode); this->resize(f_pixmap.size()); - this->move(x + (f_w - f_pixmap.width())/2, y + (f_h - f_pixmap.height())); //Always center horizontally, always put at the bottom vertically + QLabel::move(x + (f_w - f_pixmap.width())/2, y + (f_h - f_pixmap.height())); //Always center horizontally, always put at the bottom vertically return f_pixmap; } diff --git a/src/courtroom.cpp b/src/courtroom.cpp index e715c79..ee744a8 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -606,6 +606,8 @@ void Courtroom::set_widgets() set_size_and_pos(ui_vp_showname, "showname"); set_size_and_pos(ui_vp_message, "message"); + ui_vp_message->hide(); + //We detached the text as parent from the chatbox so it doesn't get affected by the screenshake. ui_vp_message->move(ui_vp_message->x() + ui_vp_chatbox->x(), ui_vp_message->y() + ui_vp_chatbox->y()); ui_vp_message->setTextInteractionFlags(Qt::NoTextInteraction); @@ -848,37 +850,40 @@ void Courtroom::set_fonts() void Courtroom::set_font(QWidget *widget, QString class_name, QString p_identifier) { QString design_file = "courtroom_fonts.ini"; - int f_weight = ao_app->get_font_size(p_identifier, design_file); + int f_pointsize = ao_app->get_font_size(p_identifier, design_file); QString font_name = ao_app->get_font_name(p_identifier + "_font", design_file); QColor f_color = ao_app->get_color(p_identifier + "_color", design_file); - bool bold = ao_app->get_font_size(p_identifier + "_bold", design_file) == 1; // is the font bold or not? + this->set_qfont(widget, class_name, get_qfont(font_name, f_pointsize), f_color, bold); +} + +QFont Courtroom::get_qfont(QString font_name, int f_pointsize) +{ QFont font; if (font_name.isEmpty()) { - font = QFont("Arial", f_weight); + font = QFont("Arial", f_pointsize); font.setStyleHint(QFont::SansSerif, QFont::NoAntialias); } else - font = QFont(font_name, f_weight); - this->set_qfont(widget, class_name, font, f_color, bold); + font = QFont(font_name, f_pointsize); + return font; } void Courtroom::set_qfont(QWidget *widget, QString class_name, QFont font, QColor f_color, bool bold) { if(class_name.isEmpty()) class_name = widget->metaObject()->className(); - widget->setFont(font); - QString is_bold = ""; - if(bold) is_bold = "font: bold;"; + font.setBold(bold); + widget->setFont(font); QString style_sheet_string = class_name + " { background-color: rgba(0, 0, 0, 0);\n" + "color: rgba(" + QString::number(f_color.red()) + ", " + QString::number(f_color.green()) + ", " + - QString::number(f_color.blue()) + ", 255);\n" + is_bold + "}"; + QString::number(f_color.blue()) + ", 255);}"; widget->setStyleSheet(style_sheet_string); } @@ -1745,8 +1750,9 @@ void Courtroom::handle_chatmessage_2() ui_vp_message->hide(); ui_vp_chatbox->hide(); + //todo: put this in its own function or update QString design_file = "courtroom_fonts.ini"; - int f_weight = ao_app->get_font_size("message", design_file); + int f_pointsize = ao_app->get_font_size("message", design_file); QString font_name = ao_app->get_font_name("message_font", design_file); QColor f_color = ao_app->get_color("message_color", design_file); bool bold = ao_app->get_font_size("message_bold", design_file) == 1; // is the font bold or not? @@ -1757,8 +1763,8 @@ void Courtroom::handle_chatmessage_2() int chatsize = ao_app->get_chat_size(m_chatmessage[CHAR_NAME]); if (chatsize != -1) - f_weight = chatsize; - this->set_qfont(ui_vp_message, "", QFont(font_name, f_weight), f_color, bold); + f_pointsize = chatsize; + this->set_qfont(ui_vp_message, "", get_qfont(font_name, f_pointsize), f_color, bold); set_scene(m_chatmessage[DESK_MOD], m_chatmessage[SIDE]); diff --git a/src/evidence.cpp b/src/evidence.cpp index 77044c9..0cee435 100644 --- a/src/evidence.cpp +++ b/src/evidence.cpp @@ -22,7 +22,7 @@ void Courtroom::initialize_evidence() ui_evidence_save = new AOButton(ui_evidence, ao_app); ui_evidence_save->setToolTip(tr("Save evidence to an .ini file.")); ui_evidence_load = new AOButton(ui_evidence, ao_app); - ui_evidence_save->setToolTip(tr("Load evidence from an .ini file.")); + ui_evidence_load->setToolTip(tr("Load evidence from an .ini file.")); ui_evidence_overlay = new AOImage(ui_evidence, ao_app); From 65332f209c9344e1d3f643ebca32a23dd6f31bdf Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Fri, 4 Oct 2019 14:41:33 +0300 Subject: [PATCH 109/268] fucking hell it's not accurate and doesn't match the absolute quality when it's played back in audacity jesus christ will the torture ever end --- include/aomusicplayer.h | 5 +-- src/aomusicplayer.cpp | 80 ++++++++++++++++++++++++----------------- 2 files changed, 50 insertions(+), 35 deletions(-) diff --git a/include/aomusicplayer.h b/include/aomusicplayer.h index 15014af..1a91d8f 100644 --- a/include/aomusicplayer.h +++ b/include/aomusicplayer.h @@ -25,8 +25,8 @@ public: const int m_channelmax = 4; //These have to be public for the stupid sync thing -// QWORD loop_start = 0; -// QWORD loop_end = 0; + QWORD loop_start = 0; + QWORD loop_end = 0; public slots: void play(QString p_song, int channel=0, bool crossfade=false); @@ -44,6 +44,7 @@ private: // Channel 2 = extra // Channel 3 = extra HSTREAM m_stream_list[4]; + HSYNC loop_sync[4]; }; #elif defined(QTAUDIO) class AOMusicPlayer diff --git a/src/aomusicplayer.cpp b/src/aomusicplayer.cpp index b44e2e2..8fe6d15 100644 --- a/src/aomusicplayer.cpp +++ b/src/aomusicplayer.cpp @@ -21,24 +21,6 @@ void AOMusicPlayer::play(QString p_song, int channel, bool crossfade) if (channel < 0) //wtf? return; QString f_path = ao_app->get_music_path(p_song); -// QString d_path = f_path + ".txt"; - -// if (file_exists(d_path)) //Contains loop/etc. information file -// { -// QStringList lines = ao_app->read_file(d_path).split("\n"); -// foreach (QString line, lines) -// { -// QStringList args = line.split("="); -// if (args.size() < 2) -// continue; -// QString arg = args[0].trimmed(); -// if (arg == "loop_start") -// loop_start = args[1].trimmed().toUInt(); -// else if (arg == "loop_end") -// loop_end = args[1].trimmed().toUInt(); -// } -// qDebug() << "Found data file for song" << p_song << loop_start << loop_end; -// } unsigned int flags = BASS_STREAM_PRESCAN | BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE; if (m_looping) @@ -48,6 +30,34 @@ void AOMusicPlayer::play(QString p_song, int channel, bool crossfade) if (ao_app->get_audio_output_device() != "default") BASS_ChannelSetDevice(m_stream_list[channel], BASS_GetDevice()); + QString d_path = f_path + ".txt"; + + loop_start = 0; + loop_end = 0; + if (m_looping && file_exists(d_path)) //Contains loop/etc. information file + { + QStringList lines = ao_app->read_file(d_path).split("\n"); + foreach (QString line, lines) + { + QStringList args = line.split("="); + if (args.size() < 2) + continue; + QString arg = args[0].trimmed(); + + float sample_rate; + BASS_ChannelGetAttribute(newstream, BASS_ATTRIB_FREQ, &sample_rate); + qDebug() << sample_rate << args[1].trimmed(); + + if (arg == "loop_start") + loop_start = BASS_ChannelSeconds2Bytes(newstream, args[1].trimmed().toDouble() / static_cast(sample_rate)); + else if (arg == "loop_length") + loop_end = loop_start + BASS_ChannelSeconds2Bytes(newstream, args[1].trimmed().toDouble() / static_cast(sample_rate)); + else if (arg == "loop_end") + loop_end = BASS_ChannelSeconds2Bytes(newstream, args[1].trimmed().toDouble() / static_cast(sample_rate)); + } + qDebug() << "Found data file for song" << p_song << "length" << BASS_ChannelGetLength(newstream, BASS_POS_BYTE) << "loop start" << loop_start << "loop end" << loop_end; + } + if (crossfade) { DWORD oldstream = m_stream_list[channel]; @@ -103,28 +113,32 @@ void AOMusicPlayer::set_volume(int p_value, int channel) } } -//void CALLBACK loopProc(HSYNC handle, DWORD channel, DWORD data, void *user) -//{ -// AOMusicPlayer *self= static_cast(user); -// qDebug() << BASS_ChannelGetPosition(channel, BASS_POS_BYTE); -// BASS_ChannelSetPosition(channel, self->loop_start, BASS_POS_BYTE); -//} +void CALLBACK loopProc(HSYNC handle, DWORD channel, DWORD data, void *user) +{ + AOMusicPlayer *self= static_cast(user); + qDebug() << BASS_ChannelGetPosition(channel, BASS_POS_BYTE); + BASS_ChannelSetPosition(channel, self->loop_start, BASS_POS_BYTE); +} void AOMusicPlayer::set_looping(bool toggle, int channel) { m_looping = toggle; - if (BASS_ChannelFlags(m_stream_list[channel], 0, 0) & BASS_SAMPLE_LOOP) + qDebug() << "looping" << m_looping; + if (m_looping == false && BASS_ChannelFlags(m_stream_list[channel], 0, 0) & BASS_SAMPLE_LOOP) { - if (m_looping == false) - BASS_ChannelFlags(m_stream_list[channel], 0, BASS_SAMPLE_LOOP); // remove the LOOP flag -// BASS_ChannelRemoveSync(m_stream_list[channel], loop_sync); + BASS_ChannelFlags(m_stream_list[channel], 0, BASS_SAMPLE_LOOP); // remove the LOOP flag + BASS_ChannelRemoveSync(m_stream_list[channel], loop_sync[channel]); } - else + else if (m_looping == true) { - if (m_looping == true) - BASS_ChannelFlags(m_stream_list[channel], BASS_SAMPLE_LOOP, BASS_SAMPLE_LOOP); // set the LOOP flag -// if (loop_end > 0 && loop_end < BASS_ChannelGetLength(m_stream_list[channel], BASS_POS_BYTE)) -// loop_sync = BASS_ChannelSetSync(m_stream_list[channel], BASS_SYNC_POS | BASS_SYNC_MIXTIME, loop_end, loopProc, this); + BASS_ChannelFlags(m_stream_list[channel], BASS_SAMPLE_LOOP, BASS_SAMPLE_LOOP); // set the LOOP flag + BASS_ChannelRemoveSync(m_stream_list[channel], loop_sync[channel]); + qDebug() << loop_end; + if (loop_end > 0) + { + loop_sync[channel] = BASS_ChannelSetSync(m_stream_list[channel], BASS_SYNC_POS | BASS_SYNC_MIXTIME, loop_end, loopProc, this); + qDebug() << "Started loop sync"; + } } } #elif defined(QTAUDIO) From bc8158cc96dd36a18ba18b0271331463cd81c497 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sat, 5 Oct 2019 16:47:59 +0300 Subject: [PATCH 110/268] Meme fix to <>, ~~ and ~> parsing (does not fully solve the issue but at least hides it from the user) Allow ascii characters to be used for color dropdown symbols --- src/courtroom.cpp | 15 ++++++++++++--- src/text_file_functions.cpp | 2 +- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index ee744a8..e368a32 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -2023,19 +2023,28 @@ QString Courtroom::filter_ic_text(QString p_text, bool html, int target_pos, int if (p_text.trimmed().startsWith("~~")) { p_text.remove(p_text.indexOf("~~"), 2); - target_pos -= 2; + if (target_pos != -1) + { + target_pos = qMax(0, target_pos - 2); + } align = "center"; } else if (p_text.trimmed().startsWith("~>")) { p_text.remove(p_text.indexOf("~>"), 2); - target_pos -= 2; + if (target_pos != -1) + { + target_pos = qMax(0, target_pos - 2); + } align = "right"; } else if (p_text.trimmed().startsWith("<>")) { p_text.remove(p_text.indexOf("<>"), 2); - target_pos -= 2; + if (target_pos != -1) + { + target_pos = qMax(0, target_pos - 2); + } align = "justify"; } diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index 35e42b4..204de69 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -441,7 +441,7 @@ QString AOApplication::get_chat_markdown(QString p_identifier, QString p_chat) if (f_result == "") f_result = read_design_ini(p_identifier, default_path); - return f_result; + return f_result.toLatin1(); } QColor AOApplication::get_chat_color(QString p_identifier, QString p_chat) From 9f543f9ef7109340142134124e8bda6c9f750a18 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sat, 5 Oct 2019 20:32:19 +0300 Subject: [PATCH 111/268] I HAVE CONQUERED BASS HELL BEHOLD, LOOP_START AND LOOP_END MUSIC POINTS! It reads the songname.mp3.txt file, looking for loop_start, loop_length and loop_end in samples MUSIC EFFECTS SYSTEM THAT CAN ***COMMUNICATE WITH THE SERVER***, WOAHHHHHHHHH! RIGHT-CLICK CONTEXT MENUS TO ENABLE/DISABLE SPECIFIC MUSIC EFFECTS MUSIC EFFECTS ENUMS Fix an issue with music looping --- include/aomusicplayer.h | 2 +- include/courtroom.h | 6 +++ include/datatypes.h | 7 +++ src/aomusicplayer.cpp | 95 ++++++++++++++++++++++++----------------- src/courtroom.cpp | 78 +++++++++++++++++++++++++-------- 5 files changed, 131 insertions(+), 57 deletions(-) diff --git a/include/aomusicplayer.h b/include/aomusicplayer.h index 1a91d8f..52c97c3 100644 --- a/include/aomusicplayer.h +++ b/include/aomusicplayer.h @@ -29,7 +29,7 @@ public: QWORD loop_end = 0; public slots: - void play(QString p_song, int channel=0, bool crossfade=false); + void play(QString p_song, int channel=0, bool loop=false, int effect_flags=0); void stop(int channel=0); private: diff --git a/include/courtroom.h b/include/courtroom.h index e800415..4b6ccc3 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -396,6 +396,9 @@ private: QString effect = ""; + //Music effect flags we want to send to server when we play music + int music_flags = 0; + int defense_bar_state = 0; int prosecution_bar_state = 0; @@ -643,6 +646,9 @@ private slots: void on_music_search_edited(QString p_text); void on_music_list_double_clicked(QTreeWidgetItem *p_item, int column); void on_music_list_context_menu_requested(const QPoint &pos); + void music_fade_out(bool toggle); + void music_fade_in(bool toggle); + void music_synchronize(bool toggle); void music_list_expand_all(); void music_list_collapse_all(); void on_area_list_double_clicked(QModelIndex p_model); diff --git a/include/datatypes.h b/include/datatypes.h index 835cf8f..921f613 100644 --- a/include/datatypes.h +++ b/include/datatypes.h @@ -110,4 +110,11 @@ enum CHAT_MESSAGE EFFECTS }; +enum MUSIC_EFFECT +{ + FADE_IN = 1, + FADE_OUT = 2, + SYNC_POS = 4 +}; + #endif // DATATYPES_H diff --git a/src/aomusicplayer.cpp b/src/aomusicplayer.cpp index 8fe6d15..49cf089 100644 --- a/src/aomusicplayer.cpp +++ b/src/aomusicplayer.cpp @@ -15,7 +15,7 @@ AOMusicPlayer::~AOMusicPlayer() } } -void AOMusicPlayer::play(QString p_song, int channel, bool crossfade) +void AOMusicPlayer::play(QString p_song, int channel, bool loop, int effect_flags) { channel = channel % m_channelmax; if (channel < 0) //wtf? @@ -23,8 +23,9 @@ void AOMusicPlayer::play(QString p_song, int channel, bool crossfade) QString f_path = ao_app->get_music_path(p_song); unsigned int flags = BASS_STREAM_PRESCAN | BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE; - if (m_looping) + if (loop) flags |= BASS_SAMPLE_LOOP; + DWORD newstream = BASS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, flags); if (ao_app->get_audio_output_device() != "default") @@ -33,8 +34,8 @@ void AOMusicPlayer::play(QString p_song, int channel, bool crossfade) QString d_path = f_path + ".txt"; loop_start = 0; - loop_end = 0; - if (m_looping && file_exists(d_path)) //Contains loop/etc. information file + loop_end = BASS_ChannelGetLength(newstream, BASS_POS_BYTE); + if (loop && file_exists(d_path)) //Contains loop/etc. information file { QStringList lines = ao_app->read_file(d_path).split("\n"); foreach (QString line, lines) @@ -46,49 +47,60 @@ void AOMusicPlayer::play(QString p_song, int channel, bool crossfade) float sample_rate; BASS_ChannelGetAttribute(newstream, BASS_ATTRIB_FREQ, &sample_rate); - qDebug() << sample_rate << args[1].trimmed(); + //Grab number of bytes for sample size + int sample_size = 16/8; + + //number of channels (stereo/mono) + int num_channels = 2; + + //Calculate the bytes for loop_start/loop_end to use with the sync proc + QWORD bytes = static_cast(args[1].trimmed().toFloat() * sample_size * num_channels); if (arg == "loop_start") - loop_start = BASS_ChannelSeconds2Bytes(newstream, args[1].trimmed().toDouble() / static_cast(sample_rate)); + loop_start = bytes; else if (arg == "loop_length") - loop_end = loop_start + BASS_ChannelSeconds2Bytes(newstream, args[1].trimmed().toDouble() / static_cast(sample_rate)); + loop_end = loop_start + bytes; else if (arg == "loop_end") - loop_end = BASS_ChannelSeconds2Bytes(newstream, args[1].trimmed().toDouble() / static_cast(sample_rate)); + loop_end = bytes; } qDebug() << "Found data file for song" << p_song << "length" << BASS_ChannelGetLength(newstream, BASS_POS_BYTE) << "loop start" << loop_start << "loop end" << loop_end; } - if (crossfade) + if (BASS_ChannelIsActive(m_stream_list[channel]) == BASS_ACTIVE_PLAYING) { DWORD oldstream = m_stream_list[channel]; - //Mute the new sample - BASS_ChannelSetAttribute(newstream, BASS_ATTRIB_VOL, 0); - //Crossfade time - if (BASS_ChannelIsActive(oldstream) == BASS_ACTIVE_PLAYING) + + if (effect_flags & SYNC_POS) { - //Fade out the other sample and stop it - BASS_ChannelSlideAttribute(oldstream, BASS_ATTRIB_VOL|BASS_SLIDE_LOG, -1, 5000); BASS_ChannelLock(oldstream, true); //Sync it with the new sample BASS_ChannelSetPosition(newstream, BASS_ChannelGetPosition(oldstream, BASS_POS_BYTE), BASS_POS_BYTE); BASS_ChannelLock(oldstream, false); } - //Start it - BASS_ChannelPlay(newstream, false); - //Fade in our sample - BASS_ChannelSlideAttribute(newstream, BASS_ATTRIB_VOL, static_cast(m_volume[channel] / 100.0f), 1000); - m_stream_list[channel] = newstream; + if (effect_flags & FADE_OUT) + { + //Fade out the other sample and stop it (due to -1) + BASS_ChannelSlideAttribute(oldstream, BASS_ATTRIB_VOL|BASS_SLIDE_LOG, -1, 4000); + } + else + BASS_ChannelStop(oldstream); //Stop the sample since we don't need it anymore } else - { BASS_ChannelStop(m_stream_list[channel]); - m_stream_list[channel] = newstream; - BASS_ChannelPlay(m_stream_list[channel], false); - this->set_volume(m_volume[channel], channel); - } - this->set_looping(m_looping); //Have to do this here due to any crossfading-related changes, etc. + m_stream_list[channel] = newstream; + BASS_ChannelPlay(m_stream_list[channel], false); + if (effect_flags & FADE_IN) + { + //Fade in our sample + BASS_ChannelSetAttribute(newstream, BASS_ATTRIB_VOL, 0); + BASS_ChannelSlideAttribute(newstream, BASS_ATTRIB_VOL, static_cast(m_volume[channel] / 100.0f), 1000); + } + else + this->set_volume(m_volume[channel], channel); + + this->set_looping(loop); //Have to do this here due to any crossfading-related changes, etc. } void AOMusicPlayer::stop(int channel) @@ -115,29 +127,36 @@ void AOMusicPlayer::set_volume(int p_value, int channel) void CALLBACK loopProc(HSYNC handle, DWORD channel, DWORD data, void *user) { - AOMusicPlayer *self= static_cast(user); - qDebug() << BASS_ChannelGetPosition(channel, BASS_POS_BYTE); - BASS_ChannelSetPosition(channel, self->loop_start, BASS_POS_BYTE); + QWORD loop_start = *(static_cast(user)); + BASS_ChannelLock(channel, true); + BASS_ChannelSetPosition(channel, loop_start, BASS_POS_BYTE); + BASS_ChannelLock(channel, false); } void AOMusicPlayer::set_looping(bool toggle, int channel) { m_looping = toggle; - qDebug() << "looping" << m_looping; - if (m_looping == false && BASS_ChannelFlags(m_stream_list[channel], 0, 0) & BASS_SAMPLE_LOOP) + if (!m_looping) { - BASS_ChannelFlags(m_stream_list[channel], 0, BASS_SAMPLE_LOOP); // remove the LOOP flag + if (BASS_ChannelFlags(m_stream_list[channel], 0, 0) & BASS_SAMPLE_LOOP) + BASS_ChannelFlags(m_stream_list[channel], 0, BASS_SAMPLE_LOOP); // remove the LOOP flag BASS_ChannelRemoveSync(m_stream_list[channel], loop_sync[channel]); + loop_sync[channel] = 0; } - else if (m_looping == true) + else { BASS_ChannelFlags(m_stream_list[channel], BASS_SAMPLE_LOOP, BASS_SAMPLE_LOOP); // set the LOOP flag - BASS_ChannelRemoveSync(m_stream_list[channel], loop_sync[channel]); - qDebug() << loop_end; - if (loop_end > 0) + if (loop_sync[channel] != 0) { - loop_sync[channel] = BASS_ChannelSetSync(m_stream_list[channel], BASS_SYNC_POS | BASS_SYNC_MIXTIME, loop_end, loopProc, this); - qDebug() << "Started loop sync"; + BASS_ChannelRemoveSync(m_stream_list[channel], loop_sync[channel]); //remove the sync + loop_sync[channel] = 0; + } + if (loop_start > 0) + { + if (loop_end == 0) + loop_end = BASS_ChannelGetLength(m_stream_list[channel], BASS_POS_BYTE); + if (loop_end > 0) //Don't loop zero length songs even if we're asked to + loop_sync[channel] = BASS_ChannelSetSync(m_stream_list[channel], BASS_SYNC_POS | BASS_SYNC_MIXTIME, loop_end, loopProc, &loop_start); } } } diff --git a/src/courtroom.cpp b/src/courtroom.cpp index ee744a8..129c4bf 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -2813,7 +2813,7 @@ void Courtroom::handle_song(QStringList *p_contents) bool looping = true; int channel = 0; - bool crossfade = false; + int effect_flags = 0; if (n_char < 0 || n_char >= char_list.size()) { int channel = 0; @@ -2823,13 +2823,12 @@ void Courtroom::handle_song(QStringList *p_contents) if (p_contents->length() > 4) //eyyy we want to change this song's CHANNEL huh channel = p_contents->at(4).toInt(); //let the music player handle it if it's bigger than the channel list - if (p_contents->length() > 5) //CROSSFADE!? Are you MAD? + if (p_contents->length() > 5) //Flags provided to us by server such as Fade In, Fade Out, Sync Pos etc. { - crossfade = p_contents->at(5) == "1"; //let the music player handle it if it's bigger than the channel list + effect_flags = p_contents->at(5).toInt(); } - music_player->set_looping(looping, channel); - music_player->play(f_song, channel, crossfade); + music_player->play(f_song, channel, looping, effect_flags); if (channel == 0) ui_music_name->setText(f_song); } @@ -2854,8 +2853,10 @@ void Courtroom::handle_song(QStringList *p_contents) if (p_contents->length() > 4) //eyyy we want to change this song's CHANNEL huh channel = p_contents->at(4).toInt(); //let the music player handle it if it's bigger than the channel list - if (p_contents->length() > 5) //CROSSFADE!? Are you MAD? - crossfade = p_contents->at(5) == "1"; //let the music player handle it if it's bigger than the channel list + if (p_contents->length() > 5) //Flags provided to us by server such as Fade In, Fade Out, Sync Pos etc. + { + effect_flags = p_contents->at(5).toInt(); + } if (!mute_map.value(n_char)) { @@ -2869,8 +2870,8 @@ void Courtroom::handle_song(QStringList *p_contents) } append_ic_text(f_song_clear, str_show, true); - music_player->set_looping(looping, channel); - music_player->play(f_song, channel, crossfade); + + music_player->play(f_song, channel, looping, effect_flags); if (channel == 0) ui_music_name->setText(f_song); } @@ -3763,14 +3764,14 @@ void Courtroom::on_music_list_double_clicked(QTreeWidgetItem *p_item, int column QString p_song = p_item->text(column); - if (!ui_ic_chat_name->text().isEmpty() && ao_app->cccc_ic_support_enabled) - { - ao_app->send_server_packet(new AOPacket("MC#" + p_song + "#" + QString::number(m_cid) + "#" + ui_ic_chat_name->text() + "#%"), false); - } - else - { - ao_app->send_server_packet(new AOPacket("MC#" + p_song + "#" + QString::number(m_cid) + "#%"), false); - } + 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_support_enabled) || ao_app->effects_enabled) + packet_contents.append(ui_ic_chat_name->text()); + if (ao_app->effects_enabled) + 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) @@ -3779,9 +3780,50 @@ void Courtroom::on_music_list_context_menu_requested(const QPoint &pos) menu->addAction(QString("Expand All Categories"), this, SLOT(music_list_expand_all())); menu->addAction(QString("Collapse All Categories"), this, SLOT(music_list_collapse_all())); - // menu->addSeparator(); + menu->addSeparator(); + + menu->addAction(new QAction("Fade Out Previous", this)); + menu->actions().back()->setCheckable(true); + menu->actions().back()->setChecked(music_flags & FADE_OUT); + connect(menu->actions().back(), SIGNAL(toggled(bool)), this, SLOT(music_fade_out(bool))); + + menu->addAction(new QAction("Fade In", this)); + menu->actions().back()->setCheckable(true); + menu->actions().back()->setChecked(music_flags & FADE_IN); + connect(menu->actions().back(), SIGNAL(toggled(bool)), this, SLOT(music_fade_in(bool))); + + menu->addAction(new QAction("Synchronize", this)); + menu->actions().back()->setCheckable(true); + menu->actions().back()->setChecked(music_flags & SYNC_POS); + connect(menu->actions().back(), SIGNAL(toggled(bool)), this, SLOT(music_synchronize(bool))); + menu->popup(ui_music_list->mapToGlobal(pos)); } + +void Courtroom::music_fade_out(bool toggle) +{ + if (toggle) + music_flags |= FADE_OUT; + else + music_flags &= ~FADE_OUT; +} + +void Courtroom::music_fade_in(bool toggle) +{ + if (toggle) + music_flags |= FADE_IN; + else + music_flags &= ~FADE_IN; +} + +void Courtroom::music_synchronize(bool toggle) +{ + if (toggle) + music_flags |= SYNC_POS; + else + music_flags &= ~SYNC_POS; +} + void Courtroom::music_list_expand_all() { ui_music_list->expandAll(); From 8ab5a3a6b27376fb7e417ce760cbd7bf827a1138 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sat, 5 Oct 2019 22:50:39 +0300 Subject: [PATCH 112/268] version 3 --- Attorney_Online.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Attorney_Online.pro b/Attorney_Online.pro index 5d3eda0..e114550 100644 --- a/Attorney_Online.pro +++ b/Attorney_Online.pro @@ -3,7 +3,7 @@ QT += core gui widgets network TARGET = Attorney_Online TEMPLATE = app -VERSION = 2.8.0.2 +VERSION = 2.8.0.3 INCLUDEPATH += $$PWD/include DESTDIR = $$PWD/bin From 85f33e13c70a523df6554f0983e84777266563e4 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sun, 6 Oct 2019 13:27:11 +0300 Subject: [PATCH 113/268] Fix some edge cases where the AOChar qlabel is moved around in weird ways (reload theme still puts qlabel at 0,0 without centering) Fix a full message of speed 0 not properly displaying itself --- src/aocharmovie.cpp | 3 +-- src/courtroom.cpp | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/aocharmovie.cpp b/src/aocharmovie.cpp index f8dc8d2..b05d7f6 100644 --- a/src/aocharmovie.cpp +++ b/src/aocharmovie.cpp @@ -240,7 +240,6 @@ QPixmap AOCharMovie::get_pixmap(QImage image) f_pixmap = f_pixmap.scaledToHeight(f_h, transform_mode); this->resize(f_pixmap.size()); - QLabel::move(x + (f_w - f_pixmap.width())/2, y + (f_h - f_pixmap.height())); //Always center horizontally, always put at the bottom vertically return f_pixmap; } @@ -248,7 +247,7 @@ QPixmap AOCharMovie::get_pixmap(QImage image) void AOCharMovie::set_frame(QPixmap f_pixmap) { this->setPixmap(f_pixmap); - QLabel::move(x + (this->width() - this->pixmap()->width())/2, y); + QLabel::move(x + (f_w - f_pixmap.width())/2, y + (f_h - f_pixmap.height())); //Always center horizontally, always put at the bottom vertically } void AOCharMovie::combo_resize(int w, int h) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 0cf5a32..1145b34 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -2605,7 +2605,7 @@ void Courtroom::chat_tick() next_character_is_not_special = false; } - if (formatting_char || (message_display_speed[current_display_speed] <= 0 && tick_pos < f_message.size())) + if ((message_display_speed[current_display_speed] <= 0 && tick_pos < f_message.size()-1) || formatting_char) { chat_tick_timer->start(0); //Don't bother rendering anything out as we're doing the SPEED. (there's latency otherwise) if (!formatting_char || f_character == "n") From 91eeffb959fb59545d89116e67312e83468e0af1 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sun, 6 Oct 2019 13:47:36 +0300 Subject: [PATCH 114/268] Courtroom Fonts can now have the "sharpness" setting (pixelated/no anti alias) --- include/courtroom.h | 2 +- src/courtroom.cpp | 22 +++++++++++++--------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/include/courtroom.h b/include/courtroom.h index 4b6ccc3..590fa0f 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -128,7 +128,7 @@ public: void set_font(QWidget *widget, QString class_name, QString p_identifier); //Get the properly constructed font - QFont get_qfont(QString font_name, int f_pointsize); + QFont get_qfont(QString font_name, int f_pointsize, bool antialias=true); //actual operation of setting the font on a widget void set_qfont(QWidget *widget, QString class_name, QFont font, QColor f_color = Qt::black, bool bold = false); diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 1145b34..34233f9 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -854,20 +854,23 @@ void Courtroom::set_font(QWidget *widget, QString class_name, QString p_identifi QString font_name = ao_app->get_font_name(p_identifier + "_font", design_file); QColor f_color = ao_app->get_color(p_identifier + "_color", design_file); bool bold = ao_app->get_font_size(p_identifier + "_bold", design_file) == 1; // is the font bold or not? + bool antialias = ao_app->get_font_size(p_identifier + "_sharp", design_file) != 1; // is the font anti-aliased or not? - this->set_qfont(widget, class_name, get_qfont(font_name, f_pointsize), f_color, bold); + this->set_qfont(widget, class_name, get_qfont(font_name, f_pointsize, antialias), f_color, bold); } -QFont Courtroom::get_qfont(QString font_name, int f_pointsize) +QFont Courtroom::get_qfont(QString font_name, int f_pointsize, bool antialias) { QFont font; if (font_name.isEmpty()) - { - font = QFont("Arial", f_pointsize); - font.setStyleHint(QFont::SansSerif, QFont::NoAntialias); - } - else - font = QFont(font_name, f_pointsize); + font_name = "Arial"; + + QFont::StyleStrategy style_strategy = QFont::PreferDefault; + if (!antialias) + style_strategy = QFont::NoAntialias; + + font = QFont(font_name, f_pointsize); + font.setStyleHint(QFont::SansSerif, style_strategy); return font; } @@ -1756,6 +1759,7 @@ void Courtroom::handle_chatmessage_2() QString font_name = ao_app->get_font_name("message_font", design_file); QColor f_color = ao_app->get_color("message_color", design_file); bool bold = ao_app->get_font_size("message_bold", design_file) == 1; // is the font bold or not? + bool antialias = ao_app->get_font_size("message_sharp", design_file) != 1; // is the font anti-aliased or not? QString chatfont = ao_app->get_chat_font(m_chatmessage[CHAR_NAME]); if (chatfont != "") @@ -1764,7 +1768,7 @@ void Courtroom::handle_chatmessage_2() int chatsize = ao_app->get_chat_size(m_chatmessage[CHAR_NAME]); if (chatsize != -1) f_pointsize = chatsize; - this->set_qfont(ui_vp_message, "", get_qfont(font_name, f_pointsize), f_color, bold); + this->set_qfont(ui_vp_message, "", get_qfont(font_name, f_pointsize, antialias), f_color, bold); set_scene(m_chatmessage[DESK_MOD], m_chatmessage[SIDE]); From ec02078b4d0596ebf69b11f2599b06d68d748b7f Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sun, 6 Oct 2019 23:23:52 +0300 Subject: [PATCH 115/268] Fix music display not displaying a stripped down version of the song name --- src/courtroom.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 34233f9..ed7e3e5 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -2820,8 +2820,7 @@ void Courtroom::handle_song(QStringList *p_contents) return; QString f_song = f_contents.at(0); - QString f_song_clear = f_song; - f_song_clear = f_song_clear.left(f_song_clear.lastIndexOf(".")); + QString f_song_clear = f_song.left(f_song.lastIndexOf(".")).right(f_song.lastIndexOf("/")); int n_char = f_contents.at(1).toInt(); bool looping = true; @@ -2843,7 +2842,7 @@ void Courtroom::handle_song(QStringList *p_contents) music_player->play(f_song, channel, looping, effect_flags); if (channel == 0) - ui_music_name->setText(f_song); + ui_music_name->setText(f_song_clear); } else { @@ -2886,7 +2885,7 @@ void Courtroom::handle_song(QStringList *p_contents) music_player->play(f_song, channel, looping, effect_flags); if (channel == 0) - ui_music_name->setText(f_song); + ui_music_name->setText(f_song_clear); } } } From 990f653e4a063a684b5d5584c7454c36a1036a85 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Tue, 8 Oct 2019 01:35:10 +0300 Subject: [PATCH 116/268] Allow -1 charid messages to be sent (system/server messages) UNTESTED --- src/courtroom.cpp | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index ed7e3e5..7d2f183 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1561,20 +1561,20 @@ void Courtroom::handle_chatmessage(QStringList *p_contents) int f_char_id = m_chatmessage[CHAR_ID].toInt(); - if (f_char_id < 0 || f_char_id >= char_list.size()) + if (f_char_id >= 0 && f_char_id >= char_list.size()) return; if (mute_map.value(m_chatmessage[CHAR_ID].toInt())) return; QString f_showname; - if (m_chatmessage[SHOWNAME].isEmpty() || !ui_showname_enable->isChecked()) + if (f_char_id > 0 && (m_chatmessage[SHOWNAME].isEmpty() || !ui_showname_enable->isChecked())) { - f_showname = ao_app->get_showname(char_list.at(f_char_id).name); + f_showname = ao_app->get_showname(char_list.at(f_char_id).name); } else { - f_showname = m_chatmessage[SHOWNAME]; + f_showname = m_chatmessage[SHOWNAME]; } if(f_showname.trimmed().isEmpty()) //Pure whitespace showname, get outta here. @@ -1583,9 +1583,14 @@ void Courtroom::handle_chatmessage(QStringList *p_contents) QString f_message = f_showname + ": " + m_chatmessage[MESSAGE] + '\n'; - if (f_message == previous_ic_message) + if (f_char_id >= 0 && f_message == previous_ic_message) //Not a system message return; + if (f_char_id <= -1) + previous_ic_message = ""; //System messages don't care about repeating themselves + else + previous_ic_message = f_message; + //Stop the chat arrow from animating ui_vp_chat_arrow->stop(); @@ -1597,8 +1602,6 @@ void Courtroom::handle_chatmessage(QStringList *p_contents) //Remove undesired newline chars m_chatmessage[MESSAGE].remove("\n"); - //Replace all trailing whitespace with a single space and remove all whitespace at the end of the string. - //m_chatmessage[MESSAGE] = m_chatmessage[MESSAGE].replace(QRegularExpression("^\\s+(?=\\s)|\\s+$|\\s+(?=\\s)"), ""); chatmessage_is_empty = m_chatmessage[MESSAGE] == " " || m_chatmessage[MESSAGE] == ""; @@ -1625,7 +1628,11 @@ void Courtroom::handle_chatmessage(QStringList *p_contents) //Let the server handle actually checking if they're allowed to do this. is_additive = m_chatmessage[ADDITIVE].toInt() == 1; - chatlogpiece* temp = new chatlogpiece(ao_app->get_showname(char_list.at(f_char_id).name), f_showname, m_chatmessage[MESSAGE], false); + QString f_charname = ""; + if (f_char_id >= 0) + f_charname = ao_app->get_showname(char_list.at(f_char_id).name); + + chatlogpiece* temp = new chatlogpiece(f_charname, f_showname, m_chatmessage[MESSAGE], false); ic_chatlog_history.append(*temp); ao_app->append_to_file(temp->get_full(), ao_app->log_filename, true); @@ -1636,8 +1643,6 @@ void Courtroom::handle_chatmessage(QStringList *p_contents) append_ic_text(m_chatmessage[MESSAGE], f_showname); - previous_ic_message = f_message; - int objection_mod = m_chatmessage[OBJECTION_MOD].toInt(); QString f_char = m_chatmessage[CHAR_NAME]; QString f_custom_theme = ao_app->get_char_shouts(f_char); @@ -1701,9 +1706,10 @@ void Courtroom::handle_chatmessage_2() else ui_vp_player_char->network_strings.clear(); - if (m_chatmessage[SHOWNAME].isEmpty() || !ui_showname_enable->isChecked()) + int f_charid = m_chatmessage[CHAR_ID].toInt(); + if (f_charid >= 0 && (m_chatmessage[SHOWNAME].isEmpty() || !ui_showname_enable->isChecked())) { - QString real_name = char_list.at(m_chatmessage[CHAR_ID].toInt()).name; + QString real_name = char_list.at(f_charid).name; QString f_showname = ao_app->get_showname(real_name); @@ -1845,7 +1851,6 @@ void Courtroom::handle_chatmessage_2() else ui_vp_player_char->move(0, 0); - qDebug() << "offset OK" << ok << "offset value" << self_offset; switch (emote_mod) { case 1: case 2: case 6: From 330aa9755095cd4f12f028452d268c50311d3710 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sat, 12 Oct 2019 01:43:48 +0300 Subject: [PATCH 117/268] Properly handle "true song name" even with folders/categories and file formats (paving way for folder-categorized music lists set up by servers) Prevent BG's from falling back on default BG path (this isn't really user-convenient and causes more trouble than its worth, e.g. stands appearing on BG's that dont' want stands to appear) Implement Case Cafe's method of categorization for (a) and (b) emotes --- src/aocharmovie.cpp | 1 + src/aoscene.cpp | 22 ++++++++++++++++++---- src/courtroom.cpp | 11 ++++++++--- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/aocharmovie.cpp b/src/aocharmovie.cpp index b05d7f6..9bbb876 100644 --- a/src/aocharmovie.cpp +++ b/src/aocharmovie.cpp @@ -28,6 +28,7 @@ void AOCharMovie::load_image(QString p_char, QString p_emote, QString emote_pref QList pathlist; pathlist = { ao_app->get_image_suffix(ao_app->get_character_path(p_char, emote_prefix + p_emote)), //Default path + ao_app->get_image_suffix(ao_app->get_character_path(p_char, emote_prefix + "/" + p_emote)),//Path check if it's categorized into a folder ao_app->get_character_path(p_char, p_emote + ".png"), //Non-animated path if emote_prefix fails 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 diff --git a/src/aoscene.cpp b/src/aoscene.cpp index c931425..527d25d 100644 --- a/src/aoscene.cpp +++ b/src/aoscene.cpp @@ -13,8 +13,15 @@ AOScene::AOScene(QWidget *parent, AOApplication *p_ao_app) : QLabel(parent) void AOScene::set_image(QString p_image) { QString background_path = ao_app->get_image_suffix(ao_app->get_background_path(p_image)); - if (!file_exists(background_path)) - background_path = ao_app->get_image_suffix(ao_app->get_default_background_path(p_image)); //Default path + if (!file_exists(background_path)) //If image is missing, clear current image + { + //background_path = ao_app->get_image_suffix(ao_app->get_default_background_path(p_image)); //Default path + this->clear(); + this->setMovie(nullptr); + + m_movie->stop(); + return; + } if (file_exists(background_path) && background_path == last_image) return; @@ -46,8 +53,15 @@ void AOScene::set_legacy_desk(QString p_image) { QString desk_path = ao_app->get_image_suffix(ao_app->get_background_path(p_image)); - if (!file_exists(desk_path)) - desk_path = ao_app->get_image_suffix(ao_app->get_default_background_path(p_image)); //Default path + if (!file_exists(desk_path)) //If image is missing, clear current image + { + //desk_path = ao_app->get_image_suffix(ao_app->get_default_background_path(p_image)); //Default path + this->clear(); + this->setMovie(nullptr); + + m_movie->stop(); + return; + } if (file_exists(desk_path) && desk_path == last_image) return; diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 7d2f183..4292791 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -127,7 +127,8 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_area_list = new QListWidget(this); ui_area_list->hide(); ui_music_list = new QTreeWidget(this); - ui_music_list->setColumnCount(1); + ui_music_list->setColumnCount(2); + ui_music_list->hideColumn(1); ui_music_list->setHeaderHidden(true); ui_music_list->header()->setStretchLastSection(false); ui_music_list->header()->setSectionResizeMode(QHeaderView::ResizeToContents); @@ -1184,13 +1185,15 @@ void Courtroom::list_music() { QString i_song = music_list.at(n_song); QString i_song_listname = i_song.left(i_song.lastIndexOf(".")); + i_song_listname = i_song_listname.right(i_song_listname.length() - (i_song_listname.lastIndexOf("/") + 1)); QTreeWidgetItem *treeItem; if (i_song_listname != i_song && parent != nullptr) //not a category, parent exists treeItem = new QTreeWidgetItem(parent); else treeItem = new QTreeWidgetItem(ui_music_list); - treeItem->setText(0, i_song); + treeItem->setText(0, i_song_listname); + treeItem->setText(1, i_song); music_row_to_number.append(n_song); QString song_path = ao_app->get_music_path(i_song); @@ -2825,7 +2828,8 @@ void Courtroom::handle_song(QStringList *p_contents) return; QString f_song = f_contents.at(0); - QString f_song_clear = f_song.left(f_song.lastIndexOf(".")).right(f_song.lastIndexOf("/")); + QString f_song_clear = f_song.left(f_song.lastIndexOf(".")); + f_song_clear = f_song_clear.right(f_song_clear.length() - (f_song_clear.lastIndexOf("/") + 1)); int n_char = f_contents.at(1).toInt(); bool looping = true; @@ -3779,6 +3783,7 @@ void Courtroom::on_music_list_double_clicked(QTreeWidgetItem *p_item, int column if (is_muted) return; + column = 1; //Column 1 is always the metadata (which we want) QString p_song = p_item->text(column); QStringList packet_contents; From a9a0f65ddb351797d8805b28fe18b1e5114dd708 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sat, 12 Oct 2019 17:57:18 +0300 Subject: [PATCH 118/268] Allow area list to contain metadata (as well as categories for future expansion) Fix backwards compatibility breaking when you join a server that doesn't support effects after previously joining a server that does --- include/courtroom.h | 8 ++---- src/courtroom.cpp | 49 +++++++++++++++++++++++-------------- src/packet_distribution.cpp | 1 + 3 files changed, 34 insertions(+), 24 deletions(-) diff --git a/include/courtroom.h b/include/courtroom.h index 590fa0f..ea84122 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -288,10 +288,6 @@ private: QVector ic_chatlog_history; - // These map music row items and area row items to their actual IDs. - QVector music_row_to_number; - QVector area_row_to_number; - //triggers ping_server() every 60 seconds QTimer *keepalive_timer; @@ -470,7 +466,7 @@ private: AOTextArea *ui_server_chatlog; QListWidget *ui_mute_list; - QListWidget *ui_area_list; + QTreeWidget *ui_area_list; QTreeWidget *ui_music_list; ScrollText *ui_music_name; @@ -651,7 +647,7 @@ private slots: void music_synchronize(bool toggle); void music_list_expand_all(); void music_list_collapse_all(); - void on_area_list_double_clicked(QModelIndex p_model); + void on_area_list_double_clicked(QTreeWidgetItem *p_item, int column); void select_emote(int p_id); diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 4292791..5a7f0d2 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -124,8 +124,14 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_server_chatlog->setReadOnly(true); ui_server_chatlog->setOpenExternalLinks(true); - ui_area_list = new QListWidget(this); + ui_area_list = new QTreeWidget(this); + ui_area_list->setColumnCount(2); + ui_area_list->hideColumn(1); + ui_area_list->setHeaderHidden(true); + ui_area_list->header()->setStretchLastSection(false); + ui_area_list->header()->setSectionResizeMode(QHeaderView::ResizeToContents); ui_area_list->hide(); + ui_music_list = new QTreeWidget(this); ui_music_list->setColumnCount(2); ui_music_list->hideColumn(1); @@ -324,7 +330,8 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() connect(ui_music_list, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this, SLOT(on_music_list_double_clicked(QTreeWidgetItem*, int))); connect(ui_music_list, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(on_music_list_context_menu_requested(QPoint))); - connect(ui_area_list, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(on_area_list_double_clicked(QModelIndex))); + + connect(ui_area_list, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this, SLOT(on_area_list_double_clicked(QTreeWidgetItem*, int))); connect(ui_hold_it, SIGNAL(clicked()), this, SLOT(on_hold_it_clicked())); connect(ui_objection, SIGNAL(clicked()), this, SLOT(on_objection_clicked())); @@ -565,7 +572,10 @@ void Courtroom::set_widgets() 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()); + set_size_and_pos(ui_music_list, "music_list"); + ui_music_list->header()->setMinimumSectionSize(ui_music_list->width()); set_size_and_pos(ui_music_name, "music_name"); @@ -1171,7 +1181,6 @@ void Courtroom::enter_courtroom() void Courtroom::list_music() { ui_music_list->clear(); - music_row_to_number.clear(); QString f_file = "courtroom_design.ini"; @@ -1194,7 +1203,6 @@ void Courtroom::list_music() treeItem = new QTreeWidgetItem(ui_music_list); treeItem->setText(0, i_song_listname); treeItem->setText(1, i_song); - music_row_to_number.append(n_song); QString song_path = ao_app->get_music_path(i_song); @@ -1215,7 +1223,6 @@ void Courtroom::list_music() void Courtroom::list_areas() { ui_area_list->clear(); - area_row_to_number.clear(); QString f_file = "courtroom_design.ini"; @@ -1254,34 +1261,35 @@ void Courtroom::list_areas() if (i_area.toLower().contains(ui_music_search->text().toLower())) { - ui_area_list->addItem(i_area); - area_row_to_number.append(n_area); + QTreeWidgetItem *treeItem = new QTreeWidgetItem(ui_area_list); + treeItem->setText(0, i_area); + treeItem->setText(1, QString::number(n_area)); if (ao_app->arup_enabled) { // Coloring logic here. - ui_area_list->item(n_listed_areas)->setBackground(free_brush); + treeItem->setBackground(0, free_brush); if (arup_locks.at(n_area) == "LOCKED") { - ui_area_list->item(n_listed_areas)->setBackground(locked_brush); + treeItem->setBackground(0, locked_brush); } else { if (arup_statuses.at(n_area) == "LOOKING-FOR-PLAYERS") - ui_area_list->item(n_listed_areas)->setBackground(lfp_brush); + treeItem->setBackground(0, lfp_brush); else if (arup_statuses.at(n_area) == "CASING") - ui_area_list->item(n_listed_areas)->setBackground(casing_brush); + treeItem->setBackground(0, casing_brush); else if (arup_statuses.at(n_area) == "RECESS") - ui_area_list->item(n_listed_areas)->setBackground(recess_brush); + treeItem->setBackground(0, recess_brush); else if (arup_statuses.at(n_area) == "RP") - ui_area_list->item(n_listed_areas)->setBackground(rp_brush); + treeItem->setBackground(0, rp_brush); else if (arup_statuses.at(n_area) == "GAMING") - ui_area_list->item(n_listed_areas)->setBackground(gaming_brush); + treeItem->setBackground(0, gaming_brush); } } else { - ui_area_list->item(n_listed_areas)->setBackground(free_brush); + treeItem->setBackground(0, free_brush); } ++n_listed_areas; @@ -3855,10 +3863,15 @@ void Courtroom::music_list_collapse_all() ui_music_list->collapseAll(); } -void Courtroom::on_area_list_double_clicked(QModelIndex p_model) +void Courtroom::on_area_list_double_clicked(QTreeWidgetItem *p_item, int column) { - QString p_area = area_list.at(area_row_to_number.at(p_model.row())); - ao_app->send_server_packet(new AOPacket("MC#" + p_area + "#" + QString::number(m_cid) + "#%"), false); + column = 0; //Column 0 is the area name, column 1 is the metadata + QString p_area = p_item->text(column); + + QStringList packet_contents; + packet_contents.append(p_area); + packet_contents.append(QString::number(m_cid)); + ao_app->send_server_packet(new AOPacket("MC", packet_contents), false); } void Courtroom::on_hold_it_clicked() diff --git a/src/packet_distribution.cpp b/src/packet_distribution.cpp index 097d251..20a07a6 100644 --- a/src/packet_distribution.cpp +++ b/src/packet_distribution.cpp @@ -151,6 +151,7 @@ void AOApplication::server_packet_received(AOPacket *p_packet) modcall_reason_enabled = false; looping_sfx_support_enabled = false; additive_enabled = false; + effects_enabled = false; //workaround for tsuserver4 if (f_contents.at(0) == "NOENCRYPT") From 1cc5b5b4412f225181567b0849ea7ba111fe6f90 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sat, 12 Oct 2019 17:58:17 +0300 Subject: [PATCH 119/268] Version 4 --- Attorney_Online.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Attorney_Online.pro b/Attorney_Online.pro index e114550..4890d80 100644 --- a/Attorney_Online.pro +++ b/Attorney_Online.pro @@ -3,7 +3,7 @@ QT += core gui widgets network TARGET = Attorney_Online TEMPLATE = app -VERSION = 2.8.0.3 +VERSION = 2.8.0.4 INCLUDEPATH += $$PWD/include DESTDIR = $$PWD/bin From 6d7a6d7398dcb74550e7722c4b1436f42d00123c Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sun, 13 Oct 2019 02:51:07 +0300 Subject: [PATCH 120/268] Fix an issue with "missing desk" not properly replacing last_image (making everyone's desk break from pos hld to def/wit/pro) --- src/aoscene.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/aoscene.cpp b/src/aoscene.cpp index 527d25d..6ada5ee 100644 --- a/src/aoscene.cpp +++ b/src/aoscene.cpp @@ -15,11 +15,11 @@ void AOScene::set_image(QString p_image) QString background_path = ao_app->get_image_suffix(ao_app->get_background_path(p_image)); if (!file_exists(background_path)) //If image is missing, clear current image { - //background_path = ao_app->get_image_suffix(ao_app->get_default_background_path(p_image)); //Default path this->clear(); this->setMovie(nullptr); m_movie->stop(); + last_image = ""; return; } @@ -55,11 +55,11 @@ void AOScene::set_legacy_desk(QString p_image) QString desk_path = ao_app->get_image_suffix(ao_app->get_background_path(p_image)); if (!file_exists(desk_path)) //If image is missing, clear current image { - //desk_path = ao_app->get_image_suffix(ao_app->get_default_background_path(p_image)); //Default path this->clear(); this->setMovie(nullptr); m_movie->stop(); + last_image = ""; return; } From 3605f223d2f8bf0548f9a9802b470fdbc4d71ba3 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sun, 20 Oct 2019 01:44:54 +0300 Subject: [PATCH 121/268] Fix input bg's not being transparent FIx chat_tick_timer not stopping when you receive a bg --- src/courtroom.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 5a7f0d2..7cb5cf3 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -628,13 +628,14 @@ void Courtroom::set_widgets() ui_muted->setToolTip(tr("Oops, you're muted!")); set_size_and_pos(ui_ooc_chat_message, "ooc_chat_message"); - ui_ooc_chat_message->setToolTip(tr("Type your message to display in the server chat here.")); + ui_ooc_chat_message->setStyleSheet("background-color: rgba(0, 0, 0, 0);"); set_size_and_pos(ui_ooc_chat_name, "ooc_chat_name"); - ui_ooc_chat_name->setToolTip(tr("Set your name to display in the server chat.")); + ui_ooc_chat_name->setStyleSheet("background-color: rgba(0, 0, 0, 0);"); //set_size_and_pos(ui_area_password, "area_password"); set_size_and_pos(ui_music_search, "music_search"); + ui_music_search->setStyleSheet("background-color: rgba(0, 0, 0, 0);"); set_size_and_pos(ui_emote_dropdown, "emote_dropdown"); ui_emote_dropdown->setToolTip(tr("Set your character's emote to play on your next message.")); @@ -1020,10 +1021,13 @@ void Courtroom::set_background(QString p_background, bool display) { ui_vp_speedlines->stop(); ui_vp_player_char->stop(); + ui_vp_sideplayer_char->stop(); ui_vp_effect->stop(); ui_vp_message->hide(); ui_vp_chatbox->hide(); + + chat_tick_timer->stop(); set_scene(QString::number(ao_app->get_desk_mod(current_char, current_emote)), current_side); } } From 7d73347618719dc7b8bf0312ba5c782995c95e9f Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sun, 20 Oct 2019 17:59:38 +0300 Subject: [PATCH 122/268] Version 2.8.0.5 Add Killing Fever Online icon (mac icon not updated yet) --- Attorney_Online.pro | 2 +- include/lobby.h | 2 +- resource/logo.ico | Bin 99678 -> 99678 bytes resource/logo.png | Bin 29302 -> 22609 bytes resource/logo_ao2.ico | Bin 0 -> 99678 bytes resource/logo_ao2.png | Bin 0 -> 29302 bytes src/lobby.cpp | 1 - 7 files changed, 2 insertions(+), 3 deletions(-) create mode 100644 resource/logo_ao2.ico create mode 100644 resource/logo_ao2.png diff --git a/Attorney_Online.pro b/Attorney_Online.pro index 4890d80..6061cd9 100644 --- a/Attorney_Online.pro +++ b/Attorney_Online.pro @@ -3,7 +3,7 @@ QT += core gui widgets network TARGET = Attorney_Online TEMPLATE = app -VERSION = 2.8.0.4 +VERSION = 2.8.0.5 INCLUDEPATH += $$PWD/include DESTDIR = $$PWD/bin diff --git a/include/lobby.h b/include/lobby.h index e0cd03d..f0c4227 100644 --- a/include/lobby.h +++ b/include/lobby.h @@ -32,7 +32,7 @@ public: void append_chatmessage(QString f_name, QString f_message); void append_error(QString f_message); void set_player_count(int players_online, int max_players); - void set_stylesheet(QWidget *widget, QString target_tag); + void set_stylesheet(QWidget *widget); void set_stylesheets(); void set_fonts(); void set_font(QWidget *widget, QString p_identifier); diff --git a/resource/logo.ico b/resource/logo.ico index b40e7866a3cb000c21a42c7581a72f9cf3affb4f..3c68adff56ff9c52b316967955e6145dc34b2f9c 100644 GIT binary patch literal 99678 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 literal 99678 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

=Rc}`xqV+ckAC_4AAHlf!OQo* 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 Ef+2ZndH?_b literal 29302 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 diff --git a/resource/logo_ao2.ico b/resource/logo_ao2.ico new file mode 100644 index 0000000000000000000000000000000000000000..b40e7866a3cb000c21a42c7581a72f9cf3affb4f GIT binary patch literal 99678 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

=Rc}`xqV+ckAC_4AAHlf!OQo* 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 literal 0 HcmV?d00001 diff --git a/src/lobby.cpp b/src/lobby.cpp index 4ca4f49..7c61aa7 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -140,7 +140,6 @@ void Lobby::set_widgets() set_size_and_pos(ui_loading_text, "loading_label"); - //WHY IS THIS FONT HARDCODED, WHAT IS WRONG WITH YOU ui_loading_text->setFont(QFont("Arial", 20, QFont::Bold)); ui_loading_text->setReadOnly(true); ui_loading_text->setAlignment(Qt::AlignCenter); From 3595fd11e60fd07a2a6802150f4dff60cf6669fc Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sun, 20 Oct 2019 18:35:28 +0300 Subject: [PATCH 123/268] oops --- include/lobby.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/lobby.h b/include/lobby.h index f0c4227..e0cd03d 100644 --- a/include/lobby.h +++ b/include/lobby.h @@ -32,7 +32,7 @@ public: void append_chatmessage(QString f_name, QString f_message); void append_error(QString f_message); void set_player_count(int players_online, int max_players); - void set_stylesheet(QWidget *widget); + void set_stylesheet(QWidget *widget, QString target_tag); void set_stylesheets(); void set_fonts(); void set_font(QWidget *widget, QString p_identifier); From 52921b51a41e44da3a5b17156845793251f0763e Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Tue, 22 Oct 2019 18:05:39 +0300 Subject: [PATCH 124/268] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 0416e4a..0cc2450 100644 --- a/README.md +++ b/README.md @@ -236,6 +236,8 @@ 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. From 39777f6d137539b0e4300f06af18da2b4348fd89 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Tue, 22 Oct 2019 18:06:43 +0300 Subject: [PATCH 125/268] Update README.md --- README.md | 171 +----------------------------------------------------- 1 file changed, 1 insertion(+), 170 deletions(-) diff --git a/README.md b/README.md index 0cc2450..cea1bfb 100644 --- a/README.md +++ b/README.md @@ -4,176 +4,7 @@ ## Introduction for beginners -You may already be familiar with roleplaying in forums, Roll20, and/or [AAO](http://aaonline.fr/) (the online casemaker). In this sense, Attorney Online is nothing more than a medium - an animated chatroom client - that allows cases to be played out as if it were an Ace Attorney game. - -Not unlike other roleplaying games, cases can last an absurd amount of time (between 4 to 6 hours) and generally follow a roleplaying format directed by a case sheet. - -An implied expectation for fast typing and real-time communication may seem daunting at first, but due to the number of people in the courtroom, things get hectic very quickly even with only a few people talking. Therefore, you should not feel pressured to talk constantly: only when you have the attention of the court (or when you have an objection to make) should you feel the need to speak. - -It is recommended, but not strictly necessary, to have played an Ace Attorney game before creating your own case. You should also try to spectate or take part in a community case in order to get a grasp of how cases are done in practice. - ---- - -## Basic features - -### In-character chat - -Type in a message in the gray box under the viewport, select an emote, and press Enter. - -### Emotes - -An emote represents a set of animations played while the character is speaking and idle. Some emotes also contain a preanimation, which is played before the text is said by the character. - -### Interjections (shouts) - -Select an interjection to toggle it. When you send a message, it will interrupt all other dialogue and interject with your message. - -### Out-of-character chat - -This is a general-purpose chat isolated within areas to discuss matters without interrupting cases. You must enter a name before chatting. - -### Music list - -Double-click a track to play it. Some servers automatically loop the track. Green tracks are available locally; red tracks are not. - -### Areas - -Servers have multiple areas to hold multiple cases simultaneously. Double-click an area in the music list to switch to it. (The reason that -areas are in the music list is a historical one.) - -### Judge controls - -The judge can set health bars and play the Witness Testimony, Cross Examination, Guilty, and Not Guilty animations. - -### Mod calls - -Calling a mod notifies moderators currently in the server of an incident. (Mod call reasons require 2.6+ server-side support.) Logged-in moderators can toggle the Guard option to be notified of mod calls. - -### Muting - -Click on a character in the mute list to ignore any in-character chat from the specified character. - -### Positions - -All characters have a default position within the courtroom, but they can nonetheless be changed within the interface. - -Available positions: - -- `def` - Defense -- `pro` - Prosecution -- `hld` - Helper defense -- `hlp` - Helper prosecution -- `jud` - Judge -- `wit` - Witness -- `jur` - Juror (2.6+) -- `sea` - Seance (2.6+) - -## Advanced features - -### Markup language - -2.6.0 introduces a markup language for in-character chat. It does not require server-side support. - -#### Color - -Wrapping text with these characters will set the text inside of them to the associated color. - -- `(` and `)` (parentheses) - blue -- \` (backtick) - green -- `|` (vertical bar) - orange -- `[` and `]` (square brackets) - grey - -#### Speed - -Type `{` to slow down the text a bit, and `}` to speed it up. This takes effect after the character has been typed, so the text may take up different speeds at different points. Both of these can be stacked up to three times, and even against each other. - -Example: -``` -Hello there! This text goes at normal speed.} Now, it's a bit faster!{ Now, it's back to normal.}}} Now it goes at maximum speed! {{Now it's only a little bit faster than normal. -``` - -#### Position - -If you begin a message with `~~` (two tildes), the two tildes are removed and the message is centered. - -### Pairing (2.6+) - -If two players are in the same position and select each other's characters using the in-game pair list (or with `/pair [id]`), they will appear alongside each other. You can set the offset of your character using the provided spinbox (or with `/offset [percentage]`). - -### Non-interrupting preanimations (2.6+) - -When checked, this will force text to immediately begin displaying without waiting for the preanimation to finish. - -### Custom IC names (shownames) (2.6+) - -You can set a custom in-character name using the provided text box. An option in the interface (or `/force_nonint_pres`) is also present to disable custom IC names for other players to prevent impersonation. - -### Extended area support (2.6+) - -Areas can be listed by clicking the A/M button (or `/switch_am`). The statuses of such areas are displayed (and updated automatically) if the server has 2.6+ support. - ---- - -## Upgrade guide for 2.6 - -2.6 inherits features from the Case Café custom client and server. Old themes and servers will still work, but they will not expose the new additions to players. - -### Server - -2.6 support has only been developed for tsuserver3. serverD is currently not equipped at all for such support. - -- Apply the new code changes. -- In `areas.yaml`: - - You may add `shouts_allowed` to any of the areas to enable / disable shouts (and judge buttons, and realisation). By default, it's `shouts_allowed: true`. - - You may add `jukebox` to any of the areas to enable the jukebox in there, but you can also use `/jukebox_toggle` in game as a mod to do the same thing. By default, it's `jukebox: false`. - - You may add `showname_changes_allowed` to any of the areas to allow custom shownames used in there. If it's forbidden, players can't send messages or change music as long as they have a custom name set. By default, it's `showname_changes_allowed: false`. - - You may add `abbreviation` to override the server-generated abbreviation of the area. Instead of area numbers, this server-pack uses area abbreviations in server messages for easier understanding (but still uses area IDs in commands, of course). No default here, but here is an example: `abbreviation: SIN` gives the area the abbreviation of 'SIN'. - - You may add `noninterrupting_pres` to force users to use non-interrupting pres only. 2.6 users will see the pres play as the text goes; pre-2.6 users will not see pres at all. The default is `noninterrupting_pres: false`. - -### Client themes - -- You'll need the following, additional images: - - `notguilty.gif` - Not Guilty verdict animation - - `guilty.gif` - Guilty verdict animation - - `notguilty.png` - Not Guilty button - - `guilty.png` - Guilty button - - `pair_button.png` - Pair button - - `pair_button_pressed.png` - Pair button (selected) -- In your `courtroom_sounds.ini`: - - Add a sound effect for `not_guilty`, for example: `not_guilty = sfx-notguilty.wav`. - - Add a sound effect for `guilty`, for example: `guilty = sfx-guilty.wav`. - - Add a sound effect for the case alerts. They work similarly to modcall alerts, or callword alerts. For example: `case_call = sfx-triplegavel-soj.wav`. -- In your `courtroom_design.ini`, place the following new UI elements as desired: - - `log_limit_label`, which is a simple text that explains what the spinbox with the numbers is. Needs an X, Y, width, height number. - - `log_limit_spinbox`, which is the spinbox for the log limit, allowing you to set the size of the log limit in-game. Needs the same stuff as above. - - `ic_chat_name`, which is an input field for your custom showname. Needs the same stuff. - - `ao2_ic_chat_name`, which is the same as above, but comes into play when the background has a desk. - - Further comments on this: all `ao2_` UI elements come into play when the background has a desk. However, in AO2 nowadays, it's customary for every background to have a desk, even if it's just an empty gif. So you most likely have never seen the `ao2_`-less UI elements ever come into play, unless someone mis-named a desk or something. - - `showname_enable` is a tickbox that toggles whether you should see shownames or not. This does not influence whether you can USE custom shownames or not, so you can have it off, while still showing a custom showname to everyone else. Needs X, Y, width, height as usual. - - `settings` is a plain button that takes up the OS's looks, like the 'Call mod' button. Takes the same arguments as above. - - You can also just type `/settings` in OOC. - - `char_search` is a text input box on the character selection screen, which allows you to filter characters down to name. Needs the same arguments. - - `char_passworded` is a tickbox, that when ticked, shows all passworded characters on the character selection screen. Needs the same as above. - - `char_taken` is another tickbox, that does the same, but for characters that are taken. - - `not_guilty` is a button similar to the CE / WT buttons, that if pressed, plays the Not Guilty verdict animation. Needs the same arguments. - - `guilty` is similar to `not_guilty`, but for the Guilty verdict. - - `pair_button` is a toggleable button, that shows and hides the pairing list and the offset spinbox. Works similarly to the mute button. - - `pair_list` is a list of all characters in alphabetical order, shown when the user presses the Pair button. If a character is clicked on it, it is selected as the character the user wants to pair up with. - - `pair_offset_spinbox` is a spinbox that allows the user to choose between offsets of -100% to 100%. - - `switch_area_music` is a button with the text 'A/M', that toggles between the music list and the areas list. Though the two are different, they are programmed to take the same space. - - `pre_no_interrupt` is a tickbox with the text 'No Intrpt', that toggles whether preanimations should delay the text or not. - - `area_free_color` is a combination of red, green, and blue values ranging from 0 to 255. This determines the colour of the area in the Area list if it's free, and has a status of `IDLE`. - - `area_lfp_color` determines the colour of the area if its status is `LOOKING-FOR-PLAYERS`. - - `area_casing_color` determines the colour of the area if its status is `CASING`. - - `area_recess_color` determines the colour of the area if its status is `RECESS`. - - `area_rp_color` determines the colour of the area if its status is `RP`. - - `area_gaming_color` determines the colour of the area if its status is `GAMING`. - - `area_locked_color` determines the colour of the area if it is locked, regardless of status. - - `ooc_default_color` determines the colour of the username in the OOC chat if the message doesn't come from the server. - - `ooc_server_color` determines the colour of the username if the message arrived from the server. - - `casing_button` is a button with the text 'Casing' that when clicked, brings up the Case Announcements dialog. You can give the case a name, and tick whom do you want to alert. You need to be a CM for it to go through. Only people who have at least one of the roles ticked will get the alert. - - `casing` is a tickbox with the text 'Casing'. If ticked, you will get the case announcements alerts you should get, in accordance to the above. In the settings, you can change your defaults on the 'Casing' tab. (That's a buncha things titled 'Casing'!) - +Rerfer to the Wiki for information. --- ## Compiling From f0a0f6bc1ac527d31c4f97ce57e2579985445e56 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Tue, 22 Oct 2019 18:07:21 +0300 Subject: [PATCH 126/268] Update README.md --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index cea1bfb..0b0da92 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,8 @@ # Attorney Online [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 Wiki for more information. -## Introduction for beginners - -Rerfer to the Wiki for information. --- ## Compiling From bef368e98651fa01e743728a2a88783fdfab74ac Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Wed, 23 Oct 2019 05:08:20 +0300 Subject: [PATCH 127/268] Allow gender (blip sounds) that don't use sfx-blip naming convention Fix "prezoom" packet being ignored Allow char.ini's to indicate a zoom w/ preanimation by using emote_mod=4 ((ALL OF THESE ARE UNTESTED - TESTING NEEDED!)) --- include/aocharmovie.h | 2 +- src/courtroom.cpp | 8 ++++---- src/emotes.cpp | 2 +- src/packet_distribution.cpp | 2 ++ src/text_file_functions.cpp | 6 ++++-- 5 files changed, 12 insertions(+), 8 deletions(-) diff --git a/include/aocharmovie.h b/include/aocharmovie.h index 8aed1eb..15fa7cf 100644 --- a/include/aocharmovie.h +++ b/include/aocharmovie.h @@ -67,7 +67,7 @@ private: QElapsedTimer actual_time; - //it will forever be a mystery who thought this time_mod system would ever be a good idea with precision-based emotes + //Usually used to turn seconds into milliseconds such as for [Time] tag in char.ini const int time_mod = 60; // These are the X and Y values before they are fixed based on the sprite's width. diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 7cb5cf3..fec354a 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1391,7 +1391,7 @@ void Courtroom::on_chat_return_pressed() { if (ui_pre->isChecked()) { - if (f_emote_mod == 5) + if (f_emote_mod == 4 || f_emote_mod == 5) f_emote_mod = 6; else f_emote_mod = 2; @@ -1957,7 +1957,7 @@ void Courtroom::play_char_sfx(QString sfx_name) { sfx_player->play(ao_app->get_sfx_suffix(sfx_name)); if(ao_app->get_looping_sfx()) - sfx_player->set_looping(ao_app->get_sfx_looping(current_char, sfx_name)!="0"); + sfx_player->set_looping(ao_app->get_sfx_looping(current_char, QString::number(current_emote))!="0"); } void Courtroom::handle_chatmessage_3() @@ -2396,7 +2396,7 @@ void Courtroom::play_preanim(bool noninterrupting) //all time values in char.inis are multiplied by a constant(time_mod) to get the actual time int ao2_duration = ao_app->get_ao2_preanim_duration(f_char, f_preanim); int text_delay = ao_app->get_text_delay(f_char, f_preanim) * time_mod; - int sfx_delay = m_chatmessage[SFX_DELAY].toInt() * 60; + int sfx_delay = m_chatmessage[SFX_DELAY].toInt() * time_mod; int preanim_duration; @@ -2493,7 +2493,7 @@ void Courtroom::start_chat_ticking() QString f_gender = ao_app->get_gender(m_chatmessage[CHAR_NAME]); - blip_player->set_blips(ao_app->get_sfx_suffix("sfx-blip" + f_gender)); + blip_player->set_blips(ao_app->get_sfx_suffix(f_gender)); //means text is currently ticking text_state = 1; diff --git a/src/emotes.cpp b/src/emotes.cpp index 58e8594..de53169 100644 --- a/src/emotes.cpp +++ b/src/emotes.cpp @@ -159,7 +159,7 @@ void Courtroom::select_emote(int p_id) { ui_pre->setChecked(!ui_pre->isChecked()); } - else if (emote_mod == 1) + else if (emote_mod == 1 || emote_mod == 4) ui_pre->setChecked(true); else ui_pre->setChecked(false); diff --git a/src/packet_distribution.cpp b/src/packet_distribution.cpp index 20a07a6..8c74b76 100644 --- a/src/packet_distribution.cpp +++ b/src/packet_distribution.cpp @@ -192,6 +192,8 @@ void AOApplication::server_packet_received(AOPacket *p_packet) { if (f_packet.contains("yellowtext",Qt::CaseInsensitive)) yellow_text_enabled = true; + if (f_packet.contains("prezoom",Qt::CaseInsensitive)) + prezoom_enabled = true; if (f_packet.contains("flipping",Qt::CaseInsensitive)) flipping_enabled = true; if (f_packet.contains("customobjections",Qt::CaseInsensitive)) diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index 204de69..f38bbb5 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -628,8 +628,10 @@ QString AOApplication::get_gender(QString p_char) QString f_result = read_char_ini(p_char, "gender", "Options"); if (f_result == "") - return "male"; - else return f_result; + return "sfx-blipmale"; + if (!file_exists(get_sfx(f_result))) + f_result = "sfx-blip" + f_result; + return f_result; } QString AOApplication::get_chat(QString p_char) From 773a61f3d4ce2284b2d5d753b5c696f7bd44a531 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Mon, 4 Nov 2019 15:32:01 +0300 Subject: [PATCH 128/268] Make the music search bar search in music metadata instead of just the displayed name (aka the filepath) Make sfx player able to play sfx without the file extension provided Allow blipsounds to seek in blips/ folder to allow better categorization, as well as direct sound references add get_emote_blip for detecting the blipsound used by an emote. Currently unused. Less strict/hardcoded custom objection detection system Allow system (charid -1) messages, and don't do the same message detection on blankposting Allow objection, hold it, take that and custom sound players to detect sounds that are not exclusively .wav --- include/aoapplication.h | 3 ++ src/aosfxplayer.cpp | 3 ++ src/courtroom.cpp | 39 ++++++++++----------- src/text_file_functions.cpp | 69 +++++++++++++++++++++---------------- 4 files changed, 64 insertions(+), 50 deletions(-) diff --git a/include/aoapplication.h b/include/aoapplication.h index af1433f..8dd48c6 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -335,6 +335,9 @@ public: //Returns the sfx of p_char's p_emote QString get_sfx_name(QString p_char, int p_emote); + //Returns the blipsound of p_char's p_emote + QString get_emote_blip(QString p_char, int p_emote); + //Returns if the sfx is defined as looping in char.ini QString get_sfx_looping(QString p_char, QString p_sfx); diff --git a/src/aosfxplayer.cpp b/src/aosfxplayer.cpp index ca2b393..cc01972 100644 --- a/src/aosfxplayer.cpp +++ b/src/aosfxplayer.cpp @@ -56,6 +56,9 @@ void AOSfxPlayer::play(QString p_sfx, QString p_char, QString shout, int channel else f_path = sound_path; + if (!file_exists(f_path)) + f_path = ao_app->get_sfx_suffix(f_path); //If we're not given a sound file with .wav/.ogg/.opus already there, let's do this thing + m_stream_list[channel] = BASS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE); set_volume_internal(m_volume); diff --git a/src/courtroom.cpp b/src/courtroom.cpp index fec354a..30c391f 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -782,7 +782,7 @@ void Courtroom::set_widgets() ui_custom_objection->setText(tr("Custom Shout!")); ui_custom_objection->set_image("custom"); ui_custom_objection->setToolTip(tr("This will display the custom character-defined animation in the viewport as soon as it is pressed.\n" - "To make one, your character's folder must contain custom.[webp/apng/gif/png] and custom.wav")); + "To make one, your character's folder must contain custom.[webp/apng/gif/png] and custom.[wav/ogg/opus] sound effect")); set_size_and_pos(ui_realization, "realization"); ui_realization->set_image("realization"); @@ -1002,9 +1002,10 @@ void Courtroom::set_background(QString p_background, bool display) ui_vp_testimony->stop(); current_background = p_background; - is_ao2_bg = file_exists(ao_app->get_static_image_suffix(ao_app->get_background_path("defensedesk"))) && - file_exists(ao_app->get_static_image_suffix(ao_app->get_background_path("prosecutiondesk"))) && - file_exists(ao_app->get_static_image_suffix(ao_app->get_background_path("stand"))); + is_ao2_bg = true; +// file_exists(ao_app->get_static_image_suffix(ao_app->get_background_path("defensedesk"))) && +// file_exists(ao_app->get_static_image_suffix(ao_app->get_background_path("prosecutiondesk"))) && +// file_exists(ao_app->get_static_image_suffix(ao_app->get_background_path("stand"))); if (is_ao2_bg) { @@ -1127,10 +1128,7 @@ void Courtroom::update_character(int p_cid) ui_prosecution_plus->hide(); } - if (ao_app->custom_objection_enabled && - (file_exists(ao_app->get_character_path(current_char, "custom.gif")) || - file_exists(ao_app->get_character_path(current_char, "custom.apng"))) && - file_exists(ao_app->get_character_path(current_char, "custom.wav"))) + if (ao_app->custom_objection_enabled && file_exists(ao_app->get_image_suffix(ao_app->get_character_path(current_char, "custom")))) ui_custom_objection->show(); else ui_custom_objection->hide(); @@ -1597,8 +1595,11 @@ void Courtroom::handle_chatmessage(QStringList *p_contents) QString f_message = f_showname + ": " + m_chatmessage[MESSAGE] + '\n'; + //Remove undesired newline chars + m_chatmessage[MESSAGE].remove("\n"); + chatmessage_is_empty = m_chatmessage[MESSAGE] == " " || m_chatmessage[MESSAGE] == ""; - if (f_char_id >= 0 && f_message == previous_ic_message) //Not a system message + if (f_char_id >= 0 && !chatmessage_is_empty && f_message == previous_ic_message) //Not a system message return; if (f_char_id <= -1) @@ -1615,11 +1616,6 @@ void Courtroom::handle_chatmessage(QStringList *p_contents) chat_tick_timer->stop(); ui_vp_evidence_display->reset(); - //Remove undesired newline chars - m_chatmessage[MESSAGE].remove("\n"); - - chatmessage_is_empty = m_chatmessage[MESSAGE] == " " || m_chatmessage[MESSAGE] == ""; - //Hey, our message showed up! Cool! if (m_chatmessage[MESSAGE] == ui_ic_chat_message->text().remove("\n") && m_chatmessage[CHAR_ID].toInt() == m_cid) { @@ -1669,22 +1665,22 @@ void Courtroom::handle_chatmessage(QStringList *p_contents) { case 1: ui_vp_objection->play("holdit_bubble", f_char, f_custom_theme, 724); - objection_player->play("holdit.wav", f_char, f_custom_theme); + objection_player->play("holdit", f_char, f_custom_theme); break; case 2: ui_vp_objection->play("objection_bubble", f_char, f_custom_theme, 724); - objection_player->play("objection.wav", f_char, f_custom_theme); + objection_player->play("objection", f_char, f_custom_theme); if(ao_app->objection_stop_music()) music_player->stop(); break; case 3: ui_vp_objection->play("takethat_bubble", f_char, f_custom_theme, 724); - objection_player->play("takethat.wav", f_char, f_custom_theme); + objection_player->play("takethat", f_char, f_custom_theme); break; //case 4 is AO2 only case 4: ui_vp_objection->play("custom", f_char, f_custom_theme, 724); - objection_player->play("custom.wav", f_char, f_custom_theme); + objection_player->play("custom", f_char, f_custom_theme); break; default: qDebug() << "W: Logic error in objection switch statement!"; @@ -2493,7 +2489,7 @@ void Courtroom::start_chat_ticking() QString f_gender = ao_app->get_gender(m_chatmessage[CHAR_NAME]); - blip_player->set_blips(ao_app->get_sfx_suffix(f_gender)); + blip_player->set_blips(f_gender); //means text is currently ticking text_state = 1; @@ -2518,7 +2514,7 @@ void Courtroom::chat_tick() ui_vp_player_char->play_idle(m_chatmessage[CHAR_NAME], m_chatmessage[EMOTE]); } 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_chat_arrow->play("chat_arrow", f_char, f_custom_theme); //Chat stopped being processed, indicate that. additive_previous = additive_previous + filter_ic_text(f_message, true, -1, m_chatmessage[TEXT_COLOR].toInt()); real_tick_pos = ui_vp_message->toPlainText().size(); @@ -3320,7 +3316,8 @@ void Courtroom::on_music_search_edited(QString p_text) if (p_text != "") { - QList clist = ui_music_list->findItems(ui_music_search->text(), Qt::MatchContains|Qt::MatchRecursive, 0); + //Search in metadata + QList clist = ui_music_list->findItems(ui_music_search->text(), Qt::MatchContains|Qt::MatchRecursive, 1); foreach(QTreeWidgetItem* item, clist) { if (item->parent() != nullptr) //So the category shows up too diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index f38bbb5..da14413 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -527,16 +527,15 @@ QString AOApplication::get_sfx(QString p_identifier) QString AOApplication::get_sfx_suffix(QString sound_to_check) { - QString mp3_check = get_sounds_path(sound_to_check + ".mp3"); - QString opus_check = get_sounds_path(sound_to_check + ".opus"); - if (file_exists(opus_check)) - { + sound_to_check = get_sounds_path(sound_to_check); + if (file_exists(sound_to_check + ".opus")) return sound_to_check + ".opus"; - } - else if (file_exists(mp3_check)) - { + if (file_exists(sound_to_check + ".ogg")) + return sound_to_check + ".ogg"; + if (file_exists(sound_to_check + ".mp3")) return sound_to_check + ".mp3"; - } + if (file_exists(sound_to_check + ".mp4")) + return sound_to_check + ".mp4"; return sound_to_check + ".wav"; } @@ -599,7 +598,7 @@ QString AOApplication::get_char_name(QString p_char) if (f_result == "") return p_char; - else return f_result; + return f_result; } QString AOApplication::get_showname(QString p_char) @@ -611,7 +610,7 @@ QString AOApplication::get_showname(QString p_char) return ""; if (f_result == "") return p_char; - else return f_result; + return f_result; } QString AOApplication::get_char_side(QString p_char) @@ -620,7 +619,7 @@ QString AOApplication::get_char_side(QString p_char) if (f_result == "") return "wit"; - else return f_result; + return f_result; } QString AOApplication::get_gender(QString p_char) @@ -629,8 +628,14 @@ QString AOApplication::get_gender(QString p_char) if (f_result == "") return "sfx-blipmale"; - if (!file_exists(get_sfx(f_result))) - f_result = "sfx-blip" + f_result; + + if (!file_exists(get_sfx_suffix(get_sfx(f_result)))) + { + if (file_exists(get_sfx_suffix(get_sfx("blips/" + f_result)))) + return "blips/" + f_result; //Return the cool kids variant + + return "sfx-blip" + f_result; //Return legacy variant + } return f_result; } @@ -663,7 +668,7 @@ QString AOApplication::get_char_shouts(QString p_char) QString f_result = read_char_ini(p_char, "shouts", "Options"); if (f_result == "") return "default"; - else return f_result; + return f_result; } int AOApplication::get_preanim_duration(QString p_char, QString p_emote) @@ -672,7 +677,7 @@ int AOApplication::get_preanim_duration(QString p_char, QString p_emote) if (f_result == "") return -1; - else return f_result.toInt(); + return f_result.toInt(); } int AOApplication::get_ao2_preanim_duration(QString p_char, QString p_emote) @@ -681,7 +686,7 @@ int AOApplication::get_ao2_preanim_duration(QString p_char, QString p_emote) if (f_result == "") return -1; - else return f_result.toInt(); + return f_result.toInt(); } int AOApplication::get_emote_number(QString p_char) @@ -690,7 +695,7 @@ int AOApplication::get_emote_number(QString p_char) if (f_result == "") return 0; - else return f_result.toInt(); + return f_result.toInt(); } QString AOApplication::get_emote_comment(QString p_char, int p_emote) @@ -704,7 +709,7 @@ QString AOApplication::get_emote_comment(QString p_char, int p_emote) qDebug() << "W: misformatted char.ini: " << p_char << ", " << p_emote; return "normal"; } - else return result_contents.at(0); + return result_contents.at(0); } QString AOApplication::get_pre_emote(QString p_char, int p_emote) @@ -718,7 +723,7 @@ QString AOApplication::get_pre_emote(QString p_char, int p_emote) qDebug() << "W: misformatted char.ini: " << p_char << ", " << p_emote; return ""; } - else return result_contents.at(1); + return result_contents.at(1); } QString AOApplication::get_emote(QString p_char, int p_emote) @@ -732,7 +737,7 @@ QString AOApplication::get_emote(QString p_char, int p_emote) qDebug() << "W: misformatted char.ini: " << p_char << ", " << p_emote; return "normal"; } - else return result_contents.at(2); + return result_contents.at(2); } int AOApplication::get_emote_mod(QString p_char, int p_emote) @@ -746,7 +751,7 @@ int AOApplication::get_emote_mod(QString p_char, int p_emote) qDebug() << "W: misformatted char.ini: " << p_char << ", " << QString::number(p_emote); return 0; } - else return result_contents.at(3).toInt(); + return result_contents.at(3).toInt(); } int AOApplication::get_desk_mod(QString p_char, int p_emote) @@ -762,7 +767,7 @@ int AOApplication::get_desk_mod(QString p_char, int p_emote) if (string_result == "") return -1; - else return string_result.toInt(); + return string_result.toInt(); } QString AOApplication::get_sfx_name(QString p_char, int p_emote) @@ -771,7 +776,13 @@ QString AOApplication::get_sfx_name(QString p_char, int p_emote) if (f_result == "") return "1"; - else return f_result; + return f_result; +} + +QString AOApplication::get_emote_blip(QString p_char, int p_emote) +{ + QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "SoundB"); + return f_result; } int AOApplication::get_sfx_delay(QString p_char, int p_emote) @@ -780,7 +791,7 @@ int AOApplication::get_sfx_delay(QString p_char, int p_emote) if (f_result == "") return 1; - else return f_result.toInt(); + return f_result.toInt(); } QString AOApplication::get_sfx_looping(QString p_char, QString p_sfx) @@ -789,7 +800,7 @@ QString AOApplication::get_sfx_looping(QString p_char, QString p_sfx) if (f_result == "") return "0"; - else return f_result; + return f_result; } QString AOApplication::get_sfx_frame(QString p_char, QString p_emote, int n_frame) @@ -798,7 +809,7 @@ QString AOApplication::get_sfx_frame(QString p_char, QString p_emote, int n_fram if (f_result == "") return ""; - else return f_result; + return f_result; } QString AOApplication::get_screenshake_frame(QString p_char, QString p_emote, int n_frame) @@ -807,7 +818,7 @@ QString AOApplication::get_screenshake_frame(QString p_char, QString p_emote, in if (f_result == "") return ""; - else return f_result; + return f_result; } QString AOApplication::get_flash_frame(QString p_char, QString p_emote, int n_frame) @@ -816,7 +827,7 @@ QString AOApplication::get_flash_frame(QString p_char, QString p_emote, int n_fr if (f_result == "") return ""; - else return f_result; + return f_result; } int AOApplication::get_text_delay(QString p_char, QString p_emote) @@ -825,7 +836,7 @@ int AOApplication::get_text_delay(QString p_char, QString p_emote) if (f_result == "") return -1; - else return f_result.toInt(); + return f_result.toInt(); } QStringList AOApplication::get_theme_effects() From 963e32109503fe7bb83c5a4111913e1d489db608 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Mon, 4 Nov 2019 15:38:54 +0300 Subject: [PATCH 129/268] If def/pro/jud/hld/hlp are missing, put the character in pos wit instead of showing broken bg. --- src/courtroom.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 30c391f..2efa34c 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -2701,7 +2701,7 @@ void Courtroom::set_scene(QString f_desk_mod, QString f_side) QString f_background = "witnessempty"; QString f_desk_image = "stand"; - if (f_side == "def") + if (f_side == "def" && file_exists(ao_app->get_image_suffix(ao_app->get_background_path("defenseempty")))) { f_background = "defenseempty"; if (is_ao2_bg) @@ -2709,7 +2709,7 @@ void Courtroom::set_scene(QString f_desk_mod, QString f_side) else f_desk_image = "bancodefensa"; } - else if (f_side == "pro") + else if (f_side == "pro" && file_exists(ao_app->get_image_suffix(ao_app->get_background_path("prosecutorempty")))) { f_background = "prosecutorempty"; if (is_ao2_bg) @@ -2717,17 +2717,17 @@ void Courtroom::set_scene(QString f_desk_mod, QString f_side) else f_desk_image = "bancoacusacion"; } - else if (f_side == "jud") + else if (f_side == "jud" && file_exists(ao_app->get_image_suffix(ao_app->get_background_path("judgestand")))) { f_background = "judgestand"; f_desk_image = "judgedesk"; } - else if (f_side == "hld") + else if (f_side == "hld" && file_exists(ao_app->get_image_suffix(ao_app->get_background_path("helperstand")))) { f_background = "helperstand"; f_desk_image = "helperdesk"; } - else if (f_side == "hlp") + else if (f_side == "hlp" && file_exists(ao_app->get_image_suffix(ao_app->get_background_path("prohelperstand")))) { f_background = "prohelperstand"; f_desk_image = "prohelperdesk"; From a49c4a503bcdfd09b9bbda3552e1598a4d147f40 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Mon, 4 Nov 2019 16:10:54 +0300 Subject: [PATCH 130/268] add .opus support --- Attorney_Online.pro | 2 +- include/aoblipplayer.h | 1 + include/aomusicplayer.h | 1 + include/aosfxplayer.h | 1 + include/bassopus.h | 52 +++++++++++++++++++++++++++++++++++++++++ src/aoblipplayer.cpp | 7 ++++-- src/aomusicplayer.cpp | 6 ++++- src/aosfxplayer.cpp | 5 +++- 8 files changed, 70 insertions(+), 5 deletions(-) create mode 100644 include/bassopus.h diff --git a/Attorney_Online.pro b/Attorney_Online.pro index 6061cd9..ab61a55 100644 --- a/Attorney_Online.pro +++ b/Attorney_Online.pro @@ -13,7 +13,6 @@ MOC_DIR = $$PWD/build SOURCES += $$files($$PWD/src/*.cpp) HEADERS += $$files($$PWD/include/*.h) - LIBS += -L$$PWD/lib DEFINES += DISCORD @@ -26,6 +25,7 @@ DEFINES += BASSAUDIO contains(DEFINES, BASSAUDIO) { LIBS += -lbass +LIBS += -lbassopus } #DEFINES += QTAUDIO diff --git a/include/aoblipplayer.h b/include/aoblipplayer.h index 9a42837..a848e80 100644 --- a/include/aoblipplayer.h +++ b/include/aoblipplayer.h @@ -3,6 +3,7 @@ #if defined(BASSAUDIO) #include "bass.h" +#include "bassopus.h" #elif defined(QTAUDIO) #include #endif diff --git a/include/aomusicplayer.h b/include/aomusicplayer.h index 52c97c3..1a53582 100644 --- a/include/aomusicplayer.h +++ b/include/aomusicplayer.h @@ -4,6 +4,7 @@ #if defined(BASSAUDIO) #include "bass.h" +#include "bassopus.h" #elif defined(QTAUDIO) #include #endif diff --git a/include/aosfxplayer.h b/include/aosfxplayer.h index 112e3ec..3ae8bdf 100644 --- a/include/aosfxplayer.h +++ b/include/aosfxplayer.h @@ -3,6 +3,7 @@ #if defined(BASSAUDIO) #include "bass.h" +#include "bassopus.h" #elif defined(QTAUDIO) #include #endif diff --git a/include/bassopus.h b/include/bassopus.h new file mode 100644 index 0000000..4e48124 --- /dev/null +++ b/include/bassopus.h @@ -0,0 +1,52 @@ +/* + BASSOPUS 2.4 C/C++ header file + Copyright (c) 2012-2015 Un4seen Developments Ltd. + + See the BASSOPUS.CHM file for more detailed documentation +*/ + +#ifndef BASSOPUS_H +#define BASSOPUS_H + +#include "bass.h" + +#if BASSVERSION!=0x204 +#error conflicting BASS and BASSOPUS versions +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef BASSOPUSDEF +#define BASSOPUSDEF(f) WINAPI f +#endif + +// BASS_CHANNELINFO type +#define BASS_CTYPE_STREAM_OPUS 0x11200 + +// Additional attributes +#define BASS_ATTRIB_OPUS_ORIGFREQ 0x13000 +#define BASS_ATTRIB_OPUS_GAIN 0x13001 + +HSTREAM BASSOPUSDEF(BASS_OPUS_StreamCreateFile)(BOOL mem, const void *file, QWORD offset, QWORD length, DWORD flags); +HSTREAM BASSOPUSDEF(BASS_OPUS_StreamCreateURL)(const char *url, DWORD offset, DWORD flags, DOWNLOADPROC *proc, void *user); +HSTREAM BASSOPUSDEF(BASS_OPUS_StreamCreateFileUser)(DWORD system, DWORD flags, const BASS_FILEPROCS *procs, void *user); + +#ifdef __cplusplus +} + +#if defined(_WIN32) && !defined(NOBASSOVERLOADS) +static inline HSTREAM BASS_OPUS_StreamCreateFile(BOOL mem, const WCHAR *file, QWORD offset, QWORD length, DWORD flags) +{ + return BASS_OPUS_StreamCreateFile(mem, (const void*)file, offset, length, flags|BASS_UNICODE); +} + +static inline HSTREAM BASS_OPUS_StreamCreateURL(const WCHAR *url, DWORD offset, DWORD flags, DOWNLOADPROC *proc, void *user) +{ + return BASS_OPUS_StreamCreateURL((const char*)url, offset, flags|BASS_UNICODE, proc, user); +} +#endif +#endif + +#endif diff --git a/src/aoblipplayer.cpp b/src/aoblipplayer.cpp index 5f4dc6c..4c7bf7b 100644 --- a/src/aoblipplayer.cpp +++ b/src/aoblipplayer.cpp @@ -15,7 +15,10 @@ void AOBlipPlayer::set_blips(QString p_sfx) { BASS_StreamFree(m_stream_list[n_stream]); - m_stream_list[n_stream] = BASS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, BASS_UNICODE | BASS_ASYNCFILE); + if (f_path.endsWith(".opus")) + m_stream_list[n_stream] = BASS_OPUS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, BASS_UNICODE | BASS_ASYNCFILE); + else + m_stream_list[n_stream] = BASS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, BASS_UNICODE | BASS_ASYNCFILE); } set_volume_internal(m_volume); @@ -46,7 +49,7 @@ void AOBlipPlayer::set_volume(qreal p_value) void AOBlipPlayer::set_volume_internal(qreal p_value) { - float volume = p_value; + float volume = static_cast(p_value); for (int n_stream = 0 ; n_stream < 5 ; ++n_stream) { diff --git a/src/aomusicplayer.cpp b/src/aomusicplayer.cpp index 49cf089..9a96b3e 100644 --- a/src/aomusicplayer.cpp +++ b/src/aomusicplayer.cpp @@ -26,7 +26,11 @@ void AOMusicPlayer::play(QString p_song, int channel, bool loop, int effect_flag if (loop) flags |= BASS_SAMPLE_LOOP; - DWORD newstream = BASS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, flags); + DWORD newstream; + if (f_path.endsWith(".opus")) + newstream = BASS_OPUS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, flags); + else + newstream = BASS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, flags); if (ao_app->get_audio_output_device() != "default") BASS_ChannelSetDevice(m_stream_list[channel], BASS_GetDevice()); diff --git a/src/aosfxplayer.cpp b/src/aosfxplayer.cpp index cc01972..98496ea 100644 --- a/src/aosfxplayer.cpp +++ b/src/aosfxplayer.cpp @@ -59,7 +59,10 @@ void AOSfxPlayer::play(QString p_sfx, QString p_char, QString shout, int channel if (!file_exists(f_path)) f_path = ao_app->get_sfx_suffix(f_path); //If we're not given a sound file with .wav/.ogg/.opus already there, let's do this thing - m_stream_list[channel] = BASS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE); + if (f_path.endsWith(".opus")) + m_stream_list[channel] = BASS_OPUS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE); + else + m_stream_list[channel] = BASS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE); set_volume_internal(m_volume); From d40292125710e2e6698ffad7f4a7d7dcc41eace6 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Mon, 4 Nov 2019 16:31:42 +0300 Subject: [PATCH 131/268] Fix screenshaking only shaking down right --- src/courtroom.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 2efa34c..4eb1287 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1912,8 +1912,9 @@ void Courtroom::do_screenshake() { double fraction = double(frame*frequency)/duration; int rng = qrand();//QRandomGenerator::global()->generate(); - int rand_x = int(rng) % max_x; - int rand_y = int(rng+100) % max_y; + int rand_x = max_x - (int(rng) % (max_x*2)); + int rand_y = max_y - (int(rng+100) % (max_y*2)); + qDebug() << rand_x << rand_y; screenshake_animation->setKeyValueAt(fraction, QPoint(pos_default.x() + rand_x, pos_default.y() + rand_y)); } screenshake_animation->setEndValue(pos_default); @@ -2456,13 +2457,6 @@ void Courtroom::start_chat_ticking() this->do_flash(); sfx_player->play(ao_app->get_custom_realization(m_chatmessage[CHAR_NAME])); } - - int emote_mod = m_chatmessage[EMOTE_MOD].toInt(); //text meme bonanza - if ((emote_mod == 0 || emote_mod == 5) && m_chatmessage[SCREENSHAKE] == "1") - { - this->do_screenshake(); - } - if (chatmessage_is_empty) { //since the message is empty, it's technically done ticking @@ -2491,6 +2485,12 @@ void Courtroom::start_chat_ticking() blip_player->set_blips(f_gender); + int emote_mod = m_chatmessage[EMOTE_MOD].toInt(); //text meme bonanza + if ((emote_mod == 0 || emote_mod == 5) && m_chatmessage[SCREENSHAKE] == "1") + { + this->do_screenshake(); + } + //means text is currently ticking text_state = 1; } From 9939637dda8cf09fc4e1620378fc5ac5de8885f6 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Mon, 4 Nov 2019 17:13:52 +0300 Subject: [PATCH 132/268] Fix the sound bonanza so they actually play sfx player and blip player now both account for extension-less sound paths and also correctly handle paths that do provide the extension. --- src/aoblipplayer.cpp | 2 +- src/aosfxplayer.cpp | 9 +++------ src/courtroom.cpp | 8 +++----- src/text_file_functions.cpp | 9 ++++++--- 4 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/aoblipplayer.cpp b/src/aoblipplayer.cpp index 4c7bf7b..008ff16 100644 --- a/src/aoblipplayer.cpp +++ b/src/aoblipplayer.cpp @@ -9,7 +9,7 @@ AOBlipPlayer::AOBlipPlayer(QWidget *parent, AOApplication *p_ao_app) void AOBlipPlayer::set_blips(QString p_sfx) { - QString f_path = ao_app->get_sounds_path(p_sfx); + QString f_path = ao_app->get_sfx_suffix(ao_app->get_sounds_path(p_sfx)); for (int n_stream = 0 ; n_stream < 5 ; ++n_stream) { diff --git a/src/aosfxplayer.cpp b/src/aosfxplayer.cpp index 98496ea..9fa3026 100644 --- a/src/aosfxplayer.cpp +++ b/src/aosfxplayer.cpp @@ -40,12 +40,12 @@ void AOSfxPlayer::play(QString p_sfx, QString p_char, QString shout, int channel QString misc_path = ""; QString char_path = ""; - QString sound_path = ao_app->get_sounds_path(p_sfx); + QString sound_path = ao_app->get_sfx_suffix(ao_app->get_sounds_path(p_sfx)); if (shout != "") - misc_path = ao_app->get_base_path() + "misc/" + shout + "/" + p_sfx; + misc_path = ao_app->get_sfx_suffix(ao_app->get_base_path() + "misc/" + shout + "/" + p_sfx); if (p_char != "") - char_path = ao_app->get_character_path(p_char, p_sfx); + char_path = ao_app->get_sfx_suffix(ao_app->get_character_path(p_char, p_sfx)); QString f_path; @@ -56,9 +56,6 @@ void AOSfxPlayer::play(QString p_sfx, QString p_char, QString shout, int channel else f_path = sound_path; - if (!file_exists(f_path)) - f_path = ao_app->get_sfx_suffix(f_path); //If we're not given a sound file with .wav/.ogg/.opus already there, let's do this thing - if (f_path.endsWith(".opus")) m_stream_list[channel] = BASS_OPUS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE); else diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 4eb1287..08acc5e 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1818,7 +1818,6 @@ void Courtroom::handle_chatmessage_2() int other_offset = m_chatmessage[OTHER_OFFSET].toInt(); ui_vp_sideplayer_char->move(ui_viewport->width() * other_offset / 100, 0); - qDebug() << "other offset" << other_offset; QStringList args = m_chatmessage[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? @@ -1914,7 +1913,6 @@ void Courtroom::do_screenshake() int rng = qrand();//QRandomGenerator::global()->generate(); int rand_x = max_x - (int(rng) % (max_x*2)); int rand_y = max_y - (int(rng+100) % (max_y*2)); - qDebug() << rand_x << rand_y; screenshake_animation->setKeyValueAt(fraction, QPoint(pos_default.x() + rand_x, pos_default.y() + rand_y)); } screenshake_animation->setEndValue(pos_default); @@ -1947,12 +1945,12 @@ void Courtroom::do_effect(QString fx_name, QString fx_sound, QString p_char) ui_vp_effect->set_play_once(false); // The effects themselves dictate whether or not they're looping. Static effects will linger. ui_vp_effect->play(effect); // It will set_play_once to true if the filepath provided is not designed to loop more than once if (fx_sound != "") - sfx_player->play(ao_app->get_sfx_suffix(fx_sound)); + sfx_player->play(fx_sound); } void Courtroom::play_char_sfx(QString sfx_name) { - sfx_player->play(ao_app->get_sfx_suffix(sfx_name)); + sfx_player->play(sfx_name); if(ao_app->get_looping_sfx()) sfx_player->set_looping(ao_app->get_sfx_looping(current_char, QString::number(current_emote))!="0"); } @@ -2690,7 +2688,7 @@ void Courtroom::play_sfx() if (sfx_name == "1") return; - sfx_player->play(ao_app->get_sfx_suffix(sfx_name)); + sfx_player->play(sfx_name); if(ao_app->get_looping_sfx()) sfx_player->set_looping(ao_app->get_sfx_looping(current_char, sfx_name)!="0"); } diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index da14413..41b20f3 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -527,7 +527,8 @@ QString AOApplication::get_sfx(QString p_identifier) QString AOApplication::get_sfx_suffix(QString sound_to_check) { - sound_to_check = get_sounds_path(sound_to_check); + if (sound_to_check.contains(".")) //We have what we could call a file extension + return sound_to_check; if (file_exists(sound_to_check + ".opus")) return sound_to_check + ".opus"; if (file_exists(sound_to_check + ".ogg")) @@ -541,6 +542,8 @@ QString AOApplication::get_sfx_suffix(QString sound_to_check) QString AOApplication::get_image_suffix(QString path_to_check) { + if (path_to_check.contains(".")) //We have what we could call a file extension + return path_to_check; if (file_exists(path_to_check + ".webp")) return path_to_check + ".webp"; if (file_exists(path_to_check + ".apng")) @@ -629,9 +632,9 @@ QString AOApplication::get_gender(QString p_char) if (f_result == "") return "sfx-blipmale"; - if (!file_exists(get_sfx_suffix(get_sfx(f_result)))) + if (!file_exists(get_sfx_suffix(get_sounds_path(f_result)))) { - if (file_exists(get_sfx_suffix(get_sfx("blips/" + f_result)))) + if (file_exists(get_sfx_suffix(get_sounds_path("blips/" + f_result)))) return "blips/" + f_result; //Return the cool kids variant return "sfx-blip" + f_result; //Return legacy variant From 886ec26e2095bdcb18a05b57cb7c302be0d906c6 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Mon, 4 Nov 2019 17:14:46 +0300 Subject: [PATCH 133/268] "temporarily" simplify code by stripping long since botched and unused AO1 backwards compatibility --- src/courtroom.cpp | 34 +++------------------------------- 1 file changed, 3 insertions(+), 31 deletions(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 08acc5e..db48e51 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -2702,18 +2702,12 @@ void Courtroom::set_scene(QString f_desk_mod, QString f_side) if (f_side == "def" && file_exists(ao_app->get_image_suffix(ao_app->get_background_path("defenseempty")))) { f_background = "defenseempty"; - if (is_ao2_bg) - f_desk_image = "defensedesk"; - else - f_desk_image = "bancodefensa"; + f_desk_image = "defensedesk"; } else if (f_side == "pro" && file_exists(ao_app->get_image_suffix(ao_app->get_background_path("prosecutorempty")))) { f_background = "prosecutorempty"; - if (is_ao2_bg) - f_desk_image = "prosecutiondesk"; - else - f_desk_image = "bancoacusacion"; + f_desk_image = "prosecutiondesk"; } else if (f_side == "jud" && file_exists(ao_app->get_image_suffix(ao_app->get_background_path("judgestand")))) { @@ -2740,13 +2734,6 @@ void Courtroom::set_scene(QString f_desk_mod, QString f_side) f_background = "seancestand"; f_desk_image = "seancedesk"; } - else - { - if (is_ao2_bg) - f_desk_image = "stand"; - else - f_desk_image = "estrado"; - } if (file_exists(ao_app->get_image_suffix(ao_app->get_background_path(f_side)))) //Unique pos path { @@ -2766,26 +2753,11 @@ void Courtroom::set_scene(QString f_desk_mod, QString f_side) ui_vp_desk->hide(); ui_vp_legacy_desk->hide(); } - else if (is_ao2_bg || (f_side == "jud" || - f_side == "hld" || - f_side == "hlp")) + else { ui_vp_legacy_desk->hide(); ui_vp_desk->show(); } - else - { - if (f_side == "wit") - { - ui_vp_desk->show(); - ui_vp_legacy_desk->hide(); - } - else - { - ui_vp_desk->hide(); - ui_vp_legacy_desk->show(); - } - } } void Courtroom::set_ip_list(QString p_list) From 34848c4eaf8df62719045889a55be4c9ac2419a8 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Mon, 18 Nov 2019 20:27:37 +0300 Subject: [PATCH 134/268] Fix a bug where user would be unable to speak if the BG changed when someone else was speaking Make it so blip sounds are accessed in base/sounds/blips/* if such a path exists --- src/courtroom.cpp | 7 +++++++ src/text_file_functions.cpp | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index db48e51..1a1fd9e 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1028,7 +1028,14 @@ void Courtroom::set_background(QString p_background, bool display) ui_vp_message->hide(); ui_vp_chatbox->hide(); + //Stop the chat arrow from animating + ui_vp_chat_arrow->stop(); + + text_state = 0; + anim_state = 0; + ui_vp_objection->stop(); chat_tick_timer->stop(); + ui_vp_evidence_display->reset(); set_scene(QString::number(ao_app->get_desk_mod(current_char, current_emote)), current_side); } } diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index 41b20f3..783c83b 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -634,8 +634,8 @@ QString AOApplication::get_gender(QString p_char) if (!file_exists(get_sfx_suffix(get_sounds_path(f_result)))) { - if (file_exists(get_sfx_suffix(get_sounds_path("blips/" + f_result)))) - return "blips/" + f_result; //Return the cool kids variant + if (file_exists(get_sfx_suffix(get_sounds_path("../blips/" + f_result)))) + return "../blips/" + f_result; //Return the cool kids variant return "sfx-blip" + f_result; //Return legacy variant } From 159f073514e2f60fd2229f21f7a536ffaddecfc2 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Thu, 21 Nov 2019 00:23:35 +0300 Subject: [PATCH 135/268] Set version to 2.8.1 woop woop --- Attorney_Online.pro | 2 +- include/aoapplication.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Attorney_Online.pro b/Attorney_Online.pro index ab61a55..97eaf51 100644 --- a/Attorney_Online.pro +++ b/Attorney_Online.pro @@ -3,7 +3,7 @@ QT += core gui widgets network TARGET = Attorney_Online TEMPLATE = app -VERSION = 2.8.0.5 +VERSION = 2.8.1.0 INCLUDEPATH += $$PWD/include DESTDIR = $$PWD/bin diff --git a/include/aoapplication.h b/include/aoapplication.h index 8dd48c6..fe1a5b7 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -396,7 +396,7 @@ public: private: const int RELEASE = 2; const int MAJOR_VERSION = 8; - const int MINOR_VERSION = 0; + const int MINOR_VERSION = 1; QString current_theme = "default"; From 07763c5ac0914d1255c4b28b29f14825ac810282 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Fri, 22 Nov 2019 00:31:17 +0300 Subject: [PATCH 136/268] actually fix the chat instead of breaking it --- src/courtroom.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 1a1fd9e..0695fe7 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1031,8 +1031,8 @@ void Courtroom::set_background(QString p_background, bool display) //Stop the chat arrow from animating ui_vp_chat_arrow->stop(); - text_state = 0; - anim_state = 0; + text_state = 2; + anim_state = 3; ui_vp_objection->stop(); chat_tick_timer->stop(); ui_vp_evidence_display->reset(); From eb014a97785db4a196d41fb38ee61612a54e0f6e Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Thu, 5 Dec 2019 22:46:26 +0300 Subject: [PATCH 137/268] Add a message delay modifier when punctuation is reached to simulate Ace Attorney 1 chat parsing (replicating the effect where characters would make a short pause, as if saying the line out loud) TODO: Make this a configurable thing --- include/courtroom.h | 6 ++++++ src/courtroom.cpp | 9 ++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/include/courtroom.h b/include/courtroom.h index ea84122..6bca28e 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -332,6 +332,12 @@ private: //the amount of time non-animated witness testimony/cross-examination images stay onscreen for in ms const int wtce_stay_time = 1500; + //characters we consider punctuation + const QString punctuation_chars = ".,?!:;"; + + //amount by which we multiply the delay when we parse punctuation chars + const int punctuation_modifier = 3; + static const int chatmessage_size = 30; QString m_chatmessage[chatmessage_size]; bool chatmessage_is_empty = false; diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 0695fe7..f4f513a 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -2638,6 +2638,7 @@ void Courtroom::chat_tick() } else { + int msg_delay = message_display_speed[current_display_speed]; //Do the colors, gradual showing, etc. in here ui_vp_message->setHtml(additive_previous + filter_ic_text(f_message, true, tick_pos, m_chatmessage[TEXT_COLOR].toInt())); @@ -2667,6 +2668,12 @@ void Courtroom::chat_tick() ++blip_ticker; } + //Punctuation delayer + if (punctuation_chars.contains(f_character)) + { + msg_delay *= punctuation_modifier; + } + //If this color is talking if (color_is_talking && anim_state != 2 && anim_state < 4) //Set it to talking as we're not on that already (though we have to avoid interrupting a non-interrupted preanim) { @@ -2681,7 +2688,7 @@ void Courtroom::chat_tick() anim_state = 3; } //Continue ticking - chat_tick_timer->start(message_display_speed[current_display_speed]); + chat_tick_timer->start(msg_delay); } } From d7e1ebeb0cd149036eeafb6452499667f7f876ff Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Fri, 6 Dec 2019 16:50:46 +0300 Subject: [PATCH 138/268] Update readme with wiki link --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0b0da92..cccd985 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ # Attorney Online [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 Wiki for more information. + +## [Refer to the Wiki](https://github.com/Crystalwarrior/KFO-Client/wiki) for more information. --- From 819d0911715065dc0d908964888a57a3f7164180 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Fri, 27 Dec 2019 01:04:48 +0300 Subject: [PATCH 139/268] UGH I BROKE BACKWARDS COMPATIBILITY NOW I'M SCRAMBLING TO FIX IT --- src/courtroom.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index f4f513a..12673ef 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -3850,12 +3850,11 @@ void Courtroom::music_list_collapse_all() void Courtroom::on_area_list_double_clicked(QTreeWidgetItem *p_item, int column) { - column = 0; //Column 0 is the area name, column 1 is the metadata - QString p_area = p_item->text(column); - + int p_area = ui_area_list->indexOfTopLevelItem(p_item); QStringList packet_contents; - packet_contents.append(p_area); + packet_contents.append(QString::number(p_area)); packet_contents.append(QString::number(m_cid)); + qDebug() << packet_contents; ao_app->send_server_packet(new AOPacket("MC", packet_contents), false); } From 7518ed8a00f57f2b850a00004d1699b4b939f79a Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Fri, 27 Dec 2019 01:20:15 +0300 Subject: [PATCH 140/268] excuse me what the fuck --- src/courtroom.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 12673ef..6faebe9 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1272,7 +1272,7 @@ void Courtroom::list_areas() { QTreeWidgetItem *treeItem = new QTreeWidgetItem(ui_area_list); treeItem->setText(0, i_area); - treeItem->setText(1, QString::number(n_area)); + treeItem->setText(1, area_list.at(n_area)); if (ao_app->arup_enabled) { @@ -3850,9 +3850,11 @@ void Courtroom::music_list_collapse_all() void Courtroom::on_area_list_double_clicked(QTreeWidgetItem *p_item, int column) { - int p_area = ui_area_list->indexOfTopLevelItem(p_item); + column = 1; //The metadata + QString p_area = p_item->text(1); + QStringList packet_contents; - packet_contents.append(QString::number(p_area)); + packet_contents.append(p_area); packet_contents.append(QString::number(m_cid)); qDebug() << packet_contents; ao_app->send_server_packet(new AOPacket("MC", packet_contents), false); From 59e8a72a50433e54817a5684be229d3a43bd508e Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sat, 28 Dec 2019 05:47:33 +0300 Subject: [PATCH 141/268] Allow colors in server chatlogs --- src/courtroom.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 6faebe9..b2482ad 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -2296,7 +2296,7 @@ void Courtroom::append_ic_text(QString p_text, QString p_name, bool is_songchang const int old_scrollbar_value = ui_ic_chatlog->verticalScrollBar()->value(); if (!is_songchange) - p_text = filter_ic_text(p_text, false); + p_text = filter_ic_text(p_text, true, -1, m_chatmessage[TEXT_COLOR].toInt()); if (log_goes_downwards) { @@ -2322,7 +2322,7 @@ void Courtroom::append_ic_text(QString p_text, QString p_name, bool is_songchang else { ui_ic_chatlog->textCursor().insertText(": ", normal); - ui_ic_chatlog->textCursor().insertText(p_text, normal); + ui_ic_chatlog->textCursor().insertHtml(p_text); } // If we got too many blocks in the current log, delete some from the top. From 8791109c6609e9b188b74f3b879501081312dab8 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Fri, 3 Jan 2020 22:34:22 +0300 Subject: [PATCH 142/268] Remove borders for chatlogs --- src/courtroom.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index b2482ad..937cfc5 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -547,10 +547,13 @@ void Courtroom::set_widgets() ui_vp_objection->combo_resize(ui_viewport->width(), ui_viewport->height()); set_size_and_pos(ui_ic_chatlog, "ic_chatlog"); + ui_ic_chatlog->setFrameShape(QFrame::NoFrame); set_size_and_pos(ui_ms_chatlog, "ms_chatlog"); + ui_ms_chatlog->setFrameShape(QFrame::NoFrame); set_size_and_pos(ui_server_chatlog, "server_chatlog"); + ui_server_chatlog->setFrameShape(QFrame::NoFrame); set_size_and_pos(ui_mute_list, "mute_list"); ui_mute_list->hide(); From f30013f7f9d9ecb840948b99663e8b1e81a6971c Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Wed, 15 Jan 2020 16:06:27 +0300 Subject: [PATCH 143/268] i am REtArd Fixed a major bug that crashed the clients on chatting + broke a lot of assets because of a single `.` boi anywhere in the filepath. --- src/aocharmovie.cpp | 3 +++ src/text_file_functions.cpp | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/aocharmovie.cpp b/src/aocharmovie.cpp index 9bbb876..0ce5c86 100644 --- a/src/aocharmovie.cpp +++ b/src/aocharmovie.cpp @@ -50,6 +50,9 @@ void AOCharMovie::load_image(QString p_char, QString p_emote, QString emote_pref movie_delays.clear(); movie_effects.clear(); + if (!file_exists(emote_path)) + return; + m_reader->setFileName(emote_path); QPixmap f_pixmap = this->get_pixmap(m_reader->read()); int f_delay = m_reader->nextImageDelay(); diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index 783c83b..2c9d5e9 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -527,7 +527,7 @@ QString AOApplication::get_sfx(QString p_identifier) QString AOApplication::get_sfx_suffix(QString sound_to_check) { - if (sound_to_check.contains(".")) //We have what we could call a file extension + if (file_exists(sound_to_check)) return sound_to_check; if (file_exists(sound_to_check + ".opus")) return sound_to_check + ".opus"; @@ -542,7 +542,7 @@ QString AOApplication::get_sfx_suffix(QString sound_to_check) QString AOApplication::get_image_suffix(QString path_to_check) { - if (path_to_check.contains(".")) //We have what we could call a file extension + if (file_exists(path_to_check)) return path_to_check; if (file_exists(path_to_check + ".webp")) return path_to_check + ".webp"; From 6138bb107b5ab4d882e9ceb75e1394c2b8ec82a3 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Wed, 15 Jan 2020 16:42:44 +0300 Subject: [PATCH 144/268] Separate screenshake options button from effects options button Add a color logging option button Update version to 2.8.2 --- Attorney_Online.pro | 2 +- include/aoapplication.h | 14 +++++++++--- include/aooptionsdialog.h | 9 ++++++-- src/aooptionsdialog.cpp | 45 +++++++++++++++++++++++++++++-------- src/courtroom.cpp | 17 ++++++++------ src/text_file_functions.cpp | 16 +++++++++++-- 6 files changed, 79 insertions(+), 24 deletions(-) diff --git a/Attorney_Online.pro b/Attorney_Online.pro index 97eaf51..cb6727f 100644 --- a/Attorney_Online.pro +++ b/Attorney_Online.pro @@ -3,7 +3,7 @@ QT += core gui widgets network TARGET = Attorney_Online TEMPLATE = app -VERSION = 2.8.1.0 +VERSION = 2.8.2.0 INCLUDEPATH += $$PWD/include DESTDIR = $$PWD/bin diff --git a/include/aoapplication.h b/include/aoapplication.h index fe1a5b7..0ab6831 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -172,14 +172,22 @@ public: // from the config.ini. bool is_discord_enabled(); - // Returns the value of whether shaking and flashing should be enabled. + // Returns the value of whether shaking should be enabled. // from the config.ini. - bool is_shake_flash_enabled(); + bool is_shake_enabled(); + + // Returns the value of whether effects should be enabled. + // from the config.ini. + bool is_effects_enabled(); // Returns the value of whether frame-specific effects defined in char.ini should be sent/received over the network. // from the config.ini. bool is_frame_network_enabled(); + // Returns the value of whether colored ic log should be a thing. + // from the config.ini. + bool is_colorlog_enabled(); + // Returns the value of the maximum amount of lines the IC chatlog // may contain, from config.ini. int get_max_log_size(); @@ -396,7 +404,7 @@ public: private: const int RELEASE = 2; const int MAJOR_VERSION = 8; - const int MINOR_VERSION = 1; + const int MINOR_VERSION = 2; QString current_theme = "default"; diff --git a/include/aooptionsdialog.h b/include/aooptionsdialog.h index 5198410..9e34e65 100644 --- a/include/aooptionsdialog.h +++ b/include/aooptionsdialog.h @@ -65,11 +65,16 @@ private: QLabel *ui_language_label; QComboBox *ui_language_combobox; - QLabel *ui_epilepsy_lbl; - QCheckBox *ui_epilepsy_cb; + QLabel *ui_shake_lbl; + QCheckBox *ui_shake_cb; + QLabel *ui_effects_lbl; + QCheckBox *ui_effects_cb; QLabel *ui_framenetwork_lbl; QCheckBox *ui_framenetwork_cb; + QLabel *ui_colorlog_lbl; + QCheckBox *ui_colorlog_cb; + QWidget *ui_callwords_tab; QWidget *ui_callwords_widget; QVBoxLayout *ui_callwords_layout; diff --git a/src/aooptionsdialog.cpp b/src/aooptionsdialog.cpp index 37694e4..ad1042f 100644 --- a/src/aooptionsdialog.cpp +++ b/src/aooptionsdialog.cpp @@ -195,16 +195,28 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_language_combobox); row += 1; - ui_epilepsy_lbl = new QLabel(ui_form_layout_widget); - ui_epilepsy_lbl->setText(tr("Allow Shake/Flash:")); - ui_epilepsy_lbl->setToolTip(tr("Allows screenshaking and flashing. Disable this if you have concerns or issues with photosensitivity and/or seizures.")); + ui_shake_lbl = new QLabel(ui_form_layout_widget); + ui_shake_lbl->setText(tr("Allow Screenshake:")); + ui_shake_lbl->setToolTip(tr("Allows screenshaking. Disable this if you have concerns or issues with photosensitivity and/or seizures.")); - ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_epilepsy_lbl); + ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_shake_lbl); - ui_epilepsy_cb = new QCheckBox(ui_form_layout_widget); - ui_epilepsy_cb->setChecked(ao_app->is_shake_flash_enabled()); + ui_shake_cb = new QCheckBox(ui_form_layout_widget); + ui_shake_cb->setChecked(ao_app->is_shake_enabled()); - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_epilepsy_cb); + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_shake_cb); + + row += 1; + ui_effects_lbl = new QLabel(ui_form_layout_widget); + ui_effects_lbl->setText(tr("Allow Effects:")); + ui_effects_lbl->setToolTip(tr("Allows screen effects. Disable this if you have concerns or issues with photosensitivity and/or seizures.")); + + ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_effects_lbl); + + ui_effects_cb = new QCheckBox(ui_form_layout_widget); + ui_effects_cb->setChecked(ao_app->is_effects_enabled()); + + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_effects_cb); row += 1; ui_framenetwork_lbl = new QLabel(ui_form_layout_widget); @@ -214,10 +226,22 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_framenetwork_lbl); ui_framenetwork_cb = new QCheckBox(ui_form_layout_widget); - ui_framenetwork_cb->setChecked(ao_app->is_shake_flash_enabled()); + ui_framenetwork_cb->setChecked(ao_app->is_frame_network_enabled()); ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_framenetwork_cb); + row += 1; + ui_colorlog_lbl = new QLabel(ui_form_layout_widget); + ui_colorlog_lbl->setText(tr("Colors in IC Log:")); + ui_colorlog_lbl->setToolTip(tr("Use the markup colors in the server IC chatlog.")); + + ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_colorlog_lbl); + + ui_colorlog_cb = new QCheckBox(ui_form_layout_widget); + ui_colorlog_cb->setChecked(ao_app->is_colorlog_enabled()); + + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_colorlog_cb); + QScrollArea *scroll = new QScrollArea; scroll->setWidget(ui_form_layout_widget); ui_gameplay_tab->setLayout(new QVBoxLayout); @@ -571,8 +595,11 @@ void AOOptionsDialog::save_pressed() configini->setValue("master", ui_ms_textbox->text()); configini->setValue("discord", ui_discord_cb->isChecked()); configini->setValue("language", ui_language_combobox->currentText().left(2)); - configini->setValue("shakeandflash", ui_epilepsy_cb->isChecked()); + configini->setValue("shake", ui_shake_cb->isChecked()); + configini->setValue("effects", ui_effects_cb->isChecked()); configini->setValue("framenetwork", ui_framenetwork_cb->isChecked()); + configini->setValue("colorlog", ui_colorlog_cb->isChecked()); + QFile* callwordsini = new QFile(ao_app->get_base_path() + "callwords.ini"); diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 937cfc5..283611f 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1889,7 +1889,7 @@ void Courtroom::handle_chatmessage_2() void Courtroom::do_screenshake() { - if(!ao_app->is_shake_flash_enabled()) + if(!ao_app->is_shake_enabled()) return; //This way, the animation is reset in such a way that last played screenshake would return to its "final frame" properly. @@ -1935,7 +1935,7 @@ void Courtroom::do_screenshake() void Courtroom::do_flash() { - if(!ao_app->is_shake_flash_enabled()) + if(!ao_app->is_effects_enabled()) return; QString f_char = m_chatmessage[CHAR_NAME]; @@ -1945,17 +1945,20 @@ void Courtroom::do_flash() void Courtroom::do_effect(QString fx_name, QString fx_sound, QString p_char) { - if(!ao_app->is_shake_flash_enabled()) - return; QString effect = ao_app->get_effect(fx_name, p_char); if (effect == "") return; - ui_vp_effect->set_play_once(false); // The effects themselves dictate whether or not they're looping. Static effects will linger. - ui_vp_effect->play(effect); // It will set_play_once to true if the filepath provided is not designed to loop more than once if (fx_sound != "") sfx_player->play(fx_sound); + + //Only check if effects are disabled after playing the sound if it exists + if(!ao_app->is_effects_enabled()) + return; + + ui_vp_effect->set_play_once(false); // The effects themselves dictate whether or not they're looping. Static effects will linger. + ui_vp_effect->play(effect); // It will set_play_once to true if the filepath provided is not designed to loop more than once } void Courtroom::play_char_sfx(QString sfx_name) @@ -2299,7 +2302,7 @@ void Courtroom::append_ic_text(QString p_text, QString p_name, bool is_songchang const int old_scrollbar_value = ui_ic_chatlog->verticalScrollBar()->value(); if (!is_songchange) - p_text = filter_ic_text(p_text, true, -1, m_chatmessage[TEXT_COLOR].toInt()); + p_text = filter_ic_text(p_text, ao_app->is_colorlog_enabled(), -1, m_chatmessage[TEXT_COLOR].toInt()); if (log_goes_downwards) { diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index 2c9d5e9..bb5d7de 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -960,9 +960,15 @@ bool AOApplication::is_discord_enabled() return result.startsWith("true"); } -bool AOApplication::is_shake_flash_enabled() +bool AOApplication::is_shake_enabled() { - QString result = configini->value("shakeandflash", "true").value(); + QString result = configini->value("shake", "true").value(); + return result.startsWith("true"); +} + +bool AOApplication::is_effects_enabled() +{ + QString result = configini->value("effects", "true").value(); return result.startsWith("true"); } @@ -972,6 +978,12 @@ bool AOApplication::is_frame_network_enabled() return result.startsWith("true"); } +bool AOApplication::is_colorlog_enabled() +{ + QString result = configini->value("colorlog", "true").value(); + return result.startsWith("true"); +} + bool AOApplication::get_casing_enabled() { QString result = configini->value("casing_enabled", "false").value(); From 43c4e3e9d703a0b7d48b634d6970906dcb5709b2 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Fri, 17 Jan 2020 18:41:27 +0300 Subject: [PATCH 145/268] Network effects folder so you don't need to modify your own char.ini to see custom effects --- include/aoapplication.h | 2 +- include/courtroom.h | 2 +- src/courtroom.cpp | 19 ++++++++++++++----- src/text_file_functions.cpp | 7 +++++-- 4 files changed, 21 insertions(+), 9 deletions(-) diff --git a/include/aoapplication.h b/include/aoapplication.h index 0ab6831..9f11087 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -317,7 +317,7 @@ public: QStringList get_effects(QString p_char); //t - QString get_effect(QString effect, QString p_char); + QString get_effect(QString effect, QString p_char, QString p_folder); //Return the effect sound associated with the fx_name in the misc/effects//sounds.ini, or theme/effects/sounds.ini. QString get_effect_sound(QString fx_name, QString p_char); diff --git a/include/courtroom.h b/include/courtroom.h index 6bca28e..d204417 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -625,7 +625,7 @@ public slots: void preanim_done(); void do_screenshake(); void do_flash(); - void do_effect(QString fx_path, QString fx_sound, QString p_char); + void do_effect(QString fx_path, QString fx_sound, QString p_char, QString p_folder); void play_char_sfx(QString sfx_name); void mod_called(QString p_ip); diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 283611f..81e043e 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1,4 +1,4 @@ -#include "courtroom.h" +#include "courtroom.h" Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() @@ -1545,7 +1545,8 @@ void Courtroom::on_chat_return_pressed() if (ao_app->effects_enabled) { QString fx_sound = ao_app->get_effect_sound(effect, current_char); - packet_contents.append(effect + "|" + fx_sound); + QString p_effect = ao_app->read_char_ini(current_char, "effects", "Options"); + packet_contents.append(effect + "|" + p_effect + "|" + fx_sound); ui_effects_dropdown->blockSignals(true); ui_effects_dropdown->setCurrentIndex(0); ui_effects_dropdown->blockSignals(false); @@ -1943,10 +1944,10 @@ void Courtroom::do_flash() ui_vp_effect->play("realizationflash", f_char, f_custom_theme, 60); } -void Courtroom::do_effect(QString fx_name, QString fx_sound, QString p_char) +void Courtroom::do_effect(QString fx_name, QString fx_sound, QString p_char, QString p_folder) { - QString effect = ao_app->get_effect(fx_name, p_char); + QString effect = ao_app->get_effect(fx_name, p_char, p_folder); if (effect == "") return; @@ -2458,10 +2459,18 @@ void Courtroom::start_chat_ticking() QStringList fx_list = m_chatmessage[EFFECTS].split("|"); QString fx = fx_list[0]; QString fx_sound; + QString fx_folder; + if (fx_list.length() > 1) fx_sound = fx_list[1]; - this->do_effect(fx, fx_sound, m_chatmessage[CHAR_NAME]); + if (fx_list.length() > 2) + { + fx_folder = fx_list[1]; + fx_sound = fx_list[2]; + } + + this->do_effect(fx, fx_sound, m_chatmessage[CHAR_NAME], fx_folder); } else if (m_chatmessage[REALIZATION] == "1") { diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index bb5d7de..49bf61f 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -885,9 +885,12 @@ QStringList AOApplication::get_effects(QString p_char) return effects; } -QString AOApplication::get_effect(QString effect, QString p_char) +QString AOApplication::get_effect(QString effect, QString p_char, QString p_folder) { - QString p_effect = read_char_ini(p_char, "effects", "Options"); + 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)); From 9df7b9648ae1bd694f99fa6748eee547752b6c9c Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Thu, 20 Feb 2020 00:32:37 +0300 Subject: [PATCH 146/268] Remove QtApng dependency --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index cccd985..4dc6956 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,6 @@ The traditional route is by undergoing the [AO2 Rite of Passage](https://gist.gi ### Dependencies -- [QtApng](https://github.com/Skycoder42/QtApng) - [BASS](http://un4seen.com) (proprietary, but will become optional in the future; see #35) - [Discord Rich Presence](https://github.com/discordapp/discord-rpc) From a4e448576b43b9cf4f984253abb3daf7296aa154 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Mon, 24 Feb 2020 22:20:43 +0300 Subject: [PATCH 147/268] Make pos dropdown more abstract and actually useful by letting servers send only pos you can actually access. Pos dropdown system also reads the actual bg folder of the current BG to see all the created pos. --- include/courtroom.h | 6 +++ src/courtroom.cpp | 79 +++++++++++++++++-------------------- src/packet_distribution.cpp | 9 +++++ 3 files changed, 51 insertions(+), 43 deletions(-) diff --git a/include/courtroom.h b/include/courtroom.h index d204417..417d455 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -159,6 +159,9 @@ public: //sets the local character pos/side to use. void set_side(QString p_side); + //sets the pos dropdown + void set_pos_dropdown(QStringList pos_dropdowns); + //sets the evidence list member variable to argument void set_evidence_list(QVector &p_evi_list); @@ -394,6 +397,9 @@ private: QVector color_markdown_talking_list; //Text Color-related optimization END + //List of all currently available pos + QStringList pos_dropdown_list; + bool is_presenting_evidence = false; QString effect = ""; diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 81e043e..ea6f165 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -180,14 +180,6 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() initialize_emotes(); ui_pos_dropdown = new QComboBox(this); - ui_pos_dropdown->addItem("wit"); - ui_pos_dropdown->addItem("def"); - ui_pos_dropdown->addItem("pro"); - ui_pos_dropdown->addItem("jud"); - ui_pos_dropdown->addItem("hld"); - ui_pos_dropdown->addItem("hlp"); - ui_pos_dropdown->addItem("jur"); - ui_pos_dropdown->addItem("sea"); ui_iniswap_dropdown = new QComboBox(this); ui_iniswap_dropdown->setContextMenuPolicy(Qt::CustomContextMenu); @@ -1005,10 +997,32 @@ void Courtroom::set_background(QString p_background, bool display) ui_vp_testimony->stop(); current_background = p_background; + //welcome to hardcode central may I take your order of regularly scheduled CBT + QMap default_pos; + default_pos["defenseempty"] = "def"; + default_pos["helperstand"] = "hld"; + default_pos["prosecutorempty"] = "pro"; + default_pos["prohelperstand"] = "hlp"; + default_pos["witnessempty"] = "wit"; + default_pos["judgestand"] = "jud"; + default_pos["jurystand"] = "jur"; + default_pos["seancestand"] = "sea"; + + //Populate the dropdown list with all pos that exist on this bg + QStringList pos_list = {}; + for (QString key : default_pos.keys()) + { + if (file_exists(ao_app->get_static_image_suffix(ao_app->get_background_path(key)))) + { + pos_list.append(default_pos[key]); + } + } + + //TODO: search through extra/custom pos and add them to the pos dropdown as well + + set_pos_dropdown(pos_list); + is_ao2_bg = true; -// file_exists(ao_app->get_static_image_suffix(ao_app->get_background_path("defensedesk"))) && -// file_exists(ao_app->get_static_image_suffix(ao_app->get_background_path("prosecutiondesk"))) && -// file_exists(ao_app->get_static_image_suffix(ao_app->get_background_path("stand"))); if (is_ao2_bg) { @@ -1070,6 +1084,13 @@ void Courtroom::set_side(QString p_side) } } +void Courtroom::set_pos_dropdown(QStringList pos_dropdowns) +{ + pos_dropdown_list = pos_dropdowns; + ui_pos_dropdown->clear(); + ui_pos_dropdown->addItems(pos_dropdown_list); + qDebug() << pos_dropdown_list; +} void Courtroom::update_character(int p_cid) { @@ -3336,42 +3357,14 @@ void Courtroom::on_pos_dropdown_changed(int p_index) toggle_judge_buttons(false); - QString f_pos; - - switch (p_index) - { - case 0: - f_pos = "wit"; - break; - case 1: - f_pos = "def"; - break; - case 2: - f_pos = "pro"; - break; - case 3: - f_pos = "jud"; - toggle_judge_buttons(true); - break; - case 4: - f_pos = "hld"; - break; - case 5: - f_pos = "hlp"; - break; - case 6: - f_pos = "jur"; - break; - case 7: - f_pos = "sea"; - break; - default: - f_pos = ""; - } + QString f_pos = ui_pos_dropdown->itemText(p_index); if (f_pos == "") return; + if (f_pos == "jud") + toggle_judge_buttons(true); + //YEAH SENDING LIKE 20 PACKETS IF THE USER SCROLLS THROUGH, GREAT IDEA //how about this instead set_side(f_pos); diff --git a/src/packet_distribution.cpp b/src/packet_distribution.cpp index 8c74b76..2305083 100644 --- a/src/packet_distribution.cpp +++ b/src/packet_distribution.cpp @@ -595,7 +595,16 @@ void AOApplication::server_packet_received(AOPacket *p_packet) goto end; if (courtroom_constructed) //We were sent a "set position" packet + { w_courtroom->set_side(f_contents.at(0)); + } + } + else if (header == "SD") //Send pos dropdown + { + if (f_contents.size() < 1) + goto end; + + w_courtroom->set_pos_dropdown(f_contents.at(0).split("*")); } //server accepting char request(CC) packet else if (header == "PV") From 39f9d1043e7f362275a189d71066ca642753f86f Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Thu, 5 Mar 2020 21:23:42 +0300 Subject: [PATCH 148/268] Add sorting by name for lobby --- include/lobby.h | 9 +++--- src/lobby.cpp | 77 ++++++++++++++++++++++++++++++------------------- 2 files changed, 53 insertions(+), 33 deletions(-) diff --git a/include/lobby.h b/include/lobby.h index e0cd03d..4b95fb2 100644 --- a/include/lobby.h +++ b/include/lobby.h @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -64,7 +65,7 @@ private: QLabel *ui_version; AOButton *ui_about; - QListWidget *ui_server_list; + QTreeWidget *ui_server_list; QLabel *ui_player_count; AOTextArea *ui_description; @@ -79,7 +80,7 @@ private: QProgressBar *ui_progress_bar; AOButton *ui_cancel; - QModelIndex last_model; + int last_index; void set_size_and_pos(QWidget *p_widget, QString p_identifier); @@ -94,8 +95,8 @@ private slots: void on_connect_pressed(); void on_connect_released(); void on_about_clicked(); - void on_server_list_clicked(QModelIndex p_model); - void on_server_list_doubleclicked(QModelIndex p_model); + void on_server_list_clicked(QTreeWidgetItem* p_item, int column); + void on_server_list_doubleclicked(QTreeWidgetItem* p_item, int column); void on_chatfield_return_pressed(); }; diff --git a/src/lobby.cpp b/src/lobby.cpp index 7c61aa7..2203337 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -20,7 +20,11 @@ Lobby::Lobby(AOApplication *p_ao_app) : QMainWindow() ui_connect = new AOButton(this, ao_app); ui_version = new QLabel(this); ui_about = new AOButton(this, ao_app); - ui_server_list = new QListWidget(this); + + ui_server_list = new QTreeWidget(this); + ui_server_list->setHeaderLabels({"#", "Name"});//, "Players"}); + ui_server_list->hideColumn(0); + ui_player_count = new QLabel(this); ui_description = new AOTextArea(this); ui_description->setOpenExternalLinks(true); @@ -47,8 +51,8 @@ Lobby::Lobby(AOApplication *p_ao_app) : QMainWindow() connect(ui_connect, SIGNAL(pressed()), this, SLOT(on_connect_pressed())); connect(ui_connect, SIGNAL(released()), this, SLOT(on_connect_released())); connect(ui_about, SIGNAL(clicked()), this, SLOT(on_about_clicked())); - connect(ui_server_list, SIGNAL(clicked(QModelIndex)), this, SLOT(on_server_list_clicked(QModelIndex))); - connect(ui_server_list, SIGNAL(activated(QModelIndex)), this, SLOT(on_server_list_doubleclicked(QModelIndex))); + connect(ui_server_list, SIGNAL(itemClicked(QTreeWidgetItem*, int)), this, SLOT(on_server_list_clicked(QTreeWidgetItem*, int))); + connect(ui_server_list, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this, SLOT(on_server_list_doubleclicked(QTreeWidgetItem*, int))); connect(ui_chatmessage, SIGNAL(returnPressed()), this, SLOT(on_chatfield_return_pressed())); connect(ui_cancel, SIGNAL(clicked()), ao_app, SLOT(loading_cancelled())); @@ -252,7 +256,7 @@ QString Lobby::get_chatlog() int Lobby::get_selected_server() { - return ui_server_list->currentRow(); + return ui_server_list->currentItem()->text(0).toInt(); } void Lobby::set_loading_value(int p_value) @@ -310,7 +314,7 @@ void Lobby::on_add_to_fav_released() if (!public_servers_selected) return; - ao_app->add_favorite_server(ui_server_list->currentRow()); + ao_app->add_favorite_server(get_selected_server()); } void Lobby::on_connect_pressed() @@ -355,32 +359,33 @@ void Lobby::on_about_clicked() } //clicked on an item in the serverlist -void Lobby::on_server_list_clicked(QModelIndex p_model) +void Lobby::on_server_list_clicked(QTreeWidgetItem* p_item, int column) { - if (p_model != last_model) + column = 0; + if (p_item->text(column).toInt() != last_index) { - server_type f_server; - last_model = p_model; - int n_server = p_model.row(); + server_type f_server; + int n_server = p_item->text(column).toInt(); + last_index = n_server; - if (n_server < 0) - return; - - if (public_servers_selected) - { - QVector f_server_list = ao_app->get_server_list(); - - if (n_server >= f_server_list.size()) + if (n_server < 0) return; - f_server = f_server_list.at(p_model.row()); - } - else - { - if (n_server >= ao_app->get_favorite_list().size()) - return; + if (public_servers_selected) + { + QVector f_server_list = ao_app->get_server_list(); - f_server = ao_app->get_favorite_list().at(p_model.row()); + if (n_server >= f_server_list.size()) + return; + + f_server = f_server_list.at(n_server); + } + else + { + if (n_server >= ao_app->get_favorite_list().size()) + return; + + f_server = ao_app->get_favorite_list().at(n_server); } ui_description->clear(); @@ -398,9 +403,9 @@ void Lobby::on_server_list_clicked(QModelIndex p_model) } //doubleclicked on an item in the serverlist so we'll connect right away -void Lobby::on_server_list_doubleclicked(QModelIndex p_model) +void Lobby::on_server_list_doubleclicked(QTreeWidgetItem* p_item, int column) { - on_server_list_clicked(p_model); + on_server_list_clicked(p_item, column); on_connect_released(); } @@ -427,22 +432,36 @@ void Lobby::list_servers() ui_favorites->set_image("favorites"); ui_public_servers->set_image("publicservers_selected"); + ui_server_list->setSortingEnabled(false); ui_server_list->clear(); + int i = 0; for (server_type i_server : ao_app->get_server_list()) { - ui_server_list->addItem(i_server.name); + QTreeWidgetItem *treeItem = new QTreeWidgetItem(ui_server_list); + treeItem->setText(0, QString::number(i)); + treeItem->setText(1, i_server.name); +// treeItem->setText(2, "-"); + i++; } + ui_server_list->setSortingEnabled(true); } void Lobby::list_favorites() { + ui_server_list->setSortingEnabled(false); ui_server_list->clear(); + int i = 0; for (server_type i_server : ao_app->get_favorite_list()) { - ui_server_list->addItem(i_server.name); + QTreeWidgetItem *treeItem = new QTreeWidgetItem(ui_server_list); + treeItem->setText(0, QString(i)); + treeItem->setText(1, i_server.name); +// treeItem->setText(2, "-"); + i++; } + ui_server_list->setSortingEnabled(true); } void Lobby::append_chatmessage(QString f_name, QString f_message) From ee9de222ad9c1c4ebf2e6a1acc2cf5d2fc9dd77c Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Fri, 6 Mar 2020 01:14:05 +0300 Subject: [PATCH 149/268] Fix a bug where you couldn't join servers from your favorites list Make column 0 the area index instead so that the areas take the full width of the treewidget --- src/courtroom.cpp | 20 ++++++++++---------- src/lobby.cpp | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index ea6f165..3b0d0f5 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -126,7 +126,7 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_area_list = new QTreeWidget(this); ui_area_list->setColumnCount(2); - ui_area_list->hideColumn(1); + ui_area_list->hideColumn(0); ui_area_list->setHeaderHidden(true); ui_area_list->header()->setStretchLastSection(false); ui_area_list->header()->setSectionResizeMode(QHeaderView::ResizeToContents); @@ -1295,8 +1295,8 @@ void Courtroom::list_areas() if (i_area.toLower().contains(ui_music_search->text().toLower())) { QTreeWidgetItem *treeItem = new QTreeWidgetItem(ui_area_list); - treeItem->setText(0, i_area); - treeItem->setText(1, area_list.at(n_area)); + treeItem->setText(0, area_list.at(n_area)); + treeItem->setText(1, i_area); if (ao_app->arup_enabled) { @@ -1304,25 +1304,25 @@ void Courtroom::list_areas() treeItem->setBackground(0, free_brush); if (arup_locks.at(n_area) == "LOCKED") { - treeItem->setBackground(0, locked_brush); + treeItem->setBackground(1, locked_brush); } else { if (arup_statuses.at(n_area) == "LOOKING-FOR-PLAYERS") - treeItem->setBackground(0, lfp_brush); + treeItem->setBackground(1, lfp_brush); else if (arup_statuses.at(n_area) == "CASING") - treeItem->setBackground(0, casing_brush); + treeItem->setBackground(1, casing_brush); else if (arup_statuses.at(n_area) == "RECESS") - treeItem->setBackground(0, recess_brush); + treeItem->setBackground(1, recess_brush); else if (arup_statuses.at(n_area) == "RP") - treeItem->setBackground(0, rp_brush); + treeItem->setBackground(1, rp_brush); else if (arup_statuses.at(n_area) == "GAMING") - treeItem->setBackground(0, gaming_brush); + treeItem->setBackground(1, gaming_brush); } } else { - treeItem->setBackground(0, free_brush); + treeItem->setBackground(1, free_brush); } ++n_listed_areas; diff --git a/src/lobby.cpp b/src/lobby.cpp index 2203337..8c67245 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -456,7 +456,7 @@ void Lobby::list_favorites() for (server_type i_server : ao_app->get_favorite_list()) { QTreeWidgetItem *treeItem = new QTreeWidgetItem(ui_server_list); - treeItem->setText(0, QString(i)); + treeItem->setText(0, QString::number(i)); treeItem->setText(1, i_server.name); // treeItem->setText(2, "-"); i++; From e4b90d36a90e4601df23b5634aa5ad123d8f6424 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Fri, 6 Mar 2020 23:29:26 +0300 Subject: [PATCH 150/268] Fix the rightclick options for editing files not working --- src/courtroom.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 3b0d0f5..f22c853 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -3446,7 +3446,7 @@ void Courtroom::on_iniswap_edit_requested() QString p_path = ao_app->get_character_path(current_char, "char.ini"); if (!file_exists(p_path)) return; - QDesktopServices::openUrl(QUrl(p_path)); + QDesktopServices::openUrl(QUrl::fromLocalFile(p_path)); } void Courtroom::on_iniswap_remove_clicked() @@ -3558,7 +3558,7 @@ void Courtroom::on_sfx_edit_requested() } } } - QDesktopServices::openUrl(QUrl(p_path)); + QDesktopServices::openUrl(QUrl::fromLocalFile(p_path)); } void Courtroom::on_sfx_remove_clicked() @@ -3644,7 +3644,7 @@ void Courtroom::on_effects_edit_requested() return; } } - QDesktopServices::openUrl(QUrl(p_path)); + QDesktopServices::openUrl(QUrl::fromLocalFile(p_path)); } void Courtroom::on_character_effects_edit_requested() { @@ -3653,7 +3653,7 @@ void Courtroom::on_character_effects_edit_requested() if (!dir_exists(p_path)) return; - QDesktopServices::openUrl(QUrl(p_path)); + QDesktopServices::openUrl(QUrl::fromLocalFile(p_path)); } void Courtroom::on_effects_dropdown_changed(int p_index) From 9b8f60061aebae849f5325189d5baf36db0c8c99 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sun, 8 Mar 2020 17:40:52 +0300 Subject: [PATCH 151/268] The Crispy:tm: update Make it so BG's and Characters will not be blurred when rescaled TODO: Make Qmovies ditch anti-aliasing during scaling as well Only apply crispy scaling if the size is 2x of the previous size or something --- src/aocharmovie.cpp | 4 +++- src/aoscene.cpp | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/aocharmovie.cpp b/src/aocharmovie.cpp index 0ce5c86..6cdcab2 100644 --- a/src/aocharmovie.cpp +++ b/src/aocharmovie.cpp @@ -240,7 +240,9 @@ QPixmap AOCharMovie::get_pixmap(QImage image) else f_pixmap = QPixmap::fromImage(image); // auto aspect_ratio = Qt::KeepAspectRatio; - auto transform_mode = Qt::SmoothTransformation; + auto transform_mode = Qt::FastTransformation; +// if () +// transform_mode = Qt::SmoothTransformation; f_pixmap = f_pixmap.scaledToHeight(f_h, transform_mode); this->resize(f_pixmap.size()); diff --git a/src/aoscene.cpp b/src/aoscene.cpp index 6ada5ee..32e5c35 100644 --- a/src/aoscene.cpp +++ b/src/aoscene.cpp @@ -36,7 +36,7 @@ void AOScene::set_image(QString p_image) m_movie->setFileName(background_path); m_movie->setScaledSize(QSize(w, h)); - if (m_movie->isValid()) + if (m_movie->isValid() && m_movie->frameCount() > 1) { this->setMovie(m_movie); m_movie->start(); @@ -85,7 +85,7 @@ void AOScene::set_legacy_desk(QString p_image) m_movie->setScaledSize(QSize(vp_width, final_h)); - if (m_movie->isValid()) + if (m_movie->isValid() && m_movie->frameCount() > 1) { this->setMovie(m_movie); m_movie->start(); From ce3269cc36485e44a85778b0d93b6bfc26f95eb1 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Thu, 12 Mar 2020 00:47:39 +0300 Subject: [PATCH 152/268] Only use anti-aliasing when sprites are being downscaled, otherwise preserve crispyness:tm: --- src/aocharmovie.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/aocharmovie.cpp b/src/aocharmovie.cpp index 6cdcab2..7bbdc1b 100644 --- a/src/aocharmovie.cpp +++ b/src/aocharmovie.cpp @@ -241,8 +241,8 @@ QPixmap AOCharMovie::get_pixmap(QImage image) f_pixmap = QPixmap::fromImage(image); // auto aspect_ratio = Qt::KeepAspectRatio; auto transform_mode = Qt::FastTransformation; -// if () -// transform_mode = Qt::SmoothTransformation; + if (f_pixmap.height() > f_h) //We are downscaling, use anti-aliasing. + transform_mode = Qt::SmoothTransformation; f_pixmap = f_pixmap.scaledToHeight(f_h, transform_mode); this->resize(f_pixmap.size()); From 7aa24bf50158b3a93c17c56e1371b72389238185 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Thu, 12 Mar 2020 18:09:56 +0300 Subject: [PATCH 153/268] Add a search bar for server list Add options for sticky sounds, sticky effects and sticky preanims Optimize the search for areas and music (previously, area search also searched for music in the background, causing lag with huge music lists) --- include/aoapplication.h | 12 ++++ include/aooptionsdialog.h | 9 +++ include/lobby.h | 2 + src/aooptionsdialog.cpp | 43 ++++++++++++- src/courtroom.cpp | 125 +++++++++++++++++++++++------------- src/emotes.cpp | 11 ++-- src/lobby.cpp | 35 +++++++++- src/text_file_functions.cpp | 18 ++++++ 8 files changed, 204 insertions(+), 51 deletions(-) diff --git a/include/aoapplication.h b/include/aoapplication.h index 9f11087..3ed7046 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -188,6 +188,18 @@ public: // from the config.ini. bool is_colorlog_enabled(); + // Returns the value of whether sticky sounds should be a thing. + // from the config.ini. + bool is_stickysounds_enabled(); + + // Returns the value of whether sticky effects should be a thing. + // from the config.ini. + bool is_stickyeffects_enabled(); + + // Returns the value of whether sticky preanims should be a thing. + // from the config.ini. + bool is_stickypres_enabled(); + // Returns the value of the maximum amount of lines the IC chatlog // may contain, from config.ini. int get_max_log_size(); diff --git a/include/aooptionsdialog.h b/include/aooptionsdialog.h index 9e34e65..4a63ca3 100644 --- a/include/aooptionsdialog.h +++ b/include/aooptionsdialog.h @@ -75,6 +75,15 @@ private: QLabel *ui_colorlog_lbl; QCheckBox *ui_colorlog_cb; + QLabel *ui_stickysounds_lbl; + QCheckBox *ui_stickysounds_cb; + + QLabel *ui_stickyeffects_lbl; + QCheckBox *ui_stickyeffects_cb; + + QLabel *ui_stickypres_lbl; + QCheckBox *ui_stickypres_cb; + QWidget *ui_callwords_tab; QWidget *ui_callwords_widget; QVBoxLayout *ui_callwords_layout; diff --git a/include/lobby.h b/include/lobby.h index 4b95fb2..10a7c1d 100644 --- a/include/lobby.h +++ b/include/lobby.h @@ -66,6 +66,7 @@ private: AOButton *ui_about; QTreeWidget *ui_server_list; + QLineEdit *ui_server_search; QLabel *ui_player_count; AOTextArea *ui_description; @@ -97,6 +98,7 @@ private slots: void on_about_clicked(); void on_server_list_clicked(QTreeWidgetItem* p_item, int column); void on_server_list_doubleclicked(QTreeWidgetItem* p_item, int column); + void on_server_search_edited(QString p_text); void on_chatfield_return_pressed(); }; diff --git a/src/aooptionsdialog.cpp b/src/aooptionsdialog.cpp index ad1042f..cfaaa20 100644 --- a/src/aooptionsdialog.cpp +++ b/src/aooptionsdialog.cpp @@ -12,7 +12,7 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi ui_settings_buttons = new QDialogButtonBox(this); - QSizePolicy sizePolicy1(QSizePolicy::Expanding, QSizePolicy::MinimumExpanding); + QSizePolicy sizePolicy1(QSizePolicy::Minimum, QSizePolicy::MinimumExpanding); sizePolicy1.setHorizontalStretch(0); sizePolicy1.setVerticalStretch(0); sizePolicy1.setHeightForWidth(ui_settings_buttons->sizePolicy().hasHeightForWidth()); @@ -39,7 +39,7 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi ui_gameplay_tab->setSizePolicy(sizePolicy1); ui_settings_tabs->addTab(ui_gameplay_tab, tr("Gameplay")); ui_form_layout_widget = new QWidget(ui_gameplay_tab); - ui_form_layout_widget->setGeometry(QRect(10, 10, 361, 211)); + ui_form_layout_widget->setGeometry(QRect(10, 10, 361, 361)); ui_form_layout_widget->setSizePolicy(sizePolicy1); ui_gameplay_form = new QFormLayout(ui_form_layout_widget); @@ -242,6 +242,42 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_colorlog_cb); + row += 1; + ui_stickysounds_lbl = new QLabel(ui_form_layout_widget); + ui_stickysounds_lbl->setText(tr("Sticky Sounds:")); + ui_stickysounds_lbl->setToolTip(tr("Turn this on to prevent the sound dropdown from clearing the sound after playing it.")); + + ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_stickysounds_lbl); + + ui_stickysounds_cb = new QCheckBox(ui_form_layout_widget); + ui_stickysounds_cb->setChecked(ao_app->is_stickysounds_enabled()); + + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_stickysounds_cb); + + row += 1; + ui_stickyeffects_lbl = new QLabel(ui_form_layout_widget); + ui_stickyeffects_lbl->setText(tr("Sticky Effects:")); + ui_stickyeffects_lbl->setToolTip(tr("Turn this on to prevent the effects dropdown from clearing the effect after playing it.")); + + ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_stickyeffects_lbl); + + ui_stickyeffects_cb = new QCheckBox(ui_form_layout_widget); + ui_stickyeffects_cb->setChecked(ao_app->is_stickyeffects_enabled()); + + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_stickyeffects_cb); + + row += 1; + ui_stickypres_lbl = new QLabel(ui_form_layout_widget); + ui_stickypres_lbl->setText(tr("Sticky Preanims:")); + ui_stickypres_lbl->setToolTip(tr("Turn this on to prevent preanimation checkbox from clearing after playing the emote.")); + + ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_stickypres_lbl); + + ui_stickypres_cb = new QCheckBox(ui_form_layout_widget); + ui_stickypres_cb->setChecked(ao_app->is_stickypres_enabled()); + + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_stickypres_cb); + QScrollArea *scroll = new QScrollArea; scroll->setWidget(ui_form_layout_widget); ui_gameplay_tab->setLayout(new QVBoxLayout); @@ -599,6 +635,9 @@ void AOOptionsDialog::save_pressed() configini->setValue("effects", ui_effects_cb->isChecked()); configini->setValue("framenetwork", ui_framenetwork_cb->isChecked()); configini->setValue("colorlog", ui_colorlog_cb->isChecked()); + configini->setValue("stickysounds", ui_stickysounds_cb->isChecked()); + configini->setValue("stickyeffects", ui_stickyeffects_cb->isChecked()); + configini->setValue("stickypres", ui_stickypres_cb->isChecked()); QFile* callwordsini = new QFile(ao_app->get_base_path() + "callwords.ini"); diff --git a/src/courtroom.cpp b/src/courtroom.cpp index f22c853..d35ba70 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1214,6 +1214,7 @@ void Courtroom::enter_courtroom() void Courtroom::list_music() { ui_music_list->clear(); + ui_music_search->setText(""); QString f_file = "courtroom_design.ini"; @@ -1256,6 +1257,7 @@ void Courtroom::list_music() void Courtroom::list_areas() { ui_area_list->clear(); + ui_music_search->setText(""); QString f_file = "courtroom_design.ini"; @@ -1292,41 +1294,38 @@ void Courtroom::list_areas() i_area.append(arup_locks.at(n_area)); } - if (i_area.toLower().contains(ui_music_search->text().toLower())) - { - QTreeWidgetItem *treeItem = new QTreeWidgetItem(ui_area_list); - treeItem->setText(0, area_list.at(n_area)); - treeItem->setText(1, i_area); + QTreeWidgetItem *treeItem = new QTreeWidgetItem(ui_area_list); + treeItem->setText(0, area_list.at(n_area)); + treeItem->setText(1, i_area); - if (ao_app->arup_enabled) + if (ao_app->arup_enabled) + { + // Coloring logic here. + treeItem->setBackground(0, free_brush); + if (arup_locks.at(n_area) == "LOCKED") { - // Coloring logic here. - treeItem->setBackground(0, 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); - } + 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; } + else + { + treeItem->setBackground(1, free_brush); + } + + ++n_listed_areas; } } @@ -1412,6 +1411,13 @@ void Courtroom::on_chat_return_pressed() packet_contents.append(current_side); packet_contents.append(get_char_sfx()); + if (ui_pre->isChecked() && !ao_app->is_stickysounds_enabled()) + { + ui_sfx_dropdown->blockSignals(true); + ui_sfx_dropdown->setCurrentIndex(0); + ui_sfx_dropdown->blockSignals(false); + ui_sfx_remove->hide(); + } int f_emote_mod = ao_app->get_emote_mod(current_char, current_emote); @@ -1568,10 +1574,13 @@ void Courtroom::on_chat_return_pressed() QString fx_sound = ao_app->get_effect_sound(effect, current_char); QString p_effect = ao_app->read_char_ini(current_char, "effects", "Options"); packet_contents.append(effect + "|" + p_effect + "|" + fx_sound); - ui_effects_dropdown->blockSignals(true); - ui_effects_dropdown->setCurrentIndex(0); - ui_effects_dropdown->blockSignals(false); - effect = ""; + if (!ao_app->is_stickyeffects_enabled()) + { + ui_effects_dropdown->blockSignals(true); + ui_effects_dropdown->setCurrentIndex(0); + ui_effects_dropdown->blockSignals(false); + effect = ""; + } } ao_app->send_server_packet(new AOPacket("MS", packet_contents)); @@ -1658,7 +1667,8 @@ void Courtroom::handle_chatmessage(QStringList *p_contents) realization_state = 0; screenshake_state = 0; is_presenting_evidence = false; - ui_pre->setChecked(false); + if (!ao_app->is_stickypres_enabled()) + ui_pre->setChecked(false); ui_hold_it->set_image("holdit"); ui_objection->set_image("objection"); ui_take_that->set_image("takethat"); @@ -3327,25 +3337,52 @@ void Courtroom::on_ooc_toggle_clicked() void Courtroom::on_music_search_edited(QString p_text) { // Iterate through all QTreeWidgetItem items - QTreeWidgetItemIterator it(ui_music_list); - while (*it) + if (!ui_music_list->isHidden()) { - (*it)->setHidden(p_text != ""); - ++it; + QTreeWidgetItemIterator it(ui_music_list); + while (*it) + { + (*it)->setHidden(p_text != ""); + ++it; + } + } + + if (!ui_area_list->isHidden()) + { + QTreeWidgetItemIterator ait(ui_area_list); + while (*ait) + { + (*ait)->setHidden(p_text != ""); + ++ait; + } } if (p_text != "") { - //Search in metadata - QList clist = ui_music_list->findItems(ui_music_search->text(), Qt::MatchContains|Qt::MatchRecursive, 1); - foreach(QTreeWidgetItem* item, clist) + if (!ui_music_list->isHidden()) { - if (item->parent() != nullptr) //So the category shows up too - item->parent()->setHidden(false); - item->setHidden(false); + //Search in metadata + QList clist = ui_music_list->findItems(ui_music_search->text(), Qt::MatchContains|Qt::MatchRecursive, 1); + foreach(QTreeWidgetItem* item, clist) + { + if (item->parent() != nullptr) //So the category shows up too + item->parent()->setHidden(false); + item->setHidden(false); + } + } + + if (!ui_area_list->isHidden()) + { + //Search in metadata + QList alist = ui_area_list->findItems(ui_music_search->text(), Qt::MatchContains|Qt::MatchRecursive, 1); + foreach(QTreeWidgetItem* item, alist) + { + if (item->parent() != nullptr) //So the category shows up too + item->parent()->setHidden(false); + item->setHidden(false); + } } } - list_areas(); } void Courtroom::on_pos_dropdown_changed(int p_index) diff --git a/src/emotes.cpp b/src/emotes.cpp index de53169..1484784 100644 --- a/src/emotes.cpp +++ b/src/emotes.cpp @@ -159,10 +159,13 @@ void Courtroom::select_emote(int p_id) { ui_pre->setChecked(!ui_pre->isChecked()); } - else if (emote_mod == 1 || emote_mod == 4) - ui_pre->setChecked(true); - else - ui_pre->setChecked(false); + else if (!ao_app->is_stickypres_enabled()) + { + if (emote_mod == 1 || emote_mod == 4) + ui_pre->setChecked(true); + else + ui_pre->setChecked(false); + } ui_emote_dropdown->setCurrentIndex(current_emote); diff --git a/src/lobby.cpp b/src/lobby.cpp index 8c67245..caa0915 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -25,6 +25,10 @@ Lobby::Lobby(AOApplication *p_ao_app) : QMainWindow() ui_server_list->setHeaderLabels({"#", "Name"});//, "Players"}); ui_server_list->hideColumn(0); + ui_server_search = new QLineEdit(this); + ui_server_search->setFrame(false); + ui_server_search->setPlaceholderText(tr("Search")); + ui_player_count = new QLabel(this); ui_description = new AOTextArea(this); ui_description->setOpenExternalLinks(true); @@ -53,6 +57,7 @@ Lobby::Lobby(AOApplication *p_ao_app) : QMainWindow() connect(ui_about, SIGNAL(clicked()), this, SLOT(on_about_clicked())); connect(ui_server_list, SIGNAL(itemClicked(QTreeWidgetItem*, int)), this, SLOT(on_server_list_clicked(QTreeWidgetItem*, int))); connect(ui_server_list, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this, SLOT(on_server_list_doubleclicked(QTreeWidgetItem*, int))); + connect(ui_server_search, SIGNAL(textChanged(QString)), this, SLOT(on_server_search_edited(QString))); connect(ui_chatmessage, SIGNAL(returnPressed()), this, SLOT(on_chatfield_return_pressed())); connect(ui_cancel, SIGNAL(clicked()), ao_app, SLOT(loading_cancelled())); @@ -116,6 +121,9 @@ void Lobby::set_widgets() ui_server_list->setStyleSheet("background-color: rgba(0, 0, 0, 0);" "font: bold;"); + set_size_and_pos(ui_server_search, "server_search"); + ui_server_search->setStyleSheet("background-color: rgba(0, 0, 0, 0);"); + set_size_and_pos(ui_player_count, "player_count"); ui_player_count->setText(tr("Offline")); ui_player_count->setStyleSheet("font: bold;" @@ -409,6 +417,30 @@ void Lobby::on_server_list_doubleclicked(QTreeWidgetItem* p_item, int column) on_connect_released(); } +void Lobby::on_server_search_edited(QString p_text) +{ + // Iterate through all QTreeWidgetItem items + QTreeWidgetItemIterator it(ui_server_list); + while (*it) + { + (*it)->setHidden(p_text != ""); + ++it; + } + + if (p_text != "") + { + //Search in metadata + QList clist = ui_server_list->findItems(ui_server_search->text(), Qt::MatchContains|Qt::MatchRecursive, 1); + foreach(QTreeWidgetItem* item, clist) + { + if (item->parent() != nullptr) //So the category shows up too + item->parent()->setHidden(false); + item->setHidden(false); + } + } +} + + void Lobby::on_chatfield_return_pressed() { //no you can't send empty messages @@ -435,13 +467,14 @@ void Lobby::list_servers() ui_server_list->setSortingEnabled(false); ui_server_list->clear(); + ui_server_search->setText(""); + int i = 0; for (server_type i_server : ao_app->get_server_list()) { QTreeWidgetItem *treeItem = new QTreeWidgetItem(ui_server_list); treeItem->setText(0, QString::number(i)); treeItem->setText(1, i_server.name); -// treeItem->setText(2, "-"); i++; } ui_server_list->setSortingEnabled(true); diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index 49bf61f..432f61a 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -987,6 +987,24 @@ bool AOApplication::is_colorlog_enabled() return result.startsWith("true"); } +bool AOApplication::is_stickysounds_enabled() +{ + QString result = configini->value("stickysounds", "false").value(); + return result.startsWith("true"); +} + +bool AOApplication::is_stickyeffects_enabled() +{ + QString result = configini->value("stickyeffects", "false").value(); + return result.startsWith("true"); +} + +bool AOApplication::is_stickypres_enabled() +{ + QString result = configini->value("stickypres", "false").value(); + return result.startsWith("true"); +} + bool AOApplication::get_casing_enabled() { QString result = configini->value("casing_enabled", "false").value(); From 4c8bf57268c09c298edc3f3695e4a2ede84643ac Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Thu, 12 Mar 2020 18:34:51 +0300 Subject: [PATCH 154/268] VERSION 2.8.3 BABYYYYYYYY Add "KFO" to version display in lobby so it's even clearer this is a custom client Add a settings button to the Lobby screen --- Attorney_Online.pro | 2 +- include/aoapplication.h | 2 +- include/lobby.h | 3 +++ src/aoapplication.cpp | 2 +- src/lobby.cpp | 12 ++++++++++++ 5 files changed, 18 insertions(+), 3 deletions(-) diff --git a/Attorney_Online.pro b/Attorney_Online.pro index cb6727f..81a3304 100644 --- a/Attorney_Online.pro +++ b/Attorney_Online.pro @@ -3,7 +3,7 @@ QT += core gui widgets network TARGET = Attorney_Online TEMPLATE = app -VERSION = 2.8.2.0 +VERSION = 2.8.3.0 INCLUDEPATH += $$PWD/include DESTDIR = $$PWD/bin diff --git a/include/aoapplication.h b/include/aoapplication.h index 3ed7046..8b520bc 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -416,7 +416,7 @@ public: private: const int RELEASE = 2; const int MAJOR_VERSION = 8; - const int MINOR_VERSION = 2; + const int MINOR_VERSION = 3; QString current_theme = "default"; diff --git a/include/lobby.h b/include/lobby.h index 10a7c1d..a969f86 100644 --- a/include/lobby.h +++ b/include/lobby.h @@ -65,6 +65,8 @@ private: QLabel *ui_version; AOButton *ui_about; + AOButton *ui_settings; + QTreeWidget *ui_server_list; QLineEdit *ui_server_search; @@ -96,6 +98,7 @@ private slots: void on_connect_pressed(); void on_connect_released(); void on_about_clicked(); + void on_settings_clicked(); void on_server_list_clicked(QTreeWidgetItem* p_item, int column); void on_server_list_doubleclicked(QTreeWidgetItem* p_item, int column); void on_server_search_edited(QString p_text); diff --git a/src/aoapplication.cpp b/src/aoapplication.cpp index 6213acd..9c3d1cd 100644 --- a/src/aoapplication.cpp +++ b/src/aoapplication.cpp @@ -93,7 +93,7 @@ void AOApplication::destruct_courtroom() QString AOApplication::get_version_string() { - return + return "KFO" + QString::number(RELEASE) + "." + QString::number(MAJOR_VERSION) + "." + QString::number(MINOR_VERSION); diff --git a/src/lobby.cpp b/src/lobby.cpp index caa0915..1c355a5 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -20,6 +20,7 @@ Lobby::Lobby(AOApplication *p_ao_app) : QMainWindow() ui_connect = new AOButton(this, ao_app); ui_version = new QLabel(this); ui_about = new AOButton(this, ao_app); + ui_settings = new AOButton(this, ao_app); ui_server_list = new QTreeWidget(this); ui_server_list->setHeaderLabels({"#", "Name"});//, "Players"}); @@ -55,6 +56,7 @@ Lobby::Lobby(AOApplication *p_ao_app) : QMainWindow() connect(ui_connect, SIGNAL(pressed()), this, SLOT(on_connect_pressed())); connect(ui_connect, SIGNAL(released()), this, SLOT(on_connect_released())); connect(ui_about, SIGNAL(clicked()), this, SLOT(on_about_clicked())); + connect(ui_settings, SIGNAL(clicked()), this, SLOT(on_settings_clicked())); connect(ui_server_list, SIGNAL(itemClicked(QTreeWidgetItem*, int)), this, SLOT(on_server_list_clicked(QTreeWidgetItem*, int))); connect(ui_server_list, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this, SLOT(on_server_list_doubleclicked(QTreeWidgetItem*, int))); connect(ui_server_search, SIGNAL(textChanged(QString)), this, SLOT(on_server_search_edited(QString))); @@ -117,6 +119,11 @@ void Lobby::set_widgets() set_size_and_pos(ui_about, "about"); ui_about->set_image("about"); + set_size_and_pos(ui_settings, "settings"); + ui_settings->setText(tr("Settings")); + ui_settings->set_image("settings"); + ui_settings->setToolTip(tr("Allows you to change various aspects of the client.")); + set_size_and_pos(ui_server_list, "server_list"); ui_server_list->setStyleSheet("background-color: rgba(0, 0, 0, 0);" "font: bold;"); @@ -366,6 +373,11 @@ void Lobby::on_about_clicked() QMessageBox::about(this, "About", msg); } +void Lobby::on_settings_clicked() +{ + ao_app->call_settings_menu(); +} + //clicked on an item in the serverlist void Lobby::on_server_list_clicked(QTreeWidgetItem* p_item, int column) { From 71967d44fd4a7d8955524045d174847e985c7a15 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Thu, 12 Mar 2020 19:20:26 +0300 Subject: [PATCH 155/268] Keep verison string as-is and only update the actual VERSION display as for some weird ass reason doing it this way won't let you join KFO server --- src/aoapplication.cpp | 2 +- src/lobby.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/aoapplication.cpp b/src/aoapplication.cpp index 9c3d1cd..6213acd 100644 --- a/src/aoapplication.cpp +++ b/src/aoapplication.cpp @@ -93,7 +93,7 @@ void AOApplication::destruct_courtroom() QString AOApplication::get_version_string() { - return "KFO" + + return QString::number(RELEASE) + "." + QString::number(MAJOR_VERSION) + "." + QString::number(MINOR_VERSION); diff --git a/src/lobby.cpp b/src/lobby.cpp index 1c355a5..19bb4c6 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -114,7 +114,7 @@ void Lobby::set_widgets() ui_connect->set_image("connect"); set_size_and_pos(ui_version, "version"); - ui_version->setText(tr("Version: %1").arg(ao_app->get_version_string())); + ui_version->setText(tr("Version: KFO%1").arg(ao_app->get_version_string())); set_size_and_pos(ui_about, "about"); ui_about->set_image("about"); From 825042b32ce9f7d672ee0ba33b1f7b2e759df14c Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sun, 22 Mar 2020 22:26:46 +0300 Subject: [PATCH 156/268] Fix a really obscure bug breaking custom realization sound effects (realization=thing) char.ini definition not starting from base/sounds/general folder --- src/text_file_functions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index 432f61a..c394812 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -936,7 +936,7 @@ QString AOApplication::get_custom_realization(QString p_char) if (f_result == "") return get_sfx("realization"); - else return get_sfx_suffix(f_result); + else return get_sfx_suffix(get_sounds_path(f_result)); } bool AOApplication::get_blank_blip() From f668d70ac5e5ed7dff8ddb4508e2b8adfcba7d66 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Wed, 25 Mar 2020 00:42:20 +0300 Subject: [PATCH 157/268] Change @ and $ to \s and \f standing for s[hake] and f[lash]. This is done because @ is used very often to refer to people, and $ is used to indicate cash money. --- src/courtroom.cpp | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index d35ba70..8cf5751 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -2169,7 +2169,7 @@ QString Courtroom::filter_ic_text(QString p_text, bool html, int target_pos, int skip = true; } //Nothing related to colors here - else if (f_character == "{" || f_character == "}" || f_character == "@" || f_character == "$") + else if (f_character == "{" || f_character == "}") //|| f_character == "@" || f_character == "$") { skip = true; } @@ -2268,6 +2268,8 @@ QString Courtroom::filter_ic_text(QString p_text, bool html, int target_pos, int check_pos_escaped += appendage.size(); skip = true; } + if (f_character == "s" || f_character == "f") // screenshake/flash + skip = true; ic_next_is_not_special = false; } @@ -2636,19 +2638,6 @@ void Courtroom::chat_tick() formatting_char = true; } - //Screenshake. - else if (f_character == "@") - { - this->do_screenshake(); - formatting_char = true; - } - - //Flash. - else if (f_character == "$") - { - this->do_flash(); - formatting_char = true; - } else { //Parse markdown colors @@ -2673,13 +2662,23 @@ void Courtroom::chat_tick() { if (f_character == "n") formatting_char = true; //it's a newline + if (f_character == "s") //Screenshake. + { + this->do_screenshake(); + formatting_char = true; + } + if (f_character == "f")//Flash. + { + this->do_flash(); + formatting_char = true; + } next_character_is_not_special = false; } if ((message_display_speed[current_display_speed] <= 0 && tick_pos < f_message.size()-1) || formatting_char) { chat_tick_timer->start(0); //Don't bother rendering anything out as we're doing the SPEED. (there's latency otherwise) - if (!formatting_char || f_character == "n") + if (!formatting_char || f_character == "n" || f_character == "f" || f_character == "s") real_tick_pos += f_char_length; //Adjust the tick position for the scrollbar convenience } else From 1634db78641526ddb88f844a46b1bdc615a89e59 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Thu, 26 Mar 2020 14:41:56 +0300 Subject: [PATCH 158/268] Make backgrounds preserve aspect ratio when used with different aspect ratio themes (e.g. a 16:9 theme would not stretch a 4:3 bg and instead have a letterboxing effect. A 4:3 theme using a 16:9 BG will not stretch the BG but instead center it, making it look like the BG is 4:3 all along.) --- include/aoscene.h | 11 +++++++++++ src/aoscene.cpp | 39 ++++++++++++++++++++++++++++++++------- src/courtroom.cpp | 4 ++-- 3 files changed, 45 insertions(+), 9 deletions(-) diff --git a/include/aoscene.h b/include/aoscene.h index ddbefe0..46d8c3b 100644 --- a/include/aoscene.h +++ b/include/aoscene.h @@ -17,12 +17,23 @@ public: void set_image(QString p_image); void set_legacy_desk(QString p_image); + //Move the label itself around + void move(int ax, int ay); + + //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); private: QWidget *m_parent; QMovie *m_movie; AOApplication *ao_app; QString last_image; + // These are the X and Y values before they are fixed based on the sprite's width. + int x = 0; + int y = 0; + // These are the width and height values before they are fixed based on the sprite's width. + int f_w = 0; + int f_h = 0; }; #endif // AOSCENE_H diff --git a/src/aoscene.cpp b/src/aoscene.cpp index 32e5c35..45eadd5 100644 --- a/src/aoscene.cpp +++ b/src/aoscene.cpp @@ -26,25 +26,35 @@ void AOScene::set_image(QString p_image) if (file_exists(background_path) && background_path == last_image) return; - int w = this->width(); - int h = this->height(); - this->clear(); this->setMovie(nullptr); m_movie->stop(); m_movie->setFileName(background_path); - m_movie->setScaledSize(QSize(w, h)); if (m_movie->isValid() && m_movie->frameCount() > 1) { + float scale_factor = f_h / m_movie->frameRect().height(); + //preserve aspect ratio + int n_w = static_cast(static_cast(m_movie->frameRect().width()) * scale_factor); + int n_h = static_cast(static_cast(m_movie->frameRect().height()) * scale_factor); + m_movie->setScaledSize(QSize(n_w, n_h)); + this->resize(m_movie->scaledSize()); this->setMovie(m_movie); + QLabel::move(x + (f_w - n_w)/2, y + (f_h - n_h)); //Always center horizontally, always put at the bottom vertically m_movie->start(); } else { QPixmap background(background_path); - this->setPixmap(background.scaled(w, h)); + auto transform_mode = Qt::FastTransformation; + if (background.height() > f_h) //We are downscaling, use anti-aliasing. + transform_mode = Qt::SmoothTransformation; + + background = background.scaledToHeight(f_h, transform_mode); + this->resize(background.size()); + this->setPixmap(background); + QLabel::move(x + (f_w - background.width())/2, y + (f_h - background.height())/2); //Always center horizontally, always center vertically } last_image = background_path; } @@ -92,8 +102,23 @@ void AOScene::set_legacy_desk(QString p_image) } else { - this->resize(vp_width, final_h); - this->setPixmap(f_desk.scaled(vp_width, final_h)); + this->resize(vp_width, final_h); + this->setPixmap(f_desk.scaled(vp_width, final_h)); } last_image = desk_path; } + +void AOScene::combo_resize(int w, int h) +{ + QSize f_size(w, h); + f_w = w; + f_h = h; + this->resize(f_size); +} + +void AOScene::move(int ax, int ay) +{ + x = ax; + y = ay; + QLabel::move(x, y); +} diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 8cf5751..dbe5323 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -487,7 +487,7 @@ void Courtroom::set_widgets() ui_settings->show(); ui_vp_background->move(0, 0); - ui_vp_background->resize(ui_viewport->width(), ui_viewport->height()); + ui_vp_background->combo_resize(ui_viewport->width(), ui_viewport->height()); ui_vp_speedlines->move(0, 0); ui_vp_speedlines->combo_resize(ui_viewport->width(), ui_viewport->height()); @@ -500,7 +500,7 @@ void Courtroom::set_widgets() //the AO2 desk element ui_vp_desk->move(0, 0); - ui_vp_desk->resize(ui_viewport->width(), ui_viewport->height()); + ui_vp_desk->combo_resize(ui_viewport->width(), ui_viewport->height()); //the size of the ui_vp_legacy_desk element relies on various factors and is set in set_scene() From 614522bc0c8683ca367c5195f1e3c8121b65ce64 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Fri, 27 Mar 2020 15:48:16 +0300 Subject: [PATCH 159/268] Quality of Life improvements Fix a bug where IC view received focus as soon as you receive the BG image update (it made navigating using /area commands a pain in the ass) Make music search behave better and not reset when server sends us music list update (todo: remember which elements were/weren't expanded) --- src/courtroom.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index dbe5323..f757130 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1214,7 +1214,7 @@ void Courtroom::enter_courtroom() void Courtroom::list_music() { ui_music_list->clear(); - ui_music_search->setText(""); +// ui_music_search->setText(""); QString f_file = "courtroom_design.ini"; @@ -1251,13 +1251,17 @@ void Courtroom::list_music() } ui_music_list->expandAll(); //Needs to somehow remember which categories were expanded/collapsed if the music list didn't change since last time + if (ui_music_search->text() != "") + { + on_music_search_edited(ui_music_search->text()); + } } //Todo: multithread this due to some servers having large as hell area list void Courtroom::list_areas() { ui_area_list->clear(); - ui_music_search->setText(""); +// ui_music_search->setText(""); QString f_file = "courtroom_design.ini"; @@ -1327,6 +1331,11 @@ void Courtroom::list_areas() ++n_listed_areas; } + + if (ui_music_search->text() != "") + { + on_music_search_edited(ui_music_search->text()); + } } void Courtroom::append_ms_chatmessage(QString f_name, QString f_message) @@ -3386,8 +3395,6 @@ void Courtroom::on_music_search_edited(QString p_text) void Courtroom::on_pos_dropdown_changed(int p_index) { - ui_ic_chat_message->setFocus(); - if (p_index < 0 || p_index > 7) return; @@ -4399,6 +4406,8 @@ void Courtroom::on_evidence_button_clicked() void Courtroom::on_switch_area_music_clicked() { + ui_music_search->setText(""); + on_music_search_edited(ui_music_search->text()); if (ui_area_list->isHidden()) { ui_area_list->show(); From 4aa1ae62e1561363db07a81dc92861fb00988a4b Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sat, 28 Mar 2020 19:29:46 +0300 Subject: [PATCH 160/268] Fix wrong pos being shown when entering area due to index signal being called in the wrong place --- src/courtroom.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index f757130..17d1f0b 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1086,9 +1086,14 @@ void Courtroom::set_side(QString p_side) void Courtroom::set_pos_dropdown(QStringList pos_dropdowns) { + //Block the signals to prevent setCurrentIndex from triggering a pos change + ui_pos_dropdown->blockSignals(true); pos_dropdown_list = pos_dropdowns; ui_pos_dropdown->clear(); ui_pos_dropdown->addItems(pos_dropdown_list); + //Unblock the signals so the element can be used for setting pos again + ui_pos_dropdown->blockSignals(false); + qDebug() << pos_dropdown_list; } From 7fb19ae7bdfc57fb7123edbe25d109b66173ab06 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Tue, 31 Mar 2020 14:24:48 +0300 Subject: [PATCH 161/268] Fix aomovie resizing algorithm for BG's crashing the client because I fucked up, lol --- src/aoscene.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/aoscene.cpp b/src/aoscene.cpp index 45eadd5..575a27d 100644 --- a/src/aoscene.cpp +++ b/src/aoscene.cpp @@ -34,14 +34,16 @@ void AOScene::set_image(QString p_image) if (m_movie->isValid() && m_movie->frameCount() > 1) { - float scale_factor = f_h / m_movie->frameRect().height(); + m_movie->jumpToNextFrame(); + float scale_factor = static_cast(f_h) / static_cast(m_movie->frameRect().height()); //preserve aspect ratio - int n_w = static_cast(static_cast(m_movie->frameRect().width()) * scale_factor); - int n_h = static_cast(static_cast(m_movie->frameRect().height()) * scale_factor); + int n_w = static_cast(m_movie->frameRect().width() * scale_factor); + int n_h = static_cast(m_movie->frameRect().height() * scale_factor); + m_movie->setScaledSize(QSize(n_w, n_h)); this->resize(m_movie->scaledSize()); this->setMovie(m_movie); - QLabel::move(x + (f_w - n_w)/2, y + (f_h - n_h)); //Always center horizontally, always put at the bottom vertically + QLabel::move(x + (f_w - n_w)/2, y + (f_h - n_h)/2); //Center m_movie->start(); } else From 2e89f0d1997fb00aeab5e73962ca42489f1706af Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Tue, 31 Mar 2020 14:26:16 +0300 Subject: [PATCH 162/268] Change the ultra-tiny-minor version so people can right-click for details and tell me which version they're using during qa-testing --- Attorney_Online.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Attorney_Online.pro b/Attorney_Online.pro index 81a3304..951d701 100644 --- a/Attorney_Online.pro +++ b/Attorney_Online.pro @@ -3,7 +3,7 @@ QT += core gui widgets network TARGET = Attorney_Online TEMPLATE = app -VERSION = 2.8.3.0 +VERSION = 2.8.3.1 INCLUDEPATH += $$PWD/include DESTDIR = $$PWD/bin From feaf04a5c48bb647d12408645f69e1ed49c9df15 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Tue, 31 Mar 2020 17:03:41 +0300 Subject: [PATCH 163/268] Fix custom chatboxes not working at all --- src/courtroom.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 17d1f0b..6763300 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1803,6 +1803,7 @@ void Courtroom::handle_chatmessage_2() if (chatbox != "") { chatbox_path = ao_app->get_base_path() + "misc/" + chatbox + "/chat"; + ui_vp_chatbox->set_chatbox(chatbox_path); } pos_size_type default_width = ao_app->get_element_dimensions("showname", "courtroom_design.ini"); From 7816c8ab234e185e5eb3410761aee3ca60e0f354 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Tue, 31 Mar 2020 17:09:00 +0300 Subject: [PATCH 164/268] Add legacy fallback for "chatbox.png" name if chat.png doesn't exist --- src/courtroom.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 6763300..d310a0a 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1793,7 +1793,8 @@ void Courtroom::handle_chatmessage_2() } else //Aw yeah dude do some showname resizing magic { - ui_vp_chatbox->set_image("chat"); + if (!ui_vp_chatbox->set_image("chat")) + ui_vp_chatbox->set_image("chatbox"); QFontMetrics fm(ui_vp_showname->font()); int fm_width=fm.horizontalAdvance(ui_vp_showname->text()); @@ -1803,7 +1804,8 @@ void Courtroom::handle_chatmessage_2() if (chatbox != "") { chatbox_path = ao_app->get_base_path() + "misc/" + chatbox + "/chat"; - ui_vp_chatbox->set_chatbox(chatbox_path); + if (!ui_vp_chatbox->set_chatbox(chatbox_path)) + ui_vp_chatbox->set_chatbox(chatbox_path + "box"); } pos_size_type default_width = ao_app->get_element_dimensions("showname", "courtroom_design.ini"); From 8007b1d1b95d476821a6b2616c09824e54911ea9 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Tue, 31 Mar 2020 18:12:15 +0300 Subject: [PATCH 165/268] Add courtroom_design.ini partial parsing for misc/ folder (only chat_arrow and showname atm) Initialize chat arrow n stuff this is still pretty gay because you can't ignore size and set pos or something like that --- include/aoapplication.h | 4 ++-- src/courtroom.cpp | 16 ++++++++++++++-- src/text_file_functions.cpp | 26 ++++++++++++++++++-------- 3 files changed, 34 insertions(+), 12 deletions(-) diff --git a/include/aoapplication.h b/include/aoapplication.h index 8b520bc..e44f2d3 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -248,10 +248,10 @@ public: QPoint get_button_spacing(QString p_identifier, QString p_file); //Returns the dimensions of widget with specified identifier from p_file - pos_size_type get_element_dimensions(QString p_identifier, QString p_file); + pos_size_type get_element_dimensions(QString p_identifier, QString p_file, QString p_char=""); //Returns the value to you - QString get_design_element(QString p_identifier, QString p_file); + 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); diff --git a/src/courtroom.cpp b/src/courtroom.cpp index d310a0a..c7f1936 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1806,10 +1806,22 @@ void Courtroom::handle_chatmessage_2() 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"); + + pos_size_type design_ini_result = ao_app->get_element_dimensions("chat_arrow", "courtroom_design.ini", m_chatmessage[CHAR_NAME]); + 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(); + } + else + { + ui_vp_chat_arrow->move(design_ini_result.x, design_ini_result.y); + ui_vp_chat_arrow->combo_resize(design_ini_result.width, design_ini_result.height); + } } - pos_size_type default_width = ao_app->get_element_dimensions("showname", "courtroom_design.ini"); - int extra_width = ao_app->get_design_element("showname_extra_width", "courtroom_design.ini").toInt(); + pos_size_type default_width = ao_app->get_element_dimensions("showname", "courtroom_design.ini", m_chatmessage[CHAR_NAME]); + int extra_width = ao_app->get_design_element("showname_extra_width", "courtroom_design.ini", m_chatmessage[CHAR_NAME]).toInt(); if(extra_width > 0) { diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index c394812..d986709 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -264,11 +264,12 @@ QPoint AOApplication::get_button_spacing(QString p_identifier, QString p_file) return return_value; } -pos_size_type AOApplication::get_element_dimensions(QString p_identifier, QString p_file) +pos_size_type AOApplication::get_element_dimensions(QString p_identifier, QString p_file, QString p_char) { + QString char_ini_path = get_base_path() + "misc/" + get_chat(p_char) + "/" + 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 f_result = read_design_ini(p_identifier, char_ini_path); pos_size_type return_value; @@ -279,10 +280,14 @@ pos_size_type AOApplication::get_element_dimensions(QString p_identifier, QStrin if (f_result == "") { - f_result = read_design_ini(p_identifier, default_path); - + f_result = read_design_ini(p_identifier, design_ini_path); if (f_result == "") - return return_value; + { + f_result = read_design_ini(p_identifier, default_path); + + if (f_result == "") + return return_value; + } } QStringList sub_line_elements = f_result.split(","); @@ -297,13 +302,18 @@ pos_size_type AOApplication::get_element_dimensions(QString p_identifier, QStrin return return_value; } -QString AOApplication::get_design_element(QString p_identifier, QString p_file) +QString AOApplication::get_design_element(QString p_identifier, QString p_file, QString p_char) { + QString char_ini_path = get_base_path() + "misc/" + get_chat(p_char) + "/" + p_file; 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); + QString f_result = read_design_ini(p_identifier, char_ini_path); if (f_result == "") - f_result = read_design_ini(p_identifier, default_path); + { + f_result = read_design_ini(p_identifier, design_ini_path); + if (f_result == "") + f_result = read_design_ini(p_identifier, default_path); + } return f_result; } QString AOApplication::get_font_name(QString p_identifier, QString p_file) From c49c9cdd777c7df38594aa444a1aee8c8f9cf09c Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Wed, 1 Apr 2020 19:48:58 +0300 Subject: [PATCH 166/268] Fix weird behavior with area list and arup system + wrong column being used for 'metadata' --- src/courtroom.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index c7f1936..2664837 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1310,7 +1310,7 @@ void Courtroom::list_areas() if (ao_app->arup_enabled) { // Coloring logic here. - treeItem->setBackground(0, free_brush); + treeItem->setBackground(1, free_brush); if (arup_locks.at(n_area) == "LOCKED") { treeItem->setBackground(1, locked_brush); @@ -3921,8 +3921,8 @@ void Courtroom::music_list_collapse_all() void Courtroom::on_area_list_double_clicked(QTreeWidgetItem *p_item, int column) { - column = 1; //The metadata - QString p_area = p_item->text(1); + column = 0; //The metadata + QString p_area = p_item->text(0); QStringList packet_contents; packet_contents.append(p_area); From 71ebdac1c1ac560d00a6d1f75ef9a45c5bc50b41 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Wed, 1 Apr 2020 20:01:00 +0300 Subject: [PATCH 167/268] Fix collapse all rightclick option being annoying in its behavior. Now it's *smart*! --- src/courtroom.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 2664837..d5dd656 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -3917,6 +3917,10 @@ void Courtroom::music_list_expand_all() void Courtroom::music_list_collapse_all() { ui_music_list->collapseAll(); + QTreeWidgetItem *current = ui_music_list->selectedItems()[0]; + if (current->parent() != nullptr) + current = current->parent(); + ui_music_list->setCurrentItem(current); } void Courtroom::on_area_list_double_clicked(QTreeWidgetItem *p_item, int column) From e0ae7c0eb5f91d7852cdeb06d6eaaca6ddd21f62 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Thu, 2 Apr 2020 23:10:54 +0300 Subject: [PATCH 168/268] Fix evidence display viewport element being a FUCKING JACKASS --- src/aoevidencedisplay.cpp | 13 ++++++------- src/courtroom.cpp | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/aoevidencedisplay.cpp b/src/aoevidencedisplay.cpp index fef072b..904568a 100644 --- a/src/aoevidencedisplay.cpp +++ b/src/aoevidencedisplay.cpp @@ -21,10 +21,6 @@ void AOEvidenceDisplay::show_evidence(QString p_evidence_image, bool is_left_sid sfx_player->set_volume(p_volume); - QString f_evidence_path = ao_app->get_evidence_path(p_evidence_image); - - QPixmap f_pixmap(f_evidence_path); - QString final_gif_path; QString gif_name; QString icon_identifier; @@ -40,12 +36,15 @@ void AOEvidenceDisplay::show_evidence(QString p_evidence_image, bool is_left_sid gif_name = "evidence_appear_right"; } + QString f_evidence_path = ao_app->get_evidence_path(p_evidence_image); + QPixmap f_pixmap(f_evidence_path); + pos_size_type icon_dimensions = ao_app->get_element_dimensions(icon_identifier, "courtroom_design.ini"); + f_pixmap = f_pixmap.scaled(icon_dimensions.width, icon_dimensions.height); + evidence_icon->setPixmap(f_pixmap); + evidence_icon->resize(f_pixmap.size()); evidence_icon->move(icon_dimensions.x, icon_dimensions.y); - evidence_icon->resize(icon_dimensions.width, icon_dimensions.height); - - evidence_icon->setPixmap(f_pixmap.scaled(evidence_icon->width(), evidence_icon->height(), Qt::IgnoreAspectRatio)); evidence_movie->play(gif_name); sfx_player->play(ao_app->get_sfx("evidence_present")); diff --git a/src/courtroom.cpp b/src/courtroom.cpp index d5dd656..f16b828 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -85,7 +85,7 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_vp_desk = new AOScene(ui_viewport, ao_app); ui_vp_legacy_desk = new AOScene(ui_viewport, ao_app); - ui_vp_evidence_display = new AOEvidenceDisplay(this, ao_app); + ui_vp_evidence_display = new AOEvidenceDisplay(ui_viewport, ao_app); ui_vp_chatbox = new AOImage(this, ao_app); ui_vp_showname = new QLabel(ui_vp_chatbox); From dfac0652c8eb9bd48ceea7ae755e9c2f7e5cb1a2 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Mon, 13 Apr 2020 17:16:26 +0300 Subject: [PATCH 169/268] Add possibility for custom use text besides just "played music" Implemented "presented evidence" message --- include/courtroom.h | 2 +- src/courtroom.cpp | 33 ++++++++++++++++++++++++--------- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/include/courtroom.h b/include/courtroom.h index 417d455..c1bd0a6 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -221,7 +221,7 @@ public: //adds text to the IC chatlog. p_name first as bold then p_text then a newlin //this function keeps the chatlog scrolled to the top unless there's text selected // or the user isn't already scrolled to the top - void append_ic_text(QString p_text, QString p_name = "", bool is_songchange = false); + void append_ic_text(QString p_text, QString p_name = "", QString action = ""); //prints who played the song to IC chat and plays said song(if found on local filesystem) //takes in a list where the first element is the song name and the second is the char id of who played it diff --git a/src/courtroom.cpp b/src/courtroom.cpp index f16b828..40d17e4 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -2036,13 +2036,28 @@ void Courtroom::handle_chatmessage_3() int f_evi_id = m_chatmessage[EVIDENCE_ID].toInt(); QString f_side = m_chatmessage[SIDE]; + QString f_showname; + int f_char_id = m_chatmessage[CHAR_ID].toInt(); + if (f_char_id > 0 && (m_chatmessage[SHOWNAME].isEmpty() || !ui_showname_enable->isChecked())) + { + f_showname = ao_app->get_showname(char_list.at(f_char_id).name); + } + else + { + f_showname = m_chatmessage[SHOWNAME]; + } + if(f_showname.trimmed().isEmpty()) //Pure whitespace showname, get outta here. + f_showname = m_chatmessage[CHAR_NAME]; + if (f_evi_id > 0 && f_evi_id <= local_evidence_list.size()) { //shifted by 1 because 0 is no evidence per legacy standards QString f_image = local_evidence_list.at(f_evi_id - 1).image; + QString f_name = local_evidence_list.at(f_evi_id - 1).name; //def jud and hlp should display the evidence icon on the RIGHT side bool is_left_side = !(f_side == "def" || f_side == "hlp" || f_side == "jud" || f_side == "jur"); ui_vp_evidence_display->show_evidence(f_image, is_left_side, ui_sfx_slider->value()); + append_ic_text(f_name, f_showname, "has presented evidence"); } int emote_mod = m_chatmessage[EMOTE_MOD].toInt(); @@ -2353,7 +2368,7 @@ QString Courtroom::filter_ic_text(QString p_text, bool html, int target_pos, int return p_text_escaped; } -void Courtroom::append_ic_text(QString p_text, QString p_name, bool is_songchange) +void Courtroom::append_ic_text(QString p_text, QString p_name, QString p_action) { QTextCharFormat bold; QTextCharFormat normal; @@ -2364,7 +2379,7 @@ void Courtroom::append_ic_text(QString p_text, QString p_name, bool is_songchang const QTextCursor old_cursor = ui_ic_chatlog->textCursor(); const int old_scrollbar_value = ui_ic_chatlog->verticalScrollBar()->value(); - if (!is_songchange) + if (p_action == "") p_text = filter_ic_text(p_text, ao_app->is_colorlog_enabled(), -1, m_chatmessage[TEXT_COLOR].toInt()); if (log_goes_downwards) @@ -2383,9 +2398,9 @@ void Courtroom::append_ic_text(QString p_text, QString p_name, bool is_songchang ui_ic_chatlog->textCursor().insertText('\n' + p_name, bold); } - if (is_songchange) + if (p_action != "") { - ui_ic_chatlog->textCursor().insertText(" has played a song: ", normal); + ui_ic_chatlog->textCursor().insertText(" " + p_action + ": ", normal); ui_ic_chatlog->textCursor().insertText(p_text + ".", italics); } else @@ -2424,9 +2439,9 @@ void Courtroom::append_ic_text(QString p_text, QString p_name, bool is_songchang ui_ic_chatlog->textCursor().insertText(p_name, bold); - if (is_songchange) + if (p_action != "") { - ui_ic_chatlog->textCursor().insertText(" has played a song: ", normal); + ui_ic_chatlog->textCursor().insertText(" " + p_action + ": ", normal); ui_ic_chatlog->textCursor().insertText(p_text + "." + '\n', italics); } else @@ -2956,7 +2971,7 @@ void Courtroom::handle_song(QStringList *p_contents) ic_chatlog_history.removeFirst(); } - append_ic_text(f_song_clear, str_show, true); + append_ic_text(f_song_clear, str_show, "has played a song"); music_player->play(f_song, channel, looping, effect_flags); if (channel == 0) @@ -4399,14 +4414,14 @@ void Courtroom::on_showname_enable_clicked() if (ui_showname_enable->isChecked()) { if (item.is_song()) - append_ic_text(item.get_message(), item.get_showname(), true); + append_ic_text(item.get_message(), item.get_showname(), "has played a song"); else append_ic_text(item.get_message(), item.get_showname()); } else { if (item.is_song()) - append_ic_text(item.get_message(), item.get_name(), true); + append_ic_text(item.get_message(), item.get_name(), "has played a song"); else append_ic_text(item.get_message(), item.get_name()); } From 4af7bc5fffd784195385712ab6ddf476d5ae1a2f Mon Sep 17 00:00:00 2001 From: oldmud0 Date: Tue, 19 May 2020 18:49:29 -0500 Subject: [PATCH 170/268] Fix broken APNG (#153) * Remove explicit APNG check * Update aocharmovie.h --- include/aocharmovie.h | 1 - src/aocharmovie.cpp | 8 ++------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/include/aocharmovie.h b/include/aocharmovie.h index 6db490b..f62820b 100644 --- a/include/aocharmovie.h +++ b/include/aocharmovie.h @@ -65,7 +65,6 @@ private: bool m_flipped = false; bool play_once = true; - bool apng = false; signals: void done(); diff --git a/src/aocharmovie.cpp b/src/aocharmovie.cpp index 4252923..35d9b03 100644 --- a/src/aocharmovie.cpp +++ b/src/aocharmovie.cpp @@ -19,8 +19,6 @@ AOCharMovie::AOCharMovie(QWidget *p_parent, AOApplication *p_ao_app) void AOCharMovie::play(QString p_char, QString p_emote, QString emote_prefix) { - apng = false; - QString original_path = ao_app->get_character_path(p_char, emote_prefix + p_emote + ".gif"); QString alt_path = @@ -35,10 +33,8 @@ void AOCharMovie::play(QString p_char, QString p_emote, QString emote_prefix) QString gif_path; current_emote = emote_prefix + p_emote; current_char = p_char; - if (file_exists(apng_path)) { + if (file_exists(apng_path)) gif_path = apng_path; - apng = true; - } else if (file_exists(original_path)) gif_path = original_path; else if (file_exists(alt_path)) @@ -184,7 +180,7 @@ void AOCharMovie::movie_ticker() if (m_movie->frameCount() == 0) { return; } - else if (!apng) { + else { ticker->start(m_movie->nextFrameDelay()); } } From 8c0bb87f09898314cbbaeb222c0bacc641ff5af2 Mon Sep 17 00:00:00 2001 From: in1tiate <32779090+in1tiate@users.noreply.github.com> Date: Wed, 20 May 2020 00:22:48 -0500 Subject: [PATCH 171/268] specify encoding for qsettings calls --- src/text_file_functions.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index 779765d..f2bec87 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -167,6 +167,7 @@ QString AOApplication::read_design_ini(QString p_identifier, QString p_design_path) { QSettings settings(p_design_path, QSettings::IniFormat); + settings.setIniCodec("UTF-8"); QVariant value = settings.value(p_identifier); if (value.isNull()) // Since the value wasn't found, maybe it uses the proper // config system @@ -450,6 +451,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.setIniCodec("UTF-8"); settings.beginGroup(target_tag); QString value = settings.value(p_search_line).toString(); settings.endGroup(); From d89a4370a753f6e1da22349866b1b00f638884a6 Mon Sep 17 00:00:00 2001 From: oldmud0 Date: Thu, 21 May 2020 14:22:51 -0500 Subject: [PATCH 172/268] Update CI pipeline for release --- .gitlab-ci.yml | 36 ++++++++++++++++++++++++++++++++---- scripts/wasabi_program.sh | 2 +- scripts/windows/Dockerfile | 11 +++++++++-- 3 files changed, 42 insertions(+), 7 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index bc15619..e9685de 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -83,6 +83,9 @@ build windows i686: - git submodule init - git submodule update + # Print versions + - /opt/mxe/usr/${TARGET_SPEC}/qt5/bin/qmake --version + # Extract BASS - mkdir bass - cd bass @@ -94,6 +97,17 @@ build windows i686: - cp bassopus.dll ../lib - cd .. + # Extract QtApng + # - mkdir qtapng + # - cd qtapng + # - curl -L https://github.com/Skycoder42/QtApng/releases/download/1.1.2-2/qtapng_mingw73_32_5.13.0.zip -o apng.zip + # - unzip apng.zip + # - mkdir ../lib/imageformats + # - cp mingw73_32/plugins/imageformats/qapng.dll ../lib/imageformats/ + # - cd .. + + - ls lib + # Build - /opt/mxe/usr/${TARGET_SPEC}/qt5/bin/qmake "DEFINES += DISCORD BASSAUDIO" - make -j4 @@ -165,6 +179,8 @@ deploy windows i686: # Platform-specific - cp -a ../lib/*.dll . + - mkdir imageformats + - 'cp -a ../lib/imageformats/*.dll imageformats/ || :' - cp -a ../bin/Attorney_Online.exe . # Zipping @@ -197,11 +213,17 @@ publish linux x86_64: - deploy linux x86_64 when: manual script: + - apt-get update + - apt-get install --no-install-recommends -y git nodejs npm awscli + - cd scripts + - npm install + - cd .. + - cd zip - - ../scripts/wasabi.sh + - ../scripts/wasabi_program.sh variables: MANIFEST: program_linux_x86_64.json - ARTIFACT_SUFFIX: _linux_x64.tar.xz + ARTIFACT_SUFFIX: linux_x64.tar.xz publish windows i686: image: ubuntu @@ -210,8 +232,14 @@ publish windows i686: - deploy windows i686 when: manual script: + - apt-get update + - apt-get install --no-install-recommends -y git nodejs npm awscli + - cd scripts + - npm install + - cd .. + - cd zip - - ../scripts/wasabi.sh + - ../scripts/wasabi_program.sh variables: MANIFEST: program_winnt_i386.json - ARTIFACT_SUFFIX: _windows_x86.zip + ARTIFACT_SUFFIX: windows_x86.zip diff --git a/scripts/wasabi_program.sh b/scripts/wasabi_program.sh index 41e2e35..37feac6 100755 --- a/scripts/wasabi_program.sh +++ b/scripts/wasabi_program.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # Updates the specified program manifest to a new archive and version # and uploads the new archive and manifest to S3/Wasabi. # diff --git a/scripts/windows/Dockerfile b/scripts/windows/Dockerfile index f4f1a83..b9a12d6 100644 --- a/scripts/windows/Dockerfile +++ b/scripts/windows/Dockerfile @@ -10,5 +10,12 @@ RUN /opt/mxe/usr/bin/${TARGET_SPEC}-cmake .. -DCMAKE_INSTALL_PREFIX=/opt/mxe/usr RUN /opt/mxe/usr/bin/${TARGET_SPEC}-cmake --build . --config Release --target install WORKDIR ../.. -# NOTE: Do not build QtApng statically! libpng contains a self-test entry point that -# takes precedence for some reason over the final build's entry point. +# Build QtApng statically +RUN git clone https://github.com/Skycoder42/QtApng +WORKDIR QtApng +# libpng contains a self-test entry point that takes precedence for some reason +# over the final build's entry point. +RUN sed -i "s/^main(/libpng_main(/g" src/3rdparty/libpng/src/pngtest.c +RUN /opt/mxe/usr/${TARGET_SPEC}/qt5/bin/qmake +RUN make && make install +WORKDIR .. \ No newline at end of file From c8e12558cdd3fd0769b81679ad09edf1f29b780f Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Fri, 22 May 2020 01:18:24 +0300 Subject: [PATCH 173/268] Clang-ify the code with this styling using Visual Studio Code: { BasedOnStyle: LLVM, UseTab: Never, IndentWidth: 4, TabWidth: 4, BreakBeforeBraces: Stroustrup, AllowShortIfStatementsOnASingleLine: false, IndentCaseLabels: false, ColumnLimit: 0, AccessModifierOffset: -4, NamespaceIndentation: All } (this is the Visual Studio preset with only "BreakBeforeBraces" changed from Allman to Stroustrup) --- include/aoapplication.h | 561 ++- include/aoblipplayer.h | 40 +- include/aobutton.h | 15 +- include/aocaseannouncerdialog.h | 41 +- include/aocharbutton.h | 37 +- include/aocharmovie.h | 144 +- include/aoemotebutton.h | 27 +- include/aoevidencebutton.h | 43 +- include/aoevidencedisplay.h | 29 +- include/aoimage.h | 19 +- include/aolineedit.h | 17 +- include/aomovie.h | 29 +- include/aomusicplayer.h | 79 +- include/aooptionsdialog.h | 5 +- include/aopacket.h | 31 +- include/aoscene.h | 42 +- include/aosfxplayer.h | 44 +- include/aotextarea.h | 23 +- include/aotextedit.h | 14 +- include/bass.h | 1520 ++++--- include/bassopus.h | 12 +- include/chatlogpiece.h | 35 +- include/courtroom.h | 1143 +++-- include/datatypes.h | 178 +- include/debug_functions.h | 2 +- include/discord-rpc.h | 48 +- include/discord_register.h | 24 +- include/discord_rich_presence.h | 36 +- include/discord_rpc.h | 52 +- include/encryption_functions.h | 8 +- include/file_functions.h | 2 +- include/hex_functions.h | 11 +- include/lobby.h | 129 +- include/misc_functions.h | 2 +- include/networkmanager.h | 73 +- include/scrolltext.h | 11 +- include/text_file_functions.h | 8 +- src/aoapplication.cpp | 182 +- src/aoblipplayer.cpp | 95 +- src/aobutton.cpp | 34 +- src/aocaseannouncerdialog.cpp | 106 +- src/aocharbutton.cpp | 112 +- src/aocharmovie.cpp | 373 +- src/aoemotebutton.cpp | 40 +- src/aoevidencebutton.cpp | 119 +- src/aoevidencedisplay.cpp | 79 +- src/aoimage.cpp | 51 +- src/aolineedit.cpp | 14 +- src/aomovie.cpp | 103 +- src/aomusicplayer.cpp | 246 +- src/aooptionsdialog.cpp | 61 +- src/aopacket.cpp | 71 +- src/aoscene.cpp | 174 +- src/aosfxplayer.cpp | 190 +- src/aotextarea.cpp | 67 +- src/aotextedit.cpp | 11 +- src/charselect.cpp | 272 +- src/chatlogpiece.cpp | 68 +- src/courtroom.cpp | 7031 +++++++++++++++---------------- src/debug_functions.cpp | 24 +- src/discord_rich_presence.cpp | 214 +- src/emotes.cpp | 226 +- src/encryption_functions.cpp | 73 +- src/evidence.cpp | 1036 +++-- src/file_functions.cpp | 15 +- src/hardware_functions.cpp | 73 +- src/hex_functions.cpp | 27 +- src/lobby.cpp | 641 ++- src/main.cpp | 12 +- src/misc_functions.cpp | 6 +- src/networkmanager.cpp | 294 +- src/packet_distribution.cpp | 1279 +++--- src/path_functions.cpp | 212 +- src/scrolltext.cpp | 43 +- src/text_file_functions.cpp | 997 +++-- 75 files changed, 9255 insertions(+), 9950 deletions(-) diff --git a/include/aoapplication.h b/include/aoapplication.h index e44f2d3..ff75e4d 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -6,23 +6,23 @@ #include "discord_rich_presence.h" #include -#include #include #include +#include #include -#include #include +#include #include #include #include -#include -#include #include #include +#include +#include #ifdef QTAUDIO #include #endif @@ -31,404 +31,403 @@ class NetworkManager; class Lobby; class Courtroom; -class AOApplication : public QApplication -{ - Q_OBJECT +class AOApplication : public QApplication { + Q_OBJECT public: - AOApplication(int &argc, char **argv); - ~AOApplication(); + AOApplication(int &argc, char **argv); + ~AOApplication(); - NetworkManager *net_manager; - Lobby *w_lobby; - Courtroom *w_courtroom; - AttorneyOnline::Discord *discord; + NetworkManager *net_manager; + Lobby *w_lobby; + Courtroom *w_courtroom; + AttorneyOnline::Discord *discord; - bool lobby_constructed = false; - bool courtroom_constructed = false; + bool lobby_constructed = false; + bool courtroom_constructed = false; - void construct_lobby(); - void destruct_lobby(); + void construct_lobby(); + void destruct_lobby(); - void construct_courtroom(); - void destruct_courtroom(); + void construct_courtroom(); + void destruct_courtroom(); - void ms_packet_received(AOPacket *p_packet); - void server_packet_received(AOPacket *p_packet); + void ms_packet_received(AOPacket *p_packet); + void server_packet_received(AOPacket *p_packet); - void send_ms_packet(AOPacket *p_packet); - void send_server_packet(AOPacket *p_packet, bool encoded = true); + void send_ms_packet(AOPacket *p_packet); + void send_server_packet(AOPacket *p_packet, bool encoded = true); - void call_settings_menu(); - void call_announce_menu(Courtroom *court); + void call_settings_menu(); + void call_announce_menu(Courtroom *court); - /////////////////server metadata////////////////// + /////////////////server metadata////////////////// - unsigned int s_decryptor = 5; - bool encryption_needed = true; + unsigned int s_decryptor = 5; + bool encryption_needed = true; - bool yellow_text_enabled = false; - bool prezoom_enabled = false; - bool flipping_enabled = false; - bool custom_objection_enabled = false; - bool improved_loading_enabled = false; - bool desk_mod_enabled = false; - bool evidence_enabled = false; - bool cccc_ic_support_enabled = false; - bool arup_enabled = false; - bool casing_alerts_enabled = false; - bool modcall_reason_enabled = false; - bool looping_sfx_support_enabled = false; - bool additive_enabled = false; - bool effects_enabled = false; + bool yellow_text_enabled = false; + bool prezoom_enabled = false; + bool flipping_enabled = false; + bool custom_objection_enabled = false; + bool improved_loading_enabled = false; + bool desk_mod_enabled = false; + bool evidence_enabled = false; + bool cccc_ic_support_enabled = false; + bool arup_enabled = false; + bool casing_alerts_enabled = false; + bool modcall_reason_enabled = false; + bool looping_sfx_support_enabled = false; + bool additive_enabled = false; + bool effects_enabled = false; - ///////////////loading info/////////////////// + ///////////////loading info/////////////////// - //player number, it's hardly used but might be needed for some old servers - int s_pv = 0; + //player number, it's hardly used but might be needed for some old servers + int s_pv = 0; - QString server_software = ""; + QString server_software = ""; - int char_list_size = 0; - int loaded_chars = 0; - int generated_chars = 0; - int evidence_list_size = 0; - int loaded_evidence = 0; - int music_list_size = 0; - int loaded_music = 0; + int char_list_size = 0; + int loaded_chars = 0; + int generated_chars = 0; + int evidence_list_size = 0; + int loaded_evidence = 0; + int music_list_size = 0; + int loaded_music = 0; - bool courtroom_loaded = false; + bool courtroom_loaded = false; - //////////////////versioning/////////////// + //////////////////versioning/////////////// - int get_release() const { return RELEASE; } - int get_major_version() const { return MAJOR_VERSION; } - int get_minor_version() const { return MINOR_VERSION; } - QString get_version_string(); + int get_release() const { return RELEASE; } + int get_major_version() const { return MAJOR_VERSION; } + int get_minor_version() const { return MINOR_VERSION; } + QString get_version_string(); - /////////////////////////////////////////// + /////////////////////////////////////////// - void set_favorite_list(); - QVector& get_favorite_list() {return favorite_list;} - void add_favorite_server(int p_server); + void set_favorite_list(); + QVector &get_favorite_list() { return favorite_list; } + void add_favorite_server(int p_server); - void set_server_list(); - QVector& get_server_list() {return server_list;} + void set_server_list(); + QVector &get_server_list() { return server_list; } - //reads the theme from config.ini and sets it accordingly - void reload_theme(); + //reads the theme from config.ini and sets it accordingly + void reload_theme(); - //Returns the character the player has currently selected - QString get_current_char(); + //Returns the character the player has currently selected + QString get_current_char(); - //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_character_path(QString p_char, QString p_file); - QString get_sounds_path(QString p_file); - QString get_music_path(QString p_song); - QString get_background_path(QString p_file); - QString get_default_background_path(QString p_file); - QString get_evidence_path(QString p_file); - QString get_case_sensitive_path(QString p_file); + //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_character_path(QString p_char, QString p_file); + QString get_sounds_path(QString p_file); + QString get_music_path(QString p_song); + QString get_background_path(QString p_file); + QString get_default_background_path(QString p_file); + QString get_evidence_path(QString p_file); + QString get_case_sensitive_path(QString p_file); - ////// Functions for reading and writing files ////// - // Implementations file_functions.cpp + ////// Functions for reading and writing files ////// + // Implementations file_functions.cpp - // Instead of reinventing the wheel, we'll use a QSettings class. - QSettings *configini; + // Instead of reinventing the wheel, we'll use a QSettings class. + QSettings *configini; - //Reads the theme from config.ini and loads it into the current_theme variable - QString read_theme(); + //Reads the theme from config.ini and loads it into the current_theme variable + QString read_theme(); - //Returns the value of ooc_name in config.ini - QString get_ooc_name(); + //Returns the value of ooc_name in config.ini + QString get_ooc_name(); - //Returns the blip rate from config.ini (once per X symbols) - int read_blip_rate(); + //Returns the blip rate from config.ini (once per X symbols) + int read_blip_rate(); - //Returns true if blank blips is enabled in config.ini and false otherwise - bool get_blank_blip(); + //Returns true if blank blips is enabled in config.ini and false otherwise + bool get_blank_blip(); - //Returns true if looping sound effects are enabled in the config.ini - bool get_looping_sfx(); + //Returns true if looping sound effects are enabled in the config.ini + bool get_looping_sfx(); - //Returns true if stop music on objection is enabled in the config.ini - bool objection_stop_music(); + //Returns true if stop music on objection is enabled in the config.ini + bool objection_stop_music(); - //Returns the value of default_music in config.ini - int get_default_music(); + //Returns the value of default_music in config.ini + int get_default_music(); - //Returns the value of default_sfx in config.ini - int get_default_sfx(); + //Returns the value of default_sfx in config.ini + int get_default_sfx(); - //Returns the value of default_blip in config.ini - int get_default_blip(); + //Returns the value of default_blip in config.ini + int get_default_blip(); - // Returns the value of whether Discord should be enabled on startup - // from the config.ini. - bool is_discord_enabled(); + // Returns the value of whether Discord should be enabled on startup + // from the config.ini. + bool is_discord_enabled(); - // Returns the value of whether shaking should be enabled. - // from the config.ini. - bool is_shake_enabled(); + // Returns the value of whether shaking should be enabled. + // from the config.ini. + bool is_shake_enabled(); - // Returns the value of whether effects should be enabled. - // from the config.ini. - bool is_effects_enabled(); + // Returns the value of whether effects should be enabled. + // from the config.ini. + bool is_effects_enabled(); - // Returns the value of whether frame-specific effects defined in char.ini should be sent/received over the network. - // from the config.ini. - bool is_frame_network_enabled(); + // Returns the value of whether frame-specific effects defined in char.ini should be sent/received over the network. + // from the config.ini. + bool is_frame_network_enabled(); - // Returns the value of whether colored ic log should be a thing. - // from the config.ini. - bool is_colorlog_enabled(); + // Returns the value of whether colored ic log should be a thing. + // from the config.ini. + bool is_colorlog_enabled(); - // Returns the value of whether sticky sounds should be a thing. - // from the config.ini. - bool is_stickysounds_enabled(); + // Returns the value of whether sticky sounds should be a thing. + // from the config.ini. + bool is_stickysounds_enabled(); - // Returns the value of whether sticky effects should be a thing. - // from the config.ini. - bool is_stickyeffects_enabled(); + // Returns the value of whether sticky effects should be a thing. + // from the config.ini. + bool is_stickyeffects_enabled(); - // Returns the value of whether sticky preanims should be a thing. - // from the config.ini. - bool is_stickypres_enabled(); + // Returns the value of whether sticky preanims should be a thing. + // from the config.ini. + bool is_stickypres_enabled(); - // Returns the value of the maximum amount of lines the IC chatlog - // may contain, from config.ini. - int get_max_log_size(); + // Returns the value of the maximum amount of lines the IC chatlog + // may contain, from config.ini. + int get_max_log_size(); - // Returns whether the log should go upwards (new behaviour) - // or downwards (vanilla behaviour). - bool get_log_goes_downwards(); + // Returns whether the log should go upwards (new behaviour) + // or downwards (vanilla behaviour). + bool get_log_goes_downwards(); - // Returns the username the user may have set in config.ini. - QString get_default_username(); + // Returns the username the user may have set in config.ini. + QString get_default_username(); - // Returns the audio device used for the client. - QString get_audio_output_device(); - #ifdef QTAUDIO - QAudioDeviceInfo QtAudioDevice; - #endif + // Returns the audio device used for the client. + QString get_audio_output_device(); +#ifdef QTAUDIO + QAudioDeviceInfo QtAudioDevice; +#endif - // Returns whether the user would like to have custom shownames on by default. - bool get_showname_enabled_by_default(); + // Returns whether the user would like to have custom shownames on by default. + bool get_showname_enabled_by_default(); - //Returns the list of words in callwords.ini - QStringList get_call_words(); + //Returns the list of words in callwords.ini + QStringList get_call_words(); - //returns all of the file's lines in a QStringList - QStringList get_list_file(QString p_file); + //returns all of the file's lines in a QStringList + QStringList get_list_file(QString p_file); - //Process a file and return its text as a QString - QString read_file(QString filename); + //Process a file and return its text as a QString + QString read_file(QString filename); - //Write text to file. make_dir would auto-create the directory if it doesn't exist. - bool write_to_file(QString p_text, QString p_file, bool make_dir = false); + //Write text to file. make_dir would auto-create the directory if it doesn't exist. + bool write_to_file(QString p_text, QString p_file, bool make_dir = false); - //Append text to the end of the file. make_dir would auto-create the directory if it doesn't exist. - bool append_to_file(QString p_text, QString p_file, bool make_dir = false); + //Append text to the end of the file. make_dir would auto-create the directory if it doesn't exist. + bool append_to_file(QString p_text, QString p_file, bool make_dir = false); - //Appends the argument string to serverlist.txt - void write_to_serverlist_txt(QString p_line); + //Appends the argument string to serverlist.txt + void write_to_serverlist_txt(QString p_line); - //Returns the contents of serverlist.txt - QVector read_serverlist_txt(); + //Returns the contents of serverlist.txt + QVector read_serverlist_txt(); - //Returns the value of p_identifier in the design.ini file in p_design_path - QString read_design_ini(QString p_identifier, QString p_design_path); + //Returns the value of p_identifier in the design.ini file in p_design_path + QString read_design_ini(QString p_identifier, QString p_design_path); - //Returns the coordinates of widget with p_identifier from p_file - QPoint get_button_spacing(QString p_identifier, QString p_file); + //Returns the coordinates of widget with p_identifier from p_file + QPoint get_button_spacing(QString p_identifier, QString p_file); - //Returns the dimensions of widget with specified identifier from p_file - pos_size_type get_element_dimensions(QString p_identifier, QString p_file, QString p_char=""); + //Returns the dimensions of widget with specified identifier from p_file + pos_size_type get_element_dimensions(QString p_identifier, QString p_file, QString p_char = ""); - //Returns the value to you - QString get_design_element(QString p_identifier, QString p_file, QString p_char=""); + //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); + //Returns the name of the font with p_identifier from p_file + QString get_font_name(QString p_identifier, QString p_file); - //Returns the value of font_size with p_identifier from p_file - int get_font_size(QString p_identifier, QString p_file); + //Returns the value of font_size with p_identifier from p_file + int get_font_size(QString p_identifier, QString p_file); - //Returns the color with p_identifier from p_file - QColor get_color(QString p_identifier, QString p_file); + //Returns the color with p_identifier from p_file + QColor get_color(QString p_identifier, QString p_file); - // Returns the markdown symbol used for specified p_identifier such as colors - QString get_chat_markdown(QString p_identifier, QString p_file); + // Returns the markdown symbol used for specified p_identifier such as colors + QString get_chat_markdown(QString p_identifier, QString p_file); - // Returns the color from the misc folder. - QColor get_chat_color(QString p_identifier, QString p_chat); + // 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); + //Returns the sfx with p_identifier from sounds.ini in the current theme path + QString get_sfx(QString p_identifier); - //Figure out if we can opus this or if we should fall back to wav - QString get_sfx_suffix(QString sound_to_check); + //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); + // 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); + // 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); - //Returns the value of p_search_line within target_tag and terminator_tag - QString read_char_ini(QString p_char, QString p_search_line, QString target_tag); + //Returns the value of p_search_line within target_tag and terminator_tag + QString read_char_ini(QString p_char, QString p_search_line, QString target_tag); - //Returns a QStringList of all key=value definitions on a given tag. - QStringList read_ini_tags(QString p_file, QString target_tag = ""); + //Returns a QStringList of all key=value definitions on a given tag. + QStringList read_ini_tags(QString p_file, QString target_tag = ""); - //Sets the char.ini p_search_line key under tag target_tag to value. - void set_char_ini(QString p_char, QString value, QString p_search_line, QString target_tag); + //Sets the char.ini p_search_line key under tag target_tag to value. + void set_char_ini(QString p_char, QString value, QString p_search_line, QString target_tag); - //Returns the text between target_tag and terminator_tag in p_file - QString get_stylesheet(QString p_file); + //Returns the text between target_tag and terminator_tag in p_file + QString get_stylesheet(QString p_file); - //Returns the text between target_tag and terminator_tag in p_file - QString get_tagged_stylesheet(QString target_tag, QString p_file); + //Returns the text between target_tag and terminator_tag in p_file + QString get_tagged_stylesheet(QString target_tag, QString p_file); - //Returns the side of the p_char character from that characters ini file - QString get_char_side(QString p_char); + //Returns the side of the p_char character from that characters ini file + QString get_char_side(QString p_char); - //Returns the showname from the ini of p_char - QString get_showname(QString p_char); + //Returns the showname from the ini of p_char + QString get_showname(QString p_char); - //Returns the value of chat image from the specific p_char's ini file - QString get_chat(QString p_char); + //Returns the value of chat image from the specific p_char's ini file + QString get_chat(QString p_char); - //Returns the value of chat font from the specific p_char's ini file - QString get_chat_font(QString p_char); + //Returns the value of chat font from the specific p_char's ini file + QString get_chat_font(QString p_char); - //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 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 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); + //Returns the preanim duration of p_char's p_emote + int get_preanim_duration(QString p_char, QString p_emote); - //Same as above, but only returns if it has a % in front(refer to Preanims section in the manual) - int get_ao2_preanim_duration(QString p_char, QString p_emote); + //Same as above, but only returns if it has a % in front(refer to Preanims section in the manual) + int get_ao2_preanim_duration(QString p_char, QString p_emote); - //Not in use - int get_text_delay(QString p_char, QString p_emote); + //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 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); + //Get the theme's effects folder, read it and return the list of filenames in a string + QStringList get_effects(QString p_char); - //t - QString get_effect(QString effect, QString p_char, QString p_folder); + //t + QString get_effect(QString effect, QString p_char, QString p_folder); - //Return the effect sound associated with the fx_name in the misc/effects//sounds.ini, or theme/effects/sounds.ini. - QString get_effect_sound(QString fx_name, QString p_char); + //Return the effect sound associated with the fx_name in the misc/effects//sounds.ini, or theme/effects/sounds.ini. + QString get_effect_sound(QString fx_name, QString p_char); - // Returns the custom realisation used by the character. - QString get_custom_realization(QString p_char); + // Returns the custom realisation used by the character. + QString get_custom_realization(QString p_char); - //Returns the name of p_char - QString get_char_name(QString p_char); + //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); + //Returns the total amount of emotes of p_char + int get_emote_number(QString p_char); - //Returns the emote comment of p_char's p_emote - QString get_emote_comment(QString p_char, int p_emote); + //Returns the emote comment of p_char's p_emote + QString get_emote_comment(QString p_char, int p_emote); - //Returns the base name of p_char's p_emote - QString get_emote(QString p_char, int p_emote); + //Returns the base name of p_char's p_emote + QString get_emote(QString p_char, int p_emote); - //Returns the preanimation name of p_char's p_emote - QString get_pre_emote(QString p_char, int p_emote); + //Returns the preanimation name of p_char's p_emote + QString get_pre_emote(QString p_char, int p_emote); - //Returns the sfx of p_char's p_emote - QString get_sfx_name(QString p_char, int p_emote); + //Returns the sfx of p_char's p_emote + QString get_sfx_name(QString p_char, int p_emote); - //Returns the blipsound of p_char's p_emote - QString get_emote_blip(QString p_char, int p_emote); + //Returns the blipsound of p_char's p_emote + QString get_emote_blip(QString p_char, int p_emote); - //Returns if the sfx is defined as looping in char.ini - QString get_sfx_looping(QString p_char, QString p_sfx); + //Returns if the sfx is defined as looping in char.ini + QString get_sfx_looping(QString p_char, QString p_sfx); - //Returns if an emote has a frame specific SFX for it - QString get_sfx_frame(QString p_char, QString p_emote, int n_frame); + //Returns if an emote has a frame specific SFX for it + QString get_sfx_frame(QString p_char, QString p_emote, int n_frame); - //Returns if an emote has a frame specific SFX for it - QString get_flash_frame(QString p_char, QString p_emote, int n_frame); + //Returns if an emote has a frame specific SFX for it + QString get_flash_frame(QString p_char, QString p_emote, int n_frame); - //Returns if an emote has a frame specific SFX for it - QString get_screenshake_frame(QString p_char, QString p_emote, int n_frame); + //Returns if an emote has a frame specific SFX for it + QString get_screenshake_frame(QString p_char, QString p_emote, int n_frame); - //Not in use - int get_sfx_delay(QString p_char, int p_emote); + //Not in use + int get_sfx_delay(QString p_char, int p_emote); - //Returns the modifier for p_char's p_emote - int get_emote_mod(QString p_char, int p_emote); + //Returns the modifier for p_char's p_emote + int get_emote_mod(QString p_char, int p_emote); - //Returns the desk modifier for p_char's p_emote - int get_desk_mod(QString p_char, int p_emote); + //Returns the desk modifier for p_char's p_emote + int get_desk_mod(QString p_char, int p_emote); - //Returns p_char's gender - QString get_gender(QString p_char); + //Returns p_char's gender + QString get_gender(QString p_char); - // ====== - // These are all casing-related settings. - // ====== + // ====== + // These are all casing-related settings. + // ====== - // Returns if the user has casing alerts enabled. - bool get_casing_enabled(); + // Returns if the user has casing alerts enabled. + bool get_casing_enabled(); - // Returns if the user wants to get alerts for the defence role. - bool get_casing_defence_enabled(); + // Returns if the user wants to get alerts for the defence role. + bool get_casing_defence_enabled(); - // Same for prosecution. - bool get_casing_prosecution_enabled(); + // Same for prosecution. + bool get_casing_prosecution_enabled(); - // Same for judge. - bool get_casing_judge_enabled(); + // Same for judge. + bool get_casing_judge_enabled(); - // Same for juror. - bool get_casing_juror_enabled(); + // Same for juror. + bool get_casing_juror_enabled(); - // Same for steno. - bool get_casing_steno_enabled(); + // Same for steno. + bool get_casing_steno_enabled(); - // Same for CM. - bool get_casing_cm_enabled(); + // Same for CM. + bool get_casing_cm_enabled(); - // Get the message for the CM for casing alerts. - QString get_casing_can_host_cases(); + // Get the message for the CM for casing alerts. + QString get_casing_can_host_cases(); - //The file name of the log file in base/logs. - QString log_filename; + //The file name of the log file in base/logs. + QString log_filename; private: - const int RELEASE = 2; - const int MAJOR_VERSION = 8; - const int MINOR_VERSION = 3; + const int RELEASE = 2; + const int MAJOR_VERSION = 8; + const int MINOR_VERSION = 3; - QString current_theme = "default"; + QString current_theme = "default"; - QVector server_list; - QVector favorite_list; + QVector server_list; + QVector favorite_list; private slots: - void ms_connect_finished(bool connected, bool will_retry); + void ms_connect_finished(bool connected, bool will_retry); public slots: - void server_disconnected(); - void loading_cancelled(); + void server_disconnected(); + void loading_cancelled(); }; #endif // AOAPPLICATION_H diff --git a/include/aoblipplayer.h b/include/aoblipplayer.h index a848e80..db6dfce 100644 --- a/include/aoblipplayer.h +++ b/include/aoblipplayer.h @@ -10,38 +10,36 @@ #include "aoapplication.h" +#include +#include #include #include -#include -#include - -class AOBlipPlayer -{ +class AOBlipPlayer { public: - AOBlipPlayer(QWidget *parent, AOApplication *p_ao_app); + AOBlipPlayer(QWidget *parent, AOApplication *p_ao_app); - void set_blips(QString p_sfx); - void blip_tick(); - void set_volume(qreal p_volume); + void set_blips(QString p_sfx); + void blip_tick(); + void set_volume(qreal p_volume); - int m_cycle = 0; + int m_cycle = 0; private: - const int max_blip_ms = 60; + const int max_blip_ms = 60; - QWidget *m_parent; - AOApplication *ao_app; - qreal m_volume; - QElapsedTimer delay; + QWidget *m_parent; + AOApplication *ao_app; + qreal m_volume; + QElapsedTimer delay; - void set_volume_internal(qreal p_volume); + void set_volume_internal(qreal p_volume); - #if defined(BASSAUDIO) - HSTREAM m_stream_list[5]; - #elif defined(QTAUDIO) - QSoundEffect m_blips; - #endif +#if defined(BASSAUDIO) + HSTREAM m_stream_list[5]; +#elif defined(QTAUDIO) + QSoundEffect m_blips; +#endif }; #endif // AOBLIPPLAYER_H diff --git a/include/aobutton.h b/include/aobutton.h index 4b7209a..598d2c0 100644 --- a/include/aobutton.h +++ b/include/aobutton.h @@ -3,20 +3,19 @@ #include "aoapplication.h" -#include #include +#include -class AOButton : public QPushButton -{ - Q_OBJECT +class AOButton : public QPushButton { + Q_OBJECT public: - AOButton(QWidget *parent, AOApplication *p_ao_app); - ~AOButton(); + AOButton(QWidget *parent, AOApplication *p_ao_app); + ~AOButton(); - AOApplication *ao_app; + AOApplication *ao_app; - void set_image(QString p_image); + void set_image(QString p_image); }; #endif // AOBUTTON_H diff --git a/include/aocaseannouncerdialog.h b/include/aocaseannouncerdialog.h index a238c3f..930fa41 100644 --- a/include/aocaseannouncerdialog.h +++ b/include/aocaseannouncerdialog.h @@ -4,42 +4,41 @@ #include "aoapplication.h" #include "courtroom.h" -#include #include -#include -#include #include +#include +#include #include #include +#include -class AOCaseAnnouncerDialog : public QDialog -{ - Q_OBJECT +class AOCaseAnnouncerDialog : public QDialog { + Q_OBJECT public: - explicit AOCaseAnnouncerDialog(QWidget *parent = nullptr, AOApplication *p_ao_app = nullptr, Courtroom *p_court = nullptr); + explicit AOCaseAnnouncerDialog(QWidget *parent = nullptr, AOApplication *p_ao_app = nullptr, Courtroom *p_court = nullptr); private: - AOApplication *ao_app; - Courtroom *court; + AOApplication *ao_app; + Courtroom *court; - QDialogButtonBox *ui_announcer_buttons; + QDialogButtonBox *ui_announcer_buttons; - QVBoxLayout *ui_vbox_layout; - QFormLayout *ui_form_layout; + QVBoxLayout *ui_vbox_layout; + QFormLayout *ui_form_layout; - QLabel *ui_case_title_label; - QLineEdit *ui_case_title_textbox; + QLabel *ui_case_title_label; + QLineEdit *ui_case_title_textbox; - QCheckBox *ui_defense_needed; - QCheckBox *ui_prosecutor_needed; - QCheckBox *ui_judge_needed; - QCheckBox *ui_juror_needed; - QCheckBox *ui_steno_needed; + QCheckBox *ui_defense_needed; + QCheckBox *ui_prosecutor_needed; + QCheckBox *ui_judge_needed; + QCheckBox *ui_juror_needed; + QCheckBox *ui_steno_needed; public slots: - void ok_pressed(); - void cancel_pressed(); + void ok_pressed(); + void cancel_pressed(); }; #endif // AOCASEANNOUNCERDIALOG_H diff --git a/include/aocharbutton.h b/include/aocharbutton.h index f372cdf..a536792 100644 --- a/include/aocharbutton.h +++ b/include/aocharbutton.h @@ -4,41 +4,40 @@ #include "aoapplication.h" #include "aoimage.h" +#include #include #include #include -#include -class AOCharButton : public QPushButton -{ - Q_OBJECT +class AOCharButton : public QPushButton { + Q_OBJECT public: - AOCharButton(QWidget *parent, AOApplication *p_ao_app, int x_pos, int y_pos, bool is_taken); + AOCharButton(QWidget *parent, AOApplication *p_ao_app, int x_pos, int y_pos, bool is_taken); - AOApplication *ao_app; + AOApplication *ao_app; - void refresh(); - void reset(); - void set_taken(bool is_taken); - void set_passworded(); + void refresh(); + void reset(); + void set_taken(bool is_taken); + void set_passworded(); - void apply_taken_image(); + void apply_taken_image(); - void set_image(QString p_character); + void set_image(QString p_character); private: - bool taken; + bool taken; - QWidget *m_parent; + QWidget *m_parent; - AOImage *ui_taken; - AOImage *ui_passworded; - AOImage *ui_selector; + AOImage *ui_taken; + AOImage *ui_passworded; + AOImage *ui_selector; protected: - void enterEvent(QEvent *e); - void leaveEvent(QEvent *e); + void enterEvent(QEvent *e); + void leaveEvent(QEvent *e); }; #endif // AOCHARBUTTON_H diff --git a/include/aocharmovie.h b/include/aocharmovie.h index 15fa7cf..2a185dd 100644 --- a/include/aocharmovie.h +++ b/include/aocharmovie.h @@ -1,120 +1,118 @@ #ifndef AOCHARMOVIE_H #define AOCHARMOVIE_H +#include +#include #include #include #include -#include -#include -#include class AOApplication; -class AOCharMovie : public QLabel -{ - Q_OBJECT +class AOCharMovie : public QLabel { + Q_OBJECT public: - AOCharMovie(QWidget *p_parent, AOApplication *p_ao_app); + AOCharMovie(QWidget *p_parent, AOApplication *p_ao_app); - //Play a hat.gif - style preanimation - void play_pre(QString p_char, QString p_emote, int duration); + //Play a hat.gif - style preanimation + void play_pre(QString p_char, QString p_emote, int duration); - //Play a (b)normal.gif - style animation (talking) - void play_talking(QString p_char, QString p_emote); + //Play a (b)normal.gif - style animation (talking) + void play_talking(QString p_char, QString p_emote); - //Play an (a)normal.gif - style animation (not talking) - void play_idle(QString p_char, QString p_emote); + //Play an (a)normal.gif - style animation (not talking) + void play_idle(QString p_char, QString p_emote); - //Stop the movie, clearing the image - void stop(); + //Stop the movie, clearing the image + void stop(); - //Set the m_flipped variable to true/false - void set_flipped(bool p_flipped) {m_flipped = p_flipped;} + //Set the m_flipped variable to true/false + void set_flipped(bool p_flipped) { m_flipped = p_flipped; } - //Set the movie's playback speed (between 10% and 1000%) - void set_speed(int modifier) {speed = qMax(10, qMin(modifier, 1000));} + //Set the movie's playback speed (between 10% and 1000%) + void set_speed(int modifier) { speed = qMax(10, qMin(modifier, 1000)); } - //Move the label itself around - void move(int ax, int ay); + //Move the label itself around + void move(int ax, int ay); - //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); + //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); - //Return the frame delay adjusted for speed - int get_frame_delay(int delay); + //Return the frame delay adjusted for speed + int get_frame_delay(int delay); - QStringList network_strings; + QStringList network_strings; - QString m_char; - QString m_emote; + QString m_char; + QString m_emote; private: - AOApplication *ao_app; + AOApplication *ao_app; - QVector movie_frames; - QVector movie_delays; + QVector movie_frames; + QVector movie_delays; - //Effects such as sfx, screenshakes and realization flashes are stored in here. - //QString entry format: "sfx^[sfx_name]", "shake", "flash". - //The program uses the QVector index as reference. - QVector> movie_effects; + //Effects such as sfx, screenshakes and realization flashes are stored in here. + //QString entry format: "sfx^[sfx_name]", "shake", "flash". + //The program uses the QVector index as reference. + QVector> movie_effects; - QTimer *preanim_timer; - QTimer *ticker; - QString last_path; - QImageReader *m_reader = new QImageReader(); + QTimer *preanim_timer; + QTimer *ticker; + QString last_path; + QImageReader *m_reader = new QImageReader(); - QElapsedTimer actual_time; + QElapsedTimer actual_time; - //Usually used to turn seconds into milliseconds such as for [Time] tag in char.ini - const int time_mod = 60; + //Usually used to turn seconds into milliseconds such as for [Time] tag in char.ini + const int time_mod = 60; - // These are the X and Y values before they are fixed based on the sprite's width. - int x = 0; - int y = 0; - // These are the width and height values before they are fixed based on the sprite's width. - int f_w = 0; - int f_h = 0; + // These are the X and Y values before they are fixed based on the sprite's width. + int x = 0; + int y = 0; + // These are the width and height values before they are fixed based on the sprite's width. + int f_w = 0; + int f_h = 0; - int frame = 0; - int max_frames = 0; + int frame = 0; + int max_frames = 0; - int speed = 100; + int speed = 100; - bool m_flipped = false; - bool play_once = true; + bool m_flipped = false; + bool play_once = true; - //Set the movie's image to provided paths, preparing for playback. - void load_image(QString p_char, QString p_emote, QString emote_prefix); + //Set the movie's image to provided paths, preparing for playback. + void load_image(QString p_char, QString p_emote, QString emote_prefix); - //Start playback of the movie (if animated). - void play(); + //Start playback of the movie (if animated). + void play(); - //Play a frame-specific effect, if there's any defined for that specific frame. - void play_frame_effect(int frame); + //Play a frame-specific effect, if there's any defined for that specific frame. + void play_frame_effect(int frame); - //Retreive a pixmap adjused for mirroring/aspect ratio shenanigans from a provided QImage - QPixmap get_pixmap(QImage image); + //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); + //Set the movie's frame to provided pixmap + void set_frame(QPixmap f_pixmap); - //Initialize the frame-specific effects from the char.ini - void load_effects(); + //Initialize the frame-specific effects from the char.ini + void load_effects(); - //Initialize the frame-specific effects from the provided network_strings, this is only initialized if network_strings has size more than 0. - void load_network_effects(); + //Initialize the frame-specific effects from the provided network_strings, this is only initialized if network_strings has size more than 0. + void load_network_effects(); signals: - void done(); - void shake(); - void flash(); - void play_sfx(QString sfx); + void done(); + void shake(); + void flash(); + void play_sfx(QString sfx); private slots: - void preanim_done(); - void movie_ticker(); + void preanim_done(); + void movie_ticker(); }; #endif // AOCHARMOVIE_H diff --git a/include/aoemotebutton.h b/include/aoemotebutton.h index a13688b..8674bb0 100644 --- a/include/aoemotebutton.h +++ b/include/aoemotebutton.h @@ -3,33 +3,32 @@ #include "aoapplication.h" -#include #include +#include -class AOEmoteButton : public QPushButton -{ - Q_OBJECT +class AOEmoteButton : public QPushButton { + Q_OBJECT public: - AOEmoteButton(QWidget *p_parent, AOApplication *p_ao_app, int p_x, int p_y, int p_w, int p_h); + AOEmoteButton(QWidget *p_parent, AOApplication *p_ao_app, int p_x, int p_y, int p_w, int p_h); - void set_image(QString p_image, QString p_emote_comment); - void set_char_image(QString p_char, int p_emote, QString suffix); + void set_image(QString p_image, QString p_emote_comment); + void set_char_image(QString p_char, int p_emote, QString suffix); - void set_id(int p_id) {m_id = p_id;} - int get_id() {return m_id;} + void set_id(int p_id) { m_id = p_id; } + int get_id() { return m_id; } private: - QWidget *parent; - AOApplication *ao_app; + QWidget *parent; + AOApplication *ao_app; - int m_id = 0; + int m_id = 0; signals: - void emote_clicked(int p_id); + void emote_clicked(int p_id); private slots: - void on_clicked(); + void on_clicked(); }; #endif // AOEMOTEBUTTON_H diff --git a/include/aoevidencebutton.h b/include/aoevidencebutton.h index 53fa11f..2ac6860 100644 --- a/include/aoevidencebutton.h +++ b/include/aoevidencebutton.h @@ -4,48 +4,47 @@ #include "aoapplication.h" #include "aoimage.h" +#include #include #include -#include -class AOEvidenceButton : public QPushButton -{ - Q_OBJECT +class AOEvidenceButton : public QPushButton { + Q_OBJECT public: - AOEvidenceButton(QWidget *p_parent, AOApplication *p_ao_app, int p_x, int p_y, int p_w, int p_h); + AOEvidenceButton(QWidget *p_parent, AOApplication *p_ao_app, int p_x, int p_y, int p_w, int p_h); - void set_image(QString p_image); - void set_theme_image(QString p_image); - void set_id(int p_id) {m_id = p_id;} + void set_image(QString p_image); + void set_theme_image(QString p_image); + void set_id(int p_id) { m_id = p_id; } - void set_selected(bool p_selected); + void set_selected(bool p_selected); private: - AOApplication *ao_app; - QWidget *m_parent; + AOApplication *ao_app; + QWidget *m_parent; - AOImage *ui_selected; - AOImage *ui_selector; + AOImage *ui_selected; + AOImage *ui_selector; - int m_id = 0; + int m_id = 0; protected: - void enterEvent(QEvent *e); - void leaveEvent(QEvent *e); - void mouseDoubleClickEvent(QMouseEvent *e); - /* + void enterEvent(QEvent *e); + void leaveEvent(QEvent *e); + void mouseDoubleClickEvent(QMouseEvent *e); + /* void dragLeaveEvent(QMouseEvent *e); void dragEnterEvent(QMouseEvent *e); */ signals: - void evidence_clicked(int p_id); - void evidence_double_clicked(int p_id); - void on_hover(int p_id, bool p_state); + void evidence_clicked(int p_id); + void evidence_double_clicked(int p_id); + void on_hover(int p_id, bool p_state); private slots: - void on_clicked(); + void on_clicked(); }; #endif // AOEVIDENCEBUTTON_H diff --git a/include/aoevidencedisplay.h b/include/aoevidencedisplay.h index 93455c0..0315ffc 100644 --- a/include/aoevidencedisplay.h +++ b/include/aoevidencedisplay.h @@ -2,32 +2,31 @@ #define AOEVIDENCEDISPLAY_H #include "aoapplication.h" -#include "aosfxplayer.h" #include "aomovie.h" +#include "aosfxplayer.h" -#include #include +#include -class AOEvidenceDisplay : public QLabel -{ - Q_OBJECT +class AOEvidenceDisplay : public QLabel { + Q_OBJECT public: - AOEvidenceDisplay(QWidget *p_parent, AOApplication *p_ao_app); + AOEvidenceDisplay(QWidget *p_parent, AOApplication *p_ao_app); - void show_evidence(QString p_evidence_image, bool is_left_side, int p_volume); - QLabel* get_evidence_icon(); - void reset(); - void combo_resize(int w, int h); + void show_evidence(QString p_evidence_image, bool is_left_side, int p_volume); + QLabel *get_evidence_icon(); + void reset(); + void combo_resize(int w, int h); private: - AOApplication *ao_app; - AOMovie *evidence_movie; - QLabel *evidence_icon; - AOSfxPlayer *sfx_player; + AOApplication *ao_app; + AOMovie *evidence_movie; + QLabel *evidence_icon; + AOSfxPlayer *sfx_player; private slots: - void show_done(); + void show_done(); }; #endif // AOEVIDENCEDISPLAY_H diff --git a/include/aoimage.h b/include/aoimage.h index 25c8e06..a6960de 100644 --- a/include/aoimage.h +++ b/include/aoimage.h @@ -5,21 +5,20 @@ #include "aoapplication.h" -#include #include +#include -class AOImage : public QLabel -{ +class AOImage : public QLabel { public: - AOImage(QWidget *parent, AOApplication *p_ao_app); - ~AOImage(); + AOImage(QWidget *parent, AOApplication *p_ao_app); + ~AOImage(); - QWidget *m_parent; - AOApplication *ao_app; + QWidget *m_parent; + AOApplication *ao_app; - bool set_image(QString p_image); - bool set_chatbox(QString p_path); - void set_size_and_pos(QString identifier); + bool set_image(QString p_image); + bool set_chatbox(QString p_path); + void set_size_and_pos(QString identifier); }; #endif // AOIMAGE_H diff --git a/include/aolineedit.h b/include/aolineedit.h index 0952172..06206a9 100644 --- a/include/aolineedit.h +++ b/include/aolineedit.h @@ -4,24 +4,23 @@ #include #include -class AOLineEdit : public QLineEdit -{ - Q_OBJECT +class AOLineEdit : public QLineEdit { + Q_OBJECT public: - AOLineEdit(QWidget *parent); + AOLineEdit(QWidget *parent); - void preserve_selection(bool toggle) {p_selection = toggle;} + void preserve_selection(bool toggle) { p_selection = toggle; } private: - bool p_selection = false; + bool p_selection = false; protected: - void mouseDoubleClickEvent(QMouseEvent *e); - void focusOutEvent(QFocusEvent *ev); + void mouseDoubleClickEvent(QMouseEvent *e); + void focusOutEvent(QFocusEvent *ev); signals: - void double_clicked(); + void double_clicked(); }; #endif // AOLINEEDIT_H diff --git a/include/aomovie.h b/include/aomovie.h index ec28619..8d60442 100644 --- a/include/aomovie.h +++ b/include/aomovie.h @@ -7,30 +7,29 @@ class Courtroom; class AOApplication; -class AOMovie : public QLabel -{ - Q_OBJECT +class AOMovie : public QLabel { + Q_OBJECT public: - AOMovie(QWidget *p_parent, AOApplication *p_ao_app); + AOMovie(QWidget *p_parent, AOApplication *p_ao_app); - void set_play_once(bool p_play_once); - void play(QString p_image, QString p_char = "", QString p_custom_theme = "", int default_duration = 0); - void combo_resize(int w, int h); - void stop(); + void set_play_once(bool p_play_once); + void play(QString p_image, QString p_char = "", QString p_custom_theme = "", int default_duration = 0); + void combo_resize(int w, int h); + void stop(); private: - QMovie *m_movie; - AOApplication *ao_app; - QTimer *timer; - bool play_once = true; + QMovie *m_movie; + AOApplication *ao_app; + QTimer *timer; + bool play_once = true; signals: - void done(); + void done(); private slots: - void frame_change(int n_frame); - void timer_done(); + void frame_change(int n_frame); + void timer_done(); }; #endif // AOMOVIE_H diff --git a/include/aomusicplayer.h b/include/aomusicplayer.h index 1a53582..d28a3ed 100644 --- a/include/aomusicplayer.h +++ b/include/aomusicplayer.h @@ -10,73 +10,70 @@ #endif #include "aoapplication.h" +#include #include #include -#include #if defined(BASSAUDIO) -class AOMusicPlayer -{ +class AOMusicPlayer { public: - AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app); - virtual ~AOMusicPlayer(); - void set_volume(int p_value, int channel=-1); - void set_looping(bool toggle, int channel=0); + AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app); + virtual ~AOMusicPlayer(); + void set_volume(int p_value, int channel = -1); + void set_looping(bool toggle, int channel = 0); - const int m_channelmax = 4; + const int m_channelmax = 4; - //These have to be public for the stupid sync thing - QWORD loop_start = 0; - QWORD loop_end = 0; + //These have to be public for the stupid sync thing + QWORD loop_start = 0; + QWORD loop_end = 0; public slots: - void play(QString p_song, int channel=0, bool loop=false, int effect_flags=0); - void stop(int channel=0); + void play(QString p_song, int channel = 0, bool loop = false, int effect_flags = 0); + void stop(int channel = 0); private: - QWidget *m_parent; - AOApplication *ao_app; + QWidget *m_parent; + AOApplication *ao_app; - bool m_looping = false; - int m_volume[4] = {0, 0, 0, 0}; + bool m_looping = false; + int m_volume[4] = {0, 0, 0, 0}; - // Channel 0 = music - // Channel 1 = ambience - // Channel 2 = extra - // Channel 3 = extra - HSTREAM m_stream_list[4]; - HSYNC loop_sync[4]; + // Channel 0 = music + // Channel 1 = ambience + // Channel 2 = extra + // Channel 3 = extra + HSTREAM m_stream_list[4]; + HSYNC loop_sync[4]; }; #elif defined(QTAUDIO) -class AOMusicPlayer -{ +class AOMusicPlayer { public: - AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app); - ~AOMusicPlayer(); + AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app); + ~AOMusicPlayer(); - void play(QString p_song); - void set_volume(int p_value); + void play(QString p_song); + void set_volume(int p_value); private: - QMediaPlayer m_player; - QWidget *m_parent; - AOApplication *ao_app; + QMediaPlayer m_player; + QWidget *m_parent; + AOApplication *ao_app; - int m_volume = 0; + int m_volume = 0; }; #else -class AOMusicPlayer -{ +class AOMusicPlayer { public: - AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app); - ~AOMusicPlayer(); + AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app); + ~AOMusicPlayer(); - void play(QString p_song); - void set_volume(int p_value); + void play(QString p_song); + void set_volume(int p_value); private: - QWidget *m_parent; - AOApplication *ao_app; + QWidget *m_parent; + AOApplication *ao_app; }; #endif diff --git a/include/aooptionsdialog.h b/include/aooptionsdialog.h index 4a63ca3..f9c369d 100644 --- a/include/aooptionsdialog.h +++ b/include/aooptionsdialog.h @@ -21,17 +21,16 @@ #include #include #include +#include #include #include #include #include -#include #include #include -class AOOptionsDialog: public QDialog -{ +class AOOptionsDialog : public QDialog { Q_OBJECT public: explicit AOOptionsDialog(QWidget *parent = nullptr, AOApplication *p_ao_app = nullptr); diff --git a/include/aopacket.h b/include/aopacket.h index 21f6e0f..4133fd5 100644 --- a/include/aopacket.h +++ b/include/aopacket.h @@ -1,32 +1,31 @@ #ifndef AOPACKET_H #define AOPACKET_H +#include #include #include -#include -class AOPacket -{ +class AOPacket { public: - AOPacket(QString p_packet_string); - AOPacket(QString header, QStringList &p_contents); - ~AOPacket(); + AOPacket(QString p_packet_string); + AOPacket(QString header, QStringList &p_contents); + ~AOPacket(); - QString get_header() {return m_header;} - QStringList &get_contents() {return m_contents;} - QString to_string(); + QString get_header() { return m_header; } + QStringList &get_contents() { return m_contents; } + QString to_string(); - void encrypt_header(unsigned int p_key); - void decrypt_header(unsigned int p_key); + void encrypt_header(unsigned int p_key); + void decrypt_header(unsigned int p_key); - void net_encode(); - void net_decode(); + void net_encode(); + void net_decode(); private: - bool encrypted = false; + bool encrypted = false; - QString m_header; - QStringList m_contents; + QString m_header; + QStringList m_contents; }; #endif // AOPACKET_H diff --git a/include/aoscene.h b/include/aoscene.h index 46d8c3b..3093b0f 100644 --- a/include/aoscene.h +++ b/include/aoscene.h @@ -1,39 +1,39 @@ #ifndef AOSCENE_H #define AOSCENE_H -#include #include +#include #include class Courtroom; class AOApplication; -class AOScene : public QLabel -{ - Q_OBJECT +class AOScene : public QLabel { + Q_OBJECT public: - explicit AOScene(QWidget *parent, AOApplication *p_ao_app); + explicit AOScene(QWidget *parent, AOApplication *p_ao_app); - void set_image(QString p_image); - void set_legacy_desk(QString p_image); + void set_image(QString p_image); + void set_legacy_desk(QString p_image); - //Move the label itself around - void move(int ax, int ay); + //Move the label itself around + void move(int ax, int ay); + + //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); - //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); private: - QWidget *m_parent; - QMovie *m_movie; - AOApplication *ao_app; - QString last_image; + QWidget *m_parent; + QMovie *m_movie; + AOApplication *ao_app; + QString last_image; - // These are the X and Y values before they are fixed based on the sprite's width. - int x = 0; - int y = 0; - // These are the width and height values before they are fixed based on the sprite's width. - int f_w = 0; - int f_h = 0; + // These are the X and Y values before they are fixed based on the sprite's width. + int x = 0; + int y = 0; + // These are the width and height values before they are fixed based on the sprite's width. + int f_w = 0; + int f_h = 0; }; #endif // AOSCENE_H diff --git a/include/aosfxplayer.h b/include/aosfxplayer.h index 3ae8bdf..4488aa6 100644 --- a/include/aosfxplayer.h +++ b/include/aosfxplayer.h @@ -10,36 +10,36 @@ #include "aoapplication.h" +#include #include #include -#include -class AOSfxPlayer -{ +class AOSfxPlayer { public: - AOSfxPlayer(QWidget *parent, AOApplication *p_ao_app); + AOSfxPlayer(QWidget *parent, AOApplication *p_ao_app); + + void clear(); + void loop_clear(); + void play(QString p_sfx, QString p_char = "", QString shout = "", int channel = -1); + void stop(int channel = -1); + void set_volume(qreal p_volume); + void set_looping(bool toggle, int channel = -1); + int m_channel = 0; - void clear(); - void loop_clear(); - void play(QString p_sfx, QString p_char = "", QString shout = "", int channel=-1); - void stop(int channel=-1); - void set_volume(qreal p_volume); - void set_looping(bool toggle, int channel=-1); - int m_channel = 0; private: - QWidget *m_parent; - AOApplication *ao_app; - qreal m_volume = 0; + QWidget *m_parent; + AOApplication *ao_app; + qreal m_volume = 0; - bool m_looping = true; - void set_volume_internal(qreal p_volume); + bool m_looping = true; + void set_volume_internal(qreal p_volume); - #if defined(BASSAUDIO) - const int m_channelmax = 5; - HSTREAM m_stream_list[5]; - #elif defined(QTAUDIO) - QSoundEffect m_sfx; - #endif +#if defined(BASSAUDIO) + const int m_channelmax = 5; + HSTREAM m_stream_list[5]; +#elif defined(QTAUDIO) + QSoundEffect m_sfx; +#endif }; #endif // AOSFXPLAYER_H diff --git a/include/aotextarea.h b/include/aotextarea.h index 643a8e3..8bf5199 100644 --- a/include/aotextarea.h +++ b/include/aotextarea.h @@ -1,25 +1,24 @@ #ifndef AOTEXTAREA_H #define AOTEXTAREA_H -#include -#include -#include -#include #include +#include +#include +#include +#include -class AOTextArea : public QTextBrowser -{ +class AOTextArea : public QTextBrowser { public: - AOTextArea(QWidget *p_parent = nullptr); + AOTextArea(QWidget *p_parent = nullptr); - void append_linked(QString p_message); - void append_chatmessage(QString p_name, QString p_message, QString p_colur); - void append_error(QString p_message); + void append_linked(QString p_message); + void append_chatmessage(QString p_name, QString p_message, QString p_colur); + void append_error(QString p_message); private: - const QRegExp url_parser_regex = QRegExp("\\b(https?://\\S+\\.\\S+)\\b"); + const QRegExp url_parser_regex = QRegExp("\\b(https?://\\S+\\.\\S+)\\b"); - void auto_scroll(QTextCursor old_cursor, int scrollbar_value, bool is_scrolled_down); + void auto_scroll(QTextCursor old_cursor, int scrollbar_value, bool is_scrolled_down); }; #endif // AOTEXTAREA_H diff --git a/include/aotextedit.h b/include/aotextedit.h index 85909c6..eb2c356 100644 --- a/include/aotextedit.h +++ b/include/aotextedit.h @@ -3,21 +3,19 @@ #include -class AOTextEdit : public QPlainTextEdit -{ - Q_OBJECT +class AOTextEdit : public QPlainTextEdit { + Q_OBJECT public: - AOTextEdit(QWidget *parent); + AOTextEdit(QWidget *parent); protected: - void mouseDoubleClickEvent(QMouseEvent *e); + void mouseDoubleClickEvent(QMouseEvent *e); signals: - void double_clicked(); + void double_clicked(); private slots: - void on_enter_pressed(); - + void on_enter_pressed(); }; #endif // AOTEXTEDIT_H diff --git a/include/bass.h b/include/bass.h index 388d406..4180a37 100644 --- a/include/bass.h +++ b/include/bass.h @@ -27,19 +27,19 @@ typedef int BOOL; #define FALSE 0 #endif #define LOBYTE(a) (BYTE)(a) -#define HIBYTE(a) (BYTE)((a)>>8) +#define HIBYTE(a) (BYTE)((a) >> 8) #define LOWORD(a) (WORD)(a) -#define HIWORD(a) (WORD)((a)>>16) -#define MAKEWORD(a,b) (WORD)(((a)&0xff)|((b)<<8)) -#define MAKELONG(a,b) (DWORD)(((a)&0xffff)|((b)<<16)) +#define HIWORD(a) (WORD)((a) >> 16) +#define MAKEWORD(a, b) (WORD)(((a)&0xff) | ((b) << 8)) +#define MAKELONG(a, b) (DWORD)(((a)&0xffff) | ((b) << 16)) #endif #ifdef __cplusplus extern "C" { #endif -#define BASSVERSION 0x204 // API version -#define BASSVERSIONTEXT "2.4" +#define BASSVERSION 0x204 // API version +#define BASSVERSIONTEXT "2.4" #ifndef BASSDEF #define BASSDEF(f) WINAPI f @@ -47,397 +47,396 @@ extern "C" { #define NOBASSOVERLOADS #endif -typedef DWORD HMUSIC; // MOD music handle -typedef DWORD HSAMPLE; // sample handle -typedef DWORD HCHANNEL; // playing sample's channel handle -typedef DWORD HSTREAM; // sample stream handle -typedef DWORD HRECORD; // recording handle -typedef DWORD HSYNC; // synchronizer handle -typedef DWORD HDSP; // DSP handle -typedef DWORD HFX; // DX8 effect handle -typedef DWORD HPLUGIN; // Plugin handle +typedef DWORD HMUSIC; // MOD music handle +typedef DWORD HSAMPLE; // sample handle +typedef DWORD HCHANNEL; // playing sample's channel handle +typedef DWORD HSTREAM; // sample stream handle +typedef DWORD HRECORD; // recording handle +typedef DWORD HSYNC; // synchronizer handle +typedef DWORD HDSP; // DSP handle +typedef DWORD HFX; // DX8 effect handle +typedef DWORD HPLUGIN; // Plugin handle // Error codes returned by BASS_ErrorGetCode -#define BASS_OK 0 // all is OK -#define BASS_ERROR_MEM 1 // memory error -#define BASS_ERROR_FILEOPEN 2 // can't open the file -#define BASS_ERROR_DRIVER 3 // can't find a free/valid driver -#define BASS_ERROR_BUFLOST 4 // the sample buffer was lost -#define BASS_ERROR_HANDLE 5 // invalid handle -#define BASS_ERROR_FORMAT 6 // unsupported sample format -#define BASS_ERROR_POSITION 7 // invalid position -#define BASS_ERROR_INIT 8 // BASS_Init has not been successfully called -#define BASS_ERROR_START 9 // BASS_Start has not been successfully called -#define BASS_ERROR_SSL 10 // SSL/HTTPS support isn't available -#define BASS_ERROR_ALREADY 14 // already initialized/paused/whatever -#define BASS_ERROR_NOCHAN 18 // can't get a free channel -#define BASS_ERROR_ILLTYPE 19 // an illegal type was specified -#define BASS_ERROR_ILLPARAM 20 // an illegal parameter was specified -#define BASS_ERROR_NO3D 21 // no 3D support -#define BASS_ERROR_NOEAX 22 // no EAX support -#define BASS_ERROR_DEVICE 23 // illegal device number -#define BASS_ERROR_NOPLAY 24 // not playing -#define BASS_ERROR_FREQ 25 // illegal sample rate -#define BASS_ERROR_NOTFILE 27 // the stream is not a file stream -#define BASS_ERROR_NOHW 29 // no hardware voices available -#define BASS_ERROR_EMPTY 31 // the MOD music has no sequence data -#define BASS_ERROR_NONET 32 // no internet connection could be opened -#define BASS_ERROR_CREATE 33 // couldn't create the file -#define BASS_ERROR_NOFX 34 // effects are not available -#define BASS_ERROR_NOTAVAIL 37 // requested data/action is not available -#define BASS_ERROR_DECODE 38 // the channel is/isn't a "decoding channel" -#define BASS_ERROR_DX 39 // a sufficient DirectX version is not installed -#define BASS_ERROR_TIMEOUT 40 // connection timedout -#define BASS_ERROR_FILEFORM 41 // unsupported file format -#define BASS_ERROR_SPEAKER 42 // unavailable speaker -#define BASS_ERROR_VERSION 43 // invalid BASS version (used by add-ons) -#define BASS_ERROR_CODEC 44 // codec is not available/supported -#define BASS_ERROR_ENDED 45 // the channel/file has ended -#define BASS_ERROR_BUSY 46 // the device is busy -#define BASS_ERROR_UNKNOWN -1 // some other mystery problem +#define BASS_OK 0 // all is OK +#define BASS_ERROR_MEM 1 // memory error +#define BASS_ERROR_FILEOPEN 2 // can't open the file +#define BASS_ERROR_DRIVER 3 // can't find a free/valid driver +#define BASS_ERROR_BUFLOST 4 // the sample buffer was lost +#define BASS_ERROR_HANDLE 5 // invalid handle +#define BASS_ERROR_FORMAT 6 // unsupported sample format +#define BASS_ERROR_POSITION 7 // invalid position +#define BASS_ERROR_INIT 8 // BASS_Init has not been successfully called +#define BASS_ERROR_START 9 // BASS_Start has not been successfully called +#define BASS_ERROR_SSL 10 // SSL/HTTPS support isn't available +#define BASS_ERROR_ALREADY 14 // already initialized/paused/whatever +#define BASS_ERROR_NOCHAN 18 // can't get a free channel +#define BASS_ERROR_ILLTYPE 19 // an illegal type was specified +#define BASS_ERROR_ILLPARAM 20 // an illegal parameter was specified +#define BASS_ERROR_NO3D 21 // no 3D support +#define BASS_ERROR_NOEAX 22 // no EAX support +#define BASS_ERROR_DEVICE 23 // illegal device number +#define BASS_ERROR_NOPLAY 24 // not playing +#define BASS_ERROR_FREQ 25 // illegal sample rate +#define BASS_ERROR_NOTFILE 27 // the stream is not a file stream +#define BASS_ERROR_NOHW 29 // no hardware voices available +#define BASS_ERROR_EMPTY 31 // the MOD music has no sequence data +#define BASS_ERROR_NONET 32 // no internet connection could be opened +#define BASS_ERROR_CREATE 33 // couldn't create the file +#define BASS_ERROR_NOFX 34 // effects are not available +#define BASS_ERROR_NOTAVAIL 37 // requested data/action is not available +#define BASS_ERROR_DECODE 38 // the channel is/isn't a "decoding channel" +#define BASS_ERROR_DX 39 // a sufficient DirectX version is not installed +#define BASS_ERROR_TIMEOUT 40 // connection timedout +#define BASS_ERROR_FILEFORM 41 // unsupported file format +#define BASS_ERROR_SPEAKER 42 // unavailable speaker +#define BASS_ERROR_VERSION 43 // invalid BASS version (used by add-ons) +#define BASS_ERROR_CODEC 44 // codec is not available/supported +#define BASS_ERROR_ENDED 45 // the channel/file has ended +#define BASS_ERROR_BUSY 46 // the device is busy +#define BASS_ERROR_UNKNOWN -1 // some other mystery problem // BASS_SetConfig options -#define BASS_CONFIG_BUFFER 0 -#define BASS_CONFIG_UPDATEPERIOD 1 -#define BASS_CONFIG_GVOL_SAMPLE 4 -#define BASS_CONFIG_GVOL_STREAM 5 -#define BASS_CONFIG_GVOL_MUSIC 6 -#define BASS_CONFIG_CURVE_VOL 7 -#define BASS_CONFIG_CURVE_PAN 8 -#define BASS_CONFIG_FLOATDSP 9 -#define BASS_CONFIG_3DALGORITHM 10 -#define BASS_CONFIG_NET_TIMEOUT 11 -#define BASS_CONFIG_NET_BUFFER 12 -#define BASS_CONFIG_PAUSE_NOPLAY 13 -#define BASS_CONFIG_NET_PREBUF 15 -#define BASS_CONFIG_NET_PASSIVE 18 -#define BASS_CONFIG_REC_BUFFER 19 -#define BASS_CONFIG_NET_PLAYLIST 21 -#define BASS_CONFIG_MUSIC_VIRTUAL 22 -#define BASS_CONFIG_VERIFY 23 -#define BASS_CONFIG_UPDATETHREADS 24 -#define BASS_CONFIG_DEV_BUFFER 27 -#define BASS_CONFIG_REC_LOOPBACK 28 -#define BASS_CONFIG_VISTA_TRUEPOS 30 -#define BASS_CONFIG_IOS_MIXAUDIO 34 -#define BASS_CONFIG_DEV_DEFAULT 36 -#define BASS_CONFIG_NET_READTIMEOUT 37 -#define BASS_CONFIG_VISTA_SPEAKERS 38 -#define BASS_CONFIG_IOS_SPEAKER 39 -#define BASS_CONFIG_MF_DISABLE 40 -#define BASS_CONFIG_HANDLES 41 -#define BASS_CONFIG_UNICODE 42 -#define BASS_CONFIG_SRC 43 -#define BASS_CONFIG_SRC_SAMPLE 44 -#define BASS_CONFIG_ASYNCFILE_BUFFER 45 -#define BASS_CONFIG_OGG_PRESCAN 47 -#define BASS_CONFIG_MF_VIDEO 48 -#define BASS_CONFIG_AIRPLAY 49 -#define BASS_CONFIG_DEV_NONSTOP 50 -#define BASS_CONFIG_IOS_NOCATEGORY 51 -#define BASS_CONFIG_VERIFY_NET 52 -#define BASS_CONFIG_DEV_PERIOD 53 -#define BASS_CONFIG_FLOAT 54 -#define BASS_CONFIG_NET_SEEK 56 -#define BASS_CONFIG_AM_DISABLE 58 -#define BASS_CONFIG_NET_PLAYLIST_DEPTH 59 -#define BASS_CONFIG_NET_PREBUF_WAIT 60 -#define BASS_CONFIG_WASAPI_PERSIST 65 -#define BASS_CONFIG_REC_WASAPI 66 +#define BASS_CONFIG_BUFFER 0 +#define BASS_CONFIG_UPDATEPERIOD 1 +#define BASS_CONFIG_GVOL_SAMPLE 4 +#define BASS_CONFIG_GVOL_STREAM 5 +#define BASS_CONFIG_GVOL_MUSIC 6 +#define BASS_CONFIG_CURVE_VOL 7 +#define BASS_CONFIG_CURVE_PAN 8 +#define BASS_CONFIG_FLOATDSP 9 +#define BASS_CONFIG_3DALGORITHM 10 +#define BASS_CONFIG_NET_TIMEOUT 11 +#define BASS_CONFIG_NET_BUFFER 12 +#define BASS_CONFIG_PAUSE_NOPLAY 13 +#define BASS_CONFIG_NET_PREBUF 15 +#define BASS_CONFIG_NET_PASSIVE 18 +#define BASS_CONFIG_REC_BUFFER 19 +#define BASS_CONFIG_NET_PLAYLIST 21 +#define BASS_CONFIG_MUSIC_VIRTUAL 22 +#define BASS_CONFIG_VERIFY 23 +#define BASS_CONFIG_UPDATETHREADS 24 +#define BASS_CONFIG_DEV_BUFFER 27 +#define BASS_CONFIG_REC_LOOPBACK 28 +#define BASS_CONFIG_VISTA_TRUEPOS 30 +#define BASS_CONFIG_IOS_MIXAUDIO 34 +#define BASS_CONFIG_DEV_DEFAULT 36 +#define BASS_CONFIG_NET_READTIMEOUT 37 +#define BASS_CONFIG_VISTA_SPEAKERS 38 +#define BASS_CONFIG_IOS_SPEAKER 39 +#define BASS_CONFIG_MF_DISABLE 40 +#define BASS_CONFIG_HANDLES 41 +#define BASS_CONFIG_UNICODE 42 +#define BASS_CONFIG_SRC 43 +#define BASS_CONFIG_SRC_SAMPLE 44 +#define BASS_CONFIG_ASYNCFILE_BUFFER 45 +#define BASS_CONFIG_OGG_PRESCAN 47 +#define BASS_CONFIG_MF_VIDEO 48 +#define BASS_CONFIG_AIRPLAY 49 +#define BASS_CONFIG_DEV_NONSTOP 50 +#define BASS_CONFIG_IOS_NOCATEGORY 51 +#define BASS_CONFIG_VERIFY_NET 52 +#define BASS_CONFIG_DEV_PERIOD 53 +#define BASS_CONFIG_FLOAT 54 +#define BASS_CONFIG_NET_SEEK 56 +#define BASS_CONFIG_AM_DISABLE 58 +#define BASS_CONFIG_NET_PLAYLIST_DEPTH 59 +#define BASS_CONFIG_NET_PREBUF_WAIT 60 +#define BASS_CONFIG_WASAPI_PERSIST 65 +#define BASS_CONFIG_REC_WASAPI 66 // BASS_SetConfigPtr options -#define BASS_CONFIG_NET_AGENT 16 -#define BASS_CONFIG_NET_PROXY 17 -#define BASS_CONFIG_IOS_NOTIFY 46 -#define BASS_CONFIG_LIBSSL 64 +#define BASS_CONFIG_NET_AGENT 16 +#define BASS_CONFIG_NET_PROXY 17 +#define BASS_CONFIG_IOS_NOTIFY 46 +#define BASS_CONFIG_LIBSSL 64 // BASS_Init flags -#define BASS_DEVICE_8BITS 1 // 8 bit -#define BASS_DEVICE_MONO 2 // mono -#define BASS_DEVICE_3D 4 // enable 3D functionality -#define BASS_DEVICE_16BITS 8 // limit output to 16 bit -#define BASS_DEVICE_LATENCY 0x100 // calculate device latency (BASS_INFO struct) -#define BASS_DEVICE_CPSPEAKERS 0x400 // detect speakers via Windows control panel -#define BASS_DEVICE_SPEAKERS 0x800 // force enabling of speaker assignment -#define BASS_DEVICE_NOSPEAKER 0x1000 // ignore speaker arrangement -#define BASS_DEVICE_DMIX 0x2000 // use ALSA "dmix" plugin -#define BASS_DEVICE_FREQ 0x4000 // set device sample rate -#define BASS_DEVICE_STEREO 0x8000 // limit output to stereo -#define BASS_DEVICE_HOG 0x10000 // hog/exclusive mode -#define BASS_DEVICE_AUDIOTRACK 0x20000 // use AudioTrack output -#define BASS_DEVICE_DSOUND 0x40000 // use DirectSound output +#define BASS_DEVICE_8BITS 1 // 8 bit +#define BASS_DEVICE_MONO 2 // mono +#define BASS_DEVICE_3D 4 // enable 3D functionality +#define BASS_DEVICE_16BITS 8 // limit output to 16 bit +#define BASS_DEVICE_LATENCY 0x100 // calculate device latency (BASS_INFO struct) +#define BASS_DEVICE_CPSPEAKERS 0x400 // detect speakers via Windows control panel +#define BASS_DEVICE_SPEAKERS 0x800 // force enabling of speaker assignment +#define BASS_DEVICE_NOSPEAKER 0x1000 // ignore speaker arrangement +#define BASS_DEVICE_DMIX 0x2000 // use ALSA "dmix" plugin +#define BASS_DEVICE_FREQ 0x4000 // set device sample rate +#define BASS_DEVICE_STEREO 0x8000 // limit output to stereo +#define BASS_DEVICE_HOG 0x10000 // hog/exclusive mode +#define BASS_DEVICE_AUDIOTRACK 0x20000 // use AudioTrack output +#define BASS_DEVICE_DSOUND 0x40000 // use DirectSound output // DirectSound interfaces (for use with BASS_GetDSoundObject) -#define BASS_OBJECT_DS 1 // IDirectSound -#define BASS_OBJECT_DS3DL 2 // IDirectSound3DListener +#define BASS_OBJECT_DS 1 // IDirectSound +#define BASS_OBJECT_DS3DL 2 // IDirectSound3DListener // Device info structure typedef struct { -#if defined(_WIN32_WCE) || (WINAPI_FAMILY && WINAPI_FAMILY!=WINAPI_FAMILY_DESKTOP_APP) - const wchar_t *name; // description - const wchar_t *driver; // driver +#if defined(_WIN32_WCE) || (WINAPI_FAMILY && WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP) + const wchar_t *name; // description + const wchar_t *driver; // driver #else - const char *name; // description - const char *driver; // driver + const char *name; // description + const char *driver; // driver #endif - DWORD flags; + DWORD flags; } BASS_DEVICEINFO; // BASS_DEVICEINFO flags -#define BASS_DEVICE_ENABLED 1 -#define BASS_DEVICE_DEFAULT 2 -#define BASS_DEVICE_INIT 4 -#define BASS_DEVICE_LOOPBACK 8 +#define BASS_DEVICE_ENABLED 1 +#define BASS_DEVICE_DEFAULT 2 +#define BASS_DEVICE_INIT 4 +#define BASS_DEVICE_LOOPBACK 8 -#define BASS_DEVICE_TYPE_MASK 0xff000000 -#define BASS_DEVICE_TYPE_NETWORK 0x01000000 -#define BASS_DEVICE_TYPE_SPEAKERS 0x02000000 -#define BASS_DEVICE_TYPE_LINE 0x03000000 -#define BASS_DEVICE_TYPE_HEADPHONES 0x04000000 -#define BASS_DEVICE_TYPE_MICROPHONE 0x05000000 -#define BASS_DEVICE_TYPE_HEADSET 0x06000000 -#define BASS_DEVICE_TYPE_HANDSET 0x07000000 -#define BASS_DEVICE_TYPE_DIGITAL 0x08000000 -#define BASS_DEVICE_TYPE_SPDIF 0x09000000 -#define BASS_DEVICE_TYPE_HDMI 0x0a000000 -#define BASS_DEVICE_TYPE_DISPLAYPORT 0x40000000 +#define BASS_DEVICE_TYPE_MASK 0xff000000 +#define BASS_DEVICE_TYPE_NETWORK 0x01000000 +#define BASS_DEVICE_TYPE_SPEAKERS 0x02000000 +#define BASS_DEVICE_TYPE_LINE 0x03000000 +#define BASS_DEVICE_TYPE_HEADPHONES 0x04000000 +#define BASS_DEVICE_TYPE_MICROPHONE 0x05000000 +#define BASS_DEVICE_TYPE_HEADSET 0x06000000 +#define BASS_DEVICE_TYPE_HANDSET 0x07000000 +#define BASS_DEVICE_TYPE_DIGITAL 0x08000000 +#define BASS_DEVICE_TYPE_SPDIF 0x09000000 +#define BASS_DEVICE_TYPE_HDMI 0x0a000000 +#define BASS_DEVICE_TYPE_DISPLAYPORT 0x40000000 + +// BASS_GetDeviceInfo flags +#define BASS_DEVICES_AIRPLAY 0x1000000 -// BASS_GetDeviceInfo flags -#define BASS_DEVICES_AIRPLAY 0x1000000 - typedef struct { - DWORD flags; // device capabilities (DSCAPS_xxx flags) - DWORD hwsize; // size of total device hardware memory - DWORD hwfree; // size of free device hardware memory - DWORD freesam; // number of free sample slots in the hardware - DWORD free3d; // number of free 3D sample slots in the hardware - DWORD minrate; // min sample rate supported by the hardware - DWORD maxrate; // max sample rate supported by the hardware - BOOL eax; // device supports EAX? (always FALSE if BASS_DEVICE_3D was not used) - DWORD minbuf; // recommended minimum buffer length in ms (requires BASS_DEVICE_LATENCY) - DWORD dsver; // DirectSound version - DWORD latency; // delay (in ms) before start of playback (requires BASS_DEVICE_LATENCY) - DWORD initflags; // BASS_Init "flags" parameter - DWORD speakers; // number of speakers available - DWORD freq; // current output rate + DWORD flags; // device capabilities (DSCAPS_xxx flags) + DWORD hwsize; // size of total device hardware memory + DWORD hwfree; // size of free device hardware memory + DWORD freesam; // number of free sample slots in the hardware + DWORD free3d; // number of free 3D sample slots in the hardware + DWORD minrate; // min sample rate supported by the hardware + DWORD maxrate; // max sample rate supported by the hardware + BOOL eax; // device supports EAX? (always FALSE if BASS_DEVICE_3D was not used) + DWORD minbuf; // recommended minimum buffer length in ms (requires BASS_DEVICE_LATENCY) + DWORD dsver; // DirectSound version + DWORD latency; // delay (in ms) before start of playback (requires BASS_DEVICE_LATENCY) + DWORD initflags; // BASS_Init "flags" parameter + DWORD speakers; // number of speakers available + DWORD freq; // current output rate } BASS_INFO; // BASS_INFO flags (from DSOUND.H) -#define DSCAPS_CONTINUOUSRATE 0x00000010 // supports all sample rates between min/maxrate -#define DSCAPS_EMULDRIVER 0x00000020 // device does NOT have hardware DirectSound support -#define DSCAPS_CERTIFIED 0x00000040 // device driver has been certified by Microsoft -#define DSCAPS_SECONDARYMONO 0x00000100 // mono -#define DSCAPS_SECONDARYSTEREO 0x00000200 // stereo -#define DSCAPS_SECONDARY8BIT 0x00000400 // 8 bit -#define DSCAPS_SECONDARY16BIT 0x00000800 // 16 bit +#define DSCAPS_CONTINUOUSRATE 0x00000010 // supports all sample rates between min/maxrate +#define DSCAPS_EMULDRIVER 0x00000020 // device does NOT have hardware DirectSound support +#define DSCAPS_CERTIFIED 0x00000040 // device driver has been certified by Microsoft +#define DSCAPS_SECONDARYMONO 0x00000100 // mono +#define DSCAPS_SECONDARYSTEREO 0x00000200 // stereo +#define DSCAPS_SECONDARY8BIT 0x00000400 // 8 bit +#define DSCAPS_SECONDARY16BIT 0x00000800 // 16 bit // Recording device info structure typedef struct { - DWORD flags; // device capabilities (DSCCAPS_xxx flags) - DWORD formats; // supported standard formats (WAVE_FORMAT_xxx flags) - DWORD inputs; // number of inputs - BOOL singlein; // TRUE = only 1 input can be set at a time - DWORD freq; // current input rate + DWORD flags; // device capabilities (DSCCAPS_xxx flags) + DWORD formats; // supported standard formats (WAVE_FORMAT_xxx flags) + DWORD inputs; // number of inputs + BOOL singlein; // TRUE = only 1 input can be set at a time + DWORD freq; // current input rate } BASS_RECORDINFO; // BASS_RECORDINFO flags (from DSOUND.H) -#define DSCCAPS_EMULDRIVER DSCAPS_EMULDRIVER // device does NOT have hardware DirectSound recording support -#define DSCCAPS_CERTIFIED DSCAPS_CERTIFIED // device driver has been certified by Microsoft +#define DSCCAPS_EMULDRIVER DSCAPS_EMULDRIVER // device does NOT have hardware DirectSound recording support +#define DSCCAPS_CERTIFIED DSCAPS_CERTIFIED // device driver has been certified by Microsoft // defines for formats field of BASS_RECORDINFO (from MMSYSTEM.H) #ifndef WAVE_FORMAT_1M08 -#define WAVE_FORMAT_1M08 0x00000001 /* 11.025 kHz, Mono, 8-bit */ -#define WAVE_FORMAT_1S08 0x00000002 /* 11.025 kHz, Stereo, 8-bit */ -#define WAVE_FORMAT_1M16 0x00000004 /* 11.025 kHz, Mono, 16-bit */ -#define WAVE_FORMAT_1S16 0x00000008 /* 11.025 kHz, Stereo, 16-bit */ -#define WAVE_FORMAT_2M08 0x00000010 /* 22.05 kHz, Mono, 8-bit */ -#define WAVE_FORMAT_2S08 0x00000020 /* 22.05 kHz, Stereo, 8-bit */ -#define WAVE_FORMAT_2M16 0x00000040 /* 22.05 kHz, Mono, 16-bit */ -#define WAVE_FORMAT_2S16 0x00000080 /* 22.05 kHz, Stereo, 16-bit */ -#define WAVE_FORMAT_4M08 0x00000100 /* 44.1 kHz, Mono, 8-bit */ -#define WAVE_FORMAT_4S08 0x00000200 /* 44.1 kHz, Stereo, 8-bit */ -#define WAVE_FORMAT_4M16 0x00000400 /* 44.1 kHz, Mono, 16-bit */ -#define WAVE_FORMAT_4S16 0x00000800 /* 44.1 kHz, Stereo, 16-bit */ +#define WAVE_FORMAT_1M08 0x00000001 /* 11.025 kHz, Mono, 8-bit */ +#define WAVE_FORMAT_1S08 0x00000002 /* 11.025 kHz, Stereo, 8-bit */ +#define WAVE_FORMAT_1M16 0x00000004 /* 11.025 kHz, Mono, 16-bit */ +#define WAVE_FORMAT_1S16 0x00000008 /* 11.025 kHz, Stereo, 16-bit */ +#define WAVE_FORMAT_2M08 0x00000010 /* 22.05 kHz, Mono, 8-bit */ +#define WAVE_FORMAT_2S08 0x00000020 /* 22.05 kHz, Stereo, 8-bit */ +#define WAVE_FORMAT_2M16 0x00000040 /* 22.05 kHz, Mono, 16-bit */ +#define WAVE_FORMAT_2S16 0x00000080 /* 22.05 kHz, Stereo, 16-bit */ +#define WAVE_FORMAT_4M08 0x00000100 /* 44.1 kHz, Mono, 8-bit */ +#define WAVE_FORMAT_4S08 0x00000200 /* 44.1 kHz, Stereo, 8-bit */ +#define WAVE_FORMAT_4M16 0x00000400 /* 44.1 kHz, Mono, 16-bit */ +#define WAVE_FORMAT_4S16 0x00000800 /* 44.1 kHz, Stereo, 16-bit */ #endif // Sample info structure typedef struct { - DWORD freq; // default playback rate - float volume; // default volume (0-1) - float pan; // default pan (-1=left, 0=middle, 1=right) - DWORD flags; // BASS_SAMPLE_xxx flags - DWORD length; // length (in bytes) - DWORD max; // maximum simultaneous playbacks - DWORD origres; // original resolution - DWORD chans; // number of channels - DWORD mingap; // minimum gap (ms) between creating channels - DWORD mode3d; // BASS_3DMODE_xxx mode - float mindist; // minimum distance - float maxdist; // maximum distance - DWORD iangle; // angle of inside projection cone - DWORD oangle; // angle of outside projection cone - float outvol; // delta-volume outside the projection cone - DWORD vam; // voice allocation/management flags (BASS_VAM_xxx) - DWORD priority; // priority (0=lowest, 0xffffffff=highest) + DWORD freq; // default playback rate + float volume; // default volume (0-1) + float pan; // default pan (-1=left, 0=middle, 1=right) + DWORD flags; // BASS_SAMPLE_xxx flags + DWORD length; // length (in bytes) + DWORD max; // maximum simultaneous playbacks + DWORD origres; // original resolution + DWORD chans; // number of channels + DWORD mingap; // minimum gap (ms) between creating channels + DWORD mode3d; // BASS_3DMODE_xxx mode + float mindist; // minimum distance + float maxdist; // maximum distance + DWORD iangle; // angle of inside projection cone + DWORD oangle; // angle of outside projection cone + float outvol; // delta-volume outside the projection cone + DWORD vam; // voice allocation/management flags (BASS_VAM_xxx) + DWORD priority; // priority (0=lowest, 0xffffffff=highest) } BASS_SAMPLE; -#define BASS_SAMPLE_8BITS 1 // 8 bit -#define BASS_SAMPLE_FLOAT 256 // 32 bit floating-point -#define BASS_SAMPLE_MONO 2 // mono -#define BASS_SAMPLE_LOOP 4 // looped -#define BASS_SAMPLE_3D 8 // 3D functionality -#define BASS_SAMPLE_SOFTWARE 16 // not using hardware mixing -#define BASS_SAMPLE_MUTEMAX 32 // mute at max distance (3D only) -#define BASS_SAMPLE_VAM 64 // DX7 voice allocation & management -#define BASS_SAMPLE_FX 128 // old implementation of DX8 effects -#define BASS_SAMPLE_OVER_VOL 0x10000 // override lowest volume -#define BASS_SAMPLE_OVER_POS 0x20000 // override longest playing -#define BASS_SAMPLE_OVER_DIST 0x30000 // override furthest from listener (3D only) +#define BASS_SAMPLE_8BITS 1 // 8 bit +#define BASS_SAMPLE_FLOAT 256 // 32 bit floating-point +#define BASS_SAMPLE_MONO 2 // mono +#define BASS_SAMPLE_LOOP 4 // looped +#define BASS_SAMPLE_3D 8 // 3D functionality +#define BASS_SAMPLE_SOFTWARE 16 // not using hardware mixing +#define BASS_SAMPLE_MUTEMAX 32 // mute at max distance (3D only) +#define BASS_SAMPLE_VAM 64 // DX7 voice allocation & management +#define BASS_SAMPLE_FX 128 // old implementation of DX8 effects +#define BASS_SAMPLE_OVER_VOL 0x10000 // override lowest volume +#define BASS_SAMPLE_OVER_POS 0x20000 // override longest playing +#define BASS_SAMPLE_OVER_DIST 0x30000 // override furthest from listener (3D only) -#define BASS_STREAM_PRESCAN 0x20000 // enable pin-point seeking/length (MP3/MP2/MP1) -#define BASS_STREAM_AUTOFREE 0x40000 // automatically free the stream when it stop/ends -#define BASS_STREAM_RESTRATE 0x80000 // restrict the download rate of internet file streams -#define BASS_STREAM_BLOCK 0x100000 // download/play internet file stream in small blocks -#define BASS_STREAM_DECODE 0x200000 // don't play the stream, only decode (BASS_ChannelGetData) -#define BASS_STREAM_STATUS 0x800000 // give server status info (HTTP/ICY tags) in DOWNLOADPROC +#define BASS_STREAM_PRESCAN 0x20000 // enable pin-point seeking/length (MP3/MP2/MP1) +#define BASS_STREAM_AUTOFREE 0x40000 // automatically free the stream when it stop/ends +#define BASS_STREAM_RESTRATE 0x80000 // restrict the download rate of internet file streams +#define BASS_STREAM_BLOCK 0x100000 // download/play internet file stream in small blocks +#define BASS_STREAM_DECODE 0x200000 // don't play the stream, only decode (BASS_ChannelGetData) +#define BASS_STREAM_STATUS 0x800000 // give server status info (HTTP/ICY tags) in DOWNLOADPROC -#define BASS_MP3_IGNOREDELAY 0x200 // ignore LAME/Xing/VBRI/iTunes delay & padding info -#define BASS_MP3_SETPOS BASS_STREAM_PRESCAN +#define BASS_MP3_IGNOREDELAY 0x200 // ignore LAME/Xing/VBRI/iTunes delay & padding info +#define BASS_MP3_SETPOS BASS_STREAM_PRESCAN -#define BASS_MUSIC_FLOAT BASS_SAMPLE_FLOAT -#define BASS_MUSIC_MONO BASS_SAMPLE_MONO -#define BASS_MUSIC_LOOP BASS_SAMPLE_LOOP -#define BASS_MUSIC_3D BASS_SAMPLE_3D -#define BASS_MUSIC_FX BASS_SAMPLE_FX -#define BASS_MUSIC_AUTOFREE BASS_STREAM_AUTOFREE -#define BASS_MUSIC_DECODE BASS_STREAM_DECODE -#define BASS_MUSIC_PRESCAN BASS_STREAM_PRESCAN // calculate playback length -#define BASS_MUSIC_CALCLEN BASS_MUSIC_PRESCAN -#define BASS_MUSIC_RAMP 0x200 // normal ramping -#define BASS_MUSIC_RAMPS 0x400 // sensitive ramping -#define BASS_MUSIC_SURROUND 0x800 // surround sound -#define BASS_MUSIC_SURROUND2 0x1000 // surround sound (mode 2) -#define BASS_MUSIC_FT2PAN 0x2000 // apply FastTracker 2 panning to XM files -#define BASS_MUSIC_FT2MOD 0x2000 // play .MOD as FastTracker 2 does -#define BASS_MUSIC_PT1MOD 0x4000 // play .MOD as ProTracker 1 does -#define BASS_MUSIC_NONINTER 0x10000 // non-interpolated sample mixing -#define BASS_MUSIC_SINCINTER 0x800000 // sinc interpolated sample mixing -#define BASS_MUSIC_POSRESET 0x8000 // stop all notes when moving position -#define BASS_MUSIC_POSRESETEX 0x400000 // stop all notes and reset bmp/etc when moving position -#define BASS_MUSIC_STOPBACK 0x80000 // stop the music on a backwards jump effect -#define BASS_MUSIC_NOSAMPLE 0x100000 // don't load the samples +#define BASS_MUSIC_FLOAT BASS_SAMPLE_FLOAT +#define BASS_MUSIC_MONO BASS_SAMPLE_MONO +#define BASS_MUSIC_LOOP BASS_SAMPLE_LOOP +#define BASS_MUSIC_3D BASS_SAMPLE_3D +#define BASS_MUSIC_FX BASS_SAMPLE_FX +#define BASS_MUSIC_AUTOFREE BASS_STREAM_AUTOFREE +#define BASS_MUSIC_DECODE BASS_STREAM_DECODE +#define BASS_MUSIC_PRESCAN BASS_STREAM_PRESCAN // calculate playback length +#define BASS_MUSIC_CALCLEN BASS_MUSIC_PRESCAN +#define BASS_MUSIC_RAMP 0x200 // normal ramping +#define BASS_MUSIC_RAMPS 0x400 // sensitive ramping +#define BASS_MUSIC_SURROUND 0x800 // surround sound +#define BASS_MUSIC_SURROUND2 0x1000 // surround sound (mode 2) +#define BASS_MUSIC_FT2PAN 0x2000 // apply FastTracker 2 panning to XM files +#define BASS_MUSIC_FT2MOD 0x2000 // play .MOD as FastTracker 2 does +#define BASS_MUSIC_PT1MOD 0x4000 // play .MOD as ProTracker 1 does +#define BASS_MUSIC_NONINTER 0x10000 // non-interpolated sample mixing +#define BASS_MUSIC_SINCINTER 0x800000 // sinc interpolated sample mixing +#define BASS_MUSIC_POSRESET 0x8000 // stop all notes when moving position +#define BASS_MUSIC_POSRESETEX 0x400000 // stop all notes and reset bmp/etc when moving position +#define BASS_MUSIC_STOPBACK 0x80000 // stop the music on a backwards jump effect +#define BASS_MUSIC_NOSAMPLE 0x100000 // don't load the samples // Speaker assignment flags -#define BASS_SPEAKER_FRONT 0x1000000 // front speakers -#define BASS_SPEAKER_REAR 0x2000000 // rear/side speakers -#define BASS_SPEAKER_CENLFE 0x3000000 // center & LFE speakers (5.1) -#define BASS_SPEAKER_REAR2 0x4000000 // rear center speakers (7.1) -#define BASS_SPEAKER_N(n) ((n)<<24) // n'th pair of speakers (max 15) -#define BASS_SPEAKER_LEFT 0x10000000 // modifier: left -#define BASS_SPEAKER_RIGHT 0x20000000 // modifier: right -#define BASS_SPEAKER_FRONTLEFT BASS_SPEAKER_FRONT|BASS_SPEAKER_LEFT -#define BASS_SPEAKER_FRONTRIGHT BASS_SPEAKER_FRONT|BASS_SPEAKER_RIGHT -#define BASS_SPEAKER_REARLEFT BASS_SPEAKER_REAR|BASS_SPEAKER_LEFT -#define BASS_SPEAKER_REARRIGHT BASS_SPEAKER_REAR|BASS_SPEAKER_RIGHT -#define BASS_SPEAKER_CENTER BASS_SPEAKER_CENLFE|BASS_SPEAKER_LEFT -#define BASS_SPEAKER_LFE BASS_SPEAKER_CENLFE|BASS_SPEAKER_RIGHT -#define BASS_SPEAKER_REAR2LEFT BASS_SPEAKER_REAR2|BASS_SPEAKER_LEFT -#define BASS_SPEAKER_REAR2RIGHT BASS_SPEAKER_REAR2|BASS_SPEAKER_RIGHT +#define BASS_SPEAKER_FRONT 0x1000000 // front speakers +#define BASS_SPEAKER_REAR 0x2000000 // rear/side speakers +#define BASS_SPEAKER_CENLFE 0x3000000 // center & LFE speakers (5.1) +#define BASS_SPEAKER_REAR2 0x4000000 // rear center speakers (7.1) +#define BASS_SPEAKER_N(n) ((n) << 24) // n'th pair of speakers (max 15) +#define BASS_SPEAKER_LEFT 0x10000000 // modifier: left +#define BASS_SPEAKER_RIGHT 0x20000000 // modifier: right +#define BASS_SPEAKER_FRONTLEFT BASS_SPEAKER_FRONT | BASS_SPEAKER_LEFT +#define BASS_SPEAKER_FRONTRIGHT BASS_SPEAKER_FRONT | BASS_SPEAKER_RIGHT +#define BASS_SPEAKER_REARLEFT BASS_SPEAKER_REAR | BASS_SPEAKER_LEFT +#define BASS_SPEAKER_REARRIGHT BASS_SPEAKER_REAR | BASS_SPEAKER_RIGHT +#define BASS_SPEAKER_CENTER BASS_SPEAKER_CENLFE | BASS_SPEAKER_LEFT +#define BASS_SPEAKER_LFE BASS_SPEAKER_CENLFE | BASS_SPEAKER_RIGHT +#define BASS_SPEAKER_REAR2LEFT BASS_SPEAKER_REAR2 | BASS_SPEAKER_LEFT +#define BASS_SPEAKER_REAR2RIGHT BASS_SPEAKER_REAR2 | BASS_SPEAKER_RIGHT -#define BASS_ASYNCFILE 0x40000000 -#define BASS_UNICODE 0x80000000 +#define BASS_ASYNCFILE 0x40000000 +#define BASS_UNICODE 0x80000000 -#define BASS_RECORD_PAUSE 0x8000 // start recording paused -#define BASS_RECORD_ECHOCANCEL 0x2000 -#define BASS_RECORD_AGC 0x4000 +#define BASS_RECORD_PAUSE 0x8000 // start recording paused +#define BASS_RECORD_ECHOCANCEL 0x2000 +#define BASS_RECORD_AGC 0x4000 // DX7 voice allocation & management flags -#define BASS_VAM_HARDWARE 1 -#define BASS_VAM_SOFTWARE 2 -#define BASS_VAM_TERM_TIME 4 -#define BASS_VAM_TERM_DIST 8 -#define BASS_VAM_TERM_PRIO 16 +#define BASS_VAM_HARDWARE 1 +#define BASS_VAM_SOFTWARE 2 +#define BASS_VAM_TERM_TIME 4 +#define BASS_VAM_TERM_DIST 8 +#define BASS_VAM_TERM_PRIO 16 // Channel info structure typedef struct { - DWORD freq; // default playback rate - DWORD chans; // channels - DWORD flags; // BASS_SAMPLE/STREAM/MUSIC/SPEAKER flags - DWORD ctype; // type of channel - DWORD origres; // original resolution - HPLUGIN plugin; // plugin - HSAMPLE sample; // sample - const char *filename; // filename + DWORD freq; // default playback rate + DWORD chans; // channels + DWORD flags; // BASS_SAMPLE/STREAM/MUSIC/SPEAKER flags + DWORD ctype; // type of channel + DWORD origres; // original resolution + HPLUGIN plugin; // plugin + HSAMPLE sample; // sample + const char *filename; // filename } BASS_CHANNELINFO; -#define BASS_ORIGRES_FLOAT 0x10000 +#define BASS_ORIGRES_FLOAT 0x10000 // BASS_CHANNELINFO types -#define BASS_CTYPE_SAMPLE 1 -#define BASS_CTYPE_RECORD 2 -#define BASS_CTYPE_STREAM 0x10000 -#define BASS_CTYPE_STREAM_OGG 0x10002 -#define BASS_CTYPE_STREAM_MP1 0x10003 -#define BASS_CTYPE_STREAM_MP2 0x10004 -#define BASS_CTYPE_STREAM_MP3 0x10005 -#define BASS_CTYPE_STREAM_AIFF 0x10006 -#define BASS_CTYPE_STREAM_CA 0x10007 -#define BASS_CTYPE_STREAM_MF 0x10008 -#define BASS_CTYPE_STREAM_AM 0x10009 -#define BASS_CTYPE_STREAM_DUMMY 0x18000 -#define BASS_CTYPE_STREAM_DEVICE 0x18001 -#define BASS_CTYPE_STREAM_WAV 0x40000 // WAVE flag, LOWORD=codec -#define BASS_CTYPE_STREAM_WAV_PCM 0x50001 -#define BASS_CTYPE_STREAM_WAV_FLOAT 0x50003 -#define BASS_CTYPE_MUSIC_MOD 0x20000 -#define BASS_CTYPE_MUSIC_MTM 0x20001 -#define BASS_CTYPE_MUSIC_S3M 0x20002 -#define BASS_CTYPE_MUSIC_XM 0x20003 -#define BASS_CTYPE_MUSIC_IT 0x20004 -#define BASS_CTYPE_MUSIC_MO3 0x00100 // MO3 flag +#define BASS_CTYPE_SAMPLE 1 +#define BASS_CTYPE_RECORD 2 +#define BASS_CTYPE_STREAM 0x10000 +#define BASS_CTYPE_STREAM_OGG 0x10002 +#define BASS_CTYPE_STREAM_MP1 0x10003 +#define BASS_CTYPE_STREAM_MP2 0x10004 +#define BASS_CTYPE_STREAM_MP3 0x10005 +#define BASS_CTYPE_STREAM_AIFF 0x10006 +#define BASS_CTYPE_STREAM_CA 0x10007 +#define BASS_CTYPE_STREAM_MF 0x10008 +#define BASS_CTYPE_STREAM_AM 0x10009 +#define BASS_CTYPE_STREAM_DUMMY 0x18000 +#define BASS_CTYPE_STREAM_DEVICE 0x18001 +#define BASS_CTYPE_STREAM_WAV 0x40000 // WAVE flag, LOWORD=codec +#define BASS_CTYPE_STREAM_WAV_PCM 0x50001 +#define BASS_CTYPE_STREAM_WAV_FLOAT 0x50003 +#define BASS_CTYPE_MUSIC_MOD 0x20000 +#define BASS_CTYPE_MUSIC_MTM 0x20001 +#define BASS_CTYPE_MUSIC_S3M 0x20002 +#define BASS_CTYPE_MUSIC_XM 0x20003 +#define BASS_CTYPE_MUSIC_IT 0x20004 +#define BASS_CTYPE_MUSIC_MO3 0x00100 // MO3 flag typedef struct { - DWORD ctype; // channel type -#if defined(_WIN32_WCE) || (WINAPI_FAMILY && WINAPI_FAMILY!=WINAPI_FAMILY_DESKTOP_APP) - const wchar_t *name; // format description - const wchar_t *exts; // file extension filter (*.ext1;*.ext2;etc...) + DWORD ctype; // channel type +#if defined(_WIN32_WCE) || (WINAPI_FAMILY && WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP) + const wchar_t *name; // format description + const wchar_t *exts; // file extension filter (*.ext1;*.ext2;etc...) #else - const char *name; // format description - const char *exts; // file extension filter (*.ext1;*.ext2;etc...) + const char *name; // format description + const char *exts; // file extension filter (*.ext1;*.ext2;etc...) #endif } BASS_PLUGINFORM; typedef struct { - DWORD version; // version (same form as BASS_GetVersion) - DWORD formatc; // number of formats - const BASS_PLUGINFORM *formats; // the array of formats + DWORD version; // version (same form as BASS_GetVersion) + DWORD formatc; // number of formats + const BASS_PLUGINFORM *formats; // the array of formats } BASS_PLUGININFO; // 3D vector (for 3D positions/velocities/orientations) typedef struct BASS_3DVECTOR { #ifdef __cplusplus - BASS_3DVECTOR() {}; - BASS_3DVECTOR(float _x, float _y, float _z) : x(_x), y(_y), z(_z) {}; + BASS_3DVECTOR(){}; + BASS_3DVECTOR(float _x, float _y, float _z) : x(_x), y(_y), z(_z){}; #endif - float x; // +=right, -=left - float y; // +=up, -=down - float z; // +=front, -=behind + float x; // +=right, -=left + float y; // +=up, -=down + float z; // +=front, -=behind } BASS_3DVECTOR; // 3D channel modes -#define BASS_3DMODE_NORMAL 0 // normal 3D processing -#define BASS_3DMODE_RELATIVE 1 // position is relative to the listener -#define BASS_3DMODE_OFF 2 // no 3D processing +#define BASS_3DMODE_NORMAL 0 // normal 3D processing +#define BASS_3DMODE_RELATIVE 1 // position is relative to the listener +#define BASS_3DMODE_OFF 2 // no 3D processing // software 3D mixing algorithms (used with BASS_CONFIG_3DALGORITHM) -#define BASS_3DALG_DEFAULT 0 -#define BASS_3DALG_OFF 1 -#define BASS_3DALG_FULL 2 -#define BASS_3DALG_LIGHT 3 +#define BASS_3DALG_DEFAULT 0 +#define BASS_3DALG_OFF 1 +#define BASS_3DALG_FULL 2 +#define BASS_3DALG_LIGHT 3 // EAX environments, use with BASS_SetEAXParameters -enum -{ +enum { EAX_ENVIRONMENT_GENERIC, EAX_ENVIRONMENT_PADDEDCELL, EAX_ENVIRONMENT_ROOM, @@ -465,38 +464,38 @@ enum EAX_ENVIRONMENT_DIZZY, EAX_ENVIRONMENT_PSYCHOTIC, - EAX_ENVIRONMENT_COUNT // total number of environments + EAX_ENVIRONMENT_COUNT // total number of environments }; // EAX presets, usage: BASS_SetEAXParameters(EAX_PRESET_xxx) -#define EAX_PRESET_GENERIC EAX_ENVIRONMENT_GENERIC,0.5F,1.493F,0.5F -#define EAX_PRESET_PADDEDCELL EAX_ENVIRONMENT_PADDEDCELL,0.25F,0.1F,0.0F -#define EAX_PRESET_ROOM EAX_ENVIRONMENT_ROOM,0.417F,0.4F,0.666F -#define EAX_PRESET_BATHROOM EAX_ENVIRONMENT_BATHROOM,0.653F,1.499F,0.166F -#define EAX_PRESET_LIVINGROOM EAX_ENVIRONMENT_LIVINGROOM,0.208F,0.478F,0.0F -#define EAX_PRESET_STONEROOM EAX_ENVIRONMENT_STONEROOM,0.5F,2.309F,0.888F -#define EAX_PRESET_AUDITORIUM EAX_ENVIRONMENT_AUDITORIUM,0.403F,4.279F,0.5F -#define EAX_PRESET_CONCERTHALL EAX_ENVIRONMENT_CONCERTHALL,0.5F,3.961F,0.5F -#define EAX_PRESET_CAVE EAX_ENVIRONMENT_CAVE,0.5F,2.886F,1.304F -#define EAX_PRESET_ARENA EAX_ENVIRONMENT_ARENA,0.361F,7.284F,0.332F -#define EAX_PRESET_HANGAR EAX_ENVIRONMENT_HANGAR,0.5F,10.0F,0.3F -#define EAX_PRESET_CARPETEDHALLWAY EAX_ENVIRONMENT_CARPETEDHALLWAY,0.153F,0.259F,2.0F -#define EAX_PRESET_HALLWAY EAX_ENVIRONMENT_HALLWAY,0.361F,1.493F,0.0F -#define EAX_PRESET_STONECORRIDOR EAX_ENVIRONMENT_STONECORRIDOR,0.444F,2.697F,0.638F -#define EAX_PRESET_ALLEY EAX_ENVIRONMENT_ALLEY,0.25F,1.752F,0.776F -#define EAX_PRESET_FOREST EAX_ENVIRONMENT_FOREST,0.111F,3.145F,0.472F -#define EAX_PRESET_CITY EAX_ENVIRONMENT_CITY,0.111F,2.767F,0.224F -#define EAX_PRESET_MOUNTAINS EAX_ENVIRONMENT_MOUNTAINS,0.194F,7.841F,0.472F -#define EAX_PRESET_QUARRY EAX_ENVIRONMENT_QUARRY,1.0F,1.499F,0.5F -#define EAX_PRESET_PLAIN EAX_ENVIRONMENT_PLAIN,0.097F,2.767F,0.224F -#define EAX_PRESET_PARKINGLOT EAX_ENVIRONMENT_PARKINGLOT,0.208F,1.652F,1.5F -#define EAX_PRESET_SEWERPIPE EAX_ENVIRONMENT_SEWERPIPE,0.652F,2.886F,0.25F -#define EAX_PRESET_UNDERWATER EAX_ENVIRONMENT_UNDERWATER,1.0F,1.499F,0.0F -#define EAX_PRESET_DRUGGED EAX_ENVIRONMENT_DRUGGED,0.875F,8.392F,1.388F -#define EAX_PRESET_DIZZY EAX_ENVIRONMENT_DIZZY,0.139F,17.234F,0.666F -#define EAX_PRESET_PSYCHOTIC EAX_ENVIRONMENT_PSYCHOTIC,0.486F,7.563F,0.806F +#define EAX_PRESET_GENERIC EAX_ENVIRONMENT_GENERIC, 0.5F, 1.493F, 0.5F +#define EAX_PRESET_PADDEDCELL EAX_ENVIRONMENT_PADDEDCELL, 0.25F, 0.1F, 0.0F +#define EAX_PRESET_ROOM EAX_ENVIRONMENT_ROOM, 0.417F, 0.4F, 0.666F +#define EAX_PRESET_BATHROOM EAX_ENVIRONMENT_BATHROOM, 0.653F, 1.499F, 0.166F +#define EAX_PRESET_LIVINGROOM EAX_ENVIRONMENT_LIVINGROOM, 0.208F, 0.478F, 0.0F +#define EAX_PRESET_STONEROOM EAX_ENVIRONMENT_STONEROOM, 0.5F, 2.309F, 0.888F +#define EAX_PRESET_AUDITORIUM EAX_ENVIRONMENT_AUDITORIUM, 0.403F, 4.279F, 0.5F +#define EAX_PRESET_CONCERTHALL EAX_ENVIRONMENT_CONCERTHALL, 0.5F, 3.961F, 0.5F +#define EAX_PRESET_CAVE EAX_ENVIRONMENT_CAVE, 0.5F, 2.886F, 1.304F +#define EAX_PRESET_ARENA EAX_ENVIRONMENT_ARENA, 0.361F, 7.284F, 0.332F +#define EAX_PRESET_HANGAR EAX_ENVIRONMENT_HANGAR, 0.5F, 10.0F, 0.3F +#define EAX_PRESET_CARPETEDHALLWAY EAX_ENVIRONMENT_CARPETEDHALLWAY, 0.153F, 0.259F, 2.0F +#define EAX_PRESET_HALLWAY EAX_ENVIRONMENT_HALLWAY, 0.361F, 1.493F, 0.0F +#define EAX_PRESET_STONECORRIDOR EAX_ENVIRONMENT_STONECORRIDOR, 0.444F, 2.697F, 0.638F +#define EAX_PRESET_ALLEY EAX_ENVIRONMENT_ALLEY, 0.25F, 1.752F, 0.776F +#define EAX_PRESET_FOREST EAX_ENVIRONMENT_FOREST, 0.111F, 3.145F, 0.472F +#define EAX_PRESET_CITY EAX_ENVIRONMENT_CITY, 0.111F, 2.767F, 0.224F +#define EAX_PRESET_MOUNTAINS EAX_ENVIRONMENT_MOUNTAINS, 0.194F, 7.841F, 0.472F +#define EAX_PRESET_QUARRY EAX_ENVIRONMENT_QUARRY, 1.0F, 1.499F, 0.5F +#define EAX_PRESET_PLAIN EAX_ENVIRONMENT_PLAIN, 0.097F, 2.767F, 0.224F +#define EAX_PRESET_PARKINGLOT EAX_ENVIRONMENT_PARKINGLOT, 0.208F, 1.652F, 1.5F +#define EAX_PRESET_SEWERPIPE EAX_ENVIRONMENT_SEWERPIPE, 0.652F, 2.886F, 0.25F +#define EAX_PRESET_UNDERWATER EAX_ENVIRONMENT_UNDERWATER, 1.0F, 1.499F, 0.0F +#define EAX_PRESET_DRUGGED EAX_ENVIRONMENT_DRUGGED, 0.875F, 8.392F, 1.388F +#define EAX_PRESET_DIZZY EAX_ENVIRONMENT_DIZZY, 0.139F, 17.234F, 0.666F +#define EAX_PRESET_PSYCHOTIC EAX_ENVIRONMENT_PSYCHOTIC, 0.486F, 7.563F, 0.806F -typedef DWORD (CALLBACK STREAMPROC)(HSTREAM handle, void *buffer, DWORD length, void *user); +typedef DWORD(CALLBACK STREAMPROC)(HSTREAM handle, void *buffer, DWORD length, void *user); /* User stream callback function. NOTE: A stream function should obviously be as quick as possible, other streams (and MOD musics) can't be mixed until it's finished. handle : The stream that needs writing @@ -505,73 +504,73 @@ length : Number of bytes to write user : The 'user' parameter value given when calling BASS_StreamCreate RETURN : Number of bytes written. Set the BASS_STREAMPROC_END flag to end the stream. */ -#define BASS_STREAMPROC_END 0x80000000 // end of user stream flag +#define BASS_STREAMPROC_END 0x80000000 // end of user stream flag // special STREAMPROCs -#define STREAMPROC_DUMMY (STREAMPROC*)0 // "dummy" stream -#define STREAMPROC_PUSH (STREAMPROC*)-1 // push stream -#define STREAMPROC_DEVICE (STREAMPROC*)-2 // device mix stream -#define STREAMPROC_DEVICE_3D (STREAMPROC*)-3 // device 3D mix stream +#define STREAMPROC_DUMMY (STREAMPROC *)0 // "dummy" stream +#define STREAMPROC_PUSH (STREAMPROC *)-1 // push stream +#define STREAMPROC_DEVICE (STREAMPROC *)-2 // device mix stream +#define STREAMPROC_DEVICE_3D (STREAMPROC *)-3 // device 3D mix stream // BASS_StreamCreateFileUser file systems -#define STREAMFILE_NOBUFFER 0 -#define STREAMFILE_BUFFER 1 -#define STREAMFILE_BUFFERPUSH 2 +#define STREAMFILE_NOBUFFER 0 +#define STREAMFILE_BUFFER 1 +#define STREAMFILE_BUFFERPUSH 2 // User file stream callback functions -typedef void (CALLBACK FILECLOSEPROC)(void *user); -typedef QWORD (CALLBACK FILELENPROC)(void *user); -typedef DWORD (CALLBACK FILEREADPROC)(void *buffer, DWORD length, void *user); -typedef BOOL (CALLBACK FILESEEKPROC)(QWORD offset, void *user); +typedef void(CALLBACK FILECLOSEPROC)(void *user); +typedef QWORD(CALLBACK FILELENPROC)(void *user); +typedef DWORD(CALLBACK FILEREADPROC)(void *buffer, DWORD length, void *user); +typedef BOOL(CALLBACK FILESEEKPROC)(QWORD offset, void *user); typedef struct { - FILECLOSEPROC *close; - FILELENPROC *length; - FILEREADPROC *read; - FILESEEKPROC *seek; + FILECLOSEPROC *close; + FILELENPROC *length; + FILEREADPROC *read; + FILESEEKPROC *seek; } BASS_FILEPROCS; // BASS_StreamPutFileData options -#define BASS_FILEDATA_END 0 // end & close the file +#define BASS_FILEDATA_END 0 // end & close the file // BASS_StreamGetFilePosition modes -#define BASS_FILEPOS_CURRENT 0 -#define BASS_FILEPOS_DECODE BASS_FILEPOS_CURRENT -#define BASS_FILEPOS_DOWNLOAD 1 -#define BASS_FILEPOS_END 2 -#define BASS_FILEPOS_START 3 -#define BASS_FILEPOS_CONNECTED 4 -#define BASS_FILEPOS_BUFFER 5 -#define BASS_FILEPOS_SOCKET 6 -#define BASS_FILEPOS_ASYNCBUF 7 -#define BASS_FILEPOS_SIZE 8 -#define BASS_FILEPOS_BUFFERING 9 +#define BASS_FILEPOS_CURRENT 0 +#define BASS_FILEPOS_DECODE BASS_FILEPOS_CURRENT +#define BASS_FILEPOS_DOWNLOAD 1 +#define BASS_FILEPOS_END 2 +#define BASS_FILEPOS_START 3 +#define BASS_FILEPOS_CONNECTED 4 +#define BASS_FILEPOS_BUFFER 5 +#define BASS_FILEPOS_SOCKET 6 +#define BASS_FILEPOS_ASYNCBUF 7 +#define BASS_FILEPOS_SIZE 8 +#define BASS_FILEPOS_BUFFERING 9 -typedef void (CALLBACK DOWNLOADPROC)(const void *buffer, DWORD length, void *user); +typedef void(CALLBACK DOWNLOADPROC)(const void *buffer, DWORD length, void *user); /* Internet stream download callback function. buffer : Buffer containing the downloaded data... NULL=end of download length : Number of bytes in the buffer user : The 'user' parameter value given when calling BASS_StreamCreateURL */ // BASS_ChannelSetSync types -#define BASS_SYNC_POS 0 -#define BASS_SYNC_END 2 -#define BASS_SYNC_META 4 -#define BASS_SYNC_SLIDE 5 -#define BASS_SYNC_STALL 6 -#define BASS_SYNC_DOWNLOAD 7 -#define BASS_SYNC_FREE 8 -#define BASS_SYNC_SETPOS 11 -#define BASS_SYNC_MUSICPOS 10 -#define BASS_SYNC_MUSICINST 1 -#define BASS_SYNC_MUSICFX 3 -#define BASS_SYNC_OGG_CHANGE 12 -#define BASS_SYNC_DEV_FAIL 14 -#define BASS_SYNC_DEV_FORMAT 15 -#define BASS_SYNC_MIXTIME 0x40000000 // flag: sync at mixtime, else at playtime -#define BASS_SYNC_ONETIME 0x80000000 // flag: sync only once, else continuously +#define BASS_SYNC_POS 0 +#define BASS_SYNC_END 2 +#define BASS_SYNC_META 4 +#define BASS_SYNC_SLIDE 5 +#define BASS_SYNC_STALL 6 +#define BASS_SYNC_DOWNLOAD 7 +#define BASS_SYNC_FREE 8 +#define BASS_SYNC_SETPOS 11 +#define BASS_SYNC_MUSICPOS 10 +#define BASS_SYNC_MUSICINST 1 +#define BASS_SYNC_MUSICFX 3 +#define BASS_SYNC_OGG_CHANGE 12 +#define BASS_SYNC_DEV_FAIL 14 +#define BASS_SYNC_DEV_FORMAT 15 +#define BASS_SYNC_MIXTIME 0x40000000 // flag: sync at mixtime, else at playtime +#define BASS_SYNC_ONETIME 0x80000000 // flag: sync only once, else continuously -typedef void (CALLBACK SYNCPROC)(HSYNC handle, DWORD channel, DWORD data, void *user); +typedef void(CALLBACK SYNCPROC)(HSYNC handle, DWORD channel, DWORD data, void *user); /* Sync callback function. NOTE: a sync callback function should be very quick as other syncs can't be processed until it has finished. If the sync is a "mixtime" sync, then other streams and MOD musics can't be mixed until @@ -581,7 +580,7 @@ channel: Channel that the sync occured in data : Additional data associated with the sync's occurance user : The 'user' parameter given when calling BASS_ChannelSetSync */ -typedef void (CALLBACK DSPPROC)(HDSP handle, DWORD channel, void *buffer, DWORD length, void *user); +typedef void(CALLBACK DSPPROC)(HDSP handle, DWORD channel, void *buffer, DWORD length, void *user); /* DSP callback function. NOTE: A DSP function should obviously be as quick as possible... other DSP functions, streams and MOD musics can not be processed until it's finished. @@ -591,7 +590,7 @@ buffer : Buffer to apply the DSP to length : Number of bytes in the buffer user : The 'user' parameter given when calling BASS_ChannelSetDSP */ -typedef BOOL (CALLBACK RECORDPROC)(HRECORD handle, const void *buffer, DWORD length, void *user); +typedef BOOL(CALLBACK RECORDPROC)(HRECORD handle, const void *buffer, DWORD length, void *user); /* Recording callback function. handle : The recording handle buffer : Buffer containing the recorded sample data @@ -600,396 +599,395 @@ user : The 'user' parameter value given when calling BASS_RecordStart RETURN : TRUE = continue recording, FALSE = stop */ // BASS_ChannelIsActive return values -#define BASS_ACTIVE_STOPPED 0 -#define BASS_ACTIVE_PLAYING 1 -#define BASS_ACTIVE_STALLED 2 -#define BASS_ACTIVE_PAUSED 3 -#define BASS_ACTIVE_PAUSED_DEVICE 4 +#define BASS_ACTIVE_STOPPED 0 +#define BASS_ACTIVE_PLAYING 1 +#define BASS_ACTIVE_STALLED 2 +#define BASS_ACTIVE_PAUSED 3 +#define BASS_ACTIVE_PAUSED_DEVICE 4 // Channel attributes -#define BASS_ATTRIB_FREQ 1 -#define BASS_ATTRIB_VOL 2 -#define BASS_ATTRIB_PAN 3 -#define BASS_ATTRIB_EAXMIX 4 -#define BASS_ATTRIB_NOBUFFER 5 -#define BASS_ATTRIB_VBR 6 -#define BASS_ATTRIB_CPU 7 -#define BASS_ATTRIB_SRC 8 -#define BASS_ATTRIB_NET_RESUME 9 -#define BASS_ATTRIB_SCANINFO 10 -#define BASS_ATTRIB_NORAMP 11 -#define BASS_ATTRIB_BITRATE 12 -#define BASS_ATTRIB_BUFFER 13 -#define BASS_ATTRIB_MUSIC_AMPLIFY 0x100 -#define BASS_ATTRIB_MUSIC_PANSEP 0x101 -#define BASS_ATTRIB_MUSIC_PSCALER 0x102 -#define BASS_ATTRIB_MUSIC_BPM 0x103 -#define BASS_ATTRIB_MUSIC_SPEED 0x104 +#define BASS_ATTRIB_FREQ 1 +#define BASS_ATTRIB_VOL 2 +#define BASS_ATTRIB_PAN 3 +#define BASS_ATTRIB_EAXMIX 4 +#define BASS_ATTRIB_NOBUFFER 5 +#define BASS_ATTRIB_VBR 6 +#define BASS_ATTRIB_CPU 7 +#define BASS_ATTRIB_SRC 8 +#define BASS_ATTRIB_NET_RESUME 9 +#define BASS_ATTRIB_SCANINFO 10 +#define BASS_ATTRIB_NORAMP 11 +#define BASS_ATTRIB_BITRATE 12 +#define BASS_ATTRIB_BUFFER 13 +#define BASS_ATTRIB_MUSIC_AMPLIFY 0x100 +#define BASS_ATTRIB_MUSIC_PANSEP 0x101 +#define BASS_ATTRIB_MUSIC_PSCALER 0x102 +#define BASS_ATTRIB_MUSIC_BPM 0x103 +#define BASS_ATTRIB_MUSIC_SPEED 0x104 #define BASS_ATTRIB_MUSIC_VOL_GLOBAL 0x105 -#define BASS_ATTRIB_MUSIC_ACTIVE 0x106 -#define BASS_ATTRIB_MUSIC_VOL_CHAN 0x200 // + channel # -#define BASS_ATTRIB_MUSIC_VOL_INST 0x300 // + instrument # +#define BASS_ATTRIB_MUSIC_ACTIVE 0x106 +#define BASS_ATTRIB_MUSIC_VOL_CHAN 0x200 // + channel # +#define BASS_ATTRIB_MUSIC_VOL_INST 0x300 // + instrument # // BASS_ChannelSlideAttribute flags -#define BASS_SLIDE_LOG 0x1000000 +#define BASS_SLIDE_LOG 0x1000000 // BASS_ChannelGetData flags -#define BASS_DATA_AVAILABLE 0 // query how much data is buffered -#define BASS_DATA_FIXED 0x20000000 // flag: return 8.24 fixed-point data -#define BASS_DATA_FLOAT 0x40000000 // flag: return floating-point sample data -#define BASS_DATA_FFT256 0x80000000 // 256 sample FFT -#define BASS_DATA_FFT512 0x80000001 // 512 FFT -#define BASS_DATA_FFT1024 0x80000002 // 1024 FFT -#define BASS_DATA_FFT2048 0x80000003 // 2048 FFT -#define BASS_DATA_FFT4096 0x80000004 // 4096 FFT -#define BASS_DATA_FFT8192 0x80000005 // 8192 FFT -#define BASS_DATA_FFT16384 0x80000006 // 16384 FFT -#define BASS_DATA_FFT32768 0x80000007 // 32768 FFT -#define BASS_DATA_FFT_INDIVIDUAL 0x10 // FFT flag: FFT for each channel, else all combined -#define BASS_DATA_FFT_NOWINDOW 0x20 // FFT flag: no Hanning window -#define BASS_DATA_FFT_REMOVEDC 0x40 // FFT flag: pre-remove DC bias -#define BASS_DATA_FFT_COMPLEX 0x80 // FFT flag: return complex data -#define BASS_DATA_FFT_NYQUIST 0x100 // FFT flag: return extra Nyquist value +#define BASS_DATA_AVAILABLE 0 // query how much data is buffered +#define BASS_DATA_FIXED 0x20000000 // flag: return 8.24 fixed-point data +#define BASS_DATA_FLOAT 0x40000000 // flag: return floating-point sample data +#define BASS_DATA_FFT256 0x80000000 // 256 sample FFT +#define BASS_DATA_FFT512 0x80000001 // 512 FFT +#define BASS_DATA_FFT1024 0x80000002 // 1024 FFT +#define BASS_DATA_FFT2048 0x80000003 // 2048 FFT +#define BASS_DATA_FFT4096 0x80000004 // 4096 FFT +#define BASS_DATA_FFT8192 0x80000005 // 8192 FFT +#define BASS_DATA_FFT16384 0x80000006 // 16384 FFT +#define BASS_DATA_FFT32768 0x80000007 // 32768 FFT +#define BASS_DATA_FFT_INDIVIDUAL 0x10 // FFT flag: FFT for each channel, else all combined +#define BASS_DATA_FFT_NOWINDOW 0x20 // FFT flag: no Hanning window +#define BASS_DATA_FFT_REMOVEDC 0x40 // FFT flag: pre-remove DC bias +#define BASS_DATA_FFT_COMPLEX 0x80 // FFT flag: return complex data +#define BASS_DATA_FFT_NYQUIST 0x100 // FFT flag: return extra Nyquist value // BASS_ChannelGetLevelEx flags -#define BASS_LEVEL_MONO 1 -#define BASS_LEVEL_STEREO 2 -#define BASS_LEVEL_RMS 4 -#define BASS_LEVEL_VOLPAN 8 +#define BASS_LEVEL_MONO 1 +#define BASS_LEVEL_STEREO 2 +#define BASS_LEVEL_RMS 4 +#define BASS_LEVEL_VOLPAN 8 // BASS_ChannelGetTags types : what's returned -#define BASS_TAG_ID3 0 // ID3v1 tags : TAG_ID3 structure -#define BASS_TAG_ID3V2 1 // ID3v2 tags : variable length block -#define BASS_TAG_OGG 2 // OGG comments : series of null-terminated UTF-8 strings -#define BASS_TAG_HTTP 3 // HTTP headers : series of null-terminated ANSI strings -#define BASS_TAG_ICY 4 // ICY headers : series of null-terminated ANSI strings -#define BASS_TAG_META 5 // ICY metadata : ANSI string -#define BASS_TAG_APE 6 // APE tags : series of null-terminated UTF-8 strings -#define BASS_TAG_MP4 7 // MP4/iTunes metadata : series of null-terminated UTF-8 strings -#define BASS_TAG_WMA 8 // WMA tags : series of null-terminated UTF-8 strings -#define BASS_TAG_VENDOR 9 // OGG encoder : UTF-8 string -#define BASS_TAG_LYRICS3 10 // Lyric3v2 tag : ASCII string -#define BASS_TAG_CA_CODEC 11 // CoreAudio codec info : TAG_CA_CODEC structure -#define BASS_TAG_MF 13 // Media Foundation tags : series of null-terminated UTF-8 strings -#define BASS_TAG_WAVEFORMAT 14 // WAVE format : WAVEFORMATEEX structure -#define BASS_TAG_AM_MIME 15 // Android Media MIME type : ASCII string -#define BASS_TAG_AM_NAME 16 // Android Media codec name : ASCII string -#define BASS_TAG_RIFF_INFO 0x100 // RIFF "INFO" tags : series of null-terminated ANSI strings -#define BASS_TAG_RIFF_BEXT 0x101 // RIFF/BWF "bext" tags : TAG_BEXT structure -#define BASS_TAG_RIFF_CART 0x102 // RIFF/BWF "cart" tags : TAG_CART structure -#define BASS_TAG_RIFF_DISP 0x103 // RIFF "DISP" text tag : ANSI string -#define BASS_TAG_RIFF_CUE 0x104 // RIFF "cue " chunk : TAG_CUE structure -#define BASS_TAG_RIFF_SMPL 0x105 // RIFF "smpl" chunk : TAG_SMPL structure -#define BASS_TAG_APE_BINARY 0x1000 // + index #, binary APE tag : TAG_APE_BINARY structure -#define BASS_TAG_MUSIC_NAME 0x10000 // MOD music name : ANSI string -#define BASS_TAG_MUSIC_MESSAGE 0x10001 // MOD message : ANSI string -#define BASS_TAG_MUSIC_ORDERS 0x10002 // MOD order list : BYTE array of pattern numbers -#define BASS_TAG_MUSIC_AUTH 0x10003 // MOD author : UTF-8 string -#define BASS_TAG_MUSIC_INST 0x10100 // + instrument #, MOD instrument name : ANSI string -#define BASS_TAG_MUSIC_SAMPLE 0x10300 // + sample #, MOD sample name : ANSI string - +#define BASS_TAG_ID3 0 // ID3v1 tags : TAG_ID3 structure +#define BASS_TAG_ID3V2 1 // ID3v2 tags : variable length block +#define BASS_TAG_OGG 2 // OGG comments : series of null-terminated UTF-8 strings +#define BASS_TAG_HTTP 3 // HTTP headers : series of null-terminated ANSI strings +#define BASS_TAG_ICY 4 // ICY headers : series of null-terminated ANSI strings +#define BASS_TAG_META 5 // ICY metadata : ANSI string +#define BASS_TAG_APE 6 // APE tags : series of null-terminated UTF-8 strings +#define BASS_TAG_MP4 7 // MP4/iTunes metadata : series of null-terminated UTF-8 strings +#define BASS_TAG_WMA 8 // WMA tags : series of null-terminated UTF-8 strings +#define BASS_TAG_VENDOR 9 // OGG encoder : UTF-8 string +#define BASS_TAG_LYRICS3 10 // Lyric3v2 tag : ASCII string +#define BASS_TAG_CA_CODEC 11 // CoreAudio codec info : TAG_CA_CODEC structure +#define BASS_TAG_MF 13 // Media Foundation tags : series of null-terminated UTF-8 strings +#define BASS_TAG_WAVEFORMAT 14 // WAVE format : WAVEFORMATEEX structure +#define BASS_TAG_AM_MIME 15 // Android Media MIME type : ASCII string +#define BASS_TAG_AM_NAME 16 // Android Media codec name : ASCII string +#define BASS_TAG_RIFF_INFO 0x100 // RIFF "INFO" tags : series of null-terminated ANSI strings +#define BASS_TAG_RIFF_BEXT 0x101 // RIFF/BWF "bext" tags : TAG_BEXT structure +#define BASS_TAG_RIFF_CART 0x102 // RIFF/BWF "cart" tags : TAG_CART structure +#define BASS_TAG_RIFF_DISP 0x103 // RIFF "DISP" text tag : ANSI string +#define BASS_TAG_RIFF_CUE 0x104 // RIFF "cue " chunk : TAG_CUE structure +#define BASS_TAG_RIFF_SMPL 0x105 // RIFF "smpl" chunk : TAG_SMPL structure +#define BASS_TAG_APE_BINARY 0x1000 // + index #, binary APE tag : TAG_APE_BINARY structure +#define BASS_TAG_MUSIC_NAME 0x10000 // MOD music name : ANSI string +#define BASS_TAG_MUSIC_MESSAGE 0x10001 // MOD message : ANSI string +#define BASS_TAG_MUSIC_ORDERS 0x10002 // MOD order list : BYTE array of pattern numbers +#define BASS_TAG_MUSIC_AUTH 0x10003 // MOD author : UTF-8 string +#define BASS_TAG_MUSIC_INST 0x10100 // + instrument #, MOD instrument name : ANSI string +#define BASS_TAG_MUSIC_SAMPLE 0x10300 // + sample #, MOD sample name : ANSI string + // ID3v1 tag structure typedef struct { - char id[3]; - char title[30]; - char artist[30]; - char album[30]; - char year[4]; - char comment[30]; - BYTE genre; + char id[3]; + char title[30]; + char artist[30]; + char album[30]; + char year[4]; + char comment[30]; + BYTE genre; } TAG_ID3; - + // Binary APE tag structure -typedef struct { - const char *key; - const void *data; - DWORD length; -} TAG_APE_BINARY; - -// BWF "bext" tag structure +typedef struct { + const char *key; + const void *data; + DWORD length; +} TAG_APE_BINARY; + +// BWF "bext" tag structure #ifdef _MSC_VER #pragma warning(push) -#pragma warning(disable:4200) +#pragma warning(disable : 4200) #endif -#pragma pack(push,1) +#pragma pack(push, 1) typedef struct { - char Description[256]; // description - char Originator[32]; // name of the originator - char OriginatorReference[32]; // reference of the originator - char OriginationDate[10]; // date of creation (yyyy-mm-dd) - char OriginationTime[8]; // time of creation (hh-mm-ss) - QWORD TimeReference; // first sample count since midnight (little-endian) - WORD Version; // BWF version (little-endian) - BYTE UMID[64]; // SMPTE UMID - BYTE Reserved[190]; -#if defined(__GNUC__) && __GNUC__<3 - char CodingHistory[0]; // history -#elif 1 // change to 0 if compiler fails the following line - char CodingHistory[]; // history + char Description[256]; // description + char Originator[32]; // name of the originator + char OriginatorReference[32]; // reference of the originator + char OriginationDate[10]; // date of creation (yyyy-mm-dd) + char OriginationTime[8]; // time of creation (hh-mm-ss) + QWORD TimeReference; // first sample count since midnight (little-endian) + WORD Version; // BWF version (little-endian) + BYTE UMID[64]; // SMPTE UMID + BYTE Reserved[190]; +#if defined(__GNUC__) && __GNUC__ < 3 + char CodingHistory[0]; // history +#elif 1 // change to 0 if compiler fails the following line + char CodingHistory[]; // history #else - char CodingHistory[1]; // history + char CodingHistory[1]; // history #endif } TAG_BEXT; -#pragma pack(pop) - -// BWF "cart" tag structures -typedef struct -{ - DWORD dwUsage; // FOURCC timer usage ID - DWORD dwValue; // timer value in samples from head -} TAG_CART_TIMER; - -typedef struct -{ - char Version[4]; // version of the data structure - char Title[64]; // title of cart audio sequence - char Artist[64]; // artist or creator name - char CutID[64]; // cut number identification - char ClientID[64]; // client identification - char Category[64]; // category ID, PSA, NEWS, etc - char Classification[64]; // classification or auxiliary key - char OutCue[64]; // out cue text - char StartDate[10]; // yyyy-mm-dd - char StartTime[8]; // hh:mm:ss - char EndDate[10]; // yyyy-mm-dd - char EndTime[8]; // hh:mm:ss - char ProducerAppID[64]; // name of vendor or application - char ProducerAppVersion[64]; // version of producer application - char UserDef[64]; // user defined text - DWORD dwLevelReference; // sample value for 0 dB reference - TAG_CART_TIMER PostTimer[8]; // 8 time markers after head - char Reserved[276]; - char URL[1024]; // uniform resource locator -#if defined(__GNUC__) && __GNUC__<3 - char TagText[0]; // free form text for scripts or tags -#elif 1 // change to 0 if compiler fails the following line - char TagText[]; // free form text for scripts or tags -#else - char TagText[1]; // free form text for scripts or tags -#endif -} TAG_CART; - -// RIFF "cue " tag structures -typedef struct -{ - DWORD dwName; - DWORD dwPosition; - DWORD fccChunk; - DWORD dwChunkStart; - DWORD dwBlockStart; - DWORD dwSampleOffset; -} TAG_CUE_POINT; - -typedef struct -{ - DWORD dwCuePoints; -#if defined(__GNUC__) && __GNUC__<3 - TAG_CUE_POINT CuePoints[0]; -#elif 1 // change to 0 if compiler fails the following line - TAG_CUE_POINT CuePoints[]; -#else - TAG_CUE_POINT CuePoints[1]; -#endif -} TAG_CUE; - -// RIFF "smpl" tag structures -typedef struct -{ - DWORD dwIdentifier; - DWORD dwType; - DWORD dwStart; - DWORD dwEnd; - DWORD dwFraction; - DWORD dwPlayCount; -} TAG_SMPL_LOOP; - -typedef struct -{ - DWORD dwManufacturer; - DWORD dwProduct; - DWORD dwSamplePeriod; - DWORD dwMIDIUnityNote; - DWORD dwMIDIPitchFraction; - DWORD dwSMPTEFormat; - DWORD dwSMPTEOffset; - DWORD cSampleLoops; - DWORD cbSamplerData; -#if defined(__GNUC__) && __GNUC__<3 - TAG_SMPL_LOOP SampleLoops[0]; -#elif 1 // change to 0 if compiler fails the following line - TAG_SMPL_LOOP SampleLoops[]; -#else - TAG_SMPL_LOOP SampleLoops[1]; -#endif -} TAG_SMPL; -#ifdef _MSC_VER -#pragma warning(pop) -#endif - +#pragma pack(pop) + +// BWF "cart" tag structures +typedef struct +{ + DWORD dwUsage; // FOURCC timer usage ID + DWORD dwValue; // timer value in samples from head +} TAG_CART_TIMER; + +typedef struct +{ + char Version[4]; // version of the data structure + char Title[64]; // title of cart audio sequence + char Artist[64]; // artist or creator name + char CutID[64]; // cut number identification + char ClientID[64]; // client identification + char Category[64]; // category ID, PSA, NEWS, etc + char Classification[64]; // classification or auxiliary key + char OutCue[64]; // out cue text + char StartDate[10]; // yyyy-mm-dd + char StartTime[8]; // hh:mm:ss + char EndDate[10]; // yyyy-mm-dd + char EndTime[8]; // hh:mm:ss + char ProducerAppID[64]; // name of vendor or application + char ProducerAppVersion[64]; // version of producer application + char UserDef[64]; // user defined text + DWORD dwLevelReference; // sample value for 0 dB reference + TAG_CART_TIMER PostTimer[8]; // 8 time markers after head + char Reserved[276]; + char URL[1024]; // uniform resource locator +#if defined(__GNUC__) && __GNUC__ < 3 + char TagText[0]; // free form text for scripts or tags +#elif 1 // change to 0 if compiler fails the following line + char TagText[]; // free form text for scripts or tags +#else + char TagText[1]; // free form text for scripts or tags +#endif +} TAG_CART; + +// RIFF "cue " tag structures +typedef struct +{ + DWORD dwName; + DWORD dwPosition; + DWORD fccChunk; + DWORD dwChunkStart; + DWORD dwBlockStart; + DWORD dwSampleOffset; +} TAG_CUE_POINT; + +typedef struct +{ + DWORD dwCuePoints; +#if defined(__GNUC__) && __GNUC__ < 3 + TAG_CUE_POINT CuePoints[0]; +#elif 1 // change to 0 if compiler fails the following line + TAG_CUE_POINT CuePoints[]; +#else + TAG_CUE_POINT CuePoints[1]; +#endif +} TAG_CUE; + +// RIFF "smpl" tag structures +typedef struct +{ + DWORD dwIdentifier; + DWORD dwType; + DWORD dwStart; + DWORD dwEnd; + DWORD dwFraction; + DWORD dwPlayCount; +} TAG_SMPL_LOOP; + +typedef struct +{ + DWORD dwManufacturer; + DWORD dwProduct; + DWORD dwSamplePeriod; + DWORD dwMIDIUnityNote; + DWORD dwMIDIPitchFraction; + DWORD dwSMPTEFormat; + DWORD dwSMPTEOffset; + DWORD cSampleLoops; + DWORD cbSamplerData; +#if defined(__GNUC__) && __GNUC__ < 3 + TAG_SMPL_LOOP SampleLoops[0]; +#elif 1 // change to 0 if compiler fails the following line + TAG_SMPL_LOOP SampleLoops[]; +#else + TAG_SMPL_LOOP SampleLoops[1]; +#endif +} TAG_SMPL; +#ifdef _MSC_VER +#pragma warning(pop) +#endif + // CoreAudio codec info structure typedef struct { - DWORD ftype; // file format - DWORD atype; // audio format - const char *name; // description + DWORD ftype; // file format + DWORD atype; // audio format + const char *name; // description } TAG_CA_CODEC; -#ifndef _WAVEFORMATEX_ -#define _WAVEFORMATEX_ -#pragma pack(push,1) -typedef struct tWAVEFORMATEX -{ - WORD wFormatTag; - WORD nChannels; - DWORD nSamplesPerSec; - DWORD nAvgBytesPerSec; - WORD nBlockAlign; - WORD wBitsPerSample; - WORD cbSize; -} WAVEFORMATEX, *PWAVEFORMATEX, *LPWAVEFORMATEX; -typedef const WAVEFORMATEX *LPCWAVEFORMATEX; -#pragma pack(pop) -#endif - +#ifndef _WAVEFORMATEX_ +#define _WAVEFORMATEX_ +#pragma pack(push, 1) +typedef struct tWAVEFORMATEX { + WORD wFormatTag; + WORD nChannels; + DWORD nSamplesPerSec; + DWORD nAvgBytesPerSec; + WORD nBlockAlign; + WORD wBitsPerSample; + WORD cbSize; +} WAVEFORMATEX, *PWAVEFORMATEX, *LPWAVEFORMATEX; +typedef const WAVEFORMATEX *LPCWAVEFORMATEX; +#pragma pack(pop) +#endif + // BASS_ChannelGetLength/GetPosition/SetPosition modes -#define BASS_POS_BYTE 0 // byte position -#define BASS_POS_MUSIC_ORDER 1 // order.row position, MAKELONG(order,row) -#define BASS_POS_OGG 3 // OGG bitstream number -#define BASS_POS_RESET 0x2000000 // flag: reset user file buffers -#define BASS_POS_RELATIVE 0x4000000 // flag: seek relative to the current position -#define BASS_POS_INEXACT 0x8000000 // flag: allow seeking to inexact position -#define BASS_POS_DECODE 0x10000000 // flag: get the decoding (not playing) position -#define BASS_POS_DECODETO 0x20000000 // flag: decode to the position instead of seeking -#define BASS_POS_SCAN 0x40000000 // flag: scan to the position +#define BASS_POS_BYTE 0 // byte position +#define BASS_POS_MUSIC_ORDER 1 // order.row position, MAKELONG(order,row) +#define BASS_POS_OGG 3 // OGG bitstream number +#define BASS_POS_RESET 0x2000000 // flag: reset user file buffers +#define BASS_POS_RELATIVE 0x4000000 // flag: seek relative to the current position +#define BASS_POS_INEXACT 0x8000000 // flag: allow seeking to inexact position +#define BASS_POS_DECODE 0x10000000 // flag: get the decoding (not playing) position +#define BASS_POS_DECODETO 0x20000000 // flag: decode to the position instead of seeking +#define BASS_POS_SCAN 0x40000000 // flag: scan to the position // BASS_ChannelSetDevice/GetDevice option -#define BASS_NODEVICE 0x20000 +#define BASS_NODEVICE 0x20000 // BASS_RecordSetInput flags -#define BASS_INPUT_OFF 0x10000 -#define BASS_INPUT_ON 0x20000 +#define BASS_INPUT_OFF 0x10000 +#define BASS_INPUT_ON 0x20000 -#define BASS_INPUT_TYPE_MASK 0xff000000 -#define BASS_INPUT_TYPE_UNDEF 0x00000000 -#define BASS_INPUT_TYPE_DIGITAL 0x01000000 -#define BASS_INPUT_TYPE_LINE 0x02000000 -#define BASS_INPUT_TYPE_MIC 0x03000000 -#define BASS_INPUT_TYPE_SYNTH 0x04000000 -#define BASS_INPUT_TYPE_CD 0x05000000 -#define BASS_INPUT_TYPE_PHONE 0x06000000 -#define BASS_INPUT_TYPE_SPEAKER 0x07000000 -#define BASS_INPUT_TYPE_WAVE 0x08000000 -#define BASS_INPUT_TYPE_AUX 0x09000000 -#define BASS_INPUT_TYPE_ANALOG 0x0a000000 +#define BASS_INPUT_TYPE_MASK 0xff000000 +#define BASS_INPUT_TYPE_UNDEF 0x00000000 +#define BASS_INPUT_TYPE_DIGITAL 0x01000000 +#define BASS_INPUT_TYPE_LINE 0x02000000 +#define BASS_INPUT_TYPE_MIC 0x03000000 +#define BASS_INPUT_TYPE_SYNTH 0x04000000 +#define BASS_INPUT_TYPE_CD 0x05000000 +#define BASS_INPUT_TYPE_PHONE 0x06000000 +#define BASS_INPUT_TYPE_SPEAKER 0x07000000 +#define BASS_INPUT_TYPE_WAVE 0x08000000 +#define BASS_INPUT_TYPE_AUX 0x09000000 +#define BASS_INPUT_TYPE_ANALOG 0x0a000000 // BASS_ChannelSetFX effect types -#define BASS_FX_DX8_CHORUS 0 -#define BASS_FX_DX8_COMPRESSOR 1 -#define BASS_FX_DX8_DISTORTION 2 -#define BASS_FX_DX8_ECHO 3 -#define BASS_FX_DX8_FLANGER 4 -#define BASS_FX_DX8_GARGLE 5 -#define BASS_FX_DX8_I3DL2REVERB 6 -#define BASS_FX_DX8_PARAMEQ 7 -#define BASS_FX_DX8_REVERB 8 -#define BASS_FX_VOLUME 9 +#define BASS_FX_DX8_CHORUS 0 +#define BASS_FX_DX8_COMPRESSOR 1 +#define BASS_FX_DX8_DISTORTION 2 +#define BASS_FX_DX8_ECHO 3 +#define BASS_FX_DX8_FLANGER 4 +#define BASS_FX_DX8_GARGLE 5 +#define BASS_FX_DX8_I3DL2REVERB 6 +#define BASS_FX_DX8_PARAMEQ 7 +#define BASS_FX_DX8_REVERB 8 +#define BASS_FX_VOLUME 9 typedef struct { - float fWetDryMix; - float fDepth; - float fFeedback; - float fFrequency; - DWORD lWaveform; // 0=triangle, 1=sine - float fDelay; - DWORD lPhase; // BASS_DX8_PHASE_xxx + float fWetDryMix; + float fDepth; + float fFeedback; + float fFrequency; + DWORD lWaveform; // 0=triangle, 1=sine + float fDelay; + DWORD lPhase; // BASS_DX8_PHASE_xxx } BASS_DX8_CHORUS; typedef struct { - float fGain; - float fAttack; - float fRelease; - float fThreshold; - float fRatio; - float fPredelay; + float fGain; + float fAttack; + float fRelease; + float fThreshold; + float fRatio; + float fPredelay; } BASS_DX8_COMPRESSOR; typedef struct { - float fGain; - float fEdge; - float fPostEQCenterFrequency; - float fPostEQBandwidth; - float fPreLowpassCutoff; + float fGain; + float fEdge; + float fPostEQCenterFrequency; + float fPostEQBandwidth; + float fPreLowpassCutoff; } BASS_DX8_DISTORTION; typedef struct { - float fWetDryMix; - float fFeedback; - float fLeftDelay; - float fRightDelay; - BOOL lPanDelay; + float fWetDryMix; + float fFeedback; + float fLeftDelay; + float fRightDelay; + BOOL lPanDelay; } BASS_DX8_ECHO; typedef struct { - float fWetDryMix; - float fDepth; - float fFeedback; - float fFrequency; - DWORD lWaveform; // 0=triangle, 1=sine - float fDelay; - DWORD lPhase; // BASS_DX8_PHASE_xxx + float fWetDryMix; + float fDepth; + float fFeedback; + float fFrequency; + DWORD lWaveform; // 0=triangle, 1=sine + float fDelay; + DWORD lPhase; // BASS_DX8_PHASE_xxx } BASS_DX8_FLANGER; typedef struct { - DWORD dwRateHz; // Rate of modulation in hz - DWORD dwWaveShape; // 0=triangle, 1=square + DWORD dwRateHz; // Rate of modulation in hz + DWORD dwWaveShape; // 0=triangle, 1=square } BASS_DX8_GARGLE; typedef struct { - int lRoom; // [-10000, 0] default: -1000 mB - int lRoomHF; // [-10000, 0] default: 0 mB - float flRoomRolloffFactor; // [0.0, 10.0] default: 0.0 - float flDecayTime; // [0.1, 20.0] default: 1.49s - float flDecayHFRatio; // [0.1, 2.0] default: 0.83 - int lReflections; // [-10000, 1000] default: -2602 mB - float flReflectionsDelay; // [0.0, 0.3] default: 0.007 s - int lReverb; // [-10000, 2000] default: 200 mB - float flReverbDelay; // [0.0, 0.1] default: 0.011 s - float flDiffusion; // [0.0, 100.0] default: 100.0 % - float flDensity; // [0.0, 100.0] default: 100.0 % - float flHFReference; // [20.0, 20000.0] default: 5000.0 Hz + int lRoom; // [-10000, 0] default: -1000 mB + int lRoomHF; // [-10000, 0] default: 0 mB + float flRoomRolloffFactor; // [0.0, 10.0] default: 0.0 + float flDecayTime; // [0.1, 20.0] default: 1.49s + float flDecayHFRatio; // [0.1, 2.0] default: 0.83 + int lReflections; // [-10000, 1000] default: -2602 mB + float flReflectionsDelay; // [0.0, 0.3] default: 0.007 s + int lReverb; // [-10000, 2000] default: 200 mB + float flReverbDelay; // [0.0, 0.1] default: 0.011 s + float flDiffusion; // [0.0, 100.0] default: 100.0 % + float flDensity; // [0.0, 100.0] default: 100.0 % + float flHFReference; // [20.0, 20000.0] default: 5000.0 Hz } BASS_DX8_I3DL2REVERB; typedef struct { - float fCenter; - float fBandwidth; - float fGain; + float fCenter; + float fBandwidth; + float fGain; } BASS_DX8_PARAMEQ; typedef struct { - float fInGain; // [-96.0,0.0] default: 0.0 dB - float fReverbMix; // [-96.0,0.0] default: 0.0 db - float fReverbTime; // [0.001,3000.0] default: 1000.0 ms - float fHighFreqRTRatio; // [0.001,0.999] default: 0.001 + float fInGain; // [-96.0,0.0] default: 0.0 dB + float fReverbMix; // [-96.0,0.0] default: 0.0 db + float fReverbTime; // [0.001,3000.0] default: 1000.0 ms + float fHighFreqRTRatio; // [0.001,0.999] default: 0.001 } BASS_DX8_REVERB; -#define BASS_DX8_PHASE_NEG_180 0 -#define BASS_DX8_PHASE_NEG_90 1 -#define BASS_DX8_PHASE_ZERO 2 -#define BASS_DX8_PHASE_90 3 -#define BASS_DX8_PHASE_180 4 - +#define BASS_DX8_PHASE_NEG_180 0 +#define BASS_DX8_PHASE_NEG_90 1 +#define BASS_DX8_PHASE_ZERO 2 +#define BASS_DX8_PHASE_90 3 +#define BASS_DX8_PHASE_180 4 + typedef struct { - float fTarget; - float fCurrent; - float fTime; - DWORD lCurve; + float fTarget; + float fCurrent; + float fTime; + DWORD lCurve; } BASS_FX_VOLUME_PARAM; - -typedef void (CALLBACK IOSNOTIFYPROC)(DWORD status); -/* iOS notification callback function. -status : The notification (BASS_IOSNOTIFY_xxx) */ - -#define BASS_IOSNOTIFY_INTERRUPT 1 // interruption started -#define BASS_IOSNOTIFY_INTERRUPT_END 2 // interruption ended + +typedef void(CALLBACK IOSNOTIFYPROC)(DWORD status); +/* iOS notification callback function. +status : The notification (BASS_IOSNOTIFY_xxx) */ + +#define BASS_IOSNOTIFY_INTERRUPT 1 // interruption started +#define BASS_IOSNOTIFY_INTERRUPT_END 2 // interruption ended BOOL BASSDEF(BASS_SetConfig)(DWORD option, DWORD value); DWORD BASSDEF(BASS_GetConfig)(DWORD option); @@ -998,7 +996,7 @@ void *BASSDEF(BASS_GetConfigPtr)(DWORD option); DWORD BASSDEF(BASS_GetVersion)(); int BASSDEF(BASS_ErrorGetCode)(); BOOL BASSDEF(BASS_GetDeviceInfo)(DWORD device, BASS_DEVICEINFO *info); -#if defined(_WIN32) && !defined(_WIN32_WCE) && !(WINAPI_FAMILY && WINAPI_FAMILY!=WINAPI_FAMILY_DESKTOP_APP) +#if defined(_WIN32) && !defined(_WIN32_WCE) && !(WINAPI_FAMILY && WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP) BOOL BASSDEF(BASS_Init)(int device, DWORD freq, DWORD flags, HWND win, const GUID *dsguid); #else BOOL BASSDEF(BASS_Init)(int device, DWORD freq, DWORD flags, void *win, void *dsguid); @@ -1006,7 +1004,7 @@ BOOL BASSDEF(BASS_Init)(int device, DWORD freq, DWORD flags, void *win, void *ds BOOL BASSDEF(BASS_SetDevice)(DWORD device); DWORD BASSDEF(BASS_GetDevice)(); BOOL BASSDEF(BASS_Free)(); -#if defined(_WIN32) && !defined(_WIN32_WCE) && !(WINAPI_FAMILY && WINAPI_FAMILY!=WINAPI_FAMILY_DESKTOP_APP) +#if defined(_WIN32) && !defined(_WIN32_WCE) && !(WINAPI_FAMILY && WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP) void *BASSDEF(BASS_GetDSoundObject)(DWORD object); #endif BOOL BASSDEF(BASS_GetInfo)(BASS_INFO *info); @@ -1028,7 +1026,7 @@ BOOL BASSDEF(BASS_Get3DFactors)(float *distf, float *rollf, float *doppf); BOOL BASSDEF(BASS_Set3DPosition)(const BASS_3DVECTOR *pos, const BASS_3DVECTOR *vel, const BASS_3DVECTOR *front, const BASS_3DVECTOR *top); BOOL BASSDEF(BASS_Get3DPosition)(BASS_3DVECTOR *pos, BASS_3DVECTOR *vel, BASS_3DVECTOR *front, BASS_3DVECTOR *top); void BASSDEF(BASS_Apply3D)(); -#if defined(_WIN32) && !defined(_WIN32_WCE) && !(WINAPI_FAMILY && WINAPI_FAMILY!=WINAPI_FAMILY_DESKTOP_APP) +#if defined(_WIN32) && !defined(_WIN32_WCE) && !(WINAPI_FAMILY && WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP) BOOL BASSDEF(BASS_SetEAXParameters)(int env, float vol, float decay, float damp); BOOL BASSDEF(BASS_GetEAXParameters)(DWORD *env, float *vol, float *decay, float *damp); #endif @@ -1094,7 +1092,7 @@ QWORD BASSDEF(BASS_ChannelGetLength)(DWORD handle, DWORD mode); BOOL BASSDEF(BASS_ChannelSetPosition)(DWORD handle, QWORD pos, DWORD mode); QWORD BASSDEF(BASS_ChannelGetPosition)(DWORD handle, DWORD mode); DWORD BASSDEF(BASS_ChannelGetLevel)(DWORD handle); -BOOL BASSDEF(BASS_ChannelGetLevelEx)(DWORD handle, float *levels, float length, DWORD flags); +BOOL BASSDEF(BASS_ChannelGetLevelEx)(DWORD handle, float *levels, float length, DWORD flags); DWORD BASSDEF(BASS_ChannelGetData)(DWORD handle, void *buffer, DWORD length); HSYNC BASSDEF(BASS_ChannelSetSync)(DWORD handle, DWORD type, QWORD param, SYNCPROC *proc, void *user); BOOL BASSDEF(BASS_ChannelRemoveSync)(DWORD handle, HSYNC sync); @@ -1109,41 +1107,41 @@ BOOL BASSDEF(BASS_FXSetParameters)(HFX handle, const void *params); BOOL BASSDEF(BASS_FXGetParameters)(HFX handle, void *params); BOOL BASSDEF(BASS_FXReset)(HFX handle); BOOL BASSDEF(BASS_FXSetPriority)(HFX handle, int priority); - + #ifdef __cplusplus } - -#if defined(_WIN32) && !defined(NOBASSOVERLOADS) -static inline HPLUGIN BASS_PluginLoad(const WCHAR *file, DWORD flags) -{ - return BASS_PluginLoad((const char*)file, flags|BASS_UNICODE); -} - -static inline HMUSIC BASS_MusicLoad(BOOL mem, const WCHAR *file, QWORD offset, DWORD length, DWORD flags, DWORD freq) -{ - return BASS_MusicLoad(mem, (const void*)file, offset, length, flags|BASS_UNICODE, freq); -} - -static inline HSAMPLE BASS_SampleLoad(BOOL mem, const WCHAR *file, QWORD offset, DWORD length, DWORD max, DWORD flags) -{ - return BASS_SampleLoad(mem, (const void*)file, offset, length, max, flags|BASS_UNICODE); -} - -static inline HSTREAM BASS_StreamCreateFile(BOOL mem, const WCHAR *file, QWORD offset, QWORD length, DWORD flags) -{ - return BASS_StreamCreateFile(mem, (const void*)file, offset, length, flags|BASS_UNICODE); -} - -static inline HSTREAM BASS_StreamCreateURL(const WCHAR *url, DWORD offset, DWORD flags, DOWNLOADPROC *proc, void *user) -{ - return BASS_StreamCreateURL((const char*)url, offset, flags|BASS_UNICODE, proc, user); -} - -static inline BOOL BASS_SetConfigPtr(DWORD option, const WCHAR *value) -{ - return BASS_SetConfigPtr(option|BASS_UNICODE, (const void*)value); -} -#endif + +#if defined(_WIN32) && !defined(NOBASSOVERLOADS) +static inline HPLUGIN BASS_PluginLoad(const WCHAR *file, DWORD flags) +{ + return BASS_PluginLoad((const char *)file, flags | BASS_UNICODE); +} + +static inline HMUSIC BASS_MusicLoad(BOOL mem, const WCHAR *file, QWORD offset, DWORD length, DWORD flags, DWORD freq) +{ + return BASS_MusicLoad(mem, (const void *)file, offset, length, flags | BASS_UNICODE, freq); +} + +static inline HSAMPLE BASS_SampleLoad(BOOL mem, const WCHAR *file, QWORD offset, DWORD length, DWORD max, DWORD flags) +{ + return BASS_SampleLoad(mem, (const void *)file, offset, length, max, flags | BASS_UNICODE); +} + +static inline HSTREAM BASS_StreamCreateFile(BOOL mem, const WCHAR *file, QWORD offset, QWORD length, DWORD flags) +{ + return BASS_StreamCreateFile(mem, (const void *)file, offset, length, flags | BASS_UNICODE); +} + +static inline HSTREAM BASS_StreamCreateURL(const WCHAR *url, DWORD offset, DWORD flags, DOWNLOADPROC *proc, void *user) +{ + return BASS_StreamCreateURL((const char *)url, offset, flags | BASS_UNICODE, proc, user); +} + +static inline BOOL BASS_SetConfigPtr(DWORD option, const WCHAR *value) +{ + return BASS_SetConfigPtr(option | BASS_UNICODE, (const void *)value); +} +#endif #endif #endif diff --git a/include/bassopus.h b/include/bassopus.h index 4e48124..757ff70 100644 --- a/include/bassopus.h +++ b/include/bassopus.h @@ -10,7 +10,7 @@ #include "bass.h" -#if BASSVERSION!=0x204 +#if BASSVERSION != 0x204 #error conflicting BASS and BASSOPUS versions #endif @@ -23,11 +23,11 @@ extern "C" { #endif // BASS_CHANNELINFO type -#define BASS_CTYPE_STREAM_OPUS 0x11200 +#define BASS_CTYPE_STREAM_OPUS 0x11200 // Additional attributes -#define BASS_ATTRIB_OPUS_ORIGFREQ 0x13000 -#define BASS_ATTRIB_OPUS_GAIN 0x13001 +#define BASS_ATTRIB_OPUS_ORIGFREQ 0x13000 +#define BASS_ATTRIB_OPUS_GAIN 0x13001 HSTREAM BASSOPUSDEF(BASS_OPUS_StreamCreateFile)(BOOL mem, const void *file, QWORD offset, QWORD length, DWORD flags); HSTREAM BASSOPUSDEF(BASS_OPUS_StreamCreateURL)(const char *url, DWORD offset, DWORD flags, DOWNLOADPROC *proc, void *user); @@ -39,12 +39,12 @@ HSTREAM BASSOPUSDEF(BASS_OPUS_StreamCreateFileUser)(DWORD system, DWORD flags, c #if defined(_WIN32) && !defined(NOBASSOVERLOADS) static inline HSTREAM BASS_OPUS_StreamCreateFile(BOOL mem, const WCHAR *file, QWORD offset, QWORD length, DWORD flags) { - return BASS_OPUS_StreamCreateFile(mem, (const void*)file, offset, length, flags|BASS_UNICODE); + return BASS_OPUS_StreamCreateFile(mem, (const void *)file, offset, length, flags | BASS_UNICODE); } static inline HSTREAM BASS_OPUS_StreamCreateURL(const WCHAR *url, DWORD offset, DWORD flags, DOWNLOADPROC *proc, void *user) { - return BASS_OPUS_StreamCreateURL((const char*)url, offset, flags|BASS_UNICODE, proc, user); + return BASS_OPUS_StreamCreateURL((const char *)url, offset, flags | BASS_UNICODE, proc, user); } #endif #endif diff --git a/include/chatlogpiece.h b/include/chatlogpiece.h index 303c235..c2d32b2 100644 --- a/include/chatlogpiece.h +++ b/include/chatlogpiece.h @@ -1,31 +1,30 @@ #ifndef CHATLOGPIECE_H #define CHATLOGPIECE_H -#include #include +#include -class chatlogpiece -{ +class chatlogpiece { public: - chatlogpiece(); - chatlogpiece(QString p_name, QString p_showname, QString p_message, bool p_song); - chatlogpiece(QString p_name, QString p_showname, QString p_message, bool p_song, QDateTime p_datetime); + chatlogpiece(); + chatlogpiece(QString p_name, QString p_showname, QString p_message, bool p_song); + chatlogpiece(QString p_name, QString p_showname, QString p_message, bool p_song, QDateTime p_datetime); - QString get_name(); - QString get_showname(); - QString get_message(); - bool is_song(); - QDateTime get_datetime(); - QString get_datetime_as_string(); + QString get_name(); + QString get_showname(); + QString get_message(); + bool is_song(); + QDateTime get_datetime(); + QString get_datetime_as_string(); - QString get_full(); + QString get_full(); private: - QString name; - QString showname; - QString message; - QDateTime datetime; - bool p_is_song; + QString name; + QString showname; + QString message; + QDateTime datetime; + bool p_is_song; }; #endif // CHATLOGPIECE_H diff --git a/include/courtroom.h b/include/courtroom.h index c1bd0a6..c3c6b87 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -1,792 +1,785 @@ #ifndef COURTROOM_H #define COURTROOM_H -#include "aoimage.h" +#include "aoapplication.h" +#include "aoblipplayer.h" #include "aobutton.h" #include "aocharbutton.h" -#include "aoemotebutton.h" -#include "aopacket.h" -#include "aoscene.h" -#include "aomovie.h" #include "aocharmovie.h" +#include "aoemotebutton.h" +#include "aoevidencebutton.h" +#include "aoevidencedisplay.h" +#include "aoimage.h" +#include "aolineedit.h" +#include "aomovie.h" #include "aomusicplayer.h" #include "aooptionsdialog.h" +#include "aopacket.h" +#include "aoscene.h" #include "aosfxplayer.h" -#include "aoblipplayer.h" -#include "aoevidencebutton.h" #include "aotextarea.h" -#include "aolineedit.h" #include "aotextedit.h" -#include "aoevidencedisplay.h" -#include "datatypes.h" -#include "aoapplication.h" -#include "lobby.h" -#include "hardware_functions.h" -#include "file_functions.h" +#include "chatlogpiece.h" #include "datatypes.h" #include "debug_functions.h" -#include "chatlogpiece.h" +#include "file_functions.h" +#include "hardware_functions.h" +#include "lobby.h" #include "scrolltext.h" -#include -#include -#include -#include -#include -#include #include -#include -#include -#include #include +#include +#include +#include +#include +#include #include -#include +#include +#include #include +#include +#include +#include -#include -#include -#include #include -#include +#include +#include +#include #include #include -#include -#include -#include -#include -#include #include -#include +#include +#include +#include +#include +#include +#include +#include //#include #include class AOApplication; -class Courtroom : public QMainWindow -{ - Q_OBJECT +class Courtroom : public QMainWindow { + Q_OBJECT public: - explicit Courtroom(AOApplication *p_ao_app); + explicit Courtroom(AOApplication *p_ao_app); - void append_char(char_type p_char){char_list.append(p_char);} - void append_evidence(evi_type p_evi){evidence_list.append(p_evi);} - void append_music(QString f_music){music_list.append(f_music);} - void append_area(QString f_area){area_list.append(f_area);} - void clear_music(){music_list.clear();} - void clear_areas(){area_list.clear();} + void append_char(char_type p_char) { char_list.append(p_char); } + void append_evidence(evi_type p_evi) { evidence_list.append(p_evi); } + void append_music(QString f_music) { music_list.append(f_music); } + void append_area(QString f_area) { area_list.append(f_area); } + void clear_music() { music_list.clear(); } + void clear_areas() { area_list.clear(); } - void fix_last_area() - { - if (area_list.size() > 0) + void fix_last_area() { - QString malplaced = area_list.last(); - area_list.removeLast(); - append_music(malplaced); + if (area_list.size() > 0) { + QString malplaced = area_list.last(); + area_list.removeLast(); + append_music(malplaced); + } } - } - void arup_append(int players, QString status, QString cm, QString locked) - { - arup_players.append(players); - arup_statuses.append(status); - arup_cms.append(cm); - arup_locks.append(locked); - } - - void arup_modify(int type, int place, QString value) - { - if (type == 0) + void arup_append(int players, QString status, QString cm, QString locked) { - if (arup_players.size() > place) - arup_players[place] = value.toInt(); + arup_players.append(players); + arup_statuses.append(status); + arup_cms.append(cm); + arup_locks.append(locked); } - else if (type == 1) + + void arup_modify(int type, int place, QString value) { - if (arup_statuses.size() > place) - arup_statuses[place] = value; + if (type == 0) { + if (arup_players.size() > place) + arup_players[place] = value.toInt(); + } + else if (type == 1) { + if (arup_statuses.size() > place) + arup_statuses[place] = value; + } + else if (type == 2) { + if (arup_cms.size() > place) + arup_cms[place] = value; + } + else if (type == 3) { + if (arup_locks.size() > place) + arup_locks[place] = value; + } + list_areas(); } - else if (type == 2) - { - if (arup_cms.size() > place) - arup_cms[place] = value; - } - else if (type == 3) - { - if (arup_locks.size() > place) - arup_locks[place] = value; - } - list_areas(); - } - void character_loading_finished(); + void character_loading_finished(); - //sets position of widgets based on theme ini files - void set_widgets(); + //sets position of widgets based on theme ini files + void set_widgets(); - //sets font size based on theme ini files - void set_font(QWidget *widget, QString class_name, QString p_identifier); + //sets font size based on theme ini files + void set_font(QWidget *widget, QString class_name, QString p_identifier); - //Get the properly constructed font - QFont get_qfont(QString font_name, int f_pointsize, bool antialias=true); + //Get the properly constructed font + QFont get_qfont(QString font_name, int f_pointsize, bool antialias = true); - //actual operation of setting the font on a widget - void set_qfont(QWidget *widget, QString class_name, QFont font, QColor f_color = Qt::black, bool bold = false); + //actual operation of setting the font on a widget + void set_qfont(QWidget *widget, QString class_name, QFont font, QColor f_color = Qt::black, bool bold = false); - //helper function that calls above function on the relevant widgets - void set_fonts(); + //helper function that calls above function on the relevant widgets + void set_fonts(); - //sets dropdown menu stylesheet - void set_dropdown(QWidget *widget); + //sets dropdown menu stylesheet + void set_dropdown(QWidget *widget); - //helper funciton that call above function on the relevant widgets - void set_dropdowns(); + //helper funciton that call above function on the relevant widgets + void set_dropdowns(); - void set_window_title(QString p_title); + void set_window_title(QString p_title); - //reads theme inis and sets size and pos based on the identifier - void set_size_and_pos(QWidget *p_widget, QString p_identifier); + //reads theme inis and sets size and pos based on the identifier + void set_size_and_pos(QWidget *p_widget, QString p_identifier); - //reads theme inis and returns the size and pos as defined by it - QPoint get_theme_pos(QString p_identifier); + //reads theme inis and returns the size and pos as defined by it + QPoint get_theme_pos(QString p_identifier); - //sets status as taken on character with cid n_char and places proper shading on charselect - void set_taken(int n_char, bool p_taken); + //sets status as taken on character with cid n_char and places proper shading on charselect + void set_taken(int n_char, bool p_taken); - //sets the current background to argument. also does some checks to see if it's a legacy bg - void set_background(QString p_background, bool display=false); + //sets the current background to argument. also does some checks to see if it's a legacy bg + void set_background(QString p_background, bool display = false); - //sets the local character pos/side to use. - void set_side(QString p_side); + //sets the local character pos/side to use. + void set_side(QString p_side); - //sets the pos dropdown - void set_pos_dropdown(QStringList pos_dropdowns); + //sets the pos dropdown + void set_pos_dropdown(QStringList pos_dropdowns); - //sets the evidence list member variable to argument - void set_evidence_list(QVector &p_evi_list); + //sets the evidence list member variable to argument + void set_evidence_list(QVector &p_evi_list); - //called when a DONE#% from the server was received - void done_received(); + //called when a DONE#% from the server was received + void done_received(); - //sets the local mute list based on characters available on the server - void set_mute_list(); + //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 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(QString f_desk_mod, QString f_side); + //sets desk and bg based on pos in chatmessage + void set_scene(QString f_desk_mod, QString f_side); - //takes in serverD-formatted IP list as prints a converted version to server OOC - //admittedly poorly named - void set_ip_list(QString p_list); + //takes in serverD-formatted IP list as prints a converted version to server OOC + //admittedly poorly named + void set_ip_list(QString p_list); - //disables chat if current cid matches second argument - //enables if p_muted is false - void set_mute(bool p_muted, int p_cid); + //disables chat if current cid matches second argument + //enables if p_muted is false + void set_mute(bool p_muted, int p_cid); - //send a message that the player is banned and quits the server - void set_ban(int p_cid); + //send a message that the player is banned and quits the server + void set_ban(int p_cid); - //cid = character id, returns the cid of the currently selected character - int get_cid() {return m_cid;} - QString get_current_char() {return current_char;} - QString get_current_background() {return current_background;} + //cid = character id, returns the cid of the currently selected character + int get_cid() { return m_cid; } + QString get_current_char() { return current_char; } + QString get_current_background() { return current_background; } - //updates character to p_cid and updates necessary ui elements - void update_character(int p_cid); + //updates character to p_cid and updates necessary ui elements + void update_character(int p_cid); - //properly sets up some varibles: resets user state - void enter_courtroom(); + //properly sets up some varibles: resets user state + void enter_courtroom(); - //helper function that populates ui_music_list with the contents of music_list - void list_music(); - void list_areas(); + //helper function that populates ui_music_list with the contents of music_list + void list_music(); + void list_areas(); - //these are for OOC chat - void append_ms_chatmessage(QString f_name, QString f_message); - void append_server_chatmessage(QString p_name, QString p_message, QString p_color); + //these are for OOC chat + void append_ms_chatmessage(QString f_name, QString f_message); + void append_server_chatmessage(QString p_name, QString p_message, QString p_color); - //these functions handle chatmessages sequentially. - //The process itself is very convoluted and merits separate documentation - //But the general idea is objection animation->pre animation->talking->idle - void handle_chatmessage(QStringList *p_contents); - void handle_chatmessage_2(); - void handle_chatmessage_3(); + //these functions handle chatmessages sequentially. + //The process itself is very convoluted and merits separate documentation + //But the general idea is objection animation->pre animation->talking->idle + void handle_chatmessage(QStringList *p_contents); + void handle_chatmessage_2(); + void handle_chatmessage_3(); - //This function filters out the common CC inline text trickery, for appending to - //the IC chatlog. - QString filter_ic_text(QString p_text, bool colorize = false, int pos = -1, int default_color = 0); + //This function filters out the common CC inline text trickery, for appending to + //the IC chatlog. + QString filter_ic_text(QString p_text, bool colorize = false, int pos = -1, int default_color = 0); - //adds text to the IC chatlog. p_name first as bold then p_text then a newlin - //this function keeps the chatlog scrolled to the top unless there's text selected - // or the user isn't already scrolled to the top - void append_ic_text(QString p_text, QString p_name = "", QString action = ""); + //adds text to the IC chatlog. p_name first as bold then p_text then a newlin + //this function keeps the chatlog scrolled to the top unless there's text selected + // or the user isn't already scrolled to the top + void append_ic_text(QString p_text, QString p_name = "", QString action = ""); - //prints who played the song to IC chat and plays said song(if found on local filesystem) - //takes in a list where the first element is the song name and the second is the char id of who played it - void handle_song(QStringList *p_contents); + //prints who played the song to IC chat and plays said song(if found on local filesystem) + //takes in a list where the first element is the song name and the second is the char id of who played it + void handle_song(QStringList *p_contents); - void play_preanim(bool noninterrupting); + void play_preanim(bool noninterrupting); - //plays the witness testimony or cross examination animation based on argument - void handle_wtce(QString p_wtce, int variant); + //plays the witness testimony or cross examination animation based on argument + void handle_wtce(QString p_wtce, int variant); - //sets the hp bar of defense(p_bar 1) or pro(p_bar 2) - //state is an number between 0 and 10 inclusive - void set_hp_bar(int p_bar, int p_state); + //sets the hp bar of defense(p_bar 1) or pro(p_bar 2) + //state is an number between 0 and 10 inclusive + void set_hp_bar(int p_bar, int p_state); - //Toggles the judge buttons, whether they should appear or not. - void toggle_judge_buttons(bool is_on); + //Toggles the judge buttons, whether they should appear or not. + void toggle_judge_buttons(bool is_on); - void announce_case(QString title, bool def, bool pro, bool jud, bool jur, bool steno); + void announce_case(QString title, bool def, bool pro, bool jud, bool jur, bool steno); - void check_connection_received(); + void check_connection_received(); - ~Courtroom(); + ~Courtroom(); private: - AOApplication *ao_app; + AOApplication *ao_app; - int m_courtroom_width = 714; - int m_courtroom_height = 668; + int m_courtroom_width = 714; + int m_courtroom_height = 668; - int m_viewport_x = 0; - int m_viewport_y = 0; + int m_viewport_x = 0; + int m_viewport_y = 0; - int m_viewport_width = 256; - int m_viewport_height = 192; + int m_viewport_width = 256; + int m_viewport_height = 192; - bool first_message_sent = false; - int maximumMessages = 0; + bool first_message_sent = false; + int maximumMessages = 0; - QParallelAnimationGroup *screenshake_animation_group = new QParallelAnimationGroup; + QParallelAnimationGroup *screenshake_animation_group = new QParallelAnimationGroup; - bool next_character_is_not_special = false; // If true, write the - // next character as it is. + bool next_character_is_not_special = false; // If true, write the + // next character as it is. - bool message_is_centered = false; + bool message_is_centered = false; - int current_display_speed = 3; - int message_display_speed[7] = {0, 10, 25, 40, 50, 70, 90}; + int current_display_speed = 3; + int message_display_speed[7] = {0, 10, 25, 40, 50, 70, 90}; - // The character ID of the character this user wants to appear alongside with. - int other_charid = -1; + // The character ID of the character this user wants to appear alongside with. + int other_charid = -1; - // The offset this user has given if they want to appear alongside someone. - int char_offset = 0; + // The offset this user has given if they want to appear alongside someone. + int char_offset = 0; - // 0 = in front, 1 = behind - int pair_order = 0; + // 0 = in front, 1 = behind + int pair_order = 0; - QVector char_list; - QVector evidence_list; - QVector music_list; - QVector area_list; + QVector char_list; + QVector evidence_list; + QVector music_list; + QVector area_list; - QVector arup_players; - QVector arup_statuses; - QVector arup_cms; - QVector arup_locks; + QVector arup_players; + QVector arup_statuses; + QVector arup_cms; + QVector arup_locks; - QVector ic_chatlog_history; + QVector ic_chatlog_history; - //triggers ping_server() every 60 seconds - QTimer *keepalive_timer; + //triggers ping_server() every 60 seconds + QTimer *keepalive_timer; - //determines how fast messages tick onto screen - QTimer *chat_tick_timer; - //int chat_tick_interval = 60; - //which tick position(character in chat message) we are at - int tick_pos = 0; - //the actual document tick pos we gotta worry about for making the text scroll better - int real_tick_pos = 0; - //used to determine how often blips sound - int blip_ticker = 0; - int blip_rate = 1; - int rainbow_counter = 0; - bool rainbow_appended = false; - bool blank_blip = false; + //determines how fast messages tick onto screen + QTimer *chat_tick_timer; + //int chat_tick_interval = 60; + //which tick position(character in chat message) we are at + int tick_pos = 0; + //the actual document tick pos we gotta worry about for making the text scroll better + int real_tick_pos = 0; + //used to determine how often blips sound + int blip_ticker = 0; + int blip_rate = 1; + int rainbow_counter = 0; + bool rainbow_appended = false; + bool blank_blip = false; - //Whether or not is this message additive to the previous one - bool is_additive = false; + //Whether or not is this message additive to the previous one + bool is_additive = false; - // Used for getting the current maximum blocks allowed in the IC chatlog. - int log_maximum_blocks = 0; + // Used for getting the current maximum blocks allowed in the IC chatlog. + int log_maximum_blocks = 0; - // True, if the log should go downwards. - bool log_goes_downwards = false; + // True, if the log should go downwards. + bool log_goes_downwards = false; - //delay before chat messages starts ticking - QTimer *text_delay_timer; + //delay before chat messages starts ticking + QTimer *text_delay_timer; - //delay before sfx plays - QTimer *sfx_delay_timer; + //delay before sfx plays + QTimer *sfx_delay_timer; - //every time point in char.inis times this equals the final time - const int time_mod = 40; + //every time point in char.inis times this equals the final time + const int time_mod = 40; - //the amount of time non-animated objection/hold it/takethat images stay onscreen for in ms - const int shout_stay_time = 724; + //the amount of time non-animated objection/hold it/takethat images stay onscreen for in ms + const int shout_stay_time = 724; - //the amount of time non-animated guilty/not guilty images stay onscreen for in ms - const int verdict_stay_time = 3000; + //the amount of time non-animated guilty/not guilty images stay onscreen for in ms + const int verdict_stay_time = 3000; - //the amount of time non-animated witness testimony/cross-examination images stay onscreen for in ms - const int wtce_stay_time = 1500; + //the amount of time non-animated witness testimony/cross-examination images stay onscreen for in ms + const int wtce_stay_time = 1500; - //characters we consider punctuation - const QString punctuation_chars = ".,?!:;"; + //characters we consider punctuation + const QString punctuation_chars = ".,?!:;"; - //amount by which we multiply the delay when we parse punctuation chars - const int punctuation_modifier = 3; + //amount by which we multiply the delay when we parse punctuation chars + const int punctuation_modifier = 3; - static const int chatmessage_size = 30; - QString m_chatmessage[chatmessage_size]; - bool chatmessage_is_empty = false; + static const int chatmessage_size = 30; + QString m_chatmessage[chatmessage_size]; + bool chatmessage_is_empty = false; - QString previous_ic_message = ""; - QString additive_previous = ""; + QString previous_ic_message = ""; + QString additive_previous = ""; - //char id, muted or not - QMap mute_map; + //char id, muted or not + QMap mute_map; - //QVector muted_cids; + //QVector muted_cids; - bool is_muted = false; + bool is_muted = false; - //state of animation, 0 = objecting, 1 = preanim, 2 = talking, 3 = idle, 4 = noniterrupting preanim - int anim_state = 3; + //state of animation, 0 = objecting, 1 = preanim, 2 = talking, 3 = idle, 4 = noniterrupting preanim + int anim_state = 3; - //whether or not current color is a talking one - bool color_is_talking = true; + //whether or not current color is a talking one + bool color_is_talking = true; - //state of text ticking, 0 = not yet ticking, 1 = ticking in progress, 2 = ticking done - int text_state = 2; + //state of text ticking, 0 = not yet ticking, 1 = ticking in progress, 2 = ticking done + int text_state = 2; - //character id, which index of the char_list the player is - int m_cid = -1; - //cid and this may differ in cases of ini-editing - QString current_char = ""; + //character id, which index of the char_list the player is + int m_cid = -1; + //cid and this may differ in cases of ini-editing + QString current_char = ""; - int objection_state = 0; - int realization_state = 0; - int screenshake_state = 0; - int text_color = 0; + int objection_state = 0; + int realization_state = 0; + int screenshake_state = 0; + int text_color = 0; - //How many unique user colors are possible - static const int max_colors = 12; + //How many unique user colors are possible + static const int max_colors = 12; - //Text Color-related optimization: - //Current color list indexes to real color references - QVector color_row_to_number; + //Text Color-related optimization: + //Current color list indexes to real color references + QVector color_row_to_number; - //List of associated RGB colors for this color index - QVector color_rgb_list; + //List of associated RGB colors for this color index + QVector color_rgb_list; - //List of markdown start characters, their index is tied to the color index - QStringList color_markdown_start_list; + //List of markdown start characters, their index is tied to the color index + QStringList color_markdown_start_list; - //List of markdown end characters, their index is tied to the color index - QStringList color_markdown_end_list; + //List of markdown end characters, their index is tied to the color index + QStringList color_markdown_end_list; - //Whether or not we're supposed to remove this char during parsing - QVector color_markdown_remove_list; + //Whether or not we're supposed to remove this char during parsing + QVector color_markdown_remove_list; - //Whether or not this color allows us to play the talking animation - QVector color_markdown_talking_list; - //Text Color-related optimization END + //Whether or not this color allows us to play the talking animation + QVector color_markdown_talking_list; + //Text Color-related optimization END - //List of all currently available pos - QStringList pos_dropdown_list; + //List of all currently available pos + QStringList pos_dropdown_list; - bool is_presenting_evidence = false; + bool is_presenting_evidence = false; - QString effect = ""; + QString effect = ""; - //Music effect flags we want to send to server when we play music - int music_flags = 0; + //Music effect flags we want to send to server when we play music + int music_flags = 0; - int defense_bar_state = 0; - int prosecution_bar_state = 0; + int defense_bar_state = 0; + int prosecution_bar_state = 0; - int current_char_page = 0; - int char_columns = 10; - int char_rows = 9; - int max_chars_on_page = 90; + int current_char_page = 0; + int char_columns = 10; + int char_rows = 9; + int max_chars_on_page = 90; - const int button_width = 60; - const int button_height = 60; + const int button_width = 60; + const int button_height = 60; - int current_emote_page = 0; - int current_emote = 0; - int emote_columns = 5; - int emote_rows = 2; - int max_emotes_on_page = 10; + int current_emote_page = 0; + int current_emote = 0; + int emote_columns = 5; + int emote_rows = 2; + int max_emotes_on_page = 10; - QVector local_evidence_list; - QVector private_evidence_list; - QVector global_evidence_list; + QVector local_evidence_list; + QVector private_evidence_list; + QVector global_evidence_list; - //false = use private_evidence_list - bool current_evidence_global = true; + //false = use private_evidence_list + bool current_evidence_global = true; - int current_evidence_page = 0; - int current_evidence = 0; - int evidence_columns = 6; - int evidence_rows = 3; - int max_evidence_on_page = 18; + int current_evidence_page = 0; + int current_evidence = 0; + int evidence_columns = 6; + int evidence_rows = 3; + int max_evidence_on_page = 18; - //is set to true if the bg folder contains defensedesk.png, prosecutiondesk.png and stand.png - bool is_ao2_bg = false; + //is set to true if the bg folder contains defensedesk.png, prosecutiondesk.png and stand.png + bool is_ao2_bg = false; - //whether the ooc chat is server or master chat, true is server - bool server_ooc = true; + //whether the ooc chat is server or master chat, true is server + bool server_ooc = true; - QString current_background = "default"; - QString current_side = ""; + QString current_background = "default"; + QString current_side = ""; - AOMusicPlayer *music_player; - AOSfxPlayer *sfx_player; - AOSfxPlayer *objection_player; - AOBlipPlayer *blip_player; + AOMusicPlayer *music_player; + AOSfxPlayer *sfx_player; + AOSfxPlayer *objection_player; + AOBlipPlayer *blip_player; - AOSfxPlayer *modcall_player; + AOSfxPlayer *modcall_player; - AOImage *ui_background; + AOImage *ui_background; - QWidget *ui_viewport; - AOScene *ui_vp_background; - AOMovie *ui_vp_speedlines; - AOCharMovie *ui_vp_player_char; - AOCharMovie *ui_vp_sideplayer_char; - AOScene *ui_vp_desk; - AOScene *ui_vp_legacy_desk; - AOEvidenceDisplay *ui_vp_evidence_display; - AOImage *ui_vp_chatbox; - QLabel *ui_vp_showname; - AOMovie *ui_vp_chat_arrow; - QTextEdit *ui_vp_message; - AOMovie *ui_vp_effect; - AOMovie *ui_vp_testimony; - AOMovie *ui_vp_wtce; - AOMovie *ui_vp_objection; + QWidget *ui_viewport; + AOScene *ui_vp_background; + AOMovie *ui_vp_speedlines; + AOCharMovie *ui_vp_player_char; + AOCharMovie *ui_vp_sideplayer_char; + AOScene *ui_vp_desk; + AOScene *ui_vp_legacy_desk; + AOEvidenceDisplay *ui_vp_evidence_display; + AOImage *ui_vp_chatbox; + QLabel *ui_vp_showname; + AOMovie *ui_vp_chat_arrow; + QTextEdit *ui_vp_message; + AOMovie *ui_vp_effect; + AOMovie *ui_vp_testimony; + AOMovie *ui_vp_wtce; + AOMovie *ui_vp_objection; - QTextEdit *ui_ic_chatlog; + QTextEdit *ui_ic_chatlog; - AOTextArea *ui_ms_chatlog; - AOTextArea *ui_server_chatlog; + AOTextArea *ui_ms_chatlog; + AOTextArea *ui_server_chatlog; - QListWidget *ui_mute_list; - QTreeWidget *ui_area_list; - QTreeWidget *ui_music_list; + QListWidget *ui_mute_list; + QTreeWidget *ui_area_list; + QTreeWidget *ui_music_list; - ScrollText *ui_music_name; - AOMovie *ui_music_display; + ScrollText *ui_music_name; + AOMovie *ui_music_display; - AOButton *ui_pair_button; - QListWidget *ui_pair_list; - QSpinBox *ui_pair_offset_spinbox; + AOButton *ui_pair_button; + QListWidget *ui_pair_list; + QSpinBox *ui_pair_offset_spinbox; - QComboBox *ui_pair_order_dropdown; + QComboBox *ui_pair_order_dropdown; - AOLineEdit *ui_ic_chat_message; - QLineEdit *ui_ic_chat_name; + AOLineEdit *ui_ic_chat_message; + QLineEdit *ui_ic_chat_name; - QLineEdit *ui_ooc_chat_message; - QLineEdit *ui_ooc_chat_name; + QLineEdit *ui_ooc_chat_message; + QLineEdit *ui_ooc_chat_name; - //QLineEdit *ui_area_password; - QLineEdit *ui_music_search; + //QLineEdit *ui_area_password; + QLineEdit *ui_music_search; - QWidget *ui_emotes; - QVector ui_emote_list; - AOButton *ui_emote_left; - AOButton *ui_emote_right; + QWidget *ui_emotes; + QVector ui_emote_list; + AOButton *ui_emote_left; + AOButton *ui_emote_right; - QComboBox *ui_emote_dropdown; - QComboBox *ui_pos_dropdown; + QComboBox *ui_emote_dropdown; + QComboBox *ui_pos_dropdown; - QComboBox *ui_iniswap_dropdown; - AOButton *ui_iniswap_remove; + QComboBox *ui_iniswap_dropdown; + AOButton *ui_iniswap_remove; - QComboBox *ui_sfx_dropdown; - AOButton *ui_sfx_remove; + QComboBox *ui_sfx_dropdown; + AOButton *ui_sfx_remove; - QComboBox *ui_effects_dropdown; + QComboBox *ui_effects_dropdown; - AOImage *ui_defense_bar; - AOImage *ui_prosecution_bar; + AOImage *ui_defense_bar; + AOImage *ui_prosecution_bar; - QLabel *ui_music_label; - QLabel *ui_sfx_label; - QLabel *ui_blip_label; + QLabel *ui_music_label; + QLabel *ui_sfx_label; + QLabel *ui_blip_label; - AOButton *ui_hold_it; - AOButton *ui_objection; - AOButton *ui_take_that; - - AOButton *ui_ooc_toggle; + AOButton *ui_hold_it; + AOButton *ui_objection; + AOButton *ui_take_that; + + AOButton *ui_ooc_toggle; - AOButton *ui_witness_testimony; - AOButton *ui_cross_examination; - AOButton *ui_guilty; - AOButton *ui_not_guilty; - - AOButton *ui_change_character; - AOButton *ui_reload_theme; - AOButton *ui_call_mod; - AOButton *ui_settings; - AOButton *ui_announce_casing; - AOButton *ui_switch_area_music; + AOButton *ui_witness_testimony; + AOButton *ui_cross_examination; + AOButton *ui_guilty; + AOButton *ui_not_guilty; + + AOButton *ui_change_character; + AOButton *ui_reload_theme; + AOButton *ui_call_mod; + AOButton *ui_settings; + AOButton *ui_announce_casing; + AOButton *ui_switch_area_music; - QCheckBox *ui_pre; - QCheckBox *ui_flip; - QCheckBox *ui_additive; - QCheckBox *ui_guard; - QCheckBox *ui_casing; - - QCheckBox *ui_pre_non_interrupt; - QCheckBox *ui_showname_enable; - - AOButton *ui_custom_objection; - AOButton *ui_realization; - AOButton *ui_screenshake; - AOButton *ui_mute; - - AOButton *ui_defense_plus; - AOButton *ui_defense_minus; - - AOButton *ui_prosecution_plus; - AOButton *ui_prosecution_minus; - - QComboBox *ui_text_color; - - QSlider *ui_music_slider; - QSlider *ui_sfx_slider; - QSlider *ui_blip_slider; + QCheckBox *ui_pre; + QCheckBox *ui_flip; + QCheckBox *ui_additive; + QCheckBox *ui_guard; + QCheckBox *ui_casing; + + QCheckBox *ui_pre_non_interrupt; + QCheckBox *ui_showname_enable; + + AOButton *ui_custom_objection; + AOButton *ui_realization; + AOButton *ui_screenshake; + AOButton *ui_mute; + + AOButton *ui_defense_plus; + AOButton *ui_defense_minus; + + AOButton *ui_prosecution_plus; + AOButton *ui_prosecution_minus; + + QComboBox *ui_text_color; + + QSlider *ui_music_slider; + QSlider *ui_sfx_slider; + QSlider *ui_blip_slider; - AOImage *ui_muted; + AOImage *ui_muted; - AOButton *ui_evidence_button; - AOImage *ui_evidence; - AOLineEdit *ui_evidence_name; - QWidget *ui_evidence_buttons; - QVector ui_evidence_list; - AOButton *ui_evidence_left; - AOButton *ui_evidence_right; - AOButton *ui_evidence_present; - AOImage *ui_evidence_overlay; - AOButton *ui_evidence_delete; - AOLineEdit *ui_evidence_image_name; - AOButton *ui_evidence_image_button; - AOButton *ui_evidence_x; - AOButton *ui_evidence_ok; - AOButton *ui_evidence_switch; - AOButton *ui_evidence_transfer; - AOButton *ui_evidence_save; - AOButton *ui_evidence_load; - AOTextEdit *ui_evidence_description; + AOButton *ui_evidence_button; + AOImage *ui_evidence; + AOLineEdit *ui_evidence_name; + QWidget *ui_evidence_buttons; + QVector ui_evidence_list; + AOButton *ui_evidence_left; + AOButton *ui_evidence_right; + AOButton *ui_evidence_present; + AOImage *ui_evidence_overlay; + AOButton *ui_evidence_delete; + AOLineEdit *ui_evidence_image_name; + AOButton *ui_evidence_image_button; + AOButton *ui_evidence_x; + AOButton *ui_evidence_ok; + AOButton *ui_evidence_switch; + AOButton *ui_evidence_transfer; + AOButton *ui_evidence_save; + AOButton *ui_evidence_load; + AOTextEdit *ui_evidence_description; - AOImage *ui_char_select_background; + AOImage *ui_char_select_background; - //abstract widget to hold char buttons - QWidget *ui_char_buttons; + //abstract widget to hold char buttons + QWidget *ui_char_buttons; - QVector ui_char_button_list; - QVector ui_char_button_list_filtered; - AOImage *ui_selector; - - AOButton *ui_back_to_lobby; + QVector ui_char_button_list; + QVector ui_char_button_list_filtered; + AOImage *ui_selector; + + AOButton *ui_back_to_lobby; - QLineEdit *ui_char_password; - - AOButton *ui_char_select_left; - AOButton *ui_char_select_right; + QLineEdit *ui_char_password; + + AOButton *ui_char_select_left; + AOButton *ui_char_select_right; - AOButton *ui_spectator; - - QLineEdit *ui_char_search; - QCheckBox *ui_char_passworded; - QCheckBox *ui_char_taken; - - void construct_char_select(); - void set_char_select(); - void set_char_select_page(); - void char_clicked(int n_char); - void put_button_in_place(int starting, int chars_on_this_page); - void filter_character_list(); - - void initialize_emotes(); - void refresh_emotes(); - void set_emote_page(); - void set_emote_dropdown(); - - void initialize_evidence(); - void refresh_evidence(); - void set_evidence_page(); + AOButton *ui_spectator; + + QLineEdit *ui_char_search; + QCheckBox *ui_char_passworded; + QCheckBox *ui_char_taken; + + void construct_char_select(); + void set_char_select(); + void set_char_select_page(); + void char_clicked(int n_char); + void put_button_in_place(int starting, int chars_on_this_page); + void filter_character_list(); + + void initialize_emotes(); + void refresh_emotes(); + void set_emote_page(); + void set_emote_dropdown(); + + void initialize_evidence(); + void refresh_evidence(); + void set_evidence_page(); public slots: - void objection_done(); - void preanim_done(); - void do_screenshake(); - void do_flash(); - void do_effect(QString fx_path, QString fx_sound, QString p_char, QString p_folder); - void play_char_sfx(QString sfx_name); + void objection_done(); + void preanim_done(); + void do_screenshake(); + void do_flash(); + void do_effect(QString fx_path, QString fx_sound, QString p_char, QString p_folder); + void play_char_sfx(QString sfx_name); - void mod_called(QString p_ip); + void mod_called(QString p_ip); - void case_called(QString msg, bool def, bool pro, bool jud, bool jur, bool steno); + void case_called(QString msg, bool def, bool pro, bool jud, bool jur, bool steno); private slots: - void start_chat_ticking(); - void play_sfx(); + void start_chat_ticking(); + void play_sfx(); - void chat_tick(); + void chat_tick(); - void on_mute_list_clicked(QModelIndex p_index); - void on_pair_list_clicked(QModelIndex p_index); + void on_mute_list_clicked(QModelIndex p_index); + void on_pair_list_clicked(QModelIndex p_index); - void on_chat_return_pressed(); + void on_chat_return_pressed(); - void on_ooc_return_pressed(); + void on_ooc_return_pressed(); - void on_music_search_edited(QString p_text); - void on_music_list_double_clicked(QTreeWidgetItem *p_item, int column); - void on_music_list_context_menu_requested(const QPoint &pos); - void music_fade_out(bool toggle); - void music_fade_in(bool toggle); - void music_synchronize(bool toggle); - void music_list_expand_all(); - void music_list_collapse_all(); - void on_area_list_double_clicked(QTreeWidgetItem *p_item, int column); + void on_music_search_edited(QString p_text); + void on_music_list_double_clicked(QTreeWidgetItem *p_item, int column); + void on_music_list_context_menu_requested(const QPoint &pos); + void music_fade_out(bool toggle); + void music_fade_in(bool toggle); + void music_synchronize(bool toggle); + void music_list_expand_all(); + void music_list_collapse_all(); + void on_area_list_double_clicked(QTreeWidgetItem *p_item, int column); - void select_emote(int p_id); + void select_emote(int p_id); - void on_emote_clicked(int p_id); + void on_emote_clicked(int p_id); - void on_emote_left_clicked(); - void on_emote_right_clicked(); + void on_emote_left_clicked(); + void on_emote_right_clicked(); - void on_emote_dropdown_changed(int p_index); - void on_pos_dropdown_changed(int p_index); + void on_emote_dropdown_changed(int p_index); + void on_pos_dropdown_changed(int p_index); - void on_iniswap_dropdown_changed(int p_index); - void set_iniswap_dropdown(); - void on_iniswap_context_menu_requested(const QPoint &pos); - void on_iniswap_edit_requested(); - void on_iniswap_remove_clicked(); + void on_iniswap_dropdown_changed(int p_index); + void set_iniswap_dropdown(); + void on_iniswap_context_menu_requested(const QPoint &pos); + void on_iniswap_edit_requested(); + void on_iniswap_remove_clicked(); - void on_sfx_dropdown_changed(int p_index); - void set_sfx_dropdown(); - void on_sfx_context_menu_requested(const QPoint &pos); - void on_sfx_edit_requested(); - void on_sfx_remove_clicked(); + void on_sfx_dropdown_changed(int p_index); + void set_sfx_dropdown(); + void on_sfx_context_menu_requested(const QPoint &pos); + void on_sfx_edit_requested(); + void on_sfx_remove_clicked(); - void set_effects_dropdown(); - void on_effects_context_menu_requested(const QPoint &pos); - void on_effects_edit_requested(); - void on_character_effects_edit_requested(); - void on_effects_dropdown_changed(int p_index); - bool effects_dropdown_find_and_set(QString effect); + void set_effects_dropdown(); + void on_effects_context_menu_requested(const QPoint &pos); + void on_effects_edit_requested(); + void on_character_effects_edit_requested(); + void on_effects_dropdown_changed(int p_index); + bool effects_dropdown_find_and_set(QString effect); - QString get_char_sfx(); - int get_char_sfx_delay(); + QString get_char_sfx(); + int get_char_sfx_delay(); - void on_evidence_name_edited(); - void on_evidence_image_name_edited(); - void on_evidence_image_button_clicked(); - void on_evidence_clicked(int p_id); - void on_evidence_double_clicked(int p_id); + void on_evidence_name_edited(); + void on_evidence_image_name_edited(); + void on_evidence_image_button_clicked(); + void on_evidence_clicked(int p_id); + void on_evidence_double_clicked(int p_id); - void on_evidence_hover(int p_id, bool p_state); + void on_evidence_hover(int p_id, bool p_state); - void on_evidence_left_clicked(); - void on_evidence_right_clicked(); - void on_evidence_present_clicked(); + void on_evidence_left_clicked(); + void on_evidence_right_clicked(); + void on_evidence_present_clicked(); - void on_hold_it_clicked(); - void on_objection_clicked(); - void on_take_that_clicked(); - void on_custom_objection_clicked(); + void on_hold_it_clicked(); + void on_objection_clicked(); + void on_take_that_clicked(); + void on_custom_objection_clicked(); - void on_realization_clicked(); - void on_screenshake_clicked(); + void on_realization_clicked(); + void on_screenshake_clicked(); - void on_mute_clicked(); - void on_pair_clicked(); - void on_pair_order_dropdown_changed(int p_index); + 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(); - void on_prosecution_minus_clicked(); - void on_prosecution_plus_clicked(); + void on_defense_minus_clicked(); + void on_defense_plus_clicked(); + void on_prosecution_minus_clicked(); + void on_prosecution_plus_clicked(); - void on_text_color_changed(int p_color); - void set_text_color_dropdown(); + void on_text_color_changed(int p_color); + void set_text_color_dropdown(); - void on_music_slider_moved(int p_value); - void on_sfx_slider_moved(int p_value); - void on_blip_slider_moved(int p_value); + void on_music_slider_moved(int p_value); + void on_sfx_slider_moved(int p_value); + void on_blip_slider_moved(int p_value); - void on_log_limit_changed(int value); - void on_pair_offset_changed(int value); + void on_log_limit_changed(int value); + void on_pair_offset_changed(int value); - void on_ooc_toggle_clicked(); + void on_ooc_toggle_clicked(); - void on_witness_testimony_clicked(); - void on_cross_examination_clicked(); - void on_not_guilty_clicked(); - void on_guilty_clicked(); + void on_witness_testimony_clicked(); + void on_cross_examination_clicked(); + void on_not_guilty_clicked(); + void on_guilty_clicked(); - void on_change_character_clicked(); - void on_reload_theme_clicked(); - void on_call_mod_clicked(); - void on_settings_clicked(); - void on_announce_casing_clicked(); + void on_change_character_clicked(); + void on_reload_theme_clicked(); + void on_call_mod_clicked(); + void on_settings_clicked(); + void on_announce_casing_clicked(); - void on_pre_clicked(); - void on_flip_clicked(); - void on_additive_clicked(); - void on_guard_clicked(); + void on_pre_clicked(); + void on_flip_clicked(); + void on_additive_clicked(); + void on_guard_clicked(); - void on_showname_enable_clicked(); + void on_showname_enable_clicked(); - void on_evidence_name_double_clicked(); - void on_evidence_image_name_double_clicked(); - void on_evidence_button_clicked(); + void on_evidence_name_double_clicked(); + void on_evidence_image_name_double_clicked(); + void on_evidence_button_clicked(); - void on_evidence_delete_clicked(); - void on_evidence_x_clicked(); - void on_evidence_ok_clicked(); - void on_evidence_switch_clicked(); - void on_evidence_transfer_clicked(); + void on_evidence_delete_clicked(); + void on_evidence_x_clicked(); + void on_evidence_ok_clicked(); + void on_evidence_switch_clicked(); + void on_evidence_transfer_clicked(); - void on_evidence_edited(); + void on_evidence_edited(); - void evidence_close(); - void evidence_switch(bool global); - void on_evidence_save_clicked(); - void on_evidence_load_clicked(); - bool compare_evidence_changed(evi_type evi_a, evi_type evi_b); + void evidence_close(); + void evidence_switch(bool global); + void on_evidence_save_clicked(); + void on_evidence_load_clicked(); + bool compare_evidence_changed(evi_type evi_a, evi_type evi_b); - void on_back_to_lobby_clicked(); + void on_back_to_lobby_clicked(); - void on_char_select_left_clicked(); - void on_char_select_right_clicked(); - void on_char_search_changed(); - void on_char_taken_clicked(); - void on_char_passworded_clicked(); + void on_char_select_left_clicked(); + void on_char_select_right_clicked(); + void on_char_search_changed(); + void on_char_taken_clicked(); + void on_char_passworded_clicked(); - void on_spectator_clicked(); + void on_spectator_clicked(); - void on_switch_area_music_clicked(); + void on_switch_area_music_clicked(); - void on_casing_clicked(); + void on_casing_clicked(); - void ping_server(); + void ping_server(); - void load_bass_opus_plugin(); + void load_bass_opus_plugin(); }; #endif // COURTROOM_H diff --git a/include/datatypes.h b/include/datatypes.h index 921f613..715bb3e 100644 --- a/include/datatypes.h +++ b/include/datatypes.h @@ -3,118 +3,108 @@ #include -struct server_type -{ - QString name; - QString desc; - QString ip; - int port; +struct server_type { + QString name; + QString desc; + QString ip; + int port; }; -struct emote_type -{ - QString comment; - QString preanim; - QString anim; - int mod; - QString sfx_name; - int sfx_delay; - int sfx_duration; +struct emote_type { + QString comment; + QString preanim; + QString anim; + int mod; + QString sfx_name; + int sfx_delay; + int sfx_duration; }; -struct char_type -{ - QString name; - QString description; - QString evidence_string; - bool taken; +struct char_type { + QString name; + QString description; + QString evidence_string; + bool taken; }; -struct evi_type -{ - QString name; - QString description; - QString image; +struct evi_type { + QString name; + QString description; + QString image; }; -struct chatmessage_type -{ - QString message; - QString character; - QString side; - QString sfx_name; - QString pre_emote; - QString emote; - int emote_modifier; - int objection_modifier; - int realization; - int text_color; - int evidence; - int cid; - int sfx_delay; - int flip; +struct chatmessage_type { + QString message; + QString character; + QString side; + QString sfx_name; + QString pre_emote; + QString emote; + int emote_modifier; + int objection_modifier; + int realization; + int text_color; + int evidence; + int cid; + int sfx_delay; + int flip; }; -struct area_type -{ - QString name; - QString background; - bool passworded; +struct area_type { + QString name; + QString background; + bool passworded; }; -struct pos_type -{ - int x; - int y; +struct pos_type { + int x; + int y; }; -struct pos_size_type -{ - int x = 0; - int y = 0; - int width = 0; - int height = 0; +struct pos_size_type { + int x = 0; + int y = 0; + int width = 0; + int height = 0; }; -enum CHAT_MESSAGE -{ - DESK_MOD = 0, - PRE_EMOTE, - CHAR_NAME, - EMOTE, - MESSAGE, - SIDE, - SFX_NAME, - EMOTE_MOD, - CHAR_ID, - SFX_DELAY, - OBJECTION_MOD, - EVIDENCE_ID, - FLIP, - REALIZATION, - TEXT_COLOR, - SHOWNAME, - OTHER_CHARID, - OTHER_NAME, - OTHER_EMOTE, - SELF_OFFSET, - OTHER_OFFSET, - OTHER_FLIP, - NONINTERRUPTING_PRE, - LOOPING_SFX, - SCREENSHAKE, - FRAME_SCREENSHAKE, - FRAME_REALIZATION, - FRAME_SFX, - ADDITIVE, - EFFECTS +enum CHAT_MESSAGE { + DESK_MOD = 0, + PRE_EMOTE, + CHAR_NAME, + EMOTE, + MESSAGE, + SIDE, + SFX_NAME, + EMOTE_MOD, + CHAR_ID, + SFX_DELAY, + OBJECTION_MOD, + EVIDENCE_ID, + FLIP, + REALIZATION, + TEXT_COLOR, + SHOWNAME, + OTHER_CHARID, + OTHER_NAME, + OTHER_EMOTE, + SELF_OFFSET, + OTHER_OFFSET, + OTHER_FLIP, + NONINTERRUPTING_PRE, + LOOPING_SFX, + SCREENSHAKE, + FRAME_SCREENSHAKE, + FRAME_REALIZATION, + FRAME_SFX, + ADDITIVE, + EFFECTS }; -enum MUSIC_EFFECT -{ - FADE_IN = 1, - FADE_OUT = 2, - SYNC_POS = 4 +enum MUSIC_EFFECT { + FADE_IN = 1, + FADE_OUT = 2, + SYNC_POS = 4 }; #endif // DATATYPES_H diff --git a/include/debug_functions.h b/include/debug_functions.h index 160274c..383431a 100644 --- a/include/debug_functions.h +++ b/include/debug_functions.h @@ -1,8 +1,8 @@ #ifndef DEBUG_FUNCTIONS_H #define DEBUG_FUNCTIONS_H -#include #include +#include void call_error(QString message); void call_notice(QString message); diff --git a/include/discord-rpc.h b/include/discord-rpc.h index feb874b..2488543 100644 --- a/include/discord-rpc.h +++ b/include/discord-rpc.h @@ -24,47 +24,47 @@ extern "C" { #endif typedef struct DiscordRichPresence { - const char* state; /* max 128 bytes */ - const char* details; /* max 128 bytes */ + const char *state; /* max 128 bytes */ + const char *details; /* max 128 bytes */ int64_t startTimestamp; int64_t endTimestamp; - const char* largeImageKey; /* max 32 bytes */ - const char* largeImageText; /* max 128 bytes */ - const char* smallImageKey; /* max 32 bytes */ - const char* smallImageText; /* max 128 bytes */ - const char* partyId; /* max 128 bytes */ + const char *largeImageKey; /* max 32 bytes */ + const char *largeImageText; /* max 128 bytes */ + const char *smallImageKey; /* max 32 bytes */ + const char *smallImageText; /* max 128 bytes */ + const char *partyId; /* max 128 bytes */ int partySize; int partyMax; - const char* matchSecret; /* max 128 bytes */ - const char* joinSecret; /* max 128 bytes */ - const char* spectateSecret; /* max 128 bytes */ + const char *matchSecret; /* max 128 bytes */ + const char *joinSecret; /* max 128 bytes */ + const char *spectateSecret; /* max 128 bytes */ int8_t instance; } DiscordRichPresence; typedef struct DiscordJoinRequest { - const char* userId; - const char* username; - const char* discriminator; - const char* avatar; + const char *userId; + const char *username; + const char *discriminator; + const char *avatar; } DiscordJoinRequest; typedef struct DiscordEventHandlers { void (*ready)(void); - void (*disconnected)(int errorCode, const char* message); - void (*errored)(int errorCode, const char* message); - void (*joinGame)(const char* joinSecret); - void (*spectateGame)(const char* spectateSecret); - void (*joinRequest)(const DiscordJoinRequest* request); + void (*disconnected)(int errorCode, const char *message); + void (*errored)(int errorCode, const char *message); + void (*joinGame)(const char *joinSecret); + void (*spectateGame)(const char *spectateSecret); + void (*joinRequest)(const DiscordJoinRequest *request); } DiscordEventHandlers; #define DISCORD_REPLY_NO 0 #define DISCORD_REPLY_YES 1 #define DISCORD_REPLY_IGNORE 2 -DISCORD_EXPORT void Discord_Initialize(const char* applicationId, - DiscordEventHandlers* handlers, +DISCORD_EXPORT void Discord_Initialize(const char *applicationId, + DiscordEventHandlers *handlers, int autoRegister, - const char* optionalSteamId); + const char *optionalSteamId); DISCORD_EXPORT void Discord_Shutdown(void); /* checks for incoming messages, dispatches callbacks */ @@ -75,10 +75,10 @@ DISCORD_EXPORT void Discord_RunCallbacks(void); DISCORD_EXPORT void Discord_UpdateConnection(void); #endif -DISCORD_EXPORT void Discord_UpdatePresence(const DiscordRichPresence* presence); +DISCORD_EXPORT void Discord_UpdatePresence(const DiscordRichPresence *presence); DISCORD_EXPORT void Discord_ClearPresence(void); -DISCORD_EXPORT void Discord_Respond(const char* userid, /* DISCORD_REPLY_ */ int reply); +DISCORD_EXPORT void Discord_Respond(const char *userid, /* DISCORD_REPLY_ */ int reply); #ifdef __cplusplus } /* extern "C" */ diff --git a/include/discord_register.h b/include/discord_register.h index 4c16b68..71e856a 100644 --- a/include/discord_register.h +++ b/include/discord_register.h @@ -1,25 +1,25 @@ #pragma once #if defined(DISCORD_DYNAMIC_LIB) -# if defined(_WIN32) -# if defined(DISCORD_BUILDING_SDK) -# define DISCORD_EXPORT __declspec(dllexport) -# else -# define DISCORD_EXPORT __declspec(dllimport) -# endif -# else -# define DISCORD_EXPORT __attribute__((visibility("default"))) -# endif +#if defined(_WIN32) +#if defined(DISCORD_BUILDING_SDK) +#define DISCORD_EXPORT __declspec(dllexport) #else -# define DISCORD_EXPORT +#define DISCORD_EXPORT __declspec(dllimport) +#endif +#else +#define DISCORD_EXPORT __attribute__((visibility("default"))) +#endif +#else +#define DISCORD_EXPORT #endif #ifdef __cplusplus extern "C" { #endif -DISCORD_EXPORT void Discord_Register(const char* applicationId, const char* command); -DISCORD_EXPORT void Discord_RegisterSteamGame(const char* applicationId, const char* steamId); +DISCORD_EXPORT void Discord_Register(const char *applicationId, const char *command); +DISCORD_EXPORT void Discord_RegisterSteamGame(const char *applicationId, const char *steamId); #ifdef __cplusplus } diff --git a/include/discord_rich_presence.h b/include/discord_rich_presence.h index 4115b51..1949d24 100644 --- a/include/discord_rich_presence.h +++ b/include/discord_rich_presence.h @@ -1,11 +1,11 @@ #ifndef DISCORD_RICH_PRESENCE_H #define DISCORD_RICH_PRESENCE_H +#include +#include #include #include -#include #include -#include #include @@ -16,23 +16,23 @@ namespace AttorneyOnline { -class Discord -{ - Q_DECLARE_TR_FUNCTIONS(Discord) + class Discord { + Q_DECLARE_TR_FUNCTIONS(Discord) -private: - const char* APPLICATION_ID = "399779271737868288"; - std::string server_name, server_id; - int64_t timestamp; -public: - Discord(); - ~Discord(); + private: + const char *APPLICATION_ID = "399779271737868288"; + std::string server_name, server_id; + int64_t timestamp; - void state_lobby(); - void state_server(std::string name, std::string server_id); - void state_character(std::string name); - void state_spectate(); -}; + public: + Discord(); + ~Discord(); -} + void state_lobby(); + void state_server(std::string name, std::string server_id); + void state_character(std::string name); + void state_spectate(); + }; + +} // namespace AttorneyOnline #endif // DISCORD_RICH_PRESENCE_H diff --git a/include/discord_rpc.h b/include/discord_rpc.h index 3e1441e..737f2f6 100644 --- a/include/discord_rpc.h +++ b/include/discord_rpc.h @@ -24,47 +24,47 @@ extern "C" { #endif typedef struct DiscordRichPresence { - const char* state; /* max 128 bytes */ - const char* details; /* max 128 bytes */ + const char *state; /* max 128 bytes */ + const char *details; /* max 128 bytes */ int64_t startTimestamp; int64_t endTimestamp; - const char* largeImageKey; /* max 32 bytes */ - const char* largeImageText; /* max 128 bytes */ - const char* smallImageKey; /* max 32 bytes */ - const char* smallImageText; /* max 128 bytes */ - const char* partyId; /* max 128 bytes */ + const char *largeImageKey; /* max 32 bytes */ + const char *largeImageText; /* max 128 bytes */ + const char *smallImageKey; /* max 32 bytes */ + const char *smallImageText; /* max 128 bytes */ + const char *partyId; /* max 128 bytes */ int partySize; int partyMax; - const char* matchSecret; /* max 128 bytes */ - const char* joinSecret; /* max 128 bytes */ - const char* spectateSecret; /* max 128 bytes */ + const char *matchSecret; /* max 128 bytes */ + const char *joinSecret; /* max 128 bytes */ + const char *spectateSecret; /* max 128 bytes */ int8_t instance; } DiscordRichPresence; typedef struct DiscordUser { - const char* userId; - const char* username; - const char* discriminator; - const char* avatar; + const char *userId; + const char *username; + const char *discriminator; + const char *avatar; } DiscordUser; typedef struct DiscordEventHandlers { - void (*ready)(const DiscordUser* request); - void (*disconnected)(int errorCode, const char* message); - void (*errored)(int errorCode, const char* message); - void (*joinGame)(const char* joinSecret); - void (*spectateGame)(const char* spectateSecret); - void (*joinRequest)(const DiscordUser* request); + void (*ready)(const DiscordUser *request); + void (*disconnected)(int errorCode, const char *message); + void (*errored)(int errorCode, const char *message); + void (*joinGame)(const char *joinSecret); + void (*spectateGame)(const char *spectateSecret); + void (*joinRequest)(const DiscordUser *request); } DiscordEventHandlers; #define DISCORD_REPLY_NO 0 #define DISCORD_REPLY_YES 1 #define DISCORD_REPLY_IGNORE 2 -DISCORD_EXPORT void Discord_Initialize(const char* applicationId, - DiscordEventHandlers* handlers, +DISCORD_EXPORT void Discord_Initialize(const char *applicationId, + DiscordEventHandlers *handlers, int autoRegister, - const char* optionalSteamId); + const char *optionalSteamId); DISCORD_EXPORT void Discord_Shutdown(void); /* checks for incoming messages, dispatches callbacks */ @@ -75,12 +75,12 @@ DISCORD_EXPORT void Discord_RunCallbacks(void); DISCORD_EXPORT void Discord_UpdateConnection(void); #endif -DISCORD_EXPORT void Discord_UpdatePresence(const DiscordRichPresence* presence); +DISCORD_EXPORT void Discord_UpdatePresence(const DiscordRichPresence *presence); DISCORD_EXPORT void Discord_ClearPresence(void); -DISCORD_EXPORT void Discord_Respond(const char* userid, /* DISCORD_REPLY_ */ int reply); +DISCORD_EXPORT void Discord_Respond(const char *userid, /* DISCORD_REPLY_ */ int reply); -DISCORD_EXPORT void Discord_UpdateHandlers(DiscordEventHandlers* handlers); +DISCORD_EXPORT void Discord_UpdateHandlers(DiscordEventHandlers *handlers); #ifdef __cplusplus } /* extern "C" */ diff --git a/include/encryption_functions.h b/include/encryption_functions.h index dc67d12..b70e8e6 100644 --- a/include/encryption_functions.h +++ b/include/encryption_functions.h @@ -3,11 +3,11 @@ #include -#include -#include -#include -#include #include +#include +#include +#include +#include QString fanta_encrypt(QString p_input, unsigned int key); QString fanta_decrypt(QString p_input, unsigned int key); diff --git a/include/file_functions.h b/include/file_functions.h index 6937ed8..8bb2e5f 100644 --- a/include/file_functions.h +++ b/include/file_functions.h @@ -1,8 +1,8 @@ #ifndef FILE_FUNCTIONS_H #define FILE_FUNCTIONS_H -#include #include +#include #include bool file_exists(QString file_path); diff --git a/include/hex_functions.h b/include/hex_functions.h index 285f096..429bdb1 100644 --- a/include/hex_functions.h +++ b/include/hex_functions.h @@ -1,17 +1,16 @@ #ifndef HEX_OPERATIONS_H #define HEX_OPERATIONS_H +#include #include #include -#include -#include -#include #include +#include #include +#include -namespace omni -{ - std::string int_to_hex(unsigned int input); +namespace omni { + std::string int_to_hex(unsigned int input); } #endif //HEX_OPERATIONS_H diff --git a/include/lobby.h b/include/lobby.h index a969f86..7b978d3 100644 --- a/include/lobby.h +++ b/include/lobby.h @@ -1,108 +1,107 @@ #ifndef LOBBY_H #define LOBBY_H -#include "aoimage.h" #include "aobutton.h" +#include "aoimage.h" #include "aopacket.h" #include "aotextarea.h" -#include -#include -#include #include -#include #include +#include +#include +#include #include #include +#include #include #include class AOApplication; -class Lobby : public QMainWindow -{ - Q_OBJECT +class Lobby : public QMainWindow { + Q_OBJECT public: - Lobby(AOApplication *p_ao_app); + Lobby(AOApplication *p_ao_app); - void set_widgets(); - void list_servers(); - void list_favorites(); - void append_chatmessage(QString f_name, QString f_message); - void append_error(QString f_message); - void set_player_count(int players_online, int max_players); - void set_stylesheet(QWidget *widget, QString target_tag); - void set_stylesheets(); - void set_fonts(); - void set_font(QWidget *widget, QString p_identifier); - void set_loading_text(QString p_text); - void show_loading_overlay(){ui_loading_background->show();} - void hide_loading_overlay(){ui_loading_background->hide();} - QString get_chatlog(); - int get_selected_server(); - void enable_connect_button(); + void set_widgets(); + void list_servers(); + void list_favorites(); + void append_chatmessage(QString f_name, QString f_message); + void append_error(QString f_message); + void set_player_count(int players_online, int max_players); + void set_stylesheet(QWidget *widget, QString target_tag); + void set_stylesheets(); + void set_fonts(); + void set_font(QWidget *widget, QString p_identifier); + void set_loading_text(QString p_text); + void show_loading_overlay() { ui_loading_background->show(); } + void hide_loading_overlay() { ui_loading_background->hide(); } + QString get_chatlog(); + int get_selected_server(); + void enable_connect_button(); - void set_loading_value(int p_value); + void set_loading_value(int p_value); - bool public_servers_selected = true; + bool public_servers_selected = true; - ~Lobby(); + ~Lobby(); private: - AOApplication *ao_app; + AOApplication *ao_app; - AOImage *ui_background; + AOImage *ui_background; - AOButton *ui_public_servers; - AOButton *ui_favorites; + AOButton *ui_public_servers; + AOButton *ui_favorites; - AOButton *ui_refresh; - AOButton *ui_add_to_fav; - AOButton *ui_connect; + AOButton *ui_refresh; + AOButton *ui_add_to_fav; + AOButton *ui_connect; - QLabel *ui_version; - AOButton *ui_about; + QLabel *ui_version; + AOButton *ui_about; - AOButton *ui_settings; + AOButton *ui_settings; - QTreeWidget *ui_server_list; - QLineEdit *ui_server_search; + QTreeWidget *ui_server_list; + QLineEdit *ui_server_search; - QLabel *ui_player_count; - AOTextArea *ui_description; + QLabel *ui_player_count; + AOTextArea *ui_description; - AOTextArea *ui_chatbox; + AOTextArea *ui_chatbox; - QLineEdit *ui_chatname; - QLineEdit *ui_chatmessage; + QLineEdit *ui_chatname; + QLineEdit *ui_chatmessage; - AOImage *ui_loading_background; - QTextEdit *ui_loading_text; - QProgressBar *ui_progress_bar; - AOButton *ui_cancel; + AOImage *ui_loading_background; + QTextEdit *ui_loading_text; + QProgressBar *ui_progress_bar; + AOButton *ui_cancel; - int last_index; + int last_index; - void set_size_and_pos(QWidget *p_widget, QString p_identifier); + void set_size_and_pos(QWidget *p_widget, QString p_identifier); private slots: - void on_public_servers_clicked(); - void on_favorites_clicked(); + void on_public_servers_clicked(); + void on_favorites_clicked(); - void on_refresh_pressed(); - void on_refresh_released(); - void on_add_to_fav_pressed(); - void on_add_to_fav_released(); - void on_connect_pressed(); - void on_connect_released(); - void on_about_clicked(); - void on_settings_clicked(); - void on_server_list_clicked(QTreeWidgetItem* p_item, int column); - void on_server_list_doubleclicked(QTreeWidgetItem* p_item, int column); - void on_server_search_edited(QString p_text); - void on_chatfield_return_pressed(); + void on_refresh_pressed(); + void on_refresh_released(); + void on_add_to_fav_pressed(); + void on_add_to_fav_released(); + void on_connect_pressed(); + void on_connect_released(); + void on_about_clicked(); + void on_settings_clicked(); + void on_server_list_clicked(QTreeWidgetItem *p_item, int column); + void on_server_list_doubleclicked(QTreeWidgetItem *p_item, int column); + void on_server_search_edited(QString p_text); + void on_chatfield_return_pressed(); }; #endif // LOBBY_H diff --git a/include/misc_functions.h b/include/misc_functions.h index 026c635..5287bee 100644 --- a/include/misc_functions.h +++ b/include/misc_functions.h @@ -1,8 +1,8 @@ #ifndef MISC_FUNCTIONS_H #define MISC_FUNCTIONS_H -#include #include +#include void delay(int p_milliseconds); diff --git a/include/networkmanager.h b/include/networkmanager.h index 08b10db..4d9d401 100644 --- a/include/networkmanager.h +++ b/include/networkmanager.h @@ -14,71 +14,70 @@ #undef MS_FAILOVER_SUPPORTED #endif -#include "aopacket.h" #include "aoapplication.h" +#include "aopacket.h" -#include #include +#include #include #include #include -class NetworkManager : public QObject -{ - Q_OBJECT +class NetworkManager : public QObject { + Q_OBJECT public: - NetworkManager(AOApplication *parent); - ~NetworkManager(); + NetworkManager(AOApplication *parent); + ~NetworkManager(); - AOApplication *ao_app; - QTcpSocket *ms_socket; - QTcpSocket *server_socket; - QDnsLookup *ms_dns; - QTimer *ms_reconnect_timer; + AOApplication *ao_app; + QTcpSocket *ms_socket; + QTcpSocket *server_socket; + QDnsLookup *ms_dns; + QTimer *ms_reconnect_timer; - const QString ms_srv_hostname = "_aoms._tcp.aceattorneyonline.com"; + const QString ms_srv_hostname = "_aoms._tcp.aceattorneyonline.com"; #ifdef LOCAL_MS - QString ms_nosrv_hostname = "localhost"; + QString ms_nosrv_hostname = "localhost"; #else - QString ms_nosrv_hostname = "master.aceattorneyonline.com"; + QString ms_nosrv_hostname = "master.aceattorneyonline.com"; #endif - const quint16 ms_port = 27016; - const int timeout_milliseconds = 2000; + const quint16 ms_port = 27016; + const int timeout_milliseconds = 2000; - // in seconds - const int ms_reconnect_delay = 7; + // in seconds + const int ms_reconnect_delay = 7; - bool ms_partial_packet = false; - QString ms_temp_packet = ""; + bool ms_partial_packet = false; + QString ms_temp_packet = ""; - bool partial_packet = false; - QString temp_packet = ""; + bool partial_packet = false; + QString temp_packet = ""; - unsigned int s_decryptor = 5; + unsigned int s_decryptor = 5; - void connect_to_master(); - void connect_to_master_nosrv(); - void connect_to_server(server_type p_server); + void connect_to_master(); + void connect_to_master_nosrv(); + void connect_to_server(server_type p_server); public slots: - void ship_ms_packet(QString p_packet); - void ship_server_packet(QString p_packet); + void ship_ms_packet(QString p_packet); + void ship_server_packet(QString p_packet); signals: - void ms_connect_finished(bool success, bool will_retry); + void ms_connect_finished(bool success, bool will_retry); private: - void perform_srv_lookup(); + void perform_srv_lookup(); private slots: - void on_srv_lookup(); - void handle_ms_packet(); - void handle_server_packet(); - void on_ms_nosrv_connect_success(); - void on_ms_socket_error(QAbstractSocket::SocketError error); - void retry_ms_connect(); + void on_srv_lookup(); + void handle_ms_packet(); + void handle_server_packet(); + void on_ms_nosrv_connect_success(); + void on_ms_socket_error(QAbstractSocket::SocketError error); + void retry_ms_connect(); }; #endif // NETWORKMANAGER_H diff --git a/include/scrolltext.h b/include/scrolltext.h index cf791c0..1455762 100644 --- a/include/scrolltext.h +++ b/include/scrolltext.h @@ -1,15 +1,13 @@ #ifndef SCROLLTEXT_H #define SCROLLTEXT_H -#include +#include +#include #include #include -#include -#include +#include - -class ScrollText : public QWidget -{ +class ScrollText : public QWidget { Q_OBJECT Q_PROPERTY(QString text READ text WRITE setText) Q_PROPERTY(QString separator READ separator WRITE setSeparator) @@ -24,7 +22,6 @@ public slots: QString separator() const; void setSeparator(QString separator); - protected: virtual void paintEvent(QPaintEvent *); virtual void resizeEvent(QResizeEvent *); diff --git a/include/text_file_functions.h b/include/text_file_functions.h index 119f38e..1da4d92 100644 --- a/include/text_file_functions.h +++ b/include/text_file_functions.h @@ -3,11 +3,11 @@ #include "aoapplication.h" #include "file_functions.h" -#include -#include -#include -#include #include +#include #include +#include +#include +#include #endif // TEXT_FILE_FUNCTIONS_H diff --git a/src/aoapplication.cpp b/src/aoapplication.cpp index 6213acd..4d2bb31 100644 --- a/src/aoapplication.cpp +++ b/src/aoapplication.cpp @@ -1,176 +1,166 @@ #include "aoapplication.h" -#include "lobby.h" #include "courtroom.h" -#include "networkmanager.h" #include "debug_functions.h" +#include "lobby.h" +#include "networkmanager.h" -#include "aooptionsdialog.h" #include "aocaseannouncerdialog.h" +#include "aooptionsdialog.h" AOApplication::AOApplication(int &argc, char **argv) : QApplication(argc, argv) { - // Create the QSettings class that points to the config.ini. - configini = new QSettings(get_base_path() + "config.ini", QSettings::IniFormat); + // Create the QSettings class that points to the config.ini. + configini = new QSettings(get_base_path() + "config.ini", QSettings::IniFormat); - net_manager = new NetworkManager(this); - discord = new AttorneyOnline::Discord(); - QObject::connect(net_manager, SIGNAL(ms_connect_finished(bool, bool)), - SLOT(ms_connect_finished(bool, bool))); + net_manager = new NetworkManager(this); + discord = new AttorneyOnline::Discord(); + QObject::connect(net_manager, SIGNAL(ms_connect_finished(bool, bool)), + SLOT(ms_connect_finished(bool, bool))); } AOApplication::~AOApplication() { - destruct_lobby(); - destruct_courtroom(); - delete discord; + destruct_lobby(); + destruct_courtroom(); + delete discord; } void AOApplication::construct_lobby() { - if (lobby_constructed) - { - qDebug() << "W: lobby was attempted constructed when it already exists"; - return; - } + if (lobby_constructed) { + qDebug() << "W: lobby was attempted constructed when it already exists"; + return; + } - w_lobby = new Lobby(this); - lobby_constructed = true; + w_lobby = new Lobby(this); + lobby_constructed = true; - QRect geometry = QGuiApplication::primaryScreen()->geometry(); - int x = (geometry.width()-w_lobby->width()) / 2; - int y = (geometry.height()-w_lobby->height()) / 2; - w_lobby->move(x, y); + QRect geometry = QGuiApplication::primaryScreen()->geometry(); + int x = (geometry.width() - w_lobby->width()) / 2; + int y = (geometry.height() - w_lobby->height()) / 2; + w_lobby->move(x, y); - if (is_discord_enabled()) - discord->state_lobby(); + if (is_discord_enabled()) + discord->state_lobby(); - w_lobby->show(); + w_lobby->show(); } void AOApplication::destruct_lobby() { - if(!lobby_constructed) - { - qDebug() << "W: lobby was attempted destructed when it did not exist"; - return; - } + if (!lobby_constructed) { + qDebug() << "W: lobby was attempted destructed when it did not exist"; + return; + } - delete w_lobby; - w_lobby = nullptr; - lobby_constructed = false; + delete w_lobby; + w_lobby = nullptr; + lobby_constructed = false; } void AOApplication::construct_courtroom() { - if (courtroom_constructed) - { - qDebug() << "W: courtroom was attempted constructed when it already exists"; - return; - } + if (courtroom_constructed) { + qDebug() << "W: courtroom was attempted constructed when it already exists"; + return; + } - w_courtroom = new Courtroom(this); - courtroom_constructed = true; + w_courtroom = new Courtroom(this); + courtroom_constructed = true; - QRect geometry = QGuiApplication::primaryScreen()->geometry(); - int x = (geometry.width()-w_courtroom->width()) / 2; - int y = (geometry.height()-w_courtroom->height()) / 2; - w_courtroom->move(x, y); + QRect geometry = QGuiApplication::primaryScreen()->geometry(); + int x = (geometry.width() - w_courtroom->width()) / 2; + int y = (geometry.height() - w_courtroom->height()) / 2; + w_courtroom->move(x, y); } void AOApplication::destruct_courtroom() { - if (!courtroom_constructed) - { - qDebug() << "W: courtroom was attempted destructed when it did not exist"; - return; - } + if (!courtroom_constructed) { + qDebug() << "W: courtroom was attempted destructed when it did not exist"; + return; + } - delete w_courtroom; - w_courtroom = nullptr; - courtroom_constructed = false; + delete w_courtroom; + w_courtroom = nullptr; + courtroom_constructed = false; } QString AOApplication::get_version_string() { - return - QString::number(RELEASE) + "." + - QString::number(MAJOR_VERSION) + "." + - QString::number(MINOR_VERSION); + return QString::number(RELEASE) + "." + + QString::number(MAJOR_VERSION) + "." + + QString::number(MINOR_VERSION); } void AOApplication::reload_theme() { - current_theme = read_theme(); + current_theme = read_theme(); } void AOApplication::set_favorite_list() { - favorite_list = read_serverlist_txt(); + favorite_list = read_serverlist_txt(); } QString AOApplication::get_current_char() { - if (courtroom_constructed) - return w_courtroom->get_current_char(); - else - return ""; + if (courtroom_constructed) + return w_courtroom->get_current_char(); + else + return ""; } void AOApplication::add_favorite_server(int p_server) { - if (p_server < 0 || p_server >= server_list.size()) - return; + if (p_server < 0 || p_server >= server_list.size()) + return; - server_type fav_server = server_list.at(p_server); + server_type fav_server = server_list.at(p_server); - QString str_port = QString::number(fav_server.port); + QString str_port = QString::number(fav_server.port); - QString server_line = fav_server.ip + ":" + str_port + ":" + fav_server.name; + QString server_line = fav_server.ip + ":" + str_port + ":" + fav_server.name; - write_to_serverlist_txt(server_line); + write_to_serverlist_txt(server_line); } void AOApplication::server_disconnected() { - if (courtroom_constructed) - { - call_notice(tr("Disconnected from server.")); - construct_lobby(); - destruct_courtroom(); - } + if (courtroom_constructed) { + call_notice(tr("Disconnected from server.")); + construct_lobby(); + destruct_courtroom(); + } } void AOApplication::loading_cancelled() { - destruct_courtroom(); + destruct_courtroom(); - w_lobby->hide_loading_overlay(); + w_lobby->hide_loading_overlay(); } void AOApplication::ms_connect_finished(bool connected, bool will_retry) { - if (connected) - { - AOPacket *f_packet = new AOPacket("ALL#%"); - send_ms_packet(f_packet); - } - else - { - if (will_retry) - { - if (lobby_constructed) - w_lobby->append_error(tr("Error connecting to master server. Will try again in %1 seconds.").arg(QString::number(net_manager->ms_reconnect_delay))); + if (connected) { + AOPacket *f_packet = new AOPacket("ALL#%"); + send_ms_packet(f_packet); } - else - { - call_error(tr("There was an error connecting to the master server.\n" - "We deploy multiple master servers to mitigate any possible downtime, " - "but the client appears to have exhausted all possible methods of finding " - "and connecting to one.\n" - "Please check your Internet connection and firewall, and please try again.")); + else { + if (will_retry) { + if (lobby_constructed) + w_lobby->append_error(tr("Error connecting to master server. Will try again in %1 seconds.").arg(QString::number(net_manager->ms_reconnect_delay))); + } + else { + call_error(tr("There was an error connecting to the master server.\n" + "We deploy multiple master servers to mitigate any possible downtime, " + "but the client appears to have exhausted all possible methods of finding " + "and connecting to one.\n" + "Please check your Internet connection and firewall, and please try again.")); + } } - } } void AOApplication::call_settings_menu() diff --git a/src/aoblipplayer.cpp b/src/aoblipplayer.cpp index 008ff16..957fd55 100644 --- a/src/aoblipplayer.cpp +++ b/src/aoblipplayer.cpp @@ -3,122 +3,115 @@ #if defined(BASSAUDIO) //Using bass.dll for the blips AOBlipPlayer::AOBlipPlayer(QWidget *parent, AOApplication *p_ao_app) { - m_parent = parent; - ao_app = p_ao_app; + m_parent = parent; + ao_app = p_ao_app; } void AOBlipPlayer::set_blips(QString p_sfx) { - QString f_path = ao_app->get_sfx_suffix(ao_app->get_sounds_path(p_sfx)); + QString f_path = ao_app->get_sfx_suffix(ao_app->get_sounds_path(p_sfx)); - for (int n_stream = 0 ; n_stream < 5 ; ++n_stream) - { - BASS_StreamFree(m_stream_list[n_stream]); + for (int n_stream = 0; n_stream < 5; ++n_stream) { + BASS_StreamFree(m_stream_list[n_stream]); - if (f_path.endsWith(".opus")) - m_stream_list[n_stream] = BASS_OPUS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, BASS_UNICODE | BASS_ASYNCFILE); - else - m_stream_list[n_stream] = BASS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, BASS_UNICODE | BASS_ASYNCFILE); - } + if (f_path.endsWith(".opus")) + m_stream_list[n_stream] = BASS_OPUS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, BASS_UNICODE | BASS_ASYNCFILE); + else + m_stream_list[n_stream] = BASS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, BASS_UNICODE | BASS_ASYNCFILE); + } - set_volume_internal(m_volume); + set_volume_internal(m_volume); } void AOBlipPlayer::blip_tick() { - if (delay.isValid() && delay.elapsed() < max_blip_ms) - return; + if (delay.isValid() && delay.elapsed() < max_blip_ms) + return; - delay.start(); - int f_cycle = m_cycle++; + delay.start(); + int f_cycle = m_cycle++; - if (m_cycle == 5) - m_cycle = 0; + if (m_cycle == 5) + m_cycle = 0; - HSTREAM f_stream = m_stream_list[f_cycle]; - if (ao_app->get_audio_output_device() != "default") - BASS_ChannelSetDevice(f_stream, BASS_GetDevice()); - BASS_ChannelPlay(f_stream, false); + HSTREAM f_stream = m_stream_list[f_cycle]; + if (ao_app->get_audio_output_device() != "default") + BASS_ChannelSetDevice(f_stream, BASS_GetDevice()); + BASS_ChannelPlay(f_stream, false); } void AOBlipPlayer::set_volume(qreal p_value) { - m_volume = p_value / 100; - set_volume_internal(m_volume); + m_volume = p_value / 100; + set_volume_internal(m_volume); } void AOBlipPlayer::set_volume_internal(qreal p_value) { - float volume = static_cast(p_value); + float volume = static_cast(p_value); - for (int n_stream = 0 ; n_stream < 5 ; ++n_stream) - { - BASS_ChannelSetAttribute(m_stream_list[n_stream], BASS_ATTRIB_VOL, volume); - } + for (int n_stream = 0; n_stream < 5; ++n_stream) { + BASS_ChannelSetAttribute(m_stream_list[n_stream], BASS_ATTRIB_VOL, volume); + } } #elif defined(QTAUDIO) //Using Qt's QSoundEffect class AOBlipPlayer::AOBlipPlayer(QWidget *parent, AOApplication *p_ao_app) { - m_parent = parent; - ao_app = p_ao_app; + m_parent = parent; + ao_app = p_ao_app; } void AOBlipPlayer::set_blips(QString p_sfx) { - QString f_path = ao_app->get_sounds_path(p_sfx); + QString f_path = ao_app->get_sounds_path(p_sfx); - for (int n_stream = 0 ; n_stream < 5 ; ++n_stream) - { - m_blips.setSource(QUrl::fromLocalFile(f_path)); - } + for (int n_stream = 0; n_stream < 5; ++n_stream) { + m_blips.setSource(QUrl::fromLocalFile(f_path)); + } - set_volume_internal(m_volume); + set_volume_internal(m_volume); } void AOBlipPlayer::blip_tick() { - int f_cycle = m_cycle++; + int f_cycle = m_cycle++; - if (m_cycle == 5) - m_cycle = 0; + if (m_cycle == 5) + m_cycle = 0; - m_blips.play(); + m_blips.play(); } void AOBlipPlayer::set_volume(qreal p_value) { - m_volume = p_value / 100; - set_volume_internal(m_volume); + m_volume = p_value / 100; + set_volume_internal(m_volume); } void AOBlipPlayer::set_volume_internal(qreal p_value) { - m_blips.setVolume(m_volume); + m_blips.setVolume(m_volume); } -#else //No audio +#else //No audio AOBlipPlayer::AOBlipPlayer(QWidget *parent, AOApplication *p_ao_app) { - m_parent = parent; - ao_app = p_ao_app; + m_parent = parent; + ao_app = p_ao_app; } void AOBlipPlayer::set_blips(QString p_sfx) { - } void AOBlipPlayer::blip_tick() { - } void AOBlipPlayer::set_volume(qreal p_value) { - } void AOBlipPlayer::set_volume_internal(qreal p_value) { - } #endif diff --git a/src/aobutton.cpp b/src/aobutton.cpp index 9efe13d..05dedc1 100644 --- a/src/aobutton.cpp +++ b/src/aobutton.cpp @@ -5,32 +5,28 @@ AOButton::AOButton(QWidget *parent, AOApplication *p_ao_app) : QPushButton(parent) { - ao_app = p_ao_app; + ao_app = p_ao_app; } AOButton::~AOButton() { - } void AOButton::set_image(QString p_image) { - 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)); + 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; }"); - } - 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; }"); - } - else - return; + 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; }"); + } + 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; }"); + } + else + return; } - diff --git a/src/aocaseannouncerdialog.cpp b/src/aocaseannouncerdialog.cpp index 5b82b64..3063aa8 100644 --- a/src/aocaseannouncerdialog.cpp +++ b/src/aocaseannouncerdialog.cpp @@ -1,82 +1,82 @@ #include "aocaseannouncerdialog.h" AOCaseAnnouncerDialog::AOCaseAnnouncerDialog(QWidget *parent, AOApplication *p_ao_app, Courtroom *p_court) - : QDialog(parent) + : QDialog(parent) { - ao_app = p_ao_app; - court = p_court; + ao_app = p_ao_app; + court = p_court; - setWindowTitle(tr("Case Announcer")); - resize(405, 235); + setWindowTitle(tr("Case Announcer")); + resize(405, 235); - ui_announcer_buttons = new QDialogButtonBox(this); + ui_announcer_buttons = new QDialogButtonBox(this); - QSizePolicy sizepolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); - sizepolicy.setHorizontalStretch(0); - sizepolicy.setVerticalStretch(0); - sizepolicy.setHeightForWidth(ui_announcer_buttons->sizePolicy().hasHeightForWidth()); - ui_announcer_buttons->setSizePolicy(sizepolicy); - ui_announcer_buttons->setOrientation(Qt::Horizontal); - ui_announcer_buttons->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + QSizePolicy sizepolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + sizepolicy.setHorizontalStretch(0); + sizepolicy.setVerticalStretch(0); + sizepolicy.setHeightForWidth(ui_announcer_buttons->sizePolicy().hasHeightForWidth()); + ui_announcer_buttons->setSizePolicy(sizepolicy); + ui_announcer_buttons->setOrientation(Qt::Horizontal); + ui_announcer_buttons->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); - QObject::connect(ui_announcer_buttons, SIGNAL(accepted()), this, SLOT(ok_pressed())); - QObject::connect(ui_announcer_buttons, SIGNAL(rejected()), this, SLOT(cancel_pressed())); + QObject::connect(ui_announcer_buttons, SIGNAL(accepted()), this, SLOT(ok_pressed())); + QObject::connect(ui_announcer_buttons, SIGNAL(rejected()), this, SLOT(cancel_pressed())); - setUpdatesEnabled(false); + setUpdatesEnabled(false); - ui_vbox_layout = new QVBoxLayout(this); + ui_vbox_layout = new QVBoxLayout(this); - ui_form_layout = new QFormLayout(this); - ui_form_layout->setLabelAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignVCenter); - ui_form_layout->setFormAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignTop); - ui_form_layout->setContentsMargins(6, 6, 6, 6); + ui_form_layout = new QFormLayout(this); + ui_form_layout->setLabelAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignVCenter); + ui_form_layout->setFormAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignTop); + ui_form_layout->setContentsMargins(6, 6, 6, 6); - ui_vbox_layout->addItem(ui_form_layout); - ui_vbox_layout->addWidget(ui_announcer_buttons); + ui_vbox_layout->addItem(ui_form_layout); + ui_vbox_layout->addWidget(ui_announcer_buttons); - ui_case_title_label = new QLabel(this); - ui_case_title_label->setText(tr("Case title:")); + ui_case_title_label = new QLabel(this); + ui_case_title_label->setText(tr("Case title:")); - ui_form_layout->setWidget(0, QFormLayout::LabelRole, ui_case_title_label); + ui_form_layout->setWidget(0, QFormLayout::LabelRole, ui_case_title_label); - ui_case_title_textbox = new QLineEdit(this); - ui_case_title_textbox->setMaxLength(50); + ui_case_title_textbox = new QLineEdit(this); + ui_case_title_textbox->setMaxLength(50); - ui_form_layout->setWidget(0, QFormLayout::FieldRole, ui_case_title_textbox); + ui_form_layout->setWidget(0, QFormLayout::FieldRole, ui_case_title_textbox); - ui_defense_needed = new QCheckBox(this); - ui_defense_needed->setText(tr("Defense needed")); - ui_prosecutor_needed = new QCheckBox(this); - ui_prosecutor_needed->setText(tr("Prosecution needed")); - ui_judge_needed = new QCheckBox(this); - ui_judge_needed->setText(tr("Judge needed")); - ui_juror_needed = new QCheckBox(this); - ui_juror_needed->setText(tr("Jurors needed")); - ui_steno_needed = new QCheckBox(this); - ui_steno_needed->setText(tr("Stenographer needed")); + ui_defense_needed = new QCheckBox(this); + ui_defense_needed->setText(tr("Defense needed")); + ui_prosecutor_needed = new QCheckBox(this); + ui_prosecutor_needed->setText(tr("Prosecution needed")); + ui_judge_needed = new QCheckBox(this); + ui_judge_needed->setText(tr("Judge needed")); + ui_juror_needed = new QCheckBox(this); + ui_juror_needed->setText(tr("Jurors needed")); + ui_steno_needed = new QCheckBox(this); + ui_steno_needed->setText(tr("Stenographer needed")); - ui_form_layout->setWidget(1, QFormLayout::FieldRole, ui_defense_needed); - ui_form_layout->setWidget(2, QFormLayout::FieldRole, ui_prosecutor_needed); - ui_form_layout->setWidget(3, QFormLayout::FieldRole, ui_judge_needed); - ui_form_layout->setWidget(4, QFormLayout::FieldRole, ui_juror_needed); - ui_form_layout->setWidget(5, QFormLayout::FieldRole, ui_steno_needed); + ui_form_layout->setWidget(1, QFormLayout::FieldRole, ui_defense_needed); + ui_form_layout->setWidget(2, QFormLayout::FieldRole, ui_prosecutor_needed); + ui_form_layout->setWidget(3, QFormLayout::FieldRole, ui_judge_needed); + ui_form_layout->setWidget(4, QFormLayout::FieldRole, ui_juror_needed); + ui_form_layout->setWidget(5, QFormLayout::FieldRole, ui_steno_needed); - setUpdatesEnabled(true); + setUpdatesEnabled(true); } void AOCaseAnnouncerDialog::ok_pressed() { - court->announce_case(ui_case_title_textbox->text(), - ui_defense_needed->isChecked(), - ui_prosecutor_needed->isChecked(), - ui_judge_needed->isChecked(), - ui_juror_needed->isChecked(), - ui_steno_needed->isChecked()); + court->announce_case(ui_case_title_textbox->text(), + ui_defense_needed->isChecked(), + ui_prosecutor_needed->isChecked(), + ui_judge_needed->isChecked(), + ui_juror_needed->isChecked(), + ui_steno_needed->isChecked()); - done(0); + done(0); } void AOCaseAnnouncerDialog::cancel_pressed() { - done(0); + done(0); } diff --git a/src/aocharbutton.cpp b/src/aocharbutton.cpp index 6acad70..d8c337d 100644 --- a/src/aocharbutton.cpp +++ b/src/aocharbutton.cpp @@ -4,98 +4,92 @@ AOCharButton::AOCharButton(QWidget *parent, AOApplication *p_ao_app, int x_pos, int y_pos, bool is_taken) : QPushButton(parent) { - m_parent = parent; + m_parent = parent; - ao_app = p_ao_app; + ao_app = p_ao_app; - taken = is_taken; + taken = is_taken; - this->resize(60, 60); - this->move(x_pos, y_pos); + this->resize(60, 60); + this->move(x_pos, y_pos); - ui_taken = new AOImage(this, ao_app); - ui_taken->resize(60, 60); - ui_taken->set_image("char_taken"); - ui_taken->setAttribute(Qt::WA_TransparentForMouseEvents); - ui_taken->hide(); + ui_taken = new AOImage(this, ao_app); + ui_taken->resize(60, 60); + ui_taken->set_image("char_taken"); + ui_taken->setAttribute(Qt::WA_TransparentForMouseEvents); + ui_taken->hide(); - ui_passworded = new AOImage(this, ao_app); - ui_passworded->resize(60, 60); - ui_passworded->set_image("char_passworded"); - ui_passworded->setAttribute(Qt::WA_TransparentForMouseEvents); - ui_passworded->hide(); + ui_passworded = new AOImage(this, ao_app); + ui_passworded->resize(60, 60); + ui_passworded->set_image("char_passworded"); + ui_passworded->setAttribute(Qt::WA_TransparentForMouseEvents); + ui_passworded->hide(); - ui_selector = new AOImage(parent, ao_app); - ui_selector->resize(62, 62); - ui_selector->move(x_pos - 1, y_pos - 1); - ui_selector->set_image("char_selector"); - ui_selector->setAttribute(Qt::WA_TransparentForMouseEvents); - ui_selector->hide(); + ui_selector = new AOImage(parent, ao_app); + ui_selector->resize(62, 62); + ui_selector->move(x_pos - 1, y_pos - 1); + ui_selector->set_image("char_selector"); + ui_selector->setAttribute(Qt::WA_TransparentForMouseEvents); + ui_selector->hide(); } void AOCharButton::reset() { - ui_taken->hide(); - ui_passworded->hide(); - ui_selector->hide(); + ui_taken->hide(); + ui_passworded->hide(); + ui_selector->hide(); } void AOCharButton::set_taken(bool is_taken) { - taken = is_taken; + taken = is_taken; } void AOCharButton::apply_taken_image() { - if (taken) - { - ui_taken->move(0,0); - ui_taken->show(); - } - else - { - ui_taken->hide(); - } + if (taken) { + ui_taken->move(0, 0); + ui_taken->show(); + } + else { + ui_taken->hide(); + } } void AOCharButton::set_passworded() { - ui_passworded->show(); + ui_passworded->show(); } void AOCharButton::set_image(QString p_character) { - QString image_path = ao_app->get_static_image_suffix(ao_app->get_character_path(p_character, "char_icon")); + QString image_path = ao_app->get_static_image_suffix(ao_app->get_character_path(p_character, "char_icon")); - this->setText(""); + this->setText(""); - if (file_exists(image_path)) - { - 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; }"); - } - else - { - this->setStyleSheet("QPushButton { border-image: url(); }" - "QToolTip { background-image: url(); color: #000000; background-color: #ffffff; border: 0px; }"); - this->setText(p_character); - } + if (file_exists(image_path)) { + 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; }"); + } + else { + this->setStyleSheet("QPushButton { border-image: url(); }" + "QToolTip { background-image: url(); color: #000000; background-color: #ffffff; border: 0px; }"); + this->setText(p_character); + } } -void AOCharButton::enterEvent(QEvent * e) +void AOCharButton::enterEvent(QEvent *e) { - ui_selector->move(this->x() - 1, this->y() - 1); - ui_selector->raise(); - ui_selector->show(); + ui_selector->move(this->x() - 1, this->y() - 1); + ui_selector->raise(); + ui_selector->show(); - setFlat(false); - QPushButton::enterEvent(e); + setFlat(false); + QPushButton::enterEvent(e); } -void AOCharButton::leaveEvent(QEvent * e) +void AOCharButton::leaveEvent(QEvent *e) { - ui_selector->hide(); - QPushButton::leaveEvent(e); + ui_selector->hide(); + QPushButton::leaveEvent(e); } - - diff --git a/src/aocharmovie.cpp b/src/aocharmovie.cpp index 7bbdc1b..2963275 100644 --- a/src/aocharmovie.cpp +++ b/src/aocharmovie.cpp @@ -1,248 +1,230 @@ #include "aocharmovie.h" -#include "misc_functions.h" -#include "file_functions.h" #include "aoapplication.h" +#include "file_functions.h" +#include "misc_functions.h" AOCharMovie::AOCharMovie(QWidget *p_parent, AOApplication *p_ao_app) : QLabel(p_parent) { - ao_app = p_ao_app; - preanim_timer = new QTimer(this); - preanim_timer->setSingleShot(true); + ao_app = p_ao_app; + preanim_timer = new QTimer(this); + preanim_timer->setSingleShot(true); - ticker = new QTimer(this); - ticker->setTimerType(Qt::PreciseTimer); - ticker->setSingleShot(false); - connect(ticker, SIGNAL(timeout()), this, SLOT(movie_ticker())); + ticker = new QTimer(this); + ticker->setTimerType(Qt::PreciseTimer); + ticker->setSingleShot(false); + connect(ticker, SIGNAL(timeout()), this, SLOT(movie_ticker())); -// connect(m_movie, SIGNAL(frameChanged(int)), this, SLOT(frame_change(int))); - connect(preanim_timer, SIGNAL(timeout()), this, SLOT(preanim_done())); + // connect(m_movie, SIGNAL(frameChanged(int)), this, SLOT(frame_change(int))); + connect(preanim_timer, SIGNAL(timeout()), this, SLOT(preanim_done())); } void AOCharMovie::load_image(QString p_char, QString p_emote, QString emote_prefix) { #ifdef DEBUG_CHARMOVIE - actual_time.restart(); + actual_time.restart(); #endif - QString emote_path; - QList pathlist; - pathlist = { - ao_app->get_image_suffix(ao_app->get_character_path(p_char, emote_prefix + p_emote)), //Default path - ao_app->get_image_suffix(ao_app->get_character_path(p_char, emote_prefix + "/" + p_emote)),//Path check if it's categorized into a folder - ao_app->get_character_path(p_char, p_emote + ".png"), //Non-animated path if emote_prefix fails - 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 - }; + QString emote_path; + QList pathlist; + pathlist = { + ao_app->get_image_suffix(ao_app->get_character_path(p_char, emote_prefix + p_emote)), //Default path + ao_app->get_image_suffix(ao_app->get_character_path(p_char, emote_prefix + "/" + p_emote)), //Path check if it's categorized into a folder + ao_app->get_character_path(p_char, p_emote + ".png"), //Non-animated path if emote_prefix fails + 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 + }; - for (QString path : pathlist) - { - if (file_exists(path)) - { - emote_path = path; - break; - } - } + for (QString path : pathlist) { + if (file_exists(path)) { + emote_path = path; + break; + } + } - this->clear(); - ticker->stop(); - preanim_timer->stop(); - movie_frames.clear(); - movie_delays.clear(); - movie_effects.clear(); + this->clear(); + ticker->stop(); + preanim_timer->stop(); + movie_frames.clear(); + movie_delays.clear(); + movie_effects.clear(); - if (!file_exists(emote_path)) - return; + if (!file_exists(emote_path)) + return; - m_reader->setFileName(emote_path); - QPixmap f_pixmap = this->get_pixmap(m_reader->read()); - int f_delay = m_reader->nextImageDelay(); + m_reader->setFileName(emote_path); + QPixmap f_pixmap = this->get_pixmap(m_reader->read()); + int f_delay = m_reader->nextImageDelay(); - frame = 0; - max_frames = m_reader->imageCount(); + frame = 0; + max_frames = m_reader->imageCount(); - this->set_frame(f_pixmap); - this->show(); - if (max_frames > 1) - { - movie_frames.append(f_pixmap); - movie_delays.append(f_delay); - } + this->set_frame(f_pixmap); + this->show(); + if (max_frames > 1) { + movie_frames.append(f_pixmap); + movie_delays.append(f_delay); + } - m_char = p_char; - m_emote = emote_prefix + p_emote; + m_char = p_char; + m_emote = emote_prefix + p_emote; - if (network_strings.size() > 0) //our FX overwritten by networked ones - this->load_network_effects(); - else //Use default ini FX - this->load_effects(); + if (network_strings.size() > 0) //our FX overwritten by networked ones + this->load_network_effects(); + else //Use default ini FX + this->load_effects(); #ifdef DEBUG_CHARMOVIE - qDebug() << max_frames << "Setting image to " << emote_path << "Time taken to process image:" << actual_time.elapsed(); + qDebug() << max_frames << "Setting image to " << emote_path << "Time taken to process image:" << actual_time.elapsed(); - actual_time.restart(); + actual_time.restart(); #endif } void AOCharMovie::load_effects() { - movie_effects.clear(); - 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); - if (effect != "") - { - movie_effects[e_frame].append("shake"); - } + movie_effects.clear(); + 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); + if (effect != "") { + movie_effects[e_frame].append("shake"); + } - effect = ao_app->get_flash_frame(m_char, m_emote, e_frame); - if (effect != "") - { - movie_effects[e_frame].append("flash"); - } + effect = ao_app->get_flash_frame(m_char, m_emote, e_frame); + if (effect != "") { + movie_effects[e_frame].append("flash"); + } - effect = ao_app->get_sfx_frame(m_char, m_emote, e_frame); - if (effect != "") - { - movie_effects[e_frame].append("sfx^"+effect); + effect = ao_app->get_sfx_frame(m_char, m_emote, e_frame); + if (effect != "") { + movie_effects[e_frame].append("sfx^" + effect); + } } - } } void AOCharMovie::load_network_effects() { - movie_effects.clear(); - movie_effects.resize(max_frames); - //Order is important!!! - QStringList effects_list = {"shake", "flash", "sfx^"}; + movie_effects.clear(); + movie_effects.resize(max_frames); + //Order is important!!! + QStringList effects_list = {"shake", "flash", "sfx^"}; - //Determines which list is smaller - effects_list or network_strings - and uses it as basis for the loop. - //This way, incomplete network_strings would still be parsed, and excess/unaccounted for networked information is omitted. - int effects_size = qMin(effects_list.size(), network_strings.size()); + //Determines which list is smaller - effects_list or network_strings - and uses it as basis for the loop. + //This way, incomplete network_strings would still be parsed, and excess/unaccounted for networked information is omitted. + int effects_size = qMin(effects_list.size(), network_strings.size()); - for (int i = 0; i < effects_size; ++i) - { - QString netstring = network_strings.at(i); - QStringList emote_splits = netstring.split("^"); - foreach (QString emote, emote_splits) - { - QStringList parsed = emote.split("|"); - if (parsed.size() <= 0 || parsed.at(0) != m_emote) - continue; - foreach (QString frame_data, parsed) - { - QStringList frame_split = frame_data.split("="); - if (frame_split.size() <= 1) //We might still be hanging at the emote itself (entry 0). - continue; - int f_frame = frame_split.at(0).toInt(); - if (f_frame >= max_frames) - { - qDebug() << "Warning: out of bounds" << effects_list[i] << "frame" << f_frame << "out of" << max_frames << "for" << m_char << m_emote; - continue; + for (int i = 0; i < effects_size; ++i) { + QString netstring = network_strings.at(i); + QStringList emote_splits = netstring.split("^"); + foreach (QString emote, emote_splits) { + QStringList parsed = emote.split("|"); + if (parsed.size() <= 0 || parsed.at(0) != m_emote) + continue; + foreach (QString frame_data, parsed) { + QStringList frame_split = frame_data.split("="); + if (frame_split.size() <= 1) //We might still be hanging at the emote itself (entry 0). + continue; + int f_frame = frame_split.at(0).toInt(); + if (f_frame >= max_frames) { + qDebug() << "Warning: out of bounds" << effects_list[i] << "frame" << f_frame << "out of" << max_frames << "for" << m_char << m_emote; + continue; + } + QString f_data = frame_split.at(1); + if (f_data != "") { + QString effect = effects_list[i]; + if (effect == "sfx^") //Currently the only frame result that feeds us data, let's yank it in. + effect += f_data; + qDebug() << effect << f_data << "frame" << f_frame << "for" << m_char << m_emote; + movie_effects[f_frame].append(effect); + } + } } - QString f_data = frame_split.at(1); - if (f_data != "") - { - QString effect = effects_list[i]; - if (effect == "sfx^") //Currently the only frame result that feeds us data, let's yank it in. - effect += f_data; - qDebug() << effect << f_data << "frame" << f_frame << "for" << m_char << m_emote; - movie_effects[f_frame].append(effect); - } - } } - } } void AOCharMovie::play() { - play_frame_effect(frame); - if (max_frames <= 1) - { - if (play_once) - ticker->start(60); - } - else - ticker->start(this->get_frame_delay(movie_delays[frame])); + play_frame_effect(frame); + if (max_frames <= 1) { + if (play_once) + ticker->start(60); + } + else + ticker->start(this->get_frame_delay(movie_delays[frame])); } void AOCharMovie::play_pre(QString p_char, QString p_emote, int duration) { - load_image(p_char, p_emote, ""); - //As much as I'd like to screw around with [Time] durations modifying the animation speed, I don't think I can reliably do that, - //not without looping through all frames in the image at least - which causes lag. So for now it simply ends the preanimation early instead. - play_once = true; - if (duration > 0) //It's -1 if there's no definition in [Time] for it. In which case, it will let the animation run out in full. Duration 0 does the same. - preanim_timer->start(duration * time_mod); //This timer will not fire if the animation finishes earlier than that - play(); + load_image(p_char, p_emote, ""); + //As much as I'd like to screw around with [Time] durations modifying the animation speed, I don't think I can reliably do that, + //not without looping through all frames in the image at least - which causes lag. So for now it simply ends the preanimation early instead. + play_once = true; + if (duration > 0) //It's -1 if there's no definition in [Time] for it. In which case, it will let the animation run out in full. Duration 0 does the same. + preanim_timer->start(duration * time_mod); //This timer will not fire if the animation finishes earlier than that + play(); } void AOCharMovie::play_talking(QString p_char, QString p_emote) { - play_once = false; - load_image(p_char, p_emote, "(b)"); - play(); + play_once = false; + load_image(p_char, p_emote, "(b)"); + play(); } void AOCharMovie::play_idle(QString p_char, QString p_emote) { - play_once = false; - load_image(p_char, p_emote, "(a)"); - play(); + play_once = false; + load_image(p_char, p_emote, "(a)"); + play(); } void AOCharMovie::play_frame_effect(int frame) { - if(frame < max_frames) - { - foreach (QString effect, movie_effects[frame]) - { - if(effect == "shake") - { - shake(); + if (frame < max_frames) { + foreach (QString effect, movie_effects[frame]) { + if (effect == "shake") { + shake(); #ifdef DEBUG_CHARMOVIE - qDebug() << "Attempting to play shake on frame" << frame; + qDebug() << "Attempting to play shake on frame" << frame; #endif - } + } - if(effect == "flash") - { - flash(); + if (effect == "flash") { + flash(); #ifdef DEBUG_CHARMOVIE - qDebug() << "Attempting to play flash on frame" << frame; + qDebug() << "Attempting to play flash on frame" << frame; #endif - } + } - if(effect.startsWith("sfx^")) - { - QString sfx = effect.section("^", 1); - play_sfx(sfx); + if (effect.startsWith("sfx^")) { + QString sfx = effect.section("^", 1); + play_sfx(sfx); #ifdef DEBUG_CHARMOVIE - qDebug() << "Attempting to play sfx" << sfx << "on frame" << frame; + qDebug() << "Attempting to play sfx" << sfx << "on frame" << frame; #endif - } + } + } } - } } void AOCharMovie::stop() { - //for all intents and purposes, stopping is the same as hiding. at no point do we want a frozen gif to display - ticker->stop(); - preanim_timer->stop(); - this->hide(); + //for all intents and purposes, stopping is the same as hiding. at no point do we want a frozen gif to display + ticker->stop(); + preanim_timer->stop(); + this->hide(); } QPixmap AOCharMovie::get_pixmap(QImage image) { QPixmap f_pixmap; - if(m_flipped) + if (m_flipped) f_pixmap = QPixmap::fromImage(image.mirrored(true, false)); else f_pixmap = QPixmap::fromImage(image); -// auto aspect_ratio = Qt::KeepAspectRatio; + // auto aspect_ratio = Qt::KeepAspectRatio; auto transform_mode = Qt::FastTransformation; if (f_pixmap.height() > f_h) //We are downscaling, use anti-aliasing. - transform_mode = Qt::SmoothTransformation; + transform_mode = Qt::SmoothTransformation; f_pixmap = f_pixmap.scaledToHeight(f_h, transform_mode); this->resize(f_pixmap.size()); @@ -253,64 +235,61 @@ QPixmap AOCharMovie::get_pixmap(QImage image) void AOCharMovie::set_frame(QPixmap f_pixmap) { this->setPixmap(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 + QLabel::move(x + (f_w - f_pixmap.width()) / 2, y + (f_h - f_pixmap.height())); //Always center horizontally, always put at the bottom vertically } void AOCharMovie::combo_resize(int w, int h) { - QSize f_size(w, h); - f_w = w; - f_h = h; - this->resize(f_size); + QSize f_size(w, h); + f_w = w; + f_h = h; + this->resize(f_size); } int AOCharMovie::get_frame_delay(int delay) { - return static_cast(double(delay) * double(speed/100)); + return static_cast(double(delay) * double(speed / 100)); } void AOCharMovie::move(int ax, int ay) { - x = ax; - y = ay; - QLabel::move(x, y); + x = ax; + y = ay; + QLabel::move(x, y); } void AOCharMovie::movie_ticker() { - ++frame; - if(frame >= max_frames) - { - if(play_once) - { - preanim_done(); - return; + ++frame; + if (frame >= max_frames) { + if (play_once) { + preanim_done(); + return; + } + else + frame = 0; + } + // qint64 difference = elapsed - movie_delays[frame]; + if (frame >= movie_frames.size()) { + m_reader->jumpToImage(frame); + movie_frames.resize(frame + 1); + movie_frames[frame] = this->get_pixmap(m_reader->read()); + movie_delays.resize(frame + 1); + movie_delays[frame] = m_reader->nextImageDelay(); } - else - frame = 0; - } -// qint64 difference = elapsed - movie_delays[frame]; - if(frame >= movie_frames.size()) - { - m_reader->jumpToImage(frame); - movie_frames.resize(frame + 1); - movie_frames[frame] = this->get_pixmap(m_reader->read()); - movie_delays.resize(frame + 1); - movie_delays[frame] = m_reader->nextImageDelay(); - } #ifdef DEBUG_CHARMOVIE - qDebug() << frame << movie_delays[frame] << "actual time taken from last frame:" << actual_time.restart(); + qDebug() << frame << movie_delays[frame] << "actual time taken from last frame:" << actual_time.restart(); #endif - this->set_frame(movie_frames[frame]); - play_frame_effect(frame); - ticker->setInterval(this->get_frame_delay(movie_delays[frame])); + this->set_frame(movie_frames[frame]); + play_frame_effect(frame); + ticker->setInterval(this->get_frame_delay(movie_delays[frame])); } void AOCharMovie::preanim_done() { - ticker->stop(); - preanim_timer->stop(); - done(); + ticker->stop(); + preanim_timer->stop(); + done(); } diff --git a/src/aoemotebutton.cpp b/src/aoemotebutton.cpp index e42bb73..991451f 100644 --- a/src/aoemotebutton.cpp +++ b/src/aoemotebutton.cpp @@ -4,40 +4,38 @@ AOEmoteButton::AOEmoteButton(QWidget *p_parent, AOApplication *p_ao_app, int p_x, int p_y, int p_w, int p_h) : QPushButton(p_parent) { - parent = p_parent; - ao_app = p_ao_app; + parent = p_parent; + ao_app = p_ao_app; - this->move(p_x, p_y); - this->resize(p_w, p_h); + this->move(p_x, p_y); + this->resize(p_w, p_h); - connect(this, SIGNAL(clicked()), this, SLOT(on_clicked())); + connect(this, SIGNAL(clicked()), this, SLOT(on_clicked())); } void AOEmoteButton::set_image(QString p_image, QString p_emote_comment) { - if (file_exists(p_image)) - { - this->setText(""); - this->setStyleSheet("QPushButton { border-image: url(\"" + p_image + "\") 0 0 0 0 stretch stretch; }" - "QToolTip { color: #000000; background-color: #ffffff; border: 0px; }"); - } - else - { - this->setText(p_emote_comment); - this->setStyleSheet("QPushButton { border-image: url(); }" - "QToolTip { background-image: url(); color: #000000; background-color: #ffffff; border: 0px; }"); - } + if (file_exists(p_image)) { + this->setText(""); + this->setStyleSheet("QPushButton { border-image: url(\"" + p_image + "\") 0 0 0 0 stretch stretch; }" + "QToolTip { color: #000000; background-color: #ffffff; border: 0px; }"); + } + else { + this->setText(p_emote_comment); + this->setStyleSheet("QPushButton { border-image: url(); }" + "QToolTip { background-image: url(); color: #000000; background-color: #ffffff; border: 0px; }"); + } } 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(p_char, "emotions/button" + emotion_number + suffix)); + QString emotion_number = QString::number(p_emote + 1); + QString image_path = ao_app->get_static_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)); + this->set_image(image_path, ao_app->get_emote_comment(p_char, p_emote)); } void AOEmoteButton::on_clicked() { - emote_clicked(m_id); + emote_clicked(m_id); } diff --git a/src/aoevidencebutton.cpp b/src/aoevidencebutton.cpp index 61847f2..596374b 100644 --- a/src/aoevidencebutton.cpp +++ b/src/aoevidencebutton.cpp @@ -4,85 +4,82 @@ AOEvidenceButton::AOEvidenceButton(QWidget *p_parent, AOApplication *p_ao_app, int p_x, int p_y, int p_w, int p_h) : QPushButton(p_parent) { - ao_app = p_ao_app; - m_parent = p_parent; + ao_app = p_ao_app; + m_parent = p_parent; - ui_selected = new AOImage(this, ao_app); - ui_selected->resize(p_w, p_h); -// ui_selected->move(p_x, p_y); - ui_selected->set_image("evidence_selected"); - ui_selected->setAttribute(Qt::WA_TransparentForMouseEvents); - ui_selected->hide(); + ui_selected = new AOImage(this, ao_app); + ui_selected->resize(p_w, p_h); + // ui_selected->move(p_x, p_y); + ui_selected->set_image("evidence_selected"); + ui_selected->setAttribute(Qt::WA_TransparentForMouseEvents); + ui_selected->hide(); - ui_selector = new AOImage(this, ao_app); - ui_selector->resize(p_w, p_h); -// ui_selector->move(p_x - 1, p_y - 1); - ui_selector->set_image("evidence_selector"); - ui_selector->setAttribute(Qt::WA_TransparentForMouseEvents); - ui_selector->hide(); + ui_selector = new AOImage(this, ao_app); + ui_selector->resize(p_w, p_h); + // ui_selector->move(p_x - 1, p_y - 1); + ui_selector->set_image("evidence_selector"); + ui_selector->setAttribute(Qt::WA_TransparentForMouseEvents); + ui_selector->hide(); - this->move(p_x, p_y); - this->resize(p_w, p_h); -// this->setAcceptDrops(true); + this->move(p_x, p_y); + this->resize(p_w, p_h); + // this->setAcceptDrops(true); - connect(this, SIGNAL(clicked()), this, SLOT(on_clicked())); + connect(this, SIGNAL(clicked()), this, SLOT(on_clicked())); } void AOEvidenceButton::set_image(QString p_image) { - QString image_path = ao_app->get_evidence_path(p_image); - if (file_exists(p_image)) - { - this->setText(""); - this->setStyleSheet("QPushButton { border-image: url(\"" + p_image + "\") 0 0 0 0 stretch stretch; }" - "QToolTip { color: #000000; background-color: #ffffff; border: 0px; }"); - } - else if (file_exists(image_path)) - { - this->setText(""); - this->setStyleSheet("QPushButton { border-image: url(\"" + image_path + "\") 0 0 0 0 stretch stretch; }" - "QToolTip { color: #000000; background-color: #ffffff; border: 0px; }"); - } - else - { - this->setText(p_image); - this->setStyleSheet("QPushButton { border-image: url(); }" - "QToolTip { background-image: url(); color: #000000; background-color: #ffffff; border: 0px; }"); - } + QString image_path = ao_app->get_evidence_path(p_image); + if (file_exists(p_image)) { + this->setText(""); + this->setStyleSheet("QPushButton { border-image: url(\"" + p_image + "\") 0 0 0 0 stretch stretch; }" + "QToolTip { color: #000000; background-color: #ffffff; border: 0px; }"); + } + else if (file_exists(image_path)) { + this->setText(""); + this->setStyleSheet("QPushButton { border-image: url(\"" + image_path + "\") 0 0 0 0 stretch stretch; }" + "QToolTip { color: #000000; background-color: #ffffff; border: 0px; }"); + } + else { + this->setText(p_image); + this->setStyleSheet("QPushButton { border-image: url(); }" + "QToolTip { background-image: url(); color: #000000; background-color: #ffffff; border: 0px; }"); + } } 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 theme_image_path = ao_app->get_theme_path(p_image); + QString default_image_path = ao_app->get_default_theme_path(p_image); - QString final_image_path; + QString final_image_path; - if (file_exists(theme_image_path)) - final_image_path = theme_image_path; - else - final_image_path = default_image_path; + if (file_exists(theme_image_path)) + final_image_path = theme_image_path; + else + final_image_path = default_image_path; - this->set_image(final_image_path); + this->set_image(final_image_path); } void AOEvidenceButton::set_selected(bool p_selected) { - if (p_selected) - ui_selected->show(); - else - ui_selected->hide(); + if (p_selected) + ui_selected->show(); + else + ui_selected->hide(); } void AOEvidenceButton::on_clicked() { - evidence_clicked(m_id); + evidence_clicked(m_id); } void AOEvidenceButton::mouseDoubleClickEvent(QMouseEvent *e) { - QPushButton::mouseDoubleClickEvent(e); - evidence_double_clicked(m_id); + QPushButton::mouseDoubleClickEvent(e); + evidence_double_clicked(m_id); } /* @@ -101,20 +98,20 @@ void AOEvidenceButton::dragEnterEvent(QMouseEvent *e) } */ -void AOEvidenceButton::enterEvent(QEvent * e) +void AOEvidenceButton::enterEvent(QEvent *e) { - ui_selector->show(); + ui_selector->show(); - on_hover(m_id, true); + on_hover(m_id, true); - setFlat(false); - QPushButton::enterEvent(e); + setFlat(false); + QPushButton::enterEvent(e); } -void AOEvidenceButton::leaveEvent(QEvent * e) +void AOEvidenceButton::leaveEvent(QEvent *e) { - ui_selector->hide(); + ui_selector->hide(); - on_hover(m_id, false); - QPushButton::leaveEvent(e); + on_hover(m_id, false); + QPushButton::leaveEvent(e); } diff --git a/src/aoevidencedisplay.cpp b/src/aoevidencedisplay.cpp index 904568a..22f5720 100644 --- a/src/aoevidencedisplay.cpp +++ b/src/aoevidencedisplay.cpp @@ -1,77 +1,74 @@ #include "aoevidencedisplay.h" -#include "file_functions.h" #include "datatypes.h" +#include "file_functions.h" #include "misc_functions.h" AOEvidenceDisplay::AOEvidenceDisplay(QWidget *p_parent, AOApplication *p_ao_app) : QLabel(p_parent) { - ao_app = p_ao_app; - evidence_icon = new QLabel(this); - sfx_player = new AOSfxPlayer(this, ao_app); + ao_app = p_ao_app; + evidence_icon = new QLabel(this); + sfx_player = new AOSfxPlayer(this, ao_app); - evidence_movie = new AOMovie(this, ao_app); + evidence_movie = new AOMovie(this, ao_app); - connect(evidence_movie, SIGNAL(done()), this, SLOT(show_done())); + connect(evidence_movie, SIGNAL(done()), this, SLOT(show_done())); } void AOEvidenceDisplay::show_evidence(QString p_evidence_image, bool is_left_side, int p_volume) { - this->reset(); + this->reset(); - sfx_player->set_volume(p_volume); + sfx_player->set_volume(p_volume); - QString final_gif_path; - QString gif_name; - QString icon_identifier; + QString final_gif_path; + QString gif_name; + QString icon_identifier; - if (is_left_side) - { - icon_identifier = "left_evidence_icon"; - gif_name = "evidence_appear_left"; - } - else - { - icon_identifier = "right_evidence_icon"; - gif_name = "evidence_appear_right"; - } + if (is_left_side) { + icon_identifier = "left_evidence_icon"; + gif_name = "evidence_appear_left"; + } + else { + icon_identifier = "right_evidence_icon"; + gif_name = "evidence_appear_right"; + } - QString f_evidence_path = ao_app->get_evidence_path(p_evidence_image); - QPixmap f_pixmap(f_evidence_path); + QString f_evidence_path = ao_app->get_evidence_path(p_evidence_image); + QPixmap f_pixmap(f_evidence_path); - pos_size_type icon_dimensions = ao_app->get_element_dimensions(icon_identifier, "courtroom_design.ini"); + pos_size_type icon_dimensions = ao_app->get_element_dimensions(icon_identifier, "courtroom_design.ini"); - f_pixmap = f_pixmap.scaled(icon_dimensions.width, icon_dimensions.height); - evidence_icon->setPixmap(f_pixmap); - evidence_icon->resize(f_pixmap.size()); - evidence_icon->move(icon_dimensions.x, icon_dimensions.y); + f_pixmap = f_pixmap.scaled(icon_dimensions.width, icon_dimensions.height); + evidence_icon->setPixmap(f_pixmap); + evidence_icon->resize(f_pixmap.size()); + evidence_icon->move(icon_dimensions.x, icon_dimensions.y); - evidence_movie->play(gif_name); - sfx_player->play(ao_app->get_sfx("evidence_present")); + evidence_movie->play(gif_name); + sfx_player->play(ao_app->get_sfx("evidence_present")); } void AOEvidenceDisplay::reset() { - sfx_player->stop(); - evidence_movie->stop(); - evidence_icon->hide(); - this->clear(); + sfx_player->stop(); + evidence_movie->stop(); + evidence_icon->hide(); + this->clear(); } void AOEvidenceDisplay::show_done() { - evidence_icon->show(); + evidence_icon->show(); } -QLabel* AOEvidenceDisplay::get_evidence_icon() +QLabel *AOEvidenceDisplay::get_evidence_icon() { - return evidence_icon; + return evidence_icon; } void AOEvidenceDisplay::combo_resize(int w, int h) { - QSize f_size(w, h); - this->resize(f_size); - evidence_movie->combo_resize(w, h); + QSize f_size(w, h); + this->resize(f_size); + evidence_movie->combo_resize(w, h); } - diff --git a/src/aoimage.cpp b/src/aoimage.cpp index 17c2ea6..e1c01e5 100644 --- a/src/aoimage.cpp +++ b/src/aoimage.cpp @@ -4,49 +4,46 @@ AOImage::AOImage(QWidget *parent, AOApplication *p_ao_app) : QLabel(parent) { - m_parent = parent; - ao_app = p_ao_app; + m_parent = parent; + ao_app = p_ao_app; } AOImage::~AOImage() { - } bool AOImage::set_image(QString p_image) { - 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)); + 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)); - QString final_image_path; + 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; - } + 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); + QPixmap f_pixmap(final_image_path); - this->setPixmap(f_pixmap.scaled(this->width(), this->height(), Qt::IgnoreAspectRatio)); - return true; + this->setPixmap(f_pixmap.scaled(this->width(), this->height(), Qt::IgnoreAspectRatio)); + 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!"; - return false; - } + 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!"; + return false; + } - QPixmap f_pixmap(p_path); + QPixmap f_pixmap(p_path); - this->setPixmap(f_pixmap.scaled(this->width(), this->height(), Qt::IgnoreAspectRatio)); - return true; + this->setPixmap(f_pixmap.scaled(this->width(), this->height(), Qt::IgnoreAspectRatio)); + return true; } diff --git a/src/aolineedit.cpp b/src/aolineedit.cpp index 1c141c3..ce851a0 100644 --- a/src/aolineedit.cpp +++ b/src/aolineedit.cpp @@ -6,15 +6,15 @@ AOLineEdit::AOLineEdit(QWidget *parent) : QLineEdit(parent) void AOLineEdit::mouseDoubleClickEvent(QMouseEvent *e) { - QLineEdit::mouseDoubleClickEvent(e); + QLineEdit::mouseDoubleClickEvent(e); - double_clicked(); + double_clicked(); } void AOLineEdit::focusOutEvent(QFocusEvent *ev) { - int start = selectionStart(); - int len = selectionEnd() - start; //We're not using selectionLength because Linux build doesn't run qt5.10 - QLineEdit::focusOutEvent(ev); - if (p_selection && start != -1 && len != -1) - this->setSelection(start, len); + int start = selectionStart(); + int len = selectionEnd() - start; //We're not using selectionLength because Linux build doesn't run qt5.10 + QLineEdit::focusOutEvent(ev); + if (p_selection && start != -1 && len != -1) + this->setSelection(start, len); } diff --git a/src/aomovie.cpp b/src/aomovie.cpp index 561f5ef..7e3bbae 100644 --- a/src/aomovie.cpp +++ b/src/aomovie.cpp @@ -1,96 +1,93 @@ #include "aomovie.h" -#include "file_functions.h" #include "courtroom.h" +#include "file_functions.h" #include "misc_functions.h" AOMovie::AOMovie(QWidget *p_parent, AOApplication *p_ao_app) : QLabel(p_parent) { - ao_app = p_ao_app; + ao_app = p_ao_app; - m_movie = new QMovie(); + m_movie = new QMovie(); - this->setMovie(m_movie); + this->setMovie(m_movie); - timer = new QTimer(this); - timer->setTimerType(Qt::PreciseTimer); - timer->setSingleShot(true); + timer = new QTimer(this); + timer->setTimerType(Qt::PreciseTimer); + timer->setSingleShot(true); - connect(m_movie, SIGNAL(frameChanged(int)), this, SLOT(frame_change(int))); - connect(timer, SIGNAL(timeout()), this, SLOT(timer_done())); + connect(m_movie, SIGNAL(frameChanged(int)), this, SLOT(frame_change(int))); + connect(timer, SIGNAL(timeout()), this, SLOT(timer_done())); } void AOMovie::set_play_once(bool p_play_once) { - play_once = p_play_once; + play_once = p_play_once; } void AOMovie::play(QString p_image, QString p_char, QString p_custom_theme, int duration) { - m_movie->stop(); + m_movie->stop(); - QString shout_path = p_image; - if (!file_exists(p_image)) - { - QList pathlist; + QString shout_path = p_image; + if (!file_exists(p_image)) { + QList pathlist; - pathlist = { - ao_app->get_image_suffix(ao_app->get_character_path(p_char, p_image)), //Character folder - ao_app->get_image_suffix(ao_app->get_base_path() + "misc/" + p_custom_theme + "/" + p_image), //Misc path - ao_app->get_image_suffix(ao_app->get_custom_theme_path(p_custom_theme, p_image)), //Custom theme path - ao_app->get_image_suffix(ao_app->get_theme_path(p_image)), //Theme path - ao_app->get_image_suffix(ao_app->get_default_theme_path(p_image)), //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 - }; + pathlist = { + ao_app->get_image_suffix(ao_app->get_character_path(p_char, p_image)), //Character folder + ao_app->get_image_suffix(ao_app->get_base_path() + "misc/" + p_custom_theme + "/" + p_image), //Misc path + ao_app->get_image_suffix(ao_app->get_custom_theme_path(p_custom_theme, p_image)), //Custom theme path + ao_app->get_image_suffix(ao_app->get_theme_path(p_image)), //Theme path + ao_app->get_image_suffix(ao_app->get_default_theme_path(p_image)), //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 + }; - for (QString path : pathlist) - { - if (file_exists(path)) - { - shout_path = path; - break; - } + for (QString path : pathlist) { + if (file_exists(path)) { + shout_path = path; + break; + } + } } - } - m_movie->setFileName(shout_path); + m_movie->setFileName(shout_path); - if (m_movie->loopCount() == 0) - play_once = true; + if (m_movie->loopCount() == 0) + play_once = true; - this->show(); - m_movie->start(); - if (m_movie->frameCount() == 0 && duration > 0) - timer->start(duration); + this->show(); + m_movie->start(); + if (m_movie->frameCount() == 0 && duration > 0) + timer->start(duration); } void AOMovie::stop() { - m_movie->stop(); - this->hide(); + m_movie->stop(); + this->hide(); } void AOMovie::frame_change(int n_frame) { - //If it's a "static movie" (only one frame - png image), we can't change frames - ignore this function (use timer instead). - //If the frame didn't reach the last frame or the movie is continuous, don't stop the movie. - if (m_movie->frameCount() == 0 || n_frame < (m_movie->frameCount() - 1) || !play_once) - return; - //we need this or else the last frame wont show - timer->start(m_movie->nextFrameDelay()); + //If it's a "static movie" (only one frame - png image), we can't change frames - ignore this function (use timer instead). + //If the frame didn't reach the last frame or the movie is continuous, don't stop the movie. + if (m_movie->frameCount() == 0 || n_frame < (m_movie->frameCount() - 1) || !play_once) + return; + //we need this or else the last frame wont show + timer->start(m_movie->nextFrameDelay()); } void AOMovie::timer_done() { - this->stop(); - //signal connected to courtroom object, let it figure out what to do - done(); + this->stop(); + //signal connected to courtroom object, let it figure out what to do + done(); } void AOMovie::combo_resize(int w, int h) { - QSize f_size(w, h); - this->resize(f_size); - m_movie->setScaledSize(f_size); + QSize f_size(w, h); + this->resize(f_size); + m_movie->setScaledSize(f_size); } diff --git a/src/aomusicplayer.cpp b/src/aomusicplayer.cpp index 9a96b3e..77222e1 100644 --- a/src/aomusicplayer.cpp +++ b/src/aomusicplayer.cpp @@ -3,108 +3,102 @@ #ifdef BASSAUDIO AOMusicPlayer::AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app) { - m_parent = parent; - ao_app = p_ao_app; + m_parent = parent; + ao_app = p_ao_app; } AOMusicPlayer::~AOMusicPlayer() { - for (int n_stream = 0 ; n_stream < m_channelmax ; ++n_stream) - { - BASS_ChannelStop(m_stream_list[n_stream]); - } + for (int n_stream = 0; n_stream < m_channelmax; ++n_stream) { + BASS_ChannelStop(m_stream_list[n_stream]); + } } void AOMusicPlayer::play(QString p_song, int channel, bool loop, int effect_flags) { - channel = channel % m_channelmax; - if (channel < 0) //wtf? - return; - QString f_path = ao_app->get_music_path(p_song); + channel = channel % m_channelmax; + if (channel < 0) //wtf? + return; + QString f_path = ao_app->get_music_path(p_song); - unsigned int flags = BASS_STREAM_PRESCAN | BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE; - if (loop) - flags |= BASS_SAMPLE_LOOP; + unsigned int flags = BASS_STREAM_PRESCAN | BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE; + if (loop) + flags |= BASS_SAMPLE_LOOP; - DWORD newstream; - if (f_path.endsWith(".opus")) - newstream = BASS_OPUS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, flags); - else - newstream = BASS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, flags); + DWORD newstream; + if (f_path.endsWith(".opus")) + newstream = BASS_OPUS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, flags); + else + newstream = BASS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, flags); - if (ao_app->get_audio_output_device() != "default") - BASS_ChannelSetDevice(m_stream_list[channel], BASS_GetDevice()); + if (ao_app->get_audio_output_device() != "default") + BASS_ChannelSetDevice(m_stream_list[channel], BASS_GetDevice()); - QString d_path = f_path + ".txt"; + QString d_path = f_path + ".txt"; - loop_start = 0; - loop_end = BASS_ChannelGetLength(newstream, BASS_POS_BYTE); - if (loop && file_exists(d_path)) //Contains loop/etc. information file - { - QStringList lines = ao_app->read_file(d_path).split("\n"); - foreach (QString line, lines) + loop_start = 0; + loop_end = BASS_ChannelGetLength(newstream, BASS_POS_BYTE); + if (loop && file_exists(d_path)) //Contains loop/etc. information file { - QStringList args = line.split("="); - if (args.size() < 2) - continue; - QString arg = args[0].trimmed(); + QStringList lines = ao_app->read_file(d_path).split("\n"); + foreach (QString line, lines) { + QStringList args = line.split("="); + if (args.size() < 2) + continue; + QString arg = args[0].trimmed(); - float sample_rate; - BASS_ChannelGetAttribute(newstream, BASS_ATTRIB_FREQ, &sample_rate); + float sample_rate; + BASS_ChannelGetAttribute(newstream, BASS_ATTRIB_FREQ, &sample_rate); - //Grab number of bytes for sample size - int sample_size = 16/8; + //Grab number of bytes for sample size + int sample_size = 16 / 8; - //number of channels (stereo/mono) - int num_channels = 2; + //number of channels (stereo/mono) + int num_channels = 2; - //Calculate the bytes for loop_start/loop_end to use with the sync proc - QWORD bytes = static_cast(args[1].trimmed().toFloat() * sample_size * num_channels); - if (arg == "loop_start") - loop_start = bytes; - else if (arg == "loop_length") - loop_end = loop_start + bytes; - else if (arg == "loop_end") - loop_end = bytes; - } - qDebug() << "Found data file for song" << p_song << "length" << BASS_ChannelGetLength(newstream, BASS_POS_BYTE) << "loop start" << loop_start << "loop end" << loop_end; - } - - if (BASS_ChannelIsActive(m_stream_list[channel]) == BASS_ACTIVE_PLAYING) - { - DWORD oldstream = m_stream_list[channel]; - - if (effect_flags & SYNC_POS) - { - BASS_ChannelLock(oldstream, true); - //Sync it with the new sample - BASS_ChannelSetPosition(newstream, BASS_ChannelGetPosition(oldstream, BASS_POS_BYTE), BASS_POS_BYTE); - BASS_ChannelLock(oldstream, false); + //Calculate the bytes for loop_start/loop_end to use with the sync proc + QWORD bytes = static_cast(args[1].trimmed().toFloat() * sample_size * num_channels); + if (arg == "loop_start") + loop_start = bytes; + else if (arg == "loop_length") + loop_end = loop_start + bytes; + else if (arg == "loop_end") + loop_end = bytes; + } + qDebug() << "Found data file for song" << p_song << "length" << BASS_ChannelGetLength(newstream, BASS_POS_BYTE) << "loop start" << loop_start << "loop end" << loop_end; } - if (effect_flags & FADE_OUT) - { - //Fade out the other sample and stop it (due to -1) - BASS_ChannelSlideAttribute(oldstream, BASS_ATTRIB_VOL|BASS_SLIDE_LOG, -1, 4000); + if (BASS_ChannelIsActive(m_stream_list[channel]) == BASS_ACTIVE_PLAYING) { + DWORD oldstream = m_stream_list[channel]; + + if (effect_flags & SYNC_POS) { + BASS_ChannelLock(oldstream, true); + //Sync it with the new sample + BASS_ChannelSetPosition(newstream, BASS_ChannelGetPosition(oldstream, BASS_POS_BYTE), BASS_POS_BYTE); + BASS_ChannelLock(oldstream, false); + } + + if (effect_flags & FADE_OUT) { + //Fade out the other sample and stop it (due to -1) + BASS_ChannelSlideAttribute(oldstream, BASS_ATTRIB_VOL | BASS_SLIDE_LOG, -1, 4000); + } + else + BASS_ChannelStop(oldstream); //Stop the sample since we don't need it anymore } else - BASS_ChannelStop(oldstream); //Stop the sample since we don't need it anymore - } - else - BASS_ChannelStop(m_stream_list[channel]); + BASS_ChannelStop(m_stream_list[channel]); - m_stream_list[channel] = newstream; - BASS_ChannelPlay(m_stream_list[channel], false); - if (effect_flags & FADE_IN) - { - //Fade in our sample - BASS_ChannelSetAttribute(newstream, BASS_ATTRIB_VOL, 0); - BASS_ChannelSlideAttribute(newstream, BASS_ATTRIB_VOL, static_cast(m_volume[channel] / 100.0f), 1000); - } - else - this->set_volume(m_volume[channel], channel); + m_stream_list[channel] = newstream; + BASS_ChannelPlay(m_stream_list[channel], false); + if (effect_flags & FADE_IN) { + //Fade in our sample + BASS_ChannelSetAttribute(newstream, BASS_ATTRIB_VOL, 0); + BASS_ChannelSlideAttribute(newstream, BASS_ATTRIB_VOL, static_cast(m_volume[channel] / 100.0f), 1000); + } + else + this->set_volume(m_volume[channel], channel); - this->set_looping(loop); //Have to do this here due to any crossfading-related changes, etc. + this->set_looping(loop); //Have to do this here due to any crossfading-related changes, etc. } void AOMusicPlayer::stop(int channel) @@ -114,105 +108,95 @@ void AOMusicPlayer::stop(int channel) void AOMusicPlayer::set_volume(int p_value, int channel) { - m_volume[channel] = p_value; - float volume = m_volume[channel] / 100.0f; - if (channel < 0) - { - for (int n_stream = 0 ; n_stream < m_channelmax ; ++n_stream) - { - BASS_ChannelSetAttribute(m_stream_list[n_stream], BASS_ATTRIB_VOL, volume); + m_volume[channel] = p_value; + float volume = m_volume[channel] / 100.0f; + if (channel < 0) { + for (int n_stream = 0; n_stream < m_channelmax; ++n_stream) { + BASS_ChannelSetAttribute(m_stream_list[n_stream], BASS_ATTRIB_VOL, volume); + } + } + else { + BASS_ChannelSetAttribute(m_stream_list[channel], BASS_ATTRIB_VOL, volume); } - } - else - { - BASS_ChannelSetAttribute(m_stream_list[channel], BASS_ATTRIB_VOL, volume); - } } void CALLBACK loopProc(HSYNC handle, DWORD channel, DWORD data, void *user) { - QWORD loop_start = *(static_cast(user)); - BASS_ChannelLock(channel, true); - BASS_ChannelSetPosition(channel, loop_start, BASS_POS_BYTE); - BASS_ChannelLock(channel, false); + QWORD loop_start = *(static_cast(user)); + BASS_ChannelLock(channel, true); + BASS_ChannelSetPosition(channel, loop_start, BASS_POS_BYTE); + BASS_ChannelLock(channel, false); } void AOMusicPlayer::set_looping(bool toggle, int channel) { - m_looping = toggle; - if (!m_looping) - { - if (BASS_ChannelFlags(m_stream_list[channel], 0, 0) & BASS_SAMPLE_LOOP) - BASS_ChannelFlags(m_stream_list[channel], 0, BASS_SAMPLE_LOOP); // remove the LOOP flag - BASS_ChannelRemoveSync(m_stream_list[channel], loop_sync[channel]); - loop_sync[channel] = 0; - } - else - { - BASS_ChannelFlags(m_stream_list[channel], BASS_SAMPLE_LOOP, BASS_SAMPLE_LOOP); // set the LOOP flag - if (loop_sync[channel] != 0) - { - BASS_ChannelRemoveSync(m_stream_list[channel], loop_sync[channel]); //remove the sync - loop_sync[channel] = 0; + m_looping = toggle; + if (!m_looping) { + if (BASS_ChannelFlags(m_stream_list[channel], 0, 0) & BASS_SAMPLE_LOOP) + BASS_ChannelFlags(m_stream_list[channel], 0, BASS_SAMPLE_LOOP); // remove the LOOP flag + BASS_ChannelRemoveSync(m_stream_list[channel], loop_sync[channel]); + loop_sync[channel] = 0; } - if (loop_start > 0) - { - if (loop_end == 0) - loop_end = BASS_ChannelGetLength(m_stream_list[channel], BASS_POS_BYTE); - if (loop_end > 0) //Don't loop zero length songs even if we're asked to - loop_sync[channel] = BASS_ChannelSetSync(m_stream_list[channel], BASS_SYNC_POS | BASS_SYNC_MIXTIME, loop_end, loopProc, &loop_start); + else { + BASS_ChannelFlags(m_stream_list[channel], BASS_SAMPLE_LOOP, BASS_SAMPLE_LOOP); // set the LOOP flag + if (loop_sync[channel] != 0) { + BASS_ChannelRemoveSync(m_stream_list[channel], loop_sync[channel]); //remove the sync + loop_sync[channel] = 0; + } + if (loop_start > 0) { + if (loop_end == 0) + loop_end = BASS_ChannelGetLength(m_stream_list[channel], BASS_POS_BYTE); + if (loop_end > 0) //Don't loop zero length songs even if we're asked to + loop_sync[channel] = BASS_ChannelSetSync(m_stream_list[channel], BASS_SYNC_POS | BASS_SYNC_MIXTIME, loop_end, loopProc, &loop_start); + } } - } } #elif defined(QTAUDIO) AOMusicPlayer::AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app) { - m_parent = parent; - ao_app = p_ao_app; + m_parent = parent; + ao_app = p_ao_app; } AOMusicPlayer::~AOMusicPlayer() { - m_player.stop(); + m_player.stop(); } void AOMusicPlayer::play(QString p_song) { - m_player.stop(); + m_player.stop(); - QString f_path = ao_app->get_music_path(p_song); + QString f_path = ao_app->get_music_path(p_song); - m_player.setMedia(QUrl::fromLocalFile(f_path)); + m_player.setMedia(QUrl::fromLocalFile(f_path)); - this->set_volume(m_volume); + this->set_volume(m_volume); - m_player.play(); + m_player.play(); } void AOMusicPlayer::set_volume(int p_value) { - m_volume = p_value; - m_player.setVolume(m_volume); + m_volume = p_value; + m_player.setVolume(m_volume); } #else AOMusicPlayer::AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app) { - m_parent = parent; - ao_app = p_ao_app; + m_parent = parent; + ao_app = p_ao_app; } AOMusicPlayer::~AOMusicPlayer() { - } void AOMusicPlayer::play(QString p_song) { - } void AOMusicPlayer::set_volume(int p_value) { - } #endif diff --git a/src/aooptionsdialog.cpp b/src/aooptionsdialog.cpp index cfaaa20..06df7a5 100644 --- a/src/aooptionsdialog.cpp +++ b/src/aooptionsdialog.cpp @@ -43,8 +43,8 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi ui_form_layout_widget->setSizePolicy(sizePolicy1); ui_gameplay_form = new QFormLayout(ui_form_layout_widget); - ui_gameplay_form->setLabelAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter); - ui_gameplay_form->setFormAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop); + ui_gameplay_form->setLabelAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignVCenter); + ui_gameplay_form->setFormAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignTop); ui_gameplay_form->setContentsMargins(0, 0, 0, 0); ui_gameplay_form->setSpacing(2); @@ -61,13 +61,12 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi // Fill the combobox with the names of the themes. QDirIterator it(p_ao_app->get_base_path() + "themes", QDir::Dirs, QDirIterator::NoIteratorFlags); - while (it.hasNext()) - { + while (it.hasNext()) { QString actualname = QDir(it.next()).dirName(); if (actualname != "." && actualname != "..") ui_theme_combobox->addItem(actualname); if (actualname == p_ao_app->read_theme()) - ui_theme_combobox->setCurrentIndex(ui_theme_combobox->count()-1); + ui_theme_combobox->setCurrentIndex(ui_theme_combobox->count() - 1); } ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_theme_combobox); @@ -158,7 +157,7 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_ms_lbl); - QSettings* configini = ao_app->configini; + QSettings *configini = ao_app->configini; ui_ms_textbox = new QLineEdit(ui_form_layout_widget); ui_ms_textbox->setText(configini->value("master", "").value()); @@ -292,7 +291,7 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi ui_callwords_widget->setGeometry(QRect(10, 10, 361, 211)); ui_callwords_layout = new QVBoxLayout(ui_callwords_widget); - ui_callwords_layout->setContentsMargins(0,0,0,0); + ui_callwords_layout->setContentsMargins(0, 0, 0, 0); ui_callwords_textbox = new QPlainTextEdit(ui_callwords_widget); QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); @@ -323,8 +322,8 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi ui_audio_widget->setGeometry(QRect(10, 10, 361, 211)); ui_audio_layout = new QFormLayout(ui_audio_widget); - ui_audio_layout->setLabelAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter); - ui_audio_layout->setFormAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop); + ui_audio_layout->setLabelAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignVCenter); + ui_audio_layout->setFormAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignTop); ui_audio_layout->setContentsMargins(0, 0, 0, 0); row = 0; @@ -338,28 +337,24 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi // Let's fill out the combobox with the available audio devices. Or don't if there is no audio int a = 0; - if (needs_default_audiodev()) - { + if (needs_default_audiodev()) { ui_audio_device_combobox->addItem("default"); - } - #ifdef BASSAUDIO +#ifdef BASSAUDIO BASS_DEVICEINFO info; - for (a = 0; BASS_GetDeviceInfo(a, &info); a++) - { + for (a = 0; BASS_GetDeviceInfo(a, &info); a++) { ui_audio_device_combobox->addItem(info.name); if (p_ao_app->get_audio_output_device() == info.name) - ui_audio_device_combobox->setCurrentIndex(ui_audio_device_combobox->count()-1); + ui_audio_device_combobox->setCurrentIndex(ui_audio_device_combobox->count() - 1); } - #elif defined QTAUDIO - foreach (const QAudioDeviceInfo &deviceInfo, QAudioDeviceInfo::availableDevices(QAudio::AudioOutput)) - { +#elif defined QTAUDIO + foreach (const QAudioDeviceInfo &deviceInfo, QAudioDeviceInfo::availableDevices(QAudio::AudioOutput)) { ui_audio_device_combobox->addItem(deviceInfo.deviceName()); if (p_ao_app->get_audio_output_device() == deviceInfo.deviceName()) - ui_audio_device_combobox->setCurrentIndex(ui_audio_device_combobox->count()-1); + ui_audio_device_combobox->setCurrentIndex(ui_audio_device_combobox->count() - 1); } - #endif +#endif ui_audio_layout->setWidget(row, QFormLayout::FieldRole, ui_audio_device_combobox); row += 1; @@ -429,7 +424,7 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi ui_bliprate_spinbox->setValue(p_ao_app->read_blip_rate()); ui_bliprate_spinbox->setMinimum(1); ui_bliprate_spinbox->setToolTip(tr("Play a blip sound \"once per every X symbols\", where " - "X is the blip rate.")); + "X is the blip rate.")); ui_audio_layout->setWidget(row, QFormLayout::FieldRole, ui_bliprate_spinbox); @@ -475,11 +470,11 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi ui_settings_tabs->addTab(ui_casing_tab, tr("Casing")); ui_casing_widget = new QWidget(ui_casing_tab); - ui_casing_widget->setGeometry(QRect(10,10, 361, 211)); + ui_casing_widget->setGeometry(QRect(10, 10, 361, 211)); ui_casing_layout = new QFormLayout(ui_casing_widget); - ui_casing_layout->setLabelAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter); - ui_casing_layout->setFormAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop); + ui_casing_layout->setLabelAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignVCenter); + ui_casing_layout->setFormAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignTop); ui_casing_layout->setContentsMargins(0, 0, 0, 0); row = 0; @@ -487,9 +482,9 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi ui_casing_supported_lbl = new QLabel(ui_casing_widget); if (ao_app->casing_alerts_enabled) - ui_casing_supported_lbl->setText(tr("This server supports case alerts.")); + ui_casing_supported_lbl->setText(tr("This server supports case alerts.")); else - ui_casing_supported_lbl->setText(tr("This server does not support case alerts.")); + ui_casing_supported_lbl->setText(tr("This server does not support case alerts.")); ui_casing_supported_lbl->setToolTip(tr("Pretty self-explanatory.")); ui_casing_layout->setWidget(row, QFormLayout::FieldRole, ui_casing_supported_lbl); @@ -621,7 +616,7 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi void AOOptionsDialog::save_pressed() { // Save everything into the config.ini. - QSettings* configini = ao_app->configini; + QSettings *configini = ao_app->configini; configini->setValue("theme", ui_theme_combobox->currentText()); configini->setValue("log_goes_downwards", ui_downwards_cb->isChecked()); @@ -639,11 +634,9 @@ void AOOptionsDialog::save_pressed() configini->setValue("stickyeffects", ui_stickyeffects_cb->isChecked()); configini->setValue("stickypres", ui_stickypres_cb->isChecked()); + QFile *callwordsini = new QFile(ao_app->get_base_path() + "callwords.ini"); - QFile* callwordsini = new QFile(ao_app->get_base_path() + "callwords.ini"); - - if (callwordsini->open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) - { + if (callwordsini->open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) { QTextStream out(callwordsini); out << ui_callwords_textbox->toPlainText(); callwordsini->close(); @@ -676,12 +669,12 @@ void AOOptionsDialog::discard_pressed() done(0); } -#if (defined (_WIN32) || defined (_WIN64)) +#if (defined(_WIN32) || defined(_WIN64)) bool AOOptionsDialog::needs_default_audiodev() { return true; } -#elif (defined (LINUX) || defined (__linux__)) +#elif (defined(LINUX) || defined(__linux__)) bool AOOptionsDialog::needs_default_audiodev() { return false; diff --git a/src/aopacket.cpp b/src/aopacket.cpp index b957efe..457cc65 100644 --- a/src/aopacket.cpp +++ b/src/aopacket.cpp @@ -4,80 +4,73 @@ AOPacket::AOPacket(QString p_packet_string) { - QStringList packet_contents = p_packet_string.split("#"); + QStringList packet_contents = p_packet_string.split("#"); - m_header = packet_contents.at(0); + m_header = packet_contents.at(0); - for(int n_string = 1 ; n_string < packet_contents.size() - 1 ; ++n_string) - { - m_contents.append(packet_contents.at(n_string)); - } + for (int n_string = 1; n_string < packet_contents.size() - 1; ++n_string) { + m_contents.append(packet_contents.at(n_string)); + } } AOPacket::AOPacket(QString p_header, QStringList &p_contents) { - m_header = p_header; - m_contents = p_contents; + m_header = p_header; + m_contents = p_contents; } AOPacket::~AOPacket() { - } QString AOPacket::to_string() { - QString f_string = m_header; + QString f_string = m_header; - for (QString i_string : m_contents) - { - f_string += ("#" + i_string); - } + for (QString i_string : m_contents) { + f_string += ("#" + i_string); + } - f_string += "#%"; + f_string += "#%"; - - if (encrypted) - return "#" + f_string; - else - return f_string; + if (encrypted) + return "#" + f_string; + else + return f_string; } void AOPacket::encrypt_header(unsigned int p_key) { - m_header = fanta_encrypt(m_header, p_key); + m_header = fanta_encrypt(m_header, p_key); - encrypted = true; + encrypted = true; } void AOPacket::decrypt_header(unsigned int p_key) { - m_header = fanta_decrypt(m_header, p_key); + m_header = fanta_decrypt(m_header, p_key); - encrypted = false; + encrypted = false; } void AOPacket::net_encode() { - for (int n_element = 0 ; n_element < m_contents.size() ; ++n_element) - { - QString f_element = m_contents.at(n_element); - f_element.replace("#", "").replace("%", "").replace("$", "").replace("&", ""); + for (int n_element = 0; n_element < m_contents.size(); ++n_element) { + QString f_element = m_contents.at(n_element); + f_element.replace("#", "").replace("%", "").replace("$", "").replace("&", ""); - m_contents.removeAt(n_element); - m_contents.insert(n_element, f_element); - } + m_contents.removeAt(n_element); + m_contents.insert(n_element, f_element); + } } void AOPacket::net_decode() { - for (int n_element = 0 ; n_element < m_contents.size() ; ++n_element) - { - QString f_element = m_contents.at(n_element); - f_element.replace("", "#").replace("", "%").replace("", "$").replace("", "&"); + for (int n_element = 0; n_element < m_contents.size(); ++n_element) { + QString f_element = m_contents.at(n_element); + f_element.replace("", "#").replace("", "%").replace("", "$").replace("", "&"); - m_contents.removeAt(n_element); - m_contents.insert(n_element, f_element); - } + m_contents.removeAt(n_element); + m_contents.insert(n_element, f_element); + } } - diff --git a/src/aoscene.cpp b/src/aoscene.cpp index 575a27d..64f741a 100644 --- a/src/aoscene.cpp +++ b/src/aoscene.cpp @@ -4,123 +4,119 @@ AOScene::AOScene(QWidget *parent, AOApplication *p_ao_app) : QLabel(parent) { - m_parent = parent; - ao_app = p_ao_app; - m_movie = new QMovie(this); - last_image = ""; + m_parent = parent; + ao_app = p_ao_app; + m_movie = new QMovie(this); + last_image = ""; } void AOScene::set_image(QString p_image) { - QString background_path = ao_app->get_image_suffix(ao_app->get_background_path(p_image)); - if (!file_exists(background_path)) //If image is missing, clear current image - { + QString background_path = ao_app->get_image_suffix(ao_app->get_background_path(p_image)); + if (!file_exists(background_path)) //If image is missing, clear current image + { + this->clear(); + this->setMovie(nullptr); + + m_movie->stop(); + last_image = ""; + return; + } + + if (file_exists(background_path) && background_path == last_image) + return; + this->clear(); this->setMovie(nullptr); m_movie->stop(); - last_image = ""; - return; - } + m_movie->setFileName(background_path); - if (file_exists(background_path) && background_path == last_image) - return; + if (m_movie->isValid() && m_movie->frameCount() > 1) { + m_movie->jumpToNextFrame(); + float scale_factor = static_cast(f_h) / static_cast(m_movie->frameRect().height()); + //preserve aspect ratio + int n_w = static_cast(m_movie->frameRect().width() * scale_factor); + int n_h = static_cast(m_movie->frameRect().height() * scale_factor); - this->clear(); - this->setMovie(nullptr); + m_movie->setScaledSize(QSize(n_w, n_h)); + this->resize(m_movie->scaledSize()); + this->setMovie(m_movie); + QLabel::move(x + (f_w - n_w) / 2, y + (f_h - n_h) / 2); //Center + m_movie->start(); + } + else { + QPixmap background(background_path); + auto transform_mode = Qt::FastTransformation; + if (background.height() > f_h) //We are downscaling, use anti-aliasing. + transform_mode = Qt::SmoothTransformation; - m_movie->stop(); - m_movie->setFileName(background_path); - - if (m_movie->isValid() && m_movie->frameCount() > 1) - { - m_movie->jumpToNextFrame(); - float scale_factor = static_cast(f_h) / static_cast(m_movie->frameRect().height()); - //preserve aspect ratio - int n_w = static_cast(m_movie->frameRect().width() * scale_factor); - int n_h = static_cast(m_movie->frameRect().height() * scale_factor); - - m_movie->setScaledSize(QSize(n_w, n_h)); - this->resize(m_movie->scaledSize()); - this->setMovie(m_movie); - QLabel::move(x + (f_w - n_w)/2, y + (f_h - n_h)/2); //Center - m_movie->start(); - } - else - { - QPixmap background(background_path); - auto transform_mode = Qt::FastTransformation; - if (background.height() > f_h) //We are downscaling, use anti-aliasing. - transform_mode = Qt::SmoothTransformation; - - background = background.scaledToHeight(f_h, transform_mode); - this->resize(background.size()); - this->setPixmap(background); - QLabel::move(x + (f_w - background.width())/2, y + (f_h - background.height())/2); //Always center horizontally, always center vertically - } - last_image = background_path; + background = background.scaledToHeight(f_h, transform_mode); + this->resize(background.size()); + this->setPixmap(background); + QLabel::move(x + (f_w - background.width()) / 2, y + (f_h - background.height()) / 2); //Always center horizontally, always center vertically + } + last_image = background_path; } void AOScene::set_legacy_desk(QString p_image) { - QString desk_path = ao_app->get_image_suffix(ao_app->get_background_path(p_image)); - if (!file_exists(desk_path)) //If image is missing, clear current image - { + QString desk_path = ao_app->get_image_suffix(ao_app->get_background_path(p_image)); + if (!file_exists(desk_path)) //If image is missing, clear current image + { + this->clear(); + this->setMovie(nullptr); + + m_movie->stop(); + last_image = ""; + return; + } + + if (file_exists(desk_path) && desk_path == last_image) + return; + + QPixmap f_desk(desk_path); + + //vanilla desks vary in both width and height. in order to make that work with viewport rescaling, + //some INTENSE math is needed. + int vp_width = m_parent->width(); + int vp_height = m_parent->height(); + + double h_modifier = vp_height / 192; + + int final_h = static_cast(h_modifier * f_desk.height()); + this->clear(); this->setMovie(nullptr); m_movie->stop(); - last_image = ""; - return; - } + m_movie->setFileName(desk_path); - if (file_exists(desk_path) && desk_path == last_image) - return; + m_movie->setScaledSize(QSize(vp_width, final_h)); - QPixmap f_desk(desk_path); - - //vanilla desks vary in both width and height. in order to make that work with viewport rescaling, - //some INTENSE math is needed. - int vp_width = m_parent->width(); - int vp_height = m_parent->height(); - - double h_modifier = vp_height / 192; - - int final_h = static_cast(h_modifier * f_desk.height()); - - this->clear(); - this->setMovie(nullptr); - - m_movie->stop(); - m_movie->setFileName(desk_path); - - m_movie->setScaledSize(QSize(vp_width, final_h)); - - if (m_movie->isValid() && m_movie->frameCount() > 1) - { - this->setMovie(m_movie); - m_movie->start(); - } - else - { - this->resize(vp_width, final_h); - this->setPixmap(f_desk.scaled(vp_width, final_h)); - } - last_image = desk_path; + if (m_movie->isValid() && m_movie->frameCount() > 1) { + this->setMovie(m_movie); + m_movie->start(); + } + else { + this->resize(vp_width, final_h); + this->setPixmap(f_desk.scaled(vp_width, final_h)); + } + last_image = desk_path; } void AOScene::combo_resize(int w, int h) { - QSize f_size(w, h); - f_w = w; - f_h = h; - this->resize(f_size); + QSize f_size(w, h); + f_w = w; + f_h = h; + this->resize(f_size); } void AOScene::move(int ax, int ay) { - x = ax; - y = ay; - QLabel::move(x, y); + x = ax; + y = ay; + QLabel::move(x, y); } diff --git a/src/aosfxplayer.cpp b/src/aosfxplayer.cpp index 9fa3026..4b375a4 100644 --- a/src/aosfxplayer.cpp +++ b/src/aosfxplayer.cpp @@ -4,190 +4,178 @@ #if defined(BASSAUDIO) //Using bass.dll for sfx AOSfxPlayer::AOSfxPlayer(QWidget *parent, AOApplication *p_ao_app) { - m_parent = parent; - ao_app = p_ao_app; + m_parent = parent; + ao_app = p_ao_app; } void AOSfxPlayer::clear() { - for (int n_stream = 0 ; n_stream < m_channelmax ; ++n_stream) - { - BASS_ChannelStop(m_stream_list[n_stream]); - } - set_volume_internal(m_volume); + for (int n_stream = 0; n_stream < m_channelmax; ++n_stream) { + BASS_ChannelStop(m_stream_list[n_stream]); + } + set_volume_internal(m_volume); } void AOSfxPlayer::loop_clear() { - for (int n_stream = 0 ; n_stream < m_channelmax ; ++n_stream) - { - if((BASS_ChannelFlags(m_stream_list[n_stream], 0, 0)&BASS_SAMPLE_LOOP)) - BASS_ChannelStop(m_stream_list[n_stream]); - } - set_volume_internal(m_volume); + for (int n_stream = 0; n_stream < m_channelmax; ++n_stream) { + if ((BASS_ChannelFlags(m_stream_list[n_stream], 0, 0) & BASS_SAMPLE_LOOP)) + BASS_ChannelStop(m_stream_list[n_stream]); + } + set_volume_internal(m_volume); } void AOSfxPlayer::play(QString p_sfx, QString p_char, QString shout, int channel) { - if (channel == -1) - { - if (BASS_ChannelIsActive(m_stream_list[channel]) == BASS_ACTIVE_PLAYING) - m_channel = (m_channel + 1) % m_channelmax; - channel = m_channel; - } + if (channel == -1) { + if (BASS_ChannelIsActive(m_stream_list[channel]) == BASS_ACTIVE_PLAYING) + m_channel = (m_channel + 1) % m_channelmax; + channel = m_channel; + } - BASS_ChannelStop(m_stream_list[channel]); - - QString misc_path = ""; - QString char_path = ""; - QString sound_path = ao_app->get_sfx_suffix(ao_app->get_sounds_path(p_sfx)); + BASS_ChannelStop(m_stream_list[channel]); - if (shout != "") - misc_path = ao_app->get_sfx_suffix(ao_app->get_base_path() + "misc/" + shout + "/" + p_sfx); - if (p_char != "") - char_path = ao_app->get_sfx_suffix(ao_app->get_character_path(p_char, p_sfx)); + QString misc_path = ""; + QString char_path = ""; + QString sound_path = ao_app->get_sfx_suffix(ao_app->get_sounds_path(p_sfx)); - QString f_path; + if (shout != "") + misc_path = ao_app->get_sfx_suffix(ao_app->get_base_path() + "misc/" + shout + "/" + p_sfx); + if (p_char != "") + char_path = ao_app->get_sfx_suffix(ao_app->get_character_path(p_char, p_sfx)); - if (file_exists(char_path)) - f_path = char_path; - else if (file_exists(misc_path)) - f_path = misc_path; - else - f_path = sound_path; + QString f_path; - if (f_path.endsWith(".opus")) - m_stream_list[channel] = BASS_OPUS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE); - else - m_stream_list[channel] = BASS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE); + if (file_exists(char_path)) + f_path = char_path; + else if (file_exists(misc_path)) + f_path = misc_path; + else + f_path = sound_path; - set_volume_internal(m_volume); + if (f_path.endsWith(".opus")) + m_stream_list[channel] = BASS_OPUS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE); + else + m_stream_list[channel] = BASS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE); - if (ao_app->get_audio_output_device() != "default") - BASS_ChannelSetDevice(m_stream_list[m_channel], BASS_GetDevice()); - BASS_ChannelPlay(m_stream_list[m_channel], false); + set_volume_internal(m_volume); + + if (ao_app->get_audio_output_device() != "default") + BASS_ChannelSetDevice(m_stream_list[m_channel], BASS_GetDevice()); + BASS_ChannelPlay(m_stream_list[m_channel], false); } void AOSfxPlayer::stop(int channel) { - if (channel == -1) - { - channel = m_channel; - } - BASS_ChannelStop(m_stream_list[channel]); + if (channel == -1) { + channel = m_channel; + } + BASS_ChannelStop(m_stream_list[channel]); } void AOSfxPlayer::set_volume(qreal p_value) { - m_volume = p_value / 100; - set_volume_internal(m_volume); + m_volume = p_value / 100; + set_volume_internal(m_volume); } void AOSfxPlayer::set_volume_internal(qreal p_value) { float volume = static_cast(p_value); - for (int n_stream = 0 ; n_stream < m_channelmax ; ++n_stream) - { - BASS_ChannelSetAttribute(m_stream_list[n_stream], BASS_ATTRIB_VOL, volume); + for (int n_stream = 0; n_stream < m_channelmax; ++n_stream) { + BASS_ChannelSetAttribute(m_stream_list[n_stream], BASS_ATTRIB_VOL, volume); } } void AOSfxPlayer::set_looping(bool toggle, int channel) { - if (channel == -1) - { - channel = m_channel; - } - m_looping = toggle; - if (BASS_ChannelFlags(m_stream_list[channel], 0, 0) & BASS_SAMPLE_LOOP) - { - if (m_looping == false) - BASS_ChannelFlags(m_stream_list[channel], 0, BASS_SAMPLE_LOOP); // remove the LOOP flag - } - else - { - if (m_looping == true) - BASS_ChannelFlags(m_stream_list[channel], BASS_SAMPLE_LOOP, BASS_SAMPLE_LOOP); // set the LOOP flag - } + if (channel == -1) { + channel = m_channel; + } + m_looping = toggle; + if (BASS_ChannelFlags(m_stream_list[channel], 0, 0) & BASS_SAMPLE_LOOP) { + if (m_looping == false) + BASS_ChannelFlags(m_stream_list[channel], 0, BASS_SAMPLE_LOOP); // remove the LOOP flag + } + else { + if (m_looping == true) + BASS_ChannelFlags(m_stream_list[channel], BASS_SAMPLE_LOOP, BASS_SAMPLE_LOOP); // set the LOOP flag + } } #elif defined(QTAUDIO) //Using Qt's QSoundEffect class AOSfxPlayer::AOSfxPlayer(QWidget *parent, AOApplication *p_ao_app) { - m_parent = parent; - ao_app = p_ao_app; + m_parent = parent; + ao_app = p_ao_app; } void AOSfxPlayer::play(QString p_sfx, QString p_char, QString shout) { - m_sfx.stop(); + m_sfx.stop(); - QString misc_path = ""; - QString char_path = ""; - QString sound_path = ao_app->get_sounds_path(p_sfx); + QString misc_path = ""; + QString char_path = ""; + QString sound_path = ao_app->get_sounds_path(p_sfx); - if (shout != "") - misc_path = ao_app->get_base_path() + "misc/" + shout + "/" + p_sfx; - if (p_char != "") - char_path = ao_app->get_character_path(p_char, p_sfx); + if (shout != "") + misc_path = ao_app->get_base_path() + "misc/" + shout + "/" + p_sfx; + if (p_char != "") + char_path = ao_app->get_character_path(p_char, p_sfx); - QString f_path; + QString f_path; - if (file_exists(char_path)) - f_path = char_path; - else if (file_exists(misc_path)) - f_path = misc_path; - else - f_path = sound_path; + if (file_exists(char_path)) + f_path = char_path; + else if (file_exists(misc_path)) + f_path = misc_path; + else + f_path = sound_path; - if (file_exists(f_path)) //if its missing, it will glitch out - { - m_sfx.setSource(QUrl::fromLocalFile(f_path)); + if (file_exists(f_path)) //if its missing, it will glitch out + { + m_sfx.setSource(QUrl::fromLocalFile(f_path)); - set_volume_internal(m_volume); + set_volume_internal(m_volume); - m_sfx.play(); - } + m_sfx.play(); + } } void AOSfxPlayer::stop() { - m_sfx.stop(); + m_sfx.stop(); } void AOSfxPlayer::set_volume(qreal p_value) { - m_volume = p_value/100; - set_volume_internal(m_volume); + m_volume = p_value / 100; + set_volume_internal(m_volume); } void AOSfxPlayer::set_volume_internal(qreal p_value) { - m_sfx.setVolume(m_volume); + m_sfx.setVolume(m_volume); } #else AOSfxPlayer::AOSfxPlayer(QWidget *parent, AOApplication *p_ao_app) { - m_parent = parent; - ao_app = p_ao_app; + m_parent = parent; + ao_app = p_ao_app; } void AOSfxPlayer::play(QString p_sfx, QString p_char, QString shout) { - } void AOSfxPlayer::stop() { - } void AOSfxPlayer::set_volume(qreal p_value) { - } void AOSfxPlayer::set_volume_internal(qreal p_value) { - } #endif diff --git a/src/aotextarea.cpp b/src/aotextarea.cpp index a34bb1a..524f328 100644 --- a/src/aotextarea.cpp +++ b/src/aotextarea.cpp @@ -2,65 +2,62 @@ AOTextArea::AOTextArea(QWidget *p_parent) : QTextBrowser(p_parent) { - } void AOTextArea::append_linked(QString p_message) { - QString result = p_message.toHtmlEscaped().replace("\n", "
").replace(url_parser_regex, "
\\1" ); - this->insertHtml(result); + QString result = p_message.toHtmlEscaped().replace("\n", "
").replace(url_parser_regex, "\\1"); + this->insertHtml(result); } void AOTextArea::append_chatmessage(QString p_name, QString p_message, QString p_colour) { - const QTextCursor old_cursor = this->textCursor(); - const int old_scrollbar_value = this->verticalScrollBar()->value(); - const bool is_scrolled_down = old_scrollbar_value == this->verticalScrollBar()->maximum(); + const QTextCursor old_cursor = this->textCursor(); + const int old_scrollbar_value = this->verticalScrollBar()->value(); + const bool is_scrolled_down = old_scrollbar_value == this->verticalScrollBar()->maximum(); - this->moveCursor(QTextCursor::End); + this->moveCursor(QTextCursor::End); - this->append(""); - this->insertHtml("" + p_name.toHtmlEscaped() + ": "); + this->append(""); + this->insertHtml("" + p_name.toHtmlEscaped() + ": "); - //cheap workarounds ahoy - p_message += " "; - QString result = p_message.toHtmlEscaped().replace("\n", "
").replace(url_parser_regex, "\\1" ); + //cheap workarounds ahoy + p_message += " "; + QString result = p_message.toHtmlEscaped().replace("\n", "
").replace(url_parser_regex, "\\1"); - this->insertHtml(result); + this->insertHtml(result); - this->auto_scroll(old_cursor, old_scrollbar_value, is_scrolled_down); + this->auto_scroll(old_cursor, old_scrollbar_value, is_scrolled_down); } void AOTextArea::append_error(QString p_message) { - const QTextCursor old_cursor = this->textCursor(); - const int old_scrollbar_value = this->verticalScrollBar()->value(); - const bool is_scrolled_down = old_scrollbar_value == this->verticalScrollBar()->maximum(); + const QTextCursor old_cursor = this->textCursor(); + const int old_scrollbar_value = this->verticalScrollBar()->value(); + const bool is_scrolled_down = old_scrollbar_value == this->verticalScrollBar()->maximum(); - this->moveCursor(QTextCursor::End); + this->moveCursor(QTextCursor::End); - this->append(""); + this->append(""); - p_message += " "; - QString result = p_message.replace("\n", "
").replace(url_parser_regex, "\\1" ); + p_message += " "; + QString result = p_message.replace("\n", "
").replace(url_parser_regex, "\\1"); - this->insertHtml("" + result + ""); + this->insertHtml("" + result + ""); - this->auto_scroll(old_cursor, old_scrollbar_value, is_scrolled_down); + this->auto_scroll(old_cursor, old_scrollbar_value, is_scrolled_down); } void AOTextArea::auto_scroll(QTextCursor old_cursor, int old_scrollbar_value, bool is_scrolled_down) { - if (old_cursor.hasSelection() || !is_scrolled_down) - { - // The user has selected text or scrolled away from the bottom: maintain position. - this->setTextCursor(old_cursor); - this->verticalScrollBar()->setValue(old_scrollbar_value); - } - else - { - // The user hasn't selected any text and the scrollbar is at the bottom: scroll to the bottom. - this->moveCursor(QTextCursor::End); - this->verticalScrollBar()->setValue(this->verticalScrollBar()->maximum()); - } + if (old_cursor.hasSelection() || !is_scrolled_down) { + // The user has selected text or scrolled away from the bottom: maintain position. + this->setTextCursor(old_cursor); + this->verticalScrollBar()->setValue(old_scrollbar_value); + } + else { + // The user hasn't selected any text and the scrollbar is at the bottom: scroll to the bottom. + this->moveCursor(QTextCursor::End); + this->verticalScrollBar()->setValue(this->verticalScrollBar()->maximum()); + } } diff --git a/src/aotextedit.cpp b/src/aotextedit.cpp index 30e48b7..0dc5cb4 100644 --- a/src/aotextedit.cpp +++ b/src/aotextedit.cpp @@ -2,20 +2,19 @@ AOTextEdit::AOTextEdit(QWidget *parent) : QPlainTextEdit(parent) { - this->setReadOnly(true); + this->setReadOnly(true); - //connect(this, SIGNAL(returnPressed()), this, SLOT(on_enter_pressed())); + //connect(this, SIGNAL(returnPressed()), this, SLOT(on_enter_pressed())); } void AOTextEdit::mouseDoubleClickEvent(QMouseEvent *e) { - QPlainTextEdit::mouseDoubleClickEvent(e); + QPlainTextEdit::mouseDoubleClickEvent(e); - this->setReadOnly(false); + this->setReadOnly(false); } void AOTextEdit::on_enter_pressed() { - this->setReadOnly(true); + this->setReadOnly(true); } - diff --git a/src/charselect.cpp b/src/charselect.cpp index 6739a1e..6575869 100644 --- a/src/charselect.cpp +++ b/src/charselect.cpp @@ -1,145 +1,139 @@ #include "courtroom.h" #include "lobby.h" -#include "file_functions.h" #include "debug_functions.h" +#include "file_functions.h" #include "hardware_functions.h" void Courtroom::construct_char_select() { - ui_char_select_background = new AOImage(this, ao_app); + ui_char_select_background = new AOImage(this, ao_app); - ui_char_buttons = new QWidget(ui_char_select_background); + ui_char_buttons = new QWidget(ui_char_select_background); - ui_selector = new AOImage(ui_char_select_background, ao_app); - ui_selector->setAttribute(Qt::WA_TransparentForMouseEvents); - ui_selector->resize(62, 62); + ui_selector = new AOImage(ui_char_select_background, ao_app); + ui_selector->setAttribute(Qt::WA_TransparentForMouseEvents); + ui_selector->resize(62, 62); - ui_back_to_lobby = new AOButton(ui_char_select_background, ao_app); + ui_back_to_lobby = new AOButton(ui_char_select_background, ao_app); - ui_char_password = new QLineEdit(ui_char_select_background); - ui_char_password->setPlaceholderText(tr("Password")); + ui_char_password = new QLineEdit(ui_char_select_background); + ui_char_password->setPlaceholderText(tr("Password")); - ui_char_select_left = new AOButton(ui_char_select_background, ao_app); - ui_char_select_right = new AOButton(ui_char_select_background, ao_app); + ui_char_select_left = new AOButton(ui_char_select_background, ao_app); + ui_char_select_right = new AOButton(ui_char_select_background, ao_app); - ui_spectator = new AOButton(ui_char_select_background, ao_app); - ui_spectator->setText(tr("Spectator")); + ui_spectator = new AOButton(ui_char_select_background, ao_app); + ui_spectator->setText(tr("Spectator")); - ui_char_search = new QLineEdit(ui_char_select_background); - ui_char_search->setPlaceholderText(tr("Search")); - ui_char_search->setFocus(); - set_size_and_pos(ui_char_search, "char_search"); + ui_char_search = new QLineEdit(ui_char_select_background); + ui_char_search->setPlaceholderText(tr("Search")); + ui_char_search->setFocus(); + set_size_and_pos(ui_char_search, "char_search"); - ui_char_passworded = new QCheckBox(ui_char_select_background); - ui_char_passworded->setText(tr("Passworded")); - set_size_and_pos(ui_char_passworded, "char_passworded"); + ui_char_passworded = new QCheckBox(ui_char_select_background); + ui_char_passworded->setText(tr("Passworded")); + set_size_and_pos(ui_char_passworded, "char_passworded"); - ui_char_taken = new QCheckBox(ui_char_select_background); - ui_char_taken->setText(tr("Taken")); - set_size_and_pos(ui_char_taken, "char_taken"); + ui_char_taken = new QCheckBox(ui_char_select_background); + ui_char_taken->setText(tr("Taken")); + set_size_and_pos(ui_char_taken, "char_taken"); - ui_char_taken->setChecked(true); - ui_char_passworded->setChecked(true); + ui_char_taken->setChecked(true); + ui_char_passworded->setChecked(true); - set_size_and_pos(ui_char_buttons, "char_buttons"); + set_size_and_pos(ui_char_buttons, "char_buttons"); - connect(ui_back_to_lobby, SIGNAL(clicked()), this, SLOT(on_back_to_lobby_clicked())); + connect(ui_back_to_lobby, SIGNAL(clicked()), this, SLOT(on_back_to_lobby_clicked())); - connect(ui_char_select_left, SIGNAL(clicked()), this, SLOT(on_char_select_left_clicked())); - connect(ui_char_select_right, SIGNAL(clicked()), this, SLOT(on_char_select_right_clicked())); + connect(ui_char_select_left, SIGNAL(clicked()), this, SLOT(on_char_select_left_clicked())); + connect(ui_char_select_right, SIGNAL(clicked()), this, SLOT(on_char_select_right_clicked())); - connect(ui_spectator, SIGNAL(clicked()), this, SLOT(on_spectator_clicked())); + connect(ui_spectator, SIGNAL(clicked()), this, SLOT(on_spectator_clicked())); - connect(ui_char_search, SIGNAL(textEdited(const QString&)), this, SLOT(on_char_search_changed())); - connect(ui_char_passworded, SIGNAL(stateChanged(int)), this, SLOT(on_char_passworded_clicked())); - connect(ui_char_taken, SIGNAL(stateChanged(int)), this, SLOT(on_char_taken_clicked())); + connect(ui_char_search, SIGNAL(textEdited(const QString &)), this, SLOT(on_char_search_changed())); + connect(ui_char_passworded, SIGNAL(stateChanged(int)), this, SLOT(on_char_passworded_clicked())); + connect(ui_char_taken, SIGNAL(stateChanged(int)), this, SLOT(on_char_taken_clicked())); } void Courtroom::set_char_select() { - QString filename = "courtroom_design.ini"; + QString filename = "courtroom_design.ini"; - pos_size_type f_charselect = ao_app->get_element_dimensions("char_select", filename); + pos_size_type f_charselect = ao_app->get_element_dimensions("char_select", filename); - if (f_charselect.width < 0 || f_charselect.height < 0) - { - qDebug() << "W: did not find char_select width or height in courtroom_design.ini!"; - this->resize(714, 668); - } - else - this->resize(f_charselect.width, f_charselect.height); + if (f_charselect.width < 0 || f_charselect.height < 0) { + qDebug() << "W: did not find char_select width or height in courtroom_design.ini!"; + this->resize(714, 668); + } + else + this->resize(f_charselect.width, f_charselect.height); - ui_char_select_background->resize(f_charselect.width, f_charselect.height); - ui_char_select_background->set_image("charselect_background"); + ui_char_select_background->resize(f_charselect.width, f_charselect.height); + ui_char_select_background->set_image("charselect_background"); - filter_character_list(); + filter_character_list(); - ui_char_search->setFocus(); + ui_char_search->setFocus(); } void Courtroom::set_char_select_page() { - ui_char_select_background->show(); + ui_char_select_background->show(); - ui_char_select_left->hide(); - ui_char_select_right->hide(); + ui_char_select_left->hide(); + ui_char_select_right->hide(); - for (AOCharButton *i_button : ui_char_button_list) - { - i_button->reset(); - i_button->hide(); - i_button->move(0,0); - } + for (AOCharButton *i_button : ui_char_button_list) { + i_button->reset(); + i_button->hide(); + i_button->move(0, 0); + } - int total_pages = ui_char_button_list_filtered.size() / max_chars_on_page; - int chars_on_page = 0; + int total_pages = ui_char_button_list_filtered.size() / max_chars_on_page; + int chars_on_page = 0; - if (ui_char_button_list_filtered.size() % max_chars_on_page != 0) - { - ++total_pages; - //i. e. not on the last page - if (total_pages > current_char_page + 1) - chars_on_page = max_chars_on_page; + if (ui_char_button_list_filtered.size() % max_chars_on_page != 0) { + ++total_pages; + //i. e. not on the last page + if (total_pages > current_char_page + 1) + chars_on_page = max_chars_on_page; + else + chars_on_page = ui_char_button_list_filtered.size() % max_chars_on_page; + } else - chars_on_page = ui_char_button_list_filtered.size() % max_chars_on_page; + chars_on_page = max_chars_on_page; - } - else - chars_on_page = max_chars_on_page; + if (total_pages > current_char_page + 1) + ui_char_select_right->show(); - if (total_pages > current_char_page + 1) - ui_char_select_right->show(); + if (current_char_page > 0) + ui_char_select_left->show(); - if (current_char_page > 0) - ui_char_select_left->show(); - - put_button_in_place(current_char_page * max_chars_on_page, chars_on_page); + put_button_in_place(current_char_page * max_chars_on_page, chars_on_page); } void Courtroom::char_clicked(int n_char) { - QString char_ini_path = ao_app->get_character_path(char_list.at(n_char).name, "char.ini"); + QString char_ini_path = ao_app->get_character_path(char_list.at(n_char).name, "char.ini"); - qDebug() << "char_ini_path" << char_ini_path; + qDebug() << "char_ini_path" << char_ini_path; - if (!file_exists(char_ini_path)) - { - call_notice("Could not find " + char_ini_path); - return; - } + if (!file_exists(char_ini_path)) { + call_notice("Could not find " + char_ini_path); + return; + } - if (n_char != m_cid) - { - ao_app->send_server_packet(new AOPacket("PW#" + ui_char_password->text() + "#%")); - ao_app->send_server_packet(new AOPacket("CC#" + QString::number(ao_app->s_pv) + "#" + QString::number(n_char) + "#" + get_hdid() + "#%")); - } - else - update_character(n_char); + if (n_char != m_cid) { + ao_app->send_server_packet(new AOPacket("PW#" + ui_char_password->text() + "#%")); + ao_app->send_server_packet(new AOPacket("CC#" + QString::number(ao_app->s_pv) + "#" + QString::number(n_char) + "#" + get_hdid() + "#%")); + } + else + update_character(n_char); - enter_courtroom(); + enter_courtroom(); - ui_ic_chat_name->setPlaceholderText(char_list.at(n_char).name); + ui_ic_chat_name->setPlaceholderText(char_list.at(n_char).name); } void Courtroom::put_button_in_place(int starting, int chars_on_this_page) @@ -161,22 +155,20 @@ void Courtroom::put_button_in_place(int starting, int chars_on_this_page) max_chars_on_page = char_columns * char_rows; int startout = starting; - for (int n = starting ; n < startout+chars_on_this_page ; ++n) - { - int x_pos = (button_width + x_spacing) * x_mod_count; - int y_pos = (button_height + y_spacing) * y_mod_count; + for (int n = starting; n < startout + chars_on_this_page; ++n) { + int x_pos = (button_width + x_spacing) * x_mod_count; + int y_pos = (button_height + y_spacing) * y_mod_count; - ui_char_button_list_filtered.at(n)->move(x_pos, y_pos); - ui_char_button_list_filtered.at(n)->show(); - ui_char_button_list_filtered.at(n)->apply_taken_image(); + ui_char_button_list_filtered.at(n)->move(x_pos, y_pos); + ui_char_button_list_filtered.at(n)->show(); + ui_char_button_list_filtered.at(n)->apply_taken_image(); - ++x_mod_count; + ++x_mod_count; - if (x_mod_count == char_columns) - { - ++y_mod_count; - x_mod_count = 0; - } + if (x_mod_count == char_columns) { + ++y_mod_count; + x_mod_count = 0; + } } } @@ -184,9 +176,8 @@ void Courtroom::character_loading_finished() { // Zeroeth, we'll clear any leftover characters from previous server visits. ao_app->generated_chars = 0; - if (ui_char_button_list.size() > 0) - { - foreach (AOCharButton* item, ui_char_button_list) { + if (ui_char_button_list.size() > 0) { + foreach (AOCharButton *item, ui_char_button_list) { delete item; } ui_char_button_list.clear(); @@ -195,28 +186,26 @@ void Courtroom::character_loading_finished() // First, we'll make all the character buttons in the very beginning. // We also hide them all, so they can't be accidentally clicked. // Later on, we'll be revealing buttons as we need them. - for (int n = 0; n < char_list.size(); n++) - { - AOCharButton* char_button = new AOCharButton(ui_char_buttons, ao_app, 0, 0, char_list.at(n).taken); - char_button->reset(); - char_button->hide(); - char_button->set_image(char_list.at(n).name); - ui_char_button_list.append(char_button); + for (int n = 0; n < char_list.size(); n++) { + AOCharButton *char_button = new AOCharButton(ui_char_buttons, ao_app, 0, 0, char_list.at(n).taken); + char_button->reset(); + char_button->hide(); + char_button->set_image(char_list.at(n).name); + ui_char_button_list.append(char_button); - connect(char_button, &AOCharButton::clicked, [this, n](){ - this->char_clicked(n); - }); + connect(char_button, &AOCharButton::clicked, [this, n]() { + this->char_clicked(n); + }); - // This part here serves as a way of showing to the player that the game is still running, it is - // just loading the pictures of the characters. - if (ao_app->lobby_constructed) - { - ao_app->generated_chars++; - int total_loading_size = ao_app->char_list_size * 2 + ao_app->evidence_list_size + ao_app->music_list_size; - int loading_value = int(((ao_app->loaded_chars + ao_app->generated_chars + ao_app->loaded_music + ao_app->loaded_evidence) / static_cast(total_loading_size)) * 100); - ao_app->w_lobby->set_loading_value(loading_value); - ao_app->w_lobby->set_loading_text(tr("Generating chars:\n%1/%2").arg(QString::number(ao_app->generated_chars)).arg(QString::number(ao_app->char_list_size))); - } + // This part here serves as a way of showing to the player that the game is still running, it is + // just loading the pictures of the characters. + if (ao_app->lobby_constructed) { + ao_app->generated_chars++; + int total_loading_size = ao_app->char_list_size * 2 + ao_app->evidence_list_size + ao_app->music_list_size; + int loading_value = int(((ao_app->loaded_chars + ao_app->generated_chars + ao_app->loaded_music + ao_app->loaded_evidence) / static_cast(total_loading_size)) * 100); + ao_app->w_lobby->set_loading_value(loading_value); + ao_app->w_lobby->set_loading_text(tr("Generating chars:\n%1/%2").arg(QString::number(ao_app->generated_chars)).arg(QString::number(ao_app->char_list_size))); + } } filter_character_list(); @@ -225,28 +214,27 @@ void Courtroom::character_loading_finished() void Courtroom::filter_character_list() { ui_char_button_list_filtered.clear(); - for (int i = 0; i < char_list.size(); i++) - { - AOCharButton* current_char = ui_char_button_list.at(i); + for (int i = 0; i < char_list.size(); i++) { + AOCharButton *current_char = ui_char_button_list.at(i); - // It seems passwording characters is unimplemented yet? - // Until then, this will stay here, I suppose. - //if (ui_char_passworded->isChecked() && character_is_passworded??) - // continue; + // It seems passwording characters is unimplemented yet? + // Until then, this will stay here, I suppose. + //if (ui_char_passworded->isChecked() && character_is_passworded??) + // continue; - if (!ui_char_taken->isChecked() && char_list.at(i).taken) - continue; + if (!ui_char_taken->isChecked() && char_list.at(i).taken) + continue; - if (!char_list.at(i).name.contains(ui_char_search->text(), Qt::CaseInsensitive)) - continue; + if (!char_list.at(i).name.contains(ui_char_search->text(), Qt::CaseInsensitive)) + continue; - // We only really need to update the fact that a character is taken - // for the buttons that actually appear. - // You'd also update the passwordedness and etc. here later. - current_char->reset(); - current_char->set_taken(char_list.at(i).taken); + // We only really need to update the fact that a character is taken + // for the buttons that actually appear. + // You'd also update the passwordedness and etc. here later. + current_char->reset(); + current_char->set_taken(char_list.at(i).taken); - ui_char_button_list_filtered.append(current_char); + ui_char_button_list_filtered.append(current_char); } current_char_page = 0; diff --git a/src/chatlogpiece.cpp b/src/chatlogpiece.cpp index dafc354..b0113de 100644 --- a/src/chatlogpiece.cpp +++ b/src/chatlogpiece.cpp @@ -2,76 +2,76 @@ chatlogpiece::chatlogpiece() { - name = "UNKNOWN"; - showname = "UNKNOWN"; - message = "UNKNOWN"; - p_is_song = false; - datetime = QDateTime::currentDateTime().toUTC(); + name = "UNKNOWN"; + showname = "UNKNOWN"; + message = "UNKNOWN"; + p_is_song = false; + datetime = QDateTime::currentDateTime().toUTC(); } chatlogpiece::chatlogpiece(QString p_name, QString p_showname, QString p_message, bool p_song) { - name = p_name; - showname = p_showname; - message = p_message; - p_is_song = p_song; - datetime = QDateTime::currentDateTime().toUTC(); + name = p_name; + showname = p_showname; + message = p_message; + p_is_song = p_song; + datetime = QDateTime::currentDateTime().toUTC(); } chatlogpiece::chatlogpiece(QString p_name, QString p_showname, QString p_message, bool p_song, QDateTime p_datetime) { - name = p_name; - showname = p_showname; - message = p_message; - p_is_song = p_song; - datetime = p_datetime.toUTC(); + name = p_name; + showname = p_showname; + message = p_message; + p_is_song = p_song; + datetime = p_datetime.toUTC(); } QString chatlogpiece::get_name() { - return name; + return name; } QString chatlogpiece::get_showname() { - return showname; + return showname; } QString chatlogpiece::get_message() { - return message; + return message; } QDateTime chatlogpiece::get_datetime() { - return datetime; + return datetime; } bool chatlogpiece::is_song() { - return p_is_song; + return p_is_song; } QString chatlogpiece::get_datetime_as_string() { - return datetime.toString(); + return datetime.toString(); } QString chatlogpiece::get_full() { - QString full = "["; + QString full = "["; - full.append(get_datetime_as_string()); - full.append("] "); - full.append(get_showname()); - full.append(" ("); - full.append(get_name()); - full.append(")"); - if (p_is_song) - full.append(" has played a song: "); - else - full.append(": "); - full.append(get_message()); + full.append(get_datetime_as_string()); + full.append("] "); + full.append(get_showname()); + full.append(" ("); + full.append(get_name()); + full.append(")"); + if (p_is_song) + full.append(" has played a song: "); + else + full.append(": "); + full.append(get_message()); - return full; + return full; } diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 40d17e4..4c240fe 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1,2179 +1,2490 @@ #include "courtroom.h" - Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() { - ao_app = p_ao_app; - #ifdef BASSAUDIO - // Change the default audio output device to be the one the user has given - // in his config.ini file for now. - unsigned int a = 0; - BASS_DEVICEINFO info; - - if (ao_app->get_audio_output_device() == "default") - { - BASS_Init(-1, 48000, BASS_DEVICE_LATENCY, nullptr, nullptr); - load_bass_opus_plugin(); - } - else - { - for (a = 0; BASS_GetDeviceInfo(a, &info); a++) - { - if (ao_app->get_audio_output_device() == info.name) - { - BASS_SetDevice(a); - BASS_Init(static_cast(a), 48000, BASS_DEVICE_LATENCY, nullptr, nullptr); - load_bass_opus_plugin(); - qDebug() << info.name << "was set as the default audio output device."; - break; - } - } - } - #elif defined QTAUDIO - - if (ao_app->get_audio_output_device() != "default") - { - foreach (const QAudioDeviceInfo &deviceInfo, QAudioDeviceInfo::availableDevices(QAudio::AudioOutput)) - { - if (ao_app->get_audio_output_device() == deviceInfo.deviceName()) - { - ao_app->QtAudioDevice = deviceInfo; - qDebug() << deviceInfo.deviceName() << "was set as the default audio output device."; - break; - } - } - } - #endif - - qsrand(static_cast(QDateTime::currentMSecsSinceEpoch() / 1000)); - - keepalive_timer = new QTimer(this); - keepalive_timer->start(60000); - - chat_tick_timer = new QTimer(this); - - text_delay_timer = new QTimer(this); - text_delay_timer->setSingleShot(true); - - sfx_delay_timer = new QTimer(this); - sfx_delay_timer->setSingleShot(true); - - music_player = new AOMusicPlayer(this, ao_app); - music_player->set_volume(0); - - sfx_player = new AOSfxPlayer(this, ao_app); - sfx_player->set_volume(0); - - objection_player = new AOSfxPlayer(this, ao_app); - objection_player->set_volume(0); - - blip_player = new AOBlipPlayer(this, ao_app); - blip_player->set_volume(0); - - modcall_player = new AOSfxPlayer(this, ao_app); - modcall_player->set_volume(50); - - ui_background = new AOImage(this, ao_app); - - ui_viewport = new QWidget(this); - ui_vp_background = new AOScene(ui_viewport, ao_app); - ui_vp_speedlines = new AOMovie(ui_viewport, ao_app); - ui_vp_speedlines->set_play_once(false); - ui_vp_player_char = new AOCharMovie(ui_viewport, ao_app); - ui_vp_sideplayer_char = new AOCharMovie(ui_viewport, ao_app); - ui_vp_sideplayer_char->hide(); - ui_vp_desk = new AOScene(ui_viewport, ao_app); - ui_vp_legacy_desk = new AOScene(ui_viewport, ao_app); - - ui_vp_evidence_display = new AOEvidenceDisplay(ui_viewport, ao_app); - - ui_vp_chatbox = new AOImage(this, ao_app); - ui_vp_showname = new QLabel(ui_vp_chatbox); - ui_vp_showname->setAlignment(Qt::AlignHCenter); - ui_vp_chat_arrow = new AOMovie(ui_vp_chatbox, ao_app); - ui_vp_chat_arrow->set_play_once(false); - - ui_vp_message = new QTextEdit(this); - ui_vp_message->setFrameStyle(QFrame::NoFrame); - ui_vp_message->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - ui_vp_message->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - ui_vp_message->setReadOnly(true); - - ui_vp_testimony = new AOMovie(this, ao_app); - ui_vp_testimony->set_play_once(false); - ui_vp_testimony->setAttribute(Qt::WA_TransparentForMouseEvents); - ui_vp_effect = new AOMovie(this, ao_app); - ui_vp_effect->setAttribute(Qt::WA_TransparentForMouseEvents); - ui_vp_wtce = new AOMovie(this, ao_app); - ui_vp_wtce->setAttribute(Qt::WA_TransparentForMouseEvents); - ui_vp_objection = new AOMovie(this, ao_app); - ui_vp_objection->setAttribute(Qt::WA_TransparentForMouseEvents); - - ui_ic_chatlog = new QTextEdit(this); - ui_ic_chatlog->setReadOnly(true); - - log_maximum_blocks = ao_app->get_max_log_size(); - log_goes_downwards = ao_app->get_log_goes_downwards(); - - ui_ms_chatlog = new AOTextArea(this); - ui_ms_chatlog->setReadOnly(true); - ui_ms_chatlog->setOpenExternalLinks(true); - ui_ms_chatlog->hide(); - - ui_server_chatlog = new AOTextArea(this); - ui_server_chatlog->setReadOnly(true); - ui_server_chatlog->setOpenExternalLinks(true); - - ui_area_list = new QTreeWidget(this); - ui_area_list->setColumnCount(2); - ui_area_list->hideColumn(0); - ui_area_list->setHeaderHidden(true); - ui_area_list->header()->setStretchLastSection(false); - ui_area_list->header()->setSectionResizeMode(QHeaderView::ResizeToContents); - ui_area_list->hide(); - - ui_music_list = new QTreeWidget(this); - ui_music_list->setColumnCount(2); - ui_music_list->hideColumn(1); - ui_music_list->setHeaderHidden(true); - ui_music_list->header()->setStretchLastSection(false); - ui_music_list->header()->setSectionResizeMode(QHeaderView::ResizeToContents); - ui_music_list->setContextMenuPolicy(Qt::CustomContextMenu); - - ui_music_display = new AOMovie(this, ao_app); - ui_music_display->set_play_once(false); - ui_music_display->setAttribute(Qt::WA_TransparentForMouseEvents); - - ui_music_name = new ScrollText(ui_music_display); - ui_music_name->setText(tr("None")); - ui_music_name->setAttribute(Qt::WA_TransparentForMouseEvents); - - ui_ic_chat_name = new QLineEdit(this); - ui_ic_chat_name->setFrame(false); - ui_ic_chat_name->setPlaceholderText(tr("Showname")); - - ui_ic_chat_message = new AOLineEdit(this); - ui_ic_chat_message->setFrame(false); - ui_ic_chat_message->setPlaceholderText(tr("Message")); - ui_ic_chat_message->preserve_selection(true); -// ui_ic_chat_message->setValidator(new QRegExpValidator(QRegExp("^\\S+(?: \\S+)*$"), ui_ic_chat_message)); - //todo: filter out \n from showing up as that commonly breaks the chatlog and can be spammed to hell - - ui_muted = new AOImage(ui_ic_chat_message, ao_app); - ui_muted->hide(); - - ui_ooc_chat_message = new QLineEdit(this); - ui_ooc_chat_message->setFrame(false); - - ui_ooc_chat_name = new QLineEdit(this); - ui_ooc_chat_name->setFrame(false); - ui_ooc_chat_name->setPlaceholderText(tr("Name")); - ui_ooc_chat_name->setMaxLength(30); - ui_ooc_chat_name->setText(p_ao_app->get_default_username()); - - //ui_area_password = new QLineEdit(this); - //ui_area_password->setFrame(false); - ui_music_search = new QLineEdit(this); - ui_music_search->setFrame(false); - ui_music_search->setPlaceholderText(tr("Search")); - - initialize_emotes(); - - ui_pos_dropdown = new QComboBox(this); - - ui_iniswap_dropdown = new QComboBox(this); - ui_iniswap_dropdown->setContextMenuPolicy(Qt::CustomContextMenu); - ui_iniswap_remove = new AOButton(this, ao_app); - - ui_sfx_dropdown = new QComboBox(this); - ui_sfx_dropdown->setContextMenuPolicy(Qt::CustomContextMenu); - ui_sfx_remove = new AOButton(this, ao_app); - - ui_effects_dropdown = new QComboBox(this); - ui_effects_dropdown->setContextMenuPolicy(Qt::CustomContextMenu); - - ui_defense_bar = new AOImage(this, ao_app); - ui_prosecution_bar = new AOImage(this, ao_app); - - ui_music_label = new QLabel(this); - ui_sfx_label = new QLabel(this); - ui_blip_label = new QLabel(this); + ao_app = p_ao_app; +#ifdef BASSAUDIO + // Change the default audio output device to be the one the user has given + // in his config.ini file for now. + unsigned int a = 0; + BASS_DEVICEINFO info; + + if (ao_app->get_audio_output_device() == "default") { + BASS_Init(-1, 48000, BASS_DEVICE_LATENCY, nullptr, nullptr); + load_bass_opus_plugin(); + } + else { + for (a = 0; BASS_GetDeviceInfo(a, &info); a++) { + if (ao_app->get_audio_output_device() == info.name) { + BASS_SetDevice(a); + BASS_Init(static_cast(a), 48000, BASS_DEVICE_LATENCY, nullptr, nullptr); + load_bass_opus_plugin(); + qDebug() << info.name << "was set as the default audio output device."; + break; + } + } + } +#elif defined QTAUDIO + + if (ao_app->get_audio_output_device() != "default") { + foreach (const QAudioDeviceInfo &deviceInfo, QAudioDeviceInfo::availableDevices(QAudio::AudioOutput)) { + if (ao_app->get_audio_output_device() == deviceInfo.deviceName()) { + ao_app->QtAudioDevice = deviceInfo; + qDebug() << deviceInfo.deviceName() << "was set as the default audio output device."; + break; + } + } + } +#endif + + qsrand(static_cast(QDateTime::currentMSecsSinceEpoch() / 1000)); + + keepalive_timer = new QTimer(this); + keepalive_timer->start(60000); + + chat_tick_timer = new QTimer(this); + + text_delay_timer = new QTimer(this); + text_delay_timer->setSingleShot(true); + + sfx_delay_timer = new QTimer(this); + sfx_delay_timer->setSingleShot(true); + + music_player = new AOMusicPlayer(this, ao_app); + music_player->set_volume(0); + + sfx_player = new AOSfxPlayer(this, ao_app); + sfx_player->set_volume(0); + + objection_player = new AOSfxPlayer(this, ao_app); + objection_player->set_volume(0); + + blip_player = new AOBlipPlayer(this, ao_app); + blip_player->set_volume(0); + + modcall_player = new AOSfxPlayer(this, ao_app); + modcall_player->set_volume(50); + + ui_background = new AOImage(this, ao_app); + + ui_viewport = new QWidget(this); + ui_vp_background = new AOScene(ui_viewport, ao_app); + ui_vp_speedlines = new AOMovie(ui_viewport, ao_app); + ui_vp_speedlines->set_play_once(false); + ui_vp_player_char = new AOCharMovie(ui_viewport, ao_app); + ui_vp_sideplayer_char = new AOCharMovie(ui_viewport, ao_app); + ui_vp_sideplayer_char->hide(); + ui_vp_desk = new AOScene(ui_viewport, ao_app); + ui_vp_legacy_desk = new AOScene(ui_viewport, ao_app); + + ui_vp_evidence_display = new AOEvidenceDisplay(ui_viewport, ao_app); + + ui_vp_chatbox = new AOImage(this, ao_app); + ui_vp_showname = new QLabel(ui_vp_chatbox); + ui_vp_showname->setAlignment(Qt::AlignHCenter); + ui_vp_chat_arrow = new AOMovie(ui_vp_chatbox, ao_app); + ui_vp_chat_arrow->set_play_once(false); + + ui_vp_message = new QTextEdit(this); + ui_vp_message->setFrameStyle(QFrame::NoFrame); + ui_vp_message->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + ui_vp_message->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + ui_vp_message->setReadOnly(true); + + ui_vp_testimony = new AOMovie(this, ao_app); + ui_vp_testimony->set_play_once(false); + ui_vp_testimony->setAttribute(Qt::WA_TransparentForMouseEvents); + ui_vp_effect = new AOMovie(this, ao_app); + ui_vp_effect->setAttribute(Qt::WA_TransparentForMouseEvents); + ui_vp_wtce = new AOMovie(this, ao_app); + ui_vp_wtce->setAttribute(Qt::WA_TransparentForMouseEvents); + ui_vp_objection = new AOMovie(this, ao_app); + ui_vp_objection->setAttribute(Qt::WA_TransparentForMouseEvents); + + ui_ic_chatlog = new QTextEdit(this); + ui_ic_chatlog->setReadOnly(true); + + log_maximum_blocks = ao_app->get_max_log_size(); + log_goes_downwards = ao_app->get_log_goes_downwards(); + + ui_ms_chatlog = new AOTextArea(this); + ui_ms_chatlog->setReadOnly(true); + ui_ms_chatlog->setOpenExternalLinks(true); + ui_ms_chatlog->hide(); + + ui_server_chatlog = new AOTextArea(this); + ui_server_chatlog->setReadOnly(true); + ui_server_chatlog->setOpenExternalLinks(true); + + ui_area_list = new QTreeWidget(this); + ui_area_list->setColumnCount(2); + ui_area_list->hideColumn(0); + ui_area_list->setHeaderHidden(true); + ui_area_list->header()->setStretchLastSection(false); + ui_area_list->header()->setSectionResizeMode(QHeaderView::ResizeToContents); + ui_area_list->hide(); + + ui_music_list = new QTreeWidget(this); + ui_music_list->setColumnCount(2); + ui_music_list->hideColumn(1); + ui_music_list->setHeaderHidden(true); + ui_music_list->header()->setStretchLastSection(false); + ui_music_list->header()->setSectionResizeMode(QHeaderView::ResizeToContents); + ui_music_list->setContextMenuPolicy(Qt::CustomContextMenu); + + ui_music_display = new AOMovie(this, ao_app); + ui_music_display->set_play_once(false); + ui_music_display->setAttribute(Qt::WA_TransparentForMouseEvents); + + ui_music_name = new ScrollText(ui_music_display); + ui_music_name->setText(tr("None")); + ui_music_name->setAttribute(Qt::WA_TransparentForMouseEvents); + + ui_ic_chat_name = new QLineEdit(this); + ui_ic_chat_name->setFrame(false); + ui_ic_chat_name->setPlaceholderText(tr("Showname")); + + ui_ic_chat_message = new AOLineEdit(this); + ui_ic_chat_message->setFrame(false); + ui_ic_chat_message->setPlaceholderText(tr("Message")); + ui_ic_chat_message->preserve_selection(true); + // ui_ic_chat_message->setValidator(new QRegExpValidator(QRegExp("^\\S+(?: \\S+)*$"), ui_ic_chat_message)); + //todo: filter out \n from showing up as that commonly breaks the chatlog and can be spammed to hell + + ui_muted = new AOImage(ui_ic_chat_message, ao_app); + ui_muted->hide(); + + ui_ooc_chat_message = new QLineEdit(this); + ui_ooc_chat_message->setFrame(false); + + ui_ooc_chat_name = new QLineEdit(this); + ui_ooc_chat_name->setFrame(false); + ui_ooc_chat_name->setPlaceholderText(tr("Name")); + ui_ooc_chat_name->setMaxLength(30); + ui_ooc_chat_name->setText(p_ao_app->get_default_username()); + + //ui_area_password = new QLineEdit(this); + //ui_area_password->setFrame(false); + ui_music_search = new QLineEdit(this); + ui_music_search->setFrame(false); + ui_music_search->setPlaceholderText(tr("Search")); + + initialize_emotes(); + + ui_pos_dropdown = new QComboBox(this); + + ui_iniswap_dropdown = new QComboBox(this); + ui_iniswap_dropdown->setContextMenuPolicy(Qt::CustomContextMenu); + ui_iniswap_remove = new AOButton(this, ao_app); + + ui_sfx_dropdown = new QComboBox(this); + ui_sfx_dropdown->setContextMenuPolicy(Qt::CustomContextMenu); + ui_sfx_remove = new AOButton(this, ao_app); + + ui_effects_dropdown = new QComboBox(this); + ui_effects_dropdown->setContextMenuPolicy(Qt::CustomContextMenu); + + ui_defense_bar = new AOImage(this, ao_app); + ui_prosecution_bar = new AOImage(this, ao_app); + + ui_music_label = new QLabel(this); + ui_sfx_label = new QLabel(this); + ui_blip_label = new QLabel(this); - ui_hold_it = new AOButton(this, ao_app); - ui_objection = new AOButton(this, ao_app); - ui_take_that = new AOButton(this, ao_app); + ui_hold_it = new AOButton(this, ao_app); + ui_objection = new AOButton(this, ao_app); + ui_take_that = new AOButton(this, ao_app); - ui_ooc_toggle = new AOButton(this, ao_app); - ui_witness_testimony = new AOButton(this, ao_app); - ui_cross_examination = new AOButton(this, ao_app); - ui_guilty = new AOButton(this, ao_app); - ui_not_guilty = new AOButton(this, ao_app); + ui_ooc_toggle = new AOButton(this, ao_app); + ui_witness_testimony = new AOButton(this, ao_app); + ui_cross_examination = new AOButton(this, ao_app); + ui_guilty = new AOButton(this, ao_app); + ui_not_guilty = new AOButton(this, ao_app); - ui_change_character = new AOButton(this, ao_app); - ui_reload_theme = new AOButton(this, ao_app); - ui_call_mod = new AOButton(this, ao_app); - ui_settings = new AOButton(this, ao_app); - ui_announce_casing = new AOButton(this, ao_app); - ui_switch_area_music = new AOButton(this, ao_app); + ui_change_character = new AOButton(this, ao_app); + ui_reload_theme = new AOButton(this, ao_app); + ui_call_mod = new AOButton(this, ao_app); + ui_settings = new AOButton(this, ao_app); + ui_announce_casing = new AOButton(this, ao_app); + ui_switch_area_music = new AOButton(this, ao_app); - ui_pre = new QCheckBox(this); - ui_pre->setText(tr("Pre")); + ui_pre = new QCheckBox(this); + ui_pre->setText(tr("Pre")); - ui_flip = new QCheckBox(this); - ui_flip->setText(tr("Flip")); - ui_flip->hide(); + ui_flip = new QCheckBox(this); + ui_flip->setText(tr("Flip")); + ui_flip->hide(); - ui_guard = new QCheckBox(this); - ui_guard->setText(tr("Guard")); - ui_guard->hide(); + ui_guard = new QCheckBox(this); + ui_guard->setText(tr("Guard")); + ui_guard->hide(); - ui_additive = new QCheckBox(this); - ui_additive->setText(tr("Additive")); - ui_additive->hide(); + ui_additive = new QCheckBox(this); + ui_additive->setText(tr("Additive")); + ui_additive->hide(); - ui_casing = new QCheckBox(this); - ui_casing->setChecked(ao_app->get_casing_enabled()); - ui_casing->setText(tr("Casing")); - ui_casing->hide(); + ui_casing = new QCheckBox(this); + ui_casing->setChecked(ao_app->get_casing_enabled()); + ui_casing->setText(tr("Casing")); + ui_casing->hide(); - ui_showname_enable = new QCheckBox(this); - ui_showname_enable->setChecked(ao_app->get_showname_enabled_by_default()); - ui_showname_enable->setText(tr("Shownames")); + ui_showname_enable = new QCheckBox(this); + ui_showname_enable->setChecked(ao_app->get_showname_enabled_by_default()); + ui_showname_enable->setText(tr("Shownames")); - ui_pre_non_interrupt = new QCheckBox(this); - ui_pre_non_interrupt->setText(tr("No Interrupt")); - ui_pre_non_interrupt->hide(); + ui_pre_non_interrupt = new QCheckBox(this); + ui_pre_non_interrupt->setText(tr("No Interrupt")); + ui_pre_non_interrupt->hide(); - ui_custom_objection = new AOButton(this, ao_app); - ui_realization = new AOButton(this, ao_app); - ui_screenshake = new AOButton(this, ao_app); - ui_mute = new AOButton(this, ao_app); + ui_custom_objection = new AOButton(this, ao_app); + ui_realization = new AOButton(this, ao_app); + ui_screenshake = new AOButton(this, ao_app); + ui_mute = new AOButton(this, ao_app); - ui_defense_plus = new AOButton(this, ao_app); - ui_defense_minus = new AOButton(this, ao_app); + ui_defense_plus = new AOButton(this, ao_app); + ui_defense_minus = new AOButton(this, ao_app); - ui_prosecution_plus = new AOButton(this, ao_app); - ui_prosecution_minus = new AOButton(this, ao_app); + ui_prosecution_plus = new AOButton(this, ao_app); + ui_prosecution_minus = new AOButton(this, ao_app); - ui_text_color = new QComboBox(this); + ui_text_color = new QComboBox(this); - ui_music_slider = new QSlider(Qt::Horizontal, this); - ui_music_slider->setRange(0, 100); - ui_music_slider->setValue(ao_app->get_default_music()); + ui_music_slider = new QSlider(Qt::Horizontal, this); + ui_music_slider->setRange(0, 100); + ui_music_slider->setValue(ao_app->get_default_music()); - ui_sfx_slider = new QSlider(Qt::Horizontal, this); - ui_sfx_slider->setRange(0, 100); - ui_sfx_slider->setValue(ao_app->get_default_sfx()); + ui_sfx_slider = new QSlider(Qt::Horizontal, this); + ui_sfx_slider->setRange(0, 100); + ui_sfx_slider->setValue(ao_app->get_default_sfx()); - ui_blip_slider = new QSlider(Qt::Horizontal, this); - ui_blip_slider->setRange(0, 100); - ui_blip_slider->setValue(ao_app->get_default_blip()); + ui_blip_slider = new QSlider(Qt::Horizontal, this); + ui_blip_slider->setRange(0, 100); + ui_blip_slider->setValue(ao_app->get_default_blip()); - ui_mute_list = new QListWidget(this); + ui_mute_list = new QListWidget(this); - ui_pair_list = new QListWidget(this); - ui_pair_offset_spinbox = new QSpinBox(this); - ui_pair_offset_spinbox->setRange(-100,100); - ui_pair_offset_spinbox->setSuffix(tr("% offset")); + ui_pair_list = new QListWidget(this); + ui_pair_offset_spinbox = new QSpinBox(this); + ui_pair_offset_spinbox->setRange(-100, 100); + ui_pair_offset_spinbox->setSuffix(tr("% offset")); - ui_pair_order_dropdown = new QComboBox(this); - ui_pair_order_dropdown->addItem("To front"); - ui_pair_order_dropdown->addItem("To behind"); + ui_pair_order_dropdown = new QComboBox(this); + ui_pair_order_dropdown->addItem("To front"); + ui_pair_order_dropdown->addItem("To behind"); - ui_pair_button = new AOButton(this, ao_app); + ui_pair_button = new AOButton(this, ao_app); - ui_evidence_button = new AOButton(this, ao_app); + ui_evidence_button = new AOButton(this, ao_app); - initialize_evidence(); + initialize_evidence(); - construct_char_select(); + construct_char_select(); - connect(keepalive_timer, SIGNAL(timeout()), this, SLOT(ping_server())); + connect(keepalive_timer, SIGNAL(timeout()), this, SLOT(ping_server())); - connect(ui_vp_objection, SIGNAL(done()), this, SLOT(objection_done())); - connect(ui_vp_player_char, SIGNAL(done()), this, SLOT(preanim_done())); - connect(ui_vp_player_char, SIGNAL(shake()), this, SLOT(do_screenshake())); - connect(ui_vp_player_char, SIGNAL(flash()), this, SLOT(do_flash())); - connect(ui_vp_player_char, SIGNAL(play_sfx(QString)), this, SLOT(play_char_sfx(QString))); + connect(ui_vp_objection, SIGNAL(done()), this, SLOT(objection_done())); + connect(ui_vp_player_char, SIGNAL(done()), this, SLOT(preanim_done())); + connect(ui_vp_player_char, SIGNAL(shake()), this, SLOT(do_screenshake())); + connect(ui_vp_player_char, SIGNAL(flash()), this, SLOT(do_flash())); + connect(ui_vp_player_char, SIGNAL(play_sfx(QString)), this, SLOT(play_char_sfx(QString))); - connect(text_delay_timer, SIGNAL(timeout()), this, SLOT(start_chat_ticking())); - connect(sfx_delay_timer, SIGNAL(timeout()), this, SLOT(play_sfx())); + connect(text_delay_timer, SIGNAL(timeout()), this, SLOT(start_chat_ticking())); + connect(sfx_delay_timer, SIGNAL(timeout()), this, SLOT(play_sfx())); - connect(chat_tick_timer, SIGNAL(timeout()), this, SLOT(chat_tick())); + connect(chat_tick_timer, SIGNAL(timeout()), this, SLOT(chat_tick())); - connect(ui_pos_dropdown, SIGNAL(currentIndexChanged(int)), this, SLOT(on_pos_dropdown_changed(int))); + connect(ui_pos_dropdown, SIGNAL(currentIndexChanged(int)), this, SLOT(on_pos_dropdown_changed(int))); - connect(ui_iniswap_dropdown, SIGNAL(currentIndexChanged(int)), this, SLOT(on_iniswap_dropdown_changed(int))); - connect(ui_iniswap_dropdown, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(on_iniswap_context_menu_requested(QPoint))); - connect(ui_iniswap_remove, SIGNAL(clicked()), this, SLOT(on_iniswap_remove_clicked())); + connect(ui_iniswap_dropdown, SIGNAL(currentIndexChanged(int)), this, SLOT(on_iniswap_dropdown_changed(int))); + connect(ui_iniswap_dropdown, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(on_iniswap_context_menu_requested(QPoint))); + connect(ui_iniswap_remove, SIGNAL(clicked()), this, SLOT(on_iniswap_remove_clicked())); - connect(ui_sfx_dropdown, SIGNAL(currentIndexChanged(int)), this, SLOT(on_sfx_dropdown_changed(int))); - connect(ui_sfx_dropdown, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(on_sfx_context_menu_requested(QPoint))); - connect(ui_sfx_remove, SIGNAL(clicked()), this, SLOT(on_sfx_remove_clicked())); + connect(ui_sfx_dropdown, SIGNAL(currentIndexChanged(int)), this, SLOT(on_sfx_dropdown_changed(int))); + connect(ui_sfx_dropdown, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(on_sfx_context_menu_requested(QPoint))); + connect(ui_sfx_remove, SIGNAL(clicked()), this, SLOT(on_sfx_remove_clicked())); - connect(ui_effects_dropdown, SIGNAL(currentIndexChanged(int)), this, SLOT(on_effects_dropdown_changed(int))); - connect(ui_effects_dropdown, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(on_effects_context_menu_requested(QPoint))); + connect(ui_effects_dropdown, SIGNAL(currentIndexChanged(int)), this, SLOT(on_effects_dropdown_changed(int))); + connect(ui_effects_dropdown, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(on_effects_context_menu_requested(QPoint))); - connect(ui_mute_list, SIGNAL(clicked(QModelIndex)), this, SLOT(on_mute_list_clicked(QModelIndex))); + connect(ui_mute_list, SIGNAL(clicked(QModelIndex)), this, SLOT(on_mute_list_clicked(QModelIndex))); - connect(ui_ic_chat_message, SIGNAL(returnPressed()), this, SLOT(on_chat_return_pressed())); + connect(ui_ic_chat_message, SIGNAL(returnPressed()), this, SLOT(on_chat_return_pressed())); - connect(ui_ooc_chat_message, SIGNAL(returnPressed()), this, SLOT(on_ooc_return_pressed())); + connect(ui_ooc_chat_message, SIGNAL(returnPressed()), this, SLOT(on_ooc_return_pressed())); - connect(ui_music_list, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this, SLOT(on_music_list_double_clicked(QTreeWidgetItem*, int))); - connect(ui_music_list, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(on_music_list_context_menu_requested(QPoint))); + connect(ui_music_list, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), this, SLOT(on_music_list_double_clicked(QTreeWidgetItem *, int))); + connect(ui_music_list, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(on_music_list_context_menu_requested(QPoint))); - connect(ui_area_list, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this, SLOT(on_area_list_double_clicked(QTreeWidgetItem*, int))); + connect(ui_area_list, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), this, SLOT(on_area_list_double_clicked(QTreeWidgetItem *, int))); - connect(ui_hold_it, SIGNAL(clicked()), this, SLOT(on_hold_it_clicked())); - connect(ui_objection, SIGNAL(clicked()), this, SLOT(on_objection_clicked())); - connect(ui_take_that, SIGNAL(clicked()), this, SLOT(on_take_that_clicked())); - connect(ui_custom_objection, SIGNAL(clicked()), this, SLOT(on_custom_objection_clicked())); + connect(ui_hold_it, SIGNAL(clicked()), this, SLOT(on_hold_it_clicked())); + connect(ui_objection, SIGNAL(clicked()), this, SLOT(on_objection_clicked())); + connect(ui_take_that, SIGNAL(clicked()), this, SLOT(on_take_that_clicked())); + connect(ui_custom_objection, SIGNAL(clicked()), this, SLOT(on_custom_objection_clicked())); - connect(ui_realization, SIGNAL(clicked()), this, SLOT(on_realization_clicked())); - connect(ui_screenshake, SIGNAL(clicked()), this, SLOT(on_screenshake_clicked())); + connect(ui_realization, SIGNAL(clicked()), this, SLOT(on_realization_clicked())); + connect(ui_screenshake, SIGNAL(clicked()), this, SLOT(on_screenshake_clicked())); - connect(ui_mute, SIGNAL(clicked()), this, SLOT(on_mute_clicked())); + connect(ui_mute, SIGNAL(clicked()), this, SLOT(on_mute_clicked())); - connect(ui_defense_minus, SIGNAL(clicked()), this, SLOT(on_defense_minus_clicked())); - connect(ui_defense_plus, SIGNAL(clicked()), this, SLOT(on_defense_plus_clicked())); - connect(ui_prosecution_minus, SIGNAL(clicked()), this, SLOT(on_prosecution_minus_clicked())); - connect(ui_prosecution_plus, SIGNAL(clicked()), this, SLOT(on_prosecution_plus_clicked())); + connect(ui_defense_minus, SIGNAL(clicked()), this, SLOT(on_defense_minus_clicked())); + connect(ui_defense_plus, SIGNAL(clicked()), this, SLOT(on_defense_plus_clicked())); + connect(ui_prosecution_minus, SIGNAL(clicked()), this, SLOT(on_prosecution_minus_clicked())); + connect(ui_prosecution_plus, SIGNAL(clicked()), this, SLOT(on_prosecution_plus_clicked())); - connect(ui_text_color, SIGNAL(currentIndexChanged(int)), this, SLOT(on_text_color_changed(int))); + connect(ui_text_color, SIGNAL(currentIndexChanged(int)), this, SLOT(on_text_color_changed(int))); - connect(ui_music_slider, SIGNAL(valueChanged(int)), this, SLOT(on_music_slider_moved(int))); - connect(ui_sfx_slider, SIGNAL(valueChanged(int)), this, SLOT(on_sfx_slider_moved(int))); - connect(ui_blip_slider, SIGNAL(valueChanged(int)), this, SLOT(on_blip_slider_moved(int))); + connect(ui_music_slider, SIGNAL(valueChanged(int)), this, SLOT(on_music_slider_moved(int))); + connect(ui_sfx_slider, SIGNAL(valueChanged(int)), this, SLOT(on_sfx_slider_moved(int))); + connect(ui_blip_slider, SIGNAL(valueChanged(int)), this, SLOT(on_blip_slider_moved(int))); - connect(ui_ooc_toggle, SIGNAL(clicked()), this, SLOT(on_ooc_toggle_clicked())); + connect(ui_ooc_toggle, SIGNAL(clicked()), this, SLOT(on_ooc_toggle_clicked())); - connect(ui_music_search, SIGNAL(textChanged(QString)), this, SLOT(on_music_search_edited(QString))); + connect(ui_music_search, SIGNAL(textChanged(QString)), this, SLOT(on_music_search_edited(QString))); - connect(ui_witness_testimony, SIGNAL(clicked()), this, SLOT(on_witness_testimony_clicked())); - connect(ui_cross_examination, SIGNAL(clicked()), this, SLOT(on_cross_examination_clicked())); - connect(ui_guilty, SIGNAL(clicked()), this, SLOT(on_guilty_clicked())); - connect(ui_not_guilty, SIGNAL(clicked()), this, SLOT(on_not_guilty_clicked())); + connect(ui_witness_testimony, SIGNAL(clicked()), this, SLOT(on_witness_testimony_clicked())); + connect(ui_cross_examination, SIGNAL(clicked()), this, SLOT(on_cross_examination_clicked())); + connect(ui_guilty, SIGNAL(clicked()), this, SLOT(on_guilty_clicked())); + connect(ui_not_guilty, SIGNAL(clicked()), this, SLOT(on_not_guilty_clicked())); - connect(ui_change_character, SIGNAL(clicked()), this, SLOT(on_change_character_clicked())); - connect(ui_reload_theme, SIGNAL(clicked()), this, SLOT(on_reload_theme_clicked())); - connect(ui_call_mod, SIGNAL(clicked()), this, SLOT(on_call_mod_clicked())); - connect(ui_settings, SIGNAL(clicked()), this, SLOT(on_settings_clicked())); - connect(ui_announce_casing, SIGNAL(clicked()), this, SLOT(on_announce_casing_clicked())); - connect(ui_switch_area_music, SIGNAL(clicked()), this, SLOT(on_switch_area_music_clicked())); + connect(ui_change_character, SIGNAL(clicked()), this, SLOT(on_change_character_clicked())); + connect(ui_reload_theme, SIGNAL(clicked()), this, SLOT(on_reload_theme_clicked())); + connect(ui_call_mod, SIGNAL(clicked()), this, SLOT(on_call_mod_clicked())); + connect(ui_settings, SIGNAL(clicked()), this, SLOT(on_settings_clicked())); + connect(ui_announce_casing, SIGNAL(clicked()), this, SLOT(on_announce_casing_clicked())); + connect(ui_switch_area_music, SIGNAL(clicked()), this, SLOT(on_switch_area_music_clicked())); - connect(ui_pre, SIGNAL(clicked()), this, SLOT(on_pre_clicked())); - connect(ui_flip, SIGNAL(clicked()), this, SLOT(on_flip_clicked())); - connect(ui_additive, SIGNAL(clicked()), this, SLOT(on_additive_clicked())); - connect(ui_guard, SIGNAL(clicked()), this, SLOT(on_guard_clicked())); - connect(ui_casing, SIGNAL(clicked()), this, SLOT(on_casing_clicked())); + connect(ui_pre, SIGNAL(clicked()), this, SLOT(on_pre_clicked())); + connect(ui_flip, SIGNAL(clicked()), this, SLOT(on_flip_clicked())); + connect(ui_additive, SIGNAL(clicked()), this, SLOT(on_additive_clicked())); + connect(ui_guard, SIGNAL(clicked()), this, SLOT(on_guard_clicked())); + connect(ui_casing, SIGNAL(clicked()), this, SLOT(on_casing_clicked())); - connect(ui_showname_enable, SIGNAL(clicked()), this, SLOT(on_showname_enable_clicked())); + connect(ui_showname_enable, SIGNAL(clicked()), this, SLOT(on_showname_enable_clicked())); - connect(ui_pair_button, SIGNAL(clicked()), this, SLOT(on_pair_clicked())); - connect(ui_pair_list, SIGNAL(clicked(QModelIndex)), this, SLOT(on_pair_list_clicked(QModelIndex))); - connect(ui_pair_offset_spinbox, SIGNAL(valueChanged(int)), this, SLOT(on_pair_offset_changed(int))); - connect(ui_pair_order_dropdown, SIGNAL(currentIndexChanged(int)), this, SLOT(on_pair_order_dropdown_changed(int))); + connect(ui_pair_button, SIGNAL(clicked()), this, SLOT(on_pair_clicked())); + connect(ui_pair_list, SIGNAL(clicked(QModelIndex)), this, SLOT(on_pair_list_clicked(QModelIndex))); + connect(ui_pair_offset_spinbox, SIGNAL(valueChanged(int)), this, SLOT(on_pair_offset_changed(int))); + connect(ui_pair_order_dropdown, SIGNAL(currentIndexChanged(int)), this, SLOT(on_pair_order_dropdown_changed(int))); - connect(ui_evidence_button, SIGNAL(clicked()), this, SLOT(on_evidence_button_clicked())); + connect(ui_evidence_button, SIGNAL(clicked()), this, SLOT(on_evidence_button_clicked())); - set_widgets(); + set_widgets(); - set_char_select(); + set_char_select(); } void Courtroom::set_mute_list() { - mute_map.clear(); + mute_map.clear(); - //maps which characters are muted based on cid, none are muted by default - for (int n_cid = 0 ; n_cid < char_list.size() ; n_cid++) - { - mute_map.insert(n_cid, false); - } + //maps which characters are muted based on cid, none are muted by default + for (int n_cid = 0; n_cid < char_list.size(); n_cid++) { + mute_map.insert(n_cid, false); + } - QStringList sorted_mute_list; + QStringList sorted_mute_list; - for (char_type i_char : char_list) - sorted_mute_list.append(i_char.name); + for (char_type i_char : char_list) + sorted_mute_list.append(i_char.name); - sorted_mute_list.sort(); + sorted_mute_list.sort(); - for (QString i_name : sorted_mute_list) - { - //mute_map.insert(i_name, false); - ui_mute_list->addItem(i_name); - } + for (QString i_name : sorted_mute_list) { + //mute_map.insert(i_name, false); + ui_mute_list->addItem(i_name); + } } void Courtroom::set_pair_list() { - QStringList sorted_pair_list; + QStringList sorted_pair_list; - for (char_type i_char : char_list) - sorted_pair_list.append(i_char.name); + for (char_type i_char : char_list) + sorted_pair_list.append(i_char.name); - sorted_pair_list.sort(); + sorted_pair_list.sort(); - for (QString i_name : sorted_pair_list) - { - ui_pair_list->addItem(i_name); - } + for (QString i_name : sorted_pair_list) { + ui_pair_list->addItem(i_name); + } } void Courtroom::set_widgets() { - blip_rate = ao_app->read_blip_rate(); - blank_blip = ao_app->get_blank_blip(); - - QString filename = "courtroom_design.ini"; - - pos_size_type f_courtroom = ao_app->get_element_dimensions("courtroom", filename); - - if (f_courtroom.width < 0 || f_courtroom.height < 0) - { - qDebug() << "W: did not find courtroom width or height in " << filename; - - this->resize(714, 668); - } - else - { - m_courtroom_width = f_courtroom.width; - m_courtroom_height = f_courtroom.height; - - this->resize(f_courtroom.width, f_courtroom.height); - } - - set_fonts(); - - ui_background->move(0, 0); - ui_background->resize(m_courtroom_width, m_courtroom_height); - ui_background->set_image("courtroombackground"); - - set_size_and_pos(ui_viewport, "viewport"); - - // 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_support_enabled) - { - ui_pair_button->show(); - ui_pre_non_interrupt->show(); - ui_showname_enable->show(); - ui_ic_chat_name->show(); - ui_ic_chat_name->setEnabled(true); - } - else - { - ui_pair_button->hide(); - ui_pre_non_interrupt->hide(); - ui_showname_enable->hide(); - ui_ic_chat_name->hide(); - ui_ic_chat_name->setEnabled(false); - } - - if (ao_app->casing_alerts_enabled) - { - ui_announce_casing->show(); - ui_casing->show(); - } - else - { - ui_announce_casing->hide(); - ui_casing->hide(); - } - - // We also show the non-server-dependent client additions. - // Once again, if the theme can't display it, set_move_and_pos will catch them. - ui_settings->show(); - - ui_vp_background->move(0, 0); - ui_vp_background->combo_resize(ui_viewport->width(), ui_viewport->height()); - - ui_vp_speedlines->move(0, 0); - ui_vp_speedlines->combo_resize(ui_viewport->width(), ui_viewport->height()); - - ui_vp_player_char->move(0, 0); - ui_vp_player_char->combo_resize(ui_viewport->width(), ui_viewport->height()); - - ui_vp_sideplayer_char->move(0, 0); - ui_vp_sideplayer_char->combo_resize(ui_viewport->width(), ui_viewport->height()); - - //the AO2 desk element - ui_vp_desk->move(0, 0); - ui_vp_desk->combo_resize(ui_viewport->width(), ui_viewport->height()); - - //the size of the ui_vp_legacy_desk element relies on various factors and is set in set_scene() - - double y_modifier = 147.0 / 192.0; - int final_y = static_cast(y_modifier * ui_viewport->height()); - ui_vp_legacy_desk->move(0, final_y); - ui_vp_legacy_desk->hide(); - - ui_vp_evidence_display->move(0, 0); - ui_vp_evidence_display->combo_resize(ui_viewport->width(), ui_viewport->height()); - - ui_vp_chat_arrow->move(0, 0); - pos_size_type design_ini_result = ao_app->get_element_dimensions("chat_arrow", "courtroom_design.ini"); - - 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(); - } - else - { - ui_vp_chat_arrow->move(design_ini_result.x, design_ini_result.y); - ui_vp_chat_arrow->combo_resize(design_ini_result.width, design_ini_result.height); - } - - ui_vp_testimony->move(ui_viewport->x(), ui_viewport->y()); - ui_vp_testimony->combo_resize(ui_viewport->width(), ui_viewport->height()); - - ui_vp_effect->move(ui_viewport->x(), ui_viewport->y()); - ui_vp_effect->combo_resize(ui_viewport->width(), ui_viewport->height()); - - ui_vp_wtce->move(ui_viewport->x(), ui_viewport->y()); - ui_vp_wtce->combo_resize(ui_viewport->width(), ui_viewport->height()); - - ui_vp_objection->move(ui_viewport->x(), ui_viewport->y()); - ui_vp_objection->combo_resize(ui_viewport->width(), ui_viewport->height()); - - set_size_and_pos(ui_ic_chatlog, "ic_chatlog"); - ui_ic_chatlog->setFrameShape(QFrame::NoFrame); - - set_size_and_pos(ui_ms_chatlog, "ms_chatlog"); - ui_ms_chatlog->setFrameShape(QFrame::NoFrame); - - set_size_and_pos(ui_server_chatlog, "server_chatlog"); - ui_server_chatlog->setFrameShape(QFrame::NoFrame); - - 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 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_offset_spinbox->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()); - - set_size_and_pos(ui_music_list, "music_list"); - ui_music_list->header()->setMinimumSectionSize(ui_music_list->width()); - - set_size_and_pos(ui_music_name, "music_name"); - - ui_music_display->move(0, 0); - design_ini_result = ao_app->get_element_dimensions("music_display", "courtroom_design.ini"); - - if (design_ini_result.width < 0 || design_ini_result.height < 0) - { - qDebug() << "W: could not find \"music_name\" in courtroom_design.ini"; - ui_music_display->hide(); - } - else - { - ui_music_display->move(design_ini_result.x, design_ini_result.y); - ui_music_display->combo_resize(design_ini_result.width, design_ini_result.height); - } - - ui_music_display->play("music_display"); - - if (is_ao2_bg) - { - set_size_and_pos(ui_ic_chat_message, "ao2_ic_chat_message"); - set_size_and_pos(ui_vp_chatbox, "ao2_chatbox"); - set_size_and_pos(ui_ic_chat_name, "ao2_ic_chat_name"); - } - else - { - set_size_and_pos(ui_ic_chat_message, "ic_chat_message"); - set_size_and_pos(ui_vp_chatbox, "chatbox"); - set_size_and_pos(ui_ic_chat_name, "ic_chat_name"); - } - - ui_ic_chat_message->setStyleSheet("QLineEdit{background-color: rgba(100, 100, 100, 255);}"); - ui_ic_chat_name->setStyleSheet("QLineEdit{background-color: rgba(180, 180, 180, 255);}"); - - ui_vp_chatbox->set_image("chatblank"); - ui_vp_chatbox->hide(); - - set_size_and_pos(ui_vp_showname, "showname"); - - set_size_and_pos(ui_vp_message, "message"); - ui_vp_message->hide(); - - //We detached the text as parent from the chatbox so it doesn't get affected by the screenshake. - ui_vp_message->move(ui_vp_message->x() + ui_vp_chatbox->x(), ui_vp_message->y() + ui_vp_chatbox->y()); - ui_vp_message->setTextInteractionFlags(Qt::NoTextInteraction); - - ui_muted->resize(ui_ic_chat_message->width(), ui_ic_chat_message->height()); - ui_muted->set_image("muted"); - ui_muted->setToolTip(tr("Oops, you're muted!")); - - set_size_and_pos(ui_ooc_chat_message, "ooc_chat_message"); - ui_ooc_chat_message->setStyleSheet("background-color: rgba(0, 0, 0, 0);"); - - set_size_and_pos(ui_ooc_chat_name, "ooc_chat_name"); - ui_ooc_chat_name->setStyleSheet("background-color: rgba(0, 0, 0, 0);"); - - //set_size_and_pos(ui_area_password, "area_password"); - set_size_and_pos(ui_music_search, "music_search"); - ui_music_search->setStyleSheet("background-color: rgba(0, 0, 0, 0);"); - - set_size_and_pos(ui_emote_dropdown, "emote_dropdown"); - ui_emote_dropdown->setToolTip(tr("Set your character's emote to play on your next message.")); - - set_size_and_pos(ui_pos_dropdown, "pos_dropdown"); - ui_pos_dropdown->setToolTip(tr("Set your character's supplementary background.")); - - set_size_and_pos(ui_iniswap_dropdown, "iniswap_dropdown"); - ui_iniswap_dropdown->setEditable(true); - ui_iniswap_dropdown->setInsertPolicy(QComboBox::InsertAtBottom); - ui_iniswap_dropdown->setToolTip(tr("Set an 'iniswap', or an alternative character folder to refer to from your current character.\n" - "Edit by typing and pressing Enter, [X] to remove. This saves to your base/characters//iniswaps.ini")); - - set_size_and_pos(ui_iniswap_remove, "iniswap_remove"); - ui_iniswap_remove->setText("X"); - ui_iniswap_remove->set_image("evidencex"); - ui_iniswap_remove->setToolTip(tr("Remove the currently selected iniswap from the list and return to the original character folder.")); - ui_iniswap_remove->hide(); - - set_size_and_pos(ui_sfx_dropdown, "sfx_dropdown"); - ui_sfx_dropdown->setEditable(true); - ui_sfx_dropdown->setInsertPolicy(QComboBox::InsertAtBottom); - ui_sfx_dropdown->setToolTip(tr("Set a sound effect to play on your next 'Preanim'. Leaving it on Default will use the emote-defined sound (if any).\n" - "Edit by typing and pressing Enter, [X] to remove. This saves to your base/characters//soundlist.ini")); - - set_size_and_pos(ui_sfx_remove, "sfx_remove"); - ui_sfx_remove->setText("X"); - ui_sfx_remove->set_image("evidencex"); - ui_sfx_remove->setToolTip(tr("Remove the currently selected iniswap from the list and return to the original character folder.")); - ui_sfx_remove->hide(); - - set_size_and_pos(ui_effects_dropdown, "effects_dropdown"); - ui_effects_dropdown->setInsertPolicy(QComboBox::InsertAtBottom); - ui_effects_dropdown->setToolTip(tr("Choose an effect to play on your next spoken message.\n" - "The effects are defined in your theme/effects/effects.ini. Your character can define custom effects by\n" - "char.ini [Options] category, effects = 'miscname' where it referes to misc//effects.ini to read the effects.")); - //Todo: recode this entire fucking system with these dumbass goddamn ini's why is everything so specifically coded for all these purposes - //is ABSTRACT CODING not a thing now huh what the FUCK why do I gotta do this pleASE FOR THE LOVE OF GOD SPARE ME FROM THIS FRESH HELL - //btw i still love coding. - QPoint p_point = ao_app->get_button_spacing("effects_icon_size", filename); - ui_effects_dropdown->setIconSize(QSize(p_point.x(), p_point.y())); - - set_size_and_pos(ui_defense_bar, "defense_bar"); - ui_defense_bar->set_image("defensebar" + QString::number(defense_bar_state)); - - set_size_and_pos(ui_prosecution_bar, "prosecution_bar"); - ui_prosecution_bar->set_image("prosecutionbar" + QString::number(prosecution_bar_state)); - - set_size_and_pos(ui_music_label, "music_label"); - ui_music_label->setText(tr("Music")); - set_size_and_pos(ui_sfx_label, "sfx_label"); - ui_sfx_label->setText(tr("Sfx")); - set_size_and_pos(ui_blip_label, "blip_label"); - ui_blip_label->setText(tr("Blips")); - - set_size_and_pos(ui_hold_it, "hold_it"); - ui_hold_it->setText(tr("Hold It!")); - ui_hold_it->setToolTip(tr("When this is turned on, your next in-character message will be a shout!")); - ui_hold_it->set_image("holdit"); - - set_size_and_pos(ui_objection, "objection"); - ui_objection->setText(tr("Objection!")); - ui_objection->setToolTip(tr("When this is turned on, your next in-character message will be a shout!")); - ui_objection->set_image("objection"); - - set_size_and_pos(ui_take_that, "take_that"); - ui_take_that->setText(tr("Take That!")); - ui_take_that->setToolTip(tr("When this is turned on, your next in-character message will be a shout!")); - ui_take_that->set_image("takethat"); - - set_size_and_pos(ui_ooc_toggle, "ooc_toggle"); - ui_ooc_toggle->setText(tr("Server")); - ui_ooc_toggle->setToolTip(tr("Toggle between server chat and global AO2 chat.")); - - set_size_and_pos(ui_witness_testimony, "witness_testimony"); - ui_witness_testimony->set_image("witnesstestimony"); - ui_witness_testimony->setToolTip(tr("This will display the animation in the viewport as soon as it is pressed.")); - set_size_and_pos(ui_cross_examination, "cross_examination"); - ui_cross_examination->set_image("crossexamination"); - ui_cross_examination->setToolTip(tr("This will display the animation in the viewport as soon as it is pressed.")); - - set_size_and_pos(ui_guilty, "guilty"); - ui_guilty->setText(tr("Guilty!")); - ui_guilty->set_image("guilty"); - ui_guilty->setToolTip(tr("This will display the animation in the viewport as soon as it is pressed.")); - set_size_and_pos(ui_not_guilty, "not_guilty"); - ui_not_guilty->set_image("notguilty"); - ui_not_guilty->setToolTip(tr("This will display the animation in the viewport as soon as it is pressed.")); - - set_size_and_pos(ui_change_character, "change_character"); - ui_change_character->setText(tr("Change character")); - ui_change_character->set_image("change_character"); - ui_change_character->setToolTip(tr("Bring up the Character Select Screen and change your character.")); - - set_size_and_pos(ui_reload_theme, "reload_theme"); - ui_reload_theme->setText(tr("Reload theme")); - ui_reload_theme->set_image("reload_theme"); - ui_reload_theme->setToolTip(tr("Refresh the theme and update all of the ui elements to match.")); - - set_size_and_pos(ui_call_mod, "call_mod"); - ui_call_mod->setText(tr("Call mod")); - ui_call_mod->set_image("call_mod"); - ui_call_mod->setToolTip(tr("Request the attention of the current server's moderator.")); - - set_size_and_pos(ui_settings, "settings"); - ui_settings->setText(tr("Settings")); - ui_settings->set_image("settings"); - ui_settings->setToolTip(tr("Allows you to change various aspects of the client.")); - - set_size_and_pos(ui_announce_casing, "casing_button"); - ui_announce_casing->setText(tr("Casing")); - ui_announce_casing->set_image("casing_button"); - ui_announce_casing->setToolTip(tr("An interface to help you announce a case (you have to be a CM first to be able to announce cases)")); - - set_size_and_pos(ui_switch_area_music, "switch_area_music"); - ui_switch_area_music->setText(tr("A/M")); - ui_switch_area_music->set_image("switch_area_music"); - ui_switch_area_music->setToolTip(tr("Switch between Areas and Music lists")); - - set_size_and_pos(ui_pre, "pre"); - ui_pre->setText(tr("Preanim")); - ui_pre->setToolTip(tr("Play a single-shot animation as defined by the emote when checked.")); - - set_size_and_pos(ui_pre_non_interrupt, "pre_no_interrupt"); - ui_pre_non_interrupt->setToolTip(tr("If preanim is checked, display the input text immediately as the animation plays concurrently.")); - - set_size_and_pos(ui_flip, "flip"); - ui_flip->setToolTip(tr("Mirror your character's emotes when checked.")); - - set_size_and_pos(ui_additive, "additive"); - ui_additive->setToolTip(tr("Add text to your last spoken message when checked.")); - - set_size_and_pos(ui_guard, "guard"); - ui_guard->setToolTip(tr("Do not listen to mod calls when checked, preventing them from playing sounds or focusing attention on the window.")); - - set_size_and_pos(ui_casing, "casing"); - ui_casing->setToolTip(tr("Lets you receive case alerts when enabled.\n" - "(You can set your preferences in the Settings!)")); - - set_size_and_pos(ui_showname_enable, "showname_enable"); - ui_showname_enable->setToolTip(tr("Display customized shownames for all users when checked.")); - - set_size_and_pos(ui_custom_objection, "custom_objection"); - ui_custom_objection->setText(tr("Custom Shout!")); - ui_custom_objection->set_image("custom"); - ui_custom_objection->setToolTip(tr("This will display the custom character-defined animation in the viewport as soon as it is pressed.\n" - "To make one, your character's folder must contain custom.[webp/apng/gif/png] and custom.[wav/ogg/opus] sound effect")); - - set_size_and_pos(ui_realization, "realization"); - ui_realization->set_image("realization"); - ui_realization->setToolTip(tr("Play realization sound and animation in the viewport on the next spoken message when checked.")); - - set_size_and_pos(ui_screenshake, "screenshake"); - ui_screenshake->set_image("screenshake"); - ui_screenshake->setToolTip(tr("Shake the screen on next spoken message when checked.")); - - set_size_and_pos(ui_mute, "mute_button"); - ui_mute->setText("Mute"); - ui_mute->set_image("mute"); - ui_mute->setToolTip(tr("Display the list of character folders you wish to mute.")); - - set_size_and_pos(ui_defense_plus, "defense_plus"); - ui_defense_plus->set_image("defplus"); - ui_defense_plus->setToolTip(tr("Increase the health bar.")); + blip_rate = ao_app->read_blip_rate(); + blank_blip = ao_app->get_blank_blip(); + + QString filename = "courtroom_design.ini"; + + pos_size_type f_courtroom = ao_app->get_element_dimensions("courtroom", filename); - set_size_and_pos(ui_defense_minus, "defense_minus"); - ui_defense_minus->set_image("defminus"); - ui_defense_minus->setToolTip(tr("Decrease the health bar.")); + if (f_courtroom.width < 0 || f_courtroom.height < 0) { + qDebug() << "W: did not find courtroom width or height in " << filename; - set_size_and_pos(ui_prosecution_plus, "prosecution_plus"); - ui_prosecution_plus->set_image("proplus"); - ui_prosecution_plus->setToolTip(tr("Increase the health bar.")); + this->resize(714, 668); + } + else { + m_courtroom_width = f_courtroom.width; + m_courtroom_height = f_courtroom.height; - set_size_and_pos(ui_prosecution_minus, "prosecution_minus"); - ui_prosecution_minus->set_image("prominus"); - ui_prosecution_minus->setToolTip(tr("Decrease the health bar.")); + this->resize(f_courtroom.width, f_courtroom.height); + } - set_size_and_pos(ui_text_color, "text_color"); - ui_text_color->setToolTip(tr("Change the text color of the spoken message.\n" - "You can also select a part of your currently typed message and use the dropdown to change its color!")); - set_text_color_dropdown(); + set_fonts(); - set_size_and_pos(ui_music_slider, "music_slider"); - set_size_and_pos(ui_sfx_slider, "sfx_slider"); - set_size_and_pos(ui_blip_slider, "blip_slider"); + ui_background->move(0, 0); + ui_background->resize(m_courtroom_width, m_courtroom_height); + ui_background->set_image("courtroombackground"); - ui_selector->set_image("char_selector"); - ui_selector->hide(); + set_size_and_pos(ui_viewport, "viewport"); - set_size_and_pos(ui_back_to_lobby, "back_to_lobby"); - ui_back_to_lobby->setText(tr("Back to Lobby")); - ui_back_to_lobby->setToolTip(tr("Return back to the server list.")); + // 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_support_enabled) { + ui_pair_button->show(); + ui_pre_non_interrupt->show(); + ui_showname_enable->show(); + ui_ic_chat_name->show(); + ui_ic_chat_name->setEnabled(true); + } + else { + ui_pair_button->hide(); + ui_pre_non_interrupt->hide(); + ui_showname_enable->hide(); + ui_ic_chat_name->hide(); + ui_ic_chat_name->setEnabled(false); + } - set_size_and_pos(ui_char_password, "char_password"); + if (ao_app->casing_alerts_enabled) { + ui_announce_casing->show(); + ui_casing->show(); + } + else { + ui_announce_casing->hide(); + ui_casing->hide(); + } - set_size_and_pos(ui_char_buttons, "char_buttons"); + // We also show the non-server-dependent client additions. + // Once again, if the theme can't display it, set_move_and_pos will catch them. + ui_settings->show(); - set_size_and_pos(ui_char_select_left, "char_select_left"); - ui_char_select_left->set_image("arrow_left"); + ui_vp_background->move(0, 0); + ui_vp_background->combo_resize(ui_viewport->width(), ui_viewport->height()); - set_size_and_pos(ui_char_select_right, "char_select_right"); - ui_char_select_right->set_image("arrow_right"); + ui_vp_speedlines->move(0, 0); + ui_vp_speedlines->combo_resize(ui_viewport->width(), ui_viewport->height()); - set_size_and_pos(ui_spectator, "spectator"); - ui_spectator->setToolTip(tr("Become a spectator. You won't be able to interact with the in-character screen.")); + ui_vp_player_char->move(0, 0); + ui_vp_player_char->combo_resize(ui_viewport->width(), ui_viewport->height()); + + ui_vp_sideplayer_char->move(0, 0); + ui_vp_sideplayer_char->combo_resize(ui_viewport->width(), ui_viewport->height()); + + //the AO2 desk element + ui_vp_desk->move(0, 0); + ui_vp_desk->combo_resize(ui_viewport->width(), ui_viewport->height()); + + //the size of the ui_vp_legacy_desk element relies on various factors and is set in set_scene() - refresh_evidence(); + double y_modifier = 147.0 / 192.0; + int final_y = static_cast(y_modifier * ui_viewport->height()); + ui_vp_legacy_desk->move(0, final_y); + ui_vp_legacy_desk->hide(); + + ui_vp_evidence_display->move(0, 0); + ui_vp_evidence_display->combo_resize(ui_viewport->width(), ui_viewport->height()); + + ui_vp_chat_arrow->move(0, 0); + pos_size_type design_ini_result = ao_app->get_element_dimensions("chat_arrow", "courtroom_design.ini"); + + 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(); + } + else { + ui_vp_chat_arrow->move(design_ini_result.x, design_ini_result.y); + ui_vp_chat_arrow->combo_resize(design_ini_result.width, design_ini_result.height); + } + + ui_vp_testimony->move(ui_viewport->x(), ui_viewport->y()); + ui_vp_testimony->combo_resize(ui_viewport->width(), ui_viewport->height()); + + ui_vp_effect->move(ui_viewport->x(), ui_viewport->y()); + ui_vp_effect->combo_resize(ui_viewport->width(), ui_viewport->height()); + + ui_vp_wtce->move(ui_viewport->x(), ui_viewport->y()); + ui_vp_wtce->combo_resize(ui_viewport->width(), ui_viewport->height()); + + ui_vp_objection->move(ui_viewport->x(), ui_viewport->y()); + ui_vp_objection->combo_resize(ui_viewport->width(), ui_viewport->height()); + + set_size_and_pos(ui_ic_chatlog, "ic_chatlog"); + ui_ic_chatlog->setFrameShape(QFrame::NoFrame); + + set_size_and_pos(ui_ms_chatlog, "ms_chatlog"); + ui_ms_chatlog->setFrameShape(QFrame::NoFrame); + + set_size_and_pos(ui_server_chatlog, "server_chatlog"); + ui_server_chatlog->setFrameShape(QFrame::NoFrame); + + 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 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_offset_spinbox->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()); + + set_size_and_pos(ui_music_list, "music_list"); + ui_music_list->header()->setMinimumSectionSize(ui_music_list->width()); + + set_size_and_pos(ui_music_name, "music_name"); + + ui_music_display->move(0, 0); + design_ini_result = ao_app->get_element_dimensions("music_display", "courtroom_design.ini"); + + if (design_ini_result.width < 0 || design_ini_result.height < 0) { + qDebug() << "W: could not find \"music_name\" in courtroom_design.ini"; + ui_music_display->hide(); + } + else { + ui_music_display->move(design_ini_result.x, design_ini_result.y); + ui_music_display->combo_resize(design_ini_result.width, design_ini_result.height); + } + + ui_music_display->play("music_display"); + + if (is_ao2_bg) { + set_size_and_pos(ui_ic_chat_message, "ao2_ic_chat_message"); + set_size_and_pos(ui_vp_chatbox, "ao2_chatbox"); + set_size_and_pos(ui_ic_chat_name, "ao2_ic_chat_name"); + } + else { + set_size_and_pos(ui_ic_chat_message, "ic_chat_message"); + set_size_and_pos(ui_vp_chatbox, "chatbox"); + set_size_and_pos(ui_ic_chat_name, "ic_chat_name"); + } + + ui_ic_chat_message->setStyleSheet("QLineEdit{background-color: rgba(100, 100, 100, 255);}"); + ui_ic_chat_name->setStyleSheet("QLineEdit{background-color: rgba(180, 180, 180, 255);}"); + + ui_vp_chatbox->set_image("chatblank"); + ui_vp_chatbox->hide(); + + set_size_and_pos(ui_vp_showname, "showname"); + + set_size_and_pos(ui_vp_message, "message"); + ui_vp_message->hide(); + + //We detached the text as parent from the chatbox so it doesn't get affected by the screenshake. + ui_vp_message->move(ui_vp_message->x() + ui_vp_chatbox->x(), ui_vp_message->y() + ui_vp_chatbox->y()); + ui_vp_message->setTextInteractionFlags(Qt::NoTextInteraction); + + ui_muted->resize(ui_ic_chat_message->width(), ui_ic_chat_message->height()); + ui_muted->set_image("muted"); + ui_muted->setToolTip(tr("Oops, you're muted!")); + + set_size_and_pos(ui_ooc_chat_message, "ooc_chat_message"); + ui_ooc_chat_message->setStyleSheet("background-color: rgba(0, 0, 0, 0);"); + + set_size_and_pos(ui_ooc_chat_name, "ooc_chat_name"); + ui_ooc_chat_name->setStyleSheet("background-color: rgba(0, 0, 0, 0);"); + + //set_size_and_pos(ui_area_password, "area_password"); + set_size_and_pos(ui_music_search, "music_search"); + ui_music_search->setStyleSheet("background-color: rgba(0, 0, 0, 0);"); + + set_size_and_pos(ui_emote_dropdown, "emote_dropdown"); + ui_emote_dropdown->setToolTip(tr("Set your character's emote to play on your next message.")); + + set_size_and_pos(ui_pos_dropdown, "pos_dropdown"); + ui_pos_dropdown->setToolTip(tr("Set your character's supplementary background.")); + + set_size_and_pos(ui_iniswap_dropdown, "iniswap_dropdown"); + ui_iniswap_dropdown->setEditable(true); + ui_iniswap_dropdown->setInsertPolicy(QComboBox::InsertAtBottom); + ui_iniswap_dropdown->setToolTip(tr("Set an 'iniswap', or an alternative character folder to refer to from your current character.\n" + "Edit by typing and pressing Enter, [X] to remove. This saves to your base/characters//iniswaps.ini")); + + set_size_and_pos(ui_iniswap_remove, "iniswap_remove"); + ui_iniswap_remove->setText("X"); + ui_iniswap_remove->set_image("evidencex"); + ui_iniswap_remove->setToolTip(tr("Remove the currently selected iniswap from the list and return to the original character folder.")); + ui_iniswap_remove->hide(); + + set_size_and_pos(ui_sfx_dropdown, "sfx_dropdown"); + ui_sfx_dropdown->setEditable(true); + ui_sfx_dropdown->setInsertPolicy(QComboBox::InsertAtBottom); + ui_sfx_dropdown->setToolTip(tr("Set a sound effect to play on your next 'Preanim'. Leaving it on Default will use the emote-defined sound (if any).\n" + "Edit by typing and pressing Enter, [X] to remove. This saves to your base/characters//soundlist.ini")); + + set_size_and_pos(ui_sfx_remove, "sfx_remove"); + ui_sfx_remove->setText("X"); + ui_sfx_remove->set_image("evidencex"); + ui_sfx_remove->setToolTip(tr("Remove the currently selected iniswap from the list and return to the original character folder.")); + ui_sfx_remove->hide(); + + set_size_and_pos(ui_effects_dropdown, "effects_dropdown"); + ui_effects_dropdown->setInsertPolicy(QComboBox::InsertAtBottom); + ui_effects_dropdown->setToolTip(tr("Choose an effect to play on your next spoken message.\n" + "The effects are defined in your theme/effects/effects.ini. Your character can define custom effects by\n" + "char.ini [Options] category, effects = 'miscname' where it referes to misc//effects.ini to read the effects.")); + //Todo: recode this entire fucking system with these dumbass goddamn ini's why is everything so specifically coded for all these purposes + //is ABSTRACT CODING not a thing now huh what the FUCK why do I gotta do this pleASE FOR THE LOVE OF GOD SPARE ME FROM THIS FRESH HELL + //btw i still love coding. + QPoint p_point = ao_app->get_button_spacing("effects_icon_size", filename); + ui_effects_dropdown->setIconSize(QSize(p_point.x(), p_point.y())); + + set_size_and_pos(ui_defense_bar, "defense_bar"); + ui_defense_bar->set_image("defensebar" + QString::number(defense_bar_state)); + + set_size_and_pos(ui_prosecution_bar, "prosecution_bar"); + ui_prosecution_bar->set_image("prosecutionbar" + QString::number(prosecution_bar_state)); + + set_size_and_pos(ui_music_label, "music_label"); + ui_music_label->setText(tr("Music")); + set_size_and_pos(ui_sfx_label, "sfx_label"); + ui_sfx_label->setText(tr("Sfx")); + set_size_and_pos(ui_blip_label, "blip_label"); + ui_blip_label->setText(tr("Blips")); + + set_size_and_pos(ui_hold_it, "hold_it"); + ui_hold_it->setText(tr("Hold It!")); + ui_hold_it->setToolTip(tr("When this is turned on, your next in-character message will be a shout!")); + ui_hold_it->set_image("holdit"); + + set_size_and_pos(ui_objection, "objection"); + ui_objection->setText(tr("Objection!")); + ui_objection->setToolTip(tr("When this is turned on, your next in-character message will be a shout!")); + ui_objection->set_image("objection"); + + set_size_and_pos(ui_take_that, "take_that"); + ui_take_that->setText(tr("Take That!")); + ui_take_that->setToolTip(tr("When this is turned on, your next in-character message will be a shout!")); + ui_take_that->set_image("takethat"); + + set_size_and_pos(ui_ooc_toggle, "ooc_toggle"); + ui_ooc_toggle->setText(tr("Server")); + ui_ooc_toggle->setToolTip(tr("Toggle between server chat and global AO2 chat.")); + + set_size_and_pos(ui_witness_testimony, "witness_testimony"); + ui_witness_testimony->set_image("witnesstestimony"); + ui_witness_testimony->setToolTip(tr("This will display the animation in the viewport as soon as it is pressed.")); + set_size_and_pos(ui_cross_examination, "cross_examination"); + ui_cross_examination->set_image("crossexamination"); + ui_cross_examination->setToolTip(tr("This will display the animation in the viewport as soon as it is pressed.")); + + set_size_and_pos(ui_guilty, "guilty"); + ui_guilty->setText(tr("Guilty!")); + ui_guilty->set_image("guilty"); + ui_guilty->setToolTip(tr("This will display the animation in the viewport as soon as it is pressed.")); + set_size_and_pos(ui_not_guilty, "not_guilty"); + ui_not_guilty->set_image("notguilty"); + ui_not_guilty->setToolTip(tr("This will display the animation in the viewport as soon as it is pressed.")); + + set_size_and_pos(ui_change_character, "change_character"); + ui_change_character->setText(tr("Change character")); + ui_change_character->set_image("change_character"); + ui_change_character->setToolTip(tr("Bring up the Character Select Screen and change your character.")); + + set_size_and_pos(ui_reload_theme, "reload_theme"); + ui_reload_theme->setText(tr("Reload theme")); + ui_reload_theme->set_image("reload_theme"); + ui_reload_theme->setToolTip(tr("Refresh the theme and update all of the ui elements to match.")); + + set_size_and_pos(ui_call_mod, "call_mod"); + ui_call_mod->setText(tr("Call mod")); + ui_call_mod->set_image("call_mod"); + ui_call_mod->setToolTip(tr("Request the attention of the current server's moderator.")); + + set_size_and_pos(ui_settings, "settings"); + ui_settings->setText(tr("Settings")); + ui_settings->set_image("settings"); + ui_settings->setToolTip(tr("Allows you to change various aspects of the client.")); + + set_size_and_pos(ui_announce_casing, "casing_button"); + ui_announce_casing->setText(tr("Casing")); + ui_announce_casing->set_image("casing_button"); + ui_announce_casing->setToolTip(tr("An interface to help you announce a case (you have to be a CM first to be able to announce cases)")); + + set_size_and_pos(ui_switch_area_music, "switch_area_music"); + ui_switch_area_music->setText(tr("A/M")); + ui_switch_area_music->set_image("switch_area_music"); + ui_switch_area_music->setToolTip(tr("Switch between Areas and Music lists")); + + set_size_and_pos(ui_pre, "pre"); + ui_pre->setText(tr("Preanim")); + ui_pre->setToolTip(tr("Play a single-shot animation as defined by the emote when checked.")); + + set_size_and_pos(ui_pre_non_interrupt, "pre_no_interrupt"); + ui_pre_non_interrupt->setToolTip(tr("If preanim is checked, display the input text immediately as the animation plays concurrently.")); + + set_size_and_pos(ui_flip, "flip"); + ui_flip->setToolTip(tr("Mirror your character's emotes when checked.")); + + set_size_and_pos(ui_additive, "additive"); + ui_additive->setToolTip(tr("Add text to your last spoken message when checked.")); + + set_size_and_pos(ui_guard, "guard"); + ui_guard->setToolTip(tr("Do not listen to mod calls when checked, preventing them from playing sounds or focusing attention on the window.")); + + set_size_and_pos(ui_casing, "casing"); + ui_casing->setToolTip(tr("Lets you receive case alerts when enabled.\n" + "(You can set your preferences in the Settings!)")); + + set_size_and_pos(ui_showname_enable, "showname_enable"); + ui_showname_enable->setToolTip(tr("Display customized shownames for all users when checked.")); + + set_size_and_pos(ui_custom_objection, "custom_objection"); + ui_custom_objection->setText(tr("Custom Shout!")); + ui_custom_objection->set_image("custom"); + ui_custom_objection->setToolTip(tr("This will display the custom character-defined animation in the viewport as soon as it is pressed.\n" + "To make one, your character's folder must contain custom.[webp/apng/gif/png] and custom.[wav/ogg/opus] sound effect")); + + set_size_and_pos(ui_realization, "realization"); + ui_realization->set_image("realization"); + ui_realization->setToolTip(tr("Play realization sound and animation in the viewport on the next spoken message when checked.")); + + set_size_and_pos(ui_screenshake, "screenshake"); + ui_screenshake->set_image("screenshake"); + ui_screenshake->setToolTip(tr("Shake the screen on next spoken message when checked.")); + + set_size_and_pos(ui_mute, "mute_button"); + ui_mute->setText("Mute"); + ui_mute->set_image("mute"); + ui_mute->setToolTip(tr("Display the list of character folders you wish to mute.")); + + set_size_and_pos(ui_defense_plus, "defense_plus"); + ui_defense_plus->set_image("defplus"); + ui_defense_plus->setToolTip(tr("Increase the health bar.")); + + set_size_and_pos(ui_defense_minus, "defense_minus"); + ui_defense_minus->set_image("defminus"); + ui_defense_minus->setToolTip(tr("Decrease the health bar.")); + + set_size_and_pos(ui_prosecution_plus, "prosecution_plus"); + ui_prosecution_plus->set_image("proplus"); + ui_prosecution_plus->setToolTip(tr("Increase the health bar.")); + + set_size_and_pos(ui_prosecution_minus, "prosecution_minus"); + ui_prosecution_minus->set_image("prominus"); + ui_prosecution_minus->setToolTip(tr("Decrease the health bar.")); + + set_size_and_pos(ui_text_color, "text_color"); + ui_text_color->setToolTip(tr("Change the text color of the spoken message.\n" + "You can also select a part of your currently typed message and use the dropdown to change its color!")); + set_text_color_dropdown(); + + set_size_and_pos(ui_music_slider, "music_slider"); + set_size_and_pos(ui_sfx_slider, "sfx_slider"); + set_size_and_pos(ui_blip_slider, "blip_slider"); + + ui_selector->set_image("char_selector"); + ui_selector->hide(); + + set_size_and_pos(ui_back_to_lobby, "back_to_lobby"); + ui_back_to_lobby->setText(tr("Back to Lobby")); + ui_back_to_lobby->setToolTip(tr("Return back to the server list.")); + + set_size_and_pos(ui_char_password, "char_password"); + + set_size_and_pos(ui_char_buttons, "char_buttons"); + + set_size_and_pos(ui_char_select_left, "char_select_left"); + ui_char_select_left->set_image("arrow_left"); + + set_size_and_pos(ui_char_select_right, "char_select_right"); + ui_char_select_right->set_image("arrow_right"); + + set_size_and_pos(ui_spectator, "spectator"); + ui_spectator->setToolTip(tr("Become a spectator. You won't be able to interact with the in-character screen.")); + + refresh_evidence(); } void Courtroom::set_fonts() { - set_font(ui_vp_showname, "", "showname"); - set_font(ui_vp_message, "", "message"); - set_font(ui_ic_chatlog, "", "ic_chatlog"); - set_font(ui_ms_chatlog, "", "ms_chatlog"); - set_font(ui_server_chatlog, "", "server_chatlog"); - set_font(ui_music_list, "", "music_list"); - set_font(ui_area_list, "", "area_list"); - set_font(ui_music_name, "", "music_name"); + set_font(ui_vp_showname, "", "showname"); + set_font(ui_vp_message, "", "message"); + set_font(ui_ic_chatlog, "", "ic_chatlog"); + set_font(ui_ms_chatlog, "", "ms_chatlog"); + set_font(ui_server_chatlog, "", "server_chatlog"); + set_font(ui_music_list, "", "music_list"); + set_font(ui_area_list, "", "area_list"); + set_font(ui_music_name, "", "music_name"); - set_dropdowns(); + set_dropdowns(); } void Courtroom::set_font(QWidget *widget, QString class_name, QString p_identifier) { - QString design_file = "courtroom_fonts.ini"; - int f_pointsize = ao_app->get_font_size(p_identifier, design_file); - QString font_name = ao_app->get_font_name(p_identifier + "_font", design_file); - QColor f_color = ao_app->get_color(p_identifier + "_color", design_file); - bool bold = ao_app->get_font_size(p_identifier + "_bold", design_file) == 1; // is the font bold or not? - bool antialias = ao_app->get_font_size(p_identifier + "_sharp", design_file) != 1; // is the font anti-aliased or not? + QString design_file = "courtroom_fonts.ini"; + int f_pointsize = ao_app->get_font_size(p_identifier, design_file); + QString font_name = ao_app->get_font_name(p_identifier + "_font", design_file); + QColor f_color = ao_app->get_color(p_identifier + "_color", design_file); + bool bold = ao_app->get_font_size(p_identifier + "_bold", design_file) == 1; // is the font bold or not? + bool antialias = ao_app->get_font_size(p_identifier + "_sharp", design_file) != 1; // is the font anti-aliased or not? - this->set_qfont(widget, class_name, get_qfont(font_name, f_pointsize, antialias), f_color, bold); + this->set_qfont(widget, class_name, get_qfont(font_name, f_pointsize, antialias), f_color, bold); } QFont Courtroom::get_qfont(QString font_name, int f_pointsize, bool antialias) { - QFont font; - if (font_name.isEmpty()) - font_name = "Arial"; + QFont font; + if (font_name.isEmpty()) + font_name = "Arial"; - QFont::StyleStrategy style_strategy = QFont::PreferDefault; - if (!antialias) - style_strategy = QFont::NoAntialias; + QFont::StyleStrategy style_strategy = QFont::PreferDefault; + if (!antialias) + style_strategy = QFont::NoAntialias; - font = QFont(font_name, f_pointsize); - font.setStyleHint(QFont::SansSerif, style_strategy); - return font; + font = QFont(font_name, f_pointsize); + font.setStyleHint(QFont::SansSerif, style_strategy); + return font; } void Courtroom::set_qfont(QWidget *widget, QString class_name, QFont font, QColor f_color, bool bold) { - if(class_name.isEmpty()) - class_name = widget->metaObject()->className(); + if (class_name.isEmpty()) + class_name = widget->metaObject()->className(); - font.setBold(bold); - widget->setFont(font); + font.setBold(bold); + widget->setFont(font); - QString style_sheet_string = class_name + " { background-color: rgba(0, 0, 0, 0);\n" + - "color: rgba(" + - QString::number(f_color.red()) + ", " + - QString::number(f_color.green()) + ", " + - QString::number(f_color.blue()) + ", 255);}"; - widget->setStyleSheet(style_sheet_string); + QString style_sheet_string = class_name + " { background-color: rgba(0, 0, 0, 0);\n" + + "color: rgba(" + + QString::number(f_color.red()) + ", " + + QString::number(f_color.green()) + ", " + + QString::number(f_color.blue()) + ", 255);}"; + widget->setStyleSheet(style_sheet_string); } void Courtroom::set_dropdown(QWidget *widget) { - QString f_file = "courtroom_stylesheets.css"; - QString style_sheet_string = ao_app->get_stylesheet(f_file); - if (style_sheet_string != "") - widget->setStyleSheet(style_sheet_string); + QString f_file = "courtroom_stylesheets.css"; + QString style_sheet_string = ao_app->get_stylesheet(f_file); + if (style_sheet_string != "") + widget->setStyleSheet(style_sheet_string); } void Courtroom::set_dropdowns() { - set_dropdown(this); //EXPERIMENTAL - Read the style-sheet as-is for maximum memeage -// set_dropdown(ui_text_color, "[TEXT COLOR]"); -// set_dropdown(ui_pos_dropdown, "[POS DROPDOWN]"); -// set_dropdown(ui_emote_dropdown, "[EMOTE DROPDOWN]"); -// set_dropdown(ui_mute_list, "[MUTE LIST]"); + set_dropdown(this); //EXPERIMENTAL - Read the style-sheet as-is for maximum memeage + // set_dropdown(ui_text_color, "[TEXT COLOR]"); + // set_dropdown(ui_pos_dropdown, "[POS DROPDOWN]"); + // set_dropdown(ui_emote_dropdown, "[EMOTE DROPDOWN]"); + // set_dropdown(ui_mute_list, "[MUTE LIST]"); } void Courtroom::set_window_title(QString p_title) { - this->setWindowTitle(p_title); + this->setWindowTitle(p_title); } void Courtroom::set_size_and_pos(QWidget *p_widget, QString p_identifier) { - QString filename = "courtroom_design.ini"; + QString filename = "courtroom_design.ini"; - pos_size_type design_ini_result = ao_app->get_element_dimensions(p_identifier, filename); + pos_size_type design_ini_result = ao_app->get_element_dimensions(p_identifier, filename); - if (design_ini_result.width < 0 || design_ini_result.height < 0) - { - qDebug() << "W: could not find \"" << p_identifier << "\" in " << filename; - p_widget->hide(); - } - else - { - p_widget->move(design_ini_result.x, design_ini_result.y); - p_widget->resize(design_ini_result.width, design_ini_result.height); - } + if (design_ini_result.width < 0 || design_ini_result.height < 0) { + qDebug() << "W: could not find \"" << p_identifier << "\" in " << filename; + p_widget->hide(); + } + else { + p_widget->move(design_ini_result.x, design_ini_result.y); + p_widget->resize(design_ini_result.width, design_ini_result.height); + } } void Courtroom::set_taken(int n_char, bool p_taken) { - if (n_char >= char_list.size()) - { - qDebug() << "W: set_taken attempted to set an index bigger than char_list size"; - return; - } + if (n_char >= char_list.size()) { + qDebug() << "W: set_taken attempted to set an index bigger than char_list size"; + return; + } - char_type f_char; - f_char.name = char_list.at(n_char).name; - f_char.description = char_list.at(n_char).description; - f_char.taken = p_taken; - f_char.evidence_string = char_list.at(n_char).evidence_string; + char_type f_char; + f_char.name = char_list.at(n_char).name; + f_char.description = char_list.at(n_char).description; + f_char.taken = p_taken; + f_char.evidence_string = char_list.at(n_char).evidence_string; - char_list.replace(n_char, f_char); + char_list.replace(n_char, f_char); } QPoint Courtroom::get_theme_pos(QString p_identifier) { - QString filename = "courtroom_design.ini"; + QString filename = "courtroom_design.ini"; - pos_size_type design_ini_result = ao_app->get_element_dimensions(p_identifier, filename); + pos_size_type design_ini_result = ao_app->get_element_dimensions(p_identifier, filename); - if (design_ini_result.width < 0 || design_ini_result.height < 0) - { - qDebug() << "W: could not find \"" << p_identifier << "\" in " << filename; - return QPoint(0,0); - } - else - { - return QPoint(design_ini_result.x, design_ini_result.y); - } + if (design_ini_result.width < 0 || design_ini_result.height < 0) { + qDebug() << "W: could not find \"" << p_identifier << "\" in " << filename; + return QPoint(0, 0); + } + else { + return QPoint(design_ini_result.x, design_ini_result.y); + } } void Courtroom::done_received() { - m_cid = -1; + m_cid = -1; - music_player->set_volume(0); - sfx_player->set_volume(0); - objection_player->set_volume(0); - blip_player->set_volume(0); + music_player->set_volume(0); + sfx_player->set_volume(0); + objection_player->set_volume(0); + blip_player->set_volume(0); - set_char_select_page(); + set_char_select_page(); - set_mute_list(); - set_pair_list(); + set_mute_list(); + set_pair_list(); - set_char_select(); + set_char_select(); - show(); + show(); - ui_spectator->show(); + ui_spectator->show(); } void Courtroom::set_background(QString p_background, bool display) { - ui_vp_testimony->stop(); - current_background = p_background; + ui_vp_testimony->stop(); + current_background = p_background; - //welcome to hardcode central may I take your order of regularly scheduled CBT - QMap default_pos; - default_pos["defenseempty"] = "def"; - default_pos["helperstand"] = "hld"; - default_pos["prosecutorempty"] = "pro"; - default_pos["prohelperstand"] = "hlp"; - default_pos["witnessempty"] = "wit"; - default_pos["judgestand"] = "jud"; - default_pos["jurystand"] = "jur"; - default_pos["seancestand"] = "sea"; + //welcome to hardcode central may I take your order of regularly scheduled CBT + QMap default_pos; + default_pos["defenseempty"] = "def"; + default_pos["helperstand"] = "hld"; + default_pos["prosecutorempty"] = "pro"; + default_pos["prohelperstand"] = "hlp"; + default_pos["witnessempty"] = "wit"; + default_pos["judgestand"] = "jud"; + default_pos["jurystand"] = "jur"; + default_pos["seancestand"] = "sea"; - //Populate the dropdown list with all pos that exist on this bg - QStringList pos_list = {}; - for (QString key : default_pos.keys()) - { - if (file_exists(ao_app->get_static_image_suffix(ao_app->get_background_path(key)))) - { - pos_list.append(default_pos[key]); + //Populate the dropdown list with all pos that exist on this bg + QStringList pos_list = {}; + for (QString key : default_pos.keys()) { + if (file_exists(ao_app->get_static_image_suffix(ao_app->get_background_path(key)))) { + pos_list.append(default_pos[key]); + } } - } - //TODO: search through extra/custom pos and add them to the pos dropdown as well + //TODO: search through extra/custom pos and add them to the pos dropdown as well - set_pos_dropdown(pos_list); + set_pos_dropdown(pos_list); - is_ao2_bg = true; + is_ao2_bg = true; - if (is_ao2_bg) - { - set_size_and_pos(ui_vp_chatbox, "ao2_chatbox"); - set_size_and_pos(ui_ic_chat_message, "ao2_ic_chat_message"); - } - else - { - set_size_and_pos(ui_vp_chatbox, "chatbox"); - set_size_and_pos(ui_ic_chat_message, "ic_chat_message"); - } + if (is_ao2_bg) { + set_size_and_pos(ui_vp_chatbox, "ao2_chatbox"); + set_size_and_pos(ui_ic_chat_message, "ao2_ic_chat_message"); + } + else { + set_size_and_pos(ui_vp_chatbox, "chatbox"); + set_size_and_pos(ui_ic_chat_message, "ic_chat_message"); + } - if (display) - { - ui_vp_speedlines->stop(); - ui_vp_player_char->stop(); + if (display) { + ui_vp_speedlines->stop(); + ui_vp_player_char->stop(); - ui_vp_sideplayer_char->stop(); - ui_vp_effect->stop(); - ui_vp_message->hide(); - ui_vp_chatbox->hide(); + ui_vp_sideplayer_char->stop(); + ui_vp_effect->stop(); + ui_vp_message->hide(); + ui_vp_chatbox->hide(); - //Stop the chat arrow from animating - ui_vp_chat_arrow->stop(); + //Stop the chat arrow from animating + ui_vp_chat_arrow->stop(); - text_state = 2; - anim_state = 3; - ui_vp_objection->stop(); - chat_tick_timer->stop(); - ui_vp_evidence_display->reset(); - set_scene(QString::number(ao_app->get_desk_mod(current_char, current_emote)), current_side); - } + text_state = 2; + anim_state = 3; + ui_vp_objection->stop(); + chat_tick_timer->stop(); + ui_vp_evidence_display->reset(); + set_scene(QString::number(ao_app->get_desk_mod(current_char, current_emote)), current_side); + } } void Courtroom::set_side(QString p_side) { - if (p_side == "") - current_side = ao_app->get_char_side(current_char); - else - current_side = p_side; + if (p_side == "") + current_side = ao_app->get_char_side(current_char); + else + current_side = p_side; - for (int i = 0; i < ui_pos_dropdown->count(); ++i) - { - QString pos = ui_pos_dropdown->itemText(i); - if (pos == current_side) - { - //Block the signals to prevent setCurrentIndex from triggering a pos change - ui_pos_dropdown->blockSignals(true); + for (int i = 0; i < ui_pos_dropdown->count(); ++i) { + QString pos = ui_pos_dropdown->itemText(i); + if (pos == current_side) { + //Block the signals to prevent setCurrentIndex from triggering a pos change + ui_pos_dropdown->blockSignals(true); - //Set the index on dropdown ui element to let you know what pos you're on right now - ui_pos_dropdown->setCurrentIndex(i); + //Set the index on dropdown ui element to let you know what pos you're on right now + ui_pos_dropdown->setCurrentIndex(i); - //Unblock the signals so the element can be used for setting pos again - ui_pos_dropdown->blockSignals(false); + //Unblock the signals so the element can be used for setting pos again + ui_pos_dropdown->blockSignals(false); - //alright we dun, jobs done here boyos - break; + //alright we dun, jobs done here boyos + break; + } } - } } void Courtroom::set_pos_dropdown(QStringList pos_dropdowns) { - //Block the signals to prevent setCurrentIndex from triggering a pos change - ui_pos_dropdown->blockSignals(true); - pos_dropdown_list = pos_dropdowns; - ui_pos_dropdown->clear(); - ui_pos_dropdown->addItems(pos_dropdown_list); - //Unblock the signals so the element can be used for setting pos again - ui_pos_dropdown->blockSignals(false); + //Block the signals to prevent setCurrentIndex from triggering a pos change + ui_pos_dropdown->blockSignals(true); + pos_dropdown_list = pos_dropdowns; + ui_pos_dropdown->clear(); + ui_pos_dropdown->addItems(pos_dropdown_list); + //Unblock the signals so the element can be used for setting pos again + ui_pos_dropdown->blockSignals(false); - qDebug() << pos_dropdown_list; + qDebug() << pos_dropdown_list; } void Courtroom::update_character(int p_cid) { - bool newchar = m_cid != p_cid; + bool newchar = m_cid != p_cid; - m_cid = p_cid; + m_cid = p_cid; - QString f_char; + QString f_char; - if (m_cid == -1) - { - if (ao_app->is_discord_enabled()) - ao_app->discord->state_spectate(); - f_char = ""; - } - else - { - f_char = ao_app->get_char_name(char_list.at(m_cid).name); + if (m_cid == -1) { + if (ao_app->is_discord_enabled()) + ao_app->discord->state_spectate(); + f_char = ""; + } + else { + f_char = ao_app->get_char_name(char_list.at(m_cid).name); - if (ao_app->is_discord_enabled()) - ao_app->discord->state_character(f_char.toStdString()); - } + if (ao_app->is_discord_enabled()) + ao_app->discord->state_character(f_char.toStdString()); + } - current_char = f_char; - current_side = ao_app->get_char_side(current_char); + current_char = f_char; + current_side = ao_app->get_char_side(current_char); - current_emote_page = 0; - current_emote = 0; + current_emote_page = 0; + current_emote = 0; - if (m_cid == -1) - ui_emotes->hide(); - else - ui_emotes->show(); + if (m_cid == -1) + ui_emotes->hide(); + else + ui_emotes->show(); - refresh_emotes(); - set_emote_page(); - set_emote_dropdown(); + refresh_emotes(); + set_emote_page(); + set_emote_dropdown(); - set_sfx_dropdown(); - set_effects_dropdown(); + set_sfx_dropdown(); + set_effects_dropdown(); - qDebug() << "update_character called"; - if (newchar) //Avoid infinite loop of death and suffering - set_iniswap_dropdown(); + qDebug() << "update_character called"; + if (newchar) //Avoid infinite loop of death and suffering + set_iniswap_dropdown(); - if (current_side == "jud") - { - ui_witness_testimony->show(); - ui_cross_examination->show(); - ui_not_guilty->show(); - ui_guilty->show(); - ui_defense_minus->show(); - ui_defense_plus->show(); - ui_prosecution_minus->show(); - ui_prosecution_plus->show(); - } - else - { - ui_witness_testimony->hide(); - ui_cross_examination->hide(); - ui_guilty->hide(); - ui_not_guilty->hide(); - ui_defense_minus->hide(); - ui_defense_plus->hide(); - ui_prosecution_minus->hide(); - ui_prosecution_plus->hide(); - } + if (current_side == "jud") { + ui_witness_testimony->show(); + ui_cross_examination->show(); + ui_not_guilty->show(); + ui_guilty->show(); + ui_defense_minus->show(); + ui_defense_plus->show(); + ui_prosecution_minus->show(); + ui_prosecution_plus->show(); + } + else { + ui_witness_testimony->hide(); + ui_cross_examination->hide(); + ui_guilty->hide(); + ui_not_guilty->hide(); + ui_defense_minus->hide(); + ui_defense_plus->hide(); + ui_prosecution_minus->hide(); + ui_prosecution_plus->hide(); + } - if (ao_app->custom_objection_enabled && file_exists(ao_app->get_image_suffix(ao_app->get_character_path(current_char, "custom")))) - ui_custom_objection->show(); - else - ui_custom_objection->hide(); + if (ao_app->custom_objection_enabled && file_exists(ao_app->get_image_suffix(ao_app->get_character_path(current_char, "custom")))) + ui_custom_objection->show(); + else + ui_custom_objection->hide(); - ui_char_select_background->hide(); - ui_ic_chat_message->setEnabled(m_cid != -1); - ui_ic_chat_message->setFocus(); + ui_char_select_background->hide(); + ui_ic_chat_message->setEnabled(m_cid != -1); + ui_ic_chat_message->setFocus(); } void Courtroom::enter_courtroom() { - set_widgets(); + set_widgets(); - current_evidence_page = 0; - current_evidence = 0; + current_evidence_page = 0; + current_evidence = 0; - set_evidence_page(); + set_evidence_page(); - if (ao_app->flipping_enabled) - ui_flip->show(); - else - ui_flip->hide(); + if (ao_app->flipping_enabled) + ui_flip->show(); + else + ui_flip->hide(); - if (ao_app->additive_enabled) - ui_additive->show(); - else - ui_additive->hide(); + if (ao_app->additive_enabled) + ui_additive->show(); + else + ui_additive->hide(); - if (ao_app->casing_alerts_enabled) - ui_casing->show(); - else - ui_casing->hide(); + if (ao_app->casing_alerts_enabled) + ui_casing->show(); + else + ui_casing->hide(); - list_music(); - list_areas(); + list_music(); + list_areas(); - music_player->set_volume(ui_music_slider->value(), 0); //set music - //Set the ambience and other misc. music layers - for (int i = 1; i < music_player->m_channelmax; ++i) - { - music_player->set_volume(ui_sfx_slider->value(), i); - } - sfx_player->set_volume(ui_sfx_slider->value()); - objection_player->set_volume(ui_sfx_slider->value()); - blip_player->set_volume(ui_blip_slider->value()); + music_player->set_volume(ui_music_slider->value(), 0); //set music + //Set the ambience and other misc. music layers + for (int i = 1; i < music_player->m_channelmax; ++i) { + music_player->set_volume(ui_sfx_slider->value(), i); + } + sfx_player->set_volume(ui_sfx_slider->value()); + objection_player->set_volume(ui_sfx_slider->value()); + blip_player->set_volume(ui_blip_slider->value()); - ui_vp_testimony->stop(); - //ui_server_chatlog->setHtml(ui_server_chatlog->toHtml()); + ui_vp_testimony->stop(); + //ui_server_chatlog->setHtml(ui_server_chatlog->toHtml()); } //Todo: multithread this due to some servers having large as hell music list void Courtroom::list_music() { - ui_music_list->clear(); -// ui_music_search->setText(""); + ui_music_list->clear(); + // ui_music_search->setText(""); - QString f_file = "courtroom_design.ini"; + QString f_file = "courtroom_design.ini"; - QBrush found_brush(ao_app->get_color("found_song_color", f_file)); - QBrush missing_brush(ao_app->get_color("missing_song_color", f_file)); + QBrush found_brush(ao_app->get_color("found_song_color", f_file)); + QBrush missing_brush(ao_app->get_color("missing_song_color", f_file)); - int n_listed_songs = 0; + int n_listed_songs = 0; - QTreeWidgetItem *parent = nullptr; - for (int n_song = 0 ; n_song < music_list.size() ; ++n_song) - { - QString i_song = music_list.at(n_song); - QString i_song_listname = i_song.left(i_song.lastIndexOf(".")); - i_song_listname = i_song_listname.right(i_song_listname.length() - (i_song_listname.lastIndexOf("/") + 1)); + QTreeWidgetItem *parent = nullptr; + for (int n_song = 0; n_song < music_list.size(); ++n_song) { + QString i_song = music_list.at(n_song); + QString i_song_listname = i_song.left(i_song.lastIndexOf(".")); + i_song_listname = i_song_listname.right(i_song_listname.length() - (i_song_listname.lastIndexOf("/") + 1)); - QTreeWidgetItem *treeItem; - if (i_song_listname != i_song && parent != nullptr) //not a category, parent exists - treeItem = new QTreeWidgetItem(parent); - else - treeItem = new QTreeWidgetItem(ui_music_list); - treeItem->setText(0, i_song_listname); - treeItem->setText(1, i_song); + QTreeWidgetItem *treeItem; + if (i_song_listname != i_song && parent != nullptr) //not a category, parent exists + treeItem = new QTreeWidgetItem(parent); + else + treeItem = new QTreeWidgetItem(ui_music_list); + treeItem->setText(0, i_song_listname); + treeItem->setText(1, i_song); - QString song_path = ao_app->get_music_path(i_song); + QString song_path = ao_app->get_music_path(i_song); - if (file_exists(song_path)) - treeItem->setBackground(0, found_brush); - else - treeItem->setBackground(0, missing_brush); + if (file_exists(song_path)) + treeItem->setBackground(0, found_brush); + else + treeItem->setBackground(0, missing_brush); - if (i_song_listname == i_song) //Not supposed to be a song to begin with - a category? - parent = treeItem; - ++n_listed_songs; - } + if (i_song_listname == i_song) //Not supposed to be a song to begin with - a category? + parent = treeItem; + ++n_listed_songs; + } - ui_music_list->expandAll(); //Needs to somehow remember which categories were expanded/collapsed if the music list didn't change since last time - if (ui_music_search->text() != "") - { - on_music_search_edited(ui_music_search->text()); - } + ui_music_list->expandAll(); //Needs to somehow remember which categories were expanded/collapsed if the music list didn't change since last time + if (ui_music_search->text() != "") { + on_music_search_edited(ui_music_search->text()); + } } //Todo: multithread this due to some servers having large as hell area list void Courtroom::list_areas() { - ui_area_list->clear(); -// ui_music_search->setText(""); + ui_area_list->clear(); + // ui_music_search->setText(""); - QString f_file = "courtroom_design.ini"; + QString f_file = "courtroom_design.ini"; - QBrush free_brush(ao_app->get_color("area_free_color", f_file)); - QBrush lfp_brush(ao_app->get_color("area_lfp_color", f_file)); - QBrush casing_brush(ao_app->get_color("area_casing_color", f_file)); - QBrush recess_brush(ao_app->get_color("area_recess_color", f_file)); - QBrush rp_brush(ao_app->get_color("area_rp_color", f_file)); - QBrush gaming_brush(ao_app->get_color("area_gaming_color", f_file)); - QBrush locked_brush(ao_app->get_color("area_locked_color", f_file)); + QBrush free_brush(ao_app->get_color("area_free_color", f_file)); + QBrush lfp_brush(ao_app->get_color("area_lfp_color", f_file)); + QBrush casing_brush(ao_app->get_color("area_casing_color", f_file)); + QBrush recess_brush(ao_app->get_color("area_recess_color", f_file)); + QBrush rp_brush(ao_app->get_color("area_rp_color", f_file)); + QBrush gaming_brush(ao_app->get_color("area_gaming_color", f_file)); + QBrush locked_brush(ao_app->get_color("area_locked_color", f_file)); - int n_listed_areas = 0; + int n_listed_areas = 0; - for (int n_area = 0 ; n_area < area_list.size() ; ++n_area) - { - QString i_area = ""; - i_area.append(area_list.at(n_area)); + for (int n_area = 0; n_area < area_list.size(); ++n_area) { + QString i_area = ""; + i_area.append(area_list.at(n_area)); - if (ao_app->arup_enabled) - { - i_area.prepend("[" + QString::number(n_area) + "] "); //Give it the index + if (ao_app->arup_enabled) { + i_area.prepend("[" + QString::number(n_area) + "] "); //Give it the index - i_area.append("\n "); + i_area.append("\n "); - i_area.append(arup_statuses.at(n_area)); - i_area.append(" | CM: "); - i_area.append(arup_cms.at(n_area)); + i_area.append(arup_statuses.at(n_area)); + i_area.append(" | CM: "); + i_area.append(arup_cms.at(n_area)); - i_area.append("\n "); + i_area.append("\n "); - i_area.append(QString::number(arup_players.at(n_area))); - i_area.append(" users | "); + i_area.append(QString::number(arup_players.at(n_area))); + i_area.append(" users | "); - i_area.append(arup_locks.at(n_area)); + i_area.append(arup_locks.at(n_area)); + } + + QTreeWidgetItem *treeItem = new QTreeWidgetItem(ui_area_list); + treeItem->setText(0, area_list.at(n_area)); + treeItem->setText(1, i_area); + + if (ao_app->arup_enabled) { + // 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); + } + } + else { + treeItem->setBackground(1, free_brush); + } + + ++n_listed_areas; } - QTreeWidgetItem *treeItem = new QTreeWidgetItem(ui_area_list); - treeItem->setText(0, area_list.at(n_area)); - treeItem->setText(1, i_area); - - if (ao_app->arup_enabled) - { - // 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); - } + if (ui_music_search->text() != "") { + on_music_search_edited(ui_music_search->text()); } - else - { - treeItem->setBackground(1, free_brush); - } - - ++n_listed_areas; - } - - if (ui_music_search->text() != "") - { - on_music_search_edited(ui_music_search->text()); - } } void Courtroom::append_ms_chatmessage(QString f_name, QString f_message) { - ui_ms_chatlog->append_chatmessage(f_name, f_message, ao_app->get_color("ms_chatlog_sender_color", "courtroom_fonts.ini").name()); + ui_ms_chatlog->append_chatmessage(f_name, f_message, ao_app->get_color("ms_chatlog_sender_color", "courtroom_fonts.ini").name()); } void Courtroom::append_server_chatmessage(QString p_name, QString p_message, QString p_color) { - QString color = "#000000"; + QString color = "#000000"; - if (p_color == "0") - color = ao_app->get_color("ms_chatlog_sender_color", "courtroom_fonts.ini").name(); - if (p_color == "1") - color = ao_app->get_color("server_chatlog_sender_color", "courtroom_fonts.ini").name(); - if(p_message == "Logged in as a moderator.") - { - ui_guard->show(); - append_server_chatmessage("CLIENT", "You were granted the Disable Modcalls button.", "1"); - } + if (p_color == "0") + color = ao_app->get_color("ms_chatlog_sender_color", "courtroom_fonts.ini").name(); + if (p_color == "1") + color = ao_app->get_color("server_chatlog_sender_color", "courtroom_fonts.ini").name(); + if (p_message == "Logged in as a moderator.") { + ui_guard->show(); + append_server_chatmessage("CLIENT", "You were granted the Disable Modcalls button.", "1"); + } - ui_server_chatlog->append_chatmessage(p_name, p_message, color); + ui_server_chatlog->append_chatmessage(p_name, p_message, color); } void Courtroom::on_chat_return_pressed() { - if (ui_ic_chat_message->text() == "" || is_muted) - return; + if (ui_ic_chat_message->text() == "" || is_muted) + return; - if ((anim_state < 3 || text_state < 2) && - objection_state == 0) - return; + if ((anim_state < 3 || text_state < 2) && + objection_state == 0) + return; - //MS# - //deskmod# - //pre-emote# - //character# - //emote# - //message# - //side# - //sfx-name# - //emote_modifier# - //char_id# - //sfx_delay# - //objection_modifier# - //evidence# - //placeholder# - //realization# - //text_color#% + //MS# + //deskmod# + //pre-emote# + //character# + //emote# + //message# + //side# + //sfx-name# + //emote_modifier# + //char_id# + //sfx_delay# + //objection_modifier# + //evidence# + //placeholder# + //realization# + //text_color#% - // Additionally, in our case: + // Additionally, in our case: - //showname# - //other_charid# - //self_offset# - //noninterrupting_preanim#% + //showname# + //other_charid# + //self_offset# + //noninterrupting_preanim#% - QStringList packet_contents; + QStringList packet_contents; - if (current_side == "") - current_side = ao_app->get_char_side(current_char); + if (current_side == "") + current_side = ao_app->get_char_side(current_char); - QString f_desk_mod = "chat"; + QString f_desk_mod = "chat"; - if (ao_app->desk_mod_enabled) - { - f_desk_mod = QString::number(ao_app->get_desk_mod(current_char, current_emote)); - if (f_desk_mod == "-1") - f_desk_mod = "chat"; - } - - packet_contents.append(f_desk_mod); - - packet_contents.append(ao_app->get_pre_emote(current_char, current_emote)); - - packet_contents.append(current_char); - - packet_contents.append(ao_app->get_emote(current_char, current_emote)); - - packet_contents.append(ui_ic_chat_message->text()); - - packet_contents.append(current_side); - - packet_contents.append(get_char_sfx()); - if (ui_pre->isChecked() && !ao_app->is_stickysounds_enabled()) - { - ui_sfx_dropdown->blockSignals(true); - ui_sfx_dropdown->setCurrentIndex(0); - ui_sfx_dropdown->blockSignals(false); - ui_sfx_remove->hide(); - } - - int f_emote_mod = ao_app->get_emote_mod(current_char, current_emote); - - //needed or else legacy won't understand what we're saying - if (objection_state > 0) - { - if (ui_pre->isChecked()) - { - if (f_emote_mod == 4 || f_emote_mod == 5) - f_emote_mod = 6; - else - f_emote_mod = 2; - } - } - else if (ui_pre->isChecked() and !ui_pre_non_interrupt->isChecked()) - { - if (f_emote_mod == 0) - f_emote_mod = 1; - else if (f_emote_mod == 5 && ao_app->prezoom_enabled) - f_emote_mod = 4; - } - else - { - if (f_emote_mod == 1) - f_emote_mod = 0; - else if (f_emote_mod == 4) - f_emote_mod = 5; - } - - packet_contents.append(QString::number(f_emote_mod)); - packet_contents.append(QString::number(m_cid)); - - packet_contents.append(QString::number(get_char_sfx_delay())); - - QString f_obj_state; - - if ((objection_state == 4 && !ao_app->custom_objection_enabled) || - (objection_state < 0)) - f_obj_state = "0"; - else - f_obj_state = QString::number(objection_state); - - packet_contents.append(f_obj_state); - - if (is_presenting_evidence) - //the evidence index is shifted by 1 because 0 is no evidence per legacy standards - //besides, older clients crash if we pass -1 - packet_contents.append(QString::number(current_evidence + 1)); - else - packet_contents.append("0"); - - QString f_flip; - - if (ao_app->flipping_enabled) - { - if (ui_flip->isChecked()) - f_flip = "1"; - else - f_flip = "0"; - } - else - f_flip = QString::number(m_cid); - - packet_contents.append(f_flip); - - packet_contents.append(QString::number(realization_state)); - - QString f_text_color; - - if (text_color < 0) - f_text_color = "0"; - else if (text_color > max_colors) - f_text_color = "0"; - else - f_text_color = QString::number(text_color); - - packet_contents.append(f_text_color); - - // If the server we're on supports CCCC stuff, we should use it! - if (ao_app->cccc_ic_support_enabled) - { - // 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(""); + if (ao_app->desk_mod_enabled) { + f_desk_mod = QString::number(ao_app->get_desk_mod(current_char, current_emote)); + if (f_desk_mod == "-1") + f_desk_mod = "chat"; } - // 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_enabled) //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 - packet_contents.append(QString::number(char_offset)); + packet_contents.append(f_desk_mod); - // Finally, we send over if we want our pres to not interrupt. - if (ui_pre_non_interrupt->isChecked() && ui_pre->isChecked()) - { - packet_contents.append("1"); + packet_contents.append(ao_app->get_pre_emote(current_char, current_emote)); + + packet_contents.append(current_char); + + packet_contents.append(ao_app->get_emote(current_char, current_emote)); + + packet_contents.append(ui_ic_chat_message->text()); + + packet_contents.append(current_side); + + packet_contents.append(get_char_sfx()); + if (ui_pre->isChecked() && !ao_app->is_stickysounds_enabled()) { + ui_sfx_dropdown->blockSignals(true); + ui_sfx_dropdown->setCurrentIndex(0); + ui_sfx_dropdown->blockSignals(false); + ui_sfx_remove->hide(); } - 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_support_enabled) - { - packet_contents.append("0"); //ao_app->get_sfx_looping(current_char, current_emote)); - packet_contents.append(QString::number(screenshake_state)); + int f_emote_mod = ao_app->get_emote_mod(current_char, current_emote); - 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 (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 += "^"; + //needed or else legacy won't understand what we're saying + if (objection_state > 0) { + if (ui_pre->isChecked()) { + if (f_emote_mod == 4 || f_emote_mod == 5) + f_emote_mod = 6; + else + f_emote_mod = 2; } - packet_contents.append(packet); - } - } - - if (ao_app->additive_enabled) - { - packet_contents.append(ui_additive->isChecked() ? "1" : "0"); - } - if (ao_app->effects_enabled) - { - QString fx_sound = ao_app->get_effect_sound(effect, current_char); - QString p_effect = ao_app->read_char_ini(current_char, "effects", "Options"); - packet_contents.append(effect + "|" + p_effect + "|" + fx_sound); - if (!ao_app->is_stickyeffects_enabled()) - { - ui_effects_dropdown->blockSignals(true); - ui_effects_dropdown->setCurrentIndex(0); - ui_effects_dropdown->blockSignals(false); - effect = ""; } - } + else if (ui_pre->isChecked() and !ui_pre_non_interrupt->isChecked()) { + if (f_emote_mod == 0) + f_emote_mod = 1; + else if (f_emote_mod == 5 && ao_app->prezoom_enabled) + f_emote_mod = 4; + } + else { + if (f_emote_mod == 1) + f_emote_mod = 0; + else if (f_emote_mod == 4) + f_emote_mod = 5; + } - ao_app->send_server_packet(new AOPacket("MS", packet_contents)); + packet_contents.append(QString::number(f_emote_mod)); + packet_contents.append(QString::number(m_cid)); + + packet_contents.append(QString::number(get_char_sfx_delay())); + + QString f_obj_state; + + if ((objection_state == 4 && !ao_app->custom_objection_enabled) || + (objection_state < 0)) + f_obj_state = "0"; + else + f_obj_state = QString::number(objection_state); + + packet_contents.append(f_obj_state); + + if (is_presenting_evidence) + //the evidence index is shifted by 1 because 0 is no evidence per legacy standards + //besides, older clients crash if we pass -1 + packet_contents.append(QString::number(current_evidence + 1)); + else + packet_contents.append("0"); + + QString f_flip; + + if (ao_app->flipping_enabled) { + if (ui_flip->isChecked()) + f_flip = "1"; + else + f_flip = "0"; + } + else + f_flip = QString::number(m_cid); + + packet_contents.append(f_flip); + + packet_contents.append(QString::number(realization_state)); + + QString f_text_color; + + if (text_color < 0) + f_text_color = "0"; + else if (text_color > max_colors) + f_text_color = "0"; + else + f_text_color = QString::number(text_color); + + packet_contents.append(f_text_color); + + // If the server we're on supports CCCC stuff, we should use it! + if (ao_app->cccc_ic_support_enabled) { + // 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_enabled) //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 + packet_contents.append(QString::number(char_offset)); + + // Finally, we send over if we want our pres to not interrupt. + if (ui_pre_non_interrupt->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_support_enabled) { + packet_contents.append("0"); //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 (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 += "^"; + } + packet_contents.append(packet); + } + } + + if (ao_app->additive_enabled) { + packet_contents.append(ui_additive->isChecked() ? "1" : "0"); + } + if (ao_app->effects_enabled) { + QString fx_sound = ao_app->get_effect_sound(effect, current_char); + QString p_effect = ao_app->read_char_ini(current_char, "effects", "Options"); + packet_contents.append(effect + "|" + p_effect + "|" + fx_sound); + if (!ao_app->is_stickyeffects_enabled()) { + ui_effects_dropdown->blockSignals(true); + ui_effects_dropdown->setCurrentIndex(0); + ui_effects_dropdown->blockSignals(false); + effect = ""; + } + } + + ao_app->send_server_packet(new AOPacket("MS", packet_contents)); } void Courtroom::handle_chatmessage(QStringList *p_contents) { - // Instead of checking for whether a message has at least chatmessage_size - // amount of packages, we'll check if it has at least 15. - // That was the original chatmessage_size. - if (p_contents->size() < 15) - return; + // Instead of checking for whether a message has at least chatmessage_size + // amount of packages, we'll check if it has at least 15. + // That was the original chatmessage_size. + if (p_contents->size() < 15) + return; - for (int n_string = 0 ; n_string < chatmessage_size ; ++n_string) - { - //m_chatmessage[n_string] = p_contents->at(n_string); + for (int n_string = 0; n_string < chatmessage_size; ++n_string) { + //m_chatmessage[n_string] = p_contents->at(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 < 15 || ao_app->cccc_ic_support_enabled)) - { - m_chatmessage[n_string] = p_contents->at(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 < 15 || ao_app->cccc_ic_support_enabled)) { + m_chatmessage[n_string] = p_contents->at(n_string); + } + else { + m_chatmessage[n_string] = ""; + } + } + + int f_char_id = m_chatmessage[CHAR_ID].toInt(); + + if (f_char_id >= 0 && f_char_id >= char_list.size()) + return; + + if (mute_map.value(m_chatmessage[CHAR_ID].toInt())) + return; + + QString f_showname; + if (f_char_id > 0 && (m_chatmessage[SHOWNAME].isEmpty() || !ui_showname_enable->isChecked())) { + f_showname = ao_app->get_showname(char_list.at(f_char_id).name); + } + else { + f_showname = m_chatmessage[SHOWNAME]; + } + + if (f_showname.trimmed().isEmpty()) //Pure whitespace showname, get outta here. + f_showname = m_chatmessage[CHAR_NAME]; + + QString f_message = f_showname + ": " + m_chatmessage[MESSAGE] + '\n'; + //Remove undesired newline chars + m_chatmessage[MESSAGE].remove("\n"); + chatmessage_is_empty = m_chatmessage[MESSAGE] == " " || m_chatmessage[MESSAGE] == ""; + + if (f_char_id >= 0 && !chatmessage_is_empty && f_message == previous_ic_message) //Not a system message + return; + + if (f_char_id <= -1) + previous_ic_message = ""; //System messages don't care about repeating themselves + else + previous_ic_message = f_message; + + //Stop the chat arrow from animating + ui_vp_chat_arrow->stop(); + + text_state = 0; + anim_state = 0; + ui_vp_objection->stop(); + chat_tick_timer->stop(); + ui_vp_evidence_display->reset(); + + //Hey, our message showed up! Cool! + if (m_chatmessage[MESSAGE] == ui_ic_chat_message->text().remove("\n") && m_chatmessage[CHAR_ID].toInt() == m_cid) { + ui_ic_chat_message->clear(); + if (ui_additive->isChecked()) + ui_ic_chat_message->insert(" "); + objection_state = 0; + realization_state = 0; + screenshake_state = 0; + is_presenting_evidence = false; + if (!ao_app->is_stickypres_enabled()) + ui_pre->setChecked(false); + ui_hold_it->set_image("holdit"); + ui_objection->set_image("objection"); + ui_take_that->set_image("takethat"); + ui_custom_objection->set_image("custom"); + ui_realization->set_image("realization"); + ui_screenshake->set_image("screenshake"); + ui_evidence_present->set_image("present"); + } + + //Let the server handle actually checking if they're allowed to do this. + is_additive = m_chatmessage[ADDITIVE].toInt() == 1; + + QString f_charname = ""; + if (f_char_id >= 0) + f_charname = ao_app->get_showname(char_list.at(f_char_id).name); + + chatlogpiece *temp = new chatlogpiece(f_charname, f_showname, m_chatmessage[MESSAGE], false); + ic_chatlog_history.append(*temp); + ao_app->append_to_file(temp->get_full(), ao_app->log_filename, true); + + while (ic_chatlog_history.size() > log_maximum_blocks && log_maximum_blocks > 0) { + ic_chatlog_history.removeFirst(); + } + + append_ic_text(m_chatmessage[MESSAGE], f_showname); + + int objection_mod = m_chatmessage[OBJECTION_MOD].toInt(); + QString f_char = m_chatmessage[CHAR_NAME]; + QString f_custom_theme = ao_app->get_char_shouts(f_char); + + //if an objection is used + if (objection_mod <= 4 && objection_mod >= 1) { + switch (objection_mod) { + case 1: + ui_vp_objection->play("holdit_bubble", f_char, f_custom_theme, 724); + objection_player->play("holdit", f_char, f_custom_theme); + break; + case 2: + ui_vp_objection->play("objection_bubble", f_char, f_custom_theme, 724); + objection_player->play("objection", f_char, f_custom_theme); + if (ao_app->objection_stop_music()) + music_player->stop(); + break; + case 3: + ui_vp_objection->play("takethat_bubble", f_char, f_custom_theme, 724); + objection_player->play("takethat", f_char, f_custom_theme); + break; + //case 4 is AO2 only + case 4: + ui_vp_objection->play("custom", f_char, f_custom_theme, 724); + objection_player->play("custom", f_char, f_custom_theme); + break; + default: + qDebug() << "W: Logic error in objection switch statement!"; + } + sfx_player->clear(); //Objection played! Cut all sfx. + int emote_mod = m_chatmessage[EMOTE_MOD].toInt(); + + if (emote_mod == 0) + m_chatmessage[EMOTE_MOD] = 1; } else - { - m_chatmessage[n_string] = ""; - } - } - - int f_char_id = m_chatmessage[CHAR_ID].toInt(); - - if (f_char_id >= 0 && f_char_id >= char_list.size()) - return; - - if (mute_map.value(m_chatmessage[CHAR_ID].toInt())) - return; - - QString f_showname; - if (f_char_id > 0 && (m_chatmessage[SHOWNAME].isEmpty() || !ui_showname_enable->isChecked())) - { - f_showname = ao_app->get_showname(char_list.at(f_char_id).name); - } - else - { - f_showname = m_chatmessage[SHOWNAME]; - } - - if(f_showname.trimmed().isEmpty()) //Pure whitespace showname, get outta here. - f_showname = m_chatmessage[CHAR_NAME]; - - - QString f_message = f_showname + ": " + m_chatmessage[MESSAGE] + '\n'; - //Remove undesired newline chars - m_chatmessage[MESSAGE].remove("\n"); - chatmessage_is_empty = m_chatmessage[MESSAGE] == " " || m_chatmessage[MESSAGE] == ""; - - if (f_char_id >= 0 && !chatmessage_is_empty && f_message == previous_ic_message) //Not a system message - return; - - if (f_char_id <= -1) - previous_ic_message = ""; //System messages don't care about repeating themselves - else - previous_ic_message = f_message; - - //Stop the chat arrow from animating - ui_vp_chat_arrow->stop(); - - text_state = 0; - anim_state = 0; - ui_vp_objection->stop(); - chat_tick_timer->stop(); - ui_vp_evidence_display->reset(); - - //Hey, our message showed up! Cool! - if (m_chatmessage[MESSAGE] == ui_ic_chat_message->text().remove("\n") && m_chatmessage[CHAR_ID].toInt() == m_cid) - { - ui_ic_chat_message->clear(); - if (ui_additive->isChecked()) - ui_ic_chat_message->insert(" "); - objection_state = 0; - realization_state = 0; - screenshake_state = 0; - is_presenting_evidence = false; - if (!ao_app->is_stickypres_enabled()) - ui_pre->setChecked(false); - ui_hold_it->set_image("holdit"); - ui_objection->set_image("objection"); - ui_take_that->set_image("takethat"); - ui_custom_objection->set_image("custom"); - ui_realization->set_image("realization"); - ui_screenshake->set_image("screenshake"); - ui_evidence_present->set_image("present"); - } - - //Let the server handle actually checking if they're allowed to do this. - is_additive = m_chatmessage[ADDITIVE].toInt() == 1; - - QString f_charname = ""; - if (f_char_id >= 0) - f_charname = ao_app->get_showname(char_list.at(f_char_id).name); - - chatlogpiece* temp = new chatlogpiece(f_charname, f_showname, m_chatmessage[MESSAGE], false); - ic_chatlog_history.append(*temp); - ao_app->append_to_file(temp->get_full(), ao_app->log_filename, true); - - while(ic_chatlog_history.size() > log_maximum_blocks && log_maximum_blocks > 0) - { - ic_chatlog_history.removeFirst(); - } - - append_ic_text(m_chatmessage[MESSAGE], f_showname); - - int objection_mod = m_chatmessage[OBJECTION_MOD].toInt(); - QString f_char = m_chatmessage[CHAR_NAME]; - QString f_custom_theme = ao_app->get_char_shouts(f_char); - - //if an objection is used - if (objection_mod <= 4 && objection_mod >= 1) - { - switch (objection_mod) - { - case 1: - ui_vp_objection->play("holdit_bubble", f_char, f_custom_theme, 724); - objection_player->play("holdit", f_char, f_custom_theme); - break; - case 2: - ui_vp_objection->play("objection_bubble", f_char, f_custom_theme, 724); - objection_player->play("objection", f_char, f_custom_theme); - if(ao_app->objection_stop_music()) - music_player->stop(); - break; - case 3: - ui_vp_objection->play("takethat_bubble", f_char, f_custom_theme, 724); - objection_player->play("takethat", f_char, f_custom_theme); - break; - //case 4 is AO2 only - case 4: - ui_vp_objection->play("custom", f_char, f_custom_theme, 724); - objection_player->play("custom", f_char, f_custom_theme); - break; - default: - qDebug() << "W: Logic error in objection switch statement!"; - } - sfx_player->clear(); //Objection played! Cut all sfx. - int emote_mod = m_chatmessage[EMOTE_MOD].toInt(); - - if (emote_mod == 0) - m_chatmessage[EMOTE_MOD] = 1; - } - else - handle_chatmessage_2(); + handle_chatmessage_2(); } void Courtroom::objection_done() { - handle_chatmessage_2(); + handle_chatmessage_2(); } void Courtroom::handle_chatmessage_2() { - ui_vp_speedlines->stop(); - ui_vp_player_char->stop(); - ui_vp_effect->stop(); - //Clear all looping sfx to prevent obnoxiousness - sfx_player->loop_clear(); + ui_vp_speedlines->stop(); + ui_vp_player_char->stop(); + ui_vp_effect->stop(); + //Clear all looping sfx to prevent obnoxiousness + sfx_player->loop_clear(); - if (!m_chatmessage[FRAME_SFX].isEmpty() && ao_app->is_frame_network_enabled()) - { - //ORDER IS IMPORTANT!! - QStringList netstrings = {m_chatmessage[FRAME_SCREENSHAKE], m_chatmessage[FRAME_REALIZATION], m_chatmessage[FRAME_SFX]}; - ui_vp_player_char->network_strings = netstrings; - } - else - ui_vp_player_char->network_strings.clear(); - - int f_charid = m_chatmessage[CHAR_ID].toInt(); - if (f_charid >= 0 && (m_chatmessage[SHOWNAME].isEmpty() || !ui_showname_enable->isChecked())) - { - QString real_name = char_list.at(f_charid).name; - - QString f_showname = ao_app->get_showname(real_name); - - ui_vp_showname->setText(f_showname); - } - else - { - ui_vp_showname->setText(m_chatmessage[SHOWNAME]); - } - - if(ui_vp_showname->text().trimmed().isEmpty()) //Whitespace showname - { - ui_vp_chatbox->set_image("chatblank"); - } - else //Aw yeah dude do some showname resizing magic - { - if (!ui_vp_chatbox->set_image("chat")) - ui_vp_chatbox->set_image("chatbox"); - - QFontMetrics fm(ui_vp_showname->font()); - int fm_width=fm.horizontalAdvance(ui_vp_showname->text()); - - QString chatbox_path = ao_app->get_theme_path("chat"); - QString chatbox = ao_app->get_chat(m_chatmessage[CHAR_NAME]); - if (chatbox != "") - { - 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"); - - pos_size_type design_ini_result = ao_app->get_element_dimensions("chat_arrow", "courtroom_design.ini", m_chatmessage[CHAR_NAME]); - 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(); - } - else - { - ui_vp_chat_arrow->move(design_ini_result.x, design_ini_result.y); - ui_vp_chat_arrow->combo_resize(design_ini_result.width, design_ini_result.height); - } + if (!m_chatmessage[FRAME_SFX].isEmpty() && ao_app->is_frame_network_enabled()) { + //ORDER IS IMPORTANT!! + QStringList netstrings = {m_chatmessage[FRAME_SCREENSHAKE], m_chatmessage[FRAME_REALIZATION], m_chatmessage[FRAME_SFX]}; + ui_vp_player_char->network_strings = netstrings; } - - pos_size_type default_width = ao_app->get_element_dimensions("showname", "courtroom_design.ini", m_chatmessage[CHAR_NAME]); - int extra_width = ao_app->get_design_element("showname_extra_width", "courtroom_design.ini", m_chatmessage[CHAR_NAME]).toInt(); - - if(extra_width > 0) - { - if (fm_width > default_width.width && ui_vp_chatbox->set_chatbox(chatbox_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_showname->resize(static_cast(default_width.width+(extra_width*2)), ui_vp_showname->height()); - } - } - else - ui_vp_showname->resize(default_width.width, ui_vp_showname->height()); - } - } - - ui_vp_message->hide(); - ui_vp_chatbox->hide(); - - //todo: put this in its own function or update - QString design_file = "courtroom_fonts.ini"; - int f_pointsize = ao_app->get_font_size("message", design_file); - QString font_name = ao_app->get_font_name("message_font", design_file); - QColor f_color = ao_app->get_color("message_color", design_file); - bool bold = ao_app->get_font_size("message_bold", design_file) == 1; // is the font bold or not? - bool antialias = ao_app->get_font_size("message_sharp", design_file) != 1; // is the font anti-aliased or not? - - QString chatfont = ao_app->get_chat_font(m_chatmessage[CHAR_NAME]); - if (chatfont != "") - font_name = chatfont; - - int chatsize = ao_app->get_chat_size(m_chatmessage[CHAR_NAME]); - if (chatsize != -1) - f_pointsize = chatsize; - this->set_qfont(ui_vp_message, "", get_qfont(font_name, f_pointsize, antialias), f_color, bold); - - set_scene(m_chatmessage[DESK_MOD], m_chatmessage[SIDE]); - - int emote_mod = m_chatmessage[EMOTE_MOD].toInt(); - - if (ao_app->flipping_enabled && m_chatmessage[FLIP].toInt() == 1) - ui_vp_player_char->set_flipped(true); - else - ui_vp_player_char->set_flipped(false); - - QString side = m_chatmessage[SIDE]; - - // Making the second character appear. - if (m_chatmessage[OTHER_CHARID].isEmpty()) - { - // If there is no second character, hide 'em - ui_vp_sideplayer_char->stop(); - ui_vp_sideplayer_char->move(0,0); - } - else - { - bool ok; - int got_other_charid = m_chatmessage[OTHER_CHARID].split("^")[0].toInt(&ok); - if (ok) - { - if (got_other_charid > -1) - { - // If there is, show them! - ui_vp_sideplayer_char->show(); - - int other_offset = m_chatmessage[OTHER_OFFSET].toInt(); - ui_vp_sideplayer_char->move(ui_viewport->width() * other_offset / 100, 0); - - QStringList args = m_chatmessage[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: - ui_vp_sideplayer_char->stackUnder(ui_vp_player_char); - break; - case 1: - ui_vp_player_char->stackUnder(ui_vp_sideplayer_char); - break; - default: - break; - } - } - - // We should probably also play the other character's idle emote. - if (ao_app->flipping_enabled && m_chatmessage[OTHER_FLIP].toInt() == 1) - ui_vp_sideplayer_char->set_flipped(true); - else - ui_vp_sideplayer_char->set_flipped(false); - ui_vp_sideplayer_char->play_idle(m_chatmessage[OTHER_NAME], m_chatmessage[OTHER_EMOTE]); - } - else - { - // If the server understands other characters, but there - // really is no second character, hide 'em, and center the first. - ui_vp_sideplayer_char->hide(); - ui_vp_sideplayer_char->move(0,0); - } - } - } - //Set ourselves according to SELF_OFFSET - - bool ok; - int self_offset = m_chatmessage[SELF_OFFSET].toInt(&ok); - if (ok) - ui_vp_player_char->move(ui_viewport->width() * self_offset / 100, 0); - else - ui_vp_player_char->move(0, 0); - - switch (emote_mod) - { - case 1: case 2: case 6: - play_preanim(false); - break; - case 0: case 5: - if (m_chatmessage[NONINTERRUPTING_PRE].toInt() == 0) - handle_chatmessage_3(); else - play_preanim(true); - break; - default: - qDebug() << "W: invalid emote mod: " << QString::number(emote_mod); - } + ui_vp_player_char->network_strings.clear(); + + int f_charid = m_chatmessage[CHAR_ID].toInt(); + if (f_charid >= 0 && (m_chatmessage[SHOWNAME].isEmpty() || !ui_showname_enable->isChecked())) { + QString real_name = char_list.at(f_charid).name; + + QString f_showname = ao_app->get_showname(real_name); + + ui_vp_showname->setText(f_showname); + } + else { + ui_vp_showname->setText(m_chatmessage[SHOWNAME]); + } + + if (ui_vp_showname->text().trimmed().isEmpty()) //Whitespace showname + { + ui_vp_chatbox->set_image("chatblank"); + } + else //Aw yeah dude do some showname resizing magic + { + if (!ui_vp_chatbox->set_image("chat")) + ui_vp_chatbox->set_image("chatbox"); + + QFontMetrics fm(ui_vp_showname->font()); + int fm_width = fm.horizontalAdvance(ui_vp_showname->text()); + + QString chatbox_path = ao_app->get_theme_path("chat"); + QString chatbox = ao_app->get_chat(m_chatmessage[CHAR_NAME]); + if (chatbox != "") { + 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"); + + pos_size_type design_ini_result = ao_app->get_element_dimensions("chat_arrow", "courtroom_design.ini", m_chatmessage[CHAR_NAME]); + 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(); + } + else { + ui_vp_chat_arrow->move(design_ini_result.x, design_ini_result.y); + ui_vp_chat_arrow->combo_resize(design_ini_result.width, design_ini_result.height); + } + } + + pos_size_type default_width = ao_app->get_element_dimensions("showname", "courtroom_design.ini", m_chatmessage[CHAR_NAME]); + int extra_width = ao_app->get_design_element("showname_extra_width", "courtroom_design.ini", m_chatmessage[CHAR_NAME]).toInt(); + + if (extra_width > 0) { + if (fm_width > default_width.width && ui_vp_chatbox->set_chatbox(chatbox_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_showname->resize(static_cast(default_width.width + (extra_width * 2)), ui_vp_showname->height()); + } + } + else + ui_vp_showname->resize(default_width.width, ui_vp_showname->height()); + } + } + + ui_vp_message->hide(); + ui_vp_chatbox->hide(); + + //todo: put this in its own function or update + QString design_file = "courtroom_fonts.ini"; + int f_pointsize = ao_app->get_font_size("message", design_file); + QString font_name = ao_app->get_font_name("message_font", design_file); + QColor f_color = ao_app->get_color("message_color", design_file); + bool bold = ao_app->get_font_size("message_bold", design_file) == 1; // is the font bold or not? + bool antialias = ao_app->get_font_size("message_sharp", design_file) != 1; // is the font anti-aliased or not? + + QString chatfont = ao_app->get_chat_font(m_chatmessage[CHAR_NAME]); + if (chatfont != "") + font_name = chatfont; + + int chatsize = ao_app->get_chat_size(m_chatmessage[CHAR_NAME]); + if (chatsize != -1) + f_pointsize = chatsize; + this->set_qfont(ui_vp_message, "", get_qfont(font_name, f_pointsize, antialias), f_color, bold); + + set_scene(m_chatmessage[DESK_MOD], m_chatmessage[SIDE]); + + int emote_mod = m_chatmessage[EMOTE_MOD].toInt(); + + if (ao_app->flipping_enabled && m_chatmessage[FLIP].toInt() == 1) + ui_vp_player_char->set_flipped(true); + else + ui_vp_player_char->set_flipped(false); + + QString side = m_chatmessage[SIDE]; + + // Making the second character appear. + if (m_chatmessage[OTHER_CHARID].isEmpty()) { + // If there is no second character, hide 'em + ui_vp_sideplayer_char->stop(); + ui_vp_sideplayer_char->move(0, 0); + } + else { + bool ok; + int got_other_charid = m_chatmessage[OTHER_CHARID].split("^")[0].toInt(&ok); + if (ok) { + if (got_other_charid > -1) { + // If there is, show them! + ui_vp_sideplayer_char->show(); + + int other_offset = m_chatmessage[OTHER_OFFSET].toInt(); + ui_vp_sideplayer_char->move(ui_viewport->width() * other_offset / 100, 0); + + QStringList args = m_chatmessage[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: + ui_vp_sideplayer_char->stackUnder(ui_vp_player_char); + break; + case 1: + ui_vp_player_char->stackUnder(ui_vp_sideplayer_char); + break; + default: + break; + } + } + + // We should probably also play the other character's idle emote. + if (ao_app->flipping_enabled && m_chatmessage[OTHER_FLIP].toInt() == 1) + ui_vp_sideplayer_char->set_flipped(true); + else + ui_vp_sideplayer_char->set_flipped(false); + ui_vp_sideplayer_char->play_idle(m_chatmessage[OTHER_NAME], m_chatmessage[OTHER_EMOTE]); + } + else { + // If the server understands other characters, but there + // really is no second character, hide 'em, and center the first. + ui_vp_sideplayer_char->hide(); + ui_vp_sideplayer_char->move(0, 0); + } + } + } + //Set ourselves according to SELF_OFFSET + + bool ok; + int self_offset = m_chatmessage[SELF_OFFSET].toInt(&ok); + if (ok) + ui_vp_player_char->move(ui_viewport->width() * self_offset / 100, 0); + else + ui_vp_player_char->move(0, 0); + + switch (emote_mod) { + case 1: + case 2: + case 6: + play_preanim(false); + break; + case 0: + case 5: + if (m_chatmessage[NONINTERRUPTING_PRE].toInt() == 0) + handle_chatmessage_3(); + else + play_preanim(true); + break; + default: + qDebug() << "W: invalid emote mod: " << QString::number(emote_mod); + } } void Courtroom::do_screenshake() { - if(!ao_app->is_shake_enabled()) - return; + if (!ao_app->is_shake_enabled()) + return; - //This way, the animation is reset in such a way that last played screenshake would return to its "final frame" properly. - //This properly resets all UI elements without having to bother keeping track of "origin" positions. - //Works great wit the chat text being detached from the chat box! - screenshake_animation_group->setCurrentTime(screenshake_animation_group->duration()); - screenshake_animation_group->clear(); + //This way, the animation is reset in such a way that last played screenshake would return to its "final frame" properly. + //This properly resets all UI elements without having to bother keeping track of "origin" positions. + //Works great wit the chat text being detached from the chat box! + screenshake_animation_group->setCurrentTime(screenshake_animation_group->duration()); + screenshake_animation_group->clear(); - QList affected_list = { - ui_vp_background, - ui_vp_player_char, - ui_vp_sideplayer_char, - ui_vp_chatbox - }; + QList affected_list = { + ui_vp_background, + ui_vp_player_char, + ui_vp_sideplayer_char, + ui_vp_chatbox}; - //I would prefer if this was its own "shake" function to be honest. - foreach (QWidget* ui_element, affected_list) - { - QPropertyAnimation *screenshake_animation = new QPropertyAnimation(ui_element, "pos", this); - QPoint pos_default = QPoint(ui_element->x(), ui_element->y()); + //I would prefer if this was its own "shake" function to be honest. + foreach (QWidget *ui_element, affected_list) { + QPropertyAnimation *screenshake_animation = new QPropertyAnimation(ui_element, "pos", this); + QPoint pos_default = QPoint(ui_element->x(), ui_element->y()); - int duration = 300; //How long does the screenshake last - int frequency = 20; //How often in ms is there a "jolt" frame - int maxframes = duration/frequency; - int max_x = 7; //Max deviation from origin on x axis - int max_y = 7; //Max deviation from origin on y axis - screenshake_animation->setDuration(duration); - for (int frame=0; frame < maxframes; frame++) - { - double fraction = double(frame*frequency)/duration; - int rng = qrand();//QRandomGenerator::global()->generate(); - int rand_x = max_x - (int(rng) % (max_x*2)); - int rand_y = max_y - (int(rng+100) % (max_y*2)); - screenshake_animation->setKeyValueAt(fraction, QPoint(pos_default.x() + rand_x, pos_default.y() + rand_y)); + int duration = 300; //How long does the screenshake last + int frequency = 20; //How often in ms is there a "jolt" frame + int maxframes = duration / frequency; + int max_x = 7; //Max deviation from origin on x axis + int max_y = 7; //Max deviation from origin on y axis + screenshake_animation->setDuration(duration); + for (int frame = 0; frame < maxframes; frame++) { + double fraction = double(frame * frequency) / duration; + int rng = qrand(); //QRandomGenerator::global()->generate(); + int rand_x = max_x - (int(rng) % (max_x * 2)); + int rand_y = max_y - (int(rng + 100) % (max_y * 2)); + screenshake_animation->setKeyValueAt(fraction, QPoint(pos_default.x() + rand_x, pos_default.y() + rand_y)); + } + screenshake_animation->setEndValue(pos_default); + screenshake_animation->setEasingCurve(QEasingCurve::Linear); + screenshake_animation_group->addAnimation(screenshake_animation); } - screenshake_animation->setEndValue(pos_default); - screenshake_animation->setEasingCurve(QEasingCurve::Linear); - screenshake_animation_group->addAnimation(screenshake_animation); - } - screenshake_animation_group->start(); + screenshake_animation_group->start(); } void Courtroom::do_flash() { - if(!ao_app->is_effects_enabled()) - return; + if (!ao_app->is_effects_enabled()) + return; - QString f_char = m_chatmessage[CHAR_NAME]; - QString f_custom_theme = ao_app->get_char_shouts(f_char); - ui_vp_effect->play("realizationflash", f_char, f_custom_theme, 60); + QString f_char = m_chatmessage[CHAR_NAME]; + QString f_custom_theme = ao_app->get_char_shouts(f_char); + ui_vp_effect->play("realizationflash", f_char, f_custom_theme, 60); } void Courtroom::do_effect(QString fx_name, QString fx_sound, QString p_char, QString p_folder) { - QString effect = ao_app->get_effect(fx_name, p_char, p_folder); - if (effect == "") - return; + QString effect = ao_app->get_effect(fx_name, p_char, p_folder); + if (effect == "") + return; - if (fx_sound != "") - sfx_player->play(fx_sound); + if (fx_sound != "") + sfx_player->play(fx_sound); - //Only check if effects are disabled after playing the sound if it exists - if(!ao_app->is_effects_enabled()) - return; + //Only check if effects are disabled after playing the sound if it exists + if (!ao_app->is_effects_enabled()) + return; - ui_vp_effect->set_play_once(false); // The effects themselves dictate whether or not they're looping. Static effects will linger. - ui_vp_effect->play(effect); // It will set_play_once to true if the filepath provided is not designed to loop more than once + ui_vp_effect->set_play_once(false); // The effects themselves dictate whether or not they're looping. Static effects will linger. + ui_vp_effect->play(effect); // It will set_play_once to true if the filepath provided is not designed to loop more than once } void Courtroom::play_char_sfx(QString sfx_name) { - sfx_player->play(sfx_name); - if(ao_app->get_looping_sfx()) - sfx_player->set_looping(ao_app->get_sfx_looping(current_char, QString::number(current_emote))!="0"); + sfx_player->play(sfx_name); + if (ao_app->get_looping_sfx()) + sfx_player->set_looping(ao_app->get_sfx_looping(current_char, QString::number(current_emote)) != "0"); } void Courtroom::handle_chatmessage_3() { - start_chat_ticking(); + start_chat_ticking(); - int f_evi_id = m_chatmessage[EVIDENCE_ID].toInt(); - QString f_side = m_chatmessage[SIDE]; + int f_evi_id = m_chatmessage[EVIDENCE_ID].toInt(); + QString f_side = m_chatmessage[SIDE]; - QString f_showname; - int f_char_id = m_chatmessage[CHAR_ID].toInt(); - if (f_char_id > 0 && (m_chatmessage[SHOWNAME].isEmpty() || !ui_showname_enable->isChecked())) - { - f_showname = ao_app->get_showname(char_list.at(f_char_id).name); - } - else - { - f_showname = m_chatmessage[SHOWNAME]; - } - if(f_showname.trimmed().isEmpty()) //Pure whitespace showname, get outta here. - f_showname = m_chatmessage[CHAR_NAME]; - - if (f_evi_id > 0 && f_evi_id <= local_evidence_list.size()) - { - //shifted by 1 because 0 is no evidence per legacy standards - QString f_image = local_evidence_list.at(f_evi_id - 1).image; - QString f_name = local_evidence_list.at(f_evi_id - 1).name; - //def jud and hlp should display the evidence icon on the RIGHT side - bool is_left_side = !(f_side == "def" || f_side == "hlp" || f_side == "jud" || f_side == "jur"); - ui_vp_evidence_display->show_evidence(f_image, is_left_side, ui_sfx_slider->value()); - append_ic_text(f_name, f_showname, "has presented evidence"); - } - - int emote_mod = m_chatmessage[EMOTE_MOD].toInt(); - - QString side = m_chatmessage[SIDE]; - - if (emote_mod == 5 || - emote_mod == 6) - { - ui_vp_desk->hide(); - ui_vp_legacy_desk->hide(); - - // Since we're zooming, hide the second character, and centre the first. - ui_vp_sideplayer_char->hide(); - ui_vp_player_char->move(0,0); - - QString f_char = m_chatmessage[CHAR_NAME]; - QString f_custom_theme = ao_app->get_char_shouts(f_char); - if (side == "pro" || - side == "hlp" || - side == "wit") - ui_vp_speedlines->play("prosecution_speedlines", f_char, f_custom_theme); - else - ui_vp_speedlines->play("defense_speedlines", f_char, f_custom_theme); - - } - - //If this color is talking - color_is_talking = color_markdown_talking_list.at(m_chatmessage[TEXT_COLOR].toInt()); - - if (color_is_talking && text_state == 1 && anim_state < 2) //Set it to talking as we're not on that already - { - ui_vp_player_char->stop(); - ui_vp_player_char->play_talking(m_chatmessage[CHAR_NAME], m_chatmessage[EMOTE]); - anim_state = 2; - } - else if (anim_state < 3) //Set it to idle as we're not on that already - { - ui_vp_player_char->stop(); - ui_vp_player_char->play_idle(m_chatmessage[CHAR_NAME], m_chatmessage[EMOTE]); - anim_state = 3; - } - - QString f_message = m_chatmessage[MESSAGE]; - QStringList call_words = ao_app->get_call_words(); - - for (QString word : call_words) - { - if (f_message.contains(word, Qt::CaseInsensitive)) - { - modcall_player->play(ao_app->get_sfx("word_call")); - ao_app->alert(this); - - break; + QString f_showname; + int f_char_id = m_chatmessage[CHAR_ID].toInt(); + if (f_char_id > 0 && (m_chatmessage[SHOWNAME].isEmpty() || !ui_showname_enable->isChecked())) { + f_showname = ao_app->get_showname(char_list.at(f_char_id).name); } - } + else { + f_showname = m_chatmessage[SHOWNAME]; + } + if (f_showname.trimmed().isEmpty()) //Pure whitespace showname, get outta here. + f_showname = m_chatmessage[CHAR_NAME]; + if (f_evi_id > 0 && f_evi_id <= local_evidence_list.size()) { + //shifted by 1 because 0 is no evidence per legacy standards + QString f_image = local_evidence_list.at(f_evi_id - 1).image; + QString f_name = local_evidence_list.at(f_evi_id - 1).name; + //def jud and hlp should display the evidence icon on the RIGHT side + bool is_left_side = !(f_side == "def" || f_side == "hlp" || f_side == "jud" || f_side == "jur"); + ui_vp_evidence_display->show_evidence(f_image, is_left_side, ui_sfx_slider->value()); + append_ic_text(f_name, f_showname, "has presented evidence"); + } + + int emote_mod = m_chatmessage[EMOTE_MOD].toInt(); + + QString side = m_chatmessage[SIDE]; + + if (emote_mod == 5 || + emote_mod == 6) { + ui_vp_desk->hide(); + ui_vp_legacy_desk->hide(); + + // Since we're zooming, hide the second character, and centre the first. + ui_vp_sideplayer_char->hide(); + ui_vp_player_char->move(0, 0); + + QString f_char = m_chatmessage[CHAR_NAME]; + QString f_custom_theme = ao_app->get_char_shouts(f_char); + if (side == "pro" || + side == "hlp" || + side == "wit") + ui_vp_speedlines->play("prosecution_speedlines", f_char, f_custom_theme); + else + ui_vp_speedlines->play("defense_speedlines", f_char, f_custom_theme); + } + + //If this color is talking + color_is_talking = color_markdown_talking_list.at(m_chatmessage[TEXT_COLOR].toInt()); + + if (color_is_talking && text_state == 1 && anim_state < 2) //Set it to talking as we're not on that already + { + ui_vp_player_char->stop(); + ui_vp_player_char->play_talking(m_chatmessage[CHAR_NAME], m_chatmessage[EMOTE]); + anim_state = 2; + } + else if (anim_state < 3) //Set it to idle as we're not on that already + { + ui_vp_player_char->stop(); + ui_vp_player_char->play_idle(m_chatmessage[CHAR_NAME], m_chatmessage[EMOTE]); + anim_state = 3; + } + + QString f_message = m_chatmessage[MESSAGE]; + QStringList call_words = ao_app->get_call_words(); + + for (QString word : call_words) { + if (f_message.contains(word, Qt::CaseInsensitive)) { + modcall_player->play(ao_app->get_sfx("word_call")); + ao_app->alert(this); + + break; + } + } } QString Courtroom::filter_ic_text(QString p_text, bool html, int target_pos, int default_color) { - QString p_text_escaped; + QString p_text_escaped; - int check_pos = 0; - int check_pos_escaped = 0; - bool ic_next_is_not_special = false; - std::stack ic_color_stack; + int check_pos = 0; + int check_pos_escaped = 0; + bool ic_next_is_not_special = false; + std::stack ic_color_stack; - //Text alignment shenanigans. Could make a dropdown for this later, too! - QString align; - if (p_text.trimmed().startsWith("~~")) - { - p_text.remove(p_text.indexOf("~~"), 2); - if (target_pos != -1) - { - target_pos = qMax(0, target_pos - 2); + //Text alignment shenanigans. Could make a dropdown for this later, too! + QString align; + if (p_text.trimmed().startsWith("~~")) { + p_text.remove(p_text.indexOf("~~"), 2); + if (target_pos != -1) { + target_pos = qMax(0, target_pos - 2); + } + align = "center"; } - align = "center"; - } - else if (p_text.trimmed().startsWith("~>")) - { - p_text.remove(p_text.indexOf("~>"), 2); - if (target_pos != -1) - { - target_pos = qMax(0, target_pos - 2); + else if (p_text.trimmed().startsWith("~>")) { + p_text.remove(p_text.indexOf("~>"), 2); + if (target_pos != -1) { + target_pos = qMax(0, target_pos - 2); + } + align = "right"; } - align = "right"; - } - else if (p_text.trimmed().startsWith("<>")) - { - p_text.remove(p_text.indexOf("<>"), 2); - if (target_pos != -1) - { - target_pos = qMax(0, target_pos - 2); + else if (p_text.trimmed().startsWith("<>")) { + p_text.remove(p_text.indexOf("<>"), 2); + if (target_pos != -1) { + target_pos = qMax(0, target_pos - 2); + } + align = "justify"; } - align = "justify"; - } - //If html is enabled, prepare this text to be all ready for it. - if (html) - { - ic_color_stack.push(default_color); - QString appendage = ""; + //If html is enabled, prepare this text to be all ready for it. + if (html) { + ic_color_stack.push(default_color); + QString appendage = ""; - if (!align.isEmpty()) - appendage.prepend("

"); + if (!align.isEmpty()) + appendage.prepend("
"); - p_text_escaped.insert(check_pos_escaped, appendage); - check_pos_escaped += appendage.size(); - } + p_text_escaped.insert(check_pos_escaped, appendage); + check_pos_escaped += appendage.size(); + } - //Current issue: does not properly escape html stuff. - //Solution: probably parse p_text and export into a different string separately, perform some mumbo jumbo to properly adjust string indexes. - while (check_pos < p_text.size()) - { - QString f_rest = p_text.right(p_text.size() - check_pos); + //Current issue: does not properly escape html stuff. + //Solution: probably parse p_text and export into a different string separately, perform some mumbo jumbo to properly adjust string indexes. + while (check_pos < p_text.size()) { + QString f_rest = p_text.right(p_text.size() - check_pos); + QTextBoundaryFinder tbf(QTextBoundaryFinder::Grapheme, f_rest); + QString f_character; + int f_char_length; + + tbf.toNextBoundary(); + + if (tbf.position() == -1) + f_character = f_rest; + else + f_character = f_rest.left(tbf.position()); + + // if (f_character == "&") //oh shit it's probably an escaped html + // { + // //Skip escaped chars like you would graphemes + // QRegularExpression re("&([a-z0-9]+|#[0-9]{1,6}|#x[0-9a-f]{1,6});", QRegularExpression::CaseInsensitiveOption); + // QRegularExpressionMatch match = re.match(f_rest); + // if (match.hasMatch()) //OH SHIT IT IS, PANIC, PANIC + // { + // f_character = match.captured(0); //Phew, we solved the big problem here. + // } + // } + + if (html) + f_character = f_character.toHtmlEscaped(); + + f_char_length = f_character.length(); + + bool color_update = false; + bool is_end = false; + bool skip = false; + + if (!ic_next_is_not_special) { + if (f_character == "\\") { + ic_next_is_not_special = true; + skip = true; + } + //Nothing related to colors here + else if (f_character == "{" || f_character == "}") //|| f_character == "@" || f_character == "$") + { + skip = true; + } + //Parse markdown colors + else { + for (int c = 0; c < max_colors; ++c) { + //Clear the stored optimization information + QString markdown_start = color_markdown_start_list.at(c); + QString markdown_end = color_markdown_end_list.at(c); + if (html) { + markdown_start = markdown_start.toHtmlEscaped(); + markdown_end = markdown_end.toHtmlEscaped(); + } + bool markdown_remove = color_markdown_remove_list.at(c); + if (markdown_start.isEmpty()) //Not defined + continue; + + if (markdown_end.isEmpty() || markdown_end == markdown_start) //"toggle switch" type + { + if (f_character == markdown_start) { + if (html) { + if (!ic_color_stack.empty() && ic_color_stack.top() == c && default_color != c) { + ic_color_stack.pop(); //Cease our coloring + is_end = true; + } + else { + ic_color_stack.push(c); //Begin our coloring + } + color_update = true; + } + skip = markdown_remove; + break; //Prevent it from looping forward for whatever reason + } + } + else if (f_character == markdown_start || (f_character == markdown_end && !ic_color_stack.empty() && ic_color_stack.top() == c)) { + if (html) { + if (f_character == markdown_end) { + ic_color_stack.pop(); //Cease our coloring + is_end = true; + } + else if (f_character == markdown_start) { + ic_color_stack.push(c); //Begin our coloring + } + color_update = true; + } + skip = markdown_remove; + break; //Prevent it from looping forward for whatever reason + } + } + //Parse the newest color stack + if (color_update && (target_pos <= -1 || check_pos < target_pos)) { + if (!ic_next_is_not_special) { + QString appendage = ""; + + if (!ic_color_stack.empty()) + appendage += ""; + + if (is_end && !skip) { + p_text_escaped.insert(check_pos_escaped, f_character); //Add that char right now + check_pos_escaped += f_char_length; //So the closing char is captured too + skip = true; + } + p_text_escaped.insert(check_pos_escaped, appendage); + check_pos_escaped += appendage.size(); + } + } + } + } + else { + if (f_character == "n") // \n, that's a line break son + { + QString appendage = "
"; + if (!html) { + //actual newline commented out + // appendage = "\n"; + // size = 1; //yeah guess what \n is a "single character" apparently + appendage = "\\n "; //visual representation of a newline + } + p_text_escaped.insert(check_pos_escaped, appendage); + check_pos_escaped += appendage.size(); + skip = true; + } + if (f_character == "s" || f_character == "f") // screenshake/flash + skip = true; + + ic_next_is_not_special = false; + } + + //Make all chars we're not supposed to see invisible + if (target_pos > -1 && check_pos == target_pos) { + QString appendage = ""; + if (!ic_color_stack.empty()) { + if (!is_end) //Was our last coloring char ending the color stack or nah + { + //God forgive me for my transgressions but I have refactored this whole thing about 25 times and having to refactor it + //again to more elegantly support this will finally make me go insane. + color_is_talking = color_markdown_talking_list.at(ic_color_stack.top()); + } + + //Clean it up, we're done here + while (!ic_color_stack.empty()) + ic_color_stack.pop(); + + appendage += "
"; + } + ic_color_stack.push(-1); //Dummy colorstack push for maximum
appendage + appendage += ""; + p_text_escaped.insert(check_pos_escaped, appendage); + check_pos_escaped += appendage.size(); + } + if (!skip) { + p_text_escaped.insert(check_pos_escaped, f_character); + check_pos_escaped += f_char_length; + } + check_pos += 1; + } + + if (!ic_color_stack.empty() && html) { + p_text_escaped.append(""); + } + + if (html) { + //Example: https://regex101.com/r/oL4nM9/37 - this replaces excessive/trailing/etc. whitespace with non-breaking space. + //I WOULD use white-space: pre; stylesheet tag, but for whataver reason it doesn't work no matter where I try it. + //If somoene else can get that piece of HTML memery to work, please do. + p_text_escaped.replace(QRegularExpression("^\\s|(?<=\\s)\\s"), " "); + if (!align.isEmpty()) + p_text_escaped.append("
"); + } + + return p_text_escaped; +} + +void Courtroom::append_ic_text(QString p_text, QString p_name, QString p_action) +{ + QTextCharFormat bold; + QTextCharFormat normal; + QTextCharFormat italics; + bold.setFontWeight(QFont::Bold); + normal.setFontWeight(QFont::Normal); + italics.setFontItalic(true); + const QTextCursor old_cursor = ui_ic_chatlog->textCursor(); + const int old_scrollbar_value = ui_ic_chatlog->verticalScrollBar()->value(); + + if (p_action == "") + p_text = filter_ic_text(p_text, ao_app->is_colorlog_enabled(), -1, m_chatmessage[TEXT_COLOR].toInt()); + + if (log_goes_downwards) { + const bool is_scrolled_down = old_scrollbar_value == ui_ic_chatlog->verticalScrollBar()->maximum(); + + ui_ic_chatlog->moveCursor(QTextCursor::End); + + if (!first_message_sent) { + ui_ic_chatlog->textCursor().insertText(p_name, bold); + first_message_sent = true; + } + else { + ui_ic_chatlog->textCursor().insertText('\n' + p_name, bold); + } + + if (p_action != "") { + ui_ic_chatlog->textCursor().insertText(" " + p_action + ": ", normal); + ui_ic_chatlog->textCursor().insertText(p_text + ".", italics); + } + else { + ui_ic_chatlog->textCursor().insertText(": ", normal); + ui_ic_chatlog->textCursor().insertHtml(p_text); + } + + // If we got too many blocks in the current log, delete some from the top. + while (ui_ic_chatlog->document()->blockCount() > log_maximum_blocks && log_maximum_blocks > 0) { + ui_ic_chatlog->moveCursor(QTextCursor::Start); + ui_ic_chatlog->textCursor().select(QTextCursor::BlockUnderCursor); + ui_ic_chatlog->textCursor().removeSelectedText(); + ui_ic_chatlog->textCursor().deleteChar(); + } + + if (old_cursor.hasSelection() || !is_scrolled_down) { + // The user has selected text or scrolled away from the bottom: maintain position. + ui_ic_chatlog->setTextCursor(old_cursor); + ui_ic_chatlog->verticalScrollBar()->setValue(old_scrollbar_value); + } + else { + // The user hasn't selected any text and the scrollbar is at the bottom: scroll to the bottom. + ui_ic_chatlog->moveCursor(QTextCursor::End); + ui_ic_chatlog->verticalScrollBar()->setValue(ui_ic_chatlog->verticalScrollBar()->maximum()); + } + } + else { + const bool is_scrolled_up = old_scrollbar_value == ui_ic_chatlog->verticalScrollBar()->minimum(); + + ui_ic_chatlog->moveCursor(QTextCursor::Start); + + ui_ic_chatlog->textCursor().insertText(p_name, bold); + + if (p_action != "") { + ui_ic_chatlog->textCursor().insertText(" " + p_action + ": ", normal); + ui_ic_chatlog->textCursor().insertText(p_text + "." + '\n', italics); + } + else { + ui_ic_chatlog->textCursor().insertText(": ", normal); + ui_ic_chatlog->textCursor().insertText(p_text + '\n', normal); + } + + // If we got too many blocks in the current log, delete some from the bottom. + while (ui_ic_chatlog->document()->blockCount() > log_maximum_blocks && log_maximum_blocks > 0) { + ui_ic_chatlog->moveCursor(QTextCursor::End); + ui_ic_chatlog->textCursor().select(QTextCursor::BlockUnderCursor); + ui_ic_chatlog->textCursor().removeSelectedText(); + ui_ic_chatlog->textCursor().deletePreviousChar(); + } + + if (old_cursor.hasSelection() || !is_scrolled_up) { + // The user has selected text or scrolled away from the top: maintain position. + ui_ic_chatlog->setTextCursor(old_cursor); + ui_ic_chatlog->verticalScrollBar()->setValue(old_scrollbar_value); + } + else { + // The user hasn't selected any text and the scrollbar is at the top: scroll to the top. + ui_ic_chatlog->moveCursor(QTextCursor::Start); + ui_ic_chatlog->verticalScrollBar()->setValue(ui_ic_chatlog->verticalScrollBar()->minimum()); + } + } +} + +void Courtroom::play_preanim(bool noninterrupting) +{ + QString f_char = m_chatmessage[CHAR_NAME]; + QString f_preanim = m_chatmessage[PRE_EMOTE]; + + //all time values in char.inis are multiplied by a constant(time_mod) to get the actual time + int ao2_duration = ao_app->get_ao2_preanim_duration(f_char, f_preanim); + int text_delay = ao_app->get_text_delay(f_char, f_preanim) * time_mod; + int sfx_delay = m_chatmessage[SFX_DELAY].toInt() * time_mod; + + int preanim_duration; + + if (ao2_duration < 0) + preanim_duration = ao_app->get_preanim_duration(f_char, f_preanim); + else + preanim_duration = ao2_duration; + + sfx_delay_timer->start(sfx_delay); + QString anim_to_find = ao_app->get_image_suffix(ao_app->get_character_path(f_char, f_preanim)); + if (!file_exists(anim_to_find)) { + if (noninterrupting) + anim_state = 4; + else + anim_state = 1; + preanim_done(); + qDebug() << "could not find " + anim_to_find; + return; + } + + ui_vp_player_char->play_pre(f_char, f_preanim, preanim_duration); + + if (noninterrupting) + anim_state = 4; + else + anim_state = 1; + + if (text_delay >= 0) + text_delay_timer->start(text_delay); + + if (noninterrupting) + handle_chatmessage_3(); +} + +void Courtroom::preanim_done() +{ + anim_state = 1; + handle_chatmessage_3(); +} + +void Courtroom::start_chat_ticking() +{ + //we need to ensure that the text isn't already ticking because this function can be called by two logic paths + if (text_state != 0) + return; + + if (m_chatmessage[EFFECTS] != "") { + QStringList fx_list = m_chatmessage[EFFECTS].split("|"); + QString fx = fx_list[0]; + QString fx_sound; + QString fx_folder; + + if (fx_list.length() > 1) + fx_sound = fx_list[1]; + + if (fx_list.length() > 2) { + fx_folder = fx_list[1]; + fx_sound = fx_list[2]; + } + + this->do_effect(fx, fx_sound, m_chatmessage[CHAR_NAME], fx_folder); + } + else if (m_chatmessage[REALIZATION] == "1") { + this->do_flash(); + sfx_player->play(ao_app->get_custom_realization(m_chatmessage[CHAR_NAME])); + } + if (chatmessage_is_empty) { + //since the message is empty, it's technically done ticking + text_state = 2; + return; + } + + ui_vp_chatbox->show(); + ui_vp_message->show(); + + if (!is_additive) { + ui_vp_message->clear(); + real_tick_pos = 0; + additive_previous = ""; + } + + tick_pos = 0; + blip_ticker = 0; + + // At the start of every new message, we set the text speed to the default. + current_display_speed = 3; + chat_tick_timer->start(0); //Display the first char right away + + QString f_gender = ao_app->get_gender(m_chatmessage[CHAR_NAME]); + + blip_player->set_blips(f_gender); + + int emote_mod = m_chatmessage[EMOTE_MOD].toInt(); //text meme bonanza + if ((emote_mod == 0 || emote_mod == 5) && m_chatmessage[SCREENSHAKE] == "1") { + this->do_screenshake(); + } + + //means text is currently ticking + text_state = 1; +} + +void Courtroom::chat_tick() +{ + //note: this is called fairly often + //do not perform heavy operations here + + QString f_message = m_chatmessage[MESSAGE]; + + // Due to our new text speed system, we always need to stop the timer now. + chat_tick_timer->stop(); + + if (tick_pos >= f_message.size()) { + text_state = 2; + if (anim_state < 3) { + anim_state = 3; + ui_vp_player_char->play_idle(m_chatmessage[CHAR_NAME], m_chatmessage[EMOTE]); + } + QString f_char = m_chatmessage[CHAR_NAME]; + QString f_custom_theme = ao_app->get_chat(f_char); + ui_vp_chat_arrow->play("chat_arrow", f_char, f_custom_theme); //Chat stopped being processed, indicate that. + additive_previous = additive_previous + filter_ic_text(f_message, true, -1, m_chatmessage[TEXT_COLOR].toInt()); + real_tick_pos = ui_vp_message->toPlainText().size(); + return; + } + + // Stops blips from playing when we have a formatting option. + bool formatting_char = false; + + QString f_rest = f_message; + + //Alignment characters + if (tick_pos < 2) { + if (f_rest.startsWith("~~")) { + tick_pos = f_rest.indexOf("~~"); + f_rest.remove(tick_pos, 2); + tick_pos += 2; + } + else if (f_rest.startsWith("~>")) { + tick_pos = f_rest.indexOf("~>"); + f_rest.remove(tick_pos, 2); + tick_pos += 2; + } + else if (f_rest.startsWith("<>")) { + tick_pos = f_rest.indexOf("<>"); + f_rest.remove(tick_pos, 2); + tick_pos += 2; + } + } + f_rest.remove(0, tick_pos); QTextBoundaryFinder tbf(QTextBoundaryFinder::Grapheme, f_rest); QString f_character; int f_char_length; @@ -2181,2192 +2492,1579 @@ QString Courtroom::filter_ic_text(QString p_text, bool html, int target_pos, int tbf.toNextBoundary(); if (tbf.position() == -1) - f_character = f_rest; + f_character = f_rest; else - f_character = f_rest.left(tbf.position()); - -// if (f_character == "&") //oh shit it's probably an escaped html -// { -// //Skip escaped chars like you would graphemes -// QRegularExpression re("&([a-z0-9]+|#[0-9]{1,6}|#x[0-9a-f]{1,6});", QRegularExpression::CaseInsensitiveOption); -// QRegularExpressionMatch match = re.match(f_rest); -// if (match.hasMatch()) //OH SHIT IT IS, PANIC, PANIC -// { -// f_character = match.captured(0); //Phew, we solved the big problem here. -// } -// } - - if (html) - f_character = f_character.toHtmlEscaped(); + f_character = f_rest.left(tbf.position()); f_char_length = f_character.length(); + tick_pos += f_char_length; - bool color_update = false; - bool is_end = false; - bool skip = false; - - if (!ic_next_is_not_special) - { - if (f_character == "\\") - { - ic_next_is_not_special = true; - skip = true; - } - //Nothing related to colors here - else if (f_character == "{" || f_character == "}") //|| f_character == "@" || f_character == "$") - { - skip = true; - } - //Parse markdown colors - else - { - for (int c = 0; c < max_colors; ++c) - { - //Clear the stored optimization information - QString markdown_start = color_markdown_start_list.at(c); - QString markdown_end = color_markdown_end_list.at(c); - if (html) - { - markdown_start = markdown_start.toHtmlEscaped(); - markdown_end = markdown_end.toHtmlEscaped(); - } - bool markdown_remove = color_markdown_remove_list.at(c); - if (markdown_start.isEmpty()) //Not defined - continue; - - if (markdown_end.isEmpty() || markdown_end == markdown_start) //"toggle switch" type - { - if (f_character == markdown_start) - { - if (html) - { - if (!ic_color_stack.empty() && ic_color_stack.top() == c && default_color != c) - { - ic_color_stack.pop(); //Cease our coloring - is_end = true; - } - else - { - ic_color_stack.push(c); //Begin our coloring - } - color_update = true; - } - skip = markdown_remove; - break; //Prevent it from looping forward for whatever reason - } - } - else if (f_character == markdown_start || (f_character == markdown_end && !ic_color_stack.empty() && ic_color_stack.top() == c)) - { - if (html) - { - if (f_character == markdown_end) - { - ic_color_stack.pop(); //Cease our coloring - is_end = true; - } - else if (f_character == markdown_start) - { - ic_color_stack.push(c); //Begin our coloring - } - color_update = true; - } - skip = markdown_remove; - break; //Prevent it from looping forward for whatever reason - } - } - //Parse the newest color stack - if (color_update && (target_pos <= -1 || check_pos < target_pos)) - { - if (!ic_next_is_not_special) - { - QString appendage = "
"; - - if (!ic_color_stack.empty()) - appendage += ""; - - if (is_end && !skip) - { - p_text_escaped.insert(check_pos_escaped, f_character); //Add that char right now - check_pos_escaped += f_char_length; //So the closing char is captured too - skip = true; - } - p_text_escaped.insert(check_pos_escaped, appendage); - check_pos_escaped += appendage.size(); - } - } - } - } - else - { - if (f_character == "n") // \n, that's a line break son - { - QString appendage = "
"; - if (!html) - { - //actual newline commented out -// appendage = "\n"; -// size = 1; //yeah guess what \n is a "single character" apparently - appendage = "\\n "; //visual representation of a newline - } - p_text_escaped.insert(check_pos_escaped, appendage); - check_pos_escaped += appendage.size(); - skip = true; - } - if (f_character == "s" || f_character == "f") // screenshake/flash - skip = true; - - ic_next_is_not_special = false; - } - - //Make all chars we're not supposed to see invisible - if (target_pos > -1 && check_pos == target_pos) - { - QString appendage = ""; - if (!ic_color_stack.empty()) - { - if (!is_end) //Was our last coloring char ending the color stack or nah - { - //God forgive me for my transgressions but I have refactored this whole thing about 25 times and having to refactor it - //again to more elegantly support this will finally make me go insane. - color_is_talking = color_markdown_talking_list.at(ic_color_stack.top()); - } - - //Clean it up, we're done here - while (!ic_color_stack.empty()) - ic_color_stack.pop(); - - appendage += "
"; - } - ic_color_stack.push(-1); //Dummy colorstack push for maximum
appendage - appendage += ""; - p_text_escaped.insert(check_pos_escaped, appendage); - check_pos_escaped += appendage.size(); - } - if (!skip) - { - p_text_escaped.insert(check_pos_escaped, f_character); - check_pos_escaped += f_char_length; - } - check_pos += 1; - } - - if (!ic_color_stack.empty() && html) - { - p_text_escaped.append(""); - } - - if (html) - { - //Example: https://regex101.com/r/oL4nM9/37 - this replaces excessive/trailing/etc. whitespace with non-breaking space. - //I WOULD use white-space: pre; stylesheet tag, but for whataver reason it doesn't work no matter where I try it. - //If somoene else can get that piece of HTML memery to work, please do. - p_text_escaped.replace(QRegularExpression("^\\s|(?<=\\s)\\s"), " "); - if (!align.isEmpty()) - p_text_escaped.append("
"); - } - - return p_text_escaped; -} - -void Courtroom::append_ic_text(QString p_text, QString p_name, QString p_action) -{ - QTextCharFormat bold; - QTextCharFormat normal; - QTextCharFormat italics; - bold.setFontWeight(QFont::Bold); - normal.setFontWeight(QFont::Normal); - italics.setFontItalic(true); - const QTextCursor old_cursor = ui_ic_chatlog->textCursor(); - const int old_scrollbar_value = ui_ic_chatlog->verticalScrollBar()->value(); - - if (p_action == "") - p_text = filter_ic_text(p_text, ao_app->is_colorlog_enabled(), -1, m_chatmessage[TEXT_COLOR].toInt()); - - if (log_goes_downwards) - { - const bool is_scrolled_down = old_scrollbar_value == ui_ic_chatlog->verticalScrollBar()->maximum(); - - ui_ic_chatlog->moveCursor(QTextCursor::End); - - if (!first_message_sent) - { - ui_ic_chatlog->textCursor().insertText(p_name, bold); - first_message_sent = true; - } - else - { - ui_ic_chatlog->textCursor().insertText('\n' + p_name, bold); - } - - if (p_action != "") - { - ui_ic_chatlog->textCursor().insertText(" " + p_action + ": ", normal); - ui_ic_chatlog->textCursor().insertText(p_text + ".", italics); - } - else - { - ui_ic_chatlog->textCursor().insertText(": ", normal); - ui_ic_chatlog->textCursor().insertHtml(p_text); - } - - // If we got too many blocks in the current log, delete some from the top. - while (ui_ic_chatlog->document()->blockCount() > log_maximum_blocks && log_maximum_blocks > 0) - { - ui_ic_chatlog->moveCursor(QTextCursor::Start); - ui_ic_chatlog->textCursor().select(QTextCursor::BlockUnderCursor); - ui_ic_chatlog->textCursor().removeSelectedText(); - ui_ic_chatlog->textCursor().deleteChar(); - } - - if (old_cursor.hasSelection() || !is_scrolled_down) - { - // The user has selected text or scrolled away from the bottom: maintain position. - ui_ic_chatlog->setTextCursor(old_cursor); - ui_ic_chatlog->verticalScrollBar()->setValue(old_scrollbar_value); - } - else - { - // The user hasn't selected any text and the scrollbar is at the bottom: scroll to the bottom. - ui_ic_chatlog->moveCursor(QTextCursor::End); - ui_ic_chatlog->verticalScrollBar()->setValue(ui_ic_chatlog->verticalScrollBar()->maximum()); - } - } - else - { - const bool is_scrolled_up = old_scrollbar_value == ui_ic_chatlog->verticalScrollBar()->minimum(); - - ui_ic_chatlog->moveCursor(QTextCursor::Start); - - ui_ic_chatlog->textCursor().insertText(p_name, bold); - - if (p_action != "") - { - ui_ic_chatlog->textCursor().insertText(" " + p_action + ": ", normal); - ui_ic_chatlog->textCursor().insertText(p_text + "." + '\n', italics); - } - else - { - ui_ic_chatlog->textCursor().insertText(": ", normal); - ui_ic_chatlog->textCursor().insertText(p_text + '\n', normal); - } - - // If we got too many blocks in the current log, delete some from the bottom. - while (ui_ic_chatlog->document()->blockCount() > log_maximum_blocks && log_maximum_blocks > 0) - { - ui_ic_chatlog->moveCursor(QTextCursor::End); - ui_ic_chatlog->textCursor().select(QTextCursor::BlockUnderCursor); - ui_ic_chatlog->textCursor().removeSelectedText(); - ui_ic_chatlog->textCursor().deletePreviousChar(); - } - - if (old_cursor.hasSelection() || !is_scrolled_up) - { - // The user has selected text or scrolled away from the top: maintain position. - ui_ic_chatlog->setTextCursor(old_cursor); - ui_ic_chatlog->verticalScrollBar()->setValue(old_scrollbar_value); - } - else - { - // The user hasn't selected any text and the scrollbar is at the top: scroll to the top. - ui_ic_chatlog->moveCursor(QTextCursor::Start); - ui_ic_chatlog->verticalScrollBar()->setValue(ui_ic_chatlog->verticalScrollBar()->minimum()); - } - } -} - -void Courtroom::play_preanim(bool noninterrupting) -{ - QString f_char = m_chatmessage[CHAR_NAME]; - QString f_preanim = m_chatmessage[PRE_EMOTE]; - - //all time values in char.inis are multiplied by a constant(time_mod) to get the actual time - int ao2_duration = ao_app->get_ao2_preanim_duration(f_char, f_preanim); - int text_delay = ao_app->get_text_delay(f_char, f_preanim) * time_mod; - int sfx_delay = m_chatmessage[SFX_DELAY].toInt() * time_mod; - - int preanim_duration; - - if (ao2_duration < 0) - preanim_duration = ao_app->get_preanim_duration(f_char, f_preanim); - else - preanim_duration = ao2_duration; - - sfx_delay_timer->start(sfx_delay); - QString anim_to_find = ao_app->get_image_suffix(ao_app->get_character_path(f_char, f_preanim)); - if (!file_exists(anim_to_find)) - { - if (noninterrupting) - anim_state = 4; - else - anim_state = 1; - preanim_done(); - qDebug() << "could not find " + anim_to_find; - return; - } - - ui_vp_player_char->play_pre(f_char, f_preanim, preanim_duration); - - if (noninterrupting) - anim_state = 4; - else - anim_state = 1; - - if (text_delay >= 0) - text_delay_timer->start(text_delay); - - if (noninterrupting) - handle_chatmessage_3(); -} - -void Courtroom::preanim_done() -{ - anim_state = 1; - handle_chatmessage_3(); -} - - -void Courtroom::start_chat_ticking() -{ - //we need to ensure that the text isn't already ticking because this function can be called by two logic paths - if (text_state != 0) - return; - - if (m_chatmessage[EFFECTS] != "") - { - QStringList fx_list = m_chatmessage[EFFECTS].split("|"); - QString fx = fx_list[0]; - QString fx_sound; - QString fx_folder; - - if (fx_list.length() > 1) - fx_sound = fx_list[1]; - - if (fx_list.length() > 2) - { - fx_folder = fx_list[1]; - fx_sound = fx_list[2]; - } - - this->do_effect(fx, fx_sound, m_chatmessage[CHAR_NAME], fx_folder); - } - else if (m_chatmessage[REALIZATION] == "1") - { - this->do_flash(); - sfx_player->play(ao_app->get_custom_realization(m_chatmessage[CHAR_NAME])); - } - if (chatmessage_is_empty) - { - //since the message is empty, it's technically done ticking - text_state = 2; - return; - } - - ui_vp_chatbox->show(); - ui_vp_message->show(); - - if (!is_additive) - { - ui_vp_message->clear(); - real_tick_pos = 0; - additive_previous = ""; - } - - tick_pos = 0; - blip_ticker = 0; - - // At the start of every new message, we set the text speed to the default. - current_display_speed = 3; - chat_tick_timer->start(0); //Display the first char right away - - QString f_gender = ao_app->get_gender(m_chatmessage[CHAR_NAME]); - - blip_player->set_blips(f_gender); - - int emote_mod = m_chatmessage[EMOTE_MOD].toInt(); //text meme bonanza - if ((emote_mod == 0 || emote_mod == 5) && m_chatmessage[SCREENSHAKE] == "1") - { - this->do_screenshake(); - } - - //means text is currently ticking - text_state = 1; -} - -void Courtroom::chat_tick() -{ - //note: this is called fairly often - //do not perform heavy operations here - - QString f_message = m_chatmessage[MESSAGE]; - - // Due to our new text speed system, we always need to stop the timer now. - chat_tick_timer->stop(); - - if (tick_pos >= f_message.size()) - { - text_state = 2; - if (anim_state < 3) - { - anim_state = 3; - ui_vp_player_char->play_idle(m_chatmessage[CHAR_NAME], m_chatmessage[EMOTE]); - } - QString f_char = m_chatmessage[CHAR_NAME]; - QString f_custom_theme = ao_app->get_chat(f_char); - ui_vp_chat_arrow->play("chat_arrow", f_char, f_custom_theme); //Chat stopped being processed, indicate that. - additive_previous = additive_previous + filter_ic_text(f_message, true, -1, m_chatmessage[TEXT_COLOR].toInt()); - real_tick_pos = ui_vp_message->toPlainText().size(); - return; - } - - // Stops blips from playing when we have a formatting option. - bool formatting_char = false; - - QString f_rest = f_message; - - //Alignment characters - if (tick_pos < 2) - { - if (f_rest.startsWith("~~")) - { - tick_pos = f_rest.indexOf("~~"); - f_rest.remove(tick_pos, 2); - tick_pos += 2; - } - else if (f_rest.startsWith("~>")) - { - tick_pos = f_rest.indexOf("~>"); - f_rest.remove(tick_pos, 2); - tick_pos += 2; - } - else if (f_rest.startsWith("<>")) - { - tick_pos = f_rest.indexOf("<>"); - f_rest.remove(tick_pos, 2); - tick_pos += 2; - } - } - f_rest.remove(0, tick_pos); - QTextBoundaryFinder tbf(QTextBoundaryFinder::Grapheme, f_rest); - QString f_character; - int f_char_length; - - tbf.toNextBoundary(); - - if (tbf.position() == -1) - f_character = f_rest; - else - f_character = f_rest.left(tbf.position()); - - f_char_length = f_character.length(); - tick_pos += f_char_length; - - // Escape character. - if (!next_character_is_not_special) - { - if (f_character == "\\") - { - next_character_is_not_special = true; - formatting_char = true; - } - - // Text speed modifier. - else if (f_character == "{") - { - // ++, because it INCREASES delay! - current_display_speed++; - formatting_char = true; - } - else if (f_character == "}") - { - current_display_speed--; - formatting_char = true; - } - - else - { - //Parse markdown colors - for (int c = 0; c < max_colors; ++c) - { - QString markdown_start = color_markdown_start_list.at(c); - QString markdown_end = color_markdown_end_list.at(c); - bool markdown_remove = color_markdown_remove_list.at(c); - if (markdown_start.isEmpty()) - continue; - - if (f_character == markdown_start || f_character == markdown_end) - { - if (markdown_remove) + // Escape character. + if (!next_character_is_not_special) { + if (f_character == "\\") { + next_character_is_not_special = true; formatting_char = true; - break; } - } + + // Text speed modifier. + else if (f_character == "{") { + // ++, because it INCREASES delay! + current_display_speed++; + formatting_char = true; + } + else if (f_character == "}") { + current_display_speed--; + formatting_char = true; + } + + else { + //Parse markdown colors + for (int c = 0; c < max_colors; ++c) { + QString markdown_start = color_markdown_start_list.at(c); + QString markdown_end = color_markdown_end_list.at(c); + bool markdown_remove = color_markdown_remove_list.at(c); + if (markdown_start.isEmpty()) + continue; + + if (f_character == markdown_start || f_character == markdown_end) { + if (markdown_remove) + formatting_char = true; + break; + } + } + } } - } - else - { - if (f_character == "n") - formatting_char = true; //it's a newline - if (f_character == "s") //Screenshake. - { - this->do_screenshake(); - formatting_char = true; - } - if (f_character == "f")//Flash. - { - this->do_flash(); - formatting_char = true; - } - next_character_is_not_special = false; - } - - if ((message_display_speed[current_display_speed] <= 0 && tick_pos < f_message.size()-1) || formatting_char) - { - chat_tick_timer->start(0); //Don't bother rendering anything out as we're doing the SPEED. (there's latency otherwise) - if (!formatting_char || f_character == "n" || f_character == "f" || f_character == "s") - real_tick_pos += f_char_length; //Adjust the tick position for the scrollbar convenience - } - else - { - int msg_delay = message_display_speed[current_display_speed]; - //Do the colors, gradual showing, etc. in here - ui_vp_message->setHtml(additive_previous + filter_ic_text(f_message, true, tick_pos, m_chatmessage[TEXT_COLOR].toInt())); - - //This should always be done AFTER setHtml. Scroll the chat window with the text. - - //Make the cursor follow the message - QTextCursor cursor = ui_vp_message->textCursor(); - cursor.setPosition(real_tick_pos); - ui_vp_message->setTextCursor(cursor); - real_tick_pos += f_char_length; - - ui_vp_message->ensureCursorVisible(); - - // Keep the speed at bay. - if (current_display_speed < 0) - current_display_speed = 0; - else if (current_display_speed > 6) - current_display_speed = 6; - - //Blip player and real tick pos ticker - if (!formatting_char && (f_character != ' ' || blank_blip)) - { - if (blip_ticker % blip_rate == 0) - { - blip_player->blip_tick(); - } - ++blip_ticker; + else { + if (f_character == "n") + formatting_char = true; //it's a newline + if (f_character == "s") //Screenshake. + { + this->do_screenshake(); + formatting_char = true; + } + if (f_character == "f") //Flash. + { + this->do_flash(); + formatting_char = true; + } + next_character_is_not_special = false; } - //Punctuation delayer - if (punctuation_chars.contains(f_character)) - { - msg_delay *= punctuation_modifier; + if ((message_display_speed[current_display_speed] <= 0 && tick_pos < f_message.size() - 1) || formatting_char) { + chat_tick_timer->start(0); //Don't bother rendering anything out as we're doing the SPEED. (there's latency otherwise) + if (!formatting_char || f_character == "n" || f_character == "f" || f_character == "s") + real_tick_pos += f_char_length; //Adjust the tick position for the scrollbar convenience } + else { + int msg_delay = message_display_speed[current_display_speed]; + //Do the colors, gradual showing, etc. in here + ui_vp_message->setHtml(additive_previous + filter_ic_text(f_message, true, tick_pos, m_chatmessage[TEXT_COLOR].toInt())); - //If this color is talking - if (color_is_talking && anim_state != 2 && anim_state < 4) //Set it to talking as we're not on that already (though we have to avoid interrupting a non-interrupted preanim) - { - ui_vp_player_char->stop(); - ui_vp_player_char->play_talking(m_chatmessage[CHAR_NAME], m_chatmessage[EMOTE]); - anim_state = 2; + //This should always be done AFTER setHtml. Scroll the chat window with the text. + + //Make the cursor follow the message + QTextCursor cursor = ui_vp_message->textCursor(); + cursor.setPosition(real_tick_pos); + ui_vp_message->setTextCursor(cursor); + real_tick_pos += f_char_length; + + ui_vp_message->ensureCursorVisible(); + + // Keep the speed at bay. + if (current_display_speed < 0) + current_display_speed = 0; + else if (current_display_speed > 6) + current_display_speed = 6; + + //Blip player and real tick pos ticker + if (!formatting_char && (f_character != ' ' || blank_blip)) { + if (blip_ticker % blip_rate == 0) { + blip_player->blip_tick(); + } + ++blip_ticker; + } + + //Punctuation delayer + if (punctuation_chars.contains(f_character)) { + msg_delay *= punctuation_modifier; + } + + //If this color is talking + if (color_is_talking && anim_state != 2 && anim_state < 4) //Set it to talking as we're not on that already (though we have to avoid interrupting a non-interrupted preanim) + { + ui_vp_player_char->stop(); + ui_vp_player_char->play_talking(m_chatmessage[CHAR_NAME], m_chatmessage[EMOTE]); + anim_state = 2; + } + else if (!color_is_talking && anim_state < 3 && anim_state != 3) //Set it to idle as we're not on that already + { + ui_vp_player_char->stop(); + ui_vp_player_char->play_idle(m_chatmessage[CHAR_NAME], m_chatmessage[EMOTE]); + anim_state = 3; + } + //Continue ticking + chat_tick_timer->start(msg_delay); } - else if (!color_is_talking && anim_state < 3 && anim_state != 3) //Set it to idle as we're not on that already - { - ui_vp_player_char->stop(); - ui_vp_player_char->play_idle(m_chatmessage[CHAR_NAME], m_chatmessage[EMOTE]); - anim_state = 3; - } - //Continue ticking - chat_tick_timer->start(msg_delay); - } } void Courtroom::play_sfx() { - QString sfx_name = m_chatmessage[SFX_NAME]; - if (m_chatmessage[SCREENSHAKE] == "1") //Screenshake dependant on preanim sfx delay meme - { - this->do_screenshake(); - } - if (sfx_name == "1") - return; + QString sfx_name = m_chatmessage[SFX_NAME]; + if (m_chatmessage[SCREENSHAKE] == "1") //Screenshake dependant on preanim sfx delay meme + { + this->do_screenshake(); + } + if (sfx_name == "1") + return; - sfx_player->play(sfx_name); - if(ao_app->get_looping_sfx()) - sfx_player->set_looping(ao_app->get_sfx_looping(current_char, sfx_name)!="0"); + sfx_player->play(sfx_name); + if (ao_app->get_looping_sfx()) + sfx_player->set_looping(ao_app->get_sfx_looping(current_char, sfx_name) != "0"); } void Courtroom::set_scene(QString f_desk_mod, QString f_side) { - //witness is default if pos is invalid - QString f_background = "witnessempty"; - QString f_desk_image = "stand"; + //witness is default if pos is invalid + QString f_background = "witnessempty"; + QString f_desk_image = "stand"; - if (f_side == "def" && file_exists(ao_app->get_image_suffix(ao_app->get_background_path("defenseempty")))) - { - f_background = "defenseempty"; - f_desk_image = "defensedesk"; - } - else if (f_side == "pro" && file_exists(ao_app->get_image_suffix(ao_app->get_background_path("prosecutorempty")))) - { - f_background = "prosecutorempty"; - f_desk_image = "prosecutiondesk"; - } - else if (f_side == "jud" && file_exists(ao_app->get_image_suffix(ao_app->get_background_path("judgestand")))) - { - f_background = "judgestand"; - f_desk_image = "judgedesk"; - } - else if (f_side == "hld" && file_exists(ao_app->get_image_suffix(ao_app->get_background_path("helperstand")))) - { - f_background = "helperstand"; - f_desk_image = "helperdesk"; - } - else if (f_side == "hlp" && file_exists(ao_app->get_image_suffix(ao_app->get_background_path("prohelperstand")))) - { - f_background = "prohelperstand"; - f_desk_image = "prohelperdesk"; - } - else if (f_side == "jur" && file_exists(ao_app->get_image_suffix(ao_app->get_background_path("jurystand")))) - { - f_background = "jurystand"; - f_desk_image = "jurydesk"; - } - else if (f_side == "sea" && file_exists(ao_app->get_image_suffix(ao_app->get_background_path("seancestand")))) - { - f_background = "seancestand"; - f_desk_image = "seancedesk"; - } + if (f_side == "def" && file_exists(ao_app->get_image_suffix(ao_app->get_background_path("defenseempty")))) { + f_background = "defenseempty"; + f_desk_image = "defensedesk"; + } + else if (f_side == "pro" && file_exists(ao_app->get_image_suffix(ao_app->get_background_path("prosecutorempty")))) { + f_background = "prosecutorempty"; + f_desk_image = "prosecutiondesk"; + } + else if (f_side == "jud" && file_exists(ao_app->get_image_suffix(ao_app->get_background_path("judgestand")))) { + f_background = "judgestand"; + f_desk_image = "judgedesk"; + } + else if (f_side == "hld" && file_exists(ao_app->get_image_suffix(ao_app->get_background_path("helperstand")))) { + f_background = "helperstand"; + f_desk_image = "helperdesk"; + } + else if (f_side == "hlp" && file_exists(ao_app->get_image_suffix(ao_app->get_background_path("prohelperstand")))) { + f_background = "prohelperstand"; + f_desk_image = "prohelperdesk"; + } + else if (f_side == "jur" && file_exists(ao_app->get_image_suffix(ao_app->get_background_path("jurystand")))) { + f_background = "jurystand"; + f_desk_image = "jurydesk"; + } + else if (f_side == "sea" && file_exists(ao_app->get_image_suffix(ao_app->get_background_path("seancestand")))) { + f_background = "seancestand"; + f_desk_image = "seancedesk"; + } - if (file_exists(ao_app->get_image_suffix(ao_app->get_background_path(f_side)))) //Unique pos path - { - f_background = f_side; - f_desk_image = f_side + "_overlay"; - } + if (file_exists(ao_app->get_image_suffix(ao_app->get_background_path(f_side)))) //Unique pos path + { + f_background = f_side; + f_desk_image = f_side + "_overlay"; + } - ui_vp_background->set_image(f_background); - ui_vp_desk->set_image(f_desk_image); - ui_vp_legacy_desk->set_legacy_desk(f_desk_image); + ui_vp_background->set_image(f_background); + ui_vp_desk->set_image(f_desk_image); + ui_vp_legacy_desk->set_legacy_desk(f_desk_image); - if (f_desk_mod == "0" || (f_desk_mod != "1" && - (f_side == "jud" || - f_side == "hld" || - f_side == "hlp"))) - { - ui_vp_desk->hide(); - ui_vp_legacy_desk->hide(); - } - else - { - ui_vp_legacy_desk->hide(); - ui_vp_desk->show(); - } + if (f_desk_mod == "0" || (f_desk_mod != "1" && + (f_side == "jud" || + f_side == "hld" || + f_side == "hlp"))) { + ui_vp_desk->hide(); + ui_vp_legacy_desk->hide(); + } + else { + ui_vp_legacy_desk->hide(); + ui_vp_desk->show(); + } } void Courtroom::set_ip_list(QString p_list) { - QString f_list = p_list.replace("|", ":").replace("*", "\n"); + QString f_list = p_list.replace("|", ":").replace("*", "\n"); - ui_server_chatlog->append(f_list); + ui_server_chatlog->append(f_list); } void Courtroom::set_mute(bool p_muted, int p_cid) { - if (p_cid != m_cid && p_cid != -1) - return; + if (p_cid != m_cid && p_cid != -1) + return; - if (p_muted) - ui_muted->show(); - else - { - ui_muted->hide(); - ui_ic_chat_message->setFocus(); - } + if (p_muted) + ui_muted->show(); + else { + ui_muted->hide(); + ui_ic_chat_message->setFocus(); + } - ui_muted->resize(ui_ic_chat_message->width(), ui_ic_chat_message->height()); - ui_muted->set_image("muted"); + ui_muted->resize(ui_ic_chat_message->width(), ui_ic_chat_message->height()); + ui_muted->set_image("muted"); - is_muted = p_muted; - ui_ic_chat_message->setEnabled(!p_muted); + is_muted = p_muted; + ui_ic_chat_message->setEnabled(!p_muted); } void Courtroom::set_ban(int p_cid) { - if (p_cid != m_cid && p_cid != -1) - return; + if (p_cid != m_cid && p_cid != -1) + return; - call_notice("You have been banned."); + call_notice("You have been banned."); - ao_app->construct_lobby(); - ao_app->destruct_courtroom(); + ao_app->construct_lobby(); + ao_app->destruct_courtroom(); } void Courtroom::handle_song(QStringList *p_contents) { - QStringList f_contents = *p_contents; + QStringList f_contents = *p_contents; - if (f_contents.size() < 2) - return; + if (f_contents.size() < 2) + return; - QString f_song = f_contents.at(0); - QString f_song_clear = f_song.left(f_song.lastIndexOf(".")); - f_song_clear = f_song_clear.right(f_song_clear.length() - (f_song_clear.lastIndexOf("/") + 1)); - int n_char = f_contents.at(1).toInt(); + QString f_song = f_contents.at(0); + QString f_song_clear = f_song.left(f_song.lastIndexOf(".")); + f_song_clear = f_song_clear.right(f_song_clear.length() - (f_song_clear.lastIndexOf("/") + 1)); + int n_char = f_contents.at(1).toInt(); - bool looping = true; - int channel = 0; - int effect_flags = 0; - if (n_char < 0 || n_char >= char_list.size()) - { + bool looping = true; int channel = 0; - if (p_contents->length() > 3 && p_contents->at(3) != "-1") - looping = false; + int effect_flags = 0; + if (n_char < 0 || n_char >= char_list.size()) { + int channel = 0; + if (p_contents->length() > 3 && p_contents->at(3) != "-1") + looping = false; - if (p_contents->length() > 4) //eyyy we want to change this song's CHANNEL huh - channel = p_contents->at(4).toInt(); //let the music player handle it if it's bigger than the channel list + if (p_contents->length() > 4) //eyyy we want to change this song's CHANNEL huh + channel = p_contents->at(4).toInt(); //let the music player handle it if it's bigger than the channel list - if (p_contents->length() > 5) //Flags provided to us by server such as Fade In, Fade Out, Sync Pos etc. - { - effect_flags = p_contents->at(5).toInt(); - } - - music_player->play(f_song, channel, looping, effect_flags); - if (channel == 0) - ui_music_name->setText(f_song_clear); - } - else - { - QString str_char = char_list.at(n_char).name; - QString str_show = char_list.at(n_char).name; - - if (p_contents->length() > 2) - { - if(p_contents->at(2) != "") + if (p_contents->length() > 5) //Flags provided to us by server such as Fade In, Fade Out, Sync Pos etc. { - str_show = p_contents->at(2); + effect_flags = p_contents->at(5).toInt(); + } + + music_player->play(f_song, channel, looping, effect_flags); + if (channel == 0) + ui_music_name->setText(f_song_clear); + } + else { + QString str_char = char_list.at(n_char).name; + QString str_show = char_list.at(n_char).name; + + if (p_contents->length() > 2) { + if (p_contents->at(2) != "") { + str_show = p_contents->at(2); + } + } + if (p_contents->length() > 3 && p_contents->at(3) != "-1") { + //I am really confused why "-1" is "loop this song" and why anything else passes as "don't loop" + //(if we even have this length) but alright + looping = false; + } + if (p_contents->length() > 4) //eyyy we want to change this song's CHANNEL huh + channel = p_contents->at(4).toInt(); //let the music player handle it if it's bigger than the channel list + + if (p_contents->length() > 5) //Flags provided to us by server such as Fade In, Fade Out, Sync Pos etc. + { + effect_flags = p_contents->at(5).toInt(); + } + + if (!mute_map.value(n_char)) { + chatlogpiece *temp = new chatlogpiece(str_char, str_show, f_song, true); + ic_chatlog_history.append(*temp); + ao_app->append_to_file(temp->get_full(), ao_app->log_filename, true); + + while (ic_chatlog_history.size() > log_maximum_blocks && log_maximum_blocks > 0) { + ic_chatlog_history.removeFirst(); + } + + append_ic_text(f_song_clear, str_show, "has played a song"); + + music_player->play(f_song, channel, looping, effect_flags); + if (channel == 0) + ui_music_name->setText(f_song_clear); } } - if (p_contents->length() > 3 && p_contents->at(3) != "-1") - { - //I am really confused why "-1" is "loop this song" and why anything else passes as "don't loop" - //(if we even have this length) but alright - looping = false; - } - if (p_contents->length() > 4) //eyyy we want to change this song's CHANNEL huh - channel = p_contents->at(4).toInt(); //let the music player handle it if it's bigger than the channel list - - if (p_contents->length() > 5) //Flags provided to us by server such as Fade In, Fade Out, Sync Pos etc. - { - effect_flags = p_contents->at(5).toInt(); - } - - if (!mute_map.value(n_char)) - { - chatlogpiece* temp = new chatlogpiece(str_char, str_show, f_song, true); - ic_chatlog_history.append(*temp); - ao_app->append_to_file(temp->get_full(), ao_app->log_filename, true); - - while(ic_chatlog_history.size() > log_maximum_blocks && log_maximum_blocks > 0) - { - ic_chatlog_history.removeFirst(); - } - - append_ic_text(f_song_clear, str_show, "has played a song"); - - music_player->play(f_song, channel, looping, effect_flags); - if (channel == 0) - ui_music_name->setText(f_song_clear); - } - } } void Courtroom::handle_wtce(QString p_wtce, int variant) { - QString sfx_file = "courtroom_sounds.ini"; + QString sfx_file = "courtroom_sounds.ini"; - //witness testimony - if (p_wtce == "testimony1") - { - sfx_player->play(ao_app->get_sfx("witness_testimony")); - ui_vp_wtce->play("witnesstestimony", "", "", 1500); - ui_vp_testimony->play("testimony"); - } - //cross examination - else if (p_wtce == "testimony2") - { - sfx_player->play(ao_app->get_sfx("cross_examination")); - ui_vp_wtce->play("crossexamination", "", "", 1500); - ui_vp_testimony->stop(); - } - else if (p_wtce == "judgeruling") - { - if (variant == 0) - { - sfx_player->play(ao_app->get_sfx("not_guilty")); - ui_vp_wtce->play("notguilty", "", "", 3000); + //witness testimony + if (p_wtce == "testimony1") { + sfx_player->play(ao_app->get_sfx("witness_testimony")); + ui_vp_wtce->play("witnesstestimony", "", "", 1500); + ui_vp_testimony->play("testimony"); + } + //cross examination + else if (p_wtce == "testimony2") { + sfx_player->play(ao_app->get_sfx("cross_examination")); + ui_vp_wtce->play("crossexamination", "", "", 1500); ui_vp_testimony->stop(); } - else if (variant == 1) { - sfx_player->play(ao_app->get_sfx("guilty")); - ui_vp_wtce->play("guilty", "", "", 3000); - ui_vp_testimony->stop(); + else if (p_wtce == "judgeruling") { + if (variant == 0) { + sfx_player->play(ao_app->get_sfx("not_guilty")); + ui_vp_wtce->play("notguilty", "", "", 3000); + ui_vp_testimony->stop(); + } + else if (variant == 1) { + sfx_player->play(ao_app->get_sfx("guilty")); + ui_vp_wtce->play("guilty", "", "", 3000); + ui_vp_testimony->stop(); + } } - } } void Courtroom::set_hp_bar(int p_bar, int p_state) { - if (p_state < 0 || p_state > 10) - return; + if (p_state < 0 || p_state > 10) + return; - if (p_bar == 1) - { - ui_defense_bar->set_image("defensebar" + QString::number(p_state)); - defense_bar_state = p_state; - } - else if (p_bar == 2) - { - ui_prosecution_bar->set_image("prosecutionbar" + QString::number(p_state)); - prosecution_bar_state = p_state; - } + if (p_bar == 1) { + ui_defense_bar->set_image("defensebar" + QString::number(p_state)); + defense_bar_state = p_state; + } + else if (p_bar == 2) { + ui_prosecution_bar->set_image("prosecutionbar" + QString::number(p_state)); + prosecution_bar_state = p_state; + } } void Courtroom::toggle_judge_buttons(bool is_on) { - if (is_on) - { - ui_witness_testimony->show(); - ui_cross_examination->show(); - ui_guilty->show(); - ui_not_guilty->show(); - ui_defense_minus->show(); - ui_defense_plus->show(); - ui_prosecution_minus->show(); - ui_prosecution_plus->show(); - } - else - { - ui_witness_testimony->hide(); - ui_cross_examination->hide(); - ui_guilty->hide(); - ui_not_guilty->hide(); - ui_defense_minus->hide(); - ui_defense_plus->hide(); - ui_prosecution_minus->hide(); - ui_prosecution_plus->hide(); - } + if (is_on) { + ui_witness_testimony->show(); + ui_cross_examination->show(); + ui_guilty->show(); + ui_not_guilty->show(); + ui_defense_minus->show(); + ui_defense_plus->show(); + ui_prosecution_minus->show(); + ui_prosecution_plus->show(); + } + else { + ui_witness_testimony->hide(); + ui_cross_examination->hide(); + ui_guilty->hide(); + ui_not_guilty->hide(); + ui_defense_minus->hide(); + ui_defense_plus->hide(); + ui_prosecution_minus->hide(); + ui_prosecution_plus->hide(); + } } 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")); - ao_app->alert(this); - } + ui_server_chatlog->append(p_ip); + if (!ui_guard->isChecked()) { + modcall_player->play(ao_app->get_sfx("mod_call")); + ao_app->alert(this); + } } void Courtroom::case_called(QString msg, bool def, bool pro, bool jud, bool jur, bool steno) { - if (ui_casing->isChecked()) - { - ui_server_chatlog->append(msg); - if ((ao_app->get_casing_defence_enabled() && def) || - (ao_app->get_casing_prosecution_enabled() && pro) || - (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")); - ao_app->alert(this); + if (ui_casing->isChecked()) { + ui_server_chatlog->append(msg); + if ((ao_app->get_casing_defence_enabled() && def) || + (ao_app->get_casing_prosecution_enabled() && pro) || + (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")); + ao_app->alert(this); + } } - } } void Courtroom::on_ooc_return_pressed() { - QString ooc_message = ui_ooc_chat_message->text(); + QString ooc_message = ui_ooc_chat_message->text(); - if (ooc_message == "" || ui_ooc_chat_name->text() == "") - return; + if (ooc_message == "" || ui_ooc_chat_name->text() == "") + return; - if (ooc_message.startsWith("/pos")) - { - if (ooc_message == "/pos jud") - { - toggle_judge_buttons(true); + if (ooc_message.startsWith("/pos")) { + if (ooc_message == "/pos jud") { + toggle_judge_buttons(true); + } + else { + toggle_judge_buttons(false); + } } - else - { - toggle_judge_buttons(false); + else if (ooc_message.startsWith("/settings")) { + ui_ooc_chat_message->clear(); + ao_app->call_settings_menu(); + append_server_chatmessage("CLIENT", tr("You opened the settings menu."), "1"); + return; } - } - else if (ooc_message.startsWith("/settings")) - { - ui_ooc_chat_message->clear(); - ao_app->call_settings_menu(); - append_server_chatmessage("CLIENT", tr("You opened the settings menu."), "1"); - return; - } - else if (ooc_message.startsWith("/pair")) - { - ui_ooc_chat_message->clear(); - ooc_message.remove(0,6); + else if (ooc_message.startsWith("/pair")) { + ui_ooc_chat_message->clear(); + ooc_message.remove(0, 6); - bool ok; - int whom = ooc_message.toInt(&ok); - if (ok) - { - if (whom > -1) - { - other_charid = whom; - QString msg = tr("You will now pair up with "); - msg.append(char_list.at(whom).name); - msg.append(tr(" if they also choose your character in return.")); - append_server_chatmessage("CLIENT", msg, "1"); - } - else - { - other_charid = -1; - append_server_chatmessage("CLIENT", tr("You are no longer paired with anyone."), "1"); - } + bool ok; + int whom = ooc_message.toInt(&ok); + if (ok) { + if (whom > -1) { + other_charid = whom; + QString msg = tr("You will now pair up with "); + msg.append(char_list.at(whom).name); + msg.append(tr(" if they also choose your character in return.")); + append_server_chatmessage("CLIENT", msg, "1"); + } + else { + other_charid = -1; + append_server_chatmessage("CLIENT", tr("You are no longer paired with anyone."), "1"); + } + } + else { + append_server_chatmessage("CLIENT", tr("Are you sure you typed that well? The char ID could not be recognised."), "1"); + } + return; } - else - { - append_server_chatmessage("CLIENT", tr("Are you sure you typed that well? The char ID could not be recognised."), "1"); + else if (ooc_message.startsWith("/offset")) { + ui_ooc_chat_message->clear(); + ooc_message.remove(0, 8); + + bool ok; + int off = ooc_message.toInt(&ok); + if (ok) { + if (off >= -100 && off <= 100) { + char_offset = off; + QString msg = tr("You have set your offset to "); + msg.append(QString::number(off)); + msg.append("%."); + append_server_chatmessage("CLIENT", msg, "1"); + } + else { + append_server_chatmessage("CLIENT", tr("Your offset must be between -100% and 100%!"), "1"); + } + } + else { + append_server_chatmessage("CLIENT", tr("That offset does not look like one."), "1"); + } + return; } - return; - } - else if (ooc_message.startsWith("/offset")) - { - ui_ooc_chat_message->clear(); - ooc_message.remove(0,8); - - bool ok; - int off = ooc_message.toInt(&ok); - if (ok) - { - if (off >= -100 && off <= 100) - { - char_offset = off; - QString msg = tr("You have set your offset to "); - msg.append(QString::number(off)); - msg.append("%."); - append_server_chatmessage("CLIENT", msg, "1"); - } - else - { - append_server_chatmessage("CLIENT", tr("Your offset must be between -100% and 100%!"), "1"); - } - } - else - { - append_server_chatmessage("CLIENT", tr("That offset does not look like one."), "1"); - } - return; - } - else if (ooc_message.startsWith("/switch_am")) - { - append_server_chatmessage("CLIENT", tr("You switched your music and area list."), "1"); - on_switch_area_music_clicked(); - ui_ooc_chat_message->clear(); - return; - } - else if (ooc_message.startsWith("/enable_blocks")) - { - append_server_chatmessage("CLIENT", tr("You have forcefully enabled features that the server may not support. You may not be able to talk IC, or worse, because of this."), "1"); - ao_app->cccc_ic_support_enabled = true; - ao_app->arup_enabled = true; - ao_app->modcall_reason_enabled = true; - on_reload_theme_clicked(); - ui_ooc_chat_message->clear(); - return; - } - else if (ooc_message.startsWith("/non_int_pre")) - { - if (ui_pre_non_interrupt->isChecked()) - append_server_chatmessage("CLIENT", tr("Your pre-animations interrupt again."), "1"); - else - append_server_chatmessage("CLIENT", tr("Your pre-animations will not interrupt text."), "1"); - ui_pre_non_interrupt->setChecked(!ui_pre_non_interrupt->isChecked()); - ui_ooc_chat_message->clear(); - return; - } - else if (ooc_message.startsWith("/save_chatlog")) - { - QFile file("chatlog.txt"); - - if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) - { - append_server_chatmessage("CLIENT", tr("Couldn't open chatlog.txt to write into."), "1"); - ui_ooc_chat_message->clear(); - return; - } - - QTextStream out(&file); - - foreach (chatlogpiece item, ic_chatlog_history) { - out << item.get_full() << '\n'; - } - - file.close(); - - append_server_chatmessage("CLIENT", tr("The IC chatlog has been saved."), "1"); - ui_ooc_chat_message->clear(); - return; - } - else if (ooc_message.startsWith("/load_case")) - { - QStringList command = ooc_message.split(" ", QString::SkipEmptyParts); - - QDir casefolder("base/cases"); - if (!casefolder.exists()) - { - QDir::current().mkdir("base/" + casefolder.dirName()); - append_server_chatmessage("CLIENT", tr("You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely the case file you're looking for can't be found in there."), "1"); + else if (ooc_message.startsWith("/switch_am")) { + append_server_chatmessage("CLIENT", tr("You switched your music and area list."), "1"); + on_switch_area_music_clicked(); ui_ooc_chat_message->clear(); return; } - QStringList caseslist = casefolder.entryList(); - caseslist.removeOne("."); - caseslist.removeOne(".."); - caseslist.replaceInStrings(".ini",""); + else if (ooc_message.startsWith("/enable_blocks")) { + append_server_chatmessage("CLIENT", tr("You have forcefully enabled features that the server may not support. You may not be able to talk IC, or worse, because of this."), "1"); + ao_app->cccc_ic_support_enabled = true; + ao_app->arup_enabled = true; + ao_app->modcall_reason_enabled = true; + on_reload_theme_clicked(); + ui_ooc_chat_message->clear(); + return; + } + else if (ooc_message.startsWith("/non_int_pre")) { + if (ui_pre_non_interrupt->isChecked()) + append_server_chatmessage("CLIENT", tr("Your pre-animations interrupt again."), "1"); + else + append_server_chatmessage("CLIENT", tr("Your pre-animations will not interrupt text."), "1"); + ui_pre_non_interrupt->setChecked(!ui_pre_non_interrupt->isChecked()); + ui_ooc_chat_message->clear(); + return; + } + else if (ooc_message.startsWith("/save_chatlog")) { + QFile file("chatlog.txt"); - if (command.size() < 2) - { - append_server_chatmessage("CLIENT", tr("You need to give a filename to load (extension not needed)! Make sure that it is in the `base/cases/` folder, and that it is a correctly formatted ini.\nCases you can load: %1").arg(caseslist.join(", ")), "1"); - ui_ooc_chat_message->clear(); - return; + if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) { + append_server_chatmessage("CLIENT", tr("Couldn't open chatlog.txt to write into."), "1"); + ui_ooc_chat_message->clear(); + return; + } + + QTextStream out(&file); + + foreach (chatlogpiece item, ic_chatlog_history) { + out << item.get_full() << '\n'; + } + + file.close(); + + append_server_chatmessage("CLIENT", tr("The IC chatlog has been saved."), "1"); + ui_ooc_chat_message->clear(); + return; + } + else if (ooc_message.startsWith("/load_case")) { + QStringList command = ooc_message.split(" ", QString::SkipEmptyParts); + + QDir casefolder("base/cases"); + if (!casefolder.exists()) { + QDir::current().mkdir("base/" + casefolder.dirName()); + append_server_chatmessage("CLIENT", tr("You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely the case file you're looking for can't be found in there."), "1"); + ui_ooc_chat_message->clear(); + return; + } + QStringList caseslist = casefolder.entryList(); + caseslist.removeOne("."); + caseslist.removeOne(".."); + caseslist.replaceInStrings(".ini", ""); + + if (command.size() < 2) { + append_server_chatmessage("CLIENT", tr("You need to give a filename to load (extension not needed)! Make sure that it is in the `base/cases/` folder, and that it is a correctly formatted ini.\nCases you can load: %1").arg(caseslist.join(", ")), "1"); + ui_ooc_chat_message->clear(); + return; + } + + if (command.size() > 2) { + append_server_chatmessage("CLIENT", tr("Too many arguments to load a case! You only need one filename, without extension."), "1"); + ui_ooc_chat_message->clear(); + return; + } + + QSettings casefile("base/cases/" + command[1] + ".ini", QSettings::IniFormat); + + QString caseauth = casefile.value("author", "").value(); + QString casedoc = casefile.value("doc", "").value(); + QString cmdoc = casefile.value("cmdoc", "").value(); + QString casestatus = casefile.value("status", "").value(); + + if (!caseauth.isEmpty()) + append_server_chatmessage("CLIENT", tr("Case made by %1.").arg(caseauth), "1"); + if (!casedoc.isEmpty()) + ao_app->send_server_packet(new AOPacket("CT#" + ui_ooc_chat_name->text() + "#/doc " + casedoc + "#%")); + if (!casestatus.isEmpty()) + ao_app->send_server_packet(new AOPacket("CT#" + ui_ooc_chat_name->text() + "#/status " + casestatus + "#%")); + if (!cmdoc.isEmpty()) + append_server_chatmessage("CLIENT", tr("Navigate to %1 for the CM doc.").arg(cmdoc), "1"); + + for (int i = local_evidence_list.size() - 1; i >= 0; i--) { + ao_app->send_server_packet(new AOPacket("DE#" + QString::number(i) + "#%")); + } + + foreach (QString evi, casefile.childGroups()) { + if (evi == "General") + continue; + + QStringList f_contents; + + f_contents.append(casefile.value(evi + "/name", "UNKNOWN").value()); + f_contents.append(casefile.value(evi + "/description", "UNKNOWN").value()); + f_contents.append(casefile.value(evi + "/image", "UNKNOWN.png").value()); + + ao_app->send_server_packet(new AOPacket("PE", f_contents)); + } + + append_server_chatmessage("CLIENT", tr("Your case \"%1\" was loaded!").arg(command[1]), "1"); + ui_ooc_chat_message->clear(); + return; + } + else if (ooc_message.startsWith("/save_case")) { + QStringList command = ooc_message.split(" ", QString::SkipEmptyParts); + + QDir casefolder("base/cases"); + if (!casefolder.exists()) { + QDir::current().mkdir("base/" + casefolder.dirName()); + append_server_chatmessage("CLIENT", tr("You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely that you somehow deleted it."), "1"); + ui_ooc_chat_message->clear(); + return; + } + QStringList caseslist = casefolder.entryList(); + caseslist.removeOne("."); + caseslist.removeOne(".."); + caseslist.replaceInStrings(".ini", ""); + + if (command.size() < 3) { + append_server_chatmessage("CLIENT", tr("You need to give a filename to save (extension not needed) and the courtroom status!"), "1"); + ui_ooc_chat_message->clear(); + return; + } + + if (command.size() > 3) { + append_server_chatmessage("CLIENT", tr("Too many arguments to save a case! You only need a filename without extension and the courtroom status!"), "1"); + ui_ooc_chat_message->clear(); + return; + } + QSettings casefile("base/cases/" + command[1] + ".ini", QSettings::IniFormat); + casefile.setValue("author", ui_ooc_chat_name->text()); + casefile.setValue("cmdoc", ""); + casefile.setValue("doc", ""); + casefile.setValue("status", command[2]); + casefile.sync(); + for (int i = 0; i < local_evidence_list.size(); i++) { + QString clean_evidence_dsc = local_evidence_list[i].description.replace(QRegularExpression("..."), ""); + clean_evidence_dsc = clean_evidence_dsc.replace(clean_evidence_dsc.lastIndexOf(">"), 1, ""); + casefile.beginGroup(QString::number(i)); + casefile.sync(); + casefile.setValue("name", local_evidence_list[i].name); + casefile.setValue("description", local_evidence_list[i].description); + casefile.setValue("image", local_evidence_list[i].image); + casefile.endGroup(); + } + casefile.sync(); + append_server_chatmessage("CLIENT", tr("Succesfully saved, edit doc and cmdoc link on the ini!"), "1"); + ui_ooc_chat_message->clear(); + return; } + QStringList packet_contents; + packet_contents.append(ui_ooc_chat_name->text()); + packet_contents.append(ooc_message); - if (command.size() > 2) - { - append_server_chatmessage("CLIENT", tr("Too many arguments to load a case! You only need one filename, without extension."), "1"); - ui_ooc_chat_message->clear(); - return; - } + AOPacket *f_packet = new AOPacket("CT", packet_contents); - QSettings casefile("base/cases/" + command[1] + ".ini", QSettings::IniFormat); + if (server_ooc) + ao_app->send_server_packet(f_packet); + else + ao_app->send_ms_packet(f_packet); - QString caseauth = casefile.value("author", "").value(); - QString casedoc = casefile.value("doc", "").value(); - QString cmdoc = casefile.value("cmdoc", "").value(); - QString casestatus = casefile.value("status", "").value(); - - if (!caseauth.isEmpty()) - append_server_chatmessage("CLIENT", tr("Case made by %1.").arg(caseauth), "1"); - if (!casedoc.isEmpty()) - ao_app->send_server_packet(new AOPacket("CT#" + ui_ooc_chat_name->text() + "#/doc " + casedoc + "#%")); - if (!casestatus.isEmpty()) - ao_app->send_server_packet(new AOPacket("CT#" + ui_ooc_chat_name->text() + "#/status " + casestatus + "#%")); - if (!cmdoc.isEmpty()) - append_server_chatmessage("CLIENT", tr("Navigate to %1 for the CM doc.").arg(cmdoc), "1"); - - for (int i = local_evidence_list.size() - 1; i >= 0; i--) { - ao_app->send_server_packet(new AOPacket("DE#" + QString::number(i) + "#%")); - } - - foreach (QString evi, casefile.childGroups()) { - if (evi == "General") - continue; - - QStringList f_contents; - - f_contents.append(casefile.value(evi + "/name", "UNKNOWN").value()); - f_contents.append(casefile.value(evi + "/description", "UNKNOWN").value()); - f_contents.append(casefile.value(evi + "/image", "UNKNOWN.png").value()); - - ao_app->send_server_packet(new AOPacket("PE", f_contents)); - } - - append_server_chatmessage("CLIENT", tr("Your case \"%1\" was loaded!").arg(command[1]), "1"); ui_ooc_chat_message->clear(); - return; - } - else if(ooc_message.startsWith("/save_case")) - { - QStringList command = ooc_message.split(" ", QString::SkipEmptyParts); - QDir casefolder("base/cases"); - if (!casefolder.exists()) - { - QDir::current().mkdir("base/" + casefolder.dirName()); - append_server_chatmessage("CLIENT", tr("You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely that you somehow deleted it."), "1"); - ui_ooc_chat_message->clear(); - return; - } - QStringList caseslist = casefolder.entryList(); - caseslist.removeOne("."); - caseslist.removeOne(".."); - caseslist.replaceInStrings(".ini",""); - - if (command.size() < 3) - { - append_server_chatmessage("CLIENT", tr("You need to give a filename to save (extension not needed) and the courtroom status!"), "1"); - ui_ooc_chat_message->clear(); - return; - } - - - if (command.size() > 3) - { - append_server_chatmessage("CLIENT", tr("Too many arguments to save a case! You only need a filename without extension and the courtroom status!"), "1"); - ui_ooc_chat_message->clear(); - return; - } - QSettings casefile("base/cases/" + command[1] + ".ini", QSettings::IniFormat); - casefile.setValue("author",ui_ooc_chat_name->text()); - casefile.setValue("cmdoc",""); - casefile.setValue("doc", ""); - casefile.setValue("status",command[2]); - casefile.sync(); - for(int i = 0; i < local_evidence_list.size(); i++) - { - QString clean_evidence_dsc = local_evidence_list[i].description.replace(QRegularExpression("..."), ""); - clean_evidence_dsc = clean_evidence_dsc.replace(clean_evidence_dsc.lastIndexOf(">"), 1, ""); - casefile.beginGroup(QString::number(i)); - casefile.sync(); - casefile.setValue("name",local_evidence_list[i].name); - casefile.setValue("description",local_evidence_list[i].description); - casefile.setValue("image",local_evidence_list[i].image); - casefile.endGroup(); - } - casefile.sync(); - append_server_chatmessage("CLIENT", tr("Succesfully saved, edit doc and cmdoc link on the ini!"), "1"); - ui_ooc_chat_message->clear(); - return; - - } - - QStringList packet_contents; - packet_contents.append(ui_ooc_chat_name->text()); - packet_contents.append(ooc_message); - - AOPacket *f_packet = new AOPacket("CT", packet_contents); - - if (server_ooc) - ao_app->send_server_packet(f_packet); - else - ao_app->send_ms_packet(f_packet); - - ui_ooc_chat_message->clear(); - - ui_ooc_chat_message->setFocus(); + ui_ooc_chat_message->setFocus(); } void Courtroom::on_ooc_toggle_clicked() { - if (server_ooc) - { - ui_ms_chatlog->show(); - ui_server_chatlog->hide(); - ui_ooc_toggle->setText(tr("Master")); + if (server_ooc) { + ui_ms_chatlog->show(); + ui_server_chatlog->hide(); + ui_ooc_toggle->setText(tr("Master")); - server_ooc = false; - } - else - { - ui_ms_chatlog->hide(); - ui_server_chatlog->show(); - ui_ooc_toggle->setText(tr("Server")); + server_ooc = false; + } + else { + ui_ms_chatlog->hide(); + ui_server_chatlog->show(); + ui_ooc_toggle->setText(tr("Server")); - server_ooc = true; - } + server_ooc = true; + } } //Todo: multithread this due to some servers having large as hell music list void Courtroom::on_music_search_edited(QString p_text) { - // Iterate through all QTreeWidgetItem items - if (!ui_music_list->isHidden()) - { - QTreeWidgetItemIterator it(ui_music_list); - while (*it) - { - (*it)->setHidden(p_text != ""); - ++it; - } - } - - if (!ui_area_list->isHidden()) - { - QTreeWidgetItemIterator ait(ui_area_list); - while (*ait) - { - (*ait)->setHidden(p_text != ""); - ++ait; - } - } - - if (p_text != "") - { - if (!ui_music_list->isHidden()) - { - //Search in metadata - QList clist = ui_music_list->findItems(ui_music_search->text(), Qt::MatchContains|Qt::MatchRecursive, 1); - foreach(QTreeWidgetItem* item, clist) - { - if (item->parent() != nullptr) //So the category shows up too - item->parent()->setHidden(false); - item->setHidden(false); - } + // Iterate through all QTreeWidgetItem items + if (!ui_music_list->isHidden()) { + QTreeWidgetItemIterator it(ui_music_list); + while (*it) { + (*it)->setHidden(p_text != ""); + ++it; + } } - if (!ui_area_list->isHidden()) - { - //Search in metadata - QList alist = ui_area_list->findItems(ui_music_search->text(), Qt::MatchContains|Qt::MatchRecursive, 1); - foreach(QTreeWidgetItem* item, alist) - { - if (item->parent() != nullptr) //So the category shows up too - item->parent()->setHidden(false); - item->setHidden(false); - } + if (!ui_area_list->isHidden()) { + QTreeWidgetItemIterator ait(ui_area_list); + while (*ait) { + (*ait)->setHidden(p_text != ""); + ++ait; + } + } + + if (p_text != "") { + if (!ui_music_list->isHidden()) { + //Search in metadata + QList clist = ui_music_list->findItems(ui_music_search->text(), Qt::MatchContains | Qt::MatchRecursive, 1); + foreach (QTreeWidgetItem *item, clist) { + if (item->parent() != nullptr) //So the category shows up too + item->parent()->setHidden(false); + item->setHidden(false); + } + } + + if (!ui_area_list->isHidden()) { + //Search in metadata + QList alist = ui_area_list->findItems(ui_music_search->text(), Qt::MatchContains | Qt::MatchRecursive, 1); + foreach (QTreeWidgetItem *item, alist) { + if (item->parent() != nullptr) //So the category shows up too + item->parent()->setHidden(false); + item->setHidden(false); + } + } } - } } void Courtroom::on_pos_dropdown_changed(int p_index) { - if (p_index < 0 || p_index > 7) - return; + if (p_index < 0 || p_index > 7) + return; - toggle_judge_buttons(false); + toggle_judge_buttons(false); - QString f_pos = ui_pos_dropdown->itemText(p_index); + QString f_pos = ui_pos_dropdown->itemText(p_index); - if (f_pos == "") - return; + if (f_pos == "") + return; - if (f_pos == "jud") - toggle_judge_buttons(true); + if (f_pos == "jud") + toggle_judge_buttons(true); - //YEAH SENDING LIKE 20 PACKETS IF THE USER SCROLLS THROUGH, GREAT IDEA - //how about this instead - set_side(f_pos); + //YEAH SENDING LIKE 20 PACKETS IF THE USER SCROLLS THROUGH, GREAT IDEA + //how about this instead + set_side(f_pos); } void Courtroom::set_iniswap_dropdown() { - ui_iniswap_dropdown->blockSignals(true); - ui_iniswap_dropdown->clear(); - if (m_cid == -1) - { - ui_iniswap_dropdown->hide(); - ui_iniswap_remove->hide(); - return; - } - QStringList iniswaps = ao_app->get_list_file(ao_app->get_character_path(char_list.at(m_cid).name, "iniswaps.ini")); - iniswaps.prepend(char_list.at(m_cid).name); - if (iniswaps.size() <= 0) - { - ui_iniswap_dropdown->hide(); - ui_iniswap_remove->hide(); - return; - } - ui_iniswap_dropdown->show(); - ui_iniswap_dropdown->addItems(iniswaps); - - for (int i = 0; i < iniswaps.size(); ++i) - { - if (iniswaps.at(i) == current_char) - { - ui_iniswap_dropdown->setCurrentIndex(i); - if (i != 0) - ui_iniswap_remove->show(); - else + ui_iniswap_dropdown->blockSignals(true); + ui_iniswap_dropdown->clear(); + if (m_cid == -1) { + ui_iniswap_dropdown->hide(); ui_iniswap_remove->hide(); - break; + return; } - } - ui_iniswap_dropdown->blockSignals(false); + QStringList iniswaps = ao_app->get_list_file(ao_app->get_character_path(char_list.at(m_cid).name, "iniswaps.ini")); + iniswaps.prepend(char_list.at(m_cid).name); + if (iniswaps.size() <= 0) { + ui_iniswap_dropdown->hide(); + ui_iniswap_remove->hide(); + return; + } + ui_iniswap_dropdown->show(); + ui_iniswap_dropdown->addItems(iniswaps); + + for (int i = 0; i < iniswaps.size(); ++i) { + if (iniswaps.at(i) == current_char) { + ui_iniswap_dropdown->setCurrentIndex(i); + if (i != 0) + ui_iniswap_remove->show(); + else + ui_iniswap_remove->hide(); + break; + } + } + ui_iniswap_dropdown->blockSignals(false); } void Courtroom::on_iniswap_dropdown_changed(int p_index) { - ui_ic_chat_message->setFocus(); - QString iniswap = ui_iniswap_dropdown->itemText(p_index); - ao_app->set_char_ini(char_list.at(m_cid).name, iniswap, "name", "Options"); + ui_ic_chat_message->setFocus(); + QString iniswap = ui_iniswap_dropdown->itemText(p_index); + ao_app->set_char_ini(char_list.at(m_cid).name, iniswap, "name", "Options"); - QStringList swaplist; - for (int i = 0; i < ui_iniswap_dropdown->count(); ++i) - { - QString entry = ui_iniswap_dropdown->itemText(i); - if (!swaplist.contains(entry) && entry != char_list.at(m_cid).name) - swaplist.append(entry); - } - ao_app->write_to_file(swaplist.join("\n"), ao_app->get_character_path(char_list.at(m_cid).name, "iniswaps.ini")); - ui_iniswap_dropdown->blockSignals(true); - ui_iniswap_dropdown->setCurrentIndex(p_index); - ui_iniswap_dropdown->blockSignals(false); - update_character(m_cid); - if (p_index != 0) - ui_iniswap_remove->show(); - else - ui_iniswap_remove->hide(); + QStringList swaplist; + for (int i = 0; i < ui_iniswap_dropdown->count(); ++i) { + QString entry = ui_iniswap_dropdown->itemText(i); + if (!swaplist.contains(entry) && entry != char_list.at(m_cid).name) + swaplist.append(entry); + } + ao_app->write_to_file(swaplist.join("\n"), ao_app->get_character_path(char_list.at(m_cid).name, "iniswaps.ini")); + ui_iniswap_dropdown->blockSignals(true); + ui_iniswap_dropdown->setCurrentIndex(p_index); + ui_iniswap_dropdown->blockSignals(false); + update_character(m_cid); + if (p_index != 0) + ui_iniswap_remove->show(); + else + ui_iniswap_remove->hide(); } void Courtroom::on_iniswap_context_menu_requested(const QPoint &pos) { - QMenu *menu = ui_iniswap_dropdown->lineEdit()->createStandardContextMenu(); + QMenu *menu = ui_iniswap_dropdown->lineEdit()->createStandardContextMenu(); - menu->addSeparator(); - if (file_exists(ao_app->get_character_path(current_char, "char.ini"))) - menu->addAction(QString("Edit " + current_char + "/char.ini"), this, SLOT(on_iniswap_edit_requested())); - if (ui_iniswap_dropdown->itemText(ui_iniswap_dropdown->currentIndex()) != char_list.at(m_cid).name) - menu->addAction(QString("Remove " + current_char), this, SLOT(on_iniswap_remove_clicked())); - menu->popup(ui_iniswap_dropdown->mapToGlobal(pos)); + menu->addSeparator(); + if (file_exists(ao_app->get_character_path(current_char, "char.ini"))) + menu->addAction(QString("Edit " + current_char + "/char.ini"), this, SLOT(on_iniswap_edit_requested())); + if (ui_iniswap_dropdown->itemText(ui_iniswap_dropdown->currentIndex()) != char_list.at(m_cid).name) + menu->addAction(QString("Remove " + current_char), this, SLOT(on_iniswap_remove_clicked())); + menu->popup(ui_iniswap_dropdown->mapToGlobal(pos)); } void Courtroom::on_iniswap_edit_requested() { - QString p_path = ao_app->get_character_path(current_char, "char.ini"); - if (!file_exists(p_path)) - return; - QDesktopServices::openUrl(QUrl::fromLocalFile(p_path)); + QString p_path = ao_app->get_character_path(current_char, "char.ini"); + if (!file_exists(p_path)) + return; + QDesktopServices::openUrl(QUrl::fromLocalFile(p_path)); } void Courtroom::on_iniswap_remove_clicked() { - if (ui_iniswap_dropdown->count() <= 0) - { - ui_iniswap_remove->hide(); //We're not supposed to see it. Do this or the client will crash - return; - } - if (ui_iniswap_dropdown->itemText(ui_iniswap_dropdown->currentIndex()) != char_list.at(m_cid).name) - { - ui_iniswap_dropdown->removeItem(ui_iniswap_dropdown->currentIndex()); - on_iniswap_dropdown_changed(0); //Reset back to original - update_character(m_cid); - } + if (ui_iniswap_dropdown->count() <= 0) { + ui_iniswap_remove->hide(); //We're not supposed to see it. Do this or the client will crash + return; + } + if (ui_iniswap_dropdown->itemText(ui_iniswap_dropdown->currentIndex()) != char_list.at(m_cid).name) { + ui_iniswap_dropdown->removeItem(ui_iniswap_dropdown->currentIndex()); + on_iniswap_dropdown_changed(0); //Reset back to original + update_character(m_cid); + } } void Courtroom::set_sfx_dropdown() { - ui_sfx_dropdown->blockSignals(true); - ui_sfx_dropdown->clear(); - if (m_cid == -1) - { - ui_sfx_dropdown->hide(); - ui_sfx_remove->hide(); - return; - } - QStringList soundlist = ao_app->get_list_file(ao_app->get_character_path(current_char, "soundlist.ini")); - - if (soundlist.size() <= 0) - { - soundlist = ao_app->get_list_file(ao_app->get_theme_path("character_soundlist.ini")); - if (soundlist.size() <= 0) - { - soundlist = ao_app->get_list_file(ao_app->get_default_theme_path("character_soundlist.ini")); + ui_sfx_dropdown->blockSignals(true); + ui_sfx_dropdown->clear(); + if (m_cid == -1) { + ui_sfx_dropdown->hide(); + ui_sfx_remove->hide(); + return; } - } + QStringList soundlist = ao_app->get_list_file(ao_app->get_character_path(current_char, "soundlist.ini")); - if (soundlist.size() <= 0) - { - ui_sfx_dropdown->hide(); + if (soundlist.size() <= 0) { + soundlist = ao_app->get_list_file(ao_app->get_theme_path("character_soundlist.ini")); + if (soundlist.size() <= 0) { + soundlist = ao_app->get_list_file(ao_app->get_default_theme_path("character_soundlist.ini")); + } + } + + if (soundlist.size() <= 0) { + ui_sfx_dropdown->hide(); + ui_sfx_remove->hide(); + return; + } + soundlist.prepend("Default"); + + ui_sfx_dropdown->show(); + ui_sfx_dropdown->addItems(soundlist); + ui_sfx_dropdown->setCurrentIndex(0); ui_sfx_remove->hide(); - return; - } - soundlist.prepend("Default"); - - ui_sfx_dropdown->show(); - ui_sfx_dropdown->addItems(soundlist); - ui_sfx_dropdown->setCurrentIndex(0); - ui_sfx_remove->hide(); - ui_sfx_dropdown->blockSignals(false); + ui_sfx_dropdown->blockSignals(false); } void Courtroom::on_sfx_dropdown_changed(int p_index) { - ui_ic_chat_message->setFocus(); + ui_ic_chat_message->setFocus(); - QStringList soundlist; - for (int i = 0; i < ui_sfx_dropdown->count(); ++i) - { - QString entry = ui_sfx_dropdown->itemText(i); - if (!soundlist.contains(entry) && entry != "Default") - soundlist.append(entry); - } + QStringList soundlist; + for (int i = 0; i < ui_sfx_dropdown->count(); ++i) { + QString entry = ui_sfx_dropdown->itemText(i); + if (!soundlist.contains(entry) && entry != "Default") + soundlist.append(entry); + } - QStringList defaultlist = ao_app->get_list_file(ao_app->get_theme_path("character_soundlist.ini")); - if (defaultlist.size() <= 0) - { - defaultlist = ao_app->get_list_file(ao_app->get_default_theme_path("character_soundlist.ini")); - } + QStringList defaultlist = ao_app->get_list_file(ao_app->get_theme_path("character_soundlist.ini")); + if (defaultlist.size() <= 0) { + defaultlist = ao_app->get_list_file(ao_app->get_default_theme_path("character_soundlist.ini")); + } - if (defaultlist.size() > 0 && defaultlist.toSet().subtract(soundlist.toSet()).size() > 0) //There's a difference from the default configuration - ao_app->write_to_file(soundlist.join("\n"), ao_app->get_character_path(current_char, "soundlist.ini")); //Create a new sound list + if (defaultlist.size() > 0 && defaultlist.toSet().subtract(soundlist.toSet()).size() > 0) //There's a difference from the default configuration + ao_app->write_to_file(soundlist.join("\n"), ao_app->get_character_path(current_char, "soundlist.ini")); //Create a new sound list - ui_sfx_dropdown->blockSignals(true); - ui_sfx_dropdown->setCurrentIndex(p_index); - ui_sfx_dropdown->blockSignals(false); - if (p_index != 0) - ui_sfx_remove->show(); - else - ui_sfx_remove->hide(); + ui_sfx_dropdown->blockSignals(true); + ui_sfx_dropdown->setCurrentIndex(p_index); + ui_sfx_dropdown->blockSignals(false); + if (p_index != 0) + ui_sfx_remove->show(); + else + ui_sfx_remove->hide(); } void Courtroom::on_sfx_context_menu_requested(const QPoint &pos) { - QMenu *menu = ui_sfx_dropdown->lineEdit()->createStandardContextMenu(); + QMenu *menu = ui_sfx_dropdown->lineEdit()->createStandardContextMenu(); - menu->addSeparator(); - if (file_exists(ao_app->get_character_path(current_char, "soundlist.ini"))) - menu->addAction(QString("Edit " + current_char + "/soundlist.ini"), this, SLOT(on_sfx_edit_requested())); - else - menu->addAction(QString("Edit theme's character_soundlist.ini"), this, SLOT(on_sfx_edit_requested())); - if (ui_sfx_dropdown->currentIndex() != 0) - menu->addAction(QString("Remove " + ui_sfx_dropdown->itemText(ui_sfx_dropdown->currentIndex())), this, SLOT(on_sfx_remove_clicked())); - menu->popup(ui_sfx_dropdown->mapToGlobal(pos)); + menu->addSeparator(); + if (file_exists(ao_app->get_character_path(current_char, "soundlist.ini"))) + menu->addAction(QString("Edit " + current_char + "/soundlist.ini"), this, SLOT(on_sfx_edit_requested())); + else + menu->addAction(QString("Edit theme's character_soundlist.ini"), this, SLOT(on_sfx_edit_requested())); + if (ui_sfx_dropdown->currentIndex() != 0) + menu->addAction(QString("Remove " + ui_sfx_dropdown->itemText(ui_sfx_dropdown->currentIndex())), this, SLOT(on_sfx_remove_clicked())); + menu->popup(ui_sfx_dropdown->mapToGlobal(pos)); } void Courtroom::on_sfx_edit_requested() { - QString p_path = ao_app->get_character_path(current_char, "soundlist.ini"); - if (!file_exists(p_path)) - { - p_path = ao_app->get_theme_path("character_soundlist.ini"); - if (!file_exists(p_path)) - { - p_path = ao_app->get_default_theme_path("character_soundlist.ini"); - if (!file_exists(p_path)) - { - return; - } + QString p_path = ao_app->get_character_path(current_char, "soundlist.ini"); + if (!file_exists(p_path)) { + p_path = ao_app->get_theme_path("character_soundlist.ini"); + if (!file_exists(p_path)) { + p_path = ao_app->get_default_theme_path("character_soundlist.ini"); + if (!file_exists(p_path)) { + return; + } + } } - } - QDesktopServices::openUrl(QUrl::fromLocalFile(p_path)); + QDesktopServices::openUrl(QUrl::fromLocalFile(p_path)); } void Courtroom::on_sfx_remove_clicked() { - if (ui_sfx_dropdown->count() <= 0) - { - ui_sfx_remove->hide(); //We're not supposed to see it. Do this or the client will crash - return; - } - if (ui_sfx_dropdown->itemText(ui_sfx_dropdown->currentIndex()) != "Default") - { - ui_sfx_dropdown->removeItem(ui_sfx_dropdown->currentIndex()); - on_sfx_dropdown_changed(0); //Reset back to original - } + if (ui_sfx_dropdown->count() <= 0) { + ui_sfx_remove->hide(); //We're not supposed to see it. Do this or the client will crash + return; + } + if (ui_sfx_dropdown->itemText(ui_sfx_dropdown->currentIndex()) != "Default") { + ui_sfx_dropdown->removeItem(ui_sfx_dropdown->currentIndex()); + on_sfx_dropdown_changed(0); //Reset back to original + } } void Courtroom::set_effects_dropdown() { - ui_effects_dropdown->blockSignals(true); - ui_effects_dropdown->clear(); - if (m_cid == -1) - { - ui_effects_dropdown->hide(); - return; - } - QStringList effectslist = ao_app->get_effects(current_char); - - if (effectslist.size() <= 0) - { - ui_effects_dropdown->hide(); - return; - } - - - effectslist.prepend("None"); - - ui_effects_dropdown->show(); - ui_effects_dropdown->addItems(effectslist); - - //ICON-MAKING HELL - QString p_effect = ao_app->read_char_ini(current_char, "effects", "Options"); - 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/"); - 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); - if (!file_exists(iconpath)) - { - iconpath = ao_app->get_static_image_suffix(theme_path + entry); - if (!file_exists(iconpath)) - { - iconpath = ao_app->get_static_image_suffix(default_path + entry); - if (!file_exists(iconpath)) - continue; - } + ui_effects_dropdown->blockSignals(true); + ui_effects_dropdown->clear(); + if (m_cid == -1) { + ui_effects_dropdown->hide(); + return; } - ui_effects_dropdown->setItemIcon(i, QIcon(iconpath)); - } + QStringList effectslist = ao_app->get_effects(current_char); - ui_effects_dropdown->setCurrentIndex(0); - ui_effects_dropdown->blockSignals(false); + if (effectslist.size() <= 0) { + ui_effects_dropdown->hide(); + return; + } + + effectslist.prepend("None"); + + ui_effects_dropdown->show(); + ui_effects_dropdown->addItems(effectslist); + + //ICON-MAKING HELL + QString p_effect = ao_app->read_char_ini(current_char, "effects", "Options"); + 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/"); + 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); + if (!file_exists(iconpath)) { + iconpath = ao_app->get_static_image_suffix(theme_path + entry); + if (!file_exists(iconpath)) { + iconpath = ao_app->get_static_image_suffix(default_path + entry); + if (!file_exists(iconpath)) + continue; + } + } + ui_effects_dropdown->setItemIcon(i, QIcon(iconpath)); + } + + ui_effects_dropdown->setCurrentIndex(0); + ui_effects_dropdown->blockSignals(false); } void Courtroom::on_effects_context_menu_requested(const QPoint &pos) { - QMenu *menu = new QMenu(); + QMenu *menu = new QMenu(); - if (!ao_app->read_char_ini(current_char, "effects", "Options").isEmpty()) - menu->addAction(QString("Open misc/" + ao_app->read_char_ini(current_char, "effects", "Options") + " folder"), this, SLOT(on_character_effects_edit_requested())); - menu->addAction(QString("Open theme's effects folder"), this, SLOT(on_effects_edit_requested())); - menu->popup(ui_effects_dropdown->mapToGlobal(pos)); + if (!ao_app->read_char_ini(current_char, "effects", "Options").isEmpty()) + menu->addAction(QString("Open misc/" + ao_app->read_char_ini(current_char, "effects", "Options") + " folder"), this, SLOT(on_character_effects_edit_requested())); + menu->addAction(QString("Open theme's effects folder"), this, SLOT(on_effects_edit_requested())); + menu->popup(ui_effects_dropdown->mapToGlobal(pos)); } 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/"); - if (!dir_exists(p_path)) - { - return; + QString p_path = ao_app->get_theme_path("effects/"); + if (!dir_exists(p_path)) { + p_path = ao_app->get_default_theme_path("effects/"); + if (!dir_exists(p_path)) { + return; + } } - } - QDesktopServices::openUrl(QUrl::fromLocalFile(p_path)); + QDesktopServices::openUrl(QUrl::fromLocalFile(p_path)); } void Courtroom::on_character_effects_edit_requested() { - QString p_effect = ao_app->read_char_ini(current_char, "effects", "Options"); - QString p_path = ao_app->get_base_path() + "misc/" + p_effect + "/"; - if (!dir_exists(p_path)) - return; + QString p_effect = ao_app->read_char_ini(current_char, "effects", "Options"); + QString p_path = ao_app->get_base_path() + "misc/" + p_effect + "/"; + if (!dir_exists(p_path)) + return; - QDesktopServices::openUrl(QUrl::fromLocalFile(p_path)); + QDesktopServices::openUrl(QUrl::fromLocalFile(p_path)); } void Courtroom::on_effects_dropdown_changed(int p_index) { - effect = ui_effects_dropdown->itemText(p_index); - ui_ic_chat_message->setFocus(); + effect = ui_effects_dropdown->itemText(p_index); + ui_ic_chat_message->setFocus(); } bool Courtroom::effects_dropdown_find_and_set(QString effect) { - for (int i = 0; i < ui_effects_dropdown->count(); ++i) - { - QString entry = ui_effects_dropdown->itemText(i); - if (entry == effect) - { - ui_effects_dropdown->setCurrentIndex(i); - return true; + for (int i = 0; i < ui_effects_dropdown->count(); ++i) { + QString entry = ui_effects_dropdown->itemText(i); + if (entry == effect) { + ui_effects_dropdown->setCurrentIndex(i); + return true; + } } - } - return false; + return false; } QString Courtroom::get_char_sfx() { - QString sfx = ui_sfx_dropdown->itemText(ui_sfx_dropdown->currentIndex()); - if (sfx != "" && sfx != "Default") - return sfx; - return ao_app->get_sfx_name(current_char, current_emote); + QString sfx = ui_sfx_dropdown->itemText(ui_sfx_dropdown->currentIndex()); + if (sfx != "" && sfx != "Default") + return sfx; + return ao_app->get_sfx_name(current_char, current_emote); } int Courtroom::get_char_sfx_delay() { -// QString sfx = ui_sfx_dropdown->itemText(ui_sfx_dropdown->currentIndex()); -// if (sfx != "" && sfx != "Default") -// return 0; //todo: a way to define this - return ao_app->get_sfx_delay(current_char, current_emote); + // QString sfx = ui_sfx_dropdown->itemText(ui_sfx_dropdown->currentIndex()); + // if (sfx != "" && sfx != "Default") + // return 0; //todo: a way to define this + return ao_app->get_sfx_delay(current_char, current_emote); } void Courtroom::on_mute_list_clicked(QModelIndex p_index) { - QListWidgetItem *f_item = ui_mute_list->item(p_index.row()); - QString f_char = f_item->text(); - QString real_char; + QListWidgetItem *f_item = ui_mute_list->item(p_index.row()); + QString f_char = f_item->text(); + QString real_char; - if (f_char.endsWith(" [x]")) - real_char = f_char.left(f_char.size() - 4); - else - real_char = f_char; + if (f_char.endsWith(" [x]")) + real_char = f_char.left(f_char.size() - 4); + else + real_char = f_char; - int f_cid = -1; + int f_cid = -1; - 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; - } + 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 < 0 || f_cid >= char_list.size()) - { - qDebug() << "W: " << real_char << " not present in char_list"; - return; - } + if (f_cid < 0 || f_cid >= char_list.size()) { + qDebug() << "W: " << real_char << " not present in char_list"; + return; + } - if (mute_map.value(f_cid)) - { - mute_map.insert(f_cid, false); - f_item->setText(real_char); - } - else - { - mute_map.insert(f_cid, true); - f_item->setText(real_char + " [x]"); - } + if (mute_map.value(f_cid)) { + mute_map.insert(f_cid, false); + f_item->setText(real_char); + } + else { + mute_map.insert(f_cid, true); + f_item->setText(real_char + " [x]"); + } } 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; + 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_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()) { + qDebug() << "W: " << real_char << " not present in char_list"; + return; + } + other_charid = f_cid; + // Redo the character list. + QStringList sorted_pair_list; - if (f_cid < -2 || f_cid >= char_list.size()) - { - qDebug() << "W: " << real_char << " not present in char_list"; - return; - } + for (char_type i_char : char_list) + sorted_pair_list.append(i_char.name); - other_charid = f_cid; + sorted_pair_list.sort(); - // Redo the character list. - QStringList sorted_pair_list; - - for (char_type i_char : 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]"); - } + 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) { - if (is_muted) - return; + if (is_muted) + return; - column = 1; //Column 1 is always the metadata (which we want) - QString p_song = p_item->text(column); + column = 1; //Column 1 is always the metadata (which we want) + QString p_song = p_item->text(column); - 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_support_enabled) || ao_app->effects_enabled) - packet_contents.append(ui_ic_chat_name->text()); - if (ao_app->effects_enabled) - packet_contents.append(QString::number(music_flags)); - ao_app->send_server_packet(new AOPacket("MC", packet_contents), false); + 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_support_enabled) || ao_app->effects_enabled) + packet_contents.append(ui_ic_chat_name->text()); + if (ao_app->effects_enabled) + 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) { - QMenu *menu = new QMenu(); + QMenu *menu = new QMenu(); - menu->addAction(QString("Expand All Categories"), this, SLOT(music_list_expand_all())); - menu->addAction(QString("Collapse All Categories"), this, SLOT(music_list_collapse_all())); - menu->addSeparator(); + menu->addAction(QString("Expand All Categories"), this, SLOT(music_list_expand_all())); + menu->addAction(QString("Collapse All Categories"), this, SLOT(music_list_collapse_all())); + menu->addSeparator(); - menu->addAction(new QAction("Fade Out Previous", this)); - menu->actions().back()->setCheckable(true); - menu->actions().back()->setChecked(music_flags & FADE_OUT); - connect(menu->actions().back(), SIGNAL(toggled(bool)), this, SLOT(music_fade_out(bool))); + menu->addAction(new QAction("Fade Out Previous", this)); + menu->actions().back()->setCheckable(true); + menu->actions().back()->setChecked(music_flags & FADE_OUT); + connect(menu->actions().back(), SIGNAL(toggled(bool)), this, SLOT(music_fade_out(bool))); - menu->addAction(new QAction("Fade In", this)); - menu->actions().back()->setCheckable(true); - menu->actions().back()->setChecked(music_flags & FADE_IN); - connect(menu->actions().back(), SIGNAL(toggled(bool)), this, SLOT(music_fade_in(bool))); + menu->addAction(new QAction("Fade In", this)); + menu->actions().back()->setCheckable(true); + menu->actions().back()->setChecked(music_flags & FADE_IN); + connect(menu->actions().back(), SIGNAL(toggled(bool)), this, SLOT(music_fade_in(bool))); - menu->addAction(new QAction("Synchronize", this)); - menu->actions().back()->setCheckable(true); - menu->actions().back()->setChecked(music_flags & SYNC_POS); - connect(menu->actions().back(), SIGNAL(toggled(bool)), this, SLOT(music_synchronize(bool))); + menu->addAction(new QAction("Synchronize", this)); + menu->actions().back()->setCheckable(true); + menu->actions().back()->setChecked(music_flags & SYNC_POS); + connect(menu->actions().back(), SIGNAL(toggled(bool)), this, SLOT(music_synchronize(bool))); - menu->popup(ui_music_list->mapToGlobal(pos)); + menu->popup(ui_music_list->mapToGlobal(pos)); } void Courtroom::music_fade_out(bool toggle) { - if (toggle) - music_flags |= FADE_OUT; - else - music_flags &= ~FADE_OUT; + if (toggle) + music_flags |= FADE_OUT; + else + music_flags &= ~FADE_OUT; } void Courtroom::music_fade_in(bool toggle) { - if (toggle) - music_flags |= FADE_IN; - else - music_flags &= ~FADE_IN; + if (toggle) + music_flags |= FADE_IN; + else + music_flags &= ~FADE_IN; } void Courtroom::music_synchronize(bool toggle) { - if (toggle) - music_flags |= SYNC_POS; - else - music_flags &= ~SYNC_POS; + if (toggle) + music_flags |= SYNC_POS; + else + music_flags &= ~SYNC_POS; } void Courtroom::music_list_expand_all() { - ui_music_list->expandAll(); + ui_music_list->expandAll(); } void Courtroom::music_list_collapse_all() { - ui_music_list->collapseAll(); - QTreeWidgetItem *current = ui_music_list->selectedItems()[0]; - if (current->parent() != nullptr) - current = current->parent(); - ui_music_list->setCurrentItem(current); + ui_music_list->collapseAll(); + QTreeWidgetItem *current = ui_music_list->selectedItems()[0]; + if (current->parent() != nullptr) + current = current->parent(); + ui_music_list->setCurrentItem(current); } void Courtroom::on_area_list_double_clicked(QTreeWidgetItem *p_item, int column) { - column = 0; //The metadata - QString p_area = p_item->text(0); + column = 0; //The metadata + QString p_area = p_item->text(0); - QStringList packet_contents; - packet_contents.append(p_area); - packet_contents.append(QString::number(m_cid)); - qDebug() << packet_contents; - ao_app->send_server_packet(new AOPacket("MC", packet_contents), false); + QStringList packet_contents; + packet_contents.append(p_area); + packet_contents.append(QString::number(m_cid)); + qDebug() << packet_contents; + ao_app->send_server_packet(new AOPacket("MC", packet_contents), false); } void Courtroom::on_hold_it_clicked() { - if (objection_state == 1) - { - ui_hold_it->set_image("holdit"); - objection_state = 0; - } - else - { - ui_objection->set_image("objection"); - ui_take_that->set_image("takethat"); - ui_custom_objection->set_image("custom"); + if (objection_state == 1) { + ui_hold_it->set_image("holdit"); + objection_state = 0; + } + else { + ui_objection->set_image("objection"); + ui_take_that->set_image("takethat"); + ui_custom_objection->set_image("custom"); - ui_hold_it->set_image("holdit_selected"); - objection_state = 1; - } + ui_hold_it->set_image("holdit_selected"); + objection_state = 1; + } - ui_ic_chat_message->setFocus(); + ui_ic_chat_message->setFocus(); } void Courtroom::on_objection_clicked() { - if (objection_state == 2) - { - ui_objection->set_image("objection"); - objection_state = 0; - } - else - { - ui_hold_it->set_image("holdit"); - ui_take_that->set_image("takethat"); - ui_custom_objection->set_image("custom"); + if (objection_state == 2) { + ui_objection->set_image("objection"); + objection_state = 0; + } + else { + ui_hold_it->set_image("holdit"); + ui_take_that->set_image("takethat"); + ui_custom_objection->set_image("custom"); - ui_objection->set_image("objection_selected"); - objection_state = 2; - } + ui_objection->set_image("objection_selected"); + objection_state = 2; + } - ui_ic_chat_message->setFocus(); + ui_ic_chat_message->setFocus(); } void Courtroom::on_take_that_clicked() { - if (objection_state == 3) - { - ui_take_that->set_image("takethat"); - objection_state = 0; - } - else - { - ui_objection->set_image("objection"); - ui_hold_it->set_image("holdit"); - ui_custom_objection->set_image("custom"); + if (objection_state == 3) { + ui_take_that->set_image("takethat"); + objection_state = 0; + } + else { + ui_objection->set_image("objection"); + ui_hold_it->set_image("holdit"); + ui_custom_objection->set_image("custom"); - ui_take_that->set_image("takethat_selected"); - objection_state = 3; - } + ui_take_that->set_image("takethat_selected"); + objection_state = 3; + } - ui_ic_chat_message->setFocus(); + ui_ic_chat_message->setFocus(); } void Courtroom::on_custom_objection_clicked() { - if (objection_state == 4) - { - ui_custom_objection->set_image("custom"); - objection_state = 0; - } - else - { - ui_objection->set_image("objection"); - ui_take_that->set_image("takethat"); - ui_hold_it->set_image("holdit"); + if (objection_state == 4) { + ui_custom_objection->set_image("custom"); + objection_state = 0; + } + else { + ui_objection->set_image("objection"); + ui_take_that->set_image("takethat"); + ui_hold_it->set_image("holdit"); - ui_custom_objection->set_image("custom_selected"); - objection_state = 4; - } + ui_custom_objection->set_image("custom_selected"); + objection_state = 4; + } - ui_ic_chat_message->setFocus(); + ui_ic_chat_message->setFocus(); } void Courtroom::on_realization_clicked() { - if (realization_state == 0) - { - realization_state = 1; - if (effects_dropdown_find_and_set("realization")) - on_effects_dropdown_changed(ui_effects_dropdown->currentIndex()); + if (realization_state == 0) { + realization_state = 1; + if (effects_dropdown_find_and_set("realization")) + on_effects_dropdown_changed(ui_effects_dropdown->currentIndex()); - ui_realization->set_image("realization_pressed"); - } - else - { - realization_state = 0; - ui_effects_dropdown->setCurrentIndex(0); - on_effects_dropdown_changed(ui_effects_dropdown->currentIndex()); - ui_realization->set_image("realization"); - } + ui_realization->set_image("realization_pressed"); + } + else { + realization_state = 0; + ui_effects_dropdown->setCurrentIndex(0); + on_effects_dropdown_changed(ui_effects_dropdown->currentIndex()); + ui_realization->set_image("realization"); + } - ui_ic_chat_message->setFocus(); + ui_ic_chat_message->setFocus(); } void Courtroom::on_screenshake_clicked() { - if (screenshake_state == 0) - { - screenshake_state = 1; - ui_screenshake->set_image("screenshake_pressed"); - } - else - { - screenshake_state = 0; - ui_screenshake->set_image("screenshake"); - } + if (screenshake_state == 0) { + screenshake_state = 1; + ui_screenshake->set_image("screenshake_pressed"); + } + else { + screenshake_state = 0; + ui_screenshake->set_image("screenshake"); + } - ui_ic_chat_message->setFocus(); + ui_ic_chat_message->setFocus(); } 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_order_dropdown->hide(); - ui_pair_button->set_image("pair_button"); - ui_mute->set_image("mute_pressed"); - } - else - { - ui_mute_list->hide(); - ui_mute->set_image("mute"); - } + if (ui_mute_list->isHidden()) { + ui_mute_list->show(); + ui_pair_list->hide(); + ui_pair_offset_spinbox->hide(); + ui_pair_order_dropdown->hide(); + ui_pair_button->set_image("pair_button"); + ui_mute->set_image("mute_pressed"); + } + else { + ui_mute_list->hide(); + ui_mute->set_image("mute"); + } } void Courtroom::on_pair_clicked() { - if (ui_pair_list->isHidden()) - { - ui_pair_list->show(); - ui_pair_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_order_dropdown->hide(); - ui_pair_button->set_image("pair_button"); - } + if (ui_pair_list->isHidden()) { + ui_pair_list->show(); + ui_pair_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_order_dropdown->hide(); + ui_pair_button->set_image("pair_button"); + } } void Courtroom::on_pair_order_dropdown_changed(int p_index) { - pair_order = p_index; + pair_order = p_index; } void Courtroom::on_defense_minus_clicked() { - int f_state = defense_bar_state - 1; + int f_state = defense_bar_state - 1; - if (f_state >= 0) - ao_app->send_server_packet(new AOPacket("HP#1#" + QString::number(f_state) + "#%")); + if (f_state >= 0) + ao_app->send_server_packet(new AOPacket("HP#1#" + QString::number(f_state) + "#%")); } void Courtroom::on_defense_plus_clicked() { - int f_state = defense_bar_state + 1; + int f_state = defense_bar_state + 1; - if (f_state <= 10) - ao_app->send_server_packet(new AOPacket("HP#1#" + QString::number(f_state) + "#%")); + if (f_state <= 10) + ao_app->send_server_packet(new AOPacket("HP#1#" + QString::number(f_state) + "#%")); } void Courtroom::on_prosecution_minus_clicked() { - int f_state = prosecution_bar_state - 1; + int f_state = prosecution_bar_state - 1; - if (f_state >= 0) - ao_app->send_server_packet(new AOPacket("HP#2#" + QString::number(f_state) + "#%")); + if (f_state >= 0) + ao_app->send_server_packet(new AOPacket("HP#2#" + QString::number(f_state) + "#%")); } void Courtroom::on_prosecution_plus_clicked() { - int f_state = prosecution_bar_state + 1; + int f_state = prosecution_bar_state + 1; - if (f_state <= 10) - ao_app->send_server_packet(new AOPacket("HP#2#" + QString::number(f_state) + "#%")); + if (f_state <= 10) + ao_app->send_server_packet(new AOPacket("HP#2#" + QString::number(f_state) + "#%")); } void Courtroom::set_text_color_dropdown() { - //Clear the lists - ui_text_color->clear(); - color_row_to_number.clear(); + //Clear the lists + ui_text_color->clear(); + color_row_to_number.clear(); - //Clear the stored optimization information - color_rgb_list.clear(); - color_markdown_start_list.clear(); - color_markdown_end_list.clear(); - color_markdown_remove_list.clear(); - color_markdown_talking_list.clear(); + //Clear the stored optimization information + color_rgb_list.clear(); + color_markdown_start_list.clear(); + color_markdown_end_list.clear(); + color_markdown_remove_list.clear(); + color_markdown_talking_list.clear(); - //Update markdown colors. TODO: make a loading function that only loads the config file once instead of several times - for (int c = 0; c < max_colors; ++c) - { - QColor color = ao_app->get_chat_color(QString::number(c), current_char); - color_rgb_list.append(color); - color_markdown_start_list.append(ao_app->get_chat_markdown("c" + QString::number(c) + "_start", current_char)); - color_markdown_end_list.append(ao_app->get_chat_markdown("c" + QString::number(c) + "_end", current_char)); - color_markdown_remove_list.append(ao_app->get_chat_markdown("c" + QString::number(c) + "_remove", current_char) == "1"); - color_markdown_talking_list.append(ao_app->get_chat_markdown("c" + QString::number(c) + "_talking", current_char) == "1"); + //Update markdown colors. TODO: make a loading function that only loads the config file once instead of several times + for (int c = 0; c < max_colors; ++c) { + QColor color = ao_app->get_chat_color(QString::number(c), current_char); + color_rgb_list.append(color); + color_markdown_start_list.append(ao_app->get_chat_markdown("c" + QString::number(c) + "_start", current_char)); + color_markdown_end_list.append(ao_app->get_chat_markdown("c" + QString::number(c) + "_end", current_char)); + color_markdown_remove_list.append(ao_app->get_chat_markdown("c" + QString::number(c) + "_remove", current_char) == "1"); + color_markdown_talking_list.append(ao_app->get_chat_markdown("c" + QString::number(c) + "_talking", current_char) == "1"); - QString color_name = ao_app->get_chat_markdown("c" + QString::number(c) + "_name", current_char); - if (color_name.isEmpty()) //Not defined - { - if (c > 0) - continue; - color_name = tr("Default"); + QString color_name = ao_app->get_chat_markdown("c" + QString::number(c) + "_name", current_char); + if (color_name.isEmpty()) //Not defined + { + if (c > 0) + continue; + color_name = tr("Default"); + } + ui_text_color->addItem(color_name); + QPixmap pixmap(16, 16); + pixmap.fill(color); + ui_text_color->setItemIcon(ui_text_color->count() - 1, QIcon(pixmap)); + color_row_to_number.append(c); } - ui_text_color->addItem(color_name); - QPixmap pixmap(16,16); - pixmap.fill(color); - ui_text_color->setItemIcon(ui_text_color->count() - 1, QIcon(pixmap)); - color_row_to_number.append(c); - } } void Courtroom::on_text_color_changed(int p_color) { - if (ui_ic_chat_message->selectionStart() != -1) //We have a selection! - { - int c = color_row_to_number.at(p_color); - QString markdown_start = color_markdown_start_list.at(c); - if (markdown_start.isEmpty()) + if (ui_ic_chat_message->selectionStart() != -1) //We have a selection! { - qDebug() << "W: Color list dropdown selected a non-existent markdown start character"; - return; + int c = color_row_to_number.at(p_color); + QString markdown_start = color_markdown_start_list.at(c); + if (markdown_start.isEmpty()) { + qDebug() << "W: Color list dropdown selected a non-existent markdown start character"; + return; + } + QString markdown_end = color_markdown_end_list.at(c); + if (markdown_end.isEmpty()) + markdown_end = markdown_start; + int start = ui_ic_chat_message->selectionStart(); + int end = ui_ic_chat_message->selectionEnd() + 1; + ui_ic_chat_message->setCursorPosition(start); + ui_ic_chat_message->insert(markdown_start); + ui_ic_chat_message->setCursorPosition(end); + ui_ic_chat_message->insert(markdown_end); + // ui_ic_chat_message->end(false); + ui_text_color->setCurrentIndex(0); } - QString markdown_end = color_markdown_end_list.at(c); - if (markdown_end.isEmpty()) - markdown_end = markdown_start; - int start = ui_ic_chat_message->selectionStart(); - int end = ui_ic_chat_message->selectionEnd()+1; - ui_ic_chat_message->setCursorPosition(start); - ui_ic_chat_message->insert(markdown_start); - ui_ic_chat_message->setCursorPosition(end); - ui_ic_chat_message->insert(markdown_end); -// ui_ic_chat_message->end(false); - ui_text_color->setCurrentIndex(0); - } - else - { - if (p_color != -1 && p_color < color_row_to_number.size()) - text_color = color_row_to_number.at(p_color); - else - text_color = 0; - } - ui_ic_chat_message->setFocus(); + else { + if (p_color != -1 && p_color < color_row_to_number.size()) + text_color = color_row_to_number.at(p_color); + else + text_color = 0; + } + ui_ic_chat_message->setFocus(); } void Courtroom::on_music_slider_moved(int p_value) { - music_player->set_volume(p_value, 0); //Set volume on music layer - ui_ic_chat_message->setFocus(); + music_player->set_volume(p_value, 0); //Set volume on music layer + ui_ic_chat_message->setFocus(); } void Courtroom::on_sfx_slider_moved(int p_value) { - sfx_player->set_volume(p_value); - //Set the ambience and other misc. music layers - for (int i = 1; i < music_player->m_channelmax; ++i) - { - music_player->set_volume(p_value, i); - } - objection_player->set_volume(p_value); - ui_ic_chat_message->setFocus(); + sfx_player->set_volume(p_value); + //Set the ambience and other misc. music layers + for (int i = 1; i < music_player->m_channelmax; ++i) { + music_player->set_volume(p_value, i); + } + objection_player->set_volume(p_value); + ui_ic_chat_message->setFocus(); } void Courtroom::on_blip_slider_moved(int p_value) { - blip_player->set_volume(p_value); - ui_ic_chat_message->setFocus(); + blip_player->set_volume(p_value); + ui_ic_chat_message->setFocus(); } void Courtroom::on_log_limit_changed(int value) { - log_maximum_blocks = value; + log_maximum_blocks = value; } void Courtroom::on_pair_offset_changed(int value) { - char_offset = value; + char_offset = value; } void Courtroom::on_witness_testimony_clicked() { - if (is_muted) - return; + if (is_muted) + return; - ao_app->send_server_packet(new AOPacket("RT#testimony1#%")); + ao_app->send_server_packet(new AOPacket("RT#testimony1#%")); - ui_ic_chat_message->setFocus(); + ui_ic_chat_message->setFocus(); } void Courtroom::on_cross_examination_clicked() { - if (is_muted) - return; + if (is_muted) + return; - ao_app->send_server_packet(new AOPacket("RT#testimony2#%")); + ao_app->send_server_packet(new AOPacket("RT#testimony2#%")); - ui_ic_chat_message->setFocus(); + ui_ic_chat_message->setFocus(); } void Courtroom::on_not_guilty_clicked() { - if (is_muted) - return; + if (is_muted) + return; - ao_app->send_server_packet(new AOPacket("RT#judgeruling#0#%")); + ao_app->send_server_packet(new AOPacket("RT#judgeruling#0#%")); - ui_ic_chat_message->setFocus(); + ui_ic_chat_message->setFocus(); } void Courtroom::on_guilty_clicked() { - if (is_muted) - return; + if (is_muted) + return; - ao_app->send_server_packet(new AOPacket("RT#judgeruling#1#%")); + ao_app->send_server_packet(new AOPacket("RT#judgeruling#1#%")); - ui_ic_chat_message->setFocus(); + ui_ic_chat_message->setFocus(); } void Courtroom::on_change_character_clicked() { - sfx_player->set_volume(0); - blip_player->set_volume(0); + sfx_player->set_volume(0); + blip_player->set_volume(0); - set_char_select(); + set_char_select(); - ui_char_select_background->show(); - ui_spectator->hide(); + ui_char_select_background->show(); + ui_spectator->hide(); } void Courtroom::on_reload_theme_clicked() { - ao_app->reload_theme(); + ao_app->reload_theme(); - enter_courtroom(); - update_character(m_cid); + enter_courtroom(); + update_character(m_cid); - anim_state = 4; - text_state = 3; + anim_state = 4; + text_state = 3; - //to update status on the background - set_background(current_background); + //to update status on the background + set_background(current_background); } void Courtroom::on_back_to_lobby_clicked() { - ao_app->construct_lobby(); - ao_app->destruct_courtroom(); + ao_app->construct_lobby(); + ao_app->destruct_courtroom(); } void Courtroom::on_char_select_left_clicked() { - --current_char_page; - set_char_select_page(); + --current_char_page; + set_char_select_page(); } void Courtroom::on_char_select_right_clicked() { - ++current_char_page; - set_char_select_page(); + ++current_char_page; + set_char_select_page(); } void Courtroom::on_spectator_clicked() { - update_character(-1); + update_character(-1); } void Courtroom::on_call_mod_clicked() { - if (ao_app->modcall_reason_enabled) { - QMessageBox errorBox; - QInputDialog input; + if (ao_app->modcall_reason_enabled) { + QMessageBox errorBox; + QInputDialog input; - input.setWindowFlags(Qt::WindowSystemMenuHint); - input.setLabelText(tr("Reason:")); - input.setWindowTitle(tr("Call Moderator")); - auto code = input.exec(); + input.setWindowFlags(Qt::WindowSystemMenuHint); + input.setLabelText(tr("Reason:")); + input.setWindowTitle(tr("Call Moderator")); + auto code = input.exec(); - if (code != QDialog::Accepted) - return; + if (code != QDialog::Accepted) + return; - 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; + 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); + + ao_app->send_server_packet(new AOPacket("ZZ", mod_reason)); + } + 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)); - } else { - ao_app->send_server_packet(new AOPacket("ZZ#%")); - } - - ui_ic_chat_message->setFocus(); + ui_ic_chat_message->setFocus(); } void Courtroom::on_settings_clicked() @@ -4381,79 +4079,72 @@ void Courtroom::on_announce_casing_clicked() void Courtroom::on_pre_clicked() { - ui_ic_chat_message->setFocus(); + ui_ic_chat_message->setFocus(); } void Courtroom::on_flip_clicked() { - ui_ic_chat_message->setFocus(); + ui_ic_chat_message->setFocus(); } void Courtroom::on_additive_clicked() { - if (ui_additive->isChecked()) - { - ui_ic_chat_message->home(false); //move cursor to the start of the message - ui_ic_chat_message->insert(" "); //preface the message by whitespace - ui_ic_chat_message->end(false); //move cursor to the end of the message without selecting anything - } - ui_ic_chat_message->setFocus(); + if (ui_additive->isChecked()) { + ui_ic_chat_message->home(false); //move cursor to the start of the message + ui_ic_chat_message->insert(" "); //preface the message by whitespace + ui_ic_chat_message->end(false); //move cursor to the end of the message without selecting anything + } + ui_ic_chat_message->setFocus(); } void Courtroom::on_guard_clicked() { - ui_ic_chat_message->setFocus(); + ui_ic_chat_message->setFocus(); } void Courtroom::on_showname_enable_clicked() { - ui_ic_chatlog->clear(); - first_message_sent = false; + ui_ic_chatlog->clear(); + first_message_sent = false; - foreach (chatlogpiece item, ic_chatlog_history) { - if (ui_showname_enable->isChecked()) - { - if (item.is_song()) - append_ic_text(item.get_message(), item.get_showname(), "has played a song"); - else - append_ic_text(item.get_message(), item.get_showname()); - } - else - { - if (item.is_song()) - append_ic_text(item.get_message(), item.get_name(), "has played a song"); - else - append_ic_text(item.get_message(), item.get_name()); - } + foreach (chatlogpiece item, ic_chatlog_history) { + if (ui_showname_enable->isChecked()) { + if (item.is_song()) + append_ic_text(item.get_message(), item.get_showname(), "has played a song"); + else + append_ic_text(item.get_message(), item.get_showname()); + } + else { + if (item.is_song()) + append_ic_text(item.get_message(), item.get_name(), "has played a song"); + else + append_ic_text(item.get_message(), item.get_name()); + } } - ui_ic_chat_message->setFocus(); + ui_ic_chat_message->setFocus(); } void Courtroom::on_evidence_button_clicked() { - if (ui_evidence->isHidden()) - { - ui_evidence->show(); - ui_evidence_overlay->hide(); - } - else - { - ui_evidence->hide(); - } + if (ui_evidence->isHidden()) { + ui_evidence->show(); + ui_evidence_overlay->hide(); + } + else { + ui_evidence->hide(); + } } void Courtroom::on_switch_area_music_clicked() { ui_music_search->setText(""); on_music_search_edited(ui_music_search->text()); - if (ui_area_list->isHidden()) - { + if (ui_area_list->isHidden()) { ui_area_list->show(); ui_music_list->hide(); } - else - { + else { ui_area_list->hide(); ui_music_list->show(); } @@ -4461,80 +4152,76 @@ void Courtroom::on_switch_area_music_clicked() void Courtroom::ping_server() { - ao_app->send_server_packet(new AOPacket("CH#" + QString::number(m_cid) + "#%")); + ao_app->send_server_packet(new AOPacket("CH#" + QString::number(m_cid) + "#%")); } void Courtroom::on_casing_clicked() { - if (ao_app->casing_alerts_enabled) - { - if (ui_casing->isChecked()) - { - QStringList f_packet; + if (ao_app->casing_alerts_enabled) { + if (ui_casing->isChecked()) { + QStringList f_packet; - f_packet.append(ao_app->get_casing_can_host_cases()); - f_packet.append(QString::number(ao_app->get_casing_cm_enabled())); - f_packet.append(QString::number(ao_app->get_casing_defence_enabled())); - f_packet.append(QString::number(ao_app->get_casing_prosecution_enabled())); - f_packet.append(QString::number(ao_app->get_casing_judge_enabled())); - f_packet.append(QString::number(ao_app->get_casing_juror_enabled())); - f_packet.append(QString::number(ao_app->get_casing_steno_enabled())); + f_packet.append(ao_app->get_casing_can_host_cases()); + f_packet.append(QString::number(ao_app->get_casing_cm_enabled())); + f_packet.append(QString::number(ao_app->get_casing_defence_enabled())); + f_packet.append(QString::number(ao_app->get_casing_prosecution_enabled())); + f_packet.append(QString::number(ao_app->get_casing_judge_enabled())); + f_packet.append(QString::number(ao_app->get_casing_juror_enabled())); + f_packet.append(QString::number(ao_app->get_casing_steno_enabled())); - ao_app->send_server_packet(new AOPacket("SETCASE", f_packet)); + ao_app->send_server_packet(new AOPacket("SETCASE", f_packet)); + } + else + ao_app->send_server_packet(new AOPacket("SETCASE#\"\"#0#0#0#0#0#0#%")); } - else - ao_app->send_server_packet(new AOPacket("SETCASE#\"\"#0#0#0#0#0#0#%")); - } } void Courtroom::announce_case(QString title, bool def, bool pro, bool jud, bool jur, bool steno) { - if (ao_app->casing_alerts_enabled) - { - QStringList f_packet; + if (ao_app->casing_alerts_enabled) { + QStringList f_packet; - f_packet.append(title); - f_packet.append(QString::number(def)); - f_packet.append(QString::number(pro)); - f_packet.append(QString::number(jud)); - f_packet.append(QString::number(jur)); - f_packet.append(QString::number(steno)); + f_packet.append(title); + f_packet.append(QString::number(def)); + f_packet.append(QString::number(pro)); + f_packet.append(QString::number(jud)); + f_packet.append(QString::number(jur)); + f_packet.append(QString::number(steno)); - ao_app->send_server_packet(new AOPacket("CASEA", f_packet)); + ao_app->send_server_packet(new AOPacket("CASEA", f_packet)); } } Courtroom::~Courtroom() { - delete music_player; - delete sfx_player; - delete objection_player; - delete blip_player; + delete music_player; + delete sfx_player; + delete objection_player; + delete blip_player; } - -#if (defined (_WIN32) || defined (_WIN64)) +#if (defined(_WIN32) || defined(_WIN64)) void Courtroom::load_bass_opus_plugin() { - #ifdef BASSAUDIO - BASS_PluginLoad("bassopus.dll", 0); - #endif +#ifdef BASSAUDIO + BASS_PluginLoad("bassopus.dll", 0); +#endif } -#elif (defined (LINUX) || defined (__linux__)) +#elif (defined(LINUX) || defined(__linux__)) void Courtroom::load_bass_opus_plugin() { - #ifdef BASSAUDIO - BASS_PluginLoad("libbassopus.so", 0); - #endif +#ifdef BASSAUDIO + BASS_PluginLoad("libbassopus.so", 0); +#endif } #elif defined __APPLE__ void Courtroom::load_bass_opus_plugin() { - QString libpath = ao_app->get_base_path() + "../../Frameworks/libbassopus.dylib"; - QByteArray ba = libpath.toLocal8Bit(); - #ifdef BASSAUDIO - BASS_PluginLoad(ba.data(), 0); - #endif + QString libpath = ao_app->get_base_path() + "../../Frameworks/libbassopus.dylib"; + QByteArray ba = libpath.toLocal8Bit(); +#ifdef BASSAUDIO + BASS_PluginLoad(ba.data(), 0); +#endif } #else #error This operating system is unsupported for bass plugins. diff --git a/src/debug_functions.cpp b/src/debug_functions.cpp index a790610..ba189ec 100644 --- a/src/debug_functions.cpp +++ b/src/debug_functions.cpp @@ -1,28 +1,26 @@ -#include #include +#include #include "debug_functions.h" void call_error(QString p_message) { - QMessageBox *msgBox = new QMessageBox; + QMessageBox *msgBox = new QMessageBox; - msgBox->setText(QCoreApplication::translate("debug_functions", "Error: %1").arg(p_message)); - msgBox->setWindowTitle(QCoreApplication::translate("debug_functions", "Error")); + msgBox->setText(QCoreApplication::translate("debug_functions", "Error: %1").arg(p_message)); + msgBox->setWindowTitle(QCoreApplication::translate("debug_functions", "Error")); - - //msgBox->setWindowModality(Qt::NonModal); - msgBox->exec(); + //msgBox->setWindowModality(Qt::NonModal); + msgBox->exec(); } void call_notice(QString p_message) { - QMessageBox *msgBox = new QMessageBox; + QMessageBox *msgBox = new QMessageBox; - msgBox->setText(p_message); - msgBox->setWindowTitle(QCoreApplication::translate("debug_functions", "Notice")); + msgBox->setText(p_message); + msgBox->setWindowTitle(QCoreApplication::translate("debug_functions", "Notice")); - - //msgBox->setWindowModality(Qt::NonModal); - msgBox->exec(); + //msgBox->setWindowModality(Qt::NonModal); + msgBox->exec(); } diff --git a/src/discord_rich_presence.cpp b/src/discord_rich_presence.cpp index 95a824a..05a9494 100644 --- a/src/discord_rich_presence.cpp +++ b/src/discord_rich_presence.cpp @@ -3,133 +3,129 @@ namespace AttorneyOnline { #ifdef DISCORD -Discord::Discord() -{ - DiscordEventHandlers handlers; - std::memset(&handlers, 0, sizeof(handlers)); - handlers = {}; - handlers.ready = [] { - qInfo() << "Discord RPC ready"; - }; - handlers.disconnected = [](int errorCode, const char* message) { - qInfo() << "Discord RPC disconnected! " << message << errorCode; - }; - handlers.errored = [](int errorCode, const char* message) { - qWarning() << "Discord RPC errored out! " << message << errorCode; - }; - qInfo() << "Initializing Discord RPC"; - Discord_Initialize(APPLICATION_ID, &handlers, 1, nullptr); -} + Discord::Discord() + { + DiscordEventHandlers handlers; + std::memset(&handlers, 0, sizeof(handlers)); + handlers = {}; + handlers.ready = [] { + qInfo() << "Discord RPC ready"; + }; + handlers.disconnected = [](int errorCode, const char *message) { + qInfo() << "Discord RPC disconnected! " << message << errorCode; + }; + handlers.errored = [](int errorCode, const char *message) { + qWarning() << "Discord RPC errored out! " << message << errorCode; + }; + qInfo() << "Initializing Discord RPC"; + Discord_Initialize(APPLICATION_ID, &handlers, 1, nullptr); + } -Discord::~Discord() -{ - Discord_Shutdown(); -} + Discord::~Discord() + { + Discord_Shutdown(); + } -void Discord::state_lobby() -{ - DiscordRichPresence presence; - std::memset(&presence, 0, sizeof(presence)); - presence.largeImageKey = "ao2-logo"; - presence.largeImageText = "Objection!"; - presence.instance = 1; + void Discord::state_lobby() + { + DiscordRichPresence presence; + std::memset(&presence, 0, sizeof(presence)); + presence.largeImageKey = "ao2-logo"; + presence.largeImageText = "Objection!"; + presence.instance = 1; - presence.state = "In Lobby"; - presence.details = "Idle"; - Discord_UpdatePresence(&presence); -} + presence.state = "In Lobby"; + presence.details = "Idle"; + Discord_UpdatePresence(&presence); + } -void Discord::state_server(std::string name, std::string server_id) -{ - qDebug() << "Discord RPC: Setting server state"; + void Discord::state_server(std::string name, std::string server_id) + { + qDebug() << "Discord RPC: Setting server state"; - DiscordRichPresence presence; - std::memset(&presence, 0, sizeof(presence)); - presence.largeImageKey = "ao2-logo"; - presence.largeImageText = "Objection!"; - presence.instance = 1; + DiscordRichPresence presence; + std::memset(&presence, 0, sizeof(presence)); + presence.largeImageKey = "ao2-logo"; + presence.largeImageText = "Objection!"; + presence.instance = 1; - auto timestamp = static_cast(std::time(nullptr)); + auto timestamp = static_cast(std::time(nullptr)); - presence.state = "In a Server"; - presence.details = name.c_str(); - presence.matchSecret = server_id.c_str(); - presence.startTimestamp = this->timestamp; + presence.state = "In a Server"; + presence.details = name.c_str(); + presence.matchSecret = server_id.c_str(); + presence.startTimestamp = this->timestamp; - this->server_id = server_id; - this->server_name = name; - this->timestamp = timestamp; - Discord_UpdatePresence(&presence); -} + this->server_id = server_id; + this->server_name = name; + this->timestamp = timestamp; + Discord_UpdatePresence(&presence); + } -void Discord::state_character(std::string name) -{ - auto name_internal = QString(name.c_str()).toLower().replace(' ', '_').toStdString(); - auto name_friendly = QString(name.c_str()).replace('_', ' ').toStdString(); - const std::string playing_as = "Playing as " + name_friendly; - qDebug() << "Discord RPC: Setting character state (" << playing_as.c_str() << ")"; + void Discord::state_character(std::string name) + { + auto name_internal = QString(name.c_str()).toLower().replace(' ', '_').toStdString(); + auto name_friendly = QString(name.c_str()).replace('_', ' ').toStdString(); + const std::string playing_as = "Playing as " + name_friendly; + qDebug() << "Discord RPC: Setting character state (" << playing_as.c_str() << ")"; - DiscordRichPresence presence; - std::memset(&presence, 0, sizeof(presence)); - presence.largeImageKey = "ao2-logo"; - presence.largeImageText = "Objection!"; - presence.instance = 1; - presence.details = this->server_name.c_str(); - presence.matchSecret = this->server_id.c_str(); - presence.startTimestamp = this->timestamp; + DiscordRichPresence presence; + std::memset(&presence, 0, sizeof(presence)); + presence.largeImageKey = "ao2-logo"; + presence.largeImageText = "Objection!"; + presence.instance = 1; + presence.details = this->server_name.c_str(); + presence.matchSecret = this->server_id.c_str(); + presence.startTimestamp = this->timestamp; - presence.state = playing_as.c_str(); - presence.smallImageKey = name_internal.c_str(); - // presence.smallImageText = name_internal.c_str(); - Discord_UpdatePresence(&presence); -} + presence.state = playing_as.c_str(); + presence.smallImageKey = name_internal.c_str(); + // presence.smallImageText = name_internal.c_str(); + Discord_UpdatePresence(&presence); + } -void Discord::state_spectate() -{ - qDebug() << "Discord RPC: Setting specator state"; + void Discord::state_spectate() + { + qDebug() << "Discord RPC: Setting specator state"; - DiscordRichPresence presence; - std::memset(&presence, 0, sizeof(presence)); - presence.largeImageKey = "ao2-logo"; - presence.largeImageText = "Objection!"; - presence.instance = 1; - presence.details = this->server_name.c_str(); - presence.matchSecret = this->server_id.c_str(); - presence.startTimestamp = this->timestamp; + DiscordRichPresence presence; + std::memset(&presence, 0, sizeof(presence)); + presence.largeImageKey = "ao2-logo"; + presence.largeImageText = "Objection!"; + presence.instance = 1; + presence.details = this->server_name.c_str(); + presence.matchSecret = this->server_id.c_str(); + presence.startTimestamp = this->timestamp; - presence.state = "Spectating"; - Discord_UpdatePresence(&presence); -} + presence.state = "Spectating"; + Discord_UpdatePresence(&presence); + } #else -Discord::Discord() -{ + Discord::Discord() + { + } -} + Discord::~Discord() + { + } -Discord::~Discord() -{ + void Discord::state_lobby() + { + } -} + void Discord::state_server(std::string name, std::string server_id) + { + qDebug() << "Discord RPC: Setting server state"; + } -void Discord::state_lobby() -{ + void Discord::state_character(std::string name) + { + qDebug() << "Discord RPC: Setting character state"; + } -} - -void Discord::state_server(std::string name, std::string server_id) -{ - qDebug() << "Discord RPC: Setting server state"; -} - -void Discord::state_character(std::string name) -{ - qDebug() << "Discord RPC: Setting character state"; -} - -void Discord::state_spectate() -{ - qDebug() << "Discord RPC: Setting specator state"; - -} + void Discord::state_spectate() + { + qDebug() << "Discord RPC: Setting specator state"; + } #endif -} +} // namespace AttorneyOnline diff --git a/src/emotes.cpp b/src/emotes.cpp index 1484784..5995297 100644 --- a/src/emotes.cpp +++ b/src/emotes.cpp @@ -4,199 +4,189 @@ void Courtroom::initialize_emotes() { - ui_emotes = new QWidget(this); + ui_emotes = new QWidget(this); - ui_emote_left = new AOButton(this, ao_app); - ui_emote_right = new AOButton(this, ao_app); + ui_emote_left = new AOButton(this, ao_app); + ui_emote_right = new AOButton(this, ao_app); - ui_emote_dropdown = new QComboBox(this); + ui_emote_dropdown = new QComboBox(this); - connect(ui_emote_left, SIGNAL(clicked()), this, SLOT(on_emote_left_clicked())); - connect(ui_emote_right, SIGNAL(clicked()), this, SLOT(on_emote_right_clicked())); + connect(ui_emote_left, SIGNAL(clicked()), this, SLOT(on_emote_left_clicked())); + connect(ui_emote_right, SIGNAL(clicked()), this, SLOT(on_emote_right_clicked())); - connect(ui_emote_dropdown, SIGNAL(activated(int)), this, SLOT(on_emote_dropdown_changed(int))); + connect(ui_emote_dropdown, SIGNAL(activated(int)), this, SLOT(on_emote_dropdown_changed(int))); } void Courtroom::refresh_emotes() { - //Should properly refresh the emote list - qDeleteAll(ui_emote_list.begin(), ui_emote_list.end()); - ui_emote_list.clear(); + //Should properly refresh the emote list + qDeleteAll(ui_emote_list.begin(), ui_emote_list.end()); + ui_emote_list.clear(); - set_size_and_pos(ui_emotes, "emotes"); + set_size_and_pos(ui_emotes, "emotes"); - set_size_and_pos(ui_emote_left, "emote_left"); - ui_emote_left->set_image("arrow_left"); + set_size_and_pos(ui_emote_left, "emote_left"); + ui_emote_left->set_image("arrow_left"); - set_size_and_pos(ui_emote_right, "emote_right"); - ui_emote_right->set_image("arrow_right"); + set_size_and_pos(ui_emote_right, "emote_right"); + ui_emote_right->set_image("arrow_right"); - QPoint f_spacing = ao_app->get_button_spacing("emote_button_spacing", "courtroom_design.ini"); - QPoint p_point = ao_app->get_button_spacing("emote_button_size", "courtroom_design.ini"); + QPoint f_spacing = ao_app->get_button_spacing("emote_button_spacing", "courtroom_design.ini"); + QPoint p_point = ao_app->get_button_spacing("emote_button_size", "courtroom_design.ini"); - const int button_width = p_point.x(); - int x_spacing = f_spacing.x(); - int x_mod_count = 0; + const int button_width = p_point.x(); + int x_spacing = f_spacing.x(); + int x_mod_count = 0; - const int button_height = p_point.y(); - int y_spacing = f_spacing.y(); - int y_mod_count = 0; + const int button_height = p_point.y(); + int y_spacing = f_spacing.y(); + int y_mod_count = 0; - emote_columns = ((ui_emotes->width() - button_width) / (x_spacing + button_width)) + 1; - emote_rows = ((ui_emotes->height() - button_height) / (y_spacing + button_height)) + 1; + emote_columns = ((ui_emotes->width() - button_width) / (x_spacing + button_width)) + 1; + emote_rows = ((ui_emotes->height() - button_height) / (y_spacing + button_height)) + 1; - max_emotes_on_page = emote_columns * emote_rows; + max_emotes_on_page = emote_columns * emote_rows; - for (int n = 0 ; n < max_emotes_on_page ; ++n) - { - int x_pos = (button_width + x_spacing) * x_mod_count; - int y_pos = (button_height + y_spacing) * y_mod_count; + for (int n = 0; n < max_emotes_on_page; ++n) { + int x_pos = (button_width + x_spacing) * x_mod_count; + int y_pos = (button_height + y_spacing) * y_mod_count; - AOEmoteButton *f_emote = new AOEmoteButton(ui_emotes, ao_app, x_pos, y_pos, button_width, button_height); + AOEmoteButton *f_emote = new AOEmoteButton(ui_emotes, ao_app, x_pos, y_pos, button_width, button_height); - ui_emote_list.append(f_emote); + ui_emote_list.append(f_emote); - f_emote->set_id(n); + f_emote->set_id(n); - connect(f_emote, SIGNAL(emote_clicked(int)), this, SLOT(on_emote_clicked(int))); + connect(f_emote, SIGNAL(emote_clicked(int)), this, SLOT(on_emote_clicked(int))); - ++x_mod_count; + ++x_mod_count; - if (x_mod_count == emote_columns) - { - ++y_mod_count; - x_mod_count = 0; + if (x_mod_count == emote_columns) { + ++y_mod_count; + x_mod_count = 0; + } } - } } void Courtroom::set_emote_page() { - if (m_cid == -1) - return; + if (m_cid == -1) + return; - int total_emotes = ao_app->get_emote_number(current_char); + int total_emotes = ao_app->get_emote_number(current_char); - ui_emote_left->hide(); - ui_emote_right->hide(); + ui_emote_left->hide(); + ui_emote_right->hide(); - for (AOEmoteButton *i_button : ui_emote_list) - { - i_button->hide(); - } + for (AOEmoteButton *i_button : ui_emote_list) { + i_button->hide(); + } - int total_pages = total_emotes / max_emotes_on_page; - int emotes_on_page = 0; + int total_pages = total_emotes / max_emotes_on_page; + int emotes_on_page = 0; + + if (total_emotes % max_emotes_on_page != 0) { + ++total_pages; + //i. e. not on the last page + if (total_pages > current_emote_page + 1) + emotes_on_page = max_emotes_on_page; + else + emotes_on_page = total_emotes % max_emotes_on_page; + } + else + emotes_on_page = max_emotes_on_page; - if (total_emotes % max_emotes_on_page != 0) - { - ++total_pages; - //i. e. not on the last page if (total_pages > current_emote_page + 1) - emotes_on_page = max_emotes_on_page; - else - emotes_on_page = total_emotes % max_emotes_on_page; + ui_emote_right->show(); - } - else - emotes_on_page = max_emotes_on_page; + if (current_emote_page > 0) + ui_emote_left->show(); - if (total_pages > current_emote_page + 1) - ui_emote_right->show(); + for (int n_emote = 0; n_emote < emotes_on_page && n_emote < ui_emote_list.size(); ++n_emote) { + int n_real_emote = n_emote + current_emote_page * max_emotes_on_page; + AOEmoteButton *f_emote = ui_emote_list.at(n_emote); - if (current_emote_page > 0) - ui_emote_left->show(); - - for (int n_emote = 0 ; n_emote < emotes_on_page && n_emote < ui_emote_list.size(); ++n_emote) - { - int n_real_emote = n_emote + current_emote_page * max_emotes_on_page; - AOEmoteButton *f_emote = ui_emote_list.at(n_emote); - - if (n_real_emote == current_emote) - f_emote->set_char_image(current_char, n_real_emote, "_on"); - else - f_emote->set_char_image(current_char, n_real_emote, "_off"); - - f_emote->show(); - f_emote->setToolTip(QString::number(n_real_emote+1) + ": " + ao_app->get_emote_comment(current_char, n_real_emote)); - } + if (n_real_emote == current_emote) + f_emote->set_char_image(current_char, n_real_emote, "_on"); + else + f_emote->set_char_image(current_char, n_real_emote, "_off"); + f_emote->show(); + f_emote->setToolTip(QString::number(n_real_emote + 1) + ": " + ao_app->get_emote_comment(current_char, n_real_emote)); + } } void Courtroom::set_emote_dropdown() { - ui_emote_dropdown->clear(); + ui_emote_dropdown->clear(); - int total_emotes = ao_app->get_emote_number(current_char); - QStringList emote_list; + int total_emotes = ao_app->get_emote_number(current_char); + QStringList emote_list; - for (int n = 0 ; n < total_emotes ; ++n) - { - emote_list.append(QString::number(n+1) + ": " + ao_app->get_emote_comment(current_char, n)); - } + for (int n = 0; n < total_emotes; ++n) { + emote_list.append(QString::number(n + 1) + ": " + ao_app->get_emote_comment(current_char, n)); + } - ui_emote_dropdown->addItems(emote_list); + ui_emote_dropdown->addItems(emote_list); } void Courtroom::select_emote(int p_id) { - int min = current_emote_page * max_emotes_on_page; - int max = (max_emotes_on_page - 1) + current_emote_page * max_emotes_on_page; + int min = current_emote_page * max_emotes_on_page; + int max = (max_emotes_on_page - 1) + current_emote_page * max_emotes_on_page; - if (current_emote >= min && current_emote <= max) - ui_emote_list.at(current_emote % max_emotes_on_page)->set_char_image(current_char, current_emote, "_off"); + if (current_emote >= min && current_emote <= max) + ui_emote_list.at(current_emote % max_emotes_on_page)->set_char_image(current_char, current_emote, "_off"); - int old_emote = current_emote; + int old_emote = current_emote; - current_emote = p_id; + current_emote = p_id; - if (current_emote >= min && current_emote <= max) - ui_emote_list.at(current_emote % max_emotes_on_page)->set_char_image(current_char, current_emote, "_on"); + if (current_emote >= min && current_emote <= max) + ui_emote_list.at(current_emote % max_emotes_on_page)->set_char_image(current_char, current_emote, "_on"); - int emote_mod = ao_app->get_emote_mod(current_char, current_emote); + int emote_mod = ao_app->get_emote_mod(current_char, current_emote); - if (old_emote == current_emote) - { - ui_pre->setChecked(!ui_pre->isChecked()); - } - else if (!ao_app->is_stickypres_enabled()) - { - if (emote_mod == 1 || emote_mod == 4) - ui_pre->setChecked(true); - else - ui_pre->setChecked(false); - } + if (old_emote == current_emote) { + ui_pre->setChecked(!ui_pre->isChecked()); + } + else if (!ao_app->is_stickypres_enabled()) { + if (emote_mod == 1 || emote_mod == 4) + ui_pre->setChecked(true); + else + ui_pre->setChecked(false); + } - ui_emote_dropdown->setCurrentIndex(current_emote); + ui_emote_dropdown->setCurrentIndex(current_emote); - ui_ic_chat_message->setFocus(); + ui_ic_chat_message->setFocus(); } void Courtroom::on_emote_clicked(int p_id) { - select_emote(p_id + max_emotes_on_page * current_emote_page); + select_emote(p_id + max_emotes_on_page * current_emote_page); } void Courtroom::on_emote_left_clicked() { - --current_emote_page; + --current_emote_page; - set_emote_page(); + set_emote_page(); - ui_ic_chat_message->setFocus(); + ui_ic_chat_message->setFocus(); } void Courtroom::on_emote_right_clicked() { - qDebug() << "emote right clicked"; - ++current_emote_page; + qDebug() << "emote right clicked"; + ++current_emote_page; - set_emote_page(); + set_emote_page(); - ui_ic_chat_message->setFocus(); + ui_ic_chat_message->setFocus(); } void Courtroom::on_emote_dropdown_changed(int p_index) { - select_emote(p_index); + select_emote(p_index); } diff --git a/src/encryption_functions.cpp b/src/encryption_functions.cpp index ffbe0cd..f26d4d4 100644 --- a/src/encryption_functions.cpp +++ b/src/encryption_functions.cpp @@ -4,60 +4,55 @@ QString fanta_encrypt(QString temp_input, unsigned int p_key) { - //using standard stdlib types is actually easier here because of implicit char<->int conversion - //which in turn makes encryption arithmetic easier + //using standard stdlib types is actually easier here because of implicit char<->int conversion + //which in turn makes encryption arithmetic easier - unsigned int key = p_key; - unsigned int C1 = 53761; - unsigned int C2 = 32618; + unsigned int key = p_key; + unsigned int C1 = 53761; + unsigned int C2 = 32618; - QVector temp_result; - std::string input = temp_input.toUtf8().constData(); + QVector temp_result; + std::string input = temp_input.toUtf8().constData(); - for (unsigned int pos = 0 ; pos < input.size() ; ++pos) - { - uint_fast8_t output = input.at(pos) ^ (key >> 8) % 256; - temp_result.append(output); - key = (temp_result.at(pos) + key) * C1 + C2; - } + for (unsigned int pos = 0; pos < input.size(); ++pos) { + uint_fast8_t output = input.at(pos) ^ (key >> 8) % 256; + temp_result.append(output); + key = (temp_result.at(pos) + key) * C1 + C2; + } - std::string result = ""; + std::string result = ""; - for (uint_fast8_t i_int : temp_result) - { - result += omni::int_to_hex(i_int); - } + for (uint_fast8_t i_int : temp_result) { + result += omni::int_to_hex(i_int); + } - QString final_result = QString::fromStdString(result); + QString final_result = QString::fromStdString(result); - return final_result; + return final_result; } QString fanta_decrypt(QString temp_input, unsigned int key) { - std::string input = temp_input.toUtf8().constData(); + std::string input = temp_input.toUtf8().constData(); - QVector unhexed_vector; + QVector unhexed_vector; - for(unsigned int i=0; i< input.length(); i+=2) - { - std::string byte = input.substr(i,2); - unsigned int hex_int = strtoul(byte.c_str(), nullptr, 16); - unhexed_vector.append(hex_int); - } + for (unsigned int i = 0; i < input.length(); i += 2) { + std::string byte = input.substr(i, 2); + unsigned int hex_int = strtoul(byte.c_str(), nullptr, 16); + unhexed_vector.append(hex_int); + } - unsigned int C1 = 53761; - unsigned int C2 = 32618; + unsigned int C1 = 53761; + unsigned int C2 = 32618; - std::string result = ""; + std::string result = ""; - for (int pos = 0 ; pos < unhexed_vector.size() ; ++pos) - { - unsigned char output = unhexed_vector.at(pos) ^ (key >> 8) % 256; - result += output; - key = (unhexed_vector.at(pos) + key) * C1 + C2; - } - - return QString::fromStdString(result); + for (int pos = 0; pos < unhexed_vector.size(); ++pos) { + unsigned char output = unhexed_vector.at(pos) ^ (key >> 8) % 256; + result += output; + key = (unhexed_vector.at(pos) + key) * C1 + C2; + } + return QString::fromStdString(result); } diff --git a/src/evidence.cpp b/src/evidence.cpp index 0cee435..50ed9a4 100644 --- a/src/evidence.cpp +++ b/src/evidence.cpp @@ -2,533 +2,510 @@ void Courtroom::initialize_evidence() { - ui_evidence = new AOImage(this, ao_app); + ui_evidence = new AOImage(this, ao_app); - //ui_evidence_name = new QLabel(ui_evidence); - ui_evidence_name = new AOLineEdit(ui_evidence); - ui_evidence_name->setAlignment(Qt::AlignCenter); - ui_evidence_name->setFrame(false); + //ui_evidence_name = new QLabel(ui_evidence); + ui_evidence_name = new AOLineEdit(ui_evidence); + ui_evidence_name->setAlignment(Qt::AlignCenter); + ui_evidence_name->setFrame(false); - ui_evidence_buttons = new QWidget(ui_evidence); + ui_evidence_buttons = new QWidget(ui_evidence); - ui_evidence_left = new AOButton(ui_evidence, ao_app); - ui_evidence_right = new AOButton(ui_evidence, ao_app); - ui_evidence_present = new AOButton(ui_evidence, ao_app); - ui_evidence_present->setToolTip(tr("Present this piece of evidence to everyone on your next spoken message")); + ui_evidence_left = new AOButton(ui_evidence, ao_app); + ui_evidence_right = new AOButton(ui_evidence, ao_app); + ui_evidence_present = new AOButton(ui_evidence, ao_app); + ui_evidence_present->setToolTip(tr("Present this piece of evidence to everyone on your next spoken message")); - ui_evidence_switch = new AOButton(ui_evidence, ao_app); - ui_evidence_transfer = new AOButton(ui_evidence, ao_app); + ui_evidence_switch = new AOButton(ui_evidence, ao_app); + ui_evidence_transfer = new AOButton(ui_evidence, ao_app); - ui_evidence_save = new AOButton(ui_evidence, ao_app); - ui_evidence_save->setToolTip(tr("Save evidence to an .ini file.")); - ui_evidence_load = new AOButton(ui_evidence, ao_app); - ui_evidence_load->setToolTip(tr("Load evidence from an .ini file.")); + ui_evidence_save = new AOButton(ui_evidence, ao_app); + ui_evidence_save->setToolTip(tr("Save evidence to an .ini file.")); + ui_evidence_load = new AOButton(ui_evidence, ao_app); + ui_evidence_load->setToolTip(tr("Load evidence from an .ini file.")); - ui_evidence_overlay = new AOImage(ui_evidence, ao_app); + ui_evidence_overlay = new AOImage(ui_evidence, ao_app); - ui_evidence_delete = new AOButton(ui_evidence_overlay, ao_app); - ui_evidence_delete->setToolTip(tr("Destroy this piece of evidence")); - ui_evidence_image_name = new AOLineEdit(ui_evidence_overlay); - ui_evidence_image_button = new AOButton(ui_evidence_overlay, ao_app); - ui_evidence_image_button->setText(tr("Choose...")); - ui_evidence_x = new AOButton(ui_evidence_overlay, ao_app); - ui_evidence_x->setToolTip(tr("Close the evidence display/editing overlay.\n" - "You will be prompted if there's any unsaved changes.")); - ui_evidence_ok = new AOButton(ui_evidence_overlay, ao_app); - ui_evidence_ok->setToolTip(tr("Save any changes made to this piece of evidence and send them to server.")); + ui_evidence_delete = new AOButton(ui_evidence_overlay, ao_app); + ui_evidence_delete->setToolTip(tr("Destroy this piece of evidence")); + ui_evidence_image_name = new AOLineEdit(ui_evidence_overlay); + ui_evidence_image_button = new AOButton(ui_evidence_overlay, ao_app); + ui_evidence_image_button->setText(tr("Choose...")); + ui_evidence_x = new AOButton(ui_evidence_overlay, ao_app); + ui_evidence_x->setToolTip(tr("Close the evidence display/editing overlay.\n" + "You will be prompted if there's any unsaved changes.")); + ui_evidence_ok = new AOButton(ui_evidence_overlay, ao_app); + ui_evidence_ok->setToolTip(tr("Save any changes made to this piece of evidence and send them to server.")); - ui_evidence_description = new AOTextEdit(ui_evidence_overlay); - ui_evidence_description->setStyleSheet("background-color: rgba(0, 0, 0, 0);" - "color: white;"); - ui_evidence_description->setFrameStyle(QFrame::NoFrame); - ui_evidence_description->setToolTip("Double-click to edit. Press [X] to update your changes."); + ui_evidence_description = new AOTextEdit(ui_evidence_overlay); + ui_evidence_description->setStyleSheet("background-color: rgba(0, 0, 0, 0);" + "color: white;"); + ui_evidence_description->setFrameStyle(QFrame::NoFrame); + ui_evidence_description->setToolTip("Double-click to edit. Press [X] to update your changes."); - connect(ui_evidence_name, SIGNAL(returnPressed()), this, SLOT(on_evidence_name_edited())); - connect(ui_evidence_name, SIGNAL(double_clicked()), this, SLOT(on_evidence_name_double_clicked())); - connect(ui_evidence_left, SIGNAL(clicked()), this, SLOT(on_evidence_left_clicked())); - connect(ui_evidence_right, SIGNAL(clicked()), this, SLOT(on_evidence_right_clicked())); - connect(ui_evidence_present, SIGNAL(clicked()), this, SLOT(on_evidence_present_clicked())); - connect(ui_evidence_switch, SIGNAL(clicked()), this, SLOT(on_evidence_switch_clicked())); - connect(ui_evidence_transfer, SIGNAL(clicked()), this, SLOT(on_evidence_transfer_clicked())); - connect(ui_evidence_save, SIGNAL(clicked()), this, SLOT(on_evidence_save_clicked())); - connect(ui_evidence_load, SIGNAL(clicked()), this, SLOT(on_evidence_load_clicked())); + connect(ui_evidence_name, SIGNAL(returnPressed()), this, SLOT(on_evidence_name_edited())); + connect(ui_evidence_name, SIGNAL(double_clicked()), this, SLOT(on_evidence_name_double_clicked())); + connect(ui_evidence_left, SIGNAL(clicked()), this, SLOT(on_evidence_left_clicked())); + connect(ui_evidence_right, SIGNAL(clicked()), this, SLOT(on_evidence_right_clicked())); + connect(ui_evidence_present, SIGNAL(clicked()), this, SLOT(on_evidence_present_clicked())); + connect(ui_evidence_switch, SIGNAL(clicked()), this, SLOT(on_evidence_switch_clicked())); + connect(ui_evidence_transfer, SIGNAL(clicked()), this, SLOT(on_evidence_transfer_clicked())); + connect(ui_evidence_save, SIGNAL(clicked()), this, SLOT(on_evidence_save_clicked())); + connect(ui_evidence_load, SIGNAL(clicked()), this, SLOT(on_evidence_load_clicked())); - connect(ui_evidence_delete, SIGNAL(clicked()), this, SLOT(on_evidence_delete_clicked())); - connect(ui_evidence_image_name, SIGNAL(returnPressed()), this, SLOT(on_evidence_image_name_edited())); - connect(ui_evidence_image_name, SIGNAL(double_clicked()), this, SLOT(on_evidence_image_name_double_clicked())); - connect(ui_evidence_image_button, SIGNAL(clicked()), this, SLOT(on_evidence_image_button_clicked())); - connect(ui_evidence_x, SIGNAL(clicked()), this, SLOT(on_evidence_x_clicked())); - connect(ui_evidence_ok, SIGNAL(clicked()), this, SLOT(on_evidence_ok_clicked())); + connect(ui_evidence_delete, SIGNAL(clicked()), this, SLOT(on_evidence_delete_clicked())); + connect(ui_evidence_image_name, SIGNAL(returnPressed()), this, SLOT(on_evidence_image_name_edited())); + connect(ui_evidence_image_name, SIGNAL(double_clicked()), this, SLOT(on_evidence_image_name_double_clicked())); + connect(ui_evidence_image_button, SIGNAL(clicked()), this, SLOT(on_evidence_image_button_clicked())); + connect(ui_evidence_x, SIGNAL(clicked()), this, SLOT(on_evidence_x_clicked())); + connect(ui_evidence_ok, SIGNAL(clicked()), this, SLOT(on_evidence_ok_clicked())); - connect(ui_evidence_name, SIGNAL(textChanged(QString)), this, SLOT(on_evidence_edited())); - connect(ui_evidence_image_name, SIGNAL(textChanged(QString)), this, SLOT(on_evidence_edited())); - connect(ui_evidence_description, SIGNAL(textChanged()), this, SLOT(on_evidence_edited())); + connect(ui_evidence_name, SIGNAL(textChanged(QString)), this, SLOT(on_evidence_edited())); + connect(ui_evidence_image_name, SIGNAL(textChanged(QString)), this, SLOT(on_evidence_edited())); + connect(ui_evidence_description, SIGNAL(textChanged()), this, SLOT(on_evidence_edited())); - ui_evidence->hide(); + ui_evidence->hide(); } void Courtroom::refresh_evidence() { - set_font(ui_evidence_name, "", "evidence_name"); - set_font(ui_evidence_image_name, "", "evidence_image_name"); - set_font(ui_evidence_description, "", "evidence_description"); + set_font(ui_evidence_name, "", "evidence_name"); + set_font(ui_evidence_image_name, "", "evidence_image_name"); + set_font(ui_evidence_description, "", "evidence_description"); - //Should properly refresh the evidence list - qDeleteAll(ui_evidence_list.begin(), ui_evidence_list.end()); - ui_evidence_list.clear(); + //Should properly refresh the evidence list + qDeleteAll(ui_evidence_list.begin(), ui_evidence_list.end()); + ui_evidence_list.clear(); - set_size_and_pos(ui_evidence_button, "evidence_button"); - ui_evidence_button->set_image("evidence_button"); - ui_evidence_button->setToolTip(tr("Bring up the Evidence screen.")); + set_size_and_pos(ui_evidence_button, "evidence_button"); + ui_evidence_button->set_image("evidence_button"); + ui_evidence_button->setToolTip(tr("Bring up the Evidence screen.")); - set_size_and_pos(ui_evidence, "evidence_background"); - if (current_evidence_global) - ui_evidence->set_image("evidence_background"); - else - ui_evidence->set_image("evidence_background_private"); + set_size_and_pos(ui_evidence, "evidence_background"); + if (current_evidence_global) + ui_evidence->set_image("evidence_background"); + else + ui_evidence->set_image("evidence_background_private"); - set_size_and_pos(ui_evidence_name, "evidence_name"); + set_size_and_pos(ui_evidence_name, "evidence_name"); - set_size_and_pos(ui_evidence_buttons, "evidence_buttons"); + set_size_and_pos(ui_evidence_buttons, "evidence_buttons"); - set_size_and_pos(ui_evidence_left, "evidence_left"); - ui_evidence_left->set_image("arrow_left"); + set_size_and_pos(ui_evidence_left, "evidence_left"); + ui_evidence_left->set_image("arrow_left"); - set_size_and_pos(ui_evidence_right, "evidence_right"); - ui_evidence_right->set_image("arrow_right"); + set_size_and_pos(ui_evidence_right, "evidence_right"); + ui_evidence_right->set_image("arrow_right"); - set_size_and_pos(ui_evidence_present, "evidence_present"); - ui_evidence_present->set_image("present"); + set_size_and_pos(ui_evidence_present, "evidence_present"); + ui_evidence_present->set_image("present"); - set_size_and_pos(ui_evidence_overlay, "evidence_overlay"); - if (current_evidence_global) - ui_evidence_overlay->set_image("evidence_overlay"); - else - ui_evidence_overlay->set_image("evidence_overlay_private"); + set_size_and_pos(ui_evidence_overlay, "evidence_overlay"); + if (current_evidence_global) + ui_evidence_overlay->set_image("evidence_overlay"); + else + ui_evidence_overlay->set_image("evidence_overlay_private"); - set_size_and_pos(ui_evidence_delete, "evidence_delete"); - ui_evidence_delete->set_image("evidence_delete"); + set_size_and_pos(ui_evidence_delete, "evidence_delete"); + ui_evidence_delete->set_image("evidence_delete"); - set_size_and_pos(ui_evidence_image_name, "evidence_image_name"); + set_size_and_pos(ui_evidence_image_name, "evidence_image_name"); - set_size_and_pos(ui_evidence_image_button, "evidence_image_button"); + set_size_and_pos(ui_evidence_image_button, "evidence_image_button"); - set_size_and_pos(ui_evidence_x, "evidence_x"); - ui_evidence_x->set_image("evidence_x"); + set_size_and_pos(ui_evidence_x, "evidence_x"); + ui_evidence_x->set_image("evidence_x"); - set_size_and_pos(ui_evidence_ok, "evidence_ok"); - ui_evidence_ok->set_image("evidence_ok"); + set_size_and_pos(ui_evidence_ok, "evidence_ok"); + ui_evidence_ok->set_image("evidence_ok"); - set_size_and_pos(ui_evidence_switch, "evidence_switch"); - if (current_evidence_global) - { - ui_evidence_switch->set_image("evidence_global"); - ui_evidence_switch->setToolTip(tr("Switch evidence to private inventory.")); - } - else - { - ui_evidence_switch->set_image("evidence_private"); - ui_evidence_switch->setToolTip(tr("Switch evidence to global inventory.")); - } - - set_size_and_pos(ui_evidence_transfer, "evidence_transfer"); - if (current_evidence_global) - { - ui_evidence_transfer->set_image("evidence_transfer"); - ui_evidence_transfer->setToolTip(tr("Transfer evidence to private inventory.")); - } - else - { - ui_evidence_transfer->set_image("evidence_transfer_private"); - ui_evidence_transfer->setToolTip(tr("Transfer evidence to global inventory.")); - } - - set_size_and_pos(ui_evidence_save, "evidence_save"); - ui_evidence_save->set_image("evidence_save"); - if (current_evidence_global) - ui_evidence_save->hide(); - else - ui_evidence_save->show(); - - set_size_and_pos(ui_evidence_load, "evidence_load"); - ui_evidence_load->set_image("evidence_load"); - if (current_evidence_global) - ui_evidence_load->hide(); - else - ui_evidence_load->show(); - - set_size_and_pos(ui_evidence_description, "evidence_description"); - - QPoint f_spacing = ao_app->get_button_spacing("evidence_button_spacing", "courtroom_design.ini"); - QPoint p_point = ao_app->get_button_spacing("evidence_button_size", "courtroom_design.ini"); - - const int button_width = p_point.x(); - int x_spacing = f_spacing.x(); - int x_mod_count = 0; - - const int button_height = p_point.y(); - int y_spacing = f_spacing.y(); - int y_mod_count = 0; - - evidence_columns = ((ui_evidence_buttons->width() - button_width) / (x_spacing + button_width)) + 1; - evidence_rows = ((ui_evidence_buttons->height() - button_height) / (y_spacing + button_height)) + 1; - - max_evidence_on_page = evidence_columns * evidence_rows; - - for (int n = 0 ; n < max_evidence_on_page ; ++n) - { - int x_pos = (button_width + x_spacing) * x_mod_count; - int y_pos = (button_height + y_spacing) * y_mod_count; - - AOEvidenceButton *f_evidence = new AOEvidenceButton(ui_evidence_buttons, ao_app, x_pos, y_pos, button_width, button_height); - - ui_evidence_list.append(f_evidence); - - f_evidence->set_id(n); - - connect(f_evidence, SIGNAL(evidence_clicked(int)), this, SLOT(on_evidence_clicked(int))); - connect(f_evidence, SIGNAL(evidence_double_clicked(int)), this, SLOT(on_evidence_double_clicked(int))); - connect(f_evidence, SIGNAL(on_hover(int, bool)), this, SLOT(on_evidence_hover(int, bool))); - - ++x_mod_count; - - if (x_mod_count == evidence_columns) - { - ++y_mod_count; - x_mod_count = 0; + set_size_and_pos(ui_evidence_switch, "evidence_switch"); + if (current_evidence_global) { + ui_evidence_switch->set_image("evidence_global"); + ui_evidence_switch->setToolTip(tr("Switch evidence to private inventory.")); + } + else { + ui_evidence_switch->set_image("evidence_private"); + ui_evidence_switch->setToolTip(tr("Switch evidence to global inventory.")); + } + + set_size_and_pos(ui_evidence_transfer, "evidence_transfer"); + if (current_evidence_global) { + ui_evidence_transfer->set_image("evidence_transfer"); + ui_evidence_transfer->setToolTip(tr("Transfer evidence to private inventory.")); + } + else { + ui_evidence_transfer->set_image("evidence_transfer_private"); + ui_evidence_transfer->setToolTip(tr("Transfer evidence to global inventory.")); + } + + set_size_and_pos(ui_evidence_save, "evidence_save"); + ui_evidence_save->set_image("evidence_save"); + if (current_evidence_global) + ui_evidence_save->hide(); + else + ui_evidence_save->show(); + + set_size_and_pos(ui_evidence_load, "evidence_load"); + ui_evidence_load->set_image("evidence_load"); + if (current_evidence_global) + ui_evidence_load->hide(); + else + ui_evidence_load->show(); + + set_size_and_pos(ui_evidence_description, "evidence_description"); + + QPoint f_spacing = ao_app->get_button_spacing("evidence_button_spacing", "courtroom_design.ini"); + QPoint p_point = ao_app->get_button_spacing("evidence_button_size", "courtroom_design.ini"); + + const int button_width = p_point.x(); + int x_spacing = f_spacing.x(); + int x_mod_count = 0; + + const int button_height = p_point.y(); + int y_spacing = f_spacing.y(); + int y_mod_count = 0; + + evidence_columns = ((ui_evidence_buttons->width() - button_width) / (x_spacing + button_width)) + 1; + evidence_rows = ((ui_evidence_buttons->height() - button_height) / (y_spacing + button_height)) + 1; + + max_evidence_on_page = evidence_columns * evidence_rows; + + for (int n = 0; n < max_evidence_on_page; ++n) { + int x_pos = (button_width + x_spacing) * x_mod_count; + int y_pos = (button_height + y_spacing) * y_mod_count; + + AOEvidenceButton *f_evidence = new AOEvidenceButton(ui_evidence_buttons, ao_app, x_pos, y_pos, button_width, button_height); + + ui_evidence_list.append(f_evidence); + + f_evidence->set_id(n); + + connect(f_evidence, SIGNAL(evidence_clicked(int)), this, SLOT(on_evidence_clicked(int))); + connect(f_evidence, SIGNAL(evidence_double_clicked(int)), this, SLOT(on_evidence_double_clicked(int))); + connect(f_evidence, SIGNAL(on_hover(int, bool)), this, SLOT(on_evidence_hover(int, bool))); + + ++x_mod_count; + + if (x_mod_count == evidence_columns) { + ++y_mod_count; + x_mod_count = 0; + } } - } } void Courtroom::set_evidence_list(QVector &p_evi_list) { - global_evidence_list = p_evi_list; - if (!current_evidence_global) - return; //We're on private evidence editing, wait for user to do their thing + global_evidence_list = p_evi_list; + if (!current_evidence_global) + return; //We're on private evidence editing, wait for user to do their thing - QVector old_list = local_evidence_list; - local_evidence_list.clear(); - local_evidence_list = p_evi_list; + QVector old_list = local_evidence_list; + local_evidence_list.clear(); + local_evidence_list = p_evi_list; - set_evidence_page(); + set_evidence_page(); - if (ui_evidence_overlay->isVisible())//Update the currently edited evidence for this user - { - if (current_evidence >= local_evidence_list.size()) + if (ui_evidence_overlay->isVisible()) //Update the currently edited evidence for this user { - evidence_close(); - ui_evidence_name->setText(""); - } - else if (ui_evidence_description->isReadOnly()) //We haven't double clicked to edit it or anything - { - on_evidence_double_clicked(current_evidence); - } - //Todo: make a function that compares two pieces of evidence for any differences - else if (compare_evidence_changed(old_list.at(current_evidence), local_evidence_list.at(current_evidence))) - { - QMessageBox *msgBox = new QMessageBox; - - msgBox->setText("The piece of evidence you've been editing has changed."); - msgBox->setInformativeText("Do you wish to keep your changes?"); - msgBox->setDetailedText("Name: " + local_evidence_list.at(current_evidence).name + "\nImage: " + local_evidence_list.at(current_evidence).image + "\nDescription:\n" + local_evidence_list.at(current_evidence).description); - msgBox->setStandardButtons(QMessageBox::Yes | QMessageBox::No); - msgBox->setDefaultButton(QMessageBox::LastButton); - //msgBox->setWindowModality(Qt::NonModal); - int ret = msgBox->exec(); - switch (ret) { - case QMessageBox::Yes: - // "Keep changes" - break; - case QMessageBox::No: - // "Discard changes and keep theirs" + if (current_evidence >= local_evidence_list.size()) { + evidence_close(); + ui_evidence_name->setText(""); + } + else if (ui_evidence_description->isReadOnly()) //We haven't double clicked to edit it or anything + { on_evidence_double_clicked(current_evidence); - break; - default: - // should never be reached - break; - } + } + //Todo: make a function that compares two pieces of evidence for any differences + else if (compare_evidence_changed(old_list.at(current_evidence), local_evidence_list.at(current_evidence))) { + QMessageBox *msgBox = new QMessageBox; + + msgBox->setText("The piece of evidence you've been editing has changed."); + msgBox->setInformativeText("Do you wish to keep your changes?"); + msgBox->setDetailedText("Name: " + local_evidence_list.at(current_evidence).name + "\nImage: " + local_evidence_list.at(current_evidence).image + "\nDescription:\n" + local_evidence_list.at(current_evidence).description); + msgBox->setStandardButtons(QMessageBox::Yes | QMessageBox::No); + msgBox->setDefaultButton(QMessageBox::LastButton); + //msgBox->setWindowModality(Qt::NonModal); + int ret = msgBox->exec(); + switch (ret) { + case QMessageBox::Yes: + // "Keep changes" + break; + case QMessageBox::No: + // "Discard changes and keep theirs" + on_evidence_double_clicked(current_evidence); + break; + default: + // should never be reached + break; + } + } } - } } void Courtroom::set_evidence_page() { - int total_evidence = local_evidence_list.size(); + int total_evidence = local_evidence_list.size(); - ui_evidence_left->hide(); - ui_evidence_right->hide(); + ui_evidence_left->hide(); + ui_evidence_right->hide(); - for (AOEvidenceButton *i_button : ui_evidence_list) - { - i_button->hide(); - } + for (AOEvidenceButton *i_button : ui_evidence_list) { + i_button->hide(); + } - //to account for the "add evidence" button - ++total_evidence; + //to account for the "add evidence" button + ++total_evidence; - int total_pages = total_evidence / max_evidence_on_page; - int evidence_on_page = 0; + int total_pages = total_evidence / max_evidence_on_page; + int evidence_on_page = 0; + + if ((total_evidence % max_evidence_on_page) != 0) { + ++total_pages; + //i. e. not on the last page + if (total_pages > current_evidence_page + 1) + evidence_on_page = max_evidence_on_page; + else + evidence_on_page = total_evidence % max_evidence_on_page; + } + else + evidence_on_page = max_evidence_on_page; - if ((total_evidence % max_evidence_on_page) != 0) - { - ++total_pages; - //i. e. not on the last page if (total_pages > current_evidence_page + 1) - evidence_on_page = max_evidence_on_page; - else - evidence_on_page = total_evidence % max_evidence_on_page; + ui_evidence_right->show(); - } - else - evidence_on_page = max_evidence_on_page; + if (current_evidence_page > 0) + ui_evidence_left->show(); - if (total_pages > current_evidence_page + 1) - ui_evidence_right->show(); + for (int n_evidence_button = 0; n_evidence_button < evidence_on_page; ++n_evidence_button) { + int n_real_evidence = n_evidence_button + current_evidence_page * max_evidence_on_page; + AOEvidenceButton *f_evidence_button = ui_evidence_list.at(n_evidence_button); - if (current_evidence_page > 0) - ui_evidence_left->show(); + f_evidence_button->set_selected(false); + f_evidence_button->setToolTip(""); + if (n_real_evidence == (total_evidence - 1)) { + f_evidence_button->set_theme_image("addevidence.png"); + } + else if (n_real_evidence < (total_evidence - 1)) { + f_evidence_button->set_image(local_evidence_list.at(n_real_evidence).image); - for (int n_evidence_button = 0 ; n_evidence_button < evidence_on_page ; ++n_evidence_button) - { - int n_real_evidence = n_evidence_button + current_evidence_page * max_evidence_on_page; - AOEvidenceButton *f_evidence_button = ui_evidence_list.at(n_evidence_button); + if (n_real_evidence == current_evidence) + f_evidence_button->set_selected(true); - f_evidence_button->set_selected(false); - f_evidence_button->setToolTip(""); - if (n_real_evidence == (total_evidence - 1)) - { - f_evidence_button->set_theme_image("addevidence.png"); + f_evidence_button->setToolTip(QString::number(n_real_evidence + 1) + ": " + local_evidence_list.at(n_real_evidence).name); + } + else + f_evidence_button->set_image(""); + + f_evidence_button->show(); } - else if (n_real_evidence < (total_evidence - 1)) - { - f_evidence_button->set_image(local_evidence_list.at(n_real_evidence).image); - - if (n_real_evidence == current_evidence) - f_evidence_button->set_selected(true); - - f_evidence_button->setToolTip(QString::number(n_real_evidence+1) + ": " + local_evidence_list.at(n_real_evidence).name); - } - else - f_evidence_button->set_image(""); - - f_evidence_button->show(); - } } void Courtroom::on_evidence_name_edited() { - ui_evidence_name->setReadOnly(true); - if (current_evidence >= local_evidence_list.size()) - return; + ui_evidence_name->setReadOnly(true); + if (current_evidence >= local_evidence_list.size()) + return; } void Courtroom::on_evidence_name_double_clicked() { - if (ui_evidence_overlay->isVisible()) - { - ui_evidence_name->setReadOnly(false); - } - else - { - ui_evidence_name->setReadOnly(true); - } + if (ui_evidence_overlay->isVisible()) { + ui_evidence_name->setReadOnly(false); + } + else { + ui_evidence_name->setReadOnly(true); + } } void Courtroom::on_evidence_image_name_double_clicked() { - ui_evidence_image_name->setReadOnly(false); + ui_evidence_image_name->setReadOnly(false); } void Courtroom::on_evidence_image_name_edited() { - ui_evidence_image_name->setReadOnly(true); - if (current_evidence >= local_evidence_list.size()) - return; + ui_evidence_image_name->setReadOnly(true); + if (current_evidence >= local_evidence_list.size()) + return; } void Courtroom::on_evidence_image_button_clicked() { - QDir dir(ao_app->get_base_path() + "evidence"); - QFileDialog dialog(this); - dialog.setFileMode(QFileDialog::ExistingFile); - dialog.setNameFilter(tr("Images (*.png)")); - dialog.setViewMode(QFileDialog::List); - dialog.setDirectory(dir); + QDir dir(ao_app->get_base_path() + "evidence"); + QFileDialog dialog(this); + dialog.setFileMode(QFileDialog::ExistingFile); + dialog.setNameFilter(tr("Images (*.png)")); + dialog.setViewMode(QFileDialog::List); + dialog.setDirectory(dir); - QStringList filenames; + QStringList filenames; - if (dialog.exec()) - filenames = dialog.selectedFiles(); + if (dialog.exec()) + filenames = dialog.selectedFiles(); - if (filenames.size() != 1) - return; + if (filenames.size() != 1) + return; - QString filename = filenames.at(0); - filename = dir.relativeFilePath(filename); - ui_evidence_image_name->setText(filename); - on_evidence_image_name_edited(); + QString filename = filenames.at(0); + filename = dir.relativeFilePath(filename); + ui_evidence_image_name->setText(filename); + on_evidence_image_name_edited(); } void Courtroom::on_evidence_clicked(int p_id) { - ui_evidence_name->setReadOnly(true); + ui_evidence_name->setReadOnly(true); - int f_real_id = p_id + max_evidence_on_page * current_evidence_page; + int f_real_id = p_id + max_evidence_on_page * current_evidence_page; - if (f_real_id == local_evidence_list.size()) - { - if (current_evidence_global) - ao_app->send_server_packet(new AOPacket("PE###empty.png#%")); - else - { - evi_type f_evi; - f_evi.name = ""; - f_evi.description = ""; - f_evi.image = "empty.png"; + if (f_real_id == local_evidence_list.size()) { + if (current_evidence_global) + ao_app->send_server_packet(new AOPacket("PE###empty.png#%")); + else { + evi_type f_evi; + f_evi.name = ""; + f_evi.description = ""; + f_evi.image = "empty.png"; - local_evidence_list.append(f_evi); - private_evidence_list = local_evidence_list; - set_evidence_page(); + local_evidence_list.append(f_evi); + private_evidence_list = local_evidence_list; + set_evidence_page(); + } + return; } - return; - } - else if (f_real_id > local_evidence_list.size()) - return; + else if (f_real_id > local_evidence_list.size()) + return; - ui_evidence_name->setText(local_evidence_list.at(f_real_id).name); + ui_evidence_name->setText(local_evidence_list.at(f_real_id).name); - for (AOEvidenceButton *i_button : ui_evidence_list) - i_button->set_selected(false); + for (AOEvidenceButton *i_button : ui_evidence_list) + i_button->set_selected(false); - ui_evidence_list.at(p_id)->set_selected(true); + ui_evidence_list.at(p_id)->set_selected(true); - current_evidence = f_real_id; - -// ui_ic_chat_message->setFocus(); + current_evidence = f_real_id; + // ui_ic_chat_message->setFocus(); } void Courtroom::on_evidence_double_clicked(int p_id) { - int f_real_id = p_id + max_evidence_on_page * current_evidence_page; + int f_real_id = p_id + max_evidence_on_page * current_evidence_page; - if (f_real_id >= local_evidence_list.size()) - return; + if (f_real_id >= local_evidence_list.size()) + return; - current_evidence = f_real_id; + current_evidence = f_real_id; - evi_type f_evi = local_evidence_list.at(f_real_id); + evi_type f_evi = local_evidence_list.at(f_real_id); - ui_evidence_description->clear(); - ui_evidence_description->appendPlainText(f_evi.description); - ui_evidence_description->setReadOnly(true); - ui_evidence_description->setToolTip("Double-click to edit..."); + ui_evidence_description->clear(); + ui_evidence_description->appendPlainText(f_evi.description); + ui_evidence_description->setReadOnly(true); + ui_evidence_description->setToolTip("Double-click to edit..."); - ui_evidence_name->setText(f_evi.name); - ui_evidence_name->setReadOnly(true); - ui_evidence_name->setToolTip("Double-click to edit..."); - ui_evidence_image_name->setText(f_evi.image); - ui_evidence_image_name->setReadOnly(true); - ui_evidence_image_name->setToolTip("Double-click to edit..."); + ui_evidence_name->setText(f_evi.name); + ui_evidence_name->setReadOnly(true); + ui_evidence_name->setToolTip("Double-click to edit..."); + ui_evidence_image_name->setText(f_evi.image); + ui_evidence_image_name->setReadOnly(true); + ui_evidence_image_name->setToolTip("Double-click to edit..."); - ui_evidence_overlay->show(); - ui_evidence_ok->hide(); + ui_evidence_overlay->show(); + ui_evidence_ok->hide(); - ui_ic_chat_message->setFocus(); + ui_ic_chat_message->setFocus(); } void Courtroom::on_evidence_hover(int p_id, bool p_state) { - ui_evidence_name->setReadOnly(true); - int final_id = p_id + max_evidence_on_page * current_evidence_page; + ui_evidence_name->setReadOnly(true); + int final_id = p_id + max_evidence_on_page * current_evidence_page; - if (p_state) - { - if (final_id == local_evidence_list.size()) - ui_evidence_name->setText(tr("Add new evidence...")); - else if (final_id < local_evidence_list.size()) - ui_evidence_name->setText(local_evidence_list.at(final_id).name); - } - else if (current_evidence < local_evidence_list.size()) - ui_evidence_name->setText(local_evidence_list.at(current_evidence).name); - else - ui_evidence_name->setText(""); + if (p_state) { + if (final_id == local_evidence_list.size()) + ui_evidence_name->setText(tr("Add new evidence...")); + else if (final_id < local_evidence_list.size()) + ui_evidence_name->setText(local_evidence_list.at(final_id).name); + } + else if (current_evidence < local_evidence_list.size()) + ui_evidence_name->setText(local_evidence_list.at(current_evidence).name); + else + ui_evidence_name->setText(""); } void Courtroom::on_evidence_left_clicked() { - --current_evidence_page; + --current_evidence_page; - set_evidence_page(); + set_evidence_page(); - ui_ic_chat_message->setFocus(); + ui_ic_chat_message->setFocus(); } void Courtroom::on_evidence_right_clicked() { - ++current_evidence_page; + ++current_evidence_page; - set_evidence_page(); + set_evidence_page(); - ui_ic_chat_message->setFocus(); + ui_ic_chat_message->setFocus(); } void Courtroom::on_evidence_present_clicked() { - if (!current_evidence_global) - { - ui_evidence_present->hide(); - is_presenting_evidence = false; - return; //otherwise we get force-disconnected - } - if (is_presenting_evidence) - ui_evidence_present->set_image("present"); - else - ui_evidence_present->set_image("present_disabled"); + if (!current_evidence_global) { + ui_evidence_present->hide(); + is_presenting_evidence = false; + return; //otherwise we get force-disconnected + } + if (is_presenting_evidence) + ui_evidence_present->set_image("present"); + else + ui_evidence_present->set_image("present_disabled"); - is_presenting_evidence = !is_presenting_evidence; + is_presenting_evidence = !is_presenting_evidence; - ui_ic_chat_message->setFocus(); + ui_ic_chat_message->setFocus(); } void Courtroom::on_evidence_delete_clicked() { - evidence_close(); - if (current_evidence_global) - ao_app->send_server_packet(new AOPacket("DE#" + QString::number(current_evidence) + "#%")); - else - { - local_evidence_list.remove(current_evidence); - private_evidence_list = local_evidence_list; - set_evidence_page(); - } + evidence_close(); + if (current_evidence_global) + ao_app->send_server_packet(new AOPacket("DE#" + QString::number(current_evidence) + "#%")); + else { + local_evidence_list.remove(current_evidence); + private_evidence_list = local_evidence_list; + set_evidence_page(); + } - current_evidence = 0; + current_evidence = 0; - ui_ic_chat_message->setFocus(); + ui_ic_chat_message->setFocus(); } void Courtroom::on_evidence_x_clicked() { - if (current_evidence >= local_evidence_list.size()) //Should never happen but you never know. - return; + if (current_evidence >= local_evidence_list.size()) //Should never happen but you never know. + return; - evi_type fake_evidence; - fake_evidence.name = ui_evidence_name->text(); - fake_evidence.description = ui_evidence_description->toPlainText(); - fake_evidence.image = ui_evidence_image_name->text(); - if (!compare_evidence_changed(fake_evidence, local_evidence_list.at(current_evidence))) - { - evidence_close(); - return; - } - QMessageBox *msgBox = new QMessageBox; - msgBox->setText("Evidence has been modified."); - msgBox->setInformativeText("Do you want to save your changes?"); - msgBox->setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); - msgBox->setDefaultButton(QMessageBox::Save); - int ret = msgBox->exec(); - switch (ret) { + evi_type fake_evidence; + fake_evidence.name = ui_evidence_name->text(); + fake_evidence.description = ui_evidence_description->toPlainText(); + fake_evidence.image = ui_evidence_image_name->text(); + if (!compare_evidence_changed(fake_evidence, local_evidence_list.at(current_evidence))) { + evidence_close(); + return; + } + QMessageBox *msgBox = new QMessageBox; + msgBox->setText("Evidence has been modified."); + msgBox->setInformativeText("Do you want to save your changes?"); + msgBox->setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); + msgBox->setDefaultButton(QMessageBox::Save); + int ret = msgBox->exec(); + switch (ret) { case QMessageBox::Save: evidence_close(); on_evidence_ok_clicked(); @@ -542,200 +519,191 @@ void Courtroom::on_evidence_x_clicked() default: // should never be reached break; - } + } } void Courtroom::on_evidence_ok_clicked() { - ui_evidence_name->setReadOnly(true); - ui_evidence_description->setReadOnly(true); - ui_evidence_image_name->setReadOnly(true); - if (current_evidence < local_evidence_list.size()) - { - evi_type f_evi = local_evidence_list.at(current_evidence); - if (current_evidence_global) - { - QStringList f_contents; - f_contents.append(QString::number(current_evidence)); - f_contents.append(ui_evidence_name->text()); - f_contents.append(ui_evidence_description->toPlainText()); - f_contents.append(ui_evidence_image_name->text()); + ui_evidence_name->setReadOnly(true); + ui_evidence_description->setReadOnly(true); + ui_evidence_image_name->setReadOnly(true); + if (current_evidence < local_evidence_list.size()) { + evi_type f_evi = local_evidence_list.at(current_evidence); + if (current_evidence_global) { + QStringList f_contents; + f_contents.append(QString::number(current_evidence)); + f_contents.append(ui_evidence_name->text()); + f_contents.append(ui_evidence_description->toPlainText()); + f_contents.append(ui_evidence_image_name->text()); - ao_app->send_server_packet(new AOPacket("EE", f_contents)); + ao_app->send_server_packet(new AOPacket("EE", f_contents)); + } + else { + f_evi.name = ui_evidence_name->text(); + f_evi.description = ui_evidence_description->toPlainText(); + f_evi.image = ui_evidence_image_name->text(); + local_evidence_list.replace(current_evidence, f_evi); + private_evidence_list = local_evidence_list; + ui_evidence_ok->hide(); + set_evidence_page(); + } } - else - { - f_evi.name = ui_evidence_name->text(); - f_evi.description = ui_evidence_description->toPlainText(); - f_evi.image = ui_evidence_image_name->text(); - local_evidence_list.replace(current_evidence, f_evi); - private_evidence_list = local_evidence_list; - ui_evidence_ok->hide(); - set_evidence_page(); - } - } } void Courtroom::on_evidence_switch_clicked() { - evidence_close(); - evidence_switch(!current_evidence_global); - if (current_evidence_global) - { - ui_evidence_switch->set_image("evidence_global"); - ui_evidence->set_image("evidence_background"); - ui_evidence_overlay->set_image("evidence_overlay"); - ui_evidence_transfer->set_image("evidence_transfer"); - ui_evidence_transfer->setToolTip(tr("Transfer evidence to private inventory.")); - ui_evidence_switch->setToolTip(tr("Current evidence is global. Click to switch to private.")); - } - else - { - ui_evidence_switch->set_image("evidence_private"); - ui_evidence->set_image("evidence_background_private"); - ui_evidence_overlay->set_image("evidence_overlay_private"); - ui_evidence_transfer->set_image("evidence_transfer_private"); - ui_evidence_transfer->setToolTip(tr("Transfer evidence to global inventory.")); - ui_evidence_switch->setToolTip(tr("Current evidence is private. Click to switch to global.")); - } + evidence_close(); + evidence_switch(!current_evidence_global); + if (current_evidence_global) { + ui_evidence_switch->set_image("evidence_global"); + ui_evidence->set_image("evidence_background"); + ui_evidence_overlay->set_image("evidence_overlay"); + ui_evidence_transfer->set_image("evidence_transfer"); + ui_evidence_transfer->setToolTip(tr("Transfer evidence to private inventory.")); + ui_evidence_switch->setToolTip(tr("Current evidence is global. Click to switch to private.")); + } + else { + ui_evidence_switch->set_image("evidence_private"); + ui_evidence->set_image("evidence_background_private"); + ui_evidence_overlay->set_image("evidence_overlay_private"); + ui_evidence_transfer->set_image("evidence_transfer_private"); + ui_evidence_transfer->setToolTip(tr("Transfer evidence to global inventory.")); + ui_evidence_switch->setToolTip(tr("Current evidence is private. Click to switch to global.")); + } } void Courtroom::on_evidence_transfer_clicked() { - if (current_evidence >= local_evidence_list.size()) - return; + if (current_evidence >= local_evidence_list.size()) + return; - QString name; - if (!current_evidence_global) //Transfer private evidence to global - { - evi_type f_evi = local_evidence_list.at(current_evidence); + QString name; + if (!current_evidence_global) //Transfer private evidence to global + { + evi_type f_evi = local_evidence_list.at(current_evidence); - QStringList f_contents; - f_contents.append(f_evi.name); - f_contents.append(f_evi.description); - f_contents.append(f_evi.image); + QStringList f_contents; + f_contents.append(f_evi.name); + f_contents.append(f_evi.description); + f_contents.append(f_evi.image); - name = f_evi.name; - ao_app->send_server_packet(new AOPacket("PE", f_contents)); - } - else //Transfer global evidence to private - { - evi_type f_evi = local_evidence_list.at(current_evidence); - name = f_evi.name; - private_evidence_list.append(f_evi); - } + name = f_evi.name; + ao_app->send_server_packet(new AOPacket("PE", f_contents)); + } + else //Transfer global evidence to private + { + evi_type f_evi = local_evidence_list.at(current_evidence); + name = f_evi.name; + private_evidence_list.append(f_evi); + } - QMessageBox *msgBox = new QMessageBox; - msgBox->setText("\"" + name + "\" has been transferred."); - msgBox->setStandardButtons(QMessageBox::Ok); - msgBox->setDefaultButton(QMessageBox::Ok); - msgBox->exec(); + QMessageBox *msgBox = new QMessageBox; + msgBox->setText("\"" + name + "\" has been transferred."); + msgBox->setStandardButtons(QMessageBox::Ok); + msgBox->setDefaultButton(QMessageBox::Ok); + msgBox->exec(); } void Courtroom::on_evidence_edited() { - if (current_evidence >= local_evidence_list.size()) //Should never happen but you never know. - return; - evi_type fake_evidence; - fake_evidence.name = ui_evidence_name->text(); - fake_evidence.description = ui_evidence_description->toPlainText(); - fake_evidence.image = ui_evidence_image_name->text(); - if (compare_evidence_changed(fake_evidence, local_evidence_list.at(current_evidence))) - ui_evidence_ok->show(); - else - ui_evidence_ok->hide(); + if (current_evidence >= local_evidence_list.size()) //Should never happen but you never know. + return; + evi_type fake_evidence; + fake_evidence.name = ui_evidence_name->text(); + fake_evidence.description = ui_evidence_description->toPlainText(); + fake_evidence.image = ui_evidence_image_name->text(); + if (compare_evidence_changed(fake_evidence, local_evidence_list.at(current_evidence))) + ui_evidence_ok->show(); + else + ui_evidence_ok->hide(); } void Courtroom::evidence_close() { - ui_evidence_description->setReadOnly(true); - ui_evidence_description->setToolTip(""); - ui_evidence_name->setReadOnly(true); - ui_evidence_name->setToolTip(""); - ui_evidence_image_name->setReadOnly(true); - ui_evidence_image_name->setToolTip(""); - ui_evidence_overlay->hide(); - ui_ic_chat_message->setFocus(); + ui_evidence_description->setReadOnly(true); + ui_evidence_description->setToolTip(""); + ui_evidence_name->setReadOnly(true); + ui_evidence_name->setToolTip(""); + ui_evidence_image_name->setReadOnly(true); + ui_evidence_image_name->setToolTip(""); + ui_evidence_overlay->hide(); + ui_ic_chat_message->setFocus(); } void Courtroom::evidence_switch(bool global) { - current_evidence_global = global; - is_presenting_evidence = false; - ui_evidence_present->set_image("present"); - local_evidence_list.clear(); - if (current_evidence_global) - { - local_evidence_list = global_evidence_list; - ui_evidence_present->show(); - ui_evidence_save->hide(); - ui_evidence_load->hide(); - } - else - { - local_evidence_list = private_evidence_list; - ui_evidence_present->hide(); - ui_evidence_save->show(); - ui_evidence_load->show(); - } - set_evidence_page(); + current_evidence_global = global; + is_presenting_evidence = false; + ui_evidence_present->set_image("present"); + local_evidence_list.clear(); + if (current_evidence_global) { + local_evidence_list = global_evidence_list; + ui_evidence_present->show(); + ui_evidence_save->hide(); + ui_evidence_load->hide(); + } + else { + local_evidence_list = private_evidence_list; + ui_evidence_present->hide(); + ui_evidence_save->show(); + ui_evidence_load->show(); + } + set_evidence_page(); } void Courtroom::on_evidence_save_clicked() { - if (current_evidence_global) - return; //Don't allow saving/loading operations when in global inventory mode for now + if (current_evidence_global) + return; //Don't allow saving/loading operations when in global inventory mode for now - QString p_path = QFileDialog::getSaveFileName(this, tr("Save Inventory"), "base/inventories/", tr("Ini Files (*.ini)")); - if (p_path.isEmpty()) - return; + QString p_path = QFileDialog::getSaveFileName(this, tr("Save Inventory"), "base/inventories/", tr("Ini Files (*.ini)")); + if (p_path.isEmpty()) + return; - evidence_close(); - ui_evidence_name->setText(""); + evidence_close(); + ui_evidence_name->setText(""); - QSettings inventory(p_path, QSettings::IniFormat); - inventory.clear(); - for(int i = 0; i < local_evidence_list.size(); i++) - { - inventory.beginGroup(QString::number(i)); - inventory.setValue("name",local_evidence_list[i].name); - inventory.setValue("description",local_evidence_list[i].description); - inventory.setValue("image",local_evidence_list[i].image); - inventory.endGroup(); - } - inventory.sync(); + QSettings inventory(p_path, QSettings::IniFormat); + inventory.clear(); + for (int i = 0; i < local_evidence_list.size(); i++) { + inventory.beginGroup(QString::number(i)); + inventory.setValue("name", local_evidence_list[i].name); + inventory.setValue("description", local_evidence_list[i].description); + inventory.setValue("image", local_evidence_list[i].image); + inventory.endGroup(); + } + inventory.sync(); } void Courtroom::on_evidence_load_clicked() { - if (current_evidence_global) - return; //Don't allow saving/loading operations when in global inventory mode for now + if (current_evidence_global) + return; //Don't allow saving/loading operations when in global inventory mode for now - QString p_path = QFileDialog::getOpenFileName(this, tr("Open Inventory"), "base/inventories/", tr("Ini Files (*.ini)")); - if (p_path.isEmpty()) - return; + QString p_path = QFileDialog::getOpenFileName(this, tr("Open Inventory"), "base/inventories/", tr("Ini Files (*.ini)")); + if (p_path.isEmpty()) + return; - evidence_close(); - ui_evidence_name->setText(""); + evidence_close(); + ui_evidence_name->setText(""); - QSettings inventory(p_path, QSettings::IniFormat); - local_evidence_list.clear(); - foreach (QString evi, inventory.childGroups()) - { - if (evi == "General") - continue; + QSettings inventory(p_path, QSettings::IniFormat); + local_evidence_list.clear(); + foreach (QString evi, inventory.childGroups()) { + if (evi == "General") + continue; - evi_type f_evi; - f_evi.name = inventory.value(evi + "/name", "UNKNOWN").value(); - f_evi.description = inventory.value(evi + "/description", "UNKNOWN").value(); - f_evi.image = inventory.value(evi + "/image", "UNKNOWN.png").value(); - local_evidence_list.append(f_evi); - } - private_evidence_list = local_evidence_list; - set_evidence_page(); + evi_type f_evi; + f_evi.name = inventory.value(evi + "/name", "UNKNOWN").value(); + f_evi.description = inventory.value(evi + "/description", "UNKNOWN").value(); + f_evi.image = inventory.value(evi + "/image", "UNKNOWN.png").value(); + local_evidence_list.append(f_evi); + } + private_evidence_list = local_evidence_list; + set_evidence_page(); } bool Courtroom::compare_evidence_changed(evi_type evi_a, evi_type evi_b) { - return evi_a.name != evi_b.name || evi_a.image != evi_b.image || evi_a.description != evi_b.description; + return evi_a.name != evi_b.name || evi_a.image != evi_b.image || evi_a.description != evi_b.description; } diff --git a/src/file_functions.cpp b/src/file_functions.cpp index f93ee15..e2b2882 100644 --- a/src/file_functions.cpp +++ b/src/file_functions.cpp @@ -2,20 +2,21 @@ bool file_exists(QString file_path) { - QFileInfo check_file(file_path); + QFileInfo check_file(file_path); - return check_file.exists() && check_file.isFile(); + return check_file.exists() && check_file.isFile(); } bool dir_exists(QString dir_path) { - QDir check_dir(dir_path); + QDir check_dir(dir_path); - return check_dir.exists(); + return check_dir.exists(); } -bool exists(QString p_path) { - QFile file(p_path); +bool exists(QString p_path) +{ + QFile file(p_path); - return file.exists(); + return file.exists(); } diff --git a/src/hardware_functions.cpp b/src/hardware_functions.cpp index bd6a6c3..21d72ec 100644 --- a/src/hardware_functions.cpp +++ b/src/hardware_functions.cpp @@ -2,7 +2,7 @@ #include -#if (defined (_WIN32) || defined (_WIN64)) +#if (defined(_WIN32) || defined(_WIN64)) #include static DWORD dwVolSerial; @@ -10,43 +10,41 @@ static BOOL bIsRetrieved; QString get_hdid() { - bIsRetrieved = GetVolumeInformation(TEXT("C:\\"), nullptr, 0, &dwVolSerial, nullptr, nullptr, nullptr, 0); + bIsRetrieved = GetVolumeInformation(TEXT("C:\\"), nullptr, 0, &dwVolSerial, nullptr, nullptr, nullptr, 0); - if (bIsRetrieved) - return QString::number(dwVolSerial, 16); - else - //a totally random string - //what could possibly go wrong - return "gxsps32sa9fnwic92mfbs0"; + if (bIsRetrieved) + return QString::number(dwVolSerial, 16); + else + //a totally random string + //what could possibly go wrong + return "gxsps32sa9fnwic92mfbs0"; } -#elif (defined (LINUX) || defined (__linux__)) +#elif (defined(LINUX) || defined(__linux__)) #include #include QString get_hdid() { - QFile fstab_file("/etc/fstab"); - if (!fstab_file.open(QIODevice::ReadOnly)) - return "gxcps32sa9fnwic92mfbs0"; + QFile fstab_file("/etc/fstab"); + if (!fstab_file.open(QIODevice::ReadOnly)) + return "gxcps32sa9fnwic92mfbs0"; - QTextStream in(&fstab_file); + QTextStream in(&fstab_file); - while(!in.atEnd()) - { - QString line = in.readLine(); + while (!in.atEnd()) { + QString line = in.readLine(); - if (line.startsWith("UUID")) - { - QStringList line_elements = line.split("="); + if (line.startsWith("UUID")) { + QStringList line_elements = line.split("="); - if (line_elements.size() > 1) - return line_elements.at(1).left(23).trimmed(); + if (line_elements.size() > 1) + return line_elements.at(1).left(23).trimmed(); + } } - } - return "gxcpz32sa9fnwic92mfbs0"; + return "gxcpz32sa9fnwic92mfbs0"; } #elif defined __APPLE__ @@ -56,25 +54,24 @@ QString get_hdid() QString get_hdid() { CFStringRef serial; - char buffer[64] = {0}; - QString hdid; - io_service_t platformExpert = IOServiceGetMatchingService(kIOMasterPortDefault, + char buffer[64] = {0}; + QString hdid; + io_service_t platformExpert = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice")); - if (platformExpert) - { - CFTypeRef serialNumberAsCFString = IORegistryEntryCreateCFProperty(platformExpert, + if (platformExpert) { + CFTypeRef serialNumberAsCFString = IORegistryEntryCreateCFProperty(platformExpert, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0); - if (serialNumberAsCFString) { - serial = (CFStringRef)serialNumberAsCFString; - } - if (CFStringGetCString(serial, buffer, 64, kCFStringEncodingUTF8)) { - hdid = buffer; - } - - IOObjectRelease(platformExpert); + if (serialNumberAsCFString) { + serial = (CFStringRef)serialNumberAsCFString; } - return hdid; + if (CFStringGetCString(serial, buffer, 64, kCFStringEncodingUTF8)) { + hdid = buffer; + } + + IOObjectRelease(platformExpert); + } + return hdid; } #else diff --git a/src/hex_functions.cpp b/src/hex_functions.cpp index 4a58d2b..63293c1 100644 --- a/src/hex_functions.cpp +++ b/src/hex_functions.cpp @@ -1,18 +1,17 @@ #include "hex_functions.h" -namespace omni -{ - std::string int_to_hex(unsigned int input) - { - if (input > 255) - return "FF"; +namespace omni { + std::string int_to_hex(unsigned int input) + { + if (input > 255) + return "FF"; - std::stringstream stream; - stream << std::setfill('0') << std::setw(sizeof(char)*2) - << std::hex << input; - std::string result(stream.str()); - std::transform(result.begin(), result.end(), result.begin(), ::toupper); + std::stringstream stream; + stream << std::setfill('0') << std::setw(sizeof(char) * 2) + << std::hex << input; + std::string result(stream.str()); + std::transform(result.begin(), result.end(), result.begin(), ::toupper); - return result; - } -} + return result; + } +} // namespace omni diff --git a/src/lobby.cpp b/src/lobby.cpp index 19bb4c6..30a8ed0 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -1,198 +1,193 @@ #include "lobby.h" -#include "debug_functions.h" #include "aoapplication.h" -#include "networkmanager.h" #include "aosfxplayer.h" +#include "debug_functions.h" +#include "networkmanager.h" Lobby::Lobby(AOApplication *p_ao_app) : QMainWindow() { - ao_app = p_ao_app; + ao_app = p_ao_app; - this->setWindowTitle(tr("Attorney Online 2")); - this->setWindowIcon(QIcon(":/logo.png")); + this->setWindowTitle(tr("Attorney Online 2")); + this->setWindowIcon(QIcon(":/logo.png")); - ui_background = new AOImage(this, ao_app); - ui_public_servers = new AOButton(this, ao_app); - ui_favorites = new AOButton(this, ao_app); - ui_refresh = new AOButton(this, ao_app); - ui_add_to_fav = new AOButton(this, ao_app); - ui_connect = new AOButton(this, ao_app); - ui_version = new QLabel(this); - ui_about = new AOButton(this, ao_app); - ui_settings = new AOButton(this, ao_app); + ui_background = new AOImage(this, ao_app); + ui_public_servers = new AOButton(this, ao_app); + ui_favorites = new AOButton(this, ao_app); + ui_refresh = new AOButton(this, ao_app); + ui_add_to_fav = new AOButton(this, ao_app); + ui_connect = new AOButton(this, ao_app); + ui_version = new QLabel(this); + ui_about = new AOButton(this, ao_app); + ui_settings = new AOButton(this, ao_app); - ui_server_list = new QTreeWidget(this); - ui_server_list->setHeaderLabels({"#", "Name"});//, "Players"}); - ui_server_list->hideColumn(0); + ui_server_list = new QTreeWidget(this); + ui_server_list->setHeaderLabels({"#", "Name"}); //, "Players"}); + ui_server_list->hideColumn(0); - ui_server_search = new QLineEdit(this); - ui_server_search->setFrame(false); - ui_server_search->setPlaceholderText(tr("Search")); + ui_server_search = new QLineEdit(this); + ui_server_search->setFrame(false); + ui_server_search->setPlaceholderText(tr("Search")); - ui_player_count = new QLabel(this); - ui_description = new AOTextArea(this); - ui_description->setOpenExternalLinks(true); - ui_chatbox = new AOTextArea(this); - ui_chatbox->setOpenExternalLinks(true); - ui_chatname = new QLineEdit(this); - ui_chatname->setPlaceholderText(tr("Name")); - ui_chatname->setText(ao_app->get_ooc_name()); - ui_chatmessage = new QLineEdit(this); - ui_loading_background = new AOImage(this, ao_app); - ui_loading_text = new QTextEdit(ui_loading_background); - ui_progress_bar = new QProgressBar(ui_loading_background); - ui_progress_bar->setMinimum(0); - ui_progress_bar->setMaximum(100); - ui_progress_bar->setStyleSheet("QProgressBar{ color: white; }"); - ui_cancel = new AOButton(ui_loading_background, ao_app); + ui_player_count = new QLabel(this); + ui_description = new AOTextArea(this); + ui_description->setOpenExternalLinks(true); + ui_chatbox = new AOTextArea(this); + ui_chatbox->setOpenExternalLinks(true); + ui_chatname = new QLineEdit(this); + ui_chatname->setPlaceholderText(tr("Name")); + ui_chatname->setText(ao_app->get_ooc_name()); + ui_chatmessage = new QLineEdit(this); + ui_loading_background = new AOImage(this, ao_app); + ui_loading_text = new QTextEdit(ui_loading_background); + ui_progress_bar = new QProgressBar(ui_loading_background); + ui_progress_bar->setMinimum(0); + ui_progress_bar->setMaximum(100); + ui_progress_bar->setStyleSheet("QProgressBar{ color: white; }"); + ui_cancel = new AOButton(ui_loading_background, ao_app); - connect(ui_public_servers, SIGNAL(clicked()), this, SLOT(on_public_servers_clicked())); - connect(ui_favorites, SIGNAL(clicked()), this, SLOT(on_favorites_clicked())); - connect(ui_refresh, SIGNAL(pressed()), this, SLOT(on_refresh_pressed())); - connect(ui_refresh, SIGNAL(released()), this, SLOT(on_refresh_released())); - connect(ui_add_to_fav, SIGNAL(pressed()), this, SLOT(on_add_to_fav_pressed())); - connect(ui_add_to_fav, SIGNAL(released()), this, SLOT(on_add_to_fav_released())); - connect(ui_connect, SIGNAL(pressed()), this, SLOT(on_connect_pressed())); - connect(ui_connect, SIGNAL(released()), this, SLOT(on_connect_released())); - connect(ui_about, SIGNAL(clicked()), this, SLOT(on_about_clicked())); - connect(ui_settings, SIGNAL(clicked()), this, SLOT(on_settings_clicked())); - connect(ui_server_list, SIGNAL(itemClicked(QTreeWidgetItem*, int)), this, SLOT(on_server_list_clicked(QTreeWidgetItem*, int))); - connect(ui_server_list, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this, SLOT(on_server_list_doubleclicked(QTreeWidgetItem*, int))); - connect(ui_server_search, SIGNAL(textChanged(QString)), this, SLOT(on_server_search_edited(QString))); - connect(ui_chatmessage, SIGNAL(returnPressed()), this, SLOT(on_chatfield_return_pressed())); - connect(ui_cancel, SIGNAL(clicked()), ao_app, SLOT(loading_cancelled())); + connect(ui_public_servers, SIGNAL(clicked()), this, SLOT(on_public_servers_clicked())); + connect(ui_favorites, SIGNAL(clicked()), this, SLOT(on_favorites_clicked())); + connect(ui_refresh, SIGNAL(pressed()), this, SLOT(on_refresh_pressed())); + connect(ui_refresh, SIGNAL(released()), this, SLOT(on_refresh_released())); + connect(ui_add_to_fav, SIGNAL(pressed()), this, SLOT(on_add_to_fav_pressed())); + connect(ui_add_to_fav, SIGNAL(released()), this, SLOT(on_add_to_fav_released())); + connect(ui_connect, SIGNAL(pressed()), this, SLOT(on_connect_pressed())); + connect(ui_connect, SIGNAL(released()), this, SLOT(on_connect_released())); + connect(ui_about, SIGNAL(clicked()), this, SLOT(on_about_clicked())); + connect(ui_settings, SIGNAL(clicked()), this, SLOT(on_settings_clicked())); + connect(ui_server_list, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, SLOT(on_server_list_clicked(QTreeWidgetItem *, int))); + connect(ui_server_list, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), this, SLOT(on_server_list_doubleclicked(QTreeWidgetItem *, int))); + connect(ui_server_search, SIGNAL(textChanged(QString)), this, SLOT(on_server_search_edited(QString))); + connect(ui_chatmessage, SIGNAL(returnPressed()), this, SLOT(on_chatfield_return_pressed())); + connect(ui_cancel, SIGNAL(clicked()), ao_app, SLOT(loading_cancelled())); - ui_connect->setEnabled(false); + ui_connect->setEnabled(false); - list_servers(); + list_servers(); - set_widgets(); + set_widgets(); } //sets images, position and size void Lobby::set_widgets() { - ao_app->reload_theme(); + ao_app->reload_theme(); - QString filename = "lobby_design.ini"; + QString filename = "lobby_design.ini"; - pos_size_type f_lobby = ao_app->get_element_dimensions("lobby", filename); + pos_size_type f_lobby = ao_app->get_element_dimensions("lobby", filename); - if (f_lobby.width < 0 || f_lobby.height < 0) - { - qDebug() << "W: did not find lobby width or height in " << filename; + if (f_lobby.width < 0 || f_lobby.height < 0) { + qDebug() << "W: did not find lobby width or height in " << filename; - // Most common symptom of bad config files and missing assets. - call_notice(tr("It doesn't look like your client is set up correctly.\n" - "Did you download all resources correctly from tiny.cc/getao, " - "including the large 'base' folder?")); + // Most common symptom of bad config files and missing assets. + call_notice(tr("It doesn't look like your client is set up correctly.\n" + "Did you download all resources correctly from tiny.cc/getao, " + "including the large 'base' folder?")); - this->resize(517, 666); - } - else - { - this->resize(f_lobby.width, f_lobby.height); - } + this->resize(517, 666); + } + else { + this->resize(f_lobby.width, f_lobby.height); + } - set_size_and_pos(ui_background, "lobby"); - ui_background->set_image("lobbybackground"); + set_size_and_pos(ui_background, "lobby"); + ui_background->set_image("lobbybackground"); - set_size_and_pos(ui_public_servers, "public_servers"); - ui_public_servers->set_image("publicservers_selected"); + set_size_and_pos(ui_public_servers, "public_servers"); + ui_public_servers->set_image("publicservers_selected"); - set_size_and_pos(ui_favorites, "favorites"); - ui_favorites->set_image("favorites"); + set_size_and_pos(ui_favorites, "favorites"); + ui_favorites->set_image("favorites"); - set_size_and_pos(ui_refresh, "refresh"); - ui_refresh->set_image("refresh"); + set_size_and_pos(ui_refresh, "refresh"); + ui_refresh->set_image("refresh"); - set_size_and_pos(ui_add_to_fav, "add_to_fav"); - ui_add_to_fav->set_image("addtofav"); + set_size_and_pos(ui_add_to_fav, "add_to_fav"); + ui_add_to_fav->set_image("addtofav"); - set_size_and_pos(ui_connect, "connect"); - ui_connect->set_image("connect"); + set_size_and_pos(ui_connect, "connect"); + ui_connect->set_image("connect"); - set_size_and_pos(ui_version, "version"); - ui_version->setText(tr("Version: KFO%1").arg(ao_app->get_version_string())); + set_size_and_pos(ui_version, "version"); + ui_version->setText(tr("Version: KFO%1").arg(ao_app->get_version_string())); - set_size_and_pos(ui_about, "about"); - ui_about->set_image("about"); + set_size_and_pos(ui_about, "about"); + ui_about->set_image("about"); - set_size_and_pos(ui_settings, "settings"); - ui_settings->setText(tr("Settings")); - ui_settings->set_image("settings"); - ui_settings->setToolTip(tr("Allows you to change various aspects of the client.")); + set_size_and_pos(ui_settings, "settings"); + ui_settings->setText(tr("Settings")); + ui_settings->set_image("settings"); + ui_settings->setToolTip(tr("Allows you to change various aspects of the client.")); - set_size_and_pos(ui_server_list, "server_list"); - ui_server_list->setStyleSheet("background-color: rgba(0, 0, 0, 0);" + set_size_and_pos(ui_server_list, "server_list"); + ui_server_list->setStyleSheet("background-color: rgba(0, 0, 0, 0);" "font: bold;"); - set_size_and_pos(ui_server_search, "server_search"); - ui_server_search->setStyleSheet("background-color: rgba(0, 0, 0, 0);"); + set_size_and_pos(ui_server_search, "server_search"); + ui_server_search->setStyleSheet("background-color: rgba(0, 0, 0, 0);"); - set_size_and_pos(ui_player_count, "player_count"); - ui_player_count->setText(tr("Offline")); - ui_player_count->setStyleSheet("font: bold;" - "color: white;" - "qproperty-alignment: AlignCenter;"); + set_size_and_pos(ui_player_count, "player_count"); + ui_player_count->setText(tr("Offline")); + ui_player_count->setStyleSheet("font: bold;" + "color: white;" + "qproperty-alignment: AlignCenter;"); - set_size_and_pos(ui_description, "description"); - ui_description->setReadOnly(true); - ui_description->setStyleSheet("background-color: rgba(0, 0, 0, 0);" - "color: white;"); + set_size_and_pos(ui_description, "description"); + ui_description->setReadOnly(true); + ui_description->setStyleSheet("background-color: rgba(0, 0, 0, 0);" + "color: white;"); - set_size_and_pos(ui_chatbox, "chatbox"); - ui_chatbox->setReadOnly(true); - ui_chatbox->setStyleSheet("QTextBrowser{background-color: rgba(0, 0, 0, 0);}"); + set_size_and_pos(ui_chatbox, "chatbox"); + ui_chatbox->setReadOnly(true); + ui_chatbox->setStyleSheet("QTextBrowser{background-color: rgba(0, 0, 0, 0);}"); - set_size_and_pos(ui_chatname, "chatname"); - ui_chatname->setStyleSheet("background-color: rgba(0, 0, 0, 0);" - "selection-background-color: rgba(0, 0, 0, 0);"); + set_size_and_pos(ui_chatname, "chatname"); + ui_chatname->setStyleSheet("background-color: rgba(0, 0, 0, 0);" + "selection-background-color: rgba(0, 0, 0, 0);"); - set_size_and_pos(ui_chatmessage, "chatmessage"); - ui_chatmessage->setStyleSheet("background-color: rgba(0, 0, 0, 0);" - "selection-background-color: rgba(0, 0, 0, 0);"); + set_size_and_pos(ui_chatmessage, "chatmessage"); + ui_chatmessage->setStyleSheet("background-color: rgba(0, 0, 0, 0);" + "selection-background-color: rgba(0, 0, 0, 0);"); - ui_loading_background->resize(this->width(), this->height()); - ui_loading_background->set_image("loadingbackground"); + ui_loading_background->resize(this->width(), this->height()); + ui_loading_background->set_image("loadingbackground"); + set_size_and_pos(ui_loading_text, "loading_label"); + ui_loading_text->setFont(QFont("Arial", 20, QFont::Bold)); + ui_loading_text->setReadOnly(true); + ui_loading_text->setAlignment(Qt::AlignCenter); + ui_loading_text->setFrameStyle(QFrame::NoFrame); + ui_loading_text->setStyleSheet("background-color: rgba(0, 0, 0, 0);" + "color: rgba(255, 128, 0, 255);"); + ui_loading_text->append(tr("Loading")); - set_size_and_pos(ui_loading_text, "loading_label"); - ui_loading_text->setFont(QFont("Arial", 20, QFont::Bold)); - ui_loading_text->setReadOnly(true); - ui_loading_text->setAlignment(Qt::AlignCenter); - ui_loading_text->setFrameStyle(QFrame::NoFrame); - ui_loading_text->setStyleSheet("background-color: rgba(0, 0, 0, 0);" - "color: rgba(255, 128, 0, 255);"); - ui_loading_text->append(tr("Loading")); + set_size_and_pos(ui_progress_bar, "progress_bar"); + set_size_and_pos(ui_cancel, "cancel"); + ui_cancel->setText(tr("Cancel")); - set_size_and_pos(ui_progress_bar, "progress_bar"); - set_size_and_pos(ui_cancel, "cancel"); - ui_cancel->setText(tr("Cancel")); + ui_loading_background->hide(); - ui_loading_background->hide(); - - set_fonts(); - set_stylesheets(); + set_fonts(); + set_stylesheets(); } void Lobby::set_size_and_pos(QWidget *p_widget, QString p_identifier) { - QString filename = "lobby_design.ini"; + QString filename = "lobby_design.ini"; - pos_size_type design_ini_result = ao_app->get_element_dimensions(p_identifier, filename); + pos_size_type design_ini_result = ao_app->get_element_dimensions(p_identifier, filename); - if (design_ini_result.width < 0 || design_ini_result.height < 0) - { - qDebug() << "W: could not find " << p_identifier << " in " << filename; - p_widget->hide(); - } - else - { - p_widget->move(design_ini_result.x, design_ini_result.y); - p_widget->resize(design_ini_result.width, design_ini_result.height); - } + if (design_ini_result.width < 0 || design_ini_result.height < 0) { + qDebug() << "W: could not find " << p_identifier << " in " << filename; + p_widget->hide(); + } + else { + p_widget->move(design_ini_result.x, design_ini_result.y); + p_widget->resize(design_ini_result.width, design_ini_result.height); + } } void Lobby::set_fonts() @@ -208,169 +203,170 @@ void Lobby::set_fonts() void Lobby::set_stylesheet(QWidget *widget, QString target_tag) { - QString f_file = "lobby_stylesheets.css"; - QString style_sheet_string = ao_app->get_tagged_stylesheet(target_tag, f_file); - if (style_sheet_string != "") - widget->setStyleSheet(style_sheet_string); + QString f_file = "lobby_stylesheets.css"; + QString style_sheet_string = ao_app->get_tagged_stylesheet(target_tag, f_file); + if (style_sheet_string != "") + widget->setStyleSheet(style_sheet_string); } void Lobby::set_stylesheets() { - set_stylesheet(ui_player_count, "[PLAYER COUNT]"); - set_stylesheet(ui_description, "[DESCRIPTION]"); - set_stylesheet(ui_chatbox, "[CHAT BOX]"); - set_stylesheet(ui_chatname, "[CHAT NAME]"); - set_stylesheet(ui_chatmessage, "[CHAT MESSAGE]"); - set_stylesheet(ui_loading_text, "[LOADING TEXT]"); - set_stylesheet(ui_server_list, "[SERVER LIST]"); + set_stylesheet(ui_player_count, "[PLAYER COUNT]"); + set_stylesheet(ui_description, "[DESCRIPTION]"); + set_stylesheet(ui_chatbox, "[CHAT BOX]"); + set_stylesheet(ui_chatname, "[CHAT NAME]"); + set_stylesheet(ui_chatmessage, "[CHAT MESSAGE]"); + set_stylesheet(ui_loading_text, "[LOADING TEXT]"); + set_stylesheet(ui_server_list, "[SERVER LIST]"); } void Lobby::set_font(QWidget *widget, QString p_identifier) { - QString design_file = "lobby_fonts.ini"; - 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("font_" + p_identifier, design_file); - QFont font(font_name, f_weight); - bool use = ao_app->get_font_size("use_custom_fonts", design_file) == 1; - if(use) - { - widget->setFont(font); - QColor f_color = ao_app->get_color(p_identifier + "_color", design_file); - bool bold = ao_app->get_font_size(p_identifier + "_bold", design_file) == 1; // is the font bold or not? - bool center = ao_app->get_font_size(p_identifier + "_center", design_file) == 1; // should it be centered? - QString is_bold = ""; - if(bold) is_bold = "bold"; - QString is_center = ""; - if(center) is_center = "qproperty-alignment: AlignCenter;"; - QString style_sheet_string = class_name + " { background-color: rgba(0, 0, 0, 0);\n" + - "color: rgba(" + - QString::number(f_color.red()) + ", " + - QString::number(f_color.green()) + ", " + - QString::number(f_color.blue()) + ", 255);\n" + - is_center + "\n" + - "font: " + is_bold + "; }"; - widget->setStyleSheet(style_sheet_string); - } - return; + QString design_file = "lobby_fonts.ini"; + 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("font_" + p_identifier, design_file); + QFont font(font_name, f_weight); + bool use = ao_app->get_font_size("use_custom_fonts", design_file) == 1; + if (use) { + widget->setFont(font); + QColor f_color = ao_app->get_color(p_identifier + "_color", design_file); + bool bold = ao_app->get_font_size(p_identifier + "_bold", design_file) == 1; // is the font bold or not? + bool center = ao_app->get_font_size(p_identifier + "_center", design_file) == 1; // should it be centered? + QString is_bold = ""; + if (bold) + is_bold = "bold"; + QString is_center = ""; + if (center) + is_center = "qproperty-alignment: AlignCenter;"; + QString style_sheet_string = class_name + " { background-color: rgba(0, 0, 0, 0);\n" + + "color: rgba(" + + QString::number(f_color.red()) + ", " + + QString::number(f_color.green()) + ", " + + QString::number(f_color.blue()) + ", 255);\n" + + is_center + "\n" + + "font: " + is_bold + "; }"; + widget->setStyleSheet(style_sheet_string); + } + return; } void Lobby::set_loading_text(QString p_text) { - ui_loading_text->clear(); - ui_loading_text->setAlignment(Qt::AlignCenter); - ui_loading_text->append(p_text); + ui_loading_text->clear(); + ui_loading_text->setAlignment(Qt::AlignCenter); + ui_loading_text->append(p_text); } QString Lobby::get_chatlog() { - QString return_value = ui_chatbox->toPlainText(); + QString return_value = ui_chatbox->toPlainText(); - return return_value; + return return_value; } int Lobby::get_selected_server() { - return ui_server_list->currentItem()->text(0).toInt(); + return ui_server_list->currentItem()->text(0).toInt(); } void Lobby::set_loading_value(int p_value) { - ui_progress_bar->setValue(p_value); + ui_progress_bar->setValue(p_value); } void Lobby::on_public_servers_clicked() { - ui_public_servers->set_image("publicservers_selected"); - ui_favorites->set_image("favorites"); + ui_public_servers->set_image("publicservers_selected"); + ui_favorites->set_image("favorites"); - list_servers(); + list_servers(); - public_servers_selected = true; + public_servers_selected = true; } void Lobby::on_favorites_clicked() { - ui_favorites->set_image("favorites_selected"); - ui_public_servers->set_image("publicservers"); + ui_favorites->set_image("favorites_selected"); + ui_public_servers->set_image("publicservers"); - ao_app->set_favorite_list(); - //ao_app->favorite_list = read_serverlist_txt(); + ao_app->set_favorite_list(); + //ao_app->favorite_list = read_serverlist_txt(); - list_favorites(); + list_favorites(); - public_servers_selected = false; + public_servers_selected = false; } void Lobby::on_refresh_pressed() { - ui_refresh->set_image("refresh_pressed"); + ui_refresh->set_image("refresh_pressed"); } void Lobby::on_refresh_released() { - ui_refresh->set_image("refresh"); + ui_refresh->set_image("refresh"); - AOPacket *f_packet = new AOPacket("ALL#%"); + AOPacket *f_packet = new AOPacket("ALL#%"); - ao_app->send_ms_packet(f_packet); + ao_app->send_ms_packet(f_packet); } void Lobby::on_add_to_fav_pressed() { - ui_add_to_fav->set_image("addtofav_pressed"); + ui_add_to_fav->set_image("addtofav_pressed"); } void Lobby::on_add_to_fav_released() { - ui_add_to_fav->set_image("addtofav"); + ui_add_to_fav->set_image("addtofav"); - //you cant add favorites from favorites m8 - if (!public_servers_selected) - return; + //you cant add favorites from favorites m8 + if (!public_servers_selected) + return; - ao_app->add_favorite_server(get_selected_server()); + ao_app->add_favorite_server(get_selected_server()); } void Lobby::on_connect_pressed() { - ui_connect->set_image("connect_pressed"); + ui_connect->set_image("connect_pressed"); } void Lobby::on_connect_released() { - ui_connect->set_image("connect"); + ui_connect->set_image("connect"); - AOPacket *f_packet; + AOPacket *f_packet; - f_packet = new AOPacket("askchaa#%"); + f_packet = new AOPacket("askchaa#%"); - ao_app->send_server_packet(f_packet); + ao_app->send_server_packet(f_packet); } void Lobby::on_about_clicked() { - QString msg = tr("

Attorney Online %1

" - "The courtroom drama simulator" - "

Source code: " - "" - "https://github.com/AttorneyOnline/AO2-Client" - "

Major development:
" - "OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter" - "

2.8 Major Release development:
" - "Crystalwarrior, Iamgoofball" - "

2.8 Quality Assurance:
" - "WillDean, Captain N, Mr M, Riel, Seimmet, Fury McFlurry," - "CedricDewitt, Chewable Tablets, Fantos, Futugaze," - "Geck, Minx, Pandae, Sierra, CrazyJC, CaseyMayCazy," - "GreenBowers, Robotic Overlord, Veritas, Gin-Gi" - "

Special thanks:
" - "Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), " - "Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, " - "Noevain, Cronnicossy, the AO2 community, server hosts, game masters," - "case makers, content creators and players!") - .arg(ao_app->get_version_string()); - QMessageBox::about(this, "About", msg); + QString msg = tr("

Attorney Online %1

" + "The courtroom drama simulator" + "

Source code: " + "" + "https://github.com/AttorneyOnline/AO2-Client" + "

Major development:
" + "OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter" + "

2.8 Major Release development:
" + "Crystalwarrior, Iamgoofball" + "

2.8 Quality Assurance:
" + "WillDean, Captain N, Mr M, Riel, Seimmet, Fury McFlurry," + "CedricDewitt, Chewable Tablets, Fantos, Futugaze," + "Geck, Minx, Pandae, Sierra, CrazyJC, CaseyMayCazy," + "GreenBowers, Robotic Overlord, Veritas, Gin-Gi" + "

Special thanks:
" + "Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), " + "Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, " + "Noevain, Cronnicossy, the AO2 community, server hosts, game masters," + "case makers, content creators and players!") + .arg(ao_app->get_version_string()); + QMessageBox::about(this, "About", msg); } void Lobby::on_settings_clicked() @@ -379,51 +375,48 @@ void Lobby::on_settings_clicked() } //clicked on an item in the serverlist -void Lobby::on_server_list_clicked(QTreeWidgetItem* p_item, int column) +void Lobby::on_server_list_clicked(QTreeWidgetItem *p_item, int column) { - column = 0; - if (p_item->text(column).toInt() != last_index) - { - server_type f_server; - int n_server = p_item->text(column).toInt(); - last_index = n_server; + column = 0; + if (p_item->text(column).toInt() != last_index) { + server_type f_server; + int n_server = p_item->text(column).toInt(); + last_index = n_server; - if (n_server < 0) - return; + if (n_server < 0) + return; - if (public_servers_selected) - { - QVector f_server_list = ao_app->get_server_list(); + if (public_servers_selected) { + QVector f_server_list = ao_app->get_server_list(); - if (n_server >= f_server_list.size()) - return; + if (n_server >= f_server_list.size()) + return; - f_server = f_server_list.at(n_server); + f_server = f_server_list.at(n_server); + } + else { + if (n_server >= ao_app->get_favorite_list().size()) + return; + + f_server = ao_app->get_favorite_list().at(n_server); + } + + ui_description->clear(); + ui_description->append_linked(f_server.desc); + + ui_description->moveCursor(QTextCursor::Start); + ui_description->ensureCursorVisible(); + + ui_player_count->setText(tr("Offline")); + + ui_connect->setEnabled(false); + + ao_app->net_manager->connect_to_server(f_server); } - else - { - if (n_server >= ao_app->get_favorite_list().size()) - return; - - f_server = ao_app->get_favorite_list().at(n_server); - } - - ui_description->clear(); - ui_description->append_linked(f_server.desc); - - ui_description->moveCursor(QTextCursor::Start); - ui_description->ensureCursorVisible(); - - ui_player_count->setText(tr("Offline")); - - ui_connect->setEnabled(false); - - ao_app->net_manager->connect_to_server(f_server); - } } //doubleclicked on an item in the serverlist so we'll connect right away -void Lobby::on_server_list_doubleclicked(QTreeWidgetItem* p_item, int column) +void Lobby::on_server_list_doubleclicked(QTreeWidgetItem *p_item, int column) { on_server_list_clicked(p_item, column); on_connect_released(); @@ -431,106 +424,98 @@ void Lobby::on_server_list_doubleclicked(QTreeWidgetItem* p_item, int column) void Lobby::on_server_search_edited(QString p_text) { - // Iterate through all QTreeWidgetItem items - QTreeWidgetItemIterator it(ui_server_list); - while (*it) - { - (*it)->setHidden(p_text != ""); - ++it; - } - - if (p_text != "") - { - //Search in metadata - QList clist = ui_server_list->findItems(ui_server_search->text(), Qt::MatchContains|Qt::MatchRecursive, 1); - foreach(QTreeWidgetItem* item, clist) - { - if (item->parent() != nullptr) //So the category shows up too - item->parent()->setHidden(false); - item->setHidden(false); + // Iterate through all QTreeWidgetItem items + QTreeWidgetItemIterator it(ui_server_list); + while (*it) { + (*it)->setHidden(p_text != ""); + ++it; } - } -} + if (p_text != "") { + //Search in metadata + QList clist = ui_server_list->findItems(ui_server_search->text(), Qt::MatchContains | Qt::MatchRecursive, 1); + foreach (QTreeWidgetItem *item, clist) { + if (item->parent() != nullptr) //So the category shows up too + item->parent()->setHidden(false); + item->setHidden(false); + } + } +} void Lobby::on_chatfield_return_pressed() { - //no you can't send empty messages - if (ui_chatname->text() == "" || ui_chatmessage->text() == "") - return; + //no you can't send empty messages + if (ui_chatname->text() == "" || ui_chatmessage->text() == "") + return; + QString f_header = "CT"; + QStringList f_contents{ui_chatname->text(), ui_chatmessage->text()}; - QString f_header = "CT"; - QStringList f_contents{ui_chatname->text(), ui_chatmessage->text()}; + AOPacket *f_packet = new AOPacket(f_header, f_contents); - AOPacket *f_packet = new AOPacket(f_header, f_contents); + ao_app->send_ms_packet(f_packet); - ao_app->send_ms_packet(f_packet); - - ui_chatmessage->clear(); + ui_chatmessage->clear(); } void Lobby::list_servers() { - public_servers_selected = true; - ui_favorites->set_image("favorites"); - ui_public_servers->set_image("publicservers_selected"); + public_servers_selected = true; + ui_favorites->set_image("favorites"); + ui_public_servers->set_image("publicservers_selected"); - ui_server_list->setSortingEnabled(false); - ui_server_list->clear(); + ui_server_list->setSortingEnabled(false); + ui_server_list->clear(); - ui_server_search->setText(""); + ui_server_search->setText(""); - int i = 0; - for (server_type i_server : ao_app->get_server_list()) - { - QTreeWidgetItem *treeItem = new QTreeWidgetItem(ui_server_list); - treeItem->setText(0, QString::number(i)); - treeItem->setText(1, i_server.name); - i++; - } - ui_server_list->setSortingEnabled(true); + int i = 0; + for (server_type i_server : ao_app->get_server_list()) { + QTreeWidgetItem *treeItem = new QTreeWidgetItem(ui_server_list); + treeItem->setText(0, QString::number(i)); + treeItem->setText(1, i_server.name); + i++; + } + ui_server_list->setSortingEnabled(true); } void Lobby::list_favorites() { - ui_server_list->setSortingEnabled(false); - ui_server_list->clear(); + ui_server_list->setSortingEnabled(false); + ui_server_list->clear(); - int i = 0; - for (server_type i_server : ao_app->get_favorite_list()) - { - QTreeWidgetItem *treeItem = new QTreeWidgetItem(ui_server_list); - treeItem->setText(0, QString::number(i)); - treeItem->setText(1, i_server.name); -// treeItem->setText(2, "-"); - i++; - } - ui_server_list->setSortingEnabled(true); + int i = 0; + for (server_type i_server : ao_app->get_favorite_list()) { + QTreeWidgetItem *treeItem = new QTreeWidgetItem(ui_server_list); + treeItem->setText(0, QString::number(i)); + treeItem->setText(1, i_server.name); + // treeItem->setText(2, "-"); + i++; + } + ui_server_list->setSortingEnabled(true); } void Lobby::append_chatmessage(QString f_name, QString f_message) { - ui_chatbox->append_chatmessage(f_name, f_message, ao_app->get_color("ooc_default_color", "courtroom_design.ini").name()); + ui_chatbox->append_chatmessage(f_name, f_message, ao_app->get_color("ooc_default_color", "courtroom_design.ini").name()); } void Lobby::append_error(QString f_message) { - ui_chatbox->append_error(f_message); + ui_chatbox->append_error(f_message); } void Lobby::set_player_count(int players_online, int max_players) { - QString f_string = tr("Online: %1/%2").arg(QString::number(players_online)).arg(QString::number(max_players)); - ui_player_count->setText(f_string); + QString f_string = tr("Online: %1/%2").arg(QString::number(players_online)).arg(QString::number(max_players)); + ui_player_count->setText(f_string); } void Lobby::enable_connect_button() { - ui_connect->setEnabled(true); + ui_connect->setEnabled(true); } Lobby::~Lobby() { - } diff --git a/src/main.cpp b/src/main.cpp index 8d3f53b..9370bce 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,13 +1,13 @@ #include "aoapplication.h" -#include "datatypes.h" -#include "networkmanager.h" -#include "lobby.h" #include "courtroom.h" -#include +#include "datatypes.h" +#include "lobby.h" +#include "networkmanager.h" #include -#include #include +#include +#include int main(int argc, char *argv[]) { @@ -36,7 +36,7 @@ int main(int argc, char *argv[]) QTranslator qtTranslator; qtTranslator.load("qt_" + p_language, - QLibraryInfo::location(QLibraryInfo::TranslationsPath)); + QLibraryInfo::location(QLibraryInfo::TranslationsPath)); main_app.installTranslator(&qtTranslator); QTranslator appTranslator; diff --git a/src/misc_functions.cpp b/src/misc_functions.cpp index 2352055..fa49ba4 100644 --- a/src/misc_functions.cpp +++ b/src/misc_functions.cpp @@ -2,8 +2,8 @@ void delay(int p_milliseconds) { - QTime dieTime = QTime::currentTime().addMSecs(p_milliseconds); + QTime dieTime = QTime::currentTime().addMSecs(p_milliseconds); - while(QTime::currentTime() < dieTime) - QCoreApplication::processEvents(QEventLoop::AllEvents, 100); + while (QTime::currentTime() < dieTime) + QCoreApplication::processEvents(QEventLoop::AllEvents, 100); } diff --git a/src/networkmanager.cpp b/src/networkmanager.cpp index a9810d4..19f0241 100644 --- a/src/networkmanager.cpp +++ b/src/networkmanager.cpp @@ -6,242 +6,220 @@ NetworkManager::NetworkManager(AOApplication *parent) : QObject(parent) { - ao_app = parent; + ao_app = parent; - ms_socket = new QTcpSocket(this); - server_socket = new QTcpSocket(this); + ms_socket = new QTcpSocket(this); + server_socket = new QTcpSocket(this); - ms_reconnect_timer = new QTimer(this); - ms_reconnect_timer->setSingleShot(true); - QObject::connect(ms_reconnect_timer, SIGNAL(timeout()), this, SLOT(retry_ms_connect())); + ms_reconnect_timer = new QTimer(this); + ms_reconnect_timer->setSingleShot(true); + QObject::connect(ms_reconnect_timer, SIGNAL(timeout()), this, SLOT(retry_ms_connect())); - QObject::connect(ms_socket, SIGNAL(readyRead()), this, SLOT(handle_ms_packet())); - QObject::connect(server_socket, SIGNAL(readyRead()), this, SLOT(handle_server_packet())); - QObject::connect(server_socket, SIGNAL(disconnected()), ao_app, SLOT(server_disconnected())); + QObject::connect(ms_socket, SIGNAL(readyRead()), this, SLOT(handle_ms_packet())); + QObject::connect(server_socket, SIGNAL(readyRead()), this, SLOT(handle_server_packet())); + QObject::connect(server_socket, SIGNAL(disconnected()), ao_app, SLOT(server_disconnected())); - QString master_config = ao_app->configini->value("master", "").value(); - if (master_config != "") - ms_nosrv_hostname = master_config; + QString master_config = ao_app->configini->value("master", "").value(); + if (master_config != "") + ms_nosrv_hostname = master_config; } NetworkManager::~NetworkManager() { - } void NetworkManager::connect_to_master() { - ms_socket->close(); - ms_socket->abort(); + ms_socket->close(); + ms_socket->abort(); #ifdef MS_FAILOVER_SUPPORTED - perform_srv_lookup(); + perform_srv_lookup(); #else - connect_to_master_nosrv(); + connect_to_master_nosrv(); #endif } void NetworkManager::connect_to_master_nosrv() { - QObject::connect(ms_socket, SIGNAL(error(QAbstractSocket::SocketError)), - this, SLOT(on_ms_socket_error(QAbstractSocket::SocketError))); + QObject::connect(ms_socket, SIGNAL(error(QAbstractSocket::SocketError)), + this, SLOT(on_ms_socket_error(QAbstractSocket::SocketError))); - QObject::connect(ms_socket, SIGNAL(connected()), - this, SLOT(on_ms_nosrv_connect_success())); - ms_socket->connectToHost(ms_nosrv_hostname, ms_port); + QObject::connect(ms_socket, SIGNAL(connected()), + this, SLOT(on_ms_nosrv_connect_success())); + ms_socket->connectToHost(ms_nosrv_hostname, ms_port); } void NetworkManager::connect_to_server(server_type p_server) { - server_socket->close(); - server_socket->abort(); + server_socket->close(); + server_socket->abort(); - server_socket->connectToHost(p_server.ip, p_server.port); + server_socket->connectToHost(p_server.ip, p_server.port); } void NetworkManager::ship_ms_packet(QString p_packet) { - if (!ms_socket->isOpen()) - { - retry_ms_connect(); - } - else - { - ms_socket->write(p_packet.toUtf8()); - } + if (!ms_socket->isOpen()) { + retry_ms_connect(); + } + else { + ms_socket->write(p_packet.toUtf8()); + } } void NetworkManager::ship_server_packet(QString p_packet) { - server_socket->write(p_packet.toUtf8()); + server_socket->write(p_packet.toUtf8()); } void NetworkManager::handle_ms_packet() { - QByteArray buffer = ms_socket->readAll(); - QString in_data = QString::fromUtf8(buffer, buffer.size()); + QByteArray buffer = ms_socket->readAll(); + QString in_data = QString::fromUtf8(buffer, buffer.size()); - if (!in_data.endsWith("%")) - { - ms_partial_packet = true; - ms_temp_packet += in_data; - return; - } - - else - { - if (ms_partial_packet) - { - in_data = ms_temp_packet + in_data; - ms_temp_packet = ""; - ms_partial_packet = false; + if (!in_data.endsWith("%")) { + ms_partial_packet = true; + ms_temp_packet += in_data; + return; } - } - QStringList packet_list = in_data.split("%", QString::SplitBehavior(QString::SkipEmptyParts)); + else { + if (ms_partial_packet) { + in_data = ms_temp_packet + in_data; + ms_temp_packet = ""; + ms_partial_packet = false; + } + } - for (QString packet : packet_list) - { - AOPacket *f_packet = new AOPacket(packet); + QStringList packet_list = in_data.split("%", QString::SplitBehavior(QString::SkipEmptyParts)); - ao_app->ms_packet_received(f_packet); - } + for (QString packet : packet_list) { + AOPacket *f_packet = new AOPacket(packet); + + ao_app->ms_packet_received(f_packet); + } } - void NetworkManager::perform_srv_lookup() { - #ifdef MS_FAILOVER_SUPPORTED - ms_dns = new QDnsLookup(QDnsLookup::SRV, ms_srv_hostname, this); +#ifdef MS_FAILOVER_SUPPORTED + ms_dns = new QDnsLookup(QDnsLookup::SRV, ms_srv_hostname, this); - connect(ms_dns, SIGNAL(finished()), this, SLOT(on_srv_lookup())); - ms_dns->lookup(); - #endif + connect(ms_dns, SIGNAL(finished()), this, SLOT(on_srv_lookup())); + ms_dns->lookup(); +#endif } void NetworkManager::on_srv_lookup() { - #ifdef MS_FAILOVER_SUPPORTED - bool connected = false; - if (ms_dns->error() != QDnsLookup::NoError) - { - qWarning("SRV lookup of the master server DNS failed."); - ms_dns->deleteLater(); - } - else - { - const auto srv_records = ms_dns->serviceRecords(); - - for (const QDnsServiceRecord &record : srv_records) - { -#ifdef DEBUG_NETWORK - qDebug() << "Connecting to " << record.target() << ":" << record.port(); -#endif - ms_socket->connectToHost(record.target(), record.port()); - QTime timer; - timer.start(); - do - { - ao_app->processEvents(); - if (ms_socket->state() == QAbstractSocket::ConnectedState) - { - connected = true; - break; - } - else if (ms_socket->state() != QAbstractSocket::ConnectingState - && ms_socket->state() != QAbstractSocket::HostLookupState - && ms_socket->error() != -1) - { - qDebug() << ms_socket->error(); - qWarning() << "Error connecting to master server:" << ms_socket->errorString(); - ms_socket->abort(); - ms_socket->close(); - break; - } - } while (timer.elapsed() < timeout_milliseconds); // Very expensive spin-wait loop - it will bring CPU to 100%! - if (connected) - { - // Connect a one-shot signal in case the master server disconnects randomly - QObject::connect(ms_socket, SIGNAL(error(QAbstractSocket::SocketError)), - this, SLOT(on_ms_socket_error(QAbstractSocket::SocketError))); - break; - } - else - { - ms_socket->abort(); - ms_socket->close(); - } +#ifdef MS_FAILOVER_SUPPORTED + bool connected = false; + if (ms_dns->error() != QDnsLookup::NoError) { + qWarning("SRV lookup of the master server DNS failed."); + ms_dns->deleteLater(); } - } + else { + const auto srv_records = ms_dns->serviceRecords(); - // Failover to non-SRV connection - if (!connected) - connect_to_master_nosrv(); - else - emit ms_connect_finished(connected, false); - #endif + for (const QDnsServiceRecord &record : srv_records) { +#ifdef DEBUG_NETWORK + qDebug() << "Connecting to " << record.target() << ":" << record.port(); +#endif + ms_socket->connectToHost(record.target(), record.port()); + QTime timer; + timer.start(); + do { + ao_app->processEvents(); + if (ms_socket->state() == QAbstractSocket::ConnectedState) { + connected = true; + break; + } + else if (ms_socket->state() != QAbstractSocket::ConnectingState && ms_socket->state() != QAbstractSocket::HostLookupState && ms_socket->error() != -1) { + qDebug() << ms_socket->error(); + qWarning() << "Error connecting to master server:" << ms_socket->errorString(); + ms_socket->abort(); + ms_socket->close(); + break; + } + } while (timer.elapsed() < timeout_milliseconds); // Very expensive spin-wait loop - it will bring CPU to 100%! + if (connected) { + // Connect a one-shot signal in case the master server disconnects randomly + QObject::connect(ms_socket, SIGNAL(error(QAbstractSocket::SocketError)), + this, SLOT(on_ms_socket_error(QAbstractSocket::SocketError))); + break; + } + else { + ms_socket->abort(); + ms_socket->close(); + } + } + } + + // Failover to non-SRV connection + if (!connected) + connect_to_master_nosrv(); + else + emit ms_connect_finished(connected, false); +#endif } void NetworkManager::on_ms_nosrv_connect_success() { - emit ms_connect_finished(true, false); + emit ms_connect_finished(true, false); - QObject::disconnect(ms_socket, SIGNAL(connected()), - this, SLOT(on_ms_nosrv_connect_success())); + QObject::disconnect(ms_socket, SIGNAL(connected()), + this, SLOT(on_ms_nosrv_connect_success())); - QObject::connect(ms_socket, SIGNAL(error(QAbstractSocket::SocketError)), - this, SLOT(on_ms_socket_error(QAbstractSocket::SocketError))); + QObject::connect(ms_socket, SIGNAL(error(QAbstractSocket::SocketError)), + this, SLOT(on_ms_socket_error(QAbstractSocket::SocketError))); } void NetworkManager::on_ms_socket_error(QAbstractSocket::SocketError error) { - qWarning() << "Master server socket error:" << ms_socket->errorString() - << "(" << error << ")"; + qWarning() << "Master server socket error:" << ms_socket->errorString() + << "(" << error << ")"; - // Disconnect the one-shot signal - this way, failover connect attempts - // don't trigger a full retry - QObject::disconnect(ms_socket, SIGNAL(error(QAbstractSocket::SocketError)), - this, SLOT(on_ms_socket_error(QAbstractSocket::SocketError))); + // Disconnect the one-shot signal - this way, failover connect attempts + // don't trigger a full retry + QObject::disconnect(ms_socket, SIGNAL(error(QAbstractSocket::SocketError)), + this, SLOT(on_ms_socket_error(QAbstractSocket::SocketError))); - emit ms_connect_finished(false, true); + emit ms_connect_finished(false, true); - ms_reconnect_timer->start(ms_reconnect_delay * 1000); + ms_reconnect_timer->start(ms_reconnect_delay * 1000); } void NetworkManager::retry_ms_connect() { - if (!ms_reconnect_timer->isActive() && ms_socket->state() != QAbstractSocket::ConnectingState) - connect_to_master(); + if (!ms_reconnect_timer->isActive() && ms_socket->state() != QAbstractSocket::ConnectingState) + connect_to_master(); } void NetworkManager::handle_server_packet() { - QByteArray buffer = server_socket->readAll(); - QString in_data = QString::fromUtf8(buffer, buffer.size()); + QByteArray buffer = server_socket->readAll(); + QString in_data = QString::fromUtf8(buffer, buffer.size()); - if (!in_data.endsWith("%")) - { - partial_packet = true; - temp_packet += in_data; - return; - } - - else - { - if (partial_packet) - { - in_data = temp_packet + in_data; - temp_packet = ""; - partial_packet = false; + if (!in_data.endsWith("%")) { + partial_packet = true; + temp_packet += in_data; + return; } - } - QStringList packet_list = in_data.split("%", QString::SplitBehavior(QString::SkipEmptyParts)); + else { + if (partial_packet) { + in_data = temp_packet + in_data; + temp_packet = ""; + partial_packet = false; + } + } - for (QString packet : packet_list) - { - AOPacket *f_packet = new AOPacket(packet); + QStringList packet_list = in_data.split("%", QString::SplitBehavior(QString::SkipEmptyParts)); - ao_app->server_packet_received(f_packet); - } + for (QString packet : packet_list) { + AOPacket *f_packet = new AOPacket(packet); + + ao_app->server_packet_received(f_packet); + } } diff --git a/src/packet_distribution.cpp b/src/packet_distribution.cpp index 2305083..68f568b 100644 --- a/src/packet_distribution.cpp +++ b/src/packet_distribution.cpp @@ -1,776 +1,699 @@ #include "aoapplication.h" -#include "lobby.h" #include "courtroom.h" -#include "networkmanager.h" +#include "debug_functions.h" #include "encryption_functions.h" #include "hardware_functions.h" -#include "debug_functions.h" +#include "lobby.h" +#include "networkmanager.h" void AOApplication::ms_packet_received(AOPacket *p_packet) { - p_packet->net_decode(); + p_packet->net_decode(); - QString header = p_packet->get_header(); - QStringList f_contents = p_packet->get_contents(); + QString header = p_packet->get_header(); + QStringList f_contents = p_packet->get_contents(); #ifdef DEBUG_NETWORK - if (header != "CHECK") - qDebug() << "R(ms):" << p_packet->to_string(); + if (header != "CHECK") + qDebug() << "R(ms):" << p_packet->to_string(); #endif - if (header == "ALL") - { - server_list.clear(); + if (header == "ALL") { + server_list.clear(); - for (QString i_string : p_packet->get_contents()) - { - server_type f_server; - QStringList sub_contents = i_string.split("&"); + for (QString i_string : p_packet->get_contents()) { + server_type f_server; + QStringList sub_contents = i_string.split("&"); - if (sub_contents.size() < 4) - { - qDebug() << "W: malformed packet"; - continue; - } + if (sub_contents.size() < 4) { + qDebug() << "W: malformed packet"; + continue; + } - f_server.name = sub_contents.at(0); - f_server.desc = sub_contents.at(1); - f_server.ip = sub_contents.at(2); - f_server.port = sub_contents.at(3).toInt(); + f_server.name = sub_contents.at(0); + f_server.desc = sub_contents.at(1); + f_server.ip = sub_contents.at(2); + f_server.port = sub_contents.at(3).toInt(); - server_list.append(f_server); + server_list.append(f_server); + } + + if (lobby_constructed) { + w_lobby->list_servers(); + } + } + else if (header == "CT") { + QString f_name, f_message; + + if (f_contents.size() == 1) { + f_name = ""; + f_message = f_contents.at(0); + } + else if (f_contents.size() >= 2) { + f_name = f_contents.at(0); + f_message = f_contents.at(1); + } + else + goto end; + + if (lobby_constructed) { + w_lobby->append_chatmessage(f_name, f_message); + } + if (courtroom_constructed && courtroom_loaded) { + w_courtroom->append_ms_chatmessage(f_name, f_message); + } + } + else if (header == "AO2CHECK") { + send_ms_packet(new AOPacket("ID#AO2#" + get_version_string() + "#%")); + send_ms_packet(new AOPacket("HI#" + get_hdid() + "#%")); + + if (f_contents.size() < 1) + goto end; + + QStringList version_contents = f_contents.at(0).split("."); + + if (version_contents.size() < 3) + goto end; + + int f_release = version_contents.at(0).toInt(); + int f_major = version_contents.at(1).toInt(); + int f_minor = version_contents.at(2).toInt(); + + if (get_release() > f_release) + goto end; + else if (get_release() == f_release) { + if (get_major_version() > f_major) + goto end; + else if (get_major_version() == f_major) { + if (get_minor_version() >= f_minor) + goto end; + } + } + + call_notice(tr("Outdated version! Your version: %1\n" + "Please go to aceattorneyonline.com to update.") + .arg(get_version_string())); + destruct_courtroom(); + destruct_lobby(); } - if (lobby_constructed) - { - w_lobby->list_servers(); - } - } - else if (header == "CT") - { - QString f_name, f_message; +end: - if (f_contents.size() == 1) - { - f_name = ""; - f_message = f_contents.at(0); - } - else if (f_contents.size() >= 2) - { - f_name = f_contents.at(0); - f_message = f_contents.at(1); - } - else - goto end; - - if (lobby_constructed) - { - w_lobby->append_chatmessage(f_name, f_message); - } - if (courtroom_constructed && courtroom_loaded) - { - w_courtroom->append_ms_chatmessage(f_name, f_message); - } - } - else if (header == "AO2CHECK") - { - send_ms_packet(new AOPacket("ID#AO2#" + get_version_string() + "#%")); - send_ms_packet(new AOPacket("HI#" + get_hdid() + "#%")); - - if (f_contents.size() < 1) - goto end; - - QStringList version_contents = f_contents.at(0).split("."); - - if (version_contents.size() < 3) - goto end; - - int f_release = version_contents.at(0).toInt(); - int f_major = version_contents.at(1).toInt(); - int f_minor = version_contents.at(2).toInt(); - - if (get_release() > f_release) - goto end; - else if (get_release() == f_release) - { - if (get_major_version() > f_major) - goto end; - else if (get_major_version() == f_major) - { - if (get_minor_version() >= f_minor) - goto end; - } - } - - call_notice(tr("Outdated version! Your version: %1\n" - "Please go to aceattorneyonline.com to update.") - .arg(get_version_string())); - destruct_courtroom(); - destruct_lobby(); - } - - end: - - delete p_packet; + delete p_packet; } void AOApplication::server_packet_received(AOPacket *p_packet) { - p_packet->net_decode(); + p_packet->net_decode(); - QString header = p_packet->get_header(); - QStringList f_contents = p_packet->get_contents(); - QString f_packet = p_packet->to_string(); + QString header = p_packet->get_header(); + QStringList f_contents = p_packet->get_contents(); + QString f_packet = p_packet->to_string(); #ifdef DEBUG_NETWORK - if (header != "checkconnection") - qDebug() << "R:" << f_packet; + if (header != "checkconnection") + qDebug() << "R:" << f_packet; #endif - if (header == "decryptor") - { - if (f_contents.size() == 0) - goto end; + if (header == "decryptor") { + if (f_contents.size() == 0) + goto end; - //you may ask where 322 comes from. that would be a good question. - s_decryptor = fanta_decrypt(f_contents.at(0), 322).toUInt(); + //you may ask where 322 comes from. that would be a good question. + s_decryptor = fanta_decrypt(f_contents.at(0), 322).toUInt(); - //default(legacy) values - encryption_needed = true; - yellow_text_enabled = false; - prezoom_enabled = false; - flipping_enabled = false; - custom_objection_enabled = false; - improved_loading_enabled = false; - desk_mod_enabled = false; - evidence_enabled = false; - cccc_ic_support_enabled = false; - arup_enabled = false; - casing_alerts_enabled = false; - modcall_reason_enabled = false; - looping_sfx_support_enabled = false; - additive_enabled = false; - effects_enabled = false; + //default(legacy) values + encryption_needed = true; + yellow_text_enabled = false; + prezoom_enabled = false; + flipping_enabled = false; + custom_objection_enabled = false; + improved_loading_enabled = false; + desk_mod_enabled = false; + evidence_enabled = false; + cccc_ic_support_enabled = false; + arup_enabled = false; + casing_alerts_enabled = false; + modcall_reason_enabled = false; + looping_sfx_support_enabled = false; + additive_enabled = false; + effects_enabled = false; - //workaround for tsuserver4 - if (f_contents.at(0) == "NOENCRYPT") - encryption_needed = false; + //workaround for tsuserver4 + if (f_contents.at(0) == "NOENCRYPT") + encryption_needed = false; - QString f_hdid; - f_hdid = get_hdid(); + QString f_hdid; + f_hdid = get_hdid(); - AOPacket *hi_packet = new AOPacket("HI#" + f_hdid + "#%"); - send_server_packet(hi_packet); - } - else if (header == "ID") - { - if (f_contents.size() < 2) - goto end; - - s_pv = f_contents.at(0).toInt(); - server_software = f_contents.at(1); - - w_lobby->enable_connect_button(); - - send_server_packet(new AOPacket("ID#AO2#" + get_version_string() + "#%")); - } - else if (header == "CT") - { - if (f_contents.size() < 2) - goto end; - - if (courtroom_constructed) - { - if (f_contents.size() == 3) - w_courtroom->append_server_chatmessage(f_contents.at(0), f_contents.at(1), f_contents.at(2)); - else - w_courtroom->append_server_chatmessage(f_contents.at(0), f_contents.at(1), "0"); + AOPacket *hi_packet = new AOPacket("HI#" + f_hdid + "#%"); + send_server_packet(hi_packet); } - } - else if (header == "FL") - { - if (f_packet.contains("yellowtext",Qt::CaseInsensitive)) - yellow_text_enabled = true; - if (f_packet.contains("prezoom",Qt::CaseInsensitive)) - prezoom_enabled = true; - if (f_packet.contains("flipping",Qt::CaseInsensitive)) - flipping_enabled = true; - if (f_packet.contains("customobjections",Qt::CaseInsensitive)) - custom_objection_enabled = true; - if (f_packet.contains("fastloading",Qt::CaseInsensitive)) - improved_loading_enabled = true; - if (f_packet.contains("noencryption",Qt::CaseInsensitive)) - encryption_needed = false; - if (f_packet.contains("deskmod",Qt::CaseInsensitive)) - desk_mod_enabled = true; - if (f_packet.contains("evidence",Qt::CaseInsensitive)) - evidence_enabled = true; - if (f_packet.contains("cccc_ic_support",Qt::CaseInsensitive)) - cccc_ic_support_enabled = true; - if (f_packet.contains("arup",Qt::CaseInsensitive)) - arup_enabled = true; - if (f_packet.contains("casing_alerts",Qt::CaseInsensitive)) - casing_alerts_enabled = true; - if (f_packet.contains("modcall_reason",Qt::CaseInsensitive)) - modcall_reason_enabled = true; - if (f_packet.contains("looping_sfx",Qt::CaseInsensitive)) - looping_sfx_support_enabled = true; - if (f_packet.contains("additive",Qt::CaseInsensitive)) - additive_enabled = true; - if (f_packet.contains("effects",Qt::CaseInsensitive)) - effects_enabled = true; - } - else if (header == "PN") - { - if (f_contents.size() < 2) - goto end; + else if (header == "ID") { + if (f_contents.size() < 2) + goto end; - w_lobby->set_player_count(f_contents.at(0).toInt(), f_contents.at(1).toInt()); - } - else if (header == "SI") - { - if (f_contents.size() != 3) - goto end; + s_pv = f_contents.at(0).toInt(); + server_software = f_contents.at(1); - char_list_size = f_contents.at(0).toInt(); - evidence_list_size = f_contents.at(1).toInt(); - music_list_size = f_contents.at(2).toInt(); + w_lobby->enable_connect_button(); - if (char_list_size < 1 || evidence_list_size < 0 || music_list_size < 0) - goto end; - - loaded_chars = 0; - loaded_evidence = 0; - loaded_music = 0; - generated_chars = 0; - - destruct_courtroom(); - construct_courtroom(); - - courtroom_loaded = false; - - QString window_title = tr("Attorney Online 2"); - int selected_server = w_lobby->get_selected_server(); - - QString server_address = "", server_name = ""; - if (w_lobby->public_servers_selected) - { - 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)); - qDebug() << server_address; - window_title += ": " + server_name; - } + send_server_packet(new AOPacket("ID#AO2#" + get_version_string() + "#%")); } - else - { - 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)); - qDebug() << server_address; - window_title += ": " + server_name; - } + else if (header == "CT") { + if (f_contents.size() < 2) + goto end; + + if (courtroom_constructed) { + if (f_contents.size() == 3) + w_courtroom->append_server_chatmessage(f_contents.at(0), f_contents.at(1), f_contents.at(2)); + else + w_courtroom->append_server_chatmessage(f_contents.at(0), f_contents.at(1), "0"); + } } - - 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; - - if(improved_loading_enabled) - f_packet = new AOPacket("RC#%"); - else - f_packet = new AOPacket("askchar2#%"); - - send_server_packet(f_packet); - - //Remove any characters not accepted in folder names for the server_name here - this->log_filename = QDateTime::currentDateTime().toUTC().toString("'logs/" + server_name.remove(QRegExp("[\\\\/:*?\"<>|\']")) + "/'ddd MMMM yyyy hh.mm.ss t'.log'"); - this->write_to_file("Joined server " + server_name + " on address " + server_address +" on " + QDateTime::currentDateTime().toUTC().toString(), log_filename, true); - QCryptographicHash hash(QCryptographicHash::Algorithm::Sha256); - hash.addData(server_address.toUtf8()); - if (is_discord_enabled()) - discord->state_server(server_name.toStdString(), hash.result().toBase64().toStdString()); - } - else if (header == "CI") - { - if (!courtroom_constructed) - goto end; - - for (int n_element = 0 ; n_element < f_contents.size() ; n_element += 2) - { - if (f_contents.at(n_element).toInt() != loaded_chars) - break; - - //this means we are on the last element and checking n + 1 element will be game over so - if (n_element == f_contents.size() - 1) - break; - - QStringList sub_elements = f_contents.at(n_element + 1).split("&"); - if (sub_elements.size() < 2) - break; - - char_type f_char; - f_char.name = sub_elements.at(0); - f_char.description = sub_elements.at(1); - f_char.evidence_string = sub_elements.at(3); - //temporary. the CharsCheck packet sets this properly - f_char.taken = false; - - ++loaded_chars; - - w_lobby->set_loading_text("Loading chars:\n" + QString::number(loaded_chars) + "/" + QString::number(char_list_size)); - - w_courtroom->append_char(f_char); - - int total_loading_size = char_list_size * 2 + evidence_list_size + music_list_size; - int loading_value = int(((loaded_chars + generated_chars + loaded_music + loaded_evidence) / static_cast(total_loading_size)) * 100); - w_lobby->set_loading_value(loading_value); + else if (header == "FL") { + if (f_packet.contains("yellowtext", Qt::CaseInsensitive)) + yellow_text_enabled = true; + if (f_packet.contains("prezoom", Qt::CaseInsensitive)) + prezoom_enabled = true; + if (f_packet.contains("flipping", Qt::CaseInsensitive)) + flipping_enabled = true; + if (f_packet.contains("customobjections", Qt::CaseInsensitive)) + custom_objection_enabled = true; + if (f_packet.contains("fastloading", Qt::CaseInsensitive)) + improved_loading_enabled = true; + if (f_packet.contains("noencryption", Qt::CaseInsensitive)) + encryption_needed = false; + if (f_packet.contains("deskmod", Qt::CaseInsensitive)) + desk_mod_enabled = true; + if (f_packet.contains("evidence", Qt::CaseInsensitive)) + evidence_enabled = true; + if (f_packet.contains("cccc_ic_support", Qt::CaseInsensitive)) + cccc_ic_support_enabled = true; + if (f_packet.contains("arup", Qt::CaseInsensitive)) + arup_enabled = true; + if (f_packet.contains("casing_alerts", Qt::CaseInsensitive)) + casing_alerts_enabled = true; + if (f_packet.contains("modcall_reason", Qt::CaseInsensitive)) + modcall_reason_enabled = true; + if (f_packet.contains("looping_sfx", Qt::CaseInsensitive)) + looping_sfx_support_enabled = true; + if (f_packet.contains("additive", Qt::CaseInsensitive)) + additive_enabled = true; + if (f_packet.contains("effects", Qt::CaseInsensitive)) + effects_enabled = true; } + else if (header == "PN") { + if (f_contents.size() < 2) + goto end; - if (improved_loading_enabled) - send_server_packet(new AOPacket("RE#%")); - else - { - QString next_packet_number = QString::number(((loaded_chars - 1) / 10) + 1); - send_server_packet(new AOPacket("AN#" + next_packet_number + "#%")); + w_lobby->set_player_count(f_contents.at(0).toInt(), f_contents.at(1).toInt()); } + else if (header == "SI") { + if (f_contents.size() != 3) + goto end; - } - else if (header == "EI") - { - if (!courtroom_constructed) - goto end; + char_list_size = f_contents.at(0).toInt(); + evidence_list_size = f_contents.at(1).toInt(); + music_list_size = f_contents.at(2).toInt(); + if (char_list_size < 1 || evidence_list_size < 0 || music_list_size < 0) + goto end; - // +1 because evidence starts at 1 rather than 0 for whatever reason - //enjoy fanta - if (f_contents.at(0).toInt() != loaded_evidence + 1) - goto end; + loaded_chars = 0; + loaded_evidence = 0; + loaded_music = 0; + generated_chars = 0; - if (f_contents.size() < 2) - goto end; + destruct_courtroom(); + construct_courtroom(); - QStringList sub_elements = f_contents.at(1).split("&"); - if (sub_elements.size() < 4) - goto end; + courtroom_loaded = false; - evi_type f_evi; - f_evi.name = sub_elements.at(0); - f_evi.description = sub_elements.at(1); - //no idea what the number at position 2 is. probably an identifier? - f_evi.image = sub_elements.at(3); + QString window_title = tr("Attorney Online 2"); + int selected_server = w_lobby->get_selected_server(); - ++loaded_evidence; + QString server_address = "", server_name = ""; + if (w_lobby->public_servers_selected) { + 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)); + qDebug() << server_address; + window_title += ": " + server_name; + } + } + else { + 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)); + qDebug() << server_address; + window_title += ": " + server_name; + } + } - w_lobby->set_loading_text(tr("Loading evidence:\n%1/%2").arg(QString::number(loaded_evidence)).arg(QString::number(evidence_list_size))); + w_courtroom->set_window_title(window_title); - w_courtroom->append_evidence(f_evi); + w_lobby->show_loading_overlay(); + w_lobby->set_loading_text(tr("Loading")); + w_lobby->set_loading_value(0); - int total_loading_size = char_list_size * 2 + evidence_list_size + music_list_size; - int loading_value = int(((loaded_chars + generated_chars + loaded_music + loaded_evidence) / static_cast(total_loading_size)) * 100); - w_lobby->set_loading_value(loading_value); + AOPacket *f_packet; - QString next_packet_number = QString::number(loaded_evidence); - send_server_packet(new AOPacket("AE#" + next_packet_number + "#%")); + if (improved_loading_enabled) + f_packet = new AOPacket("RC#%"); + else + f_packet = new AOPacket("askchar2#%"); - } - else if (header == "EM") - { - if (!courtroom_constructed) - goto end; + send_server_packet(f_packet); - bool musics_time = false; - int areas = 0; - - for (int n_element = 0 ; n_element < f_contents.size() ; n_element += 2) - { - if (f_contents.at(n_element).toInt() != loaded_music) - break; - - if (n_element == f_contents.size() - 1) - break; - - QString f_music = f_contents.at(n_element + 1); - - ++loaded_music; - - w_lobby->set_loading_text(tr("Loading music:\n%1/%2").arg(QString::number(loaded_music)).arg(QString::number(music_list_size))); - - if (musics_time) - { - w_courtroom->append_music(f_music); - } - else - { - if (f_music.endsWith(".wav") || - f_music.endsWith(".mp3") || - f_music.endsWith(".mp4") || - f_music.endsWith(".ogg") || - f_music.endsWith(".opus")) - { - musics_time = true; - areas--; - w_courtroom->fix_last_area(); - w_courtroom->append_music(f_music); - } - else - { - w_courtroom->append_area(f_music); - areas++; - } - } - - for (int area_n = 0; area_n < areas; area_n++) - { - w_courtroom->arup_append(0, "Unknown", "Unknown", "Unknown"); - } - - int total_loading_size = char_list_size * 2 + evidence_list_size + music_list_size; - int loading_value = int(((loaded_chars + generated_chars + loaded_music + loaded_evidence) / static_cast(total_loading_size)) * 100); - w_lobby->set_loading_value(loading_value); + //Remove any characters not accepted in folder names for the server_name here + this->log_filename = QDateTime::currentDateTime().toUTC().toString("'logs/" + server_name.remove(QRegExp("[\\\\/:*?\"<>|\']")) + "/'ddd MMMM yyyy hh.mm.ss t'.log'"); + this->write_to_file("Joined server " + server_name + " on address " + server_address + " on " + QDateTime::currentDateTime().toUTC().toString(), log_filename, true); + QCryptographicHash hash(QCryptographicHash::Algorithm::Sha256); + hash.addData(server_address.toUtf8()); + if (is_discord_enabled()) + discord->state_server(server_name.toStdString(), hash.result().toBase64().toStdString()); } + else if (header == "CI") { + if (!courtroom_constructed) + goto end; - QString next_packet_number = QString::number(((loaded_music - 1) / 10) + 1); - send_server_packet(new AOPacket("AM#" + next_packet_number + "#%")); - } - else if (header == "CharsCheck") - { - if (!courtroom_constructed) - goto end; + for (int n_element = 0; n_element < f_contents.size(); n_element += 2) { + if (f_contents.at(n_element).toInt() != loaded_chars) + break; - for (int n_char = 0 ; n_char < f_contents.size() ; ++n_char) - { - if (f_contents.at(n_char) == "-1") - w_courtroom->set_taken(n_char, true); - else - w_courtroom->set_taken(n_char, false); + //this means we are on the last element and checking n + 1 element will be game over so + if (n_element == f_contents.size() - 1) + break; + + QStringList sub_elements = f_contents.at(n_element + 1).split("&"); + if (sub_elements.size() < 2) + break; + + char_type f_char; + f_char.name = sub_elements.at(0); + f_char.description = sub_elements.at(1); + f_char.evidence_string = sub_elements.at(3); + //temporary. the CharsCheck packet sets this properly + f_char.taken = false; + + ++loaded_chars; + + w_lobby->set_loading_text("Loading chars:\n" + QString::number(loaded_chars) + "/" + QString::number(char_list_size)); + + w_courtroom->append_char(f_char); + + int total_loading_size = char_list_size * 2 + evidence_list_size + music_list_size; + int loading_value = int(((loaded_chars + generated_chars + loaded_music + loaded_evidence) / static_cast(total_loading_size)) * 100); + w_lobby->set_loading_value(loading_value); + } + + if (improved_loading_enabled) + send_server_packet(new AOPacket("RE#%")); + else { + QString next_packet_number = QString::number(((loaded_chars - 1) / 10) + 1); + send_server_packet(new AOPacket("AN#" + next_packet_number + "#%")); + } } - } + else if (header == "EI") { + if (!courtroom_constructed) + goto end; - else if (header == "SC") - { - if (!courtroom_constructed) - goto end; + // +1 because evidence starts at 1 rather than 0 for whatever reason + //enjoy fanta + if (f_contents.at(0).toInt() != loaded_evidence + 1) + goto end; - for (int n_element = 0 ; n_element < f_contents.size() ; ++n_element) - { - QStringList sub_elements = f_contents.at(n_element).split("&"); + if (f_contents.size() < 2) + goto end; - char_type f_char; - f_char.name = sub_elements.at(0); - if (sub_elements.size() >= 2) - f_char.description = sub_elements.at(1); - - //temporary. the CharsCheck packet sets this properly - f_char.taken = false; - - ++loaded_chars; - - w_lobby->set_loading_text(tr("Loading chars:\n%1/%2").arg(QString::number(loaded_chars)).arg(QString::number(char_list_size))); - - w_courtroom->append_char(f_char); - - int total_loading_size = char_list_size * 2 + evidence_list_size + music_list_size; - int loading_value = int(((loaded_chars + generated_chars + loaded_music + loaded_evidence) / static_cast(total_loading_size)) * 100); - w_lobby->set_loading_value(loading_value); - } - - send_server_packet(new AOPacket("RM#%")); - } - else if (header == "SM") - { - if (!courtroom_constructed) - goto end; - - bool musics_time = false; - int areas = 0; - - for (int n_element = 0 ; n_element < f_contents.size() ; ++n_element) - { - ++loaded_music; - - w_lobby->set_loading_text(tr("Loading music:\n%1/%2").arg(QString::number(loaded_music)).arg(QString::number(music_list_size))); - - if (musics_time) - { - w_courtroom->append_music(f_contents.at(n_element)); - } - else - { - if (f_contents.at(n_element).endsWith(".wav") || - f_contents.at(n_element).endsWith(".mp3") || - f_contents.at(n_element).endsWith(".mp4") || - f_contents.at(n_element).endsWith(".ogg") || - f_contents.at(n_element).endsWith(".opus")) - { - musics_time = true; - w_courtroom->fix_last_area(); - w_courtroom->append_music(f_contents.at(n_element)); - areas--; - } - else - { - w_courtroom->append_area(f_contents.at(n_element)); - areas++; - } - } - - for (int area_n = 0; area_n < areas; area_n++) - { - w_courtroom->arup_append(0, "Unknown", "Unknown", "Unknown"); - } - - int total_loading_size = char_list_size * 2 + evidence_list_size + music_list_size; - int loading_value = int(((loaded_chars + generated_chars + loaded_music + loaded_evidence) / static_cast(total_loading_size)) * 100); - w_lobby->set_loading_value(loading_value); - } - - send_server_packet(new AOPacket("RD#%")); - } - else if (header == "FM") //Fetch music ONLY - { - if (!courtroom_constructed) - goto end; - - w_courtroom->clear_music(); - - for (int n_element = 0 ; n_element < f_contents.size() ; ++n_element) - { - w_courtroom->append_music(f_contents.at(n_element)); - } - - w_courtroom->list_music(); - } - else if (header == "FA") //Fetch areas ONLY - { - if (!courtroom_constructed) - goto end; - - w_courtroom->clear_areas(); - - for (int n_element = 0 ; n_element < f_contents.size() ; ++n_element) - { - w_courtroom->append_area(f_contents.at(n_element)); - } - - w_courtroom->list_areas(); - } - else if (header == "DONE") - { - if (!courtroom_constructed) - goto end; - - if (lobby_constructed) - w_courtroom->append_ms_chatmessage("", w_lobby->get_chatlog()); - - w_courtroom->character_loading_finished(); - w_courtroom->done_received(); - - courtroom_loaded = true; - - destruct_lobby(); - } - else if (header == "BN") - { - if (f_contents.size() < 1) - goto end; - - if (courtroom_constructed) - { - if (f_contents.size() >= 2) //We have a pos included in the background packet! - w_courtroom->set_side(f_contents.at(1)); - w_courtroom->set_background(f_contents.at(0), f_contents.size() >= 2); - } - } - else if (header == "SP") - { - if (f_contents.size() < 1) - goto end; - - if (courtroom_constructed) //We were sent a "set position" packet - { - w_courtroom->set_side(f_contents.at(0)); - } - } - else if (header == "SD") //Send pos dropdown - { - if (f_contents.size() < 1) - goto end; - - w_courtroom->set_pos_dropdown(f_contents.at(0).split("*")); - } - //server accepting char request(CC) packet - else if (header == "PV") - { - if (f_contents.size() < 3) - goto end; - - if (courtroom_constructed) - w_courtroom->update_character(f_contents.at(2).toInt()); - } - else if (header == "MS") - { - if (courtroom_constructed && courtroom_loaded) - w_courtroom->handle_chatmessage(&p_packet->get_contents()); - } - else if (header == "MC") - { - if (courtroom_constructed && courtroom_loaded) - w_courtroom->handle_song(&p_packet->get_contents()); - } - else if (header == "RT") - { - if (f_contents.size() < 1) - goto end; - if (courtroom_constructed) - { - if (f_contents.size() == 1) - w_courtroom->handle_wtce(f_contents.at(0), 0); - else if (f_contents.size() == 2) { - w_courtroom->handle_wtce(f_contents.at(0), f_contents.at(1).toInt()); - } - } - } - else if (header == "HP") - { - if (courtroom_constructed && f_contents.size() > 1) - w_courtroom->set_hp_bar(f_contents.at(0).toInt(), f_contents.at(1).toInt()); - } - else if (header == "LE") - { - if (courtroom_constructed) - { - QVector f_evi_list; - - for (QString f_string : f_contents) - { - QStringList sub_contents = f_string.split("&"); - - if (sub_contents.size() < 3) - continue; + QStringList sub_elements = f_contents.at(1).split("&"); + if (sub_elements.size() < 4) + goto end; evi_type f_evi; - f_evi.name = sub_contents.at(0); - f_evi.description = sub_contents.at(1); - f_evi.image = sub_contents.at(2); + f_evi.name = sub_elements.at(0); + f_evi.description = sub_elements.at(1); + //no idea what the number at position 2 is. probably an identifier? + f_evi.image = sub_elements.at(3); - f_evi_list.append(f_evi); - } + ++loaded_evidence; - w_courtroom->set_evidence_list(f_evi_list); + w_lobby->set_loading_text(tr("Loading evidence:\n%1/%2").arg(QString::number(loaded_evidence)).arg(QString::number(evidence_list_size))); + + w_courtroom->append_evidence(f_evi); + + int total_loading_size = char_list_size * 2 + evidence_list_size + music_list_size; + int loading_value = int(((loaded_chars + generated_chars + loaded_music + loaded_evidence) / static_cast(total_loading_size)) * 100); + w_lobby->set_loading_value(loading_value); + + QString next_packet_number = QString::number(loaded_evidence); + send_server_packet(new AOPacket("AE#" + next_packet_number + "#%")); } - } - else if (header == "ARUP") - { - if (courtroom_constructed) - { - int arup_type = f_contents.at(0).toInt(); - for (int n_element = 1 ; n_element < f_contents.size() ; n_element++) - { - w_courtroom->arup_modify(arup_type, n_element - 1, f_contents.at(n_element)); + else if (header == "EM") { + if (!courtroom_constructed) + goto end; + + bool musics_time = false; + int areas = 0; + + for (int n_element = 0; n_element < f_contents.size(); n_element += 2) { + if (f_contents.at(n_element).toInt() != loaded_music) + break; + + if (n_element == f_contents.size() - 1) + break; + + QString f_music = f_contents.at(n_element + 1); + + ++loaded_music; + + w_lobby->set_loading_text(tr("Loading music:\n%1/%2").arg(QString::number(loaded_music)).arg(QString::number(music_list_size))); + + if (musics_time) { + w_courtroom->append_music(f_music); + } + else { + if (f_music.endsWith(".wav") || + f_music.endsWith(".mp3") || + f_music.endsWith(".mp4") || + f_music.endsWith(".ogg") || + f_music.endsWith(".opus")) { + musics_time = true; + areas--; + w_courtroom->fix_last_area(); + w_courtroom->append_music(f_music); + } + else { + w_courtroom->append_area(f_music); + areas++; + } + } + + for (int area_n = 0; area_n < areas; area_n++) { + w_courtroom->arup_append(0, "Unknown", "Unknown", "Unknown"); + } + + int total_loading_size = char_list_size * 2 + evidence_list_size + music_list_size; + int loading_value = int(((loaded_chars + generated_chars + loaded_music + loaded_evidence) / static_cast(total_loading_size)) * 100); + w_lobby->set_loading_value(loading_value); } - } - } - else if (header == "IL") - { - if (courtroom_constructed && f_contents.size() > 0) - w_courtroom->set_ip_list(f_contents.at(0)); - } - else if (header == "MU") - { - if (courtroom_constructed && f_contents.size() > 0) - w_courtroom->set_mute(true, f_contents.at(0).toInt()); - } - else if (header == "UM") - { - if (courtroom_constructed && f_contents.size() > 0) - w_courtroom->set_mute(false, f_contents.at(0).toInt()); - } - else if (header == "KK") - { - if (courtroom_constructed && f_contents.size() >= 1) - { - call_notice(tr("You have been kicked from the server.\nReason: %1").arg(f_contents.at(0))); - construct_lobby(); - destruct_courtroom(); + + QString next_packet_number = QString::number(((loaded_music - 1) / 10) + 1); + send_server_packet(new AOPacket("AM#" + next_packet_number + "#%")); } - } - else if (header == "KB") - { - if (courtroom_constructed && f_contents.size() >= 1) - { - call_notice(tr("You have been banned from the server.\nReason: %1").arg(f_contents.at(0))); - construct_lobby(); - destruct_courtroom(); + else if (header == "CharsCheck") { + if (!courtroom_constructed) + goto end; + + for (int n_char = 0; n_char < f_contents.size(); ++n_char) { + if (f_contents.at(n_char) == "-1") + w_courtroom->set_taken(n_char, true); + else + w_courtroom->set_taken(n_char, false); + } } - } - else if (header == "BD") - { - call_notice(tr("You are banned on this server.\nReason: %1").arg(f_contents.at(0))); - } - else if (header == "ZZ") - { - if (courtroom_constructed && f_contents.size() > 0) - w_courtroom->mod_called(f_contents.at(0)); - } - else if (header == "CASEA") - { - if (courtroom_constructed && f_contents.size() > 6) - w_courtroom->case_called(f_contents.at(0), f_contents.at(1) == "1", f_contents.at(2) == "1", f_contents.at(3) == "1", f_contents.at(4) == "1", f_contents.at(5) == "1"); - } + else if (header == "SC") { + if (!courtroom_constructed) + goto end; - end: + for (int n_element = 0; n_element < f_contents.size(); ++n_element) { + QStringList sub_elements = f_contents.at(n_element).split("&"); - delete p_packet; + char_type f_char; + f_char.name = sub_elements.at(0); + if (sub_elements.size() >= 2) + f_char.description = sub_elements.at(1); + + //temporary. the CharsCheck packet sets this properly + f_char.taken = false; + + ++loaded_chars; + + w_lobby->set_loading_text(tr("Loading chars:\n%1/%2").arg(QString::number(loaded_chars)).arg(QString::number(char_list_size))); + + w_courtroom->append_char(f_char); + + int total_loading_size = char_list_size * 2 + evidence_list_size + music_list_size; + int loading_value = int(((loaded_chars + generated_chars + loaded_music + loaded_evidence) / static_cast(total_loading_size)) * 100); + w_lobby->set_loading_value(loading_value); + } + + send_server_packet(new AOPacket("RM#%")); + } + else if (header == "SM") { + if (!courtroom_constructed) + goto end; + + bool musics_time = false; + int areas = 0; + + for (int n_element = 0; n_element < f_contents.size(); ++n_element) { + ++loaded_music; + + w_lobby->set_loading_text(tr("Loading music:\n%1/%2").arg(QString::number(loaded_music)).arg(QString::number(music_list_size))); + + if (musics_time) { + w_courtroom->append_music(f_contents.at(n_element)); + } + else { + if (f_contents.at(n_element).endsWith(".wav") || + f_contents.at(n_element).endsWith(".mp3") || + f_contents.at(n_element).endsWith(".mp4") || + f_contents.at(n_element).endsWith(".ogg") || + f_contents.at(n_element).endsWith(".opus")) { + musics_time = true; + w_courtroom->fix_last_area(); + w_courtroom->append_music(f_contents.at(n_element)); + areas--; + } + else { + w_courtroom->append_area(f_contents.at(n_element)); + areas++; + } + } + + for (int area_n = 0; area_n < areas; area_n++) { + w_courtroom->arup_append(0, "Unknown", "Unknown", "Unknown"); + } + + int total_loading_size = char_list_size * 2 + evidence_list_size + music_list_size; + int loading_value = int(((loaded_chars + generated_chars + loaded_music + loaded_evidence) / static_cast(total_loading_size)) * 100); + w_lobby->set_loading_value(loading_value); + } + + send_server_packet(new AOPacket("RD#%")); + } + else if (header == "FM") //Fetch music ONLY + { + if (!courtroom_constructed) + goto end; + + w_courtroom->clear_music(); + + for (int n_element = 0; n_element < f_contents.size(); ++n_element) { + w_courtroom->append_music(f_contents.at(n_element)); + } + + w_courtroom->list_music(); + } + else if (header == "FA") //Fetch areas ONLY + { + if (!courtroom_constructed) + goto end; + + w_courtroom->clear_areas(); + + for (int n_element = 0; n_element < f_contents.size(); ++n_element) { + w_courtroom->append_area(f_contents.at(n_element)); + } + + w_courtroom->list_areas(); + } + else if (header == "DONE") { + if (!courtroom_constructed) + goto end; + + if (lobby_constructed) + w_courtroom->append_ms_chatmessage("", w_lobby->get_chatlog()); + + w_courtroom->character_loading_finished(); + w_courtroom->done_received(); + + courtroom_loaded = true; + + destruct_lobby(); + } + else if (header == "BN") { + if (f_contents.size() < 1) + goto end; + + if (courtroom_constructed) { + if (f_contents.size() >= 2) //We have a pos included in the background packet! + w_courtroom->set_side(f_contents.at(1)); + w_courtroom->set_background(f_contents.at(0), f_contents.size() >= 2); + } + } + else if (header == "SP") { + if (f_contents.size() < 1) + goto end; + + if (courtroom_constructed) //We were sent a "set position" packet + { + w_courtroom->set_side(f_contents.at(0)); + } + } + else if (header == "SD") //Send pos dropdown + { + if (f_contents.size() < 1) + goto end; + + w_courtroom->set_pos_dropdown(f_contents.at(0).split("*")); + } + //server accepting char request(CC) packet + else if (header == "PV") { + if (f_contents.size() < 3) + goto end; + + if (courtroom_constructed) + w_courtroom->update_character(f_contents.at(2).toInt()); + } + else if (header == "MS") { + if (courtroom_constructed && courtroom_loaded) + w_courtroom->handle_chatmessage(&p_packet->get_contents()); + } + else if (header == "MC") { + if (courtroom_constructed && courtroom_loaded) + w_courtroom->handle_song(&p_packet->get_contents()); + } + else if (header == "RT") { + if (f_contents.size() < 1) + goto end; + if (courtroom_constructed) { + if (f_contents.size() == 1) + w_courtroom->handle_wtce(f_contents.at(0), 0); + else if (f_contents.size() == 2) { + w_courtroom->handle_wtce(f_contents.at(0), f_contents.at(1).toInt()); + } + } + } + else if (header == "HP") { + if (courtroom_constructed && f_contents.size() > 1) + w_courtroom->set_hp_bar(f_contents.at(0).toInt(), f_contents.at(1).toInt()); + } + else if (header == "LE") { + if (courtroom_constructed) { + QVector f_evi_list; + + for (QString f_string : f_contents) { + QStringList sub_contents = f_string.split("&"); + + if (sub_contents.size() < 3) + continue; + + evi_type f_evi; + f_evi.name = sub_contents.at(0); + f_evi.description = sub_contents.at(1); + f_evi.image = sub_contents.at(2); + + f_evi_list.append(f_evi); + } + + w_courtroom->set_evidence_list(f_evi_list); + } + } + else if (header == "ARUP") { + if (courtroom_constructed) { + int arup_type = f_contents.at(0).toInt(); + for (int n_element = 1; n_element < f_contents.size(); n_element++) { + w_courtroom->arup_modify(arup_type, n_element - 1, f_contents.at(n_element)); + } + } + } + else if (header == "IL") { + if (courtroom_constructed && f_contents.size() > 0) + w_courtroom->set_ip_list(f_contents.at(0)); + } + else if (header == "MU") { + if (courtroom_constructed && f_contents.size() > 0) + w_courtroom->set_mute(true, f_contents.at(0).toInt()); + } + else if (header == "UM") { + if (courtroom_constructed && f_contents.size() > 0) + w_courtroom->set_mute(false, f_contents.at(0).toInt()); + } + else if (header == "KK") { + if (courtroom_constructed && f_contents.size() >= 1) { + call_notice(tr("You have been kicked from the server.\nReason: %1").arg(f_contents.at(0))); + construct_lobby(); + destruct_courtroom(); + } + } + else if (header == "KB") { + if (courtroom_constructed && f_contents.size() >= 1) { + call_notice(tr("You have been banned from the server.\nReason: %1").arg(f_contents.at(0))); + construct_lobby(); + destruct_courtroom(); + } + } + else if (header == "BD") { + call_notice(tr("You are banned on this server.\nReason: %1").arg(f_contents.at(0))); + } + else if (header == "ZZ") { + if (courtroom_constructed && f_contents.size() > 0) + w_courtroom->mod_called(f_contents.at(0)); + } + else if (header == "CASEA") { + if (courtroom_constructed && f_contents.size() > 6) + w_courtroom->case_called(f_contents.at(0), f_contents.at(1) == "1", f_contents.at(2) == "1", f_contents.at(3) == "1", f_contents.at(4) == "1", f_contents.at(5) == "1"); + } + +end: + + delete p_packet; } void AOApplication::send_ms_packet(AOPacket *p_packet) { - p_packet->net_encode(); + p_packet->net_encode(); - QString f_packet = p_packet->to_string(); + QString f_packet = p_packet->to_string(); - net_manager->ship_ms_packet(f_packet); + net_manager->ship_ms_packet(f_packet); #ifdef DEBUG_NETWORK - qDebug() << "S(ms):" << f_packet; + qDebug() << "S(ms):" << f_packet; #endif - delete p_packet; + delete p_packet; } void AOApplication::send_server_packet(AOPacket *p_packet, bool encoded) { - if (encoded) - p_packet->net_encode(); + if (encoded) + p_packet->net_encode(); - QString f_packet = p_packet->to_string(); + QString f_packet = p_packet->to_string(); - if (encryption_needed) - { + if (encryption_needed) { #ifdef DEBUG_NETWORK - qDebug() << "S(e):" << f_packet; + qDebug() << "S(e):" << f_packet; #endif - p_packet->encrypt_header(s_decryptor); - f_packet = p_packet->to_string(); - } - else - { + p_packet->encrypt_header(s_decryptor); + f_packet = p_packet->to_string(); + } + else { #ifdef DEBUG_NETWORK - qDebug() << "S:" << f_packet; + qDebug() << "S:" << f_packet; #endif - } + } - net_manager->ship_server_packet(f_packet); + net_manager->ship_server_packet(f_packet); - delete p_packet; + delete p_packet; } diff --git a/src/path_functions.cpp b/src/path_functions.cpp index 5eb97a3..ebf4b62 100644 --- a/src/path_functions.cpp +++ b/src/path_functions.cpp @@ -3,8 +3,8 @@ #include "file_functions.h" #include -#include #include +#include #ifdef BASE_OVERRIDE #include "base_override.h" @@ -14,151 +14,153 @@ //the most common OSes(mac and windows) are _usually_ case insensitive //however, there do exist mac installations with case sensitive filesystems //in that case, define CASE_SENSITIVE_FILESYSTEM and compile on a mac -#if (defined (LINUX) || defined (__linux__)) +#if (defined(LINUX) || defined(__linux__)) #define CASE_SENSITIVE_FILESYSTEM #endif QString AOApplication::get_base_path() { - QString base_path = ""; + QString base_path = ""; #ifdef ANDROID - QString sdcard_storage = getenv("SECONDARY_STORAGE"); - if (dir_exists(sdcard_storage + "/AO2/")){ - base_path = sdcard_storage + "/AO2/"; - } - else { - QString external_storage = getenv("EXTERNAL_STORAGE"); - base_path = external_storage + "/AO2/"; - } + QString sdcard_storage = getenv("SECONDARY_STORAGE"); + if (dir_exists(sdcard_storage + "/AO2/")) { + base_path = sdcard_storage + "/AO2/"; + } + else { + QString external_storage = getenv("EXTERNAL_STORAGE"); + base_path = external_storage + "/AO2/"; + } #elif defined __APPLE__ - base_path = applicationDirPath() + "/../../../base/"; + base_path = applicationDirPath() + "/../../../base/"; #else - base_path = applicationDirPath() + "/base/"; + base_path = applicationDirPath() + "/base/"; #endif - return base_path; + return base_path; } QString AOApplication::get_data_path() { - return get_base_path() + "data/"; + return get_base_path() + "data/"; } QString AOApplication::get_default_theme_path(QString p_file) { - QString path = get_base_path() + "themes/default/" + p_file; -#ifndef CASE_SENSITIVE_FILESYSTEM - return path; -#else - return get_case_sensitive_path(path); -#endif -} - -QString AOApplication::get_custom_theme_path(QString p_theme, QString p_file) -{ - QString path = get_base_path() + "themes/" + p_theme + "/" + p_file; -#ifndef CASE_SENSITIVE_FILESYSTEM - return path; -#else - return get_case_sensitive_path(path); -#endif -} - -QString AOApplication::get_theme_path(QString p_file) -{ - QString path = get_base_path() + "themes/" + current_theme + "/" + p_file; -#ifndef CASE_SENSITIVE_FILESYSTEM - return path; -#else - return get_case_sensitive_path(path); -#endif -} - -QString AOApplication::get_character_path(QString p_char, QString p_file) -{ - QString path = get_base_path() + "characters/" + p_char + "/" + p_file; -#ifndef CASE_SENSITIVE_FILESYSTEM - return path; -#else - return get_case_sensitive_path(path); -#endif -} - -QString AOApplication::get_sounds_path(QString p_file) -{ - QString path = get_base_path() + "sounds/general/" + p_file; -#ifndef CASE_SENSITIVE_FILESYSTEM - return path; -#else - return get_case_sensitive_path(path); -#endif -} - -QString AOApplication::get_music_path(QString p_song) -{ - QString path = get_base_path() + "sounds/music/" + p_song; -#ifndef CASE_SENSITIVE_FILESYSTEM - return path; -#else - return get_case_sensitive_path(path); -#endif -} - -QString AOApplication::get_background_path(QString p_file) -{ - QString path = get_base_path() + "background/" + w_courtroom->get_current_background() + "/" + p_file; - if (courtroom_constructed) { + QString path = get_base_path() + "themes/default/" + p_file; #ifndef CASE_SENSITIVE_FILESYSTEM return path; #else return get_case_sensitive_path(path); #endif - } - return get_default_background_path(p_file); +} + +QString AOApplication::get_custom_theme_path(QString p_theme, QString p_file) +{ + QString path = get_base_path() + "themes/" + p_theme + "/" + p_file; +#ifndef CASE_SENSITIVE_FILESYSTEM + return path; +#else + return get_case_sensitive_path(path); +#endif +} + +QString AOApplication::get_theme_path(QString p_file) +{ + QString path = get_base_path() + "themes/" + current_theme + "/" + p_file; +#ifndef CASE_SENSITIVE_FILESYSTEM + return path; +#else + return get_case_sensitive_path(path); +#endif +} + +QString AOApplication::get_character_path(QString p_char, QString p_file) +{ + QString path = get_base_path() + "characters/" + p_char + "/" + p_file; +#ifndef CASE_SENSITIVE_FILESYSTEM + return path; +#else + return get_case_sensitive_path(path); +#endif +} + +QString AOApplication::get_sounds_path(QString p_file) +{ + QString path = get_base_path() + "sounds/general/" + p_file; +#ifndef CASE_SENSITIVE_FILESYSTEM + return path; +#else + return get_case_sensitive_path(path); +#endif +} + +QString AOApplication::get_music_path(QString p_song) +{ + QString path = get_base_path() + "sounds/music/" + p_song; +#ifndef CASE_SENSITIVE_FILESYSTEM + return path; +#else + return get_case_sensitive_path(path); +#endif +} + +QString AOApplication::get_background_path(QString p_file) +{ + QString path = get_base_path() + "background/" + w_courtroom->get_current_background() + "/" + p_file; + if (courtroom_constructed) { +#ifndef CASE_SENSITIVE_FILESYSTEM + return path; +#else + return get_case_sensitive_path(path); +#endif + } + return get_default_background_path(p_file); } QString AOApplication::get_default_background_path(QString p_file) { - QString path = get_base_path() + "background/default/" + p_file; + QString path = get_base_path() + "background/default/" + p_file; #ifndef CASE_SENSITIVE_FILESYSTEM - return path; + return path; #else - return get_case_sensitive_path(path); + return get_case_sensitive_path(path); #endif } QString AOApplication::get_evidence_path(QString p_file) { - QString path = get_base_path() + "evidence/" + p_file; + QString path = get_base_path() + "evidence/" + p_file; #ifndef CASE_SENSITIVE_FILESYSTEM - return path; + return path; #else - return get_case_sensitive_path(path); + return get_case_sensitive_path(path); #endif } -QString AOApplication::get_case_sensitive_path(QString p_file) { - //first, check to see if it's actually there (also serves as base case for recursion) - if (exists(p_file)) return p_file; +QString AOApplication::get_case_sensitive_path(QString p_file) +{ + //first, check to see if it's actually there (also serves as base case for recursion) + if (exists(p_file)) + return p_file; - QFileInfo file(p_file); + QFileInfo file(p_file); - QString file_basename = file.fileName(); - QString file_parent_dir = get_case_sensitive_path(file.absolutePath()); + QString file_basename = file.fileName(); + QString file_parent_dir = get_case_sensitive_path(file.absolutePath()); - //second, does it exist in the new parent dir? - if (exists(file_parent_dir + "/" + file_basename)) + //second, does it exist in the new parent dir? + if (exists(file_parent_dir + "/" + file_basename)) + return file_parent_dir + "/" + file_basename; + + //last resort, dirlist parent dir and find case insensitive match + QRegExp file_rx = QRegExp(file_basename, Qt::CaseInsensitive, QRegExp::FixedString); + QStringList files = QDir(file_parent_dir).entryList(); + + int result = files.indexOf(file_rx); + + if (result != -1) + return file_parent_dir + "/" + files.at(result); + + //if nothing is found, let the caller handle the missing file return file_parent_dir + "/" + file_basename; - - //last resort, dirlist parent dir and find case insensitive match - QRegExp file_rx = QRegExp(file_basename, Qt::CaseInsensitive, QRegExp::FixedString); - QStringList files = QDir(file_parent_dir).entryList(); - - int result = files.indexOf(file_rx); - - if (result != -1) - return file_parent_dir + "/" + files.at(result); - - //if nothing is found, let the caller handle the missing file - return file_parent_dir + "/" + file_basename; } diff --git a/src/scrolltext.cpp b/src/scrolltext.cpp index 6cf075d..543f0f6 100644 --- a/src/scrolltext.cpp +++ b/src/scrolltext.cpp @@ -1,12 +1,10 @@ #include "scrolltext.h" - -ScrollText::ScrollText(QWidget *parent) : - QWidget(parent), scrollPos(0) +ScrollText::ScrollText(QWidget *parent) : QWidget(parent), scrollPos(0) { staticText.setTextFormat(Qt::PlainText); -// setFixedHeight(fontMetrics().height()*2); //The theme sets this + // setFixedHeight(fontMetrics().height()*2); //The theme sets this leftMargin = height() / 3; setSeparator(" --- "); @@ -44,10 +42,9 @@ void ScrollText::updateText() timer.stop(); singleTextWidth = fontMetrics().horizontalAdvance(_text); - scrollEnabled = (singleTextWidth > width() - leftMargin*2); + scrollEnabled = (singleTextWidth > width() - leftMargin * 2); - if(scrollEnabled) - { + if (scrollEnabled) { scrollPos = -64; staticText.setText(_text + _separator); timer.start(); @@ -59,20 +56,18 @@ void ScrollText::updateText() wholeTextSize = QSize(fontMetrics().horizontalAdvance(staticText.text()), fontMetrics().height()); } -void ScrollText::paintEvent(QPaintEvent*) +void ScrollText::paintEvent(QPaintEvent *) { QPainter p(this); - if(scrollEnabled) - { + if (scrollEnabled) { buffer.fill(qRgba(0, 0, 0, 0)); QPainter pb(&buffer); pb.setPen(p.pen()); pb.setFont(p.font()); int x = qMin(-scrollPos, 0) + leftMargin; - while(x < width()) - { + while (x < width()) { pb.drawStaticText(QPointF(x, (height() - wholeTextSize.height()) / 2), staticText); x += wholeTextSize.width(); } @@ -83,20 +78,19 @@ void ScrollText::paintEvent(QPaintEvent*) pb.drawImage(0, 0, alphaChannel); pb.setClipRect(0, 0, 15, height()); //initial situation: don't apply alpha channel in the left half of the image at all; apply it more and more until scrollPos gets positive - if(scrollPos < 0) + if (scrollPos < 0) pb.setOpacity(static_cast((qMax(-8, scrollPos) + 8) / 8.0)); pb.drawImage(0, 0, alphaChannel); //pb.end(); p.drawImage(0, 0, buffer); } - else - { + else { p.drawStaticText(QPointF(leftMargin, (height() - wholeTextSize.height()) / 2), staticText); } } -void ScrollText::resizeEvent(QResizeEvent*) +void ScrollText::resizeEvent(QResizeEvent *) { //When the widget is resized, we need to update the alpha channel. @@ -104,31 +98,28 @@ void ScrollText::resizeEvent(QResizeEvent*) buffer = QImage(size(), QImage::Format_ARGB32_Premultiplied); //Create Alpha Channel: - if(width() > 64) - { + if (width() > 64) { //create first scanline - QRgb* scanline1 = reinterpret_cast(alphaChannel.scanLine(0)); - for(int x = 1; x < 16; ++x) + QRgb *scanline1 = reinterpret_cast(alphaChannel.scanLine(0)); + for (int x = 1; x < 16; ++x) scanline1[x - 1] = scanline1[width() - x] = qRgba(0, 0, 0, x << 4); - for(int x = 15; x < width() - 15; ++x) + for (int x = 15; x < width() - 15; ++x) scanline1[x] = qRgb(0, 0, 0); //copy scanline to the other ones - for(int y = 1; y < height(); ++y) + for (int y = 1; y < height(); ++y) memcpy(alphaChannel.scanLine(y), scanline1, static_cast(width() * 4)); } else alphaChannel.fill(qRgb(0, 0, 0)); - //Update scrolling state bool newScrollEnabled = (singleTextWidth > width() - leftMargin); - if(newScrollEnabled != scrollEnabled) + if (newScrollEnabled != scrollEnabled) updateText(); } void ScrollText::timer_timeout() { - scrollPos = (scrollPos + 2) - % wholeTextSize.width(); + scrollPos = (scrollPos + 2) % wholeTextSize.width(); update(); } diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index d986709..18da853 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -2,110 +2,108 @@ QString AOApplication::read_theme() { - QString result = configini->value("theme", "default").value(); - return result; + QString result = configini->value("theme", "default").value(); + return result; } int AOApplication::read_blip_rate() { - int result = configini->value("blip_rate", 2).toInt(); + int result = configini->value("blip_rate", 2).toInt(); - if (result < 1) - return 1; + if (result < 1) + return 1; - return result; + return result; } QString AOApplication::get_ooc_name() { - QString result = configini->value("ooc_name").value(); - return result; + QString result = configini->value("ooc_name").value(); + return result; } int AOApplication::get_default_music() { - int result = configini->value("default_music", 50).toInt(); - return result; + int result = configini->value("default_music", 50).toInt(); + return result; } int AOApplication::get_default_sfx() { - int result = configini->value("default_sfx", 50).toInt(); - return result; + int result = configini->value("default_sfx", 50).toInt(); + return result; } int AOApplication::get_default_blip() { - int result = configini->value("default_blip", 50).toInt(); - return result; + int result = configini->value("default_blip", 50).toInt(); + return result; } int AOApplication::get_max_log_size() { - int result = configini->value("log_maximum", 200).toInt(); - return result; + int result = configini->value("log_maximum", 200).toInt(); + return result; } bool AOApplication::get_log_goes_downwards() { - QString result = configini->value("log_goes_downwards", "true").value(); - return result.startsWith("true"); + QString result = configini->value("log_goes_downwards", "true").value(); + return result.startsWith("true"); } bool AOApplication::get_showname_enabled_by_default() { - QString result = configini->value("show_custom_shownames", "true").value(); - return result.startsWith("true"); + QString result = configini->value("show_custom_shownames", "true").value(); + return result.startsWith("true"); } QString AOApplication::get_default_username() { - QString result = configini->value("default_username", "").value(); - if (result.isEmpty()) - return get_ooc_name(); - else - return result; + QString result = configini->value("default_username", "").value(); + if (result.isEmpty()) + return get_ooc_name(); + else + return result; } QString AOApplication::get_audio_output_device() { - QString result = configini->value("default_audio_device", "default").value(); - return result; + QString result = configini->value("default_audio_device", "default").value(); + return result; } QStringList AOApplication::get_call_words() { - return get_list_file(get_base_path() + "callwords.ini"); + return get_list_file(get_base_path() + "callwords.ini"); } QStringList AOApplication::get_list_file(QString p_file) { - QStringList return_value; + QStringList return_value; - QFile p_ini; + QFile p_ini; - p_ini.setFileName(p_file); + p_ini.setFileName(p_file); + + if (!p_ini.open(QIODevice::ReadOnly)) + return return_value; + + QTextStream in(&p_ini); + + while (!in.atEnd()) { + QString line = in.readLine(); + return_value.append(line); + } - if (!p_ini.open(QIODevice::ReadOnly)) return return_value; - - QTextStream in(&p_ini); - - while (!in.atEnd()) - { - QString line = in.readLine(); - return_value.append(line); - } - - return return_value; } QString AOApplication::read_file(QString filename) { QFile f_log(filename); - if(!f_log.open(QIODevice::ReadOnly | QIODevice::Text)) - { + if (!f_log.open(QIODevice::ReadOnly | QIODevice::Text)) { qDebug() << "Couldn't open" << filename; return ""; } @@ -119,18 +117,16 @@ QString AOApplication::read_file(QString filename) bool AOApplication::write_to_file(QString p_text, QString p_file, bool make_dir) { QString path = QFileInfo(p_file).path(); - if(make_dir) - { - //Create the dir if it doesn't exist yet - QDir dir(path); - if (!dir.exists()) - if (!dir.mkpath(".")) - return false; + if (make_dir) { + //Create the dir if it doesn't exist yet + QDir dir(path); + if (!dir.exists()) + if (!dir.mkpath(".")) + return false; } QFile f_log(p_file); - if(f_log.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) - { + if (f_log.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) { QTextStream out(&f_log); out << p_text; @@ -146,20 +142,19 @@ bool AOApplication::append_to_file(QString p_text, QString p_file, bool make_dir { QString path = QFileInfo(p_file).path(); //Create the dir if it doesn't exist yet - if(make_dir) - { - QDir dir(path); - if (!dir.exists()) - if (!dir.mkpath(".")) - return false; + if (make_dir) { + QDir dir(path); + if (!dir.exists()) + if (!dir.mkpath(".")) + return false; } QFile f_log(p_file); - if(f_log.open(QIODevice::WriteOnly | QIODevice::Append)) - { + if (f_log.open(QIODevice::WriteOnly | QIODevice::Append)) { QTextStream out(&f_log); - out << "\r\n" << p_text; + out << "\r\n" + << p_text; f_log.flush(); f_log.close(); @@ -170,369 +165,354 @@ bool AOApplication::append_to_file(QString p_text, QString p_file, bool make_dir void AOApplication::write_to_serverlist_txt(QString p_line) { - QFile serverlist_txt; - QString serverlist_txt_path = get_base_path() + "serverlist.txt"; + QFile serverlist_txt; + QString serverlist_txt_path = get_base_path() + "serverlist.txt"; - serverlist_txt.setFileName(serverlist_txt_path); + serverlist_txt.setFileName(serverlist_txt_path); - if (!serverlist_txt.open(QIODevice::WriteOnly | QIODevice::Append)) - { - return; - } + if (!serverlist_txt.open(QIODevice::WriteOnly | QIODevice::Append)) { + return; + } - QTextStream out(&serverlist_txt); + QTextStream out(&serverlist_txt); - out << "\r\n" << p_line; + out << "\r\n" + << p_line; - serverlist_txt.close(); + serverlist_txt.close(); } QVector AOApplication::read_serverlist_txt() { - QVector f_server_list; + QVector f_server_list; - QFile serverlist_txt; - QString serverlist_txt_path = get_base_path() + "serverlist.txt"; + QFile serverlist_txt; + QString serverlist_txt_path = get_base_path() + "serverlist.txt"; - serverlist_txt.setFileName(serverlist_txt_path); + serverlist_txt.setFileName(serverlist_txt_path); + + if (!serverlist_txt.open(QIODevice::ReadOnly)) { + return f_server_list; + } + + QTextStream in(&serverlist_txt); + + while (!in.atEnd()) { + QString line = in.readLine(); + server_type f_server; + QStringList line_contents = line.split(":"); + + if (line_contents.size() < 3) + continue; + + f_server.ip = line_contents.at(0); + f_server.port = line_contents.at(1).toInt(); + f_server.name = line_contents.at(2); + f_server.desc = ""; + + f_server_list.append(f_server); + } - if (!serverlist_txt.open(QIODevice::ReadOnly)) - { return f_server_list; - } - - QTextStream in(&serverlist_txt); - - while(!in.atEnd()) - { - QString line = in.readLine(); - server_type f_server; - QStringList line_contents = line.split(":"); - - if (line_contents.size() < 3) - continue; - - f_server.ip = line_contents.at(0); - f_server.port = line_contents.at(1).toInt(); - f_server.name = line_contents.at(2); - f_server.desc = ""; - - f_server_list.append(f_server); - } - - return f_server_list; } QString AOApplication::read_design_ini(QString p_identifier, QString p_design_path) { - QSettings settings(p_design_path, QSettings::IniFormat); - QVariant value = settings.value(p_identifier); - if (value.type() == QVariant::StringList) { - return value.toStringList().join(","); - } else { - return value.toString(); - } + QSettings settings(p_design_path, QSettings::IniFormat); + QVariant value = settings.value(p_identifier); + if (value.type() == QVariant::StringList) { + return value.toStringList().join(","); + } + else { + return value.toString(); + } } 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 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); - QPoint return_value; + QPoint return_value; - return_value.setX(0); - return_value.setY(0); + return_value.setX(0); + return_value.setY(0); - if (f_result == "") - { - f_result = read_design_ini(p_identifier, default_path); + if (f_result == "") { + f_result = read_design_ini(p_identifier, default_path); - if (f_result == "") - return return_value; - } + if (f_result == "") + return return_value; + } - QStringList sub_line_elements = f_result.split(","); + QStringList sub_line_elements = f_result.split(","); + + if (sub_line_elements.size() < 2) + return return_value; + + return_value.setX(sub_line_elements.at(0).toInt()); + return_value.setY(sub_line_elements.at(1).toInt()); - if (sub_line_elements.size() < 2) return return_value; - - return_value.setX(sub_line_elements.at(0).toInt()); - return_value.setY(sub_line_elements.at(1).toInt()); - - return return_value; } pos_size_type AOApplication::get_element_dimensions(QString p_identifier, QString p_file, QString p_char) { - QString char_ini_path = get_base_path() + "misc/" + get_chat(p_char) + "/" + 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, char_ini_path); + QString char_ini_path = get_base_path() + "misc/" + get_chat(p_char) + "/" + 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, char_ini_path); - pos_size_type return_value; + pos_size_type return_value; - return_value.x = 0; - return_value.y = 0; - return_value.width = -1; - return_value.height = -1; + return_value.x = 0; + return_value.y = 0; + return_value.width = -1; + return_value.height = -1; - if (f_result == "") - { - 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 == "") { + 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 return_value; + if (f_result == "") + return return_value; + } } - } - QStringList sub_line_elements = f_result.split(","); + QStringList sub_line_elements = f_result.split(","); + + if (sub_line_elements.size() < 4) + return return_value; + + return_value.x = sub_line_elements.at(0).toInt(); + return_value.y = sub_line_elements.at(1).toInt(); + return_value.width = sub_line_elements.at(2).toInt(); + return_value.height = sub_line_elements.at(3).toInt(); - if (sub_line_elements.size() < 4) return return_value; - - return_value.x = sub_line_elements.at(0).toInt(); - return_value.y = sub_line_elements.at(1).toInt(); - return_value.width = sub_line_elements.at(2).toInt(); - return_value.height = sub_line_elements.at(3).toInt(); - - return return_value; } QString AOApplication::get_design_element(QString p_identifier, QString p_file, QString p_char) { - QString char_ini_path = get_base_path() + "misc/" + get_chat(p_char) + "/" + 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, char_ini_path); - if (f_result == "") - { - f_result = read_design_ini(p_identifier, design_ini_path); - if (f_result == "") - f_result = read_design_ini(p_identifier, default_path); - } - return f_result; + QString char_ini_path = get_base_path() + "misc/" + get_chat(p_char) + "/" + 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, char_ini_path); + if (f_result == "") { + f_result = read_design_ini(p_identifier, design_ini_path); + if (f_result == "") + f_result = read_design_ini(p_identifier, default_path); + } + return f_result; } QString AOApplication::get_font_name(QString p_identifier, QString p_file) { - 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 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; } 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); + 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 == "") { + f_result = read_design_ini(p_identifier, default_path); - if (f_result == "") - return 10; - } + if (f_result == "") + return 10; + } - return f_result.toInt(); + return f_result.toInt(); } 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 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); - QColor return_color(0, 0, 0); + QColor return_color(0, 0, 0); - if (f_result == "") - { - f_result = read_design_ini(p_identifier, default_path); + if (f_result == "") { + f_result = read_design_ini(p_identifier, default_path); - if (f_result == "") - return return_color; - } + if (f_result == "") + return return_color; + } - QStringList color_list = f_result.split(","); + QStringList color_list = f_result.split(","); + + if (color_list.size() < 3) + return return_color; + + return_color.setRed(color_list.at(0).toInt()); + return_color.setGreen(color_list.at(1).toInt()); + return_color.setBlue(color_list.at(2).toInt()); - if (color_list.size() < 3) return return_color; - - return_color.setRed(color_list.at(0).toInt()); - return_color.setGreen(color_list.at(1).toInt()); - return_color.setBlue(color_list.at(2).toInt()); - - return return_color; } 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 design_ini_path = get_theme_path(p_file); + QString default_path = get_default_theme_path(p_file); - QFile design_ini; + QFile design_ini; - design_ini.setFileName(design_ini_path); + design_ini.setFileName(design_ini_path); - if(!design_ini.open(QIODevice::ReadOnly)) - { - design_ini.setFileName(default_path); - if(!design_ini.open(QIODevice::ReadOnly)) - return ""; - } + if (!design_ini.open(QIODevice::ReadOnly)) { + design_ini.setFileName(default_path); + if (!design_ini.open(QIODevice::ReadOnly)) + return ""; + } - QTextStream in(&design_ini); + QTextStream in(&design_ini); - QString f_text; + QString f_text; - while(!in.atEnd()) - { - f_text.append(in.readLine()); - } + while (!in.atEnd()) { + f_text.append(in.readLine()); + } - design_ini.close(); - return f_text; + design_ini.close(); + return f_text; } QString AOApplication::get_tagged_stylesheet(QString target_tag, QString p_file) { - QString design_ini_path = get_theme_path(p_file); + QString design_ini_path = get_theme_path(p_file); - QFile design_ini; + QFile design_ini; - design_ini.setFileName(design_ini_path); + design_ini.setFileName(design_ini_path); - if(!design_ini.open(QIODevice::ReadOnly)) - return ""; + if (!design_ini.open(QIODevice::ReadOnly)) + return ""; - QTextStream in(&design_ini); + QTextStream in(&design_ini); - QString f_text; + QString f_text; - bool tag_found = false; + bool tag_found = false; - while(!in.atEnd()) - { - QString line = in.readLine(); + while (!in.atEnd()) { + QString line = in.readLine(); - if (line.startsWith(target_tag, Qt::CaseInsensitive)) - { - tag_found = true; - continue; + if (line.startsWith(target_tag, Qt::CaseInsensitive)) { + tag_found = true; + continue; + } + + if (tag_found) { + if ((line.startsWith("[") && line.endsWith("]"))) + break; + f_text.append(line); + } } - if(tag_found) - { - if((line.startsWith("[") && line.endsWith("]"))) - break; - f_text.append(line); - } - } - - design_ini.close(); - return f_text; + design_ini.close(); + return f_text; } QString AOApplication::get_chat_markdown(QString p_identifier, QString p_chat) { - QString design_ini_path = get_base_path() + "misc/" + p_chat + "/config.ini"; - QString default_path = get_base_path() + "misc/default/config.ini"; - QString f_result = read_design_ini(p_identifier, design_ini_path); + QString design_ini_path = get_base_path() + "misc/" + p_chat + "/config.ini"; + QString default_path = get_base_path() + "misc/default/config.ini"; + 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 == "") + f_result = read_design_ini(p_identifier, default_path); - return f_result.toLatin1(); + return f_result.toLatin1(); } QColor AOApplication::get_chat_color(QString p_identifier, QString p_chat) { - QColor return_color(255, 255, 255); + QColor return_color(255, 255, 255); - switch (p_identifier.toInt()) { + switch (p_identifier.toInt()) { case 0: //White - return_color = QColor(255, 255, 255); - break; + return_color = QColor(255, 255, 255); + break; case 1: //Green - return_color = QColor(0, 255, 0); - break; + return_color = QColor(0, 255, 0); + break; case 2: //Red - return_color = QColor(255, 0, 0); - break; + return_color = QColor(255, 0, 0); + break; case 3: //Orange - return_color = QColor(255, 165, 0); - break; + return_color = QColor(255, 165, 0); + break; case 4: //Blue - return_color = QColor(45, 150, 255); - break; + return_color = QColor(45, 150, 255); + break; case 5: //Yellow - return_color = QColor(255, 255, 0); - break; + return_color = QColor(255, 255, 0); + break; case 6: //Pink - return_color = QColor(255, 192, 203); - break; + return_color = QColor(255, 192, 203); + break; case 7: //Cyan - return_color = QColor(0, 255, 255); - break; + return_color = QColor(0, 255, 255); + break; case 8: //Grey - return_color = QColor(187, 187, 187); - break; + return_color = QColor(187, 187, 187); + break; default: - return_color = QColor(255, 255, 255); - break; - } - QString design_ini_path = get_base_path() + "misc/" + p_chat + "/config.ini"; - QString default_path = get_base_path() + "misc/default/config.ini"; - QString f_result = read_design_ini("c" + p_identifier, design_ini_path); + return_color = QColor(255, 255, 255); + break; + } + QString design_ini_path = get_base_path() + "misc/" + p_chat + "/config.ini"; + QString default_path = get_base_path() + "misc/default/config.ini"; + QString f_result = read_design_ini("c" + p_identifier, design_ini_path); - if (f_result == "") - { - f_result = read_design_ini(p_identifier, default_path); + if (f_result == "") { + f_result = read_design_ini(p_identifier, default_path); - if (f_result == "") - return return_color; - } + if (f_result == "") + return return_color; + } - QStringList color_list = f_result.split(","); + QStringList color_list = f_result.split(","); + + if (color_list.size() < 3) + return return_color; + + return_color.setRed(color_list.at(0).toInt()); + return_color.setGreen(color_list.at(1).toInt()); + return_color.setBlue(color_list.at(2).toInt()); - if (color_list.size() < 3) return return_color; - - return_color.setRed(color_list.at(0).toInt()); - return_color.setGreen(color_list.at(1).toInt()); - return_color.setBlue(color_list.at(2).toInt()); - - return return_color; } QString AOApplication::get_sfx(QString p_identifier) { - QString design_ini_path = get_theme_path("courtroom_sounds.ini"); - QString default_path = get_default_theme_path("courtroom_sounds.ini"); - QString f_result = read_design_ini(p_identifier, design_ini_path); + QString design_ini_path = get_theme_path("courtroom_sounds.ini"); + QString default_path = get_default_theme_path("courtroom_sounds.ini"); + QString f_result = read_design_ini(p_identifier, design_ini_path); - QString return_sfx = ""; + QString return_sfx = ""; - if (f_result == "") - { - f_result = read_design_ini(p_identifier, default_path); + if (f_result == "") { + f_result = read_design_ini(p_identifier, default_path); - if (f_result == "") - return return_sfx; - } + if (f_result == "") + return return_sfx; + } - return_sfx = f_result; + return_sfx = f_result; - return return_sfx; + return return_sfx; } QString AOApplication::get_sfx_suffix(QString sound_to_check) @@ -572,381 +552,368 @@ QString AOApplication::get_static_image_suffix(QString path_to_check) //returns the empty string if the search line couldnt be found QString AOApplication::read_char_ini(QString p_char, QString p_search_line, QString target_tag) { - QSettings settings(get_character_path(p_char, "char.ini"), QSettings::IniFormat); - settings.beginGroup(target_tag); - QString value = settings.value(p_search_line).toString(); - settings.endGroup(); - return value; + QSettings settings(get_character_path(p_char, "char.ini"), QSettings::IniFormat); + settings.beginGroup(target_tag); + QString value = settings.value(p_search_line).toString(); + settings.endGroup(); + return value; } void AOApplication::set_char_ini(QString p_char, QString value, QString p_search_line, QString target_tag) { - QSettings settings(get_character_path(p_char, "char.ini"), QSettings::IniFormat); - settings.beginGroup(target_tag); - settings.setValue(p_search_line, value); - settings.endGroup(); + QSettings settings(get_character_path(p_char, "char.ini"), QSettings::IniFormat); + settings.beginGroup(target_tag); + settings.setValue(p_search_line, value); + settings.endGroup(); } //returns all the values of target_tag QStringList AOApplication::read_ini_tags(QString p_path, QString target_tag) { - QStringList r_values; - QSettings settings(p_path, QSettings::IniFormat); - if (!target_tag.isEmpty()) - settings.beginGroup(target_tag); - QStringList keys = settings.allKeys(); - foreach (QString key, keys) - { - QString value = settings.value(key).toString(); - r_values << key + "=" + value; - } - if (!settings.group().isEmpty()) - settings.endGroup(); - return r_values; + QStringList r_values; + QSettings settings(p_path, QSettings::IniFormat); + if (!target_tag.isEmpty()) + settings.beginGroup(target_tag); + QStringList keys = settings.allKeys(); + foreach (QString key, keys) { + QString value = settings.value(key).toString(); + r_values << key + "=" + value; + } + if (!settings.group().isEmpty()) + settings.endGroup(); + return r_values; } QString AOApplication::get_char_name(QString p_char) { - QString f_result = read_char_ini(p_char, "name", "Options"); + QString f_result = read_char_ini(p_char, "name", "Options"); - if (f_result == "") - return p_char; - return f_result; + if (f_result == "") + return p_char; + return f_result; } QString AOApplication::get_showname(QString p_char) { - QString f_result = read_char_ini(p_char, "showname", "Options"); - QString f_needed = read_char_ini(p_char, "needs_showname", "Options"); + QString f_result = read_char_ini(p_char, "showname", "Options"); + QString f_needed = read_char_ini(p_char, "needs_showname", "Options"); - if (f_needed.startsWith("false")) - return ""; - if (f_result == "") - return p_char; - return f_result; + if (f_needed.startsWith("false")) + return ""; + if (f_result == "") + return p_char; + return f_result; } QString AOApplication::get_char_side(QString p_char) { - QString f_result = read_char_ini(p_char, "side", "Options"); + QString f_result = read_char_ini(p_char, "side", "Options"); - if (f_result == "") - return "wit"; - return f_result; + if (f_result == "") + return "wit"; + return f_result; } QString AOApplication::get_gender(QString p_char) { - QString f_result = read_char_ini(p_char, "gender", "Options"); + QString f_result = read_char_ini(p_char, "gender", "Options"); - if (f_result == "") - return "sfx-blipmale"; + if (f_result == "") + return "sfx-blipmale"; - if (!file_exists(get_sfx_suffix(get_sounds_path(f_result)))) - { - if (file_exists(get_sfx_suffix(get_sounds_path("../blips/" + f_result)))) - return "../blips/" + f_result; //Return the cool kids variant + if (!file_exists(get_sfx_suffix(get_sounds_path(f_result)))) { + if (file_exists(get_sfx_suffix(get_sounds_path("../blips/" + f_result)))) + return "../blips/" + f_result; //Return the cool kids variant - return "sfx-blip" + f_result; //Return legacy variant - } - return f_result; + return "sfx-blip" + f_result; //Return legacy variant + } + return f_result; } QString AOApplication::get_chat(QString p_char) { - QString f_result = read_char_ini(p_char, "chat", "Options"); + 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; + //handling the correct order of chat is a bit complicated, we let the caller do it + return f_result; } QString AOApplication::get_chat_font(QString p_char) { - QString f_result = read_char_ini(p_char, "chat_font", "Options"); + QString f_result = read_char_ini(p_char, "chat_font", "Options"); - return f_result; + return f_result; } int AOApplication::get_chat_size(QString p_char) { - QString f_result = read_char_ini(p_char, "chat_size", "Options"); + QString f_result = read_char_ini(p_char, "chat_size", "Options"); - if (f_result == "") - return -1; - return f_result.toInt(); + if (f_result == "") + return -1; + 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 "default"; - return f_result; + QString f_result = read_char_ini(p_char, "shouts", "Options"); + if (f_result == "") + return "default"; + 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"); + QString f_result = read_char_ini(p_char, p_emote, "Time"); - if (f_result == "") - return -1; - return f_result.toInt(); + if (f_result == "") + return -1; + return f_result.toInt(); } int AOApplication::get_ao2_preanim_duration(QString p_char, QString p_emote) { - QString f_result = read_char_ini(p_char, "%" + p_emote, "Time"); + QString f_result = read_char_ini(p_char, "%" + p_emote, "Time"); - if (f_result == "") - return -1; - return f_result.toInt(); + if (f_result == "") + return -1; + return f_result.toInt(); } int AOApplication::get_emote_number(QString p_char) { - QString f_result = read_char_ini(p_char, "number", "Emotions"); + QString f_result = read_char_ini(p_char, "number", "Emotions"); - if (f_result == "") - return 0; - return f_result.toInt(); + if (f_result == "") + return 0; + return f_result.toInt(); } QString AOApplication::get_emote_comment(QString p_char, int p_emote) { - QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); + QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); - QStringList result_contents = f_result.split("#"); + QStringList result_contents = f_result.split("#"); - if (result_contents.size() < 4) - { - qDebug() << "W: misformatted char.ini: " << p_char << ", " << p_emote; - return "normal"; - } - return result_contents.at(0); + if (result_contents.size() < 4) { + qDebug() << "W: misformatted char.ini: " << p_char << ", " << p_emote; + return "normal"; + } + return result_contents.at(0); } QString AOApplication::get_pre_emote(QString p_char, int p_emote) { - QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); + QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); - QStringList result_contents = f_result.split("#"); + QStringList result_contents = f_result.split("#"); - if (result_contents.size() < 4) - { - qDebug() << "W: misformatted char.ini: " << p_char << ", " << p_emote; - return ""; - } - return result_contents.at(1); + if (result_contents.size() < 4) { + qDebug() << "W: misformatted char.ini: " << p_char << ", " << p_emote; + return ""; + } + return result_contents.at(1); } QString AOApplication::get_emote(QString p_char, int p_emote) { - QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); + QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); - QStringList result_contents = f_result.split("#"); + QStringList result_contents = f_result.split("#"); - if (result_contents.size() < 4) - { - qDebug() << "W: misformatted char.ini: " << p_char << ", " << p_emote; - return "normal"; - } - return result_contents.at(2); + if (result_contents.size() < 4) { + qDebug() << "W: misformatted char.ini: " << p_char << ", " << p_emote; + return "normal"; + } + return result_contents.at(2); } int AOApplication::get_emote_mod(QString p_char, int p_emote) { - QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); + QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); - QStringList result_contents = f_result.split("#"); + QStringList result_contents = f_result.split("#"); - if (result_contents.size() < 4) - { - qDebug() << "W: misformatted char.ini: " << p_char << ", " << QString::number(p_emote); - return 0; - } - return result_contents.at(3).toInt(); + if (result_contents.size() < 4) { + qDebug() << "W: misformatted char.ini: " << p_char << ", " << QString::number(p_emote); + return 0; + } + return result_contents.at(3).toInt(); } int AOApplication::get_desk_mod(QString p_char, int p_emote) { - QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); + QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); - QStringList result_contents = f_result.split("#"); + QStringList result_contents = f_result.split("#"); - if (result_contents.size() < 5) - return -1; + if (result_contents.size() < 5) + return -1; - QString string_result = result_contents.at(4); - if (string_result == "") - return -1; + QString string_result = result_contents.at(4); + if (string_result == "") + return -1; - return string_result.toInt(); + return string_result.toInt(); } QString AOApplication::get_sfx_name(QString p_char, int p_emote) { - QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "SoundN"); + QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "SoundN"); - if (f_result == "") - return "1"; - return f_result; + if (f_result == "") + return "1"; + return f_result; } QString AOApplication::get_emote_blip(QString p_char, int p_emote) { - QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "SoundB"); - return f_result; + QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "SoundB"); + return f_result; } int AOApplication::get_sfx_delay(QString p_char, int p_emote) { - QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "SoundT"); + QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "SoundT"); - if (f_result == "") - return 1; - return f_result.toInt(); + if (f_result == "") + return 1; + return f_result.toInt(); } QString AOApplication::get_sfx_looping(QString p_char, QString p_sfx) { - QString f_result = read_char_ini(p_char, p_sfx, "SoundL"); + QString f_result = read_char_ini(p_char, p_sfx, "SoundL"); - if (f_result == "") - return "0"; - return f_result; + if (f_result == "") + return "0"; + return f_result; } QString AOApplication::get_sfx_frame(QString p_char, QString p_emote, int n_frame) { - QString f_result = read_char_ini(p_char, QString::number(n_frame), p_emote.append("_FrameSFX")); + QString f_result = read_char_ini(p_char, QString::number(n_frame), p_emote.append("_FrameSFX")); - if (f_result == "") - return ""; - return f_result; + if (f_result == "") + return ""; + return f_result; } QString AOApplication::get_screenshake_frame(QString p_char, QString p_emote, int n_frame) { - QString f_result = read_char_ini(p_char, QString::number(n_frame), p_emote.append("_FrameScreenshake")); + QString f_result = read_char_ini(p_char, QString::number(n_frame), p_emote.append("_FrameScreenshake")); - if (f_result == "") - return ""; - return f_result; + if (f_result == "") + return ""; + return f_result; } QString AOApplication::get_flash_frame(QString p_char, QString p_emote, int n_frame) { - QString f_result = read_char_ini(p_char, QString::number(n_frame), p_emote.append("_FrameRealization")); + QString f_result = read_char_ini(p_char, QString::number(n_frame), p_emote.append("_FrameRealization")); - if (f_result == "") - return ""; - return f_result; + if (f_result == "") + return ""; + return f_result; } int AOApplication::get_text_delay(QString p_char, QString p_emote) { - QString f_result = read_char_ini(p_char, p_emote, "TextDelay"); + QString f_result = read_char_ini(p_char, p_emote, "TextDelay"); - if (f_result == "") - return -1; - return f_result.toInt(); + if (f_result == "") + return -1; + return f_result.toInt(); } QStringList AOApplication::get_theme_effects() { - QString p_path = get_theme_path("effects/effects.ini"); - QString default_path = get_default_theme_path("effects/effects.ini"); + QString p_path = get_theme_path("effects/effects.ini"); + QString default_path = get_default_theme_path("effects/effects.ini"); - QStringList effects; - if (!file_exists(p_path)) - { - p_path = default_path; - if (!file_exists(p_path)) - return effects; - } + 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(); - if (!effect.isEmpty() && !effects.contains(effect)) - effects.append(effect); - } - return effects; + QStringList lines = read_file(p_path).split("\n"); + foreach (QString effect, lines) { + effect = effect.split("=")[0].trimmed(); + if (!effect.isEmpty() && !effects.contains(effect)) + effects.append(effect); + } + 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"; + 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(); + if (!effect.isEmpty() && !effects.contains(effect)) + effects.append(effect); + } - 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(); - if (!effect.isEmpty() && !effects.contains(effect)) - effects.append(effect); - } - - return effects; } 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_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)); + 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 ""; - } + 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 ""; + } + } } - } - return p_path; + return p_path; } QString AOApplication::get_effect_sound(QString fx_name, QString p_char) { - 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 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(fx_name, p_path); - if (f_result == "") - { - f_result = read_design_ini(fx_name, design_ini_path); - if (f_result == "") - { - f_result = read_design_ini(fx_name, default_path); + QString f_result = read_design_ini(fx_name, p_path); + if (f_result == "") { + f_result = read_design_ini(fx_name, design_ini_path); + if (f_result == "") { + f_result = read_design_ini(fx_name, default_path); + } } - } - return f_result; + return f_result; } QString AOApplication::get_custom_realization(QString p_char) { - QString f_result = read_char_ini(p_char, "realization", "Options"); + 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)); + if (f_result == "") + return get_sfx("realization"); + else + return get_sfx_suffix(get_sounds_path(f_result)); } bool AOApplication::get_blank_blip() @@ -1047,8 +1014,8 @@ bool AOApplication::get_casing_juror_enabled() bool AOApplication::get_casing_steno_enabled() { - QString result = configini->value("casing_steno_enabled", "false").value(); - return result.startsWith("true"); + QString result = configini->value("casing_steno_enabled", "false").value(); + return result.startsWith("true"); } bool AOApplication::get_casing_cm_enabled() @@ -1059,6 +1026,6 @@ bool AOApplication::get_casing_cm_enabled() QString AOApplication::get_casing_can_host_cases() { - QString result = configini->value("casing_can_host_cases", "Turnabout Check Your Settings").value(); - return result; + QString result = configini->value("casing_can_host_cases", "Turnabout Check Your Settings").value(); + return result; } From 88de4cde0433ef5e606f38a2f1e6041f0d24a87e Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Fri, 22 May 2020 02:14:54 +0300 Subject: [PATCH 174/268] clang 2 electric boogaloo { BasedOnStyle: LLVM, BreakBeforeBraces: Stroustrup} --- include/aoapplication.h | 559 +-- include/aoblipplayer.h | 26 +- include/aobutton.h | 10 +- include/aocaseannouncerdialog.h | 34 +- include/aocharbutton.h | 33 +- include/aocharmovie.h | 143 +- include/aoemotebutton.h | 23 +- include/aoevidencebutton.h | 45 +- include/aoevidencedisplay.h | 22 +- include/aoimage.h | 16 +- include/aolineedit.h | 14 +- include/aomovie.h | 27 +- include/aomusicplayer.h | 69 +- include/aooptionsdialog.h | 185 +- include/aopacket.h | 26 +- include/aoscene.h | 39 +- include/aosfxplayer.h | 33 +- include/aotextarea.h | 13 +- include/aotextedit.h | 10 +- include/bass.h | 860 ++-- include/bassopus.h | 32 +- include/chatlogpiece.h | 32 +- include/courtroom.h | 1098 ++--- include/datatypes.h | 148 +- include/discord-rpc.h | 56 +- include/discord_register.h | 6 +- include/discord_rich_presence.h | 28 +- include/discord_rpc.h | 56 +- include/hex_functions.h | 4 +- include/lobby.h | 116 +- include/networkmanager.h | 70 +- include/scrolltext.h | 46 +- src/aoapplication.cpp | 181 +- src/aoblipplayer.cpp | 110 +- src/aobutton.cpp | 44 +- src/aocaseannouncerdialog.cpp | 115 +- src/aocharbutton.cpp | 116 +- src/aocharmovie.cpp | 402 +- src/aoemotebutton.cpp | 50 +- src/aoevidencebutton.cpp | 124 +- src/aoevidencedisplay.cpp | 85 +- src/aoimage.cpp | 56 +- src/aolineedit.cpp | 19 +- src/aomovie.cpp | 114 +- src/aomusicplayer.cpp | 269 +- src/aooptionsdialog.cpp | 1152 ++--- src/aopacket.cpp | 74 +- src/aoscene.cpp | 176 +- src/aosfxplayer.cpp | 214 +- src/aotextarea.cpp | 84 +- src/aotextedit.cpp | 13 +- src/charselect.cpp | 350 +- src/chatlogpiece.cpp | 92 +- src/courtroom.cpp | 7153 ++++++++++++++++--------------- src/debug_functions.cpp | 23 +- src/discord_rich_presence.cpp | 199 +- src/emotes.cpp | 230 +- src/encryption_functions.cpp | 68 +- src/evidence.cpp | 1110 ++--- src/file_functions.cpp | 12 +- src/hardware_functions.cpp | 75 +- src/hex_functions.cpp | 22 +- src/lobby.cpp | 682 +-- src/main.cpp | 55 +- src/misc_functions.cpp | 6 +- src/networkmanager.cpp | 276 +- src/packet_distribution.cpp | 1221 +++--- src/path_functions.cpp | 150 +- src/scrolltext.cpp | 164 +- src/text_file_functions.cpp | 1221 +++--- 70 files changed, 10620 insertions(+), 9766 deletions(-) diff --git a/include/aoapplication.h b/include/aoapplication.h index ff75e4d..d9e84fa 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -32,402 +32,415 @@ class Lobby; class Courtroom; class AOApplication : public QApplication { - Q_OBJECT + Q_OBJECT public: - AOApplication(int &argc, char **argv); - ~AOApplication(); + AOApplication(int &argc, char **argv); + ~AOApplication(); - NetworkManager *net_manager; - Lobby *w_lobby; - Courtroom *w_courtroom; - AttorneyOnline::Discord *discord; + NetworkManager *net_manager; + Lobby *w_lobby; + Courtroom *w_courtroom; + AttorneyOnline::Discord *discord; - bool lobby_constructed = false; - bool courtroom_constructed = false; + bool lobby_constructed = false; + bool courtroom_constructed = false; - void construct_lobby(); - void destruct_lobby(); + void construct_lobby(); + void destruct_lobby(); - void construct_courtroom(); - void destruct_courtroom(); + void construct_courtroom(); + void destruct_courtroom(); - void ms_packet_received(AOPacket *p_packet); - void server_packet_received(AOPacket *p_packet); + void ms_packet_received(AOPacket *p_packet); + void server_packet_received(AOPacket *p_packet); - void send_ms_packet(AOPacket *p_packet); - void send_server_packet(AOPacket *p_packet, bool encoded = true); + void send_ms_packet(AOPacket *p_packet); + void send_server_packet(AOPacket *p_packet, bool encoded = true); - void call_settings_menu(); - void call_announce_menu(Courtroom *court); + void call_settings_menu(); + void call_announce_menu(Courtroom *court); - /////////////////server metadata////////////////// + /////////////////server metadata////////////////// - unsigned int s_decryptor = 5; - bool encryption_needed = true; + unsigned int s_decryptor = 5; + bool encryption_needed = true; - bool yellow_text_enabled = false; - bool prezoom_enabled = false; - bool flipping_enabled = false; - bool custom_objection_enabled = false; - bool improved_loading_enabled = false; - bool desk_mod_enabled = false; - bool evidence_enabled = false; - bool cccc_ic_support_enabled = false; - bool arup_enabled = false; - bool casing_alerts_enabled = false; - bool modcall_reason_enabled = false; - bool looping_sfx_support_enabled = false; - bool additive_enabled = false; - bool effects_enabled = false; + bool yellow_text_enabled = false; + bool prezoom_enabled = false; + bool flipping_enabled = false; + bool custom_objection_enabled = false; + bool improved_loading_enabled = false; + bool desk_mod_enabled = false; + bool evidence_enabled = false; + bool cccc_ic_support_enabled = false; + bool arup_enabled = false; + bool casing_alerts_enabled = false; + bool modcall_reason_enabled = false; + bool looping_sfx_support_enabled = false; + bool additive_enabled = false; + bool effects_enabled = false; - ///////////////loading info/////////////////// + ///////////////loading info/////////////////// - //player number, it's hardly used but might be needed for some old servers - int s_pv = 0; + // player number, it's hardly used but might be needed for some old servers + int s_pv = 0; - QString server_software = ""; + QString server_software = ""; - int char_list_size = 0; - int loaded_chars = 0; - int generated_chars = 0; - int evidence_list_size = 0; - int loaded_evidence = 0; - int music_list_size = 0; - int loaded_music = 0; + int char_list_size = 0; + int loaded_chars = 0; + int generated_chars = 0; + int evidence_list_size = 0; + int loaded_evidence = 0; + int music_list_size = 0; + int loaded_music = 0; - bool courtroom_loaded = false; + bool courtroom_loaded = false; - //////////////////versioning/////////////// + //////////////////versioning/////////////// - int get_release() const { return RELEASE; } - int get_major_version() const { return MAJOR_VERSION; } - int get_minor_version() const { return MINOR_VERSION; } - QString get_version_string(); + int get_release() const { return RELEASE; } + int get_major_version() const { return MAJOR_VERSION; } + int get_minor_version() const { return MINOR_VERSION; } + QString get_version_string(); - /////////////////////////////////////////// + /////////////////////////////////////////// - void set_favorite_list(); - QVector &get_favorite_list() { return favorite_list; } - void add_favorite_server(int p_server); + void set_favorite_list(); + QVector &get_favorite_list() { return favorite_list; } + void add_favorite_server(int p_server); - void set_server_list(); - QVector &get_server_list() { return server_list; } + void set_server_list(); + QVector &get_server_list() { return server_list; } - //reads the theme from config.ini and sets it accordingly - void reload_theme(); + // reads the theme from config.ini and sets it accordingly + void reload_theme(); - //Returns the character the player has currently selected - QString get_current_char(); + // Returns the character the player has currently selected + QString get_current_char(); - //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_character_path(QString p_char, QString p_file); - QString get_sounds_path(QString p_file); - QString get_music_path(QString p_song); - QString get_background_path(QString p_file); - QString get_default_background_path(QString p_file); - QString get_evidence_path(QString p_file); - QString get_case_sensitive_path(QString p_file); + // 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_character_path(QString p_char, QString p_file); + QString get_sounds_path(QString p_file); + QString get_music_path(QString p_song); + QString get_background_path(QString p_file); + QString get_default_background_path(QString p_file); + QString get_evidence_path(QString p_file); + QString get_case_sensitive_path(QString p_file); - ////// Functions for reading and writing files ////// - // Implementations file_functions.cpp + ////// Functions for reading and writing files ////// + // Implementations file_functions.cpp - // Instead of reinventing the wheel, we'll use a QSettings class. - QSettings *configini; + // Instead of reinventing the wheel, we'll use a QSettings class. + QSettings *configini; - //Reads the theme from config.ini and loads it into the current_theme variable - QString read_theme(); + // Reads the theme from config.ini and loads it into the current_theme + // variable + QString read_theme(); - //Returns the value of ooc_name in config.ini - QString get_ooc_name(); + // Returns the value of ooc_name in config.ini + QString get_ooc_name(); - //Returns the blip rate from config.ini (once per X symbols) - int read_blip_rate(); + // Returns the blip rate from config.ini (once per X symbols) + int read_blip_rate(); - //Returns true if blank blips is enabled in config.ini and false otherwise - bool get_blank_blip(); + // Returns true if blank blips is enabled in config.ini and false otherwise + bool get_blank_blip(); - //Returns true if looping sound effects are enabled in the config.ini - bool get_looping_sfx(); + // Returns true if looping sound effects are enabled in the config.ini + bool get_looping_sfx(); - //Returns true if stop music on objection is enabled in the config.ini - bool objection_stop_music(); + // Returns true if stop music on objection is enabled in the config.ini + bool objection_stop_music(); - //Returns the value of default_music in config.ini - int get_default_music(); + // Returns the value of default_music in config.ini + int get_default_music(); - //Returns the value of default_sfx in config.ini - int get_default_sfx(); + // Returns the value of default_sfx in config.ini + int get_default_sfx(); - //Returns the value of default_blip in config.ini - int get_default_blip(); + // Returns the value of default_blip in config.ini + int get_default_blip(); - // Returns the value of whether Discord should be enabled on startup - // from the config.ini. - bool is_discord_enabled(); + // Returns the value of whether Discord should be enabled on startup + // from the config.ini. + bool is_discord_enabled(); - // Returns the value of whether shaking should be enabled. - // from the config.ini. - bool is_shake_enabled(); + // Returns the value of whether shaking should be enabled. + // from the config.ini. + bool is_shake_enabled(); - // Returns the value of whether effects should be enabled. - // from the config.ini. - bool is_effects_enabled(); + // Returns the value of whether effects should be enabled. + // from the config.ini. + bool is_effects_enabled(); - // Returns the value of whether frame-specific effects defined in char.ini should be sent/received over the network. - // from the config.ini. - bool is_frame_network_enabled(); + // Returns the value of whether frame-specific effects defined in char.ini + // should be sent/received over the network. from the config.ini. + bool is_frame_network_enabled(); - // Returns the value of whether colored ic log should be a thing. - // from the config.ini. - bool is_colorlog_enabled(); + // Returns the value of whether colored ic log should be a thing. + // from the config.ini. + bool is_colorlog_enabled(); - // Returns the value of whether sticky sounds should be a thing. - // from the config.ini. - bool is_stickysounds_enabled(); + // Returns the value of whether sticky sounds should be a thing. + // from the config.ini. + bool is_stickysounds_enabled(); - // Returns the value of whether sticky effects should be a thing. - // from the config.ini. - bool is_stickyeffects_enabled(); + // Returns the value of whether sticky effects should be a thing. + // from the config.ini. + bool is_stickyeffects_enabled(); - // Returns the value of whether sticky preanims should be a thing. - // from the config.ini. - bool is_stickypres_enabled(); + // Returns the value of whether sticky preanims should be a thing. + // from the config.ini. + bool is_stickypres_enabled(); - // Returns the value of the maximum amount of lines the IC chatlog - // may contain, from config.ini. - int get_max_log_size(); + // Returns the value of the maximum amount of lines the IC chatlog + // may contain, from config.ini. + int get_max_log_size(); - // Returns whether the log should go upwards (new behaviour) - // or downwards (vanilla behaviour). - bool get_log_goes_downwards(); + // Returns whether the log should go upwards (new behaviour) + // or downwards (vanilla behaviour). + bool get_log_goes_downwards(); - // Returns the username the user may have set in config.ini. - QString get_default_username(); + // Returns the username the user may have set in config.ini. + QString get_default_username(); - // Returns the audio device used for the client. - QString get_audio_output_device(); + // Returns the audio device used for the client. + QString get_audio_output_device(); #ifdef QTAUDIO - QAudioDeviceInfo QtAudioDevice; + QAudioDeviceInfo QtAudioDevice; #endif - // Returns whether the user would like to have custom shownames on by default. - bool get_showname_enabled_by_default(); + // Returns whether the user would like to have custom shownames on by default. + bool get_showname_enabled_by_default(); - //Returns the list of words in callwords.ini - QStringList get_call_words(); + // Returns the list of words in callwords.ini + QStringList get_call_words(); - //returns all of the file's lines in a QStringList - QStringList get_list_file(QString p_file); + // returns all of the file's lines in a QStringList + QStringList get_list_file(QString p_file); - //Process a file and return its text as a QString - QString read_file(QString filename); + // Process a file and return its text as a QString + QString read_file(QString filename); - //Write text to file. make_dir would auto-create the directory if it doesn't exist. - bool write_to_file(QString p_text, QString p_file, bool make_dir = false); + // Write text to file. make_dir would auto-create the directory if it doesn't + // exist. + bool write_to_file(QString p_text, QString p_file, bool make_dir = false); - //Append text to the end of the file. make_dir would auto-create the directory if it doesn't exist. - bool append_to_file(QString p_text, QString p_file, bool make_dir = false); + // Append text to the end of the file. make_dir would auto-create the + // directory if it doesn't exist. + bool append_to_file(QString p_text, QString p_file, bool make_dir = false); - //Appends the argument string to serverlist.txt - void write_to_serverlist_txt(QString p_line); + // Appends the argument string to serverlist.txt + void write_to_serverlist_txt(QString p_line); - //Returns the contents of serverlist.txt - QVector read_serverlist_txt(); + // Returns the contents of serverlist.txt + QVector read_serverlist_txt(); - //Returns the value of p_identifier in the design.ini file in p_design_path - QString read_design_ini(QString p_identifier, QString p_design_path); + // Returns the value of p_identifier in the design.ini file in p_design_path + QString read_design_ini(QString p_identifier, QString p_design_path); - //Returns the coordinates of widget with p_identifier from p_file - QPoint get_button_spacing(QString p_identifier, QString p_file); + // Returns the coordinates of widget with p_identifier from p_file + QPoint get_button_spacing(QString p_identifier, QString p_file); - //Returns the dimensions of widget with specified identifier from p_file - pos_size_type get_element_dimensions(QString p_identifier, QString p_file, QString p_char = ""); + // Returns the dimensions of widget with specified identifier from p_file + pos_size_type get_element_dimensions(QString p_identifier, QString p_file, + QString p_char = ""); - //Returns the value to you - QString get_design_element(QString p_identifier, QString p_file, QString p_char = ""); + // 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); + // Returns the name of the font with p_identifier from p_file + QString get_font_name(QString p_identifier, QString p_file); - //Returns the value of font_size with p_identifier from p_file - int get_font_size(QString p_identifier, QString p_file); + // Returns the value of font_size with p_identifier from p_file + int get_font_size(QString p_identifier, QString p_file); - //Returns the color with p_identifier from p_file - QColor get_color(QString p_identifier, QString p_file); + // Returns the color with p_identifier from p_file + QColor get_color(QString p_identifier, QString p_file); - // Returns the markdown symbol used for specified p_identifier such as colors - QString get_chat_markdown(QString p_identifier, QString p_file); + // Returns the markdown symbol used for specified p_identifier such as colors + QString get_chat_markdown(QString p_identifier, QString p_file); - // Returns the color from the misc folder. - QColor get_chat_color(QString p_identifier, QString p_chat); + // 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); + // Returns the sfx with p_identifier from sounds.ini in the current theme path + QString get_sfx(QString p_identifier); - //Figure out if we can opus this or if we should fall back to wav - QString get_sfx_suffix(QString sound_to_check); + // 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); + // 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); + // 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); - //Returns the value of p_search_line within target_tag and terminator_tag - QString read_char_ini(QString p_char, QString p_search_line, QString target_tag); + // Returns the value of p_search_line within target_tag and terminator_tag + QString read_char_ini(QString p_char, QString p_search_line, + QString target_tag); - //Returns a QStringList of all key=value definitions on a given tag. - QStringList read_ini_tags(QString p_file, QString target_tag = ""); + // Returns a QStringList of all key=value definitions on a given tag. + QStringList read_ini_tags(QString p_file, QString target_tag = ""); - //Sets the char.ini p_search_line key under tag target_tag to value. - void set_char_ini(QString p_char, QString value, QString p_search_line, QString target_tag); + // Sets the char.ini p_search_line key under tag target_tag to value. + void set_char_ini(QString p_char, QString value, QString p_search_line, + QString target_tag); - //Returns the text between target_tag and terminator_tag in p_file - QString get_stylesheet(QString p_file); + // Returns the text between target_tag and terminator_tag in p_file + QString get_stylesheet(QString p_file); - //Returns the text between target_tag and terminator_tag in p_file - QString get_tagged_stylesheet(QString target_tag, QString p_file); + // Returns the text between target_tag and terminator_tag in p_file + QString get_tagged_stylesheet(QString target_tag, QString p_file); - //Returns the side of the p_char character from that characters ini file - QString get_char_side(QString p_char); + // Returns the side of the p_char character from that characters ini file + QString get_char_side(QString p_char); - //Returns the showname from the ini of p_char - QString get_showname(QString p_char); + // Returns the showname from the ini of p_char + QString get_showname(QString p_char); - //Returns the value of chat image from the specific p_char's ini file - QString get_chat(QString p_char); + // Returns the value of chat image from the specific p_char's ini file + QString get_chat(QString p_char); - //Returns the value of chat font from the specific p_char's ini file - QString get_chat_font(QString p_char); + // Returns the value of chat font from the specific p_char's ini file + QString get_chat_font(QString p_char); - //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 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 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); + // Returns the preanim duration of p_char's p_emote + int get_preanim_duration(QString p_char, QString p_emote); - //Same as above, but only returns if it has a % in front(refer to Preanims section in the manual) - int get_ao2_preanim_duration(QString p_char, QString p_emote); + // Same as above, but only returns if it has a % in front(refer to Preanims + // section in the manual) + int get_ao2_preanim_duration(QString p_char, QString p_emote); - //Not in use - int get_text_delay(QString p_char, QString p_emote); + // 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 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); + // Get the theme's effects folder, read it and return the list of filenames in + // a string + QStringList get_effects(QString p_char); - //t - QString get_effect(QString effect, QString p_char, QString p_folder); + // t + QString get_effect(QString effect, QString p_char, QString p_folder); - //Return the effect sound associated with the fx_name in the misc/effects//sounds.ini, or theme/effects/sounds.ini. - QString get_effect_sound(QString fx_name, QString p_char); + // Return the effect sound associated with the fx_name in the + // misc/effects//sounds.ini, or theme/effects/sounds.ini. + QString get_effect_sound(QString fx_name, QString p_char); - // Returns the custom realisation used by the character. - QString get_custom_realization(QString p_char); + // Returns the custom realisation used by the character. + QString get_custom_realization(QString p_char); - //Returns the name of p_char - QString get_char_name(QString p_char); + // 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); + // Returns the total amount of emotes of p_char + int get_emote_number(QString p_char); - //Returns the emote comment of p_char's p_emote - QString get_emote_comment(QString p_char, int p_emote); + // Returns the emote comment of p_char's p_emote + QString get_emote_comment(QString p_char, int p_emote); - //Returns the base name of p_char's p_emote - QString get_emote(QString p_char, int p_emote); + // Returns the base name of p_char's p_emote + QString get_emote(QString p_char, int p_emote); - //Returns the preanimation name of p_char's p_emote - QString get_pre_emote(QString p_char, int p_emote); + // Returns the preanimation name of p_char's p_emote + QString get_pre_emote(QString p_char, int p_emote); - //Returns the sfx of p_char's p_emote - QString get_sfx_name(QString p_char, int p_emote); + // Returns the sfx of p_char's p_emote + QString get_sfx_name(QString p_char, int p_emote); - //Returns the blipsound of p_char's p_emote - QString get_emote_blip(QString p_char, int p_emote); + // Returns the blipsound of p_char's p_emote + QString get_emote_blip(QString p_char, int p_emote); - //Returns if the sfx is defined as looping in char.ini - QString get_sfx_looping(QString p_char, QString p_sfx); + // Returns if the sfx is defined as looping in char.ini + QString get_sfx_looping(QString p_char, QString p_sfx); - //Returns if an emote has a frame specific SFX for it - QString get_sfx_frame(QString p_char, QString p_emote, int n_frame); + // Returns if an emote has a frame specific SFX for it + QString get_sfx_frame(QString p_char, QString p_emote, int n_frame); - //Returns if an emote has a frame specific SFX for it - QString get_flash_frame(QString p_char, QString p_emote, int n_frame); + // Returns if an emote has a frame specific SFX for it + QString get_flash_frame(QString p_char, QString p_emote, int n_frame); - //Returns if an emote has a frame specific SFX for it - QString get_screenshake_frame(QString p_char, QString p_emote, int n_frame); + // Returns if an emote has a frame specific SFX for it + QString get_screenshake_frame(QString p_char, QString p_emote, int n_frame); - //Not in use - int get_sfx_delay(QString p_char, int p_emote); + // Not in use + int get_sfx_delay(QString p_char, int p_emote); - //Returns the modifier for p_char's p_emote - int get_emote_mod(QString p_char, int p_emote); + // Returns the modifier for p_char's p_emote + int get_emote_mod(QString p_char, int p_emote); - //Returns the desk modifier for p_char's p_emote - int get_desk_mod(QString p_char, int p_emote); + // Returns the desk modifier for p_char's p_emote + int get_desk_mod(QString p_char, int p_emote); - //Returns p_char's gender - QString get_gender(QString p_char); + // Returns p_char's gender + QString get_gender(QString p_char); - // ====== - // These are all casing-related settings. - // ====== + // ====== + // These are all casing-related settings. + // ====== - // Returns if the user has casing alerts enabled. - bool get_casing_enabled(); + // Returns if the user has casing alerts enabled. + bool get_casing_enabled(); - // Returns if the user wants to get alerts for the defence role. - bool get_casing_defence_enabled(); + // Returns if the user wants to get alerts for the defence role. + bool get_casing_defence_enabled(); - // Same for prosecution. - bool get_casing_prosecution_enabled(); + // Same for prosecution. + bool get_casing_prosecution_enabled(); - // Same for judge. - bool get_casing_judge_enabled(); + // Same for judge. + bool get_casing_judge_enabled(); - // Same for juror. - bool get_casing_juror_enabled(); + // Same for juror. + bool get_casing_juror_enabled(); - // Same for steno. - bool get_casing_steno_enabled(); + // Same for steno. + bool get_casing_steno_enabled(); - // Same for CM. - bool get_casing_cm_enabled(); + // Same for CM. + bool get_casing_cm_enabled(); - // Get the message for the CM for casing alerts. - QString get_casing_can_host_cases(); + // Get the message for the CM for casing alerts. + QString get_casing_can_host_cases(); - //The file name of the log file in base/logs. - QString log_filename; + // The file name of the log file in base/logs. + QString log_filename; private: - const int RELEASE = 2; - const int MAJOR_VERSION = 8; - const int MINOR_VERSION = 3; + const int RELEASE = 2; + const int MAJOR_VERSION = 8; + const int MINOR_VERSION = 3; - QString current_theme = "default"; + QString current_theme = "default"; - QVector server_list; - QVector favorite_list; + QVector server_list; + QVector favorite_list; private slots: - void ms_connect_finished(bool connected, bool will_retry); + void ms_connect_finished(bool connected, bool will_retry); public slots: - void server_disconnected(); - void loading_cancelled(); + void server_disconnected(); + void loading_cancelled(); }; #endif // AOAPPLICATION_H diff --git a/include/aoblipplayer.h b/include/aoblipplayer.h index db6dfce..3a582a2 100644 --- a/include/aoblipplayer.h +++ b/include/aoblipplayer.h @@ -17,28 +17,28 @@ class AOBlipPlayer { public: - AOBlipPlayer(QWidget *parent, AOApplication *p_ao_app); + AOBlipPlayer(QWidget *parent, AOApplication *p_ao_app); - void set_blips(QString p_sfx); - void blip_tick(); - void set_volume(qreal p_volume); + void set_blips(QString p_sfx); + void blip_tick(); + void set_volume(qreal p_volume); - int m_cycle = 0; + int m_cycle = 0; private: - const int max_blip_ms = 60; + const int max_blip_ms = 60; - QWidget *m_parent; - AOApplication *ao_app; - qreal m_volume; - QElapsedTimer delay; + QWidget *m_parent; + AOApplication *ao_app; + qreal m_volume; + QElapsedTimer delay; - void set_volume_internal(qreal p_volume); + void set_volume_internal(qreal p_volume); #if defined(BASSAUDIO) - HSTREAM m_stream_list[5]; + HSTREAM m_stream_list[5]; #elif defined(QTAUDIO) - QSoundEffect m_blips; + QSoundEffect m_blips; #endif }; diff --git a/include/aobutton.h b/include/aobutton.h index 598d2c0..f575885 100644 --- a/include/aobutton.h +++ b/include/aobutton.h @@ -7,15 +7,15 @@ #include class AOButton : public QPushButton { - Q_OBJECT + Q_OBJECT public: - AOButton(QWidget *parent, AOApplication *p_ao_app); - ~AOButton(); + AOButton(QWidget *parent, AOApplication *p_ao_app); + ~AOButton(); - AOApplication *ao_app; + AOApplication *ao_app; - void set_image(QString p_image); + void set_image(QString p_image); }; #endif // AOBUTTON_H diff --git a/include/aocaseannouncerdialog.h b/include/aocaseannouncerdialog.h index 930fa41..0ac8f07 100644 --- a/include/aocaseannouncerdialog.h +++ b/include/aocaseannouncerdialog.h @@ -13,32 +13,34 @@ #include class AOCaseAnnouncerDialog : public QDialog { - Q_OBJECT + Q_OBJECT public: - explicit AOCaseAnnouncerDialog(QWidget *parent = nullptr, AOApplication *p_ao_app = nullptr, Courtroom *p_court = nullptr); + explicit AOCaseAnnouncerDialog(QWidget *parent = nullptr, + AOApplication *p_ao_app = nullptr, + Courtroom *p_court = nullptr); private: - AOApplication *ao_app; - Courtroom *court; + AOApplication *ao_app; + Courtroom *court; - QDialogButtonBox *ui_announcer_buttons; + QDialogButtonBox *ui_announcer_buttons; - QVBoxLayout *ui_vbox_layout; - QFormLayout *ui_form_layout; + QVBoxLayout *ui_vbox_layout; + QFormLayout *ui_form_layout; - QLabel *ui_case_title_label; - QLineEdit *ui_case_title_textbox; + QLabel *ui_case_title_label; + QLineEdit *ui_case_title_textbox; - QCheckBox *ui_defense_needed; - QCheckBox *ui_prosecutor_needed; - QCheckBox *ui_judge_needed; - QCheckBox *ui_juror_needed; - QCheckBox *ui_steno_needed; + QCheckBox *ui_defense_needed; + QCheckBox *ui_prosecutor_needed; + QCheckBox *ui_judge_needed; + QCheckBox *ui_juror_needed; + QCheckBox *ui_steno_needed; public slots: - void ok_pressed(); - void cancel_pressed(); + void ok_pressed(); + void cancel_pressed(); }; #endif // AOCASEANNOUNCERDIALOG_H diff --git a/include/aocharbutton.h b/include/aocharbutton.h index a536792..dd27e62 100644 --- a/include/aocharbutton.h +++ b/include/aocharbutton.h @@ -10,34 +10,35 @@ #include class AOCharButton : public QPushButton { - Q_OBJECT + Q_OBJECT public: - AOCharButton(QWidget *parent, AOApplication *p_ao_app, int x_pos, int y_pos, bool is_taken); + AOCharButton(QWidget *parent, AOApplication *p_ao_app, int x_pos, int y_pos, + bool is_taken); - AOApplication *ao_app; + AOApplication *ao_app; - void refresh(); - void reset(); - void set_taken(bool is_taken); - void set_passworded(); + void refresh(); + void reset(); + void set_taken(bool is_taken); + void set_passworded(); - void apply_taken_image(); + void apply_taken_image(); - void set_image(QString p_character); + void set_image(QString p_character); private: - bool taken; + bool taken; - QWidget *m_parent; + QWidget *m_parent; - AOImage *ui_taken; - AOImage *ui_passworded; - AOImage *ui_selector; + AOImage *ui_taken; + AOImage *ui_passworded; + AOImage *ui_selector; protected: - void enterEvent(QEvent *e); - void leaveEvent(QEvent *e); + void enterEvent(QEvent *e); + void leaveEvent(QEvent *e); }; #endif // AOCHARBUTTON_H diff --git a/include/aocharmovie.h b/include/aocharmovie.h index 2a185dd..2dda0ec 100644 --- a/include/aocharmovie.h +++ b/include/aocharmovie.h @@ -10,109 +10,116 @@ class AOApplication; class AOCharMovie : public QLabel { - Q_OBJECT + Q_OBJECT public: - AOCharMovie(QWidget *p_parent, AOApplication *p_ao_app); + AOCharMovie(QWidget *p_parent, AOApplication *p_ao_app); - //Play a hat.gif - style preanimation - void play_pre(QString p_char, QString p_emote, int duration); + // Play a hat.gif - style preanimation + void play_pre(QString p_char, QString p_emote, int duration); - //Play a (b)normal.gif - style animation (talking) - void play_talking(QString p_char, QString p_emote); + // Play a (b)normal.gif - style animation (talking) + void play_talking(QString p_char, QString p_emote); - //Play an (a)normal.gif - style animation (not talking) - void play_idle(QString p_char, QString p_emote); + // Play an (a)normal.gif - style animation (not talking) + void play_idle(QString p_char, QString p_emote); - //Stop the movie, clearing the image - void stop(); + // Stop the movie, clearing the image + void stop(); - //Set the m_flipped variable to true/false - void set_flipped(bool p_flipped) { m_flipped = p_flipped; } + // Set the m_flipped variable to true/false + void set_flipped(bool p_flipped) { m_flipped = p_flipped; } - //Set the movie's playback speed (between 10% and 1000%) - void set_speed(int modifier) { speed = qMax(10, qMin(modifier, 1000)); } + // Set the movie's playback speed (between 10% and 1000%) + void set_speed(int modifier) { speed = qMax(10, qMin(modifier, 1000)); } - //Move the label itself around - void move(int ax, int ay); + // Move the label itself around + void move(int ax, int ay); - //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); + // 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); - //Return the frame delay adjusted for speed - int get_frame_delay(int delay); + // Return the frame delay adjusted for speed + int get_frame_delay(int delay); - QStringList network_strings; + QStringList network_strings; - QString m_char; - QString m_emote; + QString m_char; + QString m_emote; private: - AOApplication *ao_app; + AOApplication *ao_app; - QVector movie_frames; - QVector movie_delays; + QVector movie_frames; + QVector movie_delays; - //Effects such as sfx, screenshakes and realization flashes are stored in here. - //QString entry format: "sfx^[sfx_name]", "shake", "flash". - //The program uses the QVector index as reference. - QVector> movie_effects; + // Effects such as sfx, screenshakes and realization flashes are stored in + // here. QString entry format: "sfx^[sfx_name]", "shake", "flash". The program + // uses the QVector index as reference. + QVector> movie_effects; - QTimer *preanim_timer; - QTimer *ticker; - QString last_path; - QImageReader *m_reader = new QImageReader(); + QTimer *preanim_timer; + QTimer *ticker; + QString last_path; + QImageReader *m_reader = new QImageReader(); - QElapsedTimer actual_time; + QElapsedTimer actual_time; - //Usually used to turn seconds into milliseconds such as for [Time] tag in char.ini - const int time_mod = 60; + // Usually used to turn seconds into milliseconds such as for [Time] tag in + // char.ini + const int time_mod = 60; - // These are the X and Y values before they are fixed based on the sprite's width. - int x = 0; - int y = 0; - // These are the width and height values before they are fixed based on the sprite's width. - int f_w = 0; - int f_h = 0; + // These are the X and Y values before they are fixed based on the sprite's + // width. + int x = 0; + int y = 0; + // These are the width and height values before they are fixed based on the + // sprite's width. + int f_w = 0; + int f_h = 0; - int frame = 0; - int max_frames = 0; + int frame = 0; + int max_frames = 0; - int speed = 100; + int speed = 100; - bool m_flipped = false; - bool play_once = true; + bool m_flipped = false; + bool play_once = true; - //Set the movie's image to provided paths, preparing for playback. - void load_image(QString p_char, QString p_emote, QString emote_prefix); + // Set the movie's image to provided paths, preparing for playback. + void load_image(QString p_char, QString p_emote, QString emote_prefix); - //Start playback of the movie (if animated). - void play(); + // Start playback of the movie (if animated). + void play(); - //Play a frame-specific effect, if there's any defined for that specific frame. - void play_frame_effect(int frame); + // Play a frame-specific effect, if there's any defined for that specific + // frame. + void play_frame_effect(int frame); - //Retreive a pixmap adjused for mirroring/aspect ratio shenanigans from a provided QImage - QPixmap get_pixmap(QImage image); + // 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); + // Set the movie's frame to provided pixmap + void set_frame(QPixmap f_pixmap); - //Initialize the frame-specific effects from the char.ini - void load_effects(); + // Initialize the frame-specific effects from the char.ini + void load_effects(); - //Initialize the frame-specific effects from the provided network_strings, this is only initialized if network_strings has size more than 0. - void load_network_effects(); + // Initialize the frame-specific effects from the provided network_strings, + // this is only initialized if network_strings has size more than 0. + void load_network_effects(); signals: - void done(); - void shake(); - void flash(); - void play_sfx(QString sfx); + void done(); + void shake(); + void flash(); + void play_sfx(QString sfx); private slots: - void preanim_done(); - void movie_ticker(); + void preanim_done(); + void movie_ticker(); }; #endif // AOCHARMOVIE_H diff --git a/include/aoemotebutton.h b/include/aoemotebutton.h index 8674bb0..cb46167 100644 --- a/include/aoemotebutton.h +++ b/include/aoemotebutton.h @@ -7,28 +7,29 @@ #include class AOEmoteButton : public QPushButton { - Q_OBJECT + Q_OBJECT public: - AOEmoteButton(QWidget *p_parent, AOApplication *p_ao_app, int p_x, int p_y, int p_w, int p_h); + AOEmoteButton(QWidget *p_parent, AOApplication *p_ao_app, int p_x, int p_y, + int p_w, int p_h); - void set_image(QString p_image, QString p_emote_comment); - void set_char_image(QString p_char, int p_emote, QString suffix); + void set_image(QString p_image, QString p_emote_comment); + void set_char_image(QString p_char, int p_emote, QString suffix); - void set_id(int p_id) { m_id = p_id; } - int get_id() { return m_id; } + void set_id(int p_id) { m_id = p_id; } + int get_id() { return m_id; } private: - QWidget *parent; - AOApplication *ao_app; + QWidget *parent; + AOApplication *ao_app; - int m_id = 0; + int m_id = 0; signals: - void emote_clicked(int p_id); + void emote_clicked(int p_id); private slots: - void on_clicked(); + void on_clicked(); }; #endif // AOEMOTEBUTTON_H diff --git a/include/aoevidencebutton.h b/include/aoevidencebutton.h index 2ac6860..d7812fe 100644 --- a/include/aoevidencebutton.h +++ b/include/aoevidencebutton.h @@ -9,42 +9,43 @@ #include class AOEvidenceButton : public QPushButton { - Q_OBJECT + Q_OBJECT public: - AOEvidenceButton(QWidget *p_parent, AOApplication *p_ao_app, int p_x, int p_y, int p_w, int p_h); + AOEvidenceButton(QWidget *p_parent, AOApplication *p_ao_app, int p_x, int p_y, + int p_w, int p_h); - void set_image(QString p_image); - void set_theme_image(QString p_image); - void set_id(int p_id) { m_id = p_id; } + void set_image(QString p_image); + void set_theme_image(QString p_image); + void set_id(int p_id) { m_id = p_id; } - void set_selected(bool p_selected); + void set_selected(bool p_selected); private: - AOApplication *ao_app; - QWidget *m_parent; + AOApplication *ao_app; + QWidget *m_parent; - AOImage *ui_selected; - AOImage *ui_selector; + AOImage *ui_selected; + AOImage *ui_selector; - int m_id = 0; + int m_id = 0; protected: - void enterEvent(QEvent *e); - void leaveEvent(QEvent *e); - void mouseDoubleClickEvent(QMouseEvent *e); - /* - void dragLeaveEvent(QMouseEvent *e); - void dragEnterEvent(QMouseEvent *e); - */ + void enterEvent(QEvent *e); + void leaveEvent(QEvent *e); + void mouseDoubleClickEvent(QMouseEvent *e); + /* +void dragLeaveEvent(QMouseEvent *e); +void dragEnterEvent(QMouseEvent *e); +*/ signals: - void evidence_clicked(int p_id); - void evidence_double_clicked(int p_id); - void on_hover(int p_id, bool p_state); + void evidence_clicked(int p_id); + void evidence_double_clicked(int p_id); + void on_hover(int p_id, bool p_state); private slots: - void on_clicked(); + void on_clicked(); }; #endif // AOEVIDENCEBUTTON_H diff --git a/include/aoevidencedisplay.h b/include/aoevidencedisplay.h index 0315ffc..979a754 100644 --- a/include/aoevidencedisplay.h +++ b/include/aoevidencedisplay.h @@ -9,24 +9,24 @@ #include class AOEvidenceDisplay : public QLabel { - Q_OBJECT + Q_OBJECT public: - AOEvidenceDisplay(QWidget *p_parent, AOApplication *p_ao_app); + AOEvidenceDisplay(QWidget *p_parent, AOApplication *p_ao_app); - void show_evidence(QString p_evidence_image, bool is_left_side, int p_volume); - QLabel *get_evidence_icon(); - void reset(); - void combo_resize(int w, int h); + void show_evidence(QString p_evidence_image, bool is_left_side, int p_volume); + QLabel *get_evidence_icon(); + void reset(); + void combo_resize(int w, int h); private: - AOApplication *ao_app; - AOMovie *evidence_movie; - QLabel *evidence_icon; - AOSfxPlayer *sfx_player; + AOApplication *ao_app; + AOMovie *evidence_movie; + QLabel *evidence_icon; + AOSfxPlayer *sfx_player; private slots: - void show_done(); + void show_done(); }; #endif // AOEVIDENCEDISPLAY_H diff --git a/include/aoimage.h b/include/aoimage.h index a6960de..01ef854 100644 --- a/include/aoimage.h +++ b/include/aoimage.h @@ -1,4 +1,4 @@ -//This class represents a static theme-dependent image +// This class represents a static theme-dependent image #ifndef AOIMAGE_H #define AOIMAGE_H @@ -10,15 +10,15 @@ class AOImage : public QLabel { public: - AOImage(QWidget *parent, AOApplication *p_ao_app); - ~AOImage(); + AOImage(QWidget *parent, AOApplication *p_ao_app); + ~AOImage(); - QWidget *m_parent; - AOApplication *ao_app; + QWidget *m_parent; + AOApplication *ao_app; - bool set_image(QString p_image); - bool set_chatbox(QString p_path); - void set_size_and_pos(QString identifier); + bool set_image(QString p_image); + bool set_chatbox(QString p_path); + void set_size_and_pos(QString identifier); }; #endif // AOIMAGE_H diff --git a/include/aolineedit.h b/include/aolineedit.h index 06206a9..5dce3aa 100644 --- a/include/aolineedit.h +++ b/include/aolineedit.h @@ -5,22 +5,22 @@ #include class AOLineEdit : public QLineEdit { - Q_OBJECT + Q_OBJECT public: - AOLineEdit(QWidget *parent); + AOLineEdit(QWidget *parent); - void preserve_selection(bool toggle) { p_selection = toggle; } + void preserve_selection(bool toggle) { p_selection = toggle; } private: - bool p_selection = false; + bool p_selection = false; protected: - void mouseDoubleClickEvent(QMouseEvent *e); - void focusOutEvent(QFocusEvent *ev); + void mouseDoubleClickEvent(QMouseEvent *e); + void focusOutEvent(QFocusEvent *ev); signals: - void double_clicked(); + void double_clicked(); }; #endif // AOLINEEDIT_H diff --git a/include/aomovie.h b/include/aomovie.h index 8d60442..eb7f7a5 100644 --- a/include/aomovie.h +++ b/include/aomovie.h @@ -8,28 +8,29 @@ class Courtroom; class AOApplication; class AOMovie : public QLabel { - Q_OBJECT + Q_OBJECT public: - AOMovie(QWidget *p_parent, AOApplication *p_ao_app); + AOMovie(QWidget *p_parent, AOApplication *p_ao_app); - void set_play_once(bool p_play_once); - void play(QString p_image, QString p_char = "", QString p_custom_theme = "", int default_duration = 0); - void combo_resize(int w, int h); - void stop(); + void set_play_once(bool p_play_once); + void play(QString p_image, QString p_char = "", QString p_custom_theme = "", + int default_duration = 0); + void combo_resize(int w, int h); + void stop(); private: - QMovie *m_movie; - AOApplication *ao_app; - QTimer *timer; - bool play_once = true; + QMovie *m_movie; + AOApplication *ao_app; + QTimer *timer; + bool play_once = true; signals: - void done(); + void done(); private slots: - void frame_change(int n_frame); - void timer_done(); + void frame_change(int n_frame); + void timer_done(); }; #endif // AOMOVIE_H diff --git a/include/aomusicplayer.h b/include/aomusicplayer.h index d28a3ed..5c72649 100644 --- a/include/aomusicplayer.h +++ b/include/aomusicplayer.h @@ -17,63 +17,64 @@ #if defined(BASSAUDIO) class AOMusicPlayer { public: - AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app); - virtual ~AOMusicPlayer(); - void set_volume(int p_value, int channel = -1); - void set_looping(bool toggle, int channel = 0); + AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app); + virtual ~AOMusicPlayer(); + void set_volume(int p_value, int channel = -1); + void set_looping(bool toggle, int channel = 0); - const int m_channelmax = 4; + const int m_channelmax = 4; - //These have to be public for the stupid sync thing - QWORD loop_start = 0; - QWORD loop_end = 0; + // These have to be public for the stupid sync thing + QWORD loop_start = 0; + QWORD loop_end = 0; public slots: - void play(QString p_song, int channel = 0, bool loop = false, int effect_flags = 0); - void stop(int channel = 0); + void play(QString p_song, int channel = 0, bool loop = false, + int effect_flags = 0); + void stop(int channel = 0); private: - QWidget *m_parent; - AOApplication *ao_app; + QWidget *m_parent; + AOApplication *ao_app; - bool m_looping = false; - int m_volume[4] = {0, 0, 0, 0}; + bool m_looping = false; + int m_volume[4] = {0, 0, 0, 0}; - // Channel 0 = music - // Channel 1 = ambience - // Channel 2 = extra - // Channel 3 = extra - HSTREAM m_stream_list[4]; - HSYNC loop_sync[4]; + // Channel 0 = music + // Channel 1 = ambience + // Channel 2 = extra + // Channel 3 = extra + HSTREAM m_stream_list[4]; + HSYNC loop_sync[4]; }; #elif defined(QTAUDIO) class AOMusicPlayer { public: - AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app); - ~AOMusicPlayer(); + AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app); + ~AOMusicPlayer(); - void play(QString p_song); - void set_volume(int p_value); + void play(QString p_song); + void set_volume(int p_value); private: - QMediaPlayer m_player; - QWidget *m_parent; - AOApplication *ao_app; + QMediaPlayer m_player; + QWidget *m_parent; + AOApplication *ao_app; - int m_volume = 0; + int m_volume = 0; }; #else class AOMusicPlayer { public: - AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app); - ~AOMusicPlayer(); + AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app); + ~AOMusicPlayer(); - void play(QString p_song); - void set_volume(int p_value); + void play(QString p_song); + void set_volume(int p_value); private: - QWidget *m_parent; - AOApplication *ao_app; + QWidget *m_parent; + AOApplication *ao_app; }; #endif diff --git a/include/aooptionsdialog.h b/include/aooptionsdialog.h index f9c369d..b89e317 100644 --- a/include/aooptionsdialog.h +++ b/include/aooptionsdialog.h @@ -31,116 +31,117 @@ #include class AOOptionsDialog : public QDialog { - Q_OBJECT + Q_OBJECT public: - explicit AOOptionsDialog(QWidget *parent = nullptr, AOApplication *p_ao_app = nullptr); + explicit AOOptionsDialog(QWidget *parent = nullptr, + AOApplication *p_ao_app = nullptr); private: - AOApplication *ao_app; + AOApplication *ao_app; - QVBoxLayout *ui_vertical_layout; - QTabWidget *ui_settings_tabs; + QVBoxLayout *ui_vertical_layout; + QTabWidget *ui_settings_tabs; - QWidget *ui_gameplay_tab; - QWidget *ui_form_layout_widget; - QFormLayout *ui_gameplay_form; - QLabel *ui_theme_label; - QComboBox *ui_theme_combobox; - QFrame *ui_theme_log_divider; - QLabel *ui_downwards_lbl; - QCheckBox *ui_downwards_cb; - QLabel *ui_length_lbl; - QSpinBox *ui_length_spinbox; - QFrame *ui_log_names_divider; - QLineEdit *ui_username_textbox; - QLabel *ui_username_lbl; - QLabel *ui_showname_lbl; - QCheckBox *ui_showname_cb; - QFrame *ui_net_divider; - QLabel *ui_ms_lbl; - QLineEdit *ui_ms_textbox; - QLabel *ui_discord_lbl; - QCheckBox *ui_discord_cb; - QLabel *ui_language_label; - QComboBox *ui_language_combobox; + QWidget *ui_gameplay_tab; + QWidget *ui_form_layout_widget; + QFormLayout *ui_gameplay_form; + QLabel *ui_theme_label; + QComboBox *ui_theme_combobox; + QFrame *ui_theme_log_divider; + QLabel *ui_downwards_lbl; + QCheckBox *ui_downwards_cb; + QLabel *ui_length_lbl; + QSpinBox *ui_length_spinbox; + QFrame *ui_log_names_divider; + QLineEdit *ui_username_textbox; + QLabel *ui_username_lbl; + QLabel *ui_showname_lbl; + QCheckBox *ui_showname_cb; + QFrame *ui_net_divider; + QLabel *ui_ms_lbl; + QLineEdit *ui_ms_textbox; + QLabel *ui_discord_lbl; + QCheckBox *ui_discord_cb; + QLabel *ui_language_label; + QComboBox *ui_language_combobox; - QLabel *ui_shake_lbl; - QCheckBox *ui_shake_cb; - QLabel *ui_effects_lbl; - QCheckBox *ui_effects_cb; - QLabel *ui_framenetwork_lbl; - QCheckBox *ui_framenetwork_cb; + QLabel *ui_shake_lbl; + QCheckBox *ui_shake_cb; + QLabel *ui_effects_lbl; + QCheckBox *ui_effects_cb; + QLabel *ui_framenetwork_lbl; + QCheckBox *ui_framenetwork_cb; - QLabel *ui_colorlog_lbl; - QCheckBox *ui_colorlog_cb; + QLabel *ui_colorlog_lbl; + QCheckBox *ui_colorlog_cb; - QLabel *ui_stickysounds_lbl; - QCheckBox *ui_stickysounds_cb; + QLabel *ui_stickysounds_lbl; + QCheckBox *ui_stickysounds_cb; - QLabel *ui_stickyeffects_lbl; - QCheckBox *ui_stickyeffects_cb; + QLabel *ui_stickyeffects_lbl; + QCheckBox *ui_stickyeffects_cb; - QLabel *ui_stickypres_lbl; - QCheckBox *ui_stickypres_cb; + QLabel *ui_stickypres_lbl; + QCheckBox *ui_stickypres_cb; - QWidget *ui_callwords_tab; - QWidget *ui_callwords_widget; - QVBoxLayout *ui_callwords_layout; - QPlainTextEdit *ui_callwords_textbox; - QLabel *ui_callwords_explain_lbl; - QCheckBox *ui_callwords_char_textbox; + QWidget *ui_callwords_tab; + QWidget *ui_callwords_widget; + QVBoxLayout *ui_callwords_layout; + QPlainTextEdit *ui_callwords_textbox; + QLabel *ui_callwords_explain_lbl; + QCheckBox *ui_callwords_char_textbox; - QWidget *ui_audio_tab; - QWidget *ui_audio_widget; - QFormLayout *ui_audio_layout; - QLabel *ui_audio_device_lbl; - QComboBox *ui_audio_device_combobox; - QFrame *ui_audio_volume_divider; - QSpinBox *ui_music_volume_spinbox; - QLabel *ui_music_volume_lbl; - QSpinBox *ui_sfx_volume_spinbox; - QSpinBox *ui_blips_volume_spinbox; - QLabel *ui_sfx_volume_lbl; - QLabel *ui_blips_volume_lbl; - QFrame *ui_volume_blip_divider; - QSpinBox *ui_bliprate_spinbox; - QLabel *ui_bliprate_lbl; - QCheckBox *ui_blank_blips_cb; - QLabel *ui_blank_blips_lbl; - QLabel *ui_loopsfx_lbl; - QCheckBox *ui_loopsfx_cb; - QLabel *ui_objectmusic_lbl; - QCheckBox *ui_objectmusic_cb; - QDialogButtonBox *ui_settings_buttons; + QWidget *ui_audio_tab; + QWidget *ui_audio_widget; + QFormLayout *ui_audio_layout; + QLabel *ui_audio_device_lbl; + QComboBox *ui_audio_device_combobox; + QFrame *ui_audio_volume_divider; + QSpinBox *ui_music_volume_spinbox; + QLabel *ui_music_volume_lbl; + QSpinBox *ui_sfx_volume_spinbox; + QSpinBox *ui_blips_volume_spinbox; + QLabel *ui_sfx_volume_lbl; + QLabel *ui_blips_volume_lbl; + QFrame *ui_volume_blip_divider; + QSpinBox *ui_bliprate_spinbox; + QLabel *ui_bliprate_lbl; + QCheckBox *ui_blank_blips_cb; + QLabel *ui_blank_blips_lbl; + QLabel *ui_loopsfx_lbl; + QCheckBox *ui_loopsfx_cb; + QLabel *ui_objectmusic_lbl; + QCheckBox *ui_objectmusic_cb; + QDialogButtonBox *ui_settings_buttons; - QWidget *ui_casing_tab; - QWidget *ui_casing_widget; - QFormLayout *ui_casing_layout; - QLabel *ui_casing_supported_lbl; - QLabel *ui_casing_enabled_lbl; - QCheckBox *ui_casing_enabled_cb; - QLabel *ui_casing_def_lbl; - QCheckBox *ui_casing_def_cb; - QLabel *ui_casing_pro_lbl; - QCheckBox *ui_casing_pro_cb; - QLabel *ui_casing_jud_lbl; - QCheckBox *ui_casing_jud_cb; - QLabel *ui_casing_jur_lbl; - QCheckBox *ui_casing_jur_cb; - QLabel *ui_casing_steno_lbl; - QCheckBox *ui_casing_steno_cb; - QLabel *ui_casing_cm_lbl; - QCheckBox *ui_casing_cm_cb; - QLabel *ui_casing_cm_cases_lbl; - QLineEdit *ui_casing_cm_cases_textbox; + QWidget *ui_casing_tab; + QWidget *ui_casing_widget; + QFormLayout *ui_casing_layout; + QLabel *ui_casing_supported_lbl; + QLabel *ui_casing_enabled_lbl; + QCheckBox *ui_casing_enabled_cb; + QLabel *ui_casing_def_lbl; + QCheckBox *ui_casing_def_cb; + QLabel *ui_casing_pro_lbl; + QCheckBox *ui_casing_pro_cb; + QLabel *ui_casing_jud_lbl; + QCheckBox *ui_casing_jud_cb; + QLabel *ui_casing_jur_lbl; + QCheckBox *ui_casing_jur_cb; + QLabel *ui_casing_steno_lbl; + QCheckBox *ui_casing_steno_cb; + QLabel *ui_casing_cm_lbl; + QCheckBox *ui_casing_cm_cb; + QLabel *ui_casing_cm_cases_lbl; + QLineEdit *ui_casing_cm_cases_textbox; - bool needs_default_audiodev(); + bool needs_default_audiodev(); signals: public slots: - void save_pressed(); - void discard_pressed(); + void save_pressed(); + void discard_pressed(); }; #endif // AOOPTIONSDIALOG_H diff --git a/include/aopacket.h b/include/aopacket.h index 4133fd5..4097be8 100644 --- a/include/aopacket.h +++ b/include/aopacket.h @@ -7,25 +7,25 @@ class AOPacket { public: - AOPacket(QString p_packet_string); - AOPacket(QString header, QStringList &p_contents); - ~AOPacket(); + AOPacket(QString p_packet_string); + AOPacket(QString header, QStringList &p_contents); + ~AOPacket(); - QString get_header() { return m_header; } - QStringList &get_contents() { return m_contents; } - QString to_string(); + QString get_header() { return m_header; } + QStringList &get_contents() { return m_contents; } + QString to_string(); - void encrypt_header(unsigned int p_key); - void decrypt_header(unsigned int p_key); + void encrypt_header(unsigned int p_key); + void decrypt_header(unsigned int p_key); - void net_encode(); - void net_decode(); + void net_encode(); + void net_decode(); private: - bool encrypted = false; + bool encrypted = false; - QString m_header; - QStringList m_contents; + QString m_header; + QStringList m_contents; }; #endif // AOPACKET_H diff --git a/include/aoscene.h b/include/aoscene.h index 3093b0f..726e264 100644 --- a/include/aoscene.h +++ b/include/aoscene.h @@ -9,31 +9,34 @@ class Courtroom; class AOApplication; class AOScene : public QLabel { - Q_OBJECT + Q_OBJECT public: - explicit AOScene(QWidget *parent, AOApplication *p_ao_app); + explicit AOScene(QWidget *parent, AOApplication *p_ao_app); - void set_image(QString p_image); - void set_legacy_desk(QString p_image); + void set_image(QString p_image); + void set_legacy_desk(QString p_image); - //Move the label itself around - void move(int ax, int ay); + // Move the label itself around + void move(int ax, int ay); - //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); + // 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); private: - QWidget *m_parent; - QMovie *m_movie; - AOApplication *ao_app; - QString last_image; + QWidget *m_parent; + QMovie *m_movie; + AOApplication *ao_app; + QString last_image; - // These are the X and Y values before they are fixed based on the sprite's width. - int x = 0; - int y = 0; - // These are the width and height values before they are fixed based on the sprite's width. - int f_w = 0; - int f_h = 0; + // These are the X and Y values before they are fixed based on the sprite's + // width. + int x = 0; + int y = 0; + // These are the width and height values before they are fixed based on the + // sprite's width. + int f_w = 0; + int f_h = 0; }; #endif // AOSCENE_H diff --git a/include/aosfxplayer.h b/include/aosfxplayer.h index 4488aa6..9c9824a 100644 --- a/include/aosfxplayer.h +++ b/include/aosfxplayer.h @@ -16,29 +16,30 @@ class AOSfxPlayer { public: - AOSfxPlayer(QWidget *parent, AOApplication *p_ao_app); + AOSfxPlayer(QWidget *parent, AOApplication *p_ao_app); - void clear(); - void loop_clear(); - void play(QString p_sfx, QString p_char = "", QString shout = "", int channel = -1); - void stop(int channel = -1); - void set_volume(qreal p_volume); - void set_looping(bool toggle, int channel = -1); - int m_channel = 0; + void clear(); + void loop_clear(); + void play(QString p_sfx, QString p_char = "", QString shout = "", + int channel = -1); + void stop(int channel = -1); + void set_volume(qreal p_volume); + void set_looping(bool toggle, int channel = -1); + int m_channel = 0; private: - QWidget *m_parent; - AOApplication *ao_app; - qreal m_volume = 0; + QWidget *m_parent; + AOApplication *ao_app; + qreal m_volume = 0; - bool m_looping = true; - void set_volume_internal(qreal p_volume); + bool m_looping = true; + void set_volume_internal(qreal p_volume); #if defined(BASSAUDIO) - const int m_channelmax = 5; - HSTREAM m_stream_list[5]; + const int m_channelmax = 5; + HSTREAM m_stream_list[5]; #elif defined(QTAUDIO) - QSoundEffect m_sfx; + QSoundEffect m_sfx; #endif }; diff --git a/include/aotextarea.h b/include/aotextarea.h index 8bf5199..453e965 100644 --- a/include/aotextarea.h +++ b/include/aotextarea.h @@ -9,16 +9,17 @@ class AOTextArea : public QTextBrowser { public: - AOTextArea(QWidget *p_parent = nullptr); + AOTextArea(QWidget *p_parent = nullptr); - void append_linked(QString p_message); - void append_chatmessage(QString p_name, QString p_message, QString p_colur); - void append_error(QString p_message); + void append_linked(QString p_message); + void append_chatmessage(QString p_name, QString p_message, QString p_colur); + void append_error(QString p_message); private: - const QRegExp url_parser_regex = QRegExp("\\b(https?://\\S+\\.\\S+)\\b"); + const QRegExp url_parser_regex = QRegExp("\\b(https?://\\S+\\.\\S+)\\b"); - void auto_scroll(QTextCursor old_cursor, int scrollbar_value, bool is_scrolled_down); + void auto_scroll(QTextCursor old_cursor, int scrollbar_value, + bool is_scrolled_down); }; #endif // AOTEXTAREA_H diff --git a/include/aotextedit.h b/include/aotextedit.h index eb2c356..8d876f1 100644 --- a/include/aotextedit.h +++ b/include/aotextedit.h @@ -4,18 +4,18 @@ #include class AOTextEdit : public QPlainTextEdit { - Q_OBJECT + Q_OBJECT public: - AOTextEdit(QWidget *parent); + AOTextEdit(QWidget *parent); protected: - void mouseDoubleClickEvent(QMouseEvent *e); + void mouseDoubleClickEvent(QMouseEvent *e); signals: - void double_clicked(); + void double_clicked(); private slots: - void on_enter_pressed(); + void on_enter_pressed(); }; #endif // AOTEXTEDIT_H diff --git a/include/bass.h b/include/bass.h index 4180a37..ec2c7a2 100644 --- a/include/bass.h +++ b/include/bass.h @@ -1,8 +1,8 @@ /* - BASS 2.4 C/C++ header file - Copyright (c) 1999-2019 Un4seen Developments Ltd. + BASS 2.4 C/C++ header file + Copyright (c) 1999-2019 Un4seen Developments Ltd. - See the BASS.CHM file for more detailed documentation + See the BASS.CHM file for more detailed documentation */ #ifndef BASS_H @@ -152,13 +152,14 @@ typedef DWORD HPLUGIN; // Plugin handle #define BASS_CONFIG_LIBSSL 64 // BASS_Init flags -#define BASS_DEVICE_8BITS 1 // 8 bit -#define BASS_DEVICE_MONO 2 // mono -#define BASS_DEVICE_3D 4 // enable 3D functionality -#define BASS_DEVICE_16BITS 8 // limit output to 16 bit -#define BASS_DEVICE_LATENCY 0x100 // calculate device latency (BASS_INFO struct) -#define BASS_DEVICE_CPSPEAKERS 0x400 // detect speakers via Windows control panel -#define BASS_DEVICE_SPEAKERS 0x800 // force enabling of speaker assignment +#define BASS_DEVICE_8BITS 1 // 8 bit +#define BASS_DEVICE_MONO 2 // mono +#define BASS_DEVICE_3D 4 // enable 3D functionality +#define BASS_DEVICE_16BITS 8 // limit output to 16 bit +#define BASS_DEVICE_LATENCY 0x100 // calculate device latency (BASS_INFO struct) +#define BASS_DEVICE_CPSPEAKERS \ + 0x400 // detect speakers via Windows control panel +#define BASS_DEVICE_SPEAKERS 0x800 // force enabling of speaker assignment #define BASS_DEVICE_NOSPEAKER 0x1000 // ignore speaker arrangement #define BASS_DEVICE_DMIX 0x2000 // use ALSA "dmix" plugin #define BASS_DEVICE_FREQ 0x4000 // set device sample rate @@ -173,14 +174,15 @@ typedef DWORD HPLUGIN; // Plugin handle // Device info structure typedef struct { -#if defined(_WIN32_WCE) || (WINAPI_FAMILY && WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP) - const wchar_t *name; // description - const wchar_t *driver; // driver +#if defined(_WIN32_WCE) || \ + (WINAPI_FAMILY && WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP) + const wchar_t *name; // description + const wchar_t *driver; // driver #else - const char *name; // description - const char *driver; // driver + const char *name; // description + const char *driver; // driver #endif - DWORD flags; + DWORD flags; } BASS_DEVICEINFO; // BASS_DEVICEINFO flags @@ -206,26 +208,32 @@ typedef struct { #define BASS_DEVICES_AIRPLAY 0x1000000 typedef struct { - DWORD flags; // device capabilities (DSCAPS_xxx flags) - DWORD hwsize; // size of total device hardware memory - DWORD hwfree; // size of free device hardware memory - DWORD freesam; // number of free sample slots in the hardware - DWORD free3d; // number of free 3D sample slots in the hardware - DWORD minrate; // min sample rate supported by the hardware - DWORD maxrate; // max sample rate supported by the hardware - BOOL eax; // device supports EAX? (always FALSE if BASS_DEVICE_3D was not used) - DWORD minbuf; // recommended minimum buffer length in ms (requires BASS_DEVICE_LATENCY) - DWORD dsver; // DirectSound version - DWORD latency; // delay (in ms) before start of playback (requires BASS_DEVICE_LATENCY) - DWORD initflags; // BASS_Init "flags" parameter - DWORD speakers; // number of speakers available - DWORD freq; // current output rate + DWORD flags; // device capabilities (DSCAPS_xxx flags) + DWORD hwsize; // size of total device hardware memory + DWORD hwfree; // size of free device hardware memory + DWORD freesam; // number of free sample slots in the hardware + DWORD free3d; // number of free 3D sample slots in the hardware + DWORD minrate; // min sample rate supported by the hardware + DWORD maxrate; // max sample rate supported by the hardware + BOOL + eax; // device supports EAX? (always FALSE if BASS_DEVICE_3D was not used) + DWORD minbuf; // recommended minimum buffer length in ms (requires + // BASS_DEVICE_LATENCY) + DWORD dsver; // DirectSound version + DWORD latency; // delay (in ms) before start of playback (requires + // BASS_DEVICE_LATENCY) + DWORD initflags; // BASS_Init "flags" parameter + DWORD speakers; // number of speakers available + DWORD freq; // current output rate } BASS_INFO; // BASS_INFO flags (from DSOUND.H) -#define DSCAPS_CONTINUOUSRATE 0x00000010 // supports all sample rates between min/maxrate -#define DSCAPS_EMULDRIVER 0x00000020 // device does NOT have hardware DirectSound support -#define DSCAPS_CERTIFIED 0x00000040 // device driver has been certified by Microsoft +#define DSCAPS_CONTINUOUSRATE \ + 0x00000010 // supports all sample rates between min/maxrate +#define DSCAPS_EMULDRIVER \ + 0x00000020 // device does NOT have hardware DirectSound support +#define DSCAPS_CERTIFIED \ + 0x00000040 // device driver has been certified by Microsoft #define DSCAPS_SECONDARYMONO 0x00000100 // mono #define DSCAPS_SECONDARYSTEREO 0x00000200 // stereo #define DSCAPS_SECONDARY8BIT 0x00000400 // 8 bit @@ -233,16 +241,19 @@ typedef struct { // Recording device info structure typedef struct { - DWORD flags; // device capabilities (DSCCAPS_xxx flags) - DWORD formats; // supported standard formats (WAVE_FORMAT_xxx flags) - DWORD inputs; // number of inputs - BOOL singlein; // TRUE = only 1 input can be set at a time - DWORD freq; // current input rate + DWORD flags; // device capabilities (DSCCAPS_xxx flags) + DWORD formats; // supported standard formats (WAVE_FORMAT_xxx flags) + DWORD inputs; // number of inputs + BOOL singlein; // TRUE = only 1 input can be set at a time + DWORD freq; // current input rate } BASS_RECORDINFO; // BASS_RECORDINFO flags (from DSOUND.H) -#define DSCCAPS_EMULDRIVER DSCAPS_EMULDRIVER // device does NOT have hardware DirectSound recording support -#define DSCCAPS_CERTIFIED DSCAPS_CERTIFIED // device driver has been certified by Microsoft +#define DSCCAPS_EMULDRIVER \ + DSCAPS_EMULDRIVER // device does NOT have hardware DirectSound recording + // support +#define DSCCAPS_CERTIFIED \ + DSCAPS_CERTIFIED // device driver has been certified by Microsoft // defines for formats field of BASS_RECORDINFO (from MMSYSTEM.H) #ifndef WAVE_FORMAT_1M08 @@ -262,46 +273,54 @@ typedef struct { // Sample info structure typedef struct { - DWORD freq; // default playback rate - float volume; // default volume (0-1) - float pan; // default pan (-1=left, 0=middle, 1=right) - DWORD flags; // BASS_SAMPLE_xxx flags - DWORD length; // length (in bytes) - DWORD max; // maximum simultaneous playbacks - DWORD origres; // original resolution - DWORD chans; // number of channels - DWORD mingap; // minimum gap (ms) between creating channels - DWORD mode3d; // BASS_3DMODE_xxx mode - float mindist; // minimum distance - float maxdist; // maximum distance - DWORD iangle; // angle of inside projection cone - DWORD oangle; // angle of outside projection cone - float outvol; // delta-volume outside the projection cone - DWORD vam; // voice allocation/management flags (BASS_VAM_xxx) - DWORD priority; // priority (0=lowest, 0xffffffff=highest) + DWORD freq; // default playback rate + float volume; // default volume (0-1) + float pan; // default pan (-1=left, 0=middle, 1=right) + DWORD flags; // BASS_SAMPLE_xxx flags + DWORD length; // length (in bytes) + DWORD max; // maximum simultaneous playbacks + DWORD origres; // original resolution + DWORD chans; // number of channels + DWORD mingap; // minimum gap (ms) between creating channels + DWORD mode3d; // BASS_3DMODE_xxx mode + float mindist; // minimum distance + float maxdist; // maximum distance + DWORD iangle; // angle of inside projection cone + DWORD oangle; // angle of outside projection cone + float outvol; // delta-volume outside the projection cone + DWORD vam; // voice allocation/management flags (BASS_VAM_xxx) + DWORD priority; // priority (0=lowest, 0xffffffff=highest) } BASS_SAMPLE; -#define BASS_SAMPLE_8BITS 1 // 8 bit -#define BASS_SAMPLE_FLOAT 256 // 32 bit floating-point -#define BASS_SAMPLE_MONO 2 // mono -#define BASS_SAMPLE_LOOP 4 // looped -#define BASS_SAMPLE_3D 8 // 3D functionality -#define BASS_SAMPLE_SOFTWARE 16 // not using hardware mixing -#define BASS_SAMPLE_MUTEMAX 32 // mute at max distance (3D only) -#define BASS_SAMPLE_VAM 64 // DX7 voice allocation & management -#define BASS_SAMPLE_FX 128 // old implementation of DX8 effects -#define BASS_SAMPLE_OVER_VOL 0x10000 // override lowest volume -#define BASS_SAMPLE_OVER_POS 0x20000 // override longest playing -#define BASS_SAMPLE_OVER_DIST 0x30000 // override furthest from listener (3D only) +#define BASS_SAMPLE_8BITS 1 // 8 bit +#define BASS_SAMPLE_FLOAT 256 // 32 bit floating-point +#define BASS_SAMPLE_MONO 2 // mono +#define BASS_SAMPLE_LOOP 4 // looped +#define BASS_SAMPLE_3D 8 // 3D functionality +#define BASS_SAMPLE_SOFTWARE 16 // not using hardware mixing +#define BASS_SAMPLE_MUTEMAX 32 // mute at max distance (3D only) +#define BASS_SAMPLE_VAM 64 // DX7 voice allocation & management +#define BASS_SAMPLE_FX 128 // old implementation of DX8 effects +#define BASS_SAMPLE_OVER_VOL 0x10000 // override lowest volume +#define BASS_SAMPLE_OVER_POS 0x20000 // override longest playing +#define BASS_SAMPLE_OVER_DIST \ + 0x30000 // override furthest from listener (3D only) -#define BASS_STREAM_PRESCAN 0x20000 // enable pin-point seeking/length (MP3/MP2/MP1) -#define BASS_STREAM_AUTOFREE 0x40000 // automatically free the stream when it stop/ends -#define BASS_STREAM_RESTRATE 0x80000 // restrict the download rate of internet file streams -#define BASS_STREAM_BLOCK 0x100000 // download/play internet file stream in small blocks -#define BASS_STREAM_DECODE 0x200000 // don't play the stream, only decode (BASS_ChannelGetData) -#define BASS_STREAM_STATUS 0x800000 // give server status info (HTTP/ICY tags) in DOWNLOADPROC +#define BASS_STREAM_PRESCAN \ + 0x20000 // enable pin-point seeking/length (MP3/MP2/MP1) +#define BASS_STREAM_AUTOFREE \ + 0x40000 // automatically free the stream when it stop/ends +#define BASS_STREAM_RESTRATE \ + 0x80000 // restrict the download rate of internet file streams +#define BASS_STREAM_BLOCK \ + 0x100000 // download/play internet file stream in small blocks +#define BASS_STREAM_DECODE \ + 0x200000 // don't play the stream, only decode (BASS_ChannelGetData) +#define BASS_STREAM_STATUS \ + 0x800000 // give server status info (HTTP/ICY tags) in DOWNLOADPROC -#define BASS_MP3_IGNOREDELAY 0x200 // ignore LAME/Xing/VBRI/iTunes delay & padding info +#define BASS_MP3_IGNOREDELAY \ + 0x200 // ignore LAME/Xing/VBRI/iTunes delay & padding info #define BASS_MP3_SETPOS BASS_STREAM_PRESCAN #define BASS_MUSIC_FLOAT BASS_SAMPLE_FLOAT @@ -313,19 +332,20 @@ typedef struct { #define BASS_MUSIC_DECODE BASS_STREAM_DECODE #define BASS_MUSIC_PRESCAN BASS_STREAM_PRESCAN // calculate playback length #define BASS_MUSIC_CALCLEN BASS_MUSIC_PRESCAN -#define BASS_MUSIC_RAMP 0x200 // normal ramping -#define BASS_MUSIC_RAMPS 0x400 // sensitive ramping -#define BASS_MUSIC_SURROUND 0x800 // surround sound -#define BASS_MUSIC_SURROUND2 0x1000 // surround sound (mode 2) -#define BASS_MUSIC_FT2PAN 0x2000 // apply FastTracker 2 panning to XM files -#define BASS_MUSIC_FT2MOD 0x2000 // play .MOD as FastTracker 2 does -#define BASS_MUSIC_PT1MOD 0x4000 // play .MOD as ProTracker 1 does -#define BASS_MUSIC_NONINTER 0x10000 // non-interpolated sample mixing -#define BASS_MUSIC_SINCINTER 0x800000 // sinc interpolated sample mixing -#define BASS_MUSIC_POSRESET 0x8000 // stop all notes when moving position -#define BASS_MUSIC_POSRESETEX 0x400000 // stop all notes and reset bmp/etc when moving position -#define BASS_MUSIC_STOPBACK 0x80000 // stop the music on a backwards jump effect -#define BASS_MUSIC_NOSAMPLE 0x100000 // don't load the samples +#define BASS_MUSIC_RAMP 0x200 // normal ramping +#define BASS_MUSIC_RAMPS 0x400 // sensitive ramping +#define BASS_MUSIC_SURROUND 0x800 // surround sound +#define BASS_MUSIC_SURROUND2 0x1000 // surround sound (mode 2) +#define BASS_MUSIC_FT2PAN 0x2000 // apply FastTracker 2 panning to XM files +#define BASS_MUSIC_FT2MOD 0x2000 // play .MOD as FastTracker 2 does +#define BASS_MUSIC_PT1MOD 0x4000 // play .MOD as ProTracker 1 does +#define BASS_MUSIC_NONINTER 0x10000 // non-interpolated sample mixing +#define BASS_MUSIC_SINCINTER 0x800000 // sinc interpolated sample mixing +#define BASS_MUSIC_POSRESET 0x8000 // stop all notes when moving position +#define BASS_MUSIC_POSRESETEX \ + 0x400000 // stop all notes and reset bmp/etc when moving position +#define BASS_MUSIC_STOPBACK 0x80000 // stop the music on a backwards jump effect +#define BASS_MUSIC_NOSAMPLE 0x100000 // don't load the samples // Speaker assignment flags #define BASS_SPEAKER_FRONT 0x1000000 // front speakers @@ -360,14 +380,14 @@ typedef struct { // Channel info structure typedef struct { - DWORD freq; // default playback rate - DWORD chans; // channels - DWORD flags; // BASS_SAMPLE/STREAM/MUSIC/SPEAKER flags - DWORD ctype; // type of channel - DWORD origres; // original resolution - HPLUGIN plugin; // plugin - HSAMPLE sample; // sample - const char *filename; // filename + DWORD freq; // default playback rate + DWORD chans; // channels + DWORD flags; // BASS_SAMPLE/STREAM/MUSIC/SPEAKER flags + DWORD ctype; // type of channel + DWORD origres; // original resolution + HPLUGIN plugin; // plugin + HSAMPLE sample; // sample + const char *filename; // filename } BASS_CHANNELINFO; #define BASS_ORIGRES_FLOAT 0x10000 @@ -397,31 +417,32 @@ typedef struct { #define BASS_CTYPE_MUSIC_MO3 0x00100 // MO3 flag typedef struct { - DWORD ctype; // channel type -#if defined(_WIN32_WCE) || (WINAPI_FAMILY && WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP) - const wchar_t *name; // format description - const wchar_t *exts; // file extension filter (*.ext1;*.ext2;etc...) + DWORD ctype; // channel type +#if defined(_WIN32_WCE) || \ + (WINAPI_FAMILY && WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP) + const wchar_t *name; // format description + const wchar_t *exts; // file extension filter (*.ext1;*.ext2;etc...) #else - const char *name; // format description - const char *exts; // file extension filter (*.ext1;*.ext2;etc...) + const char *name; // format description + const char *exts; // file extension filter (*.ext1;*.ext2;etc...) #endif } BASS_PLUGINFORM; typedef struct { - DWORD version; // version (same form as BASS_GetVersion) - DWORD formatc; // number of formats - const BASS_PLUGINFORM *formats; // the array of formats + DWORD version; // version (same form as BASS_GetVersion) + DWORD formatc; // number of formats + const BASS_PLUGINFORM *formats; // the array of formats } BASS_PLUGININFO; // 3D vector (for 3D positions/velocities/orientations) typedef struct BASS_3DVECTOR { #ifdef __cplusplus - BASS_3DVECTOR(){}; - BASS_3DVECTOR(float _x, float _y, float _z) : x(_x), y(_y), z(_z){}; + BASS_3DVECTOR(){}; + BASS_3DVECTOR(float _x, float _y, float _z) : x(_x), y(_y), z(_z){}; #endif - float x; // +=right, -=left - float y; // +=up, -=down - float z; // +=front, -=behind + float x; // +=right, -=left + float y; // +=up, -=down + float z; // +=front, -=behind } BASS_3DVECTOR; // 3D channel modes @@ -437,34 +458,34 @@ typedef struct BASS_3DVECTOR { // EAX environments, use with BASS_SetEAXParameters enum { - EAX_ENVIRONMENT_GENERIC, - EAX_ENVIRONMENT_PADDEDCELL, - EAX_ENVIRONMENT_ROOM, - EAX_ENVIRONMENT_BATHROOM, - EAX_ENVIRONMENT_LIVINGROOM, - EAX_ENVIRONMENT_STONEROOM, - EAX_ENVIRONMENT_AUDITORIUM, - EAX_ENVIRONMENT_CONCERTHALL, - EAX_ENVIRONMENT_CAVE, - EAX_ENVIRONMENT_ARENA, - EAX_ENVIRONMENT_HANGAR, - EAX_ENVIRONMENT_CARPETEDHALLWAY, - EAX_ENVIRONMENT_HALLWAY, - EAX_ENVIRONMENT_STONECORRIDOR, - EAX_ENVIRONMENT_ALLEY, - EAX_ENVIRONMENT_FOREST, - EAX_ENVIRONMENT_CITY, - EAX_ENVIRONMENT_MOUNTAINS, - EAX_ENVIRONMENT_QUARRY, - EAX_ENVIRONMENT_PLAIN, - EAX_ENVIRONMENT_PARKINGLOT, - EAX_ENVIRONMENT_SEWERPIPE, - EAX_ENVIRONMENT_UNDERWATER, - EAX_ENVIRONMENT_DRUGGED, - EAX_ENVIRONMENT_DIZZY, - EAX_ENVIRONMENT_PSYCHOTIC, + EAX_ENVIRONMENT_GENERIC, + EAX_ENVIRONMENT_PADDEDCELL, + EAX_ENVIRONMENT_ROOM, + EAX_ENVIRONMENT_BATHROOM, + EAX_ENVIRONMENT_LIVINGROOM, + EAX_ENVIRONMENT_STONEROOM, + EAX_ENVIRONMENT_AUDITORIUM, + EAX_ENVIRONMENT_CONCERTHALL, + EAX_ENVIRONMENT_CAVE, + EAX_ENVIRONMENT_ARENA, + EAX_ENVIRONMENT_HANGAR, + EAX_ENVIRONMENT_CARPETEDHALLWAY, + EAX_ENVIRONMENT_HALLWAY, + EAX_ENVIRONMENT_STONECORRIDOR, + EAX_ENVIRONMENT_ALLEY, + EAX_ENVIRONMENT_FOREST, + EAX_ENVIRONMENT_CITY, + EAX_ENVIRONMENT_MOUNTAINS, + EAX_ENVIRONMENT_QUARRY, + EAX_ENVIRONMENT_PLAIN, + EAX_ENVIRONMENT_PARKINGLOT, + EAX_ENVIRONMENT_SEWERPIPE, + EAX_ENVIRONMENT_UNDERWATER, + EAX_ENVIRONMENT_DRUGGED, + EAX_ENVIRONMENT_DIZZY, + EAX_ENVIRONMENT_PSYCHOTIC, - EAX_ENVIRONMENT_COUNT // total number of environments + EAX_ENVIRONMENT_COUNT // total number of environments }; // EAX presets, usage: BASS_SetEAXParameters(EAX_PRESET_xxx) @@ -479,9 +500,11 @@ enum { #define EAX_PRESET_CAVE EAX_ENVIRONMENT_CAVE, 0.5F, 2.886F, 1.304F #define EAX_PRESET_ARENA EAX_ENVIRONMENT_ARENA, 0.361F, 7.284F, 0.332F #define EAX_PRESET_HANGAR EAX_ENVIRONMENT_HANGAR, 0.5F, 10.0F, 0.3F -#define EAX_PRESET_CARPETEDHALLWAY EAX_ENVIRONMENT_CARPETEDHALLWAY, 0.153F, 0.259F, 2.0F +#define EAX_PRESET_CARPETEDHALLWAY \ + EAX_ENVIRONMENT_CARPETEDHALLWAY, 0.153F, 0.259F, 2.0F #define EAX_PRESET_HALLWAY EAX_ENVIRONMENT_HALLWAY, 0.361F, 1.493F, 0.0F -#define EAX_PRESET_STONECORRIDOR EAX_ENVIRONMENT_STONECORRIDOR, 0.444F, 2.697F, 0.638F +#define EAX_PRESET_STONECORRIDOR \ + EAX_ENVIRONMENT_STONECORRIDOR, 0.444F, 2.697F, 0.638F #define EAX_PRESET_ALLEY EAX_ENVIRONMENT_ALLEY, 0.25F, 1.752F, 0.776F #define EAX_PRESET_FOREST EAX_ENVIRONMENT_FOREST, 0.111F, 3.145F, 0.472F #define EAX_PRESET_CITY EAX_ENVIRONMENT_CITY, 0.111F, 2.767F, 0.224F @@ -495,14 +518,14 @@ enum { #define EAX_PRESET_DIZZY EAX_ENVIRONMENT_DIZZY, 0.139F, 17.234F, 0.666F #define EAX_PRESET_PSYCHOTIC EAX_ENVIRONMENT_PSYCHOTIC, 0.486F, 7.563F, 0.806F -typedef DWORD(CALLBACK STREAMPROC)(HSTREAM handle, void *buffer, DWORD length, void *user); -/* User stream callback function. NOTE: A stream function should obviously be as quick -as possible, other streams (and MOD musics) can't be mixed until it's finished. -handle : The stream that needs writing -buffer : Buffer to write the samples in -length : Number of bytes to write -user : The 'user' parameter value given when calling BASS_StreamCreate -RETURN : Number of bytes written. Set the BASS_STREAMPROC_END flag to end the stream. */ +typedef DWORD(CALLBACK STREAMPROC)(HSTREAM handle, void *buffer, DWORD length, + void *user); +/* User stream callback function. NOTE: A stream function should obviously be as +quick as possible, other streams (and MOD musics) can't be mixed until it's +finished. handle : The stream that needs writing buffer : Buffer to write the +samples in length : Number of bytes to write user : The 'user' parameter value +given when calling BASS_StreamCreate RETURN : Number of bytes written. Set the +BASS_STREAMPROC_END flag to end the stream. */ #define BASS_STREAMPROC_END 0x80000000 // end of user stream flag @@ -524,10 +547,10 @@ typedef DWORD(CALLBACK FILEREADPROC)(void *buffer, DWORD length, void *user); typedef BOOL(CALLBACK FILESEEKPROC)(QWORD offset, void *user); typedef struct { - FILECLOSEPROC *close; - FILELENPROC *length; - FILEREADPROC *read; - FILESEEKPROC *seek; + FILECLOSEPROC *close; + FILELENPROC *length; + FILEREADPROC *read; + FILESEEKPROC *seek; } BASS_FILEPROCS; // BASS_StreamPutFileData options @@ -546,7 +569,8 @@ typedef struct { #define BASS_FILEPOS_SIZE 8 #define BASS_FILEPOS_BUFFERING 9 -typedef void(CALLBACK DOWNLOADPROC)(const void *buffer, DWORD length, void *user); +typedef void(CALLBACK DOWNLOADPROC)(const void *buffer, DWORD length, + void *user); /* Internet stream download callback function. buffer : Buffer containing the downloaded data... NULL=end of download length : Number of bytes in the buffer @@ -570,7 +594,8 @@ user : The 'user' parameter value given when calling BASS_StreamCreateURL */ #define BASS_SYNC_MIXTIME 0x40000000 // flag: sync at mixtime, else at playtime #define BASS_SYNC_ONETIME 0x80000000 // flag: sync only once, else continuously -typedef void(CALLBACK SYNCPROC)(HSYNC handle, DWORD channel, DWORD data, void *user); +typedef void(CALLBACK SYNCPROC)(HSYNC handle, DWORD channel, DWORD data, + void *user); /* Sync callback function. NOTE: a sync callback function should be very quick as other syncs can't be processed until it has finished. If the sync is a "mixtime" sync, then other streams and MOD musics can't be mixed until @@ -580,7 +605,8 @@ channel: Channel that the sync occured in data : Additional data associated with the sync's occurance user : The 'user' parameter given when calling BASS_ChannelSetSync */ -typedef void(CALLBACK DSPPROC)(HDSP handle, DWORD channel, void *buffer, DWORD length, void *user); +typedef void(CALLBACK DSPPROC)(HDSP handle, DWORD channel, void *buffer, + DWORD length, void *user); /* DSP callback function. NOTE: A DSP function should obviously be as quick as possible... other DSP functions, streams and MOD musics can not be processed until it's finished. @@ -590,7 +616,8 @@ buffer : Buffer to apply the DSP to length : Number of bytes in the buffer user : The 'user' parameter given when calling BASS_ChannelSetDSP */ -typedef BOOL(CALLBACK RECORDPROC)(HRECORD handle, const void *buffer, DWORD length, void *user); +typedef BOOL(CALLBACK RECORDPROC)(HRECORD handle, const void *buffer, + DWORD length, void *user); /* Recording callback function. handle : The recording handle buffer : Buffer containing the recorded sample data @@ -644,11 +671,12 @@ RETURN : TRUE = continue recording, FALSE = stop */ #define BASS_DATA_FFT8192 0x80000005 // 8192 FFT #define BASS_DATA_FFT16384 0x80000006 // 16384 FFT #define BASS_DATA_FFT32768 0x80000007 // 32768 FFT -#define BASS_DATA_FFT_INDIVIDUAL 0x10 // FFT flag: FFT for each channel, else all combined -#define BASS_DATA_FFT_NOWINDOW 0x20 // FFT flag: no Hanning window -#define BASS_DATA_FFT_REMOVEDC 0x40 // FFT flag: pre-remove DC bias -#define BASS_DATA_FFT_COMPLEX 0x80 // FFT flag: return complex data -#define BASS_DATA_FFT_NYQUIST 0x100 // FFT flag: return extra Nyquist value +#define BASS_DATA_FFT_INDIVIDUAL \ + 0x10 // FFT flag: FFT for each channel, else all combined +#define BASS_DATA_FFT_NOWINDOW 0x20 // FFT flag: no Hanning window +#define BASS_DATA_FFT_REMOVEDC 0x40 // FFT flag: pre-remove DC bias +#define BASS_DATA_FFT_COMPLEX 0x80 // FFT flag: return complex data +#define BASS_DATA_FFT_NYQUIST 0x100 // FFT flag: return extra Nyquist value // BASS_ChannelGetLevelEx flags #define BASS_LEVEL_MONO 1 @@ -657,52 +685,59 @@ RETURN : TRUE = continue recording, FALSE = stop */ #define BASS_LEVEL_VOLPAN 8 // BASS_ChannelGetTags types : what's returned -#define BASS_TAG_ID3 0 // ID3v1 tags : TAG_ID3 structure -#define BASS_TAG_ID3V2 1 // ID3v2 tags : variable length block -#define BASS_TAG_OGG 2 // OGG comments : series of null-terminated UTF-8 strings -#define BASS_TAG_HTTP 3 // HTTP headers : series of null-terminated ANSI strings -#define BASS_TAG_ICY 4 // ICY headers : series of null-terminated ANSI strings -#define BASS_TAG_META 5 // ICY metadata : ANSI string -#define BASS_TAG_APE 6 // APE tags : series of null-terminated UTF-8 strings -#define BASS_TAG_MP4 7 // MP4/iTunes metadata : series of null-terminated UTF-8 strings -#define BASS_TAG_WMA 8 // WMA tags : series of null-terminated UTF-8 strings -#define BASS_TAG_VENDOR 9 // OGG encoder : UTF-8 string -#define BASS_TAG_LYRICS3 10 // Lyric3v2 tag : ASCII string -#define BASS_TAG_CA_CODEC 11 // CoreAudio codec info : TAG_CA_CODEC structure -#define BASS_TAG_MF 13 // Media Foundation tags : series of null-terminated UTF-8 strings -#define BASS_TAG_WAVEFORMAT 14 // WAVE format : WAVEFORMATEEX structure -#define BASS_TAG_AM_MIME 15 // Android Media MIME type : ASCII string -#define BASS_TAG_AM_NAME 16 // Android Media codec name : ASCII string -#define BASS_TAG_RIFF_INFO 0x100 // RIFF "INFO" tags : series of null-terminated ANSI strings -#define BASS_TAG_RIFF_BEXT 0x101 // RIFF/BWF "bext" tags : TAG_BEXT structure -#define BASS_TAG_RIFF_CART 0x102 // RIFF/BWF "cart" tags : TAG_CART structure -#define BASS_TAG_RIFF_DISP 0x103 // RIFF "DISP" text tag : ANSI string -#define BASS_TAG_RIFF_CUE 0x104 // RIFF "cue " chunk : TAG_CUE structure -#define BASS_TAG_RIFF_SMPL 0x105 // RIFF "smpl" chunk : TAG_SMPL structure -#define BASS_TAG_APE_BINARY 0x1000 // + index #, binary APE tag : TAG_APE_BINARY structure +#define BASS_TAG_ID3 0 // ID3v1 tags : TAG_ID3 structure +#define BASS_TAG_ID3V2 1 // ID3v2 tags : variable length block +#define BASS_TAG_OGG 2 // OGG comments : series of null-terminated UTF-8 strings +#define BASS_TAG_HTTP 3 // HTTP headers : series of null-terminated ANSI strings +#define BASS_TAG_ICY 4 // ICY headers : series of null-terminated ANSI strings +#define BASS_TAG_META 5 // ICY metadata : ANSI string +#define BASS_TAG_APE 6 // APE tags : series of null-terminated UTF-8 strings +#define BASS_TAG_MP4 \ + 7 // MP4/iTunes metadata : series of null-terminated UTF-8 strings +#define BASS_TAG_WMA 8 // WMA tags : series of null-terminated UTF-8 strings +#define BASS_TAG_VENDOR 9 // OGG encoder : UTF-8 string +#define BASS_TAG_LYRICS3 10 // Lyric3v2 tag : ASCII string +#define BASS_TAG_CA_CODEC 11 // CoreAudio codec info : TAG_CA_CODEC structure +#define BASS_TAG_MF \ + 13 // Media Foundation tags : series of null-terminated UTF-8 strings +#define BASS_TAG_WAVEFORMAT 14 // WAVE format : WAVEFORMATEEX structure +#define BASS_TAG_AM_MIME 15 // Android Media MIME type : ASCII string +#define BASS_TAG_AM_NAME 16 // Android Media codec name : ASCII string +#define BASS_TAG_RIFF_INFO \ + 0x100 // RIFF "INFO" tags : series of null-terminated ANSI strings +#define BASS_TAG_RIFF_BEXT 0x101 // RIFF/BWF "bext" tags : TAG_BEXT structure +#define BASS_TAG_RIFF_CART 0x102 // RIFF/BWF "cart" tags : TAG_CART structure +#define BASS_TAG_RIFF_DISP 0x103 // RIFF "DISP" text tag : ANSI string +#define BASS_TAG_RIFF_CUE 0x104 // RIFF "cue " chunk : TAG_CUE structure +#define BASS_TAG_RIFF_SMPL 0x105 // RIFF "smpl" chunk : TAG_SMPL structure +#define BASS_TAG_APE_BINARY \ + 0x1000 // + index #, binary APE tag : TAG_APE_BINARY structure #define BASS_TAG_MUSIC_NAME 0x10000 // MOD music name : ANSI string #define BASS_TAG_MUSIC_MESSAGE 0x10001 // MOD message : ANSI string -#define BASS_TAG_MUSIC_ORDERS 0x10002 // MOD order list : BYTE array of pattern numbers -#define BASS_TAG_MUSIC_AUTH 0x10003 // MOD author : UTF-8 string -#define BASS_TAG_MUSIC_INST 0x10100 // + instrument #, MOD instrument name : ANSI string -#define BASS_TAG_MUSIC_SAMPLE 0x10300 // + sample #, MOD sample name : ANSI string +#define BASS_TAG_MUSIC_ORDERS \ + 0x10002 // MOD order list : BYTE array of pattern numbers +#define BASS_TAG_MUSIC_AUTH 0x10003 // MOD author : UTF-8 string +#define BASS_TAG_MUSIC_INST \ + 0x10100 // + instrument #, MOD instrument name : ANSI string +#define BASS_TAG_MUSIC_SAMPLE \ + 0x10300 // + sample #, MOD sample name : ANSI string // ID3v1 tag structure typedef struct { - char id[3]; - char title[30]; - char artist[30]; - char album[30]; - char year[4]; - char comment[30]; - BYTE genre; + char id[3]; + char title[30]; + char artist[30]; + char album[30]; + char year[4]; + char comment[30]; + BYTE genre; } TAG_ID3; // Binary APE tag structure typedef struct { - const char *key; - const void *data; - DWORD length; + const char *key; + const void *data; + DWORD length; } TAG_APE_BINARY; // BWF "bext" tag structure @@ -712,113 +747,107 @@ typedef struct { #endif #pragma pack(push, 1) typedef struct { - char Description[256]; // description - char Originator[32]; // name of the originator - char OriginatorReference[32]; // reference of the originator - char OriginationDate[10]; // date of creation (yyyy-mm-dd) - char OriginationTime[8]; // time of creation (hh-mm-ss) - QWORD TimeReference; // first sample count since midnight (little-endian) - WORD Version; // BWF version (little-endian) - BYTE UMID[64]; // SMPTE UMID - BYTE Reserved[190]; + char Description[256]; // description + char Originator[32]; // name of the originator + char OriginatorReference[32]; // reference of the originator + char OriginationDate[10]; // date of creation (yyyy-mm-dd) + char OriginationTime[8]; // time of creation (hh-mm-ss) + QWORD TimeReference; // first sample count since midnight (little-endian) + WORD Version; // BWF version (little-endian) + BYTE UMID[64]; // SMPTE UMID + BYTE Reserved[190]; #if defined(__GNUC__) && __GNUC__ < 3 - char CodingHistory[0]; // history -#elif 1 // change to 0 if compiler fails the following line - char CodingHistory[]; // history + char CodingHistory[0]; // history +#elif 1 // change to 0 if compiler fails the following line + char CodingHistory[]; // history #else - char CodingHistory[1]; // history + char CodingHistory[1]; // history #endif } TAG_BEXT; #pragma pack(pop) // BWF "cart" tag structures -typedef struct -{ - DWORD dwUsage; // FOURCC timer usage ID - DWORD dwValue; // timer value in samples from head +typedef struct { + DWORD dwUsage; // FOURCC timer usage ID + DWORD dwValue; // timer value in samples from head } TAG_CART_TIMER; -typedef struct -{ - char Version[4]; // version of the data structure - char Title[64]; // title of cart audio sequence - char Artist[64]; // artist or creator name - char CutID[64]; // cut number identification - char ClientID[64]; // client identification - char Category[64]; // category ID, PSA, NEWS, etc - char Classification[64]; // classification or auxiliary key - char OutCue[64]; // out cue text - char StartDate[10]; // yyyy-mm-dd - char StartTime[8]; // hh:mm:ss - char EndDate[10]; // yyyy-mm-dd - char EndTime[8]; // hh:mm:ss - char ProducerAppID[64]; // name of vendor or application - char ProducerAppVersion[64]; // version of producer application - char UserDef[64]; // user defined text - DWORD dwLevelReference; // sample value for 0 dB reference - TAG_CART_TIMER PostTimer[8]; // 8 time markers after head - char Reserved[276]; - char URL[1024]; // uniform resource locator +typedef struct { + char Version[4]; // version of the data structure + char Title[64]; // title of cart audio sequence + char Artist[64]; // artist or creator name + char CutID[64]; // cut number identification + char ClientID[64]; // client identification + char Category[64]; // category ID, PSA, NEWS, etc + char Classification[64]; // classification or auxiliary key + char OutCue[64]; // out cue text + char StartDate[10]; // yyyy-mm-dd + char StartTime[8]; // hh:mm:ss + char EndDate[10]; // yyyy-mm-dd + char EndTime[8]; // hh:mm:ss + char ProducerAppID[64]; // name of vendor or application + char ProducerAppVersion[64]; // version of producer application + char UserDef[64]; // user defined text + DWORD dwLevelReference; // sample value for 0 dB reference + TAG_CART_TIMER PostTimer[8]; // 8 time markers after head + char Reserved[276]; + char URL[1024]; // uniform resource locator #if defined(__GNUC__) && __GNUC__ < 3 - char TagText[0]; // free form text for scripts or tags -#elif 1 // change to 0 if compiler fails the following line - char TagText[]; // free form text for scripts or tags + char TagText[0]; // free form text for scripts or tags +#elif 1 // change to 0 if compiler fails the following line + char TagText[]; // free form text for scripts or tags #else - char TagText[1]; // free form text for scripts or tags + char TagText[1]; // free form text for scripts or tags #endif } TAG_CART; // RIFF "cue " tag structures -typedef struct -{ - DWORD dwName; - DWORD dwPosition; - DWORD fccChunk; - DWORD dwChunkStart; - DWORD dwBlockStart; - DWORD dwSampleOffset; +typedef struct { + DWORD dwName; + DWORD dwPosition; + DWORD fccChunk; + DWORD dwChunkStart; + DWORD dwBlockStart; + DWORD dwSampleOffset; } TAG_CUE_POINT; -typedef struct -{ - DWORD dwCuePoints; +typedef struct { + DWORD dwCuePoints; #if defined(__GNUC__) && __GNUC__ < 3 - TAG_CUE_POINT CuePoints[0]; + TAG_CUE_POINT CuePoints[0]; #elif 1 // change to 0 if compiler fails the following line - TAG_CUE_POINT CuePoints[]; + TAG_CUE_POINT CuePoints[]; #else - TAG_CUE_POINT CuePoints[1]; + TAG_CUE_POINT CuePoints[1]; #endif } TAG_CUE; // RIFF "smpl" tag structures -typedef struct -{ - DWORD dwIdentifier; - DWORD dwType; - DWORD dwStart; - DWORD dwEnd; - DWORD dwFraction; - DWORD dwPlayCount; +typedef struct { + DWORD dwIdentifier; + DWORD dwType; + DWORD dwStart; + DWORD dwEnd; + DWORD dwFraction; + DWORD dwPlayCount; } TAG_SMPL_LOOP; -typedef struct -{ - DWORD dwManufacturer; - DWORD dwProduct; - DWORD dwSamplePeriod; - DWORD dwMIDIUnityNote; - DWORD dwMIDIPitchFraction; - DWORD dwSMPTEFormat; - DWORD dwSMPTEOffset; - DWORD cSampleLoops; - DWORD cbSamplerData; +typedef struct { + DWORD dwManufacturer; + DWORD dwProduct; + DWORD dwSamplePeriod; + DWORD dwMIDIUnityNote; + DWORD dwMIDIPitchFraction; + DWORD dwSMPTEFormat; + DWORD dwSMPTEOffset; + DWORD cSampleLoops; + DWORD cbSamplerData; #if defined(__GNUC__) && __GNUC__ < 3 - TAG_SMPL_LOOP SampleLoops[0]; + TAG_SMPL_LOOP SampleLoops[0]; #elif 1 // change to 0 if compiler fails the following line - TAG_SMPL_LOOP SampleLoops[]; + TAG_SMPL_LOOP SampleLoops[]; #else - TAG_SMPL_LOOP SampleLoops[1]; + TAG_SMPL_LOOP SampleLoops[1]; #endif } TAG_SMPL; #ifdef _MSC_VER @@ -827,37 +856,40 @@ typedef struct // CoreAudio codec info structure typedef struct { - DWORD ftype; // file format - DWORD atype; // audio format - const char *name; // description + DWORD ftype; // file format + DWORD atype; // audio format + const char *name; // description } TAG_CA_CODEC; #ifndef _WAVEFORMATEX_ #define _WAVEFORMATEX_ #pragma pack(push, 1) typedef struct tWAVEFORMATEX { - WORD wFormatTag; - WORD nChannels; - DWORD nSamplesPerSec; - DWORD nAvgBytesPerSec; - WORD nBlockAlign; - WORD wBitsPerSample; - WORD cbSize; + WORD wFormatTag; + WORD nChannels; + DWORD nSamplesPerSec; + DWORD nAvgBytesPerSec; + WORD nBlockAlign; + WORD wBitsPerSample; + WORD cbSize; } WAVEFORMATEX, *PWAVEFORMATEX, *LPWAVEFORMATEX; typedef const WAVEFORMATEX *LPCWAVEFORMATEX; #pragma pack(pop) #endif // BASS_ChannelGetLength/GetPosition/SetPosition modes -#define BASS_POS_BYTE 0 // byte position -#define BASS_POS_MUSIC_ORDER 1 // order.row position, MAKELONG(order,row) -#define BASS_POS_OGG 3 // OGG bitstream number -#define BASS_POS_RESET 0x2000000 // flag: reset user file buffers -#define BASS_POS_RELATIVE 0x4000000 // flag: seek relative to the current position -#define BASS_POS_INEXACT 0x8000000 // flag: allow seeking to inexact position -#define BASS_POS_DECODE 0x10000000 // flag: get the decoding (not playing) position -#define BASS_POS_DECODETO 0x20000000 // flag: decode to the position instead of seeking -#define BASS_POS_SCAN 0x40000000 // flag: scan to the position +#define BASS_POS_BYTE 0 // byte position +#define BASS_POS_MUSIC_ORDER 1 // order.row position, MAKELONG(order,row) +#define BASS_POS_OGG 3 // OGG bitstream number +#define BASS_POS_RESET 0x2000000 // flag: reset user file buffers +#define BASS_POS_RELATIVE \ + 0x4000000 // flag: seek relative to the current position +#define BASS_POS_INEXACT 0x8000000 // flag: allow seeking to inexact position +#define BASS_POS_DECODE \ + 0x10000000 // flag: get the decoding (not playing) position +#define BASS_POS_DECODETO \ + 0x20000000 // flag: decode to the position instead of seeking +#define BASS_POS_SCAN 0x40000000 // flag: scan to the position // BASS_ChannelSetDevice/GetDevice option #define BASS_NODEVICE 0x20000 @@ -892,81 +924,81 @@ typedef const WAVEFORMATEX *LPCWAVEFORMATEX; #define BASS_FX_VOLUME 9 typedef struct { - float fWetDryMix; - float fDepth; - float fFeedback; - float fFrequency; - DWORD lWaveform; // 0=triangle, 1=sine - float fDelay; - DWORD lPhase; // BASS_DX8_PHASE_xxx + float fWetDryMix; + float fDepth; + float fFeedback; + float fFrequency; + DWORD lWaveform; // 0=triangle, 1=sine + float fDelay; + DWORD lPhase; // BASS_DX8_PHASE_xxx } BASS_DX8_CHORUS; typedef struct { - float fGain; - float fAttack; - float fRelease; - float fThreshold; - float fRatio; - float fPredelay; + float fGain; + float fAttack; + float fRelease; + float fThreshold; + float fRatio; + float fPredelay; } BASS_DX8_COMPRESSOR; typedef struct { - float fGain; - float fEdge; - float fPostEQCenterFrequency; - float fPostEQBandwidth; - float fPreLowpassCutoff; + float fGain; + float fEdge; + float fPostEQCenterFrequency; + float fPostEQBandwidth; + float fPreLowpassCutoff; } BASS_DX8_DISTORTION; typedef struct { - float fWetDryMix; - float fFeedback; - float fLeftDelay; - float fRightDelay; - BOOL lPanDelay; + float fWetDryMix; + float fFeedback; + float fLeftDelay; + float fRightDelay; + BOOL lPanDelay; } BASS_DX8_ECHO; typedef struct { - float fWetDryMix; - float fDepth; - float fFeedback; - float fFrequency; - DWORD lWaveform; // 0=triangle, 1=sine - float fDelay; - DWORD lPhase; // BASS_DX8_PHASE_xxx + float fWetDryMix; + float fDepth; + float fFeedback; + float fFrequency; + DWORD lWaveform; // 0=triangle, 1=sine + float fDelay; + DWORD lPhase; // BASS_DX8_PHASE_xxx } BASS_DX8_FLANGER; typedef struct { - DWORD dwRateHz; // Rate of modulation in hz - DWORD dwWaveShape; // 0=triangle, 1=square + DWORD dwRateHz; // Rate of modulation in hz + DWORD dwWaveShape; // 0=triangle, 1=square } BASS_DX8_GARGLE; typedef struct { - int lRoom; // [-10000, 0] default: -1000 mB - int lRoomHF; // [-10000, 0] default: 0 mB - float flRoomRolloffFactor; // [0.0, 10.0] default: 0.0 - float flDecayTime; // [0.1, 20.0] default: 1.49s - float flDecayHFRatio; // [0.1, 2.0] default: 0.83 - int lReflections; // [-10000, 1000] default: -2602 mB - float flReflectionsDelay; // [0.0, 0.3] default: 0.007 s - int lReverb; // [-10000, 2000] default: 200 mB - float flReverbDelay; // [0.0, 0.1] default: 0.011 s - float flDiffusion; // [0.0, 100.0] default: 100.0 % - float flDensity; // [0.0, 100.0] default: 100.0 % - float flHFReference; // [20.0, 20000.0] default: 5000.0 Hz + int lRoom; // [-10000, 0] default: -1000 mB + int lRoomHF; // [-10000, 0] default: 0 mB + float flRoomRolloffFactor; // [0.0, 10.0] default: 0.0 + float flDecayTime; // [0.1, 20.0] default: 1.49s + float flDecayHFRatio; // [0.1, 2.0] default: 0.83 + int lReflections; // [-10000, 1000] default: -2602 mB + float flReflectionsDelay; // [0.0, 0.3] default: 0.007 s + int lReverb; // [-10000, 2000] default: 200 mB + float flReverbDelay; // [0.0, 0.1] default: 0.011 s + float flDiffusion; // [0.0, 100.0] default: 100.0 % + float flDensity; // [0.0, 100.0] default: 100.0 % + float flHFReference; // [20.0, 20000.0] default: 5000.0 Hz } BASS_DX8_I3DL2REVERB; typedef struct { - float fCenter; - float fBandwidth; - float fGain; + float fCenter; + float fBandwidth; + float fGain; } BASS_DX8_PARAMEQ; typedef struct { - float fInGain; // [-96.0,0.0] default: 0.0 dB - float fReverbMix; // [-96.0,0.0] default: 0.0 db - float fReverbTime; // [0.001,3000.0] default: 1000.0 ms - float fHighFreqRTRatio; // [0.001,0.999] default: 0.001 + float fInGain; // [-96.0,0.0] default: 0.0 dB + float fReverbMix; // [-96.0,0.0] default: 0.0 db + float fReverbTime; // [0.001,3000.0] default: 1000.0 ms + float fHighFreqRTRatio; // [0.001,0.999] default: 0.001 } BASS_DX8_REVERB; #define BASS_DX8_PHASE_NEG_180 0 @@ -976,10 +1008,10 @@ typedef struct { #define BASS_DX8_PHASE_180 4 typedef struct { - float fTarget; - float fCurrent; - float fTime; - DWORD lCurve; + float fTarget; + float fCurrent; + float fTime; + DWORD lCurve; } BASS_FX_VOLUME_PARAM; typedef void(CALLBACK IOSNOTIFYPROC)(DWORD status); @@ -996,15 +1028,19 @@ void *BASSDEF(BASS_GetConfigPtr)(DWORD option); DWORD BASSDEF(BASS_GetVersion)(); int BASSDEF(BASS_ErrorGetCode)(); BOOL BASSDEF(BASS_GetDeviceInfo)(DWORD device, BASS_DEVICEINFO *info); -#if defined(_WIN32) && !defined(_WIN32_WCE) && !(WINAPI_FAMILY && WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP) -BOOL BASSDEF(BASS_Init)(int device, DWORD freq, DWORD flags, HWND win, const GUID *dsguid); +#if defined(_WIN32) && !defined(_WIN32_WCE) && \ + !(WINAPI_FAMILY && WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP) +BOOL BASSDEF(BASS_Init)(int device, DWORD freq, DWORD flags, HWND win, + const GUID *dsguid); #else -BOOL BASSDEF(BASS_Init)(int device, DWORD freq, DWORD flags, void *win, void *dsguid); +BOOL BASSDEF(BASS_Init)(int device, DWORD freq, DWORD flags, void *win, + void *dsguid); #endif BOOL BASSDEF(BASS_SetDevice)(DWORD device); DWORD BASSDEF(BASS_GetDevice)(); BOOL BASSDEF(BASS_Free)(); -#if defined(_WIN32) && !defined(_WIN32_WCE) && !(WINAPI_FAMILY && WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP) +#if defined(_WIN32) && !defined(_WIN32_WCE) && \ + !(WINAPI_FAMILY && WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP) void *BASSDEF(BASS_GetDSoundObject)(DWORD object); #endif BOOL BASSDEF(BASS_GetInfo)(BASS_INFO *info); @@ -1023,19 +1059,29 @@ const BASS_PLUGININFO *BASSDEF(BASS_PluginGetInfo)(HPLUGIN handle); BOOL BASSDEF(BASS_Set3DFactors)(float distf, float rollf, float doppf); BOOL BASSDEF(BASS_Get3DFactors)(float *distf, float *rollf, float *doppf); -BOOL BASSDEF(BASS_Set3DPosition)(const BASS_3DVECTOR *pos, const BASS_3DVECTOR *vel, const BASS_3DVECTOR *front, const BASS_3DVECTOR *top); -BOOL BASSDEF(BASS_Get3DPosition)(BASS_3DVECTOR *pos, BASS_3DVECTOR *vel, BASS_3DVECTOR *front, BASS_3DVECTOR *top); +BOOL BASSDEF(BASS_Set3DPosition)(const BASS_3DVECTOR *pos, + const BASS_3DVECTOR *vel, + const BASS_3DVECTOR *front, + const BASS_3DVECTOR *top); +BOOL BASSDEF(BASS_Get3DPosition)(BASS_3DVECTOR *pos, BASS_3DVECTOR *vel, + BASS_3DVECTOR *front, BASS_3DVECTOR *top); void BASSDEF(BASS_Apply3D)(); -#if defined(_WIN32) && !defined(_WIN32_WCE) && !(WINAPI_FAMILY && WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP) -BOOL BASSDEF(BASS_SetEAXParameters)(int env, float vol, float decay, float damp); -BOOL BASSDEF(BASS_GetEAXParameters)(DWORD *env, float *vol, float *decay, float *damp); +#if defined(_WIN32) && !defined(_WIN32_WCE) && \ + !(WINAPI_FAMILY && WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP) +BOOL BASSDEF(BASS_SetEAXParameters)(int env, float vol, float decay, + float damp); +BOOL BASSDEF(BASS_GetEAXParameters)(DWORD *env, float *vol, float *decay, + float *damp); #endif -HMUSIC BASSDEF(BASS_MusicLoad)(BOOL mem, const void *file, QWORD offset, DWORD length, DWORD flags, DWORD freq); +HMUSIC BASSDEF(BASS_MusicLoad)(BOOL mem, const void *file, QWORD offset, + DWORD length, DWORD flags, DWORD freq); BOOL BASSDEF(BASS_MusicFree)(HMUSIC handle); -HSAMPLE BASSDEF(BASS_SampleLoad)(BOOL mem, const void *file, QWORD offset, DWORD length, DWORD max, DWORD flags); -HSAMPLE BASSDEF(BASS_SampleCreate)(DWORD length, DWORD freq, DWORD chans, DWORD max, DWORD flags); +HSAMPLE BASSDEF(BASS_SampleLoad)(BOOL mem, const void *file, QWORD offset, + DWORD length, DWORD max, DWORD flags); +HSAMPLE BASSDEF(BASS_SampleCreate)(DWORD length, DWORD freq, DWORD chans, + DWORD max, DWORD flags); BOOL BASSDEF(BASS_SampleFree)(HSAMPLE handle); BOOL BASSDEF(BASS_SampleSetData)(HSAMPLE handle, const void *buffer); BOOL BASSDEF(BASS_SampleGetData)(HSAMPLE handle, void *buffer); @@ -1045,14 +1091,22 @@ HCHANNEL BASSDEF(BASS_SampleGetChannel)(HSAMPLE handle, BOOL onlynew); DWORD BASSDEF(BASS_SampleGetChannels)(HSAMPLE handle, HCHANNEL *channels); BOOL BASSDEF(BASS_SampleStop)(HSAMPLE handle); -HSTREAM BASSDEF(BASS_StreamCreate)(DWORD freq, DWORD chans, DWORD flags, STREAMPROC *proc, void *user); -HSTREAM BASSDEF(BASS_StreamCreateFile)(BOOL mem, const void *file, QWORD offset, QWORD length, DWORD flags); -HSTREAM BASSDEF(BASS_StreamCreateURL)(const char *url, DWORD offset, DWORD flags, DOWNLOADPROC *proc, void *user); -HSTREAM BASSDEF(BASS_StreamCreateFileUser)(DWORD system, DWORD flags, const BASS_FILEPROCS *proc, void *user); +HSTREAM BASSDEF(BASS_StreamCreate)(DWORD freq, DWORD chans, DWORD flags, + STREAMPROC *proc, void *user); +HSTREAM BASSDEF(BASS_StreamCreateFile)(BOOL mem, const void *file, QWORD offset, + QWORD length, DWORD flags); +HSTREAM BASSDEF(BASS_StreamCreateURL)(const char *url, DWORD offset, + DWORD flags, DOWNLOADPROC *proc, + void *user); +HSTREAM BASSDEF(BASS_StreamCreateFileUser)(DWORD system, DWORD flags, + const BASS_FILEPROCS *proc, + void *user); BOOL BASSDEF(BASS_StreamFree)(HSTREAM handle); QWORD BASSDEF(BASS_StreamGetFilePosition)(HSTREAM handle, DWORD mode); -DWORD BASSDEF(BASS_StreamPutData)(HSTREAM handle, const void *buffer, DWORD length); -DWORD BASSDEF(BASS_StreamPutFileData)(HSTREAM handle, const void *buffer, DWORD length); +DWORD BASSDEF(BASS_StreamPutData)(HSTREAM handle, const void *buffer, + DWORD length); +DWORD BASSDEF(BASS_StreamPutFileData)(HSTREAM handle, const void *buffer, + DWORD length); BOOL BASSDEF(BASS_RecordGetDeviceInfo)(DWORD device, BASS_DEVICEINFO *info); BOOL BASSDEF(BASS_RecordInit)(int device); @@ -1063,7 +1117,8 @@ BOOL BASSDEF(BASS_RecordGetInfo)(BASS_RECORDINFO *info); const char *BASSDEF(BASS_RecordGetInputName)(int input); BOOL BASSDEF(BASS_RecordSetInput)(int input, DWORD flags, float volume); DWORD BASSDEF(BASS_RecordGetInput)(int input, float *volume); -HRECORD BASSDEF(BASS_RecordStart)(DWORD freq, DWORD chans, DWORD flags, RECORDPROC *proc, void *user); +HRECORD BASSDEF(BASS_RecordStart)(DWORD freq, DWORD chans, DWORD flags, + RECORDPROC *proc, void *user); double BASSDEF(BASS_ChannelBytes2Seconds)(DWORD handle, QWORD pos); QWORD BASSDEF(BASS_ChannelSeconds2Bytes)(DWORD handle, double pos); @@ -1079,24 +1134,39 @@ BOOL BASSDEF(BASS_ChannelPlay)(DWORD handle, BOOL restart); BOOL BASSDEF(BASS_ChannelStop)(DWORD handle); BOOL BASSDEF(BASS_ChannelPause)(DWORD handle); BOOL BASSDEF(BASS_ChannelSetAttribute)(DWORD handle, DWORD attrib, float value); -BOOL BASSDEF(BASS_ChannelGetAttribute)(DWORD handle, DWORD attrib, float *value); -BOOL BASSDEF(BASS_ChannelSlideAttribute)(DWORD handle, DWORD attrib, float value, DWORD time); +BOOL BASSDEF(BASS_ChannelGetAttribute)(DWORD handle, DWORD attrib, + float *value); +BOOL BASSDEF(BASS_ChannelSlideAttribute)(DWORD handle, DWORD attrib, + float value, DWORD time); BOOL BASSDEF(BASS_ChannelIsSliding)(DWORD handle, DWORD attrib); -BOOL BASSDEF(BASS_ChannelSetAttributeEx)(DWORD handle, DWORD attrib, void *value, DWORD size); -DWORD BASSDEF(BASS_ChannelGetAttributeEx)(DWORD handle, DWORD attrib, void *value, DWORD size); -BOOL BASSDEF(BASS_ChannelSet3DAttributes)(DWORD handle, int mode, float min, float max, int iangle, int oangle, float outvol); -BOOL BASSDEF(BASS_ChannelGet3DAttributes)(DWORD handle, DWORD *mode, float *min, float *max, DWORD *iangle, DWORD *oangle, float *outvol); -BOOL BASSDEF(BASS_ChannelSet3DPosition)(DWORD handle, const BASS_3DVECTOR *pos, const BASS_3DVECTOR *orient, const BASS_3DVECTOR *vel); -BOOL BASSDEF(BASS_ChannelGet3DPosition)(DWORD handle, BASS_3DVECTOR *pos, BASS_3DVECTOR *orient, BASS_3DVECTOR *vel); +BOOL BASSDEF(BASS_ChannelSetAttributeEx)(DWORD handle, DWORD attrib, + void *value, DWORD size); +DWORD BASSDEF(BASS_ChannelGetAttributeEx)(DWORD handle, DWORD attrib, + void *value, DWORD size); +BOOL BASSDEF(BASS_ChannelSet3DAttributes)(DWORD handle, int mode, float min, + float max, int iangle, int oangle, + float outvol); +BOOL BASSDEF(BASS_ChannelGet3DAttributes)(DWORD handle, DWORD *mode, float *min, + float *max, DWORD *iangle, + DWORD *oangle, float *outvol); +BOOL BASSDEF(BASS_ChannelSet3DPosition)(DWORD handle, const BASS_3DVECTOR *pos, + const BASS_3DVECTOR *orient, + const BASS_3DVECTOR *vel); +BOOL BASSDEF(BASS_ChannelGet3DPosition)(DWORD handle, BASS_3DVECTOR *pos, + BASS_3DVECTOR *orient, + BASS_3DVECTOR *vel); QWORD BASSDEF(BASS_ChannelGetLength)(DWORD handle, DWORD mode); BOOL BASSDEF(BASS_ChannelSetPosition)(DWORD handle, QWORD pos, DWORD mode); QWORD BASSDEF(BASS_ChannelGetPosition)(DWORD handle, DWORD mode); DWORD BASSDEF(BASS_ChannelGetLevel)(DWORD handle); -BOOL BASSDEF(BASS_ChannelGetLevelEx)(DWORD handle, float *levels, float length, DWORD flags); +BOOL BASSDEF(BASS_ChannelGetLevelEx)(DWORD handle, float *levels, float length, + DWORD flags); DWORD BASSDEF(BASS_ChannelGetData)(DWORD handle, void *buffer, DWORD length); -HSYNC BASSDEF(BASS_ChannelSetSync)(DWORD handle, DWORD type, QWORD param, SYNCPROC *proc, void *user); +HSYNC BASSDEF(BASS_ChannelSetSync)(DWORD handle, DWORD type, QWORD param, + SYNCPROC *proc, void *user); BOOL BASSDEF(BASS_ChannelRemoveSync)(DWORD handle, HSYNC sync); -HDSP BASSDEF(BASS_ChannelSetDSP)(DWORD handle, DSPPROC *proc, void *user, int priority); +HDSP BASSDEF(BASS_ChannelSetDSP)(DWORD handle, DSPPROC *proc, void *user, + int priority); BOOL BASSDEF(BASS_ChannelRemoveDSP)(DWORD handle, HDSP dsp); BOOL BASSDEF(BASS_ChannelSetLink)(DWORD handle, DWORD chan); BOOL BASSDEF(BASS_ChannelRemoveLink)(DWORD handle, DWORD chan); @@ -1114,32 +1184,42 @@ BOOL BASSDEF(BASS_FXSetPriority)(HFX handle, int priority); #if defined(_WIN32) && !defined(NOBASSOVERLOADS) static inline HPLUGIN BASS_PluginLoad(const WCHAR *file, DWORD flags) { - return BASS_PluginLoad((const char *)file, flags | BASS_UNICODE); + return BASS_PluginLoad((const char *)file, flags | BASS_UNICODE); } -static inline HMUSIC BASS_MusicLoad(BOOL mem, const WCHAR *file, QWORD offset, DWORD length, DWORD flags, DWORD freq) +static inline HMUSIC BASS_MusicLoad(BOOL mem, const WCHAR *file, QWORD offset, + DWORD length, DWORD flags, DWORD freq) { - return BASS_MusicLoad(mem, (const void *)file, offset, length, flags | BASS_UNICODE, freq); + return BASS_MusicLoad(mem, (const void *)file, offset, length, + flags | BASS_UNICODE, freq); } -static inline HSAMPLE BASS_SampleLoad(BOOL mem, const WCHAR *file, QWORD offset, DWORD length, DWORD max, DWORD flags) +static inline HSAMPLE BASS_SampleLoad(BOOL mem, const WCHAR *file, QWORD offset, + DWORD length, DWORD max, DWORD flags) { - return BASS_SampleLoad(mem, (const void *)file, offset, length, max, flags | BASS_UNICODE); + return BASS_SampleLoad(mem, (const void *)file, offset, length, max, + flags | BASS_UNICODE); } -static inline HSTREAM BASS_StreamCreateFile(BOOL mem, const WCHAR *file, QWORD offset, QWORD length, DWORD flags) +static inline HSTREAM BASS_StreamCreateFile(BOOL mem, const WCHAR *file, + QWORD offset, QWORD length, + DWORD flags) { - return BASS_StreamCreateFile(mem, (const void *)file, offset, length, flags | BASS_UNICODE); + return BASS_StreamCreateFile(mem, (const void *)file, offset, length, + flags | BASS_UNICODE); } -static inline HSTREAM BASS_StreamCreateURL(const WCHAR *url, DWORD offset, DWORD flags, DOWNLOADPROC *proc, void *user) +static inline HSTREAM BASS_StreamCreateURL(const WCHAR *url, DWORD offset, + DWORD flags, DOWNLOADPROC *proc, + void *user) { - return BASS_StreamCreateURL((const char *)url, offset, flags | BASS_UNICODE, proc, user); + return BASS_StreamCreateURL((const char *)url, offset, flags | BASS_UNICODE, + proc, user); } static inline BOOL BASS_SetConfigPtr(DWORD option, const WCHAR *value) { - return BASS_SetConfigPtr(option | BASS_UNICODE, (const void *)value); + return BASS_SetConfigPtr(option | BASS_UNICODE, (const void *)value); } #endif #endif diff --git a/include/bassopus.h b/include/bassopus.h index 757ff70..3d8b131 100644 --- a/include/bassopus.h +++ b/include/bassopus.h @@ -1,8 +1,8 @@ /* - BASSOPUS 2.4 C/C++ header file - Copyright (c) 2012-2015 Un4seen Developments Ltd. + BASSOPUS 2.4 C/C++ header file + Copyright (c) 2012-2015 Un4seen Developments Ltd. - See the BASSOPUS.CHM file for more detailed documentation + See the BASSOPUS.CHM file for more detailed documentation */ #ifndef BASSOPUS_H @@ -29,22 +29,34 @@ extern "C" { #define BASS_ATTRIB_OPUS_ORIGFREQ 0x13000 #define BASS_ATTRIB_OPUS_GAIN 0x13001 -HSTREAM BASSOPUSDEF(BASS_OPUS_StreamCreateFile)(BOOL mem, const void *file, QWORD offset, QWORD length, DWORD flags); -HSTREAM BASSOPUSDEF(BASS_OPUS_StreamCreateURL)(const char *url, DWORD offset, DWORD flags, DOWNLOADPROC *proc, void *user); -HSTREAM BASSOPUSDEF(BASS_OPUS_StreamCreateFileUser)(DWORD system, DWORD flags, const BASS_FILEPROCS *procs, void *user); +HSTREAM BASSOPUSDEF(BASS_OPUS_StreamCreateFile)(BOOL mem, const void *file, + QWORD offset, QWORD length, + DWORD flags); +HSTREAM BASSOPUSDEF(BASS_OPUS_StreamCreateURL)(const char *url, DWORD offset, + DWORD flags, DOWNLOADPROC *proc, + void *user); +HSTREAM BASSOPUSDEF(BASS_OPUS_StreamCreateFileUser)(DWORD system, DWORD flags, + const BASS_FILEPROCS *procs, + void *user); #ifdef __cplusplus } #if defined(_WIN32) && !defined(NOBASSOVERLOADS) -static inline HSTREAM BASS_OPUS_StreamCreateFile(BOOL mem, const WCHAR *file, QWORD offset, QWORD length, DWORD flags) +static inline HSTREAM BASS_OPUS_StreamCreateFile(BOOL mem, const WCHAR *file, + QWORD offset, QWORD length, + DWORD flags) { - return BASS_OPUS_StreamCreateFile(mem, (const void *)file, offset, length, flags | BASS_UNICODE); + return BASS_OPUS_StreamCreateFile(mem, (const void *)file, offset, length, + flags | BASS_UNICODE); } -static inline HSTREAM BASS_OPUS_StreamCreateURL(const WCHAR *url, DWORD offset, DWORD flags, DOWNLOADPROC *proc, void *user) +static inline HSTREAM BASS_OPUS_StreamCreateURL(const WCHAR *url, DWORD offset, + DWORD flags, DOWNLOADPROC *proc, + void *user) { - return BASS_OPUS_StreamCreateURL((const char *)url, offset, flags | BASS_UNICODE, proc, user); + return BASS_OPUS_StreamCreateURL((const char *)url, offset, + flags | BASS_UNICODE, proc, user); } #endif #endif diff --git a/include/chatlogpiece.h b/include/chatlogpiece.h index c2d32b2..e6f77c7 100644 --- a/include/chatlogpiece.h +++ b/include/chatlogpiece.h @@ -6,25 +6,27 @@ class chatlogpiece { public: - chatlogpiece(); - chatlogpiece(QString p_name, QString p_showname, QString p_message, bool p_song); - chatlogpiece(QString p_name, QString p_showname, QString p_message, bool p_song, QDateTime p_datetime); + chatlogpiece(); + chatlogpiece(QString p_name, QString p_showname, QString p_message, + bool p_song); + chatlogpiece(QString p_name, QString p_showname, QString p_message, + bool p_song, QDateTime p_datetime); - QString get_name(); - QString get_showname(); - QString get_message(); - bool is_song(); - QDateTime get_datetime(); - QString get_datetime_as_string(); + QString get_name(); + QString get_showname(); + QString get_message(); + bool is_song(); + QDateTime get_datetime(); + QString get_datetime_as_string(); - QString get_full(); + QString get_full(); private: - QString name; - QString showname; - QString message; - QDateTime datetime; - bool p_is_song; + QString name; + QString showname; + QString message; + QDateTime datetime; + bool p_is_song; }; #endif // CHATLOGPIECE_H diff --git a/include/courtroom.h b/include/courtroom.h index c3c6b87..259a7ed 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -63,723 +63,743 @@ class AOApplication; class Courtroom : public QMainWindow { - Q_OBJECT + Q_OBJECT public: - explicit Courtroom(AOApplication *p_ao_app); + explicit Courtroom(AOApplication *p_ao_app); - void append_char(char_type p_char) { char_list.append(p_char); } - void append_evidence(evi_type p_evi) { evidence_list.append(p_evi); } - void append_music(QString f_music) { music_list.append(f_music); } - void append_area(QString f_area) { area_list.append(f_area); } - void clear_music() { music_list.clear(); } - void clear_areas() { area_list.clear(); } + void append_char(char_type p_char) { char_list.append(p_char); } + void append_evidence(evi_type p_evi) { evidence_list.append(p_evi); } + void append_music(QString f_music) { music_list.append(f_music); } + void append_area(QString f_area) { area_list.append(f_area); } + void clear_music() { music_list.clear(); } + void clear_areas() { area_list.clear(); } - void fix_last_area() - { - if (area_list.size() > 0) { - QString malplaced = area_list.last(); - area_list.removeLast(); - append_music(malplaced); - } + void fix_last_area() + { + if (area_list.size() > 0) { + QString malplaced = area_list.last(); + area_list.removeLast(); + append_music(malplaced); } + } - void arup_append(int players, QString status, QString cm, QString locked) - { - arup_players.append(players); - arup_statuses.append(status); - arup_cms.append(cm); - arup_locks.append(locked); + void arup_append(int players, QString status, QString cm, QString locked) + { + arup_players.append(players); + arup_statuses.append(status); + arup_cms.append(cm); + arup_locks.append(locked); + } + + void arup_modify(int type, int place, QString value) + { + if (type == 0) { + if (arup_players.size() > place) + arup_players[place] = value.toInt(); } - - void arup_modify(int type, int place, QString value) - { - if (type == 0) { - if (arup_players.size() > place) - arup_players[place] = value.toInt(); - } - else if (type == 1) { - if (arup_statuses.size() > place) - arup_statuses[place] = value; - } - else if (type == 2) { - if (arup_cms.size() > place) - arup_cms[place] = value; - } - else if (type == 3) { - if (arup_locks.size() > place) - arup_locks[place] = value; - } - list_areas(); + else if (type == 1) { + if (arup_statuses.size() > place) + arup_statuses[place] = value; } + else if (type == 2) { + if (arup_cms.size() > place) + arup_cms[place] = value; + } + else if (type == 3) { + if (arup_locks.size() > place) + arup_locks[place] = value; + } + list_areas(); + } - void character_loading_finished(); + void character_loading_finished(); - //sets position of widgets based on theme ini files - void set_widgets(); + // sets position of widgets based on theme ini files + void set_widgets(); - //sets font size based on theme ini files - void set_font(QWidget *widget, QString class_name, QString p_identifier); + // sets font size based on theme ini files + void set_font(QWidget *widget, QString class_name, QString p_identifier); - //Get the properly constructed font - QFont get_qfont(QString font_name, int f_pointsize, bool antialias = true); + // Get the properly constructed font + QFont get_qfont(QString font_name, int f_pointsize, bool antialias = true); - //actual operation of setting the font on a widget - void set_qfont(QWidget *widget, QString class_name, QFont font, QColor f_color = Qt::black, bool bold = false); + // actual operation of setting the font on a widget + void set_qfont(QWidget *widget, QString class_name, QFont font, + QColor f_color = Qt::black, bool bold = false); - //helper function that calls above function on the relevant widgets - void set_fonts(); + // helper function that calls above function on the relevant widgets + void set_fonts(); - //sets dropdown menu stylesheet - void set_dropdown(QWidget *widget); + // sets dropdown menu stylesheet + void set_dropdown(QWidget *widget); - //helper funciton that call above function on the relevant widgets - void set_dropdowns(); + // helper funciton that call above function on the relevant widgets + void set_dropdowns(); - void set_window_title(QString p_title); + void set_window_title(QString p_title); - //reads theme inis and sets size and pos based on the identifier - void set_size_and_pos(QWidget *p_widget, QString p_identifier); + // reads theme inis and sets size and pos based on the identifier + void set_size_and_pos(QWidget *p_widget, QString p_identifier); - //reads theme inis and returns the size and pos as defined by it - QPoint get_theme_pos(QString p_identifier); + // reads theme inis and returns the size and pos as defined by it + QPoint get_theme_pos(QString p_identifier); - //sets status as taken on character with cid n_char and places proper shading on charselect - void set_taken(int n_char, bool p_taken); + // sets status as taken on character with cid n_char and places proper shading + // on charselect + void set_taken(int n_char, bool p_taken); - //sets the current background to argument. also does some checks to see if it's a legacy bg - void set_background(QString p_background, bool display = false); + // sets the current background to argument. also does some checks to see if + // it's a legacy bg + void set_background(QString p_background, bool display = false); - //sets the local character pos/side to use. - void set_side(QString p_side); + // sets the local character pos/side to use. + void set_side(QString p_side); - //sets the pos dropdown - void set_pos_dropdown(QStringList pos_dropdowns); + // sets the pos dropdown + void set_pos_dropdown(QStringList pos_dropdowns); - //sets the evidence list member variable to argument - void set_evidence_list(QVector &p_evi_list); + // sets the evidence list member variable to argument + void set_evidence_list(QVector &p_evi_list); - //called when a DONE#% from the server was received - void done_received(); + // called when a DONE#% from the server was received + void done_received(); - //sets the local mute list based on characters available on the server - void set_mute_list(); + // 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 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(QString f_desk_mod, QString f_side); + // sets desk and bg based on pos in chatmessage + void set_scene(QString f_desk_mod, QString f_side); - //takes in serverD-formatted IP list as prints a converted version to server OOC - //admittedly poorly named - void set_ip_list(QString p_list); + // takes in serverD-formatted IP list as prints a converted version to server + // OOC admittedly poorly named + void set_ip_list(QString p_list); - //disables chat if current cid matches second argument - //enables if p_muted is false - void set_mute(bool p_muted, int p_cid); + // disables chat if current cid matches second argument + // enables if p_muted is false + void set_mute(bool p_muted, int p_cid); - //send a message that the player is banned and quits the server - void set_ban(int p_cid); + // send a message that the player is banned and quits the server + void set_ban(int p_cid); - //cid = character id, returns the cid of the currently selected character - int get_cid() { return m_cid; } - QString get_current_char() { return current_char; } - QString get_current_background() { return current_background; } + // cid = character id, returns the cid of the currently selected character + int get_cid() { return m_cid; } + QString get_current_char() { return current_char; } + QString get_current_background() { return current_background; } - //updates character to p_cid and updates necessary ui elements - void update_character(int p_cid); + // updates character to p_cid and updates necessary ui elements + void update_character(int p_cid); - //properly sets up some varibles: resets user state - void enter_courtroom(); + // properly sets up some varibles: resets user state + void enter_courtroom(); - //helper function that populates ui_music_list with the contents of music_list - void list_music(); - void list_areas(); + // helper function that populates ui_music_list with the contents of + // music_list + void list_music(); + void list_areas(); - //these are for OOC chat - void append_ms_chatmessage(QString f_name, QString f_message); - void append_server_chatmessage(QString p_name, QString p_message, QString p_color); + // these are for OOC chat + void append_ms_chatmessage(QString f_name, QString f_message); + void append_server_chatmessage(QString p_name, QString p_message, + QString p_color); - //these functions handle chatmessages sequentially. - //The process itself is very convoluted and merits separate documentation - //But the general idea is objection animation->pre animation->talking->idle - void handle_chatmessage(QStringList *p_contents); - void handle_chatmessage_2(); - void handle_chatmessage_3(); + // these functions handle chatmessages sequentially. + // The process itself is very convoluted and merits separate documentation + // But the general idea is objection animation->pre animation->talking->idle + void handle_chatmessage(QStringList *p_contents); + void handle_chatmessage_2(); + void handle_chatmessage_3(); - //This function filters out the common CC inline text trickery, for appending to - //the IC chatlog. - QString filter_ic_text(QString p_text, bool colorize = false, int pos = -1, int default_color = 0); + // This function filters out the common CC inline text trickery, for appending + // to the IC chatlog. + QString filter_ic_text(QString p_text, bool colorize = false, int pos = -1, + int default_color = 0); - //adds text to the IC chatlog. p_name first as bold then p_text then a newlin - //this function keeps the chatlog scrolled to the top unless there's text selected - // or the user isn't already scrolled to the top - void append_ic_text(QString p_text, QString p_name = "", QString action = ""); + // adds text to the IC chatlog. p_name first as bold then p_text then a newlin + // this function keeps the chatlog scrolled to the top unless there's text + // selected + // or the user isn't already scrolled to the top + void append_ic_text(QString p_text, QString p_name = "", QString action = ""); - //prints who played the song to IC chat and plays said song(if found on local filesystem) - //takes in a list where the first element is the song name and the second is the char id of who played it - void handle_song(QStringList *p_contents); + // prints who played the song to IC chat and plays said song(if found on local + // filesystem) takes in a list where the first element is the song name and the + // second is the char id of who played it + void handle_song(QStringList *p_contents); - void play_preanim(bool noninterrupting); + void play_preanim(bool noninterrupting); - //plays the witness testimony or cross examination animation based on argument - void handle_wtce(QString p_wtce, int variant); + // plays the witness testimony or cross examination animation based on + // argument + void handle_wtce(QString p_wtce, int variant); - //sets the hp bar of defense(p_bar 1) or pro(p_bar 2) - //state is an number between 0 and 10 inclusive - void set_hp_bar(int p_bar, int p_state); + // sets the hp bar of defense(p_bar 1) or pro(p_bar 2) + // state is an number between 0 and 10 inclusive + void set_hp_bar(int p_bar, int p_state); - //Toggles the judge buttons, whether they should appear or not. - void toggle_judge_buttons(bool is_on); + // Toggles the judge buttons, whether they should appear or not. + void toggle_judge_buttons(bool is_on); - void announce_case(QString title, bool def, bool pro, bool jud, bool jur, bool steno); + void announce_case(QString title, bool def, bool pro, bool jud, bool jur, + bool steno); - void check_connection_received(); + void check_connection_received(); - ~Courtroom(); + ~Courtroom(); private: - AOApplication *ao_app; + AOApplication *ao_app; - int m_courtroom_width = 714; - int m_courtroom_height = 668; + int m_courtroom_width = 714; + int m_courtroom_height = 668; - int m_viewport_x = 0; - int m_viewport_y = 0; + int m_viewport_x = 0; + int m_viewport_y = 0; - int m_viewport_width = 256; - int m_viewport_height = 192; + int m_viewport_width = 256; + int m_viewport_height = 192; - bool first_message_sent = false; - int maximumMessages = 0; + bool first_message_sent = false; + int maximumMessages = 0; - QParallelAnimationGroup *screenshake_animation_group = new QParallelAnimationGroup; + QParallelAnimationGroup *screenshake_animation_group = + new QParallelAnimationGroup; - bool next_character_is_not_special = false; // If true, write the - // next character as it is. + bool next_character_is_not_special = false; // If true, write the + // next character as it is. - bool message_is_centered = false; + bool message_is_centered = false; - int current_display_speed = 3; - int message_display_speed[7] = {0, 10, 25, 40, 50, 70, 90}; + int current_display_speed = 3; + int message_display_speed[7] = {0, 10, 25, 40, 50, 70, 90}; - // The character ID of the character this user wants to appear alongside with. - int other_charid = -1; + // The character ID of the character this user wants to appear alongside with. + int other_charid = -1; - // The offset this user has given if they want to appear alongside someone. - int char_offset = 0; + // The offset this user has given if they want to appear alongside someone. + int char_offset = 0; - // 0 = in front, 1 = behind - int pair_order = 0; + // 0 = in front, 1 = behind + int pair_order = 0; - QVector char_list; - QVector evidence_list; - QVector music_list; - QVector area_list; + QVector char_list; + QVector evidence_list; + QVector music_list; + QVector area_list; - QVector arup_players; - QVector arup_statuses; - QVector arup_cms; - QVector arup_locks; + QVector arup_players; + QVector arup_statuses; + QVector arup_cms; + QVector arup_locks; - QVector ic_chatlog_history; + QVector ic_chatlog_history; - //triggers ping_server() every 60 seconds - QTimer *keepalive_timer; + // triggers ping_server() every 60 seconds + QTimer *keepalive_timer; - //determines how fast messages tick onto screen - QTimer *chat_tick_timer; - //int chat_tick_interval = 60; - //which tick position(character in chat message) we are at - int tick_pos = 0; - //the actual document tick pos we gotta worry about for making the text scroll better - int real_tick_pos = 0; - //used to determine how often blips sound - int blip_ticker = 0; - int blip_rate = 1; - int rainbow_counter = 0; - bool rainbow_appended = false; - bool blank_blip = false; + // determines how fast messages tick onto screen + QTimer *chat_tick_timer; + // int chat_tick_interval = 60; + // which tick position(character in chat message) we are at + int tick_pos = 0; + // the actual document tick pos we gotta worry about for making the text + // scroll better + int real_tick_pos = 0; + // used to determine how often blips sound + int blip_ticker = 0; + int blip_rate = 1; + int rainbow_counter = 0; + bool rainbow_appended = false; + bool blank_blip = false; - //Whether or not is this message additive to the previous one - bool is_additive = false; + // Whether or not is this message additive to the previous one + bool is_additive = false; - // Used for getting the current maximum blocks allowed in the IC chatlog. - int log_maximum_blocks = 0; + // Used for getting the current maximum blocks allowed in the IC chatlog. + int log_maximum_blocks = 0; - // True, if the log should go downwards. - bool log_goes_downwards = false; + // True, if the log should go downwards. + bool log_goes_downwards = false; - //delay before chat messages starts ticking - QTimer *text_delay_timer; + // delay before chat messages starts ticking + QTimer *text_delay_timer; - //delay before sfx plays - QTimer *sfx_delay_timer; + // delay before sfx plays + QTimer *sfx_delay_timer; - //every time point in char.inis times this equals the final time - const int time_mod = 40; + // every time point in char.inis times this equals the final time + const int time_mod = 40; - //the amount of time non-animated objection/hold it/takethat images stay onscreen for in ms - const int shout_stay_time = 724; + // the amount of time non-animated objection/hold it/takethat images stay + // onscreen for in ms + const int shout_stay_time = 724; - //the amount of time non-animated guilty/not guilty images stay onscreen for in ms - const int verdict_stay_time = 3000; + // the amount of time non-animated guilty/not guilty images stay onscreen for + // in ms + const int verdict_stay_time = 3000; - //the amount of time non-animated witness testimony/cross-examination images stay onscreen for in ms - const int wtce_stay_time = 1500; + // the amount of time non-animated witness testimony/cross-examination images + // stay onscreen for in ms + const int wtce_stay_time = 1500; - //characters we consider punctuation - const QString punctuation_chars = ".,?!:;"; + // characters we consider punctuation + const QString punctuation_chars = ".,?!:;"; - //amount by which we multiply the delay when we parse punctuation chars - const int punctuation_modifier = 3; + // amount by which we multiply the delay when we parse punctuation chars + const int punctuation_modifier = 3; - static const int chatmessage_size = 30; - QString m_chatmessage[chatmessage_size]; - bool chatmessage_is_empty = false; + static const int chatmessage_size = 30; + QString m_chatmessage[chatmessage_size]; + bool chatmessage_is_empty = false; - QString previous_ic_message = ""; - QString additive_previous = ""; + QString previous_ic_message = ""; + QString additive_previous = ""; - //char id, muted or not - QMap mute_map; + // char id, muted or not + QMap mute_map; - //QVector muted_cids; + // QVector muted_cids; - bool is_muted = false; + bool is_muted = false; - //state of animation, 0 = objecting, 1 = preanim, 2 = talking, 3 = idle, 4 = noniterrupting preanim - int anim_state = 3; + // state of animation, 0 = objecting, 1 = preanim, 2 = talking, 3 = idle, 4 = + // noniterrupting preanim + int anim_state = 3; - //whether or not current color is a talking one - bool color_is_talking = true; + // whether or not current color is a talking one + bool color_is_talking = true; - //state of text ticking, 0 = not yet ticking, 1 = ticking in progress, 2 = ticking done - int text_state = 2; + // state of text ticking, 0 = not yet ticking, 1 = ticking in progress, 2 = + // ticking done + int text_state = 2; - //character id, which index of the char_list the player is - int m_cid = -1; - //cid and this may differ in cases of ini-editing - QString current_char = ""; + // character id, which index of the char_list the player is + int m_cid = -1; + // cid and this may differ in cases of ini-editing + QString current_char = ""; - int objection_state = 0; - int realization_state = 0; - int screenshake_state = 0; - int text_color = 0; + int objection_state = 0; + int realization_state = 0; + int screenshake_state = 0; + int text_color = 0; - //How many unique user colors are possible - static const int max_colors = 12; + // How many unique user colors are possible + static const int max_colors = 12; - //Text Color-related optimization: - //Current color list indexes to real color references - QVector color_row_to_number; + // Text Color-related optimization: + // Current color list indexes to real color references + QVector color_row_to_number; - //List of associated RGB colors for this color index - QVector color_rgb_list; + // List of associated RGB colors for this color index + QVector color_rgb_list; - //List of markdown start characters, their index is tied to the color index - QStringList color_markdown_start_list; + // List of markdown start characters, their index is tied to the color index + QStringList color_markdown_start_list; - //List of markdown end characters, their index is tied to the color index - QStringList color_markdown_end_list; + // List of markdown end characters, their index is tied to the color index + QStringList color_markdown_end_list; - //Whether or not we're supposed to remove this char during parsing - QVector color_markdown_remove_list; + // Whether or not we're supposed to remove this char during parsing + QVector color_markdown_remove_list; - //Whether or not this color allows us to play the talking animation - QVector color_markdown_talking_list; - //Text Color-related optimization END + // Whether or not this color allows us to play the talking animation + QVector color_markdown_talking_list; + // Text Color-related optimization END - //List of all currently available pos - QStringList pos_dropdown_list; + // List of all currently available pos + QStringList pos_dropdown_list; - bool is_presenting_evidence = false; + bool is_presenting_evidence = false; - QString effect = ""; + QString effect = ""; - //Music effect flags we want to send to server when we play music - int music_flags = 0; + // Music effect flags we want to send to server when we play music + int music_flags = 0; - int defense_bar_state = 0; - int prosecution_bar_state = 0; + int defense_bar_state = 0; + int prosecution_bar_state = 0; - int current_char_page = 0; - int char_columns = 10; - int char_rows = 9; - int max_chars_on_page = 90; + int current_char_page = 0; + int char_columns = 10; + int char_rows = 9; + int max_chars_on_page = 90; - const int button_width = 60; - const int button_height = 60; + const int button_width = 60; + const int button_height = 60; - int current_emote_page = 0; - int current_emote = 0; - int emote_columns = 5; - int emote_rows = 2; - int max_emotes_on_page = 10; + int current_emote_page = 0; + int current_emote = 0; + int emote_columns = 5; + int emote_rows = 2; + int max_emotes_on_page = 10; - QVector local_evidence_list; - QVector private_evidence_list; - QVector global_evidence_list; + QVector local_evidence_list; + QVector private_evidence_list; + QVector global_evidence_list; - //false = use private_evidence_list - bool current_evidence_global = true; + // false = use private_evidence_list + bool current_evidence_global = true; - int current_evidence_page = 0; - int current_evidence = 0; - int evidence_columns = 6; - int evidence_rows = 3; - int max_evidence_on_page = 18; + int current_evidence_page = 0; + int current_evidence = 0; + int evidence_columns = 6; + int evidence_rows = 3; + int max_evidence_on_page = 18; - //is set to true if the bg folder contains defensedesk.png, prosecutiondesk.png and stand.png - bool is_ao2_bg = false; + // is set to true if the bg folder contains defensedesk.png, + // prosecutiondesk.png and stand.png + bool is_ao2_bg = false; - //whether the ooc chat is server or master chat, true is server - bool server_ooc = true; + // whether the ooc chat is server or master chat, true is server + bool server_ooc = true; - QString current_background = "default"; - QString current_side = ""; + QString current_background = "default"; + QString current_side = ""; - AOMusicPlayer *music_player; - AOSfxPlayer *sfx_player; - AOSfxPlayer *objection_player; - AOBlipPlayer *blip_player; + AOMusicPlayer *music_player; + AOSfxPlayer *sfx_player; + AOSfxPlayer *objection_player; + AOBlipPlayer *blip_player; - AOSfxPlayer *modcall_player; + AOSfxPlayer *modcall_player; - AOImage *ui_background; + AOImage *ui_background; - QWidget *ui_viewport; - AOScene *ui_vp_background; - AOMovie *ui_vp_speedlines; - AOCharMovie *ui_vp_player_char; - AOCharMovie *ui_vp_sideplayer_char; - AOScene *ui_vp_desk; - AOScene *ui_vp_legacy_desk; - AOEvidenceDisplay *ui_vp_evidence_display; - AOImage *ui_vp_chatbox; - QLabel *ui_vp_showname; - AOMovie *ui_vp_chat_arrow; - QTextEdit *ui_vp_message; - AOMovie *ui_vp_effect; - AOMovie *ui_vp_testimony; - AOMovie *ui_vp_wtce; - AOMovie *ui_vp_objection; + QWidget *ui_viewport; + AOScene *ui_vp_background; + AOMovie *ui_vp_speedlines; + AOCharMovie *ui_vp_player_char; + AOCharMovie *ui_vp_sideplayer_char; + AOScene *ui_vp_desk; + AOScene *ui_vp_legacy_desk; + AOEvidenceDisplay *ui_vp_evidence_display; + AOImage *ui_vp_chatbox; + QLabel *ui_vp_showname; + AOMovie *ui_vp_chat_arrow; + QTextEdit *ui_vp_message; + AOMovie *ui_vp_effect; + AOMovie *ui_vp_testimony; + AOMovie *ui_vp_wtce; + AOMovie *ui_vp_objection; - QTextEdit *ui_ic_chatlog; + QTextEdit *ui_ic_chatlog; - AOTextArea *ui_ms_chatlog; - AOTextArea *ui_server_chatlog; + AOTextArea *ui_ms_chatlog; + AOTextArea *ui_server_chatlog; - QListWidget *ui_mute_list; - QTreeWidget *ui_area_list; - QTreeWidget *ui_music_list; + QListWidget *ui_mute_list; + QTreeWidget *ui_area_list; + QTreeWidget *ui_music_list; - ScrollText *ui_music_name; - AOMovie *ui_music_display; + ScrollText *ui_music_name; + AOMovie *ui_music_display; - AOButton *ui_pair_button; - QListWidget *ui_pair_list; - QSpinBox *ui_pair_offset_spinbox; + AOButton *ui_pair_button; + QListWidget *ui_pair_list; + QSpinBox *ui_pair_offset_spinbox; - QComboBox *ui_pair_order_dropdown; + QComboBox *ui_pair_order_dropdown; - AOLineEdit *ui_ic_chat_message; - QLineEdit *ui_ic_chat_name; + AOLineEdit *ui_ic_chat_message; + QLineEdit *ui_ic_chat_name; - QLineEdit *ui_ooc_chat_message; - QLineEdit *ui_ooc_chat_name; + QLineEdit *ui_ooc_chat_message; + QLineEdit *ui_ooc_chat_name; - //QLineEdit *ui_area_password; - QLineEdit *ui_music_search; + // QLineEdit *ui_area_password; + QLineEdit *ui_music_search; - QWidget *ui_emotes; - QVector ui_emote_list; - AOButton *ui_emote_left; - AOButton *ui_emote_right; + QWidget *ui_emotes; + QVector ui_emote_list; + AOButton *ui_emote_left; + AOButton *ui_emote_right; - QComboBox *ui_emote_dropdown; - QComboBox *ui_pos_dropdown; + QComboBox *ui_emote_dropdown; + QComboBox *ui_pos_dropdown; - QComboBox *ui_iniswap_dropdown; - AOButton *ui_iniswap_remove; + QComboBox *ui_iniswap_dropdown; + AOButton *ui_iniswap_remove; - QComboBox *ui_sfx_dropdown; - AOButton *ui_sfx_remove; + QComboBox *ui_sfx_dropdown; + AOButton *ui_sfx_remove; - QComboBox *ui_effects_dropdown; + QComboBox *ui_effects_dropdown; + + AOImage *ui_defense_bar; + AOImage *ui_prosecution_bar; + + QLabel *ui_music_label; + QLabel *ui_sfx_label; + QLabel *ui_blip_label; - AOImage *ui_defense_bar; - AOImage *ui_prosecution_bar; + AOButton *ui_hold_it; + AOButton *ui_objection; + AOButton *ui_take_that; + + AOButton *ui_ooc_toggle; + + AOButton *ui_witness_testimony; + AOButton *ui_cross_examination; + AOButton *ui_guilty; + AOButton *ui_not_guilty; + + AOButton *ui_change_character; + AOButton *ui_reload_theme; + AOButton *ui_call_mod; + AOButton *ui_settings; + AOButton *ui_announce_casing; + AOButton *ui_switch_area_music; - QLabel *ui_music_label; - QLabel *ui_sfx_label; - QLabel *ui_blip_label; + QCheckBox *ui_pre; + QCheckBox *ui_flip; + QCheckBox *ui_additive; + QCheckBox *ui_guard; + QCheckBox *ui_casing; + + QCheckBox *ui_pre_non_interrupt; + QCheckBox *ui_showname_enable; + + AOButton *ui_custom_objection; + AOButton *ui_realization; + AOButton *ui_screenshake; + AOButton *ui_mute; + + AOButton *ui_defense_plus; + AOButton *ui_defense_minus; + + AOButton *ui_prosecution_plus; + AOButton *ui_prosecution_minus; + + QComboBox *ui_text_color; + + QSlider *ui_music_slider; + QSlider *ui_sfx_slider; + QSlider *ui_blip_slider; - AOButton *ui_hold_it; - AOButton *ui_objection; - AOButton *ui_take_that; - - AOButton *ui_ooc_toggle; + AOImage *ui_muted; - AOButton *ui_witness_testimony; - AOButton *ui_cross_examination; - AOButton *ui_guilty; - AOButton *ui_not_guilty; - - AOButton *ui_change_character; - AOButton *ui_reload_theme; - AOButton *ui_call_mod; - AOButton *ui_settings; - AOButton *ui_announce_casing; - AOButton *ui_switch_area_music; + AOButton *ui_evidence_button; + AOImage *ui_evidence; + AOLineEdit *ui_evidence_name; + QWidget *ui_evidence_buttons; + QVector ui_evidence_list; + AOButton *ui_evidence_left; + AOButton *ui_evidence_right; + AOButton *ui_evidence_present; + AOImage *ui_evidence_overlay; + AOButton *ui_evidence_delete; + AOLineEdit *ui_evidence_image_name; + AOButton *ui_evidence_image_button; + AOButton *ui_evidence_x; + AOButton *ui_evidence_ok; + AOButton *ui_evidence_switch; + AOButton *ui_evidence_transfer; + AOButton *ui_evidence_save; + AOButton *ui_evidence_load; + AOTextEdit *ui_evidence_description; - QCheckBox *ui_pre; - QCheckBox *ui_flip; - QCheckBox *ui_additive; - QCheckBox *ui_guard; - QCheckBox *ui_casing; - - QCheckBox *ui_pre_non_interrupt; - QCheckBox *ui_showname_enable; - - AOButton *ui_custom_objection; - AOButton *ui_realization; - AOButton *ui_screenshake; - AOButton *ui_mute; - - AOButton *ui_defense_plus; - AOButton *ui_defense_minus; - - AOButton *ui_prosecution_plus; - AOButton *ui_prosecution_minus; - - QComboBox *ui_text_color; - - QSlider *ui_music_slider; - QSlider *ui_sfx_slider; - QSlider *ui_blip_slider; + AOImage *ui_char_select_background; - AOImage *ui_muted; + // abstract widget to hold char buttons + QWidget *ui_char_buttons; - AOButton *ui_evidence_button; - AOImage *ui_evidence; - AOLineEdit *ui_evidence_name; - QWidget *ui_evidence_buttons; - QVector ui_evidence_list; - AOButton *ui_evidence_left; - AOButton *ui_evidence_right; - AOButton *ui_evidence_present; - AOImage *ui_evidence_overlay; - AOButton *ui_evidence_delete; - AOLineEdit *ui_evidence_image_name; - AOButton *ui_evidence_image_button; - AOButton *ui_evidence_x; - AOButton *ui_evidence_ok; - AOButton *ui_evidence_switch; - AOButton *ui_evidence_transfer; - AOButton *ui_evidence_save; - AOButton *ui_evidence_load; - AOTextEdit *ui_evidence_description; + QVector ui_char_button_list; + QVector ui_char_button_list_filtered; + AOImage *ui_selector; + + AOButton *ui_back_to_lobby; - AOImage *ui_char_select_background; + QLineEdit *ui_char_password; + + AOButton *ui_char_select_left; + AOButton *ui_char_select_right; - //abstract widget to hold char buttons - QWidget *ui_char_buttons; - - QVector ui_char_button_list; - QVector ui_char_button_list_filtered; - AOImage *ui_selector; - - AOButton *ui_back_to_lobby; - - QLineEdit *ui_char_password; - - AOButton *ui_char_select_left; - AOButton *ui_char_select_right; - - AOButton *ui_spectator; - - QLineEdit *ui_char_search; - QCheckBox *ui_char_passworded; - QCheckBox *ui_char_taken; - - void construct_char_select(); - void set_char_select(); - void set_char_select_page(); - void char_clicked(int n_char); - void put_button_in_place(int starting, int chars_on_this_page); - void filter_character_list(); - - void initialize_emotes(); - void refresh_emotes(); - void set_emote_page(); - void set_emote_dropdown(); - - void initialize_evidence(); - void refresh_evidence(); - void set_evidence_page(); + AOButton *ui_spectator; + + QLineEdit *ui_char_search; + QCheckBox *ui_char_passworded; + QCheckBox *ui_char_taken; + + void construct_char_select(); + void set_char_select(); + void set_char_select_page(); + void char_clicked(int n_char); + void put_button_in_place(int starting, int chars_on_this_page); + void filter_character_list(); + + void initialize_emotes(); + void refresh_emotes(); + void set_emote_page(); + void set_emote_dropdown(); + + void initialize_evidence(); + void refresh_evidence(); + void set_evidence_page(); public slots: - void objection_done(); - void preanim_done(); - void do_screenshake(); - void do_flash(); - void do_effect(QString fx_path, QString fx_sound, QString p_char, QString p_folder); - void play_char_sfx(QString sfx_name); + void objection_done(); + void preanim_done(); + void do_screenshake(); + void do_flash(); + void do_effect(QString fx_path, QString fx_sound, QString p_char, + QString p_folder); + void play_char_sfx(QString sfx_name); - void mod_called(QString p_ip); + void mod_called(QString p_ip); - void case_called(QString msg, bool def, bool pro, bool jud, bool jur, bool steno); + void case_called(QString msg, bool def, bool pro, bool jud, bool jur, + bool steno); private slots: - void start_chat_ticking(); - void play_sfx(); + void start_chat_ticking(); + void play_sfx(); - void chat_tick(); + void chat_tick(); - void on_mute_list_clicked(QModelIndex p_index); - void on_pair_list_clicked(QModelIndex p_index); + void on_mute_list_clicked(QModelIndex p_index); + void on_pair_list_clicked(QModelIndex p_index); - void on_chat_return_pressed(); + void on_chat_return_pressed(); - void on_ooc_return_pressed(); + void on_ooc_return_pressed(); - void on_music_search_edited(QString p_text); - void on_music_list_double_clicked(QTreeWidgetItem *p_item, int column); - void on_music_list_context_menu_requested(const QPoint &pos); - void music_fade_out(bool toggle); - void music_fade_in(bool toggle); - void music_synchronize(bool toggle); - void music_list_expand_all(); - void music_list_collapse_all(); - void on_area_list_double_clicked(QTreeWidgetItem *p_item, int column); + void on_music_search_edited(QString p_text); + void on_music_list_double_clicked(QTreeWidgetItem *p_item, int column); + void on_music_list_context_menu_requested(const QPoint &pos); + void music_fade_out(bool toggle); + void music_fade_in(bool toggle); + void music_synchronize(bool toggle); + void music_list_expand_all(); + void music_list_collapse_all(); + void on_area_list_double_clicked(QTreeWidgetItem *p_item, int column); - void select_emote(int p_id); + void select_emote(int p_id); - void on_emote_clicked(int p_id); + void on_emote_clicked(int p_id); - void on_emote_left_clicked(); - void on_emote_right_clicked(); + void on_emote_left_clicked(); + void on_emote_right_clicked(); - void on_emote_dropdown_changed(int p_index); - void on_pos_dropdown_changed(int p_index); + void on_emote_dropdown_changed(int p_index); + void on_pos_dropdown_changed(int p_index); - void on_iniswap_dropdown_changed(int p_index); - void set_iniswap_dropdown(); - void on_iniswap_context_menu_requested(const QPoint &pos); - void on_iniswap_edit_requested(); - void on_iniswap_remove_clicked(); + void on_iniswap_dropdown_changed(int p_index); + void set_iniswap_dropdown(); + void on_iniswap_context_menu_requested(const QPoint &pos); + void on_iniswap_edit_requested(); + void on_iniswap_remove_clicked(); - void on_sfx_dropdown_changed(int p_index); - void set_sfx_dropdown(); - void on_sfx_context_menu_requested(const QPoint &pos); - void on_sfx_edit_requested(); - void on_sfx_remove_clicked(); + void on_sfx_dropdown_changed(int p_index); + void set_sfx_dropdown(); + void on_sfx_context_menu_requested(const QPoint &pos); + void on_sfx_edit_requested(); + void on_sfx_remove_clicked(); - void set_effects_dropdown(); - void on_effects_context_menu_requested(const QPoint &pos); - void on_effects_edit_requested(); - void on_character_effects_edit_requested(); - void on_effects_dropdown_changed(int p_index); - bool effects_dropdown_find_and_set(QString effect); + void set_effects_dropdown(); + void on_effects_context_menu_requested(const QPoint &pos); + void on_effects_edit_requested(); + void on_character_effects_edit_requested(); + void on_effects_dropdown_changed(int p_index); + bool effects_dropdown_find_and_set(QString effect); - QString get_char_sfx(); - int get_char_sfx_delay(); + QString get_char_sfx(); + int get_char_sfx_delay(); - void on_evidence_name_edited(); - void on_evidence_image_name_edited(); - void on_evidence_image_button_clicked(); - void on_evidence_clicked(int p_id); - void on_evidence_double_clicked(int p_id); + void on_evidence_name_edited(); + void on_evidence_image_name_edited(); + void on_evidence_image_button_clicked(); + void on_evidence_clicked(int p_id); + void on_evidence_double_clicked(int p_id); - void on_evidence_hover(int p_id, bool p_state); + void on_evidence_hover(int p_id, bool p_state); - void on_evidence_left_clicked(); - void on_evidence_right_clicked(); - void on_evidence_present_clicked(); + void on_evidence_left_clicked(); + void on_evidence_right_clicked(); + void on_evidence_present_clicked(); - void on_hold_it_clicked(); - void on_objection_clicked(); - void on_take_that_clicked(); - void on_custom_objection_clicked(); + void on_hold_it_clicked(); + void on_objection_clicked(); + void on_take_that_clicked(); + void on_custom_objection_clicked(); - void on_realization_clicked(); - void on_screenshake_clicked(); + void on_realization_clicked(); + void on_screenshake_clicked(); - void on_mute_clicked(); - void on_pair_clicked(); - void on_pair_order_dropdown_changed(int p_index); + 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(); - void on_prosecution_minus_clicked(); - void on_prosecution_plus_clicked(); + void on_defense_minus_clicked(); + void on_defense_plus_clicked(); + void on_prosecution_minus_clicked(); + void on_prosecution_plus_clicked(); - void on_text_color_changed(int p_color); - void set_text_color_dropdown(); + void on_text_color_changed(int p_color); + void set_text_color_dropdown(); - void on_music_slider_moved(int p_value); - void on_sfx_slider_moved(int p_value); - void on_blip_slider_moved(int p_value); + void on_music_slider_moved(int p_value); + void on_sfx_slider_moved(int p_value); + void on_blip_slider_moved(int p_value); - void on_log_limit_changed(int value); - void on_pair_offset_changed(int value); + void on_log_limit_changed(int value); + void on_pair_offset_changed(int value); - void on_ooc_toggle_clicked(); + void on_ooc_toggle_clicked(); - void on_witness_testimony_clicked(); - void on_cross_examination_clicked(); - void on_not_guilty_clicked(); - void on_guilty_clicked(); + void on_witness_testimony_clicked(); + void on_cross_examination_clicked(); + void on_not_guilty_clicked(); + void on_guilty_clicked(); - void on_change_character_clicked(); - void on_reload_theme_clicked(); - void on_call_mod_clicked(); - void on_settings_clicked(); - void on_announce_casing_clicked(); + void on_change_character_clicked(); + void on_reload_theme_clicked(); + void on_call_mod_clicked(); + void on_settings_clicked(); + void on_announce_casing_clicked(); - void on_pre_clicked(); - void on_flip_clicked(); - void on_additive_clicked(); - void on_guard_clicked(); + void on_pre_clicked(); + void on_flip_clicked(); + void on_additive_clicked(); + void on_guard_clicked(); - void on_showname_enable_clicked(); + void on_showname_enable_clicked(); - void on_evidence_name_double_clicked(); - void on_evidence_image_name_double_clicked(); - void on_evidence_button_clicked(); + void on_evidence_name_double_clicked(); + void on_evidence_image_name_double_clicked(); + void on_evidence_button_clicked(); - void on_evidence_delete_clicked(); - void on_evidence_x_clicked(); - void on_evidence_ok_clicked(); - void on_evidence_switch_clicked(); - void on_evidence_transfer_clicked(); + void on_evidence_delete_clicked(); + void on_evidence_x_clicked(); + void on_evidence_ok_clicked(); + void on_evidence_switch_clicked(); + void on_evidence_transfer_clicked(); - void on_evidence_edited(); + void on_evidence_edited(); - void evidence_close(); - void evidence_switch(bool global); - void on_evidence_save_clicked(); - void on_evidence_load_clicked(); - bool compare_evidence_changed(evi_type evi_a, evi_type evi_b); + void evidence_close(); + void evidence_switch(bool global); + void on_evidence_save_clicked(); + void on_evidence_load_clicked(); + bool compare_evidence_changed(evi_type evi_a, evi_type evi_b); - void on_back_to_lobby_clicked(); + void on_back_to_lobby_clicked(); - void on_char_select_left_clicked(); - void on_char_select_right_clicked(); - void on_char_search_changed(); - void on_char_taken_clicked(); - void on_char_passworded_clicked(); + void on_char_select_left_clicked(); + void on_char_select_right_clicked(); + void on_char_search_changed(); + void on_char_taken_clicked(); + void on_char_passworded_clicked(); - void on_spectator_clicked(); + void on_spectator_clicked(); - void on_switch_area_music_clicked(); + void on_switch_area_music_clicked(); - void on_casing_clicked(); + void on_casing_clicked(); - void ping_server(); + void ping_server(); - void load_bass_opus_plugin(); + void load_bass_opus_plugin(); }; #endif // COURTROOM_H diff --git a/include/datatypes.h b/include/datatypes.h index 715bb3e..21ade04 100644 --- a/include/datatypes.h +++ b/include/datatypes.h @@ -4,107 +4,103 @@ #include struct server_type { - QString name; - QString desc; - QString ip; - int port; + QString name; + QString desc; + QString ip; + int port; }; struct emote_type { - QString comment; - QString preanim; - QString anim; - int mod; - QString sfx_name; - int sfx_delay; - int sfx_duration; + QString comment; + QString preanim; + QString anim; + int mod; + QString sfx_name; + int sfx_delay; + int sfx_duration; }; struct char_type { - QString name; - QString description; - QString evidence_string; - bool taken; + QString name; + QString description; + QString evidence_string; + bool taken; }; struct evi_type { - QString name; - QString description; - QString image; + QString name; + QString description; + QString image; }; struct chatmessage_type { - QString message; - QString character; - QString side; - QString sfx_name; - QString pre_emote; - QString emote; - int emote_modifier; - int objection_modifier; - int realization; - int text_color; - int evidence; - int cid; - int sfx_delay; - int flip; + QString message; + QString character; + QString side; + QString sfx_name; + QString pre_emote; + QString emote; + int emote_modifier; + int objection_modifier; + int realization; + int text_color; + int evidence; + int cid; + int sfx_delay; + int flip; }; struct area_type { - QString name; - QString background; - bool passworded; + QString name; + QString background; + bool passworded; }; struct pos_type { - int x; - int y; + int x; + int y; }; struct pos_size_type { - int x = 0; - int y = 0; - int width = 0; - int height = 0; + int x = 0; + int y = 0; + int width = 0; + int height = 0; }; enum CHAT_MESSAGE { - DESK_MOD = 0, - PRE_EMOTE, - CHAR_NAME, - EMOTE, - MESSAGE, - SIDE, - SFX_NAME, - EMOTE_MOD, - CHAR_ID, - SFX_DELAY, - OBJECTION_MOD, - EVIDENCE_ID, - FLIP, - REALIZATION, - TEXT_COLOR, - SHOWNAME, - OTHER_CHARID, - OTHER_NAME, - OTHER_EMOTE, - SELF_OFFSET, - OTHER_OFFSET, - OTHER_FLIP, - NONINTERRUPTING_PRE, - LOOPING_SFX, - SCREENSHAKE, - FRAME_SCREENSHAKE, - FRAME_REALIZATION, - FRAME_SFX, - ADDITIVE, - EFFECTS + DESK_MOD = 0, + PRE_EMOTE, + CHAR_NAME, + EMOTE, + MESSAGE, + SIDE, + SFX_NAME, + EMOTE_MOD, + CHAR_ID, + SFX_DELAY, + OBJECTION_MOD, + EVIDENCE_ID, + FLIP, + REALIZATION, + TEXT_COLOR, + SHOWNAME, + OTHER_CHARID, + OTHER_NAME, + OTHER_EMOTE, + SELF_OFFSET, + OTHER_OFFSET, + OTHER_FLIP, + NONINTERRUPTING_PRE, + LOOPING_SFX, + SCREENSHAKE, + FRAME_SCREENSHAKE, + FRAME_REALIZATION, + FRAME_SFX, + ADDITIVE, + EFFECTS }; -enum MUSIC_EFFECT { - FADE_IN = 1, - FADE_OUT = 2, - SYNC_POS = 4 -}; +enum MUSIC_EFFECT { FADE_IN = 1, FADE_OUT = 2, SYNC_POS = 4 }; #endif // DATATYPES_H diff --git a/include/discord-rpc.h b/include/discord-rpc.h index 2488543..455f62a 100644 --- a/include/discord-rpc.h +++ b/include/discord-rpc.h @@ -24,37 +24,37 @@ extern "C" { #endif typedef struct DiscordRichPresence { - const char *state; /* max 128 bytes */ - const char *details; /* max 128 bytes */ - int64_t startTimestamp; - int64_t endTimestamp; - const char *largeImageKey; /* max 32 bytes */ - const char *largeImageText; /* max 128 bytes */ - const char *smallImageKey; /* max 32 bytes */ - const char *smallImageText; /* max 128 bytes */ - const char *partyId; /* max 128 bytes */ - int partySize; - int partyMax; - const char *matchSecret; /* max 128 bytes */ - const char *joinSecret; /* max 128 bytes */ - const char *spectateSecret; /* max 128 bytes */ - int8_t instance; + const char *state; /* max 128 bytes */ + const char *details; /* max 128 bytes */ + int64_t startTimestamp; + int64_t endTimestamp; + const char *largeImageKey; /* max 32 bytes */ + const char *largeImageText; /* max 128 bytes */ + const char *smallImageKey; /* max 32 bytes */ + const char *smallImageText; /* max 128 bytes */ + const char *partyId; /* max 128 bytes */ + int partySize; + int partyMax; + const char *matchSecret; /* max 128 bytes */ + const char *joinSecret; /* max 128 bytes */ + const char *spectateSecret; /* max 128 bytes */ + int8_t instance; } DiscordRichPresence; typedef struct DiscordJoinRequest { - const char *userId; - const char *username; - const char *discriminator; - const char *avatar; + const char *userId; + const char *username; + const char *discriminator; + const char *avatar; } DiscordJoinRequest; typedef struct DiscordEventHandlers { - void (*ready)(void); - void (*disconnected)(int errorCode, const char *message); - void (*errored)(int errorCode, const char *message); - void (*joinGame)(const char *joinSecret); - void (*spectateGame)(const char *spectateSecret); - void (*joinRequest)(const DiscordJoinRequest *request); + void (*ready)(void); + void (*disconnected)(int errorCode, const char *message); + void (*errored)(int errorCode, const char *message); + void (*joinGame)(const char *joinSecret); + void (*spectateGame)(const char *spectateSecret); + void (*joinRequest)(const DiscordJoinRequest *request); } DiscordEventHandlers; #define DISCORD_REPLY_NO 0 @@ -70,7 +70,8 @@ DISCORD_EXPORT void Discord_Shutdown(void); /* checks for incoming messages, dispatches callbacks */ DISCORD_EXPORT void Discord_RunCallbacks(void); -/* If you disable the lib starting its own io thread, you'll need to call this from your own */ +/* If you disable the lib starting its own io thread, you'll need to call this + * from your own */ #ifdef DISCORD_DISABLE_IO_THREAD DISCORD_EXPORT void Discord_UpdateConnection(void); #endif @@ -78,7 +79,8 @@ DISCORD_EXPORT void Discord_UpdateConnection(void); DISCORD_EXPORT void Discord_UpdatePresence(const DiscordRichPresence *presence); DISCORD_EXPORT void Discord_ClearPresence(void); -DISCORD_EXPORT void Discord_Respond(const char *userid, /* DISCORD_REPLY_ */ int reply); +DISCORD_EXPORT void Discord_Respond(const char *userid, + /* DISCORD_REPLY_ */ int reply); #ifdef __cplusplus } /* extern "C" */ diff --git a/include/discord_register.h b/include/discord_register.h index 71e856a..655a3df 100644 --- a/include/discord_register.h +++ b/include/discord_register.h @@ -18,8 +18,10 @@ extern "C" { #endif -DISCORD_EXPORT void Discord_Register(const char *applicationId, const char *command); -DISCORD_EXPORT void Discord_RegisterSteamGame(const char *applicationId, const char *steamId); +DISCORD_EXPORT void Discord_Register(const char *applicationId, + const char *command); +DISCORD_EXPORT void Discord_RegisterSteamGame(const char *applicationId, + const char *steamId); #ifdef __cplusplus } diff --git a/include/discord_rich_presence.h b/include/discord_rich_presence.h index 1949d24..71c85e2 100644 --- a/include/discord_rich_presence.h +++ b/include/discord_rich_presence.h @@ -16,23 +16,23 @@ namespace AttorneyOnline { - class Discord { - Q_DECLARE_TR_FUNCTIONS(Discord) +class Discord { + Q_DECLARE_TR_FUNCTIONS(Discord) - private: - const char *APPLICATION_ID = "399779271737868288"; - std::string server_name, server_id; - int64_t timestamp; +private: + const char *APPLICATION_ID = "399779271737868288"; + std::string server_name, server_id; + int64_t timestamp; - public: - Discord(); - ~Discord(); +public: + Discord(); + ~Discord(); - void state_lobby(); - void state_server(std::string name, std::string server_id); - void state_character(std::string name); - void state_spectate(); - }; + void state_lobby(); + void state_server(std::string name, std::string server_id); + void state_character(std::string name); + void state_spectate(); +}; } // namespace AttorneyOnline #endif // DISCORD_RICH_PRESENCE_H diff --git a/include/discord_rpc.h b/include/discord_rpc.h index 737f2f6..6bd4404 100644 --- a/include/discord_rpc.h +++ b/include/discord_rpc.h @@ -24,37 +24,37 @@ extern "C" { #endif typedef struct DiscordRichPresence { - const char *state; /* max 128 bytes */ - const char *details; /* max 128 bytes */ - int64_t startTimestamp; - int64_t endTimestamp; - const char *largeImageKey; /* max 32 bytes */ - const char *largeImageText; /* max 128 bytes */ - const char *smallImageKey; /* max 32 bytes */ - const char *smallImageText; /* max 128 bytes */ - const char *partyId; /* max 128 bytes */ - int partySize; - int partyMax; - const char *matchSecret; /* max 128 bytes */ - const char *joinSecret; /* max 128 bytes */ - const char *spectateSecret; /* max 128 bytes */ - int8_t instance; + const char *state; /* max 128 bytes */ + const char *details; /* max 128 bytes */ + int64_t startTimestamp; + int64_t endTimestamp; + const char *largeImageKey; /* max 32 bytes */ + const char *largeImageText; /* max 128 bytes */ + const char *smallImageKey; /* max 32 bytes */ + const char *smallImageText; /* max 128 bytes */ + const char *partyId; /* max 128 bytes */ + int partySize; + int partyMax; + const char *matchSecret; /* max 128 bytes */ + const char *joinSecret; /* max 128 bytes */ + const char *spectateSecret; /* max 128 bytes */ + int8_t instance; } DiscordRichPresence; typedef struct DiscordUser { - const char *userId; - const char *username; - const char *discriminator; - const char *avatar; + const char *userId; + const char *username; + const char *discriminator; + const char *avatar; } DiscordUser; typedef struct DiscordEventHandlers { - void (*ready)(const DiscordUser *request); - void (*disconnected)(int errorCode, const char *message); - void (*errored)(int errorCode, const char *message); - void (*joinGame)(const char *joinSecret); - void (*spectateGame)(const char *spectateSecret); - void (*joinRequest)(const DiscordUser *request); + void (*ready)(const DiscordUser *request); + void (*disconnected)(int errorCode, const char *message); + void (*errored)(int errorCode, const char *message); + void (*joinGame)(const char *joinSecret); + void (*spectateGame)(const char *spectateSecret); + void (*joinRequest)(const DiscordUser *request); } DiscordEventHandlers; #define DISCORD_REPLY_NO 0 @@ -70,7 +70,8 @@ DISCORD_EXPORT void Discord_Shutdown(void); /* checks for incoming messages, dispatches callbacks */ DISCORD_EXPORT void Discord_RunCallbacks(void); -/* If you disable the lib starting its own io thread, you'll need to call this from your own */ +/* If you disable the lib starting its own io thread, you'll need to call this + * from your own */ #ifdef DISCORD_DISABLE_IO_THREAD DISCORD_EXPORT void Discord_UpdateConnection(void); #endif @@ -78,7 +79,8 @@ DISCORD_EXPORT void Discord_UpdateConnection(void); DISCORD_EXPORT void Discord_UpdatePresence(const DiscordRichPresence *presence); DISCORD_EXPORT void Discord_ClearPresence(void); -DISCORD_EXPORT void Discord_Respond(const char *userid, /* DISCORD_REPLY_ */ int reply); +DISCORD_EXPORT void Discord_Respond(const char *userid, + /* DISCORD_REPLY_ */ int reply); DISCORD_EXPORT void Discord_UpdateHandlers(DiscordEventHandlers *handlers); diff --git a/include/hex_functions.h b/include/hex_functions.h index 429bdb1..d178ba1 100644 --- a/include/hex_functions.h +++ b/include/hex_functions.h @@ -10,7 +10,7 @@ #include namespace omni { - std::string int_to_hex(unsigned int input); +std::string int_to_hex(unsigned int input); } -#endif //HEX_OPERATIONS_H +#endif // HEX_OPERATIONS_H diff --git a/include/lobby.h b/include/lobby.h index 7b978d3..42f5297 100644 --- a/include/lobby.h +++ b/include/lobby.h @@ -21,87 +21,87 @@ class AOApplication; class Lobby : public QMainWindow { - Q_OBJECT + Q_OBJECT public: - Lobby(AOApplication *p_ao_app); + Lobby(AOApplication *p_ao_app); - void set_widgets(); - void list_servers(); - void list_favorites(); - void append_chatmessage(QString f_name, QString f_message); - void append_error(QString f_message); - void set_player_count(int players_online, int max_players); - void set_stylesheet(QWidget *widget, QString target_tag); - void set_stylesheets(); - void set_fonts(); - void set_font(QWidget *widget, QString p_identifier); - void set_loading_text(QString p_text); - void show_loading_overlay() { ui_loading_background->show(); } - void hide_loading_overlay() { ui_loading_background->hide(); } - QString get_chatlog(); - int get_selected_server(); - void enable_connect_button(); + void set_widgets(); + void list_servers(); + void list_favorites(); + void append_chatmessage(QString f_name, QString f_message); + void append_error(QString f_message); + void set_player_count(int players_online, int max_players); + void set_stylesheet(QWidget *widget, QString target_tag); + void set_stylesheets(); + void set_fonts(); + void set_font(QWidget *widget, QString p_identifier); + void set_loading_text(QString p_text); + void show_loading_overlay() { ui_loading_background->show(); } + void hide_loading_overlay() { ui_loading_background->hide(); } + QString get_chatlog(); + int get_selected_server(); + void enable_connect_button(); - void set_loading_value(int p_value); + void set_loading_value(int p_value); - bool public_servers_selected = true; + bool public_servers_selected = true; - ~Lobby(); + ~Lobby(); private: - AOApplication *ao_app; + AOApplication *ao_app; - AOImage *ui_background; + AOImage *ui_background; - AOButton *ui_public_servers; - AOButton *ui_favorites; + AOButton *ui_public_servers; + AOButton *ui_favorites; - AOButton *ui_refresh; - AOButton *ui_add_to_fav; - AOButton *ui_connect; + AOButton *ui_refresh; + AOButton *ui_add_to_fav; + AOButton *ui_connect; - QLabel *ui_version; - AOButton *ui_about; + QLabel *ui_version; + AOButton *ui_about; - AOButton *ui_settings; + AOButton *ui_settings; - QTreeWidget *ui_server_list; - QLineEdit *ui_server_search; + QTreeWidget *ui_server_list; + QLineEdit *ui_server_search; - QLabel *ui_player_count; - AOTextArea *ui_description; + QLabel *ui_player_count; + AOTextArea *ui_description; - AOTextArea *ui_chatbox; + AOTextArea *ui_chatbox; - QLineEdit *ui_chatname; - QLineEdit *ui_chatmessage; + QLineEdit *ui_chatname; + QLineEdit *ui_chatmessage; - AOImage *ui_loading_background; - QTextEdit *ui_loading_text; - QProgressBar *ui_progress_bar; - AOButton *ui_cancel; + AOImage *ui_loading_background; + QTextEdit *ui_loading_text; + QProgressBar *ui_progress_bar; + AOButton *ui_cancel; - int last_index; + int last_index; - void set_size_and_pos(QWidget *p_widget, QString p_identifier); + void set_size_and_pos(QWidget *p_widget, QString p_identifier); private slots: - void on_public_servers_clicked(); - void on_favorites_clicked(); + void on_public_servers_clicked(); + void on_favorites_clicked(); - void on_refresh_pressed(); - void on_refresh_released(); - void on_add_to_fav_pressed(); - void on_add_to_fav_released(); - void on_connect_pressed(); - void on_connect_released(); - void on_about_clicked(); - void on_settings_clicked(); - void on_server_list_clicked(QTreeWidgetItem *p_item, int column); - void on_server_list_doubleclicked(QTreeWidgetItem *p_item, int column); - void on_server_search_edited(QString p_text); - void on_chatfield_return_pressed(); + void on_refresh_pressed(); + void on_refresh_released(); + void on_add_to_fav_pressed(); + void on_add_to_fav_released(); + void on_connect_pressed(); + void on_connect_released(); + void on_about_clicked(); + void on_settings_clicked(); + void on_server_list_clicked(QTreeWidgetItem *p_item, int column); + void on_server_list_doubleclicked(QTreeWidgetItem *p_item, int column); + void on_server_search_edited(QString p_text); + void on_chatfield_return_pressed(); }; #endif // LOBBY_H diff --git a/include/networkmanager.h b/include/networkmanager.h index 4d9d401..ed57a95 100644 --- a/include/networkmanager.h +++ b/include/networkmanager.h @@ -1,8 +1,8 @@ #ifndef NETWORKMANAGER_H #define NETWORKMANAGER_H -// Qt for Android has stubbed QDnsLookup. This is not documented in any part of their wiki. -// This prevents SRV lookup/failover behavior from functioning. +// Qt for Android has stubbed QDnsLookup. This is not documented in any part of +// their wiki. This prevents SRV lookup/failover behavior from functioning. // https://bugreports.qt.io/browse/QTBUG-56143 #ifndef ANDROID #define MS_FAILOVER_SUPPORTED @@ -24,60 +24,60 @@ #include class NetworkManager : public QObject { - Q_OBJECT + Q_OBJECT public: - NetworkManager(AOApplication *parent); - ~NetworkManager(); + NetworkManager(AOApplication *parent); + ~NetworkManager(); - AOApplication *ao_app; - QTcpSocket *ms_socket; - QTcpSocket *server_socket; - QDnsLookup *ms_dns; - QTimer *ms_reconnect_timer; + AOApplication *ao_app; + QTcpSocket *ms_socket; + QTcpSocket *server_socket; + QDnsLookup *ms_dns; + QTimer *ms_reconnect_timer; - const QString ms_srv_hostname = "_aoms._tcp.aceattorneyonline.com"; + const QString ms_srv_hostname = "_aoms._tcp.aceattorneyonline.com"; #ifdef LOCAL_MS - QString ms_nosrv_hostname = "localhost"; + QString ms_nosrv_hostname = "localhost"; #else - QString ms_nosrv_hostname = "master.aceattorneyonline.com"; + QString ms_nosrv_hostname = "master.aceattorneyonline.com"; #endif - const quint16 ms_port = 27016; - const int timeout_milliseconds = 2000; + const quint16 ms_port = 27016; + const int timeout_milliseconds = 2000; - // in seconds - const int ms_reconnect_delay = 7; + // in seconds + const int ms_reconnect_delay = 7; - bool ms_partial_packet = false; - QString ms_temp_packet = ""; + bool ms_partial_packet = false; + QString ms_temp_packet = ""; - bool partial_packet = false; - QString temp_packet = ""; + bool partial_packet = false; + QString temp_packet = ""; - unsigned int s_decryptor = 5; + unsigned int s_decryptor = 5; - void connect_to_master(); - void connect_to_master_nosrv(); - void connect_to_server(server_type p_server); + void connect_to_master(); + void connect_to_master_nosrv(); + void connect_to_server(server_type p_server); public slots: - void ship_ms_packet(QString p_packet); - void ship_server_packet(QString p_packet); + void ship_ms_packet(QString p_packet); + void ship_server_packet(QString p_packet); signals: - void ms_connect_finished(bool success, bool will_retry); + void ms_connect_finished(bool success, bool will_retry); private: - void perform_srv_lookup(); + void perform_srv_lookup(); private slots: - void on_srv_lookup(); - void handle_ms_packet(); - void handle_server_packet(); - void on_ms_nosrv_connect_success(); - void on_ms_socket_error(QAbstractSocket::SocketError error); - void retry_ms_connect(); + void on_srv_lookup(); + void handle_ms_packet(); + void handle_server_packet(); + void on_ms_nosrv_connect_success(); + void on_ms_socket_error(QAbstractSocket::SocketError error); + void retry_ms_connect(); }; #endif // NETWORKMANAGER_H diff --git a/include/scrolltext.h b/include/scrolltext.h index 1455762..9ed5ff7 100644 --- a/include/scrolltext.h +++ b/include/scrolltext.h @@ -8,40 +8,40 @@ #include class ScrollText : public QWidget { - Q_OBJECT - Q_PROPERTY(QString text READ text WRITE setText) - Q_PROPERTY(QString separator READ separator WRITE setSeparator) + Q_OBJECT + Q_PROPERTY(QString text READ text WRITE setText) + Q_PROPERTY(QString separator READ separator WRITE setSeparator) public: - explicit ScrollText(QWidget *parent = nullptr); + explicit ScrollText(QWidget *parent = nullptr); public slots: - QString text() const; - void setText(QString text); + QString text() const; + void setText(QString text); - QString separator() const; - void setSeparator(QString separator); + QString separator() const; + void setSeparator(QString separator); protected: - virtual void paintEvent(QPaintEvent *); - virtual void resizeEvent(QResizeEvent *); + virtual void paintEvent(QPaintEvent *); + virtual void resizeEvent(QResizeEvent *); private: - void updateText(); - QString _text; - QString _separator; - QStaticText staticText; - int singleTextWidth; - QSize wholeTextSize; - int leftMargin; - bool scrollEnabled; - int scrollPos; - QImage alphaChannel; - QImage buffer; - QTimer timer; + void updateText(); + QString _text; + QString _separator; + QStaticText staticText; + int singleTextWidth; + QSize wholeTextSize; + int leftMargin; + bool scrollEnabled; + int scrollPos; + QImage alphaChannel; + QImage buffer; + QTimer timer; private slots: - virtual void timer_timeout(); + virtual void timer_timeout(); }; #endif // SCROLLTEXT_H diff --git a/src/aoapplication.cpp b/src/aoapplication.cpp index 4d2bb31..e1e9e7f 100644 --- a/src/aoapplication.cpp +++ b/src/aoapplication.cpp @@ -10,167 +10,170 @@ AOApplication::AOApplication(int &argc, char **argv) : QApplication(argc, argv) { - // Create the QSettings class that points to the config.ini. - configini = new QSettings(get_base_path() + "config.ini", QSettings::IniFormat); + // Create the QSettings class that points to the config.ini. + configini = + new QSettings(get_base_path() + "config.ini", QSettings::IniFormat); - net_manager = new NetworkManager(this); - discord = new AttorneyOnline::Discord(); - QObject::connect(net_manager, SIGNAL(ms_connect_finished(bool, bool)), - SLOT(ms_connect_finished(bool, bool))); + net_manager = new NetworkManager(this); + discord = new AttorneyOnline::Discord(); + QObject::connect(net_manager, SIGNAL(ms_connect_finished(bool, bool)), + SLOT(ms_connect_finished(bool, bool))); } AOApplication::~AOApplication() { - destruct_lobby(); - destruct_courtroom(); - delete discord; + destruct_lobby(); + destruct_courtroom(); + delete discord; } void AOApplication::construct_lobby() { - if (lobby_constructed) { - qDebug() << "W: lobby was attempted constructed when it already exists"; - return; - } + if (lobby_constructed) { + qDebug() << "W: lobby was attempted constructed when it already exists"; + return; + } - w_lobby = new Lobby(this); - lobby_constructed = true; + w_lobby = new Lobby(this); + lobby_constructed = true; - QRect geometry = QGuiApplication::primaryScreen()->geometry(); - int x = (geometry.width() - w_lobby->width()) / 2; - int y = (geometry.height() - w_lobby->height()) / 2; - w_lobby->move(x, y); + QRect geometry = QGuiApplication::primaryScreen()->geometry(); + int x = (geometry.width() - w_lobby->width()) / 2; + int y = (geometry.height() - w_lobby->height()) / 2; + w_lobby->move(x, y); - if (is_discord_enabled()) - discord->state_lobby(); + if (is_discord_enabled()) + discord->state_lobby(); - w_lobby->show(); + w_lobby->show(); } void AOApplication::destruct_lobby() { - if (!lobby_constructed) { - qDebug() << "W: lobby was attempted destructed when it did not exist"; - return; - } + if (!lobby_constructed) { + qDebug() << "W: lobby was attempted destructed when it did not exist"; + return; + } - delete w_lobby; - w_lobby = nullptr; - lobby_constructed = false; + delete w_lobby; + w_lobby = nullptr; + lobby_constructed = false; } void AOApplication::construct_courtroom() { - if (courtroom_constructed) { - qDebug() << "W: courtroom was attempted constructed when it already exists"; - return; - } + if (courtroom_constructed) { + qDebug() << "W: courtroom was attempted constructed when it already exists"; + return; + } - w_courtroom = new Courtroom(this); - courtroom_constructed = true; + w_courtroom = new Courtroom(this); + courtroom_constructed = true; - QRect geometry = QGuiApplication::primaryScreen()->geometry(); - int x = (geometry.width() - w_courtroom->width()) / 2; - int y = (geometry.height() - w_courtroom->height()) / 2; - w_courtroom->move(x, y); + QRect geometry = QGuiApplication::primaryScreen()->geometry(); + int x = (geometry.width() - w_courtroom->width()) / 2; + int y = (geometry.height() - w_courtroom->height()) / 2; + w_courtroom->move(x, y); } void AOApplication::destruct_courtroom() { - if (!courtroom_constructed) { - qDebug() << "W: courtroom was attempted destructed when it did not exist"; - return; - } + if (!courtroom_constructed) { + qDebug() << "W: courtroom was attempted destructed when it did not exist"; + return; + } - delete w_courtroom; - w_courtroom = nullptr; - courtroom_constructed = false; + delete w_courtroom; + w_courtroom = nullptr; + courtroom_constructed = false; } QString AOApplication::get_version_string() { - return QString::number(RELEASE) + "." + - QString::number(MAJOR_VERSION) + "." + - QString::number(MINOR_VERSION); + return QString::number(RELEASE) + "." + QString::number(MAJOR_VERSION) + "." + + QString::number(MINOR_VERSION); } -void AOApplication::reload_theme() -{ - current_theme = read_theme(); -} +void AOApplication::reload_theme() { current_theme = read_theme(); } void AOApplication::set_favorite_list() { - favorite_list = read_serverlist_txt(); + favorite_list = read_serverlist_txt(); } QString AOApplication::get_current_char() { - if (courtroom_constructed) - return w_courtroom->get_current_char(); - else - return ""; + if (courtroom_constructed) + return w_courtroom->get_current_char(); + else + return ""; } void AOApplication::add_favorite_server(int p_server) { - if (p_server < 0 || p_server >= server_list.size()) - return; + if (p_server < 0 || p_server >= server_list.size()) + return; - server_type fav_server = server_list.at(p_server); + server_type fav_server = server_list.at(p_server); - QString str_port = QString::number(fav_server.port); + QString str_port = QString::number(fav_server.port); - QString server_line = fav_server.ip + ":" + str_port + ":" + fav_server.name; + QString server_line = fav_server.ip + ":" + str_port + ":" + fav_server.name; - write_to_serverlist_txt(server_line); + write_to_serverlist_txt(server_line); } void AOApplication::server_disconnected() { - if (courtroom_constructed) { - call_notice(tr("Disconnected from server.")); - construct_lobby(); - destruct_courtroom(); - } + if (courtroom_constructed) { + call_notice(tr("Disconnected from server.")); + construct_lobby(); + destruct_courtroom(); + } } void AOApplication::loading_cancelled() { - destruct_courtroom(); + destruct_courtroom(); - w_lobby->hide_loading_overlay(); + w_lobby->hide_loading_overlay(); } void AOApplication::ms_connect_finished(bool connected, bool will_retry) { - if (connected) { - AOPacket *f_packet = new AOPacket("ALL#%"); - send_ms_packet(f_packet); + if (connected) { + AOPacket *f_packet = new AOPacket("ALL#%"); + send_ms_packet(f_packet); + } + else { + if (will_retry) { + if (lobby_constructed) + w_lobby->append_error( + tr("Error connecting to master server. Will try again in %1 " + "seconds.") + .arg(QString::number(net_manager->ms_reconnect_delay))); } else { - if (will_retry) { - if (lobby_constructed) - w_lobby->append_error(tr("Error connecting to master server. Will try again in %1 seconds.").arg(QString::number(net_manager->ms_reconnect_delay))); - } - else { - call_error(tr("There was an error connecting to the master server.\n" - "We deploy multiple master servers to mitigate any possible downtime, " - "but the client appears to have exhausted all possible methods of finding " - "and connecting to one.\n" - "Please check your Internet connection and firewall, and please try again.")); - } + call_error(tr("There was an error connecting to the master server.\n" + "We deploy multiple master servers to mitigate any " + "possible downtime, " + "but the client appears to have exhausted all possible " + "methods of finding " + "and connecting to one.\n" + "Please check your Internet connection and firewall, and " + "please try again.")); } + } } void AOApplication::call_settings_menu() { - AOOptionsDialog settings(nullptr, this); - settings.exec(); + AOOptionsDialog settings(nullptr, this); + settings.exec(); } void AOApplication::call_announce_menu(Courtroom *court) { - AOCaseAnnouncerDialog announcer(nullptr, this, court); - announcer.exec(); + AOCaseAnnouncerDialog announcer(nullptr, this, court); + announcer.exec(); } diff --git a/src/aoblipplayer.cpp b/src/aoblipplayer.cpp index 957fd55..6affc28 100644 --- a/src/aoblipplayer.cpp +++ b/src/aoblipplayer.cpp @@ -1,117 +1,111 @@ #include "aoblipplayer.h" -#if defined(BASSAUDIO) //Using bass.dll for the blips +#if defined(BASSAUDIO) // Using bass.dll for the blips AOBlipPlayer::AOBlipPlayer(QWidget *parent, AOApplication *p_ao_app) { - m_parent = parent; - ao_app = p_ao_app; + m_parent = parent; + ao_app = p_ao_app; } void AOBlipPlayer::set_blips(QString p_sfx) { - QString f_path = ao_app->get_sfx_suffix(ao_app->get_sounds_path(p_sfx)); + QString f_path = ao_app->get_sfx_suffix(ao_app->get_sounds_path(p_sfx)); - for (int n_stream = 0; n_stream < 5; ++n_stream) { - BASS_StreamFree(m_stream_list[n_stream]); + for (int n_stream = 0; n_stream < 5; ++n_stream) { + BASS_StreamFree(m_stream_list[n_stream]); - if (f_path.endsWith(".opus")) - m_stream_list[n_stream] = BASS_OPUS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, BASS_UNICODE | BASS_ASYNCFILE); - else - m_stream_list[n_stream] = BASS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, BASS_UNICODE | BASS_ASYNCFILE); - } + if (f_path.endsWith(".opus")) + m_stream_list[n_stream] = BASS_OPUS_StreamCreateFile( + FALSE, f_path.utf16(), 0, 0, BASS_UNICODE | BASS_ASYNCFILE); + else + m_stream_list[n_stream] = BASS_StreamCreateFile( + FALSE, f_path.utf16(), 0, 0, BASS_UNICODE | BASS_ASYNCFILE); + } - set_volume_internal(m_volume); + set_volume_internal(m_volume); } void AOBlipPlayer::blip_tick() { - if (delay.isValid() && delay.elapsed() < max_blip_ms) - return; + if (delay.isValid() && delay.elapsed() < max_blip_ms) + return; - delay.start(); - int f_cycle = m_cycle++; + delay.start(); + int f_cycle = m_cycle++; - if (m_cycle == 5) - m_cycle = 0; + if (m_cycle == 5) + m_cycle = 0; - HSTREAM f_stream = m_stream_list[f_cycle]; - if (ao_app->get_audio_output_device() != "default") - BASS_ChannelSetDevice(f_stream, BASS_GetDevice()); - BASS_ChannelPlay(f_stream, false); + HSTREAM f_stream = m_stream_list[f_cycle]; + if (ao_app->get_audio_output_device() != "default") + BASS_ChannelSetDevice(f_stream, BASS_GetDevice()); + BASS_ChannelPlay(f_stream, false); } void AOBlipPlayer::set_volume(qreal p_value) { - m_volume = p_value / 100; - set_volume_internal(m_volume); + m_volume = p_value / 100; + set_volume_internal(m_volume); } void AOBlipPlayer::set_volume_internal(qreal p_value) { - float volume = static_cast(p_value); + float volume = static_cast(p_value); - for (int n_stream = 0; n_stream < 5; ++n_stream) { - BASS_ChannelSetAttribute(m_stream_list[n_stream], BASS_ATTRIB_VOL, volume); - } + for (int n_stream = 0; n_stream < 5; ++n_stream) { + BASS_ChannelSetAttribute(m_stream_list[n_stream], BASS_ATTRIB_VOL, volume); + } } -#elif defined(QTAUDIO) //Using Qt's QSoundEffect class +#elif defined(QTAUDIO) // Using Qt's QSoundEffect class AOBlipPlayer::AOBlipPlayer(QWidget *parent, AOApplication *p_ao_app) { - m_parent = parent; - ao_app = p_ao_app; + m_parent = parent; + ao_app = p_ao_app; } void AOBlipPlayer::set_blips(QString p_sfx) { - QString f_path = ao_app->get_sounds_path(p_sfx); + QString f_path = ao_app->get_sounds_path(p_sfx); - for (int n_stream = 0; n_stream < 5; ++n_stream) { - m_blips.setSource(QUrl::fromLocalFile(f_path)); - } + for (int n_stream = 0; n_stream < 5; ++n_stream) { + m_blips.setSource(QUrl::fromLocalFile(f_path)); + } - set_volume_internal(m_volume); + set_volume_internal(m_volume); } void AOBlipPlayer::blip_tick() { - int f_cycle = m_cycle++; + int f_cycle = m_cycle++; - if (m_cycle == 5) - m_cycle = 0; + if (m_cycle == 5) + m_cycle = 0; - m_blips.play(); + m_blips.play(); } void AOBlipPlayer::set_volume(qreal p_value) { - m_volume = p_value / 100; - set_volume_internal(m_volume); + m_volume = p_value / 100; + set_volume_internal(m_volume); } void AOBlipPlayer::set_volume_internal(qreal p_value) { - m_blips.setVolume(m_volume); + m_blips.setVolume(m_volume); } -#else //No audio +#else // No audio AOBlipPlayer::AOBlipPlayer(QWidget *parent, AOApplication *p_ao_app) { - m_parent = parent; - ao_app = p_ao_app; + m_parent = parent; + ao_app = p_ao_app; } -void AOBlipPlayer::set_blips(QString p_sfx) -{ -} +void AOBlipPlayer::set_blips(QString p_sfx) {} -void AOBlipPlayer::blip_tick() -{ -} +void AOBlipPlayer::blip_tick() {} -void AOBlipPlayer::set_volume(qreal p_value) -{ -} +void AOBlipPlayer::set_volume(qreal p_value) {} -void AOBlipPlayer::set_volume_internal(qreal p_value) -{ -} +void AOBlipPlayer::set_volume_internal(qreal p_value) {} #endif diff --git a/src/aobutton.cpp b/src/aobutton.cpp index 05dedc1..dc2d881 100644 --- a/src/aobutton.cpp +++ b/src/aobutton.cpp @@ -3,30 +3,36 @@ #include "debug_functions.h" #include "file_functions.h" -AOButton::AOButton(QWidget *parent, AOApplication *p_ao_app) : QPushButton(parent) +AOButton::AOButton(QWidget *parent, AOApplication *p_ao_app) + : QPushButton(parent) { - ao_app = p_ao_app; + ao_app = p_ao_app; } -AOButton::~AOButton() -{ -} +AOButton::~AOButton() {} void AOButton::set_image(QString p_image) { - 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)); + 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; }"); - } - 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; }"); - } - else - return; + 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; }"); + } + 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; }"); + } + else + return; } diff --git a/src/aocaseannouncerdialog.cpp b/src/aocaseannouncerdialog.cpp index 3063aa8..d91433a 100644 --- a/src/aocaseannouncerdialog.cpp +++ b/src/aocaseannouncerdialog.cpp @@ -1,82 +1,85 @@ #include "aocaseannouncerdialog.h" -AOCaseAnnouncerDialog::AOCaseAnnouncerDialog(QWidget *parent, AOApplication *p_ao_app, Courtroom *p_court) +AOCaseAnnouncerDialog::AOCaseAnnouncerDialog(QWidget *parent, + AOApplication *p_ao_app, + Courtroom *p_court) : QDialog(parent) { - ao_app = p_ao_app; - court = p_court; + ao_app = p_ao_app; + court = p_court; - setWindowTitle(tr("Case Announcer")); - resize(405, 235); + setWindowTitle(tr("Case Announcer")); + resize(405, 235); - ui_announcer_buttons = new QDialogButtonBox(this); + ui_announcer_buttons = new QDialogButtonBox(this); - QSizePolicy sizepolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); - sizepolicy.setHorizontalStretch(0); - sizepolicy.setVerticalStretch(0); - sizepolicy.setHeightForWidth(ui_announcer_buttons->sizePolicy().hasHeightForWidth()); - ui_announcer_buttons->setSizePolicy(sizepolicy); - ui_announcer_buttons->setOrientation(Qt::Horizontal); - ui_announcer_buttons->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + QSizePolicy sizepolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + sizepolicy.setHorizontalStretch(0); + sizepolicy.setVerticalStretch(0); + sizepolicy.setHeightForWidth( + ui_announcer_buttons->sizePolicy().hasHeightForWidth()); + ui_announcer_buttons->setSizePolicy(sizepolicy); + ui_announcer_buttons->setOrientation(Qt::Horizontal); + ui_announcer_buttons->setStandardButtons(QDialogButtonBox::Ok | + QDialogButtonBox::Cancel); - QObject::connect(ui_announcer_buttons, SIGNAL(accepted()), this, SLOT(ok_pressed())); - QObject::connect(ui_announcer_buttons, SIGNAL(rejected()), this, SLOT(cancel_pressed())); + QObject::connect(ui_announcer_buttons, SIGNAL(accepted()), this, + SLOT(ok_pressed())); + QObject::connect(ui_announcer_buttons, SIGNAL(rejected()), this, + SLOT(cancel_pressed())); - setUpdatesEnabled(false); + setUpdatesEnabled(false); - ui_vbox_layout = new QVBoxLayout(this); + ui_vbox_layout = new QVBoxLayout(this); - ui_form_layout = new QFormLayout(this); - ui_form_layout->setLabelAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignVCenter); - ui_form_layout->setFormAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignTop); - ui_form_layout->setContentsMargins(6, 6, 6, 6); + ui_form_layout = new QFormLayout(this); + ui_form_layout->setLabelAlignment(Qt::AlignLeading | Qt::AlignLeft | + Qt::AlignVCenter); + ui_form_layout->setFormAlignment(Qt::AlignLeading | Qt::AlignLeft | + Qt::AlignTop); + ui_form_layout->setContentsMargins(6, 6, 6, 6); - ui_vbox_layout->addItem(ui_form_layout); - ui_vbox_layout->addWidget(ui_announcer_buttons); + ui_vbox_layout->addItem(ui_form_layout); + ui_vbox_layout->addWidget(ui_announcer_buttons); - ui_case_title_label = new QLabel(this); - ui_case_title_label->setText(tr("Case title:")); + ui_case_title_label = new QLabel(this); + ui_case_title_label->setText(tr("Case title:")); - ui_form_layout->setWidget(0, QFormLayout::LabelRole, ui_case_title_label); + ui_form_layout->setWidget(0, QFormLayout::LabelRole, ui_case_title_label); - ui_case_title_textbox = new QLineEdit(this); - ui_case_title_textbox->setMaxLength(50); + ui_case_title_textbox = new QLineEdit(this); + ui_case_title_textbox->setMaxLength(50); - ui_form_layout->setWidget(0, QFormLayout::FieldRole, ui_case_title_textbox); + ui_form_layout->setWidget(0, QFormLayout::FieldRole, ui_case_title_textbox); - ui_defense_needed = new QCheckBox(this); - ui_defense_needed->setText(tr("Defense needed")); - ui_prosecutor_needed = new QCheckBox(this); - ui_prosecutor_needed->setText(tr("Prosecution needed")); - ui_judge_needed = new QCheckBox(this); - ui_judge_needed->setText(tr("Judge needed")); - ui_juror_needed = new QCheckBox(this); - ui_juror_needed->setText(tr("Jurors needed")); - ui_steno_needed = new QCheckBox(this); - ui_steno_needed->setText(tr("Stenographer needed")); + ui_defense_needed = new QCheckBox(this); + ui_defense_needed->setText(tr("Defense needed")); + ui_prosecutor_needed = new QCheckBox(this); + ui_prosecutor_needed->setText(tr("Prosecution needed")); + ui_judge_needed = new QCheckBox(this); + ui_judge_needed->setText(tr("Judge needed")); + ui_juror_needed = new QCheckBox(this); + ui_juror_needed->setText(tr("Jurors needed")); + ui_steno_needed = new QCheckBox(this); + ui_steno_needed->setText(tr("Stenographer needed")); - ui_form_layout->setWidget(1, QFormLayout::FieldRole, ui_defense_needed); - ui_form_layout->setWidget(2, QFormLayout::FieldRole, ui_prosecutor_needed); - ui_form_layout->setWidget(3, QFormLayout::FieldRole, ui_judge_needed); - ui_form_layout->setWidget(4, QFormLayout::FieldRole, ui_juror_needed); - ui_form_layout->setWidget(5, QFormLayout::FieldRole, ui_steno_needed); + ui_form_layout->setWidget(1, QFormLayout::FieldRole, ui_defense_needed); + ui_form_layout->setWidget(2, QFormLayout::FieldRole, ui_prosecutor_needed); + ui_form_layout->setWidget(3, QFormLayout::FieldRole, ui_judge_needed); + ui_form_layout->setWidget(4, QFormLayout::FieldRole, ui_juror_needed); + ui_form_layout->setWidget(5, QFormLayout::FieldRole, ui_steno_needed); - setUpdatesEnabled(true); + setUpdatesEnabled(true); } void AOCaseAnnouncerDialog::ok_pressed() { - court->announce_case(ui_case_title_textbox->text(), - ui_defense_needed->isChecked(), - ui_prosecutor_needed->isChecked(), - ui_judge_needed->isChecked(), - ui_juror_needed->isChecked(), - ui_steno_needed->isChecked()); + court->announce_case( + ui_case_title_textbox->text(), ui_defense_needed->isChecked(), + ui_prosecutor_needed->isChecked(), ui_judge_needed->isChecked(), + ui_juror_needed->isChecked(), ui_steno_needed->isChecked()); - done(0); + done(0); } -void AOCaseAnnouncerDialog::cancel_pressed() -{ - done(0); -} +void AOCaseAnnouncerDialog::cancel_pressed() { done(0); } diff --git a/src/aocharbutton.cpp b/src/aocharbutton.cpp index d8c337d..844c959 100644 --- a/src/aocharbutton.cpp +++ b/src/aocharbutton.cpp @@ -2,94 +2,94 @@ #include "file_functions.h" -AOCharButton::AOCharButton(QWidget *parent, AOApplication *p_ao_app, int x_pos, int y_pos, bool is_taken) : QPushButton(parent) +AOCharButton::AOCharButton(QWidget *parent, AOApplication *p_ao_app, int x_pos, + int y_pos, bool is_taken) + : QPushButton(parent) { - m_parent = parent; + m_parent = parent; - ao_app = p_ao_app; + ao_app = p_ao_app; - taken = is_taken; + taken = is_taken; - this->resize(60, 60); - this->move(x_pos, y_pos); + this->resize(60, 60); + this->move(x_pos, y_pos); - ui_taken = new AOImage(this, ao_app); - ui_taken->resize(60, 60); - ui_taken->set_image("char_taken"); - ui_taken->setAttribute(Qt::WA_TransparentForMouseEvents); - ui_taken->hide(); + ui_taken = new AOImage(this, ao_app); + ui_taken->resize(60, 60); + ui_taken->set_image("char_taken"); + ui_taken->setAttribute(Qt::WA_TransparentForMouseEvents); + ui_taken->hide(); - ui_passworded = new AOImage(this, ao_app); - ui_passworded->resize(60, 60); - ui_passworded->set_image("char_passworded"); - ui_passworded->setAttribute(Qt::WA_TransparentForMouseEvents); - ui_passworded->hide(); + ui_passworded = new AOImage(this, ao_app); + ui_passworded->resize(60, 60); + ui_passworded->set_image("char_passworded"); + ui_passworded->setAttribute(Qt::WA_TransparentForMouseEvents); + ui_passworded->hide(); - ui_selector = new AOImage(parent, ao_app); - ui_selector->resize(62, 62); - ui_selector->move(x_pos - 1, y_pos - 1); - ui_selector->set_image("char_selector"); - ui_selector->setAttribute(Qt::WA_TransparentForMouseEvents); - ui_selector->hide(); + ui_selector = new AOImage(parent, ao_app); + ui_selector->resize(62, 62); + ui_selector->move(x_pos - 1, y_pos - 1); + ui_selector->set_image("char_selector"); + ui_selector->setAttribute(Qt::WA_TransparentForMouseEvents); + ui_selector->hide(); } void AOCharButton::reset() { - ui_taken->hide(); - ui_passworded->hide(); - ui_selector->hide(); + ui_taken->hide(); + ui_passworded->hide(); + ui_selector->hide(); } -void AOCharButton::set_taken(bool is_taken) -{ - taken = is_taken; -} +void AOCharButton::set_taken(bool is_taken) { taken = is_taken; } void AOCharButton::apply_taken_image() { - if (taken) { - ui_taken->move(0, 0); - ui_taken->show(); - } - else { - ui_taken->hide(); - } + if (taken) { + ui_taken->move(0, 0); + ui_taken->show(); + } + else { + ui_taken->hide(); + } } -void AOCharButton::set_passworded() -{ - ui_passworded->show(); -} +void AOCharButton::set_passworded() { ui_passworded->show(); } void AOCharButton::set_image(QString p_character) { - QString image_path = ao_app->get_static_image_suffix(ao_app->get_character_path(p_character, "char_icon")); + QString image_path = ao_app->get_static_image_suffix( + ao_app->get_character_path(p_character, "char_icon")); - this->setText(""); + this->setText(""); - if (file_exists(image_path)) { - 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; }"); - } - else { - this->setStyleSheet("QPushButton { border-image: url(); }" - "QToolTip { background-image: url(); color: #000000; background-color: #ffffff; border: 0px; }"); - this->setText(p_character); - } + if (file_exists(image_path)) { + 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; }"); + } + else { + this->setStyleSheet("QPushButton { border-image: url(); }" + "QToolTip { background-image: url(); color: #000000; " + "background-color: #ffffff; border: 0px; }"); + this->setText(p_character); + } } void AOCharButton::enterEvent(QEvent *e) { - ui_selector->move(this->x() - 1, this->y() - 1); - ui_selector->raise(); - ui_selector->show(); + ui_selector->move(this->x() - 1, this->y() - 1); + ui_selector->raise(); + ui_selector->show(); - setFlat(false); - QPushButton::enterEvent(e); + setFlat(false); + QPushButton::enterEvent(e); } void AOCharButton::leaveEvent(QEvent *e) { - ui_selector->hide(); - QPushButton::leaveEvent(e); + ui_selector->hide(); + QPushButton::leaveEvent(e); } diff --git a/src/aocharmovie.cpp b/src/aocharmovie.cpp index 2963275..252aab5 100644 --- a/src/aocharmovie.cpp +++ b/src/aocharmovie.cpp @@ -4,292 +4,320 @@ #include "file_functions.h" #include "misc_functions.h" -AOCharMovie::AOCharMovie(QWidget *p_parent, AOApplication *p_ao_app) : QLabel(p_parent) +AOCharMovie::AOCharMovie(QWidget *p_parent, AOApplication *p_ao_app) + : QLabel(p_parent) { - ao_app = p_ao_app; - preanim_timer = new QTimer(this); - preanim_timer->setSingleShot(true); + ao_app = p_ao_app; + preanim_timer = new QTimer(this); + preanim_timer->setSingleShot(true); - ticker = new QTimer(this); - ticker->setTimerType(Qt::PreciseTimer); - ticker->setSingleShot(false); - connect(ticker, SIGNAL(timeout()), this, SLOT(movie_ticker())); + ticker = new QTimer(this); + ticker->setTimerType(Qt::PreciseTimer); + ticker->setSingleShot(false); + connect(ticker, SIGNAL(timeout()), this, SLOT(movie_ticker())); - // connect(m_movie, SIGNAL(frameChanged(int)), this, SLOT(frame_change(int))); - connect(preanim_timer, SIGNAL(timeout()), this, SLOT(preanim_done())); + // connect(m_movie, SIGNAL(frameChanged(int)), this, + // SLOT(frame_change(int))); + connect(preanim_timer, SIGNAL(timeout()), this, SLOT(preanim_done())); } -void AOCharMovie::load_image(QString p_char, QString p_emote, QString emote_prefix) +void AOCharMovie::load_image(QString p_char, QString p_emote, + QString emote_prefix) { #ifdef DEBUG_CHARMOVIE - actual_time.restart(); + actual_time.restart(); #endif - QString emote_path; - QList pathlist; - pathlist = { - ao_app->get_image_suffix(ao_app->get_character_path(p_char, emote_prefix + p_emote)), //Default path - ao_app->get_image_suffix(ao_app->get_character_path(p_char, emote_prefix + "/" + p_emote)), //Path check if it's categorized into a folder - ao_app->get_character_path(p_char, p_emote + ".png"), //Non-animated path if emote_prefix fails - 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 - }; + QString emote_path; + QList pathlist; + pathlist = { + ao_app->get_image_suffix(ao_app->get_character_path( + p_char, emote_prefix + p_emote)), // Default path + ao_app->get_image_suffix(ao_app->get_character_path( + p_char, emote_prefix + "/" + + p_emote)), // Path check if it's categorized into a folder + ao_app->get_character_path( + p_char, p_emote + ".png"), // Non-animated path if emote_prefix fails + 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 + }; - for (QString path : pathlist) { - if (file_exists(path)) { - emote_path = path; - break; - } + for (QString path : pathlist) { + if (file_exists(path)) { + emote_path = path; + break; } + } - this->clear(); - ticker->stop(); - preanim_timer->stop(); - movie_frames.clear(); - movie_delays.clear(); - movie_effects.clear(); + this->clear(); + ticker->stop(); + preanim_timer->stop(); + movie_frames.clear(); + movie_delays.clear(); + movie_effects.clear(); - if (!file_exists(emote_path)) - return; + if (!file_exists(emote_path)) + return; - m_reader->setFileName(emote_path); - QPixmap f_pixmap = this->get_pixmap(m_reader->read()); - int f_delay = m_reader->nextImageDelay(); + m_reader->setFileName(emote_path); + QPixmap f_pixmap = this->get_pixmap(m_reader->read()); + int f_delay = m_reader->nextImageDelay(); - frame = 0; - max_frames = m_reader->imageCount(); + frame = 0; + max_frames = m_reader->imageCount(); - this->set_frame(f_pixmap); - this->show(); - if (max_frames > 1) { - movie_frames.append(f_pixmap); - movie_delays.append(f_delay); - } + this->set_frame(f_pixmap); + this->show(); + if (max_frames > 1) { + movie_frames.append(f_pixmap); + movie_delays.append(f_delay); + } - m_char = p_char; - m_emote = emote_prefix + p_emote; + m_char = p_char; + m_emote = emote_prefix + p_emote; - if (network_strings.size() > 0) //our FX overwritten by networked ones - this->load_network_effects(); - else //Use default ini FX - this->load_effects(); + if (network_strings.size() > 0) // our FX overwritten by networked ones + this->load_network_effects(); + else // Use default ini FX + this->load_effects(); #ifdef DEBUG_CHARMOVIE - qDebug() << max_frames << "Setting image to " << emote_path << "Time taken to process image:" << actual_time.elapsed(); + qDebug() << max_frames << "Setting image to " << emote_path + << "Time taken to process image:" << actual_time.elapsed(); - actual_time.restart(); + actual_time.restart(); #endif } void AOCharMovie::load_effects() { - movie_effects.clear(); - 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); - if (effect != "") { - movie_effects[e_frame].append("shake"); - } - - effect = ao_app->get_flash_frame(m_char, m_emote, e_frame); - if (effect != "") { - movie_effects[e_frame].append("flash"); - } - - effect = ao_app->get_sfx_frame(m_char, m_emote, e_frame); - if (effect != "") { - movie_effects[e_frame].append("sfx^" + effect); - } + movie_effects.clear(); + 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); + if (effect != "") { + movie_effects[e_frame].append("shake"); } + + effect = ao_app->get_flash_frame(m_char, m_emote, e_frame); + if (effect != "") { + movie_effects[e_frame].append("flash"); + } + + effect = ao_app->get_sfx_frame(m_char, m_emote, e_frame); + if (effect != "") { + movie_effects[e_frame].append("sfx^" + effect); + } + } } void AOCharMovie::load_network_effects() { - movie_effects.clear(); - movie_effects.resize(max_frames); - //Order is important!!! - QStringList effects_list = {"shake", "flash", "sfx^"}; + movie_effects.clear(); + movie_effects.resize(max_frames); + // Order is important!!! + QStringList effects_list = {"shake", "flash", "sfx^"}; - //Determines which list is smaller - effects_list or network_strings - and uses it as basis for the loop. - //This way, incomplete network_strings would still be parsed, and excess/unaccounted for networked information is omitted. - int effects_size = qMin(effects_list.size(), network_strings.size()); + // Determines which list is smaller - effects_list or network_strings - and + // uses it as basis for the loop. This way, incomplete network_strings would + // still be parsed, and excess/unaccounted for networked information is + // omitted. + int effects_size = qMin(effects_list.size(), network_strings.size()); - for (int i = 0; i < effects_size; ++i) { - QString netstring = network_strings.at(i); - QStringList emote_splits = netstring.split("^"); - foreach (QString emote, emote_splits) { - QStringList parsed = emote.split("|"); - if (parsed.size() <= 0 || parsed.at(0) != m_emote) - continue; - foreach (QString frame_data, parsed) { - QStringList frame_split = frame_data.split("="); - if (frame_split.size() <= 1) //We might still be hanging at the emote itself (entry 0). - continue; - int f_frame = frame_split.at(0).toInt(); - if (f_frame >= max_frames) { - qDebug() << "Warning: out of bounds" << effects_list[i] << "frame" << f_frame << "out of" << max_frames << "for" << m_char << m_emote; - continue; - } - QString f_data = frame_split.at(1); - if (f_data != "") { - QString effect = effects_list[i]; - if (effect == "sfx^") //Currently the only frame result that feeds us data, let's yank it in. - effect += f_data; - qDebug() << effect << f_data << "frame" << f_frame << "for" << m_char << m_emote; - movie_effects[f_frame].append(effect); - } - } + for (int i = 0; i < effects_size; ++i) { + QString netstring = network_strings.at(i); + QStringList emote_splits = netstring.split("^"); + foreach (QString emote, emote_splits) { + QStringList parsed = emote.split("|"); + if (parsed.size() <= 0 || parsed.at(0) != m_emote) + continue; + foreach (QString frame_data, parsed) { + QStringList frame_split = frame_data.split("="); + if (frame_split.size() <= + 1) // We might still be hanging at the emote itself (entry 0). + continue; + int f_frame = frame_split.at(0).toInt(); + if (f_frame >= max_frames) { + qDebug() << "Warning: out of bounds" << effects_list[i] << "frame" + << f_frame << "out of" << max_frames << "for" << m_char + << m_emote; + continue; } + QString f_data = frame_split.at(1); + if (f_data != "") { + QString effect = effects_list[i]; + if (effect == "sfx^") // Currently the only frame result that feeds us + // data, let's yank it in. + effect += f_data; + qDebug() << effect << f_data << "frame" << f_frame << "for" << m_char + << m_emote; + movie_effects[f_frame].append(effect); + } + } } + } } void AOCharMovie::play() { - play_frame_effect(frame); - if (max_frames <= 1) { - if (play_once) - ticker->start(60); - } - else - ticker->start(this->get_frame_delay(movie_delays[frame])); + play_frame_effect(frame); + if (max_frames <= 1) { + if (play_once) + ticker->start(60); + } + else + ticker->start(this->get_frame_delay(movie_delays[frame])); } void AOCharMovie::play_pre(QString p_char, QString p_emote, int duration) { - load_image(p_char, p_emote, ""); - //As much as I'd like to screw around with [Time] durations modifying the animation speed, I don't think I can reliably do that, - //not without looping through all frames in the image at least - which causes lag. So for now it simply ends the preanimation early instead. - play_once = true; - if (duration > 0) //It's -1 if there's no definition in [Time] for it. In which case, it will let the animation run out in full. Duration 0 does the same. - preanim_timer->start(duration * time_mod); //This timer will not fire if the animation finishes earlier than that - play(); + load_image(p_char, p_emote, ""); + // As much as I'd like to screw around with [Time] durations modifying the + // animation speed, I don't think I can reliably do that, not without looping + // through all frames in the image at least - which causes lag. So for now it + // simply ends the preanimation early instead. + play_once = true; + if (duration > + 0) // It's -1 if there's no definition in [Time] for it. In which case, it + // will let the animation run out in full. Duration 0 does the same. + preanim_timer->start(duration * + time_mod); // This timer will not fire if the animation + // finishes earlier than that + play(); } void AOCharMovie::play_talking(QString p_char, QString p_emote) { - play_once = false; - load_image(p_char, p_emote, "(b)"); - play(); + play_once = false; + load_image(p_char, p_emote, "(b)"); + play(); } void AOCharMovie::play_idle(QString p_char, QString p_emote) { - play_once = false; - load_image(p_char, p_emote, "(a)"); - play(); + play_once = false; + load_image(p_char, p_emote, "(a)"); + play(); } void AOCharMovie::play_frame_effect(int frame) { - if (frame < max_frames) { - foreach (QString effect, movie_effects[frame]) { - if (effect == "shake") { - shake(); + if (frame < max_frames) { + foreach (QString effect, movie_effects[frame]) { + if (effect == "shake") { + shake(); #ifdef DEBUG_CHARMOVIE - qDebug() << "Attempting to play shake on frame" << frame; + qDebug() << "Attempting to play shake on frame" << frame; #endif - } + } - if (effect == "flash") { - flash(); + if (effect == "flash") { + flash(); #ifdef DEBUG_CHARMOVIE - qDebug() << "Attempting to play flash on frame" << frame; + qDebug() << "Attempting to play flash on frame" << frame; #endif - } + } - if (effect.startsWith("sfx^")) { - QString sfx = effect.section("^", 1); - play_sfx(sfx); + if (effect.startsWith("sfx^")) { + QString sfx = effect.section("^", 1); + play_sfx(sfx); #ifdef DEBUG_CHARMOVIE - qDebug() << "Attempting to play sfx" << sfx << "on frame" << frame; + qDebug() << "Attempting to play sfx" << sfx << "on frame" << frame; #endif - } - } + } } + } } void AOCharMovie::stop() { - //for all intents and purposes, stopping is the same as hiding. at no point do we want a frozen gif to display - ticker->stop(); - preanim_timer->stop(); - this->hide(); + // for all intents and purposes, stopping is the same as hiding. at no point + // do we want a frozen gif to display + ticker->stop(); + preanim_timer->stop(); + this->hide(); } QPixmap AOCharMovie::get_pixmap(QImage image) { - QPixmap f_pixmap; - if (m_flipped) - f_pixmap = QPixmap::fromImage(image.mirrored(true, false)); - else - f_pixmap = QPixmap::fromImage(image); - // auto aspect_ratio = Qt::KeepAspectRatio; - auto transform_mode = Qt::FastTransformation; - if (f_pixmap.height() > f_h) //We are downscaling, use anti-aliasing. - transform_mode = Qt::SmoothTransformation; + QPixmap f_pixmap; + if (m_flipped) + f_pixmap = QPixmap::fromImage(image.mirrored(true, false)); + else + f_pixmap = QPixmap::fromImage(image); + // auto aspect_ratio = Qt::KeepAspectRatio; + auto transform_mode = Qt::FastTransformation; + if (f_pixmap.height() > f_h) // We are downscaling, use anti-aliasing. + transform_mode = Qt::SmoothTransformation; - f_pixmap = f_pixmap.scaledToHeight(f_h, transform_mode); - this->resize(f_pixmap.size()); + f_pixmap = f_pixmap.scaledToHeight(f_h, transform_mode); + this->resize(f_pixmap.size()); - return f_pixmap; + return f_pixmap; } void AOCharMovie::set_frame(QPixmap f_pixmap) { - this->setPixmap(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 + this->setPixmap(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 } void AOCharMovie::combo_resize(int w, int h) { - QSize f_size(w, h); - f_w = w; - f_h = h; - this->resize(f_size); + QSize f_size(w, h); + f_w = w; + f_h = h; + this->resize(f_size); } int AOCharMovie::get_frame_delay(int delay) { - return static_cast(double(delay) * double(speed / 100)); + return static_cast(double(delay) * double(speed / 100)); } void AOCharMovie::move(int ax, int ay) { - x = ax; - y = ay; - QLabel::move(x, y); + x = ax; + y = ay; + QLabel::move(x, y); } void AOCharMovie::movie_ticker() { - ++frame; - if (frame >= max_frames) { - if (play_once) { - preanim_done(); - return; - } - else - frame = 0; - } - // qint64 difference = elapsed - movie_delays[frame]; - if (frame >= movie_frames.size()) { - m_reader->jumpToImage(frame); - movie_frames.resize(frame + 1); - movie_frames[frame] = this->get_pixmap(m_reader->read()); - movie_delays.resize(frame + 1); - movie_delays[frame] = m_reader->nextImageDelay(); + ++frame; + if (frame >= max_frames) { + if (play_once) { + preanim_done(); + return; } + else + frame = 0; + } + // qint64 difference = elapsed - movie_delays[frame]; + if (frame >= movie_frames.size()) { + m_reader->jumpToImage(frame); + movie_frames.resize(frame + 1); + movie_frames[frame] = this->get_pixmap(m_reader->read()); + movie_delays.resize(frame + 1); + movie_delays[frame] = m_reader->nextImageDelay(); + } #ifdef DEBUG_CHARMOVIE - qDebug() << frame << movie_delays[frame] << "actual time taken from last frame:" << actual_time.restart(); + qDebug() << frame << movie_delays[frame] + << "actual time taken from last frame:" << actual_time.restart(); #endif - this->set_frame(movie_frames[frame]); - play_frame_effect(frame); - ticker->setInterval(this->get_frame_delay(movie_delays[frame])); + this->set_frame(movie_frames[frame]); + play_frame_effect(frame); + ticker->setInterval(this->get_frame_delay(movie_delays[frame])); } void AOCharMovie::preanim_done() { - ticker->stop(); - preanim_timer->stop(); - done(); + ticker->stop(); + preanim_timer->stop(); + done(); } diff --git a/src/aoemotebutton.cpp b/src/aoemotebutton.cpp index 991451f..abec526 100644 --- a/src/aoemotebutton.cpp +++ b/src/aoemotebutton.cpp @@ -2,40 +2,44 @@ #include "file_functions.h" -AOEmoteButton::AOEmoteButton(QWidget *p_parent, AOApplication *p_ao_app, int p_x, int p_y, int p_w, int p_h) : QPushButton(p_parent) +AOEmoteButton::AOEmoteButton(QWidget *p_parent, AOApplication *p_ao_app, + int p_x, int p_y, int p_w, int p_h) + : QPushButton(p_parent) { - parent = p_parent; - ao_app = p_ao_app; + parent = p_parent; + ao_app = p_ao_app; - this->move(p_x, p_y); - this->resize(p_w, p_h); + this->move(p_x, p_y); + this->resize(p_w, p_h); - connect(this, SIGNAL(clicked()), this, SLOT(on_clicked())); + connect(this, SIGNAL(clicked()), this, SLOT(on_clicked())); } void AOEmoteButton::set_image(QString p_image, QString p_emote_comment) { - if (file_exists(p_image)) { - this->setText(""); - this->setStyleSheet("QPushButton { border-image: url(\"" + p_image + "\") 0 0 0 0 stretch stretch; }" - "QToolTip { color: #000000; background-color: #ffffff; border: 0px; }"); - } - else { - this->setText(p_emote_comment); - this->setStyleSheet("QPushButton { border-image: url(); }" - "QToolTip { background-image: url(); color: #000000; background-color: #ffffff; border: 0px; }"); - } + if (file_exists(p_image)) { + this->setText(""); + this->setStyleSheet( + "QPushButton { border-image: url(\"" + p_image + + "\") 0 0 0 0 stretch stretch; }" + "QToolTip { color: #000000; background-color: #ffffff; border: 0px; }"); + } + else { + this->setText(p_emote_comment); + this->setStyleSheet("QPushButton { border-image: url(); }" + "QToolTip { background-image: url(); color: #000000; " + "background-color: #ffffff; border: 0px; }"); + } } 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(p_char, "emotions/button" + emotion_number + suffix)); + QString emotion_number = QString::number(p_emote + 1); + QString image_path = + ao_app->get_static_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)); + this->set_image(image_path, ao_app->get_emote_comment(p_char, p_emote)); } -void AOEmoteButton::on_clicked() -{ - emote_clicked(m_id); -} +void AOEmoteButton::on_clicked() { emote_clicked(m_id); } diff --git a/src/aoevidencebutton.cpp b/src/aoevidencebutton.cpp index 596374b..f85a223 100644 --- a/src/aoevidencebutton.cpp +++ b/src/aoevidencebutton.cpp @@ -2,84 +2,88 @@ #include "file_functions.h" -AOEvidenceButton::AOEvidenceButton(QWidget *p_parent, AOApplication *p_ao_app, int p_x, int p_y, int p_w, int p_h) : QPushButton(p_parent) +AOEvidenceButton::AOEvidenceButton(QWidget *p_parent, AOApplication *p_ao_app, + int p_x, int p_y, int p_w, int p_h) + : QPushButton(p_parent) { - ao_app = p_ao_app; - m_parent = p_parent; + ao_app = p_ao_app; + m_parent = p_parent; - ui_selected = new AOImage(this, ao_app); - ui_selected->resize(p_w, p_h); - // ui_selected->move(p_x, p_y); - ui_selected->set_image("evidence_selected"); - ui_selected->setAttribute(Qt::WA_TransparentForMouseEvents); - ui_selected->hide(); + ui_selected = new AOImage(this, ao_app); + ui_selected->resize(p_w, p_h); + // ui_selected->move(p_x, p_y); + ui_selected->set_image("evidence_selected"); + ui_selected->setAttribute(Qt::WA_TransparentForMouseEvents); + ui_selected->hide(); - ui_selector = new AOImage(this, ao_app); - ui_selector->resize(p_w, p_h); - // ui_selector->move(p_x - 1, p_y - 1); - ui_selector->set_image("evidence_selector"); - ui_selector->setAttribute(Qt::WA_TransparentForMouseEvents); - ui_selector->hide(); + ui_selector = new AOImage(this, ao_app); + ui_selector->resize(p_w, p_h); + // ui_selector->move(p_x - 1, p_y - 1); + ui_selector->set_image("evidence_selector"); + ui_selector->setAttribute(Qt::WA_TransparentForMouseEvents); + ui_selector->hide(); - this->move(p_x, p_y); - this->resize(p_w, p_h); - // this->setAcceptDrops(true); + this->move(p_x, p_y); + this->resize(p_w, p_h); + // this->setAcceptDrops(true); - connect(this, SIGNAL(clicked()), this, SLOT(on_clicked())); + connect(this, SIGNAL(clicked()), this, SLOT(on_clicked())); } void AOEvidenceButton::set_image(QString p_image) { - QString image_path = ao_app->get_evidence_path(p_image); - if (file_exists(p_image)) { - this->setText(""); - this->setStyleSheet("QPushButton { border-image: url(\"" + p_image + "\") 0 0 0 0 stretch stretch; }" - "QToolTip { color: #000000; background-color: #ffffff; border: 0px; }"); - } - else if (file_exists(image_path)) { - this->setText(""); - this->setStyleSheet("QPushButton { border-image: url(\"" + image_path + "\") 0 0 0 0 stretch stretch; }" - "QToolTip { color: #000000; background-color: #ffffff; border: 0px; }"); - } - else { - this->setText(p_image); - this->setStyleSheet("QPushButton { border-image: url(); }" - "QToolTip { background-image: url(); color: #000000; background-color: #ffffff; border: 0px; }"); - } + QString image_path = ao_app->get_evidence_path(p_image); + if (file_exists(p_image)) { + this->setText(""); + this->setStyleSheet( + "QPushButton { border-image: url(\"" + p_image + + "\") 0 0 0 0 stretch stretch; }" + "QToolTip { color: #000000; background-color: #ffffff; border: 0px; }"); + } + else if (file_exists(image_path)) { + this->setText(""); + this->setStyleSheet( + "QPushButton { border-image: url(\"" + image_path + + "\") 0 0 0 0 stretch stretch; }" + "QToolTip { color: #000000; background-color: #ffffff; border: 0px; }"); + } + else { + this->setText(p_image); + this->setStyleSheet("QPushButton { border-image: url(); }" + "QToolTip { background-image: url(); color: #000000; " + "background-color: #ffffff; border: 0px; }"); + } } 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 theme_image_path = ao_app->get_theme_path(p_image); + QString default_image_path = ao_app->get_default_theme_path(p_image); - QString final_image_path; + QString final_image_path; - if (file_exists(theme_image_path)) - final_image_path = theme_image_path; - else - final_image_path = default_image_path; + if (file_exists(theme_image_path)) + final_image_path = theme_image_path; + else + final_image_path = default_image_path; - this->set_image(final_image_path); + this->set_image(final_image_path); } void AOEvidenceButton::set_selected(bool p_selected) { - if (p_selected) - ui_selected->show(); - else - ui_selected->hide(); + if (p_selected) + ui_selected->show(); + else + ui_selected->hide(); } -void AOEvidenceButton::on_clicked() -{ - evidence_clicked(m_id); -} +void AOEvidenceButton::on_clicked() { evidence_clicked(m_id); } void AOEvidenceButton::mouseDoubleClickEvent(QMouseEvent *e) { - QPushButton::mouseDoubleClickEvent(e); - evidence_double_clicked(m_id); + QPushButton::mouseDoubleClickEvent(e); + evidence_double_clicked(m_id); } /* @@ -100,18 +104,18 @@ void AOEvidenceButton::dragEnterEvent(QMouseEvent *e) void AOEvidenceButton::enterEvent(QEvent *e) { - ui_selector->show(); + ui_selector->show(); - on_hover(m_id, true); + on_hover(m_id, true); - setFlat(false); - QPushButton::enterEvent(e); + setFlat(false); + QPushButton::enterEvent(e); } void AOEvidenceButton::leaveEvent(QEvent *e) { - ui_selector->hide(); + ui_selector->hide(); - on_hover(m_id, false); - QPushButton::leaveEvent(e); + on_hover(m_id, false); + QPushButton::leaveEvent(e); } diff --git a/src/aoevidencedisplay.cpp b/src/aoevidencedisplay.cpp index 22f5720..2ffea2c 100644 --- a/src/aoevidencedisplay.cpp +++ b/src/aoevidencedisplay.cpp @@ -4,71 +4,68 @@ #include "file_functions.h" #include "misc_functions.h" -AOEvidenceDisplay::AOEvidenceDisplay(QWidget *p_parent, AOApplication *p_ao_app) : QLabel(p_parent) +AOEvidenceDisplay::AOEvidenceDisplay(QWidget *p_parent, AOApplication *p_ao_app) + : QLabel(p_parent) { - ao_app = p_ao_app; - evidence_icon = new QLabel(this); - sfx_player = new AOSfxPlayer(this, ao_app); + ao_app = p_ao_app; + evidence_icon = new QLabel(this); + sfx_player = new AOSfxPlayer(this, ao_app); - evidence_movie = new AOMovie(this, ao_app); + evidence_movie = new AOMovie(this, ao_app); - connect(evidence_movie, SIGNAL(done()), this, SLOT(show_done())); + connect(evidence_movie, SIGNAL(done()), this, SLOT(show_done())); } -void AOEvidenceDisplay::show_evidence(QString p_evidence_image, bool is_left_side, int p_volume) +void AOEvidenceDisplay::show_evidence(QString p_evidence_image, + bool is_left_side, int p_volume) { - this->reset(); + this->reset(); - sfx_player->set_volume(p_volume); + sfx_player->set_volume(p_volume); - QString final_gif_path; - QString gif_name; - QString icon_identifier; + QString final_gif_path; + QString gif_name; + QString icon_identifier; - if (is_left_side) { - icon_identifier = "left_evidence_icon"; - gif_name = "evidence_appear_left"; - } - else { - icon_identifier = "right_evidence_icon"; - gif_name = "evidence_appear_right"; - } + if (is_left_side) { + icon_identifier = "left_evidence_icon"; + gif_name = "evidence_appear_left"; + } + else { + icon_identifier = "right_evidence_icon"; + gif_name = "evidence_appear_right"; + } - QString f_evidence_path = ao_app->get_evidence_path(p_evidence_image); - QPixmap f_pixmap(f_evidence_path); + QString f_evidence_path = ao_app->get_evidence_path(p_evidence_image); + QPixmap f_pixmap(f_evidence_path); - pos_size_type icon_dimensions = ao_app->get_element_dimensions(icon_identifier, "courtroom_design.ini"); + pos_size_type icon_dimensions = + ao_app->get_element_dimensions(icon_identifier, "courtroom_design.ini"); - f_pixmap = f_pixmap.scaled(icon_dimensions.width, icon_dimensions.height); - evidence_icon->setPixmap(f_pixmap); - evidence_icon->resize(f_pixmap.size()); - evidence_icon->move(icon_dimensions.x, icon_dimensions.y); + f_pixmap = f_pixmap.scaled(icon_dimensions.width, icon_dimensions.height); + evidence_icon->setPixmap(f_pixmap); + evidence_icon->resize(f_pixmap.size()); + evidence_icon->move(icon_dimensions.x, icon_dimensions.y); - evidence_movie->play(gif_name); - sfx_player->play(ao_app->get_sfx("evidence_present")); + evidence_movie->play(gif_name); + sfx_player->play(ao_app->get_sfx("evidence_present")); } void AOEvidenceDisplay::reset() { - sfx_player->stop(); - evidence_movie->stop(); - evidence_icon->hide(); - this->clear(); + sfx_player->stop(); + evidence_movie->stop(); + evidence_icon->hide(); + this->clear(); } -void AOEvidenceDisplay::show_done() -{ - evidence_icon->show(); -} +void AOEvidenceDisplay::show_done() { evidence_icon->show(); } -QLabel *AOEvidenceDisplay::get_evidence_icon() -{ - return evidence_icon; -} +QLabel *AOEvidenceDisplay::get_evidence_icon() { return evidence_icon; } void AOEvidenceDisplay::combo_resize(int w, int h) { - QSize f_size(w, h); - this->resize(f_size); - evidence_movie->combo_resize(w, h); + QSize f_size(w, h); + this->resize(f_size); + evidence_movie->combo_resize(w, h); } diff --git a/src/aoimage.cpp b/src/aoimage.cpp index e1c01e5..2663ba0 100644 --- a/src/aoimage.cpp +++ b/src/aoimage.cpp @@ -4,46 +4,48 @@ AOImage::AOImage(QWidget *parent, AOApplication *p_ao_app) : QLabel(parent) { - m_parent = parent; - ao_app = p_ao_app; + m_parent = parent; + ao_app = p_ao_app; } -AOImage::~AOImage() -{ -} +AOImage::~AOImage() {} bool AOImage::set_image(QString p_image) { - 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)); + 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)); - QString final_image_path; + 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; - } + 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); + QPixmap f_pixmap(final_image_path); - this->setPixmap(f_pixmap.scaled(this->width(), this->height(), Qt::IgnoreAspectRatio)); - return true; + this->setPixmap( + f_pixmap.scaled(this->width(), this->height(), Qt::IgnoreAspectRatio)); + 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!"; - return false; - } + 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!"; + return false; + } - QPixmap f_pixmap(p_path); + QPixmap f_pixmap(p_path); - this->setPixmap(f_pixmap.scaled(this->width(), this->height(), Qt::IgnoreAspectRatio)); - return true; + this->setPixmap( + f_pixmap.scaled(this->width(), this->height(), Qt::IgnoreAspectRatio)); + return true; } diff --git a/src/aolineedit.cpp b/src/aolineedit.cpp index ce851a0..f98d95f 100644 --- a/src/aolineedit.cpp +++ b/src/aolineedit.cpp @@ -1,20 +1,19 @@ #include "aolineedit.h" -AOLineEdit::AOLineEdit(QWidget *parent) : QLineEdit(parent) -{ -} +AOLineEdit::AOLineEdit(QWidget *parent) : QLineEdit(parent) {} void AOLineEdit::mouseDoubleClickEvent(QMouseEvent *e) { - QLineEdit::mouseDoubleClickEvent(e); + QLineEdit::mouseDoubleClickEvent(e); - double_clicked(); + double_clicked(); } void AOLineEdit::focusOutEvent(QFocusEvent *ev) { - int start = selectionStart(); - int len = selectionEnd() - start; //We're not using selectionLength because Linux build doesn't run qt5.10 - QLineEdit::focusOutEvent(ev); - if (p_selection && start != -1 && len != -1) - this->setSelection(start, len); + int start = selectionStart(); + int len = selectionEnd() - start; // We're not using selectionLength because + // Linux build doesn't run qt5.10 + QLineEdit::focusOutEvent(ev); + if (p_selection && start != -1 && len != -1) + this->setSelection(start, len); } diff --git a/src/aomovie.cpp b/src/aomovie.cpp index 7e3bbae..ac94921 100644 --- a/src/aomovie.cpp +++ b/src/aomovie.cpp @@ -6,88 +6,94 @@ AOMovie::AOMovie(QWidget *p_parent, AOApplication *p_ao_app) : QLabel(p_parent) { - ao_app = p_ao_app; + ao_app = p_ao_app; - m_movie = new QMovie(); + m_movie = new QMovie(); - this->setMovie(m_movie); + this->setMovie(m_movie); - timer = new QTimer(this); - timer->setTimerType(Qt::PreciseTimer); - timer->setSingleShot(true); + timer = new QTimer(this); + timer->setTimerType(Qt::PreciseTimer); + timer->setSingleShot(true); - connect(m_movie, SIGNAL(frameChanged(int)), this, SLOT(frame_change(int))); - connect(timer, SIGNAL(timeout()), this, SLOT(timer_done())); + connect(m_movie, SIGNAL(frameChanged(int)), this, SLOT(frame_change(int))); + connect(timer, SIGNAL(timeout()), this, SLOT(timer_done())); } -void AOMovie::set_play_once(bool p_play_once) +void AOMovie::set_play_once(bool p_play_once) { play_once = p_play_once; } + +void AOMovie::play(QString p_image, QString p_char, QString p_custom_theme, + int duration) { - play_once = p_play_once; -} + m_movie->stop(); -void AOMovie::play(QString p_image, QString p_char, QString p_custom_theme, int duration) -{ - m_movie->stop(); + QString shout_path = p_image; + if (!file_exists(p_image)) { + QList pathlist; - QString shout_path = p_image; - if (!file_exists(p_image)) { - QList pathlist; + pathlist = { + ao_app->get_image_suffix( + ao_app->get_character_path(p_char, p_image)), // Character folder + ao_app->get_image_suffix(ao_app->get_base_path() + "misc/" + + p_custom_theme + "/" + p_image), // Misc path + ao_app->get_image_suffix(ao_app->get_custom_theme_path( + p_custom_theme, p_image)), // Custom theme path + ao_app->get_image_suffix(ao_app->get_theme_path(p_image)), // Theme path + ao_app->get_image_suffix( + ao_app->get_default_theme_path(p_image)), // 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 + }; - pathlist = { - ao_app->get_image_suffix(ao_app->get_character_path(p_char, p_image)), //Character folder - ao_app->get_image_suffix(ao_app->get_base_path() + "misc/" + p_custom_theme + "/" + p_image), //Misc path - ao_app->get_image_suffix(ao_app->get_custom_theme_path(p_custom_theme, p_image)), //Custom theme path - ao_app->get_image_suffix(ao_app->get_theme_path(p_image)), //Theme path - ao_app->get_image_suffix(ao_app->get_default_theme_path(p_image)), //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 - }; - - for (QString path : pathlist) { - if (file_exists(path)) { - shout_path = path; - break; - } - } + for (QString path : pathlist) { + if (file_exists(path)) { + shout_path = path; + break; + } } + } - m_movie->setFileName(shout_path); + m_movie->setFileName(shout_path); - if (m_movie->loopCount() == 0) - play_once = true; + if (m_movie->loopCount() == 0) + play_once = true; - this->show(); - m_movie->start(); - if (m_movie->frameCount() == 0 && duration > 0) - timer->start(duration); + this->show(); + m_movie->start(); + if (m_movie->frameCount() == 0 && duration > 0) + timer->start(duration); } void AOMovie::stop() { - m_movie->stop(); - this->hide(); + m_movie->stop(); + this->hide(); } void AOMovie::frame_change(int n_frame) { - //If it's a "static movie" (only one frame - png image), we can't change frames - ignore this function (use timer instead). - //If the frame didn't reach the last frame or the movie is continuous, don't stop the movie. - if (m_movie->frameCount() == 0 || n_frame < (m_movie->frameCount() - 1) || !play_once) - return; - //we need this or else the last frame wont show - timer->start(m_movie->nextFrameDelay()); + // If it's a "static movie" (only one frame - png image), we can't change + // frames - ignore this function (use timer instead). If the frame didn't reach + // the last frame or the movie is continuous, don't stop the movie. + if (m_movie->frameCount() == 0 || n_frame < (m_movie->frameCount() - 1) || + !play_once) + return; + // we need this or else the last frame wont show + timer->start(m_movie->nextFrameDelay()); } void AOMovie::timer_done() { - this->stop(); - //signal connected to courtroom object, let it figure out what to do - done(); + this->stop(); + // signal connected to courtroom object, let it figure out what to do + done(); } void AOMovie::combo_resize(int w, int h) { - QSize f_size(w, h); - this->resize(f_size); - m_movie->setScaledSize(f_size); + QSize f_size(w, h); + this->resize(f_size); + m_movie->setScaledSize(f_size); } diff --git a/src/aomusicplayer.cpp b/src/aomusicplayer.cpp index 77222e1..bc1ab23 100644 --- a/src/aomusicplayer.cpp +++ b/src/aomusicplayer.cpp @@ -3,200 +3,209 @@ #ifdef BASSAUDIO AOMusicPlayer::AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app) { - m_parent = parent; - ao_app = p_ao_app; + m_parent = parent; + ao_app = p_ao_app; } AOMusicPlayer::~AOMusicPlayer() { - for (int n_stream = 0; n_stream < m_channelmax; ++n_stream) { - BASS_ChannelStop(m_stream_list[n_stream]); - } + for (int n_stream = 0; n_stream < m_channelmax; ++n_stream) { + BASS_ChannelStop(m_stream_list[n_stream]); + } } -void AOMusicPlayer::play(QString p_song, int channel, bool loop, int effect_flags) +void AOMusicPlayer::play(QString p_song, int channel, bool loop, + int effect_flags) { - channel = channel % m_channelmax; - if (channel < 0) //wtf? - return; - QString f_path = ao_app->get_music_path(p_song); + channel = channel % m_channelmax; + if (channel < 0) // wtf? + return; + QString f_path = ao_app->get_music_path(p_song); - unsigned int flags = BASS_STREAM_PRESCAN | BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE; - if (loop) - flags |= BASS_SAMPLE_LOOP; + unsigned int flags = BASS_STREAM_PRESCAN | BASS_STREAM_AUTOFREE | + BASS_UNICODE | BASS_ASYNCFILE; + if (loop) + flags |= BASS_SAMPLE_LOOP; - DWORD newstream; - if (f_path.endsWith(".opus")) - newstream = BASS_OPUS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, flags); - else - newstream = BASS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, flags); + DWORD newstream; + if (f_path.endsWith(".opus")) + newstream = BASS_OPUS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, flags); + else + newstream = BASS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, flags); - if (ao_app->get_audio_output_device() != "default") - BASS_ChannelSetDevice(m_stream_list[channel], BASS_GetDevice()); + if (ao_app->get_audio_output_device() != "default") + BASS_ChannelSetDevice(m_stream_list[channel], BASS_GetDevice()); - QString d_path = f_path + ".txt"; + QString d_path = f_path + ".txt"; - loop_start = 0; - loop_end = BASS_ChannelGetLength(newstream, BASS_POS_BYTE); - if (loop && file_exists(d_path)) //Contains loop/etc. information file - { - QStringList lines = ao_app->read_file(d_path).split("\n"); - foreach (QString line, lines) { - QStringList args = line.split("="); - if (args.size() < 2) - continue; - QString arg = args[0].trimmed(); + loop_start = 0; + loop_end = BASS_ChannelGetLength(newstream, BASS_POS_BYTE); + if (loop && file_exists(d_path)) // Contains loop/etc. information file + { + QStringList lines = ao_app->read_file(d_path).split("\n"); + foreach (QString line, lines) { + QStringList args = line.split("="); + if (args.size() < 2) + continue; + QString arg = args[0].trimmed(); - float sample_rate; - BASS_ChannelGetAttribute(newstream, BASS_ATTRIB_FREQ, &sample_rate); + float sample_rate; + BASS_ChannelGetAttribute(newstream, BASS_ATTRIB_FREQ, &sample_rate); - //Grab number of bytes for sample size - int sample_size = 16 / 8; + // Grab number of bytes for sample size + int sample_size = 16 / 8; - //number of channels (stereo/mono) - int num_channels = 2; + // number of channels (stereo/mono) + int num_channels = 2; - //Calculate the bytes for loop_start/loop_end to use with the sync proc - QWORD bytes = static_cast(args[1].trimmed().toFloat() * sample_size * num_channels); - if (arg == "loop_start") - loop_start = bytes; - else if (arg == "loop_length") - loop_end = loop_start + bytes; - else if (arg == "loop_end") - loop_end = bytes; - } - qDebug() << "Found data file for song" << p_song << "length" << BASS_ChannelGetLength(newstream, BASS_POS_BYTE) << "loop start" << loop_start << "loop end" << loop_end; + // Calculate the bytes for loop_start/loop_end to use with the sync proc + QWORD bytes = static_cast(args[1].trimmed().toFloat() * + sample_size * num_channels); + if (arg == "loop_start") + loop_start = bytes; + else if (arg == "loop_length") + loop_end = loop_start + bytes; + else if (arg == "loop_end") + loop_end = bytes; + } + qDebug() << "Found data file for song" << p_song << "length" + << BASS_ChannelGetLength(newstream, BASS_POS_BYTE) << "loop start" + << loop_start << "loop end" << loop_end; + } + + if (BASS_ChannelIsActive(m_stream_list[channel]) == BASS_ACTIVE_PLAYING) { + DWORD oldstream = m_stream_list[channel]; + + if (effect_flags & SYNC_POS) { + BASS_ChannelLock(oldstream, true); + // Sync it with the new sample + BASS_ChannelSetPosition(newstream, + BASS_ChannelGetPosition(oldstream, BASS_POS_BYTE), + BASS_POS_BYTE); + BASS_ChannelLock(oldstream, false); } - if (BASS_ChannelIsActive(m_stream_list[channel]) == BASS_ACTIVE_PLAYING) { - DWORD oldstream = m_stream_list[channel]; - - if (effect_flags & SYNC_POS) { - BASS_ChannelLock(oldstream, true); - //Sync it with the new sample - BASS_ChannelSetPosition(newstream, BASS_ChannelGetPosition(oldstream, BASS_POS_BYTE), BASS_POS_BYTE); - BASS_ChannelLock(oldstream, false); - } - - if (effect_flags & FADE_OUT) { - //Fade out the other sample and stop it (due to -1) - BASS_ChannelSlideAttribute(oldstream, BASS_ATTRIB_VOL | BASS_SLIDE_LOG, -1, 4000); - } - else - BASS_ChannelStop(oldstream); //Stop the sample since we don't need it anymore + if (effect_flags & FADE_OUT) { + // Fade out the other sample and stop it (due to -1) + BASS_ChannelSlideAttribute(oldstream, BASS_ATTRIB_VOL | BASS_SLIDE_LOG, + -1, 4000); } else - BASS_ChannelStop(m_stream_list[channel]); + BASS_ChannelStop( + oldstream); // Stop the sample since we don't need it anymore + } + else + BASS_ChannelStop(m_stream_list[channel]); - m_stream_list[channel] = newstream; - BASS_ChannelPlay(m_stream_list[channel], false); - if (effect_flags & FADE_IN) { - //Fade in our sample - BASS_ChannelSetAttribute(newstream, BASS_ATTRIB_VOL, 0); - BASS_ChannelSlideAttribute(newstream, BASS_ATTRIB_VOL, static_cast(m_volume[channel] / 100.0f), 1000); - } - else - this->set_volume(m_volume[channel], channel); + m_stream_list[channel] = newstream; + BASS_ChannelPlay(m_stream_list[channel], false); + if (effect_flags & FADE_IN) { + // Fade in our sample + BASS_ChannelSetAttribute(newstream, BASS_ATTRIB_VOL, 0); + BASS_ChannelSlideAttribute(newstream, BASS_ATTRIB_VOL, + static_cast(m_volume[channel] / 100.0f), + 1000); + } + else + this->set_volume(m_volume[channel], channel); - this->set_looping(loop); //Have to do this here due to any crossfading-related changes, etc. + this->set_looping(loop); // Have to do this here due to any + // crossfading-related changes, etc. } void AOMusicPlayer::stop(int channel) { - BASS_ChannelStop(m_stream_list[channel]); + BASS_ChannelStop(m_stream_list[channel]); } void AOMusicPlayer::set_volume(int p_value, int channel) { - m_volume[channel] = p_value; - float volume = m_volume[channel] / 100.0f; - if (channel < 0) { - for (int n_stream = 0; n_stream < m_channelmax; ++n_stream) { - BASS_ChannelSetAttribute(m_stream_list[n_stream], BASS_ATTRIB_VOL, volume); - } - } - else { - BASS_ChannelSetAttribute(m_stream_list[channel], BASS_ATTRIB_VOL, volume); + m_volume[channel] = p_value; + float volume = m_volume[channel] / 100.0f; + if (channel < 0) { + for (int n_stream = 0; n_stream < m_channelmax; ++n_stream) { + BASS_ChannelSetAttribute(m_stream_list[n_stream], BASS_ATTRIB_VOL, + volume); } + } + else { + BASS_ChannelSetAttribute(m_stream_list[channel], BASS_ATTRIB_VOL, volume); + } } void CALLBACK loopProc(HSYNC handle, DWORD channel, DWORD data, void *user) { - QWORD loop_start = *(static_cast(user)); - BASS_ChannelLock(channel, true); - BASS_ChannelSetPosition(channel, loop_start, BASS_POS_BYTE); - BASS_ChannelLock(channel, false); + QWORD loop_start = *(static_cast(user)); + BASS_ChannelLock(channel, true); + BASS_ChannelSetPosition(channel, loop_start, BASS_POS_BYTE); + BASS_ChannelLock(channel, false); } void AOMusicPlayer::set_looping(bool toggle, int channel) { - m_looping = toggle; - if (!m_looping) { - if (BASS_ChannelFlags(m_stream_list[channel], 0, 0) & BASS_SAMPLE_LOOP) - BASS_ChannelFlags(m_stream_list[channel], 0, BASS_SAMPLE_LOOP); // remove the LOOP flag - BASS_ChannelRemoveSync(m_stream_list[channel], loop_sync[channel]); - loop_sync[channel] = 0; + m_looping = toggle; + if (!m_looping) { + if (BASS_ChannelFlags(m_stream_list[channel], 0, 0) & BASS_SAMPLE_LOOP) + BASS_ChannelFlags(m_stream_list[channel], 0, + BASS_SAMPLE_LOOP); // remove the LOOP flag + BASS_ChannelRemoveSync(m_stream_list[channel], loop_sync[channel]); + loop_sync[channel] = 0; + } + else { + BASS_ChannelFlags(m_stream_list[channel], BASS_SAMPLE_LOOP, + BASS_SAMPLE_LOOP); // set the LOOP flag + if (loop_sync[channel] != 0) { + BASS_ChannelRemoveSync(m_stream_list[channel], + loop_sync[channel]); // remove the sync + loop_sync[channel] = 0; } - else { - BASS_ChannelFlags(m_stream_list[channel], BASS_SAMPLE_LOOP, BASS_SAMPLE_LOOP); // set the LOOP flag - if (loop_sync[channel] != 0) { - BASS_ChannelRemoveSync(m_stream_list[channel], loop_sync[channel]); //remove the sync - loop_sync[channel] = 0; - } - if (loop_start > 0) { - if (loop_end == 0) - loop_end = BASS_ChannelGetLength(m_stream_list[channel], BASS_POS_BYTE); - if (loop_end > 0) //Don't loop zero length songs even if we're asked to - loop_sync[channel] = BASS_ChannelSetSync(m_stream_list[channel], BASS_SYNC_POS | BASS_SYNC_MIXTIME, loop_end, loopProc, &loop_start); - } + if (loop_start > 0) { + if (loop_end == 0) + loop_end = BASS_ChannelGetLength(m_stream_list[channel], BASS_POS_BYTE); + if (loop_end > 0) // Don't loop zero length songs even if we're asked to + loop_sync[channel] = BASS_ChannelSetSync( + m_stream_list[channel], BASS_SYNC_POS | BASS_SYNC_MIXTIME, loop_end, + loopProc, &loop_start); } + } } #elif defined(QTAUDIO) AOMusicPlayer::AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app) { - m_parent = parent; - ao_app = p_ao_app; + m_parent = parent; + ao_app = p_ao_app; } -AOMusicPlayer::~AOMusicPlayer() -{ - m_player.stop(); -} +AOMusicPlayer::~AOMusicPlayer() { m_player.stop(); } void AOMusicPlayer::play(QString p_song) { - m_player.stop(); + m_player.stop(); - QString f_path = ao_app->get_music_path(p_song); + QString f_path = ao_app->get_music_path(p_song); - m_player.setMedia(QUrl::fromLocalFile(f_path)); + m_player.setMedia(QUrl::fromLocalFile(f_path)); - this->set_volume(m_volume); + this->set_volume(m_volume); - m_player.play(); + m_player.play(); } void AOMusicPlayer::set_volume(int p_value) { - m_volume = p_value; - m_player.setVolume(m_volume); + m_volume = p_value; + m_player.setVolume(m_volume); } #else AOMusicPlayer::AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app) { - m_parent = parent; - ao_app = p_ao_app; + m_parent = parent; + ao_app = p_ao_app; } -AOMusicPlayer::~AOMusicPlayer() -{ -} +AOMusicPlayer::~AOMusicPlayer() {} -void AOMusicPlayer::play(QString p_song) -{ -} +void AOMusicPlayer::play(QString p_song) {} -void AOMusicPlayer::set_volume(int p_value) -{ -} +void AOMusicPlayer::set_volume(int p_value) {} #endif diff --git a/src/aooptionsdialog.cpp b/src/aooptionsdialog.cpp index 06df7a5..18556f3 100644 --- a/src/aooptionsdialog.cpp +++ b/src/aooptionsdialog.cpp @@ -1,689 +1,755 @@ #include "aooptionsdialog.h" #include "aoapplication.h" -AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDialog(parent) +AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) + : QDialog(parent) { - ao_app = p_ao_app; - - // Setting up the basics. - // setAttribute(Qt::WA_DeleteOnClose); - setWindowTitle(tr("Settings")); - resize(398, 320); - - ui_settings_buttons = new QDialogButtonBox(this); - - QSizePolicy sizePolicy1(QSizePolicy::Minimum, QSizePolicy::MinimumExpanding); - sizePolicy1.setHorizontalStretch(0); - sizePolicy1.setVerticalStretch(0); - sizePolicy1.setHeightForWidth(ui_settings_buttons->sizePolicy().hasHeightForWidth()); - ui_settings_buttons->setSizePolicy(sizePolicy1); - ui_settings_buttons->setOrientation(Qt::Horizontal); - ui_settings_buttons->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Save); - - QObject::connect(ui_settings_buttons, SIGNAL(accepted()), this, SLOT(save_pressed())); - QObject::connect(ui_settings_buttons, SIGNAL(rejected()), this, SLOT(discard_pressed())); - - // We'll stop updates so that the window won't flicker while it's being made. - setUpdatesEnabled(false); - - // First of all, we want a tabbed dialog, so let's add some layout. - ui_vertical_layout = new QVBoxLayout(this); - ui_settings_tabs = new QTabWidget(this); - - ui_vertical_layout->addWidget(ui_settings_tabs); - ui_vertical_layout->addWidget(ui_settings_buttons); - - // Let's add the tabs one by one. - // First, we'll start with 'Gameplay'. - ui_gameplay_tab = new QWidget(); - ui_gameplay_tab->setSizePolicy(sizePolicy1); - ui_settings_tabs->addTab(ui_gameplay_tab, tr("Gameplay")); - ui_form_layout_widget = new QWidget(ui_gameplay_tab); - ui_form_layout_widget->setGeometry(QRect(10, 10, 361, 361)); - ui_form_layout_widget->setSizePolicy(sizePolicy1); + ao_app = p_ao_app; + + // Setting up the basics. + // setAttribute(Qt::WA_DeleteOnClose); + setWindowTitle(tr("Settings")); + resize(398, 320); + + ui_settings_buttons = new QDialogButtonBox(this); + + QSizePolicy sizePolicy1(QSizePolicy::Minimum, QSizePolicy::MinimumExpanding); + sizePolicy1.setHorizontalStretch(0); + sizePolicy1.setVerticalStretch(0); + sizePolicy1.setHeightForWidth( + ui_settings_buttons->sizePolicy().hasHeightForWidth()); + ui_settings_buttons->setSizePolicy(sizePolicy1); + ui_settings_buttons->setOrientation(Qt::Horizontal); + ui_settings_buttons->setStandardButtons(QDialogButtonBox::Cancel | + QDialogButtonBox::Save); + + QObject::connect(ui_settings_buttons, SIGNAL(accepted()), this, + SLOT(save_pressed())); + QObject::connect(ui_settings_buttons, SIGNAL(rejected()), this, + SLOT(discard_pressed())); + + // We'll stop updates so that the window won't flicker while it's being made. + setUpdatesEnabled(false); + + // First of all, we want a tabbed dialog, so let's add some layout. + ui_vertical_layout = new QVBoxLayout(this); + ui_settings_tabs = new QTabWidget(this); + + ui_vertical_layout->addWidget(ui_settings_tabs); + ui_vertical_layout->addWidget(ui_settings_buttons); + + // Let's add the tabs one by one. + // First, we'll start with 'Gameplay'. + ui_gameplay_tab = new QWidget(); + ui_gameplay_tab->setSizePolicy(sizePolicy1); + ui_settings_tabs->addTab(ui_gameplay_tab, tr("Gameplay")); + ui_form_layout_widget = new QWidget(ui_gameplay_tab); + ui_form_layout_widget->setGeometry(QRect(10, 10, 361, 361)); + ui_form_layout_widget->setSizePolicy(sizePolicy1); + + ui_gameplay_form = new QFormLayout(ui_form_layout_widget); + ui_gameplay_form->setLabelAlignment(Qt::AlignLeading | Qt::AlignLeft | + Qt::AlignVCenter); + ui_gameplay_form->setFormAlignment(Qt::AlignLeading | Qt::AlignLeft | + Qt::AlignTop); + ui_gameplay_form->setContentsMargins(0, 0, 0, 0); + ui_gameplay_form->setSpacing(2); + + int row = 0; + + ui_theme_label = new QLabel(ui_form_layout_widget); + ui_theme_label->setText(tr("Theme:")); + ui_theme_label->setToolTip( + tr("Sets the theme used in-game. If the new theme changes " + "the lobby's look as well, you'll need to reload the " + "lobby for the changes to take effect, such as by joining " + "a server and leaving it.")); + ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_theme_label); + ui_theme_combobox = new QComboBox(ui_form_layout_widget); + + // Fill the combobox with the names of the themes. + QDirIterator it(p_ao_app->get_base_path() + "themes", QDir::Dirs, + QDirIterator::NoIteratorFlags); + while (it.hasNext()) { + QString actualname = QDir(it.next()).dirName(); + if (actualname != "." && actualname != "..") + ui_theme_combobox->addItem(actualname); + if (actualname == p_ao_app->read_theme()) + ui_theme_combobox->setCurrentIndex(ui_theme_combobox->count() - 1); + } + + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_theme_combobox); + + row += 1; + ui_theme_log_divider = new QFrame(ui_form_layout_widget); + ui_theme_log_divider->setMidLineWidth(0); + ui_theme_log_divider->setFrameShape(QFrame::HLine); + ui_theme_log_divider->setFrameShadow(QFrame::Sunken); + + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, + ui_theme_log_divider); + + row += 1; + ui_downwards_lbl = new QLabel(ui_form_layout_widget); + ui_downwards_lbl->setText(tr("Log goes downwards:")); + ui_downwards_lbl->setToolTip( + tr("If ticked, new messages will appear at " + "the bottom (like the OOC chatlog). The traditional " + "(AO1) behaviour is equivalent to this being unticked.")); + + ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_downwards_lbl); + + ui_downwards_cb = new QCheckBox(ui_form_layout_widget); + ui_downwards_cb->setChecked(p_ao_app->get_log_goes_downwards()); + + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_downwards_cb); + + row += 1; + ui_length_lbl = new QLabel(ui_form_layout_widget); + ui_length_lbl->setText(tr("Log length:")); + ui_length_lbl->setToolTip(tr( + "The amount of messages the IC chatlog will keep before " + "deleting older messages. A value of 0 or below counts as 'infinite'.")); + + ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_length_lbl); + + ui_length_spinbox = new QSpinBox(ui_form_layout_widget); + ui_length_spinbox->setMaximum(10000); + ui_length_spinbox->setValue(p_ao_app->get_max_log_size()); + + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_length_spinbox); + + row += 1; + ui_log_names_divider = new QFrame(ui_form_layout_widget); + ui_log_names_divider->setFrameShape(QFrame::HLine); + ui_log_names_divider->setFrameShadow(QFrame::Sunken); + + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, + ui_log_names_divider); + + row += 1; + ui_username_lbl = new QLabel(ui_form_layout_widget); + ui_username_lbl->setText(tr("Default username:")); + ui_username_lbl->setToolTip( + tr("Your OOC name will be automatically set to this value " + "when you join a server.")); + + ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_username_lbl); + + ui_username_textbox = new QLineEdit(ui_form_layout_widget); + ui_username_textbox->setMaxLength(30); + ui_username_textbox->setText(p_ao_app->get_default_username()); + + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_username_textbox); + + row += 1; + ui_showname_lbl = new QLabel(ui_form_layout_widget); + ui_showname_lbl->setText(tr("Custom shownames:")); + ui_showname_lbl->setToolTip( + tr("Gives the default value for the in-game 'Custom shownames' " + "tickbox, which in turn determines whether the client should " + "display custom in-character names.")); + + ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_showname_lbl); + + ui_showname_cb = new QCheckBox(ui_form_layout_widget); + ui_showname_cb->setChecked(p_ao_app->get_showname_enabled_by_default()); + + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_showname_cb); + + row += 1; + ui_net_divider = new QFrame(ui_form_layout_widget); + ui_net_divider->setFrameShape(QFrame::HLine); + ui_net_divider->setFrameShadow(QFrame::Sunken); + + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_net_divider); + + row += 1; + ui_ms_lbl = new QLabel(ui_form_layout_widget); + ui_ms_lbl->setText(tr("Backup MS:")); + ui_ms_lbl->setToolTip( + tr("If the built-in server lookups fail, the game will try the " + "address given here and use it as a backup master server address.")); - ui_gameplay_form = new QFormLayout(ui_form_layout_widget); - ui_gameplay_form->setLabelAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignVCenter); - ui_gameplay_form->setFormAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignTop); - ui_gameplay_form->setContentsMargins(0, 0, 0, 0); - ui_gameplay_form->setSpacing(2); - - int row = 0; + ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_ms_lbl); - ui_theme_label = new QLabel(ui_form_layout_widget); - ui_theme_label->setText(tr("Theme:")); - ui_theme_label->setToolTip(tr("Sets the theme used in-game. If the new theme changes " - "the lobby's look as well, you'll need to reload the " - "lobby for the changes to take effect, such as by joining " - "a server and leaving it.")); - ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_theme_label); - ui_theme_combobox = new QComboBox(ui_form_layout_widget); - - // Fill the combobox with the names of the themes. - QDirIterator it(p_ao_app->get_base_path() + "themes", QDir::Dirs, QDirIterator::NoIteratorFlags); - while (it.hasNext()) { - QString actualname = QDir(it.next()).dirName(); - if (actualname != "." && actualname != "..") - ui_theme_combobox->addItem(actualname); - if (actualname == p_ao_app->read_theme()) - ui_theme_combobox->setCurrentIndex(ui_theme_combobox->count() - 1); - } - - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_theme_combobox); - - row += 1; - ui_theme_log_divider = new QFrame(ui_form_layout_widget); - ui_theme_log_divider->setMidLineWidth(0); - ui_theme_log_divider->setFrameShape(QFrame::HLine); - ui_theme_log_divider->setFrameShadow(QFrame::Sunken); + QSettings *configini = ao_app->configini; + ui_ms_textbox = new QLineEdit(ui_form_layout_widget); + ui_ms_textbox->setText(configini->value("master", "").value()); - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_theme_log_divider); + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_ms_textbox); - row += 1; - ui_downwards_lbl = new QLabel(ui_form_layout_widget); - ui_downwards_lbl->setText(tr("Log goes downwards:")); - ui_downwards_lbl->setToolTip(tr("If ticked, new messages will appear at " - "the bottom (like the OOC chatlog). The traditional " - "(AO1) behaviour is equivalent to this being unticked.")); + row += 1; + ui_discord_lbl = new QLabel(ui_form_layout_widget); + ui_discord_lbl->setText(tr("Discord:")); + ui_discord_lbl->setToolTip( + tr("Allows others on Discord to see what server you are in, " + "what character are you playing, and how long you have " + "been playing for.")); - ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_downwards_lbl); - - ui_downwards_cb = new QCheckBox(ui_form_layout_widget); - ui_downwards_cb->setChecked(p_ao_app->get_log_goes_downwards()); - - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_downwards_cb); - - row += 1; - ui_length_lbl = new QLabel(ui_form_layout_widget); - ui_length_lbl->setText(tr("Log length:")); - ui_length_lbl->setToolTip(tr("The amount of messages the IC chatlog will keep before " - "deleting older messages. A value of 0 or below counts as 'infinite'.")); - - ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_length_lbl); - - ui_length_spinbox = new QSpinBox(ui_form_layout_widget); - ui_length_spinbox->setMaximum(10000); - ui_length_spinbox->setValue(p_ao_app->get_max_log_size()); + ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_discord_lbl); - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_length_spinbox); - - row += 1; - ui_log_names_divider = new QFrame(ui_form_layout_widget); - ui_log_names_divider->setFrameShape(QFrame::HLine); - ui_log_names_divider->setFrameShadow(QFrame::Sunken); + ui_discord_cb = new QCheckBox(ui_form_layout_widget); + ui_discord_cb->setChecked(ao_app->is_discord_enabled()); - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_log_names_divider); - - row += 1; - ui_username_lbl = new QLabel(ui_form_layout_widget); - ui_username_lbl->setText(tr("Default username:")); - ui_username_lbl->setToolTip(tr("Your OOC name will be automatically set to this value " - "when you join a server.")); + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_discord_cb); - ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_username_lbl); + row += 1; + ui_language_label = new QLabel(ui_form_layout_widget); + ui_language_label->setText(tr("Language:")); + ui_language_label->setToolTip( + tr("Sets the language if you don't want to use your system language.")); + ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_language_label); - ui_username_textbox = new QLineEdit(ui_form_layout_widget); - ui_username_textbox->setMaxLength(30); - ui_username_textbox->setText(p_ao_app->get_default_username()); + ui_language_combobox = new QComboBox(ui_form_layout_widget); + ui_language_combobox->addItem( + configini->value("language", " ").value() + + " - Keep current setting"); + ui_language_combobox->addItem(" - Default"); + ui_language_combobox->addItem("en - English"); + ui_language_combobox->addItem("de - Deutsch"); + ui_language_combobox->addItem("es - Español"); + ui_language_combobox->addItem("jp - 日本語"); + ui_language_combobox->addItem("ru - Русский"); + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, + ui_language_combobox); - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_username_textbox); + row += 1; + ui_shake_lbl = new QLabel(ui_form_layout_widget); + ui_shake_lbl->setText(tr("Allow Screenshake:")); + ui_shake_lbl->setToolTip( + tr("Allows screenshaking. Disable this if you have concerns or issues " + "with photosensitivity and/or seizures.")); - row += 1; - ui_showname_lbl = new QLabel(ui_form_layout_widget); - ui_showname_lbl->setText(tr("Custom shownames:")); - ui_showname_lbl->setToolTip(tr("Gives the default value for the in-game 'Custom shownames' " - "tickbox, which in turn determines whether the client should " - "display custom in-character names.")); + ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_shake_lbl); - ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_showname_lbl); + ui_shake_cb = new QCheckBox(ui_form_layout_widget); + ui_shake_cb->setChecked(ao_app->is_shake_enabled()); - ui_showname_cb = new QCheckBox(ui_form_layout_widget); - ui_showname_cb->setChecked(p_ao_app->get_showname_enabled_by_default()); + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_shake_cb); - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_showname_cb); + row += 1; + ui_effects_lbl = new QLabel(ui_form_layout_widget); + ui_effects_lbl->setText(tr("Allow Effects:")); + ui_effects_lbl->setToolTip( + tr("Allows screen effects. Disable this if you have concerns or issues " + "with photosensitivity and/or seizures.")); - row += 1; - ui_net_divider = new QFrame(ui_form_layout_widget); - ui_net_divider->setFrameShape(QFrame::HLine); - ui_net_divider->setFrameShadow(QFrame::Sunken); + ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_effects_lbl); - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_net_divider); + ui_effects_cb = new QCheckBox(ui_form_layout_widget); + ui_effects_cb->setChecked(ao_app->is_effects_enabled()); - row += 1; - ui_ms_lbl = new QLabel(ui_form_layout_widget); - ui_ms_lbl->setText(tr("Backup MS:")); - ui_ms_lbl->setToolTip(tr("If the built-in server lookups fail, the game will try the " - "address given here and use it as a backup master server address.")); + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_effects_cb); - ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_ms_lbl); + row += 1; + ui_framenetwork_lbl = new QLabel(ui_form_layout_widget); + ui_framenetwork_lbl->setText(tr("Network Frame Effects:")); + ui_framenetwork_lbl->setToolTip(tr( + "Send screen-shaking, flashes and sounds as defined in the char.ini over " + "the network. Only works for servers that support this functionality.")); - QSettings *configini = ao_app->configini; - ui_ms_textbox = new QLineEdit(ui_form_layout_widget); - ui_ms_textbox->setText(configini->value("master", "").value()); + ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_framenetwork_lbl); - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_ms_textbox); + ui_framenetwork_cb = new QCheckBox(ui_form_layout_widget); + ui_framenetwork_cb->setChecked(ao_app->is_frame_network_enabled()); - row += 1; - ui_discord_lbl = new QLabel(ui_form_layout_widget); - ui_discord_lbl->setText(tr("Discord:")); - ui_discord_lbl->setToolTip(tr("Allows others on Discord to see what server you are in, " - "what character are you playing, and how long you have " - "been playing for.")); + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_framenetwork_cb); - ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_discord_lbl); + row += 1; + ui_colorlog_lbl = new QLabel(ui_form_layout_widget); + ui_colorlog_lbl->setText(tr("Colors in IC Log:")); + ui_colorlog_lbl->setToolTip( + tr("Use the markup colors in the server IC chatlog.")); - ui_discord_cb = new QCheckBox(ui_form_layout_widget); - ui_discord_cb->setChecked(ao_app->is_discord_enabled()); + ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_colorlog_lbl); - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_discord_cb); + ui_colorlog_cb = new QCheckBox(ui_form_layout_widget); + ui_colorlog_cb->setChecked(ao_app->is_colorlog_enabled()); + + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_colorlog_cb); + + row += 1; + ui_stickysounds_lbl = new QLabel(ui_form_layout_widget); + ui_stickysounds_lbl->setText(tr("Sticky Sounds:")); + ui_stickysounds_lbl->setToolTip( + tr("Turn this on to prevent the sound dropdown from clearing the sound " + "after playing it.")); - row += 1; - ui_language_label = new QLabel(ui_form_layout_widget); - ui_language_label->setText(tr("Language:")); - ui_language_label->setToolTip(tr("Sets the language if you don't want to use your system language.")); - ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_language_label); + ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_stickysounds_lbl); - ui_language_combobox = new QComboBox(ui_form_layout_widget); - ui_language_combobox->addItem(configini->value("language", " ").value() + " - Keep current setting"); - ui_language_combobox->addItem(" - Default"); - ui_language_combobox->addItem("en - English"); - ui_language_combobox->addItem("de - Deutsch"); - ui_language_combobox->addItem("es - Español"); - ui_language_combobox->addItem("jp - 日本語"); - ui_language_combobox->addItem("ru - Русский"); - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_language_combobox); + ui_stickysounds_cb = new QCheckBox(ui_form_layout_widget); + ui_stickysounds_cb->setChecked(ao_app->is_stickysounds_enabled()); + + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_stickysounds_cb); - row += 1; - ui_shake_lbl = new QLabel(ui_form_layout_widget); - ui_shake_lbl->setText(tr("Allow Screenshake:")); - ui_shake_lbl->setToolTip(tr("Allows screenshaking. Disable this if you have concerns or issues with photosensitivity and/or seizures.")); + row += 1; + ui_stickyeffects_lbl = new QLabel(ui_form_layout_widget); + ui_stickyeffects_lbl->setText(tr("Sticky Effects:")); + ui_stickyeffects_lbl->setToolTip( + tr("Turn this on to prevent the effects dropdown from clearing the " + "effect after playing it.")); + + ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, + ui_stickyeffects_lbl); + + ui_stickyeffects_cb = new QCheckBox(ui_form_layout_widget); + ui_stickyeffects_cb->setChecked(ao_app->is_stickyeffects_enabled()); + + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_stickyeffects_cb); + + row += 1; + ui_stickypres_lbl = new QLabel(ui_form_layout_widget); + ui_stickypres_lbl->setText(tr("Sticky Preanims:")); + ui_stickypres_lbl->setToolTip( + tr("Turn this on to prevent preanimation checkbox from clearing after " + "playing the emote.")); - ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_shake_lbl); + ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_stickypres_lbl); - ui_shake_cb = new QCheckBox(ui_form_layout_widget); - ui_shake_cb->setChecked(ao_app->is_shake_enabled()); + ui_stickypres_cb = new QCheckBox(ui_form_layout_widget); + ui_stickypres_cb->setChecked(ao_app->is_stickypres_enabled()); - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_shake_cb); + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_stickypres_cb); - row += 1; - ui_effects_lbl = new QLabel(ui_form_layout_widget); - ui_effects_lbl->setText(tr("Allow Effects:")); - ui_effects_lbl->setToolTip(tr("Allows screen effects. Disable this if you have concerns or issues with photosensitivity and/or seizures.")); + QScrollArea *scroll = new QScrollArea; + scroll->setWidget(ui_form_layout_widget); + ui_gameplay_tab->setLayout(new QVBoxLayout); + ui_gameplay_tab->layout()->addWidget(scroll); + ui_gameplay_tab->show(); - ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_effects_lbl); + // Here we start the callwords tab. + ui_callwords_tab = new QWidget(); + ui_settings_tabs->addTab(ui_callwords_tab, tr("Callwords")); - ui_effects_cb = new QCheckBox(ui_form_layout_widget); - ui_effects_cb->setChecked(ao_app->is_effects_enabled()); + ui_callwords_widget = new QWidget(ui_callwords_tab); + ui_callwords_widget->setGeometry(QRect(10, 10, 361, 211)); - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_effects_cb); + ui_callwords_layout = new QVBoxLayout(ui_callwords_widget); + ui_callwords_layout->setContentsMargins(0, 0, 0, 0); - row += 1; - ui_framenetwork_lbl = new QLabel(ui_form_layout_widget); - ui_framenetwork_lbl->setText(tr("Network Frame Effects:")); - ui_framenetwork_lbl->setToolTip(tr("Send screen-shaking, flashes and sounds as defined in the char.ini over the network. Only works for servers that support this functionality.")); + ui_callwords_textbox = new QPlainTextEdit(ui_callwords_widget); + QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + sizePolicy.setHorizontalStretch(0); + sizePolicy.setVerticalStretch(0); + sizePolicy.setHeightForWidth( + ui_callwords_textbox->sizePolicy().hasHeightForWidth()); + ui_callwords_textbox->setSizePolicy(sizePolicy); - ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_framenetwork_lbl); + // Let's fill the callwords text edit with the already present callwords. + ui_callwords_textbox->document()->clear(); + foreach (QString callword, p_ao_app->get_call_words()) { + ui_callwords_textbox->appendPlainText(callword); + } - ui_framenetwork_cb = new QCheckBox(ui_form_layout_widget); - ui_framenetwork_cb->setChecked(ao_app->is_frame_network_enabled()); + ui_callwords_layout->addWidget(ui_callwords_textbox); - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_framenetwork_cb); + ui_callwords_explain_lbl = new QLabel(ui_callwords_widget); + ui_callwords_explain_lbl->setWordWrap(true); + ui_callwords_explain_lbl->setText( + tr("Enter as many callwords as you would like. These " + "are case insensitive. Make sure to leave every callword in its own " + "line!
Do not leave a line with a space at the end -- you will be " + "alerted everytime someone uses a space in their " + "messages.")); - row += 1; - ui_colorlog_lbl = new QLabel(ui_form_layout_widget); - ui_colorlog_lbl->setText(tr("Colors in IC Log:")); - ui_colorlog_lbl->setToolTip(tr("Use the markup colors in the server IC chatlog.")); + ui_callwords_layout->addWidget(ui_callwords_explain_lbl); - ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_colorlog_lbl); + // The audio tab. + ui_audio_tab = new QWidget(); + ui_settings_tabs->addTab(ui_audio_tab, tr("Audio")); - ui_colorlog_cb = new QCheckBox(ui_form_layout_widget); - ui_colorlog_cb->setChecked(ao_app->is_colorlog_enabled()); + ui_audio_widget = new QWidget(ui_audio_tab); + ui_audio_widget->setGeometry(QRect(10, 10, 361, 211)); - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_colorlog_cb); + ui_audio_layout = new QFormLayout(ui_audio_widget); + ui_audio_layout->setLabelAlignment(Qt::AlignLeading | Qt::AlignLeft | + Qt::AlignVCenter); + ui_audio_layout->setFormAlignment(Qt::AlignLeading | Qt::AlignLeft | + Qt::AlignTop); + ui_audio_layout->setContentsMargins(0, 0, 0, 0); + row = 0; + + ui_audio_device_lbl = new QLabel(ui_audio_widget); + ui_audio_device_lbl->setText(tr("Audio device:")); + ui_audio_device_lbl->setToolTip(tr("Sets the audio device for all sounds.")); - row += 1; - ui_stickysounds_lbl = new QLabel(ui_form_layout_widget); - ui_stickysounds_lbl->setText(tr("Sticky Sounds:")); - ui_stickysounds_lbl->setToolTip(tr("Turn this on to prevent the sound dropdown from clearing the sound after playing it.")); + ui_audio_layout->setWidget(row, QFormLayout::LabelRole, ui_audio_device_lbl); - ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_stickysounds_lbl); + ui_audio_device_combobox = new QComboBox(ui_audio_widget); - ui_stickysounds_cb = new QCheckBox(ui_form_layout_widget); - ui_stickysounds_cb->setChecked(ao_app->is_stickysounds_enabled()); + // Let's fill out the combobox with the available audio devices. Or don't if + // there is no audio + int a = 0; + if (needs_default_audiodev()) { - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_stickysounds_cb); - - row += 1; - ui_stickyeffects_lbl = new QLabel(ui_form_layout_widget); - ui_stickyeffects_lbl->setText(tr("Sticky Effects:")); - ui_stickyeffects_lbl->setToolTip(tr("Turn this on to prevent the effects dropdown from clearing the effect after playing it.")); - - ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_stickyeffects_lbl); - - ui_stickyeffects_cb = new QCheckBox(ui_form_layout_widget); - ui_stickyeffects_cb->setChecked(ao_app->is_stickyeffects_enabled()); - - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_stickyeffects_cb); - - row += 1; - ui_stickypres_lbl = new QLabel(ui_form_layout_widget); - ui_stickypres_lbl->setText(tr("Sticky Preanims:")); - ui_stickypres_lbl->setToolTip(tr("Turn this on to prevent preanimation checkbox from clearing after playing the emote.")); - - ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_stickypres_lbl); - - ui_stickypres_cb = new QCheckBox(ui_form_layout_widget); - ui_stickypres_cb->setChecked(ao_app->is_stickypres_enabled()); - - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_stickypres_cb); - - QScrollArea *scroll = new QScrollArea; - scroll->setWidget(ui_form_layout_widget); - ui_gameplay_tab->setLayout(new QVBoxLayout); - ui_gameplay_tab->layout()->addWidget(scroll); - ui_gameplay_tab->show(); - - // Here we start the callwords tab. - ui_callwords_tab = new QWidget(); - ui_settings_tabs->addTab(ui_callwords_tab, tr("Callwords")); - - ui_callwords_widget = new QWidget(ui_callwords_tab); - ui_callwords_widget->setGeometry(QRect(10, 10, 361, 211)); - - ui_callwords_layout = new QVBoxLayout(ui_callwords_widget); - ui_callwords_layout->setContentsMargins(0, 0, 0, 0); - - ui_callwords_textbox = new QPlainTextEdit(ui_callwords_widget); - QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - sizePolicy.setHorizontalStretch(0); - sizePolicy.setVerticalStretch(0); - sizePolicy.setHeightForWidth(ui_callwords_textbox->sizePolicy().hasHeightForWidth()); - ui_callwords_textbox->setSizePolicy(sizePolicy); - - // Let's fill the callwords text edit with the already present callwords. - ui_callwords_textbox->document()->clear(); - foreach (QString callword, p_ao_app->get_call_words()) { - ui_callwords_textbox->appendPlainText(callword); - } - - ui_callwords_layout->addWidget(ui_callwords_textbox); - - ui_callwords_explain_lbl = new QLabel(ui_callwords_widget); - ui_callwords_explain_lbl->setWordWrap(true); - ui_callwords_explain_lbl->setText(tr("Enter as many callwords as you would like. These are case insensitive. Make sure to leave every callword in its own line!
Do not leave a line with a space at the end -- you will be alerted everytime someone uses a space in their messages.")); - - ui_callwords_layout->addWidget(ui_callwords_explain_lbl); - - // The audio tab. - ui_audio_tab = new QWidget(); - ui_settings_tabs->addTab(ui_audio_tab, tr("Audio")); - - ui_audio_widget = new QWidget(ui_audio_tab); - ui_audio_widget->setGeometry(QRect(10, 10, 361, 211)); - - ui_audio_layout = new QFormLayout(ui_audio_widget); - ui_audio_layout->setLabelAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignVCenter); - ui_audio_layout->setFormAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignTop); - ui_audio_layout->setContentsMargins(0, 0, 0, 0); - row = 0; - - ui_audio_device_lbl = new QLabel(ui_audio_widget); - ui_audio_device_lbl->setText(tr("Audio device:")); - ui_audio_device_lbl->setToolTip(tr("Sets the audio device for all sounds.")); - - ui_audio_layout->setWidget(row, QFormLayout::LabelRole, ui_audio_device_lbl); - - ui_audio_device_combobox = new QComboBox(ui_audio_widget); - - // Let's fill out the combobox with the available audio devices. Or don't if there is no audio - int a = 0; - if (needs_default_audiodev()) { - - ui_audio_device_combobox->addItem("default"); - } + ui_audio_device_combobox->addItem("default"); + } #ifdef BASSAUDIO - BASS_DEVICEINFO info; - for (a = 0; BASS_GetDeviceInfo(a, &info); a++) { - ui_audio_device_combobox->addItem(info.name); - if (p_ao_app->get_audio_output_device() == info.name) - ui_audio_device_combobox->setCurrentIndex(ui_audio_device_combobox->count() - 1); - } + BASS_DEVICEINFO info; + for (a = 0; BASS_GetDeviceInfo(a, &info); a++) { + ui_audio_device_combobox->addItem(info.name); + if (p_ao_app->get_audio_output_device() == info.name) + ui_audio_device_combobox->setCurrentIndex( + ui_audio_device_combobox->count() - 1); + } #elif defined QTAUDIO - foreach (const QAudioDeviceInfo &deviceInfo, QAudioDeviceInfo::availableDevices(QAudio::AudioOutput)) { - ui_audio_device_combobox->addItem(deviceInfo.deviceName()); - if (p_ao_app->get_audio_output_device() == deviceInfo.deviceName()) - ui_audio_device_combobox->setCurrentIndex(ui_audio_device_combobox->count() - 1); - } + foreach (const QAudioDeviceInfo &deviceInfo, + QAudioDeviceInfo::availableDevices(QAudio::AudioOutput)) { + ui_audio_device_combobox->addItem(deviceInfo.deviceName()); + if (p_ao_app->get_audio_output_device() == deviceInfo.deviceName()) + ui_audio_device_combobox->setCurrentIndex( + ui_audio_device_combobox->count() - 1); + } #endif - ui_audio_layout->setWidget(row, QFormLayout::FieldRole, ui_audio_device_combobox); + ui_audio_layout->setWidget(row, QFormLayout::FieldRole, + ui_audio_device_combobox); - row += 1; - ui_audio_volume_divider = new QFrame(ui_audio_widget); - ui_audio_volume_divider->setFrameShape(QFrame::HLine); - ui_audio_volume_divider->setFrameShadow(QFrame::Sunken); + row += 1; + ui_audio_volume_divider = new QFrame(ui_audio_widget); + ui_audio_volume_divider->setFrameShape(QFrame::HLine); + ui_audio_volume_divider->setFrameShadow(QFrame::Sunken); - ui_audio_layout->setWidget(row, QFormLayout::FieldRole, ui_audio_volume_divider); + ui_audio_layout->setWidget(row, QFormLayout::FieldRole, + ui_audio_volume_divider); - row += 1; - ui_music_volume_lbl = new QLabel(ui_audio_widget); - ui_music_volume_lbl->setText(tr("Music:")); - ui_music_volume_lbl->setToolTip(tr("Sets the music's default volume.")); + row += 1; + ui_music_volume_lbl = new QLabel(ui_audio_widget); + ui_music_volume_lbl->setText(tr("Music:")); + ui_music_volume_lbl->setToolTip(tr("Sets the music's default volume.")); + + ui_audio_layout->setWidget(row, QFormLayout::LabelRole, ui_music_volume_lbl); - ui_audio_layout->setWidget(row, QFormLayout::LabelRole, ui_music_volume_lbl); + ui_music_volume_spinbox = new QSpinBox(ui_audio_widget); + ui_music_volume_spinbox->setValue(p_ao_app->get_default_music()); + ui_music_volume_spinbox->setMaximum(100); + ui_music_volume_spinbox->setSuffix("%"); - ui_music_volume_spinbox = new QSpinBox(ui_audio_widget); - ui_music_volume_spinbox->setValue(p_ao_app->get_default_music()); - ui_music_volume_spinbox->setMaximum(100); - ui_music_volume_spinbox->setSuffix("%"); + ui_audio_layout->setWidget(row, QFormLayout::FieldRole, + ui_music_volume_spinbox); - ui_audio_layout->setWidget(row, QFormLayout::FieldRole, ui_music_volume_spinbox); + row += 1; + ui_sfx_volume_lbl = new QLabel(ui_audio_widget); + ui_sfx_volume_lbl->setText(tr("SFX:")); + ui_sfx_volume_lbl->setToolTip( + tr("Sets the SFX's default volume. " + "Interjections and actual sound effects count as 'SFX'.")); + ui_audio_layout->setWidget(row, QFormLayout::LabelRole, ui_sfx_volume_lbl); - row += 1; - ui_sfx_volume_lbl = new QLabel(ui_audio_widget); - ui_sfx_volume_lbl->setText(tr("SFX:")); - ui_sfx_volume_lbl->setToolTip(tr("Sets the SFX's default volume. " - "Interjections and actual sound effects count as 'SFX'.")); - ui_audio_layout->setWidget(row, QFormLayout::LabelRole, ui_sfx_volume_lbl); + ui_sfx_volume_spinbox = new QSpinBox(ui_audio_widget); + ui_sfx_volume_spinbox->setValue(p_ao_app->get_default_sfx()); + ui_sfx_volume_spinbox->setMaximum(100); + ui_sfx_volume_spinbox->setSuffix("%"); - ui_sfx_volume_spinbox = new QSpinBox(ui_audio_widget); - ui_sfx_volume_spinbox->setValue(p_ao_app->get_default_sfx()); - ui_sfx_volume_spinbox->setMaximum(100); - ui_sfx_volume_spinbox->setSuffix("%"); + ui_audio_layout->setWidget(row, QFormLayout::FieldRole, + ui_sfx_volume_spinbox); - ui_audio_layout->setWidget(row, QFormLayout::FieldRole, ui_sfx_volume_spinbox); + row += 1; + ui_blips_volume_lbl = new QLabel(ui_audio_widget); + ui_blips_volume_lbl->setText(tr("Blips:")); + ui_blips_volume_lbl->setToolTip( + tr("Sets the volume of the blips, the talking sound effects.")); + + ui_audio_layout->setWidget(row, QFormLayout::LabelRole, ui_blips_volume_lbl); - row += 1; - ui_blips_volume_lbl = new QLabel(ui_audio_widget); - ui_blips_volume_lbl->setText(tr("Blips:")); - ui_blips_volume_lbl->setToolTip(tr("Sets the volume of the blips, the talking sound effects.")); + ui_blips_volume_spinbox = new QSpinBox(ui_audio_widget); + ui_blips_volume_spinbox->setValue(p_ao_app->get_default_blip()); + ui_blips_volume_spinbox->setMaximum(100); + ui_blips_volume_spinbox->setSuffix("%"); - ui_audio_layout->setWidget(row, QFormLayout::LabelRole, ui_blips_volume_lbl); + ui_audio_layout->setWidget(row, QFormLayout::FieldRole, + ui_blips_volume_spinbox); - ui_blips_volume_spinbox = new QSpinBox(ui_audio_widget); - ui_blips_volume_spinbox->setValue(p_ao_app->get_default_blip()); - ui_blips_volume_spinbox->setMaximum(100); - ui_blips_volume_spinbox->setSuffix("%"); + row += 1; + ui_volume_blip_divider = new QFrame(ui_audio_widget); + ui_volume_blip_divider->setFrameShape(QFrame::HLine); + ui_volume_blip_divider->setFrameShadow(QFrame::Sunken); - ui_audio_layout->setWidget(row, QFormLayout::FieldRole, ui_blips_volume_spinbox); + ui_audio_layout->setWidget(row, QFormLayout::FieldRole, + ui_volume_blip_divider); - row += 1; - ui_volume_blip_divider = new QFrame(ui_audio_widget); - ui_volume_blip_divider->setFrameShape(QFrame::HLine); - ui_volume_blip_divider->setFrameShadow(QFrame::Sunken); + row += 1; + ui_bliprate_lbl = new QLabel(ui_audio_widget); + ui_bliprate_lbl->setText(tr("Blip rate:")); + ui_bliprate_lbl->setToolTip( + tr("Sets the delay between playing the blip sounds.")); - ui_audio_layout->setWidget(row, QFormLayout::FieldRole, ui_volume_blip_divider); + ui_audio_layout->setWidget(row, QFormLayout::LabelRole, ui_bliprate_lbl); - row += 1; - ui_bliprate_lbl = new QLabel(ui_audio_widget); - ui_bliprate_lbl->setText(tr("Blip rate:")); - ui_bliprate_lbl->setToolTip(tr("Sets the delay between playing the blip sounds.")); + ui_bliprate_spinbox = new QSpinBox(ui_audio_widget); + ui_bliprate_spinbox->setValue(p_ao_app->read_blip_rate()); + ui_bliprate_spinbox->setMinimum(1); + ui_bliprate_spinbox->setToolTip( + tr("Play a blip sound \"once per every X symbols\", where " + "X is the blip rate.")); - ui_audio_layout->setWidget(row, QFormLayout::LabelRole, ui_bliprate_lbl); + ui_audio_layout->setWidget(row, QFormLayout::FieldRole, ui_bliprate_spinbox); - ui_bliprate_spinbox = new QSpinBox(ui_audio_widget); - ui_bliprate_spinbox->setValue(p_ao_app->read_blip_rate()); - ui_bliprate_spinbox->setMinimum(1); - ui_bliprate_spinbox->setToolTip(tr("Play a blip sound \"once per every X symbols\", where " - "X is the blip rate.")); + row += 1; + ui_blank_blips_lbl = new QLabel(ui_audio_widget); + ui_blank_blips_lbl->setText(tr("Blank blips:")); + ui_blank_blips_lbl->setToolTip( + tr("If true, the game will play a blip sound even " + "when a space is 'being said'.")); - ui_audio_layout->setWidget(row, QFormLayout::FieldRole, ui_bliprate_spinbox); + ui_audio_layout->setWidget(row, QFormLayout::LabelRole, ui_blank_blips_lbl); - row += 1; - ui_blank_blips_lbl = new QLabel(ui_audio_widget); - ui_blank_blips_lbl->setText(tr("Blank blips:")); - ui_blank_blips_lbl->setToolTip(tr("If true, the game will play a blip sound even " - "when a space is 'being said'.")); + ui_blank_blips_cb = new QCheckBox(ui_audio_widget); + ui_blank_blips_cb->setChecked(p_ao_app->get_blank_blip()); - ui_audio_layout->setWidget(row, QFormLayout::LabelRole, ui_blank_blips_lbl); + ui_audio_layout->setWidget(row, QFormLayout::FieldRole, ui_blank_blips_cb); - ui_blank_blips_cb = new QCheckBox(ui_audio_widget); - ui_blank_blips_cb->setChecked(p_ao_app->get_blank_blip()); + row += 1; + ui_loopsfx_lbl = new QLabel(ui_audio_widget); + ui_loopsfx_lbl->setText(tr("Enable Looping SFX:")); + ui_loopsfx_lbl->setToolTip(tr("If true, the game will allow looping sound " + "effects to play on preanimations.")); - ui_audio_layout->setWidget(row, QFormLayout::FieldRole, ui_blank_blips_cb); + ui_audio_layout->setWidget(row, QFormLayout::LabelRole, ui_loopsfx_lbl); - row += 1; - ui_loopsfx_lbl = new QLabel(ui_audio_widget); - ui_loopsfx_lbl->setText(tr("Enable Looping SFX:")); - ui_loopsfx_lbl->setToolTip(tr("If true, the game will allow looping sound effects to play on preanimations.")); + ui_loopsfx_cb = new QCheckBox(ui_audio_widget); + ui_loopsfx_cb->setChecked(p_ao_app->get_looping_sfx()); - ui_audio_layout->setWidget(row, QFormLayout::LabelRole, ui_loopsfx_lbl); + ui_audio_layout->setWidget(row, QFormLayout::FieldRole, ui_loopsfx_cb); - ui_loopsfx_cb = new QCheckBox(ui_audio_widget); - ui_loopsfx_cb->setChecked(p_ao_app->get_looping_sfx()); + row += 1; + ui_objectmusic_lbl = new QLabel(ui_audio_widget); + ui_objectmusic_lbl->setText(tr("Kill Music On Objection:")); + ui_objectmusic_lbl->setToolTip( + tr("If true, AO2 will stop the music for you when you or someone else " + "does 'Objection!'.")); - ui_audio_layout->setWidget(row, QFormLayout::FieldRole, ui_loopsfx_cb); + ui_audio_layout->setWidget(row, QFormLayout::LabelRole, ui_objectmusic_lbl); - row += 1; - ui_objectmusic_lbl = new QLabel(ui_audio_widget); - ui_objectmusic_lbl->setText(tr("Kill Music On Objection:")); - ui_objectmusic_lbl->setToolTip(tr("If true, AO2 will stop the music for you when you or someone else does 'Objection!'.")); + ui_objectmusic_cb = new QCheckBox(ui_audio_widget); + ui_objectmusic_cb->setChecked(p_ao_app->objection_stop_music()); - ui_audio_layout->setWidget(row, QFormLayout::LabelRole, ui_objectmusic_lbl); + ui_audio_layout->setWidget(row, QFormLayout::FieldRole, ui_objectmusic_cb); - ui_objectmusic_cb = new QCheckBox(ui_audio_widget); - ui_objectmusic_cb->setChecked(p_ao_app->objection_stop_music()); + // The casing tab! + ui_casing_tab = new QWidget(); + ui_settings_tabs->addTab(ui_casing_tab, tr("Casing")); - ui_audio_layout->setWidget(row, QFormLayout::FieldRole, ui_objectmusic_cb); + ui_casing_widget = new QWidget(ui_casing_tab); + ui_casing_widget->setGeometry(QRect(10, 10, 361, 211)); - // The casing tab! - ui_casing_tab = new QWidget(); - ui_settings_tabs->addTab(ui_casing_tab, tr("Casing")); + ui_casing_layout = new QFormLayout(ui_casing_widget); + ui_casing_layout->setLabelAlignment(Qt::AlignLeading | Qt::AlignLeft | + Qt::AlignVCenter); + ui_casing_layout->setFormAlignment(Qt::AlignLeading | Qt::AlignLeft | + Qt::AlignTop); + ui_casing_layout->setContentsMargins(0, 0, 0, 0); + row = 0; - ui_casing_widget = new QWidget(ui_casing_tab); - ui_casing_widget->setGeometry(QRect(10, 10, 361, 211)); + // -- SERVER SUPPORTS CASING - ui_casing_layout = new QFormLayout(ui_casing_widget); - ui_casing_layout->setLabelAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignVCenter); - ui_casing_layout->setFormAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignTop); - ui_casing_layout->setContentsMargins(0, 0, 0, 0); - row = 0; + ui_casing_supported_lbl = new QLabel(ui_casing_widget); + if (ao_app->casing_alerts_enabled) + ui_casing_supported_lbl->setText(tr("This server supports case alerts.")); + else + ui_casing_supported_lbl->setText( + tr("This server does not support case alerts.")); + ui_casing_supported_lbl->setToolTip(tr("Pretty self-explanatory.")); - // -- SERVER SUPPORTS CASING + ui_casing_layout->setWidget(row, QFormLayout::FieldRole, + ui_casing_supported_lbl); - ui_casing_supported_lbl = new QLabel(ui_casing_widget); - if (ao_app->casing_alerts_enabled) - ui_casing_supported_lbl->setText(tr("This server supports case alerts.")); - else - ui_casing_supported_lbl->setText(tr("This server does not support case alerts.")); - ui_casing_supported_lbl->setToolTip(tr("Pretty self-explanatory.")); + // -- CASE ANNOUNCEMENTS - ui_casing_layout->setWidget(row, QFormLayout::FieldRole, ui_casing_supported_lbl); + row += 1; + ui_casing_enabled_lbl = new QLabel(ui_casing_widget); + ui_casing_enabled_lbl->setText(tr("Casing:")); + ui_casing_enabled_lbl->setToolTip( + tr("If checked, you will get alerts about case " + "announcements.")); - // -- CASE ANNOUNCEMENTS + ui_casing_layout->setWidget(row, QFormLayout::LabelRole, + ui_casing_enabled_lbl); - row += 1; - ui_casing_enabled_lbl = new QLabel(ui_casing_widget); - ui_casing_enabled_lbl->setText(tr("Casing:")); - ui_casing_enabled_lbl->setToolTip(tr("If checked, you will get alerts about case " - "announcements.")); + ui_casing_enabled_cb = new QCheckBox(ui_casing_widget); + ui_casing_enabled_cb->setChecked(ao_app->get_casing_enabled()); - ui_casing_layout->setWidget(row, QFormLayout::LabelRole, ui_casing_enabled_lbl); + ui_casing_layout->setWidget(row, QFormLayout::FieldRole, + ui_casing_enabled_cb); - ui_casing_enabled_cb = new QCheckBox(ui_casing_widget); - ui_casing_enabled_cb->setChecked(ao_app->get_casing_enabled()); + // -- DEFENSE ANNOUNCEMENTS - ui_casing_layout->setWidget(row, QFormLayout::FieldRole, ui_casing_enabled_cb); + row += 1; + ui_casing_def_lbl = new QLabel(ui_casing_widget); + ui_casing_def_lbl->setText(tr("Defense:")); + ui_casing_def_lbl->setToolTip(tr("If checked, you will get alerts about case " + "announcements if a defense spot is open.")); - // -- DEFENSE ANNOUNCEMENTS + ui_casing_layout->setWidget(row, QFormLayout::LabelRole, ui_casing_def_lbl); - row += 1; - ui_casing_def_lbl = new QLabel(ui_casing_widget); - ui_casing_def_lbl->setText(tr("Defense:")); - ui_casing_def_lbl->setToolTip(tr("If checked, you will get alerts about case " - "announcements if a defense spot is open.")); + ui_casing_def_cb = new QCheckBox(ui_casing_widget); + ui_casing_def_cb->setChecked(ao_app->get_casing_defence_enabled()); - ui_casing_layout->setWidget(row, QFormLayout::LabelRole, ui_casing_def_lbl); + ui_casing_layout->setWidget(row, QFormLayout::FieldRole, ui_casing_def_cb); - ui_casing_def_cb = new QCheckBox(ui_casing_widget); - ui_casing_def_cb->setChecked(ao_app->get_casing_defence_enabled()); + // -- PROSECUTOR ANNOUNCEMENTS - ui_casing_layout->setWidget(row, QFormLayout::FieldRole, ui_casing_def_cb); + row += 1; + ui_casing_pro_lbl = new QLabel(ui_casing_widget); + ui_casing_pro_lbl->setText(tr("Prosecution:")); + ui_casing_pro_lbl->setToolTip( + tr("If checked, you will get alerts about case " + "announcements if a prosecutor spot is open.")); - // -- PROSECUTOR ANNOUNCEMENTS + ui_casing_layout->setWidget(row, QFormLayout::LabelRole, ui_casing_pro_lbl); - row += 1; - ui_casing_pro_lbl = new QLabel(ui_casing_widget); - ui_casing_pro_lbl->setText(tr("Prosecution:")); - ui_casing_pro_lbl->setToolTip(tr("If checked, you will get alerts about case " - "announcements if a prosecutor spot is open.")); + ui_casing_pro_cb = new QCheckBox(ui_casing_widget); + ui_casing_pro_cb->setChecked(ao_app->get_casing_prosecution_enabled()); - ui_casing_layout->setWidget(row, QFormLayout::LabelRole, ui_casing_pro_lbl); + ui_casing_layout->setWidget(row, QFormLayout::FieldRole, ui_casing_pro_cb); - ui_casing_pro_cb = new QCheckBox(ui_casing_widget); - ui_casing_pro_cb->setChecked(ao_app->get_casing_prosecution_enabled()); + // -- JUDGE ANNOUNCEMENTS - ui_casing_layout->setWidget(row, QFormLayout::FieldRole, ui_casing_pro_cb); + row += 1; + ui_casing_jud_lbl = new QLabel(ui_casing_widget); + ui_casing_jud_lbl->setText(tr("Judge:")); + ui_casing_jud_lbl->setToolTip(tr("If checked, you will get alerts about case " + "announcements if the judge spot is open.")); - // -- JUDGE ANNOUNCEMENTS + ui_casing_layout->setWidget(row, QFormLayout::LabelRole, ui_casing_jud_lbl); - row += 1; - ui_casing_jud_lbl = new QLabel(ui_casing_widget); - ui_casing_jud_lbl->setText(tr("Judge:")); - ui_casing_jud_lbl->setToolTip(tr("If checked, you will get alerts about case " - "announcements if the judge spot is open.")); + ui_casing_jud_cb = new QCheckBox(ui_casing_widget); + ui_casing_jud_cb->setChecked(ao_app->get_casing_judge_enabled()); - ui_casing_layout->setWidget(row, QFormLayout::LabelRole, ui_casing_jud_lbl); + ui_casing_layout->setWidget(row, QFormLayout::FieldRole, ui_casing_jud_cb); - ui_casing_jud_cb = new QCheckBox(ui_casing_widget); - ui_casing_jud_cb->setChecked(ao_app->get_casing_judge_enabled()); + // -- JUROR ANNOUNCEMENTS - ui_casing_layout->setWidget(row, QFormLayout::FieldRole, ui_casing_jud_cb); + row += 1; + ui_casing_jur_lbl = new QLabel(ui_casing_widget); + ui_casing_jur_lbl->setText(tr("Juror:")); + ui_casing_jur_lbl->setToolTip(tr("If checked, you will get alerts about case " + "announcements if a juror spot is open.")); - // -- JUROR ANNOUNCEMENTS + ui_casing_layout->setWidget(row, QFormLayout::LabelRole, ui_casing_jur_lbl); - row += 1; - ui_casing_jur_lbl = new QLabel(ui_casing_widget); - ui_casing_jur_lbl->setText(tr("Juror:")); - ui_casing_jur_lbl->setToolTip(tr("If checked, you will get alerts about case " - "announcements if a juror spot is open.")); + ui_casing_jur_cb = new QCheckBox(ui_casing_widget); + ui_casing_jur_cb->setChecked(ao_app->get_casing_juror_enabled()); - ui_casing_layout->setWidget(row, QFormLayout::LabelRole, ui_casing_jur_lbl); + ui_casing_layout->setWidget(row, QFormLayout::FieldRole, ui_casing_jur_cb); - ui_casing_jur_cb = new QCheckBox(ui_casing_widget); - ui_casing_jur_cb->setChecked(ao_app->get_casing_juror_enabled()); + // -- STENO ANNOUNCEMENTS - ui_casing_layout->setWidget(row, QFormLayout::FieldRole, ui_casing_jur_cb); + row += 1; + ui_casing_steno_lbl = new QLabel(ui_casing_widget); + ui_casing_steno_lbl->setText(tr("Stenographer:")); + ui_casing_steno_lbl->setToolTip( + tr("If checked, you will get alerts about case " + "announcements if a stenographer spot is open.")); - // -- STENO ANNOUNCEMENTS + ui_casing_layout->setWidget(row, QFormLayout::LabelRole, ui_casing_steno_lbl); - row += 1; - ui_casing_steno_lbl = new QLabel(ui_casing_widget); - ui_casing_steno_lbl->setText(tr("Stenographer:")); - ui_casing_steno_lbl->setToolTip(tr("If checked, you will get alerts about case " - "announcements if a stenographer spot is open.")); + ui_casing_steno_cb = new QCheckBox(ui_casing_widget); + ui_casing_steno_cb->setChecked(ao_app->get_casing_steno_enabled()); - ui_casing_layout->setWidget(row, QFormLayout::LabelRole, ui_casing_steno_lbl); + ui_casing_layout->setWidget(row, QFormLayout::FieldRole, ui_casing_steno_cb); - ui_casing_steno_cb = new QCheckBox(ui_casing_widget); - ui_casing_steno_cb->setChecked(ao_app->get_casing_steno_enabled()); + // -- CM ANNOUNCEMENTS - ui_casing_layout->setWidget(row, QFormLayout::FieldRole, ui_casing_steno_cb); + row += 1; + ui_casing_cm_lbl = new QLabel(ui_casing_widget); + ui_casing_cm_lbl->setText(tr("CM:")); + ui_casing_cm_lbl->setToolTip( + tr("If checked, you will appear amongst the potential " + "CMs on the server.")); - // -- CM ANNOUNCEMENTS + ui_casing_layout->setWidget(row, QFormLayout::LabelRole, ui_casing_cm_lbl); - row += 1; - ui_casing_cm_lbl = new QLabel(ui_casing_widget); - ui_casing_cm_lbl->setText(tr("CM:")); - ui_casing_cm_lbl->setToolTip(tr("If checked, you will appear amongst the potential " - "CMs on the server.")); + ui_casing_cm_cb = new QCheckBox(ui_casing_widget); + ui_casing_cm_cb->setChecked(ao_app->get_casing_cm_enabled()); - ui_casing_layout->setWidget(row, QFormLayout::LabelRole, ui_casing_cm_lbl); + ui_casing_layout->setWidget(row, QFormLayout::FieldRole, ui_casing_cm_cb); - ui_casing_cm_cb = new QCheckBox(ui_casing_widget); - ui_casing_cm_cb->setChecked(ao_app->get_casing_cm_enabled()); + // -- CM CASES ANNOUNCEMENTS - ui_casing_layout->setWidget(row, QFormLayout::FieldRole, ui_casing_cm_cb); + row += 1; + ui_casing_cm_cases_lbl = new QLabel(ui_casing_widget); + ui_casing_cm_cases_lbl->setText(tr("Hosting cases:")); + ui_casing_cm_cases_lbl->setToolTip( + tr("If you're a CM, enter what cases you are " + "willing to host.")); - // -- CM CASES ANNOUNCEMENTS + ui_casing_layout->setWidget(row, QFormLayout::LabelRole, + ui_casing_cm_cases_lbl); - row += 1; - ui_casing_cm_cases_lbl = new QLabel(ui_casing_widget); - ui_casing_cm_cases_lbl->setText(tr("Hosting cases:")); - ui_casing_cm_cases_lbl->setToolTip(tr("If you're a CM, enter what cases you are " - "willing to host.")); + ui_casing_cm_cases_textbox = new QLineEdit(ui_casing_widget); + ui_casing_cm_cases_textbox->setText(ao_app->get_casing_can_host_cases()); - ui_casing_layout->setWidget(row, QFormLayout::LabelRole, ui_casing_cm_cases_lbl); + ui_casing_layout->setWidget(row, QFormLayout::FieldRole, + ui_casing_cm_cases_textbox); - ui_casing_cm_cases_textbox = new QLineEdit(ui_casing_widget); - ui_casing_cm_cases_textbox->setText(ao_app->get_casing_can_host_cases()); - - ui_casing_layout->setWidget(row, QFormLayout::FieldRole, ui_casing_cm_cases_textbox); - - // When we're done, we should continue the updates! - setUpdatesEnabled(true); + // When we're done, we should continue the updates! + setUpdatesEnabled(true); } void AOOptionsDialog::save_pressed() { - // Save everything into the config.ini. - QSettings *configini = ao_app->configini; + // Save everything into the config.ini. + QSettings *configini = ao_app->configini; - configini->setValue("theme", ui_theme_combobox->currentText()); - configini->setValue("log_goes_downwards", ui_downwards_cb->isChecked()); - configini->setValue("log_maximum", ui_length_spinbox->value()); - configini->setValue("default_username", ui_username_textbox->text()); - configini->setValue("show_custom_shownames", ui_showname_cb->isChecked()); - configini->setValue("master", ui_ms_textbox->text()); - configini->setValue("discord", ui_discord_cb->isChecked()); - configini->setValue("language", ui_language_combobox->currentText().left(2)); - configini->setValue("shake", ui_shake_cb->isChecked()); - configini->setValue("effects", ui_effects_cb->isChecked()); - configini->setValue("framenetwork", ui_framenetwork_cb->isChecked()); - configini->setValue("colorlog", ui_colorlog_cb->isChecked()); - configini->setValue("stickysounds", ui_stickysounds_cb->isChecked()); - configini->setValue("stickyeffects", ui_stickyeffects_cb->isChecked()); - configini->setValue("stickypres", ui_stickypres_cb->isChecked()); + configini->setValue("theme", ui_theme_combobox->currentText()); + configini->setValue("log_goes_downwards", ui_downwards_cb->isChecked()); + configini->setValue("log_maximum", ui_length_spinbox->value()); + configini->setValue("default_username", ui_username_textbox->text()); + configini->setValue("show_custom_shownames", ui_showname_cb->isChecked()); + configini->setValue("master", ui_ms_textbox->text()); + configini->setValue("discord", ui_discord_cb->isChecked()); + configini->setValue("language", ui_language_combobox->currentText().left(2)); + configini->setValue("shake", ui_shake_cb->isChecked()); + configini->setValue("effects", ui_effects_cb->isChecked()); + configini->setValue("framenetwork", ui_framenetwork_cb->isChecked()); + configini->setValue("colorlog", ui_colorlog_cb->isChecked()); + configini->setValue("stickysounds", ui_stickysounds_cb->isChecked()); + configini->setValue("stickyeffects", ui_stickyeffects_cb->isChecked()); + configini->setValue("stickypres", ui_stickypres_cb->isChecked()); - QFile *callwordsini = new QFile(ao_app->get_base_path() + "callwords.ini"); - - if (callwordsini->open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) { - QTextStream out(callwordsini); - out << ui_callwords_textbox->toPlainText(); - callwordsini->close(); - } - - configini->setValue("default_audio_device", ui_audio_device_combobox->currentText()); - configini->setValue("default_music", ui_music_volume_spinbox->value()); - configini->setValue("default_sfx", ui_sfx_volume_spinbox->value()); - configini->setValue("default_blip", ui_blips_volume_spinbox->value()); - configini->setValue("blip_rate", ui_bliprate_spinbox->value()); - configini->setValue("blank_blip", ui_blank_blips_cb->isChecked()); - configini->setValue("looping_sfx", ui_loopsfx_cb->isChecked()); - configini->setValue("objection_stop_music", ui_objectmusic_cb->isChecked()); - - configini->setValue("casing_enabled", ui_casing_enabled_cb->isChecked()); - configini->setValue("casing_defence_enabled", ui_casing_def_cb->isChecked()); - configini->setValue("casing_prosecution_enabled", ui_casing_pro_cb->isChecked()); - configini->setValue("casing_judge_enabled", ui_casing_jud_cb->isChecked()); - configini->setValue("casing_juror_enabled", ui_casing_jur_cb->isChecked()); - configini->setValue("casing_steno_enabled", ui_casing_steno_cb->isChecked()); - configini->setValue("casing_cm_enabled", ui_casing_cm_cb->isChecked()); - configini->setValue("casing_can_host_cases", ui_casing_cm_cases_textbox->text()); + QFile *callwordsini = new QFile(ao_app->get_base_path() + "callwords.ini"); + if (callwordsini->open(QIODevice::WriteOnly | QIODevice::Truncate | + QIODevice::Text)) { + QTextStream out(callwordsini); + out << ui_callwords_textbox->toPlainText(); callwordsini->close(); - done(0); + } + + configini->setValue("default_audio_device", + ui_audio_device_combobox->currentText()); + configini->setValue("default_music", ui_music_volume_spinbox->value()); + configini->setValue("default_sfx", ui_sfx_volume_spinbox->value()); + configini->setValue("default_blip", ui_blips_volume_spinbox->value()); + configini->setValue("blip_rate", ui_bliprate_spinbox->value()); + configini->setValue("blank_blip", ui_blank_blips_cb->isChecked()); + configini->setValue("looping_sfx", ui_loopsfx_cb->isChecked()); + configini->setValue("objection_stop_music", ui_objectmusic_cb->isChecked()); + + configini->setValue("casing_enabled", ui_casing_enabled_cb->isChecked()); + configini->setValue("casing_defence_enabled", ui_casing_def_cb->isChecked()); + configini->setValue("casing_prosecution_enabled", + ui_casing_pro_cb->isChecked()); + configini->setValue("casing_judge_enabled", ui_casing_jud_cb->isChecked()); + configini->setValue("casing_juror_enabled", ui_casing_jur_cb->isChecked()); + configini->setValue("casing_steno_enabled", ui_casing_steno_cb->isChecked()); + configini->setValue("casing_cm_enabled", ui_casing_cm_cb->isChecked()); + configini->setValue("casing_can_host_cases", + ui_casing_cm_cases_textbox->text()); + + callwordsini->close(); + done(0); } -void AOOptionsDialog::discard_pressed() -{ - done(0); -} +void AOOptionsDialog::discard_pressed() { done(0); } #if (defined(_WIN32) || defined(_WIN64)) -bool AOOptionsDialog::needs_default_audiodev() -{ - return true; -} +bool AOOptionsDialog::needs_default_audiodev() { return true; } #elif (defined(LINUX) || defined(__linux__)) -bool AOOptionsDialog::needs_default_audiodev() -{ - return false; -} +bool AOOptionsDialog::needs_default_audiodev() { return false; } #elif defined __APPLE__ -bool AOOptionsDialog::needs_default_audiodev() -{ - return true; -} +bool AOOptionsDialog::needs_default_audiodev() { return true; } #else #error This operating system is not supported. #endif diff --git a/src/aopacket.cpp b/src/aopacket.cpp index 457cc65..6afd39e 100644 --- a/src/aopacket.cpp +++ b/src/aopacket.cpp @@ -4,73 +4,77 @@ AOPacket::AOPacket(QString p_packet_string) { - QStringList packet_contents = p_packet_string.split("#"); + QStringList packet_contents = p_packet_string.split("#"); - m_header = packet_contents.at(0); + m_header = packet_contents.at(0); - for (int n_string = 1; n_string < packet_contents.size() - 1; ++n_string) { - m_contents.append(packet_contents.at(n_string)); - } + for (int n_string = 1; n_string < packet_contents.size() - 1; ++n_string) { + m_contents.append(packet_contents.at(n_string)); + } } AOPacket::AOPacket(QString p_header, QStringList &p_contents) { - m_header = p_header; - m_contents = p_contents; + m_header = p_header; + m_contents = p_contents; } -AOPacket::~AOPacket() -{ -} +AOPacket::~AOPacket() {} QString AOPacket::to_string() { - QString f_string = m_header; + QString f_string = m_header; - for (QString i_string : m_contents) { - f_string += ("#" + i_string); - } + for (QString i_string : m_contents) { + f_string += ("#" + i_string); + } - f_string += "#%"; + f_string += "#%"; - if (encrypted) - return "#" + f_string; - else - return f_string; + if (encrypted) + return "#" + f_string; + else + return f_string; } void AOPacket::encrypt_header(unsigned int p_key) { - m_header = fanta_encrypt(m_header, p_key); + m_header = fanta_encrypt(m_header, p_key); - encrypted = true; + encrypted = true; } void AOPacket::decrypt_header(unsigned int p_key) { - m_header = fanta_decrypt(m_header, p_key); + m_header = fanta_decrypt(m_header, p_key); - encrypted = false; + encrypted = false; } void AOPacket::net_encode() { - for (int n_element = 0; n_element < m_contents.size(); ++n_element) { - QString f_element = m_contents.at(n_element); - f_element.replace("#", "").replace("%", "").replace("$", "").replace("&", ""); + for (int n_element = 0; n_element < m_contents.size(); ++n_element) { + QString f_element = m_contents.at(n_element); + f_element.replace("#", "") + .replace("%", "") + .replace("$", "") + .replace("&", ""); - m_contents.removeAt(n_element); - m_contents.insert(n_element, f_element); - } + m_contents.removeAt(n_element); + m_contents.insert(n_element, f_element); + } } void AOPacket::net_decode() { - for (int n_element = 0; n_element < m_contents.size(); ++n_element) { - QString f_element = m_contents.at(n_element); - f_element.replace("", "#").replace("", "%").replace("", "$").replace("", "&"); + for (int n_element = 0; n_element < m_contents.size(); ++n_element) { + QString f_element = m_contents.at(n_element); + f_element.replace("", "#") + .replace("", "%") + .replace("", "$") + .replace("", "&"); - m_contents.removeAt(n_element); - m_contents.insert(n_element, f_element); - } + m_contents.removeAt(n_element); + m_contents.insert(n_element, f_element); + } } diff --git a/src/aoscene.cpp b/src/aoscene.cpp index 64f741a..094d7a5 100644 --- a/src/aoscene.cpp +++ b/src/aoscene.cpp @@ -4,119 +4,125 @@ AOScene::AOScene(QWidget *parent, AOApplication *p_ao_app) : QLabel(parent) { - m_parent = parent; - ao_app = p_ao_app; - m_movie = new QMovie(this); - last_image = ""; + m_parent = parent; + ao_app = p_ao_app; + m_movie = new QMovie(this); + last_image = ""; } void AOScene::set_image(QString p_image) { - QString background_path = ao_app->get_image_suffix(ao_app->get_background_path(p_image)); - if (!file_exists(background_path)) //If image is missing, clear current image - { - this->clear(); - this->setMovie(nullptr); - - m_movie->stop(); - last_image = ""; - return; - } - - if (file_exists(background_path) && background_path == last_image) - return; - + QString background_path = + ao_app->get_image_suffix(ao_app->get_background_path(p_image)); + if (!file_exists(background_path)) // If image is missing, clear current image + { this->clear(); this->setMovie(nullptr); m_movie->stop(); - m_movie->setFileName(background_path); + last_image = ""; + return; + } - if (m_movie->isValid() && m_movie->frameCount() > 1) { - m_movie->jumpToNextFrame(); - float scale_factor = static_cast(f_h) / static_cast(m_movie->frameRect().height()); - //preserve aspect ratio - int n_w = static_cast(m_movie->frameRect().width() * scale_factor); - int n_h = static_cast(m_movie->frameRect().height() * scale_factor); + if (file_exists(background_path) && background_path == last_image) + return; - m_movie->setScaledSize(QSize(n_w, n_h)); - this->resize(m_movie->scaledSize()); - this->setMovie(m_movie); - QLabel::move(x + (f_w - n_w) / 2, y + (f_h - n_h) / 2); //Center - m_movie->start(); - } - else { - QPixmap background(background_path); - auto transform_mode = Qt::FastTransformation; - if (background.height() > f_h) //We are downscaling, use anti-aliasing. - transform_mode = Qt::SmoothTransformation; + this->clear(); + this->setMovie(nullptr); - background = background.scaledToHeight(f_h, transform_mode); - this->resize(background.size()); - this->setPixmap(background); - QLabel::move(x + (f_w - background.width()) / 2, y + (f_h - background.height()) / 2); //Always center horizontally, always center vertically - } - last_image = background_path; + m_movie->stop(); + m_movie->setFileName(background_path); + + if (m_movie->isValid() && m_movie->frameCount() > 1) { + m_movie->jumpToNextFrame(); + float scale_factor = static_cast(f_h) / + static_cast(m_movie->frameRect().height()); + // preserve aspect ratio + int n_w = static_cast(m_movie->frameRect().width() * scale_factor); + int n_h = static_cast(m_movie->frameRect().height() * scale_factor); + + m_movie->setScaledSize(QSize(n_w, n_h)); + this->resize(m_movie->scaledSize()); + this->setMovie(m_movie); + QLabel::move(x + (f_w - n_w) / 2, y + (f_h - n_h) / 2); // Center + m_movie->start(); + } + else { + QPixmap background(background_path); + auto transform_mode = Qt::FastTransformation; + if (background.height() > f_h) // We are downscaling, use anti-aliasing. + transform_mode = Qt::SmoothTransformation; + + background = background.scaledToHeight(f_h, transform_mode); + this->resize(background.size()); + this->setPixmap(background); + QLabel::move( + x + (f_w - background.width()) / 2, + y + (f_h - background.height()) / + 2); // Always center horizontally, always center vertically + } + last_image = background_path; } void AOScene::set_legacy_desk(QString p_image) { - QString desk_path = ao_app->get_image_suffix(ao_app->get_background_path(p_image)); - if (!file_exists(desk_path)) //If image is missing, clear current image - { - this->clear(); - this->setMovie(nullptr); - - m_movie->stop(); - last_image = ""; - return; - } - - if (file_exists(desk_path) && desk_path == last_image) - return; - - QPixmap f_desk(desk_path); - - //vanilla desks vary in both width and height. in order to make that work with viewport rescaling, - //some INTENSE math is needed. - int vp_width = m_parent->width(); - int vp_height = m_parent->height(); - - double h_modifier = vp_height / 192; - - int final_h = static_cast(h_modifier * f_desk.height()); - + QString desk_path = + ao_app->get_image_suffix(ao_app->get_background_path(p_image)); + if (!file_exists(desk_path)) // If image is missing, clear current image + { this->clear(); this->setMovie(nullptr); m_movie->stop(); - m_movie->setFileName(desk_path); + last_image = ""; + return; + } - m_movie->setScaledSize(QSize(vp_width, final_h)); + if (file_exists(desk_path) && desk_path == last_image) + return; - if (m_movie->isValid() && m_movie->frameCount() > 1) { - this->setMovie(m_movie); - m_movie->start(); - } - else { - this->resize(vp_width, final_h); - this->setPixmap(f_desk.scaled(vp_width, final_h)); - } - last_image = desk_path; + QPixmap f_desk(desk_path); + + // vanilla desks vary in both width and height. in order to make that work + // with viewport rescaling, some INTENSE math is needed. + int vp_width = m_parent->width(); + int vp_height = m_parent->height(); + + double h_modifier = vp_height / 192; + + int final_h = static_cast(h_modifier * f_desk.height()); + + this->clear(); + this->setMovie(nullptr); + + m_movie->stop(); + m_movie->setFileName(desk_path); + + m_movie->setScaledSize(QSize(vp_width, final_h)); + + if (m_movie->isValid() && m_movie->frameCount() > 1) { + this->setMovie(m_movie); + m_movie->start(); + } + else { + this->resize(vp_width, final_h); + this->setPixmap(f_desk.scaled(vp_width, final_h)); + } + last_image = desk_path; } void AOScene::combo_resize(int w, int h) { - QSize f_size(w, h); - f_w = w; - f_h = h; - this->resize(f_size); + QSize f_size(w, h); + f_w = w; + f_h = h; + this->resize(f_size); } void AOScene::move(int ax, int ay) { - x = ax; - y = ay; - QLabel::move(x, y); + x = ax; + y = ay; + QLabel::move(x, y); } diff --git a/src/aosfxplayer.cpp b/src/aosfxplayer.cpp index 4b375a4..3afd704 100644 --- a/src/aosfxplayer.cpp +++ b/src/aosfxplayer.cpp @@ -1,181 +1,179 @@ #include "aosfxplayer.h" #include "file_functions.h" -#if defined(BASSAUDIO) //Using bass.dll for sfx +#if defined(BASSAUDIO) // Using bass.dll for sfx AOSfxPlayer::AOSfxPlayer(QWidget *parent, AOApplication *p_ao_app) { - m_parent = parent; - ao_app = p_ao_app; + m_parent = parent; + ao_app = p_ao_app; } void AOSfxPlayer::clear() { - for (int n_stream = 0; n_stream < m_channelmax; ++n_stream) { - BASS_ChannelStop(m_stream_list[n_stream]); - } - set_volume_internal(m_volume); + for (int n_stream = 0; n_stream < m_channelmax; ++n_stream) { + BASS_ChannelStop(m_stream_list[n_stream]); + } + set_volume_internal(m_volume); } void AOSfxPlayer::loop_clear() { - for (int n_stream = 0; n_stream < m_channelmax; ++n_stream) { - if ((BASS_ChannelFlags(m_stream_list[n_stream], 0, 0) & BASS_SAMPLE_LOOP)) - BASS_ChannelStop(m_stream_list[n_stream]); - } - set_volume_internal(m_volume); + for (int n_stream = 0; n_stream < m_channelmax; ++n_stream) { + if ((BASS_ChannelFlags(m_stream_list[n_stream], 0, 0) & BASS_SAMPLE_LOOP)) + BASS_ChannelStop(m_stream_list[n_stream]); + } + set_volume_internal(m_volume); } -void AOSfxPlayer::play(QString p_sfx, QString p_char, QString shout, int channel) +void AOSfxPlayer::play(QString p_sfx, QString p_char, QString shout, + int channel) { - if (channel == -1) { - if (BASS_ChannelIsActive(m_stream_list[channel]) == BASS_ACTIVE_PLAYING) - m_channel = (m_channel + 1) % m_channelmax; - channel = m_channel; - } + if (channel == -1) { + if (BASS_ChannelIsActive(m_stream_list[channel]) == BASS_ACTIVE_PLAYING) + m_channel = (m_channel + 1) % m_channelmax; + channel = m_channel; + } - BASS_ChannelStop(m_stream_list[channel]); + BASS_ChannelStop(m_stream_list[channel]); - QString misc_path = ""; - QString char_path = ""; - QString sound_path = ao_app->get_sfx_suffix(ao_app->get_sounds_path(p_sfx)); + QString misc_path = ""; + QString char_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); - if (p_char != "") - char_path = ao_app->get_sfx_suffix(ao_app->get_character_path(p_char, p_sfx)); + if (shout != "") + misc_path = ao_app->get_sfx_suffix(ao_app->get_base_path() + "misc/" + + shout + "/" + p_sfx); + if (p_char != "") + char_path = + ao_app->get_sfx_suffix(ao_app->get_character_path(p_char, p_sfx)); - QString f_path; + QString f_path; - if (file_exists(char_path)) - f_path = char_path; - else if (file_exists(misc_path)) - f_path = misc_path; - else - f_path = sound_path; + if (file_exists(char_path)) + f_path = char_path; + else if (file_exists(misc_path)) + f_path = misc_path; + else + f_path = sound_path; - if (f_path.endsWith(".opus")) - m_stream_list[channel] = BASS_OPUS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE); - else - m_stream_list[channel] = BASS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE); + if (f_path.endsWith(".opus")) + m_stream_list[channel] = BASS_OPUS_StreamCreateFile( + FALSE, f_path.utf16(), 0, 0, + BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE); + else + m_stream_list[channel] = BASS_StreamCreateFile( + FALSE, f_path.utf16(), 0, 0, + BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE); - set_volume_internal(m_volume); + set_volume_internal(m_volume); - if (ao_app->get_audio_output_device() != "default") - BASS_ChannelSetDevice(m_stream_list[m_channel], BASS_GetDevice()); - BASS_ChannelPlay(m_stream_list[m_channel], false); + if (ao_app->get_audio_output_device() != "default") + BASS_ChannelSetDevice(m_stream_list[m_channel], BASS_GetDevice()); + BASS_ChannelPlay(m_stream_list[m_channel], false); } void AOSfxPlayer::stop(int channel) { - if (channel == -1) { - channel = m_channel; - } - BASS_ChannelStop(m_stream_list[channel]); + if (channel == -1) { + channel = m_channel; + } + BASS_ChannelStop(m_stream_list[channel]); } void AOSfxPlayer::set_volume(qreal p_value) { - m_volume = p_value / 100; - set_volume_internal(m_volume); + m_volume = p_value / 100; + set_volume_internal(m_volume); } void AOSfxPlayer::set_volume_internal(qreal p_value) { - float volume = static_cast(p_value); - for (int n_stream = 0; n_stream < m_channelmax; ++n_stream) { - BASS_ChannelSetAttribute(m_stream_list[n_stream], BASS_ATTRIB_VOL, volume); - } + float volume = static_cast(p_value); + for (int n_stream = 0; n_stream < m_channelmax; ++n_stream) { + BASS_ChannelSetAttribute(m_stream_list[n_stream], BASS_ATTRIB_VOL, volume); + } } void AOSfxPlayer::set_looping(bool toggle, int channel) { - if (channel == -1) { - channel = m_channel; - } - m_looping = toggle; - if (BASS_ChannelFlags(m_stream_list[channel], 0, 0) & BASS_SAMPLE_LOOP) { - if (m_looping == false) - BASS_ChannelFlags(m_stream_list[channel], 0, BASS_SAMPLE_LOOP); // remove the LOOP flag - } - else { - if (m_looping == true) - BASS_ChannelFlags(m_stream_list[channel], BASS_SAMPLE_LOOP, BASS_SAMPLE_LOOP); // set the LOOP flag - } + if (channel == -1) { + channel = m_channel; + } + m_looping = toggle; + if (BASS_ChannelFlags(m_stream_list[channel], 0, 0) & BASS_SAMPLE_LOOP) { + if (m_looping == false) + BASS_ChannelFlags(m_stream_list[channel], 0, + BASS_SAMPLE_LOOP); // remove the LOOP flag + } + else { + if (m_looping == true) + BASS_ChannelFlags(m_stream_list[channel], BASS_SAMPLE_LOOP, + BASS_SAMPLE_LOOP); // set the LOOP flag + } } -#elif defined(QTAUDIO) //Using Qt's QSoundEffect class +#elif defined(QTAUDIO) // Using Qt's QSoundEffect class AOSfxPlayer::AOSfxPlayer(QWidget *parent, AOApplication *p_ao_app) { - m_parent = parent; - ao_app = p_ao_app; + m_parent = parent; + ao_app = p_ao_app; } void AOSfxPlayer::play(QString p_sfx, QString p_char, QString shout) { - m_sfx.stop(); + m_sfx.stop(); - QString misc_path = ""; - QString char_path = ""; - QString sound_path = ao_app->get_sounds_path(p_sfx); + QString misc_path = ""; + QString char_path = ""; + QString sound_path = ao_app->get_sounds_path(p_sfx); - if (shout != "") - misc_path = ao_app->get_base_path() + "misc/" + shout + "/" + p_sfx; - if (p_char != "") - char_path = ao_app->get_character_path(p_char, p_sfx); + if (shout != "") + misc_path = ao_app->get_base_path() + "misc/" + shout + "/" + p_sfx; + if (p_char != "") + char_path = ao_app->get_character_path(p_char, p_sfx); - QString f_path; + QString f_path; - if (file_exists(char_path)) - f_path = char_path; - else if (file_exists(misc_path)) - f_path = misc_path; - else - f_path = sound_path; + if (file_exists(char_path)) + f_path = char_path; + else if (file_exists(misc_path)) + f_path = misc_path; + else + f_path = sound_path; - if (file_exists(f_path)) //if its missing, it will glitch out - { - m_sfx.setSource(QUrl::fromLocalFile(f_path)); + if (file_exists(f_path)) // if its missing, it will glitch out + { + m_sfx.setSource(QUrl::fromLocalFile(f_path)); - set_volume_internal(m_volume); + set_volume_internal(m_volume); - m_sfx.play(); - } + m_sfx.play(); + } } -void AOSfxPlayer::stop() -{ - m_sfx.stop(); -} +void AOSfxPlayer::stop() { m_sfx.stop(); } void AOSfxPlayer::set_volume(qreal p_value) { - m_volume = p_value / 100; - set_volume_internal(m_volume); + m_volume = p_value / 100; + set_volume_internal(m_volume); } void AOSfxPlayer::set_volume_internal(qreal p_value) { - m_sfx.setVolume(m_volume); + m_sfx.setVolume(m_volume); } #else AOSfxPlayer::AOSfxPlayer(QWidget *parent, AOApplication *p_ao_app) { - m_parent = parent; - ao_app = p_ao_app; + m_parent = parent; + ao_app = p_ao_app; } -void AOSfxPlayer::play(QString p_sfx, QString p_char, QString shout) -{ -} +void AOSfxPlayer::play(QString p_sfx, QString p_char, QString shout) {} -void AOSfxPlayer::stop() -{ -} +void AOSfxPlayer::stop() {} -void AOSfxPlayer::set_volume(qreal p_value) -{ -} +void AOSfxPlayer::set_volume(qreal p_value) {} -void AOSfxPlayer::set_volume_internal(qreal p_value) -{ -} +void AOSfxPlayer::set_volume_internal(qreal p_value) {} #endif diff --git a/src/aotextarea.cpp b/src/aotextarea.cpp index 524f328..52e32f5 100644 --- a/src/aotextarea.cpp +++ b/src/aotextarea.cpp @@ -1,63 +1,73 @@ #include "aotextarea.h" -AOTextArea::AOTextArea(QWidget *p_parent) : QTextBrowser(p_parent) -{ -} +AOTextArea::AOTextArea(QWidget *p_parent) : QTextBrowser(p_parent) {} void AOTextArea::append_linked(QString p_message) { - QString result = p_message.toHtmlEscaped().replace("\n", "
").replace(url_parser_regex, "\\1"); - this->insertHtml(result); + QString result = p_message.toHtmlEscaped() + .replace("\n", "
") + .replace(url_parser_regex, "\\1"); + this->insertHtml(result); } -void AOTextArea::append_chatmessage(QString p_name, QString p_message, QString p_colour) +void AOTextArea::append_chatmessage(QString p_name, QString p_message, + QString p_colour) { - const QTextCursor old_cursor = this->textCursor(); - const int old_scrollbar_value = this->verticalScrollBar()->value(); - const bool is_scrolled_down = old_scrollbar_value == this->verticalScrollBar()->maximum(); + const QTextCursor old_cursor = this->textCursor(); + const int old_scrollbar_value = this->verticalScrollBar()->value(); + const bool is_scrolled_down = + old_scrollbar_value == this->verticalScrollBar()->maximum(); - this->moveCursor(QTextCursor::End); + this->moveCursor(QTextCursor::End); - this->append(""); - this->insertHtml("" + p_name.toHtmlEscaped() + ": "); + this->append(""); + this->insertHtml("" + p_name.toHtmlEscaped() + + ": "); - //cheap workarounds ahoy - p_message += " "; - QString result = p_message.toHtmlEscaped().replace("\n", "
").replace(url_parser_regex, "\\1"); + // cheap workarounds ahoy + p_message += " "; + QString result = p_message.toHtmlEscaped() + .replace("\n", "
") + .replace(url_parser_regex, "\\1"); - this->insertHtml(result); + this->insertHtml(result); - this->auto_scroll(old_cursor, old_scrollbar_value, is_scrolled_down); + this->auto_scroll(old_cursor, old_scrollbar_value, is_scrolled_down); } void AOTextArea::append_error(QString p_message) { - const QTextCursor old_cursor = this->textCursor(); - const int old_scrollbar_value = this->verticalScrollBar()->value(); - const bool is_scrolled_down = old_scrollbar_value == this->verticalScrollBar()->maximum(); + const QTextCursor old_cursor = this->textCursor(); + const int old_scrollbar_value = this->verticalScrollBar()->value(); + const bool is_scrolled_down = + old_scrollbar_value == this->verticalScrollBar()->maximum(); - this->moveCursor(QTextCursor::End); + this->moveCursor(QTextCursor::End); - this->append(""); + this->append(""); - p_message += " "; - QString result = p_message.replace("\n", "
").replace(url_parser_regex, "\\1"); + p_message += " "; + QString result = p_message.replace("\n", "
") + .replace(url_parser_regex, "\\1"); - this->insertHtml("" + result + ""); + this->insertHtml("" + result + ""); - this->auto_scroll(old_cursor, old_scrollbar_value, is_scrolled_down); + this->auto_scroll(old_cursor, old_scrollbar_value, is_scrolled_down); } -void AOTextArea::auto_scroll(QTextCursor old_cursor, int old_scrollbar_value, bool is_scrolled_down) +void AOTextArea::auto_scroll(QTextCursor old_cursor, int old_scrollbar_value, + bool is_scrolled_down) { - if (old_cursor.hasSelection() || !is_scrolled_down) { - // The user has selected text or scrolled away from the bottom: maintain position. - this->setTextCursor(old_cursor); - this->verticalScrollBar()->setValue(old_scrollbar_value); - } - else { - // The user hasn't selected any text and the scrollbar is at the bottom: scroll to the bottom. - this->moveCursor(QTextCursor::End); - this->verticalScrollBar()->setValue(this->verticalScrollBar()->maximum()); - } + if (old_cursor.hasSelection() || !is_scrolled_down) { + // The user has selected text or scrolled away from the bottom: maintain + // position. + this->setTextCursor(old_cursor); + this->verticalScrollBar()->setValue(old_scrollbar_value); + } + else { + // The user hasn't selected any text and the scrollbar is at the bottom: + // scroll to the bottom. + this->moveCursor(QTextCursor::End); + this->verticalScrollBar()->setValue(this->verticalScrollBar()->maximum()); + } } diff --git a/src/aotextedit.cpp b/src/aotextedit.cpp index 0dc5cb4..22d9a62 100644 --- a/src/aotextedit.cpp +++ b/src/aotextedit.cpp @@ -2,19 +2,16 @@ AOTextEdit::AOTextEdit(QWidget *parent) : QPlainTextEdit(parent) { - this->setReadOnly(true); + this->setReadOnly(true); - //connect(this, SIGNAL(returnPressed()), this, SLOT(on_enter_pressed())); + // connect(this, SIGNAL(returnPressed()), this, SLOT(on_enter_pressed())); } void AOTextEdit::mouseDoubleClickEvent(QMouseEvent *e) { - QPlainTextEdit::mouseDoubleClickEvent(e); + QPlainTextEdit::mouseDoubleClickEvent(e); - this->setReadOnly(false); + this->setReadOnly(false); } -void AOTextEdit::on_enter_pressed() -{ - this->setReadOnly(true); -} +void AOTextEdit::on_enter_pressed() { this->setReadOnly(true); } diff --git a/src/charselect.cpp b/src/charselect.cpp index 6575869..de9748b 100644 --- a/src/charselect.cpp +++ b/src/charselect.cpp @@ -7,251 +7,269 @@ void Courtroom::construct_char_select() { - ui_char_select_background = new AOImage(this, ao_app); + ui_char_select_background = new AOImage(this, ao_app); - ui_char_buttons = new QWidget(ui_char_select_background); + ui_char_buttons = new QWidget(ui_char_select_background); - ui_selector = new AOImage(ui_char_select_background, ao_app); - ui_selector->setAttribute(Qt::WA_TransparentForMouseEvents); - ui_selector->resize(62, 62); + ui_selector = new AOImage(ui_char_select_background, ao_app); + ui_selector->setAttribute(Qt::WA_TransparentForMouseEvents); + ui_selector->resize(62, 62); - ui_back_to_lobby = new AOButton(ui_char_select_background, ao_app); + ui_back_to_lobby = new AOButton(ui_char_select_background, ao_app); - ui_char_password = new QLineEdit(ui_char_select_background); - ui_char_password->setPlaceholderText(tr("Password")); + ui_char_password = new QLineEdit(ui_char_select_background); + ui_char_password->setPlaceholderText(tr("Password")); - ui_char_select_left = new AOButton(ui_char_select_background, ao_app); - ui_char_select_right = new AOButton(ui_char_select_background, ao_app); + ui_char_select_left = new AOButton(ui_char_select_background, ao_app); + ui_char_select_right = new AOButton(ui_char_select_background, ao_app); - ui_spectator = new AOButton(ui_char_select_background, ao_app); - ui_spectator->setText(tr("Spectator")); + ui_spectator = new AOButton(ui_char_select_background, ao_app); + ui_spectator->setText(tr("Spectator")); - ui_char_search = new QLineEdit(ui_char_select_background); - ui_char_search->setPlaceholderText(tr("Search")); - ui_char_search->setFocus(); - set_size_and_pos(ui_char_search, "char_search"); + ui_char_search = new QLineEdit(ui_char_select_background); + ui_char_search->setPlaceholderText(tr("Search")); + ui_char_search->setFocus(); + set_size_and_pos(ui_char_search, "char_search"); - ui_char_passworded = new QCheckBox(ui_char_select_background); - ui_char_passworded->setText(tr("Passworded")); - set_size_and_pos(ui_char_passworded, "char_passworded"); + ui_char_passworded = new QCheckBox(ui_char_select_background); + ui_char_passworded->setText(tr("Passworded")); + set_size_and_pos(ui_char_passworded, "char_passworded"); - ui_char_taken = new QCheckBox(ui_char_select_background); - ui_char_taken->setText(tr("Taken")); - set_size_and_pos(ui_char_taken, "char_taken"); + ui_char_taken = new QCheckBox(ui_char_select_background); + ui_char_taken->setText(tr("Taken")); + set_size_and_pos(ui_char_taken, "char_taken"); - ui_char_taken->setChecked(true); - ui_char_passworded->setChecked(true); + ui_char_taken->setChecked(true); + ui_char_passworded->setChecked(true); - set_size_and_pos(ui_char_buttons, "char_buttons"); + set_size_and_pos(ui_char_buttons, "char_buttons"); - connect(ui_back_to_lobby, SIGNAL(clicked()), this, SLOT(on_back_to_lobby_clicked())); + connect(ui_back_to_lobby, SIGNAL(clicked()), this, + SLOT(on_back_to_lobby_clicked())); - connect(ui_char_select_left, SIGNAL(clicked()), this, SLOT(on_char_select_left_clicked())); - connect(ui_char_select_right, SIGNAL(clicked()), this, SLOT(on_char_select_right_clicked())); + connect(ui_char_select_left, SIGNAL(clicked()), this, + SLOT(on_char_select_left_clicked())); + connect(ui_char_select_right, SIGNAL(clicked()), this, + SLOT(on_char_select_right_clicked())); - connect(ui_spectator, SIGNAL(clicked()), this, SLOT(on_spectator_clicked())); + connect(ui_spectator, SIGNAL(clicked()), this, SLOT(on_spectator_clicked())); - connect(ui_char_search, SIGNAL(textEdited(const QString &)), this, SLOT(on_char_search_changed())); - connect(ui_char_passworded, SIGNAL(stateChanged(int)), this, SLOT(on_char_passworded_clicked())); - connect(ui_char_taken, SIGNAL(stateChanged(int)), this, SLOT(on_char_taken_clicked())); + connect(ui_char_search, SIGNAL(textEdited(const QString &)), this, + SLOT(on_char_search_changed())); + connect(ui_char_passworded, SIGNAL(stateChanged(int)), this, + SLOT(on_char_passworded_clicked())); + connect(ui_char_taken, SIGNAL(stateChanged(int)), this, + SLOT(on_char_taken_clicked())); } void Courtroom::set_char_select() { - QString filename = "courtroom_design.ini"; + QString filename = "courtroom_design.ini"; - pos_size_type f_charselect = ao_app->get_element_dimensions("char_select", filename); + pos_size_type f_charselect = + ao_app->get_element_dimensions("char_select", filename); - if (f_charselect.width < 0 || f_charselect.height < 0) { - qDebug() << "W: did not find char_select width or height in courtroom_design.ini!"; - this->resize(714, 668); - } - else - this->resize(f_charselect.width, f_charselect.height); + if (f_charselect.width < 0 || f_charselect.height < 0) { + qDebug() << "W: did not find char_select width or height in " + "courtroom_design.ini!"; + this->resize(714, 668); + } + else + this->resize(f_charselect.width, f_charselect.height); - ui_char_select_background->resize(f_charselect.width, f_charselect.height); - ui_char_select_background->set_image("charselect_background"); + ui_char_select_background->resize(f_charselect.width, f_charselect.height); + ui_char_select_background->set_image("charselect_background"); - filter_character_list(); + filter_character_list(); - ui_char_search->setFocus(); + ui_char_search->setFocus(); } void Courtroom::set_char_select_page() { - ui_char_select_background->show(); + ui_char_select_background->show(); - ui_char_select_left->hide(); - ui_char_select_right->hide(); + ui_char_select_left->hide(); + ui_char_select_right->hide(); - for (AOCharButton *i_button : ui_char_button_list) { - i_button->reset(); - i_button->hide(); - i_button->move(0, 0); - } + for (AOCharButton *i_button : ui_char_button_list) { + i_button->reset(); + i_button->hide(); + i_button->move(0, 0); + } - int total_pages = ui_char_button_list_filtered.size() / max_chars_on_page; - int chars_on_page = 0; - - if (ui_char_button_list_filtered.size() % max_chars_on_page != 0) { - ++total_pages; - //i. e. not on the last page - if (total_pages > current_char_page + 1) - chars_on_page = max_chars_on_page; - else - chars_on_page = ui_char_button_list_filtered.size() % max_chars_on_page; - } - else - chars_on_page = max_chars_on_page; + int total_pages = ui_char_button_list_filtered.size() / max_chars_on_page; + int chars_on_page = 0; + if (ui_char_button_list_filtered.size() % max_chars_on_page != 0) { + ++total_pages; + // i. e. not on the last page if (total_pages > current_char_page + 1) - ui_char_select_right->show(); + chars_on_page = max_chars_on_page; + else + chars_on_page = ui_char_button_list_filtered.size() % max_chars_on_page; + } + else + chars_on_page = max_chars_on_page; - if (current_char_page > 0) - ui_char_select_left->show(); + if (total_pages > current_char_page + 1) + ui_char_select_right->show(); - put_button_in_place(current_char_page * max_chars_on_page, chars_on_page); + if (current_char_page > 0) + ui_char_select_left->show(); + + put_button_in_place(current_char_page * max_chars_on_page, chars_on_page); } void Courtroom::char_clicked(int n_char) { - QString char_ini_path = ao_app->get_character_path(char_list.at(n_char).name, "char.ini"); + QString char_ini_path = + ao_app->get_character_path(char_list.at(n_char).name, "char.ini"); - qDebug() << "char_ini_path" << char_ini_path; + qDebug() << "char_ini_path" << char_ini_path; - if (!file_exists(char_ini_path)) { - call_notice("Could not find " + char_ini_path); - return; - } + if (!file_exists(char_ini_path)) { + call_notice("Could not find " + char_ini_path); + return; + } - if (n_char != m_cid) { - ao_app->send_server_packet(new AOPacket("PW#" + ui_char_password->text() + "#%")); - ao_app->send_server_packet(new AOPacket("CC#" + QString::number(ao_app->s_pv) + "#" + QString::number(n_char) + "#" + get_hdid() + "#%")); - } - else - update_character(n_char); + if (n_char != m_cid) { + ao_app->send_server_packet( + new AOPacket("PW#" + ui_char_password->text() + "#%")); + ao_app->send_server_packet( + new AOPacket("CC#" + QString::number(ao_app->s_pv) + "#" + + QString::number(n_char) + "#" + get_hdid() + "#%")); + } + else + update_character(n_char); - enter_courtroom(); + enter_courtroom(); - ui_ic_chat_name->setPlaceholderText(char_list.at(n_char).name); + ui_ic_chat_name->setPlaceholderText(char_list.at(n_char).name); } void Courtroom::put_button_in_place(int starting, int chars_on_this_page) { - if (ui_char_button_list_filtered.size() == 0) - return; + if (ui_char_button_list_filtered.size() == 0) + return; - QPoint f_spacing = ao_app->get_button_spacing("char_button_spacing", "courtroom_design.ini"); + QPoint f_spacing = + ao_app->get_button_spacing("char_button_spacing", "courtroom_design.ini"); - int x_spacing = f_spacing.x(); - int x_mod_count = 0; + int x_spacing = f_spacing.x(); + int x_mod_count = 0; - int y_spacing = f_spacing.y(); - int y_mod_count = 0; + int y_spacing = f_spacing.y(); + int y_mod_count = 0; - char_columns = ((ui_char_buttons->width() - button_width) / (x_spacing + button_width)) + 1; - char_rows = ((ui_char_buttons->height() - button_height) / (y_spacing + button_height)) + 1; + char_columns = + ((ui_char_buttons->width() - button_width) / (x_spacing + button_width)) + + 1; + char_rows = ((ui_char_buttons->height() - button_height) / + (y_spacing + button_height)) + + 1; - max_chars_on_page = char_columns * char_rows; + max_chars_on_page = char_columns * char_rows; - int startout = starting; - for (int n = starting; n < startout + chars_on_this_page; ++n) { - int x_pos = (button_width + x_spacing) * x_mod_count; - int y_pos = (button_height + y_spacing) * y_mod_count; + int startout = starting; + for (int n = starting; n < startout + chars_on_this_page; ++n) { + int x_pos = (button_width + x_spacing) * x_mod_count; + int y_pos = (button_height + y_spacing) * y_mod_count; - ui_char_button_list_filtered.at(n)->move(x_pos, y_pos); - ui_char_button_list_filtered.at(n)->show(); - ui_char_button_list_filtered.at(n)->apply_taken_image(); + ui_char_button_list_filtered.at(n)->move(x_pos, y_pos); + ui_char_button_list_filtered.at(n)->show(); + ui_char_button_list_filtered.at(n)->apply_taken_image(); - ++x_mod_count; + ++x_mod_count; - if (x_mod_count == char_columns) { - ++y_mod_count; - x_mod_count = 0; - } + if (x_mod_count == char_columns) { + ++y_mod_count; + x_mod_count = 0; } + } } void Courtroom::character_loading_finished() { - // Zeroeth, we'll clear any leftover characters from previous server visits. - ao_app->generated_chars = 0; - if (ui_char_button_list.size() > 0) { - foreach (AOCharButton *item, ui_char_button_list) { - delete item; - } - ui_char_button_list.clear(); + // Zeroeth, we'll clear any leftover characters from previous server visits. + ao_app->generated_chars = 0; + if (ui_char_button_list.size() > 0) { + foreach (AOCharButton *item, ui_char_button_list) { + delete item; } + ui_char_button_list.clear(); + } - // First, we'll make all the character buttons in the very beginning. - // We also hide them all, so they can't be accidentally clicked. - // Later on, we'll be revealing buttons as we need them. - for (int n = 0; n < char_list.size(); n++) { - AOCharButton *char_button = new AOCharButton(ui_char_buttons, ao_app, 0, 0, char_list.at(n).taken); - char_button->reset(); - char_button->hide(); - char_button->set_image(char_list.at(n).name); - ui_char_button_list.append(char_button); + // First, we'll make all the character buttons in the very beginning. + // We also hide them all, so they can't be accidentally clicked. + // Later on, we'll be revealing buttons as we need them. + for (int n = 0; n < char_list.size(); n++) { + AOCharButton *char_button = + new AOCharButton(ui_char_buttons, ao_app, 0, 0, char_list.at(n).taken); + char_button->reset(); + char_button->hide(); + char_button->set_image(char_list.at(n).name); + ui_char_button_list.append(char_button); - connect(char_button, &AOCharButton::clicked, [this, n]() { - this->char_clicked(n); - }); + connect(char_button, &AOCharButton::clicked, + [this, n]() { this->char_clicked(n); }); - // This part here serves as a way of showing to the player that the game is still running, it is - // just loading the pictures of the characters. - if (ao_app->lobby_constructed) { - ao_app->generated_chars++; - int total_loading_size = ao_app->char_list_size * 2 + ao_app->evidence_list_size + ao_app->music_list_size; - int loading_value = int(((ao_app->loaded_chars + ao_app->generated_chars + ao_app->loaded_music + ao_app->loaded_evidence) / static_cast(total_loading_size)) * 100); - ao_app->w_lobby->set_loading_value(loading_value); - ao_app->w_lobby->set_loading_text(tr("Generating chars:\n%1/%2").arg(QString::number(ao_app->generated_chars)).arg(QString::number(ao_app->char_list_size))); - } + // This part here serves as a way of showing to the player that the game is + // still running, it is just loading the pictures of the characters. + if (ao_app->lobby_constructed) { + ao_app->generated_chars++; + int total_loading_size = ao_app->char_list_size * 2 + + ao_app->evidence_list_size + + ao_app->music_list_size; + int loading_value = + int(((ao_app->loaded_chars + ao_app->generated_chars + + ao_app->loaded_music + ao_app->loaded_evidence) / + static_cast(total_loading_size)) * + 100); + ao_app->w_lobby->set_loading_value(loading_value); + ao_app->w_lobby->set_loading_text( + tr("Generating chars:\n%1/%2") + .arg(QString::number(ao_app->generated_chars)) + .arg(QString::number(ao_app->char_list_size))); } + } - filter_character_list(); + filter_character_list(); } void Courtroom::filter_character_list() { - ui_char_button_list_filtered.clear(); - for (int i = 0; i < char_list.size(); i++) { - AOCharButton *current_char = ui_char_button_list.at(i); + ui_char_button_list_filtered.clear(); + for (int i = 0; i < char_list.size(); i++) { + AOCharButton *current_char = ui_char_button_list.at(i); - // It seems passwording characters is unimplemented yet? - // Until then, this will stay here, I suppose. - //if (ui_char_passworded->isChecked() && character_is_passworded??) - // continue; + // It seems passwording characters is unimplemented yet? + // Until then, this will stay here, I suppose. + // if (ui_char_passworded->isChecked() && character_is_passworded??) + // continue; - if (!ui_char_taken->isChecked() && char_list.at(i).taken) - continue; + if (!ui_char_taken->isChecked() && char_list.at(i).taken) + continue; - if (!char_list.at(i).name.contains(ui_char_search->text(), Qt::CaseInsensitive)) - continue; + if (!char_list.at(i).name.contains(ui_char_search->text(), + Qt::CaseInsensitive)) + continue; - // We only really need to update the fact that a character is taken - // for the buttons that actually appear. - // You'd also update the passwordedness and etc. here later. - current_char->reset(); - current_char->set_taken(char_list.at(i).taken); + // We only really need to update the fact that a character is taken + // for the buttons that actually appear. + // You'd also update the passwordedness and etc. here later. + current_char->reset(); + current_char->set_taken(char_list.at(i).taken); - ui_char_button_list_filtered.append(current_char); - } + ui_char_button_list_filtered.append(current_char); + } - current_char_page = 0; - set_char_select_page(); + current_char_page = 0; + set_char_select_page(); } -void Courtroom::on_char_search_changed() -{ - filter_character_list(); -} +void Courtroom::on_char_search_changed() { filter_character_list(); } -void Courtroom::on_char_passworded_clicked() -{ - filter_character_list(); -} +void Courtroom::on_char_passworded_clicked() { filter_character_list(); } -void Courtroom::on_char_taken_clicked() -{ - filter_character_list(); -} +void Courtroom::on_char_taken_clicked() { filter_character_list(); } diff --git a/src/chatlogpiece.cpp b/src/chatlogpiece.cpp index b0113de..34a2fea 100644 --- a/src/chatlogpiece.cpp +++ b/src/chatlogpiece.cpp @@ -2,76 +2,60 @@ chatlogpiece::chatlogpiece() { - name = "UNKNOWN"; - showname = "UNKNOWN"; - message = "UNKNOWN"; - p_is_song = false; - datetime = QDateTime::currentDateTime().toUTC(); + name = "UNKNOWN"; + showname = "UNKNOWN"; + message = "UNKNOWN"; + p_is_song = false; + datetime = QDateTime::currentDateTime().toUTC(); } -chatlogpiece::chatlogpiece(QString p_name, QString p_showname, QString p_message, bool p_song) +chatlogpiece::chatlogpiece(QString p_name, QString p_showname, + QString p_message, bool p_song) { - name = p_name; - showname = p_showname; - message = p_message; - p_is_song = p_song; - datetime = QDateTime::currentDateTime().toUTC(); + name = p_name; + showname = p_showname; + message = p_message; + p_is_song = p_song; + datetime = QDateTime::currentDateTime().toUTC(); } -chatlogpiece::chatlogpiece(QString p_name, QString p_showname, QString p_message, bool p_song, QDateTime p_datetime) +chatlogpiece::chatlogpiece(QString p_name, QString p_showname, + QString p_message, bool p_song, QDateTime p_datetime) { - name = p_name; - showname = p_showname; - message = p_message; - p_is_song = p_song; - datetime = p_datetime.toUTC(); + name = p_name; + showname = p_showname; + message = p_message; + p_is_song = p_song; + datetime = p_datetime.toUTC(); } -QString chatlogpiece::get_name() -{ - return name; -} +QString chatlogpiece::get_name() { return name; } -QString chatlogpiece::get_showname() -{ - return showname; -} +QString chatlogpiece::get_showname() { return showname; } -QString chatlogpiece::get_message() -{ - return message; -} +QString chatlogpiece::get_message() { return message; } -QDateTime chatlogpiece::get_datetime() -{ - return datetime; -} +QDateTime chatlogpiece::get_datetime() { return datetime; } -bool chatlogpiece::is_song() -{ - return p_is_song; -} +bool chatlogpiece::is_song() { return p_is_song; } -QString chatlogpiece::get_datetime_as_string() -{ - return datetime.toString(); -} +QString chatlogpiece::get_datetime_as_string() { return datetime.toString(); } QString chatlogpiece::get_full() { - QString full = "["; + QString full = "["; - full.append(get_datetime_as_string()); - full.append("] "); - full.append(get_showname()); - full.append(" ("); - full.append(get_name()); - full.append(")"); - if (p_is_song) - full.append(" has played a song: "); - else - full.append(": "); - full.append(get_message()); + full.append(get_datetime_as_string()); + full.append("] "); + full.append(get_showname()); + full.append(" ("); + full.append(get_name()); + full.append(")"); + if (p_is_song) + full.append(" has played a song: "); + else + full.append(": "); + full.append(get_message()); - return full; + return full; } diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 4c240fe..9261de3 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -2,2489 +2,2272 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() { - ao_app = p_ao_app; + ao_app = p_ao_app; #ifdef BASSAUDIO - // Change the default audio output device to be the one the user has given - // in his config.ini file for now. - unsigned int a = 0; - BASS_DEVICEINFO info; + // Change the default audio output device to be the one the user has given + // in his config.ini file for now. + unsigned int a = 0; + BASS_DEVICEINFO info; - if (ao_app->get_audio_output_device() == "default") { - BASS_Init(-1, 48000, BASS_DEVICE_LATENCY, nullptr, nullptr); + if (ao_app->get_audio_output_device() == "default") { + BASS_Init(-1, 48000, BASS_DEVICE_LATENCY, nullptr, nullptr); + load_bass_opus_plugin(); + } + else { + for (a = 0; BASS_GetDeviceInfo(a, &info); a++) { + if (ao_app->get_audio_output_device() == info.name) { + BASS_SetDevice(a); + BASS_Init(static_cast(a), 48000, BASS_DEVICE_LATENCY, nullptr, + nullptr); load_bass_opus_plugin(); + qDebug() << info.name << "was set as the default audio output device."; + break; + } } - else { - for (a = 0; BASS_GetDeviceInfo(a, &info); a++) { - if (ao_app->get_audio_output_device() == info.name) { - BASS_SetDevice(a); - BASS_Init(static_cast(a), 48000, BASS_DEVICE_LATENCY, nullptr, nullptr); - load_bass_opus_plugin(); - qDebug() << info.name << "was set as the default audio output device."; - break; - } - } - } + } #elif defined QTAUDIO - if (ao_app->get_audio_output_device() != "default") { - foreach (const QAudioDeviceInfo &deviceInfo, QAudioDeviceInfo::availableDevices(QAudio::AudioOutput)) { - if (ao_app->get_audio_output_device() == deviceInfo.deviceName()) { - ao_app->QtAudioDevice = deviceInfo; - qDebug() << deviceInfo.deviceName() << "was set as the default audio output device."; - break; - } - } + if (ao_app->get_audio_output_device() != "default") { + foreach (const QAudioDeviceInfo &deviceInfo, + QAudioDeviceInfo::availableDevices(QAudio::AudioOutput)) { + if (ao_app->get_audio_output_device() == deviceInfo.deviceName()) { + ao_app->QtAudioDevice = deviceInfo; + qDebug() << deviceInfo.deviceName() + << "was set as the default audio output device."; + break; + } } + } #endif - qsrand(static_cast(QDateTime::currentMSecsSinceEpoch() / 1000)); - - keepalive_timer = new QTimer(this); - keepalive_timer->start(60000); - - chat_tick_timer = new QTimer(this); - - text_delay_timer = new QTimer(this); - text_delay_timer->setSingleShot(true); - - sfx_delay_timer = new QTimer(this); - sfx_delay_timer->setSingleShot(true); - - music_player = new AOMusicPlayer(this, ao_app); - music_player->set_volume(0); - - sfx_player = new AOSfxPlayer(this, ao_app); - sfx_player->set_volume(0); - - objection_player = new AOSfxPlayer(this, ao_app); - objection_player->set_volume(0); - - blip_player = new AOBlipPlayer(this, ao_app); - blip_player->set_volume(0); - - modcall_player = new AOSfxPlayer(this, ao_app); - modcall_player->set_volume(50); - - ui_background = new AOImage(this, ao_app); - - ui_viewport = new QWidget(this); - ui_vp_background = new AOScene(ui_viewport, ao_app); - ui_vp_speedlines = new AOMovie(ui_viewport, ao_app); - ui_vp_speedlines->set_play_once(false); - ui_vp_player_char = new AOCharMovie(ui_viewport, ao_app); - ui_vp_sideplayer_char = new AOCharMovie(ui_viewport, ao_app); - ui_vp_sideplayer_char->hide(); - ui_vp_desk = new AOScene(ui_viewport, ao_app); - ui_vp_legacy_desk = new AOScene(ui_viewport, ao_app); - - ui_vp_evidence_display = new AOEvidenceDisplay(ui_viewport, ao_app); - - ui_vp_chatbox = new AOImage(this, ao_app); - ui_vp_showname = new QLabel(ui_vp_chatbox); - ui_vp_showname->setAlignment(Qt::AlignHCenter); - ui_vp_chat_arrow = new AOMovie(ui_vp_chatbox, ao_app); - ui_vp_chat_arrow->set_play_once(false); - - ui_vp_message = new QTextEdit(this); - ui_vp_message->setFrameStyle(QFrame::NoFrame); - ui_vp_message->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - ui_vp_message->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - ui_vp_message->setReadOnly(true); - - ui_vp_testimony = new AOMovie(this, ao_app); - ui_vp_testimony->set_play_once(false); - ui_vp_testimony->setAttribute(Qt::WA_TransparentForMouseEvents); - ui_vp_effect = new AOMovie(this, ao_app); - ui_vp_effect->setAttribute(Qt::WA_TransparentForMouseEvents); - ui_vp_wtce = new AOMovie(this, ao_app); - ui_vp_wtce->setAttribute(Qt::WA_TransparentForMouseEvents); - ui_vp_objection = new AOMovie(this, ao_app); - ui_vp_objection->setAttribute(Qt::WA_TransparentForMouseEvents); - - ui_ic_chatlog = new QTextEdit(this); - ui_ic_chatlog->setReadOnly(true); - - log_maximum_blocks = ao_app->get_max_log_size(); - log_goes_downwards = ao_app->get_log_goes_downwards(); - - ui_ms_chatlog = new AOTextArea(this); - ui_ms_chatlog->setReadOnly(true); - ui_ms_chatlog->setOpenExternalLinks(true); - ui_ms_chatlog->hide(); - - ui_server_chatlog = new AOTextArea(this); - ui_server_chatlog->setReadOnly(true); - ui_server_chatlog->setOpenExternalLinks(true); - - ui_area_list = new QTreeWidget(this); - ui_area_list->setColumnCount(2); - ui_area_list->hideColumn(0); - ui_area_list->setHeaderHidden(true); - ui_area_list->header()->setStretchLastSection(false); - ui_area_list->header()->setSectionResizeMode(QHeaderView::ResizeToContents); - ui_area_list->hide(); - - ui_music_list = new QTreeWidget(this); - ui_music_list->setColumnCount(2); - ui_music_list->hideColumn(1); - ui_music_list->setHeaderHidden(true); - ui_music_list->header()->setStretchLastSection(false); - ui_music_list->header()->setSectionResizeMode(QHeaderView::ResizeToContents); - ui_music_list->setContextMenuPolicy(Qt::CustomContextMenu); - - ui_music_display = new AOMovie(this, ao_app); - ui_music_display->set_play_once(false); - ui_music_display->setAttribute(Qt::WA_TransparentForMouseEvents); - - ui_music_name = new ScrollText(ui_music_display); - ui_music_name->setText(tr("None")); - ui_music_name->setAttribute(Qt::WA_TransparentForMouseEvents); - - ui_ic_chat_name = new QLineEdit(this); - ui_ic_chat_name->setFrame(false); - ui_ic_chat_name->setPlaceholderText(tr("Showname")); - - ui_ic_chat_message = new AOLineEdit(this); - ui_ic_chat_message->setFrame(false); - ui_ic_chat_message->setPlaceholderText(tr("Message")); - ui_ic_chat_message->preserve_selection(true); - // ui_ic_chat_message->setValidator(new QRegExpValidator(QRegExp("^\\S+(?: \\S+)*$"), ui_ic_chat_message)); - //todo: filter out \n from showing up as that commonly breaks the chatlog and can be spammed to hell - - ui_muted = new AOImage(ui_ic_chat_message, ao_app); - ui_muted->hide(); - - ui_ooc_chat_message = new QLineEdit(this); - ui_ooc_chat_message->setFrame(false); - - ui_ooc_chat_name = new QLineEdit(this); - ui_ooc_chat_name->setFrame(false); - ui_ooc_chat_name->setPlaceholderText(tr("Name")); - ui_ooc_chat_name->setMaxLength(30); - ui_ooc_chat_name->setText(p_ao_app->get_default_username()); - - //ui_area_password = new QLineEdit(this); - //ui_area_password->setFrame(false); - ui_music_search = new QLineEdit(this); - ui_music_search->setFrame(false); - ui_music_search->setPlaceholderText(tr("Search")); - - initialize_emotes(); - - ui_pos_dropdown = new QComboBox(this); - - ui_iniswap_dropdown = new QComboBox(this); - ui_iniswap_dropdown->setContextMenuPolicy(Qt::CustomContextMenu); - ui_iniswap_remove = new AOButton(this, ao_app); - - ui_sfx_dropdown = new QComboBox(this); - ui_sfx_dropdown->setContextMenuPolicy(Qt::CustomContextMenu); - ui_sfx_remove = new AOButton(this, ao_app); - - ui_effects_dropdown = new QComboBox(this); - ui_effects_dropdown->setContextMenuPolicy(Qt::CustomContextMenu); - - ui_defense_bar = new AOImage(this, ao_app); - ui_prosecution_bar = new AOImage(this, ao_app); - - ui_music_label = new QLabel(this); - ui_sfx_label = new QLabel(this); - ui_blip_label = new QLabel(this); + qsrand(static_cast(QDateTime::currentMSecsSinceEpoch() / 1000)); + + keepalive_timer = new QTimer(this); + keepalive_timer->start(60000); + + chat_tick_timer = new QTimer(this); + + text_delay_timer = new QTimer(this); + text_delay_timer->setSingleShot(true); + + sfx_delay_timer = new QTimer(this); + sfx_delay_timer->setSingleShot(true); + + music_player = new AOMusicPlayer(this, ao_app); + music_player->set_volume(0); + + sfx_player = new AOSfxPlayer(this, ao_app); + sfx_player->set_volume(0); + + objection_player = new AOSfxPlayer(this, ao_app); + objection_player->set_volume(0); + + blip_player = new AOBlipPlayer(this, ao_app); + blip_player->set_volume(0); + + modcall_player = new AOSfxPlayer(this, ao_app); + modcall_player->set_volume(50); + + ui_background = new AOImage(this, ao_app); + + ui_viewport = new QWidget(this); + ui_vp_background = new AOScene(ui_viewport, ao_app); + ui_vp_speedlines = new AOMovie(ui_viewport, ao_app); + ui_vp_speedlines->set_play_once(false); + ui_vp_player_char = new AOCharMovie(ui_viewport, ao_app); + ui_vp_sideplayer_char = new AOCharMovie(ui_viewport, ao_app); + ui_vp_sideplayer_char->hide(); + ui_vp_desk = new AOScene(ui_viewport, ao_app); + ui_vp_legacy_desk = new AOScene(ui_viewport, ao_app); + + ui_vp_evidence_display = new AOEvidenceDisplay(ui_viewport, ao_app); + + ui_vp_chatbox = new AOImage(this, ao_app); + ui_vp_showname = new QLabel(ui_vp_chatbox); + ui_vp_showname->setAlignment(Qt::AlignHCenter); + ui_vp_chat_arrow = new AOMovie(ui_vp_chatbox, ao_app); + ui_vp_chat_arrow->set_play_once(false); + + ui_vp_message = new QTextEdit(this); + ui_vp_message->setFrameStyle(QFrame::NoFrame); + ui_vp_message->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + ui_vp_message->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + ui_vp_message->setReadOnly(true); + + ui_vp_testimony = new AOMovie(this, ao_app); + ui_vp_testimony->set_play_once(false); + ui_vp_testimony->setAttribute(Qt::WA_TransparentForMouseEvents); + ui_vp_effect = new AOMovie(this, ao_app); + ui_vp_effect->setAttribute(Qt::WA_TransparentForMouseEvents); + ui_vp_wtce = new AOMovie(this, ao_app); + ui_vp_wtce->setAttribute(Qt::WA_TransparentForMouseEvents); + ui_vp_objection = new AOMovie(this, ao_app); + ui_vp_objection->setAttribute(Qt::WA_TransparentForMouseEvents); + + ui_ic_chatlog = new QTextEdit(this); + ui_ic_chatlog->setReadOnly(true); + + log_maximum_blocks = ao_app->get_max_log_size(); + log_goes_downwards = ao_app->get_log_goes_downwards(); + + ui_ms_chatlog = new AOTextArea(this); + ui_ms_chatlog->setReadOnly(true); + ui_ms_chatlog->setOpenExternalLinks(true); + ui_ms_chatlog->hide(); + + ui_server_chatlog = new AOTextArea(this); + ui_server_chatlog->setReadOnly(true); + ui_server_chatlog->setOpenExternalLinks(true); + + ui_area_list = new QTreeWidget(this); + ui_area_list->setColumnCount(2); + ui_area_list->hideColumn(0); + ui_area_list->setHeaderHidden(true); + ui_area_list->header()->setStretchLastSection(false); + ui_area_list->header()->setSectionResizeMode(QHeaderView::ResizeToContents); + ui_area_list->hide(); + + ui_music_list = new QTreeWidget(this); + ui_music_list->setColumnCount(2); + ui_music_list->hideColumn(1); + ui_music_list->setHeaderHidden(true); + ui_music_list->header()->setStretchLastSection(false); + ui_music_list->header()->setSectionResizeMode(QHeaderView::ResizeToContents); + ui_music_list->setContextMenuPolicy(Qt::CustomContextMenu); + + ui_music_display = new AOMovie(this, ao_app); + ui_music_display->set_play_once(false); + ui_music_display->setAttribute(Qt::WA_TransparentForMouseEvents); + + ui_music_name = new ScrollText(ui_music_display); + ui_music_name->setText(tr("None")); + ui_music_name->setAttribute(Qt::WA_TransparentForMouseEvents); + + ui_ic_chat_name = new QLineEdit(this); + ui_ic_chat_name->setFrame(false); + ui_ic_chat_name->setPlaceholderText(tr("Showname")); + + ui_ic_chat_message = new AOLineEdit(this); + ui_ic_chat_message->setFrame(false); + ui_ic_chat_message->setPlaceholderText(tr("Message")); + ui_ic_chat_message->preserve_selection(true); + // ui_ic_chat_message->setValidator(new QRegExpValidator(QRegExp("^\\S+(?: + // \\S+)*$"), ui_ic_chat_message)); + // todo: filter out \n from showing up as that commonly breaks the chatlog and + // can be spammed to hell + + ui_muted = new AOImage(ui_ic_chat_message, ao_app); + ui_muted->hide(); + + ui_ooc_chat_message = new QLineEdit(this); + ui_ooc_chat_message->setFrame(false); + + ui_ooc_chat_name = new QLineEdit(this); + ui_ooc_chat_name->setFrame(false); + ui_ooc_chat_name->setPlaceholderText(tr("Name")); + ui_ooc_chat_name->setMaxLength(30); + ui_ooc_chat_name->setText(p_ao_app->get_default_username()); + + // ui_area_password = new QLineEdit(this); + // ui_area_password->setFrame(false); + ui_music_search = new QLineEdit(this); + ui_music_search->setFrame(false); + ui_music_search->setPlaceholderText(tr("Search")); + + initialize_emotes(); + + ui_pos_dropdown = new QComboBox(this); + + ui_iniswap_dropdown = new QComboBox(this); + ui_iniswap_dropdown->setContextMenuPolicy(Qt::CustomContextMenu); + ui_iniswap_remove = new AOButton(this, ao_app); + + ui_sfx_dropdown = new QComboBox(this); + ui_sfx_dropdown->setContextMenuPolicy(Qt::CustomContextMenu); + ui_sfx_remove = new AOButton(this, ao_app); + + ui_effects_dropdown = new QComboBox(this); + ui_effects_dropdown->setContextMenuPolicy(Qt::CustomContextMenu); + + ui_defense_bar = new AOImage(this, ao_app); + ui_prosecution_bar = new AOImage(this, ao_app); + + ui_music_label = new QLabel(this); + ui_sfx_label = new QLabel(this); + ui_blip_label = new QLabel(this); + + ui_hold_it = new AOButton(this, ao_app); + ui_objection = new AOButton(this, ao_app); + ui_take_that = new AOButton(this, ao_app); - ui_hold_it = new AOButton(this, ao_app); - ui_objection = new AOButton(this, ao_app); - ui_take_that = new AOButton(this, ao_app); + ui_ooc_toggle = new AOButton(this, ao_app); + ui_witness_testimony = new AOButton(this, ao_app); + ui_cross_examination = new AOButton(this, ao_app); + ui_guilty = new AOButton(this, ao_app); + ui_not_guilty = new AOButton(this, ao_app); - ui_ooc_toggle = new AOButton(this, ao_app); - ui_witness_testimony = new AOButton(this, ao_app); - ui_cross_examination = new AOButton(this, ao_app); - ui_guilty = new AOButton(this, ao_app); - ui_not_guilty = new AOButton(this, ao_app); + ui_change_character = new AOButton(this, ao_app); + ui_reload_theme = new AOButton(this, ao_app); + ui_call_mod = new AOButton(this, ao_app); + ui_settings = new AOButton(this, ao_app); + ui_announce_casing = new AOButton(this, ao_app); + ui_switch_area_music = new AOButton(this, ao_app); + + ui_pre = new QCheckBox(this); + ui_pre->setText(tr("Pre")); + + ui_flip = new QCheckBox(this); + ui_flip->setText(tr("Flip")); + ui_flip->hide(); + + ui_guard = new QCheckBox(this); + ui_guard->setText(tr("Guard")); + ui_guard->hide(); + + ui_additive = new QCheckBox(this); + ui_additive->setText(tr("Additive")); + ui_additive->hide(); - ui_change_character = new AOButton(this, ao_app); - ui_reload_theme = new AOButton(this, ao_app); - ui_call_mod = new AOButton(this, ao_app); - ui_settings = new AOButton(this, ao_app); - ui_announce_casing = new AOButton(this, ao_app); - ui_switch_area_music = new AOButton(this, ao_app); + ui_casing = new QCheckBox(this); + ui_casing->setChecked(ao_app->get_casing_enabled()); + ui_casing->setText(tr("Casing")); + ui_casing->hide(); - ui_pre = new QCheckBox(this); - ui_pre->setText(tr("Pre")); + ui_showname_enable = new QCheckBox(this); + ui_showname_enable->setChecked(ao_app->get_showname_enabled_by_default()); + ui_showname_enable->setText(tr("Shownames")); - ui_flip = new QCheckBox(this); - ui_flip->setText(tr("Flip")); - ui_flip->hide(); + ui_pre_non_interrupt = new QCheckBox(this); + ui_pre_non_interrupt->setText(tr("No Interrupt")); + ui_pre_non_interrupt->hide(); - ui_guard = new QCheckBox(this); - ui_guard->setText(tr("Guard")); - ui_guard->hide(); + ui_custom_objection = new AOButton(this, ao_app); + ui_realization = new AOButton(this, ao_app); + ui_screenshake = new AOButton(this, ao_app); + ui_mute = new AOButton(this, ao_app); - ui_additive = new QCheckBox(this); - ui_additive->setText(tr("Additive")); - ui_additive->hide(); + ui_defense_plus = new AOButton(this, ao_app); + ui_defense_minus = new AOButton(this, ao_app); - ui_casing = new QCheckBox(this); - ui_casing->setChecked(ao_app->get_casing_enabled()); - ui_casing->setText(tr("Casing")); - ui_casing->hide(); + ui_prosecution_plus = new AOButton(this, ao_app); + ui_prosecution_minus = new AOButton(this, ao_app); - ui_showname_enable = new QCheckBox(this); - ui_showname_enable->setChecked(ao_app->get_showname_enabled_by_default()); - ui_showname_enable->setText(tr("Shownames")); + ui_text_color = new QComboBox(this); - ui_pre_non_interrupt = new QCheckBox(this); - ui_pre_non_interrupt->setText(tr("No Interrupt")); - ui_pre_non_interrupt->hide(); + ui_music_slider = new QSlider(Qt::Horizontal, this); + ui_music_slider->setRange(0, 100); + ui_music_slider->setValue(ao_app->get_default_music()); - ui_custom_objection = new AOButton(this, ao_app); - ui_realization = new AOButton(this, ao_app); - ui_screenshake = new AOButton(this, ao_app); - ui_mute = new AOButton(this, ao_app); + ui_sfx_slider = new QSlider(Qt::Horizontal, this); + ui_sfx_slider->setRange(0, 100); + ui_sfx_slider->setValue(ao_app->get_default_sfx()); - ui_defense_plus = new AOButton(this, ao_app); - ui_defense_minus = new AOButton(this, ao_app); + ui_blip_slider = new QSlider(Qt::Horizontal, this); + ui_blip_slider->setRange(0, 100); + ui_blip_slider->setValue(ao_app->get_default_blip()); - ui_prosecution_plus = new AOButton(this, ao_app); - ui_prosecution_minus = new AOButton(this, ao_app); + ui_mute_list = new QListWidget(this); - ui_text_color = new QComboBox(this); + ui_pair_list = new QListWidget(this); + ui_pair_offset_spinbox = new QSpinBox(this); + ui_pair_offset_spinbox->setRange(-100, 100); + ui_pair_offset_spinbox->setSuffix(tr("% offset")); - ui_music_slider = new QSlider(Qt::Horizontal, this); - ui_music_slider->setRange(0, 100); - ui_music_slider->setValue(ao_app->get_default_music()); + ui_pair_order_dropdown = new QComboBox(this); + ui_pair_order_dropdown->addItem("To front"); + ui_pair_order_dropdown->addItem("To behind"); - ui_sfx_slider = new QSlider(Qt::Horizontal, this); - ui_sfx_slider->setRange(0, 100); - ui_sfx_slider->setValue(ao_app->get_default_sfx()); + ui_pair_button = new AOButton(this, ao_app); - ui_blip_slider = new QSlider(Qt::Horizontal, this); - ui_blip_slider->setRange(0, 100); - ui_blip_slider->setValue(ao_app->get_default_blip()); + ui_evidence_button = new AOButton(this, ao_app); - ui_mute_list = new QListWidget(this); + initialize_evidence(); + + construct_char_select(); - ui_pair_list = new QListWidget(this); - ui_pair_offset_spinbox = new QSpinBox(this); - ui_pair_offset_spinbox->setRange(-100, 100); - ui_pair_offset_spinbox->setSuffix(tr("% offset")); - - ui_pair_order_dropdown = new QComboBox(this); - ui_pair_order_dropdown->addItem("To front"); - ui_pair_order_dropdown->addItem("To behind"); - - ui_pair_button = new AOButton(this, ao_app); - - ui_evidence_button = new AOButton(this, ao_app); - - initialize_evidence(); - - construct_char_select(); - - connect(keepalive_timer, SIGNAL(timeout()), this, SLOT(ping_server())); - - connect(ui_vp_objection, SIGNAL(done()), this, SLOT(objection_done())); - connect(ui_vp_player_char, SIGNAL(done()), this, SLOT(preanim_done())); - connect(ui_vp_player_char, SIGNAL(shake()), this, SLOT(do_screenshake())); - connect(ui_vp_player_char, SIGNAL(flash()), this, SLOT(do_flash())); - connect(ui_vp_player_char, SIGNAL(play_sfx(QString)), this, SLOT(play_char_sfx(QString))); - - connect(text_delay_timer, SIGNAL(timeout()), this, SLOT(start_chat_ticking())); - connect(sfx_delay_timer, SIGNAL(timeout()), this, SLOT(play_sfx())); - - connect(chat_tick_timer, SIGNAL(timeout()), this, SLOT(chat_tick())); - - connect(ui_pos_dropdown, SIGNAL(currentIndexChanged(int)), this, SLOT(on_pos_dropdown_changed(int))); - - connect(ui_iniswap_dropdown, SIGNAL(currentIndexChanged(int)), this, SLOT(on_iniswap_dropdown_changed(int))); - connect(ui_iniswap_dropdown, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(on_iniswap_context_menu_requested(QPoint))); - connect(ui_iniswap_remove, SIGNAL(clicked()), this, SLOT(on_iniswap_remove_clicked())); - - connect(ui_sfx_dropdown, SIGNAL(currentIndexChanged(int)), this, SLOT(on_sfx_dropdown_changed(int))); - connect(ui_sfx_dropdown, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(on_sfx_context_menu_requested(QPoint))); - connect(ui_sfx_remove, SIGNAL(clicked()), this, SLOT(on_sfx_remove_clicked())); - - connect(ui_effects_dropdown, SIGNAL(currentIndexChanged(int)), this, SLOT(on_effects_dropdown_changed(int))); - connect(ui_effects_dropdown, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(on_effects_context_menu_requested(QPoint))); - - connect(ui_mute_list, SIGNAL(clicked(QModelIndex)), this, SLOT(on_mute_list_clicked(QModelIndex))); - - connect(ui_ic_chat_message, SIGNAL(returnPressed()), this, SLOT(on_chat_return_pressed())); - - connect(ui_ooc_chat_message, SIGNAL(returnPressed()), this, SLOT(on_ooc_return_pressed())); - - connect(ui_music_list, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), this, SLOT(on_music_list_double_clicked(QTreeWidgetItem *, int))); - connect(ui_music_list, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(on_music_list_context_menu_requested(QPoint))); - - connect(ui_area_list, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), this, SLOT(on_area_list_double_clicked(QTreeWidgetItem *, int))); - - connect(ui_hold_it, SIGNAL(clicked()), this, SLOT(on_hold_it_clicked())); - connect(ui_objection, SIGNAL(clicked()), this, SLOT(on_objection_clicked())); - connect(ui_take_that, SIGNAL(clicked()), this, SLOT(on_take_that_clicked())); - connect(ui_custom_objection, SIGNAL(clicked()), this, SLOT(on_custom_objection_clicked())); - - connect(ui_realization, SIGNAL(clicked()), this, SLOT(on_realization_clicked())); - connect(ui_screenshake, SIGNAL(clicked()), this, SLOT(on_screenshake_clicked())); - - connect(ui_mute, SIGNAL(clicked()), this, SLOT(on_mute_clicked())); - - connect(ui_defense_minus, SIGNAL(clicked()), this, SLOT(on_defense_minus_clicked())); - connect(ui_defense_plus, SIGNAL(clicked()), this, SLOT(on_defense_plus_clicked())); - connect(ui_prosecution_minus, SIGNAL(clicked()), this, SLOT(on_prosecution_minus_clicked())); - connect(ui_prosecution_plus, SIGNAL(clicked()), this, SLOT(on_prosecution_plus_clicked())); - - connect(ui_text_color, SIGNAL(currentIndexChanged(int)), this, SLOT(on_text_color_changed(int))); - - connect(ui_music_slider, SIGNAL(valueChanged(int)), this, SLOT(on_music_slider_moved(int))); - connect(ui_sfx_slider, SIGNAL(valueChanged(int)), this, SLOT(on_sfx_slider_moved(int))); - connect(ui_blip_slider, SIGNAL(valueChanged(int)), this, SLOT(on_blip_slider_moved(int))); - - connect(ui_ooc_toggle, SIGNAL(clicked()), this, SLOT(on_ooc_toggle_clicked())); - - connect(ui_music_search, SIGNAL(textChanged(QString)), this, SLOT(on_music_search_edited(QString))); - - connect(ui_witness_testimony, SIGNAL(clicked()), this, SLOT(on_witness_testimony_clicked())); - connect(ui_cross_examination, SIGNAL(clicked()), this, SLOT(on_cross_examination_clicked())); - connect(ui_guilty, SIGNAL(clicked()), this, SLOT(on_guilty_clicked())); - connect(ui_not_guilty, SIGNAL(clicked()), this, SLOT(on_not_guilty_clicked())); - - connect(ui_change_character, SIGNAL(clicked()), this, SLOT(on_change_character_clicked())); - connect(ui_reload_theme, SIGNAL(clicked()), this, SLOT(on_reload_theme_clicked())); - connect(ui_call_mod, SIGNAL(clicked()), this, SLOT(on_call_mod_clicked())); - connect(ui_settings, SIGNAL(clicked()), this, SLOT(on_settings_clicked())); - connect(ui_announce_casing, SIGNAL(clicked()), this, SLOT(on_announce_casing_clicked())); - connect(ui_switch_area_music, SIGNAL(clicked()), this, SLOT(on_switch_area_music_clicked())); - - connect(ui_pre, SIGNAL(clicked()), this, SLOT(on_pre_clicked())); - connect(ui_flip, SIGNAL(clicked()), this, SLOT(on_flip_clicked())); - connect(ui_additive, SIGNAL(clicked()), this, SLOT(on_additive_clicked())); - connect(ui_guard, SIGNAL(clicked()), this, SLOT(on_guard_clicked())); - connect(ui_casing, SIGNAL(clicked()), this, SLOT(on_casing_clicked())); - - connect(ui_showname_enable, SIGNAL(clicked()), this, SLOT(on_showname_enable_clicked())); - - connect(ui_pair_button, SIGNAL(clicked()), this, SLOT(on_pair_clicked())); - connect(ui_pair_list, SIGNAL(clicked(QModelIndex)), this, SLOT(on_pair_list_clicked(QModelIndex))); - connect(ui_pair_offset_spinbox, SIGNAL(valueChanged(int)), this, SLOT(on_pair_offset_changed(int))); - connect(ui_pair_order_dropdown, SIGNAL(currentIndexChanged(int)), this, SLOT(on_pair_order_dropdown_changed(int))); - - connect(ui_evidence_button, SIGNAL(clicked()), this, SLOT(on_evidence_button_clicked())); - - set_widgets(); - - set_char_select(); + connect(keepalive_timer, SIGNAL(timeout()), this, SLOT(ping_server())); + + connect(ui_vp_objection, SIGNAL(done()), this, SLOT(objection_done())); + connect(ui_vp_player_char, SIGNAL(done()), this, SLOT(preanim_done())); + connect(ui_vp_player_char, SIGNAL(shake()), this, SLOT(do_screenshake())); + connect(ui_vp_player_char, SIGNAL(flash()), this, SLOT(do_flash())); + connect(ui_vp_player_char, SIGNAL(play_sfx(QString)), this, + SLOT(play_char_sfx(QString))); + + connect(text_delay_timer, SIGNAL(timeout()), this, + SLOT(start_chat_ticking())); + connect(sfx_delay_timer, SIGNAL(timeout()), this, SLOT(play_sfx())); + + connect(chat_tick_timer, SIGNAL(timeout()), this, SLOT(chat_tick())); + + connect(ui_pos_dropdown, SIGNAL(currentIndexChanged(int)), this, + SLOT(on_pos_dropdown_changed(int))); + + connect(ui_iniswap_dropdown, SIGNAL(currentIndexChanged(int)), this, + SLOT(on_iniswap_dropdown_changed(int))); + connect(ui_iniswap_dropdown, SIGNAL(customContextMenuRequested(QPoint)), this, + SLOT(on_iniswap_context_menu_requested(QPoint))); + connect(ui_iniswap_remove, SIGNAL(clicked()), this, + SLOT(on_iniswap_remove_clicked())); + + connect(ui_sfx_dropdown, SIGNAL(currentIndexChanged(int)), this, + SLOT(on_sfx_dropdown_changed(int))); + connect(ui_sfx_dropdown, SIGNAL(customContextMenuRequested(QPoint)), this, + SLOT(on_sfx_context_menu_requested(QPoint))); + connect(ui_sfx_remove, SIGNAL(clicked()), this, + SLOT(on_sfx_remove_clicked())); + + connect(ui_effects_dropdown, SIGNAL(currentIndexChanged(int)), this, + SLOT(on_effects_dropdown_changed(int))); + connect(ui_effects_dropdown, SIGNAL(customContextMenuRequested(QPoint)), this, + SLOT(on_effects_context_menu_requested(QPoint))); + + connect(ui_mute_list, SIGNAL(clicked(QModelIndex)), this, + SLOT(on_mute_list_clicked(QModelIndex))); + + connect(ui_ic_chat_message, SIGNAL(returnPressed()), this, + SLOT(on_chat_return_pressed())); + + connect(ui_ooc_chat_message, SIGNAL(returnPressed()), this, + SLOT(on_ooc_return_pressed())); + + connect(ui_music_list, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), + this, SLOT(on_music_list_double_clicked(QTreeWidgetItem *, int))); + connect(ui_music_list, SIGNAL(customContextMenuRequested(QPoint)), this, + SLOT(on_music_list_context_menu_requested(QPoint))); + + connect(ui_area_list, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), this, + SLOT(on_area_list_double_clicked(QTreeWidgetItem *, int))); + + connect(ui_hold_it, SIGNAL(clicked()), this, SLOT(on_hold_it_clicked())); + connect(ui_objection, SIGNAL(clicked()), this, SLOT(on_objection_clicked())); + connect(ui_take_that, SIGNAL(clicked()), this, SLOT(on_take_that_clicked())); + connect(ui_custom_objection, SIGNAL(clicked()), this, + SLOT(on_custom_objection_clicked())); + + connect(ui_realization, SIGNAL(clicked()), this, + SLOT(on_realization_clicked())); + connect(ui_screenshake, SIGNAL(clicked()), this, + SLOT(on_screenshake_clicked())); + + connect(ui_mute, SIGNAL(clicked()), this, SLOT(on_mute_clicked())); + + connect(ui_defense_minus, SIGNAL(clicked()), this, + SLOT(on_defense_minus_clicked())); + connect(ui_defense_plus, SIGNAL(clicked()), this, + SLOT(on_defense_plus_clicked())); + connect(ui_prosecution_minus, SIGNAL(clicked()), this, + SLOT(on_prosecution_minus_clicked())); + connect(ui_prosecution_plus, SIGNAL(clicked()), this, + SLOT(on_prosecution_plus_clicked())); + + connect(ui_text_color, SIGNAL(currentIndexChanged(int)), this, + SLOT(on_text_color_changed(int))); + + connect(ui_music_slider, SIGNAL(valueChanged(int)), this, + SLOT(on_music_slider_moved(int))); + connect(ui_sfx_slider, SIGNAL(valueChanged(int)), this, + SLOT(on_sfx_slider_moved(int))); + connect(ui_blip_slider, SIGNAL(valueChanged(int)), this, + SLOT(on_blip_slider_moved(int))); + + connect(ui_ooc_toggle, SIGNAL(clicked()), this, + SLOT(on_ooc_toggle_clicked())); + + connect(ui_music_search, SIGNAL(textChanged(QString)), this, + SLOT(on_music_search_edited(QString))); + + connect(ui_witness_testimony, SIGNAL(clicked()), this, + SLOT(on_witness_testimony_clicked())); + connect(ui_cross_examination, SIGNAL(clicked()), this, + SLOT(on_cross_examination_clicked())); + connect(ui_guilty, SIGNAL(clicked()), this, SLOT(on_guilty_clicked())); + connect(ui_not_guilty, SIGNAL(clicked()), this, + SLOT(on_not_guilty_clicked())); + + connect(ui_change_character, SIGNAL(clicked()), this, + SLOT(on_change_character_clicked())); + connect(ui_reload_theme, SIGNAL(clicked()), this, + SLOT(on_reload_theme_clicked())); + connect(ui_call_mod, SIGNAL(clicked()), this, SLOT(on_call_mod_clicked())); + connect(ui_settings, SIGNAL(clicked()), this, SLOT(on_settings_clicked())); + connect(ui_announce_casing, SIGNAL(clicked()), this, + SLOT(on_announce_casing_clicked())); + connect(ui_switch_area_music, SIGNAL(clicked()), this, + SLOT(on_switch_area_music_clicked())); + + connect(ui_pre, SIGNAL(clicked()), this, SLOT(on_pre_clicked())); + connect(ui_flip, SIGNAL(clicked()), this, SLOT(on_flip_clicked())); + connect(ui_additive, SIGNAL(clicked()), this, SLOT(on_additive_clicked())); + connect(ui_guard, SIGNAL(clicked()), this, SLOT(on_guard_clicked())); + connect(ui_casing, SIGNAL(clicked()), this, SLOT(on_casing_clicked())); + + connect(ui_showname_enable, SIGNAL(clicked()), this, + SLOT(on_showname_enable_clicked())); + + connect(ui_pair_button, SIGNAL(clicked()), this, SLOT(on_pair_clicked())); + connect(ui_pair_list, SIGNAL(clicked(QModelIndex)), this, + SLOT(on_pair_list_clicked(QModelIndex))); + connect(ui_pair_offset_spinbox, SIGNAL(valueChanged(int)), this, + SLOT(on_pair_offset_changed(int))); + connect(ui_pair_order_dropdown, SIGNAL(currentIndexChanged(int)), this, + SLOT(on_pair_order_dropdown_changed(int))); + + connect(ui_evidence_button, SIGNAL(clicked()), this, + SLOT(on_evidence_button_clicked())); + + set_widgets(); + + set_char_select(); } void Courtroom::set_mute_list() { - mute_map.clear(); + mute_map.clear(); - //maps which characters are muted based on cid, none are muted by default - for (int n_cid = 0; n_cid < char_list.size(); n_cid++) { - mute_map.insert(n_cid, false); - } + // maps which characters are muted based on cid, none are muted by default + for (int n_cid = 0; n_cid < char_list.size(); n_cid++) { + mute_map.insert(n_cid, false); + } - QStringList sorted_mute_list; + QStringList sorted_mute_list; - for (char_type i_char : char_list) - sorted_mute_list.append(i_char.name); + for (char_type i_char : char_list) + sorted_mute_list.append(i_char.name); - sorted_mute_list.sort(); + sorted_mute_list.sort(); - for (QString i_name : sorted_mute_list) { - //mute_map.insert(i_name, false); - ui_mute_list->addItem(i_name); - } + for (QString i_name : sorted_mute_list) { + // mute_map.insert(i_name, false); + ui_mute_list->addItem(i_name); + } } void Courtroom::set_pair_list() { - QStringList sorted_pair_list; + QStringList sorted_pair_list; - for (char_type i_char : char_list) - sorted_pair_list.append(i_char.name); + for (char_type i_char : char_list) + sorted_pair_list.append(i_char.name); - sorted_pair_list.sort(); + sorted_pair_list.sort(); - for (QString i_name : sorted_pair_list) { - ui_pair_list->addItem(i_name); - } + for (QString i_name : sorted_pair_list) { + ui_pair_list->addItem(i_name); + } } void Courtroom::set_widgets() { - blip_rate = ao_app->read_blip_rate(); - blank_blip = ao_app->get_blank_blip(); - - QString filename = "courtroom_design.ini"; - - pos_size_type f_courtroom = ao_app->get_element_dimensions("courtroom", filename); - - if (f_courtroom.width < 0 || f_courtroom.height < 0) { - qDebug() << "W: did not find courtroom width or height in " << filename; - - this->resize(714, 668); - } - else { - m_courtroom_width = f_courtroom.width; - m_courtroom_height = f_courtroom.height; - - this->resize(f_courtroom.width, f_courtroom.height); - } - - set_fonts(); - - ui_background->move(0, 0); - ui_background->resize(m_courtroom_width, m_courtroom_height); - ui_background->set_image("courtroombackground"); - - set_size_and_pos(ui_viewport, "viewport"); - - // 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_support_enabled) { - ui_pair_button->show(); - ui_pre_non_interrupt->show(); - ui_showname_enable->show(); - ui_ic_chat_name->show(); - ui_ic_chat_name->setEnabled(true); - } - else { - ui_pair_button->hide(); - ui_pre_non_interrupt->hide(); - ui_showname_enable->hide(); - ui_ic_chat_name->hide(); - ui_ic_chat_name->setEnabled(false); - } - - if (ao_app->casing_alerts_enabled) { - ui_announce_casing->show(); - ui_casing->show(); - } - else { - ui_announce_casing->hide(); - ui_casing->hide(); - } - - // We also show the non-server-dependent client additions. - // Once again, if the theme can't display it, set_move_and_pos will catch them. - ui_settings->show(); - - ui_vp_background->move(0, 0); - ui_vp_background->combo_resize(ui_viewport->width(), ui_viewport->height()); - - ui_vp_speedlines->move(0, 0); - ui_vp_speedlines->combo_resize(ui_viewport->width(), ui_viewport->height()); - - ui_vp_player_char->move(0, 0); - ui_vp_player_char->combo_resize(ui_viewport->width(), ui_viewport->height()); - - ui_vp_sideplayer_char->move(0, 0); - ui_vp_sideplayer_char->combo_resize(ui_viewport->width(), ui_viewport->height()); - - //the AO2 desk element - ui_vp_desk->move(0, 0); - ui_vp_desk->combo_resize(ui_viewport->width(), ui_viewport->height()); - - //the size of the ui_vp_legacy_desk element relies on various factors and is set in set_scene() - - double y_modifier = 147.0 / 192.0; - int final_y = static_cast(y_modifier * ui_viewport->height()); - ui_vp_legacy_desk->move(0, final_y); - ui_vp_legacy_desk->hide(); - - ui_vp_evidence_display->move(0, 0); - ui_vp_evidence_display->combo_resize(ui_viewport->width(), ui_viewport->height()); - - ui_vp_chat_arrow->move(0, 0); - pos_size_type design_ini_result = ao_app->get_element_dimensions("chat_arrow", "courtroom_design.ini"); - - 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(); - } - else { - ui_vp_chat_arrow->move(design_ini_result.x, design_ini_result.y); - ui_vp_chat_arrow->combo_resize(design_ini_result.width, design_ini_result.height); - } - - ui_vp_testimony->move(ui_viewport->x(), ui_viewport->y()); - ui_vp_testimony->combo_resize(ui_viewport->width(), ui_viewport->height()); - - ui_vp_effect->move(ui_viewport->x(), ui_viewport->y()); - ui_vp_effect->combo_resize(ui_viewport->width(), ui_viewport->height()); - - ui_vp_wtce->move(ui_viewport->x(), ui_viewport->y()); - ui_vp_wtce->combo_resize(ui_viewport->width(), ui_viewport->height()); - - ui_vp_objection->move(ui_viewport->x(), ui_viewport->y()); - ui_vp_objection->combo_resize(ui_viewport->width(), ui_viewport->height()); - - set_size_and_pos(ui_ic_chatlog, "ic_chatlog"); - ui_ic_chatlog->setFrameShape(QFrame::NoFrame); - - set_size_and_pos(ui_ms_chatlog, "ms_chatlog"); - ui_ms_chatlog->setFrameShape(QFrame::NoFrame); - - set_size_and_pos(ui_server_chatlog, "server_chatlog"); - ui_server_chatlog->setFrameShape(QFrame::NoFrame); - - 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 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_offset_spinbox->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()); - - set_size_and_pos(ui_music_list, "music_list"); - ui_music_list->header()->setMinimumSectionSize(ui_music_list->width()); - - set_size_and_pos(ui_music_name, "music_name"); - - ui_music_display->move(0, 0); - design_ini_result = ao_app->get_element_dimensions("music_display", "courtroom_design.ini"); - - if (design_ini_result.width < 0 || design_ini_result.height < 0) { - qDebug() << "W: could not find \"music_name\" in courtroom_design.ini"; - ui_music_display->hide(); - } - else { - ui_music_display->move(design_ini_result.x, design_ini_result.y); - ui_music_display->combo_resize(design_ini_result.width, design_ini_result.height); - } - - ui_music_display->play("music_display"); - - if (is_ao2_bg) { - set_size_and_pos(ui_ic_chat_message, "ao2_ic_chat_message"); - set_size_and_pos(ui_vp_chatbox, "ao2_chatbox"); - set_size_and_pos(ui_ic_chat_name, "ao2_ic_chat_name"); - } - else { - set_size_and_pos(ui_ic_chat_message, "ic_chat_message"); - set_size_and_pos(ui_vp_chatbox, "chatbox"); - set_size_and_pos(ui_ic_chat_name, "ic_chat_name"); - } - - ui_ic_chat_message->setStyleSheet("QLineEdit{background-color: rgba(100, 100, 100, 255);}"); - ui_ic_chat_name->setStyleSheet("QLineEdit{background-color: rgba(180, 180, 180, 255);}"); - - ui_vp_chatbox->set_image("chatblank"); - ui_vp_chatbox->hide(); - - set_size_and_pos(ui_vp_showname, "showname"); - - set_size_and_pos(ui_vp_message, "message"); - ui_vp_message->hide(); - - //We detached the text as parent from the chatbox so it doesn't get affected by the screenshake. - ui_vp_message->move(ui_vp_message->x() + ui_vp_chatbox->x(), ui_vp_message->y() + ui_vp_chatbox->y()); - ui_vp_message->setTextInteractionFlags(Qt::NoTextInteraction); - - ui_muted->resize(ui_ic_chat_message->width(), ui_ic_chat_message->height()); - ui_muted->set_image("muted"); - ui_muted->setToolTip(tr("Oops, you're muted!")); - - set_size_and_pos(ui_ooc_chat_message, "ooc_chat_message"); - ui_ooc_chat_message->setStyleSheet("background-color: rgba(0, 0, 0, 0);"); - - set_size_and_pos(ui_ooc_chat_name, "ooc_chat_name"); - ui_ooc_chat_name->setStyleSheet("background-color: rgba(0, 0, 0, 0);"); - - //set_size_and_pos(ui_area_password, "area_password"); - set_size_and_pos(ui_music_search, "music_search"); - ui_music_search->setStyleSheet("background-color: rgba(0, 0, 0, 0);"); - - set_size_and_pos(ui_emote_dropdown, "emote_dropdown"); - ui_emote_dropdown->setToolTip(tr("Set your character's emote to play on your next message.")); - - set_size_and_pos(ui_pos_dropdown, "pos_dropdown"); - ui_pos_dropdown->setToolTip(tr("Set your character's supplementary background.")); - - set_size_and_pos(ui_iniswap_dropdown, "iniswap_dropdown"); - ui_iniswap_dropdown->setEditable(true); - ui_iniswap_dropdown->setInsertPolicy(QComboBox::InsertAtBottom); - ui_iniswap_dropdown->setToolTip(tr("Set an 'iniswap', or an alternative character folder to refer to from your current character.\n" - "Edit by typing and pressing Enter, [X] to remove. This saves to your base/characters//iniswaps.ini")); - - set_size_and_pos(ui_iniswap_remove, "iniswap_remove"); - ui_iniswap_remove->setText("X"); - ui_iniswap_remove->set_image("evidencex"); - ui_iniswap_remove->setToolTip(tr("Remove the currently selected iniswap from the list and return to the original character folder.")); - ui_iniswap_remove->hide(); - - set_size_and_pos(ui_sfx_dropdown, "sfx_dropdown"); - ui_sfx_dropdown->setEditable(true); - ui_sfx_dropdown->setInsertPolicy(QComboBox::InsertAtBottom); - ui_sfx_dropdown->setToolTip(tr("Set a sound effect to play on your next 'Preanim'. Leaving it on Default will use the emote-defined sound (if any).\n" - "Edit by typing and pressing Enter, [X] to remove. This saves to your base/characters//soundlist.ini")); - - set_size_and_pos(ui_sfx_remove, "sfx_remove"); - ui_sfx_remove->setText("X"); - ui_sfx_remove->set_image("evidencex"); - ui_sfx_remove->setToolTip(tr("Remove the currently selected iniswap from the list and return to the original character folder.")); - ui_sfx_remove->hide(); - - set_size_and_pos(ui_effects_dropdown, "effects_dropdown"); - ui_effects_dropdown->setInsertPolicy(QComboBox::InsertAtBottom); - ui_effects_dropdown->setToolTip(tr("Choose an effect to play on your next spoken message.\n" - "The effects are defined in your theme/effects/effects.ini. Your character can define custom effects by\n" - "char.ini [Options] category, effects = 'miscname' where it referes to misc//effects.ini to read the effects.")); - //Todo: recode this entire fucking system with these dumbass goddamn ini's why is everything so specifically coded for all these purposes - //is ABSTRACT CODING not a thing now huh what the FUCK why do I gotta do this pleASE FOR THE LOVE OF GOD SPARE ME FROM THIS FRESH HELL - //btw i still love coding. - QPoint p_point = ao_app->get_button_spacing("effects_icon_size", filename); - ui_effects_dropdown->setIconSize(QSize(p_point.x(), p_point.y())); - - set_size_and_pos(ui_defense_bar, "defense_bar"); - ui_defense_bar->set_image("defensebar" + QString::number(defense_bar_state)); - - set_size_and_pos(ui_prosecution_bar, "prosecution_bar"); - ui_prosecution_bar->set_image("prosecutionbar" + QString::number(prosecution_bar_state)); - - set_size_and_pos(ui_music_label, "music_label"); - ui_music_label->setText(tr("Music")); - set_size_and_pos(ui_sfx_label, "sfx_label"); - ui_sfx_label->setText(tr("Sfx")); - set_size_and_pos(ui_blip_label, "blip_label"); - ui_blip_label->setText(tr("Blips")); - - set_size_and_pos(ui_hold_it, "hold_it"); - ui_hold_it->setText(tr("Hold It!")); - ui_hold_it->setToolTip(tr("When this is turned on, your next in-character message will be a shout!")); - ui_hold_it->set_image("holdit"); - - set_size_and_pos(ui_objection, "objection"); - ui_objection->setText(tr("Objection!")); - ui_objection->setToolTip(tr("When this is turned on, your next in-character message will be a shout!")); - ui_objection->set_image("objection"); - - set_size_and_pos(ui_take_that, "take_that"); - ui_take_that->setText(tr("Take That!")); - ui_take_that->setToolTip(tr("When this is turned on, your next in-character message will be a shout!")); - ui_take_that->set_image("takethat"); - - set_size_and_pos(ui_ooc_toggle, "ooc_toggle"); - ui_ooc_toggle->setText(tr("Server")); - ui_ooc_toggle->setToolTip(tr("Toggle between server chat and global AO2 chat.")); - - set_size_and_pos(ui_witness_testimony, "witness_testimony"); - ui_witness_testimony->set_image("witnesstestimony"); - ui_witness_testimony->setToolTip(tr("This will display the animation in the viewport as soon as it is pressed.")); - set_size_and_pos(ui_cross_examination, "cross_examination"); - ui_cross_examination->set_image("crossexamination"); - ui_cross_examination->setToolTip(tr("This will display the animation in the viewport as soon as it is pressed.")); - - set_size_and_pos(ui_guilty, "guilty"); - ui_guilty->setText(tr("Guilty!")); - ui_guilty->set_image("guilty"); - ui_guilty->setToolTip(tr("This will display the animation in the viewport as soon as it is pressed.")); - set_size_and_pos(ui_not_guilty, "not_guilty"); - ui_not_guilty->set_image("notguilty"); - ui_not_guilty->setToolTip(tr("This will display the animation in the viewport as soon as it is pressed.")); - - set_size_and_pos(ui_change_character, "change_character"); - ui_change_character->setText(tr("Change character")); - ui_change_character->set_image("change_character"); - ui_change_character->setToolTip(tr("Bring up the Character Select Screen and change your character.")); - - set_size_and_pos(ui_reload_theme, "reload_theme"); - ui_reload_theme->setText(tr("Reload theme")); - ui_reload_theme->set_image("reload_theme"); - ui_reload_theme->setToolTip(tr("Refresh the theme and update all of the ui elements to match.")); - - set_size_and_pos(ui_call_mod, "call_mod"); - ui_call_mod->setText(tr("Call mod")); - ui_call_mod->set_image("call_mod"); - ui_call_mod->setToolTip(tr("Request the attention of the current server's moderator.")); - - set_size_and_pos(ui_settings, "settings"); - ui_settings->setText(tr("Settings")); - ui_settings->set_image("settings"); - ui_settings->setToolTip(tr("Allows you to change various aspects of the client.")); - - set_size_and_pos(ui_announce_casing, "casing_button"); - ui_announce_casing->setText(tr("Casing")); - ui_announce_casing->set_image("casing_button"); - ui_announce_casing->setToolTip(tr("An interface to help you announce a case (you have to be a CM first to be able to announce cases)")); - - set_size_and_pos(ui_switch_area_music, "switch_area_music"); - ui_switch_area_music->setText(tr("A/M")); - ui_switch_area_music->set_image("switch_area_music"); - ui_switch_area_music->setToolTip(tr("Switch between Areas and Music lists")); - - set_size_and_pos(ui_pre, "pre"); - ui_pre->setText(tr("Preanim")); - ui_pre->setToolTip(tr("Play a single-shot animation as defined by the emote when checked.")); - - set_size_and_pos(ui_pre_non_interrupt, "pre_no_interrupt"); - ui_pre_non_interrupt->setToolTip(tr("If preanim is checked, display the input text immediately as the animation plays concurrently.")); - - set_size_and_pos(ui_flip, "flip"); - ui_flip->setToolTip(tr("Mirror your character's emotes when checked.")); - - set_size_and_pos(ui_additive, "additive"); - ui_additive->setToolTip(tr("Add text to your last spoken message when checked.")); - - set_size_and_pos(ui_guard, "guard"); - ui_guard->setToolTip(tr("Do not listen to mod calls when checked, preventing them from playing sounds or focusing attention on the window.")); - - set_size_and_pos(ui_casing, "casing"); - ui_casing->setToolTip(tr("Lets you receive case alerts when enabled.\n" - "(You can set your preferences in the Settings!)")); - - set_size_and_pos(ui_showname_enable, "showname_enable"); - ui_showname_enable->setToolTip(tr("Display customized shownames for all users when checked.")); - - set_size_and_pos(ui_custom_objection, "custom_objection"); - ui_custom_objection->setText(tr("Custom Shout!")); - ui_custom_objection->set_image("custom"); - ui_custom_objection->setToolTip(tr("This will display the custom character-defined animation in the viewport as soon as it is pressed.\n" - "To make one, your character's folder must contain custom.[webp/apng/gif/png] and custom.[wav/ogg/opus] sound effect")); - - set_size_and_pos(ui_realization, "realization"); - ui_realization->set_image("realization"); - ui_realization->setToolTip(tr("Play realization sound and animation in the viewport on the next spoken message when checked.")); - - set_size_and_pos(ui_screenshake, "screenshake"); - ui_screenshake->set_image("screenshake"); - ui_screenshake->setToolTip(tr("Shake the screen on next spoken message when checked.")); - - set_size_and_pos(ui_mute, "mute_button"); - ui_mute->setText("Mute"); - ui_mute->set_image("mute"); - ui_mute->setToolTip(tr("Display the list of character folders you wish to mute.")); - - set_size_and_pos(ui_defense_plus, "defense_plus"); - ui_defense_plus->set_image("defplus"); - ui_defense_plus->setToolTip(tr("Increase the health bar.")); - - set_size_and_pos(ui_defense_minus, "defense_minus"); - ui_defense_minus->set_image("defminus"); - ui_defense_minus->setToolTip(tr("Decrease the health bar.")); - - set_size_and_pos(ui_prosecution_plus, "prosecution_plus"); - ui_prosecution_plus->set_image("proplus"); - ui_prosecution_plus->setToolTip(tr("Increase the health bar.")); - - set_size_and_pos(ui_prosecution_minus, "prosecution_minus"); - ui_prosecution_minus->set_image("prominus"); - ui_prosecution_minus->setToolTip(tr("Decrease the health bar.")); - - set_size_and_pos(ui_text_color, "text_color"); - ui_text_color->setToolTip(tr("Change the text color of the spoken message.\n" - "You can also select a part of your currently typed message and use the dropdown to change its color!")); - set_text_color_dropdown(); - - set_size_and_pos(ui_music_slider, "music_slider"); - set_size_and_pos(ui_sfx_slider, "sfx_slider"); - set_size_and_pos(ui_blip_slider, "blip_slider"); - - ui_selector->set_image("char_selector"); - ui_selector->hide(); - - set_size_and_pos(ui_back_to_lobby, "back_to_lobby"); - ui_back_to_lobby->setText(tr("Back to Lobby")); - ui_back_to_lobby->setToolTip(tr("Return back to the server list.")); - - set_size_and_pos(ui_char_password, "char_password"); - - set_size_and_pos(ui_char_buttons, "char_buttons"); - - set_size_and_pos(ui_char_select_left, "char_select_left"); - ui_char_select_left->set_image("arrow_left"); - - set_size_and_pos(ui_char_select_right, "char_select_right"); - ui_char_select_right->set_image("arrow_right"); - - set_size_and_pos(ui_spectator, "spectator"); - ui_spectator->setToolTip(tr("Become a spectator. You won't be able to interact with the in-character screen.")); - - refresh_evidence(); + blip_rate = ao_app->read_blip_rate(); + blank_blip = ao_app->get_blank_blip(); + + QString filename = "courtroom_design.ini"; + + pos_size_type f_courtroom = + ao_app->get_element_dimensions("courtroom", filename); + + if (f_courtroom.width < 0 || f_courtroom.height < 0) { + qDebug() << "W: did not find courtroom width or height in " << filename; + + this->resize(714, 668); + } + else { + m_courtroom_width = f_courtroom.width; + m_courtroom_height = f_courtroom.height; + + this->resize(f_courtroom.width, f_courtroom.height); + } + + set_fonts(); + + ui_background->move(0, 0); + ui_background->resize(m_courtroom_width, m_courtroom_height); + ui_background->set_image("courtroombackground"); + + set_size_and_pos(ui_viewport, "viewport"); + + // 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_support_enabled) { + ui_pair_button->show(); + ui_pre_non_interrupt->show(); + ui_showname_enable->show(); + ui_ic_chat_name->show(); + ui_ic_chat_name->setEnabled(true); + } + else { + ui_pair_button->hide(); + ui_pre_non_interrupt->hide(); + ui_showname_enable->hide(); + ui_ic_chat_name->hide(); + ui_ic_chat_name->setEnabled(false); + } + + if (ao_app->casing_alerts_enabled) { + ui_announce_casing->show(); + ui_casing->show(); + } + else { + ui_announce_casing->hide(); + ui_casing->hide(); + } + + // We also show the non-server-dependent client additions. + // Once again, if the theme can't display it, set_move_and_pos will catch + // them. + ui_settings->show(); + + ui_vp_background->move(0, 0); + ui_vp_background->combo_resize(ui_viewport->width(), ui_viewport->height()); + + ui_vp_speedlines->move(0, 0); + ui_vp_speedlines->combo_resize(ui_viewport->width(), ui_viewport->height()); + + ui_vp_player_char->move(0, 0); + ui_vp_player_char->combo_resize(ui_viewport->width(), ui_viewport->height()); + + ui_vp_sideplayer_char->move(0, 0); + ui_vp_sideplayer_char->combo_resize(ui_viewport->width(), + ui_viewport->height()); + + // the AO2 desk element + ui_vp_desk->move(0, 0); + ui_vp_desk->combo_resize(ui_viewport->width(), ui_viewport->height()); + + // the size of the ui_vp_legacy_desk element relies on various factors and is + // set in set_scene() + + double y_modifier = 147.0 / 192.0; + int final_y = static_cast(y_modifier * ui_viewport->height()); + ui_vp_legacy_desk->move(0, final_y); + ui_vp_legacy_desk->hide(); + + ui_vp_evidence_display->move(0, 0); + ui_vp_evidence_display->combo_resize(ui_viewport->width(), + ui_viewport->height()); + + ui_vp_chat_arrow->move(0, 0); + pos_size_type design_ini_result = + ao_app->get_element_dimensions("chat_arrow", "courtroom_design.ini"); + + 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(); + } + else { + ui_vp_chat_arrow->move(design_ini_result.x, design_ini_result.y); + ui_vp_chat_arrow->combo_resize(design_ini_result.width, + design_ini_result.height); + } + + ui_vp_testimony->move(ui_viewport->x(), ui_viewport->y()); + ui_vp_testimony->combo_resize(ui_viewport->width(), ui_viewport->height()); + + ui_vp_effect->move(ui_viewport->x(), ui_viewport->y()); + ui_vp_effect->combo_resize(ui_viewport->width(), ui_viewport->height()); + + ui_vp_wtce->move(ui_viewport->x(), ui_viewport->y()); + ui_vp_wtce->combo_resize(ui_viewport->width(), ui_viewport->height()); + + ui_vp_objection->move(ui_viewport->x(), ui_viewport->y()); + ui_vp_objection->combo_resize(ui_viewport->width(), ui_viewport->height()); + + set_size_and_pos(ui_ic_chatlog, "ic_chatlog"); + ui_ic_chatlog->setFrameShape(QFrame::NoFrame); + + set_size_and_pos(ui_ms_chatlog, "ms_chatlog"); + ui_ms_chatlog->setFrameShape(QFrame::NoFrame); + + set_size_and_pos(ui_server_chatlog, "server_chatlog"); + ui_server_chatlog->setFrameShape(QFrame::NoFrame); + + 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 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_offset_spinbox->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()); + + set_size_and_pos(ui_music_list, "music_list"); + ui_music_list->header()->setMinimumSectionSize(ui_music_list->width()); + + set_size_and_pos(ui_music_name, "music_name"); + + ui_music_display->move(0, 0); + design_ini_result = + ao_app->get_element_dimensions("music_display", "courtroom_design.ini"); + + if (design_ini_result.width < 0 || design_ini_result.height < 0) { + qDebug() << "W: could not find \"music_name\" in courtroom_design.ini"; + ui_music_display->hide(); + } + else { + ui_music_display->move(design_ini_result.x, design_ini_result.y); + ui_music_display->combo_resize(design_ini_result.width, + design_ini_result.height); + } + + ui_music_display->play("music_display"); + + if (is_ao2_bg) { + set_size_and_pos(ui_ic_chat_message, "ao2_ic_chat_message"); + set_size_and_pos(ui_vp_chatbox, "ao2_chatbox"); + set_size_and_pos(ui_ic_chat_name, "ao2_ic_chat_name"); + } + else { + set_size_and_pos(ui_ic_chat_message, "ic_chat_message"); + set_size_and_pos(ui_vp_chatbox, "chatbox"); + set_size_and_pos(ui_ic_chat_name, "ic_chat_name"); + } + + ui_ic_chat_message->setStyleSheet( + "QLineEdit{background-color: rgba(100, 100, 100, 255);}"); + ui_ic_chat_name->setStyleSheet( + "QLineEdit{background-color: rgba(180, 180, 180, 255);}"); + + ui_vp_chatbox->set_image("chatblank"); + ui_vp_chatbox->hide(); + + set_size_and_pos(ui_vp_showname, "showname"); + + set_size_and_pos(ui_vp_message, "message"); + ui_vp_message->hide(); + + // We detached the text as parent from the chatbox so it doesn't get affected + // by the screenshake. + ui_vp_message->move(ui_vp_message->x() + ui_vp_chatbox->x(), + ui_vp_message->y() + ui_vp_chatbox->y()); + ui_vp_message->setTextInteractionFlags(Qt::NoTextInteraction); + + ui_muted->resize(ui_ic_chat_message->width(), ui_ic_chat_message->height()); + ui_muted->set_image("muted"); + ui_muted->setToolTip(tr("Oops, you're muted!")); + + set_size_and_pos(ui_ooc_chat_message, "ooc_chat_message"); + ui_ooc_chat_message->setStyleSheet("background-color: rgba(0, 0, 0, 0);"); + + set_size_and_pos(ui_ooc_chat_name, "ooc_chat_name"); + ui_ooc_chat_name->setStyleSheet("background-color: rgba(0, 0, 0, 0);"); + + // set_size_and_pos(ui_area_password, "area_password"); + set_size_and_pos(ui_music_search, "music_search"); + ui_music_search->setStyleSheet("background-color: rgba(0, 0, 0, 0);"); + + set_size_and_pos(ui_emote_dropdown, "emote_dropdown"); + ui_emote_dropdown->setToolTip( + tr("Set your character's emote to play on your next message.")); + + set_size_and_pos(ui_pos_dropdown, "pos_dropdown"); + ui_pos_dropdown->setToolTip( + tr("Set your character's supplementary background.")); + + set_size_and_pos(ui_iniswap_dropdown, "iniswap_dropdown"); + ui_iniswap_dropdown->setEditable(true); + ui_iniswap_dropdown->setInsertPolicy(QComboBox::InsertAtBottom); + ui_iniswap_dropdown->setToolTip( + tr("Set an 'iniswap', or an alternative character folder to refer to " + "from your current character.\n" + "Edit by typing and pressing Enter, [X] to remove. This saves to your " + "base/characters//iniswaps.ini")); + + set_size_and_pos(ui_iniswap_remove, "iniswap_remove"); + ui_iniswap_remove->setText("X"); + ui_iniswap_remove->set_image("evidencex"); + ui_iniswap_remove->setToolTip( + tr("Remove the currently selected iniswap from the list and return to " + "the original character folder.")); + ui_iniswap_remove->hide(); + + set_size_and_pos(ui_sfx_dropdown, "sfx_dropdown"); + ui_sfx_dropdown->setEditable(true); + ui_sfx_dropdown->setInsertPolicy(QComboBox::InsertAtBottom); + ui_sfx_dropdown->setToolTip( + tr("Set a sound effect to play on your next 'Preanim'. Leaving it on " + "Default will use the emote-defined sound (if any).\n" + "Edit by typing and pressing Enter, [X] to remove. This saves to your " + "base/characters//soundlist.ini")); + + set_size_and_pos(ui_sfx_remove, "sfx_remove"); + ui_sfx_remove->setText("X"); + ui_sfx_remove->set_image("evidencex"); + ui_sfx_remove->setToolTip( + tr("Remove the currently selected iniswap from the list and return to " + "the original character folder.")); + ui_sfx_remove->hide(); + + set_size_and_pos(ui_effects_dropdown, "effects_dropdown"); + ui_effects_dropdown->setInsertPolicy(QComboBox::InsertAtBottom); + ui_effects_dropdown->setToolTip( + tr("Choose an effect to play on your next spoken message.\n" + "The effects are defined in your theme/effects/effects.ini. Your " + "character can define custom effects by\n" + "char.ini [Options] category, effects = 'miscname' where it referes " + "to misc//effects.ini to read the effects.")); + // Todo: recode this entire fucking system with these dumbass goddamn ini's + // why is everything so specifically coded for all these purposes is ABSTRACT + // CODING not a thing now huh what the FUCK why do I gotta do this pleASE FOR + // THE LOVE OF GOD SPARE ME FROM THIS FRESH HELL btw i still love coding. + QPoint p_point = ao_app->get_button_spacing("effects_icon_size", filename); + ui_effects_dropdown->setIconSize(QSize(p_point.x(), p_point.y())); + + set_size_and_pos(ui_defense_bar, "defense_bar"); + ui_defense_bar->set_image("defensebar" + QString::number(defense_bar_state)); + + set_size_and_pos(ui_prosecution_bar, "prosecution_bar"); + ui_prosecution_bar->set_image("prosecutionbar" + + QString::number(prosecution_bar_state)); + + set_size_and_pos(ui_music_label, "music_label"); + ui_music_label->setText(tr("Music")); + set_size_and_pos(ui_sfx_label, "sfx_label"); + ui_sfx_label->setText(tr("Sfx")); + set_size_and_pos(ui_blip_label, "blip_label"); + ui_blip_label->setText(tr("Blips")); + + set_size_and_pos(ui_hold_it, "hold_it"); + ui_hold_it->setText(tr("Hold It!")); + ui_hold_it->setToolTip(tr("When this is turned on, your next in-character " + "message will be a shout!")); + ui_hold_it->set_image("holdit"); + + set_size_and_pos(ui_objection, "objection"); + ui_objection->setText(tr("Objection!")); + ui_objection->setToolTip(tr("When this is turned on, your next in-character " + "message will be a shout!")); + ui_objection->set_image("objection"); + + set_size_and_pos(ui_take_that, "take_that"); + ui_take_that->setText(tr("Take That!")); + ui_take_that->setToolTip(tr("When this is turned on, your next in-character " + "message will be a shout!")); + ui_take_that->set_image("takethat"); + + set_size_and_pos(ui_ooc_toggle, "ooc_toggle"); + ui_ooc_toggle->setText(tr("Server")); + ui_ooc_toggle->setToolTip( + tr("Toggle between server chat and global AO2 chat.")); + + set_size_and_pos(ui_witness_testimony, "witness_testimony"); + ui_witness_testimony->set_image("witnesstestimony"); + ui_witness_testimony->setToolTip(tr("This will display the animation in the " + "viewport as soon as it is pressed.")); + set_size_and_pos(ui_cross_examination, "cross_examination"); + ui_cross_examination->set_image("crossexamination"); + ui_cross_examination->setToolTip(tr("This will display the animation in the " + "viewport as soon as it is pressed.")); + + set_size_and_pos(ui_guilty, "guilty"); + ui_guilty->setText(tr("Guilty!")); + ui_guilty->set_image("guilty"); + ui_guilty->setToolTip(tr("This will display the animation in the viewport as " + "soon as it is pressed.")); + set_size_and_pos(ui_not_guilty, "not_guilty"); + ui_not_guilty->set_image("notguilty"); + ui_not_guilty->setToolTip(tr("This will display the animation in the " + "viewport as soon as it is pressed.")); + + set_size_and_pos(ui_change_character, "change_character"); + ui_change_character->setText(tr("Change character")); + ui_change_character->set_image("change_character"); + ui_change_character->setToolTip( + tr("Bring up the Character Select Screen and change your character.")); + + set_size_and_pos(ui_reload_theme, "reload_theme"); + ui_reload_theme->setText(tr("Reload theme")); + ui_reload_theme->set_image("reload_theme"); + ui_reload_theme->setToolTip( + tr("Refresh the theme and update all of the ui elements to match.")); + + set_size_and_pos(ui_call_mod, "call_mod"); + ui_call_mod->setText(tr("Call mod")); + ui_call_mod->set_image("call_mod"); + ui_call_mod->setToolTip( + tr("Request the attention of the current server's moderator.")); + + set_size_and_pos(ui_settings, "settings"); + ui_settings->setText(tr("Settings")); + ui_settings->set_image("settings"); + ui_settings->setToolTip( + tr("Allows you to change various aspects of the client.")); + + set_size_and_pos(ui_announce_casing, "casing_button"); + ui_announce_casing->setText(tr("Casing")); + ui_announce_casing->set_image("casing_button"); + ui_announce_casing->setToolTip( + tr("An interface to help you announce a case (you have to be a CM first " + "to be able to announce cases)")); + + set_size_and_pos(ui_switch_area_music, "switch_area_music"); + ui_switch_area_music->setText(tr("A/M")); + ui_switch_area_music->set_image("switch_area_music"); + ui_switch_area_music->setToolTip(tr("Switch between Areas and Music lists")); + + set_size_and_pos(ui_pre, "pre"); + ui_pre->setText(tr("Preanim")); + ui_pre->setToolTip( + tr("Play a single-shot animation as defined by the emote when checked.")); + + set_size_and_pos(ui_pre_non_interrupt, "pre_no_interrupt"); + ui_pre_non_interrupt->setToolTip( + tr("If preanim is checked, display the input text immediately as the " + "animation plays concurrently.")); + + set_size_and_pos(ui_flip, "flip"); + ui_flip->setToolTip(tr("Mirror your character's emotes when checked.")); + + set_size_and_pos(ui_additive, "additive"); + ui_additive->setToolTip( + tr("Add text to your last spoken message when checked.")); + + set_size_and_pos(ui_guard, "guard"); + ui_guard->setToolTip( + tr("Do not listen to mod calls when checked, preventing them from " + "playing sounds or focusing attention on the window.")); + + set_size_and_pos(ui_casing, "casing"); + ui_casing->setToolTip(tr("Lets you receive case alerts when enabled.\n" + "(You can set your preferences in the Settings!)")); + + set_size_and_pos(ui_showname_enable, "showname_enable"); + ui_showname_enable->setToolTip( + tr("Display customized shownames for all users when checked.")); + + set_size_and_pos(ui_custom_objection, "custom_objection"); + ui_custom_objection->setText(tr("Custom Shout!")); + ui_custom_objection->set_image("custom"); + ui_custom_objection->setToolTip( + tr("This will display the custom character-defined animation in the " + "viewport as soon as it is pressed.\n" + "To make one, your character's folder must contain " + "custom.[webp/apng/gif/png] and custom.[wav/ogg/opus] sound effect")); + + set_size_and_pos(ui_realization, "realization"); + ui_realization->set_image("realization"); + ui_realization->setToolTip( + tr("Play realization sound and animation in the viewport on the next " + "spoken message when checked.")); + + set_size_and_pos(ui_screenshake, "screenshake"); + ui_screenshake->set_image("screenshake"); + ui_screenshake->setToolTip( + tr("Shake the screen on next spoken message when checked.")); + + set_size_and_pos(ui_mute, "mute_button"); + ui_mute->setText("Mute"); + ui_mute->set_image("mute"); + ui_mute->setToolTip( + tr("Display the list of character folders you wish to mute.")); + + set_size_and_pos(ui_defense_plus, "defense_plus"); + ui_defense_plus->set_image("defplus"); + ui_defense_plus->setToolTip(tr("Increase the health bar.")); + + set_size_and_pos(ui_defense_minus, "defense_minus"); + ui_defense_minus->set_image("defminus"); + ui_defense_minus->setToolTip(tr("Decrease the health bar.")); + + set_size_and_pos(ui_prosecution_plus, "prosecution_plus"); + ui_prosecution_plus->set_image("proplus"); + ui_prosecution_plus->setToolTip(tr("Increase the health bar.")); + + set_size_and_pos(ui_prosecution_minus, "prosecution_minus"); + ui_prosecution_minus->set_image("prominus"); + ui_prosecution_minus->setToolTip(tr("Decrease the health bar.")); + + set_size_and_pos(ui_text_color, "text_color"); + ui_text_color->setToolTip( + tr("Change the text color of the spoken message.\n" + "You can also select a part of your currently typed message and use " + "the dropdown to change its color!")); + set_text_color_dropdown(); + + set_size_and_pos(ui_music_slider, "music_slider"); + set_size_and_pos(ui_sfx_slider, "sfx_slider"); + set_size_and_pos(ui_blip_slider, "blip_slider"); + + ui_selector->set_image("char_selector"); + ui_selector->hide(); + + set_size_and_pos(ui_back_to_lobby, "back_to_lobby"); + ui_back_to_lobby->setText(tr("Back to Lobby")); + ui_back_to_lobby->setToolTip(tr("Return back to the server list.")); + + set_size_and_pos(ui_char_password, "char_password"); + + set_size_and_pos(ui_char_buttons, "char_buttons"); + + set_size_and_pos(ui_char_select_left, "char_select_left"); + ui_char_select_left->set_image("arrow_left"); + + set_size_and_pos(ui_char_select_right, "char_select_right"); + ui_char_select_right->set_image("arrow_right"); + + set_size_and_pos(ui_spectator, "spectator"); + ui_spectator->setToolTip(tr("Become a spectator. You won't be able to " + "interact with the in-character screen.")); + + refresh_evidence(); } void Courtroom::set_fonts() { - set_font(ui_vp_showname, "", "showname"); - set_font(ui_vp_message, "", "message"); - set_font(ui_ic_chatlog, "", "ic_chatlog"); - set_font(ui_ms_chatlog, "", "ms_chatlog"); - set_font(ui_server_chatlog, "", "server_chatlog"); - set_font(ui_music_list, "", "music_list"); - set_font(ui_area_list, "", "area_list"); - set_font(ui_music_name, "", "music_name"); + set_font(ui_vp_showname, "", "showname"); + set_font(ui_vp_message, "", "message"); + set_font(ui_ic_chatlog, "", "ic_chatlog"); + set_font(ui_ms_chatlog, "", "ms_chatlog"); + set_font(ui_server_chatlog, "", "server_chatlog"); + set_font(ui_music_list, "", "music_list"); + set_font(ui_area_list, "", "area_list"); + set_font(ui_music_name, "", "music_name"); - set_dropdowns(); + set_dropdowns(); } -void Courtroom::set_font(QWidget *widget, QString class_name, QString p_identifier) +void Courtroom::set_font(QWidget *widget, QString class_name, + QString p_identifier) { - QString design_file = "courtroom_fonts.ini"; - int f_pointsize = ao_app->get_font_size(p_identifier, design_file); - QString font_name = ao_app->get_font_name(p_identifier + "_font", design_file); - QColor f_color = ao_app->get_color(p_identifier + "_color", design_file); - bool bold = ao_app->get_font_size(p_identifier + "_bold", design_file) == 1; // is the font bold or not? - bool antialias = ao_app->get_font_size(p_identifier + "_sharp", design_file) != 1; // is the font anti-aliased or not? + QString design_file = "courtroom_fonts.ini"; + int f_pointsize = ao_app->get_font_size(p_identifier, design_file); + QString font_name = + ao_app->get_font_name(p_identifier + "_font", design_file); + QColor f_color = ao_app->get_color(p_identifier + "_color", design_file); + bool bold = ao_app->get_font_size(p_identifier + "_bold", design_file) == + 1; // is the font bold or not? + bool antialias = + ao_app->get_font_size(p_identifier + "_sharp", design_file) != + 1; // is the font anti-aliased or not? - this->set_qfont(widget, class_name, get_qfont(font_name, f_pointsize, antialias), f_color, bold); + this->set_qfont(widget, class_name, + get_qfont(font_name, f_pointsize, antialias), f_color, bold); } QFont Courtroom::get_qfont(QString font_name, int f_pointsize, bool antialias) { - QFont font; - if (font_name.isEmpty()) - font_name = "Arial"; + QFont font; + if (font_name.isEmpty()) + font_name = "Arial"; - QFont::StyleStrategy style_strategy = QFont::PreferDefault; - if (!antialias) - style_strategy = QFont::NoAntialias; + QFont::StyleStrategy style_strategy = QFont::PreferDefault; + if (!antialias) + style_strategy = QFont::NoAntialias; - font = QFont(font_name, f_pointsize); - font.setStyleHint(QFont::SansSerif, style_strategy); - return font; + font = QFont(font_name, f_pointsize); + font.setStyleHint(QFont::SansSerif, style_strategy); + return font; } -void Courtroom::set_qfont(QWidget *widget, QString class_name, QFont font, QColor f_color, bool bold) +void Courtroom::set_qfont(QWidget *widget, QString class_name, QFont font, + QColor f_color, bool bold) { - if (class_name.isEmpty()) - class_name = widget->metaObject()->className(); + if (class_name.isEmpty()) + class_name = widget->metaObject()->className(); - font.setBold(bold); - widget->setFont(font); + font.setBold(bold); + widget->setFont(font); - QString style_sheet_string = class_name + " { background-color: rgba(0, 0, 0, 0);\n" + - "color: rgba(" + - QString::number(f_color.red()) + ", " + - QString::number(f_color.green()) + ", " + - QString::number(f_color.blue()) + ", 255);}"; - widget->setStyleSheet(style_sheet_string); + QString style_sheet_string = + class_name + " { background-color: rgba(0, 0, 0, 0);\n" + "color: rgba(" + + QString::number(f_color.red()) + ", " + QString::number(f_color.green()) + + ", " + QString::number(f_color.blue()) + ", 255);}"; + widget->setStyleSheet(style_sheet_string); } void Courtroom::set_dropdown(QWidget *widget) { - QString f_file = "courtroom_stylesheets.css"; - QString style_sheet_string = ao_app->get_stylesheet(f_file); - if (style_sheet_string != "") - widget->setStyleSheet(style_sheet_string); + QString f_file = "courtroom_stylesheets.css"; + QString style_sheet_string = ao_app->get_stylesheet(f_file); + if (style_sheet_string != "") + widget->setStyleSheet(style_sheet_string); } void Courtroom::set_dropdowns() { - set_dropdown(this); //EXPERIMENTAL - Read the style-sheet as-is for maximum memeage - // set_dropdown(ui_text_color, "[TEXT COLOR]"); - // set_dropdown(ui_pos_dropdown, "[POS DROPDOWN]"); - // set_dropdown(ui_emote_dropdown, "[EMOTE DROPDOWN]"); - // set_dropdown(ui_mute_list, "[MUTE LIST]"); + set_dropdown( + this); // EXPERIMENTAL - Read the style-sheet as-is for maximum memeage + // set_dropdown(ui_text_color, "[TEXT COLOR]"); + // set_dropdown(ui_pos_dropdown, "[POS DROPDOWN]"); + // set_dropdown(ui_emote_dropdown, "[EMOTE DROPDOWN]"); + // set_dropdown(ui_mute_list, "[MUTE LIST]"); } void Courtroom::set_window_title(QString p_title) { - this->setWindowTitle(p_title); + this->setWindowTitle(p_title); } void Courtroom::set_size_and_pos(QWidget *p_widget, QString p_identifier) { - QString filename = "courtroom_design.ini"; + QString filename = "courtroom_design.ini"; - pos_size_type design_ini_result = ao_app->get_element_dimensions(p_identifier, filename); + pos_size_type design_ini_result = + ao_app->get_element_dimensions(p_identifier, filename); - if (design_ini_result.width < 0 || design_ini_result.height < 0) { - qDebug() << "W: could not find \"" << p_identifier << "\" in " << filename; - p_widget->hide(); - } - else { - p_widget->move(design_ini_result.x, design_ini_result.y); - p_widget->resize(design_ini_result.width, design_ini_result.height); - } + if (design_ini_result.width < 0 || design_ini_result.height < 0) { + qDebug() << "W: could not find \"" << p_identifier << "\" in " << filename; + p_widget->hide(); + } + else { + p_widget->move(design_ini_result.x, design_ini_result.y); + p_widget->resize(design_ini_result.width, design_ini_result.height); + } } void Courtroom::set_taken(int n_char, bool p_taken) { - if (n_char >= char_list.size()) { - qDebug() << "W: set_taken attempted to set an index bigger than char_list size"; - return; - } + if (n_char >= char_list.size()) { + qDebug() + << "W: set_taken attempted to set an index bigger than char_list size"; + return; + } - char_type f_char; - f_char.name = char_list.at(n_char).name; - f_char.description = char_list.at(n_char).description; - f_char.taken = p_taken; - f_char.evidence_string = char_list.at(n_char).evidence_string; + char_type f_char; + f_char.name = char_list.at(n_char).name; + f_char.description = char_list.at(n_char).description; + f_char.taken = p_taken; + f_char.evidence_string = char_list.at(n_char).evidence_string; - char_list.replace(n_char, f_char); + char_list.replace(n_char, f_char); } QPoint Courtroom::get_theme_pos(QString p_identifier) { - QString filename = "courtroom_design.ini"; + QString filename = "courtroom_design.ini"; - pos_size_type design_ini_result = ao_app->get_element_dimensions(p_identifier, filename); + pos_size_type design_ini_result = + ao_app->get_element_dimensions(p_identifier, filename); - if (design_ini_result.width < 0 || design_ini_result.height < 0) { - qDebug() << "W: could not find \"" << p_identifier << "\" in " << filename; - return QPoint(0, 0); - } - else { - return QPoint(design_ini_result.x, design_ini_result.y); - } + if (design_ini_result.width < 0 || design_ini_result.height < 0) { + qDebug() << "W: could not find \"" << p_identifier << "\" in " << filename; + return QPoint(0, 0); + } + else { + return QPoint(design_ini_result.x, design_ini_result.y); + } } void Courtroom::done_received() { - m_cid = -1; + m_cid = -1; - music_player->set_volume(0); - sfx_player->set_volume(0); - objection_player->set_volume(0); - blip_player->set_volume(0); + music_player->set_volume(0); + sfx_player->set_volume(0); + objection_player->set_volume(0); + blip_player->set_volume(0); - set_char_select_page(); + set_char_select_page(); - set_mute_list(); - set_pair_list(); + set_mute_list(); + set_pair_list(); - set_char_select(); + set_char_select(); - show(); + show(); - ui_spectator->show(); + ui_spectator->show(); } void Courtroom::set_background(QString p_background, bool display) { - ui_vp_testimony->stop(); - current_background = p_background; + ui_vp_testimony->stop(); + current_background = p_background; - //welcome to hardcode central may I take your order of regularly scheduled CBT - QMap default_pos; - default_pos["defenseempty"] = "def"; - default_pos["helperstand"] = "hld"; - default_pos["prosecutorempty"] = "pro"; - default_pos["prohelperstand"] = "hlp"; - default_pos["witnessempty"] = "wit"; - default_pos["judgestand"] = "jud"; - default_pos["jurystand"] = "jur"; - default_pos["seancestand"] = "sea"; + // welcome to hardcode central may I take your order of regularly scheduled + // CBT + QMap default_pos; + default_pos["defenseempty"] = "def"; + default_pos["helperstand"] = "hld"; + default_pos["prosecutorempty"] = "pro"; + default_pos["prohelperstand"] = "hlp"; + default_pos["witnessempty"] = "wit"; + default_pos["judgestand"] = "jud"; + default_pos["jurystand"] = "jur"; + default_pos["seancestand"] = "sea"; - //Populate the dropdown list with all pos that exist on this bg - QStringList pos_list = {}; - for (QString key : default_pos.keys()) { - if (file_exists(ao_app->get_static_image_suffix(ao_app->get_background_path(key)))) { - pos_list.append(default_pos[key]); - } + // Populate the dropdown list with all pos that exist on this bg + QStringList pos_list = {}; + for (QString key : default_pos.keys()) { + if (file_exists(ao_app->get_static_image_suffix( + ao_app->get_background_path(key)))) { + pos_list.append(default_pos[key]); } + } - //TODO: search through extra/custom pos and add them to the pos dropdown as well + // TODO: search through extra/custom pos and add them to the pos dropdown as + // well - set_pos_dropdown(pos_list); + set_pos_dropdown(pos_list); - is_ao2_bg = true; + is_ao2_bg = true; - if (is_ao2_bg) { - set_size_and_pos(ui_vp_chatbox, "ao2_chatbox"); - set_size_and_pos(ui_ic_chat_message, "ao2_ic_chat_message"); - } - else { - set_size_and_pos(ui_vp_chatbox, "chatbox"); - set_size_and_pos(ui_ic_chat_message, "ic_chat_message"); - } + if (is_ao2_bg) { + set_size_and_pos(ui_vp_chatbox, "ao2_chatbox"); + set_size_and_pos(ui_ic_chat_message, "ao2_ic_chat_message"); + } + else { + set_size_and_pos(ui_vp_chatbox, "chatbox"); + set_size_and_pos(ui_ic_chat_message, "ic_chat_message"); + } - if (display) { - ui_vp_speedlines->stop(); - ui_vp_player_char->stop(); + if (display) { + ui_vp_speedlines->stop(); + ui_vp_player_char->stop(); - ui_vp_sideplayer_char->stop(); - ui_vp_effect->stop(); - ui_vp_message->hide(); - ui_vp_chatbox->hide(); + ui_vp_sideplayer_char->stop(); + ui_vp_effect->stop(); + ui_vp_message->hide(); + ui_vp_chatbox->hide(); - //Stop the chat arrow from animating - ui_vp_chat_arrow->stop(); + // Stop the chat arrow from animating + ui_vp_chat_arrow->stop(); - text_state = 2; - anim_state = 3; - ui_vp_objection->stop(); - chat_tick_timer->stop(); - ui_vp_evidence_display->reset(); - set_scene(QString::number(ao_app->get_desk_mod(current_char, current_emote)), current_side); - } + text_state = 2; + anim_state = 3; + ui_vp_objection->stop(); + chat_tick_timer->stop(); + ui_vp_evidence_display->reset(); + set_scene( + QString::number(ao_app->get_desk_mod(current_char, current_emote)), + current_side); + } } void Courtroom::set_side(QString p_side) { - if (p_side == "") - current_side = ao_app->get_char_side(current_char); - else - current_side = p_side; + if (p_side == "") + current_side = ao_app->get_char_side(current_char); + else + current_side = p_side; - for (int i = 0; i < ui_pos_dropdown->count(); ++i) { - QString pos = ui_pos_dropdown->itemText(i); - if (pos == current_side) { - //Block the signals to prevent setCurrentIndex from triggering a pos change - ui_pos_dropdown->blockSignals(true); + for (int i = 0; i < ui_pos_dropdown->count(); ++i) { + QString pos = ui_pos_dropdown->itemText(i); + if (pos == current_side) { + // Block the signals to prevent setCurrentIndex from triggering a pos + // change + ui_pos_dropdown->blockSignals(true); - //Set the index on dropdown ui element to let you know what pos you're on right now - ui_pos_dropdown->setCurrentIndex(i); + // Set the index on dropdown ui element to let you know what pos you're on + // right now + ui_pos_dropdown->setCurrentIndex(i); - //Unblock the signals so the element can be used for setting pos again - ui_pos_dropdown->blockSignals(false); + // Unblock the signals so the element can be used for setting pos again + ui_pos_dropdown->blockSignals(false); - //alright we dun, jobs done here boyos - break; - } + // alright we dun, jobs done here boyos + break; } + } } void Courtroom::set_pos_dropdown(QStringList pos_dropdowns) { - //Block the signals to prevent setCurrentIndex from triggering a pos change - ui_pos_dropdown->blockSignals(true); - pos_dropdown_list = pos_dropdowns; - ui_pos_dropdown->clear(); - ui_pos_dropdown->addItems(pos_dropdown_list); - //Unblock the signals so the element can be used for setting pos again - ui_pos_dropdown->blockSignals(false); + // Block the signals to prevent setCurrentIndex from triggering a pos change + ui_pos_dropdown->blockSignals(true); + pos_dropdown_list = pos_dropdowns; + ui_pos_dropdown->clear(); + ui_pos_dropdown->addItems(pos_dropdown_list); + // Unblock the signals so the element can be used for setting pos again + ui_pos_dropdown->blockSignals(false); - qDebug() << pos_dropdown_list; + qDebug() << pos_dropdown_list; } void Courtroom::update_character(int p_cid) { - bool newchar = m_cid != p_cid; + bool newchar = m_cid != p_cid; - m_cid = p_cid; + m_cid = p_cid; - QString f_char; + QString f_char; - if (m_cid == -1) { - if (ao_app->is_discord_enabled()) - ao_app->discord->state_spectate(); - f_char = ""; - } - else { - f_char = ao_app->get_char_name(char_list.at(m_cid).name); + if (m_cid == -1) { + if (ao_app->is_discord_enabled()) + ao_app->discord->state_spectate(); + f_char = ""; + } + else { + f_char = ao_app->get_char_name(char_list.at(m_cid).name); - if (ao_app->is_discord_enabled()) - ao_app->discord->state_character(f_char.toStdString()); - } + if (ao_app->is_discord_enabled()) + ao_app->discord->state_character(f_char.toStdString()); + } - current_char = f_char; - current_side = ao_app->get_char_side(current_char); + current_char = f_char; + current_side = ao_app->get_char_side(current_char); - current_emote_page = 0; - current_emote = 0; + current_emote_page = 0; + current_emote = 0; - if (m_cid == -1) - ui_emotes->hide(); - else - ui_emotes->show(); + if (m_cid == -1) + ui_emotes->hide(); + else + ui_emotes->show(); - refresh_emotes(); - set_emote_page(); - set_emote_dropdown(); + refresh_emotes(); + set_emote_page(); + set_emote_dropdown(); - set_sfx_dropdown(); - set_effects_dropdown(); + set_sfx_dropdown(); + set_effects_dropdown(); - qDebug() << "update_character called"; - if (newchar) //Avoid infinite loop of death and suffering - set_iniswap_dropdown(); + qDebug() << "update_character called"; + if (newchar) // Avoid infinite loop of death and suffering + set_iniswap_dropdown(); - if (current_side == "jud") { - ui_witness_testimony->show(); - ui_cross_examination->show(); - ui_not_guilty->show(); - ui_guilty->show(); - ui_defense_minus->show(); - ui_defense_plus->show(); - ui_prosecution_minus->show(); - ui_prosecution_plus->show(); - } - else { - ui_witness_testimony->hide(); - ui_cross_examination->hide(); - ui_guilty->hide(); - ui_not_guilty->hide(); - ui_defense_minus->hide(); - ui_defense_plus->hide(); - ui_prosecution_minus->hide(); - ui_prosecution_plus->hide(); - } + if (current_side == "jud") { + ui_witness_testimony->show(); + ui_cross_examination->show(); + ui_not_guilty->show(); + ui_guilty->show(); + ui_defense_minus->show(); + ui_defense_plus->show(); + ui_prosecution_minus->show(); + ui_prosecution_plus->show(); + } + else { + ui_witness_testimony->hide(); + ui_cross_examination->hide(); + ui_guilty->hide(); + ui_not_guilty->hide(); + ui_defense_minus->hide(); + ui_defense_plus->hide(); + ui_prosecution_minus->hide(); + ui_prosecution_plus->hide(); + } - if (ao_app->custom_objection_enabled && file_exists(ao_app->get_image_suffix(ao_app->get_character_path(current_char, "custom")))) - ui_custom_objection->show(); - else - ui_custom_objection->hide(); + if (ao_app->custom_objection_enabled && + file_exists(ao_app->get_image_suffix( + ao_app->get_character_path(current_char, "custom")))) + ui_custom_objection->show(); + else + ui_custom_objection->hide(); - ui_char_select_background->hide(); - ui_ic_chat_message->setEnabled(m_cid != -1); - ui_ic_chat_message->setFocus(); + ui_char_select_background->hide(); + ui_ic_chat_message->setEnabled(m_cid != -1); + ui_ic_chat_message->setFocus(); } void Courtroom::enter_courtroom() { - set_widgets(); + set_widgets(); - current_evidence_page = 0; - current_evidence = 0; + current_evidence_page = 0; + current_evidence = 0; - set_evidence_page(); + set_evidence_page(); - if (ao_app->flipping_enabled) - ui_flip->show(); - else - ui_flip->hide(); + if (ao_app->flipping_enabled) + ui_flip->show(); + else + ui_flip->hide(); - if (ao_app->additive_enabled) - ui_additive->show(); - else - ui_additive->hide(); + if (ao_app->additive_enabled) + ui_additive->show(); + else + ui_additive->hide(); - if (ao_app->casing_alerts_enabled) - ui_casing->show(); - else - ui_casing->hide(); + if (ao_app->casing_alerts_enabled) + ui_casing->show(); + else + ui_casing->hide(); - list_music(); - list_areas(); + list_music(); + list_areas(); - music_player->set_volume(ui_music_slider->value(), 0); //set music - //Set the ambience and other misc. music layers - for (int i = 1; i < music_player->m_channelmax; ++i) { - music_player->set_volume(ui_sfx_slider->value(), i); - } - sfx_player->set_volume(ui_sfx_slider->value()); - objection_player->set_volume(ui_sfx_slider->value()); - blip_player->set_volume(ui_blip_slider->value()); + music_player->set_volume(ui_music_slider->value(), 0); // set music + // Set the ambience and other misc. music layers + for (int i = 1; i < music_player->m_channelmax; ++i) { + music_player->set_volume(ui_sfx_slider->value(), i); + } + sfx_player->set_volume(ui_sfx_slider->value()); + objection_player->set_volume(ui_sfx_slider->value()); + blip_player->set_volume(ui_blip_slider->value()); - ui_vp_testimony->stop(); - //ui_server_chatlog->setHtml(ui_server_chatlog->toHtml()); + ui_vp_testimony->stop(); + // ui_server_chatlog->setHtml(ui_server_chatlog->toHtml()); } -//Todo: multithread this due to some servers having large as hell music list +// Todo: multithread this due to some servers having large as hell music list void Courtroom::list_music() { - ui_music_list->clear(); - // ui_music_search->setText(""); + ui_music_list->clear(); + // ui_music_search->setText(""); - QString f_file = "courtroom_design.ini"; + QString f_file = "courtroom_design.ini"; - QBrush found_brush(ao_app->get_color("found_song_color", f_file)); - QBrush missing_brush(ao_app->get_color("missing_song_color", f_file)); + QBrush found_brush(ao_app->get_color("found_song_color", f_file)); + QBrush missing_brush(ao_app->get_color("missing_song_color", f_file)); - int n_listed_songs = 0; + int n_listed_songs = 0; - QTreeWidgetItem *parent = nullptr; - for (int n_song = 0; n_song < music_list.size(); ++n_song) { - QString i_song = music_list.at(n_song); - QString i_song_listname = i_song.left(i_song.lastIndexOf(".")); - i_song_listname = i_song_listname.right(i_song_listname.length() - (i_song_listname.lastIndexOf("/") + 1)); + QTreeWidgetItem *parent = nullptr; + for (int n_song = 0; n_song < music_list.size(); ++n_song) { + QString i_song = music_list.at(n_song); + QString i_song_listname = i_song.left(i_song.lastIndexOf(".")); + i_song_listname = i_song_listname.right( + i_song_listname.length() - (i_song_listname.lastIndexOf("/") + 1)); - QTreeWidgetItem *treeItem; - if (i_song_listname != i_song && parent != nullptr) //not a category, parent exists - treeItem = new QTreeWidgetItem(parent); - else - treeItem = new QTreeWidgetItem(ui_music_list); - treeItem->setText(0, i_song_listname); - treeItem->setText(1, i_song); + QTreeWidgetItem *treeItem; + if (i_song_listname != i_song && + parent != nullptr) // not a category, parent exists + treeItem = new QTreeWidgetItem(parent); + else + treeItem = new QTreeWidgetItem(ui_music_list); + treeItem->setText(0, i_song_listname); + treeItem->setText(1, i_song); - QString song_path = ao_app->get_music_path(i_song); + QString song_path = ao_app->get_music_path(i_song); - if (file_exists(song_path)) - treeItem->setBackground(0, found_brush); - else - treeItem->setBackground(0, missing_brush); + if (file_exists(song_path)) + treeItem->setBackground(0, found_brush); + else + treeItem->setBackground(0, missing_brush); - if (i_song_listname == i_song) //Not supposed to be a song to begin with - a category? - parent = treeItem; - ++n_listed_songs; - } + if (i_song_listname == + i_song) // Not supposed to be a song to begin with - a category? + parent = treeItem; + ++n_listed_songs; + } - ui_music_list->expandAll(); //Needs to somehow remember which categories were expanded/collapsed if the music list didn't change since last time - if (ui_music_search->text() != "") { - on_music_search_edited(ui_music_search->text()); - } + ui_music_list->expandAll(); // Needs to somehow remember which categories were + // expanded/collapsed if the music list didn't + // change since last time + if (ui_music_search->text() != "") { + on_music_search_edited(ui_music_search->text()); + } } -//Todo: multithread this due to some servers having large as hell area list +// Todo: multithread this due to some servers having large as hell area list void Courtroom::list_areas() { - ui_area_list->clear(); - // ui_music_search->setText(""); + ui_area_list->clear(); + // ui_music_search->setText(""); - QString f_file = "courtroom_design.ini"; + QString f_file = "courtroom_design.ini"; - QBrush free_brush(ao_app->get_color("area_free_color", f_file)); - QBrush lfp_brush(ao_app->get_color("area_lfp_color", f_file)); - QBrush casing_brush(ao_app->get_color("area_casing_color", f_file)); - QBrush recess_brush(ao_app->get_color("area_recess_color", f_file)); - QBrush rp_brush(ao_app->get_color("area_rp_color", f_file)); - QBrush gaming_brush(ao_app->get_color("area_gaming_color", f_file)); - QBrush locked_brush(ao_app->get_color("area_locked_color", f_file)); + QBrush free_brush(ao_app->get_color("area_free_color", f_file)); + QBrush lfp_brush(ao_app->get_color("area_lfp_color", f_file)); + QBrush casing_brush(ao_app->get_color("area_casing_color", f_file)); + QBrush recess_brush(ao_app->get_color("area_recess_color", f_file)); + QBrush rp_brush(ao_app->get_color("area_rp_color", f_file)); + QBrush gaming_brush(ao_app->get_color("area_gaming_color", f_file)); + QBrush locked_brush(ao_app->get_color("area_locked_color", f_file)); - int n_listed_areas = 0; + int n_listed_areas = 0; - for (int n_area = 0; n_area < area_list.size(); ++n_area) { - QString i_area = ""; - i_area.append(area_list.at(n_area)); + for (int n_area = 0; n_area < area_list.size(); ++n_area) { + QString i_area = ""; + i_area.append(area_list.at(n_area)); - if (ao_app->arup_enabled) { - i_area.prepend("[" + QString::number(n_area) + "] "); //Give it the index + if (ao_app->arup_enabled) { + i_area.prepend("[" + QString::number(n_area) + "] "); // Give it the index - i_area.append("\n "); + i_area.append("\n "); - i_area.append(arup_statuses.at(n_area)); - i_area.append(" | CM: "); - i_area.append(arup_cms.at(n_area)); + i_area.append(arup_statuses.at(n_area)); + i_area.append(" | CM: "); + i_area.append(arup_cms.at(n_area)); - i_area.append("\n "); + i_area.append("\n "); - i_area.append(QString::number(arup_players.at(n_area))); - i_area.append(" users | "); + i_area.append(QString::number(arup_players.at(n_area))); + i_area.append(" users | "); - i_area.append(arup_locks.at(n_area)); - } - - QTreeWidgetItem *treeItem = new QTreeWidgetItem(ui_area_list); - treeItem->setText(0, area_list.at(n_area)); - treeItem->setText(1, i_area); - - if (ao_app->arup_enabled) { - // 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); - } - } - else { - treeItem->setBackground(1, free_brush); - } - - ++n_listed_areas; + i_area.append(arup_locks.at(n_area)); } - if (ui_music_search->text() != "") { - on_music_search_edited(ui_music_search->text()); + QTreeWidgetItem *treeItem = new QTreeWidgetItem(ui_area_list); + treeItem->setText(0, area_list.at(n_area)); + treeItem->setText(1, i_area); + + if (ao_app->arup_enabled) { + // 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); + } } + else { + treeItem->setBackground(1, free_brush); + } + + ++n_listed_areas; + } + + if (ui_music_search->text() != "") { + on_music_search_edited(ui_music_search->text()); + } } void Courtroom::append_ms_chatmessage(QString f_name, QString f_message) { - ui_ms_chatlog->append_chatmessage(f_name, f_message, ao_app->get_color("ms_chatlog_sender_color", "courtroom_fonts.ini").name()); + ui_ms_chatlog->append_chatmessage( + f_name, f_message, + ao_app->get_color("ms_chatlog_sender_color", "courtroom_fonts.ini") + .name()); } -void Courtroom::append_server_chatmessage(QString p_name, QString p_message, QString p_color) +void Courtroom::append_server_chatmessage(QString p_name, QString p_message, + QString p_color) { - QString color = "#000000"; + QString color = "#000000"; - if (p_color == "0") - color = ao_app->get_color("ms_chatlog_sender_color", "courtroom_fonts.ini").name(); - if (p_color == "1") - color = ao_app->get_color("server_chatlog_sender_color", "courtroom_fonts.ini").name(); - if (p_message == "Logged in as a moderator.") { - ui_guard->show(); - append_server_chatmessage("CLIENT", "You were granted the Disable Modcalls button.", "1"); - } + if (p_color == "0") + color = ao_app->get_color("ms_chatlog_sender_color", "courtroom_fonts.ini") + .name(); + if (p_color == "1") + color = + ao_app->get_color("server_chatlog_sender_color", "courtroom_fonts.ini") + .name(); + if (p_message == "Logged in as a moderator.") { + ui_guard->show(); + append_server_chatmessage( + "CLIENT", "You were granted the Disable Modcalls button.", "1"); + } - ui_server_chatlog->append_chatmessage(p_name, p_message, color); + ui_server_chatlog->append_chatmessage(p_name, p_message, color); } void Courtroom::on_chat_return_pressed() { - if (ui_ic_chat_message->text() == "" || is_muted) - return; + if (ui_ic_chat_message->text() == "" || is_muted) + return; - if ((anim_state < 3 || text_state < 2) && - objection_state == 0) - return; + if ((anim_state < 3 || text_state < 2) && objection_state == 0) + return; - //MS# - //deskmod# - //pre-emote# - //character# - //emote# - //message# - //side# - //sfx-name# - //emote_modifier# - //char_id# - //sfx_delay# - //objection_modifier# - //evidence# - //placeholder# - //realization# - //text_color#% + // MS# + // deskmod# + // pre-emote# + // character# + // emote# + // message# + // side# + // sfx-name# + // emote_modifier# + // char_id# + // sfx_delay# + // objection_modifier# + // evidence# + // placeholder# + // realization# + // text_color#% - // Additionally, in our case: + // Additionally, in our case: - //showname# - //other_charid# - //self_offset# - //noninterrupting_preanim#% + // showname# + // other_charid# + // self_offset# + // noninterrupting_preanim#% - QStringList packet_contents; + QStringList packet_contents; - if (current_side == "") - current_side = ao_app->get_char_side(current_char); + if (current_side == "") + current_side = ao_app->get_char_side(current_char); - QString f_desk_mod = "chat"; + QString f_desk_mod = "chat"; - if (ao_app->desk_mod_enabled) { - f_desk_mod = QString::number(ao_app->get_desk_mod(current_char, current_emote)); - if (f_desk_mod == "-1") - f_desk_mod = "chat"; + if (ao_app->desk_mod_enabled) { + f_desk_mod = + QString::number(ao_app->get_desk_mod(current_char, current_emote)); + if (f_desk_mod == "-1") + f_desk_mod = "chat"; + } + + packet_contents.append(f_desk_mod); + + packet_contents.append(ao_app->get_pre_emote(current_char, current_emote)); + + packet_contents.append(current_char); + + packet_contents.append(ao_app->get_emote(current_char, current_emote)); + + packet_contents.append(ui_ic_chat_message->text()); + + packet_contents.append(current_side); + + packet_contents.append(get_char_sfx()); + if (ui_pre->isChecked() && !ao_app->is_stickysounds_enabled()) { + ui_sfx_dropdown->blockSignals(true); + ui_sfx_dropdown->setCurrentIndex(0); + ui_sfx_dropdown->blockSignals(false); + ui_sfx_remove->hide(); + } + + int f_emote_mod = ao_app->get_emote_mod(current_char, current_emote); + + // needed or else legacy won't understand what we're saying + if (objection_state > 0) { + if (ui_pre->isChecked()) { + if (f_emote_mod == 4 || f_emote_mod == 5) + f_emote_mod = 6; + else + f_emote_mod = 2; } + } + else if (ui_pre->isChecked() and !ui_pre_non_interrupt->isChecked()) { + if (f_emote_mod == 0) + f_emote_mod = 1; + else if (f_emote_mod == 5 && ao_app->prezoom_enabled) + f_emote_mod = 4; + } + else { + if (f_emote_mod == 1) + f_emote_mod = 0; + else if (f_emote_mod == 4) + f_emote_mod = 5; + } - packet_contents.append(f_desk_mod); + packet_contents.append(QString::number(f_emote_mod)); + packet_contents.append(QString::number(m_cid)); - packet_contents.append(ao_app->get_pre_emote(current_char, current_emote)); + packet_contents.append(QString::number(get_char_sfx_delay())); - packet_contents.append(current_char); + QString f_obj_state; - packet_contents.append(ao_app->get_emote(current_char, current_emote)); + if ((objection_state == 4 && !ao_app->custom_objection_enabled) || + (objection_state < 0)) + f_obj_state = "0"; + else + f_obj_state = QString::number(objection_state); - packet_contents.append(ui_ic_chat_message->text()); + packet_contents.append(f_obj_state); - packet_contents.append(current_side); + if (is_presenting_evidence) + // the evidence index is shifted by 1 because 0 is no evidence per legacy + // standards besides, older clients crash if we pass -1 + packet_contents.append(QString::number(current_evidence + 1)); + else + packet_contents.append("0"); - packet_contents.append(get_char_sfx()); - if (ui_pre->isChecked() && !ao_app->is_stickysounds_enabled()) { - ui_sfx_dropdown->blockSignals(true); - ui_sfx_dropdown->setCurrentIndex(0); - ui_sfx_dropdown->blockSignals(false); - ui_sfx_remove->hide(); - } + QString f_flip; - int f_emote_mod = ao_app->get_emote_mod(current_char, current_emote); + if (ao_app->flipping_enabled) { + if (ui_flip->isChecked()) + f_flip = "1"; + else + f_flip = "0"; + } + else + f_flip = QString::number(m_cid); - //needed or else legacy won't understand what we're saying - if (objection_state > 0) { - if (ui_pre->isChecked()) { - if (f_emote_mod == 4 || f_emote_mod == 5) - f_emote_mod = 6; - else - f_emote_mod = 2; - } - } - else if (ui_pre->isChecked() and !ui_pre_non_interrupt->isChecked()) { - if (f_emote_mod == 0) - f_emote_mod = 1; - else if (f_emote_mod == 5 && ao_app->prezoom_enabled) - f_emote_mod = 4; + packet_contents.append(f_flip); + + packet_contents.append(QString::number(realization_state)); + + QString f_text_color; + + if (text_color < 0) + f_text_color = "0"; + else if (text_color > max_colors) + f_text_color = "0"; + else + f_text_color = QString::number(text_color); + + packet_contents.append(f_text_color); + + // If the server we're on supports CCCC stuff, we should use it! + if (ao_app->cccc_ic_support_enabled) { + // 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 { - if (f_emote_mod == 1) - f_emote_mod = 0; - else if (f_emote_mod == 4) - f_emote_mod = 5; + packet_contents.append(""); } - packet_contents.append(QString::number(f_emote_mod)); - packet_contents.append(QString::number(m_cid)); - - packet_contents.append(QString::number(get_char_sfx_delay())); - - QString f_obj_state; - - if ((objection_state == 4 && !ao_app->custom_objection_enabled) || - (objection_state < 0)) - f_obj_state = "0"; - else - f_obj_state = QString::number(objection_state); - - packet_contents.append(f_obj_state); - - if (is_presenting_evidence) - //the evidence index is shifted by 1 because 0 is no evidence per legacy standards - //besides, older clients crash if we pass -1 - packet_contents.append(QString::number(current_evidence + 1)); - else - packet_contents.append("0"); - - QString f_flip; - - if (ao_app->flipping_enabled) { - if (ui_flip->isChecked()) - f_flip = "1"; - else - f_flip = "0"; + // 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_enabled) // Only servers with effects enabled will + // support pair reordering + packet += "^" + QString::number(pair_order); + packet_contents.append(packet); } - else - f_flip = QString::number(m_cid); - - packet_contents.append(f_flip); - - packet_contents.append(QString::number(realization_state)); - - QString f_text_color; - - if (text_color < 0) - f_text_color = "0"; - else if (text_color > max_colors) - f_text_color = "0"; - else - f_text_color = QString::number(text_color); - - packet_contents.append(f_text_color); - - // If the server we're on supports CCCC stuff, we should use it! - if (ao_app->cccc_ic_support_enabled) { - // 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_enabled) //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 - packet_contents.append(QString::number(char_offset)); - - // Finally, we send over if we want our pres to not interrupt. - if (ui_pre_non_interrupt->isChecked() && ui_pre->isChecked()) { - packet_contents.append("1"); - } - else { - packet_contents.append("0"); - } + else { + packet_contents.append("-1"); } + // Send the offset as it's gonna be used regardless + packet_contents.append(QString::number(char_offset)); - // If the server we're on supports Looping SFX and Screenshake, use it if the emote uses it. - if (ao_app->looping_sfx_support_enabled) { - packet_contents.append("0"); //ao_app->get_sfx_looping(current_char, current_emote)); - packet_contents.append(QString::number(screenshake_state)); + // Finally, we send over if we want our pres to not interrupt. + if (ui_pre_non_interrupt->isChecked() && ui_pre->isChecked()) { + packet_contents.append("1"); + } + else { + packet_contents.append("0"); + } + } - 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"}; + // If the server we're on supports Looping SFX and Screenshake, use it if the + // emote uses it. + if (ao_app->looping_sfx_support_enabled) { + packet_contents.append( + "0"); // ao_app->get_sfx_looping(current_char, current_emote)); + packet_contents.append(QString::number(screenshake_state)); - foreach (QString f_effect, effects_to_check) { - QString packet; - foreach (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 += "^"; - } - packet_contents.append(packet); + 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 (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 += "^"; + } + packet_contents.append(packet); } + } - if (ao_app->additive_enabled) { - packet_contents.append(ui_additive->isChecked() ? "1" : "0"); - } - if (ao_app->effects_enabled) { - QString fx_sound = ao_app->get_effect_sound(effect, current_char); - QString p_effect = ao_app->read_char_ini(current_char, "effects", "Options"); - packet_contents.append(effect + "|" + p_effect + "|" + fx_sound); - if (!ao_app->is_stickyeffects_enabled()) { - ui_effects_dropdown->blockSignals(true); - ui_effects_dropdown->setCurrentIndex(0); - ui_effects_dropdown->blockSignals(false); - effect = ""; - } + if (ao_app->additive_enabled) { + packet_contents.append(ui_additive->isChecked() ? "1" : "0"); + } + if (ao_app->effects_enabled) { + QString fx_sound = ao_app->get_effect_sound(effect, current_char); + QString p_effect = + ao_app->read_char_ini(current_char, "effects", "Options"); + packet_contents.append(effect + "|" + p_effect + "|" + fx_sound); + if (!ao_app->is_stickyeffects_enabled()) { + ui_effects_dropdown->blockSignals(true); + ui_effects_dropdown->setCurrentIndex(0); + ui_effects_dropdown->blockSignals(false); + effect = ""; } + } - ao_app->send_server_packet(new AOPacket("MS", packet_contents)); + ao_app->send_server_packet(new AOPacket("MS", packet_contents)); } void Courtroom::handle_chatmessage(QStringList *p_contents) { - // Instead of checking for whether a message has at least chatmessage_size - // amount of packages, we'll check if it has at least 15. - // That was the original chatmessage_size. - if (p_contents->size() < 15) - return; + // Instead of checking for whether a message has at least chatmessage_size + // amount of packages, we'll check if it has at least 15. + // That was the original chatmessage_size. + if (p_contents->size() < 15) + return; - for (int n_string = 0; n_string < chatmessage_size; ++n_string) { - //m_chatmessage[n_string] = p_contents->at(n_string); + for (int n_string = 0; n_string < chatmessage_size; ++n_string) { + // m_chatmessage[n_string] = p_contents->at(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 < 15 || ao_app->cccc_ic_support_enabled)) { - m_chatmessage[n_string] = p_contents->at(n_string); - } - else { - m_chatmessage[n_string] = ""; - } - } - - int f_char_id = m_chatmessage[CHAR_ID].toInt(); - - if (f_char_id >= 0 && f_char_id >= char_list.size()) - return; - - if (mute_map.value(m_chatmessage[CHAR_ID].toInt())) - return; - - QString f_showname; - if (f_char_id > 0 && (m_chatmessage[SHOWNAME].isEmpty() || !ui_showname_enable->isChecked())) { - f_showname = ao_app->get_showname(char_list.at(f_char_id).name); + // 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 < 15 || ao_app->cccc_ic_support_enabled)) { + m_chatmessage[n_string] = p_contents->at(n_string); } else { - f_showname = m_chatmessage[SHOWNAME]; + m_chatmessage[n_string] = ""; } + } - if (f_showname.trimmed().isEmpty()) //Pure whitespace showname, get outta here. - f_showname = m_chatmessage[CHAR_NAME]; + int f_char_id = m_chatmessage[CHAR_ID].toInt(); - QString f_message = f_showname + ": " + m_chatmessage[MESSAGE] + '\n'; - //Remove undesired newline chars - m_chatmessage[MESSAGE].remove("\n"); - chatmessage_is_empty = m_chatmessage[MESSAGE] == " " || m_chatmessage[MESSAGE] == ""; + if (f_char_id >= 0 && f_char_id >= char_list.size()) + return; - if (f_char_id >= 0 && !chatmessage_is_empty && f_message == previous_ic_message) //Not a system message - return; + if (mute_map.value(m_chatmessage[CHAR_ID].toInt())) + return; - if (f_char_id <= -1) - previous_ic_message = ""; //System messages don't care about repeating themselves - else - previous_ic_message = f_message; + QString f_showname; + if (f_char_id > 0 && + (m_chatmessage[SHOWNAME].isEmpty() || !ui_showname_enable->isChecked())) { + f_showname = ao_app->get_showname(char_list.at(f_char_id).name); + } + else { + f_showname = m_chatmessage[SHOWNAME]; + } - //Stop the chat arrow from animating - ui_vp_chat_arrow->stop(); + if (f_showname.trimmed() + .isEmpty()) // Pure whitespace showname, get outta here. + f_showname = m_chatmessage[CHAR_NAME]; - text_state = 0; - anim_state = 0; - ui_vp_objection->stop(); - chat_tick_timer->stop(); - ui_vp_evidence_display->reset(); + QString f_message = f_showname + ": " + m_chatmessage[MESSAGE] + '\n'; + // Remove undesired newline chars + m_chatmessage[MESSAGE].remove("\n"); + chatmessage_is_empty = + m_chatmessage[MESSAGE] == " " || m_chatmessage[MESSAGE] == ""; - //Hey, our message showed up! Cool! - if (m_chatmessage[MESSAGE] == ui_ic_chat_message->text().remove("\n") && m_chatmessage[CHAR_ID].toInt() == m_cid) { - ui_ic_chat_message->clear(); - if (ui_additive->isChecked()) - ui_ic_chat_message->insert(" "); - objection_state = 0; - realization_state = 0; - screenshake_state = 0; - is_presenting_evidence = false; - if (!ao_app->is_stickypres_enabled()) - ui_pre->setChecked(false); - ui_hold_it->set_image("holdit"); - ui_objection->set_image("objection"); - ui_take_that->set_image("takethat"); - ui_custom_objection->set_image("custom"); - ui_realization->set_image("realization"); - ui_screenshake->set_image("screenshake"); - ui_evidence_present->set_image("present"); + if (f_char_id >= 0 && !chatmessage_is_empty && + f_message == previous_ic_message) // Not a system message + return; + + if (f_char_id <= -1) + previous_ic_message = + ""; // System messages don't care about repeating themselves + else + previous_ic_message = f_message; + + // Stop the chat arrow from animating + ui_vp_chat_arrow->stop(); + + text_state = 0; + anim_state = 0; + ui_vp_objection->stop(); + chat_tick_timer->stop(); + ui_vp_evidence_display->reset(); + + // Hey, our message showed up! Cool! + if (m_chatmessage[MESSAGE] == ui_ic_chat_message->text().remove("\n") && + m_chatmessage[CHAR_ID].toInt() == m_cid) { + ui_ic_chat_message->clear(); + if (ui_additive->isChecked()) + ui_ic_chat_message->insert(" "); + objection_state = 0; + realization_state = 0; + screenshake_state = 0; + is_presenting_evidence = false; + if (!ao_app->is_stickypres_enabled()) + ui_pre->setChecked(false); + ui_hold_it->set_image("holdit"); + ui_objection->set_image("objection"); + ui_take_that->set_image("takethat"); + ui_custom_objection->set_image("custom"); + ui_realization->set_image("realization"); + ui_screenshake->set_image("screenshake"); + ui_evidence_present->set_image("present"); + } + + // Let the server handle actually checking if they're allowed to do this. + is_additive = m_chatmessage[ADDITIVE].toInt() == 1; + + QString f_charname = ""; + if (f_char_id >= 0) + f_charname = ao_app->get_showname(char_list.at(f_char_id).name); + + chatlogpiece *temp = + new chatlogpiece(f_charname, f_showname, m_chatmessage[MESSAGE], false); + ic_chatlog_history.append(*temp); + ao_app->append_to_file(temp->get_full(), ao_app->log_filename, true); + + while (ic_chatlog_history.size() > log_maximum_blocks && + log_maximum_blocks > 0) { + ic_chatlog_history.removeFirst(); + } + + append_ic_text(m_chatmessage[MESSAGE], f_showname); + + int objection_mod = m_chatmessage[OBJECTION_MOD].toInt(); + QString f_char = m_chatmessage[CHAR_NAME]; + QString f_custom_theme = ao_app->get_char_shouts(f_char); + + // if an objection is used + if (objection_mod <= 4 && objection_mod >= 1) { + switch (objection_mod) { + case 1: + ui_vp_objection->play("holdit_bubble", f_char, f_custom_theme, 724); + objection_player->play("holdit", f_char, f_custom_theme); + break; + case 2: + ui_vp_objection->play("objection_bubble", f_char, f_custom_theme, 724); + objection_player->play("objection", f_char, f_custom_theme); + if (ao_app->objection_stop_music()) + music_player->stop(); + break; + case 3: + ui_vp_objection->play("takethat_bubble", f_char, f_custom_theme, 724); + objection_player->play("takethat", f_char, f_custom_theme); + break; + // case 4 is AO2 only + case 4: + ui_vp_objection->play("custom", f_char, f_custom_theme, 724); + objection_player->play("custom", f_char, f_custom_theme); + break; + default: + qDebug() << "W: Logic error in objection switch statement!"; } + sfx_player->clear(); // Objection played! Cut all sfx. + int emote_mod = m_chatmessage[EMOTE_MOD].toInt(); - //Let the server handle actually checking if they're allowed to do this. - is_additive = m_chatmessage[ADDITIVE].toInt() == 1; - - QString f_charname = ""; - if (f_char_id >= 0) - f_charname = ao_app->get_showname(char_list.at(f_char_id).name); - - chatlogpiece *temp = new chatlogpiece(f_charname, f_showname, m_chatmessage[MESSAGE], false); - ic_chatlog_history.append(*temp); - ao_app->append_to_file(temp->get_full(), ao_app->log_filename, true); - - while (ic_chatlog_history.size() > log_maximum_blocks && log_maximum_blocks > 0) { - ic_chatlog_history.removeFirst(); - } - - append_ic_text(m_chatmessage[MESSAGE], f_showname); - - int objection_mod = m_chatmessage[OBJECTION_MOD].toInt(); - QString f_char = m_chatmessage[CHAR_NAME]; - QString f_custom_theme = ao_app->get_char_shouts(f_char); - - //if an objection is used - if (objection_mod <= 4 && objection_mod >= 1) { - switch (objection_mod) { - case 1: - ui_vp_objection->play("holdit_bubble", f_char, f_custom_theme, 724); - objection_player->play("holdit", f_char, f_custom_theme); - break; - case 2: - ui_vp_objection->play("objection_bubble", f_char, f_custom_theme, 724); - objection_player->play("objection", f_char, f_custom_theme); - if (ao_app->objection_stop_music()) - music_player->stop(); - break; - case 3: - ui_vp_objection->play("takethat_bubble", f_char, f_custom_theme, 724); - objection_player->play("takethat", f_char, f_custom_theme); - break; - //case 4 is AO2 only - case 4: - ui_vp_objection->play("custom", f_char, f_custom_theme, 724); - objection_player->play("custom", f_char, f_custom_theme); - break; - default: - qDebug() << "W: Logic error in objection switch statement!"; - } - sfx_player->clear(); //Objection played! Cut all sfx. - int emote_mod = m_chatmessage[EMOTE_MOD].toInt(); - - if (emote_mod == 0) - m_chatmessage[EMOTE_MOD] = 1; - } - else - handle_chatmessage_2(); -} - -void Courtroom::objection_done() -{ + if (emote_mod == 0) + m_chatmessage[EMOTE_MOD] = 1; + } + else handle_chatmessage_2(); } +void Courtroom::objection_done() { handle_chatmessage_2(); } + void Courtroom::handle_chatmessage_2() { - ui_vp_speedlines->stop(); - ui_vp_player_char->stop(); - ui_vp_effect->stop(); - //Clear all looping sfx to prevent obnoxiousness - sfx_player->loop_clear(); + ui_vp_speedlines->stop(); + ui_vp_player_char->stop(); + ui_vp_effect->stop(); + // Clear all looping sfx to prevent obnoxiousness + sfx_player->loop_clear(); - if (!m_chatmessage[FRAME_SFX].isEmpty() && ao_app->is_frame_network_enabled()) { - //ORDER IS IMPORTANT!! - QStringList netstrings = {m_chatmessage[FRAME_SCREENSHAKE], m_chatmessage[FRAME_REALIZATION], m_chatmessage[FRAME_SFX]}; - ui_vp_player_char->network_strings = netstrings; - } - else - ui_vp_player_char->network_strings.clear(); + if (!m_chatmessage[FRAME_SFX].isEmpty() && + ao_app->is_frame_network_enabled()) { + // ORDER IS IMPORTANT!! + QStringList netstrings = {m_chatmessage[FRAME_SCREENSHAKE], + m_chatmessage[FRAME_REALIZATION], + m_chatmessage[FRAME_SFX]}; + ui_vp_player_char->network_strings = netstrings; + } + else + ui_vp_player_char->network_strings.clear(); - int f_charid = m_chatmessage[CHAR_ID].toInt(); - if (f_charid >= 0 && (m_chatmessage[SHOWNAME].isEmpty() || !ui_showname_enable->isChecked())) { - QString real_name = char_list.at(f_charid).name; + int f_charid = m_chatmessage[CHAR_ID].toInt(); + if (f_charid >= 0 && + (m_chatmessage[SHOWNAME].isEmpty() || !ui_showname_enable->isChecked())) { + QString real_name = char_list.at(f_charid).name; - QString f_showname = ao_app->get_showname(real_name); + QString f_showname = ao_app->get_showname(real_name); - ui_vp_showname->setText(f_showname); - } - else { - ui_vp_showname->setText(m_chatmessage[SHOWNAME]); + ui_vp_showname->setText(f_showname); + } + else { + ui_vp_showname->setText(m_chatmessage[SHOWNAME]); + } + + if (ui_vp_showname->text().trimmed().isEmpty()) // Whitespace showname + { + ui_vp_chatbox->set_image("chatblank"); + } + else // Aw yeah dude do some showname resizing magic + { + if (!ui_vp_chatbox->set_image("chat")) + ui_vp_chatbox->set_image("chatbox"); + + QFontMetrics fm(ui_vp_showname->font()); + int fm_width = fm.horizontalAdvance(ui_vp_showname->text()); + + QString chatbox_path = ao_app->get_theme_path("chat"); + QString chatbox = ao_app->get_chat(m_chatmessage[CHAR_NAME]); + if (chatbox != "") { + 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"); + + pos_size_type design_ini_result = ao_app->get_element_dimensions( + "chat_arrow", "courtroom_design.ini", m_chatmessage[CHAR_NAME]); + 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(); + } + else { + ui_vp_chat_arrow->move(design_ini_result.x, design_ini_result.y); + ui_vp_chat_arrow->combo_resize(design_ini_result.width, + design_ini_result.height); + } } - if (ui_vp_showname->text().trimmed().isEmpty()) //Whitespace showname - { - ui_vp_chatbox->set_image("chatblank"); - } - else //Aw yeah dude do some showname resizing magic - { - if (!ui_vp_chatbox->set_image("chat")) - ui_vp_chatbox->set_image("chatbox"); + pos_size_type default_width = ao_app->get_element_dimensions( + "showname", "courtroom_design.ini", m_chatmessage[CHAR_NAME]); + int extra_width = + ao_app + ->get_design_element("showname_extra_width", "courtroom_design.ini", + m_chatmessage[CHAR_NAME]) + .toInt(); - QFontMetrics fm(ui_vp_showname->font()); - int fm_width = fm.horizontalAdvance(ui_vp_showname->text()); - - QString chatbox_path = ao_app->get_theme_path("chat"); - QString chatbox = ao_app->get_chat(m_chatmessage[CHAR_NAME]); - if (chatbox != "") { - 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"); - - pos_size_type design_ini_result = ao_app->get_element_dimensions("chat_arrow", "courtroom_design.ini", m_chatmessage[CHAR_NAME]); - 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(); - } - else { - ui_vp_chat_arrow->move(design_ini_result.x, design_ini_result.y); - ui_vp_chat_arrow->combo_resize(design_ini_result.width, design_ini_result.height); - } - } - - pos_size_type default_width = ao_app->get_element_dimensions("showname", "courtroom_design.ini", m_chatmessage[CHAR_NAME]); - int extra_width = ao_app->get_design_element("showname_extra_width", "courtroom_design.ini", m_chatmessage[CHAR_NAME]).toInt(); - - if (extra_width > 0) { - if (fm_width > default_width.width && ui_vp_chatbox->set_chatbox(chatbox_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_showname->resize(static_cast(default_width.width + (extra_width * 2)), ui_vp_showname->height()); - } - } - else - ui_vp_showname->resize(default_width.width, ui_vp_showname->height()); + if (extra_width > 0) { + if (fm_width > default_width.width && + ui_vp_chatbox->set_chatbox( + chatbox_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_showname->resize( + static_cast(default_width.width + (extra_width * 2)), + ui_vp_showname->height()); } + } + else + ui_vp_showname->resize(default_width.width, ui_vp_showname->height()); } + } - ui_vp_message->hide(); - ui_vp_chatbox->hide(); + ui_vp_message->hide(); + ui_vp_chatbox->hide(); - //todo: put this in its own function or update - QString design_file = "courtroom_fonts.ini"; - int f_pointsize = ao_app->get_font_size("message", design_file); - QString font_name = ao_app->get_font_name("message_font", design_file); - QColor f_color = ao_app->get_color("message_color", design_file); - bool bold = ao_app->get_font_size("message_bold", design_file) == 1; // is the font bold or not? - bool antialias = ao_app->get_font_size("message_sharp", design_file) != 1; // is the font anti-aliased or not? + // todo: put this in its own function or update + QString design_file = "courtroom_fonts.ini"; + int f_pointsize = ao_app->get_font_size("message", design_file); + QString font_name = ao_app->get_font_name("message_font", design_file); + QColor f_color = ao_app->get_color("message_color", design_file); + bool bold = ao_app->get_font_size("message_bold", design_file) == + 1; // is the font bold or not? + bool antialias = ao_app->get_font_size("message_sharp", design_file) != + 1; // is the font anti-aliased or not? - QString chatfont = ao_app->get_chat_font(m_chatmessage[CHAR_NAME]); - if (chatfont != "") - font_name = chatfont; + QString chatfont = ao_app->get_chat_font(m_chatmessage[CHAR_NAME]); + if (chatfont != "") + font_name = chatfont; - int chatsize = ao_app->get_chat_size(m_chatmessage[CHAR_NAME]); - if (chatsize != -1) - f_pointsize = chatsize; - this->set_qfont(ui_vp_message, "", get_qfont(font_name, f_pointsize, antialias), f_color, bold); + int chatsize = ao_app->get_chat_size(m_chatmessage[CHAR_NAME]); + if (chatsize != -1) + f_pointsize = chatsize; + this->set_qfont(ui_vp_message, "", + get_qfont(font_name, f_pointsize, antialias), f_color, bold); - set_scene(m_chatmessage[DESK_MOD], m_chatmessage[SIDE]); + set_scene(m_chatmessage[DESK_MOD], m_chatmessage[SIDE]); - int emote_mod = m_chatmessage[EMOTE_MOD].toInt(); + int emote_mod = m_chatmessage[EMOTE_MOD].toInt(); - if (ao_app->flipping_enabled && m_chatmessage[FLIP].toInt() == 1) - ui_vp_player_char->set_flipped(true); - else - ui_vp_player_char->set_flipped(false); + if (ao_app->flipping_enabled && m_chatmessage[FLIP].toInt() == 1) + ui_vp_player_char->set_flipped(true); + else + ui_vp_player_char->set_flipped(false); - QString side = m_chatmessage[SIDE]; - - // Making the second character appear. - if (m_chatmessage[OTHER_CHARID].isEmpty()) { - // If there is no second character, hide 'em - ui_vp_sideplayer_char->stop(); - ui_vp_sideplayer_char->move(0, 0); - } - else { - bool ok; - int got_other_charid = m_chatmessage[OTHER_CHARID].split("^")[0].toInt(&ok); - if (ok) { - if (got_other_charid > -1) { - // If there is, show them! - ui_vp_sideplayer_char->show(); - - int other_offset = m_chatmessage[OTHER_OFFSET].toInt(); - ui_vp_sideplayer_char->move(ui_viewport->width() * other_offset / 100, 0); - - QStringList args = m_chatmessage[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: - ui_vp_sideplayer_char->stackUnder(ui_vp_player_char); - break; - case 1: - ui_vp_player_char->stackUnder(ui_vp_sideplayer_char); - break; - default: - break; - } - } - - // We should probably also play the other character's idle emote. - if (ao_app->flipping_enabled && m_chatmessage[OTHER_FLIP].toInt() == 1) - ui_vp_sideplayer_char->set_flipped(true); - else - ui_vp_sideplayer_char->set_flipped(false); - ui_vp_sideplayer_char->play_idle(m_chatmessage[OTHER_NAME], m_chatmessage[OTHER_EMOTE]); - } - else { - // If the server understands other characters, but there - // really is no second character, hide 'em, and center the first. - ui_vp_sideplayer_char->hide(); - ui_vp_sideplayer_char->move(0, 0); - } - } - } - //Set ourselves according to SELF_OFFSET + QString side = m_chatmessage[SIDE]; + // Making the second character appear. + if (m_chatmessage[OTHER_CHARID].isEmpty()) { + // If there is no second character, hide 'em + ui_vp_sideplayer_char->stop(); + ui_vp_sideplayer_char->move(0, 0); + } + else { bool ok; - int self_offset = m_chatmessage[SELF_OFFSET].toInt(&ok); - if (ok) - ui_vp_player_char->move(ui_viewport->width() * self_offset / 100, 0); - else - ui_vp_player_char->move(0, 0); + int got_other_charid = m_chatmessage[OTHER_CHARID].split("^")[0].toInt(&ok); + if (ok) { + if (got_other_charid > -1) { + // If there is, show them! + ui_vp_sideplayer_char->show(); - switch (emote_mod) { - case 1: - case 2: - case 6: - play_preanim(false); - break; - case 0: - case 5: - if (m_chatmessage[NONINTERRUPTING_PRE].toInt() == 0) - handle_chatmessage_3(); + int other_offset = m_chatmessage[OTHER_OFFSET].toInt(); + ui_vp_sideplayer_char->move(ui_viewport->width() * other_offset / 100, + 0); + + QStringList args = m_chatmessage[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: + ui_vp_sideplayer_char->stackUnder(ui_vp_player_char); + break; + case 1: + ui_vp_player_char->stackUnder(ui_vp_sideplayer_char); + break; + default: + break; + } + } + + // We should probably also play the other character's idle emote. + if (ao_app->flipping_enabled && m_chatmessage[OTHER_FLIP].toInt() == 1) + ui_vp_sideplayer_char->set_flipped(true); else - play_preanim(true); - break; - default: - qDebug() << "W: invalid emote mod: " << QString::number(emote_mod); + ui_vp_sideplayer_char->set_flipped(false); + ui_vp_sideplayer_char->play_idle(m_chatmessage[OTHER_NAME], + m_chatmessage[OTHER_EMOTE]); + } + else { + // If the server understands other characters, but there + // really is no second character, hide 'em, and center the first. + ui_vp_sideplayer_char->hide(); + ui_vp_sideplayer_char->move(0, 0); + } } + } + // Set ourselves according to SELF_OFFSET + + bool ok; + int self_offset = m_chatmessage[SELF_OFFSET].toInt(&ok); + if (ok) + ui_vp_player_char->move(ui_viewport->width() * self_offset / 100, 0); + else + ui_vp_player_char->move(0, 0); + + switch (emote_mod) { + case 1: + case 2: + case 6: + play_preanim(false); + break; + case 0: + case 5: + if (m_chatmessage[NONINTERRUPTING_PRE].toInt() == 0) + handle_chatmessage_3(); + else + play_preanim(true); + break; + default: + qDebug() << "W: invalid emote mod: " << QString::number(emote_mod); + } } void Courtroom::do_screenshake() { - if (!ao_app->is_shake_enabled()) - return; + if (!ao_app->is_shake_enabled()) + return; - //This way, the animation is reset in such a way that last played screenshake would return to its "final frame" properly. - //This properly resets all UI elements without having to bother keeping track of "origin" positions. - //Works great wit the chat text being detached from the chat box! - screenshake_animation_group->setCurrentTime(screenshake_animation_group->duration()); - screenshake_animation_group->clear(); + // This way, the animation is reset in such a way that last played screenshake + // would return to its "final frame" properly. This properly resets all UI + // elements without having to bother keeping track of "origin" positions. + // Works great wit the chat text being detached from the chat box! + screenshake_animation_group->setCurrentTime( + screenshake_animation_group->duration()); + screenshake_animation_group->clear(); - QList affected_list = { - ui_vp_background, - ui_vp_player_char, - ui_vp_sideplayer_char, - ui_vp_chatbox}; + QList affected_list = {ui_vp_background, ui_vp_player_char, + ui_vp_sideplayer_char, ui_vp_chatbox}; - //I would prefer if this was its own "shake" function to be honest. - foreach (QWidget *ui_element, affected_list) { - QPropertyAnimation *screenshake_animation = new QPropertyAnimation(ui_element, "pos", this); - QPoint pos_default = QPoint(ui_element->x(), ui_element->y()); + // I would prefer if this was its own "shake" function to be honest. + foreach (QWidget *ui_element, affected_list) { + QPropertyAnimation *screenshake_animation = + new QPropertyAnimation(ui_element, "pos", this); + QPoint pos_default = QPoint(ui_element->x(), ui_element->y()); - int duration = 300; //How long does the screenshake last - int frequency = 20; //How often in ms is there a "jolt" frame - int maxframes = duration / frequency; - int max_x = 7; //Max deviation from origin on x axis - int max_y = 7; //Max deviation from origin on y axis - screenshake_animation->setDuration(duration); - for (int frame = 0; frame < maxframes; frame++) { - double fraction = double(frame * frequency) / duration; - int rng = qrand(); //QRandomGenerator::global()->generate(); - int rand_x = max_x - (int(rng) % (max_x * 2)); - int rand_y = max_y - (int(rng + 100) % (max_y * 2)); - screenshake_animation->setKeyValueAt(fraction, QPoint(pos_default.x() + rand_x, pos_default.y() + rand_y)); - } - screenshake_animation->setEndValue(pos_default); - screenshake_animation->setEasingCurve(QEasingCurve::Linear); - screenshake_animation_group->addAnimation(screenshake_animation); + int duration = 300; // How long does the screenshake last + int frequency = 20; // How often in ms is there a "jolt" frame + int maxframes = duration / frequency; + int max_x = 7; // Max deviation from origin on x axis + int max_y = 7; // Max deviation from origin on y axis + screenshake_animation->setDuration(duration); + for (int frame = 0; frame < maxframes; frame++) { + double fraction = double(frame * frequency) / duration; + int rng = qrand(); // QRandomGenerator::global()->generate(); + int rand_x = max_x - (int(rng) % (max_x * 2)); + int rand_y = max_y - (int(rng + 100) % (max_y * 2)); + screenshake_animation->setKeyValueAt( + fraction, QPoint(pos_default.x() + rand_x, pos_default.y() + rand_y)); } + screenshake_animation->setEndValue(pos_default); + screenshake_animation->setEasingCurve(QEasingCurve::Linear); + screenshake_animation_group->addAnimation(screenshake_animation); + } - screenshake_animation_group->start(); + screenshake_animation_group->start(); } void Courtroom::do_flash() { - if (!ao_app->is_effects_enabled()) - return; + if (!ao_app->is_effects_enabled()) + return; - QString f_char = m_chatmessage[CHAR_NAME]; - QString f_custom_theme = ao_app->get_char_shouts(f_char); - ui_vp_effect->play("realizationflash", f_char, f_custom_theme, 60); + QString f_char = m_chatmessage[CHAR_NAME]; + QString f_custom_theme = ao_app->get_char_shouts(f_char); + ui_vp_effect->play("realizationflash", f_char, f_custom_theme, 60); } -void Courtroom::do_effect(QString fx_name, QString fx_sound, QString p_char, QString p_folder) +void Courtroom::do_effect(QString fx_name, QString fx_sound, QString p_char, + QString p_folder) { - QString effect = ao_app->get_effect(fx_name, p_char, p_folder); - if (effect == "") - return; + QString effect = ao_app->get_effect(fx_name, p_char, p_folder); + if (effect == "") + return; - if (fx_sound != "") - sfx_player->play(fx_sound); + if (fx_sound != "") + sfx_player->play(fx_sound); - //Only check if effects are disabled after playing the sound if it exists - if (!ao_app->is_effects_enabled()) - return; + // Only check if effects are disabled after playing the sound if it exists + if (!ao_app->is_effects_enabled()) + return; - ui_vp_effect->set_play_once(false); // The effects themselves dictate whether or not they're looping. Static effects will linger. - ui_vp_effect->play(effect); // It will set_play_once to true if the filepath provided is not designed to loop more than once + ui_vp_effect->set_play_once( + false); // The effects themselves dictate whether or not they're looping. + // Static effects will linger. + ui_vp_effect->play(effect); // It will set_play_once to true if the filepath + // provided is not designed to loop more than once } void Courtroom::play_char_sfx(QString sfx_name) { - sfx_player->play(sfx_name); - if (ao_app->get_looping_sfx()) - sfx_player->set_looping(ao_app->get_sfx_looping(current_char, QString::number(current_emote)) != "0"); + sfx_player->play(sfx_name); + if (ao_app->get_looping_sfx()) + sfx_player->set_looping( + ao_app->get_sfx_looping(current_char, QString::number(current_emote)) != + "0"); } void Courtroom::handle_chatmessage_3() { - start_chat_ticking(); + start_chat_ticking(); - int f_evi_id = m_chatmessage[EVIDENCE_ID].toInt(); - QString f_side = m_chatmessage[SIDE]; + int f_evi_id = m_chatmessage[EVIDENCE_ID].toInt(); + QString f_side = m_chatmessage[SIDE]; - QString f_showname; - int f_char_id = m_chatmessage[CHAR_ID].toInt(); - if (f_char_id > 0 && (m_chatmessage[SHOWNAME].isEmpty() || !ui_showname_enable->isChecked())) { - f_showname = ao_app->get_showname(char_list.at(f_char_id).name); - } - else { - f_showname = m_chatmessage[SHOWNAME]; - } - if (f_showname.trimmed().isEmpty()) //Pure whitespace showname, get outta here. - f_showname = m_chatmessage[CHAR_NAME]; + QString f_showname; + int f_char_id = m_chatmessage[CHAR_ID].toInt(); + if (f_char_id > 0 && + (m_chatmessage[SHOWNAME].isEmpty() || !ui_showname_enable->isChecked())) { + f_showname = ao_app->get_showname(char_list.at(f_char_id).name); + } + else { + f_showname = m_chatmessage[SHOWNAME]; + } + if (f_showname.trimmed() + .isEmpty()) // Pure whitespace showname, get outta here. + f_showname = m_chatmessage[CHAR_NAME]; - if (f_evi_id > 0 && f_evi_id <= local_evidence_list.size()) { - //shifted by 1 because 0 is no evidence per legacy standards - QString f_image = local_evidence_list.at(f_evi_id - 1).image; - QString f_name = local_evidence_list.at(f_evi_id - 1).name; - //def jud and hlp should display the evidence icon on the RIGHT side - bool is_left_side = !(f_side == "def" || f_side == "hlp" || f_side == "jud" || f_side == "jur"); - ui_vp_evidence_display->show_evidence(f_image, is_left_side, ui_sfx_slider->value()); - append_ic_text(f_name, f_showname, "has presented evidence"); - } + if (f_evi_id > 0 && f_evi_id <= local_evidence_list.size()) { + // shifted by 1 because 0 is no evidence per legacy standards + QString f_image = local_evidence_list.at(f_evi_id - 1).image; + QString f_name = local_evidence_list.at(f_evi_id - 1).name; + // def jud and hlp should display the evidence icon on the RIGHT side + bool is_left_side = !(f_side == "def" || f_side == "hlp" || + f_side == "jud" || f_side == "jur"); + ui_vp_evidence_display->show_evidence(f_image, is_left_side, + ui_sfx_slider->value()); + append_ic_text(f_name, f_showname, "has presented evidence"); + } - int emote_mod = m_chatmessage[EMOTE_MOD].toInt(); + int emote_mod = m_chatmessage[EMOTE_MOD].toInt(); - QString side = m_chatmessage[SIDE]; + QString side = m_chatmessage[SIDE]; - if (emote_mod == 5 || - emote_mod == 6) { - ui_vp_desk->hide(); - ui_vp_legacy_desk->hide(); + if (emote_mod == 5 || emote_mod == 6) { + ui_vp_desk->hide(); + ui_vp_legacy_desk->hide(); - // Since we're zooming, hide the second character, and centre the first. - ui_vp_sideplayer_char->hide(); - ui_vp_player_char->move(0, 0); + // Since we're zooming, hide the second character, and centre the first. + ui_vp_sideplayer_char->hide(); + ui_vp_player_char->move(0, 0); - QString f_char = m_chatmessage[CHAR_NAME]; - QString f_custom_theme = ao_app->get_char_shouts(f_char); - if (side == "pro" || - side == "hlp" || - side == "wit") - ui_vp_speedlines->play("prosecution_speedlines", f_char, f_custom_theme); - else - ui_vp_speedlines->play("defense_speedlines", f_char, f_custom_theme); - } - - //If this color is talking - color_is_talking = color_markdown_talking_list.at(m_chatmessage[TEXT_COLOR].toInt()); - - if (color_is_talking && text_state == 1 && anim_state < 2) //Set it to talking as we're not on that already - { - ui_vp_player_char->stop(); - ui_vp_player_char->play_talking(m_chatmessage[CHAR_NAME], m_chatmessage[EMOTE]); - anim_state = 2; - } - else if (anim_state < 3) //Set it to idle as we're not on that already - { - ui_vp_player_char->stop(); - ui_vp_player_char->play_idle(m_chatmessage[CHAR_NAME], m_chatmessage[EMOTE]); - anim_state = 3; - } - - QString f_message = m_chatmessage[MESSAGE]; - QStringList call_words = ao_app->get_call_words(); - - for (QString word : call_words) { - if (f_message.contains(word, Qt::CaseInsensitive)) { - modcall_player->play(ao_app->get_sfx("word_call")); - ao_app->alert(this); - - break; - } - } -} - -QString Courtroom::filter_ic_text(QString p_text, bool html, int target_pos, int default_color) -{ - QString p_text_escaped; - - int check_pos = 0; - int check_pos_escaped = 0; - bool ic_next_is_not_special = false; - std::stack ic_color_stack; - - //Text alignment shenanigans. Could make a dropdown for this later, too! - QString align; - if (p_text.trimmed().startsWith("~~")) { - p_text.remove(p_text.indexOf("~~"), 2); - if (target_pos != -1) { - target_pos = qMax(0, target_pos - 2); - } - align = "center"; - } - else if (p_text.trimmed().startsWith("~>")) { - p_text.remove(p_text.indexOf("~>"), 2); - if (target_pos != -1) { - target_pos = qMax(0, target_pos - 2); - } - align = "right"; - } - else if (p_text.trimmed().startsWith("<>")) { - p_text.remove(p_text.indexOf("<>"), 2); - if (target_pos != -1) { - target_pos = qMax(0, target_pos - 2); - } - align = "justify"; - } - - //If html is enabled, prepare this text to be all ready for it. - if (html) { - ic_color_stack.push(default_color); - QString appendage = ""; - - if (!align.isEmpty()) - appendage.prepend("

"); - - p_text_escaped.insert(check_pos_escaped, appendage); - check_pos_escaped += appendage.size(); - } - - //Current issue: does not properly escape html stuff. - //Solution: probably parse p_text and export into a different string separately, perform some mumbo jumbo to properly adjust string indexes. - while (check_pos < p_text.size()) { - QString f_rest = p_text.right(p_text.size() - check_pos); - QTextBoundaryFinder tbf(QTextBoundaryFinder::Grapheme, f_rest); - QString f_character; - int f_char_length; - - tbf.toNextBoundary(); - - if (tbf.position() == -1) - f_character = f_rest; - else - f_character = f_rest.left(tbf.position()); - - // if (f_character == "&") //oh shit it's probably an escaped html - // { - // //Skip escaped chars like you would graphemes - // QRegularExpression re("&([a-z0-9]+|#[0-9]{1,6}|#x[0-9a-f]{1,6});", QRegularExpression::CaseInsensitiveOption); - // QRegularExpressionMatch match = re.match(f_rest); - // if (match.hasMatch()) //OH SHIT IT IS, PANIC, PANIC - // { - // f_character = match.captured(0); //Phew, we solved the big problem here. - // } - // } - - if (html) - f_character = f_character.toHtmlEscaped(); - - f_char_length = f_character.length(); - - bool color_update = false; - bool is_end = false; - bool skip = false; - - if (!ic_next_is_not_special) { - if (f_character == "\\") { - ic_next_is_not_special = true; - skip = true; - } - //Nothing related to colors here - else if (f_character == "{" || f_character == "}") //|| f_character == "@" || f_character == "$") - { - skip = true; - } - //Parse markdown colors - else { - for (int c = 0; c < max_colors; ++c) { - //Clear the stored optimization information - QString markdown_start = color_markdown_start_list.at(c); - QString markdown_end = color_markdown_end_list.at(c); - if (html) { - markdown_start = markdown_start.toHtmlEscaped(); - markdown_end = markdown_end.toHtmlEscaped(); - } - bool markdown_remove = color_markdown_remove_list.at(c); - if (markdown_start.isEmpty()) //Not defined - continue; - - if (markdown_end.isEmpty() || markdown_end == markdown_start) //"toggle switch" type - { - if (f_character == markdown_start) { - if (html) { - if (!ic_color_stack.empty() && ic_color_stack.top() == c && default_color != c) { - ic_color_stack.pop(); //Cease our coloring - is_end = true; - } - else { - ic_color_stack.push(c); //Begin our coloring - } - color_update = true; - } - skip = markdown_remove; - break; //Prevent it from looping forward for whatever reason - } - } - else if (f_character == markdown_start || (f_character == markdown_end && !ic_color_stack.empty() && ic_color_stack.top() == c)) { - if (html) { - if (f_character == markdown_end) { - ic_color_stack.pop(); //Cease our coloring - is_end = true; - } - else if (f_character == markdown_start) { - ic_color_stack.push(c); //Begin our coloring - } - color_update = true; - } - skip = markdown_remove; - break; //Prevent it from looping forward for whatever reason - } - } - //Parse the newest color stack - if (color_update && (target_pos <= -1 || check_pos < target_pos)) { - if (!ic_next_is_not_special) { - QString appendage = ""; - - if (!ic_color_stack.empty()) - appendage += ""; - - if (is_end && !skip) { - p_text_escaped.insert(check_pos_escaped, f_character); //Add that char right now - check_pos_escaped += f_char_length; //So the closing char is captured too - skip = true; - } - p_text_escaped.insert(check_pos_escaped, appendage); - check_pos_escaped += appendage.size(); - } - } - } - } - else { - if (f_character == "n") // \n, that's a line break son - { - QString appendage = "
"; - if (!html) { - //actual newline commented out - // appendage = "\n"; - // size = 1; //yeah guess what \n is a "single character" apparently - appendage = "\\n "; //visual representation of a newline - } - p_text_escaped.insert(check_pos_escaped, appendage); - check_pos_escaped += appendage.size(); - skip = true; - } - if (f_character == "s" || f_character == "f") // screenshake/flash - skip = true; - - ic_next_is_not_special = false; - } - - //Make all chars we're not supposed to see invisible - if (target_pos > -1 && check_pos == target_pos) { - QString appendage = ""; - if (!ic_color_stack.empty()) { - if (!is_end) //Was our last coloring char ending the color stack or nah - { - //God forgive me for my transgressions but I have refactored this whole thing about 25 times and having to refactor it - //again to more elegantly support this will finally make me go insane. - color_is_talking = color_markdown_talking_list.at(ic_color_stack.top()); - } - - //Clean it up, we're done here - while (!ic_color_stack.empty()) - ic_color_stack.pop(); - - appendage += "
"; - } - ic_color_stack.push(-1); //Dummy colorstack push for maximum
appendage - appendage += ""; - p_text_escaped.insert(check_pos_escaped, appendage); - check_pos_escaped += appendage.size(); - } - if (!skip) { - p_text_escaped.insert(check_pos_escaped, f_character); - check_pos_escaped += f_char_length; - } - check_pos += 1; - } - - if (!ic_color_stack.empty() && html) { - p_text_escaped.append(""); - } - - if (html) { - //Example: https://regex101.com/r/oL4nM9/37 - this replaces excessive/trailing/etc. whitespace with non-breaking space. - //I WOULD use white-space: pre; stylesheet tag, but for whataver reason it doesn't work no matter where I try it. - //If somoene else can get that piece of HTML memery to work, please do. - p_text_escaped.replace(QRegularExpression("^\\s|(?<=\\s)\\s"), " "); - if (!align.isEmpty()) - p_text_escaped.append("
"); - } - - return p_text_escaped; -} - -void Courtroom::append_ic_text(QString p_text, QString p_name, QString p_action) -{ - QTextCharFormat bold; - QTextCharFormat normal; - QTextCharFormat italics; - bold.setFontWeight(QFont::Bold); - normal.setFontWeight(QFont::Normal); - italics.setFontItalic(true); - const QTextCursor old_cursor = ui_ic_chatlog->textCursor(); - const int old_scrollbar_value = ui_ic_chatlog->verticalScrollBar()->value(); - - if (p_action == "") - p_text = filter_ic_text(p_text, ao_app->is_colorlog_enabled(), -1, m_chatmessage[TEXT_COLOR].toInt()); - - if (log_goes_downwards) { - const bool is_scrolled_down = old_scrollbar_value == ui_ic_chatlog->verticalScrollBar()->maximum(); - - ui_ic_chatlog->moveCursor(QTextCursor::End); - - if (!first_message_sent) { - ui_ic_chatlog->textCursor().insertText(p_name, bold); - first_message_sent = true; - } - else { - ui_ic_chatlog->textCursor().insertText('\n' + p_name, bold); - } - - if (p_action != "") { - ui_ic_chatlog->textCursor().insertText(" " + p_action + ": ", normal); - ui_ic_chatlog->textCursor().insertText(p_text + ".", italics); - } - else { - ui_ic_chatlog->textCursor().insertText(": ", normal); - ui_ic_chatlog->textCursor().insertHtml(p_text); - } - - // If we got too many blocks in the current log, delete some from the top. - while (ui_ic_chatlog->document()->blockCount() > log_maximum_blocks && log_maximum_blocks > 0) { - ui_ic_chatlog->moveCursor(QTextCursor::Start); - ui_ic_chatlog->textCursor().select(QTextCursor::BlockUnderCursor); - ui_ic_chatlog->textCursor().removeSelectedText(); - ui_ic_chatlog->textCursor().deleteChar(); - } - - if (old_cursor.hasSelection() || !is_scrolled_down) { - // The user has selected text or scrolled away from the bottom: maintain position. - ui_ic_chatlog->setTextCursor(old_cursor); - ui_ic_chatlog->verticalScrollBar()->setValue(old_scrollbar_value); - } - else { - // The user hasn't selected any text and the scrollbar is at the bottom: scroll to the bottom. - ui_ic_chatlog->moveCursor(QTextCursor::End); - ui_ic_chatlog->verticalScrollBar()->setValue(ui_ic_chatlog->verticalScrollBar()->maximum()); - } - } - else { - const bool is_scrolled_up = old_scrollbar_value == ui_ic_chatlog->verticalScrollBar()->minimum(); - - ui_ic_chatlog->moveCursor(QTextCursor::Start); - - ui_ic_chatlog->textCursor().insertText(p_name, bold); - - if (p_action != "") { - ui_ic_chatlog->textCursor().insertText(" " + p_action + ": ", normal); - ui_ic_chatlog->textCursor().insertText(p_text + "." + '\n', italics); - } - else { - ui_ic_chatlog->textCursor().insertText(": ", normal); - ui_ic_chatlog->textCursor().insertText(p_text + '\n', normal); - } - - // If we got too many blocks in the current log, delete some from the bottom. - while (ui_ic_chatlog->document()->blockCount() > log_maximum_blocks && log_maximum_blocks > 0) { - ui_ic_chatlog->moveCursor(QTextCursor::End); - ui_ic_chatlog->textCursor().select(QTextCursor::BlockUnderCursor); - ui_ic_chatlog->textCursor().removeSelectedText(); - ui_ic_chatlog->textCursor().deletePreviousChar(); - } - - if (old_cursor.hasSelection() || !is_scrolled_up) { - // The user has selected text or scrolled away from the top: maintain position. - ui_ic_chatlog->setTextCursor(old_cursor); - ui_ic_chatlog->verticalScrollBar()->setValue(old_scrollbar_value); - } - else { - // The user hasn't selected any text and the scrollbar is at the top: scroll to the top. - ui_ic_chatlog->moveCursor(QTextCursor::Start); - ui_ic_chatlog->verticalScrollBar()->setValue(ui_ic_chatlog->verticalScrollBar()->minimum()); - } - } -} - -void Courtroom::play_preanim(bool noninterrupting) -{ QString f_char = m_chatmessage[CHAR_NAME]; - QString f_preanim = m_chatmessage[PRE_EMOTE]; - - //all time values in char.inis are multiplied by a constant(time_mod) to get the actual time - int ao2_duration = ao_app->get_ao2_preanim_duration(f_char, f_preanim); - int text_delay = ao_app->get_text_delay(f_char, f_preanim) * time_mod; - int sfx_delay = m_chatmessage[SFX_DELAY].toInt() * time_mod; - - int preanim_duration; - - if (ao2_duration < 0) - preanim_duration = ao_app->get_preanim_duration(f_char, f_preanim); + QString f_custom_theme = ao_app->get_char_shouts(f_char); + if (side == "pro" || side == "hlp" || side == "wit") + ui_vp_speedlines->play("prosecution_speedlines", f_char, f_custom_theme); else - preanim_duration = ao2_duration; + ui_vp_speedlines->play("defense_speedlines", f_char, f_custom_theme); + } - sfx_delay_timer->start(sfx_delay); - QString anim_to_find = ao_app->get_image_suffix(ao_app->get_character_path(f_char, f_preanim)); - if (!file_exists(anim_to_find)) { - if (noninterrupting) - anim_state = 4; - else - anim_state = 1; - preanim_done(); - qDebug() << "could not find " + anim_to_find; - return; + // If this color is talking + color_is_talking = + color_markdown_talking_list.at(m_chatmessage[TEXT_COLOR].toInt()); + + if (color_is_talking && text_state == 1 && + anim_state < 2) // Set it to talking as we're not on that already + { + ui_vp_player_char->stop(); + ui_vp_player_char->play_talking(m_chatmessage[CHAR_NAME], + m_chatmessage[EMOTE]); + anim_state = 2; + } + else if (anim_state < 3) // Set it to idle as we're not on that already + { + ui_vp_player_char->stop(); + ui_vp_player_char->play_idle(m_chatmessage[CHAR_NAME], + m_chatmessage[EMOTE]); + anim_state = 3; + } + + QString f_message = m_chatmessage[MESSAGE]; + QStringList call_words = ao_app->get_call_words(); + + for (QString word : call_words) { + if (f_message.contains(word, Qt::CaseInsensitive)) { + modcall_player->play(ao_app->get_sfx("word_call")); + ao_app->alert(this); + + break; } - - ui_vp_player_char->play_pre(f_char, f_preanim, preanim_duration); - - if (noninterrupting) - anim_state = 4; - else - anim_state = 1; - - if (text_delay >= 0) - text_delay_timer->start(text_delay); - - if (noninterrupting) - handle_chatmessage_3(); + } } -void Courtroom::preanim_done() +QString Courtroom::filter_ic_text(QString p_text, bool html, int target_pos, + int default_color) { - anim_state = 1; - handle_chatmessage_3(); -} + QString p_text_escaped; -void Courtroom::start_chat_ticking() -{ - //we need to ensure that the text isn't already ticking because this function can be called by two logic paths - if (text_state != 0) - return; + int check_pos = 0; + int check_pos_escaped = 0; + bool ic_next_is_not_special = false; + std::stack ic_color_stack; - if (m_chatmessage[EFFECTS] != "") { - QStringList fx_list = m_chatmessage[EFFECTS].split("|"); - QString fx = fx_list[0]; - QString fx_sound; - QString fx_folder; - - if (fx_list.length() > 1) - fx_sound = fx_list[1]; - - if (fx_list.length() > 2) { - fx_folder = fx_list[1]; - fx_sound = fx_list[2]; - } - - this->do_effect(fx, fx_sound, m_chatmessage[CHAR_NAME], fx_folder); + // Text alignment shenanigans. Could make a dropdown for this later, too! + QString align; + if (p_text.trimmed().startsWith("~~")) { + p_text.remove(p_text.indexOf("~~"), 2); + if (target_pos != -1) { + target_pos = qMax(0, target_pos - 2); } - else if (m_chatmessage[REALIZATION] == "1") { - this->do_flash(); - sfx_player->play(ao_app->get_custom_realization(m_chatmessage[CHAR_NAME])); + align = "center"; + } + else if (p_text.trimmed().startsWith("~>")) { + p_text.remove(p_text.indexOf("~>"), 2); + if (target_pos != -1) { + target_pos = qMax(0, target_pos - 2); } - if (chatmessage_is_empty) { - //since the message is empty, it's technically done ticking - text_state = 2; - return; + align = "right"; + } + else if (p_text.trimmed().startsWith("<>")) { + p_text.remove(p_text.indexOf("<>"), 2); + if (target_pos != -1) { + target_pos = qMax(0, target_pos - 2); } + align = "justify"; + } - ui_vp_chatbox->show(); - ui_vp_message->show(); + // If html is enabled, prepare this text to be all ready for it. + if (html) { + ic_color_stack.push(default_color); + QString appendage = ""; - if (!is_additive) { - ui_vp_message->clear(); - real_tick_pos = 0; - additive_previous = ""; - } + if (!align.isEmpty()) + appendage.prepend("
"); - tick_pos = 0; - blip_ticker = 0; + p_text_escaped.insert(check_pos_escaped, appendage); + check_pos_escaped += appendage.size(); + } - // At the start of every new message, we set the text speed to the default. - current_display_speed = 3; - chat_tick_timer->start(0); //Display the first char right away - - QString f_gender = ao_app->get_gender(m_chatmessage[CHAR_NAME]); - - blip_player->set_blips(f_gender); - - int emote_mod = m_chatmessage[EMOTE_MOD].toInt(); //text meme bonanza - if ((emote_mod == 0 || emote_mod == 5) && m_chatmessage[SCREENSHAKE] == "1") { - this->do_screenshake(); - } - - //means text is currently ticking - text_state = 1; -} - -void Courtroom::chat_tick() -{ - //note: this is called fairly often - //do not perform heavy operations here - - QString f_message = m_chatmessage[MESSAGE]; - - // Due to our new text speed system, we always need to stop the timer now. - chat_tick_timer->stop(); - - if (tick_pos >= f_message.size()) { - text_state = 2; - if (anim_state < 3) { - anim_state = 3; - ui_vp_player_char->play_idle(m_chatmessage[CHAR_NAME], m_chatmessage[EMOTE]); - } - QString f_char = m_chatmessage[CHAR_NAME]; - QString f_custom_theme = ao_app->get_chat(f_char); - ui_vp_chat_arrow->play("chat_arrow", f_char, f_custom_theme); //Chat stopped being processed, indicate that. - additive_previous = additive_previous + filter_ic_text(f_message, true, -1, m_chatmessage[TEXT_COLOR].toInt()); - real_tick_pos = ui_vp_message->toPlainText().size(); - return; - } - - // Stops blips from playing when we have a formatting option. - bool formatting_char = false; - - QString f_rest = f_message; - - //Alignment characters - if (tick_pos < 2) { - if (f_rest.startsWith("~~")) { - tick_pos = f_rest.indexOf("~~"); - f_rest.remove(tick_pos, 2); - tick_pos += 2; - } - else if (f_rest.startsWith("~>")) { - tick_pos = f_rest.indexOf("~>"); - f_rest.remove(tick_pos, 2); - tick_pos += 2; - } - else if (f_rest.startsWith("<>")) { - tick_pos = f_rest.indexOf("<>"); - f_rest.remove(tick_pos, 2); - tick_pos += 2; - } - } - f_rest.remove(0, tick_pos); + // Current issue: does not properly escape html stuff. + // Solution: probably parse p_text and export into a different string + // separately, perform some mumbo jumbo to properly adjust string indexes. + while (check_pos < p_text.size()) { + QString f_rest = p_text.right(p_text.size() - check_pos); QTextBoundaryFinder tbf(QTextBoundaryFinder::Grapheme, f_rest); QString f_character; int f_char_length; @@ -2492,1735 +2275,2325 @@ void Courtroom::chat_tick() tbf.toNextBoundary(); if (tbf.position() == -1) - f_character = f_rest; + f_character = f_rest; else - f_character = f_rest.left(tbf.position()); + f_character = f_rest.left(tbf.position()); + + // if (f_character == "&") //oh shit it's probably an escaped html + // { + // //Skip escaped chars like you would graphemes + // QRegularExpression re("&([a-z0-9]+|#[0-9]{1,6}|#x[0-9a-f]{1,6});", + // QRegularExpression::CaseInsensitiveOption); QRegularExpressionMatch + // match = re.match(f_rest); if (match.hasMatch()) //OH SHIT IT IS, + // PANIC, PANIC + // { + // f_character = match.captured(0); //Phew, we solved the big problem + // here. + // } + // } + + if (html) + f_character = f_character.toHtmlEscaped(); f_char_length = f_character.length(); - tick_pos += f_char_length; - // Escape character. - if (!next_character_is_not_special) { - if (f_character == "\\") { - next_character_is_not_special = true; - formatting_char = true; - } + bool color_update = false; + bool is_end = false; + bool skip = false; - // Text speed modifier. - else if (f_character == "{") { - // ++, because it INCREASES delay! - current_display_speed++; - formatting_char = true; - } - else if (f_character == "}") { - current_display_speed--; - formatting_char = true; - } + if (!ic_next_is_not_special) { + if (f_character == "\\") { + ic_next_is_not_special = true; + skip = true; + } + // Nothing related to colors here + else if (f_character == "{" || + f_character == + "}") //|| f_character == "@" || f_character == "$") + { + skip = true; + } + // Parse markdown colors + else { + for (int c = 0; c < max_colors; ++c) { + // Clear the stored optimization information + QString markdown_start = color_markdown_start_list.at(c); + QString markdown_end = color_markdown_end_list.at(c); + if (html) { + markdown_start = markdown_start.toHtmlEscaped(); + markdown_end = markdown_end.toHtmlEscaped(); + } + bool markdown_remove = color_markdown_remove_list.at(c); + if (markdown_start.isEmpty()) // Not defined + continue; - else { - //Parse markdown colors - for (int c = 0; c < max_colors; ++c) { - QString markdown_start = color_markdown_start_list.at(c); - QString markdown_end = color_markdown_end_list.at(c); - bool markdown_remove = color_markdown_remove_list.at(c); - if (markdown_start.isEmpty()) - continue; - - if (f_character == markdown_start || f_character == markdown_end) { - if (markdown_remove) - formatting_char = true; - break; + if (markdown_end.isEmpty() || + markdown_end == markdown_start) //"toggle switch" type + { + if (f_character == markdown_start) { + if (html) { + if (!ic_color_stack.empty() && ic_color_stack.top() == c && + default_color != c) { + ic_color_stack.pop(); // Cease our coloring + is_end = true; } + else { + ic_color_stack.push(c); // Begin our coloring + } + color_update = true; + } + skip = markdown_remove; + break; // Prevent it from looping forward for whatever reason } + } + else if (f_character == markdown_start || + (f_character == markdown_end && !ic_color_stack.empty() && + ic_color_stack.top() == c)) { + if (html) { + if (f_character == markdown_end) { + ic_color_stack.pop(); // Cease our coloring + is_end = true; + } + else if (f_character == markdown_start) { + ic_color_stack.push(c); // Begin our coloring + } + color_update = true; + } + skip = markdown_remove; + break; // Prevent it from looping forward for whatever reason + } } + // Parse the newest color stack + if (color_update && (target_pos <= -1 || check_pos < target_pos)) { + if (!ic_next_is_not_special) { + QString appendage = ""; + + if (!ic_color_stack.empty()) + appendage += + ""; + + if (is_end && !skip) { + p_text_escaped.insert(check_pos_escaped, + f_character); // Add that char right now + check_pos_escaped += + f_char_length; // So the closing char is captured too + skip = true; + } + p_text_escaped.insert(check_pos_escaped, appendage); + check_pos_escaped += appendage.size(); + } + } + } } else { - if (f_character == "n") - formatting_char = true; //it's a newline - if (f_character == "s") //Screenshake. - { - this->do_screenshake(); - formatting_char = true; + if (f_character == "n") // \n, that's a line break son + { + QString appendage = "
"; + if (!html) { + // actual newline commented out + // appendage = "\n"; + // size = 1; //yeah guess what \n is a "single character" + // apparently + appendage = "\\n "; // visual representation of a newline } - if (f_character == "f") //Flash. - { - this->do_flash(); - formatting_char = true; - } - next_character_is_not_special = false; + p_text_escaped.insert(check_pos_escaped, appendage); + check_pos_escaped += appendage.size(); + skip = true; + } + if (f_character == "s" || f_character == "f") // screenshake/flash + skip = true; + + ic_next_is_not_special = false; } - if ((message_display_speed[current_display_speed] <= 0 && tick_pos < f_message.size() - 1) || formatting_char) { - chat_tick_timer->start(0); //Don't bother rendering anything out as we're doing the SPEED. (there's latency otherwise) - if (!formatting_char || f_character == "n" || f_character == "f" || f_character == "s") - real_tick_pos += f_char_length; //Adjust the tick position for the scrollbar convenience + // Make all chars we're not supposed to see invisible + if (target_pos > -1 && check_pos == target_pos) { + QString appendage = ""; + if (!ic_color_stack.empty()) { + if (!is_end) // Was our last coloring char ending the color stack or nah + { + // God forgive me for my transgressions but I have refactored this + // whole thing about 25 times and having to refactor it again to more + // elegantly support this will finally make me go insane. + color_is_talking = + color_markdown_talking_list.at(ic_color_stack.top()); + } + + // Clean it up, we're done here + while (!ic_color_stack.empty()) + ic_color_stack.pop(); + + appendage += "
"; + } + ic_color_stack.push( + -1); // Dummy colorstack push for maximum appendage + appendage += ""; + p_text_escaped.insert(check_pos_escaped, appendage); + check_pos_escaped += appendage.size(); + } + if (!skip) { + p_text_escaped.insert(check_pos_escaped, f_character); + check_pos_escaped += f_char_length; + } + check_pos += 1; + } + + if (!ic_color_stack.empty() && html) { + p_text_escaped.append(""); + } + + if (html) { + // Example: https://regex101.com/r/oL4nM9/37 - this replaces + // excessive/trailing/etc. whitespace with non-breaking space. I WOULD use + // white-space: pre; stylesheet tag, but for whataver reason it doesn't work + // no matter where I try it. If somoene else can get that piece of HTML + // memery to work, please do. + p_text_escaped.replace(QRegularExpression("^\\s|(?<=\\s)\\s"), " "); + if (!align.isEmpty()) + p_text_escaped.append("
"); + } + + return p_text_escaped; +} + +void Courtroom::append_ic_text(QString p_text, QString p_name, QString p_action) +{ + QTextCharFormat bold; + QTextCharFormat normal; + QTextCharFormat italics; + bold.setFontWeight(QFont::Bold); + normal.setFontWeight(QFont::Normal); + italics.setFontItalic(true); + const QTextCursor old_cursor = ui_ic_chatlog->textCursor(); + const int old_scrollbar_value = ui_ic_chatlog->verticalScrollBar()->value(); + + if (p_action == "") + p_text = filter_ic_text(p_text, ao_app->is_colorlog_enabled(), -1, + m_chatmessage[TEXT_COLOR].toInt()); + + if (log_goes_downwards) { + const bool is_scrolled_down = + old_scrollbar_value == ui_ic_chatlog->verticalScrollBar()->maximum(); + + ui_ic_chatlog->moveCursor(QTextCursor::End); + + if (!first_message_sent) { + ui_ic_chatlog->textCursor().insertText(p_name, bold); + first_message_sent = true; } else { - int msg_delay = message_display_speed[current_display_speed]; - //Do the colors, gradual showing, etc. in here - ui_vp_message->setHtml(additive_previous + filter_ic_text(f_message, true, tick_pos, m_chatmessage[TEXT_COLOR].toInt())); - - //This should always be done AFTER setHtml. Scroll the chat window with the text. - - //Make the cursor follow the message - QTextCursor cursor = ui_vp_message->textCursor(); - cursor.setPosition(real_tick_pos); - ui_vp_message->setTextCursor(cursor); - real_tick_pos += f_char_length; - - ui_vp_message->ensureCursorVisible(); - - // Keep the speed at bay. - if (current_display_speed < 0) - current_display_speed = 0; - else if (current_display_speed > 6) - current_display_speed = 6; - - //Blip player and real tick pos ticker - if (!formatting_char && (f_character != ' ' || blank_blip)) { - if (blip_ticker % blip_rate == 0) { - blip_player->blip_tick(); - } - ++blip_ticker; - } - - //Punctuation delayer - if (punctuation_chars.contains(f_character)) { - msg_delay *= punctuation_modifier; - } - - //If this color is talking - if (color_is_talking && anim_state != 2 && anim_state < 4) //Set it to talking as we're not on that already (though we have to avoid interrupting a non-interrupted preanim) - { - ui_vp_player_char->stop(); - ui_vp_player_char->play_talking(m_chatmessage[CHAR_NAME], m_chatmessage[EMOTE]); - anim_state = 2; - } - else if (!color_is_talking && anim_state < 3 && anim_state != 3) //Set it to idle as we're not on that already - { - ui_vp_player_char->stop(); - ui_vp_player_char->play_idle(m_chatmessage[CHAR_NAME], m_chatmessage[EMOTE]); - anim_state = 3; - } - //Continue ticking - chat_tick_timer->start(msg_delay); + ui_ic_chatlog->textCursor().insertText('\n' + p_name, bold); } + + if (p_action != "") { + ui_ic_chatlog->textCursor().insertText(" " + p_action + ": ", normal); + ui_ic_chatlog->textCursor().insertText(p_text + ".", italics); + } + else { + ui_ic_chatlog->textCursor().insertText(": ", normal); + ui_ic_chatlog->textCursor().insertHtml(p_text); + } + + // If we got too many blocks in the current log, delete some from the top. + while (ui_ic_chatlog->document()->blockCount() > log_maximum_blocks && + log_maximum_blocks > 0) { + ui_ic_chatlog->moveCursor(QTextCursor::Start); + ui_ic_chatlog->textCursor().select(QTextCursor::BlockUnderCursor); + ui_ic_chatlog->textCursor().removeSelectedText(); + ui_ic_chatlog->textCursor().deleteChar(); + } + + if (old_cursor.hasSelection() || !is_scrolled_down) { + // The user has selected text or scrolled away from the bottom: maintain + // position. + ui_ic_chatlog->setTextCursor(old_cursor); + ui_ic_chatlog->verticalScrollBar()->setValue(old_scrollbar_value); + } + else { + // The user hasn't selected any text and the scrollbar is at the bottom: + // scroll to the bottom. + ui_ic_chatlog->moveCursor(QTextCursor::End); + ui_ic_chatlog->verticalScrollBar()->setValue( + ui_ic_chatlog->verticalScrollBar()->maximum()); + } + } + else { + const bool is_scrolled_up = + old_scrollbar_value == ui_ic_chatlog->verticalScrollBar()->minimum(); + + ui_ic_chatlog->moveCursor(QTextCursor::Start); + + ui_ic_chatlog->textCursor().insertText(p_name, bold); + + if (p_action != "") { + ui_ic_chatlog->textCursor().insertText(" " + p_action + ": ", normal); + ui_ic_chatlog->textCursor().insertText(p_text + "." + '\n', italics); + } + else { + ui_ic_chatlog->textCursor().insertText(": ", normal); + ui_ic_chatlog->textCursor().insertText(p_text + '\n', normal); + } + + // If we got too many blocks in the current log, delete some from the + // bottom. + while (ui_ic_chatlog->document()->blockCount() > log_maximum_blocks && + log_maximum_blocks > 0) { + ui_ic_chatlog->moveCursor(QTextCursor::End); + ui_ic_chatlog->textCursor().select(QTextCursor::BlockUnderCursor); + ui_ic_chatlog->textCursor().removeSelectedText(); + ui_ic_chatlog->textCursor().deletePreviousChar(); + } + + if (old_cursor.hasSelection() || !is_scrolled_up) { + // The user has selected text or scrolled away from the top: maintain + // position. + ui_ic_chatlog->setTextCursor(old_cursor); + ui_ic_chatlog->verticalScrollBar()->setValue(old_scrollbar_value); + } + else { + // The user hasn't selected any text and the scrollbar is at the top: + // scroll to the top. + ui_ic_chatlog->moveCursor(QTextCursor::Start); + ui_ic_chatlog->verticalScrollBar()->setValue( + ui_ic_chatlog->verticalScrollBar()->minimum()); + } + } +} + +void Courtroom::play_preanim(bool noninterrupting) +{ + QString f_char = m_chatmessage[CHAR_NAME]; + QString f_preanim = m_chatmessage[PRE_EMOTE]; + + // all time values in char.inis are multiplied by a constant(time_mod) to get + // the actual time + int ao2_duration = ao_app->get_ao2_preanim_duration(f_char, f_preanim); + int text_delay = ao_app->get_text_delay(f_char, f_preanim) * time_mod; + int sfx_delay = m_chatmessage[SFX_DELAY].toInt() * time_mod; + + int preanim_duration; + + if (ao2_duration < 0) + preanim_duration = ao_app->get_preanim_duration(f_char, f_preanim); + else + preanim_duration = ao2_duration; + + sfx_delay_timer->start(sfx_delay); + QString anim_to_find = + ao_app->get_image_suffix(ao_app->get_character_path(f_char, f_preanim)); + if (!file_exists(anim_to_find)) { + if (noninterrupting) + anim_state = 4; + else + anim_state = 1; + preanim_done(); + qDebug() << "could not find " + anim_to_find; + return; + } + + ui_vp_player_char->play_pre(f_char, f_preanim, preanim_duration); + + if (noninterrupting) + anim_state = 4; + else + anim_state = 1; + + if (text_delay >= 0) + text_delay_timer->start(text_delay); + + if (noninterrupting) + handle_chatmessage_3(); +} + +void Courtroom::preanim_done() +{ + anim_state = 1; + handle_chatmessage_3(); +} + +void Courtroom::start_chat_ticking() +{ + // we need to ensure that the text isn't already ticking because this function + // can be called by two logic paths + if (text_state != 0) + return; + + if (m_chatmessage[EFFECTS] != "") { + QStringList fx_list = m_chatmessage[EFFECTS].split("|"); + QString fx = fx_list[0]; + QString fx_sound; + QString fx_folder; + + if (fx_list.length() > 1) + fx_sound = fx_list[1]; + + if (fx_list.length() > 2) { + fx_folder = fx_list[1]; + fx_sound = fx_list[2]; + } + + this->do_effect(fx, fx_sound, m_chatmessage[CHAR_NAME], fx_folder); + } + else if (m_chatmessage[REALIZATION] == "1") { + this->do_flash(); + sfx_player->play(ao_app->get_custom_realization(m_chatmessage[CHAR_NAME])); + } + if (chatmessage_is_empty) { + // since the message is empty, it's technically done ticking + text_state = 2; + return; + } + + ui_vp_chatbox->show(); + ui_vp_message->show(); + + if (!is_additive) { + ui_vp_message->clear(); + real_tick_pos = 0; + additive_previous = ""; + } + + tick_pos = 0; + blip_ticker = 0; + + // At the start of every new message, we set the text speed to the default. + current_display_speed = 3; + chat_tick_timer->start(0); // Display the first char right away + + QString f_gender = ao_app->get_gender(m_chatmessage[CHAR_NAME]); + + blip_player->set_blips(f_gender); + + int emote_mod = m_chatmessage[EMOTE_MOD].toInt(); // text meme bonanza + if ((emote_mod == 0 || emote_mod == 5) && m_chatmessage[SCREENSHAKE] == "1") { + this->do_screenshake(); + } + + // means text is currently ticking + text_state = 1; +} + +void Courtroom::chat_tick() +{ + // note: this is called fairly often + // do not perform heavy operations here + + QString f_message = m_chatmessage[MESSAGE]; + + // Due to our new text speed system, we always need to stop the timer now. + chat_tick_timer->stop(); + + if (tick_pos >= f_message.size()) { + text_state = 2; + if (anim_state < 3) { + anim_state = 3; + ui_vp_player_char->play_idle(m_chatmessage[CHAR_NAME], + m_chatmessage[EMOTE]); + } + QString f_char = m_chatmessage[CHAR_NAME]; + QString f_custom_theme = ao_app->get_chat(f_char); + ui_vp_chat_arrow->play( + "chat_arrow", f_char, + f_custom_theme); // Chat stopped being processed, indicate that. + additive_previous = + additive_previous + + filter_ic_text(f_message, true, -1, m_chatmessage[TEXT_COLOR].toInt()); + real_tick_pos = ui_vp_message->toPlainText().size(); + return; + } + + // Stops blips from playing when we have a formatting option. + bool formatting_char = false; + + QString f_rest = f_message; + + // Alignment characters + if (tick_pos < 2) { + if (f_rest.startsWith("~~")) { + tick_pos = f_rest.indexOf("~~"); + f_rest.remove(tick_pos, 2); + tick_pos += 2; + } + else if (f_rest.startsWith("~>")) { + tick_pos = f_rest.indexOf("~>"); + f_rest.remove(tick_pos, 2); + tick_pos += 2; + } + else if (f_rest.startsWith("<>")) { + tick_pos = f_rest.indexOf("<>"); + f_rest.remove(tick_pos, 2); + tick_pos += 2; + } + } + f_rest.remove(0, tick_pos); + QTextBoundaryFinder tbf(QTextBoundaryFinder::Grapheme, f_rest); + QString f_character; + int f_char_length; + + tbf.toNextBoundary(); + + if (tbf.position() == -1) + f_character = f_rest; + else + f_character = f_rest.left(tbf.position()); + + f_char_length = f_character.length(); + tick_pos += f_char_length; + + // Escape character. + if (!next_character_is_not_special) { + if (f_character == "\\") { + next_character_is_not_special = true; + formatting_char = true; + } + + // Text speed modifier. + else if (f_character == "{") { + // ++, because it INCREASES delay! + current_display_speed++; + formatting_char = true; + } + else if (f_character == "}") { + current_display_speed--; + formatting_char = true; + } + + else { + // Parse markdown colors + for (int c = 0; c < max_colors; ++c) { + QString markdown_start = color_markdown_start_list.at(c); + QString markdown_end = color_markdown_end_list.at(c); + bool markdown_remove = color_markdown_remove_list.at(c); + if (markdown_start.isEmpty()) + continue; + + if (f_character == markdown_start || f_character == markdown_end) { + if (markdown_remove) + formatting_char = true; + break; + } + } + } + } + else { + if (f_character == "n") + formatting_char = true; // it's a newline + if (f_character == "s") // Screenshake. + { + this->do_screenshake(); + formatting_char = true; + } + if (f_character == "f") // Flash. + { + this->do_flash(); + formatting_char = true; + } + next_character_is_not_special = false; + } + + if ((message_display_speed[current_display_speed] <= 0 && + tick_pos < f_message.size() - 1) || + formatting_char) { + chat_tick_timer->start(0); // Don't bother rendering anything out as we're + // doing the SPEED. (there's latency otherwise) + if (!formatting_char || f_character == "n" || f_character == "f" || + f_character == "s") + real_tick_pos += f_char_length; // Adjust the tick position for the + // scrollbar convenience + } + else { + int msg_delay = message_display_speed[current_display_speed]; + // Do the colors, gradual showing, etc. in here + ui_vp_message->setHtml(additive_previous + + filter_ic_text(f_message, true, tick_pos, + m_chatmessage[TEXT_COLOR].toInt())); + + // This should always be done AFTER setHtml. Scroll the chat window with the + // text. + + // Make the cursor follow the message + QTextCursor cursor = ui_vp_message->textCursor(); + cursor.setPosition(real_tick_pos); + ui_vp_message->setTextCursor(cursor); + real_tick_pos += f_char_length; + + ui_vp_message->ensureCursorVisible(); + + // Keep the speed at bay. + if (current_display_speed < 0) + current_display_speed = 0; + else if (current_display_speed > 6) + current_display_speed = 6; + + // Blip player and real tick pos ticker + if (!formatting_char && (f_character != ' ' || blank_blip)) { + if (blip_ticker % blip_rate == 0) { + blip_player->blip_tick(); + } + ++blip_ticker; + } + + // Punctuation delayer + if (punctuation_chars.contains(f_character)) { + msg_delay *= punctuation_modifier; + } + + // If this color is talking + if (color_is_talking && anim_state != 2 && + anim_state < + 4) // Set it to talking as we're not on that already (though we have + // to avoid interrupting a non-interrupted preanim) + { + ui_vp_player_char->stop(); + ui_vp_player_char->play_talking(m_chatmessage[CHAR_NAME], + m_chatmessage[EMOTE]); + anim_state = 2; + } + else if (!color_is_talking && anim_state < 3 && + anim_state != 3) // Set it to idle as we're not on that already + { + ui_vp_player_char->stop(); + ui_vp_player_char->play_idle(m_chatmessage[CHAR_NAME], + m_chatmessage[EMOTE]); + anim_state = 3; + } + // Continue ticking + chat_tick_timer->start(msg_delay); + } } void Courtroom::play_sfx() { - QString sfx_name = m_chatmessage[SFX_NAME]; - if (m_chatmessage[SCREENSHAKE] == "1") //Screenshake dependant on preanim sfx delay meme - { - this->do_screenshake(); - } - if (sfx_name == "1") - return; + QString sfx_name = m_chatmessage[SFX_NAME]; + if (m_chatmessage[SCREENSHAKE] == + "1") // Screenshake dependant on preanim sfx delay meme + { + this->do_screenshake(); + } + if (sfx_name == "1") + return; - sfx_player->play(sfx_name); - if (ao_app->get_looping_sfx()) - sfx_player->set_looping(ao_app->get_sfx_looping(current_char, sfx_name) != "0"); + sfx_player->play(sfx_name); + if (ao_app->get_looping_sfx()) + sfx_player->set_looping(ao_app->get_sfx_looping(current_char, sfx_name) != + "0"); } void Courtroom::set_scene(QString f_desk_mod, QString f_side) { - //witness is default if pos is invalid - QString f_background = "witnessempty"; - QString f_desk_image = "stand"; + // witness is default if pos is invalid + QString f_background = "witnessempty"; + QString f_desk_image = "stand"; - if (f_side == "def" && file_exists(ao_app->get_image_suffix(ao_app->get_background_path("defenseempty")))) { - f_background = "defenseempty"; - f_desk_image = "defensedesk"; - } - else if (f_side == "pro" && file_exists(ao_app->get_image_suffix(ao_app->get_background_path("prosecutorempty")))) { - f_background = "prosecutorempty"; - f_desk_image = "prosecutiondesk"; - } - else if (f_side == "jud" && file_exists(ao_app->get_image_suffix(ao_app->get_background_path("judgestand")))) { - f_background = "judgestand"; - f_desk_image = "judgedesk"; - } - else if (f_side == "hld" && file_exists(ao_app->get_image_suffix(ao_app->get_background_path("helperstand")))) { - f_background = "helperstand"; - f_desk_image = "helperdesk"; - } - else if (f_side == "hlp" && file_exists(ao_app->get_image_suffix(ao_app->get_background_path("prohelperstand")))) { - f_background = "prohelperstand"; - f_desk_image = "prohelperdesk"; - } - else if (f_side == "jur" && file_exists(ao_app->get_image_suffix(ao_app->get_background_path("jurystand")))) { - f_background = "jurystand"; - f_desk_image = "jurydesk"; - } - else if (f_side == "sea" && file_exists(ao_app->get_image_suffix(ao_app->get_background_path("seancestand")))) { - f_background = "seancestand"; - f_desk_image = "seancedesk"; - } + if (f_side == "def" && file_exists(ao_app->get_image_suffix( + ao_app->get_background_path("defenseempty")))) { + f_background = "defenseempty"; + f_desk_image = "defensedesk"; + } + else if (f_side == "pro" && + file_exists(ao_app->get_image_suffix( + ao_app->get_background_path("prosecutorempty")))) { + f_background = "prosecutorempty"; + f_desk_image = "prosecutiondesk"; + } + else if (f_side == "jud" && file_exists(ao_app->get_image_suffix( + ao_app->get_background_path("judgestand")))) { + f_background = "judgestand"; + f_desk_image = "judgedesk"; + } + else if (f_side == "hld" && + file_exists(ao_app->get_image_suffix( + ao_app->get_background_path("helperstand")))) { + f_background = "helperstand"; + f_desk_image = "helperdesk"; + } + else if (f_side == "hlp" && + file_exists(ao_app->get_image_suffix( + ao_app->get_background_path("prohelperstand")))) { + f_background = "prohelperstand"; + f_desk_image = "prohelperdesk"; + } + else if (f_side == "jur" && file_exists(ao_app->get_image_suffix( + ao_app->get_background_path("jurystand")))) { + f_background = "jurystand"; + f_desk_image = "jurydesk"; + } + else if (f_side == "sea" && + file_exists(ao_app->get_image_suffix( + ao_app->get_background_path("seancestand")))) { + f_background = "seancestand"; + f_desk_image = "seancedesk"; + } - if (file_exists(ao_app->get_image_suffix(ao_app->get_background_path(f_side)))) //Unique pos path - { - f_background = f_side; - f_desk_image = f_side + "_overlay"; - } + if (file_exists(ao_app->get_image_suffix( + ao_app->get_background_path(f_side)))) // Unique pos path + { + f_background = f_side; + f_desk_image = f_side + "_overlay"; + } - ui_vp_background->set_image(f_background); - ui_vp_desk->set_image(f_desk_image); - ui_vp_legacy_desk->set_legacy_desk(f_desk_image); + ui_vp_background->set_image(f_background); + ui_vp_desk->set_image(f_desk_image); + ui_vp_legacy_desk->set_legacy_desk(f_desk_image); - if (f_desk_mod == "0" || (f_desk_mod != "1" && - (f_side == "jud" || - f_side == "hld" || - f_side == "hlp"))) { - ui_vp_desk->hide(); - ui_vp_legacy_desk->hide(); - } - else { - ui_vp_legacy_desk->hide(); - ui_vp_desk->show(); - } + if (f_desk_mod == "0" || + (f_desk_mod != "1" && + (f_side == "jud" || f_side == "hld" || f_side == "hlp"))) { + ui_vp_desk->hide(); + ui_vp_legacy_desk->hide(); + } + else { + ui_vp_legacy_desk->hide(); + ui_vp_desk->show(); + } } void Courtroom::set_ip_list(QString p_list) { - QString f_list = p_list.replace("|", ":").replace("*", "\n"); + QString f_list = p_list.replace("|", ":").replace("*", "\n"); - ui_server_chatlog->append(f_list); + ui_server_chatlog->append(f_list); } void Courtroom::set_mute(bool p_muted, int p_cid) { - if (p_cid != m_cid && p_cid != -1) - return; + if (p_cid != m_cid && p_cid != -1) + return; - if (p_muted) - ui_muted->show(); - else { - ui_muted->hide(); - ui_ic_chat_message->setFocus(); - } + if (p_muted) + ui_muted->show(); + else { + ui_muted->hide(); + ui_ic_chat_message->setFocus(); + } - ui_muted->resize(ui_ic_chat_message->width(), ui_ic_chat_message->height()); - ui_muted->set_image("muted"); + ui_muted->resize(ui_ic_chat_message->width(), ui_ic_chat_message->height()); + ui_muted->set_image("muted"); - is_muted = p_muted; - ui_ic_chat_message->setEnabled(!p_muted); + is_muted = p_muted; + ui_ic_chat_message->setEnabled(!p_muted); } void Courtroom::set_ban(int p_cid) { - if (p_cid != m_cid && p_cid != -1) - return; + if (p_cid != m_cid && p_cid != -1) + return; - call_notice("You have been banned."); + call_notice("You have been banned."); - ao_app->construct_lobby(); - ao_app->destruct_courtroom(); + ao_app->construct_lobby(); + ao_app->destruct_courtroom(); } void Courtroom::handle_song(QStringList *p_contents) { - QStringList f_contents = *p_contents; + QStringList f_contents = *p_contents; - if (f_contents.size() < 2) - return; + if (f_contents.size() < 2) + return; - QString f_song = f_contents.at(0); - QString f_song_clear = f_song.left(f_song.lastIndexOf(".")); - f_song_clear = f_song_clear.right(f_song_clear.length() - (f_song_clear.lastIndexOf("/") + 1)); - int n_char = f_contents.at(1).toInt(); + QString f_song = f_contents.at(0); + QString f_song_clear = f_song.left(f_song.lastIndexOf(".")); + f_song_clear = f_song_clear.right(f_song_clear.length() - + (f_song_clear.lastIndexOf("/") + 1)); + int n_char = f_contents.at(1).toInt(); - bool looping = true; + bool looping = true; + int channel = 0; + int effect_flags = 0; + if (n_char < 0 || n_char >= char_list.size()) { int channel = 0; - int effect_flags = 0; - if (n_char < 0 || n_char >= char_list.size()) { - int channel = 0; - if (p_contents->length() > 3 && p_contents->at(3) != "-1") - looping = false; + if (p_contents->length() > 3 && p_contents->at(3) != "-1") + looping = false; - if (p_contents->length() > 4) //eyyy we want to change this song's CHANNEL huh - channel = p_contents->at(4).toInt(); //let the music player handle it if it's bigger than the channel list + if (p_contents->length() > + 4) // eyyy we want to change this song's CHANNEL huh + channel = p_contents->at(4).toInt(); // let the music player handle it if + // it's bigger than the channel list - if (p_contents->length() > 5) //Flags provided to us by server such as Fade In, Fade Out, Sync Pos etc. - { - effect_flags = p_contents->at(5).toInt(); - } - - music_player->play(f_song, channel, looping, effect_flags); - if (channel == 0) - ui_music_name->setText(f_song_clear); + if (p_contents->length() > 5) // Flags provided to us by server such as Fade + // In, Fade Out, Sync Pos etc. + { + effect_flags = p_contents->at(5).toInt(); } - else { - QString str_char = char_list.at(n_char).name; - QString str_show = char_list.at(n_char).name; - if (p_contents->length() > 2) { - if (p_contents->at(2) != "") { - str_show = p_contents->at(2); - } - } - if (p_contents->length() > 3 && p_contents->at(3) != "-1") { - //I am really confused why "-1" is "loop this song" and why anything else passes as "don't loop" - //(if we even have this length) but alright - looping = false; - } - if (p_contents->length() > 4) //eyyy we want to change this song's CHANNEL huh - channel = p_contents->at(4).toInt(); //let the music player handle it if it's bigger than the channel list + music_player->play(f_song, channel, looping, effect_flags); + if (channel == 0) + ui_music_name->setText(f_song_clear); + } + else { + QString str_char = char_list.at(n_char).name; + QString str_show = char_list.at(n_char).name; - if (p_contents->length() > 5) //Flags provided to us by server such as Fade In, Fade Out, Sync Pos etc. - { - effect_flags = p_contents->at(5).toInt(); - } - - if (!mute_map.value(n_char)) { - chatlogpiece *temp = new chatlogpiece(str_char, str_show, f_song, true); - ic_chatlog_history.append(*temp); - ao_app->append_to_file(temp->get_full(), ao_app->log_filename, true); - - while (ic_chatlog_history.size() > log_maximum_blocks && log_maximum_blocks > 0) { - ic_chatlog_history.removeFirst(); - } - - append_ic_text(f_song_clear, str_show, "has played a song"); - - music_player->play(f_song, channel, looping, effect_flags); - if (channel == 0) - ui_music_name->setText(f_song_clear); - } + if (p_contents->length() > 2) { + if (p_contents->at(2) != "") { + str_show = p_contents->at(2); + } } + if (p_contents->length() > 3 && p_contents->at(3) != "-1") { + // I am really confused why "-1" is "loop this song" and why anything else + // passes as "don't loop" (if we even have this length) but alright + looping = false; + } + if (p_contents->length() > + 4) // eyyy we want to change this song's CHANNEL huh + channel = p_contents->at(4).toInt(); // let the music player handle it if + // it's bigger than the channel list + + if (p_contents->length() > 5) // Flags provided to us by server such as Fade + // In, Fade Out, Sync Pos etc. + { + effect_flags = p_contents->at(5).toInt(); + } + + if (!mute_map.value(n_char)) { + chatlogpiece *temp = new chatlogpiece(str_char, str_show, f_song, true); + ic_chatlog_history.append(*temp); + ao_app->append_to_file(temp->get_full(), ao_app->log_filename, true); + + while (ic_chatlog_history.size() > log_maximum_blocks && + log_maximum_blocks > 0) { + ic_chatlog_history.removeFirst(); + } + + append_ic_text(f_song_clear, str_show, "has played a song"); + + music_player->play(f_song, channel, looping, effect_flags); + if (channel == 0) + ui_music_name->setText(f_song_clear); + } + } } void Courtroom::handle_wtce(QString p_wtce, int variant) { - QString sfx_file = "courtroom_sounds.ini"; + QString sfx_file = "courtroom_sounds.ini"; - //witness testimony - if (p_wtce == "testimony1") { - sfx_player->play(ao_app->get_sfx("witness_testimony")); - ui_vp_wtce->play("witnesstestimony", "", "", 1500); - ui_vp_testimony->play("testimony"); + // witness testimony + if (p_wtce == "testimony1") { + sfx_player->play(ao_app->get_sfx("witness_testimony")); + ui_vp_wtce->play("witnesstestimony", "", "", 1500); + ui_vp_testimony->play("testimony"); + } + // cross examination + else if (p_wtce == "testimony2") { + sfx_player->play(ao_app->get_sfx("cross_examination")); + ui_vp_wtce->play("crossexamination", "", "", 1500); + ui_vp_testimony->stop(); + } + else if (p_wtce == "judgeruling") { + if (variant == 0) { + sfx_player->play(ao_app->get_sfx("not_guilty")); + ui_vp_wtce->play("notguilty", "", "", 3000); + ui_vp_testimony->stop(); } - //cross examination - else if (p_wtce == "testimony2") { - sfx_player->play(ao_app->get_sfx("cross_examination")); - ui_vp_wtce->play("crossexamination", "", "", 1500); - ui_vp_testimony->stop(); - } - else if (p_wtce == "judgeruling") { - if (variant == 0) { - sfx_player->play(ao_app->get_sfx("not_guilty")); - ui_vp_wtce->play("notguilty", "", "", 3000); - ui_vp_testimony->stop(); - } - else if (variant == 1) { - sfx_player->play(ao_app->get_sfx("guilty")); - ui_vp_wtce->play("guilty", "", "", 3000); - ui_vp_testimony->stop(); - } + else if (variant == 1) { + sfx_player->play(ao_app->get_sfx("guilty")); + ui_vp_wtce->play("guilty", "", "", 3000); + ui_vp_testimony->stop(); } + } } void Courtroom::set_hp_bar(int p_bar, int p_state) { - if (p_state < 0 || p_state > 10) - return; + if (p_state < 0 || p_state > 10) + return; - if (p_bar == 1) { - ui_defense_bar->set_image("defensebar" + QString::number(p_state)); - defense_bar_state = p_state; - } - else if (p_bar == 2) { - ui_prosecution_bar->set_image("prosecutionbar" + QString::number(p_state)); - prosecution_bar_state = p_state; - } + if (p_bar == 1) { + ui_defense_bar->set_image("defensebar" + QString::number(p_state)); + defense_bar_state = p_state; + } + else if (p_bar == 2) { + ui_prosecution_bar->set_image("prosecutionbar" + QString::number(p_state)); + prosecution_bar_state = p_state; + } } void Courtroom::toggle_judge_buttons(bool is_on) { - if (is_on) { - ui_witness_testimony->show(); - ui_cross_examination->show(); - ui_guilty->show(); - ui_not_guilty->show(); - ui_defense_minus->show(); - ui_defense_plus->show(); - ui_prosecution_minus->show(); - ui_prosecution_plus->show(); - } - else { - ui_witness_testimony->hide(); - ui_cross_examination->hide(); - ui_guilty->hide(); - ui_not_guilty->hide(); - ui_defense_minus->hide(); - ui_defense_plus->hide(); - ui_prosecution_minus->hide(); - ui_prosecution_plus->hide(); - } + if (is_on) { + ui_witness_testimony->show(); + ui_cross_examination->show(); + ui_guilty->show(); + ui_not_guilty->show(); + ui_defense_minus->show(); + ui_defense_plus->show(); + ui_prosecution_minus->show(); + ui_prosecution_plus->show(); + } + else { + ui_witness_testimony->hide(); + ui_cross_examination->hide(); + ui_guilty->hide(); + ui_not_guilty->hide(); + ui_defense_minus->hide(); + ui_defense_plus->hide(); + ui_prosecution_minus->hide(); + ui_prosecution_plus->hide(); + } } 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")); - ao_app->alert(this); - } + ui_server_chatlog->append(p_ip); + if (!ui_guard->isChecked()) { + modcall_player->play(ao_app->get_sfx("mod_call")); + ao_app->alert(this); + } } -void Courtroom::case_called(QString msg, bool def, bool pro, bool jud, bool jur, bool steno) +void Courtroom::case_called(QString msg, bool def, bool pro, bool jud, bool jur, + bool steno) { - if (ui_casing->isChecked()) { - ui_server_chatlog->append(msg); - if ((ao_app->get_casing_defence_enabled() && def) || - (ao_app->get_casing_prosecution_enabled() && pro) || - (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")); - ao_app->alert(this); - } + if (ui_casing->isChecked()) { + ui_server_chatlog->append(msg); + if ((ao_app->get_casing_defence_enabled() && def) || + (ao_app->get_casing_prosecution_enabled() && pro) || + (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")); + ao_app->alert(this); } + } } void Courtroom::on_ooc_return_pressed() { - QString ooc_message = ui_ooc_chat_message->text(); + QString ooc_message = ui_ooc_chat_message->text(); - if (ooc_message == "" || ui_ooc_chat_name->text() == "") - return; + if (ooc_message == "" || ui_ooc_chat_name->text() == "") + return; - if (ooc_message.startsWith("/pos")) { - if (ooc_message == "/pos jud") { - toggle_judge_buttons(true); - } - else { - toggle_judge_buttons(false); - } + if (ooc_message.startsWith("/pos")) { + if (ooc_message == "/pos jud") { + toggle_judge_buttons(true); } - else if (ooc_message.startsWith("/settings")) { - ui_ooc_chat_message->clear(); - ao_app->call_settings_menu(); - append_server_chatmessage("CLIENT", tr("You opened the settings menu."), "1"); - return; + else { + toggle_judge_buttons(false); } - else if (ooc_message.startsWith("/pair")) { - ui_ooc_chat_message->clear(); - ooc_message.remove(0, 6); - - bool ok; - int whom = ooc_message.toInt(&ok); - if (ok) { - if (whom > -1) { - other_charid = whom; - QString msg = tr("You will now pair up with "); - msg.append(char_list.at(whom).name); - msg.append(tr(" if they also choose your character in return.")); - append_server_chatmessage("CLIENT", msg, "1"); - } - else { - other_charid = -1; - append_server_chatmessage("CLIENT", tr("You are no longer paired with anyone."), "1"); - } - } - else { - append_server_chatmessage("CLIENT", tr("Are you sure you typed that well? The char ID could not be recognised."), "1"); - } - return; - } - else if (ooc_message.startsWith("/offset")) { - ui_ooc_chat_message->clear(); - ooc_message.remove(0, 8); - - bool ok; - int off = ooc_message.toInt(&ok); - if (ok) { - if (off >= -100 && off <= 100) { - char_offset = off; - QString msg = tr("You have set your offset to "); - msg.append(QString::number(off)); - msg.append("%."); - append_server_chatmessage("CLIENT", msg, "1"); - } - else { - append_server_chatmessage("CLIENT", tr("Your offset must be between -100% and 100%!"), "1"); - } - } - else { - append_server_chatmessage("CLIENT", tr("That offset does not look like one."), "1"); - } - return; - } - else if (ooc_message.startsWith("/switch_am")) { - append_server_chatmessage("CLIENT", tr("You switched your music and area list."), "1"); - on_switch_area_music_clicked(); - ui_ooc_chat_message->clear(); - return; - } - else if (ooc_message.startsWith("/enable_blocks")) { - append_server_chatmessage("CLIENT", tr("You have forcefully enabled features that the server may not support. You may not be able to talk IC, or worse, because of this."), "1"); - ao_app->cccc_ic_support_enabled = true; - ao_app->arup_enabled = true; - ao_app->modcall_reason_enabled = true; - on_reload_theme_clicked(); - ui_ooc_chat_message->clear(); - return; - } - else if (ooc_message.startsWith("/non_int_pre")) { - if (ui_pre_non_interrupt->isChecked()) - append_server_chatmessage("CLIENT", tr("Your pre-animations interrupt again."), "1"); - else - append_server_chatmessage("CLIENT", tr("Your pre-animations will not interrupt text."), "1"); - ui_pre_non_interrupt->setChecked(!ui_pre_non_interrupt->isChecked()); - ui_ooc_chat_message->clear(); - return; - } - else if (ooc_message.startsWith("/save_chatlog")) { - QFile file("chatlog.txt"); - - if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) { - append_server_chatmessage("CLIENT", tr("Couldn't open chatlog.txt to write into."), "1"); - ui_ooc_chat_message->clear(); - return; - } - - QTextStream out(&file); - - foreach (chatlogpiece item, ic_chatlog_history) { - out << item.get_full() << '\n'; - } - - file.close(); - - append_server_chatmessage("CLIENT", tr("The IC chatlog has been saved."), "1"); - ui_ooc_chat_message->clear(); - return; - } - else if (ooc_message.startsWith("/load_case")) { - QStringList command = ooc_message.split(" ", QString::SkipEmptyParts); - - QDir casefolder("base/cases"); - if (!casefolder.exists()) { - QDir::current().mkdir("base/" + casefolder.dirName()); - append_server_chatmessage("CLIENT", tr("You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely the case file you're looking for can't be found in there."), "1"); - ui_ooc_chat_message->clear(); - return; - } - QStringList caseslist = casefolder.entryList(); - caseslist.removeOne("."); - caseslist.removeOne(".."); - caseslist.replaceInStrings(".ini", ""); - - if (command.size() < 2) { - append_server_chatmessage("CLIENT", tr("You need to give a filename to load (extension not needed)! Make sure that it is in the `base/cases/` folder, and that it is a correctly formatted ini.\nCases you can load: %1").arg(caseslist.join(", ")), "1"); - ui_ooc_chat_message->clear(); - return; - } - - if (command.size() > 2) { - append_server_chatmessage("CLIENT", tr("Too many arguments to load a case! You only need one filename, without extension."), "1"); - ui_ooc_chat_message->clear(); - return; - } - - QSettings casefile("base/cases/" + command[1] + ".ini", QSettings::IniFormat); - - QString caseauth = casefile.value("author", "").value(); - QString casedoc = casefile.value("doc", "").value(); - QString cmdoc = casefile.value("cmdoc", "").value(); - QString casestatus = casefile.value("status", "").value(); - - if (!caseauth.isEmpty()) - append_server_chatmessage("CLIENT", tr("Case made by %1.").arg(caseauth), "1"); - if (!casedoc.isEmpty()) - ao_app->send_server_packet(new AOPacket("CT#" + ui_ooc_chat_name->text() + "#/doc " + casedoc + "#%")); - if (!casestatus.isEmpty()) - ao_app->send_server_packet(new AOPacket("CT#" + ui_ooc_chat_name->text() + "#/status " + casestatus + "#%")); - if (!cmdoc.isEmpty()) - append_server_chatmessage("CLIENT", tr("Navigate to %1 for the CM doc.").arg(cmdoc), "1"); - - for (int i = local_evidence_list.size() - 1; i >= 0; i--) { - ao_app->send_server_packet(new AOPacket("DE#" + QString::number(i) + "#%")); - } - - foreach (QString evi, casefile.childGroups()) { - if (evi == "General") - continue; - - QStringList f_contents; - - f_contents.append(casefile.value(evi + "/name", "UNKNOWN").value()); - f_contents.append(casefile.value(evi + "/description", "UNKNOWN").value()); - f_contents.append(casefile.value(evi + "/image", "UNKNOWN.png").value()); - - ao_app->send_server_packet(new AOPacket("PE", f_contents)); - } - - append_server_chatmessage("CLIENT", tr("Your case \"%1\" was loaded!").arg(command[1]), "1"); - ui_ooc_chat_message->clear(); - return; - } - else if (ooc_message.startsWith("/save_case")) { - QStringList command = ooc_message.split(" ", QString::SkipEmptyParts); - - QDir casefolder("base/cases"); - if (!casefolder.exists()) { - QDir::current().mkdir("base/" + casefolder.dirName()); - append_server_chatmessage("CLIENT", tr("You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely that you somehow deleted it."), "1"); - ui_ooc_chat_message->clear(); - return; - } - QStringList caseslist = casefolder.entryList(); - caseslist.removeOne("."); - caseslist.removeOne(".."); - caseslist.replaceInStrings(".ini", ""); - - if (command.size() < 3) { - append_server_chatmessage("CLIENT", tr("You need to give a filename to save (extension not needed) and the courtroom status!"), "1"); - ui_ooc_chat_message->clear(); - return; - } - - if (command.size() > 3) { - append_server_chatmessage("CLIENT", tr("Too many arguments to save a case! You only need a filename without extension and the courtroom status!"), "1"); - ui_ooc_chat_message->clear(); - return; - } - QSettings casefile("base/cases/" + command[1] + ".ini", QSettings::IniFormat); - casefile.setValue("author", ui_ooc_chat_name->text()); - casefile.setValue("cmdoc", ""); - casefile.setValue("doc", ""); - casefile.setValue("status", command[2]); - casefile.sync(); - for (int i = 0; i < local_evidence_list.size(); i++) { - QString clean_evidence_dsc = local_evidence_list[i].description.replace(QRegularExpression("..."), ""); - clean_evidence_dsc = clean_evidence_dsc.replace(clean_evidence_dsc.lastIndexOf(">"), 1, ""); - casefile.beginGroup(QString::number(i)); - casefile.sync(); - casefile.setValue("name", local_evidence_list[i].name); - casefile.setValue("description", local_evidence_list[i].description); - casefile.setValue("image", local_evidence_list[i].image); - casefile.endGroup(); - } - casefile.sync(); - append_server_chatmessage("CLIENT", tr("Succesfully saved, edit doc and cmdoc link on the ini!"), "1"); - ui_ooc_chat_message->clear(); - return; - } - - QStringList packet_contents; - packet_contents.append(ui_ooc_chat_name->text()); - packet_contents.append(ooc_message); - - AOPacket *f_packet = new AOPacket("CT", packet_contents); - - if (server_ooc) - ao_app->send_server_packet(f_packet); - else - ao_app->send_ms_packet(f_packet); - + } + else if (ooc_message.startsWith("/settings")) { ui_ooc_chat_message->clear(); + ao_app->call_settings_menu(); + append_server_chatmessage("CLIENT", tr("You opened the settings menu."), + "1"); + return; + } + else if (ooc_message.startsWith("/pair")) { + ui_ooc_chat_message->clear(); + ooc_message.remove(0, 6); - ui_ooc_chat_message->setFocus(); + bool ok; + int whom = ooc_message.toInt(&ok); + if (ok) { + if (whom > -1) { + other_charid = whom; + QString msg = tr("You will now pair up with "); + msg.append(char_list.at(whom).name); + msg.append(tr(" if they also choose your character in return.")); + append_server_chatmessage("CLIENT", msg, "1"); + } + else { + other_charid = -1; + append_server_chatmessage( + "CLIENT", tr("You are no longer paired with anyone."), "1"); + } + } + else { + append_server_chatmessage("CLIENT", + tr("Are you sure you typed that well? The char " + "ID could not be recognised."), + "1"); + } + return; + } + else if (ooc_message.startsWith("/offset")) { + ui_ooc_chat_message->clear(); + ooc_message.remove(0, 8); + + bool ok; + int off = ooc_message.toInt(&ok); + if (ok) { + if (off >= -100 && off <= 100) { + char_offset = off; + QString msg = tr("You have set your offset to "); + msg.append(QString::number(off)); + msg.append("%."); + append_server_chatmessage("CLIENT", msg, "1"); + } + else { + append_server_chatmessage( + "CLIENT", tr("Your offset must be between -100% and 100%!"), "1"); + } + } + else { + append_server_chatmessage("CLIENT", + tr("That offset does not look like one."), "1"); + } + return; + } + else if (ooc_message.startsWith("/switch_am")) { + append_server_chatmessage( + "CLIENT", tr("You switched your music and area list."), "1"); + on_switch_area_music_clicked(); + ui_ooc_chat_message->clear(); + return; + } + else if (ooc_message.startsWith("/enable_blocks")) { + append_server_chatmessage("CLIENT", + tr("You have forcefully enabled features that " + "the server may not support. You may not be " + "able to talk IC, or worse, because of this."), + "1"); + ao_app->cccc_ic_support_enabled = true; + ao_app->arup_enabled = true; + ao_app->modcall_reason_enabled = true; + on_reload_theme_clicked(); + ui_ooc_chat_message->clear(); + return; + } + else if (ooc_message.startsWith("/non_int_pre")) { + if (ui_pre_non_interrupt->isChecked()) + append_server_chatmessage( + "CLIENT", tr("Your pre-animations interrupt again."), "1"); + else + append_server_chatmessage( + "CLIENT", tr("Your pre-animations will not interrupt text."), "1"); + ui_pre_non_interrupt->setChecked(!ui_pre_non_interrupt->isChecked()); + ui_ooc_chat_message->clear(); + return; + } + else if (ooc_message.startsWith("/save_chatlog")) { + QFile file("chatlog.txt"); + + if (!file.open(QIODevice::WriteOnly | QIODevice::Text | + QIODevice::Truncate)) { + append_server_chatmessage( + "CLIENT", tr("Couldn't open chatlog.txt to write into."), "1"); + ui_ooc_chat_message->clear(); + return; + } + + QTextStream out(&file); + + foreach (chatlogpiece item, ic_chatlog_history) { + out << item.get_full() << '\n'; + } + + file.close(); + + append_server_chatmessage("CLIENT", tr("The IC chatlog has been saved."), + "1"); + ui_ooc_chat_message->clear(); + return; + } + else if (ooc_message.startsWith("/load_case")) { + QStringList command = ooc_message.split(" ", QString::SkipEmptyParts); + + QDir casefolder("base/cases"); + if (!casefolder.exists()) { + QDir::current().mkdir("base/" + casefolder.dirName()); + append_server_chatmessage( + "CLIENT", + tr("You don't have a `base/cases/` folder! It was just made for you, " + "but seeing as it WAS just made for you, it's likely the case " + "file you're looking for can't be found in there."), + "1"); + ui_ooc_chat_message->clear(); + return; + } + QStringList caseslist = casefolder.entryList(); + caseslist.removeOne("."); + caseslist.removeOne(".."); + caseslist.replaceInStrings(".ini", ""); + + if (command.size() < 2) { + append_server_chatmessage( + "CLIENT", + tr("You need to give a filename to load (extension not needed)! Make " + "sure that it is in the `base/cases/` folder, and that it is a " + "correctly formatted ini.\nCases you can load: %1") + .arg(caseslist.join(", ")), + "1"); + ui_ooc_chat_message->clear(); + return; + } + + if (command.size() > 2) { + append_server_chatmessage( + "CLIENT", + tr("Too many arguments to load a case! You only need one filename, " + "without extension."), + "1"); + ui_ooc_chat_message->clear(); + return; + } + + QSettings casefile("base/cases/" + command[1] + ".ini", + QSettings::IniFormat); + + QString caseauth = casefile.value("author", "").value(); + QString casedoc = casefile.value("doc", "").value(); + QString cmdoc = casefile.value("cmdoc", "").value(); + QString casestatus = casefile.value("status", "").value(); + + if (!caseauth.isEmpty()) + append_server_chatmessage("CLIENT", tr("Case made by %1.").arg(caseauth), + "1"); + if (!casedoc.isEmpty()) + ao_app->send_server_packet(new AOPacket("CT#" + ui_ooc_chat_name->text() + + "#/doc " + casedoc + "#%")); + if (!casestatus.isEmpty()) + ao_app->send_server_packet(new AOPacket("CT#" + ui_ooc_chat_name->text() + + "#/status " + casestatus + "#%")); + if (!cmdoc.isEmpty()) + append_server_chatmessage( + "CLIENT", tr("Navigate to %1 for the CM doc.").arg(cmdoc), "1"); + + for (int i = local_evidence_list.size() - 1; i >= 0; i--) { + ao_app->send_server_packet( + new AOPacket("DE#" + QString::number(i) + "#%")); + } + + foreach (QString evi, casefile.childGroups()) { + if (evi == "General") + continue; + + QStringList f_contents; + + f_contents.append( + casefile.value(evi + "/name", "UNKNOWN").value()); + f_contents.append( + casefile.value(evi + "/description", "UNKNOWN").value()); + f_contents.append( + casefile.value(evi + "/image", "UNKNOWN.png").value()); + + ao_app->send_server_packet(new AOPacket("PE", f_contents)); + } + + append_server_chatmessage( + "CLIENT", tr("Your case \"%1\" was loaded!").arg(command[1]), "1"); + ui_ooc_chat_message->clear(); + return; + } + else if (ooc_message.startsWith("/save_case")) { + QStringList command = ooc_message.split(" ", QString::SkipEmptyParts); + + QDir casefolder("base/cases"); + if (!casefolder.exists()) { + QDir::current().mkdir("base/" + casefolder.dirName()); + append_server_chatmessage( + "CLIENT", + tr("You don't have a `base/cases/` folder! It was just made for you, " + "but seeing as it WAS just made for you, it's likely that you " + "somehow deleted it."), + "1"); + ui_ooc_chat_message->clear(); + return; + } + QStringList caseslist = casefolder.entryList(); + caseslist.removeOne("."); + caseslist.removeOne(".."); + caseslist.replaceInStrings(".ini", ""); + + if (command.size() < 3) { + append_server_chatmessage( + "CLIENT", + tr("You need to give a filename to save (extension not needed) and " + "the courtroom status!"), + "1"); + ui_ooc_chat_message->clear(); + return; + } + + if (command.size() > 3) { + append_server_chatmessage( + "CLIENT", + tr("Too many arguments to save a case! You only need a filename " + "without extension and the courtroom status!"), + "1"); + ui_ooc_chat_message->clear(); + return; + } + QSettings casefile("base/cases/" + command[1] + ".ini", + QSettings::IniFormat); + casefile.setValue("author", ui_ooc_chat_name->text()); + casefile.setValue("cmdoc", ""); + casefile.setValue("doc", ""); + casefile.setValue("status", command[2]); + casefile.sync(); + for (int i = 0; i < local_evidence_list.size(); i++) { + QString clean_evidence_dsc = local_evidence_list[i].description.replace( + QRegularExpression("..."), ""); + clean_evidence_dsc = clean_evidence_dsc.replace( + clean_evidence_dsc.lastIndexOf(">"), 1, ""); + casefile.beginGroup(QString::number(i)); + casefile.sync(); + casefile.setValue("name", local_evidence_list[i].name); + casefile.setValue("description", local_evidence_list[i].description); + casefile.setValue("image", local_evidence_list[i].image); + casefile.endGroup(); + } + casefile.sync(); + append_server_chatmessage( + "CLIENT", tr("Succesfully saved, edit doc and cmdoc link on the ini!"), + "1"); + ui_ooc_chat_message->clear(); + return; + } + + QStringList packet_contents; + packet_contents.append(ui_ooc_chat_name->text()); + packet_contents.append(ooc_message); + + AOPacket *f_packet = new AOPacket("CT", packet_contents); + + if (server_ooc) + ao_app->send_server_packet(f_packet); + else + ao_app->send_ms_packet(f_packet); + + ui_ooc_chat_message->clear(); + + ui_ooc_chat_message->setFocus(); } void Courtroom::on_ooc_toggle_clicked() { - if (server_ooc) { - ui_ms_chatlog->show(); - ui_server_chatlog->hide(); - ui_ooc_toggle->setText(tr("Master")); + if (server_ooc) { + ui_ms_chatlog->show(); + ui_server_chatlog->hide(); + ui_ooc_toggle->setText(tr("Master")); - server_ooc = false; - } - else { - ui_ms_chatlog->hide(); - ui_server_chatlog->show(); - ui_ooc_toggle->setText(tr("Server")); + server_ooc = false; + } + else { + ui_ms_chatlog->hide(); + ui_server_chatlog->show(); + ui_ooc_toggle->setText(tr("Server")); - server_ooc = true; - } + server_ooc = true; + } } -//Todo: multithread this due to some servers having large as hell music list +// Todo: multithread this due to some servers having large as hell music list void Courtroom::on_music_search_edited(QString p_text) { - // Iterate through all QTreeWidgetItem items + // Iterate through all QTreeWidgetItem items + if (!ui_music_list->isHidden()) { + QTreeWidgetItemIterator it(ui_music_list); + while (*it) { + (*it)->setHidden(p_text != ""); + ++it; + } + } + + if (!ui_area_list->isHidden()) { + QTreeWidgetItemIterator ait(ui_area_list); + while (*ait) { + (*ait)->setHidden(p_text != ""); + ++ait; + } + } + + if (p_text != "") { if (!ui_music_list->isHidden()) { - QTreeWidgetItemIterator it(ui_music_list); - while (*it) { - (*it)->setHidden(p_text != ""); - ++it; - } + // Search in metadata + QList clist = ui_music_list->findItems( + ui_music_search->text(), Qt::MatchContains | Qt::MatchRecursive, 1); + foreach (QTreeWidgetItem *item, clist) { + if (item->parent() != nullptr) // So the category shows up too + item->parent()->setHidden(false); + item->setHidden(false); + } } if (!ui_area_list->isHidden()) { - QTreeWidgetItemIterator ait(ui_area_list); - while (*ait) { - (*ait)->setHidden(p_text != ""); - ++ait; - } - } - - if (p_text != "") { - if (!ui_music_list->isHidden()) { - //Search in metadata - QList clist = ui_music_list->findItems(ui_music_search->text(), Qt::MatchContains | Qt::MatchRecursive, 1); - foreach (QTreeWidgetItem *item, clist) { - if (item->parent() != nullptr) //So the category shows up too - item->parent()->setHidden(false); - item->setHidden(false); - } - } - - if (!ui_area_list->isHidden()) { - //Search in metadata - QList alist = ui_area_list->findItems(ui_music_search->text(), Qt::MatchContains | Qt::MatchRecursive, 1); - foreach (QTreeWidgetItem *item, alist) { - if (item->parent() != nullptr) //So the category shows up too - item->parent()->setHidden(false); - item->setHidden(false); - } - } + // Search in metadata + QList alist = ui_area_list->findItems( + ui_music_search->text(), Qt::MatchContains | Qt::MatchRecursive, 1); + foreach (QTreeWidgetItem *item, alist) { + if (item->parent() != nullptr) // So the category shows up too + item->parent()->setHidden(false); + item->setHidden(false); + } } + } } void Courtroom::on_pos_dropdown_changed(int p_index) { - if (p_index < 0 || p_index > 7) - return; + if (p_index < 0 || p_index > 7) + return; - toggle_judge_buttons(false); + toggle_judge_buttons(false); - QString f_pos = ui_pos_dropdown->itemText(p_index); + QString f_pos = ui_pos_dropdown->itemText(p_index); - if (f_pos == "") - return; + if (f_pos == "") + return; - if (f_pos == "jud") - toggle_judge_buttons(true); + if (f_pos == "jud") + toggle_judge_buttons(true); - //YEAH SENDING LIKE 20 PACKETS IF THE USER SCROLLS THROUGH, GREAT IDEA - //how about this instead - set_side(f_pos); + // YEAH SENDING LIKE 20 PACKETS IF THE USER SCROLLS THROUGH, GREAT IDEA + // how about this instead + set_side(f_pos); } void Courtroom::set_iniswap_dropdown() { - ui_iniswap_dropdown->blockSignals(true); - ui_iniswap_dropdown->clear(); - if (m_cid == -1) { - ui_iniswap_dropdown->hide(); - ui_iniswap_remove->hide(); - return; - } - QStringList iniswaps = ao_app->get_list_file(ao_app->get_character_path(char_list.at(m_cid).name, "iniswaps.ini")); - iniswaps.prepend(char_list.at(m_cid).name); - if (iniswaps.size() <= 0) { - ui_iniswap_dropdown->hide(); - ui_iniswap_remove->hide(); - return; - } - ui_iniswap_dropdown->show(); - ui_iniswap_dropdown->addItems(iniswaps); + ui_iniswap_dropdown->blockSignals(true); + ui_iniswap_dropdown->clear(); + if (m_cid == -1) { + ui_iniswap_dropdown->hide(); + ui_iniswap_remove->hide(); + return; + } + QStringList iniswaps = ao_app->get_list_file( + ao_app->get_character_path(char_list.at(m_cid).name, "iniswaps.ini")); + iniswaps.prepend(char_list.at(m_cid).name); + if (iniswaps.size() <= 0) { + ui_iniswap_dropdown->hide(); + ui_iniswap_remove->hide(); + return; + } + ui_iniswap_dropdown->show(); + ui_iniswap_dropdown->addItems(iniswaps); - for (int i = 0; i < iniswaps.size(); ++i) { - if (iniswaps.at(i) == current_char) { - ui_iniswap_dropdown->setCurrentIndex(i); - if (i != 0) - ui_iniswap_remove->show(); - else - ui_iniswap_remove->hide(); - break; - } + for (int i = 0; i < iniswaps.size(); ++i) { + if (iniswaps.at(i) == current_char) { + ui_iniswap_dropdown->setCurrentIndex(i); + if (i != 0) + ui_iniswap_remove->show(); + else + ui_iniswap_remove->hide(); + break; } - ui_iniswap_dropdown->blockSignals(false); + } + ui_iniswap_dropdown->blockSignals(false); } void Courtroom::on_iniswap_dropdown_changed(int p_index) { - ui_ic_chat_message->setFocus(); - QString iniswap = ui_iniswap_dropdown->itemText(p_index); - ao_app->set_char_ini(char_list.at(m_cid).name, iniswap, "name", "Options"); + ui_ic_chat_message->setFocus(); + QString iniswap = ui_iniswap_dropdown->itemText(p_index); + ao_app->set_char_ini(char_list.at(m_cid).name, iniswap, "name", "Options"); - QStringList swaplist; - for (int i = 0; i < ui_iniswap_dropdown->count(); ++i) { - QString entry = ui_iniswap_dropdown->itemText(i); - if (!swaplist.contains(entry) && entry != char_list.at(m_cid).name) - swaplist.append(entry); - } - ao_app->write_to_file(swaplist.join("\n"), ao_app->get_character_path(char_list.at(m_cid).name, "iniswaps.ini")); - ui_iniswap_dropdown->blockSignals(true); - ui_iniswap_dropdown->setCurrentIndex(p_index); - ui_iniswap_dropdown->blockSignals(false); - update_character(m_cid); - if (p_index != 0) - ui_iniswap_remove->show(); - else - ui_iniswap_remove->hide(); + QStringList swaplist; + for (int i = 0; i < ui_iniswap_dropdown->count(); ++i) { + QString entry = ui_iniswap_dropdown->itemText(i); + if (!swaplist.contains(entry) && entry != char_list.at(m_cid).name) + swaplist.append(entry); + } + ao_app->write_to_file( + swaplist.join("\n"), + ao_app->get_character_path(char_list.at(m_cid).name, "iniswaps.ini")); + ui_iniswap_dropdown->blockSignals(true); + ui_iniswap_dropdown->setCurrentIndex(p_index); + ui_iniswap_dropdown->blockSignals(false); + update_character(m_cid); + if (p_index != 0) + ui_iniswap_remove->show(); + else + ui_iniswap_remove->hide(); } void Courtroom::on_iniswap_context_menu_requested(const QPoint &pos) { - QMenu *menu = ui_iniswap_dropdown->lineEdit()->createStandardContextMenu(); + QMenu *menu = ui_iniswap_dropdown->lineEdit()->createStandardContextMenu(); - menu->addSeparator(); - if (file_exists(ao_app->get_character_path(current_char, "char.ini"))) - menu->addAction(QString("Edit " + current_char + "/char.ini"), this, SLOT(on_iniswap_edit_requested())); - if (ui_iniswap_dropdown->itemText(ui_iniswap_dropdown->currentIndex()) != char_list.at(m_cid).name) - menu->addAction(QString("Remove " + current_char), this, SLOT(on_iniswap_remove_clicked())); - menu->popup(ui_iniswap_dropdown->mapToGlobal(pos)); + menu->addSeparator(); + if (file_exists(ao_app->get_character_path(current_char, "char.ini"))) + menu->addAction(QString("Edit " + current_char + "/char.ini"), this, + SLOT(on_iniswap_edit_requested())); + if (ui_iniswap_dropdown->itemText(ui_iniswap_dropdown->currentIndex()) != + char_list.at(m_cid).name) + menu->addAction(QString("Remove " + current_char), this, + SLOT(on_iniswap_remove_clicked())); + menu->popup(ui_iniswap_dropdown->mapToGlobal(pos)); } void Courtroom::on_iniswap_edit_requested() { - QString p_path = ao_app->get_character_path(current_char, "char.ini"); - if (!file_exists(p_path)) - return; - QDesktopServices::openUrl(QUrl::fromLocalFile(p_path)); + QString p_path = ao_app->get_character_path(current_char, "char.ini"); + if (!file_exists(p_path)) + return; + QDesktopServices::openUrl(QUrl::fromLocalFile(p_path)); } void Courtroom::on_iniswap_remove_clicked() { - if (ui_iniswap_dropdown->count() <= 0) { - ui_iniswap_remove->hide(); //We're not supposed to see it. Do this or the client will crash - return; - } - if (ui_iniswap_dropdown->itemText(ui_iniswap_dropdown->currentIndex()) != char_list.at(m_cid).name) { - ui_iniswap_dropdown->removeItem(ui_iniswap_dropdown->currentIndex()); - on_iniswap_dropdown_changed(0); //Reset back to original - update_character(m_cid); - } + if (ui_iniswap_dropdown->count() <= 0) { + ui_iniswap_remove->hide(); // We're not supposed to see it. Do this or the + // client will crash + return; + } + if (ui_iniswap_dropdown->itemText(ui_iniswap_dropdown->currentIndex()) != + char_list.at(m_cid).name) { + ui_iniswap_dropdown->removeItem(ui_iniswap_dropdown->currentIndex()); + on_iniswap_dropdown_changed(0); // Reset back to original + update_character(m_cid); + } } void Courtroom::set_sfx_dropdown() { - ui_sfx_dropdown->blockSignals(true); - ui_sfx_dropdown->clear(); - if (m_cid == -1) { - ui_sfx_dropdown->hide(); - ui_sfx_remove->hide(); - return; - } - QStringList soundlist = ao_app->get_list_file(ao_app->get_character_path(current_char, "soundlist.ini")); - - if (soundlist.size() <= 0) { - soundlist = ao_app->get_list_file(ao_app->get_theme_path("character_soundlist.ini")); - if (soundlist.size() <= 0) { - soundlist = ao_app->get_list_file(ao_app->get_default_theme_path("character_soundlist.ini")); - } - } - - if (soundlist.size() <= 0) { - ui_sfx_dropdown->hide(); - ui_sfx_remove->hide(); - return; - } - soundlist.prepend("Default"); - - ui_sfx_dropdown->show(); - ui_sfx_dropdown->addItems(soundlist); - ui_sfx_dropdown->setCurrentIndex(0); + ui_sfx_dropdown->blockSignals(true); + ui_sfx_dropdown->clear(); + if (m_cid == -1) { + ui_sfx_dropdown->hide(); ui_sfx_remove->hide(); - ui_sfx_dropdown->blockSignals(false); + return; + } + QStringList soundlist = ao_app->get_list_file( + ao_app->get_character_path(current_char, "soundlist.ini")); + + if (soundlist.size() <= 0) { + soundlist = ao_app->get_list_file( + ao_app->get_theme_path("character_soundlist.ini")); + if (soundlist.size() <= 0) { + soundlist = ao_app->get_list_file( + ao_app->get_default_theme_path("character_soundlist.ini")); + } + } + + if (soundlist.size() <= 0) { + ui_sfx_dropdown->hide(); + ui_sfx_remove->hide(); + return; + } + soundlist.prepend("Default"); + + ui_sfx_dropdown->show(); + ui_sfx_dropdown->addItems(soundlist); + ui_sfx_dropdown->setCurrentIndex(0); + ui_sfx_remove->hide(); + ui_sfx_dropdown->blockSignals(false); } void Courtroom::on_sfx_dropdown_changed(int p_index) { - ui_ic_chat_message->setFocus(); + ui_ic_chat_message->setFocus(); - QStringList soundlist; - for (int i = 0; i < ui_sfx_dropdown->count(); ++i) { - QString entry = ui_sfx_dropdown->itemText(i); - if (!soundlist.contains(entry) && entry != "Default") - soundlist.append(entry); - } + QStringList soundlist; + for (int i = 0; i < ui_sfx_dropdown->count(); ++i) { + QString entry = ui_sfx_dropdown->itemText(i); + if (!soundlist.contains(entry) && entry != "Default") + soundlist.append(entry); + } - QStringList defaultlist = ao_app->get_list_file(ao_app->get_theme_path("character_soundlist.ini")); - if (defaultlist.size() <= 0) { - defaultlist = ao_app->get_list_file(ao_app->get_default_theme_path("character_soundlist.ini")); - } + QStringList defaultlist = + ao_app->get_list_file(ao_app->get_theme_path("character_soundlist.ini")); + if (defaultlist.size() <= 0) { + defaultlist = ao_app->get_list_file( + ao_app->get_default_theme_path("character_soundlist.ini")); + } - if (defaultlist.size() > 0 && defaultlist.toSet().subtract(soundlist.toSet()).size() > 0) //There's a difference from the default configuration - ao_app->write_to_file(soundlist.join("\n"), ao_app->get_character_path(current_char, "soundlist.ini")); //Create a new sound list + if (defaultlist.size() > 0 && + defaultlist.toSet().subtract(soundlist.toSet()).size() > + 0) // There's a difference from the default configuration + ao_app->write_to_file( + soundlist.join("\n"), + ao_app->get_character_path(current_char, + "soundlist.ini")); // Create a new sound list - ui_sfx_dropdown->blockSignals(true); - ui_sfx_dropdown->setCurrentIndex(p_index); - ui_sfx_dropdown->blockSignals(false); - if (p_index != 0) - ui_sfx_remove->show(); - else - ui_sfx_remove->hide(); + ui_sfx_dropdown->blockSignals(true); + ui_sfx_dropdown->setCurrentIndex(p_index); + ui_sfx_dropdown->blockSignals(false); + if (p_index != 0) + ui_sfx_remove->show(); + else + ui_sfx_remove->hide(); } void Courtroom::on_sfx_context_menu_requested(const QPoint &pos) { - QMenu *menu = ui_sfx_dropdown->lineEdit()->createStandardContextMenu(); + QMenu *menu = ui_sfx_dropdown->lineEdit()->createStandardContextMenu(); - menu->addSeparator(); - if (file_exists(ao_app->get_character_path(current_char, "soundlist.ini"))) - menu->addAction(QString("Edit " + current_char + "/soundlist.ini"), this, SLOT(on_sfx_edit_requested())); - else - menu->addAction(QString("Edit theme's character_soundlist.ini"), this, SLOT(on_sfx_edit_requested())); - if (ui_sfx_dropdown->currentIndex() != 0) - menu->addAction(QString("Remove " + ui_sfx_dropdown->itemText(ui_sfx_dropdown->currentIndex())), this, SLOT(on_sfx_remove_clicked())); - menu->popup(ui_sfx_dropdown->mapToGlobal(pos)); + menu->addSeparator(); + if (file_exists(ao_app->get_character_path(current_char, "soundlist.ini"))) + menu->addAction(QString("Edit " + current_char + "/soundlist.ini"), this, + SLOT(on_sfx_edit_requested())); + else + menu->addAction(QString("Edit theme's character_soundlist.ini"), this, + SLOT(on_sfx_edit_requested())); + if (ui_sfx_dropdown->currentIndex() != 0) + menu->addAction(QString("Remove " + ui_sfx_dropdown->itemText( + ui_sfx_dropdown->currentIndex())), + this, SLOT(on_sfx_remove_clicked())); + menu->popup(ui_sfx_dropdown->mapToGlobal(pos)); } void Courtroom::on_sfx_edit_requested() { - QString p_path = ao_app->get_character_path(current_char, "soundlist.ini"); + QString p_path = ao_app->get_character_path(current_char, "soundlist.ini"); + if (!file_exists(p_path)) { + p_path = ao_app->get_theme_path("character_soundlist.ini"); if (!file_exists(p_path)) { - p_path = ao_app->get_theme_path("character_soundlist.ini"); - if (!file_exists(p_path)) { - p_path = ao_app->get_default_theme_path("character_soundlist.ini"); - if (!file_exists(p_path)) { - return; - } - } + p_path = ao_app->get_default_theme_path("character_soundlist.ini"); + if (!file_exists(p_path)) { + return; + } } - QDesktopServices::openUrl(QUrl::fromLocalFile(p_path)); + } + QDesktopServices::openUrl(QUrl::fromLocalFile(p_path)); } void Courtroom::on_sfx_remove_clicked() { - if (ui_sfx_dropdown->count() <= 0) { - ui_sfx_remove->hide(); //We're not supposed to see it. Do this or the client will crash - return; - } - if (ui_sfx_dropdown->itemText(ui_sfx_dropdown->currentIndex()) != "Default") { - ui_sfx_dropdown->removeItem(ui_sfx_dropdown->currentIndex()); - on_sfx_dropdown_changed(0); //Reset back to original - } + if (ui_sfx_dropdown->count() <= 0) { + ui_sfx_remove->hide(); // We're not supposed to see it. Do this or the + // client will crash + return; + } + if (ui_sfx_dropdown->itemText(ui_sfx_dropdown->currentIndex()) != "Default") { + ui_sfx_dropdown->removeItem(ui_sfx_dropdown->currentIndex()); + on_sfx_dropdown_changed(0); // Reset back to original + } } void Courtroom::set_effects_dropdown() { - ui_effects_dropdown->blockSignals(true); - ui_effects_dropdown->clear(); - if (m_cid == -1) { - ui_effects_dropdown->hide(); - return; + ui_effects_dropdown->blockSignals(true); + ui_effects_dropdown->clear(); + if (m_cid == -1) { + ui_effects_dropdown->hide(); + return; + } + QStringList effectslist = ao_app->get_effects(current_char); + + if (effectslist.size() <= 0) { + ui_effects_dropdown->hide(); + return; + } + + effectslist.prepend("None"); + + ui_effects_dropdown->show(); + ui_effects_dropdown->addItems(effectslist); + + // ICON-MAKING HELL + QString p_effect = ao_app->read_char_ini(current_char, "effects", "Options"); + 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/"); + 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); + if (!file_exists(iconpath)) { + iconpath = ao_app->get_static_image_suffix(theme_path + entry); + if (!file_exists(iconpath)) { + iconpath = ao_app->get_static_image_suffix(default_path + entry); + if (!file_exists(iconpath)) + continue; + } } - QStringList effectslist = ao_app->get_effects(current_char); + ui_effects_dropdown->setItemIcon(i, QIcon(iconpath)); + } - if (effectslist.size() <= 0) { - ui_effects_dropdown->hide(); - return; - } - - effectslist.prepend("None"); - - ui_effects_dropdown->show(); - ui_effects_dropdown->addItems(effectslist); - - //ICON-MAKING HELL - QString p_effect = ao_app->read_char_ini(current_char, "effects", "Options"); - 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/"); - 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); - if (!file_exists(iconpath)) { - iconpath = ao_app->get_static_image_suffix(theme_path + entry); - if (!file_exists(iconpath)) { - iconpath = ao_app->get_static_image_suffix(default_path + entry); - if (!file_exists(iconpath)) - continue; - } - } - ui_effects_dropdown->setItemIcon(i, QIcon(iconpath)); - } - - ui_effects_dropdown->setCurrentIndex(0); - ui_effects_dropdown->blockSignals(false); + ui_effects_dropdown->setCurrentIndex(0); + ui_effects_dropdown->blockSignals(false); } void Courtroom::on_effects_context_menu_requested(const QPoint &pos) { - QMenu *menu = new QMenu(); + QMenu *menu = new QMenu(); - if (!ao_app->read_char_ini(current_char, "effects", "Options").isEmpty()) - menu->addAction(QString("Open misc/" + ao_app->read_char_ini(current_char, "effects", "Options") + " folder"), this, SLOT(on_character_effects_edit_requested())); - menu->addAction(QString("Open theme's effects folder"), this, SLOT(on_effects_edit_requested())); - menu->popup(ui_effects_dropdown->mapToGlobal(pos)); + if (!ao_app->read_char_ini(current_char, "effects", "Options").isEmpty()) + menu->addAction( + QString("Open misc/" + + ao_app->read_char_ini(current_char, "effects", "Options") + + " folder"), + this, SLOT(on_character_effects_edit_requested())); + menu->addAction(QString("Open theme's effects folder"), this, + SLOT(on_effects_edit_requested())); + menu->popup(ui_effects_dropdown->mapToGlobal(pos)); } void Courtroom::on_effects_edit_requested() { - QString p_path = ao_app->get_theme_path("effects/"); + QString p_path = ao_app->get_theme_path("effects/"); + if (!dir_exists(p_path)) { + p_path = ao_app->get_default_theme_path("effects/"); if (!dir_exists(p_path)) { - p_path = ao_app->get_default_theme_path("effects/"); - if (!dir_exists(p_path)) { - return; - } + return; } - QDesktopServices::openUrl(QUrl::fromLocalFile(p_path)); + } + QDesktopServices::openUrl(QUrl::fromLocalFile(p_path)); } void Courtroom::on_character_effects_edit_requested() { - QString p_effect = ao_app->read_char_ini(current_char, "effects", "Options"); - QString p_path = ao_app->get_base_path() + "misc/" + p_effect + "/"; - if (!dir_exists(p_path)) - return; + QString p_effect = ao_app->read_char_ini(current_char, "effects", "Options"); + QString p_path = ao_app->get_base_path() + "misc/" + p_effect + "/"; + if (!dir_exists(p_path)) + return; - QDesktopServices::openUrl(QUrl::fromLocalFile(p_path)); + QDesktopServices::openUrl(QUrl::fromLocalFile(p_path)); } void Courtroom::on_effects_dropdown_changed(int p_index) { - effect = ui_effects_dropdown->itemText(p_index); - ui_ic_chat_message->setFocus(); + effect = ui_effects_dropdown->itemText(p_index); + ui_ic_chat_message->setFocus(); } bool Courtroom::effects_dropdown_find_and_set(QString effect) { - for (int i = 0; i < ui_effects_dropdown->count(); ++i) { - QString entry = ui_effects_dropdown->itemText(i); - if (entry == effect) { - ui_effects_dropdown->setCurrentIndex(i); - return true; - } + for (int i = 0; i < ui_effects_dropdown->count(); ++i) { + QString entry = ui_effects_dropdown->itemText(i); + if (entry == effect) { + ui_effects_dropdown->setCurrentIndex(i); + return true; } - return false; + } + return false; } QString Courtroom::get_char_sfx() { - QString sfx = ui_sfx_dropdown->itemText(ui_sfx_dropdown->currentIndex()); - if (sfx != "" && sfx != "Default") - return sfx; - return ao_app->get_sfx_name(current_char, current_emote); + QString sfx = ui_sfx_dropdown->itemText(ui_sfx_dropdown->currentIndex()); + if (sfx != "" && sfx != "Default") + return sfx; + return ao_app->get_sfx_name(current_char, current_emote); } int Courtroom::get_char_sfx_delay() { - // QString sfx = ui_sfx_dropdown->itemText(ui_sfx_dropdown->currentIndex()); - // if (sfx != "" && sfx != "Default") - // return 0; //todo: a way to define this - return ao_app->get_sfx_delay(current_char, current_emote); + // QString sfx = ui_sfx_dropdown->itemText(ui_sfx_dropdown->currentIndex()); + // if (sfx != "" && sfx != "Default") + // return 0; //todo: a way to define this + return ao_app->get_sfx_delay(current_char, current_emote); } void Courtroom::on_mute_list_clicked(QModelIndex p_index) { - QListWidgetItem *f_item = ui_mute_list->item(p_index.row()); - QString f_char = f_item->text(); - QString real_char; + QListWidgetItem *f_item = ui_mute_list->item(p_index.row()); + QString f_char = f_item->text(); + QString real_char; - if (f_char.endsWith(" [x]")) - real_char = f_char.left(f_char.size() - 4); - else - real_char = f_char; + if (f_char.endsWith(" [x]")) + real_char = f_char.left(f_char.size() - 4); + else + real_char = f_char; - int f_cid = -1; + int f_cid = -1; - 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; - } + 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 < 0 || f_cid >= char_list.size()) { - qDebug() << "W: " << real_char << " not present in char_list"; - return; - } + if (f_cid < 0 || f_cid >= char_list.size()) { + qDebug() << "W: " << real_char << " not present in char_list"; + return; + } - if (mute_map.value(f_cid)) { - mute_map.insert(f_cid, false); - f_item->setText(real_char); - } - else { - mute_map.insert(f_cid, true); - f_item->setText(real_char + " [x]"); - } + if (mute_map.value(f_cid)) { + mute_map.insert(f_cid, false); + f_item->setText(real_char); + } + else { + mute_map.insert(f_cid, true); + f_item->setText(real_char + " [x]"); + } } 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; + 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_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()) { - qDebug() << "W: " << real_char << " not present in char_list"; - return; - } + if (f_cid < -2 || f_cid >= char_list.size()) { + qDebug() << "W: " << real_char << " not present in char_list"; + return; + } - other_charid = f_cid; + other_charid = f_cid; - // Redo the character list. - QStringList sorted_pair_list; + // Redo the character list. + QStringList sorted_pair_list; - for (char_type i_char : char_list) - sorted_pair_list.append(i_char.name); + for (char_type i_char : char_list) + sorted_pair_list.append(i_char.name); - sorted_pair_list.sort(); + 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]"); - } + 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) +void Courtroom::on_music_list_double_clicked(QTreeWidgetItem *p_item, + int column) { - if (is_muted) - return; + if (is_muted) + return; - column = 1; //Column 1 is always the metadata (which we want) - QString p_song = p_item->text(column); + column = 1; // Column 1 is always the metadata (which we want) + QString p_song = p_item->text(column); - 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_support_enabled) || ao_app->effects_enabled) - packet_contents.append(ui_ic_chat_name->text()); - if (ao_app->effects_enabled) - packet_contents.append(QString::number(music_flags)); - ao_app->send_server_packet(new AOPacket("MC", packet_contents), false); + 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_support_enabled) || + ao_app->effects_enabled) + packet_contents.append(ui_ic_chat_name->text()); + if (ao_app->effects_enabled) + 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) { - QMenu *menu = new QMenu(); + QMenu *menu = new QMenu(); - menu->addAction(QString("Expand All Categories"), this, SLOT(music_list_expand_all())); - menu->addAction(QString("Collapse All Categories"), this, SLOT(music_list_collapse_all())); - menu->addSeparator(); + menu->addAction(QString("Expand All Categories"), this, + SLOT(music_list_expand_all())); + menu->addAction(QString("Collapse All Categories"), this, + SLOT(music_list_collapse_all())); + menu->addSeparator(); - menu->addAction(new QAction("Fade Out Previous", this)); - menu->actions().back()->setCheckable(true); - menu->actions().back()->setChecked(music_flags & FADE_OUT); - connect(menu->actions().back(), SIGNAL(toggled(bool)), this, SLOT(music_fade_out(bool))); + menu->addAction(new QAction("Fade Out Previous", this)); + menu->actions().back()->setCheckable(true); + menu->actions().back()->setChecked(music_flags & FADE_OUT); + connect(menu->actions().back(), SIGNAL(toggled(bool)), this, + SLOT(music_fade_out(bool))); - menu->addAction(new QAction("Fade In", this)); - menu->actions().back()->setCheckable(true); - menu->actions().back()->setChecked(music_flags & FADE_IN); - connect(menu->actions().back(), SIGNAL(toggled(bool)), this, SLOT(music_fade_in(bool))); + menu->addAction(new QAction("Fade In", this)); + menu->actions().back()->setCheckable(true); + menu->actions().back()->setChecked(music_flags & FADE_IN); + connect(menu->actions().back(), SIGNAL(toggled(bool)), this, + SLOT(music_fade_in(bool))); - menu->addAction(new QAction("Synchronize", this)); - menu->actions().back()->setCheckable(true); - menu->actions().back()->setChecked(music_flags & SYNC_POS); - connect(menu->actions().back(), SIGNAL(toggled(bool)), this, SLOT(music_synchronize(bool))); + menu->addAction(new QAction("Synchronize", this)); + menu->actions().back()->setCheckable(true); + menu->actions().back()->setChecked(music_flags & SYNC_POS); + connect(menu->actions().back(), SIGNAL(toggled(bool)), this, + SLOT(music_synchronize(bool))); - menu->popup(ui_music_list->mapToGlobal(pos)); + menu->popup(ui_music_list->mapToGlobal(pos)); } void Courtroom::music_fade_out(bool toggle) { - if (toggle) - music_flags |= FADE_OUT; - else - music_flags &= ~FADE_OUT; + if (toggle) + music_flags |= FADE_OUT; + else + music_flags &= ~FADE_OUT; } void Courtroom::music_fade_in(bool toggle) { - if (toggle) - music_flags |= FADE_IN; - else - music_flags &= ~FADE_IN; + if (toggle) + music_flags |= FADE_IN; + else + music_flags &= ~FADE_IN; } void Courtroom::music_synchronize(bool toggle) { - if (toggle) - music_flags |= SYNC_POS; - else - music_flags &= ~SYNC_POS; + if (toggle) + music_flags |= SYNC_POS; + else + music_flags &= ~SYNC_POS; } -void Courtroom::music_list_expand_all() -{ - ui_music_list->expandAll(); -} +void Courtroom::music_list_expand_all() { ui_music_list->expandAll(); } void Courtroom::music_list_collapse_all() { - ui_music_list->collapseAll(); - QTreeWidgetItem *current = ui_music_list->selectedItems()[0]; - if (current->parent() != nullptr) - current = current->parent(); - ui_music_list->setCurrentItem(current); + ui_music_list->collapseAll(); + QTreeWidgetItem *current = ui_music_list->selectedItems()[0]; + if (current->parent() != nullptr) + current = current->parent(); + ui_music_list->setCurrentItem(current); } void Courtroom::on_area_list_double_clicked(QTreeWidgetItem *p_item, int column) { - column = 0; //The metadata - QString p_area = p_item->text(0); + column = 0; // The metadata + QString p_area = p_item->text(0); - QStringList packet_contents; - packet_contents.append(p_area); - packet_contents.append(QString::number(m_cid)); - qDebug() << packet_contents; - ao_app->send_server_packet(new AOPacket("MC", packet_contents), false); + QStringList packet_contents; + packet_contents.append(p_area); + packet_contents.append(QString::number(m_cid)); + qDebug() << packet_contents; + ao_app->send_server_packet(new AOPacket("MC", packet_contents), false); } void Courtroom::on_hold_it_clicked() { - if (objection_state == 1) { - ui_hold_it->set_image("holdit"); - objection_state = 0; - } - else { - ui_objection->set_image("objection"); - ui_take_that->set_image("takethat"); - ui_custom_objection->set_image("custom"); + if (objection_state == 1) { + ui_hold_it->set_image("holdit"); + objection_state = 0; + } + else { + ui_objection->set_image("objection"); + ui_take_that->set_image("takethat"); + ui_custom_objection->set_image("custom"); - ui_hold_it->set_image("holdit_selected"); - objection_state = 1; - } + ui_hold_it->set_image("holdit_selected"); + objection_state = 1; + } - ui_ic_chat_message->setFocus(); + ui_ic_chat_message->setFocus(); } void Courtroom::on_objection_clicked() { - if (objection_state == 2) { - ui_objection->set_image("objection"); - objection_state = 0; - } - else { - ui_hold_it->set_image("holdit"); - ui_take_that->set_image("takethat"); - ui_custom_objection->set_image("custom"); + if (objection_state == 2) { + ui_objection->set_image("objection"); + objection_state = 0; + } + else { + ui_hold_it->set_image("holdit"); + ui_take_that->set_image("takethat"); + ui_custom_objection->set_image("custom"); - ui_objection->set_image("objection_selected"); - objection_state = 2; - } + ui_objection->set_image("objection_selected"); + objection_state = 2; + } - ui_ic_chat_message->setFocus(); + ui_ic_chat_message->setFocus(); } void Courtroom::on_take_that_clicked() { - if (objection_state == 3) { - ui_take_that->set_image("takethat"); - objection_state = 0; - } - else { - ui_objection->set_image("objection"); - ui_hold_it->set_image("holdit"); - ui_custom_objection->set_image("custom"); + if (objection_state == 3) { + ui_take_that->set_image("takethat"); + objection_state = 0; + } + else { + ui_objection->set_image("objection"); + ui_hold_it->set_image("holdit"); + ui_custom_objection->set_image("custom"); - ui_take_that->set_image("takethat_selected"); - objection_state = 3; - } + ui_take_that->set_image("takethat_selected"); + objection_state = 3; + } - ui_ic_chat_message->setFocus(); + ui_ic_chat_message->setFocus(); } void Courtroom::on_custom_objection_clicked() { - if (objection_state == 4) { - ui_custom_objection->set_image("custom"); - objection_state = 0; - } - else { - ui_objection->set_image("objection"); - ui_take_that->set_image("takethat"); - ui_hold_it->set_image("holdit"); + if (objection_state == 4) { + ui_custom_objection->set_image("custom"); + objection_state = 0; + } + else { + ui_objection->set_image("objection"); + ui_take_that->set_image("takethat"); + ui_hold_it->set_image("holdit"); - ui_custom_objection->set_image("custom_selected"); - objection_state = 4; - } + ui_custom_objection->set_image("custom_selected"); + objection_state = 4; + } - ui_ic_chat_message->setFocus(); + ui_ic_chat_message->setFocus(); } void Courtroom::on_realization_clicked() { - if (realization_state == 0) { - realization_state = 1; - if (effects_dropdown_find_and_set("realization")) - on_effects_dropdown_changed(ui_effects_dropdown->currentIndex()); + if (realization_state == 0) { + realization_state = 1; + if (effects_dropdown_find_and_set("realization")) + on_effects_dropdown_changed(ui_effects_dropdown->currentIndex()); - ui_realization->set_image("realization_pressed"); - } - else { - realization_state = 0; - ui_effects_dropdown->setCurrentIndex(0); - on_effects_dropdown_changed(ui_effects_dropdown->currentIndex()); - ui_realization->set_image("realization"); - } + ui_realization->set_image("realization_pressed"); + } + else { + realization_state = 0; + ui_effects_dropdown->setCurrentIndex(0); + on_effects_dropdown_changed(ui_effects_dropdown->currentIndex()); + ui_realization->set_image("realization"); + } - ui_ic_chat_message->setFocus(); + ui_ic_chat_message->setFocus(); } void Courtroom::on_screenshake_clicked() { - if (screenshake_state == 0) { - screenshake_state = 1; - ui_screenshake->set_image("screenshake_pressed"); - } - else { - screenshake_state = 0; - ui_screenshake->set_image("screenshake"); - } + if (screenshake_state == 0) { + screenshake_state = 1; + ui_screenshake->set_image("screenshake_pressed"); + } + else { + screenshake_state = 0; + ui_screenshake->set_image("screenshake"); + } - ui_ic_chat_message->setFocus(); + ui_ic_chat_message->setFocus(); } 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_order_dropdown->hide(); - ui_pair_button->set_image("pair_button"); - ui_mute->set_image("mute_pressed"); - } - else { - ui_mute_list->hide(); - ui_mute->set_image("mute"); - } + if (ui_mute_list->isHidden()) { + ui_mute_list->show(); + ui_pair_list->hide(); + ui_pair_offset_spinbox->hide(); + ui_pair_order_dropdown->hide(); + ui_pair_button->set_image("pair_button"); + ui_mute->set_image("mute_pressed"); + } + else { + ui_mute_list->hide(); + ui_mute->set_image("mute"); + } } void Courtroom::on_pair_clicked() { - if (ui_pair_list->isHidden()) { - ui_pair_list->show(); - ui_pair_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_order_dropdown->hide(); - ui_pair_button->set_image("pair_button"); - } + if (ui_pair_list->isHidden()) { + ui_pair_list->show(); + ui_pair_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_order_dropdown->hide(); + ui_pair_button->set_image("pair_button"); + } } void Courtroom::on_pair_order_dropdown_changed(int p_index) { - pair_order = p_index; + pair_order = p_index; } void Courtroom::on_defense_minus_clicked() { - int f_state = defense_bar_state - 1; + int f_state = defense_bar_state - 1; - if (f_state >= 0) - ao_app->send_server_packet(new AOPacket("HP#1#" + QString::number(f_state) + "#%")); + if (f_state >= 0) + ao_app->send_server_packet( + new AOPacket("HP#1#" + QString::number(f_state) + "#%")); } void Courtroom::on_defense_plus_clicked() { - int f_state = defense_bar_state + 1; + int f_state = defense_bar_state + 1; - if (f_state <= 10) - ao_app->send_server_packet(new AOPacket("HP#1#" + QString::number(f_state) + "#%")); + if (f_state <= 10) + ao_app->send_server_packet( + new AOPacket("HP#1#" + QString::number(f_state) + "#%")); } void Courtroom::on_prosecution_minus_clicked() { - int f_state = prosecution_bar_state - 1; + int f_state = prosecution_bar_state - 1; - if (f_state >= 0) - ao_app->send_server_packet(new AOPacket("HP#2#" + QString::number(f_state) + "#%")); + if (f_state >= 0) + ao_app->send_server_packet( + new AOPacket("HP#2#" + QString::number(f_state) + "#%")); } void Courtroom::on_prosecution_plus_clicked() { - int f_state = prosecution_bar_state + 1; + int f_state = prosecution_bar_state + 1; - if (f_state <= 10) - ao_app->send_server_packet(new AOPacket("HP#2#" + QString::number(f_state) + "#%")); + if (f_state <= 10) + ao_app->send_server_packet( + new AOPacket("HP#2#" + QString::number(f_state) + "#%")); } void Courtroom::set_text_color_dropdown() { - //Clear the lists - ui_text_color->clear(); - color_row_to_number.clear(); + // Clear the lists + ui_text_color->clear(); + color_row_to_number.clear(); - //Clear the stored optimization information - color_rgb_list.clear(); - color_markdown_start_list.clear(); - color_markdown_end_list.clear(); - color_markdown_remove_list.clear(); - color_markdown_talking_list.clear(); + // Clear the stored optimization information + color_rgb_list.clear(); + color_markdown_start_list.clear(); + color_markdown_end_list.clear(); + color_markdown_remove_list.clear(); + color_markdown_talking_list.clear(); - //Update markdown colors. TODO: make a loading function that only loads the config file once instead of several times - for (int c = 0; c < max_colors; ++c) { - QColor color = ao_app->get_chat_color(QString::number(c), current_char); - color_rgb_list.append(color); - color_markdown_start_list.append(ao_app->get_chat_markdown("c" + QString::number(c) + "_start", current_char)); - color_markdown_end_list.append(ao_app->get_chat_markdown("c" + QString::number(c) + "_end", current_char)); - color_markdown_remove_list.append(ao_app->get_chat_markdown("c" + QString::number(c) + "_remove", current_char) == "1"); - color_markdown_talking_list.append(ao_app->get_chat_markdown("c" + QString::number(c) + "_talking", current_char) == "1"); + // Update markdown colors. TODO: make a loading function that only loads the + // config file once instead of several times + for (int c = 0; c < max_colors; ++c) { + QColor color = ao_app->get_chat_color(QString::number(c), current_char); + color_rgb_list.append(color); + color_markdown_start_list.append(ao_app->get_chat_markdown( + "c" + QString::number(c) + "_start", current_char)); + color_markdown_end_list.append(ao_app->get_chat_markdown( + "c" + QString::number(c) + "_end", current_char)); + color_markdown_remove_list.append( + ao_app->get_chat_markdown("c" + QString::number(c) + "_remove", + current_char) == "1"); + color_markdown_talking_list.append( + ao_app->get_chat_markdown("c" + QString::number(c) + "_talking", + current_char) == "1"); - QString color_name = ao_app->get_chat_markdown("c" + QString::number(c) + "_name", current_char); - if (color_name.isEmpty()) //Not defined - { - if (c > 0) - continue; - color_name = tr("Default"); - } - ui_text_color->addItem(color_name); - QPixmap pixmap(16, 16); - pixmap.fill(color); - ui_text_color->setItemIcon(ui_text_color->count() - 1, QIcon(pixmap)); - color_row_to_number.append(c); + QString color_name = ao_app->get_chat_markdown( + "c" + QString::number(c) + "_name", current_char); + if (color_name.isEmpty()) // Not defined + { + if (c > 0) + continue; + color_name = tr("Default"); } + ui_text_color->addItem(color_name); + QPixmap pixmap(16, 16); + pixmap.fill(color); + ui_text_color->setItemIcon(ui_text_color->count() - 1, QIcon(pixmap)); + color_row_to_number.append(c); + } } void Courtroom::on_text_color_changed(int p_color) { - if (ui_ic_chat_message->selectionStart() != -1) //We have a selection! - { - int c = color_row_to_number.at(p_color); - QString markdown_start = color_markdown_start_list.at(c); - if (markdown_start.isEmpty()) { - qDebug() << "W: Color list dropdown selected a non-existent markdown start character"; - return; - } - QString markdown_end = color_markdown_end_list.at(c); - if (markdown_end.isEmpty()) - markdown_end = markdown_start; - int start = ui_ic_chat_message->selectionStart(); - int end = ui_ic_chat_message->selectionEnd() + 1; - ui_ic_chat_message->setCursorPosition(start); - ui_ic_chat_message->insert(markdown_start); - ui_ic_chat_message->setCursorPosition(end); - ui_ic_chat_message->insert(markdown_end); - // ui_ic_chat_message->end(false); - ui_text_color->setCurrentIndex(0); + if (ui_ic_chat_message->selectionStart() != -1) // We have a selection! + { + int c = color_row_to_number.at(p_color); + QString markdown_start = color_markdown_start_list.at(c); + if (markdown_start.isEmpty()) { + qDebug() << "W: Color list dropdown selected a non-existent markdown " + "start character"; + return; } - else { - if (p_color != -1 && p_color < color_row_to_number.size()) - text_color = color_row_to_number.at(p_color); - else - text_color = 0; - } - ui_ic_chat_message->setFocus(); + QString markdown_end = color_markdown_end_list.at(c); + if (markdown_end.isEmpty()) + markdown_end = markdown_start; + int start = ui_ic_chat_message->selectionStart(); + int end = ui_ic_chat_message->selectionEnd() + 1; + ui_ic_chat_message->setCursorPosition(start); + ui_ic_chat_message->insert(markdown_start); + ui_ic_chat_message->setCursorPosition(end); + ui_ic_chat_message->insert(markdown_end); + // ui_ic_chat_message->end(false); + ui_text_color->setCurrentIndex(0); + } + else { + if (p_color != -1 && p_color < color_row_to_number.size()) + text_color = color_row_to_number.at(p_color); + else + text_color = 0; + } + ui_ic_chat_message->setFocus(); } void Courtroom::on_music_slider_moved(int p_value) { - music_player->set_volume(p_value, 0); //Set volume on music layer - ui_ic_chat_message->setFocus(); + music_player->set_volume(p_value, 0); // Set volume on music layer + ui_ic_chat_message->setFocus(); } void Courtroom::on_sfx_slider_moved(int p_value) { - sfx_player->set_volume(p_value); - //Set the ambience and other misc. music layers - for (int i = 1; i < music_player->m_channelmax; ++i) { - music_player->set_volume(p_value, i); - } - objection_player->set_volume(p_value); - ui_ic_chat_message->setFocus(); + sfx_player->set_volume(p_value); + // Set the ambience and other misc. music layers + for (int i = 1; i < music_player->m_channelmax; ++i) { + music_player->set_volume(p_value, i); + } + objection_player->set_volume(p_value); + ui_ic_chat_message->setFocus(); } void Courtroom::on_blip_slider_moved(int p_value) { - blip_player->set_volume(p_value); - ui_ic_chat_message->setFocus(); + blip_player->set_volume(p_value); + ui_ic_chat_message->setFocus(); } -void Courtroom::on_log_limit_changed(int value) -{ - log_maximum_blocks = value; -} +void Courtroom::on_log_limit_changed(int value) { log_maximum_blocks = value; } -void Courtroom::on_pair_offset_changed(int value) -{ - char_offset = value; -} +void Courtroom::on_pair_offset_changed(int value) { char_offset = value; } void Courtroom::on_witness_testimony_clicked() { - if (is_muted) - return; + if (is_muted) + return; - ao_app->send_server_packet(new AOPacket("RT#testimony1#%")); + ao_app->send_server_packet(new AOPacket("RT#testimony1#%")); - ui_ic_chat_message->setFocus(); + ui_ic_chat_message->setFocus(); } void Courtroom::on_cross_examination_clicked() { - if (is_muted) - return; + if (is_muted) + return; - ao_app->send_server_packet(new AOPacket("RT#testimony2#%")); + ao_app->send_server_packet(new AOPacket("RT#testimony2#%")); - ui_ic_chat_message->setFocus(); + ui_ic_chat_message->setFocus(); } void Courtroom::on_not_guilty_clicked() { - if (is_muted) - return; + if (is_muted) + return; - ao_app->send_server_packet(new AOPacket("RT#judgeruling#0#%")); + ao_app->send_server_packet(new AOPacket("RT#judgeruling#0#%")); - ui_ic_chat_message->setFocus(); + ui_ic_chat_message->setFocus(); } void Courtroom::on_guilty_clicked() { - if (is_muted) - return; + if (is_muted) + return; - ao_app->send_server_packet(new AOPacket("RT#judgeruling#1#%")); + ao_app->send_server_packet(new AOPacket("RT#judgeruling#1#%")); - ui_ic_chat_message->setFocus(); + ui_ic_chat_message->setFocus(); } void Courtroom::on_change_character_clicked() { - sfx_player->set_volume(0); - blip_player->set_volume(0); + sfx_player->set_volume(0); + blip_player->set_volume(0); - set_char_select(); + set_char_select(); - ui_char_select_background->show(); - ui_spectator->hide(); + ui_char_select_background->show(); + ui_spectator->hide(); } void Courtroom::on_reload_theme_clicked() { - ao_app->reload_theme(); + ao_app->reload_theme(); - enter_courtroom(); - update_character(m_cid); + enter_courtroom(); + update_character(m_cid); - anim_state = 4; - text_state = 3; + anim_state = 4; + text_state = 3; - //to update status on the background - set_background(current_background); + // to update status on the background + set_background(current_background); } void Courtroom::on_back_to_lobby_clicked() { - ao_app->construct_lobby(); - ao_app->destruct_courtroom(); + ao_app->construct_lobby(); + ao_app->destruct_courtroom(); } void Courtroom::on_char_select_left_clicked() { - --current_char_page; - set_char_select_page(); + --current_char_page; + set_char_select_page(); } void Courtroom::on_char_select_right_clicked() { - ++current_char_page; - set_char_select_page(); + ++current_char_page; + set_char_select_page(); } -void Courtroom::on_spectator_clicked() -{ - update_character(-1); -} +void Courtroom::on_spectator_clicked() { update_character(-1); } void Courtroom::on_call_mod_clicked() { - if (ao_app->modcall_reason_enabled) { - QMessageBox errorBox; - QInputDialog input; + if (ao_app->modcall_reason_enabled) { + QMessageBox errorBox; + QInputDialog input; - input.setWindowFlags(Qt::WindowSystemMenuHint); - input.setLabelText(tr("Reason:")); - input.setWindowTitle(tr("Call Moderator")); - auto code = input.exec(); + input.setWindowFlags(Qt::WindowSystemMenuHint); + input.setLabelText(tr("Reason:")); + input.setWindowTitle(tr("Call Moderator")); + auto code = input.exec(); - if (code != QDialog::Accepted) - return; + if (code != QDialog::Accepted) + return; - 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); - - 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#%")); + else if (text.length() > 256) { + errorBox.critical(nullptr, tr("Error"), tr("The message is too long.")); + return; } - ui_ic_chat_message->setFocus(); + QStringList mod_reason; + mod_reason.append(text); + + ao_app->send_server_packet(new AOPacket("ZZ", mod_reason)); + } + else { + ao_app->send_server_packet(new AOPacket("ZZ#%")); + } + + ui_ic_chat_message->setFocus(); } -void Courtroom::on_settings_clicked() -{ - ao_app->call_settings_menu(); -} +void Courtroom::on_settings_clicked() { ao_app->call_settings_menu(); } void Courtroom::on_announce_casing_clicked() { - ao_app->call_announce_menu(this); + ao_app->call_announce_menu(this); } -void Courtroom::on_pre_clicked() -{ - ui_ic_chat_message->setFocus(); -} +void Courtroom::on_pre_clicked() { ui_ic_chat_message->setFocus(); } -void Courtroom::on_flip_clicked() -{ - ui_ic_chat_message->setFocus(); -} +void Courtroom::on_flip_clicked() { ui_ic_chat_message->setFocus(); } void Courtroom::on_additive_clicked() { - if (ui_additive->isChecked()) { - ui_ic_chat_message->home(false); //move cursor to the start of the message - ui_ic_chat_message->insert(" "); //preface the message by whitespace - ui_ic_chat_message->end(false); //move cursor to the end of the message without selecting anything - } - ui_ic_chat_message->setFocus(); + if (ui_additive->isChecked()) { + ui_ic_chat_message->home(false); // move cursor to the start of the message + ui_ic_chat_message->insert(" "); // preface the message by whitespace + ui_ic_chat_message->end(false); // move cursor to the end of the message + // without selecting anything + } + ui_ic_chat_message->setFocus(); } -void Courtroom::on_guard_clicked() -{ - ui_ic_chat_message->setFocus(); -} +void Courtroom::on_guard_clicked() { ui_ic_chat_message->setFocus(); } void Courtroom::on_showname_enable_clicked() { - ui_ic_chatlog->clear(); - first_message_sent = false; + ui_ic_chatlog->clear(); + first_message_sent = false; - foreach (chatlogpiece item, ic_chatlog_history) { - if (ui_showname_enable->isChecked()) { - if (item.is_song()) - append_ic_text(item.get_message(), item.get_showname(), "has played a song"); - else - append_ic_text(item.get_message(), item.get_showname()); - } - else { - if (item.is_song()) - append_ic_text(item.get_message(), item.get_name(), "has played a song"); - else - append_ic_text(item.get_message(), item.get_name()); - } + foreach (chatlogpiece item, ic_chatlog_history) { + if (ui_showname_enable->isChecked()) { + if (item.is_song()) + append_ic_text(item.get_message(), item.get_showname(), + "has played a song"); + else + append_ic_text(item.get_message(), item.get_showname()); } + else { + if (item.is_song()) + append_ic_text(item.get_message(), item.get_name(), + "has played a song"); + else + append_ic_text(item.get_message(), item.get_name()); + } + } - ui_ic_chat_message->setFocus(); + ui_ic_chat_message->setFocus(); } void Courtroom::on_evidence_button_clicked() { - if (ui_evidence->isHidden()) { - ui_evidence->show(); - ui_evidence_overlay->hide(); - } - else { - ui_evidence->hide(); - } + if (ui_evidence->isHidden()) { + ui_evidence->show(); + ui_evidence_overlay->hide(); + } + else { + ui_evidence->hide(); + } } void Courtroom::on_switch_area_music_clicked() { - ui_music_search->setText(""); - on_music_search_edited(ui_music_search->text()); - if (ui_area_list->isHidden()) { - ui_area_list->show(); - ui_music_list->hide(); - } - else { - ui_area_list->hide(); - ui_music_list->show(); - } + ui_music_search->setText(""); + on_music_search_edited(ui_music_search->text()); + if (ui_area_list->isHidden()) { + ui_area_list->show(); + ui_music_list->hide(); + } + else { + ui_area_list->hide(); + ui_music_list->show(); + } } void Courtroom::ping_server() { - ao_app->send_server_packet(new AOPacket("CH#" + QString::number(m_cid) + "#%")); + ao_app->send_server_packet( + new AOPacket("CH#" + QString::number(m_cid) + "#%")); } void Courtroom::on_casing_clicked() { - if (ao_app->casing_alerts_enabled) { - if (ui_casing->isChecked()) { - QStringList f_packet; + if (ao_app->casing_alerts_enabled) { + if (ui_casing->isChecked()) { + QStringList f_packet; - f_packet.append(ao_app->get_casing_can_host_cases()); - f_packet.append(QString::number(ao_app->get_casing_cm_enabled())); - f_packet.append(QString::number(ao_app->get_casing_defence_enabled())); - f_packet.append(QString::number(ao_app->get_casing_prosecution_enabled())); - f_packet.append(QString::number(ao_app->get_casing_judge_enabled())); - f_packet.append(QString::number(ao_app->get_casing_juror_enabled())); - f_packet.append(QString::number(ao_app->get_casing_steno_enabled())); + f_packet.append(ao_app->get_casing_can_host_cases()); + f_packet.append(QString::number(ao_app->get_casing_cm_enabled())); + f_packet.append(QString::number(ao_app->get_casing_defence_enabled())); + f_packet.append( + QString::number(ao_app->get_casing_prosecution_enabled())); + f_packet.append(QString::number(ao_app->get_casing_judge_enabled())); + f_packet.append(QString::number(ao_app->get_casing_juror_enabled())); + f_packet.append(QString::number(ao_app->get_casing_steno_enabled())); - ao_app->send_server_packet(new AOPacket("SETCASE", f_packet)); - } - else - ao_app->send_server_packet(new AOPacket("SETCASE#\"\"#0#0#0#0#0#0#%")); + ao_app->send_server_packet(new AOPacket("SETCASE", f_packet)); } + else + ao_app->send_server_packet(new AOPacket("SETCASE#\"\"#0#0#0#0#0#0#%")); + } } -void Courtroom::announce_case(QString title, bool def, bool pro, bool jud, bool jur, bool steno) +void Courtroom::announce_case(QString title, bool def, bool pro, bool jud, + bool jur, bool steno) { - if (ao_app->casing_alerts_enabled) { - QStringList f_packet; + if (ao_app->casing_alerts_enabled) { + QStringList f_packet; - f_packet.append(title); - f_packet.append(QString::number(def)); - f_packet.append(QString::number(pro)); - f_packet.append(QString::number(jud)); - f_packet.append(QString::number(jur)); - f_packet.append(QString::number(steno)); + f_packet.append(title); + f_packet.append(QString::number(def)); + f_packet.append(QString::number(pro)); + f_packet.append(QString::number(jud)); + f_packet.append(QString::number(jur)); + f_packet.append(QString::number(steno)); - ao_app->send_server_packet(new AOPacket("CASEA", f_packet)); - } + ao_app->send_server_packet(new AOPacket("CASEA", f_packet)); + } } Courtroom::~Courtroom() { - delete music_player; - delete sfx_player; - delete objection_player; - delete blip_player; + delete music_player; + delete sfx_player; + delete objection_player; + delete blip_player; } #if (defined(_WIN32) || defined(_WIN64)) void Courtroom::load_bass_opus_plugin() { #ifdef BASSAUDIO - BASS_PluginLoad("bassopus.dll", 0); + BASS_PluginLoad("bassopus.dll", 0); #endif } #elif (defined(LINUX) || defined(__linux__)) void Courtroom::load_bass_opus_plugin() { #ifdef BASSAUDIO - BASS_PluginLoad("libbassopus.so", 0); + BASS_PluginLoad("libbassopus.so", 0); #endif } #elif defined __APPLE__ void Courtroom::load_bass_opus_plugin() { - QString libpath = ao_app->get_base_path() + "../../Frameworks/libbassopus.dylib"; - QByteArray ba = libpath.toLocal8Bit(); + QString libpath = + ao_app->get_base_path() + "../../Frameworks/libbassopus.dylib"; + QByteArray ba = libpath.toLocal8Bit(); #ifdef BASSAUDIO - BASS_PluginLoad(ba.data(), 0); + BASS_PluginLoad(ba.data(), 0); #endif } #else diff --git a/src/debug_functions.cpp b/src/debug_functions.cpp index ba189ec..b832164 100644 --- a/src/debug_functions.cpp +++ b/src/debug_functions.cpp @@ -5,22 +5,25 @@ void call_error(QString p_message) { - QMessageBox *msgBox = new QMessageBox; + QMessageBox *msgBox = new QMessageBox; - msgBox->setText(QCoreApplication::translate("debug_functions", "Error: %1").arg(p_message)); - msgBox->setWindowTitle(QCoreApplication::translate("debug_functions", "Error")); + msgBox->setText(QCoreApplication::translate("debug_functions", "Error: %1") + .arg(p_message)); + msgBox->setWindowTitle( + QCoreApplication::translate("debug_functions", "Error")); - //msgBox->setWindowModality(Qt::NonModal); - msgBox->exec(); + // msgBox->setWindowModality(Qt::NonModal); + msgBox->exec(); } void call_notice(QString p_message) { - QMessageBox *msgBox = new QMessageBox; + QMessageBox *msgBox = new QMessageBox; - msgBox->setText(p_message); - msgBox->setWindowTitle(QCoreApplication::translate("debug_functions", "Notice")); + msgBox->setText(p_message); + msgBox->setWindowTitle( + QCoreApplication::translate("debug_functions", "Notice")); - //msgBox->setWindowModality(Qt::NonModal); - msgBox->exec(); + // msgBox->setWindowModality(Qt::NonModal); + msgBox->exec(); } diff --git a/src/discord_rich_presence.cpp b/src/discord_rich_presence.cpp index 05a9494..aea07e5 100644 --- a/src/discord_rich_presence.cpp +++ b/src/discord_rich_presence.cpp @@ -3,129 +3,120 @@ namespace AttorneyOnline { #ifdef DISCORD - Discord::Discord() - { - DiscordEventHandlers handlers; - std::memset(&handlers, 0, sizeof(handlers)); - handlers = {}; - handlers.ready = [] { - qInfo() << "Discord RPC ready"; - }; - handlers.disconnected = [](int errorCode, const char *message) { - qInfo() << "Discord RPC disconnected! " << message << errorCode; - }; - handlers.errored = [](int errorCode, const char *message) { - qWarning() << "Discord RPC errored out! " << message << errorCode; - }; - qInfo() << "Initializing Discord RPC"; - Discord_Initialize(APPLICATION_ID, &handlers, 1, nullptr); - } +Discord::Discord() +{ + DiscordEventHandlers handlers; + std::memset(&handlers, 0, sizeof(handlers)); + handlers = {}; + handlers.ready = [] { qInfo() << "Discord RPC ready"; }; + handlers.disconnected = [](int errorCode, const char *message) { + qInfo() << "Discord RPC disconnected! " << message << errorCode; + }; + handlers.errored = [](int errorCode, const char *message) { + qWarning() << "Discord RPC errored out! " << message << errorCode; + }; + qInfo() << "Initializing Discord RPC"; + Discord_Initialize(APPLICATION_ID, &handlers, 1, nullptr); +} - Discord::~Discord() - { - Discord_Shutdown(); - } +Discord::~Discord() { Discord_Shutdown(); } - void Discord::state_lobby() - { - DiscordRichPresence presence; - std::memset(&presence, 0, sizeof(presence)); - presence.largeImageKey = "ao2-logo"; - presence.largeImageText = "Objection!"; - presence.instance = 1; +void Discord::state_lobby() +{ + DiscordRichPresence presence; + std::memset(&presence, 0, sizeof(presence)); + presence.largeImageKey = "ao2-logo"; + presence.largeImageText = "Objection!"; + presence.instance = 1; - presence.state = "In Lobby"; - presence.details = "Idle"; - Discord_UpdatePresence(&presence); - } + presence.state = "In Lobby"; + presence.details = "Idle"; + Discord_UpdatePresence(&presence); +} - void Discord::state_server(std::string name, std::string server_id) - { - qDebug() << "Discord RPC: Setting server state"; +void Discord::state_server(std::string name, std::string server_id) +{ + qDebug() << "Discord RPC: Setting server state"; - DiscordRichPresence presence; - std::memset(&presence, 0, sizeof(presence)); - presence.largeImageKey = "ao2-logo"; - presence.largeImageText = "Objection!"; - presence.instance = 1; + DiscordRichPresence presence; + std::memset(&presence, 0, sizeof(presence)); + presence.largeImageKey = "ao2-logo"; + presence.largeImageText = "Objection!"; + presence.instance = 1; - auto timestamp = static_cast(std::time(nullptr)); + auto timestamp = static_cast(std::time(nullptr)); - presence.state = "In a Server"; - presence.details = name.c_str(); - presence.matchSecret = server_id.c_str(); - presence.startTimestamp = this->timestamp; + presence.state = "In a Server"; + presence.details = name.c_str(); + presence.matchSecret = server_id.c_str(); + presence.startTimestamp = this->timestamp; - this->server_id = server_id; - this->server_name = name; - this->timestamp = timestamp; - Discord_UpdatePresence(&presence); - } + this->server_id = server_id; + this->server_name = name; + this->timestamp = timestamp; + Discord_UpdatePresence(&presence); +} - void Discord::state_character(std::string name) - { - auto name_internal = QString(name.c_str()).toLower().replace(' ', '_').toStdString(); - auto name_friendly = QString(name.c_str()).replace('_', ' ').toStdString(); - const std::string playing_as = "Playing as " + name_friendly; - qDebug() << "Discord RPC: Setting character state (" << playing_as.c_str() << ")"; +void Discord::state_character(std::string name) +{ + auto name_internal = + QString(name.c_str()).toLower().replace(' ', '_').toStdString(); + auto name_friendly = QString(name.c_str()).replace('_', ' ').toStdString(); + const std::string playing_as = "Playing as " + name_friendly; + qDebug() << "Discord RPC: Setting character state (" << playing_as.c_str() + << ")"; - DiscordRichPresence presence; - std::memset(&presence, 0, sizeof(presence)); - presence.largeImageKey = "ao2-logo"; - presence.largeImageText = "Objection!"; - presence.instance = 1; - presence.details = this->server_name.c_str(); - presence.matchSecret = this->server_id.c_str(); - presence.startTimestamp = this->timestamp; + DiscordRichPresence presence; + std::memset(&presence, 0, sizeof(presence)); + presence.largeImageKey = "ao2-logo"; + presence.largeImageText = "Objection!"; + presence.instance = 1; + presence.details = this->server_name.c_str(); + presence.matchSecret = this->server_id.c_str(); + presence.startTimestamp = this->timestamp; - presence.state = playing_as.c_str(); - presence.smallImageKey = name_internal.c_str(); - // presence.smallImageText = name_internal.c_str(); - Discord_UpdatePresence(&presence); - } + presence.state = playing_as.c_str(); + presence.smallImageKey = name_internal.c_str(); + // presence.smallImageText = name_internal.c_str(); + Discord_UpdatePresence(&presence); +} - void Discord::state_spectate() - { - qDebug() << "Discord RPC: Setting specator state"; +void Discord::state_spectate() +{ + qDebug() << "Discord RPC: Setting specator state"; - DiscordRichPresence presence; - std::memset(&presence, 0, sizeof(presence)); - presence.largeImageKey = "ao2-logo"; - presence.largeImageText = "Objection!"; - presence.instance = 1; - presence.details = this->server_name.c_str(); - presence.matchSecret = this->server_id.c_str(); - presence.startTimestamp = this->timestamp; + DiscordRichPresence presence; + std::memset(&presence, 0, sizeof(presence)); + presence.largeImageKey = "ao2-logo"; + presence.largeImageText = "Objection!"; + presence.instance = 1; + presence.details = this->server_name.c_str(); + presence.matchSecret = this->server_id.c_str(); + presence.startTimestamp = this->timestamp; - presence.state = "Spectating"; - Discord_UpdatePresence(&presence); - } + presence.state = "Spectating"; + Discord_UpdatePresence(&presence); +} #else - Discord::Discord() - { - } +Discord::Discord() {} - Discord::~Discord() - { - } +Discord::~Discord() {} - void Discord::state_lobby() - { - } +void Discord::state_lobby() {} - void Discord::state_server(std::string name, std::string server_id) - { - qDebug() << "Discord RPC: Setting server state"; - } +void Discord::state_server(std::string name, std::string server_id) +{ + qDebug() << "Discord RPC: Setting server state"; +} - void Discord::state_character(std::string name) - { - qDebug() << "Discord RPC: Setting character state"; - } +void Discord::state_character(std::string name) +{ + qDebug() << "Discord RPC: Setting character state"; +} - void Discord::state_spectate() - { - qDebug() << "Discord RPC: Setting specator state"; - } +void Discord::state_spectate() +{ + qDebug() << "Discord RPC: Setting specator state"; +} #endif } // namespace AttorneyOnline diff --git a/src/emotes.cpp b/src/emotes.cpp index 5995297..8de5524 100644 --- a/src/emotes.cpp +++ b/src/emotes.cpp @@ -4,189 +4,203 @@ void Courtroom::initialize_emotes() { - ui_emotes = new QWidget(this); + ui_emotes = new QWidget(this); - ui_emote_left = new AOButton(this, ao_app); - ui_emote_right = new AOButton(this, ao_app); + ui_emote_left = new AOButton(this, ao_app); + ui_emote_right = new AOButton(this, ao_app); - ui_emote_dropdown = new QComboBox(this); + ui_emote_dropdown = new QComboBox(this); - connect(ui_emote_left, SIGNAL(clicked()), this, SLOT(on_emote_left_clicked())); - connect(ui_emote_right, SIGNAL(clicked()), this, SLOT(on_emote_right_clicked())); + connect(ui_emote_left, SIGNAL(clicked()), this, + SLOT(on_emote_left_clicked())); + connect(ui_emote_right, SIGNAL(clicked()), this, + SLOT(on_emote_right_clicked())); - connect(ui_emote_dropdown, SIGNAL(activated(int)), this, SLOT(on_emote_dropdown_changed(int))); + connect(ui_emote_dropdown, SIGNAL(activated(int)), this, + SLOT(on_emote_dropdown_changed(int))); } void Courtroom::refresh_emotes() { - //Should properly refresh the emote list - qDeleteAll(ui_emote_list.begin(), ui_emote_list.end()); - ui_emote_list.clear(); + // Should properly refresh the emote list + qDeleteAll(ui_emote_list.begin(), ui_emote_list.end()); + ui_emote_list.clear(); - set_size_and_pos(ui_emotes, "emotes"); + set_size_and_pos(ui_emotes, "emotes"); - set_size_and_pos(ui_emote_left, "emote_left"); - ui_emote_left->set_image("arrow_left"); + set_size_and_pos(ui_emote_left, "emote_left"); + ui_emote_left->set_image("arrow_left"); - set_size_and_pos(ui_emote_right, "emote_right"); - ui_emote_right->set_image("arrow_right"); + set_size_and_pos(ui_emote_right, "emote_right"); + ui_emote_right->set_image("arrow_right"); - QPoint f_spacing = ao_app->get_button_spacing("emote_button_spacing", "courtroom_design.ini"); - QPoint p_point = ao_app->get_button_spacing("emote_button_size", "courtroom_design.ini"); + QPoint f_spacing = ao_app->get_button_spacing("emote_button_spacing", + "courtroom_design.ini"); + QPoint p_point = + ao_app->get_button_spacing("emote_button_size", "courtroom_design.ini"); - const int button_width = p_point.x(); - int x_spacing = f_spacing.x(); - int x_mod_count = 0; + const int button_width = p_point.x(); + int x_spacing = f_spacing.x(); + int x_mod_count = 0; - const int button_height = p_point.y(); - int y_spacing = f_spacing.y(); - int y_mod_count = 0; + const int button_height = p_point.y(); + int y_spacing = f_spacing.y(); + int y_mod_count = 0; - emote_columns = ((ui_emotes->width() - button_width) / (x_spacing + button_width)) + 1; - emote_rows = ((ui_emotes->height() - button_height) / (y_spacing + button_height)) + 1; + emote_columns = + ((ui_emotes->width() - button_width) / (x_spacing + button_width)) + 1; + emote_rows = + ((ui_emotes->height() - button_height) / (y_spacing + button_height)) + 1; - max_emotes_on_page = emote_columns * emote_rows; + max_emotes_on_page = emote_columns * emote_rows; - for (int n = 0; n < max_emotes_on_page; ++n) { - int x_pos = (button_width + x_spacing) * x_mod_count; - int y_pos = (button_height + y_spacing) * y_mod_count; + for (int n = 0; n < max_emotes_on_page; ++n) { + int x_pos = (button_width + x_spacing) * x_mod_count; + int y_pos = (button_height + y_spacing) * y_mod_count; - AOEmoteButton *f_emote = new AOEmoteButton(ui_emotes, ao_app, x_pos, y_pos, button_width, button_height); + AOEmoteButton *f_emote = new AOEmoteButton(ui_emotes, ao_app, x_pos, y_pos, + button_width, button_height); - ui_emote_list.append(f_emote); + ui_emote_list.append(f_emote); - f_emote->set_id(n); + f_emote->set_id(n); - connect(f_emote, SIGNAL(emote_clicked(int)), this, SLOT(on_emote_clicked(int))); + connect(f_emote, SIGNAL(emote_clicked(int)), this, + SLOT(on_emote_clicked(int))); - ++x_mod_count; + ++x_mod_count; - if (x_mod_count == emote_columns) { - ++y_mod_count; - x_mod_count = 0; - } + if (x_mod_count == emote_columns) { + ++y_mod_count; + x_mod_count = 0; } + } } void Courtroom::set_emote_page() { - if (m_cid == -1) - return; + if (m_cid == -1) + return; - int total_emotes = ao_app->get_emote_number(current_char); + int total_emotes = ao_app->get_emote_number(current_char); - ui_emote_left->hide(); - ui_emote_right->hide(); + ui_emote_left->hide(); + ui_emote_right->hide(); - for (AOEmoteButton *i_button : ui_emote_list) { - i_button->hide(); - } + for (AOEmoteButton *i_button : ui_emote_list) { + i_button->hide(); + } - int total_pages = total_emotes / max_emotes_on_page; - int emotes_on_page = 0; - - if (total_emotes % max_emotes_on_page != 0) { - ++total_pages; - //i. e. not on the last page - if (total_pages > current_emote_page + 1) - emotes_on_page = max_emotes_on_page; - else - emotes_on_page = total_emotes % max_emotes_on_page; - } - else - emotes_on_page = max_emotes_on_page; + int total_pages = total_emotes / max_emotes_on_page; + int emotes_on_page = 0; + if (total_emotes % max_emotes_on_page != 0) { + ++total_pages; + // i. e. not on the last page if (total_pages > current_emote_page + 1) - ui_emote_right->show(); + emotes_on_page = max_emotes_on_page; + else + emotes_on_page = total_emotes % max_emotes_on_page; + } + else + emotes_on_page = max_emotes_on_page; - if (current_emote_page > 0) - ui_emote_left->show(); + if (total_pages > current_emote_page + 1) + ui_emote_right->show(); - for (int n_emote = 0; n_emote < emotes_on_page && n_emote < ui_emote_list.size(); ++n_emote) { - int n_real_emote = n_emote + current_emote_page * max_emotes_on_page; - AOEmoteButton *f_emote = ui_emote_list.at(n_emote); + if (current_emote_page > 0) + ui_emote_left->show(); - if (n_real_emote == current_emote) - f_emote->set_char_image(current_char, n_real_emote, "_on"); - else - f_emote->set_char_image(current_char, n_real_emote, "_off"); + for (int n_emote = 0; + n_emote < emotes_on_page && n_emote < ui_emote_list.size(); ++n_emote) { + int n_real_emote = n_emote + current_emote_page * max_emotes_on_page; + AOEmoteButton *f_emote = ui_emote_list.at(n_emote); - f_emote->show(); - f_emote->setToolTip(QString::number(n_real_emote + 1) + ": " + ao_app->get_emote_comment(current_char, n_real_emote)); - } + if (n_real_emote == current_emote) + f_emote->set_char_image(current_char, n_real_emote, "_on"); + else + f_emote->set_char_image(current_char, n_real_emote, "_off"); + + f_emote->show(); + f_emote->setToolTip(QString::number(n_real_emote + 1) + ": " + + ao_app->get_emote_comment(current_char, n_real_emote)); + } } void Courtroom::set_emote_dropdown() { - ui_emote_dropdown->clear(); + ui_emote_dropdown->clear(); - int total_emotes = ao_app->get_emote_number(current_char); - QStringList emote_list; + int total_emotes = ao_app->get_emote_number(current_char); + QStringList emote_list; - for (int n = 0; n < total_emotes; ++n) { - emote_list.append(QString::number(n + 1) + ": " + ao_app->get_emote_comment(current_char, n)); - } + for (int n = 0; n < total_emotes; ++n) { + emote_list.append(QString::number(n + 1) + ": " + + ao_app->get_emote_comment(current_char, n)); + } - ui_emote_dropdown->addItems(emote_list); + ui_emote_dropdown->addItems(emote_list); } void Courtroom::select_emote(int p_id) { - int min = current_emote_page * max_emotes_on_page; - int max = (max_emotes_on_page - 1) + current_emote_page * max_emotes_on_page; + int min = current_emote_page * max_emotes_on_page; + int max = (max_emotes_on_page - 1) + current_emote_page * max_emotes_on_page; - if (current_emote >= min && current_emote <= max) - ui_emote_list.at(current_emote % max_emotes_on_page)->set_char_image(current_char, current_emote, "_off"); + if (current_emote >= min && current_emote <= max) + ui_emote_list.at(current_emote % max_emotes_on_page) + ->set_char_image(current_char, current_emote, "_off"); - int old_emote = current_emote; + int old_emote = current_emote; - current_emote = p_id; + current_emote = p_id; - if (current_emote >= min && current_emote <= max) - ui_emote_list.at(current_emote % max_emotes_on_page)->set_char_image(current_char, current_emote, "_on"); + if (current_emote >= min && current_emote <= max) + ui_emote_list.at(current_emote % max_emotes_on_page) + ->set_char_image(current_char, current_emote, "_on"); - int emote_mod = ao_app->get_emote_mod(current_char, current_emote); + int emote_mod = ao_app->get_emote_mod(current_char, current_emote); - if (old_emote == current_emote) { - ui_pre->setChecked(!ui_pre->isChecked()); - } - else if (!ao_app->is_stickypres_enabled()) { - if (emote_mod == 1 || emote_mod == 4) - ui_pre->setChecked(true); - else - ui_pre->setChecked(false); - } + if (old_emote == current_emote) { + ui_pre->setChecked(!ui_pre->isChecked()); + } + else if (!ao_app->is_stickypres_enabled()) { + if (emote_mod == 1 || emote_mod == 4) + ui_pre->setChecked(true); + else + ui_pre->setChecked(false); + } - ui_emote_dropdown->setCurrentIndex(current_emote); + ui_emote_dropdown->setCurrentIndex(current_emote); - ui_ic_chat_message->setFocus(); + ui_ic_chat_message->setFocus(); } void Courtroom::on_emote_clicked(int p_id) { - select_emote(p_id + max_emotes_on_page * current_emote_page); + select_emote(p_id + max_emotes_on_page * current_emote_page); } void Courtroom::on_emote_left_clicked() { - --current_emote_page; + --current_emote_page; - set_emote_page(); + set_emote_page(); - ui_ic_chat_message->setFocus(); + ui_ic_chat_message->setFocus(); } void Courtroom::on_emote_right_clicked() { - qDebug() << "emote right clicked"; - ++current_emote_page; + qDebug() << "emote right clicked"; + ++current_emote_page; - set_emote_page(); + set_emote_page(); - ui_ic_chat_message->setFocus(); + ui_ic_chat_message->setFocus(); } void Courtroom::on_emote_dropdown_changed(int p_index) { - select_emote(p_index); + select_emote(p_index); } diff --git a/src/encryption_functions.cpp b/src/encryption_functions.cpp index f26d4d4..6669fe1 100644 --- a/src/encryption_functions.cpp +++ b/src/encryption_functions.cpp @@ -4,55 +4,55 @@ QString fanta_encrypt(QString temp_input, unsigned int p_key) { - //using standard stdlib types is actually easier here because of implicit char<->int conversion - //which in turn makes encryption arithmetic easier + // using standard stdlib types is actually easier here because of implicit + // char<->int conversion which in turn makes encryption arithmetic easier - unsigned int key = p_key; - unsigned int C1 = 53761; - unsigned int C2 = 32618; + unsigned int key = p_key; + unsigned int C1 = 53761; + unsigned int C2 = 32618; - QVector temp_result; - std::string input = temp_input.toUtf8().constData(); + QVector temp_result; + std::string input = temp_input.toUtf8().constData(); - for (unsigned int pos = 0; pos < input.size(); ++pos) { - uint_fast8_t output = input.at(pos) ^ (key >> 8) % 256; - temp_result.append(output); - key = (temp_result.at(pos) + key) * C1 + C2; - } + for (unsigned int pos = 0; pos < input.size(); ++pos) { + uint_fast8_t output = input.at(pos) ^ (key >> 8) % 256; + temp_result.append(output); + key = (temp_result.at(pos) + key) * C1 + C2; + } - std::string result = ""; + std::string result = ""; - for (uint_fast8_t i_int : temp_result) { - result += omni::int_to_hex(i_int); - } + for (uint_fast8_t i_int : temp_result) { + result += omni::int_to_hex(i_int); + } - QString final_result = QString::fromStdString(result); + QString final_result = QString::fromStdString(result); - return final_result; + return final_result; } QString fanta_decrypt(QString temp_input, unsigned int key) { - std::string input = temp_input.toUtf8().constData(); + std::string input = temp_input.toUtf8().constData(); - QVector unhexed_vector; + QVector unhexed_vector; - for (unsigned int i = 0; i < input.length(); i += 2) { - std::string byte = input.substr(i, 2); - unsigned int hex_int = strtoul(byte.c_str(), nullptr, 16); - unhexed_vector.append(hex_int); - } + for (unsigned int i = 0; i < input.length(); i += 2) { + std::string byte = input.substr(i, 2); + unsigned int hex_int = strtoul(byte.c_str(), nullptr, 16); + unhexed_vector.append(hex_int); + } - unsigned int C1 = 53761; - unsigned int C2 = 32618; + unsigned int C1 = 53761; + unsigned int C2 = 32618; - std::string result = ""; + std::string result = ""; - for (int pos = 0; pos < unhexed_vector.size(); ++pos) { - unsigned char output = unhexed_vector.at(pos) ^ (key >> 8) % 256; - result += output; - key = (unhexed_vector.at(pos) + key) * C1 + C2; - } + for (int pos = 0; pos < unhexed_vector.size(); ++pos) { + unsigned char output = unhexed_vector.at(pos) ^ (key >> 8) % 256; + result += output; + key = (unhexed_vector.at(pos) + key) * C1 + C2; + } - return QString::fromStdString(result); + return QString::fromStdString(result); } diff --git a/src/evidence.cpp b/src/evidence.cpp index 50ed9a4..edfad5d 100644 --- a/src/evidence.cpp +++ b/src/evidence.cpp @@ -2,708 +2,776 @@ void Courtroom::initialize_evidence() { - ui_evidence = new AOImage(this, ao_app); + ui_evidence = new AOImage(this, ao_app); - //ui_evidence_name = new QLabel(ui_evidence); - ui_evidence_name = new AOLineEdit(ui_evidence); - ui_evidence_name->setAlignment(Qt::AlignCenter); - ui_evidence_name->setFrame(false); + // ui_evidence_name = new QLabel(ui_evidence); + ui_evidence_name = new AOLineEdit(ui_evidence); + ui_evidence_name->setAlignment(Qt::AlignCenter); + ui_evidence_name->setFrame(false); - ui_evidence_buttons = new QWidget(ui_evidence); + ui_evidence_buttons = new QWidget(ui_evidence); - ui_evidence_left = new AOButton(ui_evidence, ao_app); - ui_evidence_right = new AOButton(ui_evidence, ao_app); - ui_evidence_present = new AOButton(ui_evidence, ao_app); - ui_evidence_present->setToolTip(tr("Present this piece of evidence to everyone on your next spoken message")); + ui_evidence_left = new AOButton(ui_evidence, ao_app); + ui_evidence_right = new AOButton(ui_evidence, ao_app); + ui_evidence_present = new AOButton(ui_evidence, ao_app); + ui_evidence_present->setToolTip(tr("Present this piece of evidence to " + "everyone on your next spoken message")); - ui_evidence_switch = new AOButton(ui_evidence, ao_app); - ui_evidence_transfer = new AOButton(ui_evidence, ao_app); + ui_evidence_switch = new AOButton(ui_evidence, ao_app); + ui_evidence_transfer = new AOButton(ui_evidence, ao_app); - ui_evidence_save = new AOButton(ui_evidence, ao_app); - ui_evidence_save->setToolTip(tr("Save evidence to an .ini file.")); - ui_evidence_load = new AOButton(ui_evidence, ao_app); - ui_evidence_load->setToolTip(tr("Load evidence from an .ini file.")); + ui_evidence_save = new AOButton(ui_evidence, ao_app); + ui_evidence_save->setToolTip(tr("Save evidence to an .ini file.")); + ui_evidence_load = new AOButton(ui_evidence, ao_app); + ui_evidence_load->setToolTip(tr("Load evidence from an .ini file.")); - ui_evidence_overlay = new AOImage(ui_evidence, ao_app); + ui_evidence_overlay = new AOImage(ui_evidence, ao_app); - ui_evidence_delete = new AOButton(ui_evidence_overlay, ao_app); - ui_evidence_delete->setToolTip(tr("Destroy this piece of evidence")); - ui_evidence_image_name = new AOLineEdit(ui_evidence_overlay); - ui_evidence_image_button = new AOButton(ui_evidence_overlay, ao_app); - ui_evidence_image_button->setText(tr("Choose...")); - ui_evidence_x = new AOButton(ui_evidence_overlay, ao_app); - ui_evidence_x->setToolTip(tr("Close the evidence display/editing overlay.\n" - "You will be prompted if there's any unsaved changes.")); - ui_evidence_ok = new AOButton(ui_evidence_overlay, ao_app); - ui_evidence_ok->setToolTip(tr("Save any changes made to this piece of evidence and send them to server.")); + ui_evidence_delete = new AOButton(ui_evidence_overlay, ao_app); + ui_evidence_delete->setToolTip(tr("Destroy this piece of evidence")); + ui_evidence_image_name = new AOLineEdit(ui_evidence_overlay); + ui_evidence_image_button = new AOButton(ui_evidence_overlay, ao_app); + ui_evidence_image_button->setText(tr("Choose...")); + ui_evidence_x = new AOButton(ui_evidence_overlay, ao_app); + ui_evidence_x->setToolTip( + tr("Close the evidence display/editing overlay.\n" + "You will be prompted if there's any unsaved changes.")); + ui_evidence_ok = new AOButton(ui_evidence_overlay, ao_app); + ui_evidence_ok->setToolTip(tr("Save any changes made to this piece of " + "evidence and send them to server.")); - ui_evidence_description = new AOTextEdit(ui_evidence_overlay); - ui_evidence_description->setStyleSheet("background-color: rgba(0, 0, 0, 0);" - "color: white;"); - ui_evidence_description->setFrameStyle(QFrame::NoFrame); - ui_evidence_description->setToolTip("Double-click to edit. Press [X] to update your changes."); + ui_evidence_description = new AOTextEdit(ui_evidence_overlay); + ui_evidence_description->setStyleSheet("background-color: rgba(0, 0, 0, 0);" + "color: white;"); + ui_evidence_description->setFrameStyle(QFrame::NoFrame); + ui_evidence_description->setToolTip( + "Double-click to edit. Press [X] to update your changes."); - connect(ui_evidence_name, SIGNAL(returnPressed()), this, SLOT(on_evidence_name_edited())); - connect(ui_evidence_name, SIGNAL(double_clicked()), this, SLOT(on_evidence_name_double_clicked())); - connect(ui_evidence_left, SIGNAL(clicked()), this, SLOT(on_evidence_left_clicked())); - connect(ui_evidence_right, SIGNAL(clicked()), this, SLOT(on_evidence_right_clicked())); - connect(ui_evidence_present, SIGNAL(clicked()), this, SLOT(on_evidence_present_clicked())); - connect(ui_evidence_switch, SIGNAL(clicked()), this, SLOT(on_evidence_switch_clicked())); - connect(ui_evidence_transfer, SIGNAL(clicked()), this, SLOT(on_evidence_transfer_clicked())); - connect(ui_evidence_save, SIGNAL(clicked()), this, SLOT(on_evidence_save_clicked())); - connect(ui_evidence_load, SIGNAL(clicked()), this, SLOT(on_evidence_load_clicked())); + connect(ui_evidence_name, SIGNAL(returnPressed()), this, + SLOT(on_evidence_name_edited())); + connect(ui_evidence_name, SIGNAL(double_clicked()), this, + SLOT(on_evidence_name_double_clicked())); + connect(ui_evidence_left, SIGNAL(clicked()), this, + SLOT(on_evidence_left_clicked())); + connect(ui_evidence_right, SIGNAL(clicked()), this, + SLOT(on_evidence_right_clicked())); + connect(ui_evidence_present, SIGNAL(clicked()), this, + SLOT(on_evidence_present_clicked())); + connect(ui_evidence_switch, SIGNAL(clicked()), this, + SLOT(on_evidence_switch_clicked())); + connect(ui_evidence_transfer, SIGNAL(clicked()), this, + SLOT(on_evidence_transfer_clicked())); + connect(ui_evidence_save, SIGNAL(clicked()), this, + SLOT(on_evidence_save_clicked())); + connect(ui_evidence_load, SIGNAL(clicked()), this, + SLOT(on_evidence_load_clicked())); - connect(ui_evidence_delete, SIGNAL(clicked()), this, SLOT(on_evidence_delete_clicked())); - connect(ui_evidence_image_name, SIGNAL(returnPressed()), this, SLOT(on_evidence_image_name_edited())); - connect(ui_evidence_image_name, SIGNAL(double_clicked()), this, SLOT(on_evidence_image_name_double_clicked())); - connect(ui_evidence_image_button, SIGNAL(clicked()), this, SLOT(on_evidence_image_button_clicked())); - connect(ui_evidence_x, SIGNAL(clicked()), this, SLOT(on_evidence_x_clicked())); - connect(ui_evidence_ok, SIGNAL(clicked()), this, SLOT(on_evidence_ok_clicked())); + connect(ui_evidence_delete, SIGNAL(clicked()), this, + SLOT(on_evidence_delete_clicked())); + connect(ui_evidence_image_name, SIGNAL(returnPressed()), this, + SLOT(on_evidence_image_name_edited())); + connect(ui_evidence_image_name, SIGNAL(double_clicked()), this, + SLOT(on_evidence_image_name_double_clicked())); + connect(ui_evidence_image_button, SIGNAL(clicked()), this, + SLOT(on_evidence_image_button_clicked())); + connect(ui_evidence_x, SIGNAL(clicked()), this, + SLOT(on_evidence_x_clicked())); + connect(ui_evidence_ok, SIGNAL(clicked()), this, + SLOT(on_evidence_ok_clicked())); - connect(ui_evidence_name, SIGNAL(textChanged(QString)), this, SLOT(on_evidence_edited())); - connect(ui_evidence_image_name, SIGNAL(textChanged(QString)), this, SLOT(on_evidence_edited())); - connect(ui_evidence_description, SIGNAL(textChanged()), this, SLOT(on_evidence_edited())); + connect(ui_evidence_name, SIGNAL(textChanged(QString)), this, + SLOT(on_evidence_edited())); + connect(ui_evidence_image_name, SIGNAL(textChanged(QString)), this, + SLOT(on_evidence_edited())); + connect(ui_evidence_description, SIGNAL(textChanged()), this, + SLOT(on_evidence_edited())); - ui_evidence->hide(); + ui_evidence->hide(); } void Courtroom::refresh_evidence() { - set_font(ui_evidence_name, "", "evidence_name"); - set_font(ui_evidence_image_name, "", "evidence_image_name"); - set_font(ui_evidence_description, "", "evidence_description"); + set_font(ui_evidence_name, "", "evidence_name"); + set_font(ui_evidence_image_name, "", "evidence_image_name"); + set_font(ui_evidence_description, "", "evidence_description"); - //Should properly refresh the evidence list - qDeleteAll(ui_evidence_list.begin(), ui_evidence_list.end()); - ui_evidence_list.clear(); + // Should properly refresh the evidence list + qDeleteAll(ui_evidence_list.begin(), ui_evidence_list.end()); + ui_evidence_list.clear(); - set_size_and_pos(ui_evidence_button, "evidence_button"); - ui_evidence_button->set_image("evidence_button"); - ui_evidence_button->setToolTip(tr("Bring up the Evidence screen.")); + set_size_and_pos(ui_evidence_button, "evidence_button"); + ui_evidence_button->set_image("evidence_button"); + ui_evidence_button->setToolTip(tr("Bring up the Evidence screen.")); - set_size_and_pos(ui_evidence, "evidence_background"); - if (current_evidence_global) - ui_evidence->set_image("evidence_background"); - else - ui_evidence->set_image("evidence_background_private"); + set_size_and_pos(ui_evidence, "evidence_background"); + if (current_evidence_global) + ui_evidence->set_image("evidence_background"); + else + ui_evidence->set_image("evidence_background_private"); - set_size_and_pos(ui_evidence_name, "evidence_name"); + set_size_and_pos(ui_evidence_name, "evidence_name"); - set_size_and_pos(ui_evidence_buttons, "evidence_buttons"); + set_size_and_pos(ui_evidence_buttons, "evidence_buttons"); - set_size_and_pos(ui_evidence_left, "evidence_left"); - ui_evidence_left->set_image("arrow_left"); + set_size_and_pos(ui_evidence_left, "evidence_left"); + ui_evidence_left->set_image("arrow_left"); - set_size_and_pos(ui_evidence_right, "evidence_right"); - ui_evidence_right->set_image("arrow_right"); + set_size_and_pos(ui_evidence_right, "evidence_right"); + ui_evidence_right->set_image("arrow_right"); - set_size_and_pos(ui_evidence_present, "evidence_present"); - ui_evidence_present->set_image("present"); + set_size_and_pos(ui_evidence_present, "evidence_present"); + ui_evidence_present->set_image("present"); - set_size_and_pos(ui_evidence_overlay, "evidence_overlay"); - if (current_evidence_global) - ui_evidence_overlay->set_image("evidence_overlay"); - else - ui_evidence_overlay->set_image("evidence_overlay_private"); + set_size_and_pos(ui_evidence_overlay, "evidence_overlay"); + if (current_evidence_global) + ui_evidence_overlay->set_image("evidence_overlay"); + else + ui_evidence_overlay->set_image("evidence_overlay_private"); - set_size_and_pos(ui_evidence_delete, "evidence_delete"); - ui_evidence_delete->set_image("evidence_delete"); + set_size_and_pos(ui_evidence_delete, "evidence_delete"); + ui_evidence_delete->set_image("evidence_delete"); - set_size_and_pos(ui_evidence_image_name, "evidence_image_name"); + set_size_and_pos(ui_evidence_image_name, "evidence_image_name"); - set_size_and_pos(ui_evidence_image_button, "evidence_image_button"); + set_size_and_pos(ui_evidence_image_button, "evidence_image_button"); - set_size_and_pos(ui_evidence_x, "evidence_x"); - ui_evidence_x->set_image("evidence_x"); + set_size_and_pos(ui_evidence_x, "evidence_x"); + ui_evidence_x->set_image("evidence_x"); - set_size_and_pos(ui_evidence_ok, "evidence_ok"); - ui_evidence_ok->set_image("evidence_ok"); + set_size_and_pos(ui_evidence_ok, "evidence_ok"); + ui_evidence_ok->set_image("evidence_ok"); - set_size_and_pos(ui_evidence_switch, "evidence_switch"); - if (current_evidence_global) { - ui_evidence_switch->set_image("evidence_global"); - ui_evidence_switch->setToolTip(tr("Switch evidence to private inventory.")); - } - else { - ui_evidence_switch->set_image("evidence_private"); - ui_evidence_switch->setToolTip(tr("Switch evidence to global inventory.")); - } - - set_size_and_pos(ui_evidence_transfer, "evidence_transfer"); - if (current_evidence_global) { - ui_evidence_transfer->set_image("evidence_transfer"); - ui_evidence_transfer->setToolTip(tr("Transfer evidence to private inventory.")); - } - else { - ui_evidence_transfer->set_image("evidence_transfer_private"); - ui_evidence_transfer->setToolTip(tr("Transfer evidence to global inventory.")); - } - - set_size_and_pos(ui_evidence_save, "evidence_save"); - ui_evidence_save->set_image("evidence_save"); - if (current_evidence_global) - ui_evidence_save->hide(); - else - ui_evidence_save->show(); - - set_size_and_pos(ui_evidence_load, "evidence_load"); - ui_evidence_load->set_image("evidence_load"); - if (current_evidence_global) - ui_evidence_load->hide(); - else - ui_evidence_load->show(); - - set_size_and_pos(ui_evidence_description, "evidence_description"); - - QPoint f_spacing = ao_app->get_button_spacing("evidence_button_spacing", "courtroom_design.ini"); - QPoint p_point = ao_app->get_button_spacing("evidence_button_size", "courtroom_design.ini"); - - const int button_width = p_point.x(); - int x_spacing = f_spacing.x(); - int x_mod_count = 0; - - const int button_height = p_point.y(); - int y_spacing = f_spacing.y(); - int y_mod_count = 0; - - evidence_columns = ((ui_evidence_buttons->width() - button_width) / (x_spacing + button_width)) + 1; - evidence_rows = ((ui_evidence_buttons->height() - button_height) / (y_spacing + button_height)) + 1; - - max_evidence_on_page = evidence_columns * evidence_rows; - - for (int n = 0; n < max_evidence_on_page; ++n) { - int x_pos = (button_width + x_spacing) * x_mod_count; - int y_pos = (button_height + y_spacing) * y_mod_count; - - AOEvidenceButton *f_evidence = new AOEvidenceButton(ui_evidence_buttons, ao_app, x_pos, y_pos, button_width, button_height); - - ui_evidence_list.append(f_evidence); - - f_evidence->set_id(n); - - connect(f_evidence, SIGNAL(evidence_clicked(int)), this, SLOT(on_evidence_clicked(int))); - connect(f_evidence, SIGNAL(evidence_double_clicked(int)), this, SLOT(on_evidence_double_clicked(int))); - connect(f_evidence, SIGNAL(on_hover(int, bool)), this, SLOT(on_evidence_hover(int, bool))); - - ++x_mod_count; - - if (x_mod_count == evidence_columns) { - ++y_mod_count; - x_mod_count = 0; - } + set_size_and_pos(ui_evidence_switch, "evidence_switch"); + if (current_evidence_global) { + ui_evidence_switch->set_image("evidence_global"); + ui_evidence_switch->setToolTip(tr("Switch evidence to private inventory.")); + } + else { + ui_evidence_switch->set_image("evidence_private"); + ui_evidence_switch->setToolTip(tr("Switch evidence to global inventory.")); + } + + set_size_and_pos(ui_evidence_transfer, "evidence_transfer"); + if (current_evidence_global) { + ui_evidence_transfer->set_image("evidence_transfer"); + ui_evidence_transfer->setToolTip( + tr("Transfer evidence to private inventory.")); + } + else { + ui_evidence_transfer->set_image("evidence_transfer_private"); + ui_evidence_transfer->setToolTip( + tr("Transfer evidence to global inventory.")); + } + + set_size_and_pos(ui_evidence_save, "evidence_save"); + ui_evidence_save->set_image("evidence_save"); + if (current_evidence_global) + ui_evidence_save->hide(); + else + ui_evidence_save->show(); + + set_size_and_pos(ui_evidence_load, "evidence_load"); + ui_evidence_load->set_image("evidence_load"); + if (current_evidence_global) + ui_evidence_load->hide(); + else + ui_evidence_load->show(); + + set_size_and_pos(ui_evidence_description, "evidence_description"); + + QPoint f_spacing = ao_app->get_button_spacing("evidence_button_spacing", + "courtroom_design.ini"); + QPoint p_point = ao_app->get_button_spacing("evidence_button_size", + "courtroom_design.ini"); + + const int button_width = p_point.x(); + int x_spacing = f_spacing.x(); + int x_mod_count = 0; + + const int button_height = p_point.y(); + int y_spacing = f_spacing.y(); + int y_mod_count = 0; + + evidence_columns = ((ui_evidence_buttons->width() - button_width) / + (x_spacing + button_width)) + + 1; + evidence_rows = ((ui_evidence_buttons->height() - button_height) / + (y_spacing + button_height)) + + 1; + + max_evidence_on_page = evidence_columns * evidence_rows; + + for (int n = 0; n < max_evidence_on_page; ++n) { + int x_pos = (button_width + x_spacing) * x_mod_count; + int y_pos = (button_height + y_spacing) * y_mod_count; + + AOEvidenceButton *f_evidence = new AOEvidenceButton( + ui_evidence_buttons, ao_app, x_pos, y_pos, button_width, button_height); + + ui_evidence_list.append(f_evidence); + + f_evidence->set_id(n); + + connect(f_evidence, SIGNAL(evidence_clicked(int)), this, + SLOT(on_evidence_clicked(int))); + connect(f_evidence, SIGNAL(evidence_double_clicked(int)), this, + SLOT(on_evidence_double_clicked(int))); + connect(f_evidence, SIGNAL(on_hover(int, bool)), this, + SLOT(on_evidence_hover(int, bool))); + + ++x_mod_count; + + if (x_mod_count == evidence_columns) { + ++y_mod_count; + x_mod_count = 0; } + } } void Courtroom::set_evidence_list(QVector &p_evi_list) { - global_evidence_list = p_evi_list; - if (!current_evidence_global) - return; //We're on private evidence editing, wait for user to do their thing + global_evidence_list = p_evi_list; + if (!current_evidence_global) + return; // We're on private evidence editing, wait for user to do their + // thing - QVector old_list = local_evidence_list; - local_evidence_list.clear(); - local_evidence_list = p_evi_list; + QVector old_list = local_evidence_list; + local_evidence_list.clear(); + local_evidence_list = p_evi_list; - set_evidence_page(); + set_evidence_page(); - if (ui_evidence_overlay->isVisible()) //Update the currently edited evidence for this user - { - if (current_evidence >= local_evidence_list.size()) { - evidence_close(); - ui_evidence_name->setText(""); - } - else if (ui_evidence_description->isReadOnly()) //We haven't double clicked to edit it or anything - { - on_evidence_double_clicked(current_evidence); - } - //Todo: make a function that compares two pieces of evidence for any differences - else if (compare_evidence_changed(old_list.at(current_evidence), local_evidence_list.at(current_evidence))) { - QMessageBox *msgBox = new QMessageBox; - - msgBox->setText("The piece of evidence you've been editing has changed."); - msgBox->setInformativeText("Do you wish to keep your changes?"); - msgBox->setDetailedText("Name: " + local_evidence_list.at(current_evidence).name + "\nImage: " + local_evidence_list.at(current_evidence).image + "\nDescription:\n" + local_evidence_list.at(current_evidence).description); - msgBox->setStandardButtons(QMessageBox::Yes | QMessageBox::No); - msgBox->setDefaultButton(QMessageBox::LastButton); - //msgBox->setWindowModality(Qt::NonModal); - int ret = msgBox->exec(); - switch (ret) { - case QMessageBox::Yes: - // "Keep changes" - break; - case QMessageBox::No: - // "Discard changes and keep theirs" - on_evidence_double_clicked(current_evidence); - break; - default: - // should never be reached - break; - } - } + if (ui_evidence_overlay + ->isVisible()) // Update the currently edited evidence for this user + { + if (current_evidence >= local_evidence_list.size()) { + evidence_close(); + ui_evidence_name->setText(""); } + else if (ui_evidence_description->isReadOnly()) // We haven't double clicked + // to edit it or anything + { + on_evidence_double_clicked(current_evidence); + } + // Todo: make a function that compares two pieces of evidence for any + // differences + else if (compare_evidence_changed( + old_list.at(current_evidence), + local_evidence_list.at(current_evidence))) { + QMessageBox *msgBox = new QMessageBox; + + msgBox->setText("The piece of evidence you've been editing has changed."); + msgBox->setInformativeText("Do you wish to keep your changes?"); + msgBox->setDetailedText( + "Name: " + local_evidence_list.at(current_evidence).name + + "\nImage: " + local_evidence_list.at(current_evidence).image + + "\nDescription:\n" + + local_evidence_list.at(current_evidence).description); + msgBox->setStandardButtons(QMessageBox::Yes | QMessageBox::No); + msgBox->setDefaultButton(QMessageBox::LastButton); + // msgBox->setWindowModality(Qt::NonModal); + int ret = msgBox->exec(); + switch (ret) { + case QMessageBox::Yes: + // "Keep changes" + break; + case QMessageBox::No: + // "Discard changes and keep theirs" + on_evidence_double_clicked(current_evidence); + break; + default: + // should never be reached + break; + } + } + } } void Courtroom::set_evidence_page() { - int total_evidence = local_evidence_list.size(); + int total_evidence = local_evidence_list.size(); - ui_evidence_left->hide(); - ui_evidence_right->hide(); + ui_evidence_left->hide(); + ui_evidence_right->hide(); - for (AOEvidenceButton *i_button : ui_evidence_list) { - i_button->hide(); + for (AOEvidenceButton *i_button : ui_evidence_list) { + i_button->hide(); + } + + // to account for the "add evidence" button + ++total_evidence; + + int total_pages = total_evidence / max_evidence_on_page; + int evidence_on_page = 0; + + if ((total_evidence % max_evidence_on_page) != 0) { + ++total_pages; + // i. e. not on the last page + if (total_pages > current_evidence_page + 1) + evidence_on_page = max_evidence_on_page; + else + evidence_on_page = total_evidence % max_evidence_on_page; + } + else + evidence_on_page = max_evidence_on_page; + + if (total_pages > current_evidence_page + 1) + ui_evidence_right->show(); + + if (current_evidence_page > 0) + ui_evidence_left->show(); + + for (int n_evidence_button = 0; n_evidence_button < evidence_on_page; + ++n_evidence_button) { + int n_real_evidence = + n_evidence_button + current_evidence_page * max_evidence_on_page; + AOEvidenceButton *f_evidence_button = + ui_evidence_list.at(n_evidence_button); + + f_evidence_button->set_selected(false); + f_evidence_button->setToolTip(""); + if (n_real_evidence == (total_evidence - 1)) { + f_evidence_button->set_theme_image("addevidence.png"); } + else if (n_real_evidence < (total_evidence - 1)) { + f_evidence_button->set_image( + local_evidence_list.at(n_real_evidence).image); - //to account for the "add evidence" button - ++total_evidence; + if (n_real_evidence == current_evidence) + f_evidence_button->set_selected(true); - int total_pages = total_evidence / max_evidence_on_page; - int evidence_on_page = 0; - - if ((total_evidence % max_evidence_on_page) != 0) { - ++total_pages; - //i. e. not on the last page - if (total_pages > current_evidence_page + 1) - evidence_on_page = max_evidence_on_page; - else - evidence_on_page = total_evidence % max_evidence_on_page; + f_evidence_button->setToolTip( + QString::number(n_real_evidence + 1) + ": " + + local_evidence_list.at(n_real_evidence).name); } else - evidence_on_page = max_evidence_on_page; + f_evidence_button->set_image(""); - if (total_pages > current_evidence_page + 1) - ui_evidence_right->show(); - - if (current_evidence_page > 0) - ui_evidence_left->show(); - - for (int n_evidence_button = 0; n_evidence_button < evidence_on_page; ++n_evidence_button) { - int n_real_evidence = n_evidence_button + current_evidence_page * max_evidence_on_page; - AOEvidenceButton *f_evidence_button = ui_evidence_list.at(n_evidence_button); - - f_evidence_button->set_selected(false); - f_evidence_button->setToolTip(""); - if (n_real_evidence == (total_evidence - 1)) { - f_evidence_button->set_theme_image("addevidence.png"); - } - else if (n_real_evidence < (total_evidence - 1)) { - f_evidence_button->set_image(local_evidence_list.at(n_real_evidence).image); - - if (n_real_evidence == current_evidence) - f_evidence_button->set_selected(true); - - f_evidence_button->setToolTip(QString::number(n_real_evidence + 1) + ": " + local_evidence_list.at(n_real_evidence).name); - } - else - f_evidence_button->set_image(""); - - f_evidence_button->show(); - } + f_evidence_button->show(); + } } void Courtroom::on_evidence_name_edited() { - ui_evidence_name->setReadOnly(true); - if (current_evidence >= local_evidence_list.size()) - return; + ui_evidence_name->setReadOnly(true); + if (current_evidence >= local_evidence_list.size()) + return; } void Courtroom::on_evidence_name_double_clicked() { - if (ui_evidence_overlay->isVisible()) { - ui_evidence_name->setReadOnly(false); - } - else { - ui_evidence_name->setReadOnly(true); - } + if (ui_evidence_overlay->isVisible()) { + ui_evidence_name->setReadOnly(false); + } + else { + ui_evidence_name->setReadOnly(true); + } } void Courtroom::on_evidence_image_name_double_clicked() { - ui_evidence_image_name->setReadOnly(false); + ui_evidence_image_name->setReadOnly(false); } void Courtroom::on_evidence_image_name_edited() { - ui_evidence_image_name->setReadOnly(true); - if (current_evidence >= local_evidence_list.size()) - return; + ui_evidence_image_name->setReadOnly(true); + if (current_evidence >= local_evidence_list.size()) + return; } void Courtroom::on_evidence_image_button_clicked() { - QDir dir(ao_app->get_base_path() + "evidence"); - QFileDialog dialog(this); - dialog.setFileMode(QFileDialog::ExistingFile); - dialog.setNameFilter(tr("Images (*.png)")); - dialog.setViewMode(QFileDialog::List); - dialog.setDirectory(dir); + QDir dir(ao_app->get_base_path() + "evidence"); + QFileDialog dialog(this); + dialog.setFileMode(QFileDialog::ExistingFile); + dialog.setNameFilter(tr("Images (*.png)")); + dialog.setViewMode(QFileDialog::List); + dialog.setDirectory(dir); - QStringList filenames; + QStringList filenames; - if (dialog.exec()) - filenames = dialog.selectedFiles(); + if (dialog.exec()) + filenames = dialog.selectedFiles(); - if (filenames.size() != 1) - return; + if (filenames.size() != 1) + return; - QString filename = filenames.at(0); - filename = dir.relativeFilePath(filename); - ui_evidence_image_name->setText(filename); - on_evidence_image_name_edited(); + QString filename = filenames.at(0); + filename = dir.relativeFilePath(filename); + ui_evidence_image_name->setText(filename); + on_evidence_image_name_edited(); } void Courtroom::on_evidence_clicked(int p_id) { - ui_evidence_name->setReadOnly(true); + ui_evidence_name->setReadOnly(true); - int f_real_id = p_id + max_evidence_on_page * current_evidence_page; + int f_real_id = p_id + max_evidence_on_page * current_evidence_page; - if (f_real_id == local_evidence_list.size()) { - if (current_evidence_global) - ao_app->send_server_packet(new AOPacket("PE###empty.png#%")); - else { - evi_type f_evi; - f_evi.name = ""; - f_evi.description = ""; - f_evi.image = "empty.png"; + if (f_real_id == local_evidence_list.size()) { + if (current_evidence_global) + ao_app->send_server_packet( + new AOPacket("PE###empty.png#%")); + else { + evi_type f_evi; + f_evi.name = ""; + f_evi.description = ""; + f_evi.image = "empty.png"; - local_evidence_list.append(f_evi); - private_evidence_list = local_evidence_list; - set_evidence_page(); - } - return; + local_evidence_list.append(f_evi); + private_evidence_list = local_evidence_list; + set_evidence_page(); } - else if (f_real_id > local_evidence_list.size()) - return; + return; + } + else if (f_real_id > local_evidence_list.size()) + return; - ui_evidence_name->setText(local_evidence_list.at(f_real_id).name); + ui_evidence_name->setText(local_evidence_list.at(f_real_id).name); - for (AOEvidenceButton *i_button : ui_evidence_list) - i_button->set_selected(false); + for (AOEvidenceButton *i_button : ui_evidence_list) + i_button->set_selected(false); - ui_evidence_list.at(p_id)->set_selected(true); + ui_evidence_list.at(p_id)->set_selected(true); - current_evidence = f_real_id; + current_evidence = f_real_id; - // ui_ic_chat_message->setFocus(); + // ui_ic_chat_message->setFocus(); } void Courtroom::on_evidence_double_clicked(int p_id) { - int f_real_id = p_id + max_evidence_on_page * current_evidence_page; + int f_real_id = p_id + max_evidence_on_page * current_evidence_page; - if (f_real_id >= local_evidence_list.size()) - return; + if (f_real_id >= local_evidence_list.size()) + return; - current_evidence = f_real_id; + current_evidence = f_real_id; - evi_type f_evi = local_evidence_list.at(f_real_id); + evi_type f_evi = local_evidence_list.at(f_real_id); - ui_evidence_description->clear(); - ui_evidence_description->appendPlainText(f_evi.description); - ui_evidence_description->setReadOnly(true); - ui_evidence_description->setToolTip("Double-click to edit..."); + ui_evidence_description->clear(); + ui_evidence_description->appendPlainText(f_evi.description); + ui_evidence_description->setReadOnly(true); + ui_evidence_description->setToolTip("Double-click to edit..."); - ui_evidence_name->setText(f_evi.name); - ui_evidence_name->setReadOnly(true); - ui_evidence_name->setToolTip("Double-click to edit..."); - ui_evidence_image_name->setText(f_evi.image); - ui_evidence_image_name->setReadOnly(true); - ui_evidence_image_name->setToolTip("Double-click to edit..."); + ui_evidence_name->setText(f_evi.name); + ui_evidence_name->setReadOnly(true); + ui_evidence_name->setToolTip("Double-click to edit..."); + ui_evidence_image_name->setText(f_evi.image); + ui_evidence_image_name->setReadOnly(true); + ui_evidence_image_name->setToolTip("Double-click to edit..."); - ui_evidence_overlay->show(); - ui_evidence_ok->hide(); + ui_evidence_overlay->show(); + ui_evidence_ok->hide(); - ui_ic_chat_message->setFocus(); + ui_ic_chat_message->setFocus(); } void Courtroom::on_evidence_hover(int p_id, bool p_state) { - ui_evidence_name->setReadOnly(true); - int final_id = p_id + max_evidence_on_page * current_evidence_page; + ui_evidence_name->setReadOnly(true); + int final_id = p_id + max_evidence_on_page * current_evidence_page; - if (p_state) { - if (final_id == local_evidence_list.size()) - ui_evidence_name->setText(tr("Add new evidence...")); - else if (final_id < local_evidence_list.size()) - ui_evidence_name->setText(local_evidence_list.at(final_id).name); - } - else if (current_evidence < local_evidence_list.size()) - ui_evidence_name->setText(local_evidence_list.at(current_evidence).name); - else - ui_evidence_name->setText(""); + if (p_state) { + if (final_id == local_evidence_list.size()) + ui_evidence_name->setText(tr("Add new evidence...")); + else if (final_id < local_evidence_list.size()) + ui_evidence_name->setText(local_evidence_list.at(final_id).name); + } + else if (current_evidence < local_evidence_list.size()) + ui_evidence_name->setText(local_evidence_list.at(current_evidence).name); + else + ui_evidence_name->setText(""); } void Courtroom::on_evidence_left_clicked() { - --current_evidence_page; + --current_evidence_page; - set_evidence_page(); + set_evidence_page(); - ui_ic_chat_message->setFocus(); + ui_ic_chat_message->setFocus(); } void Courtroom::on_evidence_right_clicked() { - ++current_evidence_page; + ++current_evidence_page; - set_evidence_page(); + set_evidence_page(); - ui_ic_chat_message->setFocus(); + ui_ic_chat_message->setFocus(); } void Courtroom::on_evidence_present_clicked() { - if (!current_evidence_global) { - ui_evidence_present->hide(); - is_presenting_evidence = false; - return; //otherwise we get force-disconnected - } - if (is_presenting_evidence) - ui_evidence_present->set_image("present"); - else - ui_evidence_present->set_image("present_disabled"); + if (!current_evidence_global) { + ui_evidence_present->hide(); + is_presenting_evidence = false; + return; // otherwise we get force-disconnected + } + if (is_presenting_evidence) + ui_evidence_present->set_image("present"); + else + ui_evidence_present->set_image("present_disabled"); - is_presenting_evidence = !is_presenting_evidence; + is_presenting_evidence = !is_presenting_evidence; - ui_ic_chat_message->setFocus(); + ui_ic_chat_message->setFocus(); } void Courtroom::on_evidence_delete_clicked() { - evidence_close(); - if (current_evidence_global) - ao_app->send_server_packet(new AOPacket("DE#" + QString::number(current_evidence) + "#%")); - else { - local_evidence_list.remove(current_evidence); - private_evidence_list = local_evidence_list; - set_evidence_page(); - } + evidence_close(); + if (current_evidence_global) + ao_app->send_server_packet( + new AOPacket("DE#" + QString::number(current_evidence) + "#%")); + else { + local_evidence_list.remove(current_evidence); + private_evidence_list = local_evidence_list; + set_evidence_page(); + } - current_evidence = 0; + current_evidence = 0; - ui_ic_chat_message->setFocus(); + ui_ic_chat_message->setFocus(); } void Courtroom::on_evidence_x_clicked() { - if (current_evidence >= local_evidence_list.size()) //Should never happen but you never know. - return; + if (current_evidence >= + local_evidence_list.size()) // Should never happen but you never know. + return; - evi_type fake_evidence; - fake_evidence.name = ui_evidence_name->text(); - fake_evidence.description = ui_evidence_description->toPlainText(); - fake_evidence.image = ui_evidence_image_name->text(); - if (!compare_evidence_changed(fake_evidence, local_evidence_list.at(current_evidence))) { - evidence_close(); - return; - } - QMessageBox *msgBox = new QMessageBox; - msgBox->setText("Evidence has been modified."); - msgBox->setInformativeText("Do you want to save your changes?"); - msgBox->setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); - msgBox->setDefaultButton(QMessageBox::Save); - int ret = msgBox->exec(); - switch (ret) { - case QMessageBox::Save: - evidence_close(); - on_evidence_ok_clicked(); - break; - case QMessageBox::Discard: - evidence_close(); - break; - case QMessageBox::Cancel: - // Cancel was clicked, do nothing - break; - default: - // should never be reached - break; - } + evi_type fake_evidence; + fake_evidence.name = ui_evidence_name->text(); + fake_evidence.description = ui_evidence_description->toPlainText(); + fake_evidence.image = ui_evidence_image_name->text(); + if (!compare_evidence_changed(fake_evidence, + local_evidence_list.at(current_evidence))) { + evidence_close(); + return; + } + QMessageBox *msgBox = new QMessageBox; + msgBox->setText("Evidence has been modified."); + msgBox->setInformativeText("Do you want to save your changes?"); + msgBox->setStandardButtons(QMessageBox::Save | QMessageBox::Discard | + QMessageBox::Cancel); + msgBox->setDefaultButton(QMessageBox::Save); + int ret = msgBox->exec(); + switch (ret) { + case QMessageBox::Save: + evidence_close(); + on_evidence_ok_clicked(); + break; + case QMessageBox::Discard: + evidence_close(); + break; + case QMessageBox::Cancel: + // Cancel was clicked, do nothing + break; + default: + // should never be reached + break; + } } void Courtroom::on_evidence_ok_clicked() { - ui_evidence_name->setReadOnly(true); - ui_evidence_description->setReadOnly(true); - ui_evidence_image_name->setReadOnly(true); - if (current_evidence < local_evidence_list.size()) { - evi_type f_evi = local_evidence_list.at(current_evidence); - if (current_evidence_global) { - QStringList f_contents; - f_contents.append(QString::number(current_evidence)); - f_contents.append(ui_evidence_name->text()); - f_contents.append(ui_evidence_description->toPlainText()); - f_contents.append(ui_evidence_image_name->text()); + ui_evidence_name->setReadOnly(true); + ui_evidence_description->setReadOnly(true); + ui_evidence_image_name->setReadOnly(true); + if (current_evidence < local_evidence_list.size()) { + evi_type f_evi = local_evidence_list.at(current_evidence); + if (current_evidence_global) { + QStringList f_contents; + f_contents.append(QString::number(current_evidence)); + f_contents.append(ui_evidence_name->text()); + f_contents.append(ui_evidence_description->toPlainText()); + f_contents.append(ui_evidence_image_name->text()); - ao_app->send_server_packet(new AOPacket("EE", f_contents)); - } - else { - f_evi.name = ui_evidence_name->text(); - f_evi.description = ui_evidence_description->toPlainText(); - f_evi.image = ui_evidence_image_name->text(); - local_evidence_list.replace(current_evidence, f_evi); - private_evidence_list = local_evidence_list; - ui_evidence_ok->hide(); - set_evidence_page(); - } + ao_app->send_server_packet(new AOPacket("EE", f_contents)); } + else { + f_evi.name = ui_evidence_name->text(); + f_evi.description = ui_evidence_description->toPlainText(); + f_evi.image = ui_evidence_image_name->text(); + local_evidence_list.replace(current_evidence, f_evi); + private_evidence_list = local_evidence_list; + ui_evidence_ok->hide(); + set_evidence_page(); + } + } } void Courtroom::on_evidence_switch_clicked() { - evidence_close(); - evidence_switch(!current_evidence_global); - if (current_evidence_global) { - ui_evidence_switch->set_image("evidence_global"); - ui_evidence->set_image("evidence_background"); - ui_evidence_overlay->set_image("evidence_overlay"); - ui_evidence_transfer->set_image("evidence_transfer"); - ui_evidence_transfer->setToolTip(tr("Transfer evidence to private inventory.")); - ui_evidence_switch->setToolTip(tr("Current evidence is global. Click to switch to private.")); - } - else { - ui_evidence_switch->set_image("evidence_private"); - ui_evidence->set_image("evidence_background_private"); - ui_evidence_overlay->set_image("evidence_overlay_private"); - ui_evidence_transfer->set_image("evidence_transfer_private"); - ui_evidence_transfer->setToolTip(tr("Transfer evidence to global inventory.")); - ui_evidence_switch->setToolTip(tr("Current evidence is private. Click to switch to global.")); - } + evidence_close(); + evidence_switch(!current_evidence_global); + if (current_evidence_global) { + ui_evidence_switch->set_image("evidence_global"); + ui_evidence->set_image("evidence_background"); + ui_evidence_overlay->set_image("evidence_overlay"); + ui_evidence_transfer->set_image("evidence_transfer"); + ui_evidence_transfer->setToolTip( + tr("Transfer evidence to private inventory.")); + ui_evidence_switch->setToolTip( + tr("Current evidence is global. Click to switch to private.")); + } + else { + ui_evidence_switch->set_image("evidence_private"); + ui_evidence->set_image("evidence_background_private"); + ui_evidence_overlay->set_image("evidence_overlay_private"); + ui_evidence_transfer->set_image("evidence_transfer_private"); + ui_evidence_transfer->setToolTip( + tr("Transfer evidence to global inventory.")); + ui_evidence_switch->setToolTip( + tr("Current evidence is private. Click to switch to global.")); + } } void Courtroom::on_evidence_transfer_clicked() { - if (current_evidence >= local_evidence_list.size()) - return; + if (current_evidence >= local_evidence_list.size()) + return; - QString name; - if (!current_evidence_global) //Transfer private evidence to global - { - evi_type f_evi = local_evidence_list.at(current_evidence); + QString name; + if (!current_evidence_global) // Transfer private evidence to global + { + evi_type f_evi = local_evidence_list.at(current_evidence); - QStringList f_contents; - f_contents.append(f_evi.name); - f_contents.append(f_evi.description); - f_contents.append(f_evi.image); + QStringList f_contents; + f_contents.append(f_evi.name); + f_contents.append(f_evi.description); + f_contents.append(f_evi.image); - name = f_evi.name; - ao_app->send_server_packet(new AOPacket("PE", f_contents)); - } - else //Transfer global evidence to private - { - evi_type f_evi = local_evidence_list.at(current_evidence); - name = f_evi.name; - private_evidence_list.append(f_evi); - } + name = f_evi.name; + ao_app->send_server_packet(new AOPacket("PE", f_contents)); + } + else // Transfer global evidence to private + { + evi_type f_evi = local_evidence_list.at(current_evidence); + name = f_evi.name; + private_evidence_list.append(f_evi); + } - QMessageBox *msgBox = new QMessageBox; - msgBox->setText("\"" + name + "\" has been transferred."); - msgBox->setStandardButtons(QMessageBox::Ok); - msgBox->setDefaultButton(QMessageBox::Ok); - msgBox->exec(); + QMessageBox *msgBox = new QMessageBox; + msgBox->setText("\"" + name + "\" has been transferred."); + msgBox->setStandardButtons(QMessageBox::Ok); + msgBox->setDefaultButton(QMessageBox::Ok); + msgBox->exec(); } void Courtroom::on_evidence_edited() { - if (current_evidence >= local_evidence_list.size()) //Should never happen but you never know. - return; - evi_type fake_evidence; - fake_evidence.name = ui_evidence_name->text(); - fake_evidence.description = ui_evidence_description->toPlainText(); - fake_evidence.image = ui_evidence_image_name->text(); - if (compare_evidence_changed(fake_evidence, local_evidence_list.at(current_evidence))) - ui_evidence_ok->show(); - else - ui_evidence_ok->hide(); + if (current_evidence >= + local_evidence_list.size()) // Should never happen but you never know. + return; + evi_type fake_evidence; + fake_evidence.name = ui_evidence_name->text(); + fake_evidence.description = ui_evidence_description->toPlainText(); + fake_evidence.image = ui_evidence_image_name->text(); + if (compare_evidence_changed(fake_evidence, + local_evidence_list.at(current_evidence))) + ui_evidence_ok->show(); + else + ui_evidence_ok->hide(); } void Courtroom::evidence_close() { - ui_evidence_description->setReadOnly(true); - ui_evidence_description->setToolTip(""); - ui_evidence_name->setReadOnly(true); - ui_evidence_name->setToolTip(""); - ui_evidence_image_name->setReadOnly(true); - ui_evidence_image_name->setToolTip(""); - ui_evidence_overlay->hide(); - ui_ic_chat_message->setFocus(); + ui_evidence_description->setReadOnly(true); + ui_evidence_description->setToolTip(""); + ui_evidence_name->setReadOnly(true); + ui_evidence_name->setToolTip(""); + ui_evidence_image_name->setReadOnly(true); + ui_evidence_image_name->setToolTip(""); + ui_evidence_overlay->hide(); + ui_ic_chat_message->setFocus(); } void Courtroom::evidence_switch(bool global) { - current_evidence_global = global; - is_presenting_evidence = false; - ui_evidence_present->set_image("present"); - local_evidence_list.clear(); - if (current_evidence_global) { - local_evidence_list = global_evidence_list; - ui_evidence_present->show(); - ui_evidence_save->hide(); - ui_evidence_load->hide(); - } - else { - local_evidence_list = private_evidence_list; - ui_evidence_present->hide(); - ui_evidence_save->show(); - ui_evidence_load->show(); - } - set_evidence_page(); + current_evidence_global = global; + is_presenting_evidence = false; + ui_evidence_present->set_image("present"); + local_evidence_list.clear(); + if (current_evidence_global) { + local_evidence_list = global_evidence_list; + ui_evidence_present->show(); + ui_evidence_save->hide(); + ui_evidence_load->hide(); + } + else { + local_evidence_list = private_evidence_list; + ui_evidence_present->hide(); + ui_evidence_save->show(); + ui_evidence_load->show(); + } + set_evidence_page(); } void Courtroom::on_evidence_save_clicked() { - if (current_evidence_global) - return; //Don't allow saving/loading operations when in global inventory mode for now + if (current_evidence_global) + return; // Don't allow saving/loading operations when in global inventory + // mode for now - QString p_path = QFileDialog::getSaveFileName(this, tr("Save Inventory"), "base/inventories/", tr("Ini Files (*.ini)")); - if (p_path.isEmpty()) - return; + QString p_path = QFileDialog::getSaveFileName( + this, tr("Save Inventory"), "base/inventories/", tr("Ini Files (*.ini)")); + if (p_path.isEmpty()) + return; - evidence_close(); - ui_evidence_name->setText(""); + evidence_close(); + ui_evidence_name->setText(""); - QSettings inventory(p_path, QSettings::IniFormat); - inventory.clear(); - for (int i = 0; i < local_evidence_list.size(); i++) { - inventory.beginGroup(QString::number(i)); - inventory.setValue("name", local_evidence_list[i].name); - inventory.setValue("description", local_evidence_list[i].description); - inventory.setValue("image", local_evidence_list[i].image); - inventory.endGroup(); - } - inventory.sync(); + QSettings inventory(p_path, QSettings::IniFormat); + inventory.clear(); + for (int i = 0; i < local_evidence_list.size(); i++) { + inventory.beginGroup(QString::number(i)); + inventory.setValue("name", local_evidence_list[i].name); + inventory.setValue("description", local_evidence_list[i].description); + inventory.setValue("image", local_evidence_list[i].image); + inventory.endGroup(); + } + inventory.sync(); } void Courtroom::on_evidence_load_clicked() { - if (current_evidence_global) - return; //Don't allow saving/loading operations when in global inventory mode for now + if (current_evidence_global) + return; // Don't allow saving/loading operations when in global inventory + // mode for now - QString p_path = QFileDialog::getOpenFileName(this, tr("Open Inventory"), "base/inventories/", tr("Ini Files (*.ini)")); - if (p_path.isEmpty()) - return; + QString p_path = QFileDialog::getOpenFileName( + this, tr("Open Inventory"), "base/inventories/", tr("Ini Files (*.ini)")); + if (p_path.isEmpty()) + return; - evidence_close(); - ui_evidence_name->setText(""); + evidence_close(); + ui_evidence_name->setText(""); - QSettings inventory(p_path, QSettings::IniFormat); - local_evidence_list.clear(); - foreach (QString evi, inventory.childGroups()) { - if (evi == "General") - continue; + QSettings inventory(p_path, QSettings::IniFormat); + local_evidence_list.clear(); + foreach (QString evi, inventory.childGroups()) { + if (evi == "General") + continue; - evi_type f_evi; - f_evi.name = inventory.value(evi + "/name", "UNKNOWN").value(); - f_evi.description = inventory.value(evi + "/description", "UNKNOWN").value(); - f_evi.image = inventory.value(evi + "/image", "UNKNOWN.png").value(); - local_evidence_list.append(f_evi); - } - private_evidence_list = local_evidence_list; - set_evidence_page(); + evi_type f_evi; + f_evi.name = inventory.value(evi + "/name", "UNKNOWN").value(); + f_evi.description = + inventory.value(evi + "/description", "UNKNOWN").value(); + f_evi.image = + inventory.value(evi + "/image", "UNKNOWN.png").value(); + local_evidence_list.append(f_evi); + } + private_evidence_list = local_evidence_list; + set_evidence_page(); } bool Courtroom::compare_evidence_changed(evi_type evi_a, evi_type evi_b) { - return evi_a.name != evi_b.name || evi_a.image != evi_b.image || evi_a.description != evi_b.description; + return evi_a.name != evi_b.name || evi_a.image != evi_b.image || + evi_a.description != evi_b.description; } diff --git a/src/file_functions.cpp b/src/file_functions.cpp index e2b2882..e64a46b 100644 --- a/src/file_functions.cpp +++ b/src/file_functions.cpp @@ -2,21 +2,21 @@ bool file_exists(QString file_path) { - QFileInfo check_file(file_path); + QFileInfo check_file(file_path); - return check_file.exists() && check_file.isFile(); + return check_file.exists() && check_file.isFile(); } bool dir_exists(QString dir_path) { - QDir check_dir(dir_path); + QDir check_dir(dir_path); - return check_dir.exists(); + return check_dir.exists(); } bool exists(QString p_path) { - QFile file(p_path); + QFile file(p_path); - return file.exists(); + return file.exists(); } diff --git a/src/hardware_functions.cpp b/src/hardware_functions.cpp index 21d72ec..96c72eb 100644 --- a/src/hardware_functions.cpp +++ b/src/hardware_functions.cpp @@ -10,14 +10,15 @@ static BOOL bIsRetrieved; QString get_hdid() { - bIsRetrieved = GetVolumeInformation(TEXT("C:\\"), nullptr, 0, &dwVolSerial, nullptr, nullptr, nullptr, 0); + bIsRetrieved = GetVolumeInformation(TEXT("C:\\"), nullptr, 0, &dwVolSerial, + nullptr, nullptr, nullptr, 0); - if (bIsRetrieved) - return QString::number(dwVolSerial, 16); - else - //a totally random string - //what could possibly go wrong - return "gxsps32sa9fnwic92mfbs0"; + if (bIsRetrieved) + return QString::number(dwVolSerial, 16); + else + // a totally random string + // what could possibly go wrong + return "gxsps32sa9fnwic92mfbs0"; } #elif (defined(LINUX) || defined(__linux__)) @@ -27,24 +28,24 @@ QString get_hdid() QString get_hdid() { - QFile fstab_file("/etc/fstab"); - if (!fstab_file.open(QIODevice::ReadOnly)) - return "gxcps32sa9fnwic92mfbs0"; + QFile fstab_file("/etc/fstab"); + if (!fstab_file.open(QIODevice::ReadOnly)) + return "gxcps32sa9fnwic92mfbs0"; - QTextStream in(&fstab_file); + QTextStream in(&fstab_file); - while (!in.atEnd()) { - QString line = in.readLine(); + while (!in.atEnd()) { + QString line = in.readLine(); - if (line.startsWith("UUID")) { - QStringList line_elements = line.split("="); + if (line.startsWith("UUID")) { + QStringList line_elements = line.split("="); - if (line_elements.size() > 1) - return line_elements.at(1).left(23).trimmed(); - } + if (line_elements.size() > 1) + return line_elements.at(1).left(23).trimmed(); } + } - return "gxcpz32sa9fnwic92mfbs0"; + return "gxcpz32sa9fnwic92mfbs0"; } #elif defined __APPLE__ @@ -53,25 +54,25 @@ QString get_hdid() QString get_hdid() { - CFStringRef serial; - char buffer[64] = {0}; - QString hdid; - io_service_t platformExpert = IOServiceGetMatchingService(kIOMasterPortDefault, - IOServiceMatching("IOPlatformExpertDevice")); - if (platformExpert) { - CFTypeRef serialNumberAsCFString = IORegistryEntryCreateCFProperty(platformExpert, - CFSTR(kIOPlatformSerialNumberKey), - kCFAllocatorDefault, 0); - if (serialNumberAsCFString) { - serial = (CFStringRef)serialNumberAsCFString; - } - if (CFStringGetCString(serial, buffer, 64, kCFStringEncodingUTF8)) { - hdid = buffer; - } - - IOObjectRelease(platformExpert); + CFStringRef serial; + char buffer[64] = {0}; + QString hdid; + io_service_t platformExpert = IOServiceGetMatchingService( + kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice")); + if (platformExpert) { + CFTypeRef serialNumberAsCFString = IORegistryEntryCreateCFProperty( + platformExpert, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, + 0); + if (serialNumberAsCFString) { + serial = (CFStringRef)serialNumberAsCFString; } - return hdid; + if (CFStringGetCString(serial, buffer, 64, kCFStringEncodingUTF8)) { + hdid = buffer; + } + + IOObjectRelease(platformExpert); + } + return hdid; } #else diff --git a/src/hex_functions.cpp b/src/hex_functions.cpp index 63293c1..1e35718 100644 --- a/src/hex_functions.cpp +++ b/src/hex_functions.cpp @@ -1,17 +1,17 @@ #include "hex_functions.h" namespace omni { - std::string int_to_hex(unsigned int input) - { - if (input > 255) - return "FF"; +std::string int_to_hex(unsigned int input) +{ + if (input > 255) + return "FF"; - std::stringstream stream; - stream << std::setfill('0') << std::setw(sizeof(char) * 2) - << std::hex << input; - std::string result(stream.str()); - std::transform(result.begin(), result.end(), result.begin(), ::toupper); + std::stringstream stream; + stream << std::setfill('0') << std::setw(sizeof(char) * 2) << std::hex + << input; + std::string result(stream.str()); + std::transform(result.begin(), result.end(), result.begin(), ::toupper); - return result; - } + return result; +} } // namespace omni diff --git a/src/lobby.cpp b/src/lobby.cpp index 30a8ed0..99172a9 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -7,515 +7,523 @@ Lobby::Lobby(AOApplication *p_ao_app) : QMainWindow() { - ao_app = p_ao_app; + ao_app = p_ao_app; - this->setWindowTitle(tr("Attorney Online 2")); - this->setWindowIcon(QIcon(":/logo.png")); + this->setWindowTitle(tr("Attorney Online 2")); + this->setWindowIcon(QIcon(":/logo.png")); - ui_background = new AOImage(this, ao_app); - ui_public_servers = new AOButton(this, ao_app); - ui_favorites = new AOButton(this, ao_app); - ui_refresh = new AOButton(this, ao_app); - ui_add_to_fav = new AOButton(this, ao_app); - ui_connect = new AOButton(this, ao_app); - ui_version = new QLabel(this); - ui_about = new AOButton(this, ao_app); - ui_settings = new AOButton(this, ao_app); + ui_background = new AOImage(this, ao_app); + ui_public_servers = new AOButton(this, ao_app); + ui_favorites = new AOButton(this, ao_app); + ui_refresh = new AOButton(this, ao_app); + ui_add_to_fav = new AOButton(this, ao_app); + ui_connect = new AOButton(this, ao_app); + ui_version = new QLabel(this); + ui_about = new AOButton(this, ao_app); + ui_settings = new AOButton(this, ao_app); - ui_server_list = new QTreeWidget(this); - ui_server_list->setHeaderLabels({"#", "Name"}); //, "Players"}); - ui_server_list->hideColumn(0); + ui_server_list = new QTreeWidget(this); + ui_server_list->setHeaderLabels({"#", "Name"}); //, "Players"}); + ui_server_list->hideColumn(0); - ui_server_search = new QLineEdit(this); - ui_server_search->setFrame(false); - ui_server_search->setPlaceholderText(tr("Search")); + ui_server_search = new QLineEdit(this); + ui_server_search->setFrame(false); + ui_server_search->setPlaceholderText(tr("Search")); - ui_player_count = new QLabel(this); - ui_description = new AOTextArea(this); - ui_description->setOpenExternalLinks(true); - ui_chatbox = new AOTextArea(this); - ui_chatbox->setOpenExternalLinks(true); - ui_chatname = new QLineEdit(this); - ui_chatname->setPlaceholderText(tr("Name")); - ui_chatname->setText(ao_app->get_ooc_name()); - ui_chatmessage = new QLineEdit(this); - ui_loading_background = new AOImage(this, ao_app); - ui_loading_text = new QTextEdit(ui_loading_background); - ui_progress_bar = new QProgressBar(ui_loading_background); - ui_progress_bar->setMinimum(0); - ui_progress_bar->setMaximum(100); - ui_progress_bar->setStyleSheet("QProgressBar{ color: white; }"); - ui_cancel = new AOButton(ui_loading_background, ao_app); + ui_player_count = new QLabel(this); + ui_description = new AOTextArea(this); + ui_description->setOpenExternalLinks(true); + ui_chatbox = new AOTextArea(this); + ui_chatbox->setOpenExternalLinks(true); + ui_chatname = new QLineEdit(this); + ui_chatname->setPlaceholderText(tr("Name")); + ui_chatname->setText(ao_app->get_ooc_name()); + ui_chatmessage = new QLineEdit(this); + ui_loading_background = new AOImage(this, ao_app); + ui_loading_text = new QTextEdit(ui_loading_background); + ui_progress_bar = new QProgressBar(ui_loading_background); + ui_progress_bar->setMinimum(0); + ui_progress_bar->setMaximum(100); + ui_progress_bar->setStyleSheet("QProgressBar{ color: white; }"); + ui_cancel = new AOButton(ui_loading_background, ao_app); - connect(ui_public_servers, SIGNAL(clicked()), this, SLOT(on_public_servers_clicked())); - connect(ui_favorites, SIGNAL(clicked()), this, SLOT(on_favorites_clicked())); - connect(ui_refresh, SIGNAL(pressed()), this, SLOT(on_refresh_pressed())); - connect(ui_refresh, SIGNAL(released()), this, SLOT(on_refresh_released())); - connect(ui_add_to_fav, SIGNAL(pressed()), this, SLOT(on_add_to_fav_pressed())); - connect(ui_add_to_fav, SIGNAL(released()), this, SLOT(on_add_to_fav_released())); - connect(ui_connect, SIGNAL(pressed()), this, SLOT(on_connect_pressed())); - connect(ui_connect, SIGNAL(released()), this, SLOT(on_connect_released())); - connect(ui_about, SIGNAL(clicked()), this, SLOT(on_about_clicked())); - connect(ui_settings, SIGNAL(clicked()), this, SLOT(on_settings_clicked())); - connect(ui_server_list, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, SLOT(on_server_list_clicked(QTreeWidgetItem *, int))); - connect(ui_server_list, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), this, SLOT(on_server_list_doubleclicked(QTreeWidgetItem *, int))); - connect(ui_server_search, SIGNAL(textChanged(QString)), this, SLOT(on_server_search_edited(QString))); - connect(ui_chatmessage, SIGNAL(returnPressed()), this, SLOT(on_chatfield_return_pressed())); - connect(ui_cancel, SIGNAL(clicked()), ao_app, SLOT(loading_cancelled())); + connect(ui_public_servers, SIGNAL(clicked()), this, + SLOT(on_public_servers_clicked())); + connect(ui_favorites, SIGNAL(clicked()), this, SLOT(on_favorites_clicked())); + connect(ui_refresh, SIGNAL(pressed()), this, SLOT(on_refresh_pressed())); + connect(ui_refresh, SIGNAL(released()), this, SLOT(on_refresh_released())); + connect(ui_add_to_fav, SIGNAL(pressed()), this, + SLOT(on_add_to_fav_pressed())); + connect(ui_add_to_fav, SIGNAL(released()), this, + SLOT(on_add_to_fav_released())); + connect(ui_connect, SIGNAL(pressed()), this, SLOT(on_connect_pressed())); + connect(ui_connect, SIGNAL(released()), this, SLOT(on_connect_released())); + connect(ui_about, SIGNAL(clicked()), this, SLOT(on_about_clicked())); + connect(ui_settings, SIGNAL(clicked()), this, SLOT(on_settings_clicked())); + connect(ui_server_list, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, + SLOT(on_server_list_clicked(QTreeWidgetItem *, int))); + connect(ui_server_list, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), + this, SLOT(on_server_list_doubleclicked(QTreeWidgetItem *, int))); + connect(ui_server_search, SIGNAL(textChanged(QString)), this, + SLOT(on_server_search_edited(QString))); + connect(ui_chatmessage, SIGNAL(returnPressed()), this, + SLOT(on_chatfield_return_pressed())); + connect(ui_cancel, SIGNAL(clicked()), ao_app, SLOT(loading_cancelled())); - ui_connect->setEnabled(false); + ui_connect->setEnabled(false); - list_servers(); + list_servers(); - set_widgets(); + set_widgets(); } -//sets images, position and size +// sets images, position and size void Lobby::set_widgets() { - ao_app->reload_theme(); + ao_app->reload_theme(); - QString filename = "lobby_design.ini"; + QString filename = "lobby_design.ini"; - pos_size_type f_lobby = ao_app->get_element_dimensions("lobby", filename); + pos_size_type f_lobby = ao_app->get_element_dimensions("lobby", filename); - if (f_lobby.width < 0 || f_lobby.height < 0) { - qDebug() << "W: did not find lobby width or height in " << filename; + if (f_lobby.width < 0 || f_lobby.height < 0) { + qDebug() << "W: did not find lobby width or height in " << filename; - // Most common symptom of bad config files and missing assets. - call_notice(tr("It doesn't look like your client is set up correctly.\n" - "Did you download all resources correctly from tiny.cc/getao, " - "including the large 'base' folder?")); + // Most common symptom of bad config files and missing assets. + call_notice( + tr("It doesn't look like your client is set up correctly.\n" + "Did you download all resources correctly from tiny.cc/getao, " + "including the large 'base' folder?")); - this->resize(517, 666); - } - else { - this->resize(f_lobby.width, f_lobby.height); - } + this->resize(517, 666); + } + else { + this->resize(f_lobby.width, f_lobby.height); + } - set_size_and_pos(ui_background, "lobby"); - ui_background->set_image("lobbybackground"); + set_size_and_pos(ui_background, "lobby"); + ui_background->set_image("lobbybackground"); - set_size_and_pos(ui_public_servers, "public_servers"); - ui_public_servers->set_image("publicservers_selected"); + set_size_and_pos(ui_public_servers, "public_servers"); + ui_public_servers->set_image("publicservers_selected"); - set_size_and_pos(ui_favorites, "favorites"); - ui_favorites->set_image("favorites"); + set_size_and_pos(ui_favorites, "favorites"); + ui_favorites->set_image("favorites"); - set_size_and_pos(ui_refresh, "refresh"); - ui_refresh->set_image("refresh"); + set_size_and_pos(ui_refresh, "refresh"); + ui_refresh->set_image("refresh"); - set_size_and_pos(ui_add_to_fav, "add_to_fav"); - ui_add_to_fav->set_image("addtofav"); + set_size_and_pos(ui_add_to_fav, "add_to_fav"); + ui_add_to_fav->set_image("addtofav"); - set_size_and_pos(ui_connect, "connect"); - ui_connect->set_image("connect"); + set_size_and_pos(ui_connect, "connect"); + ui_connect->set_image("connect"); - set_size_and_pos(ui_version, "version"); - ui_version->setText(tr("Version: KFO%1").arg(ao_app->get_version_string())); + set_size_and_pos(ui_version, "version"); + ui_version->setText(tr("Version: KFO%1").arg(ao_app->get_version_string())); - set_size_and_pos(ui_about, "about"); - ui_about->set_image("about"); + set_size_and_pos(ui_about, "about"); + ui_about->set_image("about"); - set_size_and_pos(ui_settings, "settings"); - ui_settings->setText(tr("Settings")); - ui_settings->set_image("settings"); - ui_settings->setToolTip(tr("Allows you to change various aspects of the client.")); + set_size_and_pos(ui_settings, "settings"); + ui_settings->setText(tr("Settings")); + ui_settings->set_image("settings"); + ui_settings->setToolTip( + tr("Allows you to change various aspects of the client.")); - set_size_and_pos(ui_server_list, "server_list"); - ui_server_list->setStyleSheet("background-color: rgba(0, 0, 0, 0);" - "font: bold;"); + set_size_and_pos(ui_server_list, "server_list"); + ui_server_list->setStyleSheet("background-color: rgba(0, 0, 0, 0);" + "font: bold;"); - set_size_and_pos(ui_server_search, "server_search"); - ui_server_search->setStyleSheet("background-color: rgba(0, 0, 0, 0);"); + set_size_and_pos(ui_server_search, "server_search"); + ui_server_search->setStyleSheet("background-color: rgba(0, 0, 0, 0);"); - set_size_and_pos(ui_player_count, "player_count"); - ui_player_count->setText(tr("Offline")); - ui_player_count->setStyleSheet("font: bold;" - "color: white;" - "qproperty-alignment: AlignCenter;"); + set_size_and_pos(ui_player_count, "player_count"); + ui_player_count->setText(tr("Offline")); + ui_player_count->setStyleSheet("font: bold;" + "color: white;" + "qproperty-alignment: AlignCenter;"); - set_size_and_pos(ui_description, "description"); - ui_description->setReadOnly(true); - ui_description->setStyleSheet("background-color: rgba(0, 0, 0, 0);" - "color: white;"); + set_size_and_pos(ui_description, "description"); + ui_description->setReadOnly(true); + ui_description->setStyleSheet("background-color: rgba(0, 0, 0, 0);" + "color: white;"); - set_size_and_pos(ui_chatbox, "chatbox"); - ui_chatbox->setReadOnly(true); - ui_chatbox->setStyleSheet("QTextBrowser{background-color: rgba(0, 0, 0, 0);}"); + set_size_and_pos(ui_chatbox, "chatbox"); + ui_chatbox->setReadOnly(true); + ui_chatbox->setStyleSheet( + "QTextBrowser{background-color: rgba(0, 0, 0, 0);}"); - set_size_and_pos(ui_chatname, "chatname"); - ui_chatname->setStyleSheet("background-color: rgba(0, 0, 0, 0);" - "selection-background-color: rgba(0, 0, 0, 0);"); + set_size_and_pos(ui_chatname, "chatname"); + ui_chatname->setStyleSheet("background-color: rgba(0, 0, 0, 0);" + "selection-background-color: rgba(0, 0, 0, 0);"); - set_size_and_pos(ui_chatmessage, "chatmessage"); - ui_chatmessage->setStyleSheet("background-color: rgba(0, 0, 0, 0);" - "selection-background-color: rgba(0, 0, 0, 0);"); + set_size_and_pos(ui_chatmessage, "chatmessage"); + ui_chatmessage->setStyleSheet( + "background-color: rgba(0, 0, 0, 0);" + "selection-background-color: rgba(0, 0, 0, 0);"); - ui_loading_background->resize(this->width(), this->height()); - ui_loading_background->set_image("loadingbackground"); + ui_loading_background->resize(this->width(), this->height()); + ui_loading_background->set_image("loadingbackground"); - set_size_and_pos(ui_loading_text, "loading_label"); - ui_loading_text->setFont(QFont("Arial", 20, QFont::Bold)); - ui_loading_text->setReadOnly(true); - ui_loading_text->setAlignment(Qt::AlignCenter); - ui_loading_text->setFrameStyle(QFrame::NoFrame); - ui_loading_text->setStyleSheet("background-color: rgba(0, 0, 0, 0);" - "color: rgba(255, 128, 0, 255);"); - ui_loading_text->append(tr("Loading")); + set_size_and_pos(ui_loading_text, "loading_label"); + ui_loading_text->setFont(QFont("Arial", 20, QFont::Bold)); + ui_loading_text->setReadOnly(true); + ui_loading_text->setAlignment(Qt::AlignCenter); + ui_loading_text->setFrameStyle(QFrame::NoFrame); + ui_loading_text->setStyleSheet("background-color: rgba(0, 0, 0, 0);" + "color: rgba(255, 128, 0, 255);"); + ui_loading_text->append(tr("Loading")); - set_size_and_pos(ui_progress_bar, "progress_bar"); - set_size_and_pos(ui_cancel, "cancel"); - ui_cancel->setText(tr("Cancel")); + set_size_and_pos(ui_progress_bar, "progress_bar"); + set_size_and_pos(ui_cancel, "cancel"); + ui_cancel->setText(tr("Cancel")); - ui_loading_background->hide(); + ui_loading_background->hide(); - set_fonts(); - set_stylesheets(); + set_fonts(); + set_stylesheets(); } void Lobby::set_size_and_pos(QWidget *p_widget, QString p_identifier) { - QString filename = "lobby_design.ini"; + QString filename = "lobby_design.ini"; - pos_size_type design_ini_result = ao_app->get_element_dimensions(p_identifier, filename); + pos_size_type design_ini_result = + ao_app->get_element_dimensions(p_identifier, filename); - if (design_ini_result.width < 0 || design_ini_result.height < 0) { - qDebug() << "W: could not find " << p_identifier << " in " << filename; - p_widget->hide(); - } - else { - p_widget->move(design_ini_result.x, design_ini_result.y); - p_widget->resize(design_ini_result.width, design_ini_result.height); - } + if (design_ini_result.width < 0 || design_ini_result.height < 0) { + qDebug() << "W: could not find " << p_identifier << " in " << filename; + p_widget->hide(); + } + else { + p_widget->move(design_ini_result.x, design_ini_result.y); + p_widget->resize(design_ini_result.width, design_ini_result.height); + } } void Lobby::set_fonts() { - set_font(ui_player_count, "player_count"); - set_font(ui_description, "description"); - set_font(ui_chatbox, "chatbox"); - set_font(ui_chatname, "chatname"); - set_font(ui_chatmessage, "chatmessage"); - set_font(ui_loading_text, "loading_text"); - set_font(ui_server_list, "server_list"); + set_font(ui_player_count, "player_count"); + set_font(ui_description, "description"); + set_font(ui_chatbox, "chatbox"); + set_font(ui_chatname, "chatname"); + set_font(ui_chatmessage, "chatmessage"); + set_font(ui_loading_text, "loading_text"); + set_font(ui_server_list, "server_list"); } void Lobby::set_stylesheet(QWidget *widget, QString target_tag) { - QString f_file = "lobby_stylesheets.css"; - QString style_sheet_string = ao_app->get_tagged_stylesheet(target_tag, f_file); - if (style_sheet_string != "") - widget->setStyleSheet(style_sheet_string); + QString f_file = "lobby_stylesheets.css"; + QString style_sheet_string = + ao_app->get_tagged_stylesheet(target_tag, f_file); + if (style_sheet_string != "") + widget->setStyleSheet(style_sheet_string); } void Lobby::set_stylesheets() { - set_stylesheet(ui_player_count, "[PLAYER COUNT]"); - set_stylesheet(ui_description, "[DESCRIPTION]"); - set_stylesheet(ui_chatbox, "[CHAT BOX]"); - set_stylesheet(ui_chatname, "[CHAT NAME]"); - set_stylesheet(ui_chatmessage, "[CHAT MESSAGE]"); - set_stylesheet(ui_loading_text, "[LOADING TEXT]"); - set_stylesheet(ui_server_list, "[SERVER LIST]"); + set_stylesheet(ui_player_count, "[PLAYER COUNT]"); + set_stylesheet(ui_description, "[DESCRIPTION]"); + set_stylesheet(ui_chatbox, "[CHAT BOX]"); + set_stylesheet(ui_chatname, "[CHAT NAME]"); + set_stylesheet(ui_chatmessage, "[CHAT MESSAGE]"); + set_stylesheet(ui_loading_text, "[LOADING TEXT]"); + set_stylesheet(ui_server_list, "[SERVER LIST]"); } void Lobby::set_font(QWidget *widget, QString p_identifier) { - QString design_file = "lobby_fonts.ini"; - 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("font_" + p_identifier, design_file); - QFont font(font_name, f_weight); - bool use = ao_app->get_font_size("use_custom_fonts", design_file) == 1; - if (use) { - widget->setFont(font); - QColor f_color = ao_app->get_color(p_identifier + "_color", design_file); - bool bold = ao_app->get_font_size(p_identifier + "_bold", design_file) == 1; // is the font bold or not? - bool center = ao_app->get_font_size(p_identifier + "_center", design_file) == 1; // should it be centered? - QString is_bold = ""; - if (bold) - is_bold = "bold"; - QString is_center = ""; - if (center) - is_center = "qproperty-alignment: AlignCenter;"; - QString style_sheet_string = class_name + " { background-color: rgba(0, 0, 0, 0);\n" + - "color: rgba(" + - QString::number(f_color.red()) + ", " + - QString::number(f_color.green()) + ", " + - QString::number(f_color.blue()) + ", 255);\n" + - is_center + "\n" + - "font: " + is_bold + "; }"; - widget->setStyleSheet(style_sheet_string); - } - return; + QString design_file = "lobby_fonts.ini"; + 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("font_" + p_identifier, design_file); + QFont font(font_name, f_weight); + bool use = ao_app->get_font_size("use_custom_fonts", design_file) == 1; + if (use) { + widget->setFont(font); + QColor f_color = ao_app->get_color(p_identifier + "_color", design_file); + bool bold = ao_app->get_font_size(p_identifier + "_bold", design_file) == + 1; // is the font bold or not? + bool center = + ao_app->get_font_size(p_identifier + "_center", design_file) == + 1; // should it be centered? + QString is_bold = ""; + if (bold) + is_bold = "bold"; + QString is_center = ""; + if (center) + is_center = "qproperty-alignment: AlignCenter;"; + QString style_sheet_string = + class_name + " { background-color: rgba(0, 0, 0, 0);\n" + + "color: rgba(" + QString::number(f_color.red()) + ", " + + QString::number(f_color.green()) + ", " + + QString::number(f_color.blue()) + ", 255);\n" + is_center + "\n" + + "font: " + is_bold + "; }"; + widget->setStyleSheet(style_sheet_string); + } + return; } void Lobby::set_loading_text(QString p_text) { - ui_loading_text->clear(); - ui_loading_text->setAlignment(Qt::AlignCenter); - ui_loading_text->append(p_text); + ui_loading_text->clear(); + ui_loading_text->setAlignment(Qt::AlignCenter); + ui_loading_text->append(p_text); } QString Lobby::get_chatlog() { - QString return_value = ui_chatbox->toPlainText(); + QString return_value = ui_chatbox->toPlainText(); - return return_value; + return return_value; } int Lobby::get_selected_server() { - return ui_server_list->currentItem()->text(0).toInt(); + return ui_server_list->currentItem()->text(0).toInt(); } void Lobby::set_loading_value(int p_value) { - ui_progress_bar->setValue(p_value); + ui_progress_bar->setValue(p_value); } void Lobby::on_public_servers_clicked() { - ui_public_servers->set_image("publicservers_selected"); - ui_favorites->set_image("favorites"); + ui_public_servers->set_image("publicservers_selected"); + ui_favorites->set_image("favorites"); - list_servers(); + list_servers(); - public_servers_selected = true; + public_servers_selected = true; } void Lobby::on_favorites_clicked() { - ui_favorites->set_image("favorites_selected"); - ui_public_servers->set_image("publicservers"); + ui_favorites->set_image("favorites_selected"); + ui_public_servers->set_image("publicservers"); - ao_app->set_favorite_list(); - //ao_app->favorite_list = read_serverlist_txt(); + ao_app->set_favorite_list(); + // ao_app->favorite_list = read_serverlist_txt(); - list_favorites(); + list_favorites(); - public_servers_selected = false; + public_servers_selected = false; } -void Lobby::on_refresh_pressed() -{ - ui_refresh->set_image("refresh_pressed"); -} +void Lobby::on_refresh_pressed() { ui_refresh->set_image("refresh_pressed"); } void Lobby::on_refresh_released() { - ui_refresh->set_image("refresh"); + ui_refresh->set_image("refresh"); - AOPacket *f_packet = new AOPacket("ALL#%"); + AOPacket *f_packet = new AOPacket("ALL#%"); - ao_app->send_ms_packet(f_packet); + ao_app->send_ms_packet(f_packet); } void Lobby::on_add_to_fav_pressed() { - ui_add_to_fav->set_image("addtofav_pressed"); + ui_add_to_fav->set_image("addtofav_pressed"); } void Lobby::on_add_to_fav_released() { - ui_add_to_fav->set_image("addtofav"); + ui_add_to_fav->set_image("addtofav"); - //you cant add favorites from favorites m8 - if (!public_servers_selected) - return; + // you cant add favorites from favorites m8 + if (!public_servers_selected) + return; - ao_app->add_favorite_server(get_selected_server()); + ao_app->add_favorite_server(get_selected_server()); } -void Lobby::on_connect_pressed() -{ - ui_connect->set_image("connect_pressed"); -} +void Lobby::on_connect_pressed() { ui_connect->set_image("connect_pressed"); } void Lobby::on_connect_released() { - ui_connect->set_image("connect"); + ui_connect->set_image("connect"); - AOPacket *f_packet; + AOPacket *f_packet; - f_packet = new AOPacket("askchaa#%"); + f_packet = new AOPacket("askchaa#%"); - ao_app->send_server_packet(f_packet); + ao_app->send_server_packet(f_packet); } void Lobby::on_about_clicked() { - QString msg = tr("

Attorney Online %1

" - "The courtroom drama simulator" - "

Source code: " - "" - "https://github.com/AttorneyOnline/AO2-Client" - "

Major development:
" - "OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter" - "

2.8 Major Release development:
" - "Crystalwarrior, Iamgoofball" - "

2.8 Quality Assurance:
" - "WillDean, Captain N, Mr M, Riel, Seimmet, Fury McFlurry," - "CedricDewitt, Chewable Tablets, Fantos, Futugaze," - "Geck, Minx, Pandae, Sierra, CrazyJC, CaseyMayCazy," - "GreenBowers, Robotic Overlord, Veritas, Gin-Gi" - "

Special thanks:
" - "Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), " - "Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, " - "Noevain, Cronnicossy, the AO2 community, server hosts, game masters," - "case makers, content creators and players!") - .arg(ao_app->get_version_string()); - QMessageBox::about(this, "About", msg); + QString msg = + tr("

Attorney Online %1

" + "The courtroom drama simulator" + "

Source code: " + "" + "https://github.com/AttorneyOnline/AO2-Client" + "

Major development:
" + "OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter" + "

2.8 Major Release development:
" + "Crystalwarrior, Iamgoofball" + "

2.8 Quality Assurance:
" + "WillDean, Captain N, Mr M, Riel, Seimmet, Fury McFlurry," + "CedricDewitt, Chewable Tablets, Fantos, Futugaze," + "Geck, Minx, Pandae, Sierra, CrazyJC, CaseyMayCazy," + "GreenBowers, Robotic Overlord, Veritas, Gin-Gi" + "

Special thanks:
" + "Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), " + "Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, " + "Noevain, Cronnicossy, the AO2 community, server hosts, game masters," + "case makers, content creators and players!") + .arg(ao_app->get_version_string()); + QMessageBox::about(this, "About", msg); } -void Lobby::on_settings_clicked() -{ - ao_app->call_settings_menu(); -} +void Lobby::on_settings_clicked() { ao_app->call_settings_menu(); } -//clicked on an item in the serverlist +// clicked on an item in the serverlist void Lobby::on_server_list_clicked(QTreeWidgetItem *p_item, int column) { - column = 0; - if (p_item->text(column).toInt() != last_index) { - server_type f_server; - int n_server = p_item->text(column).toInt(); - last_index = n_server; + column = 0; + if (p_item->text(column).toInt() != last_index) { + server_type f_server; + int n_server = p_item->text(column).toInt(); + last_index = n_server; - if (n_server < 0) - return; + if (n_server < 0) + return; - if (public_servers_selected) { - QVector f_server_list = ao_app->get_server_list(); + if (public_servers_selected) { + QVector f_server_list = ao_app->get_server_list(); - if (n_server >= f_server_list.size()) - return; + if (n_server >= f_server_list.size()) + return; - f_server = f_server_list.at(n_server); - } - else { - if (n_server >= ao_app->get_favorite_list().size()) - return; - - f_server = ao_app->get_favorite_list().at(n_server); - } - - ui_description->clear(); - ui_description->append_linked(f_server.desc); - - ui_description->moveCursor(QTextCursor::Start); - ui_description->ensureCursorVisible(); - - ui_player_count->setText(tr("Offline")); - - ui_connect->setEnabled(false); - - ao_app->net_manager->connect_to_server(f_server); + f_server = f_server_list.at(n_server); } + else { + if (n_server >= ao_app->get_favorite_list().size()) + return; + + f_server = ao_app->get_favorite_list().at(n_server); + } + + ui_description->clear(); + ui_description->append_linked(f_server.desc); + + ui_description->moveCursor(QTextCursor::Start); + ui_description->ensureCursorVisible(); + + ui_player_count->setText(tr("Offline")); + + ui_connect->setEnabled(false); + + ao_app->net_manager->connect_to_server(f_server); + } } -//doubleclicked on an item in the serverlist so we'll connect right away +// doubleclicked on an item in the serverlist so we'll connect right away void Lobby::on_server_list_doubleclicked(QTreeWidgetItem *p_item, int column) { - on_server_list_clicked(p_item, column); - on_connect_released(); + on_server_list_clicked(p_item, column); + on_connect_released(); } void Lobby::on_server_search_edited(QString p_text) { - // Iterate through all QTreeWidgetItem items - QTreeWidgetItemIterator it(ui_server_list); - while (*it) { - (*it)->setHidden(p_text != ""); - ++it; - } + // Iterate through all QTreeWidgetItem items + QTreeWidgetItemIterator it(ui_server_list); + while (*it) { + (*it)->setHidden(p_text != ""); + ++it; + } - if (p_text != "") { - //Search in metadata - QList clist = ui_server_list->findItems(ui_server_search->text(), Qt::MatchContains | Qt::MatchRecursive, 1); - foreach (QTreeWidgetItem *item, clist) { - if (item->parent() != nullptr) //So the category shows up too - item->parent()->setHidden(false); - item->setHidden(false); - } + if (p_text != "") { + // Search in metadata + QList clist = ui_server_list->findItems( + ui_server_search->text(), Qt::MatchContains | Qt::MatchRecursive, 1); + foreach (QTreeWidgetItem *item, clist) { + if (item->parent() != nullptr) // So the category shows up too + item->parent()->setHidden(false); + item->setHidden(false); } + } } void Lobby::on_chatfield_return_pressed() { - //no you can't send empty messages - if (ui_chatname->text() == "" || ui_chatmessage->text() == "") - return; + // no you can't send empty messages + if (ui_chatname->text() == "" || ui_chatmessage->text() == "") + return; - QString f_header = "CT"; - QStringList f_contents{ui_chatname->text(), ui_chatmessage->text()}; + QString f_header = "CT"; + QStringList f_contents{ui_chatname->text(), ui_chatmessage->text()}; - AOPacket *f_packet = new AOPacket(f_header, f_contents); + AOPacket *f_packet = new AOPacket(f_header, f_contents); - ao_app->send_ms_packet(f_packet); + ao_app->send_ms_packet(f_packet); - ui_chatmessage->clear(); + ui_chatmessage->clear(); } void Lobby::list_servers() { - public_servers_selected = true; - ui_favorites->set_image("favorites"); - ui_public_servers->set_image("publicservers_selected"); + public_servers_selected = true; + ui_favorites->set_image("favorites"); + ui_public_servers->set_image("publicservers_selected"); - ui_server_list->setSortingEnabled(false); - ui_server_list->clear(); + ui_server_list->setSortingEnabled(false); + ui_server_list->clear(); - ui_server_search->setText(""); + ui_server_search->setText(""); - int i = 0; - for (server_type i_server : ao_app->get_server_list()) { - QTreeWidgetItem *treeItem = new QTreeWidgetItem(ui_server_list); - treeItem->setText(0, QString::number(i)); - treeItem->setText(1, i_server.name); - i++; - } - ui_server_list->setSortingEnabled(true); + int i = 0; + for (server_type i_server : ao_app->get_server_list()) { + QTreeWidgetItem *treeItem = new QTreeWidgetItem(ui_server_list); + treeItem->setText(0, QString::number(i)); + treeItem->setText(1, i_server.name); + i++; + } + ui_server_list->setSortingEnabled(true); } void Lobby::list_favorites() { - ui_server_list->setSortingEnabled(false); - ui_server_list->clear(); + ui_server_list->setSortingEnabled(false); + ui_server_list->clear(); - int i = 0; - for (server_type i_server : ao_app->get_favorite_list()) { - QTreeWidgetItem *treeItem = new QTreeWidgetItem(ui_server_list); - treeItem->setText(0, QString::number(i)); - treeItem->setText(1, i_server.name); - // treeItem->setText(2, "-"); - i++; - } - ui_server_list->setSortingEnabled(true); + int i = 0; + for (server_type i_server : ao_app->get_favorite_list()) { + QTreeWidgetItem *treeItem = new QTreeWidgetItem(ui_server_list); + treeItem->setText(0, QString::number(i)); + treeItem->setText(1, i_server.name); + // treeItem->setText(2, "-"); + i++; + } + ui_server_list->setSortingEnabled(true); } void Lobby::append_chatmessage(QString f_name, QString f_message) { - ui_chatbox->append_chatmessage(f_name, f_message, ao_app->get_color("ooc_default_color", "courtroom_design.ini").name()); + ui_chatbox->append_chatmessage( + f_name, f_message, + ao_app->get_color("ooc_default_color", "courtroom_design.ini").name()); } void Lobby::append_error(QString f_message) { - ui_chatbox->append_error(f_message); + ui_chatbox->append_error(f_message); } void Lobby::set_player_count(int players_online, int max_players) { - QString f_string = tr("Online: %1/%2").arg(QString::number(players_online)).arg(QString::number(max_players)); - ui_player_count->setText(f_string); + QString f_string = tr("Online: %1/%2") + .arg(QString::number(players_online)) + .arg(QString::number(max_players)); + ui_player_count->setText(f_string); } -void Lobby::enable_connect_button() -{ - ui_connect->setEnabled(true); -} +void Lobby::enable_connect_button() { ui_connect->setEnabled(true); } -Lobby::~Lobby() -{ -} +Lobby::~Lobby() {} diff --git a/src/main.cpp b/src/main.cpp index 9370bce..ba5b516 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -12,40 +12,41 @@ int main(int argc, char *argv[]) { #if QT_VERSION > QT_VERSION_CHECK(5, 6, 0) - // High-DPI support is for Qt version >=5.6. - // However, many Linux distros still haven't brought their stable/LTS - // packages up to Qt 5.6, so this is conditional. - AOApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + // High-DPI support is for Qt version >=5.6. + // However, many Linux distros still haven't brought their stable/LTS + // packages up to Qt 5.6, so this is conditional. + AOApplication::setAttribute(Qt::AA_EnableHighDpiScaling); #endif - AOApplication main_app(argc, argv); + AOApplication main_app(argc, argv); - QSettings *configini = main_app.configini; + QSettings *configini = main_app.configini; - QPluginLoader apngPlugin("qapng"); - if (!apngPlugin.load()) - qCritical() << "QApng plugin could not be loaded"; + QPluginLoader apngPlugin("qapng"); + if (!apngPlugin.load()) + qCritical() << "QApng plugin could not be loaded"; - QPluginLoader webpPlugin("qwebp"); - if (!webpPlugin.load()) - qCritical() << "QWebp plugin could not be loaded"; + QPluginLoader webpPlugin("qwebp"); + if (!webpPlugin.load()) + qCritical() << "QWebp plugin could not be loaded"; - QString p_language = configini->value("language", QLocale::system().name()).toString(); - if (p_language == " " || p_language == "") - p_language = QLocale::system().name(); + QString p_language = + configini->value("language", QLocale::system().name()).toString(); + if (p_language == " " || p_language == "") + p_language = QLocale::system().name(); - QTranslator qtTranslator; - qtTranslator.load("qt_" + p_language, - QLibraryInfo::location(QLibraryInfo::TranslationsPath)); - main_app.installTranslator(&qtTranslator); + QTranslator qtTranslator; + qtTranslator.load("qt_" + p_language, + QLibraryInfo::location(QLibraryInfo::TranslationsPath)); + main_app.installTranslator(&qtTranslator); - QTranslator appTranslator; - qDebug() << ":/resource/translations/ao_" + p_language; - appTranslator.load("ao_" + p_language, ":/resource/translations/"); - main_app.installTranslator(&appTranslator); + QTranslator appTranslator; + qDebug() << ":/resource/translations/ao_" + p_language; + appTranslator.load("ao_" + p_language, ":/resource/translations/"); + main_app.installTranslator(&appTranslator); - main_app.construct_lobby(); - main_app.net_manager->connect_to_master(); - main_app.w_lobby->show(); - return main_app.exec(); + main_app.construct_lobby(); + main_app.net_manager->connect_to_master(); + main_app.w_lobby->show(); + return main_app.exec(); } diff --git a/src/misc_functions.cpp b/src/misc_functions.cpp index fa49ba4..cc14415 100644 --- a/src/misc_functions.cpp +++ b/src/misc_functions.cpp @@ -2,8 +2,8 @@ void delay(int p_milliseconds) { - QTime dieTime = QTime::currentTime().addMSecs(p_milliseconds); + QTime dieTime = QTime::currentTime().addMSecs(p_milliseconds); - while (QTime::currentTime() < dieTime) - QCoreApplication::processEvents(QEventLoop::AllEvents, 100); + while (QTime::currentTime() < dieTime) + QCoreApplication::processEvents(QEventLoop::AllEvents, 100); } diff --git a/src/networkmanager.cpp b/src/networkmanager.cpp index 19f0241..cf89d0a 100644 --- a/src/networkmanager.cpp +++ b/src/networkmanager.cpp @@ -6,220 +6,234 @@ NetworkManager::NetworkManager(AOApplication *parent) : QObject(parent) { - ao_app = parent; + ao_app = parent; - ms_socket = new QTcpSocket(this); - server_socket = new QTcpSocket(this); + ms_socket = new QTcpSocket(this); + server_socket = new QTcpSocket(this); - ms_reconnect_timer = new QTimer(this); - ms_reconnect_timer->setSingleShot(true); - QObject::connect(ms_reconnect_timer, SIGNAL(timeout()), this, SLOT(retry_ms_connect())); + ms_reconnect_timer = new QTimer(this); + ms_reconnect_timer->setSingleShot(true); + QObject::connect(ms_reconnect_timer, SIGNAL(timeout()), this, + SLOT(retry_ms_connect())); - QObject::connect(ms_socket, SIGNAL(readyRead()), this, SLOT(handle_ms_packet())); - QObject::connect(server_socket, SIGNAL(readyRead()), this, SLOT(handle_server_packet())); - QObject::connect(server_socket, SIGNAL(disconnected()), ao_app, SLOT(server_disconnected())); + QObject::connect(ms_socket, SIGNAL(readyRead()), this, + SLOT(handle_ms_packet())); + QObject::connect(server_socket, SIGNAL(readyRead()), this, + SLOT(handle_server_packet())); + QObject::connect(server_socket, SIGNAL(disconnected()), ao_app, + SLOT(server_disconnected())); - QString master_config = ao_app->configini->value("master", "").value(); - if (master_config != "") - ms_nosrv_hostname = master_config; + QString master_config = + ao_app->configini->value("master", "").value(); + if (master_config != "") + ms_nosrv_hostname = master_config; } -NetworkManager::~NetworkManager() -{ -} +NetworkManager::~NetworkManager() {} void NetworkManager::connect_to_master() { - ms_socket->close(); - ms_socket->abort(); + ms_socket->close(); + ms_socket->abort(); #ifdef MS_FAILOVER_SUPPORTED - perform_srv_lookup(); + perform_srv_lookup(); #else - connect_to_master_nosrv(); + connect_to_master_nosrv(); #endif } void NetworkManager::connect_to_master_nosrv() { - QObject::connect(ms_socket, SIGNAL(error(QAbstractSocket::SocketError)), - this, SLOT(on_ms_socket_error(QAbstractSocket::SocketError))); + QObject::connect(ms_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, + SLOT(on_ms_socket_error(QAbstractSocket::SocketError))); - QObject::connect(ms_socket, SIGNAL(connected()), - this, SLOT(on_ms_nosrv_connect_success())); - ms_socket->connectToHost(ms_nosrv_hostname, ms_port); + QObject::connect(ms_socket, SIGNAL(connected()), this, + SLOT(on_ms_nosrv_connect_success())); + ms_socket->connectToHost(ms_nosrv_hostname, ms_port); } void NetworkManager::connect_to_server(server_type p_server) { - server_socket->close(); - server_socket->abort(); + server_socket->close(); + server_socket->abort(); - server_socket->connectToHost(p_server.ip, p_server.port); + server_socket->connectToHost(p_server.ip, p_server.port); } void NetworkManager::ship_ms_packet(QString p_packet) { - if (!ms_socket->isOpen()) { - retry_ms_connect(); - } - else { - ms_socket->write(p_packet.toUtf8()); - } + if (!ms_socket->isOpen()) { + retry_ms_connect(); + } + else { + ms_socket->write(p_packet.toUtf8()); + } } void NetworkManager::ship_server_packet(QString p_packet) { - server_socket->write(p_packet.toUtf8()); + server_socket->write(p_packet.toUtf8()); } void NetworkManager::handle_ms_packet() { - QByteArray buffer = ms_socket->readAll(); - QString in_data = QString::fromUtf8(buffer, buffer.size()); + QByteArray buffer = ms_socket->readAll(); + QString in_data = QString::fromUtf8(buffer, buffer.size()); - if (!in_data.endsWith("%")) { - ms_partial_packet = true; - ms_temp_packet += in_data; - return; + if (!in_data.endsWith("%")) { + ms_partial_packet = true; + ms_temp_packet += in_data; + return; + } + + else { + if (ms_partial_packet) { + in_data = ms_temp_packet + in_data; + ms_temp_packet = ""; + ms_partial_packet = false; } + } - else { - if (ms_partial_packet) { - in_data = ms_temp_packet + in_data; - ms_temp_packet = ""; - ms_partial_packet = false; - } - } + QStringList packet_list = + in_data.split("%", QString::SplitBehavior(QString::SkipEmptyParts)); - QStringList packet_list = in_data.split("%", QString::SplitBehavior(QString::SkipEmptyParts)); + for (QString packet : packet_list) { + AOPacket *f_packet = new AOPacket(packet); - for (QString packet : packet_list) { - AOPacket *f_packet = new AOPacket(packet); - - ao_app->ms_packet_received(f_packet); - } + ao_app->ms_packet_received(f_packet); + } } void NetworkManager::perform_srv_lookup() { #ifdef MS_FAILOVER_SUPPORTED - ms_dns = new QDnsLookup(QDnsLookup::SRV, ms_srv_hostname, this); + ms_dns = new QDnsLookup(QDnsLookup::SRV, ms_srv_hostname, this); - connect(ms_dns, SIGNAL(finished()), this, SLOT(on_srv_lookup())); - ms_dns->lookup(); + connect(ms_dns, SIGNAL(finished()), this, SLOT(on_srv_lookup())); + ms_dns->lookup(); #endif } void NetworkManager::on_srv_lookup() { #ifdef MS_FAILOVER_SUPPORTED - bool connected = false; - if (ms_dns->error() != QDnsLookup::NoError) { - qWarning("SRV lookup of the master server DNS failed."); - ms_dns->deleteLater(); - } - else { - const auto srv_records = ms_dns->serviceRecords(); + bool connected = false; + if (ms_dns->error() != QDnsLookup::NoError) { + qWarning("SRV lookup of the master server DNS failed."); + ms_dns->deleteLater(); + } + else { + const auto srv_records = ms_dns->serviceRecords(); - for (const QDnsServiceRecord &record : srv_records) { + for (const QDnsServiceRecord &record : srv_records) { #ifdef DEBUG_NETWORK - qDebug() << "Connecting to " << record.target() << ":" << record.port(); + qDebug() << "Connecting to " << record.target() << ":" << record.port(); #endif - ms_socket->connectToHost(record.target(), record.port()); - QTime timer; - timer.start(); - do { - ao_app->processEvents(); - if (ms_socket->state() == QAbstractSocket::ConnectedState) { - connected = true; - break; - } - else if (ms_socket->state() != QAbstractSocket::ConnectingState && ms_socket->state() != QAbstractSocket::HostLookupState && ms_socket->error() != -1) { - qDebug() << ms_socket->error(); - qWarning() << "Error connecting to master server:" << ms_socket->errorString(); - ms_socket->abort(); - ms_socket->close(); - break; - } - } while (timer.elapsed() < timeout_milliseconds); // Very expensive spin-wait loop - it will bring CPU to 100%! - if (connected) { - // Connect a one-shot signal in case the master server disconnects randomly - QObject::connect(ms_socket, SIGNAL(error(QAbstractSocket::SocketError)), - this, SLOT(on_ms_socket_error(QAbstractSocket::SocketError))); - break; - } - else { - ms_socket->abort(); - ms_socket->close(); - } + ms_socket->connectToHost(record.target(), record.port()); + QTime timer; + timer.start(); + do { + ao_app->processEvents(); + if (ms_socket->state() == QAbstractSocket::ConnectedState) { + connected = true; + break; } + else if (ms_socket->state() != QAbstractSocket::ConnectingState && + ms_socket->state() != QAbstractSocket::HostLookupState && + ms_socket->error() != -1) { + qDebug() << ms_socket->error(); + qWarning() << "Error connecting to master server:" + << ms_socket->errorString(); + ms_socket->abort(); + ms_socket->close(); + break; + } + } while (timer.elapsed() < + timeout_milliseconds); // Very expensive spin-wait loop - it will + // bring CPU to 100%! + if (connected) { + // Connect a one-shot signal in case the master server disconnects + // randomly + QObject::connect( + ms_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, + SLOT(on_ms_socket_error(QAbstractSocket::SocketError))); + break; + } + else { + ms_socket->abort(); + ms_socket->close(); + } } + } - // Failover to non-SRV connection - if (!connected) - connect_to_master_nosrv(); - else - emit ms_connect_finished(connected, false); + // Failover to non-SRV connection + if (!connected) + connect_to_master_nosrv(); + else + emit ms_connect_finished(connected, false); #endif } void NetworkManager::on_ms_nosrv_connect_success() { - emit ms_connect_finished(true, false); + emit ms_connect_finished(true, false); - QObject::disconnect(ms_socket, SIGNAL(connected()), - this, SLOT(on_ms_nosrv_connect_success())); + QObject::disconnect(ms_socket, SIGNAL(connected()), this, + SLOT(on_ms_nosrv_connect_success())); - QObject::connect(ms_socket, SIGNAL(error(QAbstractSocket::SocketError)), - this, SLOT(on_ms_socket_error(QAbstractSocket::SocketError))); + QObject::connect(ms_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, + SLOT(on_ms_socket_error(QAbstractSocket::SocketError))); } void NetworkManager::on_ms_socket_error(QAbstractSocket::SocketError error) { - qWarning() << "Master server socket error:" << ms_socket->errorString() - << "(" << error << ")"; + qWarning() << "Master server socket error:" << ms_socket->errorString() << "(" + << error << ")"; - // Disconnect the one-shot signal - this way, failover connect attempts - // don't trigger a full retry - QObject::disconnect(ms_socket, SIGNAL(error(QAbstractSocket::SocketError)), - this, SLOT(on_ms_socket_error(QAbstractSocket::SocketError))); + // Disconnect the one-shot signal - this way, failover connect attempts + // don't trigger a full retry + QObject::disconnect(ms_socket, SIGNAL(error(QAbstractSocket::SocketError)), + this, + SLOT(on_ms_socket_error(QAbstractSocket::SocketError))); - emit ms_connect_finished(false, true); + emit ms_connect_finished(false, true); - ms_reconnect_timer->start(ms_reconnect_delay * 1000); + ms_reconnect_timer->start(ms_reconnect_delay * 1000); } void NetworkManager::retry_ms_connect() { - if (!ms_reconnect_timer->isActive() && ms_socket->state() != QAbstractSocket::ConnectingState) - connect_to_master(); + if (!ms_reconnect_timer->isActive() && + ms_socket->state() != QAbstractSocket::ConnectingState) + connect_to_master(); } void NetworkManager::handle_server_packet() { - QByteArray buffer = server_socket->readAll(); - QString in_data = QString::fromUtf8(buffer, buffer.size()); + QByteArray buffer = server_socket->readAll(); + QString in_data = QString::fromUtf8(buffer, buffer.size()); - if (!in_data.endsWith("%")) { - partial_packet = true; - temp_packet += in_data; - return; + if (!in_data.endsWith("%")) { + partial_packet = true; + temp_packet += in_data; + return; + } + + else { + if (partial_packet) { + in_data = temp_packet + in_data; + temp_packet = ""; + partial_packet = false; } + } - else { - if (partial_packet) { - in_data = temp_packet + in_data; - temp_packet = ""; - partial_packet = false; - } - } + QStringList packet_list = + in_data.split("%", QString::SplitBehavior(QString::SkipEmptyParts)); - QStringList packet_list = in_data.split("%", QString::SplitBehavior(QString::SkipEmptyParts)); + for (QString packet : packet_list) { + AOPacket *f_packet = new AOPacket(packet); - for (QString packet : packet_list) { - AOPacket *f_packet = new AOPacket(packet); - - ao_app->server_packet_received(f_packet); - } + ao_app->server_packet_received(f_packet); + } } diff --git a/src/packet_distribution.cpp b/src/packet_distribution.cpp index 68f568b..81a9a30 100644 --- a/src/packet_distribution.cpp +++ b/src/packet_distribution.cpp @@ -9,691 +9,742 @@ void AOApplication::ms_packet_received(AOPacket *p_packet) { - p_packet->net_decode(); + p_packet->net_decode(); - QString header = p_packet->get_header(); - QStringList f_contents = p_packet->get_contents(); + QString header = p_packet->get_header(); + QStringList f_contents = p_packet->get_contents(); #ifdef DEBUG_NETWORK - if (header != "CHECK") - qDebug() << "R(ms):" << p_packet->to_string(); + if (header != "CHECK") + qDebug() << "R(ms):" << p_packet->to_string(); #endif - if (header == "ALL") { - server_list.clear(); + if (header == "ALL") { + server_list.clear(); - for (QString i_string : p_packet->get_contents()) { - server_type f_server; - QStringList sub_contents = i_string.split("&"); + for (QString i_string : p_packet->get_contents()) { + server_type f_server; + QStringList sub_contents = i_string.split("&"); - if (sub_contents.size() < 4) { - qDebug() << "W: malformed packet"; - continue; - } + if (sub_contents.size() < 4) { + qDebug() << "W: malformed packet"; + continue; + } - f_server.name = sub_contents.at(0); - f_server.desc = sub_contents.at(1); - f_server.ip = sub_contents.at(2); - f_server.port = sub_contents.at(3).toInt(); + f_server.name = sub_contents.at(0); + f_server.desc = sub_contents.at(1); + f_server.ip = sub_contents.at(2); + f_server.port = sub_contents.at(3).toInt(); - server_list.append(f_server); - } - - if (lobby_constructed) { - w_lobby->list_servers(); - } + server_list.append(f_server); } - else if (header == "CT") { - QString f_name, f_message; - if (f_contents.size() == 1) { - f_name = ""; - f_message = f_contents.at(0); - } - else if (f_contents.size() >= 2) { - f_name = f_contents.at(0); - f_message = f_contents.at(1); - } - else - goto end; - - if (lobby_constructed) { - w_lobby->append_chatmessage(f_name, f_message); - } - if (courtroom_constructed && courtroom_loaded) { - w_courtroom->append_ms_chatmessage(f_name, f_message); - } + if (lobby_constructed) { + w_lobby->list_servers(); } - else if (header == "AO2CHECK") { - send_ms_packet(new AOPacket("ID#AO2#" + get_version_string() + "#%")); - send_ms_packet(new AOPacket("HI#" + get_hdid() + "#%")); + } + else if (header == "CT") { + QString f_name, f_message; - if (f_contents.size() < 1) - goto end; - - QStringList version_contents = f_contents.at(0).split("."); - - if (version_contents.size() < 3) - goto end; - - int f_release = version_contents.at(0).toInt(); - int f_major = version_contents.at(1).toInt(); - int f_minor = version_contents.at(2).toInt(); - - if (get_release() > f_release) - goto end; - else if (get_release() == f_release) { - if (get_major_version() > f_major) - goto end; - else if (get_major_version() == f_major) { - if (get_minor_version() >= f_minor) - goto end; - } - } - - call_notice(tr("Outdated version! Your version: %1\n" - "Please go to aceattorneyonline.com to update.") - .arg(get_version_string())); - destruct_courtroom(); - destruct_lobby(); + if (f_contents.size() == 1) { + f_name = ""; + f_message = f_contents.at(0); } + else if (f_contents.size() >= 2) { + f_name = f_contents.at(0); + f_message = f_contents.at(1); + } + else + goto end; + + if (lobby_constructed) { + w_lobby->append_chatmessage(f_name, f_message); + } + if (courtroom_constructed && courtroom_loaded) { + w_courtroom->append_ms_chatmessage(f_name, f_message); + } + } + else if (header == "AO2CHECK") { + send_ms_packet(new AOPacket("ID#AO2#" + get_version_string() + "#%")); + send_ms_packet(new AOPacket("HI#" + get_hdid() + "#%")); + + if (f_contents.size() < 1) + goto end; + + QStringList version_contents = f_contents.at(0).split("."); + + if (version_contents.size() < 3) + goto end; + + int f_release = version_contents.at(0).toInt(); + int f_major = version_contents.at(1).toInt(); + int f_minor = version_contents.at(2).toInt(); + + if (get_release() > f_release) + goto end; + else if (get_release() == f_release) { + if (get_major_version() > f_major) + goto end; + else if (get_major_version() == f_major) { + if (get_minor_version() >= f_minor) + goto end; + } + } + + call_notice(tr("Outdated version! Your version: %1\n" + "Please go to aceattorneyonline.com to update.") + .arg(get_version_string())); + destruct_courtroom(); + destruct_lobby(); + } end: - delete p_packet; + delete p_packet; } void AOApplication::server_packet_received(AOPacket *p_packet) { - p_packet->net_decode(); + p_packet->net_decode(); - QString header = p_packet->get_header(); - QStringList f_contents = p_packet->get_contents(); - QString f_packet = p_packet->to_string(); + QString header = p_packet->get_header(); + QStringList f_contents = p_packet->get_contents(); + QString f_packet = p_packet->to_string(); #ifdef DEBUG_NETWORK - if (header != "checkconnection") - qDebug() << "R:" << f_packet; + if (header != "checkconnection") + qDebug() << "R:" << f_packet; #endif - if (header == "decryptor") { - if (f_contents.size() == 0) - goto end; + if (header == "decryptor") { + if (f_contents.size() == 0) + goto end; - //you may ask where 322 comes from. that would be a good question. - s_decryptor = fanta_decrypt(f_contents.at(0), 322).toUInt(); + // you may ask where 322 comes from. that would be a good question. + s_decryptor = fanta_decrypt(f_contents.at(0), 322).toUInt(); - //default(legacy) values - encryption_needed = true; - yellow_text_enabled = false; - prezoom_enabled = false; - flipping_enabled = false; - custom_objection_enabled = false; - improved_loading_enabled = false; - desk_mod_enabled = false; - evidence_enabled = false; - cccc_ic_support_enabled = false; - arup_enabled = false; - casing_alerts_enabled = false; - modcall_reason_enabled = false; - looping_sfx_support_enabled = false; - additive_enabled = false; - effects_enabled = false; + // default(legacy) values + encryption_needed = true; + yellow_text_enabled = false; + prezoom_enabled = false; + flipping_enabled = false; + custom_objection_enabled = false; + improved_loading_enabled = false; + desk_mod_enabled = false; + evidence_enabled = false; + cccc_ic_support_enabled = false; + arup_enabled = false; + casing_alerts_enabled = false; + modcall_reason_enabled = false; + looping_sfx_support_enabled = false; + additive_enabled = false; + effects_enabled = false; - //workaround for tsuserver4 - if (f_contents.at(0) == "NOENCRYPT") - encryption_needed = false; + // workaround for tsuserver4 + if (f_contents.at(0) == "NOENCRYPT") + encryption_needed = false; - QString f_hdid; - f_hdid = get_hdid(); + QString f_hdid; + f_hdid = get_hdid(); - AOPacket *hi_packet = new AOPacket("HI#" + f_hdid + "#%"); - send_server_packet(hi_packet); + AOPacket *hi_packet = new AOPacket("HI#" + f_hdid + "#%"); + send_server_packet(hi_packet); + } + else if (header == "ID") { + if (f_contents.size() < 2) + goto end; + + s_pv = f_contents.at(0).toInt(); + server_software = f_contents.at(1); + + w_lobby->enable_connect_button(); + + send_server_packet(new AOPacket("ID#AO2#" + get_version_string() + "#%")); + } + else if (header == "CT") { + if (f_contents.size() < 2) + goto end; + + if (courtroom_constructed) { + if (f_contents.size() == 3) + w_courtroom->append_server_chatmessage( + f_contents.at(0), f_contents.at(1), f_contents.at(2)); + else + w_courtroom->append_server_chatmessage(f_contents.at(0), + f_contents.at(1), "0"); } - else if (header == "ID") { - if (f_contents.size() < 2) - goto end; + } + else if (header == "FL") { + if (f_packet.contains("yellowtext", Qt::CaseInsensitive)) + yellow_text_enabled = true; + if (f_packet.contains("prezoom", Qt::CaseInsensitive)) + prezoom_enabled = true; + if (f_packet.contains("flipping", Qt::CaseInsensitive)) + flipping_enabled = true; + if (f_packet.contains("customobjections", Qt::CaseInsensitive)) + custom_objection_enabled = true; + if (f_packet.contains("fastloading", Qt::CaseInsensitive)) + improved_loading_enabled = true; + if (f_packet.contains("noencryption", Qt::CaseInsensitive)) + encryption_needed = false; + if (f_packet.contains("deskmod", Qt::CaseInsensitive)) + desk_mod_enabled = true; + if (f_packet.contains("evidence", Qt::CaseInsensitive)) + evidence_enabled = true; + if (f_packet.contains("cccc_ic_support", Qt::CaseInsensitive)) + cccc_ic_support_enabled = true; + if (f_packet.contains("arup", Qt::CaseInsensitive)) + arup_enabled = true; + if (f_packet.contains("casing_alerts", Qt::CaseInsensitive)) + casing_alerts_enabled = true; + if (f_packet.contains("modcall_reason", Qt::CaseInsensitive)) + modcall_reason_enabled = true; + if (f_packet.contains("looping_sfx", Qt::CaseInsensitive)) + looping_sfx_support_enabled = true; + if (f_packet.contains("additive", Qt::CaseInsensitive)) + additive_enabled = true; + if (f_packet.contains("effects", Qt::CaseInsensitive)) + effects_enabled = true; + } + else if (header == "PN") { + if (f_contents.size() < 2) + goto end; - s_pv = f_contents.at(0).toInt(); - server_software = f_contents.at(1); + w_lobby->set_player_count(f_contents.at(0).toInt(), + f_contents.at(1).toInt()); + } + else if (header == "SI") { + if (f_contents.size() != 3) + goto end; - w_lobby->enable_connect_button(); + char_list_size = f_contents.at(0).toInt(); + evidence_list_size = f_contents.at(1).toInt(); + music_list_size = f_contents.at(2).toInt(); - send_server_packet(new AOPacket("ID#AO2#" + get_version_string() + "#%")); + if (char_list_size < 1 || evidence_list_size < 0 || music_list_size < 0) + goto end; + + loaded_chars = 0; + loaded_evidence = 0; + loaded_music = 0; + generated_chars = 0; + + destruct_courtroom(); + construct_courtroom(); + + courtroom_loaded = false; + + QString window_title = tr("Attorney Online 2"); + int selected_server = w_lobby->get_selected_server(); + + QString server_address = "", server_name = ""; + if (w_lobby->public_servers_selected) { + 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)); + qDebug() << server_address; + window_title += ": " + server_name; + } } - else if (header == "CT") { - if (f_contents.size() < 2) - goto end; - - if (courtroom_constructed) { - if (f_contents.size() == 3) - w_courtroom->append_server_chatmessage(f_contents.at(0), f_contents.at(1), f_contents.at(2)); - else - w_courtroom->append_server_chatmessage(f_contents.at(0), f_contents.at(1), "0"); - } + else { + 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)); + qDebug() << server_address; + window_title += ": " + server_name; + } } - else if (header == "FL") { - if (f_packet.contains("yellowtext", Qt::CaseInsensitive)) - yellow_text_enabled = true; - if (f_packet.contains("prezoom", Qt::CaseInsensitive)) - prezoom_enabled = true; - if (f_packet.contains("flipping", Qt::CaseInsensitive)) - flipping_enabled = true; - if (f_packet.contains("customobjections", Qt::CaseInsensitive)) - custom_objection_enabled = true; - if (f_packet.contains("fastloading", Qt::CaseInsensitive)) - improved_loading_enabled = true; - if (f_packet.contains("noencryption", Qt::CaseInsensitive)) - encryption_needed = false; - if (f_packet.contains("deskmod", Qt::CaseInsensitive)) - desk_mod_enabled = true; - if (f_packet.contains("evidence", Qt::CaseInsensitive)) - evidence_enabled = true; - if (f_packet.contains("cccc_ic_support", Qt::CaseInsensitive)) - cccc_ic_support_enabled = true; - if (f_packet.contains("arup", Qt::CaseInsensitive)) - arup_enabled = true; - if (f_packet.contains("casing_alerts", Qt::CaseInsensitive)) - casing_alerts_enabled = true; - if (f_packet.contains("modcall_reason", Qt::CaseInsensitive)) - modcall_reason_enabled = true; - if (f_packet.contains("looping_sfx", Qt::CaseInsensitive)) - looping_sfx_support_enabled = true; - if (f_packet.contains("additive", Qt::CaseInsensitive)) - additive_enabled = true; - if (f_packet.contains("effects", Qt::CaseInsensitive)) - effects_enabled = true; + + 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; + + if (improved_loading_enabled) + f_packet = new AOPacket("RC#%"); + else + f_packet = new AOPacket("askchar2#%"); + + send_server_packet(f_packet); + + // Remove any characters not accepted in folder names for the server_name + // here + this->log_filename = QDateTime::currentDateTime().toUTC().toString( + "'logs/" + server_name.remove(QRegExp("[\\\\/:*?\"<>|\']")) + + "/'ddd MMMM yyyy hh.mm.ss t'.log'"); + this->write_to_file("Joined server " + server_name + " on address " + + server_address + " on " + + QDateTime::currentDateTime().toUTC().toString(), + log_filename, true); + QCryptographicHash hash(QCryptographicHash::Algorithm::Sha256); + hash.addData(server_address.toUtf8()); + if (is_discord_enabled()) + discord->state_server(server_name.toStdString(), + hash.result().toBase64().toStdString()); + } + else if (header == "CI") { + if (!courtroom_constructed) + goto end; + + for (int n_element = 0; n_element < f_contents.size(); n_element += 2) { + if (f_contents.at(n_element).toInt() != loaded_chars) + break; + + // this means we are on the last element and checking n + 1 element will + // be game over so + if (n_element == f_contents.size() - 1) + break; + + QStringList sub_elements = f_contents.at(n_element + 1).split("&"); + if (sub_elements.size() < 2) + break; + + char_type f_char; + f_char.name = sub_elements.at(0); + f_char.description = sub_elements.at(1); + f_char.evidence_string = sub_elements.at(3); + // temporary. the CharsCheck packet sets this properly + f_char.taken = false; + + ++loaded_chars; + + w_lobby->set_loading_text("Loading chars:\n" + + QString::number(loaded_chars) + "/" + + QString::number(char_list_size)); + + w_courtroom->append_char(f_char); + + int total_loading_size = + char_list_size * 2 + evidence_list_size + music_list_size; + int loading_value = int( + ((loaded_chars + generated_chars + loaded_music + loaded_evidence) / + static_cast(total_loading_size)) * + 100); + w_lobby->set_loading_value(loading_value); } - else if (header == "PN") { - if (f_contents.size() < 2) - goto end; - w_lobby->set_player_count(f_contents.at(0).toInt(), f_contents.at(1).toInt()); + if (improved_loading_enabled) + send_server_packet(new AOPacket("RE#%")); + else { + QString next_packet_number = + QString::number(((loaded_chars - 1) / 10) + 1); + send_server_packet(new AOPacket("AN#" + next_packet_number + "#%")); } - else if (header == "SI") { - if (f_contents.size() != 3) - goto end; + } + else if (header == "EI") { + if (!courtroom_constructed) + goto end; - char_list_size = f_contents.at(0).toInt(); - evidence_list_size = f_contents.at(1).toInt(); - music_list_size = f_contents.at(2).toInt(); + // +1 because evidence starts at 1 rather than 0 for whatever reason + // enjoy fanta + if (f_contents.at(0).toInt() != loaded_evidence + 1) + goto end; - if (char_list_size < 1 || evidence_list_size < 0 || music_list_size < 0) - goto end; + if (f_contents.size() < 2) + goto end; - loaded_chars = 0; - loaded_evidence = 0; - loaded_music = 0; - generated_chars = 0; + QStringList sub_elements = f_contents.at(1).split("&"); + if (sub_elements.size() < 4) + goto end; - destruct_courtroom(); - construct_courtroom(); + evi_type f_evi; + f_evi.name = sub_elements.at(0); + f_evi.description = sub_elements.at(1); + // no idea what the number at position 2 is. probably an identifier? + f_evi.image = sub_elements.at(3); - courtroom_loaded = false; + ++loaded_evidence; - QString window_title = tr("Attorney Online 2"); - int selected_server = w_lobby->get_selected_server(); + w_lobby->set_loading_text(tr("Loading evidence:\n%1/%2") + .arg(QString::number(loaded_evidence)) + .arg(QString::number(evidence_list_size))); - QString server_address = "", server_name = ""; - if (w_lobby->public_servers_selected) { - 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)); - qDebug() << server_address; - window_title += ": " + server_name; - } + w_courtroom->append_evidence(f_evi); + + int total_loading_size = + char_list_size * 2 + evidence_list_size + music_list_size; + int loading_value = + int(((loaded_chars + generated_chars + loaded_music + loaded_evidence) / + static_cast(total_loading_size)) * + 100); + w_lobby->set_loading_value(loading_value); + + QString next_packet_number = QString::number(loaded_evidence); + send_server_packet(new AOPacket("AE#" + next_packet_number + "#%")); + } + else if (header == "EM") { + if (!courtroom_constructed) + goto end; + + bool musics_time = false; + int areas = 0; + + for (int n_element = 0; n_element < f_contents.size(); n_element += 2) { + if (f_contents.at(n_element).toInt() != loaded_music) + break; + + if (n_element == f_contents.size() - 1) + break; + + QString f_music = f_contents.at(n_element + 1); + + ++loaded_music; + + w_lobby->set_loading_text(tr("Loading music:\n%1/%2") + .arg(QString::number(loaded_music)) + .arg(QString::number(music_list_size))); + + if (musics_time) { + w_courtroom->append_music(f_music); + } + else { + if (f_music.endsWith(".wav") || f_music.endsWith(".mp3") || + f_music.endsWith(".mp4") || f_music.endsWith(".ogg") || + f_music.endsWith(".opus")) { + musics_time = true; + areas--; + w_courtroom->fix_last_area(); + w_courtroom->append_music(f_music); } else { - 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)); - qDebug() << server_address; - window_title += ": " + server_name; - } + w_courtroom->append_area(f_music); + areas++; } + } - w_courtroom->set_window_title(window_title); + for (int area_n = 0; area_n < areas; area_n++) { + w_courtroom->arup_append(0, "Unknown", "Unknown", "Unknown"); + } - w_lobby->show_loading_overlay(); - w_lobby->set_loading_text(tr("Loading")); - w_lobby->set_loading_value(0); - - AOPacket *f_packet; - - if (improved_loading_enabled) - f_packet = new AOPacket("RC#%"); - else - f_packet = new AOPacket("askchar2#%"); - - send_server_packet(f_packet); - - //Remove any characters not accepted in folder names for the server_name here - this->log_filename = QDateTime::currentDateTime().toUTC().toString("'logs/" + server_name.remove(QRegExp("[\\\\/:*?\"<>|\']")) + "/'ddd MMMM yyyy hh.mm.ss t'.log'"); - this->write_to_file("Joined server " + server_name + " on address " + server_address + " on " + QDateTime::currentDateTime().toUTC().toString(), log_filename, true); - QCryptographicHash hash(QCryptographicHash::Algorithm::Sha256); - hash.addData(server_address.toUtf8()); - if (is_discord_enabled()) - discord->state_server(server_name.toStdString(), hash.result().toBase64().toStdString()); + int total_loading_size = + char_list_size * 2 + evidence_list_size + music_list_size; + int loading_value = int( + ((loaded_chars + generated_chars + loaded_music + loaded_evidence) / + static_cast(total_loading_size)) * + 100); + w_lobby->set_loading_value(loading_value); } - else if (header == "CI") { - if (!courtroom_constructed) - goto end; - for (int n_element = 0; n_element < f_contents.size(); n_element += 2) { - if (f_contents.at(n_element).toInt() != loaded_chars) - break; + QString next_packet_number = QString::number(((loaded_music - 1) / 10) + 1); + send_server_packet(new AOPacket("AM#" + next_packet_number + "#%")); + } + else if (header == "CharsCheck") { + if (!courtroom_constructed) + goto end; - //this means we are on the last element and checking n + 1 element will be game over so - if (n_element == f_contents.size() - 1) - break; + for (int n_char = 0; n_char < f_contents.size(); ++n_char) { + if (f_contents.at(n_char) == "-1") + w_courtroom->set_taken(n_char, true); + else + w_courtroom->set_taken(n_char, false); + } + } - QStringList sub_elements = f_contents.at(n_element + 1).split("&"); - if (sub_elements.size() < 2) - break; + else if (header == "SC") { + if (!courtroom_constructed) + goto end; - char_type f_char; - f_char.name = sub_elements.at(0); - f_char.description = sub_elements.at(1); - f_char.evidence_string = sub_elements.at(3); - //temporary. the CharsCheck packet sets this properly - f_char.taken = false; + for (int n_element = 0; n_element < f_contents.size(); ++n_element) { + QStringList sub_elements = f_contents.at(n_element).split("&"); - ++loaded_chars; + char_type f_char; + f_char.name = sub_elements.at(0); + if (sub_elements.size() >= 2) + f_char.description = sub_elements.at(1); - w_lobby->set_loading_text("Loading chars:\n" + QString::number(loaded_chars) + "/" + QString::number(char_list_size)); + // temporary. the CharsCheck packet sets this properly + f_char.taken = false; - w_courtroom->append_char(f_char); + ++loaded_chars; - int total_loading_size = char_list_size * 2 + evidence_list_size + music_list_size; - int loading_value = int(((loaded_chars + generated_chars + loaded_music + loaded_evidence) / static_cast(total_loading_size)) * 100); - w_lobby->set_loading_value(loading_value); + w_lobby->set_loading_text(tr("Loading chars:\n%1/%2") + .arg(QString::number(loaded_chars)) + .arg(QString::number(char_list_size))); + + w_courtroom->append_char(f_char); + + int total_loading_size = + char_list_size * 2 + evidence_list_size + music_list_size; + int loading_value = int( + ((loaded_chars + generated_chars + loaded_music + loaded_evidence) / + static_cast(total_loading_size)) * + 100); + w_lobby->set_loading_value(loading_value); + } + + send_server_packet(new AOPacket("RM#%")); + } + else if (header == "SM") { + if (!courtroom_constructed) + goto end; + + bool musics_time = false; + int areas = 0; + + for (int n_element = 0; n_element < f_contents.size(); ++n_element) { + ++loaded_music; + + w_lobby->set_loading_text(tr("Loading music:\n%1/%2") + .arg(QString::number(loaded_music)) + .arg(QString::number(music_list_size))); + + if (musics_time) { + w_courtroom->append_music(f_contents.at(n_element)); + } + else { + if (f_contents.at(n_element).endsWith(".wav") || + f_contents.at(n_element).endsWith(".mp3") || + f_contents.at(n_element).endsWith(".mp4") || + f_contents.at(n_element).endsWith(".ogg") || + f_contents.at(n_element).endsWith(".opus")) { + musics_time = true; + w_courtroom->fix_last_area(); + w_courtroom->append_music(f_contents.at(n_element)); + areas--; } - - if (improved_loading_enabled) - send_server_packet(new AOPacket("RE#%")); else { - QString next_packet_number = QString::number(((loaded_chars - 1) / 10) + 1); - send_server_packet(new AOPacket("AN#" + next_packet_number + "#%")); + w_courtroom->append_area(f_contents.at(n_element)); + areas++; } + } + + for (int area_n = 0; area_n < areas; area_n++) { + w_courtroom->arup_append(0, "Unknown", "Unknown", "Unknown"); + } + + int total_loading_size = + char_list_size * 2 + evidence_list_size + music_list_size; + int loading_value = int( + ((loaded_chars + generated_chars + loaded_music + loaded_evidence) / + static_cast(total_loading_size)) * + 100); + w_lobby->set_loading_value(loading_value); } - else if (header == "EI") { - if (!courtroom_constructed) - goto end; - // +1 because evidence starts at 1 rather than 0 for whatever reason - //enjoy fanta - if (f_contents.at(0).toInt() != loaded_evidence + 1) - goto end; + send_server_packet(new AOPacket("RD#%")); + } + else if (header == "FM") // Fetch music ONLY + { + if (!courtroom_constructed) + goto end; - if (f_contents.size() < 2) - goto end; + w_courtroom->clear_music(); - QStringList sub_elements = f_contents.at(1).split("&"); - if (sub_elements.size() < 4) - goto end; + for (int n_element = 0; n_element < f_contents.size(); ++n_element) { + w_courtroom->append_music(f_contents.at(n_element)); + } + + w_courtroom->list_music(); + } + else if (header == "FA") // Fetch areas ONLY + { + if (!courtroom_constructed) + goto end; + + w_courtroom->clear_areas(); + + for (int n_element = 0; n_element < f_contents.size(); ++n_element) { + w_courtroom->append_area(f_contents.at(n_element)); + } + + w_courtroom->list_areas(); + } + else if (header == "DONE") { + if (!courtroom_constructed) + goto end; + + if (lobby_constructed) + w_courtroom->append_ms_chatmessage("", w_lobby->get_chatlog()); + + w_courtroom->character_loading_finished(); + w_courtroom->done_received(); + + courtroom_loaded = true; + + destruct_lobby(); + } + else if (header == "BN") { + if (f_contents.size() < 1) + goto end; + + if (courtroom_constructed) { + if (f_contents.size() >= + 2) // We have a pos included in the background packet! + w_courtroom->set_side(f_contents.at(1)); + w_courtroom->set_background(f_contents.at(0), f_contents.size() >= 2); + } + } + else if (header == "SP") { + if (f_contents.size() < 1) + goto end; + + if (courtroom_constructed) // We were sent a "set position" packet + { + w_courtroom->set_side(f_contents.at(0)); + } + } + else if (header == "SD") // Send pos dropdown + { + if (f_contents.size() < 1) + goto end; + + w_courtroom->set_pos_dropdown(f_contents.at(0).split("*")); + } + // server accepting char request(CC) packet + else if (header == "PV") { + if (f_contents.size() < 3) + goto end; + + if (courtroom_constructed) + w_courtroom->update_character(f_contents.at(2).toInt()); + } + else if (header == "MS") { + if (courtroom_constructed && courtroom_loaded) + w_courtroom->handle_chatmessage(&p_packet->get_contents()); + } + else if (header == "MC") { + if (courtroom_constructed && courtroom_loaded) + w_courtroom->handle_song(&p_packet->get_contents()); + } + else if (header == "RT") { + if (f_contents.size() < 1) + goto end; + if (courtroom_constructed) { + if (f_contents.size() == 1) + w_courtroom->handle_wtce(f_contents.at(0), 0); + else if (f_contents.size() == 2) { + w_courtroom->handle_wtce(f_contents.at(0), f_contents.at(1).toInt()); + } + } + } + else if (header == "HP") { + if (courtroom_constructed && f_contents.size() > 1) + w_courtroom->set_hp_bar(f_contents.at(0).toInt(), + f_contents.at(1).toInt()); + } + else if (header == "LE") { + if (courtroom_constructed) { + QVector f_evi_list; + + for (QString f_string : f_contents) { + QStringList sub_contents = f_string.split("&"); + + if (sub_contents.size() < 3) + continue; evi_type f_evi; - f_evi.name = sub_elements.at(0); - f_evi.description = sub_elements.at(1); - //no idea what the number at position 2 is. probably an identifier? - f_evi.image = sub_elements.at(3); + f_evi.name = sub_contents.at(0); + f_evi.description = sub_contents.at(1); + f_evi.image = sub_contents.at(2); - ++loaded_evidence; + f_evi_list.append(f_evi); + } - w_lobby->set_loading_text(tr("Loading evidence:\n%1/%2").arg(QString::number(loaded_evidence)).arg(QString::number(evidence_list_size))); - - w_courtroom->append_evidence(f_evi); - - int total_loading_size = char_list_size * 2 + evidence_list_size + music_list_size; - int loading_value = int(((loaded_chars + generated_chars + loaded_music + loaded_evidence) / static_cast(total_loading_size)) * 100); - w_lobby->set_loading_value(loading_value); - - QString next_packet_number = QString::number(loaded_evidence); - send_server_packet(new AOPacket("AE#" + next_packet_number + "#%")); + w_courtroom->set_evidence_list(f_evi_list); } - else if (header == "EM") { - if (!courtroom_constructed) - goto end; - - bool musics_time = false; - int areas = 0; - - for (int n_element = 0; n_element < f_contents.size(); n_element += 2) { - if (f_contents.at(n_element).toInt() != loaded_music) - break; - - if (n_element == f_contents.size() - 1) - break; - - QString f_music = f_contents.at(n_element + 1); - - ++loaded_music; - - w_lobby->set_loading_text(tr("Loading music:\n%1/%2").arg(QString::number(loaded_music)).arg(QString::number(music_list_size))); - - if (musics_time) { - w_courtroom->append_music(f_music); - } - else { - if (f_music.endsWith(".wav") || - f_music.endsWith(".mp3") || - f_music.endsWith(".mp4") || - f_music.endsWith(".ogg") || - f_music.endsWith(".opus")) { - musics_time = true; - areas--; - w_courtroom->fix_last_area(); - w_courtroom->append_music(f_music); - } - else { - w_courtroom->append_area(f_music); - areas++; - } - } - - for (int area_n = 0; area_n < areas; area_n++) { - w_courtroom->arup_append(0, "Unknown", "Unknown", "Unknown"); - } - - int total_loading_size = char_list_size * 2 + evidence_list_size + music_list_size; - int loading_value = int(((loaded_chars + generated_chars + loaded_music + loaded_evidence) / static_cast(total_loading_size)) * 100); - w_lobby->set_loading_value(loading_value); - } - - QString next_packet_number = QString::number(((loaded_music - 1) / 10) + 1); - send_server_packet(new AOPacket("AM#" + next_packet_number + "#%")); + } + else if (header == "ARUP") { + if (courtroom_constructed) { + int arup_type = f_contents.at(0).toInt(); + for (int n_element = 1; n_element < f_contents.size(); n_element++) { + w_courtroom->arup_modify(arup_type, n_element - 1, + f_contents.at(n_element)); + } } - else if (header == "CharsCheck") { - if (!courtroom_constructed) - goto end; - - for (int n_char = 0; n_char < f_contents.size(); ++n_char) { - if (f_contents.at(n_char) == "-1") - w_courtroom->set_taken(n_char, true); - else - w_courtroom->set_taken(n_char, false); - } + } + else if (header == "IL") { + if (courtroom_constructed && f_contents.size() > 0) + w_courtroom->set_ip_list(f_contents.at(0)); + } + else if (header == "MU") { + if (courtroom_constructed && f_contents.size() > 0) + w_courtroom->set_mute(true, f_contents.at(0).toInt()); + } + else if (header == "UM") { + if (courtroom_constructed && f_contents.size() > 0) + w_courtroom->set_mute(false, f_contents.at(0).toInt()); + } + else if (header == "KK") { + if (courtroom_constructed && f_contents.size() >= 1) { + call_notice(tr("You have been kicked from the server.\nReason: %1") + .arg(f_contents.at(0))); + construct_lobby(); + destruct_courtroom(); } - - else if (header == "SC") { - if (!courtroom_constructed) - goto end; - - for (int n_element = 0; n_element < f_contents.size(); ++n_element) { - QStringList sub_elements = f_contents.at(n_element).split("&"); - - char_type f_char; - f_char.name = sub_elements.at(0); - if (sub_elements.size() >= 2) - f_char.description = sub_elements.at(1); - - //temporary. the CharsCheck packet sets this properly - f_char.taken = false; - - ++loaded_chars; - - w_lobby->set_loading_text(tr("Loading chars:\n%1/%2").arg(QString::number(loaded_chars)).arg(QString::number(char_list_size))); - - w_courtroom->append_char(f_char); - - int total_loading_size = char_list_size * 2 + evidence_list_size + music_list_size; - int loading_value = int(((loaded_chars + generated_chars + loaded_music + loaded_evidence) / static_cast(total_loading_size)) * 100); - w_lobby->set_loading_value(loading_value); - } - - send_server_packet(new AOPacket("RM#%")); - } - else if (header == "SM") { - if (!courtroom_constructed) - goto end; - - bool musics_time = false; - int areas = 0; - - for (int n_element = 0; n_element < f_contents.size(); ++n_element) { - ++loaded_music; - - w_lobby->set_loading_text(tr("Loading music:\n%1/%2").arg(QString::number(loaded_music)).arg(QString::number(music_list_size))); - - if (musics_time) { - w_courtroom->append_music(f_contents.at(n_element)); - } - else { - if (f_contents.at(n_element).endsWith(".wav") || - f_contents.at(n_element).endsWith(".mp3") || - f_contents.at(n_element).endsWith(".mp4") || - f_contents.at(n_element).endsWith(".ogg") || - f_contents.at(n_element).endsWith(".opus")) { - musics_time = true; - w_courtroom->fix_last_area(); - w_courtroom->append_music(f_contents.at(n_element)); - areas--; - } - else { - w_courtroom->append_area(f_contents.at(n_element)); - areas++; - } - } - - for (int area_n = 0; area_n < areas; area_n++) { - w_courtroom->arup_append(0, "Unknown", "Unknown", "Unknown"); - } - - int total_loading_size = char_list_size * 2 + evidence_list_size + music_list_size; - int loading_value = int(((loaded_chars + generated_chars + loaded_music + loaded_evidence) / static_cast(total_loading_size)) * 100); - w_lobby->set_loading_value(loading_value); - } - - send_server_packet(new AOPacket("RD#%")); - } - else if (header == "FM") //Fetch music ONLY - { - if (!courtroom_constructed) - goto end; - - w_courtroom->clear_music(); - - for (int n_element = 0; n_element < f_contents.size(); ++n_element) { - w_courtroom->append_music(f_contents.at(n_element)); - } - - w_courtroom->list_music(); - } - else if (header == "FA") //Fetch areas ONLY - { - if (!courtroom_constructed) - goto end; - - w_courtroom->clear_areas(); - - for (int n_element = 0; n_element < f_contents.size(); ++n_element) { - w_courtroom->append_area(f_contents.at(n_element)); - } - - w_courtroom->list_areas(); - } - else if (header == "DONE") { - if (!courtroom_constructed) - goto end; - - if (lobby_constructed) - w_courtroom->append_ms_chatmessage("", w_lobby->get_chatlog()); - - w_courtroom->character_loading_finished(); - w_courtroom->done_received(); - - courtroom_loaded = true; - - destruct_lobby(); - } - else if (header == "BN") { - if (f_contents.size() < 1) - goto end; - - if (courtroom_constructed) { - if (f_contents.size() >= 2) //We have a pos included in the background packet! - w_courtroom->set_side(f_contents.at(1)); - w_courtroom->set_background(f_contents.at(0), f_contents.size() >= 2); - } - } - else if (header == "SP") { - if (f_contents.size() < 1) - goto end; - - if (courtroom_constructed) //We were sent a "set position" packet - { - w_courtroom->set_side(f_contents.at(0)); - } - } - else if (header == "SD") //Send pos dropdown - { - if (f_contents.size() < 1) - goto end; - - w_courtroom->set_pos_dropdown(f_contents.at(0).split("*")); - } - //server accepting char request(CC) packet - else if (header == "PV") { - if (f_contents.size() < 3) - goto end; - - if (courtroom_constructed) - w_courtroom->update_character(f_contents.at(2).toInt()); - } - else if (header == "MS") { - if (courtroom_constructed && courtroom_loaded) - w_courtroom->handle_chatmessage(&p_packet->get_contents()); - } - else if (header == "MC") { - if (courtroom_constructed && courtroom_loaded) - w_courtroom->handle_song(&p_packet->get_contents()); - } - else if (header == "RT") { - if (f_contents.size() < 1) - goto end; - if (courtroom_constructed) { - if (f_contents.size() == 1) - w_courtroom->handle_wtce(f_contents.at(0), 0); - else if (f_contents.size() == 2) { - w_courtroom->handle_wtce(f_contents.at(0), f_contents.at(1).toInt()); - } - } - } - else if (header == "HP") { - if (courtroom_constructed && f_contents.size() > 1) - w_courtroom->set_hp_bar(f_contents.at(0).toInt(), f_contents.at(1).toInt()); - } - else if (header == "LE") { - if (courtroom_constructed) { - QVector f_evi_list; - - for (QString f_string : f_contents) { - QStringList sub_contents = f_string.split("&"); - - if (sub_contents.size() < 3) - continue; - - evi_type f_evi; - f_evi.name = sub_contents.at(0); - f_evi.description = sub_contents.at(1); - f_evi.image = sub_contents.at(2); - - f_evi_list.append(f_evi); - } - - w_courtroom->set_evidence_list(f_evi_list); - } - } - else if (header == "ARUP") { - if (courtroom_constructed) { - int arup_type = f_contents.at(0).toInt(); - for (int n_element = 1; n_element < f_contents.size(); n_element++) { - w_courtroom->arup_modify(arup_type, n_element - 1, f_contents.at(n_element)); - } - } - } - else if (header == "IL") { - if (courtroom_constructed && f_contents.size() > 0) - w_courtroom->set_ip_list(f_contents.at(0)); - } - else if (header == "MU") { - if (courtroom_constructed && f_contents.size() > 0) - w_courtroom->set_mute(true, f_contents.at(0).toInt()); - } - else if (header == "UM") { - if (courtroom_constructed && f_contents.size() > 0) - w_courtroom->set_mute(false, f_contents.at(0).toInt()); - } - else if (header == "KK") { - if (courtroom_constructed && f_contents.size() >= 1) { - call_notice(tr("You have been kicked from the server.\nReason: %1").arg(f_contents.at(0))); - construct_lobby(); - destruct_courtroom(); - } - } - else if (header == "KB") { - if (courtroom_constructed && f_contents.size() >= 1) { - call_notice(tr("You have been banned from the server.\nReason: %1").arg(f_contents.at(0))); - construct_lobby(); - destruct_courtroom(); - } - } - else if (header == "BD") { - call_notice(tr("You are banned on this server.\nReason: %1").arg(f_contents.at(0))); - } - else if (header == "ZZ") { - if (courtroom_constructed && f_contents.size() > 0) - w_courtroom->mod_called(f_contents.at(0)); - } - else if (header == "CASEA") { - if (courtroom_constructed && f_contents.size() > 6) - w_courtroom->case_called(f_contents.at(0), f_contents.at(1) == "1", f_contents.at(2) == "1", f_contents.at(3) == "1", f_contents.at(4) == "1", f_contents.at(5) == "1"); + } + else if (header == "KB") { + if (courtroom_constructed && f_contents.size() >= 1) { + call_notice(tr("You have been banned from the server.\nReason: %1") + .arg(f_contents.at(0))); + construct_lobby(); + destruct_courtroom(); } + } + else if (header == "BD") { + call_notice( + tr("You are banned on this server.\nReason: %1").arg(f_contents.at(0))); + } + else if (header == "ZZ") { + if (courtroom_constructed && f_contents.size() > 0) + w_courtroom->mod_called(f_contents.at(0)); + } + else if (header == "CASEA") { + if (courtroom_constructed && f_contents.size() > 6) + w_courtroom->case_called(f_contents.at(0), f_contents.at(1) == "1", + f_contents.at(2) == "1", f_contents.at(3) == "1", + f_contents.at(4) == "1", + f_contents.at(5) == "1"); + } end: - delete p_packet; + delete p_packet; } void AOApplication::send_ms_packet(AOPacket *p_packet) { - p_packet->net_encode(); + p_packet->net_encode(); - QString f_packet = p_packet->to_string(); + QString f_packet = p_packet->to_string(); - net_manager->ship_ms_packet(f_packet); + net_manager->ship_ms_packet(f_packet); #ifdef DEBUG_NETWORK - qDebug() << "S(ms):" << f_packet; + qDebug() << "S(ms):" << f_packet; #endif - delete p_packet; + delete p_packet; } void AOApplication::send_server_packet(AOPacket *p_packet, bool encoded) { - if (encoded) - p_packet->net_encode(); + if (encoded) + p_packet->net_encode(); - QString f_packet = p_packet->to_string(); + QString f_packet = p_packet->to_string(); - if (encryption_needed) { + if (encryption_needed) { #ifdef DEBUG_NETWORK - qDebug() << "S(e):" << f_packet; + qDebug() << "S(e):" << f_packet; #endif - p_packet->encrypt_header(s_decryptor); - f_packet = p_packet->to_string(); - } - else { + p_packet->encrypt_header(s_decryptor); + f_packet = p_packet->to_string(); + } + else { #ifdef DEBUG_NETWORK - qDebug() << "S:" << f_packet; + qDebug() << "S:" << f_packet; #endif - } + } - net_manager->ship_server_packet(f_packet); + net_manager->ship_server_packet(f_packet); - delete p_packet; + delete p_packet; } diff --git a/src/path_functions.cpp b/src/path_functions.cpp index ebf4b62..07c9517 100644 --- a/src/path_functions.cpp +++ b/src/path_functions.cpp @@ -10,157 +10,157 @@ #include "base_override.h" #endif -//this is a quite broad generalization -//the most common OSes(mac and windows) are _usually_ case insensitive -//however, there do exist mac installations with case sensitive filesystems -//in that case, define CASE_SENSITIVE_FILESYSTEM and compile on a mac +// this is a quite broad generalization +// the most common OSes(mac and windows) are _usually_ case insensitive +// however, there do exist mac installations with case sensitive filesystems +// in that case, define CASE_SENSITIVE_FILESYSTEM and compile on a mac #if (defined(LINUX) || defined(__linux__)) #define CASE_SENSITIVE_FILESYSTEM #endif QString AOApplication::get_base_path() { - QString base_path = ""; + QString base_path = ""; #ifdef ANDROID - QString sdcard_storage = getenv("SECONDARY_STORAGE"); - if (dir_exists(sdcard_storage + "/AO2/")) { - base_path = sdcard_storage + "/AO2/"; - } - else { - QString external_storage = getenv("EXTERNAL_STORAGE"); - base_path = external_storage + "/AO2/"; - } + QString sdcard_storage = getenv("SECONDARY_STORAGE"); + if (dir_exists(sdcard_storage + "/AO2/")) { + base_path = sdcard_storage + "/AO2/"; + } + else { + QString external_storage = getenv("EXTERNAL_STORAGE"); + base_path = external_storage + "/AO2/"; + } #elif defined __APPLE__ - base_path = applicationDirPath() + "/../../../base/"; + base_path = applicationDirPath() + "/../../../base/"; #else - base_path = applicationDirPath() + "/base/"; + base_path = applicationDirPath() + "/base/"; #endif - return base_path; + return base_path; } -QString AOApplication::get_data_path() -{ - return get_base_path() + "data/"; -} +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; + QString path = get_base_path() + "themes/default/" + p_file; #ifndef CASE_SENSITIVE_FILESYSTEM - return path; + return path; #else - return get_case_sensitive_path(path); + return get_case_sensitive_path(path); #endif } QString AOApplication::get_custom_theme_path(QString p_theme, QString p_file) { - QString path = get_base_path() + "themes/" + p_theme + "/" + p_file; + QString path = get_base_path() + "themes/" + p_theme + "/" + p_file; #ifndef CASE_SENSITIVE_FILESYSTEM - return path; + return path; #else - return get_case_sensitive_path(path); + return get_case_sensitive_path(path); #endif } QString AOApplication::get_theme_path(QString p_file) { - QString path = get_base_path() + "themes/" + current_theme + "/" + p_file; + QString path = get_base_path() + "themes/" + current_theme + "/" + p_file; #ifndef CASE_SENSITIVE_FILESYSTEM - return path; + return path; #else - return get_case_sensitive_path(path); + return get_case_sensitive_path(path); #endif } QString AOApplication::get_character_path(QString p_char, QString p_file) { - QString path = get_base_path() + "characters/" + p_char + "/" + p_file; + QString path = get_base_path() + "characters/" + p_char + "/" + p_file; #ifndef CASE_SENSITIVE_FILESYSTEM - return path; + return path; #else - return get_case_sensitive_path(path); + return get_case_sensitive_path(path); #endif } QString AOApplication::get_sounds_path(QString p_file) { - QString path = get_base_path() + "sounds/general/" + p_file; + QString path = get_base_path() + "sounds/general/" + p_file; #ifndef CASE_SENSITIVE_FILESYSTEM - return path; + return path; #else - return get_case_sensitive_path(path); + return get_case_sensitive_path(path); #endif } QString AOApplication::get_music_path(QString p_song) { - QString path = get_base_path() + "sounds/music/" + p_song; + QString path = get_base_path() + "sounds/music/" + p_song; #ifndef CASE_SENSITIVE_FILESYSTEM - return path; + return path; #else - return get_case_sensitive_path(path); + return get_case_sensitive_path(path); #endif } QString AOApplication::get_background_path(QString p_file) { - QString path = get_base_path() + "background/" + w_courtroom->get_current_background() + "/" + p_file; - if (courtroom_constructed) { -#ifndef CASE_SENSITIVE_FILESYSTEM - return path; -#else - return get_case_sensitive_path(path); -#endif - } - return get_default_background_path(p_file); -} - -QString AOApplication::get_default_background_path(QString p_file) -{ - QString path = get_base_path() + "background/default/" + p_file; + QString path = get_base_path() + "background/" + + w_courtroom->get_current_background() + "/" + p_file; + if (courtroom_constructed) { #ifndef CASE_SENSITIVE_FILESYSTEM return path; #else return get_case_sensitive_path(path); +#endif + } + return get_default_background_path(p_file); +} + +QString AOApplication::get_default_background_path(QString p_file) +{ + QString path = get_base_path() + "background/default/" + p_file; +#ifndef CASE_SENSITIVE_FILESYSTEM + return path; +#else + return get_case_sensitive_path(path); #endif } QString AOApplication::get_evidence_path(QString p_file) { - QString path = get_base_path() + "evidence/" + p_file; + QString path = get_base_path() + "evidence/" + p_file; #ifndef CASE_SENSITIVE_FILESYSTEM - return path; + return path; #else - return get_case_sensitive_path(path); + return get_case_sensitive_path(path); #endif } QString AOApplication::get_case_sensitive_path(QString p_file) { - //first, check to see if it's actually there (also serves as base case for recursion) - if (exists(p_file)) - return p_file; + // first, check to see if it's actually there (also serves as base case for + // recursion) + if (exists(p_file)) + return p_file; - QFileInfo file(p_file); + QFileInfo file(p_file); - QString file_basename = file.fileName(); - QString file_parent_dir = get_case_sensitive_path(file.absolutePath()); + QString file_basename = file.fileName(); + QString file_parent_dir = get_case_sensitive_path(file.absolutePath()); - //second, does it exist in the new parent dir? - if (exists(file_parent_dir + "/" + file_basename)) - return file_parent_dir + "/" + file_basename; - - //last resort, dirlist parent dir and find case insensitive match - QRegExp file_rx = QRegExp(file_basename, Qt::CaseInsensitive, QRegExp::FixedString); - QStringList files = QDir(file_parent_dir).entryList(); - - int result = files.indexOf(file_rx); - - if (result != -1) - return file_parent_dir + "/" + files.at(result); - - //if nothing is found, let the caller handle the missing file + // second, does it exist in the new parent dir? + if (exists(file_parent_dir + "/" + file_basename)) return file_parent_dir + "/" + file_basename; + + // last resort, dirlist parent dir and find case insensitive match + QRegExp file_rx = + QRegExp(file_basename, Qt::CaseInsensitive, QRegExp::FixedString); + QStringList files = QDir(file_parent_dir).entryList(); + + int result = files.indexOf(file_rx); + + if (result != -1) + return file_parent_dir + "/" + files.at(result); + + // if nothing is found, let the caller handle the missing file + return file_parent_dir + "/" + file_basename; } diff --git a/src/scrolltext.cpp b/src/scrolltext.cpp index 543f0f6..afd0aab 100644 --- a/src/scrolltext.cpp +++ b/src/scrolltext.cpp @@ -2,124 +2,124 @@ ScrollText::ScrollText(QWidget *parent) : QWidget(parent), scrollPos(0) { - staticText.setTextFormat(Qt::PlainText); + staticText.setTextFormat(Qt::PlainText); - // setFixedHeight(fontMetrics().height()*2); //The theme sets this - leftMargin = height() / 3; + // setFixedHeight(fontMetrics().height()*2); //The theme sets this + leftMargin = height() / 3; - setSeparator(" --- "); + setSeparator(" --- "); - connect(&timer, SIGNAL(timeout()), this, SLOT(timer_timeout())); - timer.setInterval(50); + connect(&timer, SIGNAL(timeout()), this, SLOT(timer_timeout())); + timer.setInterval(50); } -QString ScrollText::text() const -{ - return _text; -} +QString ScrollText::text() const { return _text; } void ScrollText::setText(QString text) { - _text = text; - updateText(); - update(); + _text = text; + updateText(); + update(); } -QString ScrollText::separator() const -{ - return _separator; -} +QString ScrollText::separator() const { return _separator; } void ScrollText::setSeparator(QString separator) { - _separator = separator; - updateText(); - update(); + _separator = separator; + updateText(); + update(); } void ScrollText::updateText() { - timer.stop(); + timer.stop(); - singleTextWidth = fontMetrics().horizontalAdvance(_text); - scrollEnabled = (singleTextWidth > width() - leftMargin * 2); + singleTextWidth = fontMetrics().horizontalAdvance(_text); + scrollEnabled = (singleTextWidth > width() - leftMargin * 2); - if (scrollEnabled) { - scrollPos = -64; - staticText.setText(_text + _separator); - timer.start(); - } - else - staticText.setText(_text); + if (scrollEnabled) { + scrollPos = -64; + staticText.setText(_text + _separator); + timer.start(); + } + else + staticText.setText(_text); - staticText.prepare(QTransform(), font()); - wholeTextSize = QSize(fontMetrics().horizontalAdvance(staticText.text()), fontMetrics().height()); + staticText.prepare(QTransform(), font()); + wholeTextSize = QSize(fontMetrics().horizontalAdvance(staticText.text()), + fontMetrics().height()); } void ScrollText::paintEvent(QPaintEvent *) { - QPainter p(this); + QPainter p(this); - if (scrollEnabled) { - buffer.fill(qRgba(0, 0, 0, 0)); - QPainter pb(&buffer); - pb.setPen(p.pen()); - pb.setFont(p.font()); + if (scrollEnabled) { + buffer.fill(qRgba(0, 0, 0, 0)); + QPainter pb(&buffer); + pb.setPen(p.pen()); + pb.setFont(p.font()); - int x = qMin(-scrollPos, 0) + leftMargin; - while (x < width()) { - pb.drawStaticText(QPointF(x, (height() - wholeTextSize.height()) / 2), staticText); - x += wholeTextSize.width(); - } - - //Apply Alpha Channel - pb.setCompositionMode(QPainter::CompositionMode_DestinationIn); - pb.setClipRect(width() - 15, 0, 15, height()); - pb.drawImage(0, 0, alphaChannel); - pb.setClipRect(0, 0, 15, height()); - //initial situation: don't apply alpha channel in the left half of the image at all; apply it more and more until scrollPos gets positive - if (scrollPos < 0) - pb.setOpacity(static_cast((qMax(-8, scrollPos) + 8) / 8.0)); - pb.drawImage(0, 0, alphaChannel); - - //pb.end(); - p.drawImage(0, 0, buffer); - } - else { - p.drawStaticText(QPointF(leftMargin, (height() - wholeTextSize.height()) / 2), staticText); + int x = qMin(-scrollPos, 0) + leftMargin; + while (x < width()) { + pb.drawStaticText(QPointF(x, (height() - wholeTextSize.height()) / 2), + staticText); + x += wholeTextSize.width(); } + + // Apply Alpha Channel + pb.setCompositionMode(QPainter::CompositionMode_DestinationIn); + pb.setClipRect(width() - 15, 0, 15, height()); + pb.drawImage(0, 0, alphaChannel); + pb.setClipRect(0, 0, 15, height()); + // initial situation: don't apply alpha channel in the left half of the + // image at all; apply it more and more until scrollPos gets positive + if (scrollPos < 0) + pb.setOpacity(static_cast((qMax(-8, scrollPos) + 8) / 8.0)); + pb.drawImage(0, 0, alphaChannel); + + // pb.end(); + p.drawImage(0, 0, buffer); + } + else { + p.drawStaticText( + QPointF(leftMargin, (height() - wholeTextSize.height()) / 2), + staticText); + } } void ScrollText::resizeEvent(QResizeEvent *) { - //When the widget is resized, we need to update the alpha channel. + // When the widget is resized, we need to update the alpha channel. - alphaChannel = QImage(size(), QImage::Format_ARGB32_Premultiplied); - buffer = QImage(size(), QImage::Format_ARGB32_Premultiplied); + alphaChannel = QImage(size(), QImage::Format_ARGB32_Premultiplied); + buffer = QImage(size(), QImage::Format_ARGB32_Premultiplied); - //Create Alpha Channel: - if (width() > 64) { - //create first scanline - QRgb *scanline1 = reinterpret_cast(alphaChannel.scanLine(0)); - for (int x = 1; x < 16; ++x) - scanline1[x - 1] = scanline1[width() - x] = qRgba(0, 0, 0, x << 4); - for (int x = 15; x < width() - 15; ++x) - scanline1[x] = qRgb(0, 0, 0); - //copy scanline to the other ones - for (int y = 1; y < height(); ++y) - memcpy(alphaChannel.scanLine(y), scanline1, static_cast(width() * 4)); - } - else - alphaChannel.fill(qRgb(0, 0, 0)); + // Create Alpha Channel: + if (width() > 64) { + // create first scanline + QRgb *scanline1 = reinterpret_cast(alphaChannel.scanLine(0)); + for (int x = 1; x < 16; ++x) + scanline1[x - 1] = scanline1[width() - x] = qRgba(0, 0, 0, x << 4); + for (int x = 15; x < width() - 15; ++x) + scanline1[x] = qRgb(0, 0, 0); + // copy scanline to the other ones + for (int y = 1; y < height(); ++y) + memcpy(alphaChannel.scanLine(y), scanline1, + static_cast(width() * 4)); + } + else + alphaChannel.fill(qRgb(0, 0, 0)); - //Update scrolling state - bool newScrollEnabled = (singleTextWidth > width() - leftMargin); - if (newScrollEnabled != scrollEnabled) - updateText(); + // Update scrolling state + bool newScrollEnabled = (singleTextWidth > width() - leftMargin); + if (newScrollEnabled != scrollEnabled) + updateText(); } void ScrollText::timer_timeout() { - scrollPos = (scrollPos + 2) % wholeTextSize.width(); - update(); + scrollPos = (scrollPos + 2) % wholeTextSize.width(); + update(); } diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index 18da853..615a6a1 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -2,1030 +2,1073 @@ QString AOApplication::read_theme() { - QString result = configini->value("theme", "default").value(); - return result; + QString result = configini->value("theme", "default").value(); + return result; } int AOApplication::read_blip_rate() { - int result = configini->value("blip_rate", 2).toInt(); + int result = configini->value("blip_rate", 2).toInt(); - if (result < 1) - return 1; + if (result < 1) + return 1; - return result; + return result; } QString AOApplication::get_ooc_name() { - QString result = configini->value("ooc_name").value(); - return result; + QString result = configini->value("ooc_name").value(); + return result; } int AOApplication::get_default_music() { - int result = configini->value("default_music", 50).toInt(); - return result; + int result = configini->value("default_music", 50).toInt(); + return result; } int AOApplication::get_default_sfx() { - int result = configini->value("default_sfx", 50).toInt(); - return result; + int result = configini->value("default_sfx", 50).toInt(); + return result; } int AOApplication::get_default_blip() { - int result = configini->value("default_blip", 50).toInt(); - return result; + int result = configini->value("default_blip", 50).toInt(); + return result; } int AOApplication::get_max_log_size() { - int result = configini->value("log_maximum", 200).toInt(); - return result; + int result = configini->value("log_maximum", 200).toInt(); + return result; } bool AOApplication::get_log_goes_downwards() { - QString result = configini->value("log_goes_downwards", "true").value(); - return result.startsWith("true"); + QString result = + configini->value("log_goes_downwards", "true").value(); + return result.startsWith("true"); } bool AOApplication::get_showname_enabled_by_default() { - QString result = configini->value("show_custom_shownames", "true").value(); - return result.startsWith("true"); + QString result = + configini->value("show_custom_shownames", "true").value(); + return result.startsWith("true"); } QString AOApplication::get_default_username() { - QString result = configini->value("default_username", "").value(); - if (result.isEmpty()) - return get_ooc_name(); - else - return result; + QString result = configini->value("default_username", "").value(); + if (result.isEmpty()) + return get_ooc_name(); + else + return result; } QString AOApplication::get_audio_output_device() { - QString result = configini->value("default_audio_device", "default").value(); - return result; + QString result = + configini->value("default_audio_device", "default").value(); + return result; } QStringList AOApplication::get_call_words() { - return get_list_file(get_base_path() + "callwords.ini"); + return get_list_file(get_base_path() + "callwords.ini"); } QStringList AOApplication::get_list_file(QString p_file) { - QStringList return_value; + QStringList return_value; - QFile p_ini; + QFile p_ini; - p_ini.setFileName(p_file); - - if (!p_ini.open(QIODevice::ReadOnly)) - return return_value; - - QTextStream in(&p_ini); - - while (!in.atEnd()) { - QString line = in.readLine(); - return_value.append(line); - } + p_ini.setFileName(p_file); + if (!p_ini.open(QIODevice::ReadOnly)) return return_value; + + QTextStream in(&p_ini); + + while (!in.atEnd()) { + QString line = in.readLine(); + return_value.append(line); + } + + return return_value; } QString AOApplication::read_file(QString filename) { - QFile f_log(filename); + QFile f_log(filename); - if (!f_log.open(QIODevice::ReadOnly | QIODevice::Text)) { - qDebug() << "Couldn't open" << filename; - return ""; - } + if (!f_log.open(QIODevice::ReadOnly | QIODevice::Text)) { + qDebug() << "Couldn't open" << filename; + return ""; + } - QTextStream in(&f_log); - QString text = in.readAll(); - f_log.close(); - return text; + QTextStream in(&f_log); + QString text = in.readAll(); + f_log.close(); + return text; } bool AOApplication::write_to_file(QString p_text, QString p_file, bool make_dir) { - QString path = QFileInfo(p_file).path(); - if (make_dir) { - //Create the dir if it doesn't exist yet - QDir dir(path); - if (!dir.exists()) - if (!dir.mkpath(".")) - return false; - } + QString path = QFileInfo(p_file).path(); + if (make_dir) { + // Create the dir if it doesn't exist yet + QDir dir(path); + if (!dir.exists()) + if (!dir.mkpath(".")) + return false; + } - QFile f_log(p_file); - if (f_log.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) { - QTextStream out(&f_log); + QFile f_log(p_file); + if (f_log.open(QIODevice::WriteOnly | QIODevice::Text | + QIODevice::Truncate)) { + QTextStream out(&f_log); - out << p_text; + out << p_text; - f_log.flush(); - f_log.close(); - return true; - } - return false; + f_log.flush(); + f_log.close(); + return true; + } + return false; } -bool AOApplication::append_to_file(QString p_text, QString p_file, bool make_dir) +bool AOApplication::append_to_file(QString p_text, QString p_file, + bool make_dir) { - QString path = QFileInfo(p_file).path(); - //Create the dir if it doesn't exist yet - if (make_dir) { - QDir dir(path); - if (!dir.exists()) - if (!dir.mkpath(".")) - return false; - } + QString path = QFileInfo(p_file).path(); + // Create the dir if it doesn't exist yet + if (make_dir) { + QDir dir(path); + if (!dir.exists()) + if (!dir.mkpath(".")) + return false; + } - QFile f_log(p_file); - if (f_log.open(QIODevice::WriteOnly | QIODevice::Append)) { - QTextStream out(&f_log); + QFile f_log(p_file); + if (f_log.open(QIODevice::WriteOnly | QIODevice::Append)) { + QTextStream out(&f_log); - out << "\r\n" - << p_text; + out << "\r\n" << p_text; - f_log.flush(); - f_log.close(); - return true; - } - return false; + f_log.flush(); + f_log.close(); + return true; + } + return false; } void AOApplication::write_to_serverlist_txt(QString p_line) { - QFile serverlist_txt; - QString serverlist_txt_path = get_base_path() + "serverlist.txt"; + QFile serverlist_txt; + QString serverlist_txt_path = get_base_path() + "serverlist.txt"; - serverlist_txt.setFileName(serverlist_txt_path); + serverlist_txt.setFileName(serverlist_txt_path); - if (!serverlist_txt.open(QIODevice::WriteOnly | QIODevice::Append)) { - return; - } + if (!serverlist_txt.open(QIODevice::WriteOnly | QIODevice::Append)) { + return; + } - QTextStream out(&serverlist_txt); + QTextStream out(&serverlist_txt); - out << "\r\n" - << p_line; + out << "\r\n" << p_line; - serverlist_txt.close(); + serverlist_txt.close(); } QVector AOApplication::read_serverlist_txt() { - QVector f_server_list; + QVector f_server_list; - QFile serverlist_txt; - QString serverlist_txt_path = get_base_path() + "serverlist.txt"; + QFile serverlist_txt; + QString serverlist_txt_path = get_base_path() + "serverlist.txt"; - serverlist_txt.setFileName(serverlist_txt_path); - - if (!serverlist_txt.open(QIODevice::ReadOnly)) { - return f_server_list; - } - - QTextStream in(&serverlist_txt); - - while (!in.atEnd()) { - QString line = in.readLine(); - server_type f_server; - QStringList line_contents = line.split(":"); - - if (line_contents.size() < 3) - continue; - - f_server.ip = line_contents.at(0); - f_server.port = line_contents.at(1).toInt(); - f_server.name = line_contents.at(2); - f_server.desc = ""; - - f_server_list.append(f_server); - } + serverlist_txt.setFileName(serverlist_txt_path); + if (!serverlist_txt.open(QIODevice::ReadOnly)) { return f_server_list; + } + + QTextStream in(&serverlist_txt); + + while (!in.atEnd()) { + QString line = in.readLine(); + server_type f_server; + QStringList line_contents = line.split(":"); + + if (line_contents.size() < 3) + continue; + + f_server.ip = line_contents.at(0); + f_server.port = line_contents.at(1).toInt(); + f_server.name = line_contents.at(2); + f_server.desc = ""; + + f_server_list.append(f_server); + } + + return f_server_list; } -QString AOApplication::read_design_ini(QString p_identifier, QString p_design_path) +QString AOApplication::read_design_ini(QString p_identifier, + QString p_design_path) { - QSettings settings(p_design_path, QSettings::IniFormat); - QVariant value = settings.value(p_identifier); - if (value.type() == QVariant::StringList) { - return value.toStringList().join(","); - } - else { - return value.toString(); - } + QSettings settings(p_design_path, QSettings::IniFormat); + QVariant value = settings.value(p_identifier); + if (value.type() == QVariant::StringList) { + return value.toStringList().join(","); + } + else { + return value.toString(); + } } 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 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); - QPoint return_value; + QPoint return_value; - return_value.setX(0); - return_value.setY(0); + return_value.setX(0); + return_value.setY(0); - if (f_result == "") { - f_result = read_design_ini(p_identifier, default_path); + if (f_result == "") { + f_result = read_design_ini(p_identifier, default_path); - if (f_result == "") - return return_value; - } + if (f_result == "") + return return_value; + } - QStringList sub_line_elements = f_result.split(","); - - if (sub_line_elements.size() < 2) - return return_value; - - return_value.setX(sub_line_elements.at(0).toInt()); - return_value.setY(sub_line_elements.at(1).toInt()); + QStringList sub_line_elements = f_result.split(","); + if (sub_line_elements.size() < 2) return return_value; + + return_value.setX(sub_line_elements.at(0).toInt()); + return_value.setY(sub_line_elements.at(1).toInt()); + + return return_value; } -pos_size_type AOApplication::get_element_dimensions(QString p_identifier, QString p_file, QString p_char) +pos_size_type AOApplication::get_element_dimensions(QString p_identifier, + QString p_file, + QString p_char) { - QString char_ini_path = get_base_path() + "misc/" + get_chat(p_char) + "/" + 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, char_ini_path); + QString char_ini_path = + get_base_path() + "misc/" + get_chat(p_char) + "/" + 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, char_ini_path); - pos_size_type return_value; + pos_size_type return_value; - return_value.x = 0; - return_value.y = 0; - return_value.width = -1; - return_value.height = -1; + return_value.x = 0; + return_value.y = 0; + return_value.width = -1; + return_value.height = -1; + if (f_result == "") { + f_result = read_design_ini(p_identifier, design_ini_path); if (f_result == "") { - f_result = read_design_ini(p_identifier, design_ini_path); - if (f_result == "") { - f_result = read_design_ini(p_identifier, default_path); + f_result = read_design_ini(p_identifier, default_path); - if (f_result == "") - return return_value; - } - } - - QStringList sub_line_elements = f_result.split(","); - - if (sub_line_elements.size() < 4) + if (f_result == "") return return_value; - - return_value.x = sub_line_elements.at(0).toInt(); - return_value.y = sub_line_elements.at(1).toInt(); - return_value.width = sub_line_elements.at(2).toInt(); - return_value.height = sub_line_elements.at(3).toInt(); - - return return_value; -} -QString AOApplication::get_design_element(QString p_identifier, QString p_file, QString p_char) -{ - QString char_ini_path = get_base_path() + "misc/" + get_chat(p_char) + "/" + 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, char_ini_path); - if (f_result == "") { - f_result = read_design_ini(p_identifier, design_ini_path); - if (f_result == "") - f_result = read_design_ini(p_identifier, default_path); } - return f_result; + } + + QStringList sub_line_elements = f_result.split(","); + + if (sub_line_elements.size() < 4) + return return_value; + + return_value.x = sub_line_elements.at(0).toInt(); + return_value.y = sub_line_elements.at(1).toInt(); + return_value.width = sub_line_elements.at(2).toInt(); + return_value.height = sub_line_elements.at(3).toInt(); + + return return_value; +} +QString AOApplication::get_design_element(QString p_identifier, QString p_file, + QString p_char) +{ + QString char_ini_path = + get_base_path() + "misc/" + get_chat(p_char) + "/" + 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, char_ini_path); + if (f_result == "") { + f_result = read_design_ini(p_identifier, design_ini_path); + if (f_result == "") + f_result = read_design_ini(p_identifier, default_path); + } + return f_result; } QString AOApplication::get_font_name(QString p_identifier, QString p_file) { - 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 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; } 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); + 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 == "") { + f_result = read_design_ini(p_identifier, default_path); - if (f_result == "") - return 10; - } + if (f_result == "") + return 10; + } - return f_result.toInt(); + return f_result.toInt(); } 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 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); - QColor return_color(0, 0, 0); + QColor return_color(0, 0, 0); - if (f_result == "") { - f_result = read_design_ini(p_identifier, default_path); + if (f_result == "") { + f_result = read_design_ini(p_identifier, default_path); - if (f_result == "") - return return_color; - } + if (f_result == "") + return return_color; + } - QStringList color_list = f_result.split(","); - - if (color_list.size() < 3) - return return_color; - - return_color.setRed(color_list.at(0).toInt()); - return_color.setGreen(color_list.at(1).toInt()); - return_color.setBlue(color_list.at(2).toInt()); + QStringList color_list = f_result.split(","); + if (color_list.size() < 3) return return_color; + + return_color.setRed(color_list.at(0).toInt()); + return_color.setGreen(color_list.at(1).toInt()); + return_color.setBlue(color_list.at(2).toInt()); + + return return_color; } 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 design_ini_path = get_theme_path(p_file); + QString default_path = get_default_theme_path(p_file); - QFile design_ini; + QFile design_ini; - design_ini.setFileName(design_ini_path); + design_ini.setFileName(design_ini_path); - if (!design_ini.open(QIODevice::ReadOnly)) { - design_ini.setFileName(default_path); - if (!design_ini.open(QIODevice::ReadOnly)) - return ""; - } + if (!design_ini.open(QIODevice::ReadOnly)) { + design_ini.setFileName(default_path); + if (!design_ini.open(QIODevice::ReadOnly)) + return ""; + } - QTextStream in(&design_ini); + QTextStream in(&design_ini); - QString f_text; + QString f_text; - while (!in.atEnd()) { - f_text.append(in.readLine()); - } + while (!in.atEnd()) { + f_text.append(in.readLine()); + } - design_ini.close(); - return f_text; + design_ini.close(); + return f_text; } QString AOApplication::get_tagged_stylesheet(QString target_tag, QString p_file) { - QString design_ini_path = get_theme_path(p_file); + QString design_ini_path = get_theme_path(p_file); - QFile design_ini; + QFile design_ini; - design_ini.setFileName(design_ini_path); + design_ini.setFileName(design_ini_path); - if (!design_ini.open(QIODevice::ReadOnly)) - return ""; + if (!design_ini.open(QIODevice::ReadOnly)) + return ""; - QTextStream in(&design_ini); + QTextStream in(&design_ini); - QString f_text; + QString f_text; - bool tag_found = false; + bool tag_found = false; - while (!in.atEnd()) { - QString line = in.readLine(); + while (!in.atEnd()) { + QString line = in.readLine(); - if (line.startsWith(target_tag, Qt::CaseInsensitive)) { - tag_found = true; - continue; - } - - if (tag_found) { - if ((line.startsWith("[") && line.endsWith("]"))) - break; - f_text.append(line); - } + if (line.startsWith(target_tag, Qt::CaseInsensitive)) { + tag_found = true; + continue; } - design_ini.close(); - return f_text; + if (tag_found) { + if ((line.startsWith("[") && line.endsWith("]"))) + break; + f_text.append(line); + } + } + + design_ini.close(); + return f_text; } QString AOApplication::get_chat_markdown(QString p_identifier, QString p_chat) { - QString design_ini_path = get_base_path() + "misc/" + p_chat + "/config.ini"; - QString default_path = get_base_path() + "misc/default/config.ini"; - QString f_result = read_design_ini(p_identifier, design_ini_path); + QString design_ini_path = get_base_path() + "misc/" + p_chat + "/config.ini"; + QString default_path = get_base_path() + "misc/default/config.ini"; + 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 == "") + f_result = read_design_ini(p_identifier, default_path); - return f_result.toLatin1(); + return f_result.toLatin1(); } QColor AOApplication::get_chat_color(QString p_identifier, QString p_chat) { - QColor return_color(255, 255, 255); + QColor return_color(255, 255, 255); - switch (p_identifier.toInt()) { - case 0: //White - return_color = QColor(255, 255, 255); - break; - case 1: //Green - return_color = QColor(0, 255, 0); - break; - case 2: //Red - return_color = QColor(255, 0, 0); - break; - case 3: //Orange - return_color = QColor(255, 165, 0); - break; - case 4: //Blue - return_color = QColor(45, 150, 255); - break; - case 5: //Yellow - return_color = QColor(255, 255, 0); - break; - case 6: //Pink - return_color = QColor(255, 192, 203); - break; - case 7: //Cyan - return_color = QColor(0, 255, 255); - break; - case 8: //Grey - return_color = QColor(187, 187, 187); - break; - default: - return_color = QColor(255, 255, 255); - break; - } - QString design_ini_path = get_base_path() + "misc/" + p_chat + "/config.ini"; - QString default_path = get_base_path() + "misc/default/config.ini"; - QString f_result = read_design_ini("c" + p_identifier, design_ini_path); + switch (p_identifier.toInt()) { + case 0: // White + return_color = QColor(255, 255, 255); + break; + case 1: // Green + return_color = QColor(0, 255, 0); + break; + case 2: // Red + return_color = QColor(255, 0, 0); + break; + case 3: // Orange + return_color = QColor(255, 165, 0); + break; + case 4: // Blue + return_color = QColor(45, 150, 255); + break; + case 5: // Yellow + return_color = QColor(255, 255, 0); + break; + case 6: // Pink + return_color = QColor(255, 192, 203); + break; + case 7: // Cyan + return_color = QColor(0, 255, 255); + break; + case 8: // Grey + return_color = QColor(187, 187, 187); + break; + default: + return_color = QColor(255, 255, 255); + break; + } + QString design_ini_path = get_base_path() + "misc/" + p_chat + "/config.ini"; + QString default_path = get_base_path() + "misc/default/config.ini"; + QString f_result = read_design_ini("c" + p_identifier, design_ini_path); - if (f_result == "") { - f_result = read_design_ini(p_identifier, default_path); + if (f_result == "") { + f_result = read_design_ini(p_identifier, default_path); - if (f_result == "") - return return_color; - } + if (f_result == "") + return return_color; + } - QStringList color_list = f_result.split(","); - - if (color_list.size() < 3) - return return_color; - - return_color.setRed(color_list.at(0).toInt()); - return_color.setGreen(color_list.at(1).toInt()); - return_color.setBlue(color_list.at(2).toInt()); + QStringList color_list = f_result.split(","); + if (color_list.size() < 3) return return_color; + + return_color.setRed(color_list.at(0).toInt()); + return_color.setGreen(color_list.at(1).toInt()); + return_color.setBlue(color_list.at(2).toInt()); + + return return_color; } QString AOApplication::get_sfx(QString p_identifier) { - QString design_ini_path = get_theme_path("courtroom_sounds.ini"); - QString default_path = get_default_theme_path("courtroom_sounds.ini"); - QString f_result = read_design_ini(p_identifier, design_ini_path); + QString design_ini_path = get_theme_path("courtroom_sounds.ini"); + QString default_path = get_default_theme_path("courtroom_sounds.ini"); + QString f_result = read_design_ini(p_identifier, design_ini_path); - QString return_sfx = ""; + QString return_sfx = ""; - if (f_result == "") { - f_result = read_design_ini(p_identifier, default_path); + if (f_result == "") { + f_result = read_design_ini(p_identifier, default_path); - if (f_result == "") - return return_sfx; - } + if (f_result == "") + return return_sfx; + } - return_sfx = f_result; + return_sfx = f_result; - return return_sfx; + return return_sfx; } QString AOApplication::get_sfx_suffix(QString sound_to_check) { - if (file_exists(sound_to_check)) - return sound_to_check; - if (file_exists(sound_to_check + ".opus")) - return sound_to_check + ".opus"; - if (file_exists(sound_to_check + ".ogg")) - return sound_to_check + ".ogg"; - if (file_exists(sound_to_check + ".mp3")) - return sound_to_check + ".mp3"; - if (file_exists(sound_to_check + ".mp4")) - return sound_to_check + ".mp4"; - return sound_to_check + ".wav"; + if (file_exists(sound_to_check)) + return sound_to_check; + if (file_exists(sound_to_check + ".opus")) + return sound_to_check + ".opus"; + if (file_exists(sound_to_check + ".ogg")) + return sound_to_check + ".ogg"; + if (file_exists(sound_to_check + ".mp3")) + return sound_to_check + ".mp3"; + if (file_exists(sound_to_check + ".mp4")) + return sound_to_check + ".mp4"; + return sound_to_check + ".wav"; } QString AOApplication::get_image_suffix(QString path_to_check) { - 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"; + 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) { - return path_to_check + ".png"; + return path_to_check + ".png"; } -//returns whatever is to the right of "search_line =" within target_tag and terminator_tag, trimmed -//returns the empty string if the search line couldnt be found -QString AOApplication::read_char_ini(QString p_char, QString p_search_line, QString target_tag) +// returns whatever is to the right of "search_line =" within target_tag and +// terminator_tag, trimmed returns the empty string if the search line couldnt be +// found +QString AOApplication::read_char_ini(QString p_char, QString p_search_line, + QString target_tag) { - QSettings settings(get_character_path(p_char, "char.ini"), QSettings::IniFormat); - settings.beginGroup(target_tag); - QString value = settings.value(p_search_line).toString(); - settings.endGroup(); - return value; + QSettings settings(get_character_path(p_char, "char.ini"), + QSettings::IniFormat); + settings.beginGroup(target_tag); + QString value = settings.value(p_search_line).toString(); + settings.endGroup(); + return value; } -void AOApplication::set_char_ini(QString p_char, QString value, QString p_search_line, QString target_tag) +void AOApplication::set_char_ini(QString p_char, QString value, + QString p_search_line, QString target_tag) { - QSettings settings(get_character_path(p_char, "char.ini"), QSettings::IniFormat); - settings.beginGroup(target_tag); - settings.setValue(p_search_line, value); - settings.endGroup(); + QSettings settings(get_character_path(p_char, "char.ini"), + QSettings::IniFormat); + settings.beginGroup(target_tag); + settings.setValue(p_search_line, value); + settings.endGroup(); } -//returns all the values of target_tag +// returns all the values of target_tag QStringList AOApplication::read_ini_tags(QString p_path, QString target_tag) { - QStringList r_values; - QSettings settings(p_path, QSettings::IniFormat); - if (!target_tag.isEmpty()) - settings.beginGroup(target_tag); - QStringList keys = settings.allKeys(); - foreach (QString key, keys) { - QString value = settings.value(key).toString(); - r_values << key + "=" + value; - } - if (!settings.group().isEmpty()) - settings.endGroup(); - return r_values; + QStringList r_values; + QSettings settings(p_path, QSettings::IniFormat); + if (!target_tag.isEmpty()) + settings.beginGroup(target_tag); + QStringList keys = settings.allKeys(); + foreach (QString key, keys) { + QString value = settings.value(key).toString(); + r_values << key + "=" + value; + } + if (!settings.group().isEmpty()) + settings.endGroup(); + return r_values; } QString AOApplication::get_char_name(QString p_char) { - QString f_result = read_char_ini(p_char, "name", "Options"); + QString f_result = read_char_ini(p_char, "name", "Options"); - if (f_result == "") - return p_char; - return f_result; + if (f_result == "") + return p_char; + return f_result; } QString AOApplication::get_showname(QString p_char) { - QString f_result = read_char_ini(p_char, "showname", "Options"); - QString f_needed = read_char_ini(p_char, "needs_showname", "Options"); + QString f_result = read_char_ini(p_char, "showname", "Options"); + QString f_needed = read_char_ini(p_char, "needs_showname", "Options"); - if (f_needed.startsWith("false")) - return ""; - if (f_result == "") - return p_char; - return f_result; + if (f_needed.startsWith("false")) + return ""; + if (f_result == "") + return p_char; + return f_result; } QString AOApplication::get_char_side(QString p_char) { - QString f_result = read_char_ini(p_char, "side", "Options"); + QString f_result = read_char_ini(p_char, "side", "Options"); - if (f_result == "") - return "wit"; - return f_result; + if (f_result == "") + return "wit"; + return f_result; } QString AOApplication::get_gender(QString p_char) { - QString f_result = read_char_ini(p_char, "gender", "Options"); + QString f_result = read_char_ini(p_char, "gender", "Options"); - if (f_result == "") - return "sfx-blipmale"; + if (f_result == "") + return "sfx-blipmale"; - if (!file_exists(get_sfx_suffix(get_sounds_path(f_result)))) { - if (file_exists(get_sfx_suffix(get_sounds_path("../blips/" + f_result)))) - return "../blips/" + f_result; //Return the cool kids variant + if (!file_exists(get_sfx_suffix(get_sounds_path(f_result)))) { + if (file_exists(get_sfx_suffix(get_sounds_path("../blips/" + f_result)))) + return "../blips/" + f_result; // Return the cool kids variant - return "sfx-blip" + f_result; //Return legacy variant - } - return f_result; + return "sfx-blip" + f_result; // Return legacy variant + } + return f_result; } QString AOApplication::get_chat(QString p_char) { - QString f_result = read_char_ini(p_char, "chat", "Options"); + 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; + // handling the correct order of chat is a bit complicated, we let the caller + // do it + return f_result; } QString AOApplication::get_chat_font(QString p_char) { - QString f_result = read_char_ini(p_char, "chat_font", "Options"); + QString f_result = read_char_ini(p_char, "chat_font", "Options"); - return f_result; + return f_result; } int AOApplication::get_chat_size(QString p_char) { - QString f_result = read_char_ini(p_char, "chat_size", "Options"); + QString f_result = read_char_ini(p_char, "chat_size", "Options"); - if (f_result == "") - return -1; - return f_result.toInt(); + if (f_result == "") + return -1; + 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 "default"; - return f_result; + QString f_result = read_char_ini(p_char, "shouts", "Options"); + if (f_result == "") + return "default"; + 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"); + QString f_result = read_char_ini(p_char, p_emote, "Time"); - if (f_result == "") - return -1; - return f_result.toInt(); + if (f_result == "") + return -1; + return f_result.toInt(); } int AOApplication::get_ao2_preanim_duration(QString p_char, QString p_emote) { - QString f_result = read_char_ini(p_char, "%" + p_emote, "Time"); + QString f_result = read_char_ini(p_char, "%" + p_emote, "Time"); - if (f_result == "") - return -1; - return f_result.toInt(); + if (f_result == "") + return -1; + return f_result.toInt(); } int AOApplication::get_emote_number(QString p_char) { - QString f_result = read_char_ini(p_char, "number", "Emotions"); + QString f_result = read_char_ini(p_char, "number", "Emotions"); - if (f_result == "") - return 0; - return f_result.toInt(); + if (f_result == "") + return 0; + return f_result.toInt(); } QString AOApplication::get_emote_comment(QString p_char, int p_emote) { - QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); + QString f_result = + read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); - QStringList result_contents = f_result.split("#"); + QStringList result_contents = f_result.split("#"); - if (result_contents.size() < 4) { - qDebug() << "W: misformatted char.ini: " << p_char << ", " << p_emote; - return "normal"; - } - return result_contents.at(0); + if (result_contents.size() < 4) { + qDebug() << "W: misformatted char.ini: " << p_char << ", " << p_emote; + return "normal"; + } + return result_contents.at(0); } QString AOApplication::get_pre_emote(QString p_char, int p_emote) { - QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); + QString f_result = + read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); - QStringList result_contents = f_result.split("#"); + QStringList result_contents = f_result.split("#"); - if (result_contents.size() < 4) { - qDebug() << "W: misformatted char.ini: " << p_char << ", " << p_emote; - return ""; - } - return result_contents.at(1); + if (result_contents.size() < 4) { + qDebug() << "W: misformatted char.ini: " << p_char << ", " << p_emote; + return ""; + } + return result_contents.at(1); } QString AOApplication::get_emote(QString p_char, int p_emote) { - QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); + QString f_result = + read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); - QStringList result_contents = f_result.split("#"); + QStringList result_contents = f_result.split("#"); - if (result_contents.size() < 4) { - qDebug() << "W: misformatted char.ini: " << p_char << ", " << p_emote; - return "normal"; - } - return result_contents.at(2); + if (result_contents.size() < 4) { + qDebug() << "W: misformatted char.ini: " << p_char << ", " << p_emote; + return "normal"; + } + return result_contents.at(2); } int AOApplication::get_emote_mod(QString p_char, int p_emote) { - QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); + QString f_result = + read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); - QStringList result_contents = f_result.split("#"); + QStringList result_contents = f_result.split("#"); - if (result_contents.size() < 4) { - qDebug() << "W: misformatted char.ini: " << p_char << ", " << QString::number(p_emote); - return 0; - } - return result_contents.at(3).toInt(); + if (result_contents.size() < 4) { + qDebug() << "W: misformatted char.ini: " << p_char << ", " + << QString::number(p_emote); + return 0; + } + return result_contents.at(3).toInt(); } int AOApplication::get_desk_mod(QString p_char, int p_emote) { - QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); + QString f_result = + read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); - QStringList result_contents = f_result.split("#"); + QStringList result_contents = f_result.split("#"); - if (result_contents.size() < 5) - return -1; + if (result_contents.size() < 5) + return -1; - QString string_result = result_contents.at(4); - if (string_result == "") - return -1; + QString string_result = result_contents.at(4); + if (string_result == "") + return -1; - return string_result.toInt(); + return string_result.toInt(); } QString AOApplication::get_sfx_name(QString p_char, int p_emote) { - QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "SoundN"); + QString f_result = + read_char_ini(p_char, QString::number(p_emote + 1), "SoundN"); - if (f_result == "") - return "1"; - return f_result; + if (f_result == "") + return "1"; + return f_result; } QString AOApplication::get_emote_blip(QString p_char, int p_emote) { - QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "SoundB"); - return f_result; + QString f_result = + read_char_ini(p_char, QString::number(p_emote + 1), "SoundB"); + return f_result; } int AOApplication::get_sfx_delay(QString p_char, int p_emote) { - QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "SoundT"); + QString f_result = + read_char_ini(p_char, QString::number(p_emote + 1), "SoundT"); - if (f_result == "") - return 1; - return f_result.toInt(); + if (f_result == "") + return 1; + return f_result.toInt(); } QString AOApplication::get_sfx_looping(QString p_char, QString p_sfx) { - QString f_result = read_char_ini(p_char, p_sfx, "SoundL"); + QString f_result = read_char_ini(p_char, p_sfx, "SoundL"); - if (f_result == "") - return "0"; - return f_result; + if (f_result == "") + return "0"; + return f_result; } -QString AOApplication::get_sfx_frame(QString p_char, QString p_emote, int n_frame) +QString AOApplication::get_sfx_frame(QString p_char, QString p_emote, + int n_frame) { - QString f_result = read_char_ini(p_char, QString::number(n_frame), p_emote.append("_FrameSFX")); + QString f_result = read_char_ini(p_char, QString::number(n_frame), + p_emote.append("_FrameSFX")); - if (f_result == "") - return ""; - return f_result; + if (f_result == "") + return ""; + return f_result; } -QString AOApplication::get_screenshake_frame(QString p_char, QString p_emote, int n_frame) +QString AOApplication::get_screenshake_frame(QString p_char, QString p_emote, + int n_frame) { - QString f_result = read_char_ini(p_char, QString::number(n_frame), p_emote.append("_FrameScreenshake")); + QString f_result = read_char_ini(p_char, QString::number(n_frame), + p_emote.append("_FrameScreenshake")); - if (f_result == "") - return ""; - return f_result; + if (f_result == "") + return ""; + return f_result; } -QString AOApplication::get_flash_frame(QString p_char, QString p_emote, int n_frame) +QString AOApplication::get_flash_frame(QString p_char, QString p_emote, + int n_frame) { - QString f_result = read_char_ini(p_char, QString::number(n_frame), p_emote.append("_FrameRealization")); + QString f_result = read_char_ini(p_char, QString::number(n_frame), + p_emote.append("_FrameRealization")); - if (f_result == "") - return ""; - return f_result; + if (f_result == "") + return ""; + return f_result; } int AOApplication::get_text_delay(QString p_char, QString p_emote) { - QString f_result = read_char_ini(p_char, p_emote, "TextDelay"); + QString f_result = read_char_ini(p_char, p_emote, "TextDelay"); - if (f_result == "") - return -1; - return f_result.toInt(); + if (f_result == "") + return -1; + return f_result.toInt(); } QStringList AOApplication::get_theme_effects() { - QString p_path = get_theme_path("effects/effects.ini"); - QString default_path = get_default_theme_path("effects/effects.ini"); + QString p_path = get_theme_path("effects/effects.ini"); + QString default_path = get_default_theme_path("effects/effects.ini"); - QStringList effects; - if (!file_exists(p_path)) { - p_path = default_path; - if (!file_exists(p_path)) - return effects; - } + 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(); - if (!effect.isEmpty() && !effects.contains(effect)) - effects.append(effect); - } - return effects; + QStringList lines = read_file(p_path).split("\n"); + foreach (QString effect, lines) { + effect = effect.split("=")[0].trimmed(); + if (!effect.isEmpty() && !effects.contains(effect)) + effects.append(effect); + } + 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(); - if (!effect.isEmpty() && !effects.contains(effect)) - effects.append(effect); - } + 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(); + if (!effect.isEmpty() && !effects.contains(effect)) + effects.append(effect); + } + + return effects; } -QString AOApplication::get_effect(QString effect, QString p_char, QString p_folder) +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_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)); + 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 = design_ini_path; - if (!file_exists(p_path)) { - p_path = default_path; - if (!file_exists(p_path)) { - return ""; - } - } + p_path = default_path; + if (!file_exists(p_path)) { + return ""; + } } + } - return p_path; + return p_path; } QString AOApplication::get_effect_sound(QString fx_name, QString p_char) { - 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 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(fx_name, p_path); + QString f_result = read_design_ini(fx_name, p_path); + if (f_result == "") { + f_result = read_design_ini(fx_name, design_ini_path); if (f_result == "") { - f_result = read_design_ini(fx_name, design_ini_path); - if (f_result == "") { - f_result = read_design_ini(fx_name, default_path); - } + f_result = read_design_ini(fx_name, default_path); } - return f_result; + } + return f_result; } QString AOApplication::get_custom_realization(QString p_char) { - QString f_result = read_char_ini(p_char, "realization", "Options"); + 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)); + if (f_result == "") + return get_sfx("realization"); + else + return get_sfx_suffix(get_sounds_path(f_result)); } bool AOApplication::get_blank_blip() { - QString result = configini->value("blank_blip", "false").value(); - return result.startsWith("true"); + QString result = configini->value("blank_blip", "false").value(); + return result.startsWith("true"); } bool AOApplication::get_looping_sfx() { - QString result = configini->value("looping_sfx", "true").value(); - return result.startsWith("true"); + QString result = configini->value("looping_sfx", "true").value(); + return result.startsWith("true"); } bool AOApplication::objection_stop_music() { - QString result = configini->value("objection_stop_music", "false").value(); - return result.startsWith("true"); + QString result = + configini->value("objection_stop_music", "false").value(); + return result.startsWith("true"); } bool AOApplication::is_discord_enabled() { - QString result = configini->value("discord", "true").value(); - return result.startsWith("true"); + QString result = configini->value("discord", "true").value(); + return result.startsWith("true"); } bool AOApplication::is_shake_enabled() { - QString result = configini->value("shake", "true").value(); - return result.startsWith("true"); + QString result = configini->value("shake", "true").value(); + return result.startsWith("true"); } bool AOApplication::is_effects_enabled() { - QString result = configini->value("effects", "true").value(); - return result.startsWith("true"); + QString result = configini->value("effects", "true").value(); + return result.startsWith("true"); } bool AOApplication::is_frame_network_enabled() { - QString result = configini->value("framenetwork", "true").value(); - return result.startsWith("true"); + QString result = configini->value("framenetwork", "true").value(); + return result.startsWith("true"); } bool AOApplication::is_colorlog_enabled() { - QString result = configini->value("colorlog", "true").value(); - return result.startsWith("true"); + QString result = configini->value("colorlog", "true").value(); + return result.startsWith("true"); } bool AOApplication::is_stickysounds_enabled() { - QString result = configini->value("stickysounds", "false").value(); - return result.startsWith("true"); + QString result = configini->value("stickysounds", "false").value(); + return result.startsWith("true"); } bool AOApplication::is_stickyeffects_enabled() { - QString result = configini->value("stickyeffects", "false").value(); - return result.startsWith("true"); + QString result = configini->value("stickyeffects", "false").value(); + return result.startsWith("true"); } bool AOApplication::is_stickypres_enabled() { - QString result = configini->value("stickypres", "false").value(); - return result.startsWith("true"); + QString result = configini->value("stickypres", "false").value(); + return result.startsWith("true"); } bool AOApplication::get_casing_enabled() { - QString result = configini->value("casing_enabled", "false").value(); - return result.startsWith("true"); + QString result = configini->value("casing_enabled", "false").value(); + return result.startsWith("true"); } bool AOApplication::get_casing_defence_enabled() { - QString result = configini->value("casing_defence_enabled", "false").value(); - return result.startsWith("true"); + QString result = + configini->value("casing_defence_enabled", "false").value(); + return result.startsWith("true"); } bool AOApplication::get_casing_prosecution_enabled() { - QString result = configini->value("casing_prosecution_enabled", "false").value(); - return result.startsWith("true"); + QString result = + configini->value("casing_prosecution_enabled", "false").value(); + return result.startsWith("true"); } bool AOApplication::get_casing_judge_enabled() { - QString result = configini->value("casing_judge_enabled", "false").value(); - return result.startsWith("true"); + QString result = + configini->value("casing_judge_enabled", "false").value(); + return result.startsWith("true"); } bool AOApplication::get_casing_juror_enabled() { - QString result = configini->value("casing_juror_enabled", "false").value(); - return result.startsWith("true"); + QString result = + configini->value("casing_juror_enabled", "false").value(); + return result.startsWith("true"); } bool AOApplication::get_casing_steno_enabled() { - QString result = configini->value("casing_steno_enabled", "false").value(); - return result.startsWith("true"); + QString result = + configini->value("casing_steno_enabled", "false").value(); + return result.startsWith("true"); } bool AOApplication::get_casing_cm_enabled() { - QString result = configini->value("casing_cm_enabled", "false").value(); - return result.startsWith("true"); + QString result = + configini->value("casing_cm_enabled", "false").value(); + return result.startsWith("true"); } QString AOApplication::get_casing_can_host_cases() { - QString result = configini->value("casing_can_host_cases", "Turnabout Check Your Settings").value(); - return result; + QString result = + configini->value("casing_can_host_cases", "Turnabout Check Your Settings") + .value(); + return result; } From a5868aa3800de43ce6f6aee903bb0fecf2fe105b Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Fri, 22 May 2020 04:53:19 +0300 Subject: [PATCH 175/268] Fix looping frame SFX not working w/ AOV's definitions --- include/aoapplication.h | 2 +- src/courtroom.cpp | 14 +++++++------- src/text_file_functions.cpp | 13 ++++++++----- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/include/aoapplication.h b/include/aoapplication.h index d9e84fa..471fc46 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -371,7 +371,7 @@ public: QString get_emote_blip(QString p_char, int p_emote); // Returns if the sfx is defined as looping in char.ini - QString get_sfx_looping(QString p_char, QString p_sfx); + QString get_sfx_looping(QString p_char, int p_emote); // Returns if an emote has a frame specific SFX for it QString get_sfx_frame(QString p_char, QString p_emote, int n_frame); diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 9261de3..63d7f5e 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1637,7 +1637,7 @@ void Courtroom::on_chat_return_pressed() // emote uses it. if (ao_app->looping_sfx_support_enabled) { packet_contents.append( - "0"); // ao_app->get_sfx_looping(current_char, current_emote)); + 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); @@ -2124,10 +2124,10 @@ void Courtroom::do_effect(QString fx_name, QString fx_sound, QString p_char, void Courtroom::play_char_sfx(QString sfx_name) { sfx_player->play(sfx_name); - if (ao_app->get_looping_sfx()) - sfx_player->set_looping( - ao_app->get_sfx_looping(current_char, QString::number(current_emote)) != - "0"); + // sfx_player->set_looping(false); + // if (ao_app->get_looping_sfx()) + // sfx_player->set_looping( + // ao_app->get_sfx_looping(current_char, current_emote) == "1"); } void Courtroom::handle_chatmessage_3() @@ -2877,8 +2877,8 @@ void Courtroom::play_sfx() sfx_player->play(sfx_name); if (ao_app->get_looping_sfx()) - sfx_player->set_looping(ao_app->get_sfx_looping(current_char, sfx_name) != - "0"); + sfx_player->set_looping( + ao_app->get_sfx_looping(current_char, current_emote) == "1"); } void Courtroom::set_scene(QString f_desk_mod, QString f_side) diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index 615a6a1..1689cd3 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -558,8 +558,8 @@ QString AOApplication::get_static_image_suffix(QString path_to_check) } // returns whatever is to the right of "search_line =" within target_tag and -// terminator_tag, trimmed returns the empty string if the search line couldnt be -// found +// terminator_tag, trimmed returns the empty string if the search line couldnt +// be found QString AOApplication::read_char_ini(QString p_char, QString p_search_line, QString target_tag) { @@ -805,13 +805,16 @@ int AOApplication::get_sfx_delay(QString p_char, int p_emote) return f_result.toInt(); } -QString AOApplication::get_sfx_looping(QString p_char, QString p_sfx) +QString AOApplication::get_sfx_looping(QString p_char, int p_emote) { - QString f_result = read_char_ini(p_char, p_sfx, "SoundL"); + QString f_result = + read_char_ini(p_char, QString::number(p_emote + 1), "SoundL"); + qDebug() << f_result; if (f_result == "") return "0"; - return f_result; + else + return f_result; } QString AOApplication::get_sfx_frame(QString p_char, QString p_emote, From 4617e3135ed14a28c4129154486022947fda9d82 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Fri, 22 May 2020 15:28:33 +0300 Subject: [PATCH 176/268] Change version number to 2.8.4 --- include/aoapplication.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/aoapplication.h b/include/aoapplication.h index 471fc46..18f6ef2 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -428,7 +428,7 @@ public: private: const int RELEASE = 2; const int MAJOR_VERSION = 8; - const int MINOR_VERSION = 3; + const int MINOR_VERSION = 4; QString current_theme = "default"; From 156a760ebab6839c53f9c613881f0937e814414a Mon Sep 17 00:00:00 2001 From: oldmud0 Date: Fri, 22 May 2020 17:02:32 -0500 Subject: [PATCH 177/268] Full revert to tag 2.6.2 Due to a countless number of changes made to the core that were not fully understood, tested, or documented, it was decided to roll everything back to the last known stable version (2.6.2). Changes dropped include: - Witness needed - Shake - Frame SFX - Multiple custom objections - Multithreaded thumbnail generation - Looping - Various translation additions - "Mirror IC" - Color in IC log - An invocation of clang-format Next time, work together and split your big fork into independently testable feature branches. --- .github/labeler.yml | 8 - .gitignore | 4 - .gitlab-ci.yml | 69 +- .gitmodules | 3 - .travis.yml | 22 +- Attorney_Online.pro | 30 +- README.md | 18 +- android/AndroidManifest.xml | 79 - android/build.gradle | 62 - android/project.properties | 1 - android/res/drawable-ldpi/icon.png | Bin 29302 -> 0 bytes android/res/values/libs.xml | 22 - base/sounds/general/adminhelp.ogg | Bin 17220 -> 0 bytes base/sounds/general/case_announced.ogg | Bin 15790 -> 0 bytes base/sounds/music/failed_login.opus | Bin 396160 -> 0 bytes base/themes | 1 - base/themes/1.8/arrow_left.png | Bin 0 -> 742 bytes base/themes/1.8/arrow_right.png | Bin 0 -> 730 bytes base/themes/1.8/chatmed.png | Bin 0 -> 505 bytes base/themes/1.8/favorites.png | Bin 0 -> 1682 bytes base/themes/1.8/favorites_selected.png | Bin 0 -> 2238 bytes base/themes/1.8/holdit.png | Bin 0 -> 1983 bytes base/themes/1.8/holdit_selected.png | Bin 0 -> 1835 bytes base/themes/1.8/mute.png | Bin 0 -> 4984 bytes base/themes/1.8/mute_pressed.png | Bin 0 -> 4725 bytes base/themes/1.8/objection.png | Bin 0 -> 2147 bytes base/themes/1.8/objection_selected.png | Bin 0 -> 1988 bytes base/themes/1.8/publicservers.png | Bin 0 -> 1836 bytes base/themes/1.8/publicservers_selected.png | Bin 0 -> 2399 bytes base/themes/1.8/takethat.png | Bin 0 -> 2057 bytes base/themes/1.8/takethat_selected.png | Bin 0 -> 1932 bytes base/themes/default/about.png | Bin 0 -> 3298 bytes base/themes/default/addevidence.png | Bin 0 -> 403 bytes base/themes/default/addtofav.png | Bin 0 -> 972 bytes base/themes/default/addtofav_pressed.png | Bin 0 -> 938 bytes base/themes/default/arrow_left.png | Bin 0 -> 396 bytes base/themes/default/arrow_right.png | Bin 0 -> 391 bytes base/themes/default/char_passworded.png | Bin 0 -> 1904 bytes base/themes/default/char_selector.png | Bin 0 -> 285 bytes base/themes/default/char_taken.png | Bin 0 -> 215 bytes base/themes/default/charselect_background.png | Bin 0 -> 5342 bytes base/themes/default/chat.png | Bin 0 -> 1529 bytes base/themes/default/chatbig.png | Bin 0 -> 80093 bytes base/themes/default/chatmed.png | Bin 0 -> 1669 bytes base/themes/default/connect.png | Bin 0 -> 914 bytes base/themes/default/connect_pressed.png | Bin 0 -> 925 bytes base/themes/default/courtroom_design.ini | 245 + base/themes/default/courtroom_fonts.ini | 11 + base/themes/default/courtroom_sounds.ini | 8 + base/themes/default/courtroombackground.png | Bin 0 -> 63046 bytes base/themes/default/crossexamination.gif | Bin 0 -> 88834 bytes base/themes/default/crossexamination.png | Bin 0 -> 4187 bytes base/themes/default/custom.png | Bin 0 -> 2505 bytes base/themes/default/custom_selected.png | Bin 0 -> 2212 bytes base/themes/default/defense_speedlines.gif | Bin 0 -> 31308 bytes base/themes/default/defensebar0.png | Bin 0 -> 171 bytes base/themes/default/defensebar1.png | Bin 0 -> 188 bytes base/themes/default/defensebar10.png | Bin 0 -> 184 bytes base/themes/default/defensebar2.png | Bin 0 -> 187 bytes base/themes/default/defensebar3.png | Bin 0 -> 187 bytes base/themes/default/defensebar4.png | Bin 0 -> 188 bytes base/themes/default/defensebar5.png | Bin 0 -> 188 bytes base/themes/default/defensebar6.png | Bin 0 -> 188 bytes base/themes/default/defensebar7.png | Bin 0 -> 187 bytes base/themes/default/defensebar8.png | Bin 0 -> 188 bytes base/themes/default/defensebar9.png | Bin 0 -> 188 bytes base/themes/default/defminus.png | Bin 0 -> 492 bytes base/themes/default/defplus.png | Bin 0 -> 498 bytes base/themes/default/deleteevidence.png | Bin 0 -> 3280 bytes base/themes/default/emote_selected.png | Bin 0 -> 249 bytes base/themes/default/evidence_appear_left.gif | Bin 0 -> 2008 bytes base/themes/default/evidence_appear_right.gif | Bin 0 -> 2225 bytes base/themes/default/evidence_selected.png | Bin 0 -> 291 bytes base/themes/default/evidence_selector.png | Bin 0 -> 931 bytes base/themes/default/evidencebackground.png | Bin 0 -> 19927 bytes base/themes/default/evidencebutton.png | Bin 0 -> 577 bytes base/themes/default/evidenceoverlay.png | Bin 0 -> 2187 bytes base/themes/default/evidencex.png | Bin 0 -> 637 bytes base/themes/default/favorites.png | Bin 0 -> 3882 bytes base/themes/default/favorites_selected.png | Bin 0 -> 4306 bytes base/themes/default/guilty.gif | Bin 0 -> 43263 bytes base/themes/default/guilty.png | Bin 0 -> 2851 bytes base/themes/default/holdit.gif | Bin 0 -> 40518 bytes base/themes/default/holdit.png | Bin 0 -> 1983 bytes base/themes/default/holdit_selected.png | Bin 0 -> 1835 bytes base/themes/default/loadingbackground.png | Bin 0 -> 2194 bytes base/themes/default/lobby_design.ini | 17 + base/themes/default/lobbybackground.png | Bin 0 -> 29532 bytes base/themes/default/mute.png | Bin 0 -> 5037 bytes base/themes/default/mute_pressed.png | Bin 0 -> 4978 bytes base/themes/default/muted.png | Bin 0 -> 1013 bytes base/themes/default/muted_old.png | Bin 0 -> 5703 bytes base/themes/default/notguilty.gif | Bin 0 -> 34911 bytes base/themes/default/notguilty.png | Bin 0 -> 3269 bytes base/themes/default/objection.gif | Bin 0 -> 44417 bytes base/themes/default/objection.png | Bin 0 -> 2147 bytes base/themes/default/objection_selected.png | Bin 0 -> 1988 bytes base/themes/default/pair_button.png | Bin 0 -> 4677 bytes base/themes/default/pair_button_pressed.png | Bin 0 -> 4619 bytes base/themes/default/placeholder.gif | Bin 0 -> 9168 bytes base/themes/default/present.png | Bin 0 -> 3035 bytes base/themes/default/present_disabled.png | Bin 0 -> 2905 bytes base/themes/default/prominus.png | Bin 0 -> 493 bytes base/themes/default/proplus.png | Bin 0 -> 498 bytes .../themes/default/prosecution_speedlines.gif | Bin 0 -> 31252 bytes base/themes/default/prosecutionbar0.png | Bin 0 -> 200 bytes base/themes/default/prosecutionbar1.png | Bin 0 -> 237 bytes base/themes/default/prosecutionbar10.png | Bin 0 -> 173 bytes base/themes/default/prosecutionbar2.png | Bin 0 -> 241 bytes base/themes/default/prosecutionbar3.png | Bin 0 -> 230 bytes base/themes/default/prosecutionbar4.png | Bin 0 -> 243 bytes base/themes/default/prosecutionbar5.png | Bin 0 -> 241 bytes base/themes/default/prosecutionbar6.png | Bin 0 -> 241 bytes base/themes/default/prosecutionbar7.png | Bin 0 -> 242 bytes base/themes/default/prosecutionbar8.png | Bin 0 -> 240 bytes base/themes/default/prosecutionbar9.png | Bin 0 -> 237 bytes base/themes/default/publicservers.png | Bin 0 -> 3999 bytes .../themes/default/publicservers_selected.png | Bin 0 -> 4427 bytes base/themes/default/realization.png | Bin 0 -> 4259 bytes base/themes/default/realization_pressed.png | Bin 0 -> 4225 bytes base/themes/default/realizationflash.png | Bin 0 -> 646 bytes base/themes/default/refresh.png | Bin 0 -> 914 bytes base/themes/default/refresh_pressed.png | Bin 0 -> 919 bytes base/themes/default/takethat.gif | Bin 0 -> 42063 bytes base/themes/default/takethat.png | Bin 0 -> 2057 bytes base/themes/default/takethat_selected.png | Bin 0 -> 1932 bytes base/themes/default/testimony.gif | Bin 0 -> 1033 bytes base/themes/default/testimony.png | Bin 0 -> 579 bytes base/themes/default/witnesstestimony.gif | Bin 0 -> 105223 bytes base/themes/default/witnesstestimony.png | Bin 0 -> 5186 bytes include/aoapplication.h | 706 +- include/aoblipplayer.h | 18 +- include/aobutton.h | 5 +- include/aocaseannouncerdialog.h | 14 +- include/aocharbutton.h | 8 +- include/aocharmovie.h | 43 +- include/aoemotebutton.h | 13 +- include/aoevidencebutton.h | 10 +- include/aoevidencedisplay.h | 7 +- include/aoimage.h | 7 +- include/aolineedit.h | 5 +- include/aomovie.h | 9 +- include/aomusicplayer.h | 38 +- include/aooptionsdialog.h | 268 +- include/aopacket.h | 9 +- include/aoscene.h | 7 +- include/aosfxplayer.h | 22 +- include/aotextarea.h | 15 +- include/aotextedit.h | 4 +- include/bass.h | 2216 +++-- include/chatlogpiece.h | 14 +- include/courtroom.h | 1407 ++- include/datatypes.h | 47 +- include/debug_functions.h | 2 +- include/discord-rpc.h | 64 +- include/discord_register.h | 26 +- include/discord_rich_presence.h | 14 +- include/discord_rpc.h | 66 +- include/encryption_functions.h | 6 +- include/file_functions.h | 2 +- include/hex_functions.h | 13 +- include/lobby.h | 23 +- include/misc_functions.h | 2 +- include/networkmanager.h | 11 +- include/text_file_functions.h | 8 +- resource/translations/ao_de.qm | Bin 23500 -> 0 bytes resource/translations/ao_de.ts | 1118 --- resource/translations/ao_en.qm | Bin 23 -> 0 bytes resource/translations/ao_en.ts | 937 -- resource/translations/ao_es.qm | Bin 28457 -> 0 bytes resource/translations/ao_es.ts | 1048 --- resource/translations/ao_jp.qm | Bin 2004 -> 0 bytes resource/translations/ao_jp.ts | 964 -- resource/translations/ao_pl.qm | Bin 27653 -> 0 bytes resource/translations/ao_pl.ts | 987 -- resource/translations/ao_pt.qm | Bin 28605 -> 0 bytes resource/translations/ao_pt.ts | 977 -- resource/translations/ao_ru.qm | Bin 21968 -> 0 bytes resource/translations/ao_ru.ts | 999 -- resources.qrc | 7 - scripts/configure_ubuntu.sh | 6 +- scripts/macos_build.sh | 2 +- scripts/macos_post_build.sh | 4 +- scripts/release_macos.sh | 22 + scripts/wasabi_program.sh | 2 +- scripts/windows/Dockerfile | 11 +- src/aoapplication.cpp | 89 +- src/aoblipplayer.cpp | 58 +- src/aobutton.cpp | 9 +- src/aocaseannouncerdialog.cpp | 43 +- src/aocharbutton.cpp | 32 +- src/aocharmovie.cpp | 311 +- src/aoemotebutton.cpp | 18 +- src/aoevidencebutton.cpp | 23 +- src/aoevidencedisplay.cpp | 37 +- src/aoimage.cpp | 11 +- src/aolineedit.cpp | 5 +- src/aomovie.cpp | 206 +- src/aomusicplayer.cpp | 64 +- src/aooptionsdialog.cpp | 1026 +-- src/aopacket.cpp | 29 +- src/aoscene.cpp | 71 +- src/aosfxplayer.cpp | 86 +- src/aotextarea.cpp | 53 +- src/aotextedit.cpp | 8 +- src/charselect.cpp | 270 +- src/chatlogpiece.cpp | 42 +- src/courtroom.cpp | 8092 ++++++++--------- src/debug_functions.cpp | 17 +- src/discord_rich_presence.cpp | 37 +- src/emotes.cpp | 43 +- src/encryption_functions.cpp | 19 +- src/evidence.cpp | 104 +- src/file_functions.cpp | 3 +- src/hardware_functions.cpp | 41 +- src/hex_functions.cpp | 23 +- src/lobby.cpp | 791 +- src/main.cpp | 46 +- src/misc_functions.cpp | 2 +- src/networkmanager.cpp | 134 +- src/packet_distribution.cpp | 1427 +-- src/path_functions.cpp | 76 +- src/text_file_functions.cpp | 1491 ++- 223 files changed, 9459 insertions(+), 18191 deletions(-) delete mode 100644 .github/labeler.yml delete mode 100644 .gitmodules delete mode 100644 android/AndroidManifest.xml delete mode 100644 android/build.gradle delete mode 100644 android/project.properties delete mode 100644 android/res/drawable-ldpi/icon.png delete mode 100644 android/res/values/libs.xml delete mode 100644 base/sounds/general/adminhelp.ogg delete mode 100644 base/sounds/general/case_announced.ogg delete mode 100644 base/sounds/music/failed_login.opus delete mode 160000 base/themes create mode 100644 base/themes/1.8/arrow_left.png create mode 100644 base/themes/1.8/arrow_right.png create mode 100644 base/themes/1.8/chatmed.png create mode 100644 base/themes/1.8/favorites.png create mode 100644 base/themes/1.8/favorites_selected.png create mode 100644 base/themes/1.8/holdit.png create mode 100644 base/themes/1.8/holdit_selected.png create mode 100644 base/themes/1.8/mute.png create mode 100644 base/themes/1.8/mute_pressed.png create mode 100644 base/themes/1.8/objection.png create mode 100644 base/themes/1.8/objection_selected.png create mode 100644 base/themes/1.8/publicservers.png create mode 100644 base/themes/1.8/publicservers_selected.png create mode 100644 base/themes/1.8/takethat.png create mode 100644 base/themes/1.8/takethat_selected.png create mode 100644 base/themes/default/about.png create mode 100644 base/themes/default/addevidence.png create mode 100644 base/themes/default/addtofav.png create mode 100644 base/themes/default/addtofav_pressed.png create mode 100644 base/themes/default/arrow_left.png create mode 100644 base/themes/default/arrow_right.png create mode 100644 base/themes/default/char_passworded.png create mode 100644 base/themes/default/char_selector.png create mode 100644 base/themes/default/char_taken.png create mode 100644 base/themes/default/charselect_background.png create mode 100644 base/themes/default/chat.png create mode 100644 base/themes/default/chatbig.png create mode 100644 base/themes/default/chatmed.png create mode 100644 base/themes/default/connect.png create mode 100644 base/themes/default/connect_pressed.png create mode 100644 base/themes/default/courtroom_design.ini create mode 100644 base/themes/default/courtroom_fonts.ini create mode 100644 base/themes/default/courtroom_sounds.ini create mode 100644 base/themes/default/courtroombackground.png create mode 100644 base/themes/default/crossexamination.gif create mode 100644 base/themes/default/crossexamination.png create mode 100644 base/themes/default/custom.png create mode 100644 base/themes/default/custom_selected.png create mode 100644 base/themes/default/defense_speedlines.gif create mode 100644 base/themes/default/defensebar0.png create mode 100644 base/themes/default/defensebar1.png create mode 100644 base/themes/default/defensebar10.png create mode 100644 base/themes/default/defensebar2.png create mode 100644 base/themes/default/defensebar3.png create mode 100644 base/themes/default/defensebar4.png create mode 100644 base/themes/default/defensebar5.png create mode 100644 base/themes/default/defensebar6.png create mode 100644 base/themes/default/defensebar7.png create mode 100644 base/themes/default/defensebar8.png create mode 100644 base/themes/default/defensebar9.png create mode 100644 base/themes/default/defminus.png create mode 100644 base/themes/default/defplus.png create mode 100644 base/themes/default/deleteevidence.png create mode 100644 base/themes/default/emote_selected.png create mode 100644 base/themes/default/evidence_appear_left.gif create mode 100644 base/themes/default/evidence_appear_right.gif create mode 100644 base/themes/default/evidence_selected.png create mode 100644 base/themes/default/evidence_selector.png create mode 100644 base/themes/default/evidencebackground.png create mode 100644 base/themes/default/evidencebutton.png create mode 100644 base/themes/default/evidenceoverlay.png create mode 100644 base/themes/default/evidencex.png create mode 100644 base/themes/default/favorites.png create mode 100644 base/themes/default/favorites_selected.png create mode 100644 base/themes/default/guilty.gif create mode 100644 base/themes/default/guilty.png create mode 100644 base/themes/default/holdit.gif create mode 100644 base/themes/default/holdit.png create mode 100644 base/themes/default/holdit_selected.png create mode 100644 base/themes/default/loadingbackground.png create mode 100644 base/themes/default/lobby_design.ini create mode 100644 base/themes/default/lobbybackground.png create mode 100644 base/themes/default/mute.png create mode 100644 base/themes/default/mute_pressed.png create mode 100644 base/themes/default/muted.png create mode 100644 base/themes/default/muted_old.png create mode 100644 base/themes/default/notguilty.gif create mode 100644 base/themes/default/notguilty.png create mode 100644 base/themes/default/objection.gif create mode 100644 base/themes/default/objection.png create mode 100644 base/themes/default/objection_selected.png create mode 100644 base/themes/default/pair_button.png create mode 100644 base/themes/default/pair_button_pressed.png create mode 100644 base/themes/default/placeholder.gif create mode 100644 base/themes/default/present.png create mode 100644 base/themes/default/present_disabled.png create mode 100644 base/themes/default/prominus.png create mode 100644 base/themes/default/proplus.png create mode 100644 base/themes/default/prosecution_speedlines.gif create mode 100644 base/themes/default/prosecutionbar0.png create mode 100644 base/themes/default/prosecutionbar1.png create mode 100644 base/themes/default/prosecutionbar10.png create mode 100644 base/themes/default/prosecutionbar2.png create mode 100644 base/themes/default/prosecutionbar3.png create mode 100644 base/themes/default/prosecutionbar4.png create mode 100644 base/themes/default/prosecutionbar5.png create mode 100644 base/themes/default/prosecutionbar6.png create mode 100644 base/themes/default/prosecutionbar7.png create mode 100644 base/themes/default/prosecutionbar8.png create mode 100644 base/themes/default/prosecutionbar9.png create mode 100644 base/themes/default/publicservers.png create mode 100644 base/themes/default/publicservers_selected.png create mode 100644 base/themes/default/realization.png create mode 100644 base/themes/default/realization_pressed.png create mode 100644 base/themes/default/realizationflash.png create mode 100644 base/themes/default/refresh.png create mode 100644 base/themes/default/refresh_pressed.png create mode 100644 base/themes/default/takethat.gif create mode 100644 base/themes/default/takethat.png create mode 100644 base/themes/default/takethat_selected.png create mode 100644 base/themes/default/testimony.gif create mode 100644 base/themes/default/testimony.png create mode 100644 base/themes/default/witnesstestimony.gif create mode 100644 base/themes/default/witnesstestimony.png delete mode 100644 resource/translations/ao_de.qm delete mode 100644 resource/translations/ao_de.ts delete mode 100644 resource/translations/ao_en.qm delete mode 100644 resource/translations/ao_en.ts delete mode 100644 resource/translations/ao_es.qm delete mode 100644 resource/translations/ao_es.ts delete mode 100644 resource/translations/ao_jp.qm delete mode 100644 resource/translations/ao_jp.ts delete mode 100644 resource/translations/ao_pl.qm delete mode 100644 resource/translations/ao_pl.ts delete mode 100644 resource/translations/ao_pt.qm delete mode 100644 resource/translations/ao_pt.ts delete mode 100644 resource/translations/ao_ru.qm delete mode 100644 resource/translations/ao_ru.ts mode change 100755 => 100644 scripts/macos_post_build.sh create mode 100755 scripts/release_macos.sh diff --git a/.github/labeler.yml b/.github/labeler.yml deleted file mode 100644 index 56c4cc7..0000000 --- a/.github/labeler.yml +++ /dev/null @@ -1,8 +0,0 @@ -translation: - - resource/translations/* - -content: - - base/**/* - -good_luck: - - src/courtroom.cpp diff --git a/.gitignore b/.gitignore index 3f8b3ae..1adb744 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,6 @@ *.dll *.so *.pro.autosave -*.pro.user base_override.h .DS_Store @@ -22,7 +21,6 @@ debug/ Makefile* object_script* -/android/gradle* /Attorney_Online_remake_resource.rc /attorney_online_remake_plugin_import.cpp @@ -33,5 +31,3 @@ discord/ moc* /Attorney_Online_CC_resource.rc /attorney_online_cc_plugin_import.cpp - -*.autosave diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e9685de..0f68fe5 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -8,9 +8,6 @@ cache: paths: - lib/ -variables: - DEBIAN_FRONTEND: noninteractive - before_script: - echo Current working directory is $(pwd) @@ -25,24 +22,22 @@ build linux x86_64: - apt-get update - > apt-get install --no-install-recommends -y qt5-default qtmultimedia5-dev - clang make git sudo curl ca-certificates pkg-config upx unzip xz-utils - - git submodule init - - git submodule update + clang make git sudo curl ca-certificates pkg-config upx unzip # Print versions - qmake --version - clang --version # Extract BASS - #- mkdir bass - #- cd bass - #- curl http://www.un4seen.com/files/bass24-linux.zip -o bass.zip - #- unzip bass.zip - #- cp x64/libbass.so ../lib - #- curl http://www.un4seen.com/files/bassopus24-linux.zip -o bassopus.zip - #- unzip bassopus.zip - #- cp x64/libbassopus.so ../lib - #- cd .. + - mkdir bass + - cd bass + - curl http://www.un4seen.com/files/bass24-linux.zip -o bass.zip + - unzip bass.zip + - cp x64/libbass.so ../lib + - curl http://www.un4seen.com/files/bassopus24-linux.zip -o bassopus.zip + - unzip bassopus.zip + - cp x64/libbassopus.so ../lib + - cd .. # Extract Discord RPC - mkdir discord-rpc @@ -61,7 +56,7 @@ build linux x86_64: - cd .. # Build - - qmake -spec linux-clang "DEFINES += DISCORD QTAUDIO" + - qmake -spec linux-clang - make -j4 # Post-processing @@ -80,11 +75,6 @@ build windows i686: # Install dependencies - apt-get update - apt-get install --no-install-recommends -y make curl ca-certificates upx unzip - - git submodule init - - git submodule update - - # Print versions - - /opt/mxe/usr/${TARGET_SPEC}/qt5/bin/qmake --version # Extract BASS - mkdir bass @@ -97,19 +87,8 @@ build windows i686: - cp bassopus.dll ../lib - cd .. - # Extract QtApng - # - mkdir qtapng - # - cd qtapng - # - curl -L https://github.com/Skycoder42/QtApng/releases/download/1.1.2-2/qtapng_mingw73_32_5.13.0.zip -o apng.zip - # - unzip apng.zip - # - mkdir ../lib/imageformats - # - cp mingw73_32/plugins/imageformats/qapng.dll ../lib/imageformats/ - # - cd .. - - - ls lib - # Build - - /opt/mxe/usr/${TARGET_SPEC}/qt5/bin/qmake "DEFINES += DISCORD BASSAUDIO" + - /opt/mxe/usr/${TARGET_SPEC}/qt5/bin/qmake - make -j4 # Post-processing @@ -145,7 +124,7 @@ deploy linux x86_64: - *deploy_misc # Platform-specific - - cp -a ../lib/* . + - cp -a ../lib/*.so . - cp -a ../bin/Attorney_Online . - echo "#!/bin/sh" >> ./run.sh - echo "LD_LIBRARY_PATH=.:\$LD_LIBRARY_PATH ./Attorney_Online" >> ./run.sh @@ -179,8 +158,6 @@ deploy windows i686: # Platform-specific - cp -a ../lib/*.dll . - - mkdir imageformats - - 'cp -a ../lib/imageformats/*.dll imageformats/ || :' - cp -a ../bin/Attorney_Online.exe . # Zipping @@ -213,17 +190,11 @@ publish linux x86_64: - deploy linux x86_64 when: manual script: - - apt-get update - - apt-get install --no-install-recommends -y git nodejs npm awscli - - cd scripts - - npm install - - cd .. - - cd zip - - ../scripts/wasabi_program.sh + - ../scripts/wasabi.sh variables: MANIFEST: program_linux_x86_64.json - ARTIFACT_SUFFIX: linux_x64.tar.xz + ARTIFACT_SUFFIX: _linux_x64.tar.xz publish windows i686: image: ubuntu @@ -232,14 +203,8 @@ publish windows i686: - deploy windows i686 when: manual script: - - apt-get update - - apt-get install --no-install-recommends -y git nodejs npm awscli - - cd scripts - - npm install - - cd .. - - cd zip - - ../scripts/wasabi_program.sh + - ../scripts/wasabi.sh variables: MANIFEST: program_winnt_i386.json - ARTIFACT_SUFFIX: windows_x86.zip + ARTIFACT_SUFFIX: _windows_x86.zip diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 1376cc1..0000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "base/themes"] - path = base/themes - url = https://github.com/AttorneyOnline/AO2-Themes diff --git a/.travis.yml b/.travis.yml index dbd19cd..4243b3b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,21 +1,11 @@ language: cpp os: osx + addons: - homebrew: - update: true - packages: - - qt5 + homebrew: + packages: + - qt5 script: -- "./scripts/macos_build.sh" -- "./scripts/macos_post_build.sh" - -deploy: - provider: releases - api_key: - secure: mZCNwnqKeqJP5CqgYOanYnr/KHydxueGPRhvGLpY0Pop7MiH3CIHMN5dhHbtgJvE5GGMR4xUIEhPpmkCEJw7YiPREMqT4mkV4DR531ZLB3t/FizyvIwXuP6jFwzTofZ51qHfBpcurVc9sMFeD9Pw+rLTTgIiXL2sZxUUXc8U+ZZug1lYndgcO6P00fUJd6V9lyFQUGmbSca97YbG6KuCym0fEpyRnMqzKLjYsUUo8UKRBADtmD822O6z2FSldNZDn45Mkx0MYfHWyT5hzTb7WGa+DrTB/0un1HqqsNPlb/ahjrFQQNR2qd7HNGZa+Mvwi6egTDug+k15x8lbkacUoi34U1eFq9LSTYm8dSO5g23I1OvGvjTCkDj1jOLPqB99XlbAJ0E/9Jzw7wtlLaAzvFzTj/B63TQnO3IsgHBWR14CZlf05WMOFf2irwl+kL6ktspIHnlGgaiWYYrKeAt7QJAXiQOdYDz6SaWVC6TyOE/SszXRU6xFotmCjkP2irM5yGE8SUw2uIzKjD9uG0ZXtbLcdQEFD316+qglqFTCjnKsRfbtQs2u5spZPsZSdsOZCbLfNIn0GSTFRymFsK6gsvji8AD8AZo0zcOZ/7NMVC6A8RnF3Ve+vU/xljhsIOxoLZDvZPia7WozdV99xmnepWBwkuoQs/K0xmWcnLZDcb0= - file: "../bin/Attorney_Online_mac_x86_64.zip" - draft: true - on: - tags: true - repo: AttorneyOnline/AO2-Client + - ./scripts/macos_build.sh + - ./scripts/macos_post_build.sh diff --git a/Attorney_Online.pro b/Attorney_Online.pro index c773fb3..20a61d3 100644 --- a/Attorney_Online.pro +++ b/Attorney_Online.pro @@ -3,7 +3,7 @@ QT += core gui widgets network TARGET = Attorney_Online TEMPLATE = app -VERSION = 2.7.2.0 +VERSION = 2.6.2.0 INCLUDEPATH += $$PWD/include DESTDIR = $$PWD/bin @@ -16,14 +16,13 @@ HEADERS += $$files($$PWD/include/*.h) LIBS += -L$$PWD/lib - -#DEFINES += DISCORD +DEFINES += DISCORD contains(DEFINES, DISCORD) { LIBS += -ldiscord-rpc } -#DEFINES += BASSAUDIO +DEFINES += BASSAUDIO contains(DEFINES, BASSAUDIO) { LIBS += -lbass @@ -35,10 +34,6 @@ contains(DEFINES, QTAUDIO) { QT += multimedia } -contains(CONFIG, qml_debug) { -DEFINES += DEBUG_NETWORK -} - macx:LIBS += -framework CoreFoundation -framework Foundation -framework CoreServices @@ -46,24 +41,5 @@ CONFIG += c++14 RESOURCES += resources.qrc -TRANSLATIONS = resource/translations/ao_en.ts \ - resource/translations/ao_jp.ts \ - resource/translations/ao_de.ts \ - resource/translations/ao_ru.ts \ - resource/translations/ao_es.ts \ - resource/translations/ao_pt.ts \ - resource/translations/ao_pl.ts - win32:RC_ICONS = resource/logo.ico macx:ICON = resource/logo.icns - -android:DISTFILES += \ - android/AndroidManifest.xml \ - android/build.gradle \ - android/gradle/wrapper/gradle-wrapper.jar \ - android/gradle/wrapper/gradle-wrapper.properties \ - android/gradlew \ - android/gradlew.bat \ - android/res/values/libs.xml - -ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android diff --git a/README.md b/README.md index 1abd8df..0416e4a 100644 --- a/README.md +++ b/README.md @@ -100,14 +100,6 @@ If you begin a message with `~~` (two tildes), the two tildes are removed and th If two players are in the same position and select each other's characters using the in-game pair list (or with `/pair [id]`), they will appear alongside each other. You can set the offset of your character using the provided spinbox (or with `/offset [percentage]`). -### Screenflash (2.6+) - -Placing a `$` (dollar symbol) at any point in the message will cause a white flash to appear at that point, and the symbol will disappear. You can do this multiple times in one message and stack it up with any other markup symbol. The flash will be silent, unlike the equivalent button. - -### Screenshake (2.6+) - -Placing an `@` (at symbol) at any point in the message will cause the screen to shake at that point, and the symbol will disappear. You can do this multiple times in one message and stack it up with any other markup symbol (including the screenflash). - ### Non-interrupting preanimations (2.6+) When checked, this will force text to immediately begin displaying without waiting for the preanimation to finish. @@ -157,19 +149,19 @@ Areas can be listed by clicking the A/M button (or `/switch_am`). The statuses o - `ic_chat_name`, which is an input field for your custom showname. Needs the same stuff. - `ao2_ic_chat_name`, which is the same as above, but comes into play when the background has a desk. - Further comments on this: all `ao2_` UI elements come into play when the background has a desk. However, in AO2 nowadays, it's customary for every background to have a desk, even if it's just an empty gif. So you most likely have never seen the `ao2_`-less UI elements ever come into play, unless someone mis-named a desk or something. - - `showname_enable` is a checkbox that toggles whether you should see shownames or not. This does not influence whether you can USE custom shownames or not, so you can have it off, while still showing a custom showname to everyone else. Needs X, Y, width, height as usual. + - `showname_enable` is a tickbox that toggles whether you should see shownames or not. This does not influence whether you can USE custom shownames or not, so you can have it off, while still showing a custom showname to everyone else. Needs X, Y, width, height as usual. - `settings` is a plain button that takes up the OS's looks, like the 'Call mod' button. Takes the same arguments as above. - You can also just type `/settings` in OOC. - `char_search` is a text input box on the character selection screen, which allows you to filter characters down to name. Needs the same arguments. - - `char_passworded` is a checkbox, that when ticked, shows all passworded characters on the character selection screen. Needs the same as above. - - `char_taken` is another checkbox, that does the same, but for characters that are taken. + - `char_passworded` is a tickbox, that when ticked, shows all passworded characters on the character selection screen. Needs the same as above. + - `char_taken` is another tickbox, that does the same, but for characters that are taken. - `not_guilty` is a button similar to the CE / WT buttons, that if pressed, plays the Not Guilty verdict animation. Needs the same arguments. - `guilty` is similar to `not_guilty`, but for the Guilty verdict. - `pair_button` is a toggleable button, that shows and hides the pairing list and the offset spinbox. Works similarly to the mute button. - `pair_list` is a list of all characters in alphabetical order, shown when the user presses the Pair button. If a character is clicked on it, it is selected as the character the user wants to pair up with. - `pair_offset_spinbox` is a spinbox that allows the user to choose between offsets of -100% to 100%. - `switch_area_music` is a button with the text 'A/M', that toggles between the music list and the areas list. Though the two are different, they are programmed to take the same space. - - `pre_no_interrupt` is a checkbox with the text 'No Intrpt', that toggles whether preanimations should delay the text or not. + - `pre_no_interrupt` is a tickbox with the text 'No Intrpt', that toggles whether preanimations should delay the text or not. - `area_free_color` is a combination of red, green, and blue values ranging from 0 to 255. This determines the colour of the area in the Area list if it's free, and has a status of `IDLE`. - `area_lfp_color` determines the colour of the area if its status is `LOOKING-FOR-PLAYERS`. - `area_casing_color` determines the colour of the area if its status is `CASING`. @@ -180,7 +172,7 @@ Areas can be listed by clicking the A/M button (or `/switch_am`). The statuses o - `ooc_default_color` determines the colour of the username in the OOC chat if the message doesn't come from the server. - `ooc_server_color` determines the colour of the username if the message arrived from the server. - `casing_button` is a button with the text 'Casing' that when clicked, brings up the Case Announcements dialog. You can give the case a name, and tick whom do you want to alert. You need to be a CM for it to go through. Only people who have at least one of the roles ticked will get the alert. - - `casing` is a checkbox with the text 'Casing'. If ticked, you will get the case announcements alerts you should get, in accordance to the above. In the settings, you can change your defaults on the 'Casing' tab. (That's a buncha things titled 'Casing'!) + - `casing` is a tickbox with the text 'Casing'. If ticked, you will get the case announcements alerts you should get, in accordance to the above. In the settings, you can change your defaults on the 'Casing' tab. (That's a buncha things titled 'Casing'!) --- diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml deleted file mode 100644 index 0792ce8..0000000 --- a/android/AndroidManifest.xml +++ /dev/null @@ -1,79 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/android/build.gradle b/android/build.gradle deleted file mode 100644 index 3087d08..0000000 --- a/android/build.gradle +++ /dev/null @@ -1,62 +0,0 @@ -buildscript { - repositories { - google() - jcenter() - } - - dependencies { - classpath 'com.android.tools.build:gradle:3.5.0' - } -} - -repositories { - google() - jcenter() -} - -apply plugin: 'com.android.application' - -dependencies { - implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar']) -} - -android { - /******************************************************* - * The following variables: - * - androidBuildToolsVersion, - * - androidCompileSdkVersion - * - qt5AndroidDir - holds the path to qt android files - * needed to build any Qt application - * on Android. - * - * are defined in gradle.properties file. This file is - * updated by QtCreator and androiddeployqt tools. - * Changing them manually might break the compilation! - *******************************************************/ - - compileSdkVersion androidCompileSdkVersion.toInteger() - - buildToolsVersion '28.0.3' - - sourceSets { - main { - manifest.srcFile 'AndroidManifest.xml' - java.srcDirs = [qt5AndroidDir + '/src', 'src', 'java'] - aidl.srcDirs = [qt5AndroidDir + '/src', 'src', 'aidl'] - res.srcDirs = [qt5AndroidDir + '/res', 'res'] - resources.srcDirs = ['resources'] - renderscript.srcDirs = ['src'] - assets.srcDirs = ['assets'] - jniLibs.srcDirs = ['libs'] - } - } - - lintOptions { - abortOnError false - } - - // Do not compress Qt binary resources file - aaptOptions { - noCompress 'rcc' - } -} diff --git a/android/project.properties b/android/project.properties deleted file mode 100644 index a08f37e..0000000 --- a/android/project.properties +++ /dev/null @@ -1 +0,0 @@ -target=android-21 \ No newline at end of file diff --git a/android/res/drawable-ldpi/icon.png b/android/res/drawable-ldpi/icon.png deleted file mode 100644 index f53fe30cf7553fdd4ebcc0d61070c949d833a7c4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29302 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 diff --git a/android/res/values/libs.xml b/android/res/values/libs.xml deleted file mode 100644 index 6b1a4a2..0000000 --- a/android/res/values/libs.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - https://download.qt.io/ministro/android/qt5/qt-5.14 - - - - - - - - - - - - - - - - - diff --git a/base/sounds/general/adminhelp.ogg b/base/sounds/general/adminhelp.ogg deleted file mode 100644 index 704c0fd6d20fa552c750f19f606847e2dff1beaf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17220 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 diff --git a/base/sounds/general/case_announced.ogg b/base/sounds/general/case_announced.ogg deleted file mode 100644 index 1e9c3d4e6c5b840dcd19b50b9d933610e41e5103..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15790 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 diff --git a/base/sounds/music/failed_login.opus b/base/sounds/music/failed_login.opus deleted file mode 100644 index 33532ee54fb3d4686b67bb8c05587916879761c0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 396160 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 |niBBXC`Rp722;K@P}9a{G@I@c-s`6M-2=N- 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­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μDJV* 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 z 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

vY{EWse(*@2(A|HF=`;Gf?xtf#H_b1ZOC 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 X*DLP-_bW;u?(%)_wFv&dexv^ZT9FG> diff --git a/base/themes b/base/themes deleted file mode 160000 index 6e1317e..0000000 --- a/base/themes +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 6e1317ed93a9a4831047aa151c28742b1dd8afb5 diff --git a/base/themes/1.8/arrow_left.png b/base/themes/1.8/arrow_left.png new file mode 100644 index 0000000000000000000000000000000000000000..f1098c49b7fff15407ae2d9b96968898134fa106 GIT binary patch literal 742 zcmV004&&004{<008|>004nL003F*009yY002DZ000@zy2&Ck0003i zX+uL$P-t&-Z*ypGa3D!TLm+T+Z)Rz1WdHyu&tqUGmw1*$mUCju&;pFNf7oE5W5KI2_X9m zNPRk(&BOsV2f~&Cu}e}bK=v{?=ND8KWu|A8C>UB=S}HiEH; zLN@>a0RKruK~y+TV}ODG|Nm2jQ2&w~`A0CaUk8wkQH3ZnkMx=W=-sFbi_ zczb8r{~w<}VTfZjFj*Q^5iY!YVgrU4NH2zgFhj|~F#TWy(aS_~G2Ad100~fnA%KAa Y01A3evDIW@ApigX07*qoM6N<$f-AupwEzGB literal 0 HcmV?d00001 diff --git a/base/themes/1.8/arrow_right.png b/base/themes/1.8/arrow_right.png new file mode 100644 index 0000000000000000000000000000000000000000..2b5ad70d1db7dbcde655f4298f0504d8bdc885d4 GIT binary patch literal 730 zcmV<00ww*4P)004&&004{<008|>004nL003F*009yY002DZ000@zy2&Ck0003i zX+uL$P-t&-Z*ypGa3D!TLm+T+Z)Rz1WdHyu&tqUGmw1*$mUCju&;pFNf7oE5W5KI2_X9m zNPRk(&BOsV2f~&Cu}e}bK=v{?=ND8KWu|A8C>UB=S}HiEH; zLN@>a0P{&iK~y+TV}ODG|Nm2jQ2P7h9QoQL3)WY5ClHIe))e>LoS9KGA7AD5P0|G z!T+@t$r$o5OtOI>@bb>}|0@b2G1P!CSq6f@)2rwHFU|oN)(0~5GL6`swSJyZ-5EAkxB{s$LCM~w|A16 z^^&DA74DwcfFXtrgY;q;2s4x%4AT!b5WP$!7sCyM0gwPC7y=j=0IYycv5body#N3J M07*qoM6N<$f+-Xm6951J literal 0 HcmV?d00001 diff --git a/base/themes/1.8/chatmed.png b/base/themes/1.8/chatmed.png new file mode 100644 index 0000000000000000000000000000000000000000..0c3bae1e16eba3d6c0d930ef025eda4dd88c2ae4 GIT binary patch literal 505 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5{5aTvXzqQo_#Bsf2;hmB~Pm!Rs4C$ANAJpeYY*nM!ZhADAi2^x#APGmQf` zb;|2F4oJwyI~*2cWNc7iY%my7XoEeY0At3DZ~NFD6z!E)VwiJ()6dl3*$mq_7lvNRj2{{@G6?fzia^>FVdQ&MBb@07ERCb^rhX literal 0 HcmV?d00001 diff --git a/base/themes/1.8/favorites.png b/base/themes/1.8/favorites.png new file mode 100644 index 0000000000000000000000000000000000000000..0eec611403af430dde0a157536cc357000c432a3 GIT binary patch literal 1682 zcmV;D25tF?P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02*{fSaefwW^{L9 za%BKeVQFr3E>1;MAa*k@H7+qQF!XYv000I7NklBTF5XTdw(g)fCrBIGa z1*Adjg?IR@Kju#M`I z`in1>Y4mA+Dn{ex$D~q0<6wP;G=?%weIi`SdKxp8p9}dZoM)O!)Y1BB?dqPOEpwABxP-03Z`1~}Uqz?}KjlPjObWy{7ML2t+pBS-eY?Ya#m)&OIN_CO!z zjCN^0jmrkPIk-L$f|;Hp@N0N)i8a9N=|gaHpxKhp^iw#~;)Am_Tj8$%U1v=C*E`}J zHw4@<5!?nt&HHUT^f~l3Rl@Lr4`9-_&U4Q1E_)>=edVtS>f6rBIjjxFD&B*^FFvy* zH1QOMLP5A(zZ0gb)_D%ysA5K%>8kSA1odr)=eIP6<>czRqEx%%THSUS4f$-3+?Q~z zCj|Gq8sI_aC!Qm3m<>}qSLpMglIN>y-xThjs)g&l$7~6W!az$cj0d;F3~pzykvGUx zZ-TTE8M{@nQcJ$nNv*DDt*&7>&hwRVy$#1Cvfifg0(uP{Y_{#tObj2n^>D6o6HMW2 zj@Qt__y(=4Bfk*VOXC~F*Csv3*=Lh_sb!Nf8E2zdv3^bUWJ-gNW3L%KxCusDgP714 zg$d0>o?>M^d{egz?j9`j99}4urh19gN;t+P?KE2(c`bdZB`c=kI@`S1x7EuSX}si0 z;||POEuK8?!;i}Ntt6od)iW|+q8dkrtvW>n8Q9ceN~rR>{Or;l&b=&{v&9T}I` z43FV8=lmP-b0|J?gVa3Af{VueeyV1%{jb01Kwq&}0;D^t8jh4j=p;{?v2i!c6syO{d4D&*iJO zH)-@(G2hgVvDM4C7fg3n!j0aLWryNxC_RraR(%Mw`1adtyIv9?L5(_%|)>(AX36Yv^E8051DK!tGq{IdWm9dI@W#ncA<`r`|`g zc6y9`wqkL;A8ESAE5-wxVW_FvvP0t$^^NH#$E>#wOe55SO6d~XGkc14!wH14ep17@bIg>&iKs{4_py; z$4pl>eBIq@{v4W$Jb^ykp;sGr!DMB*GroV@z(=7gE*;*fep{4Y_{*?EvoRQIYrwa{ zAH!7DdS~2q#H1^#-EqEdD~z-^;tpLXOlU4X4}JI{b)tR;e1{Wr#kX%8c%xl0-nbJ6 zTI|!kR<6?fbi+afbjEv6*jE|wN>;Kr c&dSRE0l)nv;^LoU7ytkO07*qoM6N<$f}brc^Z)<= literal 0 HcmV?d00001 diff --git a/base/themes/1.8/favorites_selected.png b/base/themes/1.8/favorites_selected.png new file mode 100644 index 0000000000000000000000000000000000000000..f6a2abf886559deca23a0a21d5e96fbfac55748f GIT binary patch literal 2238 zcmV;v2toIWP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02*{fSaefwW^{L9 za%BKeVQFr3E>1;MAa*k@H7+qQF!XYv000OrNkl19@zgJl4b{8nWz07X+p=QY%htL$Y}+i4YJWW|I;@ zk*Sf0Py%6#Nka)Cg%HV`&0`I1e!uT|-20pR$m4_r z?KZVyQ#9&|^f*_MiLVReP`^_PM|lF8_v!J^Jt;VDHK1YtHu&X1Q_0SKY{scwdiwi^j58oUm$f(w2m#gGPMuR~=~W{PHoQf#y$Mhx3F9Xxsvv*+h5?_+}%#^&5aw z+WkC>U)XrCH^RBZxVl$9`_5}q-`Ie*AMCE zgT^R+|0aX<_mV!oG3j{2W37kyZmOj*I;|*Ft?a zS*M4#L`Tn`p1bdw5Zwr!ldQ=@psjmotfhVb56&OV#ps#s!1>J>J(&g9SDCJ-H2SHM!%9dZH``R}W>N=d&bS+P@l(A`M!0t-z%ZSE1DwgNwGcXevoXQ@I(x zez&V?Tv)&K-&q|8U6n!Z>HzErO0M&-gV=4c5-S8(n29fg`E7u#0<# zo-19CL3;|CcPz#Fg|lD|yF+p4g$iU;V-A~ki=bo6!`3&p2BElOT|nllN9uwH(6ZwN z4B3-#zBEB7=y$bSfiE}1Rh^AZQBR=Y#a}26f5GIC>Zcasb$;uhcGo2XT_!w>Zv88h2`Q=Z3hXXgH-k~lhGNONjx0cR9iRPDz!=IQ` zo*}0b$9bQ%-?zV%MjQ*|OZ8*O<@vZ0m|qM<#>(eq?ojd$rO)G}u%E#~KEIWQKQXC1 zgV*seqsLO(Kw~g}!ed!xEZ&!k@xEN1kFmLwA|ZVG*d03b-S~o@DbGVwMJ~=;4Ok!k zb8o?M*XV-bq# zC`m(CRW@3S;-HV13G-v*D@tMLNm0aclMGDHU@As9oasYdSY26+^!h5o5o=-9a&uBrrFD30d~nt&0z z9zEqRlTYFMVG6rbH8!e*Q7z`GNBn{r=r50f+n$J4Te48le--I{e-CXhj)rdGgV;b8 zrWQH38{|T(MdFjQaK##hp-*%;`xovG?XKAde6<7XDStUS%42b{EFKP9Dzr-?f=mMa`=pYb`9Ozu z+j?BJYH_VF8rO@Wan1S?F6S?Uvyyz_9y8)Xg#mxhPZtVG|Be1cVG8uddbIzNTY@7vq6&Vc)G zucEgy4Oc6(aCUd5^!}EUWm&jU_b&QA--0VuMzmGtp!4t+TtD^>F4`^VtjizYDQLIc zu6+7F+U;A>`}uZs*1V05Dl@KCn{dsZM{4yR8uywe7BgtKi-m;z7d7oQd%|)_;{X5v M07*qoM6N<$f+D0iQ2+n{ literal 0 HcmV?d00001 diff --git a/base/themes/1.8/holdit.png b/base/themes/1.8/holdit.png new file mode 100644 index 0000000000000000000000000000000000000000..09d1d37020bb85d5d28e6d791980adf6c1fd552f GIT binary patch literal 1983 zcmV;w2SE6VP)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00009 za7bBm000ic000ic0Tn1pfB*mh7<5HgbW?9;ba!ELWdLwtX>N2bZe?^JG%heMHD!e| zWdHyN5lKWrRA@uxn)^>wM-<0JE2&ihO%pXHYJw)l#Ay6Me=uq^{?b|>ty){FR$HyL z@qx6yiq#6f5V44$#W%GDk@8Y28t{Pv3t0Z9>G{mg+0I@rbQe(*y2;1AGiUBRzW2?(QBGuol+jmN>AV!6ue6V4_LPvaZ_E(J}PXAw$en z$0gy%nKMmuO-^}+g z$#u@GSv}ez81_zqKKEs2#%wF4toZjZrq=HqJ2uXy+`oR^6pEd-X#ZOTJgu`cl3G<& znd&4+{G+EKF8f$GBONkn22j@X?M>vu#*L=dvws(``$V2UH-}t1CVXJ}^d4=ugV&o`Zsh_xM)>+4e2=xoacy$|kPxnj;y=dnrfx2K$*iHpW@ z8;n_JSFJMl1A~+bVvD$TVS=$mUpPBkmu>6Y z!50ixdu`}{muK5He0a?El~?~jzylj^-HO=(4bVeG>pkrdu|{d0<=+hdCD@aO29xXA z@V>88QhM~Gtnk`a3JCVsjT@%w^l7tG%4>v|&VE4XY;TXdzbZf9>>fAH+!7nYW(hk+ zjf!hyP{{Mli=t zKfejw&z4mD_(vPY=M=YF+p$g9%(d5V5EV@{ih5bpvwFs?AYp>>bT4k*YV8Dn73`V7 zle@BOm)Yy;^xiVTpEP#LcoF4lSH9`W2zM(gzc5Uxo>utVZY+vpW(5mt5Tw1O#pWvh zL|7=tH`}Jg)d7OB0JaKcVvULvCYVhb1Qv`9R4@WNi7s>CK)^$oi!azG!Y}LA*>B3H z1x`t>$sg_ZbnEa1dsJB&t51Za1Ou{Roh1C=UE@W#IoE#(Ec#D@_@N?T^9AFzM6cOS zJ6w66tAp&xlkLK4i;K+(DU-X=CePVHGkRhd50Hdb#iJdGH}{{Cg8{+s34UIdD6cG- zazS7b8p8;{-%pv+t6=&{VUYzYgw^C&V-liJ%FdM-SZYLGUw%+44!#v z8w4X?<9@siL5Y`dO)$0_TdLvGrI=uBhte%utYG9)ECNBWAsBfV*S=sRv23#^uB=ej z1Q*XO-moDqB_VcxE6|RyNFRu|d}HT8z=l`xAQ_L8r0wa`&^7i&(t;h7SC0)cm`;{0 zh&T_*%j41twgc$~f@xb|LBtmo4De3B4d9g!tVf)Ryga+`hh9C9vS2?tZ=Rhi^Wt3+ z8)6|8p7>O-iEChOiIB8l5ELvd56c&rU{J6&fqFmo9rLb%WR-(}WK16LSPcU0->6_@$olJrgF_>m#n7HYyn0lpIg{*gj%}X{xR^FT1*8cAyUMHattmAcfKV zF&X+L*rVIGZJ=e~pkM@3egfhrmy-hCNRVYqkW~lY^%S1C5`6#kZGL?+Xbz~nu~QNd z>>C-7Cx&3W)N*XMKYM1qf@2>~+m@PY9@o{`i78?Iy$KMEOkV}d5&A6{Z{%Ud-stM+ zFvk}!Hg{!E^`!dJQfuSAk(>!y8XJ4u`?g?Pl7HdxKx*=$sVTH=U)WzSlJzh+w`Ps~ zQI4lY?xTVYcA_4ZHYU{A7i7))p7?(f46Uq(MIsSXTU(nHoLabcPG+XLQ&ADxW-x(9 z*2DNG%4qi;B`qz@erIHijg|xd#jo~PCw^QA_8l$%`{xM*`R4|Sp>s?({{SFz`ixcC RM#lgE002ovPDHLkV1kyyvZDY1 literal 0 HcmV?d00001 diff --git a/base/themes/1.8/holdit_selected.png b/base/themes/1.8/holdit_selected.png new file mode 100644 index 0000000000000000000000000000000000000000..51586e748d67251f3c7e7bbe0b2485b8816bbd93 GIT binary patch literal 1835 zcmV+`2h{k9P)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00009 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 Rv2_3d002ovPDHLkV1hJ7vETpz literal 0 HcmV?d00001 diff --git a/base/themes/1.8/takethat.png b/base/themes/1.8/takethat.png new file mode 100644 index 0000000000000000000000000000000000000000..8ff2befe32fd104826f57b8778c921a643de878e GIT binary patch literal 2057 zcmV+k2=@1hP)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00009 za7bBm000ic000ic0Tn1pfB*mh7<5HgbW?9;ba!ELWdLwtX>N2bZe?^JG%heMHD!e| zWdHyNTS-JgRA@u(n%h$pM-+zvuVqCRQpOjxykDxU(kk`E2OsoFlbDOSnHWvtC5ott zf)FDHf|yX=qJZe0TYpdye@E|mAApEv|eX@^lj2bm~(IjSBSB=GDS7M}!MPZ-5WEdSyS8bfbW1u8nl4E-W;=r%w;f8wlTe{ezzb#%KpVm><)SAQ}|w z`iT>E@NiG)6kL&%?}VUWJpWSIF@C(yW`7{qX{m=tgylaA*m!^)k8^@f&v?9RWPSam zk)8zU{}5|JMwW?|mYSwhr%X+LzS$&(q0DOt9t%w#tAtG>M)+_$s)7NXW-7-!JCpg% zXU`_vfW2eJnD)DOZ61Qv%CneIK5?SyXlqN>3v%!3Rr9fw`${Mj=zn)CmdLwy&1{ip z+7CFzRr1`JCaY)qqOsgk@gp%*<-uFf2JQ&uLR_d5_RO7Ys@ASGmntfJ9S`CPhPWGt z4>x<~&$oFON=nReCm-uO9B(Nb?aM6B0zpG76y_fs+W zyJsBFLad6VOU*tB+^Gb6(%o&2OPOZL%NITuPRgoe2QM&v-x09O0NxY+5XeKgwE|P` zkwAS0h42W5s0bPqjFtDwp+i1)NjViJXq$WblP}|S?I>t~7U&`|?P<|;8md^z&1lqo zAcpq|bo%(3HTJnH*jB0M*4a02o@tQh+EKieLF+w1-+G=0@k-MSsKrZf7fJ+z{Z;|N z@VqS&+uE9&eQlP_nq|vHFbXVPYv=?d_)X;X_ML zPmg`3g7L<8I}PuiF(Wyhbm@K;!Fc;DD(?zAgl;cQeHE-^!GdIazzfqhvAxktyD%j$ zmX{|5<3*p@w#{cJ3>8f@N_bhqvr_M~QlWy;xW<{bn>S6F1ad_DQBaXw!R`u7bJBPc z3yTWI^h9JpxQ9X>_Y)?V1Iw0K!OjcY$Bi>}Wo5R_s&(t^6lZ}TCL%U*5katxT>?9G zn5HTi0$!6C?T#rG3DNA?GqcYfd|x1#^(+Cwis#Hp24>zi0#ynf!Upf2vPXqqgjNAB zV|8W4yd;qCf>>pX7u)u}mNa#+!}P2cXtOdi)5f};0)kPGX}NRKq-2{2Rxo9X$u4I}|SuY&O+IDz1G+*5|K^asI$w$tUg3WgAfqJlAP$h$4D*~MEZ5A6c+YS-k+c27hw zX2ZE&*gSf4vK;l9?(7NKU%7(m76MPDJz|;r0)Xc%UMsl|8Bc!=Eb})D#y# zHI{T3v|zd!)K2~Cq{FZ~_vOp&pa|-$fGhxcW5-&1tj3r3@3+&AIH)TygZy6LWZ}LH zdro!0UXRBC0Xquy5E~I$?So@Uhd~Plu3%?`zn%Mw-c_fj3U+YiN_*C00Bl2|d3lx} zr%w#qEFc*5*r`M8@ngGLB_QKLY76uf;R>cfAG@3mG=^cDRa5QWZ)mXX@I8)| zS#7hG*^!;?8$-GbiC`RSSmNo74vMJ)4abfp)4*E~v%%Md!;;SwLYzNQ7Hui>;?T;Z5j16Q^u&{D{alf(AdL|zs5l97ND&u{m5v;bf^eMs0 zmn;djsUR3rRZjwV^4p|C%J#=gBN!kWv4%ss3I?1ExU$tius7w(6yq5i;{F69UKP!p zY0Gk=z#Fd~J{(%MKdfM!$ip(zg?NFB6VOk19SSR#F7EL~!M1+0VkKn@0jZ|=^TK|; z7_5iExuPN)%;9!zZD^Tv(a$n$5fF=g7}JzC!pgr$5+0VF8=CoF!4xW(I@KO;*st;Z z?XQ}e(6TQYw6Y%7)zxJhC5HS@YS74f82=;~>s=FM%U*?RPR{Fz`@nzkYyRNzw+lhr niTi*5JYgvR+#o%)j}h|^`=|ZHVemoH00000NkvXXu0mjfqw>jh literal 0 HcmV?d00001 diff --git a/base/themes/1.8/takethat_selected.png b/base/themes/1.8/takethat_selected.png new file mode 100644 index 0000000000000000000000000000000000000000..3fe0a8cd13fa0244f7b9c87076b6f24cef43ba57 GIT binary patch literal 1932 zcmV;72Xpv|P)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00009 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 literal 0 HcmV?d00001 diff --git a/base/themes/default/addevidence.png b/base/themes/default/addevidence.png new file mode 100644 index 0000000000000000000000000000000000000000..7a432af2d7e9596bf8c7ef74501b058b2a6a1862 GIT binary patch literal 403 zcmeAS@N?(olHy`uVBq!ia0vp^ZXnFT1|$ph9<=}|wj^(N7lsTF3|;eu5h%i0;1OBO zz`%C|gc+x5^GO2**-JcqUD+S9ii#;ISk3udz`($$;OXKRQgQ3;9mTxE4gziuw}(3D z2S_|_ZEI|8wL2uIctGL81_cH88_GW=K^9=3V$rPS?1dPrM)jAzhiy=@-D`VZL+Vwp5B)- zqfp{@L_R~srs8$(5{WH>ZgAolM{#jj|G&n}S+}yEhlajgD-rDpl03$t++%PEM5Ov& zzwdi;|KGjyXPsIL);HsSjrQGY=^xLswK;(bkPLhID=>JcC`{)e4+W?h^|tZn`Tj0U zmN~X9r6=Mz_nAud%XgL>*%Y$u$rnrJ;{tl_=k?w*J&<6qW4w38a@F&8zv;l>WAJqK Kb6Mw<&;$UY7M`O3 literal 0 HcmV?d00001 diff --git a/base/themes/default/addtofav.png b/base/themes/default/addtofav.png new file mode 100644 index 0000000000000000000000000000000000000000..7d9890347e076b58657cb28c8339fec4b83f7d3b GIT binary patch literal 972 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 literal 0 HcmV?d00001 diff --git a/base/themes/default/char_passworded.png b/base/themes/default/char_passworded.png new file mode 100644 index 0000000000000000000000000000000000000000..e79d0710bc8d9d7414b8fdcd95184c88fb429e35 GIT binary patch literal 1904 zcmeAS@N?(olHy`uVBq!ia0vp^HXzKw3=&b&bO2Hc$sR$z3=CDO3=9p;3=BX21L>Cx z45bDP46hOx7_4S6Fo@?*ia+Ycz`)E9;1l8s)FUAwU}0eq;K5K(P|%Peuw#P8iwzD7 z7A*L1q2a=X3qOAR0IC@UqaiRXLqK=+%_as0Muw6gzu^BP8!!ZaX9t!W44efXk;M!Q z+(IDCcDP; zlYQ=73NsWw`a8Sc(e=s~wV4q|eShX1oqt7~!{(*0(Z(*{NdKe1FK=K7ygZvNNz}fj zvv%R05AR}+*tKmxe7)-qL%6cKe4{H*Vg>hisadkWcza*T@wOyKeo@-Cp<{7k;j&es zTQd&+w`@JRMwao^rWdm#W|>dc)ad%>u;j(9uQ5j+Oj|2qE0iIb#g!}Lqcop;Z?1aY zI=^?OU0Dpplhk@VbYC7=n-J*YU*NI*@Ps7pjR#+tlum70q$0b+-R+c;LZEcsirg8; z&(vO6oGL$4h2L$ZhQk8$VvfUIuFWfN>uplb%uiSNa&!0Aw#hf6H{bJLbIhMpStawI$d&1sG;Vz%pkSZOJ-aS!^WhnbBbtI4k3X}KuJZaBGO^rsUh%esSzivT&5Z6;G4a*zXSuq9wRcY4 zEtTm)3>zQaIvjf9X6n%og_BJtJ&VY)-#PPq+|N_TLblZ2P}#A}W2MZ(y+;CyZ=R9N zn=py*4p*D8@eWtVBNLzGo|T^CKIzsY=I43UDrXBP&xkK)JZ0*_=6%fcaL;U(!+td% z__`B5D6iWy)70E^p=`N?pVy_v=z|;jKk_SIOKZ9y^4Pi2caz0rKAog#&pUS-YVEVS zaPDW*66Wq7iS-8Fr`PlC6P>esrUx*J#m}sZYqYq%@zZzKDGMC0e6pRr{)8XT*E?dL z)4y}x>Pp|0A=J=rvOht&ZPv?0o*wnT-`?(&oZUSyymr>T4WjzF{)er|!(p3wjR literal 0 HcmV?d00001 diff --git a/base/themes/default/char_selector.png b/base/themes/default/char_selector.png new file mode 100644 index 0000000000000000000000000000000000000000..e868cdb97b5b26084b5196183f4e6ed15e664cce GIT binary patch literal 285 zcmeAS@N?(olHy`uVBq!ia0vp^b|B2b1|*9Qu5bZTY)RhkE)4%caKYZ?lYt_f1s;*b z3=DjSL74G){)!Z!AbW|YuPggQW+8SCwaw4x83Tn@dAc};WZZju+feY3gFxHGy&jD0 z4J?mZ1bk)qe0=gRyKgc}(vDIKe;ke`|#^-M@G(8%~$-HET2 z`3Gf>-&I_es`s>NU(JQ>$D^{`=6^eW=fmA^Yh?dszgcv#v6*!6pYwjwmRa9(bIdp9 cn69d2lxH)peB>DO3g~JEPgg&ebxsLQ0N~(rng9R* literal 0 HcmV?d00001 diff --git a/base/themes/default/char_taken.png b/base/themes/default/char_taken.png new file mode 100644 index 0000000000000000000000000000000000000000..efad48dcc461474c7349bdce3fe0919497eb966b GIT binary patch literal 215 zcmeAS@N?(olHy`uVBq!ia0vp^HXzKw1|+Ti+$;i8Y)RhkE)4%caKYZ?lYt_f1s;*b z3=DjSL74G){)!Z!AbW|YuPggQW+8Sqk*Av<*#d=9JY5_^GVZ;-=*Y`pz{9*TL~8W} z=`Vpd_S>N_d)@bX*^VKtu_28oASI7w$bd@na+rpl%ERKqnu`xrc3{an^L HB{Ts5v6Dkj literal 0 HcmV?d00001 diff --git a/base/themes/default/charselect_background.png b/base/themes/default/charselect_background.png new file mode 100644 index 0000000000000000000000000000000000000000..4480e6f454289a99104a1c27d9074cdd4adb8753 GIT binary patch literal 5342 zcmeAS@N?(olHy`uVBq!ia0y~yU^)fFb2ylRBFE>5jgR3=A9lx&I`xGB7YR z1o(uw0>!zxxf2r;Gcz;0ySsthQ7{?;BPRq--<7!n^etzBM`SSr1K%MKW)#)%Y5)pK zl(rIsj|=o#vn2s>mPVPFsp@N{tusfc@fb7S6<2odIs zx!eE$pIy$jA(qX@Fhl!+&6Sg(=7~x#_m{uq@QZ9OIAzrmd`)rACccMLN;#IVakfa6 zJ*4?sfJRa-Ge3QP>w3Pwfm8VY-B~|gR-HP3yk5VmM$RPh(QIqsgHNZ#+kY>;a713M zAYN(boKLrpZ`Q9g{&5u_FMcYJ=fBi|IUZydT?F+zP%mAYCaFH9q~^+b!q<*l(cecN^QJZgTe~DWM4fl+uUP literal 0 HcmV?d00001 diff --git a/base/themes/default/chat.png b/base/themes/default/chat.png new file mode 100644 index 0000000000000000000000000000000000000000..e11f8c8aaaa1b2c283b93acb5680737e8bf7eeec GIT binary patch literal 1529 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 aS$6Bo)$!*aJ#v`9OzxW6`R;8GANUWu6Dm9a literal 0 HcmV?d00001 diff --git a/base/themes/default/chatmed.png b/base/themes/default/chatmed.png new file mode 100644 index 0000000000000000000000000000000000000000..d2fee4a6879146c729412059498912857e633b83 GIT binary patch literal 1669 zcmb_deLNF*82@dvS<}`M*V4K%qPuigEeXZU6rb`o4IyuJD)(uW3<(?3dO<#yjNVi? zZc)<r*BBLJ*)02Z}690P!c z1Q6o@0POPtSR36FNVp0B!oZ#Cd@!L;^@X!-V4Mn zMtM=u)t-)}XPercfjo@&#)`kA)fuZ;WTCp^hS!` zi?rZ1hMk+06N|z}WFTJ}NCJU8p*mbJbbnW@7UJzXhH$u$}UCbJkP7B=GFIZkI_#X7CJi^ zj<71jAsWI|R-5xc`Lxh)B$KDv>Ln2Rx_isR$#^ST;%()roR8(&y)jI9eGp-~aZS5C z9Y?_5a4M#d=QjOrSOdSQw~5%`yWkIb#IAba?1ZjlaMOh)@)3)Hu8!>d)y}BQ=>^UQ z#qjz3J*V{E#nwOg(2}Wze5!gfBTwiHy)AF+3Ja~SdbodusBN0^h09HmJ;}c|%Kx6= zZyOJ5L5MX|aDfqAtlUEE{vKdv*_uJ8L&1kX{CuIlxzq8&^M>+>to3UuA9lKrFDKV0 z7Q%#H0igV(R9=QCoIkLT+;p;Q@hjOwyO(LTE~m#;h7dWh?lGoJ4ovKaY~Tp|_6 z#UAQAZ{4lpw$43{wiTRk*v&{9)5t{u6?JbiKI`Z5`2bwPN@jM#S|oT1`@+HErZ*en zt8){h`V`cqCO-5ke-!``ub>RGHWBP|`(UABuI&N)$ipQG32I*JaWo26R3mA^A4l6t z5H90zYf7f?(dEs(IX3$J!wZB!{N-0&R^UlHsz~{_|7ACv@xa7z3GBSh=8S?9*UEYQ zokrwhKg`f1Bp^w-(ednGy;Bob>czwAS}Dw5VE6+2^vLOLtrLdka0Q*^(hPse-kVy` zEM&YejKPfggshrcS&n2vnHmiFKznc2PTNqAK@Wa1?*8KvjMjDv-9dVK8%i#=0iNC| zf77!P=vLekO$d2_iz<`ZtNMRh3xC&T=OD+63n$}A&CKx)adC>A@e;L24EiFOMfYbJ zV(_d-not^QO&iS*LbLpok{q89bb@7;Y94aTckA0h-pmOL#?va}mnmCzE5G|wqe}M5 zvyb7G`GM#27{;iQ_9{FoeUSZY-QjEggi6{jW|WK;hVTnkj0M*ud`f$bBODG5O+6hR z9$sW=H--I!;fl&w+IU5lrfU63)O^?8pAMpP_TCrBC+5~wyt$i6-m? zQXq-5VM$a7vcQ(6$7!833j3X})1DCf^M#b7%pP!02azS9dr_RkkxW9#)JPk!*E|_c zry8?3ts$UHAh_f0%V|9htgWqQWky7j2}r!XN=E`=|C;6lI2>Jr|61h#D;a^Hl`;#W z@5%jy_R=iea2~eaMFzQ5({0(*U;AD?-}9D1>^5sm;PqAVcpJs%7N?i%N}^113rr8z&GgBgI=$piCAJRfVfT~Ajaldk(?u7t%S5N9AN?6)I%^vir literal 0 HcmV?d00001 diff --git a/base/themes/default/connect.png b/base/themes/default/connect.png new file mode 100644 index 0000000000000000000000000000000000000000..6a41e86fbd39453ecb68bc042e7b1b8f57b89170 GIT binary patch literal 914 zcmV;D18w|?P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02p*dSaefwW^{L9 za%BK;VQFr3E^cLXAT%y8E;(#7eog=Y0|QA!K~!i%?U=D{6hRDz?@=h}fQl0CEr5;+ zQPSNNloaU@1qGrYL?|Z`i2@XmAb=pENP zF|>z6RKy_g{pYD;gc4@3Qce^;XK;~2Z@NmdrzNaHv(Y2 zFyxVto@(eb?zy#8BVpBIUmmm6rb3PJX!Z(@f&(3#m#w{7=c1fOKw>X!(Nm4~oLj5G z>#&!VKD9BRDS+9b`!o2(pZzb(KQ~K_`VxC#i=Jw@-uLdyXfk+wKDDvnoN?}_ zzt7<4(bCV&QgJR~FKp3M4cGhLeL0`jhtwyAKDDWEV_X=bv=NZl3tRM5Bk8p~eNNG8 z#ArEvYWsqwSW81d9tr8GM$^+c?m4s)RxS4BF-vU;1~CK>x-`%G^j0m6uC-aJf~_y@E$x*)DQq(o-gfVNP4bCO{fR# zDcaEDy|g;6<9aP$lEDoDz{NR|4hd;}IfQCbv>_}#xCXIkO0gD(sH_jw5EX}Nh>Als zM8%;RqT;YJLrkvbWvX$-&csUFcO8+wb6*@oJiBwfc{#nk61FF|HWKNsI}u3rs{}mI o8DcZIDR3hKsa`r~lNmSv0i-pe)B8t#HakN^Mx literal 0 HcmV?d00001 diff --git a/base/themes/default/connect_pressed.png b/base/themes/default/connect_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..a99d9ec119c357bacc4317b56268a8cddb903c35 GIT binary patch literal 925 zcmV;O17iG%P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02p*dSaefwW^{L9 za%BK;VQFr3E^cLXAT%y8E;(#7eog=Y0}e?)Lr<8yBd47Oo%a#DZso9DL*8Q}BXKRPr=j`xrX z45p%uaI267ZH%A4=H~eEPGW(OM71|?r6KWeviVFZE?g032L05UGoT8^O}GEdhOE#JGa)k|Ex zY&rSeVqjAcyPrm8rFhQ_3^LLPIm{4}cj;YPR3qc5TB)(&)7$dCx>R_7yw9)GiCOQz zJx{08`ne8D?(e0Tv03%< z?i&w#>6%^) zLHLH&d6zy^E8~3aLTkgPx8;3xIqA(1gdAMsJ1B|PqL|LfJ}Fusx`)ooxO}Is(Yf68 zY6yad*VqmN>9v+Mz8-W<(fZK6Y;{_v^|pLYdN%|?gKLnE@o8N-Mru;DK0YkKZ%M-tJJ&B&_qMOC zguBD58wr~Ae}X(v8)7rK0=OIjsz>kHWCqn=Evidence meme +evidence_button = 627, 322, 85, 18 +evidence_background = 0, 385, 490, 284 +evidence_name = 112, 4, 264, 19 +evidence_buttons = 28, 27, 430, 216 +evidence_button_spacing = 2, 3 +evidence_overlay = 24, 24, 439, 222 +evidence_delete = 78, 8, 70, 20 +evidence_image_name = 150, 8, 130, 20 +evidence_image_button = 280, 8, 60, 20 +evidence_x = 341, 8, 20, 20 +evidence_description = 78, 28, 281, 166 +evidence_left = 28, 0, 60, 24 +evidence_right = 400, 0, 60, 24 +evidence_present = 165, 247, 158, 41 +left_evidence_icon = 13, 13, 70, 70 +right_evidence_icon = 173, 13, 70, 70 + +; Character select widgets +char_select = 0, 0, 714, 668 +back_to_lobby = 5, 5, 91, 23 +char_password = 297, 7, 120, 22 +char_buttons = 25, 36, 663, 596 +char_button_spacing = 7, 7 +char_select_left = 100, 5, 43, 24 +char_select_right = 146, 5, 43, 24 +spectator = 317, 640, 80, 23 + +; ------------------------- +; New in 2.6.0 +; ------------------------- + +; The log limiter explaining label. This is simply a piece of text that +; explains what the spin box is for. +; log_limit_label = 190, 612, 50, 30 + +; The spinbox allows you to set the log limit ingame inbetween 1 and 10000, +; with the option to set it to 0 as well (which is considered 'infinite' by +; the log limiter). +; log_limit_spinbox = 168, 636, 70, 25 + +; This is an input field that allows you to change your in-character showname. +ic_chat_name = 200, 534, 78, 23 + +; I am sure there are some differences between the 'ao2_' versions and the +; 'ao2_'-less versions of the IC text display and input, but I do not know +; what. Still, here you go! +ao2_ic_chat_name = 200, 534, 78, 23 + +; An in-game tickbox that allows you to set whether your client should show +; custom shownames where possible, or always keep to character names. +; This is useful if you suspect someone is impersonating others, for example, +; and they are using this in combination with ini-swapping to 'duplicate' a +; character. +showname_enable = 200, 510, 80, 21 + +; A simple button that opens up the settings menu. +; Equivalent to typing /settings in the OOC chat. +settings = 130, 610, 60, 23 + +; The character search text input in the character selecton screen. +; The moment you enter some text, it immediately starts filtering. +char_search = 420, 7, 120, 22 + +; A tickbox that filters based on if a character requires password to access or not. +; Note that this is actually only partially implemented in AO. +; The interface exists for it, but no way to actually password the characters. +char_passworded = 545, 7, 100, 22 + +; A tickbox that filters characters based on if they are taken. +char_taken = 635, 7, 80, 22 + +; These buttons are similar to the CE / WT buttons, except they show a +; Not Guilty or Guilty animation instead. +not_guilty = 380, 470, 85, 42 +guilty = 380, 515, 85, 42 + +; These are responsible for the pairing stuff. +; These work much like muting, actually. +pair_button = 104, 515, 42, 42 +pair_list = 280, 490, 210, 177 +pair_offset_spinbox = 280, 470, 210, 20 + +; This button allows switching between music and areas. +switch_area_music = 590, 319, 35, 23 + +; These are colours for the various statuses an area can be in. +area_free_color = 54, 198, 68 +area_lfp_color = 255, 255, 0 +area_casing_color = 255, 166, 0 +area_recess_color = 255, 190, 30 +area_rp_color = 200, 52, 252 +area_gaming_color = 55, 255, 255 +area_locked_color = 165, 43, 43 + +; These two are casing-related inputs. +; "casing" is a tickbox that toggles whether you should receive case alerts or +; not (you can set your preferences, and its default value, in the Settings!) +; "casing_button" is an interface to help you announce a case (you have to be +; a CM first to be able to announce cases). +casing = 200, 560, 80, 21 +casing_button = 173, 637, 60, 23 \ No newline at end of file diff --git a/base/themes/default/courtroom_fonts.ini b/base/themes/default/courtroom_fonts.ini new file mode 100644 index 0000000..16e2f41 --- /dev/null +++ b/base/themes/default/courtroom_fonts.ini @@ -0,0 +1,11 @@ +showname = 8 +message = 10 +ic_chatlog = 10 +ms_chatlog = 10 +server_chatlog = 9 +music_list = 8 + +ic_chatlog_color = 255, 255, 255 + +; Color for all labels and checkboxes +label_color = 255, 255, 255 diff --git a/base/themes/default/courtroom_sounds.ini b/base/themes/default/courtroom_sounds.ini new file mode 100644 index 0000000..b24e2ce --- /dev/null +++ b/base/themes/default/courtroom_sounds.ini @@ -0,0 +1,8 @@ +realization = sfx-realization.wav +witness_testimony = sfx-testimony2.wav +cross_examination = sfx-testimony.wav +evidence_present = sfx-evidenceshoop.wav +word_call = sfx-gaspen-yeah!.wav +mod_call = sfx-gallery.wav +not_guilty = sfx-notguilty.wav +guilty = sfx-guilty.wav \ No newline at end of file diff --git a/base/themes/default/courtroombackground.png b/base/themes/default/courtroombackground.png new file mode 100644 index 0000000000000000000000000000000000000000..5ad8d51aadaf2c1f03f720a839a0b137fc8c7385 GIT binary patch literal 63046 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 Bgy;YO literal 0 HcmV?d00001 diff --git a/base/themes/default/crossexamination.gif b/base/themes/default/crossexamination.gif new file mode 100644 index 0000000000000000000000000000000000000000..a7754b6073be35351d5cab4f5864c6d1d22af944 GIT binary patch literal 88834 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

p+Q;P=Oj?LfKYA^CeEot+`#GN{r7Y!r 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

>K1IV}JlaDaLwQ#VX(jo}jbq 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

a?RCLM9n2&nwW{vb%1vw!>68h;G zH^cX7j2T9LX{g$sl}`-@BHss~F)g>|jGG}gbCgM~G{qgULKR;){xnLUt?Ud&6=a$(3+k@KRQf2aH zrZMY!_w%7uT3|mA7m=axXK`7pr-KY|+65Dyy)KK!+3(`ik~}S*=4q+#dk;pP7CpxF z)NjJ2GljoBLmx42#$jElaaR(_LE6#sSbcu&^64>^OR<35>ye<3-^<|DnJ|3>#&RXf z>{j474}kyk$jozsdNpDS>%82e z&0~8)cotrs;tlqPHv;4kHYqQ4y6kv6w(waBRN z0^w4^&T^m4ixd1gCjts z*XUPb5^`SPqB(;GurMAZRhc&I_u~rbWky2CW-+7J7RV}6J=v;z-n<1_Klt;c`eim4P#?`;XwAu=eBA@D2ejI2yo zd$AjP4K*bFJOdr7)4%m!F zJ-YwuUaf_b9EtXYm2&H?g%6u8r%`Byd1t&~DI!USb%U%Cu=`Cc6ozSj|HmiZs=E+_ zIiR0v$I0Q%7%xAyU`7$fyho!CabPP2WJvi+0p@$P<{ZU7UF`N!%LWmRGmrr!4pZ|n zn_$C6SrS258WtfifdI+>0?!tRYybcN literal 0 HcmV?d00001 diff --git a/base/themes/default/crossexamination.png b/base/themes/default/crossexamination.png new file mode 100644 index 0000000000000000000000000000000000000000..044a76b900aa1d14e44c58c46de7f5fe7ff95356 GIT binary patch literal 4187 zcmV-h5Tx&kP)KLZ*U+R`sCEkzKl)gj5&q@hY_5?)@_euSf22N!q0z{yc?Q2YY_Kym8e z5Fvwu2%hQO!{u_psMvL#(bD64NQRTZj^-}DnS22ry9f-;mW=gZvQj}U-ZdMsK&I8^7~DvX`q=ii|MMXs> zT{me^OG``D%9Sfe(7D1=R#p}P)})k*09svLJ%Y{^mWdN5Mu3ewjR_MH67YJxBqSsZx*iUPX>M+&wzl^F3gBS}H9b9@tgI|Ja|WJ#58<6su<`rM?n2NKwo+Zii)7AY48J2Jq5dWGiv#Ad_EtIjg2Fq zUaq*^ZUJ=fUii*;;Ny?wMs6;gJqxX^aNz>nbr;NRD zHa7CHUf0zQs@ZI2?AWoQncw@K0GgBpJ9fY~z5xvlaQ*dg`m_N2*S`|8Y88`QE^xWP zYL$C6HBeAMVq&5UeBuPu*Mr+lVtzhux0|Y}Dl#%MEm`ob~bLeo71OHla-Z) z#bSYq3Yl;0SP~~rBq=G0ii(OM2X2$&a4?s(cT->}FR;-YERu=s8pK$)X zv>gt(;RdL#hKC;(yZhjSFm4sur|{x~@~IaE|sT>YS?q@;*5diiC!;PJrP zwS+<;jvqgc$K$~@dNhn4O-xLTXy3c<$_xMGCvfVN^qV|cK)U{V(J~`!fWQ0&>~?tW zIoP-n9(}YwoiTw@@b=sA)1S)jSh*73dB^A<48pU|!qlm_H*O?8KA!IG?xEYM!(yl{ z7STE#`_7sL9uGdBkFKsRs;jFxeE2Zs<>iFKVcF_>3!XX!2?_9(ufVcpaPPeWsL2FB z`vrogX$CH3qac<-<{ zI=>&BPUz|qTm8fnuw{$%4~GYjU0x2azYc%+1B@Rp_W_g1G_*ct*y4(w9-|%=6#+Xj zF_GD`XESHc9Hvj7j#()S|$i4rtfNChP+PYW(NHlm}W|2N{)a5xNO#=xC-!f$>fwzare98D->Joww+ zLP3Fm3y_uufZy*IyIfEJv9S^|z4Q|N>t6ya!1U=7DJ)tf@#~2baQLujDah7eyco7` z7XYiO;Q1Gz^{kPEj2|y+9qKrJI6!S~ZWd7Py;p$M-ch$zT;JsS;C~Opu#PAP~Us z_tVnSLP|;s(Rbb{;OyTofJ~hV*Ih>_9H!Ur$Ntr?iiYmpE73q&nwWspR2hHWI+!^V z4jd5snwbepmOxw_wY9ahYJvVQ@aM}4a8B)t+4?hQLT2U_#gta7l^HW;3K^imE#cH(*_4ne7uzo$1lt57tK24Z>L4qebIvPIsKvL6; z42diP0a$)B#M&qgPg&*zNWR6BZ7KX=!O8 z5C}xp9-#{RZF}SxXX{pY{&``%3JN4zIM*s!m&Jn9=_E5VbCBui?CcaJ`y>Mgbai!c zUNdc<2WmJRHo}*}LJ8Kj8Bj`MJf)b>A4ms-K_iG(3PK@#{h*qfnj}9TKOUl@=u zZnqQFpSt!NO5sqwUTL2>0~*x%^WpBhBWY@0UY^nK^l5N9NuN2B%F0R-6BF@zy^^7| zw?kSQUayy6FsKoh?`hLC6D}tb`T1Zr6B`>#ti>Ypr=;NZdhz*u@*V^Ef$nZ-YQj5d z5-sP>QKjSTOU0>XvstuA$8QT32y=hiZSuMOcKFhlq&{a3Y}g=x?%WA;=gRY^PT??{ zF@5*DlE>%eiEutRMtpocQAdu5rfk?Cl-;yx!XPy_!!Lg+FL~2VvOV8@SJG0OP0YaT z*%E`^daJBs?p&gd9wj$7R{(wJArX3Bo+Jpbyh60e1UKJouvL#dBK_Za2P!LN9uWIl zSSbDS^P#K^hr@yCzyVqBs#OwS&z=o4X26;|NbTQ2gGxzBiE3WKX>DeN`=EpZQ5j9 z(_?$RO6}b{_<2xj%owFgOQpVbt5S`PN~NR>e#YTY>g-vi9)9@K{q^V7S0mUpHa4n~ zk`iV9OxjLwNiDtK|6bC)-MeKd5WAF=BxLmZ^^z6Mn+L!CwKzG81y-+ylPBS^$D~hX zrS#WCNiZmyuccj8C4{s#C3SUThB7lHRn;k|%Po2S!iCa4ejMuRMblTTkf`OYw`2`X zO){@$x$Jf^DYxEgXsE{{?A5t*qM`RcAX%8tCq#{&7i7I#w;EYqKPP+H?H>~pBS2~U z<8TPEk&qx;O53`$G`Qmq!;X#`1&=>2wlOCMUVT-z@|$nM8*dnkH<{qnX=$%t56?Vf zkR02#!9V^XX=YTEfYRJ7v|ekg2*Kfim-oOAejtp#u;SoJ5jKCv4iUf$FBr7rnl&P9 z&1~)8FTgZ3YOgBm1>qAmZxa4i3t9uWe7UT5F%VA+}5}a?>VxLG2^}#*XcG80U-}UOPpbP3&GUC?BU&7Tnz}{VrTE zh>(H;scX+WaiVC>BaguS_Z$8IM9WiBgcSpEm^Pc#ThEG+0|C)ei$&sLy^BB;Opm8S z%+^*B92m~^a+(?ng`mDcI;E$}Bxz~Vc_0BuNN)J$T0dP zBp8Q*S(!#=r(fLVGUhBUmV`kwQ%VU)S}6PW3u%4ih=7%tXei6Yi*nNN+H0~VmrH=G zt(AAwBv5^W2*Twy{K4h6zr*1$NaN~i!*1#F^wYvPz48iJtP)J$cb^e>A-{^pwk-hu@>_Y}?P>N2*sKA+MH);|q$yA7VzV8V~(+7 zjZ@s(n#eV!cf{p1)nqb>S6{gB)1ECVN{sxxdEywBERpNq{H83fuTQ+@tXYx_jLm>` zYXzWv`^0WtbB$<{_MVFtiKouVF`UHg`Zp8|j zGc)rue^h5GDJdEB`_#h1!Y@P~bai#%bUKIpn0F{kC=?dLWJjh77T92qlKpiPV3TjbNk*Tb#jESES#9po_rT%Yz`8*V5;2$YQ{_-&g}Hu2z|8;v002ovPDHLkV1mnz;h6vc literal 0 HcmV?d00001 diff --git a/base/themes/default/custom.png b/base/themes/default/custom.png new file mode 100644 index 0000000000000000000000000000000000000000..b58d1620b4de890be0ac754665665e39678147c9 GIT binary patch literal 2505 zcmV;)2{!hLP)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00009 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 FI1D3to7w;X literal 0 HcmV?d00001 diff --git a/base/themes/default/defensebar0.png b/base/themes/default/defensebar0.png new file mode 100644 index 0000000000000000000000000000000000000000..e15b7276c330eaf2dae6ff18f1d824605af1c69f GIT binary patch literal 171 zcmeAS@N?(olHy`uVBq!ia0vp^AwbN>!3HEZ)>#JtDYhhUcNYdT21^EeuYau7KoQOY zkH})6s@)*Wc>Ko|GoT=QiKnkC`y(E11{0977@wzrEln$e_T%VDN#* zU8*U{%lkoo_l7lg<`RFVdQ&MBb@0DGk`rT_o{ literal 0 HcmV?d00001 diff --git a/base/themes/default/defensebar1.png b/base/themes/default/defensebar1.png new file mode 100644 index 0000000000000000000000000000000000000000..ddc7c05215dd04b699336f978e6ae96b0c8f530c GIT binary patch literal 188 zcmeAS@N?(olHy`uVBq!ia0vp^AwbN>!3HEZ)>#JtDYhhUcNYdT21^EeuYau7KoQOY zkH})6s@)*Wc>Ko|GoT=QiKnkC`y(E124hq8!rN9rAx}>i$B>A_$zM)bf1RHw62QA* zk6k&-`lik9U2e{uEC)=aSQax{Ni6^pTyD%ICJye*B_cg+FESeX*j{Kz@CMvsI(G4( c;43BuLu1a_Izo!3HEZ)>#JtDYhhUcNYdT21^EeuYau7KoQOY zkH})6s@)*Wc>Ko|GoT=QiKnkC`y(E11}%nHhqf^Sg^^S@gniwbP0l+XkK9BeqM literal 0 HcmV?d00001 diff --git a/base/themes/default/defensebar2.png b/base/themes/default/defensebar2.png new file mode 100644 index 0000000000000000000000000000000000000000..78835aab9d4cc36ca86a31a62ee5bdeb6d15f409 GIT binary patch literal 187 zcmeAS@N?(olHy`uVBq!ia0vp^AwbN>!3HEZ)>#JtDYhhUcNYdT21^EeuYau7KoQOY zkH})6s@)*Wc>Ko|GoT=QiKnkC`y(E124jP8Y5lE0ArDU%$B>A_Z*OcAY)}wz2|T~h zVzuH1H>I=%g53wM%rUOs-@qHUqwwlJzNMk_Zf;|9+pSq=CCI?a72?pyBpR^5f%VJ% dLza_nbALF(Ia}ts#9g4744$rjF6*2UngAzoIE?@R literal 0 HcmV?d00001 diff --git a/base/themes/default/defensebar3.png b/base/themes/default/defensebar3.png new file mode 100644 index 0000000000000000000000000000000000000000..8d8427af95681d0c02d3526d4dff55b84dfac020 GIT binary patch literal 187 zcmeAS@N?(olHy`uVBq!ia0vp^AwbN>!3HEZ)>#JtDYhhUcNYdT21^EeuYau7KoQOY zkH})6s@)*Wc>Ko|GoT=QiKnkC`y(E124n5Jb{yINVB!G9r z9=r0EXVd1`2AL!=P02Lz?PYtB(a^{CLPLW0!bJvI-V1>SQVSL{S^!3HEZ)>#JtDYhhUcNYdT21^EeuYau7KoQOY zkH})6s@)*Wc>Ko|GoT=QiKnkC`y(E124l6w=Vv_u3VC|EIEF+VPX2Pj`s@5ekpSKe zd+f?n4#*aM^SHQyGho?86H}=Liy5teM1qNfJ97z;IGEAU$Myn9G+ks^s+%AqE3;6K afg$||=j?jV)}uf}89ZJ6T-G@yGywqLdpP0% literal 0 HcmV?d00001 diff --git a/base/themes/default/defensebar5.png b/base/themes/default/defensebar5.png new file mode 100644 index 0000000000000000000000000000000000000000..d9236c26f61a64da2fe7f68a85c5761bb251d54d GIT binary patch literal 188 zcmeAS@N?(olHy`uVBq!ia0vp^AwbN>!3HEZ)>#JtDYhhUcNYdT21^EeuYau7KoQOY zkH})6s@)*Wc>Ko|GoT=QiKnkC`y(E124e-UHTD;QLY|&3jv*0;lfRs>{yINVB!G9r z9=q}s4~s8vCN5HZ=(p^miK*0r#f(-!BEiJLow)=^9L#9wV|xK4nl3Ud)lHC*m076A Zz#!klIXk8~cp1=822WQ%mvv4FO#qOHH-P{E literal 0 HcmV?d00001 diff --git a/base/themes/default/defensebar6.png b/base/themes/default/defensebar6.png new file mode 100644 index 0000000000000000000000000000000000000000..373bc1b0f9372c6ffb70c73e3dee47acdbc7b6ce GIT binary patch literal 188 zcmeAS@N?(olHy`uVBq!ia0vp^AwbN>!3HEZ)>#JtDYhhUcNYdT21^EeuYau7KoQOY zkH})6s@)*Wc>Ko|GoT=QiKnkC`y(E124hLlmD_Iug*-i7977@wCx1C%{dIn#NC5AK zJ$B_O5fx9~OkCvnkZ;*V6H}=Liy5teM1qNfJ97z;IGEAU$Myn9G+ks^s+%AqE3;6K af#JR^=j_#YJN^I-W$<+Mb6Mw<&;$U>emQ3V literal 0 HcmV?d00001 diff --git a/base/themes/default/defensebar7.png b/base/themes/default/defensebar7.png new file mode 100644 index 0000000000000000000000000000000000000000..09c8d1af8f0fb56adb5b3742e1a025dcd57265ca GIT binary patch literal 187 zcmeAS@N?(olHy`uVBq!ia0vp^AwbN>!3HEZ)>#JtDYhhUcNYdT21^EeuYau7KoQOY zkH})6s@)*Wc>Ko|GoT=QiKnkC`y(E124jJoQvOV@Sl|>_oI0yg$ literal 0 HcmV?d00001 diff --git a/base/themes/default/defensebar8.png b/base/themes/default/defensebar8.png new file mode 100644 index 0000000000000000000000000000000000000000..13a45480535b15850e1ea8ae1a0e90515a3a8c0c GIT binary patch literal 188 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 O00000#LT=By}Z;C1rt33 zJFVdQ&MBb@02z8yJpcdz literal 0 HcmV?d00001 diff --git a/base/themes/default/evidence_appear_left.gif b/base/themes/default/evidence_appear_left.gif new file mode 100644 index 0000000000000000000000000000000000000000..352a7f190316a57d0c1e9c4a8250259505afb79c GIT binary patch literal 2008 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 XfzYmZccH$^1h>%8Yg2d^4A}h(s9xQ5 literal 0 HcmV?d00001 diff --git a/base/themes/default/evidence_selected.png b/base/themes/default/evidence_selected.png new file mode 100644 index 0000000000000000000000000000000000000000..6230c836e9342c9eb646628e7b9deb0f51262f70 GIT binary patch literal 291 zcmeAS@N?(olHy`uVBq!ia0vp^HXzKw1|+Ti+$;i8jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1qucL5ULAh?3y^w370~qEv>0#LT=By}Z;C1rt33 zJPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02y>eSaefwW^{L9 za%BK;VQFr3E^cLXAT%y8E-^DS16z6k00R?AL_t(|UhSL7ZW}QShV}k0)V+YWjGYu{ zlQ`buByGHm6JLtHz?92SW4c6dJrw!{d|>7vAow9JqUh8#O`6{ho5gh0!QcN0{J;MT zSeG>FzvDl!&erU@-=u2zK|U@9?*Xx1O+^nrm1%PENj~o9V>aSuCG)a>AVYf0#!YrB zK1Q^{4JEOAUXp2=J9evK|E+vL9A&praU|wUMjz#4O~;5tyqs7kXO?SHsOYn zsJHiInr2BQP2vd6i=#8Ga6?Jdn-v+-Xj)(7L zRF5?1y^#;Nm11rsC&%0hsa&yC&U$n$3slHLy*;Ur^NZ(Q#U|WP5{LF~#d_paj%=m4 z3K?~d#|30-S-`Cnb1NBMvY4}+qMyTLrJ{W zk7QI2Oj(>^?^bTg0&b-^x5CNsxRYab4(D}R;f9iML)tcn%tOhv!VM+ihP3nD3gQS( zoX)LqePG;+XO;Uo7(rnUZb-XzD-16w;gB}Q-jsMq8>w8tkoI4QhqTcN6zuxohqNJ% z;Kad@w&&PRS;&yK%>>Ty`XE?^%zETH2h*fVb}O_j{v>Q!pw3a^A#G$UAx!1CJ}BXk zHd+>nAJVpfjFyFv12VTPa?C-?Lg-RCWve`-{S}j4%=U-I9M&Vhcw$Ifu@_I)qsvyP zkOgxqdDQDt`2Y}Z4%uQ3mR~aVMpk}H4LW}PJd!L;`VCfL;Xj+>L`nbv002ovPDHLk FV1i$4toQ%` literal 0 HcmV?d00001 diff --git a/base/themes/default/evidencebackground.png b/base/themes/default/evidencebackground.png new file mode 100644 index 0000000000000000000000000000000000000000..ca285326cbb2df7e2d40474814a4db464248e760 GIT binary patch literal 19927 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 P00000NkvXXu0mjf_J{+{ literal 0 HcmV?d00001 diff --git a/base/themes/default/evidenceoverlay.png b/base/themes/default/evidenceoverlay.png new file mode 100644 index 0000000000000000000000000000000000000000..d409cc5822c70a63f4088ae39b5cebdd41b483a5 GIT binary patch literal 2187 zcmeAS@N?(olHy`uVBq!ia0y~yVB8L5-{W8dlKZ6n&H^dM;vjb?hIQv;UIIBR>5jgR z3=A9lx&I`x0{NT;9+AZi419+{nDKc2iWH!rWQl7;NpOBzNqJ&XDnmhHW?qS2UTTSg ziJpO;p|J^bbQJ>w`)^Md$B>G+w^tpx9Kr=%F21>9n(~BAW+(gI8O#S81O!XiFY?t# zu*%Oisj*~Dzx4R{Zu>vw_Dl!<&#Yi+(C>C<_^}BWqbvT*8NTWN6yrMGyPofzIdiVg zU*|nS{UYb9jg74%f3;Vr%4yE~o|aa&=?niyFPk8n_h-+%NqH&%XllihihHwX-aL89 z{)qNRkB@uIjWAgeDBN|ziETWf>;9kixBt)mz})=5 uFSr(Dd~o`aAj3W#Il3|IUbV~rXP(a)&@_oJJRjIrVDNPHb6Mw<&;$Vb6U2r9 literal 0 HcmV?d00001 diff --git a/base/themes/default/evidencex.png b/base/themes/default/evidencex.png new file mode 100644 index 0000000000000000000000000000000000000000..6a6be36f72644cde4a1e14813e648fff1ab6f838 GIT binary patch literal 637 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 literal 0 HcmV?d00001 diff --git a/base/themes/default/favorites_selected.png b/base/themes/default/favorites_selected.png new file mode 100644 index 0000000000000000000000000000000000000000..4c33d432ec19d0402b6a0d7ece7ca969185b26a7 GIT binary patch literal 4306 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 AzyJUM literal 0 HcmV?d00001 diff --git a/base/themes/default/guilty.gif b/base/themes/default/guilty.gif new file mode 100644 index 0000000000000000000000000000000000000000..3dd95d554410755ab1a3dd43ae1b0088d4de87dd GIT binary patch literal 43263 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 literal 0 HcmV?d00001 diff --git a/base/themes/default/guilty.png b/base/themes/default/guilty.png new file mode 100644 index 0000000000000000000000000000000000000000..efe68f702910a60e8f3e7eadd8d4d776bfe6128c GIT binary patch literal 2851 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 RM#lgE002ovPDHLkV1kyyvZDY1 literal 0 HcmV?d00001 diff --git a/base/themes/default/holdit_selected.png b/base/themes/default/holdit_selected.png new file mode 100644 index 0000000000000000000000000000000000000000..51586e748d67251f3c7e7bbe0b2485b8816bbd93 GIT binary patch literal 1835 zcmV+`2h{k9P)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00009 za7bBm000ib000ib0l1NC?EnA(7<5HgbW?9;ba!ELWdLwtX>N2bZe?^JG%heMHD!e| zWdHyMeMv+?RA@uxnF&)Q-w^utSM{e1cIDQ9QfZe;r5Yoh z(AFU7bXbSXnRs23w3EFwA0Hn#`3;`er@g)1<@5Oq0m9+{VQb&_!^CZEZT?0_M@JU| z_QIaR7QgQYH@-+>DeQ^8g>5$ek(}jS_2lHFY3b4>r_2lEw{E$@`g-KXv{{x$Mk030 z?DOZY%gi}`=T2h3&R~Ck<%*v(sZXP~93-<9ht|?TUT~hW$Wb&R3aC+14$;6+4D| zYWvXDs}Y;>d3iaqALbtr@U+v@e_M`^|7i&loc*JxAud}Gres1Etv7+^e4B;L_4T<8 zWB)5=w-opG+*s(xf?s!ZRP<570FRvN>MGklEiAZMX*(2#h1vV}-9fSFZSUlIS=u&( zjj=k;k6m1JGqf4{1sk4ndY)Z0j@x+7n(pawpJO+{i*Rl2bKZi*?Qibhb^F22ec#@^ z>DxDQIoA`~0r94vJ}r-XCyCzfP;`@_bb^&k+@n!O;kJ|b32TU#a~79m)$Oq4=B^ER)*nXkl-pVyzP!O^Y9=O*xZj{3f2sZ>=48O@Kx>>vrQR0G;%&{{M zeHl+kDmMSo2ROxjXa@!bPDeX$95gANp5cuE&q~T!agqdMBlClU-cIsY!FC0n+~UxX zfBLlPSVF)q8au!7B7U!h-|7X3u{1hbu^tr+$Yac7AA*IviZ|lH{_qfZ*sL)=ZxSU> z%ala>nrA5prkhe&z}nQ5KgKzg)tP=pO4X*<_!K*Nfs zt0E-{rcYf@LnsR-iCuFOiJrc!#R^6U&h++{PDx=>AZKw+{piCp?86F1v90ZAp)SF| z$GhQ`xyFldbFRrjY#NUvOjHDHRxn;m^qPJz!*4t9s3cuBwlO#7Uty@-=wtJxR`dwQ z1Eio;@#sh4&G-p97!drEVC%B8^38%NbAsIj33yb>lWKx#=vcuhF0~&XOB>)3yvA@3 zY9_o~#{ix}xN`y{6cs${)IO|vN~EkH94I&R5K!0<`Net=Pu}(cyfW#;^Z7EH^&8(Z?Lf(bojQxP z`gH{xVj&cshRQw-7{mojs>2Y41;z#AY13|V6t$7<0~`cU(SH59zt>!Ue zxTff(ojxiUtVoTgbG*2G*=?__xx>T5vK?pxyv>F>Wr)^~_0W)DTdS)+(Q@OsU?fxW z4T8~!O%f)A1XXqXT~FbOTdLV?dp&3ksQj=~5)h1+TAmn!@lwmN?Q0|P3XXj|ZLqo7 z6*e~f!jz=>egp`n@2D^?G%OfzUoYzQFyJo>S|*UsRIrOq$-`3hc^FVN>wDt=NiekX9#)i> z*$v4z^`Ndjp2@g1UR@IUTqMxQdl>(eXbIm@(&?+E>+kqq{85tcTZ#Ga|8rYQHFS+B Z_a7oCTd~0}o5jgR z3=A9lx&I^rRWdUK_=LCu#a&%pi}Uh;j8QNe0wXO1_!rI(1Nxb>z$3Dlfr0NZ2s0kf zUy%Y7lq_+LC<)F_D=AMbN@XZW%*-p%%S$a$Fwry6Gczopr04A!!%K!iX literal 0 HcmV?d00001 diff --git a/base/themes/default/lobby_design.ini b/base/themes/default/lobby_design.ini new file mode 100644 index 0000000..ef64114 --- /dev/null +++ b/base/themes/default/lobby_design.ini @@ -0,0 +1,17 @@ +lobby = 0, 0, 517, 666 +public_servers = 46, 88, 114, 30 +favorites = 164, 88, 114, 30 +refresh = 56, 381, 132, 28 +add_to_fav = 194, 381, 132, 28 +connect = 332, 381, 132, 28 +version = 170, 1, 300, 21 +about = 428, 1, 88, 21 +server_list = 20, 125, 286, 240 +player_count = 336, 91, 173, 16 +description = 337, 109, 173, 245 +chatbox = 2, 445, 515, 198 +chatname = 3, 646, 85, 19 +chatmessage = 93, 646, 424, 19 +loading_label = 135, 92, 254, 95 +progress_bar = 135, 188, 254, 21 +cancel = 220, 220, 80, 20 diff --git a/base/themes/default/lobbybackground.png b/base/themes/default/lobbybackground.png new file mode 100644 index 0000000000000000000000000000000000000000..094f19c35e020c3267c076a51c370db94fd39cb7 GIT binary patch literal 29532 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 literal 0 HcmV?d00001 diff --git a/base/themes/default/mute.png b/base/themes/default/mute.png new file mode 100644 index 0000000000000000000000000000000000000000..a184cbf84fd871ae980ed57f83335575ebdaf0a1 GIT binary patch literal 5037 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 D6o<7R literal 0 HcmV?d00001 diff --git a/base/themes/default/mute_pressed.png b/base/themes/default/mute_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..e9793cec4edd24ff22f06d25034b327f57056a1c GIT binary patch literal 4978 zcmV-&6OHVNP)KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z000P`Nkli26`Kw=OG9JoK7dI)ha5Limg1;ttW(-ep;ClMG>+r({@G>t;As~k>EHE zd-m)B%d)i1{QNuxtM}EPP9xpct?~JM=;`SJ$8k^;1*udDYinzpKv)O0+X3UZ5oF=q zIn?ucgr0pC(P$L6Z{J3(R@<~d)~bd2z>*{(9*=|LI8=WBoes|PysezIV$zP)Xfz6z zWl_9v0htdzz~X10(K#ZK$fg};7)AqXWIzWI3WWdw+4tYa{PE)`Ubq03WldmNmW9{r zMJN=4D2go=(OBGWH$+jydM<~BsVVw@;lv5li$!#Hc0!V*O$%l1lt~mt%4Gihd2OJn zDGIi)uMa%WWAEO*=xU;SdCrfBI=d9tnZ>kw-uXLAhLp z*Xu|POrJc7#p!7%nG8H04*)N$c%=F#xQt zu2Qhl=qS7oK1jhXOitQ@RSE_C@6;&(&~`)+uzKSL(kD;SzPXP+0szRe494L==VOo2 zxz~$DDA_FBZZ|lNGb@wMqScM*bu7zbJ(t7EpMP#FrVZG_x8Gv@&K=4MpGd&fdd9P9yG+3p3L8MZUQ=DY zRMP%8WtR|Qwxf2ks;a8isc9~@3)V9@2t`rA^SlP^&K*-9M^l*qKy3n}0Z4N$RaG}+ zv|Y5sFbrf_1^{>;eYAamYyn%Z*O5x4AW0I4s-pbE4`z|N|NaejExVS zctuel%Q9S{5CS73+X7o`I)&ceUTynt-9oKerR_SRQMkIhsaRC5UNyVfo*r!hhTw#4 z75Nwy?C#yW0D#C#FTw5iZwWR%If>Hc%W%0|P*oKj`}SeytFO{F;TK+@@hDMM$iMtT z>s%cj=-9g#wOS3;YIS4ltpTcCWK<{=P%IX~3Ig`L_Z}pJ-J|jiKss~?jLz&^Z=rbc zA{-6}8jS}0V`GTF{yIWOj==ly!%!4OvkKpQ1Jy8&?};a<8#kItr%}V(oiel8tma81 z3Gw5{(UZ-hbm@||RpBti{(iW+x=>0ck(!*;z`pyg)@Nh{s;WX783CH&!*Lu)qk*MQ zKQ+x4JaRTdOD zO9xBpb@<1|5DW&Xr~CievnJ8$dG0ytB&;}`)}w?me(dhkYyS9Cd)*+M4C!d6>s>ozAwnrPMRgt36C<1|iwgne2V)^sWvD#Fm?G%*|sJR^0ayjI``U)M< zC^`oRQJ$Lv0A%#Y>hNLhIX+JNrqgL^4XonlG=AtHNuzQ>`HLBsu%gc~u8Rc@hWsZO~e&`@mCrJ&d--J(*yS(2prU7Y zd^a(wub^QF1nxy?)M^NfkDI{ePM?N+?HYKVZodk9b*7|@t)o^H8F1Y&~L`wZAUvVGd000McNliru;Q+j|pQ{OVO{;njHn zXf0##Evp90rhl3-EpiP(EGM}xez^dhw4{hsX*?c7N*P?EpnoC6z;r$)$E7UeRCl2C>^G}|!88wbcjK8)mX71# z_VyM4Sa>|u?*0A!o$c-Iu&=Y|#!MDLoCbjzCO$Qd16}`Q*Z}?j_{JEs!(+yblQ~A! z*ohj?G!DXTuCA^gU0hr|kMLW#uP;Xa3i>58XjYX;_{_rMxOh&x$6CZB?F6l_^uV8p$2G-~nLdXFa`I ztrl!>X8-E$#@EL$4FPFMtWvRo-g?zt_uqHJbna)gMlTv4JZA)y)(AxDu) z$6OI9S4Anm_50)fc^|LW`~7&mU+44v$sixI5)qOW0)apxHr6CZ5C{z6jW5CZd0*^6 zt01ofM>|>(Kn=t4pLr7)1#gcBf$ruA@A&ZX=4d}_M|%+HtQrWE!T^DO@s?5+L7-S& z5NOF81Uhg91d^tfwjVd=5d^8$C!;~2Jx~5Ma9?DtKW|Ys#=u?G3tMf$!U3Em0Je5ahp+k^Aw zAA4jXrnMvg_e1c(+@S|(+p{CwLGNHGcBH}g3H(Mum^e7ZkF?=BEkgyx zK^qkR{@N(lhjPp0&dM(QfM#6Z*p;axqpPn41bkFGyUbr@bw2gNjoOb(hOqXFoHUY^ zr(N?VunLYSwJ^u&AbxDCBKU0|pOeto)*U-9mU5TxVDVy`B*|bG*Sr!*+P$=x-VzLN z7NiA`1a?`Ab2?&LaUCFIP$!goEoCIf1WY+YbC?O}geORvcUf8_@Z78@2-V-|nWVUzl$he>_gdgWV%Qk8k(-&cZ%k>8<9?4S^-TYgJ-xe7 z)V<=tX?_4L`H_3x=*^>+0Jya>hmP({uP+kQqIQ5NAoeCG_V=j}xJQ};^3R_WB%Kgt ziPQVe{%%B@F7J6efP%b5y0LV29ayfVS)RBbdxy+ZbdYWVw`#0XtGW%SmR(ZGB;m>+ zpgv1Qh+kmECRX&rxW^|{!xp` zo$^yf#V8ChD1E75L5_J2bFn*Iz+>MR3cOhutOn6RpDHr~>1A*4GdQt6@j2gB^U`d#pM2nAdjJgh{3nu^U^+h+i47~9~YVv*+8 z9U=OspP_#A(`CoW4Pm0e&VbTk6)(TLOz9^Ur0{5i5^E09$i z=yO=~y=b~xzUCxsldewUE8IgHoOP~`7faBXy^V(<_^olUa* zW&G9F;hC8|192zfjY)=AU+nCGOd44lzyAaS*9iEi^Wg*Tbsd}*$T0S>+9WihLdSu& z>^VUTe%3+dwR;tHVzu#&_J8}Q1N;=dP0xj@S-|u~?<4|!Qs`D7H4bPW3iX6SSj%QBztQbRLiD;-&{BW5Mt+@5 zWj|wP1yGrI6Xk-cKXgqF{MS@6k>6IBekb(<5CW24Uy6fmtKKDL@Qlw_&ZcPb)4vuO z$9)@s;kOHX?oMgd>r7}Boh5QXC+%alWZ`+$o@L360VSuOKQ@f4VU1kU4=(OUVQb5%#!N(LavNnx#mm(uuir`E1WB5kvMBXZF7NnzL zZ|S1%+j7uYiA+~Hh{={J8*ZT%oh$0=nV&Dy4(D&#Q6=4*hMQFN8jxS?)`&B4dn<$T z0v>*r{G}f-U=FR3Pc`iAU#!NAT4L83ANfvGGihi)i2)Wa z7@wI^BBFb414%KR@81QSx2 zm_fZRoI41mz~8+fUfI~b;ggP5AddN>d-V7N%%C+aT-gbrSFVp+u74auAj?ZEP3qra za**sJDSD=YQI0pOH6xZZ`3Vm#zOZmwmEDOFvC6Osx#UhqXgIuyp*&af#QHzuBZ|%6 zL)b|FDzCwn{k0b zJ_&>iz49s}7j#B7H;13w$4X3*1C$Ym)%qWF{M^?I4HAR77*x(X6k`@? zT$g`!jfsa=zOLSPYO#v#S(cchG_%Nr-Oq267l-u{-y-lznu*A4A8>Zy%!EOZJ>}MX zM7z%DeGaM59nv03xXAIme{h>Toky?GX5Ka+lGhGVwMX`Sg196AN4MV*h zndFvu$?*0U8bV05XHaWP_KPq(xrg-jR@qP z0JnM#16YgqvM1I7Yb%tu#RMytS{cGzv<6YwUMP2`dE>Zzjpk>qODH;w$#J=KrSvogmKpf>Df@}s}YzlK(9OV(54L-L3ALe~? zBBC3C4`197IzT`Q^`^k|RCw|C+rA6#Jd7%>`e46VQI(s_*Ra(F#x9Wh4>&64m4b(Gcc zXI5Y;ej7bu%oLkCDHR-a`nkVo=36;E-cQos})8nksw8 zpPWA7iVeX?Op1pSE*RU-(IbDXBMJam4flYu9i_fbmsmk<=QP=OWCx8wWcWnzE@t6! z=RO8+Ai~_Mz0;0{I}{B8*fNDjJ{-x91*0Bfo_|eds?etWf0YIdwN>FW+HUasZS@=k z-ore9{3&BbR)(=R`b3nC?6Q-(j*KzC_9^PiEV#{h~fKC2(2kzb0_~ zL3!GVT$1GEIUV1o4<&s1dUCD%JL7g`RT5G}8%&jcYm9wEiSBy2XL!M1XIG>x&pv&x zC($d(w#QAX-Ct5$wVq(2=+6CW4e|UDGV3Qx9C;bmeBV`cZ8*(U%;8+q(sMv1wY8XC zOdijxQGdm<2PA}_Eq%X&sm;E;w9kmo<+iZI2I!NFv-HC|QI=B7=^NJ##e#jc2{f$ z`^f(+C_^0^_A(9@a$PyXY9NZgiBduO@N{SKqRhpEA1hmmF>nj=$!+}++)X(C5BH`x zwDR=TA3y)XuV7aD>;eRN&U6@Uq~JVpBQkaU7K&at5_57GXEVZS&n~rRALiskMFZHxUB?ao#!{MC84Y14G%Y61{<&9tOsk_Cc&nod zxvpuK5i!?pM&agUxN52W8am%56*FOg#3sw-&K$^lf7=0F(m@YWn`2Hr|6{sNA8@7| zq{qCrtbd?MsZbHk?S6Sz$y<%ElurKh*n~({>X=hKH;*W=MHMEECd=|_woQ*i=f$8| zl6Gxf%*VIy9w~@O41YiXw2!?%l)%Ij=Pxb>)k1#4q1$lu8N}=CxtpS5f4+KFU65yv z2ERFMB#616scCCfmeqesNx*2$aBPZoqd#u!JoulfK%Ej6gHimpf^@brEI2CBn4mYT zVMqi7`nac>=MlG**Udz`oOKA~iQ?B77!+{pGOoHEI{m~OZ@&xzRhjM-l1Nvi@m z`C~c%fV}$DC*_Sb$IqH0=IT`cxAbbw*-xW$_esxzt!c@X;7?$l?QD@W%rkPLxnGB8 zS$a)=lT78}V>=#$pOi<{iD8@|o@}Rj`Z&TOqu#Pir7x0Nc%5sroWK_dmo4??8B+am zsU7xwR?u8f)f*9l$Lj(l`wxW|Ul%UY%ds1Xf;n)>fuqrd6d2~DKf`xb-}V#@MQ5!3 z3+oy12bHsb)T(0bo0f-^=I)u_ShcS`aM_MY=Xy{WGhRJIfV1Zz#gVmcs|MQaokNPx z#3_ztv~TDGtA|(;nx8q>)CcdWl8ZYlo&yP;To=WOPpGzkkF-@T(RKd0xUI^AK5_d# zktZ+ANPW&-hVur6j^QTlfpF#9`ackz1wm#7M)^HPj%a&0kbj3o{kMLL^Cw>iCn?Xy^x~4T4n;n{ZjE>H2ZYn z9Ci3QWACrolDziT=>*A8$Pkc#HnXOqMcwku>uhoj;dqzlfV10EO*maQ(BJi#stKH4 zA+)NJOv*=R#Cx%x-I+e13_H5?Y6OAL+4jee8d0mdVkdXL_~n_W@G#KXXB%fUb*yI& z+idGL7iX&fchmsJ*T34GI&m7L=*`~u9xY6-7NM)*^Y%(aTJ<+;ztg>f>A(F|uPU*g zis%=oIi3Y&(b2)F6*jp&ZsvU7o-St?x14MWV{%hnk_Cr%7oLFT`0$SA9JJo6Sdq-@ za2xZ}%RUGy`^LLGSZxQ^- zTB=vAqd896rdC4d{PC-Aw^CbsaWbYv4#~TiQXwJgeJN(9SlIqosxguc4S>4=G2l{< zW`LG0!13H>8kg;#efVfC)b~$UF)342`GD#9mA^(IBQFdAW=dkpV20(TE3>RG58`b%fe^ zslfliccwSW%}3>q41Tr4X6;*b2JWVy0;9Xn4S}{^ z)FH$8dn##&kGkd;L+7v4hg*k%)xvB({0(Kh*MDVy^x}_R?FNGjZd7Af#aZZYHJjDuon2{Td9xHFmWXTfAmN45Tuy5q!rDJ)QU#9-- zih&QmkV5uJ1j3=Ig+y5?YMI;;!#eg!6)hCGkqrhe!B4E zB4GC;;g#K5gxsF>CgVZC?cZZA!DJYgQ^BXICUFe~xllz1s8$DPWo_?!v)4c=SU6r?vs94I?+2d3&SENT8a$?ef;4!(3WTUqxOROqL?5;T zjG|BcFor#3;nWYMJT+ZAf3&O27{*d*l-n-{v4Tkn(yJ3dM-?I(9VP+pPdnv z51i&&?Xj6to4=H=4>I5WBs1P}g7Y-rBBfCdkIf$1+kNEog+siQFpLXUq{og8c;4P&~C!VFYgz9xI@DP$vQ6x{6WmX4Bxl5P~b5NwDZqAHW)L2-U za7TKNIj9FW3-DngYya@XKuiA9%aMgu8&mDM{0D(kjN=KryH%n3R4eIZE8f3bkd4JL JQUk%8{y$9L-@^a^ literal 0 HcmV?d00001 diff --git a/base/themes/default/notguilty.gif b/base/themes/default/notguilty.gif new file mode 100644 index 0000000000000000000000000000000000000000..d057715d38d499dd1b4cb28424d821556b8bf644 GIT binary patch literal 34911 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 literal 0 HcmV?d00001 diff --git a/base/themes/default/notguilty.png b/base/themes/default/notguilty.png new file mode 100644 index 0000000000000000000000000000000000000000..b9cfe3184d261845d5c2249768273bb4b89d7bca GIT binary patch literal 3269 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 S9ZIyQ(W6L{DqU(S0suS3L(6FZ literal 0 HcmV?d00001 diff --git a/base/themes/default/objection.png b/base/themes/default/objection.png new file mode 100644 index 0000000000000000000000000000000000000000..6fbcbc2fdbc234835fa6379b132a0a2506880e62 GIT binary patch literal 2147 zcmV-p2%PtcP)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00009 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 Hu0mjfQvk@v literal 0 HcmV?d00001 diff --git a/base/themes/default/pair_button_pressed.png b/base/themes/default/pair_button_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..aaf53fb6df37b5f76d2bfbf84e70eac7215a2c28 GIT binary patch literal 4619 zcmV+m67=nfP)KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z000LzNklMND`42A83mx5y3@+)Vi>AA^4zl zQL!s4D1x|1Hx?9eAr(PfNFxOmMWIT;w@q5bS4q?+O*OH$d1@Z>U;M~8naoVm$KMY^ zk~{Zt=G^a|@80hcgM)*}*ucO5Ll6WQh5`2*02qdWkmY;MubZjIA4jNeb8|D1`7h&w zY-(y^D{?_D#Dx0c6CebdAP6`d4kiOu1^^C+gK27Ng4gSnY{-9eAvOyEAk`Ha4;#xr1?;;Q!_iBE){C9v^^IUGB5l*;$y)X571X@3c(Hw+dxJ zj5#qk5b8^;&nzEh7$&Qb--!Q=3qs5t3ULWBP~5heZyA?vp_MM?M?xtaAO4Uzhvgwv&nZnAp_t8R7zzioV#s7NC=?2$ z(`m$FF+`(LOixcEl}Z&XZvY^Z5^^D?g@ORXFrX+3b#-+}rBaB;7>!0uOibX{uU`cR3t1t)!Y>!ETokD$Ye4ol}f19YUp%2XfzrW7Z-yh$(%P%CX-Mo6j--z9pdqL z-l+@(0!SnhpeRZ*aIjeT56xzC7U)?GiV7GE2GBGOpU;OtAdutFMxzlF zMIo6?<^@|-RfXTbe+!btcQYAxfsiDLbUKY&w{GFhn>X5q z2nK`f3LYC9gUMvVg$oyOgp`jtmpD2nd$VZEcicnfw3XMjCs;VkDolY1G2I%#A zwvR|8!m^vAqwn9pM|E{I>g((A?b|oW!5SMI1p#CR5Hr1AkLKoP%*@O{qtW2pxpR2- z>>2yAdc7X2SFgslZQD>+SC_qU&LB@D67czaXl-ppJRZm0yLSZ#GZ+lmx^-)gW-66R zJbn696l7^>Df;^Q*jefB?nXMD&cfjJdg1kYF+4ns{{H^In-ac-LLq3iT1i$iBArMi z*fOnF3%Oj5D_5=vw%N014~`u>hS#rO!)~`D91e>{#Y>kiL9JG^ZX^@h`H&*zF1qokw+6%`fe>gvh@4*)AyuEg%$yV2Ctgp(&vvMXIGzDFVv3=R&W zrKROBqkO@qX&SLujMYiLnayVG+O-RzP>A&*zu%7&Cr-facB8JY4l7oyKuJjn+S}U^ zkH_J1xp45{!Gh0POO`A_I2`^f_!$jl_kARZ^73*#dh|%J1G!v|*49?|d_FjxPTanI z8x0K&*tv5jdV6~T0O4>Lfj|JEPzYzwp2hR$&+{rkXJ;p9n#T9<-?41jGU#+Vc5jfi zDakmxMx%kx=fma8mjydbr_<=^>B*V}uh$EQ!-1Nb8YGiRcs!mtomBVk-HWA5m$I?n z@Au=-p+l_BW`$6b$%Jq?jBD4fiLP`2lA-bQ=g;#xQd=w*eE9GIH*Va>zs);+`ZQj> zdWC;!X0sWaH*dzqjT>RN+a(hhtd9OmkXEY|`}XaFUa!Z)hY!)!)g>rZa=H9(Wa6Kt z|DU#h|9;qPHh4T9T)%!DPo6x&oHbf#3M59rRkB>vE)&4j2g`8LBVp^>hZEbC+t*yoK z<;yWPHimca-r?%itC*OW5N+4l*$J!F3b)&ha5$W!?TgB2Z*MPZYHD!j&K=ymc@x9K z!#Pn($hK_R0;|=EPoF*^7K;g0L9Utb?wE*E-wdf34VvGVeAba!{d>-Dm6oqud! zG)9jfKaSDSQPItal$|x?9nRa_9G1VNyqqXTxk9g~xj^O7sEtOV{+Ev zZXr6!-8jtEGKWd2#6uR)`D*E6YB2vy&j&9POV|7h%P=aIFU0T_oKbN zeNF>Kqfw~UYOGnaW?l@cR4O(g2qoYQ1_OqMhG4VV2qGgZ{OcR3RJhQ8p^Tqc@=K}@ zZu#TKkJ-B>Lh3>+-*iY_Hi+GV%;lnjdm;9}0RTGrS*;gvi7x;E002ovPDHLkV1ja} BqkaGY literal 0 HcmV?d00001 diff --git a/base/themes/default/placeholder.gif b/base/themes/default/placeholder.gif new file mode 100644 index 0000000000000000000000000000000000000000..e35aaf4baf2672bd009a7e1d9d2415f164a86818 GIT binary patch literal 9168 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 literal 0 HcmV?d00001 diff --git a/base/themes/default/present_disabled.png b/base/themes/default/present_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..9c6a702d4bf2ac0b2322f05a37f7160680da811d GIT binary patch literal 2905 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 DU8$*j literal 0 HcmV?d00001 diff --git a/base/themes/default/prominus.png b/base/themes/default/prominus.png new file mode 100644 index 0000000000000000000000000000000000000000..1191e1ee157304addbb8e0d2d72d3454e0973c07 GIT binary patch literal 493 zcmVKLZ*U+R`sCEkzKl)gj5&q@hY_5?)@_euSf22N!q0z{yc?Q2YY_Kym8e z5Fvwu2%hQO!{u_psMvL#(bD64NQRTZj^-}DnS22ry9f-;mW=gZvQj}U-ZdMsK&I8^7~DvX`q=ivBBg3A5Jh8W1V jj}edm00000|NjF37T^g5&)L*a00000NkvXXu0mjf77E1@ literal 0 HcmV?d00001 diff --git a/base/themes/default/proplus.png b/base/themes/default/proplus.png new file mode 100644 index 0000000000000000000000000000000000000000..5e9d563d2226207a649d6da878da1966fa1f5a85 GIT binary patch literal 498 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 literal 0 HcmV?d00001 diff --git a/base/themes/default/prosecutionbar1.png b/base/themes/default/prosecutionbar1.png new file mode 100644 index 0000000000000000000000000000000000000000..b44323c921ade3aecf3c8a356b7c173da0f301b6 GIT binary patch literal 237 zcmeAS@N?(olHy`uVBq!ia0vp^AwbN>!2~4jWY(|)DaPU;cPEB*=VV?2IV|apzK#qG z8~eHcB(eheoCO|{#Xt?aK$uZdl!@TsywNZ vRE4|3AD->p9a;QLf1;T(0kp5~#5?BC(Gm$WZ%>E?8q476>gTe~DWM4f=JiB+ literal 0 HcmV?d00001 diff --git a/base/themes/default/prosecutionbar10.png b/base/themes/default/prosecutionbar10.png new file mode 100644 index 0000000000000000000000000000000000000000..f0a79c3ec082102246a27fda9bac3d13e8d6945f GIT binary patch literal 173 zcmeAS@N?(olHy`uVBq!ia0vp^AwbN>!3HEZ)>#JtDYhhUcNYdT21^EeuYau7KoQOY zkH})6s@)*Wc>Ko|GoT=QiKnkC`y(E11_MR0wwM;6kd>#4V@Sl|w>KOa85DS!H}aMS zw;T90c78hTd1C!r<6`fPRpE@h+XNU`xk4NonM4B?IIw>CJgvMhrTW%Uw#ZcXqRBv0 O7(8A5T-G@yGywpXa4;(X literal 0 HcmV?d00001 diff --git a/base/themes/default/prosecutionbar2.png b/base/themes/default/prosecutionbar2.png new file mode 100644 index 0000000000000000000000000000000000000000..8bb51da5b4c0b769bdb2d8c41ce74af4d15b610b GIT binary patch literal 241 zcmeAS@N?(olHy`uVBq!ia0vp^AwbN>!2~4jWY(|)DaPU;cPEB*=VV?2IV|apzK#qG z8~eHcB(eheoCO|{#Xt?aK$uZnD9B(aaQHxT`3t5uflI>| z{|vjR!&p8q|9fQdv-u%6mIWow_G-=565X~E7iZr;=Q91s>AnlD9iR3FXf%VTtDnm{ Hr-UW|)1pnX literal 0 HcmV?d00001 diff --git a/base/themes/default/prosecutionbar3.png b/base/themes/default/prosecutionbar3.png new file mode 100644 index 0000000000000000000000000000000000000000..d0b9c4c225808e9fa9b5beb6dcea1e161a97dac1 GIT binary patch literal 230 zcmeAS@N?(olHy`uVBq!ia0vp^AwbN>!2~4jWY(|)DVB6cUq=Rpjs4tz5?O(K&H|6f zVxXFxAk4UfO?*F4kiEpy*OmPd4>yC6_-n4!^MOJVC9V-A!TD(=<%vb93~dWL!?!VVcnfNBCgT^vI^yq{h(Rq*=zv4UXPOQt|&4cZ(maY!2~4jWY(|)DaPU;cPEB*=VV?2IV|apzK#qG z8~eHcB(eheoCO|{#Xt?aK$uZn$je|LaQHy`_ZM7iR_vqXnbHiFdp{}b=B|4ZF>;>KI+b3nrxJYD@<);T3K0RTpi BQ$_#) literal 0 HcmV?d00001 diff --git a/base/themes/default/prosecutionbar5.png b/base/themes/default/prosecutionbar5.png new file mode 100644 index 0000000000000000000000000000000000000000..6bb5eb56553826ea79be32a9cf329b771a58bda7 GIT binary patch literal 241 zcmeAS@N?(olHy`uVBq!ia0vp^AwbN>!2~4jWY(|)DaPU;cPEB*=VV?2IV|apzK#qG z8~eHcB(eheoCO|{#Xt?aK$uZnD9B*IbNIjk?p;jUtKKmw z@LsiL=%2Uy_gc%~uESE1GS^N#+TbSEZo0{0&BUXLy*hl^DTNWr-AGdF|4+Qj{<8kp V2HUet)j*>eJYD@<);T3K0RTL>OX~mt literal 0 HcmV?d00001 diff --git a/base/themes/default/prosecutionbar6.png b/base/themes/default/prosecutionbar6.png new file mode 100644 index 0000000000000000000000000000000000000000..9ee9638f6be7ff48c6df805150c135ff9e2e121d GIT binary patch literal 241 zcmeAS@N?(olHy`uVBq!ia0vp^AwbN>!2~4jWY(|)DaPU;cPEB*=VV?2IV|apzK#qG z8~eHcB(eheoCO|{#Xt?aK$uZn$je|LaQHy`_ZM7iR_u~) zNL_jDZKQGe_vqqf9$c#hgCcq-9Lj1D2~%FOK}xapDu?D8H;+V9CnTwT|J=*u#ToSf UFZtQ*12me!)78&qol`;+08Twg)c^nh literal 0 HcmV?d00001 diff --git a/base/themes/default/prosecutionbar7.png b/base/themes/default/prosecutionbar7.png new file mode 100644 index 0000000000000000000000000000000000000000..34e00da9068ea5ce46627d4ad03aaf014c037dfd GIT binary patch literal 242 zcmeAS@N?(olHy`uVBq!ia0vp^AwbN>!2~4jWY(|)DaPU;cPEB*=VV?2IV|apzK#qG z8~eHcB(eheoCO|{#Xt?aK$uZ{h;;P3(M_p7`U<3o3B zXsBBhne*mn*?iOVe=dBl3yUK9Cm*hwBXjNXlMQm}?O!b{*Bn2YXzPb0weO#EnZBEP Ws{Q_@`7J=R89ZJ6T-G@yGywpLKu;|I literal 0 HcmV?d00001 diff --git a/base/themes/default/prosecutionbar8.png b/base/themes/default/prosecutionbar8.png new file mode 100644 index 0000000000000000000000000000000000000000..5035b51e9826634bc211f164ffc52ecc28d5a05a GIT binary patch literal 240 zcmeAS@N?(olHy`uVBq!ia0vp^AwbN>!2~4jWY(|)DaPU;cPEB*=VV?2IV|apzK#qG z8~eHcB(eheoCO|{#Xt?aK$uZ{h;;P3(M_p7`U<3o2W zm|-{T=&^bE-y@5ksr$@$VU)P&bW5k6u-YzMoPGbC%k&ppFI0cRvh@YfWCl-HKbLh* G2~7a2l}$!2~4jWY(|)DaPU;cPEB*=VV?2IV|apzK#qG z8~eHcB(eheoCO|{#Xt?aK$uZnD9B*IbNIjk?p;jUtKLbm wI9&ak!7y+4@3oe~>4~?J@uP>Y>r=inn(FVdQ&MBb@0DiekjQ{`u literal 0 HcmV?d00001 diff --git a/base/themes/default/publicservers.png b/base/themes/default/publicservers.png new file mode 100644 index 0000000000000000000000000000000000000000..98cf2ad8e554fa9e0ee67929d56a1a9502945fbd GIT binary patch literal 3999 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 literal 0 HcmV?d00001 diff --git a/base/themes/default/refresh_pressed.png b/base/themes/default/refresh_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..803668381cc48f32b4317029d302a7a41690f562 GIT binary patch literal 919 zcmV;I18Dq-P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02p*dSaefwW^{L9 za%BK;VQFr3E^cLXAT%y8E;(#7eog=Y0|-e(K~!i%?U=o86G0S({Tx(O(9nUO0jQ|x zXq<+pNCgz>5Cs(l2%%Uc5(OwAK>$HSkp#&>fGod)A7a_DbXRA`=kA@^AMavK@!_3& z&fM|NJyMWIS(bIe-s}BrJRT=HVE@y{{EGR#H-#3PaPaxK_~Lgjj}jdq_j`IV%decz zp)RyohxuZ$7KD3=PVj@_&!P#m7|U|GECpfbYGM;$Fdn}-%tyiJ69X-Va`xwUk?82m-z=11|#CA%uFnIN$PXecjr}(nFC@IKG~p<|E~E z7HHA&{pWcp2yKPI5px-q7YX%RKGZEQVtG-I@iILInV-zlpEW{@_n$uLBnU#xWmsM$ z)NA=rx4cM*S9)4rORob4neP&`_$<2e8J!2)`I5Iz&&ju zbC$WE|GHQOW3H6N>MUWW5j`LGv0TVAHO z&ENyU{$!w+5$e@^tgd+(mKXIHFVov*kbz(tu0sg9#44Y!;o8FTYklQx#M0Yluz~P( zdA2~W`(%9u%ZIu=TVOA35A$FRvGlg-JrDxZ9q6e8>nViz&=ZQaU(>N3s<%zAfk+IG z6o^EL6o^EL6o^EL6o^ELjRj)TGVF{MSHhWulJ^}V^!*!B3dHX1YuUq{TN~lQ=QvrQbS!_R7H}VnH2);@A% YqyV2~!W#zn_94J}#!__Ld%` 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 alg;Jx`9i@6L^3TEi^WpO_7PxUeE$c+-ULMe literal 0 HcmV?d00001 diff --git a/base/themes/default/takethat.png b/base/themes/default/takethat.png new file mode 100644 index 0000000000000000000000000000000000000000..8ff2befe32fd104826f57b8778c921a643de878e GIT binary patch literal 2057 zcmV+k2=@1hP)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00009 za7bBm000ic000ic0Tn1pfB*mh7<5HgbW?9;ba!ELWdLwtX>N2bZe?^JG%heMHD!e| zWdHyNTS-JgRA@u(n%h$pM-+zvuVqCRQpOjxykDxU(kk`E2OsoFlbDOSnHWvtC5ott zf)FDHf|yX=qJZe0TYpdye@E|mAApEv|eX@^lj2bm~(IjSBSB=GDS7M}!MPZ-5WEdSyS8bfbW1u8nl4E-W;=r%w;f8wlTe{ezzb#%KpVm><)SAQ}|w z`iT>E@NiG)6kL&%?}VUWJpWSIF@C(yW`7{qX{m=tgylaA*m!^)k8^@f&v?9RWPSam zk)8zU{}5|JMwW?|mYSwhr%X+LzS$&(q0DOt9t%w#tAtG>M)+_$s)7NXW-7-!JCpg% zXU`_vfW2eJnD)DOZ61Qv%CneIK5?SyXlqN>3v%!3Rr9fw`${Mj=zn)CmdLwy&1{ip z+7CFzRr1`JCaY)qqOsgk@gp%*<-uFf2JQ&uLR_d5_RO7Ys@ASGmntfJ9S`CPhPWGt z4>x<~&$oFON=nReCm-uO9B(Nb?aM6B0zpG76y_fs+W zyJsBFLad6VOU*tB+^Gb6(%o&2OPOZL%NITuPRgoe2QM&v-x09O0NxY+5XeKgwE|P` zkwAS0h42W5s0bPqjFtDwp+i1)NjViJXq$WblP}|S?I>t~7U&`|?P<|;8md^z&1lqo zAcpq|bo%(3HTJnH*jB0M*4a02o@tQh+EKieLF+w1-+G=0@k-MSsKrZf7fJ+z{Z;|N z@VqS&+uE9&eQlP_nq|vHFbXVPYv=?d_)X;X_ML zPmg`3g7L<8I}PuiF(Wyhbm@K;!Fc;DD(?zAgl;cQeHE-^!GdIazzfqhvAxktyD%j$ zmX{|5<3*p@w#{cJ3>8f@N_bhqvr_M~QlWy;xW<{bn>S6F1ad_DQBaXw!R`u7bJBPc z3yTWI^h9JpxQ9X>_Y)?V1Iw0K!OjcY$Bi>}Wo5R_s&(t^6lZ}TCL%U*5katxT>?9G zn5HTi0$!6C?T#rG3DNA?GqcYfd|x1#^(+Cwis#Hp24>zi0#ynf!Upf2vPXqqgjNAB zV|8W4yd;qCf>>pX7u)u}mNa#+!}P2cXtOdi)5f};0)kPGX}NRKq-2{2Rxo9X$u4I}|SuY&O+IDz1G+*5|K^asI$w$tUg3WgAfqJlAP$h$4D*~MEZ5A6c+YS-k+c27hw zX2ZE&*gSf4vK;l9?(7NKU%7(m76MPDJz|;r0)Xc%UMsl|8Bc!=Eb})D#y# zHI{T3v|zd!)K2~Cq{FZ~_vOp&pa|-$fGhxcW5-&1tj3r3@3+&AIH)TygZy6LWZ}LH zdro!0UXRBC0Xquy5E~I$?So@Uhd~Plu3%?`zn%Mw-c_fj3U+YiN_*C00Bl2|d3lx} zr%w#qEFc*5*r`M8@ngGLB_QKLY76uf;R>cfAG@3mG=^cDRa5QWZ)mXX@I8)| zS#7hG*^!;?8$-GbiC`RSSmNo74vMJ)4abfp)4*E~v%%Md!;;SwLYzNQ7Hui>;?T;Z5j16Q^u&{D{alf(AdL|zs5l97ND&u{m5v;bf^eMs0 zmn;djsUR3rRZjwV^4p|C%J#=gBN!kWv4%ss3I?1ExU$tius7w(6yq5i;{F69UKP!p zY0Gk=z#Fd~J{(%MKdfM!$ip(zg?NFB6VOk19SSR#F7EL~!M1+0VkKn@0jZ|=^TK|; z7_5iExuPN)%;9!zZD^Tv(a$n$5fF=g7}JzC!pgr$5+0VF8=CoF!4xW(I@KO;*st;Z z?XQ}e(6TQYw6Y%7)zxJhC5HS@YS74f82=;~>s=FM%U*?RPR{Fz`@nzkYyRNzw+lhr niTi*5JYgvR+#o%)j}h|^`=|ZHVemoH00000NkvXXu0mjfqw>jh literal 0 HcmV?d00001 diff --git a/base/themes/default/takethat_selected.png b/base/themes/default/takethat_selected.png new file mode 100644 index 0000000000000000000000000000000000000000..3fe0a8cd13fa0244f7b9c87076b6f24cef43ba57 GIT binary patch literal 1932 zcmV;72Xpv|P)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00009 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 DatZql literal 0 HcmV?d00001 diff --git a/base/themes/default/testimony.png b/base/themes/default/testimony.png new file mode 100644 index 0000000000000000000000000000000000000000..7b81fc8edd4ef09a584d532a7dc6ffd2380a4134 GIT binary patch literal 579 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K54lpqT$!X1@Ux5@$x}&cn1H;CC?mvmFK)yn< zN02WALzNl>LqiJ#!!Mvv!wUw6QUeBtR|yOZRx=nF#0%!^3bX-A@C5jTxc>kDpW&D# zkX-tG>$bQ|d!RUDNswPKgTu2MX&_FLx4R2N2dk_Hki%Z$>Fdh=kcp2`NOZo%j@v+K zbx#+^kc@k8uNvkx8;Be$G%8?uZWFs{yU_WGHYN3Lrxz;ofa$6^7yyts4z3Ns%G(RkbM zQt6oAv^7BHyW{bn_WbN-Ieo`WOgHnj8?rbaV2d^{y*~3A-=YIHXX3pNeBCC>+V`aL6PbkT5%QsbL?x-eL`dC9J!?rSqQI)bRCt!`~?^ZQnC_LnfIn_`8dH zo!6aXUk-TwQ1vqmuu3bQG`DqSC*$?w2e!X4`K6i=m8fu!{kQ4@XC9lnz4icSH82?NY~EB@i?ssk)DI3s{^swJ)wB`Jv| zsaDBFsX&Us$iUEC*T6{E&?Lmb(8|!l%E(X~$S^R-UUYUjiiX_$l+3hB+#00*mr8?d N_jL7hS?83{1OVp+&RqZi literal 0 HcmV?d00001 diff --git a/base/themes/default/witnesstestimony.gif b/base/themes/default/witnesstestimony.gif new file mode 100644 index 0000000000000000000000000000000000000000..03b4900c1e06eb38c598cfdab23d64e66d246bf3 GIT binary patch literal 105223 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

W|mC@qaQ1*c4C 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 diff --git a/resource/translations/ao_es.ts b/resource/translations/ao_es.ts deleted file mode 100644 index 2cad7ce..0000000 --- a/resource/translations/ao_es.ts +++ /dev/null @@ -1,1048 +0,0 @@ - - - - - AOApplication - - - Disconnected from server. - Desconectado del servidor. - - - - Error connecting to master server. Will try again in %1 seconds. - Error al conectarse a la lista de servidores. Se intentará nuevamente en %1 segundos. - - - - There was an error connecting to the master server. -We deploy multiple master servers to mitigate any possible downtime, but the client appears to have exhausted all possible methods of finding and connecting to one. -Please check your Internet connection and firewall, and please try again. - I translated master servers as "lista de servidores" because literally nobody will understand if i make the literal translation "servidor maestro". And in the end a master server is just a list of servers. Also removed the part about having multiple master servers, i just don't think the average user will understand this even if i do a good translation. - Hubo un error al obtener la lista de servidores. Verifique su conexión a Internet y firewall, y vuelva a intentarlo. - - - - Outdated version! Your version: %1 -Please go to aceattorneyonline.com to update. - ¡Versión desactualizada! Su versión: %1 -Ingrese a aceattorneyonline.com para actualizar. - - - - You have been exiled from AO. -Have a nice day. - Has sido exiliado de AO. -Que tengas un buen día. - - - - Attorney Online 2 - - - - - Loading - Cargando - - - - Loading evidence: -%1/%2 - Cargando evidencia: -%1/%2 - - - - - Loading music: -%1/%2 - Cargando música: -%1/%2 - - - - - Loading chars: -%1/%2 - Cargando personajes: -%1/%2 - - - - You have been kicked from the server. -Reason: %1 - Has sido expulsado del servidor. -Razón: %1 - - - - You have been banned from the server. -Reason: %1 - Has sido bloqueado de este servidor. -Razón: %1 - - - - You are banned on this server. -Reason: %1 - Has sido bloqueado en este servidor. -Razón: %1 - - - You have been kicked from the server. -Reason: - Has sido expulsado del servidor. -Razón: - - - You are banned on this server. -Reason: - Has sido bloqueado en este servidor. -Razón: - - - - AOCaseAnnouncerDialog - - - Case Announcer - Anunciar caso - - - - Case title: - Título del caso: - - - - Defense needed - Se necesita abogado - - - - Prosecution needed - Se necesita fiscal - - - - Judge needed - Se necesita juez - - - - Jurors needed - Se necesita jurado - - - - Stenographer needed - Se necesita taquígrafo - - - - Witness needed - Se necesita testigo - - - - AOOptionsDialog - - - Settings - Ajustes - - - - Gameplay - Jugabilidad - - - - Theme: - Tema visual: - - - - Sets the theme used in-game. If the new theme changes the lobby's look as well, you'll need to reload the lobby for the changes to take effect, such as by joining a server and leaving it. - Establece el tema visual utilizado en el juego. Si el nuevo tema también cambia el aspecto del lobby, deberá volver a cargar el lobby para que los cambios surtan efecto, como unirse a un servidor y volver al lobby. - - - - Log goes downwards: - Invertir historial IC: - - - - If ticked, new messages will appear at the bottom (like the OOC chatlog). The traditional (AO1) behaviour is equivalent to this being unticked. - Si está marcado, los nuevos mensajes aparecerán en la parte inferior (como el chat OOC). - - - - Log length: - Limite del historial: - - - - The amount of messages the IC chatlog will keep before deleting older messages. A value of 0 or below counts as 'infinite'. - La cantidad de mensajes que mantendrá el historial del chat IC antes de eliminar mensajes más antiguos. 0 significa 'infinito'. - - - - Default username: - Usuario predeterminado: - - - - Your OOC name will be automatically set to this value when you join a server. - Su nombre OOC se establecerá automáticamente a este cuando se una a un servidor. - - - - Custom shownames: - Mostrar nombres: - - - Gives the default value for the in-game 'Custom shownames' tickbox, which in turn determines whether the client should display custom in-character names. - Activa la casilla 'Mostrar nombres' de forma predeterminada en el juego, que a su vez determina si el cliente debe mostrar nombres personalizados en los personajes. - - - - Backup MS: - Master SV de respaldo: - - - - If the built-in server lookups fail, the game will try the address given here and use it as a backup master server address. - Si la lista de servidores predeterminada falla, el juego probará la dirección proporcionada aquí. - - - - Discord: - Discord: - - - - Allows others on Discord to see what server you are in, what character are you playing, and how long you have been playing for. - Permite a otros en Discord ver en qué servidor estás, qué personaje juegas y cuánto tiempo has estado jugando. - - - - Allow Shake/Flash: - Permitir Shake/Flash: - - - - Allows screenshaking and flashing. Disable this if you have concerns or issues with photosensitivity and/or seizures. - Permite el movimiento de la pantalla y el parpadeo. Desactive esto si tiene inquietudes o problemas con la fotosensibilidad y/o convulsiones. - - - - Language: - Idioma: - - - - Sets the language if you don't want to use your system language. - Establece el idioma si no desea utilizar el idioma de su sistema. - - - - Punctuation delay modifier. Enable it for the blips to slow down on punctuations. - Habilítelo para agregar una pequeña pausa en los signos de puntuación. - - - - Callwords - Palabras clave - - - - <html><head/><body>Enter as many callwords as you would like. These are case insensitive. Make sure to leave every callword in its own line!<br>Do not leave a line with a space at the end -- you will be alerted everytime someone uses a space in their messages.</body></html> - <html><head/><body>Ingrese tantas palabras de llamada como desee.<br>Esto no distingue entre mayúsculas y minúsculas. ¡Asegúrese de dejar cada palabra en su propia línea!<br>No deje una línea con un espacio al final; recibirá una alerta cada vez que alguien use un espacio en sus mensajes.</body></html> - - - - Audio - Audio - - - - Audio device: - Dispositivo: - - - - Sets the audio device for all sounds. - Establece el dispositivo de audio. - - - - Music: - Música: - - - Sets the music's default volume. - Establece el volumen predeterminado de la música. - - - - SFX: - SFX: - - - Sets the SFX's default volume. Interjections and actual sound effects count as 'SFX'. - Establece el volumen predeterminado de SFX. Las interjecciones y los efectos de sonido reales cuentan como 'SFX'. - - - - Gives the default value for the in-game 'Custom shownames' checkbox, which in turn determines whether the client should display custom in-character names. - Activa la casilla 'Mostrar nombres' de forma predeterminada en el juego, que a su vez determina si el cliente debe mostrar nombres personalizados en los personajes. - - - - Slower text speed: - Texto más lento: - - - - Set the text speed to be the same as the AA games. - La velocidad del texto será la misma que en los juegos de AA. - - - - Blip delay on punctuations: - Retraso en puntuación: - - - - Sets the default volume for music. - Establece el volumen predeterminado de la música. - - - - Sets the default volume for SFX sounds, like interjections or other character sound effects. - Establece el volumen predeterminado para sonidos SFX, como las interjecciones y otros efectos de sonido de personajes. - - - - Blips: - Blips: - - - - Sets the volume of the blips, the talking sound effects. - Establece el volumen de los blips, el sonido al hablar. - - - - Blip rate: - Tasa de blips: - - - - Sets the delay between playing the blip sounds. - Establece el retraso entre la reproducción de los sonidos blip. - - - - Blank blips: - Blips en blanco: - - - - If true, the game will play a blip sound even when a space is 'being said'. - Si está marcada, el juego reproducirá un sonido blip incluso cuando se 'dice' un espacio. - - - - Enable Looping SFX: - Habilitar repetición de SFX: - - - - If true, the game will allow looping sound effects to play on preanimations. - Si está habilitado, el juego permitirá que se reproduzcan efectos de sonido en bucle en preanimaciones. - - - - Kill Music On Objection: - Parar la música al objetar: - - - - If true, the game will stop music when someone objects, like in the actual games. - Si está habilitado, el juego detendrá la música cuando alguien haga una objeción, como en los juegos. - - - - Casing - Caso - - - - This server supports case alerts. - Este servidor admite alertas de casos. - - - - This server does not support case alerts. - Este servidor no admite alertas de casos. - - - - Pretty self-explanatory. - Bastante autoexplicativo. - - - - Casing: - Caso: - - - - If checked, you will get alerts about case announcements. - Si está marcado, recibirá anuncios de casos. - - - - Defense: - Abogado: - - - - If checked, you will get alerts about case announcements if a defense spot is open. - Si está marcado, recibirá alertas sobre anuncios de casos si hay un lugar de abogado libre. - - - - Prosecution: - Fiscal: - - - - If checked, you will get alerts about case announcements if a prosecutor spot is open. - Si está marcada, recibirá alertas sobre anuncios de casos si hay un puesto de fiscal libre. - - - - Judge: - Juez: - - - - If checked, you will get alerts about case announcements if the judge spot is open. - Si está marcado, recibirá alertas sobre anuncios de casos si el puesto de juez está libre. - - - - Juror: - Jurado: - - - - If checked, you will get alerts about case announcements if a juror spot is open. - Si está marcado, recibirá alertas sobre anuncios de casos si hay un puesto de jurado libre. - - - - Stenographer: - Taquígrafo: - - - - If checked, you will get alerts about case announcements if a stenographer spot is open. - Si está marcado, recibirá alertas sobre anuncios de casos si hay un lugar de taquígrafo libre. - - - - CM: - CM: - - - - If checked, you will appear amongst the potential CMs on the server. - Si está marcado, aparecerá entre los posibles CM en el servidor. - - - - Witness: - Testigo: - - - - If checked, you will appear amongst the potential witnesses on the server. - Si está marcado, aparecerá entre los posibles testigos en el servidor. - - - - Hosting cases: - Casos: - - - - If you're a CM, enter what cases you are willing to host. - Si eres un CM, ingresa qué casos estás dispuesto a organizar. - - - - IC Log - - - - - Only inline coloring will be shown such as <>,|| etc. - Solo se mostrará el color en línea, como <>, ||, etc. - - - - IC log will mirror the IC box. Meaning that if somebody gets interrupted nobody will know what they wanted to say. Enable for a more realistic experience. - El registro de IC reflejará el chat In-Character. Lo que significa que si alguien es interrumpido, nadie sabrá lo que se iba a decir. Habilitar para una experiencia más realista. - - - IC log will mirror the IC box. Meaning that if somebody gets interrupted nobody will know what they wanted to say. Enable for a more realistic experience - El registro de IC reflejará el chat In-Character. Lo que significa que si alguien es interrumpido, nadie sabrá lo que se iba a decir. Habilitar para una experiencia más realista. - - - - Colorful IC log: - Log IC colorido: - - - - Enables colored text in the log. - Habilita texto con color en el log. - - - - Only inline coloring: - Solo coloración en línea: - - - Only inline coloring will be shown such as <>,|| etc - Solo se mostrará el color en línea, como <>, ||, etc. - - - - Mirror IC log: - IC log refleja interrupciones: - - - IC log will mirror the IC box. Meaning that if somebody gets interupted nobody will know what they wanted to say. Enable for a more realistic expierence - El registro de IC reflejará el chat In-Character. Lo que significa que si alguien es interrumpido, nadie sabrá lo que se iba a decir. Habilitar para una experiencia más realista. - - - - Courtroom - - - Password - Contraseña - - - - Spectator - Espectador - - - - - Search - Buscar - - - - Passworded - A translation wouldn't fit because of the shitty theme system. - - - - - Taken - En uso - - - - Could not find %1 - No se pudo encontrar %1 - - - Generating chars: -%1/%2 - Generando personajes: -%1/%2 - - - Generating chars: - - Generando personajes: - - - - - Showname - A translation wouldn't fit because of the shitty theme system. - - - - - Message - Mensaje - - - - Name - Nombre - - - - Pre - A translation wouldn't fit because of the shitty theme system. - - - - - Flip - A translation wouldn't fit because of the shitty theme system. - - - - Guard - Guardia - - - - - Casing - This could be translated as 'caso' and it wouldn't get cut, but there are so many other buttons that can't be translated on the courtroom window that might as well leave this also untranslated so it's at least consistent. - - - - - Shownames - A translation wouldn't fit because of the shitty theme system. - - - - - No Interrupt - A translation wouldn't fit because of the shitty theme system. - - - - - White - Blanco - - - - Green - Verde - - - - Red - Rojo - - - - Orange - Naranja - - - - Blue - Azul - - - - Yellow - Amarillo - - - - Rainbow - Arcoíris - - - - Pink - Rosado - - - - Cyan - Cian - - - - % offset - % desplazamiento - - - - Music - - - - - Sfx - - - - - Blips - - - - - Log limit - - - - - Change character - - - - - Reload theme - - - - - Call mod - - - - - Settings - - - - - A/M - - - - - Preanim - - - - - Back to Lobby - 'Volver al lobby' got cut, changed to just Lobby - Lobby - - - - - You were granted the Disable Modcalls button. - Se le concedió el botón para deshabilitar llamadas a moderadores. - - - - You have been banned. - Has sido vetado. - - - You were granted the Guard button. - Te ha sido otorgado el botón Guardia. - - - - This does nothing, but there you go. - Esto no hace nada, pero ahí lo tienes. - - - - You opened the settings menu. - Abriste el menú de configuración. - - - - You will now pair up with - Ahora te emparejarás con - - - - if they also choose your character in return. - si ellos también eligen a tu personaje a cambio. - - - - You are no longer paired with anyone. - Ya no estás emparejado con nadie. - - - - Are you sure you typed that well? The char ID could not be recognised. - ¿Estás seguro de que lo escribiste bien? El ID de personaje no pudo ser reconocido. - - - - You have set your offset to - Ha configurado su desplazamiento en - - - - Your offset must be between -100% and 100%! - ¡Su desplazamiento debe estar entre -100% y 100%! - - - - That offset does not look like one. - Ese desplazamiento no se parece a uno. - - - - You switched your music and area list. - Cambiaste tu lista de música y área. - - - - You have forcefully enabled features that the server may not support. You may not be able to talk IC, or worse, because of this. - Ha habilitado forzosamente funciones que el servidor puede no admitir. Es posible que no pueda hablar IC, o peor, debido a esto. - - - - Your pre-animations interrupt again. - Sus pre-animaciones interrumpen de nuevo. - - - - Your pre-animations will not interrupt text. - Sus pre-animaciones no interrumpirán el texto. - - - - Couldn't open chatlog.txt to write into. - No se pudo abrir chatlog.txt para escribir. - - - - The IC chatlog has been saved. - El chat IC se ha guardado. - - - - You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely the case file you're looking for can't be found in there. - ¡No tienes una carpeta `base/cases /`! Ha sido creada para ti. Pero debido a que no existia la carpeta, tampoco habían casos guardados ahí. - - - - You need to give a filename to load (extension not needed)! Make sure that it is in the `base/cases/` folder, and that it is a correctly formatted ini. -Cases you can load: %1 - ¡Debe dar un nombre de archivo para cargar (no se necesita extensión)! Asegúrese de que esté en la carpeta `base/cases/` y de que tenga el formato correcto. -Casos que puede cargar: %1 - - - - Case made by %1. - Caso hecho por %1. - - - - Navigate to %1 for the CM doc. - Navegue a %1 para el documento del CM. - - - - Your case "%1" was loaded! - Su caso "%1" fue cargado! - - - You need to give a filename to load (extension not needed)! Make sure that it is in the `base/cases/` folder, and that it is a correctly formatted ini. -Cases you can load: - ¡Debe dar un nombre de archivo para cargar (no se necesita extensión)! Asegúrese de que esté en la carpeta `base/cases/` y de que tenga el formato correcto. -Casos que puede cargar: - - - - Too many arguments to load a case! You only need one filename, without extension. - ¡Demasiados argumentos para cargar un caso! Solo necesita un nombre de archivo, sin extensión. - - - Case made by - Caso hecho por - - - Navigate to - Navegue a - - - for the CM doc. - para el documento de CM. - - - Your case " - Su caso " - - - " was loaded! - " fue cargado! - - - - You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely that you somehow deleted it. - ¡No tienes una carpeta `base/cases /`! Fue creada para ti. - - - - You need to give a filename to save (extension not needed) and the courtroom status! - ¡Debe dar un nombre de archivo para guardar (no se necesita la extensión) y el estado de la sala del tribunal! - - - Too many arguments to save a case! You only need a filename without extension and the courtroom status! - why two exclamations, seems excesive. - ¡Demasiados argumentos para salvar un caso! Solo necesita un nombre de archivo sin extensión y el estado de la sala del tribunal. - - - - Succesfully saved, edit doc and cmdoc link on the ini! - ¡Guardado con éxito, puede editar el doc y doc link en el archivo ini! - - - - Master - - - - - - Server - - - - - OOC Message - Mensaje OOC - - - - Disable Modcalls - - - - - Too many arguments to save a case! You only need a filename without extension and the courtroom status. - ¡Demasiados argumentos para salvar un caso! Solo necesita un nombre de archivo sin extensión y el estado de la sala del tribunal. - - - - Reason: - Razón: - - - - Call Moderator - Llamar Moderador - - - - - Error - Error - - - - You must provide a reason. - Debes proporcionar una razón. - - - - The message is too long. - El mensaje es muy largo. - - - - Choose... - Elegir... - - - - Images (*.png) - Imágenes (* .png) - - - - Add new evidence... - Añadir nueva evidencia... - - - - Lobby - - - Attorney Online 2 - - - - - Name - Nombre - - - - It doesn't look like your client is set up correctly. -Did you download all resources correctly from tiny.cc/getao, including the large 'base' folder? - No parece que su cliente esté configurado correctamente. -¿Descargó todos los recursos correctamente desde tiny.cc/getao, incluida la gran carpeta 'base'? - - - - Version: %1 - Versión: %1 - - - - Loading - Cargando - - - - Cancel - Cancelar - - - - <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Cents02<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, Raidensnake - <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Cents02<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, Raidensnake - - - <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy - <h2>Attorney Online %1</h2>El simulador de drama legal<p><b>Código fuente:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https: //github.com/AttorneyOnline/AO2-Client</a><p><b>Desarrollo mayor:</b> <br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>Agradecimiento especial:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (diseño de interfaz de usuario), Draxirch (diseño de interfaz de usuario), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy - - - - Online: %1/%2 - En línea: %1/%2 - - - - - Offline - Fuera de línea - - - - debug_functions - - - Error: %1 - - - - - Error - - - - - Notice - In spanish it would be "Aviso", but i believe it's going to be more useful for bug reports to not translate any debug string. - - - - diff --git a/resource/translations/ao_jp.qm b/resource/translations/ao_jp.qm deleted file mode 100644 index e4fb562afc050d239016969576561640e9f3b81b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2004 zcmai#YiJx*6vt0zXJ#LDQ?!=mLnz~iKp%E{QjwOmU-D>ebhE3QNLob9?9R<(>||z{ z-Ax}_klG3wAEiN3p;S#uB6`a ze;-hW4lj_;fO4SMBiRw<60QPJAwm3Ckr%tS5dTqh<1FP1 zZPC=57QK&0*&Fwg&WwI@Zkqg0EuWl|NUt^hJL7ZT6QoXr=q`dca1m$I8zb}pDqZ1} zs~eVMhUq@uo@p->Y%8yqEZ14)3)bL=coqM^R80s;(4ZCCU=w|B<~H}=veEKGx>rob zTH7|YZf@Y&^6IwS&r3S4t~s(1%V18PEnzxdu?{Y2%EKHk7p?r=9bf;7@EWOYPHfO5(z(qXs28DN}lTu2f^M$YdTNcVNdQ6 z9OdG8ho0Y~m0T_5=5qT5vPi8iT%rV35unm|mP2xfU1kF2KKvCg;&qB+hOT3MFW?B* zGt@XGD^YoJI3DmKp`*J7mNI%*+c|(wnUV%erR>z-By+zYsb_eYO_XQ*H%tz=U;N+SEO)o2;m< zU7sj8<~o5#1b@P5zn)y9_UOeD6ID?5w=CzBV8aS5<-T~fhhuVD9~LcU1Se@JD>%hT zHRI`yDPpBMzt9t&5P5k&HwtHU%gMQW1+hu58ypK|nW(C2wb5>4y@UG%PVy@sKRv;r zXm5e#OAU6OG*VZ!{voR*N3^T{#P

  • - - - - AOApplication - - - Disconnected from server. - - - - - Error connecting to master server. Will try again in %1 seconds. - - - - - There was an error connecting to the master server. -We deploy multiple master servers to mitigate any possible downtime, but the client appears to have exhausted all possible methods of finding and connecting to one. -Please check your Internet connection and firewall, and please try again. - - - - - Outdated version! Your version: %1 -Please go to aceattorneyonline.com to update. - - - - - You have been exiled from AO. -Have a nice day. - - - - - Attorney Online 2 - - - - - Loading - ロード中 - - - - Loading evidence: -%1/%2 - 証拠がロード中: %1/%2 - - - - - Loading music: -%1/%2 - 音楽がロード中: %1/%2 - - - - - Loading chars: -%1/%2 - キャラがロード中: %1/%2 - - - - You have been kicked from the server. -Reason: %1 - - - - - You have been banned from the server. -Reason: %1 - - - - - You are banned on this server. -Reason: %1 - - - - - AOCaseAnnouncerDialog - - - Case Announcer - - - - - Case title: - - - - - Defense needed - - - - - Prosecution needed - - - - - Judge needed - - - - - Jurors needed - - - - - Stenographer needed - - - - - Witness needed - - - - - AOOptionsDialog - - - Settings - - - - - Gameplay - - - - - Theme: - - - - - Sets the theme used in-game. If the new theme changes the lobby's look as well, you'll need to reload the lobby for the changes to take effect, such as by joining a server and leaving it. - - - - - Gives the default value for the in-game 'Custom shownames' checkbox, which in turn determines whether the client should display custom in-character names. - - - - - Sets the default volume for music. - - - - - Sets the default volume for SFX sounds, like interjections or other character sound effects. - - - - - IC Log - - - - - Colorful IC log: - - - - - Enables colored text in the log. - - - - - Only inline coloring: - - - - - Only inline coloring will be shown such as <>,|| etc. - - - - - Mirror IC log: - - - - - IC log will mirror the IC box. Meaning that if somebody gets interrupted nobody will know what they wanted to say. Enable for a more realistic experience. - - - - - Log goes downwards: - - - - - If ticked, new messages will appear at the bottom (like the OOC chatlog). The traditional (AO1) behaviour is equivalent to this being unticked. - - - - - Log length: - - - - - The amount of messages the IC chatlog will keep before deleting older messages. A value of 0 or below counts as 'infinite'. - - - - - Default username: - - - - - Your OOC name will be automatically set to this value when you join a server. - - - - - Custom shownames: - - - - - Backup MS: - - - - - If the built-in server lookups fail, the game will try the address given here and use it as a backup master server address. - - - - - Discord: - - - - - Allows others on Discord to see what server you are in, what character are you playing, and how long you have been playing for. - - - - - Allow Shake/Flash: - - - - - Allows screenshaking and flashing. Disable this if you have concerns or issues with photosensitivity and/or seizures. - - - - - Language: - - - - - Sets the language if you don't want to use your system language. - - - - - Slower text speed: - - - - - Set the text speed to be the same as the AA games. - - - - - Blip delay on punctuations: - - - - - Punctuation delay modifier. Enable it for the blips to slow down on punctuations. - - - - - Callwords - - - - - <html><head/><body>Enter as many callwords as you would like. These are case insensitive. Make sure to leave every callword in its own line!<br>Do not leave a line with a space at the end -- you will be alerted everytime someone uses a space in their messages.</body></html> - - - - - Audio - - - - - Audio device: - - - - - Sets the audio device for all sounds. - - - - - Music: - 音楽: - - - - SFX: - 効果音: - - - - Blips: - ブリップ: - - - - Sets the volume of the blips, the talking sound effects. - - - - - Blip rate: - - - - - Sets the delay between playing the blip sounds. - - - - - Blank blips: - - - - - If true, the game will play a blip sound even when a space is 'being said'. - - - - - Enable Looping SFX: - - - - - If true, the game will allow looping sound effects to play on preanimations. - - - - - Kill Music On Objection: - - - - - If true, the game will stop music when someone objects, like in the actual games. - - - - - Casing - - - - - This server supports case alerts. - - - - - This server does not support case alerts. - - - - - Pretty self-explanatory. - - - - - Casing: - - - - - If checked, you will get alerts about case announcements. - - - - - Defense: - - - - - If checked, you will get alerts about case announcements if a defense spot is open. - - - - - Prosecution: - - - - - If checked, you will get alerts about case announcements if a prosecutor spot is open. - - - - - Judge: - - - - - If checked, you will get alerts about case announcements if the judge spot is open. - - - - - Juror: - - - - - If checked, you will get alerts about case announcements if a juror spot is open. - - - - - Stenographer: - - - - - If checked, you will get alerts about case announcements if a stenographer spot is open. - - - - - CM: - - - - - If checked, you will appear amongst the potential CMs on the server. - - - - - Witness: - - - - - If checked, you will appear amongst the potential witnesses on the server. - - - - - Hosting cases: - - - - - If you're a CM, enter what cases you are willing to host. - - - - - Courtroom - - - Password - - - - - Spectator - 観客 - - - - - Search - - - - - Passworded - - - - - Taken - - - - - Could not find %1 - - - - - Showname - - - - - Message - - - - - Name - 名前 - - - - Pre - - - - - Flip - フリップ - - - Guard - ガード - - - - - Casing - - - - - Shownames - - - - - No Interrupt - - - - - White - - - - - Green - - - - - Red - - - - - Orange - オレンジ - - - - Blue - - - - - Yellow - 黄色 - - - - This does nothing, but there you go. - - - - - You need to give a filename to load (extension not needed)! Make sure that it is in the `base/cases/` folder, and that it is a correctly formatted ini. -Cases you can load: %1 - - - - - Case made by %1. - - - - - Navigate to %1 for the CM doc. - - - - - Your case "%1" was loaded! - - - - - - Server - - - - - Back to Lobby - ロビーに戻る - - - - Rainbow - - - - - OOC Message - - - - - Disable Modcalls - - - - - Pink - ピンク - - - - Cyan - シアン - - - - % offset - - - - - Music - 音楽 - - - - Sfx - 効果音 - - - - Blips - ブリップ - - - - Log limit - - - - - Change character - - - - - Reload theme - - - - - Call mod - - - - - Settings - - - - - A/M - - - - - Preanim - - - - - - You were granted the Disable Modcalls button. - - - - - You have been banned. - - - - - Too many arguments to save a case! You only need a filename without extension and the courtroom status. - - - - - You opened the settings menu. - - - - - You will now pair up with - - - - - if they also choose your character in return. - - - - - You are no longer paired with anyone. - - - - - Are you sure you typed that well? The char ID could not be recognised. - - - - - You have set your offset to - - - - - Your offset must be between -100% and 100%! - - - - - That offset does not look like one. - - - - - You switched your music and area list. - - - - - You have forcefully enabled features that the server may not support. You may not be able to talk IC, or worse, because of this. - - - - - Your pre-animations interrupt again. - - - - - Your pre-animations will not interrupt text. - - - - - Couldn't open chatlog.txt to write into. - - - - - The IC chatlog has been saved. - - - - - You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely the case file you're looking for can't be found in there. - - - - - Too many arguments to load a case! You only need one filename, without extension. - - - - - You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely that you somehow deleted it. - - - - - You need to give a filename to save (extension not needed) and the courtroom status! - - - - - Succesfully saved, edit doc and cmdoc link on the ini! - - - - - Master - マスター - - - - Reason: - - - - - Call Moderator - モデレーターを呼ぶ - - - - - Error - エラー - - - - You must provide a reason. - - - - - The message is too long. - - - - - Choose... - 選択... - - - - Images (*.png) - イメージ (*.png) - - - - Add new evidence... - 新しい証拠を付け加える... - - - - Discord - - Objection! - 意義あり! - - - In Lobby - ロビーでいる - - - Idle - 落ちている - - - In a Server - サーバーでいます - - - Spectating - 観客している - - - - Lobby - - - Attorney Online 2 - - - - - Name - 名前 - - - - It doesn't look like your client is set up correctly. -Did you download all resources correctly from tiny.cc/getao, including the large 'base' folder? - - - - - Version: %1 - - - - - Loading - ロード中 - - - - Cancel - キャンセル - - - - <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Cents02<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, Raidensnake - - - - - Online: %1/%2 - - - - - - Offline - オフライン - - - - debug_functions - - - Error: %1 - エラー: %1 - - - - Error - エラー - - - - Notice - 通知 - - - diff --git a/resource/translations/ao_pl.qm b/resource/translations/ao_pl.qm deleted file mode 100644 index 995a5bc91f08641cd446ecac2e65ce5231e56855..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27653 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 a#kE3#6>mR;MfT-#FKzDV{P9rVrT-6}pI-g| diff --git a/resource/translations/ao_pl.ts b/resource/translations/ao_pl.ts deleted file mode 100644 index 2662fcf..0000000 --- a/resource/translations/ao_pl.ts +++ /dev/null @@ -1,987 +0,0 @@ - - - - - AOApplication - - - Disconnected from server. - Odłączono od serwera. - - - - Error connecting to master server. Will try again in %1 seconds. - Błąd podczas łączenia się z głównym serwerem. Spróbuj ponownie za %1 sekundy. - - - - There was an error connecting to the master server. -We deploy multiple master servers to mitigate any possible downtime, but the client appears to have exhausted all possible methods of finding and connecting to one. -Please check your Internet connection and firewall, and please try again. - Odkryto błąd podczas łączenia się z głównym serwerem. -Używamy wielu głównych serwerów, aby zminimalizować każdą możliwą przerwę, ale klient wyczerpał jakąkolwiek możliwość znalezienia i połączenia się z jednym. -Sprawdź swoje połączenie internetowe oraz zaporę ogniową i spróbuj ponownie. - - - - Outdated version! Your version: %1 -Please go to aceattorneyonline.com to update. - Nieaktualna wersja! Twoja wersja: %1 -Udaj się do aceattorneyonline.com, aby zaktualizować. - - - - You have been exiled from AO. -Have a nice day. - Zostałeś wygnany z AO. -Życzymy miłego dnia. - - - - Attorney Online 2 - Prawnik w Internecie 2 - - - - - Loading - Ładowanie - - - - Loading evidence: -%1/%2 - Ładowanie dowodów: -%1/%2 - - - - - Loading music: -%1/%2 - Ładowanie muzyki: -%1/%2 - - - - - Loading chars: -%1/%2 - Ładowanie postaci: -%1/%2 - - - - You have been kicked from the server. -Reason: %1 - Zostałeś wyrzucony z tego serwera. -Powód: %1 - - - - You have been banned from the server. -Reason: %1 - Zostałeś zbanowany z tego serwera. -Powód: %1 - - - - You are banned on this server. -Reason: %1 - Jesteś zbanowany na tym serwerze. -Powód: %1 - - - - AOCaseAnnouncerDialog - - - Case Announcer - Ogłaszacz rozpraw - - - - Case title: - Tytuł rozprawy: - - - - Defense needed - Potrzebny obrońca - - - - Prosecution needed - Potrzebny prokurator - - - - Judge needed - Potrzebny sędzia - - - - Jurors needed - Potrzebny ławnik - - - - Stenographer needed - Potrzebny stenograf - - - - Witness needed - Potrzebny świadek - - - - AOOptionsDialog - - - Settings - Ustawienia - - - - Gameplay - Rozgrywka - - - - Theme: - Motyw: - - - - Sets the theme used in-game. If the new theme changes the lobby's look as well, you'll need to reload the lobby for the changes to take effect, such as by joining a server and leaving it. - Ustawia motyw używany w grze. Jeżeli nowy motyw równiesz zmienia wygląd poczekalni, musisz odświeżyć poczekalnię, aby zmiany zaczęły działać, np. poprzez dołączenie do serwera i wyjście z niego. - - - - Gives the default value for the in-game 'Custom shownames' checkbox, which in turn determines whether the client should display custom in-character names. - - - - - Sets the default volume for music. - - - - - Sets the default volume for SFX sounds, like interjections or other character sound effects. - - - - - IC Log - - - - - Colorful IC log: - - - - - Enables colored text in the log. - - - - - Only inline coloring: - - - - - Only inline coloring will be shown such as <>,|| etc. - - - - - Mirror IC log: - - - - - IC log will mirror the IC box. Meaning that if somebody gets interrupted nobody will know what they wanted to say. Enable for a more realistic experience. - - - - - Log goes downwards: - Dziennik idzie w dół: - - - - If ticked, new messages will appear at the bottom (like the OOC chatlog). The traditional (AO1) behaviour is equivalent to this being unticked. - Jeżeli zaznaczone, nowe wiadomości zaczną się pojawiać na dole (tak jak na czacie OOC). Tradycyjne (AO1) zachowanie jest równoważne do tego bycia nie zaznaczonym. - - - - Log length: - Długość dziennika: - - - - The amount of messages the IC chatlog will keep before deleting older messages. A value of 0 or below counts as 'infinite'. - Ilość wiadomości, jakie czat IC będzie zostawiał zanim usunie starsze wiadomości. Wartośc 0 albo niżej, liczy się jako 'nieskończone'. - - - - Default username: - Domyślna nazwa użytkownika: - - - - Your OOC name will be automatically set to this value when you join a server. - Twoja nazwa OOC będzie ustawiana automatycznie do tej wartości, kiedy dołączysz na serwer. - - - - Custom shownames: - Niestandardowe ksywki: - - - Gives the default value for the in-game 'Custom shownames' tickbox, which in turn determines whether the client should display custom in-character names. - Daje domyślną wartość przyciskowi 'Niestandardowe ksywki', który określa, czy klient powinien pokazywać niestandardowe nazwy IC. - - - - Backup MS: - Kopia zapasowa głównego serwera: - - - - If the built-in server lookups fail, the game will try the address given here and use it as a backup master server address. - Jeśli wbudowane szukanie serwerów zawiedzie, gra spróbuje użyć adresu podanego tutaj i użyje go jako adresu zapasowego głównego serwera. - - - - Discord: - - - - - Allows others on Discord to see what server you are in, what character are you playing, and how long you have been playing for. - Pozwala innym na Discordzie zobaczyć na jakim serwerze się znajdujesz, jaką postać używasz i jak długo grałeś. - - - - Allow Shake/Flash: - Zezwalaj Wstrząśnięcia/Błyśnięcia: - - - - Allows screenshaking and flashing. Disable this if you have concerns or issues with photosensitivity and/or seizures. - Pozwala na wstrząśnięcia ekranu i błyśnięcia. Wyłącz to, jeśli przejmujesz się lub masz problemy z światłoczułością oraz/lub napady padaczkowe. - - - - Language: - Język: - - - - Sets the language if you don't want to use your system language. - Ustawia język, jeśli nie chcesz używać języka systemowego. - - - - Slower text speed: - - - - - Set the text speed to be the same as the AA games. - - - - - Blip delay on punctuations: - - - - - Punctuation delay modifier. Enable it for the blips to slow down on punctuations. - - - - - Callwords - Zawołania - - - - <html><head/><body>Enter as many callwords as you would like. These are case insensitive. Make sure to leave every callword in its own line!<br>Do not leave a line with a space at the end -- you will be alerted everytime someone uses a space in their messages.</body></html> - <html><head/><body>Wpisz tyle zawołań, ile dusza zapragnie. Wielkość liter nie ma znaczenia. Miej na uwadze, aby każde zawołanie było w swojej lini!<br>Nie zostawiaj spacji na końcu -- zostaniesz zaalarmowany za każdym razem, kiedy ktoś użyje spacji w swojej wiadomości.</body></html> - - - - Audio - Dźwięk - - - - Audio device: - Urządzenie dźwiękowe: - - - - Sets the audio device for all sounds. - Ustawia urządzenie dźwiękowe dla wszystkich dźwięków. - - - - Music: - Muzyka: - - - Sets the music's default volume. - Ustawia domyślną głośność muzyki. - - - - SFX: - Efekty dźwiękowe (SFX): - - - Sets the SFX's default volume. Interjections and actual sound effects count as 'SFX'. - Ustawia domyślną głośność efektów dźwiękowych (SFX). Sprzeciwy i same efekty specjalne są zaliczane jako 'SFX'. - - - - Blips: - Blipy: - - - - Sets the volume of the blips, the talking sound effects. - Ustawia głośność blipów, efektów dźwiękowych mówienia. - - - - Blip rate: - Szybkość blipów: - - - - Sets the delay between playing the blip sounds. - Ustawia opóźnienie pomiędzy graniem blipów. - - - - Blank blips: - The 'blip' isn't an accurate polish representation of this english word. - Puste blipy: - - - - If true, the game will play a blip sound even when a space is 'being said'. - Jeżeli zaznaczone, gra zagra dźwięk blip za każdym razem spacja 'jest mówiona'. - - - - Enable Looping SFX: - Włącz pętlące się efekty dźwiękowe (SFX): - - - - If true, the game will allow looping sound effects to play on preanimations. - Jeśli zaznaczone, gra zezwoli na pętlące się efekty dźwiękowe (SFX). - - - - Kill Music On Objection: - Przerwij muzykę w czasie sprzeciwu: - - - - If true, the game will stop music when someone objects, like in the actual games. - Jeśli zaznaczone, gra przerwie muzykę, kiedy ktoś sprzeciwi się, tak jak w oryginalnych grach. - - - - Casing - Rozprawy - - - - This server supports case alerts. - Ten serwer wspiera komunikaty rozpraw. - - - - This server does not support case alerts. - Ten serwer nie wspiera komunikatów rozpraw. - - - - Pretty self-explanatory. - Dosyć oczywiste. - - - - Casing: - Rozprawy: - - - - If checked, you will get alerts about case announcements. - Jeżeli zaznaczone, dostaniesz komunikaty o ogłoszeniach rozpraw. - - - - Defense: - Obrona: - - - - If checked, you will get alerts about case announcements if a defense spot is open. - Jeśli zaznaczone, dostaniesz komunikaty o ogłoszeniach rozpraw, jeśli miejsce obrony jest otwarte. - - - - Prosecution: - Prokuratura: - - - - If checked, you will get alerts about case announcements if a prosecutor spot is open. - Jeśli zaznaczone, dostaniesz komunikaty o ogłoszeniach rozpraw, jeśli miejsce prokuratora jest otwarte. - - - - Judge: - Sędzia: - - - - If checked, you will get alerts about case announcements if the judge spot is open. - Jeśli zaznaczone, dostaniesz komunikaty o ogłoszeniach rozpraw, jeśli miejsce sędzi jest otwarte. - - - - Juror: - Ławnik: - - - - If checked, you will get alerts about case announcements if a juror spot is open. - Jeżeli zaznaczone, dostaniesz komunikaty o ogłoszeniach rozpraw, jeśli miejsce ławnika jest otwarte. - - - - Stenographer: - Stenograf: - - - - If checked, you will get alerts about case announcements if a stenographer spot is open. - Jeżeli zaznaczone, dostaniesz komunikaty o ogłoszeniach rozpraw, jeśli miejsce stenografa jest otwarte. - - - - CM: - Zarządca rozpraw (CM): - - - - If checked, you will appear amongst the potential CMs on the server. - Jeśli zaznaczone, pojawisz się wśród potencjalnych zarządców rozpraw (CM) na serwerze. - - - - Witness: - Świadek: - - - - If checked, you will appear amongst the potential witnesses on the server. - Jeżeli zaznaczone, pojawisz się wśród potencjalnych świadków na serwerze. - - - - Hosting cases: - Hostowane rozprawy: - - - - If you're a CM, enter what cases you are willing to host. - Jeżeli jesteś zarządcą rozpraw (CM), wpisz jakie rozprawy jesteś chętny hostowania. - - - - Courtroom - - - Password - Hasło - - - - Spectator - Widz - - - - - Search - Wyszukaj - - - - Passworded - Zahasłowany - - - - Taken - Zajęty - - - - Could not find %1 - Nie znaleziono %1 - - - Generating chars: -%1/%2 - Generowanie postaci: -%1.%2 - - - - Showname - Ksywka - - - - Message - Wiadomość - - - - Name - Nazwa - - - - Pre - przed- - - - - Flip - Odwróć - - - Guard - Na Służbie (mod) - - - - - Casing - Rozprawa - - - - Shownames - Ksywki - - - - No Interrupt - Bez ociągania się - - - - White - Biały - - - - Green - Zielony - - - - Red - Czerwony - - - - Orange - Pomarańczowy - - - - Blue - Niebieski - - - - Yellow - Żółty - - - - This does nothing, but there you go. - To nic nie robi, ale proszę bardzo. - - - - You need to give a filename to load (extension not needed)! Make sure that it is in the `base/cases/` folder, and that it is a correctly formatted ini. -Cases you can load: %1 - Musisz podać nazwę pliku, którego chcesz załadować (rozszerzenie nie potrzebne!) Upewnij się, że jest w folderze `base/cases/` i że jest to poprawnie sformatowane ini. -Rozprawy które możesz załadować: %1 - - - - Case made by %1. - Rozprawa zrobiona przez %1. - - - - Navigate to %1 for the CM doc. - Przejdź do %1, aby dojść do dokumentu CM. - - - - Your case "%1" was loaded! - Twoja rozprawa "%1" została wczytana! - - - - - Server - Serwer - - - - Back to Lobby - Powrót do poczekalni - - - - Rainbow - Tęczowy - - - - OOC Message - - - - - Disable Modcalls - Wyłącz wezwania moda - - - - Pink - Różowy - - - - Cyan - Turkusowy - - - - % offset - % wyrówanie - - - - Music - Muzyka - - - - Sfx - Sfx - - - - Blips - Blipy - - - - Log limit - Limit dziennika - - - - Change character - Zmiana postaci - - - - Reload theme - Odśwież motyw - - - - Call mod - Wezwij moda - - - - Settings - Ustawienia - - - - A/M - O meaning 'Obszar' and M meaning 'Muzyka'. - O/M - - - - Preanim - Sounds weird but I don't know how to translate it other than this. - przed-animacja - - - - - You were granted the Disable Modcalls button. - - - - - You have been banned. - Zostałeś zbanowany. - - - - Too many arguments to save a case! You only need a filename without extension and the courtroom status. - - - - You were granted the Guard button. - Zostałeś obdarzonym przyciskiem Na Służbie. - - - - You opened the settings menu. - Otworzyłeś opcje. - - - - You will now pair up with - Będzie teraz w parze z - - - - if they also choose your character in return. - jeżeli oni również wybiorą ciebie spowrotem. - - - - You are no longer paired with anyone. - Nie jesteś już w parze z kimkolwiek. - - - - Are you sure you typed that well? The char ID could not be recognised. - Czy jesteś pewien, że dobrze to napisałeś? ID postaci nie zostało rozpoznane. - - - - You have set your offset to - Musisz ustawić swoje wyrównanie do - - - - Your offset must be between -100% and 100%! - Twoje wyrównanie musi być między -100%, a 100%! - - - - That offset does not look like one. - To wyrównanie nie wygląda na takie. - - - - You switched your music and area list. - Przełączyłeś swoją listę obszarów i muzyki. - - - - You have forcefully enabled features that the server may not support. You may not be able to talk IC, or worse, because of this. - Włączyłeś funkcje, które ten serwer może nie wspierać. Możliwe że, nie możesz rozmawiać na czacie IC lub gorzej z powodu tego. - - - - Your pre-animations interrupt again. - Twoje przed-animacje przerywają tekst spowrotem. - - - - Your pre-animations will not interrupt text. - Twoje przed-animacje nie będą przerywać tekstu. - - - - Couldn't open chatlog.txt to write into. - Nie można było otworzyć chatlog.txt, aby pisać w nim. - - - - The IC chatlog has been saved. - Dziennik czatu IC został zapisany. - - - - You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely the case file you're looking for can't be found in there. - Nie masz folderu `base/cases/`! Został zrobiony tylko dla ciebie, ale widząc, że ZOSTAŁ zrobiony tylko dla ciebie, prawdopodobnie plik rozpraw, którego szukasz nie został znaleziony tutaj. - - - - Too many arguments to load a case! You only need one filename, without extension. - Zbyt dużo parametrów, aby załadować rozprawę! Potrzebujesz tylko jedną nazwę pliku, bez rozszerzenia nazwy pliku. - - - - You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely that you somehow deleted it. - Nie masz folderu `base/cases/`! Został zrobiony tylko dla ciebie, ale widząc, że ZOSTAŁ zrobiony tylko dla ciebie, prawdopodobnie jakoś usunąłeś go. - - - - You need to give a filename to save (extension not needed) and the courtroom status! - Musisz podać nazwę pliku, aby go zapisać (rozszerzenie nie potrzebne) i status sali sądowej! - - - Too many arguments to save a case! You only need a filename without extension and the courtroom status! - Zbyt dużo parametrów, aby zapisać rozprawę! Potrzebujesz tylko jedną nazwę pliku, bez rozszerzenia nazwy pliku i statusu sali sądowej! - - - - Succesfully saved, edit doc and cmdoc link on the ini! - Zapisano pomyślnie, edytuj dokument i link cmdoc w .ini! - - - - Master - Główny - - - - Reason: - Powód: - - - - Call Moderator - Wezwij Moderatora - - - - - Error - Błąd - - - - You must provide a reason. - Musisz podać przyczynę. - - - - The message is too long. - Ta wiadomość jest za długa. - - - - Choose... - Wybierz... - - - - Images (*.png) - Plik obrazu (*.png) - - - - Add new evidence... - Dodaj nowe dowody... - - - - Lobby - - - Attorney Online 2 - - - - - Name - Nazwa - - - - It doesn't look like your client is set up correctly. -Did you download all resources correctly from tiny.cc/getao, including the large 'base' folder? - Wygłąda na to, że twój klient nie jest ustawiony poprawnie. -Czy pobrałeś wszystkie zasoby poprawnie z tiny.cc/getao, włączając duży folder 'base'? - - - - Version: %1 - Wersja: %1 - - - - Loading - Ładowanie - - - - Cancel - Anuluj - - - - <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Cents02<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, Raidensnake - - - - <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy - <h2>Attorney Online: %1</h2>Symulator dramy sądowej<p><b>Kod żródłowy:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Główny rozwój:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>Szczególne podziękowania:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy - - - - Online: %1/%2 - - - - - - Offline - - - - - debug_functions - - - Error: %1 - Błąd: %1 - - - - Error - Błąd - - - - Notice - Ogłoszenie - - - diff --git a/resource/translations/ao_pt.qm b/resource/translations/ao_pt.qm deleted file mode 100644 index 242917fff1b18c2741f31d02bb2cd94f27fafc23..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28605 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 diff --git a/resource/translations/ao_pt.ts b/resource/translations/ao_pt.ts deleted file mode 100644 index 824c81e..0000000 --- a/resource/translations/ao_pt.ts +++ /dev/null @@ -1,977 +0,0 @@ - - - - - AOApplication - - - Disconnected from server. - Desconectado do servidor. - - - - Error connecting to master server. Will try again in %1 seconds. - Erro ao conectar ao servidor principal. Testando novamente em %1 segundos. - - - - There was an error connecting to the master server. -We deploy multiple master servers to mitigate any possible downtime, but the client appears to have exhausted all possible methods of finding and connecting to one. -Please check your Internet connection and firewall, and please try again. - Ocorreu um erro ao obter a lista de servidores. Verifique sua conexão à Internet e firewall e tente novamente. - - - - Outdated version! Your version: %1 -Please go to aceattorneyonline.com to update. - Versão desatualizada! Sua versão: %1 -Acesse aceattorneyonline.com para atualizar. - - - - You have been exiled from AO. -Have a nice day. - Você foi exilado do Attorney Online. -Tenha um bom dia. - - - - Attorney Online 2 - - - - - Loading - Carregando - - - - - Loading chars: -%1/%2 - Carregando personagens: -%1/%2 - - - - Loading evidence: -%1/%2 - Carregando evidências: -%1/%2 - - - - - Loading music: -%1/%2 - Carregando músicas: -%1/%2 - - - - You have been kicked from the server. -Reason: %1 - Você foi expulso do servidor. -Motivo: %1 - - - - You have been banned from the server. -Reason: %1 - Você foi banido do servidor. -Motivo: %1 - - - - You are banned on this server. -Reason: %1 - Você foi banido neste servidor. -Motivo: %1 - - - - AOCaseAnnouncerDialog - - - Case Announcer - Anunciar caso - - - - Case title: - Título do caso: - - - - Defense needed - Precisa-se de Defesa - - - - Prosecution needed - Precisa-se de Promotor - - - - Judge needed - Precisa-se de Juíz - - - - Jurors needed - Precisa-se de Jurados - - - - Stenographer needed - Precisa-se de Estenógrafo - - - - Witness needed - Precisa-se de Testemunha - - - - AOOptionsDialog - - - Settings - Configurações - - - - Gameplay - Jogabilidade - - - - Theme: - Tema visual: - - - - Sets the theme used in-game. If the new theme changes the lobby's look as well, you'll need to reload the lobby for the changes to take effect, such as by joining a server and leaving it. - Define o tema usado no jogo. Se o novo tema alterar a aparência do lobby, será necessário recarregá-lo para que as alterações tenham efeito, como ingressar em um servidor e deixá-lo. - - - - Log goes downwards: - Log vai para baixo: - - - - If ticked, new messages will appear at the bottom (like the OOC chatlog). The traditional (AO1) behaviour is equivalent to this being unticked. - Removed the part about AO1 behaviour, nobody cares boomer. - Se selecionado, novas mensagens irão aparecer na parte inferior (assim como o chat OOC). - - - - Log length: - Tamanho do log: - - - - The amount of messages the IC chatlog will keep before deleting older messages. A value of 0 or below counts as 'infinite'. - A quantidade de mensagens que o chat do IC manterá antes de excluir as mensagens mais antigas. Um valor igual ou inferior a 0 conta como 'infinito'. - - - - Default username: - Nome de usuário padrão: - - - - Your OOC name will be automatically set to this value when you join a server. - Seu nome OOC será automaticamente definido com esse valor quando você ingressar em um servidor. - - - - Custom shownames: - Nomes personalizados: - - - Gives the default value for the in-game 'Custom shownames' tickbox, which in turn determines whether the client should display custom in-character names. - 'Custom shownames' changed to 'Shownames' because that's the actual name - Fornece o valor padrão para a caixa de seleção 'Shownames' no jogo, que determina se o cliente deve exibir nomes personalizados nos caracteres. - - - - Backup MS: - MS de backup: - - - - If the built-in server lookups fail, the game will try the address given here and use it as a backup master server address. - Se as pesquisas internas do servidor falharem, o jogo tentará o endereço fornecido aqui e o usará como um endereço de servidor principal de backup. - - - - Discord: - - - - - Allows others on Discord to see what server you are in, what character are you playing, and how long you have been playing for. - Permite que outras pessoas no Discord vejam em que servidor você está, qual personagem está jogando e há quanto tempo está jogando. - - - - Allow Shake/Flash: - Permitir Shake/Flash: - - - - Allows screenshaking and flashing. Disable this if you have concerns or issues with photosensitivity and/or seizures. - Permite agitar e piscar. Desative isso se você tiver preocupações ou problemas com fotosensibilidade e/ou convulsões. - - - - Language: - Língua: - - - - Sets the language if you don't want to use your system language. - Define o idioma se você não quiser usar o idioma do sistema. - - - - Punctuation delay modifier. Enable it for the blips to slow down on punctuations. - Habilite para adicionar uma pequena pausa nos sinais de pontuação. - - - - Callwords - Palavras-chave - - - - <html><head/><body>Enter as many callwords as you would like. These are case insensitive. Make sure to leave every callword in its own line!<br>Do not leave a line with a space at the end -- you will be alerted everytime someone uses a space in their messages.</body></html> - <html><head/><body>Digite quantas palavras-chave você desejar. Estes não diferenciam maiúsculas de minúsculas. Certifique-se de deixar cada palavra chave em sua própria linha!<br>Não deixe uma linha com um espaço no final - você será alertado toda vez que alguém usar um espaço em suas mensagens.</body></html> - - - - Audio - Áudio - - - - Audio device: - Dispositivo de áudio: - - - - Sets the audio device for all sounds. - Define o dispositivo de áudio para todos os sons. - - - - Music: - Música: - - - Sets the music's default volume. - Define o volume padrão da música. - - - - SFX: - SFX: - - - Sets the SFX's default volume. Interjections and actual sound effects count as 'SFX'. - Define o volume padrão do SFX. Interjeições e efeitos sonoros reais contam como 'SFX'. - - - - Gives the default value for the in-game 'Custom shownames' checkbox, which in turn determines whether the client should display custom in-character names. - Fornece o valor padrão para a caixa de seleção 'Shownames' no jogo, que determina se o cliente deve exibir nomes personalizados nos caracteres. - - - - Slower text speed: - Texto mais lento: - - - - Set the text speed to be the same as the AA games. - A velocidade do texto será a mesma dos jogos AA. - - - - Blip delay on punctuations: - Atraso na pontuação: - - - - Sets the default volume for music. - Define o volume padrão da música. - - - - Sets the default volume for SFX sounds, like interjections or other character sound effects. - Define o volume padrão para sons SFX, como interjeições ou outros efeitos sonoros de personagens. - - - - Blips: - - - - - Sets the volume of the blips, the talking sound effects. - Define o volume dos blips, os efeitos sonoros de fala. - - - - Blip rate: - Taxa de blip: - - - - Sets the delay between playing the blip sounds. - Define o atraso entre a reprodução dos sons de blip. - - - - Blank blips: - Blips em branco: - - - - If true, the game will play a blip sound even when a space is 'being said'. - Se ativado, o jogo emitirá um sinal sonoro, mesmo quando um espaço estiver sendo "dito". - - - - Enable Looping SFX: - Ative o SFX em loop: - - - - If true, the game will allow looping sound effects to play on preanimations. - Se ativado, o jogo permitirá que efeitos sonoros em loop sejam reproduzidos em pré-animações. - - - - Kill Music On Objection: - Parar a música no protesto: - - - - If true, the game will stop music when someone objects, like in the actual games. - Se ativado, o jogo interrompe a música quando alguém protestar , como nos jogos reais. - - - - Casing - Caso - - - - This server supports case alerts. - Este servidor suporta anúncios de casos. - - - - This server does not support case alerts. - Este servidor não suporta alertas de caso. - - - - Pretty self-explanatory. - Bastante auto-explicativo. - - - - Casing: - Caso: - - - - If checked, you will get alerts about case announcements. - Se marcado, você será alertado quando houverem anúncios de casos. - - - - Defense: - Defesa: - - - - If checked, you will get alerts about case announcements if a defense spot is open. - Se marcado, você receberá alertas sobre os anúncios de casos, se um ponto de defesa estiver aberto. - - - - Prosecution: - Promotor: - - - - If checked, you will get alerts about case announcements if a prosecutor spot is open. - Se marcado, você receberá alertas sobre os anúncios de casos, se uma posição de promotor estiver disponível. - - - - Judge: - Juíz: - - - - If checked, you will get alerts about case announcements if the judge spot is open. - Se marcado, você receberá alertas sobre os anúncios de casos, se o local do juíz: estiver aberto. - - - - Juror: - Jurado: - - - - If checked, you will get alerts about case announcements if a juror spot is open. - Se marcado, você receberá alertas sobre os anúncios de casos, se um local do jurado estiver aberto. - - - - Stenographer: - Estenógrafo: - - - - If checked, you will get alerts about case announcements if a stenographer spot is open. - Se marcado, você receberá alertas sobre anúncios de casos, se um local de estenógrafo estiver aberto. - - - - CM: - CM: - - - - If checked, you will appear amongst the potential CMs on the server. - Se marcado, você aparecerá entre os CMs possíveis no servidor. - - - - Witness: - Testemunha: - - - - If checked, you will appear amongst the potential witnesses on the server. - Se marcado, você aparecerá entre as testemunhas em potencial no servidor. - - - - Hosting cases: - Casos: - - - - If you're a CM, enter what cases you are willing to host. - Se você é um CM, insira os casos que deseja hospedar. - - - - IC Log - - - - - Colorful IC log: - Log IC colorido: - - - - Enables colored text in the log. - Ativa o texto colorido no log. - - - - Only inline coloring: - Somente coloração em linha: - - - - Only inline coloring will be shown such as <>,|| etc. - Somente a coloração em linha será mostrada como <>, ||, etc. - - - - Mirror IC log: - O log IC reflete interrupções: - - - - IC log will mirror the IC box. Meaning that if somebody gets interrupted nobody will know what they wanted to say. Enable for a more realistic experience. - O log IC espelhará o chat IC Significando que se alguém for interrompido, ninguém saberá o que queria dizer. Habilite para uma experiência mais realista. - - - - Courtroom - - - Password - Senha - - - - Spectator - Espectador - - - - - Search - Pesquisar - - - - Passworded - A translation wouldn't fit because of the shitty theme system. - - - - - Taken - Em uso - - - - Could not find %1 - Não foi possível encontrar %1 - - - - Showname - A translation wouldn't fit because of the shitty theme system. - - - - - Message - Mensagem - - - - OOC Message - Mensagem OOC - - - - Name - Nome - - - - Pre - A translation wouldn't fit because of the shitty theme system. - - - - - Flip - A translation wouldn't fit because of the shitty theme system. - - - - - Disable Modcalls - - - - - - Casing - A translation wouldn't fit because of the shitty theme system. - - - - - Shownames - A translation wouldn't fit because of the shitty theme system. - - - - - No Interrupt - A translation wouldn't fit because of the shitty theme system. - - - - - White - Branco - - - - Green - Verde - - - - Red - Vermelho - - - - Orange - Laranja - - - - Blue - Azul - - - - Yellow - Amarelo - - - - Rainbow - Arco Iris - - - - Pink - Rosa - - - - Cyan - Ciano - - - - % offset - % deslocamento - - - - Music - - - - - Sfx - - - - - Blips - - - - - Log limit - - - - - - Server - - - - - Change character - - - - - Reload theme - - - - - Call mod - - - - - Settings - - - - - A/M - - - - - Preanim - - - - - Back to Lobby - A translation wouldn't fit because of the shitty theme system. - Lobby - - - - - You were granted the Disable Modcalls button. - Você recebeu o botão Desativar Modcalls. - - - - You have been banned. - Você foi banido. - - - - This does nothing, but there you go. - Isso não faz nada, mas lá vai você. - - - - You opened the settings menu. - Você abriu o menu de configurações. - - - - You will now pair up with - Agora você vai fazer par com - - - - if they also choose your character in return. - se eles também escolherem seu personagem em troca. - - - - You are no longer paired with anyone. - Você não está mais fazendo par com ninguém. - - - - Are you sure you typed that well? The char ID could not be recognised. - Você tem certeza que você escreveu isso certo? O ID do personagem não pôde ser encontrado. - - - - You have set your offset to - Você definiu seu deslocamento como - - - - Your offset must be between -100% and 100%! - Seu deslocamento deve estar entre -100% e 100%! - - - - That offset does not look like one. - Esse deslocamento não se parece com um. - - - - You switched your music and area list. - Você mudou sua lista de músicas e áreas. - - - - You have forcefully enabled features that the server may not support. You may not be able to talk IC, or worse, because of this. - Você forçou recursos que o servidor pode não suportar. Você pode não conseguir falar de IC, ou pior, por causa disso. - - - - Your pre-animations interrupt again. - Suas pré-animações interrompem novamente. - - - - Your pre-animations will not interrupt text. - Suas pré-animações não interromperão o texto. - - - - Couldn't open chatlog.txt to write into. - Não foi possível abrir o chatlog.txt para gravar. - - - - The IC chatlog has been saved. - O chat do IC foi salvo. - - - - You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely the case file you're looking for can't be found in there. - Você não possui uma pasta `base/cases/`! Foi feito para você, mas, como foi feito para você, provavelmente o arquivo do caso que você está procurando não pode ser encontrado lá. - - - - You need to give a filename to load (extension not needed)! Make sure that it is in the `base/cases/` folder, and that it is a correctly formatted ini. -Cases you can load: %1 - Você precisa fornecer um nome de arquivo para carregar (extensão não necessária)! Verifique se está na pasta `base/cases/` e se é um ini formatado corretamente. -Casos que você pode carregar: %1 - - - - Too many arguments to load a case! You only need one filename, without extension. - Muitos argumentos para carregar um caso! Você só precisa de um nome de arquivo, sem extensão. - - - - Case made by %1. - Caso feito por %1. - - - - Navigate to %1 for the CM doc. - Navegue para %1 para o documento do CM. - - - - Your case "%1" was loaded! - Seu caso "%1" foi carregado! - - - - You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely that you somehow deleted it. - Você não possui uma pasta `base/cases/`! Foi feito para você, mas, como foi feito para você, é provável que você o tenha excluído. - - - - You need to give a filename to save (extension not needed) and the courtroom status! - Você deve fornecer um nome de arquivo para salvar (sem extensão necessária) e o estado do tribunal! - - - - Too many arguments to save a case! You only need a filename without extension and the courtroom status. - Muitos argumentos para salvar um caso! Você só precisa de um nome de arquivo sem extensão e o estado do tribunal. - - - Too many arguments to save a case! You only need a filename without extension and the courtroom status! - Muitos argumentos para salvar um caso! Você só precisa de um nome de arquivo sem extensão e o estado do tribunal. - - - - Succesfully saved, edit doc and cmdoc link on the ini! - Salvo com sucesso, você pode editar o documento e o link do documento no arquivo ini! - - - - Master - - - - - Reason: - Razão: - - - - Call Moderator - Chamar um Moderador - - - - - Error - Erro - - - - You must provide a reason. - Você deve fornecer um motivo. - - - - The message is too long. - A mensagem é muito longa. - - - - Choose... - Escolha... - - - - Images (*.png) - Imagens (* .png) - - - - Add new evidence... - Adicionar nova evidência... - - - - Lobby - - - Attorney Online 2 - - - - - Name - Nome - - - - It doesn't look like your client is set up correctly. -Did you download all resources correctly from tiny.cc/getao, including the large 'base' folder? - Seu cliente não parece estar configurado corretamente. -Você baixou todos os recursos corretamente do tiny.cc/getao, incluindo a grande pasta 'base'? - - - - Version: %1 - Versão: %1 - - - - - Offline - Offline - - - - Loading - Carregando - - - - Cancel - Cancelar - - - - <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Cents02<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, Raidensnake - <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Cents02<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, Raidensnake - - - <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy - <h2>Attorney Online %1</h2>O simulador de drama jurídico<p><b>Código fonte:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Desenvolvimento principal:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>Agradecimentos especiais:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy - - - - Online: %1/%2 - Online: %1/%2 - - - - debug_functions - - - Error: %1 - - - - - Error - - - - - Notice - - - - diff --git a/resource/translations/ao_ru.qm b/resource/translations/ao_ru.qm deleted file mode 100644 index 19bf0a957fcb88742b350b2e65e145a30fea5687..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21968 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 QY+drw>U!ga_Qb0H1p@dxkN^Mx diff --git a/resource/translations/ao_ru.ts b/resource/translations/ao_ru.ts deleted file mode 100644 index 93a3295..0000000 --- a/resource/translations/ao_ru.ts +++ /dev/null @@ -1,999 +0,0 @@ - - - - - AOApplication - - - Disconnected from server. - Соединение с сервером прервано. - - - - Error connecting to master server. Will try again in %1 seconds. - Ошибка соединения с главным сервером. Попытка пересоединения будет через %1 с. - - - - There was an error connecting to the master server. -We deploy multiple master servers to mitigate any possible downtime, but the client appears to have exhausted all possible methods of finding and connecting to one. -Please check your Internet connection and firewall, and please try again. - Произошла ошибка соединения с главным сервером. -Пожалуйста, проверьте ваши Интернет-соединение, настройки браундмауэра, и попробуйте перезайти. - - - - Outdated version! Your version: %1 -Please go to aceattorneyonline.com to update. - Устаревшая версия! У вас установлена %1 -Проследуйте на сайт aceattorneyonline.com для обновления. - - - - You have been exiled from AO. -Have a nice day. - Из AO вас отправили в жизнь. -Хорошего дня. - - - - Attorney Online 2 - Attorney Online 2 - - - - Loading - Загрузка - - - - Loading evidence: -%1/%2 - Загрузка вещдоков: -%1/%2 - - - - - Loading music: -%1/%2 - Загрузка музыки: -%1/%2 - - - - - Loading chars: -%1/%2 - Загрузка персонажей: -%1/%2 - - - - You have been kicked from the server. -Reason: %1 - Вас выпнули с сервера. -Причина: %1 - - - - You have been banned from the server. -Reason: %1 - - - - - You are banned on this server. -Reason: %1 - Вас отправили в баню. -Причина: %1 - - - You have been kicked from the server. -Reason: - Вас выпнули с сервера. -Причина: - - - You are banned on this server. -Reason: - Вас отправили в баню. -Причина: - - - - AOCaseAnnouncerDialog - - - Case Announcer - Материалы дела - - - - Case title: - Название: - - - - Defense needed - Сторона защиты - - - - Prosecution needed - Сторона обвинения - - - - Judge needed - Без судьи никак - - - - Jurors needed - Суд присяжных - - - - Stenographer needed - Нужен стенографист? - - - - Witness needed - - - - - AOOptionsDialog - - - Settings - Настройки - - - - Gameplay - Игра - - - - Theme: - Тема: - - - - Sets the theme used in-game. If the new theme changes the lobby's look as well, you'll need to reload the lobby for the changes to take effect, such as by joining a server and leaving it. - Устанавливает внешний вид игры. Может понадобиться перезайти на сервер. - - - - Gives the default value for the in-game 'Custom shownames' checkbox, which in turn determines whether the client should display custom in-character names. - - - - - Sets the default volume for music. - - - - - Sets the default volume for SFX sounds, like interjections or other character sound effects. - - - - - IC Log - - - - - Colorful IC log: - - - - - Enables colored text in the log. - - - - - Only inline coloring: - - - - - Only inline coloring will be shown such as <>,|| etc. - - - - - Mirror IC log: - - - - - IC log will mirror the IC box. Meaning that if somebody gets interrupted nobody will know what they wanted to say. Enable for a more realistic experience. - - - - - Log goes downwards: - Портянку вниз: - - - - If ticked, new messages will appear at the bottom (like the OOC chatlog). The traditional (AO1) behaviour is equivalent to this being unticked. - Отметьте галочку, если хотите, чтобы сообщения в игровом чате отображались снизу, а не сверху. - - - - Log length: - Длина игрового чата: - - - - The amount of messages the IC chatlog will keep before deleting older messages. A value of 0 or below counts as 'infinite'. - Количество сообщений, максимально хранимых в игровом чате. Значение, равное 0 или меньше, будет расценено как снятие такого ограничения. - - - - Default username: - Никнейм по умолчанию: - - - - Your OOC name will be automatically set to this value when you join a server. - Псевдоним, используемый при соединении с сервером. В основном, его видно в чате сервера. - - - - Custom shownames: - Произвольные имена: - - - Gives the default value for the in-game 'Custom shownames' tickbox, which in turn determines whether the client should display custom in-character names. - Отображать произвольные имена персонажей, установленные самими игроками. - - - - Backup MS: - Запасной ГС: - - - - If the built-in server lookups fail, the game will try the address given here and use it as a backup master server address. - Отображать перечень серверов от главного сервера, указанного здесь, когда не удалось соединиться с первичным ГС. - - - - Discord: - Discord: - - - - Allows others on Discord to see what server you are in, what character are you playing, and how long you have been playing for. - Показать в Discord сервер, на котором вы играете, каким персонажем управляете и время игры. - - - - Allow Shake/Flash: - - - - - Allows screenshaking and flashing. Disable this if you have concerns or issues with photosensitivity and/or seizures. - - - - - Language: - Язык: - - - - Sets the language if you don't want to use your system language. - - - - - Slower text speed: - - - - - Set the text speed to be the same as the AA games. - - - - - Blip delay on punctuations: - - - - - Punctuation delay modifier. Enable it for the blips to slow down on punctuations. - - - - - Callwords - Позывные - - - - <html><head/><body>Enter as many callwords as you would like. These are case insensitive. Make sure to leave every callword in its own line!<br>Do not leave a line with a space at the end -- you will be alerted everytime someone uses a space in their messages.</body></html> - <html><head/><body>Введите на отдельных строках свои позывные, при указании которых в сообщениях будет подан звуковой сигнал.</body></html> - - - - Audio - Аудио - - - - Audio device: - Устройство воспроизведения: - - - - Sets the audio device for all sounds. - Куда вещать звук из игры. - - - - Music: - Музыка: - - - Sets the music's default volume. - Громкость музыки по умолчанию. - - - - SFX: - Звук. эффекты: - - - Sets the SFX's default volume. Interjections and actual sound effects count as 'SFX'. - Громкость звуковых эффектов по умолчанию. - - - - Blips: - Сигналы: - - - - Sets the volume of the blips, the talking sound effects. - Громкость сигналов, заменяющих голос, по умолчанию. - - - - Blip rate: - Пер. сигналов: - - - - Sets the delay between playing the blip sounds. - Период между сигналами, заменяющими голос, по умолчанию. - - - - Blank blips: - Пустые сигналы: - - - - If true, the game will play a blip sound even when a space is 'being said'. - Проигрывать сигналы даже для пробелов. - - - - Enable Looping SFX: - - - - - If true, the game will allow looping sound effects to play on preanimations. - - - - - Kill Music On Objection: - - - - - If true, the game will stop music when someone objects, like in the actual games. - - - - - Casing - Заседание - - - - This server supports case alerts. - Этот сервер поддерживает объявление заседания. - - - - This server does not support case alerts. - Этот сервер не поддерживает объявление заседания. - - - - Pretty self-explanatory. - Весьма доходчиво. - - - - Casing: - Новое дело: - - - - If checked, you will get alerts about case announcements. - При заведении дела вы получите уведомление. - - - - Defense: - Защита: - - - - If checked, you will get alerts about case announcements if a defense spot is open. - При заведении дела, в котором нужна сторона защиты, вы получите уведомление. - - - - Prosecution: - Обвинение: - - - - If checked, you will get alerts about case announcements if a prosecutor spot is open. - При заведении дела, в котором нужна сторона обвинения, вы получите уведомление. - - - - Judge: - Судья: - - - - If checked, you will get alerts about case announcements if the judge spot is open. - При заведении дела, в котором нужен судья, вы получите уведомление. - - - - Juror: - Присяжный: - - - - If checked, you will get alerts about case announcements if a juror spot is open. - При заведении дела, в котором нужны присяжные заседатели, вы получите уведомление. - - - - Stenographer: - Стенографист: - - - - If checked, you will get alerts about case announcements if a stenographer spot is open. - При заведении дела, в котором нужна стенография, вы получите уведомление. - - - - CM: - ПД: - - - - If checked, you will appear amongst the potential CMs on the server. - Отметьте, если вы хотите состоять в числе производителей дел. - - - - Witness: - - - - - If checked, you will appear amongst the potential witnesses on the server. - - - - - Hosting cases: - ПД акт.: - - - - If you're a CM, enter what cases you are willing to host. - Будучи производителем дела (ПД), вы можете войти в зону и заниматься её оркестровкой. - - - - Courtroom - - - Password - Пароль - - - - Spectator - Наблюдатель - - - - - Search - Поиск - - - - Passworded - Ограничен паролем - - - - Taken - Занят - - - - Could not find %1 - - - - Generating chars: -%1/%2 - Генерация персонажей: -%1/%2 - - - Generating chars: - - Генерация персонажей: - - - - - Showname - Имя - - - - Message - Сообщение - - - - Name - Никнейм - - - - Pre - Пред. - - - - Flip - Разв. - - - Guard - Охрана - - - - - Casing - Дело - - - - Shownames - Произв. имена - - - - No Interrupt - Говорить сразу - - - - White - Белый - - - - Green - Зелëный - - - - Red - Красный - - - - Orange - Оранжевый - - - - Blue - Синий - - - - Yellow - Жëлтый - - - - This does nothing, but there you go. - В общем-то, это ни на что не влияет... - - - - You need to give a filename to load (extension not needed)! Make sure that it is in the `base/cases/` folder, and that it is a correctly formatted ini. -Cases you can load: %1 - Укажите имя файла с делом (без расширения) для загрузки. Убедитесь, что оно расположено в папке `base/cases`. -Были найдены: %1 - - - - Case made by %1. - Дело завëл игрок: %1. - - - - Navigate to %1 for the CM doc. - Перейдите к %1 для получения материалов дела. - - - - Your case "%1" was loaded! - Дело под кодовым названием "%1" готово! - - - - - Server - Сервер - - - - Back to Lobby - Назад в лобби - - - - Rainbow - Радужный - - - - OOC Message - - - - - Disable Modcalls - - - - - Pink - Розовый - - - - Cyan - Голубой - - - - % offset - % сдвига - - - - Music - Музыка - - - - Sfx - Звук. эффекты - - - - Blips - Сигналы - - - - Log limit - - - - - Change character - - - - - Reload theme - - - - - Call mod - - - - - Settings - Настройки - - - - A/M - - - - - Preanim - - - - - - You were granted the Disable Modcalls button. - - - - - You have been banned. - - - - - Too many arguments to save a case! You only need a filename without extension and the courtroom status. - - - - You were granted the Guard button. - Теперь у вас есть кнопка "Охрана". - - - - You opened the settings menu. - Вы открыли меню настроек. - - - - You will now pair up with - Вы встанете парой с персонажем по имени - - - - if they also choose your character in return. - (если он выберет вас в ответ). - - - - You are no longer paired with anyone. - Теперь вы не стоите в парах. - - - - Are you sure you typed that well? The char ID could not be recognised. - Кажется, вам нужно поменять запрос: такой идентификатор персонажа не был найден. - - - - You have set your offset to - Вы установили сдвиг персонажа на - - - - Your offset must be between -100% and 100%! - Сдвиг персонажа должен быть между -100% и 100%! - - - - That offset does not look like one. - Неверный сдвиг персонажа. - - - - You switched your music and area list. - Вы переключили перечень зон и музыки. - - - - You have forcefully enabled features that the server may not support. You may not be able to talk IC, or worse, because of this. - Из-за того, что вы включили не поддержимаемые сервером возможности, он может не принять ваши сообщения. - - - - Your pre-animations interrupt again. - Персонаж будет говорить только после анимации. - - - - Your pre-animations will not interrupt text. - Персонаж будет говорить и во время анимации. - - - - Couldn't open chatlog.txt to write into. - Не могу открыть `chatlog.txt` для записи лога. - - - - The IC chatlog has been saved. - Лог игрового чата сохранëн. - - - - You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely the case file you're looking for can't be found in there. - Файл с делом не найден. Если найдëте, положите его в папку `base/cases/`, которую мы для вас создали. - - - - Too many arguments to load a case! You only need one filename, without extension. - Введите имя файла без расширения. - - - - You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely that you somehow deleted it. - Папка `base/cases/` отсутствует! - - - - You need to give a filename to save (extension not needed) and the courtroom status! - Введите имя файла (без расширения) и предоставьте статус зоны. - - - Too many arguments to save a case! You only need a filename without extension and the courtroom status! - Убедитесь, что имя файла не содержит расширение. - - - - Succesfully saved, edit doc and cmdoc link on the ini! - Сохранение прошло успешно! - - - - Master - Мастер - - - - Reason: - Причина: - - - - Call Moderator - Позвать модератора - - - - - Error - Ошибка - - - - You must provide a reason. - Укажите причину. - - - - The message is too long. - Слишком длинный текст. - - - - Choose... - Выбрать... - - - - Images (*.png) - Изображения (*.png) - - - - Add new evidence... - Добавить новую улику... - - - - Lobby - - - Attorney Online 2 - Attorney Online 2 - - - - Name - Никнейм - - - - It doesn't look like your client is set up correctly. -Did you download all resources correctly from tiny.cc/getao, including the large 'base' folder? - Не похоже, что ваш клиент установлен правильно. -Скачали ли вы все ресурсы (tiny.cc/getao), включая огромную папку `base`? - - - - Version: %1 - Версия: %1 - - - - Loading - Загрузка - - - - Cancel - Отмена - - - - <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Cents02<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, Raidensnake - - - - <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy - <h2>Attorney Online %1</h2>Симулятор судебной драмы<p><b>Исходный код:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Основной разработкой занимались:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>Особенная благодарность:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (дизайн интерфейса), Draxirch (дизайн интерфейса), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy - - - - Online: %1/%2 - Онлайн: %1/%2 - - - - - Offline - Вне сети - - - - debug_functions - - - Error: %1 - Ошибка: %1 - - - - Error - Ошибка - - - - Notice - На заметку - - - diff --git a/resources.qrc b/resources.qrc index 1229bc8..bc9f322 100644 --- a/resources.qrc +++ b/resources.qrc @@ -2,12 +2,5 @@ resource/fonts/Ace-Attorney.ttf resource/logo.png - resource/translations/ao_de.qm - resource/translations/ao_en.qm - resource/translations/ao_jp.qm - resource/translations/ao_es.qm - resource/translations/ao_pt.qm - resource/translations/ao_ru.qm - resource/translations/ao_pl.qm diff --git a/scripts/configure_ubuntu.sh b/scripts/configure_ubuntu.sh index 280dfdf..1f9b8e8 100755 --- a/scripts/configure_ubuntu.sh +++ b/scripts/configure_ubuntu.sh @@ -7,13 +7,11 @@ set -eu ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/" -cd "${ROOT_DIR}" - +cd ${ROOT_DIR} #need some openGL stuff sudo apt install libgl1-mesa-dev -#install curl incase of fresh vm -sudo apt install curl + mkdir tmp cd tmp diff --git a/scripts/macos_build.sh b/scripts/macos_build.sh index efb7653..22e2d45 100755 --- a/scripts/macos_build.sh +++ b/scripts/macos_build.sh @@ -30,4 +30,4 @@ tar -xvf apng.tar.xz cp clang_64/plugins/imageformats/libqapng.dylib ../lib cd .. -/usr/local/opt/qt/bin/qmake && make -j2 +qmake && make -j2 diff --git a/scripts/macos_post_build.sh b/scripts/macos_post_build.sh old mode 100755 new mode 100644 index df1475c..50acb40 --- a/scripts/macos_post_build.sh +++ b/scripts/macos_post_build.sh @@ -13,12 +13,10 @@ ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/" cd ${ROOT_DIR} # This thing basically does all the work -/usr/local/opt/qt/bin/macdeployqt ../bin/Attorney_Online.app +macdeployqt ../bin/Attorney_Online.app # Need to add the dependencies cp ../lib/* ../bin/Attorney_Online.app/Contents/Frameworks # libbass has a funny path for some reason, just use rpath install_name_tool -change @loader_path/libbass.dylib @rpath/libbass.dylib ../bin/Attorney_Online.app/Contents/MacOS/Attorney_Online - -zip -r -9 ../bin/Attorney_Online_mac_x86_64.zip ../bin/ \ No newline at end of file diff --git a/scripts/release_macos.sh b/scripts/release_macos.sh new file mode 100755 index 0000000..50acb40 --- /dev/null +++ b/scripts/release_macos.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +# This script prepares the compiled bundle for shipping as a standalone release +# Assumes the Qt bin folder is in PATH +# Should be used on a "Release" build from QT creator +# Note that this DOES NOT add the base/ folder + +# Exit on errors and unset variables +set -eu + +ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/" + +cd ${ROOT_DIR} + +# This thing basically does all the work +macdeployqt ../bin/Attorney_Online.app + +# Need to add the dependencies +cp ../lib/* ../bin/Attorney_Online.app/Contents/Frameworks + +# libbass has a funny path for some reason, just use rpath +install_name_tool -change @loader_path/libbass.dylib @rpath/libbass.dylib ../bin/Attorney_Online.app/Contents/MacOS/Attorney_Online diff --git a/scripts/wasabi_program.sh b/scripts/wasabi_program.sh index 37feac6..41e2e35 100755 --- a/scripts/wasabi_program.sh +++ b/scripts/wasabi_program.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh # Updates the specified program manifest to a new archive and version # and uploads the new archive and manifest to S3/Wasabi. # diff --git a/scripts/windows/Dockerfile b/scripts/windows/Dockerfile index b9a12d6..f4f1a83 100644 --- a/scripts/windows/Dockerfile +++ b/scripts/windows/Dockerfile @@ -10,12 +10,5 @@ RUN /opt/mxe/usr/bin/${TARGET_SPEC}-cmake .. -DCMAKE_INSTALL_PREFIX=/opt/mxe/usr RUN /opt/mxe/usr/bin/${TARGET_SPEC}-cmake --build . --config Release --target install WORKDIR ../.. -# Build QtApng statically -RUN git clone https://github.com/Skycoder42/QtApng -WORKDIR QtApng -# libpng contains a self-test entry point that takes precedence for some reason -# over the final build's entry point. -RUN sed -i "s/^main(/libpng_main(/g" src/3rdparty/libpng/src/pngtest.c -RUN /opt/mxe/usr/${TARGET_SPEC}/qt5/bin/qmake -RUN make && make install -WORKDIR .. \ No newline at end of file +# NOTE: Do not build QtApng statically! libpng contains a self-test entry point that +# takes precedence for some reason over the final build's entry point. diff --git a/src/aoapplication.cpp b/src/aoapplication.cpp index 3b5e836..4ef1edd 100644 --- a/src/aoapplication.cpp +++ b/src/aoapplication.cpp @@ -1,17 +1,17 @@ #include "aoapplication.h" -#include "aocaseannouncerdialog.h" -#include "aooptionsdialog.h" -#include "courtroom.h" -#include "debug_functions.h" #include "lobby.h" +#include "courtroom.h" #include "networkmanager.h" +#include "debug_functions.h" + +#include "aooptionsdialog.h" +#include "aocaseannouncerdialog.h" AOApplication::AOApplication(int &argc, char **argv) : QApplication(argc, argv) { // Create the QSettings class that points to the config.ini. - configini = - new QSettings(get_base_path() + "config.ini", QSettings::IniFormat); + configini = new QSettings(get_base_path() + "config.ini", QSettings::IniFormat); net_manager = new NetworkManager(this); discord = new AttorneyOnline::Discord(); @@ -28,7 +28,8 @@ AOApplication::~AOApplication() void AOApplication::construct_lobby() { - if (lobby_constructed) { + if (lobby_constructed) + { qDebug() << "W: lobby was attempted constructed when it already exists"; return; } @@ -37,8 +38,8 @@ void AOApplication::construct_lobby() lobby_constructed = true; QRect geometry = QGuiApplication::primaryScreen()->geometry(); - int x = (geometry.width() - w_lobby->width()) / 2; - int y = (geometry.height() - w_lobby->height()) / 2; + int x = (geometry.width()-w_lobby->width()) / 2; + int y = (geometry.height()-w_lobby->height()) / 2; w_lobby->move(x, y); if (is_discord_enabled()) @@ -49,7 +50,8 @@ void AOApplication::construct_lobby() void AOApplication::destruct_lobby() { - if (!lobby_constructed) { + if(!lobby_constructed) + { qDebug() << "W: lobby was attempted destructed when it did not exist"; return; } @@ -61,7 +63,8 @@ void AOApplication::destruct_lobby() void AOApplication::construct_courtroom() { - if (courtroom_constructed) { + if (courtroom_constructed) + { qDebug() << "W: courtroom was attempted constructed when it already exists"; return; } @@ -70,14 +73,15 @@ void AOApplication::construct_courtroom() courtroom_constructed = true; QRect geometry = QGuiApplication::primaryScreen()->geometry(); - int x = (geometry.width() - w_courtroom->width()) / 2; - int y = (geometry.height() - w_courtroom->height()) / 2; + int x = (geometry.width()-w_courtroom->width()) / 2; + int y = (geometry.height()-w_courtroom->height()) / 2; w_courtroom->move(x, y); } void AOApplication::destruct_courtroom() { - if (!courtroom_constructed) { + if (!courtroom_constructed) + { qDebug() << "W: courtroom was attempted destructed when it did not exist"; return; } @@ -89,11 +93,16 @@ void AOApplication::destruct_courtroom() QString AOApplication::get_version_string() { - return QString::number(RELEASE) + "." + QString::number(MAJOR_VERSION) + "." + - QString::number(MINOR_VERSION); + return + QString::number(RELEASE) + "." + + QString::number(MAJOR_VERSION) + "." + + QString::number(MINOR_VERSION); } -void AOApplication::reload_theme() { current_theme = read_theme(); } +void AOApplication::reload_theme() +{ + current_theme = read_theme(); +} void AOApplication::set_favorite_list() { @@ -124,9 +133,9 @@ void AOApplication::add_favorite_server(int p_server) void AOApplication::server_disconnected() { - if (courtroom_constructed) { - beep(); - call_notice(tr("Disconnected from server.")); + if (courtroom_constructed) + { + call_notice("Disconnected from server."); construct_lobby(); destruct_courtroom(); } @@ -135,44 +144,44 @@ void AOApplication::server_disconnected() void AOApplication::loading_cancelled() { destruct_courtroom(); + w_lobby->hide_loading_overlay(); } void AOApplication::ms_connect_finished(bool connected, bool will_retry) { - if (connected) { + if (connected) + { AOPacket *f_packet = new AOPacket("ALL#%"); send_ms_packet(f_packet); } - else { - if (will_retry) { + else + { + if (will_retry) + { if (lobby_constructed) - w_lobby->append_error( - tr("Error connecting to master server. Will try again in %1 " - "seconds.") - .arg(QString::number(net_manager->ms_reconnect_delay))); + w_lobby->append_error("Error connecting to master server. Will try again in " + + QString::number(net_manager->ms_reconnect_delay) + " seconds."); } - else { - call_error(tr("There was an error connecting to the master server.\n" - "We deploy multiple master servers to mitigate any " - "possible downtime, " - "but the client appears to have exhausted all possible " - "methods of finding " - "and connecting to one.\n" - "Please check your Internet connection and firewall, and " - "please try again.")); + else + { + call_error("There was an error connecting to the master server.\n" + "We deploy multiple master servers to mitigate any possible downtime, " + "but the client appears to have exhausted all possible methods of finding " + "and connecting to one.\n" + "Please check your Internet connection and firewall, and please try again."); } } } void AOApplication::call_settings_menu() { - AOOptionsDialog settings(nullptr, this); - settings.exec(); + AOOptionsDialog settings(nullptr, this); + settings.exec(); } void AOApplication::call_announce_menu(Courtroom *court) { - AOCaseAnnouncerDialog announcer(nullptr, this, court); - announcer.exec(); + AOCaseAnnouncerDialog announcer(nullptr, this, court); + announcer.exec(); } diff --git a/src/aoblipplayer.cpp b/src/aoblipplayer.cpp index 7d598b5..4dfb895 100644 --- a/src/aoblipplayer.cpp +++ b/src/aoblipplayer.cpp @@ -1,6 +1,6 @@ #include "aoblipplayer.h" -#if defined(BASSAUDIO) // Using bass.dll for the blips +#if defined(BASSAUDIO) //Using bass.dll for the blips AOBlipPlayer::AOBlipPlayer(QWidget *parent, AOApplication *p_ao_app) { m_parent = parent; @@ -11,14 +11,14 @@ void AOBlipPlayer::set_blips(QString p_sfx) { QString f_path = ao_app->get_sounds_path(p_sfx); - for (int n_stream = 0; n_stream < 5; ++n_stream) { + for (int n_stream = 0 ; n_stream < 5 ; ++n_stream) + { BASS_StreamFree(m_stream_list[n_stream]); - m_stream_list[n_stream] = BASS_StreamCreateFile( - FALSE, f_path.utf16(), 0, 0, BASS_UNICODE | BASS_ASYNCFILE); + m_stream_list[n_stream] = BASS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, BASS_UNICODE | BASS_ASYNCFILE); } - set_volume_internal(m_volume); + set_volume(m_volume); } void AOBlipPlayer::blip_tick() @@ -34,21 +34,18 @@ void AOBlipPlayer::blip_tick() BASS_ChannelPlay(f_stream, false); } -void AOBlipPlayer::set_volume(qreal p_value) +void AOBlipPlayer::set_volume(int p_value) { - m_volume = p_value / 100; - set_volume_internal(m_volume); -} + m_volume = p_value; -void AOBlipPlayer::set_volume_internal(qreal p_value) -{ - float volume = p_value; + float volume = p_value / 100.0f; - for (int n_stream = 0; n_stream < 5; ++n_stream) { + for (int n_stream = 0 ; n_stream < 5 ; ++n_stream) + { BASS_ChannelSetAttribute(m_stream_list[n_stream], BASS_ATTRIB_VOL, volume); } } -#elif defined(QTAUDIO) // Using Qt's QSoundEffect class +#elif defined(QTAUDIO) //Using Qt's QSoundEffect class AOBlipPlayer::AOBlipPlayer(QWidget *parent, AOApplication *p_ao_app) { m_parent = parent; @@ -59,16 +56,17 @@ void AOBlipPlayer::set_blips(QString p_sfx) { QString f_path = ao_app->get_sounds_path(p_sfx); - for (int n_stream = 0; n_stream < 5; ++n_stream) { + for (int n_stream = 0 ; n_stream < 5 ; ++n_stream) + { m_blips.setSource(QUrl::fromLocalFile(f_path)); } - set_volume_internal(m_volume); + set_volume(m_volume); } void AOBlipPlayer::blip_tick() { - m_cycle++; + int f_cycle = m_cycle++; if (m_cycle == 5) m_cycle = 0; @@ -76,28 +74,30 @@ void AOBlipPlayer::blip_tick() m_blips.play(); } -void AOBlipPlayer::set_volume(qreal p_value) -{ - m_volume = p_value / 100; - set_volume_internal(m_volume); -} - -void AOBlipPlayer::set_volume_internal(qreal p_value) +void AOBlipPlayer::set_volume(int p_value) { + m_volume = p_value; m_blips.setVolume(m_volume); } -#else // No audio +#else //No audio AOBlipPlayer::AOBlipPlayer(QWidget *parent, AOApplication *p_ao_app) { m_parent = parent; ao_app = p_ao_app; } -void AOBlipPlayer::set_blips(QString p_sfx) {} +void AOBlipPlayer::set_blips(QString p_sfx) +{ -void AOBlipPlayer::blip_tick() {} +} -void AOBlipPlayer::set_volume(qreal p_value) {} +void AOBlipPlayer::blip_tick() +{ -void AOBlipPlayer::set_volume_internal(qreal p_value) {} +} + +void AOBlipPlayer::set_volume(int p_value) +{ + +} #endif diff --git a/src/aobutton.cpp b/src/aobutton.cpp index fee946a..5be2e67 100644 --- a/src/aobutton.cpp +++ b/src/aobutton.cpp @@ -3,13 +3,15 @@ #include "debug_functions.h" #include "file_functions.h" -AOButton::AOButton(QWidget *parent, AOApplication *p_ao_app) - : QPushButton(parent) +AOButton::AOButton(QWidget *parent, AOApplication *p_ao_app) : QPushButton(parent) { ao_app = p_ao_app; } -AOButton::~AOButton() {} +AOButton::~AOButton() +{ + +} void AOButton::set_image(QString p_image) { @@ -21,3 +23,4 @@ void AOButton::set_image(QString p_image) else this->setStyleSheet("border-image:url(\"" + default_image_path + "\")"); } + diff --git a/src/aocaseannouncerdialog.cpp b/src/aocaseannouncerdialog.cpp index 0a287c3..5b82b64 100644 --- a/src/aocaseannouncerdialog.cpp +++ b/src/aocaseannouncerdialog.cpp @@ -1,9 +1,7 @@ #include "aocaseannouncerdialog.h" -AOCaseAnnouncerDialog::AOCaseAnnouncerDialog(QWidget *parent, - AOApplication *p_ao_app, - Courtroom *p_court) - : QDialog(parent) +AOCaseAnnouncerDialog::AOCaseAnnouncerDialog(QWidget *parent, AOApplication *p_ao_app, Courtroom *p_court) + : QDialog(parent) { ao_app = p_ao_app; court = p_court; @@ -16,27 +14,21 @@ AOCaseAnnouncerDialog::AOCaseAnnouncerDialog(QWidget *parent, QSizePolicy sizepolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); sizepolicy.setHorizontalStretch(0); sizepolicy.setVerticalStretch(0); - sizepolicy.setHeightForWidth( - ui_announcer_buttons->sizePolicy().hasHeightForWidth()); + sizepolicy.setHeightForWidth(ui_announcer_buttons->sizePolicy().hasHeightForWidth()); ui_announcer_buttons->setSizePolicy(sizepolicy); ui_announcer_buttons->setOrientation(Qt::Horizontal); - ui_announcer_buttons->setStandardButtons(QDialogButtonBox::Ok | - QDialogButtonBox::Cancel); + ui_announcer_buttons->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); - QObject::connect(ui_announcer_buttons, SIGNAL(accepted()), this, - SLOT(ok_pressed())); - QObject::connect(ui_announcer_buttons, SIGNAL(rejected()), this, - SLOT(cancel_pressed())); + QObject::connect(ui_announcer_buttons, SIGNAL(accepted()), this, SLOT(ok_pressed())); + QObject::connect(ui_announcer_buttons, SIGNAL(rejected()), this, SLOT(cancel_pressed())); setUpdatesEnabled(false); ui_vbox_layout = new QVBoxLayout(this); ui_form_layout = new QFormLayout(this); - ui_form_layout->setLabelAlignment(Qt::AlignLeading | Qt::AlignLeft | - Qt::AlignVCenter); - ui_form_layout->setFormAlignment(Qt::AlignLeading | Qt::AlignLeft | - Qt::AlignTop); + ui_form_layout->setLabelAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignVCenter); + ui_form_layout->setFormAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignTop); ui_form_layout->setContentsMargins(6, 6, 6, 6); ui_vbox_layout->addItem(ui_form_layout); @@ -62,28 +54,29 @@ AOCaseAnnouncerDialog::AOCaseAnnouncerDialog(QWidget *parent, ui_juror_needed->setText(tr("Jurors needed")); ui_steno_needed = new QCheckBox(this); ui_steno_needed->setText(tr("Stenographer needed")); - ui_witness_needed = new QCheckBox(this); - ui_witness_needed->setText(tr("Witness needed")); ui_form_layout->setWidget(1, QFormLayout::FieldRole, ui_defense_needed); ui_form_layout->setWidget(2, QFormLayout::FieldRole, ui_prosecutor_needed); ui_form_layout->setWidget(3, QFormLayout::FieldRole, ui_judge_needed); ui_form_layout->setWidget(4, QFormLayout::FieldRole, ui_juror_needed); ui_form_layout->setWidget(5, QFormLayout::FieldRole, ui_steno_needed); - ui_form_layout->setWidget(6, QFormLayout::FieldRole, ui_witness_needed); setUpdatesEnabled(true); } void AOCaseAnnouncerDialog::ok_pressed() { - court->announce_case( - ui_case_title_textbox->text(), ui_defense_needed->isChecked(), - ui_prosecutor_needed->isChecked(), ui_judge_needed->isChecked(), - ui_juror_needed->isChecked(), ui_steno_needed->isChecked(), - ui_witness_needed->isChecked()); + court->announce_case(ui_case_title_textbox->text(), + ui_defense_needed->isChecked(), + ui_prosecutor_needed->isChecked(), + ui_judge_needed->isChecked(), + ui_juror_needed->isChecked(), + ui_steno_needed->isChecked()); done(0); } -void AOCaseAnnouncerDialog::cancel_pressed() { done(0); } +void AOCaseAnnouncerDialog::cancel_pressed() +{ + done(0); +} diff --git a/src/aocharbutton.cpp b/src/aocharbutton.cpp index 5c8a73b..7661027 100644 --- a/src/aocharbutton.cpp +++ b/src/aocharbutton.cpp @@ -2,9 +2,7 @@ #include "file_functions.h" -AOCharButton::AOCharButton(QWidget *parent, AOApplication *p_ao_app, int x_pos, - int y_pos, bool is_taken) - : QPushButton(parent) +AOCharButton::AOCharButton(QWidget *parent, AOApplication *p_ao_app, int x_pos, int y_pos, bool is_taken) : QPushButton(parent) { m_parent = parent; @@ -42,35 +40,45 @@ void AOCharButton::reset() ui_selector->hide(); } -void AOCharButton::set_taken(bool is_taken) { taken = is_taken; } +void AOCharButton::set_taken(bool is_taken) +{ + taken = is_taken; +} void AOCharButton::apply_taken_image() { - if (taken) { - ui_taken->move(0, 0); + if (taken) + { + ui_taken->move(0,0); ui_taken->show(); } - else { + else + { ui_taken->hide(); } } -void AOCharButton::set_passworded() { ui_passworded->show(); } +void AOCharButton::set_passworded() +{ + ui_passworded->show(); +} void AOCharButton::set_image(QString p_character) { QString image_path = ao_app->get_character_path(p_character, "char_icon.png"); + this->setText(""); if (file_exists(image_path)) this->setStyleSheet("border-image:url(\"" + image_path + "\")"); - else { + else + { this->setStyleSheet("border-image:url()"); this->setText(p_character); } } -void AOCharButton::enterEvent(QEvent *e) +void AOCharButton::enterEvent(QEvent * e) { ui_selector->move(this->x() - 1, this->y() - 1); ui_selector->raise(); @@ -80,8 +88,10 @@ void AOCharButton::enterEvent(QEvent *e) QPushButton::enterEvent(e); } -void AOCharButton::leaveEvent(QEvent *e) +void AOCharButton::leaveEvent(QEvent * e) { ui_selector->hide(); QPushButton::leaveEvent(e); } + + diff --git a/src/aocharmovie.cpp b/src/aocharmovie.cpp index 35d9b03..5748723 100644 --- a/src/aocharmovie.cpp +++ b/src/aocharmovie.cpp @@ -1,211 +1,62 @@ #include "aocharmovie.h" -#include "aoapplication.h" -#include "file_functions.h" #include "misc_functions.h" +#include "file_functions.h" +#include "aoapplication.h" -AOCharMovie::AOCharMovie(QWidget *p_parent, AOApplication *p_ao_app) - : QLabel(p_parent) +AOCharMovie::AOCharMovie(QWidget *p_parent, AOApplication *p_ao_app) : QLabel(p_parent) { ao_app = p_ao_app; + m_movie = new QMovie(this); + preanim_timer = new QTimer(this); - ticker = new QTimer(this); preanim_timer->setSingleShot(true); - ticker->setSingleShot(true); - connect(ticker, SIGNAL(timeout()), this, SLOT(movie_ticker())); - this->setUpdatesEnabled(true); + + connect(m_movie, SIGNAL(frameChanged(int)), this, SLOT(frame_change(int))); + connect(preanim_timer, SIGNAL(timeout()), this, SLOT(timer_done())); } void AOCharMovie::play(QString p_char, QString p_emote, QString emote_prefix) { - QString original_path = - ao_app->get_character_path(p_char, emote_prefix + p_emote + ".gif"); - QString alt_path = - ao_app->get_character_path(p_char, emote_prefix + p_emote + ".png"); - QString apng_path = - ao_app->get_character_path(p_char, emote_prefix + p_emote + ".apng"); - QString alt_path_still = ao_app->get_character_path(p_char, p_emote + ".png"); - + QString original_path = ao_app->get_character_path(p_char, emote_prefix + p_emote + ".gif"); + QString alt_path = ao_app->get_character_path(p_char, p_emote + ".png"); + QString apng_path = ao_app->get_character_path(p_char, emote_prefix + p_emote + ".apng"); QString placeholder_path = ao_app->get_theme_path("placeholder.gif"); - QString placeholder_default_path = - ao_app->get_default_theme_path("placeholder.gif"); + QString placeholder_default_path = ao_app->get_default_theme_path("placeholder.gif"); QString gif_path; - current_emote = emote_prefix + p_emote; - current_char = p_char; + if (file_exists(apng_path)) gif_path = apng_path; else if (file_exists(original_path)) gif_path = original_path; else if (file_exists(alt_path)) gif_path = alt_path; - else if (file_exists(alt_path_still)) - gif_path = alt_path_still; else if (file_exists(placeholder_path)) gif_path = placeholder_path; else gif_path = placeholder_default_path; - last_path = gif_path; - delete m_movie; - m_movie = new QMovie(this); + m_movie->stop(); - this->clear(); m_movie->setFileName(gif_path); - m_movie->jumpToFrame(0); - this->LoadImageWithStupidMethodForFlipSupport(m_movie->currentImage()); + + QImageReader *reader = new QImageReader(gif_path); + + movie_frames.clear(); + QImage f_image = reader->read(); + while (!f_image.isNull()) + { + if (m_flipped) + movie_frames.append(f_image.mirrored(true, false)); + else + movie_frames.append(f_image); + f_image = reader->read(); + } + + delete reader; + this->show(); - this->play_frame_sfx(); - // if the frame count is 0 (i.e. it's a static PNG) don't try to play the next - // frame, ya goofus - if (m_movie->frameCount() != 0) { - ticker->start(m_movie->nextFrameDelay()); - } -} - -void AOCharMovie::play_frame_sfx() -{ - int current_frame = m_movie->currentFrameNumber(); - QString sfx_to_play = - ao_app->get_frame_sfx_name(current_char, current_emote, current_frame); - QString screenshake_to_play = - ao_app->get_screenshake_frame(current_char, current_emote, current_frame); - QString realization_to_play = - ao_app->get_realization_frame(current_char, current_emote, current_frame); - if (sfx_to_play != "" && !use_networked_framehell) { - frame_specific_sfx_player->play(ao_app->get_sfx_suffix(sfx_to_play)); - } - else if (use_networked_framehell) { - this->sfx_two_network_boogaloo(); - } - if (screenshake_to_play != "" && !use_networked_framehell) { - mycourtroom->doScreenShake(); - } - else if (use_networked_framehell) { - this->screenshake_two_network_boogaloo(); - } - if (realization_to_play != "" && !use_networked_framehell) { - mycourtroom->doRealization(); - } - else if (use_networked_framehell) { - this->realization_two_network_boogaloo(); - } -} - -void AOCharMovie::realization_two_network_boogaloo() -{ - int current_frame = m_movie->currentFrameNumber(); - QStringList realizationList = this->frame_realization_hellstring.split("^"); - for (int i = 0; i < realizationList.length(); i++) { - QString screenshakeList = realizationList.at(i); - QStringList extra_garbage = screenshakeList.split("|"); - if (extra_garbage.at(0) != current_emote) { - continue; - } - for (int ii = 1; ii < extra_garbage.length(); ii++) { - QString levels_of_garbage = extra_garbage.at(ii); - QStringList that_shouldnt_be_possible = levels_of_garbage.split("="); - if (that_shouldnt_be_possible.at(0).toInt() == current_frame && - that_shouldnt_be_possible.at(1) != "") { - mycourtroom->doRealization(); - } - } - } -} - -void AOCharMovie::screenshake_two_network_boogaloo() -{ - int current_frame = m_movie->currentFrameNumber(); - QStringList realizationList = this->frame_screenshake_hellstring.split("^"); - for (int i = 0; i < realizationList.length(); i++) { - QString screenshakeList = realizationList.at(i); - QStringList extra_garbage = screenshakeList.split("|"); - if (extra_garbage.at(0) != current_emote) { - continue; - } - for (int ii = 1; ii < extra_garbage.length(); ii++) { - QString levels_of_garbage = extra_garbage.at(ii); - QStringList that_shouldnt_be_possible = levels_of_garbage.split("="); - if (that_shouldnt_be_possible.at(0).toInt() == current_frame && - that_shouldnt_be_possible.at(1) != "") { - mycourtroom->doScreenShake(); - } - } - } -} - -void AOCharMovie::sfx_two_network_boogaloo() -{ - int current_frame = m_movie->currentFrameNumber(); - QStringList realizationList = this->frame_sfx_hellstring.split("^"); - for (int i = 0; i < realizationList.length(); i++) { - QString screenshakeList = realizationList.at(i); - QStringList extra_garbage = screenshakeList.split("|"); - if (extra_garbage.at(0) != current_emote) { - continue; - } - for (int ii = 1; ii < extra_garbage.length(); ii++) { - QString levels_of_garbage = extra_garbage.at(ii); - QStringList that_shouldnt_be_possible = levels_of_garbage.split("="); - if (that_shouldnt_be_possible.at(0).toInt() == current_frame && - that_shouldnt_be_possible.at(1) != "") { - frame_specific_sfx_player->play( - ao_app->get_sfx_suffix(that_shouldnt_be_possible.at(1))); - } - } - } -} - -void AOCharMovie::movie_ticker() -{ - if (m_movie->currentFrameNumber() == m_movie->frameCount() - 1) { - delete m_movie; - m_movie = new QMovie(this); - m_movie->stop(); - this->clear(); - m_movie->setFileName(last_path); - m_movie->jumpToFrame(0); - if (play_once) { - timer_done(); - } - } - else { - m_movie->jumpToNextFrame(); - } - this->LoadImageWithStupidMethodForFlipSupport(m_movie->currentImage()); - // imagine if QT had sane stuff like "mirror on QMovie" or "resize the image - // on QT" or "interface with the current QMovie image" or anything else - - this->play_frame_sfx(); - - if (m_movie->frameCount() == 0) { - return; - } - else { - ticker->start(m_movie->nextFrameDelay()); - } -} - -void AOCharMovie::LoadImageWithStupidMethodForFlipSupport(QImage image) -{ - QPixmap f_pixmap; - if (m_flipped) - f_pixmap = QPixmap::fromImage(image.mirrored(true, false)); - else - f_pixmap = QPixmap::fromImage(image); - auto aspect_ratio = Qt::KeepAspectRatio; - - if (f_pixmap.size().width() > f_pixmap.size().height()) - aspect_ratio = Qt::KeepAspectRatioByExpanding; - - if (f_pixmap.size().width() > this->size().width() || - f_pixmap.size().height() > this->size().height()) - this->setPixmap(f_pixmap.scaled(this->width(), this->height(), aspect_ratio, - Qt::SmoothTransformation)); - else - this->setPixmap(f_pixmap.scaled(this->width(), this->height(), aspect_ratio, - Qt::FastTransformation)); - - QLabel::move(x + (this->width() - this->pixmap()->width()) / 2, y); + m_movie->start(); } void AOCharMovie::play_pre(QString p_char, QString p_emote, int duration) @@ -213,30 +64,87 @@ void AOCharMovie::play_pre(QString p_char, QString p_emote, int duration) QString gif_path = ao_app->get_character_path(p_char, p_emote); m_movie->stop(); + this->clear(); m_movie->setFileName(gif_path); m_movie->jumpToFrame(0); - play_once = true; + + int full_duration = duration * time_mod; + int real_duration = 0; + + play_once = false; + + for (int n_frame = 0 ; n_frame < m_movie->frameCount() ; ++n_frame) + { + real_duration += m_movie->nextFrameDelay(); + m_movie->jumpToFrame(n_frame + 1); + } + +#ifdef DEBUG_GIF + qDebug() << "full_duration: " << full_duration; + qDebug() << "real_duration: " << real_duration; +#endif + + double percentage_modifier = 100.0; + + if (real_duration != 0 && duration != 0) + { + double modifier = full_duration / static_cast(real_duration); + percentage_modifier = 100 / modifier; + + if (percentage_modifier > 100.0) + percentage_modifier = 100.0; + } + +#ifdef DEBUG_GIF + qDebug() << "% mod: " << percentage_modifier; +#endif + + if (full_duration == 0 || full_duration >= real_duration) + { + play_once = true; + } + else + { + play_once = false; + preanim_timer->start(full_duration); + } + + + m_movie->setSpeed(static_cast(percentage_modifier)); play(p_char, p_emote, ""); } void AOCharMovie::play_talking(QString p_char, QString p_emote) { + QString gif_path = ao_app->get_character_path(p_char, "(b)" + p_emote); + + m_movie->stop(); + this->clear(); + m_movie->setFileName(gif_path); + play_once = false; + m_movie->setSpeed(100); play(p_char, p_emote, "(b)"); } void AOCharMovie::play_idle(QString p_char, QString p_emote) { + QString gif_path = ao_app->get_character_path(p_char, "(a)" + p_emote); + + m_movie->stop(); + this->clear(); + m_movie->setFileName(gif_path); + play_once = false; + m_movie->setSpeed(100); play(p_char, p_emote, "(a)"); } void AOCharMovie::stop() { - // for all intents and purposes, stopping is the same as hiding. at no point - // do we want a frozen gif to display + //for all intents and purposes, stopping is the same as hiding. at no point do we want a frozen gif to display m_movie->stop(); - frame_specific_sfx_player->stop(); + preanim_timer->stop(); this->hide(); } @@ -244,8 +152,9 @@ void AOCharMovie::combo_resize(int w, int h) { QSize f_size(w, h); this->resize(f_size); - m_movie->setScaledSize(this->size()); + m_movie->setScaledSize(f_size); } + void AOCharMovie::move(int ax, int ay) { x = ax; @@ -253,4 +162,34 @@ void AOCharMovie::move(int ax, int ay) QLabel::move(x, y); } -void AOCharMovie::timer_done() { done(); } +void AOCharMovie::frame_change(int n_frame) +{ + + if (movie_frames.size() > n_frame) + { + QPixmap f_pixmap = QPixmap::fromImage(movie_frames.at(n_frame)); + auto aspect_ratio = Qt::KeepAspectRatio; + + if (f_pixmap.size().width() > f_pixmap.size().height()) + aspect_ratio = Qt::KeepAspectRatioByExpanding; + + if (f_pixmap.size().width() > this->size().width() || f_pixmap.size().height() > this->size().height()) + this->setPixmap(f_pixmap.scaled(this->width(), this->height(), aspect_ratio, Qt::SmoothTransformation)); + else + this->setPixmap(f_pixmap.scaled(this->width(), this->height(), aspect_ratio, Qt::FastTransformation)); + + QLabel::move(x + (this->width() - this->pixmap()->width())/2, y); + } + + if (m_movie->frameCount() - 1 == n_frame && play_once) + { + preanim_timer->start(m_movie->nextFrameDelay()); + m_movie->stop(); + } +} + +void AOCharMovie::timer_done() +{ + + done(); +} diff --git a/src/aoemotebutton.cpp b/src/aoemotebutton.cpp index 29329c9..9c1d388 100644 --- a/src/aoemotebutton.cpp +++ b/src/aoemotebutton.cpp @@ -2,9 +2,7 @@ #include "file_functions.h" -AOEmoteButton::AOEmoteButton(QWidget *p_parent, AOApplication *p_ao_app, - int p_x, int p_y) - : QPushButton(p_parent) +AOEmoteButton::AOEmoteButton(QWidget *p_parent, AOApplication *p_ao_app, int p_x, int p_y) : QPushButton(p_parent) { parent = p_parent; ao_app = p_ao_app; @@ -18,17 +16,21 @@ AOEmoteButton::AOEmoteButton(QWidget *p_parent, AOApplication *p_ao_app, void AOEmoteButton::set_image(QString p_char, int p_emote, QString suffix) { QString emotion_number = QString::number(p_emote + 1); - QString image_path = ao_app->get_character_path( - p_char, "emotions/button" + emotion_number + suffix); + QString image_path = ao_app->get_character_path(p_char, "emotions/button" + emotion_number + suffix); - if (file_exists(image_path)) { + if (file_exists(image_path)) + { this->setText(""); this->setStyleSheet("border-image:url(\"" + image_path + "\")"); } - else { + else + { this->setText(ao_app->get_emote_comment(p_char, p_emote)); this->setStyleSheet("border-image:url(\"\")"); } } -void AOEmoteButton::on_clicked() { emote_clicked(m_id); } +void AOEmoteButton::on_clicked() +{ + emote_clicked(m_id); +} diff --git a/src/aoevidencebutton.cpp b/src/aoevidencebutton.cpp index d0a6ac1..15b598f 100644 --- a/src/aoevidencebutton.cpp +++ b/src/aoevidencebutton.cpp @@ -2,9 +2,7 @@ #include "file_functions.h" -AOEvidenceButton::AOEvidenceButton(QWidget *p_parent, AOApplication *p_ao_app, - int p_x, int p_y) - : QPushButton(p_parent) +AOEvidenceButton::AOEvidenceButton(QWidget *p_parent, AOApplication *p_ao_app, int p_x, int p_y) : QPushButton(p_parent) { ao_app = p_ao_app; m_parent = p_parent; @@ -41,11 +39,13 @@ void AOEvidenceButton::set_image(QString p_image) { QString image_path = ao_app->get_evidence_path(p_image); - if (file_exists(image_path)) { + if (file_exists(image_path)) + { this->setText(""); this->setStyleSheet("border-image:url(\"" + image_path + "\")"); } - else { + else + { this->setText(p_image); this->setStyleSheet(""); } @@ -75,7 +75,10 @@ void AOEvidenceButton::set_selected(bool p_selected) ui_selected->hide(); } -void AOEvidenceButton::on_clicked() { evidence_clicked(m_id); } +void AOEvidenceButton::on_clicked() +{ + evidence_clicked(m_id); +} void AOEvidenceButton::mouseDoubleClickEvent(QMouseEvent *e) { @@ -87,15 +90,19 @@ void AOEvidenceButton::mouseDoubleClickEvent(QMouseEvent *e) void AOEvidenceButton::dragLeaveEvent(QMouseEvent *e) { //QWidget::dragLeaveEvent(e); + + qDebug() << "drag leave event"; } void AOEvidenceButton::dragEnterEvent(QMouseEvent *e) { //QWidget::dragEnterEvent(e); + + qDebug() << "drag enter event"; } */ -void AOEvidenceButton::enterEvent(QEvent *e) +void AOEvidenceButton::enterEvent(QEvent * e) { ui_selector->show(); @@ -105,7 +112,7 @@ void AOEvidenceButton::enterEvent(QEvent *e) QPushButton::enterEvent(e); } -void AOEvidenceButton::leaveEvent(QEvent *e) +void AOEvidenceButton::leaveEvent(QEvent * e) { ui_selector->hide(); diff --git a/src/aoevidencedisplay.cpp b/src/aoevidencedisplay.cpp index 9dd062b..9ec105d 100644 --- a/src/aoevidencedisplay.cpp +++ b/src/aoevidencedisplay.cpp @@ -1,11 +1,10 @@ #include "aoevidencedisplay.h" -#include "datatypes.h" #include "file_functions.h" +#include "datatypes.h" #include "misc_functions.h" -AOEvidenceDisplay::AOEvidenceDisplay(QWidget *p_parent, AOApplication *p_ao_app) - : QLabel(p_parent) +AOEvidenceDisplay::AOEvidenceDisplay(QWidget *p_parent, AOApplication *p_ao_app) : QLabel(p_parent) { ao_app = p_ao_app; @@ -13,12 +12,10 @@ AOEvidenceDisplay::AOEvidenceDisplay(QWidget *p_parent, AOApplication *p_ao_app) evidence_icon = new QLabel(this); sfx_player = new AOSfxPlayer(this, ao_app); - connect(evidence_movie, SIGNAL(frameChanged(int)), this, - SLOT(frame_change(int))); + connect(evidence_movie, SIGNAL(frameChanged(int)), this, SLOT(frame_change(int))); } -void AOEvidenceDisplay::show_evidence(QString p_evidence_image, - bool is_left_side, int p_volume) +void AOEvidenceDisplay::show_evidence(QString p_evidence_image, bool is_left_side, int p_volume) { this->reset(); @@ -32,23 +29,23 @@ void AOEvidenceDisplay::show_evidence(QString p_evidence_image, QString gif_name; QString icon_identifier; - if (is_left_side) { + if (is_left_side) + { icon_identifier = "left_evidence_icon"; gif_name = "evidence_appear_left.gif"; } - else { + else + { icon_identifier = "right_evidence_icon"; gif_name = "evidence_appear_right.gif"; } - pos_size_type icon_dimensions = - ao_app->get_element_dimensions(icon_identifier, "courtroom_design.ini"); + pos_size_type icon_dimensions = ao_app->get_element_dimensions(icon_identifier, "courtroom_design.ini"); evidence_icon->move(icon_dimensions.x, icon_dimensions.y); evidence_icon->resize(icon_dimensions.width, icon_dimensions.height); - evidence_icon->setPixmap(f_pixmap.scaled( - evidence_icon->width(), evidence_icon->height(), Qt::IgnoreAspectRatio)); + evidence_icon->setPixmap(f_pixmap.scaled(evidence_icon->width(), evidence_icon->height(), Qt::IgnoreAspectRatio)); QString f_default_gif_path = ao_app->get_default_theme_path(gif_name); QString f_gif_path = ao_app->get_theme_path(gif_name); @@ -60,7 +57,7 @@ void AOEvidenceDisplay::show_evidence(QString p_evidence_image, evidence_movie->setFileName(final_gif_path); - if (evidence_movie->frameCount() < 1) + if(evidence_movie->frameCount() < 1) return; this->setMovie(evidence_movie); @@ -71,8 +68,9 @@ void AOEvidenceDisplay::show_evidence(QString p_evidence_image, void AOEvidenceDisplay::frame_change(int p_frame) { - if (p_frame == (evidence_movie->frameCount() - 1)) { - // we need this or else the last frame wont show + if (p_frame == (evidence_movie->frameCount() - 1)) + { + //we need this or else the last frame wont show delay(evidence_movie->nextFrameDelay()); evidence_movie->stop(); @@ -90,4 +88,9 @@ void AOEvidenceDisplay::reset() this->clear(); } -QLabel *AOEvidenceDisplay::get_evidence_icon() { return evidence_icon; } +QLabel* AOEvidenceDisplay::get_evidence_icon() +{ + return evidence_icon; +} + + diff --git a/src/aoimage.cpp b/src/aoimage.cpp index ffdf25a..7bb56bb 100644 --- a/src/aoimage.cpp +++ b/src/aoimage.cpp @@ -8,7 +8,10 @@ AOImage::AOImage(QWidget *parent, AOApplication *p_ao_app) : QLabel(parent) ao_app = p_ao_app; } -AOImage::~AOImage() {} +AOImage::~AOImage() +{ + +} void AOImage::set_image(QString p_image) { @@ -24,8 +27,7 @@ void AOImage::set_image(QString p_image) QPixmap f_pixmap(final_image_path); - this->setPixmap( - f_pixmap.scaled(this->width(), this->height(), Qt::IgnoreAspectRatio)); + this->setPixmap(f_pixmap.scaled(this->width(), this->height(), Qt::IgnoreAspectRatio)); } void AOImage::set_image_from_path(QString p_path) @@ -41,6 +43,5 @@ void AOImage::set_image_from_path(QString p_path) QPixmap f_pixmap(final_path); - this->setPixmap( - f_pixmap.scaled(this->width(), this->height(), Qt::IgnoreAspectRatio)); + this->setPixmap(f_pixmap.scaled(this->width(), this->height(), Qt::IgnoreAspectRatio)); } diff --git a/src/aolineedit.cpp b/src/aolineedit.cpp index 211d9f7..f6026e1 100644 --- a/src/aolineedit.cpp +++ b/src/aolineedit.cpp @@ -15,4 +15,7 @@ void AOLineEdit::mouseDoubleClickEvent(QMouseEvent *e) this->setReadOnly(false); } -void AOLineEdit::on_enter_pressed() { this->setReadOnly(true); } +void AOLineEdit::on_enter_pressed() +{ + this->setReadOnly(true); +} diff --git a/src/aomovie.cpp b/src/aomovie.cpp index 9ffd62f..edf5bdb 100644 --- a/src/aomovie.cpp +++ b/src/aomovie.cpp @@ -1,116 +1,90 @@ -#include "aomovie.h" - -#include "courtroom.h" -#include "file_functions.h" -#include "misc_functions.h" - -AOMovie::AOMovie(QWidget *p_parent, AOApplication *p_ao_app) : QLabel(p_parent) -{ - ao_app = p_ao_app; - - m_movie = new QMovie(); - - this->setMovie(m_movie); - timer = new QTimer(this); - timer->setTimerType(Qt::PreciseTimer); - timer->setSingleShot(true); - connect(m_movie, SIGNAL(frameChanged(int)), this, SLOT(frame_change(int))); - connect(timer, SIGNAL(timeout()), this, SLOT(timer_done())); -} - -void AOMovie::set_play_once(bool p_play_once) { play_once = p_play_once; } -void AOMovie::start_timer(int delay) { timer->start(delay); } - -void AOMovie::play(QString p_gif, QString p_char, QString p_custom_theme, - int duration) -{ - - m_movie->stop(); - // this->timer_done(); - QString shout_path = p_gif; - QList pathlist; - - if (ao_app->get_character_path(p_char, p_gif) - .contains( - "custom_objections")) // checks if the file is located within the - // folder of custom objections - pathlist << ao_app->get_character_path( - p_char, - p_gif); // get_image_suffix is unecessery as it is already given. - else if (p_gif == "custom") - pathlist << ao_app->get_image_suffix( - ao_app->get_character_path(p_char, p_gif)); - else - pathlist << ao_app->get_image_suffix( - ao_app->get_character_path(p_char, p_gif + "_bubble")); - - QString misc_path = ao_app->get_base_path() + "misc/" + p_custom_theme + "/" + - p_gif + "_bubble.gif"; - QString custom_theme_path = - ao_app->get_custom_theme_path(p_custom_theme, p_gif + ".gif"); - QString theme_path = ao_app->get_theme_path(p_gif + ".gif"); - QString default_theme_path = ao_app->get_default_theme_path(p_gif + ".gif"); - QString placeholder_path = ao_app->get_theme_path("placeholder.gif"); - QString default_placeholder_path = - ao_app->get_default_theme_path("placeholder.gif"); - - pathlist << ao_app->get_image_suffix(ao_app->get_base_path() + "misc/" + - p_custom_theme + "/" + p_gif + "_bubble") - << // Misc path - ao_app->get_image_suffix( - ao_app->get_custom_theme_path(p_custom_theme, p_gif)) - << // Custom theme path - ao_app->get_image_suffix(ao_app->get_theme_path(p_gif)) << // Theme path - ao_app->get_image_suffix(ao_app->get_default_theme_path(p_gif)) - << // 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 - - for (QString path : pathlist) { - if (file_exists(path)) { - shout_path = path; - break; - } - } - m_movie->setFileName(shout_path); - if (m_movie->loopCount() == 0) - play_once = true; - - this->show(); - m_movie->start(); - if (m_movie->frameCount() == 0 && duration > 0) - timer->start(duration); -} - -void AOMovie::stop() -{ - m_movie->stop(); - this->hide(); -} - -void AOMovie::frame_change(int n_frame) -{ - // If it's a "static movie" (only one frame - png image), we can't change - // frames - ignore this function (use timer instead). If the frame didn't - // reach the last frame or the movie is continuous, don't stop the movie. - if (m_movie->frameCount() == 0 || n_frame < (m_movie->frameCount() - 1) || - !play_once) - return; - // we need this or else the last frame wont show - timer->start(m_movie->nextFrameDelay()); -} - -void AOMovie::timer_done() -{ - this->stop(); - done(); -} - -void AOMovie::combo_resize(int w, int h) -{ - QSize f_size(w, h); - this->resize(f_size); - m_movie->setScaledSize(f_size); -} +#include "aomovie.h" + +#include "file_functions.h" +#include "courtroom.h" +#include "misc_functions.h" + +AOMovie::AOMovie(QWidget *p_parent, AOApplication *p_ao_app) : QLabel(p_parent) +{ + ao_app = p_ao_app; + + m_movie = new QMovie(); + + this->setMovie(m_movie); + + connect(m_movie, SIGNAL(frameChanged(int)), this, SLOT(frame_change(int))); +} + +void AOMovie::set_play_once(bool p_play_once) +{ + play_once = p_play_once; +} + +void AOMovie::play(QString p_gif, QString p_char, QString p_custom_theme) +{ + m_movie->stop(); + + QString gif_path; + + QString custom_path; + if (p_gif == "custom") + custom_path = ao_app->get_image_suffix(ao_app->get_character_path(p_char, p_gif)); + else + custom_path = ao_app->get_image_suffix(ao_app->get_character_path(p_char, p_gif + "_bubble")); + + QString misc_path = ao_app->get_base_path() + "misc/" + p_custom_theme + "/" + p_gif + "_bubble.gif"; + QString custom_theme_path = ao_app->get_custom_theme_path(p_custom_theme, p_gif + ".gif"); + QString theme_path = ao_app->get_theme_path(p_gif + ".gif"); + QString default_theme_path = ao_app->get_default_theme_path(p_gif + ".gif"); + QString placeholder_path = ao_app->get_theme_path("placeholder.gif"); + QString default_placeholder_path = ao_app->get_default_theme_path("placeholder.gif"); + + if (file_exists(custom_path)) + gif_path = custom_path; + else if (file_exists(misc_path)) + gif_path = misc_path; + else if (file_exists(custom_theme_path)) + gif_path = custom_theme_path; + else if (file_exists(theme_path)) + gif_path = theme_path; + else if (file_exists(default_theme_path)) + gif_path = default_theme_path; + else if (file_exists(placeholder_path)) + gif_path = placeholder_path; + else if (file_exists(default_placeholder_path)) + gif_path = default_placeholder_path; + else + gif_path = ""; + + m_movie->setFileName(gif_path); + + this->show(); + m_movie->start(); +} + +void AOMovie::stop() +{ + m_movie->stop(); + this->hide(); +} + +void AOMovie::frame_change(int n_frame) +{ + if (n_frame == (m_movie->frameCount() - 1) && play_once) + { + //we need this or else the last frame wont show + delay(m_movie->nextFrameDelay()); + + this->stop(); + + //signal connected to courtroom object, let it figure out what to do + done(); + } +} + +void AOMovie::combo_resize(int w, int h) +{ + QSize f_size(w, h); + this->resize(f_size); + m_movie->setScaledSize(f_size); +} diff --git a/src/aomusicplayer.cpp b/src/aomusicplayer.cpp index 3ba9cf1..2791809 100644 --- a/src/aomusicplayer.cpp +++ b/src/aomusicplayer.cpp @@ -2,40 +2,28 @@ #if defined(BASSAUDIO) AOMusicPlayer::AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app) - : QObject() { m_parent = parent; ao_app = p_ao_app; } -AOMusicPlayer::~AOMusicPlayer() { kill_loop(); } +AOMusicPlayer::~AOMusicPlayer() +{ + BASS_ChannelStop(m_stream); +} void AOMusicPlayer::play(QString p_song) { BASS_ChannelStop(m_stream); - f_path = ao_app->get_music_path(p_song); + QString f_path = ao_app->get_music_path(p_song); - if (p_song.startsWith("http")) { - m_stream = BASS_StreamCreateURL(f_path.toStdWString().c_str(), 0, - BASS_STREAM_AUTOFREE | BASS_UNICODE | - BASS_ASYNCFILE, NULL, NULL); - } else { - m_stream = BASS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, - BASS_STREAM_AUTOFREE | BASS_UNICODE | - BASS_ASYNCFILE); - } + m_stream = BASS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE); this->set_volume(m_volume); if (ao_app->get_audio_output_device() != "default") BASS_ChannelSetDevice(m_stream, BASS_GetDevice()); - if (enable_looping) { - BASS_ChannelFlags(m_stream, BASS_SAMPLE_LOOP, BASS_SAMPLE_LOOP); - } - else { - BASS_ChannelFlags(m_stream, 0, BASS_SAMPLE_LOOP); - } BASS_ChannelPlay(m_stream, false); } @@ -45,20 +33,17 @@ void AOMusicPlayer::set_volume(int p_value) float volume = m_volume / 100.0f; BASS_ChannelSetAttribute(m_stream, BASS_ATTRIB_VOL, volume); } - -QString AOMusicPlayer::get_path() { return f_path; } - -void AOMusicPlayer::kill_loop() { BASS_ChannelStop(m_stream); } - #elif defined(QTAUDIO) AOMusicPlayer::AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app) - : QObject() { m_parent = parent; ao_app = p_ao_app; } -AOMusicPlayer::~AOMusicPlayer() { m_player.stop(); } +AOMusicPlayer::~AOMusicPlayer() +{ + m_player.stop(); +} void AOMusicPlayer::play(QString p_song) { @@ -68,7 +53,7 @@ void AOMusicPlayer::play(QString p_song) m_player.setMedia(QUrl::fromLocalFile(f_path)); - this->set_volume(100); + this->set_volume(m_volume); m_player.play(); } @@ -76,32 +61,27 @@ void AOMusicPlayer::play(QString p_song) void AOMusicPlayer::set_volume(int p_value) { m_volume = p_value; - - qreal linearVolume = QAudio::convertVolume(m_volume / qreal(100), - QAudio::LogarithmicVolumeScale, - QAudio::LinearVolumeScale); - - m_player.setVolume(linearVolume * 100); + m_player.setVolume(m_volume); } - -QString AOMusicPlayer::get_path() { return f_path; } - -void AOMusicPlayer::kill_loop() { m_player.stop(); } #else AOMusicPlayer::AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app) - : QObject() { m_parent = parent; ao_app = p_ao_app; } -AOMusicPlayer::~AOMusicPlayer() {} +AOMusicPlayer::~AOMusicPlayer() +{ -void AOMusicPlayer::play(QString p_song) {} +} -void AOMusicPlayer::set_volume(int p_value) {} +void AOMusicPlayer::play(QString p_song) +{ -QString AOMusicPlayer::get_path() { return f_path; } +} -void AOMusicPlayer::kill_loop() {} +void AOMusicPlayer::set_volume(int p_value) +{ + +} #endif diff --git a/src/aooptionsdialog.cpp b/src/aooptionsdialog.cpp index e2c6ac8..0f6a054 100644 --- a/src/aooptionsdialog.cpp +++ b/src/aooptionsdialog.cpp @@ -1,722 +1,524 @@ #include "aooptionsdialog.h" #include "aoapplication.h" +#include "bass.h" -AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) - : QDialog(parent) +AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDialog(parent) { - ao_app = p_ao_app; - - // Setting up the basics. - // setAttribute(Qt::WA_DeleteOnClose); - setWindowTitle(tr("Settings")); - resize(398, 360); - - ui_settings_buttons = new QDialogButtonBox(this); - - QSizePolicy sizePolicy1(QSizePolicy::Expanding, QSizePolicy::Fixed); - sizePolicy1.setHorizontalStretch(0); - sizePolicy1.setVerticalStretch(0); - sizePolicy1.setHeightForWidth( - ui_settings_buttons->sizePolicy().hasHeightForWidth()); - ui_settings_buttons->setSizePolicy(sizePolicy1); - ui_settings_buttons->setOrientation(Qt::Horizontal); - ui_settings_buttons->setStandardButtons(QDialogButtonBox::Cancel | - QDialogButtonBox::Save); + ao_app = p_ao_app; - QObject::connect(ui_settings_buttons, SIGNAL(accepted()), this, - SLOT(save_pressed())); - QObject::connect(ui_settings_buttons, SIGNAL(rejected()), this, - SLOT(discard_pressed())); - - // We'll stop updates so that the window won't flicker while it's being made. - setUpdatesEnabled(false); + // Setting up the basics. + // setAttribute(Qt::WA_DeleteOnClose); + setWindowTitle(tr("Settings")); + resize(398, 320); - // First of all, we want a tabbed dialog, so let's add some layout. - ui_vertical_layout = new QVBoxLayout(this); - ui_settings_tabs = new QTabWidget(this); + ui_settings_buttons = new QDialogButtonBox(this); - ui_vertical_layout->addWidget(ui_settings_tabs); - ui_vertical_layout->addWidget(ui_settings_buttons); + QSizePolicy sizePolicy1(QSizePolicy::Expanding, QSizePolicy::Fixed); + sizePolicy1.setHorizontalStretch(0); + sizePolicy1.setVerticalStretch(0); + sizePolicy1.setHeightForWidth(ui_settings_buttons->sizePolicy().hasHeightForWidth()); + ui_settings_buttons->setSizePolicy(sizePolicy1); + ui_settings_buttons->setOrientation(Qt::Horizontal); + ui_settings_buttons->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Save); - // Let's add the tabs one by one. + QObject::connect(ui_settings_buttons, SIGNAL(accepted()), this, SLOT(save_pressed())); + QObject::connect(ui_settings_buttons, SIGNAL(rejected()), this, SLOT(discard_pressed())); - // - // GAMEPLAY - // + // We'll stop updates so that the window won't flicker while it's being made. + setUpdatesEnabled(false); - ui_gameplay_tab = new QWidget(); - ui_settings_tabs->addTab(ui_gameplay_tab, tr("Gameplay")); + // First of all, we want a tabbed dialog, so let's add some layout. + ui_vertical_layout = new QVBoxLayout(this); + ui_settings_tabs = new QTabWidget(this); - ui_form_layout_widget = new QWidget(ui_gameplay_tab); - ui_form_layout_widget->setGeometry(QRect(10, 10, 361, 240)); + ui_vertical_layout->addWidget(ui_settings_tabs); + ui_vertical_layout->addWidget(ui_settings_buttons); - ui_gameplay_form = new QFormLayout(ui_form_layout_widget); - ui_gameplay_form->setLabelAlignment(Qt::AlignLeading | Qt::AlignLeft | - Qt::AlignVCenter); - ui_gameplay_form->setFormAlignment(Qt::AlignLeading | Qt::AlignLeft | - Qt::AlignTop); - ui_gameplay_form->setContentsMargins(0, 0, 0, 0); + // Let's add the tabs one by one. + // First, we'll start with 'Gameplay'. + ui_gameplay_tab = new QWidget(); + ui_settings_tabs->addTab(ui_gameplay_tab, tr("Gameplay")); - ui_theme_label = new QLabel(ui_form_layout_widget); - ui_theme_label->setText(tr("Theme:")); - ui_theme_label->setToolTip( - tr("Sets the theme used in-game. If the new theme changes " - "the lobby's look as well, you'll need to reload the " - "lobby for the changes to take effect, such as by joining " - "a server and leaving it.")); - ui_gameplay_form->setWidget(0, QFormLayout::LabelRole, ui_theme_label); + ui_form_layout_widget = new QWidget(ui_gameplay_tab); + ui_form_layout_widget->setGeometry(QRect(10, 10, 361, 211)); - ui_theme_combobox = new QComboBox(ui_form_layout_widget); + ui_gameplay_form = new QFormLayout(ui_form_layout_widget); + ui_gameplay_form->setLabelAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter); + ui_gameplay_form->setFormAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop); + ui_gameplay_form->setContentsMargins(0, 0, 0, 0); - // Fill the combobox with the names of the themes. - QDirIterator it(p_ao_app->get_base_path() + "themes", QDir::Dirs, - QDirIterator::NoIteratorFlags); - while (it.hasNext()) { - QString actualname = QDir(it.next()).dirName(); - if (actualname != "." && actualname != "..") - ui_theme_combobox->addItem(actualname); - if (actualname == p_ao_app->read_theme()) - ui_theme_combobox->setCurrentIndex(ui_theme_combobox->count() - 1); - } + ui_theme_label = new QLabel(ui_form_layout_widget); + ui_theme_label->setText(tr("Theme:")); + ui_theme_label->setToolTip(tr("Sets the theme used in-game. If the new theme changes " + "the lobby's look as well, you'll need to reload the " + "lobby for the changes to take effect, such as by joining " + "a server and leaving it.")); + ui_gameplay_form->setWidget(0, QFormLayout::LabelRole, ui_theme_label); - ui_gameplay_form->setWidget(0, QFormLayout::FieldRole, ui_theme_combobox); - - ui_theme_log_divider = new QFrame(ui_form_layout_widget); - ui_theme_log_divider->setMidLineWidth(0); - ui_theme_log_divider->setFrameShape(QFrame::HLine); - ui_theme_log_divider->setFrameShadow(QFrame::Sunken); - - ui_gameplay_form->setWidget(1, QFormLayout::FieldRole, ui_theme_log_divider); - - - ui_username_lbl = new QLabel(ui_form_layout_widget); - ui_username_lbl->setText(tr("Default username:")); - ui_username_lbl->setToolTip( - tr("Your OOC name will be automatically set to this value " - "when you join a server.")); - - ui_gameplay_form->setWidget(2, QFormLayout::LabelRole, ui_username_lbl); - - ui_username_textbox = new QLineEdit(ui_form_layout_widget); - ui_username_textbox->setMaxLength(30); - ui_username_textbox->setText(p_ao_app->get_default_username()); - - ui_gameplay_form->setWidget(2, QFormLayout::FieldRole, ui_username_textbox); - - ui_showname_lbl = new QLabel(ui_form_layout_widget); - ui_showname_lbl->setText(tr("Custom shownames:")); - ui_showname_lbl->setToolTip( - tr("Gives the default value for the in-game 'Custom shownames' " - "checkbox, which in turn determines whether the client should " - "display custom in-character names.")); - - ui_gameplay_form->setWidget(3, QFormLayout::LabelRole, ui_showname_lbl); - - ui_showname_cb = new QCheckBox(ui_form_layout_widget); - ui_showname_cb->setChecked(p_ao_app->get_showname_enabled_by_default()); - - ui_gameplay_form->setWidget(3, QFormLayout::FieldRole, ui_showname_cb); - - ui_net_divider = new QFrame(ui_form_layout_widget); - ui_net_divider->setFrameShape(QFrame::HLine); - ui_net_divider->setFrameShadow(QFrame::Sunken); - - ui_gameplay_form->setWidget(4, QFormLayout::FieldRole, ui_net_divider); - - ui_ms_lbl = new QLabel(ui_form_layout_widget); - ui_ms_lbl->setText(tr("Backup MS:")); - ui_ms_lbl->setToolTip( - tr("If the built-in server lookups fail, the game will try the " - "address given here and use it as a backup master server address.")); - - ui_gameplay_form->setWidget(5, QFormLayout::LabelRole, ui_ms_lbl); - - QSettings *configini = ao_app->configini; - ui_ms_textbox = new QLineEdit(ui_form_layout_widget); - ui_ms_textbox->setText(configini->value("master", "").value()); - - ui_gameplay_form->setWidget(5, QFormLayout::FieldRole, ui_ms_textbox); - - ui_discord_lbl = new QLabel(ui_form_layout_widget); - ui_discord_lbl->setText(tr("Discord:")); - ui_discord_lbl->setToolTip( - tr("Allows others on Discord to see what server you are in, " - "what character are you playing, and how long you have " - "been playing for.")); - - ui_gameplay_form->setWidget(6, QFormLayout::LabelRole, ui_discord_lbl); - - ui_discord_cb = new QCheckBox(ui_form_layout_widget); - ui_discord_cb->setChecked(ao_app->is_discord_enabled()); - - ui_gameplay_form->setWidget(6, QFormLayout::FieldRole, ui_discord_cb); - - ui_epilepsy_lbl = new QLabel(ui_form_layout_widget); - ui_epilepsy_lbl->setText(tr("Allow Shake/Flash:")); - ui_epilepsy_lbl->setToolTip( - tr("Allows screenshaking and flashing. Disable this if you have concerns " - "or issues with photosensitivity and/or seizures.")); - - ui_gameplay_form->setWidget(7, QFormLayout::LabelRole, ui_epilepsy_lbl); - - ui_epilepsy_cb = new QCheckBox(ui_form_layout_widget); - ui_epilepsy_cb->setChecked(ao_app->is_shakeandflash_enabled()); - - ui_gameplay_form->setWidget(7, QFormLayout::FieldRole, ui_epilepsy_cb); - - ui_language_label = new QLabel(ui_form_layout_widget); - ui_language_label->setText(tr("Language:")); - ui_language_label->setToolTip( - tr("Sets the language if you don't want to use your system language.")); - ui_gameplay_form->setWidget(8, QFormLayout::LabelRole, ui_language_label); - - ui_language_combobox = new QComboBox(ui_form_layout_widget); - ui_language_combobox->addItem( - configini->value("language", " ").value() + - " - Keep current setting"); - ui_language_combobox->addItem(" - Default"); - ui_language_combobox->addItem("en - English"); - ui_language_combobox->addItem("de - Deutsch"); - ui_language_combobox->addItem("es - Español"); - ui_language_combobox->addItem("pt - Português"); - ui_language_combobox->addItem("pl - Polski"); - ui_language_combobox->addItem("jp - 日本語"); - ui_language_combobox->addItem("ru - Русский"); - ui_gameplay_form->setWidget(8, QFormLayout::FieldRole, ui_language_combobox); - - ui_net_divider = new QFrame(ui_form_layout_widget); - ui_net_divider->setFrameShape(QFrame::HLine); - ui_net_divider->setFrameShadow(QFrame::Sunken); - ui_gameplay_form->setWidget(9, QFormLayout::FieldRole, ui_net_divider); - - ui_slower_blips_lb = new QLabel(ui_form_layout_widget); - ui_slower_blips_lb->setText(tr("Slower text speed:")); - ui_slower_blips_lb->setToolTip(tr("Set the text speed to be the same as the AA games.")); - ui_slower_blips_cb = new QCheckBox(ui_form_layout_widget); - ui_slower_blips_cb->setChecked(p_ao_app->get_slower_blips()); - ui_gameplay_form->setWidget(10, QFormLayout::FieldRole, ui_slower_blips_cb); - ui_gameplay_form->setWidget(10, QFormLayout::LabelRole, ui_slower_blips_lb); - - ui_pun_delay = new QLabel(ui_form_layout_widget); - ui_pun_delay->setText(tr("Blip delay on punctuations:")); - ui_pun_delay->setToolTip(tr("Punctuation delay modifier." - " Enable it for the blips to slow down on punctuations.")); - ui_pun_delay_cb = new QCheckBox(ui_form_layout_widget); - ui_pun_delay_cb->setChecked(p_ao_app->get_pundelay()); - ui_gameplay_form->setWidget(11, QFormLayout::FieldRole, ui_pun_delay_cb); - ui_gameplay_form->setWidget(11, QFormLayout::LabelRole, ui_pun_delay); - - - // Here we start the callwords tab. - ui_callwords_tab = new QWidget(); - ui_settings_tabs->addTab(ui_callwords_tab, tr("Callwords")); - - ui_callwords_widget = new QWidget(ui_callwords_tab); - ui_callwords_widget->setGeometry(QRect(10, 10, 361, 211)); - - ui_callwords_layout = new QVBoxLayout(ui_callwords_widget); - ui_callwords_layout->setContentsMargins(0, 0, 0, 0); - - ui_callwords_textbox = new QPlainTextEdit(ui_callwords_widget); - QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - sizePolicy.setHorizontalStretch(0); - sizePolicy.setVerticalStretch(0); - sizePolicy.setHeightForWidth( - ui_callwords_textbox->sizePolicy().hasHeightForWidth()); - ui_callwords_textbox->setSizePolicy(sizePolicy); - - // Let's fill the callwords text edit with the already present callwords. - ui_callwords_textbox->document()->clear(); - foreach (QString callword, p_ao_app->get_call_words()) { - ui_callwords_textbox->appendPlainText(callword); - } - - ui_callwords_layout->addWidget(ui_callwords_textbox); - - ui_callwords_explain_lbl = new QLabel(ui_callwords_widget); - ui_callwords_explain_lbl->setWordWrap(true); - ui_callwords_explain_lbl->setText( - tr("Enter as many callwords as you would like. These " - "are case insensitive. Make sure to leave every callword in its own " - "line!
    Do not leave a line with a space at the end -- you will be " - "alerted everytime someone uses a space in their " - "messages.")); - - ui_callwords_layout->addWidget(ui_callwords_explain_lbl); - - // The audio tab. - ui_audio_tab = new QWidget(); - ui_settings_tabs->addTab(ui_audio_tab, tr("Audio")); - - ui_audio_widget = new QWidget(ui_audio_tab); - ui_audio_widget->setGeometry(QRect(10, 10, 361, 211)); - - ui_audio_layout = new QFormLayout(ui_audio_widget); - ui_audio_layout->setLabelAlignment(Qt::AlignLeading | Qt::AlignLeft | - Qt::AlignVCenter); - ui_audio_layout->setFormAlignment(Qt::AlignLeading | Qt::AlignLeft | - Qt::AlignTop); - ui_audio_layout->setContentsMargins(0, 0, 0, 0); - - ui_audio_device_lbl = new QLabel(ui_audio_widget); - ui_audio_device_lbl->setText(tr("Audio device:")); - ui_audio_device_lbl->setToolTip(tr("Sets the audio device for all sounds.")); - - ui_audio_layout->setWidget(0, QFormLayout::LabelRole, ui_audio_device_lbl); - - ui_audio_device_combobox = new QComboBox(ui_audio_widget); - - // Let's fill out the combobox with the available audio devices. Or don't if - // there is no audio - if (needs_default_audiodev()) { - - ui_audio_device_combobox->addItem("default"); - } -#ifdef BASSAUDIO - BASS_DEVICEINFO info; - int a = 0; - for (a = 0; BASS_GetDeviceInfo(a, &info); a++) { - ui_audio_device_combobox->addItem(info.name); - if (p_ao_app->get_audio_output_device() == info.name) - ui_audio_device_combobox->setCurrentIndex( - ui_audio_device_combobox->count() - 1); - } -#elif defined QTAUDIO - foreach (const QAudioDeviceInfo &deviceInfo, - QAudioDeviceInfo::availableDevices(QAudio::AudioOutput)) { - ui_audio_device_combobox->addItem(deviceInfo.deviceName()); - if (p_ao_app->get_audio_output_device() == deviceInfo.deviceName()) - ui_audio_device_combobox->setCurrentIndex( - ui_audio_device_combobox->count() - 1); - } -#endif - ui_audio_layout->setWidget(0, QFormLayout::FieldRole, - ui_audio_device_combobox); - - ui_audio_volume_divider = new QFrame(ui_audio_widget); - ui_audio_volume_divider->setFrameShape(QFrame::HLine); - ui_audio_volume_divider->setFrameShadow(QFrame::Sunken); - - ui_audio_layout->setWidget(1, QFormLayout::FieldRole, - ui_audio_volume_divider); - - ui_music_volume_lbl = new QLabel(ui_audio_widget); - ui_music_volume_lbl->setText(tr("Music:")); - ui_music_volume_lbl->setToolTip(tr("Sets the default volume for music.")); + ui_theme_combobox = new QComboBox(ui_form_layout_widget); - ui_audio_layout->setWidget(2, QFormLayout::LabelRole, ui_music_volume_lbl); + // Fill the combobox with the names of the themes. + QDirIterator it(p_ao_app->get_base_path() + "themes", QDir::Dirs, QDirIterator::NoIteratorFlags); + while (it.hasNext()) + { + QString actualname = QDir(it.next()).dirName(); + if (actualname != "." && actualname != "..") + ui_theme_combobox->addItem(actualname); + if (actualname == p_ao_app->read_theme()) + ui_theme_combobox->setCurrentIndex(ui_theme_combobox->count()-1); + } - ui_music_volume_spinbox = new QSpinBox(ui_audio_widget); - ui_music_volume_spinbox->setValue(p_ao_app->get_default_music()); - ui_music_volume_spinbox->setMaximum(100); - ui_music_volume_spinbox->setSuffix("%"); + ui_gameplay_form->setWidget(0, QFormLayout::FieldRole, ui_theme_combobox); - ui_audio_layout->setWidget(2, QFormLayout::FieldRole, - ui_music_volume_spinbox); - - ui_sfx_volume_lbl = new QLabel(ui_audio_widget); - ui_sfx_volume_lbl->setText(tr("SFX:")); - ui_sfx_volume_lbl->setToolTip( - tr("Sets the default volume for SFX sounds, " - "like interjections or other character sound effects.")); - - ui_audio_layout->setWidget(3, QFormLayout::LabelRole, ui_sfx_volume_lbl); - - ui_sfx_volume_spinbox = new QSpinBox(ui_audio_widget); - ui_sfx_volume_spinbox->setValue(p_ao_app->get_default_sfx()); - ui_sfx_volume_spinbox->setMaximum(100); - ui_sfx_volume_spinbox->setSuffix("%"); - - ui_audio_layout->setWidget(3, QFormLayout::FieldRole, ui_sfx_volume_spinbox); - - ui_blips_volume_lbl = new QLabel(ui_audio_widget); - ui_blips_volume_lbl->setText(tr("Blips:")); - ui_blips_volume_lbl->setToolTip( - tr("Sets the volume of the blips, the talking sound effects.")); - - ui_audio_layout->setWidget(4, QFormLayout::LabelRole, ui_blips_volume_lbl); - - ui_blips_volume_spinbox = new QSpinBox(ui_audio_widget); - ui_blips_volume_spinbox->setValue(p_ao_app->get_default_blip()); - ui_blips_volume_spinbox->setMaximum(100); - ui_blips_volume_spinbox->setSuffix("%"); + ui_theme_log_divider = new QFrame(ui_form_layout_widget); + ui_theme_log_divider->setMidLineWidth(0); + ui_theme_log_divider->setFrameShape(QFrame::HLine); + ui_theme_log_divider->setFrameShadow(QFrame::Sunken); - ui_audio_layout->setWidget(4, QFormLayout::FieldRole, - ui_blips_volume_spinbox); + ui_gameplay_form->setWidget(1, QFormLayout::FieldRole, ui_theme_log_divider); - ui_volume_blip_divider = new QFrame(ui_audio_widget); - ui_volume_blip_divider->setFrameShape(QFrame::HLine); - ui_volume_blip_divider->setFrameShadow(QFrame::Sunken); + ui_downwards_lbl = new QLabel(ui_form_layout_widget); + ui_downwards_lbl->setText(tr("Log goes downwards:")); + ui_downwards_lbl->setToolTip(tr("If ticked, new messages will appear at " + "the bottom (like the OOC chatlog). The traditional " + "(AO1) behaviour is equivalent to this being unticked.")); - ui_audio_layout->setWidget(5, QFormLayout::FieldRole, ui_volume_blip_divider); + ui_gameplay_form->setWidget(2, QFormLayout::LabelRole, ui_downwards_lbl); - ui_bliprate_lbl = new QLabel(ui_audio_widget); - ui_bliprate_lbl->setText(tr("Blip rate:")); - ui_bliprate_lbl->setToolTip( - tr("Sets the delay between playing the blip sounds.")); + ui_downwards_cb = new QCheckBox(ui_form_layout_widget); + ui_downwards_cb->setChecked(p_ao_app->get_log_goes_downwards()); - ui_audio_layout->setWidget(6, QFormLayout::LabelRole, ui_bliprate_lbl); + ui_gameplay_form->setWidget(2, QFormLayout::FieldRole, ui_downwards_cb); - ui_bliprate_spinbox = new QSpinBox(ui_audio_widget); - ui_bliprate_spinbox->setValue(p_ao_app->read_blip_rate()); - ui_bliprate_spinbox->setMinimum(1); + ui_length_lbl = new QLabel(ui_form_layout_widget); + ui_length_lbl->setText(tr("Log length:")); + ui_length_lbl->setToolTip(tr("The amount of messages the IC chatlog will keep before " + "deleting older messages. A value of 0 or below counts as 'infinite'.")); - ui_audio_layout->setWidget(6, QFormLayout::FieldRole, ui_bliprate_spinbox); + ui_gameplay_form->setWidget(3, QFormLayout::LabelRole, ui_length_lbl); - ui_blank_blips_lbl = new QLabel(ui_audio_widget); - ui_blank_blips_lbl->setText(tr("Blank blips:")); - ui_blank_blips_lbl->setToolTip( - tr("If true, the game will play a blip sound even " - "when a space is 'being said'.")); + ui_length_spinbox = new QSpinBox(ui_form_layout_widget); + ui_length_spinbox->setMaximum(10000); + ui_length_spinbox->setValue(p_ao_app->get_max_log_size()); - ui_audio_layout->setWidget(7, QFormLayout::LabelRole, ui_blank_blips_lbl); + ui_gameplay_form->setWidget(3, QFormLayout::FieldRole, ui_length_spinbox); - ui_blank_blips_cb = new QCheckBox(ui_audio_widget); - ui_blank_blips_cb->setChecked(p_ao_app->get_blank_blip()); + ui_log_names_divider = new QFrame(ui_form_layout_widget); + ui_log_names_divider->setFrameShape(QFrame::HLine); + ui_log_names_divider->setFrameShadow(QFrame::Sunken); - ui_audio_layout->setWidget(7, QFormLayout::FieldRole, ui_blank_blips_cb); + ui_gameplay_form->setWidget(4, QFormLayout::FieldRole, ui_log_names_divider); - ui_loopsfx_lbl = new QLabel(ui_audio_widget); - ui_loopsfx_lbl->setText(tr("Enable Looping SFX:")); - ui_loopsfx_lbl->setToolTip(tr("If true, the game will allow looping sound " - "effects to play on preanimations.")); + ui_username_lbl = new QLabel(ui_form_layout_widget); + ui_username_lbl->setText(tr("Default username:")); + ui_username_lbl->setToolTip(tr("Your OOC name will be automatically set to this value " + "when you join a server.")); - ui_audio_layout->setWidget(8, QFormLayout::LabelRole, ui_loopsfx_lbl); + ui_gameplay_form->setWidget(5, QFormLayout::LabelRole, ui_username_lbl); - ui_loopsfx_cb = new QCheckBox(ui_audio_widget); - ui_loopsfx_cb->setChecked(p_ao_app->get_looping_sfx()); + ui_username_textbox = new QLineEdit(ui_form_layout_widget); + ui_username_textbox->setMaxLength(30); + ui_username_textbox->setText(p_ao_app->get_default_username()); - ui_audio_layout->setWidget(8, QFormLayout::FieldRole, ui_loopsfx_cb); + ui_gameplay_form->setWidget(5, QFormLayout::FieldRole, ui_username_textbox); - ui_objectmusic_lbl = new QLabel(ui_audio_widget); - ui_objectmusic_lbl->setText(tr("Kill Music On Objection:")); - ui_objectmusic_lbl->setToolTip( - tr("If true, the game will stop music when someone objects, like in the " - "actual games.")); + ui_showname_lbl = new QLabel(ui_form_layout_widget); + ui_showname_lbl->setText(tr("Custom shownames:")); + ui_showname_lbl->setToolTip(tr("Gives the default value for the in-game 'Custom shownames' " + "tickbox, which in turn determines whether the client should " + "display custom in-character names.")); - ui_audio_layout->setWidget(9, QFormLayout::LabelRole, ui_objectmusic_lbl); + ui_gameplay_form->setWidget(6, QFormLayout::LabelRole, ui_showname_lbl); - ui_objectmusic_cb = new QCheckBox(ui_audio_widget); - ui_objectmusic_cb->setChecked(p_ao_app->get_objectmusic()); + ui_showname_cb = new QCheckBox(ui_form_layout_widget); + ui_showname_cb->setChecked(p_ao_app->get_showname_enabled_by_default()); - ui_audio_layout->setWidget(9, QFormLayout::FieldRole, ui_objectmusic_cb); + ui_gameplay_form->setWidget(6, QFormLayout::FieldRole, ui_showname_cb); - // - // CASING - // - ui_casing_tab = new QWidget(); - ui_settings_tabs->addTab(ui_casing_tab, tr("Casing")); + ui_net_divider = new QFrame(ui_form_layout_widget); + ui_net_divider->setFrameShape(QFrame::HLine); + ui_net_divider->setFrameShadow(QFrame::Sunken); - ui_casing_widget = new QWidget(ui_casing_tab); - ui_casing_widget->setGeometry(QRect(10, 10, 361, 211)); + ui_gameplay_form->setWidget(7, QFormLayout::FieldRole, ui_net_divider); - ui_casing_layout = new QFormLayout(ui_casing_widget); - ui_casing_layout->setLabelAlignment(Qt::AlignLeading | Qt::AlignLeft | - Qt::AlignVCenter); - ui_casing_layout->setFormAlignment(Qt::AlignLeading | Qt::AlignLeft | - Qt::AlignTop); - ui_casing_layout->setContentsMargins(0, 0, 0, 0); + ui_ms_lbl = new QLabel(ui_form_layout_widget); + ui_ms_lbl->setText(tr("Backup MS:")); + ui_ms_lbl->setToolTip(tr("If the built-in server lookups fail, the game will try the " + "address given here and use it as a backup master server address.")); - // -- SERVER SUPPORTS CASING + ui_gameplay_form->setWidget(8, QFormLayout::LabelRole, ui_ms_lbl); - ui_casing_supported_lbl = new QLabel(ui_casing_widget); - if (ao_app->casing_alerts_enabled) - ui_casing_supported_lbl->setText(tr("This server supports case alerts.")); - else - ui_casing_supported_lbl->setText( - tr("This server does not support case alerts.")); - ui_casing_supported_lbl->setToolTip(tr("Pretty self-explanatory.")); + QSettings* configini = ao_app->configini; + ui_ms_textbox = new QLineEdit(ui_form_layout_widget); + ui_ms_textbox->setText(configini->value("master", "").value()); - ui_casing_layout->setWidget(0, QFormLayout::FieldRole, - ui_casing_supported_lbl); + ui_gameplay_form->setWidget(8, QFormLayout::FieldRole, ui_ms_textbox); - // -- CASE ANNOUNCEMENTS + ui_discord_lbl = new QLabel(ui_form_layout_widget); + ui_discord_lbl->setText(tr("Discord:")); + ui_discord_lbl->setToolTip(tr("Allows others on Discord to see what server you are in, " + "what character are you playing, and how long you have " + "been playing for.")); - ui_casing_enabled_lbl = new QLabel(ui_casing_widget); - ui_casing_enabled_lbl->setText(tr("Casing:")); - ui_casing_enabled_lbl->setToolTip( - tr("If checked, you will get alerts about case " - "announcements.")); + ui_gameplay_form->setWidget(9, QFormLayout::LabelRole, ui_discord_lbl); - ui_casing_layout->setWidget(1, QFormLayout::LabelRole, ui_casing_enabled_lbl); + ui_discord_cb = new QCheckBox(ui_form_layout_widget); + ui_discord_cb->setChecked(ao_app->is_discord_enabled()); - ui_casing_enabled_cb = new QCheckBox(ui_casing_widget); - ui_casing_enabled_cb->setChecked(ao_app->get_casing_enabled()); + ui_gameplay_form->setWidget(9, QFormLayout::FieldRole, ui_discord_cb); - ui_casing_layout->setWidget(1, QFormLayout::FieldRole, ui_casing_enabled_cb); + // Here we start the callwords tab. + ui_callwords_tab = new QWidget(); + ui_settings_tabs->addTab(ui_callwords_tab, tr("Callwords")); - // -- DEFENSE ANNOUNCEMENTS + ui_callwords_widget = new QWidget(ui_callwords_tab); + ui_callwords_widget->setGeometry(QRect(10, 10, 361, 211)); - ui_casing_def_lbl = new QLabel(ui_casing_widget); - ui_casing_def_lbl->setText(tr("Defense:")); - ui_casing_def_lbl->setToolTip(tr("If checked, you will get alerts about case " - "announcements if a defense spot is open.")); + ui_callwords_layout = new QVBoxLayout(ui_callwords_widget); + ui_callwords_layout->setContentsMargins(0,0,0,0); - ui_casing_layout->setWidget(2, QFormLayout::LabelRole, ui_casing_def_lbl); + ui_callwords_textbox = new QPlainTextEdit(ui_callwords_widget); + QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + sizePolicy.setHorizontalStretch(0); + sizePolicy.setVerticalStretch(0); + sizePolicy.setHeightForWidth(ui_callwords_textbox->sizePolicy().hasHeightForWidth()); + ui_callwords_textbox->setSizePolicy(sizePolicy); - ui_casing_def_cb = new QCheckBox(ui_casing_widget); - ui_casing_def_cb->setChecked(ao_app->get_casing_defence_enabled()); + // Let's fill the callwords text edit with the already present callwords. + ui_callwords_textbox->document()->clear(); + foreach (QString callword, p_ao_app->get_call_words()) { + ui_callwords_textbox->appendPlainText(callword); + } - ui_casing_layout->setWidget(2, QFormLayout::FieldRole, ui_casing_def_cb); + ui_callwords_layout->addWidget(ui_callwords_textbox); - // -- PROSECUTOR ANNOUNCEMENTS + ui_callwords_explain_lbl = new QLabel(ui_callwords_widget); + ui_callwords_explain_lbl->setWordWrap(true); + ui_callwords_explain_lbl->setText(tr("Enter as many callwords as you would like. These are case insensitive. Make sure to leave every callword in its own line!
    Do not leave a line with a space at the end -- you will be alerted everytime someone uses a space in their messages.")); - ui_casing_pro_lbl = new QLabel(ui_casing_widget); - ui_casing_pro_lbl->setText(tr("Prosecution:")); - ui_casing_pro_lbl->setToolTip( - tr("If checked, you will get alerts about case " - "announcements if a prosecutor spot is open.")); + ui_callwords_layout->addWidget(ui_callwords_explain_lbl); - ui_casing_layout->setWidget(3, QFormLayout::LabelRole, ui_casing_pro_lbl); + // The audio tab. + #ifdef BASSAUDIO + ui_audio_tab = new QWidget(); + ui_settings_tabs->addTab(ui_audio_tab, tr("Audio")); - ui_casing_pro_cb = new QCheckBox(ui_casing_widget); - ui_casing_pro_cb->setChecked(ao_app->get_casing_prosecution_enabled()); + ui_audio_widget = new QWidget(ui_audio_tab); + ui_audio_widget->setGeometry(QRect(10, 10, 361, 211)); - ui_casing_layout->setWidget(3, QFormLayout::FieldRole, ui_casing_pro_cb); + ui_audio_layout = new QFormLayout(ui_audio_widget); + ui_audio_layout->setLabelAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter); + ui_audio_layout->setFormAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop); + ui_audio_layout->setContentsMargins(0, 0, 0, 0); - // -- JUDGE ANNOUNCEMENTS + ui_audio_device_lbl = new QLabel(ui_audio_widget); + ui_audio_device_lbl->setText(tr("Audio device:")); + ui_audio_device_lbl->setToolTip(tr("Sets the audio device for all sounds.")); - ui_casing_jud_lbl = new QLabel(ui_casing_widget); - ui_casing_jud_lbl->setText(tr("Judge:")); - ui_casing_jud_lbl->setToolTip(tr("If checked, you will get alerts about case " - "announcements if the judge spot is open.")); + ui_audio_layout->setWidget(0, QFormLayout::LabelRole, ui_audio_device_lbl); - ui_casing_layout->setWidget(4, QFormLayout::LabelRole, ui_casing_jud_lbl); + ui_audio_device_combobox = new QComboBox(ui_audio_widget); - ui_casing_jud_cb = new QCheckBox(ui_casing_widget); - ui_casing_jud_cb->setChecked(ao_app->get_casing_judge_enabled()); + // Let's fill out the combobox with the available audio devices. Or don't if there is no audio + int a = 0; + BASS_DEVICEINFO info; - ui_casing_layout->setWidget(4, QFormLayout::FieldRole, ui_casing_jud_cb); + if (needs_default_audiodev()) + { + ui_audio_device_combobox->addItem("default"); + } - // -- JUROR ANNOUNCEMENTS + for (a = 0; BASS_GetDeviceInfo(a, &info); a++) + { + ui_audio_device_combobox->addItem(info.name); + if (p_ao_app->get_audio_output_device() == info.name) + ui_audio_device_combobox->setCurrentIndex(ui_audio_device_combobox->count()-1); + } - ui_casing_jur_lbl = new QLabel(ui_casing_widget); - ui_casing_jur_lbl->setText(tr("Juror:")); - ui_casing_jur_lbl->setToolTip(tr("If checked, you will get alerts about case " - "announcements if a juror spot is open.")); + ui_audio_layout->setWidget(0, QFormLayout::FieldRole, ui_audio_device_combobox); - ui_casing_layout->setWidget(5, QFormLayout::LabelRole, ui_casing_jur_lbl); + ui_audio_volume_divider = new QFrame(ui_audio_widget); + ui_audio_volume_divider->setFrameShape(QFrame::HLine); + ui_audio_volume_divider->setFrameShadow(QFrame::Sunken); - ui_casing_jur_cb = new QCheckBox(ui_casing_widget); - ui_casing_jur_cb->setChecked(ao_app->get_casing_juror_enabled()); + ui_audio_layout->setWidget(1, QFormLayout::FieldRole, ui_audio_volume_divider); - ui_casing_layout->setWidget(5, QFormLayout::FieldRole, ui_casing_jur_cb); + ui_music_volume_lbl = new QLabel(ui_audio_widget); + ui_music_volume_lbl->setText(tr("Music:")); + ui_music_volume_lbl->setToolTip(tr("Sets the music's default volume.")); - // -- STENO ANNOUNCEMENTS + ui_audio_layout->setWidget(2, QFormLayout::LabelRole, ui_music_volume_lbl); - ui_casing_steno_lbl = new QLabel(ui_casing_widget); - ui_casing_steno_lbl->setText(tr("Stenographer:")); - ui_casing_steno_lbl->setToolTip( - tr("If checked, you will get alerts about case " - "announcements if a stenographer spot is open.")); + ui_music_volume_spinbox = new QSpinBox(ui_audio_widget); + ui_music_volume_spinbox->setValue(p_ao_app->get_default_music()); + ui_music_volume_spinbox->setMaximum(100); + ui_music_volume_spinbox->setSuffix("%"); - ui_casing_layout->setWidget(6, QFormLayout::LabelRole, ui_casing_steno_lbl); + ui_audio_layout->setWidget(2, QFormLayout::FieldRole, ui_music_volume_spinbox); - ui_casing_steno_cb = new QCheckBox(ui_casing_widget); - ui_casing_steno_cb->setChecked(ao_app->get_casing_steno_enabled()); + ui_sfx_volume_lbl = new QLabel(ui_audio_widget); + ui_sfx_volume_lbl->setText(tr("SFX:")); + ui_sfx_volume_lbl->setToolTip(tr("Sets the SFX's default volume. " + "Interjections and actual sound effects count as 'SFX'.")); - ui_casing_layout->setWidget(6, QFormLayout::FieldRole, ui_casing_steno_cb); + ui_audio_layout->setWidget(3, QFormLayout::LabelRole, ui_sfx_volume_lbl); - // -- CM ANNOUNCEMENTS + ui_sfx_volume_spinbox = new QSpinBox(ui_audio_widget); + ui_sfx_volume_spinbox->setValue(p_ao_app->get_default_sfx()); + ui_sfx_volume_spinbox->setMaximum(100); + ui_sfx_volume_spinbox->setSuffix("%"); - ui_casing_cm_lbl = new QLabel(ui_casing_widget); - ui_casing_cm_lbl->setText(tr("CM:")); - ui_casing_cm_lbl->setToolTip( - tr("If checked, you will appear amongst the potential " - "CMs on the server.")); + ui_audio_layout->setWidget(3, QFormLayout::FieldRole, ui_sfx_volume_spinbox); - ui_casing_layout->setWidget(7, QFormLayout::LabelRole, ui_casing_cm_lbl); + ui_blips_volume_lbl = new QLabel(ui_audio_widget); + ui_blips_volume_lbl->setText(tr("Blips:")); + ui_blips_volume_lbl->setToolTip(tr("Sets the volume of the blips, the talking sound effects.")); - ui_casing_cm_cb = new QCheckBox(ui_casing_widget); - ui_casing_cm_cb->setChecked(ao_app->get_casing_cm_enabled()); + ui_audio_layout->setWidget(4, QFormLayout::LabelRole, ui_blips_volume_lbl); - ui_casing_layout->setWidget(7, QFormLayout::FieldRole, ui_casing_cm_cb); + ui_blips_volume_spinbox = new QSpinBox(ui_audio_widget); + ui_blips_volume_spinbox->setValue(p_ao_app->get_default_blip()); + ui_blips_volume_spinbox->setMaximum(100); + ui_blips_volume_spinbox->setSuffix("%"); - ui_casing_wit_lbl = new QLabel(ui_casing_widget); - ui_casing_wit_lbl->setText(tr("Witness:")); - ui_casing_wit_lbl->setToolTip( - tr("If checked, you will appear amongst the potential " - "witnesses on the server.")); + ui_audio_layout->setWidget(4, QFormLayout::FieldRole, ui_blips_volume_spinbox); - ui_casing_layout->setWidget(8, QFormLayout::LabelRole, ui_casing_wit_lbl); + ui_volume_blip_divider = new QFrame(ui_audio_widget); + ui_volume_blip_divider->setFrameShape(QFrame::HLine); + ui_volume_blip_divider->setFrameShadow(QFrame::Sunken); - ui_casing_wit_cb = new QCheckBox(ui_casing_widget); - ui_casing_wit_cb->setChecked(ao_app->get_casing_wit_enabled()); + ui_audio_layout->setWidget(5, QFormLayout::FieldRole, ui_volume_blip_divider); - ui_casing_layout->setWidget(8, QFormLayout::FieldRole, ui_casing_wit_cb); + ui_bliprate_lbl = new QLabel(ui_audio_widget); + ui_bliprate_lbl->setText(tr("Blip rate:")); + ui_bliprate_lbl->setToolTip(tr("Sets the delay between playing the blip sounds.")); - // -- CM CASES ANNOUNCEMENTS + ui_audio_layout->setWidget(6, QFormLayout::LabelRole, ui_bliprate_lbl); - ui_casing_cm_cases_lbl = new QLabel(ui_casing_widget); - ui_casing_cm_cases_lbl->setText(tr("Hosting cases:")); - ui_casing_cm_cases_lbl->setToolTip( - tr("If you're a CM, enter what cases you are " - "willing to host.")); + ui_bliprate_spinbox = new QSpinBox(ui_audio_widget); + ui_bliprate_spinbox->setValue(p_ao_app->read_blip_rate()); + ui_bliprate_spinbox->setMinimum(1); - ui_casing_layout->setWidget(9, QFormLayout::LabelRole, - ui_casing_cm_cases_lbl); + ui_audio_layout->setWidget(6, QFormLayout::FieldRole, ui_bliprate_spinbox); - ui_casing_cm_cases_textbox = new QLineEdit(ui_casing_widget); - ui_casing_cm_cases_textbox->setText(ao_app->get_casing_can_host_cases()); + ui_blank_blips_lbl = new QLabel(ui_audio_widget); + ui_blank_blips_lbl->setText(tr("Blank blips:")); + ui_blank_blips_lbl->setToolTip(tr("If true, the game will play a blip sound even " + "when a space is 'being said'.")); - ui_casing_layout->setWidget(9, QFormLayout::FieldRole, - ui_casing_cm_cases_textbox); + ui_audio_layout->setWidget(7, QFormLayout::LabelRole, ui_blank_blips_lbl); - // ICLOG + ui_blank_blips_cb = new QCheckBox(ui_audio_widget); + ui_blank_blips_cb->setChecked(p_ao_app->get_blank_blip()); - ui_other_tab = new QWidget(); - ui_settings_tabs->addTab(ui_other_tab, tr("IC Log")); + ui_audio_layout->setWidget(7, QFormLayout::FieldRole, ui_blank_blips_cb); + #endif - ui_other_widget = new QWidget(ui_other_tab); - ui_other_widget->setGeometry(QRect(10, 10, 361, 211)); + // The casing tab! + ui_casing_tab = new QWidget(); + ui_settings_tabs->addTab(ui_casing_tab, tr("Casing")); - ui_other_layout = new QFormLayout(ui_other_widget); - ui_other_layout->setLabelAlignment(Qt::AlignLeading | Qt::AlignLeft | - Qt::AlignVCenter); - ui_other_layout->setFormAlignment(Qt::AlignLeading | Qt::AlignLeft | - Qt::AlignTop); - ui_other_layout->setContentsMargins(0, 0, 0, 0); + ui_casing_widget = new QWidget(ui_casing_tab); + ui_casing_widget->setGeometry(QRect(10,10, 361, 211)); - ui_other_fancy_icl_enabled_lb = new QLabel(ui_other_widget); - ui_other_fancy_icl_enabled_lb->setText(tr("Colorful IC log:")); - ui_other_fancy_icl_enabled_lb->setToolTip( - tr("Enables colored text in the log.")); - ui_other_layout->setWidget(1, QFormLayout::LabelRole, - ui_other_fancy_icl_enabled_lb); + ui_casing_layout = new QFormLayout(ui_casing_widget); + ui_casing_layout->setLabelAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter); + ui_casing_layout->setFormAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop); + ui_casing_layout->setContentsMargins(0, 0, 0, 0); - ui_other_fancy_icl_enabled_cb = new QCheckBox(ui_other_widget); - ui_other_fancy_icl_enabled_cb->setChecked( - ao_app->get_colored_iclog_enabled()); - ui_other_layout->setWidget(1, QFormLayout::FieldRole, - ui_other_fancy_icl_enabled_cb); + // -- SERVER SUPPORTS CASING - ui_other_fancy_icl_limit_lb = new QLabel(ui_other_widget); - ui_other_fancy_icl_limit_lb->setText(tr("Only inline coloring:")); - ui_other_fancy_icl_limit_lb->setToolTip( - tr("Only inline coloring will be shown such as <>,|| etc.")); - ui_other_layout->setWidget(2, QFormLayout::LabelRole, - ui_other_fancy_icl_limit_lb); - ui_other_fancy_icl_limit_cb = new QCheckBox(ui_other_widget); - ui_other_fancy_icl_limit_cb->setChecked( - ao_app->colorlog_restricted_enabled()); - ui_other_layout->setWidget(2, QFormLayout::FieldRole, - ui_other_fancy_icl_limit_cb); + ui_casing_supported_lbl = new QLabel(ui_casing_widget); + if (ao_app->casing_alerts_enabled) + ui_casing_supported_lbl->setText(tr("This server supports case alerts.")); + else + ui_casing_supported_lbl->setText(tr("This server does not support case alerts.")); + ui_casing_supported_lbl->setToolTip(tr("Pretty self-explanatory.")); - ui_other_mirror_icl_enabled_lb = new QLabel(ui_other_widget); - ui_other_mirror_icl_enabled_lb->setText(tr("Mirror IC log:")); - ui_other_mirror_icl_enabled_lb->setToolTip( - tr("IC log will mirror the IC box. " - "Meaning that if somebody gets interrupted nobody will know what they " - "wanted to say. " - "Enable for a more realistic experience.")); - ui_other_layout->setWidget(3, QFormLayout::LabelRole, - ui_other_mirror_icl_enabled_lb); - ui_other_mirror_icl_enabled_cb = new QCheckBox(ui_other_widget); - ui_other_mirror_icl_enabled_cb->setChecked(ao_app->get_iclmir_enabled()); - ui_other_layout->setWidget(3, QFormLayout::FieldRole, - ui_other_mirror_icl_enabled_cb); - - ui_downwards_lbl = new QLabel(ui_other_widget); - ui_downwards_lbl->setText(tr("Log goes downwards:")); - ui_downwards_lbl->setToolTip( - tr("If ticked, new messages will appear at " - "the bottom (like the OOC chatlog). The traditional " - "(AO1) behaviour is equivalent to this being unticked.")); - - ui_other_layout->setWidget(4, QFormLayout::LabelRole, ui_downwards_lbl); - - ui_downwards_cb = new QCheckBox(ui_other_widget); - ui_downwards_cb->setChecked(p_ao_app->get_log_goes_downwards()); - - ui_other_layout->setWidget(4, QFormLayout::FieldRole, ui_downwards_cb); - - ui_length_lbl = new QLabel(ui_other_widget); - ui_length_lbl->setText(tr("Log length:")); - ui_length_lbl->setToolTip(tr( - "The amount of messages the IC chatlog will keep before " - "deleting older messages. A value of 0 or below counts as 'infinite'.")); - - ui_other_layout->setWidget(5, QFormLayout::LabelRole, ui_length_lbl); - - ui_length_spinbox = new QSpinBox(ui_other_widget); - ui_length_spinbox->setMaximum(10000); - ui_length_spinbox->setValue(p_ao_app->get_max_log_size()); - - ui_other_layout->setWidget(5, QFormLayout::FieldRole, ui_length_spinbox); - - // When we're done, we should continue the updates! - setUpdatesEnabled(true); + ui_casing_layout->setWidget(0, QFormLayout::FieldRole, ui_casing_supported_lbl); + + // -- CASE ANNOUNCEMENTS + + ui_casing_enabled_lbl = new QLabel(ui_casing_widget); + ui_casing_enabled_lbl->setText(tr("Casing:")); + ui_casing_enabled_lbl->setToolTip(tr("If checked, you will get alerts about case " + "announcements.")); + + ui_casing_layout->setWidget(1, QFormLayout::LabelRole, ui_casing_enabled_lbl); + + ui_casing_enabled_cb = new QCheckBox(ui_casing_widget); + ui_casing_enabled_cb->setChecked(ao_app->get_casing_enabled()); + + ui_casing_layout->setWidget(1, QFormLayout::FieldRole, ui_casing_enabled_cb); + + // -- DEFENSE ANNOUNCEMENTS + + ui_casing_def_lbl = new QLabel(ui_casing_widget); + ui_casing_def_lbl->setText(tr("Defense:")); + ui_casing_def_lbl->setToolTip(tr("If checked, you will get alerts about case " + "announcements if a defense spot is open.")); + + ui_casing_layout->setWidget(2, QFormLayout::LabelRole, ui_casing_def_lbl); + + ui_casing_def_cb = new QCheckBox(ui_casing_widget); + ui_casing_def_cb->setChecked(ao_app->get_casing_defence_enabled()); + + ui_casing_layout->setWidget(2, QFormLayout::FieldRole, ui_casing_def_cb); + + // -- PROSECUTOR ANNOUNCEMENTS + + ui_casing_pro_lbl = new QLabel(ui_casing_widget); + ui_casing_pro_lbl->setText(tr("Prosecution:")); + ui_casing_pro_lbl->setToolTip(tr("If checked, you will get alerts about case " + "announcements if a prosecutor spot is open.")); + + ui_casing_layout->setWidget(3, QFormLayout::LabelRole, ui_casing_pro_lbl); + + ui_casing_pro_cb = new QCheckBox(ui_casing_widget); + ui_casing_pro_cb->setChecked(ao_app->get_casing_prosecution_enabled()); + + ui_casing_layout->setWidget(3, QFormLayout::FieldRole, ui_casing_pro_cb); + + // -- JUDGE ANNOUNCEMENTS + + ui_casing_jud_lbl = new QLabel(ui_casing_widget); + ui_casing_jud_lbl->setText(tr("Judge:")); + ui_casing_jud_lbl->setToolTip(tr("If checked, you will get alerts about case " + "announcements if the judge spot is open.")); + + ui_casing_layout->setWidget(4, QFormLayout::LabelRole, ui_casing_jud_lbl); + + ui_casing_jud_cb = new QCheckBox(ui_casing_widget); + ui_casing_jud_cb->setChecked(ao_app->get_casing_judge_enabled()); + + ui_casing_layout->setWidget(4, QFormLayout::FieldRole, ui_casing_jud_cb); + + // -- JUROR ANNOUNCEMENTS + + ui_casing_jur_lbl = new QLabel(ui_casing_widget); + ui_casing_jur_lbl->setText(tr("Juror:")); + ui_casing_jur_lbl->setToolTip(tr("If checked, you will get alerts about case " + "announcements if a juror spot is open.")); + + ui_casing_layout->setWidget(5, QFormLayout::LabelRole, ui_casing_jur_lbl); + + ui_casing_jur_cb = new QCheckBox(ui_casing_widget); + ui_casing_jur_cb->setChecked(ao_app->get_casing_juror_enabled()); + + ui_casing_layout->setWidget(5, QFormLayout::FieldRole, ui_casing_jur_cb); + + // -- STENO ANNOUNCEMENTS + + ui_casing_steno_lbl = new QLabel(ui_casing_widget); + ui_casing_steno_lbl->setText(tr("Stenographer:")); + ui_casing_steno_lbl->setToolTip(tr("If checked, you will get alerts about case " + "announcements if a stenographer spot is open.")); + + ui_casing_layout->setWidget(6, QFormLayout::LabelRole, ui_casing_steno_lbl); + + ui_casing_steno_cb = new QCheckBox(ui_casing_widget); + ui_casing_steno_cb->setChecked(ao_app->get_casing_steno_enabled()); + + ui_casing_layout->setWidget(6, QFormLayout::FieldRole, ui_casing_steno_cb); + + // -- CM ANNOUNCEMENTS + + ui_casing_cm_lbl = new QLabel(ui_casing_widget); + ui_casing_cm_lbl->setText(tr("CM:")); + ui_casing_cm_lbl->setToolTip(tr("If checked, you will appear amongst the potential " + "CMs on the server.")); + + ui_casing_layout->setWidget(7, QFormLayout::LabelRole, ui_casing_cm_lbl); + + ui_casing_cm_cb = new QCheckBox(ui_casing_widget); + ui_casing_cm_cb->setChecked(ao_app->get_casing_cm_enabled()); + + ui_casing_layout->setWidget(7, QFormLayout::FieldRole, ui_casing_cm_cb); + + // -- CM CASES ANNOUNCEMENTS + + ui_casing_cm_cases_lbl = new QLabel(ui_casing_widget); + ui_casing_cm_cases_lbl->setText(tr("Hosting cases:")); + ui_casing_cm_cases_lbl->setToolTip(tr("If you're a CM, enter what cases you are " + "willing to host.")); + + ui_casing_layout->setWidget(8, QFormLayout::LabelRole, ui_casing_cm_cases_lbl); + + ui_casing_cm_cases_textbox = new QLineEdit(ui_casing_widget); + ui_casing_cm_cases_textbox->setText(ao_app->get_casing_can_host_cases()); + + ui_casing_layout->setWidget(8, QFormLayout::FieldRole, ui_casing_cm_cases_textbox); + + // When we're done, we should continue the updates! + setUpdatesEnabled(true); } void AOOptionsDialog::save_pressed() { - // Save everything into the config.ini. - QSettings *configini = ao_app->configini; + // Save everything into the config.ini. + QSettings* configini = ao_app->configini; - configini->setValue("theme", ui_theme_combobox->currentText()); - configini->setValue("log_goes_downwards", ui_downwards_cb->isChecked()); - configini->setValue("log_maximum", ui_length_spinbox->value()); - configini->setValue("default_username", ui_username_textbox->text()); - configini->setValue("show_custom_shownames", ui_showname_cb->isChecked()); - configini->setValue("master", ui_ms_textbox->text()); - configini->setValue("discord", ui_discord_cb->isChecked()); - configini->setValue("shakeandflash", ui_epilepsy_cb->isChecked()); - configini->setValue("language", ui_language_combobox->currentText().left(2)); - configini->setValue("punctuation_delay", ui_pun_delay_cb->isChecked()); - configini->setValue("slower_blips", ui_slower_blips_cb->isChecked()); - QFile *callwordsini = new QFile(ao_app->get_base_path() + "callwords.ini"); + configini->setValue("theme", ui_theme_combobox->currentText()); + configini->setValue("log_goes_downwards", ui_downwards_cb->isChecked()); + configini->setValue("log_maximum", ui_length_spinbox->value()); + configini->setValue("default_username", ui_username_textbox->text()); + configini->setValue("show_custom_shownames", ui_showname_cb->isChecked()); + configini->setValue("master", ui_ms_textbox->text()); + configini->setValue("discord", ui_discord_cb->isChecked()); + + QFile* callwordsini = new QFile(ao_app->get_base_path() + "callwords.ini"); + + if (!callwordsini->open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) + { + // Nevermind! + } + else + { + QTextStream out(callwordsini); + out << ui_callwords_textbox->toPlainText(); + callwordsini->close(); + } + + configini->setValue("default_audio_device", ui_audio_device_combobox->currentText()); + configini->setValue("default_music", ui_music_volume_spinbox->value()); + configini->setValue("default_sfx", ui_sfx_volume_spinbox->value()); + configini->setValue("default_blip", ui_blips_volume_spinbox->value()); + configini->setValue("blip_rate", ui_bliprate_spinbox->value()); + configini->setValue("blank_blip", ui_blank_blips_cb->isChecked()); + + configini->setValue("casing_enabled", ui_casing_enabled_cb->isChecked()); + configini->setValue("casing_defence_enabled", ui_casing_def_cb->isChecked()); + configini->setValue("casing_prosecution_enabled", ui_casing_pro_cb->isChecked()); + configini->setValue("casing_judge_enabled", ui_casing_jud_cb->isChecked()); + configini->setValue("casing_juror_enabled", ui_casing_jur_cb->isChecked()); + configini->setValue("casing_steno_enabled", ui_casing_steno_cb->isChecked()); + configini->setValue("casing_cm_enabled", ui_casing_cm_cb->isChecked()); + configini->setValue("casing_can_host_cases", ui_casing_cm_cases_textbox->text()); - if (!callwordsini->open(QIODevice::WriteOnly | QIODevice::Truncate | - QIODevice::Text)) { - // Nevermind! - } - else { - QTextStream out(callwordsini); - out << ui_callwords_textbox->toPlainText(); callwordsini->close(); - } - - configini->setValue("default_audio_device", - ui_audio_device_combobox->currentText()); - configini->setValue("default_music", ui_music_volume_spinbox->value()); - configini->setValue("default_sfx", ui_sfx_volume_spinbox->value()); - configini->setValue("default_blip", ui_blips_volume_spinbox->value()); - configini->setValue("blip_rate", ui_bliprate_spinbox->value()); - configini->setValue("blank_blip", ui_blank_blips_cb->isChecked()); - configini->setValue("looping_sfx", ui_loopsfx_cb->isChecked()); - configini->setValue("kill_music_on_object", ui_objectmusic_cb->isChecked()); - - configini->setValue("casing_enabled", ui_casing_enabled_cb->isChecked()); - configini->setValue("casing_defence_enabled", ui_casing_def_cb->isChecked()); - configini->setValue("casing_prosecution_enabled", - ui_casing_pro_cb->isChecked()); - configini->setValue("casing_judge_enabled", ui_casing_jud_cb->isChecked()); - configini->setValue("casing_juror_enabled", ui_casing_jur_cb->isChecked()); - configini->setValue("casing_steno_enabled", ui_casing_steno_cb->isChecked()); - configini->setValue("casing_cm_enabled", ui_casing_cm_cb->isChecked()); - configini->setValue("casing_wit_enabled", ui_casing_wit_cb->isChecked()); - configini->setValue("casing_can_host_cases", - ui_casing_cm_cases_textbox->text()); - - configini->setValue("color_iclog_enabled", - ui_other_fancy_icl_enabled_cb->isChecked()); - configini->setValue("mirror_iclog_enabled", - ui_other_mirror_icl_enabled_cb->isChecked()); - configini->setValue("mirror_iclog_restricted", - ui_other_fancy_icl_limit_cb->isChecked()); - - callwordsini->close(); - done(0); + done(0); } -void AOOptionsDialog::discard_pressed() { done(0); } +void AOOptionsDialog::discard_pressed() +{ + done(0); +} -#if (defined(_WIN32) || defined(_WIN64)) -bool AOOptionsDialog::needs_default_audiodev() { return true; } -#elif (defined(LINUX) || defined(__linux__)) -bool AOOptionsDialog::needs_default_audiodev() { return false; } +#if (defined (_WIN32) || defined (_WIN64)) +bool AOOptionsDialog::needs_default_audiodev() +{ + return true; +} +#elif (defined (LINUX) || defined (__linux__)) +bool AOOptionsDialog::needs_default_audiodev() +{ + return false; +} #elif defined __APPLE__ -bool AOOptionsDialog::needs_default_audiodev() { return true; } +bool AOOptionsDialog::needs_default_audiodev() +{ + return true; +} #else #error This operating system is not supported. #endif diff --git a/src/aopacket.cpp b/src/aopacket.cpp index 6afd39e..b957efe 100644 --- a/src/aopacket.cpp +++ b/src/aopacket.cpp @@ -8,7 +8,8 @@ AOPacket::AOPacket(QString p_packet_string) m_header = packet_contents.at(0); - for (int n_string = 1; n_string < packet_contents.size() - 1; ++n_string) { + for(int n_string = 1 ; n_string < packet_contents.size() - 1 ; ++n_string) + { m_contents.append(packet_contents.at(n_string)); } } @@ -19,18 +20,23 @@ AOPacket::AOPacket(QString p_header, QStringList &p_contents) m_contents = p_contents; } -AOPacket::~AOPacket() {} +AOPacket::~AOPacket() +{ + +} QString AOPacket::to_string() { QString f_string = m_header; - for (QString i_string : m_contents) { + for (QString i_string : m_contents) + { f_string += ("#" + i_string); } f_string += "#%"; + if (encrypted) return "#" + f_string; else @@ -53,12 +59,10 @@ void AOPacket::decrypt_header(unsigned int p_key) void AOPacket::net_encode() { - for (int n_element = 0; n_element < m_contents.size(); ++n_element) { + for (int n_element = 0 ; n_element < m_contents.size() ; ++n_element) + { QString f_element = m_contents.at(n_element); - f_element.replace("#", "") - .replace("%", "") - .replace("$", "") - .replace("&", ""); + f_element.replace("#", "").replace("%", "").replace("$", "").replace("&", ""); m_contents.removeAt(n_element); m_contents.insert(n_element, f_element); @@ -67,14 +71,13 @@ void AOPacket::net_encode() void AOPacket::net_decode() { - for (int n_element = 0; n_element < m_contents.size(); ++n_element) { + for (int n_element = 0 ; n_element < m_contents.size() ; ++n_element) + { QString f_element = m_contents.at(n_element); - f_element.replace("", "#") - .replace("", "%") - .replace("", "$") - .replace("", "&"); + f_element.replace("", "#").replace("", "%").replace("", "$").replace("", "&"); m_contents.removeAt(n_element); m_contents.insert(n_element, f_element); } } + diff --git a/src/aoscene.cpp b/src/aoscene.cpp index fc68633..344522b 100644 --- a/src/aoscene.cpp +++ b/src/aoscene.cpp @@ -7,19 +7,16 @@ AOScene::AOScene(QWidget *parent, AOApplication *p_ao_app) : QLabel(parent) m_parent = parent; ao_app = p_ao_app; m_movie = new QMovie(this); - last_image = ""; } void AOScene::set_image(QString p_image) { - QString background_path = - ao_app->get_image_suffix(ao_app->get_background_path(p_image)); - if (!file_exists(background_path)) - background_path = ao_app->get_image_suffix( - ao_app->get_default_background_path(p_image)); // Default path + QString background_path = ao_app->get_background_path(p_image + ".png"); + QString animated_background_path = ao_app->get_background_path(p_image + ".gif"); + QString default_path = ao_app->get_default_background_path(p_image + ".png"); - if (file_exists(background_path) && background_path == last_image) - return; + QPixmap background(background_path); + QPixmap default_bg(default_path); int w = this->width(); int h = this->height(); @@ -28,58 +25,52 @@ void AOScene::set_image(QString p_image) this->setMovie(nullptr); m_movie->stop(); - m_movie->setFileName(background_path); + m_movie->setFileName(animated_background_path); m_movie->setScaledSize(QSize(w, h)); - if (m_movie->isValid()) { + if (m_movie->isValid()) + { this->setMovie(m_movie); m_movie->start(); } - else { - QPixmap background(background_path); + else if (file_exists(background_path)) + { this->setPixmap(background.scaled(w, h)); } - last_image = background_path; + else + { + this->setPixmap(default_bg.scaled(w, h)); + } } void AOScene::set_legacy_desk(QString p_image) { + //vanilla desks vary in both width and height. in order to make that work with viewport rescaling, + //some INTENSE math is needed. - QString desk_path = - ao_app->get_image_suffix(ao_app->get_background_path(p_image)); - if (!file_exists(desk_path)) - desk_path = ao_app->get_image_suffix( - ao_app->get_default_background_path(p_image)); // Default path + QString desk_path = ao_app->get_background_path(p_image); + QString default_path = ao_app->get_default_background_path(p_image); - if (file_exists(desk_path) && desk_path == last_image) - return; - QPixmap f_desk(desk_path); + QPixmap f_desk; - // vanilla desks vary in both width and height. in order to make that work - // with viewport rescaling, some INTENSE math is needed. + if (file_exists(desk_path)) + f_desk.load(desk_path); + else + f_desk.load(default_path); int vp_width = m_parent->width(); int vp_height = m_parent->height(); + //double y_modifier = 147 / 192; + //double w_modifier = vp_width / 256; double h_modifier = vp_height / 192; + //int final_y = y_modifier * vp_height; + //int final_w = w_modifier * f_desk.width(); int final_h = static_cast(h_modifier * f_desk.height()); - this->clear(); - this->setMovie(nullptr); - - m_movie->stop(); - m_movie->setFileName(desk_path); - - m_movie->setScaledSize(QSize(vp_width, final_h)); - - if (m_movie->isValid()) { - this->setMovie(m_movie); - m_movie->start(); - } - else { - this->resize(vp_width, final_h); - this->setPixmap(f_desk.scaled(vp_width, final_h)); - } - last_image = desk_path; + //this->resize(final_w, final_h); + //this->setPixmap(f_desk.scaled(final_w, final_h)); + this->resize(vp_width, final_h); + this->setPixmap(f_desk.scaled(vp_width, final_h)); } diff --git a/src/aosfxplayer.cpp b/src/aosfxplayer.cpp index 4684acd..710d7a8 100644 --- a/src/aosfxplayer.cpp +++ b/src/aosfxplayer.cpp @@ -1,8 +1,8 @@ #include "aosfxplayer.h" #include "file_functions.h" -#if defined(BASSAUDIO) // Using bass.dll for sfx -AOSfxPlayer::AOSfxPlayer(QWidget *parent, AOApplication *p_ao_app) : QObject() +#if defined(BASSAUDIO) //Using bass.dll for sfx +AOSfxPlayer::AOSfxPlayer(QWidget *parent, AOApplication *p_ao_app) { m_parent = parent; ao_app = p_ao_app; @@ -11,7 +11,7 @@ AOSfxPlayer::AOSfxPlayer(QWidget *parent, AOApplication *p_ao_app) : QObject() void AOSfxPlayer::play(QString p_sfx, QString p_char, QString shout) { BASS_ChannelStop(m_stream); - + QString misc_path = ""; QString char_path = ""; QString sound_path = ao_app->get_sounds_path(p_sfx); @@ -24,49 +24,34 @@ void AOSfxPlayer::play(QString p_sfx, QString p_char, QString shout) QString f_path; if (file_exists(char_path)) - f_path = char_path; + f_path = char_path; else if (file_exists(misc_path)) f_path = misc_path; else f_path = sound_path; - BASS_ChannelStop(m_stream); - m_stream = BASS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, - BASS_STREAM_AUTOFREE | BASS_UNICODE | - BASS_ASYNCFILE); - set_volume_internal(m_volume); + m_stream = BASS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE); + + set_volume(m_volume); if (ao_app->get_audio_output_device() != "default") BASS_ChannelSetDevice(m_stream, BASS_GetDevice()); BASS_ChannelPlay(m_stream, false); - if (looping_sfx && ao_app->get_looping_sfx()) { - BASS_ChannelFlags(m_stream, BASS_SAMPLE_LOOP, BASS_SAMPLE_LOOP); - } - else { - BASS_ChannelFlags(m_stream, 0, BASS_SAMPLE_LOOP); - } } -void AOSfxPlayer::setLooping(bool is_looping) +void AOSfxPlayer::stop() { - this->looping_sfx = is_looping; + BASS_ChannelStop(m_stream); } -void AOSfxPlayer::stop() { BASS_ChannelStop(m_stream); } - -void AOSfxPlayer::set_volume(qreal p_value) +void AOSfxPlayer::set_volume(int p_value) { - m_volume = p_value / 100; - set_volume_internal(m_volume); -} - -void AOSfxPlayer::set_volume_internal(qreal p_value) -{ - float volume = p_value; + m_volume = p_value; + float volume = p_value / 100.0f; BASS_ChannelSetAttribute(m_stream, BASS_ATTRIB_VOL, volume); } -#elif defined(QTAUDIO) // Using Qt's QSoundEffect class -AOSfxPlayer::AOSfxPlayer(QWidget *parent, AOApplication *p_ao_app) : QObject() +#elif defined(QTAUDIO) //Using Qt's QSoundEffect class +AOSfxPlayer::AOSfxPlayer(QWidget *parent, AOApplication *p_ao_app) { m_parent = parent; ao_app = p_ao_app; @@ -88,56 +73,51 @@ void AOSfxPlayer::play(QString p_sfx, QString p_char, QString shout) QString f_path; if (file_exists(char_path)) - f_path = char_path; + f_path = char_path; else if (file_exists(misc_path)) f_path = misc_path; else f_path = sound_path; - if (file_exists(f_path)) // if its missing, it will glitch out + if (file_exists(f_path)) //if its missing, it will glitch out { - m_sfx.setSource(QUrl::fromLocalFile(f_path)); + m_sfx.setSource(QUrl::fromLocalFile(f_path)); - set_volume_internal(m_volume); + set_volume(m_volume); - m_sfx.play(); + m_sfx.play(); } } -void AOSfxPlayer::setLooping(bool is_looping) +void AOSfxPlayer::stop() { - this->looping_sfx = is_looping; + m_sfx.stop(); } -void AOSfxPlayer::stop() { m_sfx.stop(); } - -void AOSfxPlayer::set_volume(qreal p_value) -{ - m_volume = p_value / 100; - set_volume_internal(m_volume); -} - -void AOSfxPlayer::set_volume_internal(qreal p_value) +void AOSfxPlayer::set_volume(int p_value) { + m_volume = p_value; m_sfx.setVolume(m_volume); } #else -AOSfxPlayer::AOSfxPlayer(QWidget *parent, AOApplication *p_ao_app) : QObject() +AOSfxPlayer::AOSfxPlayer(QWidget *parent, AOApplication *p_ao_app) { m_parent = parent; ao_app = p_ao_app; } -void AOSfxPlayer::play(QString p_sfx, QString p_char, QString shout) {} - -void AOSfxPlayer::setLooping(bool is_looping) +void AOSfxPlayer::play(QString p_sfx, QString p_char, QString shout) { - this->looping_sfx = is_looping; + } -void AOSfxPlayer::stop() {} +void AOSfxPlayer::stop() +{ -void AOSfxPlayer::set_volume(qreal p_value) {} +} -void AOSfxPlayer::set_volume_internal(qreal p_value) {} +void AOSfxPlayer::set_volume(int p_value) +{ + +} #endif diff --git a/src/aotextarea.cpp b/src/aotextarea.cpp index 04d4431..5e14632 100644 --- a/src/aotextarea.cpp +++ b/src/aotextarea.cpp @@ -1,30 +1,24 @@ #include "aotextarea.h" -AOTextArea::AOTextArea(QWidget *p_parent) : QTextBrowser(p_parent) {} +AOTextArea::AOTextArea(QWidget *p_parent) : QTextBrowser(p_parent) +{ -void AOTextArea::append_chatmessage(QString p_name, QString p_message, - QString p_colour, bool song) +} + +void AOTextArea::append_chatmessage(QString p_name, QString p_message, QString p_colour) { const QTextCursor old_cursor = this->textCursor(); const int old_scrollbar_value = this->verticalScrollBar()->value(); - const bool is_scrolled_down = - old_scrollbar_value == this->verticalScrollBar()->maximum(); + const bool is_scrolled_down = old_scrollbar_value == this->verticalScrollBar()->maximum(); this->moveCursor(QTextCursor::End); this->append(""); - if (song) - this->insertHtml("" + - p_name.toHtmlEscaped() + " "); - else - this->insertHtml("" + - p_name.toHtmlEscaped() + ": "); + this->insertHtml("" + p_name.toHtmlEscaped() + ": "); - // cheap workarounds ahoy + //cheap workarounds ahoy p_message += " "; - QString result = p_message.toHtmlEscaped() - .replace("\n", "
    ") - .replace(omnis_dank_url_regex, "
    \\1"); + QString result = p_message.toHtmlEscaped().replace("\n", "
    ").replace(omnis_dank_url_regex, "\\1" ); this->insertHtml(result); @@ -35,35 +29,32 @@ void AOTextArea::append_error(QString p_message) { const QTextCursor old_cursor = this->textCursor(); const int old_scrollbar_value = this->verticalScrollBar()->value(); - const bool is_scrolled_down = - old_scrollbar_value == this->verticalScrollBar()->maximum(); + const bool is_scrolled_down = old_scrollbar_value == this->verticalScrollBar()->maximum(); this->moveCursor(QTextCursor::End); this->append(""); p_message += " "; - QString result = p_message.replace("\n", "
    ") - .replace(omnis_dank_url_regex, "\\1"); + QString result = p_message.replace("\n", "
    ").replace(omnis_dank_url_regex, "\\1" ); this->insertHtml("" + result + ""); this->auto_scroll(old_cursor, old_scrollbar_value, is_scrolled_down); } -void AOTextArea::auto_scroll(QTextCursor old_cursor, int old_scrollbar_value, - bool is_scrolled_down) +void AOTextArea::auto_scroll(QTextCursor old_cursor, int old_scrollbar_value, bool is_scrolled_down) { - if (old_cursor.hasSelection() || !is_scrolled_down) { - // The user has selected text or scrolled away from the bottom: maintain - // position. - this->setTextCursor(old_cursor); - this->verticalScrollBar()->setValue(old_scrollbar_value); + if (old_cursor.hasSelection() || !is_scrolled_down) + { + // The user has selected text or scrolled away from the bottom: maintain position. + this->setTextCursor(old_cursor); + this->verticalScrollBar()->setValue(old_scrollbar_value); } - else { - // The user hasn't selected any text and the scrollbar is at the bottom: - // scroll to the bottom. - this->moveCursor(QTextCursor::End); - this->verticalScrollBar()->setValue(this->verticalScrollBar()->maximum()); + else + { + // The user hasn't selected any text and the scrollbar is at the bottom: scroll to the bottom. + this->moveCursor(QTextCursor::End); + this->verticalScrollBar()->setValue(this->verticalScrollBar()->maximum()); } } diff --git a/src/aotextedit.cpp b/src/aotextedit.cpp index 22d9a62..30e48b7 100644 --- a/src/aotextedit.cpp +++ b/src/aotextedit.cpp @@ -4,7 +4,7 @@ AOTextEdit::AOTextEdit(QWidget *parent) : QPlainTextEdit(parent) { this->setReadOnly(true); - // connect(this, SIGNAL(returnPressed()), this, SLOT(on_enter_pressed())); + //connect(this, SIGNAL(returnPressed()), this, SLOT(on_enter_pressed())); } void AOTextEdit::mouseDoubleClickEvent(QMouseEvent *e) @@ -14,4 +14,8 @@ void AOTextEdit::mouseDoubleClickEvent(QMouseEvent *e) this->setReadOnly(false); } -void AOTextEdit::on_enter_pressed() { this->setReadOnly(true); } +void AOTextEdit::on_enter_pressed() +{ + this->setReadOnly(true); +} + diff --git a/src/charselect.cpp b/src/charselect.cpp index 9dee237..4987cf5 100644 --- a/src/charselect.cpp +++ b/src/charselect.cpp @@ -1,58 +1,10 @@ #include "courtroom.h" #include "lobby.h" -#include "debug_functions.h" #include "file_functions.h" +#include "debug_functions.h" #include "hardware_functions.h" -class AOCharSelectGenerationThreading : public QRunnable { -public: - Courtroom *thisCourtroom; - int char_num; - AOCharButton *char_button; - AOCharSelectGenerationThreading(Courtroom *my_courtroom, int character_number) - { - thisCourtroom = my_courtroom; - char_num = character_number; - } - void run() - { - // we take the button we are supposed to mess with, and not whatever comes - // first - AOCharButton *thisCharacterButton = - thisCourtroom->ui_char_button_list.at(char_num); - thisCharacterButton->reset(); - thisCharacterButton->hide(); - thisCharacterButton->set_image(thisCourtroom->char_list.at(char_num).name); - - thisCourtroom->connect(thisCharacterButton, SIGNAL(clicked()), - thisCourtroom->char_button_mapper, SLOT(map())); - thisCourtroom->char_button_mapper->setMapping(thisCharacterButton, - char_num); - } -}; - -void AOCharSelectFilter(Courtroom *thisCourtroom, int char_num) -{ - AOCharButton *current_char = thisCourtroom->ui_char_button_list.at(char_num); - - if (!thisCourtroom->ui_char_taken->isChecked() && - thisCourtroom->char_list.at(char_num).taken) - return; - - if (!thisCourtroom->char_list.at(char_num).name.contains( - thisCourtroom->ui_char_search->text(), Qt::CaseInsensitive)) - return; - - // We only really need to update the fact that a character is taken - // for the buttons that actually appear. - // You'd also update the passwordedness and etc. here later. - current_char->reset(); - current_char->set_taken(thisCourtroom->char_list.at(char_num).taken); - - thisCourtroom->ui_char_button_list_filtered.append(current_char); -} - void Courtroom::construct_char_select() { ui_char_select_background = new AOImage(this, ao_app); @@ -92,36 +44,27 @@ void Courtroom::construct_char_select() set_size_and_pos(ui_char_buttons, "char_buttons"); - connect(char_button_mapper, SIGNAL(mapped(int)), this, - SLOT(char_clicked(int))); - connect(ui_back_to_lobby, SIGNAL(clicked()), this, - SLOT(on_back_to_lobby_clicked())); + connect(ui_back_to_lobby, SIGNAL(clicked()), this, SLOT(on_back_to_lobby_clicked())); - connect(ui_char_select_left, SIGNAL(clicked()), this, - SLOT(on_char_select_left_clicked())); - connect(ui_char_select_right, SIGNAL(clicked()), this, - SLOT(on_char_select_right_clicked())); + connect(ui_char_select_left, SIGNAL(clicked()), this, SLOT(on_char_select_left_clicked())); + connect(ui_char_select_right, SIGNAL(clicked()), this, SLOT(on_char_select_right_clicked())); connect(ui_spectator, SIGNAL(clicked()), this, SLOT(on_spectator_clicked())); - connect(ui_char_search, SIGNAL(textEdited(const QString &)), this, - SLOT(on_char_search_changed())); - connect(ui_char_passworded, SIGNAL(stateChanged(int)), this, - SLOT(on_char_passworded_clicked())); - connect(ui_char_taken, SIGNAL(stateChanged(int)), this, - SLOT(on_char_taken_clicked())); + connect(ui_char_search, SIGNAL(textEdited(const QString&)), this, SLOT(on_char_search_changed())); + connect(ui_char_passworded, SIGNAL(stateChanged(int)), this, SLOT(on_char_passworded_clicked())); + connect(ui_char_taken, SIGNAL(stateChanged(int)), this, SLOT(on_char_taken_clicked())); } void Courtroom::set_char_select() { QString filename = "courtroom_design.ini"; - pos_size_type f_charselect = - ao_app->get_element_dimensions("char_select", filename); + pos_size_type f_charselect = ao_app->get_element_dimensions("char_select", filename); - if (f_charselect.width < 0 || f_charselect.height < 0) { - qDebug() - << "W: did not find courtroom width or height in courtroom_design.ini!"; + if (f_charselect.width < 0 || f_charselect.height < 0) + { + qDebug() << "W: did not find courtroom width or height in courtroom_design.ini!"; this->resize(714, 668); } else @@ -142,22 +85,25 @@ void Courtroom::set_char_select_page() ui_char_select_left->hide(); ui_char_select_right->hide(); - for (AOCharButton *i_button : ui_char_button_list) { + for (AOCharButton *i_button : ui_char_button_list) + { i_button->reset(); i_button->hide(); - i_button->move(0, 0); + i_button->move(0,0); } int total_pages = ui_char_button_list_filtered.size() / max_chars_on_page; int chars_on_page = 0; - if (ui_char_button_list_filtered.size() % max_chars_on_page != 0) { + if (ui_char_button_list_filtered.size() % max_chars_on_page != 0) + { ++total_pages; - // i. e. not on the last page + //i. e. not on the last page if (total_pages > current_char_page + 1) chars_on_page = max_chars_on_page; else chars_on_page = ui_char_button_list_filtered.size() % max_chars_on_page; + } else chars_on_page = max_chars_on_page; @@ -173,25 +119,23 @@ void Courtroom::set_char_select_page() void Courtroom::char_clicked(int n_char) { - QString char_ini_path = - ao_app->get_character_path(char_list.at(n_char).name, "char.ini"); + QString char_ini_path = ao_app->get_character_path(char_list.at(n_char).name, "char.ini"); qDebug() << "char_ini_path" << char_ini_path; - if (!file_exists(char_ini_path)) { - call_notice(tr("Could not find %1").arg(char_ini_path, 1)); + if (!file_exists(char_ini_path)) + { + call_notice("Could not find " + char_ini_path); return; } - if (n_char == m_cid) { + if (n_char == m_cid) + { enter_courtroom(m_cid); } - else { - ao_app->send_server_packet( - new AOPacket("PW#" + ui_char_password->text() + "#%")); - ao_app->send_server_packet( - new AOPacket("CC#" + QString::number(ao_app->s_pv) + "#" + - QString::number(n_char) + "#" + get_hdid() + "#%")); + else + { + ao_app->send_server_packet(new AOPacket("CC#" + QString::number(ao_app->s_pv) + "#" + QString::number(n_char) + "#" + get_hdid() + "#%")); } ui_ic_chat_name->setPlaceholderText(char_list.at(n_char).name); @@ -199,94 +143,126 @@ void Courtroom::char_clicked(int n_char) void Courtroom::put_button_in_place(int starting, int chars_on_this_page) { - if (ui_char_button_list_filtered.size() == 0) - return; + if (ui_char_button_list_filtered.size() == 0) + return; - QPoint f_spacing = - ao_app->get_button_spacing("char_button_spacing", "courtroom_design.ini"); + QPoint f_spacing = ao_app->get_button_spacing("char_button_spacing", "courtroom_design.ini"); - int x_spacing = f_spacing.x(); - int x_mod_count = 0; + int x_spacing = f_spacing.x(); + int x_mod_count = 0; - int y_spacing = f_spacing.y(); - int y_mod_count = 0; + int y_spacing = f_spacing.y(); + int y_mod_count = 0; - char_columns = - ((ui_char_buttons->width() - button_width) / (x_spacing + button_width)) + - 1; - char_rows = ((ui_char_buttons->height() - button_height) / - (y_spacing + button_height)) + - 1; + char_columns = ((ui_char_buttons->width() - button_width) / (x_spacing + button_width)) + 1; + char_rows = ((ui_char_buttons->height() - button_height) / (y_spacing + button_height)) + 1; - max_chars_on_page = char_columns * char_rows; + max_chars_on_page = char_columns * char_rows; - int startout = starting; - for (int n = starting; n < startout + chars_on_this_page; ++n) { - int x_pos = (button_width + x_spacing) * x_mod_count; - int y_pos = (button_height + y_spacing) * y_mod_count; + int startout = starting; + for (int n = starting ; n < startout+chars_on_this_page ; ++n) + { + int x_pos = (button_width + x_spacing) * x_mod_count; + int y_pos = (button_height + y_spacing) * y_mod_count; - ui_char_button_list_filtered.at(n)->move(x_pos, y_pos); - ui_char_button_list_filtered.at(n)->show(); - ui_char_button_list_filtered.at(n)->apply_taken_image(); + ui_char_button_list_filtered.at(n)->move(x_pos, y_pos); + ui_char_button_list_filtered.at(n)->show(); + ui_char_button_list_filtered.at(n)->apply_taken_image(); - ++x_mod_count; + ++x_mod_count; - if (x_mod_count == char_columns) { - ++y_mod_count; - x_mod_count = 0; + if (x_mod_count == char_columns) + { + ++y_mod_count; + x_mod_count = 0; + } } - } } void Courtroom::character_loading_finished() { - // Zeroeth, we'll clear any leftover characters from previous server visits. - ao_app->generated_chars = 0; - if (ui_char_button_list.size() > 0) { - foreach (AOCharButton *item, ui_char_button_list) { - delete item; + // Zeroeth, we'll clear any leftover characters from previous server visits. + ao_app->generated_chars = 0; + if (ui_char_button_list.size() > 0) + { + foreach (AOCharButton* item, ui_char_button_list) { + delete item; + } + ui_char_button_list.clear(); } - ui_char_button_list.clear(); - } - // First, we'll make all the character buttons in the very beginning. - // Since we can't trust what will happen during the multi threading process, - // we assign the buttons their locations in the list according to the - // character list. - for (int n = 0; n < char_list.size(); n++) { - AOCharButton *characterButton = - new AOCharButton(ui_char_buttons, ao_app, 0, 0, char_list.at(n).taken); - ui_char_button_list.append(characterButton); - } + // First, we'll make all the character buttons in the very beginning. + // We also hide them all, so they can't be accidentally clicked. + // Later on, we'll be revealing buttons as we need them. + for (int n = 0; n < char_list.size(); n++) + { + AOCharButton* char_button = new AOCharButton(ui_char_buttons, ao_app, 0, 0, char_list.at(n).taken); + char_button->reset(); + char_button->hide(); + char_button->set_image(char_list.at(n).name); + ui_char_button_list.append(char_button); - // We also hide them all, so they can't be accidentally clicked. - // Later on, we'll be revealing buttons as we need them. - for (int n = 0; n < char_list.size(); n++) { - AOCharSelectGenerationThreading *char_generate = - new AOCharSelectGenerationThreading(this, n); - QThreadPool::globalInstance()->start(char_generate); - if (QThreadPool::globalInstance()->activeThreadCount() == - QThreadPool::globalInstance()->maxThreadCount()) { - QThreadPool::globalInstance()->waitForDone(); + connect(char_button, &AOCharButton::clicked, [this, n](){ + this->char_clicked(n); + }); + + // This part here serves as a way of showing to the player that the game is still running, it is + // just loading the pictures of the characters. + if (ao_app->lobby_constructed) + { + ao_app->generated_chars++; + int total_loading_size = ao_app->char_list_size * 2 + ao_app->evidence_list_size + ao_app->music_list_size; + int loading_value = int(((ao_app->loaded_chars + ao_app->generated_chars + ao_app->loaded_music + ao_app->loaded_evidence) / static_cast(total_loading_size)) * 100); + ao_app->w_lobby->set_loading_value(loading_value); + ao_app->w_lobby->set_loading_text("Generating chars:\n" + QString::number(ao_app->generated_chars) + "/" + QString::number(ao_app->char_list_size)); + } } - } - QThreadPool::globalInstance()->waitForDone(); - filter_character_list(); + + filter_character_list(); } void Courtroom::filter_character_list() { - ui_char_button_list_filtered.clear(); - for (int i = 0; i < char_list.size(); i++) { - AOCharSelectFilter(this, i); - } + ui_char_button_list_filtered.clear(); + for (int i = 0; i < char_list.size(); i++) + { + AOCharButton* current_char = ui_char_button_list.at(i); - current_char_page = 0; - set_char_select_page(); + // It seems passwording characters is unimplemented yet? + // Until then, this will stay here, I suppose. + //if (ui_char_passworded->isChecked() && character_is_passworded??) + // continue; + + if (!ui_char_taken->isChecked() && char_list.at(i).taken) + continue; + + if (!char_list.at(i).name.contains(ui_char_search->text(), Qt::CaseInsensitive)) + continue; + + // We only really need to update the fact that a character is taken + // for the buttons that actually appear. + // You'd also update the passwordedness and etc. here later. + current_char->reset(); + current_char->set_taken(char_list.at(i).taken); + + ui_char_button_list_filtered.append(current_char); + } + + current_char_page = 0; + set_char_select_page(); } -void Courtroom::on_char_search_changed() { filter_character_list(); } +void Courtroom::on_char_search_changed() +{ + filter_character_list(); +} -void Courtroom::on_char_passworded_clicked() { filter_character_list(); } +void Courtroom::on_char_passworded_clicked() +{ + filter_character_list(); +} -void Courtroom::on_char_taken_clicked() { filter_character_list(); } +void Courtroom::on_char_taken_clicked() +{ + filter_character_list(); +} diff --git a/src/chatlogpiece.cpp b/src/chatlogpiece.cpp index 9017b96..6c861f0 100644 --- a/src/chatlogpiece.cpp +++ b/src/chatlogpiece.cpp @@ -5,46 +5,58 @@ chatlogpiece::chatlogpiece() name = "UNKNOWN"; showname = "UNKNOWN"; message = "UNKNOWN"; - color = 0; is_song = false; datetime = QDateTime::currentDateTime().toUTC(); } -chatlogpiece::chatlogpiece(QString p_name, QString p_showname, - QString p_message, bool p_song, int p_color) +chatlogpiece::chatlogpiece(QString p_name, QString p_showname, QString p_message, bool p_song) { name = p_name; showname = p_showname; message = p_message; is_song = p_song; - color = p_color; datetime = QDateTime::currentDateTime().toUTC(); } -chatlogpiece::chatlogpiece(QString p_name, QString p_showname, - QString p_message, bool p_song, int p_color, - QDateTime p_datetime) +chatlogpiece::chatlogpiece(QString p_name, QString p_showname, QString p_message, bool p_song, QDateTime p_datetime) { name = p_name; showname = p_showname; message = p_message; is_song = p_song; - color = p_color; datetime = p_datetime.toUTC(); } -QString chatlogpiece::get_name() { return name; } +QString chatlogpiece::get_name() +{ + return name; +} -QString chatlogpiece::get_showname() { return showname; } +QString chatlogpiece::get_showname() +{ + return showname; +} -QString chatlogpiece::get_message() { return message; } +QString chatlogpiece::get_message() +{ + return message; +} -QDateTime chatlogpiece::get_datetime() { return datetime; } +QDateTime chatlogpiece::get_datetime() +{ + return datetime; +} -bool chatlogpiece::get_is_song() { return is_song; } +bool chatlogpiece::get_is_song() +{ + return is_song; +} + +QString chatlogpiece::get_datetime_as_string() +{ + return datetime.toString(); +} -QString chatlogpiece::get_datetime_as_string() { return datetime.toString(); } -int chatlogpiece::get_chat_color() { return color; } QString chatlogpiece::get_full() { diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 11c0bda..cd01f64 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1,4487 +1,3605 @@ -#include "courtroom.h" - -Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() -{ - ao_app = p_ao_app; -#ifdef BASSAUDIO - // Change the default audio output device to be the one the user has given - // in his config.ini file for now. - unsigned int a = 0; - BASS_DEVICEINFO info; - - if (ao_app->get_audio_output_device() == "default") { - BASS_Init(-1, 48000, BASS_DEVICE_LATENCY, nullptr, nullptr); - load_bass_opus_plugin(); - } - else { - for (a = 0; BASS_GetDeviceInfo(a, &info); a++) { - if (ao_app->get_audio_output_device() == info.name) { - BASS_SetDevice(a); - BASS_Init(static_cast(a), 48000, BASS_DEVICE_LATENCY, nullptr, - nullptr); - load_bass_opus_plugin(); - qDebug() << info.name << "was set as the default audio output device."; - break; - } - } - } -#elif defined QTAUDIO - - if (ao_app->get_audio_output_device() != "default") { - foreach (const QAudioDeviceInfo &deviceInfo, - QAudioDeviceInfo::availableDevices(QAudio::AudioOutput)) { - if (ao_app->get_audio_output_device() == deviceInfo.deviceName()) { - ao_app->QtAudioDevice = deviceInfo; - qDebug() << deviceInfo.deviceName() - << "was set as the default audio output device."; - break; - } - } - } -#endif - - keepalive_timer = new QTimer(this); - keepalive_timer->start(60000); - - chat_tick_timer = new QTimer(this); - - text_delay_timer = new QTimer(this); - text_delay_timer->setSingleShot(true); - - sfx_delay_timer = new QTimer(this); - sfx_delay_timer->setSingleShot(true); - - realization_timer = new QTimer(this); - realization_timer->setSingleShot(true); - - char_button_mapper = new QSignalMapper(this); - - music_player = new AOMusicPlayer(this, ao_app); - music_player->set_volume(0); - - sfx_player = new AOSfxPlayer(this, ao_app); - sfx_player->set_volume(0); - - objection_player = new AOSfxPlayer(this, ao_app); - objection_player->set_volume(0); - - misc_sfx_player = new AOSfxPlayer(this, ao_app); - misc_sfx_player->set_volume(0); - frame_emote_sfx_player = new AOSfxPlayer(this, ao_app); - frame_emote_sfx_player->set_volume(0); - pair_frame_emote_sfx_player = new AOSfxPlayer(this, ao_app); - pair_frame_emote_sfx_player->set_volume(0); - - char_button_mapper = new QSignalMapper(this); - - blip_player = new AOBlipPlayer(this, ao_app); - blip_player->set_volume(0); - - modcall_player = new AOSfxPlayer(this, ao_app); - modcall_player->set_volume(50); - - ui_background = new AOImage(this, ao_app); - - ui_viewport = new QWidget(this); - ui_vp_background = new AOScene(ui_viewport, ao_app); - ui_vp_speedlines = new AOMovie(ui_viewport, ao_app); - ui_vp_speedlines->set_play_once(false); - ui_vp_player_char = new AOCharMovie(ui_viewport, ao_app); - ui_vp_player_char->frame_specific_sfx_player = frame_emote_sfx_player; - ui_vp_player_char->mycourtroom = this; - ui_vp_sideplayer_char = new AOCharMovie(ui_viewport, ao_app); - ui_vp_sideplayer_char->frame_specific_sfx_player = - pair_frame_emote_sfx_player; - ui_vp_sideplayer_char->mycourtroom = this; - ui_vp_sideplayer_char->hide(); - ui_vp_desk = new AOScene(ui_viewport, ao_app); - ui_vp_legacy_desk = new AOScene(ui_viewport, ao_app); - - ui_vp_evidence_display = new AOEvidenceDisplay(this, ao_app); - - ui_vp_chatbox = new AOImage(this, ao_app); - ui_vp_showname = new QLabel(ui_vp_chatbox); - ui_vp_message = new QTextEdit(ui_vp_chatbox); - ui_vp_message->setFrameStyle(QFrame::NoFrame); - ui_vp_message->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - ui_vp_message->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - ui_vp_message->setReadOnly(true); - - ui_vp_testimony = new AOMovie(this, ao_app); - ui_vp_testimony->set_play_once(false); - ui_vp_realization = new AOMovie(this, ao_app); - ui_vp_wtce = new AOMovie(this, ao_app); - ui_vp_objection = new AOMovie(this, ao_app); - - ui_ic_chatlog = new QTextEdit(this); - ui_ic_chatlog->setReadOnly(true); - - log_maximum_blocks = ao_app->get_max_log_size(); - log_goes_downwards = ao_app->get_log_goes_downwards(); - - ui_ms_chatlog = new AOTextArea(this); - ui_ms_chatlog->setReadOnly(true); - ui_ms_chatlog->setOpenExternalLinks(true); - ui_ms_chatlog->hide(); - - ui_server_chatlog = new AOTextArea(this); - ui_server_chatlog->setReadOnly(true); - ui_server_chatlog->setOpenExternalLinks(true); - - ui_area_list = new QListWidget(this); - - ui_music_list = new QTreeWidget(this); - ui_music_list->setColumnCount(2); - ui_music_list->hideColumn(1); - ui_music_list->setHeaderHidden(true); - ui_music_list->setContextMenuPolicy(Qt::CustomContextMenu); - ui_music_list->setAutoFillBackground(true); - ui_music_list->setExpandsOnDoubleClick(true); - ui_music_list->setRootIsDecorated(true); - ui_music_list->header()->setStretchLastSection(false); - ui_music_list->header()->setSectionResizeMode(QHeaderView::ResizeToContents); - ui_music_list->setContextMenuPolicy(Qt::CustomContextMenu); - - ui_music_list->hide(); - - ui_ic_chat_name = new QLineEdit(this); - ui_ic_chat_name->setFrame(false); - ui_ic_chat_name->setPlaceholderText(tr("Showname")); - - ui_ic_chat_message = new QLineEdit(this); - ui_ic_chat_message->setFrame(false); - ui_ic_chat_message->setPlaceholderText(tr("Message")); - - ui_muted = new AOImage(ui_ic_chat_message, ao_app); - ui_muted->hide(); - - ui_ooc_chat_message = new QLineEdit(this); - ui_ooc_chat_message->setFrame(false); - ui_ooc_chat_message->setPlaceholderText(tr("OOC Message")); - - ui_ooc_chat_name = new QLineEdit(this); - ui_ooc_chat_name->setFrame(false); - ui_ooc_chat_name->setPlaceholderText(tr("Name")); - ui_ooc_chat_name->setMaxLength(30); - ui_ooc_chat_name->setText(p_ao_app->get_default_username()); - - punctuation_modifier = p_ao_app->get_pundelay(); - slower_blips = p_ao_app->get_slower_blips(); - colorf_iclog = p_ao_app->get_colored_iclog_enabled(); - mirror_iclog = p_ao_app->get_iclmir_enabled(); - colorf_limit = p_ao_app->colorlog_restricted_enabled(); - keep_evidence_display = p_ao_app->is_keepevi_enabled(); - - // ui_area_password = new QLineEdit(this); - // ui_area_password->setFrame(false); - ui_music_search = new QLineEdit(this); - ui_music_search->setFrame(false); - ui_music_search->setPlaceholderText(tr("Search")); - - construct_emotes(); - - ui_emote_left = new AOButton(this, ao_app); - ui_emote_right = new AOButton(this, ao_app); - - ui_emote_dropdown = new QComboBox(this); - ui_pos_dropdown = new QComboBox(this); - ui_pos_dropdown->addItem("wit"); - ui_pos_dropdown->addItem("def"); - ui_pos_dropdown->addItem("pro"); - ui_pos_dropdown->addItem("jud"); - ui_pos_dropdown->addItem("hld"); - ui_pos_dropdown->addItem("hlp"); - ui_pos_dropdown->addItem("jur"); - ui_pos_dropdown->addItem("sea"); - - ui_defense_bar = new AOImage(this, ao_app); - ui_prosecution_bar = new AOImage(this, ao_app); - - ui_music_label = new QLabel(this); - ui_sfx_label = new QLabel(this); - ui_blip_label = new QLabel(this); - - ui_log_limit_label = new QLabel(this); - - ui_hold_it = new AOButton(this, ao_app); - ui_objection = new AOButton(this, ao_app); - ui_take_that = new AOButton(this, ao_app); - - ui_ooc_toggle = new AOButton(this, ao_app); - ui_witness_testimony = new AOButton(this, ao_app); - ui_cross_examination = new AOButton(this, ao_app); - ui_guilty = new AOButton(this, ao_app); - ui_not_guilty = new AOButton(this, ao_app); - - ui_change_character = new AOButton(this, ao_app); - ui_reload_theme = new AOButton(this, ao_app); - ui_call_mod = new AOButton(this, ao_app); - ui_settings = new AOButton(this, ao_app); - ui_announce_casing = new AOButton(this, ao_app); - ui_switch_area_music = new AOButton(this, ao_app); - - ui_pre = new QCheckBox(this); - ui_pre->setText(tr("Pre")); - - ui_flip = new QCheckBox(this); - ui_flip->setText(tr("Flip")); - ui_flip->hide(); - - ui_guard = new QCheckBox(this); - - ui_guard->setText(tr("Disable Modcalls")); - - ui_guard->hide(); - - ui_casing = new QCheckBox(this); - ui_casing->setChecked(ao_app->get_casing_enabled()); - ui_casing->setText(tr("Casing")); - ui_casing->hide(); - - ui_showname_enable = new QCheckBox(this); - ui_showname_enable->setChecked(ao_app->get_showname_enabled_by_default()); - ui_showname_enable->setText(tr("Shownames")); - - ui_pre_non_interrupt = new QCheckBox(this); - ui_pre_non_interrupt->setText(tr("No Interrupt")); - ui_pre_non_interrupt->hide(); - - ui_custom_objection = new AOButton(this, ao_app); - ui_custom_objection->setContextMenuPolicy(Qt::CustomContextMenu); - custom_obj_menu = new QMenu; - - ui_realization = new AOButton(this, ao_app); - ui_screenshake = new AOButton(this, ao_app); - ui_mute = new AOButton(this, ao_app); - - ui_defense_plus = new AOButton(this, ao_app); - ui_defense_minus = new AOButton(this, ao_app); - - ui_prosecution_plus = new AOButton(this, ao_app); - ui_prosecution_minus = new AOButton(this, ao_app); - - ui_text_color = new QComboBox(this); - ui_text_color->addItem(tr("White")); - ui_text_color->addItem(tr("Green")); - ui_text_color->addItem(tr("Red")); - ui_text_color->addItem(tr("Orange")); - ui_text_color->addItem(tr("Blue")); - ui_text_color->addItem(tr("Yellow")); - ui_text_color->addItem(tr("Rainbow")); - ui_text_color->addItem(tr("Pink")); - ui_text_color->addItem(tr("Cyan")); - - ui_music_slider = new QSlider(Qt::Horizontal, this); - ui_music_slider->setRange(0, 100); - ui_music_slider->setValue(ao_app->get_default_music()); - - ui_sfx_slider = new QSlider(Qt::Horizontal, this); - ui_sfx_slider->setRange(0, 100); - ui_sfx_slider->setValue(ao_app->get_default_sfx()); - - ui_blip_slider = new QSlider(Qt::Horizontal, this); - ui_blip_slider->setRange(0, 100); - ui_blip_slider->setValue(ao_app->get_default_blip()); - - ui_log_limit_spinbox = new QSpinBox(this); - ui_log_limit_spinbox->setRange(0, 10000); - ui_log_limit_spinbox->setValue(ao_app->get_max_log_size()); - - ui_mute_list = new QListWidget(this); - - ui_pair_list = new QListWidget(this); - ui_pair_offset_spinbox = new QSpinBox(this); - ui_pair_offset_spinbox->setRange(-100, 100); - ui_pair_offset_spinbox->setSuffix(tr("% offset")); - ui_pair_button = new AOButton(this, ao_app); - - ui_evidence_button = new AOButton(this, ao_app); - - construct_evidence(); - - construct_char_select(); - - connect(keepalive_timer, SIGNAL(timeout()), this, SLOT(ping_server())); - - connect(ui_vp_objection, SIGNAL(done()), this, SLOT(objection_done())); - connect(ui_vp_player_char, SIGNAL(done()), this, SLOT(preanim_done())); - - connect(text_delay_timer, SIGNAL(timeout()), this, - SLOT(start_chat_ticking())); - connect(sfx_delay_timer, SIGNAL(timeout()), this, SLOT(play_sfx())); - - connect(chat_tick_timer, SIGNAL(timeout()), this, SLOT(chat_tick())); - connect(realization_timer, SIGNAL(timeout()), this, SLOT(realization_done())); - - connect(ui_emote_left, SIGNAL(clicked()), this, - SLOT(on_emote_left_clicked())); - connect(ui_emote_right, SIGNAL(clicked()), this, - SLOT(on_emote_right_clicked())); - - connect(ui_emote_dropdown, SIGNAL(activated(int)), this, - SLOT(on_emote_dropdown_changed(int))); - connect(ui_pos_dropdown, SIGNAL(currentIndexChanged(int)), this, - SLOT(on_pos_dropdown_changed(int))); - - connect(ui_mute_list, SIGNAL(clicked(QModelIndex)), this, - SLOT(on_mute_list_clicked(QModelIndex))); - - connect(ui_ic_chat_message, SIGNAL(returnPressed()), this, - SLOT(on_chat_return_pressed())); - - connect(ui_ooc_chat_message, SIGNAL(returnPressed()), this, - SLOT(on_ooc_return_pressed())); - - connect(ui_music_list, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), - this, SLOT(on_music_list_double_clicked(QTreeWidgetItem *, int))); - connect(ui_area_list, SIGNAL(doubleClicked(QModelIndex)), this, - SLOT(on_area_list_double_clicked(QModelIndex))); - connect(ui_hold_it, SIGNAL(clicked()), this, SLOT(on_hold_it_clicked())); - connect(ui_objection, SIGNAL(clicked()), this, SLOT(on_objection_clicked())); - connect(ui_take_that, SIGNAL(clicked()), this, SLOT(on_take_that_clicked())); - connect(ui_custom_objection, SIGNAL(clicked()), this, - SLOT(on_custom_objection_clicked())); - connect(ui_custom_objection, - SIGNAL(customContextMenuRequested(const QPoint &)), this, - SLOT(ShowContextMenu(const QPoint &))); - connect(ui_realization, SIGNAL(clicked()), this, - SLOT(on_realization_clicked())); - connect(ui_screenshake, SIGNAL(clicked()), this, - SLOT(on_screenshake_clicked())); - connect(ui_mute, SIGNAL(clicked()), this, SLOT(on_mute_clicked())); - - connect(ui_defense_minus, SIGNAL(clicked()), this, - SLOT(on_defense_minus_clicked())); - connect(ui_defense_plus, SIGNAL(clicked()), this, - SLOT(on_defense_plus_clicked())); - connect(ui_prosecution_minus, SIGNAL(clicked()), this, - SLOT(on_prosecution_minus_clicked())); - connect(ui_prosecution_plus, SIGNAL(clicked()), this, - SLOT(on_prosecution_plus_clicked())); - - connect(ui_text_color, SIGNAL(currentIndexChanged(int)), this, - SLOT(on_text_color_changed(int))); - - connect(ui_music_slider, SIGNAL(valueChanged(int)), this, - SLOT(on_music_slider_moved(int))); - connect(ui_sfx_slider, SIGNAL(valueChanged(int)), this, - SLOT(on_sfx_slider_moved(int))); - connect(ui_blip_slider, SIGNAL(valueChanged(int)), this, - SLOT(on_blip_slider_moved(int))); - - connect(ui_log_limit_spinbox, SIGNAL(valueChanged(int)), this, - SLOT(on_log_limit_changed(int))); - - connect(ui_ooc_toggle, SIGNAL(clicked()), this, - SLOT(on_ooc_toggle_clicked())); - - connect(ui_music_search, SIGNAL(returnPressed()), this, - SLOT(on_music_search_keypr())); - connect(ui_music_search, SIGNAL(textChanged(QString)), this, - SLOT(on_music_search_edited(QString))); - - connect(ui_witness_testimony, SIGNAL(clicked()), this, - SLOT(on_witness_testimony_clicked())); - connect(ui_cross_examination, SIGNAL(clicked()), this, - SLOT(on_cross_examination_clicked())); - connect(ui_guilty, SIGNAL(clicked()), this, SLOT(on_guilty_clicked())); - connect(ui_not_guilty, SIGNAL(clicked()), this, - SLOT(on_not_guilty_clicked())); - - connect(ui_change_character, SIGNAL(clicked()), this, - SLOT(on_change_character_clicked())); - connect(ui_reload_theme, SIGNAL(clicked()), this, - SLOT(on_reload_theme_clicked())); - connect(ui_call_mod, SIGNAL(clicked()), this, SLOT(on_call_mod_clicked())); - connect(ui_settings, SIGNAL(clicked()), this, SLOT(on_settings_clicked())); - connect(ui_announce_casing, SIGNAL(clicked()), this, - SLOT(on_announce_casing_clicked())); - connect(ui_switch_area_music, SIGNAL(clicked()), this, - SLOT(on_switch_area_music_clicked())); - - connect(ui_pre, SIGNAL(clicked()), this, SLOT(on_pre_clicked())); - connect(ui_flip, SIGNAL(clicked()), this, SLOT(on_flip_clicked())); - connect(ui_guard, SIGNAL(clicked()), this, SLOT(on_guard_clicked())); - connect(ui_casing, SIGNAL(clicked()), this, SLOT(on_casing_clicked())); - - connect(ui_showname_enable, SIGNAL(clicked()), this, - SLOT(on_showname_enable_clicked())); - - connect(ui_pair_button, SIGNAL(clicked()), this, SLOT(on_pair_clicked())); - connect(ui_pair_list, SIGNAL(clicked(QModelIndex)), this, - SLOT(on_pair_list_clicked(QModelIndex))); - connect(ui_pair_offset_spinbox, SIGNAL(valueChanged(int)), this, - SLOT(on_pair_offset_changed(int))); - - connect(ui_evidence_button, SIGNAL(clicked()), this, - SLOT(on_evidence_button_clicked())); - - set_widgets(); - - set_char_select(); - detect_fallback_text(); -} - -void Courtroom::set_mute_list() -{ - mute_map.clear(); - - // maps which characters are muted based on cid, none are muted by default - for (int n_cid = 0; n_cid < char_list.size(); n_cid++) { - mute_map.insert(n_cid, false); - } - - QStringList sorted_mute_list; - - for (char_type i_char : char_list) - sorted_mute_list.append(i_char.name); - - sorted_mute_list.sort(); - - for (QString i_name : sorted_mute_list) { - // mute_map.insert(i_name, false); - ui_mute_list->addItem(i_name); - } -} - -void Courtroom::set_pair_list() -{ - QStringList sorted_pair_list; - - for (char_type i_char : char_list) - sorted_pair_list.append(i_char.name); - - sorted_pair_list.sort(); - - for (QString i_name : sorted_pair_list) { - ui_pair_list->addItem(i_name); - } -} - -void Courtroom::set_widgets() -{ - blip_rate = ao_app->read_blip_rate(); - blank_blip = ao_app->get_blank_blip(); - - QString filename = "courtroom_design.ini"; - - pos_size_type f_courtroom = - ao_app->get_element_dimensions("courtroom", filename); - - if (f_courtroom.width < 0 || f_courtroom.height < 0) { - qDebug() << "W: did not find courtroom width or height in " << filename; - - this->resize(714, 668); - } - else { - m_courtroom_width = f_courtroom.width; - m_courtroom_height = f_courtroom.height; - - this->resize(f_courtroom.width, f_courtroom.height); - } - - set_fonts(); - - ui_background->move(0, 0); - ui_background->resize(m_courtroom_width, m_courtroom_height); - ui_background->set_image("courtroombackground.png"); - - set_size_and_pos(ui_viewport, "viewport"); - - // 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_support_enabled) { - ui_pair_button->show(); - ui_pre_non_interrupt->show(); - ui_showname_enable->show(); - ui_ic_chat_name->show(); - ui_ic_chat_name->setEnabled(true); - } - else { - ui_pair_button->hide(); - ui_pre_non_interrupt->hide(); - ui_showname_enable->hide(); - ui_ic_chat_name->hide(); - ui_ic_chat_name->setEnabled(false); - } - - if (ao_app->casing_alerts_enabled) { - ui_announce_casing->show(); - } - else { - ui_announce_casing->hide(); - } - - // We also show the non-server-dependent client additions. - // Once again, if the theme can't display it, set_move_and_pos will catch - // them. - ui_settings->show(); - ui_log_limit_label->show(); - ui_log_limit_spinbox->show(); - - ui_vp_background->move(0, 0); - ui_vp_background->resize(ui_viewport->width(), ui_viewport->height()); - - ui_vp_speedlines->move(0, 0); - ui_vp_speedlines->combo_resize(ui_viewport->width(), ui_viewport->height()); - - ui_vp_player_char->move(0, 0); - ui_vp_player_char->combo_resize(ui_viewport->width(), ui_viewport->height()); - - ui_vp_sideplayer_char->move(0, 0); - ui_vp_sideplayer_char->combo_resize(ui_viewport->width(), - ui_viewport->height()); - - // the AO2 desk element - ui_vp_desk->move(0, 0); - ui_vp_desk->resize(ui_viewport->width(), ui_viewport->height()); - - // the size of the ui_vp_legacy_desk element relies on various factors and is - // set in set_scene() - - double y_modifier = 147.0 / 192.0; - int final_y = static_cast(y_modifier * ui_viewport->height()); - ui_vp_legacy_desk->move(0, final_y); - ui_vp_legacy_desk->hide(); - - ui_vp_evidence_display->move(0, 0); - ui_vp_evidence_display->resize(ui_viewport->width(), ui_viewport->height()); - - set_size_and_pos(ui_vp_showname, "showname"); - - set_size_and_pos(ui_vp_message, "message"); - ui_vp_message->setTextInteractionFlags(Qt::NoTextInteraction); - ui_vp_message->setStyleSheet("background-color: rgba(0, 0, 0, 0);" - "color: white"); - - ui_vp_testimony->move(ui_viewport->x(), ui_viewport->y()); - ui_vp_testimony->combo_resize(ui_viewport->width(), ui_viewport->height()); - - ui_vp_realization->move(ui_viewport->x(), ui_viewport->y()); - ui_vp_realization->combo_resize(ui_viewport->width(), ui_viewport->height()); - - ui_vp_wtce->move(ui_viewport->x(), ui_viewport->y()); - ui_vp_wtce->combo_resize(ui_viewport->width(), ui_viewport->height()); - - ui_vp_objection->move(ui_viewport->x(), ui_viewport->y()); - ui_vp_objection->combo_resize(ui_viewport->width(), ui_viewport->height()); - - set_size_and_pos(ui_ic_chatlog, "ic_chatlog"); - - set_size_and_pos(ui_ms_chatlog, "ms_chatlog"); - - set_size_and_pos(ui_server_chatlog, "server_chatlog"); - - 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(); - set_size_and_pos(ui_pair_offset_spinbox, "pair_offset_spinbox"); - ui_pair_offset_spinbox->hide(); - set_size_and_pos(ui_pair_button, "pair_button"); - ui_pair_button->set_image("pair_button.png"); - - set_size_and_pos(ui_area_list, "music_list"); - ui_area_list->setStyleSheet("background-color: rgba(0, 0, 0, 0);"); - - ui_music_list->setStyleSheet("background-color: rgba(100, 103, 132, 225);"); - - ui_music_list->collapseAll(); - - set_size_and_pos(ui_music_list, "music_list"); - - if (is_ao2_bg) { - set_size_and_pos(ui_ic_chat_message, "ao2_ic_chat_message"); - set_size_and_pos(ui_vp_chatbox, "ao2_chatbox"); - set_size_and_pos(ui_ic_chat_name, "ao2_ic_chat_name"); - } - else { - set_size_and_pos(ui_ic_chat_message, "ic_chat_message"); - set_size_and_pos(ui_vp_chatbox, "chatbox"); - set_size_and_pos(ui_ic_chat_name, "ic_chat_name"); - } - - ui_ic_chat_message->setStyleSheet( - "QLineEdit{background-color: rgba(100, 100, 100, 255);}"); - ui_ic_chat_name->setStyleSheet( - "QLineEdit{background-color: rgba(180, 180, 180, 255);}"); - - ui_vp_chatbox->set_image("chatmed.png"); - ui_vp_chatbox->hide(); - - ui_muted->resize(ui_ic_chat_message->width(), ui_ic_chat_message->height()); - ui_muted->set_image("muted.png"); - - set_size_and_pos(ui_ooc_chat_message, "ooc_chat_message"); - ui_ooc_chat_message->setStyleSheet("background-color: rgba(0, 0, 0, 0);"); - - set_size_and_pos(ui_ooc_chat_name, "ooc_chat_name"); - ui_ooc_chat_name->setStyleSheet("background-color: rgba(0, 0, 0, 0);"); - - // set_size_and_pos(ui_area_password, "area_password"); - set_size_and_pos(ui_music_search, "music_search"); - - set_size_and_pos(ui_emotes, "emotes"); - - set_size_and_pos(ui_emote_left, "emote_left"); - ui_emote_left->set_image("arrow_left.png"); - - set_size_and_pos(ui_emote_right, "emote_right"); - ui_emote_right->set_image("arrow_right.png"); - - set_size_and_pos(ui_emote_dropdown, "emote_dropdown"); - set_size_and_pos(ui_pos_dropdown, "pos_dropdown"); - - set_size_and_pos(ui_defense_bar, "defense_bar"); - ui_defense_bar->set_image("defensebar" + QString::number(defense_bar_state) + - ".png"); - - set_size_and_pos(ui_prosecution_bar, "prosecution_bar"); - ui_prosecution_bar->set_image( - "prosecutionbar" + QString::number(prosecution_bar_state) + ".png"); - - set_size_and_pos(ui_music_label, "music_label"); - ui_music_label->setText(tr("Music")); - set_size_and_pos(ui_sfx_label, "sfx_label"); - ui_sfx_label->setText(tr("Sfx")); - set_size_and_pos(ui_blip_label, "blip_label"); - ui_blip_label->setText(tr("Blips")); - - set_size_and_pos(ui_log_limit_label, "log_limit_label"); - ui_log_limit_label->setText(tr("Log limit")); - - set_size_and_pos(ui_hold_it, "hold_it"); - ui_hold_it->set_image("holdit.png"); - set_size_and_pos(ui_objection, "objection"); - ui_objection->set_image("objection.png"); - set_size_and_pos(ui_take_that, "take_that"); - ui_take_that->set_image("takethat.png"); - - set_size_and_pos(ui_ooc_toggle, "ooc_toggle"); - if (ooc_toggle_fallback) { - ui_ooc_toggle->setText(tr("Server")); - } - else { - ui_ooc_toggle->set_image("ooc_toggle_server.png"); - ui_ooc_toggle->setText(tr("")); - } - - set_size_and_pos(ui_witness_testimony, "witness_testimony"); - ui_witness_testimony->set_image("witnesstestimony.png"); - set_size_and_pos(ui_cross_examination, "cross_examination"); - ui_cross_examination->set_image("crossexamination.png"); - - set_size_and_pos(ui_guilty, "guilty"); - ui_guilty->set_image("guilty.png"); - set_size_and_pos(ui_not_guilty, "not_guilty"); - ui_not_guilty->set_image("notguilty.png"); - - set_size_and_pos(ui_change_character, "change_character"); - if (change_char_fallback) { - ui_change_character->setText(tr("Change character")); - } - else { - ui_change_character->set_image("change_character.png"); - ui_change_character->setText( - tr("")); // set text to empty otherwise it just sits there - } - - set_size_and_pos(ui_reload_theme, "reload_theme"); - if (reload_theme_fallback) { - ui_reload_theme->setText(tr("Reload theme")); - } - else { - ui_reload_theme->set_image("reload_theme.png"); - ui_reload_theme->setText(tr("")); - } - - set_size_and_pos(ui_call_mod, "call_mod"); - if (call_mod_fallback) { - ui_call_mod->setText(tr("Call mod")); - } - else { - ui_call_mod->set_image("call_mod.png"); - ui_call_mod->setText(tr("")); - } - - set_size_and_pos(ui_settings, "settings"); - if (settings_fallback) { - ui_settings->setText(tr("Settings")); - } - else { - ui_settings->set_image("settings.png"); - ui_settings->setText(tr("")); - } - - set_size_and_pos(ui_announce_casing, "casing_button"); - if (casing_fallback) { - ui_announce_casing->setText(tr("Casing")); - } - else { - ui_announce_casing->set_image("casing.png"); - ui_announce_casing->setText(tr("")); - } - - set_size_and_pos(ui_switch_area_music, "switch_area_music"); - if (amswap_fallback) { - ui_switch_area_music->setText(tr("A/M")); - } - else { - ui_switch_area_music->set_image("amswap.png"); - ui_switch_area_music->setText(tr("")); - } - - set_size_and_pos(ui_pre, "pre"); - ui_pre->setText(tr("Preanim")); - - set_size_and_pos(ui_pre_non_interrupt, "pre_no_interrupt"); - set_size_and_pos(ui_flip, "flip"); - - set_size_and_pos(ui_guard, "guard"); - - set_size_and_pos(ui_casing, "casing"); - - set_size_and_pos(ui_showname_enable, "showname_enable"); - - set_size_and_pos(ui_custom_objection, "custom_objection"); - ui_custom_objection->set_image("custom.png"); - - set_size_and_pos(ui_realization, "realization"); - ui_realization->set_image("realization.png"); - - set_size_and_pos(ui_screenshake, "screenshake"); - ui_screenshake->set_image("screenshake.png"); - - set_size_and_pos(ui_mute, "mute_button"); - ui_mute->set_image("mute.png"); - - set_size_and_pos(ui_defense_plus, "defense_plus"); - ui_defense_plus->set_image("defplus.png"); - - set_size_and_pos(ui_defense_minus, "defense_minus"); - ui_defense_minus->set_image("defminus.png"); - - set_size_and_pos(ui_prosecution_plus, "prosecution_plus"); - ui_prosecution_plus->set_image("proplus.png"); - - set_size_and_pos(ui_prosecution_minus, "prosecution_minus"); - ui_prosecution_minus->set_image("prominus.png"); - - set_size_and_pos(ui_text_color, "text_color"); - - set_size_and_pos(ui_music_slider, "music_slider"); - set_size_and_pos(ui_sfx_slider, "sfx_slider"); - set_size_and_pos(ui_blip_slider, "blip_slider"); - - set_size_and_pos(ui_log_limit_spinbox, "log_limit_spinbox"); - - set_size_and_pos(ui_evidence_button, "evidence_button"); - ui_evidence_button->set_image("evidencebutton.png"); - - set_size_and_pos(ui_evidence, "evidence_background"); - ui_evidence->set_image("evidencebackground.png"); - - set_size_and_pos(ui_evidence_name, "evidence_name"); - - set_size_and_pos(ui_evidence_buttons, "evidence_buttons"); - - set_size_and_pos(ui_evidence_left, "evidence_left"); - ui_evidence_left->set_image("arrow_left.png"); - - set_size_and_pos(ui_evidence_right, "evidence_right"); - ui_evidence_right->set_image("arrow_right.png"); - - set_size_and_pos(ui_evidence_present, "evidence_present"); - ui_evidence_present->set_image("present_disabled.png"); - - set_size_and_pos(ui_evidence_overlay, "evidence_overlay"); - ui_evidence_overlay->set_image("evidenceoverlay.png"); - - set_size_and_pos(ui_evidence_delete, "evidence_delete"); - ui_evidence_delete->set_image("deleteevidence.png"); - - set_size_and_pos(ui_evidence_image_name, "evidence_image_name"); - - set_size_and_pos(ui_evidence_image_button, "evidence_image_button"); - - set_size_and_pos(ui_evidence_x, "evidence_x"); - ui_evidence_x->set_image("evidencex.png"); - - set_size_and_pos(ui_evidence_description, "evidence_description"); - - ui_selector->set_image("char_selector.png"); - ui_selector->hide(); - - set_size_and_pos(ui_back_to_lobby, "back_to_lobby"); - ui_back_to_lobby->setText(tr("Back to Lobby")); - - set_size_and_pos(ui_char_password, "char_password"); - - set_size_and_pos(ui_char_buttons, "char_buttons"); - - set_size_and_pos(ui_char_select_left, "char_select_left"); - ui_char_select_left->set_image("arrow_left.png"); - - set_size_and_pos(ui_char_select_right, "char_select_right"); - ui_char_select_right->set_image("arrow_right.png"); - - set_size_and_pos(ui_spectator, "spectator"); -} - -void Courtroom::set_fonts() -{ - set_font(ui_vp_showname, "showname"); - set_font(ui_vp_message, "message"); - set_font(ui_ic_chatlog, "ic_chatlog"); - set_font(ui_ms_chatlog, "ms_chatlog"); - set_font(ui_server_chatlog, "server_chatlog"); - set_font(ui_music_list, "music_list"); - set_font(ui_area_list, "area_list"); - - // Set color of labels and checkboxes - const QString design_file = "courtroom_fonts.ini"; - QColor f_color = ao_app->get_color("label_color", design_file); - QString color_string = "color: rgba(" + QString::number(f_color.red()) + - ", " + QString::number(f_color.green()) + ", " + - QString::number(f_color.blue()) + ", 255); }"; - QString style_sheet_string = "QLabel {" + color_string + - "}" - "QCheckBox {" + - color_string + "}"; - setStyleSheet(style_sheet_string); -} - -void Courtroom::set_font(QWidget *widget, QString p_identifier) -{ - QString design_file = "courtroom_fonts.ini"; - int f_weight = ao_app->get_font_size(p_identifier, design_file); - QString class_name = widget->metaObject()->className(); - - QString fontt = ao_app->get_font_name(p_identifier + "_font", design_file); - widget->setFont(QFont(fontt, f_weight)); - - QColor f_color = ao_app->get_color(p_identifier + "_color", design_file); - - QString style_sheet_string = - class_name + " { background-color: rgba(0, 0, 0, 0);\n" + "color: rgba(" + - QString::number(f_color.red()) + ", " + QString::number(f_color.green()) + - ", " + QString::number(f_color.blue()) + ", 255); }"; - - widget->setStyleSheet(style_sheet_string); -} - -void Courtroom::set_window_title(QString p_title) -{ - this->setWindowTitle(p_title); -} - -void Courtroom::set_size_and_pos(QWidget *p_widget, QString p_identifier) -{ - QString filename = "courtroom_design.ini"; - - pos_size_type design_ini_result = - ao_app->get_element_dimensions(p_identifier, filename); - - if (design_ini_result.width < 0 || design_ini_result.height < 0) { - qDebug() << "W: could not find \"" << p_identifier << "\" in " << filename; - p_widget->hide(); - } - else { - p_widget->move(design_ini_result.x, design_ini_result.y); - p_widget->resize(design_ini_result.width, design_ini_result.height); - } -} - -QPoint Courtroom::get_theme_pos(QString p_identifier) -{ - QString filename = "courtroom_design.ini"; - - pos_size_type design_ini_result = - ao_app->get_element_dimensions(p_identifier, filename); - - if (design_ini_result.width < 0 || design_ini_result.height < 0) { - qDebug() << "W: could not find \"" << p_identifier << "\" in " << filename; - return QPoint(0, 0); - } - else { - return QPoint(design_ini_result.x, design_ini_result.y); - } -} - -void Courtroom::set_taken(int n_char, bool p_taken) -{ - if (n_char >= char_list.size()) { - qDebug() - << "W: set_taken attempted to set an index bigger than char_list size"; - return; - } - - char_type f_char; - f_char.name = char_list.at(n_char).name; - f_char.description = char_list.at(n_char).description; - f_char.taken = p_taken; - f_char.evidence_string = char_list.at(n_char).evidence_string; - - char_list.replace(n_char, f_char); -} - -void Courtroom::done_received() -{ - m_cid = -1; - - music_player->set_volume(0); - sfx_player->set_volume(0); - objection_player->set_volume(0); - blip_player->set_volume(0); - - set_char_select_page(); - - set_mute_list(); - set_pair_list(); - - set_char_select(); - - show(); - - ui_spectator->show(); -} - -void Courtroom::set_background(QString p_background) -{ - ui_vp_testimony->stop(); - - current_background = p_background; - - is_ao2_bg = file_exists(ao_app->get_background_path("defensedesk.png")) && - file_exists(ao_app->get_background_path("prosecutiondesk.png")) && - file_exists(ao_app->get_background_path("stand.png")); - - if (is_ao2_bg) { - set_size_and_pos(ui_vp_chatbox, "ao2_chatbox"); - set_size_and_pos(ui_ic_chat_message, "ao2_ic_chat_message"); - } - else { - set_size_and_pos(ui_vp_chatbox, "chatbox"); - set_size_and_pos(ui_ic_chat_message, "ic_chat_message"); - } -} - -void Courtroom::set_character(int char_id) -{ - m_cid = char_id; - - QString f_char; - - if (m_cid == -1) { - if (ao_app->is_discord_enabled()) - ao_app->discord->state_spectate(); - f_char = ""; - } - else { - f_char = ao_app->get_char_name(char_list.at(m_cid).name); - - if (ao_app->is_discord_enabled()) - ao_app->discord->state_character(f_char.toStdString()); - } - - current_char = f_char; - - current_emote_page = 0; - current_emote = 0; - - if (m_cid == -1) - ui_emotes->hide(); - else - ui_emotes->show(); - - set_emote_page(); - set_emote_dropdown(); - - if (ao_app->custom_objection_enabled && - (file_exists(ao_app->get_character_path(current_char, "custom.gif")) || - file_exists(ao_app->get_character_path(current_char, "custom.apng"))) && - file_exists(ao_app->get_character_path(current_char, "custom.wav"))) - ui_custom_objection->show(); - else - ui_custom_objection->hide(); -} - -void Courtroom::enter_courtroom(int p_cid) -{ - this->set_character(p_cid); - current_evidence_page = 0; - current_evidence = 0; - - set_evidence_page(); - - QString side = ao_app->get_char_side(current_char); - - // We block signals from ui_pos_dropdown to stop on_pos_dropdown_changed from - // firing here. Per the Qt docs, QSignalBlocker only affects the rest of this - // function, so it doesn't stop the dropdown from working once we finish here. - const QSignalBlocker blocker(ui_pos_dropdown); - ui_pos_dropdown->setCurrentText(side); - - if (side == "jud") { - - ui_witness_testimony->show(); - ui_cross_examination->show(); - ui_not_guilty->show(); - ui_guilty->show(); - ui_defense_minus->show(); - ui_defense_plus->show(); - ui_prosecution_minus->show(); - ui_prosecution_plus->show(); - } - else { - ui_witness_testimony->hide(); - ui_cross_examination->hide(); - ui_guilty->hide(); - ui_not_guilty->hide(); - ui_defense_minus->hide(); - ui_defense_plus->hide(); - ui_prosecution_minus->hide(); - ui_prosecution_plus->hide(); - } - - if (ao_app->custom_objection_enabled && // if setting is enabled - (file_exists(ao_app->get_image_suffix( - ao_app->get_character_path(current_char, "custom"))) && - file_exists(ao_app->get_character_path(current_char, "custom.wav")))) { - ui_custom_objection->show(); - if (dir_exists( - ao_app->get_character_path(current_char, "custom_objections"))) { - custom_obj_menu->clear(); - QDir directory( - ao_app->get_character_path(current_char, "custom_objections")); - QStringList custom_obj = directory.entryList(QStringList() << "*.gif" - << "*.apng", - QDir::Files); - for (const QString &filename : custom_obj) { - custom_obj_menu->addAction(filename); - } - } - } - else - ui_custom_objection->hide(); - - if (ao_app->flipping_enabled) - ui_flip->show(); - else - ui_flip->hide(); - - if (ao_app->casing_alerts_enabled) - ui_casing->show(); - else - ui_casing->hide(); - - list_music(); - list_areas(); - - music_player->set_volume(ui_music_slider->value()); - sfx_player->set_volume(ui_sfx_slider->value()); - objection_player->set_volume(ui_sfx_slider->value()); - misc_sfx_player->set_volume(ui_sfx_slider->value()); - frame_emote_sfx_player->set_volume(ui_sfx_slider->value()); - pair_frame_emote_sfx_player->set_volume(ui_sfx_slider->value()); - blip_player->set_volume(ui_blip_slider->value()); - - misc_sfx_player->set_volume(ui_sfx_slider->value()); - frame_emote_sfx_player->set_volume(ui_sfx_slider->value()); - pair_frame_emote_sfx_player->set_volume(ui_sfx_slider->value()); - - ui_vp_testimony->stop(); - - set_widgets(); - - // ui_server_chatlog->setHtml(ui_server_chatlog->toHtml()); - - ui_char_select_background->hide(); - - ui_ic_chat_message->setEnabled(m_cid != -1); - ui_ic_chat_message->setFocus(); -} - -void Courtroom::list_music() -{ - ui_music_list->clear(); - - QString f_file = "courtroom_design.ini"; - - QBrush found_brush(ao_app->get_color("found_song_color", f_file)); - QBrush missing_brush(ao_app->get_color("missing_song_color", f_file)); - - int n_listed_songs = 0; - - QTreeWidgetItem *parent = nullptr; - for (int n_song = 0; n_song < music_list.size(); ++n_song) { - QString i_song = music_list.at(n_song); - QString i_song_listname = i_song.left(i_song.lastIndexOf(".")); - i_song_listname = i_song_listname.right( - i_song_listname.length() - (i_song_listname.lastIndexOf("/") + 1)); - - QTreeWidgetItem *treeItem; - if (i_song_listname != i_song && parent != nullptr && - i_song.toLower().contains( - ui_music_search->text().toLower())) // not a category, parent exists - { - treeItem = new QTreeWidgetItem(parent); - treeItem->setText(0, i_song_listname); - treeItem->setText(1, i_song); - - QString song_path = ao_app->get_music_path(i_song); - - if (file_exists(song_path)) - treeItem->setBackground(0, found_brush); - else - treeItem->setBackground(0, missing_brush); - - if (i_song_listname == - i_song) // Not supposed to be a song to begin with - a category? - parent = treeItem; - ++n_listed_songs; - } - else if (i_song_listname == i_song) { - treeItem = new QTreeWidgetItem(ui_music_list); - treeItem->setText(0, i_song_listname); - treeItem->setText(1, i_song); - - QString song_path = ao_app->get_music_path(i_song); - - if (file_exists(song_path)) - treeItem->setBackground(0, found_brush); - else - treeItem->setBackground(0, missing_brush); - - if (i_song_listname == - i_song) // Not supposed to be a song to begin with - a category? - parent = treeItem; - ++n_listed_songs; - } - } - ui_music_list->expandAll(); // Needs to somehow remember which categories were - // expanded/collapsed if the music list didn't - // change since last time -} - -void Courtroom::list_areas() -{ - ui_area_list->clear(); - area_row_to_number.clear(); - - QString f_file = "courtroom_design.ini"; - - QBrush free_brush(ao_app->get_color("area_free_color", f_file)); - QBrush lfp_brush(ao_app->get_color("area_lfp_color", f_file)); - QBrush casing_brush(ao_app->get_color("area_casing_color", f_file)); - QBrush recess_brush(ao_app->get_color("area_recess_color", f_file)); - QBrush rp_brush(ao_app->get_color("area_rp_color", f_file)); - QBrush gaming_brush(ao_app->get_color("area_gaming_color", f_file)); - QBrush locked_brush(ao_app->get_color("area_locked_color", f_file)); - - int n_listed_areas = 0; - - for (int n_area = 0; n_area < area_list.size(); ++n_area) { - QString i_area = ""; - - // i_area.append("["); - // i_area.append(QString::number(n_area)); - // i_area.append("] "); - - i_area.append(area_list.at(n_area)); - - if (ao_app->arup_enabled) { - i_area.append("\n "); - - i_area.append(arup_statuses.at(n_area)); - i_area.append(" | CM: "); - i_area.append(arup_cms.at(n_area)); - - i_area.append("\n "); - - i_area.append(QString::number(arup_players.at(n_area))); - i_area.append(" users | "); - - i_area.append(arup_locks.at(n_area)); - } - - if (i_area.toLower().contains(ui_music_search->text().toLower())) { - ui_area_list->addItem(i_area); - area_row_to_number.append(n_area); - - if (ao_app->arup_enabled) { - // Colouring logic here. - ui_area_list->item(n_listed_areas)->setBackground(free_brush); - if (arup_locks.at(n_area) == "LOCKED") { - ui_area_list->item(n_listed_areas)->setBackground(locked_brush); - } - else { - if (arup_statuses.at(n_area) == "LOOKING-FOR-PLAYERS") - ui_area_list->item(n_listed_areas)->setBackground(lfp_brush); - else if (arup_statuses.at(n_area) == "CASING") - ui_area_list->item(n_listed_areas)->setBackground(casing_brush); - else if (arup_statuses.at(n_area) == "RECESS") - ui_area_list->item(n_listed_areas)->setBackground(recess_brush); - else if (arup_statuses.at(n_area) == "RP") - ui_area_list->item(n_listed_areas)->setBackground(rp_brush); - else if (arup_statuses.at(n_area) == "GAMING") - ui_area_list->item(n_listed_areas)->setBackground(gaming_brush); - } - } - else { - ui_area_list->item(n_listed_areas)->setBackground(free_brush); - } - - ++n_listed_areas; - } - } -} - -void Courtroom::append_ms_chatmessage(QString f_name, QString f_message) -{ - ui_ms_chatlog->append_chatmessage( - f_name, f_message, - ao_app->get_color("ooc_default_color", "courtroom_design.ini").name(), - false); -} - -void Courtroom::append_server_chatmessage(QString p_name, QString p_message, - QString p_colour) -{ - QString colour = "#000000"; - - if (p_colour == "0") - colour = - ao_app->get_color("ooc_default_color", "courtroom_design.ini").name(); - if (p_colour == "1") - - colour = - ao_app->get_color("ooc_server_color", "courtroom_design.ini").name(); - if (p_message == "Logged in as a moderator.") { - ui_guard->show(); - append_server_chatmessage( - "CLIENT", tr("You were granted the Disable Modcalls button."), "1"); - } - - ui_server_chatlog->append_chatmessage(p_name, p_message, colour, false); -} - -void Courtroom::detect_fallback_text() -{ - QString change_char_path = ao_app->get_theme_path("change_character.png"); - QString reload_theme_path = ao_app->get_theme_path("reload_theme.png"); - QString settings_path = ao_app->get_theme_path("settings.png"); - QString call_mod_path = ao_app->get_theme_path("call_mod.png"); - QString casing_path = ao_app->get_theme_path("casing.png"); - QString amswap_path = ao_app->get_theme_path("amswap.png"); - QString ooc_toggle_path = ao_app->get_theme_path("ooc_toggle_ms.png"); - - if (file_exists(change_char_path)) { - change_char_fallback = false; - } - else { - change_char_fallback = true; - } - if (file_exists(reload_theme_path)) { - reload_theme_fallback = false; - } - else { - reload_theme_fallback = true; - } - if (file_exists(settings_path)) { - settings_fallback = false; - } - else { - settings_fallback = true; - } - if (file_exists(call_mod_path)) { - call_mod_fallback = false; - } - else { - call_mod_fallback = true; - } - if (file_exists(casing_path)) { - casing_fallback = false; - } - else { - casing_fallback = true; - } - if (file_exists(amswap_path)) { - amswap_fallback = false; - } - else { - amswap_fallback = true; - } - if (file_exists(ooc_toggle_path)) { - ooc_toggle_fallback = false; - } - else { - ooc_toggle_fallback = true; - } -} - -class AOFrameThreadingPre : public QRunnable { -public: - Courtroom *thisCourtroom; - int my_frameNumber; - AOFrameThreadingPre(Courtroom *my_courtroom, int frameNumber) - { - thisCourtroom = my_courtroom; - my_frameNumber = frameNumber; - } - void run() - { - qDebug() << my_frameNumber << " FRAME NUMBER" - << " from" << QThread::currentThread(); - QString sfx_to_play = thisCourtroom->ao_app->get_frame_sfx_name( - thisCourtroom->current_char, - thisCourtroom->ao_app->get_pre_emote(thisCourtroom->current_char, - thisCourtroom->current_emote), - my_frameNumber); - QString screenshake_to_play = thisCourtroom->ao_app->get_screenshake_frame( - thisCourtroom->current_char, - thisCourtroom->ao_app->get_pre_emote(thisCourtroom->current_char, - thisCourtroom->current_emote), - my_frameNumber); - QString realization_to_play = thisCourtroom->ao_app->get_realization_frame( - thisCourtroom->current_char, - thisCourtroom->ao_app->get_pre_emote(thisCourtroom->current_char, - thisCourtroom->current_emote), - my_frameNumber); - if (sfx_to_play != "") { - thisCourtroom->threading_sfx += - "|" + QString::number(my_frameNumber) + "=" + sfx_to_play; - } - if (screenshake_to_play != "") { - thisCourtroom->threading_shake += - "|" + QString::number(my_frameNumber) + "=" + screenshake_to_play; - } - if (realization_to_play != "") { - thisCourtroom->threading_flash += - "|" + QString::number(my_frameNumber) + "=" + realization_to_play; - } - } -}; - -class AOFrameThreading : public QRunnable { -public: - Courtroom *thisCourtroom; - int my_frameNumber; - AOFrameThreading(Courtroom *my_courtroom, int frameNumber) - { - thisCourtroom = my_courtroom; - my_frameNumber = frameNumber; - } - void run() - { - QString sfx_to_play = thisCourtroom->ao_app->get_frame_sfx_name( - thisCourtroom->current_char, - thisCourtroom->threading_prefix + - thisCourtroom->ao_app->get_emote(thisCourtroom->current_char, - thisCourtroom->current_emote), - my_frameNumber); - QString screenshake_to_play = thisCourtroom->ao_app->get_screenshake_frame( - thisCourtroom->current_char, - thisCourtroom->threading_prefix + - thisCourtroom->ao_app->get_emote(thisCourtroom->current_char, - thisCourtroom->current_emote), - my_frameNumber); - QString realization_to_play = thisCourtroom->ao_app->get_realization_frame( - thisCourtroom->current_char, - thisCourtroom->threading_prefix + - thisCourtroom->ao_app->get_emote(thisCourtroom->current_char, - thisCourtroom->current_emote), - my_frameNumber); - if (sfx_to_play != "") { - thisCourtroom->threading_sfx += - "|" + QString::number(my_frameNumber) + "=" + sfx_to_play; - } - if (screenshake_to_play != "") { - thisCourtroom->threading_shake += - "|" + QString::number(my_frameNumber) + "=" + screenshake_to_play; - } - if (realization_to_play != "") { - thisCourtroom->threading_flash += - "|" + QString::number(my_frameNumber) + "=" + realization_to_play; - } - } -}; - -void Courtroom::on_chat_return_pressed() -{ - if (ui_ic_chat_message->text() == "" || is_muted) - return; - - if ((anim_state < 3 || text_state < 2) && objection_state == 0) - return; - - // MS# - // deskmod# - // pre-emote# - // character# - // emote# - // message# - // side# - // sfx-name# - // emote_modifier# - // char_id# - // sfx_delay# - // objection_modifier# - // evidence# - // placeholder# - // realization# - // text_color#% - - // Additionally, in our case: - - // showname# - // other_charid# - // self_offset# - // noninterrupting_preanim#% - - QStringList packet_contents; - - QString f_side = ao_app->get_char_side(current_char); - - QString f_desk_mod = "chat"; - - if (ao_app->desk_mod_enabled) { - f_desk_mod = - QString::number(ao_app->get_desk_mod(current_char, current_emote)); - if (f_desk_mod == "-1") - f_desk_mod = "chat"; - } - - packet_contents.append(f_desk_mod); - - packet_contents.append(ao_app->get_pre_emote(current_char, current_emote)); - - packet_contents.append(current_char); - - packet_contents.append(ao_app->get_emote(current_char, current_emote)); - - packet_contents.append(ui_ic_chat_message->text()); - - packet_contents.append(f_side); - - packet_contents.append(ao_app->get_sfx_name(current_char, current_emote)); - - int f_emote_mod = ao_app->get_emote_mod(current_char, current_emote); - - // needed or else legacy won't understand what we're saying - if (objection_state > 0) { - if (ui_pre->isChecked()) { - if (f_emote_mod == 5 || f_emote_mod == 4) - f_emote_mod = 6; - else - f_emote_mod = 2; - } - } - else if (ui_pre->isChecked() && !ui_pre_non_interrupt->isChecked()) { - if (f_emote_mod == 0) - f_emote_mod = 1; - else if (f_emote_mod == 5 && ao_app->prezoom_enabled) - f_emote_mod = 4; - } - else { - if (f_emote_mod == 1) - f_emote_mod = 0; - else if (f_emote_mod == 4) - f_emote_mod = 5; - } - - packet_contents.append(QString::number(f_emote_mod)); - packet_contents.append(QString::number(m_cid)); - - packet_contents.append( - QString::number(ao_app->get_sfx_delay(current_char, current_emote))); - - QString f_obj_state; - - if ((objection_state == 4 && !ao_app->custom_objection_enabled) || - (objection_state < 0)) - f_obj_state = "0"; - else if (objection_custom != "" && objection_state == 4) { - f_obj_state = QString::number(objection_state) + "&" + - objection_custom; // we add the name of the objection so the - // packet is like: 4&(name of custom obj) - } - else - f_obj_state = QString::number(objection_state); - packet_contents.append(f_obj_state); - if (is_presenting_evidence) - // the evidence index is shifted by 1 because 0 is no evidence per legacy - // standards besides, older clients crash if we pass -1 - packet_contents.append(QString::number(current_evidence + 1)); - else - packet_contents.append("0"); - - QString f_flip; - - if (ao_app->flipping_enabled) { - if (ui_flip->isChecked()) - f_flip = "1"; - else - f_flip = "0"; - } - else - f_flip = QString::number(m_cid); - - packet_contents.append(f_flip); - - packet_contents.append(QString::number(realization_state)); - - QString f_text_color; - - if (text_color < 0) - f_text_color = "0"; - else if (text_color > 8) - f_text_color = "0"; - else - f_text_color = QString::number(text_color); - - packet_contents.append(f_text_color); - - // If the server we're on supports CCCC stuff, we should use it! - if (ao_app->cccc_ic_support_enabled) { - // 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) { - packet_contents.append(QString::number(other_charid)); - packet_contents.append(QString::number(offset_with_pair)); - } - else { - packet_contents.append("-1"); - packet_contents.append("0"); - } - - // Finally, we send over if we want our pres to not interrupt. - if (ui_pre_non_interrupt->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_support_enabled) { - packet_contents.append( - ao_app->get_sfx_looping(current_char, current_emote)); - qDebug() << "Are we looping this? " - << ao_app->get_sfx_looping(current_char, current_emote); - packet_contents.append(QString::number(screenshake_state)); - qDebug() << "Are we screen shaking this one? " << screenshake_state; - qDebug() << "MAX THREAD COUNT " - << QThreadPool::globalInstance()->maxThreadCount(); - QString frame_screenshake = ""; - QString frame_realization = ""; - QString frame_sfx = ""; - - QString preemote_sfx = ""; - QString preemote_shake = ""; - QString preemote_flash = ""; - - QString talkemote_sfx = ""; - QString talkemote_shake = ""; - QString talkemote_flash = ""; - - QString idleemote_sfx = ""; - QString idleemote_shake = ""; - QString idleemote_flash = ""; - - QString preemote = ao_app->get_image_suffix(ao_app->get_character_path( - current_char, ao_app->get_pre_emote(current_char, current_emote))); - QString talkemote_to_check = - ao_app->get_image_suffix(ao_app->get_character_path( - current_char, - "(b)" + ao_app->get_emote(current_char, current_emote))); - QString idleemote_to_check = - ao_app->get_image_suffix(ao_app->get_character_path( - current_char, - "(a)" + ao_app->get_emote(current_char, current_emote))); - - frame_emote_checker = new QMovie(this); - frame_emote_checker->setFileName(preemote); - frame_emote_checker->jumpToFrame(0); - qDebug() << "Premote: " << frame_emote_checker->frameCount(); - - preemote_sfx += ao_app->get_pre_emote(current_char, current_emote); - preemote_shake += ao_app->get_pre_emote(current_char, current_emote); - preemote_flash += ao_app->get_pre_emote(current_char, current_emote); - - threading_sfx = preemote_sfx; - threading_shake = preemote_shake; - threading_flash = preemote_flash; - - for (int i = 0; i < frame_emote_checker->frameCount(); i++) { - AOFrameThreadingPre *frame_thread = new AOFrameThreadingPre(this, i); - QThreadPool::globalInstance()->start(frame_thread); - frame_thread->setAutoDelete(true); - } - QThreadPool::globalInstance()->waitForDone(); - preemote_sfx = threading_sfx; - preemote_shake = threading_shake; - preemote_flash = threading_flash; - preemote_sfx += "^"; - preemote_shake += "^"; - preemote_flash += "^"; - delete frame_emote_checker; - - talkemote_sfx += "(b)" + ao_app->get_emote(current_char, current_emote); - talkemote_shake += "(b)" + ao_app->get_emote(current_char, current_emote); - talkemote_flash += "(b)" + ao_app->get_emote(current_char, current_emote); - - frame_emote_checker = new QMovie(this); - frame_emote_checker->setFileName(talkemote_to_check); - frame_emote_checker->jumpToFrame(0); - qDebug() << "Talk: " << frame_emote_checker->frameCount(); - - threading_sfx = talkemote_sfx; - threading_shake = talkemote_shake; - threading_flash = talkemote_flash; - threading_prefix = QString("(b)"); - - for (int i = 0; i < frame_emote_checker->frameCount(); i++) { - AOFrameThreading *frame_thread = new AOFrameThreading(this, i); - QThreadPool::globalInstance()->start(frame_thread); - frame_thread->setAutoDelete(true); - } - QThreadPool::globalInstance()->waitForDone(); - - talkemote_sfx = threading_sfx; - talkemote_shake = threading_shake; - talkemote_flash = threading_flash; - talkemote_sfx += "^"; - talkemote_shake += "^"; - talkemote_flash += "^"; - delete frame_emote_checker; - - idleemote_sfx += "(a)" + ao_app->get_emote(current_char, current_emote); - idleemote_shake += "(a)" + ao_app->get_emote(current_char, current_emote); - idleemote_flash += "(a)" + ao_app->get_emote(current_char, current_emote); - - frame_emote_checker = new QMovie(this); - frame_emote_checker->setFileName(idleemote_to_check); - frame_emote_checker->jumpToFrame(0); - qDebug() << "idle: " << frame_emote_checker->frameCount(); - - threading_sfx = idleemote_sfx; - threading_shake = idleemote_shake; - threading_flash = idleemote_flash; - threading_prefix = QString("(a)"); - for (int i = 0; i < frame_emote_checker->frameCount(); i++) { - AOFrameThreading *frame_thread = new AOFrameThreading(this, i); - QThreadPool::globalInstance()->start(frame_thread); - frame_thread->setAutoDelete(true); - } - QThreadPool::globalInstance()->waitForDone(); - idleemote_sfx = threading_sfx; - idleemote_shake = threading_shake; - idleemote_flash = threading_flash; - delete frame_emote_checker; - - frame_screenshake += preemote_shake; - frame_screenshake += talkemote_shake; - frame_screenshake += idleemote_shake; - - frame_realization += preemote_flash; - frame_realization += talkemote_flash; - frame_realization += idleemote_flash; - - frame_sfx += preemote_sfx; - frame_sfx += talkemote_sfx; - frame_sfx += idleemote_sfx; - - packet_contents.append(frame_screenshake); - packet_contents.append(frame_realization); - packet_contents.append(frame_sfx); - } // Honestly this is a copy paste dump and I have no idea what this does. If - // this breaks blame aov thanks - ao_app->send_server_packet(new AOPacket("MS", packet_contents)); -} -void Courtroom::handle_chatmessage(QStringList *p_contents) -{ - // Instead of checking for whether a message has at least chatmessage_size - // amount of packages, we'll check if it has at least 15. - // That was the original chatmessage_size. - if (p_contents->size() < 15) - return; - - for (int n_string = 0; n_string < chatmessage_size; ++n_string) { - // m_chatmessage[n_string] = p_contents->at(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 < 15 || ao_app->cccc_ic_support_enabled)) { - m_chatmessage[n_string] = p_contents->at(n_string); - } - else { - m_chatmessage[n_string] = ""; - } - } - - int f_char_id = m_chatmessage[CHAR_ID].toInt(); - - if (f_char_id < 0 || f_char_id >= char_list.size()) - return; - - if (mute_map.value(m_chatmessage[CHAR_ID].toInt())) - return; - - QString f_showname; - if (m_chatmessage[SHOWNAME].isEmpty() || !ui_showname_enable->isChecked()) { - f_showname = ao_app->get_showname(char_list.at(f_char_id).name); - } - else { - f_showname = m_chatmessage[SHOWNAME]; - } - - QString f_message = f_showname + ": " + m_chatmessage[MESSAGE] + '\n'; - - if (f_message == previous_ic_message) - return; - - text_state = 0; - anim_state = 0; - ui_vp_objection->stop(); - // ui_vp_player_char->stop(); - chat_tick_timer->stop(); - if (!keep_evidence_display) - ui_vp_evidence_display->reset(); - - chatmessage_is_empty = - m_chatmessage[MESSAGE] == " " || m_chatmessage[MESSAGE] == ""; - if (m_chatmessage[MESSAGE] == ui_ic_chat_message->text() && - m_chatmessage[CHAR_ID].toInt() == m_cid) { - ui_ic_chat_message->clear(); - objection_state = 0; - objection_custom = ""; - char_name = m_chatmessage[CHAR_NAME]; - realization_state = 0; - screenshake_state = 0; - is_presenting_evidence = false; - ui_pre->setChecked(false); - ui_hold_it->set_image("holdit.png"); - ui_objection->set_image("objection.png"); - ui_take_that->set_image("takethat.png"); - ui_custom_objection->set_image("custom.png"); - ui_realization->set_image("realization.png"); - ui_screenshake->set_image("screenshake.png"); - ui_evidence_present->set_image("present_disabled.png"); - ui_screenshake->set_image("screenshake.png"); - } - - QString tmpmsg = ""; - chatlogpiece *temp = new chatlogpiece( - ao_app->get_showname(char_list.at(f_char_id).name), f_showname, - ": " + m_chatmessage[MESSAGE], false, m_chatmessage[TEXT_COLOR].toInt()); - - ic_chatlog_history.append(*temp); - - while (ic_chatlog_history.size() > log_maximum_blocks && - log_maximum_blocks > 0) { - ic_chatlog_history.removeFirst(); - } - refresh_iclog(true); - - if (f_showname == "") - f_showname = m_chatmessage[CHAR_NAME]; - if (!mirror_iclog) - append_ic_text(": " + m_chatmessage[MESSAGE], f_showname, false, true, - false, m_chatmessage[TEXT_COLOR].toInt()); - - previous_ic_message = f_message; - bool ok; - int objection_mod = m_chatmessage[OBJECTION_MOD].toInt( - &ok, 10); // checks if its a custom obj. - QString custom_objection = ""; - if (!ok && m_chatmessage[OBJECTION_MOD].contains("4&")) { - objection_mod = 4; - custom_objection = m_chatmessage[OBJECTION_MOD].split( - "4&")[1]; // takes the name of custom objection. - } - QString f_char = char_name; - f_char = m_chatmessage[CHAR_NAME]; - QString f_custom_theme = ao_app->get_char_shouts(f_char); - ui_vp_message->clear(); - ui_vp_chatbox->hide(); - // if an objection is used - if (objection_mod <= 4 && objection_mod >= 1) { - - switch (objection_mod) { - case 1: - ui_vp_objection->play("holdit", f_char, f_custom_theme, shout_stay_time); - objection_player->play("holdit.wav", f_char, f_custom_theme); - break; - case 2: - ui_vp_objection->play("objection", f_char, f_custom_theme, - shout_stay_time); - objection_player->play("objection.wav", f_char, f_custom_theme); - if (ao_app->get_objectmusic()) - music_player->kill_loop(); - break; - case 3: - ui_vp_objection->play("takethat", f_char, f_custom_theme, - shout_stay_time); - objection_player->play("takethat.wav", f_char, f_custom_theme); - break; - // case 4 is AO2 only - case 4: - if (custom_objection != "") { - ui_vp_objection->play("custom_objections/" + custom_objection, f_char, - f_custom_theme, shout_stay_time); - objection_player->play("custom_objections/" + - custom_objection.split('.')[0] + ".wav", - f_char, f_custom_theme); - } - else { - ui_vp_objection->play("custom", f_char, f_custom_theme, - shout_stay_time); - objection_player->play("custom.wav", f_char, f_custom_theme); - } - break; - default: - qDebug() << "W: Logic error in objection switch statement!"; - } - - int emote_mod = m_chatmessage[EMOTE_MOD].toInt(); - - if (emote_mod == 0) - m_chatmessage[EMOTE_MOD] = 1; - } - else { - handle_chatmessage_2(); - } -} - -void Courtroom::objection_done() { handle_chatmessage_2(); } - -void Courtroom::handle_chatmessage_2() -{ - ui_vp_speedlines->stop(); - // ui_vp_player_char->stop(); - ui_vp_player_char->frame_sfx_hellstring = m_chatmessage[FRAME_SFX]; - ui_vp_player_char->frame_realization_hellstring = - m_chatmessage[FRAME_REALIZATION]; - ui_vp_player_char->frame_screenshake_hellstring = - m_chatmessage[FRAME_SCREENSHAKE]; - ui_vp_player_char->use_networked_framehell = true; - if (m_chatmessage[SHOWNAME].isEmpty() || !ui_showname_enable->isChecked()) { - QString real_name = char_list.at(m_chatmessage[CHAR_ID].toInt()).name; - - QString f_showname = ao_app->get_showname(m_chatmessage[CHAR_NAME]); - - ui_vp_showname->setText(f_showname); - } - - else { - ui_vp_showname->setText(m_chatmessage[SHOWNAME]); - } - - QString f_char = m_chatmessage[CHAR_NAME]; - QString chatbox = ao_app->get_chat(f_char); - - if (chatbox == "") { - ui_vp_chatbox->set_image("chatmed.png"); - } - else { - QString chatbox_path; - QString misc_path = - ao_app->get_base_path() + "misc/" + chatbox + "/chatbox.png"; - // support for 2.4 legacy chatboxes - QString legacy_path = ao_app->get_base_path() + "misc/" + chatbox + ".png"; - if (file_exists(misc_path)) { - chatbox_path = misc_path; - } - else if (file_exists(legacy_path)) - chatbox_path = legacy_path; - else { - QString default_chatbox_path = ao_app->get_theme_path("chatmed.png"); - chatbox_path = default_chatbox_path; - } - ui_vp_chatbox->set_image_from_path(chatbox_path); - } - - ui_vp_showname->setStyleSheet( - "QLabel { color : " + get_text_color("_showname").name() + "; }"); - - set_scene(); - set_text_color(); - - // Check if the message needs to be centered. - QString f_message = m_chatmessage[MESSAGE]; - if (f_message.size() >= 2) { - if (f_message.startsWith("~~")) { - message_is_centered = true; - } - else { - message_is_centered = false; - } - } - else { - ui_vp_message->setAlignment(Qt::AlignLeft); - } - - int emote_mod = m_chatmessage[EMOTE_MOD].toInt(); - - if (ao_app->flipping_enabled && m_chatmessage[FLIP].toInt() == 1) - ui_vp_player_char->set_flipped(true); - else - ui_vp_player_char->set_flipped(false); - - QString side = m_chatmessage[SIDE]; - if (side != "wit") - ui_vp_testimony->stop(); - - // Making the second character appear. - if (m_chatmessage[OTHER_CHARID].isEmpty()) { - // If there is no second character, hide 'em, and center the first. - ui_vp_sideplayer_char->hide(); - ui_vp_sideplayer_char->move(0, 0); - - ui_vp_player_char->move(0, 0); - } - else { - bool ok; - int got_other_charid = m_chatmessage[OTHER_CHARID].toInt(&ok); - if (ok) { - if (got_other_charid > -1) { - // If there is, show them! - ui_vp_sideplayer_char->show(); - - // Depending on where we are, we offset the characters, and reorder - // their stacking. - if (side == "def") { - - // We also move the character down depending on how far the are to the - // right. - int hor_offset = m_chatmessage[SELF_OFFSET].toInt(); - int vert_offset = 0; - if (hor_offset > 0) { - vert_offset = hor_offset / 10; - } - ui_vp_player_char->move(ui_viewport->width() * hor_offset / 100, - ui_viewport->height() * vert_offset / 100); - - // We do the same with the second character. - int hor2_offset = m_chatmessage[OTHER_OFFSET].toInt(); - int vert2_offset = 0; - if (hor2_offset > 0) { - vert2_offset = hor2_offset / 10; - } - ui_vp_sideplayer_char->move(ui_viewport->width() * hor2_offset / 100, - ui_viewport->height() * vert2_offset / - 100); - - // Finally, we reorder them based on who is more to the left. - // The person more to the left is more in the front. - if (hor2_offset >= hor_offset) { - ui_vp_sideplayer_char->raise(); - ui_vp_player_char->raise(); - } - else { - ui_vp_player_char->raise(); - ui_vp_sideplayer_char->raise(); - } - ui_vp_desk->raise(); - ui_vp_legacy_desk->raise(); - } - else if (side == "pro") { - // Almost the same thing happens here, but in reverse. - int hor_offset = m_chatmessage[SELF_OFFSET].toInt(); - int vert_offset = 0; - if (hor_offset < 0) { - // We don't want to RAISE the char off the floor. - vert_offset = -1 * hor_offset / 10; - } - ui_vp_player_char->move(ui_viewport->width() * hor_offset / 100, - ui_viewport->height() * vert_offset / 100); - - // We do the same with the second character. - int hor2_offset = m_chatmessage[OTHER_OFFSET].toInt(); - int vert2_offset = 0; - if (hor2_offset < 0) { - vert2_offset = -1 * hor2_offset / 10; - } - ui_vp_sideplayer_char->move(ui_viewport->width() * hor2_offset / 100, - ui_viewport->height() * vert2_offset / - 100); - - // Finally, we reorder them based on who is more to the right. - if (hor2_offset <= hor_offset) { - ui_vp_sideplayer_char->raise(); - ui_vp_player_char->raise(); - } - else { - ui_vp_player_char->raise(); - ui_vp_sideplayer_char->raise(); - } - ui_vp_desk->raise(); - ui_vp_legacy_desk->raise(); - } - else { - // In every other case, the person more to the left is on top. - // These cases also don't move the characters down. - int hor_offset = m_chatmessage[SELF_OFFSET].toInt(); - ui_vp_player_char->move(ui_viewport->width() * hor_offset / 100, 0); - - // We do the same with the second character. - int hor2_offset = m_chatmessage[OTHER_OFFSET].toInt(); - ui_vp_sideplayer_char->move(ui_viewport->width() * hor2_offset / 100, - 0); - - // Finally, we reorder them based on who is more to the left. - // The person more to the left is more in the front. - if (hor2_offset >= hor_offset) { - ui_vp_sideplayer_char->raise(); - ui_vp_player_char->raise(); - } - else { - ui_vp_player_char->raise(); - ui_vp_sideplayer_char->raise(); - } - ui_vp_desk->raise(); - ui_vp_legacy_desk->raise(); - } - // We should probably also play the other character's idle emote. - if (ao_app->flipping_enabled && m_chatmessage[OTHER_FLIP].toInt() == 1) - ui_vp_sideplayer_char->set_flipped(true); - else - ui_vp_sideplayer_char->set_flipped(false); - ui_vp_sideplayer_char->play_idle(m_chatmessage[OTHER_NAME], - m_chatmessage[OTHER_EMOTE]); - ui_vp_sideplayer_char->use_networked_framehell = false; - } - else { - // If the server understands other characters, but there - // really is no second character, hide 'em, and center the first. - ui_vp_sideplayer_char->hide(); - ui_vp_sideplayer_char->stop(); - ui_vp_sideplayer_char->move(0, 0); - - ui_vp_player_char->move(0, 0); - } - } - } - if (m_chatmessage[SCREENSHAKE] == "1") { - this->doScreenShake(); - } - switch (emote_mod) { - case 1: - case 2: - case 6: - play_preanim(false); - break; - case 0: - case 5: - if (m_chatmessage[NONINTERRUPTING_PRE].toInt() == 0) - handle_chatmessage_3(); - else { - - play_preanim(true); - } - break; - default: - qDebug() << "W: invalid emote mod: " << QString::number(emote_mod); - } -} -void Courtroom::realization_done() { ui_vp_realization->hide(); } - -void Courtroom::doScreenShake() -{ - if (!ao_app->is_shakeandflash_enabled()) - return; - screenshake_group = new QParallelAnimationGroup; - screenshake_animation = new QPropertyAnimation(ui_viewport, "pos", this); - chatbox_screenshake_animation = - new QPropertyAnimation(ui_vp_chatbox, "pos", this); - int screen_x = get_theme_pos("viewport").x(); - int screen_y = get_theme_pos("viewport").y(); - QPoint pos_default = QPoint(screen_x, screen_y); - QPoint pos1 = QPoint(screen_x + 3, screen_y + -5); - QPoint pos2 = QPoint(screen_x + 3, screen_y + -5); - QPoint pos3 = QPoint(screen_x + -3, screen_y + 5); - QPoint pos4 = QPoint(screen_x + 3, screen_y + -5); - QPoint pos5 = QPoint(screen_x + -3, screen_y + -5); - - int chatbox_x = get_theme_pos("ao2_chatbox").x(); - int chatbox_y = get_theme_pos("ao2_chatbox").y(); - QPoint chatbox_pos_default = QPoint(chatbox_x, chatbox_y); - QPoint chatbox_pos1 = QPoint(chatbox_x + 3, chatbox_y + -5); - QPoint chatbox_pos2 = QPoint(chatbox_x + 3, chatbox_y + -5); - QPoint chatbox_pos3 = QPoint(chatbox_x + -3, chatbox_y + 5); - QPoint chatbox_pos4 = QPoint(chatbox_x + 3, chatbox_y + -5); - QPoint chatbox_pos5 = QPoint(chatbox_x + -3, chatbox_y + -5); - - screenshake_animation->setDuration(200); - screenshake_animation->setKeyValueAt(0, pos_default); - screenshake_animation->setKeyValueAt(0.1, pos1); - screenshake_animation->setKeyValueAt(0.3, pos2); - screenshake_animation->setKeyValueAt(0.5, pos3); - screenshake_animation->setKeyValueAt(0.7, pos4); - screenshake_animation->setKeyValueAt(0.9, pos5); - screenshake_animation->setEndValue(pos_default); - screenshake_animation->setEasingCurve(QEasingCurve::Linear); - chatbox_screenshake_animation->setDuration(200); - chatbox_screenshake_animation->setKeyValueAt(0, chatbox_pos_default); - chatbox_screenshake_animation->setKeyValueAt(0.1, chatbox_pos3); - chatbox_screenshake_animation->setKeyValueAt(0.3, chatbox_pos5); - chatbox_screenshake_animation->setKeyValueAt(0.5, chatbox_pos2); - chatbox_screenshake_animation->setKeyValueAt(0.7, chatbox_pos1); - chatbox_screenshake_animation->setKeyValueAt(0.9, chatbox_pos4); - chatbox_screenshake_animation->setEndValue(chatbox_pos_default); - chatbox_screenshake_animation->setEasingCurve(QEasingCurve::Linear); - - screenshake_group->addAnimation(screenshake_animation); - screenshake_group->addAnimation(chatbox_screenshake_animation); - screenshake_group->start( - QAbstractAnimation::DeletionPolicy::DeleteWhenStopped); -} - -void Courtroom::handle_chatmessage_3() -{ - if (!log_goes_downwards && mirror_iclog) - ui_ic_chatlog->moveCursor(QTextCursor::Start); - else if (mirror_iclog) - ui_ic_chatlog->moveCursor(QTextCursor::End); - - ui_ic_chatlog->setTextInteractionFlags(Qt::TextSelectableByMouse); - - if (mirror_iclog) { - if (!ui_showname_enable->isChecked() || m_chatmessage[SHOWNAME] == "") { - if (first_message_sent && log_goes_downwards) - ui_ic_chatlog->textCursor().insertHtml("
    "); - else - first_message_sent = true; - QString char_name = char_list.at(m_chatmessage[CHAR_ID].toInt()).name; - ui_ic_chatlog->textCursor().insertHtml("" + char_name + - ": "); - } - else { - if (first_message_sent && log_goes_downwards) - ui_ic_chatlog->textCursor().insertHtml("
    "); - else - first_message_sent = true; - - ui_ic_chatlog->textCursor().insertHtml("" + m_chatmessage[SHOWNAME] + - ": "); - } - - QScrollBar *scroll = ui_vp_message->verticalScrollBar(); - scroll->setValue(scroll->maximum()); - if (chatmessage_is_empty && log_goes_downwards) { - ui_ic_chatlog->moveCursor(QTextCursor::End); - } - } - start_chat_ticking(); - int f_evi_id = m_chatmessage[EVIDENCE_ID].toInt(); - QString f_side = m_chatmessage[SIDE]; - - if (f_evi_id > 0 && f_evi_id <= local_evidence_list.size()) { - // shifted by 1 because 0 is no evidence per legacy standards - QString f_image = local_evidence_list.at(f_evi_id - 1).image; - // def jud and hlp should display the evidence icon on the RIGHT side - bool is_left_side = !(f_side == "def" || f_side == "hlp" || - f_side == "jud" || f_side == "jur"); - ui_vp_evidence_display->show_evidence(f_image, is_left_side, - ui_sfx_slider->value()); - } - - int emote_mod = m_chatmessage[EMOTE_MOD].toInt(); - - QString side = m_chatmessage[SIDE]; - - if (emote_mod == 5 || emote_mod == 6) { - ui_vp_desk->hide(); - ui_vp_legacy_desk->hide(); - - // Since we're zooming, hide the second character, and centre the first. - ui_vp_sideplayer_char->hide(); - ui_vp_player_char->move(0, 0); - - if (side == "pro" || side == "hlp" || side == "wit") - ui_vp_speedlines->play("prosecution_speedlines"); - else - ui_vp_speedlines->play("defense_speedlines"); - } - - int f_anim_state = 0; - // BLUE is from an enum in datatypes.h - bool text_is_blue = m_chatmessage[TEXT_COLOR].toInt() == BLUE; - - if (!text_is_blue && text_state == 1) { - // talking - f_anim_state = 2; - entire_message_is_blue = false; - } - else { - // idle - f_anim_state = 3; - entire_message_is_blue = true; - } - - if (f_anim_state <= anim_state) - return; - - ui_vp_player_char->stop(); - - QString f_char = ""; - f_char = m_chatmessage[CHAR_NAME]; - QString f_emote = m_chatmessage[EMOTE]; - - if (f_anim_state == 2) { - ui_vp_player_char->play_talking(f_char, f_emote); - anim_state = 2; - } - else { - ui_vp_player_char->play_idle(f_char, f_emote); - anim_state = 3; - } - - QString f_message = m_chatmessage[MESSAGE]; - QStringList call_words = ao_app->get_call_words(); - - for (QString word : call_words) { - if (f_message.contains(word, Qt::CaseInsensitive)) { - modcall_player->play(ao_app->get_sfx("word_call")); - ao_app->alert(this); - - break; - } - } -} - -QString Courtroom::filter_ic_text(QString p_text, bool skip_filter, - int chat_color) -{ - // BMKCOMMENT - // Get rid of centering. - if (p_text.startsWith(": ~~")) { - // Don't forget, the p_text part actually everything after the name! - // Hence why we check for ': ~~'. - - // Let's remove those two tildes, then. - // : _ ~ ~ - // 0 1 2 3 - p_text.remove(2, 2); - } - - // Get rid of the inline-colouring. - // I know, I know, excessive code duplication. - // Nobody looks in here, I'm fine. - int trick_check_pos = 1; - bool ic_next_is_not_special = false; - QString f_character = p_text.at(trick_check_pos); - std::stack ic_colour_stack; - QString final_text = ": "; - bool delay_pop = false; - while (trick_check_pos < p_text.size()) { - f_character = p_text.at(trick_check_pos); - if (!skip_filter) { - if (f_character == "<") - f_character = "<"; - else if (f_character == ">") - f_character = ">"; - } - // Escape character. - if (f_character == "\\" && !ic_next_is_not_special) { - ic_next_is_not_special = true; - p_text.remove(trick_check_pos, 1); - f_character = ""; - if (p_text[trick_check_pos] == 'n') { - p_text[trick_check_pos] = ' '; - f_character = " "; - } - } - - // Text speed modifier. - else if ((f_character == "{" || f_character == "}") && - !ic_next_is_not_special) { - p_text.remove(trick_check_pos, 1); - f_character = ""; - } - else if (f_character == "$" && !ic_next_is_not_special) { - p_text.remove(trick_check_pos, 1); - f_character = ""; - } - else if (f_character == "@" && !ic_next_is_not_special) { - p_text.remove(trick_check_pos, 1); - f_character = ""; - } - - // Orange inline colourisation. - else if (f_character == "|" && !ic_next_is_not_special) { - if (!ic_colour_stack.empty()) { - if (ic_colour_stack.top() == INLINE_ORANGE) { - ic_colour_stack.pop(); - p_text.remove(trick_check_pos, 1); - } - else { - ic_colour_stack.push(INLINE_ORANGE); - p_text.remove(trick_check_pos, 1); - } - } - else { - ic_colour_stack.push(INLINE_ORANGE); - p_text.remove(trick_check_pos, 1); - } - f_character = ""; - } - - // Blue inline colourisation. - else if (f_character == "(" && !ic_next_is_not_special) { - ic_colour_stack.push(INLINE_BLUE); - if (!colorf_iclog) - trick_check_pos++; - } - else if (f_character == ")" && !ic_next_is_not_special && - !ic_colour_stack.empty()) { - if (ic_colour_stack.top() == INLINE_BLUE) { - // ic_colour_stack.pop(); - delay_pop = true; - if (!colorf_iclog) - trick_check_pos++; - } - else { - ic_next_is_not_special = true; - } - } - - // Grey inline colourisation. - else if (f_character == "[" && !ic_next_is_not_special) { - ic_colour_stack.push(INLINE_GREY); - if (!colorf_iclog) - trick_check_pos++; - } - else if (f_character == "]" && !ic_next_is_not_special && - !ic_colour_stack.empty()) { - if (ic_colour_stack.top() == INLINE_GREY) { - // ic_colour_stack.pop(); - delay_pop = true; - if (!colorf_iclog) - trick_check_pos++; - } - else { - ic_next_is_not_special = true; - } - } - - // Green inline colourisation. - else if (f_character == "`" && !ic_next_is_not_special) { - if (!ic_colour_stack.empty()) { - if (ic_colour_stack.top() == INLINE_GREEN) { - ic_colour_stack.pop(); - p_text.remove(trick_check_pos, 1); - } - else { - ic_colour_stack.push(INLINE_GREEN); - p_text.remove(trick_check_pos, 1); - } - } - else { - ic_colour_stack.push(INLINE_GREEN); - p_text.remove(trick_check_pos, 1); - } - f_character = ""; - } - - if (colorf_iclog && f_character != "") { - ic_next_is_not_special = false; - if (!ic_colour_stack.empty()) { - // p_text.remove(trick_check_pos,1); - trick_check_pos++; - switch (ic_colour_stack.top()) { - case INLINE_ORANGE: - final_text += "" + - f_character + ""; - break; - case INLINE_BLUE: - final_text += "" + - f_character + ""; - break; - case INLINE_GREEN: - final_text += "" + - f_character + ""; - break; - case INLINE_GREY: - final_text += "" + - f_character + ""; - break; - } - if (delay_pop) { - ic_colour_stack.pop(); - delay_pop = false; - } - } - else if (!(chat_color == WHITE || chat_color == RAINBOW) && - !colorf_limit) { - trick_check_pos++; - QString html_color; - switch (chat_color) { - case 1: - html_color = get_text_color(QString::number(GREEN)).name(); - break; - case 2: - html_color = get_text_color(QString::number(RED)).name(); - break; - case 3: - html_color = get_text_color(QString::number(ORANGE)).name(); - break; - case 4: - html_color = get_text_color(QString::number(BLUE)).name(); - break; - case 5: - html_color = get_text_color(QString::number(YELLOW)).name(); - break; - case 7: - html_color = get_text_color(QString::number(PINK)).name(); - break; - case 8: - html_color = get_text_color(QString::number(CYAN)).name(); - break; - } - final_text += - "" + f_character + ""; - } - else if (chat_color == RAINBOW && !colorf_limit) { - QString html_color; - - switch (rainbow_counter) { - case 0: - html_color = get_text_color(QString::number(RED)).name(); - break; - case 1: - html_color = get_text_color(QString::number(ORANGE)).name(); - break; - case 2: - html_color = get_text_color(QString::number(YELLOW)).name(); - break; - case 3: - html_color = get_text_color(QString::number(GREEN)).name(); - break; - default: - html_color = get_text_color(QString::number(BLUE)).name(); - rainbow_counter = -1; - } - - ++rainbow_counter; - final_text += - "" + f_character + ""; - trick_check_pos++; - } - - else { - final_text += f_character; - trick_check_pos++; - } - } - else if (f_character != "") { - trick_check_pos++; - } - } - - if (colorf_iclog) - return final_text; - else { - return p_text; - } -} -/* - * Appends text to the ic log. - * \param p_text The text to be appended - * \param p_name The name of the character/entity who sent said text - * \param is_songchange Whether we are appending a song entry - * \param force_filter If we are sending plain text and we want to force the - * \param filtering regardless of its status (e.g chat entry, song change etc) - * \param skip_filter If we are sending appending text such as html so we skip the - * \param filter chat_color The color of the message sent - */ - -void Courtroom::append_ic_text(QString p_text, QString p_name, - bool is_songchange, bool force_filter, - bool skip_filter, int chat_color) -{ - - QTextCharFormat bold; - QTextCharFormat normal; - QTextCharFormat italics; - bold.setFontWeight(QFont::Bold); - normal.setFontWeight(QFont::Normal); - italics.setFontItalic(true); - const QTextCursor old_cursor = ui_ic_chatlog->textCursor(); - const int old_scrollbar_value = ui_ic_chatlog->verticalScrollBar()->value(); - - if ((!is_songchange && !mirror_iclog) || force_filter) - p_text = filter_ic_text(p_text, skip_filter, chat_color); - - if (log_goes_downwards) { - const bool is_scrolled_down = - old_scrollbar_value == ui_ic_chatlog->verticalScrollBar()->maximum(); - - ui_ic_chatlog->moveCursor(QTextCursor::End); - if (!(is_songchange && mirror_iclog)) { - // The only case where no new log entry should be made is when there is a - // music entry while mirror log is active This is to protect the log, as - // if there is a songchange during a new message being typed, then they - // will destructively interfere with eachother - - // If the first message hasn't been sent, and we are handling basic - // text, we put the name without the newline. - if (!first_message_sent) - ui_ic_chatlog->textCursor().insertText(p_name, bold); - - else if (force_filter || is_songchange || !mirror_iclog) { - // Otherwise we just add the plaintext with the new line. - ui_ic_chatlog->textCursor().insertText('\n' + p_name, bold); - } - first_message_sent = true; - - if (is_songchange) { - // If its a song with mirror mode enabled, we do not need to repeat it - // as it is already shown in the ooc. - ui_ic_chatlog->textCursor().insertText(" has played a song: ", normal); - ui_ic_chatlog->textCursor().insertText(p_text + ".", italics); - } - - else if (colorf_iclog && (!mirror_iclog || force_filter)) { - // if we are handling already formatted text and we have enabled colors - // in the iclog, then we insert the text - ui_ic_chatlog->textCursor().insertHtml(p_text); - } - - else if ((!colorf_iclog && !mirror_iclog) || force_filter) { - // If html is not enabled then we insert it as plain text. - ui_ic_chatlog->textCursor().insertText(p_text, normal); - } - } - // If we got too many blocks in the current log, delete some from the top. - while (ui_ic_chatlog->document()->blockCount() > log_maximum_blocks && - log_maximum_blocks > 0) { - ui_ic_chatlog->moveCursor(QTextCursor::Start); - ui_ic_chatlog->textCursor().select(QTextCursor::BlockUnderCursor); - ui_ic_chatlog->textCursor().removeSelectedText(); - ui_ic_chatlog->textCursor().deleteChar(); - // qDebug() << ui_ic_chatlog->document()->blockCount() << " < " << - // log_maximum_blocks; - } - - if (old_cursor.hasSelection() || !is_scrolled_down) { - // The user has selected text or scrolled away from the bottom: maintain - // position. - ui_ic_chatlog->setTextCursor(old_cursor); - ui_ic_chatlog->verticalScrollBar()->setValue(old_scrollbar_value); - } - else { - // The user hasn't selected any text and the scrollbar is at the bottom: - // scroll to the bottom. - ui_ic_chatlog->moveCursor(QTextCursor::End); - ui_ic_chatlog->verticalScrollBar()->setValue( - ui_ic_chatlog->verticalScrollBar()->maximum()); - } - } - else { - const bool is_scrolled_up = - old_scrollbar_value == ui_ic_chatlog->verticalScrollBar()->minimum(); - - ui_ic_chatlog->moveCursor(QTextCursor::Start); - if (!(is_songchange && mirror_iclog)) { - // The only case where no new log entry should be made is when there is a - // music entry while mirror log is active This is to protect the log, as - // if there is a songchange during a new message being typed, then they - // will destructively interfere with eachother - - if ((force_filter || !mirror_iclog || is_songchange)) { - - if (mirror_iclog) - // If mirror is enabled we need to make space on the top so the text - // can be inserted without any interuptions If mirror mode is not - // enabled, then we do not need to clear out the top line as the new - // entry pushes it automatically down. - p_name = '\n' + p_name; - - if (!first_message_sent) - first_message_sent = true; - - ui_ic_chatlog->textCursor().insertText(p_name, bold); - } - - if (is_songchange) { - ui_ic_chatlog->textCursor().insertText(" has played a song: ", normal); - ui_ic_chatlog->textCursor().insertText(p_text + "." + '\n', italics); - } - - else if (colorf_iclog && (!mirror_iclog || force_filter)) { - ui_ic_chatlog->textCursor().insertHtml(p_text); - } - else if ((!colorf_iclog && !mirror_iclog) || force_filter) { - ui_ic_chatlog->textCursor().insertText(p_text, normal); - } - if (!mirror_iclog) - ui_ic_chatlog->textCursor().insertHtml("
    "); - } - // If we got too many blocks in the current log, delete some from the - // bottom. - while (ui_ic_chatlog->document()->blockCount() > log_maximum_blocks && - log_maximum_blocks > 0) { - ui_ic_chatlog->moveCursor(QTextCursor::End); - ui_ic_chatlog->textCursor().select(QTextCursor::BlockUnderCursor); - ui_ic_chatlog->textCursor().removeSelectedText(); - ui_ic_chatlog->textCursor().deletePreviousChar(); - // qDebug() << ui_ic_chatlog->document()->blockCount() << " < " << - // log_maximum_blocks; - } - - if (old_cursor.hasSelection() || !is_scrolled_up) { - // The user has selected text or scrolled away from the top: maintain - // position. - ui_ic_chatlog->setTextCursor(old_cursor); - ui_ic_chatlog->verticalScrollBar()->setValue(old_scrollbar_value); - } - else { - // The user hasn't selected any text and the scrollbar is at the top: - // scroll to the top. - ui_ic_chatlog->moveCursor(QTextCursor::Start); - ui_ic_chatlog->verticalScrollBar()->setValue( - ui_ic_chatlog->verticalScrollBar()->minimum()); - } - } -} - -void Courtroom::play_preanim(bool noninterrupting) -{ - QString f_char = m_chatmessage[CHAR_NAME]; - QString f_preanim = m_chatmessage[PRE_EMOTE]; - - // all time values in char.inis are multiplied by a constant(time_mod) to get - // the actual time - int ao2_duration = ao_app->get_ao2_preanim_duration(f_char, f_preanim); - int text_delay = ao_app->get_text_delay(f_char, f_preanim) * time_mod; - int sfx_delay = m_chatmessage[SFX_DELAY].toInt() * 60; - bool looping_sfx = m_chatmessage[LOOPING_SFX] == "1"; - int preanim_duration; - - if (ao2_duration < 0) - preanim_duration = ao_app->get_preanim_duration(f_char, f_preanim); - else - preanim_duration = ao2_duration; - sfx_player->setLooping(looping_sfx); - sfx_delay_timer->start(sfx_delay); - QString anim_to_find = - ao_app->get_image_suffix(ao_app->get_character_path(f_char, f_preanim)); - if (!file_exists(anim_to_find) || preanim_duration < 0) { - if (noninterrupting) - anim_state = 4; - else - anim_state = 1; - preanim_done(); - qDebug() << "could not find " + anim_to_find; - return; - } - - ui_vp_player_char->play_pre(f_char, f_preanim, preanim_duration); - if (noninterrupting) - anim_state = 4; - else - anim_state = 1; - - if (text_delay >= 0) - text_delay_timer->start(text_delay); - - if (noninterrupting) - handle_chatmessage_3(); -} - -void Courtroom::preanim_done() -{ - anim_state = 1; - handle_chatmessage_3(); -} - -void Courtroom::doRealization() -{ - realization_timer->stop(); - if (!ao_app->is_shakeandflash_enabled()) - return; - ui_vp_realization->play("realizationflash", "", "", 90); -} - -void Courtroom::start_chat_ticking() -{ - // we need to ensure that the text isn't already ticking because this function - // can be called by two logic paths - if (text_state != 0) - return; - - if (m_chatmessage[REALIZATION] == "1") { - this->doRealization(); - misc_sfx_player->play( - ao_app->get_custom_realization(m_chatmessage[CHAR_NAME])); - } - if (m_chatmessage[SCREENSHAKE] == "1") { - this->doScreenShake(); - } - if (m_chatmessage[SCREENSHAKE] == "1") { - this->doScreenShake(); - } - ui_vp_message->clear(); - set_text_color(); - rainbow_counter = 0; - - if (chatmessage_is_empty) { - // since the message is empty, it's technically done ticking - text_state = 2; - return; - } - - // At this point, we'd do well to clear the inline colour stack. - // This stops it from flowing into next messages. - while (!inline_colour_stack.empty()) { - inline_colour_stack.pop(); - } - - ui_vp_chatbox->show(); - - tick_pos = 0; - blip_pos = 0; - - // Just in case we somehow got inline blue text left over from a previous - // message, let's set it to false. - inline_blue_depth = 0; - - // At the start of every new message, we set the text speed to the default. - current_display_speed = 3; - if (slower_blips) - chat_tick_timer->start(message_display_speed_slow[current_display_speed]); - else - chat_tick_timer->start(message_display_speed[current_display_speed]); - - QString f_char = m_chatmessage[CHAR_NAME]; - QString f_gender = ao_app->get_gender(f_char); - - blip_player->set_blips(ao_app->get_sfx_suffix("sfx-blip" + f_gender)); - - // means text is currently ticking - text_state = 1; -} - -void Courtroom::chat_tick() -{ - // note: this is called fairly often(every 60 ms when char is talking) - // do not perform heavy operations here - QString timem = QString::number(realization_timer->remainingTime()); - qDebug() << "TIME: " << timem; - QString f_message = m_chatmessage[MESSAGE]; - - // f_message.remove(0, tick_pos); SAFECHECK - - // Due to our new text speed system, we always need to stop the timer now. - chat_tick_timer->stop(); - int msg_delay = message_display_speed[current_display_speed]; - if (slower_blips) - msg_delay = message_display_speed_slow[current_display_speed]; - // Stops blips from playing when we have a formatting option. - bool formatting_char = false; - - // If previously, we have detected that the message is centered, now - // is the time to remove those two tildes at the start. - if (message_is_centered) { - f_message.remove(0, 2); - } - QString f_char = m_chatmessage[CHAR_NAME]; - if (log_goes_downwards && mirror_iclog) - ui_ic_chatlog->moveCursor(QTextCursor::End); - else if (!log_goes_downwards && mirror_iclog) - // ui_ic_chatlog->setTextCursor(); - ui_ic_chatlog->moveCursor(QTextCursor::EndOfLine); - - if (tick_pos >= f_message.size()) { - text_state = 2; - if (mirror_iclog) { - // After we are finished printing the text we log it in the ic log. - append_ic_text(m_chatmessage[MESSAGE], m_chatmessage[CHAR_NAME], false); - if (log_goes_downwards) - ui_ic_chatlog->moveCursor(QTextCursor::End); - else - ui_ic_chatlog->moveCursor(QTextCursor::Start); - } - if (anim_state != 4) { - anim_state = 3; - ui_vp_player_char->play_idle(f_char, m_chatmessage[EMOTE]); - } - } - - else { - QString f_character = f_message.at(tick_pos); - - f_character = f_character.toHtmlEscaped(); - if (punctuation_chars.contains(f_character)) { - msg_delay *= punctuation_modifier + 1; // Since we are handling a boolean, if its true its double (1 + 1) or false (1 + 0). - // ui_vp_message->insertPlainText(f_character); - } - - if (f_character == " ") { - ui_vp_message->insertPlainText(" "); - if (mirror_iclog) - ui_ic_chatlog->insertPlainText(" "); - } - else if (f_character == "@" && !next_character_is_not_special) { - this->doScreenShake(); - formatting_char = true; - } - - else if (f_character == "^" && !next_character_is_not_special) { - this->doRealization(); - - formatting_char = true; - } - // Escape character. - else if (f_character == "\\") { - if (f_message[tick_pos + 1] == 'n') { - ui_vp_message->insertHtml("
    "); - ui_ic_chatlog->insertPlainText(" "); - - tick_pos += 1; - next_character_is_not_special = false; - formatting_char = true; - } - else - next_character_is_not_special = true; - formatting_char = true; - msg_delay++; - } - - // Text speed modifier. - else if (f_character == "{" && !next_character_is_not_special) { - // ++, because it INCREASES delay! - current_display_speed++; - msg_delay++; - formatting_char = true; - } - else if (f_character == "}" && !next_character_is_not_special) { - current_display_speed--; - msg_delay++; - formatting_char = true; - } - - else if (f_character == "@" && !next_character_is_not_special) { - this->doScreenShake(); - formatting_char = true; - } - - else if (f_character == "$" && !next_character_is_not_special) { - this->doRealization(); - formatting_char = true; - } - - // Orange inline colourisation. - else if (f_character == "|" && !next_character_is_not_special) { - if (!inline_colour_stack.empty()) { - if (inline_colour_stack.top() == INLINE_ORANGE) { - inline_colour_stack.pop(); - } - else { - inline_colour_stack.push(INLINE_ORANGE); - } - } - else { - inline_colour_stack.push(INLINE_ORANGE); - } - formatting_char = true; - msg_delay++; - } - - // Blue inline colourisation. - else if (f_character == "(" && - !next_character_is_not_special) // EXAMPLE HERE - { - inline_colour_stack.push(INLINE_BLUE); - ui_vp_message->insertHtml("" + f_character + ""); - if (mirror_iclog && colorf_iclog) - ui_ic_chatlog->insertHtml("" + f_character + ""); - // Increase how deep we are in inline blues. - inline_blue_depth++; - - // Here, we check if the entire message is blue. - // If it isn't, we stop talking. - if (!entire_message_is_blue && anim_state != 4) { - f_char = m_chatmessage[CHAR_NAME]; - QString f_emote = m_chatmessage[EMOTE]; - ui_vp_player_char->play_idle(f_char, f_emote); - } - } - else if (f_character == ")" && !next_character_is_not_special && - !inline_colour_stack.empty()) { - if (inline_colour_stack.top() == INLINE_BLUE) { - inline_colour_stack.pop(); - ui_vp_message->insertHtml("" + f_character + ""); - if (mirror_iclog && colorf_iclog) - ui_ic_chatlog->insertHtml( - "" + f_character + ""); - // Decrease how deep we are in inline blues. - // Just in case, we do a check if we're above zero, but we should be. - if (inline_blue_depth > 0) { - inline_blue_depth--; - // Here, we check if the entire message is blue. - // If it isn't, we start talking if we have completely climbed out of - // inline blues. - if (!entire_message_is_blue) { - // We should only go back to talking if we're out of inline blues, - // not during a non. int. pre, and not on the last character. - if (inline_blue_depth == 0 && anim_state != 4 && - !(tick_pos + 1 >= f_message.size())) { - QString f_char = char_name; - f_char = m_chatmessage[CHAR_NAME]; - QString f_emote = m_chatmessage[EMOTE]; - ui_vp_player_char->play_talking(f_char, f_emote); - } - } - } - } - else { - next_character_is_not_special = true; - tick_pos--; - } - } - - // Grey inline colourisation. - else if (f_character == "[" && !next_character_is_not_special) { - inline_colour_stack.push(INLINE_GREY); - ui_vp_message->insertHtml("" + - f_character + ""); - if (mirror_iclog && colorf_iclog) - ui_ic_chatlog->insertHtml("" + f_character + ""); - } - else if (f_character == "]" && !next_character_is_not_special && - !inline_colour_stack.empty()) { - if (inline_colour_stack.top() == INLINE_GREY) { - inline_colour_stack.pop(); - ui_vp_message->insertHtml("" + f_character + ""); - if (mirror_iclog && colorf_iclog) - ui_ic_chatlog->insertHtml("" + f_character + ""); - } - else { - next_character_is_not_special = true; - tick_pos--; - } - } - - // Green inline colourisation. - else if (f_character == "`" && !next_character_is_not_special) { - if (!inline_colour_stack.empty()) { - if (inline_colour_stack.top() == INLINE_GREEN) { - inline_colour_stack.pop(); - } - else { - inline_colour_stack.push(INLINE_GREEN); - } - } - else { - inline_colour_stack.push(INLINE_GREEN); - } - msg_delay++; - formatting_char = true; - } - else { - - next_character_is_not_special = false; - if (!inline_colour_stack.empty()) { - switch (inline_colour_stack.top()) { - case INLINE_ORANGE: - ui_vp_message->insertHtml( - "" + - f_character + ""); - if (mirror_iclog && colorf_iclog) - ui_ic_chatlog->insertHtml( - "" + - f_character + ""); - break; - case INLINE_BLUE: - ui_vp_message->insertHtml( - "" + f_character + ""); - if (mirror_iclog && colorf_iclog) - ui_ic_chatlog->insertHtml( - "" + - f_character + ""); - break; - case INLINE_GREEN: - ui_vp_message->insertHtml( - "" + f_character + ""); - if (mirror_iclog && colorf_iclog) - ui_ic_chatlog->insertHtml( - "" + - f_character + ""); - break; - case INLINE_GREY: - ui_vp_message->insertHtml("" + f_character + ""); - if (mirror_iclog && colorf_iclog) - ui_ic_chatlog->insertHtml("" + f_character + ""); - break; - } - } - else { - if (m_chatmessage[TEXT_COLOR].toInt() == RAINBOW) { - QString html_color; - - switch (rainbow_counter) { - case 0: - html_color = get_text_color(QString::number(RED)).name(); - break; - case 1: - html_color = get_text_color(QString::number(ORANGE)).name(); - break; - case 2: - html_color = get_text_color(QString::number(YELLOW)).name(); - break; - case 3: - html_color = get_text_color(QString::number(GREEN)).name(); - break; - default: - html_color = get_text_color(QString::number(BLUE)).name(); - rainbow_counter = -1; - } - - ++rainbow_counter; - - ui_vp_message->insertHtml("" + - f_character + ""); - if (mirror_iclog && colorf_iclog && !colorf_limit) - ui_ic_chatlog->insertHtml("" + - f_character + ""); - } - else { - ui_vp_message->insertHtml(f_character); - if (mirror_iclog && colorf_iclog && - ((m_chatmessage[TEXT_COLOR].toInt() == WHITE) || colorf_limit)) - ui_ic_chatlog->insertHtml(f_character); - } - - if (!(m_chatmessage[TEXT_COLOR].toInt() == WHITE) && - !(m_chatmessage[TEXT_COLOR].toInt() == RAINBOW) && !colorf_limit) { - - QString html_color = - get_text_color(QString::number(m_chatmessage[TEXT_COLOR].toInt())) - .name(); - - if (mirror_iclog && colorf_iclog) - ui_ic_chatlog->insertHtml("" + - f_character + ""); - } - } - - if (mirror_iclog && !colorf_iclog) { - ui_ic_chatlog->textCursor().insertHtml(f_character); - } - if (message_is_centered) { - ui_vp_message->setAlignment(Qt::AlignCenter); - } - else { - ui_vp_message->setAlignment(Qt::AlignLeft); - } - } - - QScrollBar *scroll = ui_vp_message->verticalScrollBar(); - scroll->setValue(scroll->maximum()); - - if (blank_blip) - qDebug() << "blank_blip found true"; - - if (f_message.at(tick_pos) != ' ' || blank_blip) { - - if (blip_pos % blip_rate == 0 && !formatting_char) { - blip_pos = 0; - blip_player->blip_tick(); - } - - ++blip_pos; - } - - ++tick_pos; - - // Restart the timer, but according to the newly set speeds, if there were - // any. Keep the speed at bay. - if (current_display_speed < 0) { - current_display_speed = 0; - } - - if (current_display_speed > 6) { - current_display_speed = 6; - } - if (formatting_char) { - chat_tick_timer->start(1); - } - else { - chat_tick_timer->start(msg_delay); - } - } -} - -void Courtroom::play_sfx() -{ - QString sfx_name = m_chatmessage[SFX_NAME]; - - if (sfx_name == "1") - return; - - sfx_player->play(ao_app->get_sfx_suffix(sfx_name)); -} - -void Courtroom::set_scene() -{ - - // witness is default if pos is invalid - QString f_background = "witnessempty"; - QString f_desk_image = "stand"; - QString f_desk_mod = m_chatmessage[DESK_MOD]; - QString f_side = m_chatmessage[SIDE]; - - if (f_side == "def") { - f_background = "defenseempty"; - if (is_ao2_bg) - f_desk_image = "defensedesk"; - else - f_desk_image = "bancodefensa"; - } - else if (f_side == "pro") { - f_background = "prosecutorempty"; - if (is_ao2_bg) - f_desk_image = "prosecutiondesk"; - else - f_desk_image = "bancoacusacion"; - } - else if (f_side == "jud") { - f_background = "judgestand"; - f_desk_image = "judgedesk"; - } - else if (f_side == "hld") { - f_background = "helperstand"; - f_desk_image = "helperdesk"; - } - else if (f_side == "hlp") { - f_background = "prohelperstand"; - f_desk_image = "prohelperdesk"; - } - else if (f_side == "jur" && (file_exists(ao_app->get_image_suffix( - ao_app->get_background_path("jurystand"))))) { - f_background = "jurystand"; - f_desk_image = "jurydesk"; - } - else if (f_side == "sea" && - (file_exists(ao_app->get_image_suffix( - ao_app->get_background_path("seancestand"))))) { - f_background = "seancestand"; - f_desk_image = "seancedesk"; - } - else { - if (is_ao2_bg) - f_desk_image = "stand"; - else - f_desk_image = "estrado"; - } - - ui_vp_background->set_image(f_background); - ui_vp_desk->set_image(f_desk_image); - ui_vp_legacy_desk->set_legacy_desk(f_desk_image); - - if (f_desk_mod == "0" || - (f_desk_mod != "1" && - (f_side == "jud" || f_side == "hld" || f_side == "hlp"))) { - ui_vp_desk->hide(); - ui_vp_legacy_desk->hide(); - } - else if (is_ao2_bg || - (f_side == "jud" || f_side == "hld" || f_side == "hlp")) { - ui_vp_legacy_desk->hide(); - ui_vp_desk->show(); - } - else { - if (f_side == "wit") { - ui_vp_desk->show(); - ui_vp_legacy_desk->hide(); - } - else { - ui_vp_desk->hide(); - ui_vp_legacy_desk->show(); - } - } -} - -void Courtroom::set_text_color() -{ - QString f_char = m_chatmessage[CHAR_NAME]; - QColor textcolor = ao_app->get_chat_color(m_chatmessage[TEXT_COLOR], - ao_app->get_chat(f_char)); - - ui_vp_message->setTextBackgroundColor(QColor(0, 0, 0, 0)); - ui_vp_message->setTextColor(textcolor); - - QString style = "background-color: rgba(0, 0, 0, 0);"; - style.append("color: rgb("); - style.append(QString::number(textcolor.red())); - style.append(", "); - style.append(QString::number(textcolor.green())); - style.append(", "); - style.append(QString::number(textcolor.blue())); - style.append(")"); - - ui_vp_message->setStyleSheet(style); -} - -QColor Courtroom::get_text_color(QString color) -{ - QString f_char = m_chatmessage[CHAR_NAME]; - return ao_app->get_chat_color(color, ao_app->get_chat(f_char)); -} - -void Courtroom::set_ip_list(QString p_list) -{ - QString f_list = p_list.replace("|", ":").replace("*", "\n"); - - ui_server_chatlog->append(f_list); -} - -void Courtroom::set_mute(bool p_muted, int p_cid) -{ - if (p_cid != m_cid && p_cid != -1) - return; - - if (p_muted) - ui_muted->show(); - else { - ui_muted->hide(); - ui_ic_chat_message->setFocus(); - } - - ui_muted->resize(ui_ic_chat_message->width(), ui_ic_chat_message->height()); - ui_muted->set_image("muted.png"); - - is_muted = p_muted; - ui_ic_chat_message->setEnabled(!p_muted); -} - -void Courtroom::set_ban(int p_cid) -{ - if (p_cid != m_cid && p_cid != -1) - return; - - call_notice(tr("You have been banned.")); - - ao_app->construct_lobby(); - ao_app->destruct_courtroom(); -} - -void Courtroom::handle_song(QStringList *p_contents) -{ - QStringList f_contents = *p_contents; - - if (f_contents.size() < 2) - return; - - QString f_song = f_contents.at(0); - QString f_song_clear = f_song; - int n_char = f_contents.at(1).toInt(); - - qDebug() << "playing song " + ao_app->get_music_path(f_song); - - if (n_char < 0 || n_char >= char_list.size()) { - music_player->play(ao_app->get_music_prefix(f_song)); - } - else { - QString str_char = char_list.at(n_char).name; - QString str_show = char_list.at(n_char).name; - - if (p_contents->length() > 2) { - if (p_contents->at(2) != "") { - str_show = p_contents->at(2); - } - } - if (p_contents->length() > 3) { - if (p_contents->at(3) != "-1") { - music_player->enable_looping = false; - } - else { - music_player->enable_looping = true; - } - } - if (!mute_map.value(n_char)) { - chatlogpiece *temp = new chatlogpiece(str_char, str_show, f_song, true, - m_chatmessage[TEXT_COLOR].toInt()); - ic_chatlog_history.append(*temp); - - while (ic_chatlog_history.size() > log_maximum_blocks && - log_maximum_blocks > 0) { - ic_chatlog_history.removeFirst(); - } - if (mirror_iclog) // If mirror is enabled, we display the song in the ooc - // chat rather than ic log for a more realistic - // expierence. - { - ui_server_chatlog->append_chatmessage( - str_show, " has played a song: " + f_song_clear + ".", - ao_app->get_color("ooc_server_color", "courtroom_design.ini") - .name(), - true); - } - append_ic_text(f_song_clear, str_show, true); - music_player->play(ao_app->get_music_prefix(f_song)); - } - } -} -void Courtroom::handle_failed_login() -{ - modcall_player->play("./music/failed_login"); // aov memes -} -void Courtroom::handle_wtce(QString p_wtce, int variant) -{ - QString sfx_file = "courtroom_sounds.ini"; - - // witness testimony - if (p_wtce == "testimony1") { - misc_sfx_player->play(ao_app->get_sfx("witness_testimony")); - ui_vp_wtce->play("witnesstestimony", "", "", wtce_stay_time); - ui_vp_testimony->play("testimony"); - } - // cross examination - else if (p_wtce == "testimony2") { - misc_sfx_player->play(ao_app->get_sfx("cross_examination")); - ui_vp_wtce->play("crossexamination", "", "", wtce_stay_time); - ui_vp_testimony->stop(); - } - else if (p_wtce == "judgeruling") { - if (variant == 0) { - misc_sfx_player->play(ao_app->get_sfx("not_guilty")); - ui_vp_wtce->play("notguilty", "", "", verdict_stay_time); - ui_vp_testimony->stop(); - } - else if (variant == 1) { - misc_sfx_player->play(ao_app->get_sfx("guilty")); - ui_vp_wtce->play("guilty", "", "", verdict_stay_time); - ui_vp_testimony->stop(); - } - } -} - -void Courtroom::set_hp_bar(int p_bar, int p_state) -{ - if (p_state < 0 || p_state > 10) - return; - - if (p_bar == 1) { - ui_defense_bar->set_image("defensebar" + QString::number(p_state) + ".png"); - defense_bar_state = p_state; - } - else if (p_bar == 2) { - ui_prosecution_bar->set_image("prosecutionbar" + QString::number(p_state) + - ".png"); - prosecution_bar_state = p_state; - } -} - -void Courtroom::toggle_judge_buttons(bool is_on) -{ - if (is_on) { - ui_witness_testimony->show(); - ui_cross_examination->show(); - ui_guilty->show(); - ui_not_guilty->show(); - ui_defense_minus->show(); - ui_defense_plus->show(); - ui_prosecution_minus->show(); - ui_prosecution_plus->show(); - } - else { - ui_witness_testimony->hide(); - ui_cross_examination->hide(); - ui_guilty->hide(); - ui_not_guilty->hide(); - ui_defense_minus->hide(); - ui_defense_plus->hide(); - ui_prosecution_minus->hide(); - ui_prosecution_plus->hide(); - } -} - -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")); - ao_app->alert(this); - } -} - -void Courtroom::case_called(QString msg, bool def, bool pro, bool jud, bool jur, - bool steno, bool witness) -{ - if (ui_casing->isChecked()) { - ui_server_chatlog->append(msg); - if ((ao_app->get_casing_defence_enabled() && def) || - (ao_app->get_casing_prosecution_enabled() && pro) || - (ao_app->get_casing_judge_enabled() && jud) || - (ao_app->get_casing_juror_enabled() && jur) || - (ao_app->get_casing_steno_enabled() && steno) || - (ao_app->get_casing_wit_enabled() && witness)) { - modcall_player->play(ao_app->get_sfx("case_call")); - ao_app->alert(this); - } - } -} - -void Courtroom::on_ooc_return_pressed() -{ - QString ooc_message = ui_ooc_chat_message->text(); - - if (ooc_message == "" || ui_ooc_chat_name->text() == "") - return; - - if (ooc_message.startsWith("/pos")) { - if (ooc_message == "/pos jud") { - toggle_judge_buttons(true); - } - else { - toggle_judge_buttons(false); - } - } - else if (ooc_message.startsWith("/login")) { - ui_guard->show(); - - append_server_chatmessage( - "CLIENT", tr("You were granted the Disable Modcalls button."), "1"); - } - else if (ooc_message.startsWith("/rainbow") && ao_app->yellow_text_enabled && - !rainbow_appended) { - // ui_text_color->addItem("Rainbow"); - ui_ooc_chat_message->clear(); - // rainbow_appended = true; - append_server_chatmessage("CLIENT", - tr("This does nothing, but there you go."), "1"); - return; - } - else if (ooc_message.startsWith("/settings")) { - ui_ooc_chat_message->clear(); - ao_app->call_settings_menu(); - append_server_chatmessage("CLIENT", tr("You opened the settings menu."), - "1"); - return; - } - else if (ooc_message.startsWith("/pair")) { - ui_ooc_chat_message->clear(); - ooc_message.remove(0, 6); - - bool ok; - int whom = ooc_message.toInt(&ok); - if (ok) { - if (whom > -1) { - other_charid = whom; - QString msg = tr("You will now pair up with "); - msg.append(char_list.at(whom).name); - msg.append(tr(" if they also choose your character in return.")); - append_server_chatmessage("CLIENT", msg, "1"); - } - else { - other_charid = -1; - append_server_chatmessage( - "CLIENT", tr("You are no longer paired with anyone."), "1"); - } - } - else { - append_server_chatmessage("CLIENT", - tr("Are you sure you typed that well? The char " - "ID could not be recognised."), - "1"); - } - return; - } - else if (ooc_message.startsWith("/offset")) { - ui_ooc_chat_message->clear(); - ooc_message.remove(0, 8); - - bool ok; - int off = ooc_message.toInt(&ok); - if (ok) { - if (off >= -100 && off <= 100) { - offset_with_pair = off; - QString msg = tr("You have set your offset to "); - msg.append(QString::number(off)); - msg.append("%."); - append_server_chatmessage("CLIENT", msg, "1"); - } - else { - append_server_chatmessage( - "CLIENT", tr("Your offset must be between -100% and 100%!"), "1"); - } - } - else { - append_server_chatmessage("CLIENT", - tr("That offset does not look like one."), "1"); - } - return; - } - else if (ooc_message.startsWith("/switch_am")) { - append_server_chatmessage( - "CLIENT", tr("You switched your music and area list."), "1"); - on_switch_area_music_clicked(); - ui_ooc_chat_message->clear(); - return; - } - else if (ooc_message.startsWith("/enable_blocks")) { - append_server_chatmessage("CLIENT", - tr("You have forcefully enabled features that " - "the server may not support. You may not be " - "able to talk IC, or worse, because of this."), - "1"); - ao_app->cccc_ic_support_enabled = true; - ao_app->arup_enabled = true; - ao_app->modcall_reason_enabled = true; - on_reload_theme_clicked(); - ui_ooc_chat_message->clear(); - return; - } - else if (ooc_message.startsWith("/non_int_pre")) { - if (ui_pre_non_interrupt->isChecked()) - append_server_chatmessage( - "CLIENT", tr("Your pre-animations interrupt again."), "1"); - else - append_server_chatmessage( - "CLIENT", tr("Your pre-animations will not interrupt text."), "1"); - ui_pre_non_interrupt->setChecked(!ui_pre_non_interrupt->isChecked()); - ui_ooc_chat_message->clear(); - return; - } - else if (ooc_message.startsWith("/save_chatlog")) { - QFile file("chatlog.txt"); - - if (!file.open(QIODevice::WriteOnly | QIODevice::Text | - QIODevice::Truncate)) { - append_server_chatmessage( - "CLIENT", tr("Couldn't open chatlog.txt to write into."), "1"); - ui_ooc_chat_message->clear(); - return; - } - - QTextStream out(&file); - - foreach (chatlogpiece item, ic_chatlog_history) { - out << item.get_full() << '\n'; - } - - file.close(); - - append_server_chatmessage("CLIENT", tr("The IC chatlog has been saved."), - "1"); - ui_ooc_chat_message->clear(); - return; - } - else if (ooc_message.startsWith("/load_case")) { - QStringList command = ooc_message.split(" ", QString::SkipEmptyParts); - - QDir casefolder("base/cases"); - if (!casefolder.exists()) { - QDir::current().mkdir("base/" + casefolder.dirName()); - append_server_chatmessage( - "CLIENT", - tr("You don't have a `base/cases/` folder! It was just made for you, " - "but seeing as it WAS just made for you, it's likely the case " - "file you're looking for can't be found in there."), - "1"); - ui_ooc_chat_message->clear(); - return; - } - QStringList caseslist = casefolder.entryList(); - caseslist.removeOne("."); - caseslist.removeOne(".."); - caseslist.replaceInStrings(".ini", ""); - - if (command.size() < 2) { - append_server_chatmessage( - "CLIENT", - tr("You need to give a filename to load (extension not needed)! Make " - "sure that it is in the `base/cases/` folder, and that it is a " - "correctly formatted ini.\nCases you can load: %1") - .arg(caseslist.join(", ")), - "1"); - ui_ooc_chat_message->clear(); - return; - } - - if (command.size() > 2) { - append_server_chatmessage( - "CLIENT", - tr("Too many arguments to load a case! You only need one filename, " - "without extension."), - "1"); - ui_ooc_chat_message->clear(); - return; - } - - QSettings casefile("base/cases/" + command[1] + ".ini", - QSettings::IniFormat); - - QString caseauth = casefile.value("author", "").value(); - QString casedoc = casefile.value("doc", "").value(); - QString cmdoc = casefile.value("cmdoc", "").value(); - QString casestatus = casefile.value("status", "").value(); - - if (!caseauth.isEmpty()) - append_server_chatmessage("CLIENT", tr("Case made by %1.").arg(caseauth), - "1"); - if (!casedoc.isEmpty()) - ao_app->send_server_packet(new AOPacket("CT#" + ui_ooc_chat_name->text() + - "#/doc " + casedoc + "#%")); - if (!casestatus.isEmpty()) - ao_app->send_server_packet(new AOPacket("CT#" + ui_ooc_chat_name->text() + - "#/status " + casestatus + "#%")); - if (!cmdoc.isEmpty()) - append_server_chatmessage( - "CLIENT", tr("Navigate to %1 for the CM doc.").arg(cmdoc), "1"); - - for (int i = local_evidence_list.size() - 1; i >= 0; i--) { - ao_app->send_server_packet( - new AOPacket("DE#" + QString::number(i) + "#%")); - } - - foreach (QString evi, casefile.childGroups()) { - if (evi == "General") - continue; - - QStringList f_contents; - - f_contents.append( - casefile.value(evi + "/name", "UNKNOWN").value()); - f_contents.append( - casefile.value(evi + "/description", "UNKNOWN").value()); - f_contents.append( - casefile.value(evi + "/image", "UNKNOWN.png").value()); - - ao_app->send_server_packet(new AOPacket("PE", f_contents)); - } - append_server_chatmessage( - "CLIENT", tr("Your case \"%1\" was loaded!").arg(command[1]), "1"); - ui_ooc_chat_message->clear(); - return; - } - else if (ooc_message.startsWith("/save_case")) { - QStringList command = ooc_message.split(" ", QString::SkipEmptyParts); - - QDir casefolder("base/cases"); - if (!casefolder.exists()) { - QDir::current().mkdir("base/" + casefolder.dirName()); - append_server_chatmessage( - "CLIENT", - tr("You don't have a `base/cases/` folder! It was just made for you, " - "but seeing as it WAS just made for you, it's likely that you " - "somehow deleted it."), - "1"); - ui_ooc_chat_message->clear(); - return; - } - QStringList caseslist = casefolder.entryList(); - caseslist.removeOne("."); - caseslist.removeOne(".."); - caseslist.replaceInStrings(".ini", ""); - - if (command.size() < 3) { - append_server_chatmessage( - "CLIENT", - tr("You need to give a filename to save (extension not needed) and " - "the courtroom status!"), - "1"); - ui_ooc_chat_message->clear(); - return; - } - - if (command.size() > 3) { - append_server_chatmessage( - "CLIENT", - tr("Too many arguments to save a case! You only need a filename " - "without extension and the courtroom status."), - "1"); - ui_ooc_chat_message->clear(); - return; - } - QSettings casefile("base/cases/" + command[1] + ".ini", - QSettings::IniFormat); - casefile.setValue("author", ui_ooc_chat_name->text()); - casefile.setValue("cmdoc", ""); - casefile.setValue("doc", ""); - casefile.setValue("status", command[2]); - casefile.sync(); - for (int i = local_evidence_list.size() - 1; i >= 0; i--) { - QString clean_evidence_dsc = local_evidence_list[i].description.replace( - QRegularExpression("..."), ""); - clean_evidence_dsc = clean_evidence_dsc.replace( - clean_evidence_dsc.lastIndexOf(">"), 1, ""); - casefile.beginGroup(QString::number(i)); - casefile.sync(); - casefile.setValue("name", local_evidence_list[i].name); - casefile.setValue("description", local_evidence_list[i].description); - casefile.setValue("image", local_evidence_list[i].image); - casefile.endGroup(); - } - casefile.sync(); - append_server_chatmessage( - "CLIENT", tr("Succesfully saved, edit doc and cmdoc link on the ini!"), - "1"); - ui_ooc_chat_message->clear(); - return; - } - else if (ooc_message.startsWith("/clearooc")) { - ui_server_chatlog->clear(); - ui_ooc_chat_message->clear(); - return; - } - else if (ooc_message.startsWith("/version")) { - append_server_chatmessage("CLIENT", ao_app->get_version_string(), "1"); - ui_ooc_chat_message->clear(); - return; - } - - QStringList packet_contents; - packet_contents.append(ui_ooc_chat_name->text()); - packet_contents.append(ooc_message); - - AOPacket *f_packet = new AOPacket("CT", packet_contents); - - if (server_ooc) - ao_app->send_server_packet(f_packet); - else - ao_app->send_ms_packet(f_packet); - - ui_ooc_chat_message->clear(); - - ui_ooc_chat_message->setFocus(); -} - -void Courtroom::on_ooc_toggle_clicked() -{ - if (server_ooc) { - ui_ms_chatlog->show(); - ui_server_chatlog->hide(); - ui_ooc_toggle->setText(tr("")); - ui_ooc_toggle->set_image("ooc_toggle_ms.png"); - if (ooc_toggle_fallback) { - ui_ooc_toggle->setText(tr("Master")); - } - server_ooc = false; - } - else { - ui_ms_chatlog->hide(); - ui_server_chatlog->show(); - ui_ooc_toggle->setText(tr("")); - ui_ooc_toggle->set_image("ooc_toggle_server.png"); - if (ooc_toggle_fallback) { - ui_ooc_toggle->setText(tr("Server")); - } - server_ooc = true; - } -} - -void Courtroom::on_music_search_keypr() -{ - if (ui_music_search->text() == "") { - ui_music_list->collapseAll(); - } -} - -void Courtroom::on_music_search_edited(QString p_text) -{ - // preventing compiler warnings - p_text += "a"; - list_music(); - list_areas(); -} - -void Courtroom::on_pos_dropdown_changed(int p_index) -{ - ui_ic_chat_message->setFocus(); - - if (p_index < 0 || p_index > 7) - return; - - toggle_judge_buttons(false); - - QString f_pos; - - switch (p_index) { - case 0: - f_pos = "wit"; - break; - case 1: - f_pos = "def"; - break; - case 2: - f_pos = "pro"; - break; - case 3: - f_pos = "jud"; - toggle_judge_buttons(true); - break; - case 4: - f_pos = "hld"; - break; - case 5: - f_pos = "hlp"; - break; - case 6: - f_pos = "jur"; - break; - case 7: - f_pos = "sea"; - break; - default: - f_pos = ""; - } - - if (f_pos == "" || ui_ooc_chat_name->text() == "") - return; - - ao_app->send_server_packet( - new AOPacket("CT#" + ui_ooc_chat_name->text() + "#/pos " + f_pos + "#%")); -} - -void Courtroom::on_mute_list_clicked(QModelIndex p_index) -{ - QListWidgetItem *f_item = ui_mute_list->item(p_index.row()); - QString f_char = f_item->text(); - QString real_char; - - if (f_char.endsWith(" [x]")) - real_char = f_char.left(f_char.size() - 4); - else - real_char = f_char; - - int f_cid = -1; - - 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 < 0 || f_cid >= char_list.size()) { - qDebug() << "W: " << real_char << " not present in char_list"; - return; - } - - if (mute_map.value(f_cid)) { - mute_map.insert(f_cid, false); - f_item->setText(real_char); - } - else { - mute_map.insert(f_cid, true); - f_item->setText(real_char + " [x]"); - } -} - -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()) { - qDebug() << "W: " << real_char << " not present in char_list"; - return; - } - - other_charid = f_cid; - - // Redo the character list. - QStringList sorted_pair_list; - - for (char_type i_char : 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) -{ - if (is_muted) - return; - - column = 1; // Column 1 is always the metadata (which we want) - QString p_song = p_item->text(column); - if (!ui_ic_chat_name->text().isEmpty() && ao_app->cccc_ic_support_enabled) { - ao_app->send_server_packet(new AOPacket("MC#" + p_song + "#" + - QString::number(m_cid) + "#" + - ui_ic_chat_name->text() + "#%"), - false); - } - else { - ao_app->send_server_packet( - new AOPacket("MC#" + p_song + "#" + QString::number(m_cid) + "#%"), - false); - } -} - -void Courtroom::on_area_list_double_clicked(QModelIndex p_model) - -{ - - QString p_area = area_list.at(area_row_to_number.at(p_model.row())); - - ao_app->send_server_packet( - new AOPacket("MC#" + p_area + "#" + QString::number(m_cid) + "#%"), - false); -} - -void Courtroom::on_hold_it_clicked() -{ - if (objection_state == 1) { - ui_hold_it->set_image("holdit.png"); - objection_state = 0; - } - else { - ui_objection->set_image("objection.png"); - ui_take_that->set_image("takethat.png"); - ui_custom_objection->set_image("custom.png"); - - ui_hold_it->set_image("holdit_selected.png"); - objection_state = 1; - } - - ui_ic_chat_message->setFocus(); -} - -void Courtroom::on_objection_clicked() -{ - if (objection_state == 2) { - ui_objection->set_image("objection.png"); - objection_state = 0; - } - else { - ui_hold_it->set_image("holdit.png"); - ui_take_that->set_image("takethat.png"); - ui_custom_objection->set_image("custom.png"); - - ui_objection->set_image("objection_selected.png"); - objection_state = 2; - } - - ui_ic_chat_message->setFocus(); -} - -void Courtroom::on_take_that_clicked() -{ - if (objection_state == 3) { - ui_take_that->set_image("takethat.png"); - objection_state = 0; - } - else { - ui_objection->set_image("objection.png"); - ui_hold_it->set_image("holdit.png"); - ui_custom_objection->set_image("custom.png"); - - ui_take_that->set_image("takethat_selected.png"); - objection_state = 3; - } - - ui_ic_chat_message->setFocus(); -} - -void Courtroom::on_custom_objection_clicked() -{ - if (objection_state == 4) { - ui_custom_objection->set_image("custom.png"); - objection_state = 0; - objection_custom = ""; - } - else { - ui_objection->set_image("objection.png"); - ui_take_that->set_image("takethat.png"); - ui_hold_it->set_image("holdit.png"); - ui_custom_objection->set_image("custom_selected.png"); - objection_state = 4; - } - - ui_ic_chat_message->setFocus(); -} - -void Courtroom::ShowContextMenu(const QPoint &pos) -{ - QPoint globalPos = ui_custom_objection->mapToGlobal(pos); - QAction *selecteditem = custom_obj_menu->exec(globalPos); - if (selecteditem) { - ui_objection->set_image("objection.png"); - ui_take_that->set_image("takethat.png"); - ui_hold_it->set_image("holdit.png"); - ui_custom_objection->set_image("custom_selected.png"); - objection_custom = selecteditem->text(); - objection_state = 4; - } -} - -void Courtroom::on_realization_clicked() -{ - if (realization_state == 0) { - realization_state = 1; - ui_realization->set_image("realization_pressed.png"); - } - else { - realization_state = 0; - ui_realization->set_image("realization.png"); - } - - ui_ic_chat_message->setFocus(); -} -void Courtroom::on_screenshake_clicked() -{ - if (screenshake_state == 0) { - screenshake_state = 1; - ui_screenshake->set_image("screenshake_pressed.png"); - } - else { - screenshake_state = 0; - ui_screenshake->set_image("screenshake.png"); - } - - ui_ic_chat_message->setFocus(); -} -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_button->set_image("pair_button.png"); - ui_mute->set_image("mute_pressed.png"); - } - else { - ui_mute_list->hide(); - ui_mute->set_image("mute.png"); - } -} - -void Courtroom::on_pair_clicked() -{ - if (ui_pair_list->isHidden()) { - ui_pair_list->show(); - ui_pair_offset_spinbox->show(); - ui_mute_list->hide(); - ui_mute->set_image("mute.png"); - ui_pair_button->set_image("pair_button_pressed.png"); - } - else { - ui_pair_list->hide(); - ui_pair_offset_spinbox->hide(); - ui_pair_button->set_image("pair_button.png"); - } -} - -void Courtroom::on_defense_minus_clicked() -{ - int f_state = defense_bar_state - 1; - - if (f_state >= 0) - ao_app->send_server_packet( - new AOPacket("HP#1#" + QString::number(f_state) + "#%")); -} - -void Courtroom::on_defense_plus_clicked() -{ - int f_state = defense_bar_state + 1; - - if (f_state <= 10) - ao_app->send_server_packet( - new AOPacket("HP#1#" + QString::number(f_state) + "#%")); -} - -void Courtroom::on_prosecution_minus_clicked() -{ - int f_state = prosecution_bar_state - 1; - - if (f_state >= 0) - ao_app->send_server_packet( - new AOPacket("HP#2#" + QString::number(f_state) + "#%")); -} - -void Courtroom::on_prosecution_plus_clicked() -{ - int f_state = prosecution_bar_state + 1; - - if (f_state <= 10) - ao_app->send_server_packet( - new AOPacket("HP#2#" + QString::number(f_state) + "#%")); -} - -void Courtroom::on_text_color_changed(int p_color) -{ - text_color = p_color; - ui_ic_chat_message->setFocus(); -} - -void Courtroom::on_music_slider_moved(int p_value) -{ - music_player->set_volume(p_value); - ui_ic_chat_message->setFocus(); -} - -void Courtroom::on_sfx_slider_moved(int p_value) -{ - sfx_player->set_volume(p_value); - objection_player->set_volume(p_value); - misc_sfx_player->set_volume(p_value); - frame_emote_sfx_player->set_volume(p_value); - pair_frame_emote_sfx_player->set_volume(p_value); - ui_ic_chat_message->setFocus(); -} - -void Courtroom::on_blip_slider_moved(int p_value) -{ - blip_player->set_volume(p_value); - ui_ic_chat_message->setFocus(); -} - -void Courtroom::on_log_limit_changed(int value) { log_maximum_blocks = value; } - -void Courtroom::on_pair_offset_changed(int value) { offset_with_pair = value; } - -void Courtroom::on_witness_testimony_clicked() -{ - if (is_muted) - return; - - ao_app->send_server_packet(new AOPacket("RT#testimony1#%")); - - ui_ic_chat_message->setFocus(); -} - -void Courtroom::on_cross_examination_clicked() -{ - if (is_muted) - return; - - ao_app->send_server_packet(new AOPacket("RT#testimony2#%")); - - ui_ic_chat_message->setFocus(); -} - -void Courtroom::on_not_guilty_clicked() -{ - if (is_muted) - return; - - ao_app->send_server_packet(new AOPacket("RT#judgeruling#0#%")); - - ui_ic_chat_message->setFocus(); -} - -void Courtroom::on_guilty_clicked() -{ - if (is_muted) - return; - - ao_app->send_server_packet(new AOPacket("RT#judgeruling#1#%")); - - ui_ic_chat_message->setFocus(); -} - -void Courtroom::on_change_character_clicked() -{ - music_player->set_volume(0); - sfx_player->set_volume(0); - sfx_player->set_volume(0); - blip_player->set_volume(0); - - set_char_select(); - - ui_char_select_background->show(); - ui_spectator->hide(); -} - -void Courtroom::on_reload_theme_clicked() -{ - ao_app->reload_theme(); - punctuation_modifier = ao_app->get_pundelay(); - slower_blips = ao_app->get_slower_blips(); - colorf_iclog = ao_app->get_colored_iclog_enabled(); - mirror_iclog = ao_app->get_iclmir_enabled(); - colorf_limit = ao_app->colorlog_restricted_enabled(); - keep_evidence_display = ao_app->is_keepevi_enabled(); - // to update status on the background - set_background(current_background); - // to update fallback text bools - detect_fallback_text(); - enter_courtroom(m_cid); - - anim_state = 4; - text_state = 3; -} - -void Courtroom::on_back_to_lobby_clicked() -{ - ao_app->construct_lobby(); - ao_app->destruct_courtroom(); -} - -void Courtroom::on_char_select_left_clicked() -{ - --current_char_page; - set_char_select_page(); -} - -void Courtroom::on_char_select_right_clicked() -{ - ++current_char_page; - set_char_select_page(); -} - -void Courtroom::on_spectator_clicked() -{ - this->set_character(-1); - - ui_emotes->hide(); - - ui_char_select_background->hide(); -} - -void Courtroom::on_call_mod_clicked() -{ - if (ao_app->modcall_reason_enabled) { - 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; - - 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); - - ao_app->send_server_packet(new AOPacket("ZZ", mod_reason)); - } - else { - ao_app->send_server_packet(new AOPacket("ZZ#%")); - } - - ui_ic_chat_message->setFocus(); -} - -void Courtroom::on_settings_clicked() { ao_app->call_settings_menu(); } - -void Courtroom::on_announce_casing_clicked() -{ - ao_app->call_announce_menu(this); -} - -void Courtroom::on_pre_clicked() { ui_ic_chat_message->setFocus(); } - -void Courtroom::on_flip_clicked() { ui_ic_chat_message->setFocus(); } - -void Courtroom::on_guard_clicked() { ui_ic_chat_message->setFocus(); } - -void Courtroom::on_showname_enable_clicked() -{ - - refresh_iclog(false); - ui_ic_chat_message->setFocus(); -} - -void Courtroom::on_evidence_button_clicked() -{ - if (ui_evidence->isHidden()) { - ui_evidence->show(); - ui_evidence_overlay->hide(); - } - else { - ui_evidence->hide(); - } -} - -void Courtroom::on_switch_area_music_clicked() -{ - - if (ui_area_list->isHidden()) { - music_search_par = ui_music_search->text(); - ui_music_search->setText(area_search_par); - ui_area_list->show(); - ui_music_list->hide(); - } - else { - area_search_par = ui_music_search->text(); - ui_music_search->setText(music_search_par); - ui_area_list->hide(); - ui_music_list->show(); - } -} - -void Courtroom::ping_server() -{ - ao_app->send_server_packet( - new AOPacket("CH#" + QString::number(m_cid) + "#%")); -} - -void Courtroom::on_casing_clicked() -{ - if (ao_app->casing_alerts_enabled) { - if (ui_casing->isChecked()) { - QStringList f_packet; - - f_packet.append(ao_app->get_casing_can_host_cases()); - f_packet.append(QString::number(ao_app->get_casing_cm_enabled())); - f_packet.append(QString::number(ao_app->get_casing_defence_enabled())); - f_packet.append( - QString::number(ao_app->get_casing_prosecution_enabled())); - f_packet.append(QString::number(ao_app->get_casing_judge_enabled())); - f_packet.append(QString::number(ao_app->get_casing_juror_enabled())); - f_packet.append(QString::number(ao_app->get_casing_steno_enabled())); - f_packet.append(QString::number(ao_app->get_casing_wit_enabled())); - - ao_app->send_server_packet(new AOPacket("SETCASE", f_packet)); - } - else - ao_app->send_server_packet(new AOPacket("SETCASE#\"\"#0#0#0#0#0#0#0#%")); - } -} - -void Courtroom::announce_case(QString title, bool def, bool pro, bool jud, - bool jur, bool steno, bool wit) -{ - if (ao_app->casing_alerts_enabled) { - QStringList f_packet; - - f_packet.append(title); - f_packet.append(QString::number(def)); - f_packet.append(QString::number(pro)); - f_packet.append(QString::number(jud)); - f_packet.append(QString::number(jur)); - f_packet.append(QString::number(steno)); - f_packet.append(QString::number(wit)); - - ao_app->send_server_packet(new AOPacket("CASEA", f_packet)); - } -} - -Courtroom::~Courtroom() -{ - delete music_player; - delete sfx_player; - delete objection_player; - delete blip_player; -} - -void Courtroom::refresh_iclog(bool skiplast) -{ - ui_ic_chatlog->clear(); - first_message_sent = false; - - foreach (chatlogpiece item, ic_chatlog_history) { - if (skiplast && ic_chatlog_history.last().get_full() == item.get_full()) { - break; - } - if (ui_showname_enable->isChecked()) { - if (item.get_is_song()) - append_ic_text(item.get_message(), item.get_showname(), true, false, - false); - else - append_ic_text(item.get_message(), item.get_showname(), false, true, - true, item.get_chat_color()); - } - else { - if (item.get_is_song()) - append_ic_text(item.get_message(), item.get_name(), true, false, true); - else - append_ic_text(item.get_message(), item.get_name(), false, true, false, - item.get_chat_color()); - } - } -} - -#ifdef BASSAUDIO -#if (defined(_WIN32) || defined(_WIN64)) -void Courtroom::load_bass_opus_plugin() { BASS_PluginLoad("bassopus.dll", 0); } -#elif (defined(LINUX) || defined(__linux__)) -void Courtroom::load_bass_opus_plugin() -{ - BASS_PluginLoad("libbassopus.so", 0); -} -#elif defined __APPLE__ -void Courtroom::load_bass_opus_plugin() -{ - QString libpath = - ao_app->get_base_path() + "../../Frameworks/libbassopus.dylib"; - QByteArray ba = libpath.toLocal8Bit(); - BASS_PluginLoad(ba.data(), 0); -} -#else -#error This operating system is unsupported for bass plugins. -#endif -#endif +#include "courtroom.h" + +Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() +{ + ao_app = p_ao_app; + #ifdef BASSAUDIO + // Change the default audio output device to be the one the user has given + // in his config.ini file for now. + unsigned int a = 0; + BASS_DEVICEINFO info; + + if (ao_app->get_audio_output_device() == "default") + { + BASS_Init(-1, 48000, BASS_DEVICE_LATENCY, nullptr, nullptr); + load_bass_opus_plugin(); + } + else + { + for (a = 0; BASS_GetDeviceInfo(a, &info); a++) + { + if (ao_app->get_audio_output_device() == info.name) + { + BASS_SetDevice(a); + BASS_Init(static_cast(a), 48000, BASS_DEVICE_LATENCY, nullptr, nullptr); + load_bass_opus_plugin(); + qDebug() << info.name << "was set as the default audio output device."; + break; + } + } + } + #endif + + keepalive_timer = new QTimer(this); + keepalive_timer->start(60000); + + chat_tick_timer = new QTimer(this); + + text_delay_timer = new QTimer(this); + text_delay_timer->setSingleShot(true); + + sfx_delay_timer = new QTimer(this); + sfx_delay_timer->setSingleShot(true); + + realization_timer = new QTimer(this); + realization_timer->setSingleShot(true); + + testimony_show_timer = new QTimer(this); + testimony_show_timer->setSingleShot(true); + + testimony_hide_timer = new QTimer(this); + testimony_hide_timer->setSingleShot(true); + + music_player = new AOMusicPlayer(this, ao_app); + music_player->set_volume(0); + + sfx_player = new AOSfxPlayer(this, ao_app); + sfx_player->set_volume(0); + + objection_player = new AOSfxPlayer(this, ao_app); + objection_player->set_volume(0); + + blip_player = new AOBlipPlayer(this, ao_app); + blip_player->set_volume(0); + + modcall_player = new AOSfxPlayer(this, ao_app); + modcall_player->set_volume(50); + + ui_background = new AOImage(this, ao_app); + + ui_viewport = new QWidget(this); + ui_vp_background = new AOScene(ui_viewport, ao_app); + ui_vp_speedlines = new AOMovie(ui_viewport, ao_app); + ui_vp_speedlines->set_play_once(false); + ui_vp_player_char = new AOCharMovie(ui_viewport, ao_app); + ui_vp_sideplayer_char = new AOCharMovie(ui_viewport, ao_app); + ui_vp_sideplayer_char->hide(); + ui_vp_desk = new AOScene(ui_viewport, ao_app); + ui_vp_legacy_desk = new AOScene(ui_viewport, ao_app); + + ui_vp_evidence_display = new AOEvidenceDisplay(this, ao_app); + + ui_vp_chatbox = new AOImage(this, ao_app); + ui_vp_showname = new QLabel(ui_vp_chatbox); + ui_vp_message = new QTextEdit(ui_vp_chatbox); + ui_vp_message->setFrameStyle(QFrame::NoFrame); + ui_vp_message->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + ui_vp_message->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + ui_vp_message->setReadOnly(true); + + ui_vp_testimony = new AOImage(this, ao_app); + ui_vp_realization = new AOImage(this, ao_app); + ui_vp_wtce = new AOMovie(this, ao_app); + ui_vp_objection = new AOMovie(this, ao_app); + + ui_ic_chatlog = new QTextEdit(this); + ui_ic_chatlog->setReadOnly(true); + + log_maximum_blocks = ao_app->get_max_log_size(); + log_goes_downwards = ao_app->get_log_goes_downwards(); + + ui_ms_chatlog = new AOTextArea(this); + ui_ms_chatlog->setReadOnly(true); + ui_ms_chatlog->setOpenExternalLinks(true); + ui_ms_chatlog->hide(); + + ui_server_chatlog = new AOTextArea(this); + ui_server_chatlog->setReadOnly(true); + ui_server_chatlog->setOpenExternalLinks(true); + + ui_area_list = new QListWidget(this); + ui_area_list->hide(); + ui_music_list = new QListWidget(this); + + ui_ic_chat_name = new QLineEdit(this); + ui_ic_chat_name->setFrame(false); + ui_ic_chat_name->setPlaceholderText(tr("Showname")); + + ui_ic_chat_message = new QLineEdit(this); + ui_ic_chat_message->setFrame(false); + ui_ic_chat_message->setPlaceholderText(tr("Message")); + + ui_muted = new AOImage(ui_ic_chat_message, ao_app); + ui_muted->hide(); + + ui_ooc_chat_message = new QLineEdit(this); + ui_ooc_chat_message->setFrame(false); + + ui_ooc_chat_name = new QLineEdit(this); + ui_ooc_chat_name->setFrame(false); + ui_ooc_chat_name->setPlaceholderText("Name"); + ui_ooc_chat_name->setMaxLength(30); + ui_ooc_chat_name->setText(p_ao_app->get_default_username()); + + //ui_area_password = new QLineEdit(this); + //ui_area_password->setFrame(false); + ui_music_search = new QLineEdit(this); + ui_music_search->setFrame(false); + ui_music_search->setPlaceholderText(tr("Search")); + + construct_emotes(); + + ui_emote_left = new AOButton(this, ao_app); + ui_emote_right = new AOButton(this, ao_app); + + ui_emote_dropdown = new QComboBox(this); + ui_pos_dropdown = new QComboBox(this); + ui_pos_dropdown->addItem("wit"); + ui_pos_dropdown->addItem("def"); + ui_pos_dropdown->addItem("pro"); + ui_pos_dropdown->addItem("jud"); + ui_pos_dropdown->addItem("hld"); + ui_pos_dropdown->addItem("hlp"); + ui_pos_dropdown->addItem("jur"); + ui_pos_dropdown->addItem("sea"); + + ui_defense_bar = new AOImage(this, ao_app); + ui_prosecution_bar = new AOImage(this, ao_app); + + ui_music_label = new QLabel(this); + ui_sfx_label = new QLabel(this); + ui_blip_label = new QLabel(this); + + ui_log_limit_label = new QLabel(this); + + ui_hold_it = new AOButton(this, ao_app); + ui_objection = new AOButton(this, ao_app); + ui_take_that = new AOButton(this, ao_app); + + ui_ooc_toggle = new AOButton(this, ao_app); + ui_witness_testimony = new AOButton(this, ao_app); + ui_cross_examination = new AOButton(this, ao_app); + ui_guilty = new AOButton(this, ao_app); + ui_not_guilty = new AOButton(this, ao_app); + + ui_change_character = new AOButton(this, ao_app); + ui_reload_theme = new AOButton(this, ao_app); + ui_call_mod = new AOButton(this, ao_app); + ui_settings = new AOButton(this, ao_app); + ui_announce_casing = new AOButton(this, ao_app); + ui_switch_area_music = new AOButton(this, ao_app); + + ui_pre = new QCheckBox(this); + ui_pre->setText("Pre"); + + ui_flip = new QCheckBox(this); + ui_flip->setText("Flip"); + ui_flip->hide(); + + ui_guard = new QCheckBox(this); + ui_guard->setText("Guard"); + ui_guard->hide(); + + ui_casing = new QCheckBox(this); + ui_casing->setChecked(ao_app->get_casing_enabled()); + ui_casing->setText(tr("Casing")); + ui_casing->hide(); + + ui_showname_enable = new QCheckBox(this); + ui_showname_enable->setChecked(ao_app->get_showname_enabled_by_default()); + ui_showname_enable->setText(tr("Shownames")); + + ui_pre_non_interrupt = new QCheckBox(this); + ui_pre_non_interrupt->setText(tr("No Interrupt")); + ui_pre_non_interrupt->hide(); + + ui_custom_objection = new AOButton(this, ao_app); + ui_realization = new AOButton(this, ao_app); + ui_mute = new AOButton(this, ao_app); + + ui_defense_plus = new AOButton(this, ao_app); + ui_defense_minus = new AOButton(this, ao_app); + + ui_prosecution_plus = new AOButton(this, ao_app); + ui_prosecution_minus = new AOButton(this, ao_app); + + ui_text_color = new QComboBox(this); + ui_text_color->addItem("White"); + ui_text_color->addItem("Green"); + ui_text_color->addItem("Red"); + ui_text_color->addItem("Orange"); + ui_text_color->addItem("Blue"); + ui_text_color->addItem("Yellow"); + ui_text_color->addItem("Rainbow"); + ui_text_color->addItem("Pink"); + ui_text_color->addItem("Cyan"); + + ui_music_slider = new QSlider(Qt::Horizontal, this); + ui_music_slider->setRange(0, 100); + ui_music_slider->setValue(ao_app->get_default_music()); + + ui_sfx_slider = new QSlider(Qt::Horizontal, this); + ui_sfx_slider->setRange(0, 100); + ui_sfx_slider->setValue(ao_app->get_default_sfx()); + + ui_blip_slider = new QSlider(Qt::Horizontal, this); + ui_blip_slider->setRange(0, 100); + ui_blip_slider->setValue(ao_app->get_default_blip()); + + ui_log_limit_spinbox = new QSpinBox(this); + ui_log_limit_spinbox->setRange(0, 10000); + ui_log_limit_spinbox->setValue(ao_app->get_max_log_size()); + + ui_mute_list = new QListWidget(this); + + ui_pair_list = new QListWidget(this); + ui_pair_offset_spinbox = new QSpinBox(this); + ui_pair_offset_spinbox->setRange(-100,100); + ui_pair_offset_spinbox->setSuffix("% offset"); + ui_pair_button = new AOButton(this, ao_app); + + ui_evidence_button = new AOButton(this, ao_app); + + construct_evidence(); + + construct_char_select(); + + connect(keepalive_timer, SIGNAL(timeout()), this, SLOT(ping_server())); + + connect(ui_vp_objection, SIGNAL(done()), this, SLOT(objection_done())); + connect(ui_vp_player_char, SIGNAL(done()), this, SLOT(preanim_done())); + + connect(text_delay_timer, SIGNAL(timeout()), this, SLOT(start_chat_ticking())); + connect(sfx_delay_timer, SIGNAL(timeout()), this, SLOT(play_sfx())); + + connect(chat_tick_timer, SIGNAL(timeout()), this, SLOT(chat_tick())); + + connect(realization_timer, SIGNAL(timeout()), this, SLOT(realization_done())); + + connect(testimony_show_timer, SIGNAL(timeout()), this, SLOT(hide_testimony())); + connect(testimony_hide_timer, SIGNAL(timeout()), this, SLOT(show_testimony())); + + connect(ui_emote_left, SIGNAL(clicked()), this, SLOT(on_emote_left_clicked())); + connect(ui_emote_right, SIGNAL(clicked()), this, SLOT(on_emote_right_clicked())); + + connect(ui_emote_dropdown, SIGNAL(activated(int)), this, SLOT(on_emote_dropdown_changed(int))); + connect(ui_pos_dropdown, SIGNAL(currentIndexChanged(int)), this, SLOT(on_pos_dropdown_changed(int))); + + connect(ui_mute_list, SIGNAL(clicked(QModelIndex)), this, SLOT(on_mute_list_clicked(QModelIndex))); + + connect(ui_ic_chat_message, SIGNAL(returnPressed()), this, SLOT(on_chat_return_pressed())); + + connect(ui_ooc_chat_message, SIGNAL(returnPressed()), this, SLOT(on_ooc_return_pressed())); + + connect(ui_music_list, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(on_music_list_double_clicked(QModelIndex))); + connect(ui_area_list, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(on_area_list_double_clicked(QModelIndex))); + + connect(ui_hold_it, SIGNAL(clicked()), this, SLOT(on_hold_it_clicked())); + connect(ui_objection, SIGNAL(clicked()), this, SLOT(on_objection_clicked())); + connect(ui_take_that, SIGNAL(clicked()), this, SLOT(on_take_that_clicked())); + connect(ui_custom_objection, SIGNAL(clicked()), this, SLOT(on_custom_objection_clicked())); + + connect(ui_realization, SIGNAL(clicked()), this, SLOT(on_realization_clicked())); + + connect(ui_mute, SIGNAL(clicked()), this, SLOT(on_mute_clicked())); + + connect(ui_defense_minus, SIGNAL(clicked()), this, SLOT(on_defense_minus_clicked())); + connect(ui_defense_plus, SIGNAL(clicked()), this, SLOT(on_defense_plus_clicked())); + connect(ui_prosecution_minus, SIGNAL(clicked()), this, SLOT(on_prosecution_minus_clicked())); + connect(ui_prosecution_plus, SIGNAL(clicked()), this, SLOT(on_prosecution_plus_clicked())); + + connect(ui_text_color, SIGNAL(currentIndexChanged(int)), this, SLOT(on_text_color_changed(int))); + + connect(ui_music_slider, SIGNAL(valueChanged(int)), this, SLOT(on_music_slider_moved(int))); + connect(ui_sfx_slider, SIGNAL(valueChanged(int)), this, SLOT(on_sfx_slider_moved(int))); + connect(ui_blip_slider, SIGNAL(valueChanged(int)), this, SLOT(on_blip_slider_moved(int))); + + connect(ui_log_limit_spinbox, SIGNAL(valueChanged(int)), this, SLOT(on_log_limit_changed(int))); + + connect(ui_ooc_toggle, SIGNAL(clicked()), this, SLOT(on_ooc_toggle_clicked())); + + connect(ui_music_search, SIGNAL(textChanged(QString)), this, SLOT(on_music_search_edited(QString))); + + connect(ui_witness_testimony, SIGNAL(clicked()), this, SLOT(on_witness_testimony_clicked())); + connect(ui_cross_examination, SIGNAL(clicked()), this, SLOT(on_cross_examination_clicked())); + connect(ui_guilty, SIGNAL(clicked()), this, SLOT(on_guilty_clicked())); + connect(ui_not_guilty, SIGNAL(clicked()), this, SLOT(on_not_guilty_clicked())); + + connect(ui_change_character, SIGNAL(clicked()), this, SLOT(on_change_character_clicked())); + connect(ui_reload_theme, SIGNAL(clicked()), this, SLOT(on_reload_theme_clicked())); + connect(ui_call_mod, SIGNAL(clicked()), this, SLOT(on_call_mod_clicked())); + connect(ui_settings, SIGNAL(clicked()), this, SLOT(on_settings_clicked())); + connect(ui_announce_casing, SIGNAL(clicked()), this, SLOT(on_announce_casing_clicked())); + connect(ui_switch_area_music, SIGNAL(clicked()), this, SLOT(on_switch_area_music_clicked())); + + connect(ui_pre, SIGNAL(clicked()), this, SLOT(on_pre_clicked())); + connect(ui_flip, SIGNAL(clicked()), this, SLOT(on_flip_clicked())); + connect(ui_guard, SIGNAL(clicked()), this, SLOT(on_guard_clicked())); + connect(ui_casing, SIGNAL(clicked()), this, SLOT(on_casing_clicked())); + + connect(ui_showname_enable, SIGNAL(clicked()), this, SLOT(on_showname_enable_clicked())); + + connect(ui_pair_button, SIGNAL(clicked()), this, SLOT(on_pair_clicked())); + connect(ui_pair_list, SIGNAL(clicked(QModelIndex)), this, SLOT(on_pair_list_clicked(QModelIndex))); + connect(ui_pair_offset_spinbox, SIGNAL(valueChanged(int)), this, SLOT(on_pair_offset_changed(int))); + + connect(ui_evidence_button, SIGNAL(clicked()), this, SLOT(on_evidence_button_clicked())); + + set_widgets(); + + set_char_select(); +} + +void Courtroom::set_mute_list() +{ + mute_map.clear(); + + //maps which characters are muted based on cid, none are muted by default + for (int n_cid = 0 ; n_cid < char_list.size() ; n_cid++) + { + mute_map.insert(n_cid, false); + } + + QStringList sorted_mute_list; + + for (char_type i_char : char_list) + sorted_mute_list.append(i_char.name); + + sorted_mute_list.sort(); + + for (QString i_name : sorted_mute_list) + { + //mute_map.insert(i_name, false); + ui_mute_list->addItem(i_name); + } +} + +void Courtroom::set_pair_list() +{ + QStringList sorted_pair_list; + + for (char_type i_char : char_list) + sorted_pair_list.append(i_char.name); + + sorted_pair_list.sort(); + + for (QString i_name : sorted_pair_list) + { + ui_pair_list->addItem(i_name); + } +} + +void Courtroom::set_widgets() +{ + blip_rate = ao_app->read_blip_rate(); + blank_blip = ao_app->get_blank_blip(); + + QString filename = "courtroom_design.ini"; + + pos_size_type f_courtroom = ao_app->get_element_dimensions("courtroom", filename); + + if (f_courtroom.width < 0 || f_courtroom.height < 0) + { + qDebug() << "W: did not find courtroom width or height in " << filename; + + this->resize(714, 668); + } + else + { + m_courtroom_width = f_courtroom.width; + m_courtroom_height = f_courtroom.height; + + this->resize(f_courtroom.width, f_courtroom.height); + } + + set_fonts(); + + ui_background->move(0, 0); + ui_background->resize(m_courtroom_width, m_courtroom_height); + ui_background->set_image("courtroombackground.png"); + + set_size_and_pos(ui_viewport, "viewport"); + + // 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_support_enabled) + { + ui_pair_button->show(); + ui_pre_non_interrupt->show(); + ui_showname_enable->show(); + ui_ic_chat_name->show(); + ui_ic_chat_name->setEnabled(true); + } + else + { + ui_pair_button->hide(); + ui_pre_non_interrupt->hide(); + ui_showname_enable->hide(); + ui_ic_chat_name->hide(); + ui_ic_chat_name->setEnabled(false); + } + + if (ao_app->casing_alerts_enabled) + { + ui_announce_casing->show(); + } + else + { + ui_announce_casing->hide(); + } + + // We also show the non-server-dependent client additions. + // Once again, if the theme can't display it, set_move_and_pos will catch them. + ui_settings->show(); + ui_log_limit_label->show(); + ui_log_limit_spinbox->show(); + + ui_vp_background->move(0, 0); + ui_vp_background->resize(ui_viewport->width(), ui_viewport->height()); + + ui_vp_speedlines->move(0, 0); + ui_vp_speedlines->combo_resize(ui_viewport->width(), ui_viewport->height()); + + ui_vp_player_char->move(0, 0); + ui_vp_player_char->combo_resize(ui_viewport->width(), ui_viewport->height()); + + ui_vp_sideplayer_char->move(0, 0); + ui_vp_sideplayer_char->combo_resize(ui_viewport->width(), ui_viewport->height()); + + //the AO2 desk element + ui_vp_desk->move(0, 0); + ui_vp_desk->resize(ui_viewport->width(), ui_viewport->height()); + + //the size of the ui_vp_legacy_desk element relies on various factors and is set in set_scene() + + double y_modifier = 147.0 / 192.0; + int final_y = static_cast(y_modifier * ui_viewport->height()); + ui_vp_legacy_desk->move(0, final_y); + ui_vp_legacy_desk->hide(); + + ui_vp_evidence_display->move(0, 0); + ui_vp_evidence_display->resize(ui_viewport->width(), ui_viewport->height()); + + set_size_and_pos(ui_vp_showname, "showname"); + + set_size_and_pos(ui_vp_message, "message"); + ui_vp_message->setTextInteractionFlags(Qt::NoTextInteraction); + ui_vp_message->setStyleSheet("background-color: rgba(0, 0, 0, 0);" + "color: white"); + + ui_vp_testimony->move(ui_viewport->x(), ui_viewport->y()); + ui_vp_testimony->resize(ui_viewport->width(), ui_viewport->height()); + ui_vp_testimony->set_image("testimony.png"); + ui_vp_testimony->hide(); + + ui_vp_realization->move(ui_viewport->x(), ui_viewport->y()); + ui_vp_realization->resize(ui_viewport->width(), ui_viewport->height()); + ui_vp_realization->set_image("realizationflash.png"); + ui_vp_realization->hide(); + + ui_vp_wtce->move(ui_viewport->x(), ui_viewport->y()); + ui_vp_wtce->combo_resize(ui_viewport->width(), ui_viewport->height()); + + ui_vp_objection->move(ui_viewport->x(), ui_viewport->y()); + ui_vp_objection->combo_resize(ui_viewport->width(), ui_viewport->height()); + + set_size_and_pos(ui_ic_chatlog, "ic_chatlog"); + + set_size_and_pos(ui_ms_chatlog, "ms_chatlog"); + + set_size_and_pos(ui_server_chatlog, "server_chatlog"); + + 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(); + set_size_and_pos(ui_pair_offset_spinbox, "pair_offset_spinbox"); + ui_pair_offset_spinbox->hide(); + set_size_and_pos(ui_pair_button, "pair_button"); + ui_pair_button->set_image("pair_button.png"); + + set_size_and_pos(ui_area_list, "music_list"); + ui_area_list->setStyleSheet("background-color: rgba(0, 0, 0, 0);"); + + set_size_and_pos(ui_music_list, "music_list"); + + if (is_ao2_bg) + { + set_size_and_pos(ui_ic_chat_message, "ao2_ic_chat_message"); + set_size_and_pos(ui_vp_chatbox, "ao2_chatbox"); + set_size_and_pos(ui_ic_chat_name, "ao2_ic_chat_name"); + } + else + { + set_size_and_pos(ui_ic_chat_message, "ic_chat_message"); + set_size_and_pos(ui_vp_chatbox, "chatbox"); + set_size_and_pos(ui_ic_chat_name, "ic_chat_name"); + } + + ui_ic_chat_message->setStyleSheet("QLineEdit{background-color: rgba(100, 100, 100, 255);}"); + ui_ic_chat_name->setStyleSheet("QLineEdit{background-color: rgba(180, 180, 180, 255);}"); + + ui_vp_chatbox->set_image("chatmed.png"); + ui_vp_chatbox->hide(); + + ui_muted->resize(ui_ic_chat_message->width(), ui_ic_chat_message->height()); + ui_muted->set_image("muted.png"); + + set_size_and_pos(ui_ooc_chat_message, "ooc_chat_message"); + ui_ooc_chat_message->setStyleSheet("background-color: rgba(0, 0, 0, 0);"); + + set_size_and_pos(ui_ooc_chat_name, "ooc_chat_name"); + ui_ooc_chat_name->setStyleSheet("background-color: rgba(0, 0, 0, 0);"); + + //set_size_and_pos(ui_area_password, "area_password"); + set_size_and_pos(ui_music_search, "music_search"); + + set_size_and_pos(ui_emotes, "emotes"); + + set_size_and_pos(ui_emote_left, "emote_left"); + ui_emote_left->set_image("arrow_left.png"); + + set_size_and_pos(ui_emote_right, "emote_right"); + ui_emote_right->set_image("arrow_right.png"); + + set_size_and_pos(ui_emote_dropdown, "emote_dropdown"); + set_size_and_pos(ui_pos_dropdown, "pos_dropdown"); + + set_size_and_pos(ui_defense_bar, "defense_bar"); + ui_defense_bar->set_image("defensebar" + QString::number(defense_bar_state) + ".png"); + + set_size_and_pos(ui_prosecution_bar, "prosecution_bar"); + ui_prosecution_bar->set_image("prosecutionbar" + QString::number(prosecution_bar_state) + ".png"); + + set_size_and_pos(ui_music_label, "music_label"); + ui_music_label->setText("Music"); + set_size_and_pos(ui_sfx_label, "sfx_label"); + ui_sfx_label->setText("Sfx"); + set_size_and_pos(ui_blip_label, "blip_label"); + ui_blip_label->setText("Blips"); + + set_size_and_pos(ui_log_limit_label, "log_limit_label"); + ui_log_limit_label->setText("Log limit"); + + set_size_and_pos(ui_hold_it, "hold_it"); + ui_hold_it->set_image("holdit.png"); + set_size_and_pos(ui_objection, "objection"); + ui_objection->set_image("objection.png"); + set_size_and_pos(ui_take_that, "take_that"); + ui_take_that->set_image("takethat.png"); + + set_size_and_pos(ui_ooc_toggle, "ooc_toggle"); + ui_ooc_toggle->setText("Server"); + + set_size_and_pos(ui_witness_testimony, "witness_testimony"); + ui_witness_testimony->set_image("witnesstestimony.png"); + set_size_and_pos(ui_cross_examination, "cross_examination"); + ui_cross_examination->set_image("crossexamination.png"); + + set_size_and_pos(ui_guilty, "guilty"); + ui_guilty->set_image("guilty.png"); + set_size_and_pos(ui_not_guilty, "not_guilty"); + ui_not_guilty->set_image("notguilty.png"); + + set_size_and_pos(ui_change_character, "change_character"); + ui_change_character->setText("Change character"); + + set_size_and_pos(ui_reload_theme, "reload_theme"); + ui_reload_theme->setText("Reload theme"); + + set_size_and_pos(ui_call_mod, "call_mod"); + ui_call_mod->setText("Call mod"); + + set_size_and_pos(ui_settings, "settings"); + ui_settings->setText("Settings"); + + set_size_and_pos(ui_announce_casing, "casing_button"); + ui_announce_casing->setText("Casing"); + + set_size_and_pos(ui_switch_area_music, "switch_area_music"); + ui_switch_area_music->setText("A/M"); + + set_size_and_pos(ui_pre, "pre"); + ui_pre->setText("Preanim"); + + set_size_and_pos(ui_pre_non_interrupt, "pre_no_interrupt"); + set_size_and_pos(ui_flip, "flip"); + + set_size_and_pos(ui_guard, "guard"); + + set_size_and_pos(ui_casing, "casing"); + + set_size_and_pos(ui_showname_enable, "showname_enable"); + + set_size_and_pos(ui_custom_objection, "custom_objection"); + ui_custom_objection->set_image("custom.png"); + + set_size_and_pos(ui_realization, "realization"); + ui_realization->set_image("realization.png"); + + set_size_and_pos(ui_mute, "mute_button"); + ui_mute->set_image("mute.png"); + + set_size_and_pos(ui_defense_plus, "defense_plus"); + ui_defense_plus->set_image("defplus.png"); + + set_size_and_pos(ui_defense_minus, "defense_minus"); + ui_defense_minus->set_image("defminus.png"); + + set_size_and_pos(ui_prosecution_plus, "prosecution_plus"); + ui_prosecution_plus->set_image("proplus.png"); + + set_size_and_pos(ui_prosecution_minus, "prosecution_minus"); + ui_prosecution_minus->set_image("prominus.png"); + + set_size_and_pos(ui_text_color, "text_color"); + + set_size_and_pos(ui_music_slider, "music_slider"); + set_size_and_pos(ui_sfx_slider, "sfx_slider"); + set_size_and_pos(ui_blip_slider, "blip_slider"); + + set_size_and_pos(ui_log_limit_spinbox, "log_limit_spinbox"); + + set_size_and_pos(ui_evidence_button, "evidence_button"); + ui_evidence_button->set_image("evidencebutton.png"); + + set_size_and_pos(ui_evidence, "evidence_background"); + ui_evidence->set_image("evidencebackground.png"); + + set_size_and_pos(ui_evidence_name, "evidence_name"); + + set_size_and_pos(ui_evidence_buttons, "evidence_buttons"); + + set_size_and_pos(ui_evidence_left, "evidence_left"); + ui_evidence_left->set_image("arrow_left.png"); + + set_size_and_pos(ui_evidence_right, "evidence_right"); + ui_evidence_right->set_image("arrow_right.png"); + + set_size_and_pos(ui_evidence_present, "evidence_present"); + ui_evidence_present->set_image("present_disabled.png"); + + set_size_and_pos(ui_evidence_overlay, "evidence_overlay"); + ui_evidence_overlay->set_image("evidenceoverlay.png"); + + set_size_and_pos(ui_evidence_delete, "evidence_delete"); + ui_evidence_delete->set_image("deleteevidence.png"); + + set_size_and_pos(ui_evidence_image_name, "evidence_image_name"); + + set_size_and_pos(ui_evidence_image_button, "evidence_image_button"); + + set_size_and_pos(ui_evidence_x, "evidence_x"); + ui_evidence_x->set_image("evidencex.png"); + + set_size_and_pos(ui_evidence_description, "evidence_description"); + + ui_selector->set_image("char_selector.png"); + ui_selector->hide(); + + set_size_and_pos(ui_back_to_lobby, "back_to_lobby"); + ui_back_to_lobby->setText("Back to Lobby"); + + set_size_and_pos(ui_char_password, "char_password"); + + set_size_and_pos(ui_char_buttons, "char_buttons"); + + set_size_and_pos(ui_char_select_left, "char_select_left"); + ui_char_select_left->set_image("arrow_left.png"); + + set_size_and_pos(ui_char_select_right, "char_select_right"); + ui_char_select_right->set_image("arrow_right.png"); + + set_size_and_pos(ui_spectator, "spectator"); +} + +void Courtroom::set_fonts() +{ + set_font(ui_vp_showname, "showname"); + set_font(ui_vp_message, "message"); + set_font(ui_ic_chatlog, "ic_chatlog"); + set_font(ui_ms_chatlog, "ms_chatlog"); + set_font(ui_server_chatlog, "server_chatlog"); + set_font(ui_music_list, "music_list"); + set_font(ui_area_list, "music_list"); + + // Set color of labels and checkboxes + const QString design_file = "courtroom_fonts.ini"; + QColor f_color = ao_app->get_color("label_color", design_file); + QString color_string = "color: rgba(" + + QString::number(f_color.red()) + ", " + + QString::number(f_color.green()) + ", " + + QString::number(f_color.blue()) + ", 255); }"; + QString style_sheet_string = "QLabel {" + color_string + "}" + "QCheckBox {" + color_string + "}"; + setStyleSheet(style_sheet_string); +} + +void Courtroom::set_font(QWidget *widget, QString p_identifier) +{ + QString design_file = "courtroom_fonts.ini"; + int f_weight = ao_app->get_font_size(p_identifier, design_file); + QString class_name = widget->metaObject()->className(); + + QString fontt = ao_app->get_font_name(p_identifier + "_font", design_file); + widget->setFont(QFont(fontt, f_weight)); + + + QColor f_color = ao_app->get_color(p_identifier + "_color", design_file); + + QString style_sheet_string = class_name + " { background-color: rgba(0, 0, 0, 0);\n" + + "color: rgba(" + + QString::number(f_color.red()) + ", " + + QString::number(f_color.green()) + ", " + + QString::number(f_color.blue()) + ", 255); }"; + + widget->setStyleSheet(style_sheet_string); +} + +void Courtroom::set_window_title(QString p_title) +{ + this->setWindowTitle(p_title); +} + +void Courtroom::set_size_and_pos(QWidget *p_widget, QString p_identifier) +{ + QString filename = "courtroom_design.ini"; + + pos_size_type design_ini_result = ao_app->get_element_dimensions(p_identifier, filename); + + if (design_ini_result.width < 0 || design_ini_result.height < 0) + { + qDebug() << "W: could not find \"" << p_identifier << "\" in " << filename; + p_widget->hide(); + } + else + { + p_widget->move(design_ini_result.x, design_ini_result.y); + p_widget->resize(design_ini_result.width, design_ini_result.height); + } +} + +void Courtroom::set_taken(int n_char, bool p_taken) +{ + if (n_char >= char_list.size()) + { + qDebug() << "W: set_taken attempted to set an index bigger than char_list size"; + return; + } + + char_type f_char; + f_char.name = char_list.at(n_char).name; + f_char.description = char_list.at(n_char).description; + f_char.taken = p_taken; + f_char.evidence_string = char_list.at(n_char).evidence_string; + + char_list.replace(n_char, f_char); +} + +void Courtroom::done_received() +{ + m_cid = -1; + + music_player->set_volume(0); + sfx_player->set_volume(0); + objection_player->set_volume(0); + blip_player->set_volume(0); + + set_char_select_page(); + + set_mute_list(); + set_pair_list(); + + set_char_select(); + + show(); + + ui_spectator->show(); +} + +void Courtroom::set_background(QString p_background) +{ + testimony_in_progress = false; + + current_background = p_background; + + is_ao2_bg = file_exists(ao_app->get_background_path("defensedesk.png")) && + file_exists(ao_app->get_background_path("prosecutiondesk.png")) && + file_exists(ao_app->get_background_path("stand.png")); + + if (is_ao2_bg) + { + set_size_and_pos(ui_vp_chatbox, "ao2_chatbox"); + set_size_and_pos(ui_ic_chat_message, "ao2_ic_chat_message"); + } + else + { + set_size_and_pos(ui_vp_chatbox, "chatbox"); + set_size_and_pos(ui_ic_chat_message, "ic_chat_message"); + } +} + +void Courtroom::enter_courtroom(int p_cid) +{ + m_cid = p_cid; + + QString f_char; + + if (m_cid == -1) + { + if (ao_app->is_discord_enabled()) + ao_app->discord->state_spectate(); + f_char = ""; + } + else + { + f_char = ao_app->get_char_name(char_list.at(m_cid).name); + + if (ao_app->is_discord_enabled()) + ao_app->discord->state_character(f_char.toStdString()); + } + + current_char = f_char; + + current_emote_page = 0; + current_emote = 0; + + if (m_cid == -1) + ui_emotes->hide(); + else + ui_emotes->show(); + + set_emote_page(); + set_emote_dropdown(); + + current_evidence_page = 0; + current_evidence = 0; + + set_evidence_page(); + + QString side = ao_app->get_char_side(f_char); + + if (side == "jud") + { + ui_witness_testimony->show(); + ui_cross_examination->show(); + ui_not_guilty->show(); + ui_guilty->show(); + ui_defense_minus->show(); + ui_defense_plus->show(); + ui_prosecution_minus->show(); + ui_prosecution_plus->show(); + } + else + { + ui_witness_testimony->hide(); + ui_cross_examination->hide(); + ui_guilty->hide(); + ui_not_guilty->hide(); + ui_defense_minus->hide(); + ui_defense_plus->hide(); + ui_prosecution_minus->hide(); + ui_prosecution_plus->hide(); + } + + if (ao_app->custom_objection_enabled && + (file_exists(ao_app->get_character_path(current_char, "custom.gif")) || + file_exists(ao_app->get_character_path(current_char, "custom.apng"))) && + file_exists(ao_app->get_character_path(current_char, "custom.wav"))) + ui_custom_objection->show(); + else + ui_custom_objection->hide(); + + if (ao_app->flipping_enabled) + ui_flip->show(); + else + ui_flip->hide(); + + if (ao_app->casing_alerts_enabled) + ui_casing->show(); + else + ui_casing->hide(); + + list_music(); + list_areas(); + + music_player->set_volume(ui_music_slider->value()); + sfx_player->set_volume(ui_sfx_slider->value()); + objection_player->set_volume(ui_sfx_slider->value()); + blip_player->set_volume(ui_blip_slider->value()); + + testimony_in_progress = false; + + set_widgets(); + + //ui_server_chatlog->setHtml(ui_server_chatlog->toHtml()); + + ui_char_select_background->hide(); + + ui_ic_chat_message->setEnabled(m_cid != -1); + ui_ic_chat_message->setFocus(); +} + +void Courtroom::list_music() +{ + ui_music_list->clear(); + music_row_to_number.clear(); + + QString f_file = "courtroom_design.ini"; + + QBrush found_brush(ao_app->get_color("found_song_color", f_file)); + QBrush missing_brush(ao_app->get_color("missing_song_color", f_file)); + + int n_listed_songs = 0; + + for (int n_song = 0 ; n_song < music_list.size() ; ++n_song) + { + QString i_song = music_list.at(n_song); + QString i_song_listname = i_song; + i_song_listname = i_song_listname.left(i_song_listname.lastIndexOf(".")); + + if (i_song.toLower().contains(ui_music_search->text().toLower())) + { + ui_music_list->addItem(i_song_listname); + music_row_to_number.append(n_song); + + QString song_path = ao_app->get_music_path(i_song); + + if (file_exists(song_path)) + ui_music_list->item(n_listed_songs)->setBackground(found_brush); + else + ui_music_list->item(n_listed_songs)->setBackground(missing_brush); + + ++n_listed_songs; + } + } +} + +void Courtroom::list_areas() +{ + ui_area_list->clear(); + area_row_to_number.clear(); + + QString f_file = "courtroom_design.ini"; + + QBrush free_brush(ao_app->get_color("area_free_color", f_file)); + QBrush lfp_brush(ao_app->get_color("area_lfp_color", f_file)); + QBrush casing_brush(ao_app->get_color("area_casing_color", f_file)); + QBrush recess_brush(ao_app->get_color("area_recess_color", f_file)); + QBrush rp_brush(ao_app->get_color("area_rp_color", f_file)); + QBrush gaming_brush(ao_app->get_color("area_gaming_color", f_file)); + QBrush locked_brush(ao_app->get_color("area_locked_color", f_file)); + + int n_listed_areas = 0; + + for (int n_area = 0 ; n_area < area_list.size() ; ++n_area) + { + QString i_area = ""; + i_area.append("["); + i_area.append(QString::number(n_area)); + i_area.append("] "); + + i_area.append(area_list.at(n_area)); + + if (ao_app->arup_enabled) + { + i_area.append("\n "); + + i_area.append(arup_statuses.at(n_area)); + i_area.append(" | CM: "); + i_area.append(arup_cms.at(n_area)); + + i_area.append("\n "); + + i_area.append(QString::number(arup_players.at(n_area))); + i_area.append(" users | "); + + i_area.append(arup_locks.at(n_area)); + } + + if (i_area.toLower().contains(ui_music_search->text().toLower())) + { + ui_area_list->addItem(i_area); + area_row_to_number.append(n_area); + + if (ao_app->arup_enabled) + { + // Colouring logic here. + ui_area_list->item(n_listed_areas)->setBackground(free_brush); + if (arup_locks.at(n_area) == "LOCKED") + { + ui_area_list->item(n_listed_areas)->setBackground(locked_brush); + } + else + { + if (arup_statuses.at(n_area) == "LOOKING-FOR-PLAYERS") + ui_area_list->item(n_listed_areas)->setBackground(lfp_brush); + else if (arup_statuses.at(n_area) == "CASING") + ui_area_list->item(n_listed_areas)->setBackground(casing_brush); + else if (arup_statuses.at(n_area) == "RECESS") + ui_area_list->item(n_listed_areas)->setBackground(recess_brush); + else if (arup_statuses.at(n_area) == "RP") + ui_area_list->item(n_listed_areas)->setBackground(rp_brush); + else if (arup_statuses.at(n_area) == "GAMING") + ui_area_list->item(n_listed_areas)->setBackground(gaming_brush); + } + } + else + { + ui_area_list->item(n_listed_areas)->setBackground(free_brush); + } + + ++n_listed_areas; + } + } +} + +void Courtroom::append_ms_chatmessage(QString f_name, QString f_message) +{ + ui_ms_chatlog->append_chatmessage(f_name, f_message, ao_app->get_color("ooc_default_color", "courtroom_design.ini").name()); +} + +void Courtroom::append_server_chatmessage(QString p_name, QString p_message, QString p_colour) +{ + QString colour = "#000000"; + + if (p_colour == "0") + colour = ao_app->get_color("ooc_default_color", "courtroom_design.ini").name(); + if (p_colour == "1") + colour = ao_app->get_color("ooc_server_color", "courtroom_design.ini").name(); + + ui_server_chatlog->append_chatmessage(p_name, p_message, colour); +} + +void Courtroom::on_chat_return_pressed() +{ + if (ui_ic_chat_message->text() == "" || is_muted) + return; + + if ((anim_state < 3 || text_state < 2) && + objection_state == 0) + return; + + //MS# + //deskmod# + //pre-emote# + //character# + //emote# + //message# + //side# + //sfx-name# + //emote_modifier# + //char_id# + //sfx_delay# + //objection_modifier# + //evidence# + //placeholder# + //realization# + //text_color#% + + // Additionally, in our case: + + //showname# + //other_charid# + //self_offset# + //noninterrupting_preanim#% + + QStringList packet_contents; + + QString f_side = ao_app->get_char_side(current_char); + + QString f_desk_mod = "chat"; + + if (ao_app->desk_mod_enabled) + { + f_desk_mod = QString::number(ao_app->get_desk_mod(current_char, current_emote)); + if (f_desk_mod == "-1") + f_desk_mod = "chat"; + } + + packet_contents.append(f_desk_mod); + + packet_contents.append(ao_app->get_pre_emote(current_char, current_emote)); + + packet_contents.append(current_char); + + packet_contents.append(ao_app->get_emote(current_char, current_emote)); + + packet_contents.append(ui_ic_chat_message->text()); + + packet_contents.append(f_side); + + packet_contents.append(ao_app->get_sfx_name(current_char, current_emote)); + + int f_emote_mod = ao_app->get_emote_mod(current_char, current_emote); + + //needed or else legacy won't understand what we're saying + if (objection_state > 0) + { + if (ui_pre->isChecked()) + { + if (f_emote_mod == 5) + f_emote_mod = 6; + else + f_emote_mod = 2; + } + } + else if (ui_pre->isChecked() and !ui_pre_non_interrupt->isChecked()) + { + if (f_emote_mod == 0) + f_emote_mod = 1; + else if (f_emote_mod == 5 && ao_app->prezoom_enabled) + f_emote_mod = 4; + } + else + { + if (f_emote_mod == 1) + f_emote_mod = 0; + else if (f_emote_mod == 4) + f_emote_mod = 5; + } + + packet_contents.append(QString::number(f_emote_mod)); + packet_contents.append(QString::number(m_cid)); + + packet_contents.append(QString::number(ao_app->get_sfx_delay(current_char, current_emote))); + + QString f_obj_state; + + if ((objection_state == 4 && !ao_app->custom_objection_enabled) || + (objection_state < 0)) + f_obj_state = "0"; + else + f_obj_state = QString::number(objection_state); + + packet_contents.append(f_obj_state); + + if (is_presenting_evidence) + //the evidence index is shifted by 1 because 0 is no evidence per legacy standards + //besides, older clients crash if we pass -1 + packet_contents.append(QString::number(current_evidence + 1)); + else + packet_contents.append("0"); + + QString f_flip; + + if (ao_app->flipping_enabled) + { + if (ui_flip->isChecked()) + f_flip = "1"; + else + f_flip = "0"; + } + else + f_flip = QString::number(m_cid); + + packet_contents.append(f_flip); + + packet_contents.append(QString::number(realization_state)); + + QString f_text_color; + + if (text_color < 0) + f_text_color = "0"; + else if (text_color > 8) + f_text_color = "0"; + else + f_text_color = QString::number(text_color); + + packet_contents.append(f_text_color); + + // If the server we're on supports CCCC stuff, we should use it! + if (ao_app->cccc_ic_support_enabled) + { + // 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) + { + packet_contents.append(QString::number(other_charid)); + packet_contents.append(QString::number(offset_with_pair)); + } + else + { + packet_contents.append("-1"); + packet_contents.append("0"); + } + + // Finally, we send over if we want our pres to not interrupt. + if (ui_pre_non_interrupt->isChecked() && ui_pre->isChecked()) + { + packet_contents.append("1"); + } + else + { + packet_contents.append("0"); + } + } + + ao_app->send_server_packet(new AOPacket("MS", packet_contents)); +} + +void Courtroom::handle_chatmessage(QStringList *p_contents) +{ + // Instead of checking for whether a message has at least chatmessage_size + // amount of packages, we'll check if it has at least 15. + // That was the original chatmessage_size. + if (p_contents->size() < 15) + return; + + for (int n_string = 0 ; n_string < chatmessage_size ; ++n_string) + { + //m_chatmessage[n_string] = p_contents->at(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 < 15 || ao_app->cccc_ic_support_enabled)) + { + m_chatmessage[n_string] = p_contents->at(n_string); + } + else + { + m_chatmessage[n_string] = ""; + } + } + + int f_char_id = m_chatmessage[CHAR_ID].toInt(); + + if (f_char_id < 0 || f_char_id >= char_list.size()) + return; + + if (mute_map.value(m_chatmessage[CHAR_ID].toInt())) + return; + + QString f_showname; + if (m_chatmessage[SHOWNAME].isEmpty() || !ui_showname_enable->isChecked()) + { + f_showname = ao_app->get_showname(char_list.at(f_char_id).name); + } + else + { + f_showname = m_chatmessage[SHOWNAME]; + } + + + QString f_message = f_showname + ": " + m_chatmessage[MESSAGE] + '\n'; + + if (f_message == previous_ic_message) + return; + + text_state = 0; + anim_state = 0; + ui_vp_objection->stop(); + ui_vp_player_char->stop(); + chat_tick_timer->stop(); + ui_vp_evidence_display->reset(); + + chatmessage_is_empty = m_chatmessage[MESSAGE] == " " || m_chatmessage[MESSAGE] == ""; + + if (m_chatmessage[MESSAGE] == ui_ic_chat_message->text() && m_chatmessage[CHAR_ID].toInt() == m_cid) + { + ui_ic_chat_message->clear(); + objection_state = 0; + realization_state = 0; + is_presenting_evidence = false; + ui_pre->setChecked(false); + ui_hold_it->set_image("holdit.png"); + ui_objection->set_image("objection.png"); + ui_take_that->set_image("takethat.png"); + ui_custom_objection->set_image("custom.png"); + ui_realization->set_image("realization.png"); + ui_evidence_present->set_image("present_disabled.png"); + } + + chatlogpiece* temp = new chatlogpiece(ao_app->get_showname(char_list.at(f_char_id).name), f_showname, ": " + m_chatmessage[MESSAGE], false); + ic_chatlog_history.append(*temp); + + while(ic_chatlog_history.size() > log_maximum_blocks && log_maximum_blocks > 0) + { + ic_chatlog_history.removeFirst(); + } + + append_ic_text(": " + m_chatmessage[MESSAGE], f_showname); + + previous_ic_message = f_message; + + int objection_mod = m_chatmessage[OBJECTION_MOD].toInt(); + QString f_char = m_chatmessage[CHAR_NAME]; + QString f_custom_theme = ao_app->get_char_shouts(f_char); + + //if an objection is used + if (objection_mod <= 4 && objection_mod >= 1) + { + switch (objection_mod) + { + case 1: + ui_vp_objection->play("holdit", f_char, f_custom_theme); + objection_player->play("holdit.wav", f_char, f_custom_theme); + break; + case 2: + ui_vp_objection->play("objection", f_char, f_custom_theme); + objection_player->play("objection.wav", f_char, f_custom_theme); + break; + case 3: + ui_vp_objection->play("takethat", f_char, f_custom_theme); + objection_player->play("takethat.wav", f_char, f_custom_theme); + break; + //case 4 is AO2 only + case 4: + ui_vp_objection->play("custom", f_char, f_custom_theme); + objection_player->play("custom.wav", f_char, f_custom_theme); + break; + default: + qDebug() << "W: Logic error in objection switch statement!"; + } + + int emote_mod = m_chatmessage[EMOTE_MOD].toInt(); + + if (emote_mod == 0) + m_chatmessage[EMOTE_MOD] = 1; + } + else + handle_chatmessage_2(); +} + +void Courtroom::objection_done() +{ + handle_chatmessage_2(); +} + +void Courtroom::handle_chatmessage_2() +{ + ui_vp_speedlines->stop(); + ui_vp_player_char->stop(); + + if (m_chatmessage[SHOWNAME].isEmpty() || !ui_showname_enable->isChecked()) + { + QString real_name = char_list.at(m_chatmessage[CHAR_ID].toInt()).name; + + QString f_showname = ao_app->get_showname(real_name); + + ui_vp_showname->setText(f_showname); + } + else + { + ui_vp_showname->setText(m_chatmessage[SHOWNAME]); + } + + ui_vp_message->clear(); + ui_vp_chatbox->hide(); + + QString chatbox = ao_app->get_chat(m_chatmessage[CHAR_NAME]); + + if (chatbox == "") + ui_vp_chatbox->set_image("chatmed.png"); + else + { + QString chatbox_path = ao_app->get_base_path() + "misc/" + chatbox + "/chatbox.png"; + ui_vp_chatbox->set_image_from_path(chatbox_path); + } + + ui_vp_showname->setStyleSheet("QLabel { color : " + get_text_color("_showname").name() + "; }"); + + set_scene(); + set_text_color(); + + // Check if the message needs to be centered. + QString f_message = m_chatmessage[MESSAGE]; + if (f_message.size() >= 2) + { + if (f_message.startsWith("~~")) + { + message_is_centered = true; + } + else + { + message_is_centered = false; + } + } + else + { + ui_vp_message->setAlignment(Qt::AlignLeft); + } + + + int emote_mod = m_chatmessage[EMOTE_MOD].toInt(); + + if (ao_app->flipping_enabled && m_chatmessage[FLIP].toInt() == 1) + ui_vp_player_char->set_flipped(true); + else + ui_vp_player_char->set_flipped(false); + + QString side = m_chatmessage[SIDE]; + + // Making the second character appear. + if (m_chatmessage[OTHER_CHARID].isEmpty()) + { + // If there is no second character, hide 'em, and center the first. + ui_vp_sideplayer_char->hide(); + ui_vp_sideplayer_char->move(0,0); + + ui_vp_player_char->move(0,0); + } + else + { + bool ok; + int got_other_charid = m_chatmessage[OTHER_CHARID].toInt(&ok); + if (ok) + { + if (got_other_charid > -1) + { + // If there is, show them! + ui_vp_sideplayer_char->show(); + + // Depending on where we are, we offset the characters, and reorder their stacking. + if (side == "def") + { + // We also move the character down depending on how far the are to the right. + int hor_offset = m_chatmessage[SELF_OFFSET].toInt(); + int vert_offset = 0; + if (hor_offset > 0) + { + vert_offset = hor_offset / 10; + } + ui_vp_player_char->move(ui_viewport->width() * hor_offset / 100, ui_viewport->height() * vert_offset / 100); + + // We do the same with the second character. + int hor2_offset = m_chatmessage[OTHER_OFFSET].toInt(); + int vert2_offset = 0; + if (hor2_offset > 0) + { + vert2_offset = hor2_offset / 10; + } + ui_vp_sideplayer_char->move(ui_viewport->width() * hor2_offset / 100, ui_viewport->height() * vert2_offset / 100); + + // Finally, we reorder them based on who is more to the left. + // The person more to the left is more in the front. + if (hor2_offset >= hor_offset) + { + ui_vp_sideplayer_char->raise(); + ui_vp_player_char->raise(); + } + else + { + ui_vp_player_char->raise(); + ui_vp_sideplayer_char->raise(); + } + ui_vp_desk->raise(); + ui_vp_legacy_desk->raise(); + } + else if (side == "pro") + { + // Almost the same thing happens here, but in reverse. + int hor_offset = m_chatmessage[SELF_OFFSET].toInt(); + int vert_offset = 0; + if (hor_offset < 0) + { + // We don't want to RAISE the char off the floor. + vert_offset = -1 * hor_offset / 10; + } + ui_vp_player_char->move(ui_viewport->width() * hor_offset / 100, ui_viewport->height() * vert_offset / 100); + + // We do the same with the second character. + int hor2_offset = m_chatmessage[OTHER_OFFSET].toInt(); + int vert2_offset = 0; + if (hor2_offset < 0) + { + vert2_offset = -1 * hor2_offset / 10; + } + ui_vp_sideplayer_char->move(ui_viewport->width() * hor2_offset / 100, ui_viewport->height() * vert2_offset / 100); + + // Finally, we reorder them based on who is more to the right. + if (hor2_offset <= hor_offset) + { + ui_vp_sideplayer_char->raise(); + ui_vp_player_char->raise(); + } + else + { + ui_vp_player_char->raise(); + ui_vp_sideplayer_char->raise(); + } + ui_vp_desk->raise(); + ui_vp_legacy_desk->raise(); + } + else + { + // In every other case, the person more to the left is on top. + // These cases also don't move the characters down. + int hor_offset = m_chatmessage[SELF_OFFSET].toInt(); + ui_vp_player_char->move(ui_viewport->width() * hor_offset / 100, 0); + + // We do the same with the second character. + int hor2_offset = m_chatmessage[OTHER_OFFSET].toInt(); + ui_vp_sideplayer_char->move(ui_viewport->width() * hor2_offset / 100, 0); + + // Finally, we reorder them based on who is more to the left. + // The person more to the left is more in the front. + if (hor2_offset >= hor_offset) + { + ui_vp_sideplayer_char->raise(); + ui_vp_player_char->raise(); + } + else + { + ui_vp_player_char->raise(); + ui_vp_sideplayer_char->raise(); + } + ui_vp_desk->raise(); + ui_vp_legacy_desk->raise(); + } + // We should probably also play the other character's idle emote. + if (ao_app->flipping_enabled && m_chatmessage[OTHER_FLIP].toInt() == 1) + ui_vp_sideplayer_char->set_flipped(true); + else + ui_vp_sideplayer_char->set_flipped(false); + ui_vp_sideplayer_char->play_idle(m_chatmessage[OTHER_NAME], m_chatmessage[OTHER_EMOTE]); + } + else + { + // If the server understands other characters, but there + // really is no second character, hide 'em, and center the first. + ui_vp_sideplayer_char->hide(); + ui_vp_sideplayer_char->move(0,0); + + ui_vp_player_char->move(0,0); + } + } + } + + switch (emote_mod) + { + case 1: case 2: case 6: + play_preanim(false); + break; + case 0: case 5: + if (m_chatmessage[NONINTERRUPTING_PRE].toInt() == 0) + handle_chatmessage_3(); + else + play_preanim(true); + break; + default: + qDebug() << "W: invalid emote mod: " << QString::number(emote_mod); + } +} + +void Courtroom::handle_chatmessage_3() +{ + start_chat_ticking(); + + int f_evi_id = m_chatmessage[EVIDENCE_ID].toInt(); + QString f_side = m_chatmessage[SIDE]; + + if (f_evi_id > 0 && f_evi_id <= local_evidence_list.size()) + { + //shifted by 1 because 0 is no evidence per legacy standards + QString f_image = local_evidence_list.at(f_evi_id - 1).image; + //def jud and hlp should display the evidence icon on the RIGHT side + bool is_left_side = !(f_side == "def" || f_side == "hlp" || f_side == "jud" || f_side == "jur"); + ui_vp_evidence_display->show_evidence(f_image, is_left_side, ui_sfx_slider->value()); + } + + int emote_mod = m_chatmessage[EMOTE_MOD].toInt(); + + QString side = m_chatmessage[SIDE]; + + if (emote_mod == 5 || + emote_mod == 6) + { + ui_vp_desk->hide(); + ui_vp_legacy_desk->hide(); + + // Since we're zooming, hide the second character, and centre the first. + ui_vp_sideplayer_char->hide(); + ui_vp_player_char->move(0,0); + + if (side == "pro" || + side == "hlp" || + side == "wit") + ui_vp_speedlines->play("prosecution_speedlines"); + else + ui_vp_speedlines->play("defense_speedlines"); + + } + + int f_anim_state = 0; + //BLUE is from an enum in datatypes.h + bool text_is_blue = m_chatmessage[TEXT_COLOR].toInt() == BLUE; + + if (!text_is_blue && text_state == 1) + { + //talking + f_anim_state = 2; + entire_message_is_blue = false; + } + else + { + //idle + f_anim_state = 3; + entire_message_is_blue = true; + } + + if (f_anim_state <= anim_state) + return; + + ui_vp_player_char->stop(); + QString f_char = m_chatmessage[CHAR_NAME]; + QString f_emote = m_chatmessage[EMOTE]; + + if (f_anim_state == 2) { + ui_vp_player_char->play_talking(f_char, f_emote); + anim_state = 2; + } + else + { + ui_vp_player_char->play_idle(f_char, f_emote); + anim_state = 3; + } + + QString f_message = m_chatmessage[MESSAGE]; + QStringList call_words = ao_app->get_call_words(); + + for (QString word : call_words) + { + if (f_message.contains(word, Qt::CaseInsensitive)) + { + modcall_player->play(ao_app->get_sfx("word_call")); + ao_app->alert(this); + + break; + } + } + +} + +QString Courtroom::filter_ic_text(QString p_text) +{ + // Get rid of centering. + if(p_text.startsWith(": ~~")) + { + // Don't forget, the p_text part actually everything after the name! + // Hence why we check for ': ~~'. + + // Let's remove those two tildes, then. + // : _ ~ ~ + // 0 1 2 3 + p_text.remove(2,2); + } + + // Get rid of the inline-colouring. + // I know, I know, excessive code duplication. + // Nobody looks in here, I'm fine. + int trick_check_pos = 0; + bool ic_next_is_not_special = false; + QString f_character = p_text.at(trick_check_pos); + std::stack ic_colour_stack; + while (trick_check_pos < p_text.size()) + { + f_character = p_text.at(trick_check_pos); + + // Escape character. + if (f_character == "\\" and !ic_next_is_not_special) + { + ic_next_is_not_special = true; + p_text.remove(trick_check_pos,1); + } + + // Text speed modifier. + else if (f_character == "{" and !ic_next_is_not_special) + { + p_text.remove(trick_check_pos,1); + } + else if (f_character == "}" and !ic_next_is_not_special) + { + p_text.remove(trick_check_pos,1); + } + + // Orange inline colourisation. + else if (f_character == "|" and !ic_next_is_not_special) + { + if (!ic_colour_stack.empty()) + { + if (ic_colour_stack.top() == INLINE_ORANGE) + { + ic_colour_stack.pop(); + p_text.remove(trick_check_pos,1); + } + else + { + ic_colour_stack.push(INLINE_ORANGE); + p_text.remove(trick_check_pos,1); + } + } + else + { + ic_colour_stack.push(INLINE_ORANGE); + p_text.remove(trick_check_pos,1); + } + } + + // Blue inline colourisation. + else if (f_character == "(" and !ic_next_is_not_special) + { + ic_colour_stack.push(INLINE_BLUE); + trick_check_pos++; + } + else if (f_character == ")" and !ic_next_is_not_special + and !ic_colour_stack.empty()) + { + if (ic_colour_stack.top() == INLINE_BLUE) + { + ic_colour_stack.pop(); + trick_check_pos++; + } + else + { + ic_next_is_not_special = true; + } + } + + // Grey inline colourisation. + else if (f_character == "[" and !ic_next_is_not_special) + { + ic_colour_stack.push(INLINE_GREY); + trick_check_pos++; + } + else if (f_character == "]" and !ic_next_is_not_special + and !ic_colour_stack.empty()) + { + if (ic_colour_stack.top() == INLINE_GREY) + { + ic_colour_stack.pop(); + trick_check_pos++; + } + else + { + ic_next_is_not_special = true; + } + } + + // Green inline colourisation. + else if (f_character == "`" and !ic_next_is_not_special) + { + if (!ic_colour_stack.empty()) + { + if (ic_colour_stack.top() == INLINE_GREEN) + { + ic_colour_stack.pop(); + p_text.remove(trick_check_pos,1); + } + else + { + ic_colour_stack.push(INLINE_GREEN); + p_text.remove(trick_check_pos,1); + } + } + else + { + ic_colour_stack.push(INLINE_GREEN); + p_text.remove(trick_check_pos,1); + } + } + else + { + trick_check_pos++; + ic_next_is_not_special = false; + } + } + + return p_text; +} + +void Courtroom::append_ic_text(QString p_text, QString p_name, bool is_songchange) +{ + QTextCharFormat bold; + QTextCharFormat normal; + QTextCharFormat italics; + bold.setFontWeight(QFont::Bold); + normal.setFontWeight(QFont::Normal); + italics.setFontItalic(true); + const QTextCursor old_cursor = ui_ic_chatlog->textCursor(); + const int old_scrollbar_value = ui_ic_chatlog->verticalScrollBar()->value(); + + if (!is_songchange) + p_text = filter_ic_text(p_text); + + if (log_goes_downwards) + { + const bool is_scrolled_down = old_scrollbar_value == ui_ic_chatlog->verticalScrollBar()->maximum(); + + ui_ic_chatlog->moveCursor(QTextCursor::End); + + if (!first_message_sent) + { + ui_ic_chatlog->textCursor().insertText(p_name, bold); + first_message_sent = true; + } + else + { + ui_ic_chatlog->textCursor().insertText('\n' + p_name, bold); + } + + if (is_songchange) + { + ui_ic_chatlog->textCursor().insertText(" has played a song: ", normal); + ui_ic_chatlog->textCursor().insertText(p_text + ".", italics); + } + else + { + ui_ic_chatlog->textCursor().insertText(p_text, normal); + } + + // If we got too many blocks in the current log, delete some from the top. + while (ui_ic_chatlog->document()->blockCount() > log_maximum_blocks && log_maximum_blocks > 0) + { + ui_ic_chatlog->moveCursor(QTextCursor::Start); + ui_ic_chatlog->textCursor().select(QTextCursor::BlockUnderCursor); + ui_ic_chatlog->textCursor().removeSelectedText(); + ui_ic_chatlog->textCursor().deleteChar(); + //qDebug() << ui_ic_chatlog->document()->blockCount() << " < " << log_maximum_blocks; + } + + if (old_cursor.hasSelection() || !is_scrolled_down) + { + // The user has selected text or scrolled away from the bottom: maintain position. + ui_ic_chatlog->setTextCursor(old_cursor); + ui_ic_chatlog->verticalScrollBar()->setValue(old_scrollbar_value); + } + else + { + // The user hasn't selected any text and the scrollbar is at the bottom: scroll to the bottom. + ui_ic_chatlog->moveCursor(QTextCursor::End); + ui_ic_chatlog->verticalScrollBar()->setValue(ui_ic_chatlog->verticalScrollBar()->maximum()); + } + } + else + { + const bool is_scrolled_up = old_scrollbar_value == ui_ic_chatlog->verticalScrollBar()->minimum(); + + ui_ic_chatlog->moveCursor(QTextCursor::Start); + + ui_ic_chatlog->textCursor().insertText(p_name, bold); + + if (is_songchange) + { + ui_ic_chatlog->textCursor().insertText(" has played a song: ", normal); + ui_ic_chatlog->textCursor().insertText(p_text + "." + '\n', italics); + } + else + { + ui_ic_chatlog->textCursor().insertText(p_text + '\n', normal); + } + + // If we got too many blocks in the current log, delete some from the bottom. + while (ui_ic_chatlog->document()->blockCount() > log_maximum_blocks && log_maximum_blocks > 0) + { + ui_ic_chatlog->moveCursor(QTextCursor::End); + ui_ic_chatlog->textCursor().select(QTextCursor::BlockUnderCursor); + ui_ic_chatlog->textCursor().removeSelectedText(); + ui_ic_chatlog->textCursor().deletePreviousChar(); + //qDebug() << ui_ic_chatlog->document()->blockCount() << " < " << log_maximum_blocks; + } + + if (old_cursor.hasSelection() || !is_scrolled_up) + { + // The user has selected text or scrolled away from the top: maintain position. + ui_ic_chatlog->setTextCursor(old_cursor); + ui_ic_chatlog->verticalScrollBar()->setValue(old_scrollbar_value); + } + else + { + // The user hasn't selected any text and the scrollbar is at the top: scroll to the top. + ui_ic_chatlog->moveCursor(QTextCursor::Start); + ui_ic_chatlog->verticalScrollBar()->setValue(ui_ic_chatlog->verticalScrollBar()->minimum()); + } + } +} + +void Courtroom::play_preanim(bool noninterrupting) +{ + QString f_char = m_chatmessage[CHAR_NAME]; + QString f_preanim = m_chatmessage[PRE_EMOTE]; + + //all time values in char.inis are multiplied by a constant(time_mod) to get the actual time + int ao2_duration = ao_app->get_ao2_preanim_duration(f_char, f_preanim); + int text_delay = ao_app->get_text_delay(f_char, f_preanim) * time_mod; + int sfx_delay = m_chatmessage[SFX_DELAY].toInt() * 60; + + int preanim_duration; + + if (ao2_duration < 0) + preanim_duration = ao_app->get_preanim_duration(f_char, f_preanim); + else + preanim_duration = ao2_duration; + + sfx_delay_timer->start(sfx_delay); + QString anim_to_find = ao_app->get_image_suffix(ao_app->get_character_path(f_char, f_preanim)); + if (!file_exists(anim_to_find) || + preanim_duration < 0) + { + if (noninterrupting) + anim_state = 4; + else + anim_state = 1; + preanim_done(); + qDebug() << "could not find " + anim_to_find; + return; + } + + ui_vp_player_char->play_pre(f_char, f_preanim, preanim_duration); + + if (noninterrupting) + anim_state = 4; + else + anim_state = 1; + + if (text_delay >= 0) + text_delay_timer->start(text_delay); + + if (noninterrupting) + handle_chatmessage_3(); +} + +void Courtroom::preanim_done() +{ + anim_state = 1; + handle_chatmessage_3(); +} + +void Courtroom::realization_done() +{ + ui_vp_realization->hide(); +} + +void Courtroom::start_chat_ticking() +{ + //we need to ensure that the text isn't already ticking because this function can be called by two logic paths + if (text_state != 0) + return; + + if (m_chatmessage[REALIZATION] == "1") + { + realization_timer->start(60); + ui_vp_realization->show(); + sfx_player->play(ao_app->get_custom_realization(m_chatmessage[CHAR_NAME])); + } + + ui_vp_message->clear(); + set_text_color(); + rainbow_counter = 0; + + if (chatmessage_is_empty) + { + //since the message is empty, it's technically done ticking + text_state = 2; + return; + } + + // At this point, we'd do well to clear the inline colour stack. + // This stops it from flowing into next messages. + while (!inline_colour_stack.empty()) + { + inline_colour_stack.pop(); + } + + ui_vp_chatbox->show(); + + tick_pos = 0; + blip_pos = 0; + + // Just in case we somehow got inline blue text left over from a previous message, + // let's set it to false. + inline_blue_depth = 0; + + // At the start of every new message, we set the text speed to the default. + current_display_speed = 3; + chat_tick_timer->start(message_display_speed[current_display_speed]); + + QString f_gender = ao_app->get_gender(m_chatmessage[CHAR_NAME]); + + blip_player->set_blips(ao_app->get_sfx_suffix("sfx-blip" + f_gender)); + + //means text is currently ticking + text_state = 1; +} + +void Courtroom::chat_tick() +{ + //note: this is called fairly often(every 60 ms when char is talking) + //do not perform heavy operations here + + QString f_message = m_chatmessage[MESSAGE]; + f_message.remove(0, tick_pos); + + // Due to our new text speed system, we always need to stop the timer now. + chat_tick_timer->stop(); + + // Stops blips from playing when we have a formatting option. + bool formatting_char = false; + + // If previously, we have detected that the message is centered, now + // is the time to remove those two tildes at the start. + if (message_is_centered) + { + f_message.remove(0,2); + } + + if (f_message.size() == 0) + { + text_state = 2; + if (anim_state != 4) + { + anim_state = 3; + ui_vp_player_char->play_idle(m_chatmessage[CHAR_NAME], m_chatmessage[EMOTE]); + } + } + + else + { + QTextBoundaryFinder tbf(QTextBoundaryFinder::Grapheme, f_message); + QString f_character; + int f_char_length; + + tbf.toNextBoundary(); + + if (tbf.position() == -1) + f_character = f_message; + else + f_character = f_message.left(tbf.position()); + + f_char_length = f_character.length(); + f_character = f_character.toHtmlEscaped(); + + + if (f_character == " ") + ui_vp_message->insertPlainText(" "); + + // Escape character. + else if (f_character == "\\" and !next_character_is_not_special) + { + next_character_is_not_special = true; + formatting_char = true; + } + + // Text speed modifier. + else if (f_character == "{" and !next_character_is_not_special) + { + // ++, because it INCREASES delay! + current_display_speed++; + formatting_char = true; + } + else if (f_character == "}" and !next_character_is_not_special) + { + current_display_speed--; + formatting_char = true; + } + + // Orange inline colourisation. + else if (f_character == "|" and !next_character_is_not_special) + { + if (!inline_colour_stack.empty()) + { + if (inline_colour_stack.top() == INLINE_ORANGE) + { + inline_colour_stack.pop(); + } + else + { + inline_colour_stack.push(INLINE_ORANGE); + } + } + else + { + inline_colour_stack.push(INLINE_ORANGE); + } + formatting_char = true; + } + + // Blue inline colourisation. + else if (f_character == "(" and !next_character_is_not_special) + { + inline_colour_stack.push(INLINE_BLUE); + ui_vp_message->insertHtml("" + f_character + ""); + + // Increase how deep we are in inline blues. + inline_blue_depth++; + + // Here, we check if the entire message is blue. + // If it isn't, we stop talking. + if (!entire_message_is_blue and anim_state != 4) + { + QString f_char = m_chatmessage[CHAR_NAME]; + QString f_emote = m_chatmessage[EMOTE]; + ui_vp_player_char->play_idle(f_char, f_emote); + } + } + else if (f_character == ")" and !next_character_is_not_special + and !inline_colour_stack.empty()) + { + if (inline_colour_stack.top() == INLINE_BLUE) + { + inline_colour_stack.pop(); + ui_vp_message->insertHtml("" + f_character + ""); + + // Decrease how deep we are in inline blues. + // Just in case, we do a check if we're above zero, but we should be. + if (inline_blue_depth > 0) + { + inline_blue_depth--; + // Here, we check if the entire message is blue. + // If it isn't, we start talking if we have completely climbed out of inline blues. + if (!entire_message_is_blue) + { + // We should only go back to talking if we're out of inline blues, not during a non. int. pre, and not on the last character. + if (inline_blue_depth == 0 and anim_state != 4 and !(tick_pos+1 >= f_message.size())) + { + QString f_char = m_chatmessage[CHAR_NAME]; + QString f_emote = m_chatmessage[EMOTE]; + ui_vp_player_char->play_talking(f_char, f_emote); + } + } + } + } + else + { + next_character_is_not_special = true; + tick_pos -= f_char_length; + } + } + + // Grey inline colourisation. + else if (f_character == "[" and !next_character_is_not_special) + { + inline_colour_stack.push(INLINE_GREY); + ui_vp_message->insertHtml("" + f_character + ""); + } + else if (f_character == "]" and !next_character_is_not_special + and !inline_colour_stack.empty()) + { + if (inline_colour_stack.top() == INLINE_GREY) + { + inline_colour_stack.pop(); + ui_vp_message->insertHtml("" + f_character + ""); + } + else + { + next_character_is_not_special = true; + tick_pos -= f_char_length; + } + } + + // Green inline colourisation. + else if (f_character == "`" and !next_character_is_not_special) + { + if (!inline_colour_stack.empty()) + { + if (inline_colour_stack.top() == INLINE_GREEN) + { + inline_colour_stack.pop(); + formatting_char = true; + } + else + { + inline_colour_stack.push(INLINE_GREEN); + formatting_char = true; + } + } + else + { + inline_colour_stack.push(INLINE_GREEN); + formatting_char = true; + } + } + else + { + next_character_is_not_special = false; + if (!inline_colour_stack.empty()) + { + switch (inline_colour_stack.top()) { + case INLINE_ORANGE: + ui_vp_message->insertHtml("" + f_character + ""); + break; + case INLINE_BLUE: + ui_vp_message->insertHtml("" + f_character + ""); + break; + case INLINE_GREEN: + ui_vp_message->insertHtml("" + f_character + ""); + break; + case INLINE_GREY: + ui_vp_message->insertHtml("" + f_character + ""); + break; + } + } + else + { + if (m_chatmessage[TEXT_COLOR].toInt() == RAINBOW) + { + QString html_color; + + switch (rainbow_counter) + { + case 0: + html_color = get_text_color(QString::number(RED)).name(); + break; + case 1: + html_color = get_text_color(QString::number(ORANGE)).name(); + break; + case 2: + html_color = get_text_color(QString::number(YELLOW)).name(); + break; + case 3: + html_color = get_text_color(QString::number(GREEN)).name(); + break; + default: + html_color = get_text_color(QString::number(BLUE)).name(); + rainbow_counter = -1; + } + + ++rainbow_counter; + + ui_vp_message->insertHtml("" + f_character + ""); + } + else + ui_vp_message->insertHtml(f_character); + } + + if (message_is_centered) + { + ui_vp_message->setAlignment(Qt::AlignCenter); + } + else + { + ui_vp_message->setAlignment(Qt::AlignLeft); + } + } + + QScrollBar *scroll = ui_vp_message->verticalScrollBar(); + scroll->setValue(scroll->maximum()); + + if(blank_blip) + qDebug() << "blank_blip found true"; + + if (f_character != ' ' || blank_blip) + { + + if (blip_pos % blip_rate == 0 && !formatting_char) + { + blip_pos = 0; + blip_player->blip_tick(); + } + + ++blip_pos; + } + + tick_pos += f_char_length; + + // Restart the timer, but according to the newly set speeds, if there were any. + // Keep the speed at bay. + if (current_display_speed < 0) + { + current_display_speed = 0; + } + + if (current_display_speed > 6) + { + current_display_speed = 6; + } + + // If we had a formatting char, we shouldn't wait so long again, as it won't appear! + if (formatting_char) + { + chat_tick_timer->start(1); + } + else + { + chat_tick_timer->start(message_display_speed[current_display_speed]); + } + + } +} + + +void Courtroom::show_testimony() +{ + if (!testimony_in_progress || m_chatmessage[SIDE] != "wit") + return; + + ui_vp_testimony->show(); + + testimony_show_timer->start(testimony_show_time); +} + +void Courtroom::hide_testimony() +{ + ui_vp_testimony->hide(); + + if (!testimony_in_progress) + return; + + testimony_hide_timer->start(testimony_hide_time); +} + +void Courtroom::play_sfx() +{ + QString sfx_name = m_chatmessage[SFX_NAME]; + + if (sfx_name == "1") + return; + + sfx_player->play(ao_app->get_sfx_suffix(sfx_name)); +} + +void Courtroom::set_scene() +{ + if (testimony_in_progress) + show_testimony(); + + //witness is default if pos is invalid + QString f_background = "witnessempty"; + QString f_desk_image = "stand"; + QString f_desk_mod = m_chatmessage[DESK_MOD]; + QString f_side = m_chatmessage[SIDE]; + + if (f_side == "def") + { + f_background = "defenseempty"; + if (is_ao2_bg) + f_desk_image = "defensedesk"; + else + f_desk_image = "bancodefensa"; + } + else if (f_side == "pro") + { + f_background = "prosecutorempty"; + if (is_ao2_bg) + f_desk_image = "prosecutiondesk"; + else + f_desk_image = "bancoacusacion"; + } + else if (f_side == "jud") + { + f_background = "judgestand"; + f_desk_image = "judgedesk"; + } + else if (f_side == "hld") + { + f_background = "helperstand"; + f_desk_image = "helperdesk"; + } + else if (f_side == "hlp") + { + f_background = "prohelperstand"; + f_desk_image = "prohelperdesk"; + } + else if (f_side == "jur" && (file_exists(ao_app->get_background_path("jurystand.png")) || + file_exists(ao_app->get_background_path("jurystand.gif")))) + { + f_background = "jurystand"; + f_desk_image = "jurydesk"; + } + else if (f_side == "sea" && (file_exists(ao_app->get_background_path("seancestand.png")) || + file_exists(ao_app->get_background_path("seancestand.gif")))) + { + f_background = "seancestand"; + f_desk_image = "seancedesk"; + } + else + { + if (is_ao2_bg) + f_desk_image = "stand"; + else + f_desk_image = "estrado"; + } + + ui_vp_background->set_image(f_background); + ui_vp_desk->set_image(f_desk_image); + ui_vp_legacy_desk->set_legacy_desk(f_desk_image); + + if (f_desk_mod == "0" || (f_desk_mod != "1" && + (f_side == "jud" || + f_side == "hld" || + f_side == "hlp"))) + { + ui_vp_desk->hide(); + ui_vp_legacy_desk->hide(); + } + else if (is_ao2_bg || (f_side == "jud" || + f_side == "hld" || + f_side == "hlp")) + { + ui_vp_legacy_desk->hide(); + ui_vp_desk->show(); + } + else + { + if (f_side == "wit") + { + ui_vp_desk->show(); + ui_vp_legacy_desk->hide(); + } + else + { + ui_vp_desk->hide(); + ui_vp_legacy_desk->show(); + } + } +} + +void Courtroom::set_text_color() +{ + QColor textcolor = ao_app->get_chat_color(m_chatmessage[TEXT_COLOR], ao_app->get_chat(m_chatmessage[CHAR_NAME])); + + ui_vp_message->setTextBackgroundColor(QColor(0,0,0,0)); + ui_vp_message->setTextColor(textcolor); + + QString style = "background-color: rgba(0, 0, 0, 0);"; + style.append("color: rgb("); + style.append(QString::number(textcolor.red())); + style.append(", "); + style.append(QString::number(textcolor.green())); + style.append(", "); + style.append(QString::number(textcolor.blue())); + style.append(")"); + + ui_vp_message->setStyleSheet(style); +} + +QColor Courtroom::get_text_color(QString color) +{ + return ao_app->get_chat_color(color, ao_app->get_chat(m_chatmessage[CHAR_NAME])); +} + +void Courtroom::set_ip_list(QString p_list) +{ + QString f_list = p_list.replace("|", ":").replace("*", "\n"); + + ui_server_chatlog->append(f_list); +} + +void Courtroom::set_mute(bool p_muted, int p_cid) +{ + if (p_cid != m_cid && p_cid != -1) + return; + + if (p_muted) + ui_muted->show(); + else + { + ui_muted->hide(); + ui_ic_chat_message->setFocus(); + } + + ui_muted->resize(ui_ic_chat_message->width(), ui_ic_chat_message->height()); + ui_muted->set_image("muted.png"); + + is_muted = p_muted; + ui_ic_chat_message->setEnabled(!p_muted); +} + +void Courtroom::set_ban(int p_cid) +{ + if (p_cid != m_cid && p_cid != -1) + return; + + call_notice("You have been banned."); + + ao_app->construct_lobby(); + ao_app->destruct_courtroom(); +} + +void Courtroom::handle_song(QStringList *p_contents) +{ + QStringList f_contents = *p_contents; + + if (f_contents.size() < 2) + return; + + QString f_song = f_contents.at(0); + QString f_song_clear = f_song; + f_song_clear = f_song_clear.left(f_song_clear.lastIndexOf(".")); + int n_char = f_contents.at(1).toInt(); + + if (n_char < 0 || n_char >= char_list.size()) + { + music_player->play(f_song); + } + else + { + QString str_char = char_list.at(n_char).name; + QString str_show = char_list.at(n_char).name; + + if (p_contents->length() > 2) + { + str_show = p_contents->at(2); + } + + if (!mute_map.value(n_char)) + { + chatlogpiece* temp = new chatlogpiece(str_char, str_show, f_song, true); + ic_chatlog_history.append(*temp); + + while(ic_chatlog_history.size() > log_maximum_blocks && log_maximum_blocks > 0) + { + ic_chatlog_history.removeFirst(); + } + + append_ic_text(f_song_clear, str_show, true); + music_player->play(f_song); + } + } +} + +void Courtroom::handle_wtce(QString p_wtce, int variant) +{ + QString sfx_file = "courtroom_sounds.ini"; + + //witness testimony + if (p_wtce == "testimony1") + { + sfx_player->play(ao_app->get_sfx("witness_testimony")); + ui_vp_wtce->play("witnesstestimony"); + testimony_in_progress = true; + show_testimony(); + } + //cross examination + else if (p_wtce == "testimony2") + { + sfx_player->play(ao_app->get_sfx("cross_examination")); + ui_vp_wtce->play("crossexamination"); + testimony_in_progress = false; + } + else if (p_wtce == "judgeruling") + { + if (variant == 0) + { + sfx_player->play(ao_app->get_sfx("not_guilty")); + ui_vp_wtce->play("notguilty"); + testimony_in_progress = false; + } + else if (variant == 1) { + sfx_player->play(ao_app->get_sfx("guilty")); + ui_vp_wtce->play("guilty"); + testimony_in_progress = false; + } + } +} + +void Courtroom::set_hp_bar(int p_bar, int p_state) +{ + if (p_state < 0 || p_state > 10) + return; + + if (p_bar == 1) + { + ui_defense_bar->set_image("defensebar" + QString::number(p_state) + ".png"); + defense_bar_state = p_state; + } + else if (p_bar == 2) + { + ui_prosecution_bar->set_image("prosecutionbar" + QString::number(p_state) + ".png"); + prosecution_bar_state = p_state; + } +} + +void Courtroom::toggle_judge_buttons(bool is_on) +{ + if (is_on) + { + ui_witness_testimony->show(); + ui_cross_examination->show(); + ui_guilty->show(); + ui_not_guilty->show(); + ui_defense_minus->show(); + ui_defense_plus->show(); + ui_prosecution_minus->show(); + ui_prosecution_plus->show(); + } + else + { + ui_witness_testimony->hide(); + ui_cross_examination->hide(); + ui_guilty->hide(); + ui_not_guilty->hide(); + ui_defense_minus->hide(); + ui_defense_plus->hide(); + ui_prosecution_minus->hide(); + ui_prosecution_plus->hide(); + } +} + +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")); + ao_app->alert(this); + } +} + +void Courtroom::case_called(QString msg, bool def, bool pro, bool jud, bool jur, bool steno) +{ + if (ui_casing->isChecked()) + { + ui_server_chatlog->append(msg); + if ((ao_app->get_casing_defence_enabled() && def) || + (ao_app->get_casing_prosecution_enabled() && pro) || + (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")); + ao_app->alert(this); + } + } +} + +void Courtroom::on_ooc_return_pressed() +{ + QString ooc_message = ui_ooc_chat_message->text(); + + if (ooc_message == "" || ui_ooc_chat_name->text() == "") + return; + + if (ooc_message.startsWith("/pos")) + { + if (ooc_message == "/pos jud") + { + toggle_judge_buttons(true); + } + else + { + toggle_judge_buttons(false); + } + } + else if (ooc_message.startsWith("/login")) + { + ui_guard->show(); + append_server_chatmessage("CLIENT", "You were granted the Guard button.", "1"); + } + else if (ooc_message.startsWith("/rainbow") && ao_app->yellow_text_enabled && !rainbow_appended) + { + //ui_text_color->addItem("Rainbow"); + ui_ooc_chat_message->clear(); + //rainbow_appended = true; + append_server_chatmessage("CLIENT", "This does nohing, but there you go.", "1"); + return; + } + else if (ooc_message.startsWith("/settings")) + { + ui_ooc_chat_message->clear(); + ao_app->call_settings_menu(); + append_server_chatmessage("CLIENT", "You opened the settings menu.", "1"); + return; + } + else if (ooc_message.startsWith("/pair")) + { + ui_ooc_chat_message->clear(); + ooc_message.remove(0,6); + + bool ok; + int whom = ooc_message.toInt(&ok); + if (ok) + { + if (whom > -1) + { + other_charid = whom; + QString msg = "You will now pair up with "; + msg.append(char_list.at(whom).name); + msg.append(" if they also choose your character in return."); + append_server_chatmessage("CLIENT", msg, "1"); + } + else + { + other_charid = -1; + append_server_chatmessage("CLIENT", "You are no longer paired with anyone.", "1"); + } + } + else + { + append_server_chatmessage("CLIENT", "Are you sure you typed that well? The char ID could not be recognised.", "1"); + } + return; + } + else if (ooc_message.startsWith("/offset")) + { + ui_ooc_chat_message->clear(); + ooc_message.remove(0,8); + + bool ok; + int off = ooc_message.toInt(&ok); + if (ok) + { + if (off >= -100 && off <= 100) + { + offset_with_pair = off; + QString msg = "You have set your offset to "; + msg.append(QString::number(off)); + msg.append("%."); + append_server_chatmessage("CLIENT", msg, "1"); + } + else + { + append_server_chatmessage("CLIENT", "Your offset must be between -100% and 100%!", "1"); + } + } + else + { + append_server_chatmessage("CLIENT", "That offset does not look like one.", "1"); + } + return; + } + else if (ooc_message.startsWith("/switch_am")) + { + append_server_chatmessage("CLIENT", "You switched your music and area list.", "1"); + on_switch_area_music_clicked(); + ui_ooc_chat_message->clear(); + return; + } + else if (ooc_message.startsWith("/enable_blocks")) + { + append_server_chatmessage("CLIENT", "You have forcefully enabled features that the server may not support. You may not be able to talk IC, or worse, because of this.", "1"); + ao_app->cccc_ic_support_enabled = true; + ao_app->arup_enabled = true; + ao_app->modcall_reason_enabled = true; + on_reload_theme_clicked(); + ui_ooc_chat_message->clear(); + return; + } + else if (ooc_message.startsWith("/non_int_pre")) + { + if (ui_pre_non_interrupt->isChecked()) + append_server_chatmessage("CLIENT", "Your pre-animations interrupt again.", "1"); + else + append_server_chatmessage("CLIENT", "Your pre-animations will not interrupt text.", "1"); + ui_pre_non_interrupt->setChecked(!ui_pre_non_interrupt->isChecked()); + ui_ooc_chat_message->clear(); + return; + } + else if (ooc_message.startsWith("/save_chatlog")) + { + QFile file("chatlog.txt"); + + if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) + { + append_server_chatmessage("CLIENT", "Couldn't open chatlog.txt to write into.", "1"); + ui_ooc_chat_message->clear(); + return; + } + + QTextStream out(&file); + + foreach (chatlogpiece item, ic_chatlog_history) { + out << item.get_full() << '\n'; + } + + file.close(); + + append_server_chatmessage("CLIENT", "The IC chatlog has been saved.", "1"); + ui_ooc_chat_message->clear(); + return; + } + else if (ooc_message.startsWith("/load_case")) + { + QStringList command = ooc_message.split(" ", QString::SkipEmptyParts); + + QDir casefolder("base/cases"); + if (!casefolder.exists()) + { + QDir::current().mkdir("base/" + casefolder.dirName()); + append_server_chatmessage("CLIENT", "You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely the case file you're looking for can't be found in there.", "1"); + ui_ooc_chat_message->clear(); + return; + } + QStringList caseslist = casefolder.entryList(); + caseslist.removeOne("."); + caseslist.removeOne(".."); + caseslist.replaceInStrings(".ini",""); + + if (command.size() < 2) + { + append_server_chatmessage("CLIENT", "You need to give a filename to load (extension not needed)! Make sure that it is in the `base/cases/` folder, and that it is a correctly formatted ini.\nCases you can load: " + caseslist.join(", "), "1"); + ui_ooc_chat_message->clear(); + return; + } + + + if (command.size() > 2) + { + append_server_chatmessage("CLIENT", "Too many arguments to load a case! You only need one filename, without extension.", "1"); + ui_ooc_chat_message->clear(); + return; + } + + QSettings casefile("base/cases/" + command[1] + ".ini", QSettings::IniFormat); + + QString caseauth = casefile.value("author", "").value(); + QString casedoc = casefile.value("doc", "").value(); + QString cmdoc = casefile.value("cmdoc", "").value(); + QString casestatus = casefile.value("status", "").value(); + + if (!caseauth.isEmpty()) + append_server_chatmessage("CLIENT", "Case made by " + caseauth + ".", "1"); + if (!casedoc.isEmpty()) + ao_app->send_server_packet(new AOPacket("CT#" + ui_ooc_chat_name->text() + "#/doc " + casedoc + "#%")); + if (!casestatus.isEmpty()) + ao_app->send_server_packet(new AOPacket("CT#" + ui_ooc_chat_name->text() + "#/status " + casestatus + "#%")); + if (!cmdoc.isEmpty()) + append_server_chatmessage("CLIENT", "Navigate to " + cmdoc + " for the CM doc.", "1"); + + for (int i = local_evidence_list.size() - 1; i >= 0; i--) { + ao_app->send_server_packet(new AOPacket("DE#" + QString::number(i) + "#%")); + } + + foreach (QString evi, casefile.childGroups()) { + if (evi == "General") + continue; + + QStringList f_contents; + + f_contents.append(casefile.value(evi + "/name", "UNKNOWN").value()); + f_contents.append(casefile.value(evi + "/description", "UNKNOWN").value()); + f_contents.append(casefile.value(evi + "/image", "UNKNOWN.png").value()); + + ao_app->send_server_packet(new AOPacket("PE", f_contents)); + } + + append_server_chatmessage("CLIENT", "Your case \"" + command[1] + "\" was loaded!", "1"); + ui_ooc_chat_message->clear(); + return; + } + else if(ooc_message.startsWith("/save_case")) + { + QStringList command = ooc_message.split(" ", QString::SkipEmptyParts); + + QDir casefolder("base/cases"); + if (!casefolder.exists()) + { + QDir::current().mkdir("base/" + casefolder.dirName()); + append_server_chatmessage("CLIENT", "You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely that you somehow deleted it.", "1"); + ui_ooc_chat_message->clear(); + return; + } + QStringList caseslist = casefolder.entryList(); + caseslist.removeOne("."); + caseslist.removeOne(".."); + caseslist.replaceInStrings(".ini",""); + + if (command.size() < 3) + { + append_server_chatmessage("CLIENT", "You need to give a filename to save (extension not needed) and the courtroom status!", "1"); + ui_ooc_chat_message->clear(); + return; + } + + + if (command.size() > 3) + { + append_server_chatmessage("CLIENT", "Too many arguments to save a case! You only need a filename without extension and the courtroom status!", "1"); + ui_ooc_chat_message->clear(); + return; + } + QSettings casefile("base/cases/" + command[1] + ".ini", QSettings::IniFormat); + casefile.setValue("author",ui_ooc_chat_name->text()); + casefile.setValue("cmdoc",""); + casefile.setValue("doc", ""); + casefile.setValue("status",command[2]); + casefile.sync(); + for(int i = local_evidence_list.size() - 1; i >= 0; i--) + { + QString clean_evidence_dsc = local_evidence_list[i].description.replace(QRegularExpression("..."), ""); + clean_evidence_dsc = clean_evidence_dsc.replace(clean_evidence_dsc.lastIndexOf(">"), 1, ""); + casefile.beginGroup(QString::number(i)); + casefile.sync(); + casefile.setValue("name",local_evidence_list[i].name); + casefile.setValue("description",local_evidence_list[i].description); + casefile.setValue("image",local_evidence_list[i].image); + casefile.endGroup(); + } + casefile.sync(); + append_server_chatmessage("CLIENT", "Succesfully saved, edit doc and cmdoc link on the ini!", "1"); + ui_ooc_chat_message->clear(); + return; + + } + + QStringList packet_contents; + packet_contents.append(ui_ooc_chat_name->text()); + packet_contents.append(ooc_message); + + AOPacket *f_packet = new AOPacket("CT", packet_contents); + + if (server_ooc) + ao_app->send_server_packet(f_packet); + else + ao_app->send_ms_packet(f_packet); + + ui_ooc_chat_message->clear(); + + ui_ooc_chat_message->setFocus(); +} + +void Courtroom::on_ooc_toggle_clicked() +{ + if (server_ooc) + { + ui_ms_chatlog->show(); + ui_server_chatlog->hide(); + ui_ooc_toggle->setText("Master"); + + server_ooc = false; + } + else + { + ui_ms_chatlog->hide(); + ui_server_chatlog->show(); + ui_ooc_toggle->setText("Server"); + + server_ooc = true; + } +} + +void Courtroom::on_music_search_edited(QString p_text) +{ + //preventing compiler warnings + p_text += "a"; + list_music(); + list_areas(); +} + +void Courtroom::on_pos_dropdown_changed(int p_index) +{ + ui_ic_chat_message->setFocus(); + + if (p_index < 0 || p_index > 5) + return; + + toggle_judge_buttons(false); + + QString f_pos; + + switch (p_index) + { + case 0: + f_pos = "wit"; + break; + case 1: + f_pos = "def"; + break; + case 2: + f_pos = "pro"; + break; + case 3: + f_pos = "jud"; + toggle_judge_buttons(true); + break; + case 4: + f_pos = "hld"; + break; + case 5: + f_pos = "hlp"; + break; + default: + f_pos = ""; + } + + if (f_pos == "" || ui_ooc_chat_name->text() == "") + return; + + ao_app->send_server_packet(new AOPacket("CT#" + ui_ooc_chat_name->text() + "#/pos " + f_pos + "#%")); +} + +void Courtroom::on_mute_list_clicked(QModelIndex p_index) +{ + QListWidgetItem *f_item = ui_mute_list->item(p_index.row()); + QString f_char = f_item->text(); + QString real_char; + + if (f_char.endsWith(" [x]")) + real_char = f_char.left(f_char.size() - 4); + else + real_char = f_char; + + int f_cid = -1; + + 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 < 0 || f_cid >= char_list.size()) + { + qDebug() << "W: " << real_char << " not present in char_list"; + return; + } + + if (mute_map.value(f_cid)) + { + mute_map.insert(f_cid, false); + f_item->setText(real_char); + } + else + { + mute_map.insert(f_cid, true); + f_item->setText(real_char + " [x]"); + } +} + +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()) + { + qDebug() << "W: " << real_char << " not present in char_list"; + return; + } + + other_charid = f_cid; + + // Redo the character list. + QStringList sorted_pair_list; + + for (char_type i_char : 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(QModelIndex p_model) +{ + if (is_muted) + return; + + QString p_song = music_list.at(music_row_to_number.at(p_model.row())); + + if (!ui_ic_chat_name->text().isEmpty() && ao_app->cccc_ic_support_enabled) + { + ao_app->send_server_packet(new AOPacket("MC#" + p_song + "#" + QString::number(m_cid) + "#" + ui_ic_chat_name->text() + "#%"), false); + } + else + { + ao_app->send_server_packet(new AOPacket("MC#" + p_song + "#" + QString::number(m_cid) + "#%"), false); + } +} + +void Courtroom::on_area_list_double_clicked(QModelIndex p_model) +{ + QString p_area = area_list.at(area_row_to_number.at(p_model.row())); + ao_app->send_server_packet(new AOPacket("MC#" + p_area + "#" + QString::number(m_cid) + "#%"), false); +} + +void Courtroom::on_hold_it_clicked() +{ + if (objection_state == 1) + { + ui_hold_it->set_image("holdit.png"); + objection_state = 0; + } + else + { + ui_objection->set_image("objection.png"); + ui_take_that->set_image("takethat.png"); + ui_custom_objection->set_image("custom.png"); + + ui_hold_it->set_image("holdit_selected.png"); + objection_state = 1; + } + + ui_ic_chat_message->setFocus(); +} + +void Courtroom::on_objection_clicked() +{ + if (objection_state == 2) + { + ui_objection->set_image("objection.png"); + objection_state = 0; + } + else + { + ui_hold_it->set_image("holdit.png"); + ui_take_that->set_image("takethat.png"); + ui_custom_objection->set_image("custom.png"); + + ui_objection->set_image("objection_selected.png"); + objection_state = 2; + } + + ui_ic_chat_message->setFocus(); +} + +void Courtroom::on_take_that_clicked() +{ + if (objection_state == 3) + { + ui_take_that->set_image("takethat.png"); + objection_state = 0; + } + else + { + ui_objection->set_image("objection.png"); + ui_hold_it->set_image("holdit.png"); + ui_custom_objection->set_image("custom.png"); + + ui_take_that->set_image("takethat_selected.png"); + objection_state = 3; + } + + ui_ic_chat_message->setFocus(); +} + +void Courtroom::on_custom_objection_clicked() +{ + if (objection_state == 4) + { + ui_custom_objection->set_image("custom.png"); + objection_state = 0; + } + else + { + ui_objection->set_image("objection.png"); + ui_take_that->set_image("takethat.png"); + ui_hold_it->set_image("holdit.png"); + + ui_custom_objection->set_image("custom_selected.png"); + objection_state = 4; + } + + ui_ic_chat_message->setFocus(); +} + +void Courtroom::on_realization_clicked() +{ + if (realization_state == 0) + { + realization_state = 1; + ui_realization->set_image("realization_pressed.png"); + } + else + { + realization_state = 0; + ui_realization->set_image("realization.png"); + } + + ui_ic_chat_message->setFocus(); +} + +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_button->set_image("pair_button.png"); + ui_mute->set_image("mute_pressed.png"); + } + else + { + ui_mute_list->hide(); + ui_mute->set_image("mute.png"); + } +} + +void Courtroom::on_pair_clicked() +{ + if (ui_pair_list->isHidden()) + { + ui_pair_list->show(); + ui_pair_offset_spinbox->show(); + ui_mute_list->hide(); + ui_mute->set_image("mute.png"); + ui_pair_button->set_image("pair_button_pressed.png"); + } + else + { + ui_pair_list->hide(); + ui_pair_offset_spinbox->hide(); + ui_pair_button->set_image("pair_button.png"); + } +} + +void Courtroom::on_defense_minus_clicked() +{ + int f_state = defense_bar_state - 1; + + if (f_state >= 0) + ao_app->send_server_packet(new AOPacket("HP#1#" + QString::number(f_state) + "#%")); +} + +void Courtroom::on_defense_plus_clicked() +{ + int f_state = defense_bar_state + 1; + + if (f_state <= 10) + ao_app->send_server_packet(new AOPacket("HP#1#" + QString::number(f_state) + "#%")); +} + +void Courtroom::on_prosecution_minus_clicked() +{ + int f_state = prosecution_bar_state - 1; + + if (f_state >= 0) + ao_app->send_server_packet(new AOPacket("HP#2#" + QString::number(f_state) + "#%")); +} + +void Courtroom::on_prosecution_plus_clicked() +{ + int f_state = prosecution_bar_state + 1; + + if (f_state <= 10) + ao_app->send_server_packet(new AOPacket("HP#2#" + QString::number(f_state) + "#%")); +} + +void Courtroom::on_text_color_changed(int p_color) +{ + text_color = p_color; + ui_ic_chat_message->setFocus(); +} + +void Courtroom::on_music_slider_moved(int p_value) +{ + music_player->set_volume(p_value); + ui_ic_chat_message->setFocus(); +} + +void Courtroom::on_sfx_slider_moved(int p_value) +{ + sfx_player->set_volume(p_value); + objection_player->set_volume(p_value); + ui_ic_chat_message->setFocus(); +} + +void Courtroom::on_blip_slider_moved(int p_value) +{ + blip_player->set_volume(p_value); + ui_ic_chat_message->setFocus(); +} + +void Courtroom::on_log_limit_changed(int value) +{ + log_maximum_blocks = value; +} + +void Courtroom::on_pair_offset_changed(int value) +{ + offset_with_pair = value; +} + +void Courtroom::on_witness_testimony_clicked() +{ + if (is_muted) + return; + + ao_app->send_server_packet(new AOPacket("RT#testimony1#%")); + + ui_ic_chat_message->setFocus(); +} + +void Courtroom::on_cross_examination_clicked() +{ + if (is_muted) + return; + + ao_app->send_server_packet(new AOPacket("RT#testimony2#%")); + + ui_ic_chat_message->setFocus(); +} + +void Courtroom::on_not_guilty_clicked() +{ + if (is_muted) + return; + + ao_app->send_server_packet(new AOPacket("RT#judgeruling#0#%")); + + ui_ic_chat_message->setFocus(); +} + +void Courtroom::on_guilty_clicked() +{ + if (is_muted) + return; + + ao_app->send_server_packet(new AOPacket("RT#judgeruling#1#%")); + + ui_ic_chat_message->setFocus(); +} + +void Courtroom::on_change_character_clicked() +{ + music_player->set_volume(0); + sfx_player->set_volume(0); + sfx_player->set_volume(0); + blip_player->set_volume(0); + + set_char_select(); + + ui_char_select_background->show(); + ui_spectator->hide(); +} + +void Courtroom::on_reload_theme_clicked() +{ + ao_app->reload_theme(); + + //to update status on the background + set_background(current_background); + enter_courtroom(m_cid); + + anim_state = 4; + text_state = 3; +} + +void Courtroom::on_back_to_lobby_clicked() +{ + ao_app->construct_lobby(); + ao_app->destruct_courtroom(); +} + +void Courtroom::on_char_select_left_clicked() +{ + --current_char_page; + set_char_select_page(); +} + +void Courtroom::on_char_select_right_clicked() +{ + ++current_char_page; + set_char_select_page(); +} + +void Courtroom::on_spectator_clicked() +{ + enter_courtroom(-1); + + ui_emotes->hide(); + + ui_char_select_background->hide(); +} + +void Courtroom::on_call_mod_clicked() +{ + if (ao_app->modcall_reason_enabled) { + QMessageBox errorBox; + QInputDialog input; + + input.setWindowFlags(Qt::WindowSystemMenuHint); + input.setLabelText("Reason:"); + input.setWindowTitle("Call Moderator"); + auto code = input.exec(); + + if (code != QDialog::Accepted) + return; + + QString text = input.textValue(); + if (text.isEmpty()) { + errorBox.critical(nullptr, "Error", "You must provide a reason."); + return; + } else if (text.length() > 256) { + errorBox.critical(nullptr, "Error", "The message is too long."); + return; + } + + QStringList mod_reason; + mod_reason.append(text); + + ao_app->send_server_packet(new AOPacket("ZZ", mod_reason)); + } else { + ao_app->send_server_packet(new AOPacket("ZZ#%")); + } + + ui_ic_chat_message->setFocus(); +} + +void Courtroom::on_settings_clicked() +{ + ao_app->call_settings_menu(); +} + +void Courtroom::on_announce_casing_clicked() +{ + ao_app->call_announce_menu(this); +} + +void Courtroom::on_pre_clicked() +{ + ui_ic_chat_message->setFocus(); +} + +void Courtroom::on_flip_clicked() +{ + ui_ic_chat_message->setFocus(); +} + +void Courtroom::on_guard_clicked() +{ + ui_ic_chat_message->setFocus(); +} + +void Courtroom::on_showname_enable_clicked() +{ + ui_ic_chatlog->clear(); + first_message_sent = false; + + foreach (chatlogpiece item, ic_chatlog_history) { + if (ui_showname_enable->isChecked()) + { + if (item.get_is_song()) + append_ic_text(item.get_message(), item.get_showname(), true); + else + append_ic_text(item.get_message(), item.get_showname()); + } + else + { + if (item.get_is_song()) + append_ic_text(item.get_message(), item.get_name(), true); + else + append_ic_text(item.get_message(), item.get_name()); + } + } + + ui_ic_chat_message->setFocus(); +} + +void Courtroom::on_evidence_button_clicked() +{ + if (ui_evidence->isHidden()) + { + ui_evidence->show(); + ui_evidence_overlay->hide(); + } + else + { + ui_evidence->hide(); + } +} + +void Courtroom::on_switch_area_music_clicked() +{ + if (ui_area_list->isHidden()) + { + ui_area_list->show(); + ui_music_list->hide(); + } + else + { + ui_area_list->hide(); + ui_music_list->show(); + } +} + +void Courtroom::ping_server() +{ + ao_app->send_server_packet(new AOPacket("CH#" + QString::number(m_cid) + "#%")); +} + +void Courtroom::on_casing_clicked() +{ + if (ao_app->casing_alerts_enabled) + { + if (ui_casing->isChecked()) + { + QStringList f_packet; + + f_packet.append(ao_app->get_casing_can_host_cases()); + f_packet.append(QString::number(ao_app->get_casing_cm_enabled())); + f_packet.append(QString::number(ao_app->get_casing_defence_enabled())); + f_packet.append(QString::number(ao_app->get_casing_prosecution_enabled())); + f_packet.append(QString::number(ao_app->get_casing_judge_enabled())); + f_packet.append(QString::number(ao_app->get_casing_juror_enabled())); + f_packet.append(QString::number(ao_app->get_casing_steno_enabled())); + + ao_app->send_server_packet(new AOPacket("SETCASE", f_packet)); + } + else + ao_app->send_server_packet(new AOPacket("SETCASE#\"\"#0#0#0#0#0#0#%")); + } +} + +void Courtroom::announce_case(QString title, bool def, bool pro, bool jud, bool jur, bool steno) +{ + if (ao_app->casing_alerts_enabled) + { + QStringList f_packet; + + f_packet.append(title); + f_packet.append(QString::number(def)); + f_packet.append(QString::number(pro)); + f_packet.append(QString::number(jud)); + f_packet.append(QString::number(jur)); + f_packet.append(QString::number(steno)); + + ao_app->send_server_packet(new AOPacket("CASEA", f_packet)); + } +} + +Courtroom::~Courtroom() +{ + delete music_player; + delete sfx_player; + delete objection_player; + delete blip_player; +} + + +#if (defined (_WIN32) || defined (_WIN64)) +void Courtroom::load_bass_opus_plugin() +{ + #ifdef BASSAUDIO + BASS_PluginLoad("bassopus.dll", 0); + #endif +} +#elif (defined (LINUX) || defined (__linux__)) +void Courtroom::load_bass_opus_plugin() +{ + #ifdef BASSAUDIO + BASS_PluginLoad("libbassopus.so", 0); + #endif +} +#elif defined __APPLE__ +void Courtroom::load_bass_opus_plugin() +{ + QString libpath = ao_app->get_base_path() + "../../Frameworks/libbassopus.dylib"; + QByteArray ba = libpath.toLocal8Bit(); + #ifdef BASSAUDIO + BASS_PluginLoad(ba.data(), 0); + #endif +} +#else +#error This operating system is unsupported for bass plugins. +#endif diff --git a/src/debug_functions.cpp b/src/debug_functions.cpp index 6186b9d..77f2f35 100644 --- a/src/debug_functions.cpp +++ b/src/debug_functions.cpp @@ -1,18 +1,14 @@ -#include -#include - #include "debug_functions.h" void call_error(QString p_message) { QMessageBox *msgBox = new QMessageBox; - msgBox->setText(QCoreApplication::translate("debug_functions", "Error: %1") - .arg(p_message)); - msgBox->setWindowTitle( - QCoreApplication::translate("debug_functions", "Error")); + msgBox->setText("Error: " + p_message); + msgBox->setWindowTitle("Error"); - // msgBox->setWindowModality(Qt::NonModal); + + //msgBox->setWindowModality(Qt::NonModal); msgBox->exec(); } @@ -21,10 +17,9 @@ void call_notice(QString p_message) QMessageBox *msgBox = new QMessageBox; msgBox->setText(p_message); + msgBox->setWindowTitle("Notice"); - msgBox->setWindowTitle( - QCoreApplication::translate("debug_functions", "Notice")); - // msgBox->setWindowModality(Qt::NonModal); + //msgBox->setWindowModality(Qt::NonModal); msgBox->exec(); } diff --git a/src/discord_rich_presence.cpp b/src/discord_rich_presence.cpp index aea07e5..95a824a 100644 --- a/src/discord_rich_presence.cpp +++ b/src/discord_rich_presence.cpp @@ -8,18 +8,23 @@ Discord::Discord() DiscordEventHandlers handlers; std::memset(&handlers, 0, sizeof(handlers)); handlers = {}; - handlers.ready = [] { qInfo() << "Discord RPC ready"; }; - handlers.disconnected = [](int errorCode, const char *message) { + handlers.ready = [] { + qInfo() << "Discord RPC ready"; + }; + handlers.disconnected = [](int errorCode, const char* message) { qInfo() << "Discord RPC disconnected! " << message << errorCode; }; - handlers.errored = [](int errorCode, const char *message) { + handlers.errored = [](int errorCode, const char* message) { qWarning() << "Discord RPC errored out! " << message << errorCode; }; qInfo() << "Initializing Discord RPC"; Discord_Initialize(APPLICATION_ID, &handlers, 1, nullptr); } -Discord::~Discord() { Discord_Shutdown(); } +Discord::~Discord() +{ + Discord_Shutdown(); +} void Discord::state_lobby() { @@ -59,12 +64,10 @@ void Discord::state_server(std::string name, std::string server_id) void Discord::state_character(std::string name) { - auto name_internal = - QString(name.c_str()).toLower().replace(' ', '_').toStdString(); + auto name_internal = QString(name.c_str()).toLower().replace(' ', '_').toStdString(); auto name_friendly = QString(name.c_str()).replace('_', ' ').toStdString(); const std::string playing_as = "Playing as " + name_friendly; - qDebug() << "Discord RPC: Setting character state (" << playing_as.c_str() - << ")"; + qDebug() << "Discord RPC: Setting character state (" << playing_as.c_str() << ")"; DiscordRichPresence presence; std::memset(&presence, 0, sizeof(presence)); @@ -98,11 +101,20 @@ void Discord::state_spectate() Discord_UpdatePresence(&presence); } #else -Discord::Discord() {} +Discord::Discord() +{ -Discord::~Discord() {} +} -void Discord::state_lobby() {} +Discord::~Discord() +{ + +} + +void Discord::state_lobby() +{ + +} void Discord::state_server(std::string name, std::string server_id) { @@ -117,6 +129,7 @@ void Discord::state_character(std::string name) void Discord::state_spectate() { qDebug() << "Discord RPC: Setting specator state"; + } #endif -} // namespace AttorneyOnline +} diff --git a/src/emotes.cpp b/src/emotes.cpp index bbe2f5c..b6a217e 100644 --- a/src/emotes.cpp +++ b/src/emotes.cpp @@ -8,8 +8,7 @@ void Courtroom::construct_emotes() set_size_and_pos(ui_emotes, "emotes"); - QPoint f_spacing = ao_app->get_button_spacing("emote_button_spacing", - "courtroom_design.ini"); + QPoint f_spacing = ao_app->get_button_spacing("emote_button_spacing", "courtroom_design.ini"); const int button_width = 40; int x_spacing = f_spacing.x(); @@ -19,14 +18,13 @@ void Courtroom::construct_emotes() int y_spacing = f_spacing.y(); int y_mod_count = 0; - emote_columns = - ((ui_emotes->width() - button_width) / (x_spacing + button_width)) + 1; - emote_rows = - ((ui_emotes->height() - button_height) / (y_spacing + button_height)) + 1; + emote_columns = ((ui_emotes->width() - button_width) / (x_spacing + button_width)) + 1; + emote_rows = ((ui_emotes->height() - button_height) / (y_spacing + button_height)) + 1; max_emotes_on_page = emote_columns * emote_rows; - for (int n = 0; n < max_emotes_on_page; ++n) { + for (int n = 0 ; n < max_emotes_on_page ; ++n) + { int x_pos = (button_width + x_spacing) * x_mod_count; int y_pos = (button_height + y_spacing) * y_mod_count; @@ -36,12 +34,12 @@ void Courtroom::construct_emotes() f_emote->set_id(n); - connect(f_emote, SIGNAL(emote_clicked(int)), this, - SLOT(on_emote_clicked(int))); + connect(f_emote, SIGNAL(emote_clicked(int)), this, SLOT(on_emote_clicked(int))); ++x_mod_count; - if (x_mod_count == emote_columns) { + if (x_mod_count == emote_columns) + { ++y_mod_count; x_mod_count = 0; } @@ -58,20 +56,23 @@ void Courtroom::set_emote_page() ui_emote_left->hide(); ui_emote_right->hide(); - for (AOEmoteButton *i_button : ui_emote_list) { + for (AOEmoteButton *i_button : ui_emote_list) + { i_button->hide(); } int total_pages = total_emotes / max_emotes_on_page; int emotes_on_page = 0; - if (total_emotes % max_emotes_on_page != 0) { + if (total_emotes % max_emotes_on_page != 0) + { ++total_pages; - // i. e. not on the last page + //i. e. not on the last page if (total_pages > current_emote_page + 1) emotes_on_page = max_emotes_on_page; else emotes_on_page = total_emotes % max_emotes_on_page; + } else emotes_on_page = max_emotes_on_page; @@ -82,7 +83,8 @@ void Courtroom::set_emote_page() if (current_emote_page > 0) ui_emote_left->show(); - for (int n_emote = 0; n_emote < emotes_on_page; ++n_emote) { + for (int n_emote = 0 ; n_emote < emotes_on_page ; ++n_emote) + { int n_real_emote = n_emote + current_emote_page * max_emotes_on_page; AOEmoteButton *f_emote = ui_emote_list.at(n_emote); @@ -93,6 +95,7 @@ void Courtroom::set_emote_page() f_emote->show(); } + } void Courtroom::set_emote_dropdown() @@ -102,7 +105,8 @@ void Courtroom::set_emote_dropdown() int total_emotes = ao_app->get_emote_number(current_char); QStringList emote_list; - for (int n = 0; n < total_emotes; ++n) { + for (int n = 0 ; n < total_emotes ; ++n) + { emote_list.append(ao_app->get_emote_comment(current_char, n)); } @@ -115,20 +119,19 @@ void Courtroom::select_emote(int p_id) int max = (max_emotes_on_page - 1) + current_emote_page * max_emotes_on_page; if (current_emote >= min && current_emote <= max) - ui_emote_list.at(current_emote % max_emotes_on_page) - ->set_image(current_char, current_emote, "_off.png"); + ui_emote_list.at(current_emote % max_emotes_on_page)->set_image(current_char, current_emote, "_off.png"); int old_emote = current_emote; current_emote = p_id; if (current_emote >= min && current_emote <= max) - ui_emote_list.at(current_emote % max_emotes_on_page) - ->set_image(current_char, current_emote, "_on.png"); + ui_emote_list.at(current_emote % max_emotes_on_page)->set_image(current_char, current_emote, "_on.png"); int emote_mod = ao_app->get_emote_mod(current_char, current_emote); - if (old_emote == current_emote) { + if (old_emote == current_emote) + { ui_pre->setChecked(!ui_pre->isChecked()); } else if (emote_mod == 1) diff --git a/src/encryption_functions.cpp b/src/encryption_functions.cpp index 6669fe1..ffbe0cd 100644 --- a/src/encryption_functions.cpp +++ b/src/encryption_functions.cpp @@ -4,8 +4,8 @@ QString fanta_encrypt(QString temp_input, unsigned int p_key) { - // using standard stdlib types is actually easier here because of implicit - // char<->int conversion which in turn makes encryption arithmetic easier + //using standard stdlib types is actually easier here because of implicit char<->int conversion + //which in turn makes encryption arithmetic easier unsigned int key = p_key; unsigned int C1 = 53761; @@ -14,7 +14,8 @@ QString fanta_encrypt(QString temp_input, unsigned int p_key) QVector temp_result; std::string input = temp_input.toUtf8().constData(); - for (unsigned int pos = 0; pos < input.size(); ++pos) { + for (unsigned int pos = 0 ; pos < input.size() ; ++pos) + { uint_fast8_t output = input.at(pos) ^ (key >> 8) % 256; temp_result.append(output); key = (temp_result.at(pos) + key) * C1 + C2; @@ -22,7 +23,8 @@ QString fanta_encrypt(QString temp_input, unsigned int p_key) std::string result = ""; - for (uint_fast8_t i_int : temp_result) { + for (uint_fast8_t i_int : temp_result) + { result += omni::int_to_hex(i_int); } @@ -37,8 +39,9 @@ QString fanta_decrypt(QString temp_input, unsigned int key) QVector unhexed_vector; - for (unsigned int i = 0; i < input.length(); i += 2) { - std::string byte = input.substr(i, 2); + for(unsigned int i=0; i< input.length(); i+=2) + { + std::string byte = input.substr(i,2); unsigned int hex_int = strtoul(byte.c_str(), nullptr, 16); unhexed_vector.append(hex_int); } @@ -48,11 +51,13 @@ QString fanta_decrypt(QString temp_input, unsigned int key) std::string result = ""; - for (int pos = 0; pos < unhexed_vector.size(); ++pos) { + for (int pos = 0 ; pos < unhexed_vector.size() ; ++pos) + { unsigned char output = unhexed_vector.at(pos) ^ (key >> 8) % 256; result += output; key = (unhexed_vector.at(pos) + key) * C1 + C2; } return QString::fromStdString(result); + } diff --git a/src/evidence.cpp b/src/evidence.cpp index 502fae7..ebef749 100644 --- a/src/evidence.cpp +++ b/src/evidence.cpp @@ -4,7 +4,7 @@ void Courtroom::construct_evidence() { ui_evidence = new AOImage(this, ao_app); - // ui_evidence_name = new QLabel(ui_evidence); + //ui_evidence_name = new QLabel(ui_evidence); ui_evidence_name = new AOLineEdit(ui_evidence); ui_evidence_name->setAlignment(Qt::AlignCenter); ui_evidence_name->setFont(QFont("Arial", 14, QFont::Bold)); @@ -22,7 +22,7 @@ void Courtroom::construct_evidence() ui_evidence_delete = new AOButton(ui_evidence_overlay, ao_app); ui_evidence_image_name = new AOLineEdit(ui_evidence_overlay); ui_evidence_image_button = new AOButton(ui_evidence_overlay, ao_app); - ui_evidence_image_button->setText(tr("Choose...")); + ui_evidence_image_button->setText("Choose.."); ui_evidence_x = new AOButton(ui_evidence_overlay, ao_app); ui_evidence_description = new AOTextEdit(ui_evidence_overlay); @@ -32,8 +32,7 @@ void Courtroom::construct_evidence() set_size_and_pos(ui_evidence, "evidence_background"); set_size_and_pos(ui_evidence_buttons, "evidence_buttons"); - QPoint f_spacing = ao_app->get_button_spacing("evidence_button_spacing", - "courtroom_design.ini"); + QPoint f_spacing = ao_app->get_button_spacing("evidence_button_spacing", "courtroom_design.ini"); const int button_width = 70; int x_spacing = f_spacing.x(); @@ -43,57 +42,43 @@ void Courtroom::construct_evidence() int y_spacing = f_spacing.y(); int y_mod_count = 0; - evidence_columns = ((ui_evidence_buttons->width() - button_width) / - (x_spacing + button_width)) + - 1; - evidence_rows = ((ui_evidence_buttons->height() - button_height) / - (y_spacing + button_height)) + - 1; + evidence_columns = ((ui_evidence_buttons->width() - button_width) / (x_spacing + button_width)) + 1; + evidence_rows = ((ui_evidence_buttons->height() - button_height) / (y_spacing + button_height)) + 1; max_evidence_on_page = evidence_columns * evidence_rows; - for (int n = 0; n < max_evidence_on_page; ++n) { + for (int n = 0 ; n < max_evidence_on_page ; ++n) + { int x_pos = (button_width + x_spacing) * x_mod_count; int y_pos = (button_height + y_spacing) * y_mod_count; - AOEvidenceButton *f_evidence = - new AOEvidenceButton(ui_evidence_buttons, ao_app, x_pos, y_pos); + AOEvidenceButton *f_evidence = new AOEvidenceButton(ui_evidence_buttons, ao_app, x_pos, y_pos); ui_evidence_list.append(f_evidence); f_evidence->set_id(n); - connect(f_evidence, SIGNAL(evidence_clicked(int)), this, - SLOT(on_evidence_clicked(int))); - connect(f_evidence, SIGNAL(evidence_double_clicked(int)), this, - SLOT(on_evidence_double_clicked(int))); - connect(f_evidence, SIGNAL(on_hover(int, bool)), this, - SLOT(on_evidence_hover(int, bool))); + connect(f_evidence, SIGNAL(evidence_clicked(int)), this, SLOT(on_evidence_clicked(int))); + connect(f_evidence, SIGNAL(evidence_double_clicked(int)), this, SLOT(on_evidence_double_clicked(int))); + connect(f_evidence, SIGNAL(on_hover(int, bool)), this, SLOT(on_evidence_hover(int, bool))); ++x_mod_count; - if (x_mod_count == evidence_columns) { + if (x_mod_count == evidence_columns) + { ++y_mod_count; x_mod_count = 0; } } - connect(ui_evidence_name, SIGNAL(returnPressed()), this, - SLOT(on_evidence_name_edited())); - connect(ui_evidence_left, SIGNAL(clicked()), this, - SLOT(on_evidence_left_clicked())); - connect(ui_evidence_right, SIGNAL(clicked()), this, - SLOT(on_evidence_right_clicked())); - connect(ui_evidence_present, SIGNAL(clicked()), this, - SLOT(on_evidence_present_clicked())); - connect(ui_evidence_delete, SIGNAL(clicked()), this, - SLOT(on_evidence_delete_clicked())); - connect(ui_evidence_image_name, SIGNAL(returnPressed()), this, - SLOT(on_evidence_image_name_edited())); - connect(ui_evidence_image_button, SIGNAL(clicked()), this, - SLOT(on_evidence_image_button_clicked())); - connect(ui_evidence_x, SIGNAL(clicked()), this, - SLOT(on_evidence_x_clicked())); + connect(ui_evidence_name, SIGNAL(returnPressed()), this, SLOT(on_evidence_name_edited())); + connect(ui_evidence_left, SIGNAL(clicked()), this, SLOT(on_evidence_left_clicked())); + connect(ui_evidence_right, SIGNAL(clicked()), this, SLOT(on_evidence_right_clicked())); + connect(ui_evidence_present, SIGNAL(clicked()), this, SLOT(on_evidence_present_clicked())); + connect(ui_evidence_delete, SIGNAL(clicked()), this, SLOT(on_evidence_delete_clicked())); + connect(ui_evidence_image_name, SIGNAL(returnPressed()), this, SLOT(on_evidence_image_name_edited())); + connect(ui_evidence_image_button, SIGNAL(clicked()), this, SLOT(on_evidence_image_button_clicked())); + connect(ui_evidence_x, SIGNAL(clicked()), this, SLOT(on_evidence_x_clicked())); ui_evidence->hide(); } @@ -113,23 +98,26 @@ void Courtroom::set_evidence_page() ui_evidence_left->hide(); ui_evidence_right->hide(); - for (AOEvidenceButton *i_button : ui_evidence_list) { + for (AOEvidenceButton *i_button : ui_evidence_list) + { i_button->reset(); } - // to account for the "add evidence" button + //to account for the "add evidence" button ++total_evidence; int total_pages = total_evidence / max_evidence_on_page; int evidence_on_page = 0; - if ((total_evidence % max_evidence_on_page) != 0) { + if ((total_evidence % max_evidence_on_page) != 0) + { ++total_pages; - // i. e. not on the last page + //i. e. not on the last page if (total_pages > current_evidence_page + 1) evidence_on_page = max_evidence_on_page; else evidence_on_page = total_evidence % max_evidence_on_page; + } else evidence_on_page = max_evidence_on_page; @@ -140,19 +128,17 @@ void Courtroom::set_evidence_page() if (current_evidence_page > 0) ui_evidence_left->show(); - for (int n_evidence_button = 0; n_evidence_button < evidence_on_page; - ++n_evidence_button) { - int n_real_evidence = - n_evidence_button + current_evidence_page * max_evidence_on_page; - AOEvidenceButton *f_evidence_button = - ui_evidence_list.at(n_evidence_button); + for (int n_evidence_button = 0 ; n_evidence_button < evidence_on_page ; ++n_evidence_button) + { + int n_real_evidence = n_evidence_button + current_evidence_page * max_evidence_on_page; + AOEvidenceButton *f_evidence_button = ui_evidence_list.at(n_evidence_button); - // ie. the add evidence button + //ie. the add evidence button if (n_real_evidence == (total_evidence - 1)) f_evidence_button->set_theme_image("addevidence.png"); - else if (n_real_evidence < (total_evidence - 1)) { - f_evidence_button->set_image( - local_evidence_list.at(n_real_evidence).image); + else if (n_real_evidence < (total_evidence - 1)) + { + f_evidence_button->set_image(local_evidence_list.at(n_real_evidence).image); if (n_real_evidence == current_evidence) f_evidence_button->set_selected(true); @@ -212,7 +198,7 @@ void Courtroom::on_evidence_image_button_clicked() QStringList filenames; if (dialog.exec()) - filenames = dialog.selectedFiles(); + filenames = dialog.selectedFiles(); if (filenames.size() != 1) return; @@ -229,9 +215,9 @@ void Courtroom::on_evidence_clicked(int p_id) int f_real_id = p_id + max_evidence_on_page * current_evidence_page; - if (f_real_id == local_evidence_list.size()) { - ao_app->send_server_packet( - new AOPacket("PE###empty.png#%")); + if (f_real_id == local_evidence_list.size()) + { + ao_app->send_server_packet(new AOPacket("PE###empty.png#%")); return; } else if (f_real_id > local_evidence_list.size()) @@ -247,6 +233,7 @@ void Courtroom::on_evidence_clicked(int p_id) current_evidence = f_real_id; ui_ic_chat_message->setFocus(); + } void Courtroom::on_evidence_double_clicked(int p_id) @@ -275,9 +262,10 @@ void Courtroom::on_evidence_hover(int p_id, bool p_state) ui_evidence_name->setReadOnly(true); int final_id = p_id + max_evidence_on_page * current_evidence_page; - if (p_state) { + if (p_state) + { if (final_id == local_evidence_list.size()) - ui_evidence_name->setText(tr("Add new evidence...")); + ui_evidence_name->setText("Add new evidence..."); else if (final_id < local_evidence_list.size()) ui_evidence_name->setText(local_evidence_list.at(final_id).name); } @@ -322,8 +310,7 @@ void Courtroom::on_evidence_delete_clicked() ui_evidence_description->setReadOnly(true); ui_evidence_overlay->hide(); - ao_app->send_server_packet( - new AOPacket("DE#" + QString::number(current_evidence) + "#%")); + ao_app->send_server_packet(new AOPacket("DE#" + QString::number(current_evidence) + "#%")); current_evidence = 0; @@ -351,3 +338,4 @@ void Courtroom::on_evidence_x_clicked() ui_ic_chat_message->setFocus(); } + diff --git a/src/file_functions.cpp b/src/file_functions.cpp index e64a46b..f93ee15 100644 --- a/src/file_functions.cpp +++ b/src/file_functions.cpp @@ -14,8 +14,7 @@ bool dir_exists(QString dir_path) return check_dir.exists(); } -bool exists(QString p_path) -{ +bool exists(QString p_path) { QFile file(p_path); return file.exists(); diff --git a/src/hardware_functions.cpp b/src/hardware_functions.cpp index 96c72eb..5d6b6ff 100644 --- a/src/hardware_functions.cpp +++ b/src/hardware_functions.cpp @@ -2,7 +2,7 @@ #include -#if (defined(_WIN32) || defined(_WIN64)) +#if (defined (_WIN32) || defined (_WIN64)) #include static DWORD dwVolSerial; @@ -10,18 +10,17 @@ static BOOL bIsRetrieved; QString get_hdid() { - bIsRetrieved = GetVolumeInformation(TEXT("C:\\"), nullptr, 0, &dwVolSerial, - nullptr, nullptr, nullptr, 0); + bIsRetrieved = GetVolumeInformation(TEXT("C:\\"), nullptr, 0, &dwVolSerial, nullptr, nullptr, nullptr, 0); if (bIsRetrieved) return QString::number(dwVolSerial, 16); else - // a totally random string - // what could possibly go wrong + //a totally random string + //what could possibly go wrong return "gxsps32sa9fnwic92mfbs0"; } -#elif (defined(LINUX) || defined(__linux__)) +#elif (defined (LINUX) || defined (__linux__)) #include #include @@ -34,10 +33,12 @@ QString get_hdid() QTextStream in(&fstab_file); - while (!in.atEnd()) { + while(!in.atEnd()) + { QString line = in.readLine(); - if (line.startsWith("UUID")) { + if (line.startsWith("UUID")) + { QStringList line_elements = line.split("="); if (line_elements.size() > 1) @@ -49,30 +50,10 @@ QString get_hdid() } #elif defined __APPLE__ -#include -#include - QString get_hdid() { - CFStringRef serial; - char buffer[64] = {0}; - QString hdid; - io_service_t platformExpert = IOServiceGetMatchingService( - kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice")); - if (platformExpert) { - CFTypeRef serialNumberAsCFString = IORegistryEntryCreateCFProperty( - platformExpert, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, - 0); - if (serialNumberAsCFString) { - serial = (CFStringRef)serialNumberAsCFString; - } - if (CFStringGetCString(serial, buffer, 64, kCFStringEncodingUTF8)) { - hdid = buffer; - } - - IOObjectRelease(platformExpert); - } - return hdid; + //hdids are broken at this point anyways + return "just a mac passing by"; } #else diff --git a/src/hex_functions.cpp b/src/hex_functions.cpp index 1e35718..4a58d2b 100644 --- a/src/hex_functions.cpp +++ b/src/hex_functions.cpp @@ -1,17 +1,18 @@ #include "hex_functions.h" -namespace omni { -std::string int_to_hex(unsigned int input) +namespace omni { - if (input > 255) - return "FF"; + std::string int_to_hex(unsigned int input) + { + if (input > 255) + return "FF"; - std::stringstream stream; - stream << std::setfill('0') << std::setw(sizeof(char) * 2) << std::hex - << input; - std::string result(stream.str()); - std::transform(result.begin(), result.end(), result.begin(), ::toupper); + std::stringstream stream; + stream << std::setfill('0') << std::setw(sizeof(char)*2) + << std::hex << input; + std::string result(stream.str()); + std::transform(result.begin(), result.end(), result.begin(), ::toupper); - return result; + return result; + } } -} // namespace omni diff --git a/src/lobby.cpp b/src/lobby.cpp index 853b6ae..4a96e56 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -1,403 +1,388 @@ -#include "lobby.h" - -#include "aoapplication.h" -#include "aosfxplayer.h" -#include "debug_functions.h" -#include "networkmanager.h" - -Lobby::Lobby(AOApplication *p_ao_app) : QMainWindow() -{ - ao_app = p_ao_app; - - this->setWindowTitle(tr("Attorney Online 2")); - this->setWindowIcon(QIcon(":/logo.png")); - - ui_background = new AOImage(this, ao_app); - ui_public_servers = new AOButton(this, ao_app); - ui_favorites = new AOButton(this, ao_app); - ui_refresh = new AOButton(this, ao_app); - ui_add_to_fav = new AOButton(this, ao_app); - ui_connect = new AOButton(this, ao_app); - ui_version = new QLabel(this); - ui_about = new AOButton(this, ao_app); - ui_server_list = new QListWidget(this); - ui_player_count = new QLabel(this); - ui_description = new AOTextArea(this); - ui_chatbox = new AOTextArea(this); - ui_chatbox->setOpenExternalLinks(true); - ui_chatname = new QLineEdit(this); - ui_chatname->setPlaceholderText(tr("Name")); - ui_chatname->setText(ao_app->get_ooc_name()); - ui_chatmessage = new QLineEdit(this); - ui_loading_background = new AOImage(this, ao_app); - ui_loading_text = new QTextEdit(ui_loading_background); - ui_progress_bar = new QProgressBar(ui_loading_background); - ui_progress_bar->setMinimum(0); - ui_progress_bar->setMaximum(100); - ui_progress_bar->setStyleSheet("QProgressBar{ color: white; }"); - ui_cancel = new AOButton(ui_loading_background, ao_app); - - connect(ui_public_servers, SIGNAL(clicked()), this, - SLOT(on_public_servers_clicked())); - connect(ui_favorites, SIGNAL(clicked()), this, SLOT(on_favorites_clicked())); - connect(ui_refresh, SIGNAL(pressed()), this, SLOT(on_refresh_pressed())); - connect(ui_refresh, SIGNAL(released()), this, SLOT(on_refresh_released())); - connect(ui_add_to_fav, SIGNAL(pressed()), this, - SLOT(on_add_to_fav_pressed())); - connect(ui_add_to_fav, SIGNAL(released()), this, - SLOT(on_add_to_fav_released())); - connect(ui_connect, SIGNAL(pressed()), this, SLOT(on_connect_pressed())); - connect(ui_connect, SIGNAL(released()), this, SLOT(on_connect_released())); - connect(ui_about, SIGNAL(clicked()), this, SLOT(on_about_clicked())); - connect(ui_server_list, SIGNAL(clicked(QModelIndex)), this, - SLOT(on_server_list_clicked(QModelIndex))); - connect(ui_server_list, SIGNAL(activated(QModelIndex)), this, - SLOT(on_server_list_doubleclicked(QModelIndex))); - connect(ui_chatmessage, SIGNAL(returnPressed()), this, - SLOT(on_chatfield_return_pressed())); - connect(ui_cancel, SIGNAL(clicked()), ao_app, SLOT(loading_cancelled())); - - ui_connect->setEnabled(false); - - list_servers(); - - set_widgets(); -} - -// sets images, position and size -void Lobby::set_widgets() -{ - ao_app->reload_theme(); - - QString filename = "lobby_design.ini"; - - pos_size_type f_lobby = ao_app->get_element_dimensions("lobby", filename); - - if (f_lobby.width < 0 || f_lobby.height < 0) { - qDebug() << "W: did not find lobby width or height in " - << ao_app->get_theme_path(filename); - - // Most common symptom of bad config files and missing assets. - call_notice( - tr("It doesn't look like your client is set up correctly.\n" - "Did you download all resources correctly from tiny.cc/getao, " - "including the large 'base' folder?")); - - this->resize(517, 666); - } - else { - this->resize(f_lobby.width, f_lobby.height); - } - - set_size_and_pos(ui_background, "lobby"); - ui_background->set_image("lobbybackground.png"); - - set_size_and_pos(ui_public_servers, "public_servers"); - ui_public_servers->set_image("publicservers_selected.png"); - - set_size_and_pos(ui_favorites, "favorites"); - ui_favorites->set_image("favorites.png"); - - set_size_and_pos(ui_refresh, "refresh"); - ui_refresh->set_image("refresh.png"); - - set_size_and_pos(ui_add_to_fav, "add_to_fav"); - ui_add_to_fav->set_image("addtofav.png"); - - set_size_and_pos(ui_connect, "connect"); - ui_connect->set_image("connect.png"); - - set_size_and_pos(ui_version, "version"); - ui_version->setText(tr("Version: %1").arg(ao_app->get_version_string())); - - set_size_and_pos(ui_about, "about"); - ui_about->set_image("about.png"); - - set_size_and_pos(ui_server_list, "server_list"); - ui_server_list->setStyleSheet("background-color: rgba(0, 0, 0, 0);" - "font: bold;"); - - set_size_and_pos(ui_player_count, "player_count"); - ui_player_count->setText(tr("Offline")); - ui_player_count->setStyleSheet("font: bold;" - "color: white;" - "qproperty-alignment: AlignCenter;"); - - set_size_and_pos(ui_description, "description"); - ui_description->setReadOnly(true); - ui_description->setStyleSheet("background-color: rgba(0, 0, 0, 0);" - "color: white;"); - - set_size_and_pos(ui_chatbox, "chatbox"); - ui_chatbox->setReadOnly(true); - ui_chatbox->setStyleSheet( - "QTextBrowser{background-color: rgba(0, 0, 0, 0);}"); - - set_size_and_pos(ui_chatname, "chatname"); - ui_chatname->setStyleSheet("background-color: rgba(0, 0, 0, 0);" - "selection-background-color: rgba(0, 0, 0, 0);"); - - set_size_and_pos(ui_chatmessage, "chatmessage"); - ui_chatmessage->setStyleSheet( - "background-color: rgba(0, 0, 0, 0);" - "selection-background-color: rgba(0, 0, 0, 0);"); - - ui_loading_background->resize(this->width(), this->height()); - ui_loading_background->set_image("loadingbackground.png"); - - set_size_and_pos(ui_loading_text, "loading_label"); - ui_loading_text->setFont(QFont("Arial", 20, QFont::Bold)); - ui_loading_text->setReadOnly(true); - ui_loading_text->setAlignment(Qt::AlignCenter); - ui_loading_text->setFrameStyle(QFrame::NoFrame); - ui_loading_text->setStyleSheet("background-color: rgba(0, 0, 0, 0);" - "color: rgba(255, 128, 0, 255);"); - ui_loading_text->append(tr("Loading")); - - set_size_and_pos(ui_progress_bar, "progress_bar"); - set_size_and_pos(ui_cancel, "cancel"); - ui_cancel->setText(tr("Cancel")); - - ui_loading_background->hide(); -} - -void Lobby::lobbyThreadHandler(QString loadingText) -{ - this->set_loading_text(loadingText); -} - -void Lobby::set_size_and_pos(QWidget *p_widget, QString p_identifier) -{ - QString filename = "lobby_design.ini"; - - pos_size_type design_ini_result = - ao_app->get_element_dimensions(p_identifier, filename); - - if (design_ini_result.width < 0 || design_ini_result.height < 0) { - qDebug() << "W: could not find " << p_identifier << " in " << filename; - p_widget->hide(); - } - else { - p_widget->move(design_ini_result.x, design_ini_result.y); - p_widget->resize(design_ini_result.width, design_ini_result.height); - } -} - -void Lobby::set_loading_text(QString p_text) -{ - ui_loading_text->clear(); - ui_loading_text->setAlignment(Qt::AlignCenter); - ui_loading_text->append(p_text); -} - -QString Lobby::get_chatlog() -{ - QString return_value = ui_chatbox->toPlainText(); - - return return_value; -} - -int Lobby::get_selected_server() { return ui_server_list->currentRow(); } - -void Lobby::set_loading_value(int p_value) -{ - ui_progress_bar->setValue(p_value); -} - -void Lobby::on_public_servers_clicked() -{ - ui_public_servers->set_image("publicservers_selected.png"); - ui_favorites->set_image("favorites.png"); - - list_servers(); - - public_servers_selected = true; -} - -void Lobby::on_favorites_clicked() -{ - ui_favorites->set_image("favorites_selected.png"); - ui_public_servers->set_image("publicservers.png"); - - ao_app->set_favorite_list(); - // ao_app->favorite_list = read_serverlist_txt(); - - list_favorites(); - - public_servers_selected = false; -} - -void Lobby::on_refresh_pressed() -{ - ui_refresh->set_image("refresh_pressed.png"); -} - -void Lobby::on_refresh_released() -{ - ui_refresh->set_image("refresh.png"); - - AOPacket *f_packet = new AOPacket("ALL#%"); - - ao_app->send_ms_packet(f_packet); -} - -void Lobby::on_add_to_fav_pressed() -{ - ui_add_to_fav->set_image("addtofav_pressed.png"); -} - -void Lobby::on_add_to_fav_released() -{ - ui_add_to_fav->set_image("addtofav.png"); - - // you cant add favorites from favorites m8 - if (!public_servers_selected) - return; - - ao_app->add_favorite_server(ui_server_list->currentRow()); -} - -void Lobby::on_connect_pressed() -{ - ui_connect->set_image("connect_pressed.png"); -} - -void Lobby::on_connect_released() -{ - ui_connect->set_image("connect.png"); - - AOPacket *f_packet; - - f_packet = new AOPacket("askchaa#%"); - - ao_app->send_server_packet(f_packet); -} - -void Lobby::on_about_clicked() -{ - QString msg = - tr("

    Attorney Online %1

    " - "The courtroom drama simulator" - "

    Source code: " - "" - "https://github.com/AttorneyOnline/AO2-Client" - "

    Major development:
    " - "OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, " - "Cents02" - "

    Special thanks:
    " - "Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), " - "Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, " - "Noevain, Cronnicossy, Raidensnake") - .arg(ao_app->get_version_string()); - QMessageBox::about(this, "About", msg); -} - -// clicked on an item in the serverlist -void Lobby::on_server_list_clicked(QModelIndex p_model) -{ - if (p_model != last_model) { - server_type f_server; - last_model = p_model; - int n_server = p_model.row(); - - if (n_server < 0) - return; - - if (public_servers_selected) { - QVector f_server_list = ao_app->get_server_list(); - - if (n_server >= f_server_list.size()) - return; - - f_server = f_server_list.at(p_model.row()); - } - else { - if (n_server >= ao_app->get_favorite_list().size()) - return; - - f_server = ao_app->get_favorite_list().at(p_model.row()); - } - - ui_description->clear(); - ui_description->append(f_server.desc); - - ui_description->moveCursor(QTextCursor::Start); - ui_description->ensureCursorVisible(); - - ui_player_count->setText(tr("Offline")); - - ui_connect->setEnabled(false); - - ao_app->net_manager->connect_to_server(f_server); - } -} - -// doubleclicked on an item in the serverlist so we'll connect right away -void Lobby::on_server_list_doubleclicked(QModelIndex p_model) -{ - on_server_list_clicked(p_model); - on_connect_released(); -} - -void Lobby::on_chatfield_return_pressed() -{ - // no you can't send empty messages - if (ui_chatname->text() == "" || ui_chatmessage->text() == "") - return; - - QString f_header = "CT"; - QStringList f_contents{ui_chatname->text(), ui_chatmessage->text()}; - - AOPacket *f_packet = new AOPacket(f_header, f_contents); - - ao_app->send_ms_packet(f_packet); - - ui_chatmessage->clear(); -} - -void Lobby::list_servers() -{ - public_servers_selected = true; - ui_favorites->set_image("favorites.png"); - ui_public_servers->set_image("publicservers_selected.png"); - - ui_server_list->clear(); - - for (server_type i_server : ao_app->get_server_list()) { - ui_server_list->addItem(i_server.name); - } -} - -void Lobby::list_favorites() -{ - ui_server_list->clear(); - - for (server_type i_server : ao_app->get_favorite_list()) { - ui_server_list->addItem(i_server.name); - } -} - -void Lobby::append_chatmessage(QString f_name, QString f_message) -{ - ui_chatbox->append_chatmessage( - f_name, f_message, - ao_app->get_color("ooc_default_color", "courtroom_design.ini").name(), - false); -} - -void Lobby::append_error(QString f_message) -{ - ui_chatbox->append_error(f_message); -} - -void Lobby::set_player_count(int players_online, int max_players) -{ - QString f_string = tr("Online: %1/%2") - .arg(QString::number(players_online)) - .arg(QString::number(max_players)); - ui_player_count->setText(f_string); -} - -void Lobby::enable_connect_button() { ui_connect->setEnabled(true); } - -Lobby::~Lobby() {} +#include "lobby.h" + +#include "debug_functions.h" +#include "aoapplication.h" +#include "networkmanager.h" +#include "aosfxplayer.h" + +Lobby::Lobby(AOApplication *p_ao_app) : QMainWindow() +{ + ao_app = p_ao_app; + + this->setWindowTitle("Attorney Online 2"); + this->setWindowIcon(QIcon(":/logo.png")); + + ui_background = new AOImage(this, ao_app); + ui_public_servers = new AOButton(this, ao_app); + ui_favorites = new AOButton(this, ao_app); + ui_refresh = new AOButton(this, ao_app); + ui_add_to_fav = new AOButton(this, ao_app); + ui_connect = new AOButton(this, ao_app); + ui_version = new QLabel(this); + ui_about = new AOButton(this, ao_app); + ui_server_list = new QListWidget(this); + ui_player_count = new QLabel(this); + ui_description = new AOTextArea(this); + ui_chatbox = new AOTextArea(this); + ui_chatbox->setOpenExternalLinks(true); + ui_chatname = new QLineEdit(this); + ui_chatname->setPlaceholderText("Name"); + ui_chatname->setText(ao_app->get_ooc_name()); + ui_chatmessage = new QLineEdit(this); + ui_loading_background = new AOImage(this, ao_app); + ui_loading_text = new QTextEdit(ui_loading_background); + ui_progress_bar = new QProgressBar(ui_loading_background); + ui_progress_bar->setMinimum(0); + ui_progress_bar->setMaximum(100); + ui_progress_bar->setStyleSheet("QProgressBar{ color: white; }"); + ui_cancel = new AOButton(ui_loading_background, ao_app); + + connect(ui_public_servers, SIGNAL(clicked()), this, SLOT(on_public_servers_clicked())); + connect(ui_favorites, SIGNAL(clicked()), this, SLOT(on_favorites_clicked())); + connect(ui_refresh, SIGNAL(pressed()), this, SLOT(on_refresh_pressed())); + connect(ui_refresh, SIGNAL(released()), this, SLOT(on_refresh_released())); + connect(ui_add_to_fav, SIGNAL(pressed()), this, SLOT(on_add_to_fav_pressed())); + connect(ui_add_to_fav, SIGNAL(released()), this, SLOT(on_add_to_fav_released())); + connect(ui_connect, SIGNAL(pressed()), this, SLOT(on_connect_pressed())); + connect(ui_connect, SIGNAL(released()), this, SLOT(on_connect_released())); + connect(ui_about, SIGNAL(clicked()), this, SLOT(on_about_clicked())); + connect(ui_server_list, SIGNAL(clicked(QModelIndex)), this, SLOT(on_server_list_clicked(QModelIndex))); + connect(ui_chatmessage, SIGNAL(returnPressed()), this, SLOT(on_chatfield_return_pressed())); + connect(ui_cancel, SIGNAL(clicked()), ao_app, SLOT(loading_cancelled())); + + ui_connect->setEnabled(false); + + list_servers(); + + set_widgets(); +} + +//sets images, position and size +void Lobby::set_widgets() +{ + ao_app->reload_theme(); + + QString filename = "lobby_design.ini"; + + pos_size_type f_lobby = ao_app->get_element_dimensions("lobby", filename); + + if (f_lobby.width < 0 || f_lobby.height < 0) + { + qDebug() << "W: did not find lobby width or height in " << filename; + + // Most common symptom of bad config files and missing assets. + call_notice("It doesn't look like your client is set up correctly.\n" + "Did you download all resources correctly from tiny.cc/getao, " + "including the large 'base' folder?"); + + this->resize(517, 666); + } + else + { + this->resize(f_lobby.width, f_lobby.height); + } + + set_size_and_pos(ui_background, "lobby"); + ui_background->set_image("lobbybackground.png"); + + set_size_and_pos(ui_public_servers, "public_servers"); + ui_public_servers->set_image("publicservers_selected.png"); + + set_size_and_pos(ui_favorites, "favorites"); + ui_favorites->set_image("favorites.png"); + + set_size_and_pos(ui_refresh, "refresh"); + ui_refresh->set_image("refresh.png"); + + set_size_and_pos(ui_add_to_fav, "add_to_fav"); + ui_add_to_fav->set_image("addtofav.png"); + + set_size_and_pos(ui_connect, "connect"); + ui_connect->set_image("connect.png"); + + set_size_and_pos(ui_version, "version"); + ui_version->setText("Version: " + ao_app->get_version_string()); + + set_size_and_pos(ui_about, "about"); + ui_about->set_image("about.png"); + + set_size_and_pos(ui_server_list, "server_list"); + ui_server_list->setStyleSheet("background-color: rgba(0, 0, 0, 0);" + "font: bold;"); + + set_size_and_pos(ui_player_count, "player_count"); + ui_player_count->setText("Offline"); + ui_player_count->setStyleSheet("font: bold;" + "color: white;" + "qproperty-alignment: AlignCenter;"); + + set_size_and_pos(ui_description, "description"); + ui_description->setReadOnly(true); + ui_description->setStyleSheet("background-color: rgba(0, 0, 0, 0);" + "color: white;"); + + set_size_and_pos(ui_chatbox, "chatbox"); + ui_chatbox->setReadOnly(true); + ui_chatbox->setStyleSheet("QTextBrowser{background-color: rgba(0, 0, 0, 0);}"); + + set_size_and_pos(ui_chatname, "chatname"); + ui_chatname->setStyleSheet("background-color: rgba(0, 0, 0, 0);" + "selection-background-color: rgba(0, 0, 0, 0);"); + + set_size_and_pos(ui_chatmessage, "chatmessage"); + ui_chatmessage->setStyleSheet("background-color: rgba(0, 0, 0, 0);" + "selection-background-color: rgba(0, 0, 0, 0);"); + + ui_loading_background->resize(this->width(), this->height()); + ui_loading_background->set_image("loadingbackground.png"); + + + set_size_and_pos(ui_loading_text, "loading_label"); + ui_loading_text->setFont(QFont("Arial", 20, QFont::Bold)); + ui_loading_text->setReadOnly(true); + ui_loading_text->setAlignment(Qt::AlignCenter); + ui_loading_text->setFrameStyle(QFrame::NoFrame); + ui_loading_text->setStyleSheet("background-color: rgba(0, 0, 0, 0);" + "color: rgba(255, 128, 0, 255);"); + ui_loading_text->append("Loading"); + + set_size_and_pos(ui_progress_bar, "progress_bar"); + set_size_and_pos(ui_cancel, "cancel"); + ui_cancel->setText("Cancel"); + + ui_loading_background->hide(); + +} + +void Lobby::set_size_and_pos(QWidget *p_widget, QString p_identifier) +{ + QString filename = "lobby_design.ini"; + + pos_size_type design_ini_result = ao_app->get_element_dimensions(p_identifier, filename); + + if (design_ini_result.width < 0 || design_ini_result.height < 0) + { + qDebug() << "W: could not find " << p_identifier << " in " << filename; + p_widget->hide(); + } + else + { + p_widget->move(design_ini_result.x, design_ini_result.y); + p_widget->resize(design_ini_result.width, design_ini_result.height); + } +} + +void Lobby::set_loading_text(QString p_text) +{ + ui_loading_text->clear(); + ui_loading_text->setAlignment(Qt::AlignCenter); + ui_loading_text->append(p_text); +} + +QString Lobby::get_chatlog() +{ + QString return_value = ui_chatbox->toPlainText(); + + return return_value; +} + +int Lobby::get_selected_server() +{ + return ui_server_list->currentRow(); +} + +void Lobby::set_loading_value(int p_value) +{ + ui_progress_bar->setValue(p_value); +} + +void Lobby::on_public_servers_clicked() +{ + ui_public_servers->set_image("publicservers_selected.png"); + ui_favorites->set_image("favorites.png"); + + list_servers(); + + public_servers_selected = true; +} + +void Lobby::on_favorites_clicked() +{ + ui_favorites->set_image("favorites_selected.png"); + ui_public_servers->set_image("publicservers.png"); + + ao_app->set_favorite_list(); + //ao_app->favorite_list = read_serverlist_txt(); + + list_favorites(); + + public_servers_selected = false; +} + +void Lobby::on_refresh_pressed() +{ + ui_refresh->set_image("refresh_pressed.png"); +} + +void Lobby::on_refresh_released() +{ + ui_refresh->set_image("refresh.png"); + + AOPacket *f_packet = new AOPacket("ALL#%"); + + ao_app->send_ms_packet(f_packet); +} + +void Lobby::on_add_to_fav_pressed() +{ + ui_add_to_fav->set_image("addtofav_pressed.png"); +} + +void Lobby::on_add_to_fav_released() +{ + ui_add_to_fav->set_image("addtofav.png"); + + //you cant add favorites from favorites m8 + if (!public_servers_selected) + return; + + ao_app->add_favorite_server(ui_server_list->currentRow()); +} + +void Lobby::on_connect_pressed() +{ + ui_connect->set_image("connect_pressed.png"); +} + +void Lobby::on_connect_released() +{ + ui_connect->set_image("connect.png"); + + AOPacket *f_packet; + + f_packet = new AOPacket("askchaa#%"); + + ao_app->send_server_packet(f_packet); +} + +void Lobby::on_about_clicked() +{ + QString msg = tr("

    Attorney Online %1

    " + "The courtroom drama simulator" + "

    Source code: " + "" + "https://github.com/AttorneyOnline/AO2-Client" + "

    Major development:
    " + "OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter" + "

    Special thanks:
    " + "Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), " + "Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, " + "Noevain, Cronnicossy") + .arg(ao_app->get_version_string()); + QMessageBox::about(this, "About", msg); +} + +void Lobby::on_server_list_clicked(QModelIndex p_model) +{ + server_type f_server; + int n_server = p_model.row(); + + if (n_server < 0) + return; + + if (public_servers_selected) + { + QVector f_server_list = ao_app->get_server_list(); + + if (n_server >= f_server_list.size()) + return; + + f_server = f_server_list.at(p_model.row()); + } + else + { + if (n_server >= ao_app->get_favorite_list().size()) + return; + + f_server = ao_app->get_favorite_list().at(p_model.row()); + } + + ui_description->clear(); + ui_description->append(f_server.desc); + + ui_description->moveCursor(QTextCursor::Start); + ui_description->ensureCursorVisible(); + + ui_player_count->setText("Offline"); + + ui_connect->setEnabled(false); + + ao_app->net_manager->connect_to_server(f_server); +} + +void Lobby::on_chatfield_return_pressed() +{ + //no you can't send empty messages + if (ui_chatname->text() == "" || ui_chatmessage->text() == "") + return; + + + QString f_header = "CT"; + QStringList f_contents{ui_chatname->text(), ui_chatmessage->text()}; + + AOPacket *f_packet = new AOPacket(f_header, f_contents); + + ao_app->send_ms_packet(f_packet); + + ui_chatmessage->clear(); +} + +void Lobby::list_servers() +{ + public_servers_selected = true; + ui_favorites->set_image("favorites.png"); + ui_public_servers->set_image("publicservers_selected.png"); + + ui_server_list->clear(); + + for (server_type i_server : ao_app->get_server_list()) + { + ui_server_list->addItem(i_server.name); + } +} + +void Lobby::list_favorites() +{ + ui_server_list->clear(); + + for (server_type i_server : ao_app->get_favorite_list()) + { + ui_server_list->addItem(i_server.name); + } +} + +void Lobby::append_chatmessage(QString f_name, QString f_message) +{ + ui_chatbox->append_chatmessage(f_name, f_message, ao_app->get_color("ooc_default_color", "courtroom_design.ini").name()); +} + +void Lobby::append_error(QString f_message) +{ + ui_chatbox->append_error(f_message); +} + +void Lobby::set_player_count(int players_online, int max_players) +{ + QString f_string = "Online: " + QString::number(players_online) + "/" + QString::number(max_players); + ui_player_count->setText(f_string); +} + +void Lobby::enable_connect_button() +{ + ui_connect->setEnabled(true); +} + +Lobby::~Lobby() +{ + +} diff --git a/src/main.cpp b/src/main.cpp index 1b105c3..80ea93b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,44 +1,24 @@ + #include "aoapplication.h" -#include "courtroom.h" #include "datatypes.h" -#include "lobby.h" #include "networkmanager.h" -#include -#include +#include "lobby.h" +#include "courtroom.h" #include -#include - +#include int main(int argc, char *argv[]) { #if QT_VERSION > QT_VERSION_CHECK(5, 6, 0) - // High-DPI support is for Qt version >=5.6. - // However, many Linux distros still haven't brought their stable/LTS - // packages up to Qt 5.6, so this is conditional. - AOApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + // High-DPI support is for Qt version >=5.6. + // However, many Linux distros still haven't brought their stable/LTS + // packages up to Qt 5.6, so this is conditional. + AOApplication::setAttribute(Qt::AA_EnableHighDpiScaling); #endif - AOApplication main_app(argc, argv); - - QSettings *configini = main_app.configini; - - QString p_language = - configini->value("language", QLocale::system().name()).toString(); - if (p_language == " " || p_language == "") - p_language = QLocale::system().name(); - - QTranslator qtTranslator; - qtTranslator.load("qt_" + p_language, - QLibraryInfo::location(QLibraryInfo::TranslationsPath)); - main_app.installTranslator(&qtTranslator); - - QTranslator appTranslator; - qDebug() << ":/resource/translations/ao_" + p_language; - appTranslator.load("ao_" + p_language, ":/resource/translations/"); - main_app.installTranslator(&appTranslator); - - main_app.construct_lobby(); - main_app.w_lobby->show(); - main_app.net_manager->connect_to_master(); - return main_app.exec(); + AOApplication main_app(argc, argv); + main_app.construct_lobby(); + main_app.net_manager->connect_to_master(); + main_app.w_lobby->show(); + return main_app.exec(); } diff --git a/src/misc_functions.cpp b/src/misc_functions.cpp index cc14415..2352055 100644 --- a/src/misc_functions.cpp +++ b/src/misc_functions.cpp @@ -4,6 +4,6 @@ void delay(int p_milliseconds) { QTime dieTime = QTime::currentTime().addMSecs(p_milliseconds); - while (QTime::currentTime() < dieTime) + while(QTime::currentTime() < dieTime) QCoreApplication::processEvents(QEventLoop::AllEvents, 100); } diff --git a/src/networkmanager.cpp b/src/networkmanager.cpp index cf89d0a..a9810d4 100644 --- a/src/networkmanager.cpp +++ b/src/networkmanager.cpp @@ -13,23 +13,21 @@ NetworkManager::NetworkManager(AOApplication *parent) : QObject(parent) ms_reconnect_timer = new QTimer(this); ms_reconnect_timer->setSingleShot(true); - QObject::connect(ms_reconnect_timer, SIGNAL(timeout()), this, - SLOT(retry_ms_connect())); + QObject::connect(ms_reconnect_timer, SIGNAL(timeout()), this, SLOT(retry_ms_connect())); - QObject::connect(ms_socket, SIGNAL(readyRead()), this, - SLOT(handle_ms_packet())); - QObject::connect(server_socket, SIGNAL(readyRead()), this, - SLOT(handle_server_packet())); - QObject::connect(server_socket, SIGNAL(disconnected()), ao_app, - SLOT(server_disconnected())); + QObject::connect(ms_socket, SIGNAL(readyRead()), this, SLOT(handle_ms_packet())); + QObject::connect(server_socket, SIGNAL(readyRead()), this, SLOT(handle_server_packet())); + QObject::connect(server_socket, SIGNAL(disconnected()), ao_app, SLOT(server_disconnected())); - QString master_config = - ao_app->configini->value("master", "").value(); + QString master_config = ao_app->configini->value("master", "").value(); if (master_config != "") ms_nosrv_hostname = master_config; } -NetworkManager::~NetworkManager() {} +NetworkManager::~NetworkManager() +{ + +} void NetworkManager::connect_to_master() { @@ -45,11 +43,11 @@ void NetworkManager::connect_to_master() void NetworkManager::connect_to_master_nosrv() { - QObject::connect(ms_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, - SLOT(on_ms_socket_error(QAbstractSocket::SocketError))); + QObject::connect(ms_socket, SIGNAL(error(QAbstractSocket::SocketError)), + this, SLOT(on_ms_socket_error(QAbstractSocket::SocketError))); - QObject::connect(ms_socket, SIGNAL(connected()), this, - SLOT(on_ms_nosrv_connect_success())); + QObject::connect(ms_socket, SIGNAL(connected()), + this, SLOT(on_ms_nosrv_connect_success())); ms_socket->connectToHost(ms_nosrv_hostname, ms_port); } @@ -63,10 +61,12 @@ void NetworkManager::connect_to_server(server_type p_server) void NetworkManager::ship_ms_packet(QString p_packet) { - if (!ms_socket->isOpen()) { + if (!ms_socket->isOpen()) + { retry_ms_connect(); } - else { + else + { ms_socket->write(p_packet.toUtf8()); } } @@ -81,86 +81,93 @@ void NetworkManager::handle_ms_packet() QByteArray buffer = ms_socket->readAll(); QString in_data = QString::fromUtf8(buffer, buffer.size()); - if (!in_data.endsWith("%")) { + if (!in_data.endsWith("%")) + { ms_partial_packet = true; ms_temp_packet += in_data; return; } - else { - if (ms_partial_packet) { + else + { + if (ms_partial_packet) + { in_data = ms_temp_packet + in_data; ms_temp_packet = ""; ms_partial_packet = false; } } - QStringList packet_list = - in_data.split("%", QString::SplitBehavior(QString::SkipEmptyParts)); + QStringList packet_list = in_data.split("%", QString::SplitBehavior(QString::SkipEmptyParts)); - for (QString packet : packet_list) { + for (QString packet : packet_list) + { AOPacket *f_packet = new AOPacket(packet); ao_app->ms_packet_received(f_packet); } } + void NetworkManager::perform_srv_lookup() { -#ifdef MS_FAILOVER_SUPPORTED + #ifdef MS_FAILOVER_SUPPORTED ms_dns = new QDnsLookup(QDnsLookup::SRV, ms_srv_hostname, this); connect(ms_dns, SIGNAL(finished()), this, SLOT(on_srv_lookup())); ms_dns->lookup(); -#endif + #endif } void NetworkManager::on_srv_lookup() { -#ifdef MS_FAILOVER_SUPPORTED + #ifdef MS_FAILOVER_SUPPORTED bool connected = false; - if (ms_dns->error() != QDnsLookup::NoError) { + if (ms_dns->error() != QDnsLookup::NoError) + { qWarning("SRV lookup of the master server DNS failed."); ms_dns->deleteLater(); } - else { + else + { const auto srv_records = ms_dns->serviceRecords(); - for (const QDnsServiceRecord &record : srv_records) { + for (const QDnsServiceRecord &record : srv_records) + { #ifdef DEBUG_NETWORK qDebug() << "Connecting to " << record.target() << ":" << record.port(); #endif ms_socket->connectToHost(record.target(), record.port()); QTime timer; timer.start(); - do { + do + { ao_app->processEvents(); - if (ms_socket->state() == QAbstractSocket::ConnectedState) { + if (ms_socket->state() == QAbstractSocket::ConnectedState) + { connected = true; break; } - else if (ms_socket->state() != QAbstractSocket::ConnectingState && - ms_socket->state() != QAbstractSocket::HostLookupState && - ms_socket->error() != -1) { + else if (ms_socket->state() != QAbstractSocket::ConnectingState + && ms_socket->state() != QAbstractSocket::HostLookupState + && ms_socket->error() != -1) + { qDebug() << ms_socket->error(); - qWarning() << "Error connecting to master server:" - << ms_socket->errorString(); + qWarning() << "Error connecting to master server:" << ms_socket->errorString(); ms_socket->abort(); ms_socket->close(); break; } - } while (timer.elapsed() < - timeout_milliseconds); // Very expensive spin-wait loop - it will - // bring CPU to 100%! - if (connected) { - // Connect a one-shot signal in case the master server disconnects - // randomly - QObject::connect( - ms_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, - SLOT(on_ms_socket_error(QAbstractSocket::SocketError))); + } while (timer.elapsed() < timeout_milliseconds); // Very expensive spin-wait loop - it will bring CPU to 100%! + if (connected) + { + // Connect a one-shot signal in case the master server disconnects randomly + QObject::connect(ms_socket, SIGNAL(error(QAbstractSocket::SocketError)), + this, SLOT(on_ms_socket_error(QAbstractSocket::SocketError))); break; } - else { + else + { ms_socket->abort(); ms_socket->close(); } @@ -172,30 +179,29 @@ void NetworkManager::on_srv_lookup() connect_to_master_nosrv(); else emit ms_connect_finished(connected, false); -#endif + #endif } void NetworkManager::on_ms_nosrv_connect_success() { emit ms_connect_finished(true, false); - QObject::disconnect(ms_socket, SIGNAL(connected()), this, - SLOT(on_ms_nosrv_connect_success())); + QObject::disconnect(ms_socket, SIGNAL(connected()), + this, SLOT(on_ms_nosrv_connect_success())); - QObject::connect(ms_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, - SLOT(on_ms_socket_error(QAbstractSocket::SocketError))); + QObject::connect(ms_socket, SIGNAL(error(QAbstractSocket::SocketError)), + this, SLOT(on_ms_socket_error(QAbstractSocket::SocketError))); } void NetworkManager::on_ms_socket_error(QAbstractSocket::SocketError error) { - qWarning() << "Master server socket error:" << ms_socket->errorString() << "(" - << error << ")"; + qWarning() << "Master server socket error:" << ms_socket->errorString() + << "(" << error << ")"; // Disconnect the one-shot signal - this way, failover connect attempts // don't trigger a full retry QObject::disconnect(ms_socket, SIGNAL(error(QAbstractSocket::SocketError)), - this, - SLOT(on_ms_socket_error(QAbstractSocket::SocketError))); + this, SLOT(on_ms_socket_error(QAbstractSocket::SocketError))); emit ms_connect_finished(false, true); @@ -204,8 +210,7 @@ void NetworkManager::on_ms_socket_error(QAbstractSocket::SocketError error) void NetworkManager::retry_ms_connect() { - if (!ms_reconnect_timer->isActive() && - ms_socket->state() != QAbstractSocket::ConnectingState) + if (!ms_reconnect_timer->isActive() && ms_socket->state() != QAbstractSocket::ConnectingState) connect_to_master(); } @@ -214,24 +219,27 @@ void NetworkManager::handle_server_packet() QByteArray buffer = server_socket->readAll(); QString in_data = QString::fromUtf8(buffer, buffer.size()); - if (!in_data.endsWith("%")) { + if (!in_data.endsWith("%")) + { partial_packet = true; temp_packet += in_data; return; } - else { - if (partial_packet) { + else + { + if (partial_packet) + { in_data = temp_packet + in_data; temp_packet = ""; partial_packet = false; } } - QStringList packet_list = - in_data.split("%", QString::SplitBehavior(QString::SkipEmptyParts)); + QStringList packet_list = in_data.split("%", QString::SplitBehavior(QString::SkipEmptyParts)); - for (QString packet : packet_list) { + for (QString packet : packet_list) + { AOPacket *f_packet = new AOPacket(packet); ao_app->server_packet_received(f_packet); diff --git a/src/packet_distribution.cpp b/src/packet_distribution.cpp index a110ec4..942c275 100644 --- a/src/packet_distribution.cpp +++ b/src/packet_distribution.cpp @@ -1,710 +1,717 @@ -#include "aoapplication.h" - -#include "courtroom.h" -#include "debug_functions.h" -#include "encryption_functions.h" -#include "hardware_functions.h" -#include "lobby.h" -#include "networkmanager.h" - -void AOPacketLoadMusic(AOApplication *my_app, QString file_name, bool is_music) -{ - if (is_music) { - my_app->w_courtroom->append_music(file_name); - } - else { - my_app->w_courtroom->append_area(file_name); - my_app->area_count++; - } - for (int area_n = 0; area_n < my_app->area_count; area_n++) { - my_app->w_courtroom->arup_append(0, "Unknown", "Unknown", "Unknown"); - } -} - -void AOApplication::ms_packet_received(AOPacket *p_packet) -{ - p_packet->net_decode(); - - QString header = p_packet->get_header(); - QStringList f_contents = p_packet->get_contents(); - -#ifdef DEBUG_NETWORK - if (header != "CHECK") - qDebug() << "R(ms):" << p_packet->to_string(); -#endif - - if (header == "ALL") { - server_list.clear(); - - for (QString i_string : p_packet->get_contents()) { - server_type f_server; - QStringList sub_contents = i_string.split("&"); - - if (sub_contents.size() < 4) { - qDebug() << "W: malformed packet"; - continue; - } - - f_server.name = sub_contents.at(0); - f_server.desc = sub_contents.at(1); - f_server.ip = sub_contents.at(2); - f_server.port = sub_contents.at(3).toInt(); - - server_list.append(f_server); - } - - if (lobby_constructed) { - w_lobby->list_servers(); - } - } - else if (header == "CT") { - QString f_name, f_message; - - if (f_contents.size() == 1) { - f_name = ""; - f_message = f_contents.at(0); - } - else if (f_contents.size() >= 2) { - f_name = f_contents.at(0); - f_message = f_contents.at(1); - } - else - goto end; - - if (lobby_constructed) { - w_lobby->append_chatmessage(f_name, f_message); - } - if (courtroom_constructed && courtroom_loaded) { - w_courtroom->append_ms_chatmessage(f_name, f_message); - } - } - else if (header == "AO2CHECK") { - send_ms_packet(new AOPacket("ID#AO2#" + get_version_string() + "#%")); - send_ms_packet(new AOPacket("HI#" + get_hdid() + "#%")); - - if (f_contents.size() < 1) - goto end; - - QStringList version_contents = f_contents.at(0).split("."); - - if (version_contents.size() < 3) - goto end; - - int f_release = version_contents.at(0).toInt(); - int f_major = version_contents.at(1).toInt(); - int f_minor = version_contents.at(2).toInt(); - - if (get_release() > f_release) - goto end; - else if (get_release() == f_release) { - if (get_major_version() > f_major) - goto end; - else if (get_major_version() == f_major) { - if (get_minor_version() >= f_minor) - goto end; - } - } - - call_notice(tr("Outdated version! Your version: %1\n" - "Please go to aceattorneyonline.com to update.") - .arg(get_version_string())); - destruct_courtroom(); - destruct_lobby(); - } - else if (header == "DOOM") { - call_notice(tr("You have been exiled from AO.\n" - "Have a nice day.")); - destruct_courtroom(); - destruct_lobby(); - } - -end: - - delete p_packet; -} - -bool AOApplication::is_music_track(QString trackname) -{ - return (trackname.startsWith("==") || trackname.endsWith(".wav") || - trackname.endsWith(".mp3") || trackname.endsWith(".mp4") || - trackname.endsWith(".ogg") || trackname.endsWith(".opus")); -} - -void AOApplication::server_packet_received(AOPacket *p_packet) -{ - p_packet->net_decode(); - - QString header = p_packet->get_header(); - QStringList f_contents = p_packet->get_contents(); - QString f_packet = p_packet->to_string(); - -#ifdef DEBUG_NETWORK - if (header != "checkconnection") - qDebug() << "R:" << f_packet; -#endif - - if (header == "decryptor") { - if (f_contents.size() == 0) - goto end; - - // you may ask where 322 comes from. that would be a good question. - s_decryptor = fanta_decrypt(f_contents.at(0), 322).toUInt(); - - // default(legacy) values - encryption_needed = true; - yellow_text_enabled = false; - prezoom_enabled = false; - flipping_enabled = false; - custom_objection_enabled = false; - improved_loading_enabled = false; - desk_mod_enabled = false; - evidence_enabled = false; - cccc_ic_support_enabled = false; - arup_enabled = false; - casing_alerts_enabled = false; - modcall_reason_enabled = false; - looping_sfx_support_enabled = false; - - // workaround for tsuserver4 - if (f_contents.at(0) == "NOENCRYPT") - encryption_needed = false; - - QString f_hdid; - f_hdid = get_hdid(); - - AOPacket *hi_packet = new AOPacket("HI#" + f_hdid + "#%"); - send_server_packet(hi_packet); - } - else if (header == "ID") { - if (f_contents.size() < 2) - goto end; - - s_pv = f_contents.at(0).toInt(); - server_software = f_contents.at(1); - - w_lobby->enable_connect_button(); - - send_server_packet(new AOPacket("ID#AO2#" + get_version_string() + "#%")); - } - else if (header == "CT") { - if (f_contents.size() < 2) - goto end; - - if (courtroom_constructed) { - if (f_contents.size() == 3) - w_courtroom->append_server_chatmessage( - f_contents.at(0), f_contents.at(1), f_contents.at(2)); - else - w_courtroom->append_server_chatmessage(f_contents.at(0), - f_contents.at(1), "0"); - } - } - else if (header == "FL") { - if (f_packet.contains("yellowtext", Qt::CaseInsensitive)) - yellow_text_enabled = true; - if (f_packet.contains("flipping", Qt::CaseInsensitive)) - flipping_enabled = true; - if (f_packet.contains("customobjections", Qt::CaseInsensitive)) - custom_objection_enabled = true; - if (f_packet.contains("fastloading", Qt::CaseInsensitive)) - improved_loading_enabled = true; - if (f_packet.contains("noencryption", Qt::CaseInsensitive)) - encryption_needed = false; - if (f_packet.contains("deskmod", Qt::CaseInsensitive)) - desk_mod_enabled = true; - if (f_packet.contains("evidence", Qt::CaseInsensitive)) - evidence_enabled = true; - if (f_packet.contains("cccc_ic_support", Qt::CaseInsensitive)) - cccc_ic_support_enabled = true; - if (f_packet.contains("arup", Qt::CaseInsensitive)) - arup_enabled = true; - if (f_packet.contains("casing_alerts", Qt::CaseInsensitive)) - casing_alerts_enabled = true; - if (f_packet.contains("modcall_reason", Qt::CaseInsensitive)) - modcall_reason_enabled = true; - if (f_packet.contains("looping_sfx", Qt::CaseInsensitive)) - looping_sfx_support_enabled = true; - - w_lobby->enable_connect_button(); - } - else if (header == "PN") { - if (f_contents.size() < 2) - goto end; - - w_lobby->set_player_count(f_contents.at(0).toInt(), - f_contents.at(1).toInt()); - } - else if (header == "SI") { - if (f_contents.size() != 3) - goto end; - - char_list_size = f_contents.at(0).toInt(); - evidence_list_size = f_contents.at(1).toInt(); - music_list_size = f_contents.at(2).toInt(); - - if (char_list_size < 1 || evidence_list_size < 0 || music_list_size < 0) - goto end; - - loaded_chars = 0; - loaded_evidence = 0; - loaded_music = 0; - generated_chars = 0; - - destruct_courtroom(); - construct_courtroom(); - - courtroom_loaded = false; - - QString window_title = tr("Attorney Online 2"); - int selected_server = w_lobby->get_selected_server(); - - QString server_address = "", server_name = ""; - if (w_lobby->public_servers_selected) { - 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, info.port); - window_title += ": " + server_name; - } - } - else { - if (selected_server >= 0 && selected_server < favorite_list.size()) { - auto info = favorite_list.at(selected_server); - server_name = info.name; - server_address = info.ip + info.port; - window_title += ": " + server_name; - } - } - - 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; - - if (improved_loading_enabled) - f_packet = new AOPacket("RC#%"); - else - f_packet = new AOPacket("askchar2#%"); - - send_server_packet(f_packet); - - QCryptographicHash hash(QCryptographicHash::Algorithm::Sha256); - hash.addData(server_address.toUtf8()); - if (is_discord_enabled()) - discord->state_server(server_name.toStdString(), - hash.result().toBase64().toStdString()); - } - else if (header == "CI") { - if (!courtroom_constructed) - goto end; - - for (int n_element = 0; n_element < f_contents.size(); n_element += 2) { - if (f_contents.at(n_element).toInt() != loaded_chars) - break; - - // this means we are on the last element and checking n + 1 element will - // be game over so - if (n_element == f_contents.size() - 1) - break; - - QStringList sub_elements = f_contents.at(n_element + 1).split("&"); - if (sub_elements.size() < 2) - break; - - char_type f_char; - f_char.name = sub_elements.at(0); - f_char.description = sub_elements.at(1); - f_char.evidence_string = sub_elements.at(3); - // temporary. the CharsCheck packet sets this properly - f_char.taken = false; - - ++loaded_chars; - - w_lobby->set_loading_text(tr("Loading chars:\n%1/%2") - .arg(QString::number(loaded_chars)) - .arg(QString::number(char_list_size))); - - w_courtroom->append_char(f_char); - - int total_loading_size = - char_list_size * 2 + evidence_list_size + music_list_size; - int loading_value = int( - ((loaded_chars + generated_chars + loaded_music + loaded_evidence) / - static_cast(total_loading_size)) * - 100); - w_lobby->set_loading_value(loading_value); - } - - if (improved_loading_enabled) - send_server_packet(new AOPacket("RE#%")); - else { - QString next_packet_number = - QString::number(((loaded_chars - 1) / 10) + 1); - send_server_packet(new AOPacket("AN#" + next_packet_number + "#%")); - } - } - else if (header == "EI") { - if (!courtroom_constructed) - goto end; - - // +1 because evidence starts at 1 rather than 0 for whatever reason - // enjoy fanta - if (f_contents.at(0).toInt() != loaded_evidence + 1) - goto end; - - if (f_contents.size() < 2) - goto end; - - QStringList sub_elements = f_contents.at(1).split("&"); - if (sub_elements.size() < 4) - goto end; - - evi_type f_evi; - f_evi.name = sub_elements.at(0); - f_evi.description = sub_elements.at(1); - // no idea what the number at position 2 is. probably an identifier? - f_evi.image = sub_elements.at(3); - - ++loaded_evidence; - - w_lobby->set_loading_text(tr("Loading evidence:\n%1/%2") - .arg(QString::number(loaded_evidence)) - .arg(QString::number(evidence_list_size))); - - w_courtroom->append_evidence(f_evi); - - int total_loading_size = - char_list_size * 2 + evidence_list_size + music_list_size; - int loading_value = - int(((loaded_chars + generated_chars + loaded_music + loaded_evidence) / - static_cast(total_loading_size)) * - 100); - w_lobby->set_loading_value(loading_value); - - QString next_packet_number = QString::number(loaded_evidence); - send_server_packet(new AOPacket("AE#" + next_packet_number + "#%")); - } - else if (header == "EM") { - if (!courtroom_constructed) - goto end; - - bool musiclist_start = false; - int areas = 0; - - for (int n_element = 0; n_element < f_contents.size(); n_element += 2) { - if (f_contents.at(n_element).toInt() != loaded_music) - break; - - if (n_element == f_contents.size() - 1) - break; - - QString f_music = f_contents.at(n_element + 1); - - ++loaded_music; - - w_lobby->set_loading_text(tr("Loading music:\n%1/%2") - .arg(QString::number(loaded_music)) - .arg(QString::number(music_list_size))); - - for (int area_n = 0; area_n < areas; area_n++) { - w_courtroom->arup_append(0, "Unknown", "Unknown", "Unknown"); - } - - int total_loading_size = - char_list_size * 2 + evidence_list_size + music_list_size; - int loading_value = int( - ((loaded_chars + generated_chars + loaded_music + loaded_evidence) / - static_cast(total_loading_size)) * - 100); - w_lobby->set_loading_value(loading_value); - } - - QString next_packet_number = QString::number(((loaded_music - 1) / 10) + 1); - send_server_packet(new AOPacket("AM#" + next_packet_number + "#%")); - } - else if (header == "CharsCheck") { - if (!courtroom_constructed) - goto end; - - for (int n_char = 0; n_char < f_contents.size(); ++n_char) { - if (f_contents.at(n_char) == "-1") - w_courtroom->set_taken(n_char, true); - else - w_courtroom->set_taken(n_char, false); - } - } - - else if (header == "SC") { - if (!courtroom_constructed) - goto end; - - for (int n_element = 0; n_element < f_contents.size(); ++n_element) { - QStringList sub_elements = f_contents.at(n_element).split("&"); - - char_type f_char; - f_char.name = sub_elements.at(0); - if (sub_elements.size() >= 2) - f_char.description = sub_elements.at(1); - - // temporary. the CharsCheck packet sets this properly - f_char.taken = false; - - ++loaded_chars; - - w_lobby->set_loading_text(tr("Loading chars:\n%1/%2") - .arg(QString::number(loaded_chars)) - .arg(QString::number(char_list_size))); - - w_courtroom->append_char(f_char); - - int total_loading_size = - char_list_size * 2 + evidence_list_size + music_list_size; - int loading_value = int( - ((loaded_chars + generated_chars + loaded_music + loaded_evidence) / - static_cast(total_loading_size)) * - 100); - w_lobby->set_loading_value(loading_value); - } - - send_server_packet(new AOPacket("RM#%")); - } - - else if (header == "SM") { - if (!courtroom_constructed) - goto end; - - bool musics_time = false; - area_count = 0; - - for (int n_element = 0; n_element < f_contents.size(); ++n_element) { - int element2check = n_element + 1; - if (element2check > f_contents.size()) { - element2check = n_element; // I know this is very lazy code but cba - } - if (!musics_time && (f_contents.at(n_element).startsWith("==") || - f_contents.at(element2check).endsWith(".wav") || - f_contents.at(element2check).endsWith(".mp3") || - f_contents.at(element2check).endsWith(".mp4") || - f_contents.at(element2check).endsWith(".ogg") || - f_contents.at(element2check).endsWith(".opus"))) { - musics_time = true; - } - - // Not everything needs to have a thread. - AOPacketLoadMusic(this, f_contents.at(n_element), musics_time); - ++loaded_music; - int total_loading_size = - char_list_size * 2 + evidence_list_size + music_list_size; - int loading_value = int( - ((loaded_chars + generated_chars + loaded_music + loaded_evidence) / - static_cast(total_loading_size)) * - 100); - w_lobby->set_loading_value(loading_value); - w_lobby->set_loading_text(tr("Loading music:\n%1/%2") - .arg(QString::number(loaded_music)) - .arg(QString::number(music_list_size))); - } - - send_server_packet(new AOPacket("RD#%")); - } - else if (header == "DONE") { - - if (!courtroom_constructed) - goto end; - - if (lobby_constructed) - w_courtroom->append_ms_chatmessage("", w_lobby->get_chatlog()); - - w_courtroom->character_loading_finished(); - w_courtroom->done_received(); - - courtroom_loaded = true; - - destruct_lobby(); - } - else if (header == "REFMUSIC") { - if (courtroom_constructed) - w_courtroom->reset_music_list(); - for (int n_element = 0; n_element < f_contents.size(); ++n_element) { - w_courtroom->append_music(f_contents.at(n_element)); - } - w_courtroom->list_music(); - } - else if (header == "BN") { - - if (f_contents.size() < 1) - goto end; - - if (courtroom_constructed) - w_courtroom->set_background(f_contents.at(0)); - } - // server accepting char request(CC) packet - else if (header == "PV") { - if (f_contents.size() < 3) - goto end; - if (f_contents.size() < 4) { - if (courtroom_constructed) - w_courtroom->enter_courtroom(f_contents.at(2).toInt()); - } - else { - if (courtroom_constructed) { - if (f_contents.at(3) == "True") { - w_courtroom->set_character(f_contents.at(2).toInt()); - } - else { - w_courtroom->enter_courtroom(f_contents.at(2).toInt()); - } - } - } - } - else if (header == "MS") { - if (courtroom_constructed && courtroom_loaded) - w_courtroom->handle_chatmessage(&p_packet->get_contents()); - } - else if (header == "MC") { - if (courtroom_constructed && courtroom_loaded) - w_courtroom->handle_song(&p_packet->get_contents()); - } - else if (header == "RT") { - if (f_contents.size() < 1) - goto end; - if (courtroom_constructed) { - if (f_contents.size() == 1) - w_courtroom->handle_wtce(f_contents.at(0), 0); - else if (f_contents.size() == 2) { - w_courtroom->handle_wtce(f_contents.at(0), f_contents.at(1).toInt()); - } - } - } - else if (header == "HP") { - if (courtroom_constructed && f_contents.size() > 1) - w_courtroom->set_hp_bar(f_contents.at(0).toInt(), - f_contents.at(1).toInt()); - } - else if (header == "LE") { - if (courtroom_constructed) { - QVector f_evi_list; - - for (QString f_string : f_contents) { - QStringList sub_contents = f_string.split("&"); - - if (sub_contents.size() < 3) - continue; - - evi_type f_evi; - f_evi.name = sub_contents.at(0); - f_evi.description = sub_contents.at(1); - f_evi.image = sub_contents.at(2); - - f_evi_list.append(f_evi); - } - - w_courtroom->set_evidence_list(f_evi_list); - } - } - else if (header == "ARUP") { - if (courtroom_constructed) { - int arup_type = f_contents.at(0).toInt(); - for (int n_element = 1; n_element < f_contents.size(); n_element++) { - w_courtroom->arup_modify(arup_type, n_element - 1, - f_contents.at(n_element)); - } - } - } - else if (header == "FAILEDLOGIN") { - if (courtroom_constructed) - w_courtroom->handle_failed_login(); - } - else if (header == "IL") { - if (courtroom_constructed && f_contents.size() > 0) - w_courtroom->set_ip_list(f_contents.at(0)); - } - else if (header == "MU") { - if (courtroom_constructed && f_contents.size() > 0) - w_courtroom->set_mute(true, f_contents.at(0).toInt()); - } - else if (header == "UM") { - if (courtroom_constructed && f_contents.size() > 0) - w_courtroom->set_mute(false, f_contents.at(0).toInt()); - } - else if (header == "KK") { - if (courtroom_constructed && f_contents.size() >= 1) { - call_notice(tr("You have been kicked from the server.\nReason: %1") - .arg(f_contents.at(0))); - construct_lobby(); - destruct_courtroom(); - } - } - else if (header == "KB") { - if (courtroom_constructed && f_contents.size() >= 1) { - call_notice(tr("You have been banned from the server.\nReason: %1") - .arg(f_contents.at(0))); - construct_lobby(); - destruct_courtroom(); - } - } - else if (header == "BD") { - call_notice( - tr("You are banned on this server.\nReason: %1").arg(f_contents.at(0))); - } - else if (header == "ZZ") { - if (courtroom_constructed && f_contents.size() > 0) - w_courtroom->mod_called(f_contents.at(0)); - } - else if (header == "CASEA") { - if (courtroom_constructed && f_contents.size() > 7) - w_courtroom->case_called(f_contents.at(0), f_contents.at(1) == "1", - f_contents.at(2) == "1", f_contents.at(3) == "1", - f_contents.at(4) == "1", f_contents.at(5) == "1", - f_contents.at(6) == "1"); - } - -end: - - delete p_packet; -} - -void AOApplication::send_ms_packet(AOPacket *p_packet) -{ - p_packet->net_encode(); - - QString f_packet = p_packet->to_string(); - - net_manager->ship_ms_packet(f_packet); - -#ifdef DEBUG_NETWORK - qDebug() << "S(ms):" << f_packet; -#endif - - delete p_packet; -} - -void AOApplication::send_server_packet(AOPacket *p_packet, bool encoded) -{ - if (encoded) - p_packet->net_encode(); - - QString f_packet = p_packet->to_string(); - - if (encryption_needed) { -#ifdef DEBUG_NETWORK - qDebug() << "S(e):" << f_packet; -#endif - - p_packet->encrypt_header(s_decryptor); - f_packet = p_packet->to_string(); - } - else { - qDebug() << "S:" << f_packet; -#ifdef DEBUG_NETWORK - qDebug() << "S:" << f_packet; -#endif - } - - net_manager->ship_server_packet(f_packet); - - delete p_packet; -} +#include "aoapplication.h" + +#include "lobby.h" +#include "courtroom.h" +#include "networkmanager.h" +#include "encryption_functions.h" +#include "hardware_functions.h" +#include "debug_functions.h" + +void AOApplication::ms_packet_received(AOPacket *p_packet) +{ + p_packet->net_decode(); + + QString header = p_packet->get_header(); + QStringList f_contents = p_packet->get_contents(); + +#ifdef DEBUG_NETWORK + if (header != "CHECK") + qDebug() << "R(ms):" << p_packet->to_string(); +#endif + + if (header == "ALL") + { + server_list.clear(); + + for (QString i_string : p_packet->get_contents()) + { + server_type f_server; + QStringList sub_contents = i_string.split("&"); + + if (sub_contents.size() < 4) + { + qDebug() << "W: malformed packet"; + continue; + } + + f_server.name = sub_contents.at(0); + f_server.desc = sub_contents.at(1); + f_server.ip = sub_contents.at(2); + f_server.port = sub_contents.at(3).toInt(); + + server_list.append(f_server); + } + + if (lobby_constructed) + { + w_lobby->list_servers(); + } + } + else if (header == "CT") + { + QString f_name, f_message; + + if (f_contents.size() == 1) + { + f_name = ""; + f_message = f_contents.at(0); + } + else if (f_contents.size() >= 2) + { + f_name = f_contents.at(0); + f_message = f_contents.at(1); + } + else + goto end; + + if (lobby_constructed) + { + w_lobby->append_chatmessage(f_name, f_message); + } + if (courtroom_constructed && courtroom_loaded) + { + w_courtroom->append_ms_chatmessage(f_name, f_message); + } + } + else if (header == "AO2CHECK") + { + send_ms_packet(new AOPacket("ID#AO2#" + get_version_string() + "#%")); + send_ms_packet(new AOPacket("HI#" + get_hdid() + "#%")); + + if (f_contents.size() < 1) + goto end; + + QStringList version_contents = f_contents.at(0).split("."); + + if (version_contents.size() < 3) + goto end; + + int f_release = version_contents.at(0).toInt(); + int f_major = version_contents.at(1).toInt(); + int f_minor = version_contents.at(2).toInt(); + + if (get_release() > f_release) + goto end; + else if (get_release() == f_release) + { + if (get_major_version() > f_major) + goto end; + else if (get_major_version() == f_major) + { + if (get_minor_version() >= f_minor) + goto end; + } + } + + call_notice("Outdated version! Your version: " + get_version_string() + + "\nPlease go to aceattorneyonline.com to update."); + destruct_courtroom(); + destruct_lobby(); + } + else if (header == "DOOM") + { + call_notice("You have been exiled from AO." + "Have a nice day."); + destruct_courtroom(); + destruct_lobby(); + } + + end: + + delete p_packet; +} + +void AOApplication::server_packet_received(AOPacket *p_packet) +{ + p_packet->net_decode(); + + QString header = p_packet->get_header(); + QStringList f_contents = p_packet->get_contents(); + QString f_packet = p_packet->to_string(); + +#ifdef DEBUG_NETWORK + if (header != "checkconnection") + qDebug() << "R:" << f_packet; +#endif + + if (header == "decryptor") + { + if (f_contents.size() == 0) + goto end; + + //you may ask where 322 comes from. that would be a good question. + s_decryptor = fanta_decrypt(f_contents.at(0), 322).toUInt(); + + //default(legacy) values + encryption_needed = true; + yellow_text_enabled = false; + prezoom_enabled = false; + flipping_enabled = false; + custom_objection_enabled = false; + improved_loading_enabled = false; + desk_mod_enabled = false; + evidence_enabled = false; + cccc_ic_support_enabled = false; + arup_enabled = false; + casing_alerts_enabled = false; + modcall_reason_enabled = false; + + //workaround for tsuserver4 + if (f_contents.at(0) == "NOENCRYPT") + encryption_needed = false; + + QString f_hdid; + f_hdid = get_hdid(); + + AOPacket *hi_packet = new AOPacket("HI#" + f_hdid + "#%"); + send_server_packet(hi_packet); + } + else if (header == "ID") + { + if (f_contents.size() < 2) + goto end; + + s_pv = f_contents.at(0).toInt(); + server_software = f_contents.at(1); + + send_server_packet(new AOPacket("ID#AO2#" + get_version_string() + "#%")); + } + else if (header == "CT") + { + if (f_contents.size() < 2) + goto end; + + if (courtroom_constructed) + { + if (f_contents.size() == 3) + w_courtroom->append_server_chatmessage(f_contents.at(0), f_contents.at(1), f_contents.at(2)); + else + w_courtroom->append_server_chatmessage(f_contents.at(0), f_contents.at(1), "0"); + } + } + else if (header == "FL") + { + if (f_packet.contains("yellowtext",Qt::CaseInsensitive)) + yellow_text_enabled = true; + if (f_packet.contains("flipping",Qt::CaseInsensitive)) + flipping_enabled = true; + if (f_packet.contains("customobjections",Qt::CaseInsensitive)) + custom_objection_enabled = true; + if (f_packet.contains("fastloading",Qt::CaseInsensitive)) + improved_loading_enabled = true; + if (f_packet.contains("noencryption",Qt::CaseInsensitive)) + encryption_needed = false; + if (f_packet.contains("deskmod",Qt::CaseInsensitive)) + desk_mod_enabled = true; + if (f_packet.contains("evidence",Qt::CaseInsensitive)) + evidence_enabled = true; + if (f_packet.contains("cccc_ic_support",Qt::CaseInsensitive)) + cccc_ic_support_enabled = true; + if (f_packet.contains("arup",Qt::CaseInsensitive)) + arup_enabled = true; + if (f_packet.contains("casing_alerts",Qt::CaseInsensitive)) + casing_alerts_enabled = true; + if (f_packet.contains("modcall_reason",Qt::CaseInsensitive)) + modcall_reason_enabled = true; + + w_lobby->enable_connect_button(); + } + else if (header == "PN") + { + if (f_contents.size() < 2) + goto end; + + w_lobby->set_player_count(f_contents.at(0).toInt(), f_contents.at(1).toInt()); + } + else if (header == "SI") + { + if (f_contents.size() != 3) + goto end; + + char_list_size = f_contents.at(0).toInt(); + evidence_list_size = f_contents.at(1).toInt(); + music_list_size = f_contents.at(2).toInt(); + + if (char_list_size < 1 || evidence_list_size < 0 || music_list_size < 0) + goto end; + + loaded_chars = 0; + loaded_evidence = 0; + loaded_music = 0; + generated_chars = 0; + + destruct_courtroom(); + construct_courtroom(); + + courtroom_loaded = false; + + QString window_title = "Attorney Online 2"; + int selected_server = w_lobby->get_selected_server(); + + QString server_address = "", server_name = ""; + if (w_lobby->public_servers_selected) + { + 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, info.port); + window_title += ": " + server_name; + } + } + else + { + if (selected_server >= 0 && selected_server < favorite_list.size()) { + auto info = favorite_list.at(selected_server); + server_name = info.name; + server_address = info.ip + info.port; + window_title += ": " + server_name; + } + } + + w_courtroom->set_window_title(window_title); + + w_lobby->show_loading_overlay(); + w_lobby->set_loading_text("Loading"); + w_lobby->set_loading_value(0); + + AOPacket *f_packet; + + if(improved_loading_enabled) + f_packet = new AOPacket("RC#%"); + else + f_packet = new AOPacket("askchar2#%"); + + send_server_packet(f_packet); + + QCryptographicHash hash(QCryptographicHash::Algorithm::Sha256); + hash.addData(server_address.toUtf8()); + if (is_discord_enabled()) + discord->state_server(server_name.toStdString(), hash.result().toBase64().toStdString()); + } + else if (header == "CI") + { + if (!courtroom_constructed) + goto end; + + for (int n_element = 0 ; n_element < f_contents.size() ; n_element += 2) + { + if (f_contents.at(n_element).toInt() != loaded_chars) + break; + + //this means we are on the last element and checking n + 1 element will be game over so + if (n_element == f_contents.size() - 1) + break; + + QStringList sub_elements = f_contents.at(n_element + 1).split("&"); + if (sub_elements.size() < 2) + break; + + char_type f_char; + f_char.name = sub_elements.at(0); + f_char.description = sub_elements.at(1); + f_char.evidence_string = sub_elements.at(3); + //temporary. the CharsCheck packet sets this properly + f_char.taken = false; + + ++loaded_chars; + + w_lobby->set_loading_text("Loading chars:\n" + QString::number(loaded_chars) + "/" + QString::number(char_list_size)); + + w_courtroom->append_char(f_char); + + int total_loading_size = char_list_size * 2 + evidence_list_size + music_list_size; + int loading_value = int(((loaded_chars + generated_chars + loaded_music + loaded_evidence) / static_cast(total_loading_size)) * 100); + w_lobby->set_loading_value(loading_value); + } + + if (improved_loading_enabled) + send_server_packet(new AOPacket("RE#%")); + else + { + QString next_packet_number = QString::number(((loaded_chars - 1) / 10) + 1); + send_server_packet(new AOPacket("AN#" + next_packet_number + "#%")); + } + + } + else if (header == "EI") + { + if (!courtroom_constructed) + goto end; + + + // +1 because evidence starts at 1 rather than 0 for whatever reason + //enjoy fanta + if (f_contents.at(0).toInt() != loaded_evidence + 1) + goto end; + + if (f_contents.size() < 2) + goto end; + + QStringList sub_elements = f_contents.at(1).split("&"); + if (sub_elements.size() < 4) + goto end; + + evi_type f_evi; + f_evi.name = sub_elements.at(0); + f_evi.description = sub_elements.at(1); + //no idea what the number at position 2 is. probably an identifier? + f_evi.image = sub_elements.at(3); + + ++loaded_evidence; + + w_lobby->set_loading_text("Loading evidence:\n" + QString::number(loaded_evidence) + "/" + QString::number(evidence_list_size)); + + w_courtroom->append_evidence(f_evi); + + int total_loading_size = char_list_size * 2 + evidence_list_size + music_list_size; + int loading_value = int(((loaded_chars + generated_chars + loaded_music + loaded_evidence) / static_cast(total_loading_size)) * 100); + w_lobby->set_loading_value(loading_value); + + QString next_packet_number = QString::number(loaded_evidence); + send_server_packet(new AOPacket("AE#" + next_packet_number + "#%")); + + } + else if (header == "EM") + { + if (!courtroom_constructed) + goto end; + + bool musics_time = false; + int areas = 0; + + for (int n_element = 0 ; n_element < f_contents.size() ; n_element += 2) + { + if (f_contents.at(n_element).toInt() != loaded_music) + break; + + if (n_element == f_contents.size() - 1) + break; + + QString f_music = f_contents.at(n_element + 1); + + ++loaded_music; + + w_lobby->set_loading_text("Loading music:\n" + QString::number(loaded_music) + "/" + QString::number(music_list_size)); + + if (musics_time) + { + w_courtroom->append_music(f_music); + } + else + { + if (f_music.endsWith(".wav") || + f_music.endsWith(".mp3") || + f_music.endsWith(".mp4") || + f_music.endsWith(".ogg") || + f_music.endsWith(".opus")) + { + musics_time = true; + areas--; + w_courtroom->fix_last_area(); + w_courtroom->append_music(f_music); + } + else + { + w_courtroom->append_area(f_music); + areas++; + } + } + + for (int area_n = 0; area_n < areas; area_n++) + { + w_courtroom->arup_append(0, "Unknown", "Unknown", "Unknown"); + } + + int total_loading_size = char_list_size * 2 + evidence_list_size + music_list_size; + int loading_value = int(((loaded_chars + generated_chars + loaded_music + loaded_evidence) / static_cast(total_loading_size)) * 100); + w_lobby->set_loading_value(loading_value); + } + + QString next_packet_number = QString::number(((loaded_music - 1) / 10) + 1); + send_server_packet(new AOPacket("AM#" + next_packet_number + "#%")); + } + else if (header == "CharsCheck") + { + if (!courtroom_constructed) + goto end; + + for (int n_char = 0 ; n_char < f_contents.size() ; ++n_char) + { + if (f_contents.at(n_char) == "-1") + w_courtroom->set_taken(n_char, true); + else + w_courtroom->set_taken(n_char, false); + } + } + + else if (header == "SC") + { + if (!courtroom_constructed) + goto end; + + for (int n_element = 0 ; n_element < f_contents.size() ; ++n_element) + { + QStringList sub_elements = f_contents.at(n_element).split("&"); + + char_type f_char; + f_char.name = sub_elements.at(0); + if (sub_elements.size() >= 2) + f_char.description = sub_elements.at(1); + + //temporary. the CharsCheck packet sets this properly + f_char.taken = false; + + ++loaded_chars; + + w_lobby->set_loading_text("Loading chars:\n" + QString::number(loaded_chars) + "/" + QString::number(char_list_size)); + + w_courtroom->append_char(f_char); + + int total_loading_size = char_list_size * 2 + evidence_list_size + music_list_size; + int loading_value = int(((loaded_chars + generated_chars + loaded_music + loaded_evidence) / static_cast(total_loading_size)) * 100); + w_lobby->set_loading_value(loading_value); + } + + send_server_packet(new AOPacket("RM#%")); + } + else if (header == "SM") + { + if (!courtroom_constructed) + goto end; + + bool musics_time = false; + int areas = 0; + + for (int n_element = 0 ; n_element < f_contents.size() ; ++n_element) + { + ++loaded_music; + + w_lobby->set_loading_text("Loading music:\n" + QString::number(loaded_music) + "/" + QString::number(music_list_size)); + + if (musics_time) + { + w_courtroom->append_music(f_contents.at(n_element)); + } + else + { + if (f_contents.at(n_element).endsWith(".wav") || + f_contents.at(n_element).endsWith(".mp3") || + f_contents.at(n_element).endsWith(".mp4") || + f_contents.at(n_element).endsWith(".ogg") || + f_contents.at(n_element).endsWith(".opus")) + { + musics_time = true; + w_courtroom->fix_last_area(); + w_courtroom->append_music(f_contents.at(n_element)); + areas--; + } + else + { + w_courtroom->append_area(f_contents.at(n_element)); + areas++; + } + } + + for (int area_n = 0; area_n < areas; area_n++) + { + w_courtroom->arup_append(0, "Unknown", "Unknown", "Unknown"); + } + + int total_loading_size = char_list_size * 2 + evidence_list_size + music_list_size; + int loading_value = int(((loaded_chars + generated_chars + loaded_music + loaded_evidence) / static_cast(total_loading_size)) * 100); + w_lobby->set_loading_value(loading_value); + } + + send_server_packet(new AOPacket("RD#%")); + } + else if (header == "DONE") + { + if (!courtroom_constructed) + goto end; + + if (lobby_constructed) + w_courtroom->append_ms_chatmessage("", w_lobby->get_chatlog()); + + w_courtroom->character_loading_finished(); + w_courtroom->done_received(); + + courtroom_loaded = true; + + destruct_lobby(); + } + else if (header == "BN") + { + if (f_contents.size() < 1) + goto end; + + if (courtroom_constructed) + w_courtroom->set_background(f_contents.at(0)); + } + //server accepting char request(CC) packet + else if (header == "PV") + { + if (f_contents.size() < 3) + goto end; + + if (courtroom_constructed) + w_courtroom->enter_courtroom(f_contents.at(2).toInt()); + } + else if (header == "MS") + { + if (courtroom_constructed && courtroom_loaded) + w_courtroom->handle_chatmessage(&p_packet->get_contents()); + } + else if (header == "MC") + { + if (courtroom_constructed && courtroom_loaded) + w_courtroom->handle_song(&p_packet->get_contents()); + } + else if (header == "RT") + { + if (f_contents.size() < 1) + goto end; + if (courtroom_constructed) + { + if (f_contents.size() == 1) + w_courtroom->handle_wtce(f_contents.at(0), 0); + else if (f_contents.size() == 2) { + w_courtroom->handle_wtce(f_contents.at(0), f_contents.at(1).toInt()); + } + } + } + else if (header == "HP") + { + if (courtroom_constructed && f_contents.size() > 1) + w_courtroom->set_hp_bar(f_contents.at(0).toInt(), f_contents.at(1).toInt()); + } + else if (header == "LE") + { + if (courtroom_constructed) + { + QVector f_evi_list; + + for (QString f_string : f_contents) + { + QStringList sub_contents = f_string.split("&"); + + if (sub_contents.size() < 3) + continue; + + evi_type f_evi; + f_evi.name = sub_contents.at(0); + f_evi.description = sub_contents.at(1); + f_evi.image = sub_contents.at(2); + + f_evi_list.append(f_evi); + } + + w_courtroom->set_evidence_list(f_evi_list); + } + } + else if (header == "ARUP") + { + if (courtroom_constructed) + { + int arup_type = f_contents.at(0).toInt(); + for (int n_element = 1 ; n_element < f_contents.size() ; n_element++) + { + w_courtroom->arup_modify(arup_type, n_element - 1, f_contents.at(n_element)); + } + } + } + else if (header == "IL") + { + if (courtroom_constructed && f_contents.size() > 0) + w_courtroom->set_ip_list(f_contents.at(0)); + } + else if (header == "MU") + { + if (courtroom_constructed && f_contents.size() > 0) + w_courtroom->set_mute(true, f_contents.at(0).toInt()); + } + else if (header == "UM") + { + if (courtroom_constructed && f_contents.size() > 0) + w_courtroom->set_mute(false, f_contents.at(0).toInt()); + } + else if (header == "KK") + { + if (courtroom_constructed && f_contents.size() >= 1) + { + call_notice("You have been kicked from the server.\nReason: " + f_contents.at(0)); + construct_lobby(); + destruct_courtroom(); + } + } + else if (header == "KB") + { + if (courtroom_constructed && f_contents.size() >= 1) + { + call_notice("You have been banned from the server.\nReason: " + f_contents.at(0)); + construct_lobby(); + destruct_courtroom(); + } + + } + else if (header == "BD") + { + call_notice("You are banned on this server.\nReason: " + f_contents.at(0)); + } + else if (header == "ZZ") + { + if (courtroom_constructed && f_contents.size() > 0) + w_courtroom->mod_called(f_contents.at(0)); + } + else if (header == "CASEA") + { + if (courtroom_constructed && f_contents.size() > 6) + w_courtroom->case_called(f_contents.at(0), f_contents.at(1) == "1", f_contents.at(2) == "1", f_contents.at(3) == "1", f_contents.at(4) == "1", f_contents.at(5) == "1"); + } + + end: + + delete p_packet; +} + +void AOApplication::send_ms_packet(AOPacket *p_packet) +{ + p_packet->net_encode(); + + QString f_packet = p_packet->to_string(); + + net_manager->ship_ms_packet(f_packet); + +#ifdef DEBUG_NETWORK + qDebug() << "S(ms):" << f_packet; +#endif + + delete p_packet; +} + +void AOApplication::send_server_packet(AOPacket *p_packet, bool encoded) +{ + if (encoded) + p_packet->net_encode(); + + QString f_packet = p_packet->to_string(); + + if (encryption_needed) + { +#ifdef DEBUG_NETWORK + qDebug() << "S(e):" << f_packet; +#endif + + p_packet->encrypt_header(s_decryptor); + f_packet = p_packet->to_string(); + } + else + { +#ifdef DEBUG_NETWORK + qDebug() << "S:" << f_packet; +#endif + } + + net_manager->ship_server_packet(f_packet); + + delete p_packet; +} diff --git a/src/path_functions.cpp b/src/path_functions.cpp index 358f146..c51cfde 100644 --- a/src/path_functions.cpp +++ b/src/path_functions.cpp @@ -3,18 +3,18 @@ #include "file_functions.h" #include -#include #include +#include #ifdef BASE_OVERRIDE #include "base_override.h" #endif -// this is a quite broad generalization -// the most common OSes(mac and windows) are _usually_ case insensitive -// however, there do exist mac installations with case sensitive filesystems -// in that case, define CASE_SENSITIVE_FILESYSTEM and compile on a mac -#if (defined(LINUX) || defined(__linux__)) +//this is a quite broad generalization +//the most common OSes(mac and windows) are _usually_ case insensitive +//however, there do exist mac installations with case sensitive filesystems +//in that case, define CASE_SENSITIVE_FILESYSTEM and compile on a mac +#if (defined (LINUX) || defined (__linux__)) #define CASE_SENSITIVE_FILESYSTEM #endif @@ -23,15 +23,13 @@ QString AOApplication::get_base_path() QString base_path = ""; #ifdef ANDROID QString sdcard_storage = getenv("SECONDARY_STORAGE"); - if (dir_exists(sdcard_storage + "/AO2/")) { + if (dir_exists(sdcard_storage + "/AO2/")){ base_path = sdcard_storage + "/AO2/"; } else { QString external_storage = getenv("EXTERNAL_STORAGE"); base_path = external_storage + "/AO2/"; } -#elif defined __APPLE__ - base_path = applicationDirPath() + "/../../../base/"; #else base_path = applicationDirPath() + "/base/"; #endif @@ -39,7 +37,10 @@ QString AOApplication::get_base_path() return base_path; } -QString AOApplication::get_data_path() { return get_base_path() + "data/"; } +QString AOApplication::get_data_path() +{ + return get_base_path() + "data/"; +} QString AOApplication::get_default_theme_path(QString p_file) { @@ -93,46 +94,17 @@ QString AOApplication::get_sounds_path(QString p_file) QString AOApplication::get_music_path(QString p_song) { - QString withending_check = get_base_path() + "sounds/music/" + p_song; - QString mp3_check = get_base_path() + "sounds/music/" + p_song + ".mp3"; - QString opus_check = get_base_path() + "sounds/music/" + p_song + ".opus"; - if (p_song.startsWith("http")) { - //it's an URL - return p_song; - } - else if (file_exists(opus_check)) { + QString path = get_base_path() + "sounds/music/" + p_song; #ifndef CASE_SENSITIVE_FILESYSTEM - return opus_check; + return path; #else - return get_case_sensitive_path(opus_check); -#endif - } - else if (file_exists(mp3_check)) { -#ifndef CASE_SENSITIVE_FILESYSTEM - return mp3_check; -#else - return get_case_sensitive_path(mp3_check); -#endif - } - else if (file_exists(withending_check)) { -#ifndef CASE_SENSITIVE_FILESYSTEM - return withending_check; -#else - return get_case_sensitive_path(withending_check); -#endif - } -#ifndef CASE_SENSITIVE_FILESYSTEM - return get_base_path() + "sounds/music/" + p_song + ".wav"; -#else - return get_case_sensitive_path(get_base_path() + "sounds/music/" + p_song + - ".wav"); + return get_case_sensitive_path(path); #endif } QString AOApplication::get_background_path(QString p_file) { - QString path = get_base_path() + "background/" + - w_courtroom->get_current_background() + "/" + p_file; + QString path = get_base_path() + "background/" + w_courtroom->get_current_background() + "/" + p_file; if (courtroom_constructed) { #ifndef CASE_SENSITIVE_FILESYSTEM return path; @@ -163,25 +135,21 @@ QString AOApplication::get_evidence_path(QString p_file) #endif } -QString AOApplication::get_case_sensitive_path(QString p_file) -{ - // first, check to see if it's actually there (also serves as base case for - // recursion) - if (exists(p_file)) - return p_file; +QString AOApplication::get_case_sensitive_path(QString p_file) { + //first, check to see if it's actually there (also serves as base case for recursion) + if (exists(p_file)) return p_file; QFileInfo file(p_file); QString file_basename = file.fileName(); QString file_parent_dir = get_case_sensitive_path(file.absolutePath()); - // second, does it exist in the new parent dir? + //second, does it exist in the new parent dir? if (exists(file_parent_dir + "/" + file_basename)) return file_parent_dir + "/" + file_basename; - // last resort, dirlist parent dir and find case insensitive match - QRegExp file_rx = - QRegExp(file_basename, Qt::CaseInsensitive, QRegExp::FixedString); + //last resort, dirlist parent dir and find case insensitive match + QRegExp file_rx = QRegExp(file_basename, Qt::CaseInsensitive, QRegExp::FixedString); QStringList files = QDir(file_parent_dir).entryList(); int result = files.indexOf(file_rx); @@ -189,6 +157,6 @@ QString AOApplication::get_case_sensitive_path(QString p_file) if (result != -1) return file_parent_dir + "/" + files.at(result); - // if nothing is found, let the caller handle the missing file + //if nothing is found, let the caller handle the missing file return file_parent_dir + "/" + file_basename; } diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index f2bec87..5a34ac8 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -1,835 +1,656 @@ -#include "text_file_functions.h" - -QString AOApplication::read_theme() -{ - QString result = configini->value("theme", "default").value(); - return result; -} - -int AOApplication::read_blip_rate() -{ - int result = configini->value("blip_rate", 2).toInt(); - - if (result < 1) - return 1; - - return result; -} - -QString AOApplication::get_ooc_name() -{ - QString result = configini->value("ooc_name").value(); - return result; -} - -int AOApplication::get_default_music() -{ - int result = configini->value("default_music", 50).toInt(); - return result; -} - -int AOApplication::get_default_sfx() -{ - int result = configini->value("default_sfx", 50).toInt(); - return result; -} - -int AOApplication::get_default_blip() -{ - int result = configini->value("default_blip", 50).toInt(); - return result; -} - -int AOApplication::get_max_log_size() -{ - int result = configini->value("log_maximum", 200).toInt(); - return result; -} - -bool AOApplication::get_slower_blips() -{ - QString result = - configini->value("slower_blips", "false").value(); - return result.startsWith("true"); -} - -bool AOApplication::get_pundelay() -{ - QString result = - configini->value("punctuation_delay", "false").value(); - return result.startsWith("true"); -} - -bool AOApplication::get_log_goes_downwards() -{ - QString result = - configini->value("log_goes_downwards", "false").value(); - return result.startsWith("true"); -} - -bool AOApplication::get_showname_enabled_by_default() -{ - QString result = - configini->value("show_custom_shownames", "true").value(); - return result.startsWith("true"); -} - -QString AOApplication::get_default_username() -{ - QString result = configini->value("default_username", "").value(); - if (result.isEmpty()) - return get_ooc_name(); - else - return result; -} - -QString AOApplication::get_audio_output_device() -{ - QString result = - configini->value("default_audio_device", "default").value(); - return result; -} - -QStringList AOApplication::get_call_words() -{ - QStringList return_value; - - QFile callwords_ini; - - callwords_ini.setFileName(get_base_path() + "callwords.ini"); - - if (!callwords_ini.open(QIODevice::ReadOnly)) - return return_value; - - QTextStream in(&callwords_ini); - - while (!in.atEnd()) { - QString line = in.readLine(); - return_value.append(line); - } - - return return_value; -} - -void AOApplication::write_to_serverlist_txt(QString p_line) -{ - QFile serverlist_txt; - QString serverlist_txt_path = get_base_path() + "serverlist.txt"; - - serverlist_txt.setFileName(serverlist_txt_path); - - if (!serverlist_txt.open(QIODevice::WriteOnly | QIODevice::Append)) { - return; - } - - QTextStream out(&serverlist_txt); - - out << "\r\n" << p_line; - - serverlist_txt.close(); -} - -QVector AOApplication::read_serverlist_txt() -{ - QVector f_server_list; - - QFile serverlist_txt; - QString serverlist_txt_path = get_base_path() + "serverlist.txt"; - - serverlist_txt.setFileName(serverlist_txt_path); - - if (!serverlist_txt.open(QIODevice::ReadOnly)) { - return f_server_list; - } - - QTextStream in(&serverlist_txt); - - while (!in.atEnd()) { - QString line = in.readLine(); - server_type f_server; - QStringList line_contents = line.split(":"); - - if (line_contents.size() < 3) - continue; - - f_server.ip = line_contents.at(0); - f_server.port = line_contents.at(1).toInt(); - f_server.name = line_contents.at(2); - f_server.desc = ""; - - f_server_list.append(f_server); - } - - return f_server_list; -} - -QString AOApplication::read_design_ini(QString p_identifier, - QString p_design_path) -{ - QSettings settings(p_design_path, QSettings::IniFormat); - settings.setIniCodec("UTF-8"); - QVariant value = settings.value(p_identifier); - if (value.isNull()) // Since the value wasn't found, maybe it uses the proper - // config system - { - int last_underscore_index = p_identifier.lastIndexOf( - '_'); // we will use this in order to check wether it is just showname - // or showname_something - if (last_underscore_index != -1) { - p_identifier.replace( - last_underscore_index, 1, - '/'); // we replace the last dash in order to access the category, e.g - // from showname_font -> showname/font - value = settings.value(p_identifier); - } - else if (!settings.value(p_identifier + "/size") - .isNull()) // This is to check whether showname/size exists, - // because size is defined as widgetname = x - { - value = settings.value(p_identifier + "/size"); - } - } - if (value.type() == QVariant::StringList) { - return value.toStringList().join(","); - } - else { - return value.toString(); - } -} - -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); - - QPoint return_value; - - return_value.setX(0); - return_value.setY(0); - - if (f_result == "") { - f_result = read_design_ini(p_identifier, default_path); - - if (f_result == "") - return return_value; - } - - QStringList sub_line_elements = f_result.split(","); - - if (sub_line_elements.size() < 2) - return return_value; - - return_value.setX(sub_line_elements.at(0).toInt()); - return_value.setY(sub_line_elements.at(1).toInt()); - - return return_value; -} - -pos_size_type AOApplication::get_element_dimensions(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); - - pos_size_type return_value; - - return_value.x = 0; - return_value.y = 0; - return_value.width = -1; - return_value.height = -1; - - if (f_result == "") { - f_result = read_design_ini(p_identifier, default_path); - - if (f_result == "") - return return_value; - } - - QStringList sub_line_elements = f_result.split(","); - - if (sub_line_elements.size() < 4) - return return_value; - - return_value.x = sub_line_elements.at(0).toInt(); - return_value.y = sub_line_elements.at(1).toInt(); - return_value.width = sub_line_elements.at(2).toInt(); - return_value.height = sub_line_elements.at(3).toInt(); - - return return_value; -} -QString AOApplication::get_font_name(QString p_identifier, QString p_file) -{ - 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 "Sans"; - } - return f_result; -} -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(); -} - -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); - - QColor return_color(0, 0, 0); - - if (f_result == "") { - f_result = read_design_ini(p_identifier, default_path); - - if (f_result == "") - return return_color; - } - - QStringList color_list = f_result.split(","); - - if (color_list.size() < 3) - return return_color; - - return_color.setRed(color_list.at(0).toInt()); - return_color.setGreen(color_list.at(1).toInt()); - return_color.setBlue(color_list.at(2).toInt()); - - return return_color; -} - -QColor AOApplication::get_chat_color(QString p_identifier, QString p_chat) -{ - QColor return_color(255, 255, 255); - - if (p_identifier == "_inline_grey") { - return_color = QColor(187, 187, 187); - } - else { - switch (p_identifier.toInt()) { - case 1: - return_color = QColor(0, 255, 0); - break; - case 2: - return_color = QColor(255, 0, 0); - break; - case 3: - return_color = QColor(255, 165, 0); - break; - case 4: - return_color = QColor(45, 150, 255); - break; - case 5: - return_color = QColor(255, 255, 0); - break; - case 7: - return_color = QColor(255, 192, 203); - break; - case 8: - return_color = QColor(0, 255, 255); - break; - case 0: - case 6: // 6 is rainbow. - default: - return_color = QColor(255, 255, 255); - break; - } - } - - p_identifier = p_identifier.prepend("c"); - QString design_ini_path = get_base_path() + "misc/" + p_chat + "/config.ini"; - QString default_path = get_base_path() + "misc/default/config.ini"; - 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 return_color; - } - - QStringList color_list = f_result.split(","); - - if (color_list.size() < 3) - return return_color; - - return_color.setRed(color_list.at(0).toInt()); - return_color.setGreen(color_list.at(1).toInt()); - return_color.setBlue(color_list.at(2).toInt()); - - return return_color; -} - -QString AOApplication::get_sfx(QString p_identifier) -{ - QString design_ini_path = get_theme_path("courtroom_sounds.ini"); - QString default_path = get_default_theme_path("courtroom_sounds.ini"); - QString f_result = read_design_ini(p_identifier, design_ini_path); - - QString return_sfx = ""; - - if (f_result == "") { - f_result = read_design_ini(p_identifier, default_path); - - if (f_result == "") - return return_sfx; - } - - return_sfx = f_result; - - return return_sfx; -} - -QString AOApplication::get_music_prefix(QString song_to_check) -{ - if (!file_exists(get_music_path(song_to_check))) { - QString mp3_check = get_music_path(song_to_check + ".mp3"); - QString opus_check = get_music_path(song_to_check + ".opus"); - if (file_exists(opus_check)) { - return song_to_check + ".opus"; - } - else if (file_exists(mp3_check)) { - return song_to_check + ".mp3"; - } - return song_to_check + ".wav"; - } - else { - return song_to_check; - } -} - -QString AOApplication::get_sfx_suffix(QString sound_to_check) -{ - if (!file_exists(get_sounds_path(sound_to_check))) { - QString mp3_check = get_sounds_path(sound_to_check + ".mp3"); - QString opus_check = get_sounds_path(sound_to_check + ".opus"); - if (file_exists(opus_check)) { - return sound_to_check + ".opus"; - } - else if (file_exists(mp3_check)) { - return sound_to_check + ".mp3"; - } - return sound_to_check + ".wav"; - } - else { - return sound_to_check; - } -} - -QString AOApplication::get_image_suffix(QString 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"; -} - -// returns whatever is to the right of "search_line =" within target_tag and -// terminator_tag, trimmed returns the empty string if the search line couldnt -// be found -QString AOApplication::read_char_ini(QString p_char, QString p_search_line, - QString target_tag) -{ - QSettings settings(get_character_path(p_char, "char.ini"), - QSettings::IniFormat); - settings.setIniCodec("UTF-8"); - settings.beginGroup(target_tag); - QString value = settings.value(p_search_line).toString(); - settings.endGroup(); - return value; -} - -QString AOApplication::get_char_name(QString p_char) -{ - QString f_result = read_char_ini(p_char, "name", "Options"); - - if (f_result == "") - return p_char; - else - return f_result; -} - -QString AOApplication::get_showname(QString p_char) -{ - QString f_result = read_char_ini(p_char, "showname", "Options"); - QString f_needed = read_char_ini(p_char, "needs_showname", "Options"); - - if (f_needed.startsWith("false")) - return ""; - if (f_result == "") - return p_char; - else - return f_result; -} - -QString AOApplication::get_char_side(QString p_char) -{ - QString f_result = read_char_ini(p_char, "side", "Options"); - - if (f_result == "") - return "wit"; - else - return f_result; -} - -QString AOApplication::get_gender(QString p_char) -{ - QString f_result = read_char_ini(p_char, "gender", "Options"); - - if (f_result == "") - return "male"; - else - return f_result; -} - -QString AOApplication::get_chat(QString p_char) -{ - 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; -} - -QString AOApplication::get_char_shouts(QString p_char) -{ - QString f_result = read_char_ini(p_char, "shouts", "Options"); - if (f_result == "") - return "default"; - else - 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"); - - if (f_result == "") - return -1; - else - return f_result.toInt(); -} - -int AOApplication::get_ao2_preanim_duration(QString p_char, QString p_emote) -{ - QString f_result = read_char_ini(p_char, "%" + p_emote, "Time"); - - if (f_result == "") - return -1; - else - return f_result.toInt(); -} - -int AOApplication::get_emote_number(QString p_char) -{ - QString f_result = read_char_ini(p_char, "number", "Emotions"); - - if (f_result == "") - return 0; - else - return f_result.toInt(); -} - -QString AOApplication::get_emote_comment(QString p_char, int p_emote) -{ - QString f_result = - read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); - - QStringList result_contents = f_result.split("#"); - - if (result_contents.size() < 4) { - qDebug() << "W: misformatted char.ini: " << p_char << ", " << p_emote; - return "normal"; - } - else - return result_contents.at(0); -} - -QString AOApplication::get_pre_emote(QString p_char, int p_emote) -{ - QString f_result = - read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); - - QStringList result_contents = f_result.split("#"); - - if (result_contents.size() < 4) { - qDebug() << "W: misformatted char.ini: " << p_char << ", " << p_emote; - return ""; - } - else - return result_contents.at(1); -} - -QString AOApplication::get_emote(QString p_char, int p_emote) -{ - QString f_result = - read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); - - QStringList result_contents = f_result.split("#"); - - if (result_contents.size() < 4) { - qDebug() << "W: misformatted char.ini: " << p_char << ", " << p_emote; - return "normal"; - } - else - return result_contents.at(2); -} - -int AOApplication::get_emote_mod(QString p_char, int p_emote) -{ - QString f_result = - read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); - - QStringList result_contents = f_result.split("#"); - - if (result_contents.size() < 4) { - qDebug() << "W: misformatted char.ini: " << p_char << ", " - << QString::number(p_emote); - return 0; - } - else - return result_contents.at(3).toInt(); -} - -int AOApplication::get_desk_mod(QString p_char, int p_emote) -{ - QString f_result = - read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); - - QStringList result_contents = f_result.split("#"); - - if (result_contents.size() < 5) - return -1; - - QString string_result = result_contents.at(4); - if (string_result == "") - return -1; - - else - return string_result.toInt(); -} - -QString AOApplication::get_sfx_name(QString p_char, int p_emote) -{ - QString f_result = - read_char_ini(p_char, QString::number(p_emote + 1), "SoundN"); - - if (f_result == "") - return "1"; - else - return f_result; -} - -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"); - - if (f_result == "") - return "0"; - else - return f_result; -} - -QString AOApplication::get_frame_sfx_name(QString p_char, QString p_emote, - int n_frame) -{ - QString f_result = read_char_ini(p_char, QString::number(n_frame), - p_emote.append("_FrameSFX")); - if (f_result == "") - return ""; - else - return f_result; -} - -QString AOApplication::get_screenshake_frame(QString p_char, QString p_emote, - int n_frame) -{ - QString f_result = read_char_ini(p_char, QString::number(n_frame), - p_emote.append("_FrameScreenshake")); - if (f_result == "") - return ""; - else - return f_result; -} - -QString AOApplication::get_realization_frame(QString p_char, QString p_emote, - int n_frame) -{ - QString f_result = read_char_ini(p_char, QString::number(n_frame), - p_emote.append("_FrameRealization")); - if (f_result == "") - return ""; - else - return f_result; -} - -int AOApplication::get_sfx_delay(QString p_char, int p_emote) -{ - QString f_result = - read_char_ini(p_char, QString::number(p_emote + 1), "SoundT"); - - if (f_result == "") - return 1; - else - return f_result.toInt(); -} - -int AOApplication::get_text_delay(QString p_char, QString p_emote) -{ - QString f_result = read_char_ini(p_char, p_emote, "TextDelay"); - - if (f_result == "") - return -1; - else - return f_result.toInt(); -} - -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(f_result); -} - -bool AOApplication::get_blank_blip() -{ - QString result = configini->value("blank_blip", "false").value(); - return result.startsWith("true"); -} - -bool AOApplication::get_looping_sfx() -{ - QString result = configini->value("looping_sfx", "true").value(); - return result.startsWith("true"); -} - -bool AOApplication::get_objectmusic() -{ - QString result = - configini->value("kill_music_on_object", "false").value(); - return result.startsWith("true"); -} - -bool AOApplication::is_discord_enabled() -{ - QString result = configini->value("discord", "true").value(); - return result.startsWith("true"); -} - -bool AOApplication::is_keepevi_enabled() -{ - QString result = configini->value("keep_evidence", "false").value(); - return result.startsWith("true"); -} - -bool AOApplication::get_casing_enabled() -{ - QString result = configini->value("casing_enabled", "false").value(); - return result.startsWith("true"); -} - -bool AOApplication::get_casing_defence_enabled() -{ - QString result = - configini->value("casing_defence_enabled", "false").value(); - return result.startsWith("true"); -} - -bool AOApplication::get_casing_prosecution_enabled() -{ - QString result = - configini->value("casing_prosecution_enabled", "false").value(); - return result.startsWith("true"); -} - -bool AOApplication::get_casing_judge_enabled() -{ - QString result = - configini->value("casing_judge_enabled", "false").value(); - return result.startsWith("true"); -} - -bool AOApplication::get_casing_juror_enabled() -{ - QString result = - configini->value("casing_juror_enabled", "false").value(); - return result.startsWith("true"); -} - -bool AOApplication::get_casing_steno_enabled() -{ - QString result = - configini->value("casing_steno_enabled", "false").value(); - return result.startsWith("true"); -} - -bool AOApplication::get_casing_wit_enabled() -{ - QString result = - configini->value("casing_wit_enabled", "false").value(); - return result.startsWith("true"); -} - -bool AOApplication::get_casing_cm_enabled() -{ - QString result = - configini->value("casing_cm_enabled", "false").value(); - return result.startsWith("true"); -} - -QString AOApplication::get_casing_can_host_cases() -{ - QString result = - configini->value("casing_can_host_cases", "Turnabout Check Your Settings") - .value(); - return result; -} - -bool AOApplication::get_colored_iclog_enabled() -{ - QString result = - configini->value("color_iclog_enabled", "false").value(); - return result.startsWith("true"); -} - -bool AOApplication::get_iclmir_enabled() -{ - QString result = - configini->value("mirror_iclog_enabled", "false").value(); - return result.startsWith("true"); -} -bool AOApplication::colorlog_restricted_enabled() -{ - QString result = - configini->value("mirror_iclog_restricted", "false").value(); - return result.startsWith("true"); -} - -bool AOApplication::is_shakeandflash_enabled() -{ - QString result = configini->value("shakeandflash", "true").value(); - return result.startsWith("true"); -} +#include "text_file_functions.h" + +QString AOApplication::read_theme() +{ + QString result = configini->value("theme", "default").value(); + return result; +} + +int AOApplication::read_blip_rate() +{ + int result = configini->value("blip_rate", 1).toInt(); + + if (result < 1) + return 1; + + return result; +} + +QString AOApplication::get_ooc_name() +{ + QString result = configini->value("ooc_name").value(); + return result; +} + +int AOApplication::get_default_music() +{ + int result = configini->value("default_music", 50).toInt(); + return result; +} + +int AOApplication::get_default_sfx() +{ + int result = configini->value("default_sfx", 50).toInt(); + return result; +} + +int AOApplication::get_default_blip() +{ + int result = configini->value("default_blip", 50).toInt(); + return result; +} + +int AOApplication::get_max_log_size() +{ + int result = configini->value("log_maximum", 200).toInt(); + return result; +} + +bool AOApplication::get_log_goes_downwards() +{ + QString result = configini->value("log_goes_downwards", "false").value(); + return result.startsWith("true"); +} + +bool AOApplication::get_showname_enabled_by_default() +{ + QString result = configini->value("show_custom_shownames", "true").value(); + return result.startsWith("true"); +} + +QString AOApplication::get_default_username() +{ + QString result = configini->value("default_username", "").value(); + if (result.isEmpty()) + return get_ooc_name(); + else + return result; +} + +QString AOApplication::get_audio_output_device() +{ + QString result = configini->value("default_audio_device", "default").value(); + return result; +} + +QStringList AOApplication::get_call_words() +{ + QStringList return_value; + + QFile callwords_ini; + + callwords_ini.setFileName(get_base_path() + "callwords.ini"); + + if (!callwords_ini.open(QIODevice::ReadOnly)) + return return_value; + + QTextStream in(&callwords_ini); + + while (!in.atEnd()) + { + QString line = in.readLine(); + return_value.append(line); + } + + return return_value; +} + +void AOApplication::write_to_serverlist_txt(QString p_line) +{ + QFile serverlist_txt; + QString serverlist_txt_path = get_base_path() + "serverlist.txt"; + + serverlist_txt.setFileName(serverlist_txt_path); + + if (!serverlist_txt.open(QIODevice::WriteOnly | QIODevice::Append)) + { + return; + } + + QTextStream out(&serverlist_txt); + + out << "\r\n" << p_line; + + serverlist_txt.close(); +} + +QVector AOApplication::read_serverlist_txt() +{ + QVector f_server_list; + + QFile serverlist_txt; + QString serverlist_txt_path = get_base_path() + "serverlist.txt"; + + serverlist_txt.setFileName(serverlist_txt_path); + + if (!serverlist_txt.open(QIODevice::ReadOnly)) + { + return f_server_list; + } + + QTextStream in(&serverlist_txt); + + while(!in.atEnd()) + { + QString line = in.readLine(); + server_type f_server; + QStringList line_contents = line.split(":"); + + if (line_contents.size() < 3) + continue; + + f_server.ip = line_contents.at(0); + f_server.port = line_contents.at(1).toInt(); + f_server.name = line_contents.at(2); + f_server.desc = ""; + + f_server_list.append(f_server); + } + + return f_server_list; +} + +QString AOApplication::read_design_ini(QString p_identifier, QString p_design_path) +{ + QSettings settings(p_design_path, QSettings::IniFormat); + QVariant value = settings.value(p_identifier); + if (value.type() == QVariant::StringList) { + return value.toStringList().join(","); + } else { + return value.toString(); + } +} + +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); + + QPoint return_value; + + return_value.setX(0); + return_value.setY(0); + + if (f_result == "") + { + f_result = read_design_ini(p_identifier, default_path); + + if (f_result == "") + return return_value; + } + + QStringList sub_line_elements = f_result.split(","); + + if (sub_line_elements.size() < 2) + return return_value; + + return_value.setX(sub_line_elements.at(0).toInt()); + return_value.setY(sub_line_elements.at(1).toInt()); + + return return_value; +} + +pos_size_type AOApplication::get_element_dimensions(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); + + pos_size_type return_value; + + return_value.x = 0; + return_value.y = 0; + return_value.width = -1; + return_value.height = -1; + + if (f_result == "") + { + f_result = read_design_ini(p_identifier, default_path); + + if (f_result == "") + return return_value; + } + + QStringList sub_line_elements = f_result.split(","); + + if (sub_line_elements.size() < 4) + return return_value; + + return_value.x = sub_line_elements.at(0).toInt(); + return_value.y = sub_line_elements.at(1).toInt(); + return_value.width = sub_line_elements.at(2).toInt(); + return_value.height = sub_line_elements.at(3).toInt(); + + return return_value; +} +QString AOApplication::get_font_name(QString p_identifier, QString p_file) +{ + 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 "Sans"; + } + return f_result; +} +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(); +} + +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); + + QColor return_color(0, 0, 0); + + if (f_result == "") + { + f_result = read_design_ini(p_identifier, default_path); + + if (f_result == "") + return return_color; + } + + QStringList color_list = f_result.split(","); + + if (color_list.size() < 3) + return return_color; + + return_color.setRed(color_list.at(0).toInt()); + return_color.setGreen(color_list.at(1).toInt()); + return_color.setBlue(color_list.at(2).toInt()); + + return return_color; +} + +QColor AOApplication::get_chat_color(QString p_identifier, QString p_chat) +{ + QColor return_color(255, 255, 255); + + if (p_identifier == "_inline_grey") + { + return_color = QColor(187, 187, 187); + } + else + { + switch (p_identifier.toInt()) { + case 1: + return_color = QColor(0, 255, 0); + break; + case 2: + return_color = QColor(255, 0, 0); + break; + case 3: + return_color = QColor(255, 165, 0); + break; + case 4: + return_color = QColor(45, 150, 255); + break; + case 5: + return_color = QColor(255, 255, 0); + break; + case 7: + return_color = QColor(255, 192, 203); + break; + case 8: + return_color = QColor(0, 255, 255); + break; + case 0: + case 6: // 6 is rainbow. + default: + return_color = QColor(255, 255, 255); + break; + } + } + + p_identifier = p_identifier.prepend("c"); + QString design_ini_path = get_base_path() + "misc/" + p_chat + "/config.ini"; + QString default_path = get_base_path() + "misc/default/config.ini"; + 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 return_color; + } + + QStringList color_list = f_result.split(","); + + if (color_list.size() < 3) + return return_color; + + return_color.setRed(color_list.at(0).toInt()); + return_color.setGreen(color_list.at(1).toInt()); + return_color.setBlue(color_list.at(2).toInt()); + + return return_color; +} + +QString AOApplication::get_sfx(QString p_identifier) +{ + QString design_ini_path = get_theme_path("courtroom_sounds.ini"); + QString default_path = get_default_theme_path("courtroom_sounds.ini"); + QString f_result = read_design_ini(p_identifier, design_ini_path); + + QString return_sfx = ""; + + if (f_result == "") + { + f_result = read_design_ini(p_identifier, default_path); + + if (f_result == "") + return return_sfx; + } + + return_sfx = f_result; + + return return_sfx; +} + +QString AOApplication::get_sfx_suffix(QString sound_to_check) +{ + QString mp3_check = get_sounds_path(sound_to_check + ".mp3"); + QString opus_check = get_sounds_path(sound_to_check + ".opus"); + if (file_exists(opus_check)) + { + return sound_to_check + ".opus"; + } + else if (file_exists(mp3_check)) + { + return sound_to_check + ".mp3"; + } + return sound_to_check + ".wav"; +} + +QString AOApplication::get_image_suffix(QString path_to_check) +{ + QString apng_check = path_to_check + ".apng"; + if (file_exists(apng_check)) + { + return apng_check; + } + return path_to_check + ".gif"; +} + + +//returns whatever is to the right of "search_line =" within target_tag and terminator_tag, trimmed +//returns the empty string if the search line couldnt be found +QString AOApplication::read_char_ini(QString p_char, QString p_search_line, QString target_tag) +{ + QSettings settings(get_character_path(p_char, "char.ini"), QSettings::IniFormat); + settings.beginGroup(target_tag); + QString value = settings.value(p_search_line).toString(); + settings.endGroup(); + return value; +} + +QString AOApplication::get_char_name(QString p_char) +{ + QString f_result = read_char_ini(p_char, "name", "Options"); + + if (f_result == "") + return p_char; + else return f_result; +} + +QString AOApplication::get_showname(QString p_char) +{ + QString f_result = read_char_ini(p_char, "showname", "Options"); + QString f_needed = read_char_ini(p_char, "needs_showname", "Options"); + + if (f_needed.startsWith("false")) + return ""; + if (f_result == "") + return p_char; + else return f_result; +} + +QString AOApplication::get_char_side(QString p_char) +{ + QString f_result = read_char_ini(p_char, "side", "Options"); + + if (f_result == "") + return "wit"; + else return f_result; +} + +QString AOApplication::get_gender(QString p_char) +{ + QString f_result = read_char_ini(p_char, "gender", "Options"); + + if (f_result == "") + return "male"; + else return f_result; +} + +QString AOApplication::get_chat(QString p_char) +{ + 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; +} + +QString AOApplication::get_char_shouts(QString p_char) +{ + QString f_result = read_char_ini(p_char, "shouts", "Options"); + if (f_result == "") + return "default"; + else 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"); + + if (f_result == "") + return -1; + else return f_result.toInt(); +} + +int AOApplication::get_ao2_preanim_duration(QString p_char, QString p_emote) +{ + QString f_result = read_char_ini(p_char, "%" + p_emote, "Time"); + + if (f_result == "") + return -1; + else return f_result.toInt(); +} + +int AOApplication::get_emote_number(QString p_char) +{ + QString f_result = read_char_ini(p_char, "number", "Emotions"); + + if (f_result == "") + return 0; + else return f_result.toInt(); +} + +QString AOApplication::get_emote_comment(QString p_char, int p_emote) +{ + QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); + + QStringList result_contents = f_result.split("#"); + + if (result_contents.size() < 4) + { + qDebug() << "W: misformatted char.ini: " << p_char << ", " << p_emote; + return "normal"; + } + else return result_contents.at(0); +} + +QString AOApplication::get_pre_emote(QString p_char, int p_emote) +{ + QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); + + QStringList result_contents = f_result.split("#"); + + if (result_contents.size() < 4) + { + qDebug() << "W: misformatted char.ini: " << p_char << ", " << p_emote; + return ""; + } + else return result_contents.at(1); +} + +QString AOApplication::get_emote(QString p_char, int p_emote) +{ + QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); + + QStringList result_contents = f_result.split("#"); + + if (result_contents.size() < 4) + { + qDebug() << "W: misformatted char.ini: " << p_char << ", " << p_emote; + return "normal"; + } + else return result_contents.at(2); +} + +int AOApplication::get_emote_mod(QString p_char, int p_emote) +{ + QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); + + QStringList result_contents = f_result.split("#"); + + if (result_contents.size() < 4) + { + qDebug() << "W: misformatted char.ini: " << p_char << ", " << QString::number(p_emote); + return 0; + } + else return result_contents.at(3).toInt(); +} + +int AOApplication::get_desk_mod(QString p_char, int p_emote) +{ + QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); + + QStringList result_contents = f_result.split("#"); + + if (result_contents.size() < 5) + return -1; + + QString string_result = result_contents.at(4); + if (string_result == "") + return -1; + + else return string_result.toInt(); +} + +QString AOApplication::get_sfx_name(QString p_char, int p_emote) +{ + QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "SoundN"); + + if (f_result == "") + return "1"; + else return f_result; +} + +int AOApplication::get_sfx_delay(QString p_char, int p_emote) +{ + QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "SoundT"); + + if (f_result == "") + return 1; + else return f_result.toInt(); +} + +int AOApplication::get_text_delay(QString p_char, QString p_emote) +{ + QString f_result = read_char_ini(p_char, p_emote, "TextDelay"); + + if (f_result == "") + return -1; + else return f_result.toInt(); +} + +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 f_result; +} + +bool AOApplication::get_blank_blip() +{ + QString result = configini->value("blank_blip", "false").value(); + return result.startsWith("true"); +} + +bool AOApplication::is_discord_enabled() +{ + QString result = configini->value("discord", "true").value(); + return result.startsWith("true"); +} + +bool AOApplication::get_casing_enabled() +{ + QString result = configini->value("casing_enabled", "false").value(); + return result.startsWith("true"); +} + +bool AOApplication::get_casing_defence_enabled() +{ + QString result = configini->value("casing_defence_enabled", "false").value(); + return result.startsWith("true"); +} + +bool AOApplication::get_casing_prosecution_enabled() +{ + QString result = configini->value("casing_prosecution_enabled", "false").value(); + return result.startsWith("true"); +} + +bool AOApplication::get_casing_judge_enabled() +{ + QString result = configini->value("casing_judge_enabled", "false").value(); + return result.startsWith("true"); +} + +bool AOApplication::get_casing_juror_enabled() +{ + QString result = configini->value("casing_juror_enabled", "false").value(); + return result.startsWith("true"); +} + +bool AOApplication::get_casing_steno_enabled() +{ + QString result = configini->value("casing_steno_enabled", "false").value(); + return result.startsWith("true"); +} + +bool AOApplication::get_casing_cm_enabled() +{ + QString result = configini->value("casing_cm_enabled", "false").value(); + return result.startsWith("true"); +} + +QString AOApplication::get_casing_can_host_cases() +{ + QString result = configini->value("casing_can_host_cases", "Turnabout Check Your Settings").value(); + return result; +} From 8928aa2718378bc42d20d5bbe6c17be68d65d6f3 Mon Sep 17 00:00:00 2001 From: oldmud0 Date: Fri, 22 May 2020 17:13:17 -0500 Subject: [PATCH 178/268] Perform clang-format If you don't want to see this commit on blames, use the hidden whitespace option on GitHub, or use `-w` in git-blame. --- .clang-format | 2 + include/aoapplication.h | 103 +- include/aoblipplayer.h | 12 +- include/aobutton.h | 5 +- include/aocaseannouncerdialog.h | 13 +- include/aocharbutton.h | 8 +- include/aocharmovie.h | 14 +- include/aoemotebutton.h | 13 +- include/aoevidencebutton.h | 10 +- include/aoevidencedisplay.h | 7 +- include/aoimage.h | 7 +- include/aolineedit.h | 5 +- include/aomovie.h | 3 +- include/aomusicplayer.h | 11 +- include/aooptionsdialog.h | 148 +-- include/aopacket.h | 9 +- include/aoscene.h | 6 +- include/aosfxplayer.h | 11 +- include/aotextarea.h | 14 +- include/aotextedit.h | 4 +- include/bass.h | 1706 ++++++++++++------------ include/chatlogpiece.h | 11 +- include/courtroom.h | 245 ++-- include/datatypes.h | 40 +- include/debug_functions.h | 2 +- include/discord-rpc.h | 64 +- include/discord_register.h | 26 +- include/discord_rich_presence.h | 12 +- include/discord_rpc.h | 66 +- include/encryption_functions.h | 8 +- include/file_functions.h | 2 +- include/hex_functions.h | 13 +- include/lobby.h | 15 +- include/misc_functions.h | 2 +- include/networkmanager.h | 11 +- include/text_file_functions.h | 8 +- src/aoapplication.cpp | 77 +- src/aoblipplayer.cpp | 33 +- src/aobutton.cpp | 9 +- src/aocaseannouncerdialog.cpp | 39 +- src/aocharbutton.cpp | 31 +- src/aocharmovie.cpp | 60 +- src/aoemotebutton.cpp | 18 +- src/aoevidencebutton.cpp | 19 +- src/aoevidencedisplay.cpp | 37 +- src/aoimage.cpp | 11 +- src/aolineedit.cpp | 5 +- src/aomovie.cpp | 29 +- src/aomusicplayer.cpp | 29 +- src/aooptionsdialog.cpp | 795 ++++++------ src/aopacket.cpp | 29 +- src/aoscene.cpp | 28 +- src/aosfxplayer.cpp | 47 +- src/aotextarea.cpp | 49 +- src/aotextedit.cpp | 8 +- src/charselect.cpp | 233 ++-- src/chatlogpiece.cpp | 37 +- src/courtroom.cpp | 2145 +++++++++++++++---------------- src/debug_functions.cpp | 6 +- src/discord_rich_presence.cpp | 37 +- src/emotes.cpp | 43 +- src/encryption_functions.cpp | 19 +- src/evidence.cpp | 100 +- src/file_functions.cpp | 3 +- src/hardware_functions.cpp | 19 +- src/hex_functions.cpp | 23 +- src/lobby.cpp | 112 +- src/main.cpp | 26 +- src/misc_functions.cpp | 2 +- src/networkmanager.cpp | 134 +- src/packet_distribution.cpp | 425 +++--- src/path_functions.cpp | 40 +- src/text_file_functions.cpp | 292 +++-- 73 files changed, 3765 insertions(+), 3920 deletions(-) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..a050582 --- /dev/null +++ b/.clang-format @@ -0,0 +1,2 @@ +BasedOnStyle: LLVM +BreakBeforeBraces: Stroustrup diff --git a/include/aoapplication.h b/include/aoapplication.h index 67f9a0d..ef1a168 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -6,30 +6,29 @@ #include "discord_rich_presence.h" #include -#include #include #include +#include #include -#include #include +#include #include #include #include -#include -#include #include #include +#include +#include class NetworkManager; class Lobby; class Courtroom; -class AOApplication : public QApplication -{ +class AOApplication : public QApplication { Q_OBJECT public: @@ -78,7 +77,7 @@ public: ///////////////loading info/////////////////// - //player number, it's hardly used but might be needed for some old servers + // player number, it's hardly used but might be needed for some old servers int s_pv = 0; QString server_software = ""; @@ -103,19 +102,19 @@ public: /////////////////////////////////////////// void set_favorite_list(); - QVector& get_favorite_list() {return favorite_list;} + QVector &get_favorite_list() { return favorite_list; } void add_favorite_server(int p_server); void set_server_list(); - QVector& get_server_list() {return server_list;} + QVector &get_server_list() { return server_list; } - //reads the theme from config.ini and sets it accordingly + // reads the theme from config.ini and sets it accordingly void reload_theme(); - //Returns the character the player has currently selected + // Returns the character the player has currently selected QString get_current_char(); - //implementation in path_functions.cpp + // implementation in path_functions.cpp QString get_base_path(); QString get_data_path(); QString get_theme_path(QString p_file); @@ -135,25 +134,26 @@ public: // Instead of reinventing the wheel, we'll use a QSettings class. QSettings *configini; - //Reads the theme from config.ini and loads it into the current_theme variable + // Reads the theme from config.ini and loads it into the current_theme + // variable QString read_theme(); - //Returns the value of ooc_name in config.ini + // Returns the value of ooc_name in config.ini QString get_ooc_name(); - //Returns the blip rate from config.ini + // Returns the blip rate from config.ini int read_blip_rate(); - //Returns true if blank blips is enabled in config.ini and false otherwise + // Returns true if blank blips is enabled in config.ini and false otherwise bool get_blank_blip(); - //Returns the value of default_music in config.ini + // Returns the value of default_music in config.ini int get_default_music(); - //Returns the value of default_sfx in config.ini + // Returns the value of default_sfx in config.ini int get_default_sfx(); - //Returns the value of default_blip in config.ini + // Returns the value of default_blip in config.ini int get_default_blip(); // Returns the value of whether Discord should be enabled on startup @@ -177,101 +177,102 @@ public: // Returns whether the user would like to have custom shownames on by default. bool get_showname_enabled_by_default(); - //Returns the list of words in callwords.ini + // Returns the list of words in callwords.ini QStringList get_call_words(); - //Appends the argument string to serverlist.txt + // Appends the argument string to serverlist.txt void write_to_serverlist_txt(QString p_line); - //Returns the contents of serverlist.txt + // Returns the contents of serverlist.txt QVector read_serverlist_txt(); - //Returns the value of p_identifier in the design.ini file in p_design_path + // Returns the value of p_identifier in the design.ini file in p_design_path QString read_design_ini(QString p_identifier, QString p_design_path); - //Returns the coordinates of widget with p_identifier from p_file + // Returns the coordinates of widget with p_identifier from p_file QPoint get_button_spacing(QString p_identifier, QString p_file); - //Returns the dimensions of widget with specified identifier from p_file + // Returns the dimensions of widget with specified identifier from p_file pos_size_type get_element_dimensions(QString p_identifier, QString p_file); - //Returns the name of the font with p_identifier from p_file - QString get_font_name(QString p_identifier, QString p_file); + // Returns the name of the font with p_identifier from p_file + QString get_font_name(QString p_identifier, QString p_file); - - //Returns the value of font_size with p_identifier from p_file + // Returns the value of font_size with p_identifier from p_file int get_font_size(QString p_identifier, QString p_file); - //Returns the color with p_identifier from p_file + // Returns the color with p_identifier from p_file QColor get_color(QString p_identifier, QString p_file); // Returns the colour 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 + // Returns the sfx with p_identifier from sounds.ini in the current theme path QString get_sfx(QString p_identifier); - //Figure out if we can opus this or if we should fall back to wav + // 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, fall back to a gif. QString get_image_suffix(QString path_to_check); - //Returns the value of p_search_line within target_tag and terminator_tag - QString read_char_ini(QString p_char, QString p_search_line, QString target_tag); + // Returns the value of p_search_line within target_tag and terminator_tag + QString read_char_ini(QString p_char, QString p_search_line, + QString target_tag); - //Returns the side of the p_char character from that characters ini file + // Returns the side of the p_char character from that characters ini file QString get_char_side(QString p_char); - //Returns the showname from the ini of p_char + // Returns the showname from the ini of p_char QString get_showname(QString p_char); - //Returns the value of chat from the specific p_char's ini file + // Returns the value of chat from the specific p_char's ini file QString get_chat(QString p_char); - //Returns the value of shouts from the specified p_char's ini file + // 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 + // Returns the preanim duration of p_char's p_emote int get_preanim_duration(QString p_char, QString p_emote); - //Same as above, but only returns if it has a % in front(refer to Preanims section in the manual) + // Same as above, but only returns if it has a % in front(refer to Preanims + // section in the manual) int get_ao2_preanim_duration(QString p_char, QString p_emote); - //Not in use + // Not in use int get_text_delay(QString p_char, QString p_emote); // Returns the custom realisation used by the character. QString get_custom_realization(QString p_char); - //Returns the name of p_char + // Returns the name of p_char QString get_char_name(QString p_char); - //Returns the total amount of emotes of p_char + // Returns the total amount of emotes of p_char int get_emote_number(QString p_char); - //Returns the emote comment of p_char's p_emote + // Returns the emote comment of p_char's p_emote QString get_emote_comment(QString p_char, int p_emote); - //Returns the base name of p_char's p_emote + // Returns the base name of p_char's p_emote QString get_emote(QString p_char, int p_emote); - //Returns the preanimation name of p_char's p_emote + // Returns the preanimation name of p_char's p_emote QString get_pre_emote(QString p_char, int p_emote); - //Returns the sfx of p_char's p_emote + // Returns the sfx of p_char's p_emote QString get_sfx_name(QString p_char, int p_emote); - //Not in use + // Not in use int get_sfx_delay(QString p_char, int p_emote); - //Returns the modifier for p_char's p_emote + // Returns the modifier for p_char's p_emote int get_emote_mod(QString p_char, int p_emote); - //Returns the desk modifier for p_char's p_emote + // Returns the desk modifier for p_char's p_emote int get_desk_mod(QString p_char, int p_emote); - //Returns p_char's gender + // Returns p_char's gender QString get_gender(QString p_char); // ====== diff --git a/include/aoblipplayer.h b/include/aoblipplayer.h index 102a040..02bd3c6 100644 --- a/include/aoblipplayer.h +++ b/include/aoblipplayer.h @@ -9,13 +9,11 @@ #include "aoapplication.h" +#include #include #include -#include - -class AOBlipPlayer -{ +class AOBlipPlayer { public: AOBlipPlayer(QWidget *parent, AOApplication *p_ao_app); @@ -30,11 +28,11 @@ private: AOApplication *ao_app; int m_volume; - #if defined(BASSAUDIO) +#if defined(BASSAUDIO) HSTREAM m_stream_list[5]; - #elif defined(QTAUDIO) +#elif defined(QTAUDIO) QSoundEffect m_blips; - #endif +#endif }; #endif // AOBLIPPLAYER_H diff --git a/include/aobutton.h b/include/aobutton.h index 4b7209a..f575885 100644 --- a/include/aobutton.h +++ b/include/aobutton.h @@ -3,11 +3,10 @@ #include "aoapplication.h" -#include #include +#include -class AOButton : public QPushButton -{ +class AOButton : public QPushButton { Q_OBJECT public: diff --git a/include/aocaseannouncerdialog.h b/include/aocaseannouncerdialog.h index a238c3f..0ac8f07 100644 --- a/include/aocaseannouncerdialog.h +++ b/include/aocaseannouncerdialog.h @@ -4,20 +4,21 @@ #include "aoapplication.h" #include "courtroom.h" -#include #include -#include -#include #include +#include +#include #include #include +#include -class AOCaseAnnouncerDialog : public QDialog -{ +class AOCaseAnnouncerDialog : public QDialog { Q_OBJECT public: - explicit AOCaseAnnouncerDialog(QWidget *parent = nullptr, AOApplication *p_ao_app = nullptr, Courtroom *p_court = nullptr); + explicit AOCaseAnnouncerDialog(QWidget *parent = nullptr, + AOApplication *p_ao_app = nullptr, + Courtroom *p_court = nullptr); private: AOApplication *ao_app; diff --git a/include/aocharbutton.h b/include/aocharbutton.h index f372cdf..dd27e62 100644 --- a/include/aocharbutton.h +++ b/include/aocharbutton.h @@ -4,17 +4,17 @@ #include "aoapplication.h" #include "aoimage.h" +#include #include #include #include -#include -class AOCharButton : public QPushButton -{ +class AOCharButton : public QPushButton { Q_OBJECT public: - AOCharButton(QWidget *parent, AOApplication *p_ao_app, int x_pos, int y_pos, bool is_taken); + AOCharButton(QWidget *parent, AOApplication *p_ao_app, int x_pos, int y_pos, + bool is_taken); AOApplication *ao_app; diff --git a/include/aocharmovie.h b/include/aocharmovie.h index 7ef7da3..b4a8be2 100644 --- a/include/aocharmovie.h +++ b/include/aocharmovie.h @@ -1,16 +1,15 @@ #ifndef AOCHARMOVIE_H #define AOCHARMOVIE_H -#include -#include -#include #include #include +#include +#include +#include class AOApplication; -class AOCharMovie : public QLabel -{ +class AOCharMovie : public QLabel { Q_OBJECT public: @@ -21,7 +20,7 @@ public: void play_talking(QString p_char, QString p_emote); void play_idle(QString p_char, QString p_emote); - void set_flipped(bool p_flipped) {m_flipped = p_flipped;} + void set_flipped(bool p_flipped) { m_flipped = p_flipped; } void stop(); @@ -38,7 +37,8 @@ private: const int time_mod = 62; - // These are the X and Y values before they are fixed based on the sprite's width. + // These are the X and Y values before they are fixed based on the sprite's + // width. int x = 0; int y = 0; diff --git a/include/aoemotebutton.h b/include/aoemotebutton.h index c99a73b..acf0b48 100644 --- a/include/aoemotebutton.h +++ b/include/aoemotebutton.h @@ -3,22 +3,21 @@ #include "aoapplication.h" -#include #include +#include -class AOEmoteButton : public QPushButton -{ +class AOEmoteButton : public QPushButton { Q_OBJECT public: AOEmoteButton(QWidget *p_parent, AOApplication *p_ao_app, int p_x, int p_y); - //void set_on(QString p_char, int p_emote); - //void set_off(QString p_char, int p_emote); + // void set_on(QString p_char, int p_emote); + // void set_off(QString p_char, int p_emote); void set_image(QString p_char, int p_emote, QString suffix); - void set_id(int p_id) {m_id = p_id;} - int get_id() {return m_id;} + void set_id(int p_id) { m_id = p_id; } + int get_id() { return m_id; } private: QWidget *parent; diff --git a/include/aoevidencebutton.h b/include/aoevidencebutton.h index 80b747c..b56bfb1 100644 --- a/include/aoevidencebutton.h +++ b/include/aoevidencebutton.h @@ -4,21 +4,21 @@ #include "aoapplication.h" #include "aoimage.h" +#include #include #include -#include -class AOEvidenceButton : public QPushButton -{ +class AOEvidenceButton : public QPushButton { Q_OBJECT public: - AOEvidenceButton(QWidget *p_parent, AOApplication *p_ao_app, int p_x, int p_y); + AOEvidenceButton(QWidget *p_parent, AOApplication *p_ao_app, int p_x, + int p_y); void reset(); void set_image(QString p_image); void set_theme_image(QString p_image); - void set_id(int p_id) {m_id = p_id;} + void set_id(int p_id) { m_id = p_id; } void set_selected(bool p_selected); diff --git a/include/aoevidencedisplay.h b/include/aoevidencedisplay.h index 13ca00d..1d6280d 100644 --- a/include/aoevidencedisplay.h +++ b/include/aoevidencedisplay.h @@ -4,19 +4,18 @@ #include "aoapplication.h" #include "aosfxplayer.h" +#include #include #include -#include -class AOEvidenceDisplay : public QLabel -{ +class AOEvidenceDisplay : public QLabel { Q_OBJECT public: AOEvidenceDisplay(QWidget *p_parent, AOApplication *p_ao_app); void show_evidence(QString p_evidence_image, bool is_left_side, int p_volume); - QLabel* get_evidence_icon(); + QLabel *get_evidence_icon(); void reset(); private: diff --git a/include/aoimage.h b/include/aoimage.h index 4713be0..c4fdf2e 100644 --- a/include/aoimage.h +++ b/include/aoimage.h @@ -1,15 +1,14 @@ -//This class represents a static theme-dependent image +// This class represents a static theme-dependent image #ifndef AOIMAGE_H #define AOIMAGE_H #include "aoapplication.h" -#include #include +#include -class AOImage : public QLabel -{ +class AOImage : public QLabel { public: AOImage(QWidget *parent, AOApplication *p_ao_app); ~AOImage(); diff --git a/include/aolineedit.h b/include/aolineedit.h index ce17680..70f1f97 100644 --- a/include/aolineedit.h +++ b/include/aolineedit.h @@ -4,8 +4,7 @@ #include #include -class AOLineEdit : public QLineEdit -{ +class AOLineEdit : public QLineEdit { Q_OBJECT public: @@ -19,8 +18,6 @@ signals: private slots: void on_enter_pressed(); - - }; #endif // AOLINEEDIT_H diff --git a/include/aomovie.h b/include/aomovie.h index 1f278bf..d22f725 100644 --- a/include/aomovie.h +++ b/include/aomovie.h @@ -7,8 +7,7 @@ class Courtroom; class AOApplication; -class AOMovie : public QLabel -{ +class AOMovie : public QLabel { Q_OBJECT public: diff --git a/include/aomusicplayer.h b/include/aomusicplayer.h index b34267c..fd6b254 100644 --- a/include/aomusicplayer.h +++ b/include/aomusicplayer.h @@ -8,13 +8,12 @@ #endif #include "aoapplication.h" +#include #include #include -#include #if defined(BASSAUDIO) -class AOMusicPlayer -{ +class AOMusicPlayer { public: AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app); ~AOMusicPlayer(); @@ -30,8 +29,7 @@ private: HSTREAM m_stream; }; #elif defined(QTAUDIO) -class AOMusicPlayer -{ +class AOMusicPlayer { public: AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app); ~AOMusicPlayer(); @@ -47,8 +45,7 @@ private: int m_volume = 0; }; #else -class AOMusicPlayer -{ +class AOMusicPlayer { public: AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app); ~AOMusicPlayer(); diff --git a/include/aooptionsdialog.h b/include/aooptionsdialog.h index a65e3f5..ec0889b 100644 --- a/include/aooptionsdialog.h +++ b/include/aooptionsdialog.h @@ -23,93 +23,93 @@ #include #include -class AOOptionsDialog: public QDialog -{ - Q_OBJECT +class AOOptionsDialog : public QDialog { + Q_OBJECT public: - explicit AOOptionsDialog(QWidget *parent = nullptr, AOApplication *p_ao_app = nullptr); + explicit AOOptionsDialog(QWidget *parent = nullptr, + AOApplication *p_ao_app = nullptr); private: - AOApplication *ao_app; + AOApplication *ao_app; - QVBoxLayout *ui_vertical_layout; - QTabWidget *ui_settings_tabs; + QVBoxLayout *ui_vertical_layout; + QTabWidget *ui_settings_tabs; - QWidget *ui_gameplay_tab; - QWidget *ui_form_layout_widget; - QFormLayout *ui_gameplay_form; - QLabel *ui_theme_label; - QComboBox *ui_theme_combobox; - QFrame *ui_theme_log_divider; - QLabel *ui_downwards_lbl; - QCheckBox *ui_downwards_cb; - QLabel *ui_length_lbl; - QSpinBox *ui_length_spinbox; - QFrame *ui_log_names_divider; - QLineEdit *ui_username_textbox; - QLabel *ui_username_lbl; - QLabel *ui_showname_lbl; - QCheckBox *ui_showname_cb; - QFrame *ui_net_divider; - QLabel *ui_ms_lbl; - QLineEdit *ui_ms_textbox; - QLabel *ui_discord_lbl; - QCheckBox *ui_discord_cb; + QWidget *ui_gameplay_tab; + QWidget *ui_form_layout_widget; + QFormLayout *ui_gameplay_form; + QLabel *ui_theme_label; + QComboBox *ui_theme_combobox; + QFrame *ui_theme_log_divider; + QLabel *ui_downwards_lbl; + QCheckBox *ui_downwards_cb; + QLabel *ui_length_lbl; + QSpinBox *ui_length_spinbox; + QFrame *ui_log_names_divider; + QLineEdit *ui_username_textbox; + QLabel *ui_username_lbl; + QLabel *ui_showname_lbl; + QCheckBox *ui_showname_cb; + QFrame *ui_net_divider; + QLabel *ui_ms_lbl; + QLineEdit *ui_ms_textbox; + QLabel *ui_discord_lbl; + QCheckBox *ui_discord_cb; - QWidget *ui_callwords_tab; - QWidget *ui_callwords_widget; - QVBoxLayout *ui_callwords_layout; - QPlainTextEdit *ui_callwords_textbox; - QLabel *ui_callwords_explain_lbl; - QCheckBox *ui_callwords_char_textbox; + QWidget *ui_callwords_tab; + QWidget *ui_callwords_widget; + QVBoxLayout *ui_callwords_layout; + QPlainTextEdit *ui_callwords_textbox; + QLabel *ui_callwords_explain_lbl; + QCheckBox *ui_callwords_char_textbox; - QWidget *ui_audio_tab; - QWidget *ui_audio_widget; - QFormLayout *ui_audio_layout; - QLabel *ui_audio_device_lbl; - QComboBox *ui_audio_device_combobox; - QFrame *ui_audio_volume_divider; - QSpinBox *ui_music_volume_spinbox; - QLabel *ui_music_volume_lbl; - QSpinBox *ui_sfx_volume_spinbox; - QSpinBox *ui_blips_volume_spinbox; - QLabel *ui_sfx_volume_lbl; - QLabel *ui_blips_volume_lbl; - QFrame *ui_volume_blip_divider; - QSpinBox *ui_bliprate_spinbox; - QLabel *ui_bliprate_lbl; - QCheckBox *ui_blank_blips_cb; - QLabel *ui_blank_blips_lbl; - QDialogButtonBox *ui_settings_buttons; + QWidget *ui_audio_tab; + QWidget *ui_audio_widget; + QFormLayout *ui_audio_layout; + QLabel *ui_audio_device_lbl; + QComboBox *ui_audio_device_combobox; + QFrame *ui_audio_volume_divider; + QSpinBox *ui_music_volume_spinbox; + QLabel *ui_music_volume_lbl; + QSpinBox *ui_sfx_volume_spinbox; + QSpinBox *ui_blips_volume_spinbox; + QLabel *ui_sfx_volume_lbl; + QLabel *ui_blips_volume_lbl; + QFrame *ui_volume_blip_divider; + QSpinBox *ui_bliprate_spinbox; + QLabel *ui_bliprate_lbl; + QCheckBox *ui_blank_blips_cb; + QLabel *ui_blank_blips_lbl; + QDialogButtonBox *ui_settings_buttons; - QWidget *ui_casing_tab; - QWidget *ui_casing_widget; - QFormLayout *ui_casing_layout; - QLabel *ui_casing_supported_lbl; - QLabel *ui_casing_enabled_lbl; - QCheckBox *ui_casing_enabled_cb; - QLabel *ui_casing_def_lbl; - QCheckBox *ui_casing_def_cb; - QLabel *ui_casing_pro_lbl; - QCheckBox *ui_casing_pro_cb; - QLabel *ui_casing_jud_lbl; - QCheckBox *ui_casing_jud_cb; - QLabel *ui_casing_jur_lbl; - QCheckBox *ui_casing_jur_cb; - QLabel *ui_casing_steno_lbl; - QCheckBox *ui_casing_steno_cb; - QLabel *ui_casing_cm_lbl; - QCheckBox *ui_casing_cm_cb; - QLabel *ui_casing_cm_cases_lbl; - QLineEdit *ui_casing_cm_cases_textbox; + QWidget *ui_casing_tab; + QWidget *ui_casing_widget; + QFormLayout *ui_casing_layout; + QLabel *ui_casing_supported_lbl; + QLabel *ui_casing_enabled_lbl; + QCheckBox *ui_casing_enabled_cb; + QLabel *ui_casing_def_lbl; + QCheckBox *ui_casing_def_cb; + QLabel *ui_casing_pro_lbl; + QCheckBox *ui_casing_pro_cb; + QLabel *ui_casing_jud_lbl; + QCheckBox *ui_casing_jud_cb; + QLabel *ui_casing_jur_lbl; + QCheckBox *ui_casing_jur_cb; + QLabel *ui_casing_steno_lbl; + QCheckBox *ui_casing_steno_cb; + QLabel *ui_casing_cm_lbl; + QCheckBox *ui_casing_cm_cb; + QLabel *ui_casing_cm_cases_lbl; + QLineEdit *ui_casing_cm_cases_textbox; - bool needs_default_audiodev(); + bool needs_default_audiodev(); signals: public slots: - void save_pressed(); - void discard_pressed(); + void save_pressed(); + void discard_pressed(); }; #endif // AOOPTIONSDIALOG_H diff --git a/include/aopacket.h b/include/aopacket.h index 21f6e0f..4097be8 100644 --- a/include/aopacket.h +++ b/include/aopacket.h @@ -1,19 +1,18 @@ #ifndef AOPACKET_H #define AOPACKET_H +#include #include #include -#include -class AOPacket -{ +class AOPacket { public: AOPacket(QString p_packet_string); AOPacket(QString header, QStringList &p_contents); ~AOPacket(); - QString get_header() {return m_header;} - QStringList &get_contents() {return m_contents;} + QString get_header() { return m_header; } + QStringList &get_contents() { return m_contents; } QString to_string(); void encrypt_header(unsigned int p_key); diff --git a/include/aoscene.h b/include/aoscene.h index b58c0fd..1c258f2 100644 --- a/include/aoscene.h +++ b/include/aoscene.h @@ -1,15 +1,14 @@ #ifndef AOSCENE_H #define AOSCENE_H -#include #include +#include #include class Courtroom; class AOApplication; -class AOScene : public QLabel -{ +class AOScene : public QLabel { Q_OBJECT public: explicit AOScene(QWidget *parent, AOApplication *p_ao_app); @@ -21,7 +20,6 @@ private: QWidget *m_parent; QMovie *m_movie; AOApplication *ao_app; - }; #endif // AOSCENE_H diff --git a/include/aosfxplayer.h b/include/aosfxplayer.h index 4b97685..b6dce85 100644 --- a/include/aosfxplayer.h +++ b/include/aosfxplayer.h @@ -9,12 +9,11 @@ #include "aoapplication.h" +#include #include #include -#include -class AOSfxPlayer -{ +class AOSfxPlayer { public: AOSfxPlayer(QWidget *parent, AOApplication *p_ao_app); @@ -25,11 +24,11 @@ public: private: QWidget *m_parent; AOApplication *ao_app; - #if defined(BASSAUDIO) +#if defined(BASSAUDIO) HSTREAM m_stream; - #elif defined(QTAUDIO) +#elif defined(QTAUDIO) QSoundEffect m_sfx; - #endif +#endif int m_volume = 0; }; diff --git a/include/aotextarea.h b/include/aotextarea.h index d44596b..13532d2 100644 --- a/include/aotextarea.h +++ b/include/aotextarea.h @@ -1,14 +1,13 @@ #ifndef AOTEXTAREA_H #define AOTEXTAREA_H -#include -#include -#include -#include #include +#include +#include +#include +#include -class AOTextArea : public QTextBrowser -{ +class AOTextArea : public QTextBrowser { public: AOTextArea(QWidget *p_parent = nullptr); @@ -18,7 +17,8 @@ public: private: const QRegExp omnis_dank_url_regex = QRegExp("\\b(https?://\\S+\\.\\S+)\\b"); - void auto_scroll(QTextCursor old_cursor, int scrollbar_value, bool is_scrolled_down); + void auto_scroll(QTextCursor old_cursor, int scrollbar_value, + bool is_scrolled_down); }; #endif // AOTEXTAREA_H diff --git a/include/aotextedit.h b/include/aotextedit.h index 85909c6..8d876f1 100644 --- a/include/aotextedit.h +++ b/include/aotextedit.h @@ -3,8 +3,7 @@ #include -class AOTextEdit : public QPlainTextEdit -{ +class AOTextEdit : public QPlainTextEdit { Q_OBJECT public: AOTextEdit(QWidget *parent); @@ -17,7 +16,6 @@ signals: private slots: void on_enter_pressed(); - }; #endif // AOTEXTEDIT_H diff --git a/include/bass.h b/include/bass.h index 1c50903..068b963 100644 --- a/include/bass.h +++ b/include/bass.h @@ -1,8 +1,8 @@ /* - BASS 2.4 C/C++ header file - Copyright (c) 1999-2018 Un4seen Developments Ltd. + BASS 2.4 C/C++ header file + Copyright (c) 1999-2018 Un4seen Developments Ltd. - See the BASS.CHM file for more detailed documentation + See the BASS.CHM file for more detailed documentation */ #ifndef BASS_H @@ -27,19 +27,19 @@ typedef int BOOL; #define FALSE 0 #endif #define LOBYTE(a) (BYTE)(a) -#define HIBYTE(a) (BYTE)((a)>>8) +#define HIBYTE(a) (BYTE)((a) >> 8) #define LOWORD(a) (WORD)(a) -#define HIWORD(a) (WORD)((a)>>16) -#define MAKEWORD(a,b) (WORD)(((a)&0xff)|((b)<<8)) -#define MAKELONG(a,b) (DWORD)(((a)&0xffff)|((b)<<16)) +#define HIWORD(a) (WORD)((a) >> 16) +#define MAKEWORD(a, b) (WORD)(((a)&0xff) | ((b) << 8)) +#define MAKELONG(a, b) (DWORD)(((a)&0xffff) | ((b) << 16)) #endif #ifdef __cplusplus extern "C" { #endif -#define BASSVERSION 0x204 // API version -#define BASSVERSIONTEXT "2.4" +#define BASSVERSION 0x204 // API version +#define BASSVERSIONTEXT "2.4" #ifndef BASSDEF #define BASSDEF(f) WINAPI f @@ -47,524 +47,548 @@ extern "C" { #define NOBASSOVERLOADS #endif -typedef DWORD HMUSIC; // MOD music handle -typedef DWORD HSAMPLE; // sample handle -typedef DWORD HCHANNEL; // playing sample's channel handle -typedef DWORD HSTREAM; // sample stream handle -typedef DWORD HRECORD; // recording handle -typedef DWORD HSYNC; // synchronizer handle -typedef DWORD HDSP; // DSP handle -typedef DWORD HFX; // DX8 effect handle -typedef DWORD HPLUGIN; // Plugin handle +typedef DWORD HMUSIC; // MOD music handle +typedef DWORD HSAMPLE; // sample handle +typedef DWORD HCHANNEL; // playing sample's channel handle +typedef DWORD HSTREAM; // sample stream handle +typedef DWORD HRECORD; // recording handle +typedef DWORD HSYNC; // synchronizer handle +typedef DWORD HDSP; // DSP handle +typedef DWORD HFX; // DX8 effect handle +typedef DWORD HPLUGIN; // Plugin handle // Error codes returned by BASS_ErrorGetCode -#define BASS_OK 0 // all is OK -#define BASS_ERROR_MEM 1 // memory error -#define BASS_ERROR_FILEOPEN 2 // can't open the file -#define BASS_ERROR_DRIVER 3 // can't find a free/valid driver -#define BASS_ERROR_BUFLOST 4 // the sample buffer was lost -#define BASS_ERROR_HANDLE 5 // invalid handle -#define BASS_ERROR_FORMAT 6 // unsupported sample format -#define BASS_ERROR_POSITION 7 // invalid position -#define BASS_ERROR_INIT 8 // BASS_Init has not been successfully called -#define BASS_ERROR_START 9 // BASS_Start has not been successfully called -#define BASS_ERROR_SSL 10 // SSL/HTTPS support isn't available -#define BASS_ERROR_ALREADY 14 // already initialized/paused/whatever -#define BASS_ERROR_NOCHAN 18 // can't get a free channel -#define BASS_ERROR_ILLTYPE 19 // an illegal type was specified -#define BASS_ERROR_ILLPARAM 20 // an illegal parameter was specified -#define BASS_ERROR_NO3D 21 // no 3D support -#define BASS_ERROR_NOEAX 22 // no EAX support -#define BASS_ERROR_DEVICE 23 // illegal device number -#define BASS_ERROR_NOPLAY 24 // not playing -#define BASS_ERROR_FREQ 25 // illegal sample rate -#define BASS_ERROR_NOTFILE 27 // the stream is not a file stream -#define BASS_ERROR_NOHW 29 // no hardware voices available -#define BASS_ERROR_EMPTY 31 // the MOD music has no sequence data -#define BASS_ERROR_NONET 32 // no internet connection could be opened -#define BASS_ERROR_CREATE 33 // couldn't create the file -#define BASS_ERROR_NOFX 34 // effects are not available -#define BASS_ERROR_NOTAVAIL 37 // requested data/action is not available -#define BASS_ERROR_DECODE 38 // the channel is/isn't a "decoding channel" -#define BASS_ERROR_DX 39 // a sufficient DirectX version is not installed -#define BASS_ERROR_TIMEOUT 40 // connection timedout -#define BASS_ERROR_FILEFORM 41 // unsupported file format -#define BASS_ERROR_SPEAKER 42 // unavailable speaker -#define BASS_ERROR_VERSION 43 // invalid BASS version (used by add-ons) -#define BASS_ERROR_CODEC 44 // codec is not available/supported -#define BASS_ERROR_ENDED 45 // the channel/file has ended -#define BASS_ERROR_BUSY 46 // the device is busy -#define BASS_ERROR_UNKNOWN -1 // some other mystery problem +#define BASS_OK 0 // all is OK +#define BASS_ERROR_MEM 1 // memory error +#define BASS_ERROR_FILEOPEN 2 // can't open the file +#define BASS_ERROR_DRIVER 3 // can't find a free/valid driver +#define BASS_ERROR_BUFLOST 4 // the sample buffer was lost +#define BASS_ERROR_HANDLE 5 // invalid handle +#define BASS_ERROR_FORMAT 6 // unsupported sample format +#define BASS_ERROR_POSITION 7 // invalid position +#define BASS_ERROR_INIT 8 // BASS_Init has not been successfully called +#define BASS_ERROR_START 9 // BASS_Start has not been successfully called +#define BASS_ERROR_SSL 10 // SSL/HTTPS support isn't available +#define BASS_ERROR_ALREADY 14 // already initialized/paused/whatever +#define BASS_ERROR_NOCHAN 18 // can't get a free channel +#define BASS_ERROR_ILLTYPE 19 // an illegal type was specified +#define BASS_ERROR_ILLPARAM 20 // an illegal parameter was specified +#define BASS_ERROR_NO3D 21 // no 3D support +#define BASS_ERROR_NOEAX 22 // no EAX support +#define BASS_ERROR_DEVICE 23 // illegal device number +#define BASS_ERROR_NOPLAY 24 // not playing +#define BASS_ERROR_FREQ 25 // illegal sample rate +#define BASS_ERROR_NOTFILE 27 // the stream is not a file stream +#define BASS_ERROR_NOHW 29 // no hardware voices available +#define BASS_ERROR_EMPTY 31 // the MOD music has no sequence data +#define BASS_ERROR_NONET 32 // no internet connection could be opened +#define BASS_ERROR_CREATE 33 // couldn't create the file +#define BASS_ERROR_NOFX 34 // effects are not available +#define BASS_ERROR_NOTAVAIL 37 // requested data/action is not available +#define BASS_ERROR_DECODE 38 // the channel is/isn't a "decoding channel" +#define BASS_ERROR_DX 39 // a sufficient DirectX version is not installed +#define BASS_ERROR_TIMEOUT 40 // connection timedout +#define BASS_ERROR_FILEFORM 41 // unsupported file format +#define BASS_ERROR_SPEAKER 42 // unavailable speaker +#define BASS_ERROR_VERSION 43 // invalid BASS version (used by add-ons) +#define BASS_ERROR_CODEC 44 // codec is not available/supported +#define BASS_ERROR_ENDED 45 // the channel/file has ended +#define BASS_ERROR_BUSY 46 // the device is busy +#define BASS_ERROR_UNKNOWN -1 // some other mystery problem // BASS_SetConfig options -#define BASS_CONFIG_BUFFER 0 -#define BASS_CONFIG_UPDATEPERIOD 1 -#define BASS_CONFIG_GVOL_SAMPLE 4 -#define BASS_CONFIG_GVOL_STREAM 5 -#define BASS_CONFIG_GVOL_MUSIC 6 -#define BASS_CONFIG_CURVE_VOL 7 -#define BASS_CONFIG_CURVE_PAN 8 -#define BASS_CONFIG_FLOATDSP 9 -#define BASS_CONFIG_3DALGORITHM 10 -#define BASS_CONFIG_NET_TIMEOUT 11 -#define BASS_CONFIG_NET_BUFFER 12 -#define BASS_CONFIG_PAUSE_NOPLAY 13 -#define BASS_CONFIG_NET_PREBUF 15 -#define BASS_CONFIG_NET_PASSIVE 18 -#define BASS_CONFIG_REC_BUFFER 19 -#define BASS_CONFIG_NET_PLAYLIST 21 -#define BASS_CONFIG_MUSIC_VIRTUAL 22 -#define BASS_CONFIG_VERIFY 23 -#define BASS_CONFIG_UPDATETHREADS 24 -#define BASS_CONFIG_DEV_BUFFER 27 -#define BASS_CONFIG_VISTA_TRUEPOS 30 -#define BASS_CONFIG_IOS_MIXAUDIO 34 -#define BASS_CONFIG_DEV_DEFAULT 36 -#define BASS_CONFIG_NET_READTIMEOUT 37 -#define BASS_CONFIG_VISTA_SPEAKERS 38 -#define BASS_CONFIG_IOS_SPEAKER 39 -#define BASS_CONFIG_MF_DISABLE 40 -#define BASS_CONFIG_HANDLES 41 -#define BASS_CONFIG_UNICODE 42 -#define BASS_CONFIG_SRC 43 -#define BASS_CONFIG_SRC_SAMPLE 44 -#define BASS_CONFIG_ASYNCFILE_BUFFER 45 -#define BASS_CONFIG_OGG_PRESCAN 47 -#define BASS_CONFIG_MF_VIDEO 48 -#define BASS_CONFIG_AIRPLAY 49 -#define BASS_CONFIG_DEV_NONSTOP 50 -#define BASS_CONFIG_IOS_NOCATEGORY 51 -#define BASS_CONFIG_VERIFY_NET 52 -#define BASS_CONFIG_DEV_PERIOD 53 -#define BASS_CONFIG_FLOAT 54 -#define BASS_CONFIG_NET_SEEK 56 -#define BASS_CONFIG_AM_DISABLE 58 -#define BASS_CONFIG_NET_PLAYLIST_DEPTH 59 -#define BASS_CONFIG_NET_PREBUF_WAIT 60 +#define BASS_CONFIG_BUFFER 0 +#define BASS_CONFIG_UPDATEPERIOD 1 +#define BASS_CONFIG_GVOL_SAMPLE 4 +#define BASS_CONFIG_GVOL_STREAM 5 +#define BASS_CONFIG_GVOL_MUSIC 6 +#define BASS_CONFIG_CURVE_VOL 7 +#define BASS_CONFIG_CURVE_PAN 8 +#define BASS_CONFIG_FLOATDSP 9 +#define BASS_CONFIG_3DALGORITHM 10 +#define BASS_CONFIG_NET_TIMEOUT 11 +#define BASS_CONFIG_NET_BUFFER 12 +#define BASS_CONFIG_PAUSE_NOPLAY 13 +#define BASS_CONFIG_NET_PREBUF 15 +#define BASS_CONFIG_NET_PASSIVE 18 +#define BASS_CONFIG_REC_BUFFER 19 +#define BASS_CONFIG_NET_PLAYLIST 21 +#define BASS_CONFIG_MUSIC_VIRTUAL 22 +#define BASS_CONFIG_VERIFY 23 +#define BASS_CONFIG_UPDATETHREADS 24 +#define BASS_CONFIG_DEV_BUFFER 27 +#define BASS_CONFIG_VISTA_TRUEPOS 30 +#define BASS_CONFIG_IOS_MIXAUDIO 34 +#define BASS_CONFIG_DEV_DEFAULT 36 +#define BASS_CONFIG_NET_READTIMEOUT 37 +#define BASS_CONFIG_VISTA_SPEAKERS 38 +#define BASS_CONFIG_IOS_SPEAKER 39 +#define BASS_CONFIG_MF_DISABLE 40 +#define BASS_CONFIG_HANDLES 41 +#define BASS_CONFIG_UNICODE 42 +#define BASS_CONFIG_SRC 43 +#define BASS_CONFIG_SRC_SAMPLE 44 +#define BASS_CONFIG_ASYNCFILE_BUFFER 45 +#define BASS_CONFIG_OGG_PRESCAN 47 +#define BASS_CONFIG_MF_VIDEO 48 +#define BASS_CONFIG_AIRPLAY 49 +#define BASS_CONFIG_DEV_NONSTOP 50 +#define BASS_CONFIG_IOS_NOCATEGORY 51 +#define BASS_CONFIG_VERIFY_NET 52 +#define BASS_CONFIG_DEV_PERIOD 53 +#define BASS_CONFIG_FLOAT 54 +#define BASS_CONFIG_NET_SEEK 56 +#define BASS_CONFIG_AM_DISABLE 58 +#define BASS_CONFIG_NET_PLAYLIST_DEPTH 59 +#define BASS_CONFIG_NET_PREBUF_WAIT 60 // BASS_SetConfigPtr options -#define BASS_CONFIG_NET_AGENT 16 -#define BASS_CONFIG_NET_PROXY 17 -#define BASS_CONFIG_IOS_NOTIFY 46 +#define BASS_CONFIG_NET_AGENT 16 +#define BASS_CONFIG_NET_PROXY 17 +#define BASS_CONFIG_IOS_NOTIFY 46 // BASS_Init flags -#define BASS_DEVICE_8BITS 1 // 8 bit -#define BASS_DEVICE_MONO 2 // mono -#define BASS_DEVICE_3D 4 // enable 3D functionality -#define BASS_DEVICE_16BITS 8 // limit output to 16 bit -#define BASS_DEVICE_LATENCY 0x100 // calculate device latency (BASS_INFO struct) -#define BASS_DEVICE_CPSPEAKERS 0x400 // detect speakers via Windows control panel -#define BASS_DEVICE_SPEAKERS 0x800 // force enabling of speaker assignment -#define BASS_DEVICE_NOSPEAKER 0x1000 // ignore speaker arrangement -#define BASS_DEVICE_DMIX 0x2000 // use ALSA "dmix" plugin -#define BASS_DEVICE_FREQ 0x4000 // set device sample rate -#define BASS_DEVICE_STEREO 0x8000 // limit output to stereo -#define BASS_DEVICE_HOG 0x10000 // hog/exclusive mode -#define BASS_DEVICE_AUDIOTRACK 0x20000 // use AudioTrack output -#define BASS_DEVICE_DSOUND 0x40000 // use DirectSound output +#define BASS_DEVICE_8BITS 1 // 8 bit +#define BASS_DEVICE_MONO 2 // mono +#define BASS_DEVICE_3D 4 // enable 3D functionality +#define BASS_DEVICE_16BITS 8 // limit output to 16 bit +#define BASS_DEVICE_LATENCY 0x100 // calculate device latency (BASS_INFO struct) +#define BASS_DEVICE_CPSPEAKERS \ + 0x400 // detect speakers via Windows control panel +#define BASS_DEVICE_SPEAKERS 0x800 // force enabling of speaker assignment +#define BASS_DEVICE_NOSPEAKER 0x1000 // ignore speaker arrangement +#define BASS_DEVICE_DMIX 0x2000 // use ALSA "dmix" plugin +#define BASS_DEVICE_FREQ 0x4000 // set device sample rate +#define BASS_DEVICE_STEREO 0x8000 // limit output to stereo +#define BASS_DEVICE_HOG 0x10000 // hog/exclusive mode +#define BASS_DEVICE_AUDIOTRACK 0x20000 // use AudioTrack output +#define BASS_DEVICE_DSOUND 0x40000 // use DirectSound output // DirectSound interfaces (for use with BASS_GetDSoundObject) -#define BASS_OBJECT_DS 1 // IDirectSound -#define BASS_OBJECT_DS3DL 2 // IDirectSound3DListener +#define BASS_OBJECT_DS 1 // IDirectSound +#define BASS_OBJECT_DS3DL 2 // IDirectSound3DListener // Device info structure typedef struct { -#if defined(_WIN32_WCE) || (WINAPI_FAMILY && WINAPI_FAMILY!=WINAPI_FAMILY_DESKTOP_APP) - const wchar_t *name; // description - const wchar_t *driver; // driver +#if defined(_WIN32_WCE) || \ + (WINAPI_FAMILY && WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP) + const wchar_t *name; // description + const wchar_t *driver; // driver #else - const char *name; // description - const char *driver; // driver + const char *name; // description + const char *driver; // driver #endif - DWORD flags; + DWORD flags; } BASS_DEVICEINFO; // BASS_DEVICEINFO flags -#define BASS_DEVICE_ENABLED 1 -#define BASS_DEVICE_DEFAULT 2 -#define BASS_DEVICE_INIT 4 -#define BASS_DEVICE_LOOPBACK 8 +#define BASS_DEVICE_ENABLED 1 +#define BASS_DEVICE_DEFAULT 2 +#define BASS_DEVICE_INIT 4 +#define BASS_DEVICE_LOOPBACK 8 -#define BASS_DEVICE_TYPE_MASK 0xff000000 -#define BASS_DEVICE_TYPE_NETWORK 0x01000000 -#define BASS_DEVICE_TYPE_SPEAKERS 0x02000000 -#define BASS_DEVICE_TYPE_LINE 0x03000000 -#define BASS_DEVICE_TYPE_HEADPHONES 0x04000000 -#define BASS_DEVICE_TYPE_MICROPHONE 0x05000000 -#define BASS_DEVICE_TYPE_HEADSET 0x06000000 -#define BASS_DEVICE_TYPE_HANDSET 0x07000000 -#define BASS_DEVICE_TYPE_DIGITAL 0x08000000 -#define BASS_DEVICE_TYPE_SPDIF 0x09000000 -#define BASS_DEVICE_TYPE_HDMI 0x0a000000 -#define BASS_DEVICE_TYPE_DISPLAYPORT 0x40000000 +#define BASS_DEVICE_TYPE_MASK 0xff000000 +#define BASS_DEVICE_TYPE_NETWORK 0x01000000 +#define BASS_DEVICE_TYPE_SPEAKERS 0x02000000 +#define BASS_DEVICE_TYPE_LINE 0x03000000 +#define BASS_DEVICE_TYPE_HEADPHONES 0x04000000 +#define BASS_DEVICE_TYPE_MICROPHONE 0x05000000 +#define BASS_DEVICE_TYPE_HEADSET 0x06000000 +#define BASS_DEVICE_TYPE_HANDSET 0x07000000 +#define BASS_DEVICE_TYPE_DIGITAL 0x08000000 +#define BASS_DEVICE_TYPE_SPDIF 0x09000000 +#define BASS_DEVICE_TYPE_HDMI 0x0a000000 +#define BASS_DEVICE_TYPE_DISPLAYPORT 0x40000000 + +// BASS_GetDeviceInfo flags +#define BASS_DEVICES_AIRPLAY 0x1000000 -// BASS_GetDeviceInfo flags -#define BASS_DEVICES_AIRPLAY 0x1000000 - typedef struct { - DWORD flags; // device capabilities (DSCAPS_xxx flags) - DWORD hwsize; // size of total device hardware memory - DWORD hwfree; // size of free device hardware memory - DWORD freesam; // number of free sample slots in the hardware - DWORD free3d; // number of free 3D sample slots in the hardware - DWORD minrate; // min sample rate supported by the hardware - DWORD maxrate; // max sample rate supported by the hardware - BOOL eax; // device supports EAX? (always FALSE if BASS_DEVICE_3D was not used) - DWORD minbuf; // recommended minimum buffer length in ms (requires BASS_DEVICE_LATENCY) - DWORD dsver; // DirectSound version - DWORD latency; // delay (in ms) before start of playback (requires BASS_DEVICE_LATENCY) - DWORD initflags; // BASS_Init "flags" parameter - DWORD speakers; // number of speakers available - DWORD freq; // current output rate + DWORD flags; // device capabilities (DSCAPS_xxx flags) + DWORD hwsize; // size of total device hardware memory + DWORD hwfree; // size of free device hardware memory + DWORD freesam; // number of free sample slots in the hardware + DWORD free3d; // number of free 3D sample slots in the hardware + DWORD minrate; // min sample rate supported by the hardware + DWORD maxrate; // max sample rate supported by the hardware + BOOL + eax; // device supports EAX? (always FALSE if BASS_DEVICE_3D was not used) + DWORD minbuf; // recommended minimum buffer length in ms (requires + // BASS_DEVICE_LATENCY) + DWORD dsver; // DirectSound version + DWORD latency; // delay (in ms) before start of playback (requires + // BASS_DEVICE_LATENCY) + DWORD initflags; // BASS_Init "flags" parameter + DWORD speakers; // number of speakers available + DWORD freq; // current output rate } BASS_INFO; // BASS_INFO flags (from DSOUND.H) -#define DSCAPS_CONTINUOUSRATE 0x00000010 // supports all sample rates between min/maxrate -#define DSCAPS_EMULDRIVER 0x00000020 // device does NOT have hardware DirectSound support -#define DSCAPS_CERTIFIED 0x00000040 // device driver has been certified by Microsoft -#define DSCAPS_SECONDARYMONO 0x00000100 // mono -#define DSCAPS_SECONDARYSTEREO 0x00000200 // stereo -#define DSCAPS_SECONDARY8BIT 0x00000400 // 8 bit -#define DSCAPS_SECONDARY16BIT 0x00000800 // 16 bit +#define DSCAPS_CONTINUOUSRATE \ + 0x00000010 // supports all sample rates between min/maxrate +#define DSCAPS_EMULDRIVER \ + 0x00000020 // device does NOT have hardware DirectSound support +#define DSCAPS_CERTIFIED \ + 0x00000040 // device driver has been certified by Microsoft +#define DSCAPS_SECONDARYMONO 0x00000100 // mono +#define DSCAPS_SECONDARYSTEREO 0x00000200 // stereo +#define DSCAPS_SECONDARY8BIT 0x00000400 // 8 bit +#define DSCAPS_SECONDARY16BIT 0x00000800 // 16 bit // Recording device info structure typedef struct { - DWORD flags; // device capabilities (DSCCAPS_xxx flags) - DWORD formats; // supported standard formats (WAVE_FORMAT_xxx flags) - DWORD inputs; // number of inputs - BOOL singlein; // TRUE = only 1 input can be set at a time - DWORD freq; // current input rate + DWORD flags; // device capabilities (DSCCAPS_xxx flags) + DWORD formats; // supported standard formats (WAVE_FORMAT_xxx flags) + DWORD inputs; // number of inputs + BOOL singlein; // TRUE = only 1 input can be set at a time + DWORD freq; // current input rate } BASS_RECORDINFO; // BASS_RECORDINFO flags (from DSOUND.H) -#define DSCCAPS_EMULDRIVER DSCAPS_EMULDRIVER // device does NOT have hardware DirectSound recording support -#define DSCCAPS_CERTIFIED DSCAPS_CERTIFIED // device driver has been certified by Microsoft +#define DSCCAPS_EMULDRIVER \ + DSCAPS_EMULDRIVER // device does NOT have hardware DirectSound recording + // support +#define DSCCAPS_CERTIFIED \ + DSCAPS_CERTIFIED // device driver has been certified by Microsoft // defines for formats field of BASS_RECORDINFO (from MMSYSTEM.H) #ifndef WAVE_FORMAT_1M08 -#define WAVE_FORMAT_1M08 0x00000001 /* 11.025 kHz, Mono, 8-bit */ -#define WAVE_FORMAT_1S08 0x00000002 /* 11.025 kHz, Stereo, 8-bit */ -#define WAVE_FORMAT_1M16 0x00000004 /* 11.025 kHz, Mono, 16-bit */ -#define WAVE_FORMAT_1S16 0x00000008 /* 11.025 kHz, Stereo, 16-bit */ -#define WAVE_FORMAT_2M08 0x00000010 /* 22.05 kHz, Mono, 8-bit */ -#define WAVE_FORMAT_2S08 0x00000020 /* 22.05 kHz, Stereo, 8-bit */ -#define WAVE_FORMAT_2M16 0x00000040 /* 22.05 kHz, Mono, 16-bit */ -#define WAVE_FORMAT_2S16 0x00000080 /* 22.05 kHz, Stereo, 16-bit */ -#define WAVE_FORMAT_4M08 0x00000100 /* 44.1 kHz, Mono, 8-bit */ -#define WAVE_FORMAT_4S08 0x00000200 /* 44.1 kHz, Stereo, 8-bit */ -#define WAVE_FORMAT_4M16 0x00000400 /* 44.1 kHz, Mono, 16-bit */ -#define WAVE_FORMAT_4S16 0x00000800 /* 44.1 kHz, Stereo, 16-bit */ +#define WAVE_FORMAT_1M08 0x00000001 /* 11.025 kHz, Mono, 8-bit */ +#define WAVE_FORMAT_1S08 0x00000002 /* 11.025 kHz, Stereo, 8-bit */ +#define WAVE_FORMAT_1M16 0x00000004 /* 11.025 kHz, Mono, 16-bit */ +#define WAVE_FORMAT_1S16 0x00000008 /* 11.025 kHz, Stereo, 16-bit */ +#define WAVE_FORMAT_2M08 0x00000010 /* 22.05 kHz, Mono, 8-bit */ +#define WAVE_FORMAT_2S08 0x00000020 /* 22.05 kHz, Stereo, 8-bit */ +#define WAVE_FORMAT_2M16 0x00000040 /* 22.05 kHz, Mono, 16-bit */ +#define WAVE_FORMAT_2S16 0x00000080 /* 22.05 kHz, Stereo, 16-bit */ +#define WAVE_FORMAT_4M08 0x00000100 /* 44.1 kHz, Mono, 8-bit */ +#define WAVE_FORMAT_4S08 0x00000200 /* 44.1 kHz, Stereo, 8-bit */ +#define WAVE_FORMAT_4M16 0x00000400 /* 44.1 kHz, Mono, 16-bit */ +#define WAVE_FORMAT_4S16 0x00000800 /* 44.1 kHz, Stereo, 16-bit */ #endif // Sample info structure typedef struct { - DWORD freq; // default playback rate - float volume; // default volume (0-1) - float pan; // default pan (-1=left, 0=middle, 1=right) - DWORD flags; // BASS_SAMPLE_xxx flags - DWORD length; // length (in bytes) - DWORD max; // maximum simultaneous playbacks - DWORD origres; // original resolution - DWORD chans; // number of channels - DWORD mingap; // minimum gap (ms) between creating channels - DWORD mode3d; // BASS_3DMODE_xxx mode - float mindist; // minimum distance - float maxdist; // maximum distance - DWORD iangle; // angle of inside projection cone - DWORD oangle; // angle of outside projection cone - float outvol; // delta-volume outside the projection cone - DWORD vam; // voice allocation/management flags (BASS_VAM_xxx) - DWORD priority; // priority (0=lowest, 0xffffffff=highest) + DWORD freq; // default playback rate + float volume; // default volume (0-1) + float pan; // default pan (-1=left, 0=middle, 1=right) + DWORD flags; // BASS_SAMPLE_xxx flags + DWORD length; // length (in bytes) + DWORD max; // maximum simultaneous playbacks + DWORD origres; // original resolution + DWORD chans; // number of channels + DWORD mingap; // minimum gap (ms) between creating channels + DWORD mode3d; // BASS_3DMODE_xxx mode + float mindist; // minimum distance + float maxdist; // maximum distance + DWORD iangle; // angle of inside projection cone + DWORD oangle; // angle of outside projection cone + float outvol; // delta-volume outside the projection cone + DWORD vam; // voice allocation/management flags (BASS_VAM_xxx) + DWORD priority; // priority (0=lowest, 0xffffffff=highest) } BASS_SAMPLE; -#define BASS_SAMPLE_8BITS 1 // 8 bit -#define BASS_SAMPLE_FLOAT 256 // 32 bit floating-point -#define BASS_SAMPLE_MONO 2 // mono -#define BASS_SAMPLE_LOOP 4 // looped -#define BASS_SAMPLE_3D 8 // 3D functionality -#define BASS_SAMPLE_SOFTWARE 16 // not using hardware mixing -#define BASS_SAMPLE_MUTEMAX 32 // mute at max distance (3D only) -#define BASS_SAMPLE_VAM 64 // DX7 voice allocation & management -#define BASS_SAMPLE_FX 128 // old implementation of DX8 effects -#define BASS_SAMPLE_OVER_VOL 0x10000 // override lowest volume -#define BASS_SAMPLE_OVER_POS 0x20000 // override longest playing -#define BASS_SAMPLE_OVER_DIST 0x30000 // override furthest from listener (3D only) +#define BASS_SAMPLE_8BITS 1 // 8 bit +#define BASS_SAMPLE_FLOAT 256 // 32 bit floating-point +#define BASS_SAMPLE_MONO 2 // mono +#define BASS_SAMPLE_LOOP 4 // looped +#define BASS_SAMPLE_3D 8 // 3D functionality +#define BASS_SAMPLE_SOFTWARE 16 // not using hardware mixing +#define BASS_SAMPLE_MUTEMAX 32 // mute at max distance (3D only) +#define BASS_SAMPLE_VAM 64 // DX7 voice allocation & management +#define BASS_SAMPLE_FX 128 // old implementation of DX8 effects +#define BASS_SAMPLE_OVER_VOL 0x10000 // override lowest volume +#define BASS_SAMPLE_OVER_POS 0x20000 // override longest playing +#define BASS_SAMPLE_OVER_DIST \ + 0x30000 // override furthest from listener (3D only) -#define BASS_STREAM_PRESCAN 0x20000 // enable pin-point seeking/length (MP3/MP2/MP1) -#define BASS_STREAM_AUTOFREE 0x40000 // automatically free the stream when it stop/ends -#define BASS_STREAM_RESTRATE 0x80000 // restrict the download rate of internet file streams -#define BASS_STREAM_BLOCK 0x100000 // download/play internet file stream in small blocks -#define BASS_STREAM_DECODE 0x200000 // don't play the stream, only decode (BASS_ChannelGetData) -#define BASS_STREAM_STATUS 0x800000 // give server status info (HTTP/ICY tags) in DOWNLOADPROC +#define BASS_STREAM_PRESCAN \ + 0x20000 // enable pin-point seeking/length (MP3/MP2/MP1) +#define BASS_STREAM_AUTOFREE \ + 0x40000 // automatically free the stream when it stop/ends +#define BASS_STREAM_RESTRATE \ + 0x80000 // restrict the download rate of internet file streams +#define BASS_STREAM_BLOCK \ + 0x100000 // download/play internet file stream in small blocks +#define BASS_STREAM_DECODE \ + 0x200000 // don't play the stream, only decode (BASS_ChannelGetData) +#define BASS_STREAM_STATUS \ + 0x800000 // give server status info (HTTP/ICY tags) in DOWNLOADPROC -#define BASS_MP3_IGNOREDELAY 0x200 // ignore LAME/Xing/VBRI/iTunes delay & padding info -#define BASS_MP3_SETPOS BASS_STREAM_PRESCAN +#define BASS_MP3_IGNOREDELAY \ + 0x200 // ignore LAME/Xing/VBRI/iTunes delay & padding info +#define BASS_MP3_SETPOS BASS_STREAM_PRESCAN -#define BASS_MUSIC_FLOAT BASS_SAMPLE_FLOAT -#define BASS_MUSIC_MONO BASS_SAMPLE_MONO -#define BASS_MUSIC_LOOP BASS_SAMPLE_LOOP -#define BASS_MUSIC_3D BASS_SAMPLE_3D -#define BASS_MUSIC_FX BASS_SAMPLE_FX -#define BASS_MUSIC_AUTOFREE BASS_STREAM_AUTOFREE -#define BASS_MUSIC_DECODE BASS_STREAM_DECODE -#define BASS_MUSIC_PRESCAN BASS_STREAM_PRESCAN // calculate playback length -#define BASS_MUSIC_CALCLEN BASS_MUSIC_PRESCAN -#define BASS_MUSIC_RAMP 0x200 // normal ramping -#define BASS_MUSIC_RAMPS 0x400 // sensitive ramping -#define BASS_MUSIC_SURROUND 0x800 // surround sound -#define BASS_MUSIC_SURROUND2 0x1000 // surround sound (mode 2) -#define BASS_MUSIC_FT2PAN 0x2000 // apply FastTracker 2 panning to XM files -#define BASS_MUSIC_FT2MOD 0x2000 // play .MOD as FastTracker 2 does -#define BASS_MUSIC_PT1MOD 0x4000 // play .MOD as ProTracker 1 does -#define BASS_MUSIC_NONINTER 0x10000 // non-interpolated sample mixing -#define BASS_MUSIC_SINCINTER 0x800000 // sinc interpolated sample mixing -#define BASS_MUSIC_POSRESET 0x8000 // stop all notes when moving position -#define BASS_MUSIC_POSRESETEX 0x400000 // stop all notes and reset bmp/etc when moving position -#define BASS_MUSIC_STOPBACK 0x80000 // stop the music on a backwards jump effect -#define BASS_MUSIC_NOSAMPLE 0x100000 // don't load the samples +#define BASS_MUSIC_FLOAT BASS_SAMPLE_FLOAT +#define BASS_MUSIC_MONO BASS_SAMPLE_MONO +#define BASS_MUSIC_LOOP BASS_SAMPLE_LOOP +#define BASS_MUSIC_3D BASS_SAMPLE_3D +#define BASS_MUSIC_FX BASS_SAMPLE_FX +#define BASS_MUSIC_AUTOFREE BASS_STREAM_AUTOFREE +#define BASS_MUSIC_DECODE BASS_STREAM_DECODE +#define BASS_MUSIC_PRESCAN BASS_STREAM_PRESCAN // calculate playback length +#define BASS_MUSIC_CALCLEN BASS_MUSIC_PRESCAN +#define BASS_MUSIC_RAMP 0x200 // normal ramping +#define BASS_MUSIC_RAMPS 0x400 // sensitive ramping +#define BASS_MUSIC_SURROUND 0x800 // surround sound +#define BASS_MUSIC_SURROUND2 0x1000 // surround sound (mode 2) +#define BASS_MUSIC_FT2PAN 0x2000 // apply FastTracker 2 panning to XM files +#define BASS_MUSIC_FT2MOD 0x2000 // play .MOD as FastTracker 2 does +#define BASS_MUSIC_PT1MOD 0x4000 // play .MOD as ProTracker 1 does +#define BASS_MUSIC_NONINTER 0x10000 // non-interpolated sample mixing +#define BASS_MUSIC_SINCINTER 0x800000 // sinc interpolated sample mixing +#define BASS_MUSIC_POSRESET 0x8000 // stop all notes when moving position +#define BASS_MUSIC_POSRESETEX \ + 0x400000 // stop all notes and reset bmp/etc when moving position +#define BASS_MUSIC_STOPBACK 0x80000 // stop the music on a backwards jump effect +#define BASS_MUSIC_NOSAMPLE 0x100000 // don't load the samples // Speaker assignment flags -#define BASS_SPEAKER_FRONT 0x1000000 // front speakers -#define BASS_SPEAKER_REAR 0x2000000 // rear/side speakers -#define BASS_SPEAKER_CENLFE 0x3000000 // center & LFE speakers (5.1) -#define BASS_SPEAKER_REAR2 0x4000000 // rear center speakers (7.1) -#define BASS_SPEAKER_N(n) ((n)<<24) // n'th pair of speakers (max 15) -#define BASS_SPEAKER_LEFT 0x10000000 // modifier: left -#define BASS_SPEAKER_RIGHT 0x20000000 // modifier: right -#define BASS_SPEAKER_FRONTLEFT BASS_SPEAKER_FRONT|BASS_SPEAKER_LEFT -#define BASS_SPEAKER_FRONTRIGHT BASS_SPEAKER_FRONT|BASS_SPEAKER_RIGHT -#define BASS_SPEAKER_REARLEFT BASS_SPEAKER_REAR|BASS_SPEAKER_LEFT -#define BASS_SPEAKER_REARRIGHT BASS_SPEAKER_REAR|BASS_SPEAKER_RIGHT -#define BASS_SPEAKER_CENTER BASS_SPEAKER_CENLFE|BASS_SPEAKER_LEFT -#define BASS_SPEAKER_LFE BASS_SPEAKER_CENLFE|BASS_SPEAKER_RIGHT -#define BASS_SPEAKER_REAR2LEFT BASS_SPEAKER_REAR2|BASS_SPEAKER_LEFT -#define BASS_SPEAKER_REAR2RIGHT BASS_SPEAKER_REAR2|BASS_SPEAKER_RIGHT +#define BASS_SPEAKER_FRONT 0x1000000 // front speakers +#define BASS_SPEAKER_REAR 0x2000000 // rear/side speakers +#define BASS_SPEAKER_CENLFE 0x3000000 // center & LFE speakers (5.1) +#define BASS_SPEAKER_REAR2 0x4000000 // rear center speakers (7.1) +#define BASS_SPEAKER_N(n) ((n) << 24) // n'th pair of speakers (max 15) +#define BASS_SPEAKER_LEFT 0x10000000 // modifier: left +#define BASS_SPEAKER_RIGHT 0x20000000 // modifier: right +#define BASS_SPEAKER_FRONTLEFT BASS_SPEAKER_FRONT | BASS_SPEAKER_LEFT +#define BASS_SPEAKER_FRONTRIGHT BASS_SPEAKER_FRONT | BASS_SPEAKER_RIGHT +#define BASS_SPEAKER_REARLEFT BASS_SPEAKER_REAR | BASS_SPEAKER_LEFT +#define BASS_SPEAKER_REARRIGHT BASS_SPEAKER_REAR | BASS_SPEAKER_RIGHT +#define BASS_SPEAKER_CENTER BASS_SPEAKER_CENLFE | BASS_SPEAKER_LEFT +#define BASS_SPEAKER_LFE BASS_SPEAKER_CENLFE | BASS_SPEAKER_RIGHT +#define BASS_SPEAKER_REAR2LEFT BASS_SPEAKER_REAR2 | BASS_SPEAKER_LEFT +#define BASS_SPEAKER_REAR2RIGHT BASS_SPEAKER_REAR2 | BASS_SPEAKER_RIGHT -#define BASS_ASYNCFILE 0x40000000 -#define BASS_UNICODE 0x80000000 +#define BASS_ASYNCFILE 0x40000000 +#define BASS_UNICODE 0x80000000 -#define BASS_RECORD_PAUSE 0x8000 // start recording paused -#define BASS_RECORD_ECHOCANCEL 0x2000 -#define BASS_RECORD_AGC 0x4000 +#define BASS_RECORD_PAUSE 0x8000 // start recording paused +#define BASS_RECORD_ECHOCANCEL 0x2000 +#define BASS_RECORD_AGC 0x4000 // DX7 voice allocation & management flags -#define BASS_VAM_HARDWARE 1 -#define BASS_VAM_SOFTWARE 2 -#define BASS_VAM_TERM_TIME 4 -#define BASS_VAM_TERM_DIST 8 -#define BASS_VAM_TERM_PRIO 16 +#define BASS_VAM_HARDWARE 1 +#define BASS_VAM_SOFTWARE 2 +#define BASS_VAM_TERM_TIME 4 +#define BASS_VAM_TERM_DIST 8 +#define BASS_VAM_TERM_PRIO 16 // Channel info structure typedef struct { - DWORD freq; // default playback rate - DWORD chans; // channels - DWORD flags; // BASS_SAMPLE/STREAM/MUSIC/SPEAKER flags - DWORD ctype; // type of channel - DWORD origres; // original resolution - HPLUGIN plugin; // plugin - HSAMPLE sample; // sample - const char *filename; // filename + DWORD freq; // default playback rate + DWORD chans; // channels + DWORD flags; // BASS_SAMPLE/STREAM/MUSIC/SPEAKER flags + DWORD ctype; // type of channel + DWORD origres; // original resolution + HPLUGIN plugin; // plugin + HSAMPLE sample; // sample + const char *filename; // filename } BASS_CHANNELINFO; -#define BASS_ORIGRES_FLOAT 0x10000 +#define BASS_ORIGRES_FLOAT 0x10000 // BASS_CHANNELINFO types -#define BASS_CTYPE_SAMPLE 1 -#define BASS_CTYPE_RECORD 2 -#define BASS_CTYPE_STREAM 0x10000 -#define BASS_CTYPE_STREAM_OGG 0x10002 -#define BASS_CTYPE_STREAM_MP1 0x10003 -#define BASS_CTYPE_STREAM_MP2 0x10004 -#define BASS_CTYPE_STREAM_MP3 0x10005 -#define BASS_CTYPE_STREAM_AIFF 0x10006 -#define BASS_CTYPE_STREAM_CA 0x10007 -#define BASS_CTYPE_STREAM_MF 0x10008 -#define BASS_CTYPE_STREAM_AM 0x10009 -#define BASS_CTYPE_STREAM_DUMMY 0x18000 -#define BASS_CTYPE_STREAM_DEVICE 0x18001 -#define BASS_CTYPE_STREAM_WAV 0x40000 // WAVE flag, LOWORD=codec -#define BASS_CTYPE_STREAM_WAV_PCM 0x50001 -#define BASS_CTYPE_STREAM_WAV_FLOAT 0x50003 -#define BASS_CTYPE_MUSIC_MOD 0x20000 -#define BASS_CTYPE_MUSIC_MTM 0x20001 -#define BASS_CTYPE_MUSIC_S3M 0x20002 -#define BASS_CTYPE_MUSIC_XM 0x20003 -#define BASS_CTYPE_MUSIC_IT 0x20004 -#define BASS_CTYPE_MUSIC_MO3 0x00100 // MO3 flag +#define BASS_CTYPE_SAMPLE 1 +#define BASS_CTYPE_RECORD 2 +#define BASS_CTYPE_STREAM 0x10000 +#define BASS_CTYPE_STREAM_OGG 0x10002 +#define BASS_CTYPE_STREAM_MP1 0x10003 +#define BASS_CTYPE_STREAM_MP2 0x10004 +#define BASS_CTYPE_STREAM_MP3 0x10005 +#define BASS_CTYPE_STREAM_AIFF 0x10006 +#define BASS_CTYPE_STREAM_CA 0x10007 +#define BASS_CTYPE_STREAM_MF 0x10008 +#define BASS_CTYPE_STREAM_AM 0x10009 +#define BASS_CTYPE_STREAM_DUMMY 0x18000 +#define BASS_CTYPE_STREAM_DEVICE 0x18001 +#define BASS_CTYPE_STREAM_WAV 0x40000 // WAVE flag, LOWORD=codec +#define BASS_CTYPE_STREAM_WAV_PCM 0x50001 +#define BASS_CTYPE_STREAM_WAV_FLOAT 0x50003 +#define BASS_CTYPE_MUSIC_MOD 0x20000 +#define BASS_CTYPE_MUSIC_MTM 0x20001 +#define BASS_CTYPE_MUSIC_S3M 0x20002 +#define BASS_CTYPE_MUSIC_XM 0x20003 +#define BASS_CTYPE_MUSIC_IT 0x20004 +#define BASS_CTYPE_MUSIC_MO3 0x00100 // MO3 flag typedef struct { - DWORD ctype; // channel type -#if defined(_WIN32_WCE) || (WINAPI_FAMILY && WINAPI_FAMILY!=WINAPI_FAMILY_DESKTOP_APP) - const wchar_t *name; // format description - const wchar_t *exts; // file extension filter (*.ext1;*.ext2;etc...) + DWORD ctype; // channel type +#if defined(_WIN32_WCE) || \ + (WINAPI_FAMILY && WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP) + const wchar_t *name; // format description + const wchar_t *exts; // file extension filter (*.ext1;*.ext2;etc...) #else - const char *name; // format description - const char *exts; // file extension filter (*.ext1;*.ext2;etc...) + const char *name; // format description + const char *exts; // file extension filter (*.ext1;*.ext2;etc...) #endif } BASS_PLUGINFORM; typedef struct { - DWORD version; // version (same form as BASS_GetVersion) - DWORD formatc; // number of formats - const BASS_PLUGINFORM *formats; // the array of formats + DWORD version; // version (same form as BASS_GetVersion) + DWORD formatc; // number of formats + const BASS_PLUGINFORM *formats; // the array of formats } BASS_PLUGININFO; // 3D vector (for 3D positions/velocities/orientations) typedef struct BASS_3DVECTOR { #ifdef __cplusplus - BASS_3DVECTOR() {}; - BASS_3DVECTOR(float _x, float _y, float _z) : x(_x), y(_y), z(_z) {}; + BASS_3DVECTOR(){}; + BASS_3DVECTOR(float _x, float _y, float _z) : x(_x), y(_y), z(_z){}; #endif - float x; // +=right, -=left - float y; // +=up, -=down - float z; // +=front, -=behind + float x; // +=right, -=left + float y; // +=up, -=down + float z; // +=front, -=behind } BASS_3DVECTOR; // 3D channel modes -#define BASS_3DMODE_NORMAL 0 // normal 3D processing -#define BASS_3DMODE_RELATIVE 1 // position is relative to the listener -#define BASS_3DMODE_OFF 2 // no 3D processing +#define BASS_3DMODE_NORMAL 0 // normal 3D processing +#define BASS_3DMODE_RELATIVE 1 // position is relative to the listener +#define BASS_3DMODE_OFF 2 // no 3D processing // software 3D mixing algorithms (used with BASS_CONFIG_3DALGORITHM) -#define BASS_3DALG_DEFAULT 0 -#define BASS_3DALG_OFF 1 -#define BASS_3DALG_FULL 2 -#define BASS_3DALG_LIGHT 3 +#define BASS_3DALG_DEFAULT 0 +#define BASS_3DALG_OFF 1 +#define BASS_3DALG_FULL 2 +#define BASS_3DALG_LIGHT 3 // EAX environments, use with BASS_SetEAXParameters -enum -{ - EAX_ENVIRONMENT_GENERIC, - EAX_ENVIRONMENT_PADDEDCELL, - EAX_ENVIRONMENT_ROOM, - EAX_ENVIRONMENT_BATHROOM, - EAX_ENVIRONMENT_LIVINGROOM, - EAX_ENVIRONMENT_STONEROOM, - EAX_ENVIRONMENT_AUDITORIUM, - EAX_ENVIRONMENT_CONCERTHALL, - EAX_ENVIRONMENT_CAVE, - EAX_ENVIRONMENT_ARENA, - EAX_ENVIRONMENT_HANGAR, - EAX_ENVIRONMENT_CARPETEDHALLWAY, - EAX_ENVIRONMENT_HALLWAY, - EAX_ENVIRONMENT_STONECORRIDOR, - EAX_ENVIRONMENT_ALLEY, - EAX_ENVIRONMENT_FOREST, - EAX_ENVIRONMENT_CITY, - EAX_ENVIRONMENT_MOUNTAINS, - EAX_ENVIRONMENT_QUARRY, - EAX_ENVIRONMENT_PLAIN, - EAX_ENVIRONMENT_PARKINGLOT, - EAX_ENVIRONMENT_SEWERPIPE, - EAX_ENVIRONMENT_UNDERWATER, - EAX_ENVIRONMENT_DRUGGED, - EAX_ENVIRONMENT_DIZZY, - EAX_ENVIRONMENT_PSYCHOTIC, +enum { + EAX_ENVIRONMENT_GENERIC, + EAX_ENVIRONMENT_PADDEDCELL, + EAX_ENVIRONMENT_ROOM, + EAX_ENVIRONMENT_BATHROOM, + EAX_ENVIRONMENT_LIVINGROOM, + EAX_ENVIRONMENT_STONEROOM, + EAX_ENVIRONMENT_AUDITORIUM, + EAX_ENVIRONMENT_CONCERTHALL, + EAX_ENVIRONMENT_CAVE, + EAX_ENVIRONMENT_ARENA, + EAX_ENVIRONMENT_HANGAR, + EAX_ENVIRONMENT_CARPETEDHALLWAY, + EAX_ENVIRONMENT_HALLWAY, + EAX_ENVIRONMENT_STONECORRIDOR, + EAX_ENVIRONMENT_ALLEY, + EAX_ENVIRONMENT_FOREST, + EAX_ENVIRONMENT_CITY, + EAX_ENVIRONMENT_MOUNTAINS, + EAX_ENVIRONMENT_QUARRY, + EAX_ENVIRONMENT_PLAIN, + EAX_ENVIRONMENT_PARKINGLOT, + EAX_ENVIRONMENT_SEWERPIPE, + EAX_ENVIRONMENT_UNDERWATER, + EAX_ENVIRONMENT_DRUGGED, + EAX_ENVIRONMENT_DIZZY, + EAX_ENVIRONMENT_PSYCHOTIC, - EAX_ENVIRONMENT_COUNT // total number of environments + EAX_ENVIRONMENT_COUNT // total number of environments }; // EAX presets, usage: BASS_SetEAXParameters(EAX_PRESET_xxx) -#define EAX_PRESET_GENERIC EAX_ENVIRONMENT_GENERIC,0.5F,1.493F,0.5F -#define EAX_PRESET_PADDEDCELL EAX_ENVIRONMENT_PADDEDCELL,0.25F,0.1F,0.0F -#define EAX_PRESET_ROOM EAX_ENVIRONMENT_ROOM,0.417F,0.4F,0.666F -#define EAX_PRESET_BATHROOM EAX_ENVIRONMENT_BATHROOM,0.653F,1.499F,0.166F -#define EAX_PRESET_LIVINGROOM EAX_ENVIRONMENT_LIVINGROOM,0.208F,0.478F,0.0F -#define EAX_PRESET_STONEROOM EAX_ENVIRONMENT_STONEROOM,0.5F,2.309F,0.888F -#define EAX_PRESET_AUDITORIUM EAX_ENVIRONMENT_AUDITORIUM,0.403F,4.279F,0.5F -#define EAX_PRESET_CONCERTHALL EAX_ENVIRONMENT_CONCERTHALL,0.5F,3.961F,0.5F -#define EAX_PRESET_CAVE EAX_ENVIRONMENT_CAVE,0.5F,2.886F,1.304F -#define EAX_PRESET_ARENA EAX_ENVIRONMENT_ARENA,0.361F,7.284F,0.332F -#define EAX_PRESET_HANGAR EAX_ENVIRONMENT_HANGAR,0.5F,10.0F,0.3F -#define EAX_PRESET_CARPETEDHALLWAY EAX_ENVIRONMENT_CARPETEDHALLWAY,0.153F,0.259F,2.0F -#define EAX_PRESET_HALLWAY EAX_ENVIRONMENT_HALLWAY,0.361F,1.493F,0.0F -#define EAX_PRESET_STONECORRIDOR EAX_ENVIRONMENT_STONECORRIDOR,0.444F,2.697F,0.638F -#define EAX_PRESET_ALLEY EAX_ENVIRONMENT_ALLEY,0.25F,1.752F,0.776F -#define EAX_PRESET_FOREST EAX_ENVIRONMENT_FOREST,0.111F,3.145F,0.472F -#define EAX_PRESET_CITY EAX_ENVIRONMENT_CITY,0.111F,2.767F,0.224F -#define EAX_PRESET_MOUNTAINS EAX_ENVIRONMENT_MOUNTAINS,0.194F,7.841F,0.472F -#define EAX_PRESET_QUARRY EAX_ENVIRONMENT_QUARRY,1.0F,1.499F,0.5F -#define EAX_PRESET_PLAIN EAX_ENVIRONMENT_PLAIN,0.097F,2.767F,0.224F -#define EAX_PRESET_PARKINGLOT EAX_ENVIRONMENT_PARKINGLOT,0.208F,1.652F,1.5F -#define EAX_PRESET_SEWERPIPE EAX_ENVIRONMENT_SEWERPIPE,0.652F,2.886F,0.25F -#define EAX_PRESET_UNDERWATER EAX_ENVIRONMENT_UNDERWATER,1.0F,1.499F,0.0F -#define EAX_PRESET_DRUGGED EAX_ENVIRONMENT_DRUGGED,0.875F,8.392F,1.388F -#define EAX_PRESET_DIZZY EAX_ENVIRONMENT_DIZZY,0.139F,17.234F,0.666F -#define EAX_PRESET_PSYCHOTIC EAX_ENVIRONMENT_PSYCHOTIC,0.486F,7.563F,0.806F +#define EAX_PRESET_GENERIC EAX_ENVIRONMENT_GENERIC, 0.5F, 1.493F, 0.5F +#define EAX_PRESET_PADDEDCELL EAX_ENVIRONMENT_PADDEDCELL, 0.25F, 0.1F, 0.0F +#define EAX_PRESET_ROOM EAX_ENVIRONMENT_ROOM, 0.417F, 0.4F, 0.666F +#define EAX_PRESET_BATHROOM EAX_ENVIRONMENT_BATHROOM, 0.653F, 1.499F, 0.166F +#define EAX_PRESET_LIVINGROOM EAX_ENVIRONMENT_LIVINGROOM, 0.208F, 0.478F, 0.0F +#define EAX_PRESET_STONEROOM EAX_ENVIRONMENT_STONEROOM, 0.5F, 2.309F, 0.888F +#define EAX_PRESET_AUDITORIUM EAX_ENVIRONMENT_AUDITORIUM, 0.403F, 4.279F, 0.5F +#define EAX_PRESET_CONCERTHALL EAX_ENVIRONMENT_CONCERTHALL, 0.5F, 3.961F, 0.5F +#define EAX_PRESET_CAVE EAX_ENVIRONMENT_CAVE, 0.5F, 2.886F, 1.304F +#define EAX_PRESET_ARENA EAX_ENVIRONMENT_ARENA, 0.361F, 7.284F, 0.332F +#define EAX_PRESET_HANGAR EAX_ENVIRONMENT_HANGAR, 0.5F, 10.0F, 0.3F +#define EAX_PRESET_CARPETEDHALLWAY \ + EAX_ENVIRONMENT_CARPETEDHALLWAY, 0.153F, 0.259F, 2.0F +#define EAX_PRESET_HALLWAY EAX_ENVIRONMENT_HALLWAY, 0.361F, 1.493F, 0.0F +#define EAX_PRESET_STONECORRIDOR \ + EAX_ENVIRONMENT_STONECORRIDOR, 0.444F, 2.697F, 0.638F +#define EAX_PRESET_ALLEY EAX_ENVIRONMENT_ALLEY, 0.25F, 1.752F, 0.776F +#define EAX_PRESET_FOREST EAX_ENVIRONMENT_FOREST, 0.111F, 3.145F, 0.472F +#define EAX_PRESET_CITY EAX_ENVIRONMENT_CITY, 0.111F, 2.767F, 0.224F +#define EAX_PRESET_MOUNTAINS EAX_ENVIRONMENT_MOUNTAINS, 0.194F, 7.841F, 0.472F +#define EAX_PRESET_QUARRY EAX_ENVIRONMENT_QUARRY, 1.0F, 1.499F, 0.5F +#define EAX_PRESET_PLAIN EAX_ENVIRONMENT_PLAIN, 0.097F, 2.767F, 0.224F +#define EAX_PRESET_PARKINGLOT EAX_ENVIRONMENT_PARKINGLOT, 0.208F, 1.652F, 1.5F +#define EAX_PRESET_SEWERPIPE EAX_ENVIRONMENT_SEWERPIPE, 0.652F, 2.886F, 0.25F +#define EAX_PRESET_UNDERWATER EAX_ENVIRONMENT_UNDERWATER, 1.0F, 1.499F, 0.0F +#define EAX_PRESET_DRUGGED EAX_ENVIRONMENT_DRUGGED, 0.875F, 8.392F, 1.388F +#define EAX_PRESET_DIZZY EAX_ENVIRONMENT_DIZZY, 0.139F, 17.234F, 0.666F +#define EAX_PRESET_PSYCHOTIC EAX_ENVIRONMENT_PSYCHOTIC, 0.486F, 7.563F, 0.806F -typedef DWORD (CALLBACK STREAMPROC)(HSTREAM handle, void *buffer, DWORD length, void *user); -/* User stream callback function. NOTE: A stream function should obviously be as quick -as possible, other streams (and MOD musics) can't be mixed until it's finished. -handle : The stream that needs writing -buffer : Buffer to write the samples in -length : Number of bytes to write -user : The 'user' parameter value given when calling BASS_StreamCreate -RETURN : Number of bytes written. Set the BASS_STREAMPROC_END flag to end the stream. */ +typedef DWORD(CALLBACK STREAMPROC)(HSTREAM handle, void *buffer, DWORD length, + void *user); +/* User stream callback function. NOTE: A stream function should obviously be as +quick as possible, other streams (and MOD musics) can't be mixed until it's +finished. handle : The stream that needs writing buffer : Buffer to write the +samples in length : Number of bytes to write user : The 'user' parameter value +given when calling BASS_StreamCreate RETURN : Number of bytes written. Set the +BASS_STREAMPROC_END flag to end the stream. */ -#define BASS_STREAMPROC_END 0x80000000 // end of user stream flag +#define BASS_STREAMPROC_END 0x80000000 // end of user stream flag // special STREAMPROCs -#define STREAMPROC_DUMMY (STREAMPROC*)0 // "dummy" stream -#define STREAMPROC_PUSH (STREAMPROC*)-1 // push stream -#define STREAMPROC_DEVICE (STREAMPROC*)-2 // device mix stream +#define STREAMPROC_DUMMY (STREAMPROC *)0 // "dummy" stream +#define STREAMPROC_PUSH (STREAMPROC *)-1 // push stream +#define STREAMPROC_DEVICE (STREAMPROC *)-2 // device mix stream // BASS_StreamCreateFileUser file systems -#define STREAMFILE_NOBUFFER 0 -#define STREAMFILE_BUFFER 1 -#define STREAMFILE_BUFFERPUSH 2 +#define STREAMFILE_NOBUFFER 0 +#define STREAMFILE_BUFFER 1 +#define STREAMFILE_BUFFERPUSH 2 // User file stream callback functions -typedef void (CALLBACK FILECLOSEPROC)(void *user); -typedef QWORD (CALLBACK FILELENPROC)(void *user); -typedef DWORD (CALLBACK FILEREADPROC)(void *buffer, DWORD length, void *user); -typedef BOOL (CALLBACK FILESEEKPROC)(QWORD offset, void *user); +typedef void(CALLBACK FILECLOSEPROC)(void *user); +typedef QWORD(CALLBACK FILELENPROC)(void *user); +typedef DWORD(CALLBACK FILEREADPROC)(void *buffer, DWORD length, void *user); +typedef BOOL(CALLBACK FILESEEKPROC)(QWORD offset, void *user); typedef struct { - FILECLOSEPROC *close; - FILELENPROC *length; - FILEREADPROC *read; - FILESEEKPROC *seek; + FILECLOSEPROC *close; + FILELENPROC *length; + FILEREADPROC *read; + FILESEEKPROC *seek; } BASS_FILEPROCS; // BASS_StreamPutFileData options -#define BASS_FILEDATA_END 0 // end & close the file +#define BASS_FILEDATA_END 0 // end & close the file // BASS_StreamGetFilePosition modes -#define BASS_FILEPOS_CURRENT 0 -#define BASS_FILEPOS_DECODE BASS_FILEPOS_CURRENT -#define BASS_FILEPOS_DOWNLOAD 1 -#define BASS_FILEPOS_END 2 -#define BASS_FILEPOS_START 3 -#define BASS_FILEPOS_CONNECTED 4 -#define BASS_FILEPOS_BUFFER 5 -#define BASS_FILEPOS_SOCKET 6 -#define BASS_FILEPOS_ASYNCBUF 7 -#define BASS_FILEPOS_SIZE 8 -#define BASS_FILEPOS_BUFFERING 9 +#define BASS_FILEPOS_CURRENT 0 +#define BASS_FILEPOS_DECODE BASS_FILEPOS_CURRENT +#define BASS_FILEPOS_DOWNLOAD 1 +#define BASS_FILEPOS_END 2 +#define BASS_FILEPOS_START 3 +#define BASS_FILEPOS_CONNECTED 4 +#define BASS_FILEPOS_BUFFER 5 +#define BASS_FILEPOS_SOCKET 6 +#define BASS_FILEPOS_ASYNCBUF 7 +#define BASS_FILEPOS_SIZE 8 +#define BASS_FILEPOS_BUFFERING 9 -typedef void (CALLBACK DOWNLOADPROC)(const void *buffer, DWORD length, void *user); +typedef void(CALLBACK DOWNLOADPROC)(const void *buffer, DWORD length, + void *user); /* Internet stream download callback function. buffer : Buffer containing the downloaded data... NULL=end of download length : Number of bytes in the buffer user : The 'user' parameter value given when calling BASS_StreamCreateURL */ // BASS_ChannelSetSync types -#define BASS_SYNC_POS 0 -#define BASS_SYNC_END 2 -#define BASS_SYNC_META 4 -#define BASS_SYNC_SLIDE 5 -#define BASS_SYNC_STALL 6 -#define BASS_SYNC_DOWNLOAD 7 -#define BASS_SYNC_FREE 8 -#define BASS_SYNC_SETPOS 11 -#define BASS_SYNC_MUSICPOS 10 -#define BASS_SYNC_MUSICINST 1 -#define BASS_SYNC_MUSICFX 3 -#define BASS_SYNC_OGG_CHANGE 12 -#define BASS_SYNC_MIXTIME 0x40000000 // flag: sync at mixtime, else at playtime -#define BASS_SYNC_ONETIME 0x80000000 // flag: sync only once, else continuously +#define BASS_SYNC_POS 0 +#define BASS_SYNC_END 2 +#define BASS_SYNC_META 4 +#define BASS_SYNC_SLIDE 5 +#define BASS_SYNC_STALL 6 +#define BASS_SYNC_DOWNLOAD 7 +#define BASS_SYNC_FREE 8 +#define BASS_SYNC_SETPOS 11 +#define BASS_SYNC_MUSICPOS 10 +#define BASS_SYNC_MUSICINST 1 +#define BASS_SYNC_MUSICFX 3 +#define BASS_SYNC_OGG_CHANGE 12 +#define BASS_SYNC_MIXTIME 0x40000000 // flag: sync at mixtime, else at playtime +#define BASS_SYNC_ONETIME 0x80000000 // flag: sync only once, else continuously -typedef void (CALLBACK SYNCPROC)(HSYNC handle, DWORD channel, DWORD data, void *user); +typedef void(CALLBACK SYNCPROC)(HSYNC handle, DWORD channel, DWORD data, + void *user); /* Sync callback function. NOTE: a sync callback function should be very quick as other syncs can't be processed until it has finished. If the sync is a "mixtime" sync, then other streams and MOD musics can't be mixed until @@ -574,7 +598,8 @@ channel: Channel that the sync occured in data : Additional data associated with the sync's occurance user : The 'user' parameter given when calling BASS_ChannelSetSync */ -typedef void (CALLBACK DSPPROC)(HDSP handle, DWORD channel, void *buffer, DWORD length, void *user); +typedef void(CALLBACK DSPPROC)(HDSP handle, DWORD channel, void *buffer, + DWORD length, void *user); /* DSP callback function. NOTE: A DSP function should obviously be as quick as possible... other DSP functions, streams and MOD musics can not be processed until it's finished. @@ -584,7 +609,8 @@ buffer : Buffer to apply the DSP to length : Number of bytes in the buffer user : The 'user' parameter given when calling BASS_ChannelSetDSP */ -typedef BOOL (CALLBACK RECORDPROC)(HRECORD handle, const void *buffer, DWORD length, void *user); +typedef BOOL(CALLBACK RECORDPROC)(HRECORD handle, const void *buffer, + DWORD length, void *user); /* Recording callback function. handle : The recording handle buffer : Buffer containing the recorded sample data @@ -593,394 +619,398 @@ user : The 'user' parameter value given when calling BASS_RecordStart RETURN : TRUE = continue recording, FALSE = stop */ // BASS_ChannelIsActive return values -#define BASS_ACTIVE_STOPPED 0 -#define BASS_ACTIVE_PLAYING 1 -#define BASS_ACTIVE_STALLED 2 -#define BASS_ACTIVE_PAUSED 3 +#define BASS_ACTIVE_STOPPED 0 +#define BASS_ACTIVE_PLAYING 1 +#define BASS_ACTIVE_STALLED 2 +#define BASS_ACTIVE_PAUSED 3 // Channel attributes -#define BASS_ATTRIB_FREQ 1 -#define BASS_ATTRIB_VOL 2 -#define BASS_ATTRIB_PAN 3 -#define BASS_ATTRIB_EAXMIX 4 -#define BASS_ATTRIB_NOBUFFER 5 -#define BASS_ATTRIB_VBR 6 -#define BASS_ATTRIB_CPU 7 -#define BASS_ATTRIB_SRC 8 -#define BASS_ATTRIB_NET_RESUME 9 -#define BASS_ATTRIB_SCANINFO 10 -#define BASS_ATTRIB_NORAMP 11 -#define BASS_ATTRIB_BITRATE 12 -#define BASS_ATTRIB_BUFFER 13 -#define BASS_ATTRIB_MUSIC_AMPLIFY 0x100 -#define BASS_ATTRIB_MUSIC_PANSEP 0x101 -#define BASS_ATTRIB_MUSIC_PSCALER 0x102 -#define BASS_ATTRIB_MUSIC_BPM 0x103 -#define BASS_ATTRIB_MUSIC_SPEED 0x104 +#define BASS_ATTRIB_FREQ 1 +#define BASS_ATTRIB_VOL 2 +#define BASS_ATTRIB_PAN 3 +#define BASS_ATTRIB_EAXMIX 4 +#define BASS_ATTRIB_NOBUFFER 5 +#define BASS_ATTRIB_VBR 6 +#define BASS_ATTRIB_CPU 7 +#define BASS_ATTRIB_SRC 8 +#define BASS_ATTRIB_NET_RESUME 9 +#define BASS_ATTRIB_SCANINFO 10 +#define BASS_ATTRIB_NORAMP 11 +#define BASS_ATTRIB_BITRATE 12 +#define BASS_ATTRIB_BUFFER 13 +#define BASS_ATTRIB_MUSIC_AMPLIFY 0x100 +#define BASS_ATTRIB_MUSIC_PANSEP 0x101 +#define BASS_ATTRIB_MUSIC_PSCALER 0x102 +#define BASS_ATTRIB_MUSIC_BPM 0x103 +#define BASS_ATTRIB_MUSIC_SPEED 0x104 #define BASS_ATTRIB_MUSIC_VOL_GLOBAL 0x105 -#define BASS_ATTRIB_MUSIC_ACTIVE 0x106 -#define BASS_ATTRIB_MUSIC_VOL_CHAN 0x200 // + channel # -#define BASS_ATTRIB_MUSIC_VOL_INST 0x300 // + instrument # +#define BASS_ATTRIB_MUSIC_ACTIVE 0x106 +#define BASS_ATTRIB_MUSIC_VOL_CHAN 0x200 // + channel # +#define BASS_ATTRIB_MUSIC_VOL_INST 0x300 // + instrument # // BASS_ChannelSlideAttribute flags -#define BASS_SLIDE_LOG 0x1000000 +#define BASS_SLIDE_LOG 0x1000000 // BASS_ChannelGetData flags -#define BASS_DATA_AVAILABLE 0 // query how much data is buffered -#define BASS_DATA_FIXED 0x20000000 // flag: return 8.24 fixed-point data -#define BASS_DATA_FLOAT 0x40000000 // flag: return floating-point sample data -#define BASS_DATA_FFT256 0x80000000 // 256 sample FFT -#define BASS_DATA_FFT512 0x80000001 // 512 FFT -#define BASS_DATA_FFT1024 0x80000002 // 1024 FFT -#define BASS_DATA_FFT2048 0x80000003 // 2048 FFT -#define BASS_DATA_FFT4096 0x80000004 // 4096 FFT -#define BASS_DATA_FFT8192 0x80000005 // 8192 FFT -#define BASS_DATA_FFT16384 0x80000006 // 16384 FFT -#define BASS_DATA_FFT32768 0x80000007 // 32768 FFT -#define BASS_DATA_FFT_INDIVIDUAL 0x10 // FFT flag: FFT for each channel, else all combined -#define BASS_DATA_FFT_NOWINDOW 0x20 // FFT flag: no Hanning window -#define BASS_DATA_FFT_REMOVEDC 0x40 // FFT flag: pre-remove DC bias -#define BASS_DATA_FFT_COMPLEX 0x80 // FFT flag: return complex data +#define BASS_DATA_AVAILABLE 0 // query how much data is buffered +#define BASS_DATA_FIXED 0x20000000 // flag: return 8.24 fixed-point data +#define BASS_DATA_FLOAT 0x40000000 // flag: return floating-point sample data +#define BASS_DATA_FFT256 0x80000000 // 256 sample FFT +#define BASS_DATA_FFT512 0x80000001 // 512 FFT +#define BASS_DATA_FFT1024 0x80000002 // 1024 FFT +#define BASS_DATA_FFT2048 0x80000003 // 2048 FFT +#define BASS_DATA_FFT4096 0x80000004 // 4096 FFT +#define BASS_DATA_FFT8192 0x80000005 // 8192 FFT +#define BASS_DATA_FFT16384 0x80000006 // 16384 FFT +#define BASS_DATA_FFT32768 0x80000007 // 32768 FFT +#define BASS_DATA_FFT_INDIVIDUAL \ + 0x10 // FFT flag: FFT for each channel, else all combined +#define BASS_DATA_FFT_NOWINDOW 0x20 // FFT flag: no Hanning window +#define BASS_DATA_FFT_REMOVEDC 0x40 // FFT flag: pre-remove DC bias +#define BASS_DATA_FFT_COMPLEX 0x80 // FFT flag: return complex data // BASS_ChannelGetLevelEx flags -#define BASS_LEVEL_MONO 1 -#define BASS_LEVEL_STEREO 2 -#define BASS_LEVEL_RMS 4 -#define BASS_LEVEL_VOLPAN 8 +#define BASS_LEVEL_MONO 1 +#define BASS_LEVEL_STEREO 2 +#define BASS_LEVEL_RMS 4 +#define BASS_LEVEL_VOLPAN 8 // BASS_ChannelGetTags types : what's returned -#define BASS_TAG_ID3 0 // ID3v1 tags : TAG_ID3 structure -#define BASS_TAG_ID3V2 1 // ID3v2 tags : variable length block -#define BASS_TAG_OGG 2 // OGG comments : series of null-terminated UTF-8 strings -#define BASS_TAG_HTTP 3 // HTTP headers : series of null-terminated ANSI strings -#define BASS_TAG_ICY 4 // ICY headers : series of null-terminated ANSI strings -#define BASS_TAG_META 5 // ICY metadata : ANSI string -#define BASS_TAG_APE 6 // APE tags : series of null-terminated UTF-8 strings -#define BASS_TAG_MP4 7 // MP4/iTunes metadata : series of null-terminated UTF-8 strings -#define BASS_TAG_WMA 8 // WMA tags : series of null-terminated UTF-8 strings -#define BASS_TAG_VENDOR 9 // OGG encoder : UTF-8 string -#define BASS_TAG_LYRICS3 10 // Lyric3v2 tag : ASCII string -#define BASS_TAG_CA_CODEC 11 // CoreAudio codec info : TAG_CA_CODEC structure -#define BASS_TAG_MF 13 // Media Foundation tags : series of null-terminated UTF-8 strings -#define BASS_TAG_WAVEFORMAT 14 // WAVE format : WAVEFORMATEEX structure -#define BASS_TAG_AM_MIME 15 // Android Media MIME type : ASCII string -#define BASS_TAG_AM_NAME 16 // Android Media codec name : ASCII string -#define BASS_TAG_RIFF_INFO 0x100 // RIFF "INFO" tags : series of null-terminated ANSI strings -#define BASS_TAG_RIFF_BEXT 0x101 // RIFF/BWF "bext" tags : TAG_BEXT structure -#define BASS_TAG_RIFF_CART 0x102 // RIFF/BWF "cart" tags : TAG_CART structure -#define BASS_TAG_RIFF_DISP 0x103 // RIFF "DISP" text tag : ANSI string -#define BASS_TAG_RIFF_CUE 0x104 // RIFF "cue " chunk : TAG_CUE structure -#define BASS_TAG_RIFF_SMPL 0x105 // RIFF "smpl" chunk : TAG_SMPL structure -#define BASS_TAG_APE_BINARY 0x1000 // + index #, binary APE tag : TAG_APE_BINARY structure -#define BASS_TAG_MUSIC_NAME 0x10000 // MOD music name : ANSI string -#define BASS_TAG_MUSIC_MESSAGE 0x10001 // MOD message : ANSI string -#define BASS_TAG_MUSIC_ORDERS 0x10002 // MOD order list : BYTE array of pattern numbers -#define BASS_TAG_MUSIC_AUTH 0x10003 // MOD author : UTF-8 string -#define BASS_TAG_MUSIC_INST 0x10100 // + instrument #, MOD instrument name : ANSI string -#define BASS_TAG_MUSIC_SAMPLE 0x10300 // + sample #, MOD sample name : ANSI string - +#define BASS_TAG_ID3 0 // ID3v1 tags : TAG_ID3 structure +#define BASS_TAG_ID3V2 1 // ID3v2 tags : variable length block +#define BASS_TAG_OGG 2 // OGG comments : series of null-terminated UTF-8 strings +#define BASS_TAG_HTTP 3 // HTTP headers : series of null-terminated ANSI strings +#define BASS_TAG_ICY 4 // ICY headers : series of null-terminated ANSI strings +#define BASS_TAG_META 5 // ICY metadata : ANSI string +#define BASS_TAG_APE 6 // APE tags : series of null-terminated UTF-8 strings +#define BASS_TAG_MP4 \ + 7 // MP4/iTunes metadata : series of null-terminated UTF-8 strings +#define BASS_TAG_WMA 8 // WMA tags : series of null-terminated UTF-8 strings +#define BASS_TAG_VENDOR 9 // OGG encoder : UTF-8 string +#define BASS_TAG_LYRICS3 10 // Lyric3v2 tag : ASCII string +#define BASS_TAG_CA_CODEC 11 // CoreAudio codec info : TAG_CA_CODEC structure +#define BASS_TAG_MF \ + 13 // Media Foundation tags : series of null-terminated UTF-8 strings +#define BASS_TAG_WAVEFORMAT 14 // WAVE format : WAVEFORMATEEX structure +#define BASS_TAG_AM_MIME 15 // Android Media MIME type : ASCII string +#define BASS_TAG_AM_NAME 16 // Android Media codec name : ASCII string +#define BASS_TAG_RIFF_INFO \ + 0x100 // RIFF "INFO" tags : series of null-terminated ANSI strings +#define BASS_TAG_RIFF_BEXT 0x101 // RIFF/BWF "bext" tags : TAG_BEXT structure +#define BASS_TAG_RIFF_CART 0x102 // RIFF/BWF "cart" tags : TAG_CART structure +#define BASS_TAG_RIFF_DISP 0x103 // RIFF "DISP" text tag : ANSI string +#define BASS_TAG_RIFF_CUE 0x104 // RIFF "cue " chunk : TAG_CUE structure +#define BASS_TAG_RIFF_SMPL 0x105 // RIFF "smpl" chunk : TAG_SMPL structure +#define BASS_TAG_APE_BINARY \ + 0x1000 // + index #, binary APE tag : TAG_APE_BINARY structure +#define BASS_TAG_MUSIC_NAME 0x10000 // MOD music name : ANSI string +#define BASS_TAG_MUSIC_MESSAGE 0x10001 // MOD message : ANSI string +#define BASS_TAG_MUSIC_ORDERS \ + 0x10002 // MOD order list : BYTE array of pattern numbers +#define BASS_TAG_MUSIC_AUTH 0x10003 // MOD author : UTF-8 string +#define BASS_TAG_MUSIC_INST \ + 0x10100 // + instrument #, MOD instrument name : ANSI string +#define BASS_TAG_MUSIC_SAMPLE \ + 0x10300 // + sample #, MOD sample name : ANSI string + // ID3v1 tag structure typedef struct { - char id[3]; - char title[30]; - char artist[30]; - char album[30]; - char year[4]; - char comment[30]; - BYTE genre; + char id[3]; + char title[30]; + char artist[30]; + char album[30]; + char year[4]; + char comment[30]; + BYTE genre; } TAG_ID3; - + // Binary APE tag structure -typedef struct { - const char *key; - const void *data; - DWORD length; -} TAG_APE_BINARY; - -// BWF "bext" tag structure +typedef struct { + const char *key; + const void *data; + DWORD length; +} TAG_APE_BINARY; + +// BWF "bext" tag structure #ifdef _MSC_VER #pragma warning(push) -#pragma warning(disable:4200) +#pragma warning(disable : 4200) #endif -#pragma pack(push,1) +#pragma pack(push, 1) typedef struct { - char Description[256]; // description - char Originator[32]; // name of the originator - char OriginatorReference[32]; // reference of the originator - char OriginationDate[10]; // date of creation (yyyy-mm-dd) - char OriginationTime[8]; // time of creation (hh-mm-ss) - QWORD TimeReference; // first sample count since midnight (little-endian) - WORD Version; // BWF version (little-endian) - BYTE UMID[64]; // SMPTE UMID - BYTE Reserved[190]; -#if defined(__GNUC__) && __GNUC__<3 - char CodingHistory[0]; // history -#elif 1 // change to 0 if compiler fails the following line - char CodingHistory[]; // history + char Description[256]; // description + char Originator[32]; // name of the originator + char OriginatorReference[32]; // reference of the originator + char OriginationDate[10]; // date of creation (yyyy-mm-dd) + char OriginationTime[8]; // time of creation (hh-mm-ss) + QWORD TimeReference; // first sample count since midnight (little-endian) + WORD Version; // BWF version (little-endian) + BYTE UMID[64]; // SMPTE UMID + BYTE Reserved[190]; +#if defined(__GNUC__) && __GNUC__ < 3 + char CodingHistory[0]; // history +#elif 1 // change to 0 if compiler fails the following line + char CodingHistory[]; // history #else - char CodingHistory[1]; // history + char CodingHistory[1]; // history #endif } TAG_BEXT; -#pragma pack(pop) - -// BWF "cart" tag structures -typedef struct -{ - DWORD dwUsage; // FOURCC timer usage ID - DWORD dwValue; // timer value in samples from head -} TAG_CART_TIMER; - -typedef struct -{ - char Version[4]; // version of the data structure - char Title[64]; // title of cart audio sequence - char Artist[64]; // artist or creator name - char CutID[64]; // cut number identification - char ClientID[64]; // client identification - char Category[64]; // category ID, PSA, NEWS, etc - char Classification[64]; // classification or auxiliary key - char OutCue[64]; // out cue text - char StartDate[10]; // yyyy-mm-dd - char StartTime[8]; // hh:mm:ss - char EndDate[10]; // yyyy-mm-dd - char EndTime[8]; // hh:mm:ss - char ProducerAppID[64]; // name of vendor or application - char ProducerAppVersion[64]; // version of producer application - char UserDef[64]; // user defined text - DWORD dwLevelReference; // sample value for 0 dB reference - TAG_CART_TIMER PostTimer[8]; // 8 time markers after head - char Reserved[276]; - char URL[1024]; // uniform resource locator -#if defined(__GNUC__) && __GNUC__<3 - char TagText[0]; // free form text for scripts or tags -#elif 1 // change to 0 if compiler fails the following line - char TagText[]; // free form text for scripts or tags -#else - char TagText[1]; // free form text for scripts or tags -#endif -} TAG_CART; - -// RIFF "cue " tag structures -typedef struct -{ - DWORD dwName; - DWORD dwPosition; - DWORD fccChunk; - DWORD dwChunkStart; - DWORD dwBlockStart; - DWORD dwSampleOffset; -} TAG_CUE_POINT; - -typedef struct -{ - DWORD dwCuePoints; -#if defined(__GNUC__) && __GNUC__<3 - TAG_CUE_POINT CuePoints[0]; -#elif 1 // change to 0 if compiler fails the following line - TAG_CUE_POINT CuePoints[]; -#else - TAG_CUE_POINT CuePoints[1]; -#endif -} TAG_CUE; - -// RIFF "smpl" tag structures -typedef struct -{ - DWORD dwIdentifier; - DWORD dwType; - DWORD dwStart; - DWORD dwEnd; - DWORD dwFraction; - DWORD dwPlayCount; -} TAG_SMPL_LOOP; - -typedef struct -{ - DWORD dwManufacturer; - DWORD dwProduct; - DWORD dwSamplePeriod; - DWORD dwMIDIUnityNote; - DWORD dwMIDIPitchFraction; - DWORD dwSMPTEFormat; - DWORD dwSMPTEOffset; - DWORD cSampleLoops; - DWORD cbSamplerData; -#if defined(__GNUC__) && __GNUC__<3 - TAG_SMPL_LOOP SampleLoops[0]; -#elif 1 // change to 0 if compiler fails the following line - TAG_SMPL_LOOP SampleLoops[]; -#else - TAG_SMPL_LOOP SampleLoops[1]; -#endif -} TAG_SMPL; -#ifdef _MSC_VER -#pragma warning(pop) -#endif - +#pragma pack(pop) + +// BWF "cart" tag structures +typedef struct { + DWORD dwUsage; // FOURCC timer usage ID + DWORD dwValue; // timer value in samples from head +} TAG_CART_TIMER; + +typedef struct { + char Version[4]; // version of the data structure + char Title[64]; // title of cart audio sequence + char Artist[64]; // artist or creator name + char CutID[64]; // cut number identification + char ClientID[64]; // client identification + char Category[64]; // category ID, PSA, NEWS, etc + char Classification[64]; // classification or auxiliary key + char OutCue[64]; // out cue text + char StartDate[10]; // yyyy-mm-dd + char StartTime[8]; // hh:mm:ss + char EndDate[10]; // yyyy-mm-dd + char EndTime[8]; // hh:mm:ss + char ProducerAppID[64]; // name of vendor or application + char ProducerAppVersion[64]; // version of producer application + char UserDef[64]; // user defined text + DWORD dwLevelReference; // sample value for 0 dB reference + TAG_CART_TIMER PostTimer[8]; // 8 time markers after head + char Reserved[276]; + char URL[1024]; // uniform resource locator +#if defined(__GNUC__) && __GNUC__ < 3 + char TagText[0]; // free form text for scripts or tags +#elif 1 // change to 0 if compiler fails the following line + char TagText[]; // free form text for scripts or tags +#else + char TagText[1]; // free form text for scripts or tags +#endif +} TAG_CART; + +// RIFF "cue " tag structures +typedef struct { + DWORD dwName; + DWORD dwPosition; + DWORD fccChunk; + DWORD dwChunkStart; + DWORD dwBlockStart; + DWORD dwSampleOffset; +} TAG_CUE_POINT; + +typedef struct { + DWORD dwCuePoints; +#if defined(__GNUC__) && __GNUC__ < 3 + TAG_CUE_POINT CuePoints[0]; +#elif 1 // change to 0 if compiler fails the following line + TAG_CUE_POINT CuePoints[]; +#else + TAG_CUE_POINT CuePoints[1]; +#endif +} TAG_CUE; + +// RIFF "smpl" tag structures +typedef struct { + DWORD dwIdentifier; + DWORD dwType; + DWORD dwStart; + DWORD dwEnd; + DWORD dwFraction; + DWORD dwPlayCount; +} TAG_SMPL_LOOP; + +typedef struct { + DWORD dwManufacturer; + DWORD dwProduct; + DWORD dwSamplePeriod; + DWORD dwMIDIUnityNote; + DWORD dwMIDIPitchFraction; + DWORD dwSMPTEFormat; + DWORD dwSMPTEOffset; + DWORD cSampleLoops; + DWORD cbSamplerData; +#if defined(__GNUC__) && __GNUC__ < 3 + TAG_SMPL_LOOP SampleLoops[0]; +#elif 1 // change to 0 if compiler fails the following line + TAG_SMPL_LOOP SampleLoops[]; +#else + TAG_SMPL_LOOP SampleLoops[1]; +#endif +} TAG_SMPL; +#ifdef _MSC_VER +#pragma warning(pop) +#endif + // CoreAudio codec info structure typedef struct { - DWORD ftype; // file format - DWORD atype; // audio format - const char *name; // description + DWORD ftype; // file format + DWORD atype; // audio format + const char *name; // description } TAG_CA_CODEC; -#ifndef _WAVEFORMATEX_ -#define _WAVEFORMATEX_ -#pragma pack(push,1) -typedef struct tWAVEFORMATEX -{ - WORD wFormatTag; - WORD nChannels; - DWORD nSamplesPerSec; - DWORD nAvgBytesPerSec; - WORD nBlockAlign; - WORD wBitsPerSample; - WORD cbSize; -} WAVEFORMATEX, *PWAVEFORMATEX, *LPWAVEFORMATEX; -typedef const WAVEFORMATEX *LPCWAVEFORMATEX; -#pragma pack(pop) -#endif - +#ifndef _WAVEFORMATEX_ +#define _WAVEFORMATEX_ +#pragma pack(push, 1) +typedef struct tWAVEFORMATEX { + WORD wFormatTag; + WORD nChannels; + DWORD nSamplesPerSec; + DWORD nAvgBytesPerSec; + WORD nBlockAlign; + WORD wBitsPerSample; + WORD cbSize; +} WAVEFORMATEX, *PWAVEFORMATEX, *LPWAVEFORMATEX; +typedef const WAVEFORMATEX *LPCWAVEFORMATEX; +#pragma pack(pop) +#endif + // BASS_ChannelGetLength/GetPosition/SetPosition modes -#define BASS_POS_BYTE 0 // byte position -#define BASS_POS_MUSIC_ORDER 1 // order.row position, MAKELONG(order,row) -#define BASS_POS_OGG 3 // OGG bitstream number -#define BASS_POS_RESET 0x2000000 // flag: reset user file buffers -#define BASS_POS_RELATIVE 0x4000000 // flag: seek relative to the current position -#define BASS_POS_INEXACT 0x8000000 // flag: allow seeking to inexact position -#define BASS_POS_DECODE 0x10000000 // flag: get the decoding (not playing) position -#define BASS_POS_DECODETO 0x20000000 // flag: decode to the position instead of seeking -#define BASS_POS_SCAN 0x40000000 // flag: scan to the position +#define BASS_POS_BYTE 0 // byte position +#define BASS_POS_MUSIC_ORDER 1 // order.row position, MAKELONG(order,row) +#define BASS_POS_OGG 3 // OGG bitstream number +#define BASS_POS_RESET 0x2000000 // flag: reset user file buffers +#define BASS_POS_RELATIVE \ + 0x4000000 // flag: seek relative to the current position +#define BASS_POS_INEXACT 0x8000000 // flag: allow seeking to inexact position +#define BASS_POS_DECODE \ + 0x10000000 // flag: get the decoding (not playing) position +#define BASS_POS_DECODETO \ + 0x20000000 // flag: decode to the position instead of seeking +#define BASS_POS_SCAN 0x40000000 // flag: scan to the position // BASS_ChannelSetDevice/GetDevice option -#define BASS_NODEVICE 0x20000 +#define BASS_NODEVICE 0x20000 // BASS_RecordSetInput flags -#define BASS_INPUT_OFF 0x10000 -#define BASS_INPUT_ON 0x20000 +#define BASS_INPUT_OFF 0x10000 +#define BASS_INPUT_ON 0x20000 -#define BASS_INPUT_TYPE_MASK 0xff000000 -#define BASS_INPUT_TYPE_UNDEF 0x00000000 -#define BASS_INPUT_TYPE_DIGITAL 0x01000000 -#define BASS_INPUT_TYPE_LINE 0x02000000 -#define BASS_INPUT_TYPE_MIC 0x03000000 -#define BASS_INPUT_TYPE_SYNTH 0x04000000 -#define BASS_INPUT_TYPE_CD 0x05000000 -#define BASS_INPUT_TYPE_PHONE 0x06000000 -#define BASS_INPUT_TYPE_SPEAKER 0x07000000 -#define BASS_INPUT_TYPE_WAVE 0x08000000 -#define BASS_INPUT_TYPE_AUX 0x09000000 -#define BASS_INPUT_TYPE_ANALOG 0x0a000000 +#define BASS_INPUT_TYPE_MASK 0xff000000 +#define BASS_INPUT_TYPE_UNDEF 0x00000000 +#define BASS_INPUT_TYPE_DIGITAL 0x01000000 +#define BASS_INPUT_TYPE_LINE 0x02000000 +#define BASS_INPUT_TYPE_MIC 0x03000000 +#define BASS_INPUT_TYPE_SYNTH 0x04000000 +#define BASS_INPUT_TYPE_CD 0x05000000 +#define BASS_INPUT_TYPE_PHONE 0x06000000 +#define BASS_INPUT_TYPE_SPEAKER 0x07000000 +#define BASS_INPUT_TYPE_WAVE 0x08000000 +#define BASS_INPUT_TYPE_AUX 0x09000000 +#define BASS_INPUT_TYPE_ANALOG 0x0a000000 // BASS_ChannelSetFX effect types -#define BASS_FX_DX8_CHORUS 0 -#define BASS_FX_DX8_COMPRESSOR 1 -#define BASS_FX_DX8_DISTORTION 2 -#define BASS_FX_DX8_ECHO 3 -#define BASS_FX_DX8_FLANGER 4 -#define BASS_FX_DX8_GARGLE 5 -#define BASS_FX_DX8_I3DL2REVERB 6 -#define BASS_FX_DX8_PARAMEQ 7 -#define BASS_FX_DX8_REVERB 8 -#define BASS_FX_VOLUME 9 +#define BASS_FX_DX8_CHORUS 0 +#define BASS_FX_DX8_COMPRESSOR 1 +#define BASS_FX_DX8_DISTORTION 2 +#define BASS_FX_DX8_ECHO 3 +#define BASS_FX_DX8_FLANGER 4 +#define BASS_FX_DX8_GARGLE 5 +#define BASS_FX_DX8_I3DL2REVERB 6 +#define BASS_FX_DX8_PARAMEQ 7 +#define BASS_FX_DX8_REVERB 8 +#define BASS_FX_VOLUME 9 typedef struct { - float fWetDryMix; - float fDepth; - float fFeedback; - float fFrequency; - DWORD lWaveform; // 0=triangle, 1=sine - float fDelay; - DWORD lPhase; // BASS_DX8_PHASE_xxx + float fWetDryMix; + float fDepth; + float fFeedback; + float fFrequency; + DWORD lWaveform; // 0=triangle, 1=sine + float fDelay; + DWORD lPhase; // BASS_DX8_PHASE_xxx } BASS_DX8_CHORUS; typedef struct { - float fGain; - float fAttack; - float fRelease; - float fThreshold; - float fRatio; - float fPredelay; + float fGain; + float fAttack; + float fRelease; + float fThreshold; + float fRatio; + float fPredelay; } BASS_DX8_COMPRESSOR; typedef struct { - float fGain; - float fEdge; - float fPostEQCenterFrequency; - float fPostEQBandwidth; - float fPreLowpassCutoff; + float fGain; + float fEdge; + float fPostEQCenterFrequency; + float fPostEQBandwidth; + float fPreLowpassCutoff; } BASS_DX8_DISTORTION; typedef struct { - float fWetDryMix; - float fFeedback; - float fLeftDelay; - float fRightDelay; - BOOL lPanDelay; + float fWetDryMix; + float fFeedback; + float fLeftDelay; + float fRightDelay; + BOOL lPanDelay; } BASS_DX8_ECHO; typedef struct { - float fWetDryMix; - float fDepth; - float fFeedback; - float fFrequency; - DWORD lWaveform; // 0=triangle, 1=sine - float fDelay; - DWORD lPhase; // BASS_DX8_PHASE_xxx + float fWetDryMix; + float fDepth; + float fFeedback; + float fFrequency; + DWORD lWaveform; // 0=triangle, 1=sine + float fDelay; + DWORD lPhase; // BASS_DX8_PHASE_xxx } BASS_DX8_FLANGER; typedef struct { - DWORD dwRateHz; // Rate of modulation in hz - DWORD dwWaveShape; // 0=triangle, 1=square + DWORD dwRateHz; // Rate of modulation in hz + DWORD dwWaveShape; // 0=triangle, 1=square } BASS_DX8_GARGLE; typedef struct { - int lRoom; // [-10000, 0] default: -1000 mB - int lRoomHF; // [-10000, 0] default: 0 mB - float flRoomRolloffFactor; // [0.0, 10.0] default: 0.0 - float flDecayTime; // [0.1, 20.0] default: 1.49s - float flDecayHFRatio; // [0.1, 2.0] default: 0.83 - int lReflections; // [-10000, 1000] default: -2602 mB - float flReflectionsDelay; // [0.0, 0.3] default: 0.007 s - int lReverb; // [-10000, 2000] default: 200 mB - float flReverbDelay; // [0.0, 0.1] default: 0.011 s - float flDiffusion; // [0.0, 100.0] default: 100.0 % - float flDensity; // [0.0, 100.0] default: 100.0 % - float flHFReference; // [20.0, 20000.0] default: 5000.0 Hz + int lRoom; // [-10000, 0] default: -1000 mB + int lRoomHF; // [-10000, 0] default: 0 mB + float flRoomRolloffFactor; // [0.0, 10.0] default: 0.0 + float flDecayTime; // [0.1, 20.0] default: 1.49s + float flDecayHFRatio; // [0.1, 2.0] default: 0.83 + int lReflections; // [-10000, 1000] default: -2602 mB + float flReflectionsDelay; // [0.0, 0.3] default: 0.007 s + int lReverb; // [-10000, 2000] default: 200 mB + float flReverbDelay; // [0.0, 0.1] default: 0.011 s + float flDiffusion; // [0.0, 100.0] default: 100.0 % + float flDensity; // [0.0, 100.0] default: 100.0 % + float flHFReference; // [20.0, 20000.0] default: 5000.0 Hz } BASS_DX8_I3DL2REVERB; typedef struct { - float fCenter; - float fBandwidth; - float fGain; + float fCenter; + float fBandwidth; + float fGain; } BASS_DX8_PARAMEQ; typedef struct { - float fInGain; // [-96.0,0.0] default: 0.0 dB - float fReverbMix; // [-96.0,0.0] default: 0.0 db - float fReverbTime; // [0.001,3000.0] default: 1000.0 ms - float fHighFreqRTRatio; // [0.001,0.999] default: 0.001 + float fInGain; // [-96.0,0.0] default: 0.0 dB + float fReverbMix; // [-96.0,0.0] default: 0.0 db + float fReverbTime; // [0.001,3000.0] default: 1000.0 ms + float fHighFreqRTRatio; // [0.001,0.999] default: 0.001 } BASS_DX8_REVERB; -#define BASS_DX8_PHASE_NEG_180 0 -#define BASS_DX8_PHASE_NEG_90 1 -#define BASS_DX8_PHASE_ZERO 2 -#define BASS_DX8_PHASE_90 3 -#define BASS_DX8_PHASE_180 4 - +#define BASS_DX8_PHASE_NEG_180 0 +#define BASS_DX8_PHASE_NEG_90 1 +#define BASS_DX8_PHASE_ZERO 2 +#define BASS_DX8_PHASE_90 3 +#define BASS_DX8_PHASE_180 4 + typedef struct { - float fTarget; - float fCurrent; - float fTime; - DWORD lCurve; + float fTarget; + float fCurrent; + float fTime; + DWORD lCurve; } BASS_FX_VOLUME_PARAM; - -typedef void (CALLBACK IOSNOTIFYPROC)(DWORD status); -/* iOS notification callback function. -status : The notification (BASS_IOSNOTIFY_xxx) */ - -#define BASS_IOSNOTIFY_INTERRUPT 1 // interruption started -#define BASS_IOSNOTIFY_INTERRUPT_END 2 // interruption ended + +typedef void(CALLBACK IOSNOTIFYPROC)(DWORD status); +/* iOS notification callback function. +status : The notification (BASS_IOSNOTIFY_xxx) */ + +#define BASS_IOSNOTIFY_INTERRUPT 1 // interruption started +#define BASS_IOSNOTIFY_INTERRUPT_END 2 // interruption ended BOOL BASSDEF(BASS_SetConfig)(DWORD option, DWORD value); DWORD BASSDEF(BASS_GetConfig)(DWORD option); @@ -989,15 +1019,19 @@ void *BASSDEF(BASS_GetConfigPtr)(DWORD option); DWORD BASSDEF(BASS_GetVersion)(); int BASSDEF(BASS_ErrorGetCode)(); BOOL BASSDEF(BASS_GetDeviceInfo)(DWORD device, BASS_DEVICEINFO *info); -#if defined(_WIN32) && !defined(_WIN32_WCE) && !(WINAPI_FAMILY && WINAPI_FAMILY!=WINAPI_FAMILY_DESKTOP_APP) -BOOL BASSDEF(BASS_Init)(int device, DWORD freq, DWORD flags, HWND win, const GUID *dsguid); +#if defined(_WIN32) && !defined(_WIN32_WCE) && \ + !(WINAPI_FAMILY && WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP) +BOOL BASSDEF(BASS_Init)(int device, DWORD freq, DWORD flags, HWND win, + const GUID *dsguid); #else -BOOL BASSDEF(BASS_Init)(int device, DWORD freq, DWORD flags, void *win, void *dsguid); +BOOL BASSDEF(BASS_Init)(int device, DWORD freq, DWORD flags, void *win, + void *dsguid); #endif BOOL BASSDEF(BASS_SetDevice)(DWORD device); DWORD BASSDEF(BASS_GetDevice)(); BOOL BASSDEF(BASS_Free)(); -#if defined(_WIN32) && !defined(_WIN32_WCE) && !(WINAPI_FAMILY && WINAPI_FAMILY!=WINAPI_FAMILY_DESKTOP_APP) +#if defined(_WIN32) && !defined(_WIN32_WCE) && \ + !(WINAPI_FAMILY && WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP) void *BASSDEF(BASS_GetDSoundObject)(DWORD object); #endif BOOL BASSDEF(BASS_GetInfo)(BASS_INFO *info); @@ -1015,19 +1049,29 @@ const BASS_PLUGININFO *BASSDEF(BASS_PluginGetInfo)(HPLUGIN handle); BOOL BASSDEF(BASS_Set3DFactors)(float distf, float rollf, float doppf); BOOL BASSDEF(BASS_Get3DFactors)(float *distf, float *rollf, float *doppf); -BOOL BASSDEF(BASS_Set3DPosition)(const BASS_3DVECTOR *pos, const BASS_3DVECTOR *vel, const BASS_3DVECTOR *front, const BASS_3DVECTOR *top); -BOOL BASSDEF(BASS_Get3DPosition)(BASS_3DVECTOR *pos, BASS_3DVECTOR *vel, BASS_3DVECTOR *front, BASS_3DVECTOR *top); +BOOL BASSDEF(BASS_Set3DPosition)(const BASS_3DVECTOR *pos, + const BASS_3DVECTOR *vel, + const BASS_3DVECTOR *front, + const BASS_3DVECTOR *top); +BOOL BASSDEF(BASS_Get3DPosition)(BASS_3DVECTOR *pos, BASS_3DVECTOR *vel, + BASS_3DVECTOR *front, BASS_3DVECTOR *top); void BASSDEF(BASS_Apply3D)(); -#if defined(_WIN32) && !defined(_WIN32_WCE) && !(WINAPI_FAMILY && WINAPI_FAMILY!=WINAPI_FAMILY_DESKTOP_APP) -BOOL BASSDEF(BASS_SetEAXParameters)(int env, float vol, float decay, float damp); -BOOL BASSDEF(BASS_GetEAXParameters)(DWORD *env, float *vol, float *decay, float *damp); +#if defined(_WIN32) && !defined(_WIN32_WCE) && \ + !(WINAPI_FAMILY && WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP) +BOOL BASSDEF(BASS_SetEAXParameters)(int env, float vol, float decay, + float damp); +BOOL BASSDEF(BASS_GetEAXParameters)(DWORD *env, float *vol, float *decay, + float *damp); #endif -HMUSIC BASSDEF(BASS_MusicLoad)(BOOL mem, const void *file, QWORD offset, DWORD length, DWORD flags, DWORD freq); +HMUSIC BASSDEF(BASS_MusicLoad)(BOOL mem, const void *file, QWORD offset, + DWORD length, DWORD flags, DWORD freq); BOOL BASSDEF(BASS_MusicFree)(HMUSIC handle); -HSAMPLE BASSDEF(BASS_SampleLoad)(BOOL mem, const void *file, QWORD offset, DWORD length, DWORD max, DWORD flags); -HSAMPLE BASSDEF(BASS_SampleCreate)(DWORD length, DWORD freq, DWORD chans, DWORD max, DWORD flags); +HSAMPLE BASSDEF(BASS_SampleLoad)(BOOL mem, const void *file, QWORD offset, + DWORD length, DWORD max, DWORD flags); +HSAMPLE BASSDEF(BASS_SampleCreate)(DWORD length, DWORD freq, DWORD chans, + DWORD max, DWORD flags); BOOL BASSDEF(BASS_SampleFree)(HSAMPLE handle); BOOL BASSDEF(BASS_SampleSetData)(HSAMPLE handle, const void *buffer); BOOL BASSDEF(BASS_SampleGetData)(HSAMPLE handle, void *buffer); @@ -1037,14 +1081,22 @@ HCHANNEL BASSDEF(BASS_SampleGetChannel)(HSAMPLE handle, BOOL onlynew); DWORD BASSDEF(BASS_SampleGetChannels)(HSAMPLE handle, HCHANNEL *channels); BOOL BASSDEF(BASS_SampleStop)(HSAMPLE handle); -HSTREAM BASSDEF(BASS_StreamCreate)(DWORD freq, DWORD chans, DWORD flags, STREAMPROC *proc, void *user); -HSTREAM BASSDEF(BASS_StreamCreateFile)(BOOL mem, const void *file, QWORD offset, QWORD length, DWORD flags); -HSTREAM BASSDEF(BASS_StreamCreateURL)(const char *url, DWORD offset, DWORD flags, DOWNLOADPROC *proc, void *user); -HSTREAM BASSDEF(BASS_StreamCreateFileUser)(DWORD system, DWORD flags, const BASS_FILEPROCS *proc, void *user); +HSTREAM BASSDEF(BASS_StreamCreate)(DWORD freq, DWORD chans, DWORD flags, + STREAMPROC *proc, void *user); +HSTREAM BASSDEF(BASS_StreamCreateFile)(BOOL mem, const void *file, QWORD offset, + QWORD length, DWORD flags); +HSTREAM BASSDEF(BASS_StreamCreateURL)(const char *url, DWORD offset, + DWORD flags, DOWNLOADPROC *proc, + void *user); +HSTREAM BASSDEF(BASS_StreamCreateFileUser)(DWORD system, DWORD flags, + const BASS_FILEPROCS *proc, + void *user); BOOL BASSDEF(BASS_StreamFree)(HSTREAM handle); QWORD BASSDEF(BASS_StreamGetFilePosition)(HSTREAM handle, DWORD mode); -DWORD BASSDEF(BASS_StreamPutData)(HSTREAM handle, const void *buffer, DWORD length); -DWORD BASSDEF(BASS_StreamPutFileData)(HSTREAM handle, const void *buffer, DWORD length); +DWORD BASSDEF(BASS_StreamPutData)(HSTREAM handle, const void *buffer, + DWORD length); +DWORD BASSDEF(BASS_StreamPutFileData)(HSTREAM handle, const void *buffer, + DWORD length); BOOL BASSDEF(BASS_RecordGetDeviceInfo)(DWORD device, BASS_DEVICEINFO *info); BOOL BASSDEF(BASS_RecordInit)(int device); @@ -1055,7 +1107,8 @@ BOOL BASSDEF(BASS_RecordGetInfo)(BASS_RECORDINFO *info); const char *BASSDEF(BASS_RecordGetInputName)(int input); BOOL BASSDEF(BASS_RecordSetInput)(int input, DWORD flags, float volume); DWORD BASSDEF(BASS_RecordGetInput)(int input, float *volume); -HRECORD BASSDEF(BASS_RecordStart)(DWORD freq, DWORD chans, DWORD flags, RECORDPROC *proc, void *user); +HRECORD BASSDEF(BASS_RecordStart)(DWORD freq, DWORD chans, DWORD flags, + RECORDPROC *proc, void *user); double BASSDEF(BASS_ChannelBytes2Seconds)(DWORD handle, QWORD pos); QWORD BASSDEF(BASS_ChannelSeconds2Bytes)(DWORD handle, double pos); @@ -1071,24 +1124,39 @@ BOOL BASSDEF(BASS_ChannelPlay)(DWORD handle, BOOL restart); BOOL BASSDEF(BASS_ChannelStop)(DWORD handle); BOOL BASSDEF(BASS_ChannelPause)(DWORD handle); BOOL BASSDEF(BASS_ChannelSetAttribute)(DWORD handle, DWORD attrib, float value); -BOOL BASSDEF(BASS_ChannelGetAttribute)(DWORD handle, DWORD attrib, float *value); -BOOL BASSDEF(BASS_ChannelSlideAttribute)(DWORD handle, DWORD attrib, float value, DWORD time); +BOOL BASSDEF(BASS_ChannelGetAttribute)(DWORD handle, DWORD attrib, + float *value); +BOOL BASSDEF(BASS_ChannelSlideAttribute)(DWORD handle, DWORD attrib, + float value, DWORD time); BOOL BASSDEF(BASS_ChannelIsSliding)(DWORD handle, DWORD attrib); -BOOL BASSDEF(BASS_ChannelSetAttributeEx)(DWORD handle, DWORD attrib, void *value, DWORD size); -DWORD BASSDEF(BASS_ChannelGetAttributeEx)(DWORD handle, DWORD attrib, void *value, DWORD size); -BOOL BASSDEF(BASS_ChannelSet3DAttributes)(DWORD handle, int mode, float min, float max, int iangle, int oangle, float outvol); -BOOL BASSDEF(BASS_ChannelGet3DAttributes)(DWORD handle, DWORD *mode, float *min, float *max, DWORD *iangle, DWORD *oangle, float *outvol); -BOOL BASSDEF(BASS_ChannelSet3DPosition)(DWORD handle, const BASS_3DVECTOR *pos, const BASS_3DVECTOR *orient, const BASS_3DVECTOR *vel); -BOOL BASSDEF(BASS_ChannelGet3DPosition)(DWORD handle, BASS_3DVECTOR *pos, BASS_3DVECTOR *orient, BASS_3DVECTOR *vel); +BOOL BASSDEF(BASS_ChannelSetAttributeEx)(DWORD handle, DWORD attrib, + void *value, DWORD size); +DWORD BASSDEF(BASS_ChannelGetAttributeEx)(DWORD handle, DWORD attrib, + void *value, DWORD size); +BOOL BASSDEF(BASS_ChannelSet3DAttributes)(DWORD handle, int mode, float min, + float max, int iangle, int oangle, + float outvol); +BOOL BASSDEF(BASS_ChannelGet3DAttributes)(DWORD handle, DWORD *mode, float *min, + float *max, DWORD *iangle, + DWORD *oangle, float *outvol); +BOOL BASSDEF(BASS_ChannelSet3DPosition)(DWORD handle, const BASS_3DVECTOR *pos, + const BASS_3DVECTOR *orient, + const BASS_3DVECTOR *vel); +BOOL BASSDEF(BASS_ChannelGet3DPosition)(DWORD handle, BASS_3DVECTOR *pos, + BASS_3DVECTOR *orient, + BASS_3DVECTOR *vel); QWORD BASSDEF(BASS_ChannelGetLength)(DWORD handle, DWORD mode); BOOL BASSDEF(BASS_ChannelSetPosition)(DWORD handle, QWORD pos, DWORD mode); QWORD BASSDEF(BASS_ChannelGetPosition)(DWORD handle, DWORD mode); DWORD BASSDEF(BASS_ChannelGetLevel)(DWORD handle); -BOOL BASSDEF(BASS_ChannelGetLevelEx)(DWORD handle, float *levels, float length, DWORD flags); +BOOL BASSDEF(BASS_ChannelGetLevelEx)(DWORD handle, float *levels, float length, + DWORD flags); DWORD BASSDEF(BASS_ChannelGetData)(DWORD handle, void *buffer, DWORD length); -HSYNC BASSDEF(BASS_ChannelSetSync)(DWORD handle, DWORD type, QWORD param, SYNCPROC *proc, void *user); +HSYNC BASSDEF(BASS_ChannelSetSync)(DWORD handle, DWORD type, QWORD param, + SYNCPROC *proc, void *user); BOOL BASSDEF(BASS_ChannelRemoveSync)(DWORD handle, HSYNC sync); -HDSP BASSDEF(BASS_ChannelSetDSP)(DWORD handle, DSPPROC *proc, void *user, int priority); +HDSP BASSDEF(BASS_ChannelSetDSP)(DWORD handle, DSPPROC *proc, void *user, + int priority); BOOL BASSDEF(BASS_ChannelRemoveDSP)(DWORD handle, HDSP dsp); BOOL BASSDEF(BASS_ChannelSetLink)(DWORD handle, DWORD chan); BOOL BASSDEF(BASS_ChannelRemoveLink)(DWORD handle, DWORD chan); @@ -1099,41 +1167,51 @@ BOOL BASSDEF(BASS_FXSetParameters)(HFX handle, const void *params); BOOL BASSDEF(BASS_FXGetParameters)(HFX handle, void *params); BOOL BASSDEF(BASS_FXReset)(HFX handle); BOOL BASSDEF(BASS_FXSetPriority)(HFX handle, int priority); - + #ifdef __cplusplus } - -#if defined(_WIN32) && !defined(NOBASSOVERLOADS) -static inline HPLUGIN BASS_PluginLoad(const WCHAR *file, DWORD flags) -{ - return BASS_PluginLoad((const char*)file, flags|BASS_UNICODE); -} - -static inline HMUSIC BASS_MusicLoad(BOOL mem, const WCHAR *file, QWORD offset, DWORD length, DWORD flags, DWORD freq) -{ - return BASS_MusicLoad(mem, (const void*)file, offset, length, flags|BASS_UNICODE, freq); -} - -static inline HSAMPLE BASS_SampleLoad(BOOL mem, const WCHAR *file, QWORD offset, DWORD length, DWORD max, DWORD flags) -{ - return BASS_SampleLoad(mem, (const void*)file, offset, length, max, flags|BASS_UNICODE); -} - -static inline HSTREAM BASS_StreamCreateFile(BOOL mem, const WCHAR *file, QWORD offset, QWORD length, DWORD flags) -{ - return BASS_StreamCreateFile(mem, (const void*)file, offset, length, flags|BASS_UNICODE); -} - -static inline HSTREAM BASS_StreamCreateURL(const WCHAR *url, DWORD offset, DWORD flags, DOWNLOADPROC *proc, void *user) -{ - return BASS_StreamCreateURL((const char*)url, offset, flags|BASS_UNICODE, proc, user); -} - -static inline BOOL BASS_SetConfigPtr(DWORD option, const WCHAR *value) -{ - return BASS_SetConfigPtr(option|BASS_UNICODE, (const void*)value); -} -#endif + +#if defined(_WIN32) && !defined(NOBASSOVERLOADS) +static inline HPLUGIN BASS_PluginLoad(const WCHAR *file, DWORD flags) +{ + return BASS_PluginLoad((const char *)file, flags | BASS_UNICODE); +} + +static inline HMUSIC BASS_MusicLoad(BOOL mem, const WCHAR *file, QWORD offset, + DWORD length, DWORD flags, DWORD freq) +{ + return BASS_MusicLoad(mem, (const void *)file, offset, length, + flags | BASS_UNICODE, freq); +} + +static inline HSAMPLE BASS_SampleLoad(BOOL mem, const WCHAR *file, QWORD offset, + DWORD length, DWORD max, DWORD flags) +{ + return BASS_SampleLoad(mem, (const void *)file, offset, length, max, + flags | BASS_UNICODE); +} + +static inline HSTREAM BASS_StreamCreateFile(BOOL mem, const WCHAR *file, + QWORD offset, QWORD length, + DWORD flags) +{ + return BASS_StreamCreateFile(mem, (const void *)file, offset, length, + flags | BASS_UNICODE); +} + +static inline HSTREAM BASS_StreamCreateURL(const WCHAR *url, DWORD offset, + DWORD flags, DOWNLOADPROC *proc, + void *user) +{ + return BASS_StreamCreateURL((const char *)url, offset, flags | BASS_UNICODE, + proc, user); +} + +static inline BOOL BASS_SetConfigPtr(DWORD option, const WCHAR *value) +{ + return BASS_SetConfigPtr(option | BASS_UNICODE, (const void *)value); +} +#endif #endif #endif diff --git a/include/chatlogpiece.h b/include/chatlogpiece.h index 34c5926..1fbca25 100644 --- a/include/chatlogpiece.h +++ b/include/chatlogpiece.h @@ -1,15 +1,16 @@ #ifndef CHATLOGPIECE_H #define CHATLOGPIECE_H -#include #include +#include -class chatlogpiece -{ +class chatlogpiece { public: chatlogpiece(); - chatlogpiece(QString p_name, QString p_showname, QString p_message, bool p_song); - chatlogpiece(QString p_name, QString p_showname, QString p_message, bool p_song, QDateTime p_datetime); + chatlogpiece(QString p_name, QString p_showname, QString p_message, + bool p_song); + chatlogpiece(QString p_name, QString p_showname, QString p_message, + bool p_song, QDateTime p_datetime); QString get_name(); QString get_showname(); diff --git a/include/courtroom.h b/include/courtroom.h index 99a090b..5d9a4b8 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -1,73 +1,70 @@ #ifndef COURTROOM_H #define COURTROOM_H -#include "aoimage.h" +#include "aoapplication.h" +#include "aoblipplayer.h" #include "aobutton.h" #include "aocharbutton.h" +#include "aocharmovie.h" #include "aoemotebutton.h" +#include "aoevidencebutton.h" +#include "aoevidencedisplay.h" +#include "aoimage.h" +#include "aolineedit.h" +#include "aomovie.h" +#include "aomusicplayer.h" #include "aopacket.h" #include "aoscene.h" -#include "aomovie.h" -#include "aocharmovie.h" -#include "aomusicplayer.h" #include "aosfxplayer.h" -#include "aoblipplayer.h" -#include "aoevidencebutton.h" #include "aotextarea.h" -#include "aolineedit.h" #include "aotextedit.h" -#include "aoevidencedisplay.h" -#include "datatypes.h" -#include "aoapplication.h" -#include "lobby.h" -#include "hardware_functions.h" -#include "file_functions.h" +#include "chatlogpiece.h" #include "datatypes.h" #include "debug_functions.h" -#include "chatlogpiece.h" +#include "file_functions.h" +#include "hardware_functions.h" +#include "lobby.h" -#include -#include -#include -#include #include -#include -#include -#include #include +#include +#include +#include +#include #include -#include +#include +#include #include +#include +#include -#include -#include -#include #include -#include +#include +#include #include #include -#include +#include +#include #include +#include #include class AOApplication; -class Courtroom : public QMainWindow -{ +class Courtroom : public QMainWindow { Q_OBJECT public: explicit Courtroom(AOApplication *p_ao_app); - void append_char(char_type p_char){char_list.append(p_char);} - void append_evidence(evi_type p_evi){evidence_list.append(p_evi);} - void append_music(QString f_music){music_list.append(f_music);} - void append_area(QString f_area){area_list.append(f_area);} + void append_char(char_type p_char) { char_list.append(p_char); } + void append_evidence(evi_type p_evi) { evidence_list.append(p_evi); } + void append_music(QString f_music) { music_list.append(f_music); } + void append_area(QString f_area) { area_list.append(f_area); } void fix_last_area() { - if (area_list.size() > 0) - { + if (area_list.size() > 0) { QString malplaced = area_list.last(); area_list.removeLast(); append_music(malplaced); @@ -76,31 +73,27 @@ public: void arup_append(int players, QString status, QString cm, QString locked) { - arup_players.append(players); - arup_statuses.append(status); - arup_cms.append(cm); - arup_locks.append(locked); + arup_players.append(players); + arup_statuses.append(status); + arup_cms.append(cm); + arup_locks.append(locked); } void arup_modify(int type, int place, QString value) { - if (type == 0) - { + if (type == 0) { if (arup_players.size() > place) arup_players[place] = value.toInt(); } - else if (type == 1) - { + else if (type == 1) { if (arup_statuses.size() > place) arup_statuses[place] = value; } - else if (type == 2) - { + else if (type == 2) { if (arup_cms.size() > place) arup_cms[place] = value; } - else if (type == 3) - { + else if (type == 3) { if (arup_locks.size() > place) arup_locks[place] = value; } @@ -109,105 +102,114 @@ public: void character_loading_finished(); - //sets position of widgets based on theme ini files + // sets position of widgets based on theme ini files void set_widgets(); - //sets font size based on theme ini files + // sets font size based on theme ini files void set_font(QWidget *widget, QString p_identifier); - //helper function that calls above function on the relevant widgets + // helper function that calls above function on the relevant widgets void set_fonts(); void set_window_title(QString p_title); - //reads theme inis and sets size and pos based on the identifier + // reads theme inis and sets size and pos based on the identifier void set_size_and_pos(QWidget *p_widget, QString p_identifier); - //sets status as taken on character with cid n_char and places proper shading on charselect + // sets status as taken on character with cid n_char and places proper shading + // on charselect void set_taken(int n_char, bool p_taken); - //sets the current background to argument. also does some checks to see if it's a legacy bg + // sets the current background to argument. also does some checks to see if + // it's a legacy bg void set_background(QString p_background); - //sets the evidence list member variable to argument + // sets the evidence list member variable to argument void set_evidence_list(QVector &p_evi_list); - //called when a DONE#% from the server was received + // called when a DONE#% from the server was received void done_received(); - //sets the local mute list based on characters available on the server + // 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 + // sets desk and bg based on pos in chatmessage void set_scene(); - //sets text color based on text color in chatmessage + // sets text color based on text color in chatmessage void set_text_color(); // And gets the colour, too! QColor get_text_color(QString color); - //takes in serverD-formatted IP list as prints a converted version to server OOC - //admittedly poorly named + // takes in serverD-formatted IP list as prints a converted version to server + // OOC admittedly poorly named void set_ip_list(QString p_list); - //disables chat if current cid matches second argument - //enables if p_muted is false + // disables chat if current cid matches second argument + // enables if p_muted is false void set_mute(bool p_muted, int p_cid); - //send a message that the player is banned and quits the server + // send a message that the player is banned and quits the server void set_ban(int p_cid); - //cid = character id, returns the cid of the currently selected character - int get_cid() {return m_cid;} - QString get_current_char() {return current_char;} - QString get_current_background() {return current_background;} + // cid = character id, returns the cid of the currently selected character + int get_cid() { return m_cid; } + QString get_current_char() { return current_char; } + QString get_current_background() { return current_background; } - //properly sets up some varibles: resets user state + // properly sets up some varibles: resets user state void enter_courtroom(int p_cid); - //helper function that populates ui_music_list with the contents of music_list + // helper function that populates ui_music_list with the contents of + // music_list void list_music(); void list_areas(); - //these are for OOC chat + // these are for OOC chat void append_ms_chatmessage(QString f_name, QString f_message); - void append_server_chatmessage(QString p_name, QString p_message, QString p_colour); + void append_server_chatmessage(QString p_name, QString p_message, + QString p_colour); - //these functions handle chatmessages sequentially. - //The process itself is very convoluted and merits separate documentation - //But the general idea is objection animation->pre animation->talking->idle + // these functions handle chatmessages sequentially. + // The process itself is very convoluted and merits separate documentation + // But the general idea is objection animation->pre animation->talking->idle void handle_chatmessage(QStringList *p_contents); void handle_chatmessage_2(); void handle_chatmessage_3(); - //This function filters out the common CC inline text trickery, for appending to - //the IC chatlog. + // This function filters out the common CC inline text trickery, for appending + // to the IC chatlog. QString filter_ic_text(QString p_text); - //adds text to the IC chatlog. p_name first as bold then p_text then a newlin - //this function keeps the chatlog scrolled to the top unless there's text selected + // adds text to the IC chatlog. p_name first as bold then p_text then a newlin + // this function keeps the chatlog scrolled to the top unless there's text + // selected // or the user isn't already scrolled to the top - void append_ic_text(QString p_text, QString p_name = "", bool is_songchange = false); + void append_ic_text(QString p_text, QString p_name = "", + bool is_songchange = false); - //prints who played the song to IC chat and plays said song(if found on local filesystem) - //takes in a list where the first element is the song name and the second is the char id of who played it + // prints who played the song to IC chat and plays said song(if found on local + // filesystem) takes in a list where the first element is the song name and the + // second is the char id of who played it void handle_song(QStringList *p_contents); void play_preanim(bool noninterrupting); - //plays the witness testimony or cross examination animation based on argument + // plays the witness testimony or cross examination animation based on + // argument void handle_wtce(QString p_wtce, int variant); - //sets the hp bar of defense(p_bar 1) or pro(p_bar 2) - //state is an number between 0 and 10 inclusive + // sets the hp bar of defense(p_bar 1) or pro(p_bar 2) + // state is an number between 0 and 10 inclusive void set_hp_bar(int p_bar, int p_state); - //Toggles the judge buttons, whether they should appear or not. + // Toggles the judge buttons, whether they should appear or not. void toggle_judge_buttons(bool is_on); - void announce_case(QString title, bool def, bool pro, bool jud, bool jur, bool steno); + void announce_case(QString title, bool def, bool pro, bool jud, bool jur, + bool steno); void check_connection_received(); @@ -230,18 +232,13 @@ private: // This is for inline message-colouring. - enum INLINE_COLOURS { - INLINE_BLUE, - INLINE_GREEN, - INLINE_ORANGE, - INLINE_GREY - }; + enum INLINE_COLOURS { INLINE_BLUE, INLINE_GREEN, INLINE_ORANGE, INLINE_GREY }; // A stack of inline colours. std::stack inline_colour_stack; bool next_character_is_not_special = false; // If true, write the - // next character as it is. + // next character as it is. bool message_is_centered = false; @@ -278,15 +275,15 @@ private: QVector music_row_to_number; QVector area_row_to_number; - //triggers ping_server() every 60 seconds + // triggers ping_server() every 60 seconds QTimer *keepalive_timer; - //determines how fast messages tick onto screen + // determines how fast messages tick onto screen QTimer *chat_tick_timer; - //int chat_tick_interval = 60; - //which tick position(character in chat message) we are at + // int chat_tick_interval = 60; + // which tick position(character in chat message) we are at int tick_pos = 0; - //used to determine how often blips sound + // used to determine how often blips sound int blip_pos = 0; int blip_rate = 1; int rainbow_counter = 0; @@ -299,21 +296,23 @@ private: // True, if the log should go downwards. bool log_goes_downwards = false; - //delay before chat messages starts ticking + // delay before chat messages starts ticking QTimer *text_delay_timer; - //delay before sfx plays + // delay before sfx plays QTimer *sfx_delay_timer; - //keeps track of how long realization is visible(it's just a white square and should be visible less than a second) + // keeps track of how long realization is visible(it's just a white square and + // should be visible less than a second) QTimer *realization_timer; - //times how long the blinking testimony should be shown(green one in the corner) + // times how long the blinking testimony should be shown(green one in the + // corner) QTimer *testimony_show_timer; - //times how long the blinking testimony should be hidden + // times how long the blinking testimony should be hidden QTimer *testimony_hide_timer; - //every time point in char.inis times this equals the final time + // every time point in char.inis times this equals the final time const int time_mod = 40; static const int chatmessage_size = 23; @@ -324,28 +323,30 @@ private: bool testimony_in_progress = false; - //in milliseconds + // in milliseconds const int testimony_show_time = 1500; - //in milliseconds + // in milliseconds const int testimony_hide_time = 500; - //char id, muted or not + // char id, muted or not QMap mute_map; - //QVector muted_cids; + // QVector muted_cids; bool is_muted = false; - //state of animation, 0 = objecting, 1 = preanim, 2 = talking, 3 = idle, 4 = noniterrupting preanim + // state of animation, 0 = objecting, 1 = preanim, 2 = talking, 3 = idle, 4 = + // noniterrupting preanim int anim_state = 3; - //state of text ticking, 0 = not yet ticking, 1 = ticking in progress, 2 = ticking done + // state of text ticking, 0 = not yet ticking, 1 = ticking in progress, 2 = + // ticking done int text_state = 2; - //character id, which index of the char_list the player is + // character id, which index of the char_list the player is int m_cid = -1; - //cid and this may differ in cases of ini-editing + // cid and this may differ in cases of ini-editing QString current_char = ""; int objection_state = 0; @@ -378,10 +379,11 @@ private: int evidence_rows = 3; int max_evidence_on_page = 18; - //is set to true if the bg folder contains defensedesk.png, prosecutiondesk.png and stand.png + // is set to true if the bg folder contains defensedesk.png, + // prosecutiondesk.png and stand.png bool is_ao2_bg = false; - //whether the ooc chat is server or master chat, true is server + // whether the ooc chat is server or master chat, true is server bool server_ooc = true; QString current_background = "default"; @@ -430,11 +432,11 @@ private: QLineEdit *ui_ooc_chat_message; QLineEdit *ui_ooc_chat_name; - //QLineEdit *ui_area_password; + // QLineEdit *ui_area_password; QLineEdit *ui_music_search; QWidget *ui_emotes; - QVector ui_emote_list; + QVector ui_emote_list; AOButton *ui_emote_left; AOButton *ui_emote_right; @@ -499,7 +501,7 @@ private: AOImage *ui_evidence; AOLineEdit *ui_evidence_name; QWidget *ui_evidence_buttons; - QVector ui_evidence_list; + QVector ui_evidence_list; AOButton *ui_evidence_left; AOButton *ui_evidence_right; AOButton *ui_evidence_present; @@ -512,11 +514,11 @@ private: AOImage *ui_char_select_background; - //abstract widget to hold char buttons + // abstract widget to hold char buttons QWidget *ui_char_buttons; - QVector ui_char_button_list; - QVector ui_char_button_list_filtered; + QVector ui_char_button_list; + QVector ui_char_button_list_filtered; AOImage *ui_selector; AOButton *ui_back_to_lobby; @@ -557,7 +559,8 @@ public slots: void mod_called(QString p_ip); - void case_called(QString msg, bool def, bool pro, bool jud, bool jur, bool steno); + void case_called(QString msg, bool def, bool pro, bool jud, bool jur, + bool steno); private slots: void start_chat_ticking(); diff --git a/include/datatypes.h b/include/datatypes.h index aaa5de5..207f506 100644 --- a/include/datatypes.h +++ b/include/datatypes.h @@ -3,16 +3,14 @@ #include -struct server_type -{ +struct server_type { QString name; QString desc; QString ip; int port; }; -struct emote_type -{ +struct emote_type { QString comment; QString preanim; QString anim; @@ -22,23 +20,20 @@ struct emote_type int sfx_duration; }; -struct char_type -{ +struct char_type { QString name; QString description; QString evidence_string; bool taken; }; -struct evi_type -{ +struct evi_type { QString name; QString description; QString image; }; -struct chatmessage_type -{ +struct chatmessage_type { QString message; QString character; QString side; @@ -55,29 +50,25 @@ struct chatmessage_type int flip; }; -struct area_type -{ +struct area_type { QString name; QString background; bool passworded; }; -struct pos_type -{ +struct pos_type { int x; int y; }; -struct pos_size_type -{ +struct pos_size_type { int x = 0; int y = 0; int width = 0; int height = 0; }; -enum CHAT_MESSAGE -{ +enum CHAT_MESSAGE { DESK_MOD = 0, PRE_EMOTE, CHAR_NAME, @@ -103,17 +94,6 @@ enum CHAT_MESSAGE NONINTERRUPTING_PRE }; -enum COLOR -{ - WHITE = 0, - GREEN, - RED, - ORANGE, - BLUE, - YELLOW, - RAINBOW, - PINK, - CYAN -}; +enum COLOR { WHITE = 0, GREEN, RED, ORANGE, BLUE, YELLOW, RAINBOW, PINK, CYAN }; #endif // DATATYPES_H diff --git a/include/debug_functions.h b/include/debug_functions.h index 160274c..383431a 100644 --- a/include/debug_functions.h +++ b/include/debug_functions.h @@ -1,8 +1,8 @@ #ifndef DEBUG_FUNCTIONS_H #define DEBUG_FUNCTIONS_H -#include #include +#include void call_error(QString message); void call_notice(QString message); diff --git a/include/discord-rpc.h b/include/discord-rpc.h index feb874b..455f62a 100644 --- a/include/discord-rpc.h +++ b/include/discord-rpc.h @@ -24,61 +24,63 @@ extern "C" { #endif typedef struct DiscordRichPresence { - const char* state; /* max 128 bytes */ - const char* details; /* max 128 bytes */ - int64_t startTimestamp; - int64_t endTimestamp; - const char* largeImageKey; /* max 32 bytes */ - const char* largeImageText; /* max 128 bytes */ - const char* smallImageKey; /* max 32 bytes */ - const char* smallImageText; /* max 128 bytes */ - const char* partyId; /* max 128 bytes */ - int partySize; - int partyMax; - const char* matchSecret; /* max 128 bytes */ - const char* joinSecret; /* max 128 bytes */ - const char* spectateSecret; /* max 128 bytes */ - int8_t instance; + const char *state; /* max 128 bytes */ + const char *details; /* max 128 bytes */ + int64_t startTimestamp; + int64_t endTimestamp; + const char *largeImageKey; /* max 32 bytes */ + const char *largeImageText; /* max 128 bytes */ + const char *smallImageKey; /* max 32 bytes */ + const char *smallImageText; /* max 128 bytes */ + const char *partyId; /* max 128 bytes */ + int partySize; + int partyMax; + const char *matchSecret; /* max 128 bytes */ + const char *joinSecret; /* max 128 bytes */ + const char *spectateSecret; /* max 128 bytes */ + int8_t instance; } DiscordRichPresence; typedef struct DiscordJoinRequest { - const char* userId; - const char* username; - const char* discriminator; - const char* avatar; + const char *userId; + const char *username; + const char *discriminator; + const char *avatar; } DiscordJoinRequest; typedef struct DiscordEventHandlers { - void (*ready)(void); - void (*disconnected)(int errorCode, const char* message); - void (*errored)(int errorCode, const char* message); - void (*joinGame)(const char* joinSecret); - void (*spectateGame)(const char* spectateSecret); - void (*joinRequest)(const DiscordJoinRequest* request); + void (*ready)(void); + void (*disconnected)(int errorCode, const char *message); + void (*errored)(int errorCode, const char *message); + void (*joinGame)(const char *joinSecret); + void (*spectateGame)(const char *spectateSecret); + void (*joinRequest)(const DiscordJoinRequest *request); } DiscordEventHandlers; #define DISCORD_REPLY_NO 0 #define DISCORD_REPLY_YES 1 #define DISCORD_REPLY_IGNORE 2 -DISCORD_EXPORT void Discord_Initialize(const char* applicationId, - DiscordEventHandlers* handlers, +DISCORD_EXPORT void Discord_Initialize(const char *applicationId, + DiscordEventHandlers *handlers, int autoRegister, - const char* optionalSteamId); + const char *optionalSteamId); DISCORD_EXPORT void Discord_Shutdown(void); /* checks for incoming messages, dispatches callbacks */ DISCORD_EXPORT void Discord_RunCallbacks(void); -/* If you disable the lib starting its own io thread, you'll need to call this from your own */ +/* If you disable the lib starting its own io thread, you'll need to call this + * from your own */ #ifdef DISCORD_DISABLE_IO_THREAD DISCORD_EXPORT void Discord_UpdateConnection(void); #endif -DISCORD_EXPORT void Discord_UpdatePresence(const DiscordRichPresence* presence); +DISCORD_EXPORT void Discord_UpdatePresence(const DiscordRichPresence *presence); DISCORD_EXPORT void Discord_ClearPresence(void); -DISCORD_EXPORT void Discord_Respond(const char* userid, /* DISCORD_REPLY_ */ int reply); +DISCORD_EXPORT void Discord_Respond(const char *userid, + /* DISCORD_REPLY_ */ int reply); #ifdef __cplusplus } /* extern "C" */ diff --git a/include/discord_register.h b/include/discord_register.h index 4c16b68..655a3df 100644 --- a/include/discord_register.h +++ b/include/discord_register.h @@ -1,25 +1,27 @@ #pragma once #if defined(DISCORD_DYNAMIC_LIB) -# if defined(_WIN32) -# if defined(DISCORD_BUILDING_SDK) -# define DISCORD_EXPORT __declspec(dllexport) -# else -# define DISCORD_EXPORT __declspec(dllimport) -# endif -# else -# define DISCORD_EXPORT __attribute__((visibility("default"))) -# endif +#if defined(_WIN32) +#if defined(DISCORD_BUILDING_SDK) +#define DISCORD_EXPORT __declspec(dllexport) #else -# define DISCORD_EXPORT +#define DISCORD_EXPORT __declspec(dllimport) +#endif +#else +#define DISCORD_EXPORT __attribute__((visibility("default"))) +#endif +#else +#define DISCORD_EXPORT #endif #ifdef __cplusplus extern "C" { #endif -DISCORD_EXPORT void Discord_Register(const char* applicationId, const char* command); -DISCORD_EXPORT void Discord_RegisterSteamGame(const char* applicationId, const char* steamId); +DISCORD_EXPORT void Discord_Register(const char *applicationId, + const char *command); +DISCORD_EXPORT void Discord_RegisterSteamGame(const char *applicationId, + const char *steamId); #ifdef __cplusplus } diff --git a/include/discord_rich_presence.h b/include/discord_rich_presence.h index e7ecc6e..77c0eff 100644 --- a/include/discord_rich_presence.h +++ b/include/discord_rich_presence.h @@ -1,11 +1,11 @@ #ifndef DISCORD_RICH_PRESENCE_H #define DISCORD_RICH_PRESENCE_H +#include #include #include -#include -#include #include +#include #include #include @@ -14,12 +14,12 @@ namespace AttorneyOnline { -class Discord -{ +class Discord { private: - const char* APPLICATION_ID = "399779271737868288"; + const char *APPLICATION_ID = "399779271737868288"; std::string server_name, server_id; int64_t timestamp; + public: Discord(); ~Discord(); @@ -30,5 +30,5 @@ public: void state_spectate(); }; -} +} // namespace AttorneyOnline #endif // DISCORD_RICH_PRESENCE_H diff --git a/include/discord_rpc.h b/include/discord_rpc.h index 3e1441e..6bd4404 100644 --- a/include/discord_rpc.h +++ b/include/discord_rpc.h @@ -24,63 +24,65 @@ extern "C" { #endif typedef struct DiscordRichPresence { - const char* state; /* max 128 bytes */ - const char* details; /* max 128 bytes */ - int64_t startTimestamp; - int64_t endTimestamp; - const char* largeImageKey; /* max 32 bytes */ - const char* largeImageText; /* max 128 bytes */ - const char* smallImageKey; /* max 32 bytes */ - const char* smallImageText; /* max 128 bytes */ - const char* partyId; /* max 128 bytes */ - int partySize; - int partyMax; - const char* matchSecret; /* max 128 bytes */ - const char* joinSecret; /* max 128 bytes */ - const char* spectateSecret; /* max 128 bytes */ - int8_t instance; + const char *state; /* max 128 bytes */ + const char *details; /* max 128 bytes */ + int64_t startTimestamp; + int64_t endTimestamp; + const char *largeImageKey; /* max 32 bytes */ + const char *largeImageText; /* max 128 bytes */ + const char *smallImageKey; /* max 32 bytes */ + const char *smallImageText; /* max 128 bytes */ + const char *partyId; /* max 128 bytes */ + int partySize; + int partyMax; + const char *matchSecret; /* max 128 bytes */ + const char *joinSecret; /* max 128 bytes */ + const char *spectateSecret; /* max 128 bytes */ + int8_t instance; } DiscordRichPresence; typedef struct DiscordUser { - const char* userId; - const char* username; - const char* discriminator; - const char* avatar; + const char *userId; + const char *username; + const char *discriminator; + const char *avatar; } DiscordUser; typedef struct DiscordEventHandlers { - void (*ready)(const DiscordUser* request); - void (*disconnected)(int errorCode, const char* message); - void (*errored)(int errorCode, const char* message); - void (*joinGame)(const char* joinSecret); - void (*spectateGame)(const char* spectateSecret); - void (*joinRequest)(const DiscordUser* request); + void (*ready)(const DiscordUser *request); + void (*disconnected)(int errorCode, const char *message); + void (*errored)(int errorCode, const char *message); + void (*joinGame)(const char *joinSecret); + void (*spectateGame)(const char *spectateSecret); + void (*joinRequest)(const DiscordUser *request); } DiscordEventHandlers; #define DISCORD_REPLY_NO 0 #define DISCORD_REPLY_YES 1 #define DISCORD_REPLY_IGNORE 2 -DISCORD_EXPORT void Discord_Initialize(const char* applicationId, - DiscordEventHandlers* handlers, +DISCORD_EXPORT void Discord_Initialize(const char *applicationId, + DiscordEventHandlers *handlers, int autoRegister, - const char* optionalSteamId); + const char *optionalSteamId); DISCORD_EXPORT void Discord_Shutdown(void); /* checks for incoming messages, dispatches callbacks */ DISCORD_EXPORT void Discord_RunCallbacks(void); -/* If you disable the lib starting its own io thread, you'll need to call this from your own */ +/* If you disable the lib starting its own io thread, you'll need to call this + * from your own */ #ifdef DISCORD_DISABLE_IO_THREAD DISCORD_EXPORT void Discord_UpdateConnection(void); #endif -DISCORD_EXPORT void Discord_UpdatePresence(const DiscordRichPresence* presence); +DISCORD_EXPORT void Discord_UpdatePresence(const DiscordRichPresence *presence); DISCORD_EXPORT void Discord_ClearPresence(void); -DISCORD_EXPORT void Discord_Respond(const char* userid, /* DISCORD_REPLY_ */ int reply); +DISCORD_EXPORT void Discord_Respond(const char *userid, + /* DISCORD_REPLY_ */ int reply); -DISCORD_EXPORT void Discord_UpdateHandlers(DiscordEventHandlers* handlers); +DISCORD_EXPORT void Discord_UpdateHandlers(DiscordEventHandlers *handlers); #ifdef __cplusplus } /* extern "C" */ diff --git a/include/encryption_functions.h b/include/encryption_functions.h index dc67d12..b70e8e6 100644 --- a/include/encryption_functions.h +++ b/include/encryption_functions.h @@ -3,11 +3,11 @@ #include -#include -#include -#include -#include #include +#include +#include +#include +#include QString fanta_encrypt(QString p_input, unsigned int key); QString fanta_decrypt(QString p_input, unsigned int key); diff --git a/include/file_functions.h b/include/file_functions.h index 6937ed8..8bb2e5f 100644 --- a/include/file_functions.h +++ b/include/file_functions.h @@ -1,8 +1,8 @@ #ifndef FILE_FUNCTIONS_H #define FILE_FUNCTIONS_H -#include #include +#include #include bool file_exists(QString file_path); diff --git a/include/hex_functions.h b/include/hex_functions.h index 285f096..d178ba1 100644 --- a/include/hex_functions.h +++ b/include/hex_functions.h @@ -1,17 +1,16 @@ #ifndef HEX_OPERATIONS_H #define HEX_OPERATIONS_H +#include #include #include -#include -#include -#include #include +#include #include +#include -namespace omni -{ - std::string int_to_hex(unsigned int input); +namespace omni { +std::string int_to_hex(unsigned int input); } -#endif //HEX_OPERATIONS_H +#endif // HEX_OPERATIONS_H diff --git a/include/lobby.h b/include/lobby.h index 19276a7..833450d 100644 --- a/include/lobby.h +++ b/include/lobby.h @@ -1,16 +1,16 @@ #ifndef LOBBY_H #define LOBBY_H -#include "aoimage.h" #include "aobutton.h" +#include "aoimage.h" #include "aopacket.h" #include "aotextarea.h" -#include -#include #include -#include #include +#include +#include +#include #include #include @@ -19,8 +19,7 @@ class AOApplication; -class Lobby : public QMainWindow -{ +class Lobby : public QMainWindow { Q_OBJECT public: @@ -33,8 +32,8 @@ public: void append_error(QString f_message); void set_player_count(int players_online, int max_players); void set_loading_text(QString p_text); - void show_loading_overlay(){ui_loading_background->show();} - void hide_loading_overlay(){ui_loading_background->hide();} + void show_loading_overlay() { ui_loading_background->show(); } + void hide_loading_overlay() { ui_loading_background->hide(); } QString get_chatlog(); int get_selected_server(); void enable_connect_button(); diff --git a/include/misc_functions.h b/include/misc_functions.h index 026c635..5287bee 100644 --- a/include/misc_functions.h +++ b/include/misc_functions.h @@ -1,8 +1,8 @@ #ifndef MISC_FUNCTIONS_H #define MISC_FUNCTIONS_H -#include #include +#include void delay(int p_milliseconds); diff --git a/include/networkmanager.h b/include/networkmanager.h index 08b10db..ed57a95 100644 --- a/include/networkmanager.h +++ b/include/networkmanager.h @@ -1,8 +1,8 @@ #ifndef NETWORKMANAGER_H #define NETWORKMANAGER_H -// Qt for Android has stubbed QDnsLookup. This is not documented in any part of their wiki. -// This prevents SRV lookup/failover behavior from functioning. +// Qt for Android has stubbed QDnsLookup. This is not documented in any part of +// their wiki. This prevents SRV lookup/failover behavior from functioning. // https://bugreports.qt.io/browse/QTBUG-56143 #ifndef ANDROID #define MS_FAILOVER_SUPPORTED @@ -14,17 +14,16 @@ #undef MS_FAILOVER_SUPPORTED #endif -#include "aopacket.h" #include "aoapplication.h" +#include "aopacket.h" -#include #include +#include #include #include #include -class NetworkManager : public QObject -{ +class NetworkManager : public QObject { Q_OBJECT public: diff --git a/include/text_file_functions.h b/include/text_file_functions.h index 119f38e..1da4d92 100644 --- a/include/text_file_functions.h +++ b/include/text_file_functions.h @@ -3,11 +3,11 @@ #include "aoapplication.h" #include "file_functions.h" -#include -#include -#include -#include #include +#include #include +#include +#include +#include #endif // TEXT_FILE_FUNCTIONS_H diff --git a/src/aoapplication.cpp b/src/aoapplication.cpp index 4ef1edd..9bed218 100644 --- a/src/aoapplication.cpp +++ b/src/aoapplication.cpp @@ -1,17 +1,18 @@ #include "aoapplication.h" -#include "lobby.h" #include "courtroom.h" -#include "networkmanager.h" #include "debug_functions.h" +#include "lobby.h" +#include "networkmanager.h" -#include "aooptionsdialog.h" #include "aocaseannouncerdialog.h" +#include "aooptionsdialog.h" AOApplication::AOApplication(int &argc, char **argv) : QApplication(argc, argv) { // Create the QSettings class that points to the config.ini. - configini = new QSettings(get_base_path() + "config.ini", QSettings::IniFormat); + configini = + new QSettings(get_base_path() + "config.ini", QSettings::IniFormat); net_manager = new NetworkManager(this); discord = new AttorneyOnline::Discord(); @@ -28,8 +29,7 @@ AOApplication::~AOApplication() void AOApplication::construct_lobby() { - if (lobby_constructed) - { + if (lobby_constructed) { qDebug() << "W: lobby was attempted constructed when it already exists"; return; } @@ -38,8 +38,8 @@ void AOApplication::construct_lobby() lobby_constructed = true; QRect geometry = QGuiApplication::primaryScreen()->geometry(); - int x = (geometry.width()-w_lobby->width()) / 2; - int y = (geometry.height()-w_lobby->height()) / 2; + int x = (geometry.width() - w_lobby->width()) / 2; + int y = (geometry.height() - w_lobby->height()) / 2; w_lobby->move(x, y); if (is_discord_enabled()) @@ -50,8 +50,7 @@ void AOApplication::construct_lobby() void AOApplication::destruct_lobby() { - if(!lobby_constructed) - { + if (!lobby_constructed) { qDebug() << "W: lobby was attempted destructed when it did not exist"; return; } @@ -63,8 +62,7 @@ void AOApplication::destruct_lobby() void AOApplication::construct_courtroom() { - if (courtroom_constructed) - { + if (courtroom_constructed) { qDebug() << "W: courtroom was attempted constructed when it already exists"; return; } @@ -73,15 +71,14 @@ void AOApplication::construct_courtroom() courtroom_constructed = true; QRect geometry = QGuiApplication::primaryScreen()->geometry(); - int x = (geometry.width()-w_courtroom->width()) / 2; - int y = (geometry.height()-w_courtroom->height()) / 2; + int x = (geometry.width() - w_courtroom->width()) / 2; + int y = (geometry.height() - w_courtroom->height()) / 2; w_courtroom->move(x, y); } void AOApplication::destruct_courtroom() { - if (!courtroom_constructed) - { + if (!courtroom_constructed) { qDebug() << "W: courtroom was attempted destructed when it did not exist"; return; } @@ -93,16 +90,11 @@ void AOApplication::destruct_courtroom() QString AOApplication::get_version_string() { - return - QString::number(RELEASE) + "." + - QString::number(MAJOR_VERSION) + "." + - QString::number(MINOR_VERSION); + return QString::number(RELEASE) + "." + QString::number(MAJOR_VERSION) + "." + + QString::number(MINOR_VERSION); } -void AOApplication::reload_theme() -{ - current_theme = read_theme(); -} +void AOApplication::reload_theme() { current_theme = read_theme(); } void AOApplication::set_favorite_list() { @@ -133,8 +125,7 @@ void AOApplication::add_favorite_server(int p_server) void AOApplication::server_disconnected() { - if (courtroom_constructed) - { + if (courtroom_constructed) { call_notice("Disconnected from server."); construct_lobby(); destruct_courtroom(); @@ -150,38 +141,38 @@ void AOApplication::loading_cancelled() void AOApplication::ms_connect_finished(bool connected, bool will_retry) { - if (connected) - { + if (connected) { AOPacket *f_packet = new AOPacket("ALL#%"); send_ms_packet(f_packet); } - else - { - if (will_retry) - { + else { + if (will_retry) { if (lobby_constructed) - w_lobby->append_error("Error connecting to master server. Will try again in " - + QString::number(net_manager->ms_reconnect_delay) + " seconds."); + w_lobby->append_error( + "Error connecting to master server. Will try again in " + + QString::number(net_manager->ms_reconnect_delay) + " seconds."); } - else - { + else { call_error("There was an error connecting to the master server.\n" - "We deploy multiple master servers to mitigate any possible downtime, " - "but the client appears to have exhausted all possible methods of finding " + "We deploy multiple master servers to mitigate any possible " + "downtime, " + "but the client appears to have exhausted all possible " + "methods of finding " "and connecting to one.\n" - "Please check your Internet connection and firewall, and please try again."); + "Please check your Internet connection and firewall, and " + "please try again."); } } } void AOApplication::call_settings_menu() { - AOOptionsDialog settings(nullptr, this); - settings.exec(); + AOOptionsDialog settings(nullptr, this); + settings.exec(); } void AOApplication::call_announce_menu(Courtroom *court) { - AOCaseAnnouncerDialog announcer(nullptr, this, court); - announcer.exec(); + AOCaseAnnouncerDialog announcer(nullptr, this, court); + announcer.exec(); } diff --git a/src/aoblipplayer.cpp b/src/aoblipplayer.cpp index 4dfb895..0355414 100644 --- a/src/aoblipplayer.cpp +++ b/src/aoblipplayer.cpp @@ -1,6 +1,6 @@ #include "aoblipplayer.h" -#if defined(BASSAUDIO) //Using bass.dll for the blips +#if defined(BASSAUDIO) // Using bass.dll for the blips AOBlipPlayer::AOBlipPlayer(QWidget *parent, AOApplication *p_ao_app) { m_parent = parent; @@ -11,11 +11,11 @@ void AOBlipPlayer::set_blips(QString p_sfx) { QString f_path = ao_app->get_sounds_path(p_sfx); - for (int n_stream = 0 ; n_stream < 5 ; ++n_stream) - { + for (int n_stream = 0; n_stream < 5; ++n_stream) { BASS_StreamFree(m_stream_list[n_stream]); - m_stream_list[n_stream] = BASS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, BASS_UNICODE | BASS_ASYNCFILE); + m_stream_list[n_stream] = BASS_StreamCreateFile( + FALSE, f_path.utf16(), 0, 0, BASS_UNICODE | BASS_ASYNCFILE); } set_volume(m_volume); @@ -40,12 +40,11 @@ void AOBlipPlayer::set_volume(int p_value) float volume = p_value / 100.0f; - for (int n_stream = 0 ; n_stream < 5 ; ++n_stream) - { + for (int n_stream = 0; n_stream < 5; ++n_stream) { BASS_ChannelSetAttribute(m_stream_list[n_stream], BASS_ATTRIB_VOL, volume); } } -#elif defined(QTAUDIO) //Using Qt's QSoundEffect class +#elif defined(QTAUDIO) // Using Qt's QSoundEffect class AOBlipPlayer::AOBlipPlayer(QWidget *parent, AOApplication *p_ao_app) { m_parent = parent; @@ -56,8 +55,7 @@ void AOBlipPlayer::set_blips(QString p_sfx) { QString f_path = ao_app->get_sounds_path(p_sfx); - for (int n_stream = 0 ; n_stream < 5 ; ++n_stream) - { + for (int n_stream = 0; n_stream < 5; ++n_stream) { m_blips.setSource(QUrl::fromLocalFile(f_path)); } @@ -79,25 +77,16 @@ void AOBlipPlayer::set_volume(int p_value) m_volume = p_value; m_blips.setVolume(m_volume); } -#else //No audio +#else // No audio AOBlipPlayer::AOBlipPlayer(QWidget *parent, AOApplication *p_ao_app) { m_parent = parent; ao_app = p_ao_app; } -void AOBlipPlayer::set_blips(QString p_sfx) -{ +void AOBlipPlayer::set_blips(QString p_sfx) {} -} +void AOBlipPlayer::blip_tick() {} -void AOBlipPlayer::blip_tick() -{ - -} - -void AOBlipPlayer::set_volume(int p_value) -{ - -} +void AOBlipPlayer::set_volume(int p_value) {} #endif diff --git a/src/aobutton.cpp b/src/aobutton.cpp index 5be2e67..fee946a 100644 --- a/src/aobutton.cpp +++ b/src/aobutton.cpp @@ -3,15 +3,13 @@ #include "debug_functions.h" #include "file_functions.h" -AOButton::AOButton(QWidget *parent, AOApplication *p_ao_app) : QPushButton(parent) +AOButton::AOButton(QWidget *parent, AOApplication *p_ao_app) + : QPushButton(parent) { ao_app = p_ao_app; } -AOButton::~AOButton() -{ - -} +AOButton::~AOButton() {} void AOButton::set_image(QString p_image) { @@ -23,4 +21,3 @@ void AOButton::set_image(QString p_image) else this->setStyleSheet("border-image:url(\"" + default_image_path + "\")"); } - diff --git a/src/aocaseannouncerdialog.cpp b/src/aocaseannouncerdialog.cpp index 5b82b64..d91433a 100644 --- a/src/aocaseannouncerdialog.cpp +++ b/src/aocaseannouncerdialog.cpp @@ -1,7 +1,9 @@ #include "aocaseannouncerdialog.h" -AOCaseAnnouncerDialog::AOCaseAnnouncerDialog(QWidget *parent, AOApplication *p_ao_app, Courtroom *p_court) - : QDialog(parent) +AOCaseAnnouncerDialog::AOCaseAnnouncerDialog(QWidget *parent, + AOApplication *p_ao_app, + Courtroom *p_court) + : QDialog(parent) { ao_app = p_ao_app; court = p_court; @@ -14,21 +16,27 @@ AOCaseAnnouncerDialog::AOCaseAnnouncerDialog(QWidget *parent, AOApplication *p_a QSizePolicy sizepolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); sizepolicy.setHorizontalStretch(0); sizepolicy.setVerticalStretch(0); - sizepolicy.setHeightForWidth(ui_announcer_buttons->sizePolicy().hasHeightForWidth()); + sizepolicy.setHeightForWidth( + ui_announcer_buttons->sizePolicy().hasHeightForWidth()); ui_announcer_buttons->setSizePolicy(sizepolicy); ui_announcer_buttons->setOrientation(Qt::Horizontal); - ui_announcer_buttons->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + ui_announcer_buttons->setStandardButtons(QDialogButtonBox::Ok | + QDialogButtonBox::Cancel); - QObject::connect(ui_announcer_buttons, SIGNAL(accepted()), this, SLOT(ok_pressed())); - QObject::connect(ui_announcer_buttons, SIGNAL(rejected()), this, SLOT(cancel_pressed())); + QObject::connect(ui_announcer_buttons, SIGNAL(accepted()), this, + SLOT(ok_pressed())); + QObject::connect(ui_announcer_buttons, SIGNAL(rejected()), this, + SLOT(cancel_pressed())); setUpdatesEnabled(false); ui_vbox_layout = new QVBoxLayout(this); ui_form_layout = new QFormLayout(this); - ui_form_layout->setLabelAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignVCenter); - ui_form_layout->setFormAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignTop); + ui_form_layout->setLabelAlignment(Qt::AlignLeading | Qt::AlignLeft | + Qt::AlignVCenter); + ui_form_layout->setFormAlignment(Qt::AlignLeading | Qt::AlignLeft | + Qt::AlignTop); ui_form_layout->setContentsMargins(6, 6, 6, 6); ui_vbox_layout->addItem(ui_form_layout); @@ -66,17 +74,12 @@ AOCaseAnnouncerDialog::AOCaseAnnouncerDialog(QWidget *parent, AOApplication *p_a void AOCaseAnnouncerDialog::ok_pressed() { - court->announce_case(ui_case_title_textbox->text(), - ui_defense_needed->isChecked(), - ui_prosecutor_needed->isChecked(), - ui_judge_needed->isChecked(), - ui_juror_needed->isChecked(), - ui_steno_needed->isChecked()); + court->announce_case( + ui_case_title_textbox->text(), ui_defense_needed->isChecked(), + ui_prosecutor_needed->isChecked(), ui_judge_needed->isChecked(), + ui_juror_needed->isChecked(), ui_steno_needed->isChecked()); done(0); } -void AOCaseAnnouncerDialog::cancel_pressed() -{ - done(0); -} +void AOCaseAnnouncerDialog::cancel_pressed() { done(0); } diff --git a/src/aocharbutton.cpp b/src/aocharbutton.cpp index 7661027..6c27e3e 100644 --- a/src/aocharbutton.cpp +++ b/src/aocharbutton.cpp @@ -2,7 +2,9 @@ #include "file_functions.h" -AOCharButton::AOCharButton(QWidget *parent, AOApplication *p_ao_app, int x_pos, int y_pos, bool is_taken) : QPushButton(parent) +AOCharButton::AOCharButton(QWidget *parent, AOApplication *p_ao_app, int x_pos, + int y_pos, bool is_taken) + : QPushButton(parent) { m_parent = parent; @@ -40,28 +42,20 @@ void AOCharButton::reset() ui_selector->hide(); } -void AOCharButton::set_taken(bool is_taken) -{ - taken = is_taken; -} +void AOCharButton::set_taken(bool is_taken) { taken = is_taken; } void AOCharButton::apply_taken_image() { - if (taken) - { - ui_taken->move(0,0); + if (taken) { + ui_taken->move(0, 0); ui_taken->show(); } - else - { + else { ui_taken->hide(); } } -void AOCharButton::set_passworded() -{ - ui_passworded->show(); -} +void AOCharButton::set_passworded() { ui_passworded->show(); } void AOCharButton::set_image(QString p_character) { @@ -71,14 +65,13 @@ void AOCharButton::set_image(QString p_character) if (file_exists(image_path)) this->setStyleSheet("border-image:url(\"" + image_path + "\")"); - else - { + else { this->setStyleSheet("border-image:url()"); this->setText(p_character); } } -void AOCharButton::enterEvent(QEvent * e) +void AOCharButton::enterEvent(QEvent *e) { ui_selector->move(this->x() - 1, this->y() - 1); ui_selector->raise(); @@ -88,10 +81,8 @@ void AOCharButton::enterEvent(QEvent * e) QPushButton::enterEvent(e); } -void AOCharButton::leaveEvent(QEvent * e) +void AOCharButton::leaveEvent(QEvent *e) { ui_selector->hide(); QPushButton::leaveEvent(e); } - - diff --git a/src/aocharmovie.cpp b/src/aocharmovie.cpp index 5748723..3e0a4de 100644 --- a/src/aocharmovie.cpp +++ b/src/aocharmovie.cpp @@ -1,10 +1,11 @@ #include "aocharmovie.h" -#include "misc_functions.h" -#include "file_functions.h" #include "aoapplication.h" +#include "file_functions.h" +#include "misc_functions.h" -AOCharMovie::AOCharMovie(QWidget *p_parent, AOApplication *p_ao_app) : QLabel(p_parent) +AOCharMovie::AOCharMovie(QWidget *p_parent, AOApplication *p_ao_app) + : QLabel(p_parent) { ao_app = p_ao_app; @@ -19,11 +20,14 @@ AOCharMovie::AOCharMovie(QWidget *p_parent, AOApplication *p_ao_app) : QLabel(p_ void AOCharMovie::play(QString p_char, QString p_emote, QString emote_prefix) { - QString original_path = ao_app->get_character_path(p_char, emote_prefix + p_emote + ".gif"); + QString original_path = + ao_app->get_character_path(p_char, emote_prefix + p_emote + ".gif"); QString alt_path = ao_app->get_character_path(p_char, p_emote + ".png"); - QString apng_path = ao_app->get_character_path(p_char, emote_prefix + p_emote + ".apng"); + QString apng_path = + ao_app->get_character_path(p_char, emote_prefix + p_emote + ".apng"); QString placeholder_path = ao_app->get_theme_path("placeholder.gif"); - QString placeholder_default_path = ao_app->get_default_theme_path("placeholder.gif"); + QString placeholder_default_path = + ao_app->get_default_theme_path("placeholder.gif"); QString gif_path; if (file_exists(apng_path)) @@ -44,8 +48,7 @@ void AOCharMovie::play(QString p_char, QString p_emote, QString emote_prefix) movie_frames.clear(); QImage f_image = reader->read(); - while (!f_image.isNull()) - { + while (!f_image.isNull()) { if (m_flipped) movie_frames.append(f_image.mirrored(true, false)); else @@ -73,8 +76,7 @@ void AOCharMovie::play_pre(QString p_char, QString p_emote, int duration) play_once = false; - for (int n_frame = 0 ; n_frame < m_movie->frameCount() ; ++n_frame) - { + for (int n_frame = 0; n_frame < m_movie->frameCount(); ++n_frame) { real_duration += m_movie->nextFrameDelay(); m_movie->jumpToFrame(n_frame + 1); } @@ -86,8 +88,7 @@ void AOCharMovie::play_pre(QString p_char, QString p_emote, int duration) double percentage_modifier = 100.0; - if (real_duration != 0 && duration != 0) - { + if (real_duration != 0 && duration != 0) { double modifier = full_duration / static_cast(real_duration); percentage_modifier = 100 / modifier; @@ -99,17 +100,14 @@ void AOCharMovie::play_pre(QString p_char, QString p_emote, int duration) qDebug() << "% mod: " << percentage_modifier; #endif - if (full_duration == 0 || full_duration >= real_duration) - { + if (full_duration == 0 || full_duration >= real_duration) { play_once = true; } - else - { + else { play_once = false; preanim_timer->start(full_duration); } - m_movie->setSpeed(static_cast(percentage_modifier)); play(p_char, p_emote, ""); } @@ -142,7 +140,8 @@ void AOCharMovie::play_idle(QString p_char, QString p_emote) void AOCharMovie::stop() { - //for all intents and purposes, stopping is the same as hiding. at no point do we want a frozen gif to display + // for all intents and purposes, stopping is the same as hiding. at no point + // do we want a frozen gif to display m_movie->stop(); preanim_timer->stop(); this->hide(); @@ -165,31 +164,28 @@ void AOCharMovie::move(int ax, int ay) void AOCharMovie::frame_change(int n_frame) { - if (movie_frames.size() > n_frame) - { + if (movie_frames.size() > n_frame) { QPixmap f_pixmap = QPixmap::fromImage(movie_frames.at(n_frame)); auto aspect_ratio = Qt::KeepAspectRatio; if (f_pixmap.size().width() > f_pixmap.size().height()) aspect_ratio = Qt::KeepAspectRatioByExpanding; - if (f_pixmap.size().width() > this->size().width() || f_pixmap.size().height() > this->size().height()) - this->setPixmap(f_pixmap.scaled(this->width(), this->height(), aspect_ratio, Qt::SmoothTransformation)); + if (f_pixmap.size().width() > this->size().width() || + f_pixmap.size().height() > this->size().height()) + this->setPixmap(f_pixmap.scaled(this->width(), this->height(), + aspect_ratio, Qt::SmoothTransformation)); else - this->setPixmap(f_pixmap.scaled(this->width(), this->height(), aspect_ratio, Qt::FastTransformation)); + this->setPixmap(f_pixmap.scaled(this->width(), this->height(), + aspect_ratio, Qt::FastTransformation)); - QLabel::move(x + (this->width() - this->pixmap()->width())/2, y); - } + QLabel::move(x + (this->width() - this->pixmap()->width()) / 2, y); + } - if (m_movie->frameCount() - 1 == n_frame && play_once) - { + if (m_movie->frameCount() - 1 == n_frame && play_once) { preanim_timer->start(m_movie->nextFrameDelay()); m_movie->stop(); } } -void AOCharMovie::timer_done() -{ - - done(); -} +void AOCharMovie::timer_done() { done(); } diff --git a/src/aoemotebutton.cpp b/src/aoemotebutton.cpp index 9c1d388..29329c9 100644 --- a/src/aoemotebutton.cpp +++ b/src/aoemotebutton.cpp @@ -2,7 +2,9 @@ #include "file_functions.h" -AOEmoteButton::AOEmoteButton(QWidget *p_parent, AOApplication *p_ao_app, int p_x, int p_y) : QPushButton(p_parent) +AOEmoteButton::AOEmoteButton(QWidget *p_parent, AOApplication *p_ao_app, + int p_x, int p_y) + : QPushButton(p_parent) { parent = p_parent; ao_app = p_ao_app; @@ -16,21 +18,17 @@ AOEmoteButton::AOEmoteButton(QWidget *p_parent, AOApplication *p_ao_app, int p_x void AOEmoteButton::set_image(QString p_char, int p_emote, QString suffix) { QString emotion_number = QString::number(p_emote + 1); - QString image_path = ao_app->get_character_path(p_char, "emotions/button" + emotion_number + suffix); + QString image_path = ao_app->get_character_path( + p_char, "emotions/button" + emotion_number + suffix); - if (file_exists(image_path)) - { + if (file_exists(image_path)) { this->setText(""); this->setStyleSheet("border-image:url(\"" + image_path + "\")"); } - else - { + else { this->setText(ao_app->get_emote_comment(p_char, p_emote)); this->setStyleSheet("border-image:url(\"\")"); } } -void AOEmoteButton::on_clicked() -{ - emote_clicked(m_id); -} +void AOEmoteButton::on_clicked() { emote_clicked(m_id); } diff --git a/src/aoevidencebutton.cpp b/src/aoevidencebutton.cpp index 15b598f..a94519e 100644 --- a/src/aoevidencebutton.cpp +++ b/src/aoevidencebutton.cpp @@ -2,7 +2,9 @@ #include "file_functions.h" -AOEvidenceButton::AOEvidenceButton(QWidget *p_parent, AOApplication *p_ao_app, int p_x, int p_y) : QPushButton(p_parent) +AOEvidenceButton::AOEvidenceButton(QWidget *p_parent, AOApplication *p_ao_app, + int p_x, int p_y) + : QPushButton(p_parent) { ao_app = p_ao_app; m_parent = p_parent; @@ -39,13 +41,11 @@ void AOEvidenceButton::set_image(QString p_image) { QString image_path = ao_app->get_evidence_path(p_image); - if (file_exists(image_path)) - { + if (file_exists(image_path)) { this->setText(""); this->setStyleSheet("border-image:url(\"" + image_path + "\")"); } - else - { + else { this->setText(p_image); this->setStyleSheet(""); } @@ -75,10 +75,7 @@ void AOEvidenceButton::set_selected(bool p_selected) ui_selected->hide(); } -void AOEvidenceButton::on_clicked() -{ - evidence_clicked(m_id); -} +void AOEvidenceButton::on_clicked() { evidence_clicked(m_id); } void AOEvidenceButton::mouseDoubleClickEvent(QMouseEvent *e) { @@ -102,7 +99,7 @@ void AOEvidenceButton::dragEnterEvent(QMouseEvent *e) } */ -void AOEvidenceButton::enterEvent(QEvent * e) +void AOEvidenceButton::enterEvent(QEvent *e) { ui_selector->show(); @@ -112,7 +109,7 @@ void AOEvidenceButton::enterEvent(QEvent * e) QPushButton::enterEvent(e); } -void AOEvidenceButton::leaveEvent(QEvent * e) +void AOEvidenceButton::leaveEvent(QEvent *e) { ui_selector->hide(); diff --git a/src/aoevidencedisplay.cpp b/src/aoevidencedisplay.cpp index 9ec105d..9dd062b 100644 --- a/src/aoevidencedisplay.cpp +++ b/src/aoevidencedisplay.cpp @@ -1,10 +1,11 @@ #include "aoevidencedisplay.h" -#include "file_functions.h" #include "datatypes.h" +#include "file_functions.h" #include "misc_functions.h" -AOEvidenceDisplay::AOEvidenceDisplay(QWidget *p_parent, AOApplication *p_ao_app) : QLabel(p_parent) +AOEvidenceDisplay::AOEvidenceDisplay(QWidget *p_parent, AOApplication *p_ao_app) + : QLabel(p_parent) { ao_app = p_ao_app; @@ -12,10 +13,12 @@ AOEvidenceDisplay::AOEvidenceDisplay(QWidget *p_parent, AOApplication *p_ao_app) evidence_icon = new QLabel(this); sfx_player = new AOSfxPlayer(this, ao_app); - connect(evidence_movie, SIGNAL(frameChanged(int)), this, SLOT(frame_change(int))); + connect(evidence_movie, SIGNAL(frameChanged(int)), this, + SLOT(frame_change(int))); } -void AOEvidenceDisplay::show_evidence(QString p_evidence_image, bool is_left_side, int p_volume) +void AOEvidenceDisplay::show_evidence(QString p_evidence_image, + bool is_left_side, int p_volume) { this->reset(); @@ -29,23 +32,23 @@ void AOEvidenceDisplay::show_evidence(QString p_evidence_image, bool is_left_sid QString gif_name; QString icon_identifier; - if (is_left_side) - { + if (is_left_side) { icon_identifier = "left_evidence_icon"; gif_name = "evidence_appear_left.gif"; } - else - { + else { icon_identifier = "right_evidence_icon"; gif_name = "evidence_appear_right.gif"; } - pos_size_type icon_dimensions = ao_app->get_element_dimensions(icon_identifier, "courtroom_design.ini"); + pos_size_type icon_dimensions = + ao_app->get_element_dimensions(icon_identifier, "courtroom_design.ini"); evidence_icon->move(icon_dimensions.x, icon_dimensions.y); evidence_icon->resize(icon_dimensions.width, icon_dimensions.height); - evidence_icon->setPixmap(f_pixmap.scaled(evidence_icon->width(), evidence_icon->height(), Qt::IgnoreAspectRatio)); + evidence_icon->setPixmap(f_pixmap.scaled( + evidence_icon->width(), evidence_icon->height(), Qt::IgnoreAspectRatio)); QString f_default_gif_path = ao_app->get_default_theme_path(gif_name); QString f_gif_path = ao_app->get_theme_path(gif_name); @@ -57,7 +60,7 @@ void AOEvidenceDisplay::show_evidence(QString p_evidence_image, bool is_left_sid evidence_movie->setFileName(final_gif_path); - if(evidence_movie->frameCount() < 1) + if (evidence_movie->frameCount() < 1) return; this->setMovie(evidence_movie); @@ -68,9 +71,8 @@ void AOEvidenceDisplay::show_evidence(QString p_evidence_image, bool is_left_sid void AOEvidenceDisplay::frame_change(int p_frame) { - if (p_frame == (evidence_movie->frameCount() - 1)) - { - //we need this or else the last frame wont show + if (p_frame == (evidence_movie->frameCount() - 1)) { + // we need this or else the last frame wont show delay(evidence_movie->nextFrameDelay()); evidence_movie->stop(); @@ -88,9 +90,4 @@ void AOEvidenceDisplay::reset() this->clear(); } -QLabel* AOEvidenceDisplay::get_evidence_icon() -{ - return evidence_icon; -} - - +QLabel *AOEvidenceDisplay::get_evidence_icon() { return evidence_icon; } diff --git a/src/aoimage.cpp b/src/aoimage.cpp index 7bb56bb..ffdf25a 100644 --- a/src/aoimage.cpp +++ b/src/aoimage.cpp @@ -8,10 +8,7 @@ AOImage::AOImage(QWidget *parent, AOApplication *p_ao_app) : QLabel(parent) ao_app = p_ao_app; } -AOImage::~AOImage() -{ - -} +AOImage::~AOImage() {} void AOImage::set_image(QString p_image) { @@ -27,7 +24,8 @@ void AOImage::set_image(QString p_image) QPixmap f_pixmap(final_image_path); - this->setPixmap(f_pixmap.scaled(this->width(), this->height(), Qt::IgnoreAspectRatio)); + this->setPixmap( + f_pixmap.scaled(this->width(), this->height(), Qt::IgnoreAspectRatio)); } void AOImage::set_image_from_path(QString p_path) @@ -43,5 +41,6 @@ void AOImage::set_image_from_path(QString p_path) QPixmap f_pixmap(final_path); - this->setPixmap(f_pixmap.scaled(this->width(), this->height(), Qt::IgnoreAspectRatio)); + this->setPixmap( + f_pixmap.scaled(this->width(), this->height(), Qt::IgnoreAspectRatio)); } diff --git a/src/aolineedit.cpp b/src/aolineedit.cpp index f6026e1..211d9f7 100644 --- a/src/aolineedit.cpp +++ b/src/aolineedit.cpp @@ -15,7 +15,4 @@ void AOLineEdit::mouseDoubleClickEvent(QMouseEvent *e) this->setReadOnly(false); } -void AOLineEdit::on_enter_pressed() -{ - this->setReadOnly(true); -} +void AOLineEdit::on_enter_pressed() { this->setReadOnly(true); } diff --git a/src/aomovie.cpp b/src/aomovie.cpp index edf5bdb..8642688 100644 --- a/src/aomovie.cpp +++ b/src/aomovie.cpp @@ -1,7 +1,7 @@ #include "aomovie.h" -#include "file_functions.h" #include "courtroom.h" +#include "file_functions.h" #include "misc_functions.h" AOMovie::AOMovie(QWidget *p_parent, AOApplication *p_ao_app) : QLabel(p_parent) @@ -15,10 +15,7 @@ AOMovie::AOMovie(QWidget *p_parent, AOApplication *p_ao_app) : QLabel(p_parent) connect(m_movie, SIGNAL(frameChanged(int)), this, SLOT(frame_change(int))); } -void AOMovie::set_play_once(bool p_play_once) -{ - play_once = p_play_once; -} +void AOMovie::set_play_once(bool p_play_once) { play_once = p_play_once; } void AOMovie::play(QString p_gif, QString p_char, QString p_custom_theme) { @@ -28,16 +25,21 @@ void AOMovie::play(QString p_gif, QString p_char, QString p_custom_theme) QString custom_path; if (p_gif == "custom") - custom_path = ao_app->get_image_suffix(ao_app->get_character_path(p_char, p_gif)); + custom_path = + ao_app->get_image_suffix(ao_app->get_character_path(p_char, p_gif)); else - custom_path = ao_app->get_image_suffix(ao_app->get_character_path(p_char, p_gif + "_bubble")); + custom_path = ao_app->get_image_suffix( + ao_app->get_character_path(p_char, p_gif + "_bubble")); - QString misc_path = ao_app->get_base_path() + "misc/" + p_custom_theme + "/" + p_gif + "_bubble.gif"; - QString custom_theme_path = ao_app->get_custom_theme_path(p_custom_theme, p_gif + ".gif"); + QString misc_path = ao_app->get_base_path() + "misc/" + p_custom_theme + "/" + + p_gif + "_bubble.gif"; + QString custom_theme_path = + ao_app->get_custom_theme_path(p_custom_theme, p_gif + ".gif"); QString theme_path = ao_app->get_theme_path(p_gif + ".gif"); QString default_theme_path = ao_app->get_default_theme_path(p_gif + ".gif"); QString placeholder_path = ao_app->get_theme_path("placeholder.gif"); - QString default_placeholder_path = ao_app->get_default_theme_path("placeholder.gif"); + QString default_placeholder_path = + ao_app->get_default_theme_path("placeholder.gif"); if (file_exists(custom_path)) gif_path = custom_path; @@ -70,14 +72,13 @@ void AOMovie::stop() void AOMovie::frame_change(int n_frame) { - if (n_frame == (m_movie->frameCount() - 1) && play_once) - { - //we need this or else the last frame wont show + if (n_frame == (m_movie->frameCount() - 1) && play_once) { + // we need this or else the last frame wont show delay(m_movie->nextFrameDelay()); this->stop(); - //signal connected to courtroom object, let it figure out what to do + // signal connected to courtroom object, let it figure out what to do done(); } } diff --git a/src/aomusicplayer.cpp b/src/aomusicplayer.cpp index 2791809..e61555a 100644 --- a/src/aomusicplayer.cpp +++ b/src/aomusicplayer.cpp @@ -7,10 +7,7 @@ AOMusicPlayer::AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app) ao_app = p_ao_app; } -AOMusicPlayer::~AOMusicPlayer() -{ - BASS_ChannelStop(m_stream); -} +AOMusicPlayer::~AOMusicPlayer() { BASS_ChannelStop(m_stream); } void AOMusicPlayer::play(QString p_song) { @@ -18,7 +15,9 @@ void AOMusicPlayer::play(QString p_song) QString f_path = ao_app->get_music_path(p_song); - m_stream = BASS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE); + m_stream = BASS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, + BASS_STREAM_AUTOFREE | BASS_UNICODE | + BASS_ASYNCFILE); this->set_volume(m_volume); @@ -40,10 +39,7 @@ AOMusicPlayer::AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app) ao_app = p_ao_app; } -AOMusicPlayer::~AOMusicPlayer() -{ - m_player.stop(); -} +AOMusicPlayer::~AOMusicPlayer() { m_player.stop(); } void AOMusicPlayer::play(QString p_song) { @@ -70,18 +66,9 @@ AOMusicPlayer::AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app) ao_app = p_ao_app; } -AOMusicPlayer::~AOMusicPlayer() -{ +AOMusicPlayer::~AOMusicPlayer() {} -} +void AOMusicPlayer::play(QString p_song) {} -void AOMusicPlayer::play(QString p_song) -{ - -} - -void AOMusicPlayer::set_volume(int p_value) -{ - -} +void AOMusicPlayer::set_volume(int p_value) {} #endif diff --git a/src/aooptionsdialog.cpp b/src/aooptionsdialog.cpp index 0f6a054..5653fd9 100644 --- a/src/aooptionsdialog.cpp +++ b/src/aooptionsdialog.cpp @@ -2,523 +2,554 @@ #include "aoapplication.h" #include "bass.h" -AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDialog(parent) +AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) + : QDialog(parent) { - ao_app = p_ao_app; + ao_app = p_ao_app; + + // Setting up the basics. + // setAttribute(Qt::WA_DeleteOnClose); + setWindowTitle(tr("Settings")); + resize(398, 320); + + ui_settings_buttons = new QDialogButtonBox(this); + + QSizePolicy sizePolicy1(QSizePolicy::Expanding, QSizePolicy::Fixed); + sizePolicy1.setHorizontalStretch(0); + sizePolicy1.setVerticalStretch(0); + sizePolicy1.setHeightForWidth( + ui_settings_buttons->sizePolicy().hasHeightForWidth()); + ui_settings_buttons->setSizePolicy(sizePolicy1); + ui_settings_buttons->setOrientation(Qt::Horizontal); + ui_settings_buttons->setStandardButtons(QDialogButtonBox::Cancel | + QDialogButtonBox::Save); + + QObject::connect(ui_settings_buttons, SIGNAL(accepted()), this, + SLOT(save_pressed())); + QObject::connect(ui_settings_buttons, SIGNAL(rejected()), this, + SLOT(discard_pressed())); + + // We'll stop updates so that the window won't flicker while it's being made. + setUpdatesEnabled(false); + + // First of all, we want a tabbed dialog, so let's add some layout. + ui_vertical_layout = new QVBoxLayout(this); + ui_settings_tabs = new QTabWidget(this); + + ui_vertical_layout->addWidget(ui_settings_tabs); + ui_vertical_layout->addWidget(ui_settings_buttons); + + // Let's add the tabs one by one. + // First, we'll start with 'Gameplay'. + ui_gameplay_tab = new QWidget(); + ui_settings_tabs->addTab(ui_gameplay_tab, tr("Gameplay")); + + ui_form_layout_widget = new QWidget(ui_gameplay_tab); + ui_form_layout_widget->setGeometry(QRect(10, 10, 361, 211)); - // Setting up the basics. - // setAttribute(Qt::WA_DeleteOnClose); - setWindowTitle(tr("Settings")); - resize(398, 320); + ui_gameplay_form = new QFormLayout(ui_form_layout_widget); + ui_gameplay_form->setLabelAlignment(Qt::AlignLeading | Qt::AlignLeft | + Qt::AlignVCenter); + ui_gameplay_form->setFormAlignment(Qt::AlignLeading | Qt::AlignLeft | + Qt::AlignTop); + ui_gameplay_form->setContentsMargins(0, 0, 0, 0); - ui_settings_buttons = new QDialogButtonBox(this); + ui_theme_label = new QLabel(ui_form_layout_widget); + ui_theme_label->setText(tr("Theme:")); + ui_theme_label->setToolTip( + tr("Sets the theme used in-game. If the new theme changes " + "the lobby's look as well, you'll need to reload the " + "lobby for the changes to take effect, such as by joining " + "a server and leaving it.")); + ui_gameplay_form->setWidget(0, QFormLayout::LabelRole, ui_theme_label); - QSizePolicy sizePolicy1(QSizePolicy::Expanding, QSizePolicy::Fixed); - sizePolicy1.setHorizontalStretch(0); - sizePolicy1.setVerticalStretch(0); - sizePolicy1.setHeightForWidth(ui_settings_buttons->sizePolicy().hasHeightForWidth()); - ui_settings_buttons->setSizePolicy(sizePolicy1); - ui_settings_buttons->setOrientation(Qt::Horizontal); - ui_settings_buttons->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Save); + ui_theme_combobox = new QComboBox(ui_form_layout_widget); - QObject::connect(ui_settings_buttons, SIGNAL(accepted()), this, SLOT(save_pressed())); - QObject::connect(ui_settings_buttons, SIGNAL(rejected()), this, SLOT(discard_pressed())); + // Fill the combobox with the names of the themes. + QDirIterator it(p_ao_app->get_base_path() + "themes", QDir::Dirs, + QDirIterator::NoIteratorFlags); + while (it.hasNext()) { + QString actualname = QDir(it.next()).dirName(); + if (actualname != "." && actualname != "..") + ui_theme_combobox->addItem(actualname); + if (actualname == p_ao_app->read_theme()) + ui_theme_combobox->setCurrentIndex(ui_theme_combobox->count() - 1); + } - // We'll stop updates so that the window won't flicker while it's being made. - setUpdatesEnabled(false); + ui_gameplay_form->setWidget(0, QFormLayout::FieldRole, ui_theme_combobox); - // First of all, we want a tabbed dialog, so let's add some layout. - ui_vertical_layout = new QVBoxLayout(this); - ui_settings_tabs = new QTabWidget(this); + ui_theme_log_divider = new QFrame(ui_form_layout_widget); + ui_theme_log_divider->setMidLineWidth(0); + ui_theme_log_divider->setFrameShape(QFrame::HLine); + ui_theme_log_divider->setFrameShadow(QFrame::Sunken); - ui_vertical_layout->addWidget(ui_settings_tabs); - ui_vertical_layout->addWidget(ui_settings_buttons); + ui_gameplay_form->setWidget(1, QFormLayout::FieldRole, ui_theme_log_divider); - // Let's add the tabs one by one. - // First, we'll start with 'Gameplay'. - ui_gameplay_tab = new QWidget(); - ui_settings_tabs->addTab(ui_gameplay_tab, tr("Gameplay")); + ui_downwards_lbl = new QLabel(ui_form_layout_widget); + ui_downwards_lbl->setText(tr("Log goes downwards:")); + ui_downwards_lbl->setToolTip( + tr("If ticked, new messages will appear at " + "the bottom (like the OOC chatlog). The traditional " + "(AO1) behaviour is equivalent to this being unticked.")); - ui_form_layout_widget = new QWidget(ui_gameplay_tab); - ui_form_layout_widget->setGeometry(QRect(10, 10, 361, 211)); + ui_gameplay_form->setWidget(2, QFormLayout::LabelRole, ui_downwards_lbl); - ui_gameplay_form = new QFormLayout(ui_form_layout_widget); - ui_gameplay_form->setLabelAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter); - ui_gameplay_form->setFormAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop); - ui_gameplay_form->setContentsMargins(0, 0, 0, 0); + ui_downwards_cb = new QCheckBox(ui_form_layout_widget); + ui_downwards_cb->setChecked(p_ao_app->get_log_goes_downwards()); - ui_theme_label = new QLabel(ui_form_layout_widget); - ui_theme_label->setText(tr("Theme:")); - ui_theme_label->setToolTip(tr("Sets the theme used in-game. If the new theme changes " - "the lobby's look as well, you'll need to reload the " - "lobby for the changes to take effect, such as by joining " - "a server and leaving it.")); - ui_gameplay_form->setWidget(0, QFormLayout::LabelRole, ui_theme_label); + ui_gameplay_form->setWidget(2, QFormLayout::FieldRole, ui_downwards_cb); - ui_theme_combobox = new QComboBox(ui_form_layout_widget); + ui_length_lbl = new QLabel(ui_form_layout_widget); + ui_length_lbl->setText(tr("Log length:")); + ui_length_lbl->setToolTip(tr( + "The amount of messages the IC chatlog will keep before " + "deleting older messages. A value of 0 or below counts as 'infinite'.")); - // Fill the combobox with the names of the themes. - QDirIterator it(p_ao_app->get_base_path() + "themes", QDir::Dirs, QDirIterator::NoIteratorFlags); - while (it.hasNext()) - { - QString actualname = QDir(it.next()).dirName(); - if (actualname != "." && actualname != "..") - ui_theme_combobox->addItem(actualname); - if (actualname == p_ao_app->read_theme()) - ui_theme_combobox->setCurrentIndex(ui_theme_combobox->count()-1); - } + ui_gameplay_form->setWidget(3, QFormLayout::LabelRole, ui_length_lbl); - ui_gameplay_form->setWidget(0, QFormLayout::FieldRole, ui_theme_combobox); + ui_length_spinbox = new QSpinBox(ui_form_layout_widget); + ui_length_spinbox->setMaximum(10000); + ui_length_spinbox->setValue(p_ao_app->get_max_log_size()); - ui_theme_log_divider = new QFrame(ui_form_layout_widget); - ui_theme_log_divider->setMidLineWidth(0); - ui_theme_log_divider->setFrameShape(QFrame::HLine); - ui_theme_log_divider->setFrameShadow(QFrame::Sunken); + ui_gameplay_form->setWidget(3, QFormLayout::FieldRole, ui_length_spinbox); + + ui_log_names_divider = new QFrame(ui_form_layout_widget); + ui_log_names_divider->setFrameShape(QFrame::HLine); + ui_log_names_divider->setFrameShadow(QFrame::Sunken); + + ui_gameplay_form->setWidget(4, QFormLayout::FieldRole, ui_log_names_divider); - ui_gameplay_form->setWidget(1, QFormLayout::FieldRole, ui_theme_log_divider); + ui_username_lbl = new QLabel(ui_form_layout_widget); + ui_username_lbl->setText(tr("Default username:")); + ui_username_lbl->setToolTip( + tr("Your OOC name will be automatically set to this value " + "when you join a server.")); - ui_downwards_lbl = new QLabel(ui_form_layout_widget); - ui_downwards_lbl->setText(tr("Log goes downwards:")); - ui_downwards_lbl->setToolTip(tr("If ticked, new messages will appear at " - "the bottom (like the OOC chatlog). The traditional " - "(AO1) behaviour is equivalent to this being unticked.")); + ui_gameplay_form->setWidget(5, QFormLayout::LabelRole, ui_username_lbl); - ui_gameplay_form->setWidget(2, QFormLayout::LabelRole, ui_downwards_lbl); + ui_username_textbox = new QLineEdit(ui_form_layout_widget); + ui_username_textbox->setMaxLength(30); + ui_username_textbox->setText(p_ao_app->get_default_username()); - ui_downwards_cb = new QCheckBox(ui_form_layout_widget); - ui_downwards_cb->setChecked(p_ao_app->get_log_goes_downwards()); + ui_gameplay_form->setWidget(5, QFormLayout::FieldRole, ui_username_textbox); - ui_gameplay_form->setWidget(2, QFormLayout::FieldRole, ui_downwards_cb); + ui_showname_lbl = new QLabel(ui_form_layout_widget); + ui_showname_lbl->setText(tr("Custom shownames:")); + ui_showname_lbl->setToolTip( + tr("Gives the default value for the in-game 'Custom shownames' " + "tickbox, which in turn determines whether the client should " + "display custom in-character names.")); - ui_length_lbl = new QLabel(ui_form_layout_widget); - ui_length_lbl->setText(tr("Log length:")); - ui_length_lbl->setToolTip(tr("The amount of messages the IC chatlog will keep before " - "deleting older messages. A value of 0 or below counts as 'infinite'.")); + ui_gameplay_form->setWidget(6, QFormLayout::LabelRole, ui_showname_lbl); - ui_gameplay_form->setWidget(3, QFormLayout::LabelRole, ui_length_lbl); + ui_showname_cb = new QCheckBox(ui_form_layout_widget); + ui_showname_cb->setChecked(p_ao_app->get_showname_enabled_by_default()); - ui_length_spinbox = new QSpinBox(ui_form_layout_widget); - ui_length_spinbox->setMaximum(10000); - ui_length_spinbox->setValue(p_ao_app->get_max_log_size()); + ui_gameplay_form->setWidget(6, QFormLayout::FieldRole, ui_showname_cb); - ui_gameplay_form->setWidget(3, QFormLayout::FieldRole, ui_length_spinbox); + ui_net_divider = new QFrame(ui_form_layout_widget); + ui_net_divider->setFrameShape(QFrame::HLine); + ui_net_divider->setFrameShadow(QFrame::Sunken); - ui_log_names_divider = new QFrame(ui_form_layout_widget); - ui_log_names_divider->setFrameShape(QFrame::HLine); - ui_log_names_divider->setFrameShadow(QFrame::Sunken); + ui_gameplay_form->setWidget(7, QFormLayout::FieldRole, ui_net_divider); - ui_gameplay_form->setWidget(4, QFormLayout::FieldRole, ui_log_names_divider); + ui_ms_lbl = new QLabel(ui_form_layout_widget); + ui_ms_lbl->setText(tr("Backup MS:")); + ui_ms_lbl->setToolTip( + tr("If the built-in server lookups fail, the game will try the " + "address given here and use it as a backup master server address.")); - ui_username_lbl = new QLabel(ui_form_layout_widget); - ui_username_lbl->setText(tr("Default username:")); - ui_username_lbl->setToolTip(tr("Your OOC name will be automatically set to this value " - "when you join a server.")); + ui_gameplay_form->setWidget(8, QFormLayout::LabelRole, ui_ms_lbl); - ui_gameplay_form->setWidget(5, QFormLayout::LabelRole, ui_username_lbl); + QSettings *configini = ao_app->configini; + ui_ms_textbox = new QLineEdit(ui_form_layout_widget); + ui_ms_textbox->setText(configini->value("master", "").value()); - ui_username_textbox = new QLineEdit(ui_form_layout_widget); - ui_username_textbox->setMaxLength(30); - ui_username_textbox->setText(p_ao_app->get_default_username()); + ui_gameplay_form->setWidget(8, QFormLayout::FieldRole, ui_ms_textbox); - ui_gameplay_form->setWidget(5, QFormLayout::FieldRole, ui_username_textbox); + ui_discord_lbl = new QLabel(ui_form_layout_widget); + ui_discord_lbl->setText(tr("Discord:")); + ui_discord_lbl->setToolTip( + tr("Allows others on Discord to see what server you are in, " + "what character are you playing, and how long you have " + "been playing for.")); - ui_showname_lbl = new QLabel(ui_form_layout_widget); - ui_showname_lbl->setText(tr("Custom shownames:")); - ui_showname_lbl->setToolTip(tr("Gives the default value for the in-game 'Custom shownames' " - "tickbox, which in turn determines whether the client should " - "display custom in-character names.")); + ui_gameplay_form->setWidget(9, QFormLayout::LabelRole, ui_discord_lbl); - ui_gameplay_form->setWidget(6, QFormLayout::LabelRole, ui_showname_lbl); + ui_discord_cb = new QCheckBox(ui_form_layout_widget); + ui_discord_cb->setChecked(ao_app->is_discord_enabled()); - ui_showname_cb = new QCheckBox(ui_form_layout_widget); - ui_showname_cb->setChecked(p_ao_app->get_showname_enabled_by_default()); + ui_gameplay_form->setWidget(9, QFormLayout::FieldRole, ui_discord_cb); - ui_gameplay_form->setWidget(6, QFormLayout::FieldRole, ui_showname_cb); + // Here we start the callwords tab. + ui_callwords_tab = new QWidget(); + ui_settings_tabs->addTab(ui_callwords_tab, tr("Callwords")); - ui_net_divider = new QFrame(ui_form_layout_widget); - ui_net_divider->setFrameShape(QFrame::HLine); - ui_net_divider->setFrameShadow(QFrame::Sunken); + ui_callwords_widget = new QWidget(ui_callwords_tab); + ui_callwords_widget->setGeometry(QRect(10, 10, 361, 211)); - ui_gameplay_form->setWidget(7, QFormLayout::FieldRole, ui_net_divider); + ui_callwords_layout = new QVBoxLayout(ui_callwords_widget); + ui_callwords_layout->setContentsMargins(0, 0, 0, 0); - ui_ms_lbl = new QLabel(ui_form_layout_widget); - ui_ms_lbl->setText(tr("Backup MS:")); - ui_ms_lbl->setToolTip(tr("If the built-in server lookups fail, the game will try the " - "address given here and use it as a backup master server address.")); + ui_callwords_textbox = new QPlainTextEdit(ui_callwords_widget); + QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + sizePolicy.setHorizontalStretch(0); + sizePolicy.setVerticalStretch(0); + sizePolicy.setHeightForWidth( + ui_callwords_textbox->sizePolicy().hasHeightForWidth()); + ui_callwords_textbox->setSizePolicy(sizePolicy); - ui_gameplay_form->setWidget(8, QFormLayout::LabelRole, ui_ms_lbl); + // Let's fill the callwords text edit with the already present callwords. + ui_callwords_textbox->document()->clear(); + foreach (QString callword, p_ao_app->get_call_words()) { + ui_callwords_textbox->appendPlainText(callword); + } - QSettings* configini = ao_app->configini; - ui_ms_textbox = new QLineEdit(ui_form_layout_widget); - ui_ms_textbox->setText(configini->value("master", "").value()); + ui_callwords_layout->addWidget(ui_callwords_textbox); - ui_gameplay_form->setWidget(8, QFormLayout::FieldRole, ui_ms_textbox); + ui_callwords_explain_lbl = new QLabel(ui_callwords_widget); + ui_callwords_explain_lbl->setWordWrap(true); + ui_callwords_explain_lbl->setText( + tr("Enter as many callwords as you would like. These " + "are case insensitive. Make sure to leave every callword in its own " + "line!
    Do not leave a line with a space at the end -- you will be " + "alerted everytime someone uses a space in their " + "messages.")); - ui_discord_lbl = new QLabel(ui_form_layout_widget); - ui_discord_lbl->setText(tr("Discord:")); - ui_discord_lbl->setToolTip(tr("Allows others on Discord to see what server you are in, " - "what character are you playing, and how long you have " - "been playing for.")); + ui_callwords_layout->addWidget(ui_callwords_explain_lbl); - ui_gameplay_form->setWidget(9, QFormLayout::LabelRole, ui_discord_lbl); +// The audio tab. +#ifdef BASSAUDIO + ui_audio_tab = new QWidget(); + ui_settings_tabs->addTab(ui_audio_tab, tr("Audio")); - ui_discord_cb = new QCheckBox(ui_form_layout_widget); - ui_discord_cb->setChecked(ao_app->is_discord_enabled()); + ui_audio_widget = new QWidget(ui_audio_tab); + ui_audio_widget->setGeometry(QRect(10, 10, 361, 211)); - ui_gameplay_form->setWidget(9, QFormLayout::FieldRole, ui_discord_cb); + ui_audio_layout = new QFormLayout(ui_audio_widget); + ui_audio_layout->setLabelAlignment(Qt::AlignLeading | Qt::AlignLeft | + Qt::AlignVCenter); + ui_audio_layout->setFormAlignment(Qt::AlignLeading | Qt::AlignLeft | + Qt::AlignTop); + ui_audio_layout->setContentsMargins(0, 0, 0, 0); - // Here we start the callwords tab. - ui_callwords_tab = new QWidget(); - ui_settings_tabs->addTab(ui_callwords_tab, tr("Callwords")); + ui_audio_device_lbl = new QLabel(ui_audio_widget); + ui_audio_device_lbl->setText(tr("Audio device:")); + ui_audio_device_lbl->setToolTip(tr("Sets the audio device for all sounds.")); - ui_callwords_widget = new QWidget(ui_callwords_tab); - ui_callwords_widget->setGeometry(QRect(10, 10, 361, 211)); + ui_audio_layout->setWidget(0, QFormLayout::LabelRole, ui_audio_device_lbl); - ui_callwords_layout = new QVBoxLayout(ui_callwords_widget); - ui_callwords_layout->setContentsMargins(0,0,0,0); + ui_audio_device_combobox = new QComboBox(ui_audio_widget); - ui_callwords_textbox = new QPlainTextEdit(ui_callwords_widget); - QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - sizePolicy.setHorizontalStretch(0); - sizePolicy.setVerticalStretch(0); - sizePolicy.setHeightForWidth(ui_callwords_textbox->sizePolicy().hasHeightForWidth()); - ui_callwords_textbox->setSizePolicy(sizePolicy); + // Let's fill out the combobox with the available audio devices. Or don't if + // there is no audio + int a = 0; + BASS_DEVICEINFO info; - // Let's fill the callwords text edit with the already present callwords. - ui_callwords_textbox->document()->clear(); - foreach (QString callword, p_ao_app->get_call_words()) { - ui_callwords_textbox->appendPlainText(callword); - } + if (needs_default_audiodev()) { + ui_audio_device_combobox->addItem("default"); + } - ui_callwords_layout->addWidget(ui_callwords_textbox); + for (a = 0; BASS_GetDeviceInfo(a, &info); a++) { + ui_audio_device_combobox->addItem(info.name); + if (p_ao_app->get_audio_output_device() == info.name) + ui_audio_device_combobox->setCurrentIndex( + ui_audio_device_combobox->count() - 1); + } - ui_callwords_explain_lbl = new QLabel(ui_callwords_widget); - ui_callwords_explain_lbl->setWordWrap(true); - ui_callwords_explain_lbl->setText(tr("Enter as many callwords as you would like. These are case insensitive. Make sure to leave every callword in its own line!
    Do not leave a line with a space at the end -- you will be alerted everytime someone uses a space in their messages.")); + ui_audio_layout->setWidget(0, QFormLayout::FieldRole, + ui_audio_device_combobox); - ui_callwords_layout->addWidget(ui_callwords_explain_lbl); + ui_audio_volume_divider = new QFrame(ui_audio_widget); + ui_audio_volume_divider->setFrameShape(QFrame::HLine); + ui_audio_volume_divider->setFrameShadow(QFrame::Sunken); - // The audio tab. - #ifdef BASSAUDIO - ui_audio_tab = new QWidget(); - ui_settings_tabs->addTab(ui_audio_tab, tr("Audio")); + ui_audio_layout->setWidget(1, QFormLayout::FieldRole, + ui_audio_volume_divider); - ui_audio_widget = new QWidget(ui_audio_tab); - ui_audio_widget->setGeometry(QRect(10, 10, 361, 211)); + ui_music_volume_lbl = new QLabel(ui_audio_widget); + ui_music_volume_lbl->setText(tr("Music:")); + ui_music_volume_lbl->setToolTip(tr("Sets the music's default volume.")); - ui_audio_layout = new QFormLayout(ui_audio_widget); - ui_audio_layout->setLabelAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter); - ui_audio_layout->setFormAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop); - ui_audio_layout->setContentsMargins(0, 0, 0, 0); + ui_audio_layout->setWidget(2, QFormLayout::LabelRole, ui_music_volume_lbl); - ui_audio_device_lbl = new QLabel(ui_audio_widget); - ui_audio_device_lbl->setText(tr("Audio device:")); - ui_audio_device_lbl->setToolTip(tr("Sets the audio device for all sounds.")); + ui_music_volume_spinbox = new QSpinBox(ui_audio_widget); + ui_music_volume_spinbox->setValue(p_ao_app->get_default_music()); + ui_music_volume_spinbox->setMaximum(100); + ui_music_volume_spinbox->setSuffix("%"); - ui_audio_layout->setWidget(0, QFormLayout::LabelRole, ui_audio_device_lbl); + ui_audio_layout->setWidget(2, QFormLayout::FieldRole, + ui_music_volume_spinbox); - ui_audio_device_combobox = new QComboBox(ui_audio_widget); + ui_sfx_volume_lbl = new QLabel(ui_audio_widget); + ui_sfx_volume_lbl->setText(tr("SFX:")); + ui_sfx_volume_lbl->setToolTip( + tr("Sets the SFX's default volume. " + "Interjections and actual sound effects count as 'SFX'.")); - // Let's fill out the combobox with the available audio devices. Or don't if there is no audio - int a = 0; - BASS_DEVICEINFO info; + ui_audio_layout->setWidget(3, QFormLayout::LabelRole, ui_sfx_volume_lbl); - if (needs_default_audiodev()) - { - ui_audio_device_combobox->addItem("default"); - } + ui_sfx_volume_spinbox = new QSpinBox(ui_audio_widget); + ui_sfx_volume_spinbox->setValue(p_ao_app->get_default_sfx()); + ui_sfx_volume_spinbox->setMaximum(100); + ui_sfx_volume_spinbox->setSuffix("%"); - for (a = 0; BASS_GetDeviceInfo(a, &info); a++) - { - ui_audio_device_combobox->addItem(info.name); - if (p_ao_app->get_audio_output_device() == info.name) - ui_audio_device_combobox->setCurrentIndex(ui_audio_device_combobox->count()-1); - } + ui_audio_layout->setWidget(3, QFormLayout::FieldRole, ui_sfx_volume_spinbox); - ui_audio_layout->setWidget(0, QFormLayout::FieldRole, ui_audio_device_combobox); + ui_blips_volume_lbl = new QLabel(ui_audio_widget); + ui_blips_volume_lbl->setText(tr("Blips:")); + ui_blips_volume_lbl->setToolTip( + tr("Sets the volume of the blips, the talking sound effects.")); - ui_audio_volume_divider = new QFrame(ui_audio_widget); - ui_audio_volume_divider->setFrameShape(QFrame::HLine); - ui_audio_volume_divider->setFrameShadow(QFrame::Sunken); + ui_audio_layout->setWidget(4, QFormLayout::LabelRole, ui_blips_volume_lbl); - ui_audio_layout->setWidget(1, QFormLayout::FieldRole, ui_audio_volume_divider); + ui_blips_volume_spinbox = new QSpinBox(ui_audio_widget); + ui_blips_volume_spinbox->setValue(p_ao_app->get_default_blip()); + ui_blips_volume_spinbox->setMaximum(100); + ui_blips_volume_spinbox->setSuffix("%"); - ui_music_volume_lbl = new QLabel(ui_audio_widget); - ui_music_volume_lbl->setText(tr("Music:")); - ui_music_volume_lbl->setToolTip(tr("Sets the music's default volume.")); + ui_audio_layout->setWidget(4, QFormLayout::FieldRole, + ui_blips_volume_spinbox); - ui_audio_layout->setWidget(2, QFormLayout::LabelRole, ui_music_volume_lbl); + ui_volume_blip_divider = new QFrame(ui_audio_widget); + ui_volume_blip_divider->setFrameShape(QFrame::HLine); + ui_volume_blip_divider->setFrameShadow(QFrame::Sunken); - ui_music_volume_spinbox = new QSpinBox(ui_audio_widget); - ui_music_volume_spinbox->setValue(p_ao_app->get_default_music()); - ui_music_volume_spinbox->setMaximum(100); - ui_music_volume_spinbox->setSuffix("%"); + ui_audio_layout->setWidget(5, QFormLayout::FieldRole, ui_volume_blip_divider); - ui_audio_layout->setWidget(2, QFormLayout::FieldRole, ui_music_volume_spinbox); + ui_bliprate_lbl = new QLabel(ui_audio_widget); + ui_bliprate_lbl->setText(tr("Blip rate:")); + ui_bliprate_lbl->setToolTip( + tr("Sets the delay between playing the blip sounds.")); - ui_sfx_volume_lbl = new QLabel(ui_audio_widget); - ui_sfx_volume_lbl->setText(tr("SFX:")); - ui_sfx_volume_lbl->setToolTip(tr("Sets the SFX's default volume. " - "Interjections and actual sound effects count as 'SFX'.")); + ui_audio_layout->setWidget(6, QFormLayout::LabelRole, ui_bliprate_lbl); - ui_audio_layout->setWidget(3, QFormLayout::LabelRole, ui_sfx_volume_lbl); + ui_bliprate_spinbox = new QSpinBox(ui_audio_widget); + ui_bliprate_spinbox->setValue(p_ao_app->read_blip_rate()); + ui_bliprate_spinbox->setMinimum(1); - ui_sfx_volume_spinbox = new QSpinBox(ui_audio_widget); - ui_sfx_volume_spinbox->setValue(p_ao_app->get_default_sfx()); - ui_sfx_volume_spinbox->setMaximum(100); - ui_sfx_volume_spinbox->setSuffix("%"); + ui_audio_layout->setWidget(6, QFormLayout::FieldRole, ui_bliprate_spinbox); - ui_audio_layout->setWidget(3, QFormLayout::FieldRole, ui_sfx_volume_spinbox); + ui_blank_blips_lbl = new QLabel(ui_audio_widget); + ui_blank_blips_lbl->setText(tr("Blank blips:")); + ui_blank_blips_lbl->setToolTip( + tr("If true, the game will play a blip sound even " + "when a space is 'being said'.")); - ui_blips_volume_lbl = new QLabel(ui_audio_widget); - ui_blips_volume_lbl->setText(tr("Blips:")); - ui_blips_volume_lbl->setToolTip(tr("Sets the volume of the blips, the talking sound effects.")); + ui_audio_layout->setWidget(7, QFormLayout::LabelRole, ui_blank_blips_lbl); - ui_audio_layout->setWidget(4, QFormLayout::LabelRole, ui_blips_volume_lbl); + ui_blank_blips_cb = new QCheckBox(ui_audio_widget); + ui_blank_blips_cb->setChecked(p_ao_app->get_blank_blip()); - ui_blips_volume_spinbox = new QSpinBox(ui_audio_widget); - ui_blips_volume_spinbox->setValue(p_ao_app->get_default_blip()); - ui_blips_volume_spinbox->setMaximum(100); - ui_blips_volume_spinbox->setSuffix("%"); + ui_audio_layout->setWidget(7, QFormLayout::FieldRole, ui_blank_blips_cb); +#endif - ui_audio_layout->setWidget(4, QFormLayout::FieldRole, ui_blips_volume_spinbox); + // The casing tab! + ui_casing_tab = new QWidget(); + ui_settings_tabs->addTab(ui_casing_tab, tr("Casing")); - ui_volume_blip_divider = new QFrame(ui_audio_widget); - ui_volume_blip_divider->setFrameShape(QFrame::HLine); - ui_volume_blip_divider->setFrameShadow(QFrame::Sunken); + ui_casing_widget = new QWidget(ui_casing_tab); + ui_casing_widget->setGeometry(QRect(10, 10, 361, 211)); - ui_audio_layout->setWidget(5, QFormLayout::FieldRole, ui_volume_blip_divider); + ui_casing_layout = new QFormLayout(ui_casing_widget); + ui_casing_layout->setLabelAlignment(Qt::AlignLeading | Qt::AlignLeft | + Qt::AlignVCenter); + ui_casing_layout->setFormAlignment(Qt::AlignLeading | Qt::AlignLeft | + Qt::AlignTop); + ui_casing_layout->setContentsMargins(0, 0, 0, 0); - ui_bliprate_lbl = new QLabel(ui_audio_widget); - ui_bliprate_lbl->setText(tr("Blip rate:")); - ui_bliprate_lbl->setToolTip(tr("Sets the delay between playing the blip sounds.")); + // -- SERVER SUPPORTS CASING - ui_audio_layout->setWidget(6, QFormLayout::LabelRole, ui_bliprate_lbl); + ui_casing_supported_lbl = new QLabel(ui_casing_widget); + if (ao_app->casing_alerts_enabled) + ui_casing_supported_lbl->setText(tr("This server supports case alerts.")); + else + ui_casing_supported_lbl->setText( + tr("This server does not support case alerts.")); + ui_casing_supported_lbl->setToolTip(tr("Pretty self-explanatory.")); - ui_bliprate_spinbox = new QSpinBox(ui_audio_widget); - ui_bliprate_spinbox->setValue(p_ao_app->read_blip_rate()); - ui_bliprate_spinbox->setMinimum(1); + ui_casing_layout->setWidget(0, QFormLayout::FieldRole, + ui_casing_supported_lbl); - ui_audio_layout->setWidget(6, QFormLayout::FieldRole, ui_bliprate_spinbox); + // -- CASE ANNOUNCEMENTS - ui_blank_blips_lbl = new QLabel(ui_audio_widget); - ui_blank_blips_lbl->setText(tr("Blank blips:")); - ui_blank_blips_lbl->setToolTip(tr("If true, the game will play a blip sound even " - "when a space is 'being said'.")); + ui_casing_enabled_lbl = new QLabel(ui_casing_widget); + ui_casing_enabled_lbl->setText(tr("Casing:")); + ui_casing_enabled_lbl->setToolTip( + tr("If checked, you will get alerts about case " + "announcements.")); - ui_audio_layout->setWidget(7, QFormLayout::LabelRole, ui_blank_blips_lbl); + ui_casing_layout->setWidget(1, QFormLayout::LabelRole, ui_casing_enabled_lbl); - ui_blank_blips_cb = new QCheckBox(ui_audio_widget); - ui_blank_blips_cb->setChecked(p_ao_app->get_blank_blip()); + ui_casing_enabled_cb = new QCheckBox(ui_casing_widget); + ui_casing_enabled_cb->setChecked(ao_app->get_casing_enabled()); - ui_audio_layout->setWidget(7, QFormLayout::FieldRole, ui_blank_blips_cb); - #endif + ui_casing_layout->setWidget(1, QFormLayout::FieldRole, ui_casing_enabled_cb); - // The casing tab! - ui_casing_tab = new QWidget(); - ui_settings_tabs->addTab(ui_casing_tab, tr("Casing")); + // -- DEFENSE ANNOUNCEMENTS - ui_casing_widget = new QWidget(ui_casing_tab); - ui_casing_widget->setGeometry(QRect(10,10, 361, 211)); + ui_casing_def_lbl = new QLabel(ui_casing_widget); + ui_casing_def_lbl->setText(tr("Defense:")); + ui_casing_def_lbl->setToolTip(tr("If checked, you will get alerts about case " + "announcements if a defense spot is open.")); - ui_casing_layout = new QFormLayout(ui_casing_widget); - ui_casing_layout->setLabelAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter); - ui_casing_layout->setFormAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop); - ui_casing_layout->setContentsMargins(0, 0, 0, 0); + ui_casing_layout->setWidget(2, QFormLayout::LabelRole, ui_casing_def_lbl); - // -- SERVER SUPPORTS CASING + ui_casing_def_cb = new QCheckBox(ui_casing_widget); + ui_casing_def_cb->setChecked(ao_app->get_casing_defence_enabled()); - ui_casing_supported_lbl = new QLabel(ui_casing_widget); - if (ao_app->casing_alerts_enabled) - ui_casing_supported_lbl->setText(tr("This server supports case alerts.")); - else - ui_casing_supported_lbl->setText(tr("This server does not support case alerts.")); - ui_casing_supported_lbl->setToolTip(tr("Pretty self-explanatory.")); + ui_casing_layout->setWidget(2, QFormLayout::FieldRole, ui_casing_def_cb); - ui_casing_layout->setWidget(0, QFormLayout::FieldRole, ui_casing_supported_lbl); + // -- PROSECUTOR ANNOUNCEMENTS - // -- CASE ANNOUNCEMENTS + ui_casing_pro_lbl = new QLabel(ui_casing_widget); + ui_casing_pro_lbl->setText(tr("Prosecution:")); + ui_casing_pro_lbl->setToolTip( + tr("If checked, you will get alerts about case " + "announcements if a prosecutor spot is open.")); - ui_casing_enabled_lbl = new QLabel(ui_casing_widget); - ui_casing_enabled_lbl->setText(tr("Casing:")); - ui_casing_enabled_lbl->setToolTip(tr("If checked, you will get alerts about case " - "announcements.")); + ui_casing_layout->setWidget(3, QFormLayout::LabelRole, ui_casing_pro_lbl); - ui_casing_layout->setWidget(1, QFormLayout::LabelRole, ui_casing_enabled_lbl); + ui_casing_pro_cb = new QCheckBox(ui_casing_widget); + ui_casing_pro_cb->setChecked(ao_app->get_casing_prosecution_enabled()); - ui_casing_enabled_cb = new QCheckBox(ui_casing_widget); - ui_casing_enabled_cb->setChecked(ao_app->get_casing_enabled()); + ui_casing_layout->setWidget(3, QFormLayout::FieldRole, ui_casing_pro_cb); - ui_casing_layout->setWidget(1, QFormLayout::FieldRole, ui_casing_enabled_cb); + // -- JUDGE ANNOUNCEMENTS - // -- DEFENSE ANNOUNCEMENTS + ui_casing_jud_lbl = new QLabel(ui_casing_widget); + ui_casing_jud_lbl->setText(tr("Judge:")); + ui_casing_jud_lbl->setToolTip(tr("If checked, you will get alerts about case " + "announcements if the judge spot is open.")); - ui_casing_def_lbl = new QLabel(ui_casing_widget); - ui_casing_def_lbl->setText(tr("Defense:")); - ui_casing_def_lbl->setToolTip(tr("If checked, you will get alerts about case " - "announcements if a defense spot is open.")); + ui_casing_layout->setWidget(4, QFormLayout::LabelRole, ui_casing_jud_lbl); - ui_casing_layout->setWidget(2, QFormLayout::LabelRole, ui_casing_def_lbl); + ui_casing_jud_cb = new QCheckBox(ui_casing_widget); + ui_casing_jud_cb->setChecked(ao_app->get_casing_judge_enabled()); - ui_casing_def_cb = new QCheckBox(ui_casing_widget); - ui_casing_def_cb->setChecked(ao_app->get_casing_defence_enabled()); + ui_casing_layout->setWidget(4, QFormLayout::FieldRole, ui_casing_jud_cb); - ui_casing_layout->setWidget(2, QFormLayout::FieldRole, ui_casing_def_cb); + // -- JUROR ANNOUNCEMENTS - // -- PROSECUTOR ANNOUNCEMENTS + ui_casing_jur_lbl = new QLabel(ui_casing_widget); + ui_casing_jur_lbl->setText(tr("Juror:")); + ui_casing_jur_lbl->setToolTip(tr("If checked, you will get alerts about case " + "announcements if a juror spot is open.")); - ui_casing_pro_lbl = new QLabel(ui_casing_widget); - ui_casing_pro_lbl->setText(tr("Prosecution:")); - ui_casing_pro_lbl->setToolTip(tr("If checked, you will get alerts about case " - "announcements if a prosecutor spot is open.")); + ui_casing_layout->setWidget(5, QFormLayout::LabelRole, ui_casing_jur_lbl); - ui_casing_layout->setWidget(3, QFormLayout::LabelRole, ui_casing_pro_lbl); + ui_casing_jur_cb = new QCheckBox(ui_casing_widget); + ui_casing_jur_cb->setChecked(ao_app->get_casing_juror_enabled()); - ui_casing_pro_cb = new QCheckBox(ui_casing_widget); - ui_casing_pro_cb->setChecked(ao_app->get_casing_prosecution_enabled()); + ui_casing_layout->setWidget(5, QFormLayout::FieldRole, ui_casing_jur_cb); - ui_casing_layout->setWidget(3, QFormLayout::FieldRole, ui_casing_pro_cb); + // -- STENO ANNOUNCEMENTS - // -- JUDGE ANNOUNCEMENTS + ui_casing_steno_lbl = new QLabel(ui_casing_widget); + ui_casing_steno_lbl->setText(tr("Stenographer:")); + ui_casing_steno_lbl->setToolTip( + tr("If checked, you will get alerts about case " + "announcements if a stenographer spot is open.")); - ui_casing_jud_lbl = new QLabel(ui_casing_widget); - ui_casing_jud_lbl->setText(tr("Judge:")); - ui_casing_jud_lbl->setToolTip(tr("If checked, you will get alerts about case " - "announcements if the judge spot is open.")); + ui_casing_layout->setWidget(6, QFormLayout::LabelRole, ui_casing_steno_lbl); - ui_casing_layout->setWidget(4, QFormLayout::LabelRole, ui_casing_jud_lbl); + ui_casing_steno_cb = new QCheckBox(ui_casing_widget); + ui_casing_steno_cb->setChecked(ao_app->get_casing_steno_enabled()); - ui_casing_jud_cb = new QCheckBox(ui_casing_widget); - ui_casing_jud_cb->setChecked(ao_app->get_casing_judge_enabled()); + ui_casing_layout->setWidget(6, QFormLayout::FieldRole, ui_casing_steno_cb); - ui_casing_layout->setWidget(4, QFormLayout::FieldRole, ui_casing_jud_cb); + // -- CM ANNOUNCEMENTS - // -- JUROR ANNOUNCEMENTS + ui_casing_cm_lbl = new QLabel(ui_casing_widget); + ui_casing_cm_lbl->setText(tr("CM:")); + ui_casing_cm_lbl->setToolTip( + tr("If checked, you will appear amongst the potential " + "CMs on the server.")); - ui_casing_jur_lbl = new QLabel(ui_casing_widget); - ui_casing_jur_lbl->setText(tr("Juror:")); - ui_casing_jur_lbl->setToolTip(tr("If checked, you will get alerts about case " - "announcements if a juror spot is open.")); + ui_casing_layout->setWidget(7, QFormLayout::LabelRole, ui_casing_cm_lbl); - ui_casing_layout->setWidget(5, QFormLayout::LabelRole, ui_casing_jur_lbl); + ui_casing_cm_cb = new QCheckBox(ui_casing_widget); + ui_casing_cm_cb->setChecked(ao_app->get_casing_cm_enabled()); - ui_casing_jur_cb = new QCheckBox(ui_casing_widget); - ui_casing_jur_cb->setChecked(ao_app->get_casing_juror_enabled()); + ui_casing_layout->setWidget(7, QFormLayout::FieldRole, ui_casing_cm_cb); - ui_casing_layout->setWidget(5, QFormLayout::FieldRole, ui_casing_jur_cb); + // -- CM CASES ANNOUNCEMENTS - // -- STENO ANNOUNCEMENTS + ui_casing_cm_cases_lbl = new QLabel(ui_casing_widget); + ui_casing_cm_cases_lbl->setText(tr("Hosting cases:")); + ui_casing_cm_cases_lbl->setToolTip( + tr("If you're a CM, enter what cases you are " + "willing to host.")); - ui_casing_steno_lbl = new QLabel(ui_casing_widget); - ui_casing_steno_lbl->setText(tr("Stenographer:")); - ui_casing_steno_lbl->setToolTip(tr("If checked, you will get alerts about case " - "announcements if a stenographer spot is open.")); + ui_casing_layout->setWidget(8, QFormLayout::LabelRole, + ui_casing_cm_cases_lbl); - ui_casing_layout->setWidget(6, QFormLayout::LabelRole, ui_casing_steno_lbl); + ui_casing_cm_cases_textbox = new QLineEdit(ui_casing_widget); + ui_casing_cm_cases_textbox->setText(ao_app->get_casing_can_host_cases()); - ui_casing_steno_cb = new QCheckBox(ui_casing_widget); - ui_casing_steno_cb->setChecked(ao_app->get_casing_steno_enabled()); + ui_casing_layout->setWidget(8, QFormLayout::FieldRole, + ui_casing_cm_cases_textbox); - ui_casing_layout->setWidget(6, QFormLayout::FieldRole, ui_casing_steno_cb); - - // -- CM ANNOUNCEMENTS - - ui_casing_cm_lbl = new QLabel(ui_casing_widget); - ui_casing_cm_lbl->setText(tr("CM:")); - ui_casing_cm_lbl->setToolTip(tr("If checked, you will appear amongst the potential " - "CMs on the server.")); - - ui_casing_layout->setWidget(7, QFormLayout::LabelRole, ui_casing_cm_lbl); - - ui_casing_cm_cb = new QCheckBox(ui_casing_widget); - ui_casing_cm_cb->setChecked(ao_app->get_casing_cm_enabled()); - - ui_casing_layout->setWidget(7, QFormLayout::FieldRole, ui_casing_cm_cb); - - // -- CM CASES ANNOUNCEMENTS - - ui_casing_cm_cases_lbl = new QLabel(ui_casing_widget); - ui_casing_cm_cases_lbl->setText(tr("Hosting cases:")); - ui_casing_cm_cases_lbl->setToolTip(tr("If you're a CM, enter what cases you are " - "willing to host.")); - - ui_casing_layout->setWidget(8, QFormLayout::LabelRole, ui_casing_cm_cases_lbl); - - ui_casing_cm_cases_textbox = new QLineEdit(ui_casing_widget); - ui_casing_cm_cases_textbox->setText(ao_app->get_casing_can_host_cases()); - - ui_casing_layout->setWidget(8, QFormLayout::FieldRole, ui_casing_cm_cases_textbox); - - // When we're done, we should continue the updates! - setUpdatesEnabled(true); + // When we're done, we should continue the updates! + setUpdatesEnabled(true); } void AOOptionsDialog::save_pressed() { - // Save everything into the config.ini. - QSettings* configini = ao_app->configini; + // Save everything into the config.ini. + QSettings *configini = ao_app->configini; - configini->setValue("theme", ui_theme_combobox->currentText()); - configini->setValue("log_goes_downwards", ui_downwards_cb->isChecked()); - configini->setValue("log_maximum", ui_length_spinbox->value()); - configini->setValue("default_username", ui_username_textbox->text()); - configini->setValue("show_custom_shownames", ui_showname_cb->isChecked()); - configini->setValue("master", ui_ms_textbox->text()); - configini->setValue("discord", ui_discord_cb->isChecked()); + configini->setValue("theme", ui_theme_combobox->currentText()); + configini->setValue("log_goes_downwards", ui_downwards_cb->isChecked()); + configini->setValue("log_maximum", ui_length_spinbox->value()); + configini->setValue("default_username", ui_username_textbox->text()); + configini->setValue("show_custom_shownames", ui_showname_cb->isChecked()); + configini->setValue("master", ui_ms_textbox->text()); + configini->setValue("discord", ui_discord_cb->isChecked()); - QFile* callwordsini = new QFile(ao_app->get_base_path() + "callwords.ini"); - - if (!callwordsini->open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) - { - // Nevermind! - } - else - { - QTextStream out(callwordsini); - out << ui_callwords_textbox->toPlainText(); - callwordsini->close(); - } - - configini->setValue("default_audio_device", ui_audio_device_combobox->currentText()); - configini->setValue("default_music", ui_music_volume_spinbox->value()); - configini->setValue("default_sfx", ui_sfx_volume_spinbox->value()); - configini->setValue("default_blip", ui_blips_volume_spinbox->value()); - configini->setValue("blip_rate", ui_bliprate_spinbox->value()); - configini->setValue("blank_blip", ui_blank_blips_cb->isChecked()); - - configini->setValue("casing_enabled", ui_casing_enabled_cb->isChecked()); - configini->setValue("casing_defence_enabled", ui_casing_def_cb->isChecked()); - configini->setValue("casing_prosecution_enabled", ui_casing_pro_cb->isChecked()); - configini->setValue("casing_judge_enabled", ui_casing_jud_cb->isChecked()); - configini->setValue("casing_juror_enabled", ui_casing_jur_cb->isChecked()); - configini->setValue("casing_steno_enabled", ui_casing_steno_cb->isChecked()); - configini->setValue("casing_cm_enabled", ui_casing_cm_cb->isChecked()); - configini->setValue("casing_can_host_cases", ui_casing_cm_cases_textbox->text()); + QFile *callwordsini = new QFile(ao_app->get_base_path() + "callwords.ini"); + if (!callwordsini->open(QIODevice::WriteOnly | QIODevice::Truncate | + QIODevice::Text)) { + // Nevermind! + } + else { + QTextStream out(callwordsini); + out << ui_callwords_textbox->toPlainText(); callwordsini->close(); - done(0); + } + + configini->setValue("default_audio_device", + ui_audio_device_combobox->currentText()); + configini->setValue("default_music", ui_music_volume_spinbox->value()); + configini->setValue("default_sfx", ui_sfx_volume_spinbox->value()); + configini->setValue("default_blip", ui_blips_volume_spinbox->value()); + configini->setValue("blip_rate", ui_bliprate_spinbox->value()); + configini->setValue("blank_blip", ui_blank_blips_cb->isChecked()); + + configini->setValue("casing_enabled", ui_casing_enabled_cb->isChecked()); + configini->setValue("casing_defence_enabled", ui_casing_def_cb->isChecked()); + configini->setValue("casing_prosecution_enabled", + ui_casing_pro_cb->isChecked()); + configini->setValue("casing_judge_enabled", ui_casing_jud_cb->isChecked()); + configini->setValue("casing_juror_enabled", ui_casing_jur_cb->isChecked()); + configini->setValue("casing_steno_enabled", ui_casing_steno_cb->isChecked()); + configini->setValue("casing_cm_enabled", ui_casing_cm_cb->isChecked()); + configini->setValue("casing_can_host_cases", + ui_casing_cm_cases_textbox->text()); + + callwordsini->close(); + done(0); } -void AOOptionsDialog::discard_pressed() -{ - done(0); -} +void AOOptionsDialog::discard_pressed() { done(0); } -#if (defined (_WIN32) || defined (_WIN64)) -bool AOOptionsDialog::needs_default_audiodev() -{ - return true; -} -#elif (defined (LINUX) || defined (__linux__)) -bool AOOptionsDialog::needs_default_audiodev() -{ - return false; -} +#if (defined(_WIN32) || defined(_WIN64)) +bool AOOptionsDialog::needs_default_audiodev() { return true; } +#elif (defined(LINUX) || defined(__linux__)) +bool AOOptionsDialog::needs_default_audiodev() { return false; } #elif defined __APPLE__ -bool AOOptionsDialog::needs_default_audiodev() -{ - return true; -} +bool AOOptionsDialog::needs_default_audiodev() { return true; } #else #error This operating system is not supported. #endif diff --git a/src/aopacket.cpp b/src/aopacket.cpp index b957efe..6afd39e 100644 --- a/src/aopacket.cpp +++ b/src/aopacket.cpp @@ -8,8 +8,7 @@ AOPacket::AOPacket(QString p_packet_string) m_header = packet_contents.at(0); - for(int n_string = 1 ; n_string < packet_contents.size() - 1 ; ++n_string) - { + for (int n_string = 1; n_string < packet_contents.size() - 1; ++n_string) { m_contents.append(packet_contents.at(n_string)); } } @@ -20,23 +19,18 @@ AOPacket::AOPacket(QString p_header, QStringList &p_contents) m_contents = p_contents; } -AOPacket::~AOPacket() -{ - -} +AOPacket::~AOPacket() {} QString AOPacket::to_string() { QString f_string = m_header; - for (QString i_string : m_contents) - { + for (QString i_string : m_contents) { f_string += ("#" + i_string); } f_string += "#%"; - if (encrypted) return "#" + f_string; else @@ -59,10 +53,12 @@ void AOPacket::decrypt_header(unsigned int p_key) void AOPacket::net_encode() { - for (int n_element = 0 ; n_element < m_contents.size() ; ++n_element) - { + for (int n_element = 0; n_element < m_contents.size(); ++n_element) { QString f_element = m_contents.at(n_element); - f_element.replace("#", "").replace("%", "").replace("$", "").replace("&", ""); + f_element.replace("#", "") + .replace("%", "") + .replace("$", "") + .replace("&", ""); m_contents.removeAt(n_element); m_contents.insert(n_element, f_element); @@ -71,13 +67,14 @@ void AOPacket::net_encode() void AOPacket::net_decode() { - for (int n_element = 0 ; n_element < m_contents.size() ; ++n_element) - { + for (int n_element = 0; n_element < m_contents.size(); ++n_element) { QString f_element = m_contents.at(n_element); - f_element.replace("", "#").replace("", "%").replace("", "$").replace("", "&"); + f_element.replace("", "#") + .replace("", "%") + .replace("", "$") + .replace("", "&"); m_contents.removeAt(n_element); m_contents.insert(n_element, f_element); } } - diff --git a/src/aoscene.cpp b/src/aoscene.cpp index 344522b..aad6c10 100644 --- a/src/aoscene.cpp +++ b/src/aoscene.cpp @@ -12,7 +12,8 @@ AOScene::AOScene(QWidget *parent, AOApplication *p_ao_app) : QLabel(parent) void AOScene::set_image(QString p_image) { QString background_path = ao_app->get_background_path(p_image + ".png"); - QString animated_background_path = ao_app->get_background_path(p_image + ".gif"); + QString animated_background_path = + ao_app->get_background_path(p_image + ".gif"); QString default_path = ao_app->get_default_background_path(p_image + ".png"); QPixmap background(background_path); @@ -28,25 +29,22 @@ void AOScene::set_image(QString p_image) m_movie->setFileName(animated_background_path); m_movie->setScaledSize(QSize(w, h)); - if (m_movie->isValid()) - { + if (m_movie->isValid()) { this->setMovie(m_movie); m_movie->start(); } - else if (file_exists(background_path)) - { + else if (file_exists(background_path)) { this->setPixmap(background.scaled(w, h)); } - else - { + else { this->setPixmap(default_bg.scaled(w, h)); } } void AOScene::set_legacy_desk(QString p_image) { - //vanilla desks vary in both width and height. in order to make that work with viewport rescaling, - //some INTENSE math is needed. + // vanilla desks vary in both width and height. in order to make that work + // with viewport rescaling, some INTENSE math is needed. QString desk_path = ao_app->get_background_path(p_image); QString default_path = ao_app->get_default_background_path(p_image); @@ -61,16 +59,16 @@ void AOScene::set_legacy_desk(QString p_image) int vp_width = m_parent->width(); int vp_height = m_parent->height(); - //double y_modifier = 147 / 192; - //double w_modifier = vp_width / 256; + // double y_modifier = 147 / 192; + // double w_modifier = vp_width / 256; double h_modifier = vp_height / 192; - //int final_y = y_modifier * vp_height; - //int final_w = w_modifier * f_desk.width(); + // int final_y = y_modifier * vp_height; + // int final_w = w_modifier * f_desk.width(); int final_h = static_cast(h_modifier * f_desk.height()); - //this->resize(final_w, final_h); - //this->setPixmap(f_desk.scaled(final_w, final_h)); + // this->resize(final_w, final_h); + // this->setPixmap(f_desk.scaled(final_w, final_h)); this->resize(vp_width, final_h); this->setPixmap(f_desk.scaled(vp_width, final_h)); } diff --git a/src/aosfxplayer.cpp b/src/aosfxplayer.cpp index 710d7a8..543da5c 100644 --- a/src/aosfxplayer.cpp +++ b/src/aosfxplayer.cpp @@ -1,7 +1,7 @@ #include "aosfxplayer.h" #include "file_functions.h" -#if defined(BASSAUDIO) //Using bass.dll for sfx +#if defined(BASSAUDIO) // Using bass.dll for sfx AOSfxPlayer::AOSfxPlayer(QWidget *parent, AOApplication *p_ao_app) { m_parent = parent; @@ -11,7 +11,7 @@ AOSfxPlayer::AOSfxPlayer(QWidget *parent, AOApplication *p_ao_app) void AOSfxPlayer::play(QString p_sfx, QString p_char, QString shout) { BASS_ChannelStop(m_stream); - + QString misc_path = ""; QString char_path = ""; QString sound_path = ao_app->get_sounds_path(p_sfx); @@ -24,13 +24,15 @@ void AOSfxPlayer::play(QString p_sfx, QString p_char, QString shout) QString f_path; if (file_exists(char_path)) - f_path = char_path; + f_path = char_path; else if (file_exists(misc_path)) f_path = misc_path; else f_path = sound_path; - m_stream = BASS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE); + m_stream = BASS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, + BASS_STREAM_AUTOFREE | BASS_UNICODE | + BASS_ASYNCFILE); set_volume(m_volume); @@ -39,10 +41,7 @@ void AOSfxPlayer::play(QString p_sfx, QString p_char, QString shout) BASS_ChannelPlay(m_stream, false); } -void AOSfxPlayer::stop() -{ - BASS_ChannelStop(m_stream); -} +void AOSfxPlayer::stop() { BASS_ChannelStop(m_stream); } void AOSfxPlayer::set_volume(int p_value) { @@ -50,7 +49,7 @@ void AOSfxPlayer::set_volume(int p_value) float volume = p_value / 100.0f; BASS_ChannelSetAttribute(m_stream, BASS_ATTRIB_VOL, volume); } -#elif defined(QTAUDIO) //Using Qt's QSoundEffect class +#elif defined(QTAUDIO) // Using Qt's QSoundEffect class AOSfxPlayer::AOSfxPlayer(QWidget *parent, AOApplication *p_ao_app) { m_parent = parent; @@ -73,26 +72,23 @@ void AOSfxPlayer::play(QString p_sfx, QString p_char, QString shout) QString f_path; if (file_exists(char_path)) - f_path = char_path; + f_path = char_path; else if (file_exists(misc_path)) f_path = misc_path; else f_path = sound_path; - if (file_exists(f_path)) //if its missing, it will glitch out + if (file_exists(f_path)) // if its missing, it will glitch out { - m_sfx.setSource(QUrl::fromLocalFile(f_path)); + m_sfx.setSource(QUrl::fromLocalFile(f_path)); - set_volume(m_volume); + set_volume(m_volume); - m_sfx.play(); + m_sfx.play(); } } -void AOSfxPlayer::stop() -{ - m_sfx.stop(); -} +void AOSfxPlayer::stop() { m_sfx.stop(); } void AOSfxPlayer::set_volume(int p_value) { @@ -106,18 +102,9 @@ AOSfxPlayer::AOSfxPlayer(QWidget *parent, AOApplication *p_ao_app) ao_app = p_ao_app; } -void AOSfxPlayer::play(QString p_sfx, QString p_char, QString shout) -{ +void AOSfxPlayer::play(QString p_sfx, QString p_char, QString shout) {} -} +void AOSfxPlayer::stop() {} -void AOSfxPlayer::stop() -{ - -} - -void AOSfxPlayer::set_volume(int p_value) -{ - -} +void AOSfxPlayer::set_volume(int p_value) {} #endif diff --git a/src/aotextarea.cpp b/src/aotextarea.cpp index 5e14632..ebc75e2 100644 --- a/src/aotextarea.cpp +++ b/src/aotextarea.cpp @@ -1,24 +1,26 @@ #include "aotextarea.h" -AOTextArea::AOTextArea(QWidget *p_parent) : QTextBrowser(p_parent) -{ +AOTextArea::AOTextArea(QWidget *p_parent) : QTextBrowser(p_parent) {} -} - -void AOTextArea::append_chatmessage(QString p_name, QString p_message, QString p_colour) +void AOTextArea::append_chatmessage(QString p_name, QString p_message, + QString p_colour) { const QTextCursor old_cursor = this->textCursor(); const int old_scrollbar_value = this->verticalScrollBar()->value(); - const bool is_scrolled_down = old_scrollbar_value == this->verticalScrollBar()->maximum(); + const bool is_scrolled_down = + old_scrollbar_value == this->verticalScrollBar()->maximum(); this->moveCursor(QTextCursor::End); this->append(""); - this->insertHtml("" + p_name.toHtmlEscaped() + ": "); + this->insertHtml("" + p_name.toHtmlEscaped() + + ": "); - //cheap workarounds ahoy + // cheap workarounds ahoy p_message += " "; - QString result = p_message.toHtmlEscaped().replace("\n", "
    ").replace(omnis_dank_url_regex, "\\1" ); + QString result = p_message.toHtmlEscaped() + .replace("\n", "
    ") + .replace(omnis_dank_url_regex, "\\1"); this->insertHtml(result); @@ -29,32 +31,35 @@ void AOTextArea::append_error(QString p_message) { const QTextCursor old_cursor = this->textCursor(); const int old_scrollbar_value = this->verticalScrollBar()->value(); - const bool is_scrolled_down = old_scrollbar_value == this->verticalScrollBar()->maximum(); + const bool is_scrolled_down = + old_scrollbar_value == this->verticalScrollBar()->maximum(); this->moveCursor(QTextCursor::End); this->append(""); p_message += " "; - QString result = p_message.replace("\n", "
    ").replace(omnis_dank_url_regex, "\\1" ); + QString result = p_message.replace("\n", "
    ") + .replace(omnis_dank_url_regex, "\\1"); this->insertHtml("" + result + ""); this->auto_scroll(old_cursor, old_scrollbar_value, is_scrolled_down); } -void AOTextArea::auto_scroll(QTextCursor old_cursor, int old_scrollbar_value, bool is_scrolled_down) +void AOTextArea::auto_scroll(QTextCursor old_cursor, int old_scrollbar_value, + bool is_scrolled_down) { - if (old_cursor.hasSelection() || !is_scrolled_down) - { - // The user has selected text or scrolled away from the bottom: maintain position. - this->setTextCursor(old_cursor); - this->verticalScrollBar()->setValue(old_scrollbar_value); + if (old_cursor.hasSelection() || !is_scrolled_down) { + // The user has selected text or scrolled away from the bottom: maintain + // position. + this->setTextCursor(old_cursor); + this->verticalScrollBar()->setValue(old_scrollbar_value); } - else - { - // The user hasn't selected any text and the scrollbar is at the bottom: scroll to the bottom. - this->moveCursor(QTextCursor::End); - this->verticalScrollBar()->setValue(this->verticalScrollBar()->maximum()); + else { + // The user hasn't selected any text and the scrollbar is at the bottom: + // scroll to the bottom. + this->moveCursor(QTextCursor::End); + this->verticalScrollBar()->setValue(this->verticalScrollBar()->maximum()); } } diff --git a/src/aotextedit.cpp b/src/aotextedit.cpp index 30e48b7..22d9a62 100644 --- a/src/aotextedit.cpp +++ b/src/aotextedit.cpp @@ -4,7 +4,7 @@ AOTextEdit::AOTextEdit(QWidget *parent) : QPlainTextEdit(parent) { this->setReadOnly(true); - //connect(this, SIGNAL(returnPressed()), this, SLOT(on_enter_pressed())); + // connect(this, SIGNAL(returnPressed()), this, SLOT(on_enter_pressed())); } void AOTextEdit::mouseDoubleClickEvent(QMouseEvent *e) @@ -14,8 +14,4 @@ void AOTextEdit::mouseDoubleClickEvent(QMouseEvent *e) this->setReadOnly(false); } -void AOTextEdit::on_enter_pressed() -{ - this->setReadOnly(true); -} - +void AOTextEdit::on_enter_pressed() { this->setReadOnly(true); } diff --git a/src/charselect.cpp b/src/charselect.cpp index 4987cf5..c207d57 100644 --- a/src/charselect.cpp +++ b/src/charselect.cpp @@ -1,8 +1,8 @@ #include "courtroom.h" #include "lobby.h" -#include "file_functions.h" #include "debug_functions.h" +#include "file_functions.h" #include "hardware_functions.h" void Courtroom::construct_char_select() @@ -44,27 +44,34 @@ void Courtroom::construct_char_select() set_size_and_pos(ui_char_buttons, "char_buttons"); - connect(ui_back_to_lobby, SIGNAL(clicked()), this, SLOT(on_back_to_lobby_clicked())); + connect(ui_back_to_lobby, SIGNAL(clicked()), this, + SLOT(on_back_to_lobby_clicked())); - connect(ui_char_select_left, SIGNAL(clicked()), this, SLOT(on_char_select_left_clicked())); - connect(ui_char_select_right, SIGNAL(clicked()), this, SLOT(on_char_select_right_clicked())); + connect(ui_char_select_left, SIGNAL(clicked()), this, + SLOT(on_char_select_left_clicked())); + connect(ui_char_select_right, SIGNAL(clicked()), this, + SLOT(on_char_select_right_clicked())); connect(ui_spectator, SIGNAL(clicked()), this, SLOT(on_spectator_clicked())); - connect(ui_char_search, SIGNAL(textEdited(const QString&)), this, SLOT(on_char_search_changed())); - connect(ui_char_passworded, SIGNAL(stateChanged(int)), this, SLOT(on_char_passworded_clicked())); - connect(ui_char_taken, SIGNAL(stateChanged(int)), this, SLOT(on_char_taken_clicked())); + connect(ui_char_search, SIGNAL(textEdited(const QString &)), this, + SLOT(on_char_search_changed())); + connect(ui_char_passworded, SIGNAL(stateChanged(int)), this, + SLOT(on_char_passworded_clicked())); + connect(ui_char_taken, SIGNAL(stateChanged(int)), this, + SLOT(on_char_taken_clicked())); } void Courtroom::set_char_select() { QString filename = "courtroom_design.ini"; - pos_size_type f_charselect = ao_app->get_element_dimensions("char_select", filename); + pos_size_type f_charselect = + ao_app->get_element_dimensions("char_select", filename); - if (f_charselect.width < 0 || f_charselect.height < 0) - { - qDebug() << "W: did not find courtroom width or height in courtroom_design.ini!"; + if (f_charselect.width < 0 || f_charselect.height < 0) { + qDebug() + << "W: did not find courtroom width or height in courtroom_design.ini!"; this->resize(714, 668); } else @@ -85,25 +92,22 @@ void Courtroom::set_char_select_page() ui_char_select_left->hide(); ui_char_select_right->hide(); - for (AOCharButton *i_button : ui_char_button_list) - { + for (AOCharButton *i_button : ui_char_button_list) { i_button->reset(); i_button->hide(); - i_button->move(0,0); + i_button->move(0, 0); } int total_pages = ui_char_button_list_filtered.size() / max_chars_on_page; int chars_on_page = 0; - if (ui_char_button_list_filtered.size() % max_chars_on_page != 0) - { + if (ui_char_button_list_filtered.size() % max_chars_on_page != 0) { ++total_pages; - //i. e. not on the last page + // i. e. not on the last page if (total_pages > current_char_page + 1) chars_on_page = max_chars_on_page; else chars_on_page = ui_char_button_list_filtered.size() % max_chars_on_page; - } else chars_on_page = max_chars_on_page; @@ -119,23 +123,23 @@ void Courtroom::set_char_select_page() void Courtroom::char_clicked(int n_char) { - QString char_ini_path = ao_app->get_character_path(char_list.at(n_char).name, "char.ini"); + QString char_ini_path = + ao_app->get_character_path(char_list.at(n_char).name, "char.ini"); qDebug() << "char_ini_path" << char_ini_path; - if (!file_exists(char_ini_path)) - { + if (!file_exists(char_ini_path)) { call_notice("Could not find " + char_ini_path); return; } - if (n_char == m_cid) - { + if (n_char == m_cid) { enter_courtroom(m_cid); } - else - { - ao_app->send_server_packet(new AOPacket("CC#" + QString::number(ao_app->s_pv) + "#" + QString::number(n_char) + "#" + get_hdid() + "#%")); + else { + ao_app->send_server_packet( + new AOPacket("CC#" + QString::number(ao_app->s_pv) + "#" + + QString::number(n_char) + "#" + get_hdid() + "#%")); } ui_ic_chat_name->setPlaceholderText(char_list.at(n_char).name); @@ -143,126 +147,125 @@ void Courtroom::char_clicked(int n_char) void Courtroom::put_button_in_place(int starting, int chars_on_this_page) { - if (ui_char_button_list_filtered.size() == 0) - return; + if (ui_char_button_list_filtered.size() == 0) + return; - QPoint f_spacing = ao_app->get_button_spacing("char_button_spacing", "courtroom_design.ini"); + QPoint f_spacing = + ao_app->get_button_spacing("char_button_spacing", "courtroom_design.ini"); - int x_spacing = f_spacing.x(); - int x_mod_count = 0; + int x_spacing = f_spacing.x(); + int x_mod_count = 0; - int y_spacing = f_spacing.y(); - int y_mod_count = 0; + int y_spacing = f_spacing.y(); + int y_mod_count = 0; - char_columns = ((ui_char_buttons->width() - button_width) / (x_spacing + button_width)) + 1; - char_rows = ((ui_char_buttons->height() - button_height) / (y_spacing + button_height)) + 1; + char_columns = + ((ui_char_buttons->width() - button_width) / (x_spacing + button_width)) + + 1; + char_rows = ((ui_char_buttons->height() - button_height) / + (y_spacing + button_height)) + + 1; - max_chars_on_page = char_columns * char_rows; + max_chars_on_page = char_columns * char_rows; - int startout = starting; - for (int n = starting ; n < startout+chars_on_this_page ; ++n) - { - int x_pos = (button_width + x_spacing) * x_mod_count; - int y_pos = (button_height + y_spacing) * y_mod_count; + int startout = starting; + for (int n = starting; n < startout + chars_on_this_page; ++n) { + int x_pos = (button_width + x_spacing) * x_mod_count; + int y_pos = (button_height + y_spacing) * y_mod_count; - ui_char_button_list_filtered.at(n)->move(x_pos, y_pos); - ui_char_button_list_filtered.at(n)->show(); - ui_char_button_list_filtered.at(n)->apply_taken_image(); + ui_char_button_list_filtered.at(n)->move(x_pos, y_pos); + ui_char_button_list_filtered.at(n)->show(); + ui_char_button_list_filtered.at(n)->apply_taken_image(); - ++x_mod_count; + ++x_mod_count; - if (x_mod_count == char_columns) - { - ++y_mod_count; - x_mod_count = 0; - } + if (x_mod_count == char_columns) { + ++y_mod_count; + x_mod_count = 0; } + } } void Courtroom::character_loading_finished() { - // Zeroeth, we'll clear any leftover characters from previous server visits. - ao_app->generated_chars = 0; - if (ui_char_button_list.size() > 0) - { - foreach (AOCharButton* item, ui_char_button_list) { - delete item; - } - ui_char_button_list.clear(); + // Zeroeth, we'll clear any leftover characters from previous server visits. + ao_app->generated_chars = 0; + if (ui_char_button_list.size() > 0) { + foreach (AOCharButton *item, ui_char_button_list) { + delete item; } + ui_char_button_list.clear(); + } - // First, we'll make all the character buttons in the very beginning. - // We also hide them all, so they can't be accidentally clicked. - // Later on, we'll be revealing buttons as we need them. - for (int n = 0; n < char_list.size(); n++) - { - AOCharButton* char_button = new AOCharButton(ui_char_buttons, ao_app, 0, 0, char_list.at(n).taken); - char_button->reset(); - char_button->hide(); - char_button->set_image(char_list.at(n).name); - ui_char_button_list.append(char_button); + // First, we'll make all the character buttons in the very beginning. + // We also hide them all, so they can't be accidentally clicked. + // Later on, we'll be revealing buttons as we need them. + for (int n = 0; n < char_list.size(); n++) { + AOCharButton *char_button = + new AOCharButton(ui_char_buttons, ao_app, 0, 0, char_list.at(n).taken); + char_button->reset(); + char_button->hide(); + char_button->set_image(char_list.at(n).name); + ui_char_button_list.append(char_button); - connect(char_button, &AOCharButton::clicked, [this, n](){ - this->char_clicked(n); - }); + connect(char_button, &AOCharButton::clicked, + [this, n]() { this->char_clicked(n); }); - // This part here serves as a way of showing to the player that the game is still running, it is - // just loading the pictures of the characters. - if (ao_app->lobby_constructed) - { - ao_app->generated_chars++; - int total_loading_size = ao_app->char_list_size * 2 + ao_app->evidence_list_size + ao_app->music_list_size; - int loading_value = int(((ao_app->loaded_chars + ao_app->generated_chars + ao_app->loaded_music + ao_app->loaded_evidence) / static_cast(total_loading_size)) * 100); - ao_app->w_lobby->set_loading_value(loading_value); - ao_app->w_lobby->set_loading_text("Generating chars:\n" + QString::number(ao_app->generated_chars) + "/" + QString::number(ao_app->char_list_size)); - } + // This part here serves as a way of showing to the player that the game is + // still running, it is just loading the pictures of the characters. + if (ao_app->lobby_constructed) { + ao_app->generated_chars++; + int total_loading_size = ao_app->char_list_size * 2 + + ao_app->evidence_list_size + + ao_app->music_list_size; + int loading_value = + int(((ao_app->loaded_chars + ao_app->generated_chars + + ao_app->loaded_music + ao_app->loaded_evidence) / + static_cast(total_loading_size)) * + 100); + ao_app->w_lobby->set_loading_value(loading_value); + ao_app->w_lobby->set_loading_text( + "Generating chars:\n" + QString::number(ao_app->generated_chars) + + "/" + QString::number(ao_app->char_list_size)); } + } - filter_character_list(); + filter_character_list(); } void Courtroom::filter_character_list() { - ui_char_button_list_filtered.clear(); - for (int i = 0; i < char_list.size(); i++) - { - AOCharButton* current_char = ui_char_button_list.at(i); + ui_char_button_list_filtered.clear(); + for (int i = 0; i < char_list.size(); i++) { + AOCharButton *current_char = ui_char_button_list.at(i); - // It seems passwording characters is unimplemented yet? - // Until then, this will stay here, I suppose. - //if (ui_char_passworded->isChecked() && character_is_passworded??) - // continue; + // It seems passwording characters is unimplemented yet? + // Until then, this will stay here, I suppose. + // if (ui_char_passworded->isChecked() && character_is_passworded??) + // continue; - if (!ui_char_taken->isChecked() && char_list.at(i).taken) - continue; + if (!ui_char_taken->isChecked() && char_list.at(i).taken) + continue; - if (!char_list.at(i).name.contains(ui_char_search->text(), Qt::CaseInsensitive)) - continue; + if (!char_list.at(i).name.contains(ui_char_search->text(), + Qt::CaseInsensitive)) + continue; - // We only really need to update the fact that a character is taken - // for the buttons that actually appear. - // You'd also update the passwordedness and etc. here later. - current_char->reset(); - current_char->set_taken(char_list.at(i).taken); + // We only really need to update the fact that a character is taken + // for the buttons that actually appear. + // You'd also update the passwordedness and etc. here later. + current_char->reset(); + current_char->set_taken(char_list.at(i).taken); - ui_char_button_list_filtered.append(current_char); - } + ui_char_button_list_filtered.append(current_char); + } - current_char_page = 0; - set_char_select_page(); + current_char_page = 0; + set_char_select_page(); } -void Courtroom::on_char_search_changed() -{ - filter_character_list(); -} +void Courtroom::on_char_search_changed() { filter_character_list(); } -void Courtroom::on_char_passworded_clicked() -{ - filter_character_list(); -} +void Courtroom::on_char_passworded_clicked() { filter_character_list(); } -void Courtroom::on_char_taken_clicked() -{ - filter_character_list(); -} +void Courtroom::on_char_taken_clicked() { filter_character_list(); } diff --git a/src/chatlogpiece.cpp b/src/chatlogpiece.cpp index 6c861f0..be3be4a 100644 --- a/src/chatlogpiece.cpp +++ b/src/chatlogpiece.cpp @@ -9,7 +9,8 @@ chatlogpiece::chatlogpiece() datetime = QDateTime::currentDateTime().toUTC(); } -chatlogpiece::chatlogpiece(QString p_name, QString p_showname, QString p_message, bool p_song) +chatlogpiece::chatlogpiece(QString p_name, QString p_showname, + QString p_message, bool p_song) { name = p_name; showname = p_showname; @@ -18,7 +19,8 @@ chatlogpiece::chatlogpiece(QString p_name, QString p_showname, QString p_message datetime = QDateTime::currentDateTime().toUTC(); } -chatlogpiece::chatlogpiece(QString p_name, QString p_showname, QString p_message, bool p_song, QDateTime p_datetime) +chatlogpiece::chatlogpiece(QString p_name, QString p_showname, + QString p_message, bool p_song, QDateTime p_datetime) { name = p_name; showname = p_showname; @@ -27,36 +29,17 @@ chatlogpiece::chatlogpiece(QString p_name, QString p_showname, QString p_message datetime = p_datetime.toUTC(); } -QString chatlogpiece::get_name() -{ - return name; -} +QString chatlogpiece::get_name() { return name; } -QString chatlogpiece::get_showname() -{ - return showname; -} +QString chatlogpiece::get_showname() { return showname; } -QString chatlogpiece::get_message() -{ - return message; -} +QString chatlogpiece::get_message() { return message; } -QDateTime chatlogpiece::get_datetime() -{ - return datetime; -} +QDateTime chatlogpiece::get_datetime() { return datetime; } -bool chatlogpiece::get_is_song() -{ - return is_song; -} - -QString chatlogpiece::get_datetime_as_string() -{ - return datetime.toString(); -} +bool chatlogpiece::get_is_song() { return is_song; } +QString chatlogpiece::get_datetime_as_string() { return datetime.toString(); } QString chatlogpiece::get_full() { diff --git a/src/courtroom.cpp b/src/courtroom.cpp index cd01f64..25b4826 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -3,32 +3,29 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() { ao_app = p_ao_app; - #ifdef BASSAUDIO +#ifdef BASSAUDIO // Change the default audio output device to be the one the user has given // in his config.ini file for now. unsigned int a = 0; BASS_DEVICEINFO info; - if (ao_app->get_audio_output_device() == "default") - { - BASS_Init(-1, 48000, BASS_DEVICE_LATENCY, nullptr, nullptr); - load_bass_opus_plugin(); + if (ao_app->get_audio_output_device() == "default") { + BASS_Init(-1, 48000, BASS_DEVICE_LATENCY, nullptr, nullptr); + load_bass_opus_plugin(); } - else - { - for (a = 0; BASS_GetDeviceInfo(a, &info); a++) - { - if (ao_app->get_audio_output_device() == info.name) - { - BASS_SetDevice(a); - BASS_Init(static_cast(a), 48000, BASS_DEVICE_LATENCY, nullptr, nullptr); - load_bass_opus_plugin(); - qDebug() << info.name << "was set as the default audio output device."; - break; - } + else { + for (a = 0; BASS_GetDeviceInfo(a, &info); a++) { + if (ao_app->get_audio_output_device() == info.name) { + BASS_SetDevice(a); + BASS_Init(static_cast(a), 48000, BASS_DEVICE_LATENCY, nullptr, + nullptr); + load_bass_opus_plugin(); + qDebug() << info.name << "was set as the default audio output device."; + break; } + } } - #endif +#endif keepalive_timer = new QTimer(this); keepalive_timer->start(60000); @@ -131,8 +128,8 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_ooc_chat_name->setMaxLength(30); ui_ooc_chat_name->setText(p_ao_app->get_default_username()); - //ui_area_password = new QLineEdit(this); - //ui_area_password->setFrame(false); + // ui_area_password = new QLineEdit(this); + // ui_area_password->setFrame(false); ui_music_search = new QLineEdit(this); ui_music_search->setFrame(false); ui_music_search->setPlaceholderText(tr("Search")); @@ -154,7 +151,7 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_pos_dropdown->addItem("sea"); ui_defense_bar = new AOImage(this, ao_app); - ui_prosecution_bar = new AOImage(this, ao_app); + ui_prosecution_bar = new AOImage(this, ao_app); ui_music_label = new QLabel(this); ui_sfx_label = new QLabel(this); @@ -244,7 +241,7 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_pair_list = new QListWidget(this); ui_pair_offset_spinbox = new QSpinBox(this); - ui_pair_offset_spinbox->setRange(-100,100); + ui_pair_offset_spinbox->setRange(-100, 100); ui_pair_offset_spinbox->setSuffix("% offset"); ui_pair_button = new AOButton(this, ao_app); @@ -259,81 +256,117 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() connect(ui_vp_objection, SIGNAL(done()), this, SLOT(objection_done())); connect(ui_vp_player_char, SIGNAL(done()), this, SLOT(preanim_done())); - connect(text_delay_timer, SIGNAL(timeout()), this, SLOT(start_chat_ticking())); + connect(text_delay_timer, SIGNAL(timeout()), this, + SLOT(start_chat_ticking())); connect(sfx_delay_timer, SIGNAL(timeout()), this, SLOT(play_sfx())); connect(chat_tick_timer, SIGNAL(timeout()), this, SLOT(chat_tick())); connect(realization_timer, SIGNAL(timeout()), this, SLOT(realization_done())); - connect(testimony_show_timer, SIGNAL(timeout()), this, SLOT(hide_testimony())); - connect(testimony_hide_timer, SIGNAL(timeout()), this, SLOT(show_testimony())); + connect(testimony_show_timer, SIGNAL(timeout()), this, + SLOT(hide_testimony())); + connect(testimony_hide_timer, SIGNAL(timeout()), this, + SLOT(show_testimony())); - connect(ui_emote_left, SIGNAL(clicked()), this, SLOT(on_emote_left_clicked())); - connect(ui_emote_right, SIGNAL(clicked()), this, SLOT(on_emote_right_clicked())); + connect(ui_emote_left, SIGNAL(clicked()), this, + SLOT(on_emote_left_clicked())); + connect(ui_emote_right, SIGNAL(clicked()), this, + SLOT(on_emote_right_clicked())); - connect(ui_emote_dropdown, SIGNAL(activated(int)), this, SLOT(on_emote_dropdown_changed(int))); - connect(ui_pos_dropdown, SIGNAL(currentIndexChanged(int)), this, SLOT(on_pos_dropdown_changed(int))); + connect(ui_emote_dropdown, SIGNAL(activated(int)), this, + SLOT(on_emote_dropdown_changed(int))); + connect(ui_pos_dropdown, SIGNAL(currentIndexChanged(int)), this, + SLOT(on_pos_dropdown_changed(int))); - connect(ui_mute_list, SIGNAL(clicked(QModelIndex)), this, SLOT(on_mute_list_clicked(QModelIndex))); + connect(ui_mute_list, SIGNAL(clicked(QModelIndex)), this, + SLOT(on_mute_list_clicked(QModelIndex))); - connect(ui_ic_chat_message, SIGNAL(returnPressed()), this, SLOT(on_chat_return_pressed())); + connect(ui_ic_chat_message, SIGNAL(returnPressed()), this, + SLOT(on_chat_return_pressed())); - connect(ui_ooc_chat_message, SIGNAL(returnPressed()), this, SLOT(on_ooc_return_pressed())); + connect(ui_ooc_chat_message, SIGNAL(returnPressed()), this, + SLOT(on_ooc_return_pressed())); - connect(ui_music_list, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(on_music_list_double_clicked(QModelIndex))); - connect(ui_area_list, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(on_area_list_double_clicked(QModelIndex))); + connect(ui_music_list, SIGNAL(doubleClicked(QModelIndex)), this, + SLOT(on_music_list_double_clicked(QModelIndex))); + connect(ui_area_list, SIGNAL(doubleClicked(QModelIndex)), this, + SLOT(on_area_list_double_clicked(QModelIndex))); connect(ui_hold_it, SIGNAL(clicked()), this, SLOT(on_hold_it_clicked())); connect(ui_objection, SIGNAL(clicked()), this, SLOT(on_objection_clicked())); connect(ui_take_that, SIGNAL(clicked()), this, SLOT(on_take_that_clicked())); - connect(ui_custom_objection, SIGNAL(clicked()), this, SLOT(on_custom_objection_clicked())); + connect(ui_custom_objection, SIGNAL(clicked()), this, + SLOT(on_custom_objection_clicked())); - connect(ui_realization, SIGNAL(clicked()), this, SLOT(on_realization_clicked())); + connect(ui_realization, SIGNAL(clicked()), this, + SLOT(on_realization_clicked())); connect(ui_mute, SIGNAL(clicked()), this, SLOT(on_mute_clicked())); - connect(ui_defense_minus, SIGNAL(clicked()), this, SLOT(on_defense_minus_clicked())); - connect(ui_defense_plus, SIGNAL(clicked()), this, SLOT(on_defense_plus_clicked())); - connect(ui_prosecution_minus, SIGNAL(clicked()), this, SLOT(on_prosecution_minus_clicked())); - connect(ui_prosecution_plus, SIGNAL(clicked()), this, SLOT(on_prosecution_plus_clicked())); + connect(ui_defense_minus, SIGNAL(clicked()), this, + SLOT(on_defense_minus_clicked())); + connect(ui_defense_plus, SIGNAL(clicked()), this, + SLOT(on_defense_plus_clicked())); + connect(ui_prosecution_minus, SIGNAL(clicked()), this, + SLOT(on_prosecution_minus_clicked())); + connect(ui_prosecution_plus, SIGNAL(clicked()), this, + SLOT(on_prosecution_plus_clicked())); - connect(ui_text_color, SIGNAL(currentIndexChanged(int)), this, SLOT(on_text_color_changed(int))); + connect(ui_text_color, SIGNAL(currentIndexChanged(int)), this, + SLOT(on_text_color_changed(int))); - connect(ui_music_slider, SIGNAL(valueChanged(int)), this, SLOT(on_music_slider_moved(int))); - connect(ui_sfx_slider, SIGNAL(valueChanged(int)), this, SLOT(on_sfx_slider_moved(int))); - connect(ui_blip_slider, SIGNAL(valueChanged(int)), this, SLOT(on_blip_slider_moved(int))); + connect(ui_music_slider, SIGNAL(valueChanged(int)), this, + SLOT(on_music_slider_moved(int))); + connect(ui_sfx_slider, SIGNAL(valueChanged(int)), this, + SLOT(on_sfx_slider_moved(int))); + connect(ui_blip_slider, SIGNAL(valueChanged(int)), this, + SLOT(on_blip_slider_moved(int))); - connect(ui_log_limit_spinbox, SIGNAL(valueChanged(int)), this, SLOT(on_log_limit_changed(int))); + connect(ui_log_limit_spinbox, SIGNAL(valueChanged(int)), this, + SLOT(on_log_limit_changed(int))); - connect(ui_ooc_toggle, SIGNAL(clicked()), this, SLOT(on_ooc_toggle_clicked())); + connect(ui_ooc_toggle, SIGNAL(clicked()), this, + SLOT(on_ooc_toggle_clicked())); - connect(ui_music_search, SIGNAL(textChanged(QString)), this, SLOT(on_music_search_edited(QString))); + connect(ui_music_search, SIGNAL(textChanged(QString)), this, + SLOT(on_music_search_edited(QString))); - connect(ui_witness_testimony, SIGNAL(clicked()), this, SLOT(on_witness_testimony_clicked())); - connect(ui_cross_examination, SIGNAL(clicked()), this, SLOT(on_cross_examination_clicked())); + connect(ui_witness_testimony, SIGNAL(clicked()), this, + SLOT(on_witness_testimony_clicked())); + connect(ui_cross_examination, SIGNAL(clicked()), this, + SLOT(on_cross_examination_clicked())); connect(ui_guilty, SIGNAL(clicked()), this, SLOT(on_guilty_clicked())); - connect(ui_not_guilty, SIGNAL(clicked()), this, SLOT(on_not_guilty_clicked())); + connect(ui_not_guilty, SIGNAL(clicked()), this, + SLOT(on_not_guilty_clicked())); - connect(ui_change_character, SIGNAL(clicked()), this, SLOT(on_change_character_clicked())); - connect(ui_reload_theme, SIGNAL(clicked()), this, SLOT(on_reload_theme_clicked())); + connect(ui_change_character, SIGNAL(clicked()), this, + SLOT(on_change_character_clicked())); + connect(ui_reload_theme, SIGNAL(clicked()), this, + SLOT(on_reload_theme_clicked())); connect(ui_call_mod, SIGNAL(clicked()), this, SLOT(on_call_mod_clicked())); connect(ui_settings, SIGNAL(clicked()), this, SLOT(on_settings_clicked())); - connect(ui_announce_casing, SIGNAL(clicked()), this, SLOT(on_announce_casing_clicked())); - connect(ui_switch_area_music, SIGNAL(clicked()), this, SLOT(on_switch_area_music_clicked())); + connect(ui_announce_casing, SIGNAL(clicked()), this, + SLOT(on_announce_casing_clicked())); + connect(ui_switch_area_music, SIGNAL(clicked()), this, + SLOT(on_switch_area_music_clicked())); connect(ui_pre, SIGNAL(clicked()), this, SLOT(on_pre_clicked())); connect(ui_flip, SIGNAL(clicked()), this, SLOT(on_flip_clicked())); connect(ui_guard, SIGNAL(clicked()), this, SLOT(on_guard_clicked())); connect(ui_casing, SIGNAL(clicked()), this, SLOT(on_casing_clicked())); - connect(ui_showname_enable, SIGNAL(clicked()), this, SLOT(on_showname_enable_clicked())); + connect(ui_showname_enable, SIGNAL(clicked()), this, + SLOT(on_showname_enable_clicked())); connect(ui_pair_button, SIGNAL(clicked()), this, SLOT(on_pair_clicked())); - connect(ui_pair_list, SIGNAL(clicked(QModelIndex)), this, SLOT(on_pair_list_clicked(QModelIndex))); - connect(ui_pair_offset_spinbox, SIGNAL(valueChanged(int)), this, SLOT(on_pair_offset_changed(int))); + connect(ui_pair_list, SIGNAL(clicked(QModelIndex)), this, + SLOT(on_pair_list_clicked(QModelIndex))); + connect(ui_pair_offset_spinbox, SIGNAL(valueChanged(int)), this, + SLOT(on_pair_offset_changed(int))); - connect(ui_evidence_button, SIGNAL(clicked()), this, SLOT(on_evidence_button_clicked())); + connect(ui_evidence_button, SIGNAL(clicked()), this, + SLOT(on_evidence_button_clicked())); set_widgets(); @@ -344,9 +377,8 @@ void Courtroom::set_mute_list() { mute_map.clear(); - //maps which characters are muted based on cid, none are muted by default - for (int n_cid = 0 ; n_cid < char_list.size() ; n_cid++) - { + // maps which characters are muted based on cid, none are muted by default + for (int n_cid = 0; n_cid < char_list.size(); n_cid++) { mute_map.insert(n_cid, false); } @@ -357,9 +389,8 @@ void Courtroom::set_mute_list() sorted_mute_list.sort(); - for (QString i_name : sorted_mute_list) - { - //mute_map.insert(i_name, false); + for (QString i_name : sorted_mute_list) { + // mute_map.insert(i_name, false); ui_mute_list->addItem(i_name); } } @@ -373,8 +404,7 @@ void Courtroom::set_pair_list() sorted_pair_list.sort(); - for (QString i_name : sorted_pair_list) - { + for (QString i_name : sorted_pair_list) { ui_pair_list->addItem(i_name); } } @@ -386,16 +416,15 @@ void Courtroom::set_widgets() QString filename = "courtroom_design.ini"; - pos_size_type f_courtroom = ao_app->get_element_dimensions("courtroom", filename); + pos_size_type f_courtroom = + ao_app->get_element_dimensions("courtroom", filename); - if (f_courtroom.width < 0 || f_courtroom.height < 0) - { + if (f_courtroom.width < 0 || f_courtroom.height < 0) { qDebug() << "W: did not find courtroom width or height in " << filename; this->resize(714, 668); } - else - { + else { m_courtroom_width = f_courtroom.width; m_courtroom_height = f_courtroom.height; @@ -411,17 +440,16 @@ void Courtroom::set_widgets() set_size_and_pos(ui_viewport, "viewport"); // 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_support_enabled) - { + // We also do this this soon so that set_size_and_pos can hide them all later, + // if needed. + if (ao_app->cccc_ic_support_enabled) { ui_pair_button->show(); ui_pre_non_interrupt->show(); ui_showname_enable->show(); ui_ic_chat_name->show(); ui_ic_chat_name->setEnabled(true); } - else - { + else { ui_pair_button->hide(); ui_pre_non_interrupt->hide(); ui_showname_enable->hide(); @@ -429,17 +457,16 @@ void Courtroom::set_widgets() ui_ic_chat_name->setEnabled(false); } - if (ao_app->casing_alerts_enabled) - { + if (ao_app->casing_alerts_enabled) { ui_announce_casing->show(); } - else - { + else { ui_announce_casing->hide(); } // We also show the non-server-dependent client additions. - // Once again, if the theme can't display it, set_move_and_pos will catch them. + // Once again, if the theme can't display it, set_move_and_pos will catch + // them. ui_settings->show(); ui_log_limit_label->show(); ui_log_limit_spinbox->show(); @@ -454,13 +481,15 @@ void Courtroom::set_widgets() ui_vp_player_char->combo_resize(ui_viewport->width(), ui_viewport->height()); ui_vp_sideplayer_char->move(0, 0); - ui_vp_sideplayer_char->combo_resize(ui_viewport->width(), ui_viewport->height()); + ui_vp_sideplayer_char->combo_resize(ui_viewport->width(), + ui_viewport->height()); - //the AO2 desk element + // the AO2 desk element ui_vp_desk->move(0, 0); ui_vp_desk->resize(ui_viewport->width(), ui_viewport->height()); - //the size of the ui_vp_legacy_desk element relies on various factors and is set in set_scene() + // the size of the ui_vp_legacy_desk element relies on various factors and is + // set in set_scene() double y_modifier = 147.0 / 192.0; int final_y = static_cast(y_modifier * ui_viewport->height()); @@ -514,21 +543,21 @@ void Courtroom::set_widgets() set_size_and_pos(ui_music_list, "music_list"); - if (is_ao2_bg) - { + if (is_ao2_bg) { set_size_and_pos(ui_ic_chat_message, "ao2_ic_chat_message"); set_size_and_pos(ui_vp_chatbox, "ao2_chatbox"); set_size_and_pos(ui_ic_chat_name, "ao2_ic_chat_name"); } - else - { + else { set_size_and_pos(ui_ic_chat_message, "ic_chat_message"); set_size_and_pos(ui_vp_chatbox, "chatbox"); set_size_and_pos(ui_ic_chat_name, "ic_chat_name"); } - ui_ic_chat_message->setStyleSheet("QLineEdit{background-color: rgba(100, 100, 100, 255);}"); - ui_ic_chat_name->setStyleSheet("QLineEdit{background-color: rgba(180, 180, 180, 255);}"); + ui_ic_chat_message->setStyleSheet( + "QLineEdit{background-color: rgba(100, 100, 100, 255);}"); + ui_ic_chat_name->setStyleSheet( + "QLineEdit{background-color: rgba(180, 180, 180, 255);}"); ui_vp_chatbox->set_image("chatmed.png"); ui_vp_chatbox->hide(); @@ -542,7 +571,7 @@ void Courtroom::set_widgets() set_size_and_pos(ui_ooc_chat_name, "ooc_chat_name"); ui_ooc_chat_name->setStyleSheet("background-color: rgba(0, 0, 0, 0);"); - //set_size_and_pos(ui_area_password, "area_password"); + // set_size_and_pos(ui_area_password, "area_password"); set_size_and_pos(ui_music_search, "music_search"); set_size_and_pos(ui_emotes, "emotes"); @@ -557,10 +586,12 @@ void Courtroom::set_widgets() set_size_and_pos(ui_pos_dropdown, "pos_dropdown"); set_size_and_pos(ui_defense_bar, "defense_bar"); - ui_defense_bar->set_image("defensebar" + QString::number(defense_bar_state) + ".png"); + ui_defense_bar->set_image("defensebar" + QString::number(defense_bar_state) + + ".png"); set_size_and_pos(ui_prosecution_bar, "prosecution_bar"); - ui_prosecution_bar->set_image("prosecutionbar" + QString::number(prosecution_bar_state) + ".png"); + ui_prosecution_bar->set_image( + "prosecutionbar" + QString::number(prosecution_bar_state) + ".png"); set_size_and_pos(ui_music_label, "music_label"); ui_music_label->setText("Music"); @@ -717,12 +748,13 @@ void Courtroom::set_fonts() // Set color of labels and checkboxes const QString design_file = "courtroom_fonts.ini"; QColor f_color = ao_app->get_color("label_color", design_file); - QString color_string = "color: rgba(" + - QString::number(f_color.red()) + ", " + - QString::number(f_color.green()) + ", " + - QString::number(f_color.blue()) + ", 255); }"; - QString style_sheet_string = "QLabel {" + color_string + "}" - "QCheckBox {" + color_string + "}"; + QString color_string = "color: rgba(" + QString::number(f_color.red()) + + ", " + QString::number(f_color.green()) + ", " + + QString::number(f_color.blue()) + ", 255); }"; + QString style_sheet_string = "QLabel {" + color_string + + "}" + "QCheckBox {" + + color_string + "}"; setStyleSheet(style_sheet_string); } @@ -733,16 +765,14 @@ void Courtroom::set_font(QWidget *widget, QString p_identifier) QString class_name = widget->metaObject()->className(); QString fontt = ao_app->get_font_name(p_identifier + "_font", design_file); - widget->setFont(QFont(fontt, f_weight)); - + widget->setFont(QFont(fontt, f_weight)); QColor f_color = ao_app->get_color(p_identifier + "_color", design_file); - QString style_sheet_string = class_name + " { background-color: rgba(0, 0, 0, 0);\n" + - "color: rgba(" + - QString::number(f_color.red()) + ", " + - QString::number(f_color.green()) + ", " + - QString::number(f_color.blue()) + ", 255); }"; + QString style_sheet_string = + class_name + " { background-color: rgba(0, 0, 0, 0);\n" + "color: rgba(" + + QString::number(f_color.red()) + ", " + QString::number(f_color.green()) + + ", " + QString::number(f_color.blue()) + ", 255); }"; widget->setStyleSheet(style_sheet_string); } @@ -756,15 +786,14 @@ void Courtroom::set_size_and_pos(QWidget *p_widget, QString p_identifier) { QString filename = "courtroom_design.ini"; - pos_size_type design_ini_result = ao_app->get_element_dimensions(p_identifier, filename); + pos_size_type design_ini_result = + ao_app->get_element_dimensions(p_identifier, filename); - if (design_ini_result.width < 0 || design_ini_result.height < 0) - { + if (design_ini_result.width < 0 || design_ini_result.height < 0) { qDebug() << "W: could not find \"" << p_identifier << "\" in " << filename; p_widget->hide(); } - else - { + else { p_widget->move(design_ini_result.x, design_ini_result.y); p_widget->resize(design_ini_result.width, design_ini_result.height); } @@ -772,9 +801,9 @@ void Courtroom::set_size_and_pos(QWidget *p_widget, QString p_identifier) void Courtroom::set_taken(int n_char, bool p_taken) { - if (n_char >= char_list.size()) - { - qDebug() << "W: set_taken attempted to set an index bigger than char_list size"; + if (n_char >= char_list.size()) { + qDebug() + << "W: set_taken attempted to set an index bigger than char_list size"; return; } @@ -818,32 +847,28 @@ void Courtroom::set_background(QString p_background) file_exists(ao_app->get_background_path("prosecutiondesk.png")) && file_exists(ao_app->get_background_path("stand.png")); - if (is_ao2_bg) - { + if (is_ao2_bg) { set_size_and_pos(ui_vp_chatbox, "ao2_chatbox"); set_size_and_pos(ui_ic_chat_message, "ao2_ic_chat_message"); } - else - { + else { set_size_and_pos(ui_vp_chatbox, "chatbox"); set_size_and_pos(ui_ic_chat_message, "ic_chat_message"); } } void Courtroom::enter_courtroom(int p_cid) -{ +{ m_cid = p_cid; QString f_char; - if (m_cid == -1) - { + if (m_cid == -1) { if (ao_app->is_discord_enabled()) ao_app->discord->state_spectate(); f_char = ""; } - else - { + else { f_char = ao_app->get_char_name(char_list.at(m_cid).name); if (ao_app->is_discord_enabled()) @@ -870,8 +895,7 @@ void Courtroom::enter_courtroom(int p_cid) QString side = ao_app->get_char_side(f_char); - if (side == "jud") - { + if (side == "jud") { ui_witness_testimony->show(); ui_cross_examination->show(); ui_not_guilty->show(); @@ -881,8 +905,7 @@ void Courtroom::enter_courtroom(int p_cid) ui_prosecution_minus->show(); ui_prosecution_plus->show(); } - else - { + else { ui_witness_testimony->hide(); ui_cross_examination->hide(); ui_guilty->hide(); @@ -895,7 +918,7 @@ void Courtroom::enter_courtroom(int p_cid) if (ao_app->custom_objection_enabled && (file_exists(ao_app->get_character_path(current_char, "custom.gif")) || - file_exists(ao_app->get_character_path(current_char, "custom.apng"))) && + file_exists(ao_app->get_character_path(current_char, "custom.apng"))) && file_exists(ao_app->get_character_path(current_char, "custom.wav"))) ui_custom_objection->show(); else @@ -923,7 +946,7 @@ void Courtroom::enter_courtroom(int p_cid) set_widgets(); - //ui_server_chatlog->setHtml(ui_server_chatlog->toHtml()); + // ui_server_chatlog->setHtml(ui_server_chatlog->toHtml()); ui_char_select_background->hide(); @@ -943,14 +966,12 @@ void Courtroom::list_music() int n_listed_songs = 0; - for (int n_song = 0 ; n_song < music_list.size() ; ++n_song) - { + for (int n_song = 0; n_song < music_list.size(); ++n_song) { QString i_song = music_list.at(n_song); QString i_song_listname = i_song; i_song_listname = i_song_listname.left(i_song_listname.lastIndexOf(".")); - if (i_song.toLower().contains(ui_music_search->text().toLower())) - { + if (i_song.toLower().contains(ui_music_search->text().toLower())) { ui_music_list->addItem(i_song_listname); music_row_to_number.append(n_song); @@ -983,8 +1004,7 @@ void Courtroom::list_areas() int n_listed_areas = 0; - for (int n_area = 0 ; n_area < area_list.size() ; ++n_area) - { + for (int n_area = 0; n_area < area_list.size(); ++n_area) { QString i_area = ""; i_area.append("["); i_area.append(QString::number(n_area)); @@ -992,8 +1012,7 @@ void Courtroom::list_areas() i_area.append(area_list.at(n_area)); - if (ao_app->arup_enabled) - { + if (ao_app->arup_enabled) { i_area.append("\n "); i_area.append(arup_statuses.at(n_area)); @@ -1008,35 +1027,30 @@ void Courtroom::list_areas() i_area.append(arup_locks.at(n_area)); } - if (i_area.toLower().contains(ui_music_search->text().toLower())) - { + if (i_area.toLower().contains(ui_music_search->text().toLower())) { ui_area_list->addItem(i_area); area_row_to_number.append(n_area); - if (ao_app->arup_enabled) - { + if (ao_app->arup_enabled) { // Colouring logic here. ui_area_list->item(n_listed_areas)->setBackground(free_brush); - if (arup_locks.at(n_area) == "LOCKED") - { - ui_area_list->item(n_listed_areas)->setBackground(locked_brush); + if (arup_locks.at(n_area) == "LOCKED") { + ui_area_list->item(n_listed_areas)->setBackground(locked_brush); } - else - { - if (arup_statuses.at(n_area) == "LOOKING-FOR-PLAYERS") - ui_area_list->item(n_listed_areas)->setBackground(lfp_brush); - else if (arup_statuses.at(n_area) == "CASING") - ui_area_list->item(n_listed_areas)->setBackground(casing_brush); - else if (arup_statuses.at(n_area) == "RECESS") - ui_area_list->item(n_listed_areas)->setBackground(recess_brush); - else if (arup_statuses.at(n_area) == "RP") - ui_area_list->item(n_listed_areas)->setBackground(rp_brush); - else if (arup_statuses.at(n_area) == "GAMING") - ui_area_list->item(n_listed_areas)->setBackground(gaming_brush); + else { + if (arup_statuses.at(n_area) == "LOOKING-FOR-PLAYERS") + ui_area_list->item(n_listed_areas)->setBackground(lfp_brush); + else if (arup_statuses.at(n_area) == "CASING") + ui_area_list->item(n_listed_areas)->setBackground(casing_brush); + else if (arup_statuses.at(n_area) == "RECESS") + ui_area_list->item(n_listed_areas)->setBackground(recess_brush); + else if (arup_statuses.at(n_area) == "RP") + ui_area_list->item(n_listed_areas)->setBackground(rp_brush); + else if (arup_statuses.at(n_area) == "GAMING") + ui_area_list->item(n_listed_areas)->setBackground(gaming_brush); } } - else - { + else { ui_area_list->item(n_listed_areas)->setBackground(free_brush); } @@ -1047,17 +1061,22 @@ void Courtroom::list_areas() void Courtroom::append_ms_chatmessage(QString f_name, QString f_message) { - ui_ms_chatlog->append_chatmessage(f_name, f_message, ao_app->get_color("ooc_default_color", "courtroom_design.ini").name()); + ui_ms_chatlog->append_chatmessage( + f_name, f_message, + ao_app->get_color("ooc_default_color", "courtroom_design.ini").name()); } -void Courtroom::append_server_chatmessage(QString p_name, QString p_message, QString p_colour) +void Courtroom::append_server_chatmessage(QString p_name, QString p_message, + QString p_colour) { QString colour = "#000000"; if (p_colour == "0") - colour = ao_app->get_color("ooc_default_color", "courtroom_design.ini").name(); + colour = + ao_app->get_color("ooc_default_color", "courtroom_design.ini").name(); if (p_colour == "1") - colour = ao_app->get_color("ooc_server_color", "courtroom_design.ini").name(); + colour = + ao_app->get_color("ooc_server_color", "courtroom_design.ini").name(); ui_server_chatlog->append_chatmessage(p_name, p_message, colour); } @@ -1067,33 +1086,32 @@ void Courtroom::on_chat_return_pressed() if (ui_ic_chat_message->text() == "" || is_muted) return; - if ((anim_state < 3 || text_state < 2) && - objection_state == 0) + if ((anim_state < 3 || text_state < 2) && objection_state == 0) return; - //MS# - //deskmod# - //pre-emote# - //character# - //emote# - //message# - //side# - //sfx-name# - //emote_modifier# - //char_id# - //sfx_delay# - //objection_modifier# - //evidence# - //placeholder# - //realization# - //text_color#% + // MS# + // deskmod# + // pre-emote# + // character# + // emote# + // message# + // side# + // sfx-name# + // emote_modifier# + // char_id# + // sfx_delay# + // objection_modifier# + // evidence# + // placeholder# + // realization# + // text_color#% // Additionally, in our case: - //showname# - //other_charid# - //self_offset# - //noninterrupting_preanim#% + // showname# + // other_charid# + // self_offset# + // noninterrupting_preanim#% QStringList packet_contents; @@ -1101,9 +1119,9 @@ void Courtroom::on_chat_return_pressed() QString f_desk_mod = "chat"; - if (ao_app->desk_mod_enabled) - { - f_desk_mod = QString::number(ao_app->get_desk_mod(current_char, current_emote)); + if (ao_app->desk_mod_enabled) { + f_desk_mod = + QString::number(ao_app->get_desk_mod(current_char, current_emote)); if (f_desk_mod == "-1") f_desk_mod = "chat"; } @@ -1124,26 +1142,22 @@ void Courtroom::on_chat_return_pressed() int f_emote_mod = ao_app->get_emote_mod(current_char, current_emote); - //needed or else legacy won't understand what we're saying - if (objection_state > 0) - { - if (ui_pre->isChecked()) - { + // needed or else legacy won't understand what we're saying + if (objection_state > 0) { + if (ui_pre->isChecked()) { if (f_emote_mod == 5) f_emote_mod = 6; else f_emote_mod = 2; } } - else if (ui_pre->isChecked() and !ui_pre_non_interrupt->isChecked()) - { + else if (ui_pre->isChecked() and !ui_pre_non_interrupt->isChecked()) { if (f_emote_mod == 0) f_emote_mod = 1; else if (f_emote_mod == 5 && ao_app->prezoom_enabled) f_emote_mod = 4; } - else - { + else { if (f_emote_mod == 1) f_emote_mod = 0; else if (f_emote_mod == 4) @@ -1153,12 +1167,13 @@ void Courtroom::on_chat_return_pressed() packet_contents.append(QString::number(f_emote_mod)); packet_contents.append(QString::number(m_cid)); - packet_contents.append(QString::number(ao_app->get_sfx_delay(current_char, current_emote))); + packet_contents.append( + QString::number(ao_app->get_sfx_delay(current_char, current_emote))); QString f_obj_state; if ((objection_state == 4 && !ao_app->custom_objection_enabled) || - (objection_state < 0)) + (objection_state < 0)) f_obj_state = "0"; else f_obj_state = QString::number(objection_state); @@ -1166,16 +1181,15 @@ void Courtroom::on_chat_return_pressed() packet_contents.append(f_obj_state); if (is_presenting_evidence) - //the evidence index is shifted by 1 because 0 is no evidence per legacy standards - //besides, older clients crash if we pass -1 + // the evidence index is shifted by 1 because 0 is no evidence per legacy + // standards besides, older clients crash if we pass -1 packet_contents.append(QString::number(current_evidence + 1)); else packet_contents.append("0"); QString f_flip; - if (ao_app->flipping_enabled) - { + if (ao_app->flipping_enabled) { if (ui_flip->isChecked()) f_flip = "1"; else @@ -1200,38 +1214,32 @@ 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_support_enabled) - { - // If there is a showname entered, use that -- else, just send an empty packet-part. - if (!ui_ic_chat_name->text().isEmpty()) - { + if (ao_app->cccc_ic_support_enabled) { + // 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 - { + 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) - { + // 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) { packet_contents.append(QString::number(other_charid)); packet_contents.append(QString::number(offset_with_pair)); } - else - { + else { packet_contents.append("-1"); packet_contents.append("0"); } // Finally, we send over if we want our pres to not interrupt. - if (ui_pre_non_interrupt->isChecked() && ui_pre->isChecked()) - { + if (ui_pre_non_interrupt->isChecked() && ui_pre->isChecked()) { packet_contents.append("1"); } - else - { + else { packet_contents.append("0"); } } @@ -1247,21 +1255,19 @@ void Courtroom::handle_chatmessage(QStringList *p_contents) if (p_contents->size() < 15) return; - for (int n_string = 0 ; n_string < chatmessage_size ; ++n_string) - { - //m_chatmessage[n_string] = p_contents->at(n_string); + for (int n_string = 0; n_string < chatmessage_size; ++n_string) { + // m_chatmessage[n_string] = p_contents->at(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. + // 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 < 15 || ao_app->cccc_ic_support_enabled)) - { + (n_string < 15 || ao_app->cccc_ic_support_enabled)) { m_chatmessage[n_string] = p_contents->at(n_string); } - else - { + else { m_chatmessage[n_string] = ""; } } @@ -1275,16 +1281,13 @@ void Courtroom::handle_chatmessage(QStringList *p_contents) return; QString f_showname; - if (m_chatmessage[SHOWNAME].isEmpty() || !ui_showname_enable->isChecked()) - { - f_showname = ao_app->get_showname(char_list.at(f_char_id).name); + if (m_chatmessage[SHOWNAME].isEmpty() || !ui_showname_enable->isChecked()) { + f_showname = ao_app->get_showname(char_list.at(f_char_id).name); } - else - { - f_showname = m_chatmessage[SHOWNAME]; + else { + f_showname = m_chatmessage[SHOWNAME]; } - QString f_message = f_showname + ": " + m_chatmessage[MESSAGE] + '\n'; if (f_message == previous_ic_message) @@ -1297,10 +1300,11 @@ void Courtroom::handle_chatmessage(QStringList *p_contents) chat_tick_timer->stop(); ui_vp_evidence_display->reset(); - chatmessage_is_empty = m_chatmessage[MESSAGE] == " " || m_chatmessage[MESSAGE] == ""; + chatmessage_is_empty = + m_chatmessage[MESSAGE] == " " || m_chatmessage[MESSAGE] == ""; - if (m_chatmessage[MESSAGE] == ui_ic_chat_message->text() && m_chatmessage[CHAR_ID].toInt() == m_cid) - { + if (m_chatmessage[MESSAGE] == ui_ic_chat_message->text() && + m_chatmessage[CHAR_ID].toInt() == m_cid) { ui_ic_chat_message->clear(); objection_state = 0; realization_state = 0; @@ -1314,11 +1318,13 @@ void Courtroom::handle_chatmessage(QStringList *p_contents) ui_evidence_present->set_image("present_disabled.png"); } - chatlogpiece* temp = new chatlogpiece(ao_app->get_showname(char_list.at(f_char_id).name), f_showname, ": " + m_chatmessage[MESSAGE], false); + chatlogpiece *temp = + new chatlogpiece(ao_app->get_showname(char_list.at(f_char_id).name), + f_showname, ": " + m_chatmessage[MESSAGE], false); ic_chatlog_history.append(*temp); - while(ic_chatlog_history.size() > log_maximum_blocks && log_maximum_blocks > 0) - { + while (ic_chatlog_history.size() > log_maximum_blocks && + log_maximum_blocks > 0) { ic_chatlog_history.removeFirst(); } @@ -1330,11 +1336,9 @@ void Courtroom::handle_chatmessage(QStringList *p_contents) QString f_char = m_chatmessage[CHAR_NAME]; QString f_custom_theme = ao_app->get_char_shouts(f_char); - //if an objection is used - if (objection_mod <= 4 && objection_mod >= 1) - { - switch (objection_mod) - { + // if an objection is used + if (objection_mod <= 4 && objection_mod >= 1) { + switch (objection_mod) { case 1: ui_vp_objection->play("holdit", f_char, f_custom_theme); objection_player->play("holdit.wav", f_char, f_custom_theme); @@ -1347,7 +1351,7 @@ void Courtroom::handle_chatmessage(QStringList *p_contents) ui_vp_objection->play("takethat", f_char, f_custom_theme); objection_player->play("takethat.wav", f_char, f_custom_theme); break; - //case 4 is AO2 only + // case 4 is AO2 only case 4: ui_vp_objection->play("custom", f_char, f_custom_theme); objection_player->play("custom.wav", f_char, f_custom_theme); @@ -1365,27 +1369,22 @@ void Courtroom::handle_chatmessage(QStringList *p_contents) handle_chatmessage_2(); } -void Courtroom::objection_done() -{ - handle_chatmessage_2(); -} +void Courtroom::objection_done() { handle_chatmessage_2(); } void Courtroom::handle_chatmessage_2() { ui_vp_speedlines->stop(); ui_vp_player_char->stop(); - if (m_chatmessage[SHOWNAME].isEmpty() || !ui_showname_enable->isChecked()) - { - QString real_name = char_list.at(m_chatmessage[CHAR_ID].toInt()).name; + if (m_chatmessage[SHOWNAME].isEmpty() || !ui_showname_enable->isChecked()) { + QString real_name = char_list.at(m_chatmessage[CHAR_ID].toInt()).name; - QString f_showname = ao_app->get_showname(real_name); + QString f_showname = ao_app->get_showname(real_name); - ui_vp_showname->setText(f_showname); + ui_vp_showname->setText(f_showname); } - else - { - ui_vp_showname->setText(m_chatmessage[SHOWNAME]); + else { + ui_vp_showname->setText(m_chatmessage[SHOWNAME]); } ui_vp_message->clear(); @@ -1395,36 +1394,32 @@ void Courtroom::handle_chatmessage_2() if (chatbox == "") ui_vp_chatbox->set_image("chatmed.png"); - else - { - QString chatbox_path = ao_app->get_base_path() + "misc/" + chatbox + "/chatbox.png"; + else { + QString chatbox_path = + ao_app->get_base_path() + "misc/" + chatbox + "/chatbox.png"; ui_vp_chatbox->set_image_from_path(chatbox_path); } - ui_vp_showname->setStyleSheet("QLabel { color : " + get_text_color("_showname").name() + "; }"); + ui_vp_showname->setStyleSheet( + "QLabel { color : " + get_text_color("_showname").name() + "; }"); set_scene(); set_text_color(); // Check if the message needs to be centered. QString f_message = m_chatmessage[MESSAGE]; - if (f_message.size() >= 2) - { - if (f_message.startsWith("~~")) - { - message_is_centered = true; - } - else - { - message_is_centered = false; - } + if (f_message.size() >= 2) { + if (f_message.startsWith("~~")) { + message_is_centered = true; + } + else { + message_is_centered = false; + } } - else - { - ui_vp_message->setAlignment(Qt::AlignLeft); + else { + ui_vp_message->setAlignment(Qt::AlignLeft); } - int emote_mod = m_chatmessage[EMOTE_MOD].toInt(); if (ao_app->flipping_enabled && m_chatmessage[FLIP].toInt() == 1) @@ -1435,98 +1430,91 @@ void Courtroom::handle_chatmessage_2() QString side = m_chatmessage[SIDE]; // Making the second character appear. - if (m_chatmessage[OTHER_CHARID].isEmpty()) - { + if (m_chatmessage[OTHER_CHARID].isEmpty()) { // If there is no second character, hide 'em, and center the first. ui_vp_sideplayer_char->hide(); - ui_vp_sideplayer_char->move(0,0); + ui_vp_sideplayer_char->move(0, 0); - ui_vp_player_char->move(0,0); + ui_vp_player_char->move(0, 0); } - else - { + else { bool ok; int got_other_charid = m_chatmessage[OTHER_CHARID].toInt(&ok); - if (ok) - { - if (got_other_charid > -1) - { + if (ok) { + if (got_other_charid > -1) { // If there is, show them! ui_vp_sideplayer_char->show(); - // Depending on where we are, we offset the characters, and reorder their stacking. - if (side == "def") - { - // We also move the character down depending on how far the are to the right. + // Depending on where we are, we offset the characters, and reorder + // their stacking. + if (side == "def") { + // We also move the character down depending on how far the are to the + // right. int hor_offset = m_chatmessage[SELF_OFFSET].toInt(); int vert_offset = 0; - if (hor_offset > 0) - { + if (hor_offset > 0) { vert_offset = hor_offset / 10; } - ui_vp_player_char->move(ui_viewport->width() * hor_offset / 100, ui_viewport->height() * vert_offset / 100); + ui_vp_player_char->move(ui_viewport->width() * hor_offset / 100, + ui_viewport->height() * vert_offset / 100); // We do the same with the second character. int hor2_offset = m_chatmessage[OTHER_OFFSET].toInt(); int vert2_offset = 0; - if (hor2_offset > 0) - { + if (hor2_offset > 0) { vert2_offset = hor2_offset / 10; } - ui_vp_sideplayer_char->move(ui_viewport->width() * hor2_offset / 100, ui_viewport->height() * vert2_offset / 100); + ui_vp_sideplayer_char->move(ui_viewport->width() * hor2_offset / 100, + ui_viewport->height() * vert2_offset / + 100); // Finally, we reorder them based on who is more to the left. // The person more to the left is more in the front. - if (hor2_offset >= hor_offset) - { + if (hor2_offset >= hor_offset) { ui_vp_sideplayer_char->raise(); ui_vp_player_char->raise(); } - else - { + else { ui_vp_player_char->raise(); ui_vp_sideplayer_char->raise(); } ui_vp_desk->raise(); ui_vp_legacy_desk->raise(); } - else if (side == "pro") - { + else if (side == "pro") { // Almost the same thing happens here, but in reverse. int hor_offset = m_chatmessage[SELF_OFFSET].toInt(); int vert_offset = 0; - if (hor_offset < 0) - { + if (hor_offset < 0) { // We don't want to RAISE the char off the floor. vert_offset = -1 * hor_offset / 10; } - ui_vp_player_char->move(ui_viewport->width() * hor_offset / 100, ui_viewport->height() * vert_offset / 100); + ui_vp_player_char->move(ui_viewport->width() * hor_offset / 100, + ui_viewport->height() * vert_offset / 100); // We do the same with the second character. int hor2_offset = m_chatmessage[OTHER_OFFSET].toInt(); int vert2_offset = 0; - if (hor2_offset < 0) - { + if (hor2_offset < 0) { vert2_offset = -1 * hor2_offset / 10; } - ui_vp_sideplayer_char->move(ui_viewport->width() * hor2_offset / 100, ui_viewport->height() * vert2_offset / 100); + ui_vp_sideplayer_char->move(ui_viewport->width() * hor2_offset / 100, + ui_viewport->height() * vert2_offset / + 100); // Finally, we reorder them based on who is more to the right. - if (hor2_offset <= hor_offset) - { + if (hor2_offset <= hor_offset) { ui_vp_sideplayer_char->raise(); ui_vp_player_char->raise(); } - else - { + else { ui_vp_player_char->raise(); ui_vp_sideplayer_char->raise(); } ui_vp_desk->raise(); ui_vp_legacy_desk->raise(); } - else - { + else { // In every other case, the person more to the left is on top. // These cases also don't move the characters down. int hor_offset = m_chatmessage[SELF_OFFSET].toInt(); @@ -1534,17 +1522,16 @@ void Courtroom::handle_chatmessage_2() // We do the same with the second character. int hor2_offset = m_chatmessage[OTHER_OFFSET].toInt(); - ui_vp_sideplayer_char->move(ui_viewport->width() * hor2_offset / 100, 0); + ui_vp_sideplayer_char->move(ui_viewport->width() * hor2_offset / 100, + 0); // Finally, we reorder them based on who is more to the left. // The person more to the left is more in the front. - if (hor2_offset >= hor_offset) - { + if (hor2_offset >= hor_offset) { ui_vp_sideplayer_char->raise(); ui_vp_player_char->raise(); } - else - { + else { ui_vp_player_char->raise(); ui_vp_sideplayer_char->raise(); } @@ -1556,26 +1543,28 @@ void Courtroom::handle_chatmessage_2() ui_vp_sideplayer_char->set_flipped(true); else ui_vp_sideplayer_char->set_flipped(false); - ui_vp_sideplayer_char->play_idle(m_chatmessage[OTHER_NAME], m_chatmessage[OTHER_EMOTE]); + ui_vp_sideplayer_char->play_idle(m_chatmessage[OTHER_NAME], + m_chatmessage[OTHER_EMOTE]); } - else - { - // If the server understands other characters, but there - // really is no second character, hide 'em, and center the first. - ui_vp_sideplayer_char->hide(); - ui_vp_sideplayer_char->move(0,0); + else { + // If the server understands other characters, but there + // really is no second character, hide 'em, and center the first. + ui_vp_sideplayer_char->hide(); + ui_vp_sideplayer_char->move(0, 0); - ui_vp_player_char->move(0,0); + ui_vp_player_char->move(0, 0); } } } - switch (emote_mod) - { - case 1: case 2: case 6: + switch (emote_mod) { + case 1: + case 2: + case 6: play_preanim(false); break; - case 0: case 5: + case 0: + case 5: if (m_chatmessage[NONINTERRUPTING_PRE].toInt() == 0) handle_chatmessage_3(); else @@ -1593,51 +1582,45 @@ void Courtroom::handle_chatmessage_3() int f_evi_id = m_chatmessage[EVIDENCE_ID].toInt(); QString f_side = m_chatmessage[SIDE]; - if (f_evi_id > 0 && f_evi_id <= local_evidence_list.size()) - { - //shifted by 1 because 0 is no evidence per legacy standards + if (f_evi_id > 0 && f_evi_id <= local_evidence_list.size()) { + // shifted by 1 because 0 is no evidence per legacy standards QString f_image = local_evidence_list.at(f_evi_id - 1).image; - //def jud and hlp should display the evidence icon on the RIGHT side - bool is_left_side = !(f_side == "def" || f_side == "hlp" || f_side == "jud" || f_side == "jur"); - ui_vp_evidence_display->show_evidence(f_image, is_left_side, ui_sfx_slider->value()); + // def jud and hlp should display the evidence icon on the RIGHT side + bool is_left_side = !(f_side == "def" || f_side == "hlp" || + f_side == "jud" || f_side == "jur"); + ui_vp_evidence_display->show_evidence(f_image, is_left_side, + ui_sfx_slider->value()); } int emote_mod = m_chatmessage[EMOTE_MOD].toInt(); QString side = m_chatmessage[SIDE]; - if (emote_mod == 5 || - emote_mod == 6) - { + if (emote_mod == 5 || emote_mod == 6) { ui_vp_desk->hide(); ui_vp_legacy_desk->hide(); // Since we're zooming, hide the second character, and centre the first. - ui_vp_sideplayer_char->hide(); - ui_vp_player_char->move(0,0); + ui_vp_sideplayer_char->hide(); + ui_vp_player_char->move(0, 0); - if (side == "pro" || - side == "hlp" || - side == "wit") + if (side == "pro" || side == "hlp" || side == "wit") ui_vp_speedlines->play("prosecution_speedlines"); else ui_vp_speedlines->play("defense_speedlines"); - } int f_anim_state = 0; - //BLUE is from an enum in datatypes.h + // BLUE is from an enum in datatypes.h bool text_is_blue = m_chatmessage[TEXT_COLOR].toInt() == BLUE; - if (!text_is_blue && text_state == 1) - { - //talking + if (!text_is_blue && text_state == 1) { + // talking f_anim_state = 2; entire_message_is_blue = false; } - else - { - //idle + else { + // idle f_anim_state = 3; entire_message_is_blue = true; } @@ -1653,8 +1636,7 @@ void Courtroom::handle_chatmessage_3() ui_vp_player_char->play_talking(f_char, f_emote); anim_state = 2; } - else - { + else { ui_vp_player_char->play_idle(f_char, f_emote); anim_state = 3; } @@ -1662,31 +1644,27 @@ void Courtroom::handle_chatmessage_3() QString f_message = m_chatmessage[MESSAGE]; QStringList call_words = ao_app->get_call_words(); - for (QString word : call_words) - { - if (f_message.contains(word, Qt::CaseInsensitive)) - { + for (QString word : call_words) { + if (f_message.contains(word, Qt::CaseInsensitive)) { modcall_player->play(ao_app->get_sfx("word_call")); ao_app->alert(this); break; } } - } QString Courtroom::filter_ic_text(QString p_text) { // Get rid of centering. - if(p_text.startsWith(": ~~")) - { - // Don't forget, the p_text part actually everything after the name! - // Hence why we check for ': ~~'. + if (p_text.startsWith(": ~~")) { + // Don't forget, the p_text part actually everything after the name! + // Hence why we check for ': ~~'. - // Let's remove those two tildes, then. - // : _ ~ ~ - // 0 1 2 3 - p_text.remove(2,2); + // Let's remove those two tildes, then. + // : _ ~ ~ + // 0 1 2 3 + p_text.remove(2, 2); } // Get rid of the inline-colouring. @@ -1696,123 +1674,101 @@ QString Courtroom::filter_ic_text(QString p_text) bool ic_next_is_not_special = false; QString f_character = p_text.at(trick_check_pos); std::stack ic_colour_stack; - while (trick_check_pos < p_text.size()) - { - f_character = p_text.at(trick_check_pos); + while (trick_check_pos < p_text.size()) { + f_character = p_text.at(trick_check_pos); - // Escape character. - if (f_character == "\\" and !ic_next_is_not_special) - { - ic_next_is_not_special = true; - p_text.remove(trick_check_pos,1); - } + // Escape character. + if (f_character == "\\" and !ic_next_is_not_special) { + ic_next_is_not_special = true; + p_text.remove(trick_check_pos, 1); + } - // Text speed modifier. - else if (f_character == "{" and !ic_next_is_not_special) - { - p_text.remove(trick_check_pos,1); - } - else if (f_character == "}" and !ic_next_is_not_special) - { - p_text.remove(trick_check_pos,1); - } + // Text speed modifier. + else if (f_character == "{" and !ic_next_is_not_special) { + p_text.remove(trick_check_pos, 1); + } + else if (f_character == "}" and !ic_next_is_not_special) { + p_text.remove(trick_check_pos, 1); + } - // Orange inline colourisation. - else if (f_character == "|" and !ic_next_is_not_special) - { - if (!ic_colour_stack.empty()) - { - if (ic_colour_stack.top() == INLINE_ORANGE) - { - ic_colour_stack.pop(); - p_text.remove(trick_check_pos,1); - } - else - { - ic_colour_stack.push(INLINE_ORANGE); - p_text.remove(trick_check_pos,1); - } - } - else - { - ic_colour_stack.push(INLINE_ORANGE); - p_text.remove(trick_check_pos,1); - } + // Orange inline colourisation. + else if (f_character == "|" and !ic_next_is_not_special) { + if (!ic_colour_stack.empty()) { + if (ic_colour_stack.top() == INLINE_ORANGE) { + ic_colour_stack.pop(); + p_text.remove(trick_check_pos, 1); + } + else { + ic_colour_stack.push(INLINE_ORANGE); + p_text.remove(trick_check_pos, 1); + } } + else { + ic_colour_stack.push(INLINE_ORANGE); + p_text.remove(trick_check_pos, 1); + } + } - // Blue inline colourisation. - else if (f_character == "(" and !ic_next_is_not_special) - { - ic_colour_stack.push(INLINE_BLUE); - trick_check_pos++; + // Blue inline colourisation. + else if (f_character == "(" and !ic_next_is_not_special) { + ic_colour_stack.push(INLINE_BLUE); + trick_check_pos++; + } + else if (f_character == ")" and !ic_next_is_not_special and + !ic_colour_stack.empty()) { + if (ic_colour_stack.top() == INLINE_BLUE) { + ic_colour_stack.pop(); + trick_check_pos++; } - else if (f_character == ")" and !ic_next_is_not_special - and !ic_colour_stack.empty()) - { - if (ic_colour_stack.top() == INLINE_BLUE) - { - ic_colour_stack.pop(); - trick_check_pos++; - } - else - { - ic_next_is_not_special = true; - } + else { + ic_next_is_not_special = true; } + } - // Grey inline colourisation. - else if (f_character == "[" and !ic_next_is_not_special) - { - ic_colour_stack.push(INLINE_GREY); - trick_check_pos++; + // Grey inline colourisation. + else if (f_character == "[" and !ic_next_is_not_special) { + ic_colour_stack.push(INLINE_GREY); + trick_check_pos++; + } + else if (f_character == "]" and !ic_next_is_not_special and + !ic_colour_stack.empty()) { + if (ic_colour_stack.top() == INLINE_GREY) { + ic_colour_stack.pop(); + trick_check_pos++; } - else if (f_character == "]" and !ic_next_is_not_special - and !ic_colour_stack.empty()) - { - if (ic_colour_stack.top() == INLINE_GREY) - { - ic_colour_stack.pop(); - trick_check_pos++; - } - else - { - ic_next_is_not_special = true; - } + else { + ic_next_is_not_special = true; } + } - // Green inline colourisation. - else if (f_character == "`" and !ic_next_is_not_special) - { - if (!ic_colour_stack.empty()) - { - if (ic_colour_stack.top() == INLINE_GREEN) - { - ic_colour_stack.pop(); - p_text.remove(trick_check_pos,1); - } - else - { - ic_colour_stack.push(INLINE_GREEN); - p_text.remove(trick_check_pos,1); - } - } - else - { - ic_colour_stack.push(INLINE_GREEN); - p_text.remove(trick_check_pos,1); - } + // Green inline colourisation. + else if (f_character == "`" and !ic_next_is_not_special) { + if (!ic_colour_stack.empty()) { + if (ic_colour_stack.top() == INLINE_GREEN) { + ic_colour_stack.pop(); + p_text.remove(trick_check_pos, 1); + } + else { + ic_colour_stack.push(INLINE_GREEN); + p_text.remove(trick_check_pos, 1); + } } - else - { - trick_check_pos++; - ic_next_is_not_special = false; + else { + ic_colour_stack.push(INLINE_GREEN); + p_text.remove(trick_check_pos, 1); } + } + else { + trick_check_pos++; + ic_next_is_not_special = false; + } } return p_text; } -void Courtroom::append_ic_text(QString p_text, QString p_name, bool is_songchange) +void Courtroom::append_ic_text(QString p_text, QString p_name, + bool is_songchange) { QTextCharFormat bold; QTextCharFormat normal; @@ -1826,95 +1782,94 @@ void Courtroom::append_ic_text(QString p_text, QString p_name, bool is_songchang if (!is_songchange) p_text = filter_ic_text(p_text); - if (log_goes_downwards) - { - const bool is_scrolled_down = old_scrollbar_value == ui_ic_chatlog->verticalScrollBar()->maximum(); + if (log_goes_downwards) { + const bool is_scrolled_down = + old_scrollbar_value == ui_ic_chatlog->verticalScrollBar()->maximum(); - ui_ic_chatlog->moveCursor(QTextCursor::End); - - if (!first_message_sent) - { - ui_ic_chatlog->textCursor().insertText(p_name, bold); - first_message_sent = true; - } - else - { - ui_ic_chatlog->textCursor().insertText('\n' + p_name, bold); - } - - if (is_songchange) - { - ui_ic_chatlog->textCursor().insertText(" has played a song: ", normal); - ui_ic_chatlog->textCursor().insertText(p_text + ".", italics); - } - else - { - ui_ic_chatlog->textCursor().insertText(p_text, normal); - } - - // If we got too many blocks in the current log, delete some from the top. - while (ui_ic_chatlog->document()->blockCount() > log_maximum_blocks && log_maximum_blocks > 0) - { - ui_ic_chatlog->moveCursor(QTextCursor::Start); - ui_ic_chatlog->textCursor().select(QTextCursor::BlockUnderCursor); - ui_ic_chatlog->textCursor().removeSelectedText(); - ui_ic_chatlog->textCursor().deleteChar(); - //qDebug() << ui_ic_chatlog->document()->blockCount() << " < " << log_maximum_blocks; - } - - if (old_cursor.hasSelection() || !is_scrolled_down) - { - // The user has selected text or scrolled away from the bottom: maintain position. - ui_ic_chatlog->setTextCursor(old_cursor); - ui_ic_chatlog->verticalScrollBar()->setValue(old_scrollbar_value); - } - else - { - // The user hasn't selected any text and the scrollbar is at the bottom: scroll to the bottom. - ui_ic_chatlog->moveCursor(QTextCursor::End); - ui_ic_chatlog->verticalScrollBar()->setValue(ui_ic_chatlog->verticalScrollBar()->maximum()); - } - } - else - { - const bool is_scrolled_up = old_scrollbar_value == ui_ic_chatlog->verticalScrollBar()->minimum(); - - ui_ic_chatlog->moveCursor(QTextCursor::Start); + ui_ic_chatlog->moveCursor(QTextCursor::End); + if (!first_message_sent) { ui_ic_chatlog->textCursor().insertText(p_name, bold); + first_message_sent = true; + } + else { + ui_ic_chatlog->textCursor().insertText('\n' + p_name, bold); + } - if (is_songchange) - { - ui_ic_chatlog->textCursor().insertText(" has played a song: ", normal); - ui_ic_chatlog->textCursor().insertText(p_text + "." + '\n', italics); - } - else - { - ui_ic_chatlog->textCursor().insertText(p_text + '\n', normal); - } + if (is_songchange) { + ui_ic_chatlog->textCursor().insertText(" has played a song: ", normal); + ui_ic_chatlog->textCursor().insertText(p_text + ".", italics); + } + else { + ui_ic_chatlog->textCursor().insertText(p_text, normal); + } - // If we got too many blocks in the current log, delete some from the bottom. - while (ui_ic_chatlog->document()->blockCount() > log_maximum_blocks && log_maximum_blocks > 0) - { - ui_ic_chatlog->moveCursor(QTextCursor::End); - ui_ic_chatlog->textCursor().select(QTextCursor::BlockUnderCursor); - ui_ic_chatlog->textCursor().removeSelectedText(); - ui_ic_chatlog->textCursor().deletePreviousChar(); - //qDebug() << ui_ic_chatlog->document()->blockCount() << " < " << log_maximum_blocks; - } + // If we got too many blocks in the current log, delete some from the top. + while (ui_ic_chatlog->document()->blockCount() > log_maximum_blocks && + log_maximum_blocks > 0) { + ui_ic_chatlog->moveCursor(QTextCursor::Start); + ui_ic_chatlog->textCursor().select(QTextCursor::BlockUnderCursor); + ui_ic_chatlog->textCursor().removeSelectedText(); + ui_ic_chatlog->textCursor().deleteChar(); + // qDebug() << ui_ic_chatlog->document()->blockCount() << " < " << + // log_maximum_blocks; + } - if (old_cursor.hasSelection() || !is_scrolled_up) - { - // The user has selected text or scrolled away from the top: maintain position. - ui_ic_chatlog->setTextCursor(old_cursor); - ui_ic_chatlog->verticalScrollBar()->setValue(old_scrollbar_value); - } - else - { - // The user hasn't selected any text and the scrollbar is at the top: scroll to the top. - ui_ic_chatlog->moveCursor(QTextCursor::Start); - ui_ic_chatlog->verticalScrollBar()->setValue(ui_ic_chatlog->verticalScrollBar()->minimum()); - } + if (old_cursor.hasSelection() || !is_scrolled_down) { + // The user has selected text or scrolled away from the bottom: maintain + // position. + ui_ic_chatlog->setTextCursor(old_cursor); + ui_ic_chatlog->verticalScrollBar()->setValue(old_scrollbar_value); + } + else { + // The user hasn't selected any text and the scrollbar is at the bottom: + // scroll to the bottom. + ui_ic_chatlog->moveCursor(QTextCursor::End); + ui_ic_chatlog->verticalScrollBar()->setValue( + ui_ic_chatlog->verticalScrollBar()->maximum()); + } + } + else { + const bool is_scrolled_up = + old_scrollbar_value == ui_ic_chatlog->verticalScrollBar()->minimum(); + + ui_ic_chatlog->moveCursor(QTextCursor::Start); + + ui_ic_chatlog->textCursor().insertText(p_name, bold); + + if (is_songchange) { + ui_ic_chatlog->textCursor().insertText(" has played a song: ", normal); + ui_ic_chatlog->textCursor().insertText(p_text + "." + '\n', italics); + } + else { + ui_ic_chatlog->textCursor().insertText(p_text + '\n', normal); + } + + // If we got too many blocks in the current log, delete some from the + // bottom. + while (ui_ic_chatlog->document()->blockCount() > log_maximum_blocks && + log_maximum_blocks > 0) { + ui_ic_chatlog->moveCursor(QTextCursor::End); + ui_ic_chatlog->textCursor().select(QTextCursor::BlockUnderCursor); + ui_ic_chatlog->textCursor().removeSelectedText(); + ui_ic_chatlog->textCursor().deletePreviousChar(); + // qDebug() << ui_ic_chatlog->document()->blockCount() << " < " << + // log_maximum_blocks; + } + + if (old_cursor.hasSelection() || !is_scrolled_up) { + // The user has selected text or scrolled away from the top: maintain + // position. + ui_ic_chatlog->setTextCursor(old_cursor); + ui_ic_chatlog->verticalScrollBar()->setValue(old_scrollbar_value); + } + else { + // The user hasn't selected any text and the scrollbar is at the top: + // scroll to the top. + ui_ic_chatlog->moveCursor(QTextCursor::Start); + ui_ic_chatlog->verticalScrollBar()->setValue( + ui_ic_chatlog->verticalScrollBar()->minimum()); + } } } @@ -1923,7 +1878,8 @@ void Courtroom::play_preanim(bool noninterrupting) QString f_char = m_chatmessage[CHAR_NAME]; QString f_preanim = m_chatmessage[PRE_EMOTE]; - //all time values in char.inis are multiplied by a constant(time_mod) to get the actual time + // all time values in char.inis are multiplied by a constant(time_mod) to get + // the actual time int ao2_duration = ao_app->get_ao2_preanim_duration(f_char, f_preanim); int text_delay = ao_app->get_text_delay(f_char, f_preanim) * time_mod; int sfx_delay = m_chatmessage[SFX_DELAY].toInt() * 60; @@ -1936,10 +1892,9 @@ void Courtroom::play_preanim(bool noninterrupting) preanim_duration = ao2_duration; sfx_delay_timer->start(sfx_delay); - QString anim_to_find = ao_app->get_image_suffix(ao_app->get_character_path(f_char, f_preanim)); - if (!file_exists(anim_to_find) || - preanim_duration < 0) - { + QString anim_to_find = + ao_app->get_image_suffix(ao_app->get_character_path(f_char, f_preanim)); + if (!file_exists(anim_to_find) || preanim_duration < 0) { if (noninterrupting) anim_state = 4; else @@ -1969,19 +1924,16 @@ void Courtroom::preanim_done() handle_chatmessage_3(); } -void Courtroom::realization_done() -{ - ui_vp_realization->hide(); -} +void Courtroom::realization_done() { ui_vp_realization->hide(); } void Courtroom::start_chat_ticking() { - //we need to ensure that the text isn't already ticking because this function can be called by two logic paths + // we need to ensure that the text isn't already ticking because this function + // can be called by two logic paths if (text_state != 0) return; - if (m_chatmessage[REALIZATION] == "1") - { + if (m_chatmessage[REALIZATION] == "1") { realization_timer->start(60); ui_vp_realization->show(); sfx_player->play(ao_app->get_custom_realization(m_chatmessage[CHAR_NAME])); @@ -1991,18 +1943,16 @@ void Courtroom::start_chat_ticking() set_text_color(); rainbow_counter = 0; - if (chatmessage_is_empty) - { - //since the message is empty, it's technically done ticking + if (chatmessage_is_empty) { + // since the message is empty, it's technically done ticking text_state = 2; return; } // At this point, we'd do well to clear the inline colour stack. // This stops it from flowing into next messages. - while (!inline_colour_stack.empty()) - { - inline_colour_stack.pop(); + while (!inline_colour_stack.empty()) { + inline_colour_stack.pop(); } ui_vp_chatbox->show(); @@ -2010,8 +1960,8 @@ void Courtroom::start_chat_ticking() tick_pos = 0; blip_pos = 0; - // Just in case we somehow got inline blue text left over from a previous message, - // let's set it to false. + // Just in case we somehow got inline blue text left over from a previous + // message, let's set it to false. inline_blue_depth = 0; // At the start of every new message, we set the text speed to the default. @@ -2022,14 +1972,14 @@ void Courtroom::start_chat_ticking() blip_player->set_blips(ao_app->get_sfx_suffix("sfx-blip" + f_gender)); - //means text is currently ticking + // means text is currently ticking text_state = 1; } void Courtroom::chat_tick() { - //note: this is called fairly often(every 60 ms when char is talking) - //do not perform heavy operations here + // note: this is called fairly often(every 60 ms when char is talking) + // do not perform heavy operations here QString f_message = m_chatmessage[MESSAGE]; f_message.remove(0, tick_pos); @@ -2042,23 +1992,20 @@ void Courtroom::chat_tick() // If previously, we have detected that the message is centered, now // is the time to remove those two tildes at the start. - if (message_is_centered) - { - f_message.remove(0,2); + if (message_is_centered) { + f_message.remove(0, 2); } - if (f_message.size() == 0) - { + if (f_message.size() == 0) { text_state = 2; - if (anim_state != 4) - { + if (anim_state != 4) { anim_state = 3; - ui_vp_player_char->play_idle(m_chatmessage[CHAR_NAME], m_chatmessage[EMOTE]); + ui_vp_player_char->play_idle(m_chatmessage[CHAR_NAME], + m_chatmessage[EMOTE]); } } - else - { + else { QTextBoundaryFinder tbf(QTextBoundaryFinder::Grapheme, f_message); QString f_character; int f_char_length; @@ -2073,174 +2020,163 @@ void Courtroom::chat_tick() f_char_length = f_character.length(); f_character = f_character.toHtmlEscaped(); - if (f_character == " ") ui_vp_message->insertPlainText(" "); // Escape character. - else if (f_character == "\\" and !next_character_is_not_special) - { - next_character_is_not_special = true; - formatting_char = true; + else if (f_character == "\\" and !next_character_is_not_special) { + next_character_is_not_special = true; + formatting_char = true; } // Text speed modifier. - else if (f_character == "{" and !next_character_is_not_special) - { - // ++, because it INCREASES delay! - current_display_speed++; - formatting_char = true; + else if (f_character == "{" and !next_character_is_not_special) { + // ++, because it INCREASES delay! + current_display_speed++; + formatting_char = true; } - else if (f_character == "}" and !next_character_is_not_special) - { - current_display_speed--; - formatting_char = true; + else if (f_character == "}" and !next_character_is_not_special) { + current_display_speed--; + formatting_char = true; } // Orange inline colourisation. - else if (f_character == "|" and !next_character_is_not_special) - { - if (!inline_colour_stack.empty()) - { - if (inline_colour_stack.top() == INLINE_ORANGE) - { - inline_colour_stack.pop(); - } - else - { - inline_colour_stack.push(INLINE_ORANGE); - } + else if (f_character == "|" and !next_character_is_not_special) { + if (!inline_colour_stack.empty()) { + if (inline_colour_stack.top() == INLINE_ORANGE) { + inline_colour_stack.pop(); } - else - { - inline_colour_stack.push(INLINE_ORANGE); + else { + inline_colour_stack.push(INLINE_ORANGE); } - formatting_char = true; + } + else { + inline_colour_stack.push(INLINE_ORANGE); + } + formatting_char = true; } // Blue inline colourisation. - else if (f_character == "(" and !next_character_is_not_special) - { - inline_colour_stack.push(INLINE_BLUE); - ui_vp_message->insertHtml("" + f_character + ""); + else if (f_character == "(" and !next_character_is_not_special) { + inline_colour_stack.push(INLINE_BLUE); + ui_vp_message->insertHtml("" + f_character + ""); - // Increase how deep we are in inline blues. - inline_blue_depth++; + // Increase how deep we are in inline blues. + inline_blue_depth++; - // Here, we check if the entire message is blue. - // If it isn't, we stop talking. - if (!entire_message_is_blue and anim_state != 4) - { - QString f_char = m_chatmessage[CHAR_NAME]; - QString f_emote = m_chatmessage[EMOTE]; - ui_vp_player_char->play_idle(f_char, f_emote); - } + // Here, we check if the entire message is blue. + // If it isn't, we stop talking. + if (!entire_message_is_blue and anim_state != 4) { + QString f_char = m_chatmessage[CHAR_NAME]; + QString f_emote = m_chatmessage[EMOTE]; + ui_vp_player_char->play_idle(f_char, f_emote); + } } - else if (f_character == ")" and !next_character_is_not_special - and !inline_colour_stack.empty()) - { - if (inline_colour_stack.top() == INLINE_BLUE) - { - inline_colour_stack.pop(); - ui_vp_message->insertHtml("" + f_character + ""); + else if (f_character == ")" and !next_character_is_not_special and + !inline_colour_stack.empty()) { + if (inline_colour_stack.top() == INLINE_BLUE) { + inline_colour_stack.pop(); + ui_vp_message->insertHtml("" + f_character + ""); - // Decrease how deep we are in inline blues. - // Just in case, we do a check if we're above zero, but we should be. - if (inline_blue_depth > 0) - { - inline_blue_depth--; - // Here, we check if the entire message is blue. - // If it isn't, we start talking if we have completely climbed out of inline blues. - if (!entire_message_is_blue) - { - // We should only go back to talking if we're out of inline blues, not during a non. int. pre, and not on the last character. - if (inline_blue_depth == 0 and anim_state != 4 and !(tick_pos+1 >= f_message.size())) - { - QString f_char = m_chatmessage[CHAR_NAME]; - QString f_emote = m_chatmessage[EMOTE]; - ui_vp_player_char->play_talking(f_char, f_emote); - } - } + // Decrease how deep we are in inline blues. + // Just in case, we do a check if we're above zero, but we should be. + if (inline_blue_depth > 0) { + inline_blue_depth--; + // Here, we check if the entire message is blue. + // If it isn't, we start talking if we have completely climbed out of + // inline blues. + if (!entire_message_is_blue) { + // We should only go back to talking if we're out of inline blues, + // not during a non. int. pre, and not on the last character. + if (inline_blue_depth == 0 and anim_state != 4 and + !(tick_pos + 1 >= f_message.size())) { + QString f_char = m_chatmessage[CHAR_NAME]; + QString f_emote = m_chatmessage[EMOTE]; + ui_vp_player_char->play_talking(f_char, f_emote); } + } } - else - { - next_character_is_not_special = true; - tick_pos -= f_char_length; - } + } + else { + next_character_is_not_special = true; + tick_pos -= f_char_length; + } } // Grey inline colourisation. - else if (f_character == "[" and !next_character_is_not_special) - { - inline_colour_stack.push(INLINE_GREY); - ui_vp_message->insertHtml("" + f_character + ""); + else if (f_character == "[" and !next_character_is_not_special) { + inline_colour_stack.push(INLINE_GREY); + ui_vp_message->insertHtml("" + + f_character + ""); } - else if (f_character == "]" and !next_character_is_not_special - and !inline_colour_stack.empty()) - { - if (inline_colour_stack.top() == INLINE_GREY) - { - inline_colour_stack.pop(); - ui_vp_message->insertHtml("" + f_character + ""); - } - else - { - next_character_is_not_special = true; - tick_pos -= f_char_length; - } + else if (f_character == "]" and !next_character_is_not_special and + !inline_colour_stack.empty()) { + if (inline_colour_stack.top() == INLINE_GREY) { + inline_colour_stack.pop(); + ui_vp_message->insertHtml("" + f_character + ""); + } + else { + next_character_is_not_special = true; + tick_pos -= f_char_length; + } } // Green inline colourisation. - else if (f_character == "`" and !next_character_is_not_special) - { - if (!inline_colour_stack.empty()) - { - if (inline_colour_stack.top() == INLINE_GREEN) - { - inline_colour_stack.pop(); - formatting_char = true; - } - else - { - inline_colour_stack.push(INLINE_GREEN); - formatting_char = true; - } + else if (f_character == "`" and !next_character_is_not_special) { + if (!inline_colour_stack.empty()) { + if (inline_colour_stack.top() == INLINE_GREEN) { + inline_colour_stack.pop(); + formatting_char = true; } - else - { - inline_colour_stack.push(INLINE_GREEN); - formatting_char = true; + else { + inline_colour_stack.push(INLINE_GREEN); + formatting_char = true; } - } - else - { - next_character_is_not_special = false; - if (!inline_colour_stack.empty()) - { - switch (inline_colour_stack.top()) { - case INLINE_ORANGE: - ui_vp_message->insertHtml("" + f_character + ""); - break; - case INLINE_BLUE: - ui_vp_message->insertHtml("" + f_character + ""); - break; - case INLINE_GREEN: - ui_vp_message->insertHtml("" + f_character + ""); - break; - case INLINE_GREY: - ui_vp_message->insertHtml("" + f_character + ""); - break; - } } - else - { - if (m_chatmessage[TEXT_COLOR].toInt() == RAINBOW) - { + else { + inline_colour_stack.push(INLINE_GREEN); + formatting_char = true; + } + } + else { + next_character_is_not_special = false; + if (!inline_colour_stack.empty()) { + switch (inline_colour_stack.top()) { + case INLINE_ORANGE: + ui_vp_message->insertHtml( + "" + + f_character + ""); + break; + case INLINE_BLUE: + ui_vp_message->insertHtml( + "" + f_character + ""); + break; + case INLINE_GREEN: + ui_vp_message->insertHtml( + "" + f_character + ""); + break; + case INLINE_GREY: + ui_vp_message->insertHtml("" + f_character + ""); + break; + } + } + else { + if (m_chatmessage[TEXT_COLOR].toInt() == RAINBOW) { QString html_color; - switch (rainbow_counter) - { + switch (rainbow_counter) { case 0: html_color = get_text_color(QString::number(RED)).name(); break; @@ -2260,33 +2196,30 @@ void Courtroom::chat_tick() ++rainbow_counter; - ui_vp_message->insertHtml("" + f_character + ""); + ui_vp_message->insertHtml("" + + f_character + ""); } else ui_vp_message->insertHtml(f_character); } - if (message_is_centered) - { - ui_vp_message->setAlignment(Qt::AlignCenter); + if (message_is_centered) { + ui_vp_message->setAlignment(Qt::AlignCenter); } - else - { - ui_vp_message->setAlignment(Qt::AlignLeft); + else { + ui_vp_message->setAlignment(Qt::AlignLeft); } } QScrollBar *scroll = ui_vp_message->verticalScrollBar(); scroll->setValue(scroll->maximum()); - if(blank_blip) + if (blank_blip) qDebug() << "blank_blip found true"; - if (f_character != ' ' || blank_blip) - { + if (f_character != ' ' || blank_blip) { - if (blip_pos % blip_rate == 0 && !formatting_char) - { + if (blip_pos % blip_rate == 0 && !formatting_char) { blip_pos = 0; blip_player->blip_tick(); } @@ -2296,32 +2229,27 @@ void Courtroom::chat_tick() tick_pos += f_char_length; - // Restart the timer, but according to the newly set speeds, if there were any. - // Keep the speed at bay. - if (current_display_speed < 0) - { - current_display_speed = 0; + // Restart the timer, but according to the newly set speeds, if there were + // any. Keep the speed at bay. + if (current_display_speed < 0) { + current_display_speed = 0; } - if (current_display_speed > 6) - { - current_display_speed = 6; + if (current_display_speed > 6) { + current_display_speed = 6; } - // If we had a formatting char, we shouldn't wait so long again, as it won't appear! - if (formatting_char) - { - chat_tick_timer->start(1); + // If we had a formatting char, we shouldn't wait so long again, as it won't + // appear! + if (formatting_char) { + chat_tick_timer->start(1); } - else - { - chat_tick_timer->start(message_display_speed[current_display_speed]); + else { + chat_tick_timer->start(message_display_speed[current_display_speed]); } - } } - void Courtroom::show_testimony() { if (!testimony_in_progress || m_chatmessage[SIDE] != "wit") @@ -2357,57 +2285,51 @@ void Courtroom::set_scene() if (testimony_in_progress) show_testimony(); - //witness is default if pos is invalid + // witness is default if pos is invalid QString f_background = "witnessempty"; QString f_desk_image = "stand"; QString f_desk_mod = m_chatmessage[DESK_MOD]; QString f_side = m_chatmessage[SIDE]; - if (f_side == "def") - { + if (f_side == "def") { f_background = "defenseempty"; if (is_ao2_bg) f_desk_image = "defensedesk"; else f_desk_image = "bancodefensa"; } - else if (f_side == "pro") - { + else if (f_side == "pro") { f_background = "prosecutorempty"; if (is_ao2_bg) f_desk_image = "prosecutiondesk"; else f_desk_image = "bancoacusacion"; } - else if (f_side == "jud") - { + else if (f_side == "jud") { f_background = "judgestand"; f_desk_image = "judgedesk"; } - else if (f_side == "hld") - { + else if (f_side == "hld") { f_background = "helperstand"; f_desk_image = "helperdesk"; } - else if (f_side == "hlp") - { + else if (f_side == "hlp") { f_background = "prohelperstand"; f_desk_image = "prohelperdesk"; } - else if (f_side == "jur" && (file_exists(ao_app->get_background_path("jurystand.png")) || - file_exists(ao_app->get_background_path("jurystand.gif")))) - { + else if (f_side == "jur" && + (file_exists(ao_app->get_background_path("jurystand.png")) || + file_exists(ao_app->get_background_path("jurystand.gif")))) { f_background = "jurystand"; f_desk_image = "jurydesk"; } - else if (f_side == "sea" && (file_exists(ao_app->get_background_path("seancestand.png")) || - file_exists(ao_app->get_background_path("seancestand.gif")))) - { + else if (f_side == "sea" && + (file_exists(ao_app->get_background_path("seancestand.png")) || + file_exists(ao_app->get_background_path("seancestand.gif")))) { f_background = "seancestand"; f_desk_image = "seancedesk"; } - else - { + else { if (is_ao2_bg) f_desk_image = "stand"; else @@ -2418,30 +2340,23 @@ void Courtroom::set_scene() ui_vp_desk->set_image(f_desk_image); ui_vp_legacy_desk->set_legacy_desk(f_desk_image); - if (f_desk_mod == "0" || (f_desk_mod != "1" && - (f_side == "jud" || - f_side == "hld" || - f_side == "hlp"))) - { + if (f_desk_mod == "0" || + (f_desk_mod != "1" && + (f_side == "jud" || f_side == "hld" || f_side == "hlp"))) { ui_vp_desk->hide(); ui_vp_legacy_desk->hide(); } - else if (is_ao2_bg || (f_side == "jud" || - f_side == "hld" || - f_side == "hlp")) - { + else if (is_ao2_bg || + (f_side == "jud" || f_side == "hld" || f_side == "hlp")) { ui_vp_legacy_desk->hide(); ui_vp_desk->show(); } - else - { - if (f_side == "wit") - { + else { + if (f_side == "wit") { ui_vp_desk->show(); ui_vp_legacy_desk->hide(); } - else - { + else { ui_vp_desk->hide(); ui_vp_legacy_desk->show(); } @@ -2450,9 +2365,10 @@ void Courtroom::set_scene() void Courtroom::set_text_color() { - QColor textcolor = ao_app->get_chat_color(m_chatmessage[TEXT_COLOR], ao_app->get_chat(m_chatmessage[CHAR_NAME])); + QColor textcolor = ao_app->get_chat_color( + m_chatmessage[TEXT_COLOR], ao_app->get_chat(m_chatmessage[CHAR_NAME])); - ui_vp_message->setTextBackgroundColor(QColor(0,0,0,0)); + ui_vp_message->setTextBackgroundColor(QColor(0, 0, 0, 0)); ui_vp_message->setTextColor(textcolor); QString style = "background-color: rgba(0, 0, 0, 0);"; @@ -2469,7 +2385,8 @@ void Courtroom::set_text_color() QColor Courtroom::get_text_color(QString color) { - return ao_app->get_chat_color(color, ao_app->get_chat(m_chatmessage[CHAR_NAME])); + return ao_app->get_chat_color(color, + ao_app->get_chat(m_chatmessage[CHAR_NAME])); } void Courtroom::set_ip_list(QString p_list) @@ -2486,8 +2403,7 @@ void Courtroom::set_mute(bool p_muted, int p_cid) if (p_muted) ui_muted->show(); - else - { + else { ui_muted->hide(); ui_ic_chat_message->setFocus(); } @@ -2522,27 +2438,23 @@ void Courtroom::handle_song(QStringList *p_contents) f_song_clear = f_song_clear.left(f_song_clear.lastIndexOf(".")); int n_char = f_contents.at(1).toInt(); - if (n_char < 0 || n_char >= char_list.size()) - { + if (n_char < 0 || n_char >= char_list.size()) { music_player->play(f_song); } - else - { + else { QString str_char = char_list.at(n_char).name; QString str_show = char_list.at(n_char).name; - if (p_contents->length() > 2) - { - str_show = p_contents->at(2); + if (p_contents->length() > 2) { + str_show = p_contents->at(2); } - if (!mute_map.value(n_char)) - { - chatlogpiece* temp = new chatlogpiece(str_char, str_show, f_song, true); + if (!mute_map.value(n_char)) { + chatlogpiece *temp = new chatlogpiece(str_char, str_show, f_song, true); ic_chatlog_history.append(*temp); - while(ic_chatlog_history.size() > log_maximum_blocks && log_maximum_blocks > 0) - { + while (ic_chatlog_history.size() > log_maximum_blocks && + log_maximum_blocks > 0) { ic_chatlog_history.removeFirst(); } @@ -2556,33 +2468,29 @@ void Courtroom::handle_wtce(QString p_wtce, int variant) { QString sfx_file = "courtroom_sounds.ini"; - //witness testimony - if (p_wtce == "testimony1") - { + // witness testimony + if (p_wtce == "testimony1") { sfx_player->play(ao_app->get_sfx("witness_testimony")); ui_vp_wtce->play("witnesstestimony"); testimony_in_progress = true; show_testimony(); } - //cross examination - else if (p_wtce == "testimony2") - { + // cross examination + else if (p_wtce == "testimony2") { sfx_player->play(ao_app->get_sfx("cross_examination")); ui_vp_wtce->play("crossexamination"); testimony_in_progress = false; } - else if (p_wtce == "judgeruling") - { - if (variant == 0) - { - sfx_player->play(ao_app->get_sfx("not_guilty")); - ui_vp_wtce->play("notguilty"); - testimony_in_progress = false; + else if (p_wtce == "judgeruling") { + if (variant == 0) { + sfx_player->play(ao_app->get_sfx("not_guilty")); + ui_vp_wtce->play("notguilty"); + testimony_in_progress = false; } else if (variant == 1) { - sfx_player->play(ao_app->get_sfx("guilty")); - ui_vp_wtce->play("guilty"); - testimony_in_progress = false; + sfx_player->play(ao_app->get_sfx("guilty")); + ui_vp_wtce->play("guilty"); + testimony_in_progress = false; } } } @@ -2592,22 +2500,20 @@ void Courtroom::set_hp_bar(int p_bar, int p_state) if (p_state < 0 || p_state > 10) return; - if (p_bar == 1) - { + if (p_bar == 1) { ui_defense_bar->set_image("defensebar" + QString::number(p_state) + ".png"); defense_bar_state = p_state; } - else if (p_bar == 2) - { - ui_prosecution_bar->set_image("prosecutionbar" + QString::number(p_state) + ".png"); + else if (p_bar == 2) { + ui_prosecution_bar->set_image("prosecutionbar" + QString::number(p_state) + + ".png"); prosecution_bar_state = p_state; } } void Courtroom::toggle_judge_buttons(bool is_on) { - if (is_on) - { + if (is_on) { ui_witness_testimony->show(); ui_cross_examination->show(); ui_guilty->show(); @@ -2617,8 +2523,7 @@ void Courtroom::toggle_judge_buttons(bool is_on) ui_prosecution_minus->show(); ui_prosecution_plus->show(); } - else - { + else { ui_witness_testimony->hide(); ui_cross_examination->hide(); ui_guilty->hide(); @@ -2633,26 +2538,24 @@ void Courtroom::toggle_judge_buttons(bool is_on) void Courtroom::mod_called(QString p_ip) { ui_server_chatlog->append(p_ip); - if (ui_guard->isChecked()) - { + if (ui_guard->isChecked()) { modcall_player->play(ao_app->get_sfx("mod_call")); ao_app->alert(this); } } -void Courtroom::case_called(QString msg, bool def, bool pro, bool jud, bool jur, bool steno) +void Courtroom::case_called(QString msg, bool def, bool pro, bool jud, bool jur, + bool steno) { - if (ui_casing->isChecked()) - { + if (ui_casing->isChecked()) { ui_server_chatlog->append(msg); if ((ao_app->get_casing_defence_enabled() && def) || (ao_app->get_casing_prosecution_enabled() && pro) || (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")); - ao_app->alert(this); + (ao_app->get_casing_steno_enabled() && steno)) { + modcall_player->play(ao_app->get_sfx("case_call")); + ao_app->alert(this); } } } @@ -2664,104 +2567,100 @@ void Courtroom::on_ooc_return_pressed() if (ooc_message == "" || ui_ooc_chat_name->text() == "") return; - if (ooc_message.startsWith("/pos")) - { - if (ooc_message == "/pos jud") - { + if (ooc_message.startsWith("/pos")) { + if (ooc_message == "/pos jud") { toggle_judge_buttons(true); } - else - { + else { toggle_judge_buttons(false); } } - else if (ooc_message.startsWith("/login")) - { + else if (ooc_message.startsWith("/login")) { ui_guard->show(); - append_server_chatmessage("CLIENT", "You were granted the Guard button.", "1"); + append_server_chatmessage("CLIENT", "You were granted the Guard button.", + "1"); } - else if (ooc_message.startsWith("/rainbow") && ao_app->yellow_text_enabled && !rainbow_appended) - { - //ui_text_color->addItem("Rainbow"); + else if (ooc_message.startsWith("/rainbow") && ao_app->yellow_text_enabled && + !rainbow_appended) { + // ui_text_color->addItem("Rainbow"); ui_ooc_chat_message->clear(); - //rainbow_appended = true; - append_server_chatmessage("CLIENT", "This does nohing, but there you go.", "1"); + // rainbow_appended = true; + append_server_chatmessage("CLIENT", "This does nohing, but there you go.", + "1"); return; } - else if (ooc_message.startsWith("/settings")) - { + else if (ooc_message.startsWith("/settings")) { ui_ooc_chat_message->clear(); ao_app->call_settings_menu(); append_server_chatmessage("CLIENT", "You opened the settings menu.", "1"); return; } - else if (ooc_message.startsWith("/pair")) - { + else if (ooc_message.startsWith("/pair")) { ui_ooc_chat_message->clear(); - ooc_message.remove(0,6); - + ooc_message.remove(0, 6); + bool ok; int whom = ooc_message.toInt(&ok); - if (ok) - { - if (whom > -1) - { + if (ok) { + if (whom > -1) { other_charid = whom; QString msg = "You will now pair up with "; msg.append(char_list.at(whom).name); msg.append(" if they also choose your character in return."); append_server_chatmessage("CLIENT", msg, "1"); } - else - { + else { other_charid = -1; - append_server_chatmessage("CLIENT", "You are no longer paired with anyone.", "1"); + append_server_chatmessage("CLIENT", + "You are no longer paired with anyone.", "1"); } } - else - { - append_server_chatmessage("CLIENT", "Are you sure you typed that well? The char ID could not be recognised.", "1"); + else { + append_server_chatmessage("CLIENT", + "Are you sure you typed that well? The char ID " + "could not be recognised.", + "1"); } return; } - else if (ooc_message.startsWith("/offset")) - { + else if (ooc_message.startsWith("/offset")) { ui_ooc_chat_message->clear(); - ooc_message.remove(0,8); - + ooc_message.remove(0, 8); + bool ok; int off = ooc_message.toInt(&ok); - if (ok) - { - if (off >= -100 && off <= 100) - { + if (ok) { + if (off >= -100 && off <= 100) { offset_with_pair = off; QString msg = "You have set your offset to "; msg.append(QString::number(off)); msg.append("%."); append_server_chatmessage("CLIENT", msg, "1"); } - else - { - append_server_chatmessage("CLIENT", "Your offset must be between -100% and 100%!", "1"); + else { + append_server_chatmessage( + "CLIENT", "Your offset must be between -100% and 100%!", "1"); } } - else - { - append_server_chatmessage("CLIENT", "That offset does not look like one.", "1"); + else { + append_server_chatmessage("CLIENT", "That offset does not look like one.", + "1"); } return; } - else if (ooc_message.startsWith("/switch_am")) - { - append_server_chatmessage("CLIENT", "You switched your music and area list.", "1"); - on_switch_area_music_clicked(); - ui_ooc_chat_message->clear(); - return; + else if (ooc_message.startsWith("/switch_am")) { + append_server_chatmessage("CLIENT", + "You switched your music and area list.", "1"); + on_switch_area_music_clicked(); + ui_ooc_chat_message->clear(); + return; } - else if (ooc_message.startsWith("/enable_blocks")) - { - append_server_chatmessage("CLIENT", "You have forcefully enabled features that the server may not support. You may not be able to talk IC, or worse, because of this.", "1"); + else if (ooc_message.startsWith("/enable_blocks")) { + append_server_chatmessage( + "CLIENT", + "You have forcefully enabled features that the server may not support. " + "You may not be able to talk IC, or worse, because of this.", + "1"); ao_app->cccc_ic_support_enabled = true; ao_app->arup_enabled = true; ao_app->modcall_reason_enabled = true; @@ -2769,23 +2668,24 @@ void Courtroom::on_ooc_return_pressed() ui_ooc_chat_message->clear(); return; } - else if (ooc_message.startsWith("/non_int_pre")) - { + else if (ooc_message.startsWith("/non_int_pre")) { if (ui_pre_non_interrupt->isChecked()) - append_server_chatmessage("CLIENT", "Your pre-animations interrupt again.", "1"); + append_server_chatmessage("CLIENT", + "Your pre-animations interrupt again.", "1"); else - append_server_chatmessage("CLIENT", "Your pre-animations will not interrupt text.", "1"); + append_server_chatmessage( + "CLIENT", "Your pre-animations will not interrupt text.", "1"); ui_pre_non_interrupt->setChecked(!ui_pre_non_interrupt->isChecked()); ui_ooc_chat_message->clear(); return; } - else if (ooc_message.startsWith("/save_chatlog")) - { + else if (ooc_message.startsWith("/save_chatlog")) { QFile file("chatlog.txt"); - if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) - { - append_server_chatmessage("CLIENT", "Couldn't open chatlog.txt to write into.", "1"); + if (!file.open(QIODevice::WriteOnly | QIODevice::Text | + QIODevice::Truncate)) { + append_server_chatmessage( + "CLIENT", "Couldn't open chatlog.txt to write into.", "1"); ui_ooc_chat_message->clear(); return; } @@ -2793,8 +2693,8 @@ void Courtroom::on_ooc_return_pressed() QTextStream out(&file); foreach (chatlogpiece item, ic_chatlog_history) { - out << item.get_full() << '\n'; - } + out << item.get_full() << '\n'; + } file.close(); @@ -2802,39 +2702,49 @@ void Courtroom::on_ooc_return_pressed() ui_ooc_chat_message->clear(); return; } - else if (ooc_message.startsWith("/load_case")) - { + else if (ooc_message.startsWith("/load_case")) { QStringList command = ooc_message.split(" ", QString::SkipEmptyParts); QDir casefolder("base/cases"); - if (!casefolder.exists()) - { - QDir::current().mkdir("base/" + casefolder.dirName()); - append_server_chatmessage("CLIENT", "You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely the case file you're looking for can't be found in there.", "1"); - ui_ooc_chat_message->clear(); - return; + if (!casefolder.exists()) { + QDir::current().mkdir("base/" + casefolder.dirName()); + append_server_chatmessage( + "CLIENT", + "You don't have a `base/cases/` folder! It was just made for you, " + "but seeing as it WAS just made for you, it's likely the case file " + "you're looking for can't be found in there.", + "1"); + ui_ooc_chat_message->clear(); + return; } QStringList caseslist = casefolder.entryList(); caseslist.removeOne("."); caseslist.removeOne(".."); - caseslist.replaceInStrings(".ini",""); + caseslist.replaceInStrings(".ini", ""); - if (command.size() < 2) - { - append_server_chatmessage("CLIENT", "You need to give a filename to load (extension not needed)! Make sure that it is in the `base/cases/` folder, and that it is a correctly formatted ini.\nCases you can load: " + caseslist.join(", "), "1"); + if (command.size() < 2) { + append_server_chatmessage( + "CLIENT", + "You need to give a filename to load (extension not needed)! Make " + "sure that it is in the `base/cases/` folder, and that it is a " + "correctly formatted ini.\nCases you can load: " + + caseslist.join(", "), + "1"); ui_ooc_chat_message->clear(); return; } - - if (command.size() > 2) - { - append_server_chatmessage("CLIENT", "Too many arguments to load a case! You only need one filename, without extension.", "1"); + if (command.size() > 2) { + append_server_chatmessage("CLIENT", + "Too many arguments to load a case! You only " + "need one filename, without extension.", + "1"); ui_ooc_chat_message->clear(); return; } - QSettings casefile("base/cases/" + command[1] + ".ini", QSettings::IniFormat); + QSettings casefile("base/cases/" + command[1] + ".ini", + QSettings::IniFormat); QString caseauth = casefile.value("author", "").value(); QString casedoc = casefile.value("doc", "").value(); @@ -2842,88 +2752,108 @@ void Courtroom::on_ooc_return_pressed() QString casestatus = casefile.value("status", "").value(); if (!caseauth.isEmpty()) - append_server_chatmessage("CLIENT", "Case made by " + caseauth + ".", "1"); + append_server_chatmessage("CLIENT", "Case made by " + caseauth + ".", + "1"); if (!casedoc.isEmpty()) - ao_app->send_server_packet(new AOPacket("CT#" + ui_ooc_chat_name->text() + "#/doc " + casedoc + "#%")); + ao_app->send_server_packet(new AOPacket("CT#" + ui_ooc_chat_name->text() + + "#/doc " + casedoc + "#%")); if (!casestatus.isEmpty()) - ao_app->send_server_packet(new AOPacket("CT#" + ui_ooc_chat_name->text() + "#/status " + casestatus + "#%")); + ao_app->send_server_packet(new AOPacket("CT#" + ui_ooc_chat_name->text() + + "#/status " + casestatus + "#%")); if (!cmdoc.isEmpty()) - append_server_chatmessage("CLIENT", "Navigate to " + cmdoc + " for the CM doc.", "1"); + append_server_chatmessage( + "CLIENT", "Navigate to " + cmdoc + " for the CM doc.", "1"); for (int i = local_evidence_list.size() - 1; i >= 0; i--) { - ao_app->send_server_packet(new AOPacket("DE#" + QString::number(i) + "#%")); + ao_app->send_server_packet( + new AOPacket("DE#" + QString::number(i) + "#%")); } foreach (QString evi, casefile.childGroups()) { - if (evi == "General") - continue; + if (evi == "General") + continue; - QStringList f_contents; + QStringList f_contents; - f_contents.append(casefile.value(evi + "/name", "UNKNOWN").value()); - f_contents.append(casefile.value(evi + "/description", "UNKNOWN").value()); - f_contents.append(casefile.value(evi + "/image", "UNKNOWN.png").value()); + f_contents.append( + casefile.value(evi + "/name", "UNKNOWN").value()); + f_contents.append( + casefile.value(evi + "/description", "UNKNOWN").value()); + f_contents.append( + casefile.value(evi + "/image", "UNKNOWN.png").value()); - ao_app->send_server_packet(new AOPacket("PE", f_contents)); - } + ao_app->send_server_packet(new AOPacket("PE", f_contents)); + } - append_server_chatmessage("CLIENT", "Your case \"" + command[1] + "\" was loaded!", "1"); + append_server_chatmessage( + "CLIENT", "Your case \"" + command[1] + "\" was loaded!", "1"); ui_ooc_chat_message->clear(); return; } - else if(ooc_message.startsWith("/save_case")) - { - QStringList command = ooc_message.split(" ", QString::SkipEmptyParts); + else if (ooc_message.startsWith("/save_case")) { + QStringList command = ooc_message.split(" ", QString::SkipEmptyParts); - QDir casefolder("base/cases"); - if (!casefolder.exists()) - { - QDir::current().mkdir("base/" + casefolder.dirName()); - append_server_chatmessage("CLIENT", "You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely that you somehow deleted it.", "1"); - ui_ooc_chat_message->clear(); - return; - } - QStringList caseslist = casefolder.entryList(); - caseslist.removeOne("."); - caseslist.removeOne(".."); - caseslist.replaceInStrings(".ini",""); - - if (command.size() < 3) - { - append_server_chatmessage("CLIENT", "You need to give a filename to save (extension not needed) and the courtroom status!", "1"); - ui_ooc_chat_message->clear(); - return; - } - - - if (command.size() > 3) - { - append_server_chatmessage("CLIENT", "Too many arguments to save a case! You only need a filename without extension and the courtroom status!", "1"); - ui_ooc_chat_message->clear(); - return; - } - QSettings casefile("base/cases/" + command[1] + ".ini", QSettings::IniFormat); - casefile.setValue("author",ui_ooc_chat_name->text()); - casefile.setValue("cmdoc",""); - casefile.setValue("doc", ""); - casefile.setValue("status",command[2]); - casefile.sync(); - for(int i = local_evidence_list.size() - 1; i >= 0; i--) - { - QString clean_evidence_dsc = local_evidence_list[i].description.replace(QRegularExpression("..."), ""); - clean_evidence_dsc = clean_evidence_dsc.replace(clean_evidence_dsc.lastIndexOf(">"), 1, ""); - casefile.beginGroup(QString::number(i)); - casefile.sync(); - casefile.setValue("name",local_evidence_list[i].name); - casefile.setValue("description",local_evidence_list[i].description); - casefile.setValue("image",local_evidence_list[i].image); - casefile.endGroup(); - } - casefile.sync(); - append_server_chatmessage("CLIENT", "Succesfully saved, edit doc and cmdoc link on the ini!", "1"); + QDir casefolder("base/cases"); + if (!casefolder.exists()) { + QDir::current().mkdir("base/" + casefolder.dirName()); + append_server_chatmessage( + "CLIENT", + "You don't have a `base/cases/` folder! It was just made for you, " + "but seeing as it WAS just made for you, it's likely that you " + "somehow deleted it.", + "1"); ui_ooc_chat_message->clear(); return; + } + QStringList caseslist = casefolder.entryList(); + caseslist.removeOne("."); + caseslist.removeOne(".."); + caseslist.replaceInStrings(".ini", ""); + if (command.size() < 3) { + append_server_chatmessage( + "CLIENT", + "You need to give a filename to save (extension not needed) and the " + "courtroom status!", + "1"); + ui_ooc_chat_message->clear(); + return; + } + + if (command.size() > 3) { + append_server_chatmessage( + "CLIENT", + "Too many arguments to save a case! You only need a filename without " + "extension and the courtroom status!", + "1"); + ui_ooc_chat_message->clear(); + return; + } + QSettings casefile("base/cases/" + command[1] + ".ini", + QSettings::IniFormat); + casefile.setValue("author", ui_ooc_chat_name->text()); + casefile.setValue("cmdoc", ""); + casefile.setValue("doc", ""); + casefile.setValue("status", command[2]); + casefile.sync(); + for (int i = local_evidence_list.size() - 1; i >= 0; i--) { + QString clean_evidence_dsc = local_evidence_list[i].description.replace( + QRegularExpression("..."), ""); + clean_evidence_dsc = clean_evidence_dsc.replace( + clean_evidence_dsc.lastIndexOf(">"), 1, ""); + casefile.beginGroup(QString::number(i)); + casefile.sync(); + casefile.setValue("name", local_evidence_list[i].name); + casefile.setValue("description", local_evidence_list[i].description); + casefile.setValue("image", local_evidence_list[i].image); + casefile.endGroup(); + } + casefile.sync(); + append_server_chatmessage( + "CLIENT", "Succesfully saved, edit doc and cmdoc link on the ini!", + "1"); + ui_ooc_chat_message->clear(); + return; } QStringList packet_contents; @@ -2944,16 +2874,14 @@ void Courtroom::on_ooc_return_pressed() void Courtroom::on_ooc_toggle_clicked() { - if (server_ooc) - { + if (server_ooc) { ui_ms_chatlog->show(); ui_server_chatlog->hide(); ui_ooc_toggle->setText("Master"); server_ooc = false; } - else - { + else { ui_ms_chatlog->hide(); ui_server_chatlog->show(); ui_ooc_toggle->setText("Server"); @@ -2964,7 +2892,7 @@ void Courtroom::on_ooc_toggle_clicked() void Courtroom::on_music_search_edited(QString p_text) { - //preventing compiler warnings + // preventing compiler warnings p_text += "a"; list_music(); list_areas(); @@ -2981,8 +2909,7 @@ void Courtroom::on_pos_dropdown_changed(int p_index) QString f_pos; - switch (p_index) - { + switch (p_index) { case 0: f_pos = "wit"; break; @@ -3009,7 +2936,8 @@ void Courtroom::on_pos_dropdown_changed(int p_index) if (f_pos == "" || ui_ooc_chat_name->text() == "") return; - ao_app->send_server_packet(new AOPacket("CT#" + ui_ooc_chat_name->text() + "#/pos " + f_pos + "#%")); + ao_app->send_server_packet( + new AOPacket("CT#" + ui_ooc_chat_name->text() + "#/pos " + f_pos + "#%")); } void Courtroom::on_mute_list_clicked(QModelIndex p_index) @@ -3025,25 +2953,21 @@ void Courtroom::on_mute_list_clicked(QModelIndex p_index) int f_cid = -1; - for (int n_char = 0 ; n_char < char_list.size() ; n_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 < 0 || f_cid >= char_list.size()) - { + if (f_cid < 0 || f_cid >= char_list.size()) { qDebug() << "W: " << real_char << " not present in char_list"; return; } - if (mute_map.value(f_cid)) - { + if (mute_map.value(f_cid)) { mute_map.insert(f_cid, false); f_item->setText(real_char); } - else - { + else { mute_map.insert(f_cid, true); f_item->setText(real_char + " [x]"); } @@ -3056,26 +2980,19 @@ void Courtroom::on_pair_list_clicked(QModelIndex p_index) QString real_char; int f_cid = -1; - if (f_char.endsWith(" [x]")) - { + 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; - } + 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()) - { + if (f_cid < -2 || f_cid >= char_list.size()) { qDebug() << "W: " << real_char << " not present in char_list"; return; } @@ -3093,9 +3010,8 @@ void Courtroom::on_pair_list_clicked(QModelIndex p_index) 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]"); + if (other_charid != -1) { + f_item->setText(real_char + " [x]"); } } @@ -3106,31 +3022,34 @@ void Courtroom::on_music_list_double_clicked(QModelIndex p_model) QString p_song = music_list.at(music_row_to_number.at(p_model.row())); - if (!ui_ic_chat_name->text().isEmpty() && ao_app->cccc_ic_support_enabled) - { - ao_app->send_server_packet(new AOPacket("MC#" + p_song + "#" + QString::number(m_cid) + "#" + ui_ic_chat_name->text() + "#%"), false); + if (!ui_ic_chat_name->text().isEmpty() && ao_app->cccc_ic_support_enabled) { + ao_app->send_server_packet(new AOPacket("MC#" + p_song + "#" + + QString::number(m_cid) + "#" + + ui_ic_chat_name->text() + "#%"), + false); } - else - { - ao_app->send_server_packet(new AOPacket("MC#" + p_song + "#" + QString::number(m_cid) + "#%"), false); + else { + ao_app->send_server_packet( + new AOPacket("MC#" + p_song + "#" + QString::number(m_cid) + "#%"), + false); } } void Courtroom::on_area_list_double_clicked(QModelIndex p_model) { - QString p_area = area_list.at(area_row_to_number.at(p_model.row())); - ao_app->send_server_packet(new AOPacket("MC#" + p_area + "#" + QString::number(m_cid) + "#%"), false); + QString p_area = area_list.at(area_row_to_number.at(p_model.row())); + ao_app->send_server_packet( + new AOPacket("MC#" + p_area + "#" + QString::number(m_cid) + "#%"), + false); } void Courtroom::on_hold_it_clicked() { - if (objection_state == 1) - { + if (objection_state == 1) { ui_hold_it->set_image("holdit.png"); objection_state = 0; } - else - { + else { ui_objection->set_image("objection.png"); ui_take_that->set_image("takethat.png"); ui_custom_objection->set_image("custom.png"); @@ -3144,13 +3063,11 @@ void Courtroom::on_hold_it_clicked() void Courtroom::on_objection_clicked() { - if (objection_state == 2) - { + if (objection_state == 2) { ui_objection->set_image("objection.png"); objection_state = 0; } - else - { + else { ui_hold_it->set_image("holdit.png"); ui_take_that->set_image("takethat.png"); ui_custom_objection->set_image("custom.png"); @@ -3164,13 +3081,11 @@ void Courtroom::on_objection_clicked() void Courtroom::on_take_that_clicked() { - if (objection_state == 3) - { + if (objection_state == 3) { ui_take_that->set_image("takethat.png"); objection_state = 0; } - else - { + else { ui_objection->set_image("objection.png"); ui_hold_it->set_image("holdit.png"); ui_custom_objection->set_image("custom.png"); @@ -3184,13 +3099,11 @@ void Courtroom::on_take_that_clicked() void Courtroom::on_custom_objection_clicked() { - if (objection_state == 4) - { + if (objection_state == 4) { ui_custom_objection->set_image("custom.png"); objection_state = 0; } - else - { + else { ui_objection->set_image("objection.png"); ui_take_that->set_image("takethat.png"); ui_hold_it->set_image("holdit.png"); @@ -3204,13 +3117,11 @@ void Courtroom::on_custom_objection_clicked() void Courtroom::on_realization_clicked() { - if (realization_state == 0) - { + if (realization_state == 0) { realization_state = 1; ui_realization->set_image("realization_pressed.png"); } - else - { + else { realization_state = 0; ui_realization->set_image("realization.png"); } @@ -3220,16 +3131,14 @@ void Courtroom::on_realization_clicked() void Courtroom::on_mute_clicked() { - if (ui_mute_list->isHidden()) - { + if (ui_mute_list->isHidden()) { ui_mute_list->show(); ui_pair_list->hide(); ui_pair_offset_spinbox->hide(); ui_pair_button->set_image("pair_button.png"); ui_mute->set_image("mute_pressed.png"); } - else - { + else { ui_mute_list->hide(); ui_mute->set_image("mute.png"); } @@ -3237,16 +3146,14 @@ void Courtroom::on_mute_clicked() void Courtroom::on_pair_clicked() { - if (ui_pair_list->isHidden()) - { + if (ui_pair_list->isHidden()) { ui_pair_list->show(); ui_pair_offset_spinbox->show(); ui_mute_list->hide(); ui_mute->set_image("mute.png"); ui_pair_button->set_image("pair_button_pressed.png"); } - else - { + else { ui_pair_list->hide(); ui_pair_offset_spinbox->hide(); ui_pair_button->set_image("pair_button.png"); @@ -3258,7 +3165,8 @@ void Courtroom::on_defense_minus_clicked() int f_state = defense_bar_state - 1; if (f_state >= 0) - ao_app->send_server_packet(new AOPacket("HP#1#" + QString::number(f_state) + "#%")); + ao_app->send_server_packet( + new AOPacket("HP#1#" + QString::number(f_state) + "#%")); } void Courtroom::on_defense_plus_clicked() @@ -3266,7 +3174,8 @@ void Courtroom::on_defense_plus_clicked() int f_state = defense_bar_state + 1; if (f_state <= 10) - ao_app->send_server_packet(new AOPacket("HP#1#" + QString::number(f_state) + "#%")); + ao_app->send_server_packet( + new AOPacket("HP#1#" + QString::number(f_state) + "#%")); } void Courtroom::on_prosecution_minus_clicked() @@ -3274,7 +3183,8 @@ void Courtroom::on_prosecution_minus_clicked() int f_state = prosecution_bar_state - 1; if (f_state >= 0) - ao_app->send_server_packet(new AOPacket("HP#2#" + QString::number(f_state) + "#%")); + ao_app->send_server_packet( + new AOPacket("HP#2#" + QString::number(f_state) + "#%")); } void Courtroom::on_prosecution_plus_clicked() @@ -3282,7 +3192,8 @@ void Courtroom::on_prosecution_plus_clicked() int f_state = prosecution_bar_state + 1; if (f_state <= 10) - ao_app->send_server_packet(new AOPacket("HP#2#" + QString::number(f_state) + "#%")); + ao_app->send_server_packet( + new AOPacket("HP#2#" + QString::number(f_state) + "#%")); } void Courtroom::on_text_color_changed(int p_color) @@ -3310,15 +3221,9 @@ void Courtroom::on_blip_slider_moved(int p_value) ui_ic_chat_message->setFocus(); } -void Courtroom::on_log_limit_changed(int value) -{ - log_maximum_blocks = value; -} +void Courtroom::on_log_limit_changed(int value) { log_maximum_blocks = value; } -void Courtroom::on_pair_offset_changed(int value) -{ - offset_with_pair = value; -} +void Courtroom::on_pair_offset_changed(int value) { offset_with_pair = value; } void Courtroom::on_witness_testimony_clicked() { @@ -3374,10 +3279,10 @@ void Courtroom::on_change_character_clicked() } void Courtroom::on_reload_theme_clicked() -{ +{ ao_app->reload_theme(); - //to update status on the background + // to update status on the background set_background(current_background); enter_courtroom(m_cid); @@ -3430,7 +3335,8 @@ void Courtroom::on_call_mod_clicked() if (text.isEmpty()) { errorBox.critical(nullptr, "Error", "You must provide a reason."); return; - } else if (text.length() > 256) { + } + else if (text.length() > 256) { errorBox.critical(nullptr, "Error", "The message is too long."); return; } @@ -3439,37 +3345,26 @@ void Courtroom::on_call_mod_clicked() mod_reason.append(text); ao_app->send_server_packet(new AOPacket("ZZ", mod_reason)); - } else { + } + else { ao_app->send_server_packet(new AOPacket("ZZ#%")); } ui_ic_chat_message->setFocus(); } -void Courtroom::on_settings_clicked() -{ - ao_app->call_settings_menu(); -} +void Courtroom::on_settings_clicked() { ao_app->call_settings_menu(); } void Courtroom::on_announce_casing_clicked() { - ao_app->call_announce_menu(this); + ao_app->call_announce_menu(this); } -void Courtroom::on_pre_clicked() -{ - ui_ic_chat_message->setFocus(); -} +void Courtroom::on_pre_clicked() { ui_ic_chat_message->setFocus(); } -void Courtroom::on_flip_clicked() -{ - ui_ic_chat_message->setFocus(); -} +void Courtroom::on_flip_clicked() { ui_ic_chat_message->setFocus(); } -void Courtroom::on_guard_clicked() -{ - ui_ic_chat_message->setFocus(); -} +void Courtroom::on_guard_clicked() { ui_ic_chat_message->setFocus(); } void Courtroom::on_showname_enable_clicked() { @@ -3477,69 +3372,63 @@ void Courtroom::on_showname_enable_clicked() first_message_sent = false; foreach (chatlogpiece item, ic_chatlog_history) { - if (ui_showname_enable->isChecked()) - { - if (item.get_is_song()) - append_ic_text(item.get_message(), item.get_showname(), true); - else - append_ic_text(item.get_message(), item.get_showname()); - } + if (ui_showname_enable->isChecked()) { + if (item.get_is_song()) + append_ic_text(item.get_message(), item.get_showname(), true); else - { - if (item.get_is_song()) - append_ic_text(item.get_message(), item.get_name(), true); - else - append_ic_text(item.get_message(), item.get_name()); - } + append_ic_text(item.get_message(), item.get_showname()); } + else { + if (item.get_is_song()) + append_ic_text(item.get_message(), item.get_name(), true); + else + append_ic_text(item.get_message(), item.get_name()); + } + } ui_ic_chat_message->setFocus(); } void Courtroom::on_evidence_button_clicked() { - if (ui_evidence->isHidden()) - { + if (ui_evidence->isHidden()) { ui_evidence->show(); ui_evidence_overlay->hide(); } - else - { + else { ui_evidence->hide(); } } void Courtroom::on_switch_area_music_clicked() { - if (ui_area_list->isHidden()) - { - ui_area_list->show(); - ui_music_list->hide(); - } - else - { - ui_area_list->hide(); - ui_music_list->show(); - } + if (ui_area_list->isHidden()) { + ui_area_list->show(); + ui_music_list->hide(); + } + else { + ui_area_list->hide(); + ui_music_list->show(); + } } void Courtroom::ping_server() { - ao_app->send_server_packet(new AOPacket("CH#" + QString::number(m_cid) + "#%")); + ao_app->send_server_packet( + new AOPacket("CH#" + QString::number(m_cid) + "#%")); } void Courtroom::on_casing_clicked() { - if (ao_app->casing_alerts_enabled) - { - if (ui_casing->isChecked()) - { + if (ao_app->casing_alerts_enabled) { + if (ui_casing->isChecked()) { QStringList f_packet; f_packet.append(ao_app->get_casing_can_host_cases()); f_packet.append(QString::number(ao_app->get_casing_cm_enabled())); f_packet.append(QString::number(ao_app->get_casing_defence_enabled())); - f_packet.append(QString::number(ao_app->get_casing_prosecution_enabled())); + f_packet.append( + QString::number(ao_app->get_casing_prosecution_enabled())); f_packet.append(QString::number(ao_app->get_casing_judge_enabled())); f_packet.append(QString::number(ao_app->get_casing_juror_enabled())); f_packet.append(QString::number(ao_app->get_casing_steno_enabled())); @@ -3551,10 +3440,10 @@ void Courtroom::on_casing_clicked() } } -void Courtroom::announce_case(QString title, bool def, bool pro, bool jud, bool jur, bool steno) +void Courtroom::announce_case(QString title, bool def, bool pro, bool jud, + bool jur, bool steno) { - if (ao_app->casing_alerts_enabled) - { + if (ao_app->casing_alerts_enabled) { QStringList f_packet; f_packet.append(title); @@ -3565,7 +3454,7 @@ void Courtroom::announce_case(QString title, bool def, bool pro, bool jud, bool f_packet.append(QString::number(steno)); ao_app->send_server_packet(new AOPacket("CASEA", f_packet)); - } + } } Courtroom::~Courtroom() @@ -3576,29 +3465,29 @@ Courtroom::~Courtroom() delete blip_player; } - -#if (defined (_WIN32) || defined (_WIN64)) +#if (defined(_WIN32) || defined(_WIN64)) void Courtroom::load_bass_opus_plugin() { - #ifdef BASSAUDIO +#ifdef BASSAUDIO BASS_PluginLoad("bassopus.dll", 0); - #endif +#endif } -#elif (defined (LINUX) || defined (__linux__)) +#elif (defined(LINUX) || defined(__linux__)) void Courtroom::load_bass_opus_plugin() { - #ifdef BASSAUDIO +#ifdef BASSAUDIO BASS_PluginLoad("libbassopus.so", 0); - #endif +#endif } #elif defined __APPLE__ void Courtroom::load_bass_opus_plugin() { - QString libpath = ao_app->get_base_path() + "../../Frameworks/libbassopus.dylib"; + QString libpath = + ao_app->get_base_path() + "../../Frameworks/libbassopus.dylib"; QByteArray ba = libpath.toLocal8Bit(); - #ifdef BASSAUDIO +#ifdef BASSAUDIO BASS_PluginLoad(ba.data(), 0); - #endif +#endif } #else #error This operating system is unsupported for bass plugins. diff --git a/src/debug_functions.cpp b/src/debug_functions.cpp index 77f2f35..f33a2c6 100644 --- a/src/debug_functions.cpp +++ b/src/debug_functions.cpp @@ -7,8 +7,7 @@ void call_error(QString p_message) msgBox->setText("Error: " + p_message); msgBox->setWindowTitle("Error"); - - //msgBox->setWindowModality(Qt::NonModal); + // msgBox->setWindowModality(Qt::NonModal); msgBox->exec(); } @@ -19,7 +18,6 @@ void call_notice(QString p_message) msgBox->setText(p_message); msgBox->setWindowTitle("Notice"); - - //msgBox->setWindowModality(Qt::NonModal); + // msgBox->setWindowModality(Qt::NonModal); msgBox->exec(); } diff --git a/src/discord_rich_presence.cpp b/src/discord_rich_presence.cpp index 95a824a..aea07e5 100644 --- a/src/discord_rich_presence.cpp +++ b/src/discord_rich_presence.cpp @@ -8,23 +8,18 @@ Discord::Discord() DiscordEventHandlers handlers; std::memset(&handlers, 0, sizeof(handlers)); handlers = {}; - handlers.ready = [] { - qInfo() << "Discord RPC ready"; - }; - handlers.disconnected = [](int errorCode, const char* message) { + handlers.ready = [] { qInfo() << "Discord RPC ready"; }; + handlers.disconnected = [](int errorCode, const char *message) { qInfo() << "Discord RPC disconnected! " << message << errorCode; }; - handlers.errored = [](int errorCode, const char* message) { + handlers.errored = [](int errorCode, const char *message) { qWarning() << "Discord RPC errored out! " << message << errorCode; }; qInfo() << "Initializing Discord RPC"; Discord_Initialize(APPLICATION_ID, &handlers, 1, nullptr); } -Discord::~Discord() -{ - Discord_Shutdown(); -} +Discord::~Discord() { Discord_Shutdown(); } void Discord::state_lobby() { @@ -64,10 +59,12 @@ void Discord::state_server(std::string name, std::string server_id) void Discord::state_character(std::string name) { - auto name_internal = QString(name.c_str()).toLower().replace(' ', '_').toStdString(); + auto name_internal = + QString(name.c_str()).toLower().replace(' ', '_').toStdString(); auto name_friendly = QString(name.c_str()).replace('_', ' ').toStdString(); const std::string playing_as = "Playing as " + name_friendly; - qDebug() << "Discord RPC: Setting character state (" << playing_as.c_str() << ")"; + qDebug() << "Discord RPC: Setting character state (" << playing_as.c_str() + << ")"; DiscordRichPresence presence; std::memset(&presence, 0, sizeof(presence)); @@ -101,20 +98,11 @@ void Discord::state_spectate() Discord_UpdatePresence(&presence); } #else -Discord::Discord() -{ +Discord::Discord() {} -} +Discord::~Discord() {} -Discord::~Discord() -{ - -} - -void Discord::state_lobby() -{ - -} +void Discord::state_lobby() {} void Discord::state_server(std::string name, std::string server_id) { @@ -129,7 +117,6 @@ void Discord::state_character(std::string name) void Discord::state_spectate() { qDebug() << "Discord RPC: Setting specator state"; - } #endif -} +} // namespace AttorneyOnline diff --git a/src/emotes.cpp b/src/emotes.cpp index b6a217e..bbe2f5c 100644 --- a/src/emotes.cpp +++ b/src/emotes.cpp @@ -8,7 +8,8 @@ void Courtroom::construct_emotes() set_size_and_pos(ui_emotes, "emotes"); - QPoint f_spacing = ao_app->get_button_spacing("emote_button_spacing", "courtroom_design.ini"); + QPoint f_spacing = ao_app->get_button_spacing("emote_button_spacing", + "courtroom_design.ini"); const int button_width = 40; int x_spacing = f_spacing.x(); @@ -18,13 +19,14 @@ void Courtroom::construct_emotes() int y_spacing = f_spacing.y(); int y_mod_count = 0; - emote_columns = ((ui_emotes->width() - button_width) / (x_spacing + button_width)) + 1; - emote_rows = ((ui_emotes->height() - button_height) / (y_spacing + button_height)) + 1; + emote_columns = + ((ui_emotes->width() - button_width) / (x_spacing + button_width)) + 1; + emote_rows = + ((ui_emotes->height() - button_height) / (y_spacing + button_height)) + 1; max_emotes_on_page = emote_columns * emote_rows; - for (int n = 0 ; n < max_emotes_on_page ; ++n) - { + for (int n = 0; n < max_emotes_on_page; ++n) { int x_pos = (button_width + x_spacing) * x_mod_count; int y_pos = (button_height + y_spacing) * y_mod_count; @@ -34,12 +36,12 @@ void Courtroom::construct_emotes() f_emote->set_id(n); - connect(f_emote, SIGNAL(emote_clicked(int)), this, SLOT(on_emote_clicked(int))); + connect(f_emote, SIGNAL(emote_clicked(int)), this, + SLOT(on_emote_clicked(int))); ++x_mod_count; - if (x_mod_count == emote_columns) - { + if (x_mod_count == emote_columns) { ++y_mod_count; x_mod_count = 0; } @@ -56,23 +58,20 @@ void Courtroom::set_emote_page() ui_emote_left->hide(); ui_emote_right->hide(); - for (AOEmoteButton *i_button : ui_emote_list) - { + for (AOEmoteButton *i_button : ui_emote_list) { i_button->hide(); } int total_pages = total_emotes / max_emotes_on_page; int emotes_on_page = 0; - if (total_emotes % max_emotes_on_page != 0) - { + if (total_emotes % max_emotes_on_page != 0) { ++total_pages; - //i. e. not on the last page + // i. e. not on the last page if (total_pages > current_emote_page + 1) emotes_on_page = max_emotes_on_page; else emotes_on_page = total_emotes % max_emotes_on_page; - } else emotes_on_page = max_emotes_on_page; @@ -83,8 +82,7 @@ void Courtroom::set_emote_page() if (current_emote_page > 0) ui_emote_left->show(); - for (int n_emote = 0 ; n_emote < emotes_on_page ; ++n_emote) - { + for (int n_emote = 0; n_emote < emotes_on_page; ++n_emote) { int n_real_emote = n_emote + current_emote_page * max_emotes_on_page; AOEmoteButton *f_emote = ui_emote_list.at(n_emote); @@ -95,7 +93,6 @@ void Courtroom::set_emote_page() f_emote->show(); } - } void Courtroom::set_emote_dropdown() @@ -105,8 +102,7 @@ void Courtroom::set_emote_dropdown() int total_emotes = ao_app->get_emote_number(current_char); QStringList emote_list; - for (int n = 0 ; n < total_emotes ; ++n) - { + for (int n = 0; n < total_emotes; ++n) { emote_list.append(ao_app->get_emote_comment(current_char, n)); } @@ -119,19 +115,20 @@ void Courtroom::select_emote(int p_id) int max = (max_emotes_on_page - 1) + current_emote_page * max_emotes_on_page; if (current_emote >= min && current_emote <= max) - ui_emote_list.at(current_emote % max_emotes_on_page)->set_image(current_char, current_emote, "_off.png"); + ui_emote_list.at(current_emote % max_emotes_on_page) + ->set_image(current_char, current_emote, "_off.png"); int old_emote = current_emote; current_emote = p_id; if (current_emote >= min && current_emote <= max) - ui_emote_list.at(current_emote % max_emotes_on_page)->set_image(current_char, current_emote, "_on.png"); + ui_emote_list.at(current_emote % max_emotes_on_page) + ->set_image(current_char, current_emote, "_on.png"); int emote_mod = ao_app->get_emote_mod(current_char, current_emote); - if (old_emote == current_emote) - { + if (old_emote == current_emote) { ui_pre->setChecked(!ui_pre->isChecked()); } else if (emote_mod == 1) diff --git a/src/encryption_functions.cpp b/src/encryption_functions.cpp index ffbe0cd..6669fe1 100644 --- a/src/encryption_functions.cpp +++ b/src/encryption_functions.cpp @@ -4,8 +4,8 @@ QString fanta_encrypt(QString temp_input, unsigned int p_key) { - //using standard stdlib types is actually easier here because of implicit char<->int conversion - //which in turn makes encryption arithmetic easier + // using standard stdlib types is actually easier here because of implicit + // char<->int conversion which in turn makes encryption arithmetic easier unsigned int key = p_key; unsigned int C1 = 53761; @@ -14,8 +14,7 @@ QString fanta_encrypt(QString temp_input, unsigned int p_key) QVector temp_result; std::string input = temp_input.toUtf8().constData(); - for (unsigned int pos = 0 ; pos < input.size() ; ++pos) - { + for (unsigned int pos = 0; pos < input.size(); ++pos) { uint_fast8_t output = input.at(pos) ^ (key >> 8) % 256; temp_result.append(output); key = (temp_result.at(pos) + key) * C1 + C2; @@ -23,8 +22,7 @@ QString fanta_encrypt(QString temp_input, unsigned int p_key) std::string result = ""; - for (uint_fast8_t i_int : temp_result) - { + for (uint_fast8_t i_int : temp_result) { result += omni::int_to_hex(i_int); } @@ -39,9 +37,8 @@ QString fanta_decrypt(QString temp_input, unsigned int key) QVector unhexed_vector; - for(unsigned int i=0; i< input.length(); i+=2) - { - std::string byte = input.substr(i,2); + for (unsigned int i = 0; i < input.length(); i += 2) { + std::string byte = input.substr(i, 2); unsigned int hex_int = strtoul(byte.c_str(), nullptr, 16); unhexed_vector.append(hex_int); } @@ -51,13 +48,11 @@ QString fanta_decrypt(QString temp_input, unsigned int key) std::string result = ""; - for (int pos = 0 ; pos < unhexed_vector.size() ; ++pos) - { + for (int pos = 0; pos < unhexed_vector.size(); ++pos) { unsigned char output = unhexed_vector.at(pos) ^ (key >> 8) % 256; result += output; key = (unhexed_vector.at(pos) + key) * C1 + C2; } return QString::fromStdString(result); - } diff --git a/src/evidence.cpp b/src/evidence.cpp index ebef749..128156c 100644 --- a/src/evidence.cpp +++ b/src/evidence.cpp @@ -4,7 +4,7 @@ void Courtroom::construct_evidence() { ui_evidence = new AOImage(this, ao_app); - //ui_evidence_name = new QLabel(ui_evidence); + // ui_evidence_name = new QLabel(ui_evidence); ui_evidence_name = new AOLineEdit(ui_evidence); ui_evidence_name->setAlignment(Qt::AlignCenter); ui_evidence_name->setFont(QFont("Arial", 14, QFont::Bold)); @@ -32,7 +32,8 @@ void Courtroom::construct_evidence() set_size_and_pos(ui_evidence, "evidence_background"); set_size_and_pos(ui_evidence_buttons, "evidence_buttons"); - QPoint f_spacing = ao_app->get_button_spacing("evidence_button_spacing", "courtroom_design.ini"); + QPoint f_spacing = ao_app->get_button_spacing("evidence_button_spacing", + "courtroom_design.ini"); const int button_width = 70; int x_spacing = f_spacing.x(); @@ -42,43 +43,57 @@ void Courtroom::construct_evidence() int y_spacing = f_spacing.y(); int y_mod_count = 0; - evidence_columns = ((ui_evidence_buttons->width() - button_width) / (x_spacing + button_width)) + 1; - evidence_rows = ((ui_evidence_buttons->height() - button_height) / (y_spacing + button_height)) + 1; + evidence_columns = ((ui_evidence_buttons->width() - button_width) / + (x_spacing + button_width)) + + 1; + evidence_rows = ((ui_evidence_buttons->height() - button_height) / + (y_spacing + button_height)) + + 1; max_evidence_on_page = evidence_columns * evidence_rows; - for (int n = 0 ; n < max_evidence_on_page ; ++n) - { + for (int n = 0; n < max_evidence_on_page; ++n) { int x_pos = (button_width + x_spacing) * x_mod_count; int y_pos = (button_height + y_spacing) * y_mod_count; - AOEvidenceButton *f_evidence = new AOEvidenceButton(ui_evidence_buttons, ao_app, x_pos, y_pos); + AOEvidenceButton *f_evidence = + new AOEvidenceButton(ui_evidence_buttons, ao_app, x_pos, y_pos); ui_evidence_list.append(f_evidence); f_evidence->set_id(n); - connect(f_evidence, SIGNAL(evidence_clicked(int)), this, SLOT(on_evidence_clicked(int))); - connect(f_evidence, SIGNAL(evidence_double_clicked(int)), this, SLOT(on_evidence_double_clicked(int))); - connect(f_evidence, SIGNAL(on_hover(int, bool)), this, SLOT(on_evidence_hover(int, bool))); + connect(f_evidence, SIGNAL(evidence_clicked(int)), this, + SLOT(on_evidence_clicked(int))); + connect(f_evidence, SIGNAL(evidence_double_clicked(int)), this, + SLOT(on_evidence_double_clicked(int))); + connect(f_evidence, SIGNAL(on_hover(int, bool)), this, + SLOT(on_evidence_hover(int, bool))); ++x_mod_count; - if (x_mod_count == evidence_columns) - { + if (x_mod_count == evidence_columns) { ++y_mod_count; x_mod_count = 0; } } - connect(ui_evidence_name, SIGNAL(returnPressed()), this, SLOT(on_evidence_name_edited())); - connect(ui_evidence_left, SIGNAL(clicked()), this, SLOT(on_evidence_left_clicked())); - connect(ui_evidence_right, SIGNAL(clicked()), this, SLOT(on_evidence_right_clicked())); - connect(ui_evidence_present, SIGNAL(clicked()), this, SLOT(on_evidence_present_clicked())); - connect(ui_evidence_delete, SIGNAL(clicked()), this, SLOT(on_evidence_delete_clicked())); - connect(ui_evidence_image_name, SIGNAL(returnPressed()), this, SLOT(on_evidence_image_name_edited())); - connect(ui_evidence_image_button, SIGNAL(clicked()), this, SLOT(on_evidence_image_button_clicked())); - connect(ui_evidence_x, SIGNAL(clicked()), this, SLOT(on_evidence_x_clicked())); + connect(ui_evidence_name, SIGNAL(returnPressed()), this, + SLOT(on_evidence_name_edited())); + connect(ui_evidence_left, SIGNAL(clicked()), this, + SLOT(on_evidence_left_clicked())); + connect(ui_evidence_right, SIGNAL(clicked()), this, + SLOT(on_evidence_right_clicked())); + connect(ui_evidence_present, SIGNAL(clicked()), this, + SLOT(on_evidence_present_clicked())); + connect(ui_evidence_delete, SIGNAL(clicked()), this, + SLOT(on_evidence_delete_clicked())); + connect(ui_evidence_image_name, SIGNAL(returnPressed()), this, + SLOT(on_evidence_image_name_edited())); + connect(ui_evidence_image_button, SIGNAL(clicked()), this, + SLOT(on_evidence_image_button_clicked())); + connect(ui_evidence_x, SIGNAL(clicked()), this, + SLOT(on_evidence_x_clicked())); ui_evidence->hide(); } @@ -98,26 +113,23 @@ void Courtroom::set_evidence_page() ui_evidence_left->hide(); ui_evidence_right->hide(); - for (AOEvidenceButton *i_button : ui_evidence_list) - { + for (AOEvidenceButton *i_button : ui_evidence_list) { i_button->reset(); } - //to account for the "add evidence" button + // to account for the "add evidence" button ++total_evidence; int total_pages = total_evidence / max_evidence_on_page; int evidence_on_page = 0; - if ((total_evidence % max_evidence_on_page) != 0) - { + if ((total_evidence % max_evidence_on_page) != 0) { ++total_pages; - //i. e. not on the last page + // i. e. not on the last page if (total_pages > current_evidence_page + 1) evidence_on_page = max_evidence_on_page; else evidence_on_page = total_evidence % max_evidence_on_page; - } else evidence_on_page = max_evidence_on_page; @@ -128,17 +140,19 @@ void Courtroom::set_evidence_page() if (current_evidence_page > 0) ui_evidence_left->show(); - for (int n_evidence_button = 0 ; n_evidence_button < evidence_on_page ; ++n_evidence_button) - { - int n_real_evidence = n_evidence_button + current_evidence_page * max_evidence_on_page; - AOEvidenceButton *f_evidence_button = ui_evidence_list.at(n_evidence_button); + for (int n_evidence_button = 0; n_evidence_button < evidence_on_page; + ++n_evidence_button) { + int n_real_evidence = + n_evidence_button + current_evidence_page * max_evidence_on_page; + AOEvidenceButton *f_evidence_button = + ui_evidence_list.at(n_evidence_button); - //ie. the add evidence button + // ie. the add evidence button if (n_real_evidence == (total_evidence - 1)) f_evidence_button->set_theme_image("addevidence.png"); - else if (n_real_evidence < (total_evidence - 1)) - { - f_evidence_button->set_image(local_evidence_list.at(n_real_evidence).image); + else if (n_real_evidence < (total_evidence - 1)) { + f_evidence_button->set_image( + local_evidence_list.at(n_real_evidence).image); if (n_real_evidence == current_evidence) f_evidence_button->set_selected(true); @@ -198,7 +212,7 @@ void Courtroom::on_evidence_image_button_clicked() QStringList filenames; if (dialog.exec()) - filenames = dialog.selectedFiles(); + filenames = dialog.selectedFiles(); if (filenames.size() != 1) return; @@ -215,9 +229,9 @@ void Courtroom::on_evidence_clicked(int p_id) int f_real_id = p_id + max_evidence_on_page * current_evidence_page; - if (f_real_id == local_evidence_list.size()) - { - ao_app->send_server_packet(new AOPacket("PE###empty.png#%")); + if (f_real_id == local_evidence_list.size()) { + ao_app->send_server_packet( + new AOPacket("PE###empty.png#%")); return; } else if (f_real_id > local_evidence_list.size()) @@ -233,7 +247,6 @@ void Courtroom::on_evidence_clicked(int p_id) current_evidence = f_real_id; ui_ic_chat_message->setFocus(); - } void Courtroom::on_evidence_double_clicked(int p_id) @@ -262,8 +275,7 @@ void Courtroom::on_evidence_hover(int p_id, bool p_state) ui_evidence_name->setReadOnly(true); int final_id = p_id + max_evidence_on_page * current_evidence_page; - if (p_state) - { + if (p_state) { if (final_id == local_evidence_list.size()) ui_evidence_name->setText("Add new evidence..."); else if (final_id < local_evidence_list.size()) @@ -310,7 +322,8 @@ void Courtroom::on_evidence_delete_clicked() ui_evidence_description->setReadOnly(true); ui_evidence_overlay->hide(); - ao_app->send_server_packet(new AOPacket("DE#" + QString::number(current_evidence) + "#%")); + ao_app->send_server_packet( + new AOPacket("DE#" + QString::number(current_evidence) + "#%")); current_evidence = 0; @@ -338,4 +351,3 @@ void Courtroom::on_evidence_x_clicked() ui_ic_chat_message->setFocus(); } - diff --git a/src/file_functions.cpp b/src/file_functions.cpp index f93ee15..e64a46b 100644 --- a/src/file_functions.cpp +++ b/src/file_functions.cpp @@ -14,7 +14,8 @@ bool dir_exists(QString dir_path) return check_dir.exists(); } -bool exists(QString p_path) { +bool exists(QString p_path) +{ QFile file(p_path); return file.exists(); diff --git a/src/hardware_functions.cpp b/src/hardware_functions.cpp index 5d6b6ff..4dbc438 100644 --- a/src/hardware_functions.cpp +++ b/src/hardware_functions.cpp @@ -2,7 +2,7 @@ #include -#if (defined (_WIN32) || defined (_WIN64)) +#if (defined(_WIN32) || defined(_WIN64)) #include static DWORD dwVolSerial; @@ -10,17 +10,18 @@ static BOOL bIsRetrieved; QString get_hdid() { - bIsRetrieved = GetVolumeInformation(TEXT("C:\\"), nullptr, 0, &dwVolSerial, nullptr, nullptr, nullptr, 0); + bIsRetrieved = GetVolumeInformation(TEXT("C:\\"), nullptr, 0, &dwVolSerial, + nullptr, nullptr, nullptr, 0); if (bIsRetrieved) return QString::number(dwVolSerial, 16); else - //a totally random string - //what could possibly go wrong + // a totally random string + // what could possibly go wrong return "gxsps32sa9fnwic92mfbs0"; } -#elif (defined (LINUX) || defined (__linux__)) +#elif (defined(LINUX) || defined(__linux__)) #include #include @@ -33,12 +34,10 @@ QString get_hdid() QTextStream in(&fstab_file); - while(!in.atEnd()) - { + while (!in.atEnd()) { QString line = in.readLine(); - if (line.startsWith("UUID")) - { + if (line.startsWith("UUID")) { QStringList line_elements = line.split("="); if (line_elements.size() > 1) @@ -52,7 +51,7 @@ QString get_hdid() #elif defined __APPLE__ QString get_hdid() { - //hdids are broken at this point anyways + // hdids are broken at this point anyways return "just a mac passing by"; } diff --git a/src/hex_functions.cpp b/src/hex_functions.cpp index 4a58d2b..1e35718 100644 --- a/src/hex_functions.cpp +++ b/src/hex_functions.cpp @@ -1,18 +1,17 @@ #include "hex_functions.h" -namespace omni +namespace omni { +std::string int_to_hex(unsigned int input) { - std::string int_to_hex(unsigned int input) - { - if (input > 255) - return "FF"; + if (input > 255) + return "FF"; - std::stringstream stream; - stream << std::setfill('0') << std::setw(sizeof(char)*2) - << std::hex << input; - std::string result(stream.str()); - std::transform(result.begin(), result.end(), result.begin(), ::toupper); + std::stringstream stream; + stream << std::setfill('0') << std::setw(sizeof(char) * 2) << std::hex + << input; + std::string result(stream.str()); + std::transform(result.begin(), result.end(), result.begin(), ::toupper); - return result; - } + return result; } +} // namespace omni diff --git a/src/lobby.cpp b/src/lobby.cpp index 4a96e56..79a37be 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -1,9 +1,9 @@ #include "lobby.h" -#include "debug_functions.h" #include "aoapplication.h" -#include "networkmanager.h" #include "aosfxplayer.h" +#include "debug_functions.h" +#include "networkmanager.h" Lobby::Lobby(AOApplication *p_ao_app) : QMainWindow() { @@ -37,17 +37,22 @@ Lobby::Lobby(AOApplication *p_ao_app) : QMainWindow() ui_progress_bar->setStyleSheet("QProgressBar{ color: white; }"); ui_cancel = new AOButton(ui_loading_background, ao_app); - connect(ui_public_servers, SIGNAL(clicked()), this, SLOT(on_public_servers_clicked())); + connect(ui_public_servers, SIGNAL(clicked()), this, + SLOT(on_public_servers_clicked())); connect(ui_favorites, SIGNAL(clicked()), this, SLOT(on_favorites_clicked())); connect(ui_refresh, SIGNAL(pressed()), this, SLOT(on_refresh_pressed())); connect(ui_refresh, SIGNAL(released()), this, SLOT(on_refresh_released())); - connect(ui_add_to_fav, SIGNAL(pressed()), this, SLOT(on_add_to_fav_pressed())); - connect(ui_add_to_fav, SIGNAL(released()), this, SLOT(on_add_to_fav_released())); + connect(ui_add_to_fav, SIGNAL(pressed()), this, + SLOT(on_add_to_fav_pressed())); + connect(ui_add_to_fav, SIGNAL(released()), this, + SLOT(on_add_to_fav_released())); connect(ui_connect, SIGNAL(pressed()), this, SLOT(on_connect_pressed())); connect(ui_connect, SIGNAL(released()), this, SLOT(on_connect_released())); connect(ui_about, SIGNAL(clicked()), this, SLOT(on_about_clicked())); - connect(ui_server_list, SIGNAL(clicked(QModelIndex)), this, SLOT(on_server_list_clicked(QModelIndex))); - connect(ui_chatmessage, SIGNAL(returnPressed()), this, SLOT(on_chatfield_return_pressed())); + connect(ui_server_list, SIGNAL(clicked(QModelIndex)), this, + SLOT(on_server_list_clicked(QModelIndex))); + connect(ui_chatmessage, SIGNAL(returnPressed()), this, + SLOT(on_chatfield_return_pressed())); connect(ui_cancel, SIGNAL(clicked()), ao_app, SLOT(loading_cancelled())); ui_connect->setEnabled(false); @@ -57,7 +62,7 @@ Lobby::Lobby(AOApplication *p_ao_app) : QMainWindow() set_widgets(); } -//sets images, position and size +// sets images, position and size void Lobby::set_widgets() { ao_app->reload_theme(); @@ -66,8 +71,7 @@ void Lobby::set_widgets() pos_size_type f_lobby = ao_app->get_element_dimensions("lobby", filename); - if (f_lobby.width < 0 || f_lobby.height < 0) - { + if (f_lobby.width < 0 || f_lobby.height < 0) { qDebug() << "W: did not find lobby width or height in " << filename; // Most common symptom of bad config files and missing assets. @@ -77,8 +81,7 @@ void Lobby::set_widgets() this->resize(517, 666); } - else - { + else { this->resize(f_lobby.width, f_lobby.height); } @@ -108,7 +111,7 @@ void Lobby::set_widgets() set_size_and_pos(ui_server_list, "server_list"); ui_server_list->setStyleSheet("background-color: rgba(0, 0, 0, 0);" - "font: bold;"); + "font: bold;"); set_size_and_pos(ui_player_count, "player_count"); ui_player_count->setText("Offline"); @@ -123,20 +126,21 @@ void Lobby::set_widgets() set_size_and_pos(ui_chatbox, "chatbox"); ui_chatbox->setReadOnly(true); - ui_chatbox->setStyleSheet("QTextBrowser{background-color: rgba(0, 0, 0, 0);}"); + ui_chatbox->setStyleSheet( + "QTextBrowser{background-color: rgba(0, 0, 0, 0);}"); set_size_and_pos(ui_chatname, "chatname"); ui_chatname->setStyleSheet("background-color: rgba(0, 0, 0, 0);" "selection-background-color: rgba(0, 0, 0, 0);"); set_size_and_pos(ui_chatmessage, "chatmessage"); - ui_chatmessage->setStyleSheet("background-color: rgba(0, 0, 0, 0);" - "selection-background-color: rgba(0, 0, 0, 0);"); + ui_chatmessage->setStyleSheet( + "background-color: rgba(0, 0, 0, 0);" + "selection-background-color: rgba(0, 0, 0, 0);"); ui_loading_background->resize(this->width(), this->height()); ui_loading_background->set_image("loadingbackground.png"); - set_size_and_pos(ui_loading_text, "loading_label"); ui_loading_text->setFont(QFont("Arial", 20, QFont::Bold)); ui_loading_text->setReadOnly(true); @@ -151,22 +155,20 @@ void Lobby::set_widgets() ui_cancel->setText("Cancel"); ui_loading_background->hide(); - } void Lobby::set_size_and_pos(QWidget *p_widget, QString p_identifier) { QString filename = "lobby_design.ini"; - pos_size_type design_ini_result = ao_app->get_element_dimensions(p_identifier, filename); + pos_size_type design_ini_result = + ao_app->get_element_dimensions(p_identifier, filename); - if (design_ini_result.width < 0 || design_ini_result.height < 0) - { + if (design_ini_result.width < 0 || design_ini_result.height < 0) { qDebug() << "W: could not find " << p_identifier << " in " << filename; p_widget->hide(); } - else - { + else { p_widget->move(design_ini_result.x, design_ini_result.y); p_widget->resize(design_ini_result.width, design_ini_result.height); } @@ -186,10 +188,7 @@ QString Lobby::get_chatlog() return return_value; } -int Lobby::get_selected_server() -{ - return ui_server_list->currentRow(); -} +int Lobby::get_selected_server() { return ui_server_list->currentRow(); } void Lobby::set_loading_value(int p_value) { @@ -212,7 +211,7 @@ void Lobby::on_favorites_clicked() ui_public_servers->set_image("publicservers.png"); ao_app->set_favorite_list(); - //ao_app->favorite_list = read_serverlist_txt(); + // ao_app->favorite_list = read_serverlist_txt(); list_favorites(); @@ -242,7 +241,7 @@ void Lobby::on_add_to_fav_released() { ui_add_to_fav->set_image("addtofav.png"); - //you cant add favorites from favorites m8 + // you cant add favorites from favorites m8 if (!public_servers_selected) return; @@ -267,17 +266,18 @@ void Lobby::on_connect_released() void Lobby::on_about_clicked() { - QString msg = tr("

    Attorney Online %1

    " - "The courtroom drama simulator" - "

    Source code: " - "" - "https://github.com/AttorneyOnline/AO2-Client" - "

    Major development:
    " - "OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter" - "

    Special thanks:
    " - "Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), " - "Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, " - "Noevain, Cronnicossy") + QString msg = + tr("

    Attorney Online %1

    " + "The courtroom drama simulator" + "

    Source code: " + "" + "https://github.com/AttorneyOnline/AO2-Client" + "

    Major development:
    " + "OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter" + "

    Special thanks:
    " + "Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), " + "Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, " + "Noevain, Cronnicossy") .arg(ao_app->get_version_string()); QMessageBox::about(this, "About", msg); } @@ -290,8 +290,7 @@ void Lobby::on_server_list_clicked(QModelIndex p_model) if (n_server < 0) return; - if (public_servers_selected) - { + if (public_servers_selected) { QVector f_server_list = ao_app->get_server_list(); if (n_server >= f_server_list.size()) @@ -299,8 +298,7 @@ void Lobby::on_server_list_clicked(QModelIndex p_model) f_server = f_server_list.at(p_model.row()); } - else - { + else { if (n_server >= ao_app->get_favorite_list().size()) return; @@ -322,11 +320,10 @@ void Lobby::on_server_list_clicked(QModelIndex p_model) void Lobby::on_chatfield_return_pressed() { - //no you can't send empty messages + // no you can't send empty messages if (ui_chatname->text() == "" || ui_chatmessage->text() == "") return; - QString f_header = "CT"; QStringList f_contents{ui_chatname->text(), ui_chatmessage->text()}; @@ -345,8 +342,7 @@ void Lobby::list_servers() ui_server_list->clear(); - for (server_type i_server : ao_app->get_server_list()) - { + for (server_type i_server : ao_app->get_server_list()) { ui_server_list->addItem(i_server.name); } } @@ -355,15 +351,16 @@ void Lobby::list_favorites() { ui_server_list->clear(); - for (server_type i_server : ao_app->get_favorite_list()) - { + for (server_type i_server : ao_app->get_favorite_list()) { ui_server_list->addItem(i_server.name); } } void Lobby::append_chatmessage(QString f_name, QString f_message) { - ui_chatbox->append_chatmessage(f_name, f_message, ao_app->get_color("ooc_default_color", "courtroom_design.ini").name()); + ui_chatbox->append_chatmessage( + f_name, f_message, + ao_app->get_color("ooc_default_color", "courtroom_design.ini").name()); } void Lobby::append_error(QString f_message) @@ -373,16 +370,11 @@ void Lobby::append_error(QString f_message) void Lobby::set_player_count(int players_online, int max_players) { - QString f_string = "Online: " + QString::number(players_online) + "/" + QString::number(max_players); + QString f_string = "Online: " + QString::number(players_online) + "/" + + QString::number(max_players); ui_player_count->setText(f_string); } -void Lobby::enable_connect_button() -{ - ui_connect->setEnabled(true); -} +void Lobby::enable_connect_button() { ui_connect->setEnabled(true); } -Lobby::~Lobby() -{ - -} +Lobby::~Lobby() {} diff --git a/src/main.cpp b/src/main.cpp index 80ea93b..1caa394 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,24 +1,24 @@ #include "aoapplication.h" -#include "datatypes.h" -#include "networkmanager.h" -#include "lobby.h" #include "courtroom.h" -#include +#include "datatypes.h" +#include "lobby.h" +#include "networkmanager.h" #include +#include int main(int argc, char *argv[]) { #if QT_VERSION > QT_VERSION_CHECK(5, 6, 0) - // High-DPI support is for Qt version >=5.6. - // However, many Linux distros still haven't brought their stable/LTS - // packages up to Qt 5.6, so this is conditional. - AOApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + // High-DPI support is for Qt version >=5.6. + // However, many Linux distros still haven't brought their stable/LTS + // packages up to Qt 5.6, so this is conditional. + AOApplication::setAttribute(Qt::AA_EnableHighDpiScaling); #endif - AOApplication main_app(argc, argv); - main_app.construct_lobby(); - main_app.net_manager->connect_to_master(); - main_app.w_lobby->show(); - return main_app.exec(); + AOApplication main_app(argc, argv); + main_app.construct_lobby(); + main_app.net_manager->connect_to_master(); + main_app.w_lobby->show(); + return main_app.exec(); } diff --git a/src/misc_functions.cpp b/src/misc_functions.cpp index 2352055..cc14415 100644 --- a/src/misc_functions.cpp +++ b/src/misc_functions.cpp @@ -4,6 +4,6 @@ void delay(int p_milliseconds) { QTime dieTime = QTime::currentTime().addMSecs(p_milliseconds); - while(QTime::currentTime() < dieTime) + while (QTime::currentTime() < dieTime) QCoreApplication::processEvents(QEventLoop::AllEvents, 100); } diff --git a/src/networkmanager.cpp b/src/networkmanager.cpp index a9810d4..cf89d0a 100644 --- a/src/networkmanager.cpp +++ b/src/networkmanager.cpp @@ -13,21 +13,23 @@ NetworkManager::NetworkManager(AOApplication *parent) : QObject(parent) ms_reconnect_timer = new QTimer(this); ms_reconnect_timer->setSingleShot(true); - QObject::connect(ms_reconnect_timer, SIGNAL(timeout()), this, SLOT(retry_ms_connect())); + QObject::connect(ms_reconnect_timer, SIGNAL(timeout()), this, + SLOT(retry_ms_connect())); - QObject::connect(ms_socket, SIGNAL(readyRead()), this, SLOT(handle_ms_packet())); - QObject::connect(server_socket, SIGNAL(readyRead()), this, SLOT(handle_server_packet())); - QObject::connect(server_socket, SIGNAL(disconnected()), ao_app, SLOT(server_disconnected())); + QObject::connect(ms_socket, SIGNAL(readyRead()), this, + SLOT(handle_ms_packet())); + QObject::connect(server_socket, SIGNAL(readyRead()), this, + SLOT(handle_server_packet())); + QObject::connect(server_socket, SIGNAL(disconnected()), ao_app, + SLOT(server_disconnected())); - QString master_config = ao_app->configini->value("master", "").value(); + QString master_config = + ao_app->configini->value("master", "").value(); if (master_config != "") ms_nosrv_hostname = master_config; } -NetworkManager::~NetworkManager() -{ - -} +NetworkManager::~NetworkManager() {} void NetworkManager::connect_to_master() { @@ -43,11 +45,11 @@ void NetworkManager::connect_to_master() void NetworkManager::connect_to_master_nosrv() { - QObject::connect(ms_socket, SIGNAL(error(QAbstractSocket::SocketError)), - this, SLOT(on_ms_socket_error(QAbstractSocket::SocketError))); + QObject::connect(ms_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, + SLOT(on_ms_socket_error(QAbstractSocket::SocketError))); - QObject::connect(ms_socket, SIGNAL(connected()), - this, SLOT(on_ms_nosrv_connect_success())); + QObject::connect(ms_socket, SIGNAL(connected()), this, + SLOT(on_ms_nosrv_connect_success())); ms_socket->connectToHost(ms_nosrv_hostname, ms_port); } @@ -61,12 +63,10 @@ void NetworkManager::connect_to_server(server_type p_server) void NetworkManager::ship_ms_packet(QString p_packet) { - if (!ms_socket->isOpen()) - { + if (!ms_socket->isOpen()) { retry_ms_connect(); } - else - { + else { ms_socket->write(p_packet.toUtf8()); } } @@ -81,93 +81,86 @@ void NetworkManager::handle_ms_packet() QByteArray buffer = ms_socket->readAll(); QString in_data = QString::fromUtf8(buffer, buffer.size()); - if (!in_data.endsWith("%")) - { + if (!in_data.endsWith("%")) { ms_partial_packet = true; ms_temp_packet += in_data; return; } - else - { - if (ms_partial_packet) - { + else { + if (ms_partial_packet) { in_data = ms_temp_packet + in_data; ms_temp_packet = ""; ms_partial_packet = false; } } - QStringList packet_list = in_data.split("%", QString::SplitBehavior(QString::SkipEmptyParts)); + QStringList packet_list = + in_data.split("%", QString::SplitBehavior(QString::SkipEmptyParts)); - for (QString packet : packet_list) - { + for (QString packet : packet_list) { AOPacket *f_packet = new AOPacket(packet); ao_app->ms_packet_received(f_packet); } } - void NetworkManager::perform_srv_lookup() { - #ifdef MS_FAILOVER_SUPPORTED +#ifdef MS_FAILOVER_SUPPORTED ms_dns = new QDnsLookup(QDnsLookup::SRV, ms_srv_hostname, this); connect(ms_dns, SIGNAL(finished()), this, SLOT(on_srv_lookup())); ms_dns->lookup(); - #endif +#endif } void NetworkManager::on_srv_lookup() { - #ifdef MS_FAILOVER_SUPPORTED +#ifdef MS_FAILOVER_SUPPORTED bool connected = false; - if (ms_dns->error() != QDnsLookup::NoError) - { + if (ms_dns->error() != QDnsLookup::NoError) { qWarning("SRV lookup of the master server DNS failed."); ms_dns->deleteLater(); } - else - { + else { const auto srv_records = ms_dns->serviceRecords(); - for (const QDnsServiceRecord &record : srv_records) - { + for (const QDnsServiceRecord &record : srv_records) { #ifdef DEBUG_NETWORK qDebug() << "Connecting to " << record.target() << ":" << record.port(); #endif ms_socket->connectToHost(record.target(), record.port()); QTime timer; timer.start(); - do - { + do { ao_app->processEvents(); - if (ms_socket->state() == QAbstractSocket::ConnectedState) - { + if (ms_socket->state() == QAbstractSocket::ConnectedState) { connected = true; break; } - else if (ms_socket->state() != QAbstractSocket::ConnectingState - && ms_socket->state() != QAbstractSocket::HostLookupState - && ms_socket->error() != -1) - { + else if (ms_socket->state() != QAbstractSocket::ConnectingState && + ms_socket->state() != QAbstractSocket::HostLookupState && + ms_socket->error() != -1) { qDebug() << ms_socket->error(); - qWarning() << "Error connecting to master server:" << ms_socket->errorString(); + qWarning() << "Error connecting to master server:" + << ms_socket->errorString(); ms_socket->abort(); ms_socket->close(); break; } - } while (timer.elapsed() < timeout_milliseconds); // Very expensive spin-wait loop - it will bring CPU to 100%! - if (connected) - { - // Connect a one-shot signal in case the master server disconnects randomly - QObject::connect(ms_socket, SIGNAL(error(QAbstractSocket::SocketError)), - this, SLOT(on_ms_socket_error(QAbstractSocket::SocketError))); + } while (timer.elapsed() < + timeout_milliseconds); // Very expensive spin-wait loop - it will + // bring CPU to 100%! + if (connected) { + // Connect a one-shot signal in case the master server disconnects + // randomly + QObject::connect( + ms_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, + SLOT(on_ms_socket_error(QAbstractSocket::SocketError))); break; } - else - { + else { ms_socket->abort(); ms_socket->close(); } @@ -179,29 +172,30 @@ void NetworkManager::on_srv_lookup() connect_to_master_nosrv(); else emit ms_connect_finished(connected, false); - #endif +#endif } void NetworkManager::on_ms_nosrv_connect_success() { emit ms_connect_finished(true, false); - QObject::disconnect(ms_socket, SIGNAL(connected()), - this, SLOT(on_ms_nosrv_connect_success())); + QObject::disconnect(ms_socket, SIGNAL(connected()), this, + SLOT(on_ms_nosrv_connect_success())); - QObject::connect(ms_socket, SIGNAL(error(QAbstractSocket::SocketError)), - this, SLOT(on_ms_socket_error(QAbstractSocket::SocketError))); + QObject::connect(ms_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, + SLOT(on_ms_socket_error(QAbstractSocket::SocketError))); } void NetworkManager::on_ms_socket_error(QAbstractSocket::SocketError error) { - qWarning() << "Master server socket error:" << ms_socket->errorString() - << "(" << error << ")"; + qWarning() << "Master server socket error:" << ms_socket->errorString() << "(" + << error << ")"; // Disconnect the one-shot signal - this way, failover connect attempts // don't trigger a full retry QObject::disconnect(ms_socket, SIGNAL(error(QAbstractSocket::SocketError)), - this, SLOT(on_ms_socket_error(QAbstractSocket::SocketError))); + this, + SLOT(on_ms_socket_error(QAbstractSocket::SocketError))); emit ms_connect_finished(false, true); @@ -210,7 +204,8 @@ void NetworkManager::on_ms_socket_error(QAbstractSocket::SocketError error) void NetworkManager::retry_ms_connect() { - if (!ms_reconnect_timer->isActive() && ms_socket->state() != QAbstractSocket::ConnectingState) + if (!ms_reconnect_timer->isActive() && + ms_socket->state() != QAbstractSocket::ConnectingState) connect_to_master(); } @@ -219,27 +214,24 @@ void NetworkManager::handle_server_packet() QByteArray buffer = server_socket->readAll(); QString in_data = QString::fromUtf8(buffer, buffer.size()); - if (!in_data.endsWith("%")) - { + if (!in_data.endsWith("%")) { partial_packet = true; temp_packet += in_data; return; } - else - { - if (partial_packet) - { + else { + if (partial_packet) { in_data = temp_packet + in_data; temp_packet = ""; partial_packet = false; } } - QStringList packet_list = in_data.split("%", QString::SplitBehavior(QString::SkipEmptyParts)); + QStringList packet_list = + in_data.split("%", QString::SplitBehavior(QString::SkipEmptyParts)); - for (QString packet : packet_list) - { + for (QString packet : packet_list) { AOPacket *f_packet = new AOPacket(packet); ao_app->server_packet_received(f_packet); diff --git a/src/packet_distribution.cpp b/src/packet_distribution.cpp index 942c275..baba0ea 100644 --- a/src/packet_distribution.cpp +++ b/src/packet_distribution.cpp @@ -1,11 +1,11 @@ #include "aoapplication.h" -#include "lobby.h" #include "courtroom.h" -#include "networkmanager.h" +#include "debug_functions.h" #include "encryption_functions.h" #include "hardware_functions.h" -#include "debug_functions.h" +#include "lobby.h" +#include "networkmanager.h" void AOApplication::ms_packet_received(AOPacket *p_packet) { @@ -19,17 +19,14 @@ void AOApplication::ms_packet_received(AOPacket *p_packet) qDebug() << "R(ms):" << p_packet->to_string(); #endif - if (header == "ALL") - { + if (header == "ALL") { server_list.clear(); - for (QString i_string : p_packet->get_contents()) - { + for (QString i_string : p_packet->get_contents()) { server_type f_server; QStringList sub_contents = i_string.split("&"); - if (sub_contents.size() < 4) - { + if (sub_contents.size() < 4) { qDebug() << "W: malformed packet"; continue; } @@ -42,39 +39,32 @@ void AOApplication::ms_packet_received(AOPacket *p_packet) server_list.append(f_server); } - if (lobby_constructed) - { + if (lobby_constructed) { w_lobby->list_servers(); } } - else if (header == "CT") - { + else if (header == "CT") { QString f_name, f_message; - if (f_contents.size() == 1) - { + if (f_contents.size() == 1) { f_name = ""; f_message = f_contents.at(0); } - else if (f_contents.size() >= 2) - { + else if (f_contents.size() >= 2) { f_name = f_contents.at(0); f_message = f_contents.at(1); } else goto end; - if (lobby_constructed) - { + if (lobby_constructed) { w_lobby->append_chatmessage(f_name, f_message); } - if (courtroom_constructed && courtroom_loaded) - { + if (courtroom_constructed && courtroom_loaded) { w_courtroom->append_ms_chatmessage(f_name, f_message); } } - else if (header == "AO2CHECK") - { + else if (header == "AO2CHECK") { send_ms_packet(new AOPacket("ID#AO2#" + get_version_string() + "#%")); send_ms_packet(new AOPacket("HI#" + get_hdid() + "#%")); @@ -92,31 +82,28 @@ void AOApplication::ms_packet_received(AOPacket *p_packet) if (get_release() > f_release) goto end; - else if (get_release() == f_release) - { + else if (get_release() == f_release) { if (get_major_version() > f_major) goto end; - else if (get_major_version() == f_major) - { + else if (get_major_version() == f_major) { if (get_minor_version() >= f_minor) goto end; } } - call_notice("Outdated version! Your version: " + get_version_string() - + "\nPlease go to aceattorneyonline.com to update."); + call_notice("Outdated version! Your version: " + get_version_string() + + "\nPlease go to aceattorneyonline.com to update."); destruct_courtroom(); destruct_lobby(); } - else if (header == "DOOM") - { + else if (header == "DOOM") { call_notice("You have been exiled from AO." "Have a nice day."); destruct_courtroom(); destruct_lobby(); } - end: +end: delete p_packet; } @@ -134,15 +121,14 @@ void AOApplication::server_packet_received(AOPacket *p_packet) qDebug() << "R:" << f_packet; #endif - if (header == "decryptor") - { + if (header == "decryptor") { if (f_contents.size() == 0) goto end; - //you may ask where 322 comes from. that would be a good question. + // you may ask where 322 comes from. that would be a good question. s_decryptor = fanta_decrypt(f_contents.at(0), 322).toUInt(); - //default(legacy) values + // default(legacy) values encryption_needed = true; yellow_text_enabled = false; prezoom_enabled = false; @@ -156,7 +142,7 @@ void AOApplication::server_packet_received(AOPacket *p_packet) casing_alerts_enabled = false; modcall_reason_enabled = false; - //workaround for tsuserver4 + // workaround for tsuserver4 if (f_contents.at(0) == "NOENCRYPT") encryption_needed = false; @@ -166,8 +152,7 @@ void AOApplication::server_packet_received(AOPacket *p_packet) AOPacket *hi_packet = new AOPacket("HI#" + f_hdid + "#%"); send_server_packet(hi_packet); } - else if (header == "ID") - { + else if (header == "ID") { if (f_contents.size() < 2) goto end; @@ -176,55 +161,53 @@ void AOApplication::server_packet_received(AOPacket *p_packet) send_server_packet(new AOPacket("ID#AO2#" + get_version_string() + "#%")); } - else if (header == "CT") - { + else if (header == "CT") { if (f_contents.size() < 2) goto end; - if (courtroom_constructed) - { + if (courtroom_constructed) { if (f_contents.size() == 3) - w_courtroom->append_server_chatmessage(f_contents.at(0), f_contents.at(1), f_contents.at(2)); + w_courtroom->append_server_chatmessage( + f_contents.at(0), f_contents.at(1), f_contents.at(2)); else - w_courtroom->append_server_chatmessage(f_contents.at(0), f_contents.at(1), "0"); + w_courtroom->append_server_chatmessage(f_contents.at(0), + f_contents.at(1), "0"); } } - else if (header == "FL") - { - if (f_packet.contains("yellowtext",Qt::CaseInsensitive)) + else if (header == "FL") { + if (f_packet.contains("yellowtext", Qt::CaseInsensitive)) yellow_text_enabled = true; - if (f_packet.contains("flipping",Qt::CaseInsensitive)) + if (f_packet.contains("flipping", Qt::CaseInsensitive)) flipping_enabled = true; - if (f_packet.contains("customobjections",Qt::CaseInsensitive)) + if (f_packet.contains("customobjections", Qt::CaseInsensitive)) custom_objection_enabled = true; - if (f_packet.contains("fastloading",Qt::CaseInsensitive)) + if (f_packet.contains("fastloading", Qt::CaseInsensitive)) improved_loading_enabled = true; - if (f_packet.contains("noencryption",Qt::CaseInsensitive)) + if (f_packet.contains("noencryption", Qt::CaseInsensitive)) encryption_needed = false; - if (f_packet.contains("deskmod",Qt::CaseInsensitive)) + if (f_packet.contains("deskmod", Qt::CaseInsensitive)) desk_mod_enabled = true; - if (f_packet.contains("evidence",Qt::CaseInsensitive)) + if (f_packet.contains("evidence", Qt::CaseInsensitive)) evidence_enabled = true; - if (f_packet.contains("cccc_ic_support",Qt::CaseInsensitive)) + if (f_packet.contains("cccc_ic_support", Qt::CaseInsensitive)) cccc_ic_support_enabled = true; - if (f_packet.contains("arup",Qt::CaseInsensitive)) + if (f_packet.contains("arup", Qt::CaseInsensitive)) arup_enabled = true; - if (f_packet.contains("casing_alerts",Qt::CaseInsensitive)) + if (f_packet.contains("casing_alerts", Qt::CaseInsensitive)) casing_alerts_enabled = true; - if (f_packet.contains("modcall_reason",Qt::CaseInsensitive)) + if (f_packet.contains("modcall_reason", Qt::CaseInsensitive)) modcall_reason_enabled = true; w_lobby->enable_connect_button(); } - else if (header == "PN") - { + else if (header == "PN") { if (f_contents.size() < 2) goto end; - w_lobby->set_player_count(f_contents.at(0).toInt(), f_contents.at(1).toInt()); + w_lobby->set_player_count(f_contents.at(0).toInt(), + f_contents.at(1).toInt()); } - else if (header == "SI") - { + else if (header == "SI") { if (f_contents.size() != 3) goto end; @@ -249,8 +232,7 @@ void AOApplication::server_packet_received(AOPacket *p_packet) int selected_server = w_lobby->get_selected_server(); QString server_address = "", server_name = ""; - if (w_lobby->public_servers_selected) - { + if (w_lobby->public_servers_selected) { if (selected_server >= 0 && selected_server < server_list.size()) { auto info = server_list.at(selected_server); server_name = info.name; @@ -258,8 +240,7 @@ void AOApplication::server_packet_received(AOPacket *p_packet) window_title += ": " + server_name; } } - else - { + else { if (selected_server >= 0 && selected_server < favorite_list.size()) { auto info = favorite_list.at(selected_server); server_name = info.name; @@ -276,7 +257,7 @@ void AOApplication::server_packet_received(AOPacket *p_packet) AOPacket *f_packet; - if(improved_loading_enabled) + if (improved_loading_enabled) f_packet = new AOPacket("RC#%"); else f_packet = new AOPacket("askchar2#%"); @@ -286,19 +267,19 @@ void AOApplication::server_packet_received(AOPacket *p_packet) QCryptographicHash hash(QCryptographicHash::Algorithm::Sha256); hash.addData(server_address.toUtf8()); if (is_discord_enabled()) - discord->state_server(server_name.toStdString(), hash.result().toBase64().toStdString()); + discord->state_server(server_name.toStdString(), + hash.result().toBase64().toStdString()); } - else if (header == "CI") - { + else if (header == "CI") { if (!courtroom_constructed) goto end; - for (int n_element = 0 ; n_element < f_contents.size() ; n_element += 2) - { + for (int n_element = 0; n_element < f_contents.size(); n_element += 2) { if (f_contents.at(n_element).toInt() != loaded_chars) break; - //this means we are on the last element and checking n + 1 element will be game over so + // this means we are on the last element and checking n + 1 element will + // be game over so if (n_element == f_contents.size() - 1) break; @@ -310,37 +291,40 @@ void AOApplication::server_packet_received(AOPacket *p_packet) f_char.name = sub_elements.at(0); f_char.description = sub_elements.at(1); f_char.evidence_string = sub_elements.at(3); - //temporary. the CharsCheck packet sets this properly + // temporary. the CharsCheck packet sets this properly f_char.taken = false; ++loaded_chars; - w_lobby->set_loading_text("Loading chars:\n" + QString::number(loaded_chars) + "/" + QString::number(char_list_size)); + w_lobby->set_loading_text("Loading chars:\n" + + QString::number(loaded_chars) + "/" + + QString::number(char_list_size)); w_courtroom->append_char(f_char); - int total_loading_size = char_list_size * 2 + evidence_list_size + music_list_size; - int loading_value = int(((loaded_chars + generated_chars + loaded_music + loaded_evidence) / static_cast(total_loading_size)) * 100); + int total_loading_size = + char_list_size * 2 + evidence_list_size + music_list_size; + int loading_value = int( + ((loaded_chars + generated_chars + loaded_music + loaded_evidence) / + static_cast(total_loading_size)) * + 100); w_lobby->set_loading_value(loading_value); } if (improved_loading_enabled) send_server_packet(new AOPacket("RE#%")); - else - { - QString next_packet_number = QString::number(((loaded_chars - 1) / 10) + 1); + else { + QString next_packet_number = + QString::number(((loaded_chars - 1) / 10) + 1); send_server_packet(new AOPacket("AN#" + next_packet_number + "#%")); } - } - else if (header == "EI") - { + else if (header == "EI") { if (!courtroom_constructed) goto end; - // +1 because evidence starts at 1 rather than 0 for whatever reason - //enjoy fanta + // enjoy fanta if (f_contents.at(0).toInt() != loaded_evidence + 1) goto end; @@ -354,33 +338,36 @@ void AOApplication::server_packet_received(AOPacket *p_packet) evi_type f_evi; f_evi.name = sub_elements.at(0); f_evi.description = sub_elements.at(1); - //no idea what the number at position 2 is. probably an identifier? + // no idea what the number at position 2 is. probably an identifier? f_evi.image = sub_elements.at(3); ++loaded_evidence; - w_lobby->set_loading_text("Loading evidence:\n" + QString::number(loaded_evidence) + "/" + QString::number(evidence_list_size)); + w_lobby->set_loading_text("Loading evidence:\n" + + QString::number(loaded_evidence) + "/" + + QString::number(evidence_list_size)); w_courtroom->append_evidence(f_evi); - int total_loading_size = char_list_size * 2 + evidence_list_size + music_list_size; - int loading_value = int(((loaded_chars + generated_chars + loaded_music + loaded_evidence) / static_cast(total_loading_size)) * 100); + int total_loading_size = + char_list_size * 2 + evidence_list_size + music_list_size; + int loading_value = + int(((loaded_chars + generated_chars + loaded_music + loaded_evidence) / + static_cast(total_loading_size)) * + 100); w_lobby->set_loading_value(loading_value); QString next_packet_number = QString::number(loaded_evidence); send_server_packet(new AOPacket("AE#" + next_packet_number + "#%")); - } - else if (header == "EM") - { + else if (header == "EM") { if (!courtroom_constructed) goto end; bool musics_time = false; int areas = 0; - for (int n_element = 0 ; n_element < f_contents.size() ; n_element += 2) - { + for (int n_element = 0; n_element < f_contents.size(); n_element += 2) { if (f_contents.at(n_element).toInt() != loaded_music) break; @@ -391,52 +378,49 @@ void AOApplication::server_packet_received(AOPacket *p_packet) ++loaded_music; - w_lobby->set_loading_text("Loading music:\n" + QString::number(loaded_music) + "/" + QString::number(music_list_size)); + w_lobby->set_loading_text("Loading music:\n" + + QString::number(loaded_music) + "/" + + QString::number(music_list_size)); - if (musics_time) - { + if (musics_time) { + w_courtroom->append_music(f_music); + } + else { + if (f_music.endsWith(".wav") || f_music.endsWith(".mp3") || + f_music.endsWith(".mp4") || f_music.endsWith(".ogg") || + f_music.endsWith(".opus")) { + musics_time = true; + areas--; + w_courtroom->fix_last_area(); w_courtroom->append_music(f_music); - } - else - { - if (f_music.endsWith(".wav") || - f_music.endsWith(".mp3") || - f_music.endsWith(".mp4") || - f_music.endsWith(".ogg") || - f_music.endsWith(".opus")) - { - musics_time = true; - areas--; - w_courtroom->fix_last_area(); - w_courtroom->append_music(f_music); - } - else - { - w_courtroom->append_area(f_music); - areas++; - } + } + else { + w_courtroom->append_area(f_music); + areas++; + } } - for (int area_n = 0; area_n < areas; area_n++) - { - w_courtroom->arup_append(0, "Unknown", "Unknown", "Unknown"); + for (int area_n = 0; area_n < areas; area_n++) { + w_courtroom->arup_append(0, "Unknown", "Unknown", "Unknown"); } - int total_loading_size = char_list_size * 2 + evidence_list_size + music_list_size; - int loading_value = int(((loaded_chars + generated_chars + loaded_music + loaded_evidence) / static_cast(total_loading_size)) * 100); + int total_loading_size = + char_list_size * 2 + evidence_list_size + music_list_size; + int loading_value = int( + ((loaded_chars + generated_chars + loaded_music + loaded_evidence) / + static_cast(total_loading_size)) * + 100); w_lobby->set_loading_value(loading_value); } QString next_packet_number = QString::number(((loaded_music - 1) / 10) + 1); send_server_packet(new AOPacket("AM#" + next_packet_number + "#%")); } - else if (header == "CharsCheck") - { + else if (header == "CharsCheck") { if (!courtroom_constructed) goto end; - for (int n_char = 0 ; n_char < f_contents.size() ; ++n_char) - { + for (int n_char = 0; n_char < f_contents.size(); ++n_char) { if (f_contents.at(n_char) == "-1") w_courtroom->set_taken(n_char, true); else @@ -444,13 +428,11 @@ void AOApplication::server_packet_received(AOPacket *p_packet) } } - else if (header == "SC") - { + else if (header == "SC") { if (!courtroom_constructed) goto end; - for (int n_element = 0 ; n_element < f_contents.size() ; ++n_element) - { + for (int n_element = 0; n_element < f_contents.size(); ++n_element) { QStringList sub_elements = f_contents.at(n_element).split("&"); char_type f_char; @@ -458,74 +440,78 @@ void AOApplication::server_packet_received(AOPacket *p_packet) if (sub_elements.size() >= 2) f_char.description = sub_elements.at(1); - //temporary. the CharsCheck packet sets this properly + // temporary. the CharsCheck packet sets this properly f_char.taken = false; ++loaded_chars; - w_lobby->set_loading_text("Loading chars:\n" + QString::number(loaded_chars) + "/" + QString::number(char_list_size)); + w_lobby->set_loading_text("Loading chars:\n" + + QString::number(loaded_chars) + "/" + + QString::number(char_list_size)); w_courtroom->append_char(f_char); - int total_loading_size = char_list_size * 2 + evidence_list_size + music_list_size; - int loading_value = int(((loaded_chars + generated_chars + loaded_music + loaded_evidence) / static_cast(total_loading_size)) * 100); + int total_loading_size = + char_list_size * 2 + evidence_list_size + music_list_size; + int loading_value = int( + ((loaded_chars + generated_chars + loaded_music + loaded_evidence) / + static_cast(total_loading_size)) * + 100); w_lobby->set_loading_value(loading_value); } send_server_packet(new AOPacket("RM#%")); } - else if (header == "SM") - { + else if (header == "SM") { if (!courtroom_constructed) goto end; bool musics_time = false; int areas = 0; - for (int n_element = 0 ; n_element < f_contents.size() ; ++n_element) - { + for (int n_element = 0; n_element < f_contents.size(); ++n_element) { ++loaded_music; - w_lobby->set_loading_text("Loading music:\n" + QString::number(loaded_music) + "/" + QString::number(music_list_size)); + w_lobby->set_loading_text("Loading music:\n" + + QString::number(loaded_music) + "/" + + QString::number(music_list_size)); - if (musics_time) - { + if (musics_time) { + w_courtroom->append_music(f_contents.at(n_element)); + } + else { + if (f_contents.at(n_element).endsWith(".wav") || + f_contents.at(n_element).endsWith(".mp3") || + f_contents.at(n_element).endsWith(".mp4") || + f_contents.at(n_element).endsWith(".ogg") || + f_contents.at(n_element).endsWith(".opus")) { + musics_time = true; + w_courtroom->fix_last_area(); w_courtroom->append_music(f_contents.at(n_element)); - } - else - { - if (f_contents.at(n_element).endsWith(".wav") || - f_contents.at(n_element).endsWith(".mp3") || - f_contents.at(n_element).endsWith(".mp4") || - f_contents.at(n_element).endsWith(".ogg") || - f_contents.at(n_element).endsWith(".opus")) - { - musics_time = true; - w_courtroom->fix_last_area(); - w_courtroom->append_music(f_contents.at(n_element)); - areas--; - } - else - { - w_courtroom->append_area(f_contents.at(n_element)); - areas++; - } + areas--; + } + else { + w_courtroom->append_area(f_contents.at(n_element)); + areas++; + } } - for (int area_n = 0; area_n < areas; area_n++) - { - w_courtroom->arup_append(0, "Unknown", "Unknown", "Unknown"); + for (int area_n = 0; area_n < areas; area_n++) { + w_courtroom->arup_append(0, "Unknown", "Unknown", "Unknown"); } - int total_loading_size = char_list_size * 2 + evidence_list_size + music_list_size; - int loading_value = int(((loaded_chars + generated_chars + loaded_music + loaded_evidence) / static_cast(total_loading_size)) * 100); + int total_loading_size = + char_list_size * 2 + evidence_list_size + music_list_size; + int loading_value = int( + ((loaded_chars + generated_chars + loaded_music + loaded_evidence) / + static_cast(total_loading_size)) * + 100); w_lobby->set_loading_value(loading_value); } send_server_packet(new AOPacket("RD#%")); } - else if (header == "DONE") - { + else if (header == "DONE") { if (!courtroom_constructed) goto end; @@ -539,59 +525,50 @@ void AOApplication::server_packet_received(AOPacket *p_packet) destruct_lobby(); } - else if (header == "BN") - { + else if (header == "BN") { if (f_contents.size() < 1) goto end; if (courtroom_constructed) w_courtroom->set_background(f_contents.at(0)); } - //server accepting char request(CC) packet - else if (header == "PV") - { + // server accepting char request(CC) packet + else if (header == "PV") { if (f_contents.size() < 3) goto end; if (courtroom_constructed) w_courtroom->enter_courtroom(f_contents.at(2).toInt()); } - else if (header == "MS") - { + else if (header == "MS") { if (courtroom_constructed && courtroom_loaded) w_courtroom->handle_chatmessage(&p_packet->get_contents()); } - else if (header == "MC") - { + else if (header == "MC") { if (courtroom_constructed && courtroom_loaded) w_courtroom->handle_song(&p_packet->get_contents()); } - else if (header == "RT") - { + else if (header == "RT") { if (f_contents.size() < 1) goto end; - if (courtroom_constructed) - { + if (courtroom_constructed) { if (f_contents.size() == 1) - w_courtroom->handle_wtce(f_contents.at(0), 0); + w_courtroom->handle_wtce(f_contents.at(0), 0); else if (f_contents.size() == 2) { - w_courtroom->handle_wtce(f_contents.at(0), f_contents.at(1).toInt()); + w_courtroom->handle_wtce(f_contents.at(0), f_contents.at(1).toInt()); } } } - else if (header == "HP") - { + else if (header == "HP") { if (courtroom_constructed && f_contents.size() > 1) - w_courtroom->set_hp_bar(f_contents.at(0).toInt(), f_contents.at(1).toInt()); + w_courtroom->set_hp_bar(f_contents.at(0).toInt(), + f_contents.at(1).toInt()); } - else if (header == "LE") - { - if (courtroom_constructed) - { + else if (header == "LE") { + if (courtroom_constructed) { QVector f_evi_list; - for (QString f_string : f_contents) - { + for (QString f_string : f_contents) { QStringList sub_contents = f_string.split("&"); if (sub_contents.size() < 3) @@ -608,67 +585,59 @@ void AOApplication::server_packet_received(AOPacket *p_packet) w_courtroom->set_evidence_list(f_evi_list); } } - else if (header == "ARUP") - { - if (courtroom_constructed) - { - int arup_type = f_contents.at(0).toInt(); - for (int n_element = 1 ; n_element < f_contents.size() ; n_element++) - { - w_courtroom->arup_modify(arup_type, n_element - 1, f_contents.at(n_element)); - } + else if (header == "ARUP") { + if (courtroom_constructed) { + int arup_type = f_contents.at(0).toInt(); + for (int n_element = 1; n_element < f_contents.size(); n_element++) { + w_courtroom->arup_modify(arup_type, n_element - 1, + f_contents.at(n_element)); } + } } - else if (header == "IL") - { + else if (header == "IL") { if (courtroom_constructed && f_contents.size() > 0) w_courtroom->set_ip_list(f_contents.at(0)); } - else if (header == "MU") - { + else if (header == "MU") { if (courtroom_constructed && f_contents.size() > 0) w_courtroom->set_mute(true, f_contents.at(0).toInt()); } - else if (header == "UM") - { + else if (header == "UM") { if (courtroom_constructed && f_contents.size() > 0) w_courtroom->set_mute(false, f_contents.at(0).toInt()); } - else if (header == "KK") - { - if (courtroom_constructed && f_contents.size() >= 1) - { - call_notice("You have been kicked from the server.\nReason: " + f_contents.at(0)); + else if (header == "KK") { + if (courtroom_constructed && f_contents.size() >= 1) { + call_notice("You have been kicked from the server.\nReason: " + + f_contents.at(0)); construct_lobby(); destruct_courtroom(); } } - else if (header == "KB") - { - if (courtroom_constructed && f_contents.size() >= 1) - { - call_notice("You have been banned from the server.\nReason: " + f_contents.at(0)); + else if (header == "KB") { + if (courtroom_constructed && f_contents.size() >= 1) { + call_notice("You have been banned from the server.\nReason: " + + f_contents.at(0)); construct_lobby(); destruct_courtroom(); } - } - else if (header == "BD") - { + else if (header == "BD") { call_notice("You are banned on this server.\nReason: " + f_contents.at(0)); } - else if (header == "ZZ") - { + else if (header == "ZZ") { if (courtroom_constructed && f_contents.size() > 0) w_courtroom->mod_called(f_contents.at(0)); } - else if (header == "CASEA") - { + else if (header == "CASEA") { if (courtroom_constructed && f_contents.size() > 6) - w_courtroom->case_called(f_contents.at(0), f_contents.at(1) == "1", f_contents.at(2) == "1", f_contents.at(3) == "1", f_contents.at(4) == "1", f_contents.at(5) == "1"); + w_courtroom->case_called(f_contents.at(0), f_contents.at(1) == "1", + f_contents.at(2) == "1", f_contents.at(3) == "1", + f_contents.at(4) == "1", + f_contents.at(5) == "1"); } - end: +end: delete p_packet; } @@ -695,8 +664,7 @@ void AOApplication::send_server_packet(AOPacket *p_packet, bool encoded) QString f_packet = p_packet->to_string(); - if (encryption_needed) - { + if (encryption_needed) { #ifdef DEBUG_NETWORK qDebug() << "S(e):" << f_packet; #endif @@ -704,8 +672,7 @@ void AOApplication::send_server_packet(AOPacket *p_packet, bool encoded) p_packet->encrypt_header(s_decryptor); f_packet = p_packet->to_string(); } - else - { + else { #ifdef DEBUG_NETWORK qDebug() << "S:" << f_packet; #endif diff --git a/src/path_functions.cpp b/src/path_functions.cpp index c51cfde..811ca76 100644 --- a/src/path_functions.cpp +++ b/src/path_functions.cpp @@ -3,18 +3,18 @@ #include "file_functions.h" #include -#include #include +#include #ifdef BASE_OVERRIDE #include "base_override.h" #endif -//this is a quite broad generalization -//the most common OSes(mac and windows) are _usually_ case insensitive -//however, there do exist mac installations with case sensitive filesystems -//in that case, define CASE_SENSITIVE_FILESYSTEM and compile on a mac -#if (defined (LINUX) || defined (__linux__)) +// this is a quite broad generalization +// the most common OSes(mac and windows) are _usually_ case insensitive +// however, there do exist mac installations with case sensitive filesystems +// in that case, define CASE_SENSITIVE_FILESYSTEM and compile on a mac +#if (defined(LINUX) || defined(__linux__)) #define CASE_SENSITIVE_FILESYSTEM #endif @@ -23,7 +23,7 @@ QString AOApplication::get_base_path() QString base_path = ""; #ifdef ANDROID QString sdcard_storage = getenv("SECONDARY_STORAGE"); - if (dir_exists(sdcard_storage + "/AO2/")){ + if (dir_exists(sdcard_storage + "/AO2/")) { base_path = sdcard_storage + "/AO2/"; } else { @@ -37,10 +37,7 @@ QString AOApplication::get_base_path() return base_path; } -QString AOApplication::get_data_path() -{ - return get_base_path() + "data/"; -} +QString AOApplication::get_data_path() { return get_base_path() + "data/"; } QString AOApplication::get_default_theme_path(QString p_file) { @@ -104,7 +101,8 @@ QString AOApplication::get_music_path(QString p_song) QString AOApplication::get_background_path(QString p_file) { - QString path = get_base_path() + "background/" + w_courtroom->get_current_background() + "/" + p_file; + QString path = get_base_path() + "background/" + + w_courtroom->get_current_background() + "/" + p_file; if (courtroom_constructed) { #ifndef CASE_SENSITIVE_FILESYSTEM return path; @@ -135,21 +133,25 @@ QString AOApplication::get_evidence_path(QString p_file) #endif } -QString AOApplication::get_case_sensitive_path(QString p_file) { - //first, check to see if it's actually there (also serves as base case for recursion) - if (exists(p_file)) return p_file; +QString AOApplication::get_case_sensitive_path(QString p_file) +{ + // first, check to see if it's actually there (also serves as base case for + // recursion) + if (exists(p_file)) + return p_file; QFileInfo file(p_file); QString file_basename = file.fileName(); QString file_parent_dir = get_case_sensitive_path(file.absolutePath()); - //second, does it exist in the new parent dir? + // second, does it exist in the new parent dir? if (exists(file_parent_dir + "/" + file_basename)) return file_parent_dir + "/" + file_basename; - //last resort, dirlist parent dir and find case insensitive match - QRegExp file_rx = QRegExp(file_basename, Qt::CaseInsensitive, QRegExp::FixedString); + // last resort, dirlist parent dir and find case insensitive match + QRegExp file_rx = + QRegExp(file_basename, Qt::CaseInsensitive, QRegExp::FixedString); QStringList files = QDir(file_parent_dir).entryList(); int result = files.indexOf(file_rx); @@ -157,6 +159,6 @@ QString AOApplication::get_case_sensitive_path(QString p_file) { if (result != -1) return file_parent_dir + "/" + files.at(result); - //if nothing is found, let the caller handle the missing file + // if nothing is found, let the caller handle the missing file return file_parent_dir + "/" + file_basename; } diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index 5a34ac8..18f0e4c 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -48,13 +48,15 @@ int AOApplication::get_max_log_size() bool AOApplication::get_log_goes_downwards() { - QString result = configini->value("log_goes_downwards", "false").value(); + QString result = + configini->value("log_goes_downwards", "false").value(); return result.startsWith("true"); } bool AOApplication::get_showname_enabled_by_default() { - QString result = configini->value("show_custom_shownames", "true").value(); + QString result = + configini->value("show_custom_shownames", "true").value(); return result.startsWith("true"); } @@ -62,14 +64,15 @@ QString AOApplication::get_default_username() { QString result = configini->value("default_username", "").value(); if (result.isEmpty()) - return get_ooc_name(); + return get_ooc_name(); else - return result; + return result; } QString AOApplication::get_audio_output_device() { - QString result = configini->value("default_audio_device", "default").value(); + QString result = + configini->value("default_audio_device", "default").value(); return result; } @@ -86,8 +89,7 @@ QStringList AOApplication::get_call_words() QTextStream in(&callwords_ini); - while (!in.atEnd()) - { + while (!in.atEnd()) { QString line = in.readLine(); return_value.append(line); } @@ -102,8 +104,7 @@ void AOApplication::write_to_serverlist_txt(QString p_line) serverlist_txt.setFileName(serverlist_txt_path); - if (!serverlist_txt.open(QIODevice::WriteOnly | QIODevice::Append)) - { + if (!serverlist_txt.open(QIODevice::WriteOnly | QIODevice::Append)) { return; } @@ -123,21 +124,19 @@ QVector AOApplication::read_serverlist_txt() serverlist_txt.setFileName(serverlist_txt_path); - if (!serverlist_txt.open(QIODevice::ReadOnly)) - { + if (!serverlist_txt.open(QIODevice::ReadOnly)) { return f_server_list; } QTextStream in(&serverlist_txt); - while(!in.atEnd()) - { + while (!in.atEnd()) { QString line = in.readLine(); server_type f_server; QStringList line_contents = line.split(":"); if (line_contents.size() < 3) - continue; + continue; f_server.ip = line_contents.at(0); f_server.port = line_contents.at(1).toInt(); @@ -150,13 +149,15 @@ QVector AOApplication::read_serverlist_txt() return f_server_list; } -QString AOApplication::read_design_ini(QString p_identifier, QString p_design_path) +QString AOApplication::read_design_ini(QString p_identifier, + QString p_design_path) { QSettings settings(p_design_path, QSettings::IniFormat); QVariant value = settings.value(p_identifier); if (value.type() == QVariant::StringList) { return value.toStringList().join(","); - } else { + } + else { return value.toString(); } } @@ -172,8 +173,7 @@ QPoint AOApplication::get_button_spacing(QString p_identifier, QString p_file) return_value.setX(0); return_value.setY(0); - if (f_result == "") - { + if (f_result == "") { f_result = read_design_ini(p_identifier, default_path); if (f_result == "") @@ -191,7 +191,8 @@ QPoint AOApplication::get_button_spacing(QString p_identifier, QString p_file) return return_value; } -pos_size_type AOApplication::get_element_dimensions(QString p_identifier, QString p_file) +pos_size_type AOApplication::get_element_dimensions(QString p_identifier, + QString p_file) { QString design_ini_path = get_theme_path(p_file); QString default_path = get_default_theme_path(p_file); @@ -204,8 +205,7 @@ pos_size_type AOApplication::get_element_dimensions(QString p_identifier, QStrin return_value.width = -1; return_value.height = -1; - if (f_result == "") - { + if (f_result == "") { f_result = read_design_ini(p_identifier, default_path); if (f_result == "") @@ -229,8 +229,7 @@ QString AOApplication::get_font_name(QString p_identifier, QString p_file) 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 == "") - { + if (f_result == "") { f_result = read_design_ini(p_identifier, default_path); if (f_result == "") return "Sans"; @@ -243,8 +242,7 @@ int AOApplication::get_font_size(QString p_identifier, QString 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 == "") - { + if (f_result == "") { f_result = read_design_ini(p_identifier, default_path); if (f_result == "") @@ -262,8 +260,7 @@ QColor AOApplication::get_color(QString p_identifier, QString p_file) QColor return_color(0, 0, 0); - if (f_result == "") - { + if (f_result == "") { f_result = read_design_ini(p_identifier, default_path); if (f_result == "") @@ -286,39 +283,37 @@ QColor AOApplication::get_chat_color(QString p_identifier, QString p_chat) { QColor return_color(255, 255, 255); - if (p_identifier == "_inline_grey") - { + if (p_identifier == "_inline_grey") { return_color = QColor(187, 187, 187); } - else - { + else { switch (p_identifier.toInt()) { - case 1: - return_color = QColor(0, 255, 0); - break; - case 2: - return_color = QColor(255, 0, 0); - break; - case 3: - return_color = QColor(255, 165, 0); - break; - case 4: - return_color = QColor(45, 150, 255); - break; - case 5: - return_color = QColor(255, 255, 0); - break; - case 7: - return_color = QColor(255, 192, 203); - break; - case 8: - return_color = QColor(0, 255, 255); - break; - case 0: - case 6: // 6 is rainbow. - default: - return_color = QColor(255, 255, 255); - break; + case 1: + return_color = QColor(0, 255, 0); + break; + case 2: + return_color = QColor(255, 0, 0); + break; + case 3: + return_color = QColor(255, 165, 0); + break; + case 4: + return_color = QColor(45, 150, 255); + break; + case 5: + return_color = QColor(255, 255, 0); + break; + case 7: + return_color = QColor(255, 192, 203); + break; + case 8: + return_color = QColor(0, 255, 255); + break; + case 0: + case 6: // 6 is rainbow. + default: + return_color = QColor(255, 255, 255); + break; } } @@ -327,8 +322,7 @@ QColor AOApplication::get_chat_color(QString p_identifier, QString p_chat) QString default_path = get_base_path() + "misc/default/config.ini"; QString f_result = read_design_ini(p_identifier, design_ini_path); - if (f_result == "") - { + if (f_result == "") { f_result = read_design_ini(p_identifier, default_path); if (f_result == "") @@ -355,8 +349,7 @@ QString AOApplication::get_sfx(QString p_identifier) QString return_sfx = ""; - if (f_result == "") - { + if (f_result == "") { f_result = read_design_ini(p_identifier, default_path); if (f_result == "") @@ -370,35 +363,34 @@ QString AOApplication::get_sfx(QString p_identifier) QString AOApplication::get_sfx_suffix(QString sound_to_check) { - QString mp3_check = get_sounds_path(sound_to_check + ".mp3"); - QString opus_check = get_sounds_path(sound_to_check + ".opus"); - if (file_exists(opus_check)) - { - return sound_to_check + ".opus"; - } - else if (file_exists(mp3_check)) - { - return sound_to_check + ".mp3"; - } - return sound_to_check + ".wav"; + QString mp3_check = get_sounds_path(sound_to_check + ".mp3"); + QString opus_check = get_sounds_path(sound_to_check + ".opus"); + if (file_exists(opus_check)) { + return sound_to_check + ".opus"; + } + else if (file_exists(mp3_check)) { + return sound_to_check + ".mp3"; + } + return sound_to_check + ".wav"; } QString AOApplication::get_image_suffix(QString path_to_check) { - QString apng_check = path_to_check + ".apng"; - if (file_exists(apng_check)) - { - return apng_check; - } - return path_to_check + ".gif"; + QString apng_check = path_to_check + ".apng"; + if (file_exists(apng_check)) { + return apng_check; + } + return path_to_check + ".gif"; } - -//returns whatever is to the right of "search_line =" within target_tag and terminator_tag, trimmed -//returns the empty string if the search line couldnt be found -QString AOApplication::read_char_ini(QString p_char, QString p_search_line, QString target_tag) +// returns whatever is to the right of "search_line =" within target_tag and +// terminator_tag, trimmed returns the empty string if the search line couldnt +// be found +QString AOApplication::read_char_ini(QString p_char, QString p_search_line, + QString target_tag) { - QSettings settings(get_character_path(p_char, "char.ini"), QSettings::IniFormat); + QSettings settings(get_character_path(p_char, "char.ini"), + QSettings::IniFormat); settings.beginGroup(target_tag); QString value = settings.value(p_search_line).toString(); settings.endGroup(); @@ -411,7 +403,8 @@ QString AOApplication::get_char_name(QString p_char) if (f_result == "") return p_char; - else return f_result; + else + return f_result; } QString AOApplication::get_showname(QString p_char) @@ -423,7 +416,8 @@ QString AOApplication::get_showname(QString p_char) return ""; if (f_result == "") return p_char; - else return f_result; + else + return f_result; } QString AOApplication::get_char_side(QString p_char) @@ -432,7 +426,8 @@ QString AOApplication::get_char_side(QString p_char) if (f_result == "") return "wit"; - else return f_result; + else + return f_result; } QString AOApplication::get_gender(QString p_char) @@ -441,14 +436,16 @@ QString AOApplication::get_gender(QString p_char) if (f_result == "") return "male"; - else return f_result; + else + return f_result; } QString AOApplication::get_chat(QString p_char) { 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 + // handling the correct order of chat is a bit complicated, we let the caller + // do it return f_result; } @@ -457,7 +454,8 @@ QString AOApplication::get_char_shouts(QString p_char) QString f_result = read_char_ini(p_char, "shouts", "Options"); if (f_result == "") return "default"; - else return f_result; + else + return f_result; } int AOApplication::get_preanim_duration(QString p_char, QString p_emote) @@ -466,7 +464,8 @@ int AOApplication::get_preanim_duration(QString p_char, QString p_emote) if (f_result == "") return -1; - else return f_result.toInt(); + else + return f_result.toInt(); } int AOApplication::get_ao2_preanim_duration(QString p_char, QString p_emote) @@ -475,7 +474,8 @@ int AOApplication::get_ao2_preanim_duration(QString p_char, QString p_emote) if (f_result == "") return -1; - else return f_result.toInt(); + else + return f_result.toInt(); } int AOApplication::get_emote_number(QString p_char) @@ -484,68 +484,75 @@ int AOApplication::get_emote_number(QString p_char) if (f_result == "") return 0; - else return f_result.toInt(); + else + return f_result.toInt(); } QString AOApplication::get_emote_comment(QString p_char, int p_emote) { - QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); + QString f_result = + read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); QStringList result_contents = f_result.split("#"); - if (result_contents.size() < 4) - { + if (result_contents.size() < 4) { qDebug() << "W: misformatted char.ini: " << p_char << ", " << p_emote; return "normal"; } - else return result_contents.at(0); + else + return result_contents.at(0); } QString AOApplication::get_pre_emote(QString p_char, int p_emote) { - QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); + QString f_result = + read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); QStringList result_contents = f_result.split("#"); - if (result_contents.size() < 4) - { + if (result_contents.size() < 4) { qDebug() << "W: misformatted char.ini: " << p_char << ", " << p_emote; return ""; } - else return result_contents.at(1); + else + return result_contents.at(1); } QString AOApplication::get_emote(QString p_char, int p_emote) { - QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); + QString f_result = + read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); QStringList result_contents = f_result.split("#"); - if (result_contents.size() < 4) - { + if (result_contents.size() < 4) { qDebug() << "W: misformatted char.ini: " << p_char << ", " << p_emote; return "normal"; } - else return result_contents.at(2); + else + return result_contents.at(2); } int AOApplication::get_emote_mod(QString p_char, int p_emote) { - QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); + QString f_result = + read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); QStringList result_contents = f_result.split("#"); - if (result_contents.size() < 4) - { - qDebug() << "W: misformatted char.ini: " << p_char << ", " << QString::number(p_emote); + if (result_contents.size() < 4) { + qDebug() << "W: misformatted char.ini: " << p_char << ", " + << QString::number(p_emote); return 0; } - else return result_contents.at(3).toInt(); + else + return result_contents.at(3).toInt(); } int AOApplication::get_desk_mod(QString p_char, int p_emote) { - QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); + QString f_result = + read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); QStringList result_contents = f_result.split("#"); @@ -556,25 +563,30 @@ int AOApplication::get_desk_mod(QString p_char, int p_emote) if (string_result == "") return -1; - else return string_result.toInt(); + else + return string_result.toInt(); } QString AOApplication::get_sfx_name(QString p_char, int p_emote) { - QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "SoundN"); + QString f_result = + read_char_ini(p_char, QString::number(p_emote + 1), "SoundN"); if (f_result == "") return "1"; - else return f_result; + else + return f_result; } int AOApplication::get_sfx_delay(QString p_char, int p_emote) { - QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "SoundT"); + QString f_result = + read_char_ini(p_char, QString::number(p_emote + 1), "SoundT"); if (f_result == "") return 1; - else return f_result.toInt(); + else + return f_result.toInt(); } int AOApplication::get_text_delay(QString p_char, QString p_emote) @@ -583,7 +595,8 @@ int AOApplication::get_text_delay(QString p_char, QString p_emote) if (f_result == "") return -1; - else return f_result.toInt(); + else + return f_result.toInt(); } QString AOApplication::get_custom_realization(QString p_char) @@ -592,65 +605,74 @@ QString AOApplication::get_custom_realization(QString p_char) if (f_result == "") return get_sfx("realization"); - else return f_result; + else + return f_result; } bool AOApplication::get_blank_blip() { - QString result = configini->value("blank_blip", "false").value(); - return result.startsWith("true"); + QString result = configini->value("blank_blip", "false").value(); + return result.startsWith("true"); } bool AOApplication::is_discord_enabled() { - QString result = configini->value("discord", "true").value(); - return result.startsWith("true"); + QString result = configini->value("discord", "true").value(); + return result.startsWith("true"); } bool AOApplication::get_casing_enabled() { - QString result = configini->value("casing_enabled", "false").value(); - return result.startsWith("true"); + QString result = configini->value("casing_enabled", "false").value(); + return result.startsWith("true"); } bool AOApplication::get_casing_defence_enabled() { - QString result = configini->value("casing_defence_enabled", "false").value(); - return result.startsWith("true"); + QString result = + configini->value("casing_defence_enabled", "false").value(); + return result.startsWith("true"); } bool AOApplication::get_casing_prosecution_enabled() { - QString result = configini->value("casing_prosecution_enabled", "false").value(); - return result.startsWith("true"); + QString result = + configini->value("casing_prosecution_enabled", "false").value(); + return result.startsWith("true"); } bool AOApplication::get_casing_judge_enabled() { - QString result = configini->value("casing_judge_enabled", "false").value(); - return result.startsWith("true"); + QString result = + configini->value("casing_judge_enabled", "false").value(); + return result.startsWith("true"); } bool AOApplication::get_casing_juror_enabled() { - QString result = configini->value("casing_juror_enabled", "false").value(); - return result.startsWith("true"); + QString result = + configini->value("casing_juror_enabled", "false").value(); + return result.startsWith("true"); } bool AOApplication::get_casing_steno_enabled() { - QString result = configini->value("casing_steno_enabled", "false").value(); + QString result = + configini->value("casing_steno_enabled", "false").value(); return result.startsWith("true"); } bool AOApplication::get_casing_cm_enabled() { - QString result = configini->value("casing_cm_enabled", "false").value(); - return result.startsWith("true"); + QString result = + configini->value("casing_cm_enabled", "false").value(); + return result.startsWith("true"); } QString AOApplication::get_casing_can_host_cases() { - QString result = configini->value("casing_can_host_cases", "Turnabout Check Your Settings").value(); + QString result = + configini->value("casing_can_host_cases", "Turnabout Check Your Settings") + .value(); return result; } From df8f19320b3a37521a7f93a578bf31c81f885238 Mon Sep 17 00:00:00 2001 From: oldmud0 Date: Fri, 22 May 2020 19:35:49 -0500 Subject: [PATCH 179/268] Bring back CI changes and macOS support --- .github/labeler.yml | 8 +++++ .gitignore | 4 +++ .gitlab-ci.yml | 69 ++++++++++++++++++++++++++++--------- .travis.yml | 22 ++++++++---- scripts/configure_ubuntu.sh | 6 ++-- scripts/macos_build.sh | 2 +- scripts/macos_post_build.sh | 4 ++- scripts/wasabi_program.sh | 2 +- scripts/windows/Dockerfile | 11 ++++-- src/hardware_functions.cpp | 4 +++ src/path_functions.cpp | 2 ++ 11 files changed, 104 insertions(+), 30 deletions(-) create mode 100644 .github/labeler.yml mode change 100644 => 100755 scripts/macos_post_build.sh diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 0000000..56c4cc7 --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,8 @@ +translation: + - resource/translations/* + +content: + - base/**/* + +good_luck: + - src/courtroom.cpp diff --git a/.gitignore b/.gitignore index 1adb744..3f8b3ae 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ *.dll *.so *.pro.autosave +*.pro.user base_override.h .DS_Store @@ -21,6 +22,7 @@ debug/ Makefile* object_script* +/android/gradle* /Attorney_Online_remake_resource.rc /attorney_online_remake_plugin_import.cpp @@ -31,3 +33,5 @@ discord/ moc* /Attorney_Online_CC_resource.rc /attorney_online_cc_plugin_import.cpp + +*.autosave diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0f68fe5..e9685de 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -8,6 +8,9 @@ cache: paths: - lib/ +variables: + DEBIAN_FRONTEND: noninteractive + before_script: - echo Current working directory is $(pwd) @@ -22,22 +25,24 @@ build linux x86_64: - apt-get update - > apt-get install --no-install-recommends -y qt5-default qtmultimedia5-dev - clang make git sudo curl ca-certificates pkg-config upx unzip + clang make git sudo curl ca-certificates pkg-config upx unzip xz-utils + - git submodule init + - git submodule update # Print versions - qmake --version - clang --version # Extract BASS - - mkdir bass - - cd bass - - curl http://www.un4seen.com/files/bass24-linux.zip -o bass.zip - - unzip bass.zip - - cp x64/libbass.so ../lib - - curl http://www.un4seen.com/files/bassopus24-linux.zip -o bassopus.zip - - unzip bassopus.zip - - cp x64/libbassopus.so ../lib - - cd .. + #- mkdir bass + #- cd bass + #- curl http://www.un4seen.com/files/bass24-linux.zip -o bass.zip + #- unzip bass.zip + #- cp x64/libbass.so ../lib + #- curl http://www.un4seen.com/files/bassopus24-linux.zip -o bassopus.zip + #- unzip bassopus.zip + #- cp x64/libbassopus.so ../lib + #- cd .. # Extract Discord RPC - mkdir discord-rpc @@ -56,7 +61,7 @@ build linux x86_64: - cd .. # Build - - qmake -spec linux-clang + - qmake -spec linux-clang "DEFINES += DISCORD QTAUDIO" - make -j4 # Post-processing @@ -75,6 +80,11 @@ build windows i686: # Install dependencies - apt-get update - apt-get install --no-install-recommends -y make curl ca-certificates upx unzip + - git submodule init + - git submodule update + + # Print versions + - /opt/mxe/usr/${TARGET_SPEC}/qt5/bin/qmake --version # Extract BASS - mkdir bass @@ -87,8 +97,19 @@ build windows i686: - cp bassopus.dll ../lib - cd .. + # Extract QtApng + # - mkdir qtapng + # - cd qtapng + # - curl -L https://github.com/Skycoder42/QtApng/releases/download/1.1.2-2/qtapng_mingw73_32_5.13.0.zip -o apng.zip + # - unzip apng.zip + # - mkdir ../lib/imageformats + # - cp mingw73_32/plugins/imageformats/qapng.dll ../lib/imageformats/ + # - cd .. + + - ls lib + # Build - - /opt/mxe/usr/${TARGET_SPEC}/qt5/bin/qmake + - /opt/mxe/usr/${TARGET_SPEC}/qt5/bin/qmake "DEFINES += DISCORD BASSAUDIO" - make -j4 # Post-processing @@ -124,7 +145,7 @@ deploy linux x86_64: - *deploy_misc # Platform-specific - - cp -a ../lib/*.so . + - cp -a ../lib/* . - cp -a ../bin/Attorney_Online . - echo "#!/bin/sh" >> ./run.sh - echo "LD_LIBRARY_PATH=.:\$LD_LIBRARY_PATH ./Attorney_Online" >> ./run.sh @@ -158,6 +179,8 @@ deploy windows i686: # Platform-specific - cp -a ../lib/*.dll . + - mkdir imageformats + - 'cp -a ../lib/imageformats/*.dll imageformats/ || :' - cp -a ../bin/Attorney_Online.exe . # Zipping @@ -190,11 +213,17 @@ publish linux x86_64: - deploy linux x86_64 when: manual script: + - apt-get update + - apt-get install --no-install-recommends -y git nodejs npm awscli + - cd scripts + - npm install + - cd .. + - cd zip - - ../scripts/wasabi.sh + - ../scripts/wasabi_program.sh variables: MANIFEST: program_linux_x86_64.json - ARTIFACT_SUFFIX: _linux_x64.tar.xz + ARTIFACT_SUFFIX: linux_x64.tar.xz publish windows i686: image: ubuntu @@ -203,8 +232,14 @@ publish windows i686: - deploy windows i686 when: manual script: + - apt-get update + - apt-get install --no-install-recommends -y git nodejs npm awscli + - cd scripts + - npm install + - cd .. + - cd zip - - ../scripts/wasabi.sh + - ../scripts/wasabi_program.sh variables: MANIFEST: program_winnt_i386.json - ARTIFACT_SUFFIX: _windows_x86.zip + ARTIFACT_SUFFIX: windows_x86.zip diff --git a/.travis.yml b/.travis.yml index 4243b3b..dbd19cd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,11 +1,21 @@ language: cpp os: osx - addons: - homebrew: - packages: - - qt5 + homebrew: + update: true + packages: + - qt5 script: - - ./scripts/macos_build.sh - - ./scripts/macos_post_build.sh +- "./scripts/macos_build.sh" +- "./scripts/macos_post_build.sh" + +deploy: + provider: releases + api_key: + secure: mZCNwnqKeqJP5CqgYOanYnr/KHydxueGPRhvGLpY0Pop7MiH3CIHMN5dhHbtgJvE5GGMR4xUIEhPpmkCEJw7YiPREMqT4mkV4DR531ZLB3t/FizyvIwXuP6jFwzTofZ51qHfBpcurVc9sMFeD9Pw+rLTTgIiXL2sZxUUXc8U+ZZug1lYndgcO6P00fUJd6V9lyFQUGmbSca97YbG6KuCym0fEpyRnMqzKLjYsUUo8UKRBADtmD822O6z2FSldNZDn45Mkx0MYfHWyT5hzTb7WGa+DrTB/0un1HqqsNPlb/ahjrFQQNR2qd7HNGZa+Mvwi6egTDug+k15x8lbkacUoi34U1eFq9LSTYm8dSO5g23I1OvGvjTCkDj1jOLPqB99XlbAJ0E/9Jzw7wtlLaAzvFzTj/B63TQnO3IsgHBWR14CZlf05WMOFf2irwl+kL6ktspIHnlGgaiWYYrKeAt7QJAXiQOdYDz6SaWVC6TyOE/SszXRU6xFotmCjkP2irM5yGE8SUw2uIzKjD9uG0ZXtbLcdQEFD316+qglqFTCjnKsRfbtQs2u5spZPsZSdsOZCbLfNIn0GSTFRymFsK6gsvji8AD8AZo0zcOZ/7NMVC6A8RnF3Ve+vU/xljhsIOxoLZDvZPia7WozdV99xmnepWBwkuoQs/K0xmWcnLZDcb0= + file: "../bin/Attorney_Online_mac_x86_64.zip" + draft: true + on: + tags: true + repo: AttorneyOnline/AO2-Client diff --git a/scripts/configure_ubuntu.sh b/scripts/configure_ubuntu.sh index 1f9b8e8..280dfdf 100755 --- a/scripts/configure_ubuntu.sh +++ b/scripts/configure_ubuntu.sh @@ -7,11 +7,13 @@ set -eu ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/" -cd ${ROOT_DIR} +cd "${ROOT_DIR}" + #need some openGL stuff sudo apt install libgl1-mesa-dev - +#install curl incase of fresh vm +sudo apt install curl mkdir tmp cd tmp diff --git a/scripts/macos_build.sh b/scripts/macos_build.sh index 22e2d45..efb7653 100755 --- a/scripts/macos_build.sh +++ b/scripts/macos_build.sh @@ -30,4 +30,4 @@ tar -xvf apng.tar.xz cp clang_64/plugins/imageformats/libqapng.dylib ../lib cd .. -qmake && make -j2 +/usr/local/opt/qt/bin/qmake && make -j2 diff --git a/scripts/macos_post_build.sh b/scripts/macos_post_build.sh old mode 100644 new mode 100755 index 50acb40..df1475c --- a/scripts/macos_post_build.sh +++ b/scripts/macos_post_build.sh @@ -13,10 +13,12 @@ ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/" cd ${ROOT_DIR} # This thing basically does all the work -macdeployqt ../bin/Attorney_Online.app +/usr/local/opt/qt/bin/macdeployqt ../bin/Attorney_Online.app # Need to add the dependencies cp ../lib/* ../bin/Attorney_Online.app/Contents/Frameworks # libbass has a funny path for some reason, just use rpath install_name_tool -change @loader_path/libbass.dylib @rpath/libbass.dylib ../bin/Attorney_Online.app/Contents/MacOS/Attorney_Online + +zip -r -9 ../bin/Attorney_Online_mac_x86_64.zip ../bin/ \ No newline at end of file diff --git a/scripts/wasabi_program.sh b/scripts/wasabi_program.sh index 41e2e35..37feac6 100755 --- a/scripts/wasabi_program.sh +++ b/scripts/wasabi_program.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # Updates the specified program manifest to a new archive and version # and uploads the new archive and manifest to S3/Wasabi. # diff --git a/scripts/windows/Dockerfile b/scripts/windows/Dockerfile index f4f1a83..b9a12d6 100644 --- a/scripts/windows/Dockerfile +++ b/scripts/windows/Dockerfile @@ -10,5 +10,12 @@ RUN /opt/mxe/usr/bin/${TARGET_SPEC}-cmake .. -DCMAKE_INSTALL_PREFIX=/opt/mxe/usr RUN /opt/mxe/usr/bin/${TARGET_SPEC}-cmake --build . --config Release --target install WORKDIR ../.. -# NOTE: Do not build QtApng statically! libpng contains a self-test entry point that -# takes precedence for some reason over the final build's entry point. +# Build QtApng statically +RUN git clone https://github.com/Skycoder42/QtApng +WORKDIR QtApng +# libpng contains a self-test entry point that takes precedence for some reason +# over the final build's entry point. +RUN sed -i "s/^main(/libpng_main(/g" src/3rdparty/libpng/src/pngtest.c +RUN /opt/mxe/usr/${TARGET_SPEC}/qt5/bin/qmake +RUN make && make install +WORKDIR .. \ No newline at end of file diff --git a/src/hardware_functions.cpp b/src/hardware_functions.cpp index c898aef..82b4f0c 100644 --- a/src/hardware_functions.cpp +++ b/src/hardware_functions.cpp @@ -49,6 +49,10 @@ QString get_hdid() } #elif defined __APPLE__ + +#include +#include + QString get_hdid() { CFStringRef serial; diff --git a/src/path_functions.cpp b/src/path_functions.cpp index 811ca76..10c8ae5 100644 --- a/src/path_functions.cpp +++ b/src/path_functions.cpp @@ -30,6 +30,8 @@ QString AOApplication::get_base_path() QString external_storage = getenv("EXTERNAL_STORAGE"); base_path = external_storage + "/AO2/"; } +#elif defined(__APPLE__) + base_path = applicationDirPath() + "/../../../base/"; #else base_path = applicationDirPath() + "/base/"; #endif From 25ae8071fb18c000804660f671b1cb0f9d69b3f9 Mon Sep 17 00:00:00 2001 From: oldmud0 Date: Fri, 22 May 2020 19:37:12 -0500 Subject: [PATCH 180/268] Bring back Android project files --- Attorney_Online.pro | 11 ++++ android/AndroidManifest.xml | 79 +++++++++++++++++++++++++++++ android/build.gradle | 62 ++++++++++++++++++++++ android/project.properties | 1 + android/res/drawable-ldpi/icon.png | Bin 0 -> 29302 bytes android/res/values/libs.xml | 22 ++++++++ 6 files changed, 175 insertions(+) create mode 100644 android/AndroidManifest.xml create mode 100644 android/build.gradle create mode 100644 android/project.properties create mode 100644 android/res/drawable-ldpi/icon.png create mode 100644 android/res/values/libs.xml diff --git a/Attorney_Online.pro b/Attorney_Online.pro index 7eda548..f04c22a 100644 --- a/Attorney_Online.pro +++ b/Attorney_Online.pro @@ -43,3 +43,14 @@ RESOURCES += resources.qrc win32:RC_ICONS = resource/logo.ico macx:ICON = resource/logo.icns + +android:DISTFILES += \ + android/AndroidManifest.xml \ + android/build.gradle \ + android/gradle/wrapper/gradle-wrapper.jar \ + android/gradle/wrapper/gradle-wrapper.properties \ + android/gradlew \ + android/gradlew.bat \ + android/res/values/libs.xml + +ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml new file mode 100644 index 0000000..0792ce8 --- /dev/null +++ b/android/AndroidManifest.xml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/build.gradle b/android/build.gradle new file mode 100644 index 0000000..3087d08 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,62 @@ +buildscript { + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + } +} + +repositories { + google() + jcenter() +} + +apply plugin: 'com.android.application' + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar']) +} + +android { + /******************************************************* + * The following variables: + * - androidBuildToolsVersion, + * - androidCompileSdkVersion + * - qt5AndroidDir - holds the path to qt android files + * needed to build any Qt application + * on Android. + * + * are defined in gradle.properties file. This file is + * updated by QtCreator and androiddeployqt tools. + * Changing them manually might break the compilation! + *******************************************************/ + + compileSdkVersion androidCompileSdkVersion.toInteger() + + buildToolsVersion '28.0.3' + + sourceSets { + main { + manifest.srcFile 'AndroidManifest.xml' + java.srcDirs = [qt5AndroidDir + '/src', 'src', 'java'] + aidl.srcDirs = [qt5AndroidDir + '/src', 'src', 'aidl'] + res.srcDirs = [qt5AndroidDir + '/res', 'res'] + resources.srcDirs = ['resources'] + renderscript.srcDirs = ['src'] + assets.srcDirs = ['assets'] + jniLibs.srcDirs = ['libs'] + } + } + + lintOptions { + abortOnError false + } + + // Do not compress Qt binary resources file + aaptOptions { + noCompress 'rcc' + } +} diff --git a/android/project.properties b/android/project.properties new file mode 100644 index 0000000..a08f37e --- /dev/null +++ b/android/project.properties @@ -0,0 +1 @@ +target=android-21 \ No newline at end of file diff --git a/android/res/drawable-ldpi/icon.png b/android/res/drawable-ldpi/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..f53fe30cf7553fdd4ebcc0d61070c949d833a7c4 GIT binary patch literal 29302 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 literal 0 HcmV?d00001 diff --git a/android/res/values/libs.xml b/android/res/values/libs.xml new file mode 100644 index 0000000..6b1a4a2 --- /dev/null +++ b/android/res/values/libs.xml @@ -0,0 +1,22 @@ + + + + https://download.qt.io/ministro/android/qt5/qt-5.14 + + + + + + + + + + + + + + + + + From 392cefbee43c667ca21244f08f5d97814f282327 Mon Sep 17 00:00:00 2001 From: oldmud0 Date: Fri, 22 May 2020 19:42:47 -0500 Subject: [PATCH 181/268] Bring back translation files Note that there are some strings that had the tr() qualification removed, and also a LOT of strings that were never wrapped with tr() to begin with. It will take some work to bring back i18n support. --- Attorney_Online.pro | 8 + resource/translations/ao_de.qm | Bin 0 -> 23500 bytes resource/translations/ao_de.ts | 1118 ++++++++++++++++++++++++++++++++ resource/translations/ao_en.qm | Bin 0 -> 23 bytes resource/translations/ao_en.ts | 937 ++++++++++++++++++++++++++ resource/translations/ao_es.qm | Bin 0 -> 28457 bytes resource/translations/ao_es.ts | 1048 ++++++++++++++++++++++++++++++ resource/translations/ao_jp.qm | Bin 0 -> 2004 bytes resource/translations/ao_jp.ts | 964 +++++++++++++++++++++++++++ resource/translations/ao_pl.qm | Bin 0 -> 27653 bytes resource/translations/ao_pl.ts | 987 ++++++++++++++++++++++++++++ resource/translations/ao_pt.qm | Bin 0 -> 28605 bytes resource/translations/ao_pt.ts | 977 ++++++++++++++++++++++++++++ resource/translations/ao_ru.qm | Bin 0 -> 21968 bytes resource/translations/ao_ru.ts | 999 ++++++++++++++++++++++++++++ 15 files changed, 7038 insertions(+) create mode 100644 resource/translations/ao_de.qm create mode 100644 resource/translations/ao_de.ts create mode 100644 resource/translations/ao_en.qm create mode 100644 resource/translations/ao_en.ts create mode 100644 resource/translations/ao_es.qm create mode 100644 resource/translations/ao_es.ts create mode 100644 resource/translations/ao_jp.qm create mode 100644 resource/translations/ao_jp.ts create mode 100644 resource/translations/ao_pl.qm create mode 100644 resource/translations/ao_pl.ts create mode 100644 resource/translations/ao_pt.qm create mode 100644 resource/translations/ao_pt.ts create mode 100644 resource/translations/ao_ru.qm create mode 100644 resource/translations/ao_ru.ts diff --git a/Attorney_Online.pro b/Attorney_Online.pro index f04c22a..4b06b22 100644 --- a/Attorney_Online.pro +++ b/Attorney_Online.pro @@ -41,6 +41,14 @@ CONFIG += c++14 RESOURCES += resources.qrc +TRANSLATIONS = resource/translations/ao_en.ts \ + resource/translations/ao_jp.ts \ + resource/translations/ao_de.ts \ + resource/translations/ao_ru.ts \ + resource/translations/ao_es.ts \ + resource/translations/ao_pt.ts \ + resource/translations/ao_pl.ts + win32:RC_ICONS = resource/logo.ico macx:ICON = resource/logo.icns diff --git a/resource/translations/ao_de.qm b/resource/translations/ao_de.qm new file mode 100644 index 0000000000000000000000000000000000000000..6fd250decadf789e64aa740b969b06e29ee0a58d GIT binary patch literal 23500 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 rpRNU2F + + + + AOApplication + + + Disconnected from server. + Vom Server getrennt. + + + + Error connecting to master server. Will try again in %1 seconds. + Fehler bei der Verbindung zum Master Server. Erneuter Versuch in %1 Sekunden. + + + Error connecting to master server. Will try again in %n seconds. + Fehler bei der Verbindung zum Master Server. Erneuter Versuch in %n Sekunden. + + + + There was an error connecting to the master server. +We deploy multiple master servers to mitigate any possible downtime, but the client appears to have exhausted all possible methods of finding and connecting to one. +Please check your Internet connection and firewall, and please try again. + Es gab einen Fehler beim Verbinden zum Master Server. +Wir verwenden mehrere Master Server um Ausfälle zu verhindern, jedoch hat der Client alle Möglichkeiten einen zu finden erschöpft. +Bitte prüfe deine Internetverbindung und Firewall, und versuche es erneut. + + + + Outdated version! Your version: %1 +Please go to aceattorneyonline.com to update. + Version zu alt! Deine Version: %1 +Bitte besuche aceattorneyonline.com für ein Update. + + + + You have been exiled from AO. +Have a nice day. + Du wurdest von AO befreit. +Schönen Urlaub. + + + + Attorney Online 2 + Attorney Online 2 + + + + Loading + Laden + + + + Loading evidence: +%1/%2 + Lade Beweisstücke: +%1/%2 + + + + + Loading music: +%1/%2 + Lade Musik: +%1/%2 + + + + + Loading chars: +%1/%2 + Lade Charaktere: +%1/%2 + + + + You have been kicked from the server. +Reason: %1 + Du wurdest von diesem Server geschmissen. +Grund: %1 + + + + You have been banned from the server. +Reason: %1 + Du wurdest von diesem Server verbannt. +Grund: %1 + + + + You are banned on this server. +Reason: %1 + Du bist von diesem Server verbannt. +Grund: %1 + + + You have been kicked from the server. +Reason: + Du wurdest von diesem Server geschmissen. +Grund: + + + You are banned on this server. +Reason: + Du wurdest von diesem Server verbannt. +Grund: + + + You have been kicked. + Du wurdest rausgeschmissen. + + + You are banned on this server. + Du wurdest verbannt. + + + + AOCaseAnnouncerDialog + + + Case Announcer + Fallansager + + + + Case title: + Fallname: + + + + Defense needed + Verteidiger benötigt + + + + Prosecution needed + Kläger benötigt + + + + Judge needed + Richter benötigt + + + + Jurors needed + Jury benötigt + + + + Stenographer needed + Stenograph benötigt + + + + Witness needed + Zeuge benötigt + + + + AOOptionsDialog + + + Settings + Einstellungen + + + + Gameplay + Spiel + + + + Theme: + Theme: + + + + Sets the theme used in-game. If the new theme changes the lobby's look as well, you'll need to reload the lobby for the changes to take effect, such as by joining a server and leaving it. + Setzt das Theme. Wenn das neue Theme auch das Aussehen der Lobby verändert, must du diese neu laden um die Änderungen zu sehen. + + + + Gives the default value for the in-game 'Custom shownames' checkbox, which in turn determines whether the client should display custom in-character names. + Setzt den Standardwerd für den eigenen Anzeigenamen. + + + + Sets the default volume for music. + Standardlautstärke für die Musik. + + + + Sets the default volume for SFX sounds, like interjections or other character sound effects. + Standardlautstärke für Soundeffekte. + + + + IC Log + Log + + + + Colorful IC log: + Farbiges Log: + + + + Enables colored text in the log. + Aktiviert farbigen Text im Log. + + + + Only inline coloring: + Nur in-Zeilen Farben: + + + + Only inline coloring will be shown such as <>,|| etc. + Nur die in-Zeilen Farben wie <>,|| etc. werden gezeigt. + + + + Mirror IC log: + Log spiegeln: + + + + IC log will mirror the IC box. Meaning that if somebody gets interrupted nobody will know what they wanted to say. Enable for a more realistic experience. + Das Log spiegelt die Nachrichten. Bedeutet dass wenn jemand unterbrochen wird, kann man nicht sehen was derjenige sagen wollte. Für ein realistischeres Spielerlebnis. + + + + Log goes downwards: + Verlauf geht nach unten: + + + + If ticked, new messages will appear at the bottom (like the OOC chatlog). The traditional (AO1) behaviour is equivalent to this being unticked. + Wenn angehakt werden neue Nachrichten unten erscheinen (wie beim OOC). Das traditionelle (AO1) Verhalten wäre nicht angehakt. + + + + Log length: + Länge: + + + + The amount of messages the IC chatlog will keep before deleting older messages. A value of 0 or below counts as 'infinite'. + Die Menge an Nachrichten die aufgehoben werden bevor alte gelöscht werden. 0 bedeutet unendlich. + + + + Default username: + Standard Benutzername: + + + + Your OOC name will be automatically set to this value when you join a server. + Dein OOC Name wird automatisch auf dies gesetzt. + + + + Custom shownames: + Eigener Anzeigename: + + + Gives the default value for the in-game 'Custom shownames' tickbox, which in turn determines whether the client should display custom in-character names. + Standardwert für die Anzeigename Box, welche den In-Charakter Namen bestimmt. + + + + Backup MS: + Rückfall MS: + + + + If the built-in server lookups fail, the game will try the address given here and use it as a backup master server address. + Wenn dereingebaute Master Server fehlschlägt, wird das Spiel diesen hier verwenden. + + + + Discord: + Discord: + + + + Allows others on Discord to see what server you are in, what character are you playing, and how long you have been playing for. + Erlaubt anderen auf Discord zu sehen auf welchem Server du spielst, welchen Charakter du spielst und wie lange. + + + + Allow Shake/Flash: + Schütteln/Geistesblitz erlauben: + + + + Allows screenshaking and flashing. Disable this if you have concerns or issues with photosensitivity and/or seizures. + Erlaubt schütteln des Bildschirms und weiße Blitze. Deaktiviere dies falls du Bedenken wegen Photosensitivität hast. + + + + Language: + Sprache: + + + + Sets the language if you don't want to use your system language. + Setzte die Sprache falls du nicht die Systemsprache verwenden möchtest. + + + + Slower text speed: + Langsamerer Text: + + + + Set the text speed to be the same as the AA games. + Setzt den Text auf die gleiche Geschwindigkeit wie in den AA Spielen. + + + + Blip delay on punctuations: + Blip Pausen bei Satzzeichen: + + + + Punctuation delay modifier. Enable it for the blips to slow down on punctuations. + Aktivieren damit die Blips bei Satzzeichen langsamer werden. + + + + Callwords + Alarmwörter + + + + <html><head/><body>Enter as many callwords as you would like. These are case insensitive. Make sure to leave every callword in its own line!<br>Do not leave a line with a space at the end -- you will be alerted everytime someone uses a space in their messages.</body></html> + <html><head/><body>Gib so viele Alarmwörter ein wie du möchtest. Groß/Kleinschreibung ist egal. Für jede Wort nur eine Zeile!<br>Bitte keine leere Zeile am Ende -- du bekommst sonst bei jeder Nachricht einen Alarm.</body></html> + + + + Audio + Audio + + + + Audio device: + Audiogerät: + + + + Sets the audio device for all sounds. + Setzt das Audiogerät für all Geräusche. + + + + Music: + Musik: + + + Sets the music's default volume. + Setzt die Musiklautstärke. + + + + SFX: + SFX: + + + Sets the SFX's default volume. Interjections and actual sound effects count as 'SFX'. + Setzt die Lautstärke der Soundeffekte wie Einsprüche und die Geräusche der Charaktere. + + + + Blips: + Blips: + + + + Sets the volume of the blips, the talking sound effects. + Setzt die Lautstärke der Blips, das ist das Geräusch das die Charaktere beim Reden machen. + + + + Blip rate: + Bliprate: + + + + Sets the delay between playing the blip sounds. + Setzt die Pause zwischen einzelnen Blips. + + + + Blank blips: + Leere Blips: + + + + If true, the game will play a blip sound even when a space is 'being said'. + Wenn angehakt wird das Spiel auch bei einem Leerzeichen einen Blip machen. + + + + Enable Looping SFX: + Wiederholende Soundeffekte: + + + + If true, the game will allow looping sound effects to play on preanimations. + Wenn aktiviert, werden wiederholende Soundeffekte bei den Voranimationen erlaubt. + + + + Kill Music On Objection: + Stoppe Musik bei Einspruch: + + + + If true, the game will stop music when someone objects, like in the actual games. + Hält die Musik an wenn jemand "Einspruch" ruft, wie im echten Spiel. + + + + Casing + Fälle + + + + This server supports case alerts. + Dieser Server unterstützt Fallalarme. + + + + This server does not support case alerts. + Dieser Server unterstützt Fallalarme nicht. + + + + Pretty self-explanatory. + Eigentlich selbsterklärend. + + + + Casing: + Fälle: + + + + If checked, you will get alerts about case announcements. + Wenn angehakt wirst du benachrichtigt wenn ein Fall angekündigt wird. + + + + Defense: + Verteidigung: + + + + If checked, you will get alerts about case announcements if a defense spot is open. + Wenn angehakt wirst du benachrichtigt wenn ein Verteidiger benötigt wird. + + + + Prosecution: + Kläger: + + + + If checked, you will get alerts about case announcements if a prosecutor spot is open. + Wenn angehakt wirst du benachrichtigt wenn ein Kläger benötigt wird. + + + + Judge: + Richter: + + + + If checked, you will get alerts about case announcements if the judge spot is open. + Wenn angehakt wirst du benachrichtigt wenn ein Richter benötigt wird. + + + + Juror: + Jury: + + + + If checked, you will get alerts about case announcements if a juror spot is open. + Wenn angehakt wirst du benachrichtigt wenn eine Jury benötigt wird. + + + + Stenographer: + Stenograph: + + + + If checked, you will get alerts about case announcements if a stenographer spot is open. + Wenn angehakt wirst du benachrichtigt wenn ein Stenograph benötigt wird. + + + + CM: + CM: + + + + If checked, you will appear amongst the potential CMs on the server. + Wenn angehakt wirst du als potentielle CM angezeigt. + + + + Witness: + Zeuge: + + + + If checked, you will appear amongst the potential witnesses on the server. + Wenn angehakt wirst du als potentielle Zeuge angezeigt. + + + + Hosting cases: + Fallleitung: + + + + If you're a CM, enter what cases you are willing to host. + Wenn du CM bist, gib ein welche Fälle du spielen möchtest. + + + + Courtroom + + + Password + Passwort + + + + Spectator + Zuschauer + + + + + Search + Suche + + + + Passworded + Gesperrt + + + + Taken + Benutzt + + + Generating chars: +%1/%2 + Generiere Charaktere: +%1/%2 + + + Generating chars: + + Generiere Charaktere: + + + + + Could not find %1 + Konnte %1 nicht finden + + + + Showname + Anzeigename + + + + Message + Nachricht + + + + OOC Message + OOC Nachricht + + + + Name + Name + + + + Pre + Vor + + + + Flip + Spiegeln + + + Guard + Wache + + + + Disable Modcalls + Deaktiviere Moderatorenrufe + + + + + Casing + Fall + + + + Shownames + Anzeigenamen + + + + No Interrupt + Keine Unterbrechung + + + + White + Weiß + + + + Green + Grün + + + + Red + Rot + + + + Orange + Orange + + + + Blue + Blau + + + + Yellow + Gelb + + + + Music + Musik + + + + Sfx + Sfx + + + + Blips + Blips + + + + Log limit + Verlaufsgrenze + + + + + Server + Server + + + + Change character + Charakter ändern + + + + Reload theme + Aussehen neu laden + + + + Call mod + Moderator rufen + + + + Settings + Einstellungen + + + + A/M + A/M + + + + Preanim + Voranimation + + + + Back to Lobby + Zurück zur Lobby + + + + + You were granted the Disable Modcalls button. + Du hast nun den "Modcall deaktivieren" Knopf. + + + + You have been banned. + Du wurdest verbannt. + + + + Too many arguments to save a case! You only need a filename without extension and the courtroom status. + Zu viele Argumente zum Speichern! Bitte gib nur den Dateinamen ohne Erweiterung und den Saalstatus an. + + + %1 has played a song: %2 + %1 hat ein Lied gespielt: %2 + + + + Rainbow + Regenbogen + + + + Pink + Pink + + + + Cyan + Cyan + + + + % offset + % Abstand + + + You were granted the Guard button. + Dir wurde der Wache Knopf gegeben. + + + This does nohing, but there you go. + Dies bewirkt nichts, aber egal. + + + + This does nothing, but there you go. + Dies bewirkt nichts, aber egal. + + + + You opened the settings menu. + Du hast die Einstellungen geöffnet. + + + + You will now pair up with + Du wirst nun mit + + + + if they also choose your character in return. + gepaart, wenn der andere dies auch tut. + + + + You are no longer paired with anyone. + Du bist nicht mehr gepaart. + + + + Are you sure you typed that well? The char ID could not be recognised. + Hast du dich vertippt? Die ID konnte nicht erkannt werden. + + + + You have set your offset to + Dein Abstand ist auf + + + + Your offset must be between -100% and 100%! + Der Abstand muss zwischen -100% und 100% liegen! + + + + That offset does not look like one. + Das sieht nicht wie ein Abstand aus. + + + + You switched your music and area list. + Du hast zwischen Musik- und Gebitsliste umgeschaltet. + + + + You have forcefully enabled features that the server may not support. You may not be able to talk IC, or worse, because of this. + Du hast Funktionen erzwungen die der Server eventuell nicht unterstützt. Möglicherweise wirst du nicht mehr sprechen können. + + + + Your pre-animations interrupt again. + Deine Voranimation unterbrechen nun Text. + + + + Your pre-animations will not interrupt text. + Deine Voranimation unterbrechen Text nicht. + + + + Couldn't open chatlog.txt to write into. + Konnte chatlog.txt nicht öffnen. + + + + The IC chatlog has been saved. + Der IC Verlauf wurde gespeichert. + + + + You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely the case file you're looking for can't be found in there. + Du hattest keinen 'base/cases' Ordner! Ich hab ihn nun angelegt aber bedenke das er leer sein wird. + + + + You need to give a filename to load (extension not needed)! Make sure that it is in the `base/cases/` folder, and that it is a correctly formatted ini. +Cases you can load: %1 + Du musst einen Dateinamen angeben (ohne .ini). Stelle sicher das er im 'base/cases' Ordner ist und das er korrekt formatiert ist. +Verfügbare Fälle: %1 + + + + Case made by %1. + Fall von %1. + + + + Navigate to %1 for the CM doc. + Gehe zu %1 für das CM Dokument. + + + + Your case "%1" was loaded! + Dein Fall "%1" wurde geladen! + + + You need to give a filename to load (extension not needed)! Make sure that it is in the `base/cases/` folder, and that it is a correctly formatted ini. +Cases you can load: + Du musst einen Dateinamen angeben (ohne .ini). Stelle sicher das er im 'base/cases' Ordner ist und das er korrekt formatiert ist. +Verfügbare Fälle: + + + + Too many arguments to load a case! You only need one filename, without extension. + Zu viele Argumente! Du brauchst nur den Dateinamen, ohne Erweiterung. + + + Case made by + Fall von + + + Navigate to + Gehe zu + + + for the CM doc. + für das CM Dokument. + + + Your case " + Dein Fall " + + + " was loaded! + " wurde geladen! + + + + You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely that you somehow deleted it. + Du hattest keinen 'base/cases' Ordner! Ich hab ihn nun angelegt aber bedenke das er leer sein wird. + + + + You need to give a filename to save (extension not needed) and the courtroom status! + Du musst einen Dateinamen (ohne Erweiterung) angebenn, sowie den Gebietsstatus! + + + Too many arguments to save a case! You only need a filename without extension and the courtroom status! + Zu viele Argumente! Du brauchst nur den Dateinamen, ohne Erweiterung sowie den Gebietsstatus! + + + + Succesfully saved, edit doc and cmdoc link on the ini! + Erfolgreich gespeichert! + + + + Master + Master + + + + Reason: + Grund: + + + + Call Moderator + Moderator rufen + + + + + Error + Fehler + + + + You must provide a reason. + Du musst einen Grund angeben. + + + + The message is too long. + Die Nachricht ist zu lang. + + + Choose.. + Wähle.. + + + + Choose... + Wähle... + + + + Images (*.png) + Bilder (*.png) + + + + Add new evidence... + Neues Beweisstück... + + + + Discord + + Objection! + Einspruch! + + + In Lobby + In Lobby + + + Idle + Untätig + + + In a Server + In einem Server + + + Playing as %1 + Spielt als %1 + + + Spectating + Zuschauend + + + + Lobby + + + Attorney Online 2 + Attorney Online 2 + + + + Name + Name + + + + It doesn't look like your client is set up correctly. +Did you download all resources correctly from tiny.cc/getao, including the large 'base' folder? + Dein Client ist nicht korrekt eingerichtet. +Hast du ALLES von tiny.cc/getao heruntergeladen und entpackt, auch den großen 'base' Ordner? + + + + Version: %1 + Version: %1 + + + + Loading + Laden + + + + Cancel + Abbrechen + + + + <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Cents02<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, Raidensnake + <h2>Attorney Online %1</h2>Der Gerichtsdrama Simulator<p><b>Quelltext:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Leitende Entwicklung:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Cents02<p><b>Danksagungen:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, Raidensnake + + + <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy + <h2>Attorney Online %1</h2>Der Gerichtsdrama Simulator<p><b>Quelltext:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Leitende Entwicklung:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>Danksagungen:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy + + + + Online: %1/%2 + Online: %1/%2 + + + Attorney Online 2 is built using Qt 5.11. + +Lead development: +longbyte1 +OmniTroid + +stonedDiscord +Supporting development: +Fiercy + +UI design: +Ruekasu +Draxirch + +Special thanks: +Unishred +Argoneus +Noevain +Cronnicossy + Attorney Online 2 wurde gemacht mit Qt 5.11. + +Leitende Entwicklung: +longbyte1 +OmniTroid +stonedDiscord + +Unterstützende Entwicklung: +Fiercy + +UI Design: +Ruekasu +Draxirch + +Speziellen Dank: +Unishred +Argoneus +Noevain +Cronnicossy + + + + + Offline + Offline + + + + debug_functions + + + Error: %1 + Fehler: %1 + + + + Error + Fehler + + + + Notice + Hinweis + + + diff --git a/resource/translations/ao_en.qm b/resource/translations/ao_en.qm new file mode 100644 index 0000000000000000000000000000000000000000..9dad8dffceb9623e88f8b96d9cd0caf25574c6fa GIT binary patch literal 23 fcmcE7ks@*G{hX<16=n7(EZlpygMop8iIEWihQJ9+ literal 0 HcmV?d00001 diff --git a/resource/translations/ao_en.ts b/resource/translations/ao_en.ts new file mode 100644 index 0000000..9719319 --- /dev/null +++ b/resource/translations/ao_en.ts @@ -0,0 +1,937 @@ + + + + + AOApplication + + + Disconnected from server. + + + + + Error connecting to master server. Will try again in %1 seconds. + + + + + There was an error connecting to the master server. +We deploy multiple master servers to mitigate any possible downtime, but the client appears to have exhausted all possible methods of finding and connecting to one. +Please check your Internet connection and firewall, and please try again. + + + + + Outdated version! Your version: %1 +Please go to aceattorneyonline.com to update. + + + + + You have been exiled from AO. +Have a nice day. + + + + + Attorney Online 2 + + + + + Loading + + + + + Loading evidence: +%1/%2 + + + + + + Loading music: +%1/%2 + + + + + + Loading chars: +%1/%2 + + + + + You have been kicked from the server. +Reason: %1 + + + + + You have been banned from the server. +Reason: %1 + + + + + You are banned on this server. +Reason: %1 + + + + + AOCaseAnnouncerDialog + + + Case Announcer + + + + + Case title: + + + + + Defense needed + + + + + Prosecution needed + + + + + Judge needed + + + + + Jurors needed + + + + + Stenographer needed + + + + + Witness needed + + + + + AOOptionsDialog + + + Settings + + + + + Gameplay + + + + + Theme: + + + + + Sets the theme used in-game. If the new theme changes the lobby's look as well, you'll need to reload the lobby for the changes to take effect, such as by joining a server and leaving it. + + + + + Gives the default value for the in-game 'Custom shownames' checkbox, which in turn determines whether the client should display custom in-character names. + + + + + Sets the default volume for music. + + + + + Sets the default volume for SFX sounds, like interjections or other character sound effects. + + + + + IC Log + + + + + Colorful IC log: + + + + + Enables colored text in the log. + + + + + Only inline coloring: + + + + + Only inline coloring will be shown such as <>,|| etc. + + + + + Mirror IC log: + + + + + IC log will mirror the IC box. Meaning that if somebody gets interrupted nobody will know what they wanted to say. Enable for a more realistic experience. + + + + + Log goes downwards: + + + + + If ticked, new messages will appear at the bottom (like the OOC chatlog). The traditional (AO1) behaviour is equivalent to this being unticked. + + + + + Log length: + + + + + The amount of messages the IC chatlog will keep before deleting older messages. A value of 0 or below counts as 'infinite'. + + + + + Default username: + + + + + Your OOC name will be automatically set to this value when you join a server. + + + + + Custom shownames: + + + + + Backup MS: + + + + + If the built-in server lookups fail, the game will try the address given here and use it as a backup master server address. + + + + + Discord: + + + + + Allows others on Discord to see what server you are in, what character are you playing, and how long you have been playing for. + + + + + Allow Shake/Flash: + + + + + Allows screenshaking and flashing. Disable this if you have concerns or issues with photosensitivity and/or seizures. + + + + + Language: + + + + + Sets the language if you don't want to use your system language. + + + + + Slower text speed: + + + + + Set the text speed to be the same as the AA games. + + + + + Blip delay on punctuations: + + + + + Punctuation delay modifier. Enable it for the blips to slow down on punctuations. + + + + + Callwords + + + + + <html><head/><body>Enter as many callwords as you would like. These are case insensitive. Make sure to leave every callword in its own line!<br>Do not leave a line with a space at the end -- you will be alerted everytime someone uses a space in their messages.</body></html> + + + + + Audio + + + + + Audio device: + + + + + Sets the audio device for all sounds. + + + + + Music: + + + + + SFX: + + + + + Blips: + + + + + Sets the volume of the blips, the talking sound effects. + + + + + Blip rate: + + + + + Sets the delay between playing the blip sounds. + + + + + Blank blips: + + + + + If true, the game will play a blip sound even when a space is 'being said'. + + + + + Enable Looping SFX: + + + + + If true, the game will allow looping sound effects to play on preanimations. + + + + + Kill Music On Objection: + + + + + If true, the game will stop music when someone objects, like in the actual games. + + + + + Casing + + + + + This server supports case alerts. + + + + + This server does not support case alerts. + + + + + Pretty self-explanatory. + + + + + Casing: + + + + + If checked, you will get alerts about case announcements. + + + + + Defense: + + + + + If checked, you will get alerts about case announcements if a defense spot is open. + + + + + Prosecution: + + + + + If checked, you will get alerts about case announcements if a prosecutor spot is open. + + + + + Judge: + + + + + If checked, you will get alerts about case announcements if the judge spot is open. + + + + + Juror: + + + + + If checked, you will get alerts about case announcements if a juror spot is open. + + + + + Stenographer: + + + + + If checked, you will get alerts about case announcements if a stenographer spot is open. + + + + + CM: + + + + + If checked, you will appear amongst the potential CMs on the server. + + + + + Witness: + + + + + If checked, you will appear amongst the potential witnesses on the server. + + + + + Hosting cases: + + + + + If you're a CM, enter what cases you are willing to host. + + + + + Courtroom + + + Password + + + + + Spectator + + + + + + Search + + + + + Passworded + + + + + Taken + + + + + Could not find %1 + + + + + Showname + + + + + Message + + + + + OOC Message + + + + + Name + + + + + Pre + + + + + Flip + + + + + + Casing + + + + + Shownames + + + + + No Interrupt + + + + + White + + + + + Green + + + + + Red + + + + + Orange + + + + + Blue + + + + + Yellow + + + + + + You were granted the Disable Modcalls button. + + + + + This does nothing, but there you go. + + + + + You need to give a filename to load (extension not needed)! Make sure that it is in the `base/cases/` folder, and that it is a correctly formatted ini. +Cases you can load: %1 + + + + + Case made by %1. + + + + + Navigate to %1 for the CM doc. + + + + + Your case "%1" was loaded! + + + + + Too many arguments to save a case! You only need a filename without extension and the courtroom status. + + + + + + Server + + + + + Back to Lobby + + + + + Rainbow + + + + + Disable Modcalls + + + + + Pink + + + + + Cyan + + + + + % offset + + + + + Music + + + + + Sfx + + + + + Blips + + + + + Log limit + + + + + Change character + + + + + Reload theme + + + + + Call mod + + + + + Settings + + + + + A/M + + + + + Preanim + + + + + You have been banned. + + + + + You opened the settings menu. + + + + + You will now pair up with + + + + + if they also choose your character in return. + + + + + You are no longer paired with anyone. + + + + + Are you sure you typed that well? The char ID could not be recognised. + + + + + You have set your offset to + + + + + Your offset must be between -100% and 100%! + + + + + That offset does not look like one. + + + + + You switched your music and area list. + + + + + You have forcefully enabled features that the server may not support. You may not be able to talk IC, or worse, because of this. + + + + + Your pre-animations interrupt again. + + + + + Your pre-animations will not interrupt text. + + + + + Couldn't open chatlog.txt to write into. + + + + + The IC chatlog has been saved. + + + + + You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely the case file you're looking for can't be found in there. + + + + + Too many arguments to load a case! You only need one filename, without extension. + + + + + You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely that you somehow deleted it. + + + + + You need to give a filename to save (extension not needed) and the courtroom status! + + + + + Succesfully saved, edit doc and cmdoc link on the ini! + + + + + Master + + + + + Reason: + + + + + Call Moderator + + + + + + Error + + + + + You must provide a reason. + + + + + The message is too long. + + + + + Choose... + + + + + Images (*.png) + + + + + Add new evidence... + + + + + Lobby + + + Attorney Online 2 + + + + + Name + + + + + It doesn't look like your client is set up correctly. +Did you download all resources correctly from tiny.cc/getao, including the large 'base' folder? + + + + + Version: %1 + + + + + Loading + + + + + Cancel + + + + + <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Cents02<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, Raidensnake + + + + + Online: %1/%2 + + + + + + Offline + + + + + debug_functions + + + Error: %1 + + + + + Error + + + + + Notice + + + + diff --git a/resource/translations/ao_es.qm b/resource/translations/ao_es.qm new file mode 100644 index 0000000000000000000000000000000000000000..42ca3a006295aa12bbbe5ad28617f6dd55081d1f GIT binary patch literal 28457 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

    W|mC@qaQ1*c4C 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 literal 0 HcmV?d00001 diff --git a/resource/translations/ao_es.ts b/resource/translations/ao_es.ts new file mode 100644 index 0000000..2cad7ce --- /dev/null +++ b/resource/translations/ao_es.ts @@ -0,0 +1,1048 @@ + + + + + AOApplication + + + Disconnected from server. + Desconectado del servidor. + + + + Error connecting to master server. Will try again in %1 seconds. + Error al conectarse a la lista de servidores. Se intentará nuevamente en %1 segundos. + + + + There was an error connecting to the master server. +We deploy multiple master servers to mitigate any possible downtime, but the client appears to have exhausted all possible methods of finding and connecting to one. +Please check your Internet connection and firewall, and please try again. + I translated master servers as "lista de servidores" because literally nobody will understand if i make the literal translation "servidor maestro". And in the end a master server is just a list of servers. Also removed the part about having multiple master servers, i just don't think the average user will understand this even if i do a good translation. + Hubo un error al obtener la lista de servidores. Verifique su conexión a Internet y firewall, y vuelva a intentarlo. + + + + Outdated version! Your version: %1 +Please go to aceattorneyonline.com to update. + ¡Versión desactualizada! Su versión: %1 +Ingrese a aceattorneyonline.com para actualizar. + + + + You have been exiled from AO. +Have a nice day. + Has sido exiliado de AO. +Que tengas un buen día. + + + + Attorney Online 2 + + + + + Loading + Cargando + + + + Loading evidence: +%1/%2 + Cargando evidencia: +%1/%2 + + + + + Loading music: +%1/%2 + Cargando música: +%1/%2 + + + + + Loading chars: +%1/%2 + Cargando personajes: +%1/%2 + + + + You have been kicked from the server. +Reason: %1 + Has sido expulsado del servidor. +Razón: %1 + + + + You have been banned from the server. +Reason: %1 + Has sido bloqueado de este servidor. +Razón: %1 + + + + You are banned on this server. +Reason: %1 + Has sido bloqueado en este servidor. +Razón: %1 + + + You have been kicked from the server. +Reason: + Has sido expulsado del servidor. +Razón: + + + You are banned on this server. +Reason: + Has sido bloqueado en este servidor. +Razón: + + + + AOCaseAnnouncerDialog + + + Case Announcer + Anunciar caso + + + + Case title: + Título del caso: + + + + Defense needed + Se necesita abogado + + + + Prosecution needed + Se necesita fiscal + + + + Judge needed + Se necesita juez + + + + Jurors needed + Se necesita jurado + + + + Stenographer needed + Se necesita taquígrafo + + + + Witness needed + Se necesita testigo + + + + AOOptionsDialog + + + Settings + Ajustes + + + + Gameplay + Jugabilidad + + + + Theme: + Tema visual: + + + + Sets the theme used in-game. If the new theme changes the lobby's look as well, you'll need to reload the lobby for the changes to take effect, such as by joining a server and leaving it. + Establece el tema visual utilizado en el juego. Si el nuevo tema también cambia el aspecto del lobby, deberá volver a cargar el lobby para que los cambios surtan efecto, como unirse a un servidor y volver al lobby. + + + + Log goes downwards: + Invertir historial IC: + + + + If ticked, new messages will appear at the bottom (like the OOC chatlog). The traditional (AO1) behaviour is equivalent to this being unticked. + Si está marcado, los nuevos mensajes aparecerán en la parte inferior (como el chat OOC). + + + + Log length: + Limite del historial: + + + + The amount of messages the IC chatlog will keep before deleting older messages. A value of 0 or below counts as 'infinite'. + La cantidad de mensajes que mantendrá el historial del chat IC antes de eliminar mensajes más antiguos. 0 significa 'infinito'. + + + + Default username: + Usuario predeterminado: + + + + Your OOC name will be automatically set to this value when you join a server. + Su nombre OOC se establecerá automáticamente a este cuando se una a un servidor. + + + + Custom shownames: + Mostrar nombres: + + + Gives the default value for the in-game 'Custom shownames' tickbox, which in turn determines whether the client should display custom in-character names. + Activa la casilla 'Mostrar nombres' de forma predeterminada en el juego, que a su vez determina si el cliente debe mostrar nombres personalizados en los personajes. + + + + Backup MS: + Master SV de respaldo: + + + + If the built-in server lookups fail, the game will try the address given here and use it as a backup master server address. + Si la lista de servidores predeterminada falla, el juego probará la dirección proporcionada aquí. + + + + Discord: + Discord: + + + + Allows others on Discord to see what server you are in, what character are you playing, and how long you have been playing for. + Permite a otros en Discord ver en qué servidor estás, qué personaje juegas y cuánto tiempo has estado jugando. + + + + Allow Shake/Flash: + Permitir Shake/Flash: + + + + Allows screenshaking and flashing. Disable this if you have concerns or issues with photosensitivity and/or seizures. + Permite el movimiento de la pantalla y el parpadeo. Desactive esto si tiene inquietudes o problemas con la fotosensibilidad y/o convulsiones. + + + + Language: + Idioma: + + + + Sets the language if you don't want to use your system language. + Establece el idioma si no desea utilizar el idioma de su sistema. + + + + Punctuation delay modifier. Enable it for the blips to slow down on punctuations. + Habilítelo para agregar una pequeña pausa en los signos de puntuación. + + + + Callwords + Palabras clave + + + + <html><head/><body>Enter as many callwords as you would like. These are case insensitive. Make sure to leave every callword in its own line!<br>Do not leave a line with a space at the end -- you will be alerted everytime someone uses a space in their messages.</body></html> + <html><head/><body>Ingrese tantas palabras de llamada como desee.<br>Esto no distingue entre mayúsculas y minúsculas. ¡Asegúrese de dejar cada palabra en su propia línea!<br>No deje una línea con un espacio al final; recibirá una alerta cada vez que alguien use un espacio en sus mensajes.</body></html> + + + + Audio + Audio + + + + Audio device: + Dispositivo: + + + + Sets the audio device for all sounds. + Establece el dispositivo de audio. + + + + Music: + Música: + + + Sets the music's default volume. + Establece el volumen predeterminado de la música. + + + + SFX: + SFX: + + + Sets the SFX's default volume. Interjections and actual sound effects count as 'SFX'. + Establece el volumen predeterminado de SFX. Las interjecciones y los efectos de sonido reales cuentan como 'SFX'. + + + + Gives the default value for the in-game 'Custom shownames' checkbox, which in turn determines whether the client should display custom in-character names. + Activa la casilla 'Mostrar nombres' de forma predeterminada en el juego, que a su vez determina si el cliente debe mostrar nombres personalizados en los personajes. + + + + Slower text speed: + Texto más lento: + + + + Set the text speed to be the same as the AA games. + La velocidad del texto será la misma que en los juegos de AA. + + + + Blip delay on punctuations: + Retraso en puntuación: + + + + Sets the default volume for music. + Establece el volumen predeterminado de la música. + + + + Sets the default volume for SFX sounds, like interjections or other character sound effects. + Establece el volumen predeterminado para sonidos SFX, como las interjecciones y otros efectos de sonido de personajes. + + + + Blips: + Blips: + + + + Sets the volume of the blips, the talking sound effects. + Establece el volumen de los blips, el sonido al hablar. + + + + Blip rate: + Tasa de blips: + + + + Sets the delay between playing the blip sounds. + Establece el retraso entre la reproducción de los sonidos blip. + + + + Blank blips: + Blips en blanco: + + + + If true, the game will play a blip sound even when a space is 'being said'. + Si está marcada, el juego reproducirá un sonido blip incluso cuando se 'dice' un espacio. + + + + Enable Looping SFX: + Habilitar repetición de SFX: + + + + If true, the game will allow looping sound effects to play on preanimations. + Si está habilitado, el juego permitirá que se reproduzcan efectos de sonido en bucle en preanimaciones. + + + + Kill Music On Objection: + Parar la música al objetar: + + + + If true, the game will stop music when someone objects, like in the actual games. + Si está habilitado, el juego detendrá la música cuando alguien haga una objeción, como en los juegos. + + + + Casing + Caso + + + + This server supports case alerts. + Este servidor admite alertas de casos. + + + + This server does not support case alerts. + Este servidor no admite alertas de casos. + + + + Pretty self-explanatory. + Bastante autoexplicativo. + + + + Casing: + Caso: + + + + If checked, you will get alerts about case announcements. + Si está marcado, recibirá anuncios de casos. + + + + Defense: + Abogado: + + + + If checked, you will get alerts about case announcements if a defense spot is open. + Si está marcado, recibirá alertas sobre anuncios de casos si hay un lugar de abogado libre. + + + + Prosecution: + Fiscal: + + + + If checked, you will get alerts about case announcements if a prosecutor spot is open. + Si está marcada, recibirá alertas sobre anuncios de casos si hay un puesto de fiscal libre. + + + + Judge: + Juez: + + + + If checked, you will get alerts about case announcements if the judge spot is open. + Si está marcado, recibirá alertas sobre anuncios de casos si el puesto de juez está libre. + + + + Juror: + Jurado: + + + + If checked, you will get alerts about case announcements if a juror spot is open. + Si está marcado, recibirá alertas sobre anuncios de casos si hay un puesto de jurado libre. + + + + Stenographer: + Taquígrafo: + + + + If checked, you will get alerts about case announcements if a stenographer spot is open. + Si está marcado, recibirá alertas sobre anuncios de casos si hay un lugar de taquígrafo libre. + + + + CM: + CM: + + + + If checked, you will appear amongst the potential CMs on the server. + Si está marcado, aparecerá entre los posibles CM en el servidor. + + + + Witness: + Testigo: + + + + If checked, you will appear amongst the potential witnesses on the server. + Si está marcado, aparecerá entre los posibles testigos en el servidor. + + + + Hosting cases: + Casos: + + + + If you're a CM, enter what cases you are willing to host. + Si eres un CM, ingresa qué casos estás dispuesto a organizar. + + + + IC Log + + + + + Only inline coloring will be shown such as <>,|| etc. + Solo se mostrará el color en línea, como <>, ||, etc. + + + + IC log will mirror the IC box. Meaning that if somebody gets interrupted nobody will know what they wanted to say. Enable for a more realistic experience. + El registro de IC reflejará el chat In-Character. Lo que significa que si alguien es interrumpido, nadie sabrá lo que se iba a decir. Habilitar para una experiencia más realista. + + + IC log will mirror the IC box. Meaning that if somebody gets interrupted nobody will know what they wanted to say. Enable for a more realistic experience + El registro de IC reflejará el chat In-Character. Lo que significa que si alguien es interrumpido, nadie sabrá lo que se iba a decir. Habilitar para una experiencia más realista. + + + + Colorful IC log: + Log IC colorido: + + + + Enables colored text in the log. + Habilita texto con color en el log. + + + + Only inline coloring: + Solo coloración en línea: + + + Only inline coloring will be shown such as <>,|| etc + Solo se mostrará el color en línea, como <>, ||, etc. + + + + Mirror IC log: + IC log refleja interrupciones: + + + IC log will mirror the IC box. Meaning that if somebody gets interupted nobody will know what they wanted to say. Enable for a more realistic expierence + El registro de IC reflejará el chat In-Character. Lo que significa que si alguien es interrumpido, nadie sabrá lo que se iba a decir. Habilitar para una experiencia más realista. + + + + Courtroom + + + Password + Contraseña + + + + Spectator + Espectador + + + + + Search + Buscar + + + + Passworded + A translation wouldn't fit because of the shitty theme system. + + + + + Taken + En uso + + + + Could not find %1 + No se pudo encontrar %1 + + + Generating chars: +%1/%2 + Generando personajes: +%1/%2 + + + Generating chars: + + Generando personajes: + + + + + Showname + A translation wouldn't fit because of the shitty theme system. + + + + + Message + Mensaje + + + + Name + Nombre + + + + Pre + A translation wouldn't fit because of the shitty theme system. + + + + + Flip + A translation wouldn't fit because of the shitty theme system. + + + + Guard + Guardia + + + + + Casing + This could be translated as 'caso' and it wouldn't get cut, but there are so many other buttons that can't be translated on the courtroom window that might as well leave this also untranslated so it's at least consistent. + + + + + Shownames + A translation wouldn't fit because of the shitty theme system. + + + + + No Interrupt + A translation wouldn't fit because of the shitty theme system. + + + + + White + Blanco + + + + Green + Verde + + + + Red + Rojo + + + + Orange + Naranja + + + + Blue + Azul + + + + Yellow + Amarillo + + + + Rainbow + Arcoíris + + + + Pink + Rosado + + + + Cyan + Cian + + + + % offset + % desplazamiento + + + + Music + + + + + Sfx + + + + + Blips + + + + + Log limit + + + + + Change character + + + + + Reload theme + + + + + Call mod + + + + + Settings + + + + + A/M + + + + + Preanim + + + + + Back to Lobby + 'Volver al lobby' got cut, changed to just Lobby + Lobby + + + + + You were granted the Disable Modcalls button. + Se le concedió el botón para deshabilitar llamadas a moderadores. + + + + You have been banned. + Has sido vetado. + + + You were granted the Guard button. + Te ha sido otorgado el botón Guardia. + + + + This does nothing, but there you go. + Esto no hace nada, pero ahí lo tienes. + + + + You opened the settings menu. + Abriste el menú de configuración. + + + + You will now pair up with + Ahora te emparejarás con + + + + if they also choose your character in return. + si ellos también eligen a tu personaje a cambio. + + + + You are no longer paired with anyone. + Ya no estás emparejado con nadie. + + + + Are you sure you typed that well? The char ID could not be recognised. + ¿Estás seguro de que lo escribiste bien? El ID de personaje no pudo ser reconocido. + + + + You have set your offset to + Ha configurado su desplazamiento en + + + + Your offset must be between -100% and 100%! + ¡Su desplazamiento debe estar entre -100% y 100%! + + + + That offset does not look like one. + Ese desplazamiento no se parece a uno. + + + + You switched your music and area list. + Cambiaste tu lista de música y área. + + + + You have forcefully enabled features that the server may not support. You may not be able to talk IC, or worse, because of this. + Ha habilitado forzosamente funciones que el servidor puede no admitir. Es posible que no pueda hablar IC, o peor, debido a esto. + + + + Your pre-animations interrupt again. + Sus pre-animaciones interrumpen de nuevo. + + + + Your pre-animations will not interrupt text. + Sus pre-animaciones no interrumpirán el texto. + + + + Couldn't open chatlog.txt to write into. + No se pudo abrir chatlog.txt para escribir. + + + + The IC chatlog has been saved. + El chat IC se ha guardado. + + + + You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely the case file you're looking for can't be found in there. + ¡No tienes una carpeta `base/cases /`! Ha sido creada para ti. Pero debido a que no existia la carpeta, tampoco habían casos guardados ahí. + + + + You need to give a filename to load (extension not needed)! Make sure that it is in the `base/cases/` folder, and that it is a correctly formatted ini. +Cases you can load: %1 + ¡Debe dar un nombre de archivo para cargar (no se necesita extensión)! Asegúrese de que esté en la carpeta `base/cases/` y de que tenga el formato correcto. +Casos que puede cargar: %1 + + + + Case made by %1. + Caso hecho por %1. + + + + Navigate to %1 for the CM doc. + Navegue a %1 para el documento del CM. + + + + Your case "%1" was loaded! + Su caso "%1" fue cargado! + + + You need to give a filename to load (extension not needed)! Make sure that it is in the `base/cases/` folder, and that it is a correctly formatted ini. +Cases you can load: + ¡Debe dar un nombre de archivo para cargar (no se necesita extensión)! Asegúrese de que esté en la carpeta `base/cases/` y de que tenga el formato correcto. +Casos que puede cargar: + + + + Too many arguments to load a case! You only need one filename, without extension. + ¡Demasiados argumentos para cargar un caso! Solo necesita un nombre de archivo, sin extensión. + + + Case made by + Caso hecho por + + + Navigate to + Navegue a + + + for the CM doc. + para el documento de CM. + + + Your case " + Su caso " + + + " was loaded! + " fue cargado! + + + + You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely that you somehow deleted it. + ¡No tienes una carpeta `base/cases /`! Fue creada para ti. + + + + You need to give a filename to save (extension not needed) and the courtroom status! + ¡Debe dar un nombre de archivo para guardar (no se necesita la extensión) y el estado de la sala del tribunal! + + + Too many arguments to save a case! You only need a filename without extension and the courtroom status! + why two exclamations, seems excesive. + ¡Demasiados argumentos para salvar un caso! Solo necesita un nombre de archivo sin extensión y el estado de la sala del tribunal. + + + + Succesfully saved, edit doc and cmdoc link on the ini! + ¡Guardado con éxito, puede editar el doc y doc link en el archivo ini! + + + + Master + + + + + + Server + + + + + OOC Message + Mensaje OOC + + + + Disable Modcalls + + + + + Too many arguments to save a case! You only need a filename without extension and the courtroom status. + ¡Demasiados argumentos para salvar un caso! Solo necesita un nombre de archivo sin extensión y el estado de la sala del tribunal. + + + + Reason: + Razón: + + + + Call Moderator + Llamar Moderador + + + + + Error + Error + + + + You must provide a reason. + Debes proporcionar una razón. + + + + The message is too long. + El mensaje es muy largo. + + + + Choose... + Elegir... + + + + Images (*.png) + Imágenes (* .png) + + + + Add new evidence... + Añadir nueva evidencia... + + + + Lobby + + + Attorney Online 2 + + + + + Name + Nombre + + + + It doesn't look like your client is set up correctly. +Did you download all resources correctly from tiny.cc/getao, including the large 'base' folder? + No parece que su cliente esté configurado correctamente. +¿Descargó todos los recursos correctamente desde tiny.cc/getao, incluida la gran carpeta 'base'? + + + + Version: %1 + Versión: %1 + + + + Loading + Cargando + + + + Cancel + Cancelar + + + + <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Cents02<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, Raidensnake + <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Cents02<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, Raidensnake + + + <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy + <h2>Attorney Online %1</h2>El simulador de drama legal<p><b>Código fuente:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https: //github.com/AttorneyOnline/AO2-Client</a><p><b>Desarrollo mayor:</b> <br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>Agradecimiento especial:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (diseño de interfaz de usuario), Draxirch (diseño de interfaz de usuario), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy + + + + Online: %1/%2 + En línea: %1/%2 + + + + + Offline + Fuera de línea + + + + debug_functions + + + Error: %1 + + + + + Error + + + + + Notice + In spanish it would be "Aviso", but i believe it's going to be more useful for bug reports to not translate any debug string. + + + + diff --git a/resource/translations/ao_jp.qm b/resource/translations/ao_jp.qm new file mode 100644 index 0000000000000000000000000000000000000000..e4fb562afc050d239016969576561640e9f3b81b GIT binary patch literal 2004 zcmai#YiJx*6vt0zXJ#LDQ?!=mLnz~iKp%E{QjwOmU-D>ebhE3QNLob9?9R<(>||z{ z-Ax}_klG3wAEiN3p;S#uB6`a ze;-hW4lj_;fO4SMBiRw<60QPJAwm3Ckr%tS5dTqh<1FP1 zZPC=57QK&0*&Fwg&WwI@Zkqg0EuWl|NUt^hJL7ZT6QoXr=q`dca1m$I8zb}pDqZ1} zs~eVMhUq@uo@p->Y%8yqEZ14)3)bL=coqM^R80s;(4ZCCU=w|B<~H}=veEKGx>rob zTH7|YZf@Y&^6IwS&r3S4t~s(1%V18PEnzxdu?{Y2%EKHk7p?r=9bf;7@EWOYPHfO5(z(qXs28DN}lTu2f^M$YdTNcVNdQ6 z9OdG8ho0Y~m0T_5=5qT5vPi8iT%rV35unm|mP2xfU1kF2KKvCg;&qB+hOT3MFW?B* zGt@XGD^YoJI3DmKp`*J7mNI%*+c|(wnUV%erR>z-By+zYsb_eYO_XQ*H%tz=U;N+SEO)o2;m< zU7sj8<~o5#1b@P5zn)y9_UOeD6ID?5w=CzBV8aS5<-T~fhhuVD9~LcU1Se@JD>%hT zHRI`yDPpBMzt9t&5P5k&HwtHU%gMQW1+hu58ypK|nW(C2wb5>4y@UG%PVy@sKRv;r zXm5e#OAU6OG*VZ!{voR*N3^T{#P

  • + + + + AOApplication + + + Disconnected from server. + + + + + Error connecting to master server. Will try again in %1 seconds. + + + + + There was an error connecting to the master server. +We deploy multiple master servers to mitigate any possible downtime, but the client appears to have exhausted all possible methods of finding and connecting to one. +Please check your Internet connection and firewall, and please try again. + + + + + Outdated version! Your version: %1 +Please go to aceattorneyonline.com to update. + + + + + You have been exiled from AO. +Have a nice day. + + + + + Attorney Online 2 + + + + + Loading + ロード中 + + + + Loading evidence: +%1/%2 + 証拠がロード中: %1/%2 + + + + + Loading music: +%1/%2 + 音楽がロード中: %1/%2 + + + + + Loading chars: +%1/%2 + キャラがロード中: %1/%2 + + + + You have been kicked from the server. +Reason: %1 + + + + + You have been banned from the server. +Reason: %1 + + + + + You are banned on this server. +Reason: %1 + + + + + AOCaseAnnouncerDialog + + + Case Announcer + + + + + Case title: + + + + + Defense needed + + + + + Prosecution needed + + + + + Judge needed + + + + + Jurors needed + + + + + Stenographer needed + + + + + Witness needed + + + + + AOOptionsDialog + + + Settings + + + + + Gameplay + + + + + Theme: + + + + + Sets the theme used in-game. If the new theme changes the lobby's look as well, you'll need to reload the lobby for the changes to take effect, such as by joining a server and leaving it. + + + + + Gives the default value for the in-game 'Custom shownames' checkbox, which in turn determines whether the client should display custom in-character names. + + + + + Sets the default volume for music. + + + + + Sets the default volume for SFX sounds, like interjections or other character sound effects. + + + + + IC Log + + + + + Colorful IC log: + + + + + Enables colored text in the log. + + + + + Only inline coloring: + + + + + Only inline coloring will be shown such as <>,|| etc. + + + + + Mirror IC log: + + + + + IC log will mirror the IC box. Meaning that if somebody gets interrupted nobody will know what they wanted to say. Enable for a more realistic experience. + + + + + Log goes downwards: + + + + + If ticked, new messages will appear at the bottom (like the OOC chatlog). The traditional (AO1) behaviour is equivalent to this being unticked. + + + + + Log length: + + + + + The amount of messages the IC chatlog will keep before deleting older messages. A value of 0 or below counts as 'infinite'. + + + + + Default username: + + + + + Your OOC name will be automatically set to this value when you join a server. + + + + + Custom shownames: + + + + + Backup MS: + + + + + If the built-in server lookups fail, the game will try the address given here and use it as a backup master server address. + + + + + Discord: + + + + + Allows others on Discord to see what server you are in, what character are you playing, and how long you have been playing for. + + + + + Allow Shake/Flash: + + + + + Allows screenshaking and flashing. Disable this if you have concerns or issues with photosensitivity and/or seizures. + + + + + Language: + + + + + Sets the language if you don't want to use your system language. + + + + + Slower text speed: + + + + + Set the text speed to be the same as the AA games. + + + + + Blip delay on punctuations: + + + + + Punctuation delay modifier. Enable it for the blips to slow down on punctuations. + + + + + Callwords + + + + + <html><head/><body>Enter as many callwords as you would like. These are case insensitive. Make sure to leave every callword in its own line!<br>Do not leave a line with a space at the end -- you will be alerted everytime someone uses a space in their messages.</body></html> + + + + + Audio + + + + + Audio device: + + + + + Sets the audio device for all sounds. + + + + + Music: + 音楽: + + + + SFX: + 効果音: + + + + Blips: + ブリップ: + + + + Sets the volume of the blips, the talking sound effects. + + + + + Blip rate: + + + + + Sets the delay between playing the blip sounds. + + + + + Blank blips: + + + + + If true, the game will play a blip sound even when a space is 'being said'. + + + + + Enable Looping SFX: + + + + + If true, the game will allow looping sound effects to play on preanimations. + + + + + Kill Music On Objection: + + + + + If true, the game will stop music when someone objects, like in the actual games. + + + + + Casing + + + + + This server supports case alerts. + + + + + This server does not support case alerts. + + + + + Pretty self-explanatory. + + + + + Casing: + + + + + If checked, you will get alerts about case announcements. + + + + + Defense: + + + + + If checked, you will get alerts about case announcements if a defense spot is open. + + + + + Prosecution: + + + + + If checked, you will get alerts about case announcements if a prosecutor spot is open. + + + + + Judge: + + + + + If checked, you will get alerts about case announcements if the judge spot is open. + + + + + Juror: + + + + + If checked, you will get alerts about case announcements if a juror spot is open. + + + + + Stenographer: + + + + + If checked, you will get alerts about case announcements if a stenographer spot is open. + + + + + CM: + + + + + If checked, you will appear amongst the potential CMs on the server. + + + + + Witness: + + + + + If checked, you will appear amongst the potential witnesses on the server. + + + + + Hosting cases: + + + + + If you're a CM, enter what cases you are willing to host. + + + + + Courtroom + + + Password + + + + + Spectator + 観客 + + + + + Search + + + + + Passworded + + + + + Taken + + + + + Could not find %1 + + + + + Showname + + + + + Message + + + + + Name + 名前 + + + + Pre + + + + + Flip + フリップ + + + Guard + ガード + + + + + Casing + + + + + Shownames + + + + + No Interrupt + + + + + White + + + + + Green + + + + + Red + + + + + Orange + オレンジ + + + + Blue + + + + + Yellow + 黄色 + + + + This does nothing, but there you go. + + + + + You need to give a filename to load (extension not needed)! Make sure that it is in the `base/cases/` folder, and that it is a correctly formatted ini. +Cases you can load: %1 + + + + + Case made by %1. + + + + + Navigate to %1 for the CM doc. + + + + + Your case "%1" was loaded! + + + + + + Server + + + + + Back to Lobby + ロビーに戻る + + + + Rainbow + + + + + OOC Message + + + + + Disable Modcalls + + + + + Pink + ピンク + + + + Cyan + シアン + + + + % offset + + + + + Music + 音楽 + + + + Sfx + 効果音 + + + + Blips + ブリップ + + + + Log limit + + + + + Change character + + + + + Reload theme + + + + + Call mod + + + + + Settings + + + + + A/M + + + + + Preanim + + + + + + You were granted the Disable Modcalls button. + + + + + You have been banned. + + + + + Too many arguments to save a case! You only need a filename without extension and the courtroom status. + + + + + You opened the settings menu. + + + + + You will now pair up with + + + + + if they also choose your character in return. + + + + + You are no longer paired with anyone. + + + + + Are you sure you typed that well? The char ID could not be recognised. + + + + + You have set your offset to + + + + + Your offset must be between -100% and 100%! + + + + + That offset does not look like one. + + + + + You switched your music and area list. + + + + + You have forcefully enabled features that the server may not support. You may not be able to talk IC, or worse, because of this. + + + + + Your pre-animations interrupt again. + + + + + Your pre-animations will not interrupt text. + + + + + Couldn't open chatlog.txt to write into. + + + + + The IC chatlog has been saved. + + + + + You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely the case file you're looking for can't be found in there. + + + + + Too many arguments to load a case! You only need one filename, without extension. + + + + + You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely that you somehow deleted it. + + + + + You need to give a filename to save (extension not needed) and the courtroom status! + + + + + Succesfully saved, edit doc and cmdoc link on the ini! + + + + + Master + マスター + + + + Reason: + + + + + Call Moderator + モデレーターを呼ぶ + + + + + Error + エラー + + + + You must provide a reason. + + + + + The message is too long. + + + + + Choose... + 選択... + + + + Images (*.png) + イメージ (*.png) + + + + Add new evidence... + 新しい証拠を付け加える... + + + + Discord + + Objection! + 意義あり! + + + In Lobby + ロビーでいる + + + Idle + 落ちている + + + In a Server + サーバーでいます + + + Spectating + 観客している + + + + Lobby + + + Attorney Online 2 + + + + + Name + 名前 + + + + It doesn't look like your client is set up correctly. +Did you download all resources correctly from tiny.cc/getao, including the large 'base' folder? + + + + + Version: %1 + + + + + Loading + ロード中 + + + + Cancel + キャンセル + + + + <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Cents02<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, Raidensnake + + + + + Online: %1/%2 + + + + + + Offline + オフライン + + + + debug_functions + + + Error: %1 + エラー: %1 + + + + Error + エラー + + + + Notice + 通知 + + + diff --git a/resource/translations/ao_pl.qm b/resource/translations/ao_pl.qm new file mode 100644 index 0000000000000000000000000000000000000000..995a5bc91f08641cd446ecac2e65ce5231e56855 GIT binary patch literal 27653 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 a#kE3#6>mR;MfT-#FKzDV{P9rVrT-6}pI-g| literal 0 HcmV?d00001 diff --git a/resource/translations/ao_pl.ts b/resource/translations/ao_pl.ts new file mode 100644 index 0000000..2662fcf --- /dev/null +++ b/resource/translations/ao_pl.ts @@ -0,0 +1,987 @@ + + + + + AOApplication + + + Disconnected from server. + Odłączono od serwera. + + + + Error connecting to master server. Will try again in %1 seconds. + Błąd podczas łączenia się z głównym serwerem. Spróbuj ponownie za %1 sekundy. + + + + There was an error connecting to the master server. +We deploy multiple master servers to mitigate any possible downtime, but the client appears to have exhausted all possible methods of finding and connecting to one. +Please check your Internet connection and firewall, and please try again. + Odkryto błąd podczas łączenia się z głównym serwerem. +Używamy wielu głównych serwerów, aby zminimalizować każdą możliwą przerwę, ale klient wyczerpał jakąkolwiek możliwość znalezienia i połączenia się z jednym. +Sprawdź swoje połączenie internetowe oraz zaporę ogniową i spróbuj ponownie. + + + + Outdated version! Your version: %1 +Please go to aceattorneyonline.com to update. + Nieaktualna wersja! Twoja wersja: %1 +Udaj się do aceattorneyonline.com, aby zaktualizować. + + + + You have been exiled from AO. +Have a nice day. + Zostałeś wygnany z AO. +Życzymy miłego dnia. + + + + Attorney Online 2 + Prawnik w Internecie 2 + + + + + Loading + Ładowanie + + + + Loading evidence: +%1/%2 + Ładowanie dowodów: +%1/%2 + + + + + Loading music: +%1/%2 + Ładowanie muzyki: +%1/%2 + + + + + Loading chars: +%1/%2 + Ładowanie postaci: +%1/%2 + + + + You have been kicked from the server. +Reason: %1 + Zostałeś wyrzucony z tego serwera. +Powód: %1 + + + + You have been banned from the server. +Reason: %1 + Zostałeś zbanowany z tego serwera. +Powód: %1 + + + + You are banned on this server. +Reason: %1 + Jesteś zbanowany na tym serwerze. +Powód: %1 + + + + AOCaseAnnouncerDialog + + + Case Announcer + Ogłaszacz rozpraw + + + + Case title: + Tytuł rozprawy: + + + + Defense needed + Potrzebny obrońca + + + + Prosecution needed + Potrzebny prokurator + + + + Judge needed + Potrzebny sędzia + + + + Jurors needed + Potrzebny ławnik + + + + Stenographer needed + Potrzebny stenograf + + + + Witness needed + Potrzebny świadek + + + + AOOptionsDialog + + + Settings + Ustawienia + + + + Gameplay + Rozgrywka + + + + Theme: + Motyw: + + + + Sets the theme used in-game. If the new theme changes the lobby's look as well, you'll need to reload the lobby for the changes to take effect, such as by joining a server and leaving it. + Ustawia motyw używany w grze. Jeżeli nowy motyw równiesz zmienia wygląd poczekalni, musisz odświeżyć poczekalnię, aby zmiany zaczęły działać, np. poprzez dołączenie do serwera i wyjście z niego. + + + + Gives the default value for the in-game 'Custom shownames' checkbox, which in turn determines whether the client should display custom in-character names. + + + + + Sets the default volume for music. + + + + + Sets the default volume for SFX sounds, like interjections or other character sound effects. + + + + + IC Log + + + + + Colorful IC log: + + + + + Enables colored text in the log. + + + + + Only inline coloring: + + + + + Only inline coloring will be shown such as <>,|| etc. + + + + + Mirror IC log: + + + + + IC log will mirror the IC box. Meaning that if somebody gets interrupted nobody will know what they wanted to say. Enable for a more realistic experience. + + + + + Log goes downwards: + Dziennik idzie w dół: + + + + If ticked, new messages will appear at the bottom (like the OOC chatlog). The traditional (AO1) behaviour is equivalent to this being unticked. + Jeżeli zaznaczone, nowe wiadomości zaczną się pojawiać na dole (tak jak na czacie OOC). Tradycyjne (AO1) zachowanie jest równoważne do tego bycia nie zaznaczonym. + + + + Log length: + Długość dziennika: + + + + The amount of messages the IC chatlog will keep before deleting older messages. A value of 0 or below counts as 'infinite'. + Ilość wiadomości, jakie czat IC będzie zostawiał zanim usunie starsze wiadomości. Wartośc 0 albo niżej, liczy się jako 'nieskończone'. + + + + Default username: + Domyślna nazwa użytkownika: + + + + Your OOC name will be automatically set to this value when you join a server. + Twoja nazwa OOC będzie ustawiana automatycznie do tej wartości, kiedy dołączysz na serwer. + + + + Custom shownames: + Niestandardowe ksywki: + + + Gives the default value for the in-game 'Custom shownames' tickbox, which in turn determines whether the client should display custom in-character names. + Daje domyślną wartość przyciskowi 'Niestandardowe ksywki', który określa, czy klient powinien pokazywać niestandardowe nazwy IC. + + + + Backup MS: + Kopia zapasowa głównego serwera: + + + + If the built-in server lookups fail, the game will try the address given here and use it as a backup master server address. + Jeśli wbudowane szukanie serwerów zawiedzie, gra spróbuje użyć adresu podanego tutaj i użyje go jako adresu zapasowego głównego serwera. + + + + Discord: + + + + + Allows others on Discord to see what server you are in, what character are you playing, and how long you have been playing for. + Pozwala innym na Discordzie zobaczyć na jakim serwerze się znajdujesz, jaką postać używasz i jak długo grałeś. + + + + Allow Shake/Flash: + Zezwalaj Wstrząśnięcia/Błyśnięcia: + + + + Allows screenshaking and flashing. Disable this if you have concerns or issues with photosensitivity and/or seizures. + Pozwala na wstrząśnięcia ekranu i błyśnięcia. Wyłącz to, jeśli przejmujesz się lub masz problemy z światłoczułością oraz/lub napady padaczkowe. + + + + Language: + Język: + + + + Sets the language if you don't want to use your system language. + Ustawia język, jeśli nie chcesz używać języka systemowego. + + + + Slower text speed: + + + + + Set the text speed to be the same as the AA games. + + + + + Blip delay on punctuations: + + + + + Punctuation delay modifier. Enable it for the blips to slow down on punctuations. + + + + + Callwords + Zawołania + + + + <html><head/><body>Enter as many callwords as you would like. These are case insensitive. Make sure to leave every callword in its own line!<br>Do not leave a line with a space at the end -- you will be alerted everytime someone uses a space in their messages.</body></html> + <html><head/><body>Wpisz tyle zawołań, ile dusza zapragnie. Wielkość liter nie ma znaczenia. Miej na uwadze, aby każde zawołanie było w swojej lini!<br>Nie zostawiaj spacji na końcu -- zostaniesz zaalarmowany za każdym razem, kiedy ktoś użyje spacji w swojej wiadomości.</body></html> + + + + Audio + Dźwięk + + + + Audio device: + Urządzenie dźwiękowe: + + + + Sets the audio device for all sounds. + Ustawia urządzenie dźwiękowe dla wszystkich dźwięków. + + + + Music: + Muzyka: + + + Sets the music's default volume. + Ustawia domyślną głośność muzyki. + + + + SFX: + Efekty dźwiękowe (SFX): + + + Sets the SFX's default volume. Interjections and actual sound effects count as 'SFX'. + Ustawia domyślną głośność efektów dźwiękowych (SFX). Sprzeciwy i same efekty specjalne są zaliczane jako 'SFX'. + + + + Blips: + Blipy: + + + + Sets the volume of the blips, the talking sound effects. + Ustawia głośność blipów, efektów dźwiękowych mówienia. + + + + Blip rate: + Szybkość blipów: + + + + Sets the delay between playing the blip sounds. + Ustawia opóźnienie pomiędzy graniem blipów. + + + + Blank blips: + The 'blip' isn't an accurate polish representation of this english word. + Puste blipy: + + + + If true, the game will play a blip sound even when a space is 'being said'. + Jeżeli zaznaczone, gra zagra dźwięk blip za każdym razem spacja 'jest mówiona'. + + + + Enable Looping SFX: + Włącz pętlące się efekty dźwiękowe (SFX): + + + + If true, the game will allow looping sound effects to play on preanimations. + Jeśli zaznaczone, gra zezwoli na pętlące się efekty dźwiękowe (SFX). + + + + Kill Music On Objection: + Przerwij muzykę w czasie sprzeciwu: + + + + If true, the game will stop music when someone objects, like in the actual games. + Jeśli zaznaczone, gra przerwie muzykę, kiedy ktoś sprzeciwi się, tak jak w oryginalnych grach. + + + + Casing + Rozprawy + + + + This server supports case alerts. + Ten serwer wspiera komunikaty rozpraw. + + + + This server does not support case alerts. + Ten serwer nie wspiera komunikatów rozpraw. + + + + Pretty self-explanatory. + Dosyć oczywiste. + + + + Casing: + Rozprawy: + + + + If checked, you will get alerts about case announcements. + Jeżeli zaznaczone, dostaniesz komunikaty o ogłoszeniach rozpraw. + + + + Defense: + Obrona: + + + + If checked, you will get alerts about case announcements if a defense spot is open. + Jeśli zaznaczone, dostaniesz komunikaty o ogłoszeniach rozpraw, jeśli miejsce obrony jest otwarte. + + + + Prosecution: + Prokuratura: + + + + If checked, you will get alerts about case announcements if a prosecutor spot is open. + Jeśli zaznaczone, dostaniesz komunikaty o ogłoszeniach rozpraw, jeśli miejsce prokuratora jest otwarte. + + + + Judge: + Sędzia: + + + + If checked, you will get alerts about case announcements if the judge spot is open. + Jeśli zaznaczone, dostaniesz komunikaty o ogłoszeniach rozpraw, jeśli miejsce sędzi jest otwarte. + + + + Juror: + Ławnik: + + + + If checked, you will get alerts about case announcements if a juror spot is open. + Jeżeli zaznaczone, dostaniesz komunikaty o ogłoszeniach rozpraw, jeśli miejsce ławnika jest otwarte. + + + + Stenographer: + Stenograf: + + + + If checked, you will get alerts about case announcements if a stenographer spot is open. + Jeżeli zaznaczone, dostaniesz komunikaty o ogłoszeniach rozpraw, jeśli miejsce stenografa jest otwarte. + + + + CM: + Zarządca rozpraw (CM): + + + + If checked, you will appear amongst the potential CMs on the server. + Jeśli zaznaczone, pojawisz się wśród potencjalnych zarządców rozpraw (CM) na serwerze. + + + + Witness: + Świadek: + + + + If checked, you will appear amongst the potential witnesses on the server. + Jeżeli zaznaczone, pojawisz się wśród potencjalnych świadków na serwerze. + + + + Hosting cases: + Hostowane rozprawy: + + + + If you're a CM, enter what cases you are willing to host. + Jeżeli jesteś zarządcą rozpraw (CM), wpisz jakie rozprawy jesteś chętny hostowania. + + + + Courtroom + + + Password + Hasło + + + + Spectator + Widz + + + + + Search + Wyszukaj + + + + Passworded + Zahasłowany + + + + Taken + Zajęty + + + + Could not find %1 + Nie znaleziono %1 + + + Generating chars: +%1/%2 + Generowanie postaci: +%1.%2 + + + + Showname + Ksywka + + + + Message + Wiadomość + + + + Name + Nazwa + + + + Pre + przed- + + + + Flip + Odwróć + + + Guard + Na Służbie (mod) + + + + + Casing + Rozprawa + + + + Shownames + Ksywki + + + + No Interrupt + Bez ociągania się + + + + White + Biały + + + + Green + Zielony + + + + Red + Czerwony + + + + Orange + Pomarańczowy + + + + Blue + Niebieski + + + + Yellow + Żółty + + + + This does nothing, but there you go. + To nic nie robi, ale proszę bardzo. + + + + You need to give a filename to load (extension not needed)! Make sure that it is in the `base/cases/` folder, and that it is a correctly formatted ini. +Cases you can load: %1 + Musisz podać nazwę pliku, którego chcesz załadować (rozszerzenie nie potrzebne!) Upewnij się, że jest w folderze `base/cases/` i że jest to poprawnie sformatowane ini. +Rozprawy które możesz załadować: %1 + + + + Case made by %1. + Rozprawa zrobiona przez %1. + + + + Navigate to %1 for the CM doc. + Przejdź do %1, aby dojść do dokumentu CM. + + + + Your case "%1" was loaded! + Twoja rozprawa "%1" została wczytana! + + + + + Server + Serwer + + + + Back to Lobby + Powrót do poczekalni + + + + Rainbow + Tęczowy + + + + OOC Message + + + + + Disable Modcalls + Wyłącz wezwania moda + + + + Pink + Różowy + + + + Cyan + Turkusowy + + + + % offset + % wyrówanie + + + + Music + Muzyka + + + + Sfx + Sfx + + + + Blips + Blipy + + + + Log limit + Limit dziennika + + + + Change character + Zmiana postaci + + + + Reload theme + Odśwież motyw + + + + Call mod + Wezwij moda + + + + Settings + Ustawienia + + + + A/M + O meaning 'Obszar' and M meaning 'Muzyka'. + O/M + + + + Preanim + Sounds weird but I don't know how to translate it other than this. + przed-animacja + + + + + You were granted the Disable Modcalls button. + + + + + You have been banned. + Zostałeś zbanowany. + + + + Too many arguments to save a case! You only need a filename without extension and the courtroom status. + + + + You were granted the Guard button. + Zostałeś obdarzonym przyciskiem Na Służbie. + + + + You opened the settings menu. + Otworzyłeś opcje. + + + + You will now pair up with + Będzie teraz w parze z + + + + if they also choose your character in return. + jeżeli oni również wybiorą ciebie spowrotem. + + + + You are no longer paired with anyone. + Nie jesteś już w parze z kimkolwiek. + + + + Are you sure you typed that well? The char ID could not be recognised. + Czy jesteś pewien, że dobrze to napisałeś? ID postaci nie zostało rozpoznane. + + + + You have set your offset to + Musisz ustawić swoje wyrównanie do + + + + Your offset must be between -100% and 100%! + Twoje wyrównanie musi być między -100%, a 100%! + + + + That offset does not look like one. + To wyrównanie nie wygląda na takie. + + + + You switched your music and area list. + Przełączyłeś swoją listę obszarów i muzyki. + + + + You have forcefully enabled features that the server may not support. You may not be able to talk IC, or worse, because of this. + Włączyłeś funkcje, które ten serwer może nie wspierać. Możliwe że, nie możesz rozmawiać na czacie IC lub gorzej z powodu tego. + + + + Your pre-animations interrupt again. + Twoje przed-animacje przerywają tekst spowrotem. + + + + Your pre-animations will not interrupt text. + Twoje przed-animacje nie będą przerywać tekstu. + + + + Couldn't open chatlog.txt to write into. + Nie można było otworzyć chatlog.txt, aby pisać w nim. + + + + The IC chatlog has been saved. + Dziennik czatu IC został zapisany. + + + + You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely the case file you're looking for can't be found in there. + Nie masz folderu `base/cases/`! Został zrobiony tylko dla ciebie, ale widząc, że ZOSTAŁ zrobiony tylko dla ciebie, prawdopodobnie plik rozpraw, którego szukasz nie został znaleziony tutaj. + + + + Too many arguments to load a case! You only need one filename, without extension. + Zbyt dużo parametrów, aby załadować rozprawę! Potrzebujesz tylko jedną nazwę pliku, bez rozszerzenia nazwy pliku. + + + + You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely that you somehow deleted it. + Nie masz folderu `base/cases/`! Został zrobiony tylko dla ciebie, ale widząc, że ZOSTAŁ zrobiony tylko dla ciebie, prawdopodobnie jakoś usunąłeś go. + + + + You need to give a filename to save (extension not needed) and the courtroom status! + Musisz podać nazwę pliku, aby go zapisać (rozszerzenie nie potrzebne) i status sali sądowej! + + + Too many arguments to save a case! You only need a filename without extension and the courtroom status! + Zbyt dużo parametrów, aby zapisać rozprawę! Potrzebujesz tylko jedną nazwę pliku, bez rozszerzenia nazwy pliku i statusu sali sądowej! + + + + Succesfully saved, edit doc and cmdoc link on the ini! + Zapisano pomyślnie, edytuj dokument i link cmdoc w .ini! + + + + Master + Główny + + + + Reason: + Powód: + + + + Call Moderator + Wezwij Moderatora + + + + + Error + Błąd + + + + You must provide a reason. + Musisz podać przyczynę. + + + + The message is too long. + Ta wiadomość jest za długa. + + + + Choose... + Wybierz... + + + + Images (*.png) + Plik obrazu (*.png) + + + + Add new evidence... + Dodaj nowe dowody... + + + + Lobby + + + Attorney Online 2 + + + + + Name + Nazwa + + + + It doesn't look like your client is set up correctly. +Did you download all resources correctly from tiny.cc/getao, including the large 'base' folder? + Wygłąda na to, że twój klient nie jest ustawiony poprawnie. +Czy pobrałeś wszystkie zasoby poprawnie z tiny.cc/getao, włączając duży folder 'base'? + + + + Version: %1 + Wersja: %1 + + + + Loading + Ładowanie + + + + Cancel + Anuluj + + + + <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Cents02<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, Raidensnake + + + + <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy + <h2>Attorney Online: %1</h2>Symulator dramy sądowej<p><b>Kod żródłowy:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Główny rozwój:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>Szczególne podziękowania:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy + + + + Online: %1/%2 + + + + + + Offline + + + + + debug_functions + + + Error: %1 + Błąd: %1 + + + + Error + Błąd + + + + Notice + Ogłoszenie + + + diff --git a/resource/translations/ao_pt.qm b/resource/translations/ao_pt.qm new file mode 100644 index 0000000000000000000000000000000000000000..242917fff1b18c2741f31d02bb2cd94f27fafc23 GIT binary patch literal 28605 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 literal 0 HcmV?d00001 diff --git a/resource/translations/ao_pt.ts b/resource/translations/ao_pt.ts new file mode 100644 index 0000000..824c81e --- /dev/null +++ b/resource/translations/ao_pt.ts @@ -0,0 +1,977 @@ + + + + + AOApplication + + + Disconnected from server. + Desconectado do servidor. + + + + Error connecting to master server. Will try again in %1 seconds. + Erro ao conectar ao servidor principal. Testando novamente em %1 segundos. + + + + There was an error connecting to the master server. +We deploy multiple master servers to mitigate any possible downtime, but the client appears to have exhausted all possible methods of finding and connecting to one. +Please check your Internet connection and firewall, and please try again. + Ocorreu um erro ao obter a lista de servidores. Verifique sua conexão à Internet e firewall e tente novamente. + + + + Outdated version! Your version: %1 +Please go to aceattorneyonline.com to update. + Versão desatualizada! Sua versão: %1 +Acesse aceattorneyonline.com para atualizar. + + + + You have been exiled from AO. +Have a nice day. + Você foi exilado do Attorney Online. +Tenha um bom dia. + + + + Attorney Online 2 + + + + + Loading + Carregando + + + + + Loading chars: +%1/%2 + Carregando personagens: +%1/%2 + + + + Loading evidence: +%1/%2 + Carregando evidências: +%1/%2 + + + + + Loading music: +%1/%2 + Carregando músicas: +%1/%2 + + + + You have been kicked from the server. +Reason: %1 + Você foi expulso do servidor. +Motivo: %1 + + + + You have been banned from the server. +Reason: %1 + Você foi banido do servidor. +Motivo: %1 + + + + You are banned on this server. +Reason: %1 + Você foi banido neste servidor. +Motivo: %1 + + + + AOCaseAnnouncerDialog + + + Case Announcer + Anunciar caso + + + + Case title: + Título do caso: + + + + Defense needed + Precisa-se de Defesa + + + + Prosecution needed + Precisa-se de Promotor + + + + Judge needed + Precisa-se de Juíz + + + + Jurors needed + Precisa-se de Jurados + + + + Stenographer needed + Precisa-se de Estenógrafo + + + + Witness needed + Precisa-se de Testemunha + + + + AOOptionsDialog + + + Settings + Configurações + + + + Gameplay + Jogabilidade + + + + Theme: + Tema visual: + + + + Sets the theme used in-game. If the new theme changes the lobby's look as well, you'll need to reload the lobby for the changes to take effect, such as by joining a server and leaving it. + Define o tema usado no jogo. Se o novo tema alterar a aparência do lobby, será necessário recarregá-lo para que as alterações tenham efeito, como ingressar em um servidor e deixá-lo. + + + + Log goes downwards: + Log vai para baixo: + + + + If ticked, new messages will appear at the bottom (like the OOC chatlog). The traditional (AO1) behaviour is equivalent to this being unticked. + Removed the part about AO1 behaviour, nobody cares boomer. + Se selecionado, novas mensagens irão aparecer na parte inferior (assim como o chat OOC). + + + + Log length: + Tamanho do log: + + + + The amount of messages the IC chatlog will keep before deleting older messages. A value of 0 or below counts as 'infinite'. + A quantidade de mensagens que o chat do IC manterá antes de excluir as mensagens mais antigas. Um valor igual ou inferior a 0 conta como 'infinito'. + + + + Default username: + Nome de usuário padrão: + + + + Your OOC name will be automatically set to this value when you join a server. + Seu nome OOC será automaticamente definido com esse valor quando você ingressar em um servidor. + + + + Custom shownames: + Nomes personalizados: + + + Gives the default value for the in-game 'Custom shownames' tickbox, which in turn determines whether the client should display custom in-character names. + 'Custom shownames' changed to 'Shownames' because that's the actual name + Fornece o valor padrão para a caixa de seleção 'Shownames' no jogo, que determina se o cliente deve exibir nomes personalizados nos caracteres. + + + + Backup MS: + MS de backup: + + + + If the built-in server lookups fail, the game will try the address given here and use it as a backup master server address. + Se as pesquisas internas do servidor falharem, o jogo tentará o endereço fornecido aqui e o usará como um endereço de servidor principal de backup. + + + + Discord: + + + + + Allows others on Discord to see what server you are in, what character are you playing, and how long you have been playing for. + Permite que outras pessoas no Discord vejam em que servidor você está, qual personagem está jogando e há quanto tempo está jogando. + + + + Allow Shake/Flash: + Permitir Shake/Flash: + + + + Allows screenshaking and flashing. Disable this if you have concerns or issues with photosensitivity and/or seizures. + Permite agitar e piscar. Desative isso se você tiver preocupações ou problemas com fotosensibilidade e/ou convulsões. + + + + Language: + Língua: + + + + Sets the language if you don't want to use your system language. + Define o idioma se você não quiser usar o idioma do sistema. + + + + Punctuation delay modifier. Enable it for the blips to slow down on punctuations. + Habilite para adicionar uma pequena pausa nos sinais de pontuação. + + + + Callwords + Palavras-chave + + + + <html><head/><body>Enter as many callwords as you would like. These are case insensitive. Make sure to leave every callword in its own line!<br>Do not leave a line with a space at the end -- you will be alerted everytime someone uses a space in their messages.</body></html> + <html><head/><body>Digite quantas palavras-chave você desejar. Estes não diferenciam maiúsculas de minúsculas. Certifique-se de deixar cada palavra chave em sua própria linha!<br>Não deixe uma linha com um espaço no final - você será alertado toda vez que alguém usar um espaço em suas mensagens.</body></html> + + + + Audio + Áudio + + + + Audio device: + Dispositivo de áudio: + + + + Sets the audio device for all sounds. + Define o dispositivo de áudio para todos os sons. + + + + Music: + Música: + + + Sets the music's default volume. + Define o volume padrão da música. + + + + SFX: + SFX: + + + Sets the SFX's default volume. Interjections and actual sound effects count as 'SFX'. + Define o volume padrão do SFX. Interjeições e efeitos sonoros reais contam como 'SFX'. + + + + Gives the default value for the in-game 'Custom shownames' checkbox, which in turn determines whether the client should display custom in-character names. + Fornece o valor padrão para a caixa de seleção 'Shownames' no jogo, que determina se o cliente deve exibir nomes personalizados nos caracteres. + + + + Slower text speed: + Texto mais lento: + + + + Set the text speed to be the same as the AA games. + A velocidade do texto será a mesma dos jogos AA. + + + + Blip delay on punctuations: + Atraso na pontuação: + + + + Sets the default volume for music. + Define o volume padrão da música. + + + + Sets the default volume for SFX sounds, like interjections or other character sound effects. + Define o volume padrão para sons SFX, como interjeições ou outros efeitos sonoros de personagens. + + + + Blips: + + + + + Sets the volume of the blips, the talking sound effects. + Define o volume dos blips, os efeitos sonoros de fala. + + + + Blip rate: + Taxa de blip: + + + + Sets the delay between playing the blip sounds. + Define o atraso entre a reprodução dos sons de blip. + + + + Blank blips: + Blips em branco: + + + + If true, the game will play a blip sound even when a space is 'being said'. + Se ativado, o jogo emitirá um sinal sonoro, mesmo quando um espaço estiver sendo "dito". + + + + Enable Looping SFX: + Ative o SFX em loop: + + + + If true, the game will allow looping sound effects to play on preanimations. + Se ativado, o jogo permitirá que efeitos sonoros em loop sejam reproduzidos em pré-animações. + + + + Kill Music On Objection: + Parar a música no protesto: + + + + If true, the game will stop music when someone objects, like in the actual games. + Se ativado, o jogo interrompe a música quando alguém protestar , como nos jogos reais. + + + + Casing + Caso + + + + This server supports case alerts. + Este servidor suporta anúncios de casos. + + + + This server does not support case alerts. + Este servidor não suporta alertas de caso. + + + + Pretty self-explanatory. + Bastante auto-explicativo. + + + + Casing: + Caso: + + + + If checked, you will get alerts about case announcements. + Se marcado, você será alertado quando houverem anúncios de casos. + + + + Defense: + Defesa: + + + + If checked, you will get alerts about case announcements if a defense spot is open. + Se marcado, você receberá alertas sobre os anúncios de casos, se um ponto de defesa estiver aberto. + + + + Prosecution: + Promotor: + + + + If checked, you will get alerts about case announcements if a prosecutor spot is open. + Se marcado, você receberá alertas sobre os anúncios de casos, se uma posição de promotor estiver disponível. + + + + Judge: + Juíz: + + + + If checked, you will get alerts about case announcements if the judge spot is open. + Se marcado, você receberá alertas sobre os anúncios de casos, se o local do juíz: estiver aberto. + + + + Juror: + Jurado: + + + + If checked, you will get alerts about case announcements if a juror spot is open. + Se marcado, você receberá alertas sobre os anúncios de casos, se um local do jurado estiver aberto. + + + + Stenographer: + Estenógrafo: + + + + If checked, you will get alerts about case announcements if a stenographer spot is open. + Se marcado, você receberá alertas sobre anúncios de casos, se um local de estenógrafo estiver aberto. + + + + CM: + CM: + + + + If checked, you will appear amongst the potential CMs on the server. + Se marcado, você aparecerá entre os CMs possíveis no servidor. + + + + Witness: + Testemunha: + + + + If checked, you will appear amongst the potential witnesses on the server. + Se marcado, você aparecerá entre as testemunhas em potencial no servidor. + + + + Hosting cases: + Casos: + + + + If you're a CM, enter what cases you are willing to host. + Se você é um CM, insira os casos que deseja hospedar. + + + + IC Log + + + + + Colorful IC log: + Log IC colorido: + + + + Enables colored text in the log. + Ativa o texto colorido no log. + + + + Only inline coloring: + Somente coloração em linha: + + + + Only inline coloring will be shown such as <>,|| etc. + Somente a coloração em linha será mostrada como <>, ||, etc. + + + + Mirror IC log: + O log IC reflete interrupções: + + + + IC log will mirror the IC box. Meaning that if somebody gets interrupted nobody will know what they wanted to say. Enable for a more realistic experience. + O log IC espelhará o chat IC Significando que se alguém for interrompido, ninguém saberá o que queria dizer. Habilite para uma experiência mais realista. + + + + Courtroom + + + Password + Senha + + + + Spectator + Espectador + + + + + Search + Pesquisar + + + + Passworded + A translation wouldn't fit because of the shitty theme system. + + + + + Taken + Em uso + + + + Could not find %1 + Não foi possível encontrar %1 + + + + Showname + A translation wouldn't fit because of the shitty theme system. + + + + + Message + Mensagem + + + + OOC Message + Mensagem OOC + + + + Name + Nome + + + + Pre + A translation wouldn't fit because of the shitty theme system. + + + + + Flip + A translation wouldn't fit because of the shitty theme system. + + + + + Disable Modcalls + + + + + + Casing + A translation wouldn't fit because of the shitty theme system. + + + + + Shownames + A translation wouldn't fit because of the shitty theme system. + + + + + No Interrupt + A translation wouldn't fit because of the shitty theme system. + + + + + White + Branco + + + + Green + Verde + + + + Red + Vermelho + + + + Orange + Laranja + + + + Blue + Azul + + + + Yellow + Amarelo + + + + Rainbow + Arco Iris + + + + Pink + Rosa + + + + Cyan + Ciano + + + + % offset + % deslocamento + + + + Music + + + + + Sfx + + + + + Blips + + + + + Log limit + + + + + + Server + + + + + Change character + + + + + Reload theme + + + + + Call mod + + + + + Settings + + + + + A/M + + + + + Preanim + + + + + Back to Lobby + A translation wouldn't fit because of the shitty theme system. + Lobby + + + + + You were granted the Disable Modcalls button. + Você recebeu o botão Desativar Modcalls. + + + + You have been banned. + Você foi banido. + + + + This does nothing, but there you go. + Isso não faz nada, mas lá vai você. + + + + You opened the settings menu. + Você abriu o menu de configurações. + + + + You will now pair up with + Agora você vai fazer par com + + + + if they also choose your character in return. + se eles também escolherem seu personagem em troca. + + + + You are no longer paired with anyone. + Você não está mais fazendo par com ninguém. + + + + Are you sure you typed that well? The char ID could not be recognised. + Você tem certeza que você escreveu isso certo? O ID do personagem não pôde ser encontrado. + + + + You have set your offset to + Você definiu seu deslocamento como + + + + Your offset must be between -100% and 100%! + Seu deslocamento deve estar entre -100% e 100%! + + + + That offset does not look like one. + Esse deslocamento não se parece com um. + + + + You switched your music and area list. + Você mudou sua lista de músicas e áreas. + + + + You have forcefully enabled features that the server may not support. You may not be able to talk IC, or worse, because of this. + Você forçou recursos que o servidor pode não suportar. Você pode não conseguir falar de IC, ou pior, por causa disso. + + + + Your pre-animations interrupt again. + Suas pré-animações interrompem novamente. + + + + Your pre-animations will not interrupt text. + Suas pré-animações não interromperão o texto. + + + + Couldn't open chatlog.txt to write into. + Não foi possível abrir o chatlog.txt para gravar. + + + + The IC chatlog has been saved. + O chat do IC foi salvo. + + + + You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely the case file you're looking for can't be found in there. + Você não possui uma pasta `base/cases/`! Foi feito para você, mas, como foi feito para você, provavelmente o arquivo do caso que você está procurando não pode ser encontrado lá. + + + + You need to give a filename to load (extension not needed)! Make sure that it is in the `base/cases/` folder, and that it is a correctly formatted ini. +Cases you can load: %1 + Você precisa fornecer um nome de arquivo para carregar (extensão não necessária)! Verifique se está na pasta `base/cases/` e se é um ini formatado corretamente. +Casos que você pode carregar: %1 + + + + Too many arguments to load a case! You only need one filename, without extension. + Muitos argumentos para carregar um caso! Você só precisa de um nome de arquivo, sem extensão. + + + + Case made by %1. + Caso feito por %1. + + + + Navigate to %1 for the CM doc. + Navegue para %1 para o documento do CM. + + + + Your case "%1" was loaded! + Seu caso "%1" foi carregado! + + + + You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely that you somehow deleted it. + Você não possui uma pasta `base/cases/`! Foi feito para você, mas, como foi feito para você, é provável que você o tenha excluído. + + + + You need to give a filename to save (extension not needed) and the courtroom status! + Você deve fornecer um nome de arquivo para salvar (sem extensão necessária) e o estado do tribunal! + + + + Too many arguments to save a case! You only need a filename without extension and the courtroom status. + Muitos argumentos para salvar um caso! Você só precisa de um nome de arquivo sem extensão e o estado do tribunal. + + + Too many arguments to save a case! You only need a filename without extension and the courtroom status! + Muitos argumentos para salvar um caso! Você só precisa de um nome de arquivo sem extensão e o estado do tribunal. + + + + Succesfully saved, edit doc and cmdoc link on the ini! + Salvo com sucesso, você pode editar o documento e o link do documento no arquivo ini! + + + + Master + + + + + Reason: + Razão: + + + + Call Moderator + Chamar um Moderador + + + + + Error + Erro + + + + You must provide a reason. + Você deve fornecer um motivo. + + + + The message is too long. + A mensagem é muito longa. + + + + Choose... + Escolha... + + + + Images (*.png) + Imagens (* .png) + + + + Add new evidence... + Adicionar nova evidência... + + + + Lobby + + + Attorney Online 2 + + + + + Name + Nome + + + + It doesn't look like your client is set up correctly. +Did you download all resources correctly from tiny.cc/getao, including the large 'base' folder? + Seu cliente não parece estar configurado corretamente. +Você baixou todos os recursos corretamente do tiny.cc/getao, incluindo a grande pasta 'base'? + + + + Version: %1 + Versão: %1 + + + + + Offline + Offline + + + + Loading + Carregando + + + + Cancel + Cancelar + + + + <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Cents02<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, Raidensnake + <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Cents02<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, Raidensnake + + + <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy + <h2>Attorney Online %1</h2>O simulador de drama jurídico<p><b>Código fonte:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Desenvolvimento principal:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>Agradecimentos especiais:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy + + + + Online: %1/%2 + Online: %1/%2 + + + + debug_functions + + + Error: %1 + + + + + Error + + + + + Notice + + + + diff --git a/resource/translations/ao_ru.qm b/resource/translations/ao_ru.qm new file mode 100644 index 0000000000000000000000000000000000000000..19bf0a957fcb88742b350b2e65e145a30fea5687 GIT binary patch literal 21968 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 QY+drw>U!ga_Qb0H1p@dxkN^Mx literal 0 HcmV?d00001 diff --git a/resource/translations/ao_ru.ts b/resource/translations/ao_ru.ts new file mode 100644 index 0000000..93a3295 --- /dev/null +++ b/resource/translations/ao_ru.ts @@ -0,0 +1,999 @@ + + + + + AOApplication + + + Disconnected from server. + Соединение с сервером прервано. + + + + Error connecting to master server. Will try again in %1 seconds. + Ошибка соединения с главным сервером. Попытка пересоединения будет через %1 с. + + + + There was an error connecting to the master server. +We deploy multiple master servers to mitigate any possible downtime, but the client appears to have exhausted all possible methods of finding and connecting to one. +Please check your Internet connection and firewall, and please try again. + Произошла ошибка соединения с главным сервером. +Пожалуйста, проверьте ваши Интернет-соединение, настройки браундмауэра, и попробуйте перезайти. + + + + Outdated version! Your version: %1 +Please go to aceattorneyonline.com to update. + Устаревшая версия! У вас установлена %1 +Проследуйте на сайт aceattorneyonline.com для обновления. + + + + You have been exiled from AO. +Have a nice day. + Из AO вас отправили в жизнь. +Хорошего дня. + + + + Attorney Online 2 + Attorney Online 2 + + + + Loading + Загрузка + + + + Loading evidence: +%1/%2 + Загрузка вещдоков: +%1/%2 + + + + + Loading music: +%1/%2 + Загрузка музыки: +%1/%2 + + + + + Loading chars: +%1/%2 + Загрузка персонажей: +%1/%2 + + + + You have been kicked from the server. +Reason: %1 + Вас выпнули с сервера. +Причина: %1 + + + + You have been banned from the server. +Reason: %1 + + + + + You are banned on this server. +Reason: %1 + Вас отправили в баню. +Причина: %1 + + + You have been kicked from the server. +Reason: + Вас выпнули с сервера. +Причина: + + + You are banned on this server. +Reason: + Вас отправили в баню. +Причина: + + + + AOCaseAnnouncerDialog + + + Case Announcer + Материалы дела + + + + Case title: + Название: + + + + Defense needed + Сторона защиты + + + + Prosecution needed + Сторона обвинения + + + + Judge needed + Без судьи никак + + + + Jurors needed + Суд присяжных + + + + Stenographer needed + Нужен стенографист? + + + + Witness needed + + + + + AOOptionsDialog + + + Settings + Настройки + + + + Gameplay + Игра + + + + Theme: + Тема: + + + + Sets the theme used in-game. If the new theme changes the lobby's look as well, you'll need to reload the lobby for the changes to take effect, such as by joining a server and leaving it. + Устанавливает внешний вид игры. Может понадобиться перезайти на сервер. + + + + Gives the default value for the in-game 'Custom shownames' checkbox, which in turn determines whether the client should display custom in-character names. + + + + + Sets the default volume for music. + + + + + Sets the default volume for SFX sounds, like interjections or other character sound effects. + + + + + IC Log + + + + + Colorful IC log: + + + + + Enables colored text in the log. + + + + + Only inline coloring: + + + + + Only inline coloring will be shown such as <>,|| etc. + + + + + Mirror IC log: + + + + + IC log will mirror the IC box. Meaning that if somebody gets interrupted nobody will know what they wanted to say. Enable for a more realistic experience. + + + + + Log goes downwards: + Портянку вниз: + + + + If ticked, new messages will appear at the bottom (like the OOC chatlog). The traditional (AO1) behaviour is equivalent to this being unticked. + Отметьте галочку, если хотите, чтобы сообщения в игровом чате отображались снизу, а не сверху. + + + + Log length: + Длина игрового чата: + + + + The amount of messages the IC chatlog will keep before deleting older messages. A value of 0 or below counts as 'infinite'. + Количество сообщений, максимально хранимых в игровом чате. Значение, равное 0 или меньше, будет расценено как снятие такого ограничения. + + + + Default username: + Никнейм по умолчанию: + + + + Your OOC name will be automatically set to this value when you join a server. + Псевдоним, используемый при соединении с сервером. В основном, его видно в чате сервера. + + + + Custom shownames: + Произвольные имена: + + + Gives the default value for the in-game 'Custom shownames' tickbox, which in turn determines whether the client should display custom in-character names. + Отображать произвольные имена персонажей, установленные самими игроками. + + + + Backup MS: + Запасной ГС: + + + + If the built-in server lookups fail, the game will try the address given here and use it as a backup master server address. + Отображать перечень серверов от главного сервера, указанного здесь, когда не удалось соединиться с первичным ГС. + + + + Discord: + Discord: + + + + Allows others on Discord to see what server you are in, what character are you playing, and how long you have been playing for. + Показать в Discord сервер, на котором вы играете, каким персонажем управляете и время игры. + + + + Allow Shake/Flash: + + + + + Allows screenshaking and flashing. Disable this if you have concerns or issues with photosensitivity and/or seizures. + + + + + Language: + Язык: + + + + Sets the language if you don't want to use your system language. + + + + + Slower text speed: + + + + + Set the text speed to be the same as the AA games. + + + + + Blip delay on punctuations: + + + + + Punctuation delay modifier. Enable it for the blips to slow down on punctuations. + + + + + Callwords + Позывные + + + + <html><head/><body>Enter as many callwords as you would like. These are case insensitive. Make sure to leave every callword in its own line!<br>Do not leave a line with a space at the end -- you will be alerted everytime someone uses a space in their messages.</body></html> + <html><head/><body>Введите на отдельных строках свои позывные, при указании которых в сообщениях будет подан звуковой сигнал.</body></html> + + + + Audio + Аудио + + + + Audio device: + Устройство воспроизведения: + + + + Sets the audio device for all sounds. + Куда вещать звук из игры. + + + + Music: + Музыка: + + + Sets the music's default volume. + Громкость музыки по умолчанию. + + + + SFX: + Звук. эффекты: + + + Sets the SFX's default volume. Interjections and actual sound effects count as 'SFX'. + Громкость звуковых эффектов по умолчанию. + + + + Blips: + Сигналы: + + + + Sets the volume of the blips, the talking sound effects. + Громкость сигналов, заменяющих голос, по умолчанию. + + + + Blip rate: + Пер. сигналов: + + + + Sets the delay between playing the blip sounds. + Период между сигналами, заменяющими голос, по умолчанию. + + + + Blank blips: + Пустые сигналы: + + + + If true, the game will play a blip sound even when a space is 'being said'. + Проигрывать сигналы даже для пробелов. + + + + Enable Looping SFX: + + + + + If true, the game will allow looping sound effects to play on preanimations. + + + + + Kill Music On Objection: + + + + + If true, the game will stop music when someone objects, like in the actual games. + + + + + Casing + Заседание + + + + This server supports case alerts. + Этот сервер поддерживает объявление заседания. + + + + This server does not support case alerts. + Этот сервер не поддерживает объявление заседания. + + + + Pretty self-explanatory. + Весьма доходчиво. + + + + Casing: + Новое дело: + + + + If checked, you will get alerts about case announcements. + При заведении дела вы получите уведомление. + + + + Defense: + Защита: + + + + If checked, you will get alerts about case announcements if a defense spot is open. + При заведении дела, в котором нужна сторона защиты, вы получите уведомление. + + + + Prosecution: + Обвинение: + + + + If checked, you will get alerts about case announcements if a prosecutor spot is open. + При заведении дела, в котором нужна сторона обвинения, вы получите уведомление. + + + + Judge: + Судья: + + + + If checked, you will get alerts about case announcements if the judge spot is open. + При заведении дела, в котором нужен судья, вы получите уведомление. + + + + Juror: + Присяжный: + + + + If checked, you will get alerts about case announcements if a juror spot is open. + При заведении дела, в котором нужны присяжные заседатели, вы получите уведомление. + + + + Stenographer: + Стенографист: + + + + If checked, you will get alerts about case announcements if a stenographer spot is open. + При заведении дела, в котором нужна стенография, вы получите уведомление. + + + + CM: + ПД: + + + + If checked, you will appear amongst the potential CMs on the server. + Отметьте, если вы хотите состоять в числе производителей дел. + + + + Witness: + + + + + If checked, you will appear amongst the potential witnesses on the server. + + + + + Hosting cases: + ПД акт.: + + + + If you're a CM, enter what cases you are willing to host. + Будучи производителем дела (ПД), вы можете войти в зону и заниматься её оркестровкой. + + + + Courtroom + + + Password + Пароль + + + + Spectator + Наблюдатель + + + + + Search + Поиск + + + + Passworded + Ограничен паролем + + + + Taken + Занят + + + + Could not find %1 + + + + Generating chars: +%1/%2 + Генерация персонажей: +%1/%2 + + + Generating chars: + + Генерация персонажей: + + + + + Showname + Имя + + + + Message + Сообщение + + + + Name + Никнейм + + + + Pre + Пред. + + + + Flip + Разв. + + + Guard + Охрана + + + + + Casing + Дело + + + + Shownames + Произв. имена + + + + No Interrupt + Говорить сразу + + + + White + Белый + + + + Green + Зелëный + + + + Red + Красный + + + + Orange + Оранжевый + + + + Blue + Синий + + + + Yellow + Жëлтый + + + + This does nothing, but there you go. + В общем-то, это ни на что не влияет... + + + + You need to give a filename to load (extension not needed)! Make sure that it is in the `base/cases/` folder, and that it is a correctly formatted ini. +Cases you can load: %1 + Укажите имя файла с делом (без расширения) для загрузки. Убедитесь, что оно расположено в папке `base/cases`. +Были найдены: %1 + + + + Case made by %1. + Дело завëл игрок: %1. + + + + Navigate to %1 for the CM doc. + Перейдите к %1 для получения материалов дела. + + + + Your case "%1" was loaded! + Дело под кодовым названием "%1" готово! + + + + + Server + Сервер + + + + Back to Lobby + Назад в лобби + + + + Rainbow + Радужный + + + + OOC Message + + + + + Disable Modcalls + + + + + Pink + Розовый + + + + Cyan + Голубой + + + + % offset + % сдвига + + + + Music + Музыка + + + + Sfx + Звук. эффекты + + + + Blips + Сигналы + + + + Log limit + + + + + Change character + + + + + Reload theme + + + + + Call mod + + + + + Settings + Настройки + + + + A/M + + + + + Preanim + + + + + + You were granted the Disable Modcalls button. + + + + + You have been banned. + + + + + Too many arguments to save a case! You only need a filename without extension and the courtroom status. + + + + You were granted the Guard button. + Теперь у вас есть кнопка "Охрана". + + + + You opened the settings menu. + Вы открыли меню настроек. + + + + You will now pair up with + Вы встанете парой с персонажем по имени + + + + if they also choose your character in return. + (если он выберет вас в ответ). + + + + You are no longer paired with anyone. + Теперь вы не стоите в парах. + + + + Are you sure you typed that well? The char ID could not be recognised. + Кажется, вам нужно поменять запрос: такой идентификатор персонажа не был найден. + + + + You have set your offset to + Вы установили сдвиг персонажа на + + + + Your offset must be between -100% and 100%! + Сдвиг персонажа должен быть между -100% и 100%! + + + + That offset does not look like one. + Неверный сдвиг персонажа. + + + + You switched your music and area list. + Вы переключили перечень зон и музыки. + + + + You have forcefully enabled features that the server may not support. You may not be able to talk IC, or worse, because of this. + Из-за того, что вы включили не поддержимаемые сервером возможности, он может не принять ваши сообщения. + + + + Your pre-animations interrupt again. + Персонаж будет говорить только после анимации. + + + + Your pre-animations will not interrupt text. + Персонаж будет говорить и во время анимации. + + + + Couldn't open chatlog.txt to write into. + Не могу открыть `chatlog.txt` для записи лога. + + + + The IC chatlog has been saved. + Лог игрового чата сохранëн. + + + + You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely the case file you're looking for can't be found in there. + Файл с делом не найден. Если найдëте, положите его в папку `base/cases/`, которую мы для вас создали. + + + + Too many arguments to load a case! You only need one filename, without extension. + Введите имя файла без расширения. + + + + You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely that you somehow deleted it. + Папка `base/cases/` отсутствует! + + + + You need to give a filename to save (extension not needed) and the courtroom status! + Введите имя файла (без расширения) и предоставьте статус зоны. + + + Too many arguments to save a case! You only need a filename without extension and the courtroom status! + Убедитесь, что имя файла не содержит расширение. + + + + Succesfully saved, edit doc and cmdoc link on the ini! + Сохранение прошло успешно! + + + + Master + Мастер + + + + Reason: + Причина: + + + + Call Moderator + Позвать модератора + + + + + Error + Ошибка + + + + You must provide a reason. + Укажите причину. + + + + The message is too long. + Слишком длинный текст. + + + + Choose... + Выбрать... + + + + Images (*.png) + Изображения (*.png) + + + + Add new evidence... + Добавить новую улику... + + + + Lobby + + + Attorney Online 2 + Attorney Online 2 + + + + Name + Никнейм + + + + It doesn't look like your client is set up correctly. +Did you download all resources correctly from tiny.cc/getao, including the large 'base' folder? + Не похоже, что ваш клиент установлен правильно. +Скачали ли вы все ресурсы (tiny.cc/getao), включая огромную папку `base`? + + + + Version: %1 + Версия: %1 + + + + Loading + Загрузка + + + + Cancel + Отмена + + + + <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Cents02<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, Raidensnake + + + + <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy + <h2>Attorney Online %1</h2>Симулятор судебной драмы<p><b>Исходный код:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Основной разработкой занимались:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>Особенная благодарность:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (дизайн интерфейса), Draxirch (дизайн интерфейса), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy + + + + Online: %1/%2 + Онлайн: %1/%2 + + + + + Offline + Вне сети + + + + debug_functions + + + Error: %1 + Ошибка: %1 + + + + Error + Ошибка + + + + Notice + На заметку + + + From 75453510e080978681ec5603e283c36638f155cc Mon Sep 17 00:00:00 2001 From: oldmud0 Date: Fri, 22 May 2020 21:14:37 -0500 Subject: [PATCH 182/268] Fix compile errors from merge --- include/aoapplication.h | 6 +++--- src/aoblipplayer.cpp | 6 ++++-- src/aosfxplayer.cpp | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/include/aoapplication.h b/include/aoapplication.h index fa1757b..18f6ef2 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -100,9 +100,9 @@ public: //////////////////versioning/////////////// - const int get_release() const { return RELEASE; } - const int get_major_version() const { return MAJOR_VERSION; } - const int get_minor_version() const { return MINOR_VERSION; } + int get_release() const { return RELEASE; } + int get_major_version() const { return MAJOR_VERSION; } + int get_minor_version() const { return MINOR_VERSION; } QString get_version_string(); /////////////////////////////////////////// diff --git a/src/aoblipplayer.cpp b/src/aoblipplayer.cpp index 39158fd..b67f9c3 100644 --- a/src/aoblipplayer.cpp +++ b/src/aoblipplayer.cpp @@ -22,7 +22,7 @@ void AOBlipPlayer::set_blips(QString p_sfx) FALSE, f_path.utf16(), 0, 0, BASS_UNICODE | BASS_ASYNCFILE); } - set_volume(m_volume); + set_volume_internal(m_volume); } void AOBlipPlayer::blip_tick() @@ -44,7 +44,9 @@ void AOBlipPlayer::blip_tick() void AOBlipPlayer::set_volume(int p_value) { - m_volume = p_value; + m_volume = static_cast(p_value) / 100; + set_volume_internal(m_volume); +} void AOBlipPlayer::set_volume_internal(qreal p_value) { diff --git a/src/aosfxplayer.cpp b/src/aosfxplayer.cpp index 6db6f37..607d605 100644 --- a/src/aosfxplayer.cpp +++ b/src/aosfxplayer.cpp @@ -86,7 +86,7 @@ void AOSfxPlayer::set_volume(qreal p_value) set_volume_internal(m_volume); } -void AOSfxPlayer::set_volume(int p_value) +void AOSfxPlayer::set_volume_internal(qreal p_value) { float volume = static_cast(p_value); for (int n_stream = 0; n_stream < m_channelmax; ++n_stream) { From 80daf94895d90afd89d9ebd80a517dbcde8e132f Mon Sep 17 00:00:00 2001 From: oldmud0 Date: Fri, 22 May 2020 21:55:09 -0500 Subject: [PATCH 183/268] Fix Linux build trying to use BASS --- Attorney_Online.pro | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/Attorney_Online.pro b/Attorney_Online.pro index 4b06b22..79f534a 100644 --- a/Attorney_Online.pro +++ b/Attorney_Online.pro @@ -15,23 +15,28 @@ HEADERS += $$files($$PWD/include/*.h) LIBS += -L$$PWD/lib -DEFINES += DISCORD +# Uncomment to enable Discord Rich Presence +# DEFINES += DISCORD contains(DEFINES, DISCORD) { -LIBS += -ldiscord-rpc + LIBS += -ldiscord-rpc } -DEFINES += BASSAUDIO +# Uncomment to enable the BASS audio engine +# (Recommended for Windows) +# DEFINES += BASSAUDIO contains(DEFINES, BASSAUDIO) { -LIBS += -lbass -LIBS += -lbassopus + LIBS += -lbass + LIBS += -lbassopus } -#DEFINES += QTAUDIO +# Uncomment to enable the Qt audio engine +# (Recommended for non-Windows platforms) +# DEFINES += QTAUDIO contains(DEFINES, QTAUDIO) { -QT += multimedia + QT += multimedia } macx:LIBS += -framework CoreFoundation -framework Foundation -framework CoreServices From 52736498b15a7464a2a395eb1984f9aa6578736d Mon Sep 17 00:00:00 2001 From: sD Date: Sat, 23 May 2020 17:21:22 +0200 Subject: [PATCH 184/268] fix up nomusic --- include/aomusicplayer.h | 20 +++++++++++++++++--- src/aoblipplayer.cpp | 2 +- src/aomusicplayer.cpp | 5 +++-- src/aosfxplayer.cpp | 5 +++-- 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/include/aomusicplayer.h b/include/aomusicplayer.h index 5c72649..f08b7d2 100644 --- a/include/aomusicplayer.h +++ b/include/aomusicplayer.h @@ -67,14 +67,28 @@ private: class AOMusicPlayer { public: AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app); - ~AOMusicPlayer(); + virtual ~AOMusicPlayer(); + void set_volume(int p_value, int channel = -1); + void set_looping(bool toggle, int channel = 0); - void play(QString p_song); - void set_volume(int p_value); + const int m_channelmax = 4; + +public slots: + void play(QString p_song, int channel = 0, bool loop = false, + int effect_flags = 0); + void stop(int channel = 0); private: QWidget *m_parent; AOApplication *ao_app; + + bool m_looping = false; + int m_volume[4] = {0, 0, 0, 0}; + + // Channel 0 = music + // Channel 1 = ambience + // Channel 2 = extra + // Channel 3 = extra }; #endif diff --git a/src/aoblipplayer.cpp b/src/aoblipplayer.cpp index b67f9c3..57b2d27 100644 --- a/src/aoblipplayer.cpp +++ b/src/aoblipplayer.cpp @@ -100,7 +100,7 @@ void AOBlipPlayer::set_blips(QString p_sfx) {} void AOBlipPlayer::blip_tick() {} -void AOBlipPlayer::set_volume(qreal p_value) {} +void AOBlipPlayer::set_volume(int p_value) {} void AOBlipPlayer::set_volume_internal(qreal p_value) {} #endif diff --git a/src/aomusicplayer.cpp b/src/aomusicplayer.cpp index bc1ab23..60b1c7c 100644 --- a/src/aomusicplayer.cpp +++ b/src/aomusicplayer.cpp @@ -205,7 +205,8 @@ AOMusicPlayer::AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app) AOMusicPlayer::~AOMusicPlayer() {} -void AOMusicPlayer::play(QString p_song) {} +void AOMusicPlayer::play(QString p_song, int channel, bool loop, + int effect_flags) {} -void AOMusicPlayer::set_volume(int p_value) {} +void AOMusicPlayer::set_volume(int p_value, int channel) {} #endif diff --git a/src/aosfxplayer.cpp b/src/aosfxplayer.cpp index 607d605..d23d5f9 100644 --- a/src/aosfxplayer.cpp +++ b/src/aosfxplayer.cpp @@ -170,9 +170,10 @@ AOSfxPlayer::AOSfxPlayer(QWidget *parent, AOApplication *p_ao_app) ao_app = p_ao_app; } -void AOSfxPlayer::play(QString p_sfx, QString p_char, QString shout) {} +void AOSfxPlayer::play(QString p_sfx, QString p_char, QString shout, + int channel) {} -void AOSfxPlayer::stop() {} +void AOSfxPlayer::stop(int channel) {} void AOSfxPlayer::set_volume(qreal p_value) {} From 5922bf748aa65f085d28b3a91e5961793aabd0c9 Mon Sep 17 00:00:00 2001 From: sD Date: Sat, 23 May 2020 17:28:27 +0200 Subject: [PATCH 185/268] no and zone --- src/courtroom.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index bcd3b47..caab3a5 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1537,7 +1537,7 @@ void Courtroom::on_chat_return_pressed() f_emote_mod = 2; } } - else if (ui_pre->isChecked() and !ui_pre_non_interrupt->isChecked()) { + else if (ui_pre->isChecked() && !ui_pre_non_interrupt->isChecked()) { if (f_emote_mod == 0) f_emote_mod = 1; else if (f_emote_mod == 5 && ao_app->prezoom_enabled) From 68bd38b7fe7be6bdbb3d6ccd52e6207eac5b983a Mon Sep 17 00:00:00 2001 From: sD Date: Sat, 23 May 2020 17:28:54 +0200 Subject: [PATCH 186/268] forgot those on noaudio --- src/aomusicplayer.cpp | 6 ++++++ src/aosfxplayer.cpp | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/src/aomusicplayer.cpp b/src/aomusicplayer.cpp index 60b1c7c..68af961 100644 --- a/src/aomusicplayer.cpp +++ b/src/aomusicplayer.cpp @@ -208,5 +208,11 @@ AOMusicPlayer::~AOMusicPlayer() {} void AOMusicPlayer::play(QString p_song, int channel, bool loop, int effect_flags) {} +void AOMusicPlayer::stop(int channel) {} + void AOMusicPlayer::set_volume(int p_value, int channel) {} + +void loopProc(int handle, int channel, int data, int *user) {} + +void AOMusicPlayer::set_looping(bool toggle, int channel) {} #endif diff --git a/src/aosfxplayer.cpp b/src/aosfxplayer.cpp index d23d5f9..121ac0b 100644 --- a/src/aosfxplayer.cpp +++ b/src/aosfxplayer.cpp @@ -170,6 +170,10 @@ AOSfxPlayer::AOSfxPlayer(QWidget *parent, AOApplication *p_ao_app) ao_app = p_ao_app; } +void AOSfxPlayer::clear() {} + +void AOSfxPlayer::loop_clear() {} + void AOSfxPlayer::play(QString p_sfx, QString p_char, QString shout, int channel) {} @@ -178,4 +182,6 @@ void AOSfxPlayer::stop(int channel) {} void AOSfxPlayer::set_volume(qreal p_value) {} void AOSfxPlayer::set_volume_internal(qreal p_value) {} + +void AOSfxPlayer::set_looping(bool toggle, int channel) {} #endif From 86cc7950061f3efb346cc7510d71dfb681a26172 Mon Sep 17 00:00:00 2001 From: cents Date: Sat, 23 May 2020 09:23:42 -0700 Subject: [PATCH 187/268] Other image formats now support the present evidence --- src/aoevidencedisplay.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/aoevidencedisplay.cpp b/src/aoevidencedisplay.cpp index 9dd062b..64e4e24 100644 --- a/src/aoevidencedisplay.cpp +++ b/src/aoevidencedisplay.cpp @@ -34,11 +34,11 @@ void AOEvidenceDisplay::show_evidence(QString p_evidence_image, if (is_left_side) { icon_identifier = "left_evidence_icon"; - gif_name = "evidence_appear_left.gif"; + gif_name = "evidence_appear_left"; } else { icon_identifier = "right_evidence_icon"; - gif_name = "evidence_appear_right.gif"; + gif_name = "evidence_appear_right"; } pos_size_type icon_dimensions = @@ -49,9 +49,8 @@ void AOEvidenceDisplay::show_evidence(QString p_evidence_image, evidence_icon->setPixmap(f_pixmap.scaled( evidence_icon->width(), evidence_icon->height(), Qt::IgnoreAspectRatio)); - - QString f_default_gif_path = ao_app->get_default_theme_path(gif_name); - QString f_gif_path = ao_app->get_theme_path(gif_name); + QString f_default_gif_path = ao_app->get_image_suffix(ao_app->get_default_theme_path(gif_name)); + QString f_gif_path = ao_app->get_image_suffix(ao_app->get_theme_path(gif_name)); if (file_exists(f_gif_path)) final_gif_path = f_gif_path; From ba9aebec57d231236642f9e58329b1d87b264dbd Mon Sep 17 00:00:00 2001 From: sD Date: Sat, 23 May 2020 18:32:05 +0200 Subject: [PATCH 188/268] translate stuff that got run over --- include/chatlogpiece.h | 2 ++ src/aooptionsdialog.cpp | 4 +-- src/chatlogpiece.cpp | 8 +++--- src/courtroom.cpp | 54 ++++++++++++++++++------------------- src/evidence.cpp | 35 ++++++++++++------------ src/lobby.cpp | 12 ++++----- src/packet_distribution.cpp | 10 +++---- 7 files changed, 62 insertions(+), 63 deletions(-) diff --git a/include/chatlogpiece.h b/include/chatlogpiece.h index e6f77c7..f3a9dc8 100644 --- a/include/chatlogpiece.h +++ b/include/chatlogpiece.h @@ -1,10 +1,12 @@ #ifndef CHATLOGPIECE_H #define CHATLOGPIECE_H +#include #include #include class chatlogpiece { + Q_DECLARE_TR_FUNCTIONS(chatlogpiece) public: chatlogpiece(); chatlogpiece(QString p_name, QString p_showname, QString p_message, diff --git a/src/aooptionsdialog.cpp b/src/aooptionsdialog.cpp index e911963..80746f7 100644 --- a/src/aooptionsdialog.cpp +++ b/src/aooptionsdialog.cpp @@ -205,7 +205,7 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) ui_language_combobox = new QComboBox(ui_form_layout_widget); ui_language_combobox->addItem( configini->value("language", " ").value() + - " - Keep current setting"); + tr(" - Keep current setting")); ui_language_combobox->addItem(" - Default"); ui_language_combobox->addItem("en - English"); ui_language_combobox->addItem("de - Deutsch"); @@ -384,7 +384,7 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) int a = 0; if (needs_default_audiodev()) { - ui_audio_device_combobox->addItem("default"); + ui_audio_device_combobox->addItem("default"); //TODO translate this without breaking the default audio device } #ifdef BASSAUDIO BASS_DEVICEINFO info; diff --git a/src/chatlogpiece.cpp b/src/chatlogpiece.cpp index 34a2fea..ec964b9 100644 --- a/src/chatlogpiece.cpp +++ b/src/chatlogpiece.cpp @@ -2,9 +2,9 @@ chatlogpiece::chatlogpiece() { - name = "UNKNOWN"; - showname = "UNKNOWN"; - message = "UNKNOWN"; + name = tr("UNKNOWN"); + showname = tr("UNKNOWN"); + message = tr("UNKNOWN"); p_is_song = false; datetime = QDateTime::currentDateTime().toUTC(); } @@ -52,7 +52,7 @@ QString chatlogpiece::get_full() full.append(get_name()); full.append(")"); if (p_is_song) - full.append(" has played a song: "); + full.append(tr(" has played a song: ")); else full.append(": "); full.append(get_message()); diff --git a/src/courtroom.cpp b/src/courtroom.cpp index caab3a5..e3eeb59 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -164,7 +164,7 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_ooc_chat_name = new QLineEdit(this); ui_ooc_chat_name->setFrame(false); - ui_ooc_chat_name->setPlaceholderText("Name"); + ui_ooc_chat_name->setPlaceholderText(tr("Name")); ui_ooc_chat_name->setMaxLength(30); ui_ooc_chat_name->setText(p_ao_app->get_default_username()); @@ -214,14 +214,14 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_switch_area_music = new AOButton(this, ao_app); ui_pre = new QCheckBox(this); - ui_pre->setText("Pre"); + ui_pre->setText(tr("Pre")); ui_flip = new QCheckBox(this); - ui_flip->setText("Flip"); + ui_flip->setText(tr("Flip")); ui_flip->hide(); ui_guard = new QCheckBox(this); - ui_guard->setText("Guard"); + ui_guard->setText(tr("Guard")); ui_guard->hide(); ui_additive = new QCheckBox(this); @@ -274,8 +274,8 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_pair_offset_spinbox->setSuffix(tr("% offset")); ui_pair_order_dropdown = new QComboBox(this); - ui_pair_order_dropdown->addItem("To front"); - ui_pair_order_dropdown->addItem("To behind"); + ui_pair_order_dropdown->addItem(tr("To front")); + ui_pair_order_dropdown->addItem(tr("To behind")); ui_pair_button = new AOButton(this, ao_app); @@ -739,11 +739,11 @@ void Courtroom::set_widgets() QString::number(prosecution_bar_state)); set_size_and_pos(ui_music_label, "music_label"); - ui_music_label->setText("Music"); + ui_music_label->setText(tr("Music")); set_size_and_pos(ui_sfx_label, "sfx_label"); - ui_sfx_label->setText("Sfx"); + ui_sfx_label->setText(tr("Sfx")); set_size_and_pos(ui_blip_label, "blip_label"); - ui_blip_label->setText("Blips"); + ui_blip_label->setText(tr("Blips")); set_size_and_pos(ui_hold_it, "hold_it"); ui_hold_it->setText(tr("Hold It!")); @@ -1454,7 +1454,7 @@ void Courtroom::append_server_chatmessage(QString p_name, QString p_message, if (p_message == "Logged in as a moderator.") { ui_guard->show(); append_server_chatmessage( - "CLIENT", "You were granted the Disable Modcalls button.", "1"); + tr("CLIENT"), tr("You were granted the Disable Modcalls button."), "1"); } ui_server_chatlog->append_chatmessage(p_name, p_message, color); @@ -2981,7 +2981,7 @@ void Courtroom::set_ban(int p_cid) if (p_cid != m_cid && p_cid != -1) return; - call_notice("You have been banned."); + call_notice(tr("You have been banned.")); ao_app->construct_lobby(); ao_app->destruct_courtroom(); @@ -3058,7 +3058,7 @@ void Courtroom::handle_song(QStringList *p_contents) ic_chatlog_history.removeFirst(); } - append_ic_text(f_song_clear, str_show, "has played a song"); + append_ic_text(f_song_clear, str_show, tr("has played a song")); music_player->play(f_song, channel, looping, effect_flags); if (channel == 0) @@ -3192,9 +3192,7 @@ void Courtroom::on_ooc_return_pressed() if (ok) { if (whom > -1) { other_charid = whom; - QString msg = "You will now pair up with "; - msg.append(char_list.at(whom).name); - msg.append(" if they also choose your character in return."); + QString msg = tr("You will now pair up with %1 if they also choose your character in return.").arg(char_list.at(whom).name); append_server_chatmessage("CLIENT", msg, "1"); } else { @@ -3342,7 +3340,7 @@ void Courtroom::on_ooc_return_pressed() QString casestatus = casefile.value("status", "").value(); if (!caseauth.isEmpty()) - append_server_chatmessage("CLIENT", tr("Case made by %1.").arg(caseauth), + append_server_chatmessage(tr("CLIENT"), tr("Case made by %1.").arg(caseauth), "1"); if (!casedoc.isEmpty()) ao_app->send_server_packet(new AOPacket("CT#" + ui_ooc_chat_name->text() + @@ -3366,9 +3364,9 @@ void Courtroom::on_ooc_return_pressed() QStringList f_contents; f_contents.append( - casefile.value(evi + "/name", "UNKNOWN").value()); + casefile.value(evi + "/name", tr("UNKNOWN")).value()); f_contents.append( - casefile.value(evi + "/description", "UNKNOWN").value()); + casefile.value(evi + "/description", tr("UNKNOWN")).value()); f_contents.append( casefile.value(evi + "/image", "UNKNOWN.png").value()); @@ -3967,25 +3965,25 @@ void Courtroom::on_music_list_context_menu_requested(const QPoint &pos) { QMenu *menu = new QMenu(); - menu->addAction(QString("Expand All Categories"), this, + menu->addAction(QString(tr("Expand All Categories")), this, SLOT(music_list_expand_all())); - menu->addAction(QString("Collapse All Categories"), this, + menu->addAction(QString(tr("Collapse All Categories")), this, SLOT(music_list_collapse_all())); menu->addSeparator(); - menu->addAction(new QAction("Fade Out Previous", this)); + menu->addAction(new QAction(tr("Fade Out Previous"), this)); menu->actions().back()->setCheckable(true); menu->actions().back()->setChecked(music_flags & FADE_OUT); connect(menu->actions().back(), SIGNAL(toggled(bool)), this, SLOT(music_fade_out(bool))); - menu->addAction(new QAction("Fade In", this)); + menu->addAction(new QAction(tr("Fade In"), this)); menu->actions().back()->setCheckable(true); menu->actions().back()->setChecked(music_flags & FADE_IN); connect(menu->actions().back(), SIGNAL(toggled(bool)), this, SLOT(music_fade_in(bool))); - menu->addAction(new QAction("Synchronize", this)); + menu->addAction(new QAction(tr("Synchronize"), this)); menu->actions().back()->setCheckable(true); menu->actions().back()->setChecked(music_flags & SYNC_POS); connect(menu->actions().back(), SIGNAL(toggled(bool)), this, @@ -4416,8 +4414,8 @@ void Courtroom::on_call_mod_clicked() QInputDialog input; input.setWindowFlags(Qt::WindowSystemMenuHint); - input.setLabelText("Reason:"); - input.setWindowTitle("Call Moderator"); + input.setLabelText(tr("Reason:")); + input.setWindowTitle(tr("Call Moderator")); auto code = input.exec(); if (code != QDialog::Accepted) @@ -4425,7 +4423,7 @@ void Courtroom::on_call_mod_clicked() QString text = input.textValue(); if (text.isEmpty()) { - errorBox.critical(nullptr, "Error", "You must provide a reason."); + errorBox.critical(nullptr, tr("Error"), tr("You must provide a reason.")); return; } else if (text.length() > 256) { @@ -4478,14 +4476,14 @@ void Courtroom::on_showname_enable_clicked() if (ui_showname_enable->isChecked()) { if (item.is_song()) append_ic_text(item.get_message(), item.get_showname(), - "has played a song"); + tr("has played a song")); else append_ic_text(item.get_message(), item.get_showname()); } else { if (item.is_song()) append_ic_text(item.get_message(), item.get_name(), - "has played a song"); + tr("has played a song")); else append_ic_text(item.get_message(), item.get_name()); } diff --git a/src/evidence.cpp b/src/evidence.cpp index dffe848..99d365d 100644 --- a/src/evidence.cpp +++ b/src/evidence.cpp @@ -31,7 +31,7 @@ void Courtroom::initialize_evidence() ui_evidence_delete->setToolTip(tr("Destroy this piece of evidence")); ui_evidence_image_name = new AOLineEdit(ui_evidence_overlay); ui_evidence_image_button = new AOButton(ui_evidence_overlay, ao_app); - ui_evidence_image_button->setText("Choose.."); + ui_evidence_image_button->setText(tr("Choose..")); ui_evidence_x = new AOButton(ui_evidence_overlay, ao_app); ui_evidence_x->setToolTip( tr("Close the evidence display/editing overlay.\n" @@ -45,7 +45,7 @@ void Courtroom::initialize_evidence() "color: white;"); ui_evidence_description->setFrameStyle(QFrame::NoFrame); ui_evidence_description->setToolTip( - "Double-click to edit. Press [X] to update your changes."); + tr("Double-click to edit. Press [X] to update your changes.")); connect(ui_evidence_name, SIGNAL(returnPressed()), this, SLOT(on_evidence_name_edited())); @@ -260,13 +260,12 @@ void Courtroom::set_evidence_list(QVector &p_evi_list) local_evidence_list.at(current_evidence))) { QMessageBox *msgBox = new QMessageBox; - msgBox->setText("The piece of evidence you've been editing has changed."); - msgBox->setInformativeText("Do you wish to keep your changes?"); - msgBox->setDetailedText( - "Name: " + local_evidence_list.at(current_evidence).name + - "\nImage: " + local_evidence_list.at(current_evidence).image + - "\nDescription:\n" + - local_evidence_list.at(current_evidence).description); + msgBox->setText(tr("The piece of evidence you've been editing has changed.")); + msgBox->setInformativeText(tr("Do you wish to keep your changes?")); + msgBox->setDetailedText(tr( + "Name: %1\n" + "Image: %2\n" + "Description:\n%3").arg(local_evidence_list.at(current_evidence).name).arg(local_evidence_list.at(current_evidence).image).arg(local_evidence_list.at(current_evidence).description)); msgBox->setStandardButtons(QMessageBox::Yes | QMessageBox::No); msgBox->setDefaultButton(QMessageBox::LastButton); // msgBox->setWindowModality(Qt::NonModal); @@ -454,14 +453,14 @@ void Courtroom::on_evidence_double_clicked(int p_id) ui_evidence_description->clear(); ui_evidence_description->appendPlainText(f_evi.description); ui_evidence_description->setReadOnly(true); - ui_evidence_description->setToolTip("Double-click to edit..."); + ui_evidence_description->setToolTip(tr("Double-click to edit...")); ui_evidence_name->setText(f_evi.name); ui_evidence_name->setReadOnly(true); - ui_evidence_name->setToolTip("Double-click to edit..."); + ui_evidence_name->setToolTip(tr("Double-click to edit...")); ui_evidence_image_name->setText(f_evi.image); ui_evidence_image_name->setReadOnly(true); - ui_evidence_image_name->setToolTip("Double-click to edit..."); + ui_evidence_image_name->setToolTip(tr("Double-click to edit...")); ui_evidence_overlay->show(); ui_evidence_ok->hide(); @@ -476,7 +475,7 @@ void Courtroom::on_evidence_hover(int p_id, bool p_state) if (p_state) { if (final_id == local_evidence_list.size()) - ui_evidence_name->setText("Add new evidence..."); + ui_evidence_name->setText(tr("Add new evidence...")); else if (final_id < local_evidence_list.size()) ui_evidence_name->setText(local_evidence_list.at(final_id).name); } @@ -554,8 +553,8 @@ void Courtroom::on_evidence_x_clicked() return; } QMessageBox *msgBox = new QMessageBox; - msgBox->setText("Evidence has been modified."); - msgBox->setInformativeText("Do you want to save your changes?"); + msgBox->setText(tr("Evidence has been modified.")); + msgBox->setInformativeText(tr("Do you want to save your changes?")); msgBox->setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); msgBox->setDefaultButton(QMessageBox::Save); @@ -657,7 +656,7 @@ void Courtroom::on_evidence_transfer_clicked() } QMessageBox *msgBox = new QMessageBox; - msgBox->setText("\"" + name + "\" has been transferred."); + msgBox->setText(tr("\"%1\" has been transferred.").arg(name)); msgBox->setStandardButtons(QMessageBox::Ok); msgBox->setDefaultButton(QMessageBox::Ok); msgBox->exec(); @@ -759,9 +758,9 @@ void Courtroom::on_evidence_load_clicked() continue; evi_type f_evi; - f_evi.name = inventory.value(evi + "/name", "UNKNOWN").value(); + f_evi.name = inventory.value(evi + "/name", tr("UNKNOWN")).value(); f_evi.description = - inventory.value(evi + "/description", "UNKNOWN").value(); + inventory.value(evi + "/description", tr("UNKNOWN")).value(); f_evi.image = inventory.value(evi + "/image", "UNKNOWN.png").value(); local_evidence_list.append(f_evi); diff --git a/src/lobby.cpp b/src/lobby.cpp index 81e4086..91c4b7c 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -9,7 +9,7 @@ Lobby::Lobby(AOApplication *p_ao_app) : QMainWindow() { ao_app = p_ao_app; - this->setWindowTitle("Attorney Online 2"); + this->setWindowTitle(tr("Attorney Online 2")); this->setWindowIcon(QIcon(":/logo.png")); ui_background = new AOImage(this, ao_app); @@ -36,7 +36,7 @@ Lobby::Lobby(AOApplication *p_ao_app) : QMainWindow() ui_chatbox = new AOTextArea(this); ui_chatbox->setOpenExternalLinks(true); ui_chatname = new QLineEdit(this); - ui_chatname->setPlaceholderText("Name"); + ui_chatname->setPlaceholderText(tr("Name")); ui_chatname->setText(ao_app->get_ooc_name()); ui_chatmessage = new QLineEdit(this); ui_loading_background = new AOImage(this, ao_app); @@ -139,7 +139,7 @@ void Lobby::set_widgets() ui_server_search->setStyleSheet("background-color: rgba(0, 0, 0, 0);"); set_size_and_pos(ui_player_count, "player_count"); - ui_player_count->setText("Offline"); + ui_player_count->setText(tr("Offline")); ui_player_count->setStyleSheet("font: bold;" "color: white;" "qproperty-alignment: AlignCenter;"); @@ -173,11 +173,11 @@ void Lobby::set_widgets() ui_loading_text->setFrameStyle(QFrame::NoFrame); ui_loading_text->setStyleSheet("background-color: rgba(0, 0, 0, 0);" "color: rgba(255, 128, 0, 255);"); - ui_loading_text->append("Loading"); + ui_loading_text->append(tr("Loading")); set_size_and_pos(ui_progress_bar, "progress_bar"); set_size_and_pos(ui_cancel, "cancel"); - ui_cancel->setText("Cancel"); + ui_cancel->setText(tr("Cancel")); ui_loading_background->hide(); @@ -377,7 +377,7 @@ void Lobby::on_about_clicked() "Noevain, Cronnicossy, the AO2 community, server hosts, game masters," "case makers, content creators and players!") .arg(ao_app->get_version_string()); - QMessageBox::about(this, "About", msg); + QMessageBox::about(this, tr("About"), msg); } void Lobby::on_settings_clicked() { ao_app->call_settings_menu(); } diff --git a/src/packet_distribution.cpp b/src/packet_distribution.cpp index a7bdbab..44e2816 100644 --- a/src/packet_distribution.cpp +++ b/src/packet_distribution.cpp @@ -232,7 +232,7 @@ void AOApplication::server_packet_received(AOPacket *p_packet) courtroom_loaded = false; - QString window_title = "Attorney Online 2"; + QString window_title = tr("Attorney Online 2"); int selected_server = w_lobby->get_selected_server(); QString server_address = "", server_name = ""; @@ -260,7 +260,7 @@ void AOApplication::server_packet_received(AOPacket *p_packet) w_courtroom->set_window_title(window_title); w_lobby->show_loading_overlay(); - w_lobby->set_loading_text("Loading"); + w_lobby->set_loading_text(tr("Loading")); w_lobby->set_loading_value(0); AOPacket *f_packet; @@ -313,9 +313,9 @@ void AOApplication::server_packet_received(AOPacket *p_packet) ++loaded_chars; - w_lobby->set_loading_text("Loading chars:\n" + - QString::number(loaded_chars) + "/" + - QString::number(char_list_size)); + w_lobby->set_loading_text(tr("Loading chars:\n%1/%2") + .arg(QString::number(loaded_chars)) + .arg(QString::number(char_list_size))); w_courtroom->append_char(f_char); From 3329ce1416dbdf6fa9d1136468efa12fd40c7815 Mon Sep 17 00:00:00 2001 From: sD Date: Sat, 23 May 2020 18:32:45 +0200 Subject: [PATCH 189/268] use new hdid method if supported --- src/hardware_functions.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/hardware_functions.cpp b/src/hardware_functions.cpp index 82b4f0c..6da642a 100644 --- a/src/hardware_functions.cpp +++ b/src/hardware_functions.cpp @@ -1,6 +1,9 @@ #include "hardware_functions.h" #include +#include + +#if QT_VERSION < QT_VERSION_CHECK(5, 4, 0) #if (defined(_WIN32) || defined(_WIN64)) #include @@ -81,3 +84,16 @@ QString get_hdid() #error This operating system is unsupported for hardware functions. #endif + +#else +#include + +QByteArray machineId; + +QString get_hdid() +{ + machineId = QSysInfo::machineUniqueId(); + return QString(machineId); +} + +#endif From 7166b50f4b8ebdeb6bfcfd114e8ad2df60cbd21d Mon Sep 17 00:00:00 2001 From: sD Date: Sat, 23 May 2020 18:36:28 +0200 Subject: [PATCH 190/268] rename logo files --- resource/{logo.ico => logo_kfo.ico} | Bin resource/{logo.png => logo_kfo.png} | Bin 2 files changed, 0 insertions(+), 0 deletions(-) rename resource/{logo.ico => logo_kfo.ico} (100%) rename resource/{logo.png => logo_kfo.png} (100%) diff --git a/resource/logo.ico b/resource/logo_kfo.ico similarity index 100% rename from resource/logo.ico rename to resource/logo_kfo.ico diff --git a/resource/logo.png b/resource/logo_kfo.png similarity index 100% rename from resource/logo.png rename to resource/logo_kfo.png From e7ec42f977eb1681f20d6b5f68625cda088597e1 Mon Sep 17 00:00:00 2001 From: sD Date: Sat, 23 May 2020 18:41:27 +0200 Subject: [PATCH 191/268] undo branding --- Attorney_Online.pro | 4 ++-- resource/{logo.icns => logo_ao2.icns} | Bin resources.qrc | 2 +- src/lobby.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename resource/{logo.icns => logo_ao2.icns} (100%) diff --git a/Attorney_Online.pro b/Attorney_Online.pro index 79f534a..2a47afd 100644 --- a/Attorney_Online.pro +++ b/Attorney_Online.pro @@ -54,8 +54,8 @@ TRANSLATIONS = resource/translations/ao_en.ts \ resource/translations/ao_pt.ts \ resource/translations/ao_pl.ts -win32:RC_ICONS = resource/logo.ico -macx:ICON = resource/logo.icns +win32:RC_ICONS = resource/logo_ao2.ico +macx:ICON = resource/logo_ao2.icns android:DISTFILES += \ android/AndroidManifest.xml \ diff --git a/resource/logo.icns b/resource/logo_ao2.icns similarity index 100% rename from resource/logo.icns rename to resource/logo_ao2.icns diff --git a/resources.qrc b/resources.qrc index bc9f322..974f797 100644 --- a/resources.qrc +++ b/resources.qrc @@ -1,6 +1,6 @@ resource/fonts/Ace-Attorney.ttf - resource/logo.png + resource/logo_ao2.png diff --git a/src/lobby.cpp b/src/lobby.cpp index 91c4b7c..9804855 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -120,7 +120,7 @@ void Lobby::set_widgets() ui_connect->set_image("connect"); set_size_and_pos(ui_version, "version"); - ui_version->setText(tr("Version: KFO%1").arg(ao_app->get_version_string())); + ui_version->setText(tr("Version: %1").arg(ao_app->get_version_string())); set_size_and_pos(ui_about, "about"); ui_about->set_image("about"); From f0a0ecb983a5e160adaefca139f0fe034cb11062 Mon Sep 17 00:00:00 2001 From: sD Date: Sat, 23 May 2020 18:53:31 +0200 Subject: [PATCH 192/268] ignore the logs --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 3f8b3ae..212daec 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ base_override.h base-full/ base/ +logs/ bass.lib bin/ From 53c72227c4ade7c3e28bf0051346d297f56e51be Mon Sep 17 00:00:00 2001 From: cents Date: Sat, 23 May 2020 09:54:33 -0700 Subject: [PATCH 193/268] Disable html injection --- src/courtroom.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 11c0bda..4d73507 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -2293,12 +2293,10 @@ QString Courtroom::filter_ic_text(QString p_text, bool skip_filter, bool delay_pop = false; while (trick_check_pos < p_text.size()) { f_character = p_text.at(trick_check_pos); - if (!skip_filter) { if (f_character == "<") f_character = "<"; else if (f_character == ">") f_character = ">"; - } // Escape character. if (f_character == "\\" && !ic_next_is_not_special) { ic_next_is_not_special = true; @@ -2511,10 +2509,9 @@ QString Courtroom::filter_ic_text(QString p_text, bool skip_filter, * \param p_text The text to be appended * \param p_name The name of the character/entity who sent said text * \param is_songchange Whether we are appending a song entry - * \param force_filter If we are sending plain text and we want to force the - * \param filtering regardless of its status (e.g chat entry, song change etc) - * \param skip_filter If we are sending appending text such as html so we skip the - * \param filter chat_color The color of the message sent + * \param force_filter If we are sending plain text and we want to force the filtering regardless of its status (e.g chat entry, song change etc) + * \param skip_filter If we are sending appending text such as html so we skip the html filter + * \param chat_color The color of the message sent */ void Courtroom::append_ic_text(QString p_text, QString p_name, From 8a4fc4516c406a2fa63039310914c6a5514e7c04 Mon Sep 17 00:00:00 2001 From: sD Date: Sat, 23 May 2020 19:18:35 +0200 Subject: [PATCH 194/268] fix qt music player --- include/aomusicplayer.h | 54 ++++++----------------------------------- src/aomusicplayer.cpp | 34 ++++++++++++++++++-------- 2 files changed, 31 insertions(+), 57 deletions(-) diff --git a/include/aomusicplayer.h b/include/aomusicplayer.h index f08b7d2..de673e5 100644 --- a/include/aomusicplayer.h +++ b/include/aomusicplayer.h @@ -8,13 +8,13 @@ #elif defined(QTAUDIO) #include #endif + #include "aoapplication.h" #include #include #include -#if defined(BASSAUDIO) class AOMusicPlayer { public: AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app); @@ -25,8 +25,8 @@ public: const int m_channelmax = 4; // These have to be public for the stupid sync thing - QWORD loop_start = 0; - QWORD loop_end = 0; + int loop_start = 0; + int loop_end = 0; public slots: void play(QString p_song, int channel = 0, bool loop = false, @@ -44,52 +44,12 @@ private: // Channel 1 = ambience // Channel 2 = extra // Channel 3 = extra + #if defined(BASSAUDIO) HSTREAM m_stream_list[4]; HSYNC loop_sync[4]; + #elif defined(QTAUDIO) + QMediaPlayer m_stream_list[4]; + #endif }; -#elif defined(QTAUDIO) -class AOMusicPlayer { -public: - AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app); - ~AOMusicPlayer(); - - void play(QString p_song); - void set_volume(int p_value); - -private: - QMediaPlayer m_player; - QWidget *m_parent; - AOApplication *ao_app; - - int m_volume = 0; -}; -#else -class AOMusicPlayer { -public: - AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app); - virtual ~AOMusicPlayer(); - void set_volume(int p_value, int channel = -1); - void set_looping(bool toggle, int channel = 0); - - const int m_channelmax = 4; - -public slots: - void play(QString p_song, int channel = 0, bool loop = false, - int effect_flags = 0); - void stop(int channel = 0); - -private: - QWidget *m_parent; - AOApplication *ao_app; - - bool m_looping = false; - int m_volume[4] = {0, 0, 0, 0}; - - // Channel 0 = music - // Channel 1 = ambience - // Channel 2 = extra - // Channel 3 = extra -}; -#endif #endif // AOMUSICPLAYER_H diff --git a/src/aomusicplayer.cpp b/src/aomusicplayer.cpp index 68af961..5878dcd 100644 --- a/src/aomusicplayer.cpp +++ b/src/aomusicplayer.cpp @@ -176,26 +176,40 @@ AOMusicPlayer::AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app) ao_app = p_ao_app; } -AOMusicPlayer::~AOMusicPlayer() { m_player.stop(); } +AOMusicPlayer::~AOMusicPlayer() { + for (int n_stream = 0; n_stream < m_channelmax; ++n_stream) { + m_stream_list[n_stream].stop(); + } +} -void AOMusicPlayer::play(QString p_song) +void AOMusicPlayer::play(QString p_song, int channel, bool loop, + int effect_flags) { - m_player.stop(); - + channel = channel % m_channelmax; + if (channel < 0) // wtf? + return; QString f_path = ao_app->get_music_path(p_song); - m_player.setMedia(QUrl::fromLocalFile(f_path)); + m_stream_list[channel].stop(); - this->set_volume(m_volume); + m_stream_list[channel].setMedia(QUrl::fromLocalFile(f_path)); - m_player.play(); + this->set_volume(m_volume[channel], channel); + + m_stream_list[channel].play(); } -void AOMusicPlayer::set_volume(int p_value) +void AOMusicPlayer::stop(int channel) { - m_volume = p_value; - m_player.setVolume(m_volume); + m_stream_list[channel].stop(); } + +void AOMusicPlayer::set_volume(int p_value, int channel) +{ + m_volume[channel] = p_value; + m_stream_list[channel].setVolume(m_volume[channel]); +} + #else AOMusicPlayer::AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app) { From 7a7dd25459f19796e38fde2148304376389a7a16 Mon Sep 17 00:00:00 2001 From: sD Date: Sat, 23 May 2020 19:21:25 +0200 Subject: [PATCH 195/268] i don't need this 3 times --- src/aomusicplayer.cpp | 14 +++----------- src/aosfxplayer.cpp | 14 ++------------ 2 files changed, 5 insertions(+), 23 deletions(-) diff --git a/src/aomusicplayer.cpp b/src/aomusicplayer.cpp index 5878dcd..8ba1641 100644 --- a/src/aomusicplayer.cpp +++ b/src/aomusicplayer.cpp @@ -1,12 +1,14 @@ #include "aomusicplayer.h" -#ifdef BASSAUDIO + AOMusicPlayer::AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app) { m_parent = parent; ao_app = p_ao_app; } +#ifdef BASSAUDIO + AOMusicPlayer::~AOMusicPlayer() { for (int n_stream = 0; n_stream < m_channelmax; ++n_stream) { @@ -170,11 +172,6 @@ void AOMusicPlayer::set_looping(bool toggle, int channel) } } #elif defined(QTAUDIO) -AOMusicPlayer::AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app) -{ - m_parent = parent; - ao_app = p_ao_app; -} AOMusicPlayer::~AOMusicPlayer() { for (int n_stream = 0; n_stream < m_channelmax; ++n_stream) { @@ -211,11 +208,6 @@ void AOMusicPlayer::set_volume(int p_value, int channel) } #else -AOMusicPlayer::AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app) -{ - m_parent = parent; - ao_app = p_ao_app; -} AOMusicPlayer::~AOMusicPlayer() {} diff --git a/src/aosfxplayer.cpp b/src/aosfxplayer.cpp index 121ac0b..6fb5bec 100644 --- a/src/aosfxplayer.cpp +++ b/src/aosfxplayer.cpp @@ -1,13 +1,14 @@ #include "aosfxplayer.h" #include "file_functions.h" -#if defined(BASSAUDIO) // Using bass.dll for sfx + AOSfxPlayer::AOSfxPlayer(QWidget *parent, AOApplication *p_ao_app) { m_parent = parent; ao_app = p_ao_app; } +#if defined(BASSAUDIO) // Using bass.dll for sfx void AOSfxPlayer::clear() { for (int n_stream = 0; n_stream < m_channelmax; ++n_stream) { @@ -112,11 +113,6 @@ void AOSfxPlayer::set_looping(bool toggle, int channel) } } #elif defined(QTAUDIO) // Using Qt's QSoundEffect class -AOSfxPlayer::AOSfxPlayer(QWidget *parent, AOApplication *p_ao_app) -{ - m_parent = parent; - ao_app = p_ao_app; -} void AOSfxPlayer::play(QString p_sfx, QString p_char, QString shout) { @@ -164,12 +160,6 @@ void AOSfxPlayer::set_volume_internal(qreal p_value) m_sfx.setVolume(m_volume); } #else -AOSfxPlayer::AOSfxPlayer(QWidget *parent, AOApplication *p_ao_app) -{ - m_parent = parent; - ao_app = p_ao_app; -} - void AOSfxPlayer::clear() {} void AOSfxPlayer::loop_clear() {} From e81fac7e07cdeca4682e712ec4c9b9585942f50a Mon Sep 17 00:00:00 2001 From: sD Date: Sat, 23 May 2020 19:28:34 +0200 Subject: [PATCH 196/268] fix qt sfx player --- include/aosfxplayer.h | 5 +++-- src/aosfxplayer.cpp | 48 ++++++++++++++++++++++++++++++++++++------- 2 files changed, 44 insertions(+), 9 deletions(-) diff --git a/include/aosfxplayer.h b/include/aosfxplayer.h index 9c9824a..9918871 100644 --- a/include/aosfxplayer.h +++ b/include/aosfxplayer.h @@ -35,11 +35,12 @@ private: bool m_looping = true; void set_volume_internal(qreal p_volume); -#if defined(BASSAUDIO) const int m_channelmax = 5; + +#if defined(BASSAUDIO) HSTREAM m_stream_list[5]; #elif defined(QTAUDIO) - QSoundEffect m_sfx; + QSoundEffect m_stream_list[5]; #endif }; diff --git a/src/aosfxplayer.cpp b/src/aosfxplayer.cpp index 6fb5bec..0fdba1b 100644 --- a/src/aosfxplayer.cpp +++ b/src/aosfxplayer.cpp @@ -114,9 +114,26 @@ void AOSfxPlayer::set_looping(bool toggle, int channel) } #elif defined(QTAUDIO) // Using Qt's QSoundEffect class -void AOSfxPlayer::play(QString p_sfx, QString p_char, QString shout) +void AOSfxPlayer::clear() { - m_sfx.stop(); + for (int n_stream = 0; n_stream < m_channelmax; ++n_stream) { + m_stream_list[n_stream].stop(); + } + set_volume_internal(m_volume); +} + +void AOSfxPlayer::loop_clear() +{ + for (int n_stream = 0; n_stream < m_channelmax; ++n_stream) { + m_stream_list[n_stream].stop(); + } + set_volume_internal(m_volume); +} + +void AOSfxPlayer::play(QString p_sfx, QString p_char, QString shout, + int channel) +{ + m_stream_list[channel].stop(); QString misc_path = ""; QString char_path = ""; @@ -138,15 +155,21 @@ void AOSfxPlayer::play(QString p_sfx, QString p_char, QString shout) if (file_exists(f_path)) // if its missing, it will glitch out { - m_sfx.setSource(QUrl::fromLocalFile(f_path)); + m_stream_list[channel].setSource(QUrl::fromLocalFile(f_path)); set_volume_internal(m_volume); - m_sfx.play(); + m_stream_list[channel].play(); } } -void AOSfxPlayer::stop() { m_sfx.stop(); } +void AOSfxPlayer::stop(int channel) +{ + if (channel == -1) { + channel = m_channel; + } + m_stream_list[channel].stop(); +} void AOSfxPlayer::set_volume(qreal p_value) { @@ -156,8 +179,19 @@ void AOSfxPlayer::set_volume(qreal p_value) void AOSfxPlayer::set_volume_internal(qreal p_value) { - m_volume = p_value; - m_sfx.setVolume(m_volume); + float volume = static_cast(p_value); + for (int n_stream = 0; n_stream < m_channelmax; ++n_stream) { + m_stream_list[n_stream].setVolume(volume); + } +} + +void AOSfxPlayer::set_looping(bool toggle, int channel) +{ + if (channel == -1) { + channel = m_channel; + } + m_looping = toggle; + // TODO } #else void AOSfxPlayer::clear() {} From c83fd9f7323464493b76af915e974c1dc2262686 Mon Sep 17 00:00:00 2001 From: cents Date: Sat, 23 May 2020 10:41:20 -0700 Subject: [PATCH 197/268] Added backwards compatibility for the music list --- src/packet_distribution.cpp | 42 +++++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/src/packet_distribution.cpp b/src/packet_distribution.cpp index a110ec4..36593d6 100644 --- a/src/packet_distribution.cpp +++ b/src/packet_distribution.cpp @@ -478,19 +478,39 @@ void AOApplication::server_packet_received(AOPacket *p_packet) bool musics_time = false; area_count = 0; - + bool legacy_system = false; + int element_ahead = 0; for (int n_element = 0; n_element < f_contents.size(); ++n_element) { - int element2check = n_element + 1; - if (element2check > f_contents.size()) { - element2check = n_element; // I know this is very lazy code but cba + element_ahead = n_element + 1; + if (!musics_time && f_contents.at(n_element).startsWith("==") && ( + f_contents.at(element_ahead).endsWith(".wav") || + f_contents.at(element_ahead).endsWith(".mp3") || + f_contents.at(element_ahead).endsWith(".mp4") || + f_contents.at(element_ahead).endsWith(".ogg") || + f_contents.at(element_ahead).endsWith(".opus"))) { + legacy_system = true; + } - if (!musics_time && (f_contents.at(n_element).startsWith("==") || - f_contents.at(element2check).endsWith(".wav") || - f_contents.at(element2check).endsWith(".mp3") || - f_contents.at(element2check).endsWith(".mp4") || - f_contents.at(element2check).endsWith(".ogg") || - f_contents.at(element2check).endsWith(".opus"))) { - musics_time = true; + if(!legacy_system) { + if (!musics_time && (f_contents.at(n_element).startsWith("==") || + f_contents.at(element_ahead).endsWith(".wav") || + f_contents.at(element_ahead).endsWith(".mp3") || + f_contents.at(element_ahead).endsWith(".mp4") || + f_contents.at(element_ahead).endsWith(".ogg") || + f_contents.at(element_ahead).endsWith(".opus"))) { + musics_time = true; + } + } + else{ + if (!musics_time && (f_contents.at(n_element).startsWith("==") || + f_contents.at(n_element).endsWith(".wav") || + f_contents.at(n_element).endsWith(".mp3") || + f_contents.at(n_element).endsWith(".mp4") || + f_contents.at(n_element).endsWith(".ogg") || + f_contents.at(n_element).endsWith(".opus"))) { + musics_time = true; + } + } // Not everything needs to have a thread. From 8ea01d4c3139e27e84091c0b24266d9fb50ddf38 Mon Sep 17 00:00:00 2001 From: cents Date: Sat, 23 May 2020 10:44:36 -0700 Subject: [PATCH 198/268] Clanged changes --- src/courtroom.cpp | 24 +++++++++-------- src/packet_distribution.cpp | 52 ++++++++++++++++++------------------- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 4d73507..f5361ef 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -2170,8 +2170,7 @@ void Courtroom::handle_chatmessage_3() else first_message_sent = true; QString char_name = char_list.at(m_chatmessage[CHAR_ID].toInt()).name; - ui_ic_chatlog->textCursor().insertHtml("" + char_name + - ": "); + ui_ic_chatlog->textCursor().insertHtml("" + char_name + ": "); } else { if (first_message_sent && log_goes_downwards) @@ -2293,10 +2292,10 @@ QString Courtroom::filter_ic_text(QString p_text, bool skip_filter, bool delay_pop = false; while (trick_check_pos < p_text.size()) { f_character = p_text.at(trick_check_pos); - if (f_character == "<") - f_character = "<"; - else if (f_character == ">") - f_character = ">"; + if (f_character == "<") + f_character = "<"; + else if (f_character == ">") + f_character = ">"; // Escape character. if (f_character == "\\" && !ic_next_is_not_special) { ic_next_is_not_special = true; @@ -2509,9 +2508,10 @@ QString Courtroom::filter_ic_text(QString p_text, bool skip_filter, * \param p_text The text to be appended * \param p_name The name of the character/entity who sent said text * \param is_songchange Whether we are appending a song entry - * \param force_filter If we are sending plain text and we want to force the filtering regardless of its status (e.g chat entry, song change etc) - * \param skip_filter If we are sending appending text such as html so we skip the html filter - * \param chat_color The color of the message sent + * \param force_filter If we are sending plain text and we want to force the + * filtering regardless of its status (e.g chat entry, song change etc) \param + * skip_filter If we are sending appending text such as html so we skip the html + * filter \param chat_color The color of the message sent */ void Courtroom::append_ic_text(QString p_text, QString p_name, @@ -2795,7 +2795,7 @@ void Courtroom::chat_tick() chat_tick_timer->stop(); int msg_delay = message_display_speed[current_display_speed]; if (slower_blips) - msg_delay = message_display_speed_slow[current_display_speed]; + msg_delay = message_display_speed_slow[current_display_speed]; // Stops blips from playing when we have a formatting option. bool formatting_char = false; @@ -2832,7 +2832,9 @@ void Courtroom::chat_tick() f_character = f_character.toHtmlEscaped(); if (punctuation_chars.contains(f_character)) { - msg_delay *= punctuation_modifier + 1; // Since we are handling a boolean, if its true its double (1 + 1) or false (1 + 0). + msg_delay *= + punctuation_modifier + 1; // Since we are handling a boolean, if its + // true its double (1 + 1) or false (1 + 0). // ui_vp_message->insertPlainText(f_character); } diff --git a/src/packet_distribution.cpp b/src/packet_distribution.cpp index 36593d6..37231d8 100644 --- a/src/packet_distribution.cpp +++ b/src/packet_distribution.cpp @@ -482,35 +482,33 @@ void AOApplication::server_packet_received(AOPacket *p_packet) int element_ahead = 0; for (int n_element = 0; n_element < f_contents.size(); ++n_element) { element_ahead = n_element + 1; - if (!musics_time && f_contents.at(n_element).startsWith("==") && ( - f_contents.at(element_ahead).endsWith(".wav") || - f_contents.at(element_ahead).endsWith(".mp3") || - f_contents.at(element_ahead).endsWith(".mp4") || - f_contents.at(element_ahead).endsWith(".ogg") || - f_contents.at(element_ahead).endsWith(".opus"))) { - legacy_system = true; - + if (!musics_time && f_contents.at(n_element).startsWith("==") && + (f_contents.at(element_ahead).endsWith(".wav") || + f_contents.at(element_ahead).endsWith(".mp3") || + f_contents.at(element_ahead).endsWith(".mp4") || + f_contents.at(element_ahead).endsWith(".ogg") || + f_contents.at(element_ahead).endsWith(".opus"))) { + legacy_system = true; } - if(!legacy_system) { - if (!musics_time && (f_contents.at(n_element).startsWith("==") || - f_contents.at(element_ahead).endsWith(".wav") || - f_contents.at(element_ahead).endsWith(".mp3") || - f_contents.at(element_ahead).endsWith(".mp4") || - f_contents.at(element_ahead).endsWith(".ogg") || - f_contents.at(element_ahead).endsWith(".opus"))) { - musics_time = true; + if (!legacy_system) { + if (!musics_time && (f_contents.at(n_element).startsWith("==") || + f_contents.at(element_ahead).endsWith(".wav") || + f_contents.at(element_ahead).endsWith(".mp3") || + f_contents.at(element_ahead).endsWith(".mp4") || + f_contents.at(element_ahead).endsWith(".ogg") || + f_contents.at(element_ahead).endsWith(".opus"))) { + musics_time = true; + } } - } - else{ - if (!musics_time && (f_contents.at(n_element).startsWith("==") || - f_contents.at(n_element).endsWith(".wav") || - f_contents.at(n_element).endsWith(".mp3") || - f_contents.at(n_element).endsWith(".mp4") || - f_contents.at(n_element).endsWith(".ogg") || - f_contents.at(n_element).endsWith(".opus"))) { - musics_time = true; - } - + else { + if (!musics_time && (f_contents.at(n_element).startsWith("==") || + f_contents.at(n_element).endsWith(".wav") || + f_contents.at(n_element).endsWith(".mp3") || + f_contents.at(n_element).endsWith(".mp4") || + f_contents.at(n_element).endsWith(".ogg") || + f_contents.at(n_element).endsWith(".opus"))) { + musics_time = true; + } } // Not everything needs to have a thread. From 5636ddf449eaa570466133d66c79b799ebea8eb0 Mon Sep 17 00:00:00 2001 From: sD Date: Sat, 23 May 2020 20:32:12 +0200 Subject: [PATCH 199/268] give the translators something to do --- resource/translations/ao_de.ts | 964 ++++++++++++++++++++------- resource/translations/ao_en.ts | 1118 +++++++++++++++++++++----------- resource/translations/ao_es.ts | 970 ++++++++++++++++++++------- resource/translations/ao_jp.ts | 1116 +++++++++++++++++++++---------- resource/translations/ao_pl.ts | 968 +++++++++++++++++++-------- resource/translations/ao_pt.ts | 977 +++++++++++++++++++++------- resource/translations/ao_ru.ts | 978 ++++++++++++++++++++-------- 7 files changed, 5152 insertions(+), 1939 deletions(-) diff --git a/resource/translations/ao_de.ts b/resource/translations/ao_de.ts index c4e9f30..b4090bf 100644 --- a/resource/translations/ao_de.ts +++ b/resource/translations/ao_de.ts @@ -9,7 +9,7 @@ Vom Server getrennt. - + Error connecting to master server. Will try again in %1 seconds. Fehler bei der Verbindung zum Master Server. Erneuter Versuch in %1 Sekunden. @@ -18,7 +18,7 @@ Fehler bei der Verbindung zum Master Server. Erneuter Versuch in %n Sekunden. - + There was an error connecting to the master server. We deploy multiple master servers to mitigate any possible downtime, but the client appears to have exhausted all possible methods of finding and connecting to one. Please check your Internet connection and firewall, and please try again. @@ -27,68 +27,67 @@ Wir verwenden mehrere Master Server um Ausfälle zu verhindern, jedoch hat der C Bitte prüfe deine Internetverbindung und Firewall, und versuche es erneut. - + Outdated version! Your version: %1 Please go to aceattorneyonline.com to update. Version zu alt! Deine Version: %1 Bitte besuche aceattorneyonline.com für ein Update. - You have been exiled from AO. Have a nice day. - Du wurdest von AO befreit. + Du wurdest von AO befreit. Schönen Urlaub. - + Attorney Online 2 Attorney Online 2 - + Loading Laden - + Loading evidence: %1/%2 Lade Beweisstücke: %1/%2 - - + + Loading music: %1/%2 Lade Musik: %1/%2 - - + + Loading chars: %1/%2 Lade Charaktere: %1/%2 - + You have been kicked from the server. Reason: %1 Du wurdest von diesem Server geschmissen. Grund: %1 - + You have been banned from the server. Reason: %1 Du wurdest von diesem Server verbannt. Grund: %1 - + You are banned on this server. Reason: %1 Du bist von diesem Server verbannt. @@ -153,382 +152,450 @@ Grund: Stenograph benötigt - Witness needed - Zeuge benötigt + Zeuge benötigt AOOptionsDialog - + Settings Einstellungen - + Gameplay Spiel - + Theme: Theme: - + Sets the theme used in-game. If the new theme changes the lobby's look as well, you'll need to reload the lobby for the changes to take effect, such as by joining a server and leaving it. Setzt das Theme. Wenn das neue Theme auch das Aussehen der Lobby verändert, must du diese neu laden um die Änderungen zu sehen. - Gives the default value for the in-game 'Custom shownames' checkbox, which in turn determines whether the client should display custom in-character names. - Setzt den Standardwerd für den eigenen Anzeigenamen. + Setzt den Standardwerd für den eigenen Anzeigenamen. - Sets the default volume for music. - Standardlautstärke für die Musik. + Standardlautstärke für die Musik. - Sets the default volume for SFX sounds, like interjections or other character sound effects. - Standardlautstärke für Soundeffekte. + Standardlautstärke für Soundeffekte. - IC Log - Log + Log - Colorful IC log: - Farbiges Log: + Farbiges Log: - Enables colored text in the log. - Aktiviert farbigen Text im Log. + Aktiviert farbigen Text im Log. - Only inline coloring: - Nur in-Zeilen Farben: + Nur in-Zeilen Farben: - Only inline coloring will be shown such as <>,|| etc. - Nur die in-Zeilen Farben wie <>,|| etc. werden gezeigt. + Nur die in-Zeilen Farben wie <>,|| etc. werden gezeigt. - Mirror IC log: - Log spiegeln: + Log spiegeln: - IC log will mirror the IC box. Meaning that if somebody gets interrupted nobody will know what they wanted to say. Enable for a more realistic experience. - Das Log spiegelt die Nachrichten. Bedeutet dass wenn jemand unterbrochen wird, kann man nicht sehen was derjenige sagen wollte. Für ein realistischeres Spielerlebnis. + Das Log spiegelt die Nachrichten. Bedeutet dass wenn jemand unterbrochen wird, kann man nicht sehen was derjenige sagen wollte. Für ein realistischeres Spielerlebnis. - + Log goes downwards: Verlauf geht nach unten: - + If ticked, new messages will appear at the bottom (like the OOC chatlog). The traditional (AO1) behaviour is equivalent to this being unticked. Wenn angehakt werden neue Nachrichten unten erscheinen (wie beim OOC). Das traditionelle (AO1) Verhalten wäre nicht angehakt. - + Log length: Länge: - + The amount of messages the IC chatlog will keep before deleting older messages. A value of 0 or below counts as 'infinite'. Die Menge an Nachrichten die aufgehoben werden bevor alte gelöscht werden. 0 bedeutet unendlich. - + Default username: Standard Benutzername: - + Your OOC name will be automatically set to this value when you join a server. Dein OOC Name wird automatisch auf dies gesetzt. - + Custom shownames: Eigener Anzeigename: + Gives the default value for the in-game 'Custom shownames' tickbox, which in turn determines whether the client should display custom in-character names. - Standardwert für die Anzeigename Box, welche den In-Charakter Namen bestimmt. + Standardwert für die Anzeigename Box, welche den In-Charakter Namen bestimmt. - + Backup MS: Rückfall MS: - + If the built-in server lookups fail, the game will try the address given here and use it as a backup master server address. Wenn dereingebaute Master Server fehlschlägt, wird das Spiel diesen hier verwenden. - + Discord: Discord: - + Allows others on Discord to see what server you are in, what character are you playing, and how long you have been playing for. Erlaubt anderen auf Discord zu sehen auf welchem Server du spielst, welchen Charakter du spielst und wie lange. - Allow Shake/Flash: - Schütteln/Geistesblitz erlauben: + Schütteln/Geistesblitz erlauben: - Allows screenshaking and flashing. Disable this if you have concerns or issues with photosensitivity and/or seizures. - Erlaubt schütteln des Bildschirms und weiße Blitze. Deaktiviere dies falls du Bedenken wegen Photosensitivität hast. + Erlaubt schütteln des Bildschirms und weiße Blitze. Deaktiviere dies falls du Bedenken wegen Photosensitivität hast. - + Language: Sprache: - + Sets the language if you don't want to use your system language. Setzte die Sprache falls du nicht die Systemsprache verwenden möchtest. - Slower text speed: - Langsamerer Text: + Langsamerer Text: - Set the text speed to be the same as the AA games. - Setzt den Text auf die gleiche Geschwindigkeit wie in den AA Spielen. + Setzt den Text auf die gleiche Geschwindigkeit wie in den AA Spielen. - Blip delay on punctuations: - Blip Pausen bei Satzzeichen: + Blip Pausen bei Satzzeichen: - Punctuation delay modifier. Enable it for the blips to slow down on punctuations. - Aktivieren damit die Blips bei Satzzeichen langsamer werden. + Aktivieren damit die Blips bei Satzzeichen langsamer werden. - + + - Keep current setting + + + + + Allow Screenshake: + + + + + Allows screenshaking. Disable this if you have concerns or issues with photosensitivity and/or seizures. + + + + + Allow Effects: + + + + + Allows screen effects. Disable this if you have concerns or issues with photosensitivity and/or seizures. + + + + + Network Frame Effects: + + + + + Send screen-shaking, flashes and sounds as defined in the char.ini over the network. Only works for servers that support this functionality. + + + + + Colors in IC Log: + + + + + Use the markup colors in the server IC chatlog. + + + + + Sticky Sounds: + + + + + Turn this on to prevent the sound dropdown from clearing the sound after playing it. + + + + + Sticky Effects: + + + + + Turn this on to prevent the effects dropdown from clearing the effect after playing it. + + + + + Sticky Preanims: + + + + + Turn this on to prevent preanimation checkbox from clearing after playing the emote. + + + + Callwords Alarmwörter - + <html><head/><body>Enter as many callwords as you would like. These are case insensitive. Make sure to leave every callword in its own line!<br>Do not leave a line with a space at the end -- you will be alerted everytime someone uses a space in their messages.</body></html> <html><head/><body>Gib so viele Alarmwörter ein wie du möchtest. Groß/Kleinschreibung ist egal. Für jede Wort nur eine Zeile!<br>Bitte keine leere Zeile am Ende -- du bekommst sonst bei jeder Nachricht einen Alarm.</body></html> - + Audio Audio - + Audio device: Audiogerät: - + Sets the audio device for all sounds. Setzt das Audiogerät für all Geräusche. - + Music: Musik: + Sets the music's default volume. - Setzt die Musiklautstärke. + Setzt die Musiklautstärke. - + SFX: SFX: + Sets the SFX's default volume. Interjections and actual sound effects count as 'SFX'. - Setzt die Lautstärke der Soundeffekte wie Einsprüche und die Geräusche der Charaktere. + Setzt die Lautstärke der Soundeffekte wie Einsprüche und die Geräusche der Charaktere. - + Blips: Blips: - + Sets the volume of the blips, the talking sound effects. Setzt die Lautstärke der Blips, das ist das Geräusch das die Charaktere beim Reden machen. - + Blip rate: Bliprate: - + Sets the delay between playing the blip sounds. Setzt die Pause zwischen einzelnen Blips. - + + Play a blip sound "once per every X symbols", where X is the blip rate. + + + + Blank blips: Leere Blips: - + If true, the game will play a blip sound even when a space is 'being said'. Wenn angehakt wird das Spiel auch bei einem Leerzeichen einen Blip machen. - + Enable Looping SFX: Wiederholende Soundeffekte: - + If true, the game will allow looping sound effects to play on preanimations. Wenn aktiviert, werden wiederholende Soundeffekte bei den Voranimationen erlaubt. - + Kill Music On Objection: Stoppe Musik bei Einspruch: - - If true, the game will stop music when someone objects, like in the actual games. - Hält die Musik an wenn jemand "Einspruch" ruft, wie im echten Spiel. + + If true, AO2 will stop the music for you when you or someone else does 'Objection!'. + - + If true, the game will stop music when someone objects, like in the actual games. + Hält die Musik an wenn jemand "Einspruch" ruft, wie im echten Spiel. + + + Casing Fälle - + This server supports case alerts. Dieser Server unterstützt Fallalarme. - + This server does not support case alerts. Dieser Server unterstützt Fallalarme nicht. - + Pretty self-explanatory. Eigentlich selbsterklärend. - + Casing: Fälle: - + If checked, you will get alerts about case announcements. Wenn angehakt wirst du benachrichtigt wenn ein Fall angekündigt wird. - + Defense: Verteidigung: - + If checked, you will get alerts about case announcements if a defense spot is open. Wenn angehakt wirst du benachrichtigt wenn ein Verteidiger benötigt wird. - + Prosecution: Kläger: - + If checked, you will get alerts about case announcements if a prosecutor spot is open. Wenn angehakt wirst du benachrichtigt wenn ein Kläger benötigt wird. - + Judge: Richter: - + If checked, you will get alerts about case announcements if the judge spot is open. Wenn angehakt wirst du benachrichtigt wenn ein Richter benötigt wird. - + Juror: Jury: - + If checked, you will get alerts about case announcements if a juror spot is open. Wenn angehakt wirst du benachrichtigt wenn eine Jury benötigt wird. - + Stenographer: Stenograph: - + If checked, you will get alerts about case announcements if a stenographer spot is open. Wenn angehakt wirst du benachrichtigt wenn ein Stenograph benötigt wird. - + CM: CM: - + If checked, you will appear amongst the potential CMs on the server. Wenn angehakt wirst du als potentielle CM angezeigt. - Witness: - Zeuge: + Zeuge: - If checked, you will appear amongst the potential witnesses on the server. - Wenn angehakt wirst du als potentielle Zeuge angezeigt. + Wenn angehakt wirst du als potentielle Zeuge angezeigt. - + Hosting cases: Fallleitung: - + If you're a CM, enter what cases you are willing to host. Wenn du CM bist, gib ein welche Fälle du spielen möchtest. @@ -536,35 +603,36 @@ Grund: Courtroom - + Password Passwort - + Spectator Zuschauer - - + + Search Suche - + Passworded Gesperrt - + Taken Benutzt + Generating chars: %1/%2 - Generiere Charaktere: + Generiere Charaktere: %1/%2 @@ -574,193 +642,179 @@ Grund: - Could not find %1 - Konnte %1 nicht finden + Konnte %1 nicht finden - + Showname Anzeigename - + Message Nachricht - OOC Message - OOC Nachricht + OOC Nachricht - + Name Name - + Pre Vor - + Flip Spiegeln + Guard - Wache + Wache - Disable Modcalls - Deaktiviere Moderatorenrufe + Deaktiviere Moderatorenrufe - - + + Casing Fall - + Shownames Anzeigenamen - + No Interrupt Keine Unterbrechung - White - Weiß + Weiß - Green - Grün + Grün - Red - Rot + Rot - Orange - Orange + Orange - Blue - Blau + Blau - Yellow - Gelb + Gelb - + Music Musik - + Sfx Sfx - + Blips Blips - Log limit - Verlaufsgrenze + Verlaufsgrenze - - + + Server Server - + Change character Charakter ändern - + Reload theme Aussehen neu laden - + Call mod Moderator rufen - + Settings Einstellungen - + A/M A/M - + Preanim Voranimation - + Back to Lobby Zurück zur Lobby - - + You were granted the Disable Modcalls button. Du hast nun den "Modcall deaktivieren" Knopf. - + You have been banned. Du wurdest verbannt. - Too many arguments to save a case! You only need a filename without extension and the courtroom status. - Zu viele Argumente zum Speichern! Bitte gib nur den Dateinamen ohne Erweiterung und den Saalstatus an. + Zu viele Argumente zum Speichern! Bitte gib nur den Dateinamen ohne Erweiterung und den Saalstatus an. %1 has played a song: %2 %1 hat ein Lied gespielt: %2 - Rainbow - Regenbogen + Regenbogen - Pink - Pink + Pink - Cyan - Cyan + Cyan - + % offset % Abstand @@ -773,104 +827,367 @@ Grund: Dies bewirkt nichts, aber egal. - This does nothing, but there you go. - Dies bewirkt nichts, aber egal. + Dies bewirkt nichts, aber egal. - + You opened the settings menu. Du hast die Einstellungen geöffnet. - You will now pair up with - Du wirst nun mit + Du wirst nun mit - if they also choose your character in return. - gepaart, wenn der andere dies auch tut. + gepaart, wenn der andere dies auch tut. - + + None + + + + + Additive + + + + + To front + + + + + To behind + + + + + Select a character you wish to pair with. + + + + + Change the percentage offset of your character's position from the center of the screen. + + + + + Change the order of appearance for your character. + + + + + Display the list of characters to pair with. + + + + + Oops, you're muted! + + + + + Set your character's emote to play on your next message. + + + + + Set your character's supplementary background. + + + + + Set an 'iniswap', or an alternative character folder to refer to from your current character. +Edit by typing and pressing Enter, [X] to remove. This saves to your base/characters/<charname>/iniswaps.ini + + + + + + Remove the currently selected iniswap from the list and return to the original character folder. + + + + + Set a sound effect to play on your next 'Preanim'. Leaving it on Default will use the emote-defined sound (if any). +Edit by typing and pressing Enter, [X] to remove. This saves to your base/characters/<charname>/soundlist.ini + + + + + Choose an effect to play on your next spoken message. +The effects are defined in your theme/effects/effects.ini. Your character can define custom effects by +char.ini [Options] category, effects = 'miscname' where it referes to misc/<miscname>/effects.ini to read the effects. + + + + + Hold It! + + + + + + + When this is turned on, your next in-character message will be a shout! + + + + + Objection! + Einspruch! + + + + Take That! + + + + + Toggle between server chat and global AO2 chat. + + + + + + + + This will display the animation in the viewport as soon as it is pressed. + + + + + Guilty! + + + + + Bring up the Character Select Screen and change your character. + + + + + Refresh the theme and update all of the ui elements to match. + + + + + Request the attention of the current server's moderator. + + + + + Allows you to change various aspects of the client. + + + + + An interface to help you announce a case (you have to be a CM first to be able to announce cases) + + + + + Switch between Areas and Music lists + + + + + Play a single-shot animation as defined by the emote when checked. + + + + + If preanim is checked, display the input text immediately as the animation plays concurrently. + + + + + Mirror your character's emotes when checked. + + + + + Add text to your last spoken message when checked. + + + + + Do not listen to mod calls when checked, preventing them from playing sounds or focusing attention on the window. + + + + + Lets you receive case alerts when enabled. +(You can set your preferences in the Settings!) + + + + + Display customized shownames for all users when checked. + + + + + Custom Shout! + + + + + This will display the custom character-defined animation in the viewport as soon as it is pressed. +To make one, your character's folder must contain custom.[webp/apng/gif/png] and custom.[wav/ogg/opus] sound effect + + + + + Play realization sound and animation in the viewport on the next spoken message when checked. + + + + + Shake the screen on next spoken message when checked. + + + + + Display the list of character folders you wish to mute. + + + + + + Increase the health bar. + + + + + + Decrease the health bar. + + + + + Change the text color of the spoken message. +You can also select a part of your currently typed message and use the dropdown to change its color! + + + + + Return back to the server list. + + + + + Become a spectator. You won't be able to interact with the in-character screen. + + + + + + CLIENT + + + + + + + has played a song + + + + + You will now pair up with %1 if they also choose your character in return. + + + + You are no longer paired with anyone. Du bist nicht mehr gepaart. - + Are you sure you typed that well? The char ID could not be recognised. Hast du dich vertippt? Die ID konnte nicht erkannt werden. - + You have set your offset to Dein Abstand ist auf - + Your offset must be between -100% and 100%! Der Abstand muss zwischen -100% und 100% liegen! - + That offset does not look like one. Das sieht nicht wie ein Abstand aus. - + You switched your music and area list. Du hast zwischen Musik- und Gebitsliste umgeschaltet. - + You have forcefully enabled features that the server may not support. You may not be able to talk IC, or worse, because of this. Du hast Funktionen erzwungen die der Server eventuell nicht unterstützt. Möglicherweise wirst du nicht mehr sprechen können. - + Your pre-animations interrupt again. Deine Voranimation unterbrechen nun Text. - + Your pre-animations will not interrupt text. Deine Voranimation unterbrechen Text nicht. - + Couldn't open chatlog.txt to write into. Konnte chatlog.txt nicht öffnen. - + The IC chatlog has been saved. Der IC Verlauf wurde gespeichert. - + You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely the case file you're looking for can't be found in there. Du hattest keinen 'base/cases' Ordner! Ich hab ihn nun angelegt aber bedenke das er leer sein wird. - + You need to give a filename to load (extension not needed)! Make sure that it is in the `base/cases/` folder, and that it is a correctly formatted ini. Cases you can load: %1 Du musst einen Dateinamen angeben (ohne .ini). Stelle sicher das er im 'base/cases' Ordner ist und das er korrekt formatiert ist. Verfügbare Fälle: %1 - + Case made by %1. Fall von %1. - + Navigate to %1 for the CM doc. Gehe zu %1 für das CM Dokument. - + + + + + UNKNOWN + + + + Your case "%1" was loaded! Dein Fall "%1" wurde geladen! @@ -881,7 +1198,7 @@ Cases you can load: Verfügbare Fälle: - + Too many arguments to load a case! You only need one filename, without extension. Zu viele Argumente! Du brauchst nur den Dateinamen, ohne Erweiterung. @@ -906,74 +1223,234 @@ Verfügbare Fälle: " wurde geladen! - + You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely that you somehow deleted it. Du hattest keinen 'base/cases' Ordner! Ich hab ihn nun angelegt aber bedenke das er leer sein wird. - + You need to give a filename to save (extension not needed) and the courtroom status! Du musst einen Dateinamen (ohne Erweiterung) angebenn, sowie den Gebietsstatus! + Too many arguments to save a case! You only need a filename without extension and the courtroom status! - Zu viele Argumente! Du brauchst nur den Dateinamen, ohne Erweiterung sowie den Gebietsstatus! + Zu viele Argumente! Du brauchst nur den Dateinamen, ohne Erweiterung sowie den Gebietsstatus! - + Succesfully saved, edit doc and cmdoc link on the ini! Erfolgreich gespeichert! - + Master Master - + + Expand All Categories + + + + + Collapse All Categories + + + + + Fade Out Previous + + + + + Fade In + + + + + Synchronize + + + + + Default + + + + Reason: Grund: - + Call Moderator Moderator rufen - - + + Error Fehler - + You must provide a reason. Du musst einen Grund angeben. - + The message is too long. Die Nachricht ist zu lang. + Choose.. - Wähle.. + Wähle.. - Choose... - Wähle... + Wähle... - + + Present this piece of evidence to everyone on your next spoken message + + + + + Save evidence to an .ini file. + + + + + Load evidence from an .ini file. + + + + + Destroy this piece of evidence + + + + + Close the evidence display/editing overlay. +You will be prompted if there's any unsaved changes. + + + + + Save any changes made to this piece of evidence and send them to server. + + + + + Double-click to edit. Press [X] to update your changes. + + + + + Bring up the Evidence screen. + + + + + Switch evidence to private inventory. + + + + + Switch evidence to global inventory. + + + + + + Transfer evidence to private inventory. + + + + + + Transfer evidence to global inventory. + + + + + The piece of evidence you've been editing has changed. + + + + + Do you wish to keep your changes? + + + + + Name: %1 +Image: %2 +Description: +%3 + + + + Images (*.png) Bilder (*.png) - + + + + Double-click to edit... + + + + Add new evidence... Neues Beweisstück... + + + Evidence has been modified. + + + + + Do you want to save your changes? + + + + + Current evidence is global. Click to switch to private. + + + + + Current evidence is private. Click to switch to global. + + + + + "%1" has been transferred. + + + + + Save Inventory + + + + + + Ini Files (*.ini) + + + + + Open Inventory + + Discord @@ -1010,43 +1487,67 @@ Verfügbare Fälle: Attorney Online 2 - + + Search + Suche + + + Name Name - + It doesn't look like your client is set up correctly. Did you download all resources correctly from tiny.cc/getao, including the large 'base' folder? Dein Client ist nicht korrekt eingerichtet. Hast du ALLES von tiny.cc/getao heruntergeladen und entpackt, auch den großen 'base' Ordner? - + Version: %1 Version: %1 - + + Settings + Einstellungen + + + + Allows you to change various aspects of the client. + + + + Loading Laden - + Cancel Abbrechen - + + <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>2.8 Major Release development:</b><br>Crystalwarrior, Iamgoofball<p><b>2.8 Quality Assurance:</b><br>WillDean, Captain N, Mr M, Riel, Seimmet, Fury McFlurry,CedricDewitt, Chewable Tablets, Fantos, Futugaze,Geck, Minx, Pandae, Sierra, CrazyJC, CaseyMayCazy,GreenBowers, Robotic Overlord, Veritas, Gin-Gi<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, the AO2 community, server hosts, game masters,case makers, content creators and players! + + + + + About + + + <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Cents02<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, Raidensnake - <h2>Attorney Online %1</h2>Der Gerichtsdrama Simulator<p><b>Quelltext:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Leitende Entwicklung:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Cents02<p><b>Danksagungen:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, Raidensnake + <h2>Attorney Online %1</h2>Der Gerichtsdrama Simulator<p><b>Quelltext:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Leitende Entwicklung:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Cents02<p><b>Danksagungen:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, Raidensnake <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy <h2>Attorney Online %1</h2>Der Gerichtsdrama Simulator<p><b>Quelltext:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Leitende Entwicklung:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>Danksagungen:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy - + Online: %1/%2 Online: %1/%2 @@ -1091,12 +1592,27 @@ Noevain Cronnicossy - - + + Offline Offline + + chatlogpiece + + + + + UNKNOWN + + + + + has played a song: + + + debug_functions @@ -1110,7 +1626,7 @@ Cronnicossy Fehler - + Notice Hinweis diff --git a/resource/translations/ao_en.ts b/resource/translations/ao_en.ts index 9719319..ee104b9 100644 --- a/resource/translations/ao_en.ts +++ b/resource/translations/ao_en.ts @@ -9,73 +9,67 @@ - + Error connecting to master server. Will try again in %1 seconds. - + There was an error connecting to the master server. We deploy multiple master servers to mitigate any possible downtime, but the client appears to have exhausted all possible methods of finding and connecting to one. Please check your Internet connection and firewall, and please try again. - + Outdated version! Your version: %1 Please go to aceattorneyonline.com to update. - - You have been exiled from AO. -Have a nice day. - - - - + Attorney Online 2 - + Loading - + Loading evidence: %1/%2 - - + + Loading music: %1/%2 - - + + Loading chars: %1/%2 - + You have been kicked from the server. Reason: %1 - + You have been banned from the server. Reason: %1 - + You are banned on this server. Reason: %1 @@ -118,371 +112,371 @@ Reason: %1 Stenographer needed - - - Witness needed - - AOOptionsDialog - + Settings - + Gameplay - + Theme: - + Sets the theme used in-game. If the new theme changes the lobby's look as well, you'll need to reload the lobby for the changes to take effect, such as by joining a server and leaving it. - - Gives the default value for the in-game 'Custom shownames' checkbox, which in turn determines whether the client should display custom in-character names. - - - - - Sets the default volume for music. - - - - - Sets the default volume for SFX sounds, like interjections or other character sound effects. - - - - - IC Log - - - - - Colorful IC log: - - - - - Enables colored text in the log. - - - - - Only inline coloring: - - - - - Only inline coloring will be shown such as <>,|| etc. - - - - - Mirror IC log: - - - - - IC log will mirror the IC box. Meaning that if somebody gets interrupted nobody will know what they wanted to say. Enable for a more realistic experience. - - - - + Log goes downwards: - + If ticked, new messages will appear at the bottom (like the OOC chatlog). The traditional (AO1) behaviour is equivalent to this being unticked. - + Log length: - + The amount of messages the IC chatlog will keep before deleting older messages. A value of 0 or below counts as 'infinite'. - + Default username: - + Your OOC name will be automatically set to this value when you join a server. - + Custom shownames: - - Backup MS: - - - - - If the built-in server lookups fail, the game will try the address given here and use it as a backup master server address. - - - - - Discord: - - - - - Allows others on Discord to see what server you are in, what character are you playing, and how long you have been playing for. - - - - - Allow Shake/Flash: - - - - - Allows screenshaking and flashing. Disable this if you have concerns or issues with photosensitivity and/or seizures. - - - - - Language: + + Gives the default value for the in-game 'Custom shownames' tickbox, which in turn determines whether the client should display custom in-character names. - Sets the language if you don't want to use your system language. + Backup MS: - - Slower text speed: + + If the built-in server lookups fail, the game will try the address given here and use it as a backup master server address. - - Set the text speed to be the same as the AA games. + + Discord: - - Blip delay on punctuations: + + Allows others on Discord to see what server you are in, what character are you playing, and how long you have been playing for. + + + + + Language: - Punctuation delay modifier. Enable it for the blips to slow down on punctuations. + Sets the language if you don't want to use your system language. - + Callwords - + <html><head/><body>Enter as many callwords as you would like. These are case insensitive. Make sure to leave every callword in its own line!<br>Do not leave a line with a space at the end -- you will be alerted everytime someone uses a space in their messages.</body></html> - + Audio - + Audio device: - + Sets the audio device for all sounds. - + Music: - + SFX: - + Blips: - + Sets the volume of the blips, the talking sound effects. - + Blip rate: - + Sets the delay between playing the blip sounds. - + Blank blips: - + If true, the game will play a blip sound even when a space is 'being said'. - + Enable Looping SFX: - + If true, the game will allow looping sound effects to play on preanimations. - + Kill Music On Objection: - - If true, the game will stop music when someone objects, like in the actual games. + + - Keep current setting - - Casing + + Allow Screenshake: - - This server supports case alerts. + + Allows screenshaking. Disable this if you have concerns or issues with photosensitivity and/or seizures. - - This server does not support case alerts. + + Allow Effects: - - Pretty self-explanatory. + + Allows screen effects. Disable this if you have concerns or issues with photosensitivity and/or seizures. + + + + + Network Frame Effects: + + + + + Send screen-shaking, flashes and sounds as defined in the char.ini over the network. Only works for servers that support this functionality. + + + + + Colors in IC Log: + + + + + Use the markup colors in the server IC chatlog. + + + + + Sticky Sounds: + + + + + Turn this on to prevent the sound dropdown from clearing the sound after playing it. + + + + + Sticky Effects: + + + + + Turn this on to prevent the effects dropdown from clearing the effect after playing it. + + + + + Sticky Preanims: + + + + + Turn this on to prevent preanimation checkbox from clearing after playing the emote. + + + + + Sets the music's default volume. - Casing: + Sets the SFX's default volume. Interjections and actual sound effects count as 'SFX'. - - If checked, you will get alerts about case announcements. + + Play a blip sound "once per every X symbols", where X is the blip rate. - - Defense: + + If true, AO2 will stop the music for you when you or someone else does 'Objection!'. - - If checked, you will get alerts about case announcements if a defense spot is open. + + Casing - - Prosecution: + + This server supports case alerts. - - If checked, you will get alerts about case announcements if a prosecutor spot is open. - - - - - Judge: - - - - - If checked, you will get alerts about case announcements if the judge spot is open. - - - - - Juror: - - - - - If checked, you will get alerts about case announcements if a juror spot is open. - - - - - Stenographer: - - - - - If checked, you will get alerts about case announcements if a stenographer spot is open. - - - - - CM: - - - - - If checked, you will appear amongst the potential CMs on the server. - - - - - Witness: - - - - - If checked, you will appear amongst the potential witnesses on the server. - - - - - Hosting cases: + + This server does not support case alerts. + Pretty self-explanatory. + + + + + Casing: + + + + + If checked, you will get alerts about case announcements. + + + + + Defense: + + + + + If checked, you will get alerts about case announcements if a defense spot is open. + + + + + Prosecution: + + + + + If checked, you will get alerts about case announcements if a prosecutor spot is open. + + + + + Judge: + + + + + If checked, you will get alerts about case announcements if the judge spot is open. + + + + + Juror: + + + + + If checked, you will get alerts about case announcements if a juror spot is open. + + + + + Stenographer: + + + + + If checked, you will get alerts about case announcements if a stenographer spot is open. + + + + + CM: + + + + + If checked, you will appear amongst the potential CMs on the server. + + + + + Hosting cases: + + + + If you're a CM, enter what cases you are willing to host. @@ -490,381 +484,736 @@ Reason: %1 Courtroom - + Password - + Spectator - - + + Search - + Passworded - + Taken - - Could not find %1 + + Generating chars: +%1/%2 - + Showname - + Message - - OOC Message - - - - + Name - + Pre - + Flip - - + + Casing - + Shownames - + No Interrupt - - White - - - - - Green - - - - - Red - - - - - Orange - - - - - Blue - - - - - Yellow - - - - - + You were granted the Disable Modcalls button. - - This does nothing, but there you go. - - - - + You need to give a filename to load (extension not needed)! Make sure that it is in the `base/cases/` folder, and that it is a correctly formatted ini. Cases you can load: %1 - + Case made by %1. - + Navigate to %1 for the CM doc. - + Your case "%1" was loaded! - - Too many arguments to save a case! You only need a filename without extension and the courtroom status. - - - - - + + Server - + Back to Lobby - - Rainbow - - - - - Disable Modcalls - - - - - Pink - - - - - Cyan - - - - + % offset - + Music - + Sfx - + Blips - - Log limit - - - - + Change character - + Reload theme - + Call mod - + Settings - + A/M - + Preanim - + You have been banned. - + You opened the settings menu. - - You will now pair up with + + None - - if they also choose your character in return. + + Guard - + + Additive + + + + + To front + + + + + To behind + + + + + Select a character you wish to pair with. + + + + + Change the percentage offset of your character's position from the center of the screen. + + + + + Change the order of appearance for your character. + + + + + Display the list of characters to pair with. + + + + + Oops, you're muted! + + + + + Set your character's emote to play on your next message. + + + + + Set your character's supplementary background. + + + + + Set an 'iniswap', or an alternative character folder to refer to from your current character. +Edit by typing and pressing Enter, [X] to remove. This saves to your base/characters/<charname>/iniswaps.ini + + + + + + Remove the currently selected iniswap from the list and return to the original character folder. + + + + + Set a sound effect to play on your next 'Preanim'. Leaving it on Default will use the emote-defined sound (if any). +Edit by typing and pressing Enter, [X] to remove. This saves to your base/characters/<charname>/soundlist.ini + + + + + Choose an effect to play on your next spoken message. +The effects are defined in your theme/effects/effects.ini. Your character can define custom effects by +char.ini [Options] category, effects = 'miscname' where it referes to misc/<miscname>/effects.ini to read the effects. + + + + + Hold It! + + + + + + + When this is turned on, your next in-character message will be a shout! + + + + + Objection! + + + + + Take That! + + + + + Toggle between server chat and global AO2 chat. + + + + + + + + This will display the animation in the viewport as soon as it is pressed. + + + + + Guilty! + + + + + Bring up the Character Select Screen and change your character. + + + + + Refresh the theme and update all of the ui elements to match. + + + + + Request the attention of the current server's moderator. + + + + + Allows you to change various aspects of the client. + + + + + An interface to help you announce a case (you have to be a CM first to be able to announce cases) + + + + + Switch between Areas and Music lists + + + + + Play a single-shot animation as defined by the emote when checked. + + + + + If preanim is checked, display the input text immediately as the animation plays concurrently. + + + + + Mirror your character's emotes when checked. + + + + + Add text to your last spoken message when checked. + + + + + Do not listen to mod calls when checked, preventing them from playing sounds or focusing attention on the window. + + + + + Lets you receive case alerts when enabled. +(You can set your preferences in the Settings!) + + + + + Display customized shownames for all users when checked. + + + + + Custom Shout! + + + + + This will display the custom character-defined animation in the viewport as soon as it is pressed. +To make one, your character's folder must contain custom.[webp/apng/gif/png] and custom.[wav/ogg/opus] sound effect + + + + + Play realization sound and animation in the viewport on the next spoken message when checked. + + + + + Shake the screen on next spoken message when checked. + + + + + Display the list of character folders you wish to mute. + + + + + + Increase the health bar. + + + + + + Decrease the health bar. + + + + + Change the text color of the spoken message. +You can also select a part of your currently typed message and use the dropdown to change its color! + + + + + Return back to the server list. + + + + + Become a spectator. You won't be able to interact with the in-character screen. + + + + + + CLIENT + + + + + + + has played a song + + + + + You will now pair up with %1 if they also choose your character in return. + + + + You are no longer paired with anyone. - + Are you sure you typed that well? The char ID could not be recognised. - + You have set your offset to - + Your offset must be between -100% and 100%! - + That offset does not look like one. - + You switched your music and area list. - + You have forcefully enabled features that the server may not support. You may not be able to talk IC, or worse, because of this. - + Your pre-animations interrupt again. - + Your pre-animations will not interrupt text. - + Couldn't open chatlog.txt to write into. - + The IC chatlog has been saved. - + You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely the case file you're looking for can't be found in there. - + Too many arguments to load a case! You only need one filename, without extension. - + + + + + UNKNOWN + + + + You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely that you somehow deleted it. - + You need to give a filename to save (extension not needed) and the courtroom status! - + + Too many arguments to save a case! You only need a filename without extension and the courtroom status! + + + + Succesfully saved, edit doc and cmdoc link on the ini! - + Master - + + Expand All Categories + + + + + Collapse All Categories + + + + + Fade Out Previous + + + + + Fade In + + + + + Synchronize + + + + + Default + + + + Reason: - + Call Moderator - - + + Error - + You must provide a reason. - + The message is too long. - - Choose... + + Present this piece of evidence to everyone on your next spoken message - + + Save evidence to an .ini file. + + + + + Load evidence from an .ini file. + + + + + Destroy this piece of evidence + + + + + Choose.. + + + + + Close the evidence display/editing overlay. +You will be prompted if there's any unsaved changes. + + + + + Save any changes made to this piece of evidence and send them to server. + + + + + Double-click to edit. Press [X] to update your changes. + + + + + Bring up the Evidence screen. + + + + + Switch evidence to private inventory. + + + + + Switch evidence to global inventory. + + + + + + Transfer evidence to private inventory. + + + + + + Transfer evidence to global inventory. + + + + + The piece of evidence you've been editing has changed. + + + + + Do you wish to keep your changes? + + + + + Name: %1 +Image: %2 +Description: +%3 + + + + Images (*.png) - + + + + Double-click to edit... + + + + Add new evidence... + + + Evidence has been modified. + + + + + Do you want to save your changes? + + + + + Current evidence is global. Click to switch to private. + + + + + Current evidence is private. Click to switch to global. + + + + + "%1" has been transferred. + + + + + Save Inventory + + + + + + Ini Files (*.ini) + + + + + Open Inventory + + Lobby @@ -874,48 +1223,83 @@ Cases you can load: %1 - + + Search + + + + Name - + It doesn't look like your client is set up correctly. Did you download all resources correctly from tiny.cc/getao, including the large 'base' folder? - + Version: %1 - + + Settings + + + + + Allows you to change various aspects of the client. + + + + Loading - + Cancel - - <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Cents02<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, Raidensnake + + <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>2.8 Major Release development:</b><br>Crystalwarrior, Iamgoofball<p><b>2.8 Quality Assurance:</b><br>WillDean, Captain N, Mr M, Riel, Seimmet, Fury McFlurry,CedricDewitt, Chewable Tablets, Fantos, Futugaze,Geck, Minx, Pandae, Sierra, CrazyJC, CaseyMayCazy,GreenBowers, Robotic Overlord, Veritas, Gin-Gi<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, the AO2 community, server hosts, game masters,case makers, content creators and players! - + + About + + + + Online: %1/%2 - - + + Offline + + chatlogpiece + + + + + UNKNOWN + + + + + has played a song: + + + debug_functions @@ -929,7 +1313,7 @@ Did you download all resources correctly from tiny.cc/getao, including the large - + Notice diff --git a/resource/translations/ao_es.ts b/resource/translations/ao_es.ts index 2cad7ce..3d456a5 100644 --- a/resource/translations/ao_es.ts +++ b/resource/translations/ao_es.ts @@ -9,12 +9,12 @@ Desconectado del servidor. - + Error connecting to master server. Will try again in %1 seconds. Error al conectarse a la lista de servidores. Se intentará nuevamente en %1 segundos. - + There was an error connecting to the master server. We deploy multiple master servers to mitigate any possible downtime, but the client appears to have exhausted all possible methods of finding and connecting to one. Please check your Internet connection and firewall, and please try again. @@ -22,68 +22,67 @@ Please check your Internet connection and firewall, and please try again.Hubo un error al obtener la lista de servidores. Verifique su conexión a Internet y firewall, y vuelva a intentarlo. - + Outdated version! Your version: %1 Please go to aceattorneyonline.com to update. ¡Versión desactualizada! Su versión: %1 Ingrese a aceattorneyonline.com para actualizar. - You have been exiled from AO. Have a nice day. - Has sido exiliado de AO. + Has sido exiliado de AO. Que tengas un buen día. - + Attorney Online 2 - + Loading Cargando - + Loading evidence: %1/%2 Cargando evidencia: %1/%2 - - + + Loading music: %1/%2 Cargando música: %1/%2 - - + + Loading chars: %1/%2 Cargando personajes: %1/%2 - + You have been kicked from the server. Reason: %1 Has sido expulsado del servidor. Razón: %1 - + You have been banned from the server. Reason: %1 Has sido bloqueado de este servidor. Razón: %1 - + You are banned on this server. Reason: %1 Has sido bloqueado en este servidor. @@ -140,392 +139,456 @@ Razón: Se necesita taquígrafo - Witness needed - Se necesita testigo + Se necesita testigo AOOptionsDialog - + Settings Ajustes - + Gameplay Jugabilidad - + Theme: Tema visual: - + Sets the theme used in-game. If the new theme changes the lobby's look as well, you'll need to reload the lobby for the changes to take effect, such as by joining a server and leaving it. Establece el tema visual utilizado en el juego. Si el nuevo tema también cambia el aspecto del lobby, deberá volver a cargar el lobby para que los cambios surtan efecto, como unirse a un servidor y volver al lobby. - + Log goes downwards: Invertir historial IC: - + If ticked, new messages will appear at the bottom (like the OOC chatlog). The traditional (AO1) behaviour is equivalent to this being unticked. Si está marcado, los nuevos mensajes aparecerán en la parte inferior (como el chat OOC). - + Log length: Limite del historial: - + The amount of messages the IC chatlog will keep before deleting older messages. A value of 0 or below counts as 'infinite'. La cantidad de mensajes que mantendrá el historial del chat IC antes de eliminar mensajes más antiguos. 0 significa 'infinito'. - + Default username: Usuario predeterminado: - + Your OOC name will be automatically set to this value when you join a server. Su nombre OOC se establecerá automáticamente a este cuando se una a un servidor. - + Custom shownames: Mostrar nombres: + Gives the default value for the in-game 'Custom shownames' tickbox, which in turn determines whether the client should display custom in-character names. - Activa la casilla 'Mostrar nombres' de forma predeterminada en el juego, que a su vez determina si el cliente debe mostrar nombres personalizados en los personajes. + Activa la casilla 'Mostrar nombres' de forma predeterminada en el juego, que a su vez determina si el cliente debe mostrar nombres personalizados en los personajes. - + Backup MS: Master SV de respaldo: - + If the built-in server lookups fail, the game will try the address given here and use it as a backup master server address. Si la lista de servidores predeterminada falla, el juego probará la dirección proporcionada aquí. - + Discord: Discord: - + Allows others on Discord to see what server you are in, what character are you playing, and how long you have been playing for. Permite a otros en Discord ver en qué servidor estás, qué personaje juegas y cuánto tiempo has estado jugando. - Allow Shake/Flash: - Permitir Shake/Flash: + Permitir Shake/Flash: - Allows screenshaking and flashing. Disable this if you have concerns or issues with photosensitivity and/or seizures. - Permite el movimiento de la pantalla y el parpadeo. Desactive esto si tiene inquietudes o problemas con la fotosensibilidad y/o convulsiones. + Permite el movimiento de la pantalla y el parpadeo. Desactive esto si tiene inquietudes o problemas con la fotosensibilidad y/o convulsiones. - + Language: Idioma: - + Sets the language if you don't want to use your system language. Establece el idioma si no desea utilizar el idioma de su sistema. - Punctuation delay modifier. Enable it for the blips to slow down on punctuations. - Habilítelo para agregar una pequeña pausa en los signos de puntuación. + Habilítelo para agregar una pequeña pausa en los signos de puntuación. - + Callwords Palabras clave - + <html><head/><body>Enter as many callwords as you would like. These are case insensitive. Make sure to leave every callword in its own line!<br>Do not leave a line with a space at the end -- you will be alerted everytime someone uses a space in their messages.</body></html> <html><head/><body>Ingrese tantas palabras de llamada como desee.<br>Esto no distingue entre mayúsculas y minúsculas. ¡Asegúrese de dejar cada palabra en su propia línea!<br>No deje una línea con un espacio al final; recibirá una alerta cada vez que alguien use un espacio en sus mensajes.</body></html> - + Audio Audio - + Audio device: Dispositivo: - + Sets the audio device for all sounds. Establece el dispositivo de audio. - + Music: Música: + Sets the music's default volume. - Establece el volumen predeterminado de la música. + Establece el volumen predeterminado de la música. - + SFX: SFX: + Sets the SFX's default volume. Interjections and actual sound effects count as 'SFX'. - Establece el volumen predeterminado de SFX. Las interjecciones y los efectos de sonido reales cuentan como 'SFX'. + Establece el volumen predeterminado de SFX. Las interjecciones y los efectos de sonido reales cuentan como 'SFX'. - Gives the default value for the in-game 'Custom shownames' checkbox, which in turn determines whether the client should display custom in-character names. - Activa la casilla 'Mostrar nombres' de forma predeterminada en el juego, que a su vez determina si el cliente debe mostrar nombres personalizados en los personajes. + Activa la casilla 'Mostrar nombres' de forma predeterminada en el juego, que a su vez determina si el cliente debe mostrar nombres personalizados en los personajes. - Slower text speed: - Texto más lento: + Texto más lento: - Set the text speed to be the same as the AA games. - La velocidad del texto será la misma que en los juegos de AA. + La velocidad del texto será la misma que en los juegos de AA. - Blip delay on punctuations: - Retraso en puntuación: + Retraso en puntuación: - Sets the default volume for music. - Establece el volumen predeterminado de la música. + Establece el volumen predeterminado de la música. - Sets the default volume for SFX sounds, like interjections or other character sound effects. - Establece el volumen predeterminado para sonidos SFX, como las interjecciones y otros efectos de sonido de personajes. + Establece el volumen predeterminado para sonidos SFX, como las interjecciones y otros efectos de sonido de personajes. - + Blips: Blips: - + Sets the volume of the blips, the talking sound effects. Establece el volumen de los blips, el sonido al hablar. - + Blip rate: Tasa de blips: - + Sets the delay between playing the blip sounds. Establece el retraso entre la reproducción de los sonidos blip. - + Blank blips: Blips en blanco: - + If true, the game will play a blip sound even when a space is 'being said'. Si está marcada, el juego reproducirá un sonido blip incluso cuando se 'dice' un espacio. - + Enable Looping SFX: Habilitar repetición de SFX: - + If true, the game will allow looping sound effects to play on preanimations. Si está habilitado, el juego permitirá que se reproduzcan efectos de sonido en bucle en preanimaciones. - + Kill Music On Objection: Parar la música al objetar: - If true, the game will stop music when someone objects, like in the actual games. - Si está habilitado, el juego detendrá la música cuando alguien haga una objeción, como en los juegos. + Si está habilitado, el juego detendrá la música cuando alguien haga una objeción, como en los juegos. - + + - Keep current setting + + + + + Allow Screenshake: + + + + + Allows screenshaking. Disable this if you have concerns or issues with photosensitivity and/or seizures. + + + + + Allow Effects: + + + + + Allows screen effects. Disable this if you have concerns or issues with photosensitivity and/or seizures. + + + + + Network Frame Effects: + + + + + Send screen-shaking, flashes and sounds as defined in the char.ini over the network. Only works for servers that support this functionality. + + + + + Colors in IC Log: + + + + + Use the markup colors in the server IC chatlog. + + + + + Sticky Sounds: + + + + + Turn this on to prevent the sound dropdown from clearing the sound after playing it. + + + + + Sticky Effects: + + + + + Turn this on to prevent the effects dropdown from clearing the effect after playing it. + + + + + Sticky Preanims: + + + + + Turn this on to prevent preanimation checkbox from clearing after playing the emote. + + + + + Play a blip sound "once per every X symbols", where X is the blip rate. + + + + + If true, AO2 will stop the music for you when you or someone else does 'Objection!'. + + + + Casing Caso - + This server supports case alerts. Este servidor admite alertas de casos. - + This server does not support case alerts. Este servidor no admite alertas de casos. - + Pretty self-explanatory. Bastante autoexplicativo. - + Casing: Caso: - + If checked, you will get alerts about case announcements. Si está marcado, recibirá anuncios de casos. - + Defense: Abogado: - + If checked, you will get alerts about case announcements if a defense spot is open. Si está marcado, recibirá alertas sobre anuncios de casos si hay un lugar de abogado libre. - + Prosecution: Fiscal: - + If checked, you will get alerts about case announcements if a prosecutor spot is open. Si está marcada, recibirá alertas sobre anuncios de casos si hay un puesto de fiscal libre. - + Judge: Juez: - + If checked, you will get alerts about case announcements if the judge spot is open. Si está marcado, recibirá alertas sobre anuncios de casos si el puesto de juez está libre. - + Juror: Jurado: - + If checked, you will get alerts about case announcements if a juror spot is open. Si está marcado, recibirá alertas sobre anuncios de casos si hay un puesto de jurado libre. - + Stenographer: Taquígrafo: - + If checked, you will get alerts about case announcements if a stenographer spot is open. Si está marcado, recibirá alertas sobre anuncios de casos si hay un lugar de taquígrafo libre. - + CM: CM: - + If checked, you will appear amongst the potential CMs on the server. Si está marcado, aparecerá entre los posibles CM en el servidor. - Witness: - Testigo: + Testigo: - If checked, you will appear amongst the potential witnesses on the server. - Si está marcado, aparecerá entre los posibles testigos en el servidor. + Si está marcado, aparecerá entre los posibles testigos en el servidor. - + Hosting cases: Casos: - + If you're a CM, enter what cases you are willing to host. Si eres un CM, ingresa qué casos estás dispuesto a organizar. - - IC Log - - - - Only inline coloring will be shown such as <>,|| etc. - Solo se mostrará el color en línea, como <>, ||, etc. + Solo se mostrará el color en línea, como <>, ||, etc. - IC log will mirror the IC box. Meaning that if somebody gets interrupted nobody will know what they wanted to say. Enable for a more realistic experience. - El registro de IC reflejará el chat In-Character. Lo que significa que si alguien es interrumpido, nadie sabrá lo que se iba a decir. Habilitar para una experiencia más realista. + El registro de IC reflejará el chat In-Character. Lo que significa que si alguien es interrumpido, nadie sabrá lo que se iba a decir. Habilitar para una experiencia más realista. IC log will mirror the IC box. Meaning that if somebody gets interrupted nobody will know what they wanted to say. Enable for a more realistic experience El registro de IC reflejará el chat In-Character. Lo que significa que si alguien es interrumpido, nadie sabrá lo que se iba a decir. Habilitar para una experiencia más realista. - Colorful IC log: - Log IC colorido: + Log IC colorido: - Enables colored text in the log. - Habilita texto con color en el log. + Habilita texto con color en el log. - Only inline coloring: - Solo coloración en línea: + Solo coloración en línea: Only inline coloring will be shown such as <>,|| etc Solo se mostrará el color en línea, como <>, ||, etc. - Mirror IC log: - IC log refleja interrupciones: + IC log refleja interrupciones: IC log will mirror the IC box. Meaning that if somebody gets interupted nobody will know what they wanted to say. Enable for a more realistic expierence @@ -535,41 +598,41 @@ Razón: Courtroom - + Password Contraseña - + Spectator Espectador - - + + Search Buscar - + Passworded A translation wouldn't fit because of the shitty theme system. - + Taken En uso - Could not find %1 - No se pudo encontrar %1 + No se pudo encontrar %1 + Generating chars: %1/%2 - Generando personajes: + Generando personajes: %1/%2 @@ -579,170 +642,156 @@ Razón: - + Showname A translation wouldn't fit because of the shitty theme system. - + Message Mensaje - + Name Nombre - + Pre A translation wouldn't fit because of the shitty theme system. - + Flip A translation wouldn't fit because of the shitty theme system. + Guard - Guardia + Guardia - - + + Casing This could be translated as 'caso' and it wouldn't get cut, but there are so many other buttons that can't be translated on the courtroom window that might as well leave this also untranslated so it's at least consistent. - + Shownames A translation wouldn't fit because of the shitty theme system. - + No Interrupt A translation wouldn't fit because of the shitty theme system. - White - Blanco + Blanco - Green - Verde + Verde - Red - Rojo + Rojo - Orange - Naranja + Naranja - Blue - Azul + Azul - Yellow - Amarillo + Amarillo - Rainbow - Arcoíris + Arcoíris - Pink - Rosado + Rosado - Cyan - Cian + Cian - + % offset % desplazamiento - + Music - + Sfx - + Blips - - Log limit - - - - + Change character - + Reload theme - + Call mod - + Settings - + A/M - + Preanim - + Back to Lobby 'Volver al lobby' got cut, changed to just Lobby Lobby - - + You were granted the Disable Modcalls button. Se le concedió el botón para deshabilitar llamadas a moderadores. - + You have been banned. Has sido vetado. @@ -751,107 +800,400 @@ Razón: Te ha sido otorgado el botón Guardia. - This does nothing, but there you go. - Esto no hace nada, pero ahí lo tienes. + Esto no hace nada, pero ahí lo tienes. - + You opened the settings menu. Abriste el menú de configuración. - You will now pair up with - Ahora te emparejarás con + Ahora te emparejarás con - if they also choose your character in return. - si ellos también eligen a tu personaje a cambio. + si ellos también eligen a tu personaje a cambio. - + + None + + + + + Additive + + + + + To front + + + + + To behind + + + + + Select a character you wish to pair with. + + + + + Change the percentage offset of your character's position from the center of the screen. + + + + + Change the order of appearance for your character. + + + + + Display the list of characters to pair with. + + + + + Oops, you're muted! + + + + + Set your character's emote to play on your next message. + + + + + Set your character's supplementary background. + + + + + Set an 'iniswap', or an alternative character folder to refer to from your current character. +Edit by typing and pressing Enter, [X] to remove. This saves to your base/characters/<charname>/iniswaps.ini + + + + + + Remove the currently selected iniswap from the list and return to the original character folder. + + + + + Set a sound effect to play on your next 'Preanim'. Leaving it on Default will use the emote-defined sound (if any). +Edit by typing and pressing Enter, [X] to remove. This saves to your base/characters/<charname>/soundlist.ini + + + + + Choose an effect to play on your next spoken message. +The effects are defined in your theme/effects/effects.ini. Your character can define custom effects by +char.ini [Options] category, effects = 'miscname' where it referes to misc/<miscname>/effects.ini to read the effects. + + + + + Hold It! + + + + + + + When this is turned on, your next in-character message will be a shout! + + + + + Objection! + + + + + Take That! + + + + + Toggle between server chat and global AO2 chat. + + + + + + + + This will display the animation in the viewport as soon as it is pressed. + + + + + Guilty! + + + + + Bring up the Character Select Screen and change your character. + + + + + Refresh the theme and update all of the ui elements to match. + + + + + Request the attention of the current server's moderator. + + + + + Allows you to change various aspects of the client. + + + + + An interface to help you announce a case (you have to be a CM first to be able to announce cases) + + + + + Switch between Areas and Music lists + + + + + Play a single-shot animation as defined by the emote when checked. + + + + + If preanim is checked, display the input text immediately as the animation plays concurrently. + + + + + Mirror your character's emotes when checked. + + + + + Add text to your last spoken message when checked. + + + + + Do not listen to mod calls when checked, preventing them from playing sounds or focusing attention on the window. + + + + + Lets you receive case alerts when enabled. +(You can set your preferences in the Settings!) + + + + + Display customized shownames for all users when checked. + + + + + Custom Shout! + + + + + This will display the custom character-defined animation in the viewport as soon as it is pressed. +To make one, your character's folder must contain custom.[webp/apng/gif/png] and custom.[wav/ogg/opus] sound effect + + + + + Play realization sound and animation in the viewport on the next spoken message when checked. + + + + + Shake the screen on next spoken message when checked. + + + + + Display the list of character folders you wish to mute. + + + + + + Increase the health bar. + + + + + + Decrease the health bar. + + + + + Change the text color of the spoken message. +You can also select a part of your currently typed message and use the dropdown to change its color! + + + + + Return back to the server list. + + + + + Become a spectator. You won't be able to interact with the in-character screen. + + + + + + CLIENT + + + + + + + has played a song + + + + + You will now pair up with %1 if they also choose your character in return. + + + + You are no longer paired with anyone. Ya no estás emparejado con nadie. - + Are you sure you typed that well? The char ID could not be recognised. ¿Estás seguro de que lo escribiste bien? El ID de personaje no pudo ser reconocido. - + You have set your offset to Ha configurado su desplazamiento en - + Your offset must be between -100% and 100%! ¡Su desplazamiento debe estar entre -100% y 100%! - + That offset does not look like one. Ese desplazamiento no se parece a uno. - + You switched your music and area list. Cambiaste tu lista de música y área. - + You have forcefully enabled features that the server may not support. You may not be able to talk IC, or worse, because of this. Ha habilitado forzosamente funciones que el servidor puede no admitir. Es posible que no pueda hablar IC, o peor, debido a esto. - + Your pre-animations interrupt again. Sus pre-animaciones interrumpen de nuevo. - + Your pre-animations will not interrupt text. Sus pre-animaciones no interrumpirán el texto. - + Couldn't open chatlog.txt to write into. No se pudo abrir chatlog.txt para escribir. - + The IC chatlog has been saved. El chat IC se ha guardado. - + You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely the case file you're looking for can't be found in there. ¡No tienes una carpeta `base/cases /`! Ha sido creada para ti. Pero debido a que no existia la carpeta, tampoco habían casos guardados ahí. - + You need to give a filename to load (extension not needed)! Make sure that it is in the `base/cases/` folder, and that it is a correctly formatted ini. Cases you can load: %1 ¡Debe dar un nombre de archivo para cargar (no se necesita extensión)! Asegúrese de que esté en la carpeta `base/cases/` y de que tenga el formato correcto. Casos que puede cargar: %1 - + Case made by %1. Caso hecho por %1. - + Navigate to %1 for the CM doc. Navegue a %1 para el documento del CM. - + + + + + UNKNOWN + + + + Your case "%1" was loaded! Su caso "%1" fue cargado! + + + Expand All Categories + + + + + Collapse All Categories + + + + + Fade Out Previous + + + + + Fade In + + + + + Synchronize + + + + + Default + + You need to give a filename to load (extension not needed)! Make sure that it is in the `base/cases/` folder, and that it is a correctly formatted ini. Cases you can load: @@ -859,7 +1201,7 @@ Cases you can load: Casos que puede cargar: - + Too many arguments to load a case! You only need one filename, without extension. ¡Demasiados argumentos para cargar un caso! Solo necesita un nombre de archivo, sin extensión. @@ -884,92 +1226,219 @@ Casos que puede cargar: " fue cargado! - + You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely that you somehow deleted it. ¡No tienes una carpeta `base/cases /`! Fue creada para ti. - + You need to give a filename to save (extension not needed) and the courtroom status! ¡Debe dar un nombre de archivo para guardar (no se necesita la extensión) y el estado de la sala del tribunal! + Too many arguments to save a case! You only need a filename without extension and the courtroom status! why two exclamations, seems excesive. - ¡Demasiados argumentos para salvar un caso! Solo necesita un nombre de archivo sin extensión y el estado de la sala del tribunal. + ¡Demasiados argumentos para salvar un caso! Solo necesita un nombre de archivo sin extensión y el estado de la sala del tribunal. - + Succesfully saved, edit doc and cmdoc link on the ini! ¡Guardado con éxito, puede editar el doc y doc link en el archivo ini! - + Master - - + + Server - OOC Message - Mensaje OOC + Mensaje OOC - - Disable Modcalls - - - - Too many arguments to save a case! You only need a filename without extension and the courtroom status. - ¡Demasiados argumentos para salvar un caso! Solo necesita un nombre de archivo sin extensión y el estado de la sala del tribunal. + ¡Demasiados argumentos para salvar un caso! Solo necesita un nombre de archivo sin extensión y el estado de la sala del tribunal. - + Reason: Razón: - + Call Moderator Llamar Moderador - - + + Error Error - + You must provide a reason. Debes proporcionar una razón. - + The message is too long. El mensaje es muy largo. - Choose... - Elegir... + Elegir... - + + Present this piece of evidence to everyone on your next spoken message + + + + + Save evidence to an .ini file. + + + + + Load evidence from an .ini file. + + + + + Destroy this piece of evidence + + + + + Choose.. + + + + + Close the evidence display/editing overlay. +You will be prompted if there's any unsaved changes. + + + + + Save any changes made to this piece of evidence and send them to server. + + + + + Double-click to edit. Press [X] to update your changes. + + + + + Bring up the Evidence screen. + + + + + Switch evidence to private inventory. + + + + + Switch evidence to global inventory. + + + + + + Transfer evidence to private inventory. + + + + + + Transfer evidence to global inventory. + + + + + The piece of evidence you've been editing has changed. + + + + + Do you wish to keep your changes? + + + + + Name: %1 +Image: %2 +Description: +%3 + + + + Images (*.png) Imágenes (* .png) - + + + + Double-click to edit... + + + + Add new evidence... Añadir nueva evidencia... + + + Evidence has been modified. + + + + + Do you want to save your changes? + + + + + Current evidence is global. Click to switch to private. + + + + + Current evidence is private. Click to switch to global. + + + + + "%1" has been transferred. + + + + + Save Inventory + + + + + + Ini Files (*.ini) + + + + + Open Inventory + + Lobby @@ -979,53 +1448,92 @@ Casos que puede cargar: - + + Search + Buscar + + + Name Nombre - + It doesn't look like your client is set up correctly. Did you download all resources correctly from tiny.cc/getao, including the large 'base' folder? No parece que su cliente esté configurado correctamente. ¿Descargó todos los recursos correctamente desde tiny.cc/getao, incluida la gran carpeta 'base'? - + Version: %1 Versión: %1 - + + Settings + Ajustes + + + + Allows you to change various aspects of the client. + + + + Loading Cargando - + Cancel Cancelar - + + <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>2.8 Major Release development:</b><br>Crystalwarrior, Iamgoofball<p><b>2.8 Quality Assurance:</b><br>WillDean, Captain N, Mr M, Riel, Seimmet, Fury McFlurry,CedricDewitt, Chewable Tablets, Fantos, Futugaze,Geck, Minx, Pandae, Sierra, CrazyJC, CaseyMayCazy,GreenBowers, Robotic Overlord, Veritas, Gin-Gi<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, the AO2 community, server hosts, game masters,case makers, content creators and players! + + + + + About + + + <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Cents02<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, Raidensnake - <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Cents02<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, Raidensnake + <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Cents02<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, Raidensnake <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy <h2>Attorney Online %1</h2>El simulador de drama legal<p><b>Código fuente:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https: //github.com/AttorneyOnline/AO2-Client</a><p><b>Desarrollo mayor:</b> <br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>Agradecimiento especial:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (diseño de interfaz de usuario), Draxirch (diseño de interfaz de usuario), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy - + Online: %1/%2 En línea: %1/%2 - - + + Offline Fuera de línea + + chatlogpiece + + + + + UNKNOWN + + + + + has played a song: + + + debug_functions @@ -1039,7 +1547,7 @@ Did you download all resources correctly from tiny.cc/getao, including the large - + Notice In spanish it would be "Aviso", but i believe it's going to be more useful for bug reports to not translate any debug string. diff --git a/resource/translations/ao_jp.ts b/resource/translations/ao_jp.ts index 029e84a..a6594de 100644 --- a/resource/translations/ao_jp.ts +++ b/resource/translations/ao_jp.ts @@ -9,73 +9,67 @@ - + Error connecting to master server. Will try again in %1 seconds. - + There was an error connecting to the master server. We deploy multiple master servers to mitigate any possible downtime, but the client appears to have exhausted all possible methods of finding and connecting to one. Please check your Internet connection and firewall, and please try again. - + Outdated version! Your version: %1 Please go to aceattorneyonline.com to update. - - You have been exiled from AO. -Have a nice day. - - - - + Attorney Online 2 - + Loading ロード中 - + Loading evidence: %1/%2 証拠がロード中: %1/%2 - - + + Loading music: %1/%2 音楽がロード中: %1/%2 - - + + Loading chars: %1/%2 キャラがロード中: %1/%2 - + You have been kicked from the server. Reason: %1 - + You have been banned from the server. Reason: %1 - + You are banned on this server. Reason: %1 @@ -118,371 +112,371 @@ Reason: %1 Stenographer needed - - - Witness needed - - AOOptionsDialog - + Settings - + Gameplay - + Theme: - + Sets the theme used in-game. If the new theme changes the lobby's look as well, you'll need to reload the lobby for the changes to take effect, such as by joining a server and leaving it. - - Gives the default value for the in-game 'Custom shownames' checkbox, which in turn determines whether the client should display custom in-character names. - - - - - Sets the default volume for music. - - - - - Sets the default volume for SFX sounds, like interjections or other character sound effects. - - - - - IC Log - - - - - Colorful IC log: - - - - - Enables colored text in the log. - - - - - Only inline coloring: - - - - - Only inline coloring will be shown such as <>,|| etc. - - - - - Mirror IC log: - - - - - IC log will mirror the IC box. Meaning that if somebody gets interrupted nobody will know what they wanted to say. Enable for a more realistic experience. - - - - + Log goes downwards: - + If ticked, new messages will appear at the bottom (like the OOC chatlog). The traditional (AO1) behaviour is equivalent to this being unticked. - + Log length: - + The amount of messages the IC chatlog will keep before deleting older messages. A value of 0 or below counts as 'infinite'. - + Default username: - + Your OOC name will be automatically set to this value when you join a server. - + Custom shownames: - - Backup MS: - - - - - If the built-in server lookups fail, the game will try the address given here and use it as a backup master server address. - - - - - Discord: - - - - - Allows others on Discord to see what server you are in, what character are you playing, and how long you have been playing for. - - - - - Allow Shake/Flash: - - - - - Allows screenshaking and flashing. Disable this if you have concerns or issues with photosensitivity and/or seizures. - - - - - Language: + + Gives the default value for the in-game 'Custom shownames' tickbox, which in turn determines whether the client should display custom in-character names. - Sets the language if you don't want to use your system language. + Backup MS: - - Slower text speed: + + If the built-in server lookups fail, the game will try the address given here and use it as a backup master server address. - - Set the text speed to be the same as the AA games. + + Discord: - - Blip delay on punctuations: + + Allows others on Discord to see what server you are in, what character are you playing, and how long you have been playing for. + + + + + Language: - Punctuation delay modifier. Enable it for the blips to slow down on punctuations. + Sets the language if you don't want to use your system language. - + Callwords - + <html><head/><body>Enter as many callwords as you would like. These are case insensitive. Make sure to leave every callword in its own line!<br>Do not leave a line with a space at the end -- you will be alerted everytime someone uses a space in their messages.</body></html> - + Audio - + Audio device: - + Sets the audio device for all sounds. - + Music: 音楽: - + SFX: 効果音: - + Blips: ブリップ: - + Sets the volume of the blips, the talking sound effects. - + Blip rate: - + Sets the delay between playing the blip sounds. - + Blank blips: - + If true, the game will play a blip sound even when a space is 'being said'. - + Enable Looping SFX: - + If true, the game will allow looping sound effects to play on preanimations. - + Kill Music On Objection: - - If true, the game will stop music when someone objects, like in the actual games. + + - Keep current setting - - Casing + + Allow Screenshake: - - This server supports case alerts. + + Allows screenshaking. Disable this if you have concerns or issues with photosensitivity and/or seizures. - - This server does not support case alerts. + + Allow Effects: - - Pretty self-explanatory. + + Allows screen effects. Disable this if you have concerns or issues with photosensitivity and/or seizures. + + + + + Network Frame Effects: + + + + + Send screen-shaking, flashes and sounds as defined in the char.ini over the network. Only works for servers that support this functionality. + + + + + Colors in IC Log: + + + + + Use the markup colors in the server IC chatlog. + + + + + Sticky Sounds: + + + + + Turn this on to prevent the sound dropdown from clearing the sound after playing it. + + + + + Sticky Effects: + + + + + Turn this on to prevent the effects dropdown from clearing the effect after playing it. + + + + + Sticky Preanims: + + + + + Turn this on to prevent preanimation checkbox from clearing after playing the emote. + + + + + Sets the music's default volume. - Casing: + Sets the SFX's default volume. Interjections and actual sound effects count as 'SFX'. - - If checked, you will get alerts about case announcements. + + Play a blip sound "once per every X symbols", where X is the blip rate. - - Defense: + + If true, AO2 will stop the music for you when you or someone else does 'Objection!'. - - If checked, you will get alerts about case announcements if a defense spot is open. + + Casing - - Prosecution: + + This server supports case alerts. - - If checked, you will get alerts about case announcements if a prosecutor spot is open. - - - - - Judge: - - - - - If checked, you will get alerts about case announcements if the judge spot is open. - - - - - Juror: - - - - - If checked, you will get alerts about case announcements if a juror spot is open. - - - - - Stenographer: - - - - - If checked, you will get alerts about case announcements if a stenographer spot is open. - - - - - CM: - - - - - If checked, you will appear amongst the potential CMs on the server. - - - - - Witness: - - - - - If checked, you will appear amongst the potential witnesses on the server. - - - - - Hosting cases: + + This server does not support case alerts. + Pretty self-explanatory. + + + + + Casing: + + + + + If checked, you will get alerts about case announcements. + + + + + Defense: + + + + + If checked, you will get alerts about case announcements if a defense spot is open. + + + + + Prosecution: + + + + + If checked, you will get alerts about case announcements if a prosecutor spot is open. + + + + + Judge: + + + + + If checked, you will get alerts about case announcements if the judge spot is open. + + + + + Juror: + + + + + If checked, you will get alerts about case announcements if a juror spot is open. + + + + + Stenographer: + + + + + If checked, you will get alerts about case announcements if a stenographer spot is open. + + + + + CM: + + + + + If checked, you will appear amongst the potential CMs on the server. + + + + + Hosting cases: + + + + If you're a CM, enter what cases you are willing to host. @@ -490,385 +484,776 @@ Reason: %1 Courtroom - + Password - + Spectator 観客 - - + + Search - + Passworded - + Taken - - Could not find %1 + + Generating chars: +%1/%2 - + Showname - + Message - + Name 名前 - + Pre - + Flip フリップ + Guard - ガード + ガード - - + + Additive + + + + + Casing - + Shownames - + No Interrupt - White - + - Green - + - Red - + - Orange - オレンジ + オレンジ - Blue - + - Yellow - 黄色 + 黄色 - - This does nothing, but there you go. - - - - + You need to give a filename to load (extension not needed)! Make sure that it is in the `base/cases/` folder, and that it is a correctly formatted ini. Cases you can load: %1 - + Case made by %1. - + Navigate to %1 for the CM doc. - + Your case "%1" was loaded! - - + + Server + + + None + + + + + Hold It! + + + + + + + When this is turned on, your next in-character message will be a shout! + + + + + Objection! + 意義あり! + + + + Take That! + + + + + Toggle between server chat and global AO2 chat. + + + + + + + + This will display the animation in the viewport as soon as it is pressed. + + + + + Guilty! + + + + + Bring up the Character Select Screen and change your character. + + + + + Refresh the theme and update all of the ui elements to match. + + + + + Request the attention of the current server's moderator. + + + + + Allows you to change various aspects of the client. + + + An interface to help you announce a case (you have to be a CM first to be able to announce cases) + + + + + Switch between Areas and Music lists + + + + + Play a single-shot animation as defined by the emote when checked. + + + + + If preanim is checked, display the input text immediately as the animation plays concurrently. + + + + + Mirror your character's emotes when checked. + + + + + Add text to your last spoken message when checked. + + + + + Do not listen to mod calls when checked, preventing them from playing sounds or focusing attention on the window. + + + + + Lets you receive case alerts when enabled. +(You can set your preferences in the Settings!) + + + + + Display customized shownames for all users when checked. + + + + + Custom Shout! + + + + + This will display the custom character-defined animation in the viewport as soon as it is pressed. +To make one, your character's folder must contain custom.[webp/apng/gif/png] and custom.[wav/ogg/opus] sound effect + + + + + Play realization sound and animation in the viewport on the next spoken message when checked. + + + + + Shake the screen on next spoken message when checked. + + + + + Display the list of character folders you wish to mute. + + + + + + Increase the health bar. + + + + + + Decrease the health bar. + + + + + Change the text color of the spoken message. +You can also select a part of your currently typed message and use the dropdown to change its color! + + + + Back to Lobby ロビーに戻る - + + + + has played a song + + + + + You will now pair up with %1 if they also choose your character in return. + + + Rainbow - + - - OOC Message - - - - - Disable Modcalls - - - - Pink - ピンク + ピンク - Cyan - シアン + シアン - + % offset - - Music - 音楽 + + To front + - - Sfx - 効果音 + + To behind + - - Blips - ブリップ + + Select a character you wish to pair with. + - - Log limit + + Change the percentage offset of your character's position from the center of the screen. + + + + + Change the order of appearance for your character. + + + + + Display the list of characters to pair with. + + + + + Oops, you're muted! + + + + + Set your character's emote to play on your next message. + Set your character's supplementary background. + + + + + Set an 'iniswap', or an alternative character folder to refer to from your current character. +Edit by typing and pressing Enter, [X] to remove. This saves to your base/characters/<charname>/iniswaps.ini + + + + + + Remove the currently selected iniswap from the list and return to the original character folder. + + + + + Set a sound effect to play on your next 'Preanim'. Leaving it on Default will use the emote-defined sound (if any). +Edit by typing and pressing Enter, [X] to remove. This saves to your base/characters/<charname>/soundlist.ini + + + + + Choose an effect to play on your next spoken message. +The effects are defined in your theme/effects/effects.ini. Your character can define custom effects by +char.ini [Options] category, effects = 'miscname' where it referes to misc/<miscname>/effects.ini to read the effects. + + + + + Music + 音楽 + + + + Sfx + 効果音 + + + + Blips + ブリップ + + + Change character - + Reload theme - + Call mod - + Settings - + A/M - + Preanim - - + + Return back to the server list. + + + + + Become a spectator. You won't be able to interact with the in-character screen. + + + + You were granted the Disable Modcalls button. - + + + CLIENT + + + + You have been banned. - - Too many arguments to save a case! You only need a filename without extension and the courtroom status. - - - - + You opened the settings menu. - - You will now pair up with - - - - - if they also choose your character in return. - - - - + You are no longer paired with anyone. - + Are you sure you typed that well? The char ID could not be recognised. - + You have set your offset to - + Your offset must be between -100% and 100%! - + That offset does not look like one. - + You switched your music and area list. - + You have forcefully enabled features that the server may not support. You may not be able to talk IC, or worse, because of this. - + Your pre-animations interrupt again. - + Your pre-animations will not interrupt text. - + Couldn't open chatlog.txt to write into. - + The IC chatlog has been saved. - + You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely the case file you're looking for can't be found in there. - + Too many arguments to load a case! You only need one filename, without extension. - + + + + + UNKNOWN + + + + You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely that you somehow deleted it. - + You need to give a filename to save (extension not needed) and the courtroom status! - + + Too many arguments to save a case! You only need a filename without extension and the courtroom status! + + + + Succesfully saved, edit doc and cmdoc link on the ini! - + Master マスター - + + Expand All Categories + + + + + Collapse All Categories + + + + + Fade Out Previous + + + + + Fade In + + + + + Synchronize + + + + + Default + + + + Reason: - + Call Moderator モデレーターを呼ぶ - - + + Error エラー - + You must provide a reason. - + The message is too long. - Choose... - 選択... + 選択... - + + Present this piece of evidence to everyone on your next spoken message + + + + + Save evidence to an .ini file. + + + + + Load evidence from an .ini file. + + + + + Destroy this piece of evidence + + + + + Choose.. + + + + + Close the evidence display/editing overlay. +You will be prompted if there's any unsaved changes. + + + + + Save any changes made to this piece of evidence and send them to server. + + + + + Double-click to edit. Press [X] to update your changes. + + + + + Bring up the Evidence screen. + + + + + Switch evidence to private inventory. + + + + + Switch evidence to global inventory. + + + + + + Transfer evidence to private inventory. + + + + + + Transfer evidence to global inventory. + + + + + The piece of evidence you've been editing has changed. + + + + + Do you wish to keep your changes? + + + + + Name: %1 +Image: %2 +Description: +%3 + + + + Images (*.png) イメージ (*.png) - + + + + Double-click to edit... + + + + Add new evidence... 新しい証拠を付け加える... + + + Evidence has been modified. + + + + + Do you want to save your changes? + + + + + Current evidence is global. Click to switch to private. + + + + + Current evidence is private. Click to switch to global. + + + + + "%1" has been transferred. + + + + + Save Inventory + + + + + + Ini Files (*.ini) + + + + + Open Inventory + + Discord @@ -901,48 +1286,83 @@ Cases you can load: %1 - + + Search + + + + Name 名前 - + It doesn't look like your client is set up correctly. Did you download all resources correctly from tiny.cc/getao, including the large 'base' folder? - + Version: %1 - + + Settings + + + + + Allows you to change various aspects of the client. + + + + Loading ロード中 - + Cancel キャンセル - - <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Cents02<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, Raidensnake + + <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>2.8 Major Release development:</b><br>Crystalwarrior, Iamgoofball<p><b>2.8 Quality Assurance:</b><br>WillDean, Captain N, Mr M, Riel, Seimmet, Fury McFlurry,CedricDewitt, Chewable Tablets, Fantos, Futugaze,Geck, Minx, Pandae, Sierra, CrazyJC, CaseyMayCazy,GreenBowers, Robotic Overlord, Veritas, Gin-Gi<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, the AO2 community, server hosts, game masters,case makers, content creators and players! - + + About + + + + Online: %1/%2 - - + + Offline オフライン + + chatlogpiece + + + + + UNKNOWN + + + + + has played a song: + + + debug_functions @@ -956,7 +1376,7 @@ Did you download all resources correctly from tiny.cc/getao, including the large エラー - + Notice 通知 diff --git a/resource/translations/ao_pl.ts b/resource/translations/ao_pl.ts index 2662fcf..009a1f7 100644 --- a/resource/translations/ao_pl.ts +++ b/resource/translations/ao_pl.ts @@ -9,12 +9,12 @@ Odłączono od serwera. - + Error connecting to master server. Will try again in %1 seconds. Błąd podczas łączenia się z głównym serwerem. Spróbuj ponownie za %1 sekundy. - + There was an error connecting to the master server. We deploy multiple master servers to mitigate any possible downtime, but the client appears to have exhausted all possible methods of finding and connecting to one. Please check your Internet connection and firewall, and please try again. @@ -23,69 +23,68 @@ Używamy wielu głównych serwerów, aby zminimalizować każdą możliwą przer Sprawdź swoje połączenie internetowe oraz zaporę ogniową i spróbuj ponownie. - + Outdated version! Your version: %1 Please go to aceattorneyonline.com to update. Nieaktualna wersja! Twoja wersja: %1 Udaj się do aceattorneyonline.com, aby zaktualizować. - You have been exiled from AO. Have a nice day. - Zostałeś wygnany z AO. + Zostałeś wygnany z AO. Życzymy miłego dnia. - + Attorney Online 2 Prawnik w Internecie 2 - + Loading Ładowanie - + Loading evidence: %1/%2 Ładowanie dowodów: %1/%2 - - + + Loading music: %1/%2 Ładowanie muzyki: %1/%2 - - + + Loading chars: %1/%2 Ładowanie postaci: %1/%2 - + You have been kicked from the server. Reason: %1 Zostałeś wyrzucony z tego serwera. Powód: %1 - + You have been banned from the server. Reason: %1 Zostałeś zbanowany z tego serwera. Powód: %1 - + You are banned on this server. Reason: %1 Jesteś zbanowany na tym serwerze. @@ -130,383 +129,395 @@ Powód: %1 Potrzebny stenograf - Witness needed - Potrzebny świadek + Potrzebny świadek AOOptionsDialog - + Settings Ustawienia - + Gameplay Rozgrywka - + Theme: Motyw: - + Sets the theme used in-game. If the new theme changes the lobby's look as well, you'll need to reload the lobby for the changes to take effect, such as by joining a server and leaving it. Ustawia motyw używany w grze. Jeżeli nowy motyw równiesz zmienia wygląd poczekalni, musisz odświeżyć poczekalnię, aby zmiany zaczęły działać, np. poprzez dołączenie do serwera i wyjście z niego. - - Gives the default value for the in-game 'Custom shownames' checkbox, which in turn determines whether the client should display custom in-character names. - - - - - Sets the default volume for music. - - - - - Sets the default volume for SFX sounds, like interjections or other character sound effects. - - - - - IC Log - - - - - Colorful IC log: - - - - - Enables colored text in the log. - - - - - Only inline coloring: - - - - - Only inline coloring will be shown such as <>,|| etc. - - - - - Mirror IC log: - - - - - IC log will mirror the IC box. Meaning that if somebody gets interrupted nobody will know what they wanted to say. Enable for a more realistic experience. - - - - + Log goes downwards: Dziennik idzie w dół: - + If ticked, new messages will appear at the bottom (like the OOC chatlog). The traditional (AO1) behaviour is equivalent to this being unticked. Jeżeli zaznaczone, nowe wiadomości zaczną się pojawiać na dole (tak jak na czacie OOC). Tradycyjne (AO1) zachowanie jest równoważne do tego bycia nie zaznaczonym. - + Log length: Długość dziennika: - + The amount of messages the IC chatlog will keep before deleting older messages. A value of 0 or below counts as 'infinite'. Ilość wiadomości, jakie czat IC będzie zostawiał zanim usunie starsze wiadomości. Wartośc 0 albo niżej, liczy się jako 'nieskończone'. - + Default username: Domyślna nazwa użytkownika: - + Your OOC name will be automatically set to this value when you join a server. Twoja nazwa OOC będzie ustawiana automatycznie do tej wartości, kiedy dołączysz na serwer. - + Custom shownames: Niestandardowe ksywki: + Gives the default value for the in-game 'Custom shownames' tickbox, which in turn determines whether the client should display custom in-character names. - Daje domyślną wartość przyciskowi 'Niestandardowe ksywki', który określa, czy klient powinien pokazywać niestandardowe nazwy IC. + Daje domyślną wartość przyciskowi 'Niestandardowe ksywki', który określa, czy klient powinien pokazywać niestandardowe nazwy IC. - + Backup MS: Kopia zapasowa głównego serwera: - + If the built-in server lookups fail, the game will try the address given here and use it as a backup master server address. Jeśli wbudowane szukanie serwerów zawiedzie, gra spróbuje użyć adresu podanego tutaj i użyje go jako adresu zapasowego głównego serwera. - + Discord: - + Allows others on Discord to see what server you are in, what character are you playing, and how long you have been playing for. Pozwala innym na Discordzie zobaczyć na jakim serwerze się znajdujesz, jaką postać używasz i jak długo grałeś. - Allow Shake/Flash: - Zezwalaj Wstrząśnięcia/Błyśnięcia: + Zezwalaj Wstrząśnięcia/Błyśnięcia: - Allows screenshaking and flashing. Disable this if you have concerns or issues with photosensitivity and/or seizures. - Pozwala na wstrząśnięcia ekranu i błyśnięcia. Wyłącz to, jeśli przejmujesz się lub masz problemy z światłoczułością oraz/lub napady padaczkowe. + Pozwala na wstrząśnięcia ekranu i błyśnięcia. Wyłącz to, jeśli przejmujesz się lub masz problemy z światłoczułością oraz/lub napady padaczkowe. - + Language: Język: - + Sets the language if you don't want to use your system language. Ustawia język, jeśli nie chcesz używać języka systemowego. - - Slower text speed: + + - Keep current setting - - Set the text speed to be the same as the AA games. + + Allow Screenshake: - - Blip delay on punctuations: + + Allows screenshaking. Disable this if you have concerns or issues with photosensitivity and/or seizures. - - Punctuation delay modifier. Enable it for the blips to slow down on punctuations. + + Allow Effects: - + + Allows screen effects. Disable this if you have concerns or issues with photosensitivity and/or seizures. + + + + + Network Frame Effects: + + + + + Send screen-shaking, flashes and sounds as defined in the char.ini over the network. Only works for servers that support this functionality. + + + + + Colors in IC Log: + + + + + Use the markup colors in the server IC chatlog. + + + + + Sticky Sounds: + + + + + Turn this on to prevent the sound dropdown from clearing the sound after playing it. + + + + + Sticky Effects: + + + + + Turn this on to prevent the effects dropdown from clearing the effect after playing it. + + + + + Sticky Preanims: + + + + + Turn this on to prevent preanimation checkbox from clearing after playing the emote. + + + + Callwords Zawołania - + <html><head/><body>Enter as many callwords as you would like. These are case insensitive. Make sure to leave every callword in its own line!<br>Do not leave a line with a space at the end -- you will be alerted everytime someone uses a space in their messages.</body></html> <html><head/><body>Wpisz tyle zawołań, ile dusza zapragnie. Wielkość liter nie ma znaczenia. Miej na uwadze, aby każde zawołanie było w swojej lini!<br>Nie zostawiaj spacji na końcu -- zostaniesz zaalarmowany za każdym razem, kiedy ktoś użyje spacji w swojej wiadomości.</body></html> - + Audio Dźwięk - + Audio device: Urządzenie dźwiękowe: - + Sets the audio device for all sounds. Ustawia urządzenie dźwiękowe dla wszystkich dźwięków. - + Music: Muzyka: + Sets the music's default volume. - Ustawia domyślną głośność muzyki. + Ustawia domyślną głośność muzyki. - + SFX: Efekty dźwiękowe (SFX): + Sets the SFX's default volume. Interjections and actual sound effects count as 'SFX'. - Ustawia domyślną głośność efektów dźwiękowych (SFX). Sprzeciwy i same efekty specjalne są zaliczane jako 'SFX'. + Ustawia domyślną głośność efektów dźwiękowych (SFX). Sprzeciwy i same efekty specjalne są zaliczane jako 'SFX'. - + Blips: Blipy: - + Sets the volume of the blips, the talking sound effects. Ustawia głośność blipów, efektów dźwiękowych mówienia. - + Blip rate: Szybkość blipów: - + Sets the delay between playing the blip sounds. Ustawia opóźnienie pomiędzy graniem blipów. - + + Play a blip sound "once per every X symbols", where X is the blip rate. + + + + Blank blips: The 'blip' isn't an accurate polish representation of this english word. Puste blipy: - + If true, the game will play a blip sound even when a space is 'being said'. Jeżeli zaznaczone, gra zagra dźwięk blip za każdym razem spacja 'jest mówiona'. - + Enable Looping SFX: Włącz pętlące się efekty dźwiękowe (SFX): - + If true, the game will allow looping sound effects to play on preanimations. Jeśli zaznaczone, gra zezwoli na pętlące się efekty dźwiękowe (SFX). - + Kill Music On Objection: Przerwij muzykę w czasie sprzeciwu: - - If true, the game will stop music when someone objects, like in the actual games. - Jeśli zaznaczone, gra przerwie muzykę, kiedy ktoś sprzeciwi się, tak jak w oryginalnych grach. + + If true, AO2 will stop the music for you when you or someone else does 'Objection!'. + - + If true, the game will stop music when someone objects, like in the actual games. + Jeśli zaznaczone, gra przerwie muzykę, kiedy ktoś sprzeciwi się, tak jak w oryginalnych grach. + + + Casing Rozprawy - + This server supports case alerts. Ten serwer wspiera komunikaty rozpraw. - + This server does not support case alerts. Ten serwer nie wspiera komunikatów rozpraw. - + Pretty self-explanatory. Dosyć oczywiste. - + Casing: Rozprawy: - + If checked, you will get alerts about case announcements. Jeżeli zaznaczone, dostaniesz komunikaty o ogłoszeniach rozpraw. - + Defense: Obrona: - + If checked, you will get alerts about case announcements if a defense spot is open. Jeśli zaznaczone, dostaniesz komunikaty o ogłoszeniach rozpraw, jeśli miejsce obrony jest otwarte. - + Prosecution: Prokuratura: - + If checked, you will get alerts about case announcements if a prosecutor spot is open. Jeśli zaznaczone, dostaniesz komunikaty o ogłoszeniach rozpraw, jeśli miejsce prokuratora jest otwarte. - + Judge: Sędzia: - + If checked, you will get alerts about case announcements if the judge spot is open. Jeśli zaznaczone, dostaniesz komunikaty o ogłoszeniach rozpraw, jeśli miejsce sędzi jest otwarte. - + Juror: Ławnik: - + If checked, you will get alerts about case announcements if a juror spot is open. Jeżeli zaznaczone, dostaniesz komunikaty o ogłoszeniach rozpraw, jeśli miejsce ławnika jest otwarte. - + Stenographer: Stenograf: - + If checked, you will get alerts about case announcements if a stenographer spot is open. Jeżeli zaznaczone, dostaniesz komunikaty o ogłoszeniach rozpraw, jeśli miejsce stenografa jest otwarte. - + CM: Zarządca rozpraw (CM): - + If checked, you will appear amongst the potential CMs on the server. Jeśli zaznaczone, pojawisz się wśród potencjalnych zarządców rozpraw (CM) na serwerze. - Witness: - Świadek: + Świadek: - If checked, you will appear amongst the potential witnesses on the server. - Jeżeli zaznaczone, pojawisz się wśród potencjalnych świadków na serwerze. + Jeżeli zaznaczone, pojawisz się wśród potencjalnych świadków na serwerze. - + Hosting cases: Hostowane rozprawy: - + If you're a CM, enter what cases you are willing to host. Jeżeli jesteś zarządcą rozpraw (CM), wpisz jakie rozprawy jesteś chętny hostowania. @@ -514,402 +525,808 @@ Powód: %1 Courtroom - + Password Hasło - + Spectator Widz - - + + Search Wyszukaj - + Passworded Zahasłowany - + Taken Zajęty - Could not find %1 - Nie znaleziono %1 + Nie znaleziono %1 + Generating chars: %1/%2 - Generowanie postaci: + Generowanie postaci: %1.%2 - + Showname Ksywka - + Message Wiadomość - + Name Nazwa - + Pre przed- - + Flip Odwróć + Guard - Na Służbie (mod) + Na Służbie (mod) - - + + Additive + + + + + Casing Rozprawa - + Shownames Ksywki - + No Interrupt Bez ociągania się - White - Biały + Biały - Green - Zielony + Zielony - Red - Czerwony + Czerwony - Orange - Pomarańczowy + Pomarańczowy - Blue - Niebieski + Niebieski - Yellow - Żółty + Żółty - This does nothing, but there you go. - To nic nie robi, ale proszę bardzo. + To nic nie robi, ale proszę bardzo. - + You need to give a filename to load (extension not needed)! Make sure that it is in the `base/cases/` folder, and that it is a correctly formatted ini. Cases you can load: %1 Musisz podać nazwę pliku, którego chcesz załadować (rozszerzenie nie potrzebne!) Upewnij się, że jest w folderze `base/cases/` i że jest to poprawnie sformatowane ini. Rozprawy które możesz załadować: %1 - + Case made by %1. Rozprawa zrobiona przez %1. - + Navigate to %1 for the CM doc. Przejdź do %1, aby dojść do dokumentu CM. - + Your case "%1" was loaded! Twoja rozprawa "%1" została wczytana! - - + + Server Serwer + + + None + + + + + Hold It! + + + + + + + When this is turned on, your next in-character message will be a shout! + + + + + Objection! + + + + + Take That! + + + + + Toggle between server chat and global AO2 chat. + + + + + + + + This will display the animation in the viewport as soon as it is pressed. + + + + + Guilty! + + + + + Bring up the Character Select Screen and change your character. + + + + + Refresh the theme and update all of the ui elements to match. + + + + + Request the attention of the current server's moderator. + + + + + Allows you to change various aspects of the client. + + + An interface to help you announce a case (you have to be a CM first to be able to announce cases) + + + + + Switch between Areas and Music lists + + + + + Play a single-shot animation as defined by the emote when checked. + + + + + If preanim is checked, display the input text immediately as the animation plays concurrently. + + + + + Mirror your character's emotes when checked. + + + + + Add text to your last spoken message when checked. + + + + + Do not listen to mod calls when checked, preventing them from playing sounds or focusing attention on the window. + + + + + Lets you receive case alerts when enabled. +(You can set your preferences in the Settings!) + + + + + Display customized shownames for all users when checked. + + + + + Custom Shout! + + + + + This will display the custom character-defined animation in the viewport as soon as it is pressed. +To make one, your character's folder must contain custom.[webp/apng/gif/png] and custom.[wav/ogg/opus] sound effect + + + + + Play realization sound and animation in the viewport on the next spoken message when checked. + + + + + Shake the screen on next spoken message when checked. + + + + + Display the list of character folders you wish to mute. + + + + + + Increase the health bar. + + + + + + Decrease the health bar. + + + + + Change the text color of the spoken message. +You can also select a part of your currently typed message and use the dropdown to change its color! + + + + Back to Lobby Powrót do poczekalni - - Rainbow - Tęczowy - - - - OOC Message + + + + has played a song - + + You will now pair up with %1 if they also choose your character in return. + + + + Rainbow + Tęczowy + + Disable Modcalls - Wyłącz wezwania moda + Wyłącz wezwania moda - Pink - Różowy + Różowy - Cyan - Turkusowy + Turkusowy - + % offset % wyrówanie - + + To front + + + + + To behind + + + + + Select a character you wish to pair with. + + + + + Change the percentage offset of your character's position from the center of the screen. + + + + + Change the order of appearance for your character. + + + + + Display the list of characters to pair with. + + + + + Oops, you're muted! + + + + + Set your character's emote to play on your next message. + + + + + Set your character's supplementary background. + + + + + Set an 'iniswap', or an alternative character folder to refer to from your current character. +Edit by typing and pressing Enter, [X] to remove. This saves to your base/characters/<charname>/iniswaps.ini + + + + + + Remove the currently selected iniswap from the list and return to the original character folder. + + + + + Set a sound effect to play on your next 'Preanim'. Leaving it on Default will use the emote-defined sound (if any). +Edit by typing and pressing Enter, [X] to remove. This saves to your base/characters/<charname>/soundlist.ini + + + + + Choose an effect to play on your next spoken message. +The effects are defined in your theme/effects/effects.ini. Your character can define custom effects by +char.ini [Options] category, effects = 'miscname' where it referes to misc/<miscname>/effects.ini to read the effects. + + + + Music Muzyka - + Sfx Sfx - + Blips Blipy - Log limit - Limit dziennika + Limit dziennika - + Change character Zmiana postaci - + Reload theme Odśwież motyw - + Call mod Wezwij moda - + Settings Ustawienia - + A/M O meaning 'Obszar' and M meaning 'Muzyka'. O/M - + Preanim Sounds weird but I don't know how to translate it other than this. przed-animacja - - + + Return back to the server list. + + + + + Become a spectator. You won't be able to interact with the in-character screen. + + + + You were granted the Disable Modcalls button. - - You have been banned. - Zostałeś zbanowany. + + + CLIENT + - - Too many arguments to save a case! You only need a filename without extension and the courtroom status. - + + You have been banned. + Zostałeś zbanowany. You were granted the Guard button. Zostałeś obdarzonym przyciskiem Na Służbie. - + You opened the settings menu. Otworzyłeś opcje. - You will now pair up with - Będzie teraz w parze z + Będzie teraz w parze z - if they also choose your character in return. - jeżeli oni również wybiorą ciebie spowrotem. + jeżeli oni również wybiorą ciebie spowrotem. - + You are no longer paired with anyone. Nie jesteś już w parze z kimkolwiek. - + Are you sure you typed that well? The char ID could not be recognised. Czy jesteś pewien, że dobrze to napisałeś? ID postaci nie zostało rozpoznane. - + You have set your offset to Musisz ustawić swoje wyrównanie do - + Your offset must be between -100% and 100%! Twoje wyrównanie musi być między -100%, a 100%! - + That offset does not look like one. To wyrównanie nie wygląda na takie. - + You switched your music and area list. Przełączyłeś swoją listę obszarów i muzyki. - + You have forcefully enabled features that the server may not support. You may not be able to talk IC, or worse, because of this. Włączyłeś funkcje, które ten serwer może nie wspierać. Możliwe że, nie możesz rozmawiać na czacie IC lub gorzej z powodu tego. - + Your pre-animations interrupt again. Twoje przed-animacje przerywają tekst spowrotem. - + Your pre-animations will not interrupt text. Twoje przed-animacje nie będą przerywać tekstu. - + Couldn't open chatlog.txt to write into. Nie można było otworzyć chatlog.txt, aby pisać w nim. - + The IC chatlog has been saved. Dziennik czatu IC został zapisany. - + You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely the case file you're looking for can't be found in there. Nie masz folderu `base/cases/`! Został zrobiony tylko dla ciebie, ale widząc, że ZOSTAŁ zrobiony tylko dla ciebie, prawdopodobnie plik rozpraw, którego szukasz nie został znaleziony tutaj. - + Too many arguments to load a case! You only need one filename, without extension. Zbyt dużo parametrów, aby załadować rozprawę! Potrzebujesz tylko jedną nazwę pliku, bez rozszerzenia nazwy pliku. - + + + + + UNKNOWN + + + + You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely that you somehow deleted it. Nie masz folderu `base/cases/`! Został zrobiony tylko dla ciebie, ale widząc, że ZOSTAŁ zrobiony tylko dla ciebie, prawdopodobnie jakoś usunąłeś go. - + You need to give a filename to save (extension not needed) and the courtroom status! Musisz podać nazwę pliku, aby go zapisać (rozszerzenie nie potrzebne) i status sali sądowej! + Too many arguments to save a case! You only need a filename without extension and the courtroom status! - Zbyt dużo parametrów, aby zapisać rozprawę! Potrzebujesz tylko jedną nazwę pliku, bez rozszerzenia nazwy pliku i statusu sali sądowej! + Zbyt dużo parametrów, aby zapisać rozprawę! Potrzebujesz tylko jedną nazwę pliku, bez rozszerzenia nazwy pliku i statusu sali sądowej! - + Succesfully saved, edit doc and cmdoc link on the ini! Zapisano pomyślnie, edytuj dokument i link cmdoc w .ini! - + Master Główny - + + Expand All Categories + + + + + Collapse All Categories + + + + + Fade Out Previous + + + + + Fade In + + + + + Synchronize + + + + + Default + + + + Reason: Powód: - + Call Moderator Wezwij Moderatora - - + + Error Błąd - + You must provide a reason. Musisz podać przyczynę. - + The message is too long. Ta wiadomość jest za długa. - Choose... - Wybierz... + Wybierz... - + + Present this piece of evidence to everyone on your next spoken message + + + + + Save evidence to an .ini file. + + + + + Load evidence from an .ini file. + + + + + Destroy this piece of evidence + + + + + Choose.. + + + + + Close the evidence display/editing overlay. +You will be prompted if there's any unsaved changes. + + + + + Save any changes made to this piece of evidence and send them to server. + + + + + Double-click to edit. Press [X] to update your changes. + + + + + Bring up the Evidence screen. + + + + + Switch evidence to private inventory. + + + + + Switch evidence to global inventory. + + + + + + Transfer evidence to private inventory. + + + + + + Transfer evidence to global inventory. + + + + + The piece of evidence you've been editing has changed. + + + + + Do you wish to keep your changes? + + + + + Name: %1 +Image: %2 +Description: +%3 + + + + Images (*.png) Plik obrazu (*.png) - + + + + Double-click to edit... + + + + Add new evidence... Dodaj nowe dowody... + + + Evidence has been modified. + + + + + Do you want to save your changes? + + + + + Current evidence is global. Click to switch to private. + + + + + Current evidence is private. Click to switch to global. + + + + + "%1" has been transferred. + + + + + Save Inventory + + + + + + Ini Files (*.ini) + + + + + Open Inventory + + Lobby @@ -919,35 +1336,55 @@ Rozprawy które możesz załadować: %1 - + + Search + Wyszukaj + + + Name Nazwa - + It doesn't look like your client is set up correctly. Did you download all resources correctly from tiny.cc/getao, including the large 'base' folder? Wygłąda na to, że twój klient nie jest ustawiony poprawnie. Czy pobrałeś wszystkie zasoby poprawnie z tiny.cc/getao, włączając duży folder 'base'? - + Version: %1 Wersja: %1 - + + Settings + Ustawienia + + + + Allows you to change various aspects of the client. + + + + Loading Ładowanie - + Cancel Anuluj - - <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Cents02<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, Raidensnake + + <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>2.8 Major Release development:</b><br>Crystalwarrior, Iamgoofball<p><b>2.8 Quality Assurance:</b><br>WillDean, Captain N, Mr M, Riel, Seimmet, Fury McFlurry,CedricDewitt, Chewable Tablets, Fantos, Futugaze,Geck, Minx, Pandae, Sierra, CrazyJC, CaseyMayCazy,GreenBowers, Robotic Overlord, Veritas, Gin-Gi<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, the AO2 community, server hosts, game masters,case makers, content creators and players! + + + + + About @@ -955,17 +1392,32 @@ Czy pobrałeś wszystkie zasoby poprawnie z tiny.cc/getao, włączając duży fo <h2>Attorney Online: %1</h2>Symulator dramy sądowej<p><b>Kod żródłowy:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Główny rozwój:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>Szczególne podziękowania:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy - + Online: %1/%2 - - + + Offline + + chatlogpiece + + + + + UNKNOWN + + + + + has played a song: + + + debug_functions @@ -979,7 +1431,7 @@ Czy pobrałeś wszystkie zasoby poprawnie z tiny.cc/getao, włączając duży fo Błąd - + Notice Ogłoszenie diff --git a/resource/translations/ao_pt.ts b/resource/translations/ao_pt.ts index 824c81e..7a69475 100644 --- a/resource/translations/ao_pt.ts +++ b/resource/translations/ao_pt.ts @@ -9,80 +9,79 @@ Desconectado do servidor. - + Error connecting to master server. Will try again in %1 seconds. Erro ao conectar ao servidor principal. Testando novamente em %1 segundos. - + There was an error connecting to the master server. We deploy multiple master servers to mitigate any possible downtime, but the client appears to have exhausted all possible methods of finding and connecting to one. Please check your Internet connection and firewall, and please try again. Ocorreu um erro ao obter a lista de servidores. Verifique sua conexão à Internet e firewall e tente novamente. - + Outdated version! Your version: %1 Please go to aceattorneyonline.com to update. Versão desatualizada! Sua versão: %1 Acesse aceattorneyonline.com para atualizar. - You have been exiled from AO. Have a nice day. - Você foi exilado do Attorney Online. + Você foi exilado do Attorney Online. Tenha um bom dia. - + Attorney Online 2 - + Loading Carregando - - + + Loading chars: %1/%2 Carregando personagens: %1/%2 - + Loading evidence: %1/%2 Carregando evidências: %1/%2 - - + + Loading music: %1/%2 Carregando músicas: %1/%2 - + You have been kicked from the server. Reason: %1 Você foi expulso do servidor. Motivo: %1 - + You have been banned from the server. Reason: %1 Você foi banido do servidor. Motivo: %1 - + You are banned on this server. Reason: %1 Você foi banido neste servidor. @@ -127,779 +126,1258 @@ Motivo: %1 Precisa-se de Estenógrafo - Witness needed - Precisa-se de Testemunha + Precisa-se de Testemunha AOOptionsDialog - + Settings Configurações - + Gameplay Jogabilidade - + Theme: Tema visual: - + Sets the theme used in-game. If the new theme changes the lobby's look as well, you'll need to reload the lobby for the changes to take effect, such as by joining a server and leaving it. Define o tema usado no jogo. Se o novo tema alterar a aparência do lobby, será necessário recarregá-lo para que as alterações tenham efeito, como ingressar em um servidor e deixá-lo. - + Log goes downwards: Log vai para baixo: - + If ticked, new messages will appear at the bottom (like the OOC chatlog). The traditional (AO1) behaviour is equivalent to this being unticked. Removed the part about AO1 behaviour, nobody cares boomer. Se selecionado, novas mensagens irão aparecer na parte inferior (assim como o chat OOC). - + Log length: Tamanho do log: - + The amount of messages the IC chatlog will keep before deleting older messages. A value of 0 or below counts as 'infinite'. A quantidade de mensagens que o chat do IC manterá antes de excluir as mensagens mais antigas. Um valor igual ou inferior a 0 conta como 'infinito'. - + Default username: Nome de usuário padrão: - + Your OOC name will be automatically set to this value when you join a server. Seu nome OOC será automaticamente definido com esse valor quando você ingressar em um servidor. - + Custom shownames: Nomes personalizados: + Gives the default value for the in-game 'Custom shownames' tickbox, which in turn determines whether the client should display custom in-character names. 'Custom shownames' changed to 'Shownames' because that's the actual name - Fornece o valor padrão para a caixa de seleção 'Shownames' no jogo, que determina se o cliente deve exibir nomes personalizados nos caracteres. + Fornece o valor padrão para a caixa de seleção 'Shownames' no jogo, que determina se o cliente deve exibir nomes personalizados nos caracteres. - + Backup MS: MS de backup: - + If the built-in server lookups fail, the game will try the address given here and use it as a backup master server address. Se as pesquisas internas do servidor falharem, o jogo tentará o endereço fornecido aqui e o usará como um endereço de servidor principal de backup. - + Discord: - + Allows others on Discord to see what server you are in, what character are you playing, and how long you have been playing for. Permite que outras pessoas no Discord vejam em que servidor você está, qual personagem está jogando e há quanto tempo está jogando. - Allow Shake/Flash: - Permitir Shake/Flash: + Permitir Shake/Flash: - Allows screenshaking and flashing. Disable this if you have concerns or issues with photosensitivity and/or seizures. - Permite agitar e piscar. Desative isso se você tiver preocupações ou problemas com fotosensibilidade e/ou convulsões. + Permite agitar e piscar. Desative isso se você tiver preocupações ou problemas com fotosensibilidade e/ou convulsões. - + Language: Língua: - + Sets the language if you don't want to use your system language. Define o idioma se você não quiser usar o idioma do sistema. - Punctuation delay modifier. Enable it for the blips to slow down on punctuations. - Habilite para adicionar uma pequena pausa nos sinais de pontuação. + Habilite para adicionar uma pequena pausa nos sinais de pontuação. - + Callwords Palavras-chave - + <html><head/><body>Enter as many callwords as you would like. These are case insensitive. Make sure to leave every callword in its own line!<br>Do not leave a line with a space at the end -- you will be alerted everytime someone uses a space in their messages.</body></html> <html><head/><body>Digite quantas palavras-chave você desejar. Estes não diferenciam maiúsculas de minúsculas. Certifique-se de deixar cada palavra chave em sua própria linha!<br>Não deixe uma linha com um espaço no final - você será alertado toda vez que alguém usar um espaço em suas mensagens.</body></html> - + Audio Áudio - + Audio device: Dispositivo de áudio: - + Sets the audio device for all sounds. Define o dispositivo de áudio para todos os sons. - + Music: Música: + Sets the music's default volume. - Define o volume padrão da música. + Define o volume padrão da música. - + SFX: SFX: + Sets the SFX's default volume. Interjections and actual sound effects count as 'SFX'. - Define o volume padrão do SFX. Interjeições e efeitos sonoros reais contam como 'SFX'. + Define o volume padrão do SFX. Interjeições e efeitos sonoros reais contam como 'SFX'. - Gives the default value for the in-game 'Custom shownames' checkbox, which in turn determines whether the client should display custom in-character names. - Fornece o valor padrão para a caixa de seleção 'Shownames' no jogo, que determina se o cliente deve exibir nomes personalizados nos caracteres. + Fornece o valor padrão para a caixa de seleção 'Shownames' no jogo, que determina se o cliente deve exibir nomes personalizados nos caracteres. - Slower text speed: - Texto mais lento: + Texto mais lento: - Set the text speed to be the same as the AA games. - A velocidade do texto será a mesma dos jogos AA. + A velocidade do texto será a mesma dos jogos AA. - Blip delay on punctuations: - Atraso na pontuação: + Atraso na pontuação: - Sets the default volume for music. - Define o volume padrão da música. + Define o volume padrão da música. - Sets the default volume for SFX sounds, like interjections or other character sound effects. - Define o volume padrão para sons SFX, como interjeições ou outros efeitos sonoros de personagens. + Define o volume padrão para sons SFX, como interjeições ou outros efeitos sonoros de personagens. - + Blips: - + Sets the volume of the blips, the talking sound effects. Define o volume dos blips, os efeitos sonoros de fala. - + Blip rate: Taxa de blip: - + Sets the delay between playing the blip sounds. Define o atraso entre a reprodução dos sons de blip. - + Blank blips: Blips em branco: - + If true, the game will play a blip sound even when a space is 'being said'. Se ativado, o jogo emitirá um sinal sonoro, mesmo quando um espaço estiver sendo "dito". - + Enable Looping SFX: Ative o SFX em loop: - + If true, the game will allow looping sound effects to play on preanimations. Se ativado, o jogo permitirá que efeitos sonoros em loop sejam reproduzidos em pré-animações. - + Kill Music On Objection: Parar a música no protesto: - If true, the game will stop music when someone objects, like in the actual games. - Se ativado, o jogo interrompe a música quando alguém protestar , como nos jogos reais. + Se ativado, o jogo interrompe a música quando alguém protestar , como nos jogos reais. - + + - Keep current setting + + + + + Allow Screenshake: + + + + + Allows screenshaking. Disable this if you have concerns or issues with photosensitivity and/or seizures. + + + + + Allow Effects: + + + + + Allows screen effects. Disable this if you have concerns or issues with photosensitivity and/or seizures. + + + + + Network Frame Effects: + + + + + Send screen-shaking, flashes and sounds as defined in the char.ini over the network. Only works for servers that support this functionality. + + + + + Colors in IC Log: + + + + + Use the markup colors in the server IC chatlog. + + + + + Sticky Sounds: + + + + + Turn this on to prevent the sound dropdown from clearing the sound after playing it. + + + + + Sticky Effects: + + + + + Turn this on to prevent the effects dropdown from clearing the effect after playing it. + + + + + Sticky Preanims: + + + + + Turn this on to prevent preanimation checkbox from clearing after playing the emote. + + + + + Play a blip sound "once per every X symbols", where X is the blip rate. + + + + + If true, AO2 will stop the music for you when you or someone else does 'Objection!'. + + + + Casing Caso - + This server supports case alerts. Este servidor suporta anúncios de casos. - + This server does not support case alerts. Este servidor não suporta alertas de caso. - + Pretty self-explanatory. Bastante auto-explicativo. - + Casing: Caso: - + If checked, you will get alerts about case announcements. Se marcado, você será alertado quando houverem anúncios de casos. - + Defense: Defesa: - + If checked, you will get alerts about case announcements if a defense spot is open. Se marcado, você receberá alertas sobre os anúncios de casos, se um ponto de defesa estiver aberto. - + Prosecution: Promotor: - + If checked, you will get alerts about case announcements if a prosecutor spot is open. Se marcado, você receberá alertas sobre os anúncios de casos, se uma posição de promotor estiver disponível. - + Judge: Juíz: - + If checked, you will get alerts about case announcements if the judge spot is open. Se marcado, você receberá alertas sobre os anúncios de casos, se o local do juíz: estiver aberto. - + Juror: Jurado: - + If checked, you will get alerts about case announcements if a juror spot is open. Se marcado, você receberá alertas sobre os anúncios de casos, se um local do jurado estiver aberto. - + Stenographer: Estenógrafo: - + If checked, you will get alerts about case announcements if a stenographer spot is open. Se marcado, você receberá alertas sobre anúncios de casos, se um local de estenógrafo estiver aberto. - + CM: CM: - + If checked, you will appear amongst the potential CMs on the server. Se marcado, você aparecerá entre os CMs possíveis no servidor. - Witness: - Testemunha: + Testemunha: - If checked, you will appear amongst the potential witnesses on the server. - Se marcado, você aparecerá entre as testemunhas em potencial no servidor. + Se marcado, você aparecerá entre as testemunhas em potencial no servidor. - + Hosting cases: Casos: - + If you're a CM, enter what cases you are willing to host. Se você é um CM, insira os casos que deseja hospedar. - - IC Log - - - - Colorful IC log: - Log IC colorido: + Log IC colorido: - Enables colored text in the log. - Ativa o texto colorido no log. + Ativa o texto colorido no log. - Only inline coloring: - Somente coloração em linha: + Somente coloração em linha: - Only inline coloring will be shown such as <>,|| etc. - Somente a coloração em linha será mostrada como <>, ||, etc. + Somente a coloração em linha será mostrada como <>, ||, etc. - Mirror IC log: - O log IC reflete interrupções: + O log IC reflete interrupções: - IC log will mirror the IC box. Meaning that if somebody gets interrupted nobody will know what they wanted to say. Enable for a more realistic experience. - O log IC espelhará o chat IC Significando que se alguém for interrompido, ninguém saberá o que queria dizer. Habilite para uma experiência mais realista. + O log IC espelhará o chat IC Significando que se alguém for interrompido, ninguém saberá o que queria dizer. Habilite para uma experiência mais realista. Courtroom - + Password Senha - + Spectator Espectador - - + + Search Pesquisar - + Passworded A translation wouldn't fit because of the shitty theme system. - + Taken Em uso - - Could not find %1 - Não foi possível encontrar %1 + + Generating chars: +%1/%2 + - + Could not find %1 + Não foi possível encontrar %1 + + + Showname A translation wouldn't fit because of the shitty theme system. - + Message Mensagem - OOC Message - Mensagem OOC + Mensagem OOC - + Name Nome - + Pre A translation wouldn't fit because of the shitty theme system. - + Flip A translation wouldn't fit because of the shitty theme system. - - Disable Modcalls - - - - - + + Casing A translation wouldn't fit because of the shitty theme system. - + Shownames A translation wouldn't fit because of the shitty theme system. - + No Interrupt A translation wouldn't fit because of the shitty theme system. - White - Branco + Branco - Green - Verde + Verde - Red - Vermelho + Vermelho - Orange - Laranja + Laranja - Blue - Azul + Azul - Yellow - Amarelo + Amarelo - Rainbow - Arco Iris + Arco Iris - Pink - Rosa + Rosa - Cyan - Ciano + Ciano - + % offset % deslocamento - + Music - + Sfx - + Blips - - Log limit - - - - - + + Server - + Change character - + Reload theme - + Call mod - + Settings - + A/M - + Preanim - + Back to Lobby A translation wouldn't fit because of the shitty theme system. Lobby - - + You were granted the Disable Modcalls button. Você recebeu o botão Desativar Modcalls. - + You have been banned. Você foi banido. - This does nothing, but there you go. - Isso não faz nada, mas lá vai você. + Isso não faz nada, mas lá vai você. - + You opened the settings menu. Você abriu o menu de configurações. - You will now pair up with - Agora você vai fazer par com + Agora você vai fazer par com - if they also choose your character in return. - se eles também escolherem seu personagem em troca. + se eles também escolherem seu personagem em troca. - + + None + + + + + Guard + + + + + Additive + + + + + To front + + + + + To behind + + + + + Select a character you wish to pair with. + + + + + Change the percentage offset of your character's position from the center of the screen. + + + + + Change the order of appearance for your character. + + + + + Display the list of characters to pair with. + + + + + Oops, you're muted! + + + + + Set your character's emote to play on your next message. + + + + + Set your character's supplementary background. + + + + + Set an 'iniswap', or an alternative character folder to refer to from your current character. +Edit by typing and pressing Enter, [X] to remove. This saves to your base/characters/<charname>/iniswaps.ini + + + + + + Remove the currently selected iniswap from the list and return to the original character folder. + + + + + Set a sound effect to play on your next 'Preanim'. Leaving it on Default will use the emote-defined sound (if any). +Edit by typing and pressing Enter, [X] to remove. This saves to your base/characters/<charname>/soundlist.ini + + + + + Choose an effect to play on your next spoken message. +The effects are defined in your theme/effects/effects.ini. Your character can define custom effects by +char.ini [Options] category, effects = 'miscname' where it referes to misc/<miscname>/effects.ini to read the effects. + + + + + Hold It! + + + + + + + When this is turned on, your next in-character message will be a shout! + + + + + Objection! + + + + + Take That! + + + + + Toggle between server chat and global AO2 chat. + + + + + + + + This will display the animation in the viewport as soon as it is pressed. + + + + + Guilty! + + + + + Bring up the Character Select Screen and change your character. + + + + + Refresh the theme and update all of the ui elements to match. + + + + + Request the attention of the current server's moderator. + + + + + Allows you to change various aspects of the client. + + + + + An interface to help you announce a case (you have to be a CM first to be able to announce cases) + + + + + Switch between Areas and Music lists + + + + + Play a single-shot animation as defined by the emote when checked. + + + + + If preanim is checked, display the input text immediately as the animation plays concurrently. + + + + + Mirror your character's emotes when checked. + + + + + Add text to your last spoken message when checked. + + + + + Do not listen to mod calls when checked, preventing them from playing sounds or focusing attention on the window. + + + + + Lets you receive case alerts when enabled. +(You can set your preferences in the Settings!) + + + + + Display customized shownames for all users when checked. + + + + + Custom Shout! + + + + + This will display the custom character-defined animation in the viewport as soon as it is pressed. +To make one, your character's folder must contain custom.[webp/apng/gif/png] and custom.[wav/ogg/opus] sound effect + + + + + Play realization sound and animation in the viewport on the next spoken message when checked. + + + + + Shake the screen on next spoken message when checked. + + + + + Display the list of character folders you wish to mute. + + + + + + Increase the health bar. + + + + + + Decrease the health bar. + + + + + Change the text color of the spoken message. +You can also select a part of your currently typed message and use the dropdown to change its color! + + + + + Return back to the server list. + + + + + Become a spectator. You won't be able to interact with the in-character screen. + + + + + + CLIENT + + + + + + + has played a song + + + + + You will now pair up with %1 if they also choose your character in return. + + + + You are no longer paired with anyone. Você não está mais fazendo par com ninguém. - + Are you sure you typed that well? The char ID could not be recognised. Você tem certeza que você escreveu isso certo? O ID do personagem não pôde ser encontrado. - + You have set your offset to Você definiu seu deslocamento como - + Your offset must be between -100% and 100%! Seu deslocamento deve estar entre -100% e 100%! - + That offset does not look like one. Esse deslocamento não se parece com um. - + You switched your music and area list. Você mudou sua lista de músicas e áreas. - + You have forcefully enabled features that the server may not support. You may not be able to talk IC, or worse, because of this. Você forçou recursos que o servidor pode não suportar. Você pode não conseguir falar de IC, ou pior, por causa disso. - + Your pre-animations interrupt again. Suas pré-animações interrompem novamente. - + Your pre-animations will not interrupt text. Suas pré-animações não interromperão o texto. - + Couldn't open chatlog.txt to write into. Não foi possível abrir o chatlog.txt para gravar. - + The IC chatlog has been saved. O chat do IC foi salvo. - + You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely the case file you're looking for can't be found in there. Você não possui uma pasta `base/cases/`! Foi feito para você, mas, como foi feito para você, provavelmente o arquivo do caso que você está procurando não pode ser encontrado lá. - + You need to give a filename to load (extension not needed)! Make sure that it is in the `base/cases/` folder, and that it is a correctly formatted ini. Cases you can load: %1 Você precisa fornecer um nome de arquivo para carregar (extensão não necessária)! Verifique se está na pasta `base/cases/` e se é um ini formatado corretamente. Casos que você pode carregar: %1 - + Too many arguments to load a case! You only need one filename, without extension. Muitos argumentos para carregar um caso! Você só precisa de um nome de arquivo, sem extensão. - + Case made by %1. Caso feito por %1. - + Navigate to %1 for the CM doc. Navegue para %1 para o documento do CM. - + + + + + UNKNOWN + + + + Your case "%1" was loaded! Seu caso "%1" foi carregado! - + You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely that you somehow deleted it. Você não possui uma pasta `base/cases/`! Foi feito para você, mas, como foi feito para você, é provável que você o tenha excluído. - + You need to give a filename to save (extension not needed) and the courtroom status! Você deve fornecer um nome de arquivo para salvar (sem extensão necessária) e o estado do tribunal! - Too many arguments to save a case! You only need a filename without extension and the courtroom status. - Muitos argumentos para salvar um caso! Você só precisa de um nome de arquivo sem extensão e o estado do tribunal. + Muitos argumentos para salvar um caso! Você só precisa de um nome de arquivo sem extensão e o estado do tribunal. + Too many arguments to save a case! You only need a filename without extension and the courtroom status! - Muitos argumentos para salvar um caso! Você só precisa de um nome de arquivo sem extensão e o estado do tribunal. + Muitos argumentos para salvar um caso! Você só precisa de um nome de arquivo sem extensão e o estado do tribunal. - + Succesfully saved, edit doc and cmdoc link on the ini! Salvo com sucesso, você pode editar o documento e o link do documento no arquivo ini! - + Master - + + Expand All Categories + + + + + Collapse All Categories + + + + + Fade Out Previous + + + + + Fade In + + + + + Synchronize + + + + + Default + + + + Reason: Razão: - + Call Moderator Chamar um Moderador - - + + Error Erro - + You must provide a reason. Você deve fornecer um motivo. - + The message is too long. A mensagem é muito longa. - Choose... - Escolha... + Escolha... - + + Present this piece of evidence to everyone on your next spoken message + + + + + Save evidence to an .ini file. + + + + + Load evidence from an .ini file. + + + + + Destroy this piece of evidence + + + + + Choose.. + + + + + Close the evidence display/editing overlay. +You will be prompted if there's any unsaved changes. + + + + + Save any changes made to this piece of evidence and send them to server. + + + + + Double-click to edit. Press [X] to update your changes. + + + + + Bring up the Evidence screen. + + + + + Switch evidence to private inventory. + + + + + Switch evidence to global inventory. + + + + + + Transfer evidence to private inventory. + + + + + + Transfer evidence to global inventory. + + + + + The piece of evidence you've been editing has changed. + + + + + Do you wish to keep your changes? + + + + + Name: %1 +Image: %2 +Description: +%3 + + + + Images (*.png) Imagens (* .png) - + + + + Double-click to edit... + + + + Add new evidence... Adicionar nova evidência... + + + Evidence has been modified. + + + + + Do you want to save your changes? + + + + + Current evidence is global. Click to switch to private. + + + + + Current evidence is private. Click to switch to global. + + + + + "%1" has been transferred. + + + + + Save Inventory + + + + + + Ini Files (*.ini) + + + + + Open Inventory + + Lobby @@ -909,53 +1387,92 @@ Casos que você pode carregar: %1 - + + Search + Pesquisar + + + Name Nome - + It doesn't look like your client is set up correctly. Did you download all resources correctly from tiny.cc/getao, including the large 'base' folder? Seu cliente não parece estar configurado corretamente. Você baixou todos os recursos corretamente do tiny.cc/getao, incluindo a grande pasta 'base'? - + Version: %1 Versão: %1 - - + + Settings + Configurações + + + + Allows you to change various aspects of the client. + + + + + Offline Offline - + Loading Carregando - + Cancel Cancelar - + + <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>2.8 Major Release development:</b><br>Crystalwarrior, Iamgoofball<p><b>2.8 Quality Assurance:</b><br>WillDean, Captain N, Mr M, Riel, Seimmet, Fury McFlurry,CedricDewitt, Chewable Tablets, Fantos, Futugaze,Geck, Minx, Pandae, Sierra, CrazyJC, CaseyMayCazy,GreenBowers, Robotic Overlord, Veritas, Gin-Gi<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, the AO2 community, server hosts, game masters,case makers, content creators and players! + + + + + About + + + <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Cents02<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, Raidensnake - <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Cents02<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, Raidensnake + <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Cents02<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, Raidensnake <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy <h2>Attorney Online %1</h2>O simulador de drama jurídico<p><b>Código fonte:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Desenvolvimento principal:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>Agradecimentos especiais:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy - + Online: %1/%2 Online: %1/%2 + + chatlogpiece + + + + + UNKNOWN + + + + + has played a song: + + + debug_functions @@ -969,7 +1486,7 @@ Você baixou todos os recursos corretamente do tiny.cc/getao, incluindo a grande - + Notice diff --git a/resource/translations/ao_ru.ts b/resource/translations/ao_ru.ts index 93a3295..3b0af42 100644 --- a/resource/translations/ao_ru.ts +++ b/resource/translations/ao_ru.ts @@ -9,12 +9,12 @@ Соединение с сервером прервано. - + Error connecting to master server. Will try again in %1 seconds. Ошибка соединения с главным сервером. Попытка пересоединения будет через %1 с. - + There was an error connecting to the master server. We deploy multiple master servers to mitigate any possible downtime, but the client appears to have exhausted all possible methods of finding and connecting to one. Please check your Internet connection and firewall, and please try again. @@ -22,67 +22,66 @@ Please check your Internet connection and firewall, and please try again. - + Outdated version! Your version: %1 Please go to aceattorneyonline.com to update. Устаревшая версия! У вас установлена %1 Проследуйте на сайт aceattorneyonline.com для обновления. - You have been exiled from AO. Have a nice day. - Из AO вас отправили в жизнь. + Из AO вас отправили в жизнь. Хорошего дня. - + Attorney Online 2 Attorney Online 2 - + Loading Загрузка - + Loading evidence: %1/%2 Загрузка вещдоков: %1/%2 - - + + Loading music: %1/%2 Загрузка музыки: %1/%2 - - + + Loading chars: %1/%2 Загрузка персонажей: %1/%2 - + You have been kicked from the server. Reason: %1 Вас выпнули с сервера. Причина: %1 - + You have been banned from the server. Reason: %1 - + You are banned on this server. Reason: %1 Вас отправили в баню. @@ -138,383 +137,371 @@ Reason: Stenographer needed Нужен стенографист? - - - Witness needed - - AOOptionsDialog - + Settings Настройки - + Gameplay Игра - + Theme: Тема: - + Sets the theme used in-game. If the new theme changes the lobby's look as well, you'll need to reload the lobby for the changes to take effect, such as by joining a server and leaving it. Устанавливает внешний вид игры. Может понадобиться перезайти на сервер. - - Gives the default value for the in-game 'Custom shownames' checkbox, which in turn determines whether the client should display custom in-character names. - - - - - Sets the default volume for music. - - - - - Sets the default volume for SFX sounds, like interjections or other character sound effects. - - - - - IC Log - - - - - Colorful IC log: - - - - - Enables colored text in the log. - - - - - Only inline coloring: - - - - - Only inline coloring will be shown such as <>,|| etc. - - - - - Mirror IC log: - - - - - IC log will mirror the IC box. Meaning that if somebody gets interrupted nobody will know what they wanted to say. Enable for a more realistic experience. - - - - + Log goes downwards: Портянку вниз: - + If ticked, new messages will appear at the bottom (like the OOC chatlog). The traditional (AO1) behaviour is equivalent to this being unticked. Отметьте галочку, если хотите, чтобы сообщения в игровом чате отображались снизу, а не сверху. - + Log length: Длина игрового чата: - + The amount of messages the IC chatlog will keep before deleting older messages. A value of 0 or below counts as 'infinite'. Количество сообщений, максимально хранимых в игровом чате. Значение, равное 0 или меньше, будет расценено как снятие такого ограничения. - + Default username: Никнейм по умолчанию: - + Your OOC name will be automatically set to this value when you join a server. Псевдоним, используемый при соединении с сервером. В основном, его видно в чате сервера. - + Custom shownames: Произвольные имена: + Gives the default value for the in-game 'Custom shownames' tickbox, which in turn determines whether the client should display custom in-character names. - Отображать произвольные имена персонажей, установленные самими игроками. + Отображать произвольные имена персонажей, установленные самими игроками. - + Backup MS: Запасной ГС: - + If the built-in server lookups fail, the game will try the address given here and use it as a backup master server address. Отображать перечень серверов от главного сервера, указанного здесь, когда не удалось соединиться с первичным ГС. - + Discord: Discord: - + Allows others on Discord to see what server you are in, what character are you playing, and how long you have been playing for. Показать в Discord сервер, на котором вы играете, каким персонажем управляете и время игры. - - Allow Shake/Flash: - - - - - Allows screenshaking and flashing. Disable this if you have concerns or issues with photosensitivity and/or seizures. - - - - + Language: Язык: - + Sets the language if you don't want to use your system language. - - Slower text speed: + + - Keep current setting - - Set the text speed to be the same as the AA games. + + Allow Screenshake: - - Blip delay on punctuations: + + Allows screenshaking. Disable this if you have concerns or issues with photosensitivity and/or seizures. - - Punctuation delay modifier. Enable it for the blips to slow down on punctuations. + + Allow Effects: - + + Allows screen effects. Disable this if you have concerns or issues with photosensitivity and/or seizures. + + + + + Network Frame Effects: + + + + + Send screen-shaking, flashes and sounds as defined in the char.ini over the network. Only works for servers that support this functionality. + + + + + Colors in IC Log: + + + + + Use the markup colors in the server IC chatlog. + + + + + Sticky Sounds: + + + + + Turn this on to prevent the sound dropdown from clearing the sound after playing it. + + + + + Sticky Effects: + + + + + Turn this on to prevent the effects dropdown from clearing the effect after playing it. + + + + + Sticky Preanims: + + + + + Turn this on to prevent preanimation checkbox from clearing after playing the emote. + + + + Callwords Позывные - + <html><head/><body>Enter as many callwords as you would like. These are case insensitive. Make sure to leave every callword in its own line!<br>Do not leave a line with a space at the end -- you will be alerted everytime someone uses a space in their messages.</body></html> <html><head/><body>Введите на отдельных строках свои позывные, при указании которых в сообщениях будет подан звуковой сигнал.</body></html> - + Audio Аудио - + Audio device: Устройство воспроизведения: - + Sets the audio device for all sounds. Куда вещать звук из игры. - + Music: Музыка: + Sets the music's default volume. - Громкость музыки по умолчанию. + Громкость музыки по умолчанию. - + SFX: Звук. эффекты: + Sets the SFX's default volume. Interjections and actual sound effects count as 'SFX'. - Громкость звуковых эффектов по умолчанию. + Громкость звуковых эффектов по умолчанию. - + Blips: Сигналы: - + Sets the volume of the blips, the talking sound effects. Громкость сигналов, заменяющих голос, по умолчанию. - + Blip rate: Пер. сигналов: - + Sets the delay between playing the blip sounds. Период между сигналами, заменяющими голос, по умолчанию. - + + Play a blip sound "once per every X symbols", where X is the blip rate. + + + + Blank blips: Пустые сигналы: - + If true, the game will play a blip sound even when a space is 'being said'. Проигрывать сигналы даже для пробелов. - + Enable Looping SFX: - + If true, the game will allow looping sound effects to play on preanimations. - + Kill Music On Objection: - - If true, the game will stop music when someone objects, like in the actual games. + + If true, AO2 will stop the music for you when you or someone else does 'Objection!'. - + Casing Заседание - + This server supports case alerts. Этот сервер поддерживает объявление заседания. - + This server does not support case alerts. Этот сервер не поддерживает объявление заседания. - + Pretty self-explanatory. Весьма доходчиво. - + Casing: Новое дело: - + If checked, you will get alerts about case announcements. При заведении дела вы получите уведомление. - + Defense: Защита: - + If checked, you will get alerts about case announcements if a defense spot is open. При заведении дела, в котором нужна сторона защиты, вы получите уведомление. - + Prosecution: Обвинение: - + If checked, you will get alerts about case announcements if a prosecutor spot is open. При заведении дела, в котором нужна сторона обвинения, вы получите уведомление. - + Judge: Судья: - + If checked, you will get alerts about case announcements if the judge spot is open. При заведении дела, в котором нужен судья, вы получите уведомление. - + Juror: Присяжный: - + If checked, you will get alerts about case announcements if a juror spot is open. При заведении дела, в котором нужны присяжные заседатели, вы получите уведомление. - + Stenographer: Стенографист: - + If checked, you will get alerts about case announcements if a stenographer spot is open. При заведении дела, в котором нужна стенография, вы получите уведомление. - + CM: ПД: - + If checked, you will appear amongst the potential CMs on the server. Отметьте, если вы хотите состоять в числе производителей дел. - - Witness: - - - - - If checked, you will appear amongst the potential witnesses on the server. - - - - + Hosting cases: ПД акт.: - + If you're a CM, enter what cases you are willing to host. Будучи производителем дела (ПД), вы можете войти в зону и заниматься её оркестровкой. @@ -522,40 +509,36 @@ Reason: Courtroom - + Password Пароль - + Spectator Наблюдатель - - + + Search Поиск - + Passworded Ограничен паролем - + Taken Занят - - Could not find %1 - - - + Generating chars: %1/%2 - Генерация персонажей: + Генерация персонажей: %1/%2 @@ -565,212 +548,440 @@ Reason: - + Showname Имя - + Message Сообщение - + Name Никнейм - + Pre Пред. - + Flip Разв. + Guard - Охрана + Охрана - - + + Additive + + + + + Casing Дело - + Shownames Произв. имена - + No Interrupt Говорить сразу - White - Белый + Белый - Green - Зелëный + Зелëный - Red - Красный + Красный - Orange - Оранжевый + Оранжевый - Blue - Синий + Синий - Yellow - Жëлтый + Жëлтый - This does nothing, but there you go. - В общем-то, это ни на что не влияет... + В общем-то, это ни на что не влияет... - + You need to give a filename to load (extension not needed)! Make sure that it is in the `base/cases/` folder, and that it is a correctly formatted ini. Cases you can load: %1 Укажите имя файла с делом (без расширения) для загрузки. Убедитесь, что оно расположено в папке `base/cases`. Были найдены: %1 - + Case made by %1. Дело завëл игрок: %1. - + Navigate to %1 for the CM doc. Перейдите к %1 для получения материалов дела. - + Your case "%1" was loaded! Дело под кодовым названием "%1" готово! - - + + Server Сервер + + + None + + + + + Hold It! + + + + + + + When this is turned on, your next in-character message will be a shout! + + + + + Objection! + + + + + Take That! + + + + + Toggle between server chat and global AO2 chat. + + + + + + + + This will display the animation in the viewport as soon as it is pressed. + + + + + Guilty! + + + + + Bring up the Character Select Screen and change your character. + + + + + Refresh the theme and update all of the ui elements to match. + + + + + Request the attention of the current server's moderator. + + + + + Allows you to change various aspects of the client. + + + An interface to help you announce a case (you have to be a CM first to be able to announce cases) + + + + + Switch between Areas and Music lists + + + + + Play a single-shot animation as defined by the emote when checked. + + + + + If preanim is checked, display the input text immediately as the animation plays concurrently. + + + + + Mirror your character's emotes when checked. + + + + + Add text to your last spoken message when checked. + + + + + Do not listen to mod calls when checked, preventing them from playing sounds or focusing attention on the window. + + + + + Lets you receive case alerts when enabled. +(You can set your preferences in the Settings!) + + + + + Display customized shownames for all users when checked. + + + + + Custom Shout! + + + + + This will display the custom character-defined animation in the viewport as soon as it is pressed. +To make one, your character's folder must contain custom.[webp/apng/gif/png] and custom.[wav/ogg/opus] sound effect + + + + + Play realization sound and animation in the viewport on the next spoken message when checked. + + + + + Shake the screen on next spoken message when checked. + + + + + Display the list of character folders you wish to mute. + + + + + + Increase the health bar. + + + + + + Decrease the health bar. + + + + + Change the text color of the spoken message. +You can also select a part of your currently typed message and use the dropdown to change its color! + + + + Back to Lobby Назад в лобби - + + + + has played a song + + + + + You will now pair up with %1 if they also choose your character in return. + + + Rainbow - Радужный + Радужный - - OOC Message - - - - - Disable Modcalls - - - - Pink - Розовый + Розовый - Cyan - Голубой + Голубой - + % offset % сдвига - - Music - Музыка + + To front + - - Sfx - Звук. эффекты + + To behind + - - Blips - Сигналы + + Select a character you wish to pair with. + - - Log limit + + Change the percentage offset of your character's position from the center of the screen. + + + + + Change the order of appearance for your character. + + + + + Display the list of characters to pair with. + + + + + Oops, you're muted! + + + + + Set your character's emote to play on your next message. + Set your character's supplementary background. + + + + + Set an 'iniswap', or an alternative character folder to refer to from your current character. +Edit by typing and pressing Enter, [X] to remove. This saves to your base/characters/<charname>/iniswaps.ini + + + + + + Remove the currently selected iniswap from the list and return to the original character folder. + + + + + Set a sound effect to play on your next 'Preanim'. Leaving it on Default will use the emote-defined sound (if any). +Edit by typing and pressing Enter, [X] to remove. This saves to your base/characters/<charname>/soundlist.ini + + + + + Choose an effect to play on your next spoken message. +The effects are defined in your theme/effects/effects.ini. Your character can define custom effects by +char.ini [Options] category, effects = 'miscname' where it referes to misc/<miscname>/effects.ini to read the effects. + + + + + Music + Музыка + + + + Sfx + Звук. эффекты + + + + Blips + Сигналы + + + Change character - + Reload theme - + Call mod - + Settings Настройки - + A/M - + Preanim - - + + Return back to the server list. + + + + + Become a spectator. You won't be able to interact with the in-character screen. + + + + You were granted the Disable Modcalls button. - - You have been banned. + + + CLIENT - - Too many arguments to save a case! You only need a filename without extension and the courtroom status. + + You have been banned. @@ -778,150 +989,320 @@ Cases you can load: %1 Теперь у вас есть кнопка "Охрана". - + You opened the settings menu. Вы открыли меню настроек. - You will now pair up with - Вы встанете парой с персонажем по имени + Вы встанете парой с персонажем по имени - if they also choose your character in return. - (если он выберет вас в ответ). + (если он выберет вас в ответ). - + You are no longer paired with anyone. Теперь вы не стоите в парах. - + Are you sure you typed that well? The char ID could not be recognised. Кажется, вам нужно поменять запрос: такой идентификатор персонажа не был найден. - + You have set your offset to Вы установили сдвиг персонажа на - + Your offset must be between -100% and 100%! Сдвиг персонажа должен быть между -100% и 100%! - + That offset does not look like one. Неверный сдвиг персонажа. - + You switched your music and area list. Вы переключили перечень зон и музыки. - + You have forcefully enabled features that the server may not support. You may not be able to talk IC, or worse, because of this. Из-за того, что вы включили не поддержимаемые сервером возможности, он может не принять ваши сообщения. - + Your pre-animations interrupt again. Персонаж будет говорить только после анимации. - + Your pre-animations will not interrupt text. Персонаж будет говорить и во время анимации. - + Couldn't open chatlog.txt to write into. Не могу открыть `chatlog.txt` для записи лога. - + The IC chatlog has been saved. Лог игрового чата сохранëн. - + You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely the case file you're looking for can't be found in there. Файл с делом не найден. Если найдëте, положите его в папку `base/cases/`, которую мы для вас создали. - + Too many arguments to load a case! You only need one filename, without extension. Введите имя файла без расширения. - + + + + + UNKNOWN + + + + You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely that you somehow deleted it. Папка `base/cases/` отсутствует! - + You need to give a filename to save (extension not needed) and the courtroom status! Введите имя файла (без расширения) и предоставьте статус зоны. + Too many arguments to save a case! You only need a filename without extension and the courtroom status! - Убедитесь, что имя файла не содержит расширение. + Убедитесь, что имя файла не содержит расширение. - + Succesfully saved, edit doc and cmdoc link on the ini! Сохранение прошло успешно! - + Master Мастер - + + Expand All Categories + + + + + Collapse All Categories + + + + + Fade Out Previous + + + + + Fade In + + + + + Synchronize + + + + + Default + + + + Reason: Причина: - + Call Moderator Позвать модератора - - + + Error Ошибка - + You must provide a reason. Укажите причину. - + The message is too long. Слишком длинный текст. - Choose... - Выбрать... + Выбрать... - + + Present this piece of evidence to everyone on your next spoken message + + + + + Save evidence to an .ini file. + + + + + Load evidence from an .ini file. + + + + + Destroy this piece of evidence + + + + + Choose.. + + + + + Close the evidence display/editing overlay. +You will be prompted if there's any unsaved changes. + + + + + Save any changes made to this piece of evidence and send them to server. + + + + + Double-click to edit. Press [X] to update your changes. + + + + + Bring up the Evidence screen. + + + + + Switch evidence to private inventory. + + + + + Switch evidence to global inventory. + + + + + + Transfer evidence to private inventory. + + + + + + Transfer evidence to global inventory. + + + + + The piece of evidence you've been editing has changed. + + + + + Do you wish to keep your changes? + + + + + Name: %1 +Image: %2 +Description: +%3 + + + + Images (*.png) Изображения (*.png) - + + + + Double-click to edit... + + + + Add new evidence... Добавить новую улику... + + + Evidence has been modified. + + + + + Do you want to save your changes? + + + + + Current evidence is global. Click to switch to private. + + + + + Current evidence is private. Click to switch to global. + + + + + "%1" has been transferred. + + + + + Save Inventory + + + + + + Ini Files (*.ini) + + + + + Open Inventory + + Lobby @@ -931,35 +1312,55 @@ Cases you can load: %1 Attorney Online 2 - + + Search + Поиск + + + Name Никнейм - + It doesn't look like your client is set up correctly. Did you download all resources correctly from tiny.cc/getao, including the large 'base' folder? Не похоже, что ваш клиент установлен правильно. Скачали ли вы все ресурсы (tiny.cc/getao), включая огромную папку `base`? - + Version: %1 Версия: %1 - + + Settings + Настройки + + + + Allows you to change various aspects of the client. + + + + Loading Загрузка - + Cancel Отмена - - <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Cents02<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, Raidensnake + + <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>2.8 Major Release development:</b><br>Crystalwarrior, Iamgoofball<p><b>2.8 Quality Assurance:</b><br>WillDean, Captain N, Mr M, Riel, Seimmet, Fury McFlurry,CedricDewitt, Chewable Tablets, Fantos, Futugaze,Geck, Minx, Pandae, Sierra, CrazyJC, CaseyMayCazy,GreenBowers, Robotic Overlord, Veritas, Gin-Gi<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, the AO2 community, server hosts, game masters,case makers, content creators and players! + + + + + About @@ -967,17 +1368,32 @@ Did you download all resources correctly from tiny.cc/getao, including the large <h2>Attorney Online %1</h2>Симулятор судебной драмы<p><b>Исходный код:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Основной разработкой занимались:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>Особенная благодарность:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (дизайн интерфейса), Draxirch (дизайн интерфейса), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy - + Online: %1/%2 Онлайн: %1/%2 - - + + Offline Вне сети + + chatlogpiece + + + + + UNKNOWN + + + + + has played a song: + + + debug_functions @@ -991,7 +1407,7 @@ Did you download all resources correctly from tiny.cc/getao, including the large Ошибка - + Notice На заметку From 9f526c6ecfdc46b6fc424cbb4dcf8b1c96639153 Mon Sep 17 00:00:00 2001 From: sD Date: Sat, 23 May 2020 20:57:06 +0200 Subject: [PATCH 200/268] update german translation --- resource/translations/ao_de.ts | 98 +++++++++++++++++----------------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/resource/translations/ao_de.ts b/resource/translations/ao_de.ts index b4090bf..8b1aa84 100644 --- a/resource/translations/ao_de.ts +++ b/resource/translations/ao_de.ts @@ -315,77 +315,77 @@ Grund: - Keep current setting - + - aktuelle Einstellung behalten Allow Screenshake: - + Schütteln erlauben: Allows screenshaking. Disable this if you have concerns or issues with photosensitivity and/or seizures. - + Erlaubt schütteln des Bildschirms. Deaktiviere dies falls du Bedenken wegen Photosensitivität hast. Allow Effects: - + Effekte erlauben: Allows screen effects. Disable this if you have concerns or issues with photosensitivity and/or seizures. - + Erlaubt Bildeffekte. Deaktiviere dies falls du Bedenken wegen Photosensitivität hast. Network Frame Effects: - + Netzwerk Frame-Effekte: Send screen-shaking, flashes and sounds as defined in the char.ini over the network. Only works for servers that support this functionality. - + Sendet schüttel, Blitze und Geräusche aus der char.ini Datei über das Netzwerk. Funkioniert nur wenn der Server dies unterstützt. Colors in IC Log: - + Farben im IC Log: Use the markup colors in the server IC chatlog. - + Verwendet Farbe im IC Log so wie im Bild. Sticky Sounds: - + Klebende Geräuschauswahl: Turn this on to prevent the sound dropdown from clearing the sound after playing it. - + Aktiviere dies damit die Geräuschauswahl nicht zurückspringt nachdem es abgespielt wurde. Sticky Effects: - + Klebende Effekt: Turn this on to prevent the effects dropdown from clearing the effect after playing it. - + Aktiviere dies damit die Effektauswahl nicht zurückspringt nachdem er abgespielt wurde. Sticky Preanims: - + Klebende Voranimation: Turn this on to prevent preanimation checkbox from clearing after playing the emote. - + Aktiviere dies damit das Kontrollkästchen für die Voranimation nicht zurückspringt nachdem sie abgespielt wurde. @@ -455,7 +455,7 @@ Grund: Play a blip sound "once per every X symbols", where X is the blip rate. - + Spiele ein blip einmal für all X Buchstaben. @@ -485,7 +485,7 @@ Grund: If true, AO2 will stop the music for you when you or someone else does 'Objection!'. - + Hält die Musik an wenn jemand "Einspruch" ruft, wie im echten Spiel. If true, the game will stop music when someone objects, like in the actual games. @@ -846,57 +846,57 @@ Grund: None - + Keine Additive - + Hinzufügend To front - + Vorne To behind - + Hinten Select a character you wish to pair with. - + Wähle einen Charakter mit dem du gepaart sein möchtest. Change the percentage offset of your character's position from the center of the screen. - + Ändere den Abstand des Charakters zur Mitte. Change the order of appearance for your character. - + Ändere die Reihenfolge in der die Charaktere erscheinen. Display the list of characters to pair with. - + Zeigt die Liste der paarbaren Charaktere. Oops, you're muted! - + Ohje, du bist stumm! Set your character's emote to play on your next message. - + Setzt den Ausdruck für die nächste Nachricht. Set your character's supplementary background. - + Setzt die Position des Charakters. @@ -926,29 +926,29 @@ char.ini [Options] category, effects = 'miscname' where it referes to Hold It! - + Moment mal! When this is turned on, your next in-character message will be a shout! - + Wenn dies an ist, wird die Nächste Nachricht ein Zuruf! Objection! - Einspruch! + Einspruch! Take That! - + Nimm das! Toggle between server chat and global AO2 chat. - + Wechselt zwischen Serverchat und AO2 Chat. @@ -961,7 +961,7 @@ char.ini [Options] category, effects = 'miscname' where it referes to Guilty! - + Schuldig! @@ -1087,14 +1087,14 @@ You can also select a part of your currently typed message and use the dropdown CLIENT - + CLIENT has played a song - + spielte ein Lied @@ -1184,7 +1184,7 @@ Verfügbare Fälle: %1 UNKNOWN - + UNBEKANNT @@ -1250,12 +1250,12 @@ Verfügbare Fälle: Expand All Categories - + Alle Kategorien erweitern Collapse All Categories - + Alle Kategorien verstecken @@ -1275,7 +1275,7 @@ Verfügbare Fälle: Default - + Standard @@ -1444,12 +1444,12 @@ Description: Ini Files (*.ini) - + Ini Dateien (*.ini) Open Inventory - + Inventar öffnen @@ -1489,7 +1489,7 @@ Description: Search - Suche + Suche @@ -1511,12 +1511,12 @@ Hast du ALLES von tiny.cc/getao heruntergeladen und entpackt, auch den großen & Settings - Einstellungen + Einstellungen Allows you to change various aspects of the client. - + Erlaubt es verschiedene Aspekte des Clients zu ändern. @@ -1531,12 +1531,12 @@ Hast du ALLES von tiny.cc/getao heruntergeladen und entpackt, auch den großen & <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>2.8 Major Release development:</b><br>Crystalwarrior, Iamgoofball<p><b>2.8 Quality Assurance:</b><br>WillDean, Captain N, Mr M, Riel, Seimmet, Fury McFlurry,CedricDewitt, Chewable Tablets, Fantos, Futugaze,Geck, Minx, Pandae, Sierra, CrazyJC, CaseyMayCazy,GreenBowers, Robotic Overlord, Veritas, Gin-Gi<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, the AO2 community, server hosts, game masters,case makers, content creators and players! - + <h2>Attorney Online %1</h2>Der Gerichtsdrama Simulator<p><b>Quelltext:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Leitende Entwicklung:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>Version 2.8 Entwicklung:</b><br>Crystalwarrior, Iamgoofball<p><b>2.8 Qualitätskontrolle:</b><br>WillDean, Captain N, Mr M, Riel, Seimmet, Fury McFlurry,CedricDewitt, Chewable Tablets, Fantos, Futugaze,Geck, Minx, Pandae, Sierra, CrazyJC, CaseyMayCazy,GreenBowers, Robotic Overlord, Veritas, Gin-Gi<p><b>Danksagungen:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, die AO2 Community, Serverbetreiber, Gamemaster, Fallersteller, Inhaltersteller und Spieler! About - + Über <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Cents02<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, Raidensnake @@ -1605,12 +1605,12 @@ Cronnicossy UNKNOWN - + UNBEKANNT has played a song: - + hat ein Lied gespielt: From 4c45e45257c6681562de3a3157d7c29975456e2d Mon Sep 17 00:00:00 2001 From: sD Date: Sat, 23 May 2020 21:01:43 +0200 Subject: [PATCH 201/268] include the translations with the client or they can't get loaded --- resources.qrc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/resources.qrc b/resources.qrc index 974f797..cca23ef 100644 --- a/resources.qrc +++ b/resources.qrc @@ -2,5 +2,12 @@ resource/fonts/Ace-Attorney.ttf resource/logo_ao2.png + resource/translations/ao_de.qm + resource/translations/ao_en.qm + resource/translations/ao_es.qm + resource/translations/ao_jp.qm + resource/translations/ao_pl.qm + resource/translations/ao_pt.qm + resource/translations/ao_ru.qm From a8035542bd379c8f27087895d126361de22c19b2 Mon Sep 17 00:00:00 2001 From: oldmud0 Date: Sun, 31 May 2020 17:05:55 -0500 Subject: [PATCH 202/268] Bring back AO themes submodule --- .gitmodules | 3 + base/themes | 1 + base/themes/default/about.png | Bin 3298 -> 0 bytes base/themes/default/addevidence.png | Bin 403 -> 0 bytes base/themes/default/addtofav.png | Bin 972 -> 0 bytes base/themes/default/addtofav_pressed.png | Bin 938 -> 0 bytes base/themes/default/arrow_left.png | Bin 396 -> 0 bytes base/themes/default/arrow_right.png | Bin 391 -> 0 bytes base/themes/default/char_passworded.png | Bin 1904 -> 0 bytes base/themes/default/char_selector.png | Bin 285 -> 0 bytes base/themes/default/char_taken.png | Bin 215 -> 0 bytes base/themes/default/charselect_background.png | Bin 5342 -> 0 bytes base/themes/default/chat.png | Bin 590 -> 0 bytes base/themes/default/chatbig.png | Bin 584 -> 0 bytes base/themes/default/chatmed.png | Bin 579 -> 0 bytes base/themes/default/connect.png | Bin 914 -> 0 bytes base/themes/default/connect_pressed.png | Bin 925 -> 0 bytes base/themes/default/courtroom_design.ini | 302 ------------------ base/themes/default/courtroom_fonts.ini | 56 ---- base/themes/default/courtroom_sounds.ini | 8 - base/themes/default/courtroombackground.png | Bin 50139 -> 0 bytes base/themes/default/crossexamination.gif | Bin 88834 -> 0 bytes base/themes/default/crossexamination.png | Bin 4187 -> 0 bytes base/themes/default/custom.png | Bin 2505 -> 0 bytes base/themes/default/custom_selected.png | Bin 2212 -> 0 bytes base/themes/default/defense_speedlines.gif | Bin 31308 -> 0 bytes base/themes/default/defensebar0.png | Bin 171 -> 0 bytes base/themes/default/defensebar1.png | Bin 188 -> 0 bytes base/themes/default/defensebar10.png | Bin 184 -> 0 bytes base/themes/default/defensebar2.png | Bin 187 -> 0 bytes base/themes/default/defensebar3.png | Bin 187 -> 0 bytes base/themes/default/defensebar4.png | Bin 188 -> 0 bytes base/themes/default/defensebar5.png | Bin 188 -> 0 bytes base/themes/default/defensebar6.png | Bin 188 -> 0 bytes base/themes/default/defensebar7.png | Bin 187 -> 0 bytes base/themes/default/defensebar8.png | Bin 188 -> 0 bytes base/themes/default/defensebar9.png | Bin 188 -> 0 bytes base/themes/default/defminus.png | Bin 492 -> 0 bytes base/themes/default/defplus.png | Bin 498 -> 0 bytes base/themes/default/deleteevidence.png | Bin 3280 -> 0 bytes base/themes/default/emote_selected.png | Bin 249 -> 0 bytes base/themes/default/evidence_appear_left.gif | Bin 2008 -> 0 bytes base/themes/default/evidence_appear_right.gif | Bin 2225 -> 0 bytes base/themes/default/evidence_selected.png | Bin 291 -> 0 bytes base/themes/default/evidence_selector.png | Bin 931 -> 0 bytes base/themes/default/evidencebackground.png | Bin 19927 -> 0 bytes base/themes/default/evidencebutton.png | Bin 577 -> 0 bytes base/themes/default/evidenceoverlay.png | Bin 2187 -> 0 bytes base/themes/default/evidencex.png | Bin 637 -> 0 bytes base/themes/default/favorites.png | Bin 3882 -> 0 bytes base/themes/default/favorites_selected.png | Bin 4306 -> 0 bytes base/themes/default/guilty.gif | Bin 43263 -> 0 bytes base/themes/default/guilty.png | Bin 2851 -> 0 bytes base/themes/default/holdit.png | Bin 1983 -> 0 bytes base/themes/default/holdit_selected.png | Bin 1835 -> 0 bytes base/themes/default/loadingbackground.png | Bin 2194 -> 0 bytes base/themes/default/lobby_design.ini | 17 - base/themes/default/lobbybackground.png | Bin 29532 -> 0 bytes base/themes/default/mute.png | Bin 5037 -> 0 bytes base/themes/default/mute_pressed.png | Bin 4978 -> 0 bytes base/themes/default/muted.png | Bin 1013 -> 0 bytes base/themes/default/notguilty.gif | Bin 34911 -> 0 bytes base/themes/default/notguilty.png | Bin 3269 -> 0 bytes base/themes/default/objection.png | Bin 2147 -> 0 bytes base/themes/default/objection_selected.png | Bin 1988 -> 0 bytes base/themes/default/pair_button.png | Bin 4677 -> 0 bytes base/themes/default/pair_button_pressed.png | Bin 4619 -> 0 bytes base/themes/default/placeholder.gif | Bin 9168 -> 0 bytes base/themes/default/present.png | Bin 3035 -> 0 bytes base/themes/default/present_disabled.png | Bin 2905 -> 0 bytes base/themes/default/prominus.png | Bin 493 -> 0 bytes base/themes/default/proplus.png | Bin 498 -> 0 bytes .../themes/default/prosecution_speedlines.gif | Bin 31252 -> 0 bytes base/themes/default/prosecutionbar0.png | Bin 200 -> 0 bytes base/themes/default/prosecutionbar1.png | Bin 237 -> 0 bytes base/themes/default/prosecutionbar10.png | Bin 173 -> 0 bytes base/themes/default/prosecutionbar2.png | Bin 241 -> 0 bytes base/themes/default/prosecutionbar3.png | Bin 230 -> 0 bytes base/themes/default/prosecutionbar4.png | Bin 243 -> 0 bytes base/themes/default/prosecutionbar5.png | Bin 241 -> 0 bytes base/themes/default/prosecutionbar6.png | Bin 241 -> 0 bytes base/themes/default/prosecutionbar7.png | Bin 242 -> 0 bytes base/themes/default/prosecutionbar8.png | Bin 240 -> 0 bytes base/themes/default/prosecutionbar9.png | Bin 237 -> 0 bytes base/themes/default/publicservers.png | Bin 3999 -> 0 bytes .../themes/default/publicservers_selected.png | Bin 4427 -> 0 bytes base/themes/default/realization.png | Bin 4259 -> 0 bytes base/themes/default/realization_pressed.png | Bin 4225 -> 0 bytes base/themes/default/realizationflash.png | Bin 646 -> 0 bytes base/themes/default/refresh.png | Bin 914 -> 0 bytes base/themes/default/refresh_pressed.png | Bin 919 -> 0 bytes base/themes/default/takethat.png | Bin 2057 -> 0 bytes base/themes/default/takethat_selected.png | Bin 1932 -> 0 bytes base/themes/default/testimony.gif | Bin 1033 -> 0 bytes base/themes/default/testimony.png | Bin 579 -> 0 bytes base/themes/default/witnesstestimony.gif | Bin 105223 -> 0 bytes base/themes/default/witnesstestimony.png | Bin 5186 -> 0 bytes 97 files changed, 4 insertions(+), 383 deletions(-) create mode 100644 .gitmodules create mode 160000 base/themes delete mode 100644 base/themes/default/about.png delete mode 100644 base/themes/default/addevidence.png delete mode 100644 base/themes/default/addtofav.png delete mode 100644 base/themes/default/addtofav_pressed.png delete mode 100644 base/themes/default/arrow_left.png delete mode 100644 base/themes/default/arrow_right.png delete mode 100644 base/themes/default/char_passworded.png delete mode 100644 base/themes/default/char_selector.png delete mode 100644 base/themes/default/char_taken.png delete mode 100644 base/themes/default/charselect_background.png delete mode 100644 base/themes/default/chat.png delete mode 100644 base/themes/default/chatbig.png delete mode 100644 base/themes/default/chatmed.png delete mode 100644 base/themes/default/connect.png delete mode 100644 base/themes/default/connect_pressed.png delete mode 100644 base/themes/default/courtroom_design.ini delete mode 100644 base/themes/default/courtroom_fonts.ini delete mode 100644 base/themes/default/courtroom_sounds.ini delete mode 100644 base/themes/default/courtroombackground.png delete mode 100644 base/themes/default/crossexamination.gif delete mode 100644 base/themes/default/crossexamination.png delete mode 100644 base/themes/default/custom.png delete mode 100644 base/themes/default/custom_selected.png delete mode 100644 base/themes/default/defense_speedlines.gif delete mode 100644 base/themes/default/defensebar0.png delete mode 100644 base/themes/default/defensebar1.png delete mode 100644 base/themes/default/defensebar10.png delete mode 100644 base/themes/default/defensebar2.png delete mode 100644 base/themes/default/defensebar3.png delete mode 100644 base/themes/default/defensebar4.png delete mode 100644 base/themes/default/defensebar5.png delete mode 100644 base/themes/default/defensebar6.png delete mode 100644 base/themes/default/defensebar7.png delete mode 100644 base/themes/default/defensebar8.png delete mode 100644 base/themes/default/defensebar9.png delete mode 100644 base/themes/default/defminus.png delete mode 100644 base/themes/default/defplus.png delete mode 100644 base/themes/default/deleteevidence.png delete mode 100644 base/themes/default/emote_selected.png delete mode 100644 base/themes/default/evidence_appear_left.gif delete mode 100644 base/themes/default/evidence_appear_right.gif delete mode 100644 base/themes/default/evidence_selected.png delete mode 100644 base/themes/default/evidence_selector.png delete mode 100644 base/themes/default/evidencebackground.png delete mode 100644 base/themes/default/evidencebutton.png delete mode 100644 base/themes/default/evidenceoverlay.png delete mode 100644 base/themes/default/evidencex.png delete mode 100644 base/themes/default/favorites.png delete mode 100644 base/themes/default/favorites_selected.png delete mode 100644 base/themes/default/guilty.gif delete mode 100644 base/themes/default/guilty.png delete mode 100644 base/themes/default/holdit.png delete mode 100644 base/themes/default/holdit_selected.png delete mode 100644 base/themes/default/loadingbackground.png delete mode 100644 base/themes/default/lobby_design.ini delete mode 100644 base/themes/default/lobbybackground.png delete mode 100644 base/themes/default/mute.png delete mode 100644 base/themes/default/mute_pressed.png delete mode 100644 base/themes/default/muted.png delete mode 100644 base/themes/default/notguilty.gif delete mode 100644 base/themes/default/notguilty.png delete mode 100644 base/themes/default/objection.png delete mode 100644 base/themes/default/objection_selected.png delete mode 100644 base/themes/default/pair_button.png delete mode 100644 base/themes/default/pair_button_pressed.png delete mode 100644 base/themes/default/placeholder.gif delete mode 100644 base/themes/default/present.png delete mode 100644 base/themes/default/present_disabled.png delete mode 100644 base/themes/default/prominus.png delete mode 100644 base/themes/default/proplus.png delete mode 100644 base/themes/default/prosecution_speedlines.gif delete mode 100644 base/themes/default/prosecutionbar0.png delete mode 100644 base/themes/default/prosecutionbar1.png delete mode 100644 base/themes/default/prosecutionbar10.png delete mode 100644 base/themes/default/prosecutionbar2.png delete mode 100644 base/themes/default/prosecutionbar3.png delete mode 100644 base/themes/default/prosecutionbar4.png delete mode 100644 base/themes/default/prosecutionbar5.png delete mode 100644 base/themes/default/prosecutionbar6.png delete mode 100644 base/themes/default/prosecutionbar7.png delete mode 100644 base/themes/default/prosecutionbar8.png delete mode 100644 base/themes/default/prosecutionbar9.png delete mode 100644 base/themes/default/publicservers.png delete mode 100644 base/themes/default/publicservers_selected.png delete mode 100644 base/themes/default/realization.png delete mode 100644 base/themes/default/realization_pressed.png delete mode 100644 base/themes/default/realizationflash.png delete mode 100644 base/themes/default/refresh.png delete mode 100644 base/themes/default/refresh_pressed.png delete mode 100644 base/themes/default/takethat.png delete mode 100644 base/themes/default/takethat_selected.png delete mode 100644 base/themes/default/testimony.gif delete mode 100644 base/themes/default/testimony.png delete mode 100644 base/themes/default/witnesstestimony.gif delete mode 100644 base/themes/default/witnesstestimony.png diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..1376cc1 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "base/themes"] + path = base/themes + url = https://github.com/AttorneyOnline/AO2-Themes diff --git a/base/themes b/base/themes new file mode 160000 index 0000000..620915d --- /dev/null +++ b/base/themes @@ -0,0 +1 @@ +Subproject commit 620915d85afdeb51bb3bd7766d5807bbdc6fa876 diff --git a/base/themes/default/about.png b/base/themes/default/about.png deleted file mode 100644 index 50fc821394fa482018033752c79d87094dd34e68..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3298 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 diff --git a/base/themes/default/addevidence.png b/base/themes/default/addevidence.png deleted file mode 100644 index 7a432af2d7e9596bf8c7ef74501b058b2a6a1862..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 403 zcmeAS@N?(olHy`uVBq!ia0vp^ZXnFT1|$ph9<=}|wj^(N7lsTF3|;eu5h%i0;1OBO zz`%C|gc+x5^GO2**-JcqUD+S9ii#;ISk3udz`($$;OXKRQgQ3;9mTxE4gziuw}(3D z2S_|_ZEI|8wL2uIctGL81_cH88_GW=K^9=3V$rPS?1dPrM)jAzhiy=@-D`VZL+Vwp5B)- zqfp{@L_R~srs8$(5{WH>ZgAolM{#jj|G&n}S+}yEhlajgD-rDpl03$t++%PEM5Ov& zzwdi;|KGjyXPsIL);HsSjrQGY=^xLswK;(bkPLhID=>JcC`{)e4+W?h^|tZn`Tj0U zmN~X9r6=Mz_nAud%XgL>*%Y$u$rnrJ;{tl_=k?w*J&<6qW4w38a@F&8zv;l>WAJqK Kb6Mw<&;$UY7M`O3 diff --git a/base/themes/default/addtofav.png b/base/themes/default/addtofav.png deleted file mode 100644 index 7d9890347e076b58657cb28c8339fec4b83f7d3b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 972 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 diff --git a/base/themes/default/char_passworded.png b/base/themes/default/char_passworded.png deleted file mode 100644 index e79d0710bc8d9d7414b8fdcd95184c88fb429e35..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1904 zcmeAS@N?(olHy`uVBq!ia0vp^HXzKw3=&b&bO2Hc$sR$z3=CDO3=9p;3=BX21L>Cx z45bDP46hOx7_4S6Fo@?*ia+Ycz`)E9;1l8s)FUAwU}0eq;K5K(P|%Peuw#P8iwzD7 z7A*L1q2a=X3qOAR0IC@UqaiRXLqK=+%_as0Muw6gzu^BP8!!ZaX9t!W44efXk;M!Q z+(IDCcDP; zlYQ=73NsWw`a8Sc(e=s~wV4q|eShX1oqt7~!{(*0(Z(*{NdKe1FK=K7ygZvNNz}fj zvv%R05AR}+*tKmxe7)-qL%6cKe4{H*Vg>hisadkWcza*T@wOyKeo@-Cp<{7k;j&es zTQd&+w`@JRMwao^rWdm#W|>dc)ad%>u;j(9uQ5j+Oj|2qE0iIb#g!}Lqcop;Z?1aY zI=^?OU0Dpplhk@VbYC7=n-J*YU*NI*@Ps7pjR#+tlum70q$0b+-R+c;LZEcsirg8; z&(vO6oGL$4h2L$ZhQk8$VvfUIuFWfN>uplb%uiSNa&!0Aw#hf6H{bJLbIhMpStawI$d&1sG;Vz%pkSZOJ-aS!^WhnbBbtI4k3X}KuJZaBGO^rsUh%esSzivT&5Z6;G4a*zXSuq9wRcY4 zEtTm)3>zQaIvjf9X6n%og_BJtJ&VY)-#PPq+|N_TLblZ2P}#A}W2MZ(y+;CyZ=R9N zn=py*4p*D8@eWtVBNLzGo|T^CKIzsY=I43UDrXBP&xkK)JZ0*_=6%fcaL;U(!+td% z__`B5D6iWy)70E^p=`N?pVy_v=z|;jKk_SIOKZ9y^4Pi2caz0rKAog#&pUS-YVEVS zaPDW*66Wq7iS-8Fr`PlC6P>esrUx*J#m}sZYqYq%@zZzKDGMC0e6pRr{)8XT*E?dL z)4y}x>Pp|0A=J=rvOht&ZPv?0o*wnT-`?(&oZUSyymr>T4WjzF{)er|!(p3wjR diff --git a/base/themes/default/char_selector.png b/base/themes/default/char_selector.png deleted file mode 100644 index e868cdb97b5b26084b5196183f4e6ed15e664cce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 285 zcmeAS@N?(olHy`uVBq!ia0vp^b|B2b1|*9Qu5bZTY)RhkE)4%caKYZ?lYt_f1s;*b z3=DjSL74G){)!Z!AbW|YuPggQW+8SCwaw4x83Tn@dAc};WZZju+feY3gFxHGy&jD0 z4J?mZ1bk)qe0=gRyKgc}(vDIKe;ke`|#^-M@G(8%~$-HET2 z`3Gf>-&I_es`s>NU(JQ>$D^{`=6^eW=fmA^Yh?dszgcv#v6*!6pYwjwmRa9(bIdp9 cn69d2lxH)peB>DO3g~JEPgg&ebxsLQ0N~(rng9R* diff --git a/base/themes/default/char_taken.png b/base/themes/default/char_taken.png deleted file mode 100644 index efad48dcc461474c7349bdce3fe0919497eb966b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 215 zcmeAS@N?(olHy`uVBq!ia0vp^HXzKw1|+Ti+$;i8Y)RhkE)4%caKYZ?lYt_f1s;*b z3=DjSL74G){)!Z!AbW|YuPggQW+8Sqk*Av<*#d=9JY5_^GVZ;-=*Y`pz{9*TL~8W} z=`Vpd_S>N_d)@bX*^VKtu_28oASI7w$bd@na+rpl%ERKqnu`xrc3{an^L HB{Ts5v6Dkj diff --git a/base/themes/default/charselect_background.png b/base/themes/default/charselect_background.png deleted file mode 100644 index 4480e6f454289a99104a1c27d9074cdd4adb8753..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5342 zcmeAS@N?(olHy`uVBq!ia0y~yU^)fFb2ylRBFE>5jgR3=A9lx&I`xGB7YR z1o(uw0>!zxxf2r;Gcz;0ySsthQ7{?;BPRq--<7!n^etzBM`SSr1K%MKW)#)%Y5)pK zl(rIsj|=o#vn2s>mPVPFsp@N{tusfc@fb7S6<2odIs zx!eE$pIy$jA(qX@Fhl!+&6Sg(=7~x#_m{uq@QZ9OIAzrmd`)rACccMLN;#IVakfa6 zJ*4?sfJRa-Ge3QP>w3Pwfm8VY-B~|gR-HP3yk5VmM$RPh(QIqsgHNZ#+kY>;a713M zAYN(boKLrpZ`Q9g{&5u_FMcYJ=fBi|IUZydT?F+zP%mAYCaFH9q~^+b!q<*l(cecN^QJZgTe~DWM4fl+uUP diff --git a/base/themes/default/chat.png b/base/themes/default/chat.png deleted file mode 100644 index 47281a9618763259f1c1f312b66513a153b08e15..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 590 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5GC0_Pq}(FCr$CCaILO_JVcj{Imp~3nx}&cn z1H;CC?mvmFKt5-IM`SSr1K&XqX529``z=tzV^0^ykczmsw+zc>JBT<0PIRr}zSk7X zICXDpj^b<;M#a8pZM~Lzd(WPcl$!OQYsSM*=Qruhe_dsE*kI4w=m&gbP0l+XkK#M!IF diff --git a/base/themes/default/chatbig.png b/base/themes/default/chatbig.png deleted file mode 100644 index ee8d9ce2176ce424374fcb851b7223e74cce7bed..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 584 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5GC0_Pq}(FCr$CCaILO_JVcj{Imp~3nx}&cn z1H;CC?mvmFKt5-IM`SSr1K&XqX529``z=tzT~8Oskczmsw>K6xJBTs1D>4yG)oAb9B&l~nV z-qyvCev4^C{J+dywo`1bncS^=Z_31UU}hh~n(6=lKCV0ETw8xvNr7R`+qe5Zxj3D! zS7Z=SLq%mQ34itW*3DS3CnBG1}p{DwK>xXJ?dPd{CzZ+;WJqTa3XucCm~vX{GD z4|qFp2s4amWX)vYd;K?GMQZ)~UmJ8zKi@U;d8IW&+YryJM(G2=P>cW0}&RNra)^PkHO+*pSVav>LPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02p*dSaefwW^{L9 za%BK;VQFr3E^cLXAT%y8E;(#7eog=Y0|QA!K~!i%?U=D{6hRDz?@=h}fQl0CEr5;+ zQPSNNloaU@1qGrYL?|Z`i2@XmAb=pENP zF|>z6RKy_g{pYD;gc4@3Qce^;XK;~2Z@NmdrzNaHv(Y2 zFyxVto@(eb?zy#8BVpBIUmmm6rb3PJX!Z(@f&(3#m#w{7=c1fOKw>X!(Nm4~oLj5G z>#&!VKD9BRDS+9b`!o2(pZzb(KQ~K_`VxC#i=Jw@-uLdyXfk+wKDDvnoN?}_ zzt7<4(bCV&QgJR~FKp3M4cGhLeL0`jhtwyAKDDWEV_X=bv=NZl3tRM5Bk8p~eNNG8 z#ArEvYWsqwSW81d9tr8GM$^+c?m4s)RxS4BF-vU;1~CK>x-`%G^j0m6uC-aJf~_y@E$x*)DQq(o-gfVNP4bCO{fR# zDcaEDy|g;6<9aP$lEDoDz{NR|4hd;}IfQCbv>_}#xCXIkO0gD(sH_jw5EX}Nh>Als zM8%;RqT;YJLrkvbWvX$-&csUFcO8+wb6*@oJiBwfc{#nk61FF|HWKNsI}u3rs{}mI o8DcZIDR3hKsa`r~lNmSv0i-pe)B8t#HakN^Mx diff --git a/base/themes/default/connect_pressed.png b/base/themes/default/connect_pressed.png deleted file mode 100644 index a99d9ec119c357bacc4317b56268a8cddb903c35..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 925 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 CP6M<6 diff --git a/base/themes/default/crossexamination.gif b/base/themes/default/crossexamination.gif deleted file mode 100644 index a7754b6073be35351d5cab4f5864c6d1d22af944..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 88834 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

    p+Q;P=Oj?LfKYA^CeEot+`#GN{r7Y!r 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

    >K1IV}JlaDaLwQ#VX(jo}jbq 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

    a?RCLM9n2&nwW{vb%1vw!>68h;G zH^cX7j2T9LX{g$sl}`-@BHss~F)g>|jGG}gbCgM~G{qgULKR;){xnLUt?Ud&6=a$(3+k@KRQf2aH zrZMY!_w%7uT3|mA7m=axXK`7pr-KY|+65Dyy)KK!+3(`ik~}S*=4q+#dk;pP7CpxF z)NjJ2GljoBLmx42#$jElaaR(_LE6#sSbcu&^64>^OR<35>ye<3-^<|DnJ|3>#&RXf z>{j474}kyk$jozsdNpDS>%82e z&0~8)cotrs;tlqPHv;4kHYqQ4y6kv6w(waBRN z0^w4^&T^m4ixd1gCjts z*XUPb5^`SPqB(;GurMAZRhc&I_u~rbWky2CW-+7J7RV}6J=v;z-n<1_Klt;c`eim4P#?`;XwAu=eBA@D2ejI2yo zd$AjP4K*bFJOdr7)4%m!F zJ-YwuUaf_b9EtXYm2&H?g%6u8r%`Byd1t&~DI!USb%U%Cu=`Cc6ozSj|HmiZs=E+_ zIiR0v$I0Q%7%xAyU`7$fyho!CabPP2WJvi+0p@$P<{ZU7UF`N!%LWmRGmrr!4pZ|n zn_$C6SrS258WtfifdI+>0?!tRYybcN diff --git a/base/themes/default/crossexamination.png b/base/themes/default/crossexamination.png deleted file mode 100644 index 044a76b900aa1d14e44c58c46de7f5fe7ff95356..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4187 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 diff --git a/base/themes/default/custom.png b/base/themes/default/custom.png deleted file mode 100644 index b58d1620b4de890be0ac754665665e39678147c9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2505 zcmV;)2{!hLP)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00009 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 FI1D3to7w;X diff --git a/base/themes/default/defensebar0.png b/base/themes/default/defensebar0.png deleted file mode 100644 index e15b7276c330eaf2dae6ff18f1d824605af1c69f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 171 zcmeAS@N?(olHy`uVBq!ia0vp^AwbN>!3HEZ)>#JtDYhhUcNYdT21^EeuYau7KoQOY zkH})6s@)*Wc>Ko|GoT=QiKnkC`y(E11{0977@wzrEln$e_T%VDN#* zU8*U{%lkoo_l7lg<`RFVdQ&MBb@0DGk`rT_o{ diff --git a/base/themes/default/defensebar1.png b/base/themes/default/defensebar1.png deleted file mode 100644 index ddc7c05215dd04b699336f978e6ae96b0c8f530c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 188 zcmeAS@N?(olHy`uVBq!ia0vp^AwbN>!3HEZ)>#JtDYhhUcNYdT21^EeuYau7KoQOY zkH})6s@)*Wc>Ko|GoT=QiKnkC`y(E124hq8!rN9rAx}>i$B>A_$zM)bf1RHw62QA* zk6k&-`lik9U2e{uEC)=aSQax{Ni6^pTyD%ICJye*B_cg+FESeX*j{Kz@CMvsI(G4( c;43BuLu1a_Izo!3HEZ)>#JtDYhhUcNYdT21^EeuYau7KoQOY zkH})6s@)*Wc>Ko|GoT=QiKnkC`y(E11}%nHhqf^Sg^^S@gniwbP0l+XkK9BeqM diff --git a/base/themes/default/defensebar2.png b/base/themes/default/defensebar2.png deleted file mode 100644 index 78835aab9d4cc36ca86a31a62ee5bdeb6d15f409..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 187 zcmeAS@N?(olHy`uVBq!ia0vp^AwbN>!3HEZ)>#JtDYhhUcNYdT21^EeuYau7KoQOY zkH})6s@)*Wc>Ko|GoT=QiKnkC`y(E124jP8Y5lE0ArDU%$B>A_Z*OcAY)}wz2|T~h zVzuH1H>I=%g53wM%rUOs-@qHUqwwlJzNMk_Zf;|9+pSq=CCI?a72?pyBpR^5f%VJ% dLza_nbALF(Ia}ts#9g4744$rjF6*2UngAzoIE?@R diff --git a/base/themes/default/defensebar3.png b/base/themes/default/defensebar3.png deleted file mode 100644 index 8d8427af95681d0c02d3526d4dff55b84dfac020..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 187 zcmeAS@N?(olHy`uVBq!ia0vp^AwbN>!3HEZ)>#JtDYhhUcNYdT21^EeuYau7KoQOY zkH})6s@)*Wc>Ko|GoT=QiKnkC`y(E124n5Jb{yINVB!G9r z9=r0EXVd1`2AL!=P02Lz?PYtB(a^{CLPLW0!bJvI-V1>SQVSL{S^!3HEZ)>#JtDYhhUcNYdT21^EeuYau7KoQOY zkH})6s@)*Wc>Ko|GoT=QiKnkC`y(E124l6w=Vv_u3VC|EIEF+VPX2Pj`s@5ekpSKe zd+f?n4#*aM^SHQyGho?86H}=Liy5teM1qNfJ97z;IGEAU$Myn9G+ks^s+%AqE3;6K afg$||=j?jV)}uf}89ZJ6T-G@yGywqLdpP0% diff --git a/base/themes/default/defensebar5.png b/base/themes/default/defensebar5.png deleted file mode 100644 index d9236c26f61a64da2fe7f68a85c5761bb251d54d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 188 zcmeAS@N?(olHy`uVBq!ia0vp^AwbN>!3HEZ)>#JtDYhhUcNYdT21^EeuYau7KoQOY zkH})6s@)*Wc>Ko|GoT=QiKnkC`y(E124e-UHTD;QLY|&3jv*0;lfRs>{yINVB!G9r z9=q}s4~s8vCN5HZ=(p^miK*0r#f(-!BEiJLow)=^9L#9wV|xK4nl3Ud)lHC*m076A Zz#!klIXk8~cp1=822WQ%mvv4FO#qOHH-P{E diff --git a/base/themes/default/defensebar6.png b/base/themes/default/defensebar6.png deleted file mode 100644 index 373bc1b0f9372c6ffb70c73e3dee47acdbc7b6ce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 188 zcmeAS@N?(olHy`uVBq!ia0vp^AwbN>!3HEZ)>#JtDYhhUcNYdT21^EeuYau7KoQOY zkH})6s@)*Wc>Ko|GoT=QiKnkC`y(E124hLlmD_Iug*-i7977@wCx1C%{dIn#NC5AK zJ$B_O5fx9~OkCvnkZ;*V6H}=Liy5teM1qNfJ97z;IGEAU$Myn9G+ks^s+%AqE3;6K af#JR^=j_#YJN^I-W$<+Mb6Mw<&;$U>emQ3V diff --git a/base/themes/default/defensebar7.png b/base/themes/default/defensebar7.png deleted file mode 100644 index 09c8d1af8f0fb56adb5b3742e1a025dcd57265ca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 187 zcmeAS@N?(olHy`uVBq!ia0vp^AwbN>!3HEZ)>#JtDYhhUcNYdT21^EeuYau7KoQOY zkH})6s@)*Wc>Ko|GoT=QiKnkC`y(E124jJoQvOV@Sl|>_oI0yg$ diff --git a/base/themes/default/defensebar8.png b/base/themes/default/defensebar8.png deleted file mode 100644 index 13a45480535b15850e1ea8ae1a0e90515a3a8c0c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 188 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 O00000#LT=By}Z;C1rt33 zJFVdQ&MBb@02z8yJpcdz diff --git a/base/themes/default/evidence_appear_left.gif b/base/themes/default/evidence_appear_left.gif deleted file mode 100644 index 352a7f190316a57d0c1e9c4a8250259505afb79c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2008 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 XfzYmZccH$^1h>%8Yg2d^4A}h(s9xQ5 diff --git a/base/themes/default/evidence_selected.png b/base/themes/default/evidence_selected.png deleted file mode 100644 index 6230c836e9342c9eb646628e7b9deb0f51262f70..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 291 zcmeAS@N?(olHy`uVBq!ia0vp^HXzKw1|+Ti+$;i8jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1qucL5ULAh?3y^w370~qEv>0#LT=By}Z;C1rt33 zJPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02y>eSaefwW^{L9 za%BK;VQFr3E^cLXAT%y8E-^DS16z6k00R?AL_t(|UhSL7ZW}QShV}k0)V+YWjGYu{ zlQ`buByGHm6JLtHz?92SW4c6dJrw!{d|>7vAow9JqUh8#O`6{ho5gh0!QcN0{J;MT zSeG>FzvDl!&erU@-=u2zK|U@9?*Xx1O+^nrm1%PENj~o9V>aSuCG)a>AVYf0#!YrB zK1Q^{4JEOAUXp2=J9evK|E+vL9A&praU|wUMjz#4O~;5tyqs7kXO?SHsOYn zsJHiInr2BQP2vd6i=#8Ga6?Jdn-v+-Xj)(7L zRF5?1y^#;Nm11rsC&%0hsa&yC&U$n$3slHLy*;Ur^NZ(Q#U|WP5{LF~#d_paj%=m4 z3K?~d#|30-S-`Cnb1NBMvY4}+qMyTLrJ{W zk7QI2Oj(>^?^bTg0&b-^x5CNsxRYab4(D}R;f9iML)tcn%tOhv!VM+ihP3nD3gQS( zoX)LqePG;+XO;Uo7(rnUZb-XzD-16w;gB}Q-jsMq8>w8tkoI4QhqTcN6zuxohqNJ% z;Kad@w&&PRS;&yK%>>Ty`XE?^%zETH2h*fVb}O_j{v>Q!pw3a^A#G$UAx!1CJ}BXk zHd+>nAJVpfjFyFv12VTPa?C-?Lg-RCWve`-{S}j4%=U-I9M&Vhcw$Ifu@_I)qsvyP zkOgxqdDQDt`2Y}Z4%uQ3mR~aVMpk}H4LW}PJd!L;`VCfL;Xj+>L`nbv002ovPDHLk FV1i$4toQ%` diff --git a/base/themes/default/evidencebackground.png b/base/themes/default/evidencebackground.png deleted file mode 100644 index ca285326cbb2df7e2d40474814a4db464248e760..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19927 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 P00000NkvXXu0mjf_J{+{ diff --git a/base/themes/default/evidenceoverlay.png b/base/themes/default/evidenceoverlay.png deleted file mode 100644 index d409cc5822c70a63f4088ae39b5cebdd41b483a5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2187 zcmeAS@N?(olHy`uVBq!ia0y~yVB8L5-{W8dlKZ6n&H^dM;vjb?hIQv;UIIBR>5jgR z3=A9lx&I`x0{NT;9+AZi419+{nDKc2iWH!rWQl7;NpOBzNqJ&XDnmhHW?qS2UTTSg ziJpO;p|J^bbQJ>w`)^Md$B>G+w^tpx9Kr=%F21>9n(~BAW+(gI8O#S81O!XiFY?t# zu*%Oisj*~Dzx4R{Zu>vw_Dl!<&#Yi+(C>C<_^}BWqbvT*8NTWN6yrMGyPofzIdiVg zU*|nS{UYb9jg74%f3;Vr%4yE~o|aa&=?niyFPk8n_h-+%NqH&%XllihihHwX-aL89 z{)qNRkB@uIjWAgeDBN|ziETWf>;9kixBt)mz})=5 uFSr(Dd~o`aAj3W#Il3|IUbV~rXP(a)&@_oJJRjIrVDNPHb6Mw<&;$Vb6U2r9 diff --git a/base/themes/default/evidencex.png b/base/themes/default/evidencex.png deleted file mode 100644 index 6a6be36f72644cde4a1e14813e648fff1ab6f838..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 637 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 diff --git a/base/themes/default/favorites_selected.png b/base/themes/default/favorites_selected.png deleted file mode 100644 index 4c33d432ec19d0402b6a0d7ece7ca969185b26a7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4306 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 AzyJUM diff --git a/base/themes/default/guilty.gif b/base/themes/default/guilty.gif deleted file mode 100644 index 3dd95d554410755ab1a3dd43ae1b0088d4de87dd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 43263 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 diff --git a/base/themes/default/guilty.png b/base/themes/default/guilty.png deleted file mode 100644 index efe68f702910a60e8f3e7eadd8d4d776bfe6128c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2851 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 RM#lgE002ovPDHLkV1kyyvZDY1 diff --git a/base/themes/default/holdit_selected.png b/base/themes/default/holdit_selected.png deleted file mode 100644 index 51586e748d67251f3c7e7bbe0b2485b8816bbd93..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1835 zcmV+`2h{k9P)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00009 za7bBm000ib000ib0l1NC?EnA(7<5HgbW?9;ba!ELWdLwtX>N2bZe?^JG%heMHD!e| zWdHyMeMv+?RA@uxnF&)Q-w^utSM{e1cIDQ9QfZe;r5Yoh z(AFU7bXbSXnRs23w3EFwA0Hn#`3;`er@g)1<@5Oq0m9+{VQb&_!^CZEZT?0_M@JU| z_QIaR7QgQYH@-+>DeQ^8g>5$ek(}jS_2lHFY3b4>r_2lEw{E$@`g-KXv{{x$Mk030 z?DOZY%gi}`=T2h3&R~Ck<%*v(sZXP~93-<9ht|?TUT~hW$Wb&R3aC+14$;6+4D| zYWvXDs}Y;>d3iaqALbtr@U+v@e_M`^|7i&loc*JxAud}Gres1Etv7+^e4B;L_4T<8 zWB)5=w-opG+*s(xf?s!ZRP<570FRvN>MGklEiAZMX*(2#h1vV}-9fSFZSUlIS=u&( zjj=k;k6m1JGqf4{1sk4ndY)Z0j@x+7n(pawpJO+{i*Rl2bKZi*?Qibhb^F22ec#@^ z>DxDQIoA`~0r94vJ}r-XCyCzfP;`@_bb^&k+@n!O;kJ|b32TU#a~79m)$Oq4=B^ER)*nXkl-pVyzP!O^Y9=O*xZj{3f2sZ>=48O@Kx>>vrQR0G;%&{{M zeHl+kDmMSo2ROxjXa@!bPDeX$95gANp5cuE&q~T!agqdMBlClU-cIsY!FC0n+~UxX zfBLlPSVF)q8au!7B7U!h-|7X3u{1hbu^tr+$Yac7AA*IviZ|lH{_qfZ*sL)=ZxSU> z%ala>nrA5prkhe&z}nQ5KgKzg)tP=pO4X*<_!K*Nfs zt0E-{rcYf@LnsR-iCuFOiJrc!#R^6U&h++{PDx=>AZKw+{piCp?86F1v90ZAp)SF| z$GhQ`xyFldbFRrjY#NUvOjHDHRxn;m^qPJz!*4t9s3cuBwlO#7Uty@-=wtJxR`dwQ z1Eio;@#sh4&G-p97!drEVC%B8^38%NbAsIj33yb>lWKx#=vcuhF0~&XOB>)3yvA@3 zY9_o~#{ix}xN`y{6cs${)IO|vN~EkH94I&R5K!0<`Net=Pu}(cyfW#;^Z7EH^&8(Z?Lf(bojQxP z`gH{xVj&cshRQw-7{mojs>2Y41;z#AY13|V6t$7<0~`cU(SH59zt>!Ue zxTff(ojxiUtVoTgbG*2G*=?__xx>T5vK?pxyv>F>Wr)^~_0W)DTdS)+(Q@OsU?fxW z4T8~!O%f)A1XXqXT~FbOTdLV?dp&3ksQj=~5)h1+TAmn!@lwmN?Q0|P3XXj|ZLqo7 z6*e~f!jz=>egp`n@2D^?G%OfzUoYzQFyJo>S|*UsRIrOq$-`3hc^FVN>wDt=NiekX9#)i> z*$v4z^`Ndjp2@g1UR@IUTqMxQdl>(eXbIm@(&?+E>+kqq{85tcTZ#Ga|8rYQHFS+B Z_a7oCTd~0}o5jgR z3=A9lx&I^rRWdUK_=LCu#a&%pi}Uh;j8QNe0wXO1_!rI(1Nxb>z$3Dlfr0NZ2s0kf zUy%Y7lq_+LC<)F_D=AMbN@XZW%*-p%%S$a$Fwry6Gczopr04A!!%K!iX diff --git a/base/themes/default/lobby_design.ini b/base/themes/default/lobby_design.ini deleted file mode 100644 index ef64114..0000000 --- a/base/themes/default/lobby_design.ini +++ /dev/null @@ -1,17 +0,0 @@ -lobby = 0, 0, 517, 666 -public_servers = 46, 88, 114, 30 -favorites = 164, 88, 114, 30 -refresh = 56, 381, 132, 28 -add_to_fav = 194, 381, 132, 28 -connect = 332, 381, 132, 28 -version = 170, 1, 300, 21 -about = 428, 1, 88, 21 -server_list = 20, 125, 286, 240 -player_count = 336, 91, 173, 16 -description = 337, 109, 173, 245 -chatbox = 2, 445, 515, 198 -chatname = 3, 646, 85, 19 -chatmessage = 93, 646, 424, 19 -loading_label = 135, 92, 254, 95 -progress_bar = 135, 188, 254, 21 -cancel = 220, 220, 80, 20 diff --git a/base/themes/default/lobbybackground.png b/base/themes/default/lobbybackground.png deleted file mode 100644 index 094f19c35e020c3267c076a51c370db94fd39cb7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29532 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 diff --git a/base/themes/default/mute.png b/base/themes/default/mute.png deleted file mode 100644 index a184cbf84fd871ae980ed57f83335575ebdaf0a1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5037 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 D6o<7R diff --git a/base/themes/default/mute_pressed.png b/base/themes/default/mute_pressed.png deleted file mode 100644 index e9793cec4edd24ff22f06d25034b327f57056a1c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4978 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 diff --git a/base/themes/default/notguilty.png b/base/themes/default/notguilty.png deleted file mode 100644 index b9cfe3184d261845d5c2249768273bb4b89d7bca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3269 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 Hu0mjfQvk@v diff --git a/base/themes/default/pair_button_pressed.png b/base/themes/default/pair_button_pressed.png deleted file mode 100644 index aaf53fb6df37b5f76d2bfbf84e70eac7215a2c28..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4619 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 BqkaGY diff --git a/base/themes/default/placeholder.gif b/base/themes/default/placeholder.gif deleted file mode 100644 index e35aaf4baf2672bd009a7e1d9d2415f164a86818..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9168 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 diff --git a/base/themes/default/present_disabled.png b/base/themes/default/present_disabled.png deleted file mode 100644 index 9c6a702d4bf2ac0b2322f05a37f7160680da811d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2905 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 DU8$*j diff --git a/base/themes/default/prominus.png b/base/themes/default/prominus.png deleted file mode 100644 index 1191e1ee157304addbb8e0d2d72d3454e0973c07..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 493 zcmVKLZ*U+R`sCEkzKl)gj5&q@hY_5?)@_euSf22N!q0z{yc?Q2YY_Kym8e z5Fvwu2%hQO!{u_psMvL#(bD64NQRTZj^-}DnS22ry9f-;mW=gZvQj}U-ZdMsK&I8^7~DvX`q=ivBBg3A5Jh8W1V jj}edm00000|NjF37T^g5&)L*a00000NkvXXu0mjf77E1@ diff --git a/base/themes/default/proplus.png b/base/themes/default/proplus.png deleted file mode 100644 index 5e9d563d2226207a649d6da878da1966fa1f5a85..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 498 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 diff --git a/base/themes/default/prosecutionbar1.png b/base/themes/default/prosecutionbar1.png deleted file mode 100644 index b44323c921ade3aecf3c8a356b7c173da0f301b6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 237 zcmeAS@N?(olHy`uVBq!ia0vp^AwbN>!2~4jWY(|)DaPU;cPEB*=VV?2IV|apzK#qG z8~eHcB(eheoCO|{#Xt?aK$uZdl!@TsywNZ vRE4|3AD->p9a;QLf1;T(0kp5~#5?BC(Gm$WZ%>E?8q476>gTe~DWM4f=JiB+ diff --git a/base/themes/default/prosecutionbar10.png b/base/themes/default/prosecutionbar10.png deleted file mode 100644 index f0a79c3ec082102246a27fda9bac3d13e8d6945f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 173 zcmeAS@N?(olHy`uVBq!ia0vp^AwbN>!3HEZ)>#JtDYhhUcNYdT21^EeuYau7KoQOY zkH})6s@)*Wc>Ko|GoT=QiKnkC`y(E11_MR0wwM;6kd>#4V@Sl|w>KOa85DS!H}aMS zw;T90c78hTd1C!r<6`fPRpE@h+XNU`xk4NonM4B?IIw>CJgvMhrTW%Uw#ZcXqRBv0 O7(8A5T-G@yGywpXa4;(X diff --git a/base/themes/default/prosecutionbar2.png b/base/themes/default/prosecutionbar2.png deleted file mode 100644 index 8bb51da5b4c0b769bdb2d8c41ce74af4d15b610b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 241 zcmeAS@N?(olHy`uVBq!ia0vp^AwbN>!2~4jWY(|)DaPU;cPEB*=VV?2IV|apzK#qG z8~eHcB(eheoCO|{#Xt?aK$uZnD9B(aaQHxT`3t5uflI>| z{|vjR!&p8q|9fQdv-u%6mIWow_G-=565X~E7iZr;=Q91s>AnlD9iR3FXf%VTtDnm{ Hr-UW|)1pnX diff --git a/base/themes/default/prosecutionbar3.png b/base/themes/default/prosecutionbar3.png deleted file mode 100644 index d0b9c4c225808e9fa9b5beb6dcea1e161a97dac1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 230 zcmeAS@N?(olHy`uVBq!ia0vp^AwbN>!2~4jWY(|)DVB6cUq=Rpjs4tz5?O(K&H|6f zVxXFxAk4UfO?*F4kiEpy*OmPd4>yC6_-n4!^MOJVC9V-A!TD(=<%vb93~dWL!?!VVcnfNBCgT^vI^yq{h(Rq*=zv4UXPOQt|&4cZ(maY!2~4jWY(|)DaPU;cPEB*=VV?2IV|apzK#qG z8~eHcB(eheoCO|{#Xt?aK$uZn$je|LaQHy`_ZM7iR_vqXnbHiFdp{}b=B|4ZF>;>KI+b3nrxJYD@<);T3K0RTpi BQ$_#) diff --git a/base/themes/default/prosecutionbar5.png b/base/themes/default/prosecutionbar5.png deleted file mode 100644 index 6bb5eb56553826ea79be32a9cf329b771a58bda7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 241 zcmeAS@N?(olHy`uVBq!ia0vp^AwbN>!2~4jWY(|)DaPU;cPEB*=VV?2IV|apzK#qG z8~eHcB(eheoCO|{#Xt?aK$uZnD9B*IbNIjk?p;jUtKKmw z@LsiL=%2Uy_gc%~uESE1GS^N#+TbSEZo0{0&BUXLy*hl^DTNWr-AGdF|4+Qj{<8kp V2HUet)j*>eJYD@<);T3K0RTL>OX~mt diff --git a/base/themes/default/prosecutionbar6.png b/base/themes/default/prosecutionbar6.png deleted file mode 100644 index 9ee9638f6be7ff48c6df805150c135ff9e2e121d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 241 zcmeAS@N?(olHy`uVBq!ia0vp^AwbN>!2~4jWY(|)DaPU;cPEB*=VV?2IV|apzK#qG z8~eHcB(eheoCO|{#Xt?aK$uZn$je|LaQHy`_ZM7iR_u~) zNL_jDZKQGe_vqqf9$c#hgCcq-9Lj1D2~%FOK}xapDu?D8H;+V9CnTwT|J=*u#ToSf UFZtQ*12me!)78&qol`;+08Twg)c^nh diff --git a/base/themes/default/prosecutionbar7.png b/base/themes/default/prosecutionbar7.png deleted file mode 100644 index 34e00da9068ea5ce46627d4ad03aaf014c037dfd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 242 zcmeAS@N?(olHy`uVBq!ia0vp^AwbN>!2~4jWY(|)DaPU;cPEB*=VV?2IV|apzK#qG z8~eHcB(eheoCO|{#Xt?aK$uZ{h;;P3(M_p7`U<3o3B zXsBBhne*mn*?iOVe=dBl3yUK9Cm*hwBXjNXlMQm}?O!b{*Bn2YXzPb0weO#EnZBEP Ws{Q_@`7J=R89ZJ6T-G@yGywpLKu;|I diff --git a/base/themes/default/prosecutionbar8.png b/base/themes/default/prosecutionbar8.png deleted file mode 100644 index 5035b51e9826634bc211f164ffc52ecc28d5a05a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 240 zcmeAS@N?(olHy`uVBq!ia0vp^AwbN>!2~4jWY(|)DaPU;cPEB*=VV?2IV|apzK#qG z8~eHcB(eheoCO|{#Xt?aK$uZ{h;;P3(M_p7`U<3o2W zm|-{T=&^bE-y@5ksr$@$VU)P&bW5k6u-YzMoPGbC%k&ppFI0cRvh@YfWCl-HKbLh* G2~7a2l}$!2~4jWY(|)DaPU;cPEB*=VV?2IV|apzK#qG z8~eHcB(eheoCO|{#Xt?aK$uZnD9B*IbNIjk?p;jUtKLbm wI9&ak!7y+4@3oe~>4~?J@uP>Y>r=inn(FVdQ&MBb@0DiekjQ{`u diff --git a/base/themes/default/publicservers.png b/base/themes/default/publicservers.png deleted file mode 100644 index 98cf2ad8e554fa9e0ee67929d56a1a9502945fbd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3999 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 diff --git a/base/themes/default/refresh_pressed.png b/base/themes/default/refresh_pressed.png deleted file mode 100644 index 803668381cc48f32b4317029d302a7a41690f562..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 919 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 diff --git a/base/themes/default/takethat_selected.png b/base/themes/default/takethat_selected.png deleted file mode 100644 index 3fe0a8cd13fa0244f7b9c87076b6f24cef43ba57..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1932 zcmV;72Xpv|P)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00009 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 DatZql diff --git a/base/themes/default/testimony.png b/base/themes/default/testimony.png deleted file mode 100644 index 7b81fc8edd4ef09a584d532a7dc6ffd2380a4134..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 579 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K54lpqT$!X1@Ux5@$x}&cn1H;CC?mvmFK)yn< zN02WALzNl>LqiJ#!!Mvv!wUw6QUeBtR|yOZRx=nF#0%!^3bX-A@C5jTxc>kDpW&D# zkX-tG>$bQ|d!RUDNswPKgTu2MX&_FLx4R2N2dk_Hki%Z$>Fdh=kcp2`NOZo%j@v+K zbx#+^kc@k8uNvkx8;Be$G%8?uZWFs{yU_WGHYN3Lrxz;ofa$6^7yyts4z3Ns%G(RkbM zQt6oAv^7BHyW{bn_WbN-Ieo`WOgHnj8?rbaV2d^{y*~3A-=YIHXX3pNeBCC>+V`aL6PbkT5%QsbL?x-eL`dC9J!?rSqQI)bRCt!`~?^ZQnC_LnfIn_`8dH zo!6aXUk-TwQ1vqmuu3bQG`DqSC*$?w2e!X4`K6i=m8fu!{kQ4@XC9lnz4icSH82?NY~EB@i?ssk)DI3s{^swJ)wB`Jv| zsaDBFsX&Us$iUEC*T6{E&?Lmb(8|!l%E(X~$S^R-UUYUjiiX_$l+3hB+#00*mr8?d N_jL7hS?83{1OVp+&RqZi diff --git a/base/themes/default/witnesstestimony.gif b/base/themes/default/witnesstestimony.gif deleted file mode 100644 index 03b4900c1e06eb38c598cfdab23d64e66d246bf3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 105223 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

    Attorney Online %1

    " "The courtroom drama simulator" @@ -360,20 +368,28 @@ void Lobby::on_about_clicked() "" "https://github.com/AttorneyOnline/AO2-Client" "

    Major development:
    " - "OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter" - "

    2.8 Major Release development:
    " + "OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, " "Crystalwarrior, Iamgoofball" - "

    2.8 Quality Assurance:
    " - "WillDean, Captain N, Mr M, Riel, Seimmet, Fury McFlurry," - "CedricDewitt, Chewable Tablets, Fantos, Futugaze," - "Geck, Minx, Pandae, Sierra, CrazyJC, CaseyMayCazy," + "

    QA testing:
    " + "WillDean, Captain N, Mr M, Riel, Seimmet, Fury McFlurry, " + "CedricDewitt, Chewable Tablets, Fantos, Futugaze, " + "Geck, Minx, Pandae, Sierra, CrazyJC, CaseyMayCazy, " "GreenBowers, Robotic Overlord, Veritas, Gin-Gi" "

    Special thanks:
    " - "Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), " + "Remy, Hibiki, Qubrick (webAO), Ruekasu (UI design), " "Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, " - "Noevain, Cronnicossy, the AO2 community, server hosts, game masters," - "case makers, content creators and players!") - .arg(ao_app->get_version_string()); + "Noevain, Cronnicossy, FanatSors (AO1), server hosts, game masters, " + "case makers, content creators, and the whole AO2 community!" + "

    The Attorney Online networked visual novel project " + "is copyright (c) 2016-2020 Attorney Online developers. Open-source " + "licenses apply. All other assets are the property of their " + "respective owners." + "

    Running on Qt version %2 with the %3 audio engine." + "

    Built on %4") + .arg(ao_app->get_version_string()) + .arg(QLatin1String(QT_VERSION_STR)) + .arg(audio) + .arg(QLatin1String(__DATE__)); QMessageBox::about(this, tr("About"), msg); } From 3e27548d3914fc01a72651e8398756843b98ff6d Mon Sep 17 00:00:00 2001 From: Pyraq Date: Tue, 9 Jun 2020 12:44:25 +0200 Subject: [PATCH 209/268] Yet another update to the Polish translation. --- resource/translations/ao_pl.qm | Bin 27653 -> 46479 bytes resource/translations/ao_pl.ts | 224 +++++++++++++++++---------------- 2 files changed, 118 insertions(+), 106 deletions(-) diff --git a/resource/translations/ao_pl.qm b/resource/translations/ao_pl.qm index 995a5bc91f08641cd446ecac2e65ce5231e56855..99f3c75d64e5964d7c255d07cf0f82c778beb3b9 100644 GIT binary patch literal 46479 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 delta 2953 zcmZ8h2~IK;jbI!lDQwAd4t2&A>dECy#k#7AK&AU}EEv zYU;1Xg}Bg|oN$t=d8SokTxyQTSfe#YvuI3DOp`XI(MFq^4SV0vLrBh?nLF?Oclqx3 z-TSYzI7d6?^7p*QU2q5|2H+`;CwC0K-I}USe}`e_I3WL#J}Z{N&@zkSQ(#zj7;t zJjds$!$Q4%y~LJK#{~fGHxB&e{#>PAz<}I-1DWmz=Cbusk*O#I6e1n z3EAPZxi8O9;%S5V2)3A*yUeFNL7hgA=SLs<0vLaYpLY5QYQ)7mZj7{ z!7q;^WYO*X>Jyzr^Y{GW{q2D1Km4gnXUO3+|JlWEVqz74^I9oxZ zKw6q1adRzMmtkVhpGlf4hLW9>&tWyp-Ma~BXfQZ+1wi;BgZs%#G*>}GTcsD^#~HS- z+5&XU*lg(PqQDtv41YLD2`9c}csnziW+G_#A-j<@{W5HhLIoFI51XfTGU{%aRNPBc z-wAu-Ds?dVv9K4f(Rpcn*rz$fMB#6Z$&-?R>TKh}D>ST=IoJG=$5I z7o#X{+G7fol;{o9ii=dh+HG1JPX*_vnzokr0)u!{&-G8KQ`L0vg<|r%W!9Gs0*pOo zL-jS9g~*n-flj1?;P;Z0HNKmQAl9Cbw9+ z%rsjIVl6Li+XYmqmP525nB=#-SJ^?7r`K4nxKB{R49oRTq6qnQ%iS1a!uqXsw5uH` zUvBNWz!SB{t!EdFrb6#o-?`uO>v{uzyBi{Rgo`+3{_-y?W zqJB!mj}gO2n(4M7$-O|v6kA#i4G+*~>%O)XtjM9^>$0_fKpkfl+MfE{MgCvg_K%_G z2Upl$UHKJ|`h)Gj(;RKpEZec?=zVdu?dnHlg@4%=-aAHG@H^~0p8}LP?1OR^(}nVh zJ!ADc(sYHrP}~3HJ$6q%T`+|U>|4$bCx*t@)mM5*x}EmFOt=R8s>S|}y%ZQT%6?Ir z3XDBXdNw@IKG-*04KrObb<9OA6!_qWlgoq1Er5U^TG0p(ob+v_=QjH0q6`jLxMlRF zp5C;gIds+xNsA+Yg}hu8AyJ&eq;U~OU&nkUAh?}NMWIdBbD?5tvq19-CrzJDbFe8M4#IQpP8!n_}C!FfIw@P*_*Oq&R`H3aHb(sRn`O z;;1cx&MqgMPY&eDvJ&(OzIrc#_E9Ry(xbt? z4uIN(+XymcRH^jdjn#c;CG8cqqA8Qf|4u?KEKi; zGzWZAy%2Ph8a}02R6L@f)GZO~{k}9IMwXgHLGpy+ob~>IQx1i*EJwULKRZFkPEPn% zeL3fZQI+%W)1^dmwF3o0PQOH^K8e_FAwm6XaVlr64Rs`P%OSGIx-+aA+al_;U$*P{ zWX{2Ebmy{PmmE>8<#RZ;pdwuujMAT+XhxeL_2<{;$pOZdMya1x%G~`?s3Cen$%u|N znpFDq`A;LbE#D{-%leglT#CO z$VFL6D53wflQcxyHnxSrJ)!DN1FD)!ltw|8nkCk`K8pRr)5vr!3)tnB4@bsoD?%BZ z+E{S~p+0`zZCIJtNdd$?yX5sGgrfqtN!6b_>B}Wg69J57?tm=VP!-y*wqJM|E1Z(2 zP6>t_-&~q8G!prQS)|&*U$m^N5ZS-IQS4l>fL&kq0Q=+e3?@8Tr&h0=$EiQA>gHJ5 zYLl$7Tu+^ARwV1CEZS6PYo)D?_O2!L)`vENL{~tlQ;jKQz{Cu%a!WqJrHDRl7~Hh| zX+mAVudRhw6k6#@YgAb0!%^zOXFlQMEXbo8+Wk2|q8hj4*GNjx?#$bC<{xkxHeb|k z7)?QS^(H=?o6DZwots=rU<6c>bATA_8|R*?e|`u*R5eU_l)3jSo8~(+;UZV;YChu?`h=v1GtmwYcI!fjNjX%p4)eo QXW<7Pr1?u^cMfd-AC9sPMF0Q* diff --git a/resource/translations/ao_pl.ts b/resource/translations/ao_pl.ts index 009a1f7..9bcb496 100644 --- a/resource/translations/ao_pl.ts +++ b/resource/translations/ao_pl.ts @@ -236,77 +236,77 @@ Powód: %1 - Keep current setting - + - Zostaw obecne ustawienia Allow Screenshake: - + Zezwalaj Wstrząśnięcia: Allows screenshaking. Disable this if you have concerns or issues with photosensitivity and/or seizures. - + Zezwala na wstrząśnięcia ekranu. Wyłącz to, jeśli przejmujesz się lub masz problemy z światłoczułością oraz/lub napady padaczkowe. Allow Effects: - + Zezwalaj Efekty: Allows screen effects. Disable this if you have concerns or issues with photosensitivity and/or seizures. - + Zezwala na efekty ekranu. Wyłącz to, jeśli przejmujesz się lub masz problemy z światłoczułością oraz/lub napady padaczkowe. Network Frame Effects: - + Efekty Network Frame: Send screen-shaking, flashes and sounds as defined in the char.ini over the network. Only works for servers that support this functionality. - + Wysyła wstrząśnięcia ekranu, błyśnięcia i dźwięki, jak zdefiniowano w pliku char.ini, przez sieć. Działa tylko w przypadku serwerów, które obsługują tę funkcję. Colors in IC Log: - + Kolory w dzienniku IC: Use the markup colors in the server IC chatlog. - + Użyj znaczników kolorów w serwerowym dzienniku IC. Sticky Sounds: - + Lepkie Dźwięki: Turn this on to prevent the sound dropdown from clearing the sound after playing it. - + Włącz to, aby zapobiec listy dźwięków przed odznaczeniem zaznaczonego dźwięku po odtworzeniu. Sticky Effects: - + Lepkie Efekty: Turn this on to prevent the effects dropdown from clearing the effect after playing it. - + Włącz to, aby zapobiec listy efektów przed odznaczeniem zaznaczonego efektu po odtworzeniu. Sticky Preanims: - + Lepkie Przed-animacje: Turn this on to prevent preanimation checkbox from clearing after playing the emote. - + Włącz to, aby zapobiec przycisku wyboru przed-animacji od odznaczenia się po odegraniu emotki. @@ -376,7 +376,7 @@ Powód: %1 Play a blip sound "once per every X symbols", where X is the blip rate. - + Zagraj dźwięk blipa "raz na X symboli", gdzie X to tempo blipów. @@ -407,7 +407,7 @@ Powód: %1 If true, AO2 will stop the music for you when you or someone else does 'Objection!'. - + Jeśli zaznaczone, gra przerwie muzykę, kiedy ktoś sprzeciwi się (Objection!). If true, the game will stop music when someone objects, like in the actual games. @@ -594,7 +594,8 @@ Powód: %1 Additive - + I'm not sure about this one. + Dodatek @@ -671,34 +672,34 @@ Rozprawy które możesz załadować: %1 None - + Nic Hold It! - + (Hold It)! Zaczekaj! When this is turned on, your next in-character message will be a shout! - + Kiedy to jest włączone, twoja następna wiadomość IC będzie krzykiem! Objection! - + (Objection!) Sprzeciw! Take That! - + (Take That!) Weź To! Toggle between server chat and global AO2 chat. - + Przełączaj pomiędzy czatem serwerowym i globalnym czatem AO2. @@ -706,122 +707,125 @@ Rozprawy które możesz załadować: %1 This will display the animation in the viewport as soon as it is pressed. - + To będzie wyświetlać animację w oknie tak szybko jak jest to wciśnięte. Guilty! - + Winny! Bring up the Character Select Screen and change your character. - + Wyświetl ekran zmiany postaci i zmień swoją postać. Refresh the theme and update all of the ui elements to match. - + Odśwież motyw i uaktualnij wszystkie elementy UI, aby dopasować. Request the attention of the current server's moderator. - + Poproś uwagę moderatora obecnego serwera. Allows you to change various aspects of the client. - + Umożliwia zmianę różnych aspektów klienta. An interface to help you announce a case (you have to be a CM first to be able to announce cases) - + Interfejs, który pomoże ci ogłosić rozprawę (musisz być zarządcą rozpraw (CM), aby móc ogłaszać rozprawy) Switch between Areas and Music lists - + Przełącz pomiędzy listami Obszarów i Muzyki Play a single-shot animation as defined by the emote when checked. - + Odegraj pojedyńczą animację, jak zdefiniowano przez emotkę, gdy zaznaczone. If preanim is checked, display the input text immediately as the animation plays concurrently. - + Jeśli przed-animacja jest zaznaczona, wyświetl wpisany tekst natychmiastowo, jednocześnie podczas odgrywania animacji. Mirror your character's emotes when checked. - + Odzwierciedlij emotki twojej postaci, gdy zaznaczone. Add text to your last spoken message when checked. - + Dodaj tekst do twojej ostatniej wiadomości, gdy zaznaczone. Do not listen to mod calls when checked, preventing them from playing sounds or focusing attention on the window. - + Nie słuchaj wezwań moda, gdy zaznaczone, zapobiegając grania dźwięków oraz skupiania uwagi na okienko. Lets you receive case alerts when enabled. (You can set your preferences in the Settings!) - + Pozwala ci otrzymywać komunikaty rozpraw, gdy włączone. +(Możesz ustawić swoje preferencje w Ustawieniach!) Display customized shownames for all users when checked. - + Wyświetl niestandardowe ksywki dla wszystkich użytkowników, gdy zaznaczone. Custom Shout! - + Niestandardowy Krzyk (sprzeciw)! This will display the custom character-defined animation in the viewport as soon as it is pressed. To make one, your character's folder must contain custom.[webp/apng/gif/png] and custom.[wav/ogg/opus] sound effect - + To będzie wyświetlać zdefiniowanej animacji niestandardowej postaci w oknie tak szybko, jak jest to wciśnięte. +Aby zrobić coś takiego, folder twojej postaci musi zawierać niestandardowe [webp/apng/gif/png] i niestandardowe [wav/ogg/opus] efekty dźwiękowe Play realization sound and animation in the viewport on the next spoken message when checked. - + Zagraj dźwięk realizacji i animację w oknie podczas następnej wiadomości, gdy zaznaczone. Shake the screen on next spoken message when checked. - + Wstrząśnij ekranem podczas następnej wiadomości, gdy zaznaczone. Display the list of character folders you wish to mute. - + Wyświetl listę folderów postaci, których chcesz zmutować. Increase the health bar. - + Zwiększ pasek życia. Decrease the health bar. - + Obniż pasek życia. Change the text color of the spoken message. You can also select a part of your currently typed message and use the dropdown to change its color! - + Zmień kolor tekstu dla twojej wiadomości. +Możesz również zaznaczyć część twojej obecnie pisanej wiadomości i użyć list aby zmienić jej kolor! @@ -833,12 +837,12 @@ You can also select a part of your currently typed message and use the dropdown has played a song - + włączył piosenkę You will now pair up with %1 if they also choose your character in return. - + Będzie teraz w parze z %1, jeśli oni również wybiorą twoją postać. Rainbow @@ -864,72 +868,76 @@ You can also select a part of your currently typed message and use the dropdown To front - + Do przodu To behind - + Do tyłu Select a character you wish to pair with. - + Zaznacz postać, z którą chcesz się sparować. Change the percentage offset of your character's position from the center of the screen. - + Zmień procentową odległość dla pozycji twojej postaci licząc od środka ekranu. Change the order of appearance for your character. - + Zmień kolejność występowania dla twojej postaci. Display the list of characters to pair with. - + Wyświetl listę postaci to sparowania się. Oops, you're muted! - + Ups, jesteś zmutowany! Set your character's emote to play on your next message. - + Ustaw emotki twojej postaci do odegrania podczas następnej wiadomości. Set your character's supplementary background. - + Ustaw uzupełniające tło twojej postaci. Set an 'iniswap', or an alternative character folder to refer to from your current character. Edit by typing and pressing Enter, [X] to remove. This saves to your base/characters/<charname>/iniswaps.ini - + Ustaw 'iniswap' albo alternatywny folder postaci, aby odnosił się do twojej obecnej postaci. +Edytuj poprzez pisanie i naciśnięcie enter, [X] aby usunąć. To się zapisuje do base/characters/<charname>/iniswaps.ini Remove the currently selected iniswap from the list and return to the original character folder. - + Usuń obecne zaznaczony iniswap z listy i powróć do pierwotnego foldera postaci. Set a sound effect to play on your next 'Preanim'. Leaving it on Default will use the emote-defined sound (if any). Edit by typing and pressing Enter, [X] to remove. This saves to your base/characters/<charname>/soundlist.ini - + Ustaw efekt dźwiękowy do zagrania dla twojej następnej 'przed-animacji' Zostawienie to jako domyślne, użyje dźwięku zdefiniowanego przez emotkę (jeśli istnieje). +Edytuj poprzez pisanie i naciśnięcie enter, [X] aby usunąć. To się zapisuje do base/characters/<charname>/soundlist.ini Choose an effect to play on your next spoken message. The effects are defined in your theme/effects/effects.ini. Your character can define custom effects by char.ini [Options] category, effects = 'miscname' where it referes to misc/<miscname>/effects.ini to read the effects. - + Wybierz efekt dla twojej następnej wiadomości. +Efekty są zdefiniowane w twoim pliku theme/effect/effects.ini. Twoja postać może zdefiniować niestandardowe efekty przez +kategorię char.ini [Options], effects = 'miscname' gdzie się odnosi do misc/<miscname>/effects.ini, aby przejrzeć efekty. @@ -985,23 +993,23 @@ char.ini [Options] category, effects = 'miscname' where it referes to Return back to the server list. - + Wróć spowrotem do listy serwerów. Become a spectator. You won't be able to interact with the in-character screen. - + Zostań spektatorem. Nie będziesz mógł wchodzić w interakcję z ekranem IC. You were granted the Disable Modcalls button. - + Zostałeś obdarzonym przyciskiem Wyłącz Wezwania Moda. CLIENT - + KLIENT @@ -1096,7 +1104,7 @@ char.ini [Options] category, effects = 'miscname' where it referes to UNKNOWN - + NIEZNANE @@ -1126,32 +1134,32 @@ char.ini [Options] category, effects = 'miscname' where it referes to Expand All Categories - + Rozwiń Wszystkie Kategorie Collapse All Categories - + Zwiń Wszystkie Kategorie Fade Out Previous - + Zanikaj poprzednie Fade In - + Rozjaśnij Synchronize - + Zsynchronizuj Default - + Domyślne @@ -1186,80 +1194,81 @@ char.ini [Options] category, effects = 'miscname' where it referes to Present this piece of evidence to everyone on your next spoken message - + Zaprezentuj ten dowód dla każdego podczas twojej następnej wiadomości Save evidence to an .ini file. - + Zapisz dowody do pliku .ini. Load evidence from an .ini file. - + Załaduj dowody z pliku .ini. Destroy this piece of evidence - + Zniszcz ten dowód Choose.. - + Wybierz.. Close the evidence display/editing overlay. You will be prompted if there's any unsaved changes. - + Zamknij wyświetlanie/edytowanie okienka dowodów. +Zostaniesz poproszony, jeśli są jakieś niezapisane zmiany. Save any changes made to this piece of evidence and send them to server. - + Zapisz zmiany do tego dowodu i wyślij je do serwera. Double-click to edit. Press [X] to update your changes. - + Kliknij dwa razy, aby edytować. Naciśnij [X], by uaktualnić zmiany. Bring up the Evidence screen. - + Wyświetl ekran dowodów. Switch evidence to private inventory. - + Przełącz dowody do prywatnego ekwipunku. Switch evidence to global inventory. - + Przełącz dowody do globalnego ekwipunku. Transfer evidence to private inventory. - + Przenieś dowody do prywatnego ekwipunku. Transfer evidence to global inventory. - + Przenieś dowody do globalnego ekwipunku. The piece of evidence you've been editing has changed. - + Ten dowód, który edytujesz, zmienił się. Do you wish to keep your changes? - + Czy chcesz zatrzymać zmiany? @@ -1267,19 +1276,22 @@ You will be prompted if there's any unsaved changes. Image: %2 Description: %3 - + Nazwa: %1 +Obraz: %2 +Opis: +%3 Images (*.png) - Plik obrazu (*.png) + Pliki obrazu (*.png) Double-click to edit... - + Kliknij dwa razy, aby edytować... @@ -1289,43 +1301,43 @@ Description: Evidence has been modified. - + Dowody zostały zmodyfikowane. Do you want to save your changes? - + Czy chcesz zapisać zmiany? Current evidence is global. Click to switch to private. - + Obecne dowody są globalne. Kliknij, aby przełączyć na prywatne. Current evidence is private. Click to switch to global. - + Obecne dowody są prywatne. Kliknij, aby przełączyć na globalne. "%1" has been transferred. - + "%1" został przeniesiony. Save Inventory - + Zapisz ekwipunek Ini Files (*.ini) - + Pliki ini (*.ini) Open Inventory - + Otwórz ekwipunek @@ -1338,7 +1350,7 @@ Description: Search - Wyszukaj + Szukaj @@ -1360,12 +1372,12 @@ Czy pobrałeś wszystkie zasoby poprawnie z tiny.cc/getao, włączając duży fo Settings - Ustawienia + Ustawienia Allows you to change various aspects of the client. - + Umożliwia zmianę różnych aspektów klienta. @@ -1380,12 +1392,12 @@ Czy pobrałeś wszystkie zasoby poprawnie z tiny.cc/getao, włączając duży fo <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>2.8 Major Release development:</b><br>Crystalwarrior, Iamgoofball<p><b>2.8 Quality Assurance:</b><br>WillDean, Captain N, Mr M, Riel, Seimmet, Fury McFlurry,CedricDewitt, Chewable Tablets, Fantos, Futugaze,Geck, Minx, Pandae, Sierra, CrazyJC, CaseyMayCazy,GreenBowers, Robotic Overlord, Veritas, Gin-Gi<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, the AO2 community, server hosts, game masters,case makers, content creators and players! - + <h2>Attorney Online %1</h2>Symulator dramy sądowej<p><b>Kod źródłowy:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Główny rozwój:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>Główny rozwój nad wydaniem 2.8:</b><br>Crystalwarrior, Iamgoofball<p><b>Zapewnienie jakości 2.8:</b><br>WillDean, Captain N, Mr M, Riel, Seimmet, Fury McFlurry,CedricDewitt, Chewable Tablets, Fantos, Futugaze,Geck, Minx, Pandae, Sierra, CrazyJC, CaseyMayCazy,GreenBowers, Robotic Overlord, Veritas, Gin-Gi<p><b>Szczególne podziękowania:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, społeczności AO2, hostów serwerów, mistrzów gier, twórców rozpraw, twórców kontentu i dla graczy! About - + Opis <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy @@ -1410,12 +1422,12 @@ Czy pobrałeś wszystkie zasoby poprawnie z tiny.cc/getao, włączając duży fo UNKNOWN - + NIEZNANE has played a song: - + włączył piosenkę: From f13635b5cdc238af5464b4aa916999b4e1f017b8 Mon Sep 17 00:00:00 2001 From: oldmud0 Date: Tue, 9 Jun 2020 13:44:50 -0500 Subject: [PATCH 210/268] Update credits again - Alphabetized QA section - Added MaximumVolty - Added court-records.net - Renamed Unishred to Lewdton --- src/lobby.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/lobby.cpp b/src/lobby.cpp index cc9c44d..2aeb47d 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -371,15 +371,18 @@ void Lobby::on_about_clicked() "OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, " "Crystalwarrior, Iamgoofball" "

    QA testing:
    " - "WillDean, Captain N, Mr M, Riel, Seimmet, Fury McFlurry, " - "CedricDewitt, Chewable Tablets, Fantos, Futugaze, " - "Geck, Minx, Pandae, Sierra, CrazyJC, CaseyMayCazy, " - "GreenBowers, Robotic Overlord, Veritas, Gin-Gi" + "CaseyCazy, CedricDewitt, Chewable Tablets, CrazyJC, Fantos, " + "Fury McFlurry, Geck, Gin-Gi, Jamania, Minx, Pandae, " + "Robotic Overlord, Shadowlions (aka Shali), Sierra, SomeGuy, " + "Veritas, Wiso" "

    Special thanks:
    " - "Remy, Hibiki, Qubrick (webAO), Ruekasu (UI design), " - "Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, " - "Noevain, Cronnicossy, FanatSors (AO1), server hosts, game masters, " - "case makers, content creators, and the whole AO2 community!" + "CrazyJC and MaximumVolty (2.8 release); " + "Remy, Hibiki, court-records.net (sprites); Qubrick (webAO); " + "Rue (website); Draxirch (UI design); " + "Lewdton and Argoneus (tsuserver); " + "Fiercy, Noevain, Cronnicossy, and FanatSors (AO1); " + "server hosts, game masters, case makers, content creators, " + "and the whole AO2 community!" "

    The Attorney Online networked visual novel project " "is copyright (c) 2016-2020 Attorney Online developers. Open-source " "licenses apply. All other assets are the property of their " From 35b9c834e2cbc49b1f479797fed8a9775e5c3e0f Mon Sep 17 00:00:00 2001 From: oldmud0 Date: Tue, 9 Jun 2020 16:42:52 -0500 Subject: [PATCH 211/268] Lobby: Fix incorrect sorted server list --- src/lobby.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lobby.cpp b/src/lobby.cpp index 2aeb47d..613bee5 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -497,7 +497,7 @@ void Lobby::list_servers() int i = 0; for (server_type i_server : ao_app->get_server_list()) { QTreeWidgetItem *treeItem = new QTreeWidgetItem(ui_server_list); - treeItem->setText(0, QString::number(i)); + treeItem->setData(0, Qt::DisplayRole, i); treeItem->setText(1, i_server.name); i++; } @@ -513,7 +513,7 @@ void Lobby::list_favorites() int i = 0; for (server_type i_server : ao_app->get_favorite_list()) { QTreeWidgetItem *treeItem = new QTreeWidgetItem(ui_server_list); - treeItem->setText(0, QString::number(i)); + treeItem->setData(0, Qt::DisplayRole, i); treeItem->setText(1, i_server.name); // treeItem->setText(2, "-"); i++; From 4bc23c889f22d8babe073a1e13693623f74261e3 Mon Sep 17 00:00:00 2001 From: oldmud0 Date: Wed, 10 Jun 2020 16:00:29 -0500 Subject: [PATCH 212/268] Bump .pro version to 2.8.4 I won't roll the minor version back to 2.8.0 - that'll just cause headaches. --- Attorney_Online.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Attorney_Online.pro b/Attorney_Online.pro index d49676e..28a1e7c 100644 --- a/Attorney_Online.pro +++ b/Attorney_Online.pro @@ -3,7 +3,7 @@ QT += core gui widgets network TARGET = Attorney_Online TEMPLATE = app -VERSION = 2.8.3.1 +VERSION = 2.8.4.0 INCLUDEPATH += $$PWD/include DESTDIR = $$PWD/bin From 0bdcf03793d6f1304d02e008f4cfdaecd5e9119f Mon Sep 17 00:00:00 2001 From: oldmud0 Date: Wed, 10 Jun 2020 21:42:42 -0500 Subject: [PATCH 213/268] Remove extraneous files; update themes submodule - A preconfigured config.ini is probably not useful these days. There's an options menu now. - Removed gs4 background - already in vanilla pack. - Themes submodule should probably be configured to track master. Meh. Submodules can be so finicky. It probably doesn't belong in this repo anyway - it should be in the vanilla repo (currently invisible). --- .gitlab-ci.yml | 1 - base/background/gs4/defensedesk.png | Bin 6880 -> 0 bytes base/background/gs4/prosecutiondesk.png | Bin 6551 -> 0 bytes base/background/gs4/stand.png | Bin 2657 -> 0 bytes base/config.ini | 10 ---------- base/themes | 2 +- 6 files changed, 1 insertion(+), 12 deletions(-) delete mode 100644 base/background/gs4/defensedesk.png delete mode 100644 base/background/gs4/prosecutiondesk.png delete mode 100644 base/background/gs4/stand.png delete mode 100644 base/config.ini diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e9685de..4c7f079 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -123,7 +123,6 @@ build windows i686: mkdir base mkdir base/themes cp -a ../base/themes/default base/themes/ - cp -a ../base/config.ini base/config.sample.ini cp -a ../base/serverlist.txt base/serverlist.sample.txt # Miscellaneous files diff --git a/base/background/gs4/defensedesk.png b/base/background/gs4/defensedesk.png deleted file mode 100644 index 00a3ffb68aaac2626c95f48464645ca3c2f9dcc0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6880 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 YlC$-zU7KHS0)fY&B&RM5mo^Rh4_0lj0ssI2 diff --git a/base/background/gs4/prosecutiondesk.png b/base/background/gs4/prosecutiondesk.png deleted file mode 100644 index 9f62673352f3312636da79f412a48cca0e562797..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6551 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 E0MKCZJ^%m! diff --git a/base/background/gs4/stand.png b/base/background/gs4/stand.png deleted file mode 100644 index 3719e36a0d88750aaf70a40a6df1bd4e7a6ba805..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2657 zcmd6p{X5f(8^=HU7#bm*m7@m^^AM+0&Z#I(rPel2r?Qn{D;1H4PJJ`ebkk#86Wuk-LNi9|H}_E@DHjsIyclMJaQJ|lmSZ)?hh8kZGX<;eYyVS+5~ zo#ZS%Xba*~doLcWinB*}UFF__2ey;(V41`m3zp3=*aFoC`8pb87NBTGx#*tW+&pj2 zOjZU8@8Ph;@2V?+60GM?M3>5iKAIvCXLk(Ufb)6 zK6i+D3bgA;zMp#Txr$mJVVBEC`O6@x6|%|jYBHL~;b_s)R=B^Ra_?1o$V3FR>!^_P zN`uK;q+42cZMZMkc4{nX6hiwMSBbmLJq6Jj>DGVhZ_xi5P8xAF(Y$DmD)nwXofdQX zABBgWwgR<=Y0+}JBsMM~;Etb@E~H^9L-`w5FOqB#r2|cCKeX0SFQ>U!89%H5Y#Nqp z{9%7#!6xU#5GBUJz;^lX_v2aV{sx*mXSQuxD05Cq{O6qg+$QREg}3e+ACUe4IM=VY zw*vfK==2x!ryu9Kt8!O|>@=O+qZt{u;<{NkS#K)*^rQql;ig{B^oKy#O0&5h3?JT-AVX#6 zt2x)xv>}%O25Q^m`f4Thz3g!%X(Hi}Q~8mMCZ`2OFzj89=RSuiGlbX_=~-!Z;t@RI zOxr0`!Qn4Nbjc|9Gqa3K-;HU&XA+MCes_Rgag1GR-X*}+VRP%vh8+}EQEQy?6;%-i zw=tQTt?soYDhATcCd{1|iRX=rk!rtuIIckx=9E&!*d2&Zr*#8eLOTm1X-MpRnz}1T zQW!60yEyGHgr>!B&Pka607!hA$`{A@^n2}j^D55p27 zD|-Ib74Ep(2CBBh+syIVvtxECgh!TCA*8$(6gl{*H1zx+>-t@`SjVqw`KJ9aAJt>1 zVakP;@n>*@BKx(SUS@ucJ5DmDIN}bn0-U?ttvhQhKn}G1Yf1{}=t3r-EDnRQs8wM( zylY}BEXZm{Kk1z%l>f*IRXQ)8D&?Y=b@n%e$_9G3<-iGg+VC~i#u};8wh($27dC%o z_CygDBu!<#lWA1%@F_GC-9rwHbH;Jy2ia>cc(I#otiPD1lpn!{49+9RX((7QBcTLq z&CS^5+PS?Kimdx~U26;06(BT(&NsQ9QE6jw?K+mKWHv}So4NaWj*4bJ^Yg0C);V?5 zPG`0#5x$o@Q+t|=aZXjM|7CmhnXt@zU5>$Spi-Irds50W4)Il)$o(e_I(}NPA+q?D zP+;`<;2UyLq0k(iHa+!v0T=x86&*O{aJTg2I89wH{&@t zYo%}}EdYE$bi5sM^U5JmDqp%LW9=%vP^e`jU*0)I{(G{>2V`v#Y)|Cei*RL&E`g4^ zWM^3ES=IcX0Q0mHP`rjhdjf$ka(U9lukYhwI0R)bIE6Xx-Ye$Dg9Q_q zZ{8@H_{hrl0XVND*+jb(=|NXjH`&8A*x_yPxWF^|H zl6>{!3(H)Ue1U$Ua|v;z>70MM~@uieo_!(@af zm_u^9KQI}^l_^X>xoD6BebE*=q~%4z4qNHBIl(TN z@h;h=44CKZee}4?-{+2>IL{Lt++9h4-DcC^T7DL)HqkM==Ch+m-U-2%71^}miwmRM z-4TwkmaA}or>C~$san}Zaj)&8rm(Nw(NB=-PL6VuXo}YI8aithKCGorY6n6$sSYq* zpPC@VAK}}k7i(QZr(SScx(MLJjB)F_Umpg2cicb|dguJqee(PjRH`K2Ef=169ZGaT zxi$Fio4#G%8~O5ZF7HKT8!Dy!D$_-OA1%XIXS;SsPi2nh#0aZp=Dw&TH@WT^(=C-G zG4eb=1!)?W`*16`IAK=M=qgIC!<^Ulb+}H)z8w&|cw|t=3ISDIb<%UmM74%G{?f0@ z+w6fZv>Emg2bM)hR&_`s8?&s3&?I6z1J#o_^k^hL`S}(?s_WSE&_>~q=Z`pE9x`X^=gF<!YfKe0Nj?zaB7=MH Date: Fri, 12 Jun 2020 16:45:50 -0500 Subject: [PATCH 214/268] Fix connect button not enabling Apparently this had never been staged, and while everyone was having problems with the connect button, everything was working just fine for me. This enables the connect button a bit earlier in the handshake process than in 2.6, since there are some older servers out there that don't send FL (and so the connect button would never get enabled). This might lead to race conditions, and sometimes the progress bar does hang, but you can just cancel and reconnect - I haven't encountered a crash so far. --- src/packet_distribution.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/packet_distribution.cpp b/src/packet_distribution.cpp index 44e2816..670dab4 100644 --- a/src/packet_distribution.cpp +++ b/src/packet_distribution.cpp @@ -157,6 +157,9 @@ void AOApplication::server_packet_received(AOPacket *p_packet) s_pv = f_contents.at(0).toInt(); server_software = f_contents.at(1); + if (lobby_constructed) + w_lobby->enable_connect_button(); + send_server_packet(new AOPacket("ID#AO2#" + get_version_string() + "#%")); } else if (header == "CT") { From 45baa626bc23000de15bec6aa2b3c1192efc5dbe Mon Sep 17 00:00:00 2001 From: in1tiate <32779090+in1tiate@users.noreply.github.com> Date: Sat, 20 Jun 2020 10:22:10 -0500 Subject: [PATCH 215/268] set tooltips of char buttons to char names --- src/charselect.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/charselect.cpp b/src/charselect.cpp index de9748b..d003b34 100644 --- a/src/charselect.cpp +++ b/src/charselect.cpp @@ -209,6 +209,7 @@ void Courtroom::character_loading_finished() char_button->reset(); char_button->hide(); char_button->set_image(char_list.at(n).name); + char_button->setToolTip(char_list.at(n).name); ui_char_button_list.append(char_button); connect(char_button, &AOCharButton::clicked, From 12023c4d5c5c57ae4e06a75d1a94f7b03a88fc28 Mon Sep 17 00:00:00 2001 From: oldmud0 Date: Sun, 28 Jun 2020 19:53:42 -0500 Subject: [PATCH 216/268] Update readme (#172) * Readme: link to docs repository * Move compile and release instructions to new file * Remove compile and release instructions from readme --- CONTRIBUTING.md | 44 ++++++++++++++++++++++++++++++++++++++++++++ README.md | 47 +---------------------------------------------- 2 files changed, 45 insertions(+), 46 deletions(-) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..72cfa8f --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,44 @@ +## Compiling + +The traditional route is by undergoing the [AO2 Rite of Passage](https://gist.github.com/oldmud0/6c645bd1667370c3e92686f7d0642c38). + +However, these days it is easy to get away with using the default Qt toolchain on any platform, which creates a dynamic executable. (Don't forget to invoke windeployqt when creating a release.) + +### Dependencies + +- [BASS](http://un4seen.com) (optional; may use Qt Multimedia instead) +- [Discord Rich Presence](https://github.com/discordapp/discord-rpc) (optional) + +## Release instructions + +Follow these steps to make a new full release: + +- Set a new AO version in the `.pro` file and in `aoapplication.h`. +- Compile the project. +- Commit the version bump and and create a tag for the commit. +- Rename the executable to `Attorney_Online`. +- Create a temp directory. +- Copy a fresh `base` folder to the temp dir. Ensure that the timestamps are consistent. + - Ignore this step if creating a client-only release. +- Copy the repository's `base` folder to the temp dir. +- Append `.sample` to the names of all `.ini` files, including `serverlist.txt`. +- Copy the game executable to the temp dir. +- Copy `bass.dll`, `discord-rpc.dll`, and `qapng.dll` if applicable. +- Copy `README.md` as `README.md.txt` with CRLF line endings. +- Copy `LICENSE` as `LICENSE.txt` with CRLF line endings. +- Compress the contents of the temp dir to an archive with maximum compression, but + be sure that the contents are placed inside the root directory of the archive and not + within a subdirectory. +- Compute the SHA-1 hash of the archive. +- Upload the archive to the Wasabi bucket and an additional mirror (e.g. MEGA or OneDrive) + (if this is a full release). +- Publish a GitHub release and upload the archive there (if this is a client-only release). +- Add the new version to the `program.json` manifest for the respective platform + (if this is a client-only release). +- Update the following on the website for the respective platform: + - Full download links (Wasabi and mirror) + - Client download link + - Full download hash + - Client download hash + +Repeat for each platform (currently 32-bit Windows and 64-bit Linux). Once you're done, don't forget to announce your release! diff --git a/README.md b/README.md index 4dc6956..2f5341d 100644 --- a/README.md +++ b/README.md @@ -2,52 +2,7 @@ [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 Wiki](https://github.com/Crystalwarrior/KFO-Client/wiki) for more information. - ---- - -## Compiling - -The traditional route is by undergoing the [AO2 Rite of Passage](https://gist.github.com/oldmud0/6c645bd1667370c3e92686f7d0642c38). Recently, however, it has become more feasible to get away with a dynamic compilation, which is much easier for beginners and requires less setup. - -### Dependencies - -- [BASS](http://un4seen.com) (proprietary, but will become optional in the future; see #35) -- [Discord Rich Presence](https://github.com/discordapp/discord-rpc) - -## Release instructions - -Follow these steps to make a new full release: - -- Set a new AO version in the `.pro` file and in `aoapplication.h`. -- Compile the project. -- Commit the version bump and and create a tag for the commit. -- Rename the executable to `Attorney_Online`. -- Create a temp directory. -- Copy a fresh `base` folder to the temp dir. Ensure that the timestamps are consistent. - - Ignore this step if creating a client-only release. -- Copy the repository's `base` folder to the temp dir. -- Append `.sample` to the names of all `.ini` files, including `serverlist.txt`. -- Copy the game executable to the temp dir. -- Copy `bass.dll`, `discord-rpc.dll`, and `qapng.dll` if applicable. -- Copy `README.md` as `README.md.txt` with CRLF line endings. -- Copy `LICENSE` as `LICENSE.txt` with CRLF line endings. -- Compress the contents of the temp dir to an archive with maximum compression, but - be sure that the contents are placed inside the root directory of the archive and not - within a subdirectory. -- Compute the SHA-1 hash of the archive. -- Upload the archive to the Wasabi bucket and an additional mirror (e.g. MEGA or OneDrive) - (if this is a full release). -- Publish a GitHub release and upload the archive there (if this is a client-only release). -- Add the new version to the `program.json` manifest for the respective platform - (if this is a client-only release). -- Update the following on the website for the respective platform: - - Full download links (Wasabi and mirror) - - Client download link - - Full download hash - - Client download hash - -Repeat for each platform (currently 32-bit Windows and 64-bit Linux). Once you're done, don't forget to announce your release! +**[Refer to the docs](https://github.com/AttorneyOnline/docs/blob/master/docs/index.md) for more information.** ## Credits From 19d0c29b35cafc3d12209aa29fa4db5c8dbe930b Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Mon, 29 Jun 2020 18:39:27 +0300 Subject: [PATCH 217/268] Fix issues when undefined colors result in everyone's chat not using talk anims (#174) base/misc/default/config.ini with properly defined "baseline" colors will have to be supplied with vanilla content later. Remove hardcoded colors - user has no access to these unless config.ini is valid, yet when others speak using these ID's their text shows up just fine. Either reimplement full on hardcoding madness (NOOOOOOOOOOOOOOOOOOOOOOOO NO NO NO NOOOOOOOOOOOOOOOO NOOOOO!!!!) or yeet. I chose the sensible option :^) --- src/courtroom.cpp | 2 +- src/text_file_functions.cpp | 32 -------------------------------- 2 files changed, 1 insertion(+), 33 deletions(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index e3eeb59..5080b1d 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -4245,7 +4245,7 @@ void Courtroom::set_text_color_dropdown() current_char) == "1"); color_markdown_talking_list.append( ao_app->get_chat_markdown("c" + QString::number(c) + "_talking", - current_char) == "1"); + current_char) != "0"); QString color_name = ao_app->get_chat_markdown( "c" + QString::number(c) + "_name", current_char); diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index 1689cd3..4ea58d6 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -449,38 +449,6 @@ QColor AOApplication::get_chat_color(QString p_identifier, QString p_chat) { QColor return_color(255, 255, 255); - switch (p_identifier.toInt()) { - case 0: // White - return_color = QColor(255, 255, 255); - break; - case 1: // Green - return_color = QColor(0, 255, 0); - break; - case 2: // Red - return_color = QColor(255, 0, 0); - break; - case 3: // Orange - return_color = QColor(255, 165, 0); - break; - case 4: // Blue - return_color = QColor(45, 150, 255); - break; - case 5: // Yellow - return_color = QColor(255, 255, 0); - break; - case 6: // Pink - return_color = QColor(255, 192, 203); - break; - case 7: // Cyan - return_color = QColor(0, 255, 255); - break; - case 8: // Grey - return_color = QColor(187, 187, 187); - break; - default: - return_color = QColor(255, 255, 255); - break; - } QString design_ini_path = get_base_path() + "misc/" + p_chat + "/config.ini"; QString default_path = get_base_path() + "misc/default/config.ini"; QString f_result = read_design_ini("c" + p_identifier, design_ini_path); From 6d4eb8774912ce81593e0503df3923d1bc6df699 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Tue, 30 Jun 2020 23:29:51 +0300 Subject: [PATCH 218/268] Add explanation comments to the music looping vars Make music not loop by default for backwards compatibility with old style on servers not supporting clientside music looping Make the music loop when the packet containing loop data gives us "1", treating it as "looping=true". --- src/courtroom.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 5080b1d..7a38b94 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -3000,13 +3000,17 @@ void Courtroom::handle_song(QStringList *p_contents) (f_song_clear.lastIndexOf("/") + 1)); int n_char = f_contents.at(1).toInt(); - bool looping = true; + //Assume the song doesn't loop unless told otherwise (due to most outdated servers handling looping through serverside) + bool looping = false; + //Channel 0 is the 'master music', other channels would commonly be used for ambience int channel = 0; + //No effects assumed by default - vanilla functionality int effect_flags = 0; + if (n_char < 0 || n_char >= char_list.size()) { int channel = 0; - if (p_contents->length() > 3 && p_contents->at(3) != "-1") - looping = false; + if (p_contents->length() > 3 && p_contents->at(3) == "1") + looping = true; if (p_contents->length() > 4) // eyyy we want to change this song's CHANNEL huh @@ -3032,10 +3036,8 @@ void Courtroom::handle_song(QStringList *p_contents) str_show = p_contents->at(2); } } - if (p_contents->length() > 3 && p_contents->at(3) != "-1") { - // I am really confused why "-1" is "loop this song" and why anything else - // passes as "don't loop" (if we even have this length) but alright - looping = false; + if (p_contents->length() > 3 && p_contents->at(3) == "1") { + looping = true; } if (p_contents->length() > 4) // eyyy we want to change this song's CHANNEL huh From 19c3aa93fedcf9f1a6e64d4c97270c89b840d769 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Thu, 2 Jul 2020 21:52:35 +0300 Subject: [PATCH 219/268] Some commit managed to regress the colors and it actually totally wasn't my fault!!! Fix colors being broken --- src/courtroom.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 5080b1d..ba16f8c 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -4234,7 +4234,7 @@ void Courtroom::set_text_color_dropdown() // Update markdown colors. TODO: make a loading function that only loads the // config file once instead of several times for (int c = 0; c < max_colors; ++c) { - QColor color = ao_app->get_chat_color(QString::number(c), current_char); + QColor color = ao_app->get_chat_color("c" + QString::number(c), current_char); color_rgb_list.append(color); color_markdown_start_list.append(ao_app->get_chat_markdown( "c" + QString::number(c) + "_start", current_char)); From 5cd9da37063bccab1d00931091df3f8b71225540 Mon Sep 17 00:00:00 2001 From: oldmud0 Date: Fri, 3 Jul 2020 09:57:39 -0500 Subject: [PATCH 220/268] Credit some more people Not sure how to split this up, frankly. Some people have been more involved in client/server/protocol development than others. I'll figure this out eventually. --- src/lobby.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lobby.cpp b/src/lobby.cpp index 613bee5..3d47416 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -370,6 +370,8 @@ void Lobby::on_about_clicked() "

    Major development:
    " "OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, " "Crystalwarrior, Iamgoofball" + "

    Client development:
    " + "Cents02, in1tiate, raidensnake, windrammer" "

    QA testing:
    " "CaseyCazy, CedricDewitt, Chewable Tablets, CrazyJC, Fantos, " "Fury McFlurry, Geck, Gin-Gi, Jamania, Minx, Pandae, " From 0a31a20266adcbd9afd6ef54abe4123f5f1708a3 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sat, 4 Jul 2020 00:34:09 +0300 Subject: [PATCH 221/268] Add a setting to turn on/off custom character-defined chatboxes (#166) * Add a new "Custom Chatboxes" settings option to enable/disable char.ini setting custom chat box designs per-character * Fix chat_arrow being incorrectly updated between character messages if the custom chatbox modified the chat arrow positioning/size in any way * brackets matter --- include/aoapplication.h | 5 +++++ include/aooptionsdialog.h | 3 +++ src/aooptionsdialog.cpp | 15 +++++++++++++ src/courtroom.cpp | 42 +++++++++++++++++++++++-------------- src/text_file_functions.cpp | 6 ++++++ 5 files changed, 55 insertions(+), 16 deletions(-) diff --git a/include/aoapplication.h b/include/aoapplication.h index 18f6ef2..af357d0 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -200,6 +200,11 @@ public: // from the config.ini. bool is_stickypres_enabled(); + // Returns the value of whether custom chatboxes should be a thing. + // from the config.ini. + // I am increasingly maddened by the lack of dynamic auto-generation system for settings. + bool is_customchat_enabled(); + // Returns the value of the maximum amount of lines the IC chatlog // may contain, from config.ini. int get_max_log_size(); diff --git a/include/aooptionsdialog.h b/include/aooptionsdialog.h index 7e983a3..06684ef 100644 --- a/include/aooptionsdialog.h +++ b/include/aooptionsdialog.h @@ -78,6 +78,9 @@ private: QLabel *ui_stickypres_lbl; QCheckBox *ui_stickypres_cb; + QLabel *ui_customchat_lbl; + QCheckBox *ui_customchat_cb; + QWidget *ui_callwords_tab; QWidget *ui_callwords_widget; QVBoxLayout *ui_callwords_layout; diff --git a/src/aooptionsdialog.cpp b/src/aooptionsdialog.cpp index 80746f7..e6ff8ff 100644 --- a/src/aooptionsdialog.cpp +++ b/src/aooptionsdialog.cpp @@ -313,6 +313,20 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_stickypres_cb); + row += 1; + ui_customchat_lbl = new QLabel(ui_form_layout_widget); + ui_customchat_lbl->setText(tr("Custom Chatboxes:")); + ui_customchat_lbl->setToolTip( + tr("Turn this on to allow characters to define their own " + "custom chat box designs.")); + + ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_customchat_lbl); + + ui_customchat_cb = new QCheckBox(ui_form_layout_widget); + ui_customchat_cb->setChecked(ao_app->is_customchat_enabled()); + + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_customchat_cb); + QScrollArea *scroll = new QScrollArea; scroll->setWidget(ui_form_layout_widget); ui_gameplay_tab->setLayout(new QVBoxLayout); @@ -708,6 +722,7 @@ void AOOptionsDialog::save_pressed() configini->setValue("stickysounds", ui_stickysounds_cb->isChecked()); configini->setValue("stickyeffects", ui_stickyeffects_cb->isChecked()); configini->setValue("stickypres", ui_stickypres_cb->isChecked()); + configini->setValue("customchat", ui_customchat_cb->isChecked()); QFile *callwordsini = new QFile(ao_app->get_base_path() + "callwords.ini"); diff --git a/src/courtroom.cpp b/src/courtroom.cpp index ba16f8c..7326948 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1883,30 +1883,35 @@ void Courtroom::handle_chatmessage_2() QString chatbox_path = ao_app->get_theme_path("chat"); QString chatbox = ao_app->get_chat(m_chatmessage[CHAR_NAME]); - if (chatbox != "") { + QString customchar; + if (ao_app->is_customchat_enabled()) + customchar = m_chatmessage[CHAR_NAME]; + + if (chatbox != "" && ao_app->is_customchat_enabled()) { 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"); + } - pos_size_type design_ini_result = ao_app->get_element_dimensions( - "chat_arrow", "courtroom_design.ini", m_chatmessage[CHAR_NAME]); - 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(); - } - else { - ui_vp_chat_arrow->move(design_ini_result.x, design_ini_result.y); - ui_vp_chat_arrow->combo_resize(design_ini_result.width, - design_ini_result.height); - } + //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); + 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(); + } + else { + ui_vp_chat_arrow->move(design_ini_result.x, design_ini_result.y); + ui_vp_chat_arrow->combo_resize(design_ini_result.width, + design_ini_result.height); } pos_size_type default_width = ao_app->get_element_dimensions( - "showname", "courtroom_design.ini", m_chatmessage[CHAR_NAME]); + "showname", "courtroom_design.ini", customchar); int extra_width = ao_app ->get_design_element("showname_extra_width", "courtroom_design.ini", - m_chatmessage[CHAR_NAME]) + customchar) .toInt(); if (extra_width > 0) { @@ -2692,8 +2697,13 @@ void Courtroom::chat_tick() ui_vp_player_char->play_idle(m_chatmessage[CHAR_NAME], m_chatmessage[EMOTE]); } - QString f_char = m_chatmessage[CHAR_NAME]; - QString f_custom_theme = ao_app->get_chat(f_char); + QString f_char; + QString f_custom_theme; + if (ao_app->is_customchat_enabled()) + { + f_char = m_chatmessage[CHAR_NAME]; + f_custom_theme = ao_app->get_chat(f_char); + } ui_vp_chat_arrow->play( "chat_arrow", f_char, f_custom_theme); // Chat stopped being processed, indicate that. diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index 4ea58d6..8f86840 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -988,6 +988,12 @@ bool AOApplication::is_stickypres_enabled() return result.startsWith("true"); } +bool AOApplication::is_customchat_enabled() +{ + QString result = configini->value("customchat", "true").value(); + return result.startsWith("true"); +} + bool AOApplication::get_casing_enabled() { QString result = configini->value("casing_enabled", "false").value(); From c533370fd8a939721af41e566fc28c854d616b09 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sat, 4 Jul 2020 20:15:19 +0300 Subject: [PATCH 222/268] Fix the blips folder not seeking the blips/ folder for the male.wav sound effect first instead of trying to find sfx-blipmale in base/general folder, makes using the blips folder more viable. (#173) --- src/text_file_functions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index 8f86840..122bc41 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -601,7 +601,7 @@ QString AOApplication::get_gender(QString p_char) QString f_result = read_char_ini(p_char, "gender", "Options"); if (f_result == "") - return "sfx-blipmale"; + f_result = "male"; if (!file_exists(get_sfx_suffix(get_sounds_path(f_result)))) { if (file_exists(get_sfx_suffix(get_sounds_path("../blips/" + f_result)))) From 44a4a2d23ede7986212558e9cc53387d6f3a1dc9 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sat, 4 Jul 2020 20:15:52 +0300 Subject: [PATCH 223/268] Fix an issue where the Ambience layer would break looping points for all other channels due to loop_start and loop_end only being a single variable. (#164) This occurs due to BASS not having any private variables of its own, so it was simply using the public variables loop_start and loop_end as reference - since those changed for any new song playing on another channel, the old looping points got replaced, and the seamless looping stops working. The solution was easy - just make a loop_start/loop_end variable for every supported channel - so 4 variables in our case. --- include/aomusicplayer.h | 4 ++-- src/aomusicplayer.cpp | 25 +++++++++++++------------ 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/include/aomusicplayer.h b/include/aomusicplayer.h index de673e5..82751b6 100644 --- a/include/aomusicplayer.h +++ b/include/aomusicplayer.h @@ -25,8 +25,8 @@ public: const int m_channelmax = 4; // These have to be public for the stupid sync thing - int loop_start = 0; - int loop_end = 0; + int loop_start[4] = {0, 0, 0, 0}; + int loop_end[4] = {0, 0, 0, 0}; public slots: void play(QString p_song, int channel = 0, bool loop = false, diff --git a/src/aomusicplayer.cpp b/src/aomusicplayer.cpp index 8ba1641..249e01e 100644 --- a/src/aomusicplayer.cpp +++ b/src/aomusicplayer.cpp @@ -40,8 +40,8 @@ void AOMusicPlayer::play(QString p_song, int channel, bool loop, QString d_path = f_path + ".txt"; - loop_start = 0; - loop_end = BASS_ChannelGetLength(newstream, BASS_POS_BYTE); + loop_start[channel] = 0; + loop_end[channel] = BASS_ChannelGetLength(newstream, BASS_POS_BYTE); if (loop && file_exists(d_path)) // Contains loop/etc. information file { QStringList lines = ao_app->read_file(d_path).split("\n"); @@ -64,11 +64,11 @@ void AOMusicPlayer::play(QString p_song, int channel, bool loop, QWORD bytes = static_cast(args[1].trimmed().toFloat() * sample_size * num_channels); if (arg == "loop_start") - loop_start = bytes; + loop_start[channel] = bytes; else if (arg == "loop_length") - loop_end = loop_start + bytes; + loop_end[channel] = loop_start[channel] + bytes; else if (arg == "loop_end") - loop_end = bytes; + loop_end[channel] = bytes; } qDebug() << "Found data file for song" << p_song << "length" << BASS_ChannelGetLength(newstream, BASS_POS_BYTE) << "loop start" @@ -111,7 +111,7 @@ void AOMusicPlayer::play(QString p_song, int channel, bool loop, else this->set_volume(m_volume[channel], channel); - this->set_looping(loop); // Have to do this here due to any + this->set_looping(loop, channel); // Have to do this here due to any // crossfading-related changes, etc. } @@ -145,6 +145,7 @@ void CALLBACK loopProc(HSYNC handle, DWORD channel, DWORD data, void *user) void AOMusicPlayer::set_looping(bool toggle, int channel) { + qDebug() << "Setting looping for channel" << channel << "to" << toggle; m_looping = toggle; if (!m_looping) { if (BASS_ChannelFlags(m_stream_list[channel], 0, 0) & BASS_SAMPLE_LOOP) @@ -161,13 +162,13 @@ void AOMusicPlayer::set_looping(bool toggle, int channel) loop_sync[channel]); // remove the sync loop_sync[channel] = 0; } - if (loop_start > 0) { - if (loop_end == 0) - loop_end = BASS_ChannelGetLength(m_stream_list[channel], BASS_POS_BYTE); - if (loop_end > 0) // Don't loop zero length songs even if we're asked to + if (loop_start[channel] > 0) { + if (loop_end[channel] == 0) + loop_end[channel] = BASS_ChannelGetLength(m_stream_list[channel], BASS_POS_BYTE); + if (loop_end[channel] > 0) // Don't loop zero length songs even if we're asked to loop_sync[channel] = BASS_ChannelSetSync( - m_stream_list[channel], BASS_SYNC_POS | BASS_SYNC_MIXTIME, loop_end, - loopProc, &loop_start); + m_stream_list[channel], BASS_SYNC_POS | BASS_SYNC_MIXTIME, loop_end[channel], + loopProc, &loop_start[channel]); } } } From b12f82dc8cd1137586781e8142556a6c495a0c11 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sun, 5 Jul 2020 03:07:09 +0300 Subject: [PATCH 224/268] Fix html not being parsed in ic logs when ic logs go downwards (#178) I found this bug like 3 weeks ago but I forgot to actually make a PR for it oops --- src/courtroom.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 55b851e..9920b3b 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -2538,7 +2538,7 @@ void Courtroom::append_ic_text(QString p_text, QString p_name, QString p_action) } else { ui_ic_chatlog->textCursor().insertText(": ", normal); - ui_ic_chatlog->textCursor().insertText(p_text + '\n', normal); + ui_ic_chatlog->textCursor().insertHtml(p_text + '\n'); } // If we got too many blocks in the current log, delete some from the From ec9244809cd09521fd582e5812ac5f0440860677 Mon Sep 17 00:00:00 2001 From: oldmud0 Date: Sun, 5 Jul 2020 15:29:41 -0500 Subject: [PATCH 225/268] Fix Mac build missing audio (#180) --- .travis.yml | 2 +- scripts/macos_build.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index dbd19cd..48bc2b5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,7 @@ deploy: provider: releases api_key: secure: mZCNwnqKeqJP5CqgYOanYnr/KHydxueGPRhvGLpY0Pop7MiH3CIHMN5dhHbtgJvE5GGMR4xUIEhPpmkCEJw7YiPREMqT4mkV4DR531ZLB3t/FizyvIwXuP6jFwzTofZ51qHfBpcurVc9sMFeD9Pw+rLTTgIiXL2sZxUUXc8U+ZZug1lYndgcO6P00fUJd6V9lyFQUGmbSca97YbG6KuCym0fEpyRnMqzKLjYsUUo8UKRBADtmD822O6z2FSldNZDn45Mkx0MYfHWyT5hzTb7WGa+DrTB/0un1HqqsNPlb/ahjrFQQNR2qd7HNGZa+Mvwi6egTDug+k15x8lbkacUoi34U1eFq9LSTYm8dSO5g23I1OvGvjTCkDj1jOLPqB99XlbAJ0E/9Jzw7wtlLaAzvFzTj/B63TQnO3IsgHBWR14CZlf05WMOFf2irwl+kL6ktspIHnlGgaiWYYrKeAt7QJAXiQOdYDz6SaWVC6TyOE/SszXRU6xFotmCjkP2irM5yGE8SUw2uIzKjD9uG0ZXtbLcdQEFD316+qglqFTCjnKsRfbtQs2u5spZPsZSdsOZCbLfNIn0GSTFRymFsK6gsvji8AD8AZo0zcOZ/7NMVC6A8RnF3Ve+vU/xljhsIOxoLZDvZPia7WozdV99xmnepWBwkuoQs/K0xmWcnLZDcb0= - file: "../bin/Attorney_Online_mac_x86_64.zip" + file: "../bin/Attorney_Online_macOS.zip" draft: true on: tags: true diff --git a/scripts/macos_build.sh b/scripts/macos_build.sh index efb7653..fb631e9 100755 --- a/scripts/macos_build.sh +++ b/scripts/macos_build.sh @@ -30,4 +30,4 @@ tar -xvf apng.tar.xz cp clang_64/plugins/imageformats/libqapng.dylib ../lib cd .. -/usr/local/opt/qt/bin/qmake && make -j2 +/usr/local/opt/qt/bin/qmake "DEFINES += DISCORD QTAUDIO" && make -j2 From e827f560f3c7ea3279a81b2737802734e80c431d Mon Sep 17 00:00:00 2001 From: oldmud0 Date: Sun, 5 Jul 2020 15:48:24 -0500 Subject: [PATCH 226/268] Mac CI: Fix wrong zip name --- scripts/macos_post_build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/macos_post_build.sh b/scripts/macos_post_build.sh index df1475c..cdf7514 100755 --- a/scripts/macos_post_build.sh +++ b/scripts/macos_post_build.sh @@ -21,4 +21,4 @@ cp ../lib/* ../bin/Attorney_Online.app/Contents/Frameworks # libbass has a funny path for some reason, just use rpath install_name_tool -change @loader_path/libbass.dylib @rpath/libbass.dylib ../bin/Attorney_Online.app/Contents/MacOS/Attorney_Online -zip -r -9 ../bin/Attorney_Online_mac_x86_64.zip ../bin/ \ No newline at end of file +zip -r -9 ../bin/Attorney_Online_macOS.zip ../bin/ \ No newline at end of file From c29fe7c7ba234e1819f5b5fb566173b4a1831fa4 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Tue, 7 Jul 2020 01:46:22 +0300 Subject: [PATCH 227/268] Regenerate the background when reload_theme is pressed to prevent scaling issues (#181) --- src/courtroom.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 9920b3b..8f7e1b7 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -4396,7 +4396,7 @@ void Courtroom::on_reload_theme_clicked() text_state = 3; // to update status on the background - set_background(current_background); + set_background(current_background, true); } void Courtroom::on_back_to_lobby_clicked() From 4c5fdab9e97287cd2cb76f0c9893c0420caed837 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Wed, 8 Jul 2020 00:02:17 +0300 Subject: [PATCH 228/268] Fix the color fix pr when logs go downwards where it didn't add an \n because html doesn't like \n very much so it has to be
    because that's what HTML does yea --- src/courtroom.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 8f7e1b7..5b043c4 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -2538,7 +2538,7 @@ void Courtroom::append_ic_text(QString p_text, QString p_name, QString p_action) } else { ui_ic_chatlog->textCursor().insertText(": ", normal); - ui_ic_chatlog->textCursor().insertHtml(p_text + '\n'); + ui_ic_chatlog->textCursor().insertHtml(p_text + "
    "); } // If we got too many blocks in the current log, delete some from the From b38e221fb169400a2f1afda0df18821b3c12381b Mon Sep 17 00:00:00 2001 From: raidensnake Date: Sun, 12 Jul 2020 05:06:38 +0100 Subject: [PATCH 229/268] Fix APNG backgrounds not appearing on list; fix BASSOPUS path for macOS (#185) * Added apng support for animated background positioning. * Adjusted the apng background position search. * Fixed libbassopus.dylib path on MacOS preventing opus files from playing. --- src/courtroom.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 5b043c4..effef54 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1107,7 +1107,7 @@ void Courtroom::set_background(QString p_background, bool display) // Populate the dropdown list with all pos that exist on this bg QStringList pos_list = {}; for (QString key : default_pos.keys()) { - if (file_exists(ao_app->get_static_image_suffix( + if (file_exists(ao_app->get_image_suffix( ao_app->get_background_path(key)))) { pos_list.append(default_pos[key]); } @@ -4599,11 +4599,8 @@ void Courtroom::load_bass_opus_plugin() #elif defined __APPLE__ void Courtroom::load_bass_opus_plugin() { - QString libpath = - ao_app->get_base_path() + "../../Frameworks/libbassopus.dylib"; - QByteArray ba = libpath.toLocal8Bit(); #ifdef BASSAUDIO - BASS_PluginLoad(ba.data(), 0); + BASS_PluginLoad("libbassopus.dylib", 0); #endif } #else From 44659fd2a6693d82443ba666a4f1a086b39e7f77 Mon Sep 17 00:00:00 2001 From: likeawindrammer <31085911+likeawindrammer@users.noreply.github.com> Date: Tue, 14 Jul 2020 03:55:18 -0600 Subject: [PATCH 230/268] Update some strings for 2.8 in the Spanish translation. (WIP) --- resource/translations/ao_es.ts | 390 +++++++++++++++++---------------- 1 file changed, 201 insertions(+), 189 deletions(-) diff --git a/resource/translations/ao_es.ts b/resource/translations/ao_es.ts index 3d456a5..d25c145 100644 --- a/resource/translations/ao_es.ts +++ b/resource/translations/ao_es.ts @@ -31,58 +31,58 @@ Ingrese a aceattorneyonline.com para actualizar. You have been exiled from AO. Have a nice day. - Has sido exiliado de AO. + Has sido exiliado de AO. Que tengas un buen día. - + Attorney Online 2 - + Loading Cargando - + Loading evidence: %1/%2 Cargando evidencia: %1/%2 - - + + Loading music: %1/%2 Cargando música: %1/%2 - - + + Loading chars: %1/%2 Cargando personajes: %1/%2 - + You have been kicked from the server. Reason: %1 Has sido expulsado del servidor. Razón: %1 - + You have been banned from the server. Reason: %1 Has sido bloqueado de este servidor. Razón: %1 - + You are banned on this server. Reason: %1 Has sido bloqueado en este servidor. @@ -140,7 +140,7 @@ Razón: Witness needed - Se necesita testigo + Se necesita testigo @@ -203,7 +203,7 @@ Razón: Gives the default value for the in-game 'Custom shownames' tickbox, which in turn determines whether the client should display custom in-character names. - Activa la casilla 'Mostrar nombres' de forma predeterminada en el juego, que a su vez determina si el cliente debe mostrar nombres personalizados en los personajes. + Activa la casilla 'Mostrar nombres' de forma predeterminada en el juego, que a su vez determina si el cliente debe mostrar nombres personalizados en los personajes. @@ -227,11 +227,11 @@ Razón: Allow Shake/Flash: - Permitir Shake/Flash: + Permitir Shake/Flash: Allows screenshaking and flashing. Disable this if you have concerns or issues with photosensitivity and/or seizures. - Permite el movimiento de la pantalla y el parpadeo. Desactive esto si tiene inquietudes o problemas con la fotosensibilidad y/o convulsiones. + Permite el movimiento de la pantalla y el parpadeo. Desactive esto si tiene inquietudes o problemas con la fotosensibilidad y/o convulsiones. @@ -245,326 +245,336 @@ Razón: Punctuation delay modifier. Enable it for the blips to slow down on punctuations. - Habilítelo para agregar una pequeña pausa en los signos de puntuación. + Habilítelo para agregar una pequeña pausa en los signos de puntuación. - + Callwords Palabras clave - + <html><head/><body>Enter as many callwords as you would like. These are case insensitive. Make sure to leave every callword in its own line!<br>Do not leave a line with a space at the end -- you will be alerted everytime someone uses a space in their messages.</body></html> <html><head/><body>Ingrese tantas palabras de llamada como desee.<br>Esto no distingue entre mayúsculas y minúsculas. ¡Asegúrese de dejar cada palabra en su propia línea!<br>No deje una línea con un espacio al final; recibirá una alerta cada vez que alguien use un espacio en sus mensajes.</body></html> - + Audio Audio - + Audio device: Dispositivo: - + Sets the audio device for all sounds. Establece el dispositivo de audio. - + Music: Música: - + Sets the music's default volume. - Establece el volumen predeterminado de la música. + Establece el volumen predeterminado de la música. - + SFX: SFX: - + Sets the SFX's default volume. Interjections and actual sound effects count as 'SFX'. - Establece el volumen predeterminado de SFX. Las interjecciones y los efectos de sonido reales cuentan como 'SFX'. + Establece el volumen predeterminado de SFX. Las interjecciones y los efectos de sonido reales cuentan como 'SFX'. Gives the default value for the in-game 'Custom shownames' checkbox, which in turn determines whether the client should display custom in-character names. - Activa la casilla 'Mostrar nombres' de forma predeterminada en el juego, que a su vez determina si el cliente debe mostrar nombres personalizados en los personajes. + Activa la casilla 'Mostrar nombres' de forma predeterminada en el juego, que a su vez determina si el cliente debe mostrar nombres personalizados en los personajes. Slower text speed: - Texto más lento: + Texto más lento: Set the text speed to be the same as the AA games. - La velocidad del texto será la misma que en los juegos de AA. + La velocidad del texto será la misma que en los juegos de AA. Blip delay on punctuations: - Retraso en puntuación: + Retraso en puntuación: Sets the default volume for music. - Establece el volumen predeterminado de la música. + Establece el volumen predeterminado de la música. Sets the default volume for SFX sounds, like interjections or other character sound effects. - Establece el volumen predeterminado para sonidos SFX, como las interjecciones y otros efectos de sonido de personajes. + Establece el volumen predeterminado para sonidos SFX, como las interjecciones y otros efectos de sonido de personajes. - + Blips: Blips: - + Sets the volume of the blips, the talking sound effects. Establece el volumen de los blips, el sonido al hablar. - + Blip rate: Tasa de blips: - + Sets the delay between playing the blip sounds. Establece el retraso entre la reproducción de los sonidos blip. - + Blank blips: Blips en blanco: - + If true, the game will play a blip sound even when a space is 'being said'. Si está marcada, el juego reproducirá un sonido blip incluso cuando se 'dice' un espacio. - + Enable Looping SFX: Habilitar repetición de SFX: - + If true, the game will allow looping sound effects to play on preanimations. Si está habilitado, el juego permitirá que se reproduzcan efectos de sonido en bucle en preanimaciones. - + Kill Music On Objection: Parar la música al objetar: If true, the game will stop music when someone objects, like in the actual games. - Si está habilitado, el juego detendrá la música cuando alguien haga una objeción, como en los juegos. + Si está habilitado, el juego detendrá la música cuando alguien haga una objeción, como en los juegos. - Keep current setting - + - Mantener la configuración actual Allow Screenshake: - + Permitir Screenshake: Allows screenshaking. Disable this if you have concerns or issues with photosensitivity and/or seizures. - + Permite el movimiento de la pantalla (Advertencia esto podría inducir convulsiones debido a imágenes parpadeantes). Allow Effects: - + Permitir efectos: Allows screen effects. Disable this if you have concerns or issues with photosensitivity and/or seizures. - + Permite efectos de pantalla (Advertencia esto podría inducir convulsiones debido a imágenes parpadeantes). Network Frame Effects: - + Efectos de marco de red: Send screen-shaking, flashes and sounds as defined in the char.ini over the network. Only works for servers that support this functionality. - + Envíe temblores de pantalla, destellos y sonidos como se define en char.ini a través de la red. Solo funciona para servidores que admiten esta funcionalidad. Colors in IC Log: - + Colores en el registro IC: Use the markup colors in the server IC chatlog. - + Permite colores en el chat IC del servidor. Sticky Sounds: - + Sonidos pegajosos: Turn this on to prevent the sound dropdown from clearing the sound after playing it. - + Actívelo para evitar que el menú desplegable de sonido borre el sonido después de reproducirlo. Sticky Effects: - + Efectos pegajosos: Turn this on to prevent the effects dropdown from clearing the effect after playing it. - + Actívelo para evitar que el menú desplegable de efectos elimine el efecto después de reproducirlo. Sticky Preanims: - + Preanims pegajosos: Turn this on to prevent preanimation checkbox from clearing after playing the emote. - + Actívelo para evitar que la casilla preanimation se desactive después de reproducir el emote. - + + Custom Chatboxes: + Chatboxes personalizados: + + + + Turn this on to allow characters to define their own custom chat box designs. + Actívelo para permitir que los personajes definan sus propios diseños de cuadros de chat personalizados. + + + Play a blip sound "once per every X symbols", where X is the blip rate. - + Reproduzca un sonido de blip "una vez por cada X símbolos", donde X es la tasa de blip. - + If true, AO2 will stop the music for you when you or someone else does 'Objection!'. - + Si es activado, AO2 detendrá la música por ti cuando tú u otra persona hagan '¡Objeción!'. - + Casing Caso - + This server supports case alerts. Este servidor admite alertas de casos. - + This server does not support case alerts. Este servidor no admite alertas de casos. - + Pretty self-explanatory. Bastante autoexplicativo. - + Casing: Caso: - + If checked, you will get alerts about case announcements. Si está marcado, recibirá anuncios de casos. - + Defense: Abogado: - + If checked, you will get alerts about case announcements if a defense spot is open. Si está marcado, recibirá alertas sobre anuncios de casos si hay un lugar de abogado libre. - + Prosecution: Fiscal: - + If checked, you will get alerts about case announcements if a prosecutor spot is open. Si está marcada, recibirá alertas sobre anuncios de casos si hay un puesto de fiscal libre. - + Judge: Juez: - + If checked, you will get alerts about case announcements if the judge spot is open. Si está marcado, recibirá alertas sobre anuncios de casos si el puesto de juez está libre. - + Juror: Jurado: - + If checked, you will get alerts about case announcements if a juror spot is open. Si está marcado, recibirá alertas sobre anuncios de casos si hay un puesto de jurado libre. - + Stenographer: Taquígrafo: - + If checked, you will get alerts about case announcements if a stenographer spot is open. Si está marcado, recibirá alertas sobre anuncios de casos si hay un lugar de taquígrafo libre. - + CM: CM: - + If checked, you will appear amongst the potential CMs on the server. Si está marcado, aparecerá entre los posibles CM en el servidor. Witness: - Testigo: + Testigo: If checked, you will appear amongst the potential witnesses on the server. - Si está marcado, aparecerá entre los posibles testigos en el servidor. + Si está marcado, aparecerá entre los posibles testigos en el servidor. - + Hosting cases: Casos: - + If you're a CM, enter what cases you are willing to host. Si eres un CM, ingresa qué casos estás dispuesto a organizar. Only inline coloring will be shown such as <>,|| etc. - Solo se mostrará el color en línea, como <>, ||, etc. + Solo se mostrará el color en línea, como <>, ||, etc. IC log will mirror the IC box. Meaning that if somebody gets interrupted nobody will know what they wanted to say. Enable for a more realistic experience. - El registro de IC reflejará el chat In-Character. Lo que significa que si alguien es interrumpido, nadie sabrá lo que se iba a decir. Habilitar para una experiencia más realista. + El registro de IC reflejará el chat In-Character. Lo que significa que si alguien es interrumpido, nadie sabrá lo que se iba a decir. Habilitar para una experiencia más realista. IC log will mirror the IC box. Meaning that if somebody gets interrupted nobody will know what they wanted to say. Enable for a more realistic experience @@ -572,15 +582,15 @@ Razón: Colorful IC log: - Log IC colorido: + Log IC colorido: Enables colored text in the log. - Habilita texto con color en el log. + Habilita texto con color en el log. Only inline coloring: - Solo coloración en línea: + Solo coloración en línea: Only inline coloring will be shown such as <>,|| etc @@ -588,7 +598,7 @@ Razón: Mirror IC log: - IC log refleja interrupciones: + IC log refleja interrupciones: IC log will mirror the IC box. Meaning that if somebody gets interupted nobody will know what they wanted to say. Enable for a more realistic expierence @@ -626,13 +636,13 @@ Razón: Could not find %1 - No se pudo encontrar %1 + No se pudo encontrar %1 - + Generating chars: %1/%2 - Generando personajes: + Generando personajes: %1/%2 @@ -672,7 +682,7 @@ Razón: Guard - Guardia + Guardia @@ -695,39 +705,39 @@ Razón: White - Blanco + Blanco Green - Verde + Verde Red - Rojo + Rojo Orange - Naranja + Naranja Blue - Azul + Azul Yellow - Amarillo + Amarillo Rainbow - Arcoíris + Arcoíris Pink - Rosado + Rosado Cyan - Cian + Cian @@ -791,7 +801,7 @@ Razón: Se le concedió el botón para deshabilitar llamadas a moderadores. - + You have been banned. Has sido vetado. @@ -801,20 +811,20 @@ Razón: This does nothing, but there you go. - Esto no hace nada, pero ahí lo tienes. + Esto no hace nada, pero ahí lo tienes. - + You opened the settings menu. Abriste el menú de configuración. You will now pair up with - Ahora te emparejarás con + Ahora te emparejarás con if they also choose your character in return. - si ellos también eligen a tu personaje a cambio. + si ellos también eligen a tu personaje a cambio. @@ -824,7 +834,7 @@ Razón: Additive - + Aditivo @@ -844,12 +854,12 @@ Razón: Change the percentage offset of your character's position from the center of the screen. - + Cambia el desplazamiento porcentual de la posición de tu personaje desde el centro de la pantalla. Change the order of appearance for your character. - + Cambia el orden de aparición de tu personaje. @@ -939,7 +949,7 @@ char.ini [Options] category, effects = 'miscname' where it referes to Bring up the Character Select Screen and change your character. - + Abre la pantalla de selección de personaje y cambia tu personaje. @@ -954,12 +964,12 @@ char.ini [Options] category, effects = 'miscname' where it referes to Allows you to change various aspects of the client. - + Le permite cambiar varios aspectos del cliente. An interface to help you announce a case (you have to be a CM first to be able to announce cases) - + Una interfaz para ayudarlo a anunciar un caso (debe ser un CM para poder anunciar casos) @@ -984,7 +994,7 @@ char.ini [Options] category, effects = 'miscname' where it referes to Add text to your last spoken message when checked. - + Agregue texto a su último mensaje hablado cuando esté marcado. @@ -1000,12 +1010,12 @@ char.ini [Options] category, effects = 'miscname' where it referes to Display customized shownames for all users when checked. - + Mostrar nombres personalizados para todos los usuarios cuando esté marcado. Custom Shout! - + ¡Grito personalizado! @@ -1026,7 +1036,7 @@ To make one, your character's folder must contain custom.[webp/apng/gif/png Display the list of character folders you wish to mute. - + Muestra la lista de carpetas de caracteres que desea silenciar. @@ -1038,13 +1048,14 @@ To make one, your character's folder must contain custom.[webp/apng/gif/png Decrease the health bar. - + Disminuye la barra de salud. Change the text color of the spoken message. You can also select a part of your currently typed message and use the dropdown to change its color! - + Cambia el color del texto en el chat IC. +¡También puede seleccionar una parte de su mensaje escrito actualmente y usar el menú desplegable para cambiar su color! @@ -1054,145 +1065,145 @@ You can also select a part of your currently typed message and use the dropdown Become a spectator. You won't be able to interact with the in-character screen. - + Conviértete en espectador. No podrás interactuar con la pantalla del personaje. - + CLIENT - - - + + + has played a song - + You will now pair up with %1 if they also choose your character in return. - + You are no longer paired with anyone. Ya no estás emparejado con nadie. - + Are you sure you typed that well? The char ID could not be recognised. ¿Estás seguro de que lo escribiste bien? El ID de personaje no pudo ser reconocido. - + You have set your offset to Ha configurado su desplazamiento en - + Your offset must be between -100% and 100%! ¡Su desplazamiento debe estar entre -100% y 100%! - + That offset does not look like one. Ese desplazamiento no se parece a uno. - + You switched your music and area list. Cambiaste tu lista de música y área. - + You have forcefully enabled features that the server may not support. You may not be able to talk IC, or worse, because of this. Ha habilitado forzosamente funciones que el servidor puede no admitir. Es posible que no pueda hablar IC, o peor, debido a esto. - + Your pre-animations interrupt again. Sus pre-animaciones interrumpen de nuevo. - + Your pre-animations will not interrupt text. Sus pre-animaciones no interrumpirán el texto. - + Couldn't open chatlog.txt to write into. No se pudo abrir chatlog.txt para escribir. - + The IC chatlog has been saved. El chat IC se ha guardado. - + You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely the case file you're looking for can't be found in there. ¡No tienes una carpeta `base/cases /`! Ha sido creada para ti. Pero debido a que no existia la carpeta, tampoco habían casos guardados ahí. - + You need to give a filename to load (extension not needed)! Make sure that it is in the `base/cases/` folder, and that it is a correctly formatted ini. Cases you can load: %1 ¡Debe dar un nombre de archivo para cargar (no se necesita extensión)! Asegúrese de que esté en la carpeta `base/cases/` y de que tenga el formato correcto. Casos que puede cargar: %1 - + Case made by %1. Caso hecho por %1. - + Navigate to %1 for the CM doc. Navegue a %1 para el documento del CM. - - + + UNKNOWN - + Your case "%1" was loaded! Su caso "%1" fue cargado! - + Expand All Categories - + Collapse All Categories - + Contraer todas las categorías - + Fade Out Previous - + Fade In - + Synchronize - + Default - + Predeterminado You need to give a filename to load (extension not needed)! Make sure that it is in the `base/cases/` folder, and that it is a correctly formatted ini. @@ -1201,7 +1212,7 @@ Cases you can load: Casos que puede cargar: - + Too many arguments to load a case! You only need one filename, without extension. ¡Demasiados argumentos para cargar un caso! Solo necesita un nombre de archivo, sin extensión. @@ -1226,74 +1237,74 @@ Casos que puede cargar: " fue cargado! - + You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely that you somehow deleted it. ¡No tienes una carpeta `base/cases /`! Fue creada para ti. - + You need to give a filename to save (extension not needed) and the courtroom status! ¡Debe dar un nombre de archivo para guardar (no se necesita la extensión) y el estado de la sala del tribunal! - + Too many arguments to save a case! You only need a filename without extension and the courtroom status! why two exclamations, seems excesive. - ¡Demasiados argumentos para salvar un caso! Solo necesita un nombre de archivo sin extensión y el estado de la sala del tribunal. + ¡Demasiados argumentos para salvar un caso! Solo necesita un nombre de archivo sin extensión y el estado de la sala del tribunal. - + Succesfully saved, edit doc and cmdoc link on the ini! ¡Guardado con éxito, puede editar el doc y doc link en el archivo ini! - + Master - + Server OOC Message - Mensaje OOC + Mensaje OOC Too many arguments to save a case! You only need a filename without extension and the courtroom status. - ¡Demasiados argumentos para salvar un caso! Solo necesita un nombre de archivo sin extensión y el estado de la sala del tribunal. + ¡Demasiados argumentos para salvar un caso! Solo necesita un nombre de archivo sin extensión y el estado de la sala del tribunal. - + Reason: Razón: - + Call Moderator Llamar Moderador - - + + Error Error - + You must provide a reason. Debes proporcionar una razón. - + The message is too long. El mensaje es muy largo. Choose... - Elegir... + Elegir... @@ -1313,18 +1324,19 @@ Casos que puede cargar: Destroy this piece of evidence - + Destruye esta evidencia Choose.. - + Elegir.. Close the evidence display/editing overlay. You will be prompted if there's any unsaved changes. - + Cierra la superposición para visualizar/editar evidencia. +Se le preguntará si hay cambios no guardados. @@ -1339,7 +1351,7 @@ You will be prompted if there's any unsaved changes. Bring up the Evidence screen. - + Abre la ventana para evidencia. @@ -1411,17 +1423,17 @@ Description: Current evidence is global. Click to switch to private. - + La evidencia actual es global. Haga clic para cambiar a privado. Current evidence is private. Click to switch to global. - + La evidencia actual es privada. Haga clic para cambiar a global. "%1" has been transferred. - + "%1" ha sido transferido. @@ -1450,7 +1462,7 @@ Description: Search - Buscar + Buscar @@ -1472,12 +1484,12 @@ Did you download all resources correctly from tiny.cc/getao, including the large Settings - Ajustes + Ajustes Allows you to change various aspects of the client. - + Le permite cambiar varios aspectos del cliente. @@ -1490,31 +1502,31 @@ Did you download all resources correctly from tiny.cc/getao, including the large Cancelar - - <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>2.8 Major Release development:</b><br>Crystalwarrior, Iamgoofball<p><b>2.8 Quality Assurance:</b><br>WillDean, Captain N, Mr M, Riel, Seimmet, Fury McFlurry,CedricDewitt, Chewable Tablets, Fantos, Futugaze,Geck, Minx, Pandae, Sierra, CrazyJC, CaseyMayCazy,GreenBowers, Robotic Overlord, Veritas, Gin-Gi<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, the AO2 community, server hosts, game masters,case makers, content creators and players! - + + <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Crystalwarrior, Iamgoofball<p><b>Client development:</b><br>Cents02, in1tiate, raidensnake, windrammer<p><b>QA testing:</b><br>CaseyCazy, CedricDewitt, Chewable Tablets, CrazyJC, Fantos, Fury McFlurry, Geck, Gin-Gi, Jamania, Minx, Pandae, Robotic Overlord, Shadowlions (aka Shali), Sierra, SomeGuy, Veritas, Wiso<p><b>Special thanks:</b><br>CrazyJC and MaximumVolty (2.8 release); Remy, Hibiki, court-records.net (sprites); Qubrick (webAO); Rue (website); Draxirch (UI design); Lewdton and Argoneus (tsuserver); Fiercy, Noevain, Cronnicossy, and FanatSors (AO1); server hosts, game masters, case makers, content creators, and the whole AO2 community!<p>The Attorney Online networked visual novel project is copyright (c) 2016-2020 Attorney Online developers. Open-source licenses apply. All other assets are the property of their respective owners.<p>Running on Qt version %2 with the %3 audio engine.<p>Built on %4 + <h2>Attorney Online %1</h2>El simulador de drama legal<p><b>Código fuente:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Desarrollo mayor:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Crystalwarrior, Iamgoofball<p><b>Desarrollo del cliente:</b><br>Cents02, in1tiate, raidensnake, windrammer<p><b>Prueba de control de calidad:</b><br>CaseyCazy, CedricDewitt, Chewable Tablets, CrazyJC, Fantos, Fury McFlurry, Geck, Gin-Gi, Jamania, Minx, Pandae, Robotic Overlord, Shadowlions (aka Shali), Sierra, SomeGuy, Veritas, Wiso<p><b>Agradecimiento especial:</b><br>CrazyJC y MaximumVolty (versión 2.8); Remy, Hibiki, court-records.net (sprites); Qubrick (webAO); Rue (website); Draxirch (UI design); Lewdton and Argoneus (tsuserver); Fiercy, Noevain, Cronnicossy, y FanatSors (AO1); server hosts, game masters, case makers, creadores de contenido y toda la comunidad AO2.<p>El proyecto Attorney Online novela visual en red tiene copyright (c) 2016-2020 Attorney Online developers. Se aplican licencias de código abierto. Todos los demás activos son propiedad de sus respectivos dueños.<p>Usando Qt versión %2 con el motor de audio %3.<p>Compilado el %4 - + About - + Acerca de <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Cents02<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, Raidensnake - <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Cents02<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, Raidensnake + <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Cents02<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, Raidensnake <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy <h2>Attorney Online %1</h2>El simulador de drama legal<p><b>Código fuente:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https: //github.com/AttorneyOnline/AO2-Client</a><p><b>Desarrollo mayor:</b> <br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>Agradecimiento especial:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (diseño de interfaz de usuario), Draxirch (diseño de interfaz de usuario), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy - + Online: %1/%2 En línea: %1/%2 - + Offline Fuera de línea @@ -1531,7 +1543,7 @@ Did you download all resources correctly from tiny.cc/getao, including the large has played a song: - + ha comenzado a reproducir la canción: @@ -1549,7 +1561,7 @@ Did you download all resources correctly from tiny.cc/getao, including the large Notice - In spanish it would be "Aviso", but i believe it's going to be more useful for bug reports to not translate any debug string. + In spanish it would be "Aviso", but I believe it's going to be more useful for bug reports to not translate any debug strings. From 8639dc2f6116915b51d6a2adfe5111f81bd3612f Mon Sep 17 00:00:00 2001 From: likeawindrammer <31085911+likeawindrammer@users.noreply.github.com> Date: Tue, 14 Jul 2020 20:46:57 -0600 Subject: [PATCH 231/268] Finished updating the Spanish translation. --- resource/translations/ao_es.qm | Bin 28457 -> 47340 bytes resource/translations/ao_es.ts | 218 +++++++++++++++++---------------- 2 files changed, 114 insertions(+), 104 deletions(-) diff --git a/resource/translations/ao_es.qm b/resource/translations/ao_es.qm index 42ca3a006295aa12bbbe5ad28617f6dd55081d1f..0aefb4910a052fc74e3d4e340994f4754c81c58b 100644 GIT binary patch literal 47340 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 delta 5558 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 a>gjl~O - Keep current setting - - Mantener la configuración actual + - Mantener la configuración actual Allow Screenshake: - Permitir Screenshake: + Permitir screenshake: Allows screenshaking. Disable this if you have concerns or issues with photosensitivity and/or seizures. - Permite el movimiento de la pantalla (Advertencia esto podría inducir convulsiones debido a imágenes parpadeantes). + Permite el movimiento de la pantalla (Advertencia esto podría inducir convulsiones debido a imágenes parpadeantes). Allow Effects: - Permitir efectos: + Permitir efectos: Allows screen effects. Disable this if you have concerns or issues with photosensitivity and/or seizures. - Permite efectos de pantalla (Advertencia esto podría inducir convulsiones debido a imágenes parpadeantes). + Permite efectos de pantalla (Advertencia esto podría inducir convulsiones debido a imágenes parpadeantes). Network Frame Effects: - Efectos de marco de red: + Enviar efectos al servidor: Send screen-shaking, flashes and sounds as defined in the char.ini over the network. Only works for servers that support this functionality. - Envíe temblores de pantalla, destellos y sonidos como se define en char.ini a través de la red. Solo funciona para servidores que admiten esta funcionalidad. + Envíe temblores de pantalla, destellos y sonidos como se define en char.ini a través de la red. Solo funciona para servidores que admiten esta funcionalidad. Colors in IC Log: - Colores en el registro IC: + Colores en el registro IC: Use the markup colors in the server IC chatlog. - Permite colores en el chat IC del servidor. + Permite colores en el chat IC del servidor. Sticky Sounds: - Sonidos pegajosos: + Mantener sonidos: Turn this on to prevent the sound dropdown from clearing the sound after playing it. - Actívelo para evitar que el menú desplegable de sonido borre el sonido después de reproducirlo. + Actívelo para evitar que el menú desplegable de sonido borre el sonido después de reproducirlo. Sticky Effects: - Efectos pegajosos: + Mantener efectos: Turn this on to prevent the effects dropdown from clearing the effect after playing it. - Actívelo para evitar que el menú desplegable de efectos elimine el efecto después de reproducirlo. + Actívelo para evitar que el menú desplegable de efectos elimine el efecto después de reproducirlo. Sticky Preanims: - Preanims pegajosos: + Mantener preanims: Turn this on to prevent preanimation checkbox from clearing after playing the emote. - Actívelo para evitar que la casilla preanimation se desactive después de reproducir el emote. + Actívelo para evitar que la casilla preanimation se desactive después de reproducir el emote. Custom Chatboxes: - Chatboxes personalizados: + Chatboxes personalizados: Turn this on to allow characters to define their own custom chat box designs. - Actívelo para permitir que los personajes definan sus propios diseños de cuadros de chat personalizados. + Actívelo para permitir que los personajes definan sus propios diseños de cuadros de chat personalizados. Play a blip sound "once per every X symbols", where X is the blip rate. - Reproduzca un sonido de blip "una vez por cada X símbolos", donde X es la tasa de blip. + Reproduce un sonido de blip "una vez por cada X símbolos", donde X es la tasa de blip. If true, AO2 will stop the music for you when you or someone else does 'Objection!'. - Si es activado, AO2 detendrá la música por ti cuando tú u otra persona hagan '¡Objeción!'. + Si es activado, AO2 detendrá la música por ti cuando tú u otra persona hagan '¡Objeción!'. @@ -829,109 +829,114 @@ Razón: None - + Nada Additive - Aditivo + Aditivo To front - + Al frente To behind - + Al fondo Select a character you wish to pair with. - + Seleccione un personaje con el que desee emparejarse. Change the percentage offset of your character's position from the center of the screen. - Cambia el desplazamiento porcentual de la posición de tu personaje desde el centro de la pantalla. + Cambia el desplazamiento porcentual de la posición de tu personaje desde el centro de la pantalla. Change the order of appearance for your character. - Cambia el orden de aparición de tu personaje. + Cambia el orden de aparición de tu personaje. Display the list of characters to pair with. - + Muestra la lista de personajes para emparejar. Oops, you're muted! - + ¡Ups, estas silenciado! Set your character's emote to play on your next message. - + Configura el emote de tu personaje para usar en tu próximo mensaje. Set your character's supplementary background. - + Establece el fondo suplementario de tu personaje. Set an 'iniswap', or an alternative character folder to refer to from your current character. Edit by typing and pressing Enter, [X] to remove. This saves to your base/characters/<charname>/iniswaps.ini - + Establece un 'iniswap', o una carpeta de caracteres alternativa para consultar desde su personaje actual. +Edite escribiendo y presionando Enter, [X] para eliminar. Esto es guardado en base/characters/<charname>/iniswaps.ini Remove the currently selected iniswap from the list and return to the original character folder. - + Elimina el iniswap seleccionado actualmente de la lista y regresa a la carpeta de caracteres original. Set a sound effect to play on your next 'Preanim'. Leaving it on Default will use the emote-defined sound (if any). Edit by typing and pressing Enter, [X] to remove. This saves to your base/characters/<charname>/soundlist.ini - + Establece un efecto de sonido para jugar en su próximo 'Preanim'. Dejarlo en Predeterminado usará el sonido definido por emoticones (si hay). +Edite escribiendo y presionando Enter, [X] para eliminar. Esto es guardado en base/characters/<charname>/iniswaps.ini Choose an effect to play on your next spoken message. The effects are defined in your theme/effects/effects.ini. Your character can define custom effects by char.ini [Options] category, effects = 'miscname' where it referes to misc/<miscname>/effects.ini to read the effects. - + Elije un efecto para reproducir en su próximo mensaje hablado. +Los efectos se definen en theme/effects/effects.ini. Tu personaje puede definir efectos personalizados por +char.ini [Opciones] categoría, effects = 'miscname' donde se refiere a misc/<miscname>/effects.ini para leer los efectos. Hold It! - + ¡Un Momento! When this is turned on, your next in-character message will be a shout! - + Why the exclamation? + Cuando esto es activado, tu próximo mensaje del personaje será un grito. Objection! - + ¡Objeción! Take That! - + ¡Toma Eso! Toggle between server chat and global AO2 chat. - + Alternar entre el chat del servidor y el chat global. @@ -939,151 +944,153 @@ char.ini [Options] category, effects = 'miscname' where it referes to This will display the animation in the viewport as soon as it is pressed. - + Esto mostrará la animación en el viewport tan pronto como se presione. Guilty! - + ¡Culpable! Bring up the Character Select Screen and change your character. - Abre la pantalla de selección de personaje y cambia tu personaje. + Abre la pantalla de selección de personaje y cambia tu personaje. Refresh the theme and update all of the ui elements to match. - + Actualiza el tema y todos los elementos de la interfaz de usuario para que coincidan. Request the attention of the current server's moderator. - + Solicite la atención del moderador actual del servidor. Allows you to change various aspects of the client. - Le permite cambiar varios aspectos del cliente. + Le permite cambiar varios aspectos del cliente. An interface to help you announce a case (you have to be a CM first to be able to announce cases) - Una interfaz para ayudarlo a anunciar un caso (debe ser un CM para poder anunciar casos) + Una interfaz para ayudarlo a anunciar un caso (debe ser un CM para poder anunciar casos) Switch between Areas and Music lists - + Cambiar entre áreas y listas de música Play a single-shot animation as defined by the emote when checked. - + Reproduzca una animación de un solo disparo según lo definido por el emote cuando esté marcado. If preanim is checked, display the input text immediately as the animation plays concurrently. - + Si se marca preanim, muestre el texto de entrada inmediatamente mientras la animación se reproduce simultáneamente. Mirror your character's emotes when checked. - + Refleja los gestos de tu personaje cuando esté marcado. Add text to your last spoken message when checked. - Agregue texto a su último mensaje hablado cuando esté marcado. + Agregue texto a su último mensaje hablado cuando esté marcado. Do not listen to mod calls when checked, preventing them from playing sounds or focusing attention on the window. - + No escucha llamadas de moderación cuando esté marcado, evitando que reproduzcan sonidos o centrando la atención en la ventana. Lets you receive case alerts when enabled. (You can set your preferences in the Settings!) - + Le permite recibir alertas de casos cuando está habilitado. +(¡Puedes configurar tus preferencias en la Configuración!) Display customized shownames for all users when checked. - Mostrar nombres personalizados para todos los usuarios cuando esté marcado. + Mostrar nombres personalizados para todos los usuarios cuando esté marcado. Custom Shout! - ¡Grito personalizado! + ¡Grito personalizado! This will display the custom character-defined animation in the viewport as soon as it is pressed. To make one, your character's folder must contain custom.[webp/apng/gif/png] and custom.[wav/ogg/opus] sound effect - + Esto mostrará la animación de personaje personalizada definida en el viewport tan pronto como se presione. +Para hacer una, la carpeta de tu personaje debe contener efectos personalizados [webp/apng/gif/png]. y efectos [wav/ogg/opus] personalizados de sonido Play realization sound and animation in the viewport on the next spoken message when checked. - + Reproduzca sonido y animación de realización en la ventana gráfica en el siguiente mensaje hablado cuando esté marcado. Shake the screen on next spoken message when checked. - + Agite la pantalla en el siguiente mensaje hablado cuando esté marcado. Display the list of character folders you wish to mute. - Muestra la lista de carpetas de caracteres que desea silenciar. + Muestra la lista de carpetas de caracteres que desea silenciar. Increase the health bar. - + Aumenta la barra de salud. Decrease the health bar. - Disminuye la barra de salud. + Disminuye la barra de salud. Change the text color of the spoken message. You can also select a part of your currently typed message and use the dropdown to change its color! - Cambia el color del texto en el chat IC. + Cambia el color del texto en el chat IC. ¡También puede seleccionar una parte de su mensaje escrito actualmente y usar el menú desplegable para cambiar su color! Return back to the server list. - + Regresa a la lista de servidores. Become a spectator. You won't be able to interact with the in-character screen. - Conviértete en espectador. No podrás interactuar con la pantalla del personaje. + Conviértete en espectador. No podrás interactuar con la pantalla del personaje. CLIENT - + has played a song - + ha reproducido la canción You will now pair up with %1 if they also choose your character in return. - + Ahora se emparejará con %1 si también eligen a su personaje. @@ -1168,7 +1175,7 @@ Casos que puede cargar: %1 UNKNOWN - + @@ -1178,32 +1185,32 @@ Casos que puede cargar: %1 Expand All Categories - + Expandir todas las categorías Collapse All Categories - Contraer todas las categorías + Contraer todas las categorías Fade Out Previous - + Desvanecerse Anterior Fade In - + Fundirse Synchronize - + Sincronizar Default - Predeterminado + Predeterminado You need to give a filename to load (extension not needed)! Make sure that it is in the `base/cases/` folder, and that it is a correctly formatted ini. @@ -1309,81 +1316,81 @@ Casos que puede cargar: Present this piece of evidence to everyone on your next spoken message - + Presente esta evidencia a todos en su próximo mensaje hablado Save evidence to an .ini file. - + Guardar evidencia en un archivo .ini. Load evidence from an .ini file. - + Cargar evidencia de un archivo .ini. Destroy this piece of evidence - Destruye esta evidencia + Destruye esta evidencia Choose.. - Elegir.. + Elegir.. Close the evidence display/editing overlay. You will be prompted if there's any unsaved changes. - Cierra la superposición para visualizar/editar evidencia. + Cierra la superposición para visualizar/editar evidencia. Se le preguntará si hay cambios no guardados. Save any changes made to this piece of evidence and send them to server. - + Guardar los cambios realizados en esta evidencia y enviarlos al servidor. Double-click to edit. Press [X] to update your changes. - + Doble click para editar. Presione [X] para actualizar sus cambios. Bring up the Evidence screen. - Abre la ventana para evidencia. + Abre la ventana para evidencia. Switch evidence to private inventory. - + Cambiar la evidencia al inventario privado. Switch evidence to global inventory. - + Cambiar la evidencia al inventario global. Transfer evidence to private inventory. - + Transferir evidencia al inventario privado. Transfer evidence to global inventory. - + Transferir evidencia al inventario global. The piece of evidence you've been editing has changed. - + La evidencia que has estado editando ha cambiado. Do you wish to keep your changes? - + ¿Desea conservar sus cambios? @@ -1391,7 +1398,10 @@ Se le preguntará si hay cambios no guardados. Image: %2 Description: %3 - + Nombre: %1 +Imagen: %2 +Descripción: +%3 @@ -1403,7 +1413,7 @@ Description: Double-click to edit... - + Doble click para editar... @@ -1413,43 +1423,43 @@ Description: Evidence has been modified. - + La evidencia ha sido modificada. Do you want to save your changes? - + ¿Quieres guardar tus cambios? Current evidence is global. Click to switch to private. - La evidencia actual es global. Haga clic para cambiar a privado. + La evidencia actual es global. Haga clic para cambiar a privado. Current evidence is private. Click to switch to global. - La evidencia actual es privada. Haga clic para cambiar a global. + La evidencia actual es privada. Haga clic para cambiar a global. "%1" has been transferred. - "%1" ha sido transferido. + "%1" ha sido transferido. Save Inventory - + Guardar inventario Ini Files (*.ini) - + Archivos Ini (*.ini) Open Inventory - + Abrir el inventario @@ -1489,7 +1499,7 @@ Did you download all resources correctly from tiny.cc/getao, including the large Allows you to change various aspects of the client. - Le permite cambiar varios aspectos del cliente. + Le permite cambiar varios aspectos del cliente. @@ -1504,12 +1514,12 @@ Did you download all resources correctly from tiny.cc/getao, including the large <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Crystalwarrior, Iamgoofball<p><b>Client development:</b><br>Cents02, in1tiate, raidensnake, windrammer<p><b>QA testing:</b><br>CaseyCazy, CedricDewitt, Chewable Tablets, CrazyJC, Fantos, Fury McFlurry, Geck, Gin-Gi, Jamania, Minx, Pandae, Robotic Overlord, Shadowlions (aka Shali), Sierra, SomeGuy, Veritas, Wiso<p><b>Special thanks:</b><br>CrazyJC and MaximumVolty (2.8 release); Remy, Hibiki, court-records.net (sprites); Qubrick (webAO); Rue (website); Draxirch (UI design); Lewdton and Argoneus (tsuserver); Fiercy, Noevain, Cronnicossy, and FanatSors (AO1); server hosts, game masters, case makers, content creators, and the whole AO2 community!<p>The Attorney Online networked visual novel project is copyright (c) 2016-2020 Attorney Online developers. Open-source licenses apply. All other assets are the property of their respective owners.<p>Running on Qt version %2 with the %3 audio engine.<p>Built on %4 - <h2>Attorney Online %1</h2>El simulador de drama legal<p><b>Código fuente:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Desarrollo mayor:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Crystalwarrior, Iamgoofball<p><b>Desarrollo del cliente:</b><br>Cents02, in1tiate, raidensnake, windrammer<p><b>Prueba de control de calidad:</b><br>CaseyCazy, CedricDewitt, Chewable Tablets, CrazyJC, Fantos, Fury McFlurry, Geck, Gin-Gi, Jamania, Minx, Pandae, Robotic Overlord, Shadowlions (aka Shali), Sierra, SomeGuy, Veritas, Wiso<p><b>Agradecimiento especial:</b><br>CrazyJC y MaximumVolty (versión 2.8); Remy, Hibiki, court-records.net (sprites); Qubrick (webAO); Rue (website); Draxirch (UI design); Lewdton and Argoneus (tsuserver); Fiercy, Noevain, Cronnicossy, y FanatSors (AO1); server hosts, game masters, case makers, creadores de contenido y toda la comunidad AO2.<p>El proyecto Attorney Online novela visual en red tiene copyright (c) 2016-2020 Attorney Online developers. Se aplican licencias de código abierto. Todos los demás activos son propiedad de sus respectivos dueños.<p>Usando Qt versión %2 con el motor de audio %3.<p>Compilado el %4 + <h2>Attorney Online %1</h2>El simulador de drama legal<p><b>Código fuente:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Desarrollo mayor:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Crystalwarrior, Iamgoofball<p><b>Desarrollo del cliente:</b><br>Cents02, in1tiate, raidensnake, windrammer<p><b>Prueba de control de calidad:</b><br>CaseyCazy, CedricDewitt, Chewable Tablets, CrazyJC, Fantos, Fury McFlurry, Geck, Gin-Gi, Jamania, Minx, Pandae, Robotic Overlord, Shadowlions (aka Shali), Sierra, SomeGuy, Veritas, Wiso<p><b>Agradecimiento especial:</b><br>CrazyJC y MaximumVolty (versión 2.8); Remy, Hibiki, court-records.net (sprites); Qubrick (webAO); Rue (website); Draxirch (UI design); Lewdton and Argoneus (tsuserver); Fiercy, Noevain, Cronnicossy, y FanatSors (AO1); server hosts, game masters, case makers, creadores de contenido y toda la comunidad AO2.<p>El proyecto Attorney Online novela visual en red tiene copyright (c) 2016-2020 Attorney Online developers. Se aplican licencias de código abierto. Todos los demás activos son propiedad de sus respectivos dueños.<p>Usando Qt versión %2 con el motor de audio %3.<p>Compilado el %4 About - Acerca de + Acerca de <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Cents02<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, Raidensnake @@ -1538,12 +1548,12 @@ Did you download all resources correctly from tiny.cc/getao, including the large UNKNOWN - + has played a song: - ha comenzado a reproducir la canción: + ha comenzado a reproducir la canción: From 4be472f36006443b8f66491c44d8ced3f457706c Mon Sep 17 00:00:00 2001 From: likeawindrammer <31085911+likeawindrammer@users.noreply.github.com> Date: Wed, 15 Jul 2020 18:16:21 -0600 Subject: [PATCH 232/268] Update Portuguese translation. (Needs review) --- resource/translations/ao_pt.qm | Bin 28605 -> 47036 bytes resource/translations/ao_pt.ts | 532 +++++++++++++++++---------------- 2 files changed, 277 insertions(+), 255 deletions(-) diff --git a/resource/translations/ao_pt.qm b/resource/translations/ao_pt.qm index 242917fff1b18c2741f31d02bb2cd94f27fafc23..6e4437927db4439cebeca5a2bd4c1b043b8a412f 100644 GIT binary patch literal 47036 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 From 6dde524a160f445e47edb5c6befb78bfc1092a61 Mon Sep 17 00:00:00 2001 From: oldmud0 Date: Sun, 31 May 2020 17:07:35 -0500 Subject: [PATCH 203/268] Lobby: Change "font_*" config entry to "*_font" --- src/lobby.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/lobby.cpp b/src/lobby.cpp index 9804855..33fe7a8 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -239,20 +239,18 @@ 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("font_" + p_identifier, design_file); + ao_app->get_font_name(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) { - widget->setFont(font); - QColor f_color = ao_app->get_color(p_identifier + "_color", design_file); bool bold = ao_app->get_font_size(p_identifier + "_bold", design_file) == 1; // is the font bold or not? + font.setBold(bold); + widget->setFont(font); + QColor f_color = ao_app->get_color(p_identifier + "_color", design_file); bool center = ao_app->get_font_size(p_identifier + "_center", design_file) == 1; // should it be centered? - QString is_bold = ""; - if (bold) - is_bold = "bold"; QString is_center = ""; if (center) is_center = "qproperty-alignment: AlignCenter;"; @@ -260,8 +258,7 @@ void Lobby::set_font(QWidget *widget, QString p_identifier) class_name + " { background-color: rgba(0, 0, 0, 0);\n" + "color: rgba(" + QString::number(f_color.red()) + ", " + QString::number(f_color.green()) + ", " + - QString::number(f_color.blue()) + ", 255);\n" + is_center + "\n" + - "font: " + is_bold + "; }"; + QString::number(f_color.blue()) + ", 255);\n" + is_center + "}"; widget->setStyleSheet(style_sheet_string); } return; From 8e106c5d21c57cfeb717408321eb579683e5095a Mon Sep 17 00:00:00 2001 From: oldmud0 Date: Sun, 31 May 2020 17:08:01 -0500 Subject: [PATCH 204/268] Fix server list showing in reverse order --- src/lobby.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lobby.cpp b/src/lobby.cpp index 33fe7a8..d6900c6 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -483,6 +483,7 @@ void Lobby::list_servers() i++; } ui_server_list->setSortingEnabled(true); + ui_server_list->sortItems(0, Qt::SortOrder::AscendingOrder); } void Lobby::list_favorites() From ab00005bf7d4ffde047f30bad622de35e7485c51 Mon Sep 17 00:00:00 2001 From: oldmud0 Date: Sun, 31 May 2020 21:20:59 -0500 Subject: [PATCH 205/268] Update themes submodule --- .gitignore | 1 - base/themes | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 212daec..eb0b979 100644 --- a/.gitignore +++ b/.gitignore @@ -9,7 +9,6 @@ base_override.h .DS_Store base-full/ -base/ logs/ bass.lib diff --git a/base/themes b/base/themes index 620915d..49cc126 160000 --- a/base/themes +++ b/base/themes @@ -1 +1 @@ -Subproject commit 620915d85afdeb51bb3bd7766d5807bbdc6fa876 +Subproject commit 49cc1265f55e2939248bc1eeb6be93a8a03b9853 From 012a03e961f91d560ceb5146b2fcfea0c73ca569 Mon Sep 17 00:00:00 2001 From: oldmud0 Date: Sun, 31 May 2020 21:22:54 -0500 Subject: [PATCH 206/268] Warn/error on incorrect compile settings for audio --- Attorney_Online.pro | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Attorney_Online.pro b/Attorney_Online.pro index 2a47afd..d49676e 100644 --- a/Attorney_Online.pro +++ b/Attorney_Online.pro @@ -39,6 +39,15 @@ contains(DEFINES, QTAUDIO) { QT += multimedia } +AUDIO_DEFINES = $$find(DEFINES, BASSAUDIO) $$find(DEFINES, QTAUDIO) +count(AUDIO_DEFINES, 0) { + warning("No audio system selected. Your build will not have audio.") +} + +count(AUDIO_DEFINES, 2) { + error("More than one audio system selected.") +} + macx:LIBS += -framework CoreFoundation -framework Foundation -framework CoreServices From 032e53d1570f9accee6dc8b7877efc0d4108f55a Mon Sep 17 00:00:00 2001 From: oldmud0 Date: Sun, 31 May 2020 21:54:35 -0500 Subject: [PATCH 207/268] Fix SFX playing at 1/100th of its intended volume --- src/aosfxplayer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aosfxplayer.cpp b/src/aosfxplayer.cpp index 0fdba1b..127bda6 100644 --- a/src/aosfxplayer.cpp +++ b/src/aosfxplayer.cpp @@ -66,7 +66,7 @@ void AOSfxPlayer::play(QString p_sfx, QString p_char, QString shout, FALSE, f_path.utf16(), 0, 0, BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE); - set_volume(m_volume); + set_volume_internal(m_volume); if (ao_app->get_audio_output_device() != "default") BASS_ChannelSetDevice(m_stream_list[m_channel], BASS_GetDevice()); From e0fb90984ce9b1c0430b1add185cc1d91f06792a Mon Sep 17 00:00:00 2001 From: oldmud0 Date: Sat, 6 Jun 2020 23:20:32 -0500 Subject: [PATCH 208/268] Update about dialog - Credited FanatSors - Added Qt version, audio engine, and build date --- src/lobby.cpp | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/src/lobby.cpp b/src/lobby.cpp index d6900c6..cc9c44d 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -353,6 +353,14 @@ void Lobby::on_connect_released() void Lobby::on_about_clicked() { +#ifdef BASSAUDIO + const QString audio = "BASS"; +#elif defined(QTAUDIO) + const QString audio = "Qt Multimedia"; +#else + const QString audio = "null"; +#endif + QString msg = tr("

  • ){k91A=j}Iy-)+AkNd8XyZSS}C8`j@yze)Wa?KfsPBx0k# zqx}{>aNm9#mHgZ7H{!o;zpcXkZu^b+&)aWj|E~Q;@&Dd_yMz0;_S=-?e}4Nd;79w- z^l!G`!X%5-%>VKB+gDi7kMTg-D_PdzgycugYtL7H2E)KD*g+m z{~$~Y{)=Ji^9!cGVCpEGKUd+YSZh$fTH`%=_VmS0gRe4Y_Uuv1(`o1K?GGIRs`anm z-}XG8eg6dp2?`E@hK7YlL`Fr&#Ky%ZBqk-Nq^6~3WM*aO)*k2=67JqgZ*#YvY2Ch z{}GrH{($MM^cwO#Odb9brkFor>H_@Q?Miw zk>1|{Q{ta6{r@=2K=juzJ^Fo^68$+$IpF^KECc2LJ500wc$Q)6zu+tb{STPR{7sk= z-NRJ&ABSnqAI>tcBK!%aX#Yf*68|1d`TizM?F!ULe}k#Ye>T^1p{E-oG+Tk!}APrU-vGOtb$Irg*<#`VYdi;=dTC>Azt53#R{~ zFvWsDJ;NG5IXitnj&pf+0gwCBrSM1Jx|!zm`n++lkiV|f&r0|q!N~wf)XgM9$H*b8 z9gU{a;@F#3h#feYVtzE_h7y8d^Wg?wls!F>HRh5H*~t$ZNMbe5SEAtfX%So#10z)b!JU?AzuX7|Yho zz#)#(;3drjWEmqakK3-*zFW>%TL+*n^xd@Zc9&z3^CGhwalPB27bDiuH}aGj9@&Tg zFii&14`oeO>ZM30cuvWwD?O$^5xLh%g7{ePI;e5?z$nv`BX}p?ni9z%4|g-IqRf9O6S+f zePm8Es%c)I(PAO;g}`SmWaO4HK?;S`qtFkdDa6tXZsJj?upB8Gxx~ddv5l0S)f%JB zaIc4kP-|5gKOGV$1ugqRUVwzPP%uQZ}_nRPzX3N?vmBDf#r6=Lc>rxPIVT zR4VgsBmn|;k6z+@2t%9Yt}6#83Tt@$S(=6!v20n@Qy~rccnD#k<&l0Xylf)mO>32L z3J?wTtfZ!mB(s?mRD}(C$|6$Gj-wE9qEYsyOtsVYWh%_NthWk{^BKoLL~ZxfR6BMZ z{cx3P_iOkOm&_*pXv3=aE0t=w{fq(n zx3SjGtjhDPkv~Qihr@IIANKCTtqMh38~vPgcXx+`bc1wvw{(|us7$)MQ@Xobx?55} zxop#pBR=!Ea)D8d* z3>~IeY}Z&aOo*9^SF%!wc~)n{;P*SfiG8mYD>;!gS~7)u#+Kt`uR|V*R5^hos#IsNw(Ppf3HNN~n^^KK8} zSXe$voU}|XgRK?C;60N`?}U%gkyzpW!`Im`>_`1Z_~I#(`NELymyVA9vHb0ZF9!K{ zlfd}=`&s@!D~>DQzg1%!avr^I7`RG(P@6@sdfeGX5BZ7XHt_gx2-6>b27E`!UTvO#tZ97sqdwqWzWXYUqPZ2$izj7 zzn;nt2doOgNJc=(u|mDWwA6BPOMlIVFWP5O{8omm;2TQNpkkeMSgPA5R{bkBt8h8L z6&vz<00Q&L5R5hd?u@{LHpH5!Qm4Xo|k!nVz}c!E3OS51Rs!{v{NV z5YLFb*Sk01{jl|tDnD<#U0C&oiMc7F%6=qG?BjrlBAcpPrpvjr8FCD_17$Fu>25CN27IQGpCph8s zX#^aUHQ3op;_@s%ilW&b?C9@MX*Ry%T41@EOs%<0A0D}_j#ODN_e;*?M?RS=OrX`W zWQm$@Y_rUr3M}ETX6OKVv`FQi6Kl?OsD|9|G(;=l+xt(%=H{V=N@Q6}_F5Di&&tx`99yQB46sJ(7)qfy_O4qD?LFZ;(g8Jta>HLofxoolXhK3Yk{iHWs#m8Xn@ z-XkgY;JP&`&<69JdoMQj;#9mS#85!WUT%2pP%|%FYUspNXyFFD?_p@czOU$AZ)^YJ&|I@xwhiTH#tT}4;+WX9VD`mxw@zG1ERj&bDbOp<*~W%# z-!o@qk(d1J!5bZBvYBR|X7^%|){0!eX{Z_ECx=CCa=qtmF}`KtY(#m^`_)5&ZU~>{ zIo`%Vd^09B+{U|o;#moPeTi*;%ryH+6>2vdo96v=D=^1LHase-dE4PnnJEJTFKeW! zLmeDxCM0vh2UjU}zFUTER@zF1dA~J2Gm?SPBZ|G8iy5Vhu8%Mhd%b}%Z|typQSt1T$^Jywg{)eh<48 z=7eSbk@8b=_mtc{bshgWeEJ`{j!((mQ`hl-?H$!q*AcRW z^VD^G>N@_q^#9a#{PWWPQ`hmob?N`9>j+uGdFnboE#drmk^euy^r`Fk1k?Y&!W0&G zc8)Rzb$*UG3HRj;>huihkD2nXu46990uhSn&#ogHr0b~oyX!~>={jZrU?{}?Iu}I$ zvFnKVyX*Kl;CI)NSoBxdkpR+lWcz(||5w*BHxTOA5>9t70Md0tEz|xlx{mO_x{g(# z|JD-D(+jGn7gSF#sQ#y3P(5vjKW&FY9!NdG^q<4@X*>K0rvH0j3iTJ-4sZIu?Ki67 zB!NsNV6djkR=36!7@xFZpvnV$nK%pi26Y>qvF`%;2E~f9RVQfvH<+?W3=@k2_tyR% zrqjP+nwE9Xljj=%+?z|S)V>sIZ`2$4FMp$sSy1=*6K;Nc$grp*Ud@je5__XffyrilLW8x^*p5oEL67YLqwO`Rc~%Z>qOf)6@Zl{VG>Se$O^ zGFGi?8vXnti8PQf7xEjG{Ey$Lush1lq`KySc+z9tfB%hI1UX~BUzl*7{Ks!p<3E3+ zKJxzg8l|-s3{9a*F;;ORt`pJC?8F>Gr~oMV?K47OOv3Qt8Dwtiza! zS|7S##6;Lj$ziTvIaN}z)QsPBXcU1`uKt#{rY*6W9()W%86dfx)`@Qgr7PfL;2u3T<8u}%8Wqrcs4ip!AgA@8Gm;SGIrY9s%AbrmgaU5uF#8V|or zE5cXarXK1(0j~JHBHn2ItHY8}6dgNXew9L*$W-IdtM)^-lxJ&xC}UDnhRf_!OI6PW z%UO+R`Z=g2n_?zkYnoJu#kH=E18r!lyPWzyCI;Lv6UEQ(v4PwmA5rUgX4iAecgK@c za<-OhtXk11GGdLD>=q5G_svKAWffJUwP&Q8+KoO<4Ql z-P;)LD0-cJ{N+l%f6ycI?Xk}1{Ww-aO&Lk$5|>Zs5uZ)EDswjXl&YS^0+G0Vu%=T}`kfWQbzpSNaly0zS$1 zxWFIP60!6tdZ2me1=VYQM6qv)Mrw2|r{-V6LVWdlOEDctxm#=*H_WyFvW!o9x=s!I z%|tN_ww#QMOR;~+i2@gNIi5sfQWl+<(jk-w`AOB+H+E-qe0K}ITeAvryIj^U#z)~D zxt@hD9&Ph)2V~iyAmtw9(V$b7qso8!Kn%Nh$ofGq=01;w2t~BlkIV}7`%Rcp0Vcp9 zxPh3W1sQm)s@iE7M1fZz9SjCcjpU&KX5yNd7zwKtWK|+T*dj+oQ3^7m38jO}xC;D_ z4XR8!{QyjU28!bR_)O1(cNkU(#p4$6uHkggiekbu)}di|Xka1VgHhQ-`71-&0{eh- zSSk!r%Svr@L@LHg9ggohmWehEh6R)y~fLU=;80B~VR zfac7~YKlSHvqUkDHrxW!zNo$T%zmqM-2-(}*xPqaK4i+2DAYx?#5WgsE$@}N>VE!M ziXHdj$zCmflZZ;1O%ObhWrAnwnLwOHpg{qdqT0p@-;8FnWx&ur?k$nEaa*J!Q#><@HMD~0X;wCZT z^hBDqMQ#1z^7*k}~>PlS=hc=)$0FSgkIzvZask-POTB{`~@hL-)FZe~nhb zw{E78jnVUy9)h(=v&#@=D|jJWxtTLjTsJ~$y`Vr6v2fH#W@yEYx2XB-ND91dXR!amj!SyIrt2a~YA^Q&1Y~0udi^!jbq}xyIm`mA})*66tMv z6_0~Pt>@cqwI!G^qtBtitb$JSXDJ4gC-j><8#JF#NEio=3kbhC)Kh=7Vnax!g(mrM zCX1GRB-UUSq1okofdu;c_?*XhSR4VgifmYGVO_lq3Et< z9TQGC!C%pKJ)46(x{w5C>MT@KgwP+urQD1`O<4xB+Am^cmO{0-4gY(^b^>-jE- z6a##w^$^JRf@2P>_+`TFaY<;G|4YRARW`xTJ{)&G3DPNe5b(}!)e97RDUHO3XtMx9 zO9x@_1;qTz&lW*mK{-HPK|y|_{#iEtD+#sb|2Cm2p8lIq&s+qnp?)MSLR*Vf}ys&=>H9Y``V zG*9VoENqh&Cb$R(ib0p=G1nf64&Qcx72#7&+VvRD_liTkUlf+sO4(LBtPVGYTJPo} z1DV3LVkrUEWp>{1`efw0i*H|#8$Q?)0>U4nM{|Q<5llcpNuFS@s_j*kBs90)tWw*N__=8oCfbB8YpXg$SC4H>aV-; z{gI&R>9J#^^3!gwErq6hyF%@zK6%T~D>b|QvMNfC3XKXTD246U762W|ZD~N}e$F;I&y4*FHH*CVP z%ju2QjPKN)wWg?6(17SPM$e?@Y-VZ%bux3SB$p1~JTwjGwE9tuQzxm5O%gny$G{WK z-ot2pml2KDZ^BN?#0?J-BGgwLNQAZik%!!cNX9ijOYe!W%cEY}XHWX!7_q1pkroye zK@pSog3HukKOPupH*(hf*pE83`7S@MY|qGPtbFkOGd<4$sjy`S$)h}*QZ!G`JsLvS zl`;IHT0H0O28s@IR3w}E0lAMxH>G(kclR=VAuAUf7`ayMCoZ|Y(bkKysvD`}k3kg6 zsb_<7Z{dpw!93Dk&h^l)!xZyiD;TlmoDnCMKocM?ErqwcYCx^oFmQdpowH#k1^=RUm{oFjy6Odpf@U3)=GN!t*sT~y=@pA23rfpl0pHNFK&A<6^-E>8n(j4cTY9vEvR zdj)(&uJ8Vmc-B>haZfGIVauF6|59ciwjnmiFi^&6bW~b8^tmMiyfqo(s3g@kmzup{ z?64@BB;r_nst~dv$5``LNC1g`#TuPN`Dk^*yg|uB|9d{`obLgNDX#7xnQWWn*$fr! zUP|Dy8W8pwvCcB9M?`82%Vt&ZmwDUj6%w2CPidLG%E(+vU?*otx5*4*`p%^Fa-mJS z8K;5EAwbrX?_22))v%mMYzyx0e0mHx_%I!sLw;BZ0uSvVwHH-z=&$CZ1H^-5uewm2 zq^Ut5DoGB_;3E+~TP%l3ddFE40MsYy?7gxp^OT5uQxods4X$J(guJl8m3<-@%ZUi^ zOGF!ya0^iI+h8NPIU6GZHx17WHXwr(Xa^90s?Ck+qhlZ{j=NZkgyFg-ELMw{ zA7Kq9-0Vq|Al~C+)=bA)n+M4(*hwM2PNeJfq^}W)HRF4@${$;i8-kT_X6ZW=W`5tf?~&?Hj1H>GJ@?(6nktb3h12EDWXw zaUhO(Qeru$;dlt%e;VVu4i#mpkLAv{Q;W@jpl>+9GR?6MF#Sl3?i%3TMloN&in(`#}fQs25f zRaH4+mTzpsRTP7RlUA%|l)DE%VH8S~5WI|`VHIY@@Ks)6V5r(6BW?yfXmzyqWqv`N z$jEdi)CS%kKY$SO^7Pw>6OxoRjR<0N(UouD5P+hwI#R>tW0nP;+x#Me@*Q zqaR)`u>?hI7@Q-vk=U_VhCYV$!FPUsx1x1<~ z`z4<&vldo@W{OS;8mlbf*HP-xCnGP; zHs7P(&ae~F1#t|}AWG{Hb6b)^%OdV3gOV`bqO5?K%+|qH??^4Gp%CD_BqPltojBY<2WrsT{1A-f}VPi|8(Jbal{@HN;nK(cg zXOMN7g24c+{17SnRg4Cj;hOqPeq8!=o-n&%A{bGY5ef$$!J)3gcC_;&6i!9iTdkuM zCR0E-pEtU%5`vP@kD0sM6q1h=Bc}P|MJuUrT?N|I>KI%M{|u@3|Bh5R)C3O1Uq~Iw zgaR!K_y1F*a{YnS5QK?+_rFIflT++5LHuI6fsOvh83{2ySCF7Jy${QBw9`^C(N#eF3Z7aO~Ok{GAU%`KAlbRpgz z?-B@fy5=z6!S4f0hRo`+IIO}nA6txqT%__1P2;lewoS=PB|tcg=7!`#O<|9-xd;xq zv8}6U^OJ|e_%H{?59ZaFV;_tVg^DRXD?2!*my*Yfs>Jze#dm3RCV*n2lgTjr7rLRc z->9(k00ib>hTul;~|3 zKx>!ebj_1z+bU`4ptogxUDfmNgiHMqKV(E9keQ}!dz$jbodh}7t@^aHw*g_xvDE7J zC)p9*Wj&lVI9Hi=N3<@D;Wg4t*VX%6bcf+%@wYC) z{@RQW)2cwUEeKMb{y-`W1gX)3HQMv)s}Q8lX8cB~K=q-7p-?Kr^Sg|^(y?Ditx&Al z5gl|WuJ4p0op$F4ZvyxKMrsf*{W*T~C!0TzO2cC9nOC7ZJgBPPmE4l$+{`g^5qev3 ze$nrwe!Tg~J1ar@l_!n$)S$=>pzsY>B{jNxJ(}d2+*^6)T4oVE9A(ZLVKQIQq?6Rr z2V1EZ-CGRPl?Te2TR01D3N@XgNUaA(p=kAKeHdZneMc?Cu-}p=lFrFYv*aZ`DhSI@z<{E6aIH(Y(4$>gX=n(T*lETU&?lpmu*xsVu zf%Y*1l2F=SdF`9^%rz%_mfkfoca`|K830O!Y~yRP2Z53?9_XNZg1|5qo@LT zAtX$#7mE*i{hz{Ak&riP$fD|0i2pfEHHZ}-g8?RT0OCmo{xM7)*9filIoHcmcZmp& zK2Id&Q{QFT;8TPXsWvs6&?k1|R}?tGj8a}5jE%h)?JFu~{_WI)$@#M4_yb9rzd1Eq zVB-F7PPLV8`8TJAC;c<0t}2N9y;EiW*PS~0UpZAEMmz0Kr&@#pRzlN<>$oKd>bHbW ztV@&nPU(@3Uhga~2FW9OxUjCO({WDDc<cNdEO3R8!k#rf4=1c(0)Q%PY28>th_&TKQ7 zdIQ)_IsiTAu<#C|=T3MGzrs`-jpn`jUtwwld#A0*1y7sR65?UVbA(TpC58S2jMQE* z++{za_u6)2LhpoDOz_Ov#KtHRH6N{ZJ-ut>`y}(T?ygM9!G!~B!msGwHF1Pv5{&Lf~t_(^Pykj z(z5w{4jyO}yi#Nsg49J=dRkIkNP0B3=PLf$V@1ig^#ghb8Z*Vm<{>NLIKU5mIR(e( zg*H3n_A%k*U#4bd2-(f~sqrdy5l^qZg_|yl8g{j;TIN?`^cDS|kMH_&AQ5kat@Jzn zcGXU&(t)hi-{tfN%bukUu_xm^FOD&vO<$kwRC7eD#aegZWe%#F<{lGYIWl7Ul&K^s z2Di3x`A#x-SVq~kNgMlf#rNjM50U37vjbvZIO+!}t!I8}Nxw4Y_9}oX&CAhooq^J9 z$ zKGgK>Ik{bIJaYOK%{z0<@dgzKaqtfxNIZ=8)7-x%H`>~Q?r!-rK5gq!`QA%j@|fC@ zuhvOF&*F6XJN$EO(orlSLX~PohX@r25vn^VsrL<18|cR}2+ij0Uu)d&_ZJju|C3Ok zg!&}ZC!zieg*t}<5h}^=aX&<;e~$Zq3Dx~CAyjgz!9SDKY=QE!KgRvc^a4M`2*OSN zVch@aKaBg^mH#)7``cY<|M|GTbnN7RVBD|94WA&O^bD5lvIAcCxd%-rC|ddjJCY-o z0r4`bwc6na9lDfOVcNcG4AXW)R`#sbRMKP8WYjGcm!T=R3v^S0SEqK;axE`IUFw2` zhl4o=hUpk7{$bqjz`|i$iSf52HGd}Xe>h3S6b+--j>Lj;ix`)-=^QEZ`kkbj>F&RJ zzLbN(j;)Vi-sxsy?Mb5^#eMDy%lA7;ZRySfp{5)Ck)*;oR-_93PEy&ec#*q|;Fc!^ zwwo?t-*-;BUpw@q{4V<41_tk|?$N1M@NOlNS%ej&8J>+ho5NjJTh zqzzXOd_fp6HF3pL*(Csl$TN60dzv%+jK!pyKA?mvI7drIdNq}!JyMCGRMIAUuVF+9 zAtNJ^g5CnYKao&vm?P9I+5kg_jUqFDl8F%&zctZPLfhQEhuHMUe_tlo)T~b$iq=SRl&g#7{x;p!rq6Wi9FRnkn0^|2Hi*Yq z!ow-J$A4sYsw-<4K+%3qSm^%4ZRLjuv**bCdqGBsP$lj<$zPWSJg;<&6+t+n8Z6nP z^_`9DfSz40X3OJl+relL7PTzU(!P$24`8=hx zRy}KMevvn$BT3NkUic?eJ7@2dO(#E7!eoycsnngg3;nAF2P!1iyNfU|%@-cXG0=C- znLauxwOKJs_O-!eXo)%zm}u?3JlUOFL3!=ar4+e3>N8La@|cokC9(795TTArwHkq% zKl5)(lM}3|XL=!oejPph;!O2@OcAcC=~gLuQ$B{FEkalzojx5P-!O5cwA=q=No}JROt-jEs(rijPkLCa32n zh9c+3sFo&H=NA^&Hn-+BBDVJrmUiEc!UE4PP{yGyE)b{SzMexa#UpJWzd5~x1*JJ` z3IWHl5V-O#DcbyB$CF~nVq`!CARr?NQ8*iO01?DPg{F;2_}_NQ3-yIl!2&vdRinv9=ne)5$IaAr4lm7Rb8KgyFb0XM7M6 zDSHpUuGdp|&k3>2tdcOLk25>ddAJmzt;%KqYhh;sy)g7q>3^xqgdjHy& zO4&9r;St+RoWrtkpyS)#e?Q0LRuXb{*=dg0z>0>@_-m1$MPmBj_obBB!~)WQcx=-T zevn1}cmK98HUE2Gir;p@#ddSO^N~R04Kr*g>?hVU;No2<6BFpIt6s#pY0o#(cUG%< zVZ5mkmLowZPpdWgBr`rQyLz^68BmPwRwHO60HCFL@i?SEj(aR z#Sf|I)`(*d)yq1TO8E%VMkPYRD|fTi*>Mgg!dQxXq}4ukbL)UQRXX2x--T+*_ubWQ z+8^JD_^jqzEKx-pg0BE)lOCPE=u~K1;dyoA;G=y2UtM|5i~vg9`Gf=6m!b-x$(u_Ss~t@R*_V>|;j380>d9}n8Qv|VT0~yjR0~DY?Fc@OYe8(AJ3~1#zEa07 z6ya%^?rP6C?EzOtd)}n;Q;1JD;%F?}9CTK9TSna9%#)$=ulAQo%W(!>)kupZ@vRDO z-7+=W-E_?D(KeRJe&*#_mG*g&*Ra6E@-rH_LMmpjC|Xu5*0792Ll*{?U+fAUq?9$c zBB{+9;drVfV<+8L08IWtx@AQ0dS-GQFU{L>f>2cA!)+T@t&g6I!A*yfMKtV6S6O*IkC=#$f6ubZJvrk zi*-^mCL0Sh$x(=XP%j^+3J*yh29gnIe(AosQ%P%X+8>t9pys?#OIABWajZJXtEX(# z8N;#S>by%CNAWfnoIeSf)s7bMMr|VIxKmSFP#Ie`KBys8aFg4W@|-bo=x(( zaAZ=p^e}%q8Rv1g|YdChI`O50+yufy6Q{lr~gg z-LHKqCgC`^61`81mRJ39%aXfe!2L2NSiZ^zm}2&PRqm<~RU^R`bs1pt3}0IQ%cu)+ zF(TkTLlb`$lp!w(F|93MjbHKv>xg!`6jxmqtUU>f-|8$8B3anfOL)D|DMM~NeLL>W zrfAO&44@mvd!$*e*AYB98$-rPsHAYX*NaG2+IC*-8rcYZ6tG9kIs}sm!8@Me_OU85 zZ$l!~a~Fixp0x;No8t%qrLexl2mjia0%Zi73%-4`tPs_JDEfz&8 zWxJcYEdW=zbybK(s}_+_1b?dBxS+&R^!#&5W$`sW0Gkr8_r8)?j6ljr;!^$n@Sw>{ z!8I)QVrJqA&1o;);@ro z&}!-FscT66ZKR5iYtb7(vJgaVVS+RGFfl@ezLsjv5l1%rAZ&IN!TSNjj(U&ss^~kK zS|L~qIU~-aI>7E{Q5YBp57MpBGt)z|(}))3AsO+W)>>HGFpj|fw7l{8 z_X``T7%EQiR`Fuv_zIHMmJu^EVB;Z1t`DONl2kcqas7Kde#nar8?|8{q>_~AiRg~k z7au=mPXK#9PVz;d&s=xb)h(1Ve}+=K`^2^L6V9SRvl8|yux zoAIt8gEvRMXBOPMn$sA1C3wI+&iCvSAnfeDrh@mMEcSGrs~b~3pK)`)(iVK|ty~L# zd{6L755t(w!8%sSG(K8cZlQ9_Ycl7!0Rf3JzfvtLQgEdrmvBiW^(I%YD}zryyc>N0 z@w3x+a;*3AV^F0Yf+9hEzGqRoC%DhwS94Q&_25g)T77%>9D79mC7-X&*Ds!`t6v#; zi6yzk1Po#JqoZV~rB3k#;(STL+MwdwXHsZ!Dg`o$ddftLh}WN6^^1~ui>J&9xkNJzA-k}y-) zc}^<*cvVEa=yxFAx`k2nHE6fR38|Lac&TXauDLFsBHyMp%7fR-;qw`}>6%s_s!tN# zacRsfJux9@9*O|Xg@I*fi(>p?o@VpzCl~Sw-K2NNdyN}gp!L_*+7Wr=>hI}zBDcrh zu~%;3hh;w3s6@N(AFQu37PAXUr{aEIW7EaVi)M@m5=JO~l_**2^G^gwL-B$3bwF_5 z(g-X5JFOtdlpo_aPyh9A-qi^Hc=P^OT9X=7_&*S)Gz~5P6sA8zld(zC@fu=vfYFu_ zUkS{-3}9ua!%;S&8WF#zMyGAM6|5`QRf^A_*f?>4@U1w^Yn#~Ie97_bU zg`;Mf1VTNBX119myc2?jH~@rA+Ge zhho|K5RB2%C~Dh4BLOCti%apE3<9px<_V^$l`VQQSTSU~KGQ}hjCznwHwmT7#f=Jk zd;_~}ME=Es7{DveKp3M>DPa~mNQgiwrkr@F7q%%TO{059Vwn;un?GU}is%lH?E{Qt z`~_3c%ZR(}>*CN4zhLTq(`pHzyp=HXL;np^oMVza(04vfVFD{eQ79?6+4OXT4O`-Z z>*CgU&+BHHeReP@K=Z{VV_v5BShmc14u7m}z6xckO_?CjRY1p!4oapBXi7-H1l20S zTgp`208bvswwQVnW3Y&4pF%XQbDUDtl8R%@OsJ~QVW!_XRT61AhTl|oo37YYEAVmB z@UY?6B0p6KWQYcVX>T*2sbb5cq_4mt6gUil=}S9lGrel#wTe>N0^(v92ux`rQF$9T z`+e{2YvkD$k1<-HwwWM{{1R=81NXER^-$jlhjD|`%I%6ce2Ni4mJpaWHeGW?7FnNI zGHm)WtCYL8Z+R#fSJY;vTXWJ-IdUm+(r4EPVSG9x7_0dye>kqb!|asyr3W@u_>BMS zrW%wUDH^nZ41(L5xU-#AtXj*N`kc|eu1frrkij-@=M@B|%48UP&L4%la6MgcA!`ex53BDuJOMGIvJ zz1N)e=OByx>6|^g$IQPL`KMmXt)BK49w~a=q~AAOGY?6=`gnh$U~)O)&yp-7KA+vn zY1Axa*B_G;N27cjnfVheGU1j2ESySZEXmwZv+R%(PS^1HvdDju*?T0h5;#0C`3-A^0{tMME7>nTaKOg@01p?1N^z%f;UKX4(_-wQ_Tp*a<`}X1PjI&Yoy1ab*pEi@cHl z!GcP+d!i$+u80c9OxC>H&BV%AQaxJOQSb;Z?NwnvsA7)^5y%I5cZWEOP|6PDNb`QI4OpQ_`SBHvF$sN(KTFa zmn;q^cuj?_tsr;Ud?VYLtnb^VhKbFc>Ps~?+=#TPQj>$KKWWq4vz5G(Lq&Lp^D=#Y zyt7Y0$o;II$1K)mz#G-xTX*KLi1D!;b2=rLCifXAr?qGlwLSgrnYtbn!EPTJ)%f{} zBBX(O+}700e0{&V0!AV=Q%%jBfPrhQ#5+adqgRDY_Bs3yz8~^p`s7F}e(JZlrF%`A zCL(nDJbfVWT|*a>r0kFRXXxqq%Ab8O)^OQ9E4oa>`>PiwF5FyUcF5LzQR(l-?CVn& zQ8Y7R-uc=*;`hRhsy~$svwrNpe~HN z@O{ARcv`Js_llBc@6nj!1{_4n{3O+^Wcw9g@ma#MA8o~$`OdX<9J;BDy+E>1?9F|g z;96vb@Ewx&Se8sO68zY6BCRBWC=dNHgQP~{fMdY*QZ!IV`I?K7Gjdxph2*7Scxrc( zPiHuVljbJy-38|ke$SYTK7CqlU)XPq>ikIwNcyDcx#N)oQc>Nb2c~_ z)pHUqJcaM>uXA5gjY$B{I4P6L&BRa3WnK#eiP%L!R-yp!wi&ErC>o@G!H5WqPod3`)Y#825L@*&k^RO$)?hG&AtJa(N`wm!sj?HYv679Y-yznl^J( z@t$WhPjY5IB%B}tCM^+9-ci{dQD}yZ6%Q6>j?6`WcNu(ve*?`RQ;uqadnvHPhVMcU zXRNno4o9CB@-)TN+tF5j>Ka(d;zcDV{GNr&~Nr=$T zf$z}|>mO7Nr%Zol;7`1wDQC&u07XI}Ml@ttJHFg(J+|&fsi@7K&rCe3nCq>-mS%1x8g}c&7 z^$J0-eJQa2ZjAHTn#gR-#`xxzzy=T4>-YgYP64yIm)kIv+{KOCiHYny;xN@FpDFn{k)x16S&{#h1+t&*hQdm4)<={u840OOGnms$ zO3o=r%j1QzU3aM^_=RMefYz{CYE<$U+UD}t6{*`^@6$+4V^0O;WV_p7UWTqfof>)! zW4qaN6Kr`>pdOC}-IbqqdbxgR{YWTa*M;q`WSvw>Hja`|_xap%0J+OIs?o0X2YnlC z-@}{mt<(4U<^3lfga+)Bl(H21x-uc%yKkoW`##dC5Bd{+*8BE}8cAcaBEAU_3QZyx z$Hx~+^nz>v{-@YXfWRJV?xp)A9Z|Q>!^yJ79PTZgpx;YruAaH?TjWYyHKlil669Gn z5k1%EvNM-22T0DrZ%xfmMct{>4#<(70*bYc4n< zu+505F)%C~ryzFNBz9W%Kp=E4Z~-bWnIoB6O#;#dC}$gs)^&B%Fc_z+WgF{>hs^Ff zV;{Nr#~EZ$-%%F)@0{R!@lJe7g!6*qe);`zi%C-ALA5YLH8D^a}r)*OM%; z=2F^rDyM@YsZ3shV^kM-^v4_gSjS)D5mERMU=*P36dL0|2KE3+k++PcJYzoTWvUXI zC9uy+7-^K&uy)hS?HH)>i^3i+f*XE^p?$x?P*6D}4E>6ez=D0%Y`nx|472$6_B3?- z`iDJFEKJJ3b9oIqVp`}S^;YTgq){T0`QcKix^l}A4L!4%GpmB?{6Hqha*DY*kIC|( zq_J~F0f>OGkwvsn+OOTB|BC-(CXohr&d`Yxf5EINrl7(cN3*Ws4{a|fE*+moM%4`( z9Jy(UL}^qRfECg7xum9{4<(Y%hiF8YpyyW)B7elexpJxW-PKsd=Lor3E8}*^QC{C`t2=Y?s^|SF31g5Smw{n3@N;+o&}5X>neHH34@?eLi76VrA8~H%VWk`w|O>nTXxTEWNEHSbz zt4@Diq!e68(GRxlyNe=<*G9VHT>GQlZc}l_^H2`UWtoPn*w-6&hH z3V7u*)KKURIuujiFB_07m-!)5%O+&2eYPo+)c}`p?OxDxZz|5yFHlE3o;cV5UDqTt zS-zz$++Mmy60br}WwsBXI=&>&`t*F@wDUy`SYVewV~i-9dp;E})9;XQ315(|b}Z?G zedA;XB>NW*CM?kMGZ^bG$#uaC(==m}cR{Xb6P@e9wdr@*mHQ+1{I2^zHw?MnRj<6# zmJ~7YK-L^Nvvwuh^nnni*9M3J&lgSh$_1z-jIQ*;_iZMu$Ectn&BrliCryo;wwX7b zEYw?avpu&CBs7;EDi8LuyS|QTk7w}Dr~8~gR1e9F2pluSBo&{fCdTtBNg~Oe{rD93 zX{P6L;PbslBKXJ5i}&A`XMWyxf*&vA-aj0wfWNPSf8Nc!|M_hO{PPDG3?KkOX816= zkQx3z5vl6`PLUq{C6Q_Mgv=*oJ|Xi7ng2Ru20v2?fFLtGw0!UvGNs8j0i&Xc+hGDk zLHq*L8K(sEC`ZpE_)YHW z&Vx^49hTCAXuNAOi8&}kl ziTEu~&f2RUa(5J?gO|HZ#SfSH%Rx)Yu%?oAy{|?rgN2U5>)JmIiKG3?khYz;|6s@k z{r_OdDB*qKp+Hu|l0i{AeJX4}0rc0+Xdw~#7!qt+JV!h8)QLOghHGNHZCn*iDWhPL zsdR>aCevD4h4ckDeg{jcWI#% zC=Lzo?o!;{y%d)ag1Z#A0>z!O+`F%K_WpKfcV=gwKOk>1lkYh>_R00;V83G->y!*` zdb@-+fW+AIK8R}oGmj#Ra~SiWGF?Kx6#^0TSv zIPe6rmmIZ^jNrKDA&M4Z#Z6Aw$!fe8Io}!(cTgY{0!^K==cv9cIzGtAAJEU1{BY5$ zwN~9^3bf7uQv6GkG?x9hCTTa6Fa|2G%+gQVYSG|pKUXVF>EdJYUS_K{xY}TSb;g4S zVX!)9>TIQ>`rub*TsA?kj8>&Ls}uDS)5uTqUE<`HusYRe^_KOb7F zNZ>utJ9l{^YSr1iX-_mu^Lfu&jt;a5yY0qa;W@xW6#S(p`;*+CYq~8*Q3&QHTrrp# z{Qk)f=e?|bHoJ9w@<9E)god0=_qNUbli(Dy_at`7RY{oWk?zF9eCOZmy0{<5wrY>d zD}Qg=CVrfHOgyeX{=MzN?mi1sd)gv@xf@aIzDS#Rwd-H*C*!)WO4Xi^3|}4=C%SK1 zC!SAzULH5Ff8GtN{k_O~c{))0KOmW<|HQ)3mwzY;l%D&q3q$mQu}9pMe>}HV&^ETZ z3IUNVm-cBnOE#aLFDDOr!8pd*|?M--SaSJ&Cnf2`sVJ*eKF2a)Sc?sFgk7% zp2F+ck60WoIziXS9TiVc2l(8Zh7pXghuq^!FQK!}jfn()S#aWl!`YNwZg>4<4ULee z{xljLuBK8+8Xgxy;x9vO!bjz5_@1YMcPSFVX>K!e@M|-zge>e}o*OCg$~a7}mybg8 zgj#(o64lv*)XRKVW<7!{$F9du(0B>Uty+JvD4FbLW-}1;-$6_g6w2>z%dbI9f-Tn% zKpx=|YXFKu21V{=ajUw!zP{%=ocQ%+4zMa>VM|5(ehC_nepi$q=G`&F@a@t5-rU)f z3@0_Akk)xEk#+rwO7#~<&svx=BLlJb_#&xk!B@Du%$guFKqk*%4iZ~35D9(W2%-le z^qG=efvSgcQftaTr+CqN4NSiOp#w$^<+efQW5oZm55HhVDmR zxrY_#G(qnC$KVNi#jrX<+~X_Jhk5WoMDwVB36B;cJ7V$d$kA+8vOqK&9^f83U%p=jApo;#`vu;%oE$ zI#d6bI_&5{ufj9d*74UVb(z600&-!a$jeZld<#x&tFk@>WWFLG1ts;ihAb;}518B- z1~|CeExjufZU|=M(bXXmI40?&5Gwti99n5V>hUQ5}{f7NPu$Z4a(o<_+ zZmr=keGC9x!SMd52qZc3im2Y5Xzb_5LcQK>#bO`b&KuQ3?lXj1^Ia`}bj+EPE_Mg( z%!qjG$TI!#c{qa{$AiSrO-wq91#HhwJXTy+)w)B30RHH3z&yPxmqKwgR_DO>1X(0q zO9_a1JWujiV&y?FK*$)F9C5qGfI@uPEm0b5=4AyqUnCjy(U*>nM?$F-cUi=DR42%G-ZcXlx$M{j-voH} zm)~uLg^J4QB7|q(6eA`^AJbsvHl%V`G=y(@;zN|(B*<-Cl9WXYm~f;rq;gz>rtK0j zd&_z!{NSUDp|Wfm8S-kcy`4Was*xn4;7dDnUSRsTy7y(fqy8ZiELz1hnlB&V&E<{A z6%QAPoao51o8}==0>Y(kMu<-0EMPV{)7dUiT^g4lGl&r{Sa?H{@yQopGzIc#&UV#+ zd@FDniuX-~CHYxd6@4OxHSmI1WR495+llRlV~P@yP(iUL{kTQkBs8bgo&cWnxNK;Y>Eb$$ckQnqnqD+If?q>s|GidK|o!*|~O%4ki{-OYT zR1i{uk()VEQ91%K!Iev$bfiJ*{QwjA&;i+)q5=bJEZpw9Ujk@;#XOs{nBYrvAz;aH z8qlc3o~~H?ZRKNY-D)ZO+BD8ZjkK{>jeOq?-yjAeR|7=8e3;ZE7JR~AcPyrAK*NCU zfxyhLW8K!R^lngKo6GG z5rzFXd>ex{$#%wR+;R{JX=C;|opV(`w*(qWt#*sI#)$W}fyz@N9=bmx&`$VG#xdbN zosHF_)dlmTfrwiJEj^<8N-A#fdE@!THrb9R>bvey>8!US6?dDas;C#KpBsE_g*n(# z?XZ|Tp7yX4kf3Y#W;C6e2}TGEuyzesdBsBW>URQfel4DrIBG>Jr42v|Ij^ZTe;ft3 z3(p7D1Yg(qJpVSs?pz#Jy=lmLKDJZqTwZ|Pv~)h7ILCFa?yKH*tURB3PIRu{zLLPl z=RaWVt_@_hyFT*2XW?pHTf`H0Ln43A8C%X0oChlQAe=qZ}e;mlE zJxpi)y(&}t@gGUxJHo(!patyre@)DWhHu7$(v!`w%#Sp0KQ8x48d05#k2=$&lff#!18Z&Z2W=0_cI3~g_7KLM}N zIh+%`^foOuEq+t>zmfXXj!z0UVA;>}J(*0#2!;cuQH2Qb$-F4@Y-dn)`OIEQ+JMsau$kX_cJfthf_i)G)1(wr# z+C~|Ckui26%e3B()@3lv<#{K2!%|(rne6Ce>BaW)D~f8<%*o#3Miv1ICd;kr624sJh*52RJcF^bwf^G2 zT-5>LrQuFFa-i>)mC)`Tq|a=Ym8*vIqBA*>@w_|sAhv$O%HHoo#g0bvbOT2!jF*7{ z=U)k0Vl305clsU@$m-+iA}cWxuA%I2BqKYeXT;8E@1{4YhlAAGFJe*dh9MWIXXZIt zoilO?wX4vYsm0FY9))t@CDPx0%?H3g8=N=VR_i8!hq0R)8;`W19$4w?^%k?GaZn~|+^nO3*&vLsIEf*uu z*hVYs$&$$VN6X0J?yLJCJ^Zo}g7wL&p9eUL4$QqsLv-o~Po!(wq8;>Xi`Ts+Y}!B+ z0UK4p}LMBrzjr-sMY>2p3RnR^($6*H=~Z1-p=~ zEMkpv^H@(gnM+|H2naKagrApM$pYTse@*X2(V1eWIF2xpy%NrT-CNY1RR$Cm5b58k zDLuHv-virvxgTm{l&nGsM;FpRO}@zKc-xyloZZ9_)o_!4b=x*E2#`rF3)79o1vuo< zlXqRC!Clv>)hY)O!wWKg7LN=SJFo- zx0r2;zXjMSESIbPi7lqtdt$Wo@y@x5*X3ht;Gut;h5EX#&N`<*Y7D=EI#V;-Ph{;N zjVNye5G5?Jp&rqy1*je{OA~*cn)E2mjQ1tzQC@pea=UCG;lsBf_NKB*shq?F4foMI z%&BKqha;P0LELI z;erRa-LhA%@X~emn3If#>0ekOF|@VX;Pykj;uTT+we>>!KrS=U3{70?4FuK1K1bC}#N^~}#} zr#8=dQp}VeDAX!g-M?sC0EmnFkzyqWcTL%+)1WbWqdyRyV;mp(M2Gkf6Aw7vy6?L* zl1SVT){&CUvdYmflen==e2}$&wqm`SZ(Ad-5n*AqI!$IFlwxQ&ize~+1frvVWAkWhqUv0 zJ+#d#r^?r&N+me25yr=sVbctuS*yCOh5dj=lA}d=LYM@0lx*JRq?6n}Ear3sxqz*9 z$7T+p%nkK%2~XvMrspK1zOol56Q@#{AqK zHLI|*8F4=~N?c-yhvqBLRmt(k%d&1gp-rIscKnb3RBN9(*}xKTOTp( zEL7xa6DO{1fJyZ{((q}EWTI_I0Cpbh^R!Kk-994sI_#76w8N~{4$*~Oq;@{-a>cbn zZB;KbSDy9+C)!~iu*;msr+snkj>$09s{-=p19`QM=``3?iOBPzdR)hBsp@rw;q#Ft z3h-#vmIU{YYl|HgpVG zv$W;u?m%TE4vtIxd**9#m*H2+P1NwR#W*->-okiUR?k=R<5t>ZH=(ch!SHU8a6VSb(Q8-qFr#!cZh&yVM0M?C zU==6~IV=!)gS7}v{`HKU8lF&%vSEx)N=heoJ)oOs1ZWza%Nk8yh<35$6rYwygD@E+ za1?}>=1gg%LSx`ibgA`$PD3VgiK!#WMO!f*rRsI5LwJECUTC@^xP3x872P@EYIP;; z^lX3{sv?Z=d|E@g_b~Zo>xkc!uHQvw{T*J|TlPsSY69|}=ar*j1dG`1Nqk8Fi$ko+ zPqi_8mvaHNtc7`ggJf-!@%vnP;y=y$9&1{^@#{K@gwAj0gJRt?|L`|X4dvP4$T1Q3 zpuCAV7$i_crLKN^SeXq`!qwRwpR~VIjv~pe@8AbURu7x%?(pudPXB@Tx8_$Ct0a~sBHe((4bIb;jX(} z0LBne;$GdLP4dXbBl^U(sh8%-*Yn&LeU{FG{o83E&SpQlQ@{vMu zKY~%hGvMk%e^8G* z!_N+yV~vo*QC5qbQO~oGH#EN(U1UY{55ND6N8`PeKpjuZz`4OJPcwQ<1DuWxWKCwj z%f`x0H%OrQ=HC29-!}Q>xo{i5xSqDUc{nf(Ui-Z%Ej3&Phb`Mm>~2>(Z>Bw4Nqe5U z^AX<%WX%!N!p8}lzn3y#)nqEP>A4b@ilo^eb;Lh$3o za~gCm7J_`!>|}Wbe1|wy60X2CY0@NK2h)@E!dY$J znF)9VcU8Vhy&jVljkp?j!}?~r_#-q7Tt~!oL9f_YSz=x50c08zmlJ49g|0_Ym2C@V z*;}LO=38*_yJ3cx3CoENVgg*&NZLLH9UAi0U?|}PI<~&&F?e-r+L;)wI`CXV@n-0LnTgOZ;DN6{@gov^&t=kE$}a$>30If-X!3z zHL>Nkc*#wi8T|r91a||2_Y&CywSs8B9?@BY;Lo2p!)Xi9J?M#i_TZgK)_#{%rkEX^ zRsK-I;S;gznX~P5S#|scyM(N~m$~&PoqY1%G#QY0SS){2E**zGk>YIB9|_>oTM!(3f#bCs>iZ-bSG`8HT{jmP+JlgEdJ9;}wS zFqLBq^2fyy)s}{|@naj2$EC^GmZnmb69>b`B_^Es6R%}Kfx}<2jTzs5_2Lmi&KaGG-;7MvGv1!*}kF2hqXJRuxOs1(4 z^XF#Gz4c#~*kt7?zy#Zu^Hqy+8^-V#P-r<{ysWY3CL3bP61v`oL&LD~7rFDkT+X2H zqyq13?hUUa$FGnvg8%5E?qm4@2a_?tz`@o5U&k-jIYw9JDF*KkxJ%Q$NGyuq_@W7a zeZlair!4)Y;V>8aK?DWm^;YwM&``FnE4Q3k7*+S2PQ>kXp{dUw!hg--<+TFhrG;P3 zE>vHS4?sd9S&A5WibW#zXQNWEEkxlE=E!gn1`S2ObNl5l+W}wbaVf4(#51AqkrV@u zx6hD$A|F1HL1eyw;b)@lNviHZc1|cZF&C8M?*tcbtuxCqV+@i?(aVyjIV38}yEjLn z3p^1`jgCx2CDIYyN)ToUWj8jEwu9mh*n30Db`Qg%8s=2XG&QaqDk`vg9Rf@(JoTe_ zzwGDo7|aD%i7OXmn$;%TU)z*G$MqS%3GsspKo8g3$BmPJ4Jw<$`QT?W7`7r__L?|x zE11O~Vsn+%vfmHVK^QRb5*<`rQ_C< z0Z}U3tNDGX-@7qA#*Dr771Dq`LTX-sQU>Z6Xavvc+OV- zhf3j3_j{o488{i#4q(B5D=(-(l$CUG1g5LppOnkB8p5bQdD5Jdn>`1sgpK>%GCf1% zS~lK&6IrX*`dQJ{F~-)UW4fQUa6Eg-Cwy3gE#VU|y2LUgLSIP_Xf;pui*V&oZgL}0UrY+P@0C9(!#L)S2vLcYvC>dw6i!K<%&-@*>dr-8RMlw=a??EG1jG~c)Z@x z>`_N{gM`n!Sx(cFEUeLanoj61u9S<=qJN$a$t817lx<>qTDNP)mk;uAq;wHZk{_tw zC`|Le?Z-|%4K6~Xv{vq-K8)%Bp0(^rvCA6Wh_F zKwbZIA~vsyI}sRE5x1w2V2(k*aW*y88iCG)&=Jk`D__fhnkWB@D63|!V>wuLx(^iTF7Zs8F62U?>e{$ zfLobYq{qW_KYjZX(7go~J~Rc8w^5)FI6DqpWWm>-_SPj0RhArxUBDq^@hX^Kup4#3 zyR`LJK5~USGHt!5ZW~}$t&h}&ZV`3f4RXcSN82iIldaqh3Bu}QJ)qlEk9Wi3SPk)E z$~&~=_apME4T)*c9Y&G+QT5n{OOU9;_j?6}rpmb3bN=)tEl4yvLJu54BTm z%zWh_{GIpX&asWz`^x*mEB7!@SYysDbYDzK2<4xrGvxo{FkaP`)Cv?tYuKZC$enlZ z50i?=fD_Bzj}>Bo=i99>AWt&R_8F?}wE-WW4ZG=d$;pE=GxmiekTvtwxwp}Mq2ejU{ohp?h*=nnGe+FO`i=$+?v4-9?bZ+bihUZkz=TA&h(nTXI%qT51E#5 zl*XEf1U1;EG^i-)BGhFm`Nkc-|ad-B= zLX`D3Q)L*nR(yx!1#w&>C422G0`ct13@>L9O1;O;tXVZLcf!?5)qK5o5*1kC3B0$f zJ8ZuxW}<+_>x5}4MZ(UBO)3miQmT|(mkal5Ymvqfz+I5h>7oxU+hjTh^GUz5wD^!u zM5k4KbbPA#D_=0u8aOu!{7L#!l)H2j4QucqjQqLvg%7u?W#`;^EG6=P(KmnG*+8b# z_BnSjLc^vMv2_+T$;IF0(m+4B+2~j0g0}U^axGScrOvsfI|{k+!cv!`O9S`+;RmI1IIJN29k`64|%Eadh zcF#yiExcx795;3VdUgI@K-F4wsPT%-!m8U0;VsTD@gOYzl{3oJ_0_v)=vtrvq9@1& z+2l?t>}TlhMzB_*$4;oSst`@8Db+|O_OKHnZj;;ffy>ym5cG7vC(wjkZr6q7cy-HVNd0q* zxvT4&ch{<4lELycb3v5%8Tz*1{BpSa(Nk47FjH-y()8aL$TTvudcs*JwDn$z`)Hre4?+Jhka&1FD*YKc@lerCOh{Y*?! zWPf%#cr=vh6Q0ttE~~P6hT~RsQ>}yrz@E1^Mu#2 zkc<|Qa8jW)P!>sV(j|;$`?p8v51<;LbKj@pmsh4yWe}I8x-~5`@5vw(7SCesjItml zgDU<+haZ&T}b-@?h5Tw0g#K_iZ@cSa(H zF=o}A;e0ciIAdIGa8!#gkEI~fvRVcZ~1;#scB61T{(>yOS?GlnuAms(Hyj!My zPyW^|17G?VC`?RR6L9N0k%MK(;-ICp(oUKnnfBp>qX!$7{i-{hSpeZ@T!F4nJEtUc zP)lp;+tBd~DgPWxC(2{SwZojk4)-=r_v*2>6Yty34a{24VWstp%-gO56`NY`g|YRU zj@ut+F}1$?O1~bKZ@cftYyEG>e*JxT#dxebFtYLnko>L(MYS%F7`lNZa@UI!TNliv zyoqLb*GB@Y3l)HFV)@+lQ)AVK%PDW+W!?Rc7%%-#{Ci#fPlMh>t^NN5y??U{0x~c3 zrea1pVIpW7pOm8Rj=tlI+~~=b1G-+f>WQn3;lQt3_0Cx0zz(%X|97e2qjfOXE>*gy zkOZ*D37#1MB?Z7kl293$&+zI=tuTvix>3`vxqTn>&~_fCDHq^lS28%0pr22ch6_5z zJX_c7mhPM@zUqqq=~}Z&+;x&`5IpO;Tl5Y^-4M8dFJDvfK=zAv^QEu1dC$LIvEo0L zfDB-N@w(@-pMnp6{fx#Y91fDc2ud)MDX_9vdfm@#Cyf9+e?4Og@THtFg#(h9iTlDi z9K7V~_{=5syu;uRkM?*Si=S{q<3%#$`KgVP=RTrLlBaf&e1{l4s!~d!oH5mAsws-Q zh!KVkM(hC!drxV*f5B`|@&6&@rtLC*$Do&_YQX$PcWso3+CjrRBF#bvZP1z+zCk+P zL$6}M_+vjyW2TWy&8SRP&>XX=tjzq?a<=@`4u*)gQ*Y_V#ZgB3@V_+p<{*5rNaF$n zc7y$t2K_n4^c6>IwQNpAusxAXjkaBGAxc?&~;?8Nid#r;2cN3%)|1UEhH^k00hrkv~fC)sZlXkr=@M*ieJHlCnZPL)Xv1d0`-e~@N5edF+2My)yh25Hr!0JOJStKTVOUp-Y#jlT zK-6BzIH0*&-o7vy)3g^nFRFd+ch9e2tOFtal_+E^xC0LJ~Hjo&L^c1Mj0vWBR;p zw?!F_OwjMUrQAx4Y8&VX>DbIVePvp$ z>?Uh?>FQ4BLwHJfb8!-BkZ$wQE|+ziM(F6aNeIbECMrjL3M@U9x!j|gSVzHVaJqnH zus;C-5*uXXiOeE1O}1=~>HCSVze2&f89FtA1|b`vWmDN7EL z+{;hqQwr3G(hm)05Z=|IkyV@sj+!YZ`FJgFrs$fEX;~tidfHE5STPbxGJug7k^z364Xpb!}<)>B+_$t zpXoSJAAy<)L$+bSjxG7OpOL^<@39s~%f!a9yD{UZK+pnXB=>t~A4} z)EicuZ^*o^vQw!vSb)s8bX-?E$5a~aD=u^_U)Ok!SDM^H7P=p_G@uI-BmLVho@ytUXVfs>=($DQ_HoN-K{pY$o;7* z>b1Q;e-AU!gc#`&iUH8(RiikO4vZYJu~OBe#k%q1L_|wAsgw{9Gd8(@H+w_}JhEu% zB-*jFSS7F{rqZg^_0C31=;h>FhyE=V*b5!l)S8JBN!1_9I7M)$jFkUTnk~Xc3(CrN z^>0_tG3-dr*Jcbv0y~2fdnsewkm9!^aB|wk18{~G4oG~2Wy_?-?Q}IVjjLPBNxom$ zGblyS;+v)zp%tx&mWE0YCshu)7s@Uoz5;Y#7Hoj$5*Dtuyk+28HhS9#ekk z`od!hFMh(Wd;erZbA|(WF3opH_USV&jJg-I?|{AP3qFKv zwZ0GV+ox{yO`#9g80#=bqxL-Flv%E67yLPF+ zSnO@bJGKdVDO^O>Zt7*tiSt@eN(I@4 z6;cX+(zJ)*?xz;=)@yJJB?KtL;ZV1|Gf?*1jvA)yy(w4taq@1xuaJ&1^{roc(O1+D zOV3Enkih%nRLu|Lz&u-SqpgoNrBt!_21cpiuma2_^D_HDxm0*z6z1M>`TZ=qRCHfq!h88L=MGvbb~`%Z z|8SWLz$_C-R-6nZyUIgRDU&3IOoj?y<>SPZNi!)eefB%;?lta&pCphsSl){nP_yu@9i0R)#|;uG0{@lzD(pWw#e-<{L& zhEtOQv*qDfn%f#J8=^0xv8*F;KkB?60e4HerxZ_GI;=>9u;tY>xZA!I?V?c!Xth#U z&XarRodqDE9_2uzZqlV1q=~x`0rP8Cr)L{7 z*YSGy1*rgg_dE*JKq9c+?|Lgko>@e$7d_886?wT}G0LQTD~Mg|Cii}XAacZA)xnzY zsI<)tcU!x>xj2z3f8nQb65cEW;ZqdwXXM_tY@QEG9;OMO-LA9TxP_B8t&k*8!;+OQ zQ1n0uiDlNw!*;qWVRC^jQ%)yFJFDqVfQ6R8L7f_MTInqkx0cwgZK{duKcb&?{Z3THI1ue`yDE4 zx;sjE%Kg1z)$_C7LjsdKk>mV7RSVfjd$2Y?)^1UY95+Duf4_Q!vTP?!vpOHE>xW<8 z@Rn72pK78e+TUz7U6Gw9O@HGnUupz5KRl{fxNoBU?pRlh0%XzM8G#a;j=J)Q-&mZYPJu{)NB;#vAjtq|la4WI(00D0*aDB||-BSczS0R|K8#DboO( zz--SsX|-_@`UgY%j0Ja1&8Dmr1}e|vPGqjtNnni4rN{>dQXXCJrp$7muNfacsY z%Kvp8`Utc8m2srYk;VS{{gQw9O>I^D_FmOpGF@ddXNzQ&&ywa&Gx44ZMMC%-7VxEh zeT&_*^cr{4U_;2v5vW~%9}>b9$^ro15p$xT^)diamVZ#`zMc>Nt|vnVCQC3^OO z0^xL>L}!Jzn1@{^zt+d@b`(-#msUF5Y5bs)h0VAW3QOPkFV0>aIWdcS!H?}Z0lf1b8 zYkD%JU&K+A)Wu;PZ&MAIfXo)15+95hqo{<*K)uQ_%5YDH$cbeiq(_m4t|FTA6>UsQ8Iu+@ z>;VWPX6p#l)YS%7x=V9z6}X(>B1zL_z9RNN9hruxScqnVfZ3cNbhu_+(1CEzaVTW> z=q*qFsG0!s2Dy0euf|avPpTql;d*rmCR?2Yw#D#Vpg|>X*YxWPYPG=O6fP3a1MNE* zzkE);XaEex&`GII)_#mZN05yBE0?FQv z{h9XW?|0>(uXpDXi5C1zh3h=m2yMe)*l5@?4;D+=uqwjW-3_BLD7`rq!SePCaZtuP zy7^E~bwd2`uy;v#5gzFyvG!x(H->y-^>%W42r+W&L9f{-OG?4{Jq-Io?d|P2S7y4N zL}i_Rt0Yy(pO3y}LNN{`Pwrb|vL|nV(t?_p+S*+c7hY zV5Fs_mImca-}hD{f^)#3`o+257y;IKVMt_*`LbNLJ(kQg)a6C$+~91u6I8ClB8re^ zmSPhggJ4Y*D7*z6s(LHz6Q{{dbOl9(u!A2W=b(}38(`0BKy^1^MU|9qT1v$)LIqRN z?-k2bbpo<3zJ0%_D8afTlN*gnB#+)s5^elF4W<;=ooc87uo| zuE})2)=Y_y#(6m7 zGJjOg^c!&&Ep-2-e=s*`I6XAc)P71r`>wA>`HLDtMrwMj(e{J#w_`!S%SnaLop@hK zJ`P%ju@)j;;{Yj~*`n!1`dh+R=BxNRoNzx)fS@VLr@m?v9Ko9EENhKC2usnghSFTH@5q>LjJLfYL_{=A$ibteq?h<>XO1r4Yi!U+vaA8kjqUoQIg7t5;zITg%6#VaZ zvupo89Jl`Y`*=3|_T}kn;q%M$-G1%M->2I@ueBPCS8YkY2S|1XMp4cK5|8vC37-Yv zMCTze$@iieoCT6V^N<8ada=CEf~Ya_QRL+N@G{SWnU(X=bVvG#I?h74qVq9qU;EBE zbpJqadT{9Vyeni3Iu4tdoSL4Qots}+Tv}dPU0eUPvAMOqv%9x{aCr3l_~i7@+4;rg z)%DHo-TlMk)AQdK06ZFnd|h5|5DGr4(MVl>e;5v(VzzvJ!C({#$YFJ)zHm5>S}Kx4 zp`mCriCL?{XtbetERD+&lC98KGM**qdbB#)SUMq-D;|VKsn}FDRVbgtY7A*ApD9%@ zRQ#^kTrpRv*XXbYX|7zTHS3S0RBEYOYP6fFFdl2EUTJmShJ06Qty$~zyySe{+7KLZ*U+R`sCEkzKl)gj5&q@hY_5?)@_euSf22N!q0z{yc?Q2YY_Kym8e z5Fvwu2%hQO!{u_psMvL#(bD64NQRTZj^-}DnS22ry9f-;mW=gZvQj}U-ZdMsK&I8^7~DvX`q=i>wz}QY(m} zb*UC@TYl>LakV=wYKWzg4WV%u`RV|75zkz%@7FLNG984GLy_C znf-i!Jd*@2j0}Ixu5sdlu`_qb?ep*|2SDbQ(3-zxi&lEI;9kCZEfV{=Azf@hw6jDAfZr*?Ck6jpSNev9>U@9 zzYW001*)cLSS%LYb$Z-QV9;Q~Oc*m}3;{pvc~|b6Faw;;UNbuY*^sIjbY{0Ycz_?lP=ik7Oe*k*m@jt-) zuS07+TsIHe;;`fb@U+33+u`N6VbW}QG9dX&O$a6Nkewbg$3nqrJTyr4%VCDcEc_>~{N6*W23K0LaS9B0D>K zsIPcDj@#`f7z}=Spjt9u(6LQPg@$U_^B$xCVIZ8`(XYP*QDEF;m~{>;ybKIF$SH){ z-O$quSwQ(DxqnP)Ik7k>1*Rmno)(D5pr8ayCKD|!EtHp+W3gE9b%Ngqx%rS&k%QH0 z#qD-8e*Ab+Qd01DLSG+bJ0T}0hm4F2`uqDSD=Q-rht>u#r$e3#a&vR3uCAu5tLw`F zH7j@UkOHL>mIf2TQ~c@e;iIR|v)6J3oSJf09E^P7Zz#tXc+d{uz4x;4Fsk-U1hW--*-dq^lLy z+z#9R0>K{0D~0dg3g=ztlEr=je)j+z+6|_3m^v43`-MhjWhMLf?>}x}PYBdZtJqF- z(B_7Jz68eP)>lAuK!ENFLy;90EP;1lgSX#-91FD6!k%i#1|kXA@(xUIhwOaVxf?Qp z53c|(VrERh`g?@!r4!)h#qiD!&?P6*To0>mg7TR#W-{D*9=x|p+G#+|0l52mn6?0F z_rR@}K`hxe&;u{O3g#48^P-OY{QTnvRd*twrlbj|CNu2X3N?FSTqTrGmch0)z+10C z9600akYNLFhX9{j0;ev33Kt9jB_(kEci{5n5b%i!i2~&l;MXs}H@^i5J zu^l>EAQBS$dc5VhL5;`bq@@c$Dj_TlB;f4Jg+&^$Z8KEwgbZNumC~-gQ2=-3!qxu+ zqsKuIn0+p+d>k%aE}+GLiVAr6uW;rPxbQk*zbUy`uRSe*x$+^e7@P%=o+|yeH-pmT ze+}627U)gz+%DKu2d6KF$bdXA5QM+K2utsP&2{k5t6)swC|~;v0W}_vyT=RedST?OMPM&T zwyTl4R3ms>h4E(KU>#g}4lKI{I{RdSqG4EgDSY#4X|roLthf~J{1)_f$&Ok6Ae0tD zZv>ut46a)MFRzEJY>34oC*; zM-y~5Ln=@?GZ}&T$wP8?I5ca!zbqm9+4haIHaRKnRtKoqg;N8DKf4|h_6%F@QzgHG0(+;jtvaKVC zUt4u6q^Co`52gr&`rzv6P<0v%gy6pCz?}4{TN+@^wQ%tySoLkV_I9}VJM!!(aA1do z;U<&m%VBC-8tC;9jzU2;%>CM6xFw(t0CN|EBQGgBbU;F+I8hYz}erAuJe*P!M@@s;nt0c=h= zd_usy^C299o%_VQxMI4nS^-uQ%sF@1#C<7DO|!|i3nLS?CH>Y+i`cR>4KBQP`2NmT z=!*&i(=uS(bXateY+C~`_7pJ>k>obdN@_5Dz2f|9Kz=C{RlrRTg3%~`ajOqfba3sJ zaK{r+F%6d818D|{`&5-U(;S6d>I`=Mxz*wMoKH;skb3586D`2iZw549Ik=h z9>_0&fdDM5lI?8ClD4VoMjqTGjLI7&{Z!qeF>Sua!4Jf?mrjHUr%D*>_xJOyJFJ|x zNFp{(!KiUCWxn)lPKOO|z_!<*rvuV$aLRnJyF^v1uC6{In`#&duum#|eSP?Qx^a#c z*-rs`_qLEoBq%N}rf_VMot`KS4GrYy=VP&0C`i_~wTEeMZ>OlJh|D}4nMo6oo&uH} z>A&f4FI`<-l$Mr~H)eQ}2M>A(27?q86)|`8@Dx0r1a)|b15jLYTvR4P>>k)Xf7pZ)vyA9ZctzJ15s zKaz`5U0r=lU1en@X=!QXBMezu=OSA>V%3(Fy$+9?dLbcD{sN?pMwRL4cqJg zm!LWv4jOifJ7h|_2Pw&LFPii{2OEx`31+jIva&ML($bEwZ64a&+vPCQ>#^JIIGs*( z$q1mYuaDl|UTiiS!CqK%Jsj}E%9R3YJO-U^umIUfB4=i1qLjj9G7agc!C(-N$AiP+ z7}8sPJ|AwkoAmVbqv{9KJ&{O+l9H06%vdNC8XA8n6gtMt#N%;%J|8xl?U?X25{b~; z+xzjLYMREV3b=2BxGerISicf_qj1U$_{R6d;g7{&;^|;87$__(q@xL1o57w9W5?Oa z$jG3vv60HkN^CY8?mBVyZ4MY!DWY*K25n6c3W?8{KL$brvVfO-4;FU8=R_RZ1zPR6HJ6gC*co>b~ohnxCoE zRFs-+R_g96mFn+RDijK-UawNCu9EtxD0P}isnypg6^|+P_$s9q7AiFZrA|eu3rdu_ zbi7i3Sg+L5nM$oVU#V@cD0Oa$QkRTTYV(syT{mB;DJZqrrBrjRQh)rlQj7AHnt)Qb zoTpTHK*qKEUrJp)OR3XzN=-wlGjo)B=@GfM^9`jI7c2G6iAp{H3#F0iU1*wy*=%OY zlquBifrt__;LMk;yMO)OU0IF0qt#Y<3gxUMp~)B zzg~s5M$ry#Tnt@7=~EAQJ+S&ls5k{YtUVJquVl+25e{w_>4u=VaLPNf4^FgtrshR+lNF=b?Y#0m%{;&c5 zwgoI2EWaBb`v=&pGQc-C!T#;Ab(7fSISb*b9WZSw6z9T$-7x2CFm9BDkM?Z1;rkNt z81xcVyaOzpm-roL^S>F*O zs=>pczFHjPtW0p^Lm&{q;cyThfR}$I56Dafs|~!(lDF#gLsu)PIHXx%ASk)3zrO%K zeNJ4Ycmh%_@b+e?Zh~{a3M(F#zMotz2c;zw4j+_>&6x#vKO^Dl@9&4c1l+nBuJ|Fm z_7uFn6*6rii0pk&*m?dnqQ#bsgI}+Ln3DN8a%B2rRB55{z@rO!W0e2vV$#0K#j#>bhJQooou^6Kish# zmM?{dW?{D8025}z4}S?(tHjsq@0V@)#-9YxNJ!*A9TK7rmW~!#tegVTR})D7NYkM9 z0|>+*LoZARaMwwnIr-3jSQu#lCe2G`P(9*T52k=RTI88CzM6Dvkkn2Bu-UR{8eu=#m8 zES4>TizdMH55cl~VRVH|wl^RQ^ma|A(Kc1x{GSy2b?hpCe4LM ze+&l>LE9lo#`X8h)|@>Tiprs8hfG!_(<1eCaQQOH24tj)kJuZAbOShYWE^#SuwTXVqQS|mr7gnp4@)^Tz4;|{EyStlEC^U4vVkSrE0-_CgJRY*LvT(Uv==3^t zdSOeqU&MxZQVG+UAgZL@puy4s{bA@&)@ex~ySih6N-0`f zTWM`=9r2z|x_+W*i_fcccXwmA+nF?J5=&P?)e5n%dcCk&(?MNb-6z`8&n5Bq?^L2u zVJ(2(Je&>ib}QQ3+lQ{51obnNKp^mu8H?k}rY>K;T-&&DBjx4gpQ)iz>V%SG|8C{T w4=GN5^7A>BV?OyAEGIusJN|Oy$7%mJ0Lyj?MG_e9QUCw|07*qoM6N<$g4<`vT>t<8 literal 0 HcmV?d00001 diff --git a/include/aoapplication.h b/include/aoapplication.h index 5646dde..67f9a0d 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -1,383 +1,323 @@ -#ifndef AOAPPLICATION_H -#define AOAPPLICATION_H - -#include "aopacket.h" -#include "datatypes.h" -#include "discord_rich_presence.h" - -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include -#include - -#include -#include -#include -#include -#ifdef QTAUDIO -#include -#endif - -#include -#include -#include -#include - -class NetworkManager; -class Lobby; -class Courtroom; -class AOApplication : public QApplication { - Q_OBJECT - -public: - AOApplication(int &argc, char **argv); - ~AOApplication(); - - NetworkManager *net_manager; - Lobby *w_lobby; - Courtroom *w_courtroom; - AttorneyOnline::Discord *discord; - - bool lobby_constructed = false; - bool courtroom_constructed = false; - - void construct_lobby(); - void destruct_lobby(); - - void construct_courtroom(); - void destruct_courtroom(); - - bool is_music_track(QString trackname); - - void ms_packet_received(AOPacket *p_packet); - void server_packet_received(AOPacket *p_packet); - - void send_ms_packet(AOPacket *p_packet); - void send_server_packet(AOPacket *p_packet, bool encoded = true); - - void call_settings_menu(); - void call_announce_menu(Courtroom *court); - - /////////////////server metadata////////////////// - - unsigned int s_decryptor = 5; - bool encryption_needed = true; - - bool yellow_text_enabled = false; - bool prezoom_enabled = false; - bool flipping_enabled = false; - bool custom_objection_enabled = false; - bool improved_loading_enabled = false; - bool desk_mod_enabled = false; - bool evidence_enabled = false; - bool cccc_ic_support_enabled = false; - bool arup_enabled = false; - bool casing_alerts_enabled = false; - bool modcall_reason_enabled = false; - bool looping_sfx_support_enabled = false; - - ///////////////loading info/////////////////// - - // player number, it's hardly used but might be needed for some old servers - int s_pv = 0; - - QString server_software = ""; - - int char_list_size = 0; - int loaded_chars = 0; - int generated_chars = 0; - int evidence_list_size = 0; - int loaded_evidence = 0; - int music_list_size = 0; - int loaded_music = 0; - int area_count = 0; - bool courtroom_loaded = false; - - //////////////////versioning/////////////// - - int get_release() const { return RELEASE; } - int get_major_version() const { return MAJOR_VERSION; } - int get_minor_version() const { return MINOR_VERSION; } - QString get_version_string(); - - /////////////////////////////////////////// - - void set_favorite_list(); - QVector &get_favorite_list() { return favorite_list; } - void add_favorite_server(int p_server); - - void set_server_list(); - QVector &get_server_list() { return server_list; } - - // reads the theme from config.ini and sets it accordingly - void reload_theme(); - - // Returns the character the player has currently selected - QString get_current_char(); - - // 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_character_path(QString p_char, QString p_file); - QString get_sounds_path(QString p_file); - QString get_music_path(QString p_song); - QString get_background_path(QString p_file); - QString get_default_background_path(QString p_file); - QString get_evidence_path(QString p_file); - QString get_case_sensitive_path(QString p_file); - - ////// Functions for reading and writing files ////// - // Implementations file_functions.cpp - - // Instead of reinventing the wheel, we'll use a QSettings class. - QSettings *configini; - - // Reads the theme from config.ini and loads it into the current_theme - // variable - QString read_theme(); - - // Returns the value of ooc_name in config.ini - QString get_ooc_name(); - - // Returns the blip rate from config.ini - int read_blip_rate(); - - // Returns true if blank blips is enabled in config.ini and false otherwise - bool get_blank_blip(); - - // Returns true if looping sound effects are enabled in the config.ini - bool get_looping_sfx(); - - // Returns true if kill music on object is enabled in the config.ini - bool get_objectmusic(); - - // Returns the value of default_music in config.ini - int get_default_music(); - - // Returns the value of default_sfx in config.ini - int get_default_sfx(); - - // Returns the value of default_blip in config.ini - int get_default_blip(); - - // Returns the value of whether Discord should be enabled on startup - // from the config.ini. - bool is_discord_enabled(); - - // Returns the value of whether shaking and flashing should be enabled. - // from the config.ini. - bool is_shakeandflash_enabled(); - - // Returns whether evidence should be maintained ic - bool is_keepevi_enabled(); - - // Returns the value of the maximum amount of lines the IC chatlog - // may contain, from config.ini. - int get_max_log_size(); - - // Gets the punctuation delay modifier - bool get_pundelay(); - - //Gets whether slower text speed is enabled - bool get_slower_blips(); - // Returns whether the log should go upwards (new behaviour) - // or downwards (vanilla behaviour). - bool get_log_goes_downwards(); - - // Returns the username the user may have set in config.ini. - QString get_default_username(); - - // Returns the audio device used for the client. - QString get_audio_output_device(); -#ifdef QTAUDIO - QAudioDeviceInfo QtAudioDevice; -#endif - - // Returns whether the user would like to have custom shownames on by default. - bool get_showname_enabled_by_default(); - - // Returns the list of words in callwords.ini - QStringList get_call_words(); - - // Appends the argument string to serverlist.txt - void write_to_serverlist_txt(QString p_line); - - // Returns the contents of serverlist.txt - QVector read_serverlist_txt(); - - // Returns the value of p_identifier in the design.ini file in p_design_path - QString read_design_ini(QString p_identifier, QString p_design_path); - - // Returns the coordinates of widget with p_identifier from p_file - QPoint get_button_spacing(QString p_identifier, QString p_file); - - // Returns the dimensions of widget with specified identifier from p_file - pos_size_type get_element_dimensions(QString p_identifier, QString p_file); - - // Returns the name of the font with p_identifier from p_file - QString get_font_name(QString p_identifier, QString p_file); - - // Returns the value of font_size with p_identifier from p_file - int get_font_size(QString p_identifier, QString p_file); - - // Returns the color with p_identifier from p_file - QColor get_color(QString p_identifier, QString p_file); - - // Returns the colour 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); - - // Figure out if we can opus this or if we should fall back to wav - QString get_sfx_suffix(QString sound_to_check); - - // figure out if we can find what prefix this song uses - QString get_music_prefix(QString song_to_check); - - // Can we use APNG for this? If not, WEBP? if not, GIF? If not, fall back to a - // gif. - QString get_image_suffix(QString path_to_check); - - // Returns the value of p_search_line within target_tag and terminator_tag - QString read_char_ini(QString p_char, QString p_search_line, - QString target_tag); - - // Returns the side of the p_char character from that characters ini file - QString get_char_side(QString p_char); - - // Returns the showname from the ini of p_char - QString get_showname(QString p_char); - - // Returns the value of chat from the specific p_char's ini file - QString get_chat(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); - - // Same as above, but only returns if it has a % in front(refer to Preanims - // section in the manual) - int get_ao2_preanim_duration(QString p_char, QString p_emote); - - // Not in use - int get_text_delay(QString p_char, QString p_emote); - - // Returns the custom realisation used by the character. - QString get_custom_realization(QString p_char); - - // 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); - - // Returns the emote comment of p_char's p_emote - QString get_emote_comment(QString p_char, int p_emote); - - // Returns if an emote loops it's SFX - QString get_sfx_looping(QString p_char, int p_emote); - - // Returns if an emote has a frame specific SFX for it - QString get_frame_sfx_name(QString p_char, QString p_emote, int n_frame); - - // Returns if an emote has a frame specific SFX for it - QString get_realization_frame(QString p_char, QString p_emote, int n_frame); - - // Returns if an emote has a frame specific SFX for it - QString get_screenshake_frame(QString p_char, QString p_emote, int n_frame); - - // Returns the base name of p_char's p_emote - QString get_emote(QString p_char, int p_emote); - - // Returns the preanimation name of p_char's p_emote - QString get_pre_emote(QString p_char, int p_emote); - - // Returns the sfx of p_char's p_emote - QString get_sfx_name(QString p_char, int p_emote); - - // Not in use - int get_sfx_delay(QString p_char, int p_emote); - - // Returns the modifier for p_char's p_emote - int get_emote_mod(QString p_char, int p_emote); - - // Returns the desk modifier for p_char's p_emote - int get_desk_mod(QString p_char, int p_emote); - - // Returns p_char's gender - QString get_gender(QString p_char); - - // ====== - // These are all casing-related settings. - // ====== - - // Returns if the user has casing alerts enabled. - bool get_casing_enabled(); - - // Returns if the user wants to get alerts for the defence role. - bool get_casing_defence_enabled(); - - // Same for prosecution. - bool get_casing_prosecution_enabled(); - - // Same for judge. - bool get_casing_judge_enabled(); - - // Same for witnesses. - bool get_casing_wit_enabled(); - - // Same for juror. - bool get_casing_juror_enabled(); - - // Same for steno. - bool get_casing_steno_enabled(); - - // Same for CM. - bool get_casing_cm_enabled(); - - // Get the message for the CM for casing alerts. - QString get_casing_can_host_cases(); - - // Get if html for ic log is enabled - bool get_colored_iclog_enabled(); - - // Get if ic log mirror is enabled - bool get_iclmir_enabled(); - - // Get if only inline coloring should be shown in log - bool colorlog_restricted_enabled(); - -private: - const int RELEASE = 2; - const int MAJOR_VERSION = 7; - const int MINOR_VERSION = 0; - - QString current_theme = "default"; - - QVector server_list; - QVector favorite_list; - -private slots: - void ms_connect_finished(bool connected, bool will_retry); - -public slots: - void server_disconnected(); - void loading_cancelled(); -}; - -#endif // AOAPPLICATION_H +#ifndef AOAPPLICATION_H +#define AOAPPLICATION_H + +#include "aopacket.h" +#include "datatypes.h" +#include "discord_rich_presence.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include + +class NetworkManager; +class Lobby; +class Courtroom; + +class AOApplication : public QApplication +{ + Q_OBJECT + +public: + AOApplication(int &argc, char **argv); + ~AOApplication(); + + NetworkManager *net_manager; + Lobby *w_lobby; + Courtroom *w_courtroom; + AttorneyOnline::Discord *discord; + + bool lobby_constructed = false; + bool courtroom_constructed = false; + + void construct_lobby(); + void destruct_lobby(); + + void construct_courtroom(); + void destruct_courtroom(); + + void ms_packet_received(AOPacket *p_packet); + void server_packet_received(AOPacket *p_packet); + + void send_ms_packet(AOPacket *p_packet); + void send_server_packet(AOPacket *p_packet, bool encoded = true); + + void call_settings_menu(); + void call_announce_menu(Courtroom *court); + + /////////////////server metadata////////////////// + + unsigned int s_decryptor = 5; + bool encryption_needed = true; + + bool yellow_text_enabled = false; + bool prezoom_enabled = false; + bool flipping_enabled = false; + bool custom_objection_enabled = false; + bool improved_loading_enabled = false; + bool desk_mod_enabled = false; + bool evidence_enabled = false; + bool cccc_ic_support_enabled = false; + bool arup_enabled = false; + bool casing_alerts_enabled = false; + bool modcall_reason_enabled = false; + + ///////////////loading info/////////////////// + + //player number, it's hardly used but might be needed for some old servers + int s_pv = 0; + + QString server_software = ""; + + int char_list_size = 0; + int loaded_chars = 0; + int generated_chars = 0; + int evidence_list_size = 0; + int loaded_evidence = 0; + int music_list_size = 0; + int loaded_music = 0; + + bool courtroom_loaded = false; + + //////////////////versioning/////////////// + + const int get_release() const { return RELEASE; } + const int get_major_version() const { return MAJOR_VERSION; } + const int get_minor_version() const { return MINOR_VERSION; } + QString get_version_string(); + + /////////////////////////////////////////// + + void set_favorite_list(); + QVector& get_favorite_list() {return favorite_list;} + void add_favorite_server(int p_server); + + void set_server_list(); + QVector& get_server_list() {return server_list;} + + //reads the theme from config.ini and sets it accordingly + void reload_theme(); + + //Returns the character the player has currently selected + QString get_current_char(); + + //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_character_path(QString p_char, QString p_file); + QString get_sounds_path(QString p_file); + QString get_music_path(QString p_song); + QString get_background_path(QString p_file); + QString get_default_background_path(QString p_file); + QString get_evidence_path(QString p_file); + QString get_case_sensitive_path(QString p_file); + + ////// Functions for reading and writing files ////// + // Implementations file_functions.cpp + + // Instead of reinventing the wheel, we'll use a QSettings class. + QSettings *configini; + + //Reads the theme from config.ini and loads it into the current_theme variable + QString read_theme(); + + //Returns the value of ooc_name in config.ini + QString get_ooc_name(); + + //Returns the blip rate from config.ini + int read_blip_rate(); + + //Returns true if blank blips is enabled in config.ini and false otherwise + bool get_blank_blip(); + + //Returns the value of default_music in config.ini + int get_default_music(); + + //Returns the value of default_sfx in config.ini + int get_default_sfx(); + + //Returns the value of default_blip in config.ini + int get_default_blip(); + + // Returns the value of whether Discord should be enabled on startup + // from the config.ini. + bool is_discord_enabled(); + + // Returns the value of the maximum amount of lines the IC chatlog + // may contain, from config.ini. + int get_max_log_size(); + + // Returns whether the log should go upwards (new behaviour) + // or downwards (vanilla behaviour). + bool get_log_goes_downwards(); + + // Returns the username the user may have set in config.ini. + QString get_default_username(); + + // Returns the audio device used for the client. + QString get_audio_output_device(); + + // Returns whether the user would like to have custom shownames on by default. + bool get_showname_enabled_by_default(); + + //Returns the list of words in callwords.ini + QStringList get_call_words(); + + //Appends the argument string to serverlist.txt + void write_to_serverlist_txt(QString p_line); + + //Returns the contents of serverlist.txt + QVector read_serverlist_txt(); + + //Returns the value of p_identifier in the design.ini file in p_design_path + QString read_design_ini(QString p_identifier, QString p_design_path); + + //Returns the coordinates of widget with p_identifier from p_file + QPoint get_button_spacing(QString p_identifier, QString p_file); + + //Returns the dimensions of widget with specified identifier from p_file + pos_size_type get_element_dimensions(QString p_identifier, QString p_file); + + //Returns the name of the font with p_identifier from p_file + QString get_font_name(QString p_identifier, QString p_file); + + + //Returns the value of font_size with p_identifier from p_file + int get_font_size(QString p_identifier, QString p_file); + + //Returns the color with p_identifier from p_file + QColor get_color(QString p_identifier, QString p_file); + + // Returns the colour 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); + + //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, fall back to a gif. + QString get_image_suffix(QString path_to_check); + + //Returns the value of p_search_line within target_tag and terminator_tag + QString read_char_ini(QString p_char, QString p_search_line, QString target_tag); + + //Returns the side of the p_char character from that characters ini file + QString get_char_side(QString p_char); + + //Returns the showname from the ini of p_char + QString get_showname(QString p_char); + + //Returns the value of chat from the specific p_char's ini file + QString get_chat(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); + + //Same as above, but only returns if it has a % in front(refer to Preanims section in the manual) + int get_ao2_preanim_duration(QString p_char, QString p_emote); + + //Not in use + int get_text_delay(QString p_char, QString p_emote); + + // Returns the custom realisation used by the character. + QString get_custom_realization(QString p_char); + + //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); + + //Returns the emote comment of p_char's p_emote + QString get_emote_comment(QString p_char, int p_emote); + + //Returns the base name of p_char's p_emote + QString get_emote(QString p_char, int p_emote); + + //Returns the preanimation name of p_char's p_emote + QString get_pre_emote(QString p_char, int p_emote); + + //Returns the sfx of p_char's p_emote + QString get_sfx_name(QString p_char, int p_emote); + + //Not in use + int get_sfx_delay(QString p_char, int p_emote); + + //Returns the modifier for p_char's p_emote + int get_emote_mod(QString p_char, int p_emote); + + //Returns the desk modifier for p_char's p_emote + int get_desk_mod(QString p_char, int p_emote); + + //Returns p_char's gender + QString get_gender(QString p_char); + + // ====== + // These are all casing-related settings. + // ====== + + // Returns if the user has casing alerts enabled. + bool get_casing_enabled(); + + // Returns if the user wants to get alerts for the defence role. + bool get_casing_defence_enabled(); + + // Same for prosecution. + bool get_casing_prosecution_enabled(); + + // Same for judge. + bool get_casing_judge_enabled(); + + // Same for juror. + bool get_casing_juror_enabled(); + + // Same for steno. + bool get_casing_steno_enabled(); + + // Same for CM. + bool get_casing_cm_enabled(); + + // Get the message for the CM for casing alerts. + QString get_casing_can_host_cases(); + +private: + const int RELEASE = 2; + const int MAJOR_VERSION = 6; + const int MINOR_VERSION = 2; + + QString current_theme = "default"; + + QVector server_list; + QVector favorite_list; + +private slots: + void ms_connect_finished(bool connected, bool will_retry); + +public slots: + void server_disconnected(); + void loading_cancelled(); +}; + +#endif // AOAPPLICATION_H diff --git a/include/aoblipplayer.h b/include/aoblipplayer.h index 4520120..102a040 100644 --- a/include/aoblipplayer.h +++ b/include/aoblipplayer.h @@ -9,32 +9,32 @@ #include "aoapplication.h" -#include #include #include +#include -class AOBlipPlayer { + +class AOBlipPlayer +{ public: AOBlipPlayer(QWidget *parent, AOApplication *p_ao_app); void set_blips(QString p_sfx); void blip_tick(); - void set_volume(qreal p_volume); + void set_volume(int p_volume); int m_cycle = 0; private: QWidget *m_parent; AOApplication *ao_app; - qreal m_volume; - void set_volume_internal(qreal p_volume); - -#if defined(BASSAUDIO) + int m_volume; + #if defined(BASSAUDIO) HSTREAM m_stream_list[5]; -#elif defined(QTAUDIO) + #elif defined(QTAUDIO) QSoundEffect m_blips; -#endif + #endif }; #endif // AOBLIPPLAYER_H diff --git a/include/aobutton.h b/include/aobutton.h index f575885..4b7209a 100644 --- a/include/aobutton.h +++ b/include/aobutton.h @@ -3,10 +3,11 @@ #include "aoapplication.h" -#include #include +#include -class AOButton : public QPushButton { +class AOButton : public QPushButton +{ Q_OBJECT public: diff --git a/include/aocaseannouncerdialog.h b/include/aocaseannouncerdialog.h index 89080de..a238c3f 100644 --- a/include/aocaseannouncerdialog.h +++ b/include/aocaseannouncerdialog.h @@ -4,21 +4,20 @@ #include "aoapplication.h" #include "courtroom.h" -#include -#include #include +#include +#include #include +#include #include #include -#include -class AOCaseAnnouncerDialog : public QDialog { +class AOCaseAnnouncerDialog : public QDialog +{ Q_OBJECT public: - explicit AOCaseAnnouncerDialog(QWidget *parent = nullptr, - AOApplication *p_ao_app = nullptr, - Courtroom *p_court = nullptr); + explicit AOCaseAnnouncerDialog(QWidget *parent = nullptr, AOApplication *p_ao_app = nullptr, Courtroom *p_court = nullptr); private: AOApplication *ao_app; @@ -37,7 +36,6 @@ private: QCheckBox *ui_judge_needed; QCheckBox *ui_juror_needed; QCheckBox *ui_steno_needed; - QCheckBox *ui_witness_needed; public slots: void ok_pressed(); diff --git a/include/aocharbutton.h b/include/aocharbutton.h index dd27e62..f372cdf 100644 --- a/include/aocharbutton.h +++ b/include/aocharbutton.h @@ -4,17 +4,17 @@ #include "aoapplication.h" #include "aoimage.h" -#include #include #include #include +#include -class AOCharButton : public QPushButton { +class AOCharButton : public QPushButton +{ Q_OBJECT public: - AOCharButton(QWidget *parent, AOApplication *p_ao_app, int x_pos, int y_pos, - bool is_taken); + AOCharButton(QWidget *parent, AOApplication *p_ao_app, int x_pos, int y_pos, bool is_taken); AOApplication *ao_app; diff --git a/include/aocharmovie.h b/include/aocharmovie.h index f62820b..7ef7da3 100644 --- a/include/aocharmovie.h +++ b/include/aocharmovie.h @@ -1,17 +1,16 @@ #ifndef AOCHARMOVIE_H #define AOCHARMOVIE_H -#include "include/aosfxplayer.h" -#include "include/courtroom.h" +#include +#include +#include #include #include -#include -#include -#include -#include class AOApplication; -class AOCharMovie : public QLabel { + +class AOCharMovie : public QLabel +{ Q_OBJECT public: @@ -22,24 +21,12 @@ public: void play_talking(QString p_char, QString p_emote); void play_idle(QString p_char, QString p_emote); - void set_flipped(bool p_flipped) { m_flipped = p_flipped; } - void LoadImageWithStupidMethodForFlipSupport(QImage image); + void set_flipped(bool p_flipped) {m_flipped = p_flipped;} + void stop(); - void play_frame_sfx(); - - void sfx_two_network_boogaloo(); - void screenshake_two_network_boogaloo(); - void realization_two_network_boogaloo(); - - AOSfxPlayer *frame_specific_sfx_player; - Courtroom *mycourtroom; - QString frame_sfx_hellstring = ""; - QString frame_screenshake_hellstring = ""; - QString frame_realization_hellstring = ""; - bool use_networked_framehell = false; - void move(int ax, int ay); + void combo_resize(int w, int h); private: @@ -48,17 +35,10 @@ private: QMovie *m_movie; QVector movie_frames; QTimer *preanim_timer; - QTimer *ticker; - QString last_path; - QString current_emote; - QString current_char; - int default_w; - int default_h; const int time_mod = 62; - // These are the X and Y values before they are fixed based on the sprite's - // width. + // These are the X and Y values before they are fixed based on the sprite's width. int x = 0; int y = 0; @@ -70,7 +50,8 @@ signals: void done(); private slots: + void frame_change(int n_frame); void timer_done(); - void movie_ticker(); }; + #endif // AOCHARMOVIE_H diff --git a/include/aoemotebutton.h b/include/aoemotebutton.h index acf0b48..c99a73b 100644 --- a/include/aoemotebutton.h +++ b/include/aoemotebutton.h @@ -3,21 +3,22 @@ #include "aoapplication.h" -#include #include +#include -class AOEmoteButton : public QPushButton { +class AOEmoteButton : public QPushButton +{ Q_OBJECT public: AOEmoteButton(QWidget *p_parent, AOApplication *p_ao_app, int p_x, int p_y); - // void set_on(QString p_char, int p_emote); - // void set_off(QString p_char, int p_emote); + //void set_on(QString p_char, int p_emote); + //void set_off(QString p_char, int p_emote); void set_image(QString p_char, int p_emote, QString suffix); - void set_id(int p_id) { m_id = p_id; } - int get_id() { return m_id; } + void set_id(int p_id) {m_id = p_id;} + int get_id() {return m_id;} private: QWidget *parent; diff --git a/include/aoevidencebutton.h b/include/aoevidencebutton.h index b56bfb1..80b747c 100644 --- a/include/aoevidencebutton.h +++ b/include/aoevidencebutton.h @@ -4,21 +4,21 @@ #include "aoapplication.h" #include "aoimage.h" -#include #include #include +#include -class AOEvidenceButton : public QPushButton { +class AOEvidenceButton : public QPushButton +{ Q_OBJECT public: - AOEvidenceButton(QWidget *p_parent, AOApplication *p_ao_app, int p_x, - int p_y); + AOEvidenceButton(QWidget *p_parent, AOApplication *p_ao_app, int p_x, int p_y); void reset(); void set_image(QString p_image); void set_theme_image(QString p_image); - void set_id(int p_id) { m_id = p_id; } + void set_id(int p_id) {m_id = p_id;} void set_selected(bool p_selected); diff --git a/include/aoevidencedisplay.h b/include/aoevidencedisplay.h index 1d6280d..13ca00d 100644 --- a/include/aoevidencedisplay.h +++ b/include/aoevidencedisplay.h @@ -4,18 +4,19 @@ #include "aoapplication.h" #include "aosfxplayer.h" -#include #include #include +#include -class AOEvidenceDisplay : public QLabel { +class AOEvidenceDisplay : public QLabel +{ Q_OBJECT public: AOEvidenceDisplay(QWidget *p_parent, AOApplication *p_ao_app); void show_evidence(QString p_evidence_image, bool is_left_side, int p_volume); - QLabel *get_evidence_icon(); + QLabel* get_evidence_icon(); void reset(); private: diff --git a/include/aoimage.h b/include/aoimage.h index c4fdf2e..4713be0 100644 --- a/include/aoimage.h +++ b/include/aoimage.h @@ -1,14 +1,15 @@ -// This class represents a static theme-dependent image +//This class represents a static theme-dependent image #ifndef AOIMAGE_H #define AOIMAGE_H #include "aoapplication.h" -#include #include +#include -class AOImage : public QLabel { +class AOImage : public QLabel +{ public: AOImage(QWidget *parent, AOApplication *p_ao_app); ~AOImage(); diff --git a/include/aolineedit.h b/include/aolineedit.h index 70f1f97..ce17680 100644 --- a/include/aolineedit.h +++ b/include/aolineedit.h @@ -4,7 +4,8 @@ #include #include -class AOLineEdit : public QLineEdit { +class AOLineEdit : public QLineEdit +{ Q_OBJECT public: @@ -18,6 +19,8 @@ signals: private slots: void on_enter_pressed(); + + }; #endif // AOLINEEDIT_H diff --git a/include/aomovie.h b/include/aomovie.h index caa1baa..1f278bf 100644 --- a/include/aomovie.h +++ b/include/aomovie.h @@ -7,23 +7,21 @@ class Courtroom; class AOApplication; -class AOMovie : public QLabel { +class AOMovie : public QLabel +{ Q_OBJECT public: AOMovie(QWidget *p_parent, AOApplication *p_ao_app); void set_play_once(bool p_play_once); - void start_timer(int delay); - void play(QString p_gif, QString p_char = "", QString p_custom_theme = "", - int default_duration = 0); + void play(QString p_gif, QString p_char = "", QString p_custom_theme = ""); void combo_resize(int w, int h); void stop(); private: QMovie *m_movie; AOApplication *ao_app; - QTimer *timer; bool play_once = true; signals: @@ -31,7 +29,6 @@ signals: private slots: void frame_change(int n_frame); - void timer_done(); }; #endif // AOMOVIE_H diff --git a/include/aomusicplayer.h b/include/aomusicplayer.h index 5181630..b34267c 100644 --- a/include/aomusicplayer.h +++ b/include/aomusicplayer.h @@ -6,40 +6,32 @@ #elif defined(QTAUDIO) #include #endif - #include "aoapplication.h" -#include -#include -#include #include #include +#include #if defined(BASSAUDIO) -class AOMusicPlayer : public QObject { - Q_OBJECT +class AOMusicPlayer +{ public: AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app); - virtual ~AOMusicPlayer(); + ~AOMusicPlayer(); void play(QString p_song); void set_volume(int p_value); - void kill_loop(); - QString get_path(); - bool enable_looping = true; - private: QWidget *m_parent; AOApplication *ao_app; int m_volume = 0; - QString f_path; - HSTREAM m_stream; }; #elif defined(QTAUDIO) -class AOMusicPlayer : public QObject { +class AOMusicPlayer +{ public: AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app); ~AOMusicPlayer(); @@ -47,21 +39,16 @@ public: void play(QString p_song); void set_volume(int p_value); - void kill_loop(); - QString get_path(); - bool enable_looping = true; - private: + QMediaPlayer m_player; QWidget *m_parent; AOApplication *ao_app; - QMediaPlayer m_player; - int m_volume = 0; - QString f_path; }; #else -class AOMusicPlayer : public QObject { +class AOMusicPlayer +{ public: AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app); ~AOMusicPlayer(); @@ -69,16 +56,9 @@ public: void play(QString p_song); void set_volume(int p_value); - void kill_loop(); - QString get_path(); - bool enable_looping = true; - private: QWidget *m_parent; AOApplication *ao_app; - - int m_volume = 0; - QString f_path; }; #endif diff --git a/include/aooptionsdialog.h b/include/aooptionsdialog.h index 9a1429a..a65e3f5 100644 --- a/include/aooptionsdialog.h +++ b/include/aooptionsdialog.h @@ -1,153 +1,115 @@ -#ifndef AOOPTIONSDIALOG_H -#define AOOPTIONSDIALOG_H - -#include "aoapplication.h" - -#ifdef BASSAUDIO -#include "bass.h" -#elif defined QTAUDIO -#include -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -class AOOptionsDialog : public QDialog { - Q_OBJECT -public: - explicit AOOptionsDialog(QWidget *parent = nullptr, - AOApplication *p_ao_app = nullptr); - -private: - AOApplication *ao_app; - - QVBoxLayout *ui_vertical_layout; - QTabWidget *ui_settings_tabs; - - QWidget *ui_gameplay_tab; - QWidget *ui_form_layout_widget; - QFormLayout *ui_gameplay_form; - QLabel *ui_theme_label; - QComboBox *ui_theme_combobox; - QFrame *ui_theme_log_divider; - QLabel *ui_downwards_lbl; - QCheckBox *ui_downwards_cb; - QLabel *ui_length_lbl; - QSpinBox *ui_length_spinbox; - QLabel *ui_pun_delay; - QCheckBox *ui_pun_delay_cb; - QLabel *ui_slower_blips_lb; - QCheckBox *ui_slower_blips_cb; - QLineEdit *ui_username_textbox; - QLabel *ui_username_lbl; - QLabel *ui_showname_lbl; - QCheckBox *ui_showname_cb; - QFrame *ui_net_divider; - QLabel *ui_ms_lbl; - QLineEdit *ui_ms_textbox; - QLabel *ui_discord_lbl; - QLabel *ui_epilepsy_lbl; - QCheckBox *ui_epilepsy_cb; - - QCheckBox *ui_discord_cb; - QLabel *ui_language_label; - QComboBox *ui_language_combobox; - - QLabel *ui_keepevi_lbl; - QCheckBox *ui_keepevi_cb; - - QLabel *ui_keepcobj_lbl; - QCheckBox *ui_keepcobj_cb; - - QWidget *ui_callwords_tab; - QWidget *ui_callwords_widget; - QVBoxLayout *ui_callwords_layout; - QPlainTextEdit *ui_callwords_textbox; - QLabel *ui_callwords_explain_lbl; - QCheckBox *ui_callwords_char_textbox; - - QWidget *ui_audio_tab; - QWidget *ui_audio_widget; - QFormLayout *ui_audio_layout; - QLabel *ui_audio_device_lbl; - QComboBox *ui_audio_device_combobox; - QFrame *ui_audio_volume_divider; - QSpinBox *ui_music_volume_spinbox; - QLabel *ui_music_volume_lbl; - QSpinBox *ui_sfx_volume_spinbox; - QLabel *ui_loopsfx_lbl; - QCheckBox *ui_loopsfx_cb; - QLabel *ui_objectmusic_lbl; - QCheckBox *ui_objectmusic_cb; - - QSpinBox *ui_blips_volume_spinbox; - QLabel *ui_sfx_volume_lbl; - QLabel *ui_blips_volume_lbl; - QFrame *ui_volume_blip_divider; - QSpinBox *ui_bliprate_spinbox; - QLabel *ui_bliprate_lbl; - QCheckBox *ui_blank_blips_cb; - QLabel *ui_blank_blips_lbl; - QDialogButtonBox *ui_settings_buttons; - - QWidget *ui_casing_tab; - QWidget *ui_casing_widget; - QFormLayout *ui_casing_layout; - QLabel *ui_casing_supported_lbl; - QLabel *ui_casing_enabled_lbl; - QCheckBox *ui_casing_enabled_cb; - QLabel *ui_casing_def_lbl; - QCheckBox *ui_casing_def_cb; - QLabel *ui_casing_pro_lbl; - QCheckBox *ui_casing_pro_cb; - QLabel *ui_casing_jud_lbl; - QCheckBox *ui_casing_jud_cb; - QLabel *ui_casing_jur_lbl; - QCheckBox *ui_casing_jur_cb; - QLabel *ui_casing_steno_lbl; - QCheckBox *ui_casing_steno_cb; - QLabel *ui_casing_cm_lbl; - QCheckBox *ui_casing_cm_cb; - QLabel *ui_casing_wit_lbl; - QCheckBox *ui_casing_wit_cb; - QLabel *ui_casing_cm_cases_lbl; - QLineEdit *ui_casing_cm_cases_textbox; - - QWidget *ui_other_tab; - QWidget *ui_other_widget; - QFormLayout *ui_other_layout; - QLabel *ui_other_fancy_icl_enabled_lb; - QCheckBox *ui_other_fancy_icl_enabled_cb; - QLabel *ui_other_mirror_icl_enabled_lb; - QCheckBox *ui_other_mirror_icl_enabled_cb; - - QLabel *ui_other_fancy_icl_limit_lb; - QCheckBox *ui_other_fancy_icl_limit_cb; - - bool needs_default_audiodev(); - -signals: - -public slots: - void save_pressed(); - void discard_pressed(); -}; - -#endif // AOOPTIONSDIALOG_H +#ifndef AOOPTIONSDIALOG_H +#define AOOPTIONSDIALOG_H + +#include "aoapplication.h" +#include "bass.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +class AOOptionsDialog: public QDialog +{ + Q_OBJECT +public: + explicit AOOptionsDialog(QWidget *parent = nullptr, AOApplication *p_ao_app = nullptr); + +private: + AOApplication *ao_app; + + QVBoxLayout *ui_vertical_layout; + QTabWidget *ui_settings_tabs; + + QWidget *ui_gameplay_tab; + QWidget *ui_form_layout_widget; + QFormLayout *ui_gameplay_form; + QLabel *ui_theme_label; + QComboBox *ui_theme_combobox; + QFrame *ui_theme_log_divider; + QLabel *ui_downwards_lbl; + QCheckBox *ui_downwards_cb; + QLabel *ui_length_lbl; + QSpinBox *ui_length_spinbox; + QFrame *ui_log_names_divider; + QLineEdit *ui_username_textbox; + QLabel *ui_username_lbl; + QLabel *ui_showname_lbl; + QCheckBox *ui_showname_cb; + QFrame *ui_net_divider; + QLabel *ui_ms_lbl; + QLineEdit *ui_ms_textbox; + QLabel *ui_discord_lbl; + QCheckBox *ui_discord_cb; + + QWidget *ui_callwords_tab; + QWidget *ui_callwords_widget; + QVBoxLayout *ui_callwords_layout; + QPlainTextEdit *ui_callwords_textbox; + QLabel *ui_callwords_explain_lbl; + QCheckBox *ui_callwords_char_textbox; + + QWidget *ui_audio_tab; + QWidget *ui_audio_widget; + QFormLayout *ui_audio_layout; + QLabel *ui_audio_device_lbl; + QComboBox *ui_audio_device_combobox; + QFrame *ui_audio_volume_divider; + QSpinBox *ui_music_volume_spinbox; + QLabel *ui_music_volume_lbl; + QSpinBox *ui_sfx_volume_spinbox; + QSpinBox *ui_blips_volume_spinbox; + QLabel *ui_sfx_volume_lbl; + QLabel *ui_blips_volume_lbl; + QFrame *ui_volume_blip_divider; + QSpinBox *ui_bliprate_spinbox; + QLabel *ui_bliprate_lbl; + QCheckBox *ui_blank_blips_cb; + QLabel *ui_blank_blips_lbl; + QDialogButtonBox *ui_settings_buttons; + + QWidget *ui_casing_tab; + QWidget *ui_casing_widget; + QFormLayout *ui_casing_layout; + QLabel *ui_casing_supported_lbl; + QLabel *ui_casing_enabled_lbl; + QCheckBox *ui_casing_enabled_cb; + QLabel *ui_casing_def_lbl; + QCheckBox *ui_casing_def_cb; + QLabel *ui_casing_pro_lbl; + QCheckBox *ui_casing_pro_cb; + QLabel *ui_casing_jud_lbl; + QCheckBox *ui_casing_jud_cb; + QLabel *ui_casing_jur_lbl; + QCheckBox *ui_casing_jur_cb; + QLabel *ui_casing_steno_lbl; + QCheckBox *ui_casing_steno_cb; + QLabel *ui_casing_cm_lbl; + QCheckBox *ui_casing_cm_cb; + QLabel *ui_casing_cm_cases_lbl; + QLineEdit *ui_casing_cm_cases_textbox; + + bool needs_default_audiodev(); + +signals: + +public slots: + void save_pressed(); + void discard_pressed(); +}; + +#endif // AOOPTIONSDIALOG_H diff --git a/include/aopacket.h b/include/aopacket.h index 4097be8..21f6e0f 100644 --- a/include/aopacket.h +++ b/include/aopacket.h @@ -1,18 +1,19 @@ #ifndef AOPACKET_H #define AOPACKET_H -#include #include #include +#include -class AOPacket { +class AOPacket +{ public: AOPacket(QString p_packet_string); AOPacket(QString header, QStringList &p_contents); ~AOPacket(); - QString get_header() { return m_header; } - QStringList &get_contents() { return m_contents; } + QString get_header() {return m_header;} + QStringList &get_contents() {return m_contents;} QString to_string(); void encrypt_header(unsigned int p_key); diff --git a/include/aoscene.h b/include/aoscene.h index 7c1ef6f..b58c0fd 100644 --- a/include/aoscene.h +++ b/include/aoscene.h @@ -1,14 +1,15 @@ #ifndef AOSCENE_H #define AOSCENE_H -#include #include +#include #include class Courtroom; class AOApplication; -class AOScene : public QLabel { +class AOScene : public QLabel +{ Q_OBJECT public: explicit AOScene(QWidget *parent, AOApplication *p_ao_app); @@ -20,7 +21,7 @@ private: QWidget *m_parent; QMovie *m_movie; AOApplication *ao_app; - QString last_image; + }; #endif // AOSCENE_H diff --git a/include/aosfxplayer.h b/include/aosfxplayer.h index af3aef6..4b97685 100644 --- a/include/aosfxplayer.h +++ b/include/aosfxplayer.h @@ -9,34 +9,28 @@ #include "aoapplication.h" -#include -#include #include #include +#include -class AOSfxPlayer : public QObject { - Q_OBJECT +class AOSfxPlayer +{ public: AOSfxPlayer(QWidget *parent, AOApplication *p_ao_app); void play(QString p_sfx, QString p_char = "", QString shout = ""); void stop(); - void set_volume(qreal p_volume); - void setLooping(bool is_looping); + void set_volume(int p_volume); private: QWidget *m_parent; AOApplication *ao_app; - qreal m_volume = 0; - bool looping_sfx = false; - - void set_volume_internal(qreal p_volume); - -#if defined(BASSAUDIO) + #if defined(BASSAUDIO) HSTREAM m_stream; -#elif defined(QTAUDIO) + #elif defined(QTAUDIO) QSoundEffect m_sfx; -#endif + #endif + int m_volume = 0; }; #endif // AOSFXPLAYER_H diff --git a/include/aotextarea.h b/include/aotextarea.h index b816089..d44596b 100644 --- a/include/aotextarea.h +++ b/include/aotextarea.h @@ -1,25 +1,24 @@ #ifndef AOTEXTAREA_H #define AOTEXTAREA_H -#include -#include -#include #include +#include #include +#include +#include -class AOTextArea : public QTextBrowser { +class AOTextArea : public QTextBrowser +{ public: AOTextArea(QWidget *p_parent = nullptr); - void append_chatmessage(QString p_name, QString p_message, QString p_colour, - bool song); + void append_chatmessage(QString p_name, QString p_message, QString p_colour); void append_error(QString p_message); private: const QRegExp omnis_dank_url_regex = QRegExp("\\b(https?://\\S+\\.\\S+)\\b"); - void auto_scroll(QTextCursor old_cursor, int scrollbar_value, - bool is_scrolled_down); + void auto_scroll(QTextCursor old_cursor, int scrollbar_value, bool is_scrolled_down); }; #endif // AOTEXTAREA_H diff --git a/include/aotextedit.h b/include/aotextedit.h index 8d876f1..85909c6 100644 --- a/include/aotextedit.h +++ b/include/aotextedit.h @@ -3,7 +3,8 @@ #include -class AOTextEdit : public QPlainTextEdit { +class AOTextEdit : public QPlainTextEdit +{ Q_OBJECT public: AOTextEdit(QWidget *parent); @@ -16,6 +17,7 @@ signals: private slots: void on_enter_pressed(); + }; #endif // AOTEXTEDIT_H diff --git a/include/bass.h b/include/bass.h index a3687b9..1c50903 100644 --- a/include/bass.h +++ b/include/bass.h @@ -1,1217 +1,1139 @@ -/* - BASS 2.4 C/C++ header file - Copyright (c) 1999-2018 Un4seen Developments Ltd. - - See the BASS.CHM file for more detailed documentation -*/ - -#ifndef BASS_H -#define BASS_H - -#ifdef _WIN32 -#include -typedef unsigned __int64 QWORD; -#else -#include -#define WINAPI -#define CALLBACK -typedef uint8_t BYTE; -typedef uint16_t WORD; -typedef uint32_t DWORD; -typedef uint64_t QWORD; -#ifndef __OBJC__ -typedef int BOOL; -#endif -#ifndef TRUE -#define TRUE 1 -#define FALSE 0 -#endif -#define LOBYTE(a) (BYTE)(a) -#define HIBYTE(a) (BYTE)((a) >> 8) -#define LOWORD(a) (WORD)(a) -#define HIWORD(a) (WORD)((a) >> 16) -#define MAKEWORD(a, b) (WORD)(((a)&0xff) | ((b) << 8)) -#define MAKELONG(a, b) (DWORD)(((a)&0xffff) | ((b) << 16)) -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#define BASSVERSION 0x204 // API version -#define BASSVERSIONTEXT "2.4" - -#ifndef BASSDEF -#define BASSDEF(f) WINAPI f -#else -#define NOBASSOVERLOADS -#endif - -typedef DWORD HMUSIC; // MOD music handle -typedef DWORD HSAMPLE; // sample handle -typedef DWORD HCHANNEL; // playing sample's channel handle -typedef DWORD HSTREAM; // sample stream handle -typedef DWORD HRECORD; // recording handle -typedef DWORD HSYNC; // synchronizer handle -typedef DWORD HDSP; // DSP handle -typedef DWORD HFX; // DX8 effect handle -typedef DWORD HPLUGIN; // Plugin handle - -// Error codes returned by BASS_ErrorGetCode -#define BASS_OK 0 // all is OK -#define BASS_ERROR_MEM 1 // memory error -#define BASS_ERROR_FILEOPEN 2 // can't open the file -#define BASS_ERROR_DRIVER 3 // can't find a free/valid driver -#define BASS_ERROR_BUFLOST 4 // the sample buffer was lost -#define BASS_ERROR_HANDLE 5 // invalid handle -#define BASS_ERROR_FORMAT 6 // unsupported sample format -#define BASS_ERROR_POSITION 7 // invalid position -#define BASS_ERROR_INIT 8 // BASS_Init has not been successfully called -#define BASS_ERROR_START 9 // BASS_Start has not been successfully called -#define BASS_ERROR_SSL 10 // SSL/HTTPS support isn't available -#define BASS_ERROR_ALREADY 14 // already initialized/paused/whatever -#define BASS_ERROR_NOCHAN 18 // can't get a free channel -#define BASS_ERROR_ILLTYPE 19 // an illegal type was specified -#define BASS_ERROR_ILLPARAM 20 // an illegal parameter was specified -#define BASS_ERROR_NO3D 21 // no 3D support -#define BASS_ERROR_NOEAX 22 // no EAX support -#define BASS_ERROR_DEVICE 23 // illegal device number -#define BASS_ERROR_NOPLAY 24 // not playing -#define BASS_ERROR_FREQ 25 // illegal sample rate -#define BASS_ERROR_NOTFILE 27 // the stream is not a file stream -#define BASS_ERROR_NOHW 29 // no hardware voices available -#define BASS_ERROR_EMPTY 31 // the MOD music has no sequence data -#define BASS_ERROR_NONET 32 // no internet connection could be opened -#define BASS_ERROR_CREATE 33 // couldn't create the file -#define BASS_ERROR_NOFX 34 // effects are not available -#define BASS_ERROR_NOTAVAIL 37 // requested data/action is not available -#define BASS_ERROR_DECODE 38 // the channel is/isn't a "decoding channel" -#define BASS_ERROR_DX 39 // a sufficient DirectX version is not installed -#define BASS_ERROR_TIMEOUT 40 // connection timedout -#define BASS_ERROR_FILEFORM 41 // unsupported file format -#define BASS_ERROR_SPEAKER 42 // unavailable speaker -#define BASS_ERROR_VERSION 43 // invalid BASS version (used by add-ons) -#define BASS_ERROR_CODEC 44 // codec is not available/supported -#define BASS_ERROR_ENDED 45 // the channel/file has ended -#define BASS_ERROR_BUSY 46 // the device is busy -#define BASS_ERROR_UNKNOWN -1 // some other mystery problem - -// BASS_SetConfig options -#define BASS_CONFIG_BUFFER 0 -#define BASS_CONFIG_UPDATEPERIOD 1 -#define BASS_CONFIG_GVOL_SAMPLE 4 -#define BASS_CONFIG_GVOL_STREAM 5 -#define BASS_CONFIG_GVOL_MUSIC 6 -#define BASS_CONFIG_CURVE_VOL 7 -#define BASS_CONFIG_CURVE_PAN 8 -#define BASS_CONFIG_FLOATDSP 9 -#define BASS_CONFIG_3DALGORITHM 10 -#define BASS_CONFIG_NET_TIMEOUT 11 -#define BASS_CONFIG_NET_BUFFER 12 -#define BASS_CONFIG_PAUSE_NOPLAY 13 -#define BASS_CONFIG_NET_PREBUF 15 -#define BASS_CONFIG_NET_PASSIVE 18 -#define BASS_CONFIG_REC_BUFFER 19 -#define BASS_CONFIG_NET_PLAYLIST 21 -#define BASS_CONFIG_MUSIC_VIRTUAL 22 -#define BASS_CONFIG_VERIFY 23 -#define BASS_CONFIG_UPDATETHREADS 24 -#define BASS_CONFIG_DEV_BUFFER 27 -#define BASS_CONFIG_VISTA_TRUEPOS 30 -#define BASS_CONFIG_IOS_MIXAUDIO 34 -#define BASS_CONFIG_DEV_DEFAULT 36 -#define BASS_CONFIG_NET_READTIMEOUT 37 -#define BASS_CONFIG_VISTA_SPEAKERS 38 -#define BASS_CONFIG_IOS_SPEAKER 39 -#define BASS_CONFIG_MF_DISABLE 40 -#define BASS_CONFIG_HANDLES 41 -#define BASS_CONFIG_UNICODE 42 -#define BASS_CONFIG_SRC 43 -#define BASS_CONFIG_SRC_SAMPLE 44 +/* + BASS 2.4 C/C++ header file + Copyright (c) 1999-2018 Un4seen Developments Ltd. + + See the BASS.CHM file for more detailed documentation +*/ + +#ifndef BASS_H +#define BASS_H + +#ifdef _WIN32 +#include +typedef unsigned __int64 QWORD; +#else +#include +#define WINAPI +#define CALLBACK +typedef uint8_t BYTE; +typedef uint16_t WORD; +typedef uint32_t DWORD; +typedef uint64_t QWORD; +#ifndef __OBJC__ +typedef int BOOL; +#endif +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif +#define LOBYTE(a) (BYTE)(a) +#define HIBYTE(a) (BYTE)((a)>>8) +#define LOWORD(a) (WORD)(a) +#define HIWORD(a) (WORD)((a)>>16) +#define MAKEWORD(a,b) (WORD)(((a)&0xff)|((b)<<8)) +#define MAKELONG(a,b) (DWORD)(((a)&0xffff)|((b)<<16)) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define BASSVERSION 0x204 // API version +#define BASSVERSIONTEXT "2.4" + +#ifndef BASSDEF +#define BASSDEF(f) WINAPI f +#else +#define NOBASSOVERLOADS +#endif + +typedef DWORD HMUSIC; // MOD music handle +typedef DWORD HSAMPLE; // sample handle +typedef DWORD HCHANNEL; // playing sample's channel handle +typedef DWORD HSTREAM; // sample stream handle +typedef DWORD HRECORD; // recording handle +typedef DWORD HSYNC; // synchronizer handle +typedef DWORD HDSP; // DSP handle +typedef DWORD HFX; // DX8 effect handle +typedef DWORD HPLUGIN; // Plugin handle + +// Error codes returned by BASS_ErrorGetCode +#define BASS_OK 0 // all is OK +#define BASS_ERROR_MEM 1 // memory error +#define BASS_ERROR_FILEOPEN 2 // can't open the file +#define BASS_ERROR_DRIVER 3 // can't find a free/valid driver +#define BASS_ERROR_BUFLOST 4 // the sample buffer was lost +#define BASS_ERROR_HANDLE 5 // invalid handle +#define BASS_ERROR_FORMAT 6 // unsupported sample format +#define BASS_ERROR_POSITION 7 // invalid position +#define BASS_ERROR_INIT 8 // BASS_Init has not been successfully called +#define BASS_ERROR_START 9 // BASS_Start has not been successfully called +#define BASS_ERROR_SSL 10 // SSL/HTTPS support isn't available +#define BASS_ERROR_ALREADY 14 // already initialized/paused/whatever +#define BASS_ERROR_NOCHAN 18 // can't get a free channel +#define BASS_ERROR_ILLTYPE 19 // an illegal type was specified +#define BASS_ERROR_ILLPARAM 20 // an illegal parameter was specified +#define BASS_ERROR_NO3D 21 // no 3D support +#define BASS_ERROR_NOEAX 22 // no EAX support +#define BASS_ERROR_DEVICE 23 // illegal device number +#define BASS_ERROR_NOPLAY 24 // not playing +#define BASS_ERROR_FREQ 25 // illegal sample rate +#define BASS_ERROR_NOTFILE 27 // the stream is not a file stream +#define BASS_ERROR_NOHW 29 // no hardware voices available +#define BASS_ERROR_EMPTY 31 // the MOD music has no sequence data +#define BASS_ERROR_NONET 32 // no internet connection could be opened +#define BASS_ERROR_CREATE 33 // couldn't create the file +#define BASS_ERROR_NOFX 34 // effects are not available +#define BASS_ERROR_NOTAVAIL 37 // requested data/action is not available +#define BASS_ERROR_DECODE 38 // the channel is/isn't a "decoding channel" +#define BASS_ERROR_DX 39 // a sufficient DirectX version is not installed +#define BASS_ERROR_TIMEOUT 40 // connection timedout +#define BASS_ERROR_FILEFORM 41 // unsupported file format +#define BASS_ERROR_SPEAKER 42 // unavailable speaker +#define BASS_ERROR_VERSION 43 // invalid BASS version (used by add-ons) +#define BASS_ERROR_CODEC 44 // codec is not available/supported +#define BASS_ERROR_ENDED 45 // the channel/file has ended +#define BASS_ERROR_BUSY 46 // the device is busy +#define BASS_ERROR_UNKNOWN -1 // some other mystery problem + +// BASS_SetConfig options +#define BASS_CONFIG_BUFFER 0 +#define BASS_CONFIG_UPDATEPERIOD 1 +#define BASS_CONFIG_GVOL_SAMPLE 4 +#define BASS_CONFIG_GVOL_STREAM 5 +#define BASS_CONFIG_GVOL_MUSIC 6 +#define BASS_CONFIG_CURVE_VOL 7 +#define BASS_CONFIG_CURVE_PAN 8 +#define BASS_CONFIG_FLOATDSP 9 +#define BASS_CONFIG_3DALGORITHM 10 +#define BASS_CONFIG_NET_TIMEOUT 11 +#define BASS_CONFIG_NET_BUFFER 12 +#define BASS_CONFIG_PAUSE_NOPLAY 13 +#define BASS_CONFIG_NET_PREBUF 15 +#define BASS_CONFIG_NET_PASSIVE 18 +#define BASS_CONFIG_REC_BUFFER 19 +#define BASS_CONFIG_NET_PLAYLIST 21 +#define BASS_CONFIG_MUSIC_VIRTUAL 22 +#define BASS_CONFIG_VERIFY 23 +#define BASS_CONFIG_UPDATETHREADS 24 +#define BASS_CONFIG_DEV_BUFFER 27 +#define BASS_CONFIG_VISTA_TRUEPOS 30 +#define BASS_CONFIG_IOS_MIXAUDIO 34 +#define BASS_CONFIG_DEV_DEFAULT 36 +#define BASS_CONFIG_NET_READTIMEOUT 37 +#define BASS_CONFIG_VISTA_SPEAKERS 38 +#define BASS_CONFIG_IOS_SPEAKER 39 +#define BASS_CONFIG_MF_DISABLE 40 +#define BASS_CONFIG_HANDLES 41 +#define BASS_CONFIG_UNICODE 42 +#define BASS_CONFIG_SRC 43 +#define BASS_CONFIG_SRC_SAMPLE 44 #define BASS_CONFIG_ASYNCFILE_BUFFER 45 -#define BASS_CONFIG_OGG_PRESCAN 47 -#define BASS_CONFIG_MF_VIDEO 48 -#define BASS_CONFIG_AIRPLAY 49 -#define BASS_CONFIG_DEV_NONSTOP 50 -#define BASS_CONFIG_IOS_NOCATEGORY 51 -#define BASS_CONFIG_VERIFY_NET 52 -#define BASS_CONFIG_DEV_PERIOD 53 -#define BASS_CONFIG_FLOAT 54 -#define BASS_CONFIG_NET_SEEK 56 -#define BASS_CONFIG_AM_DISABLE 58 -#define BASS_CONFIG_NET_PLAYLIST_DEPTH 59 -#define BASS_CONFIG_NET_PREBUF_WAIT 60 - -// BASS_SetConfigPtr options -#define BASS_CONFIG_NET_AGENT 16 -#define BASS_CONFIG_NET_PROXY 17 -#define BASS_CONFIG_IOS_NOTIFY 46 - -// BASS_Init flags -#define BASS_DEVICE_8BITS 1 // 8 bit -#define BASS_DEVICE_MONO 2 // mono -#define BASS_DEVICE_3D 4 // enable 3D functionality -#define BASS_DEVICE_16BITS 8 // limit output to 16 bit -#define BASS_DEVICE_LATENCY 0x100 // calculate device latency (BASS_INFO struct) -#define BASS_DEVICE_CPSPEAKERS \ - 0x400 // detect speakers via Windows control panel -#define BASS_DEVICE_SPEAKERS 0x800 // force enabling of speaker assignment -#define BASS_DEVICE_NOSPEAKER 0x1000 // ignore speaker arrangement -#define BASS_DEVICE_DMIX 0x2000 // use ALSA "dmix" plugin -#define BASS_DEVICE_FREQ 0x4000 // set device sample rate -#define BASS_DEVICE_STEREO 0x8000 // limit output to stereo -#define BASS_DEVICE_HOG 0x10000 // hog/exclusive mode -#define BASS_DEVICE_AUDIOTRACK 0x20000 // use AudioTrack output -#define BASS_DEVICE_DSOUND 0x40000 // use DirectSound output - -// DirectSound interfaces (for use with BASS_GetDSoundObject) -#define BASS_OBJECT_DS 1 // IDirectSound -#define BASS_OBJECT_DS3DL 2 // IDirectSound3DListener - -// Device info structure -typedef struct { -#if defined(_WIN32_WCE) || \ - (WINAPI_FAMILY && WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP) - const wchar_t *name; // description - const wchar_t *driver; // driver -#else - const char *name; // description - const char *driver; // driver -#endif - DWORD flags; -} BASS_DEVICEINFO; - -// BASS_DEVICEINFO flags -#define BASS_DEVICE_ENABLED 1 -#define BASS_DEVICE_DEFAULT 2 -#define BASS_DEVICE_INIT 4 -#define BASS_DEVICE_LOOPBACK 8 - -#define BASS_DEVICE_TYPE_MASK 0xff000000 -#define BASS_DEVICE_TYPE_NETWORK 0x01000000 -#define BASS_DEVICE_TYPE_SPEAKERS 0x02000000 -#define BASS_DEVICE_TYPE_LINE 0x03000000 -#define BASS_DEVICE_TYPE_HEADPHONES 0x04000000 -#define BASS_DEVICE_TYPE_MICROPHONE 0x05000000 -#define BASS_DEVICE_TYPE_HEADSET 0x06000000 -#define BASS_DEVICE_TYPE_HANDSET 0x07000000 -#define BASS_DEVICE_TYPE_DIGITAL 0x08000000 -#define BASS_DEVICE_TYPE_SPDIF 0x09000000 -#define BASS_DEVICE_TYPE_HDMI 0x0a000000 -#define BASS_DEVICE_TYPE_DISPLAYPORT 0x40000000 - +#define BASS_CONFIG_OGG_PRESCAN 47 +#define BASS_CONFIG_MF_VIDEO 48 +#define BASS_CONFIG_AIRPLAY 49 +#define BASS_CONFIG_DEV_NONSTOP 50 +#define BASS_CONFIG_IOS_NOCATEGORY 51 +#define BASS_CONFIG_VERIFY_NET 52 +#define BASS_CONFIG_DEV_PERIOD 53 +#define BASS_CONFIG_FLOAT 54 +#define BASS_CONFIG_NET_SEEK 56 +#define BASS_CONFIG_AM_DISABLE 58 +#define BASS_CONFIG_NET_PLAYLIST_DEPTH 59 +#define BASS_CONFIG_NET_PREBUF_WAIT 60 + +// BASS_SetConfigPtr options +#define BASS_CONFIG_NET_AGENT 16 +#define BASS_CONFIG_NET_PROXY 17 +#define BASS_CONFIG_IOS_NOTIFY 46 + +// BASS_Init flags +#define BASS_DEVICE_8BITS 1 // 8 bit +#define BASS_DEVICE_MONO 2 // mono +#define BASS_DEVICE_3D 4 // enable 3D functionality +#define BASS_DEVICE_16BITS 8 // limit output to 16 bit +#define BASS_DEVICE_LATENCY 0x100 // calculate device latency (BASS_INFO struct) +#define BASS_DEVICE_CPSPEAKERS 0x400 // detect speakers via Windows control panel +#define BASS_DEVICE_SPEAKERS 0x800 // force enabling of speaker assignment +#define BASS_DEVICE_NOSPEAKER 0x1000 // ignore speaker arrangement +#define BASS_DEVICE_DMIX 0x2000 // use ALSA "dmix" plugin +#define BASS_DEVICE_FREQ 0x4000 // set device sample rate +#define BASS_DEVICE_STEREO 0x8000 // limit output to stereo +#define BASS_DEVICE_HOG 0x10000 // hog/exclusive mode +#define BASS_DEVICE_AUDIOTRACK 0x20000 // use AudioTrack output +#define BASS_DEVICE_DSOUND 0x40000 // use DirectSound output + +// DirectSound interfaces (for use with BASS_GetDSoundObject) +#define BASS_OBJECT_DS 1 // IDirectSound +#define BASS_OBJECT_DS3DL 2 // IDirectSound3DListener + +// Device info structure +typedef struct { +#if defined(_WIN32_WCE) || (WINAPI_FAMILY && WINAPI_FAMILY!=WINAPI_FAMILY_DESKTOP_APP) + const wchar_t *name; // description + const wchar_t *driver; // driver +#else + const char *name; // description + const char *driver; // driver +#endif + DWORD flags; +} BASS_DEVICEINFO; + +// BASS_DEVICEINFO flags +#define BASS_DEVICE_ENABLED 1 +#define BASS_DEVICE_DEFAULT 2 +#define BASS_DEVICE_INIT 4 +#define BASS_DEVICE_LOOPBACK 8 + +#define BASS_DEVICE_TYPE_MASK 0xff000000 +#define BASS_DEVICE_TYPE_NETWORK 0x01000000 +#define BASS_DEVICE_TYPE_SPEAKERS 0x02000000 +#define BASS_DEVICE_TYPE_LINE 0x03000000 +#define BASS_DEVICE_TYPE_HEADPHONES 0x04000000 +#define BASS_DEVICE_TYPE_MICROPHONE 0x05000000 +#define BASS_DEVICE_TYPE_HEADSET 0x06000000 +#define BASS_DEVICE_TYPE_HANDSET 0x07000000 +#define BASS_DEVICE_TYPE_DIGITAL 0x08000000 +#define BASS_DEVICE_TYPE_SPDIF 0x09000000 +#define BASS_DEVICE_TYPE_HDMI 0x0a000000 +#define BASS_DEVICE_TYPE_DISPLAYPORT 0x40000000 + // BASS_GetDeviceInfo flags -#define BASS_DEVICES_AIRPLAY 0x1000000 +#define BASS_DEVICES_AIRPLAY 0x1000000 +typedef struct { + DWORD flags; // device capabilities (DSCAPS_xxx flags) + DWORD hwsize; // size of total device hardware memory + DWORD hwfree; // size of free device hardware memory + DWORD freesam; // number of free sample slots in the hardware + DWORD free3d; // number of free 3D sample slots in the hardware + DWORD minrate; // min sample rate supported by the hardware + DWORD maxrate; // max sample rate supported by the hardware + BOOL eax; // device supports EAX? (always FALSE if BASS_DEVICE_3D was not used) + DWORD minbuf; // recommended minimum buffer length in ms (requires BASS_DEVICE_LATENCY) + DWORD dsver; // DirectSound version + DWORD latency; // delay (in ms) before start of playback (requires BASS_DEVICE_LATENCY) + DWORD initflags; // BASS_Init "flags" parameter + DWORD speakers; // number of speakers available + DWORD freq; // current output rate +} BASS_INFO; + +// BASS_INFO flags (from DSOUND.H) +#define DSCAPS_CONTINUOUSRATE 0x00000010 // supports all sample rates between min/maxrate +#define DSCAPS_EMULDRIVER 0x00000020 // device does NOT have hardware DirectSound support +#define DSCAPS_CERTIFIED 0x00000040 // device driver has been certified by Microsoft +#define DSCAPS_SECONDARYMONO 0x00000100 // mono +#define DSCAPS_SECONDARYSTEREO 0x00000200 // stereo +#define DSCAPS_SECONDARY8BIT 0x00000400 // 8 bit +#define DSCAPS_SECONDARY16BIT 0x00000800 // 16 bit + +// Recording device info structure +typedef struct { + DWORD flags; // device capabilities (DSCCAPS_xxx flags) + DWORD formats; // supported standard formats (WAVE_FORMAT_xxx flags) + DWORD inputs; // number of inputs + BOOL singlein; // TRUE = only 1 input can be set at a time + DWORD freq; // current input rate +} BASS_RECORDINFO; + +// BASS_RECORDINFO flags (from DSOUND.H) +#define DSCCAPS_EMULDRIVER DSCAPS_EMULDRIVER // device does NOT have hardware DirectSound recording support +#define DSCCAPS_CERTIFIED DSCAPS_CERTIFIED // device driver has been certified by Microsoft + +// defines for formats field of BASS_RECORDINFO (from MMSYSTEM.H) +#ifndef WAVE_FORMAT_1M08 +#define WAVE_FORMAT_1M08 0x00000001 /* 11.025 kHz, Mono, 8-bit */ +#define WAVE_FORMAT_1S08 0x00000002 /* 11.025 kHz, Stereo, 8-bit */ +#define WAVE_FORMAT_1M16 0x00000004 /* 11.025 kHz, Mono, 16-bit */ +#define WAVE_FORMAT_1S16 0x00000008 /* 11.025 kHz, Stereo, 16-bit */ +#define WAVE_FORMAT_2M08 0x00000010 /* 22.05 kHz, Mono, 8-bit */ +#define WAVE_FORMAT_2S08 0x00000020 /* 22.05 kHz, Stereo, 8-bit */ +#define WAVE_FORMAT_2M16 0x00000040 /* 22.05 kHz, Mono, 16-bit */ +#define WAVE_FORMAT_2S16 0x00000080 /* 22.05 kHz, Stereo, 16-bit */ +#define WAVE_FORMAT_4M08 0x00000100 /* 44.1 kHz, Mono, 8-bit */ +#define WAVE_FORMAT_4S08 0x00000200 /* 44.1 kHz, Stereo, 8-bit */ +#define WAVE_FORMAT_4M16 0x00000400 /* 44.1 kHz, Mono, 16-bit */ +#define WAVE_FORMAT_4S16 0x00000800 /* 44.1 kHz, Stereo, 16-bit */ +#endif + +// Sample info structure +typedef struct { + DWORD freq; // default playback rate + float volume; // default volume (0-1) + float pan; // default pan (-1=left, 0=middle, 1=right) + DWORD flags; // BASS_SAMPLE_xxx flags + DWORD length; // length (in bytes) + DWORD max; // maximum simultaneous playbacks + DWORD origres; // original resolution + DWORD chans; // number of channels + DWORD mingap; // minimum gap (ms) between creating channels + DWORD mode3d; // BASS_3DMODE_xxx mode + float mindist; // minimum distance + float maxdist; // maximum distance + DWORD iangle; // angle of inside projection cone + DWORD oangle; // angle of outside projection cone + float outvol; // delta-volume outside the projection cone + DWORD vam; // voice allocation/management flags (BASS_VAM_xxx) + DWORD priority; // priority (0=lowest, 0xffffffff=highest) +} BASS_SAMPLE; + +#define BASS_SAMPLE_8BITS 1 // 8 bit +#define BASS_SAMPLE_FLOAT 256 // 32 bit floating-point +#define BASS_SAMPLE_MONO 2 // mono +#define BASS_SAMPLE_LOOP 4 // looped +#define BASS_SAMPLE_3D 8 // 3D functionality +#define BASS_SAMPLE_SOFTWARE 16 // not using hardware mixing +#define BASS_SAMPLE_MUTEMAX 32 // mute at max distance (3D only) +#define BASS_SAMPLE_VAM 64 // DX7 voice allocation & management +#define BASS_SAMPLE_FX 128 // old implementation of DX8 effects +#define BASS_SAMPLE_OVER_VOL 0x10000 // override lowest volume +#define BASS_SAMPLE_OVER_POS 0x20000 // override longest playing +#define BASS_SAMPLE_OVER_DIST 0x30000 // override furthest from listener (3D only) + +#define BASS_STREAM_PRESCAN 0x20000 // enable pin-point seeking/length (MP3/MP2/MP1) +#define BASS_STREAM_AUTOFREE 0x40000 // automatically free the stream when it stop/ends +#define BASS_STREAM_RESTRATE 0x80000 // restrict the download rate of internet file streams +#define BASS_STREAM_BLOCK 0x100000 // download/play internet file stream in small blocks +#define BASS_STREAM_DECODE 0x200000 // don't play the stream, only decode (BASS_ChannelGetData) +#define BASS_STREAM_STATUS 0x800000 // give server status info (HTTP/ICY tags) in DOWNLOADPROC + +#define BASS_MP3_IGNOREDELAY 0x200 // ignore LAME/Xing/VBRI/iTunes delay & padding info +#define BASS_MP3_SETPOS BASS_STREAM_PRESCAN + +#define BASS_MUSIC_FLOAT BASS_SAMPLE_FLOAT +#define BASS_MUSIC_MONO BASS_SAMPLE_MONO +#define BASS_MUSIC_LOOP BASS_SAMPLE_LOOP +#define BASS_MUSIC_3D BASS_SAMPLE_3D +#define BASS_MUSIC_FX BASS_SAMPLE_FX +#define BASS_MUSIC_AUTOFREE BASS_STREAM_AUTOFREE +#define BASS_MUSIC_DECODE BASS_STREAM_DECODE +#define BASS_MUSIC_PRESCAN BASS_STREAM_PRESCAN // calculate playback length +#define BASS_MUSIC_CALCLEN BASS_MUSIC_PRESCAN +#define BASS_MUSIC_RAMP 0x200 // normal ramping +#define BASS_MUSIC_RAMPS 0x400 // sensitive ramping +#define BASS_MUSIC_SURROUND 0x800 // surround sound +#define BASS_MUSIC_SURROUND2 0x1000 // surround sound (mode 2) +#define BASS_MUSIC_FT2PAN 0x2000 // apply FastTracker 2 panning to XM files +#define BASS_MUSIC_FT2MOD 0x2000 // play .MOD as FastTracker 2 does +#define BASS_MUSIC_PT1MOD 0x4000 // play .MOD as ProTracker 1 does +#define BASS_MUSIC_NONINTER 0x10000 // non-interpolated sample mixing +#define BASS_MUSIC_SINCINTER 0x800000 // sinc interpolated sample mixing +#define BASS_MUSIC_POSRESET 0x8000 // stop all notes when moving position +#define BASS_MUSIC_POSRESETEX 0x400000 // stop all notes and reset bmp/etc when moving position +#define BASS_MUSIC_STOPBACK 0x80000 // stop the music on a backwards jump effect +#define BASS_MUSIC_NOSAMPLE 0x100000 // don't load the samples + +// Speaker assignment flags +#define BASS_SPEAKER_FRONT 0x1000000 // front speakers +#define BASS_SPEAKER_REAR 0x2000000 // rear/side speakers +#define BASS_SPEAKER_CENLFE 0x3000000 // center & LFE speakers (5.1) +#define BASS_SPEAKER_REAR2 0x4000000 // rear center speakers (7.1) +#define BASS_SPEAKER_N(n) ((n)<<24) // n'th pair of speakers (max 15) +#define BASS_SPEAKER_LEFT 0x10000000 // modifier: left +#define BASS_SPEAKER_RIGHT 0x20000000 // modifier: right +#define BASS_SPEAKER_FRONTLEFT BASS_SPEAKER_FRONT|BASS_SPEAKER_LEFT +#define BASS_SPEAKER_FRONTRIGHT BASS_SPEAKER_FRONT|BASS_SPEAKER_RIGHT +#define BASS_SPEAKER_REARLEFT BASS_SPEAKER_REAR|BASS_SPEAKER_LEFT +#define BASS_SPEAKER_REARRIGHT BASS_SPEAKER_REAR|BASS_SPEAKER_RIGHT +#define BASS_SPEAKER_CENTER BASS_SPEAKER_CENLFE|BASS_SPEAKER_LEFT +#define BASS_SPEAKER_LFE BASS_SPEAKER_CENLFE|BASS_SPEAKER_RIGHT +#define BASS_SPEAKER_REAR2LEFT BASS_SPEAKER_REAR2|BASS_SPEAKER_LEFT +#define BASS_SPEAKER_REAR2RIGHT BASS_SPEAKER_REAR2|BASS_SPEAKER_RIGHT + +#define BASS_ASYNCFILE 0x40000000 +#define BASS_UNICODE 0x80000000 + +#define BASS_RECORD_PAUSE 0x8000 // start recording paused +#define BASS_RECORD_ECHOCANCEL 0x2000 +#define BASS_RECORD_AGC 0x4000 + +// DX7 voice allocation & management flags +#define BASS_VAM_HARDWARE 1 +#define BASS_VAM_SOFTWARE 2 +#define BASS_VAM_TERM_TIME 4 +#define BASS_VAM_TERM_DIST 8 +#define BASS_VAM_TERM_PRIO 16 + +// Channel info structure +typedef struct { + DWORD freq; // default playback rate + DWORD chans; // channels + DWORD flags; // BASS_SAMPLE/STREAM/MUSIC/SPEAKER flags + DWORD ctype; // type of channel + DWORD origres; // original resolution + HPLUGIN plugin; // plugin + HSAMPLE sample; // sample + const char *filename; // filename +} BASS_CHANNELINFO; + +#define BASS_ORIGRES_FLOAT 0x10000 + +// BASS_CHANNELINFO types +#define BASS_CTYPE_SAMPLE 1 +#define BASS_CTYPE_RECORD 2 +#define BASS_CTYPE_STREAM 0x10000 +#define BASS_CTYPE_STREAM_OGG 0x10002 +#define BASS_CTYPE_STREAM_MP1 0x10003 +#define BASS_CTYPE_STREAM_MP2 0x10004 +#define BASS_CTYPE_STREAM_MP3 0x10005 +#define BASS_CTYPE_STREAM_AIFF 0x10006 +#define BASS_CTYPE_STREAM_CA 0x10007 +#define BASS_CTYPE_STREAM_MF 0x10008 +#define BASS_CTYPE_STREAM_AM 0x10009 +#define BASS_CTYPE_STREAM_DUMMY 0x18000 +#define BASS_CTYPE_STREAM_DEVICE 0x18001 +#define BASS_CTYPE_STREAM_WAV 0x40000 // WAVE flag, LOWORD=codec +#define BASS_CTYPE_STREAM_WAV_PCM 0x50001 +#define BASS_CTYPE_STREAM_WAV_FLOAT 0x50003 +#define BASS_CTYPE_MUSIC_MOD 0x20000 +#define BASS_CTYPE_MUSIC_MTM 0x20001 +#define BASS_CTYPE_MUSIC_S3M 0x20002 +#define BASS_CTYPE_MUSIC_XM 0x20003 +#define BASS_CTYPE_MUSIC_IT 0x20004 +#define BASS_CTYPE_MUSIC_MO3 0x00100 // MO3 flag + +typedef struct { + DWORD ctype; // channel type +#if defined(_WIN32_WCE) || (WINAPI_FAMILY && WINAPI_FAMILY!=WINAPI_FAMILY_DESKTOP_APP) + const wchar_t *name; // format description + const wchar_t *exts; // file extension filter (*.ext1;*.ext2;etc...) +#else + const char *name; // format description + const char *exts; // file extension filter (*.ext1;*.ext2;etc...) +#endif +} BASS_PLUGINFORM; + +typedef struct { + DWORD version; // version (same form as BASS_GetVersion) + DWORD formatc; // number of formats + const BASS_PLUGINFORM *formats; // the array of formats +} BASS_PLUGININFO; + +// 3D vector (for 3D positions/velocities/orientations) +typedef struct BASS_3DVECTOR { +#ifdef __cplusplus + BASS_3DVECTOR() {}; + BASS_3DVECTOR(float _x, float _y, float _z) : x(_x), y(_y), z(_z) {}; +#endif + float x; // +=right, -=left + float y; // +=up, -=down + float z; // +=front, -=behind +} BASS_3DVECTOR; + +// 3D channel modes +#define BASS_3DMODE_NORMAL 0 // normal 3D processing +#define BASS_3DMODE_RELATIVE 1 // position is relative to the listener +#define BASS_3DMODE_OFF 2 // no 3D processing + +// software 3D mixing algorithms (used with BASS_CONFIG_3DALGORITHM) +#define BASS_3DALG_DEFAULT 0 +#define BASS_3DALG_OFF 1 +#define BASS_3DALG_FULL 2 +#define BASS_3DALG_LIGHT 3 + +// EAX environments, use with BASS_SetEAXParameters +enum +{ + EAX_ENVIRONMENT_GENERIC, + EAX_ENVIRONMENT_PADDEDCELL, + EAX_ENVIRONMENT_ROOM, + EAX_ENVIRONMENT_BATHROOM, + EAX_ENVIRONMENT_LIVINGROOM, + EAX_ENVIRONMENT_STONEROOM, + EAX_ENVIRONMENT_AUDITORIUM, + EAX_ENVIRONMENT_CONCERTHALL, + EAX_ENVIRONMENT_CAVE, + EAX_ENVIRONMENT_ARENA, + EAX_ENVIRONMENT_HANGAR, + EAX_ENVIRONMENT_CARPETEDHALLWAY, + EAX_ENVIRONMENT_HALLWAY, + EAX_ENVIRONMENT_STONECORRIDOR, + EAX_ENVIRONMENT_ALLEY, + EAX_ENVIRONMENT_FOREST, + EAX_ENVIRONMENT_CITY, + EAX_ENVIRONMENT_MOUNTAINS, + EAX_ENVIRONMENT_QUARRY, + EAX_ENVIRONMENT_PLAIN, + EAX_ENVIRONMENT_PARKINGLOT, + EAX_ENVIRONMENT_SEWERPIPE, + EAX_ENVIRONMENT_UNDERWATER, + EAX_ENVIRONMENT_DRUGGED, + EAX_ENVIRONMENT_DIZZY, + EAX_ENVIRONMENT_PSYCHOTIC, + + EAX_ENVIRONMENT_COUNT // total number of environments +}; + +// EAX presets, usage: BASS_SetEAXParameters(EAX_PRESET_xxx) +#define EAX_PRESET_GENERIC EAX_ENVIRONMENT_GENERIC,0.5F,1.493F,0.5F +#define EAX_PRESET_PADDEDCELL EAX_ENVIRONMENT_PADDEDCELL,0.25F,0.1F,0.0F +#define EAX_PRESET_ROOM EAX_ENVIRONMENT_ROOM,0.417F,0.4F,0.666F +#define EAX_PRESET_BATHROOM EAX_ENVIRONMENT_BATHROOM,0.653F,1.499F,0.166F +#define EAX_PRESET_LIVINGROOM EAX_ENVIRONMENT_LIVINGROOM,0.208F,0.478F,0.0F +#define EAX_PRESET_STONEROOM EAX_ENVIRONMENT_STONEROOM,0.5F,2.309F,0.888F +#define EAX_PRESET_AUDITORIUM EAX_ENVIRONMENT_AUDITORIUM,0.403F,4.279F,0.5F +#define EAX_PRESET_CONCERTHALL EAX_ENVIRONMENT_CONCERTHALL,0.5F,3.961F,0.5F +#define EAX_PRESET_CAVE EAX_ENVIRONMENT_CAVE,0.5F,2.886F,1.304F +#define EAX_PRESET_ARENA EAX_ENVIRONMENT_ARENA,0.361F,7.284F,0.332F +#define EAX_PRESET_HANGAR EAX_ENVIRONMENT_HANGAR,0.5F,10.0F,0.3F +#define EAX_PRESET_CARPETEDHALLWAY EAX_ENVIRONMENT_CARPETEDHALLWAY,0.153F,0.259F,2.0F +#define EAX_PRESET_HALLWAY EAX_ENVIRONMENT_HALLWAY,0.361F,1.493F,0.0F +#define EAX_PRESET_STONECORRIDOR EAX_ENVIRONMENT_STONECORRIDOR,0.444F,2.697F,0.638F +#define EAX_PRESET_ALLEY EAX_ENVIRONMENT_ALLEY,0.25F,1.752F,0.776F +#define EAX_PRESET_FOREST EAX_ENVIRONMENT_FOREST,0.111F,3.145F,0.472F +#define EAX_PRESET_CITY EAX_ENVIRONMENT_CITY,0.111F,2.767F,0.224F +#define EAX_PRESET_MOUNTAINS EAX_ENVIRONMENT_MOUNTAINS,0.194F,7.841F,0.472F +#define EAX_PRESET_QUARRY EAX_ENVIRONMENT_QUARRY,1.0F,1.499F,0.5F +#define EAX_PRESET_PLAIN EAX_ENVIRONMENT_PLAIN,0.097F,2.767F,0.224F +#define EAX_PRESET_PARKINGLOT EAX_ENVIRONMENT_PARKINGLOT,0.208F,1.652F,1.5F +#define EAX_PRESET_SEWERPIPE EAX_ENVIRONMENT_SEWERPIPE,0.652F,2.886F,0.25F +#define EAX_PRESET_UNDERWATER EAX_ENVIRONMENT_UNDERWATER,1.0F,1.499F,0.0F +#define EAX_PRESET_DRUGGED EAX_ENVIRONMENT_DRUGGED,0.875F,8.392F,1.388F +#define EAX_PRESET_DIZZY EAX_ENVIRONMENT_DIZZY,0.139F,17.234F,0.666F +#define EAX_PRESET_PSYCHOTIC EAX_ENVIRONMENT_PSYCHOTIC,0.486F,7.563F,0.806F + +typedef DWORD (CALLBACK STREAMPROC)(HSTREAM handle, void *buffer, DWORD length, void *user); +/* User stream callback function. NOTE: A stream function should obviously be as quick +as possible, other streams (and MOD musics) can't be mixed until it's finished. +handle : The stream that needs writing +buffer : Buffer to write the samples in +length : Number of bytes to write +user : The 'user' parameter value given when calling BASS_StreamCreate +RETURN : Number of bytes written. Set the BASS_STREAMPROC_END flag to end the stream. */ + +#define BASS_STREAMPROC_END 0x80000000 // end of user stream flag + +// special STREAMPROCs +#define STREAMPROC_DUMMY (STREAMPROC*)0 // "dummy" stream +#define STREAMPROC_PUSH (STREAMPROC*)-1 // push stream +#define STREAMPROC_DEVICE (STREAMPROC*)-2 // device mix stream + +// BASS_StreamCreateFileUser file systems +#define STREAMFILE_NOBUFFER 0 +#define STREAMFILE_BUFFER 1 +#define STREAMFILE_BUFFERPUSH 2 + +// User file stream callback functions +typedef void (CALLBACK FILECLOSEPROC)(void *user); +typedef QWORD (CALLBACK FILELENPROC)(void *user); +typedef DWORD (CALLBACK FILEREADPROC)(void *buffer, DWORD length, void *user); +typedef BOOL (CALLBACK FILESEEKPROC)(QWORD offset, void *user); + +typedef struct { + FILECLOSEPROC *close; + FILELENPROC *length; + FILEREADPROC *read; + FILESEEKPROC *seek; +} BASS_FILEPROCS; + +// BASS_StreamPutFileData options +#define BASS_FILEDATA_END 0 // end & close the file + +// BASS_StreamGetFilePosition modes +#define BASS_FILEPOS_CURRENT 0 +#define BASS_FILEPOS_DECODE BASS_FILEPOS_CURRENT +#define BASS_FILEPOS_DOWNLOAD 1 +#define BASS_FILEPOS_END 2 +#define BASS_FILEPOS_START 3 +#define BASS_FILEPOS_CONNECTED 4 +#define BASS_FILEPOS_BUFFER 5 +#define BASS_FILEPOS_SOCKET 6 +#define BASS_FILEPOS_ASYNCBUF 7 +#define BASS_FILEPOS_SIZE 8 +#define BASS_FILEPOS_BUFFERING 9 + +typedef void (CALLBACK DOWNLOADPROC)(const void *buffer, DWORD length, void *user); +/* Internet stream download callback function. +buffer : Buffer containing the downloaded data... NULL=end of download +length : Number of bytes in the buffer +user : The 'user' parameter value given when calling BASS_StreamCreateURL */ + +// BASS_ChannelSetSync types +#define BASS_SYNC_POS 0 +#define BASS_SYNC_END 2 +#define BASS_SYNC_META 4 +#define BASS_SYNC_SLIDE 5 +#define BASS_SYNC_STALL 6 +#define BASS_SYNC_DOWNLOAD 7 +#define BASS_SYNC_FREE 8 +#define BASS_SYNC_SETPOS 11 +#define BASS_SYNC_MUSICPOS 10 +#define BASS_SYNC_MUSICINST 1 +#define BASS_SYNC_MUSICFX 3 +#define BASS_SYNC_OGG_CHANGE 12 +#define BASS_SYNC_MIXTIME 0x40000000 // flag: sync at mixtime, else at playtime +#define BASS_SYNC_ONETIME 0x80000000 // flag: sync only once, else continuously + +typedef void (CALLBACK SYNCPROC)(HSYNC handle, DWORD channel, DWORD data, void *user); +/* Sync callback function. NOTE: a sync callback function should be very +quick as other syncs can't be processed until it has finished. If the sync +is a "mixtime" sync, then other streams and MOD musics can't be mixed until +it's finished either. +handle : The sync that has occured +channel: Channel that the sync occured in +data : Additional data associated with the sync's occurance +user : The 'user' parameter given when calling BASS_ChannelSetSync */ + +typedef void (CALLBACK DSPPROC)(HDSP handle, DWORD channel, void *buffer, DWORD length, void *user); +/* DSP callback function. NOTE: A DSP function should obviously be as quick as +possible... other DSP functions, streams and MOD musics can not be processed +until it's finished. +handle : The DSP handle +channel: Channel that the DSP is being applied to +buffer : Buffer to apply the DSP to +length : Number of bytes in the buffer +user : The 'user' parameter given when calling BASS_ChannelSetDSP */ + +typedef BOOL (CALLBACK RECORDPROC)(HRECORD handle, const void *buffer, DWORD length, void *user); +/* Recording callback function. +handle : The recording handle +buffer : Buffer containing the recorded sample data +length : Number of bytes +user : The 'user' parameter value given when calling BASS_RecordStart +RETURN : TRUE = continue recording, FALSE = stop */ + +// BASS_ChannelIsActive return values +#define BASS_ACTIVE_STOPPED 0 +#define BASS_ACTIVE_PLAYING 1 +#define BASS_ACTIVE_STALLED 2 +#define BASS_ACTIVE_PAUSED 3 + +// Channel attributes +#define BASS_ATTRIB_FREQ 1 +#define BASS_ATTRIB_VOL 2 +#define BASS_ATTRIB_PAN 3 +#define BASS_ATTRIB_EAXMIX 4 +#define BASS_ATTRIB_NOBUFFER 5 +#define BASS_ATTRIB_VBR 6 +#define BASS_ATTRIB_CPU 7 +#define BASS_ATTRIB_SRC 8 +#define BASS_ATTRIB_NET_RESUME 9 +#define BASS_ATTRIB_SCANINFO 10 +#define BASS_ATTRIB_NORAMP 11 +#define BASS_ATTRIB_BITRATE 12 +#define BASS_ATTRIB_BUFFER 13 +#define BASS_ATTRIB_MUSIC_AMPLIFY 0x100 +#define BASS_ATTRIB_MUSIC_PANSEP 0x101 +#define BASS_ATTRIB_MUSIC_PSCALER 0x102 +#define BASS_ATTRIB_MUSIC_BPM 0x103 +#define BASS_ATTRIB_MUSIC_SPEED 0x104 +#define BASS_ATTRIB_MUSIC_VOL_GLOBAL 0x105 +#define BASS_ATTRIB_MUSIC_ACTIVE 0x106 +#define BASS_ATTRIB_MUSIC_VOL_CHAN 0x200 // + channel # +#define BASS_ATTRIB_MUSIC_VOL_INST 0x300 // + instrument # + +// BASS_ChannelSlideAttribute flags +#define BASS_SLIDE_LOG 0x1000000 + +// BASS_ChannelGetData flags +#define BASS_DATA_AVAILABLE 0 // query how much data is buffered +#define BASS_DATA_FIXED 0x20000000 // flag: return 8.24 fixed-point data +#define BASS_DATA_FLOAT 0x40000000 // flag: return floating-point sample data +#define BASS_DATA_FFT256 0x80000000 // 256 sample FFT +#define BASS_DATA_FFT512 0x80000001 // 512 FFT +#define BASS_DATA_FFT1024 0x80000002 // 1024 FFT +#define BASS_DATA_FFT2048 0x80000003 // 2048 FFT +#define BASS_DATA_FFT4096 0x80000004 // 4096 FFT +#define BASS_DATA_FFT8192 0x80000005 // 8192 FFT +#define BASS_DATA_FFT16384 0x80000006 // 16384 FFT +#define BASS_DATA_FFT32768 0x80000007 // 32768 FFT +#define BASS_DATA_FFT_INDIVIDUAL 0x10 // FFT flag: FFT for each channel, else all combined +#define BASS_DATA_FFT_NOWINDOW 0x20 // FFT flag: no Hanning window +#define BASS_DATA_FFT_REMOVEDC 0x40 // FFT flag: pre-remove DC bias +#define BASS_DATA_FFT_COMPLEX 0x80 // FFT flag: return complex data + +// BASS_ChannelGetLevelEx flags +#define BASS_LEVEL_MONO 1 +#define BASS_LEVEL_STEREO 2 +#define BASS_LEVEL_RMS 4 +#define BASS_LEVEL_VOLPAN 8 + +// BASS_ChannelGetTags types : what's returned +#define BASS_TAG_ID3 0 // ID3v1 tags : TAG_ID3 structure +#define BASS_TAG_ID3V2 1 // ID3v2 tags : variable length block +#define BASS_TAG_OGG 2 // OGG comments : series of null-terminated UTF-8 strings +#define BASS_TAG_HTTP 3 // HTTP headers : series of null-terminated ANSI strings +#define BASS_TAG_ICY 4 // ICY headers : series of null-terminated ANSI strings +#define BASS_TAG_META 5 // ICY metadata : ANSI string +#define BASS_TAG_APE 6 // APE tags : series of null-terminated UTF-8 strings +#define BASS_TAG_MP4 7 // MP4/iTunes metadata : series of null-terminated UTF-8 strings +#define BASS_TAG_WMA 8 // WMA tags : series of null-terminated UTF-8 strings +#define BASS_TAG_VENDOR 9 // OGG encoder : UTF-8 string +#define BASS_TAG_LYRICS3 10 // Lyric3v2 tag : ASCII string +#define BASS_TAG_CA_CODEC 11 // CoreAudio codec info : TAG_CA_CODEC structure +#define BASS_TAG_MF 13 // Media Foundation tags : series of null-terminated UTF-8 strings +#define BASS_TAG_WAVEFORMAT 14 // WAVE format : WAVEFORMATEEX structure +#define BASS_TAG_AM_MIME 15 // Android Media MIME type : ASCII string +#define BASS_TAG_AM_NAME 16 // Android Media codec name : ASCII string +#define BASS_TAG_RIFF_INFO 0x100 // RIFF "INFO" tags : series of null-terminated ANSI strings +#define BASS_TAG_RIFF_BEXT 0x101 // RIFF/BWF "bext" tags : TAG_BEXT structure +#define BASS_TAG_RIFF_CART 0x102 // RIFF/BWF "cart" tags : TAG_CART structure +#define BASS_TAG_RIFF_DISP 0x103 // RIFF "DISP" text tag : ANSI string +#define BASS_TAG_RIFF_CUE 0x104 // RIFF "cue " chunk : TAG_CUE structure +#define BASS_TAG_RIFF_SMPL 0x105 // RIFF "smpl" chunk : TAG_SMPL structure +#define BASS_TAG_APE_BINARY 0x1000 // + index #, binary APE tag : TAG_APE_BINARY structure +#define BASS_TAG_MUSIC_NAME 0x10000 // MOD music name : ANSI string +#define BASS_TAG_MUSIC_MESSAGE 0x10001 // MOD message : ANSI string +#define BASS_TAG_MUSIC_ORDERS 0x10002 // MOD order list : BYTE array of pattern numbers +#define BASS_TAG_MUSIC_AUTH 0x10003 // MOD author : UTF-8 string +#define BASS_TAG_MUSIC_INST 0x10100 // + instrument #, MOD instrument name : ANSI string +#define BASS_TAG_MUSIC_SAMPLE 0x10300 // + sample #, MOD sample name : ANSI string + +// ID3v1 tag structure +typedef struct { + char id[3]; + char title[30]; + char artist[30]; + char album[30]; + char year[4]; + char comment[30]; + BYTE genre; +} TAG_ID3; + +// Binary APE tag structure typedef struct { - DWORD flags; // device capabilities (DSCAPS_xxx flags) - DWORD hwsize; // size of total device hardware memory - DWORD hwfree; // size of free device hardware memory - DWORD freesam; // number of free sample slots in the hardware - DWORD free3d; // number of free 3D sample slots in the hardware - DWORD minrate; // min sample rate supported by the hardware - DWORD maxrate; // max sample rate supported by the hardware - BOOL - eax; // device supports EAX? (always FALSE if BASS_DEVICE_3D was not used) - DWORD minbuf; // recommended minimum buffer length in ms (requires - // BASS_DEVICE_LATENCY) - DWORD dsver; // DirectSound version - DWORD latency; // delay (in ms) before start of playback (requires - // BASS_DEVICE_LATENCY) - DWORD initflags; // BASS_Init "flags" parameter - DWORD speakers; // number of speakers available - DWORD freq; // current output rate -} BASS_INFO; - -// BASS_INFO flags (from DSOUND.H) -#define DSCAPS_CONTINUOUSRATE \ - 0x00000010 // supports all sample rates between min/maxrate -#define DSCAPS_EMULDRIVER \ - 0x00000020 // device does NOT have hardware DirectSound support -#define DSCAPS_CERTIFIED \ - 0x00000040 // device driver has been certified by Microsoft -#define DSCAPS_SECONDARYMONO 0x00000100 // mono -#define DSCAPS_SECONDARYSTEREO 0x00000200 // stereo -#define DSCAPS_SECONDARY8BIT 0x00000400 // 8 bit -#define DSCAPS_SECONDARY16BIT 0x00000800 // 16 bit - -// Recording device info structure -typedef struct { - DWORD flags; // device capabilities (DSCCAPS_xxx flags) - DWORD formats; // supported standard formats (WAVE_FORMAT_xxx flags) - DWORD inputs; // number of inputs - BOOL singlein; // TRUE = only 1 input can be set at a time - DWORD freq; // current input rate -} BASS_RECORDINFO; - -// BASS_RECORDINFO flags (from DSOUND.H) -#define DSCCAPS_EMULDRIVER \ - DSCAPS_EMULDRIVER // device does NOT have hardware DirectSound recording - // support -#define DSCCAPS_CERTIFIED \ - DSCAPS_CERTIFIED // device driver has been certified by Microsoft - -// defines for formats field of BASS_RECORDINFO (from MMSYSTEM.H) -#ifndef WAVE_FORMAT_1M08 -#define WAVE_FORMAT_1M08 0x00000001 /* 11.025 kHz, Mono, 8-bit */ -#define WAVE_FORMAT_1S08 0x00000002 /* 11.025 kHz, Stereo, 8-bit */ -#define WAVE_FORMAT_1M16 0x00000004 /* 11.025 kHz, Mono, 16-bit */ -#define WAVE_FORMAT_1S16 0x00000008 /* 11.025 kHz, Stereo, 16-bit */ -#define WAVE_FORMAT_2M08 0x00000010 /* 22.05 kHz, Mono, 8-bit */ -#define WAVE_FORMAT_2S08 0x00000020 /* 22.05 kHz, Stereo, 8-bit */ -#define WAVE_FORMAT_2M16 0x00000040 /* 22.05 kHz, Mono, 16-bit */ -#define WAVE_FORMAT_2S16 0x00000080 /* 22.05 kHz, Stereo, 16-bit */ -#define WAVE_FORMAT_4M08 0x00000100 /* 44.1 kHz, Mono, 8-bit */ -#define WAVE_FORMAT_4S08 0x00000200 /* 44.1 kHz, Stereo, 8-bit */ -#define WAVE_FORMAT_4M16 0x00000400 /* 44.1 kHz, Mono, 16-bit */ -#define WAVE_FORMAT_4S16 0x00000800 /* 44.1 kHz, Stereo, 16-bit */ -#endif - -// Sample info structure -typedef struct { - DWORD freq; // default playback rate - float volume; // default volume (0-1) - float pan; // default pan (-1=left, 0=middle, 1=right) - DWORD flags; // BASS_SAMPLE_xxx flags - DWORD length; // length (in bytes) - DWORD max; // maximum simultaneous playbacks - DWORD origres; // original resolution - DWORD chans; // number of channels - DWORD mingap; // minimum gap (ms) between creating channels - DWORD mode3d; // BASS_3DMODE_xxx mode - float mindist; // minimum distance - float maxdist; // maximum distance - DWORD iangle; // angle of inside projection cone - DWORD oangle; // angle of outside projection cone - float outvol; // delta-volume outside the projection cone - DWORD vam; // voice allocation/management flags (BASS_VAM_xxx) - DWORD priority; // priority (0=lowest, 0xffffffff=highest) -} BASS_SAMPLE; - -#define BASS_SAMPLE_8BITS 1 // 8 bit -#define BASS_SAMPLE_FLOAT 256 // 32 bit floating-point -#define BASS_SAMPLE_MONO 2 // mono -#define BASS_SAMPLE_LOOP 4 // looped -#define BASS_SAMPLE_3D 8 // 3D functionality -#define BASS_SAMPLE_SOFTWARE 16 // not using hardware mixing -#define BASS_SAMPLE_MUTEMAX 32 // mute at max distance (3D only) -#define BASS_SAMPLE_VAM 64 // DX7 voice allocation & management -#define BASS_SAMPLE_FX 128 // old implementation of DX8 effects -#define BASS_SAMPLE_OVER_VOL 0x10000 // override lowest volume -#define BASS_SAMPLE_OVER_POS 0x20000 // override longest playing -#define BASS_SAMPLE_OVER_DIST \ - 0x30000 // override furthest from listener (3D only) - -#define BASS_STREAM_PRESCAN \ - 0x20000 // enable pin-point seeking/length (MP3/MP2/MP1) -#define BASS_STREAM_AUTOFREE \ - 0x40000 // automatically free the stream when it stop/ends -#define BASS_STREAM_RESTRATE \ - 0x80000 // restrict the download rate of internet file streams -#define BASS_STREAM_BLOCK \ - 0x100000 // download/play internet file stream in small blocks -#define BASS_STREAM_DECODE \ - 0x200000 // don't play the stream, only decode (BASS_ChannelGetData) -#define BASS_STREAM_STATUS \ - 0x800000 // give server status info (HTTP/ICY tags) in DOWNLOADPROC - -#define BASS_MP3_IGNOREDELAY \ - 0x200 // ignore LAME/Xing/VBRI/iTunes delay & padding info -#define BASS_MP3_SETPOS BASS_STREAM_PRESCAN - -#define BASS_MUSIC_FLOAT BASS_SAMPLE_FLOAT -#define BASS_MUSIC_MONO BASS_SAMPLE_MONO -#define BASS_MUSIC_LOOP BASS_SAMPLE_LOOP -#define BASS_MUSIC_3D BASS_SAMPLE_3D -#define BASS_MUSIC_FX BASS_SAMPLE_FX -#define BASS_MUSIC_AUTOFREE BASS_STREAM_AUTOFREE -#define BASS_MUSIC_DECODE BASS_STREAM_DECODE -#define BASS_MUSIC_PRESCAN BASS_STREAM_PRESCAN // calculate playback length -#define BASS_MUSIC_CALCLEN BASS_MUSIC_PRESCAN -#define BASS_MUSIC_RAMP 0x200 // normal ramping -#define BASS_MUSIC_RAMPS 0x400 // sensitive ramping -#define BASS_MUSIC_SURROUND 0x800 // surround sound -#define BASS_MUSIC_SURROUND2 0x1000 // surround sound (mode 2) -#define BASS_MUSIC_FT2PAN 0x2000 // apply FastTracker 2 panning to XM files -#define BASS_MUSIC_FT2MOD 0x2000 // play .MOD as FastTracker 2 does -#define BASS_MUSIC_PT1MOD 0x4000 // play .MOD as ProTracker 1 does -#define BASS_MUSIC_NONINTER 0x10000 // non-interpolated sample mixing -#define BASS_MUSIC_SINCINTER 0x800000 // sinc interpolated sample mixing -#define BASS_MUSIC_POSRESET 0x8000 // stop all notes when moving position -#define BASS_MUSIC_POSRESETEX \ - 0x400000 // stop all notes and reset bmp/etc when moving position -#define BASS_MUSIC_STOPBACK 0x80000 // stop the music on a backwards jump effect -#define BASS_MUSIC_NOSAMPLE 0x100000 // don't load the samples - -// Speaker assignment flags -#define BASS_SPEAKER_FRONT 0x1000000 // front speakers -#define BASS_SPEAKER_REAR 0x2000000 // rear/side speakers -#define BASS_SPEAKER_CENLFE 0x3000000 // center & LFE speakers (5.1) -#define BASS_SPEAKER_REAR2 0x4000000 // rear center speakers (7.1) -#define BASS_SPEAKER_N(n) ((n) << 24) // n'th pair of speakers (max 15) -#define BASS_SPEAKER_LEFT 0x10000000 // modifier: left -#define BASS_SPEAKER_RIGHT 0x20000000 // modifier: right -#define BASS_SPEAKER_FRONTLEFT BASS_SPEAKER_FRONT | BASS_SPEAKER_LEFT -#define BASS_SPEAKER_FRONTRIGHT BASS_SPEAKER_FRONT | BASS_SPEAKER_RIGHT -#define BASS_SPEAKER_REARLEFT BASS_SPEAKER_REAR | BASS_SPEAKER_LEFT -#define BASS_SPEAKER_REARRIGHT BASS_SPEAKER_REAR | BASS_SPEAKER_RIGHT -#define BASS_SPEAKER_CENTER BASS_SPEAKER_CENLFE | BASS_SPEAKER_LEFT -#define BASS_SPEAKER_LFE BASS_SPEAKER_CENLFE | BASS_SPEAKER_RIGHT -#define BASS_SPEAKER_REAR2LEFT BASS_SPEAKER_REAR2 | BASS_SPEAKER_LEFT -#define BASS_SPEAKER_REAR2RIGHT BASS_SPEAKER_REAR2 | BASS_SPEAKER_RIGHT - -#define BASS_ASYNCFILE 0x40000000 -#define BASS_UNICODE 0x80000000 - -#define BASS_RECORD_PAUSE 0x8000 // start recording paused -#define BASS_RECORD_ECHOCANCEL 0x2000 -#define BASS_RECORD_AGC 0x4000 - -// DX7 voice allocation & management flags -#define BASS_VAM_HARDWARE 1 -#define BASS_VAM_SOFTWARE 2 -#define BASS_VAM_TERM_TIME 4 -#define BASS_VAM_TERM_DIST 8 -#define BASS_VAM_TERM_PRIO 16 - -// Channel info structure -typedef struct { - DWORD freq; // default playback rate - DWORD chans; // channels - DWORD flags; // BASS_SAMPLE/STREAM/MUSIC/SPEAKER flags - DWORD ctype; // type of channel - DWORD origres; // original resolution - HPLUGIN plugin; // plugin - HSAMPLE sample; // sample - const char *filename; // filename -} BASS_CHANNELINFO; - -#define BASS_ORIGRES_FLOAT 0x10000 - -// BASS_CHANNELINFO types -#define BASS_CTYPE_SAMPLE 1 -#define BASS_CTYPE_RECORD 2 -#define BASS_CTYPE_STREAM 0x10000 -#define BASS_CTYPE_STREAM_OGG 0x10002 -#define BASS_CTYPE_STREAM_MP1 0x10003 -#define BASS_CTYPE_STREAM_MP2 0x10004 -#define BASS_CTYPE_STREAM_MP3 0x10005 -#define BASS_CTYPE_STREAM_AIFF 0x10006 -#define BASS_CTYPE_STREAM_CA 0x10007 -#define BASS_CTYPE_STREAM_MF 0x10008 -#define BASS_CTYPE_STREAM_AM 0x10009 -#define BASS_CTYPE_STREAM_DUMMY 0x18000 -#define BASS_CTYPE_STREAM_DEVICE 0x18001 -#define BASS_CTYPE_STREAM_WAV 0x40000 // WAVE flag, LOWORD=codec -#define BASS_CTYPE_STREAM_WAV_PCM 0x50001 -#define BASS_CTYPE_STREAM_WAV_FLOAT 0x50003 -#define BASS_CTYPE_MUSIC_MOD 0x20000 -#define BASS_CTYPE_MUSIC_MTM 0x20001 -#define BASS_CTYPE_MUSIC_S3M 0x20002 -#define BASS_CTYPE_MUSIC_XM 0x20003 -#define BASS_CTYPE_MUSIC_IT 0x20004 -#define BASS_CTYPE_MUSIC_MO3 0x00100 // MO3 flag - -typedef struct { - DWORD ctype; // channel type -#if defined(_WIN32_WCE) || \ - (WINAPI_FAMILY && WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP) - const wchar_t *name; // format description - const wchar_t *exts; // file extension filter (*.ext1;*.ext2;etc...) -#else - const char *name; // format description - const char *exts; // file extension filter (*.ext1;*.ext2;etc...) -#endif -} BASS_PLUGINFORM; - -typedef struct { - DWORD version; // version (same form as BASS_GetVersion) - DWORD formatc; // number of formats - const BASS_PLUGINFORM *formats; // the array of formats -} BASS_PLUGININFO; - -// 3D vector (for 3D positions/velocities/orientations) -typedef struct BASS_3DVECTOR { -#ifdef __cplusplus - BASS_3DVECTOR(){}; - BASS_3DVECTOR(float _x, float _y, float _z) : x(_x), y(_y), z(_z){}; -#endif - float x; // +=right, -=left - float y; // +=up, -=down - float z; // +=front, -=behind -} BASS_3DVECTOR; - -// 3D channel modes -#define BASS_3DMODE_NORMAL 0 // normal 3D processing -#define BASS_3DMODE_RELATIVE 1 // position is relative to the listener -#define BASS_3DMODE_OFF 2 // no 3D processing - -// software 3D mixing algorithms (used with BASS_CONFIG_3DALGORITHM) -#define BASS_3DALG_DEFAULT 0 -#define BASS_3DALG_OFF 1 -#define BASS_3DALG_FULL 2 -#define BASS_3DALG_LIGHT 3 - -// EAX environments, use with BASS_SetEAXParameters -enum { - EAX_ENVIRONMENT_GENERIC, - EAX_ENVIRONMENT_PADDEDCELL, - EAX_ENVIRONMENT_ROOM, - EAX_ENVIRONMENT_BATHROOM, - EAX_ENVIRONMENT_LIVINGROOM, - EAX_ENVIRONMENT_STONEROOM, - EAX_ENVIRONMENT_AUDITORIUM, - EAX_ENVIRONMENT_CONCERTHALL, - EAX_ENVIRONMENT_CAVE, - EAX_ENVIRONMENT_ARENA, - EAX_ENVIRONMENT_HANGAR, - EAX_ENVIRONMENT_CARPETEDHALLWAY, - EAX_ENVIRONMENT_HALLWAY, - EAX_ENVIRONMENT_STONECORRIDOR, - EAX_ENVIRONMENT_ALLEY, - EAX_ENVIRONMENT_FOREST, - EAX_ENVIRONMENT_CITY, - EAX_ENVIRONMENT_MOUNTAINS, - EAX_ENVIRONMENT_QUARRY, - EAX_ENVIRONMENT_PLAIN, - EAX_ENVIRONMENT_PARKINGLOT, - EAX_ENVIRONMENT_SEWERPIPE, - EAX_ENVIRONMENT_UNDERWATER, - EAX_ENVIRONMENT_DRUGGED, - EAX_ENVIRONMENT_DIZZY, - EAX_ENVIRONMENT_PSYCHOTIC, - - EAX_ENVIRONMENT_COUNT // total number of environments -}; - -// EAX presets, usage: BASS_SetEAXParameters(EAX_PRESET_xxx) -#define EAX_PRESET_GENERIC EAX_ENVIRONMENT_GENERIC, 0.5F, 1.493F, 0.5F -#define EAX_PRESET_PADDEDCELL EAX_ENVIRONMENT_PADDEDCELL, 0.25F, 0.1F, 0.0F -#define EAX_PRESET_ROOM EAX_ENVIRONMENT_ROOM, 0.417F, 0.4F, 0.666F -#define EAX_PRESET_BATHROOM EAX_ENVIRONMENT_BATHROOM, 0.653F, 1.499F, 0.166F -#define EAX_PRESET_LIVINGROOM EAX_ENVIRONMENT_LIVINGROOM, 0.208F, 0.478F, 0.0F -#define EAX_PRESET_STONEROOM EAX_ENVIRONMENT_STONEROOM, 0.5F, 2.309F, 0.888F -#define EAX_PRESET_AUDITORIUM EAX_ENVIRONMENT_AUDITORIUM, 0.403F, 4.279F, 0.5F -#define EAX_PRESET_CONCERTHALL EAX_ENVIRONMENT_CONCERTHALL, 0.5F, 3.961F, 0.5F -#define EAX_PRESET_CAVE EAX_ENVIRONMENT_CAVE, 0.5F, 2.886F, 1.304F -#define EAX_PRESET_ARENA EAX_ENVIRONMENT_ARENA, 0.361F, 7.284F, 0.332F -#define EAX_PRESET_HANGAR EAX_ENVIRONMENT_HANGAR, 0.5F, 10.0F, 0.3F -#define EAX_PRESET_CARPETEDHALLWAY \ - EAX_ENVIRONMENT_CARPETEDHALLWAY, 0.153F, 0.259F, 2.0F -#define EAX_PRESET_HALLWAY EAX_ENVIRONMENT_HALLWAY, 0.361F, 1.493F, 0.0F -#define EAX_PRESET_STONECORRIDOR \ - EAX_ENVIRONMENT_STONECORRIDOR, 0.444F, 2.697F, 0.638F -#define EAX_PRESET_ALLEY EAX_ENVIRONMENT_ALLEY, 0.25F, 1.752F, 0.776F -#define EAX_PRESET_FOREST EAX_ENVIRONMENT_FOREST, 0.111F, 3.145F, 0.472F -#define EAX_PRESET_CITY EAX_ENVIRONMENT_CITY, 0.111F, 2.767F, 0.224F -#define EAX_PRESET_MOUNTAINS EAX_ENVIRONMENT_MOUNTAINS, 0.194F, 7.841F, 0.472F -#define EAX_PRESET_QUARRY EAX_ENVIRONMENT_QUARRY, 1.0F, 1.499F, 0.5F -#define EAX_PRESET_PLAIN EAX_ENVIRONMENT_PLAIN, 0.097F, 2.767F, 0.224F -#define EAX_PRESET_PARKINGLOT EAX_ENVIRONMENT_PARKINGLOT, 0.208F, 1.652F, 1.5F -#define EAX_PRESET_SEWERPIPE EAX_ENVIRONMENT_SEWERPIPE, 0.652F, 2.886F, 0.25F -#define EAX_PRESET_UNDERWATER EAX_ENVIRONMENT_UNDERWATER, 1.0F, 1.499F, 0.0F -#define EAX_PRESET_DRUGGED EAX_ENVIRONMENT_DRUGGED, 0.875F, 8.392F, 1.388F -#define EAX_PRESET_DIZZY EAX_ENVIRONMENT_DIZZY, 0.139F, 17.234F, 0.666F -#define EAX_PRESET_PSYCHOTIC EAX_ENVIRONMENT_PSYCHOTIC, 0.486F, 7.563F, 0.806F - -typedef DWORD(CALLBACK STREAMPROC)(HSTREAM handle, void *buffer, DWORD length, - void *user); -/* User stream callback function. NOTE: A stream function should obviously be as -quick as possible, other streams (and MOD musics) can't be mixed until it's -finished. handle : The stream that needs writing buffer : Buffer to write the -samples in length : Number of bytes to write user : The 'user' parameter value -given when calling BASS_StreamCreate RETURN : Number of bytes written. Set the -BASS_STREAMPROC_END flag to end the stream. */ - -#define BASS_STREAMPROC_END 0x80000000 // end of user stream flag - -// special STREAMPROCs -#define STREAMPROC_DUMMY (STREAMPROC *)0 // "dummy" stream -#define STREAMPROC_PUSH (STREAMPROC *)-1 // push stream -#define STREAMPROC_DEVICE (STREAMPROC *)-2 // device mix stream - -// BASS_StreamCreateFileUser file systems -#define STREAMFILE_NOBUFFER 0 -#define STREAMFILE_BUFFER 1 -#define STREAMFILE_BUFFERPUSH 2 - -// User file stream callback functions -typedef void(CALLBACK FILECLOSEPROC)(void *user); -typedef QWORD(CALLBACK FILELENPROC)(void *user); -typedef DWORD(CALLBACK FILEREADPROC)(void *buffer, DWORD length, void *user); -typedef BOOL(CALLBACK FILESEEKPROC)(QWORD offset, void *user); - -typedef struct { - FILECLOSEPROC *close; - FILELENPROC *length; - FILEREADPROC *read; - FILESEEKPROC *seek; -} BASS_FILEPROCS; - -// BASS_StreamPutFileData options -#define BASS_FILEDATA_END 0 // end & close the file - -// BASS_StreamGetFilePosition modes -#define BASS_FILEPOS_CURRENT 0 -#define BASS_FILEPOS_DECODE BASS_FILEPOS_CURRENT -#define BASS_FILEPOS_DOWNLOAD 1 -#define BASS_FILEPOS_END 2 -#define BASS_FILEPOS_START 3 -#define BASS_FILEPOS_CONNECTED 4 -#define BASS_FILEPOS_BUFFER 5 -#define BASS_FILEPOS_SOCKET 6 -#define BASS_FILEPOS_ASYNCBUF 7 -#define BASS_FILEPOS_SIZE 8 -#define BASS_FILEPOS_BUFFERING 9 - -typedef void(CALLBACK DOWNLOADPROC)(const void *buffer, DWORD length, - void *user); -/* Internet stream download callback function. -buffer : Buffer containing the downloaded data... NULL=end of download -length : Number of bytes in the buffer -user : The 'user' parameter value given when calling BASS_StreamCreateURL */ - -// BASS_ChannelSetSync types -#define BASS_SYNC_POS 0 -#define BASS_SYNC_END 2 -#define BASS_SYNC_META 4 -#define BASS_SYNC_SLIDE 5 -#define BASS_SYNC_STALL 6 -#define BASS_SYNC_DOWNLOAD 7 -#define BASS_SYNC_FREE 8 -#define BASS_SYNC_SETPOS 11 -#define BASS_SYNC_MUSICPOS 10 -#define BASS_SYNC_MUSICINST 1 -#define BASS_SYNC_MUSICFX 3 -#define BASS_SYNC_OGG_CHANGE 12 -#define BASS_SYNC_MIXTIME 0x40000000 // flag: sync at mixtime, else at playtime -#define BASS_SYNC_ONETIME 0x80000000 // flag: sync only once, else continuously - -typedef void(CALLBACK SYNCPROC)(HSYNC handle, DWORD channel, DWORD data, - void *user); -/* Sync callback function. NOTE: a sync callback function should be very -quick as other syncs can't be processed until it has finished. If the sync -is a "mixtime" sync, then other streams and MOD musics can't be mixed until -it's finished either. -handle : The sync that has occured -channel: Channel that the sync occured in -data : Additional data associated with the sync's occurance -user : The 'user' parameter given when calling BASS_ChannelSetSync */ - -typedef void(CALLBACK DSPPROC)(HDSP handle, DWORD channel, void *buffer, - DWORD length, void *user); -/* DSP callback function. NOTE: A DSP function should obviously be as quick as -possible... other DSP functions, streams and MOD musics can not be processed -until it's finished. -handle : The DSP handle -channel: Channel that the DSP is being applied to -buffer : Buffer to apply the DSP to -length : Number of bytes in the buffer -user : The 'user' parameter given when calling BASS_ChannelSetDSP */ - -typedef BOOL(CALLBACK RECORDPROC)(HRECORD handle, const void *buffer, - DWORD length, void *user); -/* Recording callback function. -handle : The recording handle -buffer : Buffer containing the recorded sample data -length : Number of bytes -user : The 'user' parameter value given when calling BASS_RecordStart -RETURN : TRUE = continue recording, FALSE = stop */ - -// BASS_ChannelIsActive return values -#define BASS_ACTIVE_STOPPED 0 -#define BASS_ACTIVE_PLAYING 1 -#define BASS_ACTIVE_STALLED 2 -#define BASS_ACTIVE_PAUSED 3 - -// Channel attributes -#define BASS_ATTRIB_FREQ 1 -#define BASS_ATTRIB_VOL 2 -#define BASS_ATTRIB_PAN 3 -#define BASS_ATTRIB_EAXMIX 4 -#define BASS_ATTRIB_NOBUFFER 5 -#define BASS_ATTRIB_VBR 6 -#define BASS_ATTRIB_CPU 7 -#define BASS_ATTRIB_SRC 8 -#define BASS_ATTRIB_NET_RESUME 9 -#define BASS_ATTRIB_SCANINFO 10 -#define BASS_ATTRIB_NORAMP 11 -#define BASS_ATTRIB_BITRATE 12 -#define BASS_ATTRIB_BUFFER 13 -#define BASS_ATTRIB_MUSIC_AMPLIFY 0x100 -#define BASS_ATTRIB_MUSIC_PANSEP 0x101 -#define BASS_ATTRIB_MUSIC_PSCALER 0x102 -#define BASS_ATTRIB_MUSIC_BPM 0x103 -#define BASS_ATTRIB_MUSIC_SPEED 0x104 -#define BASS_ATTRIB_MUSIC_VOL_GLOBAL 0x105 -#define BASS_ATTRIB_MUSIC_ACTIVE 0x106 -#define BASS_ATTRIB_MUSIC_VOL_CHAN 0x200 // + channel # -#define BASS_ATTRIB_MUSIC_VOL_INST 0x300 // + instrument # - -// BASS_ChannelSlideAttribute flags -#define BASS_SLIDE_LOG 0x1000000 - -// BASS_ChannelGetData flags -#define BASS_DATA_AVAILABLE 0 // query how much data is buffered -#define BASS_DATA_FIXED 0x20000000 // flag: return 8.24 fixed-point data -#define BASS_DATA_FLOAT 0x40000000 // flag: return floating-point sample data -#define BASS_DATA_FFT256 0x80000000 // 256 sample FFT -#define BASS_DATA_FFT512 0x80000001 // 512 FFT -#define BASS_DATA_FFT1024 0x80000002 // 1024 FFT -#define BASS_DATA_FFT2048 0x80000003 // 2048 FFT -#define BASS_DATA_FFT4096 0x80000004 // 4096 FFT -#define BASS_DATA_FFT8192 0x80000005 // 8192 FFT -#define BASS_DATA_FFT16384 0x80000006 // 16384 FFT -#define BASS_DATA_FFT32768 0x80000007 // 32768 FFT -#define BASS_DATA_FFT_INDIVIDUAL \ - 0x10 // FFT flag: FFT for each channel, else all combined -#define BASS_DATA_FFT_NOWINDOW 0x20 // FFT flag: no Hanning window -#define BASS_DATA_FFT_REMOVEDC 0x40 // FFT flag: pre-remove DC bias -#define BASS_DATA_FFT_COMPLEX 0x80 // FFT flag: return complex data - -// BASS_ChannelGetLevelEx flags -#define BASS_LEVEL_MONO 1 -#define BASS_LEVEL_STEREO 2 -#define BASS_LEVEL_RMS 4 -#define BASS_LEVEL_VOLPAN 8 - -// BASS_ChannelGetTags types : what's returned -#define BASS_TAG_ID3 0 // ID3v1 tags : TAG_ID3 structure -#define BASS_TAG_ID3V2 1 // ID3v2 tags : variable length block -#define BASS_TAG_OGG 2 // OGG comments : series of null-terminated UTF-8 strings -#define BASS_TAG_HTTP 3 // HTTP headers : series of null-terminated ANSI strings -#define BASS_TAG_ICY 4 // ICY headers : series of null-terminated ANSI strings -#define BASS_TAG_META 5 // ICY metadata : ANSI string -#define BASS_TAG_APE 6 // APE tags : series of null-terminated UTF-8 strings -#define BASS_TAG_MP4 \ - 7 // MP4/iTunes metadata : series of null-terminated UTF-8 strings -#define BASS_TAG_WMA 8 // WMA tags : series of null-terminated UTF-8 strings -#define BASS_TAG_VENDOR 9 // OGG encoder : UTF-8 string -#define BASS_TAG_LYRICS3 10 // Lyric3v2 tag : ASCII string -#define BASS_TAG_CA_CODEC 11 // CoreAudio codec info : TAG_CA_CODEC structure -#define BASS_TAG_MF \ - 13 // Media Foundation tags : series of null-terminated UTF-8 strings -#define BASS_TAG_WAVEFORMAT 14 // WAVE format : WAVEFORMATEEX structure -#define BASS_TAG_AM_MIME 15 // Android Media MIME type : ASCII string -#define BASS_TAG_AM_NAME 16 // Android Media codec name : ASCII string -#define BASS_TAG_RIFF_INFO \ - 0x100 // RIFF "INFO" tags : series of null-terminated ANSI strings -#define BASS_TAG_RIFF_BEXT 0x101 // RIFF/BWF "bext" tags : TAG_BEXT structure -#define BASS_TAG_RIFF_CART 0x102 // RIFF/BWF "cart" tags : TAG_CART structure -#define BASS_TAG_RIFF_DISP 0x103 // RIFF "DISP" text tag : ANSI string -#define BASS_TAG_RIFF_CUE 0x104 // RIFF "cue " chunk : TAG_CUE structure -#define BASS_TAG_RIFF_SMPL 0x105 // RIFF "smpl" chunk : TAG_SMPL structure -#define BASS_TAG_APE_BINARY \ - 0x1000 // + index #, binary APE tag : TAG_APE_BINARY structure -#define BASS_TAG_MUSIC_NAME 0x10000 // MOD music name : ANSI string -#define BASS_TAG_MUSIC_MESSAGE 0x10001 // MOD message : ANSI string -#define BASS_TAG_MUSIC_ORDERS \ - 0x10002 // MOD order list : BYTE array of pattern numbers -#define BASS_TAG_MUSIC_AUTH 0x10003 // MOD author : UTF-8 string -#define BASS_TAG_MUSIC_INST \ - 0x10100 // + instrument #, MOD instrument name : ANSI string -#define BASS_TAG_MUSIC_SAMPLE \ - 0x10300 // + sample #, MOD sample name : ANSI string - -// ID3v1 tag structure -typedef struct { - char id[3]; - char title[30]; - char artist[30]; - char album[30]; - char year[4]; - char comment[30]; - BYTE genre; -} TAG_ID3; - -// Binary APE tag structure -typedef struct { - const char *key; - const void *data; - DWORD length; + const char *key; + const void *data; + DWORD length; } TAG_APE_BINARY; // BWF "bext" tag structure -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable : 4200) -#endif -#pragma pack(push, 1) -typedef struct { - char Description[256]; // description - char Originator[32]; // name of the originator - char OriginatorReference[32]; // reference of the originator - char OriginationDate[10]; // date of creation (yyyy-mm-dd) - char OriginationTime[8]; // time of creation (hh-mm-ss) - QWORD TimeReference; // first sample count since midnight (little-endian) - WORD Version; // BWF version (little-endian) - BYTE UMID[64]; // SMPTE UMID - BYTE Reserved[190]; -#if defined(__GNUC__) && __GNUC__ < 3 - char CodingHistory[0]; // history -#elif 1 // change to 0 if compiler fails the following line - char CodingHistory[]; // history -#else - char CodingHistory[1]; // history -#endif -} TAG_BEXT; +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4200) +#endif +#pragma pack(push,1) +typedef struct { + char Description[256]; // description + char Originator[32]; // name of the originator + char OriginatorReference[32]; // reference of the originator + char OriginationDate[10]; // date of creation (yyyy-mm-dd) + char OriginationTime[8]; // time of creation (hh-mm-ss) + QWORD TimeReference; // first sample count since midnight (little-endian) + WORD Version; // BWF version (little-endian) + BYTE UMID[64]; // SMPTE UMID + BYTE Reserved[190]; +#if defined(__GNUC__) && __GNUC__<3 + char CodingHistory[0]; // history +#elif 1 // change to 0 if compiler fails the following line + char CodingHistory[]; // history +#else + char CodingHistory[1]; // history +#endif +} TAG_BEXT; #pragma pack(pop) // BWF "cart" tag structures -typedef struct { - DWORD dwUsage; // FOURCC timer usage ID - DWORD dwValue; // timer value in samples from head +typedef struct +{ + DWORD dwUsage; // FOURCC timer usage ID + DWORD dwValue; // timer value in samples from head } TAG_CART_TIMER; -typedef struct { - char Version[4]; // version of the data structure - char Title[64]; // title of cart audio sequence - char Artist[64]; // artist or creator name - char CutID[64]; // cut number identification - char ClientID[64]; // client identification - char Category[64]; // category ID, PSA, NEWS, etc - char Classification[64]; // classification or auxiliary key - char OutCue[64]; // out cue text - char StartDate[10]; // yyyy-mm-dd - char StartTime[8]; // hh:mm:ss - char EndDate[10]; // yyyy-mm-dd - char EndTime[8]; // hh:mm:ss - char ProducerAppID[64]; // name of vendor or application - char ProducerAppVersion[64]; // version of producer application - char UserDef[64]; // user defined text - DWORD dwLevelReference; // sample value for 0 dB reference - TAG_CART_TIMER PostTimer[8]; // 8 time markers after head - char Reserved[276]; - char URL[1024]; // uniform resource locator -#if defined(__GNUC__) && __GNUC__ < 3 - char TagText[0]; // free form text for scripts or tags -#elif 1 // change to 0 if compiler fails the following line - char TagText[]; // free form text for scripts or tags +typedef struct +{ + char Version[4]; // version of the data structure + char Title[64]; // title of cart audio sequence + char Artist[64]; // artist or creator name + char CutID[64]; // cut number identification + char ClientID[64]; // client identification + char Category[64]; // category ID, PSA, NEWS, etc + char Classification[64]; // classification or auxiliary key + char OutCue[64]; // out cue text + char StartDate[10]; // yyyy-mm-dd + char StartTime[8]; // hh:mm:ss + char EndDate[10]; // yyyy-mm-dd + char EndTime[8]; // hh:mm:ss + char ProducerAppID[64]; // name of vendor or application + char ProducerAppVersion[64]; // version of producer application + char UserDef[64]; // user defined text + DWORD dwLevelReference; // sample value for 0 dB reference + TAG_CART_TIMER PostTimer[8]; // 8 time markers after head + char Reserved[276]; + char URL[1024]; // uniform resource locator +#if defined(__GNUC__) && __GNUC__<3 + char TagText[0]; // free form text for scripts or tags +#elif 1 // change to 0 if compiler fails the following line + char TagText[]; // free form text for scripts or tags #else - char TagText[1]; // free form text for scripts or tags + char TagText[1]; // free form text for scripts or tags #endif } TAG_CART; // RIFF "cue " tag structures -typedef struct { - DWORD dwName; - DWORD dwPosition; - DWORD fccChunk; - DWORD dwChunkStart; - DWORD dwBlockStart; - DWORD dwSampleOffset; +typedef struct +{ + DWORD dwName; + DWORD dwPosition; + DWORD fccChunk; + DWORD dwChunkStart; + DWORD dwBlockStart; + DWORD dwSampleOffset; } TAG_CUE_POINT; -typedef struct { - DWORD dwCuePoints; -#if defined(__GNUC__) && __GNUC__ < 3 - TAG_CUE_POINT CuePoints[0]; +typedef struct +{ + DWORD dwCuePoints; +#if defined(__GNUC__) && __GNUC__<3 + TAG_CUE_POINT CuePoints[0]; #elif 1 // change to 0 if compiler fails the following line - TAG_CUE_POINT CuePoints[]; + TAG_CUE_POINT CuePoints[]; #else - TAG_CUE_POINT CuePoints[1]; + TAG_CUE_POINT CuePoints[1]; #endif } TAG_CUE; // RIFF "smpl" tag structures -typedef struct { - DWORD dwIdentifier; - DWORD dwType; - DWORD dwStart; - DWORD dwEnd; - DWORD dwFraction; - DWORD dwPlayCount; +typedef struct +{ + DWORD dwIdentifier; + DWORD dwType; + DWORD dwStart; + DWORD dwEnd; + DWORD dwFraction; + DWORD dwPlayCount; } TAG_SMPL_LOOP; -typedef struct { - DWORD dwManufacturer; - DWORD dwProduct; - DWORD dwSamplePeriod; - DWORD dwMIDIUnityNote; - DWORD dwMIDIPitchFraction; - DWORD dwSMPTEFormat; - DWORD dwSMPTEOffset; - DWORD cSampleLoops; - DWORD cbSamplerData; -#if defined(__GNUC__) && __GNUC__ < 3 - TAG_SMPL_LOOP SampleLoops[0]; +typedef struct +{ + DWORD dwManufacturer; + DWORD dwProduct; + DWORD dwSamplePeriod; + DWORD dwMIDIUnityNote; + DWORD dwMIDIPitchFraction; + DWORD dwSMPTEFormat; + DWORD dwSMPTEOffset; + DWORD cSampleLoops; + DWORD cbSamplerData; +#if defined(__GNUC__) && __GNUC__<3 + TAG_SMPL_LOOP SampleLoops[0]; #elif 1 // change to 0 if compiler fails the following line - TAG_SMPL_LOOP SampleLoops[]; + TAG_SMPL_LOOP SampleLoops[]; #else - TAG_SMPL_LOOP SampleLoops[1]; + TAG_SMPL_LOOP SampleLoops[1]; #endif } TAG_SMPL; #ifdef _MSC_VER #pragma warning(pop) #endif -// CoreAudio codec info structure -typedef struct { - DWORD ftype; // file format - DWORD atype; // audio format - const char *name; // description -} TAG_CA_CODEC; - +// CoreAudio codec info structure +typedef struct { + DWORD ftype; // file format + DWORD atype; // audio format + const char *name; // description +} TAG_CA_CODEC; + #ifndef _WAVEFORMATEX_ #define _WAVEFORMATEX_ -#pragma pack(push, 1) -typedef struct tWAVEFORMATEX { - WORD wFormatTag; - WORD nChannels; - DWORD nSamplesPerSec; - DWORD nAvgBytesPerSec; - WORD nBlockAlign; - WORD wBitsPerSample; - WORD cbSize; +#pragma pack(push,1) +typedef struct tWAVEFORMATEX +{ + WORD wFormatTag; + WORD nChannels; + DWORD nSamplesPerSec; + DWORD nAvgBytesPerSec; + WORD nBlockAlign; + WORD wBitsPerSample; + WORD cbSize; } WAVEFORMATEX, *PWAVEFORMATEX, *LPWAVEFORMATEX; typedef const WAVEFORMATEX *LPCWAVEFORMATEX; #pragma pack(pop) #endif -// BASS_ChannelGetLength/GetPosition/SetPosition modes -#define BASS_POS_BYTE 0 // byte position -#define BASS_POS_MUSIC_ORDER 1 // order.row position, MAKELONG(order,row) -#define BASS_POS_OGG 3 // OGG bitstream number -#define BASS_POS_RESET 0x2000000 // flag: reset user file buffers -#define BASS_POS_RELATIVE \ - 0x4000000 // flag: seek relative to the current position -#define BASS_POS_INEXACT 0x8000000 // flag: allow seeking to inexact position -#define BASS_POS_DECODE \ - 0x10000000 // flag: get the decoding (not playing) position -#define BASS_POS_DECODETO \ - 0x20000000 // flag: decode to the position instead of seeking -#define BASS_POS_SCAN 0x40000000 // flag: scan to the position +// BASS_ChannelGetLength/GetPosition/SetPosition modes +#define BASS_POS_BYTE 0 // byte position +#define BASS_POS_MUSIC_ORDER 1 // order.row position, MAKELONG(order,row) +#define BASS_POS_OGG 3 // OGG bitstream number +#define BASS_POS_RESET 0x2000000 // flag: reset user file buffers +#define BASS_POS_RELATIVE 0x4000000 // flag: seek relative to the current position +#define BASS_POS_INEXACT 0x8000000 // flag: allow seeking to inexact position +#define BASS_POS_DECODE 0x10000000 // flag: get the decoding (not playing) position +#define BASS_POS_DECODETO 0x20000000 // flag: decode to the position instead of seeking +#define BASS_POS_SCAN 0x40000000 // flag: scan to the position + +// BASS_ChannelSetDevice/GetDevice option +#define BASS_NODEVICE 0x20000 + +// BASS_RecordSetInput flags +#define BASS_INPUT_OFF 0x10000 +#define BASS_INPUT_ON 0x20000 + +#define BASS_INPUT_TYPE_MASK 0xff000000 +#define BASS_INPUT_TYPE_UNDEF 0x00000000 +#define BASS_INPUT_TYPE_DIGITAL 0x01000000 +#define BASS_INPUT_TYPE_LINE 0x02000000 +#define BASS_INPUT_TYPE_MIC 0x03000000 +#define BASS_INPUT_TYPE_SYNTH 0x04000000 +#define BASS_INPUT_TYPE_CD 0x05000000 +#define BASS_INPUT_TYPE_PHONE 0x06000000 +#define BASS_INPUT_TYPE_SPEAKER 0x07000000 +#define BASS_INPUT_TYPE_WAVE 0x08000000 +#define BASS_INPUT_TYPE_AUX 0x09000000 +#define BASS_INPUT_TYPE_ANALOG 0x0a000000 + +// BASS_ChannelSetFX effect types +#define BASS_FX_DX8_CHORUS 0 +#define BASS_FX_DX8_COMPRESSOR 1 +#define BASS_FX_DX8_DISTORTION 2 +#define BASS_FX_DX8_ECHO 3 +#define BASS_FX_DX8_FLANGER 4 +#define BASS_FX_DX8_GARGLE 5 +#define BASS_FX_DX8_I3DL2REVERB 6 +#define BASS_FX_DX8_PARAMEQ 7 +#define BASS_FX_DX8_REVERB 8 +#define BASS_FX_VOLUME 9 + +typedef struct { + float fWetDryMix; + float fDepth; + float fFeedback; + float fFrequency; + DWORD lWaveform; // 0=triangle, 1=sine + float fDelay; + DWORD lPhase; // BASS_DX8_PHASE_xxx +} BASS_DX8_CHORUS; + +typedef struct { + float fGain; + float fAttack; + float fRelease; + float fThreshold; + float fRatio; + float fPredelay; +} BASS_DX8_COMPRESSOR; + +typedef struct { + float fGain; + float fEdge; + float fPostEQCenterFrequency; + float fPostEQBandwidth; + float fPreLowpassCutoff; +} BASS_DX8_DISTORTION; + +typedef struct { + float fWetDryMix; + float fFeedback; + float fLeftDelay; + float fRightDelay; + BOOL lPanDelay; +} BASS_DX8_ECHO; + +typedef struct { + float fWetDryMix; + float fDepth; + float fFeedback; + float fFrequency; + DWORD lWaveform; // 0=triangle, 1=sine + float fDelay; + DWORD lPhase; // BASS_DX8_PHASE_xxx +} BASS_DX8_FLANGER; + +typedef struct { + DWORD dwRateHz; // Rate of modulation in hz + DWORD dwWaveShape; // 0=triangle, 1=square +} BASS_DX8_GARGLE; + +typedef struct { + int lRoom; // [-10000, 0] default: -1000 mB + int lRoomHF; // [-10000, 0] default: 0 mB + float flRoomRolloffFactor; // [0.0, 10.0] default: 0.0 + float flDecayTime; // [0.1, 20.0] default: 1.49s + float flDecayHFRatio; // [0.1, 2.0] default: 0.83 + int lReflections; // [-10000, 1000] default: -2602 mB + float flReflectionsDelay; // [0.0, 0.3] default: 0.007 s + int lReverb; // [-10000, 2000] default: 200 mB + float flReverbDelay; // [0.0, 0.1] default: 0.011 s + float flDiffusion; // [0.0, 100.0] default: 100.0 % + float flDensity; // [0.0, 100.0] default: 100.0 % + float flHFReference; // [20.0, 20000.0] default: 5000.0 Hz +} BASS_DX8_I3DL2REVERB; + +typedef struct { + float fCenter; + float fBandwidth; + float fGain; +} BASS_DX8_PARAMEQ; + +typedef struct { + float fInGain; // [-96.0,0.0] default: 0.0 dB + float fReverbMix; // [-96.0,0.0] default: 0.0 db + float fReverbTime; // [0.001,3000.0] default: 1000.0 ms + float fHighFreqRTRatio; // [0.001,0.999] default: 0.001 +} BASS_DX8_REVERB; + +#define BASS_DX8_PHASE_NEG_180 0 +#define BASS_DX8_PHASE_NEG_90 1 +#define BASS_DX8_PHASE_ZERO 2 +#define BASS_DX8_PHASE_90 3 +#define BASS_DX8_PHASE_180 4 -// BASS_ChannelSetDevice/GetDevice option -#define BASS_NODEVICE 0x20000 +typedef struct { + float fTarget; + float fCurrent; + float fTime; + DWORD lCurve; +} BASS_FX_VOLUME_PARAM; -// BASS_RecordSetInput flags -#define BASS_INPUT_OFF 0x10000 -#define BASS_INPUT_ON 0x20000 - -#define BASS_INPUT_TYPE_MASK 0xff000000 -#define BASS_INPUT_TYPE_UNDEF 0x00000000 -#define BASS_INPUT_TYPE_DIGITAL 0x01000000 -#define BASS_INPUT_TYPE_LINE 0x02000000 -#define BASS_INPUT_TYPE_MIC 0x03000000 -#define BASS_INPUT_TYPE_SYNTH 0x04000000 -#define BASS_INPUT_TYPE_CD 0x05000000 -#define BASS_INPUT_TYPE_PHONE 0x06000000 -#define BASS_INPUT_TYPE_SPEAKER 0x07000000 -#define BASS_INPUT_TYPE_WAVE 0x08000000 -#define BASS_INPUT_TYPE_AUX 0x09000000 -#define BASS_INPUT_TYPE_ANALOG 0x0a000000 - -// BASS_ChannelSetFX effect types -#define BASS_FX_DX8_CHORUS 0 -#define BASS_FX_DX8_COMPRESSOR 1 -#define BASS_FX_DX8_DISTORTION 2 -#define BASS_FX_DX8_ECHO 3 -#define BASS_FX_DX8_FLANGER 4 -#define BASS_FX_DX8_GARGLE 5 -#define BASS_FX_DX8_I3DL2REVERB 6 -#define BASS_FX_DX8_PARAMEQ 7 -#define BASS_FX_DX8_REVERB 8 -#define BASS_FX_VOLUME 9 - -typedef struct { - float fWetDryMix; - float fDepth; - float fFeedback; - float fFrequency; - DWORD lWaveform; // 0=triangle, 1=sine - float fDelay; - DWORD lPhase; // BASS_DX8_PHASE_xxx -} BASS_DX8_CHORUS; - -typedef struct { - float fGain; - float fAttack; - float fRelease; - float fThreshold; - float fRatio; - float fPredelay; -} BASS_DX8_COMPRESSOR; - -typedef struct { - float fGain; - float fEdge; - float fPostEQCenterFrequency; - float fPostEQBandwidth; - float fPreLowpassCutoff; -} BASS_DX8_DISTORTION; - -typedef struct { - float fWetDryMix; - float fFeedback; - float fLeftDelay; - float fRightDelay; - BOOL lPanDelay; -} BASS_DX8_ECHO; - -typedef struct { - float fWetDryMix; - float fDepth; - float fFeedback; - float fFrequency; - DWORD lWaveform; // 0=triangle, 1=sine - float fDelay; - DWORD lPhase; // BASS_DX8_PHASE_xxx -} BASS_DX8_FLANGER; - -typedef struct { - DWORD dwRateHz; // Rate of modulation in hz - DWORD dwWaveShape; // 0=triangle, 1=square -} BASS_DX8_GARGLE; - -typedef struct { - int lRoom; // [-10000, 0] default: -1000 mB - int lRoomHF; // [-10000, 0] default: 0 mB - float flRoomRolloffFactor; // [0.0, 10.0] default: 0.0 - float flDecayTime; // [0.1, 20.0] default: 1.49s - float flDecayHFRatio; // [0.1, 2.0] default: 0.83 - int lReflections; // [-10000, 1000] default: -2602 mB - float flReflectionsDelay; // [0.0, 0.3] default: 0.007 s - int lReverb; // [-10000, 2000] default: 200 mB - float flReverbDelay; // [0.0, 0.1] default: 0.011 s - float flDiffusion; // [0.0, 100.0] default: 100.0 % - float flDensity; // [0.0, 100.0] default: 100.0 % - float flHFReference; // [20.0, 20000.0] default: 5000.0 Hz -} BASS_DX8_I3DL2REVERB; - -typedef struct { - float fCenter; - float fBandwidth; - float fGain; -} BASS_DX8_PARAMEQ; - -typedef struct { - float fInGain; // [-96.0,0.0] default: 0.0 dB - float fReverbMix; // [-96.0,0.0] default: 0.0 db - float fReverbTime; // [0.001,3000.0] default: 1000.0 ms - float fHighFreqRTRatio; // [0.001,0.999] default: 0.001 -} BASS_DX8_REVERB; - -#define BASS_DX8_PHASE_NEG_180 0 -#define BASS_DX8_PHASE_NEG_90 1 -#define BASS_DX8_PHASE_ZERO 2 -#define BASS_DX8_PHASE_90 3 -#define BASS_DX8_PHASE_180 4 - -typedef struct { - float fTarget; - float fCurrent; - float fTime; - DWORD lCurve; -} BASS_FX_VOLUME_PARAM; - -typedef void(CALLBACK IOSNOTIFYPROC)(DWORD status); +typedef void (CALLBACK IOSNOTIFYPROC)(DWORD status); /* iOS notification callback function. status : The notification (BASS_IOSNOTIFY_xxx) */ -#define BASS_IOSNOTIFY_INTERRUPT 1 // interruption started -#define BASS_IOSNOTIFY_INTERRUPT_END 2 // interruption ended +#define BASS_IOSNOTIFY_INTERRUPT 1 // interruption started +#define BASS_IOSNOTIFY_INTERRUPT_END 2 // interruption ended + +BOOL BASSDEF(BASS_SetConfig)(DWORD option, DWORD value); +DWORD BASSDEF(BASS_GetConfig)(DWORD option); +BOOL BASSDEF(BASS_SetConfigPtr)(DWORD option, const void *value); +void *BASSDEF(BASS_GetConfigPtr)(DWORD option); +DWORD BASSDEF(BASS_GetVersion)(); +int BASSDEF(BASS_ErrorGetCode)(); +BOOL BASSDEF(BASS_GetDeviceInfo)(DWORD device, BASS_DEVICEINFO *info); +#if defined(_WIN32) && !defined(_WIN32_WCE) && !(WINAPI_FAMILY && WINAPI_FAMILY!=WINAPI_FAMILY_DESKTOP_APP) +BOOL BASSDEF(BASS_Init)(int device, DWORD freq, DWORD flags, HWND win, const GUID *dsguid); +#else +BOOL BASSDEF(BASS_Init)(int device, DWORD freq, DWORD flags, void *win, void *dsguid); +#endif +BOOL BASSDEF(BASS_SetDevice)(DWORD device); +DWORD BASSDEF(BASS_GetDevice)(); +BOOL BASSDEF(BASS_Free)(); +#if defined(_WIN32) && !defined(_WIN32_WCE) && !(WINAPI_FAMILY && WINAPI_FAMILY!=WINAPI_FAMILY_DESKTOP_APP) +void *BASSDEF(BASS_GetDSoundObject)(DWORD object); +#endif +BOOL BASSDEF(BASS_GetInfo)(BASS_INFO *info); +BOOL BASSDEF(BASS_Update)(DWORD length); +float BASSDEF(BASS_GetCPU)(); +BOOL BASSDEF(BASS_Start)(); +BOOL BASSDEF(BASS_Stop)(); +BOOL BASSDEF(BASS_Pause)(); +BOOL BASSDEF(BASS_SetVolume)(float volume); +float BASSDEF(BASS_GetVolume)(); + +HPLUGIN BASSDEF(BASS_PluginLoad)(const char *file, DWORD flags); +BOOL BASSDEF(BASS_PluginFree)(HPLUGIN handle); +const BASS_PLUGININFO *BASSDEF(BASS_PluginGetInfo)(HPLUGIN handle); + +BOOL BASSDEF(BASS_Set3DFactors)(float distf, float rollf, float doppf); +BOOL BASSDEF(BASS_Get3DFactors)(float *distf, float *rollf, float *doppf); +BOOL BASSDEF(BASS_Set3DPosition)(const BASS_3DVECTOR *pos, const BASS_3DVECTOR *vel, const BASS_3DVECTOR *front, const BASS_3DVECTOR *top); +BOOL BASSDEF(BASS_Get3DPosition)(BASS_3DVECTOR *pos, BASS_3DVECTOR *vel, BASS_3DVECTOR *front, BASS_3DVECTOR *top); +void BASSDEF(BASS_Apply3D)(); +#if defined(_WIN32) && !defined(_WIN32_WCE) && !(WINAPI_FAMILY && WINAPI_FAMILY!=WINAPI_FAMILY_DESKTOP_APP) +BOOL BASSDEF(BASS_SetEAXParameters)(int env, float vol, float decay, float damp); +BOOL BASSDEF(BASS_GetEAXParameters)(DWORD *env, float *vol, float *decay, float *damp); +#endif + +HMUSIC BASSDEF(BASS_MusicLoad)(BOOL mem, const void *file, QWORD offset, DWORD length, DWORD flags, DWORD freq); +BOOL BASSDEF(BASS_MusicFree)(HMUSIC handle); + +HSAMPLE BASSDEF(BASS_SampleLoad)(BOOL mem, const void *file, QWORD offset, DWORD length, DWORD max, DWORD flags); +HSAMPLE BASSDEF(BASS_SampleCreate)(DWORD length, DWORD freq, DWORD chans, DWORD max, DWORD flags); +BOOL BASSDEF(BASS_SampleFree)(HSAMPLE handle); +BOOL BASSDEF(BASS_SampleSetData)(HSAMPLE handle, const void *buffer); +BOOL BASSDEF(BASS_SampleGetData)(HSAMPLE handle, void *buffer); +BOOL BASSDEF(BASS_SampleGetInfo)(HSAMPLE handle, BASS_SAMPLE *info); +BOOL BASSDEF(BASS_SampleSetInfo)(HSAMPLE handle, const BASS_SAMPLE *info); +HCHANNEL BASSDEF(BASS_SampleGetChannel)(HSAMPLE handle, BOOL onlynew); +DWORD BASSDEF(BASS_SampleGetChannels)(HSAMPLE handle, HCHANNEL *channels); +BOOL BASSDEF(BASS_SampleStop)(HSAMPLE handle); + +HSTREAM BASSDEF(BASS_StreamCreate)(DWORD freq, DWORD chans, DWORD flags, STREAMPROC *proc, void *user); +HSTREAM BASSDEF(BASS_StreamCreateFile)(BOOL mem, const void *file, QWORD offset, QWORD length, DWORD flags); +HSTREAM BASSDEF(BASS_StreamCreateURL)(const char *url, DWORD offset, DWORD flags, DOWNLOADPROC *proc, void *user); +HSTREAM BASSDEF(BASS_StreamCreateFileUser)(DWORD system, DWORD flags, const BASS_FILEPROCS *proc, void *user); +BOOL BASSDEF(BASS_StreamFree)(HSTREAM handle); +QWORD BASSDEF(BASS_StreamGetFilePosition)(HSTREAM handle, DWORD mode); +DWORD BASSDEF(BASS_StreamPutData)(HSTREAM handle, const void *buffer, DWORD length); +DWORD BASSDEF(BASS_StreamPutFileData)(HSTREAM handle, const void *buffer, DWORD length); + +BOOL BASSDEF(BASS_RecordGetDeviceInfo)(DWORD device, BASS_DEVICEINFO *info); +BOOL BASSDEF(BASS_RecordInit)(int device); +BOOL BASSDEF(BASS_RecordSetDevice)(DWORD device); +DWORD BASSDEF(BASS_RecordGetDevice)(); +BOOL BASSDEF(BASS_RecordFree)(); +BOOL BASSDEF(BASS_RecordGetInfo)(BASS_RECORDINFO *info); +const char *BASSDEF(BASS_RecordGetInputName)(int input); +BOOL BASSDEF(BASS_RecordSetInput)(int input, DWORD flags, float volume); +DWORD BASSDEF(BASS_RecordGetInput)(int input, float *volume); +HRECORD BASSDEF(BASS_RecordStart)(DWORD freq, DWORD chans, DWORD flags, RECORDPROC *proc, void *user); + +double BASSDEF(BASS_ChannelBytes2Seconds)(DWORD handle, QWORD pos); +QWORD BASSDEF(BASS_ChannelSeconds2Bytes)(DWORD handle, double pos); +DWORD BASSDEF(BASS_ChannelGetDevice)(DWORD handle); +BOOL BASSDEF(BASS_ChannelSetDevice)(DWORD handle, DWORD device); +DWORD BASSDEF(BASS_ChannelIsActive)(DWORD handle); +BOOL BASSDEF(BASS_ChannelGetInfo)(DWORD handle, BASS_CHANNELINFO *info); +const char *BASSDEF(BASS_ChannelGetTags)(DWORD handle, DWORD tags); +DWORD BASSDEF(BASS_ChannelFlags)(DWORD handle, DWORD flags, DWORD mask); +BOOL BASSDEF(BASS_ChannelUpdate)(DWORD handle, DWORD length); +BOOL BASSDEF(BASS_ChannelLock)(DWORD handle, BOOL lock); +BOOL BASSDEF(BASS_ChannelPlay)(DWORD handle, BOOL restart); +BOOL BASSDEF(BASS_ChannelStop)(DWORD handle); +BOOL BASSDEF(BASS_ChannelPause)(DWORD handle); +BOOL BASSDEF(BASS_ChannelSetAttribute)(DWORD handle, DWORD attrib, float value); +BOOL BASSDEF(BASS_ChannelGetAttribute)(DWORD handle, DWORD attrib, float *value); +BOOL BASSDEF(BASS_ChannelSlideAttribute)(DWORD handle, DWORD attrib, float value, DWORD time); +BOOL BASSDEF(BASS_ChannelIsSliding)(DWORD handle, DWORD attrib); +BOOL BASSDEF(BASS_ChannelSetAttributeEx)(DWORD handle, DWORD attrib, void *value, DWORD size); +DWORD BASSDEF(BASS_ChannelGetAttributeEx)(DWORD handle, DWORD attrib, void *value, DWORD size); +BOOL BASSDEF(BASS_ChannelSet3DAttributes)(DWORD handle, int mode, float min, float max, int iangle, int oangle, float outvol); +BOOL BASSDEF(BASS_ChannelGet3DAttributes)(DWORD handle, DWORD *mode, float *min, float *max, DWORD *iangle, DWORD *oangle, float *outvol); +BOOL BASSDEF(BASS_ChannelSet3DPosition)(DWORD handle, const BASS_3DVECTOR *pos, const BASS_3DVECTOR *orient, const BASS_3DVECTOR *vel); +BOOL BASSDEF(BASS_ChannelGet3DPosition)(DWORD handle, BASS_3DVECTOR *pos, BASS_3DVECTOR *orient, BASS_3DVECTOR *vel); +QWORD BASSDEF(BASS_ChannelGetLength)(DWORD handle, DWORD mode); +BOOL BASSDEF(BASS_ChannelSetPosition)(DWORD handle, QWORD pos, DWORD mode); +QWORD BASSDEF(BASS_ChannelGetPosition)(DWORD handle, DWORD mode); +DWORD BASSDEF(BASS_ChannelGetLevel)(DWORD handle); +BOOL BASSDEF(BASS_ChannelGetLevelEx)(DWORD handle, float *levels, float length, DWORD flags); +DWORD BASSDEF(BASS_ChannelGetData)(DWORD handle, void *buffer, DWORD length); +HSYNC BASSDEF(BASS_ChannelSetSync)(DWORD handle, DWORD type, QWORD param, SYNCPROC *proc, void *user); +BOOL BASSDEF(BASS_ChannelRemoveSync)(DWORD handle, HSYNC sync); +HDSP BASSDEF(BASS_ChannelSetDSP)(DWORD handle, DSPPROC *proc, void *user, int priority); +BOOL BASSDEF(BASS_ChannelRemoveDSP)(DWORD handle, HDSP dsp); +BOOL BASSDEF(BASS_ChannelSetLink)(DWORD handle, DWORD chan); +BOOL BASSDEF(BASS_ChannelRemoveLink)(DWORD handle, DWORD chan); +HFX BASSDEF(BASS_ChannelSetFX)(DWORD handle, DWORD type, int priority); +BOOL BASSDEF(BASS_ChannelRemoveFX)(DWORD handle, HFX fx); + +BOOL BASSDEF(BASS_FXSetParameters)(HFX handle, const void *params); +BOOL BASSDEF(BASS_FXGetParameters)(HFX handle, void *params); +BOOL BASSDEF(BASS_FXReset)(HFX handle); +BOOL BASSDEF(BASS_FXSetPriority)(HFX handle, int priority); -BOOL BASSDEF(BASS_SetConfig)(DWORD option, DWORD value); -DWORD BASSDEF(BASS_GetConfig)(DWORD option); -BOOL BASSDEF(BASS_SetConfigPtr)(DWORD option, const void *value); -void *BASSDEF(BASS_GetConfigPtr)(DWORD option); -DWORD BASSDEF(BASS_GetVersion)(); -int BASSDEF(BASS_ErrorGetCode)(); -BOOL BASSDEF(BASS_GetDeviceInfo)(DWORD device, BASS_DEVICEINFO *info); -#if defined(_WIN32) && !defined(_WIN32_WCE) && \ - !(WINAPI_FAMILY && WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP) -BOOL BASSDEF(BASS_Init)(int device, DWORD freq, DWORD flags, HWND win, - const GUID *dsguid); -#else -BOOL BASSDEF(BASS_Init)(int device, DWORD freq, DWORD flags, void *win, - void *dsguid); -#endif -BOOL BASSDEF(BASS_SetDevice)(DWORD device); -DWORD BASSDEF(BASS_GetDevice)(); -BOOL BASSDEF(BASS_Free)(); -#if defined(_WIN32) && !defined(_WIN32_WCE) && \ - !(WINAPI_FAMILY && WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP) -void *BASSDEF(BASS_GetDSoundObject)(DWORD object); -#endif -BOOL BASSDEF(BASS_GetInfo)(BASS_INFO *info); -BOOL BASSDEF(BASS_Update)(DWORD length); -float BASSDEF(BASS_GetCPU)(); -BOOL BASSDEF(BASS_Start)(); -BOOL BASSDEF(BASS_Stop)(); -BOOL BASSDEF(BASS_Pause)(); -BOOL BASSDEF(BASS_SetVolume)(float volume); -float BASSDEF(BASS_GetVolume)(); - -HPLUGIN BASSDEF(BASS_PluginLoad)(const char *file, DWORD flags); -BOOL BASSDEF(BASS_PluginFree)(HPLUGIN handle); -const BASS_PLUGININFO *BASSDEF(BASS_PluginGetInfo)(HPLUGIN handle); - -BOOL BASSDEF(BASS_Set3DFactors)(float distf, float rollf, float doppf); -BOOL BASSDEF(BASS_Get3DFactors)(float *distf, float *rollf, float *doppf); -BOOL BASSDEF(BASS_Set3DPosition)(const BASS_3DVECTOR *pos, - const BASS_3DVECTOR *vel, - const BASS_3DVECTOR *front, - const BASS_3DVECTOR *top); -BOOL BASSDEF(BASS_Get3DPosition)(BASS_3DVECTOR *pos, BASS_3DVECTOR *vel, - BASS_3DVECTOR *front, BASS_3DVECTOR *top); -void BASSDEF(BASS_Apply3D)(); -#if defined(_WIN32) && !defined(_WIN32_WCE) && \ - !(WINAPI_FAMILY && WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP) -BOOL BASSDEF(BASS_SetEAXParameters)(int env, float vol, float decay, - float damp); -BOOL BASSDEF(BASS_GetEAXParameters)(DWORD *env, float *vol, float *decay, - float *damp); -#endif - -HMUSIC BASSDEF(BASS_MusicLoad)(BOOL mem, const void *file, QWORD offset, - DWORD length, DWORD flags, DWORD freq); -BOOL BASSDEF(BASS_MusicFree)(HMUSIC handle); - -HSAMPLE BASSDEF(BASS_SampleLoad)(BOOL mem, const void *file, QWORD offset, - DWORD length, DWORD max, DWORD flags); -HSAMPLE BASSDEF(BASS_SampleCreate)(DWORD length, DWORD freq, DWORD chans, - DWORD max, DWORD flags); -BOOL BASSDEF(BASS_SampleFree)(HSAMPLE handle); -BOOL BASSDEF(BASS_SampleSetData)(HSAMPLE handle, const void *buffer); -BOOL BASSDEF(BASS_SampleGetData)(HSAMPLE handle, void *buffer); -BOOL BASSDEF(BASS_SampleGetInfo)(HSAMPLE handle, BASS_SAMPLE *info); -BOOL BASSDEF(BASS_SampleSetInfo)(HSAMPLE handle, const BASS_SAMPLE *info); -HCHANNEL BASSDEF(BASS_SampleGetChannel)(HSAMPLE handle, BOOL onlynew); -DWORD BASSDEF(BASS_SampleGetChannels)(HSAMPLE handle, HCHANNEL *channels); -BOOL BASSDEF(BASS_SampleStop)(HSAMPLE handle); - -HSTREAM BASSDEF(BASS_StreamCreate)(DWORD freq, DWORD chans, DWORD flags, - STREAMPROC *proc, void *user); -HSTREAM BASSDEF(BASS_StreamCreateFile)(BOOL mem, const void *file, QWORD offset, - QWORD length, DWORD flags); -HSTREAM BASSDEF(BASS_StreamCreateURL)(const char *url, DWORD offset, - DWORD flags, DOWNLOADPROC *proc, - void *user); -HSTREAM BASSDEF(BASS_StreamCreateFileUser)(DWORD system, DWORD flags, - const BASS_FILEPROCS *proc, - void *user); -BOOL BASSDEF(BASS_StreamFree)(HSTREAM handle); -QWORD BASSDEF(BASS_StreamGetFilePosition)(HSTREAM handle, DWORD mode); -DWORD BASSDEF(BASS_StreamPutData)(HSTREAM handle, const void *buffer, - DWORD length); -DWORD BASSDEF(BASS_StreamPutFileData)(HSTREAM handle, const void *buffer, - DWORD length); - -BOOL BASSDEF(BASS_RecordGetDeviceInfo)(DWORD device, BASS_DEVICEINFO *info); -BOOL BASSDEF(BASS_RecordInit)(int device); -BOOL BASSDEF(BASS_RecordSetDevice)(DWORD device); -DWORD BASSDEF(BASS_RecordGetDevice)(); -BOOL BASSDEF(BASS_RecordFree)(); -BOOL BASSDEF(BASS_RecordGetInfo)(BASS_RECORDINFO *info); -const char *BASSDEF(BASS_RecordGetInputName)(int input); -BOOL BASSDEF(BASS_RecordSetInput)(int input, DWORD flags, float volume); -DWORD BASSDEF(BASS_RecordGetInput)(int input, float *volume); -HRECORD BASSDEF(BASS_RecordStart)(DWORD freq, DWORD chans, DWORD flags, - RECORDPROC *proc, void *user); - -double BASSDEF(BASS_ChannelBytes2Seconds)(DWORD handle, QWORD pos); -QWORD BASSDEF(BASS_ChannelSeconds2Bytes)(DWORD handle, double pos); -DWORD BASSDEF(BASS_ChannelGetDevice)(DWORD handle); -BOOL BASSDEF(BASS_ChannelSetDevice)(DWORD handle, DWORD device); -DWORD BASSDEF(BASS_ChannelIsActive)(DWORD handle); -BOOL BASSDEF(BASS_ChannelGetInfo)(DWORD handle, BASS_CHANNELINFO *info); -const char *BASSDEF(BASS_ChannelGetTags)(DWORD handle, DWORD tags); -DWORD BASSDEF(BASS_ChannelFlags)(DWORD handle, DWORD flags, DWORD mask); -BOOL BASSDEF(BASS_ChannelUpdate)(DWORD handle, DWORD length); -BOOL BASSDEF(BASS_ChannelLock)(DWORD handle, BOOL lock); -BOOL BASSDEF(BASS_ChannelPlay)(DWORD handle, BOOL restart); -BOOL BASSDEF(BASS_ChannelStop)(DWORD handle); -BOOL BASSDEF(BASS_ChannelPause)(DWORD handle); -BOOL BASSDEF(BASS_ChannelSetAttribute)(DWORD handle, DWORD attrib, float value); -BOOL BASSDEF(BASS_ChannelGetAttribute)(DWORD handle, DWORD attrib, - float *value); -BOOL BASSDEF(BASS_ChannelSlideAttribute)(DWORD handle, DWORD attrib, - float value, DWORD time); -BOOL BASSDEF(BASS_ChannelIsSliding)(DWORD handle, DWORD attrib); -BOOL BASSDEF(BASS_ChannelSetAttributeEx)(DWORD handle, DWORD attrib, - void *value, DWORD size); -DWORD BASSDEF(BASS_ChannelGetAttributeEx)(DWORD handle, DWORD attrib, - void *value, DWORD size); -BOOL BASSDEF(BASS_ChannelSet3DAttributes)(DWORD handle, int mode, float min, - float max, int iangle, int oangle, - float outvol); -BOOL BASSDEF(BASS_ChannelGet3DAttributes)(DWORD handle, DWORD *mode, float *min, - float *max, DWORD *iangle, - DWORD *oangle, float *outvol); -BOOL BASSDEF(BASS_ChannelSet3DPosition)(DWORD handle, const BASS_3DVECTOR *pos, - const BASS_3DVECTOR *orient, - const BASS_3DVECTOR *vel); -BOOL BASSDEF(BASS_ChannelGet3DPosition)(DWORD handle, BASS_3DVECTOR *pos, - BASS_3DVECTOR *orient, - BASS_3DVECTOR *vel); -QWORD BASSDEF(BASS_ChannelGetLength)(DWORD handle, DWORD mode); -BOOL BASSDEF(BASS_ChannelSetPosition)(DWORD handle, QWORD pos, DWORD mode); -QWORD BASSDEF(BASS_ChannelGetPosition)(DWORD handle, DWORD mode); -DWORD BASSDEF(BASS_ChannelGetLevel)(DWORD handle); -BOOL BASSDEF(BASS_ChannelGetLevelEx)(DWORD handle, float *levels, float length, - DWORD flags); -DWORD BASSDEF(BASS_ChannelGetData)(DWORD handle, void *buffer, DWORD length); -HSYNC BASSDEF(BASS_ChannelSetSync)(DWORD handle, DWORD type, QWORD param, - SYNCPROC *proc, void *user); -BOOL BASSDEF(BASS_ChannelRemoveSync)(DWORD handle, HSYNC sync); -HDSP BASSDEF(BASS_ChannelSetDSP)(DWORD handle, DSPPROC *proc, void *user, - int priority); -BOOL BASSDEF(BASS_ChannelRemoveDSP)(DWORD handle, HDSP dsp); -BOOL BASSDEF(BASS_ChannelSetLink)(DWORD handle, DWORD chan); -BOOL BASSDEF(BASS_ChannelRemoveLink)(DWORD handle, DWORD chan); -HFX BASSDEF(BASS_ChannelSetFX)(DWORD handle, DWORD type, int priority); -BOOL BASSDEF(BASS_ChannelRemoveFX)(DWORD handle, HFX fx); - -BOOL BASSDEF(BASS_FXSetParameters)(HFX handle, const void *params); -BOOL BASSDEF(BASS_FXGetParameters)(HFX handle, void *params); -BOOL BASSDEF(BASS_FXReset)(HFX handle); -BOOL BASSDEF(BASS_FXSetPriority)(HFX handle, int priority); - -#ifdef __cplusplus -} +#ifdef __cplusplus +} #if defined(_WIN32) && !defined(NOBASSOVERLOADS) static inline HPLUGIN BASS_PluginLoad(const WCHAR *file, DWORD flags) { - return BASS_PluginLoad((const char *)file, flags | BASS_UNICODE); + return BASS_PluginLoad((const char*)file, flags|BASS_UNICODE); } -static inline HMUSIC BASS_MusicLoad(BOOL mem, const WCHAR *file, QWORD offset, - DWORD length, DWORD flags, DWORD freq) +static inline HMUSIC BASS_MusicLoad(BOOL mem, const WCHAR *file, QWORD offset, DWORD length, DWORD flags, DWORD freq) { - return BASS_MusicLoad(mem, (const void *)file, offset, length, - flags | BASS_UNICODE, freq); + return BASS_MusicLoad(mem, (const void*)file, offset, length, flags|BASS_UNICODE, freq); } -static inline HSAMPLE BASS_SampleLoad(BOOL mem, const WCHAR *file, QWORD offset, - DWORD length, DWORD max, DWORD flags) +static inline HSAMPLE BASS_SampleLoad(BOOL mem, const WCHAR *file, QWORD offset, DWORD length, DWORD max, DWORD flags) { - return BASS_SampleLoad(mem, (const void *)file, offset, length, max, - flags | BASS_UNICODE); + return BASS_SampleLoad(mem, (const void*)file, offset, length, max, flags|BASS_UNICODE); } -static inline HSTREAM BASS_StreamCreateFile(BOOL mem, const WCHAR *file, - QWORD offset, QWORD length, - DWORD flags) +static inline HSTREAM BASS_StreamCreateFile(BOOL mem, const WCHAR *file, QWORD offset, QWORD length, DWORD flags) { - return BASS_StreamCreateFile(mem, (const void *)file, offset, length, - flags | BASS_UNICODE); + return BASS_StreamCreateFile(mem, (const void*)file, offset, length, flags|BASS_UNICODE); } -static inline HSTREAM BASS_StreamCreateURL(const WCHAR *url, DWORD offset, - DWORD flags, DOWNLOADPROC *proc, - void *user) +static inline HSTREAM BASS_StreamCreateURL(const WCHAR *url, DWORD offset, DWORD flags, DOWNLOADPROC *proc, void *user) { - return BASS_StreamCreateURL((const char *)url, offset, flags | BASS_UNICODE, - proc, user); + return BASS_StreamCreateURL((const char*)url, offset, flags|BASS_UNICODE, proc, user); } static inline BOOL BASS_SetConfigPtr(DWORD option, const WCHAR *value) { - return BASS_SetConfigPtr(option | BASS_UNICODE, (const void *)value); + return BASS_SetConfigPtr(option|BASS_UNICODE, (const void*)value); } #endif -#endif - -#endif +#endif + +#endif diff --git a/include/chatlogpiece.h b/include/chatlogpiece.h index 0232666..34c5926 100644 --- a/include/chatlogpiece.h +++ b/include/chatlogpiece.h @@ -1,23 +1,22 @@ #ifndef CHATLOGPIECE_H #define CHATLOGPIECE_H -#include #include +#include -class chatlogpiece { +class chatlogpiece +{ public: chatlogpiece(); - chatlogpiece(QString p_name, QString p_showname, QString p_message, - bool p_song, int color); - chatlogpiece(QString p_name, QString p_showname, QString p_message, - bool p_song, int color, QDateTime p_datetime); + chatlogpiece(QString p_name, QString p_showname, QString p_message, bool p_song); + chatlogpiece(QString p_name, QString p_showname, QString p_message, bool p_song, QDateTime p_datetime); + QString get_name(); QString get_showname(); QString get_message(); bool get_is_song(); QDateTime get_datetime(); QString get_datetime_as_string(); - int get_chat_color(); QString get_full(); @@ -27,7 +26,6 @@ private: QString message; QDateTime datetime; bool is_song; - int color; }; #endif // CHATLOGPIECE_H diff --git a/include/courtroom.h b/include/courtroom.h index 396c4d7..99a090b 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -1,739 +1,668 @@ -#ifndef COURTROOM_H -#define COURTROOM_H - -#include "aoapplication.h" -#include "aoblipplayer.h" -#include "aobutton.h" -#include "aocharbutton.h" -#include "aocharmovie.h" -#include "aoemotebutton.h" -#include "aoevidencebutton.h" -#include "aoevidencedisplay.h" -#include "aoimage.h" -#include "aolineedit.h" -#include "aomovie.h" -#include "aomusicplayer.h" -#include "aooptionsdialog.h" -#include "aopacket.h" -#include "aoscene.h" -#include "aosfxplayer.h" -#include "aotextarea.h" -#include "aotextedit.h" -#include "chatlogpiece.h" -#include "datatypes.h" -#include "debug_functions.h" -#include "file_functions.h" -#include "hardware_functions.h" -#include "lobby.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -class AOApplication; -class AOCharMovie; -class Courtroom : public QMainWindow { - Q_OBJECT -public: - explicit Courtroom(AOApplication *p_ao_app); - - void append_char(char_type p_char) { char_list.append(p_char); } - void append_evidence(evi_type p_evi) { evidence_list.append(p_evi); } - void append_music(QString f_music) { music_list.append(f_music); } - void append_area(QString f_area) { area_list.append(f_area); } - void clear_music() { music_list.clear(); } - void clear_areas() { area_list.clear(); } - void handle_failed_login(); - QString threading_sfx = ""; - QString threading_shake = ""; - QString threading_flash = ""; - QString threading_prefix = ""; - // cid and this may differ in cases of ini-editing - QString current_char = ""; - int current_emote = 0; - AOApplication *ao_app; - // abstract widget to hold char buttons - QWidget *ui_char_buttons; - QVector char_list; - QVector evidence_list; - QVector music_list; - QVector area_list; - QSignalMapper *char_button_mapper; - QVector ui_char_button_list; - QVector ui_char_button_list_filtered; - QLineEdit *ui_char_search; - QCheckBox *ui_char_passworded; - QCheckBox *ui_char_taken; - void mt_pre_framegetter(int frameNumber); - void mt_framegetter(int frameNumber); - void reset_music_list() { music_list.clear(); } - - void arup_append(int players, QString status, QString cm, QString locked) - { - arup_players.append(players); - arup_statuses.append(status); - arup_cms.append(cm); - arup_locks.append(locked); - } - - void arup_modify(int type, int place, QString value) - { - if (type == 0) { - if (arup_players.size() > place) - arup_players[place] = value.toInt(); - } - else if (type == 1) { - if (arup_statuses.size() > place) - arup_statuses[place] = value; - } - else if (type == 2) { - if (arup_cms.size() > place) - arup_cms[place] = value; - } - else if (type == 3) { - if (arup_locks.size() > place) - arup_locks[place] = value; - } - list_areas(); - } - - void character_loading_finished(); - - // sets position of widgets based on theme ini files - void set_widgets(); - // sets font size based on theme ini files - void set_font(QWidget *widget, QString p_identifier); - // helper function that calls above function on the relevant widgets - void set_fonts(); - - void set_window_title(QString p_title); - QPoint get_theme_pos(QString p_identifier); - - // reads theme inis and sets size and pos based on the identifier - void set_size_and_pos(QWidget *p_widget, QString p_identifier); - // sets status as taken on character with cid n_char and places proper shading - // on charselect - void set_taken(int n_char, bool p_taken); - - // sets the current background to argument. also does some checks to see if - // it's a legacy bg - void set_background(QString p_background); - - // sets the evidence list member variable to argument - void set_evidence_list(QVector &p_evi_list); - - // called when a DONE#% from the server was received - void done_received(); - - // 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(); - - // sets text color based on text color in chatmessage - void set_text_color(); - - // And gets the colour, too! - QColor get_text_color(QString color); - - // takes in serverD-formatted IP list as prints a converted version to server - // OOC admittedly poorly named - void set_ip_list(QString p_list); - - // disables chat if current cid matches second argument - // enables if p_muted is false - void set_mute(bool p_muted, int p_cid); - - // send a message that the player is banned and quits the server - void set_ban(int p_cid); - - // cid = character id, returns the cid of the currently selected character - int get_cid() { return m_cid; } - QString get_current_char() { return current_char; } - QString get_current_background() { return current_background; } - - // set the character using an ID - void set_character(int char_id); - - // properly sets up some varibles: resets user state - void enter_courtroom(int p_cid); - - // helper function that populates ui_music_list with the contents of - // music_list - void list_music(); - void list_areas(); - - // these are for OOC chat - void append_ms_chatmessage(QString f_name, QString f_message); - void append_server_chatmessage(QString p_name, QString p_message, - QString p_colour); - - // check whether or not current theme has images for buttons with fallback - // text - void detect_fallback_text(); - - // these functions handle chatmessages sequentially. - // The process itself is very convoluted and merits separate documentation - // But the general idea is objection animation->pre animation->talking->idle - void handle_chatmessage(QStringList *p_contents); - void handle_chatmessage_2(); - void handle_chatmessage_3(); - - // This function filters out the common CC inline text trickery, for appending - // to the IC chatlog. - QString filter_ic_text(QString p_text, bool skip_filter, int chat_color); - - // adds text to the IC chatlog. p_name first as bold then p_text then a newlin - // this function keeps the chatlog scrolled to the top unless there's text - // selected - // or the user isn't already scrolled to the top - void append_ic_text(QString p_text, QString p_name = "", - bool is_songchange = false, bool force_filter = false, - bool skip_filter = false, int chat_color = 0); - - // prints who played the song to IC chat and plays said song(if found on local - // filesystem) takes in a list where the first element is the song name and - // the second is the char id of who played it - void handle_song(QStringList *p_contents); - - void play_preanim(bool noninterrupting); - - // plays the witness testimony or cross examination animation based on - // argument - void handle_wtce(QString p_wtce, int variant); - - // sets the hp bar of defense(p_bar 1) or pro(p_bar 2) - // state is an number between 0 and 10 inclusive - void set_hp_bar(int p_bar, int p_state); - - // Toggles the judge buttons, whether they should appear or not. - void toggle_judge_buttons(bool is_on); - void doScreenShake(); - void doRealization(); - - void announce_case(QString title, bool def, bool pro, bool jud, bool jur, - bool steno, bool wit); - - void check_connection_received(); - - void refresh_iclog(bool skiplast); - - ~Courtroom(); - -private: - int m_courtroom_width = 714; - int m_courtroom_height = 668; - - int m_viewport_x = 0; - int m_viewport_y = 0; - - int m_viewport_width = 256; - int m_viewport_height = 192; - - bool first_message_sent = false; - int maximumMessages = 0; - QPropertyAnimation *screenshake_animation; - QPropertyAnimation *chatbox_screenshake_animation; - QParallelAnimationGroup *screenshake_group; - QMovie *frame_emote_checker; - // This is for inline message-colouring. - - enum INLINE_COLOURS { INLINE_BLUE, INLINE_GREEN, INLINE_ORANGE, INLINE_GREY }; - - // A stack of inline colours. - std::stack inline_colour_stack; - - bool next_character_is_not_special = false; // If true, write the - // next character as it is. - - bool message_is_centered = false; - - int current_display_speed = 3; - int message_display_speed_slow[7] = {30, 40, 50, 60, 75, 100, 120}; - int message_display_speed[7] = {10, 20, 30, 40, 50, 60, 75}; - - // This is for checking if the character should start talking again - // when an inline blue text ends. - bool entire_message_is_blue = false; - - // And this is the inline 'talking checker'. Counts how 'deep' we are - // in inline blues. - int inline_blue_depth = 0; - - // The character ID of the character this user wants to appear alongside with. - int other_charid = -1; - - // The offset this user has given if they want to appear alongside someone. - int offset_with_pair = 0; - - QVector arup_players; - QVector arup_statuses; - QVector arup_cms; - QVector arup_locks; - - QVector ic_chatlog_history; - - // These map music row items and area row items to their actual IDs. - QVector music_row_to_number; - QVector area_row_to_number; - - // triggers ping_server() every 60 seconds - QTimer *keepalive_timer; - - // determines how fast messages tick onto screen - QTimer *chat_tick_timer; - // int chat_tick_interval = 60; - // which tick position(character in chat message) we are at - int tick_pos = 0; - // used to determine how often blips sound - int blip_pos = 0; - int blip_rate = 1; - int rainbow_counter = 0; - bool rainbow_appended = false; - bool blank_blip = false; - - // The cursor to write with in mirror mode - QTextCursor *mirror_cursor; - // Used for getting the current maximum blocks allowed in the IC chatlog. - int log_maximum_blocks = 0; - - // True, if the log should go downwards. - bool log_goes_downwards = false; - - // delay before chat messages starts ticking - QTimer *text_delay_timer; - - // delay before sfx plays - QTimer *sfx_delay_timer; - - // keeps track of how long realization is visible(it's just a white square and - // should be visible less than a second) - QTimer *realization_timer; - - // every time point in char.inis times this equals the final time - const int time_mod = 40; - - // the amount of time non-animated objection/hold it/takethat images stay - // onscreen for in ms - const int shout_stay_time = 724; - - // the amount of time non-animated guilty/not guilty images stay onscreen for - // in ms - const int verdict_stay_time = 3000; - - // the amount of time non-animated witness testimony/cross-examination images - // stay onscreen for in ms - const int wtce_stay_time = 1500; - - static const int chatmessage_size = 28; - QString m_chatmessage[chatmessage_size]; - bool chatmessage_is_empty = false; - - QString previous_ic_message = ""; - - // char id, muted or not - QMap mute_map; - - // QVector muted_cids; - - bool is_muted = false; - - // state of animation, 0 = objecting, 1 = preanim, 2 = talking, 3 = idle, 4 = - // noniterrupting preanim - int anim_state = 3; - - // state of text ticking, 0 = not yet ticking, 1 = ticking in progress, 2 = - // ticking done - int text_state = 2; - - // characters we consider punctuation - const QString punctuation_chars = ".,?!:;"; - - // amount by which we multiply the delay when we parse punctuation chars - int punctuation_modifier = 0; - bool slower_blips = false; - // character id, which index of the char_list the player is - int m_cid = -1; - // cid and this may differ in cases of ini-editing - - QString char_name = ""; - - int objection_state = 0; - bool keep_custom_objection = false; - QString objection_custom = ""; - int realization_state = 0; - int screenshake_state = 0; - int text_color = 0; - bool is_presenting_evidence = false; - - int defense_bar_state = 0; - int prosecution_bar_state = 0; - - int current_char_page = 0; - int char_columns = 10; - int char_rows = 9; - int max_chars_on_page = 90; - - const int button_width = 60; - const int button_height = 60; - - int current_emote_page = 0; - int emote_columns = 5; - int emote_rows = 2; - int max_emotes_on_page = 10; - - QVector local_evidence_list; - - int current_evidence_page = 0; - int current_evidence = 0; - int evidence_columns = 6; - int evidence_rows = 3; - int max_evidence_on_page = 18; - - // is set to true if the bg folder contains defensedesk.png, - // prosecutiondesk.png and stand.png - bool is_ao2_bg = false; - - // whether or not to use text for buttons instead of images, true is text - bool change_char_fallback = true; - bool reload_theme_fallback = true; - bool settings_fallback = true; - bool call_mod_fallback = true; - bool casing_fallback = true; - bool amswap_fallback = true; - bool ooc_toggle_fallback = true; - - // whether the ooc chat is server or master chat, true is server - bool server_ooc = true; - - // Is AFK enabled - bool isafk = false; - QString current_background = "default"; - - AOMusicPlayer *music_player; - AOSfxPlayer *sfx_player; - AOSfxPlayer *misc_sfx_player; - AOSfxPlayer *frame_emote_sfx_player; - AOSfxPlayer *pair_frame_emote_sfx_player; - AOSfxPlayer *objection_player; - AOBlipPlayer *blip_player; - - AOSfxPlayer *modcall_player; - - AOImage *ui_background; - - QWidget *ui_viewport; - AOScene *ui_vp_background; - AOMovie *ui_vp_speedlines; - AOCharMovie *ui_vp_player_char; - AOCharMovie *ui_vp_sideplayer_char; - AOScene *ui_vp_desk; - AOScene *ui_vp_legacy_desk; - AOEvidenceDisplay *ui_vp_evidence_display; - AOImage *ui_vp_chatbox; - QLabel *ui_vp_showname; - QTextEdit *ui_vp_message; - AOMovie *ui_vp_realization; - AOMovie *ui_vp_testimony; - AOMovie *ui_vp_wtce; - AOMovie *ui_vp_objection; - void realization_done(); - - bool colorf_iclog = false; - bool mirror_iclog = false; - bool colorf_limit = false; - - bool keep_evidence_display = false; - - QTextEdit *ui_ic_chatlog; - - AOTextArea *ui_ms_chatlog; - AOTextArea *ui_server_chatlog; - - QListWidget *ui_mute_list; - QListWidget *ui_area_list; - QTreeWidget *ui_music_list; - - AOButton *ui_pair_button; - QListWidget *ui_pair_list; - QSpinBox *ui_pair_offset_spinbox; - - QLineEdit *ui_ic_chat_message; - QLineEdit *ui_ic_chat_name; - - QLineEdit *ui_ooc_chat_message; - QLineEdit *ui_ooc_chat_name; - - // QLineEdit *ui_area_password; - QLineEdit *ui_music_search; - QString music_search_par = ""; - QString area_search_par = ""; - - QWidget *ui_emotes; - QVector ui_emote_list; - AOButton *ui_emote_left; - AOButton *ui_emote_right; - - QComboBox *ui_emote_dropdown; - QComboBox *ui_pos_dropdown; - - AOImage *ui_defense_bar; - AOImage *ui_prosecution_bar; - - QLabel *ui_music_label; - QLabel *ui_sfx_label; - QLabel *ui_blip_label; - - AOButton *ui_hold_it; - AOButton *ui_objection; - AOButton *ui_take_that; - - AOButton *ui_ooc_toggle; - - AOButton *ui_witness_testimony; - AOButton *ui_cross_examination; - AOButton *ui_guilty; - AOButton *ui_not_guilty; - - AOButton *ui_change_character; - AOButton *ui_reload_theme; - AOButton *ui_call_mod; - AOButton *ui_settings; - AOButton *ui_announce_casing; - AOButton *ui_switch_area_music; - - QCheckBox *ui_pre; - QCheckBox *ui_flip; - QCheckBox *ui_guard; - QCheckBox *ui_casing; - - QCheckBox *ui_pre_non_interrupt; - QCheckBox *ui_showname_enable; - - AOButton *ui_custom_objection; - AOButton *ui_realization; - AOButton *ui_screenshake; - AOButton *ui_mute; - - QMenu *custom_obj_menu; - - AOButton *ui_defense_plus; - AOButton *ui_defense_minus; - - AOButton *ui_prosecution_plus; - AOButton *ui_prosecution_minus; - - QComboBox *ui_text_color; - - QSlider *ui_music_slider; - QSlider *ui_sfx_slider; - QSlider *ui_blip_slider; - - AOImage *ui_muted; - - QSpinBox *ui_log_limit_spinbox; - QLabel *ui_log_limit_label; - - AOButton *ui_evidence_button; - AOImage *ui_evidence; - AOLineEdit *ui_evidence_name; - QWidget *ui_evidence_buttons; - QVector ui_evidence_list; - AOButton *ui_evidence_left; - AOButton *ui_evidence_right; - AOButton *ui_evidence_present; - AOImage *ui_evidence_overlay; - AOButton *ui_evidence_delete; - AOLineEdit *ui_evidence_image_name; - AOButton *ui_evidence_image_button; - AOButton *ui_evidence_x; - AOTextEdit *ui_evidence_description; - - AOImage *ui_char_select_background; - - AOImage *ui_selector; - - AOButton *ui_back_to_lobby; - - QLineEdit *ui_char_password; - - AOButton *ui_char_select_left; - AOButton *ui_char_select_right; - - AOButton *ui_spectator; - - void construct_char_select(); - void set_char_select(); - void set_char_select_page(); - void put_button_in_place(int starting, int chars_on_this_page); - void filter_character_list(); - - void construct_emotes(); - void set_emote_page(); - void set_emote_dropdown(); - - void construct_evidence(); - void set_evidence_page(); - -public slots: - void objection_done(); - void preanim_done(); - - void mod_called(QString p_ip); - - void case_called(QString msg, bool def, bool pro, bool jud, bool jur, - bool steno, bool witness); - -private slots: - void start_chat_ticking(); - void play_sfx(); - - void chat_tick(); - - void on_mute_list_clicked(QModelIndex p_index); - void on_pair_list_clicked(QModelIndex p_index); - - void on_chat_return_pressed(); - - void on_ooc_return_pressed(); - - void on_music_search_keypr(); - void on_music_search_edited(QString p_text); - void on_music_list_double_clicked(QTreeWidgetItem *p_item, int column); - void on_area_list_double_clicked(QModelIndex p_model); - - void select_emote(int p_id); - - void on_emote_clicked(int p_id); - - void on_emote_left_clicked(); - void on_emote_right_clicked(); - - void on_emote_dropdown_changed(int p_index); - void on_pos_dropdown_changed(int p_index); - - void on_evidence_name_edited(); - void on_evidence_image_name_edited(); - void on_evidence_image_button_clicked(); - void on_evidence_clicked(int p_id); - void on_evidence_double_clicked(int p_id); - - void on_evidence_hover(int p_id, bool p_state); - - void on_evidence_left_clicked(); - void on_evidence_right_clicked(); - void on_evidence_present_clicked(); - - void on_hold_it_clicked(); - void on_objection_clicked(); - void on_take_that_clicked(); - void on_custom_objection_clicked(); - void ShowContextMenu(const QPoint &pos); - - void on_realization_clicked(); - void on_screenshake_clicked(); - - void on_mute_clicked(); - void on_pair_clicked(); - - void on_defense_minus_clicked(); - void on_defense_plus_clicked(); - void on_prosecution_minus_clicked(); - void on_prosecution_plus_clicked(); - - void on_text_color_changed(int p_color); - - void on_music_slider_moved(int p_value); - void on_sfx_slider_moved(int p_value); - void on_blip_slider_moved(int p_value); - - void on_log_limit_changed(int value); - void on_pair_offset_changed(int value); - - void on_ooc_toggle_clicked(); - - void on_witness_testimony_clicked(); - void on_cross_examination_clicked(); - void on_not_guilty_clicked(); - void on_guilty_clicked(); - - void on_change_character_clicked(); - void on_reload_theme_clicked(); - void on_call_mod_clicked(); - void on_settings_clicked(); - void on_announce_casing_clicked(); - - void on_pre_clicked(); - void on_flip_clicked(); - void on_guard_clicked(); - - void on_showname_enable_clicked(); - - void on_evidence_button_clicked(); - - void on_evidence_delete_clicked(); - void on_evidence_x_clicked(); - - void on_back_to_lobby_clicked(); - - void on_char_select_left_clicked(); - void on_char_select_right_clicked(); - void on_char_search_changed(); - void on_char_taken_clicked(); - void on_char_passworded_clicked(); - - void on_spectator_clicked(); - - void char_clicked(int n_char); - - void on_switch_area_music_clicked(); - - void on_casing_clicked(); - - void ping_server(); - -#ifdef BASSAUDIO - void load_bass_opus_plugin(); -#endif -}; - -#endif // COURTROOM_H +#ifndef COURTROOM_H +#define COURTROOM_H + +#include "aoimage.h" +#include "aobutton.h" +#include "aocharbutton.h" +#include "aoemotebutton.h" +#include "aopacket.h" +#include "aoscene.h" +#include "aomovie.h" +#include "aocharmovie.h" +#include "aomusicplayer.h" +#include "aosfxplayer.h" +#include "aoblipplayer.h" +#include "aoevidencebutton.h" +#include "aotextarea.h" +#include "aolineedit.h" +#include "aotextedit.h" +#include "aoevidencedisplay.h" +#include "datatypes.h" +#include "aoapplication.h" +#include "lobby.h" +#include "hardware_functions.h" +#include "file_functions.h" +#include "datatypes.h" +#include "debug_functions.h" +#include "chatlogpiece.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +class AOApplication; + +class Courtroom : public QMainWindow +{ + Q_OBJECT +public: + explicit Courtroom(AOApplication *p_ao_app); + + void append_char(char_type p_char){char_list.append(p_char);} + void append_evidence(evi_type p_evi){evidence_list.append(p_evi);} + void append_music(QString f_music){music_list.append(f_music);} + void append_area(QString f_area){area_list.append(f_area);} + + void fix_last_area() + { + if (area_list.size() > 0) + { + QString malplaced = area_list.last(); + area_list.removeLast(); + append_music(malplaced); + } + } + + void arup_append(int players, QString status, QString cm, QString locked) + { + arup_players.append(players); + arup_statuses.append(status); + arup_cms.append(cm); + arup_locks.append(locked); + } + + void arup_modify(int type, int place, QString value) + { + if (type == 0) + { + if (arup_players.size() > place) + arup_players[place] = value.toInt(); + } + else if (type == 1) + { + if (arup_statuses.size() > place) + arup_statuses[place] = value; + } + else if (type == 2) + { + if (arup_cms.size() > place) + arup_cms[place] = value; + } + else if (type == 3) + { + if (arup_locks.size() > place) + arup_locks[place] = value; + } + list_areas(); + } + + void character_loading_finished(); + + //sets position of widgets based on theme ini files + void set_widgets(); + //sets font size based on theme ini files + void set_font(QWidget *widget, QString p_identifier); + //helper function that calls above function on the relevant widgets + void set_fonts(); + + void set_window_title(QString p_title); + + //reads theme inis and sets size and pos based on the identifier + void set_size_and_pos(QWidget *p_widget, QString p_identifier); + + //sets status as taken on character with cid n_char and places proper shading on charselect + void set_taken(int n_char, bool p_taken); + + //sets the current background to argument. also does some checks to see if it's a legacy bg + void set_background(QString p_background); + + //sets the evidence list member variable to argument + void set_evidence_list(QVector &p_evi_list); + + //called when a DONE#% from the server was received + void done_received(); + + //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(); + + //sets text color based on text color in chatmessage + void set_text_color(); + + // And gets the colour, too! + QColor get_text_color(QString color); + + //takes in serverD-formatted IP list as prints a converted version to server OOC + //admittedly poorly named + void set_ip_list(QString p_list); + + //disables chat if current cid matches second argument + //enables if p_muted is false + void set_mute(bool p_muted, int p_cid); + + //send a message that the player is banned and quits the server + void set_ban(int p_cid); + + //cid = character id, returns the cid of the currently selected character + int get_cid() {return m_cid;} + QString get_current_char() {return current_char;} + QString get_current_background() {return current_background;} + + //properly sets up some varibles: resets user state + void enter_courtroom(int p_cid); + + //helper function that populates ui_music_list with the contents of music_list + void list_music(); + void list_areas(); + + //these are for OOC chat + void append_ms_chatmessage(QString f_name, QString f_message); + void append_server_chatmessage(QString p_name, QString p_message, QString p_colour); + + //these functions handle chatmessages sequentially. + //The process itself is very convoluted and merits separate documentation + //But the general idea is objection animation->pre animation->talking->idle + void handle_chatmessage(QStringList *p_contents); + void handle_chatmessage_2(); + void handle_chatmessage_3(); + + //This function filters out the common CC inline text trickery, for appending to + //the IC chatlog. + QString filter_ic_text(QString p_text); + + //adds text to the IC chatlog. p_name first as bold then p_text then a newlin + //this function keeps the chatlog scrolled to the top unless there's text selected + // or the user isn't already scrolled to the top + void append_ic_text(QString p_text, QString p_name = "", bool is_songchange = false); + + //prints who played the song to IC chat and plays said song(if found on local filesystem) + //takes in a list where the first element is the song name and the second is the char id of who played it + void handle_song(QStringList *p_contents); + + void play_preanim(bool noninterrupting); + + //plays the witness testimony or cross examination animation based on argument + void handle_wtce(QString p_wtce, int variant); + + //sets the hp bar of defense(p_bar 1) or pro(p_bar 2) + //state is an number between 0 and 10 inclusive + void set_hp_bar(int p_bar, int p_state); + + //Toggles the judge buttons, whether they should appear or not. + void toggle_judge_buttons(bool is_on); + + void announce_case(QString title, bool def, bool pro, bool jud, bool jur, bool steno); + + void check_connection_received(); + + ~Courtroom(); + +private: + AOApplication *ao_app; + + int m_courtroom_width = 714; + int m_courtroom_height = 668; + + int m_viewport_x = 0; + int m_viewport_y = 0; + + int m_viewport_width = 256; + int m_viewport_height = 192; + + bool first_message_sent = false; + int maximumMessages = 0; + + // This is for inline message-colouring. + + enum INLINE_COLOURS { + INLINE_BLUE, + INLINE_GREEN, + INLINE_ORANGE, + INLINE_GREY + }; + + // A stack of inline colours. + std::stack inline_colour_stack; + + bool next_character_is_not_special = false; // If true, write the + // next character as it is. + + bool message_is_centered = false; + + int current_display_speed = 3; + int message_display_speed[7] = {30, 40, 50, 60, 75, 100, 120}; + + // This is for checking if the character should start talking again + // when an inline blue text ends. + bool entire_message_is_blue = false; + + // And this is the inline 'talking checker'. Counts how 'deep' we are + // in inline blues. + int inline_blue_depth = 0; + + // The character ID of the character this user wants to appear alongside with. + int other_charid = -1; + + // The offset this user has given if they want to appear alongside someone. + int offset_with_pair = 0; + + QVector char_list; + QVector evidence_list; + QVector music_list; + QVector area_list; + + QVector arup_players; + QVector arup_statuses; + QVector arup_cms; + QVector arup_locks; + + QVector ic_chatlog_history; + + // These map music row items and area row items to their actual IDs. + QVector music_row_to_number; + QVector area_row_to_number; + + //triggers ping_server() every 60 seconds + QTimer *keepalive_timer; + + //determines how fast messages tick onto screen + QTimer *chat_tick_timer; + //int chat_tick_interval = 60; + //which tick position(character in chat message) we are at + int tick_pos = 0; + //used to determine how often blips sound + int blip_pos = 0; + int blip_rate = 1; + int rainbow_counter = 0; + bool rainbow_appended = false; + bool blank_blip = false; + + // Used for getting the current maximum blocks allowed in the IC chatlog. + int log_maximum_blocks = 0; + + // True, if the log should go downwards. + bool log_goes_downwards = false; + + //delay before chat messages starts ticking + QTimer *text_delay_timer; + + //delay before sfx plays + QTimer *sfx_delay_timer; + + //keeps track of how long realization is visible(it's just a white square and should be visible less than a second) + QTimer *realization_timer; + + //times how long the blinking testimony should be shown(green one in the corner) + QTimer *testimony_show_timer; + //times how long the blinking testimony should be hidden + QTimer *testimony_hide_timer; + + //every time point in char.inis times this equals the final time + const int time_mod = 40; + + static const int chatmessage_size = 23; + QString m_chatmessage[chatmessage_size]; + bool chatmessage_is_empty = false; + + QString previous_ic_message = ""; + + bool testimony_in_progress = false; + + //in milliseconds + const int testimony_show_time = 1500; + + //in milliseconds + const int testimony_hide_time = 500; + + //char id, muted or not + QMap mute_map; + + //QVector muted_cids; + + bool is_muted = false; + + //state of animation, 0 = objecting, 1 = preanim, 2 = talking, 3 = idle, 4 = noniterrupting preanim + int anim_state = 3; + + //state of text ticking, 0 = not yet ticking, 1 = ticking in progress, 2 = ticking done + int text_state = 2; + + //character id, which index of the char_list the player is + int m_cid = -1; + //cid and this may differ in cases of ini-editing + QString current_char = ""; + + int objection_state = 0; + int realization_state = 0; + int text_color = 0; + bool is_presenting_evidence = false; + + int defense_bar_state = 0; + int prosecution_bar_state = 0; + + int current_char_page = 0; + int char_columns = 10; + int char_rows = 9; + int max_chars_on_page = 90; + + const int button_width = 60; + const int button_height = 60; + + int current_emote_page = 0; + int current_emote = 0; + int emote_columns = 5; + int emote_rows = 2; + int max_emotes_on_page = 10; + + QVector local_evidence_list; + + int current_evidence_page = 0; + int current_evidence = 0; + int evidence_columns = 6; + int evidence_rows = 3; + int max_evidence_on_page = 18; + + //is set to true if the bg folder contains defensedesk.png, prosecutiondesk.png and stand.png + bool is_ao2_bg = false; + + //whether the ooc chat is server or master chat, true is server + bool server_ooc = true; + + QString current_background = "default"; + + AOMusicPlayer *music_player; + AOSfxPlayer *sfx_player; + AOSfxPlayer *objection_player; + AOBlipPlayer *blip_player; + + AOSfxPlayer *modcall_player; + + AOImage *ui_background; + + QWidget *ui_viewport; + AOScene *ui_vp_background; + AOMovie *ui_vp_speedlines; + AOCharMovie *ui_vp_player_char; + AOCharMovie *ui_vp_sideplayer_char; + AOScene *ui_vp_desk; + AOScene *ui_vp_legacy_desk; + AOEvidenceDisplay *ui_vp_evidence_display; + AOImage *ui_vp_chatbox; + QLabel *ui_vp_showname; + QTextEdit *ui_vp_message; + AOImage *ui_vp_testimony; + AOImage *ui_vp_realization; + AOMovie *ui_vp_wtce; + AOMovie *ui_vp_objection; + + QTextEdit *ui_ic_chatlog; + + AOTextArea *ui_ms_chatlog; + AOTextArea *ui_server_chatlog; + + QListWidget *ui_mute_list; + QListWidget *ui_area_list; + QListWidget *ui_music_list; + + AOButton *ui_pair_button; + QListWidget *ui_pair_list; + QSpinBox *ui_pair_offset_spinbox; + + QLineEdit *ui_ic_chat_message; + QLineEdit *ui_ic_chat_name; + + QLineEdit *ui_ooc_chat_message; + QLineEdit *ui_ooc_chat_name; + + //QLineEdit *ui_area_password; + QLineEdit *ui_music_search; + + QWidget *ui_emotes; + QVector ui_emote_list; + AOButton *ui_emote_left; + AOButton *ui_emote_right; + + QComboBox *ui_emote_dropdown; + QComboBox *ui_pos_dropdown; + + AOImage *ui_defense_bar; + AOImage *ui_prosecution_bar; + + QLabel *ui_music_label; + QLabel *ui_sfx_label; + QLabel *ui_blip_label; + + AOButton *ui_hold_it; + AOButton *ui_objection; + AOButton *ui_take_that; + + AOButton *ui_ooc_toggle; + + AOButton *ui_witness_testimony; + AOButton *ui_cross_examination; + AOButton *ui_guilty; + AOButton *ui_not_guilty; + + AOButton *ui_change_character; + AOButton *ui_reload_theme; + AOButton *ui_call_mod; + AOButton *ui_settings; + AOButton *ui_announce_casing; + AOButton *ui_switch_area_music; + + QCheckBox *ui_pre; + QCheckBox *ui_flip; + QCheckBox *ui_guard; + QCheckBox *ui_casing; + + QCheckBox *ui_pre_non_interrupt; + QCheckBox *ui_showname_enable; + + AOButton *ui_custom_objection; + AOButton *ui_realization; + AOButton *ui_mute; + + AOButton *ui_defense_plus; + AOButton *ui_defense_minus; + + AOButton *ui_prosecution_plus; + AOButton *ui_prosecution_minus; + + QComboBox *ui_text_color; + + QSlider *ui_music_slider; + QSlider *ui_sfx_slider; + QSlider *ui_blip_slider; + + AOImage *ui_muted; + + QSpinBox *ui_log_limit_spinbox; + QLabel *ui_log_limit_label; + + AOButton *ui_evidence_button; + AOImage *ui_evidence; + AOLineEdit *ui_evidence_name; + QWidget *ui_evidence_buttons; + QVector ui_evidence_list; + AOButton *ui_evidence_left; + AOButton *ui_evidence_right; + AOButton *ui_evidence_present; + AOImage *ui_evidence_overlay; + AOButton *ui_evidence_delete; + AOLineEdit *ui_evidence_image_name; + AOButton *ui_evidence_image_button; + AOButton *ui_evidence_x; + AOTextEdit *ui_evidence_description; + + AOImage *ui_char_select_background; + + //abstract widget to hold char buttons + QWidget *ui_char_buttons; + + QVector ui_char_button_list; + QVector ui_char_button_list_filtered; + AOImage *ui_selector; + + AOButton *ui_back_to_lobby; + + QLineEdit *ui_char_password; + + AOButton *ui_char_select_left; + AOButton *ui_char_select_right; + + AOButton *ui_spectator; + + QLineEdit *ui_char_search; + QCheckBox *ui_char_passworded; + QCheckBox *ui_char_taken; + + void construct_char_select(); + void set_char_select(); + void set_char_select_page(); + void char_clicked(int n_char); + void put_button_in_place(int starting, int chars_on_this_page); + void filter_character_list(); + + void construct_emotes(); + void set_emote_page(); + void set_emote_dropdown(); + + void construct_evidence(); + void set_evidence_page(); + +public slots: + void objection_done(); + void preanim_done(); + + void realization_done(); + + void show_testimony(); + void hide_testimony(); + + void mod_called(QString p_ip); + + void case_called(QString msg, bool def, bool pro, bool jud, bool jur, bool steno); + +private slots: + void start_chat_ticking(); + void play_sfx(); + + void chat_tick(); + + void on_mute_list_clicked(QModelIndex p_index); + void on_pair_list_clicked(QModelIndex p_index); + + void on_chat_return_pressed(); + + void on_ooc_return_pressed(); + + void on_music_search_edited(QString p_text); + void on_music_list_double_clicked(QModelIndex p_model); + void on_area_list_double_clicked(QModelIndex p_model); + + void select_emote(int p_id); + + void on_emote_clicked(int p_id); + + void on_emote_left_clicked(); + void on_emote_right_clicked(); + + void on_emote_dropdown_changed(int p_index); + void on_pos_dropdown_changed(int p_index); + + void on_evidence_name_edited(); + void on_evidence_image_name_edited(); + void on_evidence_image_button_clicked(); + void on_evidence_clicked(int p_id); + void on_evidence_double_clicked(int p_id); + + void on_evidence_hover(int p_id, bool p_state); + + void on_evidence_left_clicked(); + void on_evidence_right_clicked(); + void on_evidence_present_clicked(); + + void on_hold_it_clicked(); + void on_objection_clicked(); + void on_take_that_clicked(); + void on_custom_objection_clicked(); + + void on_realization_clicked(); + + void on_mute_clicked(); + void on_pair_clicked(); + + void on_defense_minus_clicked(); + void on_defense_plus_clicked(); + void on_prosecution_minus_clicked(); + void on_prosecution_plus_clicked(); + + void on_text_color_changed(int p_color); + + void on_music_slider_moved(int p_value); + void on_sfx_slider_moved(int p_value); + void on_blip_slider_moved(int p_value); + + void on_log_limit_changed(int value); + void on_pair_offset_changed(int value); + + void on_ooc_toggle_clicked(); + + void on_witness_testimony_clicked(); + void on_cross_examination_clicked(); + void on_not_guilty_clicked(); + void on_guilty_clicked(); + + void on_change_character_clicked(); + void on_reload_theme_clicked(); + void on_call_mod_clicked(); + void on_settings_clicked(); + void on_announce_casing_clicked(); + + void on_pre_clicked(); + void on_flip_clicked(); + void on_guard_clicked(); + + void on_showname_enable_clicked(); + + void on_evidence_button_clicked(); + + void on_evidence_delete_clicked(); + void on_evidence_x_clicked(); + + void on_back_to_lobby_clicked(); + + void on_char_select_left_clicked(); + void on_char_select_right_clicked(); + void on_char_search_changed(); + void on_char_taken_clicked(); + void on_char_passworded_clicked(); + + void on_spectator_clicked(); + + void on_switch_area_music_clicked(); + + void on_casing_clicked(); + + void ping_server(); + + void load_bass_opus_plugin(); +}; + +#endif // COURTROOM_H diff --git a/include/datatypes.h b/include/datatypes.h index 89d4a40..aaa5de5 100644 --- a/include/datatypes.h +++ b/include/datatypes.h @@ -3,14 +3,16 @@ #include -struct server_type { +struct server_type +{ QString name; QString desc; QString ip; int port; }; -struct emote_type { +struct emote_type +{ QString comment; QString preanim; QString anim; @@ -20,20 +22,23 @@ struct emote_type { int sfx_duration; }; -struct char_type { +struct char_type +{ QString name; QString description; QString evidence_string; bool taken; }; -struct evi_type { +struct evi_type +{ QString name; QString description; QString image; }; -struct chatmessage_type { +struct chatmessage_type +{ QString message; QString character; QString side; @@ -50,25 +55,29 @@ struct chatmessage_type { int flip; }; -struct area_type { +struct area_type +{ QString name; QString background; bool passworded; }; -struct pos_type { +struct pos_type +{ int x; int y; }; -struct pos_size_type { +struct pos_size_type +{ int x = 0; int y = 0; int width = 0; int height = 0; }; -enum CHAT_MESSAGE { +enum CHAT_MESSAGE +{ DESK_MOD = 0, PRE_EMOTE, CHAR_NAME, @@ -91,14 +100,20 @@ enum CHAT_MESSAGE { SELF_OFFSET, OTHER_OFFSET, OTHER_FLIP, - NONINTERRUPTING_PRE, - LOOPING_SFX, - SCREENSHAKE, - FRAME_SCREENSHAKE, - FRAME_REALIZATION, - FRAME_SFX + NONINTERRUPTING_PRE }; -enum COLOR { WHITE = 0, GREEN, RED, ORANGE, BLUE, YELLOW, RAINBOW, PINK, CYAN }; +enum COLOR +{ + WHITE = 0, + GREEN, + RED, + ORANGE, + BLUE, + YELLOW, + RAINBOW, + PINK, + CYAN +}; #endif // DATATYPES_H diff --git a/include/debug_functions.h b/include/debug_functions.h index 383431a..160274c 100644 --- a/include/debug_functions.h +++ b/include/debug_functions.h @@ -1,8 +1,8 @@ #ifndef DEBUG_FUNCTIONS_H #define DEBUG_FUNCTIONS_H -#include #include +#include void call_error(QString message); void call_notice(QString message); diff --git a/include/discord-rpc.h b/include/discord-rpc.h index 455f62a..feb874b 100644 --- a/include/discord-rpc.h +++ b/include/discord-rpc.h @@ -24,63 +24,61 @@ extern "C" { #endif typedef struct DiscordRichPresence { - const char *state; /* max 128 bytes */ - const char *details; /* max 128 bytes */ - int64_t startTimestamp; - int64_t endTimestamp; - const char *largeImageKey; /* max 32 bytes */ - const char *largeImageText; /* max 128 bytes */ - const char *smallImageKey; /* max 32 bytes */ - const char *smallImageText; /* max 128 bytes */ - const char *partyId; /* max 128 bytes */ - int partySize; - int partyMax; - const char *matchSecret; /* max 128 bytes */ - const char *joinSecret; /* max 128 bytes */ - const char *spectateSecret; /* max 128 bytes */ - int8_t instance; + const char* state; /* max 128 bytes */ + const char* details; /* max 128 bytes */ + int64_t startTimestamp; + int64_t endTimestamp; + const char* largeImageKey; /* max 32 bytes */ + const char* largeImageText; /* max 128 bytes */ + const char* smallImageKey; /* max 32 bytes */ + const char* smallImageText; /* max 128 bytes */ + const char* partyId; /* max 128 bytes */ + int partySize; + int partyMax; + const char* matchSecret; /* max 128 bytes */ + const char* joinSecret; /* max 128 bytes */ + const char* spectateSecret; /* max 128 bytes */ + int8_t instance; } DiscordRichPresence; typedef struct DiscordJoinRequest { - const char *userId; - const char *username; - const char *discriminator; - const char *avatar; + const char* userId; + const char* username; + const char* discriminator; + const char* avatar; } DiscordJoinRequest; typedef struct DiscordEventHandlers { - void (*ready)(void); - void (*disconnected)(int errorCode, const char *message); - void (*errored)(int errorCode, const char *message); - void (*joinGame)(const char *joinSecret); - void (*spectateGame)(const char *spectateSecret); - void (*joinRequest)(const DiscordJoinRequest *request); + void (*ready)(void); + void (*disconnected)(int errorCode, const char* message); + void (*errored)(int errorCode, const char* message); + void (*joinGame)(const char* joinSecret); + void (*spectateGame)(const char* spectateSecret); + void (*joinRequest)(const DiscordJoinRequest* request); } DiscordEventHandlers; #define DISCORD_REPLY_NO 0 #define DISCORD_REPLY_YES 1 #define DISCORD_REPLY_IGNORE 2 -DISCORD_EXPORT void Discord_Initialize(const char *applicationId, - DiscordEventHandlers *handlers, +DISCORD_EXPORT void Discord_Initialize(const char* applicationId, + DiscordEventHandlers* handlers, int autoRegister, - const char *optionalSteamId); + const char* optionalSteamId); DISCORD_EXPORT void Discord_Shutdown(void); /* checks for incoming messages, dispatches callbacks */ DISCORD_EXPORT void Discord_RunCallbacks(void); -/* If you disable the lib starting its own io thread, you'll need to call this - * from your own */ +/* If you disable the lib starting its own io thread, you'll need to call this from your own */ #ifdef DISCORD_DISABLE_IO_THREAD DISCORD_EXPORT void Discord_UpdateConnection(void); #endif -DISCORD_EXPORT void Discord_UpdatePresence(const DiscordRichPresence *presence); +DISCORD_EXPORT void Discord_UpdatePresence(const DiscordRichPresence* presence); DISCORD_EXPORT void Discord_ClearPresence(void); -DISCORD_EXPORT void Discord_Respond(const char *userid, - /* DISCORD_REPLY_ */ int reply); +DISCORD_EXPORT void Discord_Respond(const char* userid, /* DISCORD_REPLY_ */ int reply); #ifdef __cplusplus } /* extern "C" */ diff --git a/include/discord_register.h b/include/discord_register.h index 655a3df..4c16b68 100644 --- a/include/discord_register.h +++ b/include/discord_register.h @@ -1,27 +1,25 @@ #pragma once #if defined(DISCORD_DYNAMIC_LIB) -#if defined(_WIN32) -#if defined(DISCORD_BUILDING_SDK) -#define DISCORD_EXPORT __declspec(dllexport) +# if defined(_WIN32) +# if defined(DISCORD_BUILDING_SDK) +# define DISCORD_EXPORT __declspec(dllexport) +# else +# define DISCORD_EXPORT __declspec(dllimport) +# endif +# else +# define DISCORD_EXPORT __attribute__((visibility("default"))) +# endif #else -#define DISCORD_EXPORT __declspec(dllimport) -#endif -#else -#define DISCORD_EXPORT __attribute__((visibility("default"))) -#endif -#else -#define DISCORD_EXPORT +# define DISCORD_EXPORT #endif #ifdef __cplusplus extern "C" { #endif -DISCORD_EXPORT void Discord_Register(const char *applicationId, - const char *command); -DISCORD_EXPORT void Discord_RegisterSteamGame(const char *applicationId, - const char *steamId); +DISCORD_EXPORT void Discord_Register(const char* applicationId, const char* command); +DISCORD_EXPORT void Discord_RegisterSteamGame(const char* applicationId, const char* steamId); #ifdef __cplusplus } diff --git a/include/discord_rich_presence.h b/include/discord_rich_presence.h index 71c85e2..e7ecc6e 100644 --- a/include/discord_rich_presence.h +++ b/include/discord_rich_presence.h @@ -1,12 +1,10 @@ #ifndef DISCORD_RICH_PRESENCE_H #define DISCORD_RICH_PRESENCE_H -#include -#include #include #include +#include #include - #include #include @@ -16,14 +14,12 @@ namespace AttorneyOnline { -class Discord { - Q_DECLARE_TR_FUNCTIONS(Discord) - +class Discord +{ private: - const char *APPLICATION_ID = "399779271737868288"; + const char* APPLICATION_ID = "399779271737868288"; std::string server_name, server_id; int64_t timestamp; - public: Discord(); ~Discord(); @@ -34,5 +30,5 @@ public: void state_spectate(); }; -} // namespace AttorneyOnline +} #endif // DISCORD_RICH_PRESENCE_H diff --git a/include/discord_rpc.h b/include/discord_rpc.h index 6bd4404..3e1441e 100644 --- a/include/discord_rpc.h +++ b/include/discord_rpc.h @@ -24,65 +24,63 @@ extern "C" { #endif typedef struct DiscordRichPresence { - const char *state; /* max 128 bytes */ - const char *details; /* max 128 bytes */ - int64_t startTimestamp; - int64_t endTimestamp; - const char *largeImageKey; /* max 32 bytes */ - const char *largeImageText; /* max 128 bytes */ - const char *smallImageKey; /* max 32 bytes */ - const char *smallImageText; /* max 128 bytes */ - const char *partyId; /* max 128 bytes */ - int partySize; - int partyMax; - const char *matchSecret; /* max 128 bytes */ - const char *joinSecret; /* max 128 bytes */ - const char *spectateSecret; /* max 128 bytes */ - int8_t instance; + const char* state; /* max 128 bytes */ + const char* details; /* max 128 bytes */ + int64_t startTimestamp; + int64_t endTimestamp; + const char* largeImageKey; /* max 32 bytes */ + const char* largeImageText; /* max 128 bytes */ + const char* smallImageKey; /* max 32 bytes */ + const char* smallImageText; /* max 128 bytes */ + const char* partyId; /* max 128 bytes */ + int partySize; + int partyMax; + const char* matchSecret; /* max 128 bytes */ + const char* joinSecret; /* max 128 bytes */ + const char* spectateSecret; /* max 128 bytes */ + int8_t instance; } DiscordRichPresence; typedef struct DiscordUser { - const char *userId; - const char *username; - const char *discriminator; - const char *avatar; + const char* userId; + const char* username; + const char* discriminator; + const char* avatar; } DiscordUser; typedef struct DiscordEventHandlers { - void (*ready)(const DiscordUser *request); - void (*disconnected)(int errorCode, const char *message); - void (*errored)(int errorCode, const char *message); - void (*joinGame)(const char *joinSecret); - void (*spectateGame)(const char *spectateSecret); - void (*joinRequest)(const DiscordUser *request); + void (*ready)(const DiscordUser* request); + void (*disconnected)(int errorCode, const char* message); + void (*errored)(int errorCode, const char* message); + void (*joinGame)(const char* joinSecret); + void (*spectateGame)(const char* spectateSecret); + void (*joinRequest)(const DiscordUser* request); } DiscordEventHandlers; #define DISCORD_REPLY_NO 0 #define DISCORD_REPLY_YES 1 #define DISCORD_REPLY_IGNORE 2 -DISCORD_EXPORT void Discord_Initialize(const char *applicationId, - DiscordEventHandlers *handlers, +DISCORD_EXPORT void Discord_Initialize(const char* applicationId, + DiscordEventHandlers* handlers, int autoRegister, - const char *optionalSteamId); + const char* optionalSteamId); DISCORD_EXPORT void Discord_Shutdown(void); /* checks for incoming messages, dispatches callbacks */ DISCORD_EXPORT void Discord_RunCallbacks(void); -/* If you disable the lib starting its own io thread, you'll need to call this - * from your own */ +/* If you disable the lib starting its own io thread, you'll need to call this from your own */ #ifdef DISCORD_DISABLE_IO_THREAD DISCORD_EXPORT void Discord_UpdateConnection(void); #endif -DISCORD_EXPORT void Discord_UpdatePresence(const DiscordRichPresence *presence); +DISCORD_EXPORT void Discord_UpdatePresence(const DiscordRichPresence* presence); DISCORD_EXPORT void Discord_ClearPresence(void); -DISCORD_EXPORT void Discord_Respond(const char *userid, - /* DISCORD_REPLY_ */ int reply); +DISCORD_EXPORT void Discord_Respond(const char* userid, /* DISCORD_REPLY_ */ int reply); -DISCORD_EXPORT void Discord_UpdateHandlers(DiscordEventHandlers *handlers); +DISCORD_EXPORT void Discord_UpdateHandlers(DiscordEventHandlers* handlers); #ifdef __cplusplus } /* extern "C" */ diff --git a/include/encryption_functions.h b/include/encryption_functions.h index b70e8e6..dc67d12 100644 --- a/include/encryption_functions.h +++ b/include/encryption_functions.h @@ -3,11 +3,11 @@ #include -#include #include -#include -#include #include +#include +#include +#include QString fanta_encrypt(QString p_input, unsigned int key); QString fanta_decrypt(QString p_input, unsigned int key); diff --git a/include/file_functions.h b/include/file_functions.h index 8bb2e5f..6937ed8 100644 --- a/include/file_functions.h +++ b/include/file_functions.h @@ -1,8 +1,8 @@ #ifndef FILE_FUNCTIONS_H #define FILE_FUNCTIONS_H -#include #include +#include #include bool file_exists(QString file_path); diff --git a/include/hex_functions.h b/include/hex_functions.h index d178ba1..285f096 100644 --- a/include/hex_functions.h +++ b/include/hex_functions.h @@ -1,16 +1,17 @@ #ifndef HEX_OPERATIONS_H #define HEX_OPERATIONS_H -#include #include #include -#include #include -#include +#include #include +#include +#include -namespace omni { -std::string int_to_hex(unsigned int input); +namespace omni +{ + std::string int_to_hex(unsigned int input); } -#endif // HEX_OPERATIONS_H +#endif //HEX_OPERATIONS_H diff --git a/include/lobby.h b/include/lobby.h index a9b6057..19276a7 100644 --- a/include/lobby.h +++ b/include/lobby.h @@ -1,16 +1,16 @@ #ifndef LOBBY_H #define LOBBY_H -#include "aobutton.h" #include "aoimage.h" +#include "aobutton.h" #include "aopacket.h" #include "aotextarea.h" -#include -#include -#include #include +#include +#include #include +#include #include #include @@ -19,7 +19,8 @@ class AOApplication; -class Lobby : public QMainWindow { +class Lobby : public QMainWindow +{ Q_OBJECT public: @@ -32,12 +33,12 @@ public: void append_error(QString f_message); void set_player_count(int players_online, int max_players); void set_loading_text(QString p_text); - void show_loading_overlay() { ui_loading_background->show(); } - void hide_loading_overlay() { ui_loading_background->hide(); } + void show_loading_overlay(){ui_loading_background->show();} + void hide_loading_overlay(){ui_loading_background->hide();} QString get_chatlog(); int get_selected_server(); void enable_connect_button(); - void check_update(); + void set_loading_value(int p_value); bool public_servers_selected = true; @@ -74,11 +75,8 @@ private: QProgressBar *ui_progress_bar; AOButton *ui_cancel; - QModelIndex last_model; - void set_size_and_pos(QWidget *p_widget, QString p_identifier); -public slots: - void lobbyThreadHandler(QString loadingText); + private slots: void on_public_servers_clicked(); void on_favorites_clicked(); @@ -91,7 +89,6 @@ private slots: void on_connect_released(); void on_about_clicked(); void on_server_list_clicked(QModelIndex p_model); - void on_server_list_doubleclicked(QModelIndex p_model); void on_chatfield_return_pressed(); }; diff --git a/include/misc_functions.h b/include/misc_functions.h index 5287bee..026c635 100644 --- a/include/misc_functions.h +++ b/include/misc_functions.h @@ -1,8 +1,8 @@ #ifndef MISC_FUNCTIONS_H #define MISC_FUNCTIONS_H -#include #include +#include void delay(int p_milliseconds); diff --git a/include/networkmanager.h b/include/networkmanager.h index ed57a95..08b10db 100644 --- a/include/networkmanager.h +++ b/include/networkmanager.h @@ -1,8 +1,8 @@ #ifndef NETWORKMANAGER_H #define NETWORKMANAGER_H -// Qt for Android has stubbed QDnsLookup. This is not documented in any part of -// their wiki. This prevents SRV lookup/failover behavior from functioning. +// Qt for Android has stubbed QDnsLookup. This is not documented in any part of their wiki. +// This prevents SRV lookup/failover behavior from functioning. // https://bugreports.qt.io/browse/QTBUG-56143 #ifndef ANDROID #define MS_FAILOVER_SUPPORTED @@ -14,16 +14,17 @@ #undef MS_FAILOVER_SUPPORTED #endif -#include "aoapplication.h" #include "aopacket.h" +#include "aoapplication.h" -#include #include +#include #include #include #include -class NetworkManager : public QObject { +class NetworkManager : public QObject +{ Q_OBJECT public: diff --git a/include/text_file_functions.h b/include/text_file_functions.h index 1da4d92..119f38e 100644 --- a/include/text_file_functions.h +++ b/include/text_file_functions.h @@ -3,11 +3,11 @@ #include "aoapplication.h" #include "file_functions.h" -#include -#include -#include -#include #include +#include #include +#include +#include +#include #endif // TEXT_FILE_FUNCTIONS_H diff --git a/resource/translations/ao_de.qm b/resource/translations/ao_de.qm deleted file mode 100644 index 6fd250decadf789e64aa740b969b06e29ee0a58d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23500 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 rpRNU2F - - - - AOApplication - - - Disconnected from server. - Vom Server getrennt. - - - - Error connecting to master server. Will try again in %1 seconds. - Fehler bei der Verbindung zum Master Server. Erneuter Versuch in %1 Sekunden. - - - Error connecting to master server. Will try again in %n seconds. - Fehler bei der Verbindung zum Master Server. Erneuter Versuch in %n Sekunden. - - - - There was an error connecting to the master server. -We deploy multiple master servers to mitigate any possible downtime, but the client appears to have exhausted all possible methods of finding and connecting to one. -Please check your Internet connection and firewall, and please try again. - Es gab einen Fehler beim Verbinden zum Master Server. -Wir verwenden mehrere Master Server um Ausfälle zu verhindern, jedoch hat der Client alle Möglichkeiten einen zu finden erschöpft. -Bitte prüfe deine Internetverbindung und Firewall, und versuche es erneut. - - - - Outdated version! Your version: %1 -Please go to aceattorneyonline.com to update. - Version zu alt! Deine Version: %1 -Bitte besuche aceattorneyonline.com für ein Update. - - - - You have been exiled from AO. -Have a nice day. - Du wurdest von AO befreit. -Schönen Urlaub. - - - - Attorney Online 2 - Attorney Online 2 - - - - Loading - Laden - - - - Loading evidence: -%1/%2 - Lade Beweisstücke: -%1/%2 - - - - - Loading music: -%1/%2 - Lade Musik: -%1/%2 - - - - - Loading chars: -%1/%2 - Lade Charaktere: -%1/%2 - - - - You have been kicked from the server. -Reason: %1 - Du wurdest von diesem Server geschmissen. -Grund: %1 - - - - You have been banned from the server. -Reason: %1 - Du wurdest von diesem Server verbannt. -Grund: %1 - - - - You are banned on this server. -Reason: %1 - Du bist von diesem Server verbannt. -Grund: %1 - - - You have been kicked from the server. -Reason: - Du wurdest von diesem Server geschmissen. -Grund: - - - You are banned on this server. -Reason: - Du wurdest von diesem Server verbannt. -Grund: - - - You have been kicked. - Du wurdest rausgeschmissen. - - - You are banned on this server. - Du wurdest verbannt. - - - - AOCaseAnnouncerDialog - - - Case Announcer - Fallansager - - - - Case title: - Fallname: - - - - Defense needed - Verteidiger benötigt - - - - Prosecution needed - Kläger benötigt - - - - Judge needed - Richter benötigt - - - - Jurors needed - Jury benötigt - - - - Stenographer needed - Stenograph benötigt - - - - Witness needed - Zeuge benötigt - - - - AOOptionsDialog - - - Settings - Einstellungen - - - - Gameplay - Spiel - - - - Theme: - Theme: - - - - Sets the theme used in-game. If the new theme changes the lobby's look as well, you'll need to reload the lobby for the changes to take effect, such as by joining a server and leaving it. - Setzt das Theme. Wenn das neue Theme auch das Aussehen der Lobby verändert, must du diese neu laden um die Änderungen zu sehen. - - - - Gives the default value for the in-game 'Custom shownames' checkbox, which in turn determines whether the client should display custom in-character names. - Setzt den Standardwerd für den eigenen Anzeigenamen. - - - - Sets the default volume for music. - Standardlautstärke für die Musik. - - - - Sets the default volume for SFX sounds, like interjections or other character sound effects. - Standardlautstärke für Soundeffekte. - - - - IC Log - Log - - - - Colorful IC log: - Farbiges Log: - - - - Enables colored text in the log. - Aktiviert farbigen Text im Log. - - - - Only inline coloring: - Nur in-Zeilen Farben: - - - - Only inline coloring will be shown such as <>,|| etc. - Nur die in-Zeilen Farben wie <>,|| etc. werden gezeigt. - - - - Mirror IC log: - Log spiegeln: - - - - IC log will mirror the IC box. Meaning that if somebody gets interrupted nobody will know what they wanted to say. Enable for a more realistic experience. - Das Log spiegelt die Nachrichten. Bedeutet dass wenn jemand unterbrochen wird, kann man nicht sehen was derjenige sagen wollte. Für ein realistischeres Spielerlebnis. - - - - Log goes downwards: - Verlauf geht nach unten: - - - - If ticked, new messages will appear at the bottom (like the OOC chatlog). The traditional (AO1) behaviour is equivalent to this being unticked. - Wenn angehakt werden neue Nachrichten unten erscheinen (wie beim OOC). Das traditionelle (AO1) Verhalten wäre nicht angehakt. - - - - Log length: - Länge: - - - - The amount of messages the IC chatlog will keep before deleting older messages. A value of 0 or below counts as 'infinite'. - Die Menge an Nachrichten die aufgehoben werden bevor alte gelöscht werden. 0 bedeutet unendlich. - - - - Default username: - Standard Benutzername: - - - - Your OOC name will be automatically set to this value when you join a server. - Dein OOC Name wird automatisch auf dies gesetzt. - - - - Custom shownames: - Eigener Anzeigename: - - - Gives the default value for the in-game 'Custom shownames' tickbox, which in turn determines whether the client should display custom in-character names. - Standardwert für die Anzeigename Box, welche den In-Charakter Namen bestimmt. - - - - Backup MS: - Rückfall MS: - - - - If the built-in server lookups fail, the game will try the address given here and use it as a backup master server address. - Wenn dereingebaute Master Server fehlschlägt, wird das Spiel diesen hier verwenden. - - - - Discord: - Discord: - - - - Allows others on Discord to see what server you are in, what character are you playing, and how long you have been playing for. - Erlaubt anderen auf Discord zu sehen auf welchem Server du spielst, welchen Charakter du spielst und wie lange. - - - - Allow Shake/Flash: - Schütteln/Geistesblitz erlauben: - - - - Allows screenshaking and flashing. Disable this if you have concerns or issues with photosensitivity and/or seizures. - Erlaubt schütteln des Bildschirms und weiße Blitze. Deaktiviere dies falls du Bedenken wegen Photosensitivität hast. - - - - Language: - Sprache: - - - - Sets the language if you don't want to use your system language. - Setzte die Sprache falls du nicht die Systemsprache verwenden möchtest. - - - - Slower text speed: - Langsamerer Text: - - - - Set the text speed to be the same as the AA games. - Setzt den Text auf die gleiche Geschwindigkeit wie in den AA Spielen. - - - - Blip delay on punctuations: - Blip Pausen bei Satzzeichen: - - - - Punctuation delay modifier. Enable it for the blips to slow down on punctuations. - Aktivieren damit die Blips bei Satzzeichen langsamer werden. - - - - Callwords - Alarmwörter - - - - <html><head/><body>Enter as many callwords as you would like. These are case insensitive. Make sure to leave every callword in its own line!<br>Do not leave a line with a space at the end -- you will be alerted everytime someone uses a space in their messages.</body></html> - <html><head/><body>Gib so viele Alarmwörter ein wie du möchtest. Groß/Kleinschreibung ist egal. Für jede Wort nur eine Zeile!<br>Bitte keine leere Zeile am Ende -- du bekommst sonst bei jeder Nachricht einen Alarm.</body></html> - - - - Audio - Audio - - - - Audio device: - Audiogerät: - - - - Sets the audio device for all sounds. - Setzt das Audiogerät für all Geräusche. - - - - Music: - Musik: - - - Sets the music's default volume. - Setzt die Musiklautstärke. - - - - SFX: - SFX: - - - Sets the SFX's default volume. Interjections and actual sound effects count as 'SFX'. - Setzt die Lautstärke der Soundeffekte wie Einsprüche und die Geräusche der Charaktere. - - - - Blips: - Blips: - - - - Sets the volume of the blips, the talking sound effects. - Setzt die Lautstärke der Blips, das ist das Geräusch das die Charaktere beim Reden machen. - - - - Blip rate: - Bliprate: - - - - Sets the delay between playing the blip sounds. - Setzt die Pause zwischen einzelnen Blips. - - - - Blank blips: - Leere Blips: - - - - If true, the game will play a blip sound even when a space is 'being said'. - Wenn angehakt wird das Spiel auch bei einem Leerzeichen einen Blip machen. - - - - Enable Looping SFX: - Wiederholende Soundeffekte: - - - - If true, the game will allow looping sound effects to play on preanimations. - Wenn aktiviert, werden wiederholende Soundeffekte bei den Voranimationen erlaubt. - - - - Kill Music On Objection: - Stoppe Musik bei Einspruch: - - - - If true, the game will stop music when someone objects, like in the actual games. - Hält die Musik an wenn jemand "Einspruch" ruft, wie im echten Spiel. - - - - Casing - Fälle - - - - This server supports case alerts. - Dieser Server unterstützt Fallalarme. - - - - This server does not support case alerts. - Dieser Server unterstützt Fallalarme nicht. - - - - Pretty self-explanatory. - Eigentlich selbsterklärend. - - - - Casing: - Fälle: - - - - If checked, you will get alerts about case announcements. - Wenn angehakt wirst du benachrichtigt wenn ein Fall angekündigt wird. - - - - Defense: - Verteidigung: - - - - If checked, you will get alerts about case announcements if a defense spot is open. - Wenn angehakt wirst du benachrichtigt wenn ein Verteidiger benötigt wird. - - - - Prosecution: - Kläger: - - - - If checked, you will get alerts about case announcements if a prosecutor spot is open. - Wenn angehakt wirst du benachrichtigt wenn ein Kläger benötigt wird. - - - - Judge: - Richter: - - - - If checked, you will get alerts about case announcements if the judge spot is open. - Wenn angehakt wirst du benachrichtigt wenn ein Richter benötigt wird. - - - - Juror: - Jury: - - - - If checked, you will get alerts about case announcements if a juror spot is open. - Wenn angehakt wirst du benachrichtigt wenn eine Jury benötigt wird. - - - - Stenographer: - Stenograph: - - - - If checked, you will get alerts about case announcements if a stenographer spot is open. - Wenn angehakt wirst du benachrichtigt wenn ein Stenograph benötigt wird. - - - - CM: - CM: - - - - If checked, you will appear amongst the potential CMs on the server. - Wenn angehakt wirst du als potentielle CM angezeigt. - - - - Witness: - Zeuge: - - - - If checked, you will appear amongst the potential witnesses on the server. - Wenn angehakt wirst du als potentielle Zeuge angezeigt. - - - - Hosting cases: - Fallleitung: - - - - If you're a CM, enter what cases you are willing to host. - Wenn du CM bist, gib ein welche Fälle du spielen möchtest. - - - - Courtroom - - - Password - Passwort - - - - Spectator - Zuschauer - - - - - Search - Suche - - - - Passworded - Gesperrt - - - - Taken - Benutzt - - - Generating chars: -%1/%2 - Generiere Charaktere: -%1/%2 - - - Generating chars: - - Generiere Charaktere: - - - - - Could not find %1 - Konnte %1 nicht finden - - - - Showname - Anzeigename - - - - Message - Nachricht - - - - OOC Message - OOC Nachricht - - - - Name - Name - - - - Pre - Vor - - - - Flip - Spiegeln - - - Guard - Wache - - - - Disable Modcalls - Deaktiviere Moderatorenrufe - - - - - Casing - Fall - - - - Shownames - Anzeigenamen - - - - No Interrupt - Keine Unterbrechung - - - - White - Weiß - - - - Green - Grün - - - - Red - Rot - - - - Orange - Orange - - - - Blue - Blau - - - - Yellow - Gelb - - - - Music - Musik - - - - Sfx - Sfx - - - - Blips - Blips - - - - Log limit - Verlaufsgrenze - - - - - Server - Server - - - - Change character - Charakter ändern - - - - Reload theme - Aussehen neu laden - - - - Call mod - Moderator rufen - - - - Settings - Einstellungen - - - - A/M - A/M - - - - Preanim - Voranimation - - - - Back to Lobby - Zurück zur Lobby - - - - - You were granted the Disable Modcalls button. - Du hast nun den "Modcall deaktivieren" Knopf. - - - - You have been banned. - Du wurdest verbannt. - - - - Too many arguments to save a case! You only need a filename without extension and the courtroom status. - Zu viele Argumente zum Speichern! Bitte gib nur den Dateinamen ohne Erweiterung und den Saalstatus an. - - - %1 has played a song: %2 - %1 hat ein Lied gespielt: %2 - - - - Rainbow - Regenbogen - - - - Pink - Pink - - - - Cyan - Cyan - - - - % offset - % Abstand - - - You were granted the Guard button. - Dir wurde der Wache Knopf gegeben. - - - This does nohing, but there you go. - Dies bewirkt nichts, aber egal. - - - - This does nothing, but there you go. - Dies bewirkt nichts, aber egal. - - - - You opened the settings menu. - Du hast die Einstellungen geöffnet. - - - - You will now pair up with - Du wirst nun mit - - - - if they also choose your character in return. - gepaart, wenn der andere dies auch tut. - - - - You are no longer paired with anyone. - Du bist nicht mehr gepaart. - - - - Are you sure you typed that well? The char ID could not be recognised. - Hast du dich vertippt? Die ID konnte nicht erkannt werden. - - - - You have set your offset to - Dein Abstand ist auf - - - - Your offset must be between -100% and 100%! - Der Abstand muss zwischen -100% und 100% liegen! - - - - That offset does not look like one. - Das sieht nicht wie ein Abstand aus. - - - - You switched your music and area list. - Du hast zwischen Musik- und Gebitsliste umgeschaltet. - - - - You have forcefully enabled features that the server may not support. You may not be able to talk IC, or worse, because of this. - Du hast Funktionen erzwungen die der Server eventuell nicht unterstützt. Möglicherweise wirst du nicht mehr sprechen können. - - - - Your pre-animations interrupt again. - Deine Voranimation unterbrechen nun Text. - - - - Your pre-animations will not interrupt text. - Deine Voranimation unterbrechen Text nicht. - - - - Couldn't open chatlog.txt to write into. - Konnte chatlog.txt nicht öffnen. - - - - The IC chatlog has been saved. - Der IC Verlauf wurde gespeichert. - - - - You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely the case file you're looking for can't be found in there. - Du hattest keinen 'base/cases' Ordner! Ich hab ihn nun angelegt aber bedenke das er leer sein wird. - - - - You need to give a filename to load (extension not needed)! Make sure that it is in the `base/cases/` folder, and that it is a correctly formatted ini. -Cases you can load: %1 - Du musst einen Dateinamen angeben (ohne .ini). Stelle sicher das er im 'base/cases' Ordner ist und das er korrekt formatiert ist. -Verfügbare Fälle: %1 - - - - Case made by %1. - Fall von %1. - - - - Navigate to %1 for the CM doc. - Gehe zu %1 für das CM Dokument. - - - - Your case "%1" was loaded! - Dein Fall "%1" wurde geladen! - - - You need to give a filename to load (extension not needed)! Make sure that it is in the `base/cases/` folder, and that it is a correctly formatted ini. -Cases you can load: - Du musst einen Dateinamen angeben (ohne .ini). Stelle sicher das er im 'base/cases' Ordner ist und das er korrekt formatiert ist. -Verfügbare Fälle: - - - - Too many arguments to load a case! You only need one filename, without extension. - Zu viele Argumente! Du brauchst nur den Dateinamen, ohne Erweiterung. - - - Case made by - Fall von - - - Navigate to - Gehe zu - - - for the CM doc. - für das CM Dokument. - - - Your case " - Dein Fall " - - - " was loaded! - " wurde geladen! - - - - You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely that you somehow deleted it. - Du hattest keinen 'base/cases' Ordner! Ich hab ihn nun angelegt aber bedenke das er leer sein wird. - - - - You need to give a filename to save (extension not needed) and the courtroom status! - Du musst einen Dateinamen (ohne Erweiterung) angebenn, sowie den Gebietsstatus! - - - Too many arguments to save a case! You only need a filename without extension and the courtroom status! - Zu viele Argumente! Du brauchst nur den Dateinamen, ohne Erweiterung sowie den Gebietsstatus! - - - - Succesfully saved, edit doc and cmdoc link on the ini! - Erfolgreich gespeichert! - - - - Master - Master - - - - Reason: - Grund: - - - - Call Moderator - Moderator rufen - - - - - Error - Fehler - - - - You must provide a reason. - Du musst einen Grund angeben. - - - - The message is too long. - Die Nachricht ist zu lang. - - - Choose.. - Wähle.. - - - - Choose... - Wähle... - - - - Images (*.png) - Bilder (*.png) - - - - Add new evidence... - Neues Beweisstück... - - - - Discord - - Objection! - Einspruch! - - - In Lobby - In Lobby - - - Idle - Untätig - - - In a Server - In einem Server - - - Playing as %1 - Spielt als %1 - - - Spectating - Zuschauend - - - - Lobby - - - Attorney Online 2 - Attorney Online 2 - - - - Name - Name - - - - It doesn't look like your client is set up correctly. -Did you download all resources correctly from tiny.cc/getao, including the large 'base' folder? - Dein Client ist nicht korrekt eingerichtet. -Hast du ALLES von tiny.cc/getao heruntergeladen und entpackt, auch den großen 'base' Ordner? - - - - Version: %1 - Version: %1 - - - - Loading - Laden - - - - Cancel - Abbrechen - - - - <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Cents02<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, Raidensnake - <h2>Attorney Online %1</h2>Der Gerichtsdrama Simulator<p><b>Quelltext:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Leitende Entwicklung:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Cents02<p><b>Danksagungen:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, Raidensnake - - - <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy - <h2>Attorney Online %1</h2>Der Gerichtsdrama Simulator<p><b>Quelltext:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Leitende Entwicklung:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>Danksagungen:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy - - - - Online: %1/%2 - Online: %1/%2 - - - Attorney Online 2 is built using Qt 5.11. - -Lead development: -longbyte1 -OmniTroid - -stonedDiscord -Supporting development: -Fiercy - -UI design: -Ruekasu -Draxirch - -Special thanks: -Unishred -Argoneus -Noevain -Cronnicossy - Attorney Online 2 wurde gemacht mit Qt 5.11. - -Leitende Entwicklung: -longbyte1 -OmniTroid -stonedDiscord - -Unterstützende Entwicklung: -Fiercy - -UI Design: -Ruekasu -Draxirch - -Speziellen Dank: -Unishred -Argoneus -Noevain -Cronnicossy - - - - - Offline - Offline - - - - debug_functions - - - Error: %1 - Fehler: %1 - - - - Error - Fehler - - - - Notice - Hinweis - - - diff --git a/resource/translations/ao_en.qm b/resource/translations/ao_en.qm deleted file mode 100644 index 9dad8dffceb9623e88f8b96d9cd0caf25574c6fa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23 fcmcE7ks@*G{hX<16=n7(EZlpygMop8iIEWihQJ9+ diff --git a/resource/translations/ao_en.ts b/resource/translations/ao_en.ts deleted file mode 100644 index 9719319..0000000 --- a/resource/translations/ao_en.ts +++ /dev/null @@ -1,937 +0,0 @@ - - - - - AOApplication - - - Disconnected from server. - - - - - Error connecting to master server. Will try again in %1 seconds. - - - - - There was an error connecting to the master server. -We deploy multiple master servers to mitigate any possible downtime, but the client appears to have exhausted all possible methods of finding and connecting to one. -Please check your Internet connection and firewall, and please try again. - - - - - Outdated version! Your version: %1 -Please go to aceattorneyonline.com to update. - - - - - You have been exiled from AO. -Have a nice day. - - - - - Attorney Online 2 - - - - - Loading - - - - - Loading evidence: -%1/%2 - - - - - - Loading music: -%1/%2 - - - - - - Loading chars: -%1/%2 - - - - - You have been kicked from the server. -Reason: %1 - - - - - You have been banned from the server. -Reason: %1 - - - - - You are banned on this server. -Reason: %1 - - - - - AOCaseAnnouncerDialog - - - Case Announcer - - - - - Case title: - - - - - Defense needed - - - - - Prosecution needed - - - - - Judge needed - - - - - Jurors needed - - - - - Stenographer needed - - - - - Witness needed - - - - - AOOptionsDialog - - - Settings - - - - - Gameplay - - - - - Theme: - - - - - Sets the theme used in-game. If the new theme changes the lobby's look as well, you'll need to reload the lobby for the changes to take effect, such as by joining a server and leaving it. - - - - - Gives the default value for the in-game 'Custom shownames' checkbox, which in turn determines whether the client should display custom in-character names. - - - - - Sets the default volume for music. - - - - - Sets the default volume for SFX sounds, like interjections or other character sound effects. - - - - - IC Log - - - - - Colorful IC log: - - - - - Enables colored text in the log. - - - - - Only inline coloring: - - - - - Only inline coloring will be shown such as <>,|| etc. - - - - - Mirror IC log: - - - - - IC log will mirror the IC box. Meaning that if somebody gets interrupted nobody will know what they wanted to say. Enable for a more realistic experience. - - - - - Log goes downwards: - - - - - If ticked, new messages will appear at the bottom (like the OOC chatlog). The traditional (AO1) behaviour is equivalent to this being unticked. - - - - - Log length: - - - - - The amount of messages the IC chatlog will keep before deleting older messages. A value of 0 or below counts as 'infinite'. - - - - - Default username: - - - - - Your OOC name will be automatically set to this value when you join a server. - - - - - Custom shownames: - - - - - Backup MS: - - - - - If the built-in server lookups fail, the game will try the address given here and use it as a backup master server address. - - - - - Discord: - - - - - Allows others on Discord to see what server you are in, what character are you playing, and how long you have been playing for. - - - - - Allow Shake/Flash: - - - - - Allows screenshaking and flashing. Disable this if you have concerns or issues with photosensitivity and/or seizures. - - - - - Language: - - - - - Sets the language if you don't want to use your system language. - - - - - Slower text speed: - - - - - Set the text speed to be the same as the AA games. - - - - - Blip delay on punctuations: - - - - - Punctuation delay modifier. Enable it for the blips to slow down on punctuations. - - - - - Callwords - - - - - <html><head/><body>Enter as many callwords as you would like. These are case insensitive. Make sure to leave every callword in its own line!<br>Do not leave a line with a space at the end -- you will be alerted everytime someone uses a space in their messages.</body></html> - - - - - Audio - - - - - Audio device: - - - - - Sets the audio device for all sounds. - - - - - Music: - - - - - SFX: - - - - - Blips: - - - - - Sets the volume of the blips, the talking sound effects. - - - - - Blip rate: - - - - - Sets the delay between playing the blip sounds. - - - - - Blank blips: - - - - - If true, the game will play a blip sound even when a space is 'being said'. - - - - - Enable Looping SFX: - - - - - If true, the game will allow looping sound effects to play on preanimations. - - - - - Kill Music On Objection: - - - - - If true, the game will stop music when someone objects, like in the actual games. - - - - - Casing - - - - - This server supports case alerts. - - - - - This server does not support case alerts. - - - - - Pretty self-explanatory. - - - - - Casing: - - - - - If checked, you will get alerts about case announcements. - - - - - Defense: - - - - - If checked, you will get alerts about case announcements if a defense spot is open. - - - - - Prosecution: - - - - - If checked, you will get alerts about case announcements if a prosecutor spot is open. - - - - - Judge: - - - - - If checked, you will get alerts about case announcements if the judge spot is open. - - - - - Juror: - - - - - If checked, you will get alerts about case announcements if a juror spot is open. - - - - - Stenographer: - - - - - If checked, you will get alerts about case announcements if a stenographer spot is open. - - - - - CM: - - - - - If checked, you will appear amongst the potential CMs on the server. - - - - - Witness: - - - - - If checked, you will appear amongst the potential witnesses on the server. - - - - - Hosting cases: - - - - - If you're a CM, enter what cases you are willing to host. - - - - - Courtroom - - - Password - - - - - Spectator - - - - - - Search - - - - - Passworded - - - - - Taken - - - - - Could not find %1 - - - - - Showname - - - - - Message - - - - - OOC Message - - - - - Name - - - - - Pre - - - - - Flip - - - - - - Casing - - - - - Shownames - - - - - No Interrupt - - - - - White - - - - - Green - - - - - Red - - - - - Orange - - - - - Blue - - - - - Yellow - - - - - - You were granted the Disable Modcalls button. - - - - - This does nothing, but there you go. - - - - - You need to give a filename to load (extension not needed)! Make sure that it is in the `base/cases/` folder, and that it is a correctly formatted ini. -Cases you can load: %1 - - - - - Case made by %1. - - - - - Navigate to %1 for the CM doc. - - - - - Your case "%1" was loaded! - - - - - Too many arguments to save a case! You only need a filename without extension and the courtroom status. - - - - - - Server - - - - - Back to Lobby - - - - - Rainbow - - - - - Disable Modcalls - - - - - Pink - - - - - Cyan - - - - - % offset - - - - - Music - - - - - Sfx - - - - - Blips - - - - - Log limit - - - - - Change character - - - - - Reload theme - - - - - Call mod - - - - - Settings - - - - - A/M - - - - - Preanim - - - - - You have been banned. - - - - - You opened the settings menu. - - - - - You will now pair up with - - - - - if they also choose your character in return. - - - - - You are no longer paired with anyone. - - - - - Are you sure you typed that well? The char ID could not be recognised. - - - - - You have set your offset to - - - - - Your offset must be between -100% and 100%! - - - - - That offset does not look like one. - - - - - You switched your music and area list. - - - - - You have forcefully enabled features that the server may not support. You may not be able to talk IC, or worse, because of this. - - - - - Your pre-animations interrupt again. - - - - - Your pre-animations will not interrupt text. - - - - - Couldn't open chatlog.txt to write into. - - - - - The IC chatlog has been saved. - - - - - You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely the case file you're looking for can't be found in there. - - - - - Too many arguments to load a case! You only need one filename, without extension. - - - - - You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely that you somehow deleted it. - - - - - You need to give a filename to save (extension not needed) and the courtroom status! - - - - - Succesfully saved, edit doc and cmdoc link on the ini! - - - - - Master - - - - - Reason: - - - - - Call Moderator - - - - - - Error - - - - - You must provide a reason. - - - - - The message is too long. - - - - - Choose... - - - - - Images (*.png) - - - - - Add new evidence... - - - - - Lobby - - - Attorney Online 2 - - - - - Name - - - - - It doesn't look like your client is set up correctly. -Did you download all resources correctly from tiny.cc/getao, including the large 'base' folder? - - - - - Version: %1 - - - - - Loading - - - - - Cancel - - - - - <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Cents02<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, Raidensnake - - - - - Online: %1/%2 - - - - - - Offline - - - - - debug_functions - - - Error: %1 - - - - - Error - - - - - Notice - - - - diff --git a/resource/translations/ao_es.qm b/resource/translations/ao_es.qm deleted file mode 100644 index 42ca3a006295aa12bbbe5ad28617f6dd55081d1f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28457 zcmd6Q3wT`RdFC%!cS|yN8$!sDiz}PRBilfrwh+jYjb$Xuwgd(W31?=GW{x#;&ScJv zWjT4=kc8b_Skg3`ln}}Wo=vx9Hy0Axr@2AW?vu7ONjIT++9ZT6O}1&W(6URK3rS($ z_y6WU=gjEL*db)w5NkB&{MYaLe&2u5*dJv#JoZobzV}N*7e0F1{h$5TZlyZ!R%+@h zr6$Id+SjMlxvy60$Q?>eU#ZlM599MYO5OA~O6`A0b-d>fl$zYAIzD<*sXhNubv&+= z+Izn0+;_QB*B+72e6Q*(U59#os`Cw>QffzD^|U{t)N4PhUb%Kisr(hIm97XJJ>^mCcI`F4Dt z*{N=Q_Crb?>Q}e__5r1?_?&wG)!$cY+d*|t;W4GwA5fyh9hf?D|RbTkV zlS*y*ruxd37nFL{uc;pl-G}-=XzTIct<-flxApwVJxZPTP}`P|egxJ2xy`%XLq9)k zd;R5iDK)#;cKZiWfBjF}e)Am|xAUX6|9oHq^E#{TuV(&HsZC#Rd-^fFpM0c!;61Me zJwMkz^cKwj>}T6A`6R}*>qG5V|JhqGuSeSL=ME^kXs0q}3%6>A>*ZG2waw&n*nVtku_XUz})=N|BJpyS~B|E^Tu zg&qIyqba4<{-EPM-AB>?KX=?c{Ta;bPdo1Z;I(M?e)*g_qvJ1k4Jvj0Ovl&ek0|wu zwH^O^v`?w6&vyKRpLV|D!|%ZJvpO$)-_7{k+j-@Ke+<5Tt8?Z* zq5aY8J8$^tdzEtccG_#E(C^mH{9C_lKkIV$zW`ZIcm2ls z-vGVmy58~x<~MO`*ME5u-`NRz?f-H2t9D%k8839-@=eJ1H9zdm7EUU4X0H34 zZ~ZXj_NML+%z|&{T+{vdIjFz$y6z{gdPFH}vHK^xo>!{Z?S8S^f$_huCv_ZjoV>ed z?AT41{~bNotV6j2H}|}0`Uvwzi{1)nM`*iQjyIknW zW4+E@DDR%%TYhK(^!>x$cXWIo{Cd3ifnoHs@RQz8um6ftJ+JTm!i!%9J$~H#XAgf8 zbTp6?h~cfeEXHQyMx>vI<=bWb9mAc#>_?Ll=;NSYekt2{d zrR3AOcW~;>J0Y(p2Y>zlzM$0h+~CQte;Muf4*vV^W>Nl;!G~Ur@8d@YKYqtQDmA=w z@Zme#pr2ov(%caMz8#{VwqT z+v~2S9T|G}I&TtoYyVf*-TlRjLC1l0pZGAwzkSQPzqsN_*pZ9ZeRbUdrABsv*=}jg zi}+s;huejJXHHZqe%W(YtU0gXdXBZD8&3x&<|ay|f}61`uJ5(2!K2I6lyX#{GRjvT ze#@wevQ-w}Ec|p-0iOXr%j%eN_4Beyh25M#*V+q(JsuFJYRzO(RFe!6(ZVabqI4~P>;;q5#IYGIfjN;~?ejeefOGf!3V z8NJ%lYuID=jBjVrQ4=Cw)>sk4FJbs39l2<$ zqxcr6ovKeyZWKRvgpHq5Yuw7@?Q*cQZ`1bCP0gfZM?y~|BPD^v%iuS=Nk8jNKh7~X z>v$Qbbyp(^T@}^yn1+jPnspLRrdSQ!OzR##rtVia)X3zj=P-PcrvR-}?5p@JptlqF z%;Mh=-p}Kyg$WCBrPfY7q0IEDX|$08*-3256D5>wIrv$@f0S}6)rw{d+vc|vO8AgN zGL8H!@(RRg0j;>(LA87HBFPJ8&Ft zggc}RY0UnFk`+8z!9Ug}-IqbV0{$DRJwK*fEND#^el%Kx0%jNLcH72Mad@=j*STA{Q|d$3rZQwdA^p02#;mYrqvGNQj>Hk6~#mNk==TOcboI7jY@ zW3V6@q^@w)I1#b2)DUuUwe3zpj}D`y6Po8W-3pD>7Rb3}gF|T>UM6c{$d$Ys7`xkd z7=!gaDnJukdAh@-J)^k4v|(=JFg4%Oj^mlZYJW%`*L>osM|)cWQ5{8vpz$yym9b8! zIhc|@b*QF9qLg$dWC|S_8A1gUL-!2cgo3Y9^&@tUy9MLHC+1Rp`zV99<+&Niti94q z2o{=*w}gHR7)N}>iAbU)^BbtTXpEQ9sw6$rzZXFhui;G!&+msS3sQexw;{Mo#>$^ZF-oJ} zGUED~8O$$;qlB_PP#8@sk<2sblhhjuXLO)854Ow^(}>iU6`Ih*ipeEM*(Xg6DM7jl zUSZ9G+J$eNJ>RGCPvR5PE=v&Wh~87gWfnxBCs5NMCYB>bT|Ae*g%ZhQkTRSzU4ukG zG|mzxkbk2Xi;)z53nj`ZSld}+`AV@cK9+av?CAJd+Rv_x?;)bFfSrm2IT>JxWxot` zf+s*6*0NtMWUYd`HyaP)`PoANnbz!%>01)XI-p$%e@R3!#1Ns5{Ap8N)jap