Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/LRZ/LRZConvItem.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: LRZConvItem Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectLRZConvItem *LRZConvItem;
11
12
void LRZConvItem_Update(void)
13
{
14
RSDK_THIS(LRZConvItem);
15
16
StateMachine_Run(self->state);
17
18
RSDK.ProcessAnimation(&self->animator);
19
}
20
21
void LRZConvItem_LateUpdate(void) {}
22
23
void LRZConvItem_StaticUpdate(void) {}
24
25
void LRZConvItem_Draw(void)
26
{
27
RSDK_THIS(LRZConvItem);
28
29
RSDK.DrawSprite(&self->animator, NULL, false);
30
}
31
32
void LRZConvItem_Create(void *data)
33
{
34
RSDK_THIS(LRZConvItem);
35
36
if (data)
37
self->type = VOID_TO_INT(data);
38
39
self->active = ACTIVE_BOUNDS;
40
self->drawGroup = Zone->objectDrawGroup[0];
41
self->startPos = self->position;
42
self->visible = true;
43
self->drawFX = FX_FLIP;
44
self->updateRange.x = 0x800000;
45
self->updateRange.y = 0x800000;
46
47
RSDK.SetSpriteAnimation(LRZConvItem->aniFrames, self->type, &self->animator, true, 0);
48
49
if (!SceneInfo->inEditor) {
50
switch (self->type) {
51
case LRZCONVITEM_ROCK: self->state = LRZConvItem_State_Rock; break;
52
case LRZCONVITEM_SPIKEBALL: self->state = LRZConvItem_State_SpikeBall; break;
53
}
54
}
55
}
56
57
void LRZConvItem_StageLoad(void)
58
{
59
LRZConvItem->aniFrames = RSDK.LoadSpriteAnimation("LRZ2/LRZConvItem.bin", SCOPE_STAGE);
60
61
LRZConvItem_SetupHitboxes();
62
63
LRZConvItem->sfxSizzle = RSDK.GetSfx("LRZ/Sizzle.wav");
64
}
65
66
void LRZConvItem_SetupHitboxes(void)
67
{
68
LRZConvItem->hitboxRock.left = -16;
69
LRZConvItem->hitboxRock.top = -16;
70
LRZConvItem->hitboxRock.right = 16;
71
LRZConvItem->hitboxRock.bottom = 16;
72
73
LRZConvItem->hitboxSpikeball.left = -10;
74
LRZConvItem->hitboxSpikeball.top = -10;
75
LRZConvItem->hitboxSpikeball.right = 10;
76
LRZConvItem->hitboxSpikeball.bottom = 10;
77
}
78
79
Vector2 LRZConvItem_HandleLRZConvPhys(void *e)
80
{
81
EntityLRZConvItem *entity = (EntityLRZConvItem *)e;
82
83
Vector2 moveOffset;
84
moveOffset.x = 0;
85
moveOffset.y = 0;
86
if (RSDK.CheckSceneFolder("LRZ2")) {
87
int32 storeX = entity->position.x;
88
int32 storeY = entity->position.y;
89
90
Hitbox hitbox;
91
hitbox.left = 0;
92
hitbox.top = 0;
93
hitbox.right = 0;
94
hitbox.bottom = 0;
95
96
if (entity->classID == LRZConvItem->classID)
97
hitbox = LRZConvItem->hitboxRock;
98
else if (entity->classID == ItemBox->classID)
99
hitbox = ItemBox->hitboxItemBox;
100
else if (entity->classID == Iwamodoki->classID)
101
hitbox = Iwamodoki->hitboxBadnik;
102
103
// Handle Object-Based Conveyor interactions
104
bool32 conveyorCollided = false;
105
if (LRZConveyor) {
106
foreach_active(LRZConveyor, conveyor)
107
{
108
int32 moveX = (conveyor->speed << 14) * (2 * (conveyor->direction == FLIP_X) - 1);
109
if (LRZConveyor_HandlePlayerCollisions(conveyor, entity, &hitbox) == C_TOP) {
110
conveyorCollided = true;
111
if (conveyor->off) {
112
entity->velocity.x = 0;
113
}
114
else {
115
entity->position.y += 0x10000;
116
entity->active = ACTIVE_NORMAL;
117
entity->velocity.x = moveX;
118
}
119
}
120
}
121
}
122
123
// Try to collide with the floor
124
int32 prevY = entity->position.y;
125
bool32 tileCollided = RSDK.ObjectTileGrip(entity, Zone->collisionLayers, CMODE_FLOOR, 0, 0, hitbox.bottom << 16, 4);
126
if (!tileCollided) {
127
if (!RSDK.ObjectTileGrip(entity, Zone->collisionLayers, CMODE_FLOOR, 0, (hitbox.right << 16) - 0x10000, hitbox.bottom << 16, 4)
128
|| !RSDK.ObjectTileGrip(entity, Zone->collisionLayers, CMODE_FLOOR, 0, (hitbox.right << 16) - 0x10000, hitbox.bottom << 16, 4)) {
129
if (RSDK.ObjectTileGrip(entity, Zone->collisionLayers, CMODE_FLOOR, 0, (hitbox.left + 1) << 16, hitbox.bottom << 16, 4)) {
130
tileCollided =
131
RSDK.ObjectTileGrip(entity, Zone->collisionLayers, CMODE_FLOOR, 0, (hitbox.left + 1) << 16, hitbox.bottom << 16, 4);
132
}
133
}
134
}
135
136
bool32 prevOnGround = entity->onGround;
137
entity->onGround = false;
138
if (tileCollided || conveyorCollided)
139
entity->onGround = true;
140
141
int32 tileInfo = 0;
142
uint8 behaviour = LRZ2_TFLAGS_NORMAL;
143
144
// try to grab tile info & behaviour for tile-based conveyor interactions
145
LRZ2Setup_GetTileInfo(entity->position.x, entity->position.y + (hitbox.bottom << 16), 0, 0, entity->collisionPlane, &tileInfo, &behaviour);
146
if (behaviour == LRZ2_TFLAGS_NORMAL) {
147
LRZ2Setup_GetTileInfo(entity->position.x + (hitbox.right << 16), entity->position.y + (hitbox.bottom << 16), 0, 0, entity->collisionPlane,
148
&tileInfo, &behaviour);
149
}
150
if (behaviour == LRZ2_TFLAGS_NORMAL) {
151
LRZ2Setup_GetTileInfo(entity->position.x + (hitbox.left << 16), entity->position.y + (hitbox.bottom << 16), 0, 0, entity->collisionPlane,
152
&tileInfo, &behaviour);
153
}
154
if (behaviour == LRZ2_TFLAGS_NORMAL) {
155
LRZ2Setup_GetTileInfo(entity->position.x, entity->position.y + (hitbox.bottom << 16), 0, 0, entity->collisionPlane, &tileInfo,
156
&behaviour);
157
}
158
159
bool32 lavaCollided = false;
160
bool32 tileConveyorCollided = false;
161
switch (behaviour) {
162
case LRZ2_TFLAGS_NORMAL: break;
163
164
case LRZ2_TFLAGS_LAVA:
165
entity->active = ACTIVE_NORMAL;
166
167
if (prevY > entity->position.y)
168
entity->position.y = prevY;
169
170
lavaCollided = true;
171
break;
172
173
case LRZ2_TFLAGS_CONVEYOR_L:
174
tileConveyorCollided = true;
175
entity->active = ACTIVE_NORMAL;
176
177
if (entity->onGround) {
178
if (LRZ2Setup->conveyorOff)
179
entity->velocity.x = 0;
180
else
181
entity->velocity.x = (2 * ((((tileInfo & 0x400) != 0) ^ LRZ2Setup->conveyorDir) != 0) - 1) << 17;
182
}
183
break;
184
185
case LRZ2_TFLAGS_CONVEYOR_R:
186
tileConveyorCollided = true;
187
entity->active = ACTIVE_NORMAL;
188
189
if (entity->onGround) {
190
if (LRZ2Setup->conveyorOff)
191
entity->velocity.x = 0;
192
else
193
entity->velocity.x = (2 * ((((tileInfo & 0x400) != 0) ^ LRZ2Setup->conveyorDir) != 1) - 1) << 17;
194
}
195
break;
196
}
197
198
if (tileCollided) {
199
if ((lavaCollided ^ 1) && (abs(entity->velocity.x) > 0) && (tileConveyorCollided ^ 1))
200
entity->velocity.x = 0;
201
}
202
203
// Apply Gravity
204
if (entity->onGround)
205
entity->velocity.y = 0;
206
else
207
entity->velocity.y += 0x3800;
208
209
bool32 wallCollided = false;
210
if (entity->velocity.x < 0)
211
wallCollided = RSDK.ObjectTileCollision(entity, Zone->collisionLayers, CMODE_FLOOR, 0, hitbox.left << 16, hitbox.top << 16, false);
212
else if (entity->velocity.x > 0)
213
wallCollided = RSDK.ObjectTileCollision(entity, Zone->collisionLayers, CMODE_FLOOR, 0, hitbox.right << 16, hitbox.top << 16, false);
214
215
// Apply Lava Physics
216
if (lavaCollided) {
217
if (!prevOnGround && entity->onGround) {
218
RSDK.PlaySfx(LRZConvItem->sfxSizzle, false, 0xFF);
219
entity->velocity.x >>= 1;
220
}
221
222
if (entity->classID != LRZConvItem->classID || entity->type) {
223
entity->velocity.y = 0x4000;
224
}
225
else {
226
if (!entity->velocity.x)
227
entity->velocity.y = 0x4000;
228
else
229
entity->velocity.y = 0;
230
}
231
}
232
233
if (wallCollided)
234
entity->velocity.x = 0;
235
236
entity->position.x += entity->velocity.x;
237
entity->position.y += entity->velocity.y;
238
moveOffset.x = entity->position.x - storeX;
239
moveOffset.y = entity->position.y - storeY;
240
241
if (lavaCollided && !RSDK.CheckOnScreen(entity, &entity->updateRange))
242
destroyEntity(entity);
243
}
244
return moveOffset;
245
}
246
247
void LRZConvItem_State_Rock(void)
248
{
249
RSDK_THIS(LRZConvItem);
250
251
int32 x = self->position.x;
252
int32 y = self->position.y;
253
Vector2 moveOffset = LRZConvItem_HandleLRZConvPhys(self);
254
255
int32 storeX = self->position.x;
256
int32 storeY = self->position.y;
257
self->position.x = x;
258
self->position.y = y;
259
260
foreach_active(Player, player)
261
{
262
switch (Player_CheckCollisionBox(player, self, &LRZConvItem->hitboxRock)) {
263
case C_TOP:
264
player->position.x += moveOffset.x;
265
player->position.y += moveOffset.y;
266
if (moveOffset.y <= 0)
267
player->collisionFlagV |= 1;
268
break;
269
270
case C_LEFT: player->collisionFlagH |= 1; break;
271
case C_RIGHT: player->collisionFlagH |= 2; break;
272
273
case C_BOTTOM:
274
if (moveOffset.y >= 0)
275
player->collisionFlagV |= 2;
276
break;
277
278
default: break;
279
}
280
}
281
282
self->position.x = storeX;
283
self->position.y = storeY;
284
}
285
286
void LRZConvItem_State_SpikeBall(void)
287
{
288
RSDK_THIS(LRZConvItem);
289
290
LRZConvItem_HandleLRZConvPhys(self);
291
292
foreach_active(Player, player)
293
{
294
if (Player_CheckCollisionTouch(player, self, &LRZConvItem->hitboxSpikeball)) {
295
#if MANIA_USE_PLUS
296
if (!Player_CheckMightyUnspin(player, 0x400, true, &player->uncurlTimer))
297
#endif
298
Player_Hurt(player, self);
299
}
300
}
301
}
302
303
#if GAME_INCLUDE_EDITOR
304
void LRZConvItem_EditorDraw(void)
305
{
306
RSDK_THIS(LRZConvItem);
307
308
RSDK.SetSpriteAnimation(LRZConvItem->aniFrames, self->type, &self->animator, true, 0);
309
310
LRZConvItem_Draw();
311
}
312
313
void LRZConvItem_EditorLoad(void)
314
{
315
LRZConvItem->aniFrames = RSDK.LoadSpriteAnimation("LRZ2/LRZConvItem.bin", SCOPE_STAGE);
316
317
RSDK_ACTIVE_VAR(LRZConvItem, type);
318
RSDK_ENUM_VAR("Rock", LRZCONVITEM_ROCK);
319
RSDK_ENUM_VAR("Spike Ball", LRZCONVITEM_SPIKEBALL);
320
}
321
#endif
322
323
void LRZConvItem_Serialize(void) { RSDK_EDITABLE_VAR(LRZConvItem, VAR_UINT8, type); }
324
325