From 6a4657ceb92f391da012657239267d83762c937a Mon Sep 17 00:00:00 2001 From: David Skoland Date: Fri, 3 Feb 2017 17:07:05 +0100 Subject: [PATCH] added viewport functionality --- aoapplication.h | 3 + aocharmovie.cpp | 40 ++++--- aocharmovie.h | 17 +-- aoimage.cpp | 10 ++ aoimage.h | 1 + aomovie.cpp | 22 +++- aomovie.h | 2 + courtroom.cpp | 245 ++++++++++++++++++++++++++++++++++------ courtroom.h | 17 ++- datatypes.h | 13 +++ path_functions.cpp | 2 +- text_file_functions.cpp | 77 ++++++++++++- 12 files changed, 378 insertions(+), 71 deletions(-) diff --git a/aoapplication.h b/aoapplication.h index 4144ef5..6c503e6 100644 --- a/aoapplication.h +++ b/aoapplication.h @@ -93,6 +93,9 @@ public: pos_size_type get_pos_and_size(QString p_identifier, QString p_design_path); QString get_char_side(QString p_char); QString get_showname(QString p_char); + QString get_chat(QString p_char); + int get_preanim_duration(QString p_char, QString p_emote); + int get_text_delay(QString p_char, QString p_emote); private: const int RELEASE = 2; diff --git a/aocharmovie.cpp b/aocharmovie.cpp index 9f5f2d7..6247f91 100644 --- a/aocharmovie.cpp +++ b/aocharmovie.cpp @@ -4,29 +4,27 @@ #include "file_functions.h" #include "aoapplication.h" +#include + 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); this->setMovie(m_movie); connect(m_movie, SIGNAL(frameChanged(int)), this, SLOT(frame_change(int))); + connect(preanim_timer, SIGNAL(timeout()), this, SLOT(preanim_done())); } -void AOCharMovie::set(QString p_char, QString p_pre, QString p_gif) -{ - m_char = p_char; - m_pre = p_pre; - m_gif = p_gif; -} - -void AOCharMovie::play_pre() +void AOCharMovie::play_pre(QString p_char, QString p_emote, int duration) { m_movie->stop(); - QString pre_path = ao_app->get_character_path(m_char) + m_pre.toLower() + ".gif"; + QString pre_path = ao_app->get_character_path(p_char) + p_emote.toLower() + ".gif"; QString placeholder_path = ao_app->get_theme_path() + "placeholder.gif"; if (file_exists(pre_path)) @@ -36,13 +34,14 @@ void AOCharMovie::play_pre() this->show(); m_movie->start(); + preanim_timer->start(duration); } -void AOCharMovie::play_talking() +void AOCharMovie::play_talking(QString p_char, QString p_emote) { m_movie->stop(); - QString talking_path = ao_app->get_character_path(m_char) + "(b)" + m_gif.toLower() + ".gif"; + QString talking_path = ao_app->get_character_path(p_char) + "(b)" + p_emote.toLower() + ".gif"; QString placeholder_path = ao_app->get_theme_path() + "placeholder.gif"; if (file_exists(talking_path)) @@ -54,11 +53,11 @@ void AOCharMovie::play_talking() m_movie->start(); } -void AOCharMovie::play_idle() +void AOCharMovie::play_idle(QString p_char, QString p_emote) { m_movie->stop(); - QString idle_path = ao_app->get_character_path(m_char) + "(a)" + m_gif.toLower() + ".gif"; + QString idle_path = ao_app->get_character_path(p_char) + "(a)" + p_emote.toLower() + ".gif"; QString placeholder_path = ao_app->get_theme_path() + "placeholder.gif"; if (file_exists(idle_path)) @@ -86,12 +85,11 @@ void AOCharMovie::combo_resize(int w, int h) void AOCharMovie::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()); - - //signal connected to courtroom object, let it figure out what to do - done(); - } + //we'll need this later + ++n_frame; +} + +void AOCharMovie::preanim_done() +{ + done(); } diff --git a/aocharmovie.h b/aocharmovie.h index 2534b6d..d009662 100644 --- a/aocharmovie.h +++ b/aocharmovie.h @@ -14,11 +14,9 @@ class AOCharMovie : public QLabel public: AOCharMovie(QWidget *p_parent, AOApplication *p_ao_app); - void set(QString p_char, QString p_pre, QString p_gif); - - void play_pre(); - void play_talking(); - void play_idle(); + void play_pre(QString p_char, QString p_emote, int duration); + void play_talking(QString p_char, QString p_emote); + void play_idle(QString p_char, QString p_emote); void stop(); @@ -27,20 +25,15 @@ public: private: AOApplication *ao_app; - bool play_once = true; - QMovie *m_movie; - QTimer *m_timer; - - QString m_char = "null"; - QString m_pre; - QString m_gif; + QTimer *preanim_timer; signals: void done(); private slots: void frame_change(int n_frame); + void preanim_done(); }; #endif // AOCHARMOVIE_H diff --git a/aoimage.cpp b/aoimage.cpp index fc72913..a8ad3a0 100644 --- a/aoimage.cpp +++ b/aoimage.cpp @@ -24,6 +24,16 @@ void AOImage::set_image(QString p_image) this->setPixmap(default_image_path); } +void AOImage::set_image_from_path(QString p_path) +{ + QString default_path = ao_app->get_default_theme_path() + "chatmed.png"; + + if (file_exists(p_path)) + this->setPixmap(p_path); + else + this->setPixmap(default_path); +} + void AOImage::set_scaled_image(QString p_image) { QString theme_image_path = ao_app->get_theme_path() + p_image; diff --git a/aoimage.h b/aoimage.h index 635d4f0..dbcf2e0 100644 --- a/aoimage.h +++ b/aoimage.h @@ -17,6 +17,7 @@ public: AOApplication *ao_app; void set_image(QString p_image); + void set_image_from_path(QString p_path); void set_scaled_image(QString p_image); void set_size_and_pos(QString identifier); }; diff --git a/aomovie.cpp b/aomovie.cpp index 2b4189e..66effb1 100644 --- a/aomovie.cpp +++ b/aomovie.cpp @@ -17,6 +17,8 @@ AOMovie::AOMovie(QWidget *p_parent, AOApplication *p_ao_app) : QLabel(p_parent) void AOMovie::play(QString p_gif, QString p_char) { + play_once = true; + m_movie->stop(); QString default_path = ao_app->get_default_theme_path() + p_gif + ".gif"; @@ -37,6 +39,24 @@ void AOMovie::play(QString p_gif, QString p_char) m_movie->start(); } +void AOMovie::play(QString p_gif, bool p_play_once) +{ + play_once = p_play_once; + + m_movie->stop(); + + QString default_path = ao_app->get_default_theme_path() + p_gif + ".gif"; + QString gif_path = ao_app->get_theme_path() + p_gif + ".gif"; + + if (file_exists(gif_path)) + m_movie->setFileName(gif_path); + else + m_movie->setFileName(default_path); + + this->show(); + m_movie->start(); +} + void AOMovie::stop() { m_movie->stop(); @@ -45,7 +65,7 @@ void AOMovie::stop() void AOMovie::frame_change(int n_frame) { - if (n_frame == (m_movie->frameCount() - 1)) + 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/aomovie.h b/aomovie.h index 93d1ef4..19d0dab 100644 --- a/aomovie.h +++ b/aomovie.h @@ -15,12 +15,14 @@ public: AOMovie(QWidget *p_parent, AOApplication *p_ao_app); void play(QString p_gif, QString p_char = "null"); + void play(QString p_gif, bool p_play_once); void combo_resize(int w, int h); void stop(); private: QMovie *m_movie; AOApplication *ao_app; + bool play_once = true; signals: void done(); diff --git a/courtroom.cpp b/courtroom.cpp index f5d342c..da598d5 100644 --- a/courtroom.cpp +++ b/courtroom.cpp @@ -19,11 +19,11 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() chat_tick_timer = new QTimer(this); - text_delay = new QTimer(this); - text_delay->setSingleShot(true); + text_delay_timer = new QTimer(this); + text_delay_timer->setSingleShot(true); - sfx_delay = new QTimer(this); - sfx_delay->setSingleShot(true); + sfx_delay_timer = new QTimer(this); + sfx_delay_timer->setSingleShot(true); char_button_mapper = new QSignalMapper(this); @@ -33,10 +33,10 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() 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_player_char = new AOCharMovie(ui_viewport, ao_app); ui_vp_desk = new AOScene(ui_viewport, ao_app); ui_vp_legacy_desk = new AOScene(ui_viewport, ao_app); - //ui_vp_legacy_padding = new AOImage(ui_viewport, ao_app); ui_vp_chatbox = new AOImage(ui_viewport, ao_app); ui_vp_showname = new QLabel(ui_vp_chatbox); ui_vp_message = new QPlainTextEdit(ui_vp_chatbox); @@ -180,6 +180,12 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() 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(ui_ooc_chat_message, SIGNAL(returnPressed()), this, SLOT(on_ooc_return_pressed())); connect(ui_ooc_toggle, SIGNAL(clicked()), this, SLOT(on_ooc_toggle_clicked())); @@ -232,6 +238,9 @@ void Courtroom::set_widgets() 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()); @@ -246,19 +255,21 @@ void Courtroom::set_widgets() ui_vp_legacy_desk->move(0, final_y); ui_vp_legacy_desk->hide(); - //set_size_and_pos(ui_vp_legacy_padding, "legacy_padding"); - //ui_vp_legacy_padding->setStyleSheet("background-color: rgba(89, 89, 89, 255);"); - set_size_and_pos(ui_vp_chatbox, "chatbox"); ui_vp_chatbox->set_scaled_image("chatmed.png"); + ui_vp_chatbox->hide(); set_size_and_pos(ui_vp_showname, "showname"); + QFont f = ui_vp_showname->font(); + f.setPointSize(8); + ui_vp_showname->setFont(f); ui_vp_showname->setStyleSheet("background-color: rgba(0, 0, 0, 0);" "color: white;"); set_size_and_pos(ui_vp_message, "message"); + ui_vp_message->setReadOnly(true); ui_vp_message->setStyleSheet("background-color: rgba(0, 0, 0, 0);" - "color: white;"); + "color: white"); ui_vp_testimony->move(0, 0); ui_vp_testimony->resize(ui_viewport->width(), ui_viewport->height()); @@ -611,14 +622,15 @@ void Courtroom::append_server_chatmessage(QString f_message) void Courtroom::handle_chatmessage(QStringList *p_contents) { text_state = 0; - - chatmessage_is_empty = m_chatmessage[MESSAGE] == " " || m_chatmessage[MESSAGE] == ""; + anim_state = 0; for (int n_string = 0 ; n_string < chatmessage_size ; ++n_string) { m_chatmessage[n_string] = p_contents->at(n_string); } + chatmessage_is_empty = m_chatmessage[MESSAGE] == " " || m_chatmessage[MESSAGE] == ""; + QString f_message = m_chatmessage[CHAR_NAME] + ": " + m_chatmessage[MESSAGE] + '\n'; const QTextCursor old_cursor = ui_ic_chatlog->textCursor(); @@ -667,7 +679,7 @@ void Courtroom::handle_chatmessage(QStringList *p_contents) } //means we are in a state of objecting - anim_state = 0; + //anim_state = 0; int emote_mod = m_chatmessage[EMOTE_MOD].toInt(); @@ -693,6 +705,7 @@ void Courtroom::objection_done() void Courtroom::handle_chatmessage_2() { + ui_vp_speedlines->stop(); ui_vp_player_char->stop(); QString remote_name = m_chatmessage[CHAR_NAME]; @@ -707,15 +720,169 @@ void Courtroom::handle_chatmessage_2() ui_vp_message->clear(); ui_vp_chatbox->hide(); - //D3BUG START + QString chatbox = ao_app->get_chat(m_chatmessage[CHAR_NAME]); - ui_vp_chatbox->show(); - ui_vp_message->appendPlainText(m_chatmessage[MESSAGE]); - - //D3BUG END + if (chatbox == "") + ui_vp_chatbox->set_image("chatmed.png"); + else + { + QString chatbox_path = ao_app->get_base_path() + "misc/" + chatbox; + ui_vp_chatbox->set_image_from_path(chatbox_path); + } set_scene(); set_text_color(); + + int emote_mod = m_chatmessage[EMOTE_MOD].toInt(); + + switch (emote_mod) + { + case 1: case 3: case 4: + play_preanim(); + break; + default: + qDebug() << "W: invalid emote mod: " << QString::number(emote_mod); + //intentional fallthru + case 0: case 2: case 5: + start_chat_ticking(); + handle_chatmessage_3(); + } +} + +void Courtroom::handle_chatmessage_3() +{ + start_chat_ticking(); + + int emote_mod = m_chatmessage[EMOTE_MOD].toInt(); + + if (emote_mod == 4 || + emote_mod == 5) + { + QString side = m_chatmessage[SIDE]; + ui_vp_desk->hide(); + ui_vp_legacy_desk->hide(); + + if (side == "pro" || + side == "hlp" || + side == "wit") + ui_vp_speedlines->play("prosecution_speedlines", false); + else + ui_vp_speedlines->play("defense_speedlines", false); + + } + + 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; + 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]; + + switch (f_anim_state) + { + case 2: + ui_vp_player_char->play_talking(f_char, f_emote); + anim_state = 2; + break; + default: + qDebug() << "W: invalid anim_state: " << f_anim_state; + case 3: + ui_vp_player_char->play_idle(f_char, f_emote); + anim_state = 3; + } + +} + +void Courtroom::play_preanim() +{ + 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 preanim_duration = ao_app->get_preanim_duration(f_char, f_preanim) * time_mod; + int text_delay = ao_app->get_text_delay(f_char, f_preanim) * time_mod; + int sfx_delay = m_chatmessage[SFX_DELAY].toInt() * time_mod; + + ui_vp_player_char->play_pre(f_char, f_preanim, preanim_duration); + anim_state = 1; + if (text_delay >= 0) + text_delay_timer->start(text_delay); + sfx_delay_timer->start(sfx_delay); +} + +void Courtroom::preanim_done() +{ + 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 (chatmessage_is_empty) + { + //since the message is empty, it's technically done ticking + text_state = 2; + return; + } + + ui_vp_chatbox->show(); + + tick_pos = 0; + chat_tick_timer->start(chat_tick_interval); + + //means text is currently ticking + text_state = 1; +} + +void Courtroom::chat_tick() +{ + //T0D0: play tick sound based on gender + //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]; + + if (tick_pos >= f_message.size()) + { + text_state = 2; + chat_tick_timer->stop(); + if (anim_state == 2) + { + ui_vp_player_char->play_idle(m_chatmessage[CHAR_NAME], m_chatmessage[EMOTE]); + anim_state = 3; + } + } + + else + { + ui_vp_message->insertPlainText(f_message.at(tick_pos)); + + QScrollBar *scroll = ui_vp_message->verticalScrollBar(); + scroll->setValue(scroll->maximum()); + scroll->hide(); + + ++tick_pos; + } +} + +void Courtroom::play_sfx() +{ + //T0D0: add audio implementation + //QString sfx_name = m_chatmessage[SFX_NAME]; } void Courtroom::set_scene() @@ -792,28 +959,33 @@ void Courtroom::set_scene() void Courtroom::set_text_color() { - switch(m_chatmessage[TEXT_COLOR].toInt()) + switch (m_chatmessage[TEXT_COLOR].toInt()) { - case 0: - ui_vp_message->setStyleSheet("QPlainTextEdit{color: white;}"); + case GREEN: + ui_vp_message->setStyleSheet("background-color: rgba(0, 0, 0, 0);" + "color: rgb(0, 255, 0)"); break; - case 1: - ui_vp_message->setStyleSheet("QPlainTextEdit{color: rgb(0, 255, 0);}"); + case RED: + ui_vp_message->setStyleSheet("background-color: rgba(0, 0, 0, 0);" + "color: red"); break; - case 2: - ui_vp_message->setStyleSheet("QPlainTextEdit{color: red;}"); + case ORANGE: + ui_vp_message->setStyleSheet("background-color: rgba(0, 0, 0, 0);" + "color: orange"); break; - case 3: - ui_vp_message->setStyleSheet("QPlainTextEdit{color: orange;}"); - break; - case 4: - ui_vp_message->setStyleSheet("QPlainTextEdit{color: rgb(45, 150, 255);}"); - break; - case 5: - ui_vp_message->setStyleSheet("QPlainTextEdit{color: yellow;}"); + case BLUE: + ui_vp_message->setStyleSheet("background-color: rgba(0, 0, 0, 0);" + "color: rgb(45, 150, 255)"); break; + case YELLOW: + ui_vp_message->setStyleSheet("background-color: rgba(0, 0, 0, 0);" + "color: yellow"); default: - ui_vp_message->setStyleSheet("QPlainTextEdit{color: white;}"); + qDebug() << "W: undefined text color: " << m_chatmessage[TEXT_COLOR]; + case WHITE: + ui_vp_message->setStyleSheet("background-color: rgba(0, 0, 0, 0);" + "color: white"); + } } @@ -886,6 +1058,13 @@ void Courtroom::on_ooc_toggle_clicked() void Courtroom::on_witness_testimony_clicked() { + //D3BUG + //ui_vp_message->setStyleSheet("background-color: rgba(0, 0, 0, 0);" + // "color: red"); + + set_text_color(); + //D3BUG + ao_app->send_server_packet(new AOPacket("RT#testimony1#%")); } diff --git a/courtroom.h b/courtroom.h index 1cb1149..2fc7da2 100644 --- a/courtroom.h +++ b/courtroom.h @@ -60,6 +60,9 @@ public: void handle_chatmessage(QStringList *p_contents); void handle_chatmessage_2(); + void handle_chatmessage_3(); + + void play_preanim(); void handle_wtce(QString p_wtce); @@ -93,10 +96,13 @@ private: int tick_pos = 0; //delay before chat messages starts ticking - QTimer *text_delay; + QTimer *text_delay_timer; //delay before sfx plays - QTimer *sfx_delay; + QTimer *sfx_delay_timer; + + //every time point in char.inis times this equals the final time + const int time_mod = 60; static const int chatmessage_size = 15; QString m_chatmessage[chatmessage_size]; @@ -130,6 +136,7 @@ private: //ui_viewport is the parent of all the viewport widgets QWidget *ui_viewport; AOScene *ui_vp_background; + AOMovie *ui_vp_speedlines; AOCharMovie *ui_vp_player_char; AOScene *ui_vp_desk; AOScene *ui_vp_legacy_desk; @@ -224,8 +231,14 @@ private: public slots: void objection_done(); + void preanim_done(); private slots: + void start_chat_ticking(); + void play_sfx(); + + void chat_tick(); + void on_ooc_return_pressed(); void on_ooc_toggle_clicked(); diff --git a/datatypes.h b/datatypes.h index 05b100c..c0ca066 100644 --- a/datatypes.h +++ b/datatypes.h @@ -94,4 +94,17 @@ enum CHAT_MESSAGE TEXT_COLOR }; +enum COLOR +{ + WHITE = 0, + GREEN, + RED, + ORANGE, + BLUE, + YELLOW, + //NYI + BLACK, + RAINBOW +}; + #endif // DATATYPES_H diff --git a/path_functions.cpp b/path_functions.cpp index c07d910..7e81e64 100644 --- a/path_functions.cpp +++ b/path_functions.cpp @@ -7,7 +7,7 @@ QString AOApplication::get_base_path(){ #ifdef OMNI_DEBUG - return "/media/omnitroid/Data/winshare/AO/client/4chan_base/"; + return "/media/omnitroid/Data/winshare/AO/client/base/"; #else return (QDir::currentPath() + "/base/"); #endif diff --git a/text_file_functions.cpp b/text_file_functions.cpp index 7379e6f..bde24fb 100644 --- a/text_file_functions.cpp +++ b/text_file_functions.cpp @@ -202,9 +202,84 @@ QString AOApplication::get_showname(QString p_char) if (line_elements.size() < 2) continue; - return line_elements.at(1).trimmed().toLower(); + return line_elements.at(1).trimmed(); } return ""; } +QString AOApplication::get_chat(QString p_char) +{ + QString char_ini_path = get_character_path(p_char) + "char.ini"; + + QFile char_ini; + + char_ini.setFileName(char_ini_path); + + if (!char_ini.open(QIODevice::ReadOnly)) + { + return ""; + } + + QTextStream in(&char_ini); + + while(!in.atEnd()) + { + QString line = in.readLine(); + + if (!line.startsWith("chat")) + continue; + + QStringList line_elements = line.split("="); + + if (line_elements.size() < 2) + continue; + + return line_elements.at(1).trimmed().toLower() + ".png"; + } + + return ""; +} + +int AOApplication::get_preanim_duration(QString p_char, QString p_emote) +{ + QString char_ini_path = get_character_path(p_char) + "char.ini"; + + QFile char_ini; + + char_ini.setFileName(char_ini_path); + + if (!char_ini.open(QIODevice::ReadOnly)) + { + //means preanim will finish instantly(i.e. not play) + return 0; + } + + QTextStream in(&char_ini); + + while(!in.atEnd()) + { + QString line = in.readLine(); + + if (!line.startsWith(p_emote)) + continue; + + QStringList line_elements = line.split("="); + + if (line_elements.size() < 2) + continue; + + return line_elements.at(1).trimmed().toInt(); + } + + return 0; +} + +int AOApplication::get_text_delay(QString p_char, QString p_emote) +{ + //T0D0: make a sane format for this and implement function + p_char.toLower(); + p_emote.toLower(); + return -1; +} +