Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/HCZ/HangConveyor.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: HangConveyor Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectHangConveyor *HangConveyor;
11
12
void HangConveyor_Update(void)
13
{
14
RSDK_THIS(HangConveyor);
15
16
RSDK.ProcessAnimation(&self->endAnimator);
17
RSDK.ProcessAnimation(&self->startAnimator);
18
RSDK.ProcessAnimation(&self->middleAnimator);
19
20
if (RSDK.CheckOnScreen(self, &self->updateRange)) {
21
HangConveyor_HandlePlayerInteractions();
22
self->active = ACTIVE_NORMAL;
23
}
24
else {
25
for (int32 p = 0; p < PLAYER_COUNT; ++p) {
26
self->playerPositions[p].x = 0;
27
self->playerPositions[p].y = 0;
28
}
29
30
self->active = ACTIVE_BOUNDS;
31
}
32
}
33
34
void HangConveyor_LateUpdate(void) {}
35
36
void HangConveyor_StaticUpdate(void) {}
37
38
void HangConveyor_Draw(void) { HangConveyor_DrawSprites(); }
39
40
void HangConveyor_Create(void *data)
41
{
42
RSDK_THIS(HangConveyor);
43
44
self->active = ACTIVE_BOUNDS;
45
self->drawGroup = Zone->objectDrawGroup[0];
46
self->startPos = self->position;
47
self->visible = true;
48
self->drawFX = FX_FLIP;
49
self->updateRange.x = 0x800000;
50
self->updateRange.y = 0x800000;
51
52
HangConveyor_SetupHitboxes();
53
self->updateRange.x += (self->hitboxFallCheckTop.right - self->hitboxFallCheckTop.left) << 16;
54
55
RSDK.SetSpriteAnimation(HangConveyor->aniFrames, 0, &self->endAnimator, true, 0);
56
RSDK.SetSpriteAnimation(HangConveyor->aniFrames, 1, &self->startAnimator, true, 0);
57
RSDK.SetSpriteAnimation(HangConveyor->aniFrames, 2, &self->middleAnimator, true, 0);
58
}
59
60
void HangConveyor_StageLoad(void) { HangConveyor->aniFrames = RSDK.LoadSpriteAnimation("HCZ/HangConveyor.bin", SCOPE_STAGE); }
61
62
void HangConveyor_DrawSprites(void)
63
{
64
RSDK_THIS(HangConveyor);
65
66
Vector2 drawPos = self->position;
67
drawPos.x += -0x80000 * (self->length != 1 ? self->length - 1 : 0);
68
int32 dirStore = self->direction;
69
70
for (int32 i = 0; i < self->length; ++i) {
71
self->direction = dirStore != FLIP_NONE;
72
drawPos.y = self->position.y - 0x150000;
73
RSDK.DrawSprite(&self->middleAnimator, &drawPos, false);
74
75
self->direction = dirStore == FLIP_NONE;
76
drawPos.y = self->position.y + 0x150000;
77
RSDK.DrawSprite(&self->middleAnimator, &drawPos, false);
78
79
drawPos.x += 0x100000;
80
}
81
82
self->direction = dirStore != FLIP_NONE;
83
drawPos.x = self->position.x;
84
drawPos.y = self->position.y;
85
86
int32 len = self->length == 1 ? 4 : (self->length + 3);
87
if (dirStore) {
88
drawPos.x += len << 19;
89
}
90
else {
91
drawPos.x += -0x80000 * len;
92
}
93
RSDK.DrawSprite(&self->endAnimator, &drawPos, false);
94
95
self->direction = dirStore == FLIP_NONE;
96
drawPos.x = self->position.x;
97
drawPos.y = self->position.y;
98
99
if (dirStore) {
100
drawPos.x += -0x80000 * len;
101
}
102
else {
103
drawPos.x += len << 19;
104
}
105
RSDK.DrawSprite(&self->startAnimator, &drawPos, false);
106
107
self->direction = dirStore;
108
}
109
110
void HangConveyor_SetupHitboxes(void)
111
{
112
RSDK_THIS(HangConveyor);
113
114
self->hitboxSpikeBallRange.left = -8 * (self->length != -6 ? self->length + 6 : 0);
115
self->hitboxSpikeBallRange.top = -24;
116
self->hitboxSpikeBallRange.right = 8 * (self->length != -6 ? self->length + 6 : 0);
117
self->hitboxSpikeBallRange.bottom = 24;
118
119
self->hitboxFallCheckTop.left = -8 * (self->length != -2 ? self->length + 2 : 0);
120
self->hitboxFallCheckTop.top = -26;
121
self->hitboxFallCheckTop.right = 8 * (self->length != -2 ? self->length + 2 : 0);
122
self->hitboxFallCheckTop.bottom = -16;
123
124
// Top Left End
125
self->endPosTopLeft.x = self->position.x + (self->hitboxFallCheckTop.left << 16);
126
self->endPosTopLeft.y = self->position.y - 0x150000;
127
128
// Top Right End
129
self->endPosTopRight.x = self->position.x + (self->hitboxFallCheckTop.right << 16);
130
self->endPosTopRight.y = self->position.y - 0x150000;
131
132
self->hitboxFallCheckBottom.left = -4 - 8 * (self->length != -2 ? self->length + 2 : 0);
133
self->hitboxFallCheckBottom.top = 16;
134
self->hitboxFallCheckBottom.right = 8 * (self->length != -2 ? self->length + 2 : 0) + 4;
135
self->hitboxFallCheckBottom.bottom = 26;
136
137
// Bottom Left End
138
self->endPosBottomLeft.x = self->position.x + (self->hitboxFallCheckBottom.left << 16);
139
self->endPosBottomLeft.y = self->position.y + 0x150000;
140
141
// Bottom Right End
142
self->endPosBottomRight.x = self->position.x + (self->hitboxFallCheckBottom.right << 16);
143
self->endPosBottomRight.y = self->position.y + 0x150000;
144
}
145
146
void HangConveyor_HandlePlayerInteractions(void)
147
{
148
RSDK_THIS(HangConveyor);
149
150
foreach_active(Player, player)
151
{
152
if (Player_CheckValidState(player)) {
153
int32 playerID = RSDK.GetEntitySlot(player);
154
155
int32 playerY = player->position.y;
156
if (player->animator.animationID != ANI_POLE_SWING_V && player->animator.animationID != ANI_SHIMMY_MOVE)
157
playerY -= 0x180000;
158
159
int32 prevX = self->playerPositions[playerID].x;
160
int32 prevY = self->playerPositions[playerID].y;
161
self->playerPositions[playerID].x = player->position.x;
162
self->playerPositions[playerID].y = playerY;
163
164
if (abs(player->position.x - prevX) < 0x800000 && abs(playerY - prevY) < 0x800000 && (prevX || prevY)) {
165
bool32 collidedTop = MathHelpers_CheckPositionOverlap(player->position.x, playerY, prevX, prevY, self->endPosTopLeft.x,
166
self->endPosTopLeft.y, self->endPosTopRight.x, self->endPosTopRight.y);
167
collidedTop = collidedTop && !self->grabDelayTop[playerID];
168
169
bool32 collidedBottom =
170
MathHelpers_CheckPositionOverlap(player->position.x, playerY, prevX, prevY, self->endPosBottomLeft.x, self->endPosBottomLeft.y,
171
self->endPosBottomRight.x, self->endPosBottomRight.y);
172
collidedBottom = collidedBottom && !self->grabDelayBottom[playerID];
173
174
if (self->grabDelayTop[playerID] > 0)
175
self->grabDelayTop[playerID]--;
176
177
if (self->grabDelayBottom[playerID] > 0)
178
self->grabDelayBottom[playerID]--;
179
180
if (!((1 << playerID) & self->movementActivePlayers) && !(self->checkableActivePlayers & (1 << playerID))) {
181
if ((collidedTop || collidedBottom) && player->state != Player_State_Static && player->animator.animationID != ANI_HURT) {
182
self->movementActivePlayers |= (1 << playerID);
183
self->checkableActivePlayers |= (1 << playerID);
184
if (collidedTop) {
185
self->activePlayersTop |= 1 << playerID;
186
player->position.y = self->position.y - 0x150000;
187
}
188
if (collidedBottom) {
189
self->activePlayersBottom |= 1 << playerID;
190
player->position.y = self->position.y + 0x150000;
191
}
192
193
RSDK.PlaySfx(Player->sfxGrab, false, 255);
194
RSDK.SetSpriteAnimation(player->aniFrames, ANI_POLE_SWING_V, &player->animator, true, 0);
195
player->animator.speed = 0;
196
player->nextGroundState = StateMachine_None;
197
player->nextAirState = StateMachine_None;
198
player->velocity.x = 0;
199
player->velocity.y = 0;
200
player->rotation = 0;
201
player->state = Player_State_Static;
202
}
203
}
204
205
int32 newPlayerY = player->position.y;
206
if (player->animator.animationID != ANI_POLE_SWING_V && player->animator.animationID != ANI_SHIMMY_MOVE)
207
newPlayerY -= 0x180000;
208
209
collidedTop = MathHelpers_PointInHitbox(self->position.x, self->position.y, player->position.x, newPlayerY, self->direction,
210
&self->hitboxFallCheckTop);
211
collidedBottom = MathHelpers_PointInHitbox(self->position.x, self->position.y, player->position.x, newPlayerY, self->direction,
212
&self->hitboxFallCheckBottom);
213
214
if (((1 << playerID) & self->movementActivePlayers)) {
215
if (self->fanTimer[playerID] > 0) {
216
RSDK.SetSpriteAnimation(player->aniFrames, ANI_POLE_SWING_V, &player->animator, true, self->fanTimer[playerID] >> 1);
217
player->animator.speed = 0;
218
}
219
else if (player->left) {
220
RSDK.SetSpriteAnimation(player->aniFrames, ANI_SHIMMY_MOVE, &player->animator, false, 0);
221
player->direction = FLIP_X;
222
}
223
else if (player->right) {
224
RSDK.SetSpriteAnimation(player->aniFrames, ANI_SHIMMY_MOVE, &player->animator, false, 0);
225
player->direction = FLIP_NONE;
226
}
227
else if (!(player->animator.animationID == ANI_POLE_SWING_V && !player->animator.frameID)) {
228
RSDK.SetSpriteAnimation(player->aniFrames, ANI_POLE_SWING_V, &player->animator, false, 0);
229
player->animator.speed = 0;
230
}
231
232
if ((1 << playerID) & self->activePlayersTop) {
233
player->position.y = self->position.y - 0x150000;
234
235
int32 moveVelocity = 0;
236
if (self->direction) {
237
moveVelocity = 0x15555;
238
239
if (player->right)
240
moveVelocity = 0x20000;
241
else if (player->left)
242
moveVelocity = 0xB000;
243
}
244
else {
245
moveVelocity = -0x15555;
246
247
if (player->left)
248
moveVelocity = -0x20000;
249
if (player->right)
250
moveVelocity = -0xB000;
251
}
252
253
player->position.x += moveVelocity;
254
}
255
256
if ((1 << playerID) & self->activePlayersBottom) {
257
player->position.y = self->position.y + 0x150000;
258
259
int32 moveVelocity = 0;
260
if (self->direction) {
261
moveVelocity = -0x15555;
262
263
if (player->left)
264
moveVelocity = -0x20000;
265
else if (player->right)
266
moveVelocity = -0xB000;
267
}
268
else {
269
moveVelocity = 0x15555;
270
271
if (player->right)
272
moveVelocity = 0x20000;
273
if (player->left)
274
moveVelocity = 0xB000;
275
}
276
277
player->position.x += moveVelocity;
278
}
279
280
bool32 noCollision = false;
281
if (((1 << playerID) & self->activePlayersTop) && !collidedTop)
282
noCollision = true;
283
if (((1 << playerID) & self->activePlayersBottom) && !collidedBottom)
284
noCollision = true;
285
286
int32 anim = player->animator.animationID;
287
if (player->jumpPress || (anim != ANI_POLE_SWING_V && anim != ANI_SHIMMY_MOVE) || player->velocity.x || player->velocity.y
288
|| noCollision) {
289
290
self->movementActivePlayers &= ~(1 << playerID);
291
player->position.y += 0x180000;
292
293
if (!player->jumpPress || player->down) {
294
RSDK.SetSpriteAnimation(player->aniFrames, ANI_JUMP, &player->animator, true, 0);
295
player->state = Player_State_Air;
296
}
297
else {
298
Player_Action_Jump(player);
299
}
300
301
if ((1 << playerID) & self->activePlayersTop)
302
self->grabDelayTop[playerID] = 60;
303
304
if ((1 << playerID) & self->activePlayersBottom)
305
self->grabDelayBottom[playerID] = 60;
306
}
307
}
308
309
if (!((1 << playerID) & self->movementActivePlayers) && ((1 << playerID) & self->checkableActivePlayers)) {
310
if (((1 << playerID) & self->activePlayersTop) && !Player_CheckCollisionTouch(player, self, &self->hitboxFallCheckTop)) {
311
self->activePlayersTop &= ~(1 << playerID);
312
self->checkableActivePlayers &= ~(1 << playerID);
313
}
314
315
if (((1 << playerID) & self->activePlayersBottom) && !Player_CheckCollisionTouch(player, self, &self->hitboxFallCheckBottom)) {
316
self->activePlayersBottom &= ~(1 << playerID);
317
self->checkableActivePlayers &= ~(1 << playerID);
318
}
319
}
320
321
if (!((1 << playerID) & self->movementActivePlayers))
322
self->fanTimer[playerID] = 0;
323
}
324
}
325
}
326
}
327
328
#if GAME_INCLUDE_EDITOR
329
void HangConveyor_EditorDraw(void) { HangConveyor_DrawSprites(); }
330
331
void HangConveyor_EditorLoad(void)
332
{
333
HangConveyor->aniFrames = RSDK.LoadSpriteAnimation("HCZ/HangConveyor.bin", SCOPE_STAGE);
334
335
RSDK_ACTIVE_VAR(HangConveyor, direction);
336
RSDK_ENUM_VAR("No Flip", FLIP_NONE);
337
RSDK_ENUM_VAR("Flipped", FLIP_X);
338
}
339
#endif
340
341
void HangConveyor_Serialize(void)
342
{
343
RSDK_EDITABLE_VAR(HangConveyor, VAR_UINT8, direction);
344
RSDK_EDITABLE_VAR(HangConveyor, VAR_UINT32, length);
345
}
346
347