Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/HCZ/HandLauncher.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: HandLauncher Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectHandLauncher *HandLauncher;
11
12
void HandLauncher_Update(void)
13
{
14
RSDK_THIS(HandLauncher);
15
16
if (self->handAnimator.animationID == 2 && self->handAnimator.frameID == self->handAnimator.frameCount - 1) // Finished "Hand Grab" Animation
17
RSDK.SetSpriteAnimation(HandLauncher->aniFrames, 3, &self->handAnimator, true, 0);
18
else if (self->handAnimator.animationID == 4
19
&& self->handAnimator.frameID == self->handAnimator.frameCount - 1) // Finished "Hand Release" Animation
20
RSDK.SetSpriteAnimation(HandLauncher->aniFrames, 1, &self->handAnimator, true, 0);
21
22
StateMachine_Run(self->state);
23
24
if (self->grabDelay > 0)
25
self->grabDelay--;
26
27
RSDK.ProcessAnimation(&self->baseAnimator);
28
RSDK.ProcessAnimation(&self->handAnimator);
29
}
30
31
void HandLauncher_LateUpdate(void) {}
32
33
void HandLauncher_StaticUpdate(void)
34
{
35
foreach_active(HandLauncher, launcher) { RSDK.AddDrawListRef(Zone->playerDrawGroup[1], RSDK.GetEntitySlot(launcher)); }
36
}
37
38
void HandLauncher_Draw(void)
39
{
40
RSDK_THIS(HandLauncher);
41
42
if (SceneInfo->currentDrawGroup == Zone->playerDrawGroup[1]) {
43
if (self->state == HandLauncher_State_GrabbedPlayer)
44
RSDK.DrawSprite(&self->handAnimator, NULL, false);
45
}
46
else {
47
RSDK.DrawSprite(&self->baseAnimator, NULL, false);
48
if (self->state != HandLauncher_State_GrabbedPlayer)
49
RSDK.DrawSprite(&self->handAnimator, NULL, false);
50
}
51
}
52
53
void HandLauncher_Create(void *data)
54
{
55
RSDK_THIS(HandLauncher);
56
57
self->active = ACTIVE_BOUNDS;
58
self->drawGroup = Zone->objectDrawGroup[0];
59
self->visible = true;
60
self->drawFX = FX_FLIP;
61
62
if (!self->speed)
63
self->speed = 16;
64
65
self->startPos = self->position;
66
self->updateRange.x = 0x800000;
67
self->updateRange.y = 0x800000;
68
self->state = HandLauncher_State_Init;
69
}
70
71
void HandLauncher_StageLoad(void)
72
{
73
HandLauncher->active = ACTIVE_ALWAYS;
74
75
HandLauncher->aniFrames = RSDK.LoadSpriteAnimation("HCZ/HandLauncher.bin", SCOPE_STAGE);
76
77
// only the cheat code was removed from HCZ/HandPulley, the actual code for dunkey mode still remains in-tact
78
HandLauncher->sfxDunkey = RSDK.GetSfx("HCZ/Dunkey.wav");
79
80
HandLauncher->hitboxRange.left = -24;
81
HandLauncher->hitboxRange.top = -240;
82
HandLauncher->hitboxRange.right = 24;
83
HandLauncher->hitboxRange.bottom = 0;
84
85
HandLauncher->hitboxGrab.left = -4;
86
HandLauncher->hitboxGrab.top = -54;
87
HandLauncher->hitboxGrab.right = 4;
88
HandLauncher->hitboxGrab.bottom = 0;
89
90
// No idea what ths was for tbh
91
HandLauncher->hitboxUnused.left = -32;
92
HandLauncher->hitboxUnused.top = 0;
93
HandLauncher->hitboxUnused.right = 32;
94
HandLauncher->hitboxUnused.bottom = 24;
95
}
96
97
void HandLauncher_CheckPlayerCollisions(void)
98
{
99
RSDK_THIS(HandLauncher);
100
101
if (self->grabDelay <= 0) {
102
foreach_active(Player, player)
103
{
104
int32 playerID = RSDK.GetEntitySlot(player);
105
106
if ((self->state == HandLauncher_State_GrabbedPlayer || !player->sidekick) && !((1 << playerID) & self->activePlayers)) {
107
if (player->onGround) {
108
if (Player_CheckCollisionTouch(player, self, &HandLauncher->hitboxGrab)) {
109
self->activePlayers |= 1 << playerID;
110
player->groundVel = 0;
111
if (self->state != HandLauncher_State_GrabbedPlayer) {
112
if (HandLauncher->dunkeyMode)
113
RSDK.PlaySfx(HandLauncher->sfxDunkey, false, 0xFF);
114
else
115
RSDK.PlaySfx(Player->sfxRoll, false, 0xFF);
116
}
117
118
if (!HandLauncher->dunkeyMode)
119
RSDK.PlaySfx(Player->sfxGrab, false, 0xFF);
120
121
RSDK.SetSpriteAnimation(player->aniFrames, ANI_RUN, &player->animator, false, 0);
122
player->nextGroundState = StateMachine_None;
123
player->nextAirState = StateMachine_None;
124
player->rotation = 0;
125
player->state = Player_State_Static;
126
}
127
}
128
}
129
}
130
}
131
}
132
133
bool32 HandLauncher_CheckPlayerInRange(void)
134
{
135
RSDK_THIS(HandLauncher);
136
137
if (self->activePlayers)
138
return true;
139
140
int32 storeX = self->position.x;
141
int32 storeY = self->position.y;
142
self->position = self->playerPos;
143
144
bool32 inRange = false;
145
foreach_active(Player, player)
146
{
147
if (Player_CheckCollisionTouch(player, self, &HandLauncher->hitboxRange)) {
148
inRange = true;
149
foreach_break;
150
}
151
}
152
153
self->position.x = storeX;
154
self->position.y = storeY;
155
return inRange;
156
}
157
158
void HandLauncher_ReleasePlayers(void)
159
{
160
RSDK_THIS(HandLauncher);
161
162
int32 releaseVel = self->speed * (2 * (self->direction == FLIP_NONE) - 1);
163
164
foreach_active(Player, player)
165
{
166
int32 playerID = RSDK.GetEntitySlot(player);
167
168
if (((1 << playerID) & self->activePlayers)) {
169
self->activePlayers &= ~(1 << playerID);
170
player->onGround = true;
171
player->groundVel = releaseVel << 16;
172
player->state = Player_State_Ground;
173
}
174
}
175
}
176
177
void HandLauncher_HandleGrabbedPlayers(void)
178
{
179
RSDK_THIS(HandLauncher);
180
181
foreach_active(Player, player)
182
{
183
int32 playerID = RSDK.GetEntitySlot(player);
184
if (((1 << playerID) & self->activePlayers)) {
185
player->velocity.x = 0;
186
player->velocity.y = 0;
187
player->direction = self->direction != FLIP_NONE;
188
player->position.x = self->position.x;
189
player->position.y = self->position.y - 0x140000;
190
if (self->playerPos.y - 0x140000 < player->position.y)
191
player->position.y -= 0x140000;
192
}
193
}
194
}
195
196
void HandLauncher_State_Init(void)
197
{
198
RSDK_THIS(HandLauncher);
199
200
self->hiddenPos = self->startPos;
201
self->hiddenPos.y += 0x4E0000;
202
203
self->playerPos = self->hiddenPos;
204
self->playerPos.y -= 0x360000;
205
206
self->position = self->hiddenPos;
207
208
RSDK.SetSpriteAnimation(HandLauncher->aniFrames, 0, &self->baseAnimator, true, 0);
209
self->baseAnimator.speed = 0;
210
RSDK.SetSpriteAnimation(HandLauncher->aniFrames, 1, &self->handAnimator, true, 0);
211
212
self->state = HandLauncher_State_AwaitPlayer;
213
}
214
215
void HandLauncher_State_AwaitPlayer(void)
216
{
217
RSDK_THIS(HandLauncher);
218
219
// Out of range, lower "Hand Position" to hide it
220
self->position = self->hiddenPos;
221
self->position.y -= ((self->hiddenPos.y - self->playerPos.y) >> 3) * MIN(self->timer, 8);
222
223
if (self->timer > 0)
224
self->timer--;
225
226
if (self->timer < 0)
227
self->timer = 0;
228
229
if (HandLauncher_CheckPlayerInRange())
230
self->state = HandLauncher_State_TryGrabPlayer;
231
}
232
233
void HandLauncher_State_TryGrabPlayer(void)
234
{
235
RSDK_THIS(HandLauncher);
236
237
// In Range, raise "Hand Position" to show it
238
self->position = self->hiddenPos;
239
self->position.y -= ((self->hiddenPos.y - self->playerPos.y) >> 3) * MIN(self->timer, 8);
240
241
if (self->timer < 8)
242
self->timer++;
243
244
if (self->timer > 8)
245
self->timer = 8;
246
247
HandLauncher_CheckPlayerCollisions();
248
249
if (self->activePlayers) {
250
RSDK.SetSpriteAnimation(HandLauncher->aniFrames, 2, &self->handAnimator, true, 0);
251
self->timer = 0;
252
self->baseAnimator.speed = 1;
253
self->state = HandLauncher_State_GrabbedPlayer;
254
}
255
256
HandLauncher_HandleGrabbedPlayers();
257
258
if (!HandLauncher_CheckPlayerInRange())
259
self->state = HandLauncher_State_AwaitPlayer;
260
}
261
262
void HandLauncher_State_GrabbedPlayer(void)
263
{
264
RSDK_THIS(HandLauncher);
265
266
if (self->timer < 3) {
267
self->position = self->playerPos;
268
269
int32 dist = (self->playerPos.y - self->startPos.y) / 3;
270
if (self->timer <= 3)
271
self->position.y -= dist * self->timer;
272
else
273
self->position.y -= dist * 3;
274
}
275
else {
276
if (self->timer < 63) {
277
self->position = self->startPos;
278
}
279
else if (self->timer < 66) {
280
self->position = self->playerPos;
281
int32 dist = (self->playerPos.y - self->startPos.y) / 3;
282
self->position.y -= dist * MIN(66 - self->timer, 3);
283
}
284
else {
285
HandLauncher_ReleasePlayers();
286
if (!HandLauncher->dunkeyMode)
287
RSDK.PlaySfx(Player->sfxRelease, false, 0xFF);
288
289
RSDK.SetSpriteAnimation(HandLauncher->aniFrames, 4, &self->handAnimator, true, 0);
290
self->position = self->playerPos;
291
self->grabDelay = 30;
292
self->timer = 0;
293
self->baseAnimator.speed = 0;
294
self->state = HandLauncher_State_AwaitPlayer;
295
}
296
}
297
298
if (self->state == HandLauncher_State_GrabbedPlayer)
299
self->timer++;
300
301
HandLauncher_CheckPlayerCollisions();
302
HandLauncher_HandleGrabbedPlayers();
303
}
304
305
#if GAME_INCLUDE_EDITOR
306
void HandLauncher_EditorDraw(void)
307
{
308
RSDK_THIS(HandLauncher);
309
310
RSDK.SetSpriteAnimation(HandLauncher->aniFrames, 0, &self->baseAnimator, true, 0);
311
RSDK.SetSpriteAnimation(HandLauncher->aniFrames, 1, &self->handAnimator, true, 0);
312
313
RSDK.DrawSprite(&self->baseAnimator, NULL, false);
314
RSDK.DrawSprite(&self->handAnimator, NULL, false);
315
316
if (showGizmos()) {
317
self->hiddenPos = self->position;
318
self->hiddenPos.y += 0x4E0000;
319
self->inkEffect = INK_BLEND;
320
321
RSDK.DrawSprite(&self->baseAnimator, &self->hiddenPos, false);
322
RSDK.DrawSprite(&self->handAnimator, &self->hiddenPos, false);
323
324
self->inkEffect = INK_NONE;
325
}
326
}
327
328
void HandLauncher_EditorLoad(void)
329
{
330
HandLauncher->aniFrames = RSDK.LoadSpriteAnimation("HCZ/HandLauncher.bin", SCOPE_STAGE);
331
332
RSDK_ACTIVE_VAR(HandLauncher, direction);
333
RSDK_ENUM_VAR("Right", FLIP_NONE);
334
RSDK_ENUM_VAR("Left", FLIP_X);
335
}
336
#endif
337
338
void HandLauncher_Serialize(void)
339
{
340
RSDK_EDITABLE_VAR(HandLauncher, VAR_UINT8, direction);
341
RSDK_EDITABLE_VAR(HandLauncher, VAR_UINT32, speed);
342
}
343
344