Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/SSZ/BouncePlant.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: BouncePlant Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectBouncePlant *BouncePlant;
11
12
void BouncePlant_Update(void)
13
{
14
RSDK_THIS(BouncePlant);
15
if (self->stood) {
16
if (self->instantRecoil) {
17
self->depression = 0x100;
18
}
19
else {
20
if (self->depression < 0x100)
21
self->depression += 0x20;
22
}
23
}
24
else {
25
if (self->depression > 0)
26
self->depression -= 0x10;
27
}
28
29
self->stood = false;
30
self->instantRecoil = false;
31
foreach_active(Player, player)
32
{
33
if (abs(player->position.x - self->position.x) <= 0x320000 && (player->velocity.y >= 0 || player->onGround)) {
34
Hitbox *playerHitbox = Player_GetHitbox(player);
35
36
if (self->stood) {
37
int32 posY = BoucePlant_GetNodeY(player->position.x) + self->stoodPos.y - (playerHitbox->bottom << 16) - 0x40000;
38
if (player->position.y > posY - 0x80000) {
39
player->velocity.x += RSDK.Sin256(self->angle) << 13 >> 8;
40
player->position.y = posY;
41
player->velocity.y = 0;
42
player->onGround = true;
43
player->groundedStore = true;
44
player->angle = 0;
45
player->collisionMode = CMODE_FLOOR;
46
player->groundVel = player->velocity.x;
47
if (player->state == Player_State_KnuxGlideSlide || player->state == Player_State_KnuxGlideDrop)
48
player->state = Player_State_Ground;
49
}
50
}
51
else {
52
int32 posY = BoucePlant_GetNodeStandY(player->position.x) + self->position.y - (playerHitbox->bottom << 16) - 0x40000;
53
if (player->position.y > posY - 0x80000 && player->position.y < self->position.y + 0x400000) {
54
player->position.y = posY;
55
if (abs(player->velocity.x) > 0xC0000)
56
self->instantRecoil = true;
57
58
if (abs(player->position.x - self->centerX) >= abs(player->velocity.x)) {
59
player->velocity.x += RSDK.Sin256(self->angle) << 13 >> 8;
60
player->velocity.y = 0;
61
player->onGround = true;
62
player->groundedStore = true;
63
player->angle = 0;
64
player->collisionMode = CMODE_FLOOR;
65
player->groundVel = player->velocity.x;
66
67
if (player->state == Player_State_KnuxGlideSlide || player->state == Player_State_KnuxGlideDrop
68
69
#if MANIA_USE_PLUS
70
|| player->state == Player_State_MightyHammerDrop
71
#endif
72
) {
73
player->state = Player_State_Ground;
74
}
75
}
76
else if (self->depression > 0xA0) {
77
if (self->direction == FLIP_NONE)
78
player->velocity.x = -0xB4000;
79
else
80
player->velocity.x = 0xB4000;
81
player->velocity.y = -0xB4000;
82
player->onGround = false;
83
player->state = Player_State_Air;
84
RSDK.SetSpriteAnimation(player->aniFrames, ANI_SPRING_DIAGONAL, &player->animator, false, 0);
85
RSDK.PlaySfx(BouncePlant->sfxBouncePlant, false, 255);
86
}
87
else if (abs(player->groundVel) <= 0xC00000) {
88
player->velocity.x += RSDK.Sin256(self->angle) << 13 >> 8;
89
player->velocity.y = 0;
90
player->onGround = true;
91
player->groundedStore = true;
92
player->angle = 0;
93
player->collisionMode = CMODE_FLOOR;
94
player->groundVel = player->velocity.x;
95
96
if (player->state == Player_State_KnuxGlideSlide || player->state == Player_State_KnuxGlideDrop
97
#if MANIA_USE_PLUS
98
|| player->state == Player_State_MightyHammerDrop
99
#endif
100
) {
101
player->state = Player_State_Ground;
102
}
103
}
104
else {
105
if (self->direction == FLIP_NONE)
106
player->velocity.x = -0xB4000;
107
else
108
player->velocity.x = 0xB4000;
109
player->velocity.y = -0xB4000;
110
player->onGround = false;
111
player->state = Player_State_Air;
112
RSDK.SetSpriteAnimation(player->aniFrames, ANI_SPRING_DIAGONAL, &player->animator, false, 0);
113
RSDK.PlaySfx(BouncePlant->sfxBouncePlant, false, 255);
114
}
115
self->stood = true;
116
self->recoilDuration = 60;
117
self->stoodPos.x = player->position.x;
118
self->stoodPos.y = self->position.y + BoucePlant_GetNodeStandY(player->position.x);
119
}
120
}
121
}
122
}
123
124
if (self->stood) {
125
for (int32 i = 0; i < BOUNCEPLANT_NODE_COUNT; ++i) self->drawPos[i].y = self->stoodPos.y + BoucePlant_GetNodeY(self->drawPos[i].x);
126
}
127
else {
128
if (self->recoilDuration <= 0) {
129
for (int32 i = 0; i < BOUNCEPLANT_NODE_COUNT; ++i) self->drawPos[i] = self->nodeStartPos[i];
130
}
131
else {
132
self->recoilDuration--;
133
134
for (int32 i = 0; i < BOUNCEPLANT_NODE_COUNT; ++i) {
135
self->recoilVelocity[i] += ((self->nodeStartPos[i].y - self->drawPos[i].y) >> 3) - (self->recoilVelocity[i] >> 3);
136
self->drawPos[i].y += self->recoilVelocity[i];
137
}
138
}
139
}
140
}
141
142
void BouncePlant_LateUpdate(void) {}
143
144
void BouncePlant_StaticUpdate(void) {}
145
146
void BouncePlant_Draw(void)
147
{
148
RSDK_THIS(BouncePlant);
149
150
for (int32 i = 0; i < BOUNCEPLANT_NODE_COUNT; ++i) {
151
RSDK.DrawSprite(&self->nodeAnimator, &self->drawPos[i], false);
152
RSDK.DrawSprite(&self->decorAnimators[i], &self->drawPos[i], false);
153
}
154
}
155
156
void BouncePlant_Create(void *data)
157
{
158
RSDK_THIS(BouncePlant);
159
if (!SceneInfo->inEditor) {
160
self->visible = true;
161
self->drawGroup = Zone->objectDrawGroup[0];
162
self->active = ACTIVE_BOUNDS;
163
self->updateRange.x = 0x800000;
164
self->updateRange.y = 0x800000;
165
BoucePlant_SetupNodePositions();
166
167
if (self->direction) {
168
self->centerX = self->position.x - 0x180000;
169
self->angle = 0x40;
170
}
171
else {
172
self->centerX = self->position.x + 0x180000;
173
self->angle = 0xC0;
174
}
175
176
RSDK.SetSpriteAnimation(BouncePlant->aniFrames, 1, &self->nodeAnimator, true, 0);
177
for (int32 i = 0; i < BOUNCEPLANT_NODE_COUNT; ++i) {
178
RSDK.SetSpriteAnimation(BouncePlant->aniFrames, 1, &self->decorAnimators[i], true, RSDK.Rand(1, 8));
179
self->drawPos[i].x = self->nodeStartPos[i].x;
180
self->drawPos[i].y = self->nodeStartPos[i].y;
181
}
182
}
183
}
184
185
void BouncePlant_StageLoad(void)
186
{
187
BouncePlant->aniFrames = RSDK.LoadSpriteAnimation("SSZ1/Plants.bin", SCOPE_STAGE);
188
189
BouncePlant->hitbox.left = -50;
190
BouncePlant->hitbox.left = -12;
191
BouncePlant->hitbox.right = 50;
192
BouncePlant->hitbox.right = 8;
193
194
BouncePlant->sfxBouncePlant = RSDK.GetSfx("SSZ1/BouncePlant.wav");
195
}
196
197
void BoucePlant_SetupNodePositions(void)
198
{
199
RSDK_THIS(BouncePlant);
200
201
if (self->direction == FLIP_NONE) {
202
int32 x = self->position.x - 0x2A0000;
203
for (int32 i = 0; i < BOUNCEPLANT_NODE_COUNT; ++i) {
204
self->nodeStartPos[i].x = x;
205
x += 0xC0000;
206
}
207
}
208
else {
209
int32 x = self->position.x + 0x2A0000;
210
for (int32 i = 0; i < BOUNCEPLANT_NODE_COUNT; ++i) {
211
self->nodeStartPos[i].x = x;
212
x -= 0xC0000;
213
}
214
}
215
216
int32 y = self->position.y + 0x2A0000;
217
for (int32 i = 0; i < BOUNCEPLANT_NODE_COUNT; ++i) {
218
self->nodeStartPos[i].y = y;
219
y -= 0xC0000;
220
}
221
}
222
223
int32 BoucePlant_GetNodeStandY(int32 x)
224
{
225
RSDK_THIS(BouncePlant);
226
227
int32 dist = 0;
228
int32 pos = 0;
229
if (self->direction == FLIP_NONE) {
230
int32 right = self->position.x + 0x180000;
231
dist = self->position.x - x;
232
if (x > right)
233
pos = 3 * (right - x);
234
else
235
pos = (right - x) / 3;
236
}
237
else {
238
int32 left = self->position.x - 0x180000;
239
dist = x - self->position.x;
240
if (x < left)
241
pos = 3 * (x - left);
242
else
243
pos = (x - left) / 3;
244
}
245
246
dist = CLAMP(dist, -0x320000, 0x320000);
247
pos = CLAMP(pos + 0x200000, -0x320000, 0x320000);
248
return dist + ((self->depression * (pos - dist)) >> 8);
249
}
250
251
int32 BoucePlant_GetNodeY(int32 x)
252
{
253
RSDK_THIS(BouncePlant);
254
255
int32 y = 0;
256
int32 distanceX = 0;
257
int32 distanceY = 0;
258
if (self->direction) {
259
y = (x - self->stoodPos.x) >> 15;
260
if (x < self->stoodPos.x) {
261
distanceX = (self->stoodPos.x - self->nodeStartPos[BOUNCEPLANT_NODE_COUNT - 1].x) >> 16;
262
distanceY = (self->stoodPos.y - self->nodeStartPos[BOUNCEPLANT_NODE_COUNT - 1].y) >> 16;
263
}
264
else {
265
distanceX = (self->nodeStartPos[0].x - self->stoodPos.x) >> 16;
266
distanceY = (self->nodeStartPos[0].y - self->stoodPos.y) >> 16;
267
}
268
}
269
else {
270
y = (self->stoodPos.x - x) >> 15;
271
if (x > self->stoodPos.x) {
272
distanceX = (self->nodeStartPos[BOUNCEPLANT_NODE_COUNT - 1].x - self->stoodPos.x) >> 16;
273
distanceY = (self->stoodPos.y - self->nodeStartPos[BOUNCEPLANT_NODE_COUNT - 1].y) >> 16;
274
}
275
else {
276
distanceX = (self->stoodPos.x - self->nodeStartPos[0].x) >> 16;
277
distanceY = (self->nodeStartPos[0].y - self->stoodPos.y) >> 16;
278
}
279
}
280
281
if (distanceX > 0)
282
y = y * distanceY / distanceX;
283
return y << 15;
284
}
285
286
#if GAME_INCLUDE_EDITOR
287
void BouncePlant_EditorDraw(void)
288
{
289
RSDK_THIS(BouncePlant);
290
291
self->drawGroup = Zone->objectDrawGroup[0];
292
self->updateRange.x = 0x800000;
293
self->updateRange.y = 0x800000;
294
BoucePlant_SetupNodePositions();
295
296
if (self->direction) {
297
self->centerX = self->position.x - 0x180000;
298
self->angle = 0x40;
299
}
300
else {
301
self->centerX = self->position.x + 0x180000;
302
self->angle = 0xC0;
303
}
304
305
RSDK.SetSpriteAnimation(BouncePlant->aniFrames, 1, &self->nodeAnimator, true, 0);
306
for (int32 i = 0; i < BOUNCEPLANT_NODE_COUNT; ++i) {
307
RSDK.SetSpriteAnimation(BouncePlant->aniFrames, 1, &self->decorAnimators[i], true, 1);
308
self->drawPos[i].x = self->nodeStartPos[i].x;
309
self->drawPos[i].y = self->nodeStartPos[i].y;
310
}
311
312
BouncePlant_Draw();
313
}
314
315
void BouncePlant_EditorLoad(void)
316
{
317
BouncePlant->aniFrames = RSDK.LoadSpriteAnimation("SSZ1/Plants.bin", SCOPE_STAGE);
318
319
RSDK_ACTIVE_VAR(BouncePlant, direction);
320
RSDK_ENUM_VAR("No Flip", FLIP_NONE);
321
RSDK_ENUM_VAR("Flip X", FLIP_X);
322
}
323
#endif
324
325
void BouncePlant_Serialize(void) { RSDK_EDITABLE_VAR(BouncePlant, VAR_UINT8, direction); }
326
327