Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/TMZ/MetalArm.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: MetalArm Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectMetalArm *MetalArm;
11
12
void MetalArm_Update(void)
13
{
14
RSDK_THIS(MetalArm);
15
16
self->moveOffset.x = -self->armPosition.x;
17
self->moveOffset.y = -self->armPosition.y;
18
19
int32 timerA = MIN(self->durationA, self->moveTimer);
20
int32 interpolateA = ((self->endAngleA - self->startAngleA) << 16) / self->durationA;
21
self->armAngle.x = (self->startAngleA << 16) + interpolateA * timerA;
22
23
int32 timerB = MIN(self->durationB, self->moveTimer);
24
int32 interpolateB = ((self->endAngleB - self->startAngleB) << 16) / self->durationB;
25
self->armAngle.y = (self->startAngleB << 16) + interpolateB * timerB;
26
27
self->armPosition = MetalArm_GetArmPosition();
28
self->armPosition.x &= 0xFFFF0000;
29
self->armPosition.y &= 0xFFFF0000;
30
31
self->position.x = self->armPosition.x;
32
self->position.y = self->armPosition.y;
33
self->moveOffset.x += self->position.x;
34
self->moveOffset.y += self->position.y;
35
36
MetalArm_CheckPlayerCollisions();
37
38
self->position.x = self->startPos.x;
39
self->position.y = self->startPos.y;
40
41
StateMachine_Run(self->state);
42
}
43
44
void MetalArm_LateUpdate(void) {}
45
46
void MetalArm_StaticUpdate(void) {}
47
48
void MetalArm_Draw(void)
49
{
50
RSDK_THIS(MetalArm);
51
52
self->rotation = 0;
53
RSDK.DrawSprite(&self->baseAnimator, NULL, false);
54
55
int32 x = 0x2400 * RSDK.Cos512((self->armAngle.x >> 16)) + self->position.x;
56
int32 y = 0x2400 * RSDK.Sin512((self->armAngle.x >> 16)) + self->position.y;
57
58
Vector2 drawPos = MetalArm_GetArmPosition();
59
self->position.x = x;
60
self->position.y = y;
61
self->position.x &= 0xFFFF0000;
62
self->position.y &= 0xFFFF0000;
63
self->rotation = (self->armAngle.x + self->armAngle.y) >> 16;
64
RSDK.DrawSprite(&self->armBAnimator, NULL, false);
65
66
self->position.x = self->startPos.x;
67
self->position.y = self->startPos.y;
68
self->position.x &= 0xFFFF0000;
69
self->position.y &= 0xFFFF0000;
70
self->rotation = (self->armAngle.x >> 16);
71
RSDK.DrawSprite(&self->armAAnimator, NULL, false);
72
73
self->rotation = 0;
74
self->position = drawPos;
75
self->position.x &= 0xFFFF0000;
76
self->position.y &= 0xFFFF0000;
77
RSDK.DrawSprite(&self->platformAnimator, &drawPos, false);
78
79
self->position.x = self->startPos.x;
80
self->position.y = self->startPos.y;
81
}
82
83
void MetalArm_Create(void *data)
84
{
85
RSDK_THIS(MetalArm);
86
87
self->active = ACTIVE_BOUNDS;
88
self->drawGroup = Zone->objectDrawGroup[1];
89
self->startPos.x = self->position.x;
90
self->startPos.y = self->position.y;
91
self->visible = true;
92
self->drawFX = FX_ROTATE | FX_FLIP;
93
self->updateRange.x = 0x1000000;
94
self->updateRange.y = 0x1000000;
95
96
if (!self->durationA)
97
self->durationA = 60;
98
99
if (!self->durationB)
100
self->durationB = 40;
101
102
if (!self->holdDuration)
103
self->holdDuration = 60;
104
105
self->hitbox.left = -56;
106
self->hitbox.top = -27;
107
self->hitbox.right = 56;
108
self->hitbox.bottom = -7;
109
110
RSDK.SetSpriteAnimation(MetalArm->aniFrames, 0, &self->baseAnimator, true, 0);
111
RSDK.SetSpriteAnimation(MetalArm->aniFrames, 1, &self->armAAnimator, true, 0);
112
RSDK.SetSpriteAnimation(MetalArm->aniFrames, 2, &self->armBAnimator, true, 0);
113
RSDK.SetSpriteAnimation(MetalArm->aniFrames, 3, &self->platformAnimator, true, 0);
114
115
self->armAngle.x = self->startAngleA << 16;
116
self->armAngle.y = self->startAngleB << 16;
117
self->moveTimer = 0;
118
self->armPosition = MetalArm_GetArmPosition();
119
self->state = MetalArm_State_Idle;
120
}
121
122
void MetalArm_StageLoad(void)
123
{
124
MetalArm->aniFrames = RSDK.LoadSpriteAnimation("TMZ1/MetalArm.bin", SCOPE_STAGE);
125
126
Soundboard_LoadSfx("TMZ1/MetalArm.wav", true, MetalArm_SfxCheck_MetalArm, StateMachine_None);
127
}
128
129
bool32 MetalArm_SfxCheck_MetalArm(void)
130
{
131
int32 activeCount = 0;
132
133
foreach_active(MetalArm, arm)
134
{
135
if (arm->state == MetalArm_State_MoveToHold || arm->state == MetalArm_State_MoveToStart)
136
++activeCount;
137
}
138
139
return activeCount > 0;
140
}
141
142
Vector2 MetalArm_GetArmPosition(void)
143
{
144
RSDK_THIS(MetalArm);
145
146
int32 x = 0x2400 * RSDK.Cos512((self->armAngle.x >> 16)) + self->position.x;
147
int32 y = 0x2400 * RSDK.Sin512((self->armAngle.x >> 16)) + self->position.y;
148
149
Vector2 armPos;
150
armPos.x = x + 0x3800 * RSDK.Cos512((self->armAngle.x + self->armAngle.y) >> 16);
151
armPos.y = y + 0x3800 * RSDK.Sin512((self->armAngle.x + self->armAngle.y) >> 16);
152
153
return armPos;
154
}
155
156
void MetalArm_CheckPlayerCollisions(void)
157
{
158
RSDK_THIS(MetalArm);
159
160
foreach_active(Player, player)
161
{
162
int32 playerID = RSDK.GetEntitySlot(player);
163
164
if ((1 << playerID) & self->stoodPlayers) {
165
player->position.x += self->moveOffset.x;
166
player->position.y += self->moveOffset.y;
167
player->position.y += 0x10000;
168
}
169
170
if (!Player_CheckCollisionPlatform(player, self, &self->hitbox))
171
self->stoodPlayers &= ~(1 << playerID);
172
else
173
self->stoodPlayers |= 1 << playerID;
174
}
175
}
176
177
void MetalArm_State_Idle(void)
178
{
179
RSDK_THIS(MetalArm);
180
181
if ((self->stoodPlayers & 1)) {
182
self->moveTimer = 0;
183
self->holdTimer = 0;
184
self->active = ACTIVE_NORMAL;
185
self->state = MetalArm_State_MoveToHold;
186
}
187
}
188
189
void MetalArm_State_MoveToHold(void)
190
{
191
RSDK_THIS(MetalArm);
192
193
if (self->moveTimer >= MAX(self->durationA, self->durationB)) {
194
self->holdTimer = 0;
195
self->state = MetalArm_State_Holding;
196
}
197
else {
198
self->moveTimer++;
199
}
200
}
201
202
void MetalArm_State_Holding(void)
203
{
204
RSDK_THIS(MetalArm);
205
206
if (self->stoodPlayers & 1) {
207
self->holdTimer = 0;
208
}
209
else {
210
if (self->holdTimer >= self->holdDuration) {
211
self->state = MetalArm_State_MoveToStart;
212
}
213
else {
214
self->holdTimer++;
215
}
216
}
217
}
218
219
void MetalArm_State_MoveToStart(void)
220
{
221
RSDK_THIS(MetalArm);
222
223
if (self->moveTimer <= 0) {
224
self->state = MetalArm_State_Idle;
225
self->active = ACTIVE_BOUNDS;
226
}
227
else {
228
self->moveTimer--;
229
}
230
}
231
232
#if GAME_INCLUDE_EDITOR
233
void MetalArm_EditorDraw(void)
234
{
235
RSDK_THIS(MetalArm);
236
237
MetalArm_Create(NULL);
238
239
self->startPos.x = self->position.x;
240
self->startPos.y = self->position.y;
241
self->armAngle.x = self->startAngleA << 16;
242
self->armAngle.y = self->startAngleB << 16;
243
self->armPosition = MetalArm_GetArmPosition();
244
245
MetalArm_Draw();
246
}
247
248
void MetalArm_EditorLoad(void) { MetalArm->aniFrames = RSDK.LoadSpriteAnimation("TMZ1/MetalArm.bin", SCOPE_STAGE); }
249
#endif
250
251
void MetalArm_Serialize(void)
252
{
253
RSDK_EDITABLE_VAR(MetalArm, VAR_INT32, startAngleA);
254
RSDK_EDITABLE_VAR(MetalArm, VAR_INT32, startAngleB);
255
RSDK_EDITABLE_VAR(MetalArm, VAR_INT32, endAngleA);
256
RSDK_EDITABLE_VAR(MetalArm, VAR_INT32, endAngleB);
257
RSDK_EDITABLE_VAR(MetalArm, VAR_INT32, durationA);
258
RSDK_EDITABLE_VAR(MetalArm, VAR_INT32, durationB);
259
RSDK_EDITABLE_VAR(MetalArm, VAR_INT32, holdDuration);
260
}
261
262