Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/CPZ/ChemicalPool.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: ChemicalPool Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectChemicalPool *ChemicalPool;
11
12
void ChemicalPool_Update(void)
13
{
14
RSDK_THIS(ChemicalPool);
15
16
if (self->timer > 0)
17
self->timer--;
18
19
self->offsetY = self->position.y - self->updateRange.y;
20
21
StateMachine_Run(self->state);
22
}
23
24
void ChemicalPool_LateUpdate(void) {}
25
26
void ChemicalPool_StaticUpdate(void) {}
27
28
void ChemicalPool_Draw(void)
29
{
30
RSDK_THIS(ChemicalPool);
31
32
RSDKScreenInfo *screen = &ScreenInfo[SceneInfo->currentScreenID];
33
34
int32 screenX = self->position.x - (screen->position.x << 16);
35
int32 screenY = screen->position.y << 16;
36
37
Vector2 verts[4];
38
Vector2 *vertices = self->vertices;
39
for (int32 i = 0; i < self->tileSizeX; ++i) {
40
verts[0].x = vertices[0].x + screenX;
41
verts[0].y = vertices[0].y - screenY;
42
verts[1].x = vertices[2].x + screenX;
43
verts[1].y = vertices[2].y - screenY;
44
verts[2].x = vertices[3].x + screenX;
45
verts[2].y = vertices[3].y - screenY;
46
verts[3].x = vertices[1].x + screenX;
47
verts[3].y = vertices[1].y - screenY;
48
49
color *surfaceColors = NULL;
50
if (self->timer >= 1)
51
surfaceColors = ChemicalPool->surfaceColorsFlash;
52
else
53
surfaceColors = self->surfaceColors;
54
RSDK.DrawBlendedFace(verts, surfaceColors, 4, 0xC0, INK_NONE);
55
56
verts[0].x = verts[3].x;
57
verts[0].y = verts[3].y;
58
verts[1].x = verts[2].x;
59
verts[1].y = verts[2].y;
60
verts[2].y = self->position.y + self->updateRange.y - screenY;
61
verts[3].y = self->position.y + self->updateRange.y - screenY;
62
if (self->timer >= 1)
63
RSDK.DrawFace(verts, 4, 0xE0, 0xE0, 0xE0, 0xC0, INK_ALPHA);
64
else
65
RSDK.DrawFace(verts, 4, self->r, self->g, self->b, 0xC0, INK_ALPHA);
66
67
vertices += 2;
68
}
69
70
if (self->type > CHEMICALPOOL_BLUE) { // da reflection
71
int32 x = ((self->position.x - self->updateRange.x) >> 16) - screen->position.x;
72
int32 y = ((self->position.y - self->updateRange.y) >> 16) - screen->position.y;
73
RSDK.SetClipBounds(SceneInfo->currentScreenID, x, y, x + (self->size.x >> 16), y + (self->size.y >> 16));
74
75
Vector2 drawPos;
76
drawPos.x = self->position.x - ((self->position.x - (screen->position.x << 16) - (ScreenInfo->center.x << 16)) >> 1);
77
78
int32 offset = CLAMP(0x800000 - self->size.y, 0, 0x400000);
79
drawPos.y = offset + self->position.y + self->maxDeform - ((self->position.y - (screen->center.y << 16) - (screen->position.y << 16)) >> 4);
80
RSDK.DrawSprite(&self->animator, &drawPos, false);
81
82
RSDK.SetClipBounds(SceneInfo->currentScreenID, 0, 0, screen->size.x, screen->size.y);
83
}
84
}
85
86
void ChemicalPool_Create(void *data)
87
{
88
RSDK_THIS(ChemicalPool);
89
90
if (!SceneInfo->inEditor) {
91
self->inkEffect = INK_ADD;
92
self->visible = true;
93
self->alpha = 0xFF;
94
self->active = ACTIVE_BOUNDS;
95
self->drawGroup = Zone->objectDrawGroup[1] - 2;
96
self->updateRange.x = self->size.x >> 1;
97
self->updateRange.y = self->size.y >> 1;
98
self->tileSizeX = self->size.x >> 20;
99
100
Vector2 *vertices = self->vertices;
101
for (int32 i = 0; i < 0x2100000; i += 0x100000) {
102
int32 x = i - (self->size.x >> 1);
103
vertices[0].x = x;
104
vertices[1].x = x;
105
106
int32 y = self->position.y - (self->size.y >> 1);
107
vertices[0].y = y;
108
vertices[1].y = y + 0x80000;
109
110
vertices += 2;
111
}
112
113
self->leftEdge = (self->position.x - (self->size.x >> 1)) >> 20;
114
self->rightEdge = (self->position.x + (self->size.x >> 1)) >> 20;
115
self->impactPower = 0x80;
116
self->impactPowerSides = 0x99;
117
self->r = 0x00;
118
self->g = 0x08;
119
self->b = 0xC0;
120
121
self->hitbox.left = -(self->size.x >> 17);
122
self->hitbox.top = (self->type == CHEMICALPOOL_BLUE ? 6 : 0) - (self->size.y >> 17);
123
self->hitbox.right = -self->hitbox.left;
124
self->hitbox.bottom = -self->hitbox.bottom;
125
126
ChemicalPool_SetupColors();
127
128
self->timer = 0;
129
130
RSDK.SetSpriteAnimation(ChemicalPool->aniFrames, 0, &self->animator, true, 0);
131
}
132
}
133
134
void ChemicalPool_StageLoad(void)
135
{
136
ChemicalPool->aniFrames = RSDK.LoadSpriteAnimation("CPZ/ChemPool.bin", SCOPE_STAGE);
137
138
ChemicalPool->sfxChemYellow = RSDK.GetSfx("CPZ/ChemYellow.wav");
139
ChemicalPool->sfxChemRed = RSDK.GetSfx("CPZ/ChemRed.wav");
140
ChemicalPool->sfxChemChange = RSDK.GetSfx("CPZ/ChemChange.wav");
141
}
142
143
void ChemicalPool_ChangeState(EntityChemicalPool *chemPool, int32 newType, int32 newR, int32 newG, int32 newB)
144
{
145
chemPool->r = chemPool->r + ((newR - chemPool->r) >> 2);
146
chemPool->b = chemPool->b + ((newB - chemPool->b) >> 2);
147
chemPool->g = chemPool->g + ((newG - chemPool->g) >> 2);
148
chemPool->surfaceColors[2] = (chemPool->r << 16) | (chemPool->g << 8) | chemPool->b;
149
chemPool->surfaceColors[3] = (chemPool->r << 16) | (chemPool->g << 8) | chemPool->b;
150
151
uint32 change = abs(newR - chemPool->r) + abs(newG - chemPool->g) + abs(newB - chemPool->b) - 1;
152
if (change < 0x1F && chemPool->state != ChemicalPool_State_Changing) {
153
chemPool->type = newType;
154
chemPool->timer = 4;
155
chemPool->state = ChemicalPool_State_Changing;
156
RSDK.PlaySfx(ChemicalPool->sfxChemChange, false, 255);
157
}
158
}
159
160
void ChemicalPool_ProcessDeformations(void)
161
{
162
RSDK_THIS(ChemicalPool);
163
164
for (int32 i = self->leftEdge; i < self->rightEdge; ++i) {
165
int32 deform = ChemicalPool->surfaceDeformation[i];
166
ChemicalPool->impactTable[i] += (-deform >> 5) - (ChemicalPool->impactTable[i] >> 3);
167
ChemicalPool->deformTable[i] = ChemicalPool->impactTable[i] + ChemicalPool->surfaceDeformation[i];
168
}
169
170
for (int32 i = self->leftEdge; i < self->rightEdge; ++i) {
171
int32 prev = MAX(i - 1, self->leftEdge);
172
int32 next = MIN(i + 1, self->rightEdge);
173
174
ChemicalPool->surfaceDeformation[i] = (self->impactPower * ChemicalPool->deformTable[i] >> 8)
175
+ (self->impactPowerSides * (ChemicalPool->deformTable[prev] + ChemicalPool->deformTable[next]) >> 9);
176
}
177
178
self->maxDeform = 0;
179
int32 id = self->leftEdge;
180
Vector2 *vertices = self->vertices;
181
for (int32 i = 0; i <= self->tileSizeX; ++i) {
182
if (ChemicalPool->surfaceDeformation[id] > self->maxDeform)
183
self->maxDeform = ChemicalPool->surfaceDeformation[id];
184
vertices[0].y = ChemicalPool->surfaceDeformation[id] + self->offsetY;
185
186
int32 deform = 2 * ChemicalPool->surfaceDeformation[id] + 0x80000;
187
if (deform < ChemicalPool->surfaceDeformation[id])
188
deform = ChemicalPool->surfaceDeformation[id] + 0x10000;
189
vertices[1].y = deform + self->offsetY;
190
191
++id;
192
vertices += 2;
193
}
194
}
195
196
void ChemicalPool_SetDeform(int32 impactX, int32 impactVelocity)
197
{
198
int32 bounceX = (impactX + 0x80000) >> 20;
199
200
foreach_active(ChemicalPool, chemPool)
201
{
202
if (bounceX > chemPool->leftEdge && bounceX < chemPool->rightEdge) {
203
int32 prev = MAX(bounceX - 1, chemPool->leftEdge + 1);
204
int32 next = MIN(bounceX + 2, chemPool->rightEdge);
205
206
for (int32 i = 0; i < next - prev; ++i) ChemicalPool->impactTable[prev + i] += impactVelocity;
207
208
foreach_break;
209
}
210
}
211
}
212
213
void ChemicalPool_SpawnDebris(int32 x, int32 y)
214
{
215
RSDK_THIS(ChemicalPool);
216
217
for (int32 i = 0; i < 6; ++i) {
218
EntityDebris *debris = CREATE_ENTITY(Debris, NULL, x + ZONE_RAND(-0x80000, 0x80000), y + ZONE_RAND(0x40000, 0x140000));
219
debris->state = Debris_State_Fall;
220
debris->gravityStrength = 0x3800;
221
debris->velocity.x = ZONE_RAND(0, 0x20000);
222
if (debris->position.x < x)
223
debris->velocity.x = -debris->velocity.x;
224
debris->velocity.y = ZONE_RAND(-0x40000, -0x10000);
225
debris->drawGroup = Zone->objectDrawGroup[1];
226
RSDK.SetSpriteAnimation(Reagent->aniFrames, self->type + 1, &debris->animator, true, ZONE_RAND(0, 2));
227
}
228
}
229
230
void ChemicalPool_SetupColors(void)
231
{
232
RSDK_THIS(ChemicalPool);
233
234
switch (self->type) {
235
case CHEMICALPOOL_BLUE:
236
default:
237
self->surfaceColors[0] = 0x0060E0;
238
self->surfaceColors[1] = 0x0060E0;
239
self->surfaceColors[2] = 0x0008C0;
240
self->surfaceColors[3] = 0x0008C0;
241
self->r = 0x00;
242
self->g = 0x08;
243
self->b = 0xC0;
244
self->state = ChemicalPool_State_HarmfulBlue;
245
self->timer = 3;
246
break;
247
248
case CHEMICALPOOL_GREEN:
249
self->surfaceColors[0] = 0x20E020;
250
self->surfaceColors[1] = 0x20E020;
251
self->surfaceColors[2] = 0x189000;
252
self->surfaceColors[3] = 0x189000;
253
self->r = 0x18;
254
self->g = 0x90;
255
self->b = 0x00;
256
self->state = ChemicalPool_State_Green;
257
self->timer = 3;
258
break;
259
260
case CHEMICALPOOL_CYAN:
261
self->surfaceColors[0] = 0x00B8F0;
262
self->surfaceColors[1] = 0x00B8F0;
263
self->surfaceColors[2] = 0x0080B0;
264
self->surfaceColors[3] = 0x0080B0;
265
self->r = 0x00;
266
self->g = 0x80;
267
self->b = 0xB0;
268
self->state = ChemicalPool_State_Cyan;
269
self->timer = 3;
270
break;
271
}
272
}
273
274
void ChemicalPool_State_HarmfulBlue(void)
275
{
276
RSDK_THIS(ChemicalPool);
277
ChemicalPool_ProcessDeformations();
278
int32 topStore = self->hitbox.top;
279
280
foreach_active(Player, player)
281
{
282
if (player->velocity.y >= 0 && Player_CheckCollisionBox(player, self, &self->hitbox)) {
283
ChemicalPool_SetDeform(player->position.x, (player->velocity.y >> 4) + 0x1000);
284
if (player->shield != SHIELD_BUBBLE) {
285
if (player->state != Player_State_Hurt && player->state != Player_State_Death && player->state != Player_State_Drown
286
&& !player->invincibleTimer && player->blinkTimer <= 0) {
287
if (player->position.x > self->position.x)
288
player->velocity.x = 0x20000;
289
else
290
player->velocity.x = -0x20000;
291
Player_Hit(player);
292
}
293
}
294
295
if (player->velocity.y < 0 && player->velocity.y > -0x40000)
296
player->velocity.y = -0x40000;
297
}
298
}
299
300
self->hitbox.top = topStore;
301
if (!(Zone->timer & 3)) {
302
EntityChemBubble *bubble = CREATE_ENTITY(ChemBubble, NULL, self->position.x + RSDK.Rand(-self->updateRange.x, self->updateRange.x),
303
self->position.y + self->updateRange.y);
304
bubble->parent = self;
305
}
306
}
307
308
void ChemicalPool_State_Green(void)
309
{
310
RSDK_THIS(ChemicalPool);
311
312
ChemicalPool_ProcessDeformations();
313
314
foreach_active(Player, player)
315
{
316
if (Player_CheckCollisionTouch(player, self, &self->hitbox)) {
317
ChemicalPool_SetDeform(player->position.x, player->velocity.y >> 1);
318
ChemicalPool_SpawnDebris(player->position.x, player->position.y);
319
320
if (player->state != Player_State_DropDash)
321
player->state = Player_State_Air;
322
323
int32 anim = player->animator.animationID;
324
if (anim != ANI_JUMP && anim != ANI_JOG && anim != ANI_RUN && anim != ANI_DASH)
325
player->animator.animationID = ANI_WALK;
326
327
player->onGround = false;
328
player->applyJumpCap = false;
329
player->velocity.y = -0x140000;
330
331
RSDK.PlaySfx(ChemicalPool->sfxChemRed, false, 255);
332
}
333
}
334
}
335
336
void ChemicalPool_State_Cyan(void)
337
{
338
RSDK_THIS(ChemicalPool);
339
340
ChemicalPool_ProcessDeformations();
341
342
foreach_active(Player, player)
343
{
344
if (player->velocity.y >= 0) {
345
if (Player_CheckCollisionTouch(player, self, &self->hitbox)) {
346
ChemicalPool_SetDeform(player->position.x, player->velocity.y >> 1);
347
ChemicalPool_SpawnDebris(player->position.x, player->position.y);
348
349
if (player->state != Player_State_DropDash)
350
player->state = Player_State_Air;
351
352
int32 anim = player->animator.animationID;
353
if (anim != ANI_JUMP && anim != ANI_JOG && anim != ANI_RUN && anim != ANI_DASH)
354
player->animator.animationID = ANI_WALK;
355
356
if ((-0x10000 - player->velocity.y) > -0x80000)
357
player->velocity.y = -0x10000 - player->velocity.y;
358
else
359
player->velocity.y = -0x80000;
360
361
player->onGround = false;
362
player->applyJumpCap = false;
363
RSDK.PlaySfx(ChemicalPool->sfxChemYellow, false, 255);
364
}
365
}
366
}
367
}
368
369
void ChemicalPool_State_Changing(void)
370
{
371
RSDK_THIS(ChemicalPool);
372
373
ChemicalPool_ProcessDeformations();
374
375
if (++self->changeTimer == 16) {
376
foreach_active(ChemBubble, bubble)
377
{
378
if (abs(bubble->position.x - self->position.x) <= self->updateRange.x) {
379
if (abs(bubble->position.y - self->position.y) <= self->updateRange.y)
380
destroyEntity(bubble);
381
}
382
}
383
384
self->changeTimer = 0;
385
ChemicalPool_SetupColors();
386
self->active = ACTIVE_BOUNDS;
387
}
388
}
389
390
#if GAME_INCLUDE_EDITOR
391
void ChemicalPool_EditorDraw(void)
392
{
393
RSDK_THIS(ChemicalPool);
394
395
self->updateRange.x = self->size.x >> 1;
396
self->updateRange.y = self->size.y >> 1;
397
398
Vector2 drawPos;
399
drawPos.x = self->position.x - (self->size.x >> 1);
400
drawPos.y = self->position.y - (self->size.y >> 1);
401
ChemicalPool_SetupColors();
402
RSDK.DrawRect(drawPos.x, drawPos.y, self->size.x, self->size.y, (self->r << 16) | (self->g << 8) | (self->b << 0), 0xC0, INK_ALPHA, false);
403
404
DrawHelpers_DrawRectOutline(self->position.x, self->position.y, self->size.x, self->size.y, 0xFFFF00);
405
}
406
407
void ChemicalPool_EditorLoad(void)
408
{
409
RSDK_ACTIVE_VAR(ChemicalPool, type);
410
RSDK_ENUM_VAR("Blue", CHEMICALPOOL_BLUE);
411
RSDK_ENUM_VAR("Green", CHEMICALPOOL_GREEN);
412
RSDK_ENUM_VAR("Cyan", CHEMICALPOOL_CYAN);
413
}
414
#endif
415
416
void ChemicalPool_Serialize(void)
417
{
418
RSDK_EDITABLE_VAR(ChemicalPool, VAR_ENUM, type);
419
RSDK_EDITABLE_VAR(ChemicalPool, VAR_VECTOR2, size);
420
}
421
422