Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/HCZ/Gondola.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: Gondola Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectGondola *Gondola;
11
12
void Gondola_Update(void)
13
{
14
RSDK_THIS(Gondola);
15
16
self->collisionOffset.x = -self->drawPos.x;
17
self->collisionOffset.y = -self->drawPos.y;
18
self->centerPos.x += self->velocity.x;
19
self->centerPos.y += self->velocity.y;
20
21
if (self->activePlayers) {
22
if (self->stoodAngle < self->maxStoodAngle)
23
self->stoodAngle += 4;
24
}
25
else {
26
if (self->stoodAngle > 0)
27
self->stoodAngle -= 4;
28
}
29
30
Gondola_HandleWaterFloating();
31
Gondola_HandleTilting();
32
Gondola_HandleMoveVelocity();
33
34
if (self->onGround && self->velocity.y > 0)
35
self->velocity.y = 0;
36
37
self->drawPos.x = self->centerPos.x + (RSDK.Sin256(self->stoodAngle) << 10);
38
self->drawPos.y = self->centerPos.y + (RSDK.Sin512(self->floatAngle * 2) * 0x180);
39
40
if (!self->onGround)
41
++self->floatAngle;
42
43
self->position.x = self->drawPos.x & 0xFFFF0000;
44
self->position.y = self->drawPos.y & 0xFFFF0000;
45
Gondola_HandleTileCollisions();
46
47
self->drawGroup = self->onGround ? Zone->objectDrawGroup[0] : Zone->playerDrawGroup[0];
48
self->collisionOffset.x += self->position.x;
49
self->collisionOffset.y += self->position.y;
50
Gondola_HandlePlayerInteractions();
51
}
52
53
void Gondola_LateUpdate(void) {}
54
55
void Gondola_StaticUpdate(void) {}
56
57
void Gondola_Draw(void)
58
{
59
RSDK_THIS(Gondola);
60
61
RSDK.DrawSprite(&self->animator, NULL, false);
62
}
63
64
void Gondola_Create(void *data)
65
{
66
RSDK_THIS(Gondola);
67
68
self->active = ACTIVE_NORMAL;
69
self->drawGroup = Zone->playerDrawGroup[1];
70
71
self->startPos = self->position;
72
self->drawPos = self->position;
73
self->centerPos = self->position;
74
75
self->visible = true;
76
self->drawFX = FX_ROTATE | FX_FLIP;
77
self->updateRange.x = 0x800000;
78
self->updateRange.y = 0x800000;
79
self->drawGroup = Zone->playerDrawGroup[0];
80
81
self->hitbox.left = -76;
82
self->hitbox.top = -12;
83
self->hitbox.right = 76;
84
self->hitbox.bottom = 4;
85
86
RSDK.SetSpriteAnimation(Gondola->aniFrames, 0, &self->animator, true, 0);
87
}
88
89
void Gondola_StageLoad(void) { Gondola->aniFrames = RSDK.LoadSpriteAnimation("HCZ/Gondola.bin", SCOPE_STAGE); }
90
91
int32 Gondola_GetWaterLevel(void)
92
{
93
RSDK_THIS(Gondola);
94
95
if (self->position.y < Water->waterLevel) {
96
foreach_active(Water, water)
97
{
98
if (water->type == WATER_POOL && RSDK.CheckObjectCollisionTouchBox(water, &water->hitbox, self, &Water->hitboxPoint)) {
99
return water->position.y + (water->hitbox.top << 16);
100
}
101
}
102
}
103
104
return Water->waterLevel;
105
}
106
107
void Gondola_HandleWaterFloating(void)
108
{
109
RSDK_THIS(Gondola);
110
111
int32 waterLevel = Gondola_GetWaterLevel();
112
113
self->waterDistance = self->centerPos.y - waterLevel;
114
self->waterInRange = abs(self->centerPos.y - waterLevel) < 0x40000;
115
116
if (abs(self->centerPos.y - waterLevel) >= 0x40000) {
117
if (self->centerPos.y - waterLevel < -0x80000) {
118
self->velocity.y += 0x3800;
119
}
120
else {
121
if (self->centerPos.y <= waterLevel)
122
self->velocity.y = 0;
123
else
124
self->velocity.y = -Water->waterMoveSpeed;
125
}
126
}
127
else {
128
if (Water->targetWaterLevel > Water->waterLevel) {
129
self->velocity.y = Water->waterMoveSpeed;
130
}
131
else {
132
if (self->centerPos.y <= waterLevel)
133
self->velocity.y = 0;
134
else
135
self->velocity.y = -Water->waterMoveSpeed;
136
}
137
}
138
139
if (self->minY) {
140
if (self->centerPos.y <= self->minY << 16) {
141
self->centerPos.y = self->minY << 16;
142
143
if (self->velocity.y < 0)
144
self->velocity.y = 0;
145
}
146
}
147
148
if (self->maxY) {
149
if (self->centerPos.y >= self->maxY << 16) {
150
self->centerPos.y = self->maxY << 16;
151
152
if (self->velocity.y > 0)
153
self->velocity.y = 0;
154
}
155
}
156
}
157
158
void Gondola_HandleTilting(void)
159
{
160
RSDK_THIS(Gondola);
161
162
int32 targetRotation = 0;
163
164
if (!self->onGround) {
165
foreach_active(Player, player)
166
{
167
if (((1 << RSDK.GetEntitySlot(player)) & self->activePlayers))
168
targetRotation += (player->position.x - self->centerPos.x) >> 21;
169
}
170
}
171
172
if (self->rotation < targetRotation)
173
self->rotation++;
174
else if (self->rotation > targetRotation)
175
self->rotation--;
176
}
177
178
void Gondola_HandleMoveVelocity(void)
179
{
180
RSDK_THIS(Gondola);
181
182
if (!self->onGround) {
183
foreach_active(Player, player)
184
{
185
int32 playerID = RSDK.GetEntitySlot(player);
186
187
if (!player->sidekick) {
188
if (((1 << playerID) & self->activePlayers)) {
189
self->velocity.x = (player->position.x - self->centerPos.x) >> 5;
190
}
191
else {
192
if (self->velocity.x > 0) {
193
self->velocity.x -= 0x200;
194
195
if (self->velocity.x < 0)
196
self->velocity.x = 0;
197
}
198
else if (self->velocity.x < 0) {
199
self->velocity.x += 0x200;
200
201
if (self->velocity.x > 0)
202
self->velocity.x = 0;
203
}
204
}
205
}
206
}
207
}
208
}
209
210
void Gondola_HandleTileCollisions(void)
211
{
212
RSDK_THIS(Gondola);
213
214
if (RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, self->hitbox.bottom << 16, true)) {
215
self->maxStoodAngle = 0;
216
217
if (self->velocity.y > 0)
218
self->velocity.y = 0;
219
220
self->onGround = true;
221
}
222
else {
223
self->maxStoodAngle = 64;
224
self->onGround = false;
225
}
226
227
if (RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_ROOF, 0, 0, self->hitbox.top << 16, true) && self->velocity.y < 0) {
228
self->velocity.y = 0;
229
}
230
231
// RWall = Right side of the wall, so this would collide with the *left* side of the boat
232
if (RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_RWALL, 0, (self->hitbox.left - 8) << 16, 0, true)) {
233
if (self->velocity.x < 0)
234
self->velocity.x = 0;
235
236
self->stoppedL = true;
237
}
238
else {
239
self->stoppedL = false;
240
}
241
242
// LWall = Left side of the wall, so this would collide with the *right* side of the boat
243
if (RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_LWALL, 0, (self->hitbox.right + 8) << 16, 0, true)) {
244
if (self->velocity.x > 0)
245
self->velocity.x = 0;
246
247
self->stoppedR = true;
248
}
249
else {
250
self->stoppedR = false;
251
}
252
253
self->drawPos.x = self->position.x;
254
self->drawPos.y = self->position.y;
255
}
256
257
void Gondola_HandlePlayerInteractions(void)
258
{
259
RSDK_THIS(Gondola);
260
261
if (self->onGround) {
262
self->activePlayers = 0;
263
}
264
else {
265
foreach_active(Player, player)
266
{
267
int32 playerID = RSDK.GetEntitySlot(player);
268
269
if (((1 << playerID) & self->activePlayers)) {
270
player->position.x += self->collisionOffset.x;
271
player->position.y += self->collisionOffset.y + 0x10000;
272
273
if (!player->sidekick && !Gondola->hasAchievement) {
274
if (!Gondola->taggedBoatIDs[self->boatID]) {
275
Gondola->taggedBoatIDs[self->boatID] = true;
276
277
if (Gondola->taggedBoatIDs[0] && Gondola->taggedBoatIDs[1] && Gondola->taggedBoatIDs[2]) {
278
API_UnlockAchievement(&achievementList[ACH_HCZ]);
279
Gondola->hasAchievement = true;
280
}
281
}
282
}
283
}
284
285
if (Player_CheckCollisionPlatform(player, self, &self->hitbox))
286
self->activePlayers |= 1 << playerID;
287
else
288
self->activePlayers &= ~(1 << playerID);
289
}
290
}
291
}
292
293
#if GAME_INCLUDE_EDITOR
294
void Gondola_EditorDraw(void) { Gondola_Draw(); }
295
296
void Gondola_EditorLoad(void)
297
{
298
Gondola->aniFrames = RSDK.LoadSpriteAnimation("HCZ/Gondola.bin", SCOPE_STAGE);
299
300
RSDK_ACTIVE_VAR(Gondola, direction);
301
RSDK_ENUM_VAR("No Flip", FLIP_NONE);
302
RSDK_ENUM_VAR("Flip X", FLIP_X);
303
304
RSDK_ACTIVE_VAR(Gondola, boatID);
305
RSDK_ENUM_VAR("Boat 1", 0);
306
RSDK_ENUM_VAR("Boat 2", 1);
307
RSDK_ENUM_VAR("Boat 3", 2);
308
}
309
#endif
310
311
void Gondola_Serialize(void)
312
{
313
RSDK_EDITABLE_VAR(Gondola, VAR_UINT8, direction);
314
RSDK_EDITABLE_VAR(Gondola, VAR_ENUM, minY);
315
RSDK_EDITABLE_VAR(Gondola, VAR_ENUM, maxY);
316
RSDK_EDITABLE_VAR(Gondola, VAR_UINT8, boatID);
317
}
318
319