Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/HCZ/HCZSpikeBall.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: HCZSpikeBall Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
// NOTE:
11
// This is a mania-fied version of the spikeballs present on S3 hang conveyors.
12
// This object is 100% fully functional.
13
// However, they're never placed in any stage, Making them unused.
14
15
ObjectHCZSpikeBall *HCZSpikeBall;
16
17
void HCZSpikeBall_Update(void)
18
{
19
HCZSpikeBall_HandleConveyorMovement();
20
HCZSpikeBall_HandlePlayerInteractions();
21
}
22
23
void HCZSpikeBall_LateUpdate(void) {}
24
25
void HCZSpikeBall_StaticUpdate(void) {}
26
27
void HCZSpikeBall_Draw(void)
28
{
29
RSDK_THIS(HCZSpikeBall);
30
31
RSDK.DrawSprite(&self->animator, NULL, false);
32
}
33
34
void HCZSpikeBall_Create(void *data)
35
{
36
RSDK_THIS(HCZSpikeBall);
37
38
self->active = ACTIVE_BOUNDS;
39
self->drawGroup = Zone->objectDrawGroup[0];
40
self->startPos = self->position;
41
self->visible = true;
42
self->drawFX = FX_FLIP;
43
self->updateRange.x = 0x800000;
44
self->updateRange.y = 0x800000;
45
46
self->hitbox.left = -10;
47
self->hitbox.top = -10;
48
self->hitbox.right = 10;
49
self->hitbox.bottom = 10;
50
51
HCZSpikeBall_HandleConveyorSetup();
52
RSDK.SetSpriteAnimation(HCZSpikeBall->aniFrames, 0, &self->animator, true, 1);
53
}
54
55
void HCZSpikeBall_StageLoad(void) { HCZSpikeBall->aniFrames = RSDK.LoadSpriteAnimation("HCZ/Platform.bin", SCOPE_STAGE); }
56
57
void HCZSpikeBall_HandleConveyorSetup(void)
58
{
59
RSDK_THIS(HCZSpikeBall);
60
61
if (!SceneInfo->inEditor) {
62
foreach_all(HangConveyor, conveyor)
63
{
64
if (MathHelpers_PointInHitbox(conveyor->position.x, conveyor->position.y, self->position.x, self->position.y, conveyor->direction,
65
&conveyor->hitboxSpikeBallRange)) {
66
self->conveyor = conveyor;
67
self->updateRange = conveyor->updateRange;
68
foreach_break;
69
}
70
}
71
72
if (self->conveyor)
73
HCZSpikeBall_LinkToConveyor();
74
}
75
}
76
77
void HCZSpikeBall_LinkToConveyor(void)
78
{
79
RSDK_THIS(HCZSpikeBall);
80
81
EntityHangConveyor *conveyor = self->conveyor;
82
if (conveyor) {
83
Hitbox hitboxTop, hitboxLeft, hitboxBottom, hitboxRight;
84
85
int32 len = 0;
86
if (conveyor->length != -3)
87
len = (conveyor->length + 3) << 20;
88
89
hitboxTop.top = -26;
90
hitboxTop.bottom = -16;
91
hitboxTop.right = len >> 17;
92
hitboxTop.left = -hitboxTop.right;
93
94
hitboxLeft.left = conveyor->hitboxSpikeBallRange.left;
95
hitboxLeft.top = conveyor->hitboxSpikeBallRange.top;
96
hitboxLeft.right = -hitboxTop.right;
97
hitboxLeft.bottom = conveyor->hitboxSpikeBallRange.bottom;
98
99
hitboxBottom.left = -(len >> 17);
100
hitboxBottom.top = 16;
101
hitboxBottom.right = len >> 17;
102
hitboxBottom.bottom = 26;
103
104
hitboxRight.left = len >> 17;
105
hitboxRight.top = hitboxLeft.top;
106
hitboxRight.right = conveyor->hitboxSpikeBallRange.right;
107
hitboxRight.bottom = hitboxLeft.bottom;
108
109
if (MathHelpers_PointInHitbox(conveyor->position.x, conveyor->position.y, self->position.x, self->position.y, conveyor->direction,
110
&hitboxTop)) {
111
int32 dist = conveyor->position.x - (len >> 1);
112
if (conveyor->direction == FLIP_NONE)
113
dist = conveyor->position.x + (len >> 1);
114
self->intervalOffset = abs(self->position.x - (self->position.x - dist)) / 0x15555;
115
}
116
else if (MathHelpers_PointInHitbox(conveyor->position.x, conveyor->position.y, self->position.x, self->position.y, conveyor->direction,
117
&hitboxLeft)) {
118
int32 dist = len / 0x15555;
119
int32 angle = 0x180;
120
if (conveyor->direction) {
121
dist = 2 * (len / 0x15555) + 51;
122
angle = 0x80;
123
}
124
125
int32 atan = RSDK.ATan2(self->position.x - conveyor->position.x - (len >> 1), self->position.y - conveyor->position.y);
126
self->intervalOffset = (abs(angle - 2 * atan) / 5) + dist;
127
}
128
else if (MathHelpers_PointInHitbox(conveyor->position.x, conveyor->position.y, self->position.x, self->position.y, conveyor->direction,
129
&hitboxBottom)) {
130
int32 dist = (len >> 1) + conveyor->position.x;
131
if (conveyor->direction == FLIP_NONE)
132
dist = conveyor->position.x - (len >> 1);
133
self->intervalOffset = abs((self->position.x - dist)) / 0x15555 + (len / 0x15555) + 51;
134
}
135
else if (MathHelpers_PointInHitbox(conveyor->position.x, conveyor->position.y, self->position.x, self->position.y, conveyor->direction,
136
&hitboxRight)) {
137
int32 dist = len / 0x15555;
138
int32 angle = 0x180;
139
if (!conveyor->direction) {
140
dist = 2 * (len / 0x15555) + 51;
141
angle = 0x80;
142
}
143
144
int32 atan = RSDK.ATan2(self->position.x - (len >> 1) + conveyor->position.x, self->position.y - conveyor->position.y);
145
self->intervalOffset = (abs(angle - 2 * atan) / 5) + dist;
146
}
147
else {
148
self->intervalOffset = 0;
149
}
150
}
151
}
152
153
void HCZSpikeBall_HandlePlayerInteractions(void)
154
{
155
RSDK_THIS(HCZSpikeBall);
156
foreach_active(Player, player)
157
{
158
// Oversight(?) Note:
159
// Due to this object being unused, it didn't get updated with mighty collision checks
160
// It's not 100% certain that it would've, but since the rest of the game's spiked objects do, this one could've too
161
if (Player_CheckCollisionTouch(player, self, &self->hitbox))
162
Player_Hurt(player, self);
163
}
164
}
165
166
void HCZSpikeBall_HandleConveyorMovement(void)
167
{
168
RSDK_THIS(HCZSpikeBall);
169
170
if (self->conveyor) {
171
int32 len = 0;
172
if (self->conveyor->length != -3)
173
len = (self->conveyor->length + 3) << 20;
174
175
int32 interval = (2 * len + 0x8A3AE6) / 0x15555;
176
int32 timer = (self->intervalOffset + Zone->timer) % interval;
177
int32 conveyX = self->conveyor->position.x;
178
int32 conveyY = self->conveyor->position.y;
179
180
if (timer < len / 0x15555) {
181
if (self->conveyor->direction == FLIP_NONE)
182
self->position.x = conveyX + (len >> 1);
183
else
184
self->position.x = conveyX - (len >> 1);
185
186
self->position.x += 0x15555 * timer * (2 * (self->conveyor->direction != FLIP_NONE) - 1);
187
self->position.y = conveyY - 0x160000;
188
}
189
else if (timer < (len / 0x15555) + 51) {
190
int32 angle = timer - (len / 0x15555);
191
if (self->conveyor->direction == FLIP_NONE)
192
self->position.x = conveyX - (len >> 1);
193
else
194
self->position.x = conveyX + (len >> 1);
195
196
int32 mult = self->conveyor->direction == FLIP_NONE ? -5 : 5;
197
198
self->position.y = conveyY;
199
self->position.x += 0xB00 * RSDK.Cos512(angle * mult + 0x180);
200
self->position.y += 0xB00 * RSDK.Sin512(angle * mult + 0x180);
201
}
202
else if (timer >= 2 * (len / 0x15555) + 51) {
203
int32 angle = -51 - 2 * (len / 0x15555) + timer;
204
if (self->conveyor->direction == FLIP_NONE)
205
self->position.x = conveyX + (len >> 1);
206
else
207
self->position.x = conveyX - (len >> 1);
208
209
int32 mult = self->conveyor->direction == FLIP_NONE ? -5 : 5;
210
211
self->position.y = conveyY;
212
self->position.x += 0xB00 * RSDK.Cos512(angle * mult + 0x80);
213
self->position.y += 0xB00 * RSDK.Sin512(angle * mult + 0x80);
214
}
215
else {
216
if (self->conveyor->direction == FLIP_NONE)
217
self->position.x = conveyX - (len >> 1);
218
else
219
self->position.x = conveyX + (len >> 1);
220
221
self->position.x += 0x15555 * (-51 - (len / 0x15555) + timer) * (2 * (self->conveyor->direction == FLIP_NONE) - 1);
222
self->position.y = conveyY + 0x160000;
223
}
224
}
225
}
226
227
#if GAME_INCLUDE_EDITOR
228
void HCZSpikeBall_EditorDraw(void) { HCZSpikeBall_Draw(); }
229
230
void HCZSpikeBall_EditorLoad(void) { HCZSpikeBall->aniFrames = RSDK.LoadSpriteAnimation("HCZ/Platform.bin", SCOPE_STAGE); }
231
#endif
232
233
void HCZSpikeBall_Serialize(void) {}
234
235