aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/aoapplication.h11
-rw-r--r--include/aooptionsdialog.h6
-rw-r--r--include/courtroom.h64
-rw-r--r--resource/translations/ao_de.ts2
-rw-r--r--resource/translations/ao_en.ts2
-rw-r--r--resource/translations/ao_es.ts2
-rw-r--r--resource/translations/ao_jp.ts2
-rw-r--r--resource/translations/ao_pl.ts2
-rw-r--r--resource/translations/ao_pt.ts2
-rw-r--r--resource/translations/ao_ru.ts2
-rw-r--r--src/aoemotebutton.cpp5
-rw-r--r--src/aooptionsdialog.cpp45
-rw-r--r--src/courtroom.cpp986
-rw-r--r--src/packet_distribution.cpp6
-rw-r--r--src/text_file_functions.cpp20
15 files changed, 777 insertions, 380 deletions
diff --git a/include/aoapplication.h b/include/aoapplication.h
index b17ac4a9..776a5f13 100644
--- a/include/aoapplication.h
+++ b/include/aoapplication.h
@@ -170,6 +170,14 @@ public:
// Returns the value of default_blip in config.ini
int get_default_blip();
+ // Returns the value if objections interrupt and skip the message queue
+ // from the config.ini.
+ bool is_instant_objection_enabled();
+
+ // returns if log will show messages as-received, while viewport will parse according to the queue (Text Stay Time)
+ // from the config.ini
+ bool is_desyncrhonized_logs_enabled();
+
// Returns the value of whether Discord should be enabled on startup
// from the config.ini.
bool is_discord_enabled();
@@ -212,6 +220,9 @@ public:
// may contain, from config.ini.
int get_max_log_size();
+ // Current wait time between messages for the queue system
+ int stay_time();
+
// Returns whether the log should go upwards (new behaviour)
// or downwards (vanilla behaviour).
bool get_log_goes_downwards();
diff --git a/include/aooptionsdialog.h b/include/aooptionsdialog.h
index 2e2d7b8a..93b66779 100644
--- a/include/aooptionsdialog.h
+++ b/include/aooptionsdialog.h
@@ -52,6 +52,12 @@ private:
QSpinBox *ui_log_margin_spinbox;
QLabel *ui_log_timestamp_lbl;
QCheckBox *ui_log_timestamp_cb;
+ QLabel *ui_stay_time_lbl;
+ QSpinBox *ui_stay_time_spinbox;
+ QLabel *ui_desync_logs_lbl;
+ QCheckBox *ui_desync_logs_cb;
+ QLabel *ui_instant_objection_lbl;
+ QCheckBox *ui_instant_objection_cb;
QLabel *ui_log_ic_actions_lbl;
QCheckBox *ui_log_ic_actions_cb;
QFrame *ui_log_names_divider;
diff --git a/include/courtroom.h b/include/courtroom.h
index 91606c38..4d4f1733 100644
--- a/include/courtroom.h
+++ b/include/courtroom.h
@@ -42,6 +42,7 @@
#include <QTextBrowser>
#include <QTreeWidget>
#include <QVector>
+#include <QQueue>
#include <QBrush>
#include <QDebug>
@@ -93,6 +94,13 @@ public:
arup_locks.append(locked);
}
+ void arup_clear() {
+ arup_players.clear();
+ arup_statuses.clear();
+ arup_cms.clear();
+ arup_locks.clear();
+ }
+
void arup_modify(int type, int place, QString value)
{
if (type == 0) {
@@ -211,12 +219,46 @@ public:
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();
+ // Add the message packet to the stack
+ void chatmessage_enqueue(QStringList p_contents);
+
+ // Parse the chat message packet and unpack it into the m_chatmessage[ITEM] format
+ void unpack_chatmessage(QStringList p_contents);
+
+ // Log the message contents and information such as evidence presenting etc. into the log file
+ void log_chatmessage(QString f_message, int f_char_id, QString f_showname = "", int f_color = 0);
+
+ // Display the message contents and information such as evidence presenting etc. in the IC logs
+ void display_log_chatmessage(QString f_message, int f_char_id, QString f_showname = "", int f_color = 0);
+
+ // Log the message contents and information such as evidence presenting etc. into the IC logs
+ void handle_callwords();
+
+ // Handle the objection logic, if it's interrupting the currently parsing message.
+ // Returns true if this message has an objection, otherwise returns false. The result decides when to call handle_ic_message()
+ bool handle_objection();
+
+ // Display the evidence image box when presenting evidence in IC
+ void display_evidence_image();
+
+ // Handle the stuff that comes when the character appears on screen and starts animating (preanims etc.)
+ void handle_ic_message();
+
+ // Display the character.
+ void display_character();
+
+ // Display the character's pair if present.
+ void display_pair_character(QString other_charid, QString other_offset);
+
+ // Handle the emote modifier value and proceed through the logic accordingly.
+ void handle_emote_mod(int emote_mod, bool p_immediate);
+
+ // Initialize the chatbox image, showname shenanigans, custom chatboxes, etc.
+ void initialize_chatbox();
+
+ // Finally start displaying the chatbox we initialized, display the evidence, and play the talking or idle emote for the character.
+ // Callwords are also handled here.
+ void handle_ic_speaking();
// This function filters out the common CC inline text trickery, for appending
// to the IC chatlog.
@@ -360,8 +402,14 @@ private:
// True, if the log should have a timestamp.
bool log_timestamp = false;
+ // How long in miliseconds should the objection wait before appearing.
+ int objection_threshold = 1500;
+
// delay before chat messages starts ticking
QTimer *text_delay_timer;
+
+ // delay before the next queue entry is going to be processed
+ QTimer *text_queue_timer;
// delay before sfx plays
QTimer *sfx_delay_timer;
@@ -710,7 +758,6 @@ private:
void refresh_evidence();
void set_evidence_page();
- void reset_ic();
void reset_ui();
void regenerate_ic_chatlog();
@@ -880,6 +927,9 @@ private slots:
void on_casing_clicked();
void ping_server();
+
+ // Proceed to parse the oldest chatmessage and remove it from the stack
+ void chatmessage_dequeue();
};
#endif // COURTROOM_H
diff --git a/resource/translations/ao_de.ts b/resource/translations/ao_de.ts
index 8b1aa844..c4e96b9a 100644
--- a/resource/translations/ao_de.ts
+++ b/resource/translations/ao_de.ts
@@ -696,7 +696,7 @@ Grund: </translation>
</message>
<message>
<location filename="../../src/courtroom.cpp" line="241"/>
- <source>No Interrupt</source>
+ <source>Immediate</source>
<translation>Keine Unterbrechung</translation>
</message>
<message>
diff --git a/resource/translations/ao_en.ts b/resource/translations/ao_en.ts
index ee104b9f..8d21c99b 100644
--- a/resource/translations/ao_en.ts
+++ b/resource/translations/ao_en.ts
@@ -553,7 +553,7 @@ Reason: %1</source>
</message>
<message>
<location filename="../../src/courtroom.cpp" line="241"/>
- <source>No Interrupt</source>
+ <source>Immediate</source>
<translation type="unfinished"></translation>
</message>
<message>
diff --git a/resource/translations/ao_es.ts b/resource/translations/ao_es.ts
index ec15abef..36cc653c 100644
--- a/resource/translations/ao_es.ts
+++ b/resource/translations/ao_es.ts
@@ -739,7 +739,7 @@ Razón: </translation>
</message>
<message>
<location filename="../../src/courtroom.cpp" line="210"/>
- <source>No Interrupt</source>
+ <source>Immediate</source>
<translatorcomment>A translation wouldn&apos;t fit because of the shitty theme system.</translatorcomment>
<translation></translation>
</message>
diff --git a/resource/translations/ao_jp.ts b/resource/translations/ao_jp.ts
index a6594dec..c2fea9a8 100644
--- a/resource/translations/ao_jp.ts
+++ b/resource/translations/ao_jp.ts
@@ -563,7 +563,7 @@ Reason: %1</source>
</message>
<message>
<location filename="../../src/courtroom.cpp" line="241"/>
- <source>No Interrupt</source>
+ <source>Immediate</source>
<translation type="unfinished"></translation>
</message>
<message>
diff --git a/resource/translations/ao_pl.ts b/resource/translations/ao_pl.ts
index 24cccf8a..63838337 100644
--- a/resource/translations/ao_pl.ts
+++ b/resource/translations/ao_pl.ts
@@ -620,7 +620,7 @@ Powód: %1</translation>
</message>
<message>
<location filename="../../src/courtroom.cpp" line="241"/>
- <source>No Interrupt</source>
+ <source>Immediate</source>
<translation>Bez ociągania się</translation>
</message>
<message>
diff --git a/resource/translations/ao_pt.ts b/resource/translations/ao_pt.ts
index 2548d832..e867729c 100644
--- a/resource/translations/ao_pt.ts
+++ b/resource/translations/ao_pt.ts
@@ -709,7 +709,7 @@ Motivo: %1</translation>
</message>
<message>
<location filename="../../src/courtroom.cpp" line="210"/>
- <source>No Interrupt</source>
+ <source>Immediate</source>
<translatorcomment>A translation wouldn&apos;t fit because of the shitty theme system.</translatorcomment>
<translation></translation>
</message>
diff --git a/resource/translations/ao_ru.ts b/resource/translations/ao_ru.ts
index 9347436f..e2e04b90 100644
--- a/resource/translations/ao_ru.ts
+++ b/resource/translations/ao_ru.ts
@@ -621,7 +621,7 @@ Reason: </source>
</message>
<message>
<location filename="../../src/courtroom.cpp" line="241"/>
- <source>No Interrupt</source>
+ <source>Immediate</source>
<translation type="unfinished"></translation>
</message>
<message>
diff --git a/src/aoemotebutton.cpp b/src/aoemotebutton.cpp
index 652010d2..07e6a42c 100644
--- a/src/aoemotebutton.cpp
+++ b/src/aoemotebutton.cpp
@@ -25,7 +25,10 @@ void AOEmoteButton::set_image(QString p_image, QString p_emote_comment)
"\") 0 0 0 0 stretch stretch; }"
"QToolTip { color: #000000; background-color: #ffffff; border: 0px; }");
}
- else if (p_image.contains("_on") && file_exists(tmp_p_image.replace("_on", "_off"))) {
+ else if ((p_image.contains("_on") &&
+ file_exists(tmp_p_image.replace("_on", "_off"))) ||
+ (p_image.contains("_off") &&
+ file_exists(tmp_p_image.replace("_off", "_on")))) {
QImage tmpImage(tmp_p_image);
tmpImage = tmpImage.convertToFormat(QImage::Format_ARGB32);
QPoint p1, p2;
diff --git a/src/aooptionsdialog.cpp b/src/aooptionsdialog.cpp
index 314e9820..7b425207 100644
--- a/src/aooptionsdialog.cpp
+++ b/src/aooptionsdialog.cpp
@@ -176,6 +176,48 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app)
ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_log_ic_actions_cb);
+
+ row += 1;
+ ui_stay_time_lbl = new QLabel(ui_form_layout_widget);
+ ui_stay_time_lbl->setText(tr("Text Stay Time:"));
+ ui_stay_time_lbl->setToolTip(tr(
+ "Minimum amount of time (in miliseconds) an IC message must stay on screen before "
+ "the next IC message is shown, acting as a 'queue'. Set to 0 to disable this behaivor."));
+
+ ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_stay_time_lbl);
+
+ ui_stay_time_spinbox = new QSpinBox(ui_form_layout_widget);
+ ui_stay_time_spinbox->setMaximum(10000);
+ ui_stay_time_spinbox->setValue(p_ao_app->stay_time());
+
+ ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_stay_time_spinbox);
+
+ row += 1;
+ ui_desync_logs_lbl = new QLabel(ui_form_layout_widget);
+ ui_desync_logs_lbl->setText(tr("Desynchronize IC Logs:"));
+ ui_desync_logs_lbl->setToolTip(
+ tr("If ticked, log will show messages as-received, while viewport will parse according to the queue (Text Stay Time)."));
+
+ ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_desync_logs_lbl);
+
+ ui_desync_logs_cb = new QCheckBox(ui_form_layout_widget);
+ ui_desync_logs_cb->setChecked(p_ao_app->get_log_timestamp());
+
+ ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_desync_logs_cb);
+
+ row += 1;
+ ui_instant_objection_lbl = new QLabel(ui_form_layout_widget);
+ ui_instant_objection_lbl->setText(tr("Instant Objection:"));
+ ui_instant_objection_lbl->setToolTip(
+ tr("If Text Stay Time is more than 0, instant objection will skip queued messages instead of waiting to catch up."));
+
+ ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_instant_objection_lbl);
+
+ ui_instant_objection_cb = new QCheckBox(ui_form_layout_widget);
+ ui_instant_objection_cb->setChecked(ao_app->is_instant_objection_enabled());
+
+ ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_instant_objection_cb);
+
row += 1;
ui_log_names_divider = new QFrame(ui_form_layout_widget);
ui_log_names_divider->setFrameShape(QFrame::HLine);
@@ -779,6 +821,9 @@ void AOOptionsDialog::save_pressed()
configini->setValue("log_margin", ui_log_margin_spinbox->value());
configini->setValue("log_timestamp", ui_log_timestamp_cb->isChecked());
configini->setValue("log_ic_actions", ui_log_ic_actions_cb->isChecked());
+ configini->setValue("desync_logs", ui_desync_logs_cb->isChecked());
+ configini->setValue("stay_time", ui_stay_time_spinbox->value());
+ configini->setValue("instant_objection", ui_instant_objection_cb->isChecked());
configini->setValue("default_username", ui_username_textbox->text());
configini->setValue("show_custom_shownames", ui_showname_cb->isChecked());
configini->setValue("master", ui_ms_textbox->text());
diff --git a/src/courtroom.cpp b/src/courtroom.cpp
index 361f08fa..4ed47355 100644
--- a/src/courtroom.cpp
+++ b/src/courtroom.cpp
@@ -19,6 +19,9 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow()
text_delay_timer = new QTimer(this);
text_delay_timer->setSingleShot(true);
+ text_queue_timer = new QTimer(this);
+ text_queue_timer->setSingleShot(true);
+
sfx_delay_timer = new QTimer(this);
sfx_delay_timer->setSingleShot(true);
@@ -217,7 +220,7 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow()
ui_showname_enable->setText(tr("Shownames"));
ui_immediate = new QCheckBox(this);
- ui_immediate->setText(tr("No Interrupt"));
+ ui_immediate->setText(tr("Immediate"));
ui_immediate->hide();
ui_custom_objection = new AOButton(this, ao_app);
@@ -280,6 +283,10 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow()
connect(text_delay_timer, SIGNAL(timeout()), this,
SLOT(start_chat_ticking()));
+
+ connect(text_queue_timer, SIGNAL(timeout()), this,
+ SLOT(chatmessage_dequeue()));
+
connect(sfx_delay_timer, SIGNAL(timeout()), this, SLOT(play_sfx()));
connect(chat_tick_timer, SIGNAL(timeout()), this, SLOT(chat_tick()));
@@ -854,7 +861,8 @@ void Courtroom::set_widgets()
"animation plays concurrently."));
design_ini_result =
- ao_app->get_element_dimensions("immediate", "courtroom_design.ini");
+ ao_app->get_element_dimensions("immediate", "courtroom_design.ini");
+
// If we don't have new-style naming, fall back to the old method
if (design_ini_result.width < 0 || design_ini_result.height < 0) {
set_size_and_pos(ui_immediate, "pre_no_interrupt");
@@ -1218,10 +1226,13 @@ void Courtroom::set_background(QString p_background, bool display)
ui_vp_effect->stop();
ui_vp_message->hide();
ui_vp_chatbox->hide();
-
// Stop the chat arrow from animating
ui_vp_chat_arrow->stop();
+ // Clear the message queue
+ text_queue_timer->stop();
+ chatmessage_queue.clear();
+
text_state = 2;
anim_state = 3;
ui_vp_objection->stop();
@@ -1393,7 +1404,9 @@ 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();
- // have to call these to make sure sfx and blips don't get accidentally muted forever when we change characters
+ // have to call these to make sure music, sfx, and blips don't get accidentally muted forever when we change characters
+ music_player->set_volume(ui_music_slider->value(), 0);
+ objection_player->set_volume(ui_sfx_slider->value());
sfx_player->set_volume(ui_sfx_slider->value());
blip_player->set_volume(ui_blip_slider->value());
}
@@ -1609,7 +1622,7 @@ void Courtroom::on_chat_return_pressed()
return;
ui_ic_chat_message->blockSignals(true);
- QTimer::singleShot(600, this,
+ QTimer::singleShot(200, this,
[=] { ui_ic_chat_message->blockSignals(false); });
// MS#
// deskmod#
@@ -1840,17 +1853,6 @@ void Courtroom::on_chat_return_pressed()
ao_app->send_server_packet(new AOPacket("MS", packet_contents));
}
-void Courtroom::reset_ic()
-{
- ui_vp_chat_arrow->stop();
- text_state = 0;
- anim_state = 0;
- evidence_presented = false;
- ui_vp_objection->stop();
- chat_tick_timer->stop();
- ui_vp_evidence_display->reset();
-}
-
void Courtroom::reset_ui()
{
ui_ic_chat_message->clear();
@@ -1871,54 +1873,298 @@ void Courtroom::reset_ui()
ui_evidence_present->set_image("present");
}
-void Courtroom::handle_chatmessage(QStringList *p_contents)
+void Courtroom::chatmessage_enqueue(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() < MS_MINIMUM)
+ if (p_contents.size() < MS_MINIMUM)
+ return;
+
+ // Check the validity of the character ID we got
+ int f_char_id = p_contents[CHAR_ID].toInt();
+ if (f_char_id < -1 || f_char_id >= char_list.size())
return;
- int prev_char_id = m_chatmessage[CHAR_ID].toInt();
+ // We muted this char, gtfo
+ if (mute_map.value(f_char_id))
+ return;
+
+ // Reset input UI elements if the char ID matches our client's char ID (most likely, this is our message coming back to us)
+ if (f_char_id == m_cid) {
+ reset_ui();
+ }
+
+ // User-created blankpost
+ if (p_contents[MESSAGE].trimmed().isEmpty()) {
+ // Turn it into true blankpost
+ p_contents[MESSAGE] = "";
+ }
+
+ bool is_objection = false;
+ // If the user wants to clear queue on objection
+ if (ao_app->is_instant_objection_enabled())
+ {
+ int objection_mod = p_contents[OBJECTION_MOD].split("&")[0].toInt();
+ is_objection = objection_mod >= 1 && objection_mod <= 5;
+ // If this is an objection, nuke the queue
+ if (is_objection)
+ chatmessage_queue.clear();
+ }
+
+ // Record the log I/O, log files should be accurate.
+ log_chatmessage(p_contents[MESSAGE], f_char_id, p_contents[SHOWNAME], p_contents[TEXT_COLOR].toInt());
+ if (ao_app->is_desyncrhonized_logs_enabled()) {
+ // Display the logs immediately.
+ display_log_chatmessage(p_contents[MESSAGE], f_char_id, p_contents[SHOWNAME], p_contents[TEXT_COLOR].toInt());
+ }
+
+ // Send this boi into the queue
+ chatmessage_queue.enqueue(p_contents);
+
+ // Our settings disabled queue, or no message is being parsed right now and we're not waiting on one
+ bool start_queue = ao_app->stay_time() <= 0 || (text_state >= 2 && !text_queue_timer->isActive());
+ // Objections also immediately play the message
+ if (start_queue || is_objection)
+ chatmessage_dequeue(); // Process the message instantly
+ // Otherwise, since a message is being parsed, chat_tick() should be called which will call dequeue once it's done.
+}
+
+void Courtroom::chatmessage_dequeue()
+{
+ // Chat stopped being processed, indicate that the user can post their message now.
+ 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);
+
+ // Nothing to parse in the queue
+ if (chatmessage_queue.isEmpty())
+ return;
+
+ // Stop the text queue timer
+ if (text_queue_timer->isActive())
+ text_queue_timer->stop();
+
+ unpack_chatmessage(chatmessage_queue.dequeue());
+}
+
+void Courtroom::unpack_chatmessage(QStringList p_contents)
+{
for (int n_string = 0; n_string < MS_MAXIMUM; ++n_string) {
// Note that we have added stuff that vanilla clients and servers simply
// won't send. So now, we have to check if the thing we want even exists
// amongst the packet's content. We also have to check if the server even
// supports CCCC's IC features, or if it's just japing us. Also, don't
// forget! A size 15 message will have indices from 0 to 14.
- if (n_string < p_contents->size() &&
+ if (n_string < p_contents.size() &&
(n_string < MS_MINIMUM || ao_app->cccc_ic_support_enabled)) {
- m_chatmessage[n_string] = p_contents->at(n_string);
+ m_chatmessage[n_string] = p_contents.at(n_string);
}
else {
m_chatmessage[n_string] = "";
}
}
- int f_char_id = m_chatmessage[CHAR_ID].toInt();
- const bool is_spectator = (f_char_id == -1);
+ if (!ao_app->is_desyncrhonized_logs_enabled()) {
+ // We have logs displaying as soon as we reach the message in our queue, which is a less confusing but also less accurate experience for the user.
+ display_log_chatmessage(m_chatmessage[MESSAGE], m_chatmessage[CHAR_ID].toInt(), m_chatmessage[SHOWNAME], m_chatmessage[TEXT_COLOR].toInt());
+ }
- if (f_char_id < -1 || f_char_id >= char_list.size())
- return;
- if (mute_map.value(m_chatmessage[CHAR_ID].toInt()))
- return;
+ // Process the callwords for this message
+ handle_callwords();
- QString f_displayname;
- if (!is_spectator &&
- (m_chatmessage[SHOWNAME].isEmpty() || !ui_showname_enable->isChecked())) {
- // If the users is not a spectator and showname is disabled, use the
- // character's name
- f_displayname = ao_app->get_showname(char_list.at(f_char_id).name);
+ // Reset the interface to make room for objection handling
+ ui_vp_chat_arrow->stop();
+ text_state = 0;
+ anim_state = 0;
+ evidence_presented = false;
+ ui_vp_objection->stop();
+ chat_tick_timer->stop();
+ ui_vp_evidence_display->reset();
+ // This chat msg is not objection so we're not waiting on the objection animation to finish to display the character.
+ if (!handle_objection())
+ handle_ic_message();
+}
+
+void Courtroom::log_chatmessage(QString f_message, int f_char_id, QString f_showname, int f_color)
+{
+ // Display name will use the showname
+ QString f_displayname = f_showname;
+ if (f_char_id != -1) {
+ // Grab the char.ini showname
+ f_showname = ao_app->get_showname(char_list.at(f_char_id).name);
+ // If custom serversided shownames are not enabled
+ if (!ui_showname_enable->isChecked()) {
+ // Set the display name to the char.ini showname
+ f_displayname = f_showname;
+ }
}
- else {
- // Otherwise, use the showname
- f_displayname = m_chatmessage[SHOWNAME];
+ // If display name is just whitespace, use the char.ini showname.
+ if (f_displayname.trimmed().isEmpty())
+ f_displayname = f_showname;
+
+ if (log_ic_actions) {
+ // Check if a custom objection is in use
+ int objection_mod = 0;
+ QString custom_objection = "";
+ if (m_chatmessage[OBJECTION_MOD].contains("4&")) {
+ objection_mod = 4;
+ custom_objection = m_chatmessage[OBJECTION_MOD].split(
+ "4&")[1]; // takes the name of custom objection.
+ }
+ else {
+ 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 (objection_mod <= 4 && objection_mod >= 1) {
+ QString shout_message;
+ switch (objection_mod) {
+ case 1:
+ shout_message = ao_app->read_char_ini(f_char, "holdit_message", "Shouts");
+ if (shout_message == "")
+ shout_message = tr("HOLD IT!");
+ break;
+ case 2:
+ shout_message = ao_app->read_char_ini(f_char, "objection_message", "Shouts");
+ if (shout_message == "")
+ shout_message = tr("OBJECTION!");
+ break;
+ case 3:
+ shout_message = ao_app->read_char_ini(f_char, "takethat_message", "Shouts");
+ if (shout_message == "")
+ shout_message = tr("TAKE THAT!");
+ break;
+ // case 4 is AO2 only
+ case 4:
+ if (custom_objection != "") {
+ shout_message = ao_app->read_char_ini(f_char, custom_objection.split('.')[0] + "_message", "Shouts");
+ if (shout_message == "")
+ shout_message = custom_objection.split('.')[0];
+ }
+ else {
+ shout_message = ao_app->read_char_ini(f_char, "custom_message", "Shouts");
+ if (shout_message == "")
+ shout_message = tr("CUSTOM OBJECTION!");
+ }
+ break;
+ }
+ log_ic_text(f_char, f_displayname, shout_message, tr("shouts"));
+ }
+
+ // Obtain evidence ID we're trying to work with
+ int f_evi_id = m_chatmessage[EVIDENCE_ID].toInt();
+ // If the evidence ID is in the valid range
+ if (f_evi_id > 0 && f_evi_id <= local_evidence_list.size()) {
+ // Obtain the evidence name
+ QString f_evi_name = local_evidence_list.at(f_evi_id - 1).name;
+ // Add the message to the logs file
+ log_ic_text(f_showname, f_displayname, f_evi_name,
+ tr("has presented evidence"));
+ }
+ }
+
+ // If the chat message isn't a blankpost, or the chatlog history is empty, or its last message isn't a blankpost
+ if (!f_message.isEmpty() ||
+ ic_chatlog_history.isEmpty() || ic_chatlog_history.last().get_message() != "") {
+ // Add the message to the logs file
+ log_ic_text(f_showname, f_displayname, f_message, "",
+ f_color);
}
+}
- // If chatblank is enabled, use the character's name for logs
+void Courtroom::display_log_chatmessage(QString f_message, int f_char_id, QString f_showname, int f_color)
+{
+ // Display name will use the showname
+ QString f_displayname = f_showname;
+ if (f_char_id != -1) {
+ // Grab the char.ini showname
+ f_showname = ao_app->get_showname(char_list.at(f_char_id).name);
+ // If custom serversided shownames are not enabled
+ if (!ui_showname_enable->isChecked()) {
+ // Set the display name to the char.ini showname
+ f_displayname = f_showname;
+ }
+ }
+ // If display name is just whitespace, use the char.ini showname.
if (f_displayname.trimmed().isEmpty())
- f_displayname = ao_app->get_showname(char_list.at(f_char_id).name);
+ f_displayname = f_showname;
+
+ if (log_ic_actions) {
+ // Check if a custom objection is in use
+ int objection_mod = 0;
+ QString custom_objection = "";
+ if (m_chatmessage[OBJECTION_MOD].contains("4&")) {
+ objection_mod = 4;
+ custom_objection = m_chatmessage[OBJECTION_MOD].split(
+ "4&")[1]; // takes the name of custom objection.
+ }
+ else {
+ 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 (objection_mod <= 4 && objection_mod >= 1) {
+ QString shout_message;
+ switch (objection_mod) {
+ case 1:
+ shout_message = ao_app->read_char_ini(f_char, "holdit_message", "Shouts");
+ if (shout_message == "")
+ shout_message = tr("HOLD IT!");
+ break;
+ case 2:
+ shout_message = ao_app->read_char_ini(f_char, "objection_message", "Shouts");
+ if (shout_message == "")
+ shout_message = tr("OBJECTION!");
+ break;
+ case 3:
+ shout_message = ao_app->read_char_ini(f_char, "takethat_message", "Shouts");
+ if (shout_message == "")
+ shout_message = tr("TAKE THAT!");
+ break;
+ // case 4 is AO2 only
+ case 4:
+ if (custom_objection != "") {
+ shout_message = ao_app->read_char_ini(f_char, custom_objection.split('.')[0] + "_message", "Shouts");
+ if (shout_message == "")
+ shout_message = custom_objection.split('.')[0];
+ }
+ else {
+ shout_message = ao_app->read_char_ini(f_char, "custom_message", "Shouts");
+ if (shout_message == "")
+ shout_message = tr("CUSTOM OBJECTION!");
+ }
+ break;
+ }
+ append_ic_text(shout_message, f_displayname, tr("shouts"));
+ }
+
+ // Obtain evidence ID we're trying to work with
+ int f_evi_id = m_chatmessage[EVIDENCE_ID].toInt();
+ // If the evidence ID is in the valid range
+ if (f_evi_id > 0 && f_evi_id <= local_evidence_list.size()) {
+ // Obtain the evidence name
+ QString f_evi_name = local_evidence_list.at(f_evi_id - 1).name;
+ // Append the message to the IC chatlogs in client
+ append_ic_text(f_evi_name, f_displayname, tr("has presented evidence"));
+ }
+ }
+
+ // If the chat message isn't a blankpost, or the chatlog history is empty, or its last message isn't a blankpost
+ if (!f_message.isEmpty() ||
+ ic_chatlog_history.isEmpty() || ic_chatlog_history.last().get_message() != "") {
+ // Append the message to the IC chatlogs in client
+ append_ic_text(f_message, f_displayname, "",
+ f_color);
+ }
+}
+bool Courtroom::handle_objection()
+{
// Check if a custom objection is in use
int objection_mod = 0;
QString custom_objection = "";
@@ -1931,23 +2177,6 @@ void Courtroom::handle_chatmessage(QStringList *p_contents)
objection_mod = m_chatmessage[OBJECTION_MOD].toInt();
}
- // Reset IC display
- reset_ic();
-
- // Reset UI elements after client message gets sent
- if (m_chatmessage[CHAR_ID].toInt() == m_cid) {
- reset_ui();
- }
-
- QString f_charname = "";
- if (f_char_id >= 0)
- f_charname = ao_app->get_showname(char_list.at(f_char_id).name);
-
- if (m_chatmessage[MESSAGE].trimmed().isEmpty()) // User-created blankpost
- {
- m_chatmessage[MESSAGE] = ""; // Turn it into true blankpost
- }
-
QString f_char = m_chatmessage[CHAR_NAME];
QString f_custom_theme = ao_app->get_char_shouts(f_char);
@@ -1998,36 +2227,46 @@ void Courtroom::handle_chatmessage(QStringList *p_contents)
if (shout_message == "")
shout_message = tr("CUSTOM OBJECTION!");
}
- m_chatmessage[EMOTE_MOD] = 1;
break;
}
- log_ic_text(f_char, f_displayname, shout_message,
- tr("shouts"),2);
- append_ic_text(shout_message, f_displayname, tr("shouts"));
sfx_player->clear(); // Objection played! Cut all sfx.
+ return true;
}
- else
- handle_chatmessage_2();
-
- if (!m_chatmessage[MESSAGE].isEmpty() || ic_chatlog_history.isEmpty() ||
- ic_chatlog_history.last().get_message() != "") {
- log_ic_text(f_charname, f_displayname, m_chatmessage[MESSAGE], "",
- m_chatmessage[TEXT_COLOR].toInt());
- append_ic_text(m_chatmessage[MESSAGE], f_displayname, "",
- m_chatmessage[TEXT_COLOR].toInt());
- }
+ return false;
}
-void Courtroom::objection_done() { handle_chatmessage_2(); }
-
-void Courtroom::handle_chatmessage_2()
+void Courtroom::display_character()
{
+ // Stop all previously playing animations, effects etc.
ui_vp_speedlines->stop();
ui_vp_player_char->stop();
ui_vp_effect->stop();
// Clear all looping sfx to prevent obnoxiousness
sfx_player->loop_clear();
+ // Hide the message and chatbox and handle the emotes
+ ui_vp_message->hide();
+ ui_vp_chatbox->hide();
+ // Initialize the correct pos (called SIDE here for some reason) with DESK_MOD to determine if we should hide the desk or not.
+ switch(m_chatmessage[DESK_MOD].toInt()) {
+ case 4:
+ set_self_offset(m_chatmessage[SELF_OFFSET]);
+ [[fallthrough]];
+ case 2:
+ set_scene("1", m_chatmessage[SIDE]);
+ break;
+ case 5:
+ ui_vp_sideplayer_char->hide();
+ ui_vp_player_char->move(0, 0);
+ [[fallthrough]];
+ case 3:
+ set_scene("0", m_chatmessage[SIDE]);
+ break;
+ default:
+ set_scene(m_chatmessage[DESK_MOD], m_chatmessage[SIDE]);
+ break;
+ }
+ // Arrange the netstrings of the frame SFX for the character to know about
if (!m_chatmessage[FRAME_SFX].isEmpty() &&
ao_app->is_frame_network_enabled()) {
// ORDER IS IMPORTANT!!
@@ -2039,249 +2278,164 @@ void Courtroom::handle_chatmessage_2()
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]);
- }
-
- QString customchar;
- if (ao_app->is_customchat_enabled())
- customchar = m_chatmessage[CHAR_NAME];
- if (ui_vp_showname->text().trimmed().isEmpty()) // Whitespace showname
- {
- ui_vp_chatbox->set_image("chatblank");
- }
- else // Aw yeah dude do some showname magic
- {
- if (!ui_vp_chatbox->set_image("chat"))
- ui_vp_chatbox->set_image("chatbox");
-
- QFontMetrics fm(ui_vp_showname->font());
-// Gotta support the slow paced ubuntu 18 STUCK IN 5.9.5!!
-#if QT_VERSION > QT_VERSION_CHECK(5, 11, 0)
- int fm_width = fm.horizontalAdvance(ui_vp_showname->text());
-#else
- int fm_width = fm.boundingRect((ui_vp_showname->text())).width();
-#endif
- QString chatbox_path = ao_app->get_theme_path("chat");
- QString chatbox = ao_app->get_chat(customchar);
-
- if (chatbox != "" && ao_app->is_customchat_enabled()) {
- chatbox_path = ao_app->get_base_path() + "misc/" + chatbox + "/chat";
- if (!ui_vp_chatbox->set_chatbox(chatbox_path))
- ui_vp_chatbox->set_chatbox(chatbox_path + "box");
- }
-
- // 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);
- }
+ // Determine if we should flip the character or not (what servers don't support flipping at this point?)
+ 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);
- pos_size_type default_width = ao_app->get_element_dimensions(
- "showname", "courtroom_design.ini", customchar);
- int extra_width =
- ao_app
- ->get_design_element("showname_extra_width", "courtroom_design.ini",
- customchar)
- .toInt();
- QString align = ao_app
- ->get_design_element("showname_align",
- "courtroom_design.ini", customchar)
- .toLower();
- if (align == "right")
- ui_vp_showname->setAlignment(Qt::AlignRight);
- else if (align == "center")
- ui_vp_showname->setAlignment(Qt::AlignHCenter);
- else if (align == "justify")
- ui_vp_showname->setAlignment(Qt::AlignHCenter);
- else
- ui_vp_showname->setAlignment(Qt::AlignLeft);
+ // Parse the character X offset
+ QStringList offsets = m_chatmessage[SELF_OFFSET].split("&");
+ int offset_x = offsets[0].toInt();
+ // Y offset is 0 by default unless we find that the server sent us the Y position as well
+ int offset_y = 0;
+ if (offsets.length() > 1)
+ offset_y = offsets[1].toInt();
+ // Move the character on the viewport according to the offsets
+ ui_vp_player_char->move(ui_viewport->width() * offset_x / 100, ui_viewport->height() * offset_y / 100);
+}
- 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.
+void Courtroom::display_pair_character(QString other_charid, QString other_offset)
+{
+ // If pair information exists
+ if (!other_charid.isEmpty()) {
+ // Initialize the "ok" bool check to see if the toInt conversion succeeded
+ bool ok;
+ // Grab the charid of the pair
+ int charid = other_charid.split("^")[0].toInt(&ok);
+ // If the charid is an int and is valid...
+ if (ok && charid > -1) {
+ // Show the pair character
+ ui_vp_sideplayer_char->show();
+ // Obtain the offsets, splitting it up by & char
+ QStringList offsets = other_offset.split("&");
+ int offset_x;
+ int offset_y;
+ // If we only got one number...
+ if (offsets.length() <= 1) {
+ // That's just the X offset. Make Y offset 0.
+ offset_x = other_offset.toInt();
+ offset_y = 0;
+ }
+ else {
+ // We got two numbers, set x and y offsets!
+ offset_x = offsets[0].toInt();
+ offset_y = offsets[1].toInt();
+ }
+ // Move pair character according to the offsets
+ ui_vp_sideplayer_char->move(ui_viewport->width() * offset_x / 100,
+ ui_viewport->height() * offset_y / 100);
+
+ // Split the charid according to the ^ to determine if we have "ordering" info
+ QStringList args = other_charid.split("^");
+ if (args.size() >
+ 1) // This ugly workaround is so we don't make an extra packet just
+ // for this purpose. Rewrite pairing when?
{
- 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<int>(default_width.width + (extra_width * 2)),
- ui_vp_showname->height());
+ // Change the order of appearance based on the pair order variable
+ int order = args.at(1).toInt();
+ switch (order) {
+ case 0: // Our character is in front
+ ui_vp_sideplayer_char->stackUnder(ui_vp_player_char);
+ break;
+ case 1: // Our character is behind
+ ui_vp_player_char->stackUnder(ui_vp_sideplayer_char);
+ break;
+ default:
+ break;
}
}
+
+ // Flip the pair character
+ if (ao_app->flipping_enabled && m_chatmessage[OTHER_FLIP].toInt() == 1)
+ ui_vp_sideplayer_char->set_flipped(true);
else
- ui_vp_showname->resize(default_width.width, ui_vp_showname->height());
+ ui_vp_sideplayer_char->set_flipped(false);
- set_font(ui_vp_showname, "", "showname", customchar);
- }
- else {
- ui_vp_showname->resize(default_width.width, ui_vp_showname->height());
+ // Play the other pair character's idle animation
+ ui_vp_sideplayer_char->play_idle(m_chatmessage[OTHER_NAME],
+ m_chatmessage[OTHER_EMOTE]);
}
}
+}
- ui_vp_message->hide();
- ui_vp_chatbox->hide();
-
- QString font_name;
- QString chatfont = ao_app->get_chat_font(m_chatmessage[CHAR_NAME]);
- if (chatfont != "")
- font_name = chatfont;
-
- int f_pointsize = 0;
- int chatsize = ao_app->get_chat_size(m_chatmessage[CHAR_NAME]);
- if (chatsize > 0)
- f_pointsize = chatsize;
- set_font(ui_vp_message, "", "message", customchar, font_name, f_pointsize);
-
- int emote_mod = m_chatmessage[EMOTE_MOD].toInt();
+void Courtroom::handle_emote_mod(int emote_mod, bool p_immediate)
+{
// Deal with invalid emote modifiers
if (emote_mod != 0 && emote_mod != 1 && emote_mod != 2 && emote_mod != 5 &&
emote_mod != 6) {
+ // If emote mod is 4...
if (emote_mod == 4)
emote_mod = 6; // Addresses issue with an old bug that sent the wrong
// emote modifier for zoompre
else
- emote_mod = 0;
+ emote_mod = 0; // Reset emote mod to 0
}
- 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();
- QStringList other_offsets = m_chatmessage[OTHER_OFFSET].split("&");
- int other_offset;
- int other_offset_v;
- if (other_offsets.length() <= 1) {
- other_offset = m_chatmessage[OTHER_OFFSET].toInt();
- other_offset_v = 0;
- }
- else {
- other_offset = other_offsets[0].toInt();
- other_offset_v = other_offsets[1].toInt();
- }
- ui_vp_sideplayer_char->move(ui_viewport->width() * other_offset / 100,
- ui_viewport->height() * other_offset_v /
- 100);
-
- 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
-
- QStringList self_offsets = m_chatmessage[SELF_OFFSET].split("&");
- int self_offset = self_offsets[0].toInt();
- int self_offset_v;
- if (self_offsets.length() <= 1)
- self_offset_v = 0;
- else
- self_offset_v = self_offsets[1].toInt();
- ui_vp_player_char->move(ui_viewport->width() * self_offset / 100,
- ui_viewport->height() * self_offset_v / 100);
-
- switch(m_chatmessage[DESK_MOD].toInt()) {
- case 4:
- ui_vp_sideplayer_char->hide();
- ui_vp_player_char->move(0, 0);
- [[fallthrough]];
- case 2:
- set_scene("0", m_chatmessage[SIDE]);
- break;
- case 5:
- case 3:
- set_scene("1", m_chatmessage[SIDE]);
- break;
- default:
- set_scene(m_chatmessage[DESK_MOD], m_chatmessage[SIDE]);
- break;
- }
+ // Handle the emote mod
switch (emote_mod) {
case 1:
case 2:
case 6:
+ // Emotes 1, 2 and 6 all play preanim that makes the chatbox wait for it to finish.
play_preanim(false);
break;
case 0:
case 5:
- if (m_chatmessage[IMMEDIATE].toInt() == 0)
- handle_chatmessage_3();
+ // If immediate is not ticked on...
+ if (!p_immediate)
+ {
+ // Skip preanim.
+ handle_ic_speaking();
+ }
else
+ {
+ // Emotes 0, 5 all play preanim alongside the chatbox, not waiting for the animation to finish.
play_preanim(true);
+ }
break;
default:
+ // This should never happen, but if it does anyway, yell in the console about it.
qDebug() << "W: invalid emote mod: " << QString::number(emote_mod);
}
}
+void Courtroom::objection_done() { handle_ic_message(); }
+
+void Courtroom::handle_ic_message()
+{
+ // Display our own character
+ display_character();
+
+ // Reset the pair character
+ ui_vp_sideplayer_char->stop();
+ ui_vp_sideplayer_char->move(0, 0);
+
+ // If the emote_mod is not zooming
+ int emote_mod = m_chatmessage[EMOTE_MOD].toInt();
+ if (emote_mod != 5 && emote_mod != 6) {
+ // Display the pair character
+ display_pair_character(m_chatmessage[OTHER_CHARID], m_chatmessage[OTHER_OFFSET]);
+ }
+
+ // Parse the emote_mod part of the chat message
+ handle_emote_mod(m_chatmessage[EMOTE_MOD].toInt(), m_chatmessage[IMMEDIATE].toInt() == 1);
+
+ // Update the chatbox information
+ initialize_chatbox();
+
+ // if we have instant objections disabled, and queue is not empty, check if next message after this is an objection.
+ if (!ao_app->is_instant_objection_enabled() && chatmessage_queue.size() > 0)
+ {
+ QStringList p_contents = chatmessage_queue.head();
+ int objection_mod = p_contents[OBJECTION_MOD].split("&")[0].toInt();
+ bool is_objection = objection_mod >= 1 && objection_mod <= 5;
+ // If this is an objection, we'll need to interrupt our current message.
+ if (is_objection)
+ text_queue_timer->start(objection_threshold);
+ }
+}
+
void Courtroom::do_screenshake()
{
if (!ao_app->is_shake_enabled())
@@ -2361,120 +2515,208 @@ 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);
- // 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()
+void Courtroom::initialize_chatbox()
{
- 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 > -1 &&
+ int f_charid = m_chatmessage[CHAR_ID].toInt();
+ if (f_charid >= 0 &&
(m_chatmessage[SHOWNAME].isEmpty() || !ui_showname_enable->isChecked())) {
- f_showname = ao_app->get_showname(char_list.at(f_char_id).name);
+ 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 {
- f_showname = m_chatmessage[SHOWNAME];
+ ui_vp_showname->setText(m_chatmessage[SHOWNAME]);
+ }
+
+ QString customchar;
+ if (ao_app->is_customchat_enabled())
+ customchar = m_chatmessage[CHAR_NAME];
+ if (ui_vp_showname->text().trimmed().isEmpty()) // Whitespace showname
+ {
+ ui_vp_chatbox->set_image("chatblank");
}
- if (f_showname.trimmed()
- .isEmpty()) // Pure whitespace showname, get outta here.
- f_showname = m_chatmessage[CHAR_NAME];
+ else // Aw yeah dude do some showname magic
+ {
+ if (!ui_vp_chatbox->set_image("chat"))
+ ui_vp_chatbox->set_image("chatbox");
+
+ QFontMetrics fm(ui_vp_showname->font());
+// Gotta support the slow paced ubuntu 18 STUCK IN 5.9.5!!
+#if QT_VERSION > QT_VERSION_CHECK(5, 11, 0)
+ int fm_width = fm.horizontalAdvance(ui_vp_showname->text());
+#else
+ int fm_width = fm.boundingRect((ui_vp_showname->text())).width();
+#endif
+ QString chatbox_path = ao_app->get_theme_path("chat");
+ QString chatbox = ao_app->get_chat(customchar);
- if (f_evi_id > 0 && f_evi_id <= local_evidence_list.size() &&
- !evidence_presented) {
+ 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");
+ }
+
+ // 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", customchar);
+ int extra_width =
+ ao_app
+ ->get_design_element("showname_extra_width", "courtroom_design.ini",
+ customchar)
+ .toInt();
+ QString align = ao_app
+ ->get_design_element("showname_align",
+ "courtroom_design.ini", customchar)
+ .toLower();
+ if (align == "right")
+ ui_vp_showname->setAlignment(Qt::AlignRight);
+ else if (align == "center")
+ ui_vp_showname->setAlignment(Qt::AlignHCenter);
+ else if (align == "justify")
+ ui_vp_showname->setAlignment(Qt::AlignHCenter);
+ else
+ ui_vp_showname->setAlignment(Qt::AlignLeft);
+
+ 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<int>(default_width.width + (extra_width * 2)),
+ ui_vp_showname->height());
+ }
+ }
+ else
+ ui_vp_showname->resize(default_width.width, ui_vp_showname->height());
+
+ set_font(ui_vp_showname, "", "showname", customchar);
+ }
+ else {
+ ui_vp_showname->resize(default_width.width, ui_vp_showname->height());
+ }
+ }
+
+ QString font_name;
+ QString chatfont = ao_app->get_chat_font(m_chatmessage[CHAR_NAME]);
+ if (chatfont != "")
+ font_name = chatfont;
+
+ int f_pointsize = 0;
+ int chatsize = ao_app->get_chat_size(m_chatmessage[CHAR_NAME]);
+ if (chatsize > 0)
+ f_pointsize = chatsize;
+ set_font(ui_vp_message, "", "message", customchar, font_name, f_pointsize);
+}
+
+void Courtroom::handle_callwords()
+{
+ // Quickly check through the message for the word_call (callwords) sfx
+ QString f_message = m_chatmessage[MESSAGE];
+ // Obtain the current call words (Really? It does File I/O on every single message???)
+ QStringList call_words = ao_app->get_call_words();
+ // Loop through each word in the call words list
+ for (QString word : call_words) {
+ // If our message contains that specific call word
+ if (f_message.contains(word, Qt::CaseInsensitive)) {
+ // Play the call word sfx on the modcall_player sound container
+ modcall_player->play(ao_app->get_sfx("word_call"));
+ // Make the window flash
+ ao_app->alert(this);
+ // Break the loop so we don't spam sound effects
+ break;
+ }
+ }
+}
+
+void Courtroom::display_evidence_image()
+{
+ QString side = m_chatmessage[SIDE];
+ int f_evi_id = m_chatmessage[EVIDENCE_ID].toInt();
+ 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_evi_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");
+ bool is_left_side = !(side == "def" || side == "hlp" ||
+ side == "jud" || side == "jur");
ui_vp_evidence_display->show_evidence(f_image, is_left_side,
ui_sfx_slider->value());
- if (log_ic_actions) {
- log_ic_text(m_chatmessage[CHAR_NAME], m_chatmessage[SHOWNAME], f_evi_name,
- tr("has presented evidence"),
- m_chatmessage[TEXT_COLOR].toInt());
- append_ic_text(f_evi_name, f_showname, tr("has presented evidence"));
- }
- evidence_presented = true; // we're done presenting evidence, and we
- // don't want to do it twice
}
+}
- int emote_mod = m_chatmessage[EMOTE_MOD].toInt();
-
+void Courtroom::handle_ic_speaking()
+{
+ // Display the evidence
+ display_evidence_image();
QString side = m_chatmessage[SIDE];
-
- switch(m_chatmessage[DESK_MOD].toInt()) {
- case 4:
- set_self_offset(m_chatmessage[SELF_OFFSET]);
- [[fallthrough]];
- case 2:
- set_scene("1", m_chatmessage[SIDE]);
- break;
- case 5:
- ui_vp_sideplayer_char->hide();
- ui_vp_player_char->move(0, 0);
- [[fallthrough]];
- case 3:
- set_scene("0", m_chatmessage[SIDE]);
- break;
- default:
- set_scene(m_chatmessage[DESK_MOD], m_chatmessage[SIDE]);
- break;
- }
+ int emote_mod = m_chatmessage[EMOTE_MOD].toInt();
+ // emote_mod 5 is zoom and emote_mod 6 is zoom w/ preanim.
if (emote_mod == 5 || emote_mod == 6) {
+ // Hide the desks
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);
-
+ // Obtain character information for our character
QString f_char = m_chatmessage[CHAR_NAME];
QString f_custom_theme = ao_app->get_char_shouts(f_char);
+ // I still hate this hardcoding. If we're on pos pro, hlp and wit, use prosecution_speedlines. Otherwise, defense_speedlines.
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
+ // Check if this is a talking color (white text, etc.)
color_is_talking =
color_markdown_talking_list.at(m_chatmessage[TEXT_COLOR].toInt());
+ // If color is talking, and our state isn't already talking
if (color_is_talking && text_state == 1 &&
- anim_state < 2) // Set it to talking as we're not on that already
+ anim_state < 2)
{
+ // Stop the previous animation and play the talking animation
ui_vp_player_char->stop();
ui_vp_player_char->play_talking(m_chatmessage[CHAR_NAME],
m_chatmessage[EMOTE]);
+ // Set the anim state accordingly
anim_state = 2;
}
- else if (anim_state < 3) // Set it to idle as we're not on that already
+ else if (anim_state < 3)
{
+ // Stop the previous animation and play the idle animation
ui_vp_player_char->stop();
ui_vp_player_char->play_idle(m_chatmessage[CHAR_NAME],
m_chatmessage[EMOTE]);
+ // Set the anim state accordingly
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;
- }
- }
-
+ // Begin parsing through the chatbox message
start_chat_ticking();
}
@@ -2780,8 +3022,16 @@ void Courtroom::append_ic_text(QString p_text, QString p_name, QString p_action,
// Make shout text bold
else if (p_action == tr("shouts") && log_ic_actions) {
ui_ic_chatlog->textCursor().insertText(" " + p_action + " ", normal);
- if (log_colors)
- ui_ic_chatlog->textCursor().insertHtml("<b>" + filter_ic_text(p_text, true, -1, 0) + "</b>");
+ if (log_colors) {
+ ui_ic_chatlog->textCursor().insertHtml(
+ "<b>" +
+ filter_ic_text(p_text, true, -1, 0)
+ .replace(
+ "$c0",
+ ao_app->get_color("ic_chatlog_color", "courtroom_fonts.ini")
+ .name(QColor::HexRgb)) +
+ "</b>");
+ }
else
ui_ic_chatlog->textCursor().insertText(" " + p_text, italics);
}
@@ -2864,7 +3114,7 @@ void Courtroom::play_preanim(bool immediate)
// 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 stay_time = ao_app->get_text_delay(f_char, f_preanim) * time_mod;
int sfx_delay = m_chatmessage[SFX_DELAY].toInt() * time_mod;
int preanim_duration;
@@ -2894,17 +3144,17 @@ void Courtroom::play_preanim(bool immediate)
else
anim_state = 1;
- if (text_delay >= 0)
- text_delay_timer->start(text_delay);
+ if (stay_time >= 0)
+ text_delay_timer->start(stay_time);
if (immediate)
- handle_chatmessage_3();
+ handle_ic_speaking();
}
void Courtroom::preanim_done()
{
anim_state = 1;
- handle_chatmessage_3();
+ handle_ic_speaking();
}
void Courtroom::start_chat_ticking()
@@ -3000,15 +3250,29 @@ void Courtroom::chat_tick()
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.
QString f_message_filtered = filter_ic_text(f_message, true, -1, m_chatmessage[TEXT_COLOR].toInt());
for (int c = 0; c < max_colors; ++c) {
f_message_filtered = f_message_filtered.replace("$c" + QString::number(c), char_color_rgb_list.at(c).name(QColor::HexRgb));
}
additive_previous = additive_previous + f_message_filtered;
real_tick_pos = ui_vp_message->toPlainText().size();
+
+
+ // If we're not already waiting on the next message, start the timer. We could be overriden if there's an objection planned.
+ int delay = ao_app->stay_time();
+ if (delay > 0 && !text_queue_timer->isActive())
+ text_queue_timer->start(delay);
+
+ // if we have instant objections disabled, and queue is not empty, check if next message after this is an objection.
+ if (!ao_app->is_instant_objection_enabled() && chatmessage_queue.size() > 0)
+ {
+ QStringList p_contents = chatmessage_queue.head();
+ int objection_mod = p_contents[OBJECTION_MOD].split("&")[0].toInt();
+ bool is_objection = objection_mod >= 1 && objection_mod <= 5;
+ // If this is an objection, we'll need to interrupt our current message.
+ if (is_objection)
+ chatmessage_dequeue();
+ }
return;
}
@@ -3413,13 +3677,11 @@ void Courtroom::handle_song(QStringList *p_contents)
if (!mute_map.value(n_char)) {
if (f_song == "~stop.mp3") {
- log_ic_text(str_char, str_show, "", tr("has stopped the music"),
- m_chatmessage[TEXT_COLOR].toInt());
+ log_ic_text(str_char, str_show, "", tr("has stopped the music"));
append_ic_text("", str_show, tr("has stopped the music"));
}
else {
- log_ic_text(str_char, str_show, f_song, tr("has played a song"),
- m_chatmessage[TEXT_COLOR].toInt());
+ log_ic_text(str_char, str_show, f_song, tr("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);
diff --git a/src/packet_distribution.cpp b/src/packet_distribution.cpp
index 2699f08f..4aae789e 100644
--- a/src/packet_distribution.cpp
+++ b/src/packet_distribution.cpp
@@ -286,7 +286,7 @@ void AOApplication::server_packet_received(AOPacket *p_packet)
if (AOApplication::get_auto_logging_enabled()) {
this->log_filename = QDateTime::currentDateTime().toUTC().toString(
"'logs/" + server_name.remove(QRegExp("[\\\\/:*?\"<>|\']")) +
- "/'ddd MMMM yyyy hh.mm.ss t'.log'");
+ "/'yyyy-MM-dd hh-mm-ss t'.log'");
this->write_to_file("Joined server " + server_name + " on address " +
server_address + " on " +
QDateTime::currentDateTime().toUTC().toString(),
@@ -413,9 +413,11 @@ void AOApplication::server_packet_received(AOPacket *p_packet)
goto end;
w_courtroom->clear_areas();
+ w_courtroom->arup_clear();
for (int n_element = 0; n_element < f_contents.size(); ++n_element) {
w_courtroom->append_area(f_contents.at(n_element));
+ w_courtroom->arup_append(0, "Unknown", "Unknown", "Unknown");
}
w_courtroom->list_areas();
@@ -473,7 +475,7 @@ void AOApplication::server_packet_received(AOPacket *p_packet)
}
else if (header == "MS") {
if (courtroom_constructed && courtroom_loaded)
- w_courtroom->handle_chatmessage(&p_packet->get_contents());
+ w_courtroom->chatmessage_enqueue(p_packet->get_contents());
}
else if (header == "MC") {
if (courtroom_constructed && courtroom_loaded)
diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp
index 3524d87e..1ea27bff 100644
--- a/src/text_file_functions.cpp
+++ b/src/text_file_functions.cpp
@@ -46,6 +46,12 @@ int AOApplication::get_max_log_size()
return result;
}
+int AOApplication::stay_time()
+{
+ int result = configini->value("stay_time", 200).toInt();
+ return result;
+}
+
bool AOApplication::get_log_goes_downwards()
{
QString result =
@@ -854,7 +860,7 @@ QString AOApplication::get_flash_frame(QString p_char, QString p_emote,
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, "stay_time");
if (f_result == "")
return -1;
@@ -979,6 +985,18 @@ bool AOApplication::objection_stop_music()
return result.startsWith("true");
}
+bool AOApplication::is_instant_objection_enabled()
+{
+ QString result = configini->value("instant_objection", "true").value<QString>();
+ return result.startsWith("true");
+}
+
+bool AOApplication::is_desyncrhonized_logs_enabled()
+{
+ QString result = configini->value("desync_logs", "false").value<QString>();
+ return result.startsWith("true");
+}
+
bool AOApplication::is_discord_enabled()
{
QString result = configini->value("discord", "true").value<QString>();