Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/GHZ/Crabmeat.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: Crabmeat Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectCrabmeat *Crabmeat;
11
12
void Crabmeat_Update(void)
13
{
14
RSDK_THIS(Crabmeat);
15
StateMachine_Run(self->state);
16
}
17
18
void Crabmeat_LateUpdate(void) {}
19
20
void Crabmeat_StaticUpdate(void) {}
21
22
void Crabmeat_Draw(void)
23
{
24
RSDK_THIS(Crabmeat);
25
RSDK.DrawSprite(&self->animator, NULL, false);
26
}
27
28
void Crabmeat_Create(void *data)
29
{
30
RSDK_THIS(Crabmeat);
31
32
self->visible = true;
33
self->drawGroup = Zone->objectDrawGroup[0];
34
35
if (data) {
36
self->inkEffect = INK_ADD;
37
self->alpha = 0xC0;
38
self->active = ACTIVE_NORMAL;
39
self->updateRange.x = 0x400000;
40
self->updateRange.y = 0x400000;
41
RSDK.SetSpriteAnimation(Crabmeat->aniFrames, 3, &self->animator, true, 0);
42
self->state = Crabmeat_State_Projectile;
43
}
44
else {
45
self->drawFX |= FX_FLIP;
46
self->startPos.x = self->position.x;
47
self->startPos.y = self->position.y;
48
self->startDir = self->direction;
49
self->active = ACTIVE_BOUNDS;
50
self->updateRange.x = 0x800000;
51
self->updateRange.y = 0x800000;
52
RSDK.SetSpriteAnimation(Crabmeat->aniFrames, 0, &self->animator, true, 0);
53
self->state = Crabmeat_State_Init;
54
}
55
}
56
57
void Crabmeat_StageLoad(void)
58
{
59
if (RSDK.CheckSceneFolder("GHZ"))
60
Crabmeat->aniFrames = RSDK.LoadSpriteAnimation("GHZ/Crabmeat.bin", SCOPE_STAGE);
61
62
Crabmeat->hitboxBadnik.left = -14;
63
Crabmeat->hitboxBadnik.top = -14;
64
Crabmeat->hitboxBadnik.right = 14;
65
Crabmeat->hitboxBadnik.bottom = 14;
66
67
Crabmeat->hitboxProjectile.left = -6;
68
Crabmeat->hitboxProjectile.top = -6;
69
Crabmeat->hitboxProjectile.right = 6;
70
Crabmeat->hitboxProjectile.bottom = 6;
71
72
DEBUGMODE_ADD_OBJ(Crabmeat);
73
}
74
75
void Crabmeat_DebugDraw(void)
76
{
77
RSDK.SetSpriteAnimation(Crabmeat->aniFrames, 0, &DebugMode->animator, true, 0);
78
RSDK.DrawSprite(&DebugMode->animator, NULL, false);
79
}
80
void Crabmeat_DebugSpawn(void)
81
{
82
RSDK_THIS(DebugMode);
83
84
CREATE_ENTITY(Crabmeat, NULL, self->position.x, self->position.y);
85
}
86
87
void Crabmeat_CheckOffScreen(void)
88
{
89
RSDK_THIS(Crabmeat);
90
91
if (self->tileCollisions != TILECOLLISION_NONE && !RSDK.CheckOnScreen(self, NULL)
92
&& !RSDK.CheckPosOnScreen(&self->startPos, &self->updateRange)) {
93
self->position.x = self->startPos.x;
94
self->position.y = self->startPos.y;
95
self->direction = self->startDir;
96
self->timer = 0;
97
Crabmeat_Create(NULL);
98
}
99
}
100
101
void Crabmeat_CheckPlayerCollisions(void)
102
{
103
RSDK_THIS(Crabmeat);
104
105
foreach_active(Player, player)
106
{
107
if (Player_CheckBadnikTouch(player, self, &Crabmeat->hitboxBadnik))
108
Player_CheckBadnikBreak(player, self, true);
109
}
110
}
111
112
void Crabmeat_State_Init(void)
113
{
114
RSDK_THIS(Crabmeat);
115
116
self->active = ACTIVE_NORMAL;
117
self->velocity.x = -0x8000;
118
RSDK.SetSpriteAnimation(Crabmeat->aniFrames, 1, &self->animator, true, 0);
119
self->state = Crabmeat_State_Moving;
120
Crabmeat_State_Moving();
121
}
122
123
void Crabmeat_State_Moving(void)
124
{
125
RSDK_THIS(Crabmeat);
126
127
self->position.x += self->velocity.x;
128
129
if (self->timer >= 128
130
|| (!RSDK.ObjectTileGrip(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0xE0000 * (self->velocity.x > 0 ? 1 : -1), 0xF0000, 8))) {
131
self->timer = 0;
132
if (self->shootState == 0)
133
RSDK.SetSpriteAnimation(Crabmeat->aniFrames, 0, &self->animator, true, 0);
134
else
135
RSDK.SetSpriteAnimation(Crabmeat->aniFrames, 2, &self->animator, true, 0);
136
self->state = Crabmeat_State_Shoot;
137
}
138
else {
139
self->timer++;
140
}
141
142
RSDK.ProcessAnimation(&self->animator);
143
144
Crabmeat_CheckPlayerCollisions();
145
Crabmeat_CheckOffScreen();
146
}
147
148
void Crabmeat_State_Shoot(void)
149
{
150
RSDK_THIS(Crabmeat);
151
152
if (++self->timer >= 60) {
153
switch (self->shootState) {
154
default:
155
case 2:
156
if (self->animator.frameID != self->animator.frameCount - 1)
157
break;
158
159
case 0:
160
self->shootState = 1;
161
RSDK.SetSpriteAnimation(Crabmeat->aniFrames, 1, &self->animator, true, 0);
162
self->direction ^= FLIP_X;
163
self->velocity.x = -self->velocity.x;
164
self->timer = 0;
165
self->state = Crabmeat_State_Moving;
166
break;
167
168
case 1:
169
self->shootState = 2;
170
171
EntityCrabmeat *projectile = CREATE_ENTITY(Crabmeat, INT_TO_VOID(true), self->position.x - 0x100000, self->position.y);
172
projectile->velocity.x = -0x10000;
173
projectile->velocity.y = -0x40000;
174
175
projectile = CREATE_ENTITY(Crabmeat, INT_TO_VOID(true), self->position.x + 0x100000, self->position.y);
176
projectile->velocity.x = 0x10000;
177
projectile->velocity.y = -0x40000;
178
break;
179
}
180
}
181
182
RSDK.ProcessAnimation(&self->animator);
183
Crabmeat_CheckPlayerCollisions();
184
Crabmeat_CheckOffScreen();
185
}
186
187
void Crabmeat_State_Projectile(void)
188
{
189
RSDK_THIS(Crabmeat);
190
191
self->position.x += self->velocity.x;
192
self->position.y += self->velocity.y;
193
self->velocity.y += 0x3800;
194
195
if (!RSDK.CheckOnScreen(self, NULL)) {
196
destroyEntity(self);
197
}
198
else {
199
RSDK.ProcessAnimation(&self->animator);
200
201
foreach_active(Player, player)
202
{
203
if (Player_CheckCollisionTouch(player, self, &Crabmeat->hitboxProjectile))
204
Player_ProjectileHurt(player, self);
205
}
206
}
207
}
208
209
#if GAME_INCLUDE_EDITOR
210
void Crabmeat_EditorDraw(void) { Crabmeat_Draw(); }
211
212
void Crabmeat_EditorLoad(void) { Crabmeat->aniFrames = RSDK.LoadSpriteAnimation("GHZ/Crabmeat.bin", SCOPE_STAGE); }
213
#endif
214
215
void Crabmeat_Serialize(void) {}
216
217