Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/GHZ/DDWrecker.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: DDWrecker Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectDDWrecker *DDWrecker;
11
12
void DDWrecker_Update(void)
13
{
14
RSDK_THIS(DDWrecker);
15
StateMachine_Run(self->state);
16
17
RSDK.ProcessAnimation(&self->animator);
18
19
if (self->type != DDWRECKER_CORE) {
20
if (self->invincibilityTimer > 0)
21
self->invincibilityTimer--;
22
23
StateMachine_Run(self->stateBall);
24
}
25
}
26
27
void DDWrecker_LateUpdate(void) {}
28
29
void DDWrecker_StaticUpdate(void) {}
30
31
void DDWrecker_Draw(void)
32
{
33
RSDK_THIS(DDWrecker);
34
if (self->type == DDWRECKER_BALL1 || self->type == DDWRECKER_BALL2) {
35
RSDK.SetActivePalette(1, 0, ScreenInfo->size.y);
36
37
self->direction = self->animator.frameID >= 16;
38
if (!(self->invincibilityTimer & 2)) {
39
RSDK.SetLimitedFade(1, 2, 3, self->blendAmount, 1, 28);
40
}
41
else {
42
for (int32 i = 1; i < 0x1C; ++i) {
43
RSDK.SetPaletteEntry(1, i, 0xF0F0F0);
44
}
45
}
46
}
47
RSDK.DrawSprite(&self->animator, NULL, false);
48
49
RSDK.SetActivePalette(0, 0, ScreenInfo->size.y);
50
}
51
52
void DDWrecker_Create(void *data)
53
{
54
RSDK_THIS(DDWrecker);
55
if (!SceneInfo->inEditor) {
56
if (globals->gameMode == MODE_TIMEATTACK || globals->gameMode >= MODE_TIMEATTACK) {
57
destroyEntity(self);
58
}
59
else if (data) {
60
self->type = VOID_TO_INT(data);
61
self->active = ACTIVE_NORMAL;
62
switch (self->type) {
63
case DDWRECKER_BALL1: // main body
64
case DDWRECKER_BALL2:
65
RSDK.SetSpriteAnimation(DDWrecker->aniFrames, 0, &self->animator, true, 0);
66
self->drawFX = FX_FLIP | FX_ROTATE;
67
self->hitbox.left = -20;
68
self->hitbox.top = -20;
69
self->hitbox.right = 20;
70
self->hitbox.bottom = 20;
71
self->health = 3;
72
break;
73
74
case DDWRECKER_CHAIN: // chains
75
RSDK.SetSpriteAnimation(DDWrecker->aniFrames, 4, &self->animator, true, 0);
76
break;
77
78
case DDWRECKER_CORE: // core
79
RSDK.SetSpriteAnimation(DDWrecker->aniFrames, 5, &self->animator, true, 0);
80
break;
81
82
default: break;
83
}
84
85
self->visible = true;
86
self->drawGroup = Zone->objectDrawGroup[0];
87
}
88
else {
89
self->active = ACTIVE_BOUNDS;
90
self->updateRange.x = 0x800000;
91
self->updateRange.y = 0x800000;
92
self->visible = false;
93
self->state = DDWrecker_State_SetupArena;
94
}
95
}
96
}
97
98
void DDWrecker_StageLoad(void)
99
{
100
DDWrecker->aniFrames = RSDK.LoadSpriteAnimation("GHZ/DDWrecker.bin", SCOPE_STAGE);
101
102
DDWrecker->sfxBossHit = RSDK.GetSfx("Stage/BossHit.wav");
103
DDWrecker->sfxExplosion = RSDK.GetSfx("Stage/Explosion2.wav");
104
DDWrecker->sfxDrop = RSDK.GetSfx("Stage/Drop.wav");
105
DDWrecker->sfxImpact = RSDK.GetSfx("Stage/Impact2.wav");
106
DDWrecker->sfxAssemble = RSDK.GetSfx("Stage/Assemble.wav");
107
DDWrecker->sfxRotate = RSDK.GetSfx("Stage/Rotate.wav");
108
DDWrecker->sfxSharp = RSDK.GetSfx("Stage/Sharp.wav");
109
}
110
111
void DDWrecker_State_SetupArena(void)
112
{
113
RSDK_THIS(DDWrecker);
114
if (++self->timer >= 8) {
115
self->timer = 0;
116
117
Zone->playerBoundActiveL[0] = true;
118
Zone->playerBoundActiveR[0] = true;
119
Zone->playerBoundActiveB[0] = true;
120
Zone->cameraBoundsL[0] = FROM_FIXED(self->position.x) - ScreenInfo->center.x;
121
Zone->cameraBoundsR[0] = FROM_FIXED(self->position.x) + ScreenInfo->center.x;
122
Zone->cameraBoundsB[0] = FROM_FIXED(self->position.y);
123
124
DDWrecker->camBoundL = self->position.x + ((160 - ScreenInfo->center.x) << 16);
125
DDWrecker->camBoundR = self->position.x + ((ScreenInfo->center.x - 160) << 16);
126
DDWrecker->bossBoundL = self->position.x + ((32 - ScreenInfo->center.x) << 16);
127
DDWrecker->bossBoundR = self->position.x + ((ScreenInfo->center.x - 32) << 16);
128
DDWrecker->bossBoundT = self->position.y - 0xC00000;
129
130
DDWrecker->attackVelocities[0] = CLAMP(ScreenInfo->center.x - 168, 0, 24);
131
DDWrecker->attackVelocities[0] = (DDWrecker->attackVelocities[0] + 32) << 11;
132
DDWrecker->attackVelocities[1] = DDWrecker->attackVelocities[0] >> 2;
133
DDWrecker->attackVelocities[2] = 288 * DDWrecker->attackVelocities[0] >> 8;
134
135
self->state = DDWrecker_State_InitChildren;
136
}
137
}
138
139
void DDWrecker_State_InitChildren(void)
140
{
141
RSDK_THIS(DDWrecker);
142
if (self->timer) {
143
self->timer++;
144
if (self->timer == 60) {
145
EntityDDWrecker *chain1 = RSDK_GET_ENTITY(SceneInfo->entitySlot + 1, DDWrecker);
146
RSDK.ResetEntity(chain1, DDWrecker->classID, INT_TO_VOID(DDWRECKER_CHAIN));
147
chain1->position.x = self->position.x;
148
chain1->position.y = self->position.y + 0x400000;
149
150
EntityDDWrecker *chain2 = RSDK_GET_ENTITY(SceneInfo->entitySlot + 2, DDWrecker);
151
RSDK.ResetEntity(chain2, DDWrecker->classID, INT_TO_VOID(DDWRECKER_CHAIN));
152
chain2->position.x = self->position.x;
153
chain2->position.y = self->position.y + 0x400000;
154
155
EntityDDWrecker *chain3 = RSDK_GET_ENTITY(SceneInfo->entitySlot + 4, DDWrecker);
156
RSDK.ResetEntity(chain3, DDWrecker->classID, INT_TO_VOID(DDWRECKER_CHAIN));
157
chain3->position.x = self->position.x;
158
chain3->position.y = self->position.y + 0x400000;
159
160
EntityDDWrecker *chain4 = RSDK_GET_ENTITY(SceneInfo->entitySlot + 5, DDWrecker);
161
RSDK.ResetEntity(chain4, DDWrecker->classID, INT_TO_VOID(DDWRECKER_CHAIN));
162
chain4->position.x = self->position.x;
163
chain4->position.y = self->position.y + 0x400000;
164
165
EntityDDWrecker *core = RSDK_GET_ENTITY(SceneInfo->entitySlot + 3, DDWrecker);
166
RSDK.ResetEntity(core, DDWrecker->classID, INT_TO_VOID(DDWRECKER_CORE));
167
core->position.x = self->position.x;
168
core->position.y = self->position.y;
169
core->position.y += 0x200000;
170
core->originPos.x = self->position.x;
171
core->originPos.y = self->position.y;
172
core->originPos.y -= 0x800000;
173
core->velocity.y = -0x98000;
174
core->siblingSlots[0] = SceneInfo->entitySlot + 6; // Ball 1
175
core->siblingSlots[1] = SceneInfo->entitySlot + 1; // Chain 1
176
core->siblingSlots[2] = SceneInfo->entitySlot + 2; // Chain 2
177
core->siblingSlots[3] = SceneInfo->entitySlot + 4; // Chain 3
178
core->siblingSlots[4] = SceneInfo->entitySlot + 5; // Chain 4
179
core->siblingSlots[5] = SceneInfo->entitySlot + 7; // Ball 2
180
core->bodyA = RSDK_GET_ENTITY(SceneInfo->entitySlot + 6, DDWrecker);
181
core->bodyB = RSDK_GET_ENTITY(SceneInfo->entitySlot + 7, DDWrecker);
182
core->state = DDWrecker_State_Assemble;
183
184
EntityDDWrecker *ball1 = RSDK_GET_ENTITY(SceneInfo->entitySlot + 6, DDWrecker);
185
RSDK.ResetEntity(ball1, DDWrecker->classID, INT_TO_VOID(DDWRECKER_BALL1));
186
ball1->position.x = self->position.x;
187
ball1->position.y = self->position.y;
188
ball1->position.y += 0x400000;
189
ball1->siblingSlots[1] = SceneInfo->entitySlot + 2; // Chain 1
190
ball1->siblingSlots[2] = SceneInfo->entitySlot + 3; // Chain 2
191
ball1->siblingSlots[0] = SceneInfo->entitySlot + 1; // Core
192
ball1->siblingSlots[3] = SceneInfo->entitySlot + 4; // Chain 3
193
ball1->siblingSlots[4] = SceneInfo->entitySlot + 5; // Chain 4
194
ball1->siblingSlots[5] = SceneInfo->entitySlot + 7; // Ball 2
195
ball1->bodyA = RSDK_GET_ENTITY(SceneInfo->entitySlot + 6, DDWrecker);
196
ball1->bodyB = RSDK_GET_ENTITY(SceneInfo->entitySlot + 7, DDWrecker);
197
ball1->radius = 64;
198
199
EntityDDWrecker *ball2 = RSDK_GET_ENTITY(SceneInfo->entitySlot + 7, DDWrecker);
200
RSDK.ResetEntity(ball2, DDWrecker->classID, INT_TO_VOID(DDWRECKER_BALL2));
201
ball2->position.x = self->position.x;
202
ball2->position.y = self->position.y;
203
ball2->position.y += 0x400000;
204
ball2->siblingSlots[0] = SceneInfo->entitySlot + 1; // Chain 1
205
ball2->siblingSlots[1] = SceneInfo->entitySlot + 2; // Chain 2
206
ball2->siblingSlots[2] = SceneInfo->entitySlot + 3; // Core
207
ball2->siblingSlots[3] = SceneInfo->entitySlot + 4; // Chain 3
208
ball2->siblingSlots[4] = SceneInfo->entitySlot + 5; // Chain 4
209
ball2->siblingSlots[5] = SceneInfo->entitySlot + 6; // Ball 1
210
ball2->bodyB = RSDK_GET_ENTITY(SceneInfo->entitySlot + 7, DDWrecker);
211
ball2->bodyA = RSDK_GET_ENTITY(SceneInfo->entitySlot + 6, DDWrecker);
212
ball2->radius = 64;
213
214
destroyEntity(self);
215
}
216
}
217
else {
218
EntityPlayer *player = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);
219
220
if (player->position.x > self->position.x) {
221
Music_TransitionTrack(TRACK_MINIBOSS, 0.0125);
222
++self->timer;
223
}
224
}
225
}
226
227
void DDWrecker_State_Assemble(void)
228
{
229
RSDK_THIS(DDWrecker);
230
231
self->velocity.y += 0x4000;
232
self->position.y += self->velocity.y;
233
234
if (self->position.y > self->originPos.y && self->velocity.y > 0) {
235
self->position.y = self->originPos.y;
236
self->velocity.y = 0;
237
self->radius = 2048;
238
self->spinTimer = 128;
239
self->state = DDWrecker_State_EnterWreckers;
240
RSDK.PlaySfx(DDWrecker->sfxAssemble, false, 255);
241
}
242
}
243
244
void DDWrecker_State_EnterWreckers(void)
245
{
246
RSDK_THIS(DDWrecker);
247
248
self->spinAngle = (self->spinAngle + (self->spinTimer >> 1)) & 0x3FF;
249
self->radius += (64 - self->radius) >> 4;
250
self->position.y = BadnikHelpers_Oscillate(self->originPos.y, 2, 10);
251
252
DDWrecker_Spin();
253
254
if (self->spinTimer <= 0) {
255
self->timer = 30;
256
self->state = DDWrecker_State_AttackDelay;
257
foreach_active(DDWrecker, child)
258
{
259
if (child->type == DDWRECKER_BALL1 || child->type == DDWRECKER_BALL2)
260
child->stateBall = DDWrecker_StateBall_Vulnerable;
261
}
262
}
263
else {
264
self->spinTimer--;
265
}
266
}
267
268
void DDWrecker_State_AttackDelay(void)
269
{
270
RSDK_THIS(DDWrecker);
271
272
self->position.y = BadnikHelpers_Oscillate(self->originPos.y, 2, 10);
273
274
DDWrecker_Spin();
275
276
if (--self->timer < 1) {
277
if (self->bodyA->position.y - self->bodyB->position.y < 0) {
278
self->bodyA->originPos.x = self->originPos.x;
279
self->bodyA->originPos.y = self->originPos.y - 0x400000;
280
self->bodyA->velocity.x = 0;
281
self->bodyA->angle = self->angle;
282
self->bodyA->spinAngle = 0;
283
self->bodyA->timer = 4;
284
self->bodyA->state = DDWrecker_State_SwingLeft;
285
}
286
else {
287
self->bodyB->originPos.x = self->originPos.x;
288
self->bodyB->originPos.y = self->originPos.y - 0x400000;
289
self->bodyB->velocity.x = 0;
290
self->bodyB->angle = self->angle;
291
self->bodyB->spinAngle = 512;
292
self->bodyB->timer = 4;
293
self->bodyB->state = DDWrecker_State_SwingRight;
294
}
295
296
if (self->swapBalls) {
297
self->bodyA->stateBall = DDWrecker_StateBall_Vulnerable;
298
self->bodyB->stateBall = DDWrecker_StateBall_Spiked;
299
}
300
else {
301
self->bodyA->stateBall = DDWrecker_StateBall_Spiked;
302
self->bodyB->stateBall = DDWrecker_StateBall_Vulnerable;
303
}
304
305
RSDK.PlaySfx(DDWrecker->sfxSharp, false, 255);
306
self->state = StateMachine_None;
307
}
308
}
309
310
void DDWrecker_State_SwingRight(void)
311
{
312
RSDK_THIS(DDWrecker);
313
314
if (self->spinAngle < 0x200) {
315
self->position.x += self->velocity.x;
316
if (self->position.x < DDWrecker->camBoundL)
317
self->position.x = DDWrecker->camBoundL;
318
}
319
320
self->spinAngle += 4;
321
self->spinAngle &= 0x3FF;
322
self->position.y = BadnikHelpers_Oscillate(self->originPos.y, 2, 10);
323
324
DDWrecker_Swing();
325
326
if (self->spinAngle >= 0x300) {
327
if (--self->timer <= 0) {
328
EntityDDWrecker *core = RSDK_GET_ENTITY(self->siblingSlots[2], DDWrecker);
329
core->velocity.x = (core->originPos.x - core->position.x) >> 6;
330
core->velocity.y = (core->originPos.y - core->position.y) >> 6;
331
core->spinTimer = -2;
332
core->spinAngle = self->spinAngle;
333
core->angle = 0;
334
core->timer = 64;
335
core->state = DDWrecker_State_SwingMoveToCenter;
336
if (self == self->bodyB)
337
core->spinAngle += 0x200;
338
self->state = StateMachine_None;
339
340
self->bodyA->stateBall = DDWrecker_StateBall_Spiked;
341
self->bodyB->stateBall = DDWrecker_StateBall_Spiked;
342
RSDK.PlaySfx(DDWrecker->sfxSharp, false, 255);
343
}
344
else {
345
if (self->velocity.x)
346
self->velocity.x = DDWrecker->attackVelocities[0];
347
else
348
self->velocity.x = DDWrecker->attackVelocities[1];
349
350
self->state = DDWrecker_State_SwingLeft;
351
352
if (self->timer == 2) {
353
if (self->bodyA->stateBall == DDWrecker_StateBall_Vulnerable)
354
self->bodyA->stateBall = DDWrecker_StateBall_Spiked;
355
else
356
self->bodyA->stateBall = DDWrecker_StateBall_Vulnerable;
357
358
if (self->bodyB->stateBall == DDWrecker_StateBall_Vulnerable)
359
self->bodyB->stateBall = DDWrecker_StateBall_Spiked;
360
else
361
self->bodyB->stateBall = DDWrecker_StateBall_Vulnerable;
362
RSDK.PlaySfx(DDWrecker->sfxSharp, false, 0xFF);
363
}
364
}
365
}
366
}
367
368
void DDWrecker_State_SwingLeft(void)
369
{
370
RSDK_THIS(DDWrecker);
371
372
if (self->spinAngle >= 0x200) {
373
self->position.x += self->velocity.x;
374
if (self->position.x > DDWrecker->camBoundR)
375
self->position.x = DDWrecker->camBoundR;
376
}
377
378
self->spinAngle += 4;
379
self->spinAngle &= 0x3FF;
380
self->position.y = BadnikHelpers_Oscillate(self->originPos.y, 2, 10);
381
382
DDWrecker_Swing();
383
384
if (self->spinAngle >= 0x100 && self->spinAngle < 0x200) {
385
if (--self->timer <= 0) {
386
EntityDDWrecker *core = RSDK_GET_ENTITY(self->siblingSlots[2], DDWrecker);
387
core->velocity.x = (core->originPos.x - core->position.x) >> 6;
388
core->velocity.y = (core->originPos.y - core->position.y) >> 6;
389
core->spinTimer = 2;
390
core->spinAngle = self->spinAngle;
391
core->angle = 0;
392
core->timer = 64;
393
core->state = DDWrecker_State_SwingMoveToCenter;
394
if (self == self->bodyB)
395
core->spinAngle += 512;
396
self->state = StateMachine_None;
397
398
self->bodyA->stateBall = DDWrecker_StateBall_Spiked;
399
self->bodyB->stateBall = DDWrecker_StateBall_Spiked;
400
RSDK.PlaySfx(DDWrecker->sfxSharp, false, 0xFF);
401
}
402
else {
403
if (self->velocity.x)
404
self->velocity.x = -DDWrecker->attackVelocities[0];
405
else
406
self->velocity.x = -DDWrecker->attackVelocities[1];
407
408
self->state = DDWrecker_State_SwingRight;
409
410
if (self->timer == 2) {
411
if (self->bodyA->stateBall == DDWrecker_StateBall_Vulnerable)
412
self->bodyA->stateBall = DDWrecker_StateBall_Spiked;
413
else
414
self->bodyA->stateBall = DDWrecker_StateBall_Vulnerable;
415
416
if (self->bodyB->stateBall == DDWrecker_StateBall_Vulnerable)
417
self->bodyB->stateBall = DDWrecker_StateBall_Spiked;
418
else
419
self->bodyB->stateBall = DDWrecker_StateBall_Vulnerable;
420
RSDK.PlaySfx(DDWrecker->sfxSharp, false, 0xFF);
421
}
422
}
423
}
424
}
425
426
void DDWrecker_State_SwingMoveToCenter(void)
427
{
428
RSDK_THIS(DDWrecker);
429
430
self->position.x += self->velocity.x;
431
self->position.y += self->velocity.y;
432
433
if (self->velocity.x > 0) {
434
if (self->position.x > self->originPos.x) {
435
self->velocity.x = 0;
436
self->position.x = self->originPos.x;
437
}
438
}
439
else if (self->velocity.x < 0) {
440
if (self->position.x < self->originPos.x) {
441
self->velocity.x = 0;
442
self->position.x = self->originPos.x;
443
}
444
}
445
446
if (self->velocity.y < 0) {
447
if (self->position.y < self->originPos.y) {
448
self->velocity.y = 0;
449
self->position.y = self->originPos.y;
450
}
451
}
452
else if (self->velocity.y > 0) {
453
if (self->position.y > self->originPos.y) {
454
self->velocity.y = 0;
455
self->position.y = self->originPos.y;
456
}
457
}
458
459
if (!self->velocity.x && !self->velocity.y)
460
self->position.y = BadnikHelpers_Oscillate(self->originPos.y, 2, 10);
461
462
if (self->spinTimer <= 0) {
463
if (self->spinTimer > -141) {
464
self->spinTimer--;
465
}
466
else {
467
self->state = DDWrecker_State_HandleSpinning;
468
RSDK.PlaySfx(DDWrecker->sfxAssemble, false, 255);
469
}
470
}
471
else if (self->spinTimer >= 144) {
472
self->state = DDWrecker_State_HandleSpinning;
473
RSDK.PlaySfx(DDWrecker->sfxAssemble, false, 255);
474
}
475
else {
476
self->spinTimer++;
477
}
478
479
self->spinAngle = (self->spinAngle + (self->spinTimer >> 2)) & 0x3FF;
480
481
DDWrecker_Spin();
482
}
483
484
void DDWrecker_State_HandleSpinning(void)
485
{
486
RSDK_THIS(DDWrecker);
487
488
self->spinAngle = (self->spinAngle + (self->spinTimer >> 2)) & 0x3FF;
489
self->position.y = BadnikHelpers_Oscillate(self->originPos.y, 2, 10);
490
491
DDWrecker_Spin();
492
493
if (!--self->timer) {
494
self->state = DDWrecker_State_SwingSlowDown;
495
496
self->bodyA->stateBall = DDWrecker_StateBall_Vulnerable;
497
self->bodyB->stateBall = DDWrecker_StateBall_Vulnerable;
498
}
499
}
500
501
void DDWrecker_State_SwingSlowDown(void)
502
{
503
RSDK_THIS(DDWrecker);
504
505
if (self->spinTimer <= 0) {
506
if (self->spinTimer < -8)
507
self->spinTimer++;
508
}
509
else {
510
if (self->spinTimer > 8)
511
self->spinTimer--;
512
}
513
514
self->spinAngle = (self->spinAngle + (self->spinTimer >> 2)) & 0x3FF;
515
self->position.y = BadnikHelpers_Oscillate(self->originPos.y, 2, 10);
516
517
DDWrecker_Spin();
518
519
if (!(self->spinAngle & 0x1FC)) {
520
if (abs(self->spinTimer) <= 8) {
521
self->spinTimer = 0;
522
self->timer = 30;
523
self->spinAngle = (self->spinAngle + 0x80) & 0x300;
524
self->state = DDWrecker_State_AttackDelay;
525
}
526
}
527
}
528
529
void DDWrecker_State_PrepareBounceAttack(void)
530
{
531
RSDK_THIS(DDWrecker);
532
533
self->velocity.y -= 0x800;
534
self->position.x += self->velocity.x;
535
self->originPos.y += self->velocity.y;
536
537
if (self->originPos.y < DDWrecker->bossBoundT) {
538
self->originPos.y = DDWrecker->bossBoundT;
539
self->velocity.y = 0;
540
}
541
542
self->position.y = BadnikHelpers_Oscillate(self->originPos.y, 2, 10);
543
544
self->angleVel = 8;
545
if (self->position.x <= DDWrecker->bossBoundL) {
546
self->position.x = DDWrecker->bossBoundL;
547
self->velocity.x = 0;
548
549
if (self->originPos.y <= DDWrecker->bossBoundT)
550
self->state = DDWrecker_State_SignalBounceAttackStart;
551
}
552
else if (self->position.x >= DDWrecker->bossBoundR) {
553
self->position.x = DDWrecker->bossBoundR;
554
self->velocity.x = 0;
555
556
if (self->originPos.y <= DDWrecker->bossBoundT)
557
self->state = DDWrecker_State_SignalBounceAttackStart;
558
}
559
560
if (self->rotation < 0) {
561
if (self->rotation + 2 > 0)
562
self->rotation = 0;
563
else
564
self->rotation += 2;
565
}
566
else if (self->rotation > 0) {
567
self->rotation -= 2;
568
if (self->rotation < 0)
569
self->rotation = 0;
570
}
571
572
if (self->animator.animationID == 2) {
573
if (self->animator.frameID == self->animator.frameCount - 1)
574
RSDK.SetSpriteAnimation(DDWrecker->aniFrames, 0, &self->animator, true, 0);
575
}
576
else {
577
if (self->animator.animationID == 3 && !self->animator.frameID)
578
RSDK.SetSpriteAnimation(DDWrecker->aniFrames, 2, &self->animator, true, 0);
579
}
580
}
581
582
void DDWrecker_State_SignalBounceAttackStart(void)
583
{
584
RSDK_THIS(DDWrecker);
585
586
self->position.y = BadnikHelpers_Oscillate(self->originPos.y, 2, 10);
587
588
if (self->animator.animationID) {
589
if (self->animator.animationID == 1) {
590
if (self->animator.frameID == self->animator.frameCount - 1)
591
RSDK.SetSpriteAnimation(DDWrecker->aniFrames, 3, &self->animator, true, 0);
592
}
593
else {
594
if (self->animator.animationID == 3) {
595
if (self->animator.speed < 0x100) {
596
self->animator.speed += 2;
597
}
598
}
599
}
600
}
601
else {
602
RSDK.SetSpriteAnimation(DDWrecker->aniFrames, 1, &self->animator, true, 0);
603
RSDK.PlaySfx(DDWrecker->sfxSharp, false, 255);
604
}
605
606
if (++self->timer == 30) {
607
self->timer = 0;
608
self->velocity.y = -0x20000;
609
self->state = DDWrecker_State_HandleBounceAttack;
610
RSDK.PlaySfx(DDWrecker->sfxDrop, false, 255);
611
}
612
}
613
614
void DDWrecker_State_HandleBounceAttack(void)
615
{
616
RSDK_THIS(DDWrecker);
617
618
self->velocity.y += 0x3800;
619
self->position.x += self->velocity.x;
620
self->position.y += self->velocity.y;
621
622
self->animator.speed = 0x100 - 32 * self->timer;
623
624
if (self->velocity.y > 0) {
625
if (RSDK.ObjectTileCollision(self, Zone->collisionLayers, 0, 0, 0, 0x180000, true)) {
626
++self->timer;
627
Camera_ShakeScreen(0, 0, 3);
628
RSDK.PlaySfx(DDWrecker->sfxImpact, false, 255);
629
self->velocity.y = (self->velocity.y >> 3) - self->velocity.y;
630
631
if (self->timer >= 2) {
632
if (self->timer == 3) {
633
self->velocity.y = 0;
634
self->timer = 0;
635
self->originPos.y = self->position.y;
636
self->angleVel = 8;
637
self->state = DDWrecker_State_EndBounceAttack;
638
}
639
}
640
else {
641
if (self->position.x - (DDWrecker->bossBoundL + 0x100000) > 0)
642
self->velocity.x = -DDWrecker->attackVelocities[2];
643
else
644
self->velocity.x = DDWrecker->attackVelocities[2];
645
}
646
}
647
}
648
}
649
650
void DDWrecker_State_EndBounceAttack(void)
651
{
652
RSDK_THIS(DDWrecker);
653
654
if (self->animator.animationID == 2) {
655
if (self->animator.frameID == self->animator.frameCount - 1)
656
RSDK.SetSpriteAnimation(DDWrecker->aniFrames, 0, &self->animator, true, 0);
657
}
658
else {
659
if (self->animator.animationID == 3 && !self->animator.frameID)
660
RSDK.SetSpriteAnimation(DDWrecker->aniFrames, 2, &self->animator, true, 0);
661
}
662
663
if (++self->timer == 30) {
664
self->timer = 0;
665
self->state = DDWrecker_State_PrepareBounceAttack;
666
}
667
}
668
669
void DDWrecker_StateBall_Vulnerable(void)
670
{
671
RSDK_THIS(DDWrecker);
672
673
foreach_active(Player, player)
674
{
675
if (!self->invincibilityTimer && Player_CheckBadnikTouch(player, self, &self->hitbox) && Player_CheckBossHit(player, self)) {
676
DDWrecker_Hit();
677
RSDK.PlaySfx(DDWrecker->sfxBossHit, false, 255);
678
}
679
}
680
681
if (self->angleVel > 0) {
682
if (self->angleVel > 8)
683
self->angleVel--;
684
685
self->unusedAngle += self->angleVel;
686
if (self->unusedAngle >= 0x400) {
687
self->unusedAngle = 0;
688
self->angleVel = 0;
689
}
690
}
691
692
if (self->animator.animationID == 2) {
693
if (self->animator.frameID == self->animator.frameCount - 1)
694
RSDK.SetSpriteAnimation(DDWrecker->aniFrames, 0, &self->animator, true, 0);
695
}
696
else if (self->animator.animationID == 3 && !self->animator.frameID) {
697
RSDK.SetSpriteAnimation(DDWrecker->aniFrames, 2, &self->animator, true, 0);
698
}
699
700
if (self->blendAmount > 0)
701
self->blendAmount -= 0x10;
702
}
703
704
void DDWrecker_StateBall_Spiked(void)
705
{
706
RSDK_THIS(DDWrecker);
707
708
foreach_active(Player, player)
709
{
710
if (!self->invincibilityTimer && Player_CheckBadnikTouch(player, self, &self->hitbox)) {
711
if (player->invincibleTimer || player->blinkTimer > 0 || self->animator.animationID < 3) {
712
if (Player_CheckBossHit(player, self)) {
713
DDWrecker_Hit();
714
RSDK.PlaySfx(DDWrecker->sfxBossHit, false, 255);
715
}
716
}
717
else {
718
Player_Hurt(player, self);
719
}
720
}
721
}
722
723
if (self->animator.animationID) {
724
if (self->animator.animationID == 1) {
725
if (self->animator.frameID == self->animator.frameCount - 1)
726
RSDK.SetSpriteAnimation(DDWrecker->aniFrames, 3, &self->animator, true, 0);
727
}
728
else if (self->animator.animationID == 3) {
729
if (self->animator.speed < 0x100)
730
self->animator.speed += 2;
731
}
732
}
733
else {
734
RSDK.SetSpriteAnimation(DDWrecker->aniFrames, 1, &self->animator, true, 0);
735
}
736
737
if (self->angleVel < 48)
738
self->angleVel += 2;
739
740
self->unusedAngle = (self->unusedAngle + self->angleVel) & 0x3FF;
741
742
if (self->blendAmount < 0x100)
743
self->blendAmount += 0x10;
744
}
745
746
void DDWrecker_StateBall_Partnerless(void)
747
{
748
RSDK_THIS(DDWrecker);
749
750
foreach_active(Player, player)
751
{
752
if (!self->invincibilityTimer && Player_CheckBadnikTouch(player, self, &self->hitbox)) {
753
if (player->invincibleTimer || player->blinkTimer > 0 || self->animator.animationID < 3) {
754
if (Player_CheckBossHit(player, self)) {
755
DDWrecker_Hit();
756
RSDK.PlaySfx(DDWrecker->sfxBossHit, false, 255);
757
}
758
}
759
else {
760
Player_Hurt(player, self);
761
}
762
}
763
}
764
765
self->unusedAngle = (self->unusedAngle + self->angleVel) & 0x3FF;
766
767
if (self->animator.animationID == 0) {
768
if (self->blendAmount > 0)
769
self->blendAmount -= 0x10;
770
}
771
else if (self->blendAmount < 0x100)
772
self->blendAmount += 0x10;
773
}
774
void DDWrecker_Hit(void)
775
{
776
RSDK_THIS(DDWrecker);
777
778
if (--self->health <= 0) {
779
self->state = DDWrecker_State_Die;
780
self->stateBall = StateMachine_None;
781
self->timer = 0;
782
foreach_active(DDWrecker, child)
783
{
784
if (self != child) {
785
switch (child->type) {
786
case DDWRECKER_BALL1:
787
case DDWRECKER_BALL2:
788
if (child->stateBall) {
789
child->state = DDWrecker_State_EndBounceAttack;
790
child->originPos.y = child->position.y;
791
child->velocity.x = -DDWrecker->attackVelocities[2];
792
child->stateBall = DDWrecker_StateBall_Partnerless;
793
}
794
break;
795
796
case DDWRECKER_CHAIN:
797
case DDWRECKER_CORE:
798
if (child->state != DDWrecker_State_Debris) {
799
child->state = DDWrecker_State_Debris;
800
child->velocity.x = RSDK.Rand(-0x20000, 0x20000);
801
child->velocity.y = RSDK.Rand(-0x20000, 0x20000);
802
}
803
break;
804
805
default: break;
806
}
807
}
808
}
809
}
810
else {
811
self->invincibilityTimer = 48;
812
RSDK.PlaySfx(DDWrecker->sfxBossHit, false, 255);
813
}
814
}
815
void DDWrecker_Spin(void)
816
{
817
RSDK_THIS(DDWrecker);
818
819
for (int32 i = 0; i < 6; ++i) {
820
EntityDDWrecker *chain = RSDK_GET_ENTITY(self->siblingSlots[i], DDWrecker);
821
chain->position.x = self->position.x + (DDWrecker->spinOffset[i] * RSDK.Sin1024(self->spinAngle) * self->radius);
822
chain->position.y = self->position.y + (DDWrecker->spinOffset[i] * RSDK.Cos1024(self->spinAngle) * self->radius);
823
824
int32 rot = chain->rotation;
825
if (rot < 0) {
826
if (rot < 0) {
827
rot += 2;
828
if (rot > 0)
829
chain->rotation = 0;
830
else
831
chain->rotation = rot;
832
}
833
}
834
else if (rot > 0) {
835
rot -= 2;
836
if (rot - 2 < 0)
837
chain->rotation = 0;
838
else
839
chain->rotation = rot;
840
}
841
}
842
}
843
void DDWrecker_Swing(void)
844
{
845
RSDK_THIS(DDWrecker);
846
int32 angle = RSDK.Sin1024(self->spinAngle) >> 2;
847
self->rotation = RSDK.Sin1024(-self->spinAngle) >> 6;
848
849
if (!self->angleVel)
850
self->unusedAngle = RSDK.Sin1024(-self->spinAngle) >> 5;
851
852
EntityDDWrecker *chain = NULL;
853
for (int32 i = 0; i < 6; ++i) {
854
chain = RSDK_GET_ENTITY(self->siblingSlots[i], DDWrecker);
855
chain->position.x = self->position.x + (DDWrecker->swingOffset[i] * RSDK.Sin1024(angle) * self->radius);
856
chain->position.y = self->position.y + (DDWrecker->swingOffset[i] * RSDK.Cos1024(angle) * self->radius);
857
}
858
chain->rotation = RSDK.Sin1024(-self->spinAngle) >> 5;
859
}
860
861
void DDWrecker_Explode(void)
862
{
863
RSDK_THIS(DDWrecker);
864
865
if (!(Zone->timer % 3)) {
866
RSDK.PlaySfx(DDWrecker->sfxExplosion, false, 255);
867
868
if (Zone->timer & 4) {
869
int32 x = self->position.x + (RSDK.Rand(-20, 20) << 16);
870
int32 y = self->position.y + (RSDK.Rand(-20, 20) << 16);
871
EntityExplosion *explosion = CREATE_ENTITY(Explosion, INT_TO_VOID((RSDK.Rand(0, 256) > 192) + EXPLOSION_BOSS), x, y);
872
873
explosion->drawGroup = Zone->objectDrawGroup[1];
874
}
875
}
876
}
877
878
void DDWrecker_State_Debris(void)
879
{
880
RSDK_THIS(DDWrecker);
881
882
self->velocity.y += 0x3800;
883
self->position.x += self->velocity.x;
884
self->position.y += self->velocity.y;
885
886
if (!RSDK.CheckOnScreen(self, NULL))
887
destroyEntity(self);
888
}
889
890
void DDWrecker_State_Die(void)
891
{
892
RSDK_THIS(DDWrecker);
893
894
DDWrecker_Explode();
895
896
if (++self->timer == 80) {
897
int32 cnt = 0;
898
foreach_active(DDWrecker, child) { ++cnt; }
899
900
if (cnt != 1) {
901
destroyEntity(self);
902
}
903
else {
904
Music_TransitionTrack(TRACK_STAGE, 0.0125);
905
self->timer = 0;
906
self->visible = false;
907
self->state = DDWrecker_State_SpawnSignpost;
908
SceneInfo->timeEnabled = false;
909
Player_GiveScore(RSDK_GET_ENTITY(SLOT_PLAYER1, Player), 1000);
910
}
911
}
912
}
913
void DDWrecker_State_SpawnSignpost(void)
914
{
915
RSDK_THIS(DDWrecker);
916
917
if (++self->timer == 48) {
918
foreach_all(SignPost, signPost)
919
{
920
signPost->position.x = self->position.x;
921
signPost->state = SignPost_State_Falling;
922
RSDK.PlaySfx(SignPost->sfxTwinkle, false, 255);
923
}
924
destroyEntity(self);
925
}
926
}
927
928
#if GAME_INCLUDE_EDITOR
929
void DDWrecker_EditorDraw(void)
930
{
931
RSDK_THIS(DDWrecker);
932
933
RSDK.SetSpriteAnimation(DDWrecker->aniFrames, 0, &self->animator, false, 0);
934
935
RSDK.DrawSprite(&self->animator, NULL, false);
936
937
if (showGizmos()) {
938
RSDK_DRAWING_OVERLAY(true);
939
DrawHelpers_DrawArenaBounds(-WIDE_SCR_XCENTER, -SCREEN_YSIZE, WIDE_SCR_XCENTER, 0, 1 | 0 | 4 | 8, 0x00C0F0);
940
941
int32 slot = RSDK.GetEntitySlot(self);
942
for (int32 i = 0; i < 6; ++i) {
943
EntityDDWrecker *child = RSDK_GET_ENTITY(slot + 1 + i, DDWrecker);
944
945
if (child)
946
DrawHelpers_DrawArrow(self->position.x, self->position.y, child->position.x, child->position.y, 0xFFFF00, INK_NONE, 0xFF);
947
}
948
949
RSDK_DRAWING_OVERLAY(false);
950
}
951
}
952
953
void DDWrecker_EditorLoad(void) { DDWrecker->aniFrames = RSDK.LoadSpriteAnimation("GHZ/DDWrecker.bin", SCOPE_STAGE); }
954
#endif
955
956
void DDWrecker_Serialize(void) {}
957
958