Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-CD-2011-Script-Decompilation
Path: blob/main/Scripts/Special/Sonic.txt
1319 views
1
//-------------------Sonic CD Sonic Script--------------------//
2
//--------Scripted by Christian Whitehead 'The Taxman'--------//
3
//-------Unpacked By Rubberduckycooly's Script Unpacker-------//
4
5
// Aliases
6
7
// These are three sets of aliases, this object is rather inconsistent in its variable use, where sometimes
8
// normal Object.Values are used, but then other times, Player. values are used instead
9
// For the sake of simplicity, these have all been merged into a SSSonic. namespace via aliases
10
11
// Value aliases
12
#alias Object.Value0 : SSSonic.ZPos
13
#alias Object.Value1 : SSSonic.FrameLoop
14
#alias Object.Value2 : SSSonic.FrameEnd
15
#alias Object.Value3 : SSSonic.FrameTimer
16
#alias Object.Value4 : SSSonic.Unused // Completely unused
17
#alias Object.Value5 : SSSonic.ScreenDepth // Same use as other Special Stage objects, see Special Setup
18
#alias Object.Value6 : SSSonic.Timer
19
#alias Object.Value7 : SSSonic.Tilt
20
21
// Player. aliases
22
#alias Player.ControlMode : SSSonic.ControlMode
23
#alias Player.Speed : SSSonic.Speed
24
#alias Player.Angle : SSSonic.Angle
25
#alias Player.XPos : SSSonic.XPos
26
#alias Player.YPos : SSSonic.YPos
27
#alias Player.ScreenXPos : SSSonic.ScreenXPos
28
#alias Player.ScreenYPos : SSSonic.ScreenYPos
29
#alias Player.YVelocity : SSSonic.YVelocity
30
31
// Object. aliases
32
#alias Object.Type : SSSonic.Type
33
#alias Object.Priority : SSSonic.Priority
34
#alias Object.State : SSSonic.State
35
#alias Object.Frame : SSSonic.Frame
36
#alias Object.Direction : SSSonic.Direction
37
#alias Object.AnimationSpeed : SSSonic.AnimationSpeed
38
39
// State aliases
40
#alias 0 : SSSONIC_INTROPOSE
41
#alias 1 : SSSONIC_INTROTURNAROUND
42
#alias 2 : SSSONIC_WALKING
43
#alias 3 : SSSONIC_JUMPING
44
#alias 4 : SSSONIC_SPEEDBOOSTER
45
#alias 5 : SSSONIC_FAN
46
#alias 6 : SSSONIC_TRIPPED
47
#alias 7 : SSSONIC_SPEEDSHOESRUN
48
#alias 8 : SSSONIC_FINISHSTAND
49
#alias 9 : SSSONIC_CAMERAPAN
50
#alias 10 : SSSONIC_STONEGRABBED
51
#alias 11 : SSSONIC_SPRING
52
53
// Animation aliases
54
// Most are divided into three parts where there's the animation's start, its loop point, and its end
55
// This is to match with how this Object animates itself, check out Sonic_ProcessAnimation for more info
56
57
#alias 1 : ANI_STANDING_START
58
// This standing animation doesn't, well, animate, so no extended aliases needed here
59
60
#alias 2 : ANI_FACINGAHEAD_START
61
#alias 4 : ANI_FACINGAHEAD_LOOP
62
#alias 4 : ANI_FACINGAHEAD_END
63
64
#alias 5 : ANI_INTROPOSE_START
65
#alias 5 : ANI_INTROPOSE_LOOP
66
#alias 8 : ANI_INTROPOSE_END
67
68
#alias 9 : ANI_WALKING_START
69
#alias 9 : ANI_WALKING_LOOP
70
#alias 14 : ANI_WALKING_END
71
72
#alias 39 : ANI_JUMPING_START
73
#alias 39 : ANI_JUMPING_LOOP
74
#alias 42 : ANI_JUMPING_END
75
76
#alias 43 : ANI_BRAKING_START
77
#alias 43 : ANI_BRAKING_LOOP
78
#alias 47 : ANI_BRAKING_END
79
80
#alias 48 : ANI_FAN_START
81
#alias 48 : ANI_FAN_LOOP
82
#alias 53 : ANI_FAN_END
83
84
#alias 54 : ANI_TRIP_START
85
#alias 54 : ANI_TRIP_LOOP
86
#alias 76 : ANI_TRIP_END
87
88
#alias 77 : ANI_RUN_START
89
#alias 77 : ANI_RUN_LOOP
90
#alias 80 : ANI_RUN_END
91
92
// HUD Aliases
93
#alias Object.Value0 : HUD.UFOsCount
94
#alias Object.Value3 : HUD.Rings
95
#alias Object.Value4 : HUD.LastUFOType
96
#alias Object.Value5 : HUD.SpeedShoes
97
98
// Ring Aliases
99
#alias Object.Value0 : Ring.ZPos
100
#alias Object.Value1 : Ring.XVelocity
101
#alias Object.Value2 : Ring.YVelocity
102
#alias Object.Value3 : Ring.ZVelocity
103
104
// Touch Control Aliases
105
// This value is used to store if the jump button was touched last frame, to help differenciate new taps from old holds
106
#alias Object.Value7 : TouchControls.TouchJump
107
108
// Generic Object Alias
109
// (Here it's only used for the Water Splash object, but it does apply to every SS game object as well)
110
#alias Object.Value5 : Object.ScreenDepth
111
112
// Player aliases
113
#alias 0 : PLAYER_SONIC_A
114
#alias 1 : PLAYER_TAILS_A
115
116
// Global SFX
117
#alias 0 : SFX_G_JUMP
118
#alias 4 : SFX_G_LOSERINGS
119
#alias 11 : SFX_G_SPRING
120
#alias 24 : SFX_G_FLYING
121
#alias 25 : SFX_G_TIRED
122
#alias 27 : SFX_G_SELECT
123
124
// Stage SFX
125
#alias 2 : SFX_S_BUMPER2
126
#alias 3 : SFX_S_LARGEBOOSTER
127
#alias 4 : SFX_S_SMALLBOOSTER
128
#alias 6 : SFX_S_FAN
129
130
// ControlMode Aliases
131
#alias -1 : CONTROLMODE_NONE
132
#alias 0 : CONTROLMODE_NORMAL
133
134
// Engine Callback Aliases
135
#alias 13 : CALLBACK_PAUSE_REQUESTED
136
137
// Engine Messages
138
#alias 2 : MESSAGE_LOSTFOCUS
139
140
// Priority
141
#alias 1 : PRIORITY_ACTIVE
142
#alias 2 : PRIORITY_ALWAYS
143
144
// Tile Layer types
145
#alias 3 : LAYER_3DFLOOR
146
147
// Tile Info
148
#alias 1 : TILEINFO_DIRECTION
149
#alias 6 : TILEINFO_ANGLEA
150
151
// Stage Finish Aliases
152
#alias Object.PropertyValue : Object.ResultsType
153
154
#alias 1 : STAGEFINISH_T_STONEOBTAINED
155
156
157
function Sonic_ProcessPlayer
158
159
if Options.AttractMode == false
160
#platform: Mobile
161
// Mobile has a lot more checks here than standard, especially because of the touchscreen, so it's just its own separate part here
162
163
if Options.TouchControls == true
164
if SSSonic.ControlMode == CONTROLMODE_NORMAL
165
CheckTouchRect(0, 96, Screen.CenterX, Screen.YSize)
166
if CheckResult > -1
167
168
// Move the current touch screen array pos to the one found by CheckTouchRect
169
ArrayPos0 = CheckResult
170
171
// Move its XPos within range
172
TempValue0 = TouchScreen[ArrayPos0].XPos
173
TempValue0 -= Options.DPadX
174
175
// And move its YPos within range too
176
TempValue1 = TouchScreen[ArrayPos0].YPos
177
TempValue1 -= 192
178
179
// Find the arctan from the value pair and shift it a bit to match with one of four directions
180
ATan2(TempValue2, TempValue0, TempValue1)
181
TempValue2 += 32
182
TempValue2 &= 255
183
TempValue2 >>= 6
184
185
// Take the result and match it with the corresponding direction of the DPad
186
switch TempValue2
187
case 0
188
KeyDown[1].Right = true
189
break
190
191
case 1
192
KeyDown[1].Down = true
193
break
194
195
case 2
196
KeyDown[1].Left = true
197
break
198
199
case 3
200
KeyDown[1].Up = true
201
break
202
203
end switch
204
end if
205
206
// Check if the jump button was pressed
207
CheckTouchRect(Screen.CenterX, 166, Screen.XSize, 240)
208
209
if CheckResult > -1
210
KeyDown[1].ButtonA = true
211
end if
212
213
// If the jump button wasn't held last frame, then that means the current touch is a new press
214
if TouchControls[25].TouchJump == false
215
KeyPress[1].ButtonA |= KeyDown[1].ButtonA
216
end if
217
TouchControls[25].TouchJump = KeyDown[1].ButtonA
218
219
// If the Pause Menu doesn't currently exist...
220
if Object[9].Type == TypeName[Blank Object]
221
222
// Check if the touch screen's pause button was pressed
223
CheckTouchRect(240, 0, Screen.XSize, 40)
224
if CheckResult > -1
225
226
// Pause the entire stage (including its objects)
227
Stage.State = STAGE_PAUSED
228
229
// Pause (but don't fully stop) the music
230
PauseMusic()
231
232
// Play the menu SFX
233
PlaySfx(SFX_G_SELECT, false)
234
235
// And stop the currently playing game SFX, if any
236
StopSfx(SFX_G_FLYING)
237
StopSfx(SFX_G_TIRED)
238
239
// Spawn the Pause Menu in reserved object slot 9
240
Object[9].Type = TypeName[Pause Menu]
241
242
// Give it a high draw order to make it draw ontop of everything
243
// The HUD object shares this same priority, but since the Pause Menu is further down the object list it'll still get drawn on top
244
Object[9].DrawOrder = 6
245
246
// Give the Pause Menu object the special PRIORITY_ALWAYS priority in order to keep it running while the stage is paused
247
Object[9].Priority = PRIORITY_ALWAYS
248
249
// Disable Frame Skip here, not too much is happening while paused anyway
250
if Engine.FrameSkipTimer > -1
251
Engine.FrameSkipTimer = -1
252
end if
253
254
// And set the floor to be of the actual "3d floor" type
255
// The floor was indeed 3d already, but this disables High Quality mode to help save on resources while paused
256
TileLayer[0].Type = LAYER_3DFLOOR
257
258
end if
259
260
// Check if game focus was lost
261
// (As in, did the player exit the app?)
262
if Engine.Message == MESSAGE_LOSTFOCUS
263
264
// Pause the entire stage (including its objects)
265
Stage.State = STAGE_PAUSED
266
267
// Pause (but don't fully stop) the music
268
PauseMusic()
269
270
// Play the menu SFX
271
PlaySfx(SFX_G_SELECT, false)
272
273
// And stop game SFX from currently playing, if there are any
274
StopSfx(SFX_G_FLYING)
275
StopSfx(SFX_G_TIRED)
276
277
// Spawn the Pause Menu in reserved object slot 9
278
Object[9].Type = TypeName[Pause Menu]
279
280
// Give it a high draw order to make it draw ontop of everything
281
// The HUD object shares this same priority, but since the Pause Menu is further down the object list it'll still get drawn on top
282
Object[9].DrawOrder = 6
283
284
// Give the Pause Menu object the special PRIORITY_ALWAYS priority in order to keep it running while the stage is paused
285
Object[9].Priority = PRIORITY_ALWAYS
286
287
// Disable Frame Skip, it's not like much is happening while paused anyway
288
if Engine.FrameSkipTimer > -1
289
Engine.FrameSkipTimer = -1
290
end if
291
292
// This sets the floor to the "3d floor" type, in order to disable High Quality rendering mode
293
TileLayer[0].Type = LAYER_3DFLOOR
294
295
end if
296
end if
297
end if
298
else
299
// Using physical controls
300
301
if SSSonic.ControlMode == CONTROLMODE_NORMAL
302
303
// Check that no Pause Menu object exists yet
304
if Object[9].Type == TypeName[Blank Object]
305
306
// First check for the physical start button being pressed
307
if KeyPress[1].Start == true
308
309
// Clear the Start button state
310
// (This is here just to make sure "double-pauses" don't occur, where the game gets paused twice or more from a single pause button press)
311
KeyPress[1].Start = false
312
313
// Pause the entire stage (including its objects)
314
Stage.State = STAGE_PAUSED
315
316
// Don't stop the music, just pause it instead so that it can be resumed later
317
PauseMusic()
318
319
// Play the menu SFX as it pops out
320
PlaySfx(SFX_G_SELECT, false)
321
322
// And stop the other game SFX currently playing, if any
323
StopSfx(SFX_G_FLYING)
324
StopSfx(SFX_G_TIRED)
325
326
// Spawn the Pause Menu in reserved object slot 9
327
Object[9].Type = TypeName[Pause Menu]
328
329
// Give it a high draw order to make it's above everything else
330
// -> This draw order is shared with the HUD object too, but since the Pause Menu object slot (9) is
331
// further down the list than the HUD object slot (4), it'll still be drawn on top
332
Object[9].DrawOrder = 6
333
334
// And give the Pause Menu a special priority to make sure it'll keep on running while the stage is paused
335
Object[9].Priority = PRIORITY_ALWAYS
336
337
// Disable frame skip, pausing doesn't have much activity anyway
338
if Engine.FrameSkipTimer > -1
339
Engine.FrameSkipTimer = -1
340
end if
341
342
// Keep the floor as 3d, but as the lower quality version to stay efficient while paused
343
TileLayer[0].Type = LAYER_3DFLOOR
344
345
end if
346
347
// Then check if game focus was lost
348
// Meaning, did the player exit the app?
349
if Engine.Message == MESSAGE_LOSTFOCUS
350
351
// Pause the entire stage, along with all objects
352
Stage.State = STAGE_PAUSED
353
354
// Pause the music as well, not stopping it so that it can be resumed rather than restarted upon resuming the game
355
PauseMusic()
356
357
// Play the select SFX as the menu slides in
358
PlaySfx(SFX_G_SELECT, false)
359
360
// And stop game SFX that could be currently playing
361
StopSfx(SFX_G_FLYING)
362
StopSfx(SFX_G_TIRED)
363
364
// Spawn the Pause Menu in reserved object slot 9
365
Object[9].Type = TypeName[Pause Menu]
366
367
// Give it a high draw priority to make sure it draws above everything else
368
Object[9].DrawOrder = 6
369
370
// And give is a special update priority too, to make sure it'll persist during the stage's paused state
371
Object[9].Priority = PRIORITY_ALWAYS
372
373
// No frame skip here, no siree!
374
if Engine.FrameSkipTimer > -1
375
Engine.FrameSkipTimer = -1
376
end if
377
378
// The floor should already be 3d here, but make it a 3d floor again in order to exit High Quality mode while paused
379
TileLayer[0].Type = LAYER_3DFLOOR
380
381
end if
382
383
end if
384
end if
385
end if
386
#endplatform
387
388
#platform: Standard
389
// Standard doesn't need nearly as much code as mobile to handle its inputs,
390
// thanks to the lack of a touchscreen and other mobile things
391
392
if SSSonic.ControlMode == CONTROLMODE_NORMAL
393
394
// Make sure no Pause Menu object exists already
395
if Object[9].Type == TypeName[Blank Object]
396
if KeyPress[1].Start == true
397
398
// Clear the Start state in order to avoid "double-pauses" oddities
399
KeyPress[1].Start = false
400
401
// If the player was brought here from the Dev Menu, use the game-object version of the pause menu
402
if Options.DevMenuFlag == true
403
404
// Pause the stage, and all objects in it
405
Stage.State = STAGE_PAUSED
406
407
// Pause the music too, not fully stopping it so that it can be resumed later
408
PauseMusic()
409
410
// Play the menu SFX as it pops out from the side
411
PlaySfx(SFX_G_SELECT, false)
412
413
// And stop the game SFX, as well
414
StopSfx(SFX_G_FLYING)
415
StopSfx(SFX_G_TIRED)
416
417
// Spawn the Pause Menu object in reserved object slot 9
418
Object[9].Type = TypeName[Pause Menu]
419
420
// Give it a high draw order to insure it stays ontop of other objects
421
Object[9].DrawOrder = 6
422
423
// Give it a special priority so that it runs even during pauses, or else it'll just be frozen
424
Object[9].Priority = PRIORITY_ALWAYS
425
426
// The floor should already be 3d, this is actually a form of exiting High Quality mode
427
TileLayer[0].Type = LAYER_3DFLOOR
428
429
else
430
431
// In normal gameplay, call the engine's built-in pause menu
432
// (Although, do note, that with the fan-made engine decompilation of the game,
433
// this callback will just call the in-game Pause Menu anyway...)
434
EngineCallback(CALLBACK_PAUSE_REQUESTED)
435
436
end if
437
end if
438
end if
439
end if
440
#endplatform
441
442
// Assign all Player.* input values to their corresponding Input.* values
443
ProcessPlayerControl()
444
445
end if // Options.AttractMode == false
446
447
end function
448
449
450
function Sonic_HandlePause
451
452
// This function is only called while tripped, it's nearly identical to the normal pause function with the exception of control values not being set
453
// Don't really know why this exists, but there's probably some reason
454
455
if Options.AttractMode == false
456
#platform: Mobile
457
if SSSonic.ControlMode == CONTROLMODE_NORMAL
458
459
// Make sure the Pause Menu doesn't already exist
460
if Object[9].Type == TypeName[Blank Object]
461
462
// See if the player's touched the pause button
463
CheckTouchRect(240, 0, Screen.XSize, 40)
464
if CheckResult > -1
465
466
// Pause the entire stage, including its objects
467
Stage.State = STAGE_PAUSED
468
469
// And pause the music too
470
// Not completely stopping the music though, since it'll possibly resumed later
471
PauseMusic()
472
473
// SFX
474
PlaySfx(SFX_G_SELECT, false)
475
StopSfx(SFX_G_FLYING)
476
StopSfx(SFX_G_TIRED)
477
478
// Create the pause menu and initialise its values
479
// - Object Type of [Pause Menu] (of course)
480
// - High Draw Order, above other things like even the HUD
481
// - Priority of PRIORITY_ALWAYS, since the Object should continue running even while the stage is paused
482
Object[9].Type = TypeName[Pause Menu]
483
Object[9].DrawOrder = 6
484
Object[9].Priority = PRIORITY_ALWAYS
485
486
// Disable frameskip when paused
487
if Engine.FrameSkipTimer > -1
488
Engine.FrameSkipTimer = -1
489
end if
490
491
// Make the floor lower quality instead while paused, to be more efficient
492
TileLayer[0].Type = LAYER_3DFLOOR
493
494
end if
495
496
// Check if focus was lost (as in, the player exiting the game)
497
if Engine.Message == MESSAGE_LOSTFOCUS
498
499
// Pause the stage & music
500
Stage.State = STAGE_PAUSED
501
PauseMusic()
502
503
// Play the menu SFX as it appears
504
PlaySfx(SFX_G_SELECT, false)
505
506
// And stop some other game SFX, too
507
StopSfx(SFX_G_FLYING)
508
StopSfx(SFX_G_TIRED)
509
510
// Place the Pause Menu in reserved object slot 9
511
Object[9].Type = TypeName[Pause Menu]
512
Object[9].DrawOrder = 6
513
Object[9].Priority = PRIORITY_ALWAYS
514
515
// No frame skip needed when paused, not much really happens then anyway
516
if Engine.FrameSkipTimer > -1
517
Engine.FrameSkipTimer = -1
518
end if
519
520
// The floor should already be 3d, this is ensuring that it's drawn in standard quality rather than High Quality mode
521
TileLayer[0].Type = LAYER_3DFLOOR
522
523
end if
524
end if
525
end if
526
#endplatform
527
528
#platform: Standard
529
if SSSonic.ControlMode == CONTROLMODE_NORMAL
530
531
// Make sure the game isn't already paused via checking if the Pause Menu object exists or not
532
if Object[9].Type == TypeName[Blank Object]
533
if KeyPress[1].Start == true
534
535
// Disable start for this frame, this'll help with "double-pausing" cases
536
KeyPress[1].Start = false
537
538
// Give different pause menus depending on if the player was brought here from the Dev Menu
539
// (...but why?)
540
if Options.DevMenuFlag == true
541
542
// Pause the stage, this'll pause all the stage's objects too
543
Stage.State = STAGE_PAUSED
544
545
// and pause the stage's music, as well
546
PauseMusic()
547
548
// SFX dealings
549
PlaySfx(SFX_G_SELECT, false)
550
StopSfx(SFX_G_FLYING)
551
StopSfx(SFX_G_TIRED)
552
553
// Create the Pause Menu and set it up as needed
554
Object[9].Type = TypeName[Pause Menu]
555
Object[9].DrawOrder = 6
556
Object[9].Priority = PRIORITY_ALWAYS
557
558
// Turn the floor into low-quality 3d
559
TileLayer[0].Type = LAYER_3DFLOOR
560
561
else
562
563
// Call the engine's built-in pause menu
564
EngineCallback(CALLBACK_PAUSE_REQUESTED)
565
566
// It may be worth noting, though, that when using the fan decompilation of the game, the Pause Menu callback
567
// just becomes a roundabout way of calling the in-game Pause Menu Object anyway...
568
569
end if
570
end if
571
end if
572
end if
573
#endplatform
574
end if // Options.AttractMode == false
575
576
end function
577
578
579
function Sonic_HandleMovement
580
581
// Update Sonic's tilt based on what directions the player is currently holding
582
// Left takes priority over right, similarly to the maingame
583
if Player.Left == true
584
SSSonic.Tilt--
585
586
// Min tilt of -8
587
if SSSonic.Tilt < -8
588
SSSonic.Tilt = -8
589
end if
590
else
591
if Player.Right == true
592
SSSonic.Tilt++
593
594
// Max tilt of 8
595
if SSSonic.Tilt > 8
596
SSSonic.Tilt = 8
597
end if
598
else
599
// Neither left nor right are held, restore Sonic's tilt to neutral position
600
601
if SSSonic.Tilt > 0
602
SSSonic.Tilt--
603
end if
604
605
if SSSonic.Tilt < 0
606
SSSonic.Tilt++
607
end if
608
end if
609
end if
610
611
if Player.Left == true
612
SSSonic.Angle += 2
613
end if
614
615
if Player.Right == true
616
SSSonic.Angle -= 2
617
end if
618
619
if SSSonic.Angle < 0
620
// It's worth noting, Angle uses a 512-based value, which is why this is "allowed"
621
SSSonic.Angle += 512
622
end if
623
624
SSSonic.Angle &= 511
625
626
// Update movement based on the player's angle
627
628
Sin(TempValue0, SSSonic.Angle)
629
TempValue0 *= SSSonic.Speed
630
TempValue0 >>= 9
631
SSSonic.XPos += TempValue0
632
633
Cos(TempValue0, SSSonic.Angle)
634
TempValue0 *= SSSonic.Speed
635
TempValue0 >>= 9
636
SSSonic.ZPos += TempValue0
637
638
end function
639
640
641
function Sonic_ProcessAnimation
642
643
// This function is used for animating the object, here's a short overview of the values it uses
644
// (Frame values are in accordance with SpriteFrames set in ObjectStartup)
645
// -> SSSonic.AnimationSpeed is the speed at which Sonic should animate, it's added to his timer every frame
646
// -> SSSonic.FrameTimer is the timer used for animating Sonic, think of it akin to Object.AnimationTimer
647
// - The next frame is triggered whenever the value is 240 or above, the speed is controlled by SSSonic.AnimationSpeed
648
// - This doesn't get reset whenever the frame transitions, so keep that in mind too
649
// -> SSSonic.FrameEnd is the final frame of the animation
650
// -> SSSonic.FrameLoop is the loop point for the animation to go back to after reaching its end
651
// -> SSSonic.Frame is the frame to be displayed when drawing the object
652
653
// For each animation's corresponding values, check out the ANI_* aliases up above
654
655
SSSonic.FrameTimer += SSSonic.AnimationSpeed
656
657
if SSSonic.FrameTimer > 239
658
SSSonic.FrameTimer -= 240
659
660
SSSonic.Frame++
661
if SSSonic.Frame > SSSonic.FrameEnd
662
SSSonic.Frame = SSSonic.FrameLoop
663
end if
664
end if
665
666
end function
667
668
669
function Sonic_HandleBumperInteraction
670
671
// Preconditions:
672
// - TempValue0 is player's truncated XPos, and
673
// - TempValue1 is truncated ZPos
674
675
// Reset TempValue2, it's gonna get used as a bitfield for where bumper collision has been sensed,
676
// see below for which bits correspond to what "sensors"
677
TempValue2 = 0
678
679
// Check upper-left tile, uses the first bit
680
TempValue0 -= 8
681
TempValue1 -= 8
682
Get16x16TileInfo(CheckResult, TempValue0, TempValue1, TILEINFO_ANGLEA)
683
if CheckResult == 3
684
SetBit(TempValue2, 0, true)
685
end if
686
687
// Check upper-right tile, uses the second bit
688
TempValue0 += 16
689
Get16x16TileInfo(CheckResult, TempValue0, TempValue1, TILEINFO_ANGLEA)
690
if CheckResult == 3
691
SetBit(TempValue2, 1, true)
692
end if
693
694
// Check bottom left tile, uses the third bit
695
TempValue0 -= 16
696
TempValue1 += 16
697
Get16x16TileInfo(CheckResult, TempValue0, TempValue1, TILEINFO_ANGLEA)
698
if CheckResult == 3
699
SetBit(TempValue2, 2, true)
700
end if
701
702
// Check bottom right tile, uses the fourth bit
703
TempValue0 += 16
704
Get16x16TileInfo(CheckResult, TempValue0, TempValue1, TILEINFO_ANGLEA)
705
if CheckResult == 3
706
SetBit(TempValue2, 3, true)
707
end if
708
709
// Was any collision sensed?
710
if TempValue2 > 0
711
TempValue3 = SSSonic.Speed
712
TempValue3 += 0x10000
713
714
if SSSonic.Timer != 32
715
PlayStageSfx(SFX_S_BUMPER2, false)
716
end if
717
718
SSSonic.Timer = 32
719
720
// Jump to the corresponding collision match, each match is labelled in accordance with what sensors are triggered
721
722
switch TempValue2
723
case 1 // Upper left tile only
724
SSSonic.ScreenXPos = TempValue3
725
SSSonic.ScreenYPos = TempValue3
726
break
727
728
case 2 // Upper right tile only
729
SSSonic.ScreenXPos = TempValue3
730
SSSonic.ScreenYPos = TempValue3
731
FlipSign(SSSonic.ScreenXPos)
732
break
733
734
case 3 // Upper left tile and upper right
735
SSSonic.ScreenXPos = 0
736
SSSonic.ScreenYPos = TempValue3
737
break
738
739
case 4 // Bottom left tile only
740
SSSonic.ScreenXPos = TempValue3
741
SSSonic.ScreenYPos = TempValue3
742
FlipSign(SSSonic.ScreenYPos)
743
break
744
745
case 5 // Upper left tile and bottom left tile
746
SSSonic.ScreenXPos = TempValue3
747
SSSonic.ScreenYPos = 0
748
break
749
750
case 6 // Upper right tile and bottom left tile
751
case 7 // Upper left tile, upper right tile, and bottom left tile
752
SSSonic.ScreenXPos = TempValue3
753
SSSonic.ScreenYPos = TempValue3
754
break
755
756
case 8 // Bottom right tile only
757
case 14 // Upper right tile, bottom left tile, and bottom right tile
758
case 15 // Upper left tile, upper right tile, bottom left tile, and bottom right tile
759
SSSonic.ScreenXPos = TempValue3
760
SSSonic.ScreenYPos = TempValue3
761
FlipSign(SSSonic.ScreenXPos)
762
FlipSign(SSSonic.ScreenYPos)
763
break
764
765
case 9 // Upper left tile and bottom right tile
766
case 11 // Upper left tile, upper right tile, and bottom right tile
767
SSSonic.ScreenXPos = TempValue3
768
SSSonic.ScreenYPos = TempValue3
769
FlipSign(SSSonic.ScreenXPos)
770
break
771
772
case 10 // Upper right tile and bottom right tile
773
SSSonic.ScreenXPos = TempValue3
774
SSSonic.ScreenYPos = 0
775
FlipSign(SSSonic.ScreenXPos)
776
break
777
778
case 12 // Bottom left tile and bottom right tile
779
SSSonic.ScreenXPos = 0
780
SSSonic.ScreenYPos = TempValue3
781
FlipSign(SSSonic.ScreenYPos)
782
break
783
784
case 13 // Upper left tile, bottom left tile, and bottom right tile
785
SSSonic.ScreenXPos = TempValue3
786
SSSonic.ScreenYPos = TempValue3
787
FlipSign(SSSonic.ScreenYPos)
788
break
789
790
end switch
791
end if
792
793
end function
794
795
796
function Sonic_HandleTileInteractions
797
798
// Get the player's truncated XPos and ZPos for tile collision purposes
799
TempValue0 = SSSonic.XPos
800
TempValue0 >>= 16
801
TempValue1 = SSSonic.ZPos
802
TempValue1 >>= 16
803
804
// Pass the results over to the bumper function for bumping interations
805
CallFunction(Sonic_HandleBumperInteraction)
806
807
// Get the player's truncated XPos and ZPos for tile collision purposes (again)
808
TempValue0 = SSSonic.XPos
809
TempValue0 >>= 16
810
TempValue1 = SSSonic.ZPos
811
TempValue1 >>= 16
812
813
// Find what tile type the player is currently standing on
814
Get16x16TileInfo(CheckResult, TempValue0, TempValue1, TILEINFO_ANGLEA)
815
switch CheckResult
816
case 1
817
// Offroad tile, slow down Sonic and kick up some dust
818
Object[3].Type = TypeName[Dust Puff]
819
820
// Note that we're giving it a Draw Order of 4, not only does this make it draw above Sonic but
821
// more importantly this makes it so that it won't be treated as a 3d object
822
Object[3].DrawOrder = 4
823
824
if HUD[4].SpeedShoes == 0
825
if SSSonic.Speed > 0x28000
826
// While on dust without speed shoes, the maximum speed is 2.5 px per frame
827
SSSonic.Speed = 0x28000
828
end if
829
else
830
if SSSonic.Speed > 0x50000
831
// While on dust *with* speed shoes, the maximum speed is now bumped up to 5 px per frame
832
SSSonic.Speed = 0x50000
833
end if
834
end if
835
break
836
837
case 2
838
// Water tile, slow down the player and make a splash
839
Object[3].Type = TypeName[WaterSplash]
840
Object[3].DrawOrder = 4
841
842
// Give the water splash a Z Pos of just a tad bit lower than Sonic, in order to make it draw behind him
843
Object[3].ScreenDepth = 0x57FE
844
845
if HUD[4].SpeedShoes > 0
846
if SSSonic.Speed > 0x50000
847
// If Sonic has speed shoes, then enforce a max speed of 5px per frame
848
SSSonic.Speed = 0x50000
849
end if
850
end if
851
break
852
853
// 3, the value used by the bumper tiles, is skipped here
854
// It's handled in Sonic_HandleBumperInteraction instead, called above
855
856
case 4
857
// Ouch, a Cruncher!
858
// Make Sonic fall
859
860
SSSonic.State = SSSONIC_TRIPPED
861
SSSonic.Timer = 136
862
863
SSSonic.Frame = ANI_TRIP_START
864
SSSonic.FrameLoop = ANI_TRIP_LOOP
865
SSSonic.FrameEnd = ANI_TRIP_END
866
867
SSSonic.AnimationSpeed = 40
868
SSSonic.FrameTimer = 0
869
870
// Go to a speed of 1px per frame
871
SSSonic.Speed = 0x10000
872
873
if HUD[4].Rings > 0
874
PlaySfx(SFX_G_LOSERINGS, false)
875
876
// Cut the player's rings in half
877
TempValue0 = HUD[4].Rings
878
HUD[4].Rings >>= 1
879
880
// Find how many rings were lost
881
TempValue0 -= HUD[4].Rings
882
883
// Max of 8 rings can be dropped
884
if TempValue0 > 8
885
TempValue0 = 8
886
end if
887
888
// If Sonic has 0 rings now, then reset the UFO streak
889
if HUD[4].Rings == 0
890
HUD[4].LastUFOType = -1
891
endif
892
893
// Create all the dropped rings
894
while TempValue0 > 0
895
CreateTempObject(TypeName[Ring], 0, SSSonic.XPos, 0)
896
Object[TempObjectPos].Priority = PRIORITY_ACTIVE
897
898
// Move the Ring to Sonic
899
// (XPos is matched already via object spawning function)
900
Ring[TempObjectPos].ZPos = SSSonic.ZPos
901
902
// Randomise the X Velocity
903
Rand(TempValue1, 64)
904
TempValue1 -= 32
905
TempValue1 <<= 10
906
Ring[TempObjectPos].XVelocity = TempValue1
907
908
// Make the Rings fall in the general direction of Sonic, though
909
Sin(TempValue1, SSSonic.Angle)
910
TempValue1 *= 96
911
Ring[TempObjectPos].XVelocity += TempValue1
912
913
// Randomise the Y Velocity as well
914
Rand(TempValue1, 64)
915
TempValue1 += 32
916
TempValue1 <<= 12
917
Ring[TempObjectPos].YVelocity = TempValue1
918
919
// No further stuff needed for Y Velocity since there's really only one way for them to go - up!
920
921
// Randomise the Ring's Z Velocity too
922
Rand(TempValue1, 64)
923
TempValue1 -= 32
924
TempValue1 <<= 10
925
Ring[TempObjectPos].ZVelocity = TempValue1
926
927
// And make it somewhat match Sonic's direction
928
Cos(TempValue1, SSSonic.Angle)
929
TempValue1 *= 96
930
Ring[TempObjectPos].ZVelocity += TempValue1
931
932
TempValue0--
933
loop
934
end if
935
break
936
937
case 5
938
// Spring, send the player up, up, and away into the skies
939
SSSonic.State = SSSONIC_SPRING
940
SSSonic.Timer = 0
941
942
SSSonic.Frame = ANI_JUMPING_START
943
SSSonic.FrameLoop = ANI_JUMPING_LOOP
944
SSSonic.FrameEnd = ANI_JUMPING_END
945
946
SSSonic.AnimationSpeed = 80
947
SSSonic.FrameTimer = 0
948
949
// Ascending at a rate of 8.75 pixels per frame
950
SSSonic.YVelocity = 0x8C000
951
952
PlaySfx(SFX_G_SPRING, false)
953
break
954
955
case 6
956
// Fan, starting gliding
957
SSSonic.State = SSSONIC_FAN
958
SSSonic.Timer = 0
959
960
SSSonic.Frame = ANI_FAN_START
961
SSSonic.FrameLoop = ANI_FAN_LOOP
962
SSSonic.FrameEnd = ANI_FAN_END
963
964
SSSonic.AnimationSpeed = 24
965
SSSonic.FrameTimer = 0
966
967
// Fans don't give that much upwards boost, only giving a starting velocity of 2.5 pixels per frame
968
SSSonic.YVelocity = 0x28000
969
970
PlayStageSfx(SFX_S_FAN, false)
971
break
972
973
case 7
974
// Large arrow booster pad, facing left
975
SSSonic.Timer = 40
976
SSSonic.ScreenXPos = -0xC0000
977
SSSonic.ScreenYPos = 0
978
979
// Get the tile's flip directions
980
Get16x16TileInfo(CheckResult, TempValue0, TempValue1, TILEINFO_DIRECTION)
981
982
// Flip Sonic's direction if needed
983
if CheckResult == 1
984
FlipSign(SSSonic.ScreenXPos)
985
else
986
if CheckResult == 3
987
FlipSign(SSSonic.ScreenXPos)
988
end if
989
end if
990
991
if SSSonic.State != SSSONIC_SPEEDBOOSTER
992
PlayStageSfx(SFX_S_LARGEBOOSTER, false)
993
end if
994
995
SSSonic.State = SSSONIC_SPEEDBOOSTER
996
997
SSSonic.Frame = ANI_BRAKING_START
998
SSSonic.FrameLoop = ANI_BRAKING_LOOP
999
SSSonic.FrameEnd = ANI_BRAKING_END
1000
1001
SSSonic.AnimationSpeed = 24
1002
SSSonic.FrameTimer = 0
1003
break
1004
1005
case 8
1006
// Large arrow booster pad, facing right
1007
SSSonic.Timer = 40
1008
SSSonic.ScreenXPos = 0xC0000
1009
SSSonic.ScreenYPos = 0
1010
1011
// Get the tile's flip directions
1012
Get16x16TileInfo(CheckResult, TempValue0, TempValue1, TILEINFO_DIRECTION)
1013
1014
// Flip Sonic's direction if needed
1015
if CheckResult == 1
1016
FlipSign(SSSonic.ScreenXPos)
1017
else
1018
if CheckResult == 3
1019
FlipSign(SSSonic.ScreenXPos)
1020
end if
1021
end if
1022
1023
if SSSonic.State != SSSONIC_SPEEDBOOSTER
1024
PlayStageSfx(SFX_S_LARGEBOOSTER, false)
1025
end if
1026
1027
SSSonic.State = SSSONIC_SPEEDBOOSTER
1028
1029
SSSonic.Frame = ANI_BRAKING_START
1030
SSSonic.FrameLoop = ANI_BRAKING_LOOP
1031
SSSonic.FrameEnd = ANI_BRAKING_END
1032
1033
SSSonic.AnimationSpeed = 24
1034
SSSonic.FrameTimer = 0
1035
break
1036
1037
case 9
1038
// Large arrow booster pad, facing up
1039
SSSonic.Timer = 40
1040
SSSonic.ScreenXPos = 0
1041
SSSonic.ScreenYPos = -0xC0000
1042
1043
// Get the tile's flip directions
1044
Get16x16TileInfo(CheckResult, TempValue0, TempValue1, TILEINFO_DIRECTION)
1045
1046
// Flip Sonic's direction if needed
1047
if CheckResult == 2
1048
FlipSign(SSSonic.ScreenYPos)
1049
else
1050
if CheckResult == 3
1051
FlipSign(SSSonic.ScreenYPos)
1052
end if
1053
end if
1054
1055
if SSSonic.State != SSSONIC_SPEEDBOOSTER
1056
PlayStageSfx(SFX_S_LARGEBOOSTER, false)
1057
end if
1058
1059
SSSonic.State = SSSONIC_SPEEDBOOSTER
1060
1061
SSSonic.Frame = ANI_BRAKING_START
1062
SSSonic.FrameLoop = ANI_BRAKING_LOOP
1063
SSSonic.FrameEnd = ANI_BRAKING_END
1064
1065
SSSonic.AnimationSpeed = 24
1066
SSSonic.FrameTimer = 0
1067
break
1068
1069
case 10
1070
// Large arrow booster pad, facing down
1071
SSSonic.Timer = 40
1072
SSSonic.ScreenXPos = 0
1073
SSSonic.ScreenYPos = 0xC0000
1074
1075
// Get the tile's flip directions
1076
Get16x16TileInfo(CheckResult, TempValue0, TempValue1, TILEINFO_DIRECTION)
1077
1078
// Flip Sonic's direction if needed
1079
if CheckResult == 2
1080
FlipSign(SSSonic.ScreenYPos)
1081
else
1082
if CheckResult == 3
1083
FlipSign(SSSonic.ScreenYPos)
1084
end if
1085
end if
1086
1087
if SSSonic.State != SSSONIC_SPEEDBOOSTER
1088
PlayStageSfx(SFX_S_LARGEBOOSTER, false)
1089
end if
1090
1091
SSSonic.State = SSSONIC_SPEEDBOOSTER
1092
1093
SSSonic.Frame = ANI_BRAKING_START
1094
SSSonic.FrameLoop = ANI_BRAKING_LOOP
1095
SSSonic.FrameEnd = ANI_BRAKING_END
1096
1097
SSSonic.AnimationSpeed = 24
1098
SSSonic.FrameTimer = 0
1099
break
1100
1101
case 11
1102
// Small arrow booster pad, facing left
1103
if SSSonic.Timer != 16
1104
PlayStageSfx(SFX_S_SMALLBOOSTER, false)
1105
end if
1106
1107
SSSonic.Timer = 16
1108
SSSonic.ScreenXPos = -0x80000
1109
SSSonic.ScreenYPos = 0
1110
1111
// Get the tile's flip directions
1112
Get16x16TileInfo(CheckResult, TempValue0, TempValue1, TILEINFO_DIRECTION)
1113
1114
// Flip Sonic's direction if needed
1115
if CheckResult == 1
1116
FlipSign(SSSonic.ScreenXPos)
1117
else
1118
if CheckResult == 3
1119
FlipSign(SSSonic.ScreenXPos)
1120
end if
1121
end if
1122
break
1123
1124
case 12
1125
// Small arrow booster pad, facing right
1126
if SSSonic.Timer != 16
1127
PlayStageSfx(SFX_S_SMALLBOOSTER, false)
1128
end if
1129
1130
SSSonic.Timer = 16
1131
SSSonic.ScreenXPos = 0x80000
1132
SSSonic.ScreenYPos = 0
1133
1134
// Get the tile's flip directions
1135
Get16x16TileInfo(CheckResult, TempValue0, TempValue1, TILEINFO_DIRECTION)
1136
1137
// Flip Sonic's direction if needed
1138
if CheckResult == 1
1139
FlipSign(SSSonic.ScreenXPos)
1140
else
1141
if CheckResult == 3
1142
FlipSign(SSSonic.ScreenXPos)
1143
end if
1144
end if
1145
break
1146
1147
case 13
1148
// Small arrow booster pad, facing up
1149
if SSSonic.Timer != 16
1150
PlayStageSfx(SFX_S_SMALLBOOSTER, false)
1151
end if
1152
1153
SSSonic.Timer = 16
1154
SSSonic.ScreenXPos = 0
1155
SSSonic.ScreenYPos = -0x80000
1156
1157
// Get the tile's flip directions
1158
Get16x16TileInfo(CheckResult, TempValue0, TempValue1, TILEINFO_DIRECTION)
1159
1160
// Flip Sonic's direction if needed
1161
if CheckResult == 2
1162
FlipSign(SSSonic.ScreenYPos)
1163
else
1164
if CheckResult == 3
1165
FlipSign(SSSonic.ScreenYPos)
1166
end if
1167
end if
1168
break
1169
1170
case 14
1171
// Small arrow booster pad, facing down
1172
if SSSonic.Timer != 16
1173
PlayStageSfx(SFX_S_SMALLBOOSTER, false)
1174
end if
1175
1176
SSSonic.Timer = 16
1177
SSSonic.ScreenXPos = 0
1178
SSSonic.ScreenYPos = 0x80000
1179
1180
// Get the tile's flip directions
1181
Get16x16TileInfo(CheckResult, TempValue0, TempValue1, TILEINFO_DIRECTION)
1182
1183
// Flip Sonic's direction if needed
1184
if CheckResult == 2
1185
FlipSign(SSSonic.ScreenYPos)
1186
else
1187
if CheckResult == 3
1188
FlipSign(SSSonic.ScreenYPos)
1189
end if
1190
end if
1191
break
1192
1193
end switch
1194
1195
end function
1196
1197
1198
sub ObjectMain
1199
// Update Speed Shoes, the value's stored within the HUD object for whatever reason
1200
if HUD[4].SpeedShoes > 0
1201
HUD[4].SpeedShoes--
1202
end if
1203
1204
switch SSSonic.State
1205
case SSSONIC_INTROPOSE
1206
CallFunction(Sonic_ProcessAnimation)
1207
SSSonic.Timer++
1208
if SSSonic.Timer == 120
1209
// Stop posing and start turning around
1210
SSSonic.Timer = 0
1211
1212
SSSonic.State = SSSONIC_INTROTURNAROUND
1213
1214
SSSonic.Frame = ANI_FACINGAHEAD_START
1215
SSSonic.FrameLoop = ANI_FACINGAHEAD_LOOP
1216
SSSonic.FrameEnd = ANI_FACINGAHEAD_END
1217
1218
SSSonic.FrameTimer = 0
1219
SSSonic.AnimationSpeed = 20
1220
end if
1221
break
1222
1223
case SSSONIC_INTROTURNAROUND
1224
CallFunction(Sonic_ProcessAnimation)
1225
SSSonic.Timer++
1226
if SSSonic.Timer == 140
1227
// Fully turned around now and ready to go!
1228
SSSonic.Timer = 0
1229
1230
// Start advancing ahead
1231
SSSonic.State = SSSONIC_WALKING
1232
1233
SSSonic.Frame = ANI_WALKING_START
1234
SSSonic.FrameLoop = ANI_WALKING_LOOP
1235
SSSonic.FrameEnd = ANI_WALKING_END
1236
1237
SSSonic.Speed = 0
1238
end if
1239
break
1240
1241
case SSSONIC_WALKING
1242
CallFunction(Sonic_ProcessPlayer)
1243
if SSSonic.Speed < 0x50000
1244
SSSonic.Speed += 0x0800
1245
else
1246
SSSonic.Speed = 0x50000
1247
end if
1248
1249
if KeyDown[1].Down == true
1250
SSSonic.Speed -= 0x0C00
1251
1252
if SSSonic.Speed < 0x1E000
1253
SSSonic.Speed = 0x1E000
1254
end if
1255
end if
1256
1257
// Sonic's animation speed is dependant on his actual speed
1258
SSSonic.AnimationSpeed = SSSonic.Speed
1259
SSSonic.AnimationSpeed *= 15
1260
SSSonic.AnimationSpeed /= 0x14000
1261
SSSonic.AnimationSpeed += 20
1262
1263
CallFunction(Sonic_HandleMovement)
1264
CallFunction(Sonic_ProcessAnimation)
1265
1266
// Update Sonic's gimmick interaction timer
1267
if SSSonic.Timer > 0
1268
SSSonic.Timer--
1269
SSSonic.XPos += SSSonic.ScreenXPos
1270
SSSonic.ZPos += SSSonic.ScreenYPos
1271
end if
1272
1273
CallFunction(Sonic_HandleTileInteractions)
1274
1275
// Check for jumping
1276
if Player.JumpPress == true
1277
SSSonic.State = SSSONIC_JUMPING
1278
SSSonic.Timer = 0
1279
SSSonic.Frame = ANI_JUMPING_START
1280
SSSonic.FrameLoop = ANI_JUMPING_LOOP
1281
SSSonic.FrameEnd = ANI_JUMPING_END
1282
SSSonic.FrameTimer = 0
1283
SSSonic.AnimationSpeed = 80
1284
SSSonic.YVelocity = 0x46000
1285
PlaySfx(SFX_G_JUMP, false)
1286
end if
1287
break
1288
1289
case SSSONIC_JUMPING
1290
CallFunction(Sonic_ProcessPlayer)
1291
if SSSonic.Speed < 0x50000
1292
SSSonic.Speed += 0x0800
1293
end if
1294
1295
if KeyDown[1].Down == true
1296
SSSonic.Speed -= 0x0C00
1297
1298
if SSSonic.Speed < 0x1E000
1299
SSSonic.Speed = 0x1E000
1300
end if
1301
end if
1302
1303
if Player.JumpHold == false
1304
if SSSonic.YVelocity > 0x2A000
1305
SSSonic.YVelocity = 0x2A000
1306
end if
1307
end if
1308
1309
CallFunction(Sonic_HandleMovement)
1310
CallFunction(Sonic_ProcessAnimation)
1311
1312
// Gravity of 0.125 per frame
1313
SSSonic.YVelocity -= 0x2000
1314
1315
SSSonic.YPos += SSSonic.YVelocity
1316
1317
// Touched the ground?
1318
if SSSonic.YPos < 0
1319
SSSonic.YPos = 0
1320
1321
if HUD[4].UFOsCount > 0
1322
if HUD[4].SpeedShoes == 0
1323
SSSonic.State = SSSONIC_WALKING
1324
1325
SSSonic.Frame = ANI_WALKING_START
1326
SSSonic.FrameLoop = ANI_WALKING_LOOP
1327
SSSonic.FrameEnd = ANI_WALKING_END
1328
1329
SSSonic.FrameTimer = 0
1330
else
1331
SSSonic.State = SSSONIC_SPEEDSHOESRUN
1332
1333
SSSonic.Frame = ANI_RUN_START
1334
SSSonic.FrameLoop = ANI_RUN_LOOP
1335
SSSonic.FrameEnd = ANI_RUN_END
1336
1337
SSSonic.AnimationSpeed = 80
1338
SSSonic.FrameTimer = 0
1339
end if
1340
else
1341
SSSonic.ControlMode = CONTROLMODE_NONE
1342
SSSonic.State = SSSONIC_FINISHSTAND
1343
Stage.TimeEnabled = false
1344
end if
1345
end if
1346
break
1347
1348
case SSSONIC_SPEEDBOOSTER
1349
CallFunction(Sonic_ProcessPlayer)
1350
1351
if SSSonic.Speed < 0x50000
1352
SSSonic.Speed += 0x0800
1353
end if
1354
1355
if KeyDown[1].Down == true
1356
SSSonic.Speed -= 0x0C00
1357
1358
if SSSonic.Speed < 0x1E000
1359
SSSonic.Speed = 0x1E000
1360
end if
1361
end if
1362
1363
CallFunction(Sonic_HandleMovement)
1364
CallFunction(Sonic_ProcessAnimation)
1365
1366
// Update the booster timer
1367
if SSSonic.Timer > 0
1368
SSSonic.Timer--
1369
SSSonic.XPos += SSSonic.ScreenXPos
1370
SSSonic.ZPos += SSSonic.ScreenYPos
1371
else
1372
// Booster's over, restore the player to normal
1373
1374
if HUD[4].SpeedShoes == 0
1375
SSSonic.State = SSSONIC_WALKING
1376
1377
SSSonic.Frame = ANI_WALKING_START
1378
SSSonic.FrameLoop = ANI_WALKING_LOOP
1379
SSSonic.FrameEnd = ANI_WALKING_END
1380
1381
SSSonic.FrameTimer = 0
1382
else
1383
SSSonic.State = SSSONIC_SPEEDSHOESRUN
1384
1385
SSSonic.Frame = ANI_RUN_START
1386
SSSonic.FrameLoop = ANI_RUN_LOOP
1387
SSSonic.FrameEnd = ANI_RUN_END
1388
1389
SSSonic.AnimationSpeed = 80
1390
SSSonic.FrameTimer = 0
1391
end if
1392
1393
end if
1394
1395
CallFunction(Sonic_HandleTileInteractions)
1396
1397
// See if the player wants to jump out of the boost
1398
if Player.JumpPress == true
1399
SSSonic.State = SSSONIC_JUMPING
1400
SSSonic.Timer = 0
1401
1402
SSSonic.Frame = ANI_JUMPING_START
1403
SSSonic.FrameLoop = ANI_JUMPING_LOOP
1404
SSSonic.FrameEnd = ANI_JUMPING_END
1405
1406
SSSonic.AnimationSpeed = 80
1407
SSSonic.YVelocity = 0x46000
1408
1409
PlaySfx(SFX_G_JUMP, false)
1410
end if
1411
break
1412
1413
case SSSONIC_FAN
1414
CallFunction(Sonic_ProcessPlayer)
1415
1416
if SSSonic.Speed < 0x50000
1417
SSSonic.Speed += 0x0800
1418
end if
1419
1420
CallFunction(Sonic_HandleMovement)
1421
CallFunction(Sonic_ProcessAnimation)
1422
1423
// Gravity of 0.03125 pixels per frame, the fan provides some air resistance to lessen the normal gravity from 0.125 pixels per frame
1424
SSSonic.YVelocity -= 0x0800
1425
1426
SSSonic.YPos += SSSonic.YVelocity
1427
1428
// Touched the ground?
1429
if SSSonic.YPos < 0
1430
SSSonic.YPos = 0
1431
1432
if HUD[4].UFOsCount > 0
1433
if HUD[4].SpeedShoes == 0
1434
SSSonic.State = SSSONIC_WALKING
1435
1436
SSSonic.Frame = ANI_WALKING_START
1437
SSSonic.FrameLoop = ANI_WALKING_LOOP
1438
SSSonic.FrameEnd = ANI_WALKING_END
1439
1440
SSSonic.FrameTimer = 0
1441
else
1442
SSSonic.State = SSSONIC_SPEEDSHOESRUN
1443
1444
SSSonic.Frame = ANI_RUN_START
1445
SSSonic.FrameLoop = ANI_RUN_LOOP
1446
SSSonic.FrameEnd = ANI_RUN_END
1447
1448
SSSonic.AnimationSpeed = 80
1449
SSSonic.FrameTimer = 0
1450
end if
1451
else
1452
SSSonic.State = SSSONIC_FINISHSTAND
1453
SSSonic.ControlMode = CONTROLMODE_NONE
1454
Stage.TimeEnabled = false
1455
end if
1456
end if
1457
break
1458
1459
case SSSONIC_TRIPPED
1460
CallFunction(Sonic_HandlePause)
1461
1462
// Lock movement
1463
Player.Left = false
1464
Player.Right = false
1465
1466
CallFunction(Sonic_HandleMovement)
1467
CallFunction(Sonic_ProcessAnimation)
1468
1469
// Get the player's truncated XPos and ZPos
1470
1471
TempValue0 = SSSonic.XPos
1472
TempValue0 >>= 16
1473
1474
TempValue1 = SSSonic.ZPos
1475
TempValue1 >>= 16
1476
1477
Get16x16TileInfo(CheckResult, TempValue0, TempValue1, TILEINFO_ANGLEA)
1478
1479
// If the player's hit a bumper tile, then get up and start walking again
1480
if CheckResult == 3
1481
SSSonic.State = SSSONIC_WALKING
1482
1483
SSSonic.Frame = ANI_WALKING_START
1484
SSSonic.FrameLoop = ANI_WALKING_LOOP
1485
SSSonic.FrameEnd = ANI_WALKING_END
1486
1487
SSSonic.FrameTimer = 0
1488
end if
1489
1490
if SSSonic.Timer > 0
1491
SSSonic.Timer--
1492
else
1493
if HUD[4].SpeedShoes == 0
1494
SSSonic.State = SSSONIC_WALKING
1495
1496
SSSonic.Frame = ANI_WALKING_START
1497
SSSonic.FrameLoop = ANI_WALKING_LOOP
1498
SSSonic.FrameEnd = ANI_WALKING_END
1499
1500
SSSonic.FrameTimer = 0
1501
else
1502
SSSonic.State = SSSONIC_SPEEDSHOESRUN
1503
1504
SSSonic.Frame = ANI_RUN_START
1505
SSSonic.FrameLoop = ANI_RUN_LOOP
1506
SSSonic.FrameEnd = ANI_RUN_END
1507
1508
SSSonic.AnimationSpeed = 80
1509
SSSonic.FrameTimer = 0
1510
end if
1511
end if
1512
break
1513
1514
case SSSONIC_SPEEDSHOESRUN
1515
CallFunction(Sonic_ProcessPlayer)
1516
1517
if SSSonic.Speed < 0x70000
1518
SSSonic.Speed += 0x1000
1519
end if
1520
1521
if KeyDown[1].Down == true
1522
SSSonic.Speed -= 0x0C00
1523
1524
if SSSonic.Speed < 0x1E000
1525
SSSonic.Speed = 0x1E000
1526
end if
1527
end if
1528
1529
CallFunction(Sonic_HandleMovement)
1530
CallFunction(Sonic_ProcessAnimation)
1531
1532
if SSSonic.Timer > 0
1533
SSSonic.Timer--
1534
SSSonic.XPos += SSSonic.ScreenXPos
1535
SSSonic.ZPos += SSSonic.ScreenYPos
1536
end if
1537
1538
CallFunction(Sonic_HandleTileInteractions)
1539
1540
if Player.JumpPress == true
1541
SSSonic.State = SSSONIC_JUMPING
1542
SSSonic.Timer = 0
1543
1544
SSSonic.Frame = ANI_JUMPING_START
1545
SSSonic.FrameLoop = ANI_JUMPING_LOOP
1546
SSSonic.FrameEnd = ANI_JUMPING_END
1547
1548
SSSonic.FrameTimer = 0
1549
SSSonic.AnimationSpeed = 80
1550
SSSonic.YVelocity = 0x46000
1551
1552
PlaySfx(SFX_G_JUMP, false)
1553
end if
1554
1555
if HUD[4].SpeedShoes == 0
1556
SSSonic.State = SSSONIC_WALKING
1557
1558
SSSonic.Frame = ANI_WALKING_START
1559
SSSonic.FrameLoop = ANI_WALKING_LOOP
1560
SSSonic.FrameEnd = ANI_WALKING_END
1561
1562
SSSonic.FrameTimer = 0
1563
end if
1564
break
1565
1566
case SSSONIC_FINISHSTAND
1567
SSSonic.Frame = ANI_STANDING_START
1568
SSSonic.Timer = 0
1569
SSSonic.Speed = 0
1570
break
1571
1572
case SSSONIC_CAMERAPAN
1573
// This state is given to Sonic from the Time Stone object, not from himself
1574
1575
if SSSonic.Timer < 128
1576
SSSonic.Timer++
1577
SSSonic.Angle -= 2
1578
if SSSonic.Angle < 0
1579
SSSonic.Angle += 512
1580
end if
1581
else
1582
if Object[3].Type == TypeName[Blank Object]
1583
// Spawn the Time Stone and place it 24 pixels above the screen
1584
ResetObjectEntity(3, TypeName[Time Stone], 0, 0, -0x180000)
1585
Object[3].iXPos = Screen.CenterX
1586
Object[3].Priority = PRIORITY_ACTIVE
1587
end if
1588
end if
1589
1590
// Make Sonic's rotation based on how far into the pan we are
1591
// -> 81 is the starting Sprite Frame ID of the rotation frames
1592
SSSonic.Frame = SSSonic.Timer
1593
SSSonic.Frame >>= 4
1594
SSSonic.Frame += 81
1595
break
1596
1597
case SSSONIC_STONEGRABBED
1598
if SSSonic.Timer == 308
1599
// Spawn the Stage Results, as the "TIME STONES" variant
1600
1601
Object[30].Type = TypeName[Stage Finish]
1602
Object[30].ResultsType = STAGEFINISH_T_STONEOBTAINED
1603
#platform: Use_Origins
1604
Object[30].DrawOrder = 6 // Make sure this is on the right draw layer, as it needs to render correctly in Mirror Mode.
1605
#endplatform
1606
else
1607
SSSonic.Timer++
1608
end if
1609
break
1610
1611
case SSSONIC_SPRING
1612
CallFunction(Sonic_ProcessPlayer)
1613
1614
if SSSonic.Speed < 0x50000
1615
SSSonic.Speed += 0x0800
1616
end if
1617
1618
if KeyDown[1].Down == true
1619
SSSonic.Speed -= 0x0C00
1620
1621
if SSSonic.Speed < 0x1E000
1622
SSSonic.Speed = 0x1E000
1623
end if
1624
end if
1625
1626
CallFunction(Sonic_HandleMovement)
1627
CallFunction(Sonic_ProcessAnimation)
1628
1629
// Update gravity with an eight of a pixel per frame as a gravity value
1630
SSSonic.YVelocity -= 0x2000
1631
SSSonic.YPos += SSSonic.YVelocity
1632
1633
if SSSonic.YPos < 0
1634
SSSonic.YPos = 0
1635
if HUD[4].UFOsCount > 0
1636
if HUD[4].SpeedShoes == 0
1637
SSSonic.State = SSSONIC_WALKING
1638
1639
SSSonic.Frame = ANI_WALKING_START
1640
SSSonic.FrameLoop = ANI_WALKING_LOOP
1641
SSSonic.FrameEnd = ANI_WALKING_END
1642
1643
SSSonic.FrameTimer = 0
1644
else
1645
SSSonic.State = SSSONIC_SPEEDSHOESRUN
1646
1647
SSSonic.Frame = ANI_RUN_START
1648
SSSonic.FrameLoop = ANI_RUN_LOOP
1649
SSSonic.FrameEnd = ANI_RUN_END
1650
1651
SSSonic.AnimationSpeed = 80
1652
SSSonic.FrameTimer = 0
1653
end if
1654
else
1655
SSSonic.ControlMode = CONTROLMODE_NONE
1656
SSSonic.State = SSSONIC_FINISHSTAND
1657
end if
1658
end if
1659
break
1660
1661
end switch
1662
1663
// Enforce stage bounds
1664
// These stage size values are set by the stage's BGEffects object on Startup
1665
1666
if SSSonic.XPos > Stage.XBoundary2
1667
SSSonic.XPos = Stage.XBoundary2
1668
end if
1669
1670
if SSSonic.XPos < Stage.XBoundary1
1671
SSSonic.XPos = Stage.XBoundary1
1672
end if
1673
1674
// The Stage Bounds are setup for a 2d plane, which is why ZPos is being paired with the "Y" Bounds here
1675
if SSSonic.ZPos > Stage.YBoundary2
1676
SSSonic.ZPos = Stage.YBoundary2
1677
end if
1678
1679
if SSSonic.ZPos < Stage.YBoundary1
1680
SSSonic.ZPos = Stage.YBoundary1
1681
end if
1682
1683
// So we're kind of not actually moving around a 3d stage - instead, we're moving the entire world around Sonic
1684
// So do the calculations for that
1685
1686
TileLayer[0].Angle = SSSonic.Angle
1687
1688
// X/Z movement
1689
Sin(TileLayer[0].XPos, TileLayer[0].Angle)
1690
Cos(TileLayer[0].ZPos, TileLayer[0].Angle)
1691
TileLayer[0].XPos *= -0x2C00
1692
TileLayer[0].ZPos *= -0x2C00
1693
TileLayer[0].XPos += SSSonic.XPos
1694
TileLayer[0].ZPos += SSSonic.ZPos
1695
1696
// Y movement is much easier, no complex calcuations needed here
1697
// Just take Sonic's Y Position, smooth it out a bit, and offset it by 88 pixels
1698
TileLayer[0].YPos = SSSonic.YPos
1699
TileLayer[0].YPos /= 3
1700
TileLayer[0].YPos += 0x580000
1701
1702
end sub
1703
1704
1705
sub ObjectDraw
1706
// First draw Sonic's shadow
1707
1708
// Find his the ground position to draw the shadow on
1709
TempValue0 = TileLayer[0].YPos
1710
TempValue0 >>= 8
1711
TempValue0 *= 96
1712
TempValue0 /= 0x5800
1713
TempValue0 += 128
1714
1715
// And now draw the shadow at that given spot
1716
DrawSpriteScreenXY(0, Screen.CenterX, TempValue0)
1717
1718
// And now draw Sonic himself
1719
1720
// Get the Y position to draw him at
1721
TempValue0 = TileLayer[0].YPos
1722
TempValue0 -= SSSonic.YPos
1723
TempValue0 >>= 8
1724
TempValue0 *= 96
1725
TempValue0 /= 0x5800
1726
TempValue0 += 128
1727
1728
// If in the walking animation, jump to its corresponding special drawing code,
1729
// otherwise just do the standard drawing sprite routine
1730
switch SSSonic.State
1731
default
1732
// Just draw Sonic's sprite, nothing special needed here
1733
DrawSpriteScreenXY(SSSonic.Frame, Screen.CenterX, TempValue0)
1734
break
1735
1736
case SSSONIC_WALKING
1737
// Bump Sonic's sprite based on how "tilted" he is
1738
1739
TempValue1 = SSSonic.Frame
1740
1741
TempValue2 = SSSonic.Tilt
1742
TempValue2 >>= 2
1743
TempValue2 += 2
1744
1745
// And now jump to the result
1746
// Alternate SpriteFrames are used, as well as sprite flipping too
1747
switch TempValue2
1748
case 0
1749
TempValue1 += 6
1750
SSSonic.Direction = FACING_LEFT
1751
break
1752
1753
case 1
1754
TempValue1 += 12
1755
SSSonic.Direction = FACING_LEFT
1756
break
1757
1758
case 2
1759
SSSonic.Direction = FACING_RIGHT
1760
break
1761
1762
case 3
1763
TempValue1 += 18
1764
SSSonic.Direction = FACING_RIGHT
1765
break
1766
1767
case 4
1768
TempValue1 += 24
1769
SSSonic.Direction = FACING_RIGHT
1770
break
1771
1772
end switch
1773
1774
// And now draw the result sprite from that
1775
DrawSpriteScreenFX(TempValue1, FX_FLIP, Screen.CenterX, TempValue0)
1776
break
1777
1778
end switch
1779
1780
end sub
1781
1782
1783
sub ObjectStartup
1784
1785
// Load the correct sprite sheet based on the current player
1786
1787
if Stage.PlayerListPos == PLAYER_SONIC_A // PLAYER_SONIC
1788
LoadSpriteSheet("Special/Sonic.gif")
1789
end if
1790
if Stage.PlayerListPos == PLAYER_TAILS_A // PLAYER_TAILS in origins
1791
LoadSpriteSheet("Special/Tails.gif")
1792
end if
1793
#platform: Use_Origins
1794
if Stage.PlayerListPos == PLAYER_KNUCKLES
1795
LoadSpriteSheet("Special/Knuckles.gif")
1796
end if
1797
if Stage.PlayerListPos == PLAYER_AMY
1798
LoadSpriteSheet("Special/Amy.gif")
1799
end if
1800
#endplatform
1801
1802
// Place a Sonic object into reserved object slot 2 and initialise its values
1803
SSSonic[2].Type = TypeName[Sonic]
1804
1805
// Make Sonic always active
1806
SSSonic[2].Priority = PRIORITY_ACTIVE
1807
1808
// Give him a standard draw order depth, since he's just about in the middle of the screen
1809
SSSonic[2].ScreenDepth = 0x5800
1810
1811
// Start with him doing his intro pose, pretty fancy
1812
SSSonic[2].Frame = ANI_INTROPOSE_START
1813
SSSonic[2].FrameLoop = ANI_INTROPOSE_LOOP
1814
SSSonic[2].FrameEnd = ANI_INTROPOSE_END
1815
SSSonic[2].AnimationSpeed = 30
1816
1817
// Cycle through the scene to find all Sonic objects
1818
ArrayPos0 = 32
1819
while ArrayPos0 < 1056
1820
if Object[ArrayPos0].Type == TypeName[Sonic]
1821
1822
// Transfer this placed Sonic object's values to the main Sonic object
1823
1824
SSSonic.XPos = Object[ArrayPos0].XPos
1825
1826
// Due to the difference between editor and game, turn YPos into ZPos here
1827
SSSonic[2].ZPos = Object[ArrayPos0].YPos
1828
1829
// And then reset YPos, so that he's starting on the floor
1830
SSSonic.YPos = 0
1831
1832
// PropertyValue is Sonic's starting direction
1833
// Sonic's PropertyValue is normally always 0xC0, which is facing left
1834
SSSonic.Angle = Object[ArrayPos0].PropertyValue
1835
SSSonic.Angle <<= 1
1836
1837
// Remove this placed Sonic object from the scene set of objects,
1838
// as it's been moved to a reserved object slot now
1839
ResetObjectEntity(ArrayPos0, TypeName[Blank Object], 0, 0, 0)
1840
1841
end if
1842
1843
ArrayPos0++
1844
loop
1845
1846
// Player Frames
1847
// Refer to the ANI_* constants too, those are a good outline of what these SpriteFrames are
1848
1849
// 0 - Shadow Frame
1850
SpriteFrame(-20, -4, 40, 8, 210, 377)
1851
1852
// 1 - Standing Frame
1853
SpriteFrame(-20, -48, 40, 48, 1, 197)
1854
1855
// 2-4 - Turning Ahead Frames
1856
SpriteFrame(-20, -48, 40, 48, 83, 197)
1857
SpriteFrame(-20, -48, 40, 48, 42, 197)
1858
SpriteFrame(-20, -48, 40, 48, 1, 197)
1859
1860
// 5-8 - Intro Animation Frames
1861
SpriteFrame(-20, -48, 40, 48, 1, 246)
1862
SpriteFrame(-20, -48, 40, 48, 42, 246)
1863
SpriteFrame(-20, -48, 40, 48, 83, 246)
1864
SpriteFrame(-20, -48, 40, 48, 42, 246)
1865
1866
// 9-14 - Walking Ahead Frames
1867
SpriteFrame(-20, -48, 40, 48, 1, 1)
1868
SpriteFrame(-20, -48, 40, 48, 42, 1)
1869
SpriteFrame(-20, -48, 40, 48, 83, 1)
1870
SpriteFrame(-20, -48, 40, 48, 1, 50)
1871
SpriteFrame(-20, -48, 40, 48, 42, 50)
1872
SpriteFrame(-20, -48, 40, 48, 83, 50)
1873
1874
// 15-20 - Heavily Leaning Right Frames
1875
SpriteFrame(-20, -48, 40, 48, 1, 99)
1876
SpriteFrame(-20, -48, 40, 48, 42, 99)
1877
SpriteFrame(-20, -48, 40, 48, 83, 99)
1878
SpriteFrame(-20, -48, 40, 48, 1, 148)
1879
SpriteFrame(-20, -48, 40, 48, 42, 148)
1880
SpriteFrame(-20, -48, 40, 48, 83, 148)
1881
1882
// 21-26 - Lightly Leaning Right Frames
1883
SpriteFrame(-20, -48, 40, 48, 124, 1)
1884
SpriteFrame(-20, -48, 40, 48, 165, 1)
1885
SpriteFrame(-20, -48, 40, 48, 206, 1)
1886
SpriteFrame(-20, -48, 40, 48, 124, 50)
1887
SpriteFrame(-20, -48, 40, 48, 165, 50)
1888
SpriteFrame(-20, -48, 40, 48, 206, 50)
1889
1890
// 27-29 - Leaning Right Frames again..?
1891
// Seems to be unused, perhaps these only exist to pad out the frame number?
1892
SpriteFrame(-20, -48, 40, 48, 124, 50)
1893
SpriteFrame(-20, -48, 40, 48, 165, 50)
1894
SpriteFrame(-20, -48, 40, 48, 206, 50)
1895
1896
// 30-35 - Lightly Leaning Right Frames
1897
SpriteFrame(-20, -48, 40, 48, 124, 1)
1898
SpriteFrame(-20, -48, 40, 48, 165, 1)
1899
SpriteFrame(-20, -48, 40, 48, 206, 1)
1900
SpriteFrame(-20, -48, 40, 48, 1, 148)
1901
SpriteFrame(-20, -48, 40, 48, 42, 148)
1902
SpriteFrame(-20, -48, 40, 48, 83, 148)
1903
1904
// 36-38 - Heavily Leaning Right Frames
1905
SpriteFrame(-20, -48, 40, 48, 1, 99)
1906
SpriteFrame(-20, -48, 40, 48, 42, 99)
1907
SpriteFrame(-20, -48, 40, 48, 83, 99)
1908
1909
// 39-42 - Jumping Animation Frames
1910
SpriteFrame(-20, -40, 40, 40, 165, 99)
1911
SpriteFrame(-20, -40, 40, 40, 206, 99)
1912
SpriteFrame(-20, -40, 40, 40, 124, 140)
1913
SpriteFrame(-20, -40, 40, 40, 124, 99)
1914
1915
// 43-47 - Braking Animation
1916
SpriteFrame(-20, -48, 40, 48, 51, 344)
1917
SpriteFrame(-21, -48, 42, 48, 182, 295)
1918
SpriteFrame(-25, -48, 49, 48, 1, 344)
1919
if Stage.PlayerListPos == PLAYER_SONIC_A // PLAYER_SONIC in origins
1920
SpriteFrame(-21, -48, 42, 48, 135, 410)
1921
SpriteFrame(-20, -48, 40, 48, 178, 410)
1922
end if
1923
if Stage.PlayerListPos == PLAYER_TAILS_A // PLAYER_TAILS in origins
1924
SpriteFrame(-21, -48, 42, 48, 135, 426)
1925
SpriteFrame(-20, -48, 40, 48, 178, 426)
1926
end if
1927
1928
#platform: Use_Origins
1929
if Stage.PlayerListPos == PLAYER_KNUCKLES
1930
SpriteFrame(-21, -48, 42, 48, 135, 410)
1931
SpriteFrame(-20, -48, 40, 48, 178, 410)
1932
end if
1933
if Stage.PlayerListPos == PLAYER_AMY
1934
SpriteFrame(-21, -48, 42, 48, 135, 410)
1935
SpriteFrame(-20, -48, 40, 48, 178, 410)
1936
end if
1937
#endplatform
1938
// 48-53 - Fan Animation
1939
SpriteFrame(-16, -32, 54, 32, 17, 442) // Not accurate to the pink sprite box, it's actually cropped a bit from that
1940
SpriteFrame(-26, -32, 52, 32, 78, 442) // Same story here, too
1941
SpriteFrame(-37, -32, 54, 32, 178, 475) // And here...
1942
SpriteFrame(-32, -32, 48, 32, 1, 475)
1943
SpriteFrame(-30, -32, 60, 32, 115, 475)
1944
SpriteFrame(-16, -32, 48, 32, 208, 344)
1945
1946
// 54-76 - Falling Down Animation
1947
SpriteFrame(-28, -48, 56, 48, 92, 344)
1948
SpriteFrame(-30, -32, 60, 32, 54, 475)
1949
1950
// Most Frames in the animation varies between Sonic and Tails
1951
if Stage.PlayerListPos != PLAYER_TAILS_A
1952
SpriteFrame(-29, -32, 58, 32, 149, 344)
1953
SpriteFrame(-30, -32, 60, 32, 149, 377)
1954
SpriteFrame(-30, -32, 60, 32, 149, 377)
1955
SpriteFrame(-30, -32, 60, 32, 149, 377)
1956
SpriteFrame(-30, -32, 60, 32, 149, 377)
1957
SpriteFrame(-30, -32, 60, 32, 149, 377)
1958
SpriteFrame(-30, -32, 60, 32, 149, 377)
1959
SpriteFrame(-30, -32, 60, 32, 149, 377)
1960
SpriteFrame(-30, -32, 60, 32, 149, 377)
1961
SpriteFrame(-30, -32, 60, 32, 149, 377)
1962
SpriteFrame(-30, -32, 60, 32, 149, 377)
1963
SpriteFrame(-30, -32, 60, 32, 149, 377)
1964
SpriteFrame(-30, -32, 60, 32, 149, 377)
1965
SpriteFrame(-30, -32, 60, 32, 149, 377)
1966
SpriteFrame(-30, -32, 60, 32, 149, 377)
1967
SpriteFrame(-30, -32, 60, 32, 149, 377)
1968
SpriteFrame(-30, -32, 60, 32, 149, 377)
1969
SpriteFrame(-30, -32, 60, 32, 149, 377)
1970
else
1971
SpriteFrame(-29, -32, 58, 37, 149, 344)
1972
SpriteFrame(-30, -32, 60, 32, 149, 382)
1973
SpriteFrame(-30, -32, 60, 32, 149, 382)
1974
SpriteFrame(-30, -32, 60, 32, 149, 382)
1975
SpriteFrame(-30, -32, 60, 32, 149, 382)
1976
SpriteFrame(-30, -32, 60, 32, 149, 382)
1977
SpriteFrame(-30, -32, 60, 32, 149, 382)
1978
SpriteFrame(-30, -32, 60, 32, 149, 382)
1979
SpriteFrame(-30, -32, 60, 32, 149, 382)
1980
SpriteFrame(-30, -32, 60, 32, 149, 382)
1981
SpriteFrame(-30, -32, 60, 32, 149, 382)
1982
SpriteFrame(-30, -32, 60, 32, 149, 382)
1983
SpriteFrame(-30, -32, 60, 32, 149, 382)
1984
SpriteFrame(-30, -32, 60, 32, 149, 382)
1985
SpriteFrame(-30, -32, 60, 32, 149, 382)
1986
SpriteFrame(-30, -32, 60, 32, 149, 382)
1987
SpriteFrame(-30, -32, 60, 32, 149, 382)
1988
SpriteFrame(-30, -32, 60, 32, 149, 382)
1989
end if
1990
SpriteFrame(-20, -48, 40, 48, 1, 393)
1991
SpriteFrame(-20, -48, 40, 48, 42, 393)
1992
SpriteFrame(-20, -48, 40, 48, 83, 393)
1993
1994
// 77-80 - Running Frames
1995
SpriteFrame(-20, -48, 40, 48, 165, 140)
1996
SpriteFrame(-20, -48, 40, 48, 206, 140)
1997
SpriteFrame(-20, -48, 40, 48, 165, 189)
1998
SpriteFrame(-20, -48, 40, 48, 206, 189)
1999
2000
// 81-90 - Time Stone Grabbing Frames
2001
// These aren't used in the traditional animation system, and are instead manually set in SSSONIC_CAMERAPAN
2002
SpriteFrame(-20, -48, 40, 48, 1, 197)
2003
SpriteFrame(-20, -48, 40, 48, 124, 246)
2004
SpriteFrame(-20, -48, 40, 48, 165, 246)
2005
SpriteFrame(-20, -48, 40, 48, 206, 246)
2006
SpriteFrame(-20, -48, 40, 48, 1, 295)
2007
SpriteFrame(-20, -48, 40, 48, 42, 295)
2008
SpriteFrame(-16, -48, 32, 48, 83, 295)
2009
SpriteFrame(-16, -48, 32, 48, 116, 295)
2010
SpriteFrame(-16, -48, 32, 48, 116, 295)
2011
SpriteFrame(-16, -48, 32, 48, 149, 295)
2012
2013
end sub
2014
2015
2016
// ========================
2017
// Editor Subs
2018
// ========================
2019
2020
sub RSDKEdit
2021
if Editor.ReturnVariable == true
2022
switch Editor.VariableID
2023
case EDIT_VAR_PROPVAL // Property Value
2024
CheckResult = Object.PropertyValue
2025
break
2026
case 0 // StartDir
2027
CheckResult = Object.PropertyValue
2028
break
2029
end switch
2030
else
2031
switch Editor.VariableID
2032
case EDIT_VAR_PROPVAL // Property Value
2033
Object.PropertyValue = Editor.VariableValue
2034
break
2035
case 0 // StartDir
2036
Object.PropertyValue = Editor.VariableValue
2037
break
2038
end switch
2039
end if
2040
end sub
2041
2042
2043
sub RSDKDraw
2044
DrawSprite(0)
2045
end sub
2046
2047
2048
sub RSDKLoad
2049
LoadSpriteSheet("Special/Sonic.gif")
2050
SpriteFrame(-20, -48, 40, 48, 1, 246)
2051
2052
AddEditorVariable("StartDir")
2053
SetActiveVariable("StartDir")
2054
AddEnumVariable("Up", 0)
2055
AddEnumVariable("Right", 64)
2056
AddEnumVariable("Down", 128)
2057
AddEnumVariable("Left", 192)
2058
end sub
2059
2060