Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/SSZ/Kabasira.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: Kabasira Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectKabasira *Kabasira;
11
12
void Kabasira_Update(void)
13
{
14
RSDK_THIS(Kabasira);
15
16
StateMachine_Run(self->state);
17
}
18
19
void Kabasira_LateUpdate(void) {}
20
21
void Kabasira_StaticUpdate(void) {}
22
23
void Kabasira_Draw(void)
24
{
25
RSDK_THIS(Kabasira);
26
27
if (self->state == Kabasira_State_LaunchedAttack) {
28
self->drawFX = FX_SCALE | FX_FLIP;
29
RSDK.DrawSprite(&self->bodyAnimator, NULL, false);
30
RSDK.DrawSprite(&self->wingsAnimator, NULL, false);
31
32
// Probably shouldn't be in Draw?
33
RSDK.ProcessAnimation(&self->wingsAnimator);
34
}
35
else {
36
int32 speed = (2 * (self->direction == FLIP_NONE) - 1);
37
38
int32 angle = self->angle + 72 * speed;
39
if (angle < 0)
40
angle = ((-1 - angle) & -0x200) + angle + 0x200;
41
angle &= 0x1FF;
42
43
int32 alpha = 0x100 / KABASIRA_BODY_COUNT; // default is 0x40
44
int32 angleVel = 24 * speed;
45
46
for (int32 i = 0; i < KABASIRA_BODY_COUNT - 1; ++i) {
47
Kabasira_DrawSegment(angle, alpha);
48
49
angle -= angleVel;
50
if (angle < 0)
51
angle = ((-1 - angle) & -0x200) + angle + 0x200;
52
angle &= 0x1FF;
53
54
alpha += 0x100 / KABASIRA_BODY_COUNT; // default is 0x40
55
}
56
57
Kabasira_DrawSegment(angle, alpha);
58
self->angle = angle;
59
}
60
}
61
62
void Kabasira_Create(void *data)
63
{
64
RSDK_THIS(Kabasira);
65
66
self->inkEffect = INK_ALPHA;
67
self->drawFX = FX_FLIP | FX_ROTATE | FX_SCALE;
68
self->scale.x = 0x200;
69
self->scale.y = 0x200;
70
71
if (!SceneInfo->inEditor) {
72
self->visible = true;
73
self->drawGroup = Zone->objectDrawGroup[0];
74
self->startPos = self->position;
75
self->startDir = self->direction;
76
self->active = ACTIVE_BOUNDS;
77
self->updateRange.x = 0x800000;
78
self->updateRange.y = 0x800000;
79
80
RSDK.SetSpriteAnimation(Kabasira->aniFrames, 0, &self->bodyAnimator, true, 0);
81
RSDK.SetSpriteAnimation(Kabasira->aniFrames, 1, &self->wingsAnimator, true, 0);
82
self->wingsAnimator.frameCount = 3;
83
84
if (data) {
85
self->alpha = 0x80;
86
self->state = Kabasira_State_LaunchedAttack;
87
}
88
else {
89
self->wingsAnimator.frameCount = 3;
90
self->wingsAnimator.loopIndex = 0;
91
92
self->state = Kabasira_State_Init;
93
}
94
}
95
}
96
97
void Kabasira_StageLoad(void)
98
{
99
if (RSDK.CheckSceneFolder("SSZ1"))
100
Kabasira->aniFrames = RSDK.LoadSpriteAnimation("SSZ1/Kabasira.bin", SCOPE_STAGE);
101
else if (RSDK.CheckSceneFolder("SSZ2"))
102
Kabasira->aniFrames = RSDK.LoadSpriteAnimation("SSZ2/Kabasira.bin", SCOPE_STAGE);
103
104
Kabasira->hitboxBadnik.left = -6;
105
Kabasira->hitboxBadnik.top = -6;
106
Kabasira->hitboxBadnik.right = 6;
107
Kabasira->hitboxBadnik.bottom = 6;
108
109
Kabasira->onScreenRange.x = 0x60000;
110
Kabasira->onScreenRange.y = 0x60000;
111
112
Kabasira->sfxPon = RSDK.GetSfx("Stage/Pon.wav");
113
Kabasira->sfxExplosion2 = RSDK.GetSfx("Stage/Explosion2.wav");
114
115
DEBUGMODE_ADD_OBJ(Kabasira);
116
}
117
118
void Kabasira_DebugSpawn(void)
119
{
120
RSDK_THIS(DebugMode);
121
122
CREATE_ENTITY(Kabasira, NULL, self->position.x, self->position.y);
123
}
124
125
void Kabasira_DebugDraw(void)
126
{
127
RSDK.SetSpriteAnimation(Kabasira->aniFrames, 0, &DebugMode->animator, true, 0);
128
RSDK.DrawSprite(&DebugMode->animator, NULL, false);
129
}
130
131
bool32 Kabasira_HandleAnimations(uint8 angle)
132
{
133
RSDK_THIS(Kabasira);
134
135
int32 rotation = 2 * angle;
136
int32 prevFrame = self->wingsAnimator.frameID % 3;
137
int32 frame = 0;
138
139
switch (rotation >> 7) {
140
case 0:
141
case 2: frame = (rotation >> 5) & 3; break;
142
143
case 1:
144
case 3: frame = 3 - ((rotation >> 5) & 3); break;
145
}
146
147
int32 frameCount = 3 * frame;
148
self->wingsAnimator.loopIndex = frameCount;
149
self->wingsAnimator.frameID = prevFrame + frameCount;
150
self->wingsAnimator.frameCount = frameCount + 3;
151
152
return rotation > 0x80 && rotation < 0x180;
153
}
154
155
void Kabasira_DrawSegment(int32 angle, int32 alpha)
156
{
157
RSDK_THIS(Kabasira);
158
Vector2 drawPos;
159
160
int32 rotation = 2 * angle;
161
drawPos.x = RSDK.Sin512(rotation) * 0xA00 + self->startPos.x;
162
drawPos.y = (RSDK.Cos512(angle) << 13) + self->startPos.y;
163
164
int32 frame = 11 - rotation % 512 / 42 % 12;
165
RSDK.SetSpriteAnimation(Kabasira->aniFrames, 0, &self->bodyAnimator, true, frame);
166
167
if (!self->bodyAnimator.frameID || self->bodyAnimator.frameID > 6) {
168
self->scale.x = 0x200;
169
self->scale.y = 0x200;
170
}
171
else {
172
self->scale.x = ((abs(2 * self->bodyAnimator.frameID - 7) << 5) / 5) + 480;
173
self->scale.y = self->scale.x;
174
}
175
176
uint8 dir = Kabasira_HandleAnimations(angle) ? FLIP_X : FLIP_NONE;
177
int32 storedDir = self->direction;
178
int32 storedAlpha = self->alpha;
179
180
if (self->angle < 0x100) {
181
self->direction = FLIP_NONE;
182
self->alpha = alpha;
183
RSDK.DrawSprite(&self->bodyAnimator, &drawPos, false);
184
185
self->direction = dir;
186
alpha >>= 1;
187
self->alpha = alpha;
188
RSDK.DrawSprite(&self->wingsAnimator, &drawPos, false);
189
}
190
else {
191
self->direction = dir;
192
self->alpha = alpha >> 1;
193
RSDK.DrawSprite(&self->wingsAnimator, &drawPos, false);
194
195
self->direction = FLIP_NONE;
196
self->alpha = alpha;
197
RSDK.DrawSprite(&self->bodyAnimator, &drawPos, false);
198
}
199
200
self->alpha = storedAlpha;
201
self->direction = storedDir;
202
}
203
204
void Kabasira_CheckPlayerCollisions(void)
205
{
206
RSDK_THIS(Kabasira);
207
208
foreach_active(Player, player)
209
{
210
if (Player_CheckBadnikTouch(player, self, &Kabasira->hitboxBadnik))
211
Player_CheckBadnikBreak(player, self, true);
212
}
213
}
214
215
void Kabasira_CheckOffScreen(void)
216
{
217
RSDK_THIS(Kabasira);
218
219
if (!RSDK.CheckOnScreen(self, NULL) && !RSDK.CheckPosOnScreen(&self->startPos, &self->updateRange)) {
220
self->position = self->startPos;
221
self->direction = self->startDir;
222
Kabasira_Create(NULL);
223
}
224
}
225
226
void Kabasira_State_Init(void)
227
{
228
RSDK_THIS(Kabasira);
229
230
self->active = ACTIVE_NORMAL;
231
self->angle = 0;
232
self->timer = 0;
233
234
self->state = Kabasira_State_Moving;
235
Kabasira_State_Moving();
236
}
237
238
void Kabasira_State_Moving(void)
239
{
240
RSDK_THIS(Kabasira);
241
242
RSDK.ProcessAnimation(&self->wingsAnimator);
243
244
self->angle += 2;
245
if (self->timer > 0) {
246
self->timer--;
247
}
248
else {
249
self->timer = 240;
250
if (RSDK.CheckOnScreen(self, &Kabasira->onScreenRange)) {
251
EntityPlayer *player = Player_GetNearestPlayer();
252
253
if (player) {
254
RSDK.PlaySfx(Kabasira->sfxPon, false, 255);
255
256
EntityKabasira *attack = CREATE_ENTITY(Kabasira, INT_TO_VOID(true), self->position.x, self->position.y);
257
int32 angle = RSDK.ATan2(player->position.x - self->position.x, player->position.y - self->position.y);
258
attack->velocity.x = RSDK.Cos256(angle) << 9;
259
attack->velocity.y = RSDK.Sin256(angle) << 9;
260
attack->direction = player->position.x < self->position.x;
261
}
262
}
263
}
264
265
self->position.x = self->startPos.x + (0xA00 * RSDK.Sin512(2 * self->angle));
266
self->position.y = self->startPos.y + (RSDK.Cos512(self->angle) << 13);
267
268
Kabasira_CheckPlayerCollisions();
269
Kabasira_CheckOffScreen();
270
}
271
272
void Kabasira_State_LaunchedAttack(void)
273
{
274
RSDK_THIS(Kabasira);
275
276
self->position.x += self->velocity.x;
277
self->position.y += self->velocity.y;
278
279
foreach_active(Player, player)
280
{
281
if (Player_CheckBadnikTouch(player, self, &Kabasira->hitboxBadnik)) {
282
if (Player_CheckAttacking(player, self)) {
283
CREATE_ENTITY(Explosion, INT_TO_VOID(EXPLOSION_ITEMBOX), self->position.x, self->position.y)->drawGroup = Zone->objectDrawGroup[1];
284
RSDK.PlaySfx(Kabasira->sfxExplosion2, false, 255);
285
286
destroyEntity(self);
287
foreach_break;
288
}
289
else {
290
Player_Hurt(player, self);
291
}
292
}
293
}
294
}
295
296
#if GAME_INCLUDE_EDITOR
297
void Kabasira_EditorDraw(void)
298
{
299
RSDK_THIS(Kabasira);
300
301
RSDK.SetSpriteAnimation(Kabasira->aniFrames, 0, &self->bodyAnimator, false, 0);
302
RSDK.SetSpriteAnimation(Kabasira->aniFrames, 1, &self->wingsAnimator, false, 0);
303
self->startPos = self->position;
304
self->startDir = self->direction;
305
306
Kabasira_Draw();
307
}
308
309
void Kabasira_EditorLoad(void)
310
{
311
if (RSDK.CheckSceneFolder("SSZ1"))
312
Kabasira->aniFrames = RSDK.LoadSpriteAnimation("SSZ1/Kabasira.bin", SCOPE_STAGE);
313
else if (RSDK.CheckSceneFolder("SSZ2"))
314
Kabasira->aniFrames = RSDK.LoadSpriteAnimation("SSZ2/Kabasira.bin", SCOPE_STAGE);
315
316
RSDK_ACTIVE_VAR(Kabasira, direction);
317
RSDK_ENUM_VAR("Left", FLIP_NONE);
318
RSDK_ENUM_VAR("Right", FLIP_X);
319
}
320
#endif
321
322
void Kabasira_Serialize(void) { RSDK_EDITABLE_VAR(Kabasira, VAR_UINT8, direction); }
323
324