Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/PGZ/Acetone.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: Acetone Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectAcetone *Acetone;
11
12
// This object goes completely unused in regular gameplay
13
// afterall, so does the entire PGZ1 ink gimmick
14
// and even then, this is basically just a tweaked copy of FrostThrower anyways
15
16
void Acetone_Update(void)
17
{
18
RSDK_THIS(Acetone);
19
StateMachine_Run(self->state);
20
}
21
22
void Acetone_LateUpdate(void) {}
23
24
void Acetone_StaticUpdate(void) {}
25
26
void Acetone_Draw(void)
27
{
28
RSDK_THIS(Acetone);
29
30
RSDK.DrawSprite(&self->dispenseAnimator, NULL, false);
31
32
if (self->isActive)
33
Acetone_DrawGustFX();
34
}
35
36
void Acetone_Create(void *data)
37
{
38
RSDK_THIS(Acetone);
39
40
self->active = ACTIVE_BOUNDS;
41
self->visible = true;
42
self->drawFX = FX_FLIP;
43
self->drawGroup = Zone->playerDrawGroup[0] + 1;
44
self->updateRange.x = 0x100000;
45
self->updateRange.y = 0x100000;
46
47
self->hitbox.left = -14;
48
self->hitbox.right = 15;
49
self->maxGustCount[0] = 2;
50
self->maxGustCount[1] = 2;
51
self->maxGustCount[2] = 3;
52
self->maxGustCount[3] = 3;
53
54
Acetone_HandleGustCount();
55
Acetone_HandleGustPos();
56
57
RSDK.SetSpriteAnimation(Acetone->aniFrames, 0, &self->dispenseAnimator, true, 0);
58
RSDK.SetSpriteAnimation(Acetone->aniFrames, 1, &self->gustAnimator, true, 0);
59
60
self->state = Acetone_State_AwaitInterval;
61
}
62
63
void Acetone_StageLoad(void)
64
{
65
if (RSDK.CheckSceneFolder("PSZ1"))
66
Acetone->aniFrames = RSDK.LoadSpriteAnimation("PSZ1/Acetone.bin", SCOPE_STAGE);
67
68
Acetone->sfxFrostThrower = RSDK.GetSfx("PSZ/FrostThrower.wav");
69
Acetone->sfxFreeze = RSDK.GetSfx("PSZ/Freeze.wav");
70
}
71
72
void Acetone_DrawGustFX(void)
73
{
74
RSDK_THIS(Acetone);
75
76
int32 pos = 0;
77
for (int32 i = 0; i < 4; ++i) {
78
int32 count = MIN(self->gustCount[i], 3);
79
80
RSDK.SetSpriteAnimation(Acetone->aniFrames, 1, &self->gustAnimator, true, i);
81
for (int32 p = 0; p < count; ++p) {
82
Vector2 drawPos;
83
drawPos.x = self->position.x + self->gustPos[pos + p].x;
84
drawPos.y = self->position.y + self->gustPos[pos + p].y;
85
RSDK.DrawSprite(&self->gustAnimator, &drawPos, false);
86
}
87
88
pos += 3;
89
}
90
}
91
92
void Acetone_CheckPlayerCollisions(void)
93
{
94
RSDK_THIS(Acetone);
95
96
foreach_active(Player, player)
97
{
98
if (Player_CheckCollisionTouch(player, self, &self->hitbox)) {
99
switch (player->characterID) {
100
// This actually wont work on sonic specifically, it uses the "old" sonic palette
101
// This palette starts at index 2, instead of index 64 like usual
102
// To fix this up to work as "intended", simply replace the "PLAYER_PALETTE_INDEX_SONIC_OLD"s with "PLAYER_PALETTE_INDEX_SONIC"
103
case ID_SONIC: RSDK.CopyPalette(6, PLAYER_PALETTE_INDEX_SONIC_OLD, 0, PLAYER_PALETTE_INDEX_SONIC_OLD, 6); break;
104
105
case ID_TAILS: RSDK.CopyPalette(6, PLAYER_PALETTE_INDEX_TAILS, 0, PLAYER_PALETTE_INDEX_TAILS, PLAYER_PRIMARY_COLOR_COUNT); break;
106
107
case ID_KNUCKLES:
108
RSDK.CopyPalette(6, PLAYER_PALETTE_INDEX_KNUX, 0, PLAYER_PALETTE_INDEX_KNUX, PLAYER_PRIMARY_COLOR_COUNT);
109
break;
110
111
// This is an unused object that was scrapped before plus was created, so there's no mighty/ray code
112
// I've created a mock-up of what mighty/ray code could've looked like, had it been implemented:
113
// case ID_MIGHTY: RSDK.CopyPalette(6, PLAYER_PALETTE_INDEX_MIGHTY, 0, PLAYER_PALETTE_INDEX_MIGHTY, PLAYER_PRIMARY_COLOR_COUNT); break;
114
// case ID_RAY: RSDK.CopyPalette(6, PLAYER_PALETTE_INDEX_RAY, 0, PLAYER_PALETTE_INDEX_RAY, PLAYER_PRIMARY_COLOR_COUNT); break;
115
}
116
117
Ink->playerColors[RSDK.GetEntitySlot(player)] = 0;
118
}
119
}
120
}
121
122
void Acetone_HandleGustCount(void)
123
{
124
RSDK_THIS(Acetone);
125
126
for (int32 i = 0; i < 4; ++i) {
127
self->gustCount[i] = self->maxGustCount[i];
128
129
if (self->maxGustCount[i] > 1) {
130
if (RSDK.Rand(0, 10) <= 6)
131
self->gustCount[i] = RSDK.Rand(1, self->maxGustCount[i]);
132
}
133
}
134
}
135
136
void Acetone_HandleGustPos(void)
137
{
138
RSDK_THIS(Acetone);
139
int32 pos = 0;
140
141
int32 yMin[] = { 2, 20, 45, 55 };
142
int32 yMax[] = { 22, 45, 62, 78 };
143
int32 xMin[] = { -3, -5, -7, -9 };
144
int32 xMax[] = { 3, 5, 7, 9 };
145
146
for (int32 i = 0; i < 4; ++i) {
147
for (int32 p = 0; p < self->gustCount[i]; ++p) {
148
self->gustPos[pos + p].x = RSDK.Rand(xMin[i], xMax[i]) << 16;
149
self->gustPos[pos + p].y = RSDK.Rand(yMin[i], yMax[i]) << 16;
150
}
151
152
pos += 3;
153
}
154
}
155
156
void Acetone_State_AwaitInterval(void)
157
{
158
RSDK_THIS(Acetone);
159
160
if (!((Zone->timer + self->intervalOffset) % self->interval)) {
161
self->active = ACTIVE_NORMAL;
162
self->timer = 0;
163
self->isActive = true;
164
self->state = Acetone_State_Dispensing;
165
RSDK.PlaySfx(Acetone->sfxFrostThrower, false, 0xFF);
166
}
167
}
168
169
void Acetone_State_Dispensing(void)
170
{
171
RSDK_THIS(Acetone);
172
173
self->hitbox.top = 0;
174
if (self->timer >= 20)
175
self->hitbox.bottom = 80;
176
else
177
self->hitbox.bottom = 4 * self->timer;
178
179
Acetone_CheckPlayerCollisions();
180
181
if (self->timer > 3)
182
self->maxGustCount[0] = 2;
183
else
184
self->maxGustCount[0] = 1;
185
186
if (self->timer > 8)
187
self->maxGustCount[1] = 2;
188
else if (self->timer > 5)
189
self->maxGustCount[1] = 1;
190
else
191
self->maxGustCount[1] = 0;
192
193
if (self->timer > 16)
194
self->maxGustCount[2] = 3;
195
else if (self->timer > 14)
196
self->maxGustCount[2] = 2;
197
else if (self->timer > 12)
198
self->maxGustCount[2] = 1;
199
else
200
self->maxGustCount[2] = 0;
201
202
if (self->timer > 19)
203
self->maxGustCount[3] = 3;
204
else if (self->timer > 17)
205
self->maxGustCount[3] = 2;
206
else if (self->timer > 15)
207
self->maxGustCount[3] = 1;
208
else
209
self->maxGustCount[3] = 0;
210
211
Acetone_HandleGustCount();
212
Acetone_HandleGustPos();
213
214
if (++self->timer >= self->duration) {
215
self->state = Acetone_State_StopDispensing;
216
self->timer = 0;
217
}
218
}
219
220
void Acetone_State_StopDispensing(void)
221
{
222
RSDK_THIS(Acetone);
223
224
self->hitbox.top = 4 * self->timer;
225
self->hitbox.bottom = 80;
226
227
Acetone_CheckPlayerCollisions();
228
229
if (self->timer > 8)
230
self->maxGustCount[0] = 0;
231
else if (self->timer > 5)
232
self->maxGustCount[0] = 1;
233
else
234
self->maxGustCount[0] = 2;
235
236
if (self->timer > 8)
237
self->maxGustCount[1] = 0;
238
else if (self->timer > 5)
239
self->maxGustCount[1] = 1;
240
else
241
self->maxGustCount[1] = 2;
242
243
if (self->timer > 19)
244
self->maxGustCount[2] = 0;
245
else if (self->timer > 17)
246
self->maxGustCount[2] = 1;
247
else if (self->timer > 15)
248
self->maxGustCount[2] = 2;
249
else
250
self->maxGustCount[2] = 3;
251
252
if (self->timer > 16)
253
self->maxGustCount[3] = 0;
254
else if (self->timer > 14)
255
self->maxGustCount[3] = 1;
256
else if (self->timer > 12)
257
self->maxGustCount[3] = 2;
258
else
259
self->maxGustCount[3] = 3;
260
261
Acetone_HandleGustCount();
262
Acetone_HandleGustPos();
263
264
if (self->timer++ >= 20) {
265
self->active = ACTIVE_BOUNDS;
266
self->isActive = false;
267
self->state = Acetone_State_AwaitInterval;
268
self->timer = 0;
269
}
270
}
271
272
#if GAME_INCLUDE_EDITOR
273
void Acetone_EditorDraw(void)
274
{
275
RSDK_THIS(Acetone);
276
277
RSDK.SetSpriteAnimation(Acetone->aniFrames, 0, &self->dispenseAnimator, true, 0);
278
RSDK.SetSpriteAnimation(Acetone->aniFrames, 1, &self->gustAnimator, true, 0);
279
280
Acetone_Draw();
281
}
282
283
void Acetone_EditorLoad(void) { Acetone->aniFrames = RSDK.LoadSpriteAnimation("PSZ1/Acetone.bin", SCOPE_STAGE); }
284
#endif
285
286
void Acetone_Serialize(void)
287
{
288
RSDK_EDITABLE_VAR(Acetone, VAR_UINT16, interval);
289
RSDK_EDITABLE_VAR(Acetone, VAR_UINT16, intervalOffset);
290
RSDK_EDITABLE_VAR(Acetone, VAR_UINT16, duration);
291
}
292
293