Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/MSZ/Cactula.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: Cactula Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectCactula *Cactula;
11
12
void Cactula_Update(void)
13
{
14
RSDK_THIS(Cactula);
15
16
StateMachine_Run(self->state);
17
}
18
19
void Cactula_LateUpdate(void) {}
20
21
void Cactula_StaticUpdate(void) {}
22
23
void Cactula_Draw(void)
24
{
25
RSDK_THIS(Cactula);
26
27
Vector2 drawPos;
28
drawPos.x = self->position.x;
29
drawPos.y = self->position.y + self->offsetY;
30
31
RSDK.DrawSprite(&self->bodyBottomAnimator, &drawPos, false);
32
RSDK.DrawSprite(&self->propellerAnimator, &drawPos, false);
33
RSDK.DrawSprite(&self->bodyTopAnimator, NULL, false);
34
}
35
36
void Cactula_Create(void *data)
37
{
38
RSDK_THIS(Cactula);
39
40
self->visible = true;
41
self->drawGroup = Zone->objectDrawGroup[0] + 1;
42
self->drawFX = FX_FLIP;
43
self->active = ACTIVE_BOUNDS;
44
self->updateRange.x = 0x800000;
45
self->updateRange.y = 0x800000;
46
self->offsetY = 0x80000;
47
48
RSDK.SetSpriteAnimation(Cactula->aniFrames, 0, &self->bodyTopAnimator, true, 0);
49
RSDK.SetSpriteAnimation(Cactula->aniFrames, 0, &self->bodyBottomAnimator, true, 1);
50
RSDK.SetSpriteAnimation(Cactula->aniFrames, 1, &self->propellerAnimator, true, 0);
51
52
self->state = Cactula_State_CheckPlayerInRange;
53
}
54
55
void Cactula_StageLoad(void)
56
{
57
if (RSDK.CheckSceneFolder("MSZ"))
58
Cactula->aniFrames = RSDK.LoadSpriteAnimation("MSZ/Cactula.bin", SCOPE_STAGE);
59
60
Cactula->hitboxBadnik.left = -12;
61
Cactula->hitboxBadnik.top = -12;
62
Cactula->hitboxBadnik.right = 12;
63
Cactula->hitboxBadnik.bottom = 12;
64
65
DEBUGMODE_ADD_OBJ(Cactula);
66
67
Cactula->sfxCactDrop = RSDK.GetSfx("MSZ/CactDrop.wav");
68
Soundboard_LoadSfx("MSZ/CactChopper.wav", true, Cactula_SfxChecK_CactChopper, StateMachine_None);
69
}
70
71
void Cactula_DebugSpawn(void)
72
{
73
RSDK_THIS(DebugMode);
74
75
CREATE_ENTITY(Cactula, NULL, self->position.x, self->position.y);
76
}
77
78
void Cactula_DebugDraw(void)
79
{
80
RSDK.SetSpriteAnimation(Cactula->aniFrames, 0, &DebugMode->animator, true, 0);
81
RSDK.DrawSprite(&DebugMode->animator, NULL, false);
82
}
83
84
void Cactula_CheckPlayerCollisions(void)
85
{
86
RSDK_THIS(Cactula);
87
88
foreach_active(Player, player)
89
{
90
if (Player_CheckBadnikTouch(player, self, &Cactula->hitboxBadnik))
91
Player_CheckBadnikBreak(player, self, true);
92
}
93
}
94
95
bool32 Cactula_SfxChecK_CactChopper(void)
96
{
97
int32 count = 0;
98
99
foreach_active(Cactula, cactula)
100
{
101
if (cactula->state == Cactula_State_Rising || cactula->state == Cactula_State_DropBomb)
102
++count;
103
}
104
105
return count > 0;
106
}
107
108
void Cactula_State_CheckPlayerInRange(void)
109
{
110
RSDK_THIS(Cactula);
111
112
EntityPlayer *player = Player_GetNearestPlayerX();
113
114
if (abs(self->position.x - player->position.x) < 0x800000) {
115
self->velocity.y = -0x20000;
116
self->state = Cactula_State_Rising;
117
}
118
119
Cactula_CheckPlayerCollisions();
120
}
121
122
void Cactula_State_Rising(void)
123
{
124
RSDK_THIS(Cactula);
125
126
RSDK.ProcessAnimation(&self->propellerAnimator);
127
128
self->offsetY += self->velocity.y;
129
self->velocity.y += 0x4000;
130
131
if (self->offsetY >= 0 && self->velocity.y >= 0) {
132
self->offsetY = 0;
133
self->velocity.y = -0xA000;
134
self->state = Cactula_State_DropBomb;
135
}
136
Cactula_CheckPlayerCollisions();
137
}
138
139
void Cactula_State_DropBomb(void)
140
{
141
RSDK_THIS(Cactula);
142
143
RSDK.ProcessAnimation(&self->propellerAnimator);
144
145
self->velocity.y += 0x100;
146
self->position.y += self->velocity.y;
147
148
EntityPlayer *player = Player_GetNearestPlayerX();
149
if (RSDK.CheckOnScreen(self, NULL) || self->position.y <= player->position.y) {
150
if (!self->droppedBomb && abs(self->position.x - player->position.x) < 0x100000) {
151
RSDK.PlaySfx(Cactula->sfxCactDrop, false, 255);
152
EntityProjectile *projectile = CREATE_ENTITY(Projectile, Projectile_State_MoveGravity, self->position.x, self->position.y);
153
projectile->gravityStrength = 0x3800;
154
projectile->drawGroup = Zone->objectDrawGroup[0];
155
projectile->hitbox.left = -6;
156
projectile->hitbox.top = -6;
157
projectile->hitbox.right = 6;
158
projectile->hitbox.bottom = 6;
159
projectile->type = PROJECTILE_BASIC2;
160
projectile->hurtDelay = 16;
161
RSDK.SetSpriteAnimation(Cactula->aniFrames, 2, &projectile->animator, true, 0);
162
self->droppedBomb = true;
163
}
164
165
if (RSDK.GetTile(Zone->fgLayer[1], self->position.x >> 20, self->position.y >> 20) == (uint16)-1)
166
Cactula_CheckPlayerCollisions();
167
}
168
else {
169
destroyEntity(self);
170
}
171
}
172
173
#if GAME_INCLUDE_EDITOR
174
void Cactula_EditorDraw(void) { Cactula_Draw(); }
175
176
void Cactula_EditorLoad(void) { Cactula->aniFrames = RSDK.LoadSpriteAnimation("MSZ/Cactula.bin", SCOPE_STAGE); }
177
#endif
178
179
void Cactula_Serialize(void) {}
180
181