Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/MMZ/PohBee.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: PohBee Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectPohBee *PohBee;
11
12
void PohBee_Update(void)
13
{
14
RSDK_THIS(PohBee);
15
16
RSDK.ProcessAnimation(&self->bodyAnimator);
17
RSDK.ProcessAnimation(&self->wingsAnimator);
18
19
StateMachine_Run(self->state);
20
21
PohBee_SetupHitboxes();
22
PohBee_CheckPlayerCollisions();
23
24
if (self->drawGroup != 1 && self->state != PohBee_State_Init)
25
PohBee_CheckOffScreen();
26
}
27
28
void PohBee_LateUpdate(void) {}
29
30
void PohBee_StaticUpdate(void) {}
31
32
void PohBee_Draw(void) { PohBee_DrawSprites(); }
33
34
void PohBee_Create(void *data)
35
{
36
RSDK_THIS(PohBee);
37
38
self->visible = true;
39
40
if (self->planeFilter > 0 && ((uint8)(self->planeFilter - 1) & 2))
41
self->drawGroup = Zone->objectDrawGroup[1];
42
else
43
self->drawGroup = Zone->objectDrawGroup[0];
44
45
self->startPos = self->position;
46
self->startDir = self->direction;
47
self->drawFX = FX_FLIP;
48
self->active = ACTIVE_BOUNDS;
49
self->updateRange.x = 0x800000;
50
self->updateRange.y = 0x800000;
51
self->state = PohBee_State_Init;
52
}
53
54
void PohBee_StageLoad(void)
55
{
56
if (RSDK.CheckSceneFolder("MMZ"))
57
PohBee->aniFrames = RSDK.LoadSpriteAnimation("MMZ/PohBee.bin", SCOPE_STAGE);
58
59
PohBee->hitbox.left = -16;
60
PohBee->hitbox.top = -16;
61
PohBee->hitbox.right = 16;
62
PohBee->hitbox.bottom = 16;
63
64
DEBUGMODE_ADD_OBJ(PohBee);
65
}
66
67
void PohBee_DebugSpawn(void)
68
{
69
RSDK_THIS(PohBee);
70
71
EntityPohBee *pohBee = CREATE_ENTITY(PohBee, NULL, self->position.x, self->position.y);
72
pohBee->direction = self->direction;
73
pohBee->startDir = self->direction;
74
}
75
76
void PohBee_DebugDraw(void)
77
{
78
RSDK.SetSpriteAnimation(PohBee->aniFrames, 2, &DebugMode->animator, true, 0);
79
RSDK.DrawSprite(&DebugMode->animator, NULL, false);
80
81
RSDK.SetSpriteAnimation(PohBee->aniFrames, 0, &DebugMode->animator, true, 0);
82
RSDK.DrawSprite(&DebugMode->animator, NULL, false);
83
}
84
85
void PohBee_CheckOffScreen(void)
86
{
87
RSDK_THIS(PohBee);
88
89
if (!RSDK.CheckOnScreen(self, NULL) && !RSDK.CheckPosOnScreen(&self->startPos, &self->updateRange)) {
90
self->direction = self->startDir;
91
self->position = self->startPos;
92
PohBee_Create(NULL);
93
}
94
}
95
96
void PohBee_CheckPlayerCollisions(void)
97
{
98
RSDK_THIS(PohBee);
99
100
foreach_active(Player, player)
101
{
102
if (self->planeFilter <= 0 || player->collisionPlane == ((uint8)(self->planeFilter - 1) & 1)) {
103
if (Player_CheckBadnikTouch(player, self, &PohBee->hitbox)) {
104
if (self->drawGroup == 1) {
105
if (Player_CheckBadnikBreak(player, self, false)) {
106
CREATE_ENTITY(Explosion, INT_TO_VOID(EXPLOSION_ENEMY), self->position.x, self->position.y)->drawGroup = 1;
107
destroyEntity(self);
108
}
109
}
110
else {
111
Player_CheckBadnikBreak(player, self, true);
112
}
113
}
114
115
for (int32 i = 0; i < self->spikeCount + 1; ++i) {
116
if (Player_CheckCollisionTouch(player, self, &self->hitboxes[i])) {
117
#if MANIA_USE_PLUS
118
int32 storeX = self->position.x;
119
int32 storeY = self->position.y;
120
self->position = PohBee_GetSpikePos(i, (self->drawGroup != 1) + 6);
121
if (!Player_CheckMightyUnspin(player, 0x300, 2, &player->uncurlTimer)) {
122
#endif
123
Player_Hurt(player, self);
124
#if MANIA_USE_PLUS
125
}
126
self->position.x = storeX;
127
self->position.y = storeY;
128
#endif
129
}
130
}
131
}
132
}
133
}
134
135
void PohBee_DrawSprites(void)
136
{
137
RSDK_THIS(PohBee);
138
139
self->drawFX = FX_FLIP;
140
141
int32 offsetY = 16;
142
int32 shift = 7;
143
if (self->drawGroup == 1) {
144
offsetY = 15;
145
shift = 6;
146
self->drawFX |= FX_SCALE;
147
}
148
149
if (self->bodyAnimator.animationID != 1)
150
RSDK.DrawSprite(&self->wingsAnimator, NULL, false);
151
152
RSDK.DrawSprite(&self->bodyAnimator, NULL, false);
153
154
Vector2 chainDrawPos;
155
chainDrawPos.x = self->position.x;
156
chainDrawPos.y = self->position.y + (16 << offsetY);
157
self->drawFX |= FX_ROTATE;
158
159
int32 id = 4;
160
for (int32 i = 0; i < 10; ++i) {
161
Vector2 drawPos = chainDrawPos;
162
drawPos.x += (id * RSDK.Cos512(self->chainAngle[0])) << shift;
163
drawPos.y += (id * RSDK.Sin512(self->chainAngle[0])) << shift;
164
RSDK.DrawSprite(&self->chainAnimator, &drawPos, false);
165
id += 8;
166
}
167
168
Vector2 drawPos = PohBee_GetSpikePos(0, shift);
169
RSDK.DrawSprite(&self->spikeAnimator, &drawPos, false);
170
171
if (self->spikeCount == 1) {
172
id = 4;
173
for (int32 i = 0; i < 4; ++i) {
174
drawPos = chainDrawPos;
175
drawPos.x += (id * RSDK.Cos512(self->chainAngle[1])) << shift;
176
drawPos.y += (id * RSDK.Sin512(self->chainAngle[1])) << shift;
177
RSDK.DrawSprite(&self->chainAnimator, &drawPos, false);
178
id += 8;
179
}
180
181
drawPos = PohBee_GetSpikePos(1, shift);
182
RSDK.DrawSprite(&self->spikeAnimator, &drawPos, false);
183
}
184
}
185
186
Vector2 PohBee_GetSpikePos(uint8 spikeID, uint8 shift)
187
{
188
RSDK_THIS(PohBee);
189
190
Vector2 spikePos = self->position;
191
spikePos.y = self->position.y + (self->drawGroup == 1 ? 0x100000 : 0x80000);
192
193
switch (spikeID) {
194
default: break;
195
196
case 0:
197
spikePos.x += (84 * RSDK.Cos512(self->chainAngle[0])) << shift;
198
spikePos.y += (84 * RSDK.Sin512(self->chainAngle[0])) << shift;
199
break;
200
201
case 1:
202
spikePos.x += (36 * RSDK.Cos512(self->chainAngle[1])) << shift;
203
spikePos.y += (36 * RSDK.Sin512(self->chainAngle[1])) << shift;
204
break;
205
}
206
207
return spikePos;
208
}
209
210
void PohBee_SetupHitboxes(void)
211
{
212
RSDK_THIS(PohBee);
213
214
for (int32 i = 0; i < 2; ++i) {
215
Vector2 pos = PohBee_GetSpikePos(i, 7);
216
int32 x = (pos.x - self->position.x) >> 16;
217
int32 y = (pos.y - self->position.y) >> 16;
218
219
Hitbox hitbox;
220
hitbox.left = x - 12;
221
hitbox.top = y - 12;
222
hitbox.right = x + 12;
223
hitbox.bottom = y + 12;
224
if (self->direction == FLIP_X) {
225
hitbox.left = 12 - x;
226
hitbox.right = -hitbox.right;
227
}
228
229
self->hitboxes[i] = hitbox;
230
}
231
}
232
233
void PohBee_State_Init(void)
234
{
235
RSDK_THIS(PohBee);
236
237
if (self->drawGroup != 1)
238
self->active = ACTIVE_NORMAL;
239
240
self->position = self->startPos;
241
self->direction = self->startDir;
242
self->chainAngle[0] = 0x80;
243
self->chainAngle[1] = 0xAC;
244
245
RSDK.SetSpriteAnimation(PohBee->aniFrames, 0, &self->bodyAnimator, true, 0);
246
RSDK.SetSpriteAnimation(PohBee->aniFrames, 2, &self->wingsAnimator, true, 0);
247
RSDK.SetSpriteAnimation(PohBee->aniFrames, 3, &self->chainAnimator, true, 0);
248
RSDK.SetSpriteAnimation(PohBee->aniFrames, 4, &self->spikeAnimator, true, 0);
249
250
self->state = PohBee_State_Move;
251
252
PohBee_State_Move();
253
}
254
255
void PohBee_State_Move(void)
256
{
257
RSDK_THIS(PohBee);
258
259
int32 distX = abs(self->position.x - self->startPos.x);
260
261
int32 move = (2 * (self->direction != FLIP_NONE) - 1) << 15;
262
if (self->bodyAnimator.animationID == 1) {
263
switch (self->bodyAnimator.frameID) {
264
default:
265
case 0: break;
266
267
case 1: move >>= 1; break;
268
case 2: move = 0; break;
269
case 3: move = (-0x8000 * (2 * (self->direction != FLIP_NONE) - 1)) >> 1; break;
270
case 4: move = -0x8000 * (2 * (self->direction != FLIP_NONE) - 1); break;
271
}
272
}
273
274
self->position.x += move;
275
276
if (distX < self->amplitude.x) {
277
self->isTurning = false;
278
}
279
else if (!self->bodyAnimator.animationID && !self->isTurning) {
280
RSDK.SetSpriteAnimation(PohBee->aniFrames, 1, &self->bodyAnimator, true, 0);
281
self->isTurning = true;
282
}
283
if (self->bodyAnimator.animationID == 1 && self->bodyAnimator.frameID == self->bodyAnimator.frameCount - 1) {
284
RSDK.SetSpriteAnimation(PohBee->aniFrames, 0, &self->bodyAnimator, true, 0);
285
self->direction = self->direction == FLIP_NONE;
286
}
287
288
self->angle = (self->angle + 8) & 0x1FF;
289
self->position.y = self->startPos.y + (RSDK.Sin512(self->angle) << 7) * (self->amplitude.y >> 16);
290
291
self->chainPos[0] = (self->chainPos[0] + 9) & 0x7FF;
292
self->chainAngle[0] = (0x70 * ((RSDK.Sin512(self->chainPos[0] >> 2) >> 2) + 0x88)) >> 7;
293
294
self->chainPos[1] = (self->chainPos[1] + 10) & 0x7FF;
295
self->chainAngle[1] = (0x70 * ((RSDK.Sin512(self->chainPos[1] >> 2) >> 2) + 0x90)) >> 7;
296
}
297
298
#if GAME_INCLUDE_EDITOR
299
void PohBee_EditorDraw(void)
300
{
301
RSDK_THIS(PohBee);
302
303
self->chainAngle[0] = 0x80;
304
self->chainAngle[1] = 0xAC;
305
RSDK.SetSpriteAnimation(PohBee->aniFrames, 0, &self->bodyAnimator, true, 0);
306
RSDK.SetSpriteAnimation(PohBee->aniFrames, 2, &self->wingsAnimator, true, 0);
307
RSDK.SetSpriteAnimation(PohBee->aniFrames, 3, &self->chainAnimator, true, 0);
308
RSDK.SetSpriteAnimation(PohBee->aniFrames, 4, &self->spikeAnimator, true, 0);
309
310
PohBee_DrawSprites();
311
}
312
313
void PohBee_EditorLoad(void)
314
{
315
PohBee->aniFrames = RSDK.LoadSpriteAnimation("MMZ/PohBee.bin", SCOPE_STAGE);
316
317
RSDK_ACTIVE_VAR(PohBee, direction);
318
RSDK_ENUM_VAR("Left", FLIP_NONE);
319
RSDK_ENUM_VAR("Right", FLIP_X);
320
321
RSDK_ACTIVE_VAR(PohBee, spikeCount);
322
RSDK_ENUM_VAR("1 Spike", 0);
323
RSDK_ENUM_VAR("2 Spikes", 1);
324
325
RSDK_ACTIVE_VAR(PohBee, planeFilter);
326
RSDK_ENUM_VAR("None", PLANEFILTER_NONE);
327
RSDK_ENUM_VAR("AL", PLANEFILTER_AL);
328
RSDK_ENUM_VAR("BL", PLANEFILTER_BL);
329
RSDK_ENUM_VAR("AH", PLANEFILTER_AH);
330
RSDK_ENUM_VAR("BH", PLANEFILTER_BH);
331
}
332
#endif
333
334
void PohBee_Serialize(void)
335
{
336
RSDK_EDITABLE_VAR(PohBee, VAR_UINT8, direction);
337
RSDK_EDITABLE_VAR(PohBee, VAR_UINT8, spikeCount);
338
RSDK_EDITABLE_VAR(PohBee, VAR_VECTOR2, amplitude);
339
RSDK_EDITABLE_VAR(PohBee, VAR_ENUM, planeFilter);
340
}
341
342