Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/ERZ/PhantomHand.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: PhantomHand Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectPhantomHand *PhantomHand;
11
12
void PhantomHand_Update(void)
13
{
14
RSDK_THIS(PhantomHand);
15
16
StateMachine_Run(self->state);
17
}
18
19
void PhantomHand_LateUpdate(void) {}
20
21
void PhantomHand_StaticUpdate(void) {}
22
23
void PhantomHand_Draw(void)
24
{
25
RSDK_THIS(PhantomHand);
26
27
RSDK.CopyPalette(1, 128, 0, 128, 128);
28
29
self->inkEffect = INK_ADD;
30
RSDK.DrawSprite(&self->handAnimator, NULL, false);
31
32
if (self->state != PhantomHand_State_Disappear) {
33
self->inkEffect = INK_ALPHA;
34
self->alpha = 0xD0;
35
RSDK.DrawSprite(&self->crystalAnimator, NULL, false);
36
37
self->inkEffect = INK_ADD;
38
self->alpha = 0x100;
39
RSDK.DrawSprite(&self->shineAnimator, NULL, false);
40
}
41
}
42
43
void PhantomHand_Create(void *data)
44
{
45
RSDK_THIS(PhantomHand);
46
47
if (!SceneInfo->inEditor) {
48
self->visible = true;
49
self->drawGroup = Zone->objectDrawGroup[0];
50
self->parent = (Entity *)data;
51
self->targetPos = self->position;
52
self->active = ACTIVE_NORMAL;
53
self->inkEffect = INK_ADD;
54
self->drawFX = FX_FLIP | FX_SCALE;
55
self->alpha = 0x100;
56
self->updateRange.x = 0x800000;
57
self->updateRange.y = 0x800000;
58
self->timerDecreaseSpeed = 64;
59
self->state = PhantomHand_State_Summon;
60
RSDK.SetSpriteAnimation(PhantomHand->aniFrames, 0, &self->handAnimator, true, 0);
61
}
62
}
63
64
void PhantomHand_StageLoad(void)
65
{
66
PhantomHand->aniFrames = RSDK.LoadSpriteAnimation("Phantom/PhantomHand.bin", SCOPE_STAGE);
67
68
PhantomHand->hitbox.left = -20;
69
PhantomHand->hitbox.top = -20;
70
PhantomHand->hitbox.right = 20;
71
PhantomHand->hitbox.bottom = 20;
72
73
int32 pos = 3;
74
for (int32 i = 0; i < PhantomHand->debrisInfo[0]; ++i) {
75
PhantomHand->debrisInfo[pos + 0] = RSDK.Rand(-0x20000, 0x20000);
76
PhantomHand->debrisInfo[pos + 1] = RSDK.Rand(-0x10000, -0x40000);
77
78
pos += 4;
79
}
80
81
PhantomHand->grabbedPlayers[0] = false;
82
PhantomHand->grabbedPlayers[1] = false;
83
PhantomHand->grabbedPlayers[2] = false;
84
PhantomHand->grabbedPlayers[3] = false;
85
}
86
87
void PhantomHand_CheckPlayerGrab(int32 playerX, int32 playerY)
88
{
89
RSDK_THIS(PhantomHand);
90
91
if (self->position.x >= playerX) {
92
if (self->position.x > playerX) {
93
int32 dist = MIN((self->position.x - playerX) >> 5, 0x10000);
94
self->position.x -= dist;
95
}
96
}
97
else {
98
int32 dist = MIN((playerX - self->position.x) >> 5, 0x10000);
99
self->position.x += dist;
100
}
101
102
if (self->targetPos.y < playerY)
103
self->targetPos.y += 0x10000;
104
105
if (playerY <= self->targetPos.y)
106
self->position.y += (playerY - self->position.y) >> 3;
107
else
108
self->position.y = self->targetPos.y;
109
110
foreach_active(Player, player)
111
{
112
if (player->state != Player_State_Static) {
113
int32 rx = (player->position.x - self->position.x) >> 16;
114
int32 ry = (player->position.y - self->position.y) >> 16;
115
if (rx * rx + ry * ry < 0x100) {
116
if (!PhantomHand->grabbedPlayers[player->playerID]) {
117
PhantomHand->grabbedPlayers[player->playerID] = true;
118
self->state = PhantomHand_State_GrabbedPlayer;
119
}
120
}
121
}
122
}
123
}
124
125
void PhantomHand_State_Summon(void)
126
{
127
RSDK_THIS(PhantomHand);
128
129
if (!self->timer)
130
RSDK.PlaySfx(PhantomEgg->sfxSummon, false, 255);
131
132
self->position.x += self->velocity.x;
133
if (self->timer > 0)
134
self->timerDecreaseSpeed -= 4;
135
136
self->timer += self->timerDecreaseSpeed;
137
138
if (self->timer < 0x200 && self->timerDecreaseSpeed < 0) {
139
self->timer = 0x200;
140
self->state = PhantomHand_State_Appear;
141
}
142
143
self->scaleAngle += 8;
144
self->scale.x = self->timer + ((self->timer * RSDK.Sin256(self->scaleAngle)) >> 11);
145
self->scale.y = self->timer + ((self->timer * RSDK.Cos256(self->scaleAngle)) >> 11);
146
}
147
148
void PhantomHand_State_Appear(void)
149
{
150
RSDK_THIS(PhantomHand);
151
152
RSDK.ProcessAnimation(&self->handAnimator);
153
154
self->scaleAngle += 16;
155
self->position.x += self->velocity.x;
156
157
self->scale.x = ((self->timer * RSDK.Sin256(self->scaleAngle)) >> 11) + 0x200;
158
self->scale.y = ((self->timer * RSDK.Cos256(self->scaleAngle)) >> 11) + 0x200;
159
160
if (self->timer <= 0) {
161
self->drawFX = FX_FLIP;
162
163
if (Player->playerCount < 2)
164
self->state = PhantomHand_State_TryGrabPlayer;
165
else
166
self->state = PhantomHand_State_TryGrabPlayers;
167
}
168
else {
169
self->timer -= 32;
170
}
171
}
172
173
void PhantomHand_State_TryGrabPlayer(void)
174
{
175
RSDK_THIS(PhantomHand);
176
177
RSDK.ProcessAnimation(&self->handAnimator);
178
179
EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);
180
181
if (player1->interaction == true && player1->state == Player_State_Static) {
182
self->state = PhantomHand_State_Disappear;
183
}
184
else {
185
if ((self->direction && player1->position.x <= PhantomEgg->boundsM) || (!self->direction && player1->position.x >= PhantomEgg->boundsM))
186
PhantomHand_CheckPlayerGrab(self->parent->position.x, player1->position.y);
187
else
188
PhantomHand_CheckPlayerGrab(player1->position.x, player1->position.y);
189
}
190
}
191
192
void PhantomHand_State_TryGrabPlayers(void)
193
{
194
RSDK_THIS(PhantomHand);
195
196
RSDK.ProcessAnimation(&self->handAnimator);
197
198
bool32 playersActive = true;
199
for (int32 i = SLOT_PLAYER1; i < SLOT_PLAYER1 + 2; ++i) {
200
EntityPlayer *player = RSDK_GET_ENTITY(i, Player);
201
if (player->classID == Player->classID)
202
playersActive = playersActive && player->interaction && player->state == Player_State_Static;
203
}
204
205
if (playersActive) {
206
self->state = PhantomHand_State_Disappear;
207
}
208
else {
209
int32 dist = 0x7FFFFFFF;
210
211
EntityPlayer *playerPtr = NULL;
212
if (self->direction == FLIP_NONE) {
213
foreach_active(Player, player)
214
{
215
if (player->state != Player_State_Static && self->position.x - player->position.x < dist) {
216
dist = self->position.x - self->position.x;
217
playerPtr = player;
218
}
219
}
220
}
221
else {
222
foreach_active(Player, player)
223
{
224
if (player->state != Player_State_Static && player->position.x - self->position.x < dist) {
225
dist = player->position.x - self->position.x;
226
playerPtr = player;
227
}
228
}
229
}
230
231
if (playerPtr)
232
PhantomHand_CheckPlayerGrab(playerPtr->position.x, playerPtr->position.y);
233
}
234
}
235
236
void PhantomHand_State_GrabbedPlayer(void)
237
{
238
RSDK_THIS(PhantomHand);
239
240
foreach_active(Player, player)
241
{
242
if (Player_CheckCollisionTouch(player, self, &PhantomHand->hitbox)) {
243
player->state = Player_State_Static;
244
player->nextAirState = StateMachine_None;
245
player->nextGroundState = StateMachine_None;
246
player->position.x = self->position.x;
247
player->position.y = self->position.y;
248
player->velocity.x = 0;
249
player->velocity.y = 0;
250
player->onGround = false;
251
player->groundVel = 0;
252
253
if (!player->playerID)
254
self->doScanlineCB = true;
255
256
RSDK.SetSpriteAnimation(player->aniFrames, ANI_JUMP, &player->animator, false, 0);
257
}
258
}
259
260
if (++self->grabTimer == 8) {
261
self->grabTimer = 0;
262
RSDK.SetSpriteAnimation(PhantomHand->aniFrames, 1, &self->handAnimator, true, 0);
263
self->state = PhantomHand_State_Clasp;
264
}
265
}
266
267
void PhantomHand_State_Clasp(void)
268
{
269
RSDK_THIS(PhantomHand);
270
271
RSDK.ProcessAnimation(&self->handAnimator);
272
273
if (self->handAnimator.frameID == 5)
274
self->drawGroup = Zone->objectDrawGroup[1];
275
276
if (self->handAnimator.frameID == 10) {
277
RSDK.SetSpriteAnimation(PhantomHand->aniFrames, 2, &self->crystalAnimator, true, 0);
278
self->state = PhantomHand_State_Crystalize;
279
}
280
}
281
282
void PhantomHand_State_Crystalize(void)
283
{
284
RSDK_THIS(PhantomHand);
285
286
RSDK.ProcessAnimation(&self->handAnimator);
287
RSDK.ProcessAnimation(&self->crystalAnimator);
288
289
if (self->crystalAnimator.frameID == self->crystalAnimator.frameCount - 1) {
290
RSDK.SetSpriteAnimation(-1, 0, &self->handAnimator, true, 0);
291
RSDK.SetSpriteAnimation(PhantomHand->aniFrames, 3, &self->shineAnimator, true, 0);
292
self->state = PhantomHand_State_Shine;
293
}
294
}
295
296
void PhantomHand_State_Shine(void)
297
{
298
RSDK_THIS(PhantomHand);
299
300
RSDK.ProcessAnimation(&self->shineAnimator);
301
302
if (self->shineAnimator.frameID == self->shineAnimator.frameCount - 1) {
303
RSDK.SetSpriteAnimation(-1, 0, &self->shineAnimator, true, 0);
304
305
if (self->doScanlineCB)
306
PhantomEgg_SetupWarpFX();
307
308
self->state = StateMachine_None;
309
}
310
}
311
312
void PhantomHand_State_BreakApart(void)
313
{
314
RSDK_THIS(PhantomHand);
315
316
Debris_CreateFromEntries(PhantomHand->aniFrames, PhantomHand->debrisInfo, 4);
317
RSDK.PlaySfx(PhantomEgg->sfxExplosion2, false, 255);
318
319
foreach_active(Player, player)
320
{
321
if (Player_CheckCollisionTouch(player, self, &PhantomHand->hitbox)) {
322
player->state = Player_State_Air;
323
player->velocity.y = -0x40000;
324
player->onGround = false;
325
player->groundVel = 0;
326
PhantomHand->grabbedPlayers[player->playerID] = false;
327
RSDK.SetSpriteAnimation(player->aniFrames, ANI_JUMP, &player->animator, false, 0);
328
}
329
}
330
331
destroyEntity(self);
332
}
333
334
void PhantomHand_State_Disappear(void)
335
{
336
RSDK_THIS(PhantomHand);
337
338
if (self->alpha <= 0)
339
destroyEntity(self);
340
else
341
self->alpha -= 8;
342
}
343
344
#if GAME_INCLUDE_EDITOR
345
void PhantomHand_EditorDraw(void)
346
{
347
RSDK_THIS(PhantomHand);
348
RSDK.SetSpriteAnimation(PhantomHand->aniFrames, 0, &self->handAnimator, true, 0);
349
350
RSDK.DrawSprite(&self->handAnimator, NULL, false);
351
}
352
353
void PhantomHand_EditorLoad(void) { PhantomHand->aniFrames = RSDK.LoadSpriteAnimation("Phantom/PhantomHand.bin", SCOPE_STAGE); }
354
#endif
355
356
void PhantomHand_Serialize(void) {}
357
358