Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-CD-2011-Script-Decompilation
Path: blob/main/Scripts/Global/StageSetup.txt
1319 views
1
//---------------Sonic CD Stage Setup Script------------------//
2
//--------Scripted by Christian Whitehead 'The Taxman'--------//
3
//-------Unpacked By Rubberduckycooly's Script Unpacker-------//
4
5
// Aliases
6
#alias Object[23].Priority : StageSetup.Priority
7
#alias Object[24].Priority : HUD.Priority
8
#alias Object[24].DrawOrder : HUD.DrawOrder
9
#alias Object[24].PropertyValue : HUD.CurrentTimePeriod
10
11
// Badnik Alias
12
#alias Object.PropertyValue : Badnik.Quality
13
14
// Player Aliases
15
#alias Player.Value0 : Player.Rings
16
#alias Player.Value6 : Player.MinRollSpeed
17
18
// Flower States
19
#alias 1 : FLOWER_SEED_FALL
20
21
// Future post State
22
#alias 2 : FUTUREPOST_USED
23
24
// Past Post State
25
#alias 2 : PASTPOST_USED
26
27
// Monitor States
28
#alias 2 : BROKENMONITOR_BLANK
29
30
// Priority
31
#alias 1 : PRIORITY_ACTIVE
32
33
// Warp Destination
34
#alias 0 : WARP_NONE
35
36
// Game Mode Aliases
37
#alias 2 : MODE_TIMEATTACK
38
39
// Player
40
#alias 0 : PLAYER_SONIC_A
41
42
// Control Mode
43
#alias -1 : CONTROLMODE_NONE
44
45
// Soundtrack
46
#alias 0 : OST_JP
47
48
// Global SFX
49
#alias 20 : SFX_G_1UP
50
#alias 21 : SFX_G_ACHIEVEMENT
51
52
// Track List
53
#alias 0 : TRACK_STAGE
54
#alias 1 : TRACK_ACTFINISH
55
#alias 2 : TRACK_INVINCIBILITY
56
#alias 3 : TRACK_SPEEDSHOES
57
#alias 4 : TRACK_BOSS
58
#alias 5 : TRACK_GAMEOVER
59
60
61
// Time Period Aliases
62
#alias 0 : TIME_PRESENT
63
#alias 1 : TIME_PAST
64
#alias 2 : TIME_GOOD_FUTURE
65
#alias 3 : TIME_BAD_FUTURE
66
67
// Function declarations
68
#function StageSetup_CheckGoodFuture
69
#function StageSetup_SaveStageState
70
#function StageSetup_LoadStageState
71
72
73
function StageSetup_CheckGoodFuture
74
if Good_Future == true
75
// Destroying the transporters in the past will get rid of any badnik with bad condition in the present
76
if Badnik.Quality > 0
77
ResetObjectEntity(Object.EntityNo, Flower_TypeNo, 0, Object.XPos, Object.YPos)
78
Object.DrawOrder = 4
79
Object.State = FLOWER_SEED_FALL
80
else
81
// And get rid entirely of them in the past and good future
82
if HUD.CurrentTimePeriod > 0
83
ResetObjectEntity(Object.EntityNo, Flower_TypeNo, 0, Object.XPos, Object.YPos)
84
Object.DrawOrder = 4
85
Object.State = FLOWER_SEED_FALL
86
end if
87
end if
88
end if
89
end function
90
91
92
function StageSetup_SaveStageState
93
ArrayPos0 = 32
94
ArrayPos1 = 7168
95
96
TempValue1 = HUD.CurrentTimePeriod
97
TempValue1 += 4
98
// Checks and saves:
99
// Anything that doesn't exist anymore
100
// Broken Monitors
101
// Used Warp Signs
102
// Anything that transformed into a flower
103
while ArrayPos0 < 1056
104
if Object[ArrayPos0].Type == TypeName[Blank Object]
105
SetBit(SaveRAM[ArrayPos1], HUD.CurrentTimePeriod, true)
106
else
107
if Object[ArrayPos0].Type == TypeName[Broken Monitor]
108
SetBit(SaveRAM[ArrayPos1], HUD.CurrentTimePeriod, true)
109
else
110
if Object[ArrayPos0].Type == TypeName[Future Post]
111
if Object[ArrayPos0].State == FUTUREPOST_USED
112
SetBit(SaveRAM[ArrayPos1], HUD.CurrentTimePeriod, true)
113
else
114
SetBit(SaveRAM[ArrayPos1], HUD.CurrentTimePeriod, false)
115
end if
116
else
117
if Object[ArrayPos0].Type == TypeName[Past Post]
118
if Object[ArrayPos0].State == PASTPOST_USED
119
SetBit(SaveRAM[ArrayPos1], HUD.CurrentTimePeriod, true)
120
else
121
SetBit(SaveRAM[ArrayPos1], HUD.CurrentTimePeriod, false)
122
end if
123
else
124
SetBit(SaveRAM[ArrayPos1], HUD.CurrentTimePeriod, false)
125
if Object[ArrayPos0].Type == Flower_TypeNo
126
SetBit(SaveRAM[ArrayPos1], TempValue1, true)
127
else
128
SetBit(SaveRAM[ArrayPos1], TempValue1, false)
129
end if
130
end if
131
end if
132
end if
133
end if
134
ArrayPos0++
135
ArrayPos1++
136
loop
137
end function
138
139
140
function StageSetup_LoadStageState
141
ArrayPos0 = 32
142
ArrayPos1 = 7168
143
144
TempValue1 = HUD.CurrentTimePeriod
145
TempValue1 += 4
146
// Checks and loads:
147
// Anything that doesn't exist anymore
148
// Broken Monitors
149
// Used Warp Signs
150
// Anything that transformed into a flower
151
while ArrayPos0 < 1056
152
if Object[ArrayPos0].Type == TypeName[Ring]
153
GetBit(TempValue0, SaveRAM[ArrayPos1], HUD.CurrentTimePeriod)
154
if TempValue0 == true
155
Object[ArrayPos0].Type = TypeName[Blank Object]
156
end if
157
else
158
if Object[ArrayPos0].Type == TypeName[Monitor]
159
GetBit(TempValue0, SaveRAM[ArrayPos1], HUD.CurrentTimePeriod)
160
if TempValue0 == true
161
Object[ArrayPos0].Type = TypeName[Broken Monitor]
162
Object[ArrayPos0].State = BROKENMONITOR_BLANK
163
end if
164
else
165
if Object[ArrayPos0].Type == TypeName[Future Post]
166
GetBit(TempValue0, SaveRAM[ArrayPos1], HUD.CurrentTimePeriod)
167
if TempValue0 == true
168
Object[ArrayPos0].State = FUTUREPOST_USED
169
end if
170
else
171
if Object[ArrayPos0].Type == TypeName[Past Post]
172
GetBit(TempValue0, SaveRAM[ArrayPos1], HUD.CurrentTimePeriod)
173
if TempValue0 == true
174
Object[ArrayPos0].State = PASTPOST_USED
175
end if
176
else
177
GetBit(TempValue0, SaveRAM[ArrayPos1], TempValue1)
178
if TempValue0 == true
179
Object[ArrayPos0].Type = TypeName[Blank Object]
180
end if
181
end if
182
end if
183
end if
184
end if
185
ArrayPos0++
186
ArrayPos1++
187
loop
188
end function
189
190
191
sub ObjectMain
192
Ring.AniCount++
193
if Ring.AniCount == 4
194
Ring.AniCount = 0
195
Ring.Frame++
196
Ring.Frame &= 7
197
end if
198
199
if Options.GameMode != MODE_TIMEATTACK
200
if Player.Score >= Player.ScoreBonus
201
202
#platform: Use_Origins
203
if game.coinMode == false
204
Player.Lives++
205
else
206
game.callbackParam0 = 1 // Set the amount of coins to add
207
EngineCallback(NOTIFY_ADD_COIN)
208
end if
209
#endplatform
210
211
#platform: Use_Standalone
212
Player.Lives++
213
#endplatform
214
215
Player.ScoreBonus += 50000
216
if Stage.PlayerListPos == PLAYER_SONIC_A // PLAYER_SONIC in origins
217
PlaySfx(SFX_G_1UP, false)
218
else
219
PlaySfx(SFX_G_ACHIEVEMENT, false)
220
end if
221
end if
222
end if
223
224
Oscillation++
225
Oscillation &= 511
226
227
#platform: Use_Origins
228
if Stage.TimeEnabled == true
229
if game.coinMode == false
230
CheckEqual(game.timeOver, false)
231
TempValue0 = CheckResult
232
CheckEqual(Stage.Minutes, 10)
233
TempValue0 &= CheckResult
234
if TempValue0 != false
235
if game.playMode == BOOT_PLAYMODE_CLASSIC
236
Stage.Minutes = 9
237
Stage.Seconds = 59
238
Stage.MilliSeconds = 99
239
Stage.TimeEnabled = false
240
end if
241
242
if game.playMode != BOOT_PLAYMODE_BOSSRUSH
243
Object[0].Type = TypeName[Player Object]
244
CallFunction(Player_Kill)
245
end if
246
end if
247
end if
248
end if
249
250
if game.forceKillPlayer == true
251
game.forceKillPlayer = false
252
CheckEqual(Player.State, Player_State_Death)
253
TempValue0 = CheckResult
254
CheckEqual(Player.State, Player_State_Drown)
255
CheckResult |= TempValue0
256
if CheckResult == false
257
Object[0].Type = TypeName[Player Object]
258
CallFunction(Player_Kill)
259
end if
260
end if
261
#endplatform
262
263
#platform: Use_Standalone
264
if Stage.TimeEnabled == true
265
if Stage.Minutes == 10
266
Stage.Minutes = 9
267
Stage.Seconds = 59
268
Stage.MilliSeconds = 99
269
Stage.TimeEnabled = false
270
Object[0].Type = TypeName[Player Object]
271
CallFunction(Player_Kill)
272
end if
273
end if
274
#endplatform
275
end sub
276
277
278
sub ObjectPlayerInteraction
279
TempValue0 = Player.CollisionLeft
280
TempValue0 <<= 16
281
TempValue0 += Player.XPos
282
283
TempValue1 = Stage.XBoundary1
284
TempValue1 <<= 16
285
if TempValue0 < TempValue1
286
if Player.Right == true
287
Player.XVelocity = 0x10000
288
Player.Speed = 0x10000
289
else
290
Player.XVelocity = 0
291
Player.Speed = 0
292
end if
293
Player.XPos = TempValue1
294
TempValue0 = Player.CollisionLeft
295
TempValue0 <<= 16
296
Player.XPos -= TempValue0
297
end if
298
// Death Boundary
299
TempValue0 = Player.CollisionBottom
300
TempValue0 <<= 16
301
TempValue0 += Player.YPos
302
if TempValue0 > Stage.DeathBoundary
303
CallFunction(Player_Kill)
304
end if
305
end sub
306
307
308
sub ObjectStartup
309
if Options.Soundtrack == OST_JP
310
SetMusicTrack("JP/ZoneComplete.ogg", TRACK_ACTFINISH, 0)
311
SetMusicTrack("JP/Invincibility.ogg", TRACK_INVINCIBILITY, 0)
312
SetMusicTrack("JP/SpeedShoes.ogg", TRACK_SPEEDSHOES, 0)
313
SetMusicTrack("JP/Boss.ogg", TRACK_BOSS, 1)
314
SetMusicTrack("JP/GameOver.ogg", TRACK_GAMEOVER, 0)
315
else
316
SetMusicTrack("US/ZoneComplete.ogg", TRACK_ACTFINISH, 0)
317
SetMusicTrack("US/Invincibility.ogg", TRACK_INVINCIBILITY, 0)
318
SetMusicTrack("US/SpeedShoes.ogg", TRACK_SPEEDSHOES, 0)
319
SetMusicTrack("US/Boss.ogg", TRACK_BOSS, 196526)
320
SetMusicTrack("US/GameOver.ogg", TRACK_GAMEOVER, 0)
321
end if
322
323
Stage.PauseEnabled = false
324
Screen.CameraStyle = Options.OriginalControls
325
Screen.CameraTarget = 0
326
327
Stage.DeathBoundary = Stage.YBoundary2
328
Stage.DeathBoundary <<= 16
329
Object[23].Type = TypeName[Stage Setup]
330
StageSetup.Priority = PRIORITY_ACTIVE
331
332
ArrayPos0 = 32
333
while ArrayPos0 < 1056
334
if Object[ArrayPos0].Type == TypeName[Stage Setup]
335
ResetObjectEntity(ArrayPos0, TypeName[Blank Object], 0, 0, 0)
336
end if
337
ArrayPos0++
338
loop
339
340
ArrayPos0 = 32
341
while ArrayPos0 < 1056
342
if Object[ArrayPos0].Type == TypeName[HUD] // Delete extra HUD objects and set the correct one
343
Object[ArrayPos0].Type = TypeName[Blank Object]
344
Object[24].Type = TypeName[HUD]
345
HUD.Priority = PRIORITY_ACTIVE
346
HUD.DrawOrder = 6
347
HUD.CurrentTimePeriod = Object[ArrayPos0].PropertyValue
348
end if
349
ArrayPos0++
350
loop
351
352
// In origins this is reset by player object so, goodbye!
353
#platform: Use_Standalone
354
Warp.Timer = 0
355
#endplatform
356
if Warp.XPos > 0 // if the player comes from a time travel, load the warp values
357
// Reload the previous player stats
358
Player.XPos = Warp.XPos
359
Player.YPos = Warp.YPos
360
Player.XVelocity = Warp.XVelocity
361
Player.YVelocity = Warp.YVelocity
362
Player.Speed = Warp.Speed
363
Player.CollisionMode = Warp.CollisionMode
364
Player.Gravity = Warp.Gravity
365
Player.State = Warp.State
366
Player.Animation = Warp.Animation
367
Player.Frame = Warp.PlayerFrame
368
Player.Angle = Warp.Angle
369
Player.Rings = Warp.Rings
370
Player.MinRollSpeed = Warp.MinRollSpeed
371
372
// Reload the previous stage time
373
Stage.MilliSeconds = Rec_Milliseconds
374
Stage.Seconds = Rec_Seconds
375
Stage.Minutes = Rec_Minutes
376
377
CallFunction(StageSetup_LoadStageState)
378
else
379
ArrayPos0 = 7168
380
while ArrayPos0 < 8192
381
SaveRAM[ArrayPos0] = 0
382
ArrayPos0++
383
loop
384
Player.Direction = FACING_RIGHT
385
Player.Left = false
386
Player.Right = true
387
Player.ControlMode = CONTROLMODE_NONE
388
Player.Speed = 0
389
Player.Animation = ANI_STOPPED
390
end if
391
392
if HUD.CurrentTimePeriod == TIME_GOOD_FUTURE
393
Good_Future = true
394
Transporter_Destroyed = true
395
end if
396
397
if SpecialStage.TimeStones == 127 // 0b1111111, each '1' bit represents an obtained time stone
398
Good_Future = true
399
Transporter_Destroyed = true
400
end if
401
402
Warp.Destination = WARP_NONE
403
Ring.ExtraLife = 100
404
Player.RoofBarrier = false
405
end sub
406
407
408
// ========================
409
// Editor Subs
410
// ========================
411
412
sub RSDKDraw
413
DrawSprite(0)
414
end sub
415
416
417
sub RSDKLoad
418
LoadSpriteSheet("Global/Display.gif")
419
SpriteFrame(-16, -16, 32, 32, 1, 143) // #0 - "Script" Icon
420
421
SetVariableAlias(ALIAS_VAR_PROPVAL, "unused")
422
end sub
423
424
425
// ========================
426
// Editor Helpers
427
// ========================
428
429
// All the following are only to be used from Editor subs, using these in the actual game itself won't do much
430
// None of these exist in the original game, they're all custom to the decomp
431
432
#function EditorHelpers_DrawHitbox
433
#function EditorHelpers_DrawX
434
#function EditorHelpers_FindTimePeriod
435
436
437
function EditorHelpers_DrawHitbox
438
439
#platform: Editor
440
441
// This function is called in order to draw an object's hitbox, as a white
442
// Editor.DrawingOverlay isn't set here
443
444
// Preconditions:
445
// - Object.XPos and Object.YPos are the position for the hitbox to be centered around
446
// - TempValue0 is the left hitbox size
447
// - TempValue1 is the top hitbox size
448
// - TempValue2 is the right hitbox size
449
// - TempValue3 is the bottom hitbox size
450
// - All these values are to be positive
451
452
// Get the base 1:1 position of the object
453
TempValue4 = Object.iXPos
454
TempValue5 = Object.iYPos
455
456
// Move to its top left corner
457
TempValue4 -= TempValue0
458
TempValue5 -= TempValue1
459
460
// Get the hitbox's total width and height
461
TempValue2 += TempValue0
462
TempValue3 += TempValue1
463
464
// Turning iPos into normal Pos
465
TempValue4 <<= 16
466
TempValue5 <<= 16
467
468
DrawRectOutline(TempValue4, TempValue5, TempValue2, TempValue3, 255, 255, 0, 255)
469
470
#endplatform
471
472
end function
473
474
475
function EditorHelpers_DrawX
476
477
#platform: Editor
478
479
// This function is called to draw a red X, just for when you wanna show something's *really* wrong
480
// Editor.DrawingOverlay isn't set here, it's expected to be set (or ignored) by the Object calling this function
481
482
// Preconditions:
483
// - TempValue0 and TempValue1 are the position for the X to be centered around, in world-space
484
485
// Left
486
TempValue2 = TempValue0
487
TempValue2 -= 0x100000
488
489
// Right
490
TempValue3 = TempValue0
491
TempValue3 += 0x100000
492
493
// Top
494
TempValue4 = TempValue1
495
TempValue4 -= 0x100000
496
497
// Bottom
498
TempValue5 = TempValue1
499
TempValue5 += 0x100000
500
501
// TL-BR
502
DrawLine(TempValue2, TempValue4, TempValue3, TempValue5, 255, 0, 0)
503
504
// TR-BL
505
DrawLine(TempValue3, TempValue4, TempValue2, TempValue5, 255, 0, 0)
506
507
#endplatform
508
509
end function
510
511
512
function EditorHelpers_FindTimePeriod
513
514
#platform: Editor
515
516
// This function is called in order to get the current Time Period
517
// Do note that this is inaccurate to how the game actually handles it, but since
518
// we can't look at the HUD's property value instead we have to estimate based on the current stage's folder
519
520
// Postconditions:
521
// - CheckResult holds the current time period
522
// - If the current folder's name doesn't end in ABCD then Present time period will be assumed
523
524
TempValue0 = TIME_PRESENT
525
526
CheckCurrentStageFolder("B")
527
SetBit(TempValue0, 0, CheckResult)
528
529
CheckCurrentStageFolder("C")
530
SetBit(TempValue0, 1, CheckResult)
531
532
CheckCurrentStageFolder("D")
533
CheckResult *= TIME_BAD_FUTURE
534
TempValue0 += CheckResult
535
536
CheckResult = TempValue0
537
538
#endplatform
539
540
end function
541
542