Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/ERZ/PhantomKing.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: PhantomKing Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectPhantomKing *PhantomKing;
11
12
void PhantomKing_Update(void)
13
{
14
RSDK_THIS(PhantomKing);
15
16
if (self->invincibilityTimer > 0)
17
self->invincibilityTimer--;
18
19
StateMachine_Run(self->state);
20
}
21
22
void PhantomKing_LateUpdate(void) {}
23
24
void PhantomKing_StaticUpdate(void) {}
25
26
void PhantomKing_Draw(void)
27
{
28
RSDK_THIS(PhantomKing);
29
30
if (self->stateDraw) {
31
StateMachine_Run(self->stateDraw);
32
}
33
else {
34
RSDK.DrawSprite(&self->basicAnimator, NULL, false);
35
}
36
}
37
38
void PhantomKing_Create(void *data)
39
{
40
RSDK_THIS(PhantomKing);
41
42
self->drawFX = FX_FLIP;
43
if (!SceneInfo->inEditor) {
44
self->updateRange.x = 0x800000;
45
self->updateRange.y = 0x1000000;
46
self->drawGroup = Zone->objectDrawGroup[0];
47
self->drawFX = FX_ROTATE | FX_FLIP;
48
self->type = VOID_TO_INT(data);
49
50
switch (self->type) {
51
case PHANTOMKING_KING:
52
self->hitbox.left = -24;
53
self->hitbox.top = -24;
54
self->hitbox.right = 24;
55
self->hitbox.bottom = 24;
56
57
self->active = ACTIVE_BOUNDS;
58
self->visible = false;
59
self->direction = FLIP_X;
60
self->health = 8;
61
62
RSDK.SetSpriteAnimation(PhantomKing->aniFrames, 0, &self->headAnimator, true, 0);
63
RSDK.SetSpriteAnimation(PhantomKing->aniFrames, 1, &self->bodyAnimator, true, 0);
64
RSDK.SetSpriteAnimation(PhantomKing->aniFrames, 2, &self->beltAnimator, true, 0);
65
RSDK.SetSpriteAnimation(PhantomKing->aniFrames, 7, &self->particleAnimator, true, 0);
66
RSDK.SetSpriteAnimation(PhantomKing->aniFrames, 8, &self->rubyAnimator, true, 0);
67
68
self->originPos = self->position;
69
self->state = PhantomKing_State_Initialize;
70
break;
71
72
case PHANTOMKING_ARM_L:
73
case PHANTOMKING_ARM_R:
74
self->active = ACTIVE_NORMAL;
75
self->visible = true;
76
77
RSDK.SetSpriteAnimation(PhantomKing->aniFrames, 3, &self->armAnimator, true, 0);
78
RSDK.SetSpriteAnimation(PhantomKing->aniFrames, 4, &self->cuffAnimator, true, 0);
79
80
if (self->type == PHANTOMKING_ARM_L) {
81
RSDK.SetSpriteAnimation(PhantomKing->aniFrames, 6, &self->handAnimator, true, 0);
82
}
83
else {
84
self->drawGroup = Zone->playerDrawGroup[0];
85
RSDK.SetSpriteAnimation(PhantomKing->aniFrames, 5, &self->handAnimator, true, 0);
86
}
87
88
self->stateDraw = PhantomKing_Draw_Arm;
89
self->state = PhantomKing_StateArm_Idle;
90
break;
91
}
92
}
93
}
94
95
void PhantomKing_StageLoad(void)
96
{
97
PhantomKing->aniFrames = RSDK.LoadSpriteAnimation("Phantom/PhantomKing.bin", SCOPE_STAGE);
98
99
PhantomKing->sfxHit = RSDK.GetSfx("Stage/BossHit.wav");
100
PhantomKing->sfxExplosion = RSDK.GetSfx("Stage/Explosion2.wav");
101
}
102
103
void PhantomKing_CheckPlayerCollisions(void)
104
{
105
RSDK_THIS(PhantomKing);
106
107
foreach_active(Player, player)
108
{
109
if (!self->invincibilityTimer && Player_CheckBadnikTouch(player, self, &self->hitbox) && Player_CheckBossHit(player, self)) {
110
PhantomKing_Hit();
111
}
112
}
113
}
114
115
void PhantomKing_Oscillate(void)
116
{
117
RSDK_THIS(PhantomKing);
118
119
self->angle = (self->angle + 3) & 0xFF;
120
self->position.y = (RSDK.Sin256(self->angle) << 10) + self->originPos.y;
121
}
122
123
void PhantomKing_Hit(void)
124
{
125
RSDK_THIS(PhantomKing);
126
127
foreach_all(PhantomRuby, ruby)
128
{
129
ruby->position.x = self->rubyPos.x;
130
ruby->position.y = self->rubyPos.y;
131
ruby->velocity.x = -0x20000;
132
ruby->velocity.y = -0x40000;
133
ruby->state = PhantomRuby_State_MoveGravity;
134
}
135
136
self->drawRuby = false;
137
if (--self->health <= 0) {
138
self->originPos.x = self->position.x;
139
self->originPos.y = self->position.y;
140
self->state = PhantomKing_State_Explode;
141
self->velocity.y = -0x10000;
142
self->timer = 0;
143
144
foreach_active(PKingAttack, attack)
145
{
146
if (attack->state == PKingAttack_State_Orbiting)
147
destroyEntity(attack);
148
}
149
150
if (KleptoMobile->defeated)
151
SceneInfo->timeEnabled = false;
152
153
Player_GiveScore(RSDK_GET_ENTITY(SLOT_PLAYER1, Player), 1000);
154
}
155
else {
156
self->invincibilityTimer = 48;
157
RSDK.PlaySfx(PhantomKing->sfxHit, false, 255);
158
self->state = PhantomKing_State_HitFall;
159
}
160
}
161
162
void PhantomKing_Explode(void)
163
{
164
RSDK_THIS(PhantomKing);
165
166
if (!(Zone->timer % 7)) {
167
RSDK.PlaySfx(PhantomKing->sfxExplosion, false, 255);
168
169
if (Zone->timer & 8) {
170
int32 x = self->position.x + (RSDK.Rand(self->hitbox.left, self->hitbox.right) << 16);
171
int32 y = self->position.y + (RSDK.Rand(self->hitbox.top, self->hitbox.bottom) << 16);
172
CREATE_ENTITY(Explosion, INT_TO_VOID((RSDK.Rand(0, 256) > 192) + EXPLOSION_BOSS), x, y)->drawGroup = Zone->objectDrawGroup[1];
173
}
174
}
175
}
176
177
void PhantomKing_HandleFrames(void)
178
{
179
RSDK_THIS(PhantomKing);
180
181
RSDK.ProcessAnimation(&self->bodyAnimator);
182
183
if (self->state != PhantomKing_State_WrestleEggman) {
184
int32 max = self->velocity.x >> 15;
185
186
if (self->rotation >= max) {
187
if (self->rotation > max) {
188
self->rotation--;
189
if (self->rotation < max)
190
self->rotation = self->velocity.x >> 15;
191
}
192
}
193
else {
194
self->rotation++;
195
if (self->rotation > max)
196
self->rotation = max;
197
}
198
}
199
200
int32 negAng = -self->rotation;
201
self->bodyAngle = (self->bodyAngle + 12) & 0x3FF;
202
203
int32 x = 0x1C00 * RSDK.Sin512(negAng) + self->position.x;
204
int32 y = 0x1C00 * RSDK.Cos512(negAng) + self->position.y;
205
206
int32 angle = self->bodyAngle;
207
208
for (int32 i = 0; i < 10; i += 2) {
209
self->armPositions[i].x = x + 2 * RSDK.Cos512(self->rotation) * RSDK.Cos1024(angle);
210
self->armPositions[i].y = y + 2 * RSDK.Sin512(self->rotation) * RSDK.Cos1024(angle);
211
self->armAngles[i] = angle & 0x3FF;
212
213
angle += 512;
214
215
self->armPositions[i + 1].x = x + 2 * RSDK.Cos512(self->rotation) * RSDK.Cos1024(angle);
216
self->armPositions[i + 1].y = y + 2 * RSDK.Sin512(self->rotation) * RSDK.Cos1024(angle);
217
self->armAngles[i + 1] = angle & 0x3FF;
218
219
x += RSDK.Sin512(negAng) << 10;
220
y += RSDK.Cos512(negAng) << 10;
221
angle += 0x240;
222
}
223
224
self->rubyPos.x = self->position.x - 0x1400 * RSDK.Sin512(negAng);
225
self->rubyPos.y = self->position.y - 0x1400 * RSDK.Cos512(negAng);
226
if (self->direction) {
227
self->rubyPos.x -= 0x180 * RSDK.Cos512(negAng);
228
self->rubyPos.y -= 0x180 * RSDK.Sin512(negAng);
229
}
230
else {
231
self->rubyPos.x += 0x180 * RSDK.Cos512(negAng);
232
self->rubyPos.y += 0x180 * RSDK.Sin512(negAng);
233
}
234
}
235
236
void PhantomKing_HandleAttacks(void)
237
{
238
RSDK_THIS(PhantomKing);
239
240
EntityPlayer *player = Player_GetNearestPlayer();
241
bool32 launchedAttack = false;
242
243
foreach_active(PKingAttack, attack)
244
{
245
if (attack->state == PKingAttack_State_Orbiting) {
246
PhantomRuby_PlaySfx(RSDK.Rand(RUBYSFX_ATTACK1, RUBYSFX_REDCUBE));
247
attack->type = PKINGATTACK_LAUNCHED;
248
int32 angle = RSDK.ATan2((player->position.x - attack->position.x) >> 16, (player->position.y - attack->position.y) >> 16);
249
250
attack->targetVelocity.x = 0x600 * RSDK.Cos256(angle);
251
attack->targetVelocity.y = 0x600 * RSDK.Sin256(angle);
252
attack->drawGroup = Zone->objectDrawGroup[0];
253
attack->state = PKingAttack_State_OrbitLaunched;
254
launchedAttack = true;
255
foreach_break;
256
}
257
}
258
259
if (!launchedAttack) {
260
// No More Attacks, lets make more
261
for (int32 i = 0; i < 0x3FC; i += 0xAA) {
262
EntityPKingAttack *attackOrb = CREATE_ENTITY(PKingAttack, INT_TO_VOID(PKINGATTACK_ORBIT), self->position.x, self->position.y);
263
attackOrb->angle = i;
264
attackOrb->target = (Entity *)self;
265
}
266
self->timer = -90;
267
}
268
}
269
270
void PhantomKing_SwitchToEggman(void)
271
{
272
EntityKleptoMobile *eggmanPtr = NULL;
273
274
foreach_active(KleptoMobile, eggman)
275
{
276
if (eggman->type == KLEPTOMOBILE_EGGMAN) {
277
EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);
278
279
eggman->direction = FLIP_X;
280
if (RSDK.Rand(0, 2))
281
eggman->position.x = player1->position.x + 0x1000000;
282
else
283
eggman->position.x = player1->position.x - 0x1000000;
284
285
eggman->position.y = player1->position.y + 0x800000;
286
eggman->originPos.y = player1->position.y + 0x800000;
287
eggman->holdingRuby = true;
288
eggman->velocity.x = 0;
289
eggman->velocity.y = 0;
290
eggman->state = KleptoMobile_State_MoveAround;
291
292
eggmanPtr = eggman;
293
foreach_break;
294
}
295
}
296
297
foreach_active(KleptoMobile, eggmanArm)
298
{
299
if (eggmanArm->type != KLEPTOMOBILE_EGGMAN) {
300
eggmanArm->position.x = eggmanPtr->position.x;
301
eggmanArm->position.y = eggmanPtr->position.y;
302
303
for (int32 i = 0; i < 10; ++i) eggmanArm->armPositions[i] = eggmanPtr->position;
304
305
eggmanArm->velocity.x = 0;
306
eggmanArm->velocity.y = 0;
307
}
308
}
309
}
310
311
void PhantomKing_SetupKing(EntityPhantomKing *king)
312
{
313
king->originPos = king->position;
314
king->velocity.x = 0;
315
king->drawRuby = true;
316
317
PhantomKing->boundsM = king->position.x;
318
PhantomKing->boundsL = PhantomKing->boundsM - 0x800000;
319
PhantomKing->boundsR = PhantomKing->boundsM + 0x800000;
320
PhantomKing->boundsT = (Zone->cameraBoundsT[0] + 48) << 16;
321
PhantomKing->boundsB = (Zone->cameraBoundsB[0] - 96) << 16;
322
323
int32 slot = RSDK.GetEntitySlot(king);
324
RSDK_GET_ENTITY(slot - 1, PhantomKing)->state = PhantomKing_StateArm_Idle;
325
RSDK_GET_ENTITY(slot + 1, PhantomKing)->state = PhantomKing_StateArm_Idle;
326
king->state = PhantomKing_State_FlyAround;
327
}
328
329
void PhantomKing_Draw_Body(void)
330
{
331
RSDK_THIS(PhantomKing);
332
333
if (self->typeChangeTimer <= 0) {
334
if (self->invincibilityTimer & 1)
335
RSDK.CopyPalette(2, 128, 0, 128, 128);
336
}
337
else {
338
RSDK.SetLimitedFade(0, 1, 4, self->typeChangeTimer, 0, 48);
339
RSDK.SetLimitedFade(0, 1, 4, self->typeChangeTimer, 128, 256);
340
}
341
342
RSDK.DrawSprite(&self->headAnimator, NULL, false);
343
RSDK.DrawSprite(&self->bodyAnimator, NULL, false);
344
345
for (int32 i = 0; i < 10; ++i) {
346
if (self->armAngles[i] < 0x200) {
347
self->particleAnimator.frameID = self->armAngles[i] / 42 % 6;
348
RSDK.DrawSprite(&self->particleAnimator, &self->armPositions[i], false);
349
}
350
}
351
352
self->drawFX = self->storeDrawFX | FX_ROTATE;
353
RSDK.DrawSprite(&self->beltAnimator, NULL, false);
354
self->drawFX = self->storeDrawFX | FX_ROTATE | FX_FLIP;
355
356
for (int32 i = 0; i < 10; ++i) {
357
if (self->armAngles[i] >= 0x200) {
358
self->particleAnimator.frameID = self->armAngles[i] / 42 % 6;
359
RSDK.DrawSprite(&self->particleAnimator, &self->armPositions[i], false);
360
}
361
}
362
363
if (self->drawRuby)
364
RSDK.DrawSprite(&self->rubyAnimator, &self->rubyPos, false);
365
366
if (self->typeChangeTimer <= 0) {
367
if (self->invincibilityTimer & 1)
368
RSDK.CopyPalette(1, 128, 0, 128, 128);
369
}
370
else {
371
RSDK.CopyPalette(1, 0, 0, 0, 48);
372
RSDK.CopyPalette(1, 128, 0, 128, 128);
373
}
374
}
375
376
void PhantomKing_Draw_Arm(void)
377
{
378
RSDK_THIS(PhantomKing);
379
380
EntityPhantomKing *parent = self->parent;
381
382
if (parent->typeChangeTimer > 0) {
383
RSDK.SetLimitedFade(0, 1, 4, parent->typeChangeTimer, 0, 48);
384
RSDK.SetLimitedFade(0, 1, 4, parent->typeChangeTimer, 128, 256);
385
}
386
387
for (int32 i = 0; i < 6; ++i) RSDK.DrawSprite(&self->armAnimator, &self->armPositions[i], false);
388
389
RSDK.DrawSprite(&self->cuffAnimator, &self->armPositions[6], false);
390
RSDK.DrawSprite(&self->handAnimator, &self->armPositions[6], false);
391
392
if (parent->typeChangeTimer > 0) {
393
RSDK.CopyPalette(1, 0, 0, 0, 48);
394
RSDK.CopyPalette(1, 128, 0, 128, 128);
395
}
396
}
397
398
void PhantomKing_State_Initialize(void)
399
{
400
RSDK_THIS(PhantomKing);
401
402
if (++self->timer >= 8) {
403
self->position.y += 0x1000000;
404
self->timer = 0;
405
self->active = ACTIVE_NORMAL;
406
self->state = StateMachine_None;
407
}
408
}
409
410
void PhantomKing_State_SetupArms(void)
411
{
412
RSDK_THIS(PhantomKing);
413
414
self->direction = RSDK_GET_ENTITY(SLOT_PLAYER1, Player)->position.x < self->position.x;
415
416
if (++self->timer == 30) {
417
EntityPhantomKing *armL = RSDK_GET_ENTITY(SceneInfo->entitySlot - 1, PhantomKing);
418
RSDK.ResetEntity(armL, PhantomKing->classID, INT_TO_VOID(PHANTOMKING_ARM_L));
419
armL->position.x = self->position.x;
420
armL->position.y = self->position.y;
421
armL->parent = self;
422
armL->armRadius = 0x2800;
423
armL->armAngle = 96;
424
armL->armAngleOffset = 32;
425
426
EntityPhantomKing *armR = RSDK_GET_ENTITY(SceneInfo->entitySlot + 1, PhantomKing);
427
RSDK.ResetEntity(armR, PhantomKing->classID, INT_TO_VOID(PHANTOMKING_ARM_R));
428
armR->position.x = self->position.x;
429
armR->position.y = self->position.y;
430
armR->parent = self;
431
armR->armRadius = 0x2800;
432
armR->armAngle = 96;
433
armR->armAngleOffset = 32;
434
435
self->timer = 0;
436
self->visible = true;
437
self->stateDraw = PhantomKing_Draw_Body;
438
self->state = PhantomKing_State_EnterKing;
439
}
440
}
441
442
void PhantomKing_State_EnterKing(void)
443
{
444
RSDK_THIS(PhantomKing);
445
446
RSDK.ProcessAnimation(&self->beltAnimator);
447
448
self->velocity.y -= 0x800;
449
450
if (self->position.y <= self->originPos.y) {
451
self->originPos.x = self->position.x;
452
self->originPos.y = self->originPos.y;
453
self->position.y = self->originPos.y;
454
RSDK_GET_ENTITY(SceneInfo->entitySlot - 1, PhantomKing)->state = PhantomKing_StateArm_PullBack;
455
self->velocity.y = 0;
456
self->state = PhantomKing_State_InitialHover;
457
}
458
else {
459
self->position.y += self->velocity.y;
460
}
461
PhantomKing_HandleFrames();
462
}
463
464
void PhantomKing_State_InitialHover(void)
465
{
466
RSDK_THIS(PhantomKing);
467
468
RSDK.ProcessAnimation(&self->beltAnimator);
469
470
PhantomKing_Oscillate();
471
472
PhantomKing_HandleFrames();
473
474
if (++self->timer >= 120) {
475
self->timer = 0;
476
self->state = PhantomKing_State_TakeRubyAway;
477
}
478
}
479
480
void PhantomKing_State_TakeRubyAway(void)
481
{
482
RSDK_THIS(PhantomKing);
483
484
RSDK.ProcessAnimation(&self->beltAnimator);
485
486
PhantomKing_Oscillate();
487
488
if (self->velocity.x < 0x40000)
489
self->velocity.x += 0x1800;
490
491
self->position.x += self->velocity.x;
492
493
PhantomKing_HandleFrames();
494
495
if (++self->timer >= 180) {
496
RSDK_GET_ENTITY(SceneInfo->entitySlot - 1, PhantomKing)->state = PhantomKing_StateArm_Idle;
497
self->velocity.x = 0;
498
self->velocity.y = 0;
499
self->state = PhantomKing_State_RubyHoldHover;
500
self->finishedMovingRuby = true;
501
}
502
}
503
504
void PhantomKing_State_RubyHoldHover(void)
505
{
506
RSDK_THIS(PhantomKing);
507
508
RSDK.ProcessAnimation(&self->beltAnimator);
509
510
PhantomKing_Oscillate();
511
512
PhantomKing_HandleFrames();
513
}
514
515
void PhantomKing_State_WrestleEggman(void)
516
{
517
RSDK_THIS(PhantomKing);
518
519
RSDK.ProcessAnimation(&self->beltAnimator);
520
RSDK.ProcessAnimation(&self->rubyAnimator);
521
522
PhantomKing_Oscillate();
523
524
self->position.x += self->velocity.x;
525
self->position.y += self->velocity.y;
526
527
PhantomKing_HandleFrames();
528
}
529
530
void PhantomKing_State_FlyAround(void)
531
{
532
RSDK_THIS(PhantomKing);
533
534
RSDK.ProcessAnimation(&self->beltAnimator);
535
536
PhantomKing_Oscillate();
537
538
PhantomKing_CheckPlayerCollisions();
539
540
EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);
541
542
int32 angle = RSDK.ATan2(self->position.x - player1->position.x, self->originPos.y - player1->position.y);
543
int32 x = (RSDK.Cos256(angle) << 15) + player1->position.x;
544
int32 y = (RSDK.Sin256(angle) << 15) + player1->position.y;
545
546
if (x <= self->position.x) {
547
if (self->velocity.x > -0x20000)
548
self->velocity.x -= 0x800;
549
}
550
else {
551
if (self->velocity.x < 0x20000)
552
self->velocity.x += 0x800;
553
}
554
555
int32 bottom = Zone->cameraBoundsB[0] << 16;
556
if (y > bottom - 0x400000)
557
y = bottom - 0x800000;
558
559
if (y <= self->originPos.y) {
560
if (self->velocity.y > -0x20000)
561
self->velocity.y -= 0x800;
562
}
563
else {
564
if (self->velocity.y < 0x20000)
565
self->velocity.y += 0x800;
566
}
567
568
self->originPos.y += self->velocity.y;
569
self->position.x += self->velocity.x;
570
self->direction = player1->position.x <= self->position.x;
571
572
if (self->canLaunchAttacks) {
573
if (++self->timer >= 60) {
574
self->timer = 0;
575
PhantomKing_HandleAttacks();
576
}
577
}
578
else if (self->onScreen == 1) {
579
self->canLaunchAttacks = true;
580
}
581
582
PhantomKing_HandleFrames();
583
}
584
585
void PhantomKing_State_Switch(void)
586
{
587
RSDK_THIS(PhantomKing);
588
589
if (++self->timer >= 120) {
590
self->timer = 0;
591
PhantomKing_SwitchToEggman();
592
self->state = StateMachine_None;
593
}
594
}
595
596
void PhantomKing_State_HitFall(void)
597
{
598
RSDK_THIS(PhantomKing);
599
600
RSDK.ProcessAnimation(&self->beltAnimator);
601
602
self->position.y += self->velocity.y;
603
self->velocity.y -= 0x3800;
604
605
if (self->position.y < -0x1000000) {
606
foreach_active(PKingAttack, attack)
607
{
608
if (attack->state == PKingAttack_State_Orbiting)
609
destroyEntity(attack);
610
}
611
612
self->canLaunchAttacks = false;
613
self->velocity.y = 0;
614
self->timer = 0;
615
self->state = PhantomKing_State_Switch;
616
}
617
618
PhantomKing_HandleFrames();
619
}
620
621
void PhantomKing_StateArm_Idle(void)
622
{
623
RSDK_THIS(PhantomKing);
624
625
EntityPhantomKing *parent = self->parent;
626
627
int32 parentX = parent->position.x;
628
int32 parentY = parent->position.y;
629
630
int32 moveX = 0;
631
int32 moveY = ((RSDK.Sin256(2 * (Zone->timer + (self->type << 6)) - 128) + 512) << 12) + parentY;
632
633
self->direction = parent->direction;
634
int32 negAngle = -parent->rotation;
635
636
int32 x = 0;
637
int32 y = 0;
638
639
int32 x2 = 0;
640
int32 y2 = 0;
641
642
if (self->direction) {
643
moveX = parentX - 0x300000;
644
x = 0xD00 * RSDK.Cos512(negAngle) + 0x300 * RSDK.Sin512(negAngle) + parent->position.x;
645
y = parent->position.y - 0xD00 * RSDK.Sin512(negAngle) + 0x300 * RSDK.Cos512(negAngle);
646
647
if (self->type == PHANTOMKING_ARM_L) {
648
x += -0x1800 * RSDK.Cos512(negAngle);
649
y += 0x1800 * RSDK.Sin512(negAngle);
650
moveX -= 0x300000;
651
}
652
653
x2 = ((self->position.x + x) >> 1) + 0x200000;
654
y2 = ((self->position.y + y) >> 1) + 0x200000;
655
}
656
else {
657
moveX = parentX + 0x300000;
658
x = 0x300 * RSDK.Sin512(negAngle) - 0xD00 * RSDK.Cos512(negAngle) + parent->position.x;
659
y = 0xD00 * RSDK.Sin512(negAngle) + 0x300 * RSDK.Cos512(negAngle) + parent->position.y;
660
661
if (self->type == PHANTOMKING_ARM_L) {
662
x += 0x1800 * RSDK.Cos512(negAngle);
663
y += -0x1800 * RSDK.Sin512(negAngle);
664
moveX += 0x300000;
665
}
666
667
x2 = ((self->position.x + x) >> 1) - 0x100000;
668
y2 = ((self->position.y + y) >> 1) + 0x100000;
669
}
670
671
self->velocity.x += ((moveX - self->position.x) >> 5) - (self->velocity.x >> 3);
672
self->velocity.y += ((moveY - self->position.y) >> 5) - (self->velocity.y >> 3);
673
self->position.x += self->velocity.x;
674
self->position.y += self->velocity.y;
675
676
int32 percent = 0x1800;
677
for (int32 i = 0; i < 7; ++i) {
678
self->armPositions[i] = MathHelpers_GetBezierPoint(percent, x, y, x2, y2, x2, y2, self->position.x, self->position.y);
679
percent += 0x2000;
680
}
681
682
RSDK.ProcessAnimation(&self->cuffAnimator);
683
RSDK.ProcessAnimation(&self->handAnimator);
684
}
685
686
void PhantomKing_StateArm_WrestleEggman(void)
687
{
688
RSDK_THIS(PhantomKing);
689
690
EntityPhantomKing *parent = self->parent;
691
692
self->direction = parent->direction;
693
int32 negAngle = -parent->rotation;
694
695
int32 x = 0;
696
int32 y = 0;
697
698
if (self->direction) {
699
x = parent->position.x + 0xD00 * RSDK.Cos512(negAngle) + 0x300 * RSDK.Sin512(negAngle);
700
y = parent->position.y - 0xD00 * RSDK.Sin512(negAngle) + 0x300 * RSDK.Cos512(negAngle);
701
702
if (self->type == PHANTOMKING_ARM_L) {
703
x += -0x1800 * RSDK.Cos512(negAngle);
704
y += 0x1800 * RSDK.Sin512(negAngle);
705
}
706
}
707
else {
708
x = 0x300 * RSDK.Sin512(negAngle) - 0xD00 * RSDK.Cos512(negAngle) + parent->position.x;
709
y = 0xD00 * RSDK.Sin512(negAngle) + 0x300 * RSDK.Cos512(negAngle) + parent->position.y;
710
711
if (self->type == PHANTOMKING_ARM_L) {
712
x += 0x1800 * RSDK.Cos512(negAngle);
713
y += -0x1800 * RSDK.Sin512(negAngle);
714
}
715
}
716
717
int32 percent = 0x1800;
718
for (int32 i = 0; i < 7; ++i) {
719
self->armPositions[i] = MathHelpers_GetBezierPoint(percent, x, y, self->armBezierPos.x, self->armBezierPos.y, self->armBezierPos.x,
720
self->armBezierPos.y, self->position.x, self->position.y);
721
percent += 0x2000;
722
}
723
724
RSDK.ProcessAnimation(&self->cuffAnimator);
725
RSDK.ProcessAnimation(&self->handAnimator);
726
}
727
728
void PhantomKing_HandleArmMovement(void)
729
{
730
RSDK_THIS(PhantomKing);
731
732
EntityPhantomKing *parent = self->parent;
733
734
RSDK.Sin256(2 * (Zone->timer + (self->type << 6)) - 128);
735
++self->timer;
736
self->direction = parent->direction;
737
int32 negAngle = -parent->rotation;
738
739
int32 x = 0;
740
int32 y = 0;
741
742
int32 x2 = 0;
743
int32 y2 = 0;
744
745
int32 x3 = 0;
746
int32 y3 = 0;
747
748
if (self->direction) {
749
x = parent->position.x + 0xD00 * RSDK.Cos512(negAngle) + 0x300 * RSDK.Sin512(negAngle);
750
y = parent->position.y - 0xD00 * RSDK.Sin512(negAngle) + 0x300 * RSDK.Cos512(negAngle);
751
752
if (self->type == PHANTOMKING_ARM_L) {
753
x += -0x1800 * RSDK.Cos512(negAngle);
754
y += 0x1800 * RSDK.Sin512(negAngle);
755
}
756
757
x2 = x + self->armRadius * RSDK.Cos256(self->armAngle);
758
y2 = y + self->armRadius * RSDK.Sin256(self->armAngle);
759
x3 = x2 + self->armRadius * RSDK.Cos256(self->armAngleOffset + self->armAngle);
760
y3 = y2 + self->armRadius * RSDK.Sin256(self->armAngleOffset + self->armAngle);
761
}
762
else {
763
x = 0x300 * RSDK.Sin512(negAngle) - 0xD00 * RSDK.Cos512(negAngle) + parent->position.x;
764
y = 0xD00 * RSDK.Sin512(negAngle) + 0x300 * RSDK.Cos512(negAngle) + parent->position.y;
765
766
if (self->type == PHANTOMKING_ARM_L) {
767
x += 0x1800 * RSDK.Cos512(negAngle);
768
y += -0x1800 * RSDK.Sin512(negAngle);
769
}
770
771
x2 = x + self->armRadius * RSDK.Cos256(self->armAngle);
772
y2 = y + self->armRadius * RSDK.Sin256(self->armAngle);
773
x3 = x2 + self->armRadius * RSDK.Cos256(self->armAngleOffset + self->armAngle);
774
y3 = y2 + self->armRadius * RSDK.Sin256(self->armAngleOffset + self->armAngle);
775
}
776
777
self->velocity.x += ((x3 - self->position.x) >> 5) - (self->velocity.x >> 3);
778
self->velocity.y += ((y3 - self->position.y) >> 5) - (self->velocity.y >> 3);
779
self->position.x += self->velocity.x;
780
self->position.y += self->velocity.y;
781
782
int32 percent = 0x1800;
783
for (int32 i = 0; i < 7; ++i) {
784
self->armPositions[i] = MathHelpers_GetBezierPoint(percent, x, y, x2, y2, x2, y2, x3, y3);
785
percent += 0x2000;
786
}
787
788
RSDK.ProcessAnimation(&self->cuffAnimator);
789
RSDK.ProcessAnimation(&self->handAnimator);
790
}
791
792
void PhantomKing_StateArm_PullBack(void)
793
{
794
RSDK_THIS(PhantomKing);
795
796
PhantomKing_HandleArmMovement();
797
798
uint8 armFinished = 0;
799
800
if (self->armAngle >= 0xC0)
801
armFinished = 1;
802
else
803
self->armAngle += 3;
804
805
if (self->armAngleOffset >= 0x60)
806
++armFinished;
807
else
808
self->armAngleOffset += 3;
809
810
if (armFinished == 2)
811
self->state = PhantomKing_StateArm_Point;
812
}
813
814
void PhantomKing_StateArm_Point(void)
815
{
816
RSDK_THIS(PhantomKing);
817
818
PhantomKing_HandleArmMovement();
819
820
if (self->armAngle <= 0x80)
821
self->armAngle = 0x80;
822
else
823
self->armAngle -= 0x10;
824
825
if (self->armAngleOffset <= 0x00)
826
self->armAngleOffset = 0x00;
827
else
828
self->armAngleOffset -= 0x10;
829
}
830
831
void PhantomKing_DestroyEntity(void)
832
{
833
RSDK_THIS(PhantomKing);
834
835
int32 slot = RSDK.GetEntitySlot(self);
836
EntityPhantomKing *armL = RSDK_GET_ENTITY(slot - 1, PhantomKing);
837
EntityPhantomKing *armR = RSDK_GET_ENTITY(slot + 1, PhantomKing);
838
839
foreach_all(PKingAttack, attack) { destroyEntity(attack); }
840
841
destroyEntity(armL);
842
destroyEntity(armR);
843
destroyEntity(self);
844
}
845
846
void PhantomKing_State_Explode(void)
847
{
848
RSDK_THIS(PhantomKing);
849
850
PhantomKing_Explode();
851
852
if (++self->timer == 60)
853
self->state = PhantomKing_State_Destroyed;
854
}
855
856
void PhantomKing_State_Destroyed(void)
857
{
858
RSDK_THIS(PhantomKing);
859
860
self->velocity.y += 0x2800;
861
self->position.y += self->velocity.y;
862
863
PhantomKing_Explode();
864
865
if (self->position.y >= 0x2800000) {
866
PhantomKing->defeated = true;
867
868
if (!KleptoMobile->defeated) {
869
PhantomKing_SwitchToEggman();
870
}
871
else {
872
foreach_all(ERZOutro, outro)
873
{
874
outro->active = ACTIVE_NORMAL;
875
foreach_break;
876
}
877
}
878
879
PhantomKing_DestroyEntity();
880
}
881
882
PhantomKing_HandleFrames();
883
}
884
885
#if GAME_INCLUDE_EDITOR
886
void PhantomKing_EditorDraw(void)
887
{
888
RSDK_THIS(PhantomKing);
889
890
self->originPos = self->position;
891
self->rotation = 0;
892
self->bodyAngle = 0;
893
self->bodyAnimator.speed = 0;
894
PhantomKing_HandleFrames();
895
896
RSDK.SetSpriteAnimation(PhantomKing->aniFrames, 0, &self->headAnimator, false, 0);
897
RSDK.SetSpriteAnimation(PhantomKing->aniFrames, 1, &self->bodyAnimator, false, 0);
898
RSDK.SetSpriteAnimation(PhantomKing->aniFrames, 2, &self->beltAnimator, false, 0);
899
RSDK.SetSpriteAnimation(PhantomKing->aniFrames, 7, &self->particleAnimator, false, 0);
900
RSDK.SetSpriteAnimation(PhantomKing->aniFrames, 8, &self->rubyAnimator, false, 0);
901
902
PhantomKing_Draw_Body();
903
}
904
905
void PhantomKing_EditorLoad(void)
906
{
907
PhantomKing->aniFrames = RSDK.LoadSpriteAnimation("Phantom/PhantomKing.bin", SCOPE_STAGE);
908
909
RSDK_ACTIVE_VAR(PhantomKing, type);
910
RSDK_ENUM_VAR("King", PHANTOMKING_KING);
911
}
912
#endif
913
914
void PhantomKing_Serialize(void) { RSDK_EDITABLE_VAR(PhantomKing, VAR_ENUM, type); }
915
916