Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/GHZ/Newtron.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: Newtron Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectNewtron *Newtron;
11
12
void Newtron_Update(void)
13
{
14
RSDK_THIS(Newtron);
15
StateMachine_Run(self->state);
16
}
17
18
void Newtron_LateUpdate(void) {}
19
20
void Newtron_StaticUpdate(void) {}
21
22
void Newtron_Draw(void)
23
{
24
RSDK_THIS(Newtron);
25
RSDK.DrawSprite(&self->animator, NULL, false);
26
if (self->state == Newtron_State_Fly)
27
RSDK.DrawSprite(&self->flameAnimator, NULL, false);
28
}
29
30
void Newtron_Create(void *data)
31
{
32
RSDK_THIS(Newtron);
33
if (!SceneInfo->inEditor) {
34
self->drawFX |= FX_FLIP;
35
self->startPos = self->position;
36
self->visible = true;
37
38
if (data == INT_TO_VOID(NEWTRON_FLY)) {
39
self->type = NEWTRON_FLY;
40
self->active = ACTIVE_BOUNDS;
41
self->updateRange.x = 0x800000;
42
self->updateRange.y = 0x800000;
43
}
44
else if (data) {
45
self->inkEffect = INK_ADD;
46
self->alpha = 0xC0;
47
RSDK.SetSpriteAnimation(Newtron->aniFrames, 6, &self->animator, true, 0);
48
self->state = Newtron_State_Projectile;
49
self->active = ACTIVE_NORMAL;
50
self->updateRange.x = 0x200000;
51
self->updateRange.y = 0x200000;
52
self->drawGroup = Zone->objectDrawGroup[1];
53
return;
54
}
55
56
self->inkEffect = INK_ALPHA;
57
self->alpha = 0x00;
58
self->active = ACTIVE_BOUNDS;
59
self->updateRange.x = 0x800000;
60
self->updateRange.y = 0x800000;
61
if (self->type == NEWTRON_FLY) {
62
RSDK.SetSpriteAnimation(Newtron->aniFrames, 2, &self->animator, true, 0);
63
self->drawGroup = Zone->objectDrawGroup[0];
64
}
65
else {
66
RSDK.SetSpriteAnimation(Newtron->aniFrames, 0, &self->animator, true, 0);
67
self->drawGroup = Zone->objectDrawGroup[1];
68
}
69
RSDK.SetSpriteAnimation(Newtron->aniFrames, 5, &self->flameAnimator, true, 0);
70
self->state = Newtron_State_Init;
71
}
72
}
73
74
void Newtron_StageLoad(void)
75
{
76
if (RSDK.CheckSceneFolder("GHZ"))
77
Newtron->aniFrames = RSDK.LoadSpriteAnimation("GHZ/Newtron.bin", SCOPE_STAGE);
78
79
Newtron->hitboxShoot.left = -12;
80
Newtron->hitboxShoot.top = -14;
81
Newtron->hitboxShoot.right = 12;
82
Newtron->hitboxShoot.bottom = 14;
83
84
// hitbox for the flying variant
85
// goes unused in this object because..... ???
86
// at least GHZ/CheckerBall uses it
87
Newtron->hitboxFly.left = -16;
88
Newtron->hitboxFly.top = -8;
89
Newtron->hitboxFly.right = 16;
90
Newtron->hitboxFly.bottom = 8;
91
92
Newtron->hitboxProjectile.left = -6;
93
Newtron->hitboxProjectile.top = -6;
94
Newtron->hitboxProjectile.right = 6;
95
Newtron->hitboxProjectile.bottom = 6;
96
97
Newtron->hitboxRange.left = -128;
98
Newtron->hitboxRange.top = -64;
99
Newtron->hitboxRange.right = 128;
100
Newtron->hitboxRange.bottom = 64;
101
102
DEBUGMODE_ADD_OBJ(Newtron);
103
}
104
105
void Newtron_DebugDraw(void)
106
{
107
RSDK.SetSpriteAnimation(Newtron->aniFrames, 0, &DebugMode->animator, true, 0);
108
RSDK.DrawSprite(&DebugMode->animator, NULL, false);
109
}
110
111
void Newtron_DebugSpawn(void)
112
{
113
RSDK_THIS(DebugMode);
114
115
CREATE_ENTITY(Newtron, NULL, self->position.x, self->position.y);
116
}
117
118
void Newtron_CheckPlayerCollisions(void)
119
{
120
RSDK_THIS(Newtron);
121
122
foreach_active(Player, player)
123
{
124
if (Player_CheckBadnikTouch(player, self, &Newtron->hitboxShoot))
125
Player_CheckBadnikBreak(player, self, true);
126
}
127
}
128
129
void Newtron_CheckOffScreen(void)
130
{
131
RSDK_THIS(Newtron);
132
133
if (!RSDK.CheckOnScreen(self, NULL) && !RSDK.CheckPosOnScreen(&self->startPos, &self->updateRange)) {
134
self->position = self->startPos;
135
self->velocity.x = 0;
136
self->velocity.y = 0;
137
self->timer = 0;
138
Newtron_Create(NULL);
139
}
140
}
141
142
void Newtron_GetTargetDir(void)
143
{
144
RSDK_THIS(Newtron);
145
146
EntityPlayer *targetPlayer = NULL;
147
foreach_active(Player, player)
148
{
149
if (targetPlayer) {
150
if (abs(player->position.x - self->position.x) < abs(targetPlayer->position.x - self->position.x))
151
targetPlayer = player;
152
}
153
else {
154
targetPlayer = player;
155
}
156
}
157
158
if (targetPlayer)
159
self->direction = targetPlayer->position.x < self->position.x;
160
}
161
162
void Newtron_State_Init(void)
163
{
164
RSDK_THIS(Newtron);
165
166
self->active = ACTIVE_NORMAL;
167
168
self->state = Newtron_State_CheckPlayerInRange;
169
Newtron_State_CheckPlayerInRange();
170
}
171
172
void Newtron_State_CheckPlayerInRange(void)
173
{
174
RSDK_THIS(Newtron);
175
176
foreach_active(Player, player)
177
{
178
if (Player_CheckCollisionTouch(player, self, &Newtron->hitboxRange))
179
self->state = Newtron_State_Appear;
180
}
181
182
Newtron_CheckOffScreen();
183
}
184
185
void Newtron_State_Appear(void)
186
{
187
RSDK_THIS(Newtron);
188
189
if (self->alpha >= 0xF8) {
190
self->alpha = 0xFF;
191
if (self->type == NEWTRON_FLY) {
192
self->state = Newtron_State_StartFly;
193
RSDK.SetSpriteAnimation(Newtron->aniFrames, 3, &self->animator, true, 0);
194
}
195
else
196
self->state = Newtron_State_Shoot;
197
}
198
else {
199
self->alpha += 4;
200
if (self->type == NEWTRON_FLY)
201
Newtron_GetTargetDir();
202
}
203
204
RSDK.ProcessAnimation(&self->animator);
205
206
Newtron_CheckOffScreen();
207
}
208
209
void Newtron_State_StartFly(void)
210
{
211
RSDK_THIS(Newtron);
212
213
Newtron_GetTargetDir();
214
215
if (self->animator.frameID >= 2) {
216
self->position.y += self->velocity.y;
217
self->velocity.y += 0x3800;
218
219
if (RSDK.ObjectTileGrip(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0x80000, 8)) {
220
self->velocity.y = 0;
221
if (self->direction == FLIP_NONE)
222
self->velocity.x = 0x20000;
223
else
224
self->velocity.x = -0x20000;
225
RSDK.SetSpriteAnimation(Newtron->aniFrames, 4, &self->animator, true, 0);
226
self->state = Newtron_State_Fly;
227
}
228
}
229
230
RSDK.ProcessAnimation(&self->animator);
231
232
Newtron_CheckPlayerCollisions();
233
Newtron_CheckOffScreen();
234
}
235
236
void Newtron_State_Fly(void)
237
{
238
RSDK_THIS(Newtron);
239
240
self->position.x += self->velocity.x;
241
RSDK.ObjectTileGrip(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0x80000, 8);
242
243
RSDK.ProcessAnimation(&self->animator);
244
RSDK.ProcessAnimation(&self->flameAnimator);
245
246
Newtron_CheckPlayerCollisions();
247
Newtron_CheckOffScreen();
248
}
249
250
void Newtron_State_Shoot(void)
251
{
252
RSDK_THIS(Newtron);
253
254
switch (++self->timer) {
255
case 30:
256
RSDK.SetSpriteAnimation(Newtron->aniFrames, 1, &self->animator, true, 0);
257
if (self->direction)
258
CREATE_ENTITY(Newtron, INT_TO_VOID(NEWTRON_PROJECTILE), self->position.x - 0x140000, self->position.y - 0x80000)->velocity.x =
259
-0x20000;
260
else
261
CREATE_ENTITY(Newtron, INT_TO_VOID(NEWTRON_PROJECTILE), self->position.x + 0x140000, self->position.y - 0x80000)->velocity.x =
262
0x20000;
263
break;
264
265
case 45: RSDK.SetSpriteAnimation(Newtron->aniFrames, 0, &self->animator, true, 0); break;
266
267
case 90: self->state = Newtron_State_FadeAway; break;
268
}
269
270
RSDK.ProcessAnimation(&self->animator);
271
272
Newtron_CheckPlayerCollisions();
273
Newtron_CheckOffScreen();
274
}
275
276
void Newtron_State_FadeAway(void)
277
{
278
RSDK_THIS(Newtron);
279
280
RSDK.ProcessAnimation(&self->animator);
281
Newtron_CheckOffScreen();
282
283
if (self->alpha <= 0)
284
destroyEntity(self);
285
else
286
self->alpha -= 4;
287
}
288
289
void Newtron_State_Projectile(void)
290
{
291
RSDK_THIS(Newtron);
292
293
self->position.x += self->velocity.x;
294
295
if (!RSDK.CheckOnScreen(self, NULL)) {
296
destroyEntity(self);
297
}
298
else {
299
RSDK.ProcessAnimation(&self->animator);
300
301
foreach_active(Player, player)
302
{
303
if (Player_CheckCollisionTouch(player, self, &Newtron->hitboxProjectile))
304
Player_ProjectileHurt(player, self);
305
}
306
}
307
}
308
309
#if GAME_INCLUDE_EDITOR
310
void Newtron_EditorDraw(void)
311
{
312
RSDK_THIS(Newtron);
313
314
self->drawFX = FX_FLIP;
315
if (self->type == NEWTRON_FLY)
316
RSDK.SetSpriteAnimation(Newtron->aniFrames, 2, &self->animator, true, 0);
317
else
318
RSDK.SetSpriteAnimation(Newtron->aniFrames, 0, &self->animator, true, 0);
319
RSDK.SetSpriteAnimation(Newtron->aniFrames, 5, &self->flameAnimator, true, 0);
320
321
Newtron_Draw();
322
}
323
324
void Newtron_EditorLoad(void)
325
{
326
Newtron->aniFrames = RSDK.LoadSpriteAnimation("GHZ/Newtron.bin", SCOPE_STAGE);
327
328
RSDK_ACTIVE_VAR(Newtron, type);
329
RSDK_ENUM_VAR("Shoot", NEWTRON_SHOOT);
330
RSDK_ENUM_VAR("Fly", NEWTRON_FLY);
331
332
// Only for "Shoot" Variant, fly variant direction is based on the target's position
333
RSDK_ACTIVE_VAR(Newtron, direction);
334
RSDK_ENUM_VAR("Right", FLIP_NONE);
335
RSDK_ENUM_VAR("Left", FLIP_X);
336
}
337
#endif
338
339
void Newtron_Serialize(void)
340
{
341
RSDK_EDITABLE_VAR(Newtron, VAR_UINT8, type);
342
RSDK_EDITABLE_VAR(Newtron, VAR_UINT8, direction);
343
}
344
345