Consolidate AOScene, AOMovie, and AOCharMovie into one class, add support for (c) animations, implement emote continuity, add scaling overrides to all layer types, allow for stretch-to-fill images, allow for additional effect configuration (#302)
* Rewrite AOScene and remove the need for AOMovie and AOCharMovie by consolidation * Rename AOScene to AOLayer, apply suggestions to improve functionality * Implement suggested change to allocation * Switch from pointer to field, fix ui_vp_player_char not resetting play_once * Use the variable gif_name instead of the string "gif_name" Oops. * Total rewrite of AOLayer (again) * Add support for (c) animations, do some housekeeping * allow themes to override misc chatboxes * add support for pulling InterfaceLayer elements from theme/misc * mistakes were made * move all frame fx functionality to CharLayer subclass * virtual functions are cool mkay * remove evidence of my incompetence * allow themes to override font design inis under theme/misc * Proper support for theme/misc chatbox, fixes * Fix chatbox dimensions not updating and inline color causing missingnos * rename chat markdown to chat markup * add missing misc overrides * quick hotfix for chatblank and misc overrides * Fix oversight with backgrounds causing them to be culled * Same as last commit but for FG layer * amend comment to explain impossible shenanigans * Adjust ForegroundLayer to take charname rather than miscname, allow for checking in char folder * fix an incredibly embarrassing pathing bug * add scaling overrides for all layer types, parent orphaned viewport elements to the viewport * stupid fix because themes use "custom.png" as a button * switch to .append() * Revert "Merge branch 'aoscene_rewrite' of https://github.com/AttorneyOnline/AO2-Client into aoscene_rewrite" This reverts commit bdeb1bff7639d522031aab3c133a83b0e2a291df, reversing changes made to 125ee63b97a6f6c156e69525d88fddc625e7a978. * switch to .append() (again) * move function call to fix showname length calculation error * fix nonlooping character animations being broken Again * unparent elements from the viewport and do fancy masking arithmetic instead * use override keyword * move scaling override to char.ini, allow stretching, restructure effect property loading * fix some redundancy * unparent chat_arrow from chatbox to prevent accidental masking * at no point do we want a frozen gif to display * overhaul how wtce is handled * oops * also let sounds be pulled from theme miscs * i should probably compile before i push * actually make it work * don't check a default bg * readd 1x1 stretch thing * actually the 1x1 thing was a bad idea * Add missing parenthesis * Use load_image instead of play play is a nonexistent method now * Remote shout_message and usages because it does nothing * Remove multiple redefinitions * Add in missing brackets and indent to fix build I have know idea what this does but it brings fear * fix build error * fix chat arrow and remove duped code * remove more duped code and fix misc themes * only update chat_arrow when needed * consolidate log_chatmessage and display_log_chatmessage Co-authored-by: scatterflower <marisaposs@gameboyprinter.moe> Co-authored-by: Skye Deving <76892045+skyedeving@users.noreply.github.com> Co-authored-by: oldmud0 <oldmud0@users.noreply.github.com>
This commit is contained in:
parent
21b4aa5072
commit
894b2b2a0e
@ -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.
|
||||
// ======
|
||||
|
@ -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
|
@ -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;
|
||||
|
||||
|
214
include/aolayer.h
Normal file
214
include/aolayer.h
Normal file
@ -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
|
@ -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
|
@ -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
|
@ -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();
|
||||
|
@ -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();
|
||||
}
|
@ -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()
|
||||
|
577
src/aolayer.cpp
Normal file
577
src/aolayer.cpp
Normal file
@ -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();
|
||||
}
|
100
src/aomovie.cpp
100
src/aomovie.cpp
@ -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);
|
||||
}
|
132
src/aoscene.cpp
132
src/aoscene.cpp
@ -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);
|
||||
}
|
@ -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,95 +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"));
|
||||
}
|
||||
|
||||
// Obtain evidence ID we're trying to work with
|
||||
int f_evi_id = m_chatmessage[EVIDENCE_ID].toInt();
|
||||
// If the evidence ID is in the valid range
|
||||
if (f_evi_id > 0 && f_evi_id <= local_evidence_list.size()) {
|
||||
// Obtain the evidence name
|
||||
QString f_evi_name = local_evidence_list.at(f_evi_id - 1).name;
|
||||
// Add the message to the logs file
|
||||
log_ic_text(f_showname, f_displayname, f_evi_name,
|
||||
tr("has presented evidence"));
|
||||
}
|
||||
}
|
||||
|
||||
// If 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;
|
||||
}
|
||||
}
|
||||
// If display name is just whitespace, use the char.ini showname.
|
||||
if (f_displayname.trimmed().isEmpty())
|
||||
f_displayname = f_showname;
|
||||
|
||||
if (log_ic_actions) {
|
||||
// Check if a custom objection is in use
|
||||
int objection_mod = 0;
|
||||
QString custom_objection = "";
|
||||
if (m_chatmessage[OBJECTION_MOD].contains("4&")) {
|
||||
objection_mod = 4;
|
||||
custom_objection = m_chatmessage[OBJECTION_MOD].split(
|
||||
"4&")[1]; // takes the name of custom objection.
|
||||
}
|
||||
else {
|
||||
objection_mod = m_chatmessage[OBJECTION_MOD].toInt();
|
||||
}
|
||||
|
||||
QString f_char = m_chatmessage[CHAR_NAME];
|
||||
QString f_custom_theme = ao_app->get_char_shouts(f_char);
|
||||
if (objection_mod <= 4 && objection_mod >= 1) {
|
||||
QString shout_message;
|
||||
switch (objection_mod) {
|
||||
case 1:
|
||||
shout_message = ao_app->read_char_ini(f_char, "holdit_message", "Shouts");
|
||||
if (shout_message == "")
|
||||
shout_message = tr("HOLD IT!");
|
||||
break;
|
||||
case 2:
|
||||
shout_message = ao_app->read_char_ini(f_char, "objection_message", "Shouts");
|
||||
if (shout_message == "")
|
||||
shout_message = tr("OBJECTION!");
|
||||
break;
|
||||
case 3:
|
||||
shout_message = ao_app->read_char_ini(f_char, "takethat_message", "Shouts");
|
||||
if (shout_message == "")
|
||||
shout_message = tr("TAKE THAT!");
|
||||
break;
|
||||
// case 4 is AO2 only
|
||||
case 4:
|
||||
if (custom_objection != "") {
|
||||
shout_message = ao_app->read_char_ini(f_char, custom_objection.split('.')[0] + "_message", "Shouts");
|
||||
if (shout_message == "")
|
||||
shout_message = custom_objection.split('.')[0];
|
||||
}
|
||||
else {
|
||||
shout_message = ao_app->read_char_ini(f_char, "custom_message", "Shouts");
|
||||
if (shout_message == "")
|
||||
shout_message = tr("CUSTOM OBJECTION!");
|
||||
}
|
||||
break;
|
||||
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;
|
||||
}
|
||||
append_ic_text(shout_message, f_displayname, tr("shouts"));
|
||||
}
|
||||
|
||||
// Obtain evidence ID we're trying to work with
|
||||
@ -2155,19 +2098,35 @@ void Courtroom::display_log_chatmessage(QString f_message, int f_char_id, QStrin
|
||||
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"));
|
||||
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 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);
|
||||
// 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 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user