1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
|
#pragma once
#include <QBitmap>
#include <QDebug>
#include <QElapsedTimer>
#include <QImageReader>
#include <QLabel>
#include <QMutex>
#include <QPropertyAnimation>
#include <QTimer>
#include <QWaitCondition>
#include <QtConcurrent/QtConcurrentRun>
class AOApplication;
class VPath;
// "Brief" explanation of what the hell this is:
//
// AOLayer handles all animations both inside and outside
// the viewport. It was originally devised as a layering
// system, but turned into a full refactor of the existing
// animation code.
//
// AOLayer has six subclasses, all of which differ mainly in
// how they handle path resolution.
//
// - BackgroundLayer: self-explanatory, handles files found in base/background
// - CharLayer: handles all the "wonderful" quirks of character path resolution
// - SplashLayer: handles elements that can either be provided by a misc/ directory
// or by the theme - speedlines, shouts, WT/CE, et cetera
// - EffectLayer: this is basically a dummy layer since effects do their own wonky
// path resolution in a different file
// - InterfaceLayer: handles UI elements like the chat arrow and the music display
// - StickerLayer: Crystalwarrior really wanted this. Handles "stickers," whatever those are.
//
// For questions comments or concerns, bother someone else
class AOLayer : public QLabel
{
Q_OBJECT
public:
AOLayer(AOApplication *p_ao_app, QWidget *p_parent = nullptr);
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
// Are we loading this from the same frame we left off on?
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;
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?
bool masked = true; // Set a mask to the dimensions of the widget?
// 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();
// Stop the movie and clear all vectors
void kill();
// Set the m_flipped variable to true/false
void set_flipped(bool p_flipped) { m_flipped = p_flipped; }
// Move the label itself around
void move(int ax, int ay);
// Move the label and center it
void move_and_center(int ax, int ay);
// Returns the factor by which the image is scaled
float get_scaling_factor();
// 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);
/**
* @brief Returns the x offset to use to ensure proper centering in the
* viewport. This is used by courtroom transition code to know exactly where
* to put the characters at the start and end of the animation.
* @return The offset to center the pixmap in the viewport
*/
int get_centered_offset();
// 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(QStringList p_list);
QPropertyAnimation *slide(int newcenter, int duration);
// Start playback of the movie (if animated).
void play();
// Freeze the movie at the current frame.
void freeze();
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;
// 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;
float scaling_factor = 0.0;
int frame = 0;
int max_frames = 0;
int last_max_frames = 0;
int speed = 100;
bool m_flipped = false;
int duration = 0;
// 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);
// If set to anything other than -1, overrides center_pixmap to use it as a
// pixel position to center at. Currently only used by background layers
int g_center = -1;
int last_center = -1; // g_center from the last image.
int centered_offset = 0;
// Center the QLabel in the viewport based on the dimensions of f_pixmap
void center_pixmap(QPixmap f_pixmap);
/*!
@brief Get the position to move us to, given the pixel X position of the
point in the original image that we'd like to be centered.
@return The position to move to.
*/
int get_pos_from_center(int f_center);
private:
// Populates the frame and delay vectors.
void populate_vectors();
// used in populate_vectors
void load_next_frame();
std::atomic_bool exit_loop{false}; // awful solution but i'm not fucking using QThread
QFuture<void> frame_loader;
QMutex mutex;
QWaitCondition frameAdded;
Q_SIGNALS:
void done();
protected Q_SLOTS:
virtual void preanim_done();
void shfx_timer_done();
virtual void movie_ticker();
};
class BackgroundLayer : public AOLayer
{
Q_OBJECT
public:
BackgroundLayer(AOApplication *p_ao_app, QWidget *p_parent);
void load_image(QString p_filename, int center = -1);
};
class CharLayer : public AOLayer
{
Q_OBJECT
public:
CharLayer(AOApplication *p_ao_app, QWidget *p_parent = nullptr);
QStringList &network_strings2() { return m_network_strings; }
void set_network_string(QStringList list) { m_network_strings = list; }
void load_image(QString p_filename, QString p_charname, int p_duration, bool p_is_preanim);
void play(); // overloaded so we can play effects
private:
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
QStringList m_network_strings;
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 Q_SLOTS:
void preanim_done() override; // overridden so we don't accidentally cull characters
void movie_ticker() override; // overridden so we can play effects
Q_SIGNALS:
void shake();
void flash();
void play_sfx(QString sfx);
};
class SplashLayer : public AOLayer
{
Q_OBJECT
public:
SplashLayer(AOApplication *p_ao_app, QWidget *p_parent = nullptr);
void load_image(QString p_filename, QString p_charname, QString p_miscname);
};
class EffectLayer : public AOLayer
{
Q_OBJECT
public:
EffectLayer(AOApplication *p_ao_app, QWidget *p_parent = nullptr);
void load_image(QString p_filename, bool p_looping);
};
class InterfaceLayer : public AOLayer
{
Q_OBJECT
public:
InterfaceLayer(AOApplication *p_ao_app, QWidget *p_parent = nullptr);
void load_image(QString p_filename, QString p_miscname);
};
class StickerLayer : public AOLayer
{
Q_OBJECT
public:
StickerLayer(AOApplication *p_ao_app, QWidget *p_parent = nullptr);
void load_image(QString p_charname);
};
|