forked from DarkArchon85/RMMZ-Plugins
-
Notifications
You must be signed in to change notification settings - Fork 0
/
LvMZ_AnimatedFaces.js
358 lines (335 loc) · 12.1 KB
/
LvMZ_AnimatedFaces.js
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
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
// ============================================================================
// LordValinar Plugin - Animated Faces
// LvMZ_AnimatedFaces.js
// ============================================================================
var Imported = Imported || {};
Imported["LvMZAnimatedFaces"] = true;
//=============================================================================
/*:
* @target MZ
* @plugindesc [v1.2] Animates face sets to appear as if speaking. Or when
* idle, it will run that animation too (blinking).
* @author LordValinar
* @url https://github.com/DarkArchon85/RMMZ-Plugins
*
* @help
* ============================================================================
* Introduction
* ============================================================================
*
* This plugin will allow you to have animated faces when using Show Text
* commands. The face must have a prefix (default: 'anim_') in order to be
* considered "animated" by the plugin. There are default settings in case
* you wish to just "plug n' play", but they can also be altered, or even
* changed via a plugin command on the fly with events!
*
* Minor setup required. You will have to setup a face set with the top
* row for "Idle" animations (typically blinking eyes), and the bottom row
* for "Speaking".
*
* ============================================================================
* Plugin Commands
* ============================================================================
*
* The plugin comes pre-packaged and ready to go; however, if at any time you
* with to alter the idle animations or maximum amount of frames for idle or
* speaking animations, then you can change them on the fly!
*
* ---
*
* Idle Delay:
* Set a minimum and maximum for the delay between idle animations. The
* actual amount is random chosen from these numbers.
*
* ---
*
* Max Frames:
* Set a maximum number of frames for the Idle and Speaking animations.
* There is technically no limit, just have the face set's width match
* the maximum possible frames (each frame = 48x48 pixels).
*
* ============================================================================
* Terms of Use
* ============================================================================
*
* Free to use and modify for commercial and noncommercial games, with credit.
* Do NOT remove my name from the Author of this plugin
* Do NOT reupload this plugin (modified or otherwise) anywhere other than the
* RPG Maker MV main forums: https://forums.rpgmakerweb.com/index.php
*
* ============================================================================
* Credits
* ============================================================================
*
* Myself (LordValinar) and Fogomax (for the original source from the
* TTKMessagePlus plugin).
*
* ============================================================================
* Changelog
* ============================================================================
*
* v1.2 - Fixed error with "this.pause" and added in battle scene animations.
* v1.1 - Added in a 'stop' to animations when "waiting" in the message.
* v1.0 - Plugin Converted from MV
*
* ============================================================================
*
* @param AnimFacePrefix
* @text Animated Faces Prefix
* @desc Prefix to determine an animated face set.
* @default anim_
*
* @param MinAnimDelay
* @text Minimum Animation Delay
* @type number
* @min 0
* @max 9999
* @desc Random delay before next animation
* @default 90
*
* @param MaxAnimDelay
* @text Maximum Animation Delay
* @type number
* @min 0
* @max 9999
* @desc Random delay before next animation
* @default 240
*
* @param MaxIdleFrames
* @text Maximum Idle Frames
* @type number
* @decimals 0
* @min 1
* @desc How many frames to run an idle face animation
* @default 2
*
* @param MaxSpeakFrames
* @text Maximum Speak Frames
* @type number
* @decimals 0
* @min 1
* @desc How many frames to run speaking face animation
* @default 3
*
* @ --------------------------------------------------------------------------
*
* @command setDelay
* @text Set Idle Delay
* @desc Choose a minimum and maximum delay for the idle
* face animation (top row of the face set).
*
* @arg minDelay
* @text Minimum Delay
* @type number
* @desc What is the minimum amount of frames to wait
* before cycling through the idle face animation?
* @default 90
*
* @arg maxDelay
* @text Maximum Delay
* @type number
* @desc What is the maximum amount of frames to wait
* before cycling through the idle face animation?
* @default 240
*
* @ --------------------------------------------------------------------------
*
* @command setFrames
* @text Set Face Frames
* @desc Choose a maximum amount of frames for the idle
* (top row) and speaking (bottom row).
*
* @arg idleFrames
* @text Idle Frames
* @type number
* @min 1
* @desc How many frames is the idle animation?
* It cycles from left to right and back again.
* @default 2
*
* @arg speakFrames
* @text Speaking Frames
* @type number
* @min 1
* @desc How many frames is the speaking animation?
* It cycles from left to right and back again.
* @default 3
*
* @ --------------------------------------------------------------------------
*
* @command reset
* @text Reset Settings
* @desc Reset delay and max frame settings.
*
*/
//=============================================================================
(() => {
'use strict';
const pluginName = 'LvMZ_AnimatedFaces';
const lvParams = PluginManager.parameters(pluginName);
const animPrefix = lvParams['AnimFacePrefix'];
const minAnimDelay = Number(lvParams['MinAnimDelay']);
const maxAnimDelay = Number(lvParams['MaxAnimDelay']);
const idleFrames = Number(lvParams['MaxIdleFrames']);
const speakFrames = Number(lvParams['MaxSpeakFrames']);
/******************************************************************************
rmmv_managers.js
/*****************************************************************************/
PluginManager.registerCommand(pluginName, 'setDelay', args => {
$gameMessage.setAnimationDelay(args.minDelay, args.maxDelay);
});
PluginManager.registerCommand(pluginName, 'setFrames', args => {
$gameMessage.setAnimationFrames(args.idleFrames, args.speakFrames);
});
PluginManager.registerCommand(pluginName, 'reset', () => {
$gameMessage.setAnimationDelay(minAnimDelay, maxAnimDelay);
$gameMessage.setAnimationFrames(idleFrames, speakFrames);
});
/******************************************************************************
rmmv_objects.js
******************************************************************************/
// --- GAME MESSAGE ---
const gameMsg_init = Game_Message.prototype.initialize;
Game_Message.prototype.initialize = function() {
gameMsg_init.call(this);
this._minAnimDelay = minAnimDelay;
this._maxAnimDelay = maxAnimDelay;
this._animIdleFrames = idleFrames - 1;
this._animSpeakFrames = speakFrames - 1;
};
Game_Message.prototype.setAnimationDelay = function(min, max) {
this._minAnimDelay = min;
this._maxAnimDelay = max;
};
Game_Message.prototype.setAnimationFrames = function(idle, speak) {
this._animIdleFrames = idle - 1;
this._animSpeakFrames = speak - 1;
}
Game_Message.prototype.animatedFace = function() {
const length = animPrefix.length;
return this._faceName.substring(0, length) === animPrefix;
};
/******************************************************************************
rmmv_scenes.js
******************************************************************************/
const sceneMap_update = Scene_Map.prototype.update;
Scene_Map.prototype.update = function() {
sceneMap_update.call(this);
if ($gameMessage.hasText() && $gameMessage.animatedFace()) {
this._messageWindow.updateFaceAnimation();
}
};
const sceneBattle_update = Scene_Battle.prototype.update;
Scene_Battle.prototype.update = function() {
sceneBattle_update.call(this);
if ($gameMessage.hasText() && $gameMessage.animatedFace()) {
this._messageWindow.updateFaceAnimation();
}
};
/******************************************************************************
rmmv_windows.js
******************************************************************************/
const windowMsg_init = Window_Message.prototype.initialize;
Window_Message.prototype.initialize = function(rect) {
windowMsg_init.call(this, rect);
this._animFaceSide = 'left';
this._afIdleY = -1;
this._afSpeakY = -1;
this._afMaxFrames = 0;
this._afSpeakFrames = 0;
this._afDelay = [0,0];
this._animFaceIndex = 0;
this._afTick = 0;
};
// New - Where the magic happens! (Credit: Fogomax for the original function I altered from)
Window_Message.prototype.updateFaceAnimation = function() {
if (this.pause || this._waitCount > 0) {
this._afTick = 0;
this._animFaceWait = 0;
this._animFaceIndex = 0;
this._animFaceSide = 'left';
this.drawMessageFace();
} else if (this._animFaceWait > 0) {
this._animFaceWait--;
} else {
this._afTick++;
if (this._afTick >= 6) {
this._afTick = 0;
if (this._animFaceSide == 'left') {
this._animFaceIndex++;
if ((this._animFaceIndex >= this._afMaxFrames && !this._textState) || (this._animFaceIndex >= this._afSpeakFrames && this._textState)) {
this._animFaceSide = 'right';
}
} else {
this._animFaceIndex--;
if (this._animFaceIndex <= 0) {
this._animFaceSide = 'left';
if (this._afDelay[1] > 0 && (this._textState == null || this._afSpeakY < 0)) {
this._animFaceWait = ~~(Math.random() * (this._afDelay[1] - this._afDelay[0] + 1) + this._afDelay[0]);
}
}
}
this.drawMessageFace();
}
}
};
// Alias - For each message, we ensure the values are updated so it is ongoing
const windowMsg_start = Window_Message.prototype.startMessage;
Window_Message.prototype.startMessage = function() {
windowMsg_start.call(this);
if ($gameMessage.animatedFace()) {
this._animFaceIndex = 0;
this._animFaceWait = 0;
this._afIdleY = 0;
this._afSpeakY = 1;
this._afDelay[0] = $gameMessage._minAnimDelay;
this._afDelay[1] = $gameMessage._maxAnimDelay;
this._afMaxFrames = $gameMessage._animIdleFrames;
this._afSpeakFrames = $gameMessage._animSpeakFrames;
}
};
// Alias - Animated faces update index by frame
const windowMsg_drawMsgFace = Window_Message.prototype.drawMessageFace;
Window_Message.prototype.drawMessageFace = function() {
if ($gameMessage.animatedFace()) {
const faceName = $gameMessage.faceName();
const faceIndex = this._animFaceIndex;
const rtl = $gameMessage.isRTL();
const width = ImageManager.faceWidth;
const height = this.innerHeight;
const x = rtl ? this.innerWidth - width - 4 : 4;
this.drawFace(faceName, faceIndex, x, 0, width, height);
} else {
windowMsg_drawMsgFace.call(this);
}
};
// Alias - Animated faces get drawn specifically
const windowBase_drawFace = Window_Base.prototype.drawFace;
Window_Base.prototype.drawFace = function(faceName, faceIndex, x, y, width, height) {
let anim = $gameMessage.animatedFace();
if (anim) {
width = width || ImageManager.faceWidth;
height = height || ImageManager.faceHeight;
const bitmap = ImageManager.loadFace(faceName);
const pw = ImageManager.faceWidth;
const ph = ImageManager.faceHeight;
const sw = Math.min(width, pw);
const sh = Math.min(height, ph);
const dx = Math.floor(x + Math.max(width - pw, 0) / 2);
const dy = Math.floor(y + Math.max(height - ph, 0) / 2);
let sx = (faceIndex % 4) * pw + (pw - sw) / 2;
let sy = Math.floor(faceIndex / 4) * ph + (ph - sh) / 2;
if (anim && this._afSpeakY >= 0 && this._textState) {
sx = faceIndex * pw;
sy = ph * this._afSpeakY;
} else if (anim && this._afIdleY >= 0 && !this._textState) {
sx = faceIndex * pw;
sy = ph * this._afIdleY;
}
this.contents.clearRect(dx, dy, pw, ph);
this.contents.blt(bitmap, sx, sy, sw, sh, dx, dy);
} else {
windowBase_drawFace.call(this, faceName, faceIndex, x, y, width, height);
}
};
})();