Merge branch 'master' into feature/timerclock
# Conflicts: # include/courtroom.h
This commit is contained in:
commit
1b016ddf91
@ -1,8 +1,11 @@
|
||||
#ifndef AOAPPLICATION_H
|
||||
#define AOAPPLICATION_H
|
||||
|
||||
#define UNUSED(x) (void)(x)
|
||||
|
||||
#include "aopacket.h"
|
||||
#include "datatypes.h"
|
||||
#include "demoserver.h"
|
||||
#include "discord_rich_presence.h"
|
||||
|
||||
#include "bass.h"
|
||||
@ -28,6 +31,8 @@
|
||||
#include <QTextStream>
|
||||
#include <QTime>
|
||||
|
||||
#include <QElapsedTimer>
|
||||
|
||||
class NetworkManager;
|
||||
class Lobby;
|
||||
class Courtroom;
|
||||
@ -129,6 +134,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);
|
||||
@ -223,6 +229,9 @@ public:
|
||||
// Current wait time between messages for the queue system
|
||||
int stay_time();
|
||||
|
||||
// Returns Minimum amount of time (in miliseconds) that must pass before the next Enter key press will send your IC message. (new behaviour)
|
||||
int get_chat_ratelimit();
|
||||
|
||||
// Returns whether the log should go upwards (new behaviour)
|
||||
// or downwards (vanilla behaviour).
|
||||
bool get_log_goes_downwards();
|
||||
@ -265,6 +274,9 @@ public:
|
||||
// directory if it doesn't exist.
|
||||
bool append_to_file(QString p_text, QString p_file, bool make_dir = false);
|
||||
|
||||
// Append to the currently open demo file if there is one
|
||||
void append_to_demofile(QString packet_string);
|
||||
|
||||
// Appends the argument string to serverlist.txt
|
||||
void write_to_serverlist_txt(QString p_line);
|
||||
|
||||
@ -294,14 +306,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);
|
||||
@ -337,6 +349,9 @@ public:
|
||||
// Returns the showname from the ini of p_char
|
||||
QString get_showname(QString p_char);
|
||||
|
||||
// Returns the category of this character
|
||||
QString get_category(QString p_char);
|
||||
|
||||
// Returns the value of chat image from the specific p_char's ini file
|
||||
QString get_chat(QString p_char);
|
||||
|
||||
@ -370,9 +385,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);
|
||||
@ -422,6 +437,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.
|
||||
// ======
|
||||
@ -462,6 +486,9 @@ public:
|
||||
void *user);
|
||||
static void doBASSreset();
|
||||
|
||||
QElapsedTimer demo_timer;
|
||||
DemoServer* demo_server = nullptr;
|
||||
|
||||
private:
|
||||
const int RELEASE = 2;
|
||||
const int MAJOR_VERSION = 8;
|
||||
|
@ -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;
|
||||
|
||||
|
221
include/aolayer.h
Normal file
221
include/aolayer.h
Normal file
@ -0,0 +1,221 @@
|
||||
#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);
|
||||
};
|
||||
|
||||
class StickerLayer : public AOLayer {
|
||||
Q_OBJECT
|
||||
public:
|
||||
StickerLayer(QWidget *p_parent, AOApplication *p_ao_app);
|
||||
void load_image(QString p_charname);
|
||||
};
|
||||
#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
|
@ -58,6 +58,8 @@ private:
|
||||
QCheckBox *ui_desync_logs_cb;
|
||||
QLabel *ui_instant_objection_lbl;
|
||||
QCheckBox *ui_instant_objection_cb;
|
||||
QLabel *ui_chat_ratelimit_lbl;
|
||||
QSpinBox *ui_chat_ratelimit_spinbox;
|
||||
QLabel *ui_log_ic_actions_lbl;
|
||||
QCheckBox *ui_log_ic_actions_cb;
|
||||
QFrame *ui_log_names_divider;
|
||||
|
@ -12,7 +12,7 @@ public:
|
||||
|
||||
QString get_header() { return m_header; }
|
||||
QStringList &get_contents() { return m_contents; }
|
||||
QString to_string();
|
||||
QString to_string(bool encoded = false);
|
||||
|
||||
void net_encode();
|
||||
void net_decode();
|
||||
|
@ -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,18 +5,16 @@
|
||||
#include "aoblipplayer.h"
|
||||
#include "aobutton.h"
|
||||
#include "aocharbutton.h"
|
||||
#include "aocharmovie.h"
|
||||
#include "aoclocklabel.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"
|
||||
@ -152,6 +150,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);
|
||||
|
||||
@ -225,11 +226,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();
|
||||
@ -265,7 +268,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
|
||||
@ -357,6 +361,7 @@ private:
|
||||
QVector<QString> arup_locks;
|
||||
|
||||
QVector<chatlogpiece> ic_chatlog_history;
|
||||
QString last_ic_message = "";
|
||||
|
||||
QQueue<QStringList> chatmessage_queue;
|
||||
|
||||
@ -392,7 +397,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.
|
||||
@ -420,16 +426,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 = ".,?!:;";
|
||||
@ -453,7 +464,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
|
||||
@ -516,8 +527,15 @@ private:
|
||||
// List of all currently available pos
|
||||
QStringList pos_dropdown_list;
|
||||
|
||||
// Current list file sorted line by line
|
||||
QStringList sound_list;
|
||||
|
||||
// Current SFX the user put in for the sfx dropdown list
|
||||
QString custom_sfx = "";
|
||||
|
||||
// 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;
|
||||
@ -585,21 +603,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;
|
||||
|
||||
@ -611,7 +628,9 @@ private:
|
||||
QTreeWidget *ui_music_list;
|
||||
|
||||
ScrollText *ui_music_name;
|
||||
AOMovie *ui_music_display;
|
||||
InterfaceLayer *ui_music_display;
|
||||
|
||||
StickerLayer *ui_vp_sticker;
|
||||
|
||||
static const int max_clocks = 5;
|
||||
AOClockLabel *ui_clock[max_clocks];
|
||||
@ -724,6 +743,9 @@ private:
|
||||
|
||||
AOImage *ui_char_select_background;
|
||||
|
||||
// pretty list of characters
|
||||
QTreeWidget *ui_char_list;
|
||||
|
||||
// abstract widget to hold char buttons
|
||||
QWidget *ui_char_buttons;
|
||||
|
||||
@ -765,6 +787,7 @@ private:
|
||||
void regenerate_ic_chatlog();
|
||||
public slots:
|
||||
void objection_done();
|
||||
void effect_done();
|
||||
void preanim_done();
|
||||
void do_screenshake();
|
||||
void do_flash();
|
||||
@ -820,6 +843,7 @@ private slots:
|
||||
void on_iniswap_remove_clicked();
|
||||
|
||||
void on_sfx_dropdown_changed(int p_index);
|
||||
void on_sfx_dropdown_custom(QString p_sfx);
|
||||
void set_sfx_dropdown();
|
||||
void on_sfx_context_menu_requested(const QPoint &pos);
|
||||
void on_sfx_edit_requested();
|
||||
@ -916,6 +940,7 @@ private slots:
|
||||
|
||||
void on_back_to_lobby_clicked();
|
||||
|
||||
void on_char_list_double_clicked(QTreeWidgetItem *p_item, int column);
|
||||
void on_char_select_left_clicked();
|
||||
void on_char_select_right_clicked();
|
||||
void on_char_search_changed();
|
||||
|
55
include/demoserver.h
Normal file
55
include/demoserver.h
Normal file
@ -0,0 +1,55 @@
|
||||
#ifndef DEMOSERVER_H
|
||||
#define DEMOSERVER_H
|
||||
|
||||
#include "aopacket.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QObject>
|
||||
#include <QQueue>
|
||||
#include <QTcpServer>
|
||||
#include <QTcpSocket>
|
||||
#include <QTimer>
|
||||
#include <QFileDialog>
|
||||
|
||||
class DemoServer : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit DemoServer(QObject *parent = nullptr);
|
||||
|
||||
bool server_started = false;
|
||||
int port = 27088;
|
||||
int max_wait = -1;
|
||||
int min_wait = -1;
|
||||
|
||||
private:
|
||||
void handle_packet(AOPacket packet);
|
||||
void load_demo(QString filename);
|
||||
|
||||
QTcpServer* tcp_server;
|
||||
QTcpSocket* client_sock = nullptr;
|
||||
bool client_connected = false;
|
||||
bool partial_packet = false;
|
||||
QString temp_packet = "";
|
||||
QQueue<QString> demo_data;
|
||||
QString sc_packet;
|
||||
int num_chars = 0;
|
||||
QString p_path;
|
||||
QTimer *timer;
|
||||
int elapsed_time = 0;
|
||||
|
||||
private slots:
|
||||
void accept_connection();
|
||||
void destroy_connection();
|
||||
void recv_data();
|
||||
void client_disconnect();
|
||||
void playback();
|
||||
|
||||
public slots:
|
||||
void start_server();
|
||||
|
||||
signals:
|
||||
|
||||
};
|
||||
|
||||
#endif // DEMOSERVER_H
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -45,6 +45,10 @@ void AOApplication::construct_lobby()
|
||||
if (is_discord_enabled())
|
||||
discord->state_lobby();
|
||||
|
||||
if (demo_server)
|
||||
demo_server->deleteLater();
|
||||
demo_server = new DemoServer();
|
||||
|
||||
w_lobby->show();
|
||||
}
|
||||
|
||||
@ -182,6 +186,10 @@ void AOApplication::call_announce_menu(Courtroom *court)
|
||||
void CALLBACK AOApplication::BASSreset(HSTREAM handle, DWORD channel,
|
||||
DWORD data, void *user)
|
||||
{
|
||||
UNUSED(handle);
|
||||
UNUSED(channel);
|
||||
UNUSED(data);
|
||||
UNUSED(user);
|
||||
doBASSreset();
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
|
601
src/aolayer.cpp
Normal file
601
src/aolayer.cpp
Normal file
@ -0,0 +1,601 @@
|
||||
#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)
|
||||
{
|
||||
}
|
||||
|
||||
StickerLayer::StickerLayer(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 StickerLayer::load_image(QString p_charname)
|
||||
{
|
||||
QString miscname = ao_app->get_char_shouts(p_charname);
|
||||
transform_mode = ao_app->get_misc_scaling(miscname);
|
||||
QList<QString> pathlist = {
|
||||
ao_app->get_image_suffix(ao_app->get_base_path() + "misc/" +
|
||||
miscname + "/sticker/" + p_charname), // Misc path
|
||||
ao_app->get_image_suffix(ao_app->get_custom_theme_path(miscname, "sticker/" + p_charname)), // Custom theme path
|
||||
ao_app->get_image_suffix(ao_app->get_theme_path("sticker/" + p_charname)), // Theme path
|
||||
ao_app->get_image_suffix(
|
||||
ao_app->get_default_theme_path("sticker/" + p_charname)), // Default theme path
|
||||
ao_app->get_image_suffix(
|
||||
ao_app->get_character_path(p_charname, "sticker")), // Character folder
|
||||
ao_app->get_image_suffix(
|
||||
ao_app->get_character_path(p_charname, "showname")), // Scuffed DRO way
|
||||
};
|
||||
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);
|
||||
}
|
@ -96,7 +96,7 @@ void AOMusicPlayer::play(QString p_song, int channel, bool loop,
|
||||
BASS_ChannelLock(oldstream, false);
|
||||
}
|
||||
|
||||
if (effect_flags & FADE_OUT) {
|
||||
if (effect_flags & FADE_OUT & (m_volume[channel] != 0)) {
|
||||
// Fade out the other sample and stop it (due to -1)
|
||||
BASS_ChannelSlideAttribute(oldstream, BASS_ATTRIB_VOL | BASS_SLIDE_LOG,
|
||||
-1, 4000);
|
||||
@ -116,6 +116,7 @@ void AOMusicPlayer::play(QString p_song, int channel, bool loop,
|
||||
BASS_ChannelSlideAttribute(newstream, BASS_ATTRIB_VOL,
|
||||
static_cast<float>(m_volume[channel] / 100.0f),
|
||||
1000);
|
||||
|
||||
}
|
||||
else
|
||||
this->set_volume(m_volume[channel], channel);
|
||||
@ -149,12 +150,15 @@ void AOMusicPlayer::set_volume(int p_value, int channel)
|
||||
|
||||
void CALLBACK loopProc(HSYNC handle, DWORD channel, DWORD data, void *user)
|
||||
{
|
||||
UNUSED(handle);
|
||||
UNUSED(data);
|
||||
QWORD loop_start = *(static_cast<unsigned *>(user));
|
||||
BASS_ChannelLock(channel, true);
|
||||
BASS_ChannelSetPosition(channel, loop_start, BASS_POS_BYTE);
|
||||
BASS_ChannelLock(channel, false);
|
||||
}
|
||||
|
||||
|
||||
void AOMusicPlayer::set_looping(bool toggle, int channel)
|
||||
{
|
||||
m_looping = toggle;
|
||||
|
@ -182,7 +182,7 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app)
|
||||
ui_stay_time_lbl->setText(tr("Text Stay Time:"));
|
||||
ui_stay_time_lbl->setToolTip(tr(
|
||||
"Minimum amount of time (in miliseconds) an IC message must stay on screen before "
|
||||
"the next IC message is shown, acting as a 'queue'. Set to 0 to disable this behaivor."));
|
||||
"the next IC message is shown, acting as a 'queue'. Set to 0 to disable this behavior."));
|
||||
|
||||
ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_stay_time_lbl);
|
||||
|
||||
@ -218,6 +218,19 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app)
|
||||
|
||||
ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_instant_objection_cb);
|
||||
|
||||
row += 1;
|
||||
ui_chat_ratelimit_lbl = new QLabel(ui_form_layout_widget);
|
||||
ui_chat_ratelimit_lbl->setText(tr("Chat Rate Limit:"));
|
||||
ui_chat_ratelimit_lbl->setToolTip(tr(
|
||||
"Minimum amount of time (in miliseconds) that must pass before the next Enter key press will send your IC message."));
|
||||
|
||||
ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_chat_ratelimit_lbl);
|
||||
|
||||
ui_chat_ratelimit_spinbox = new QSpinBox(ui_form_layout_widget);
|
||||
ui_chat_ratelimit_spinbox->setMaximum(5000);
|
||||
ui_chat_ratelimit_spinbox->setValue(p_ao_app->get_chat_ratelimit());
|
||||
|
||||
ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_chat_ratelimit_spinbox);
|
||||
row += 1;
|
||||
ui_log_names_divider = new QFrame(ui_form_layout_widget);
|
||||
ui_log_names_divider->setFrameShape(QFrame::HLine);
|
||||
@ -824,6 +837,7 @@ void AOOptionsDialog::save_pressed()
|
||||
configini->setValue("desync_logs", ui_desync_logs_cb->isChecked());
|
||||
configini->setValue("stay_time", ui_stay_time_spinbox->value());
|
||||
configini->setValue("instant_objection", ui_instant_objection_cb->isChecked());
|
||||
configini->setValue("chat_ratelimit", ui_chat_ratelimit_spinbox->value());
|
||||
configini->setValue("default_username", ui_username_textbox->text());
|
||||
configini->setValue("show_custom_shownames", ui_showname_cb->isChecked());
|
||||
configini->setValue("master", ui_ms_textbox->text());
|
||||
|
@ -8,9 +8,15 @@ AOPacket::AOPacket(QString p_packet_string)
|
||||
m_contents = packet_contents.mid(1, packet_contents.size()-2); // trims %
|
||||
}
|
||||
|
||||
QString AOPacket::to_string()
|
||||
QString AOPacket::to_string(bool encoded)
|
||||
{
|
||||
return m_header + "#" + m_contents.join("#") + "#%";
|
||||
QStringList contents = m_contents;
|
||||
if (encoded)
|
||||
contents.replaceInStrings("#", "<num>")
|
||||
.replaceInStrings("%", "<percent>")
|
||||
.replaceInStrings("$", "<dollar>")
|
||||
.replaceInStrings("&", "<and>");
|
||||
return m_header + "#" + contents.join("#") + "#%";
|
||||
}
|
||||
|
||||
void AOPacket::net_encode()
|
||||
|
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);
|
||||
}
|
@ -11,6 +11,16 @@ void Courtroom::construct_char_select()
|
||||
|
||||
ui_char_select_background = new AOImage(this, ao_app);
|
||||
|
||||
ui_char_list = new QTreeWidget(ui_char_select_background);
|
||||
ui_char_list->setColumnCount(2);
|
||||
ui_char_list->setHeaderLabels({"Name", "ID"});
|
||||
ui_char_list->setHeaderHidden(true);
|
||||
ui_char_list->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
|
||||
ui_char_list->hideColumn(1);
|
||||
ui_char_list->setDropIndicatorShown(true);
|
||||
set_size_and_pos(ui_char_list, "char_list");
|
||||
|
||||
|
||||
ui_char_buttons = new QWidget(ui_char_select_background);
|
||||
|
||||
ui_selector = new AOImage(ui_char_select_background, ao_app);
|
||||
@ -46,6 +56,9 @@ void Courtroom::construct_char_select()
|
||||
|
||||
set_size_and_pos(ui_char_buttons, "char_buttons");
|
||||
|
||||
connect(ui_char_list, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)),
|
||||
this, SLOT(on_char_list_double_clicked(QTreeWidgetItem *, int)));
|
||||
|
||||
connect(ui_back_to_lobby, SIGNAL(clicked()), this,
|
||||
SLOT(on_back_to_lobby_clicked()));
|
||||
|
||||
@ -126,6 +139,21 @@ void Courtroom::set_char_select_page()
|
||||
put_button_in_place(current_char_page * max_chars_on_page, chars_on_page);
|
||||
}
|
||||
|
||||
void Courtroom::on_char_list_double_clicked(QTreeWidgetItem *p_item, int column)
|
||||
{
|
||||
UNUSED(column);
|
||||
int cid = p_item->text(1).toInt();
|
||||
if (cid == -1 && !p_item->isExpanded()) {
|
||||
p_item->setExpanded(true);
|
||||
return;
|
||||
}
|
||||
else if (cid == -1) {
|
||||
p_item->setExpanded(false);
|
||||
return;
|
||||
}
|
||||
char_clicked(cid);
|
||||
}
|
||||
|
||||
void Courtroom::char_clicked(int n_char)
|
||||
{
|
||||
if (n_char != -1)
|
||||
@ -218,7 +246,32 @@ void Courtroom::character_loading_finished()
|
||||
char_button->set_image(char_list.at(n).name);
|
||||
char_button->setToolTip(char_list.at(n).name);
|
||||
ui_char_button_list.append(char_button);
|
||||
|
||||
QString char_category = ao_app->get_category(char_list.at(n).name);
|
||||
QList<QTreeWidgetItem*> matching_list = ui_char_list->findItems(char_category, Qt::MatchFixedString, 0);
|
||||
// create the character tree item
|
||||
QTreeWidgetItem *treeItem = new QTreeWidgetItem();
|
||||
treeItem->setText(0, char_list.at(n).name);
|
||||
treeItem->setIcon(0, QIcon(ao_app->get_static_image_suffix(
|
||||
ao_app->get_character_path(char_list.at(n).name, "char_icon"))));
|
||||
treeItem->setText(1, QString::number(n));
|
||||
// category logic
|
||||
QTreeWidgetItem *category;
|
||||
if (char_category == "") // no category
|
||||
ui_char_list->addTopLevelItem(treeItem);
|
||||
else if (!matching_list.isEmpty()) { // our category already exists
|
||||
category = matching_list[0];
|
||||
category->addChild(treeItem);
|
||||
}
|
||||
else { // we need to make a new category
|
||||
category = new QTreeWidgetItem();
|
||||
category->setText(0, char_category);
|
||||
category->setText(1, "-1");
|
||||
category->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicatorWhenChildless);
|
||||
ui_char_list->insertTopLevelItem(0, category);
|
||||
category->addChild(treeItem);
|
||||
}
|
||||
|
||||
|
||||
connect(char_button, &AOCharButton::clicked,
|
||||
[this, n]() { this->char_clicked(n); });
|
||||
|
||||
@ -241,7 +294,7 @@ void Courtroom::character_loading_finished()
|
||||
.arg(QString::number(ao_app->char_list_size)));
|
||||
}
|
||||
}
|
||||
|
||||
ui_char_list->expandAll();
|
||||
filter_character_list();
|
||||
}
|
||||
|
||||
@ -250,24 +303,37 @@ void Courtroom::filter_character_list()
|
||||
ui_char_button_list_filtered.clear();
|
||||
for (int i = 0; i < char_list.size(); i++) {
|
||||
AOCharButton *current_char = ui_char_button_list.at(i);
|
||||
QTreeWidgetItem* current_char_list_item = ui_char_list->findItems(QString::number(i), Qt::MatchExactly | Qt::MatchRecursive, 1)[0];
|
||||
|
||||
|
||||
|
||||
// It seems passwording characters is unimplemented yet?
|
||||
// Until then, this will stay here, I suppose.
|
||||
// if (ui_char_passworded->isChecked() && character_is_passworded??)
|
||||
// continue;
|
||||
|
||||
if (!ui_char_taken->isChecked() && char_list.at(i).taken)
|
||||
if (!ui_char_taken->isChecked() && char_list.at(i).taken) {
|
||||
current_char_list_item->setHidden(true);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!char_list.at(i).name.contains(ui_char_search->text(),
|
||||
Qt::CaseInsensitive))
|
||||
Qt::CaseInsensitive)) {
|
||||
current_char_list_item->setHidden(true);
|
||||
continue;
|
||||
}
|
||||
|
||||
// We only really need to update the fact that a character is taken
|
||||
// for the buttons that actually appear.
|
||||
// You'd also update the passwordedness and etc. here later.
|
||||
current_char->reset();
|
||||
current_char_list_item->setHidden(false);
|
||||
current_char->set_taken(char_list.at(i).taken);
|
||||
current_char_list_item->setText(0, char_list.at(i).name);
|
||||
// reset disabled
|
||||
current_char_list_item->setDisabled(false);
|
||||
if (char_list.at(i).taken) // woops, we are taken
|
||||
current_char_list_item->setDisabled(true);
|
||||
|
||||
ui_char_button_list_filtered.append(current_char);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
304
src/demoserver.cpp
Normal file
304
src/demoserver.cpp
Normal file
@ -0,0 +1,304 @@
|
||||
#include "demoserver.h"
|
||||
#include "lobby.h"
|
||||
|
||||
DemoServer::DemoServer(QObject *parent) : QObject(parent)
|
||||
{
|
||||
timer = new QTimer(this);
|
||||
timer->setTimerType(Qt::PreciseTimer);
|
||||
timer->setSingleShot(true);
|
||||
|
||||
tcp_server = new QTcpServer(this);
|
||||
connect(tcp_server, &QTcpServer::newConnection, this, &DemoServer::accept_connection);
|
||||
connect(timer, &QTimer::timeout, this, &DemoServer::playback);
|
||||
}
|
||||
|
||||
void DemoServer::start_server()
|
||||
{
|
||||
if (server_started) return;
|
||||
if (!tcp_server->listen(QHostAddress::LocalHost, 0)) {
|
||||
qCritical() << "Could not start demo playback server...";
|
||||
qDebug() << tcp_server->errorString();
|
||||
return;
|
||||
}
|
||||
this->port = tcp_server->serverPort();
|
||||
qDebug() << "Server started";
|
||||
server_started = true;
|
||||
}
|
||||
|
||||
void DemoServer::destroy_connection()
|
||||
{
|
||||
QTcpSocket* temp_socket = tcp_server->nextPendingConnection();
|
||||
connect(temp_socket, &QAbstractSocket::disconnected, temp_socket, &QObject::deleteLater);
|
||||
temp_socket->disconnectFromHost();
|
||||
return;
|
||||
}
|
||||
|
||||
void DemoServer::accept_connection()
|
||||
{
|
||||
QString path = QFileDialog::getOpenFileName(nullptr, tr("Load Demo"), "logs/", tr("Demo Files (*.demo)"));
|
||||
if (path.isEmpty())
|
||||
{
|
||||
destroy_connection();
|
||||
return;
|
||||
}
|
||||
load_demo(path);
|
||||
|
||||
if (demo_data.isEmpty())
|
||||
{
|
||||
destroy_connection();
|
||||
return;
|
||||
}
|
||||
|
||||
if (demo_data.head().startsWith("SC#"))
|
||||
{
|
||||
sc_packet = demo_data.dequeue();
|
||||
AOPacket sc(sc_packet);
|
||||
num_chars = sc.get_contents().length();
|
||||
}
|
||||
else
|
||||
{
|
||||
sc_packet = "SC#%";
|
||||
num_chars = 0;
|
||||
}
|
||||
|
||||
if (client_sock) {
|
||||
// Client is already connected...
|
||||
qDebug() << "Multiple connections to demo server disallowed.";
|
||||
QTcpSocket* temp_socket = tcp_server->nextPendingConnection();
|
||||
connect(temp_socket, &QAbstractSocket::disconnected, temp_socket, &QObject::deleteLater);
|
||||
temp_socket->disconnectFromHost();
|
||||
return;
|
||||
}
|
||||
client_sock = tcp_server->nextPendingConnection();
|
||||
connect(client_sock, &QAbstractSocket::disconnected, this, &DemoServer::client_disconnect);
|
||||
connect(client_sock, &QAbstractSocket::readyRead, this, &DemoServer::recv_data);
|
||||
client_sock->write("decryptor#NOENCRYPT#%");
|
||||
}
|
||||
|
||||
void DemoServer::recv_data()
|
||||
{
|
||||
QString in_data = QString::fromUtf8(client_sock->readAll());
|
||||
|
||||
// Copypasted from NetworkManager
|
||||
if (!in_data.endsWith("%")) {
|
||||
partial_packet = true;
|
||||
temp_packet += in_data;
|
||||
return;
|
||||
}
|
||||
|
||||
else {
|
||||
if (partial_packet) {
|
||||
in_data = temp_packet + in_data;
|
||||
temp_packet = "";
|
||||
partial_packet = false;
|
||||
}
|
||||
}
|
||||
|
||||
QStringList packet_list =
|
||||
in_data.split("%", QString::SplitBehavior(QString::SkipEmptyParts));
|
||||
|
||||
for (QString packet : packet_list) {
|
||||
AOPacket ao_packet(packet);
|
||||
handle_packet(ao_packet);
|
||||
}
|
||||
}
|
||||
|
||||
void DemoServer::handle_packet(AOPacket packet)
|
||||
{
|
||||
packet.net_decode();
|
||||
|
||||
// This code is literally a barebones AO server
|
||||
// It is wise to do it this way, because I can
|
||||
// avoid touching any of this disgusting shit
|
||||
// related to hardcoding this stuff in.
|
||||
|
||||
// Also, at some point, I will make akashit
|
||||
// into a shared library.
|
||||
|
||||
QString header = packet.get_header();
|
||||
QStringList contents = packet.get_contents();
|
||||
|
||||
if (header == "HI") {
|
||||
client_sock->write("ID#0#DEMOINTERNAL#0#%");
|
||||
}
|
||||
else if (header == "ID") {
|
||||
QStringList feature_list = {
|
||||
"noencryption", "yellowtext", "prezoom",
|
||||
"flipping", "customobjections", "fastloading",
|
||||
"deskmod", "evidence", "cccc_ic_support",
|
||||
"arup", "casing_alerts", "modcall_reason",
|
||||
"looping_sfx", "additive", "effects",
|
||||
"y_offset", "expanded_desk_mods"};
|
||||
client_sock->write("PN#0#1#%");
|
||||
client_sock->write("FL#");
|
||||
client_sock->write(feature_list.join('#').toUtf8());
|
||||
client_sock->write("#%");
|
||||
}
|
||||
else if (header == "askchaa") {
|
||||
client_sock->write("SI#");
|
||||
client_sock->write(QString::number(num_chars).toUtf8());
|
||||
client_sock->write("#0#1#%");
|
||||
}
|
||||
else if (header == "RC") {
|
||||
client_sock->write(sc_packet.toUtf8());
|
||||
}
|
||||
else if (header == "RM") {
|
||||
client_sock->write("SM#%");
|
||||
}
|
||||
else if (header == "RD") {
|
||||
client_sock->write("DONE#%");
|
||||
}
|
||||
else if (header == "CC") {
|
||||
client_sock->write("PV#0#CID#-1#%");
|
||||
client_sock->write("CT#DEMO#Demo file loaded. Send /play or > in OOC to begin playback.#1#%");
|
||||
}
|
||||
else if (header == "CT") {
|
||||
if (contents[1].startsWith("/load"))
|
||||
{
|
||||
QString path = QFileDialog::getOpenFileName(nullptr, tr("Load Demo"), "logs/", tr("Demo Files (*.demo)"));
|
||||
if (path.isEmpty())
|
||||
return;
|
||||
load_demo(path);
|
||||
client_sock->write("CT#DEMO#Demo file loaded. Send /play or > in OOC to begin playback.#1#%");
|
||||
}
|
||||
else if (contents[1].startsWith("/play") || contents[1] == ">")
|
||||
{
|
||||
if (timer->interval() != 0 && !timer->isActive())
|
||||
{
|
||||
timer->start();
|
||||
client_sock->write("CT#DEMO#Resuming playback.#1#%");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (demo_data.isEmpty() && p_path != "")
|
||||
load_demo(p_path);
|
||||
playback();
|
||||
}
|
||||
}
|
||||
else if (contents[1].startsWith("/pause") || contents[1] == "|")
|
||||
{
|
||||
int timeleft = timer->remainingTime();
|
||||
timer->stop();
|
||||
timer->setInterval(timeleft);
|
||||
client_sock->write("CT#DEMO#Pausing playback.#1#%");
|
||||
}
|
||||
else if (contents[1].startsWith("/max_wait"))
|
||||
{
|
||||
QStringList args = contents[1].split(" ");
|
||||
if (args.size() > 1)
|
||||
{
|
||||
bool ok;
|
||||
int p_max_wait = args.at(1).toInt(&ok);
|
||||
if (ok)
|
||||
{
|
||||
if (p_max_wait < 0)
|
||||
p_max_wait = -1;
|
||||
max_wait = p_max_wait;
|
||||
client_sock->write("CT#DEMO#Setting max_wait to ");
|
||||
client_sock->write(QString::number(max_wait).toUtf8());
|
||||
client_sock->write(" milliseconds.#1#%");
|
||||
}
|
||||
else
|
||||
{
|
||||
client_sock->write("CT#DEMO#Not a valid integer!#1#%");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
client_sock->write("CT#DEMO#Current max_wait is ");
|
||||
client_sock->write(QString::number(max_wait).toUtf8());
|
||||
client_sock->write(" milliseconds.#1#%");
|
||||
}
|
||||
}
|
||||
else if (contents[1].startsWith("/min_wait"))
|
||||
{
|
||||
QStringList args = contents[1].split(" ");
|
||||
if (args.size() > 1)
|
||||
{
|
||||
bool ok;
|
||||
int p_min_wait = args.at(1).toInt(&ok);
|
||||
if (ok)
|
||||
{
|
||||
if (p_min_wait < 0)
|
||||
p_min_wait = -1;
|
||||
min_wait = p_min_wait;
|
||||
client_sock->write("CT#DEMO#Setting min_wait to ");
|
||||
client_sock->write(QString::number(min_wait).toUtf8());
|
||||
client_sock->write(" milliseconds.#1#%");
|
||||
}
|
||||
else
|
||||
{
|
||||
client_sock->write("CT#DEMO#Not a valid integer!#1#%");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
client_sock->write("CT#DEMO#Current min_wait is ");
|
||||
client_sock->write(QString::number(min_wait).toUtf8());
|
||||
client_sock->write(" milliseconds.#1#%");
|
||||
}
|
||||
}
|
||||
else if (contents[1].startsWith("/help"))
|
||||
{
|
||||
client_sock->write("CT#DEMO#Available commands:\nload, play, pause, max_wait, min_wait, help#1#%");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DemoServer::load_demo(QString filename)
|
||||
{
|
||||
QFile demo_file(filename);
|
||||
demo_file.open(QIODevice::ReadOnly);
|
||||
if (!demo_file.isOpen())
|
||||
return;
|
||||
demo_data.clear();
|
||||
p_path = filename;
|
||||
QTextStream demo_stream(&demo_file);
|
||||
QString line = demo_stream.readLine();
|
||||
while (!line.isNull()) {
|
||||
if (!line.endsWith("%")) {
|
||||
line += "\n";
|
||||
}
|
||||
demo_data.enqueue(line);
|
||||
line = demo_stream.readLine();
|
||||
}
|
||||
}
|
||||
|
||||
void DemoServer::playback()
|
||||
{
|
||||
if (demo_data.isEmpty())
|
||||
return;
|
||||
|
||||
QString current_packet = demo_data.dequeue();
|
||||
// We reset the elapsed time with this packet
|
||||
if (current_packet.startsWith("MS#"))
|
||||
elapsed_time = 0;
|
||||
|
||||
while (!current_packet.startsWith("wait") && !demo_data.isEmpty()) {
|
||||
client_sock->write(current_packet.toUtf8());
|
||||
current_packet = demo_data.dequeue();
|
||||
}
|
||||
if (!demo_data.isEmpty()) {
|
||||
AOPacket wait_packet = AOPacket(current_packet);
|
||||
|
||||
int duration = wait_packet.get_contents().at(0).toInt();
|
||||
if (max_wait != -1 && duration + elapsed_time > max_wait)
|
||||
duration = qMax(0, max_wait - elapsed_time);
|
||||
// We use elapsed_time to make sure that the packet we're using min_wait on is "priority" (e.g. IC)
|
||||
if (elapsed_time == 0 && min_wait != -1 && duration < min_wait)
|
||||
duration = min_wait;
|
||||
elapsed_time += duration;
|
||||
timer->start(duration);
|
||||
}
|
||||
else
|
||||
{
|
||||
client_sock->write("CT#DEMO#Reached the end of the demo file. Send /play or > in OOC to restart, or /load to open a new file.#1#%");
|
||||
timer->setInterval(0);
|
||||
}
|
||||
}
|
||||
|
||||
void DemoServer::client_disconnect()
|
||||
{
|
||||
client_sock->deleteLater();
|
||||
client_sock = nullptr;
|
||||
}
|
@ -3,6 +3,7 @@
|
||||
#include "aoapplication.h"
|
||||
#include "aosfxplayer.h"
|
||||
#include "debug_functions.h"
|
||||
#include "demoserver.h"
|
||||
#include "networkmanager.h"
|
||||
|
||||
#include <QImageReader>
|
||||
@ -28,6 +29,7 @@ Lobby::Lobby(AOApplication *p_ao_app) : QMainWindow()
|
||||
ui_server_list = new QTreeWidget(this);
|
||||
ui_server_list->setHeaderLabels({"#", "Name"}); //, "Players"});
|
||||
ui_server_list->hideColumn(0);
|
||||
ui_server_list->setHeaderHidden(true);
|
||||
|
||||
ui_server_search = new QLineEdit(this);
|
||||
ui_server_search->setFrame(false);
|
||||
@ -438,7 +440,15 @@ void Lobby::on_server_list_clicked(QTreeWidgetItem *p_item, int column)
|
||||
|
||||
ui_connect->setEnabled(false);
|
||||
|
||||
ao_app->net_manager->connect_to_server(f_server);
|
||||
if (f_server.port == 99999 && f_server.ip == "127.0.0.1") {
|
||||
// Demo playback server selected
|
||||
ao_app->demo_server->start_server();
|
||||
server_type demo_server;
|
||||
demo_server.ip = "127.0.0.1";
|
||||
demo_server.port = ao_app->demo_server->port;
|
||||
ao_app->net_manager->connect_to_server(demo_server);
|
||||
}
|
||||
else ao_app->net_manager->connect_to_server(f_server);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -131,7 +131,7 @@ void NetworkManager::on_srv_lookup()
|
||||
qDebug() << "Connecting to " << record.target() << ":" << record.port();
|
||||
#endif
|
||||
ms_socket->connectToHost(record.target(), record.port());
|
||||
QTime timer;
|
||||
QElapsedTimer timer;
|
||||
timer.start();
|
||||
do {
|
||||
ao_app->processEvents();
|
||||
|
@ -102,6 +102,19 @@ end:
|
||||
delete p_packet;
|
||||
}
|
||||
|
||||
void AOApplication::append_to_demofile(QString packet_string)
|
||||
{
|
||||
if (get_auto_logging_enabled() && !log_filename.isEmpty())
|
||||
{
|
||||
QString path = log_filename.left(log_filename.size()).replace(".log", ".demo");
|
||||
append_to_file(packet_string, path, true);
|
||||
if (!demo_timer.isValid())
|
||||
demo_timer.start();
|
||||
else
|
||||
append_to_file("wait#"+ QString::number(demo_timer.restart()) + "#%", path, true);
|
||||
}
|
||||
}
|
||||
|
||||
void AOApplication::server_packet_received(AOPacket *p_packet)
|
||||
{
|
||||
p_packet->net_decode();
|
||||
@ -164,6 +177,8 @@ void AOApplication::server_packet_received(AOPacket *p_packet)
|
||||
else
|
||||
w_courtroom->append_server_chatmessage(f_contents.at(0),
|
||||
f_contents.at(1), "0");
|
||||
|
||||
append_to_demofile(p_packet->to_string(true));
|
||||
}
|
||||
}
|
||||
else if (header == "FL") {
|
||||
@ -232,7 +247,7 @@ void AOApplication::server_packet_received(AOPacket *p_packet)
|
||||
evidence_list_size = f_contents.at(1).toInt();
|
||||
music_list_size = f_contents.at(2).toInt();
|
||||
|
||||
if (char_list_size < 1 || evidence_list_size < 0 || music_list_size < 0)
|
||||
if (char_list_size < 0 || evidence_list_size < 0 || music_list_size < 0)
|
||||
goto end;
|
||||
|
||||
loaded_chars = 0;
|
||||
@ -255,7 +270,6 @@ void AOApplication::server_packet_received(AOPacket *p_packet)
|
||||
server_name = info.name;
|
||||
server_address =
|
||||
QString("%1:%2").arg(info.ip, QString::number(info.port));
|
||||
qDebug() << server_address;
|
||||
window_title += ": " + server_name;
|
||||
}
|
||||
}
|
||||
@ -265,7 +279,6 @@ void AOApplication::server_packet_received(AOPacket *p_packet)
|
||||
server_name = info.name;
|
||||
server_address =
|
||||
QString("%1:%2").arg(info.ip, QString::number(info.port));
|
||||
qDebug() << server_address;
|
||||
window_title += ": " + server_name;
|
||||
}
|
||||
}
|
||||
@ -283,7 +296,7 @@ void AOApplication::server_packet_received(AOPacket *p_packet)
|
||||
|
||||
// Remove any characters not accepted in folder names for the server_name
|
||||
// here
|
||||
if (AOApplication::get_auto_logging_enabled()) {
|
||||
if (AOApplication::get_auto_logging_enabled() && server_name != "Demo playback") {
|
||||
this->log_filename = QDateTime::currentDateTime().toUTC().toString(
|
||||
"'logs/" + server_name.remove(QRegExp("[\\\\/:*?\"<>|\']")) +
|
||||
"/'yyyy-MM-dd hh-mm-ss t'.log'");
|
||||
@ -292,6 +305,8 @@ void AOApplication::server_packet_received(AOPacket *p_packet)
|
||||
QDateTime::currentDateTime().toUTC().toString(),
|
||||
log_filename, true);
|
||||
}
|
||||
else
|
||||
this->log_filename = "";
|
||||
|
||||
QCryptographicHash hash(QCryptographicHash::Algorithm::Sha256);
|
||||
hash.addData(server_address.toUtf8());
|
||||
@ -312,7 +327,7 @@ void AOApplication::server_packet_received(AOPacket *p_packet)
|
||||
}
|
||||
|
||||
else if (header == "SC") {
|
||||
if (!courtroom_constructed)
|
||||
if (!courtroom_constructed || courtroom_loaded)
|
||||
goto end;
|
||||
|
||||
for (int n_element = 0; n_element < f_contents.size(); ++n_element) {
|
||||
@ -344,9 +359,10 @@ void AOApplication::server_packet_received(AOPacket *p_packet)
|
||||
}
|
||||
|
||||
send_server_packet(new AOPacket("RM#%"));
|
||||
append_to_demofile(p_packet->to_string(true));
|
||||
}
|
||||
else if (header == "SM") {
|
||||
if (!courtroom_constructed)
|
||||
if (!courtroom_constructed || courtroom_loaded)
|
||||
goto end;
|
||||
|
||||
bool musics_time = false;
|
||||
@ -445,6 +461,7 @@ void AOApplication::server_packet_received(AOPacket *p_packet)
|
||||
2) // We have a pos included in the background packet!
|
||||
w_courtroom->set_side(f_contents.at(1));
|
||||
w_courtroom->set_background(f_contents.at(0), f_contents.size() >= 2);
|
||||
append_to_demofile(p_packet->to_string(true));
|
||||
}
|
||||
}
|
||||
else if (header == "SP") {
|
||||
@ -454,6 +471,7 @@ void AOApplication::server_packet_received(AOPacket *p_packet)
|
||||
if (courtroom_constructed) // We were sent a "set position" packet
|
||||
{
|
||||
w_courtroom->set_side(f_contents.at(0));
|
||||
append_to_demofile(p_packet->to_string(true));
|
||||
}
|
||||
}
|
||||
else if (header == "SD") // Send pos dropdown
|
||||
@ -475,27 +493,37 @@ void AOApplication::server_packet_received(AOPacket *p_packet)
|
||||
}
|
||||
else if (header == "MS") {
|
||||
if (courtroom_constructed && courtroom_loaded)
|
||||
{
|
||||
w_courtroom->chatmessage_enqueue(p_packet->get_contents());
|
||||
append_to_demofile(p_packet->to_string(true));
|
||||
}
|
||||
}
|
||||
else if (header == "MC") {
|
||||
if (courtroom_constructed && courtroom_loaded)
|
||||
{
|
||||
w_courtroom->handle_song(&p_packet->get_contents());
|
||||
append_to_demofile(p_packet->to_string(true));
|
||||
}
|
||||
}
|
||||
else if (header == "RT") {
|
||||
if (f_contents.size() < 1)
|
||||
goto end;
|
||||
if (courtroom_constructed) {
|
||||
if (f_contents.size() == 1)
|
||||
w_courtroom->handle_wtce(f_contents.at(0), 0);
|
||||
else if (f_contents.size() == 2) {
|
||||
w_courtroom->handle_wtce(f_contents.at(0), f_contents.at(1).toInt());
|
||||
if (f_contents.size() == 1)
|
||||
w_courtroom->handle_wtce(f_contents.at(0), 0);
|
||||
else if (f_contents.size() == 2) {
|
||||
w_courtroom->handle_wtce(f_contents.at(0), f_contents.at(1).toInt());
|
||||
append_to_demofile(p_packet->to_string(true));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (header == "HP") {
|
||||
if (courtroom_constructed && f_contents.size() > 1)
|
||||
{
|
||||
w_courtroom->set_hp_bar(f_contents.at(0).toInt(),
|
||||
f_contents.at(1).toInt());
|
||||
append_to_demofile(p_packet->to_string(true));
|
||||
}
|
||||
}
|
||||
else if (header == "LE") {
|
||||
if (courtroom_constructed) {
|
||||
|
@ -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;
|
||||
|
@ -52,6 +52,12 @@ int AOApplication::stay_time()
|
||||
return result;
|
||||
}
|
||||
|
||||
int AOApplication::get_chat_ratelimit()
|
||||
{
|
||||
int result = configini->value("chat_ratelimit", 300).toInt();
|
||||
return result;
|
||||
}
|
||||
|
||||
bool AOApplication::get_log_goes_downwards()
|
||||
{
|
||||
QString result =
|
||||
@ -61,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");
|
||||
}
|
||||
|
||||
@ -74,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");
|
||||
}
|
||||
|
||||
@ -178,6 +182,10 @@ bool AOApplication::write_to_file(QString p_text, QString p_file, bool make_dir)
|
||||
bool AOApplication::append_to_file(QString p_text, QString p_file,
|
||||
bool make_dir)
|
||||
{
|
||||
if(!file_exists(p_file)) //Don't create a newline if file didn't exist before now
|
||||
{
|
||||
return write_to_file(p_text, p_file, make_dir);
|
||||
}
|
||||
QString path = QFileInfo(p_file).path();
|
||||
// Create the dir if it doesn't exist yet
|
||||
if (make_dir) {
|
||||
@ -249,6 +257,13 @@ QVector<server_type> AOApplication::read_serverlist_txt()
|
||||
f_server_list.append(f_server);
|
||||
}
|
||||
|
||||
server_type demo_server;
|
||||
demo_server.ip = "127.0.0.1";
|
||||
demo_server.port = 99999;
|
||||
demo_server.name = "Demo playback";
|
||||
demo_server.desc = "Play back demos you have previously recorded";
|
||||
f_server_list.append(demo_server);
|
||||
|
||||
return f_server_list;
|
||||
}
|
||||
|
||||
@ -265,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);
|
||||
@ -298,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(",");
|
||||
|
||||
@ -336,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)
|
||||
{
|
||||
@ -466,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(",");
|
||||
|
||||
@ -507,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;
|
||||
}
|
||||
|
||||
@ -650,6 +649,37 @@ 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");
|
||||
return f_result;
|
||||
}
|
||||
|
||||
QString AOApplication::get_chat(QString p_char)
|
||||
{
|
||||
if (p_char == "default")
|
||||
@ -881,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);
|
||||
}
|
||||
@ -899,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);
|
||||
}
|
||||
@ -934,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