Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/GHZ/Chopper.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: Chopper Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectChopper *Chopper;
11
12
void Chopper_Update(void)
13
{
14
RSDK_THIS(Chopper);
15
StateMachine_Run(self->state);
16
}
17
18
void Chopper_LateUpdate(void) {}
19
20
void Chopper_StaticUpdate(void) {}
21
22
void Chopper_Draw(void)
23
{
24
RSDK_THIS(Chopper);
25
RSDK.DrawSprite(&self->animator, NULL, false);
26
}
27
28
void Chopper_Create(void *data)
29
{
30
RSDK_THIS(Chopper);
31
self->visible = true;
32
self->drawGroup = Zone->objectDrawGroup[0];
33
self->startPos = self->position;
34
self->startDir = self->direction;
35
self->active = ACTIVE_BOUNDS;
36
self->updateRange.x = 0x800000;
37
self->updateRange.y = 0x1200000;
38
self->drawFX = FX_FLIP;
39
self->state = Chopper_State_Init;
40
}
41
42
void Chopper_StageLoad(void)
43
{
44
if (RSDK.CheckSceneFolder("GHZ"))
45
Chopper->aniFrames = RSDK.LoadSpriteAnimation("GHZ/Chopper.bin", SCOPE_STAGE);
46
47
Chopper->hitboxJump.left = -10;
48
Chopper->hitboxJump.top = -20;
49
Chopper->hitboxJump.right = 6;
50
Chopper->hitboxJump.bottom = 20;
51
52
Chopper->hitboxSwim.left = -20;
53
Chopper->hitboxSwim.top = -6;
54
Chopper->hitboxSwim.right = 20;
55
Chopper->hitboxSwim.bottom = 10;
56
57
Chopper->hitboxRange.left = -160;
58
Chopper->hitboxRange.top = -32;
59
Chopper->hitboxRange.right = 16;
60
Chopper->hitboxRange.bottom = 32;
61
62
Chopper->hitboxWater.left = -20;
63
Chopper->hitboxWater.top = -24;
64
Chopper->hitboxWater.right = 20;
65
Chopper->hitboxWater.bottom = -16;
66
67
DEBUGMODE_ADD_OBJ(Chopper);
68
}
69
void Chopper_DebugDraw(void)
70
{
71
RSDK.SetSpriteAnimation(Chopper->aniFrames, 0, &DebugMode->animator, true, 0);
72
RSDK.DrawSprite(&DebugMode->animator, NULL, false);
73
}
74
75
void Chopper_DebugSpawn(void)
76
{
77
RSDK_THIS(DebugMode);
78
79
CREATE_ENTITY(Chopper, NULL, self->position.x, self->position.y);
80
}
81
82
void Chopper_CheckOffScreen(void)
83
{
84
RSDK_THIS(Chopper);
85
86
if (!RSDK.CheckOnScreen(self, NULL) && !RSDK.CheckPosOnScreen(&self->startPos, &self->updateRange)) {
87
self->position.x = self->startPos.x;
88
self->position.y = self->startPos.y;
89
self->direction = self->startDir;
90
Chopper_Create(NULL);
91
}
92
}
93
94
void Chopper_CheckPlayerCollisions_Jump(void)
95
{
96
RSDK_THIS(Chopper);
97
98
foreach_active(Player, player)
99
{
100
if (Player_CheckBadnikTouch(player, self, &Chopper->hitboxJump))
101
Player_CheckBadnikBreak(player, self, true);
102
}
103
}
104
105
void Chopper_CheckPlayerCollisions_Swim(void)
106
{
107
RSDK_THIS(Chopper);
108
109
foreach_active(Player, player)
110
{
111
if (Player_CheckBadnikTouch(player, self, &Chopper->hitboxSwim))
112
Player_CheckBadnikBreak(player, self, true);
113
}
114
}
115
116
void Chopper_State_Init(void)
117
{
118
RSDK_THIS(Chopper);
119
120
self->active = ACTIVE_NORMAL;
121
self->velocity.x = -0x10000;
122
123
if (self->type == CHOPPER_JUMP) {
124
RSDK.SetSpriteAnimation(Chopper->aniFrames, 0, &self->animator, true, 0);
125
self->state = Chopper_State_Jump;
126
Chopper_State_Jump();
127
}
128
else {
129
RSDK.SetSpriteAnimation(Chopper->aniFrames, 1, &self->animator, true, 0);
130
self->state = Chopper_State_Swim;
131
self->timer = 512;
132
133
if (!self->direction)
134
self->velocity.x = -0x4000;
135
else
136
self->velocity.x = 0x4000;
137
Chopper_State_Swim();
138
}
139
}
140
141
void Chopper_State_Jump(void)
142
{
143
RSDK_THIS(Chopper);
144
145
self->position.y += self->velocity.y;
146
self->velocity.y += 0x1800;
147
148
if (self->velocity.y < -0x38000) {
149
self->animator.speed = 1;
150
}
151
else {
152
if (self->velocity.y > 0x38000) {
153
self->animator.frameID = 0;
154
self->animator.speed = 0;
155
}
156
else {
157
self->animator.speed = 2;
158
}
159
}
160
161
if (self->position.y > self->startPos.y) {
162
self->position.y = self->startPos.y;
163
self->velocity.y = -0x70000;
164
}
165
166
RSDK.ProcessAnimation(&self->animator);
167
168
Chopper_CheckPlayerCollisions_Jump();
169
Chopper_CheckOffScreen();
170
}
171
172
void Chopper_State_Swim(void)
173
{
174
RSDK_THIS(Chopper);
175
176
self->position.x += self->velocity.x;
177
178
bool32 hitWall = false;
179
if (self->direction) {
180
hitWall = RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_LWALL, 0, 0x100000, 0, true);
181
hitWall |= RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_LWALL, 0, 0x100000, -0xF0000, true);
182
hitWall |= RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_LWALL, 0, 0x100000, 0xF0000, true);
183
}
184
else {
185
hitWall = RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_RWALL, 0, -0x100000, 0, true);
186
hitWall |= RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_RWALL, 0, -0x100000, -0xF0000, true);
187
hitWall |= RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_RWALL, 0, -0x100000, 0xF0000, true);
188
}
189
190
if (--self->timer <= 0 || hitWall) {
191
self->direction ^= FLIP_X;
192
self->velocity.x = -self->velocity.x;
193
self->timer = 512;
194
}
195
196
if (self->charge) {
197
foreach_active(Player, player)
198
{
199
if (Player_CheckCollisionTouch(player, self, &Chopper->hitboxRange)) {
200
self->state = Chopper_State_ChargeDelay;
201
RSDK.SetSpriteAnimation(Chopper->aniFrames, 2, &self->animator, false, 0);
202
self->timer = 16;
203
if (!self->direction)
204
self->velocity.x = -0x20000;
205
else
206
self->velocity.x = 0x20000;
207
208
if (abs(player->position.y - self->position.y) > 0x100000) {
209
if (player->position.y < self->position.y)
210
self->velocity.y = -0x8000;
211
else
212
self->velocity.y = 0x8000;
213
}
214
}
215
}
216
}
217
218
RSDK.ProcessAnimation(&self->animator);
219
220
Chopper_CheckPlayerCollisions_Swim();
221
Chopper_CheckOffScreen();
222
}
223
224
void Chopper_State_ChargeDelay(void)
225
{
226
RSDK_THIS(Chopper);
227
228
if (!self->timer)
229
self->state = Chopper_State_Charge;
230
else
231
--self->timer;
232
233
RSDK.ProcessAnimation(&self->animator);
234
Chopper_CheckPlayerCollisions_Swim();
235
Chopper_CheckOffScreen();
236
}
237
238
void Chopper_State_Charge(void)
239
{
240
RSDK_THIS(Chopper);
241
self->position.x += self->velocity.x;
242
self->position.y += self->velocity.y;
243
244
bool32 hitWall = false;
245
if (self->direction) {
246
hitWall = RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_LWALL, 0, 0x100000, 0, true);
247
hitWall |= RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_LWALL, 0, 0x100000, -0xF0000, true);
248
hitWall |= RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_LWALL, 0, 0x100000, 0xF0000, true);
249
}
250
else {
251
hitWall = RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_RWALL, 0, -0x100000, 0, true);
252
hitWall |= RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_RWALL, 0, -0x100000, -0xF0000, true);
253
hitWall |= RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_RWALL, 0, -0x100000, 0xF0000, true);
254
}
255
256
if (hitWall) {
257
RSDK.SetSpriteAnimation(Chopper->aniFrames, 1, &self->animator, false, 0);
258
self->timer = 512;
259
self->velocity.y = 0;
260
if (self->direction == FLIP_X)
261
self->velocity.x = -0x4000;
262
else
263
self->velocity.x = 0x4000;
264
self->direction ^= FLIP_X;
265
self->state = Chopper_State_Swim;
266
267
hitWall = false;
268
}
269
else if (self->velocity.y >= 0) {
270
if (self->velocity.y > 0)
271
hitWall = RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0x100000, true);
272
}
273
else {
274
hitWall = RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_ROOF, 0, 0, -0x100000, true);
275
foreach_active(Water, water)
276
{
277
if (water->type == WATER_POOL)
278
hitWall |= !RSDK.CheckObjectCollisionTouchBox(water, &water->hitbox, self, &Chopper->hitboxWater);
279
}
280
}
281
282
if (hitWall) {
283
RSDK.SetSpriteAnimation(Chopper->aniFrames, 1, &self->animator, false, 0);
284
self->timer = 512;
285
self->velocity.y = 0;
286
if (self->direction == FLIP_NONE)
287
self->velocity.x = -0x4000;
288
else
289
self->velocity.x = 0x4000;
290
self->state = Chopper_State_Swim;
291
}
292
293
RSDK.ProcessAnimation(&self->animator);
294
Chopper_CheckPlayerCollisions_Swim();
295
Chopper_CheckOffScreen();
296
}
297
298
#if GAME_INCLUDE_EDITOR
299
void Chopper_EditorDraw(void)
300
{
301
RSDK_THIS(Chopper);
302
if (self->type == CHOPPER_JUMP)
303
RSDK.SetSpriteAnimation(Chopper->aniFrames, 0, &self->animator, true, 0);
304
else
305
RSDK.SetSpriteAnimation(Chopper->aniFrames, 1, &self->animator, true, 0);
306
307
Chopper_Draw();
308
}
309
310
void Chopper_EditorLoad(void)
311
{
312
Chopper->aniFrames = RSDK.LoadSpriteAnimation("GHZ/Chopper.bin", SCOPE_STAGE);
313
314
RSDK_ACTIVE_VAR(Chopper, type);
315
RSDK_ENUM_VAR("Jump", CHOPPER_JUMP);
316
RSDK_ENUM_VAR("Swim", CHOPPER_SWIM);
317
318
// Only used with "Swim" type, "Jump" type ignores it
319
RSDK_ACTIVE_VAR(Chopper, direction);
320
RSDK_ENUM_VAR("Left", FLIP_NONE);
321
RSDK_ENUM_VAR("Right", FLIP_X);
322
}
323
#endif
324
325
void Chopper_Serialize(void)
326
{
327
RSDK_EDITABLE_VAR(Chopper, VAR_UINT8, type);
328
RSDK_EDITABLE_VAR(Chopper, VAR_UINT8, direction);
329
RSDK_EDITABLE_VAR(Chopper, VAR_BOOL, charge);
330
}
331
332