Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/PGZ/IceSpring.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: IceSpring Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectIceSpring *IceSpring;
11
12
void IceSpring_Update(void)
13
{
14
RSDK_THIS(IceSpring);
15
16
// this was unironically fun to decompile
17
// so many label jumps
18
// - RMG
19
self->activePlayers = 0;
20
21
if (self->state) {
22
if (!self->animator.speed) {
23
// Bug Details:
24
// due to this foreach loop using playerID as a variable instead of player->playerID there's a bug where if you have P2 hit the spring
25
// while P1 is in debug mode the animator will be copied into P1's slot instead of P2's one Fix: use player->playerID or playerID =
26
// RSDK.GetEntitySlot(player) instead of a manual playerID variable
27
int32 playerID = 0;
28
29
foreach_active(Player, player)
30
{
31
if (!self->planeFilter || player->collisionPlane == ((uint8)(self->planeFilter - 1) & 1)) {
32
int32 storeX = player->position.x;
33
int32 storeY = player->position.y;
34
35
int32 collided = false;
36
if (player->state == Ice_PlayerState_Frozen)
37
collided = MathHelpers_CheckBoxCollision(self, &self->hitbox, player, &Ice->hitboxPlayerBlockOuter);
38
else
39
collided = MathHelpers_CheckBoxCollision(self, &self->hitbox, player, Player_GetHitbox(player));
40
41
if (collided) {
42
int32 type = self->type;
43
bool32 canSpring = false;
44
switch (self->type) {
45
default:
46
case ICESPRING_DIAGONAL: break;
47
48
case ICESPRING_VERTICAL: canSpring = (self->direction & FLIP_Y) ? collided == C_BOTTOM : collided == C_TOP; break;
49
50
case ICESPRING_HORIZONTAL: canSpring = (self->direction & FLIP_X) ? collided == C_LEFT : collided == C_RIGHT; break;
51
}
52
53
if (!canSpring && type == ICESPRING_DIAGONAL)
54
canSpring |= (player->onGround || player->velocity.y >= 0 || abs(player->velocity.x) > -player->velocity.y);
55
56
if (canSpring) {
57
self->activePlayers |= 1 << playerID;
58
memcpy(&IceSpring->animators[playerID], &player->animator, sizeof(Animator));
59
}
60
61
EntityShield *shield = RSDK_GET_ENTITY(Player->playerCount + RSDK.GetEntitySlot(player), Shield);
62
if (player->state != Ice_PlayerState_Frozen && shield->shieldAnimator.animationID != SHIELDANI_FIREATTACK
63
#if MANIA_USE_PLUS
64
&& player->state != Player_State_MightyHammerDrop
65
#endif
66
) {
67
if (player->shield == SHIELD_FIRE && player->invincibleTimer <= 0 && !self->shatterTimer) {
68
self->shatterTimer = 15;
69
Ice_ShatterGenerator(6, 8, 8, 0, 0, false);
70
}
71
}
72
else if (!canSpring
73
#if MANIA_USE_PLUS
74
|| player->state == Player_State_MightyHammerDrop
75
#endif
76
) {
77
switch (collided) {
78
case C_TOP: IceSpring_Shatter(0, 0); break;
79
case C_LEFT:
80
case C_RIGHT: IceSpring_Shatter(player->velocity.x, 0); break;
81
case C_BOTTOM: IceSpring_Shatter(0, player->velocity.y); break;
82
default: break;
83
}
84
85
foreach_return;
86
}
87
}
88
89
player->position.x = storeX;
90
player->position.y = storeY;
91
}
92
93
++playerID;
94
}
95
}
96
97
StateMachine_Run(self->state);
98
99
for (int32 i = 0; i < Player->playerCount; ++i) {
100
if ((1 << i) & self->activePlayers) {
101
EntityPlayer *player = RSDK_GET_ENTITY(i, Player);
102
if (IceSpring->animators[i].animationID == ANI_JUMP)
103
memcpy(&player->animator, &IceSpring->animators[i], sizeof(Animator));
104
105
player->applyJumpCap = false;
106
if (player->sidekick && self->activePlayers == 0b10) {
107
RSDK.SetSpriteAnimation(IceSpring->aniFrames, self->type, &self->animator, true, 0);
108
self->animator.speed = 0;
109
self->activePlayers = 0;
110
}
111
}
112
}
113
114
RSDK.ProcessAnimation(&self->animator);
115
if (self->animator.frameID == 7)
116
IceSpring_Shatter(0, 0);
117
}
118
119
if (self->shatterTimer > 0) {
120
if (self->animator.frameID <= 0) {
121
--self->shatterTimer;
122
if (self->shatterTimer <= 0)
123
IceSpring_Shatter(0, 0);
124
}
125
else
126
self->shatterTimer = 0;
127
}
128
}
129
130
void IceSpring_LateUpdate(void) {}
131
132
void IceSpring_StaticUpdate(void) {}
133
134
void IceSpring_Draw(void)
135
{
136
RSDK_THIS(IceSpring);
137
138
RSDK.DrawSprite(&self->animator, NULL, false);
139
}
140
141
void IceSpring_Create(void *data)
142
{
143
RSDK_THIS(IceSpring);
144
145
self->drawFX = FX_FLIP;
146
if (!SceneInfo->inEditor) {
147
self->type %= 3;
148
if (data) {
149
self->type = (VOID_TO_INT(data) >> 0) & 0xFF;
150
self->flipFlag = (VOID_TO_INT(data) >> 8) & 0xFF;
151
}
152
153
RSDK.SetSpriteAnimation(IceSpring->aniFrames, self->type, &self->animator, true, 0);
154
self->active = ACTIVE_BOUNDS;
155
self->animator.speed = 0;
156
self->updateRange.x = 0x600000;
157
self->updateRange.y = 0x600000;
158
self->visible = true;
159
160
if (self->planeFilter && ((uint8)(self->planeFilter - 1) & 2))
161
self->drawGroup = Zone->objectDrawGroup[1];
162
else
163
self->drawGroup = Zone->objectDrawGroup[0];
164
165
switch (self->type) {
166
case ICESPRING_VERTICAL:
167
self->velocity.y = 0x80000 * (self->flipFlag ? 1 : -1);
168
self->direction = self->flipFlag;
169
170
self->hitbox.left = -16;
171
self->hitbox.top = -8;
172
self->hitbox.right = 16;
173
self->hitbox.bottom = 8;
174
175
self->state = Spring_State_Vertical;
176
break;
177
178
case ICESPRING_HORIZONTAL:
179
self->velocity.x = 0x80000 * (self->flipFlag ? -1 : 1);
180
self->direction = self->flipFlag;
181
182
self->hitbox.left = -8;
183
self->hitbox.top = -16;
184
self->hitbox.right = 8;
185
self->hitbox.bottom = 16;
186
187
self->state = Spring_State_Horizontal;
188
break;
189
190
case ICESPRING_DIAGONAL:
191
self->direction = self->flipFlag;
192
self->velocity.x = 0x54000 * ((self->flipFlag & 1) ? -1 : 1);
193
self->velocity.y = 0x54000 * ((self->flipFlag < 2) ? -1 : 1);
194
195
self->hitbox.left = -12;
196
self->hitbox.top = -12;
197
self->hitbox.right = 12;
198
self->hitbox.bottom = 12;
199
200
self->state = Spring_State_Diagonal;
201
break;
202
}
203
}
204
}
205
206
void IceSpring_StageLoad(void)
207
{
208
IceSpring->aniFrames = RSDK.LoadSpriteAnimation("PSZ2/IceSpring.bin", SCOPE_STAGE);
209
210
IceSpring->sfxBounce = RSDK.GetSfx("Global/Spring.wav");
211
IceSpring->sfxShatter = RSDK.GetSfx("Stage/WindowShatter.wav");
212
}
213
214
void IceSpring_Shatter(int32 velX, int32 velY)
215
{
216
RSDK_THIS(IceSpring);
217
218
RSDK.PlaySfx(IceSpring->sfxShatter, false, 255);
219
Ice_ShatterGenerator(16, 8, 8, velX, velY, false);
220
221
if (self->type < ICESPRING_DIAGONAL)
222
destroyEntity(self);
223
else
224
self->animator.frameID = 7;
225
}
226
227
#if GAME_INCLUDE_EDITOR
228
void IceSpring_EditorDraw(void)
229
{
230
RSDK_THIS(IceSpring);
231
232
RSDK.SetSpriteAnimation(IceSpring->aniFrames, self->type % 3, &self->animator, true, 0);
233
self->direction = self->flipFlag & 3;
234
235
IceSpring_Draw();
236
}
237
238
void IceSpring_EditorLoad(void)
239
{
240
IceSpring->aniFrames = RSDK.LoadSpriteAnimation("PSZ2/IceSpring.bin", SCOPE_STAGE);
241
242
RSDK_ACTIVE_VAR(IceSpring, type);
243
RSDK_ENUM_VAR("Vertical", ICESPRING_VERTICAL);
244
RSDK_ENUM_VAR("Horizontal", ICESPRING_HORIZONTAL);
245
RSDK_ENUM_VAR("Diagonal", ICESPRING_DIAGONAL);
246
247
RSDK_ACTIVE_VAR(IceSpring, flipFlag);
248
RSDK_ENUM_VAR("No Flip", FLIP_NONE);
249
RSDK_ENUM_VAR("Flip X", FLIP_X);
250
RSDK_ENUM_VAR("Flip Y", FLIP_Y);
251
RSDK_ENUM_VAR("Flip XY", FLIP_XY);
252
253
RSDK_ACTIVE_VAR(IceSpring, planeFilter);
254
RSDK_ENUM_VAR("None", PLANEFILTER_NONE);
255
RSDK_ENUM_VAR("AL", PLANEFILTER_AL);
256
RSDK_ENUM_VAR("BL", PLANEFILTER_BL);
257
RSDK_ENUM_VAR("AH", PLANEFILTER_AH);
258
RSDK_ENUM_VAR("BH", PLANEFILTER_BH);
259
}
260
#endif
261
262
void IceSpring_Serialize(void)
263
{
264
RSDK_EDITABLE_VAR(IceSpring, VAR_ENUM, type);
265
RSDK_EDITABLE_VAR(IceSpring, VAR_ENUM, flipFlag);
266
RSDK_EDITABLE_VAR(IceSpring, VAR_BOOL, onGround);
267
RSDK_EDITABLE_VAR(IceSpring, VAR_UINT8, planeFilter);
268
}
269
270