Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-1-Sonic-2-2013-Script-Decompilation
Path: blob/master/Sonic 2/Scripts/Mission/Water.txt
1482 views
1
// ----------------------------------
2
// RSDK Project: Sonic 2
3
// Script Description: Water Object
4
// Script Author: Christian Whitehead/Simon Thomley
5
// Unpacked by Rubberduckycooly's script unpacker
6
// ----------------------------------
7
8
// Any water objects in the scene should be followed by THREE blank objects, these manage player stuff
9
10
// This Object is used in Mission "Extreme! Tails Doggy Paddle Challenge" - M105 - DLC_Zone02
11
// It's a modified version of CPZ's Water object, but with all the moving water functionality taken out
12
13
// ========================
14
// Aliases
15
// ========================
16
17
private alias object.value1 : object.constBubbleTimer
18
private alias object.value2 : object.randBubbleTimer
19
private alias object.value3 : object.proccessActEffects // Not used
20
private alias object.value8 : object.nextTrackID // stores the track that should play after the drowning one stops
21
22
// AirBubble Aliases
23
private alias object.value1 : airBubble.originPos.x
24
private alias object.value2 : airBubble.targetPlayer
25
26
// CountdownBubble Aliases
27
private alias object.value1 : countdownBubble.drawPos.x
28
private alias object.value2 : countdownBubble.drawPos.y
29
30
// Player Aliases
31
private alias object.type : player.type
32
private alias object.state : player.state
33
private alias object.xpos : player.xpos
34
private alias object.ypos : player.ypos
35
private alias object.xvel : player.xvel
36
private alias object.yvel : player.yvel
37
private alias object.speed : player.speed
38
private alias object.direction : player.direction
39
private alias object.gravity : player.gravity
40
private alias object.animation : player.animation
41
private alias object.interaction : player.interaction
42
private alias object.tileCollisions : player.tileCollisions
43
private alias object.value1 : player.timer
44
private alias object.value3 : player.drownTimer
45
private alias object.value4 : player.drownLevel
46
private alias object.value7 : player.invincibleTimer
47
private alias object.value18 : player.sortedDrawOrder
48
private alias object.value20 : player.topSpeed
49
private alias object.value21 : player.acceleration
50
private alias object.value22 : player.deceleration
51
private alias object.value23 : player.airAcceleration
52
private alias object.value24 : player.airDeceleration
53
private alias object.value25 : player.gravityStrength
54
private alias object.value27 : player.jumpStrength
55
private alias object.value28 : player.jumpCap
56
private alias object.value37 : player.shield
57
58
private alias 1 : SUPERSTATE_SUPER
59
60
// Shields
61
private alias 0 : SHIELD_NONE
62
private alias 2 : SHIELD_BUBBLE
63
private alias 3 : SHIELD_FIRE
64
private alias 4 : SHIELD_LIGHTNING
65
66
// Tracks
67
private alias 0 : TRACK_STAGE
68
private alias 2 : TRACK_INVINCIBLE
69
private alias 6 : TRACK_DROWNING
70
71
72
// ========================
73
// Function Declarations
74
// ========================
75
76
reserve function Water_SpawnSmallAirBubble
77
reserve function Water_SpawnCountDownBubble
78
reserve function Water_ResetDrownMusic
79
80
81
// ========================
82
// Static Values
83
// ========================
84
85
private value Water_waterSlotID = 0
86
private value Water_activateFlag = 0
87
88
89
// ========================
90
// Function Definitions
91
// ========================
92
93
private function Water_SpawnSmallAirBubble
94
if object[+currentPlayer].constBubbleTimer > 0
95
object[+currentPlayer].constBubbleTimer--
96
97
if object[+currentPlayer].randBubbleTimer > 0
98
object[+currentPlayer].randBubbleTimer--
99
else
100
CreateTempObject(TypeName[Air Bubble], 2, player[currentPlayer].xpos, player[currentPlayer].ypos)
101
object[tempObjectPos].drawOrder = 4
102
object[tempObjectPos].yvel = -0x8800
103
airBubble[tempObjectPos].targetPlayer = currentPlayer
104
if player[currentPlayer].direction == FACING_RIGHT
105
object[tempObjectPos].xpos += 0x60000
106
else
107
object[tempObjectPos].xpos -= 0x60000
108
object[tempObjectPos].angle = 256
109
end if
110
airBubble[tempObjectPos].originPos.x = object[tempObjectPos].xpos
111
object[+currentPlayer].randBubbleTimer = 512
112
end if
113
else
114
Rand(temp0, 3)
115
if temp0 == 1
116
Rand(object[+currentPlayer].randBubbleTimer, 16)
117
object[+currentPlayer].randBubbleTimer += 8
118
else
119
object[+currentPlayer].randBubbleTimer = 512
120
end if
121
122
object[+currentPlayer].constBubbleTimer = 60
123
CreateTempObject(TypeName[Air Bubble], 2, player[currentPlayer].xpos, player[currentPlayer].ypos)
124
object[tempObjectPos].drawOrder = 4
125
object[tempObjectPos].yvel = -0x8800
126
airBubble[tempObjectPos].targetPlayer = currentPlayer
127
if player[currentPlayer].direction == FACING_RIGHT
128
object[tempObjectPos].xpos += 0x60000
129
else
130
object[tempObjectPos].xpos -= 0x60000
131
object[tempObjectPos].angle = 256
132
end if
133
134
airBubble[tempObjectPos].originPos.x = object[tempObjectPos].xpos
135
end if
136
end function
137
138
139
private function Water_SpawnCountDownBubble
140
CreateTempObject(TypeName[Countdown Bubble], temp0, player[currentPlayer].xpos, player[currentPlayer].ypos)
141
object[tempObjectPos].drawOrder = 5
142
object[tempObjectPos].yvel = -0x8800
143
countdownBubble[tempObjectPos].drawPos.y = currentPlayer // this is odd... this is drawPos.y, not "targetPlayer", likely a leftover from AirBubble spawning
144
if player[currentPlayer].direction == FACING_RIGHT
145
object[tempObjectPos].xpos += 0x60000
146
else
147
object[tempObjectPos].xpos -= 0x60000
148
object[tempObjectPos].angle = 256
149
end if
150
151
countdownBubble[tempObjectPos].drawPos.x = object[tempObjectPos].xpos
152
end function
153
154
155
private function Water_ResetDrownMusic
156
if currentPlayer == 0
157
arrayPos0 = Water_waterSlotID
158
arrayPos0 += currentPlayer
159
if player[currentPlayer].type != TypeName[Death Event]
160
if music.currentTrack == TRACK_DROWNING
161
if object[arrayPos0].nextTrackID == TRACK_INVINCIBLE
162
arrayPos1 = currentPlayer
163
arrayPos1 += playerCount
164
if object[arrayPos1].type != TypeName[Invincibility]
165
if Player_superState != SUPERSTATE_SUPER
166
object[arrayPos0].nextTrackID = TRACK_STAGE
167
end if
168
end if
169
end if
170
171
PlayMusic(object[arrayPos0].nextTrackID)
172
end if
173
end if
174
end if
175
end function
176
177
178
// ========================
179
// Events
180
// ========================
181
182
event ObjectUpdate
183
temp0 = player[0].xpos
184
temp0 >>= 16
185
temp1 = player[0].ypos
186
temp1 >>= 16
187
188
arrayPos0 = object.entityPos
189
190
if object.ypos < stage.newWaterLevel
191
object.ypos += 0x10000
192
end if
193
if object.ypos > stage.newWaterLevel
194
object.ypos -= 0x10000
195
end if
196
197
temp0 = oscillation
198
temp0 <<= 1
199
Sin(stage.waterLevel, temp0)
200
stage.waterLevel <<= 10
201
stage.waterLevel += object.ypos
202
temp7 = stage.waterLevel
203
stage.waterLevel >>= 16
204
205
currentPlayer = 0
206
while currentPlayer < playerCount
207
if player[currentPlayer].gravityStrength == 0x3800
208
CheckNotEqual(player[currentPlayer].type, TypeName[Debug Mode])
209
temp0 = checkResult
210
CheckNotEqual(player[currentPlayer].state, Player_State_Death)
211
temp0 &= checkResult
212
CheckNotEqual(player[currentPlayer].state, Player_State_Static)
213
temp0 &= checkResult
214
CheckGreater(player[currentPlayer].ypos, temp7)
215
temp0 &= checkResult
216
if temp0 == true
217
if player[currentPlayer].yvel > 0
218
player[currentPlayer].yvel >>= 2
219
end if
220
221
if object.ypos < stage.newWaterLevel
222
player[currentPlayer].yvel += 0x10000
223
end if
224
225
if player[currentPlayer].state == Player_State_Fly
226
StopSfx(SfxName[Flying])
227
StopSfx(SfxName[Jump])
228
end if
229
230
player[currentPlayer].xvel >>= 1
231
player[currentPlayer].speed >>= 1
232
233
CallFunction(Player_UpdatePhysicsState)
234
if currentPlayer == 0
235
CPZSetup_enteredWater = true
236
end if
237
238
if player[currentPlayer].yvel != 0
239
CreateTempObject(TypeName[Water Splash], 0, player[currentPlayer].xpos, temp7)
240
object[tempObjectPos].drawOrder = 4
241
player[currentPlayer].sortedDrawOrder = 4
242
PlaySfx(SfxName[Water Splash], false)
243
end if
244
245
object[+currentPlayer].constBubbleTimer = 52
246
player[currentPlayer].drownTimer = 0
247
end if
248
else
249
if player[currentPlayer].invincibleTimer == 0
250
if player[currentPlayer].shield == SHIELD_FIRE
251
temp2 = 0
252
while temp2 < 8
253
Rand(temp0, 32)
254
Rand(temp1, 32)
255
temp0 -= 16
256
temp0 <<= 16
257
temp0 += player[currentPlayer].xpos
258
temp1 -= 16
259
temp1 <<= 16
260
temp1 += player[currentPlayer].ypos
261
CreateTempObject(TypeName[Dust Puff], 0, temp0, temp1)
262
object[tempObjectPos].drawOrder = player[currentPlayer].sortedDrawOrder
263
object[tempObjectPos].drawOrder++
264
object[tempObjectPos].xvel = player[currentPlayer].xvel
265
object[tempObjectPos].yvel = player[currentPlayer].yvel
266
temp2++
267
loop
268
269
player[currentPlayer].shield = SHIELD_NONE
270
arrayPos0 = currentPlayer
271
arrayPos0 += playerCount
272
CallFunction(Player_ApplyShield)
273
end if
274
275
// Player hit the water with a lightning shield - take their shield and electrocute the water
276
if player[currentPlayer].shield == SHIELD_LIGHTNING
277
player[currentPlayer].shield = SHIELD_NONE
278
arrayPos0 = currentPlayer
279
arrayPos0 += playerCount
280
CallFunction(Player_ApplyShield)
281
Water_flashTimer = 4
282
end if
283
end if
284
285
if player[currentPlayer].shield != SHIELD_BUBBLE
286
if player[currentPlayer].drownTimer == 0
287
player[currentPlayer].drownLevel = 0
288
CallFunction(Water_ResetDrownMusic)
289
end if
290
291
switch player[currentPlayer].drownLevel
292
case 0
293
CallFunction(Water_SpawnSmallAirBubble)
294
player[currentPlayer].drownTimer++
295
if player[currentPlayer].drownTimer == 360
296
if currentPlayer == 0
297
PlaySfx(SfxName[Drown Alert], false)
298
end if
299
player[currentPlayer].drownLevel++
300
end if
301
break
302
303
case 1
304
CallFunction(Water_SpawnSmallAirBubble)
305
player[currentPlayer].drownTimer++
306
if player[currentPlayer].drownTimer == 660
307
if currentPlayer == 0
308
PlaySfx(SfxName[Drown Alert], false)
309
end if
310
player[currentPlayer].drownLevel++
311
end if
312
break
313
314
case 2
315
CallFunction(Water_SpawnSmallAirBubble)
316
player[currentPlayer].drownTimer++
317
if player[currentPlayer].drownTimer == 960
318
if currentPlayer == 0
319
PlaySfx(SfxName[Drown Alert], false)
320
end if
321
player[currentPlayer].drownLevel++
322
end if
323
break
324
325
case 3
326
CallFunction(Water_SpawnSmallAirBubble)
327
player[currentPlayer].drownTimer++
328
if player[currentPlayer].drownTimer == 1080
329
if currentPlayer == 0
330
object.nextTrackID = music.currentTrack
331
PlayMusic(TRACK_DROWNING)
332
end if
333
334
temp0 = 0
335
CallFunction(Water_SpawnCountDownBubble)
336
player[currentPlayer].drownLevel++
337
end if
338
break
339
340
case 4
341
CallFunction(Water_SpawnSmallAirBubble)
342
player[currentPlayer].drownTimer++
343
if player[currentPlayer].drownTimer == 1200
344
temp0 = 1
345
CallFunction(Water_SpawnCountDownBubble)
346
player[currentPlayer].drownLevel++
347
end if
348
break
349
350
case 5
351
CallFunction(Water_SpawnSmallAirBubble)
352
player[currentPlayer].drownTimer++
353
if player[currentPlayer].drownTimer == 1320
354
temp0 = 2
355
CallFunction(Water_SpawnCountDownBubble)
356
player[currentPlayer].drownLevel++
357
end if
358
break
359
360
case 6
361
CallFunction(Water_SpawnSmallAirBubble)
362
player[currentPlayer].drownTimer++
363
if player[currentPlayer].drownTimer == 1440
364
temp0 = 3
365
CallFunction(Water_SpawnCountDownBubble)
366
player[currentPlayer].drownLevel++
367
end if
368
break
369
370
case 7
371
CallFunction(Water_SpawnSmallAirBubble)
372
player[currentPlayer].drownTimer++
373
if player[currentPlayer].drownTimer == 1560
374
temp0 = 4
375
CallFunction(Water_SpawnCountDownBubble)
376
player[currentPlayer].drownLevel++
377
end if
378
break
379
380
case 8
381
CallFunction(Water_SpawnSmallAirBubble)
382
player[currentPlayer].drownTimer++
383
if player[currentPlayer].drownTimer == 1680
384
temp0 = 5
385
CallFunction(Water_SpawnCountDownBubble)
386
player[currentPlayer].drownLevel++
387
end if
388
break
389
390
case 9
391
CallFunction(Water_SpawnSmallAirBubble)
392
player[currentPlayer].drownTimer++
393
if player[currentPlayer].drownTimer == 1800
394
if player[currentPlayer].state != Player_State_Death
395
if currentPlayer == 0
396
stage.timeEnabled = false
397
camera[0].enabled = false
398
end if
399
player[currentPlayer].state = Player_State_Drown
400
player[currentPlayer].animation = ANI_DROWNING
401
player[currentPlayer].speed = 0
402
player[currentPlayer].xvel = 0
403
player[currentPlayer].yvel = 0
404
player[currentPlayer].tileCollisions = false
405
player[currentPlayer].interaction = false
406
player[currentPlayer].sortedDrawOrder = 5
407
object[+currentPlayer].constBubbleTimer = 2
408
PlaySfx(SfxName[Drowning], false)
409
player[currentPlayer].drownLevel++
410
end if
411
end if
412
break
413
414
case 10
415
player[currentPlayer].drownTimer++
416
if player[currentPlayer].drownTimer == 1860
417
player[currentPlayer].drownLevel++
418
end if
419
420
if object[+currentPlayer].constBubbleTimer > 0
421
object[+currentPlayer].constBubbleTimer--
422
if object[+currentPlayer].randBubbleTimer > 0
423
object[+currentPlayer].randBubbleTimer--
424
else
425
Rand(temp1, 2)
426
temp1 += 2
427
CreateTempObject(TypeName[Air Bubble], temp1, player[currentPlayer].xpos, player[currentPlayer].ypos)
428
object[tempObjectPos].drawOrder = 5
429
object[tempObjectPos].yvel = -0x8800
430
object[tempObjectPos].ypos -= 0x60000
431
airBubble[tempObjectPos].targetPlayer = currentPlayer
432
Rand(object[tempObjectPos].angle, 256)
433
airBubble[tempObjectPos].originPos.x = object[tempObjectPos].xpos
434
object[+currentPlayer].randBubbleTimer = 512
435
end if
436
else
437
Rand(temp0, 5)
438
if temp0 == 1
439
object[+currentPlayer].randBubbleTimer = 2
440
else
441
object[+currentPlayer].randBubbleTimer = 512
442
end if
443
object[+currentPlayer].constBubbleTimer = 6
444
445
Rand(temp1, 2)
446
temp1 += 2
447
CreateTempObject(TypeName[Air Bubble], temp1, player[currentPlayer].xpos, player[currentPlayer].ypos)
448
object[tempObjectPos].drawOrder = 5
449
object[tempObjectPos].yvel = -0x8800
450
object[tempObjectPos].ypos -= 0x60000
451
airBubble[tempObjectPos].targetPlayer = currentPlayer
452
Rand(object[tempObjectPos].angle, 0x100)
453
airBubble[tempObjectPos].originPos.x = object[tempObjectPos].xpos
454
end if
455
break
456
end switch
457
end if
458
459
CheckEqual(player[currentPlayer].type, TypeName[Debug Mode])
460
temp0 = checkResult
461
CheckLower(player[currentPlayer].ypos, temp7)
462
temp0 |= checkResult
463
if temp0 == true
464
if player[currentPlayer].state != Player_State_Death
465
player[currentPlayer].yvel <<= 1
466
if player[currentPlayer].yvel < -0x100000
467
player[currentPlayer].yvel = -0x100000
468
end if
469
470
// (Normally the hi-jump water bug fix would be here, but Origins doesn't have it so)
471
472
if player[currentPlayer].state == Player_State_Fly
473
if player[currentPlayer].timer < 480
474
PlaySfx(SfxName[Flying], true)
475
else
476
PlaySfx(SfxName[Jump], true)
477
end if
478
end if
479
480
481
CallFunction(Player_UpdatePhysicsState)
482
if player[currentPlayer].yvel != 0
483
temp0 = object.ypos
484
temp0 -= player[currentPlayer].ypos
485
if temp0 < 0xF00000
486
CreateTempObject(TypeName[Water Splash], 0, player[currentPlayer].xpos, temp7)
487
object[tempObjectPos].drawOrder = 4
488
player[currentPlayer].sortedDrawOrder = 4
489
PlaySfx(SfxName[Water Splash], false)
490
end if
491
end if
492
493
player[currentPlayer].drownTimer = 0
494
CallFunction(Water_ResetDrownMusic)
495
end if
496
end if
497
end if
498
499
currentPlayer++
500
loop
501
502
object.animationTimer++
503
object.animationTimer &= 31
504
object.frame = object.animationTimer
505
object.frame >>= 3
506
end event
507
508
509
event ObjectDraw
510
temp0 = screen.xoffset
511
Sin(temp1, oscillation)
512
temp1 >>= 5
513
temp0 += temp1
514
temp0 &= 63
515
FlipSign(temp0)
516
517
temp1 = stage.waterLevel
518
temp1 -= screen.yoffset
519
DrawSpriteScreenFX(object.frame, FX_INK, temp0, temp1)
520
521
temp0 += 256
522
DrawSpriteScreenFX(object.frame, FX_INK, temp0, temp1)
523
end event
524
525
526
event ObjectStartup
527
if options.vsMode == true
528
foreach (TypeName[Water], arrayPos0, ALL_ENTITIES)
529
object[arrayPos0].type = TypeName[Blank Object]
530
next
531
end if
532
533
foreach (TypeName[Water], arrayPos0, ALL_ENTITIES)
534
object[arrayPos0].priority = PRIORITY_ACTIVE
535
object[arrayPos0].drawOrder = 5
536
object[arrayPos0].inkEffect = INK_ALPHA
537
object[arrayPos0].alpha = 0xA0
538
539
// Huh? In-game credits?
540
// This is just a leftover from the S1 LZ Water script, where Water would be specially set up for the credits demo
541
// In this game there's no such thing though, this never really hits
542
if credits.screen == 0
543
stage.newWaterLevel = object[arrayPos0].ypos
544
else
545
stage.waterState = 1
546
stage.newWaterLevel = 0x4C80000
547
temp0 = player[0].xpos
548
temp0 >>= 16
549
temp1 = player[0].ypos
550
temp1 >>= 16
551
end if
552
Water_waterSlotID = arrayPos0
553
stage.newWaterLevel = object[arrayPos0].ypos // While the original CPZ Water script would call object.proccessActEffects here, the Mission Water script just sticks with where the Water obj is placed in the scene
554
stage.waterLevel = stage.newWaterLevel
555
stage.waterLevel >>= 16
556
557
if starPostID >= 32
558
stage.waterState = recWaterState
559
stage.waterLevel = recWaterLevel
560
stage.newWaterLevel = recWaterLevel
561
stage.newWaterLevel <<= 16
562
arrayPos0 = Water_waterSlotID
563
object[arrayPos0].ypos = stage.newWaterLevel
564
else
565
if credits.screen == 0
566
stage.waterState = 0
567
end if
568
end if
569
next
570
571
Water_activateFlag = false
572
573
foreach (GROUP_PLAYERS, currentPlayer, ALL_ENTITIES)
574
player[currentPlayer].drownTimer = 0
575
if player[currentPlayer].ypos > stage.newWaterLevel
576
player[currentPlayer].yvel >>= 2
577
player[currentPlayer].xvel >>= 1
578
player[currentPlayer].speed >>= 1
579
player[currentPlayer].topSpeed >>= 1
580
player[currentPlayer].acceleration >>= 1
581
player[currentPlayer].deceleration >>= 1
582
player[currentPlayer].airAcceleration >>= 1
583
player[currentPlayer].airDeceleration >>= 1
584
player[currentPlayer].gravityStrength = 0x1000
585
if stage.playerListPos == PLAYER_KNUCKLES_A
586
player[currentPlayer].jumpStrength = 0x30000
587
else
588
player[currentPlayer].jumpStrength = 0x38000
589
end if
590
player[currentPlayer].jumpCap = -0x20000
591
arrayPos0 = Water_waterSlotID
592
arrayPos0 += currentPlayer
593
object[arrayPos0].constBubbleTimer = 52
594
end if
595
next
596
597
LoadSpriteSheet("CPZ/Objects2.gif")
598
SpriteFrame(0, -8, 256, 16, 0, 0)
599
SpriteFrame(0, -8, 256, 16, 0, 16)
600
SpriteFrame(0, -8, 256, 16, 0, 32)
601
SpriteFrame(0, -8, 256, 16, 0, 48)
602
603
BrokenMonitor_ResetDrownMusic = Water_ResetDrownMusic
604
end event
605
606
607
// ========================
608
// Editor Events
609
// ========================
610
611
event RSDKDraw
612
DrawSprite(0)
613
end event
614
615
616
event RSDKLoad
617
LoadSpriteSheet("CPZ/Objects2.gif")
618
SpriteFrame(0, -8, 256, 16, 0, 0)
619
620
SetVariableAlias(ALIAS_VAR_PROPVAL, "unused")
621
end event
622
623