Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/ERZ/PhantomGunner.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: PhantomGunner Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectPhantomGunner *PhantomGunner;
11
12
void PhantomGunner_Update(void)
13
{
14
RSDK_THIS(PhantomGunner);
15
16
StateMachine_Run(self->state);
17
}
18
19
void PhantomGunner_LateUpdate(void) {}
20
21
void PhantomGunner_StaticUpdate(void) {}
22
23
void PhantomGunner_Draw(void)
24
{
25
RSDK_THIS(PhantomGunner);
26
27
RSDK.SetActivePalette(4, 0, ScreenInfo[SceneInfo->currentScreenID].size.y);
28
29
if (self->stateDraw) {
30
StateMachine_Run(self->stateDraw);
31
}
32
else {
33
RSDK.DrawSprite(&self->mainAnimator, NULL, false);
34
}
35
36
RSDK.SetActivePalette(0, 0, ScreenInfo[SceneInfo->currentScreenID].size.y);
37
}
38
39
void PhantomGunner_Create(void *data)
40
{
41
RSDK_THIS(PhantomGunner);
42
43
if (!SceneInfo->inEditor) {
44
self->startPos = self->position;
45
self->visible = true;
46
self->drawGroup = 2;
47
self->active = ACTIVE_NORMAL;
48
self->updateRange.x = 0x800000;
49
self->updateRange.y = 0x800000;
50
51
self->type = VOID_TO_INT(data);
52
switch (self->type) {
53
case PHANTOMGUNNER_BOSS:
54
self->drawFX = FX_FLIP;
55
self->active = ACTIVE_NEVER;
56
57
RSDK.SetSpriteAnimation(PhantomGunner->aniFrames, 0, &self->mainAnimator, true, 0);
58
RSDK.SetSpriteAnimation(PhantomGunner->aniFrames, 1, &self->fxAnimator, true, 0);
59
60
self->originPos = self->position;
61
self->screenPos.x = (self->position.x >> 16) - ScreenInfo->center.x;
62
self->screenPos.y = (self->position.y >> 16) - ScreenInfo->center.y;
63
64
self->stateDraw = PhantomGunner_Draw_Gunner;
65
self->state = PhantomGunner_State_Idle;
66
break;
67
68
case PHANTOMGUNNER_LAUNCHROCKET:
69
RSDK.SetSpriteAnimation(PhantomGunner->aniFrames, 10, &self->mainAnimator, true, 0);
70
RSDK.SetSpriteAnimation(PhantomGunner->aniFrames, 11, &self->fxAnimator, true, 0);
71
72
self->stateDraw = PhantomGunner_Draw_RocketLaunch;
73
self->state = PhantomGunner_State_LaunchedRocket;
74
break;
75
76
case PHANTOMGUNNER_NAPALM_EXPLOSION:
77
self->originPos = self->position;
78
79
self->state = PhantomGunner_State_NapalmExplosion;
80
break;
81
82
case PHANTOMGUNNER_MORTAR_EXPLOSION:
83
self->originPos = self->position;
84
85
self->state = PhantomGunner_State_MortarExplosion;
86
break;
87
88
default: break;
89
}
90
}
91
}
92
93
void PhantomGunner_StageLoad(void)
94
{
95
PhantomGunner->aniFrames = RSDK.LoadSpriteAnimation("Phantom/PhantomGunner.bin", SCOPE_STAGE);
96
97
PhantomGunner->hitboxNapalm.left = -8;
98
PhantomGunner->hitboxNapalm.top = 4;
99
PhantomGunner->hitboxNapalm.right = 8;
100
PhantomGunner->hitboxNapalm.bottom = 26;
101
102
PhantomGunner->hitboxMortar.left = -16;
103
PhantomGunner->hitboxMortar.top = -32;
104
PhantomGunner->hitboxMortar.right = 16;
105
PhantomGunner->hitboxMortar.bottom = -16;
106
107
PhantomGunner->hitboxDud.left = -8;
108
PhantomGunner->hitboxDud.top = -8;
109
PhantomGunner->hitboxDud.right = 8;
110
PhantomGunner->hitboxDud.bottom = 8;
111
112
PhantomGunner->sfxCannonFire = RSDK.GetSfx("Stage/CannonFire.wav");
113
}
114
115
void PhantomGunner_HandleDudExhaust(void)
116
{
117
RSDK_THIS(PhantomGunner);
118
119
if (!(Zone->timer & 7)) {
120
int32 x = self->position.x + (RSDK.Sin512(self->rotation) << 11);
121
int32 y = self->position.y - (RSDK.Cos512(self->rotation) << 11);
122
EntityDebris *debris = CREATE_ENTITY(Debris, Debris_State_Move, x, y);
123
124
RSDK.SetSpriteAnimation(Explosion->aniFrames, 3, &debris->animator, true, 0);
125
debris->velocity.x = RSDK.Sin512(self->rotation) << 8;
126
debris->velocity.y = RSDK.Sin512(self->rotation) << 4;
127
debris->drawGroup = Zone->objectDrawGroup[0];
128
debris->timer = 41;
129
}
130
}
131
132
void PhantomGunner_HandleMalfunctionDudExhaust(void)
133
{
134
RSDK_THIS(PhantomGunner);
135
136
if (Zone->timer & 3) {
137
if ((Zone->timer & 3) == 2) {
138
int32 x = self->position.x + (RSDK.Sin512(self->rotation) * 0x600);
139
int32 y = self->position.y - (RSDK.Cos512(self->rotation) * 0x600);
140
EntityDebris *debris = CREATE_ENTITY(Debris, Debris_State_Move, x, y);
141
142
RSDK.SetSpriteAnimation(Explosion->aniFrames, 2, &debris->animator, true, 0);
143
debris->drawGroup = Zone->objectDrawGroup[1];
144
debris->drawFX = FX_SCALE;
145
debris->timer = 52;
146
debris->scale.x = (self->scale.x * RSDK.Rand(128, 384)) >> 9;
147
debris->scale.y = debris->scale.x;
148
}
149
}
150
else {
151
int32 x = self->position.x + (RSDK.Sin512(self->rotation) << 11);
152
int32 y = self->position.y - (RSDK.Cos512(self->rotation) << 11);
153
EntityDebris *debris = CREATE_ENTITY(Debris, Debris_State_Move, x, y);
154
155
RSDK.SetSpriteAnimation(Explosion->aniFrames, 3, &debris->animator, true, 0);
156
debris->velocity.x = RSDK.Sin512(self->rotation) << 8;
157
debris->velocity.y = RSDK.Sin512(self->rotation) << 4;
158
debris->drawGroup = Zone->objectDrawGroup[0];
159
debris->drawFX = FX_SCALE;
160
debris->timer = 41;
161
debris->scale.y = self->scale.x;
162
}
163
}
164
165
void PhantomGunner_SpawnDust(void)
166
{
167
RSDK_THIS(PhantomGunner);
168
169
for (int32 i = 0; i < 4; ++i) {
170
int32 x = self->position.x + RSDK.Rand(-0x100000, 0x100000);
171
int32 y = self->position.y + RSDK.Rand(-0x280000, -0x180000);
172
EntityDust *dust = CREATE_ENTITY(Dust, NULL, x, y);
173
dust->state = Dust_State_DustPuff;
174
dust->drawGroup = Zone->objectDrawGroup[1];
175
}
176
}
177
178
void PhantomGunner_HandleRotations(int32 angle)
179
{
180
RSDK_THIS(PhantomGunner);
181
182
int32 ang = angle - self->rotation;
183
184
if (abs(angle - self->rotation) >= abs(angle - self->rotation - 0x200)) {
185
if (abs(angle - self->rotation - 0x200) < abs(angle - self->rotation + 0x200))
186
self->rotation += (ang - 0x200) >> 4;
187
else
188
self->rotation += (ang + 0x200) >> 4;
189
}
190
else {
191
if (abs(angle - self->rotation) < abs(angle - self->rotation + 0x200))
192
self->rotation += ang >> 4;
193
else
194
self->rotation += (ang + 0x200) >> 4;
195
}
196
197
self->rotation &= 0x1FF;
198
}
199
200
void PhantomGunner_CheckPlayerMissileCollisions(void)
201
{
202
RSDK_THIS(PhantomGunner);
203
204
foreach_active(Player, player)
205
{
206
if (self->parachuteAnimator.frameID > 0 && player->velocity.y >= 0 && Player_CheckBadnikTouch(player, self, &PhantomGunner->hitboxMortar)
207
&& player->animator.animationID != ANI_HURT) {
208
RSDK.SetSpriteAnimation(-1, 0, &self->parachuteAnimator, true, 0);
209
player->velocity.y = -0x60000;
210
PhantomGunner_SpawnDust();
211
self->state = PhantomGunner_State_Napalm;
212
}
213
else {
214
if (Player_CheckBadnikTouch(player, self, &PhantomGunner->hitboxNapalm)) {
215
int32 anim = player->animator.animationID;
216
if (anim == ANI_JUMP || anim == ANI_SPINDASH || anim == ANI_DROPDASH) {
217
EntityExplosion *explosion = CREATE_ENTITY(Explosion, INT_TO_VOID(EXPLOSION_ENEMY), self->position.x, self->position.y);
218
explosion->interaction = false;
219
explosion->drawGroup = Zone->objectDrawGroup[1];
220
if (self->parachuteAnimator.animationID == 12 && self->parachuteAnimator.frameID > 0)
221
PhantomGunner_SpawnDust();
222
RSDK.PlaySfx(PhantomEgg->sfxExplosion2, false, 255);
223
destroyEntity(self);
224
foreach_break;
225
}
226
}
227
}
228
}
229
}
230
231
void PhantomGunner_CheckPlayerExplosionCollisions(void)
232
{
233
foreach_active(Player, player)
234
{
235
foreach_active(Explosion, explosion)
236
{
237
if (explosion->animator.frameID <= 6) {
238
if (Player_CheckCollisionTouch(player, explosion, &PhantomGunner->hitboxDud)) {
239
Player_ElementHurt(player, explosion, SHIELD_FIRE);
240
}
241
}
242
}
243
}
244
}
245
246
void PhantomGunner_Hit(EntityPhantomGunner *entity)
247
{
248
RSDK.PlaySfx(PhantomEgg->sfxHit, false, 255);
249
entity->invincibilityTimer = 48;
250
}
251
252
void PhantomGunner_Draw_Gunner(void)
253
{
254
RSDK_THIS(PhantomGunner);
255
256
if (self->invincibilityTimer & 1) {
257
RSDK.CopyPalette(6, 128, 4, 128, 128);
258
259
RSDK.DrawSprite(&self->mainAnimator, NULL, false);
260
261
self->direction = FLIP_X;
262
RSDK.DrawSprite(&self->fxAnimator, NULL, false);
263
264
self->direction = FLIP_NONE;
265
RSDK.DrawSprite(&self->fxAnimator, NULL, false);
266
267
RSDK.CopyPalette(5, 128, 4, 128, 128);
268
}
269
else {
270
RSDK.DrawSprite(&self->mainAnimator, NULL, false);
271
272
self->direction = FLIP_X;
273
RSDK.DrawSprite(&self->fxAnimator, NULL, false);
274
275
self->direction = FLIP_NONE;
276
RSDK.DrawSprite(&self->fxAnimator, NULL, false);
277
}
278
}
279
280
void PhantomGunner_Draw_RocketLaunch(void)
281
{
282
RSDK_THIS(PhantomGunner);
283
284
EntityPhantomGunner *parent = self->parent;
285
286
RSDK.SetClipBounds(0, 0, 0, ScreenInfo->size.x, ((self->originPos.y + parent->position.y) >> 16) - ScreenInfo->position.y);
287
288
Vector2 drawPos;
289
drawPos.x = parent->position.x + self->originPos.x;
290
drawPos.y = self->position.y;
291
RSDK.DrawSprite(&self->mainAnimator, &drawPos, false);
292
293
RSDK.SetClipBounds(0, 0, 0, ScreenInfo->size.x, ScreenInfo->size.y);
294
295
drawPos.y = parent->position.y + self->originPos.y;
296
RSDK.DrawSprite(&self->fxAnimator, &drawPos, false);
297
}
298
299
void PhantomGunner_Draw_Rocket(void)
300
{
301
RSDK_THIS(PhantomGunner);
302
303
RSDK.DrawSprite(&self->mainAnimator, NULL, false);
304
RSDK.DrawSprite(&self->tailAnimator, NULL, false);
305
RSDK.DrawSprite(&self->parachuteAnimator, NULL, false);
306
}
307
308
void PhantomGunner_State_ResetState(void)
309
{
310
RSDK_THIS(PhantomGunner);
311
312
if (self->invincibilityTimer > 0)
313
self->invincibilityTimer--;
314
315
self->position.x += (ScreenInfo->position.x - self->screenPos.x) << 15;
316
self->position.y = BadnikHelpers_Oscillate(self->originPos.y, 3, 11);
317
318
self->screenPos = ScreenInfo->position;
319
320
RSDK.ProcessAnimation(&self->fxAnimator);
321
322
if (++self->timer == 60) {
323
self->position = self->startPos;
324
self->originPos = self->startPos;
325
self->timer = 0;
326
self->rocketLaunchCount = 0;
327
self->screenPos.x = (self->position.x >> 16) - ScreenInfo->center.x;
328
self->screenPos.y = (self->position.y >> 16) - ScreenInfo->center.y;
329
self->stateDraw = PhantomGunner_Draw_Gunner;
330
self->state = PhantomGunner_State_Idle;
331
self->active = ACTIVE_NEVER;
332
}
333
}
334
335
void PhantomGunner_State_Idle(void)
336
{
337
RSDK_THIS(PhantomGunner);
338
339
if (self->invincibilityTimer > 0)
340
self->invincibilityTimer--;
341
342
self->position.x += (ScreenInfo->position.x - self->screenPos.x) << 15;
343
self->position.y = BadnikHelpers_Oscillate(self->originPos.y, 3, 11);
344
345
self->screenPos = ScreenInfo->position;
346
RSDK.ProcessAnimation(&self->fxAnimator);
347
348
self->fireAnimTimer = 8;
349
if (++self->timer < 120 || RSDK.GetEntityCount(PhantomGunner->classID, true) >= 2) {
350
PhantomGunner_CheckPlayerExplosionCollisions();
351
}
352
else {
353
if (++self->rocketLaunchCount == 2) {
354
PhantomEgg_SetupWarpFX();
355
self->timer = 0;
356
self->state = PhantomGunner_State_ResetState;
357
}
358
else {
359
PhantomGunner->launchedRocketID = 0;
360
self->timer = 0;
361
RSDK.SetSpriteAnimation(PhantomGunner->aniFrames, 2, &self->mainAnimator, true, 0);
362
363
self->state = PhantomGunner_State_LaunchRockets;
364
PhantomGunner_CheckPlayerExplosionCollisions();
365
}
366
}
367
}
368
369
void PhantomGunner_State_LaunchRockets(void)
370
{
371
RSDK_THIS(PhantomGunner);
372
373
if (self->invincibilityTimer > 0)
374
self->invincibilityTimer--;
375
376
self->position.x += (ScreenInfo->position.x - self->screenPos.x) << 15;
377
self->position.y = BadnikHelpers_Oscillate(self->originPos.y, 3, 11);
378
379
self->screenPos = ScreenInfo->position;
380
381
RSDK.ProcessAnimation(&self->mainAnimator);
382
RSDK.ProcessAnimation(&self->fxAnimator);
383
384
if (++self->timer == 8) {
385
EntityPhantomGunner *rocket = CREATE_ENTITY(PhantomGunner, INT_TO_VOID(PHANTOMGUNNER_LAUNCHROCKET), self->position.x, self->position.y);
386
rocket->parent = self;
387
rocket->originPos.x = PhantomGunner->rocketOffsets[self->rocketOffsetID] << 16;
388
rocket->originPos.y = PhantomGunner->rocketOffsets[self->rocketOffsetID + 1] << 16;
389
rocket->position.x += rocket->originPos.x;
390
rocket->position.y += rocket->originPos.y + 0x100000;
391
self->rocketOffsetID = (self->rocketOffsetID - 14) & 0x1F;
392
393
RSDK.PlaySfx(PhantomGunner->sfxCannonFire, false, 255);
394
}
395
396
if (self->mainAnimator.frameID == self->mainAnimator.frameCount - 1) {
397
self->timer = 0;
398
399
if (--self->fireAnimTimer > 0) {
400
if (!(self->fireAnimTimer & 1))
401
RSDK.SetSpriteAnimation(PhantomGunner->aniFrames, 2, &self->mainAnimator, true, 0);
402
else
403
RSDK.SetSpriteAnimation(PhantomGunner->aniFrames, 3, &self->mainAnimator, true, 0);
404
}
405
else {
406
RSDK.SetSpriteAnimation(PhantomGunner->aniFrames, 0, &self->mainAnimator, true, 0);
407
self->state = PhantomGunner_State_Idle;
408
}
409
}
410
411
PhantomGunner_CheckPlayerExplosionCollisions();
412
}
413
414
void PhantomGunner_State_LaunchedRocket(void)
415
{
416
RSDK_THIS(PhantomGunner);
417
418
RSDK.ProcessAnimation(&self->mainAnimator);
419
RSDK.ProcessAnimation(&self->fxAnimator);
420
421
self->position.y -= 0x80000;
422
423
if (++self->timer == 60) {
424
EntityPhantomGunner *parent = self->parent;
425
426
self->timer = 0;
427
if ((PhantomGunner->launchedRocketID & 3) == 3)
428
self->type = PHANTOMGUNNER_DUD;
429
else
430
self->type = (PhantomGunner->launchedRocketID & 1) + PHANTOMGUNNER_MORTAR;
431
432
++PhantomGunner->launchedRocketID;
433
self->drawGroup = Zone->objectDrawGroup[0];
434
self->position.y = (ScreenInfo->position.y - 64) << 16;
435
436
bool32 canFire = false;
437
while (!canFire) {
438
canFire = true;
439
self->position.x = parent->position.x + RSDK.Rand(-0x1000000, 0x1000000);
440
441
foreach_active(PhantomGunner, gunner)
442
{
443
if (gunner != self && gunner->type >= PHANTOMGUNNER_MORTAR) {
444
int32 dist = abs(gunner->position.x - self->position.x);
445
if (dist < 0x180000 && gunner->position.y - self->position.y < 0x800000)
446
canFire = false;
447
}
448
}
449
}
450
451
if (self->type == PHANTOMGUNNER_MORTAR) {
452
RSDK.SetSpriteAnimation(PhantomGunner->aniFrames, 4, &self->mainAnimator, true, 0);
453
RSDK.SetSpriteAnimation(PhantomGunner->aniFrames, 5, &self->tailAnimator, true, 0);
454
RSDK.SetSpriteAnimation(PhantomGunner->aniFrames, 12, &self->parachuteAnimator, true, 0);
455
456
self->state = PhantomGunner_State_Mortar;
457
self->timer = RSDK.Rand(0, 2) << 8;
458
self->stateDraw = PhantomGunner_Draw_Rocket;
459
}
460
else if (self->type == PHANTOMGUNNER_NAPALM) {
461
RSDK.SetSpriteAnimation(PhantomGunner->aniFrames, 6, &self->mainAnimator, true, 0);
462
RSDK.SetSpriteAnimation(PhantomGunner->aniFrames, 7, &self->tailAnimator, true, 0);
463
464
self->state = PhantomGunner_State_Napalm;
465
self->stateDraw = PhantomGunner_Draw_Rocket;
466
}
467
else if (self->type == PHANTOMGUNNER_DUD) {
468
RSDK.SetSpriteAnimation(PhantomGunner->aniFrames, 8, &self->mainAnimator, true, 0);
469
RSDK.SetSpriteAnimation(PhantomGunner->aniFrames, 9, &self->tailAnimator, true, 0);
470
471
self->position.x = parent->position.x;
472
self->drawFX = FX_ROTATE;
473
self->velocity.x = (Zone->timer & 1) ? -0x40000 : 0x40000;
474
475
self->state = PhantomGunner_State_Dud_Active;
476
self->stateDraw = PhantomGunner_Draw_Rocket;
477
}
478
}
479
}
480
481
void PhantomGunner_State_Mortar(void)
482
{
483
RSDK_THIS(PhantomGunner);
484
485
RSDK.ProcessAnimation(&self->parachuteAnimator);
486
RSDK.ProcessAnimation(&self->tailAnimator);
487
488
if (self->parachuteAnimator.frameID) {
489
self->drawFX = FX_ROTATE;
490
if (self->velocity.y > 0xC000)
491
self->velocity.y -= 0x3800;
492
493
self->rotation = RSDK.Sin512(self->timer) >> 6;
494
self->timer = (self->timer + 4) & 0x1FF;
495
}
496
else if (self->velocity.y < 0x40000)
497
self->velocity.y += 0x3800;
498
499
self->position.y += self->velocity.y;
500
501
PhantomGunner_CheckPlayerMissileCollisions();
502
if (self->classID) {
503
if (RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0x100000, true)) {
504
if (self->type == PHANTOMGUNNER_NAPALM) {
505
EntityPhantomGunner *napalm =
506
CREATE_ENTITY(PhantomGunner, INT_TO_VOID(PHANTOMGUNNER_NAPALM_EXPLOSION), self->position.x, self->position.y);
507
napalm->velocity.x = self->velocity.y > 0x20000 ? 0x80000 : 0x40000;
508
destroyEntity(self);
509
}
510
else {
511
CREATE_ENTITY(PhantomGunner, INT_TO_VOID(PHANTOMGUNNER_MORTAR_EXPLOSION), self->position.x, self->position.y);
512
destroyEntity(self);
513
}
514
}
515
}
516
}
517
518
void PhantomGunner_State_Napalm(void)
519
{
520
RSDK_THIS(PhantomGunner);
521
522
RSDK.ProcessAnimation(&self->tailAnimator);
523
524
if (self->velocity.y < 0x40000)
525
self->velocity.y += 0x1800;
526
527
self->position.y += self->velocity.y;
528
529
PhantomGunner_CheckPlayerMissileCollisions();
530
if (self->classID) {
531
if (RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0x100000, true)) {
532
if (self->type == PHANTOMGUNNER_NAPALM) {
533
EntityPhantomGunner *napalm =
534
CREATE_ENTITY(PhantomGunner, INT_TO_VOID(PHANTOMGUNNER_NAPALM_EXPLOSION), self->position.x, self->position.y);
535
napalm->velocity.x = self->velocity.y > 0x20000 ? 0x80000 : 0x40000;
536
destroyEntity(self);
537
}
538
else {
539
CREATE_ENTITY(PhantomGunner, INT_TO_VOID(PHANTOMGUNNER_MORTAR_EXPLOSION), self->position.x, self->position.y);
540
destroyEntity(self);
541
}
542
}
543
}
544
}
545
546
void PhantomGunner_State_Dud_Active(void)
547
{
548
RSDK_THIS(PhantomGunner);
549
550
RSDK.ProcessAnimation(&self->tailAnimator);
551
EntityPhantomGunner *parent = self->parent;
552
553
++self->timer;
554
555
self->velocity.x = RSDK.Cos256(self->timer) << 11;
556
if (self->position.y < parent->position.y - 0x800000) {
557
if (self->velocity.y < 0x20000)
558
self->velocity.y += 0x2000;
559
}
560
561
if (self->position.y > parent->position.y - 0x200000) {
562
if (self->velocity.y > -0x20000)
563
self->velocity.y -= 0x2000;
564
}
565
566
self->position.x += self->velocity.x;
567
self->position.y += self->velocity.y;
568
PhantomGunner_HandleDudExhaust();
569
570
int32 angle = RSDK.ATan2(self->velocity.y, -self->velocity.x);
571
PhantomGunner_HandleRotations(2 * angle);
572
573
if (self->timer == 320) {
574
EntityExplosion *explosion = CREATE_ENTITY(Explosion, INT_TO_VOID(EXPLOSION_ITEMBOX), self->position.x, self->position.y);
575
explosion->interaction = false;
576
explosion->drawGroup = Zone->objectDrawGroup[1];
577
destroyEntity(self);
578
}
579
else {
580
foreach_active(Player, player)
581
{
582
if (Player_CheckBadnikTouch(player, self, &PhantomGunner->hitboxDud)) {
583
self->angle = self->rotation << 8;
584
self->timer = 0;
585
self->drawFX = FX_SCALE | FX_ROTATE;
586
self->groundVel = 0x4000;
587
self->scale.x = 0x200;
588
self->scale.y = 0x200;
589
self->state = PhantomGunner_State_Dud_HitByPlayer;
590
RSDK.PlaySfx(PhantomEgg->sfxHit, false, 255);
591
}
592
}
593
}
594
}
595
596
void PhantomGunner_State_Dud_HitByPlayer(void)
597
{
598
RSDK_THIS(PhantomGunner);
599
600
RSDK.ProcessAnimation(&self->tailAnimator);
601
602
self->angle += self->groundVel;
603
self->rotation = self->angle >> 8;
604
self->groundVel -= self->groundVel >> 3;
605
606
PhantomGunner_HandleDudExhaust();
607
608
if (self->groundVel < 128) {
609
RSDK.PlaySfx(PhantomEgg->sfxRocketJet, false, 255);
610
self->state = PhantomGunner_State_Dud_Malfunction;
611
}
612
}
613
614
void PhantomGunner_State_Dud_Malfunction(void)
615
{
616
RSDK_THIS(PhantomGunner);
617
618
RSDK.ProcessAnimation(&self->tailAnimator);
619
620
EntityPhantomGunner *parent = self->parent;
621
622
int32 angle = RSDK.ATan2((parent->position.y - self->position.y) >> 16, -((parent->position.x - self->position.x) >> 16));
623
PhantomGunner_HandleRotations(2 * angle);
624
625
self->rotation &= 0x1FF;
626
self->position.x -= RSDK.Sin512(self->rotation) << 9;
627
self->scale.x -= 6;
628
self->position.y += RSDK.Cos512(self->rotation) << 9;
629
self->scale.y = self->scale.x;
630
631
PhantomGunner_HandleMalfunctionDudExhaust();
632
if (self->scale.x < 0x80) {
633
PhantomGunner_Hit(parent);
634
635
self->position.x = parent->position.x;
636
self->position.y = parent->position.y;
637
self->visible = false;
638
self->state = PhantomGunner_State_Dud_Explode;
639
}
640
}
641
642
void PhantomGunner_State_Dud_Explode(void)
643
{
644
RSDK_THIS(PhantomGunner);
645
646
if (!(Zone->timer % 3) && !(Zone->timer & 4)) {
647
int32 x = self->position.x + RSDK.Rand(-0x100000, 0x100000);
648
int32 y = self->position.y + RSDK.Rand(-0x100000, 0x100000);
649
EntityExplosion *explosion = CREATE_ENTITY(Explosion, INT_TO_VOID((RSDK.Rand(0, 256) > 192) + EXPLOSION_BOSS), x, y);
650
explosion->interaction = false;
651
explosion->drawGroup = 1;
652
explosion->scale = self->scale;
653
}
654
655
if (++self->timer == 16)
656
destroyEntity(self);
657
}
658
659
void PhantomGunner_State_NapalmExplosion(void)
660
{
661
RSDK_THIS(PhantomGunner);
662
663
if (!(Zone->timer & 3)) {
664
CREATE_ENTITY(Explosion, INT_TO_VOID(EXPLOSION_BOSS), self->originPos.x - self->napalmExplosionPos, self->position.y);
665
CREATE_ENTITY(Explosion, INT_TO_VOID(EXPLOSION_BOSS), self->originPos.x + self->napalmExplosionPos, self->position.y);
666
}
667
668
self->napalmExplosionPos += self->velocity.x;
669
670
if (++self->timer == 16)
671
destroyEntity(self);
672
}
673
674
void PhantomGunner_State_MortarExplosion(void)
675
{
676
RSDK_THIS(PhantomGunner);
677
678
if (!(Zone->timer & 3))
679
CREATE_ENTITY(Explosion, INT_TO_VOID(EXPLOSION_ITEMBOX), self->position.x, self->position.y);
680
681
self->position.y -= 0x40000;
682
683
if (++self->timer == 16)
684
destroyEntity(self);
685
}
686
687
#if GAME_INCLUDE_EDITOR
688
void PhantomGunner_EditorDraw(void)
689
{
690
RSDK_THIS(PhantomGunner);
691
692
self->drawFX = FX_FLIP;
693
RSDK.SetSpriteAnimation(PhantomGunner->aniFrames, 0, &self->mainAnimator, false, 0);
694
RSDK.SetSpriteAnimation(PhantomGunner->aniFrames, 1, &self->fxAnimator, false, 0);
695
696
self->originPos = self->position;
697
self->screenPos.x = (self->position.x >> 16) - ScreenInfo->center.x;
698
self->screenPos.y = (self->position.y >> 16) - ScreenInfo->center.y;
699
700
PhantomGunner_Draw_Gunner();
701
}
702
703
void PhantomGunner_EditorLoad(void) { PhantomGunner->aniFrames = RSDK.LoadSpriteAnimation("Phantom/PhantomGunner.bin", SCOPE_STAGE); }
704
#endif
705
706
void PhantomGunner_Serialize(void) {}
707
708