Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/HCZ/BreakBar.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: BreakBar Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectBreakBar *BreakBar;
11
12
void BreakBar_Update(void)
13
{
14
RSDK_THIS(BreakBar);
15
16
StateMachine_Run(self->state);
17
}
18
19
void BreakBar_LateUpdate(void) { BreakBar_CheckPlayerCollisions(); }
20
21
void BreakBar_StaticUpdate(void) {}
22
23
void BreakBar_Draw(void) { BreakBar_DrawSprites(); }
24
25
void BreakBar_Create(void *data)
26
{
27
RSDK_THIS(BreakBar);
28
29
self->active = ACTIVE_BOUNDS;
30
self->drawGroup = Zone->objectDrawGroup[0];
31
self->startPos = self->position;
32
self->visible = true;
33
self->updateRange.x = 0x800000;
34
self->updateRange.y = 0x800000;
35
36
self->hitbox.left = 24;
37
self->hitbox.top = 24;
38
self->hitbox.right = 32;
39
self->hitbox.bottom = 32;
40
41
if (self->orientation == BREAKBAR_V) {
42
self->hitbox.top = -8 - ((8 * self->length) >> 1);
43
self->hitbox.bottom = ((8 * self->length) >> 1) + 8;
44
}
45
else {
46
self->hitbox.left = -8 - ((8 * self->length) >> 1);
47
self->hitbox.right = ((8 * self->length) >> 1) + 8;
48
}
49
50
self->state = BreakBar_State_Init;
51
}
52
53
void BreakBar_StageLoad(void)
54
{
55
BreakBar->aniFrames = RSDK.LoadSpriteAnimation("HCZ/BreakBar.bin", SCOPE_STAGE);
56
57
BreakBar->sfxBreak = RSDK.GetSfx("Stage/LedgeBreak.wav");
58
}
59
60
void BreakBar_DrawSprites(void)
61
{
62
RSDK_THIS(BreakBar);
63
64
Vector2 drawPos = self->position;
65
66
if (self->orientation != BREAKBAR_V) {
67
drawPos.x += -0x40000 - (((8 * self->length) >> 1) << 16);
68
RSDK.SetSpriteAnimation(BreakBar->aniFrames, 1, &self->animator, true, 0);
69
RSDK.DrawSprite(&self->animator, &drawPos, false);
70
71
drawPos.x += 0x80000;
72
RSDK.SetSpriteAnimation(BreakBar->aniFrames, 1, &self->animator, true, 1);
73
for (int32 i = 0; i < self->length; ++i) {
74
RSDK.DrawSprite(&self->animator, &drawPos, false);
75
drawPos.x += 0x80000;
76
}
77
78
RSDK.SetSpriteAnimation(BreakBar->aniFrames, 1, &self->animator, true, 2);
79
}
80
else {
81
drawPos.y += -0x40000 - (((8 * self->length) >> 1) << 16);
82
RSDK.SetSpriteAnimation(BreakBar->aniFrames, 0, &self->animator, true, 0);
83
RSDK.DrawSprite(&self->animator, &drawPos, false);
84
85
drawPos.y += 0x80000;
86
RSDK.SetSpriteAnimation(BreakBar->aniFrames, 0, &self->animator, true, 1);
87
for (int32 i = 0; i < self->length; ++i) {
88
RSDK.DrawSprite(&self->animator, &drawPos, false);
89
drawPos.y += 0x80000;
90
}
91
92
RSDK.SetSpriteAnimation(BreakBar->aniFrames, 0, &self->animator, true, 2);
93
}
94
95
RSDK.DrawSprite(&self->animator, &drawPos, false);
96
}
97
98
void BreakBar_CheckPlayerCollisions(void)
99
{
100
RSDK_THIS(BreakBar);
101
102
foreach_active(Player, player)
103
{
104
int32 playerID = RSDK.GetEntitySlot(player);
105
if (((1 << playerID) & self->activePlayersGrabbed) && !((1 << playerID) & self->activePlayersReleased)) {
106
if (!Player_CheckValidState(player)) {
107
self->activePlayersGrabbed &= ~(1 << playerID);
108
}
109
else {
110
player->direction = FLIP_NONE;
111
112
if (self->orientation != BREAKBAR_V) {
113
player->position.y = self->startPos.y;
114
115
if (player->velocity.y <= 0) {
116
player->position.y -= 0x140000;
117
player->rotation = 0x180;
118
}
119
else {
120
player->position.y += 0x140000;
121
player->rotation = 0x080;
122
}
123
}
124
else {
125
player->position.x = self->startPos.x;
126
127
if (player->velocity.x <= 0) {
128
player->position.x -= 0x140000;
129
player->rotation = 0x100;
130
}
131
else {
132
player->position.x += 0x140000;
133
player->rotation = 0x000;
134
}
135
}
136
}
137
}
138
}
139
}
140
141
void BreakBar_HandlePlayerInteractions(EntityPlayer *player)
142
{
143
RSDK_THIS(BreakBar);
144
145
if (!self->isBroken) {
146
int32 spawnX = self->position.x;
147
int32 spawnY = self->position.y;
148
149
if (self->orientation != BREAKBAR_V)
150
spawnX += -0x40000 - ((8 * self->length) >> 1 << 16);
151
else
152
spawnY += -0x40000 - ((8 * self->length) >> 1 << 16);
153
154
if (self->length != 0xFFFE) {
155
int32 len = (self->length + 2) << 19;
156
for (int32 i = 0; i < self->length + 2; ++i) {
157
int32 frame = i == self->length + 1 ? 2 : (i != 0);
158
EntityDebris *debris = CREATE_ENTITY(Debris, Debris_State_Move, spawnX, spawnY);
159
160
debris->drawGroup = Zone->objectDrawGroup[0];
161
debris->gravityStrength = player->underwater ? 0x2000 : 0x3800;
162
debris->velocity.x = player->velocity.x >> 3;
163
debris->velocity.y = player->velocity.y >> 3;
164
165
if (self->orientation != BREAKBAR_V) {
166
RSDK.SetSpriteAnimation(BreakBar->aniFrames, 1, &debris->animator, true, frame);
167
debris->velocity.x = abs(debris->position.x - player->position.x) >> 6;
168
169
if (debris->position.x < player->position.x)
170
debris->velocity.x = -(abs(debris->position.x - player->position.x) >> 6);
171
172
if (len > abs(debris->position.x - player->position.x))
173
debris->velocity.y += (2 * (player->velocity.y > 0) - 1) * (MAX(len - abs(debris->position.x - player->position.x), 0) >> 5);
174
175
debris->velocity.y = (3 * ((RSDK.Rand(-12, 12) << 10) + debris->velocity.y)) >> 3;
176
spawnX += 0x80000;
177
}
178
else {
179
RSDK.SetSpriteAnimation(BreakBar->aniFrames, 0, &debris->animator, true, frame);
180
181
debris->velocity.y = abs(debris->position.y - player->position.y) >> 6;
182
183
if (debris->position.y < player->position.y)
184
debris->velocity.y = -debris->velocity.y;
185
186
if (len > abs(debris->position.y - player->position.y))
187
debris->velocity.x += (2 * (player->velocity.x > 0) - 1) * (MAX(len - abs(debris->position.y - player->position.y), 0) >> 5);
188
189
debris->velocity.x = (3 * ((RSDK.Rand(-12, 12) << 10) + debris->velocity.x)) >> 3;
190
spawnY += 0x80000;
191
}
192
}
193
}
194
195
RSDK.PlaySfx(BreakBar->sfxBreak, false, 255);
196
self->isBroken = true;
197
}
198
}
199
200
void BreakBar_State_Init(void)
201
{
202
RSDK_THIS(BreakBar);
203
204
self->activePlayersGrabbed = 0;
205
self->activePlayersReleased = 0;
206
self->releaseTimer = 0;
207
self->state = BreakBar_State_Main;
208
}
209
210
void BreakBar_State_Main(void)
211
{
212
RSDK_THIS(BreakBar);
213
214
foreach_active(Player, player)
215
{
216
int32 playerID = RSDK.GetEntitySlot(player);
217
218
if ((player->sidekick && Player->respawnTimer >= 239) || !Player_CheckValidState(player)) {
219
self->activePlayersReleased &= ~(1 << playerID);
220
self->activePlayersGrabbed &= ~(1 << playerID);
221
self->playerTimers[playerID] = 8;
222
}
223
else {
224
if (self->playerTimers[playerID]) {
225
self->playerTimers[playerID]--;
226
}
227
else if (!((1 << playerID) & self->activePlayersGrabbed) && !((1 << playerID) & self->activePlayersReleased)) {
228
self->direction = FLIP_NONE;
229
230
if (player->velocity.x < 0)
231
self->direction = FLIP_X;
232
233
if (player->velocity.y < 0)
234
self->direction |= FLIP_Y;
235
236
if (Player_CheckCollisionTouch(player, self, &self->hitbox)) {
237
self->activePlayersGrabbed |= 1 << playerID;
238
RSDK.PlaySfx(Player->sfxGrab, false, 255);
239
}
240
}
241
242
if (((1 << playerID) & self->activePlayersGrabbed)) {
243
if (!((1 << playerID) & self->activePlayersReleased)) {
244
if (player->jumpPress || self->releaseTimer >= 240 || self->isBroken) {
245
self->activePlayersReleased |= 1 << playerID;
246
}
247
else {
248
RSDK.SetSpriteAnimation(player->aniFrames, ANI_CLING, &player->animator, false, 0);
249
player->onGround = false;
250
player->nextGroundState = StateMachine_None;
251
player->nextAirState = StateMachine_None;
252
player->state = Player_State_Static;
253
}
254
255
if (!player->sidekick && globals->gameMode != MODE_COMPETITION)
256
++self->releaseTimer;
257
}
258
}
259
260
if (((1 << playerID) & self->activePlayersReleased)) {
261
if (globals->gameMode == MODE_COMPETITION) {
262
self->activePlayersReleased &= ~(1 << playerID);
263
self->activePlayersGrabbed &= ~(1 << playerID);
264
self->playerTimers[playerID] = 8;
265
}
266
else if (!player->sidekick && !self->isBroken) {
267
BreakBar_HandlePlayerInteractions(player);
268
}
269
270
RSDK.SetSpriteAnimation(player->aniFrames, ANI_FAN, &player->animator, false, 0);
271
player->state = Player_State_Static;
272
}
273
}
274
}
275
276
if (self->isBroken)
277
destroyEntity(self);
278
}
279
280
#if GAME_INCLUDE_EDITOR
281
void BreakBar_EditorDraw(void) { BreakBar_DrawSprites(); }
282
283
void BreakBar_EditorLoad(void)
284
{
285
BreakBar->aniFrames = RSDK.LoadSpriteAnimation("HCZ/BreakBar.bin", SCOPE_STAGE);
286
287
RSDK_ACTIVE_VAR(BreakBar, orientation);
288
RSDK_ENUM_VAR("Vertical", BREAKBAR_V);
289
RSDK_ENUM_VAR("Horizontal", BREAKBAR_H);
290
}
291
#endif
292
293
void BreakBar_Serialize(void)
294
{
295
RSDK_EDITABLE_VAR(BreakBar, VAR_UINT8, orientation);
296
RSDK_EDITABLE_VAR(BreakBar, VAR_UINT16, length);
297
}
298
299