Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/ERZ/PhantomMissile.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: PhantomMissile Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectPhantomMissile *PhantomMissile;
11
12
void PhantomMissile_Update(void) {}
13
14
void PhantomMissile_LateUpdate(void)
15
{
16
RSDK_THIS(PhantomMissile);
17
18
StateMachine_Run(self->state);
19
}
20
21
void PhantomMissile_StaticUpdate(void) {}
22
23
void PhantomMissile_Draw(void)
24
{
25
RSDK_THIS(PhantomMissile);
26
27
RSDK.DrawSprite(&self->missileAnimator, NULL, false);
28
RSDK.DrawSprite(&self->targetOutsideAnimator, &self->targetPos, false);
29
30
if (Zone->timer & 0x10)
31
RSDK.DrawSprite(&self->targetNumbersAnimator, &self->targetPos, false);
32
else
33
RSDK.DrawSprite(&self->targetInsideAnimator, &self->targetPos, false);
34
}
35
36
void PhantomMissile_Create(void *data)
37
{
38
RSDK_THIS(PhantomMissile);
39
40
if (!SceneInfo->inEditor) {
41
self->visible = true;
42
self->drawGroup = Zone->objectDrawGroup[0];
43
self->drawFX = FX_ROTATE;
44
self->updateRange.x = 0x800000;
45
self->updateRange.y = 0x800000;
46
self->state = PhantomMissile_State_Attached;
47
48
RSDK.SetSpriteAnimation(PhantomMissile->aniFrames, 0, &self->missileAnimator, true, 0);
49
}
50
}
51
52
void PhantomMissile_StageLoad(void)
53
{
54
PhantomMissile->aniFrames = RSDK.LoadSpriteAnimation("Phantom/EggMissile.bin", SCOPE_STAGE);
55
56
PhantomMissile->hitbox.left = -16;
57
PhantomMissile->hitbox.top = -12;
58
PhantomMissile->hitbox.right = 16;
59
PhantomMissile->hitbox.bottom = 12;
60
}
61
62
void PhantomMissile_GetTargetPos(void)
63
{
64
RSDK_THIS(PhantomMissile);
65
66
int32 distance = 0x7FFFFFFF;
67
68
for (int32 p = SLOT_PLAYER1; p < Player->playerCount; ++p) {
69
EntityPlayer *player = RSDK_GET_ENTITY(p, Player);
70
71
if (player->sidekick == true && player->stateInput != Player_Input_P2_Player) {
72
int32 storeX = self->position.x;
73
int32 storeY = self->position.y;
74
self->position.x = self->targetPos.x;
75
self->position.y = self->targetPos.y;
76
77
while (!RSDK.ObjectTileGrip(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0x100000, 16)) {
78
self->position.y += 0x100000;
79
}
80
81
int32 y = self->position.y;
82
self->position.x = storeX;
83
self->position.y = storeY;
84
self->targetPos.y = y;
85
foreach_break;
86
}
87
88
int32 rx = (self->position.x - player->position.x) >> 16;
89
int32 ry = (self->position.y - player->position.y) >> 16;
90
int32 dist = rx * rx + ry * ry;
91
if (dist < distance) {
92
distance = dist;
93
self->targetPos.x = player->position.x;
94
self->targetPos.y = player->position.y;
95
}
96
}
97
}
98
99
void PhantomMissile_HandleExhaust(void)
100
{
101
RSDK_THIS(PhantomMissile);
102
103
if (!(Zone->timer & 3)) {
104
int32 x = self->position.x - (RSDK.Sin512(self->rotation) << 11);
105
int32 y = self->position.y + (RSDK.Cos512(self->rotation) << 11);
106
EntityDust *dust = CREATE_ENTITY(Dust, NULL, x, y);
107
108
dust->state = Dust_State_DustPuff;
109
dust->drawGroup = Zone->objectDrawGroup[1];
110
dust->inkEffect = INK_BLEND;
111
}
112
}
113
114
void PhantomMissile_State_Attached(void)
115
{
116
RSDK_THIS(PhantomMissile);
117
118
if (self->parent) {
119
self->position.x = self->parent->position.x;
120
self->position.y = self->parent->position.y;
121
self->oscillateAngle = (self->oscillateAngle + 6) & 0xFF;
122
int32 off = 8 * RSDK.Sin256(self->oscillateAngle) + 0x2000;
123
124
self->position.x += off * RSDK.Sin256(self->angle);
125
self->position.y -= off * RSDK.Cos256(self->angle);
126
self->rotation = 2 * self->angle;
127
128
if (self->timer > 0) {
129
if (!--self->timer) {
130
self->velocity.x = 0x300 * RSDK.Sin256(self->angle) + self->parent->velocity.x;
131
self->velocity.y = -0x300 * RSDK.Cos256(self->angle) + self->parent->velocity.y;
132
self->timer = 8;
133
self->state = PhantomMissile_State_PrepareLaunch;
134
}
135
}
136
}
137
}
138
139
void PhantomMissile_State_PrepareLaunch(void)
140
{
141
RSDK_THIS(PhantomMissile);
142
143
self->velocity.y += 0x3800;
144
self->position.x += self->velocity.x;
145
self->position.y += self->velocity.y;
146
147
if (!--self->timer) {
148
self->targetRadius = 0x400;
149
self->state = PhantomMissile_State_Launched;
150
RSDK.PlaySfx(PhantomEgg->sfxRocketJet, false, 255);
151
}
152
}
153
154
void PhantomMissile_State_Launched(void)
155
{
156
RSDK_THIS(PhantomMissile);
157
158
RSDK.ProcessAnimation(&self->missileAnimator);
159
160
if (self->targetRadius < 0x600)
161
self->targetRadius += 4;
162
163
self->position.x += self->targetRadius * RSDK.Sin256(self->angle);
164
self->position.y -= self->targetRadius * RSDK.Cos256(self->angle);
165
166
if (++self->timer == 24) {
167
self->timer = 32;
168
self->targetRadius >>= 1;
169
PhantomMissile_GetTargetPos();
170
171
RSDK.SetSpriteAnimation(PhantomMissile->aniFrames, 1, &self->targetOutsideAnimator, true, 0);
172
RSDK.SetSpriteAnimation(PhantomMissile->aniFrames, 2, &self->targetInsideAnimator, true, 0);
173
RSDK.SetSpriteAnimation(PhantomMissile->aniFrames, 3, &self->targetNumbersAnimator, true, self->id);
174
175
self->drawGroup = Zone->objectDrawGroup[1];
176
self->state = PhantomMissile_State_Attacking;
177
}
178
179
PhantomMissile_HandleExhaust();
180
}
181
182
void PhantomMissile_State_Attacking(void)
183
{
184
RSDK_THIS(PhantomMissile);
185
186
RSDK.ProcessAnimation(&self->missileAnimator);
187
RSDK.ProcessAnimation(&self->targetOutsideAnimator);
188
RSDK.ProcessAnimation(&self->targetInsideAnimator);
189
RSDK.ProcessAnimation(&self->targetNumbersAnimator);
190
191
if (self->targetRadius < 0x800)
192
self->targetRadius += 4;
193
194
if (self->timer > 4)
195
self->timer--;
196
197
int32 shift = self->timer >> 2;
198
int32 rx = (self->targetPos.x - self->position.x) >> 16;
199
int32 ry = (self->targetPos.y - self->position.y) >> 16;
200
int32 angle = RSDK.ATan2(-ry, rx);
201
int32 rot = 2 * angle - self->rotation;
202
203
if (abs(rot) >= abs(rot - 0x200)) {
204
if (abs(rot - 0x200) < abs(rot + 0x200))
205
self->rotation += ((rot - 0x200) >> shift);
206
else
207
self->rotation += ((rot + 0x200) >> shift);
208
}
209
else {
210
if (abs(rot) < abs(rot + 0x200))
211
self->rotation += (rot >> shift);
212
else
213
self->rotation += ((rot + 0x200) >> shift);
214
}
215
216
self->rotation &= 0x1FF;
217
218
self->position.x += self->targetRadius * RSDK.Sin512(self->rotation);
219
self->position.y -= self->targetRadius * RSDK.Cos512(self->rotation);
220
221
if (rx * rx + ry * ry < 64) {
222
CREATE_ENTITY(Explosion, INT_TO_VOID(EXPLOSION_ITEMBOX), self->targetPos.x, self->targetPos.y - 0x80000)->drawGroup =
223
Zone->objectDrawGroup[1];
224
225
RSDK.SetSpriteAnimation(PhantomMissile->aniFrames, 0, &self->missileAnimator, true, 0);
226
RSDK.SetSpriteAnimation(-1, 1, &self->targetOutsideAnimator, true, 0);
227
RSDK.SetSpriteAnimation(-1, 0, &self->targetInsideAnimator, true, 0);
228
RSDK.SetSpriteAnimation(-1, 0, &self->targetNumbersAnimator, true, 0);
229
230
self->timer = 0;
231
self->reattachRadius = 0;
232
self->drawGroup = Zone->objectDrawGroup[0];
233
self->visible = false;
234
self->state = PhantomMissile_State_Explode;
235
236
Camera_ShakeScreen(0, 0, 3);
237
RSDK.PlaySfx(PhantomEgg->sfxMissile, false, 255);
238
}
239
240
PhantomMissile_HandleExhaust();
241
}
242
243
void PhantomMissile_State_Explode(void)
244
{
245
RSDK_THIS(PhantomMissile);
246
247
foreach_active(Player, player)
248
{
249
if (Player_CheckCollisionTouch(player, self, &PhantomMissile->hitbox)) {
250
Player_ElementHurt(player, self, SHIELD_FIRE);
251
}
252
}
253
254
if (++self->timer >= 16 && self->parent) {
255
self->position.x = self->parent->position.x;
256
self->position.y = self->parent->position.y;
257
self->timer = 0;
258
self->visible = true;
259
self->state = PhantomMissile_State_Reattach;
260
}
261
}
262
263
void PhantomMissile_State_Reattach(void)
264
{
265
RSDK_THIS(PhantomMissile);
266
267
if (self->parent) {
268
self->position.x = self->parent->position.x;
269
self->position.y = self->parent->position.y;
270
271
if (self->reattachRadius >= 0x2000) {
272
self->oscillateAngle = 0;
273
self->state = PhantomMissile_State_Attached;
274
}
275
else {
276
self->reattachRadius += 0x100;
277
}
278
279
self->position.x += self->reattachRadius * RSDK.Sin256(self->angle);
280
self->position.y -= self->reattachRadius * RSDK.Cos256(self->angle);
281
self->rotation = self->angle << 1;
282
}
283
}
284
285
void PhantomMissile_State_Destroyed(void)
286
{
287
RSDK_THIS(PhantomMissile);
288
289
self->velocity.y += 0x3800;
290
self->position.x += self->velocity.x;
291
self->position.y += self->velocity.y;
292
293
self->rotation = (self->rotation + self->groundVel) & 0x1FF;
294
295
if (!RSDK.CheckOnScreen(self, NULL))
296
destroyEntity(self);
297
}
298
299
#if GAME_INCLUDE_EDITOR
300
void PhantomMissile_EditorDraw(void)
301
{
302
RSDK_THIS(PhantomMissile);
303
304
RSDK.SetSpriteAnimation(PhantomMissile->aniFrames, 0, &self->missileAnimator, false, 0);
305
306
RSDK.DrawSprite(&self->missileAnimator, NULL, false);
307
}
308
309
void PhantomMissile_EditorLoad(void) { PhantomMissile->aniFrames = RSDK.LoadSpriteAnimation("Phantom/EggMissile.bin", SCOPE_STAGE); }
310
#endif
311
312
void PhantomMissile_Serialize(void) {}
313
314