Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/GHZ/Bridge.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: Bridge Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectBridge *Bridge;
11
12
void Bridge_Update(void)
13
{
14
RSDK_THIS(Bridge);
15
16
if (self->stoodEntityCount) {
17
if (self->timer < 0x80)
18
self->timer += 8;
19
}
20
else {
21
if (self->timer) {
22
self->stoodEntity = (Entity *)-1;
23
self->timer -= 8;
24
}
25
else {
26
self->depression = 0;
27
}
28
}
29
30
self->stoodEntityCount = 0;
31
self->bridgeDepth = (self->depression * self->timer) >> 7;
32
33
foreach_active(Player, player)
34
{
35
Hitbox *playerHitbox = Player_GetHitbox(player);
36
if (player->state == Player_State_KnuxLedgePullUp)
37
continue;
38
39
Bridge_HandleCollisions(player, self, playerHitbox, true, true);
40
}
41
42
if (self->burnOffset != 0xFF)
43
Bridge_Burn(self->burnOffset);
44
}
45
46
void Bridge_LateUpdate(void) {}
47
48
void Bridge_StaticUpdate(void) {}
49
50
void Bridge_Draw(void)
51
{
52
RSDK_THIS(Bridge);
53
int32 id = 0;
54
Vector2 drawPos;
55
56
int32 size = self->stoodPos >> 20;
57
int32 ang = 0x80000;
58
drawPos.x = self->startPos + 0x80000;
59
for (int32 i = 0; i < size; ++i) {
60
drawPos.y = (self->bridgeDepth * RSDK.Sin512((ang << 7) / self->stoodPos) >> 9) + self->position.y;
61
RSDK.DrawSprite(&self->animator, &drawPos, false);
62
drawPos.x += 0x100000;
63
ang += 0x100000;
64
}
65
id = size;
66
67
drawPos.y = self->bridgeDepth + self->position.y;
68
RSDK.DrawSprite(&self->animator, &drawPos, false);
69
drawPos.x += 0x100000;
70
++id;
71
72
ang = 0x80000;
73
int32 divisor = self->endPos - self->startPos - self->stoodPos;
74
drawPos.x = self->endPos - 0x80000;
75
for (; id < self->length; ++id) {
76
drawPos.y = (self->bridgeDepth * RSDK.Sin512((ang << 7) / divisor) >> 9) + self->position.y;
77
RSDK.DrawSprite(&self->animator, &drawPos, false);
78
drawPos.x -= 0x100000;
79
ang += 0x100000;
80
}
81
}
82
83
void Bridge_Create(void *data)
84
{
85
RSDK_THIS(Bridge);
86
self->visible = true;
87
++self->length;
88
self->drawGroup = Zone->objectDrawGroup[0];
89
self->active = ACTIVE_BOUNDS;
90
int32 len = self->length << 19;
91
self->startPos = self->position.x - len;
92
self->endPos = len + self->position.x;
93
self->updateRange.x = len;
94
self->updateRange.y = 0x800000;
95
self->stoodEntity = (Entity *)-1;
96
self->burnOffset = 0xFF;
97
RSDK.SetSpriteAnimation(Bridge->aniFrames, 0, &self->animator, true, 0);
98
}
99
100
void Bridge_StageLoad(void)
101
{
102
if (RSDK.CheckSceneFolder("GHZ"))
103
Bridge->aniFrames = RSDK.LoadSpriteAnimation("GHZ/Bridge.bin", SCOPE_STAGE);
104
if (RSDK.CheckSceneFolder("HCZ"))
105
Bridge->aniFrames = RSDK.LoadSpriteAnimation("HCZ/Bridge.bin", SCOPE_STAGE);
106
if (RSDK.CheckSceneFolder("LRZ1"))
107
Bridge->aniFrames = RSDK.LoadSpriteAnimation("LRZ1/Bridge.bin", SCOPE_STAGE);
108
}
109
110
void Bridge_Burn(int32 offset)
111
{
112
RSDK_THIS(Bridge);
113
114
int32 size = self->stoodPos >> 20;
115
int32 spawnX = self->startPos + 0x80000;
116
int32 off = -offset;
117
int32 ang = 0x80000;
118
for (int32 i = 0; i < size; ++i) {
119
int32 sine = RSDK.Sin512((ang << 7) / self->stoodPos);
120
CREATE_ENTITY(BurningLog, INT_TO_VOID(8 * abs(off++) + 16), spawnX, (self->bridgeDepth * sine >> 9) + self->position.y);
121
ang += 0x100000;
122
spawnX += 0x100000;
123
}
124
125
int32 id = size;
126
CREATE_ENTITY(BurningLog, INT_TO_VOID(8 * abs(id++ - offset) + 16), spawnX, self->bridgeDepth + self->position.y);
127
128
spawnX = self->endPos - 0x80000;
129
int32 divisor = self->endPos - self->startPos - self->stoodPos;
130
ang = 0x80000;
131
if (id < self->length) {
132
off = offset - id;
133
for (; id < self->length; ++id, --off) {
134
int32 spawnY = (self->bridgeDepth * RSDK.Sin512((ang << 7) / divisor) >> 9) + self->position.y;
135
CREATE_ENTITY(BurningLog, INT_TO_VOID(8 * abs(self->length - abs(off) - offset) + 16), spawnX, spawnY);
136
ang += 0x100000;
137
spawnX -= 0x100000;
138
}
139
}
140
destroyEntity(self);
141
}
142
143
bool32 Bridge_HandleCollisions(void *e, EntityBridge *self, Hitbox *entityHitbox, bool32 updateVars, bool32 isPlayer)
144
{
145
EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);
146
147
// use EntityPlayer as the type so we can access player variables if needed
148
// if `isPlayer` is false, then only base entity variables will be accessed
149
EntityPlayer *entity = (EntityPlayer *)e;
150
151
bool32 bridgeCollided = false;
152
153
if (entity->position.x > self->startPos && entity->position.x < self->endPos) {
154
if (entity != self->stoodEntity) {
155
if (updateVars && !self->stoodEntityCount)
156
self->stoodPos = entity->position.x - self->startPos;
157
158
if (entity->velocity.y >= 0) {
159
Hitbox hitboxBridge;
160
hitboxBridge.left = -0x400;
161
hitboxBridge.right = 0x400;
162
163
int32 divisor = 0;
164
int32 ang = 0;
165
if (entity->position.x - self->startPos <= self->stoodPos) {
166
divisor = self->stoodPos;
167
ang = (entity->position.x - self->startPos) << 7;
168
}
169
else {
170
divisor = self->endPos - self->startPos - self->stoodPos;
171
ang = (self->endPos - entity->position.x) << 7;
172
}
173
174
int32 hitY = (self->bridgeDepth * RSDK.Sin512(ang / divisor) >> 9) - 0x80000;
175
if (entity->velocity.y >= 0x8000) {
176
hitboxBridge.top = (hitY >> 16);
177
hitboxBridge.bottom = hitboxBridge.top + 8;
178
}
179
else {
180
hitboxBridge.bottom = (hitY >> 16);
181
hitboxBridge.top = hitboxBridge.bottom - 8;
182
}
183
184
bool32 collided = false;
185
if (isPlayer)
186
collided = Player_CheckCollisionTouch(entity, self, &hitboxBridge);
187
else
188
collided = RSDK.CheckObjectCollisionTouchBox(self, &hitboxBridge, entity, entityHitbox);
189
190
if (collided) {
191
entity->position.y = hitY + self->position.y - (entityHitbox->bottom << 16);
192
193
if (updateVars) {
194
++self->stoodEntityCount;
195
if (!entity->onGround) {
196
entity->onGround = true;
197
entity->groundVel = entity->velocity.x;
198
}
199
200
if (isPlayer)
201
entity->flailing = false;
202
203
if (entity == player1) {
204
if (self->stoodEntity != (void *)-1 && self->stoodEntity != (void *)-2) {
205
int32 distance = self->endPos - self->startPos;
206
self->stoodPos = entity->position.x - self->startPos;
207
self->depression = (distance >> 13) * RSDK.Sin512((self->stoodPos >> 8) / (distance >> 16));
208
self->bridgeDepth = (self->depression * self->timer) >> 7;
209
}
210
211
self->stoodEntity = entity;
212
if (entity->velocity.y < 0x10000)
213
self->timer = 0x80;
214
}
215
else {
216
if (self->stoodEntity == (void *)-1) {
217
self->stoodEntity = entity;
218
if (entity->velocity.y < 0x10000)
219
self->timer = 0x80;
220
}
221
222
if (self->stoodEntity == (void *)-2)
223
self->stoodEntity = entity;
224
}
225
226
if (!entity->onGround) {
227
entity->onGround = true;
228
entity->groundVel = entity->velocity.x;
229
}
230
231
entity->velocity.y = 0;
232
233
if (isPlayer) {
234
if (entity->shield == SHIELD_FIRE && self->burnable)
235
Bridge_Burn((entity->position.x - self->startPos) >> 20);
236
}
237
}
238
239
bridgeCollided = true;
240
}
241
}
242
}
243
else if (updateVars) {
244
self->stoodPos = entity->position.x - self->startPos;
245
int32 distance = (self->endPos - self->startPos);
246
self->depression = RSDK.Sin512((self->stoodPos >> 8) / (distance >> 16)) * (distance >> 13);
247
248
if (entity->position.y > self->position.y - 0x300000) {
249
if (entity->velocity.y >= 0) {
250
++self->stoodEntityCount;
251
entity->position.y = self->position.y + self->bridgeDepth - ((entityHitbox->bottom + 8) << 16);
252
253
if (!entity->onGround) {
254
entity->onGround = true;
255
entity->groundVel = entity->velocity.x;
256
}
257
258
entity->velocity.y = 0;
259
if (isPlayer) {
260
entity->flailing = false;
261
if (entity->shield == SHIELD_FIRE && self->burnable)
262
Bridge_Burn((entity->position.x - self->startPos) >> 20);
263
}
264
265
bridgeCollided = true;
266
}
267
else {
268
self->stoodEntity = (void *)-2;
269
}
270
}
271
}
272
}
273
else if (entity == self->stoodEntity) {
274
self->timer = 32;
275
self->stoodEntity = (void *)-2;
276
}
277
278
return bridgeCollided;
279
}
280
281
#if GAME_INCLUDE_EDITOR
282
void Bridge_EditorDraw(void)
283
{
284
RSDK_THIS(Bridge);
285
int32 length = self->length++;
286
287
int32 len = self->length << 19;
288
self->startPos = self->position.x - len;
289
self->endPos = len + self->position.x;
290
self->updateRange.x = len;
291
self->updateRange.y = 0x800000;
292
293
Bridge_Draw();
294
295
self->length = length;
296
}
297
298
void Bridge_EditorLoad(void)
299
{
300
if (RSDK.CheckSceneFolder("GHZ"))
301
Bridge->aniFrames = RSDK.LoadSpriteAnimation("GHZ/Bridge.bin", SCOPE_STAGE);
302
if (RSDK.CheckSceneFolder("HCZ"))
303
Bridge->aniFrames = RSDK.LoadSpriteAnimation("HCZ/Bridge.bin", SCOPE_STAGE);
304
if (RSDK.CheckSceneFolder("LRZ1"))
305
Bridge->aniFrames = RSDK.LoadSpriteAnimation("LRZ1/Bridge.bin", SCOPE_STAGE);
306
}
307
#endif
308
309
void Bridge_Serialize(void)
310
{
311
RSDK_EDITABLE_VAR(Bridge, VAR_UINT8, length);
312
RSDK_EDITABLE_VAR(Bridge, VAR_BOOL, burnable);
313
}
314
315