aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/aoapplication.h22
-rw-r--r--include/aocharmovie.h125
-rw-r--r--include/aoevidencedisplay.h4
-rw-r--r--include/aolayer.h214
-rw-r--r--include/aomovie.h36
-rw-r--r--include/aoscene.h42
-rw-r--r--include/courtroom.h69
-rw-r--r--src/aocharmovie.cpp332
-rw-r--r--src/aoevidencedisplay.cpp10
-rw-r--r--src/aolayer.cpp577
-rw-r--r--src/aomovie.cpp100
-rw-r--r--src/aoscene.cpp132
-rw-r--r--src/courtroom.cpp514
-rw-r--r--src/path_functions.cpp10
-rw-r--r--src/text_file_functions.cpp155
15 files changed, 1207 insertions, 1135 deletions
diff --git a/include/aoapplication.h b/include/aoapplication.h
index 9b7cef13..c0c3ba37 100644
--- a/include/aoapplication.h
+++ b/include/aoapplication.h
@@ -130,6 +130,7 @@ public:
QString get_default_theme_path(QString p_file);
QString get_custom_theme_path(QString p_theme, QString p_file);
QString get_character_path(QString p_char, QString p_file);
+ QString get_misc_path(QString p_misc, QString p_file);
QString get_sounds_path(QString p_file);
QString get_music_path(QString p_song);
QString get_background_path(QString p_file);
@@ -301,14 +302,14 @@ public:
// Returns the color with p_identifier from p_file
QColor get_color(QString p_identifier, QString p_file);
- // Returns the markdown symbol used for specified p_identifier such as colors
- QString get_chat_markdown(QString p_identifier, QString p_file);
+ // Returns the markup symbol used for specified p_identifier such as colors
+ QString get_chat_markup(QString p_identifier, QString p_file);
// Returns the color from the misc folder.
QColor get_chat_color(QString p_identifier, QString p_chat);
// Returns the sfx with p_identifier from sounds.ini in the current theme path
- QString get_sfx(QString p_identifier);
+ QString get_sfx(QString p_identifier, QString p_misc="default");
// Figure out if we can opus this or if we should fall back to wav
QString get_sfx_suffix(QString sound_to_check);
@@ -380,9 +381,9 @@ public:
// t
QString get_effect(QString effect, QString p_char, QString p_folder);
- // Return the effect sound associated with the fx_name in the
- // misc/effects/<char-defined>/sounds.ini, or theme/effects/sounds.ini.
- QString get_effect_sound(QString fx_name, QString p_char);
+ // Return p_property of fx_name. If p_property is "sound", return
+ // the value associated with fx_name, otherwise use fx_name + '_' + p_property.
+ QString get_effect_property(QString fx_name, QString p_char, QString p_property);
// Returns the custom realisation used by the character.
QString get_custom_realization(QString p_char);
@@ -432,6 +433,15 @@ public:
// Returns p_char's blips (previously called their "gender")
QString get_blips(QString p_char);
+ // Get a property of a given emote, or get it from "options" if emote doesn't have it
+ QString get_emote_property(QString p_char, QString p_emote, QString p_property);
+
+ // Return a transformation mode from a string ("smooth" for smooth, anything else for fast)
+ Qt::TransformationMode get_scaling(QString p_scaling);
+
+ // Returns the scaling type for p_miscname
+ Qt::TransformationMode get_misc_scaling(QString p_miscname);
+
// ======
// These are all casing-related settings.
// ======
diff --git a/include/aocharmovie.h b/include/aocharmovie.h
deleted file mode 100644
index 2dda0ec2..00000000
--- a/include/aocharmovie.h
+++ /dev/null
@@ -1,125 +0,0 @@
-#ifndef AOCHARMOVIE_H
-#define AOCHARMOVIE_H
-
-#include <QDebug>
-#include <QElapsedTimer>
-#include <QImageReader>
-#include <QLabel>
-#include <QTimer>
-
-class AOApplication;
-
-class AOCharMovie : public QLabel {
- Q_OBJECT
-
-public:
- AOCharMovie(QWidget *p_parent, AOApplication *p_ao_app);
-
- // Play a hat.gif - style preanimation
- void play_pre(QString p_char, QString p_emote, int duration);
-
- // Play a (b)normal.gif - style animation (talking)
- void play_talking(QString p_char, QString p_emote);
-
- // Play an (a)normal.gif - style animation (not talking)
- void play_idle(QString p_char, QString p_emote);
-
- // Stop the movie, clearing the image
- void stop();
-
- // Set the m_flipped variable to true/false
- void set_flipped(bool p_flipped) { m_flipped = p_flipped; }
-
- // Set the movie's playback speed (between 10% and 1000%)
- void set_speed(int modifier) { speed = qMax(10, qMin(modifier, 1000)); }
-
- // Move the label itself around
- void move(int ax, int ay);
-
- // This is somewhat pointless now as there's no "QMovie" object to resize, aka
- // no "combo" to speak of
- void combo_resize(int w, int h);
-
- // Return the frame delay adjusted for speed
- int get_frame_delay(int delay);
-
- QStringList network_strings;
-
- QString m_char;
- QString m_emote;
-
-private:
- AOApplication *ao_app;
-
- QVector<QPixmap> movie_frames;
- QVector<int> movie_delays;
-
- // Effects such as sfx, screenshakes and realization flashes are stored in
- // here. QString entry format: "sfx^[sfx_name]", "shake", "flash". The program
- // uses the QVector index as reference.
- QVector<QVector<QString>> movie_effects;
-
- QTimer *preanim_timer;
- QTimer *ticker;
- QString last_path;
- QImageReader *m_reader = new QImageReader();
-
- QElapsedTimer actual_time;
-
- // Usually used to turn seconds into milliseconds such as for [Time] tag in
- // char.ini
- const int time_mod = 60;
-
- // These are the X and Y values before they are fixed based on the sprite's
- // width.
- int x = 0;
- int y = 0;
- // These are the width and height values before they are fixed based on the
- // sprite's width.
- int f_w = 0;
- int f_h = 0;
-
- int frame = 0;
- int max_frames = 0;
-
- int speed = 100;
-
- bool m_flipped = false;
- bool play_once = true;
-
- // Set the movie's image to provided paths, preparing for playback.
- void load_image(QString p_char, QString p_emote, QString emote_prefix);
-
- // Start playback of the movie (if animated).
- void play();
-
- // Play a frame-specific effect, if there's any defined for that specific
- // frame.
- void play_frame_effect(int frame);
-
- // Retreive a pixmap adjused for mirroring/aspect ratio shenanigans from a
- // provided QImage
- QPixmap get_pixmap(QImage image);
-
- // Set the movie's frame to provided pixmap
- void set_frame(QPixmap f_pixmap);
-
- // Initialize the frame-specific effects from the char.ini
- void load_effects();
-
- // Initialize the frame-specific effects from the provided network_strings,
- // this is only initialized if network_strings has size more than 0.
- void load_network_effects();
-
-signals:
- void done();
- void shake();
- void flash();
- void play_sfx(QString sfx);
-
-private slots:
- void preanim_done();
- void movie_ticker();
-};
-
-#endif // AOCHARMOVIE_H
diff --git a/include/aoevidencedisplay.h b/include/aoevidencedisplay.h
index 979a754e..ff448c91 100644
--- a/include/aoevidencedisplay.h
+++ b/include/aoevidencedisplay.h
@@ -2,7 +2,7 @@
#define AOEVIDENCEDISPLAY_H
#include "aoapplication.h"
-#include "aomovie.h"
+#include "aolayer.h"
#include "aosfxplayer.h"
#include <QDebug>
@@ -21,7 +21,7 @@ public:
private:
AOApplication *ao_app;
- AOMovie *evidence_movie;
+ InterfaceLayer *evidence_movie;
QLabel *evidence_icon;
AOSfxPlayer *sfx_player;
diff --git a/include/aolayer.h b/include/aolayer.h
new file mode 100644
index 00000000..2e0510a9
--- /dev/null
+++ b/include/aolayer.h
@@ -0,0 +1,214 @@
+#ifndef AOLAYER_H
+#define AOLAYER_H
+
+#include <QDebug>
+#include <QElapsedTimer>
+#include <QImageReader>
+#include <QLabel>
+#include <QTimer>
+#include <QBitmap>
+
+class AOApplication;
+
+class AOLayer : public QLabel {
+ Q_OBJECT
+
+public:
+ AOLayer(QWidget *p_parent, AOApplication *p_ao_app);
+
+ QString filename; // file name without extension, i.e. "witnesstestimony"
+ int static_duration; // time in ms for static images to be displayed, if
+ // applicable. set to 0 for infinite
+ int max_duration; // maximum duration in ms, image will be culled if it is
+ // exceeded. set this to 0 for infinite duration
+ bool play_once = false; // Whether to loop this animation or not
+ bool cull_image = true; // if we're done playing this animation, should we
+ // hide it? also controls durational culling
+ Qt::TransformationMode transform_mode = Qt::FastTransformation; // transformation mode to use for this image
+ bool stretch = false; // Should we stretch/squash this image to fill the screen?
+
+ // Set the movie's image to provided paths, preparing for playback.
+ void start_playback(QString p_image);
+
+ void set_play_once(bool p_play_once);
+ void set_cull_image(bool p_cull_image);
+ void set_static_duration(int p_static_duration);
+ void set_max_duration(int p_max_duration);
+
+ // Stop the movie, clearing the image
+ void stop();
+
+ // Set the m_flipped variable to true/false
+ void set_flipped(bool p_flipped) { m_flipped = p_flipped; }
+
+ // Set the movie's playback speed (between 10% and 1000%)
+ void set_speed(int modifier) { speed = qMax(10, qMin(modifier, 1000)); }
+
+ // Move the label itself around
+ void move(int ax, int ay);
+
+ // This is somewhat pointless now as there's no "QMovie" object to resize, aka
+ // no "combo" to speak of
+ void combo_resize(int w, int h);
+
+ // Return the frame delay adjusted for speed
+ int get_frame_delay(int delay);
+
+ // iterate through a list of paths and return the first entry that exists. if
+ // none exist, return NULL (safe because we check again for existence later)
+ QString find_image(QList<QString> p_list);
+
+protected:
+ AOApplication *ao_app;
+ QVector<QPixmap> movie_frames;
+ QVector<int> movie_delays;
+
+ QTimer *preanim_timer;
+ QTimer *shfx_timer;
+ QTimer *ticker;
+ QString last_path;
+ QImageReader m_reader;
+
+ QElapsedTimer actual_time;
+
+ // Usually used to turn seconds into milliseconds such as for [Time] tag in
+ // char.ini
+ const int tick_ms = 60;
+
+ // These are the X and Y values before they are fixed based on the sprite's
+ // width.
+ int x = 0;
+ int y = 0;
+ // These are the width and height values before they are fixed based on the
+ // sprite's width.
+ int f_w = 0;
+ int f_h = 0;
+
+ int frame = 0;
+ int max_frames = 0;
+ int last_max_frames = 0;
+
+ int speed = 100;
+
+ bool m_flipped = false;
+ // Are we loading this from the same frame we left off on? TODO: actually make
+ // this work
+ bool continuous = false;
+ // Whether or not to forcibly bypass the simple check done by start_playback
+ // and use the existent value of continuous instead
+ bool force_continuous = false;
+
+ int duration = 0;
+
+ // Start playback of the movie (if animated).
+ void play();
+
+ // Freeze the movie at the current frame.
+ void freeze();
+
+ // Retreive a pixmap adjused for mirroring/aspect ratio shenanigans from a
+ // provided QImage
+ QPixmap get_pixmap(QImage image);
+
+ // Set the movie's frame to provided pixmap
+ void set_frame(QPixmap f_pixmap);
+
+signals:
+ void done();
+
+protected slots:
+ virtual void preanim_done();
+ void shfx_timer_done();
+ virtual void movie_ticker();
+};
+
+class BackgroundLayer : public AOLayer {
+ Q_OBJECT
+public:
+ BackgroundLayer(QWidget *p_parent, AOApplication *p_ao_app);
+ void load_image(QString p_filename);
+};
+
+class ForegroundLayer : public AOLayer {
+ Q_OBJECT
+public:
+ ForegroundLayer(QWidget *p_parent, AOApplication *p_ao_app);
+ QString miscname; //'misc' folder to search. we fetch this based on p_charname below
+ void load_image(QString p_filename, QString p_charname);
+};
+
+class CharLayer : public AOLayer {
+ Q_OBJECT
+public:
+ CharLayer(QWidget *p_parent, AOApplication *p_ao_app);
+ QString current_emote = ""; // name of the emote we're using
+ bool is_preanim; // equivalent to the old play_once, if true we don't want
+ // to loop this
+ QString prefix = ""; // prefix, left blank if it's a preanim
+
+ void load_image(QString p_filename, QString p_charname, int p_duration, bool p_is_preanim);
+ void play(); // overloaded so we can play effects
+
+ // networked frame fx string
+ QStringList network_strings;
+
+private:
+ QString last_char; // name of the last character we used
+ QString last_emote; // name of the last animation we used
+ QString last_prefix; // prefix of the last animation we played
+ bool was_preanim = false; // whether is_preanim was true last time
+
+ // Effects such as sfx, screenshakes and realization flashes are stored in
+ // here. QString entry format: "sfx^[sfx_name]", "shake", "flash". The program
+ // uses the QVector index as reference.
+ QVector<QVector<QString>> movie_effects;
+
+ // used for effect loading
+ QString m_char = "";
+ QString m_emote = "";
+
+ // overloaded for effects reasons
+ void start_playback(QString p_image);
+
+ // Initialize the frame-specific effects from the char.ini
+ void load_effects();
+
+ // Initialize the frame-specific effects from the provided network_strings,
+ // this is only initialized if network_strings has size more than 0.
+ void load_network_effects();
+
+ // Play a frame-specific effect, if there's any defined for that specific
+ // frame.
+ void play_frame_effect(int p_frame);
+
+private slots:
+ void preanim_done() override; // overridden so we don't accidentally cull characters
+ void movie_ticker() override; // overridden so we can play effects
+
+signals:
+ void shake();
+ void flash();
+ void play_sfx(QString sfx);
+};
+
+class InterjectionLayer : public AOLayer {
+ Q_OBJECT
+public:
+ InterjectionLayer(QWidget *p_parent, AOApplication *p_ao_app);
+ void load_image(QString p_filename, QString p_charname, QString p_miscname);
+};
+
+class EffectLayer : public AOLayer {
+ Q_OBJECT
+public:
+ EffectLayer(QWidget *p_parent, AOApplication *p_ao_app);
+ void load_image(QString p_filename, bool p_looping);
+};
+
+class InterfaceLayer : public AOLayer {
+ Q_OBJECT
+public:
+ InterfaceLayer(QWidget *p_parent, AOApplication *p_ao_app);
+ void load_image(QString p_filename, QString p_miscname);
+};
+#endif // AOLAYER_H
diff --git a/include/aomovie.h b/include/aomovie.h
deleted file mode 100644
index eb7f7a53..00000000
--- a/include/aomovie.h
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef AOMOVIE_H
-#define AOMOVIE_H
-
-#include <QLabel>
-#include <QMovie>
-
-class Courtroom;
-class AOApplication;
-
-class AOMovie : public QLabel {
- Q_OBJECT
-
-public:
- AOMovie(QWidget *p_parent, AOApplication *p_ao_app);
-
- void set_play_once(bool p_play_once);
- void play(QString p_image, QString p_char = "", QString p_custom_theme = "",
- int default_duration = 0);
- void combo_resize(int w, int h);
- void stop();
-
-private:
- QMovie *m_movie;
- AOApplication *ao_app;
- QTimer *timer;
- bool play_once = true;
-
-signals:
- void done();
-
-private slots:
- void frame_change(int n_frame);
- void timer_done();
-};
-
-#endif // AOMOVIE_H
diff --git a/include/aoscene.h b/include/aoscene.h
deleted file mode 100644
index 726e2641..00000000
--- a/include/aoscene.h
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef AOSCENE_H
-#define AOSCENE_H
-
-#include <QDebug>
-#include <QLabel>
-#include <QMovie>
-
-class Courtroom;
-class AOApplication;
-
-class AOScene : public QLabel {
- Q_OBJECT
-public:
- explicit AOScene(QWidget *parent, AOApplication *p_ao_app);
-
- void set_image(QString p_image);
- void set_legacy_desk(QString p_image);
-
- // Move the label itself around
- void move(int ax, int ay);
-
- // This is somewhat pointless now as there's no "QMovie" object to resize, aka
- // no "combo" to speak of
- void combo_resize(int w, int h);
-
-private:
- QWidget *m_parent;
- QMovie *m_movie;
- AOApplication *ao_app;
- QString last_image;
-
- // These are the X and Y values before they are fixed based on the sprite's
- // width.
- int x = 0;
- int y = 0;
- // These are the width and height values before they are fixed based on the
- // sprite's width.
- int f_w = 0;
- int f_h = 0;
-};
-
-#endif // AOSCENE_H
diff --git a/include/courtroom.h b/include/courtroom.h
index e86330e6..5ad6fa61 100644
--- a/include/courtroom.h
+++ b/include/courtroom.h
@@ -5,17 +5,15 @@
#include "aoblipplayer.h"
#include "aobutton.h"
#include "aocharbutton.h"
-#include "aocharmovie.h"
#include "aoemotebutton.h"
#include "aoevidencebutton.h"
#include "aoevidencedisplay.h"
#include "aoimage.h"
+#include "aolayer.h"
#include "aolineedit.h"
-#include "aomovie.h"
#include "aomusicplayer.h"
#include "aooptionsdialog.h"
#include "aopacket.h"
-#include "aoscene.h"
#include "aosfxplayer.h"
#include "aotextarea.h"
#include "aotextedit.h"
@@ -151,6 +149,9 @@ public:
// reads theme inis and sets size and pos based on the identifier
void set_size_and_pos(QWidget *p_widget, QString p_identifier);
+ // reads theme and char inis and sets size and pos based on the identifier
+ void set_size_and_pos(QWidget *p_widget, QString p_identifier, QString p_char);
+
// reads theme inis and returns the size and pos as defined by it
QPoint get_theme_pos(QString p_identifier);
@@ -224,11 +225,13 @@ public:
// 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);
+ enum LogMode {
+ IO_ONLY,
+ DISPLAY_ONLY,
+ DISPLAY_AND_IO
+ };
+ // Log the message contents and information such as evidence presenting etc. into the log file, the IC log, or both.
+ void log_chatmessage(QString f_message, int f_char_id, QString f_showname = "", int f_color = 0, LogMode f_log_mode=IO_ONLY);
// Log the message contents and information such as evidence presenting etc. into the IC logs
void handle_callwords();
@@ -264,7 +267,8 @@ public:
QString filter_ic_text(QString p_text, bool colorize = false, int pos = -1,
int default_color = 0);
- void log_ic_text(QString p_name, QString p_showname, QString p_message, QString p_action="", int p_color=0);
+ void log_ic_text(QString p_name, QString p_showname, QString p_message,
+ QString p_action = "", int p_color = 0);
// adds text to the IC chatlog. p_name first as bold then p_text then a newlin
// this function keeps the chatlog scrolled to the top unless there's text
@@ -380,7 +384,8 @@ private:
// True, if log should display colors.
bool log_colors = true;
- // True, if the log should display the message like name<br>text instead of name: text
+ // True, if the log should display the message like name<br>text instead of
+ // name: text
bool log_newline = false;
// True, if the log should include RP actions like interjections, showing evidence, etc.
@@ -408,16 +413,21 @@ private:
const int time_mod = 40;
// the amount of time non-animated objection/hold it/takethat images stay
- // onscreen for in ms
- const int shout_stay_time = 724;
+ // onscreen for in ms, and the maximum amount of time any interjections are
+ // allowed to play
+ const int shout_static_time = 724;
+ const int shout_max_time = 1500;
// the amount of time non-animated guilty/not guilty images stay onscreen for
- // in ms
- const int verdict_stay_time = 3000;
+ // in ms, and the maximum amount of time g/ng images are allowed to play
+ const int verdict_static_time = 3000;
+ const int verdict_max_time = 4000;
// the amount of time non-animated witness testimony/cross-examination images
- // stay onscreen for in ms
- const int wtce_stay_time = 1500;
+ // stay onscreen for in ms, and the maximum time any wt/ce image is allowed to
+ // play
+ const int wtce_static_time = 1500;
+ const int wtce_max_time = 4000;
// characters we consider punctuation
const QString punctuation_chars = ".,?!:;";
@@ -441,7 +451,7 @@ private:
bool is_muted = false;
// state of animation, 0 = objecting, 1 = preanim, 2 = talking, 3 = idle, 4 =
- // noniterrupting preanim
+ // noniterrupting preanim, 5 = (c) animation
int anim_state = 3;
// whether or not current color is a talking one
@@ -512,6 +522,7 @@ private:
// is the message we're about to send supposed to present evidence?
bool is_presenting_evidence = false;
+ bool c_played = false; // whether we've played a (c)-style postanimation yet
// have we already presented evidence for this message?
bool evidence_presented = false;
@@ -579,21 +590,20 @@ private:
AOImage *ui_background;
QWidget *ui_viewport;
- AOScene *ui_vp_background;
- AOMovie *ui_vp_speedlines;
- AOCharMovie *ui_vp_player_char;
- AOCharMovie *ui_vp_sideplayer_char;
- AOScene *ui_vp_desk;
- AOScene *ui_vp_legacy_desk;
+ BackgroundLayer *ui_vp_background;
+ ForegroundLayer *ui_vp_speedlines;
+ CharLayer *ui_vp_player_char;
+ CharLayer *ui_vp_sideplayer_char;
+ BackgroundLayer *ui_vp_desk;
AOEvidenceDisplay *ui_vp_evidence_display;
AOImage *ui_vp_chatbox;
QLabel *ui_vp_showname;
- AOMovie *ui_vp_chat_arrow;
+ InterfaceLayer *ui_vp_chat_arrow;
QTextEdit *ui_vp_message;
- AOMovie *ui_vp_effect;
- AOMovie *ui_vp_testimony;
- AOMovie *ui_vp_wtce;
- AOMovie *ui_vp_objection;
+ EffectLayer *ui_vp_effect;
+ InterfaceLayer *ui_vp_testimony;
+ InterjectionLayer *ui_vp_wtce;
+ InterjectionLayer *ui_vp_objection;
QTextEdit *ui_ic_chatlog;
@@ -605,7 +615,7 @@ private:
QTreeWidget *ui_music_list;
ScrollText *ui_music_name;
- AOMovie *ui_music_display;
+ InterfaceLayer *ui_music_display;
AOButton *ui_pair_button;
QListWidget *ui_pair_list;
@@ -759,6 +769,7 @@ private:
void regenerate_ic_chatlog();
public slots:
void objection_done();
+ void effect_done();
void preanim_done();
void do_screenshake();
void do_flash();
diff --git a/src/aocharmovie.cpp b/src/aocharmovie.cpp
deleted file mode 100644
index 09a4b889..00000000
--- a/src/aocharmovie.cpp
+++ /dev/null
@@ -1,332 +0,0 @@
-#include "aocharmovie.h"
-
-#include "aoapplication.h"
-#include "file_functions.h"
-#include "misc_functions.h"
-
-AOCharMovie::AOCharMovie(QWidget *p_parent, AOApplication *p_ao_app)
- : QLabel(p_parent)
-{
- ao_app = p_ao_app;
- preanim_timer = new QTimer(this);
- preanim_timer->setSingleShot(true);
-
- ticker = new QTimer(this);
- ticker->setTimerType(Qt::PreciseTimer);
- ticker->setSingleShot(false);
- connect(ticker, SIGNAL(timeout()), this, SLOT(movie_ticker()));
-
- // connect(m_movie, SIGNAL(frameChanged(int)), this,
- // SLOT(frame_change(int)));
- connect(preanim_timer, SIGNAL(timeout()), this, SLOT(preanim_done()));
-}
-
-void AOCharMovie::load_image(QString p_char, QString p_emote,
- QString emote_prefix)
-{
-#ifdef DEBUG_CHARMOVIE
- actual_time.restart();
-#endif
- QString emote_path;
- QList<QString> pathlist;
- pathlist = {
- ao_app->get_image_suffix(ao_app->get_character_path(
- p_char, emote_prefix + p_emote)), // Default path
- ao_app->get_image_suffix(ao_app->get_character_path(
- p_char, emote_prefix + "/" +
- p_emote)), // Path check if it's categorized into a folder
- ao_app->get_image_suffix(ao_app->get_character_path(
- p_char, p_emote)), // Just use the non-prefixed image, animated or not
- ao_app->get_image_suffix(
- ao_app->get_theme_path("placeholder")), // Theme placeholder path
- ao_app->get_image_suffix(ao_app->get_default_theme_path(
- "placeholder")), // Default theme placeholder path
- };
-
- for (QString path : pathlist) {
- if (file_exists(path)) {
- emote_path = path;
- break;
- }
- }
-
- this->clear();
- ticker->stop();
- preanim_timer->stop();
- movie_frames.clear();
- movie_delays.clear();
- movie_effects.clear();
-
- if (!file_exists(emote_path))
- return;
-
- m_reader->setFileName(emote_path);
-
- // set format to apng if png supports animation
- if (emote_path.endsWith("png")) {
- m_reader->setFormat("apng");
- if (!m_reader->supportsAnimation()) {
- m_reader->setFormat("png");
- }
- }
-
- QPixmap f_pixmap = this->get_pixmap(m_reader->read());
- int f_delay = m_reader->nextImageDelay();
-
- frame = 0;
- max_frames = m_reader->imageCount();
-
- this->set_frame(f_pixmap);
- this->show();
- if (max_frames > 1) {
- movie_frames.append(f_pixmap);
- movie_delays.append(f_delay);
- }
-
- m_char = p_char;
- m_emote = emote_prefix + p_emote;
-
- if (network_strings.size() > 0) // our FX overwritten by networked ones
- this->load_network_effects();
- else // Use default ini FX
- this->load_effects();
-#ifdef DEBUG_CHARMOVIE
- qDebug() << max_frames << "Setting image to " << emote_path
- << "Time taken to process image:" << actual_time.elapsed();
-
- actual_time.restart();
-#endif
-}
-
-void AOCharMovie::load_effects()
-{
- movie_effects.clear();
- movie_effects.resize(max_frames);
- for (int e_frame = 0; e_frame < max_frames; ++e_frame) {
- QString effect = ao_app->get_screenshake_frame(m_char, m_emote, e_frame);
- if (effect != "") {
- movie_effects[e_frame].append("shake");
- }
-
- effect = ao_app->get_flash_frame(m_char, m_emote, e_frame);
- if (effect != "") {
- movie_effects[e_frame].append("flash");
- }
-
- effect = ao_app->get_sfx_frame(m_char, m_emote, e_frame);
- if (effect != "") {
- movie_effects[e_frame].append("sfx^" + effect);
- }
- }
-}
-
-void AOCharMovie::load_network_effects()
-{
- movie_effects.clear();
- movie_effects.resize(max_frames);
- // Order is important!!!
- QStringList effects_list = {"shake", "flash", "sfx^"};
-
- // Determines which list is smaller - effects_list or network_strings - and
- // uses it as basis for the loop. This way, incomplete network_strings would
- // still be parsed, and excess/unaccounted for networked information is
- // omitted.
- int effects_size = qMin(effects_list.size(), network_strings.size());
-
- for (int i = 0; i < effects_size; ++i) {
- QString netstring = network_strings.at(i);
- QStringList emote_splits = netstring.split("^");
- foreach (QString emote, emote_splits) {
- QStringList parsed = emote.split("|");
- if (parsed.size() <= 0 || parsed.at(0) != m_emote)
- continue;
- foreach (QString frame_data, parsed) {
- QStringList frame_split = frame_data.split("=");
- if (frame_split.size() <=
- 1) // We might still be hanging at the emote itself (entry 0).
- continue;
- int f_frame = frame_split.at(0).toInt();
- if (f_frame >= max_frames) {
- qDebug() << "Warning: out of bounds" << effects_list[i] << "frame"
- << f_frame << "out of" << max_frames << "for" << m_char
- << m_emote;
- continue;
- }
- QString f_data = frame_split.at(1);
- if (f_data != "") {
- QString effect = effects_list[i];
- if (effect == "sfx^") // Currently the only frame result that feeds us
- // data, let's yank it in.
- effect += f_data;
- qDebug() << effect << f_data << "frame" << f_frame << "for" << m_char
- << m_emote;
- movie_effects[f_frame].append(effect);
- }
- }
- }
- }
-}
-
-void AOCharMovie::play()
-{
- play_frame_effect(frame);
- if (max_frames <= 1) {
- if (play_once)
- ticker->start(60);
- }
- else
- ticker->start(this->get_frame_delay(movie_delays[frame]));
-}
-
-void AOCharMovie::play_pre(QString p_char, QString p_emote, int duration)
-{
- load_image(p_char, p_emote, "");
- // As much as I'd like to screw around with [Time] durations modifying the
- // animation speed, I don't think I can reliably do that, not without looping
- // through all frames in the image at least - which causes lag. So for now it
- // simply ends the preanimation early instead.
- play_once = true;
- if (duration >
- 0) // It's -1 if there's no definition in [Time] for it. In which case, it
- // will let the animation run out in full. Duration 0 does the same.
- preanim_timer->start(duration *
- time_mod); // This timer will not fire if the animation
- // finishes earlier than that
- play();
-}
-
-void AOCharMovie::play_talking(QString p_char, QString p_emote)
-{
- play_once = false;
- load_image(p_char, p_emote, "(b)");
- play();
-}
-
-void AOCharMovie::play_idle(QString p_char, QString p_emote)
-{
- play_once = false;
- load_image(p_char, p_emote, "(a)");
- play();
-}
-
-void AOCharMovie::play_frame_effect(int frame)
-{
- if (frame < max_frames) {
- foreach (QString effect, movie_effects[frame]) {
- if (effect == "shake") {
- shake();
-#ifdef DEBUG_CHARMOVIE
- qDebug() << "Attempting to play shake on frame" << frame;
-#endif
- }
-
- if (effect == "flash") {
- flash();
-#ifdef DEBUG_CHARMOVIE
- qDebug() << "Attempting to play flash on frame" << frame;
-#endif
- }
-
- if (effect.startsWith("sfx^")) {
- QString sfx = effect.section("^", 1);
- play_sfx(sfx);
-#ifdef DEBUG_CHARMOVIE
- qDebug() << "Attempting to play sfx" << sfx << "on frame" << frame;
-#endif
- }
- }
- }
-}
-
-void AOCharMovie::stop()
-{
- // for all intents and purposes, stopping is the same as hiding. at no point
- // do we want a frozen gif to display
- ticker->stop();
- preanim_timer->stop();
- this->hide();
-}
-
-QPixmap AOCharMovie::get_pixmap(QImage image)
-{
- QPixmap f_pixmap;
- if (m_flipped)
- f_pixmap = QPixmap::fromImage(image.mirrored(true, false));
- else
- f_pixmap = QPixmap::fromImage(image);
- // auto aspect_ratio = Qt::KeepAspectRatio;
- auto transform_mode = Qt::FastTransformation;
- if (f_pixmap.height() > f_h) // We are downscaling, use anti-aliasing.
- transform_mode = Qt::SmoothTransformation;
-
- f_pixmap = f_pixmap.scaledToHeight(f_h, transform_mode);
- this->resize(f_pixmap.size());
-
- return f_pixmap;
-}
-
-void AOCharMovie::set_frame(QPixmap f_pixmap)
-{
- this->setPixmap(f_pixmap);
- QLabel::move(
- x + (f_w - f_pixmap.width()) / 2,
- y + (f_h - f_pixmap.height())); // Always center horizontally, always put
- // at the bottom vertically
-}
-
-void AOCharMovie::combo_resize(int w, int h)
-{
- QSize f_size(w, h);
- f_w = w;
- f_h = h;
- this->resize(f_size);
-}
-
-int AOCharMovie::get_frame_delay(int delay)
-{
- return static_cast<int>(double(delay) * double(speed / 100));
-}
-
-void AOCharMovie::move(int ax, int ay)
-{
- x = ax;
- y = ay;
- QLabel::move(x, y);
-}
-
-void AOCharMovie::movie_ticker()
-{
- ++frame;
- if (frame >= max_frames) {
- if (play_once) {
- preanim_done();
- return;
- }
- else
- frame = 0;
- }
- // qint64 difference = elapsed - movie_delays[frame];
- if (frame >= movie_frames.size()) {
- m_reader->jumpToImage(frame);
- movie_frames.resize(frame + 1);
- movie_frames[frame] = this->get_pixmap(m_reader->read());
- movie_delays.resize(frame + 1);
- movie_delays[frame] = m_reader->nextImageDelay();
- }
-
-#ifdef DEBUG_CHARMOVIE
- qDebug() << frame << movie_delays[frame]
- << "actual time taken from last frame:" << actual_time.restart();
-#endif
-
- this->set_frame(movie_frames[frame]);
- play_frame_effect(frame);
- ticker->setInterval(this->get_frame_delay(movie_delays[frame]));
-}
-
-void AOCharMovie::preanim_done()
-{
- ticker->stop();
- preanim_timer->stop();
- done();
-}
diff --git a/src/aoevidencedisplay.cpp b/src/aoevidencedisplay.cpp
index 2ffea2c9..f6dffd85 100644
--- a/src/aoevidencedisplay.cpp
+++ b/src/aoevidencedisplay.cpp
@@ -11,7 +11,7 @@ AOEvidenceDisplay::AOEvidenceDisplay(QWidget *p_parent, AOApplication *p_ao_app)
evidence_icon = new QLabel(this);
sfx_player = new AOSfxPlayer(this, ao_app);
- evidence_movie = new AOMovie(this, ao_app);
+ evidence_movie = new InterfaceLayer(this, ao_app);
connect(evidence_movie, SIGNAL(done()), this, SLOT(show_done()));
}
@@ -46,9 +46,11 @@ void AOEvidenceDisplay::show_evidence(QString p_evidence_image,
evidence_icon->setPixmap(f_pixmap);
evidence_icon->resize(f_pixmap.size());
evidence_icon->move(icon_dimensions.x, icon_dimensions.y);
-
- evidence_movie->play(gif_name);
- sfx_player->play(ao_app->get_sfx("evidence_present"));
+ evidence_movie->static_duration = 320;
+ evidence_movie->max_duration = 1000;
+ evidence_movie->set_play_once(true);
+ evidence_movie->load_image(gif_name, "");
+ sfx_player->play(ao_app->get_sfx("evidence_present", "default"));
}
void AOEvidenceDisplay::reset()
diff --git a/src/aolayer.cpp b/src/aolayer.cpp
new file mode 100644
index 00000000..de8a451c
--- /dev/null
+++ b/src/aolayer.cpp
@@ -0,0 +1,577 @@
+#include "aolayer.h"
+
+#include "aoapplication.h"
+#include "file_functions.h"
+#include "misc_functions.h"
+
+AOLayer::AOLayer(QWidget *p_parent, AOApplication *p_ao_app) : QLabel(p_parent)
+{
+ ao_app = p_ao_app;
+
+ // used for culling images when their max_duration is exceeded
+ shfx_timer = new QTimer(this);
+ shfx_timer->setTimerType(Qt::PreciseTimer);
+ shfx_timer->setSingleShot(true);
+ connect(shfx_timer, SIGNAL(timeout()), this, SLOT(shfx_timer_done()));
+
+ ticker = new QTimer(this);
+ ticker->setTimerType(Qt::PreciseTimer);
+ ticker->setSingleShot(false);
+ connect(ticker, SIGNAL(timeout()), this, SLOT(movie_ticker()));
+
+ preanim_timer = new QTimer(this);
+ preanim_timer->setSingleShot(true);
+ connect(preanim_timer, SIGNAL(timeout()), this, SLOT(preanim_done()));
+}
+
+BackgroundLayer::BackgroundLayer(QWidget *p_parent, AOApplication *p_ao_app)
+ : AOLayer(p_parent, p_ao_app)
+{
+}
+ForegroundLayer::ForegroundLayer(QWidget *p_parent, AOApplication *p_ao_app)
+ : AOLayer(p_parent, p_ao_app)
+{
+}
+CharLayer::CharLayer(QWidget *p_parent, AOApplication *p_ao_app)
+ : AOLayer(p_parent, p_ao_app)
+{
+}
+EffectLayer::EffectLayer(QWidget *p_parent, AOApplication *p_ao_app)
+ : AOLayer(p_parent, p_ao_app)
+{
+}
+InterjectionLayer::InterjectionLayer(QWidget *p_parent, AOApplication *p_ao_app)
+ : AOLayer(p_parent, p_ao_app)
+{
+}
+InterfaceLayer::InterfaceLayer(QWidget *p_parent, AOApplication *p_ao_app)
+ : AOLayer(p_parent, p_ao_app)
+{
+}
+
+QString AOLayer::find_image(QList<QString> p_list)
+{
+ QString image_path;
+ for (QString path : p_list) {
+#ifdef DEBUG_MOVIE
+ qDebug() << "checking path " << path;
+#endif
+ if (file_exists(path)) {
+ image_path = path;
+#ifdef DEBUG_MOVIE
+ qDebug() << "found path " << path;
+#endif
+ break;
+ }
+ }
+ return image_path;
+}
+
+QPixmap AOLayer::get_pixmap(QImage image)
+{
+ QPixmap f_pixmap;
+ if (m_flipped)
+ f_pixmap = QPixmap::fromImage(image.mirrored(true, false));
+ else
+ f_pixmap = QPixmap::fromImage(image);
+ // auto aspect_ratio = Qt::KeepAspectRatio;
+ if (f_pixmap.height() > f_h) // We are downscaling, use anti-aliasing.
+ transform_mode = Qt::SmoothTransformation;
+ if (stretch)
+ f_pixmap = f_pixmap.scaled(f_w, f_h);
+ else
+ f_pixmap = f_pixmap.scaledToHeight(f_h, transform_mode);
+ this->resize(f_pixmap.size());
+
+ return f_pixmap;
+}
+
+void AOLayer::set_frame(QPixmap f_pixmap)
+{
+ this->setPixmap(f_pixmap);
+ QLabel::move(
+ x + (f_w - f_pixmap.width()) / 2,
+ y + (f_h - f_pixmap.height())); // Always center horizontally, always put
+ // at the bottom vertically
+ this->setMask(
+ QRegion((f_pixmap.width() - f_w) / 2, (f_pixmap.height() - f_h) / 2, f_w,
+ f_h)); // make sure we don't escape the area we've been given
+}
+
+void AOLayer::combo_resize(int w, int h)
+{
+ QSize f_size(w, h);
+ f_w = w;
+ f_h = h;
+ this->resize(f_size);
+}
+
+int AOLayer::get_frame_delay(int delay)
+{
+ return static_cast<int>(double(delay) * double(speed / 100));
+}
+
+void AOLayer::move(int ax, int ay)
+{
+ x = ax;
+ y = ay;
+ QLabel::move(x, y);
+}
+
+void BackgroundLayer::load_image(QString p_filename)
+{
+ play_once = false;
+ cull_image = false;
+ QString design_path = ao_app->get_background_path("design.ini");
+ transform_mode =
+ ao_app->get_scaling(ao_app->read_design_ini("scaling", design_path));
+ stretch = ao_app->read_design_ini("stretch", design_path).startsWith("true");
+ qDebug() << "[BackgroundLayer] BG loaded: " << p_filename;
+ start_playback(ao_app->get_image_suffix(ao_app->get_background_path(p_filename)));
+}
+
+void ForegroundLayer::load_image(QString p_filename, QString p_charname)
+{
+ play_once = false;
+ cull_image = false;
+ miscname = ao_app->get_char_shouts(p_charname);
+ qDebug() << "[ForegroundLayer] FG loaded: " << p_filename;
+ QList<QString> pathlist = {
+ ao_app->get_image_suffix(ao_app->get_character_path(
+ p_charname, p_filename)), // first check the character folder
+ ao_app->get_image_suffix(ao_app->get_theme_path(
+ "misc/" + miscname + "/" +
+ p_filename)), // then check our theme's misc directory
+ ao_app->get_image_suffix(ao_app->get_misc_path(
+ miscname, p_filename)), // then check our global misc folder
+ ao_app->get_image_suffix(
+ ao_app->get_theme_path(p_filename)), // then check the user's theme
+ ao_app->get_image_suffix(ao_app->get_default_theme_path(
+ p_filename))}; // and finally check the default theme
+ start_playback(find_image(pathlist));
+}
+
+void CharLayer::load_image(QString p_filename, QString p_charname,
+ int p_duration, bool p_is_preanim)
+{
+ duration = p_duration;
+ cull_image = false;
+ force_continuous = false;
+ transform_mode = ao_app->get_scaling(
+ ao_app->get_emote_property(p_charname, p_filename, "scaling"));
+ stretch = ao_app->get_emote_property(p_charname, p_filename, "stretch")
+ .startsWith(true);
+ if ((p_charname == last_char) &&
+ ((p_filename == last_emote) ||
+ (p_filename.mid(3, -1) == last_emote.mid(3, -1))) &&
+ (!is_preanim) && (!was_preanim)) {
+ continuous = true;
+ force_continuous = true;
+ }
+ else {
+ continuous = false;
+ force_continuous = true;
+ }
+ prefix = "";
+ current_emote = p_filename;
+ was_preanim = is_preanim;
+ m_char = p_charname;
+ m_emote = current_emote;
+ last_char = p_charname;
+ last_emote = current_emote;
+ last_prefix = prefix;
+ is_preanim = p_is_preanim;
+ if ((p_filename.left(3) == "(a)") || (p_filename.left(3) == "(b)")) {
+ prefix = p_filename.left(3);
+ current_emote = p_filename.mid(3, -1);
+ }
+ else if ((duration > 0) || (p_filename.left(3) == "(c)")) {
+ if (p_filename.left(3) == "(c)") {
+ prefix = "(c)";
+ current_emote = p_filename.mid(3, -1);
+ }
+ is_preanim = true;
+ play_once = true;
+ preanim_timer->start(duration * tick_ms);
+ }
+ qDebug() << "[CharLayer] anim loaded: prefix " << prefix << " filename "
+ << current_emote << " from character: " << p_charname
+ << " continuous: " << continuous;
+ QList<QString> pathlist = {
+ ao_app->get_image_suffix(ao_app->get_character_path(
+ p_charname, prefix + current_emote)), // Default path
+ ao_app->get_image_suffix(ao_app->get_character_path(
+ p_charname,
+ prefix + "/" + current_emote)), // Path check if it's categorized
+ // into a folder
+ ao_app->get_image_suffix(ao_app->get_character_path(
+ p_charname,
+ current_emote)), // Just use the non-prefixed image, animated or not
+ ao_app->get_image_suffix(
+ ao_app->get_theme_path("placeholder")), // Theme placeholder path
+ ao_app->get_image_suffix(ao_app->get_default_theme_path(
+ "placeholder"))}; // Default theme placeholder path
+ this->start_playback(find_image(pathlist));
+}
+
+void InterjectionLayer::load_image(QString p_filename, QString p_charname,
+ QString p_miscname)
+{
+ continuous = false;
+ force_continuous = true;
+ play_once = true;
+ transform_mode = ao_app->get_misc_scaling(p_miscname);
+ QList<QString> pathlist = {
+ ao_app->get_image_suffix(ao_app->get_character_path(
+ p_charname, p_filename)), // Character folder
+ ao_app->get_image_suffix(ao_app->get_theme_path(
+ "misc/" + p_miscname + "/" + p_filename)), // Theme misc path
+ ao_app->get_image_suffix(
+ ao_app->get_misc_path(p_miscname, p_filename)), // Misc path
+ ao_app->get_image_suffix(
+ ao_app->get_theme_path(p_filename)), // Theme path
+ ao_app->get_image_suffix(
+ ao_app->get_default_theme_path(p_filename)), // Default theme path
+ ao_app->get_image_suffix(
+ ao_app->get_theme_path("placeholder")), // Placeholder path
+ ao_app->get_image_suffix(ao_app->get_default_theme_path(
+ "placeholder")), // Default placeholder path
+ };
+ QString final_image = find_image(pathlist);
+ if (final_image == ao_app->get_theme_path("custom.png") ||
+ final_image == ao_app->get_default_theme_path("custom.png") ||
+ final_image == ao_app->get_theme_path("witnesstestimony.png") ||
+ final_image == ao_app->get_default_theme_path("witnesstestimony.png") ||
+ final_image == ao_app->get_theme_path("crossexamination.png") ||
+ final_image == ao_app->get_default_theme_path("crossexamination.png"))
+ // stupid exceptions because themes are stupid
+ final_image = find_image(
+ {ao_app->get_image_suffix(ao_app->get_theme_path("placeholder")),
+ ao_app->get_image_suffix(ao_app->get_default_theme_path("placeholder"))});
+ start_playback(final_image);
+}
+
+void EffectLayer::load_image(QString p_filename, bool p_looping)
+{
+ if (p_looping)
+ play_once = false;
+ else
+ play_once = true;
+ continuous = false;
+ force_continuous = true;
+ start_playback(p_filename); // handled in its own file before we see it
+}
+
+void InterfaceLayer::load_image(QString p_filename, QString p_miscname)
+{
+ transform_mode = ao_app->get_misc_scaling(p_miscname);
+ QList<QString> pathlist = {
+ ao_app->get_image_suffix(ao_app->get_theme_path(
+ "misc/" + p_miscname + "/" +
+ p_filename)), // first check our theme's misc directory
+ ao_app->get_image_suffix(ao_app->get_misc_path(
+ p_miscname, p_filename)), // then check our global misc folder
+ ao_app->get_image_suffix(ao_app->get_theme_path(
+ p_filename)), // then check the user's theme for a default image
+ ao_app->get_image_suffix(ao_app->get_default_theme_path(
+ p_filename))}; // and finally check the default theme
+ start_playback(find_image(pathlist));
+}
+
+void CharLayer::start_playback(QString p_image)
+{
+ movie_effects.clear();
+ AOLayer::start_playback(p_image);
+ if (network_strings.size() > 0) // our FX overwritten by networked ones
+ load_network_effects();
+ else // Use default ini FX
+ load_effects();
+}
+
+void AOLayer::start_playback(QString p_image)
+{
+#ifdef DEBUG_MOVIE
+ actual_time.restart();
+#endif
+ this->clear();
+ freeze();
+ movie_frames.clear();
+ movie_delays.clear();
+
+ if (!file_exists(p_image))
+ return;
+
+ QString scaling_override =
+ ao_app->read_design_ini("scaling", p_image + ".ini");
+ if (scaling_override != "")
+ transform_mode = ao_app->get_scaling(scaling_override);
+ QString stretch_override =
+ ao_app->read_design_ini("stretch", p_image + ".ini");
+ if (stretch_override != "")
+ stretch = stretch_override.startsWith("true");
+
+ qDebug() << "stretch:" << stretch << "filename:" << p_image;
+ m_reader.setFileName(p_image);
+ if (m_reader.loopCount() == 0)
+ play_once = true;
+ if ((last_path == p_image) && (!force_continuous))
+ continuous = true;
+ else if ((last_path != p_image) && !force_continuous)
+ continuous = false;
+ if (!continuous)
+ frame = 0;
+ force_continuous = false;
+ last_max_frames = max_frames;
+ max_frames = m_reader.imageCount();
+ if (((continuous) && (max_frames != last_max_frames)) || max_frames == 0) {
+ frame = 0;
+ continuous = false;
+ }
+ // CANTFIX: this causes a slight hitch
+ // The correct way of doing this would be to use QImageReader::jumpToImage()
+ // and populate missing data in the movie ticker when it's needed. This is
+ // unforunately completely impossible, because QImageReader::jumpToImage() is
+ // not implemented in any image format AO2 is equipped to use. Instead, the
+ // default behavior is used - that is, absolutely nothing.
+ if (continuous) {
+ for (int i = frame; i--;) {
+ if (i <= -1)
+ break;
+ QPixmap l_pixmap = this->get_pixmap(m_reader.read());
+ int l_delay = m_reader.nextImageDelay();
+ movie_frames.append(l_pixmap);
+ movie_delays.append(l_delay);
+ // qDebug() << "appending delay of " << l_delay;
+ }
+ }
+ // qDebug() << "CONT: " << continuous << " MAX: " << max_frames
+ // << " LAST MAX: " << last_max_frames << " FRAME: " << frame;
+ QPixmap f_pixmap = this->get_pixmap(m_reader.read());
+ int f_delay = m_reader.nextImageDelay();
+
+ this->set_frame(f_pixmap);
+ this->show();
+ if (max_frames > 1) {
+ movie_frames.append(f_pixmap);
+ movie_delays.append(f_delay);
+ }
+ else if (max_frames <= 1) {
+ duration = static_duration;
+ play_once = false;
+#ifdef DEBUG_MOVIE
+ qDebug() << "max_frames is <= 1, using static duration";
+#endif
+ }
+ if (duration > 0 && cull_image == true)
+ shfx_timer->start(duration);
+ play();
+#ifdef DEBUG_MOVIE
+ qDebug() << max_frames << "Setting image to " << image_path
+ << "Time taken to process image:" << actual_time.elapsed();
+
+ actual_time.restart();
+#endif
+}
+
+void CharLayer::play()
+{
+ play_frame_effect(frame);
+ AOLayer::play();
+}
+
+void AOLayer::play()
+{
+ if (max_frames <= 1) {
+ if (play_once)
+ ticker->start(tick_ms);
+ else
+ this->freeze();
+ }
+ else
+ ticker->start(this->get_frame_delay(movie_delays[frame]));
+}
+
+void AOLayer::set_play_once(bool p_play_once) { play_once = p_play_once; }
+void AOLayer::set_cull_image(bool p_cull_image) { cull_image = p_cull_image; }
+void AOLayer::set_static_duration(int p_static_duration)
+{
+ static_duration = p_static_duration;
+}
+void AOLayer::set_max_duration(int p_max_duration)
+{
+ max_duration = p_max_duration;
+}
+
+void CharLayer::load_effects()
+{
+ movie_effects.clear();
+ movie_effects.resize(max_frames);
+ for (int e_frame = 0; e_frame < max_frames; ++e_frame) {
+ QString effect = ao_app->get_screenshake_frame(m_char, m_emote, e_frame);
+ if (effect != "") {
+ movie_effects[e_frame].append("shake");
+ }
+
+ effect = ao_app->get_flash_frame(m_char, m_emote, e_frame);
+ if (effect != "") {
+ movie_effects[e_frame].append("flash");
+ }
+
+ effect = ao_app->get_sfx_frame(m_char, m_emote, e_frame);
+ if (effect != "") {
+ movie_effects[e_frame].append("sfx^" + effect);
+ }
+ }
+}
+
+void CharLayer::load_network_effects()
+{
+ movie_effects.clear();
+ movie_effects.resize(max_frames);
+ // Order is important!!!
+ QStringList effects_list = {"shake", "flash", "sfx^"};
+
+ // Determines which list is smaller - effects_list or network_strings - and
+ // uses it as basis for the loop. This way, incomplete network_strings would
+ // still be parsed, and excess/unaccounted for networked information is
+ // omitted.
+ int effects_size = qMin(effects_list.size(), network_strings.size());
+
+ for (int i = 0; i < effects_size; ++i) {
+ QString netstring = network_strings.at(i);
+ QStringList emote_splits = netstring.split("^");
+ for (const QString &emote : emote_splits) {
+ QStringList parsed = emote.split("|");
+ if (parsed.size() <= 0 || parsed.at(0) != m_emote)
+ continue;
+ foreach (QString frame_data, parsed) {
+ QStringList frame_split = frame_data.split("=");
+ if (frame_split.size() <=
+ 1) // We might still be hanging at the emote itself (entry 0).
+ continue;
+ int f_frame = frame_split.at(0).toInt();
+ if (f_frame >= max_frames || f_frame < 0) {
+ qDebug() << "Warning: out of bounds" << effects_list[i] << "frame"
+ << f_frame << "out of" << max_frames << "for" << m_emote;
+ continue;
+ }
+ QString f_data = frame_split.at(1);
+ if (f_data != "") {
+ QString effect = effects_list[i];
+ if (effect == "sfx^") // Currently the only frame result that feeds us
+ // data, let's yank it in.
+ effect += f_data;
+ qDebug() << effect << f_data << "frame" << f_frame << "for"
+ << m_emote;
+ movie_effects[f_frame].append(effect);
+ }
+ }
+ }
+ }
+}
+
+void CharLayer::play_frame_effect(int p_frame)
+{
+ if (p_frame < max_frames) {
+ foreach (QString effect, movie_effects[p_frame]) {
+ if (effect == "shake") {
+ shake();
+#ifdef DEBUG_MOVIE
+ qDebug() << "Attempting to play shake on frame" << frame;
+#endif
+ }
+
+ if (effect == "flash") {
+ flash();
+#ifdef DEBUG_MOVIE
+ qDebug() << "Attempting to play flash on frame" << frame;
+#endif
+ }
+
+ if (effect.startsWith("sfx^")) {
+ QString sfx = effect.section("^", 1);
+ play_sfx(sfx);
+#ifdef DEBUG_MOVIE
+ qDebug() << "Attempting to play sfx" << sfx << "on frame" << frame;
+#endif
+ }
+ }
+ }
+}
+
+void AOLayer::stop()
+{
+ // for all intents and purposes, stopping is the same as hiding. at no point
+ // do we want a frozen gif to display
+ this->freeze();
+ this->hide();
+}
+
+void AOLayer::freeze()
+{
+ // aT nO pOiNt Do We WaNt A fRoZeN gIf To DiSpLaY
+ ticker->stop();
+ preanim_timer->stop();
+ shfx_timer->stop();
+}
+
+void CharLayer::movie_ticker()
+{
+ AOLayer::movie_ticker();
+ play_frame_effect(frame);
+}
+
+void AOLayer::movie_ticker()
+{
+ ++frame;
+ if ((frame >= max_frames) && (max_frames > 1)) {
+ if (play_once) {
+ if (cull_image)
+ this->stop();
+ else
+ this->freeze();
+ preanim_done();
+ return;
+ }
+ else
+ frame = 0;
+ }
+ // qint64 difference = elapsed - movie_delays[frame];
+ if (frame >= movie_frames.size()) {
+ movie_frames.append(this->get_pixmap(m_reader.read()));
+ movie_delays.append(m_reader.nextImageDelay());
+ }
+
+#ifdef DEBUG_MOVIE
+ qDebug() << frame << movie_delays[frame]
+ << "actual time taken from last frame:" << actual_time.restart();
+#endif
+
+ this->set_frame(movie_frames[frame]);
+ ticker->setInterval(this->get_frame_delay(movie_delays[frame]));
+}
+
+void CharLayer::preanim_done()
+{
+ if (is_preanim)
+ AOLayer::preanim_done();
+ else
+ return;
+}
+
+void AOLayer::preanim_done()
+{
+ ticker->stop();
+ preanim_timer->stop();
+ done();
+}
+
+void AOLayer::shfx_timer_done()
+{
+ this->stop();
+#ifdef DEBUG_MOVIE
+ qDebug() << "shfx timer signaled done";
+#endif
+ // signal connected to courtroom object, let it figure out what to do
+ done();
+}
diff --git a/src/aomovie.cpp b/src/aomovie.cpp
deleted file mode 100644
index 196c1d3e..00000000
--- a/src/aomovie.cpp
+++ /dev/null
@@ -1,100 +0,0 @@
-#include "aomovie.h"
-
-#include "courtroom.h"
-#include "file_functions.h"
-#include "misc_functions.h"
-
-AOMovie::AOMovie(QWidget *p_parent, AOApplication *p_ao_app) : QLabel(p_parent)
-{
- ao_app = p_ao_app;
-
- m_movie = new QMovie();
- m_movie->setCacheMode(QMovie::CacheAll);
-
- this->setMovie(m_movie);
-
- timer = new QTimer(this);
- timer->setTimerType(Qt::PreciseTimer);
- timer->setSingleShot(true);
-
- connect(m_movie, SIGNAL(frameChanged(int)), this, SLOT(frame_change(int)));
- connect(timer, SIGNAL(timeout()), this, SLOT(timer_done()));
-}
-
-void AOMovie::set_play_once(bool p_play_once) { play_once = p_play_once; }
-
-void AOMovie::play(QString p_image, QString p_char, QString p_custom_theme,
- int duration)
-{
- m_movie->stop();
-
- QString shout_path = p_image;
- if (!file_exists(p_image)) {
- QList<QString> pathlist;
-
- pathlist = {
- ao_app->get_image_suffix(
- ao_app->get_character_path(p_char, p_image)), // Character folder
- ao_app->get_image_suffix(ao_app->get_base_path() + "misc/" +
- p_custom_theme + "/" + p_image), // Misc path
- ao_app->get_image_suffix(ao_app->get_custom_theme_path(
- p_custom_theme, p_image)), // Custom theme path
- ao_app->get_image_suffix(ao_app->get_theme_path(p_image)), // Theme path
- ao_app->get_image_suffix(
- ao_app->get_default_theme_path(p_image)), // Default theme path
- ao_app->get_image_suffix(
- ao_app->get_theme_path("placeholder")), // Placeholder path
- ao_app->get_image_suffix(ao_app->get_default_theme_path(
- "placeholder")), // Default placeholder path
- };
-
- for (QString path : pathlist) {
- if (file_exists(path)) {
- shout_path = path;
- break;
- }
- }
- }
-
- m_movie->setFileName(shout_path);
-
- if (m_movie->loopCount() == 0)
- play_once = true;
-
- this->show();
- m_movie->start();
- if (m_movie->frameCount() == 0 && duration > 0)
- timer->start(duration);
-}
-
-void AOMovie::stop()
-{
- m_movie->stop();
- this->hide();
-}
-
-void AOMovie::frame_change(int n_frame)
-{
- // If it's a "static movie" (only one frame - png image), we can't change
- // frames - ignore this function (use timer instead). If the frame didn't reach
- // the last frame or the movie is continuous, don't stop the movie.
- if (m_movie->frameCount() == 0 || n_frame < (m_movie->frameCount() - 1) ||
- !play_once)
- return;
- // we need this or else the last frame wont show
- timer->start(m_movie->nextFrameDelay());
-}
-
-void AOMovie::timer_done()
-{
- this->stop();
- // signal connected to courtroom object, let it figure out what to do
- done();
-}
-
-void AOMovie::combo_resize(int w, int h)
-{
- QSize f_size(w, h);
- this->resize(f_size);
- m_movie->setScaledSize(f_size);
-}
diff --git a/src/aoscene.cpp b/src/aoscene.cpp
deleted file mode 100644
index 78d69acd..00000000
--- a/src/aoscene.cpp
+++ /dev/null
@@ -1,132 +0,0 @@
-#include "aoscene.h"
-#include "courtroom.h"
-#include "file_functions.h"
-
-AOScene::AOScene(QWidget *parent, AOApplication *p_ao_app) : QLabel(parent)
-{
- m_parent = parent;
- ao_app = p_ao_app;
- m_movie = new QMovie(this);
- m_movie->setCacheMode(QMovie::CacheAll);
- last_image = "";
-}
-
-void AOScene::set_image(QString p_image)
-{
- QString background_path =
- ao_app->get_image_suffix(ao_app->get_background_path(p_image));
- if (!file_exists(background_path)) // If image is missing, clear current image
- {
- this->clear();
- this->setMovie(nullptr);
-
- m_movie->stop();
- last_image = "";
- return;
- }
-
- if (!file_exists(background_path) || background_path != last_image)
- {
- this->clear();
- this->setMovie(nullptr);
-
- m_movie->stop();
- m_movie->setFileName(background_path);
- }
-
- if (m_movie->isValid() && m_movie->frameCount() > 1) {
- m_movie->jumpToNextFrame();
- float scale_factor = static_cast<float>(f_h) /
- static_cast<float>(m_movie->frameRect().height());
- // preserve aspect ratio
- int n_w = static_cast<int>(m_movie->frameRect().width() * scale_factor);
- int n_h = static_cast<int>(m_movie->frameRect().height() * scale_factor);
-
- m_movie->setScaledSize(QSize(n_w, n_h));
- this->resize(m_movie->scaledSize());
- if (!file_exists(background_path) || background_path != last_image)
- {
- this->setMovie(m_movie);
- m_movie->start();
- }
- QLabel::move(x + (f_w - n_w) / 2, y + (f_h - n_h) / 2); // Center
- }
- else {
- QPixmap background(background_path);
- auto transform_mode = Qt::FastTransformation;
- if (background.height() > f_h) // We are downscaling, use anti-aliasing.
- transform_mode = Qt::SmoothTransformation;
-
- background = background.scaledToHeight(f_h, transform_mode);
- this->resize(background.size());
- this->setPixmap(background);
- QLabel::move(
- x + (f_w - background.width()) / 2,
- y + (f_h - background.height()) /
- 2); // Always center horizontally, always center vertically
- }
- last_image = background_path;
-}
-
-void AOScene::set_legacy_desk(QString p_image)
-{
-
- QString desk_path =
- ao_app->get_image_suffix(ao_app->get_background_path(p_image));
- if (!file_exists(desk_path)) // If image is missing, clear current image
- {
- this->clear();
- this->setMovie(nullptr);
-
- m_movie->stop();
- last_image = "";
- return;
- }
-
- if (file_exists(desk_path) && desk_path == last_image)
- return;
-
- QPixmap f_desk(desk_path);
-
- // vanilla desks vary in both width and height. in order to make that work
- // with viewport rescaling, some INTENSE math is needed.
- int vp_width = m_parent->width();
- int vp_height = m_parent->height();
-
- double h_modifier = vp_height / 192;
-
- int final_h = static_cast<int>(h_modifier * f_desk.height());
-
- this->clear();
- this->setMovie(nullptr);
-
- m_movie->stop();
- m_movie->setFileName(desk_path);
-
- m_movie->setScaledSize(QSize(vp_width, final_h));
-
- if (m_movie->isValid() && m_movie->frameCount() > 1) {
- this->setMovie(m_movie);
- m_movie->start();
- }
- else {
- this->resize(vp_width, final_h);
- this->setPixmap(f_desk.scaled(vp_width, final_h));
- }
- last_image = desk_path;
-}
-
-void AOScene::combo_resize(int w, int h)
-{
- QSize f_size(w, h);
- f_w = w;
- f_h = h;
- this->resize(f_size);
-}
-
-void AOScene::move(int ax, int ay)
-{
- x = ax;
- y = ay;
- QLabel::move(x, y);
-}
diff --git a/src/courtroom.cpp b/src/courtroom.cpp
index 20216716..8f5ee4b6 100644
--- a/src/courtroom.cpp
+++ b/src/courtroom.cpp
@@ -43,21 +43,22 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow()
ui_background = new AOImage(this, ao_app);
ui_viewport = new QWidget(this);
- ui_vp_background = new AOScene(ui_viewport, ao_app);
- ui_vp_speedlines = new AOMovie(ui_viewport, ao_app);
- ui_vp_speedlines->set_play_once(false);
- ui_vp_player_char = new AOCharMovie(ui_viewport, ao_app);
- ui_vp_sideplayer_char = new AOCharMovie(ui_viewport, ao_app);
+ ui_vp_background = new BackgroundLayer(ui_viewport, ao_app);
+ ui_vp_speedlines = new ForegroundLayer(ui_viewport, ao_app);
+ ui_vp_player_char = new CharLayer(ui_viewport, ao_app);
+ ui_vp_sideplayer_char = new CharLayer(ui_viewport, ao_app);
ui_vp_sideplayer_char->hide();
- ui_vp_desk = new AOScene(ui_viewport, ao_app);
- ui_vp_legacy_desk = new AOScene(ui_viewport, ao_app);
+ ui_vp_desk = new BackgroundLayer(ui_viewport, ao_app);
+
+ ui_vp_effect = new EffectLayer(this, ao_app);
+ ui_vp_effect->setAttribute(Qt::WA_TransparentForMouseEvents);
ui_vp_evidence_display = new AOEvidenceDisplay(ui_viewport, ao_app);
ui_vp_chatbox = new AOImage(this, ao_app);
ui_vp_showname = new QLabel(ui_vp_chatbox);
ui_vp_showname->setAlignment(Qt::AlignLeft);
- ui_vp_chat_arrow = new AOMovie(ui_vp_chatbox, ao_app);
+ ui_vp_chat_arrow = new InterfaceLayer(this, ao_app);
ui_vp_chat_arrow->set_play_once(false);
ui_vp_message = new QTextEdit(this);
@@ -66,14 +67,13 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow()
ui_vp_message->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
ui_vp_message->setReadOnly(true);
- ui_vp_testimony = new AOMovie(this, ao_app);
+ ui_vp_testimony = new InterfaceLayer(this, ao_app);
ui_vp_testimony->set_play_once(false);
ui_vp_testimony->setAttribute(Qt::WA_TransparentForMouseEvents);
- ui_vp_effect = new AOMovie(this, ao_app);
- ui_vp_effect->setAttribute(Qt::WA_TransparentForMouseEvents);
- ui_vp_wtce = new AOMovie(this, ao_app);
+ ui_vp_wtce = new InterjectionLayer(this, ao_app);
+ ui_vp_wtce->set_play_once(true);
ui_vp_wtce->setAttribute(Qt::WA_TransparentForMouseEvents);
- ui_vp_objection = new AOMovie(this, ao_app);
+ ui_vp_objection = new InterjectionLayer(this, ao_app);
ui_vp_objection->setAttribute(Qt::WA_TransparentForMouseEvents);
ui_ic_chatlog = new QTextEdit(this);
@@ -113,7 +113,7 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow()
ui_music_list->setUniformRowHeights(true);
- ui_music_display = new AOMovie(this, ao_app);
+ ui_music_display = new InterfaceLayer(this, ao_app);
ui_music_display->set_play_once(false);
ui_music_display->setAttribute(Qt::WA_TransparentForMouseEvents);
@@ -271,6 +271,8 @@ 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_effect, SIGNAL(done()), this, SLOT(effect_done()));
+ connect(ui_vp_wtce, SIGNAL(done()), this, SLOT(effect_done()));
connect(ui_vp_player_char, SIGNAL(done()), this, SLOT(preanim_done()));
connect(ui_vp_player_char, SIGNAL(shake()), this, SLOT(do_screenshake()));
connect(ui_vp_player_char, SIGNAL(flash()), this, SLOT(do_flash()));
@@ -532,13 +534,8 @@ void Courtroom::set_widgets()
ui_vp_desk->move(0, 0);
ui_vp_desk->combo_resize(ui_viewport->width(), ui_viewport->height());
- // the size of the ui_vp_legacy_desk element relies on various factors and is
- // set in set_scene()
-
double y_modifier = 147.0 / 192.0;
int final_y = static_cast<int>(y_modifier * ui_viewport->height());
- ui_vp_legacy_desk->move(0, final_y);
- ui_vp_legacy_desk->hide();
ui_vp_evidence_display->move(0, 0);
ui_vp_evidence_display->combo_resize(ui_viewport->width(),
@@ -553,11 +550,14 @@ void Courtroom::set_widgets()
ui_vp_chat_arrow->hide();
}
else {
- ui_vp_chat_arrow->move(design_ini_result.x, design_ini_result.y);
- ui_vp_chat_arrow->combo_resize(design_ini_result.width,
- design_ini_result.height);
+ ui_vp_chat_arrow->move(design_ini_result.x + ui_vp_chatbox->x(), design_ini_result.y + ui_vp_chatbox->y());
+ ui_vp_chat_arrow->combo_resize(design_ini_result.width, design_ini_result.height);
}
+ // layering shenanigans with ui_vp_chatbox prevent us from doing the sensible
+ // thing, which is to parent these to ui_viewport. instead, AOLayer handles
+ // masking so we don't overlap parts of the UI, and they become free floating
+ // widgets.
ui_vp_testimony->move(ui_viewport->x(), ui_viewport->y());
ui_vp_testimony->combo_resize(ui_viewport->width(), ui_viewport->height());
@@ -659,18 +659,16 @@ void Courtroom::set_widgets()
ui_music_display->combo_resize(design_ini_result.width,
design_ini_result.height);
}
-
- ui_music_display->play("music_display");
- ui_music_display->set_play_once(false);
+ ui_music_display->load_image("music_display", "");
if (is_ao2_bg) {
set_size_and_pos(ui_ic_chat_message, "ao2_ic_chat_message");
- set_size_and_pos(ui_vp_chatbox, "ao2_chatbox");
+ // set_size_and_pos(ui_vp_chatbox, "ao2_chatbox");
set_size_and_pos(ui_ic_chat_name, "ao2_ic_chat_name");
}
else {
set_size_and_pos(ui_ic_chat_message, "ic_chat_message");
- set_size_and_pos(ui_vp_chatbox, "chatbox");
+ // set_size_and_pos(ui_vp_chatbox, "chatbox");
set_size_and_pos(ui_ic_chat_name, "ic_chat_name");
}
@@ -1120,6 +1118,24 @@ void Courtroom::set_size_and_pos(QWidget *p_widget, QString p_identifier)
}
}
+void Courtroom::set_size_and_pos(QWidget *p_widget, QString p_identifier,
+ QString p_char)
+{
+ QString filename = "courtroom_design.ini";
+
+ pos_size_type design_ini_result =
+ ao_app->get_element_dimensions(p_identifier, filename, p_char);
+
+ if (design_ini_result.width < 0 || design_ini_result.height < 0) {
+ qDebug() << "W: could not find \"" << p_identifier << "\" in " << filename;
+ p_widget->hide();
+ }
+ else {
+ p_widget->move(design_ini_result.x, design_ini_result.y);
+ p_widget->resize(design_ini_result.width, design_ini_result.height);
+ }
+}
+
void Courtroom::set_taken(int n_char, bool p_taken)
{
if (n_char >= char_list.size()) {
@@ -1219,11 +1235,11 @@ void Courtroom::set_background(QString p_background, bool display)
is_ao2_bg = true;
if (is_ao2_bg) {
- set_size_and_pos(ui_vp_chatbox, "ao2_chatbox");
+ // set_size_and_pos(ui_vp_chatbox, "ao2_chatbox");
set_size_and_pos(ui_ic_chat_message, "ao2_ic_chat_message");
}
else {
- set_size_and_pos(ui_vp_chatbox, "chatbox");
+ // set_size_and_pos(ui_vp_chatbox, "chatbox");
set_size_and_pos(ui_ic_chat_message, "ic_chat_message");
}
@@ -1403,6 +1419,12 @@ void Courtroom::update_character(int p_cid)
}
}
}
+ if (is_ao2_bg) {
+ set_size_and_pos(ui_vp_chatbox, "ao2_chatbox", f_char);
+ }
+ else {
+ set_size_and_pos(ui_vp_chatbox, "chatbox", f_char);
+ }
if (m_cid != -1) // there is no name at char_list -1, and we crash if we try
// to find one
@@ -1838,7 +1860,8 @@ void Courtroom::on_chat_return_pressed()
packet_contents.append(ui_additive->isChecked() ? "1" : "0");
}
if (ao_app->effects_enabled) {
- QString fx_sound = ao_app->get_effect_sound(effect, current_char);
+ QString fx_sound =
+ ao_app->get_effect_property(effect, current_char, "sound");
QString p_effect =
ao_app->read_char_ini(current_char, "effects", "Options");
packet_contents.append(effect + "|" + p_effect + "|" + fx_sound);
@@ -1919,12 +1942,9 @@ void Courtroom::chatmessage_enqueue(QStringList p_contents)
}
// 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());
- }
-
+ // If desynced logs are on, display the log IC immediately.
+ LogMode log_mode = ao_app->is_desyncrhonized_logs_enabled() ? DISPLAY_AND_IO : IO_ONLY;
+ log_chatmessage(p_contents[MESSAGE], f_char_id, p_contents[SHOWNAME], p_contents[TEXT_COLOR].toInt(), log_mode);
// Send this boi into the queue
chatmessage_queue.enqueue(p_contents);
@@ -1939,11 +1959,12 @@ void Courtroom::chatmessage_enqueue(QStringList p_contents)
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);
+ QString f_custom_theme;
+ if (ao_app->is_customchat_enabled()) {
+ QString f_char = m_chatmessage[CHAR_NAME];
+ f_custom_theme = ao_app->get_chat(f_char);
+ }
+ ui_vp_chat_arrow->load_image("chat_arrow", f_custom_theme);
// Nothing to parse in the queue
if (chatmessage_queue.isEmpty())
@@ -1975,7 +1996,7 @@ void Courtroom::unpack_chatmessage(QStringList p_contents)
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());
+ log_chatmessage(m_chatmessage[MESSAGE], m_chatmessage[CHAR_ID].toInt(), m_chatmessage[SHOWNAME], m_chatmessage[TEXT_COLOR].toInt(), DISPLAY_ONLY);
}
// Process the callwords for this message
@@ -1994,7 +2015,7 @@ void Courtroom::unpack_chatmessage(QStringList p_contents)
handle_ic_message();
}
-void Courtroom::log_chatmessage(QString f_message, int f_char_id, QString f_showname, int f_color)
+void Courtroom::log_chatmessage(QString f_message, int f_char_id, QString f_showname, int f_color, LogMode f_log_mode)
{
// Display name will use the showname
QString f_displayname = f_showname;
@@ -2058,7 +2079,17 @@ void Courtroom::log_chatmessage(QString f_message, int f_char_id, QString f_show
}
break;
}
- log_ic_text(f_char, f_displayname, shout_message, tr("shouts"));
+ switch (f_log_mode) {
+ case IO_ONLY:
+ log_ic_text(f_char, f_displayname, shout_message, tr("shouts"));
+ break;
+ case DISPLAY_AND_IO:
+ log_ic_text(f_char, f_displayname, shout_message, tr("shouts"));
+ [[fallthrough]];
+ case DISPLAY_ONLY:
+ append_ic_text(shout_message, f_displayname, tr("shouts"));
+ break;
+ }
}
// Obtain evidence ID we're trying to work with
@@ -2067,107 +2098,35 @@ void Courtroom::log_chatmessage(QString f_message, int f_char_id, QString f_show
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 our current message is a blankpost, the chat log isn't empty, the chat log's last message is a blank post, and the blankpost's showname is the same as ours
- if (f_message.isEmpty() && !ic_chatlog_history.isEmpty() && ic_chatlog_history.last().get_message().isEmpty() && ic_chatlog_history.last().get_showname() == f_displayname)
- return; // Skip adding message
-
- // Add the message to the logs file
- log_ic_text(f_showname, f_displayname, f_message, "",
- f_color);
-}
-
-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;
+ switch (f_log_mode) {
+ case IO_ONLY:
+ log_ic_text(f_showname, f_displayname, f_evi_name, tr("has presented evidence"));
+ break;
+ case DISPLAY_AND_IO:
+ log_ic_text(f_showname, f_displayname, f_evi_name, tr("has presented evidence"));
+ [[fallthrough]];
+ case DISPLAY_ONLY:
+ append_ic_text(f_evi_name, f_displayname, tr("has presented evidence"));
+ break;
+ }
}
}
- // 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!");
+ // 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() != "") {
+ switch (f_log_mode) {
+ case IO_ONLY:
+ log_ic_text(f_showname, f_displayname, f_message, "",f_color);
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!");
+ case DISPLAY_AND_IO:
+ log_ic_text(f_showname, f_displayname, f_message, "",f_color);
+ [[fallthrough]];
+ case DISPLAY_ONLY:
+ append_ic_text(f_message, f_displayname, "",f_color);
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 our current message is a blankpost, the chat log isn't empty, the chat log's last message is a blank post, and the blankpost's showname is the same as ours
- if (f_message.isEmpty() && last_ic_message == f_displayname + ":")
- return; // Skip adding message
-
- last_ic_message = f_displayname + ":" + f_message;
- // Append the message to the IC chatlogs in client
- append_ic_text(f_message, f_displayname, "",
- f_color);
}
bool Courtroom::handle_objection()
@@ -2184,64 +2143,75 @@ bool Courtroom::handle_objection()
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 (is_ao2_bg) {
+ set_size_and_pos(ui_vp_chatbox, "ao2_chatbox", m_chatmessage[CHAR_NAME]);
+ }
+ else {
+ set_size_and_pos(ui_vp_chatbox, "chatbox", m_chatmessage[CHAR_NAME]);
+ }
+ set_size_and_pos(ui_vp_showname, "showname", m_chatmessage[CHAR_NAME]);
+ set_size_and_pos(ui_vp_message, "message", m_chatmessage[CHAR_NAME]);
+ ui_vp_message->move(ui_vp_message->x() + ui_vp_chatbox->x(),
+ ui_vp_message->y() + ui_vp_chatbox->y());
+ ui_vp_message->setTextInteractionFlags(Qt::NoTextInteraction);
// if an objection is used
if (objection_mod <= 4 && objection_mod >= 1) {
- QString shout_message;
+ ui_vp_objection->set_static_duration(shout_static_time);
+ ui_vp_objection->set_max_duration(shout_max_time);
+ QString filename;
switch (objection_mod) {
case 1:
- ui_vp_objection->play("holdit_bubble", f_char, f_custom_theme, 724);
- objection_player->play("holdit", f_char, f_custom_theme);
- shout_message = ao_app->read_char_ini(f_char, "holdit_message", "Shouts");
- if (shout_message == "")
- shout_message = tr("HOLD IT!");
+ filename = "holdit_bubble";
+ objection_player->play("holdit", m_chatmessage[CHAR_NAME],
+ ao_app->get_char_shouts(m_chatmessage[CHAR_NAME]));
break;
case 2:
- ui_vp_objection->play("objection_bubble", f_char, f_custom_theme, 724);
- objection_player->play("objection", f_char, f_custom_theme);
- shout_message = ao_app->read_char_ini(f_char, "objection_message", "Shouts");
- if (shout_message == "")
- shout_message = tr("OBJECTION!");
+ filename = "objection_bubble";
+ objection_player->play("objection", m_chatmessage[CHAR_NAME],
+ ao_app->get_char_shouts(m_chatmessage[CHAR_NAME]));
if (ao_app->objection_stop_music())
music_player->stop();
break;
case 3:
- ui_vp_objection->play("takethat_bubble", f_char, f_custom_theme, 724);
- objection_player->play("takethat", f_char, f_custom_theme);
- shout_message = ao_app->read_char_ini(f_char, "takethat_message", "Shouts");
- if (shout_message == "")
- shout_message = tr("TAKE THAT!");
+ filename = "takethat_bubble";
+ objection_player->play("takethat", m_chatmessage[CHAR_NAME],
+ ao_app->get_char_shouts(m_chatmessage[CHAR_NAME]));
break;
// case 4 is AO2 only
case 4:
if (custom_objection != "") {
- ui_vp_objection->play("custom_objections/" + custom_objection, f_char,
- f_custom_theme, shout_stay_time);
- objection_player->play("custom_objections/" +
- custom_objection.split('.')[0],
- f_char, f_custom_theme);
- shout_message = ao_app->read_char_ini(f_char, custom_objection.split('.')[0] + "_message", "Shouts");
- if (shout_message == "")
- shout_message = custom_objection.split('.')[0];
+ filename = "custom_objections/" + custom_objection;
+ objection_player->play(
+ "custom_objections/" + custom_objection.split('.')[0],
+ m_chatmessage[CHAR_NAME],
+ ao_app->get_char_shouts(m_chatmessage[CHAR_NAME]));
}
else {
- ui_vp_objection->play("custom", f_char, f_custom_theme,
- shout_stay_time);
- objection_player->play("custom", f_char, f_custom_theme);
- shout_message = ao_app->read_char_ini(f_char, "custom_message", "Shouts");
- if (shout_message == "")
- shout_message = tr("CUSTOM OBJECTION!");
+ filename = "custom";
+ objection_player->play(
+ "custom", m_chatmessage[CHAR_NAME],
+ ao_app->get_char_shouts(m_chatmessage[CHAR_NAME]));
}
- break;
+ break;
+ m_chatmessage[EMOTE_MOD] = 1;
}
+ ui_vp_objection->load_image(
+ filename, m_chatmessage[CHAR_NAME],
+ ao_app->get_char_shouts(m_chatmessage[CHAR_NAME]));
sfx_player->clear(); // Objection played! Cut all sfx.
return true;
}
+ display_character();
return false;
}
+void Courtroom::effect_done()
+{
+ ui_vp_effect->stop();
+ ui_vp_wtce->stop();
+}
+
void Courtroom::display_character()
{
// Stop all previously playing animations, effects etc.
@@ -2333,26 +2303,6 @@ void Courtroom::display_pair_character(QString other_charid, QString other_offse
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?
- {
- // 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);
@@ -2360,10 +2310,11 @@ void Courtroom::display_pair_character(QString other_charid, QString other_offse
ui_vp_sideplayer_char->set_flipped(false);
// Play the other pair character's idle animation
- ui_vp_sideplayer_char->play_idle(m_chatmessage[OTHER_NAME],
- m_chatmessage[OTHER_EMOTE]);
+ QString filename = "(a)" + m_chatmessage[OTHER_EMOTE];
+ ui_vp_sideplayer_char->load_image(filename, m_chatmessage[OTHER_NAME],
+ 0, false);
+ }
}
- }
}
void Courtroom::handle_emote_mod(int emote_mod, bool p_immediate)
@@ -2494,7 +2445,11 @@ void Courtroom::do_flash()
QString f_char = m_chatmessage[CHAR_NAME];
QString f_custom_theme = ao_app->get_char_shouts(f_char);
- ui_vp_effect->play("realizationflash", f_char, f_custom_theme, 60);
+ ui_vp_effect->stretch = true;
+ ui_vp_effect->set_static_duration(60);
+ ui_vp_effect->set_max_duration(60);
+ ui_vp_effect->load_image(
+ ao_app->get_effect("realization", f_char, f_custom_theme), false);
}
void Courtroom::do_effect(QString fx_name, QString fx_sound, QString p_char,
@@ -2511,12 +2466,17 @@ void Courtroom::do_effect(QString fx_name, QString fx_sound, QString p_char,
// Only check if effects are disabled after playing the sound if it exists
if (!ao_app->is_effects_enabled())
return;
-
+ ui_vp_effect->transform_mode = ao_app->get_scaling(
+ ao_app->get_effect_property(fx_name, p_char, "scaling"));
+ ui_vp_effect->stretch =
+ ao_app->get_effect_property(fx_name, p_char, "stretch")
+ .startsWith("true");
ui_vp_effect->set_play_once(
false); // The effects themselves dictate whether or not they're looping.
// Static effects will linger.
- ui_vp_effect->play(effect); // It will set_play_once to true if the filepath
- // provided is not designed to loop more than once
+ ui_vp_effect->set_static_duration(0);
+ ui_vp_effect->set_max_duration(0);
+ ui_vp_effect->load_image(effect, false);
}
void Courtroom::play_char_sfx(QString sfx_name)
@@ -2530,7 +2490,7 @@ void Courtroom::initialize_chatbox()
if (f_charid >= 0 && f_charid < char_list.size() &&
(m_chatmessage[SHOWNAME].isEmpty() || !ui_showname_enable->isChecked())) {
QString real_name = char_list.at(f_charid).name;
-
+ ui_vp_player_char->set_static_duration(0);
QString f_showname = ao_app->get_showname(real_name);
ui_vp_showname->setText(f_showname);
@@ -2562,23 +2522,28 @@ void Courtroom::initialize_chatbox()
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");
+ chatbox_path = ao_app->get_theme_path("misc/" + chatbox + "/chat");
+ if (!ui_vp_chatbox->set_chatbox(chatbox_path)) {
+ chatbox_path = ao_app->get_base_path() + "misc/" + chatbox + "/chat";
+ if (!ui_vp_chatbox->set_chatbox(chatbox_path))
+ ui_vp_chatbox->set_chatbox(chatbox_path + "box");
+ }
}
// 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);
+ if (current_misc != last_misc) {
+ 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 + ui_vp_chatbox->x(), design_ini_result.y + ui_vp_chatbox->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(
@@ -2686,39 +2651,41 @@ void Courtroom::handle_ic_speaking()
if (emote_mod == 5 || emote_mod == 6) {
// Hide the desks
ui_vp_desk->hide();
- ui_vp_legacy_desk->hide();
// Obtain character information for our character
- QString f_char = m_chatmessage[CHAR_NAME];
- QString f_custom_theme = ao_app->get_char_shouts(f_char);
+ QString filename;
// 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);
+ filename = "prosecution_speedlines";
else
- ui_vp_speedlines->play("defense_speedlines", f_char, f_custom_theme);
+ filename = "defense_speedlines";
+ ui_vp_speedlines->load_image(filename, m_chatmessage[CHAR_NAME]);
}
// Check if this is a talking color (white text, etc.)
color_is_talking =
color_markdown_talking_list.at(m_chatmessage[TEXT_COLOR].toInt());
-
+ QString filename;
// If color is talking, and our state isn't already talking
if (color_is_talking && text_state == 1 &&
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]);
+ ui_vp_player_char->set_play_once(false);
+ filename = "(b)" + m_chatmessage[EMOTE];
+ ui_vp_player_char->load_image(filename, m_chatmessage[CHAR_NAME], 0, false);
// Set the anim state accordingly
anim_state = 2;
}
- else if (anim_state < 3)
+ else if (anim_state < 3 &&
+ anim_state != 3) // Set it to idle as we're not on that already
{
// 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]);
+ ui_vp_player_char->set_play_once(false);
+ filename = "(a)" + m_chatmessage[EMOTE];
+ ui_vp_player_char->load_image(filename, m_chatmessage[CHAR_NAME], 0, false);
// Set the anim state accordingly
anim_state = 3;
}
@@ -3117,7 +3084,6 @@ void Courtroom::play_preanim(bool immediate)
{
QString f_char = m_chatmessage[CHAR_NAME];
QString f_preanim = m_chatmessage[PRE_EMOTE];
-
// all time values in char.inis are multiplied by a constant(time_mod) to get
// the actual time
int ao2_duration = ao_app->get_ao2_preanim_duration(f_char, f_preanim);
@@ -3143,8 +3109,9 @@ void Courtroom::play_preanim(bool immediate)
qDebug() << "W: could not find " + anim_to_find;
return;
}
-
- ui_vp_player_char->play_pre(f_char, f_preanim, preanim_duration);
+ ui_vp_player_char->set_static_duration(preanim_duration);
+ ui_vp_player_char->set_play_once(true);
+ ui_vp_player_char->load_image(f_preanim, f_char, preanim_duration, true);
if (immediate)
anim_state = 4;
@@ -3161,6 +3128,7 @@ void Courtroom::play_preanim(bool immediate)
void Courtroom::preanim_done()
{
anim_state = 1;
+ qDebug() << "preanim over, anim_state set to 1";
handle_ic_speaking();
}
@@ -3232,6 +3200,8 @@ void Courtroom::start_chat_ticking()
// means text is currently ticking
text_state = 1;
+
+ c_played = false;
}
void Courtroom::chat_tick()
@@ -3243,13 +3213,30 @@ void Courtroom::chat_tick()
// Due to our new text speed system, we always need to stop the timer now.
chat_tick_timer->stop();
+ ui_vp_player_char->set_static_duration(0);
+ QString filename;
if (tick_pos >= f_message.size()) {
text_state = 2;
if (anim_state < 3) {
- anim_state = 3;
- ui_vp_player_char->play_idle(m_chatmessage[CHAR_NAME],
- m_chatmessage[EMOTE]);
+ QStringList c_paths = {
+ ao_app->get_image_suffix(ao_app->get_character_path(m_chatmessage[CHAR_NAME], "(c)" + m_chatmessage[EMOTE])),
+ ao_app->get_image_suffix(ao_app->get_character_path(m_chatmessage[CHAR_NAME], "(c)/" + m_chatmessage[EMOTE]))
+ };
+ // if there is a (c) animation for this emote and we haven't played it already
+ if (file_exists(ui_vp_player_char->find_image(c_paths)) &&(!c_played)) {
+ anim_state = 5;
+ ui_vp_player_char->set_play_once(true);
+ filename = "(c)" + m_chatmessage[EMOTE];
+ c_played = true;
+ }
+ else {
+ anim_state = 3;
+ ui_vp_player_char->set_play_once(false);
+ filename = "(a)" + m_chatmessage[EMOTE];
+ }
+ ui_vp_player_char->load_image(filename, m_chatmessage[CHAR_NAME], 0,
+ false);
}
QString f_char;
QString f_custom_theme;
@@ -3257,7 +3244,11 @@ void Courtroom::chat_tick()
f_char = m_chatmessage[CHAR_NAME];
f_custom_theme = ao_app->get_chat(f_char);
}
- QString f_message_filtered = filter_ic_text(f_message, true, -1, m_chatmessage[TEXT_COLOR].toInt());
+ ui_vp_chat_arrow->load_image("chat_arrow",f_custom_theme); // Chat stopped being processed, indicate that.
+ additive_previous =
+ additive_previous +
+ filter_ic_text(f_message, true, -1, m_chatmessage[TEXT_COLOR].toInt());
+ 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));
}
@@ -3453,16 +3444,20 @@ void Courtroom::chat_tick()
// to avoid interrupting a non-interrupted preanim)
{
ui_vp_player_char->stop();
- ui_vp_player_char->play_talking(m_chatmessage[CHAR_NAME],
- m_chatmessage[EMOTE]);
+ ui_vp_player_char->set_play_once(false);
+ filename = "(b)" + m_chatmessage[EMOTE];
+ ui_vp_player_char->load_image(filename, m_chatmessage[CHAR_NAME], 0,
+ false);
anim_state = 2;
}
else if (!color_is_talking && anim_state < 3 &&
anim_state != 3) // Set it to idle as we're not on that already
{
ui_vp_player_char->stop();
- ui_vp_player_char->play_idle(m_chatmessage[CHAR_NAME],
- m_chatmessage[EMOTE]);
+ ui_vp_player_char->set_play_once(false);
+ filename = "(a)" + m_chatmessage[EMOTE];
+ ui_vp_player_char->load_image(filename, m_chatmessage[CHAR_NAME], 0,
+ false);
anim_state = 3;
}
// Continue ticking
@@ -3547,19 +3542,15 @@ void Courtroom::set_scene(QString f_desk_mod, QString f_side)
f_background = f_side;
f_desk_image = f_side + "_overlay";
}
-
- ui_vp_background->set_image(f_background);
- ui_vp_desk->set_image(f_desk_image);
- ui_vp_legacy_desk->set_legacy_desk(f_desk_image);
+ ui_vp_background->load_image(f_background);
+ ui_vp_desk->load_image(f_desk_image);
if (f_desk_mod == "0" ||
(f_desk_mod != "1" &&
(f_side == "jud" || f_side == "hld" || f_side == "hlp"))) {
ui_vp_desk->hide();
- ui_vp_legacy_desk->hide();
}
else {
- ui_vp_legacy_desk->hide();
ui_vp_desk->show();
}
}
@@ -3707,31 +3698,40 @@ void Courtroom::handle_song(QStringList *p_contents)
void Courtroom::handle_wtce(QString p_wtce, int variant)
{
QString sfx_file = "courtroom_sounds.ini";
-
+ QString sfx_name;
+ QString filename;
+ ui_vp_wtce->set_static_duration(wtce_static_time);
+ ui_vp_wtce->set_max_duration(wtce_max_time);
// witness testimony
if (p_wtce == "testimony1") {
- sfx_player->play(ao_app->get_sfx("witness_testimony"));
- ui_vp_wtce->play("witnesstestimony", "", "", 1500);
- ui_vp_testimony->play("testimony");
+ sfx_name = "witness_testimony";
+ filename = "witnesstestimony";
+ ui_vp_testimony->load_image("testimony", "");
}
// cross examination
else if (p_wtce == "testimony2") {
- sfx_player->play(ao_app->get_sfx("cross_examination"));
- ui_vp_wtce->play("crossexamination", "", "", 1500);
+ sfx_name = "cross_examination";
+ filename = "crossexamination";
ui_vp_testimony->stop();
}
else if (p_wtce == "judgeruling") {
+ ui_vp_wtce->set_static_duration(verdict_static_time);
+ ui_vp_wtce->set_max_duration(verdict_max_time);
if (variant == 0) {
- sfx_player->play(ao_app->get_sfx("not_guilty"));
- ui_vp_wtce->play("notguilty", "", "", 3000);
+ sfx_name = "not_guilty";
+ filename = "notguilty";
ui_vp_testimony->stop();
}
else if (variant == 1) {
- sfx_player->play(ao_app->get_sfx("guilty"));
- ui_vp_wtce->play("guilty", "", "", 3000);
+ sfx_name = "guilty";
+ filename = "guilty";
ui_vp_testimony->stop();
}
}
+ QString bg_misc = ao_app->read_design_ini("misc", ao_app->get_background_path("design.ini"));
+ sfx_player->play(ao_app->get_sfx(sfx_name, bg_misc));
+ ui_vp_wtce->load_image(filename, "", bg_misc);
+ ui_vp_wtce->set_play_once(true);
}
void Courtroom::set_hp_bar(int p_bar, int p_state)
@@ -4954,18 +4954,18 @@ void Courtroom::set_text_color_dropdown()
QColor color =
ao_app->get_chat_color("c" + QString::number(c), current_char);
color_rgb_list.append(color);
- color_markdown_start_list.append(ao_app->get_chat_markdown(
+ color_markdown_start_list.append(ao_app->get_chat_markup(
"c" + QString::number(c) + "_start", current_char));
- color_markdown_end_list.append(ao_app->get_chat_markdown(
+ color_markdown_end_list.append(ao_app->get_chat_markup(
"c" + QString::number(c) + "_end", current_char));
color_markdown_remove_list.append(
- ao_app->get_chat_markdown("c" + QString::number(c) + "_remove",
- current_char) == "1");
+ ao_app->get_chat_markup("c" + QString::number(c) + "_remove",
+ current_char) == "1");
color_markdown_talking_list.append(
- ao_app->get_chat_markdown("c" + QString::number(c) + "_talking",
- current_char) != "0");
+ ao_app->get_chat_markup("c" + QString::number(c) + "_talking",
+ current_char) != "0");
- QString color_name = ao_app->get_chat_markdown(
+ QString color_name = ao_app->get_chat_markup(
"c" + QString::number(c) + "_name", current_char);
if (color_name.isEmpty()) // Not defined
{
diff --git a/src/path_functions.cpp b/src/path_functions.cpp
index c6c73a8b..728f5a40 100644
--- a/src/path_functions.cpp
+++ b/src/path_functions.cpp
@@ -65,6 +65,16 @@ QString AOApplication::get_character_path(QString p_char, QString p_file)
return get_case_sensitive_path(path);
}
+QString AOApplication::get_misc_path(QString p_misc, QString p_file)
+{
+ QString path = get_base_path() + "misc/" + p_misc + "/" + p_file;
+#ifndef CASE_SENSITIVE_FILESYSTEM
+ return path;
+#else
+ return get_case_sensitive_path(path);
+#endif
+}
+
QString AOApplication::get_sounds_path(QString p_file)
{
QString path = get_base_path() + "sounds/general/" + p_file;
diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp
index 43a72ecc..0128f565 100644
--- a/src/text_file_functions.cpp
+++ b/src/text_file_functions.cpp
@@ -67,8 +67,7 @@ bool AOApplication::get_log_goes_downwards()
bool AOApplication::get_log_newline()
{
- QString result =
- configini->value("log_newline", "false").value<QString>();
+ QString result = configini->value("log_newline", "false").value<QString>();
return result.startsWith("true");
}
@@ -80,8 +79,7 @@ int AOApplication::get_log_margin()
bool AOApplication::get_log_timestamp()
{
- QString result =
- configini->value("log_timestamp", "false").value<QString>();
+ QString result = configini->value("log_timestamp", "false").value<QString>();
return result.startsWith("true");
}
@@ -282,6 +280,13 @@ QString AOApplication::read_design_ini(QString p_identifier,
}
}
+Qt::TransformationMode AOApplication::get_scaling(QString p_scaling)
+{
+ if (p_scaling == "smooth")
+ return Qt::SmoothTransformation;
+ return Qt::FastTransformation;
+}
+
QPoint AOApplication::get_button_spacing(QString p_identifier, QString p_file)
{
QString design_ini_path = get_theme_path(p_file);
@@ -315,28 +320,12 @@ pos_size_type AOApplication::get_element_dimensions(QString p_identifier,
QString p_file,
QString p_char)
{
- QString char_ini_path =
- get_base_path() + "misc/" + get_chat(p_char) + "/" + p_file;
- QString design_ini_path = get_theme_path(p_file);
- QString default_path = get_default_theme_path(p_file);
- QString f_result = read_design_ini(p_identifier, char_ini_path);
-
pos_size_type return_value;
-
return_value.x = 0;
return_value.y = 0;
return_value.width = -1;
return_value.height = -1;
-
- if (f_result == "") {
- f_result = read_design_ini(p_identifier, design_ini_path);
- if (f_result == "") {
- f_result = read_design_ini(p_identifier, default_path);
-
- if (f_result == "")
- return return_value;
- }
- }
+ QString f_result = get_design_element(p_identifier, p_file, p_char);
QStringList sub_line_elements = f_result.split(",");
@@ -353,17 +342,16 @@ pos_size_type AOApplication::get_element_dimensions(QString p_identifier,
QString AOApplication::get_design_element(QString p_identifier, QString p_file,
QString p_char)
{
- QString char_ini_path =
- get_base_path() + "misc/" + get_chat(p_char) + "/" + p_file;
- QString design_ini_path = get_theme_path(p_file);
- QString default_path = get_default_theme_path(p_file);
- QString f_result = read_design_ini(p_identifier, char_ini_path);
- if (f_result == "") {
- f_result = read_design_ini(p_identifier, design_ini_path);
- if (f_result == "")
- f_result = read_design_ini(p_identifier, default_path);
+ QStringList paths{get_theme_path("misc/" + get_chat(p_char) + "/" +
+ p_file), // user theme overrides base/misc
+ get_base_path() + "misc/" + get_chat(p_char) + "/" + p_file,
+ get_theme_path(p_file), get_default_theme_path(p_file)};
+ for (const QString &path : paths) {
+ QString value = read_design_ini(p_identifier, path);
+ if (!value.isEmpty())
+ return value;
}
- return f_result;
+ return "";
}
QString AOApplication::get_font_name(QString p_identifier, QString p_file)
{
@@ -483,34 +471,30 @@ QString AOApplication::get_tagged_stylesheet(QString target_tag, QString p_file)
return f_text;
}
-QString AOApplication::get_chat_markdown(QString p_identifier, QString p_chat)
+QString AOApplication::get_chat_markup(QString p_identifier, QString p_chat)
{
- QString design_ini_path =
- get_base_path() + "misc/" + get_chat(p_chat) + "/config.ini";
- QString default_path = get_base_path() + "misc/default/config.ini";
- QString f_result = read_design_ini(p_identifier, design_ini_path);
+ QStringList paths{get_theme_path("misc/" + get_chat(p_chat) + "/config.ini"),
+ get_base_path() + "misc/" + get_chat(p_chat) +
+ "/config.ini",
+ get_base_path() + "misc/default/config.ini",
+ get_theme_path("misc/default/config.ini")};
- if (f_result == "")
- f_result = read_design_ini(p_identifier, default_path);
+ for (const QString &path : paths) {
+ QString value = read_design_ini(p_identifier, path);
+ if (!value.isEmpty()) {
+ return value.toLatin1();
+ }
+ }
- return f_result.toLatin1();
+ return "";
}
QColor AOApplication::get_chat_color(QString p_identifier, QString p_chat)
{
QColor return_color(255, 255, 255);
-
- QString design_ini_path =
- get_base_path() + "misc/" + get_chat(p_chat) + "/config.ini";
- QString default_path = get_base_path() + "misc/default/config.ini";
- QString f_result = read_design_ini(p_identifier, design_ini_path);
-
- if (f_result == "") {
- f_result = read_design_ini(p_identifier, default_path);
-
- if (f_result == "")
- return return_color;
- }
+ QString f_result = get_chat_markup(p_identifier, p_chat);
+ if (f_result == "")
+ return return_color;
QStringList color_list = f_result.split(",");
@@ -524,23 +508,21 @@ QColor AOApplication::get_chat_color(QString p_identifier, QString p_chat)
return return_color;
}
-QString AOApplication::get_sfx(QString p_identifier)
+QString AOApplication::get_sfx(QString p_identifier, QString p_misc)
{
- QString design_ini_path = get_theme_path("courtroom_sounds.ini");
- QString default_path = get_default_theme_path("courtroom_sounds.ini");
- QString f_result = read_design_ini(p_identifier, design_ini_path);
+ QStringList paths{get_theme_path("misc/" + p_misc + "/courtroom_sounds.ini"),
+ get_misc_path(p_misc, "courtroom_sounds.ini"),
+ get_theme_path("courtroom_sounds.ini"),
+ get_default_theme_path("courtroom_sounds.ini")};
QString return_sfx = "";
- if (f_result == "") {
- f_result = read_design_ini(p_identifier, default_path);
-
- if (f_result == "")
- return return_sfx;
+ for (const QString &path : paths) {
+ QString value = read_design_ini(p_identifier, path);
+ if (!value.isEmpty()) {
+ return value.toLatin1();
+ }
}
-
- return_sfx = f_result;
-
return return_sfx;
}
@@ -667,6 +649,31 @@ QString AOApplication::get_blips(QString p_char)
return f_result;
}
+QString AOApplication::get_emote_property(QString p_char, QString p_emote,
+ QString p_property)
+{
+ QString f_result =
+ read_char_ini(p_char, p_emote, p_property); // per-emote override
+ if (f_result == "")
+ f_result = read_char_ini(p_char, p_property,
+ "Options"); // global for this character
+ return f_result;
+}
+
+Qt::TransformationMode AOApplication::get_misc_scaling(QString p_miscname)
+{
+ if (p_miscname != "") {
+ QString misc_transform_mode = read_design_ini(
+ "scaling", get_theme_path("misc/" + p_miscname + "/config.ini"));
+ if (misc_transform_mode == "")
+ misc_transform_mode =
+ read_design_ini("scaling", get_misc_path(p_miscname, "config.ini"));
+ if (misc_transform_mode == "smooth")
+ return Qt::SmoothTransformation;
+ }
+ return Qt::FastTransformation;
+}
+
QString AOApplication::get_category(QString p_char)
{
QString f_result = read_char_ini(p_char, "category", "Options");
@@ -904,7 +911,7 @@ QStringList AOApplication::get_theme_effects()
QStringList lines = read_file(p_path).split("\n");
foreach (QString effect, lines) {
- effect = effect.split("=")[0].trimmed();
+ effect = effect.split("=")[0].trimmed().split("_")[0];
if (!effect.isEmpty() && !effects.contains(effect))
effects.append(effect);
}
@@ -922,7 +929,7 @@ QStringList AOApplication::get_effects(QString p_char)
QStringList lines = read_file(p_path).split("\n");
foreach (QString effect, lines) {
- effect = effect.split("=")[0].trimmed();
+ effect = effect.split("=")[0].trimmed().split("_")[0];
if (!effect.isEmpty() && !effects.contains(effect))
effects.append(effect);
}
@@ -957,25 +964,33 @@ QString AOApplication::get_effect(QString effect, QString p_char,
return p_path;
}
-QString AOApplication::get_effect_sound(QString fx_name, QString p_char)
+QString AOApplication::get_effect_property(QString fx_name, QString p_char,
+ QString p_property)
{
+ QString f_property;
+ if (p_property == "sound")
+ f_property = fx_name;
+ else
+ f_property = fx_name + "_" + p_property;
QString p_effect = read_char_ini(p_char, "effects", "Options");
QString p_path = get_base_path() + "misc/" + p_effect + "/effects.ini";
QString design_ini_path = get_theme_path("effects/effects.ini");
QString default_path = get_default_theme_path("effects/effects.ini");
- QString f_result = read_design_ini(fx_name, p_path);
+ QString f_result = read_design_ini(f_property, p_path);
if (f_result == "") {
- f_result = read_design_ini(fx_name, design_ini_path);
+ f_result = read_design_ini(f_property, design_ini_path);
if (f_result == "") {
- f_result = read_design_ini(fx_name, default_path);
+ f_result = read_design_ini(f_property, default_path);
}
}
- if (fx_name == "realization") {
+ if (fx_name == "realization" && p_property == "sound") {
f_result = get_custom_realization(p_char);
}
+ qDebug() << "got" << f_property << "of" << fx_name << "==" << f_result;
+
return f_result;
}