Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/MSZ/HeavyMystic.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: HeavyMystic Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectHeavyMystic *HeavyMystic;
11
12
void HeavyMystic_Update(void)
13
{
14
RSDK_THIS(HeavyMystic);
15
16
if (self->invincibilityTimer > 0)
17
self->invincibilityTimer--;
18
19
if (self->particleFXTimer) {
20
self->particleFXTimer--;
21
HeavyMystic_HandleParticleFX();
22
}
23
24
StateMachine_Run(self->state);
25
26
self->position.x += TornadoPath->moveVel.x;
27
self->position.y += TornadoPath->moveVel.y;
28
}
29
30
void HeavyMystic_LateUpdate(void) {}
31
32
void HeavyMystic_StaticUpdate(void)
33
{
34
foreach_active(HeavyMystic, mysticBox)
35
{
36
if (mysticBox->type == MYSTIC_BOX) {
37
RSDK.AddDrawListRef(Zone->objectDrawGroup[1], RSDK.GetEntitySlot(mysticBox));
38
}
39
}
40
}
41
42
void HeavyMystic_Draw(void)
43
{
44
RSDK_THIS(HeavyMystic);
45
46
if (self->stateDraw) {
47
StateMachine_Run(self->stateDraw);
48
}
49
else {
50
if (self->invincibilityTimer & 1)
51
RSDK.SetPaletteEntry(0, 158, 0xE0E0E0);
52
53
RSDK.DrawSprite(&self->animator, NULL, false);
54
55
RSDK.SetPaletteEntry(0, 158, 0x000000);
56
}
57
}
58
59
void HeavyMystic_Create(void *data)
60
{
61
RSDK_THIS(HeavyMystic);
62
63
if (!SceneInfo->inEditor) {
64
if (globals->gameMode < MODE_TIMEATTACK) {
65
self->updateRange.x = 0x800000;
66
self->updateRange.y = 0x800000;
67
68
if (data)
69
self->type = VOID_TO_INT(data);
70
71
switch (self->type) {
72
case MYSTIC_MISCHIEF:
73
self->active = ACTIVE_BOUNDS;
74
self->visible = false;
75
self->drawGroup = Zone->objectDrawGroup[0] + 2;
76
self->drawFX = FX_FLIP;
77
self->health = 6;
78
79
RSDK.SetSpriteAnimation(HeavyMystic->aniFrames, 0, &self->animator, true, 0);
80
81
self->state = HeavyMystic_StateMischief_Setup;
82
break;
83
84
case MYSTIC_BOSS:
85
if (globals->gameMode >= MODE_TIMEATTACK) {
86
destroyEntity(self);
87
}
88
else {
89
self->active = ACTIVE_BOUNDS;
90
self->visible = false;
91
self->drawGroup = Zone->objectDrawGroup[0] + 1;
92
self->drawFX = FX_FLIP;
93
94
self->hitbox.left = -22;
95
self->hitbox.top = -22;
96
self->hitbox.right = 22;
97
self->hitbox.bottom = 22;
98
99
self->health = 8;
100
HeavyMystic->curtainLinePos = 0xD00000;
101
102
RSDK.SetSpriteAnimation(HeavyMystic->aniFrames, 0, &self->animator, true, 0);
103
self->state = HeavyMystic_StateBoss_SetupArena;
104
}
105
break;
106
107
case MYSTIC_BOX:
108
if (globals->gameMode >= MODE_TIMEATTACK) {
109
destroyEntity(self);
110
}
111
else {
112
self->scale.x = 0x200;
113
self->scale.y = 0x200;
114
self->active = ACTIVE_BOUNDS;
115
self->visible = true;
116
self->drawGroup = Zone->objectDrawGroup[0];
117
self->targetPos = self->position;
118
self->drawFX = FX_SCALE | FX_ROTATE | FX_FLIP;
119
120
RSDK.SetSpriteAnimation(HeavyMystic->aniFrames, 10, &self->animator, true, 0);
121
self->state = HeavyMystic_StateBox_AwaitCurtainRise;
122
self->stateDraw = HeavyMystic_Draw_BoxOpened;
123
}
124
break;
125
126
case MYSTIC_CORK:
127
self->active = ACTIVE_NORMAL;
128
self->visible = true;
129
self->drawGroup = Zone->objectDrawGroup[0];
130
self->drawFX = FX_FLIP;
131
132
RSDK.SetSpriteAnimation(HeavyMystic->roguesFrames, 4, &self->animator, true, 0);
133
self->state = HeavyMystic_StateCork_Fired;
134
135
self->hitbox.left = -3;
136
self->hitbox.top = -3;
137
self->hitbox.right = 3;
138
self->hitbox.bottom = 3;
139
break;
140
141
case MYSTIC_BOMB:
142
self->active = ACTIVE_NORMAL;
143
self->visible = true;
144
self->drawGroup = Zone->objectDrawGroup[0];
145
self->drawFX = FX_FLIP;
146
147
RSDK.SetSpriteAnimation(HeavyMystic->roguesFrames, 11, &self->animator, true, 0);
148
self->state = HeavyMystic_State_Bomb;
149
150
self->hitbox.left = -8;
151
self->hitbox.top = -8;
152
self->hitbox.right = 8;
153
self->hitbox.bottom = 8;
154
break;
155
156
case MYSTIC_DEBRIS:
157
self->active = ACTIVE_NORMAL;
158
self->visible = true;
159
self->drawGroup = Zone->objectDrawGroup[0];
160
self->drawFX = FX_FLIP;
161
162
RSDK.SetSpriteAnimation(HeavyMystic->roguesFrames, 16, &self->animator, true, 0);
163
self->state = HeavyMystic_State_BarkDebris;
164
165
self->hitbox.left = -8;
166
self->hitbox.top = -8;
167
self->hitbox.right = 8;
168
self->hitbox.bottom = 8;
169
break;
170
171
default: break;
172
}
173
}
174
else {
175
destroyEntity(self);
176
}
177
}
178
}
179
180
void HeavyMystic_StageLoad(void)
181
{
182
HeavyMystic->aniFrames = RSDK.LoadSpriteAnimation("MSZ/HeavyMystic.bin", SCOPE_STAGE);
183
HeavyMystic->roguesFrames = RSDK.LoadSpriteAnimation("MSZ/Rogues.bin", SCOPE_STAGE);
184
185
HeavyMystic->active = ACTIVE_ALWAYS;
186
HeavyMystic->curtainLinePos = 0;
187
188
HeavyMystic->sfxHit = RSDK.GetSfx("Stage/BossHit.wav");
189
HeavyMystic->sfxExplosion = RSDK.GetSfx("Stage/Explosion2.wav");
190
HeavyMystic->sfxMagicBox = RSDK.GetSfx("MSZ/MagicBox.wav");
191
HeavyMystic->sfxClack = RSDK.GetSfx("Stage/Clack.wav");
192
HeavyMystic->sfxImpact = RSDK.GetSfx("Stage/Impact3.wav");
193
HeavyMystic->sfxPowerDown = RSDK.GetSfx("Stage/PowerDown.wav");
194
HeavyMystic->sfxPon = RSDK.GetSfx("Stage/Pon.wav");
195
HeavyMystic->sfxDrop = RSDK.GetSfx("Stage/Drop.wav");
196
HeavyMystic->sfxImpact2 = RSDK.GetSfx("Stage/Impact3.wav");
197
HeavyMystic->sfxAssemble = RSDK.GetSfx("Stage/Assemble.wav");
198
HeavyMystic->sfxPoof = RSDK.GetSfx("MSZ/MysticPoof.wav");
199
HeavyMystic->sfxTwinkle = RSDK.GetSfx("MSZ/MysticTwinkle.wav");
200
HeavyMystic->sfxHat = RSDK.GetSfx("MSZ/MysticHat.wav");
201
HeavyMystic->sfxHatNode = RSDK.GetSfx("MSZ/MysticHatNode.wav");
202
HeavyMystic->sfxBleeps = RSDK.GetSfx("MSZ/MysticBleeps.wav");
203
HeavyMystic->sfxAppear1 = RSDK.GetSfx("MSZ/MysticAppearAct1.wav");
204
HeavyMystic->sfxTransform = RSDK.GetSfx("MSZ/MysticTransform.wav");
205
}
206
207
void HeavyMystic_SpawnParticleFX(int32 x, int32 y)
208
{
209
int32 velX = RSDK.Rand(-0xC000, 0xC000);
210
int32 velY = RSDK.Rand(-0xC000, 0xC000);
211
212
EntityDebris *particles = CREATE_ENTITY(Debris, Debris_State_Move, x, y);
213
particles->drawGroup = Zone->objectDrawGroup[0];
214
particles->drawFX = FX_FLIP;
215
particles->direction = RSDK.Rand(0, 4);
216
particles->velocity.x = velX;
217
particles->velocity.y = velY;
218
particles->inkEffect = INK_SUB;
219
particles->alpha = 0xE0;
220
RSDK.SetSpriteAnimation(HeavyMystic->aniFrames, RSDK.Rand(0, 2) + 5, &particles->animator, true, 0);
221
particles->timer = 3 * particles->animator.frameCount;
222
223
particles = CREATE_ENTITY(Debris, Debris_State_Move, x, y);
224
particles->velocity.x = velX;
225
particles->velocity.y = velY;
226
particles->drawGroup = Zone->objectDrawGroup[0];
227
particles->inkEffect = INK_ADD;
228
particles->alpha = 0xFF;
229
RSDK.SetSpriteAnimation(HeavyMystic->aniFrames, RSDK.Rand(0, 2) + 7, &particles->animator, true, 0);
230
particles->timer = 3 * particles->animator.frameCount;
231
}
232
233
void HeavyMystic_HandleParticleFX(void)
234
{
235
RSDK_THIS(HeavyMystic);
236
237
if (!(Zone->timer & 7)) {
238
HeavyMystic_SpawnParticleFX(self->position.x + RSDK.Rand(-0x200000, -0x100000), self->position.y + RSDK.Rand(-0x100000, 0));
239
HeavyMystic_SpawnParticleFX(self->position.x + RSDK.Rand(0x100000, 0x200000), self->position.y + RSDK.Rand(-0x100000, 0));
240
}
241
}
242
243
void HeavyMystic_CheckPlayerCollisions(void)
244
{
245
RSDK_THIS(HeavyMystic);
246
247
if (!self->particleFXTimer && !self->invincibilityTimer) {
248
foreach_active(Player, player)
249
{
250
if (Player_CheckBadnikTouch(player, self, &self->hitbox) && Player_CheckBossHit(player, self)) {
251
HeavyMystic_Hit();
252
foreach_break;
253
}
254
}
255
}
256
}
257
258
void HeavyMystic_Hit(void)
259
{
260
RSDK_THIS(HeavyMystic);
261
262
--self->health;
263
--self->rogueHealth;
264
265
if (self->health <= 0) {
266
RSDK.PlaySfx(HeavyMystic->sfxExplosion, false, 255);
267
self->timer = 120;
268
SceneInfo->timeEnabled = false;
269
Player_GiveScore(RSDK_GET_ENTITY(SLOT_PLAYER1, Player), 1000);
270
self->state = HeavyMystic_StateBoss_Destroyed;
271
}
272
else {
273
self->timer -= 30;
274
self->invincibilityTimer = 48;
275
RSDK.PlaySfx(HeavyMystic->sfxHit, false, 255);
276
}
277
}
278
279
void HeavyMystic_CheckPlayerCollisions_Fang(void)
280
{
281
RSDK_THIS(HeavyMystic);
282
283
if (!self->particleFXTimer) {
284
if (self->invincibilityTimer > 0)
285
self->invincibilityTimer--;
286
287
foreach_active(Player, player)
288
{
289
if (!self->invincibilityTimer && Player_CheckBadnikTouch(player, self, &self->hitbox) && Player_CheckBossHit(player, self)) {
290
RSDK.PlaySfx(HeavyMystic->sfxImpact, false, 255);
291
self->velocity.x = player->position.x < self->position.x ? 0x20000 : -0x20000;
292
self->velocity.y = -0x40000;
293
RSDK.SetSpriteAnimation(HeavyMystic->roguesFrames, 3, &self->animator, true, 0);
294
self->state = HeavyMystic_StateBoss_RogueHit;
295
}
296
}
297
}
298
}
299
300
void HeavyMystic_CheckPlayerCollisions_Bark(void)
301
{
302
RSDK_THIS(HeavyMystic);
303
304
if (!self->particleFXTimer) {
305
if (self->invincibilityTimer > 0)
306
self->invincibilityTimer--;
307
308
foreach_active(Player, player)
309
{
310
if (!self->invincibilityTimer && Player_CheckBadnikTouch(player, self, &self->hitbox)) {
311
#if MANIA_USE_PLUS
312
313
if (self->animator.animationID == ANI_SKID_TURN
314
&& ((self->direction == FLIP_NONE && player->position.x > self->position.x)
315
|| (self->direction == FLIP_X && player->position.x < self->position.x))) {
316
if (!Player_CheckMightyUnspin(player, 0x600, false, &player->uncurlTimer))
317
Player_Hurt(player, self);
318
}
319
else
320
#endif
321
if (Player_CheckBossHit(player, self)) {
322
323
RSDK.PlaySfx(HeavyMystic->sfxImpact, false, 255);
324
325
self->velocity.x = player->position.x < self->position.x ? 0x20000 : -0x20000;
326
self->velocity.y = -0x40000;
327
RSDK.SetSpriteAnimation(HeavyMystic->roguesFrames, 15, &self->animator, true, 0);
328
self->state = HeavyMystic_StateBoss_RogueHit;
329
}
330
}
331
}
332
}
333
}
334
335
void HeavyMystic_CheckPlayerCollisions_Bean(void)
336
{
337
RSDK_THIS(HeavyMystic);
338
339
if (!self->particleFXTimer) {
340
341
if (self->invincibilityTimer > 0)
342
self->invincibilityTimer--;
343
344
foreach_active(Player, player)
345
{
346
if (!self->invincibilityTimer && Player_CheckBadnikTouch(player, self, &self->hitbox) && Player_CheckBossHit(player, self)) {
347
RSDK.PlaySfx(HeavyMystic->sfxImpact, false, 255);
348
349
self->velocity.x = player->position.x < self->position.x ? 0x20000 : -0x20000;
350
self->velocity.y = -0x40000;
351
RSDK.SetSpriteAnimation(HeavyMystic->roguesFrames, 9, &self->animator, true, 0);
352
self->state = HeavyMystic_StateBoss_RogueHit;
353
}
354
}
355
}
356
}
357
358
void HeavyMystic_Explode(void)
359
{
360
RSDK_THIS(HeavyMystic);
361
362
if (!(Zone->timer & 3)) {
363
RSDK.PlaySfx(UberCaterkiller->sfxExplosion2, false, 255);
364
365
if (!(Zone->timer & 7)) {
366
int32 x = self->position.x + (RSDK.Rand(-19, 20) << 16);
367
int32 y = self->position.y + (RSDK.Rand(-24, 25) << 16);
368
EntityExplosion *explosion = CREATE_ENTITY(Explosion, INT_TO_VOID((RSDK.Rand(0, 256) > 192) + EXPLOSION_BOSS), x, y);
369
explosion->drawGroup = Zone->objectDrawGroup[1] + 2;
370
}
371
}
372
}
373
374
void HeavyMystic_Scanline_Curtains(ScanlineInfo *scanlines)
375
{
376
int32 curtainPos = HeavyMystic->curtainLinePos;
377
int32 moveY = (0x1100000 - curtainPos) >> 6;
378
int32 max = MAX(curtainPos - 0x400000, 0x100000);
379
380
int32 posY = (ScreenInfo->position.y + 207) << 16;
381
if (curtainPos > max) {
382
int32 scanlineID = HeavyMystic->curtainLinePos >> 16;
383
384
for (int32 i = 0; i < ((curtainPos - max - 1) >> 16) + 1; ++i) {
385
scanlines[scanlineID--].position.y = posY;
386
posY -= moveY;
387
}
388
}
389
390
for (int32 i = HeavyMystic->curtainLinePos >> 16; i < 208; ++i) {
391
scanlines[i].position.y = 0x6200000;
392
}
393
}
394
395
void HeavyMystic_StateMischief_Setup(void)
396
{
397
RSDK_THIS(HeavyMystic);
398
399
RSDK.ProcessAnimation(&self->animator);
400
401
if (++self->timer >= 8) {
402
self->velocity.x = 0x20000;
403
404
// I'd prolly put a position check here too, its not hard to: go into the special stage, then not hit the starpost, doing so causes a softlock
405
if (StarPost->postIDs[0])
406
HeavyMystic->curtainLinePos = 1;
407
408
self->targetPos = self->position;
409
self->position.y += 0xC00000;
410
self->visible = true;
411
self->timer = 120;
412
self->state = HeavyMystic_StateMischief_EnterMystic;
413
}
414
}
415
416
void HeavyMystic_StateBoss_SetupArena(void)
417
{
418
RSDK_THIS(HeavyMystic);
419
if (++self->timer >= 8) {
420
self->timer = 0;
421
422
HeavyMystic->boundsL = (Zone->cameraBoundsL[0] + 64) << 16;
423
HeavyMystic->boundsR = (Zone->cameraBoundsR[0] - 64) << 16;
424
HeavyMystic->boundsM = self->position.x;
425
HeavyMystic->boundsT = (Zone->cameraBoundsT[0] + 48) << 16;
426
HeavyMystic->boundsB = (Zone->cameraBoundsB[0] - 8) << 16;
427
428
self->state = HeavyMystic_StateBoss_AwaitPlayer;
429
}
430
}
431
432
void HeavyMystic_StateBoss_AwaitPlayer(void)
433
{
434
RSDK_THIS(HeavyMystic);
435
436
if (self->timer) {
437
if (++self->timer == 120) {
438
Zone->cameraBoundsT[0] = Zone->cameraBoundsB[0] - ScreenInfo->size.y;
439
MSZSetup_SetBGScrollOrigin(self->position.x + 0x4000000, 0);
440
441
self->position.y += 0x500000;
442
self->targetPos = self->position;
443
self->timer = 0;
444
self->inkEffect = INK_ALPHA;
445
self->visible = true;
446
447
self->state = HeavyMystic_StateBoss_BeginShow;
448
RSDK.GetTileLayer(Zone->fgLayer[1])->scanlineCallback = HeavyMystic_Scanline_Curtains;
449
450
foreach_active(MSZSpotlight, spotlight) { spotlight->state = MSZSpotlight_State_Appear; }
451
}
452
}
453
else {
454
if (RSDK_GET_ENTITY(SLOT_PLAYER1, Player)->position.y > self->position.y) {
455
Music_TransitionTrack(TRACK_HBHBOSS, 0.0125);
456
457
Zone->playerBoundActiveL[0] = true;
458
Zone->playerBoundActiveR[0] = true;
459
460
Zone->cameraBoundsL[0] = (self->position.x >> 16) - ScreenInfo->center.x;
461
Zone->cameraBoundsR[0] = (self->position.x >> 16) + ScreenInfo->center.x;
462
Zone->cameraBoundsB[0] = (self->position.y >> 16) + 256;
463
464
++self->timer;
465
self->active = ACTIVE_NORMAL;
466
}
467
}
468
}
469
470
void HeavyMystic_StateMischief_EnterMystic(void)
471
{
472
RSDK_THIS(HeavyMystic);
473
474
RSDK.ProcessAnimation(&self->animator);
475
HeavyMystic_HandleParticleFX();
476
477
if (self->timer > 0) {
478
self->timer--;
479
}
480
else {
481
self->velocity.y -= 0x1800;
482
self->position.x += self->velocity.x;
483
self->position.y += self->velocity.y;
484
}
485
486
if (self->timer == 50)
487
RSDK.PlaySfx(HeavyMystic->sfxAppear1, false, 255);
488
489
if (self->position.y <= self->targetPos.y)
490
self->state = HeavyMystic_StateMischief_HandleAppearArc;
491
}
492
493
void HeavyMystic_StateMischief_HandleAppearArc(void)
494
{
495
RSDK_THIS(HeavyMystic);
496
497
RSDK.ProcessAnimation(&self->animator);
498
499
HeavyMystic_HandleParticleFX();
500
501
self->velocity.y += 0x3800;
502
self->position.x += self->velocity.x;
503
self->position.y += self->velocity.y;
504
505
if (self->position.y >= self->targetPos.y) {
506
self->velocity.x = 0;
507
self->velocity.y = 0;
508
self->position.y = self->targetPos.y;
509
510
RSDK.PlaySfx(HeavyMystic->sfxBleeps, false, 255);
511
self->state = HeavyMystic_StateMischief_MoveIntoPlace;
512
}
513
}
514
515
void HeavyMystic_StateBoss_BeginShow(void)
516
{
517
RSDK_THIS(HeavyMystic);
518
519
if (self->alpha > 0xC0)
520
HeavyMystic_HandleParticleFX();
521
522
#if MANIA_USE_PLUS
523
if (SceneInfo->filter & FILTER_ENCORE) {
524
if (self->timer < 256) {
525
self->timer += 3;
526
RSDK.SetLimitedFade(0, 1, 5, self->timer, 128, 255);
527
}
528
}
529
#endif
530
531
if (HeavyMystic->curtainLinePos <= 0x100000) {
532
self->timer = 0;
533
self->inkEffect = INK_NONE;
534
self->state = HeavyMystic_StateBoss_AwaitBoxOpened;
535
}
536
else {
537
HeavyMystic->curtainLinePos -= 0x20000;
538
}
539
}
540
541
void HeavyMystic_StateMischief_Idle(void)
542
{
543
RSDK_THIS(HeavyMystic);
544
545
RSDK.ProcessAnimation(&self->animator);
546
547
self->position.y = BadnikHelpers_Oscillate(self->targetPos.y, 4, 11);
548
549
HeavyMystic_HandleParticleFX();
550
HeavyMystic_HandleParticleFX();
551
}
552
553
void HeavyMystic_StateMischief_MoveIntoPlace(void)
554
{
555
RSDK_THIS(HeavyMystic);
556
557
RSDK.ProcessAnimation(&self->animator);
558
self->position.x += 0x8000;
559
560
self->position.y = BadnikHelpers_Oscillate(self->targetPos.y, 4, 11);
561
562
HeavyMystic_HandleParticleFX();
563
HeavyMystic_HandleParticleFX();
564
565
if (++self->timer == 90) {
566
self->timer = 0;
567
RSDK.SetSpriteAnimation(HeavyMystic->aniFrames, 1, &self->animator, true, 0);
568
RSDK.PlaySfx(HeavyMystic->sfxHat, false, 255);
569
self->state = HeavyMystic_StateMischief_GoodDay;
570
}
571
}
572
573
void HeavyMystic_StateMischief_FinishedMagicTrick(void)
574
{
575
RSDK_THIS(HeavyMystic);
576
577
self->position.y = BadnikHelpers_Oscillate(self->targetPos.y, 4, 11);
578
579
RSDK.ProcessAnimation(&self->animator);
580
581
HeavyMystic_HandleParticleFX();
582
HeavyMystic_HandleParticleFX();
583
584
if (++self->timer == 60) {
585
self->timer = 0;
586
587
RSDK.SetSpriteAnimation(HeavyMystic->aniFrames, 3, &self->animator, true, 0);
588
RSDK.PlaySfx(HeavyMystic->sfxTransform, false, 255);
589
self->state = HeavyMystic_StateMischief_Disappear;
590
}
591
}
592
593
void HeavyMystic_StateMischief_PrepareMagicTrick(void)
594
{
595
RSDK_THIS(HeavyMystic);
596
597
self->position.y = BadnikHelpers_Oscillate(self->targetPos.y, 4, 11);
598
599
RSDK.ProcessAnimation(&self->animator);
600
601
HeavyMystic_HandleParticleFX();
602
HeavyMystic_HandleParticleFX();
603
604
if (++self->timer == 60) {
605
if (RSDK.CheckSceneFolder("MSZCutscene")) {
606
self->state = HeavyMystic_StateMischief_Idle;
607
}
608
else {
609
self->timer = 0;
610
RSDK.SetSpriteAnimation(HeavyMystic->aniFrames, 2, &self->animator, true, 0);
611
RSDK.PlaySfx(HeavyMystic->sfxHat, false, 255);
612
self->state = HeavyMystic_StateMischief_ConjureHatterkiller;
613
}
614
}
615
}
616
617
void HeavyMystic_StateMischief_GoodDay(void)
618
{
619
RSDK_THIS(HeavyMystic);
620
621
self->position.y = BadnikHelpers_Oscillate(self->targetPos.y, 4, 11);
622
623
RSDK.ProcessAnimation(&self->animator);
624
625
HeavyMystic_HandleParticleFX();
626
627
if (self->animator.frameID == self->animator.frameCount - 1) {
628
RSDK.SetSpriteAnimation(HeavyMystic->aniFrames, 0, &self->animator, true, 0);
629
self->state = HeavyMystic_StateMischief_PrepareMagicTrick;
630
}
631
}
632
633
void HeavyMystic_StateMischief_ConjureHatterkiller(void)
634
{
635
RSDK_THIS(HeavyMystic);
636
637
self->position.y = BadnikHelpers_Oscillate(self->targetPos.y, 4, 11);
638
639
RSDK.ProcessAnimation(&self->animator);
640
641
HeavyMystic_HandleParticleFX();
642
643
if (self->animator.frameID == 8 && !self->timer) {
644
RSDK.PlaySfx(HeavyMystic->sfxHatNode, false, 255);
645
CREATE_ENTITY(Hatterkiller, INT_TO_VOID(RSDK.Rand(-0x20000, 0x20000)), self->position.x + 0x320000, self->position.y);
646
self->timer = 1;
647
}
648
649
if (self->animator.frameID == self->animator.frameCount - 1) {
650
self->timer = 0;
651
RSDK.SetSpriteAnimation(HeavyMystic->aniFrames, 0, &self->animator, true, 0);
652
self->state = HeavyMystic_StateMischief_FinishedMagicTrick;
653
}
654
}
655
656
void HeavyMystic_StateMischief_Disappear(void)
657
{
658
RSDK_THIS(HeavyMystic);
659
660
RSDK.ProcessAnimation(&self->animator);
661
662
HeavyMystic_HandleParticleFX();
663
664
if (self->animator.frameID == self->animator.frameCount - 1) {
665
if (!HeavyMystic->curtainLinePos) {
666
HeavyMystic->curtainLinePos = 1;
667
668
CREATE_ENTITY(Vultron, INT_TO_VOID(VULTRON_TARGET), self->position.x, self->position.y);
669
CREATE_ENTITY(Vultron, INT_TO_VOID(VULTRON_TARGET), self->position.x, self->position.y);
670
}
671
672
RSDK.PlaySfx(HeavyMystic->sfxPoof, false, 255);
673
CREATE_ENTITY(Explosion, INT_TO_VOID(EXPLOSION_BOSS), self->position.x, self->position.y)->drawGroup = Zone->objectDrawGroup[1];
674
675
destroyEntity(self);
676
}
677
}
678
679
void HeavyMystic_StateBoss_Destroyed(void)
680
{
681
RSDK_THIS(HeavyMystic);
682
683
RSDK.ProcessAnimation(&self->animator);
684
685
HeavyMystic_Explode();
686
687
if (--self->timer <= 0) {
688
self->velocity.y = 0;
689
RSDK.SetSpriteAnimation(HeavyMystic->aniFrames, 0, &self->animator, true, 0);
690
self->state = HeavyMystic_StateBoss_Finish;
691
}
692
}
693
694
void HeavyMystic_StateBoss_Finish(void)
695
{
696
RSDK_THIS(HeavyMystic);
697
698
RSDK.ProcessAnimation(&self->animator);
699
700
HeavyMystic_HandleParticleFX();
701
702
self->position.y += self->velocity.y;
703
self->velocity.y -= 0x3800;
704
705
if (!RSDK.CheckOnScreen(self, &self->updateRange)) {
706
Music_TransitionTrack(TRACK_STAGE, 0.0125);
707
self->state = HeavyMystic_StateBoss_CloseCurtains;
708
}
709
}
710
711
void HeavyMystic_StateBoss_CloseCurtains(void)
712
{
713
RSDK_THIS(HeavyMystic);
714
715
#if MANIA_USE_PLUS
716
if (SceneInfo->filter & FILTER_ENCORE) {
717
if (self->timer < 256) {
718
self->timer += 3;
719
RSDK.SetLimitedFade(0, 5, 1, self->timer, 128, 255);
720
}
721
}
722
#endif
723
724
if (HeavyMystic->curtainLinePos >= 0xD00000) {
725
HeavyMystic->curtainLinePos = 0xD00000;
726
727
RSDK.GetTileLayer(Zone->fgLayer[1])->scanlineCallback = StateMachine_None;
728
Zone->cameraBoundsR[0] += WIDE_SCR_XSIZE * 2;
729
destroyEntity(self);
730
}
731
else {
732
HeavyMystic->curtainLinePos += 0x20000;
733
}
734
}
735
736
void HeavyMystic_StateBoss_AwaitBoxOpened(void) {}
737
738
void HeavyMystic_StateBoss_EnterMystic(void)
739
{
740
RSDK_THIS(HeavyMystic);
741
742
RSDK.ProcessAnimation(&self->animator);
743
744
self->position.y = BadnikHelpers_Oscillate(self->targetPos.y, 4, 11);
745
746
HeavyMystic_HandleParticleFX();
747
HeavyMystic_HandleParticleFX();
748
749
if (++self->timer == 45) {
750
self->timer = 0;
751
RSDK.SetSpriteAnimation(HeavyMystic->aniFrames, 1, &self->animator, true, 0);
752
self->state = HeavyMystic_StateBoss_GoodDay;
753
}
754
}
755
756
void HeavyMystic_StateBoss_GoodDay(void)
757
{
758
RSDK_THIS(HeavyMystic);
759
760
self->position.y = BadnikHelpers_Oscillate(self->targetPos.y, 4, 11);
761
762
RSDK.ProcessAnimation(&self->animator);
763
764
HeavyMystic_HandleParticleFX();
765
766
if (self->animator.frameID == self->animator.frameCount - 8)
767
RSDK.PlaySfx(HeavyMystic->sfxHat, false, 255);
768
769
if (self->animator.frameID == self->animator.frameCount - 1) {
770
RSDK.SetSpriteAnimation(HeavyMystic->aniFrames, 0, &self->animator, true, 0);
771
self->state = HeavyMystic_StateBoss_BoxCloseDelay;
772
}
773
}
774
775
void HeavyMystic_StateBoss_BoxCloseDelay(void)
776
{
777
RSDK_THIS(HeavyMystic);
778
779
RSDK.ProcessAnimation(&self->animator);
780
781
HeavyMystic_HandleParticleFX();
782
783
self->position.y = BadnikHelpers_Oscillate(self->targetPos.y, 4, 11);
784
785
if (self->angle == 192) {
786
foreach_active(HeavyMystic, boss)
787
{
788
if (boss->type == MYSTIC_BOX)
789
boss->state = HeavyMystic_StateBox_CloseDoors;
790
}
791
792
RSDK.PlaySfx(HeavyMystic->sfxClack, false, 255);
793
self->state = HeavyMystic_StateBoss_AwaitBoxClosing;
794
}
795
}
796
797
void HeavyMystic_StateBoss_AwaitBoxClosing(void)
798
{
799
RSDK_THIS(HeavyMystic);
800
801
RSDK.ProcessAnimation(&self->animator);
802
803
HeavyMystic_HandleParticleFX();
804
805
self->position.y = BadnikHelpers_Oscillate(self->targetPos.y, 4, 11);
806
807
if (self->angle == 252)
808
self->state = HeavyMystic_StateBoss_AwaitBoxClosed;
809
}
810
811
void HeavyMystic_StateBoss_AwaitBoxClosed(void)
812
{
813
RSDK_THIS(HeavyMystic);
814
815
if (++self->timer == 60) {
816
self->timer = 0;
817
self->visible = false;
818
819
foreach_active(HeavyMystic, boss)
820
{
821
if (boss->type == MYSTIC_BOX)
822
boss->state = HeavyMystic_StateBox_Transforming;
823
}
824
825
self->state = HeavyMystic_StateBoss_Transforming;
826
}
827
}
828
829
void HeavyMystic_StateBoss_Transforming(void)
830
{
831
RSDK_THIS(HeavyMystic);
832
833
foreach_active(HeavyMystic, boss)
834
{
835
if (boss->type == MYSTIC_BOX && boss->state == HeavyMystic_StateBox_ShowContents) {
836
self->position = boss->position;
837
boss->position = boss->targetPos;
838
self->visible = true;
839
self->state = HeavyMystic_StateBoss_ShowRogue;
840
}
841
}
842
}
843
844
void HeavyMystic_StateBoss_ShowRogue(void)
845
{
846
RSDK_THIS(HeavyMystic);
847
848
self->velocity.x = 0;
849
self->velocity.y = 0;
850
self->rogueHealth = 2;
851
RSDK.PlaySfx(HeavyMystic->sfxTwinkle, false, 255);
852
853
self->velocity.y = -0x40000;
854
self->particleFXTimer = 75;
855
switch (self->rogueID) {
856
case 0: // Fang
857
case 3: // Fang
858
RSDK.SetSpriteAnimation(HeavyMystic->roguesFrames, 2, &self->animator, true, 4);
859
self->state = HeavyMystic_StateBoss_FangHop;
860
self->attackID = 8;
861
break;
862
863
case 1: // Bean
864
RSDK.SetSpriteAnimation(HeavyMystic->roguesFrames, 6, &self->animator, true, 3);
865
self->state = HeavyMystic_StateBoss_BeanJump;
866
break;
867
868
case 2: // Bark
869
RSDK.SetSpriteAnimation(HeavyMystic->roguesFrames, 13, &self->animator, true, 3);
870
self->state = HeavyMystic_StateBoss_BarkJump;
871
break;
872
873
default: break;
874
}
875
}
876
877
void HeavyMystic_StateBoss_MysticReveal(void)
878
{
879
RSDK_THIS(HeavyMystic);
880
881
RSDK.ProcessAnimation(&self->animator);
882
883
self->position.y = BadnikHelpers_Oscillate(self->targetPos.y, 4, 11);
884
885
HeavyMystic_CheckPlayerCollisions();
886
if (--self->timer <= 0) {
887
foreach_active(HeavyMystic, boss)
888
{
889
if (boss->type == MYSTIC_BOX) {
890
self->targetPos = boss->position;
891
}
892
}
893
894
if (self->rogueHealth > 0) {
895
RSDK.SetSpriteAnimation(HeavyMystic->aniFrames, 3, &self->animator, true, 0);
896
self->state = HeavyMystic_StateBoss_TransformBackIntoRogue;
897
}
898
else {
899
RSDK.SetSpriteAnimation(HeavyMystic->aniFrames, 0, &self->animator, true, 0);
900
self->state = HeavyMystic_StateBoss_MoveToBoxY;
901
}
902
}
903
}
904
905
void HeavyMystic_StateBoss_MoveToBoxY(void)
906
{
907
RSDK_THIS(HeavyMystic);
908
909
RSDK.ProcessAnimation(&self->animator);
910
911
HeavyMystic_HandleParticleFX();
912
913
if (self->position.x != self->targetPos.x) {
914
if (self->position.x <= self->targetPos.x) {
915
self->position.x += self->velocity.x;
916
917
if (self->position.x > self->targetPos.x)
918
self->position.x = self->targetPos.x;
919
else if (self->velocity.x < 0x30000)
920
self->velocity.x += 0x3800;
921
}
922
else {
923
self->position.x += self->velocity.x;
924
925
if (self->position.x < self->targetPos.x)
926
self->position.x = self->targetPos.x;
927
else if (self->velocity.x > -0x30000)
928
self->velocity.x -= 0x3800;
929
}
930
}
931
932
if (self->position.y <= self->targetPos.y) {
933
self->position.y = self->targetPos.y;
934
self->angle = 0x80;
935
936
if (self->position.x == self->targetPos.x) {
937
++self->rogueID;
938
self->state = HeavyMystic_StateBoss_BoxCloseDelay;
939
}
940
else {
941
self->state = HeavyMystic_StateBoss_MoveToBoxX;
942
}
943
}
944
else {
945
self->position.y += self->velocity.y;
946
947
if (self->velocity.y > -0x20000)
948
self->velocity.y -= 0x2000;
949
}
950
}
951
952
void HeavyMystic_StateBoss_MoveToBoxX(void)
953
{
954
RSDK_THIS(HeavyMystic);
955
956
RSDK.ProcessAnimation(&self->animator);
957
958
HeavyMystic_HandleParticleFX();
959
960
self->position.y = BadnikHelpers_Oscillate(self->targetPos.y, 4, 11);
961
962
if (self->position.x == self->targetPos.x) {
963
++self->rogueID;
964
965
self->position.y = self->targetPos.y;
966
self->state = HeavyMystic_StateBoss_BoxCloseDelay;
967
}
968
else if (self->position.x > self->targetPos.x) {
969
self->position.x += self->velocity.x;
970
971
if (self->position.x >= self->targetPos.x) {
972
if (self->velocity.x > -0x30000)
973
self->velocity.x -= 0x3800;
974
}
975
else
976
self->position.x = self->targetPos.x;
977
}
978
else {
979
self->position.x += self->velocity.x;
980
981
if (self->position.x > self->targetPos.x)
982
self->position.x = self->targetPos.x;
983
else if (self->velocity.x < 0x30000)
984
self->velocity.x += 0x3800;
985
}
986
}
987
988
void HeavyMystic_StateBoss_TransformBackIntoRogue(void)
989
{
990
RSDK_THIS(HeavyMystic);
991
992
RSDK.ProcessAnimation(&self->animator);
993
994
HeavyMystic_HandleParticleFX();
995
996
if (self->animator.frameID == self->animator.frameCount - 5)
997
RSDK.PlaySfx(HeavyMystic->sfxTransform, false, 255);
998
999
if (self->animator.frameID == self->animator.frameCount - 1) {
1000
CREATE_ENTITY(Explosion, INT_TO_VOID(EXPLOSION_BOSS), self->position.x, self->position.y)->drawGroup = Zone->objectDrawGroup[1];
1001
self->velocity.x = 0;
1002
self->velocity.y = -0x20000;
1003
RSDK.PlaySfx(HeavyMystic->sfxPoof, false, 255);
1004
1005
self->velocity.y = -0x40000;
1006
self->particleFXTimer = 75;
1007
switch (self->rogueID) {
1008
case 0:
1009
case 3:
1010
RSDK.SetSpriteAnimation(HeavyMystic->roguesFrames, 2, &self->animator, true, 4);
1011
self->state = HeavyMystic_StateBoss_FangHop;
1012
self->attackID = 8;
1013
break;
1014
1015
case 1:
1016
RSDK.SetSpriteAnimation(HeavyMystic->roguesFrames, 6, &self->animator, true, 3);
1017
self->state = HeavyMystic_StateBoss_BeanJump;
1018
break;
1019
1020
case 2:
1021
RSDK.SetSpriteAnimation(HeavyMystic->roguesFrames, 13, &self->animator, true, 3);
1022
self->state = HeavyMystic_StateBoss_BarkJump;
1023
break;
1024
1025
default: break;
1026
}
1027
}
1028
}
1029
1030
void HeavyMystic_StateBoss_FangIdle(void)
1031
{
1032
RSDK_THIS(HeavyMystic);
1033
1034
EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);
1035
1036
RSDK.ProcessAnimation(&self->animator);
1037
1038
self->direction = player1->position.x < self->position.x;
1039
1040
if (!--self->timer) {
1041
RSDK.SetSpriteAnimation(HeavyMystic->roguesFrames, 1, &self->animator, true, 0);
1042
self->state = HeavyMystic_StateBoss_FangTell;
1043
}
1044
1045
HeavyMystic_CheckPlayerCollisions_Fang();
1046
}
1047
1048
void HeavyMystic_StateBoss_FangTell(void)
1049
{
1050
RSDK_THIS(HeavyMystic);
1051
1052
RSDK.ProcessAnimation(&self->animator);
1053
1054
if (self->animator.frameID == self->animator.frameCount - 1) {
1055
self->velocity.x = RSDK.Rand(0, 2) != 0 ? -0x10000 : 0x10000;
1056
self->velocity.y = -0x50000;
1057
self->attackID = 8;
1058
RSDK.SetSpriteAnimation(HeavyMystic->roguesFrames, 2, &self->animator, true, 0);
1059
self->state = HeavyMystic_StateBoss_FangHop;
1060
}
1061
1062
HeavyMystic_CheckPlayerCollisions_Fang();
1063
}
1064
1065
void HeavyMystic_StateBoss_FangHop(void)
1066
{
1067
RSDK_THIS(HeavyMystic);
1068
1069
EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);
1070
1071
self->direction = player1->position.x < self->position.x;
1072
1073
self->position.x += self->velocity.x;
1074
self->position.y += self->velocity.y;
1075
self->velocity.y += 0x3800;
1076
1077
if (self->velocity.x >= 0) {
1078
if (self->position.x > (ScreenInfo->position.x + ScreenInfo->size.x - 16) << 16)
1079
self->velocity.x = -self->velocity.x;
1080
}
1081
else {
1082
if (self->position.x < (ScreenInfo->position.x + 16) << 16)
1083
self->velocity.x = -self->velocity.x;
1084
}
1085
1086
RSDK.ProcessAnimation(&self->animator);
1087
1088
if (self->velocity.y > 0 && RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0x140000, true)) {
1089
if (--self->attackID > 0) {
1090
self->velocity.y = -0x50000;
1091
self->velocity.x = RSDK.Rand(0, 2) != 0 ? -0x10000 : 0x10000;
1092
RSDK.SetSpriteAnimation(HeavyMystic->roguesFrames, 2, &self->animator, true, 0);
1093
self->state = HeavyMystic_StateBoss_FangHop;
1094
}
1095
else {
1096
self->timer = 15;
1097
self->velocity.x = 0;
1098
self->velocity.y = 0;
1099
RSDK.SetSpriteAnimation(HeavyMystic->roguesFrames, 0, &self->animator, true, 0);
1100
self->state = HeavyMystic_StateBoss_FangIdle;
1101
}
1102
}
1103
1104
if (self->attackID && !(Zone->timer & 0x3F)) {
1105
RSDK.PlaySfx(HeavyMystic->sfxPon, false, 255);
1106
EntityHeavyMystic *cork = CREATE_ENTITY(HeavyMystic, INT_TO_VOID(MYSTIC_CORK), self->position.x, self->position.y - 0x40000);
1107
if (self->direction == FLIP_NONE) {
1108
cork->position.x += 0x180000;
1109
cork->velocity.x = 0x20000;
1110
cork->direction = self->direction;
1111
}
1112
else {
1113
cork->position.x -= 0x180000;
1114
cork->velocity.x = -0x20000;
1115
cork->direction = self->direction;
1116
}
1117
}
1118
1119
HeavyMystic_CheckPlayerCollisions_Fang();
1120
}
1121
1122
void HeavyMystic_StateBoss_RogueHit(void)
1123
{
1124
RSDK_THIS(HeavyMystic);
1125
1126
self->position.x += self->velocity.x;
1127
self->position.y += self->velocity.y;
1128
self->velocity.y += 0x3800;
1129
1130
if (self->velocity.x >= 0) {
1131
if (self->position.x > (ScreenInfo->position.x + ScreenInfo->size.x - 16) << 16)
1132
self->velocity.x = 0;
1133
}
1134
else {
1135
if (self->position.x < (ScreenInfo->position.x + 16) << 16)
1136
self->velocity.x = 0;
1137
}
1138
1139
self->visible ^= true;
1140
RSDK.ProcessAnimation(&self->animator);
1141
1142
if (self->velocity.y > 0) {
1143
if (RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0x240000, true)) {
1144
RSDK.PlaySfx(HeavyMystic->sfxPowerDown, false, 255);
1145
CREATE_ENTITY(Explosion, INT_TO_VOID(EXPLOSION_BOSS), self->position.x, self->position.y)->drawGroup = Zone->objectDrawGroup[1];
1146
self->direction ^= FLIP_X;
1147
self->timer = 90;
1148
self->attackID = 0;
1149
self->visible = true;
1150
self->targetPos.y = self->position.y;
1151
self->velocity.x = 0;
1152
self->velocity.y = 0;
1153
RSDK.SetSpriteAnimation(HeavyMystic->aniFrames, 4, &self->animator, true, 0);
1154
self->state = HeavyMystic_StateBoss_MysticReveal;
1155
}
1156
}
1157
}
1158
1159
void HeavyMystic_StateBoss_BarkIdle(void)
1160
{
1161
RSDK_THIS(HeavyMystic);
1162
EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);
1163
1164
RSDK.ProcessAnimation(&self->animator);
1165
1166
self->direction = player1->position.x < self->position.x;
1167
1168
if (!--self->timer) {
1169
self->velocity.x = RSDK.Rand(0, 2) != 0 ? -0x10000 : 0x10000;
1170
self->velocity.y = -0x40000;
1171
1172
if (self->attackID == 1) {
1173
self->timer = 240;
1174
RSDK.SetSpriteAnimation(HeavyMystic->roguesFrames, 14, &self->animator, true, 0);
1175
self->state = HeavyMystic_StateBoss_BarkPounding;
1176
}
1177
else {
1178
self->attackID = 1;
1179
RSDK.SetSpriteAnimation(HeavyMystic->roguesFrames, 13, &self->animator, true, 0);
1180
self->state = HeavyMystic_StateBoss_BarkJump;
1181
}
1182
}
1183
1184
HeavyMystic_CheckPlayerCollisions_Bark();
1185
}
1186
1187
void HeavyMystic_StateBoss_BarkPounding(void)
1188
{
1189
RSDK_THIS(HeavyMystic);
1190
1191
RSDK.ProcessAnimation(&self->animator);
1192
1193
// check when bark's hand hits the grounds
1194
if (self->animator.frameID == 3 || self->animator.frameID == 10) {
1195
if (self->attackID != self->animator.frameID)
1196
RSDK.PlaySfx(HeavyMystic->sfxImpact2, false, 255);
1197
self->attackID = self->animator.frameID;
1198
}
1199
1200
if (--self->timer <= 0) {
1201
self->attackID = 0;
1202
self->timer = 15;
1203
self->velocity.x = 0;
1204
self->velocity.y = 0;
1205
RSDK.SetSpriteAnimation(HeavyMystic->roguesFrames, 12, &self->animator, true, 0);
1206
self->state = HeavyMystic_StateBoss_BarkIdle;
1207
}
1208
1209
if (self->attackID != 1) {
1210
if (!(Zone->timer & 3))
1211
Camera_ShakeScreen(0, 0, 2);
1212
1213
if (!(Zone->timer & 0xF)) {
1214
int32 x = ScreenInfo->position.x + 16 + 32 * RSDK.Rand(0, ScreenInfo->size.x >> 5);
1215
EntityHeavyMystic *debris = CREATE_ENTITY(HeavyMystic, INT_TO_VOID(MYSTIC_DEBRIS), x << 16, (ScreenInfo->position.y - 16) << 16);
1216
debris->animator.frameID = RSDK.Rand(0, 6);
1217
}
1218
}
1219
1220
HeavyMystic_CheckPlayerCollisions_Bark();
1221
}
1222
1223
void HeavyMystic_StateBoss_BarkJump(void)
1224
{
1225
RSDK_THIS(HeavyMystic);
1226
EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);
1227
1228
self->direction = player1->position.x < self->position.x;
1229
1230
self->position.x += self->velocity.x;
1231
self->position.y += self->velocity.y;
1232
self->velocity.y += 0x3800;
1233
1234
if (self->velocity.x >= 0) {
1235
if (self->position.x > (ScreenInfo->position.x + ScreenInfo->size.x - 16) << 16)
1236
self->velocity.x = -self->velocity.x;
1237
}
1238
else {
1239
if (self->position.x < (ScreenInfo->position.x + 16) << 16)
1240
self->velocity.x = -self->velocity.x;
1241
}
1242
1243
RSDK.ProcessAnimation(&self->animator);
1244
1245
if (self->velocity.y > 0 && RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0x200000, true)) {
1246
self->timer = 15;
1247
RSDK.SetSpriteAnimation(HeavyMystic->roguesFrames, 12, &self->animator, true, 0);
1248
self->state = HeavyMystic_StateBoss_BarkIdle;
1249
}
1250
1251
HeavyMystic_CheckPlayerCollisions_Bark();
1252
}
1253
1254
void HeavyMystic_StateBoss_BeanIdle(void)
1255
{
1256
RSDK_THIS(HeavyMystic);
1257
EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);
1258
1259
self->direction = player1->position.x < self->position.x;
1260
1261
RSDK.ProcessAnimation(&self->animator);
1262
1263
if (!--self->timer) {
1264
self->velocity.x = RSDK.Rand(0, 2) != 0 ? -0x20000 : 0x20000;
1265
self->velocity.y = -0x68000;
1266
1267
if (self->attackID == 1) {
1268
RSDK.SetSpriteAnimation(HeavyMystic->roguesFrames, 8, &self->animator, true, 0);
1269
self->state = HeavyMystic_StateBoss_BeanBomb1Throw;
1270
}
1271
else {
1272
self->attackID = 1;
1273
RSDK.SetSpriteAnimation(HeavyMystic->roguesFrames, 6, &self->animator, true, 0);
1274
self->state = HeavyMystic_StateBoss_BeanJump;
1275
}
1276
}
1277
1278
HeavyMystic_CheckPlayerCollisions_Bean();
1279
}
1280
1281
void HeavyMystic_StateBoss_BeanBomb1Throw(void)
1282
{
1283
RSDK_THIS(HeavyMystic);
1284
1285
RSDK.ProcessAnimation(&self->animator);
1286
1287
if (self->attackID == 1 && self->animator.frameID == 3) {
1288
self->attackID = 2;
1289
RSDK.PlaySfx(HeavyMystic->sfxDrop, false, 255);
1290
1291
EntityHeavyMystic *bomb = CREATE_ENTITY(HeavyMystic, INT_TO_VOID(MYSTIC_BOMB), self->position.x, self->position.y + 0x130000);
1292
if (self->direction) {
1293
bomb->position.x += 0xB0000;
1294
bomb->velocity.x = -0x40000;
1295
}
1296
else {
1297
bomb->position.x -= 0xB0000;
1298
bomb->velocity.x = 0x40000;
1299
}
1300
1301
bomb->velocity.y = -0x40000;
1302
bomb->direction = self->direction;
1303
}
1304
1305
if (self->animator.frameID == self->animator.frameCount - 1) {
1306
self->attackID = 1;
1307
RSDK.SetSpriteAnimation(HeavyMystic->roguesFrames, 7, &self->animator, true, 0);
1308
self->state = HeavyMystic_StateBoss_BeanBomb2Throw;
1309
}
1310
1311
HeavyMystic_CheckPlayerCollisions_Bean();
1312
}
1313
1314
void HeavyMystic_StateBoss_BeanBomb2Throw(void)
1315
{
1316
RSDK_THIS(HeavyMystic);
1317
1318
RSDK.ProcessAnimation(&self->animator);
1319
1320
if (self->attackID == 1 && self->animator.frameID == 2) {
1321
self->attackID = 2;
1322
RSDK.PlaySfx(HeavyMystic->sfxDrop, false, 255);
1323
1324
EntityHeavyMystic *bomb = CREATE_ENTITY(HeavyMystic, INT_TO_VOID(MYSTIC_BOMB), self->position.x, self->position.y - 0x130000);
1325
if (self->direction) {
1326
bomb->position.x += 0xB0000;
1327
bomb->velocity.x = -0x40000;
1328
}
1329
else {
1330
bomb->position.x -= 0xB0000;
1331
bomb->velocity.x = 0x40000;
1332
}
1333
1334
bomb->velocity.y = -0x40000;
1335
bomb->direction = self->direction;
1336
}
1337
1338
if (self->animator.frameID == self->animator.frameCount - 1) {
1339
self->attackID = 0;
1340
self->timer = 5;
1341
self->velocity.x = 0;
1342
self->velocity.y = 0;
1343
RSDK.SetSpriteAnimation(HeavyMystic->roguesFrames, 5, &self->animator, true, 0);
1344
self->state = HeavyMystic_StateBoss_BeanIdle;
1345
}
1346
1347
HeavyMystic_CheckPlayerCollisions_Bean();
1348
}
1349
1350
void HeavyMystic_StateBoss_BeanJump(void)
1351
{
1352
RSDK_THIS(HeavyMystic);
1353
EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);
1354
1355
self->direction = player1->position.x < self->position.x;
1356
1357
self->position.x += self->velocity.x;
1358
self->position.y += self->velocity.y;
1359
self->velocity.y += 0x3800;
1360
1361
if (self->velocity.x >= 0) {
1362
if (self->position.x > (ScreenInfo->position.x + ScreenInfo->size.x - 16) << 16)
1363
self->velocity.x = -self->velocity.x;
1364
}
1365
else {
1366
if (self->position.x < (ScreenInfo->position.x + 16) << 16)
1367
self->velocity.x = -self->velocity.x;
1368
}
1369
1370
RSDK.ProcessAnimation(&self->animator);
1371
1372
if (self->velocity.y > 0 && RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0x140000, true) == true) {
1373
if (--self->attackID <= 0) {
1374
self->attackID = 1;
1375
self->timer = 15;
1376
self->velocity.x = 0;
1377
self->velocity.y = 0;
1378
RSDK.SetSpriteAnimation(HeavyMystic->roguesFrames, 5, &self->animator, true, 0);
1379
self->state = HeavyMystic_StateBoss_BeanIdle;
1380
}
1381
else {
1382
self->velocity.y = -0x50000;
1383
self->velocity.x = RSDK.Rand(0, 2) != 0 ? -0x10000 : 0x10000;
1384
RSDK.SetSpriteAnimation(HeavyMystic->roguesFrames, 6, &self->animator, true, 0);
1385
}
1386
}
1387
1388
HeavyMystic_CheckPlayerCollisions_Bean();
1389
}
1390
1391
void HeavyMystic_StateCork_Fired(void)
1392
{
1393
RSDK_THIS(HeavyMystic);
1394
1395
RSDK.ProcessAnimation(&self->animator);
1396
1397
self->position.x += self->velocity.x;
1398
1399
foreach_active(Player, player)
1400
{
1401
if (Player_CheckCollisionTouch(player, self, &self->hitbox)) {
1402
#if MANIA_USE_PLUS
1403
if (Player_CheckMightyShellHit(player, self, -0x300, -0x400))
1404
self->state = HeavyMystic_StateCork_MightyRebound;
1405
else
1406
#endif
1407
Player_Hurt(player, self);
1408
1409
RSDK.PlaySfx(HeavyMystic->sfxExplosion, false, 255);
1410
CREATE_ENTITY(Explosion, INT_TO_VOID(EXPLOSION_BOSSPUFF), self->position.x, self->position.y)->drawGroup = Zone->objectDrawGroup[1] + 2;
1411
destroyEntity(self);
1412
foreach_break;
1413
}
1414
}
1415
1416
if (!RSDK.CheckOnScreen(self, &self->updateRange))
1417
destroyEntity(self);
1418
}
1419
1420
#if MANIA_USE_PLUS
1421
void HeavyMystic_StateCork_MightyRebound(void)
1422
{
1423
RSDK_THIS(HeavyMystic);
1424
1425
self->visible ^= true;
1426
1427
RSDK.ProcessAnimation(&self->animator);
1428
1429
self->position.x += self->velocity.x;
1430
self->position.y += self->velocity.y;
1431
self->velocity.y += 0x3800;
1432
1433
if (!RSDK.CheckOnScreen(self, &self->updateRange))
1434
destroyEntity(self);
1435
}
1436
#endif
1437
1438
void HeavyMystic_State_Bomb(void)
1439
{
1440
RSDK_THIS(HeavyMystic);
1441
1442
RSDK.ProcessAnimation(&self->animator);
1443
1444
self->position.x += self->velocity.x;
1445
self->position.y += self->velocity.y;
1446
self->velocity.y += 0x3800;
1447
1448
foreach_active(Player, player)
1449
{
1450
if (Player_CheckCollisionTouch(player, self, &self->hitbox)) {
1451
#if MANIA_USE_PLUS
1452
if (!Player_CheckMightyUnspin(player, 0x300, false, &player->uncurlTimer))
1453
#endif
1454
Player_Hurt(player, self);
1455
RSDK.PlaySfx(HeavyMystic->sfxExplosion, false, 255);
1456
CREATE_ENTITY(Explosion, INT_TO_VOID(EXPLOSION_BOSSPUFF), self->position.x, self->position.y)->drawGroup = Zone->objectDrawGroup[1] + 2;
1457
destroyEntity(self);
1458
foreach_break;
1459
}
1460
}
1461
1462
if (!RSDK.CheckOnScreen(self, &self->updateRange))
1463
destroyEntity(self);
1464
}
1465
1466
void HeavyMystic_State_BarkDebris(void)
1467
{
1468
RSDK_THIS(HeavyMystic);
1469
1470
RSDK.ProcessAnimation(&self->animator);
1471
1472
self->position.y += self->velocity.y;
1473
self->velocity.y += 0x1800;
1474
1475
foreach_active(Player, player)
1476
{
1477
if (Player_CheckCollisionTouch(player, self, &self->hitbox)) {
1478
#if MANIA_USE_PLUS
1479
if (!Player_CheckMightyUnspin(player, 0x300, false, &player->uncurlTimer))
1480
#endif
1481
Player_Hurt(player, self);
1482
}
1483
}
1484
1485
if (!RSDK.CheckOnScreen(self, &self->updateRange))
1486
destroyEntity(self);
1487
}
1488
1489
void HeavyMystic_StateBox_AwaitCurtainRise(void)
1490
{
1491
RSDK_THIS(HeavyMystic);
1492
1493
self->timer = 2;
1494
if (HeavyMystic->curtainLinePos <= 0x100000) {
1495
self->state = HeavyMystic_StateBox_Idle;
1496
self->stateDraw = HeavyMystic_Draw_BoxTransforming;
1497
}
1498
}
1499
1500
void HeavyMystic_StateBox_Idle(void) {}
1501
1502
void HeavyMystic_StateBox_CloseDoors(void)
1503
{
1504
RSDK_THIS(HeavyMystic);
1505
1506
self->scale.x -= 0x20;
1507
if (self->scale.x <= 0) {
1508
if (self->timer == 2) {
1509
foreach_active(HeavyMystic, boss)
1510
{
1511
if (boss->state == HeavyMystic_StateBoss_AwaitBoxOpened)
1512
boss->state = HeavyMystic_StateBoss_EnterMystic;
1513
}
1514
1515
self->timer = 1;
1516
self->stateDraw = HeavyMystic_Draw_BoxOpened;
1517
self->state = HeavyMystic_StateBox_OpenDoors;
1518
}
1519
else {
1520
self->timer = 2;
1521
self->stateDraw = HeavyMystic_Draw_BoxTransforming;
1522
self->state = HeavyMystic_StateBox_OpenDoors;
1523
}
1524
}
1525
}
1526
1527
void HeavyMystic_StateBox_OpenDoors(void)
1528
{
1529
RSDK_THIS(HeavyMystic);
1530
1531
self->scale.x += 0x20;
1532
if (self->scale.x >= 0x200)
1533
self->state = HeavyMystic_StateBox_Idle;
1534
}
1535
1536
void HeavyMystic_StateBox_Transforming(void)
1537
{
1538
RSDK_THIS(HeavyMystic);
1539
1540
if (!(Zone->timer & 7)) {
1541
RSDK.PlaySfx(HeavyMystic->sfxMagicBox, false, 255);
1542
int32 x = self->position.x + (RSDK.Rand(-24, 25) << 16);
1543
int32 y = self->position.y + (RSDK.Rand(-24, 25) << 16);
1544
CREATE_ENTITY(Explosion, INT_TO_VOID(EXPLOSION_ENEMY), x, y)->drawGroup = Zone->objectDrawGroup[1] + 2;
1545
}
1546
1547
self->scale.x = 0x200 + RSDK.Cos256(self->angle + 0x40);
1548
self->scale.y = 0x200 + RSDK.Sin256(self->angle);
1549
1550
if (self->angle == 0x300) {
1551
RSDK.StopSfx(HeavyMystic->sfxMagicBox);
1552
RSDK.PlaySfx(HeavyMystic->sfxPowerDown, false, 255);
1553
self->angle = 0;
1554
self->timer = 0;
1555
self->state = HeavyMystic_StateBox_TransformFinish;
1556
self->stateDraw = HeavyMystic_Draw_BoxClosed;
1557
}
1558
else {
1559
self->angle += 8;
1560
}
1561
}
1562
1563
void HeavyMystic_StateBox_TransformFinish(void)
1564
{
1565
RSDK_THIS(HeavyMystic);
1566
1567
if (++self->timer > 30) {
1568
RSDK.PlaySfx(HeavyMystic->sfxDrop, false, 255);
1569
self->state = HeavyMystic_StateBox_Dropping;
1570
}
1571
}
1572
1573
void HeavyMystic_StateBox_Dropping(void)
1574
{
1575
RSDK_THIS(HeavyMystic);
1576
1577
self->position.y += self->velocity.y;
1578
self->velocity.y += 0x2800;
1579
1580
if (RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0x280000, true)) {
1581
Camera_ShakeScreen(0, 0, 6);
1582
RSDK.PlaySfx(HeavyMystic->sfxImpact2, false, 255);
1583
RSDK.PlaySfx(HeavyMystic->sfxExplosion, false, 255);
1584
1585
EntityDebris *debris = CREATE_ENTITY(Debris, Debris_State_FallAndFlicker, self->position.x, self->position.y);
1586
debris->drawGroup = Zone->objectDrawGroup[0];
1587
debris->drawFX = FX_FLIP;
1588
debris->direction = FLIP_NONE;
1589
debris->velocity.y = -0x40000;
1590
debris->gravityStrength = 0x2800;
1591
RSDK.SetSpriteAnimation(HeavyMystic->aniFrames, 10, &debris->animator, true, 0);
1592
debris->animator.frameID = 0;
1593
1594
debris = CREATE_ENTITY(Debris, Debris_State_FallAndFlicker, self->position.x - 0x280000, self->position.y);
1595
debris->drawGroup = Zone->objectDrawGroup[1];
1596
debris->drawFX = FX_FLIP;
1597
debris->direction = FLIP_NONE;
1598
debris->velocity.x = -0x20000;
1599
debris->velocity.y = -0x40000;
1600
debris->gravityStrength = 0x2800;
1601
RSDK.SetSpriteAnimation(HeavyMystic->aniFrames, 10, &debris->animator, true, 0);
1602
debris->animator.frameID = 2;
1603
1604
debris = CREATE_ENTITY(Debris, Debris_State_FallAndFlicker, self->position.x + 0x280000, self->position.y);
1605
debris->drawGroup = Zone->objectDrawGroup[1];
1606
debris->drawFX = FX_FLIP;
1607
debris->direction = FLIP_X;
1608
debris->velocity.x = 0x20000;
1609
debris->velocity.y = -0x40000;
1610
debris->gravityStrength = 0x2800;
1611
RSDK.SetSpriteAnimation(HeavyMystic->aniFrames, 10, &debris->animator, true, 0);
1612
debris->animator.frameID = 2;
1613
1614
self->timer = 0;
1615
self->visible = false;
1616
self->velocity.y = 0;
1617
self->state = HeavyMystic_StateBox_ShowContents;
1618
}
1619
}
1620
1621
void HeavyMystic_StateBox_ShowContents(void)
1622
{
1623
RSDK_THIS(HeavyMystic);
1624
1625
if (++self->timer > 96) {
1626
CREATE_ENTITY(Explosion, INT_TO_VOID(EXPLOSION_ENEMY), self->position.x, self->position.y)->drawGroup = Zone->objectDrawGroup[1] + 2;
1627
self->visible = true;
1628
self->scale.x = 0;
1629
self->scale.y = 0;
1630
RSDK.PlaySfx(HeavyMystic->sfxAssemble, false, 255);
1631
self->stateDraw = HeavyMystic_Draw_BoxClosed;
1632
self->state = HeavyMystic_StateBox_Reappear;
1633
}
1634
}
1635
1636
void HeavyMystic_StateBox_Reappear(void)
1637
{
1638
RSDK_THIS(HeavyMystic);
1639
1640
if (self->scale.x < 0x200) {
1641
self->scale.y += 8;
1642
self->scale.x = self->scale.y;
1643
self->rotation -= 8;
1644
}
1645
else {
1646
if (self->rotation & 0x1FF) {
1647
self->rotation -= 8;
1648
}
1649
else {
1650
RSDK.PlaySfx(HeavyMystic->sfxClack, false, 255);
1651
self->timer = 2;
1652
self->stateDraw = HeavyMystic_Draw_BoxTransforming;
1653
self->state = HeavyMystic_StateBox_CloseDoors;
1654
}
1655
1656
self->rotation &= 0x1FF;
1657
}
1658
}
1659
1660
void HeavyMystic_Draw_BoxOpened(void)
1661
{
1662
RSDK_THIS(HeavyMystic);
1663
1664
if (SceneInfo->currentDrawGroup == self->drawGroup) {
1665
self->drawFX = FX_NONE;
1666
self->animator.frameID = 0;
1667
RSDK.DrawSprite(&self->animator, NULL, false);
1668
1669
Vector2 drawPos;
1670
drawPos.x = self->position.x - 0x280000;
1671
drawPos.y = self->position.y;
1672
self->animator.frameID = self->timer;
1673
self->drawFX = FX_SCALE | FX_ROTATE | FX_FLIP;
1674
RSDK.DrawSprite(&self->animator, &drawPos, false);
1675
1676
drawPos.x += 0x500000;
1677
self->direction = FLIP_X;
1678
RSDK.DrawSprite(&self->animator, &drawPos, false);
1679
1680
self->direction = FLIP_NONE;
1681
}
1682
}
1683
1684
void HeavyMystic_Draw_BoxTransforming(void)
1685
{
1686
RSDK_THIS(HeavyMystic);
1687
1688
if (SceneInfo->currentDrawGroup == self->drawGroup) {
1689
self->drawFX = FX_NONE;
1690
if (self->state != HeavyMystic_StateBox_Transforming) {
1691
self->animator.frameID = 0;
1692
RSDK.DrawSprite(&self->animator, NULL, false);
1693
}
1694
}
1695
else {
1696
Vector2 drawPos;
1697
1698
drawPos.x = self->position.x - 0x280000;
1699
drawPos.y = self->position.y;
1700
self->animator.frameID = self->timer;
1701
self->drawFX = FX_SCALE | FX_ROTATE | FX_FLIP;
1702
if (self->state == HeavyMystic_StateBox_Transforming)
1703
drawPos.x += 0x1400 * (0x200 - self->scale.x);
1704
RSDK.DrawSprite(&self->animator, &drawPos, false);
1705
1706
self->direction = FLIP_X;
1707
drawPos.x = self->position.x + 0x280000;
1708
if (self->state == HeavyMystic_StateBox_Transforming)
1709
drawPos.x += 0x1400 * (self->scale.x - 0x200);
1710
RSDK.DrawSprite(&self->animator, &drawPos, false);
1711
self->direction = FLIP_NONE;
1712
}
1713
}
1714
1715
void HeavyMystic_Draw_BoxClosed(void)
1716
{
1717
RSDK_THIS(HeavyMystic);
1718
1719
if (SceneInfo->currentDrawGroup == self->drawGroup) {
1720
self->drawFX = FX_SCALE | FX_ROTATE;
1721
self->animator.frameID = 3;
1722
RSDK.DrawSprite(&self->animator, NULL, false);
1723
}
1724
}
1725
1726
#if GAME_INCLUDE_EDITOR
1727
void HeavyMystic_EditorDraw(void)
1728
{
1729
RSDK_THIS(HeavyMystic);
1730
1731
switch (self->type) {
1732
case MYSTIC_MISCHIEF:
1733
self->drawFX = FX_FLIP;
1734
RSDK.SetSpriteAnimation(HeavyMystic->aniFrames, 0, &self->animator, true, 0);
1735
break;
1736
1737
case MYSTIC_BOSS:
1738
self->drawFX = FX_FLIP;
1739
RSDK.SetSpriteAnimation(HeavyMystic->aniFrames, 0, &self->animator, true, 0);
1740
1741
if (showGizmos()) {
1742
RSDK_DRAWING_OVERLAY(true);
1743
1744
DrawHelpers_DrawArenaBounds(-WIDE_SCR_XCENTER, (256 - SCREEN_YSIZE), WIDE_SCR_XCENTER, 256, 1 | 2 | 4 | 8, 0x00C0F0);
1745
1746
RSDK_DRAWING_OVERLAY(false);
1747
}
1748
break;
1749
1750
case MYSTIC_BOX:
1751
self->drawFX = FX_SCALE | FX_ROTATE | FX_FLIP;
1752
RSDK.SetSpriteAnimation(HeavyMystic->aniFrames, 10, &self->animator, true, 0);
1753
break;
1754
1755
default: break;
1756
}
1757
1758
RSDK.DrawSprite(&self->animator, NULL, false);
1759
}
1760
1761
void HeavyMystic_EditorLoad(void)
1762
{
1763
HeavyMystic->aniFrames = RSDK.LoadSpriteAnimation("MSZ/HeavyMystic.bin", SCOPE_STAGE);
1764
HeavyMystic->roguesFrames = RSDK.LoadSpriteAnimation("MSZ/Rogues.bin", SCOPE_STAGE);
1765
1766
RSDK_ACTIVE_VAR(HeavyMystic, type);
1767
RSDK_ENUM_VAR("Mischief", MYSTIC_MISCHIEF);
1768
RSDK_ENUM_VAR("Boss", MYSTIC_BOSS);
1769
RSDK_ENUM_VAR("Box", MYSTIC_BOX);
1770
// RSDK_ENUM_VAR("Cork", MYSTIC_CORK);
1771
// RSDK_ENUM_VAR("Bomb", MYSTIC_BOMB);
1772
// RSDK_ENUM_VAR("Debris", MYSTIC_DEBRIS);
1773
}
1774
#endif
1775
1776
void HeavyMystic_Serialize(void) { RSDK_EDITABLE_VAR(HeavyMystic, VAR_ENUM, type); }
1777
1778