Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/GHZ/DERobot.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: DERobot Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectDERobot *DERobot;
11
12
void DERobot_Update(void)
13
{
14
RSDK_THIS(DERobot);
15
StateMachine_Run(self->state);
16
}
17
18
void DERobot_LateUpdate(void) {}
19
20
void DERobot_StaticUpdate(void) {}
21
22
void DERobot_Draw(void)
23
{
24
RSDK_THIS(DERobot);
25
StateMachine_Run(self->stateDraw);
26
}
27
28
void DERobot_Create(void *data)
29
{
30
RSDK_THIS(DERobot);
31
if (!SceneInfo->inEditor) {
32
if (globals->gameMode < MODE_TIMEATTACK) {
33
self->drawGroup = Zone->objectDrawGroup[0];
34
self->updateRange.x = 0x800000;
35
self->updateRange.y = 0x800000;
36
int32 slotID = RSDK.GetEntitySlot(self);
37
if (data)
38
self->aniID = VOID_TO_INT(data);
39
40
switch (self->aniID) {
41
case DEROBOT_BODY:
42
self->active = ACTIVE_BOUNDS;
43
self->legs[0] = RSDK_GET_ENTITY(slotID - 7, DERobot);
44
self->legs[1] = RSDK_GET_ENTITY(slotID - 6, DERobot);
45
self->legs[2] = RSDK_GET_ENTITY(slotID - 5, DERobot);
46
self->arms[0] = RSDK_GET_ENTITY(slotID - 4, DERobot);
47
self->arms[1] = RSDK_GET_ENTITY(slotID - 3, DERobot);
48
self->eggman = RSDK_GET_ENTITY(slotID - 2, Eggman);
49
self->head = RSDK_GET_ENTITY(slotID - 1, DERobot);
50
self->legs[3] = RSDK_GET_ENTITY(slotID + 1, DERobot);
51
self->legs[4] = RSDK_GET_ENTITY(slotID + 2, DERobot);
52
self->legs[5] = RSDK_GET_ENTITY(slotID + 3, DERobot);
53
self->shoulderFront = RSDK_GET_ENTITY(slotID + 4, DERobot);
54
self->arms[2] = RSDK_GET_ENTITY(slotID + 5, DERobot);
55
self->arms[3] = RSDK_GET_ENTITY(slotID + 6, DERobot);
56
self->health = 8;
57
self->state = DERobot_State_SetupArena;
58
self->stateDraw = DERobot_Draw_Simple;
59
RSDK.SetSpriteAnimation(DERobot->aniFrames, self->aniID, &self->mainAnimator, true, self->frameID);
60
break;
61
62
case DEROBOT_HEAD:
63
self->parent = (Entity *)RSDK_GET_ENTITY(slotID + 1, DERobot);
64
self->stateDraw = DERobot_Draw_RelativeToParent;
65
self->drawFX = FX_ROTATE;
66
self->offset.x = -0x160000;
67
self->offset.y = -0x240000;
68
RSDK.SetSpriteAnimation(DERobot->aniFrames, self->aniID, &self->mainAnimator, true, self->frameID);
69
break;
70
71
case DEROBOT_ARM:
72
if (self->frameID == 2) {
73
RSDK.SetSpriteAnimation(DERobot->aniFrames, 5, &self->altAnimator, true, 0);
74
RSDK.SetSpriteAnimation(DERobot->aniFrames, 4, &self->armAnimator, true, 0);
75
self->stateDraw = DERobot_Draw_Arm;
76
self->drawFX = FX_ROTATE;
77
self->state = DERobot_State_ArmIdle;
78
}
79
else if (self->frameID) {
80
self->stateDraw = DERobot_Draw_Simple;
81
}
82
else {
83
self->parent = (Entity *)RSDK_GET_ENTITY(slotID - 4, DERobot);
84
self->stateDraw = DERobot_Draw_RelativeToParent;
85
self->offset.x = -0xC0000;
86
self->offset.y = -0x100000;
87
}
88
RSDK.SetSpriteAnimation(DERobot->aniFrames, self->aniID, &self->mainAnimator, true, self->frameID);
89
break;
90
91
case DEROBOT_LEG:
92
if (self->frameID) {
93
self->stateDraw = DERobot_Draw_Simple;
94
}
95
else {
96
RSDK.SetSpriteAnimation(DERobot->aniFrames, self->aniID, &self->altAnimator, true, 1);
97
self->stateDraw = DERobot_Draw_FrontLeg;
98
}
99
100
if (self->frameID > 1)
101
self->drawFX = FX_ROTATE;
102
RSDK.SetSpriteAnimation(DERobot->aniFrames, self->aniID, &self->mainAnimator, true, self->frameID);
103
break;
104
105
case DEROBOT_TARGET_EDGE:
106
self->active = ACTIVE_NORMAL;
107
self->visible = true;
108
self->drawFX = FX_FLIP;
109
self->drawGroup = Zone->objectDrawGroup[1];
110
self->velocity.x = 0x20000;
111
RSDK.SetSpriteAnimation(DERobot->aniFrames, 7, &self->altAnimator, true, 0);
112
self->state = DERobot_State_Target;
113
self->stateDraw = DERobot_Draw_Target;
114
RSDK.SetSpriteAnimation(DERobot->aniFrames, self->aniID, &self->mainAnimator, true, self->frameID);
115
break;
116
117
case DEROBOT_BOMB:
118
self->active = ACTIVE_NORMAL;
119
self->visible = true;
120
self->state = DERobot_State_BombLaunched;
121
self->stateDraw = DERobot_Draw_Simple;
122
RSDK.SetSpriteAnimation(DERobot->aniFrames, self->aniID, &self->mainAnimator, true, self->frameID);
123
break;
124
125
case DEROBOT_BODY_CUTSCENE:
126
self->active = ACTIVE_BOUNDS;
127
self->visible = true;
128
self->stateDraw = DERobot_Draw_Simple;
129
self->shoulderFront = RSDK_GET_ENTITY(slotID + 4, DERobot);
130
self->arms[0] = RSDK_GET_ENTITY(slotID + 1, DERobot);
131
self->arms[1] = RSDK_GET_ENTITY(slotID + 2, DERobot);
132
RSDK.SetSpriteAnimation(DERobot->aniFrames, self->aniID, &self->mainAnimator, true, self->frameID);
133
break;
134
135
default:
136
self->stateDraw = DERobot_Draw_Simple;
137
RSDK.SetSpriteAnimation(DERobot->aniFrames, self->aniID, &self->mainAnimator, true, self->frameID);
138
break;
139
}
140
}
141
else {
142
destroyEntity(self);
143
}
144
}
145
}
146
147
void DERobot_StageLoad(void)
148
{
149
DERobot->aniFrames = RSDK.LoadSpriteAnimation("GHZ/DERobot.bin", SCOPE_STAGE);
150
151
DERobot->hitboxBody.left = -32;
152
DERobot->hitboxBody.top = -40;
153
DERobot->hitboxBody.right = 32;
154
DERobot->hitboxBody.bottom = 32;
155
156
DERobot->hitboxHand.left = -9;
157
DERobot->hitboxHand.top = -9;
158
DERobot->hitboxHand.right = 9;
159
DERobot->hitboxHand.bottom = 9;
160
161
DERobot->sfxHit = RSDK.GetSfx("Stage/BossHit.wav");
162
DERobot->sfxExplosion = RSDK.GetSfx("Stage/Explosion2.wav");
163
DERobot->sfxImpact = RSDK.GetSfx("Stage/Impact2.wav");
164
DERobot->sfxTargeting = RSDK.GetSfx("Stage/Targeting1.wav");
165
DERobot->sfxLedgeBreak = RSDK.GetSfx("Stage/LedgeBreak.wav");
166
DERobot->sfxBuzzsaw = RSDK.GetSfx("Stage/Buzzsaw.wav");
167
DERobot->sfxDrop = RSDK.GetSfx("Stage/Drop.wav");
168
DERobot->sfxButton2 = RSDK.GetSfx("Stage/Button2.wav");
169
DERobot->sfxHullClose = RSDK.GetSfx("Stage/HullClose.wav");
170
171
RSDK.SetPaletteEntry(0, 236, 0x282028);
172
RSDK.SetPaletteEntry(0, 237, 0x383040);
173
RSDK.SetPaletteEntry(0, 238, 0x484868);
174
RSDK.SetPaletteEntry(0, 239, 0x587090);
175
RSDK.SetPaletteEntry(0, 244, 0x000000);
176
177
// Bug Details:
178
// palette entry 244 is overwritten in GHZ2Cutscene during plus
179
// this is due to the additional colours in the tileset
180
// the simple fix to this should be to move DERobot above CutsceneHBH in the scene/stageconfig
181
// this will allow the CutsceneHBH object to properly store the 0x000000 colour set here when it does its palette swaps
182
// therefore fixing the orange DERobot bug
183
// alternatively, have GHZ2Outro_Cutscene_HoleSceneFadeIn call CutsceneHBH_StorePalette to store the updated palette
184
}
185
186
void DERobot_HandleScreenBounds(void)
187
{
188
RSDK_THIS(DERobot);
189
int32 x = (self->position.x >> 16) - ScreenInfo->center.x + 128;
190
if (x > Zone->cameraBoundsL[0]) {
191
Zone->cameraBoundsL[0] = x;
192
Zone->cameraBoundsR[0] = ScreenInfo->size.x + 96 + x;
193
Zone->playerBoundsL[0] = Zone->cameraBoundsL[0] << 16;
194
Zone->playerBoundsR[0] = Zone->cameraBoundsR[0] << 16;
195
Zone->playerBoundActiveB[0] = 0;
196
RSDK_GET_ENTITY(SLOT_CAMERA1, Camera)->boundsL = Zone->cameraBoundsL[0];
197
}
198
}
199
200
void DERobot_HandleLegMovement(int32 offset)
201
{
202
RSDK_THIS(DERobot);
203
EntityDERobot *knee = self->legs[offset + 0];
204
EntityDERobot *leg = self->legs[offset + 1];
205
EntityDERobot *foot = self->legs[offset + 2];
206
207
knee->position.x = 0x440 * RSDK.Sin1024(knee->angle) + self->position.x;
208
knee->position.y = 0x440 * RSDK.Cos1024(knee->angle) + self->position.y + 0x190000;
209
leg->position.x = knee->position.x;
210
leg->position.y = knee->position.y;
211
leg->angle = MAX(knee->angle >> 2, 0);
212
leg->rotation = -(leg->angle >> 1);
213
foot->position.x = 0xA00 * RSDK.Sin1024(leg->angle) + leg->position.x;
214
foot->position.y = 0xA00 * RSDK.Cos1024(leg->angle) + leg->position.y;
215
foot->onGround = false;
216
int32 storeX = foot->position.x;
217
int32 storeY = foot->position.y;
218
if (RSDK.ObjectTileGrip(foot, Zone->collisionLayers, CMODE_FLOOR, 0, -0x100000, 0x100000, 32)) {
219
foot->position.y = storeY;
220
if (RSDK.ObjectTileGrip(foot, Zone->collisionLayers, CMODE_FLOOR, 0, 0x100000, 0x100000, 32))
221
foot->rotation = 2 * RSDK.ATan2(32, (foot->position.y >> 16) - (foot->position.y >> 16));
222
}
223
foot->position.x = storeX;
224
foot->position.y = storeY;
225
if (RSDK.ObjectTileCollision(foot, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0x110000, true))
226
foot->onGround = true;
227
}
228
229
void DERobot_HandleLegMovement2(int32 offset)
230
{
231
RSDK_THIS(DERobot);
232
EntityDERobot *leg = self->legs[offset + 0];
233
EntityDERobot *foot = self->legs[offset + 1];
234
EntityDERobot *knee = self->legs[offset - 1];
235
leg->position.x = foot->position.x - 0xA00 * RSDK.Sin1024(leg->angle);
236
leg->position.y = foot->position.y - 0xA00 * RSDK.Cos1024(leg->angle);
237
leg->angle -= leg->angle >> 3;
238
leg->rotation -= leg->rotation >> 3;
239
knee->position.x = leg->position.x;
240
knee->position.y = leg->position.y;
241
self->position.x = knee->position.x - 0x440 * RSDK.Sin1024(knee->angle);
242
self->position.y = knee->position.y - (0x440 * RSDK.Cos1024(knee->angle)) - 0x190000;
243
}
244
245
void DERobot_HandleArmMovement(int32 offset)
246
{
247
RSDK_THIS(DERobot);
248
EntityDERobot *arm = self->arms[offset + 0];
249
EntityDERobot *hand = self->arms[offset + 1];
250
arm->position.x = 0x600 * (RSDK.Sin1024(arm->angle) - 0x200) + self->position.x;
251
arm->position.y = 0x600 * (RSDK.Cos1024(arm->angle) - 0x300) + self->position.y;
252
hand->position.x = arm->position.x + 0x600 * RSDK.Cos1024(MIN(arm->angle, 0));
253
hand->position.y = arm->position.y - 0x600 * RSDK.Sin1024(MIN(arm->angle, 0));
254
}
255
256
void DERobot_HandleTerrainDestruction(void)
257
{
258
RSDK_THIS(DERobot);
259
int32 tx = (self->position.x + 0xC0000) >> 20;
260
if (tx > self->destroyedTerrainX) {
261
self->destroyedTerrainX = tx;
262
int32 ty = (self->position.y >> 20) - 16;
263
264
int32 spawnX = (tx << 20) + 0x80000;
265
int32 spawnY = (ty << 20) + 0x80000;
266
267
bool32 playSfx = false;
268
for (int32 i = 0; i < 32; ++i) {
269
uint16 tile = RSDK.GetTile(Zone->fgLayer[1], tx, ty);
270
if (tile != (uint16)-1) {
271
RSDK.SetTile(Zone->fgLayer[1], tx, ty, -1);
272
273
EntityBreakableWall *wall = CREATE_ENTITY(BreakableWall, INT_TO_VOID(BREAKWALL_TILE_FIXED), spawnX, spawnY);
274
wall->drawGroup = Zone->objectDrawGroup[1];
275
wall->visible = true;
276
wall->tileInfo = tile;
277
wall->velocity.x = RSDK.Rand(-0x20000, 0x20000);
278
wall->velocity.y = RSDK.Rand(-0x20000, 0x20000);
279
wall->drawFX = FX_ROTATE | FX_FLIP;
280
playSfx = true;
281
}
282
++ty;
283
spawnY += 0x100000;
284
}
285
286
if (playSfx)
287
RSDK.PlaySfx(DERobot->sfxLedgeBreak, false, 255);
288
}
289
}
290
291
void DERobot_DestroyTerrainFinal(void)
292
{
293
RSDK_THIS(DERobot);
294
295
int32 tx = (self->position.x >> 20) - 4;
296
int32 ty = (self->position.y >> 20) - 16;
297
298
int32 spawnX = (tx << 20) + 0x80000;
299
for (int32 y = 0; y < 8; ++y) {
300
int32 spawnY = (ty << 20) + 0x80000;
301
for (int32 x = 0; x < 32; ++x) {
302
uint16 tile = RSDK.GetTile(Zone->fgLayer[0], tx, ty);
303
if (tile != (uint16)-1) {
304
RSDK.SetTile(Zone->fgLayer[0], tx, ty, -1);
305
306
EntityBreakableWall *wall = CREATE_ENTITY(BreakableWall, INT_TO_VOID(BREAKWALL_TILE_FIXED), spawnX, spawnY);
307
wall->drawGroup = Zone->objectDrawGroup[1];
308
wall->visible = true;
309
wall->tileInfo = tile;
310
wall->velocity.x = RSDK.Rand(-0x20000, 0x20000);
311
wall->velocity.y = RSDK.Rand(-0x20000, 0x20000);
312
wall->drawFX = FX_ROTATE | FX_FLIP;
313
}
314
++ty;
315
spawnY += 0x100000;
316
}
317
spawnX += 0x100000;
318
ty -= 32;
319
++tx;
320
}
321
322
tx = (self->position.x >> 20) - 4;
323
ty = (self->position.y >> 20) - 16;
324
spawnX = (tx << 20) + 0x80000;
325
for (int32 y = 0; y < 32; ++y) {
326
int32 spawnY = (ty << 20) + 0x80000;
327
for (int32 x = 0; x < 32; ++x) {
328
uint16 tile = RSDK.GetTile(Zone->fgLayer[1], tx, ty);
329
if (tile != (uint16)-1) {
330
RSDK.SetTile(Zone->fgLayer[1], tx, ty, -1);
331
EntityBreakableWall *wall = CREATE_ENTITY(BreakableWall, INT_TO_VOID(BREAKWALL_TILE_FIXED), spawnX, spawnY);
332
wall->drawGroup = Zone->objectDrawGroup[1];
333
wall->visible = true;
334
wall->tileInfo = tile;
335
wall->velocity.x = RSDK.Rand(-0x20000, 0x20000);
336
wall->velocity.y = RSDK.Rand(-0x20000, 0x20000);
337
wall->drawFX = FX_ROTATE | FX_FLIP;
338
}
339
++ty;
340
spawnY += 0x100000;
341
}
342
spawnX += 0x100000;
343
ty -= 32;
344
++tx;
345
}
346
}
347
348
void DERobot_Hit(void)
349
{
350
RSDK_THIS(DERobot);
351
352
if (--self->health <= 0) {
353
self->timer = 0;
354
self->state = DERobot_State_Explode;
355
SceneInfo->timeEnabled = false;
356
Player_GiveScore(RSDK_GET_ENTITY(SLOT_PLAYER1, Player), 1000);
357
self->arms[1]->state = DERobot_State_ArmDestroyed;
358
self->arms[3]->state = DERobot_State_ArmDestroyed;
359
}
360
else {
361
self->invincibilityTimer = 48;
362
RSDK.PlaySfx(DERobot->sfxHit, false, 255);
363
if (self->health == 2) {
364
self->kneeAngleVel = 16;
365
self->angleVelStart = 0x20000;
366
self->angleMaxInc = -0x4000;
367
self->legs[0]->angleVel *= 2;
368
self->legs[0]->angleInc *= 4;
369
self->legs[3]->angleVel *= 2;
370
self->legs[3]->angleInc *= 4;
371
}
372
}
373
}
374
375
void DERobot_Explode(void)
376
{
377
RSDK_THIS(DERobot);
378
379
if (!(Zone->timer % 3)) {
380
RSDK.PlaySfx(DERobot->sfxExplosion, false, 0xFF);
381
382
if ((Zone->timer & 4)) {
383
int32 x = self->position.x + (RSDK.Rand(-48, 48) << 16);
384
int32 y = self->position.y + (RSDK.Rand(-48, 48) << 16);
385
EntityExplosion *explosion = CREATE_ENTITY(Explosion, INT_TO_VOID((RSDK.Rand(0, 256) > 192) + EXPLOSION_BOSS), x, y);
386
explosion->drawGroup = Zone->objectDrawGroup[1];
387
}
388
}
389
}
390
391
void DERobot_CheckPlayerCollisions_Body(void)
392
{
393
RSDK_THIS(DERobot);
394
395
if (self->invincibilityTimer > 0) {
396
self->invincibilityTimer--;
397
398
if ((self->invincibilityTimer & 2)) {
399
RSDK.SetPaletteEntry(0, 236, 0xC0C0C0);
400
RSDK.SetPaletteEntry(0, 237, 0xD0D0D0);
401
RSDK.SetPaletteEntry(0, 238, 0xE0E0E0);
402
RSDK.SetPaletteEntry(0, 239, 0xF0F0F0);
403
RSDK.SetPaletteEntry(0, 244, 0xA0A0A0);
404
}
405
else {
406
RSDK.SetPaletteEntry(0, 236, 0x282028);
407
RSDK.SetPaletteEntry(0, 237, 0x383040);
408
RSDK.SetPaletteEntry(0, 238, 0x484868);
409
RSDK.SetPaletteEntry(0, 239, 0x587090);
410
RSDK.SetPaletteEntry(0, 244, 0x000000);
411
}
412
}
413
414
foreach_active(Player, player)
415
{
416
if (!self->invincibilityTimer && Player_CheckBadnikTouch(player, self, &DERobot->hitboxBody) && Player_CheckBossHit(player, self)) {
417
DERobot_Hit();
418
// DERobot_Hit should already play sfxHit, not sure why its here too
419
RSDK.PlaySfx(DERobot->sfxHit, false, 255);
420
player->velocity.x = 0x60000;
421
}
422
}
423
}
424
425
void DERobot_CheckPlayerCollisions_ArmExtend(void)
426
{
427
RSDK_THIS(DERobot);
428
429
int32 extend = ((self->armExtend + 22) << 16) >> 8;
430
431
int32 angle = -(self->angle >> 3);
432
int32 left = (-0xE00 * RSDK.Sin256(angle)) + (0x1600 * RSDK.Cos256(angle));
433
int32 top = (-0xE00 * RSDK.Cos256(angle)) - (0x1600 * RSDK.Sin256(angle));
434
int32 right = (-0xE00 * RSDK.Sin256(angle)) + extend * RSDK.Cos256(angle);
435
int32 bottom = (((-0xE00 * RSDK.Cos256(angle)) - (extend * RSDK.Sin256(angle))) >> 16) - (top >> 16);
436
437
self->hitbox.left = (left >> 16);
438
self->hitbox.right = (right >> 16);
439
440
foreach_active(Player, player)
441
{
442
int32 dist = (player->position.x - self->position.x) >> 16;
443
if (dist >= left >> 16) {
444
if (dist > (right >> 16))
445
dist = (right >> 16);
446
}
447
else {
448
dist = left >> 16;
449
}
450
self->hitbox.top = (top >> 16) + bottom * (dist - (left >> 16)) / ((right >> 16) - (left >> 16));
451
self->hitbox.bottom = self->hitbox.top + 16;
452
if (Player_CheckCollisionPlatform(player, self, &self->hitbox))
453
player->position.y += 0x40000;
454
}
455
}
456
457
void DERobot_CheckPlayerCollisions_Hand(void)
458
{
459
RSDK_THIS(DERobot);
460
461
int32 storeX = self->position.x;
462
int32 storeY = self->position.y;
463
464
Vector2 pivot;
465
pivot.x = self->position.x;
466
pivot.y = self->position.y;
467
self->position.x += (self->armExtend + 35) << 16;
468
Zone_RotateOnPivot(&self->position, &pivot, -(self->angle >> 3));
469
470
foreach_active(Player, player)
471
{
472
if (Player_CheckCollisionTouch(player, self, &DERobot->hitboxHand)) {
473
#if MANIA_USE_PLUS
474
if (!Player_CheckMightyUnspin(player, 0x400, false, &player->uncurlTimer))
475
#endif
476
Player_Hurt(player, self);
477
}
478
}
479
480
DERobot_HandleTerrainDestruction();
481
self->position.x = storeX;
482
self->position.y = storeY;
483
}
484
485
bool32 DERobot_CheckRubyGrabbed(void)
486
{
487
RSDK_THIS(DERobot);
488
489
bool32 grabbedRuby = false;
490
int32 storeX = self->position.x;
491
int32 storeY = self->position.y;
492
493
Vector2 pivot;
494
pivot.x = self->position.x;
495
pivot.y = self->position.y;
496
self->position.x += (self->armExtend + 48) << 16;
497
Zone_RotateOnPivot(&self->position, &pivot, -(self->angle >> 3));
498
499
foreach_active(PhantomRuby, ruby)
500
{
501
if (abs(self->position.x - ruby->position.x) < 0x80000) {
502
if (abs(self->position.y - ruby->position.y) < 0x80000) {
503
grabbedRuby = true;
504
ruby->position.x = self->position.x;
505
ruby->position.y = self->position.y;
506
ruby->drawGroup = Zone->objectDrawGroup[0];
507
ruby->state = PhantomRuby_State_RotateToOrigin;
508
}
509
}
510
}
511
512
self->position.x = storeX;
513
self->position.y = storeY;
514
return grabbedRuby;
515
}
516
517
void DERobot_CheckPlayerCollisions_Bomb(void)
518
{
519
RSDK_THIS(DERobot);
520
521
foreach_active(Player, player)
522
{
523
if (Player_CheckCollisionTouch(player, self, &DERobot->hitboxHand))
524
Player_Hurt(player, self);
525
}
526
}
527
528
void DERobot_Draw_RelativeToParent(void)
529
{
530
RSDK_THIS(DERobot);
531
532
self->position.x = self->parent->position.x + self->offset.x;
533
self->position.y = self->parent->position.y + self->offset.y;
534
RSDK.DrawSprite(&self->mainAnimator, NULL, false);
535
}
536
537
void DERobot_Draw_Arm(void)
538
{
539
RSDK_THIS(DERobot);
540
541
self->rotation = self->angle >> 2;
542
RSDK.DrawSprite(&self->mainAnimator, NULL, false);
543
544
if (self->armExtend > 0) {
545
SpriteFrame *frame = RSDK.GetFrame(DERobot->aniFrames, self->altAnimator.animationID, self->altAnimator.frameID);
546
frame->width = self->armExtend;
547
frame->sprX = 4 * (Zone->timer & 3);
548
RSDK.DrawSprite(&self->altAnimator, NULL, false);
549
}
550
551
RSDK.GetFrame(DERobot->aniFrames, self->armAnimator.animationID, self->armAnimator.frameID)->pivotX = self->armExtend + 22;
552
RSDK.DrawSprite(&self->armAnimator, NULL, false);
553
}
554
555
void DERobot_Draw_Simple(void)
556
{
557
RSDK_THIS(DERobot);
558
559
RSDK.DrawSprite(&self->mainAnimator, NULL, false);
560
}
561
562
void DERobot_Draw_FrontLeg(void)
563
{
564
RSDK_THIS(DERobot);
565
566
self->drawFX = FX_NONE;
567
self->rotation = -(self->angle >> 1);
568
RSDK.DrawSprite(&self->mainAnimator, NULL, false);
569
570
self->drawFX = FX_ROTATE;
571
RSDK.DrawSprite(&self->altAnimator, NULL, false);
572
}
573
574
void DERobot_Draw_Target(void)
575
{
576
RSDK_THIS(DERobot);
577
578
Vector2 drawPos;
579
580
self->mainAnimator.frameID = 0;
581
self->inkEffect = INK_ALPHA;
582
self->direction = FLIP_NONE;
583
drawPos.x = self->position.x - self->offset.x;
584
drawPos.y = self->position.y - self->offset.y;
585
RSDK.DrawSprite(&self->mainAnimator, &drawPos, false);
586
587
self->direction = FLIP_X;
588
drawPos.x = self->position.x + self->offset.x;
589
drawPos.y = self->position.y - self->offset.y;
590
RSDK.DrawSprite(&self->mainAnimator, &drawPos, false);
591
592
self->mainAnimator.frameID = 1;
593
self->direction = FLIP_NONE;
594
drawPos.x = self->position.x - self->offset.x;
595
drawPos.y = self->position.y + self->offset.y;
596
RSDK.DrawSprite(&self->mainAnimator, &drawPos, false);
597
598
self->direction = FLIP_X;
599
drawPos.x = self->position.x + self->offset.x;
600
drawPos.y = self->position.y + self->offset.y;
601
RSDK.DrawSprite(&self->mainAnimator, &drawPos, false);
602
603
self->inkEffect = INK_NONE;
604
self->direction = FLIP_NONE;
605
RSDK.DrawSprite(&self->altAnimator, NULL, false);
606
RSDK.DrawSprite(&self->armAnimator, NULL, false);
607
}
608
609
void DERobot_State_ArmIdle(void)
610
{
611
RSDK_THIS(DERobot);
612
613
RSDK.ProcessAnimation(&self->armAnimator);
614
if (self->armAnimator.speed > 0x40)
615
self->armAnimator.speed -= 4;
616
617
DERobot_CheckPlayerCollisions_Hand();
618
}
619
620
void DERobot_State_ArmExtendPrepare(void)
621
{
622
RSDK_THIS(DERobot);
623
624
RSDK.ProcessAnimation(&self->armAnimator);
625
626
if (self->armAnimator.speed == 240)
627
RSDK.PlaySfx(DERobot->sfxBuzzsaw, false, 255);
628
629
if (self->armAnimator.speed >= 0x100)
630
self->state = DERobot_State_ArmExtending;
631
else
632
self->armAnimator.speed += 4;
633
634
DERobot_CheckPlayerCollisions_Hand();
635
}
636
637
void DERobot_State_ArmExtending(void)
638
{
639
RSDK_THIS(DERobot);
640
641
RSDK.ProcessAnimation(&self->altAnimator);
642
RSDK.ProcessAnimation(&self->armAnimator);
643
if (self->armExtend < 192)
644
self->armExtend += 8;
645
646
DERobot_CheckPlayerCollisions_ArmExtend();
647
DERobot_CheckPlayerCollisions_Hand();
648
649
if (++self->timer == 120) {
650
self->timer = 0;
651
self->state = DERobot_State_ArmRetracting;
652
}
653
}
654
655
void DERobot_State_ArmRetracting(void)
656
{
657
RSDK_THIS(DERobot);
658
659
RSDK.ProcessAnimation(&self->altAnimator);
660
RSDK.ProcessAnimation(&self->armAnimator);
661
662
if (self->armExtend <= 0) {
663
self->state = DERobot_State_ArmIdle;
664
}
665
else {
666
DERobot_CheckPlayerCollisions_ArmExtend();
667
self->armExtend -= 8;
668
}
669
670
DERobot_CheckPlayerCollisions_Hand();
671
}
672
673
void DERobot_State_ArmDestroyed(void)
674
{
675
RSDK_THIS(DERobot);
676
677
RSDK.ProcessAnimation(&self->altAnimator);
678
RSDK.ProcessAnimation(&self->armAnimator);
679
680
if (self->armExtend > 0)
681
self->armExtend -= 8;
682
}
683
684
void DERobot_Cutscene_ActivateArm(void)
685
{
686
RSDK_THIS(DERobot);
687
RSDK.ProcessAnimation(&self->armAnimator);
688
689
if (self->angle > -96)
690
self->angle -= 4;
691
692
if (self->armAnimator.speed < 0x80)
693
self->armAnimator.speed += 4;
694
695
if (self->timer++ == -1)
696
RSDK.PlaySfx(DERobot->sfxButton2, false, 255);
697
698
if (self->timer == 30) {
699
self->timer = 0;
700
self->state = DERobot_Cutscene_ReachForRuby;
701
RSDK.PlaySfx(DERobot->sfxBuzzsaw, false, 255);
702
}
703
}
704
705
void DERobot_Cutscene_ReachForRuby(void)
706
{
707
RSDK_THIS(DERobot);
708
709
RSDK.ProcessAnimation(&self->altAnimator);
710
RSDK.ProcessAnimation(&self->armAnimator);
711
712
if (DERobot_CheckRubyGrabbed() || self->armExtend >= 192)
713
self->state = DERobot_Cutscene_GrabbedRuby;
714
else
715
self->armExtend += 8;
716
}
717
718
void DERobot_Cutscene_GrabbedRuby(void)
719
{
720
RSDK_THIS(DERobot);
721
722
RSDK.ProcessAnimation(&self->altAnimator);
723
RSDK.ProcessAnimation(&self->armAnimator);
724
725
if (self->armExtend <= 0) {
726
RSDK.StopSfx(DERobot->sfxBuzzsaw);
727
self->state = DERobot_Cutscene_ArmDeactivate;
728
}
729
else {
730
self->armExtend -= 8;
731
DERobot_CheckRubyGrabbed();
732
}
733
}
734
735
void DERobot_Cutscene_ArmDeactivate(void)
736
{
737
RSDK_THIS(DERobot);
738
739
RSDK.ProcessAnimation(&self->armAnimator);
740
741
if (self->armAnimator.speed)
742
self->armAnimator.speed--;
743
}
744
745
void DERobot_State_CloseHeadHatch(void)
746
{
747
RSDK_THIS(DERobot);
748
749
self->timer++;
750
if (self->timer == 30) {
751
RSDK.PlaySfx(DERobot->sfxButton2, false, 255);
752
}
753
754
if (self->timer >= 30) {
755
if (self->rotation >= 0) {
756
self->timer = 0;
757
self->state = 0;
758
self->drawFX = FX_NONE;
759
RSDK.PlaySfx(DERobot->sfxHullClose, false, 255);
760
}
761
else {
762
self->rotation += 8;
763
}
764
}
765
}
766
767
void DERobot_State_BombLaunched(void)
768
{
769
RSDK_THIS(DERobot);
770
771
self->angle += 7;
772
if (self->angle > 480) {
773
self->velocity.y += 0x4000;
774
self->position.x += self->velocity.x;
775
self->position.y += self->velocity.y;
776
}
777
else {
778
self->velocity.x = self->position.x;
779
self->position.x = self->offset.x - self->scale.x * RSDK.Cos1024(self->angle);
780
self->velocity.x = self->position.x - self->velocity.x;
781
self->velocity.y = self->position.y;
782
self->position.y = self->offset.y - self->scale.y * RSDK.Sin1024(self->angle);
783
self->velocity.y = self->position.y - self->velocity.y;
784
}
785
786
if (RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0xE0000, true))
787
self->state = DERobot_State_BombLanded;
788
789
DERobot_CheckPlayerCollisions_Bomb();
790
}
791
792
void DERobot_State_BombLanded(void)
793
{
794
RSDK_THIS(DERobot);
795
796
RSDK.ProcessAnimation(&self->mainAnimator);
797
798
if (self->mainAnimator.speed >= 0x80) {
799
self->visible = false;
800
self->state = DERobot_State_BombExplode;
801
EntityExplosion *explosion = CREATE_ENTITY(Explosion, INT_TO_VOID(EXPLOSION_BOSSPUFF), self->position.x, self->position.y - 0x80000);
802
explosion->drawGroup = Zone->objectDrawGroup[1];
803
RSDK.PlaySfx(DERobot->sfxExplosion, false, 255);
804
}
805
else {
806
self->mainAnimator.speed++;
807
}
808
809
DERobot_CheckPlayerCollisions_Bomb();
810
}
811
812
void DERobot_State_BombExplode(void)
813
{
814
RSDK_THIS(DERobot);
815
816
self->position.y -= 0x20000;
817
818
++self->timer;
819
if (self->timer < 16)
820
DERobot_CheckPlayerCollisions_Bomb();
821
822
if (!(self->timer & 7)) {
823
EntityExplosion *explosion = CREATE_ENTITY(Explosion, INT_TO_VOID(EXPLOSION_BOSSPUFF), self->position.x, self->position.y);
824
explosion->drawGroup = Zone->objectDrawGroup[1];
825
}
826
827
if (self->timer == 32)
828
destroyEntity(self);
829
}
830
831
void DERobot_State_SetupArena(void)
832
{
833
RSDK_THIS(DERobot);
834
835
if (++self->timer >= 8) {
836
self->timer = 0;
837
838
EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);
839
if (player1->position.y <= self->position.y + 0x200000 && player1->state != Player_State_TubeRoll) {
840
for (int32 i = 0; i < Player->playerCount; ++i) {
841
Zone->cameraBoundsL[i] = (self->position.x >> 16) - ScreenInfo->center.x + 128;
842
Zone->cameraBoundsR[i] = ScreenInfo->center.x + 128 + (self->position.x >> 16);
843
Zone->cameraBoundsB[i] = self->position.y >> 16;
844
Zone->playerBoundsB[i] = Zone->cameraBoundsB[i] << 16;
845
Zone->playerBoundActiveL[i] = true;
846
Zone->playerBoundActiveR[i] = true;
847
Zone->playerBoundActiveB[i] = false;
848
}
849
self->position.y -= 0x1800000;
850
self->active = ACTIVE_NORMAL;
851
self->state = DERobot_State_SetupBoss;
852
}
853
}
854
}
855
856
void DERobot_State_SetupBoss(void)
857
{
858
RSDK_THIS(DERobot);
859
860
EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);
861
862
if (self->timer) {
863
self->timer++;
864
if (self->timer == 60) {
865
CREATE_ENTITY(DERobot, INT_TO_VOID(DEROBOT_TARGET_EDGE), self->position.x, 0x3080000);
866
RSDK.PlaySfx(DERobot->sfxTargeting, false, 255);
867
Music_TransitionTrack(TRACK_EGGMAN1, 0.0125);
868
}
869
870
if (self->timer == 160) {
871
self->timer = 0;
872
self->visible = true;
873
self->state = DERobot_State_SurpriseFall;
874
if (player1->characterID == ID_TAILS)
875
player1->stateAbility = Player_JumpAbility_Tails;
876
877
EntityDERobot *kneeBack = self->legs[0];
878
kneeBack->active = ACTIVE_NORMAL;
879
kneeBack->visible = true;
880
881
EntityDERobot *legBack = self->legs[1];
882
legBack->active = ACTIVE_NORMAL;
883
legBack->visible = true;
884
885
EntityDERobot *footBack = self->legs[2];
886
footBack->active = ACTIVE_NORMAL;
887
footBack->visible = true;
888
889
EntityDERobot *kneeFront = self->legs[3];
890
kneeFront->active = ACTIVE_NORMAL;
891
kneeFront->visible = true;
892
893
EntityDERobot *legFront = self->legs[4];
894
legFront->active = ACTIVE_NORMAL;
895
legFront->visible = true;
896
897
EntityDERobot *footFront = self->legs[5];
898
footFront->active = ACTIVE_NORMAL;
899
footFront->visible = true;
900
901
EntityDERobot *head = self->head;
902
head->active = ACTIVE_NORMAL;
903
head->visible = true;
904
head->rotation = -128;
905
906
EntityDERobot *shoulder = self->shoulderFront;
907
shoulder->active = ACTIVE_NORMAL;
908
shoulder->visible = true;
909
910
EntityDERobot *armBack = self->arms[0];
911
armBack->active = ACTIVE_NORMAL;
912
armBack->visible = true;
913
914
EntityDERobot *handBack = self->arms[1];
915
handBack->active = ACTIVE_NORMAL;
916
handBack->visible = true;
917
918
EntityDERobot *armFront = self->arms[2];
919
armFront->active = ACTIVE_NORMAL;
920
armFront->visible = true;
921
922
EntityDERobot *handFront = self->arms[3];
923
handFront->active = ACTIVE_NORMAL;
924
handFront->visible = true;
925
926
EntityEggman *eggman = self->eggman;
927
RSDK.ResetEntity(eggman, Eggman->classID, self);
928
eggman->state = Eggman_State_ProcessAnimation;
929
eggman->animID = 0;
930
eggman->offset.x = -0x40000;
931
eggman->offset.y = -0x200000;
932
}
933
}
934
else if (player1->position.x > 0x800000 + self->position.x && player1->onGround) {
935
RSDK_GET_ENTITY(SLOT_CAMERA1, Camera)->boundsOffset.x = 1;
936
937
++self->timer;
938
if (player1->characterID == ID_TAILS)
939
player1->stateAbility = StateMachine_None;
940
}
941
942
foreach_active(Player, player)
943
{
944
if (player->state == Player_State_TubeRoll || player->state == Player_State_TubeAirRoll)
945
player->state = Player_State_Air;
946
}
947
}
948
949
void DERobot_State_Target(void)
950
{
951
RSDK_THIS(DERobot);
952
953
RSDK.ProcessAnimation(&self->altAnimator);
954
RSDK.ProcessAnimation(&self->armAnimator);
955
956
if (self->parent) {
957
self->position.x = self->parent->position.x;
958
self->position.y = self->parent->position.y;
959
}
960
961
self->alpha += 0x20;
962
self->offset.x -= self->velocity.x;
963
if (self->offset.x <= 0xC0000) {
964
self->alpha = 0;
965
self->offset.x = 0x2C0000;
966
}
967
968
self->offset.y = self->offset.x;
969
if (++self->timer == 60)
970
RSDK.SetSpriteAnimation(DERobot->aniFrames, 8, &self->armAnimator, true, 0);
971
972
if (self->timer == 96) {
973
self->parent = 0;
974
foreach_active(DERobot, robot)
975
{
976
if (!robot->aniID) {
977
robot->offset.x = self->position.x;
978
robot->offset.y = self->position.y;
979
}
980
}
981
}
982
983
if (self->timer == 128)
984
destroyEntity(self);
985
}
986
987
void DERobot_State_SurpriseFall(void)
988
{
989
RSDK_THIS(DERobot);
990
991
self->velocity.y += 0x3800;
992
self->position.y += self->velocity.y;
993
994
DERobot_HandleLegMovement(0);
995
DERobot_HandleLegMovement(3);
996
997
if (self->legs[2]->onGround) {
998
self->angleVel = -0x10000;
999
self->state = DERobot_State_FallLand;
1000
RSDK.SetSpriteAnimation(Eggman->aniFrames, 2, &self->eggman->animator, true, 0);
1001
self->eggman->state = Eggman_State_ProcessThenSet;
1002
Camera_ShakeScreen(0, 0, 8);
1003
RSDK.PlaySfx(DERobot->sfxLedgeBreak, false, 255);
1004
}
1005
1006
DERobot_HandleArmMovement(0);
1007
DERobot_HandleArmMovement(2);
1008
}
1009
1010
void DERobot_State_FallLand(void)
1011
{
1012
RSDK_THIS(DERobot);
1013
1014
EntityDERobot *kneeBack = self->legs[0];
1015
EntityDERobot *kneeFront = self->legs[3];
1016
1017
kneeBack->angle += self->angleVel >> 12;
1018
if (kneeBack->angle <= 0) {
1019
self->angleVel += 2048;
1020
}
1021
else {
1022
kneeBack->angle = 0;
1023
self->angleVel = 0;
1024
self->movingSide = 0;
1025
kneeBack->angleVel = 0x10000;
1026
kneeBack->angleInc = 0;
1027
kneeFront->angleVel = 0x10000;
1028
kneeFront->angleInc = 0;
1029
self->kneeAngleVel = 8;
1030
self->angleVelStart = 0x10000;
1031
self->angleMaxInc = -0x1000;
1032
RSDK.SetSpriteAnimation(Eggman->aniFrames, 3, &self->eggman->animator, true, 0);
1033
self->eggman->state = Eggman_State_ProcessThenSet;
1034
self->head->state = DERobot_State_CloseHeadHatch;
1035
self->state = DERobot_State_Walk;
1036
}
1037
kneeFront->angle = kneeBack->angle;
1038
1039
DERobot_HandleLegMovement2(1);
1040
DERobot_HandleLegMovement2(4);
1041
DERobot_HandleArmMovement(0);
1042
DERobot_HandleArmMovement(2);
1043
1044
DERobot_CheckPlayerCollisions_Body();
1045
}
1046
1047
void DERobot_State_Walk(void)
1048
{
1049
RSDK_THIS(DERobot);
1050
1051
int32 id = self->movingSide;
1052
1053
EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);
1054
DERobot_HandleScreenBounds();
1055
1056
++self->timer;
1057
if (self->timer == 240) {
1058
EntityDERobot *robotPart = CREATE_ENTITY(DERobot, INT_TO_VOID(DEROBOT_TARGET_EDGE), self->position.x, 0x3080000);
1059
robotPart->parent = (Entity *)player1;
1060
RSDK.PlaySfx(DERobot->sfxTargeting, false, 0xFF);
1061
}
1062
else if (self->timer == 340) {
1063
self->timer = 0;
1064
if (self->offset.x - self->position.x <= 0xD00000) {
1065
self->arms[3]->state = DERobot_State_ArmExtendPrepare;
1066
self->state = DERobot_State_ArmAttack;
1067
}
1068
else {
1069
EntityDERobot *robotPart = CREATE_ENTITY(DERobot, INT_TO_VOID(DEROBOT_BOMB), self->position.x - 0x360000, self->position.y - 0x60000);
1070
robotPart->offset.x = (self->offset.x >> 1) + ((self->position.x - 0x360000) >> 1);
1071
robotPart->offset.y = robotPart->position.y;
1072
robotPart->scale.y = 0x2000;
1073
robotPart->scale.x = (self->offset.x - self->position.x + 0x360000) >> 11;
1074
RSDK.PlaySfx(DERobot->sfxDrop, false, 255);
1075
}
1076
}
1077
1078
if (self->movingSide == 3) {
1079
self->arms[0]->angle += (-112 - self->arms[0]->angle) >> 4;
1080
self->arms[1]->angle += (64 - self->arms[1]->angle) >> 4;
1081
if (self->timer >= 240 && player1->position.x - self->position.x <= 0xD00000) {
1082
int32 armAngle =
1083
4 * RSDK.ATan2((player1->position.x - self->arms[3]->position.x) >> 16, (player1->position.y - self->arms[3]->position.y) >> 16);
1084
1085
if (armAngle > 0x200)
1086
armAngle = armAngle - 0x400;
1087
1088
armAngle = CLAMP(armAngle, -0x60, 0x80);
1089
int32 armAngle2 = MIN(self->arms[2]->angle + (-(self->arms[2]->angle + armAngle) >> 3), 0x80);
1090
1091
self->arms[2]->angle = armAngle2;
1092
self->arms[3]->angle += (armAngle - self->arms[3]->angle) >> 3;
1093
}
1094
else {
1095
self->arms[2]->angle += (0x70 - self->arms[2]->angle) >> 4;
1096
self->arms[3]->angle += (-0x20 - self->arms[3]->angle) >> 4;
1097
}
1098
}
1099
else {
1100
self->arms[0]->angle += (112 - self->arms[0]->angle) >> 4;
1101
self->arms[1]->angle += (-32 - self->arms[1]->angle) >> 4;
1102
if (self->timer >= 240 && player1->position.x - self->position.x <= 0xD00000) {
1103
int32 armAngle =
1104
4 * RSDK.ATan2((player1->position.x - self->arms[3]->position.x) >> 16, (player1->position.y - self->arms[3]->position.y) >> 16);
1105
if (armAngle > 0x200)
1106
armAngle = armAngle - 0x400;
1107
armAngle = MIN(armAngle, 0x80);
1108
1109
int32 armAngle2 = MIN(self->arms[2]->angle + (-(self->arms[2]->angle + armAngle) >> 3), 0x80);
1110
1111
self->arms[2]->angle = armAngle2;
1112
self->arms[3]->angle += (armAngle - self->arms[3]->angle) >> 3;
1113
}
1114
else {
1115
self->arms[2]->angle += (-112 - self->arms[2]->angle) >> 4;
1116
self->arms[3]->angle += (64 - self->arms[3]->angle) >> 4;
1117
}
1118
}
1119
1120
DERobot_HandleArmMovement(0);
1121
DERobot_HandleArmMovement(2);
1122
1123
EntityDERobot *knee = self->legs[id];
1124
EntityDERobot *leg = self->legs[((id + 3) % 6) + 0];
1125
EntityDERobot *foot = self->legs[((id + 3) % 6) + 2];
1126
knee->angle -= self->kneeAngleVel;
1127
DERobot_HandleLegMovement2(id + 1);
1128
1129
leg->angle += leg->angleVel >> 12;
1130
leg->angleVel += leg->angleInc;
1131
if (leg->angle > 176)
1132
leg->angleInc = self->angleMaxInc;
1133
1134
DERobot_HandleLegMovement((id + 3) % 6);
1135
1136
if (foot->onGround && (-knee->angle >> 6) > 0) {
1137
self->movingSide = (self->movingSide + 3) % 6;
1138
leg->angleVel = self->angleVelStart;
1139
leg->angleInc = 0;
1140
Camera_ShakeScreen(0, 0, 4);
1141
RSDK.PlaySfx(DERobot->sfxImpact, false, 255);
1142
if (self->position.x > 0x4D800000) {
1143
self->health = 1;
1144
DERobot_Hit();
1145
foreach_active(CollapsingPlatform, platform) { platform->stoodPos.x = platform->position.x; }
1146
}
1147
}
1148
1149
DERobot_CheckPlayerCollisions_Body();
1150
}
1151
1152
void DERobot_State_ArmAttack(void)
1153
{
1154
RSDK_THIS(DERobot);
1155
1156
DERobot_HandleScreenBounds();
1157
EntityDERobot *armBack = self->arms[0];
1158
if (self->movingSide == 3) {
1159
armBack->angle += (-112 - armBack->angle) >> 4;
1160
self->arms[1]->angle += (64 - self->arms[1]->angle) >> 4;
1161
}
1162
else {
1163
armBack->angle += (112 - armBack->angle) >> 4;
1164
self->arms[1]->angle += (-32 - self->arms[1]->angle) >> 4;
1165
}
1166
1167
if (self->arms[3]->state == DERobot_State_ArmRetracting)
1168
self->state = DERobot_State_Walk;
1169
1170
DERobot_HandleArmMovement(0);
1171
DERobot_HandleArmMovement(2);
1172
1173
EntityDERobot *knee = self->legs[self->movingSide];
1174
knee->angle -= self->kneeAngleVel;
1175
DERobot_HandleLegMovement2(self->movingSide + 1);
1176
1177
EntityDERobot *leg = self->legs[((self->movingSide + 3) % 6) + 0];
1178
EntityDERobot *foot = self->legs[((self->movingSide + 3) % 6) + 2];
1179
1180
leg->angle += leg->angleVel >> 12;
1181
leg->angleVel += leg->angleInc;
1182
if (leg->angle > 176)
1183
leg->angleInc = self->angleMaxInc;
1184
1185
DERobot_HandleLegMovement((self->movingSide + 3) % 6);
1186
1187
if (foot->onGround && (-knee->angle >> 6) > 0) {
1188
self->movingSide = (self->movingSide + 3) % 6;
1189
leg->angleVel = self->angleVelStart;
1190
leg->angleInc = 0;
1191
Camera_ShakeScreen(0, 0, 4);
1192
RSDK.PlaySfx(DERobot->sfxImpact, false, 0xFF);
1193
if (self->position.x > 0x4E000000) {
1194
self->health = 1;
1195
DERobot_Hit();
1196
}
1197
}
1198
1199
DERobot_CheckPlayerCollisions_Body();
1200
}
1201
1202
void DERobot_State_Explode(void)
1203
{
1204
RSDK_THIS(DERobot);
1205
1206
DERobot_Explode();
1207
1208
if (++self->timer == 90) {
1209
foreach_active(DERobot, robot)
1210
{
1211
switch (robot->aniID) {
1212
case DEROBOT_BODY: break;
1213
case DEROBOT_HEAD:
1214
robot->velocity.x = -0x10000;
1215
robot->velocity.y = -0x40000;
1216
robot->angleVel = -8;
1217
robot->drawFX = FX_ROTATE;
1218
robot->state = DERobot_State_DebrisFall;
1219
robot->stateDraw = DERobot_Draw_Simple;
1220
break;
1221
1222
case DEROBOT_ARM:
1223
case DEROBOT_LEG:
1224
case DEROBOT_SPIKES:
1225
case DEROBOT_ARM_THREAD:
1226
case DEROBOT_TARGET_EDGE:
1227
case DEROBOT_TARGET_CENTER:
1228
robot->velocity.x = RSDK.Rand(-0x40000, 0x40000);
1229
robot->velocity.y = RSDK.Rand(-0x40000, -0x10000);
1230
robot->angleVel = RSDK.Rand(-16, 16);
1231
robot->drawFX = FX_ROTATE;
1232
robot->state = DERobot_State_DebrisFall;
1233
if (robot->stateDraw == DERobot_Draw_RelativeToParent)
1234
robot->stateDraw = DERobot_Draw_Simple;
1235
break;
1236
}
1237
}
1238
1239
RSDK.SetSpriteAnimation(Eggman->aniFrames, 4, &self->eggman->animator, true, 0);
1240
self->timer = 0;
1241
self->offset.x = 0;
1242
self->velocity.y = -0x40000;
1243
self->state = DERobot_State_ExplodeTerrain;
1244
RSDK.PlaySfx(DERobot->sfxLedgeBreak, false, 0xFF);
1245
}
1246
}
1247
1248
void DERobot_State_ExplodeTerrain(void)
1249
{
1250
RSDK_THIS(DERobot);
1251
1252
DERobot_Explode();
1253
1254
self->velocity.y += 0x3800;
1255
self->position.y += self->velocity.y;
1256
1257
if (RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0x280000, true)) {
1258
DERobot_DestroyTerrainFinal();
1259
RSDK.PlaySfx(DERobot->sfxLedgeBreak, false, 255);
1260
self->state = DERobot_State_Finish;
1261
self->velocity.y = -0x10000 - (self->velocity.y >> 1);
1262
Camera_ShakeScreen(0, 0, 8);
1263
}
1264
1265
if (self->offset.x < 0x480000)
1266
self->offset.x += 0x40000;
1267
1268
foreach_active(Player, player)
1269
{
1270
if (player->position.x < self->offset.x + self->position.x) {
1271
player->position.x = self->offset.x + self->position.x;
1272
player->velocity.x = 0x40000;
1273
player->groundVel = 0x40000;
1274
}
1275
}
1276
}
1277
1278
void DERobot_State_Finish(void)
1279
{
1280
RSDK_THIS(DERobot);
1281
1282
self->velocity.y += 0x2000;
1283
self->position.y += self->velocity.y;
1284
1285
if (++self->timer == 96)
1286
RSDK.PlaySfx(DERobot->sfxDrop, false, 255);
1287
1288
if (self->timer == 180) {
1289
Music_TransitionTrack(TRACK_STAGE, 0.0125);
1290
1291
EntityEggPrison *prison = (EntityEggPrison *)self->eggman;
1292
RSDK.ResetEntity(prison, EggPrison->classID, INT_TO_VOID(EGGPRISON_FLYING));
1293
prison->position.x = (ScreenInfo->position.x + ScreenInfo->center.x) << 16;
1294
prison->checkTileCollisions = true;
1295
prison->position.y = (ScreenInfo->position.y - 48) << 16;
1296
1297
foreach_all(BoundsMarker, marker) { destroyEntity(marker); }
1298
self->state = DERobot_State_FinishBounds;
1299
}
1300
1301
if (!(Zone->timer & 7)) {
1302
int32 x = (RSDK.Rand(-48, 48) << 16) + self->position.x;
1303
int32 y = (RSDK.Rand(-48, 48) << 16) + self->position.y;
1304
EntityExplosion *explosion = CREATE_ENTITY(Explosion, INT_TO_VOID(EXPLOSION_BOSSPUFF), x, y);
1305
explosion->drawGroup = Zone->objectDrawGroup[1];
1306
}
1307
1308
foreach_active(Player, player)
1309
{
1310
if (player->position.x < self->position.x + 0x480000) {
1311
player->position.x = self->position.x + 0x480000;
1312
player->velocity.x = 0;
1313
player->groundVel = 0;
1314
player->pushing = false;
1315
}
1316
}
1317
}
1318
1319
void DERobot_State_DebrisFall(void)
1320
{
1321
RSDK_THIS(DERobot);
1322
1323
self->velocity.y += 0x3800;
1324
self->position.x += self->velocity.x;
1325
self->position.y += self->velocity.y;
1326
1327
self->rotation += self->angleVel;
1328
1329
if (!RSDK.CheckOnScreen(self, NULL))
1330
destroyEntity(self);
1331
}
1332
1333
void DERobot_State_FinishBounds(void)
1334
{
1335
RSDK_THIS(DERobot);
1336
1337
foreach_active(Player, player)
1338
{
1339
if (player->position.x < self->position.x + 0x480000) {
1340
player->position.x = self->position.x + 0x480000;
1341
player->velocity.x = 0;
1342
player->groundVel = 0;
1343
player->pushing = false;
1344
}
1345
1346
if (player->position.x > 0x4E800000) {
1347
player->position.x = 0x4E800000;
1348
player->velocity.x = 0;
1349
player->groundVel = 0;
1350
player->pushing = false;
1351
}
1352
}
1353
}
1354
1355
void DERobot_State_CutsceneExplode(void)
1356
{
1357
RSDK_THIS(DERobot);
1358
1359
if (!(Zone->timer & 0x3F)) {
1360
int32 x = (RSDK.Rand(-32, 32) << 16) + self->position.x;
1361
int32 y = (RSDK.Rand(-32, 32) << 16) + self->position.y;
1362
EntityExplosion *explosion = CREATE_ENTITY(Explosion, INT_TO_VOID(EXPLOSION_BOSSPUFF), x, y);
1363
explosion->drawGroup = Zone->objectDrawGroup[1];
1364
}
1365
}
1366
1367
#if GAME_INCLUDE_EDITOR
1368
void DERobot_EditorDraw(void)
1369
{
1370
RSDK_THIS(DERobot);
1371
1372
self->drawFX = FX_NONE;
1373
self->parent = (Entity *)self;
1374
1375
switch (self->aniID) {
1376
case DEROBOT_BODY:
1377
self->stateDraw = DERobot_Draw_Simple;
1378
RSDK.SetSpriteAnimation(DERobot->aniFrames, self->aniID, &self->mainAnimator, true, self->frameID);
1379
1380
if (showGizmos()) {
1381
RSDK_DRAWING_OVERLAY(true);
1382
DrawHelpers_DrawArenaBounds(-WIDE_SCR_XCENTER + 128, -SCREEN_YSIZE, WIDE_SCR_XCENTER + 128, 0, 1 | 0 | 4 | 8, 0x00C0F0);
1383
1384
int32 slot = RSDK.GetEntitySlot(self);
1385
for (int32 i = -7; i < 7; ++i) {
1386
if (i == 0) // thats this object lol
1387
continue;
1388
1389
EntityDERobot *child = RSDK_GET_ENTITY(slot + i, DERobot);
1390
1391
if (child)
1392
DrawHelpers_DrawArrow(self->position.x, self->position.y, child->position.x, child->position.y, 0xFFFF00, INK_NONE, 0xFF);
1393
}
1394
1395
RSDK_DRAWING_OVERLAY(false);
1396
}
1397
break;
1398
1399
case DEROBOT_HEAD:
1400
self->stateDraw = DERobot_Draw_RelativeToParent;
1401
self->drawFX = FX_ROTATE;
1402
self->offset.x = -0x160000;
1403
self->offset.y = -0x240000;
1404
RSDK.SetSpriteAnimation(DERobot->aniFrames, self->aniID, &self->mainAnimator, true, self->frameID);
1405
break;
1406
1407
case DEROBOT_ARM:
1408
if (self->frameID == 2) {
1409
RSDK.SetSpriteAnimation(DERobot->aniFrames, 5, &self->altAnimator, true, 0);
1410
RSDK.SetSpriteAnimation(DERobot->aniFrames, 4, &self->armAnimator, true, 0);
1411
self->stateDraw = DERobot_Draw_Arm;
1412
self->drawFX = FX_ROTATE;
1413
self->state = DERobot_State_ArmIdle;
1414
}
1415
else if (self->frameID) {
1416
self->stateDraw = DERobot_Draw_Simple;
1417
}
1418
else {
1419
self->stateDraw = DERobot_Draw_RelativeToParent;
1420
self->offset.x = -0xC0000;
1421
self->offset.y = -0x100000;
1422
}
1423
RSDK.SetSpriteAnimation(DERobot->aniFrames, self->aniID, &self->mainAnimator, true, self->frameID);
1424
break;
1425
1426
case DEROBOT_LEG:
1427
if (self->frameID) {
1428
self->stateDraw = DERobot_Draw_Simple;
1429
}
1430
else {
1431
RSDK.SetSpriteAnimation(DERobot->aniFrames, self->aniID, &self->altAnimator, true, 1);
1432
self->stateDraw = DERobot_Draw_FrontLeg;
1433
}
1434
1435
if (self->frameID > 1)
1436
self->drawFX = FX_ROTATE;
1437
RSDK.SetSpriteAnimation(DERobot->aniFrames, self->aniID, &self->mainAnimator, true, self->frameID);
1438
break;
1439
1440
case DEROBOT_TARGET_EDGE:
1441
self->drawFX = FX_FLIP;
1442
RSDK.SetSpriteAnimation(DERobot->aniFrames, 7, &self->altAnimator, true, 0);
1443
self->stateDraw = DERobot_Draw_Target;
1444
RSDK.SetSpriteAnimation(DERobot->aniFrames, self->aniID, &self->mainAnimator, true, self->frameID);
1445
break;
1446
1447
default:
1448
self->stateDraw = DERobot_Draw_Simple;
1449
RSDK.SetSpriteAnimation(DERobot->aniFrames, self->aniID, &self->mainAnimator, true, self->frameID);
1450
break;
1451
}
1452
1453
StateMachine_Run(self->stateDraw);
1454
}
1455
1456
void DERobot_EditorLoad(void)
1457
{
1458
DERobot->aniFrames = RSDK.LoadSpriteAnimation("GHZ/DERobot.bin", SCOPE_STAGE);
1459
1460
RSDK_ACTIVE_VAR(DERobot, aniID);
1461
RSDK_ENUM_VAR("Body", DEROBOT_BODY);
1462
RSDK_ENUM_VAR("Head", DEROBOT_HEAD);
1463
RSDK_ENUM_VAR("Arm", DEROBOT_ARM);
1464
RSDK_ENUM_VAR("Leg", DEROBOT_LEG);
1465
RSDK_ENUM_VAR("Spikes", DEROBOT_SPIKES);
1466
RSDK_ENUM_VAR("Arm Thread", DEROBOT_ARM_THREAD);
1467
RSDK_ENUM_VAR("Target Edge", DEROBOT_TARGET_EDGE);
1468
RSDK_ENUM_VAR("Target Center", DEROBOT_TARGET_CENTER);
1469
RSDK_ENUM_VAR("Target Lock", DEROBOT_TARGET_LOCK);
1470
RSDK_ENUM_VAR("Bomb", DEROBOT_BOMB);
1471
RSDK_ENUM_VAR("Body (Cutscene)", DEROBOT_BODY_CUTSCENE);
1472
}
1473
#endif
1474
1475
void DERobot_Serialize(void)
1476
{
1477
RSDK_EDITABLE_VAR(DERobot, VAR_ENUM, aniID);
1478
RSDK_EDITABLE_VAR(DERobot, VAR_ENUM, frameID);
1479
}
1480
1481