From 3c0cedbe922c9fcacd0d171423f83e375f66e178 Mon Sep 17 00:00:00 2001 From: iamgoofball Date: Fri, 18 Jan 2019 19:08:56 -0800 Subject: [PATCH] Add screenshake, frame-specific effects, looping SFX, and clientside music looping Committed by patch since Goof is currently banned on GitHub for no good reason. --- Attorney_Online.pro | 2 +- base/themes/default/courtroom_design.ini | 3 + base/themes/default/screenshake.png | Bin 0 -> 3507 bytes base/themes/default/screenshake_pressed.png | Bin 0 -> 3324 bytes include/aoapplication.h | 29 +- include/aocharmovie.h | 28 +- include/aomusicplayer.h | 18 +- include/aooptionsdialog.h | 4 + include/aosfxplayer.h | 10 +- include/courtroom.h | 23 +- include/datatypes.h | 7 +- src/aocharmovie.cpp | 294 +++++++++++--------- src/aomusicplayer.cpp | 44 ++- src/aooptionsdialog.cpp | 25 ++ src/aosfxplayer.cpp | 31 ++- src/courtroom.cpp | 271 +++++++++++++++++- src/packet_distribution.cpp | 3 + src/text_file_functions.cpp | 48 ++++ 18 files changed, 669 insertions(+), 171 deletions(-) create mode 100644 base/themes/default/screenshake.png create mode 100644 base/themes/default/screenshake_pressed.png diff --git a/Attorney_Online.pro b/Attorney_Online.pro index 39366c0..73d3534 100644 --- a/Attorney_Online.pro +++ b/Attorney_Online.pro @@ -11,7 +11,7 @@ OBJECTS_DIR = $$PWD/build MOC_DIR = $$PWD/build SOURCES += $$files($$PWD/src/*.cpp) -HEADERS += $$files($$PWD/include/*.h) +HEADERS += $$files($$PWD/include/*.h) $$PWD/include/aomusicplayer.h $$PWD/include/aosfxplayer.h LIBS += -L$$PWD/lib -lbass -ldiscord-rpc CONFIG += c++11 diff --git a/base/themes/default/courtroom_design.ini b/base/themes/default/courtroom_design.ini index 960d6e4..fe8fadf 100644 --- a/base/themes/default/courtroom_design.ini +++ b/base/themes/default/courtroom_design.ini @@ -132,6 +132,9 @@ 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 diff --git a/base/themes/default/screenshake.png b/base/themes/default/screenshake.png new file mode 100644 index 0000000000000000000000000000000000000000..5b71e3bc5b53454f483b7dec9bafc39ac9da3427 GIT binary patch literal 3507 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 xPs#eJ@sjuKkJKHNl+6k{Q-m3dsZ@*mIXZOQ-u literal 0 HcmV?d00001 diff --git a/base/themes/default/screenshake_pressed.png b/base/themes/default/screenshake_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..43e01c85f2c4098af8c7799c00d40e90c3260adf GIT binary patch literal 3324 zcmb_f2~-nV77aEkg4zg(925!BcCVzelQIDzVF{XmfmT}FDpeJTB&nE%O%w-E!3|kl zK+r)%#08xO#to1WZCu9%5p6{f6c@w|1vflXVQZaZJDxt1bE@iB{rB&?@BRD!J4p_Z z`V6ylv?P&8!^FNK8S$KAx-13}_cK-JLWsu@t?w^-63NQebeWN|vK>gI!C}gvU_-EE z7KGqxDvaWCj2flZ64oRV-#tnTBjK2VEXP8X8Uf|`iIWtv5*1M9vL&EIE5yQ-zA-v1 zFh&}L#DpU}l;ZA2=0`yUfEqKvjM?)62y z2`FI(gBGIEA|oTIkxVMC3#HL{JRS{X&=?GWumJSY8Uq{!X!PUy5JZ?B(J8eCC9WZx z5MeoPGzcgJ)1DC2+J0D#zBf%o!e~*jmPV(7rjWV~QKa8aYt*T_oudd1Q(>xT9qSGO^>r~w5|U#SsGI4|;4Srhq|~E5M)=kQkT60(fi=4^UuCHp^9kFxgB+9~*z2lBh{o^*O4E z6-pqoIZPgmuoZwS9b*C*%whmMCY?aUSRjWd=b;FLZc_dqp8HTdi1_rxrt5nv%M%Xm z9jTOVUnk9>a~K%HMFAF@%?3aPiw(dWItCytkS%A+Q8~;(`7~2e5fJ2_Q4cKb+y1+y z4*4oge4=|<1Y%43`H;KS4Z(=1Y6TR;Bv%Zj^nO-;Ww*X7FTLv{!!QE$8yfEMuE!OI zNLYt?gc3XZJ!L}sGyZxw;@j*o4hn)i1qZ+o4%2i@vH&^EWdaN?OF>8#WpP~DebIl( zzPGGE2<)%GzsSBfIY=0+3B`y;K%@Nic)qW8dWe2Cp3jeo|7$$mYVDC4?Y~vnJ@;9= z=#w7t`TZlqH+7fqio$tw_sOr_6jy4fzYR(l^|XAJvxOZ3 zj;dj8ejf)rv}C_~o~aM_LR14mK`mcS-#NutR(BOdV8!}ire}C_uwt7lv#j$ z$EcDOHO6H1?cgn5$L9amUY2WUZJrPv8+-A_jp=t!x;HkGXZTqNLCLwMrU8Z5$E2sH z+pRluFNu@a!9T1XT?Ot9TEbt}5l=4JmYvC+UUgJ)xcrP;v5#t&MT5e0LsUUY4O{bf5QZW~%P!{T2pEjyzY zt`CAF*0Geja3L>i{|43U1$D{Zd1IWMUOxFb_1*oS5*ufwkzm&{I78Nz@c3N%#Dg!p zK6HjO*VfkFxcO_vgHwiV@M%%=)}3*x4e9MO!?O5+k=*PHKHIl#Kbe&Ax^%(}oy$gR zIX}9jOFTI9NRz!_L3wlKjk>zvMT@2rrmYwgAh& zk@V@^{U0-CMnAiA>`ZgD`{wiIaPkbly<^6t#-&&Nb7bc;Al3Kg zxVCYLjiSJ77e3~+Gnveli;c#dRYCSOjM2PyTd^b|=M?8mz1n^h?boB*ye&M+7Z%70 z4Yjwz52bET^Bo_bk>;1b_W9rfn zpo?0*`YIGt=us*QjeG9YKwC6=w3x(O5@@s9Qb4)Fa#V_0=h07X&UcQw&1CRuD33oZ zps0g)zm4)DoDFm)~9%>rjye%tK0b-Q&Os{Uf6n5b8}^hxl1yni*bC7D#C1XX|7|F z2ib*+iz?<#Y&LRY6LNyo030Ge7zVS(^uxY8)g1Qhh_S%ut zufBP-toH8UAIDmoyQGZm@-97oHLFu_Sp7rd>eiUk&E;JF{-Vx!Yx&#PyIXB)`0rw4 z%=gtg?j_Z%ADWL_Ps)Gqv;0GP%#P~Qr_H(egvp!viicFDVEf;XE;}o|$F3_nlU#i; zFx7o8t>aYT;wOXajL9MjQA5*cRqICGR#jZIO|HBqiyzIUng#5yeLv_L=x}yd+Y5e* z?%2ia*X@Y%w6bEpU6GVAU;+NoB_b;7EjB*(a{HvsenfSTw{fviTEAZITxaA#kmK}o zxhWMx8agL$z0llJW9wJ=vWyxx{G-3&&fDkK#xXv2mIGDGN+O@d*<6~7RWD5(zUh*} zi#V?q{r*Oh8&J74+q~q#?CPbWhpQa4E%`s&mQ#;FM)sRG>FOf #include #include +#include +#include "include/aosfxplayer.h" +#include "include/courtroom.h" + class AOApplication; - class AOCharMovie : public QLabel { Q_OBJECT @@ -22,25 +25,41 @@ public: void play_idle(QString p_char, QString p_emote); void set_flipped(bool p_flipped) {m_flipped = p_flipped;} - + void LoadImageWithStupidMethodForFlipSupport(QImage image); void stop(); void move(int ax, int ay); - void combo_resize(int w, int h); + 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; private: AOApplication *ao_app; QMovie *m_movie; QVector movie_frames; QTimer *preanim_timer; + QTimer *ticker; + QString last_path; + QString current_emote; + QString current_char; const int time_mod = 62; // These are the X and Y values before they are fixed based on the sprite's width. int x = 0; int y = 0; + int default_w; + int default_h; bool m_flipped = false; @@ -50,8 +69,7 @@ signals: void done(); private slots: - void frame_change(int n_frame); void timer_done(); + void movie_ticker(); }; - #endif // AOCHARMOVIE_H diff --git a/include/aomusicplayer.h b/include/aomusicplayer.h index 560a7f9..54f3b5f 100644 --- a/include/aomusicplayer.h +++ b/include/aomusicplayer.h @@ -7,22 +7,32 @@ #include #include #include +#include +#include -class AOMusicPlayer +class AOMusicPlayer : public QObject { + Q_OBJECT public: AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app); - ~AOMusicPlayer(); - + virtual ~AOMusicPlayer(); void play(QString p_song); void set_volume(int p_value); + void kill_loop(); + QString get_path(); + private: QWidget *m_parent; AOApplication *ao_app; - + QTimer *music_loop_timer; int m_volume = 0; + QString f_path; + HSTREAM m_stream; + +private slots: + void restart_loop(); }; #endif // AOMUSICPLAYER_H diff --git a/include/aooptionsdialog.h b/include/aooptionsdialog.h index a65e3f5..03b1e71 100644 --- a/include/aooptionsdialog.h +++ b/include/aooptionsdialog.h @@ -80,6 +80,10 @@ 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; QWidget *ui_casing_tab; diff --git a/include/aosfxplayer.h b/include/aosfxplayer.h index 30cbe9d..5c6f108 100644 --- a/include/aosfxplayer.h +++ b/include/aosfxplayer.h @@ -7,22 +7,28 @@ #include #include #include +#include -class AOSfxPlayer +class AOSfxPlayer : public QObject { + Q_OBJECT public: AOSfxPlayer(QWidget *parent, AOApplication *p_ao_app); void play(QString p_sfx, QString p_char = "", QString shout = ""); void stop(); void set_volume(int p_volume); - + void setLooping(bool is_looping); private: QWidget *m_parent; AOApplication *ao_app; + QTimer *sfx_loop_timer; int m_volume = 0; + bool looping_sfx = false; HSTREAM m_stream; +private slots: + void restart_loop(); }; #endif // AOSFXPLAYER_H diff --git a/include/courtroom.h b/include/courtroom.h index ec9f9ef..3f93e4c 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -25,6 +25,7 @@ #include "datatypes.h" #include "debug_functions.h" #include "chatlogpiece.h" +#include "aocharmovie.h" #include #include @@ -48,11 +49,15 @@ #include #include #include +#include +#include +#include +#include #include class AOApplication; - +class AOCharMovie; class Courtroom : public QMainWindow { Q_OBJECT @@ -63,7 +68,6 @@ public: 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) @@ -210,6 +214,8 @@ public: void announce_case(QString title, bool def, bool pro, bool jud, bool jur, bool steno); void check_connection_received(); + void doScreenShake(); + void doRealization(); ~Courtroom(); @@ -227,7 +233,10 @@ private: bool first_message_sent = false; int maximumMessages = 0; - + QPropertyAnimation *screenshake_animation; + QPropertyAnimation *chatbox_screenshake_animation; + QParallelAnimationGroup *screenshake_group; + QImageReader *frame_emote_checker; // This is for inline message-colouring. enum INLINE_COLOURS { @@ -318,7 +327,7 @@ private: //every time point in char.inis times this equals the final time const int time_mod = 40; - static const int chatmessage_size = 23; + static const int chatmessage_size = 28; QString m_chatmessage[chatmessage_size]; bool chatmessage_is_empty = false; @@ -352,6 +361,7 @@ private: int objection_state = 0; int realization_state = 0; + int screenshake_state = 0; int text_color = 0; bool is_presenting_evidence = false; @@ -390,6 +400,9 @@ private: 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; @@ -478,6 +491,7 @@ private: AOButton *ui_custom_objection; AOButton *ui_realization; + AOButton *ui_screenshake; AOButton *ui_mute; AOButton *ui_defense_plus; @@ -605,6 +619,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/aocharmovie.cpp b/src/aocharmovie.cpp index 5748723..a5beefb 100644 --- a/src/aocharmovie.cpp +++ b/src/aocharmovie.cpp @@ -7,25 +7,26 @@ 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); - - connect(m_movie, SIGNAL(frameChanged(int)), this, SLOT(frame_change(int))); + ticker->setSingleShot(true); + connect(ticker, SIGNAL(timeout()), this, SLOT(movie_ticker())); connect(preanim_timer, SIGNAL(timeout()), this, SLOT(timer_done())); + this->setUpdatesEnabled(true); } 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 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 placeholder_path = ao_app->get_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)) @@ -36,138 +37,128 @@ void AOCharMovie::play(QString p_char, QString p_emote, QString emote_prefix) gif_path = placeholder_path; else gif_path = placeholder_default_path; - - m_movie->stop(); - m_movie->setFileName(gif_path); - - 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(); - m_movie->start(); -} - -void AOCharMovie::play_pre(QString p_char, QString p_emote, int duration) -{ - QString gif_path = ao_app->get_character_path(p_char, p_emote); - + 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()); + qDebug() << "playing file path: " << gif_path; + this->show(); + this->play_frame_sfx(); + ticker->start(m_movie->nextFrameDelay()); +} - 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) +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) { - real_duration += m_movie->nextFrameDelay(); - m_movie->jumpToFrame(n_frame + 1); + frame_specific_sfx_player->play(ao_app->get_sfx_suffix(sfx_to_play)); } - -#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) + else if(use_networked_framehell) { - double modifier = full_duration / static_cast(real_duration); - percentage_modifier = 100 / modifier; - - if (percentage_modifier > 100.0) - percentage_modifier = 100.0; + this->sfx_two_network_boogaloo(); } - -#ifdef DEBUG_GIF - qDebug() << "% mod: " << percentage_modifier; -#endif - - if (full_duration == 0 || full_duration >= real_duration) + if(screenshake_to_play != "" && !use_networked_framehell) { - play_once = true; + mycourtroom->doScreenShake(); } - else + else if(use_networked_framehell) { - play_once = false; - preanim_timer->start(full_duration); + this->screenshake_two_network_boogaloo(); } - - - 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 - m_movie->stop(); - preanim_timer->stop(); - this->hide(); -} - -void AOCharMovie::combo_resize(int w, int h) -{ - 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) + if(realization_to_play != "" && !use_networked_framehell) { - QPixmap f_pixmap = QPixmap::fromImage(movie_frames.at(n_frame)); + 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 fucking_garbage = this->frame_realization_hellstring.split("^"); + for (int i = 0; i < fucking_garbage.length(); i++) { + QString fucking_christ = fucking_garbage.at(i); + QStringList extra_garbage = fucking_christ.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 fucking_garbage = this->frame_screenshake_hellstring.split("^"); + for (int i = 0; i < fucking_garbage.length(); i++) { + QString fucking_christ = fucking_garbage.at(i); + QStringList extra_garbage = fucking_christ.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 fucking_garbage = this->frame_sfx_hellstring.split("^"); + for (int i = 0; i < fucking_garbage.length(); i++) { + QString fucking_christ = fucking_garbage.at(i); + QStringList extra_garbage = fucking_christ.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() +{ + 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 + // ps: fuck private functions/variables as a concept, freedom 2 do dangerous things 5ever + this->play_frame_sfx(); + ticker->start(m_movie->nextFrameDelay()); +} + +void AOCharMovie::LoadImageWithStupidMethodForFlipSupport(QImage image) +{ + QPixmap f_pixmap; + if(m_flipped) // imagine if QT wasn't handicapped harder than people who think MLP is good + 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()) @@ -179,17 +170,62 @@ 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) +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(); + m_movie->setFileName(gif_path); + m_movie->jumpToFrame(0); + int real_duration = 0; + for (int n_frame = 0 ; n_frame < m_movie->frameCount() ; ++n_frame) { - preanim_timer->start(m_movie->nextFrameDelay()); - m_movie->stop(); + qDebug() << "frame " << n_frame << " delay of " << m_movie->nextFrameDelay(); + real_duration += m_movie->nextFrameDelay(); + m_movie->jumpToFrame(n_frame + 1); } + play_once = true; + preanim_timer->start(real_duration); + play(p_char, p_emote, ""); +} + +void AOCharMovie::play_talking(QString p_char, QString p_emote) +{ + play_once = false; + play(p_char, p_emote, "(b)"); +} + +void AOCharMovie::play_idle(QString p_char, QString p_emote) +{ + play_once = false; + 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(); + preanim_timer->stop(); + frame_specific_sfx_player->stop(); + this->hide(); +} + +void AOCharMovie::combo_resize(int w, int h) +{ + QSize f_size(w, h); + this->resize(f_size); + m_movie->setScaledSize(this->size()); +} +void AOCharMovie::move(int ax, int ay) +{ + x = ax; + y = ay; + QLabel::move(x, y); } void AOCharMovie::timer_done() { - done(); } diff --git a/src/aomusicplayer.cpp b/src/aomusicplayer.cpp index 997d82d..a52603c 100644 --- a/src/aomusicplayer.cpp +++ b/src/aomusicplayer.cpp @@ -1,21 +1,25 @@ #include "aomusicplayer.h" -AOMusicPlayer::AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app) + +AOMusicPlayer::AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app): QObject() { m_parent = parent; ao_app = p_ao_app; + music_loop_timer = new QTimer(this); + music_loop_timer->setSingleShot(true); + connect(music_loop_timer, SIGNAL(timeout()), this, SLOT(restart_loop())); } AOMusicPlayer::~AOMusicPlayer() { - BASS_ChannelStop(m_stream); + kill_loop(); } void AOMusicPlayer::play(QString p_song) { BASS_ChannelStop(m_stream); - QString f_path = ao_app->get_music_path(p_song); + 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); @@ -24,6 +28,15 @@ void AOMusicPlayer::play(QString p_song) if (ao_app->get_audio_output_device() != "default") BASS_ChannelSetDevice(m_stream, BASS_GetDevice()); BASS_ChannelPlay(m_stream, false); + music_loop_timer->stop(); + QWORD len=BASS_ChannelGetLength(m_stream, BASS_POS_BYTE); // the length in bytes + double time=BASS_ChannelBytes2Seconds(m_stream, len); // the length in seconds + if(time > 0) + { + qDebug() << "Will loop in " << time << " seconds."; + music_loop_timer->start(time*1000); + } + } void AOMusicPlayer::set_volume(int p_value) @@ -32,3 +45,28 @@ 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::restart_loop() +{ + qDebug() << "Restarting Music"; + /* + m_stream = 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, BASS_GetDevice());*/ + QWORD len=BASS_ChannelGetLength(m_stream, BASS_POS_BYTE); // the length in bytes + double time=BASS_ChannelBytes2Seconds(m_stream, len); // the length in seconds + music_loop_timer->start(time*1000); + BASS_ChannelPlay(m_stream, true); +} + +void AOMusicPlayer::kill_loop() +{ + music_loop_timer->stop(); + BASS_ChannelStop(m_stream); +} + diff --git a/src/aooptionsdialog.cpp b/src/aooptionsdialog.cpp index cd69c76..4d0e479 100644 --- a/src/aooptionsdialog.cpp +++ b/src/aooptionsdialog.cpp @@ -312,6 +312,29 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDi ui_audio_layout->setWidget(7, 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.")); + + ui_audio_layout->setWidget(8, 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(8, 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_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")); @@ -483,6 +506,8 @@ 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("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/aosfxplayer.cpp b/src/aosfxplayer.cpp index 7fe7987..e219c03 100644 --- a/src/aosfxplayer.cpp +++ b/src/aosfxplayer.cpp @@ -1,10 +1,13 @@ #include "aosfxplayer.h" #include "file_functions.h" -AOSfxPlayer::AOSfxPlayer(QWidget *parent, AOApplication *p_ao_app) +AOSfxPlayer::AOSfxPlayer(QWidget *parent, AOApplication *p_ao_app): QObject() { m_parent = parent; ao_app = p_ao_app; + sfx_loop_timer = new QTimer(this); + sfx_loop_timer->setSingleShot(true); + connect(sfx_loop_timer, SIGNAL(timeout()), this, SLOT(restart_loop())); } void AOSfxPlayer::play(QString p_sfx, QString p_char, QString shout) @@ -28,7 +31,7 @@ void AOSfxPlayer::play(QString p_sfx, QString p_char, QString shout) 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(m_volume); @@ -36,11 +39,35 @@ void AOSfxPlayer::play(QString p_sfx, QString p_char, QString shout) if (ao_app->get_audio_output_device() != "default") BASS_ChannelSetDevice(m_stream, BASS_GetDevice()); BASS_ChannelPlay(m_stream, false); + sfx_loop_timer->stop(); + QWORD len=BASS_ChannelGetLength(m_stream, BASS_POS_BYTE); // the length in bytes + double time=BASS_ChannelBytes2Seconds(m_stream, len); // the length in seconds + if(time > 0 && looping_sfx && ao_app->get_looping_sfx()) + { + sfx_loop_timer->start(time*1000); + } +} + +void AOSfxPlayer::setLooping(bool is_looping) +{ + this->looping_sfx = is_looping; } void AOSfxPlayer::stop() { BASS_ChannelStop(m_stream); + sfx_loop_timer->stop(); +} + +void AOSfxPlayer::restart_loop() +{ + if(ao_app->get_looping_sfx() && looping_sfx) + { + QWORD len=BASS_ChannelGetLength(m_stream, BASS_POS_BYTE); // the length in bytes + double time=BASS_ChannelBytes2Seconds(m_stream, len); // the length in seconds + sfx_loop_timer->start(time*1000); + BASS_ChannelPlay(m_stream, true); + } } void AOSfxPlayer::set_volume(int p_value) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index be7629b..ab387da 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -56,7 +56,13 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() sfx_player = new AOSfxPlayer(this, ao_app); sfx_player->set_volume(0); objection_player = new AOSfxPlayer(this, ao_app); - sfx_player->set_volume(0); + 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); // todo: recode pair // todo: recode fucking everything + pair_frame_emote_sfx_player->set_volume(0); blip_player = new AOBlipPlayer(this, ao_app); blip_player->set_volume(0); @@ -70,7 +76,11 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() 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); @@ -200,6 +210,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); @@ -284,7 +295,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())); connect(ui_defense_minus, SIGNAL(clicked()), this, SLOT(on_defense_minus_clicked())); @@ -622,6 +633,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"); @@ -909,6 +923,9 @@ void Courtroom::enter_courtroom(int p_cid) 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()); testimony_in_progress = false; @@ -1227,7 +1244,126 @@ void Courtroom::on_chat_return_pressed() 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; + 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 QImageReader(preemote); + 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); + for (int i = 0; i < frame_emote_checker->imageCount(); i++) { + QString sfx_to_play = ao_app->get_frame_sfx_name(current_char, ao_app->get_pre_emote(current_char, current_emote), i); + QString screenshake_to_play = ao_app->get_screenshake_frame(current_char, ao_app->get_pre_emote(current_char, current_emote), i); + QString realization_to_play = ao_app->get_realization_frame(current_char, ao_app->get_pre_emote(current_char, current_emote), i); + if(sfx_to_play != "") + { + preemote_sfx += "|" + QString::number(i) + "=" + sfx_to_play; + } + if(screenshake_to_play != "") + { + preemote_shake += "|" + QString::number(i) + "=" + screenshake_to_play; + } + if(realization_to_play != "") + { + preemote_flash += "|" + QString::number(i) + "=" + realization_to_play; + } + } + 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 QImageReader(talkemote_to_check); + for (int i = 0; i < frame_emote_checker->imageCount(); i++) { + QString sfx_to_play = ao_app->get_frame_sfx_name(current_char, "(b)" + ao_app->get_emote(current_char, current_emote), i); + QString screenshake_to_play = ao_app->get_screenshake_frame(current_char, "(b)" + ao_app->get_emote(current_char, current_emote), i); + QString realization_to_play = ao_app->get_realization_frame(current_char, "(b)" + ao_app->get_emote(current_char, current_emote), i); + if(sfx_to_play != "") + { + talkemote_sfx += "|" + QString::number(i) + "=" + sfx_to_play; + } + if(screenshake_to_play != "") + { + talkemote_shake += "|" + QString::number(i) + "=" + screenshake_to_play; + } + if(realization_to_play != "") + { + talkemote_flash += "|" + QString::number(i) + "=" + realization_to_play; + } + } + 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 QImageReader(idleemote_to_check); + for (int i = 0; i < frame_emote_checker->imageCount(); i++) { + QString sfx_to_play = ao_app->get_frame_sfx_name(current_char, "(a)" + ao_app->get_emote(current_char, current_emote), i); + QString screenshake_to_play = ao_app->get_screenshake_frame(current_char, "(a)" + ao_app->get_emote(current_char, current_emote), i); + QString realization_to_play = ao_app->get_realization_frame(current_char, "(a)" + ao_app->get_emote(current_char, current_emote), i); + if(sfx_to_play != "") + { + idleemote_sfx += "|" + QString::number(i) + "=" + sfx_to_play; + } + if(screenshake_to_play != "") + { + idleemote_shake += "|" + QString::number(i) + "=" + screenshake_to_play; + } + if(realization_to_play != "") + { + idleemote_flash += "|" + QString::number(i) + "=" + realization_to_play; + } + } + 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; + 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)); } @@ -1296,6 +1432,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"); @@ -1303,6 +1440,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"); } @@ -1334,6 +1472,8 @@ void Courtroom::handle_chatmessage(QStringList *p_contents) case 2: ui_vp_objection->play("objection", f_char, f_custom_theme); 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); @@ -1366,7 +1506,10 @@ 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; @@ -1548,6 +1691,7 @@ void Courtroom::handle_chatmessage_2() ui_vp_sideplayer_char->set_flipped(true); else ui_vp_sideplayer_char->set_flipped(false); + ui_vp_sideplayer_char->use_networked_framehell = false; ui_vp_sideplayer_char->play_idle(m_chatmessage[OTHER_NAME], m_chatmessage[OTHER_EMOTE]); } else @@ -1555,13 +1699,17 @@ void Courtroom::handle_chatmessage_2() // 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: @@ -1578,6 +1726,53 @@ void Courtroom::handle_chatmessage_2() } } +void Courtroom::doScreenShake() +{ + 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 = ui_viewport->x(); + int screen_y = ui_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 = ui_vp_chatbox->x(); + int chatbox_y = ui_vp_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() { start_chat_ticking(); @@ -1709,6 +1904,17 @@ 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) { @@ -1919,14 +2125,14 @@ void Courtroom::play_preanim(bool noninterrupting) 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) || @@ -1942,7 +2148,6 @@ void Courtroom::play_preanim(bool noninterrupting) } ui_vp_player_char->play_pre(f_char, f_preanim, preanim_duration); - if (noninterrupting) anim_state = 4; else @@ -1966,6 +2171,13 @@ void Courtroom::realization_done() ui_vp_realization->hide(); } +void Courtroom::doRealization() +{ + realization_timer->start(60); + ui_vp_realization->show(); + +} + 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 @@ -1974,11 +2186,9 @@ void Courtroom::start_chat_ticking() 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])); + this->doRealization(); + misc_sfx_player->play(ao_app->get_custom_realization(m_chatmessage[CHAR_NAME])); } - ui_vp_message->clear(); set_text_color(); rainbow_counter = 0; @@ -2076,6 +2286,18 @@ void Courtroom::chat_tick() formatting_char = true; } + else if (f_character == "@" and !next_character_is_not_special) + { + this->doScreenShake(); + formatting_char = true; + } + + else if (f_character == "$" and !next_character_is_not_special) + { + this->doRealization(); + formatting_char = true; + } + // Orange inline colourisation. else if (f_character == "|" and !next_character_is_not_special) { @@ -2541,7 +2763,7 @@ void Courtroom::handle_wtce(QString p_wtce, int variant) //witness testimony if (p_wtce == "testimony1") { - sfx_player->play(ao_app->get_sfx("witness_testimony")); + misc_sfx_player->play(ao_app->get_sfx("witness_testimony")); ui_vp_wtce->play("witnesstestimony"); testimony_in_progress = true; show_testimony(); @@ -2549,7 +2771,7 @@ void Courtroom::handle_wtce(QString p_wtce, int variant) //cross examination else if (p_wtce == "testimony2") { - sfx_player->play(ao_app->get_sfx("cross_examination")); + misc_sfx_player->play(ao_app->get_sfx("cross_examination")); ui_vp_wtce->play("crossexamination"); testimony_in_progress = false; } @@ -2557,12 +2779,12 @@ void Courtroom::handle_wtce(QString p_wtce, int variant) { if (variant == 0) { - sfx_player->play(ao_app->get_sfx("not_guilty")); + misc_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")); + misc_sfx_player->play(ao_app->get_sfx("guilty")); ui_vp_wtce->play("guilty"); testimony_in_progress = false; } @@ -3140,6 +3362,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()) @@ -3223,6 +3461,9 @@ 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(); } diff --git a/src/packet_distribution.cpp b/src/packet_distribution.cpp index 68d2fb9..f8adb12 100644 --- a/src/packet_distribution.cpp +++ b/src/packet_distribution.cpp @@ -151,6 +151,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") @@ -209,6 +210,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; w_lobby->enable_connect_button(); } diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index 1e920d7..e8cfeba 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -555,6 +555,42 @@ QString AOApplication::get_sfx_name(QString p_char, int p_emote) 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"); @@ -588,6 +624,18 @@ 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::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();