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/Players/Player2Object.txt
1479 views
1
// ----------------------------------
2
// RSDK Project: Sonic 2
3
// Script Description: Player 2 Object Object
4
// Script Author: Christian Whitehead/Simon Thomley
5
// Unpacked by Rubberduckycooly's script unpacker
6
// ----------------------------------
7
8
// ========================
9
// Aliases
10
// ========================
11
12
private alias object.type : player.type
13
private alias object.groupID : player.groupID
14
private alias object.entityPos : player.entityPos
15
private alias object.state : player.state
16
private alias object.visible : player.visible
17
private alias object.propertyValue : player.character
18
private alias object.priority : player.priority
19
private alias object.xpos : player.xpos
20
private alias object.ypos : player.ypos
21
private alias object.ixpos : player.ixpos
22
private alias object.iypos : player.iypos
23
private alias object.lookPosY : player.lookPosY
24
private alias object.xvel : player.xvel
25
private alias object.yvel : player.yvel
26
private alias object.speed : player.speed
27
private alias object.rotation : player.rotation
28
private alias object.angle : player.angle
29
private alias object.direction : player.direction
30
private alias object.gravity : player.gravity
31
private alias object.frame : player.frame
32
private alias object.animation : player.animation
33
private alias object.prevAnimation : player.prevAnimation
34
private alias object.animationSpeed : player.animationSpeed
35
private alias object.animationTimer : player.animationTimer
36
private alias object.drawOrder : player.drawOrder
37
private alias object.controlLock : player.controlLock
38
private alias object.controlMode : player.controlMode
39
private alias object.interaction : player.interaction
40
private alias object.collisionPlane : player.collisionPlane
41
private alias object.tileCollisions : player.tileCollisions
42
private alias object.outOfBounds : player.outOfBounds
43
44
private alias object.jumpPress : player.jumpPress
45
private alias object.jumpHold : player.jumpHold
46
private alias object.up : player.up
47
private alias object.down : player.down
48
private alias object.left : player.left
49
private alias object.right : player.right
50
51
private alias object.value1 : player.timer
52
private alias object.value3 : player.drownTimer // Countdown before player moves to next drown "level"
53
private alias object.value4 : player.drownLevel
54
private alias object.value6 : player.speedShoesTimer
55
private alias object.value7 : player.invincibleTimer
56
private alias object.value8 : player.blinkTimer
57
private alias object.value11 : player.scrollDelay // A timer of how long the camera will stay locked for
58
private alias object.value12 : player.tailFrame
59
private alias object.value13 : player.tailAnim
60
private alias object.value16 : player.isSidekick // 0/false is player 1, 1/true if player 2
61
private alias object.value18 : player.sortedDrawOrder
62
private alias object.value19 : player.badnikBonus
63
private alias object.value25 : player.gravityStrength // Also used in underwater checks , 0x1000 if underwater, otherwise 0x3800. Not to be confused with player.gravity
64
private alias object.value26 : player.flightVelocity
65
private alias object.value30 : player.jumpOffset
66
private alias object.value31 : player.rollingDeceleration // Passive rolling deceleration - Without the player holding the opposite direction
67
private alias object.value32 : player.jumpAbility // Used to store whatever function this player has for its jump ability
68
private alias object.value33 : player.spindashFunction // Used to store whatever function this player has for its spindash ability
69
private alias object.value34 : player.collisionDisabled
70
private alias object.value40 : player.hitboxLeft
71
private alias object.value38 : player.hitboxTop
72
private alias object.value41 : player.hitboxRight
73
private alias object.value39 : player.hitboxBottom
74
private alias object.value42 : player.prevGravity
75
private alias object.value43 : player.jumpInTimer
76
private alias object.value44 : player.p2InputFunction
77
private alias object.value45 : player.autoJumpTimer
78
private alias object.value46 : player.targetLeaderPos.x
79
private alias object.value47 : player.targetLeaderPos.y
80
81
// Draw Order Aliases
82
private alias -1 : DRAWORDER_PLAYER
83
84
// Tracks
85
private alias 0 : TRACK_STAGE
86
private alias 2 : TRACK_INVINCIBLE
87
private alias 5 : TRACK_GAMEOVER
88
private alias 7 : TRACK_SUPER
89
90
// Reserved Object Slots
91
private alias 0 : SLOT_PLAYER1
92
private alias 1 : SLOT_PLAYER2
93
94
95
// ========================
96
// Function Declarations
97
// ========================
98
99
reserve function Player2_GetDelayedInput
100
reserve function Player2_Input_GamepadAssist
101
reserve function Player2_Input_AI_Follow
102
reserve function Player2_Input_AI_SpindashPt1
103
reserve function Player2_Input_AI_SpindashPt2
104
reserve function Player2_State_FlyToPlayer
105
reserve function Player2_HandleSidekickRespawn
106
reserve function Player_ProcessUpdateP2
107
reserve function Player2_Input_None
108
reserve function Player2_Action_DblJumpTailsAI
109
reserve function Player_ProcessUpdateP2_VS
110
111
112
// ========================
113
// Static Values
114
// ========================
115
116
public value Player2Object_stateUp = 0;
117
public value Player2Object_stateDown = 0;
118
public value Player2Object_stateLeft = 0;
119
public value Player2Object_stateRight = 0;
120
public value Player2Object_stateJumpPress = 0;
121
public value Player2Object_stateJumpHold = 0;
122
public value Player2Object_nextLeaderPosID = 0;
123
public value Player2Object_lastLeaderPosID = 0;
124
125
126
// ========================
127
// Tables
128
// ========================
129
130
public table Player2Object_leaderPosBufferX[16]
131
public table Player2Object_leaderPosBufferY[16]
132
133
134
// ========================
135
// Function Definitions
136
// ========================
137
138
public function Player2_Input_None
139
temp0 = 0
140
end function
141
142
143
public function Player2_Action_DblJumpTailsAI
144
CheckNotEqual(player.p2InputFunction, Player2_Input_None)
145
temp0 = checkResult
146
#platform: USE_ORIGINS
147
CheckNotEqual(player.p2InputFunction, Player2_Input_GamepadAssist)
148
temp0 &= checkResult
149
#endplatform
150
CheckNotEqual(player.up, true)
151
temp0 &= checkResult
152
if temp0 == false
153
CallFunction(Player_Action_DblJumpTails)
154
end if
155
end function
156
157
158
public function Player2_GetDelayedInput
159
if player.controlMode > CONTROLMODE_NONE
160
Player2Object_stateUp <<= 1
161
Player2Object_stateUp |= player[SLOT_PLAYER1].up
162
Player2Object_stateUp &= 0xFFFF
163
164
Player2Object_stateDown <<= 1
165
Player2Object_stateDown |= player[SLOT_PLAYER1].down
166
Player2Object_stateDown &= 0xFFFF
167
168
Player2Object_stateLeft <<= 1
169
Player2Object_stateLeft |= player[SLOT_PLAYER1].left
170
Player2Object_stateLeft &= 0xFFFF
171
172
Player2Object_stateRight <<= 1
173
Player2Object_stateRight |= player[SLOT_PLAYER1].right
174
Player2Object_stateRight &= 0xFFFF
175
176
Player2Object_stateJumpPress <<= 1
177
Player2Object_stateJumpPress |= player[SLOT_PLAYER1].jumpPress
178
Player2Object_stateJumpPress &= 0xFFFF
179
180
Player2Object_stateJumpHold <<= 1
181
Player2Object_stateJumpHold |= player[SLOT_PLAYER1].jumpHold
182
Player2Object_stateJumpHold &= 0xFFFF
183
184
if player[SLOT_PLAYER1].state == Player_State_Carried
185
Player2Object_stateDown <<= 15
186
Player2Object_stateLeft <<= 15
187
Player2Object_stateRight <<= 15
188
Player2Object_stateJumpPress <<= 15
189
Player2Object_stateJumpHold <<= 15
190
end if
191
192
temp0 = Player2Object_stateUp
193
temp0 >>= 15
194
player.up = temp0
195
196
temp0 = Player2Object_stateDown
197
temp0 >>= 15
198
player.down = temp0
199
200
temp0 = Player2Object_stateLeft
201
temp0 >>= 15
202
player.left = temp0
203
204
temp0 = Player2Object_stateRight
205
temp0 >>= 15
206
player.right = temp0
207
208
temp0 = Player2Object_stateJumpPress
209
temp0 >>= 15
210
player.jumpPress = temp0
211
212
temp0 = Player2Object_stateJumpHold
213
temp0 >>= 15
214
player.jumpHold = temp0
215
else
216
Player2Object_stateUp = 0
217
Player2Object_stateDown = 0
218
Player2Object_stateLeft = 0
219
Player2Object_stateRight = 0
220
Player2Object_stateJumpPress = 0
221
Player2Object_stateJumpHold = 0
222
end if
223
224
if player[SLOT_PLAYER1].state != Player_State_Death
225
if player[SLOT_PLAYER1].type != TypeName[Death Event]
226
SetTableValue(player[SLOT_PLAYER1].xpos, Player2Object_lastLeaderPosID, Player2Object_leaderPosBufferX)
227
SetTableValue(player[SLOT_PLAYER1].ypos, Player2Object_lastLeaderPosID, Player2Object_leaderPosBufferY)
228
229
Player2Object_lastLeaderPosID++
230
Player2Object_lastLeaderPosID &= 15
231
Player2Object_nextLeaderPosID++
232
Player2Object_nextLeaderPosID &= 15
233
CheckEqual(player[SLOT_PLAYER1].gravity, GRAVITY_AIR)
234
temp0 = checkResult
235
CheckEqual(player[SLOT_PLAYER1].prevGravity, GRAVITY_GROUND)
236
temp0 &= checkResult
237
238
if temp0 == false
239
GetTableValue(player.targetLeaderPos.x, Player2Object_nextLeaderPosID, Player2Object_leaderPosBufferX)
240
GetTableValue(player.targetLeaderPos.y, Player2Object_nextLeaderPosID, Player2Object_leaderPosBufferY)
241
else
242
player.targetLeaderPos.x = player[SLOT_PLAYER1].xpos
243
player.targetLeaderPos.y = player[SLOT_PLAYER1].ypos
244
end if
245
else
246
temp0 = Player2Object_lastLeaderPosID
247
temp0--
248
if temp0 < 0
249
temp0 += 16
250
end if
251
252
GetTableValue(player.targetLeaderPos.x, temp0, Player2Object_leaderPosBufferX)
253
GetTableValue(player.targetLeaderPos.y, temp0, Player2Object_leaderPosBufferY)
254
end if
255
else
256
temp0 = Player2Object_lastLeaderPosID
257
temp0--
258
if temp0 < 0
259
temp0 += 16
260
end if
261
262
GetTableValue(player.targetLeaderPos.x, temp0, Player2Object_leaderPosBufferX)
263
GetTableValue(player.targetLeaderPos.y, temp0, Player2Object_leaderPosBufferY)
264
end if
265
end function
266
267
268
public function Player2_Input_GamepadAssist
269
#platform: USE_ORIGINS
270
IsInputSlotAssigned(2)
271
if checkResult == false
272
player.p2InputFunction = Player2_Input_AI_Follow
273
AssignInputSlotToDevice(2, -1)
274
return
275
end if
276
277
ProcessObjectControl()
278
279
temp0 = player.up
280
temp0 |= player.down
281
temp0 |= player.left
282
temp0 |= player.right
283
temp0 |= player.jumpHold
284
if temp0 == false
285
player.autoJumpTimer++
286
if player.autoJumpTimer >= 600
287
player.p2InputFunction = Player2_Input_AI_Follow
288
AssignInputSlotToDevice(2, -1)
289
end if
290
else
291
player.autoJumpTimer = 0
292
end if
293
#endplatform
294
end function
295
296
297
public function Player2_Input_AI_Follow
298
CallFunction(Player2_GetDelayedInput)
299
if player[SLOT_PLAYER1].type == TypeName[Player Object]
300
temp0 = player.angle
301
temp0 += 0x10
302
temp0 &= 0xE0
303
if temp0 == 0
304
if player.left == true
305
temp0 = player[SLOT_PLAYER1].xpos
306
temp0 -= 0x80000
307
if player.xpos < temp0
308
if player.xvel <= 0
309
player.left = false
310
end if
311
end if
312
end if
313
314
if player.right == true
315
temp0 = player[SLOT_PLAYER1].xpos
316
temp0 += 0x80000
317
if player.xpos > temp0
318
if player.yvel <= 0
319
player.right = false
320
end if
321
end if
322
end if
323
end if
324
325
if player[SLOT_PLAYER1].state != Player_State_Carried
326
temp0 = player.targetLeaderPos.x
327
temp1 = player[SLOT_PLAYER1].gravity
328
temp1 |= player[SLOT_PLAYER1].prevGravity
329
330
if temp1 == GRAVITY_GROUND
331
if player[SLOT_PLAYER1].speed < 0x20000
332
if player[SLOT_PLAYER1].speed > -0x20000
333
if player[SLOT_PLAYER1].direction == 0
334
temp0 -= 0x200000
335
else
336
temp0 += 0x200000
337
end if
338
end if
339
end if
340
end if
341
temp0 -= player.xpos
342
343
if temp0 != 0
344
if temp0 < 0
345
if temp0 <= -0x300000
346
player.right = false
347
player.left = true
348
end if
349
350
if player.speed != 0
351
if player.direction == FACING_LEFT
352
Cos256(temp1, player.angle)
353
temp1 *= 0xC0
354
player.xpos -= temp1
355
end if
356
end if
357
else
358
if temp0 >= 0x300000
359
player.left = false
360
player.right = true
361
end if
362
363
if player.speed != 0
364
if player.direction == FACING_RIGHT
365
Cos256(temp1, player.angle)
366
temp1 *= 0xC0
367
player.xpos += temp1
368
end if
369
end if
370
end if
371
end if
372
373
if player.animation == ANI_PUSHING
374
player.autoJumpTimer++
375
if player[SLOT_PLAYER1].direction == player.direction
376
if player[SLOT_PLAYER1].animation == ANI_PUSHING
377
player.autoJumpTimer = 0
378
end if
379
end if
380
381
if player.autoJumpTimer >= 30
382
if player.gravity == GRAVITY_GROUND
383
CallFunction(Player_Action_Jump)
384
end if
385
player.timer = 0
386
player.autoJumpTimer = 0
387
end if
388
else
389
temp0 = player.ypos
390
temp0 -= player.targetLeaderPos.y
391
if temp0 > 0x200000
392
player.autoJumpTimer++
393
if player.autoJumpTimer >= 64
394
if player.gravity == GRAVITY_GROUND
395
CallFunction(Player_Action_Jump)
396
end if
397
player.timer = 0
398
player.autoJumpTimer = 0
399
end if
400
else
401
player.autoJumpTimer = 0
402
end if
403
end if
404
405
if player.controlLock > 0
406
if player.speed < 0x8000
407
if player.speed > -0x8000
408
player.p2InputFunction = Player2_Input_AI_SpindashPt1
409
end if
410
end if
411
end if
412
end if
413
end if
414
415
#platform: USE_ORIGINS
416
if game.playMode != BOOT_PLAYMODE_MISSION
417
temp0 = keyDown[2].up
418
temp0 |= keyDown[2].down
419
temp0 |= keyDown[2].left
420
temp0 |= keyDown[2].right
421
temp0 |= keyDown[2].buttonA
422
temp0 |= keyDown[2].buttonB
423
temp0 |= keyDown[2].buttonC
424
if temp0 == true
425
player.autoJumpTimer = 0
426
player.p2InputFunction = Player2_Input_GamepadAssist
427
end if
428
end if
429
#endplatform
430
end function
431
432
433
public function Player2_Input_AI_SpindashPt1
434
player.up = false
435
player.down = false
436
player.left = false
437
player.right = false
438
player.jumpPress = false
439
player.jumpHold = false
440
441
if player.controlLock == 0
442
if player.gravity == GRAVITY_GROUND
443
if player.speed < 0x4000
444
if player.speed > -0x4000
445
player.p2InputFunction = Player2_Input_AI_SpindashPt2
446
player.autoJumpTimer = 1
447
448
if player.animation != ANI_SPINDASH
449
if player.xpos < player.targetLeaderPos.x
450
player.direction = FACING_RIGHT
451
else
452
player.direction = FACING_LEFT
453
end if
454
player.down = true
455
end if
456
end if
457
end if
458
end if
459
end if
460
end function
461
462
463
public function Player2_Input_AI_SpindashPt2
464
if player.autoJumpTimer < 64
465
player.down = true
466
temp0 = player.autoJumpTimer
467
temp0 &= 15
468
if temp0 == 0
469
player.jumpPress = true
470
else
471
player.jumpPress = false
472
end if
473
474
player.autoJumpTimer++
475
else
476
player.autoJumpTimer = 0
477
player.down = false
478
player.jumpPress = false
479
player.p2InputFunction = Player2_Input_AI_Follow
480
end if
481
end function
482
483
484
public function Player2_State_FlyToPlayer
485
CallFunction(Player2_GetDelayedInput)
486
487
if player.gravityStrength == 0x3800
488
player.animation = ANI_FLYING
489
else
490
player.animation = ANI_SWIMMING
491
end if
492
493
temp0 = player.targetLeaderPos.x
494
temp0 -= player.xpos
495
temp1 = temp0
496
temp0 >>= 4
497
498
if player.xpos < player.targetLeaderPos.x
499
player.direction = FACING_RIGHT
500
if temp0 > 0xC0000
501
temp0 = 0xC0000
502
end if
503
504
if player[SLOT_PLAYER1].xvel > 0
505
temp0 += player[SLOT_PLAYER1].xvel
506
end if
507
508
temp0 += 0x10000
509
if temp0 > temp1
510
temp0 = temp1
511
temp1 = 0
512
end if
513
else
514
player.direction = FACING_LEFT
515
if temp0 < -0xC0000
516
temp0 = -0xC0000
517
end if
518
519
if player[SLOT_PLAYER1].xvel < 0
520
temp0 += player[SLOT_PLAYER1].xvel
521
end if
522
523
temp0 -= 0x10000
524
if temp0 < temp1
525
temp0 = temp1
526
temp1 = 0
527
end if
528
end if
529
530
player.xpos += temp0
531
if player.ypos < player.targetLeaderPos.y
532
player.ypos += 0x10000
533
end if
534
535
if player.ypos > player.targetLeaderPos.y
536
player.ypos -= 0x10000
537
end if
538
539
if player[SLOT_PLAYER1].type != TypeName[Death Event]
540
if player[SLOT_PLAYER1].state != Player_State_Death
541
if player[SLOT_PLAYER1].state != Player_State_Drown
542
if player[SLOT_PLAYER1].state != Player_State_TubeRoll
543
if temp1 == 0
544
temp0 = player.targetLeaderPos.y
545
temp0 -= player.ypos
546
if temp0 < 0
547
FlipSign(temp0)
548
end if
549
550
if temp0 < 0x20000
551
#platform: USE_STANDALONE
552
player.state = Player_State_Air
553
#endplatform
554
#platform: USE_ORIGINS
555
player.state = Player_State_Air_NoDropDash
556
#endplatform
557
player.animation = ANI_JUMPING
558
player.gravity = GRAVITY_AIR
559
player.tileCollisions = true
560
player.interaction = true
561
player.controlMode = CONTROLMODE_P2
562
player.controlLock = 0
563
player.angle = 0
564
player.p2InputFunction = Player2_Input_AI_Follow
565
player.collisionPlane = player[SLOT_PLAYER1].collisionPlane
566
#platform: USE_ORIGINS
567
player.sortedDrawOrder = player[SLOT_PLAYER1].sortedDrawOrder
568
#endplatform
569
570
Player2Object_stateUp = 0
571
Player2Object_stateDown = 0
572
Player2Object_stateLeft = 0
573
Player2Object_stateRight = 0
574
Player2Object_stateJumpPress = 0
575
Player2Object_stateJumpHold = 0
576
end if
577
end if
578
end if
579
end if
580
end if
581
end if
582
end function
583
584
585
public function Player2_HandleSidekickRespawn
586
if player[SLOT_PLAYER1].type == TypeName[Player Object]
587
if player.outOfBounds == true
588
player.jumpInTimer++
589
else
590
player.jumpInTimer = 0
591
end if
592
593
if player.jumpInTimer >= 240
594
player.jumpInTimer = 0
595
player.state = Player2_State_FlyToPlayer
596
player.xpos = player[SLOT_PLAYER1].xpos
597
player.ypos = screen.yoffset
598
player.ypos -= 128
599
player.ypos <<= 16
600
player.xvel = 0
601
player.yvel = 0
602
player.speed = 0
603
player.tileCollisions = false
604
player.interaction = false
605
player.controlMode = CONTROLMODE_P2
606
#platform: USE_STANDALONE
607
player.sortedDrawOrder = 4
608
#endplatform
609
#platform: USE_ORIGINS
610
player.sortedDrawOrder = player[SLOT_PLAYER1].sortedDrawOrder
611
#endplatform
612
player.drownTimer = 0
613
player.drownLevel = 0
614
end if
615
616
CheckEqual(player[SLOT_PLAYER1].state, Player_State_Death)
617
temp0 = checkResult
618
CheckEqual(player[SLOT_PLAYER1].type, TypeName[Death Event])
619
temp0 |= checkResult
620
CheckNotEqual(player.state, Player_State_Hurt)
621
temp0 &= checkResult
622
CheckNotEqual(player.state, Player_State_Death)
623
temp0 &= checkResult
624
if temp0 == true
625
player.jumpInTimer = 0
626
player.state = Player2_State_FlyToPlayer
627
player.xvel = 0
628
player.yvel = 0
629
player.speed = 0
630
player.tileCollisions = false
631
player.interaction = false
632
end if
633
end if
634
end function
635
636
637
public function Player_ProcessUpdateP2
638
if player.state == Player_State_Death
639
player.p2InputFunction = Player2_Input_None
640
end if
641
642
if player.state == Player_State_Drown
643
player.p2InputFunction = Player2_Input_None
644
end if
645
646
CallFunction(player.p2InputFunction)
647
648
if player.state != Player_State_Hurt
649
if player.blinkTimer > 0
650
player.blinkTimer--
651
652
GetBit(temp0, player.blinkTimer, 2)
653
if temp0 == true
654
player.visible = false
655
else
656
player.visible = true
657
end if
658
end if
659
end if
660
661
if player.invincibleTimer > 0
662
if player.state != Player_State_Hurt
663
if player.invincibleTimer > 2000
664
player.invincibleTimer = 120
665
player.blinkTimer = 3
666
end if
667
end if
668
669
player.invincibleTimer--
670
if player.invincibleTimer == 0
671
player.blinkTimer = 0
672
player.visible = true
673
end if
674
end if
675
676
if player.state != Player_State_LookUp
677
if player.state != Player_State_Crouch
678
if player.lookPosY > 0
679
player.lookPosY -= 2
680
end if
681
682
if player.lookPosY < 0
683
player.lookPosY += 2
684
end if
685
end if
686
end if
687
688
if player.state != Player_State_Fly
689
if player.flightVelocity != 0
690
StopSfx(SfxName[Flying])
691
StopSfx(SfxName[Tired])
692
player.flightVelocity = 0
693
end if
694
end if
695
end function
696
697
698
public function Player_ProcessUpdateP2_VS
699
#platform: USE_STANDALONE
700
CallNativeFunction2(ReceiveEntity, player.entityPos, true)
701
player.type = TypeName[Player 2 Object]
702
#endplatform
703
704
#platform: USE_ORIGINS
705
ProcessObjectControl()
706
#endplatform
707
708
if player.speedShoesTimer > 0
709
player.speedShoesTimer--
710
if player.speedShoesTimer < 1
711
currentPlayer = player.entityPos
712
CallFunction(Player_UpdatePhysicsState)
713
714
temp0 = false
715
foreach (GROUP_PLAYERS, currentPlayer, ACTIVE_ENTITIES)
716
temp0 += player[currentPlayer].speedShoesTimer
717
next
718
719
if temp0 == false
720
if SlowDownMusic != 0
721
CallFunction(SlowDownMusic)
722
end if
723
end if
724
725
player.speedShoesTimer = 0
726
end if
727
end if
728
729
if player.state != Player_State_Hurt
730
if player.blinkTimer > 0
731
player.blinkTimer--
732
GetBit(temp0, player.blinkTimer, 2)
733
if temp0 == true
734
player.visible = false
735
else
736
player.visible = true
737
end if
738
end if
739
end if
740
741
if player.invincibleTimer > 0
742
player.invincibleTimer--
743
if player.invincibleTimer == 0
744
temp0 = false
745
foreach (GROUP_PLAYERS, currentPlayer, ACTIVE_ENTITIES)
746
temp0 += player[currentPlayer].invincibleTimer
747
next
748
749
if temp0 == false
750
if music.currentTrack == TRACK_INVINCIBLE
751
PlayMusic(TRACK_STAGE)
752
end if
753
end if
754
755
if object[+playerCount].type == invincibilityType
756
currentPlayer = player.entityPos
757
arrayPos0 = currentPlayer
758
arrayPos0 += playerCount
759
CallFunction(Player_ApplyShield)
760
end if
761
end if
762
end if
763
764
if player.state != Player_State_LookUp
765
if player.state != Player_State_Crouch
766
if player.lookPosY > 0
767
player.lookPosY -= 2
768
end if
769
770
if player.lookPosY < 0
771
player.lookPosY += 2
772
end if
773
end if
774
end if
775
776
if player.scrollDelay > 0
777
player.scrollDelay--
778
if player.scrollDelay == 0
779
if player.entityPos == camera[1].target
780
camera[1].style = CAMERASTYLE_FOLLOW
781
end if
782
end if
783
end if
784
785
if player.state != Player_State_Fly
786
if player.flightVelocity != 0
787
StopSfx(SfxName[Flying])
788
StopSfx(SfxName[Tired])
789
player.flightVelocity = 0
790
end if
791
end if
792
end function
793
794
795
// ========================
796
// Events
797
// ========================
798
799
event ObjectUpdate
800
if options.vsMode == false
801
CallFunction(Player_ProcessUpdateP2)
802
CallFunction(player.state)
803
ProcessAnimation()
804
805
CallFunction(TailsObject_ProcessTailSprite)
806
else
807
CallFunction(Player_ProcessUpdateP2_VS)
808
CallFunction(player.state)
809
810
// Bug Details:
811
// -> In the main Player Object script, the Drop Dash "animation" code in Origins would normally be here
812
// However, they had forgot to copy it over here too
813
// -> Because of that, using the Drop Dash as P2 Sonic in 2PVS means he doesn't always look quite right...
814
815
ProcessAnimation()
816
817
if player.character == PLAYER_TAILS_A
818
CallFunction(TailsObject_ProcessTailSprite)
819
end if
820
end if
821
822
// Bug Details:
823
// The code to set the jump ability state to 0 when you're on the ground isn't here
824
// This means when P2 jumps and lands without using their ability, their ability state is stored,
825
// allowing them to roll off of a ledge and use their ability out of it, which isn't intended
826
827
if player.entityPos == camera[1].target
828
if player.animation == ANI_JUMPING
829
camera[1].adjustY = player.jumpOffset
830
else
831
if camera[1].adjustY == player.jumpOffset
832
camera[1].adjustY = 0
833
player.iypos += player.jumpOffset
834
end if
835
end if
836
end if
837
838
if player.collisionDisabled == false
839
temp0 = player.prevGravity
840
player.prevGravity = player.gravity
841
ProcessObjectMovement()
842
player.prevGravity ^= GRAVITY_AIR
843
CheckEqual(player.gravity, GRAVITY_GROUND)
844
player.prevGravity |= checkResult
845
player.prevGravity ^= GRAVITY_AIR
846
847
if temp0 == GRAVITY_AIR
848
if player.prevGravity == GRAVITY_GROUND
849
player.badnikBonus = 0
850
if player.animation == ANI_JUMPING
851
if player.down == false
852
if player.state != Player_State_Roll
853
if player.state != Player_State_TubeRoll
854
player.animation = ANI_WALKING
855
if player.entityPos == camera[1].target
856
camera[1].adjustY = 0
857
end if
858
859
player.iypos += player.jumpOffset
860
end if
861
end if
862
end if
863
end if
864
end if
865
end if
866
else
867
player.collisionDisabled = false
868
end if
869
870
if options.vsMode == false
871
CallFunction(Player2_HandleSidekickRespawn)
872
end if
873
874
// Bug Details:
875
// Amy's hitbox handling function doesn't get called here, so P2 Amy never gets the extended hammer hitbox...
876
end event
877
878
879
event ObjectDraw
880
if player.animation != player.prevAnimation
881
player.prevAnimation = player.animation
882
player.frame = 0
883
player.animationTimer = 0
884
player.animationSpeed = 0
885
end if
886
887
if player.character == PLAYER_TAILS_A
888
if player.tailAnim != player.animation
889
if player.animation > ANI_LOOKINGDOWN
890
player.tailFrame = 0
891
end if
892
893
if player.tailAnim > ANI_LOOKINGDOWN
894
player.tailFrame = 0
895
end if
896
897
player.tailAnim = player.animation
898
end if
899
900
// Draw the Tails part of Tails
901
switch player.tailAnim
902
case 0 // ANI_STOPPED
903
if player.frame == 0
904
temp0 = player.tailFrame
905
temp0 >>= 3
906
if player.visible == true
907
DrawSpriteFX(temp0, FX_FLIP, player.xpos, player.ypos)
908
end if
909
end if
910
break
911
912
case 1 // ANI_WAITING
913
case 3 // ANI_LOOKINGUP
914
case 4 // ANI_LOOKINGDOWN
915
case 21 // ANI_HANGING
916
case 36 // ANI_CONTINUE
917
case 37 // ANI_CONTINUE_UP
918
temp0 = player.tailFrame
919
temp0 >>= 3
920
if player.visible == true
921
DrawSpriteFX(temp0, FX_FLIP, player.xpos, player.ypos)
922
end if
923
break
924
925
case 7 // ANI_SKIDDING
926
case 9 // ANI_SPINDASH
927
temp0 = player.tailFrame
928
temp0 >>= 2
929
temp0 += 11
930
if player.visible == true
931
DrawSpriteFX(temp0, FX_FLIP, player.xpos, player.ypos)
932
end if
933
break
934
935
case 10 // ANI_JUMPING
936
case 43 // Unknown, this was probably "SSRoll" in Sonic 1 before it got moved to its own ani file in that game
937
temp0 = player.tailFrame
938
temp0 >>= 2
939
CheckEqual(player.xvel, 0)
940
temp1 = checkResult
941
CheckEqual(player.yvel, 0)
942
temp1 &= checkResult
943
temp2 = player.rotation
944
if temp1 == false
945
ATan2(player.rotation, player.xvel, player.yvel)
946
player.rotation += 0x10
947
player.rotation &= 0xFF
948
player.rotation >>= 5
949
switch player.rotation
950
case 0
951
case 8
952
temp0 += 5
953
player.rotation = 0x00
954
break
955
956
case 1
957
temp0 += 8
958
if player.direction == FACING_RIGHT
959
player.rotation = 0x40
960
else
961
player.rotation = 0x00
962
end if
963
break
964
965
case 2
966
temp0 += 5
967
player.rotation = 0x40
968
break
969
970
case 3
971
temp0 += 8
972
if player.direction == FACING_RIGHT
973
player.rotation = 0x80
974
else
975
player.rotation = 0x40
976
end if
977
break
978
979
case 4
980
temp0 += 5
981
player.rotation = 0x80
982
break
983
984
case 5
985
temp0 += 8
986
if player.direction == FACING_RIGHT
987
player.rotation = 0xC0
988
else
989
player.rotation = 0x80
990
end if
991
break
992
993
case 6
994
temp0 += 5
995
player.rotation = 0xC0
996
break
997
998
case 7
999
temp0 += 8
1000
if player.direction == FACING_RIGHT
1001
player.rotation = 0x00
1002
else
1003
player.rotation = 0xC0
1004
end if
1005
break
1006
1007
end switch
1008
1009
if player.direction == FACING_LEFT
1010
player.rotation += 0x80
1011
end if
1012
else
1013
temp0 += 5
1014
player.rotation = 0x00
1015
end if
1016
1017
player.rotation <<= 1
1018
if player.visible == true
1019
DrawSpriteFX(temp0, FX_ROTATE, player.xpos, player.ypos)
1020
end if
1021
player.rotation = temp2
1022
break
1023
1024
case 17 // ANI_PUSHING
1025
temp0 = player.tailFrame
1026
temp0 /= 10
1027
temp0 += 11
1028
if player.visible == true
1029
DrawSpriteFX(temp0, FX_FLIP, player.xpos, player.ypos)
1030
end if
1031
break
1032
1033
end switch
1034
end if
1035
1036
DrawObjectAnimation()
1037
end event
1038
1039
1040
event ObjectStartup
1041
Player2Object_nextLeaderPosID = 1
1042
Player2Object_lastLeaderPosID = 0
1043
Player2Object_stateUp = 0
1044
Player2Object_stateDown = 0
1045
Player2Object_stateLeft = 0
1046
Player2Object_stateRight = 0
1047
Player2Object_stateJumpPress = 0
1048
Player2Object_stateJumpHold = 0
1049
1050
temp7 = false
1051
1052
if options.vsMode == true
1053
ResetObjectEntity(SLOT_PLAYER2, TypeName[Player 2 Object], 1, player[SLOT_PLAYER1].xpos, player[SLOT_PLAYER1].ypos)
1054
vs.restartX1 = player[SLOT_PLAYER1].xpos
1055
vs.restartY1 = player[SLOT_PLAYER1].ypos
1056
vs.restartX2 = player[SLOT_PLAYER1].xpos
1057
vs.restartY2 = player[SLOT_PLAYER1].ypos
1058
1059
player[SLOT_PLAYER2].groupID = GROUP_PLAYERS
1060
#platform: USE_STANDALONE
1061
player[SLOT_PLAYER2].state = Player_State_Air
1062
#endplatform
1063
#platform: USE_ORIGINS
1064
player[SLOT_PLAYER2].state = Player_State_Air_NoDropDash
1065
#endplatform
1066
player[SLOT_PLAYER2].priority = PRIORITY_ACTIVE
1067
#platform: USE_ORIGINS
1068
player[SLOT_PLAYER2].controlMode = CONTROLMODE_P2
1069
#endplatform
1070
player[SLOT_PLAYER2].drawOrder = DRAWORDER_PLAYER
1071
player[SLOT_PLAYER2].sortedDrawOrder = 4
1072
player[SLOT_PLAYER2].rollingDeceleration = 0x2000
1073
player[SLOT_PLAYER2].spindashFunction = Player_Action_Spindash
1074
1075
currentPlayer = SLOT_PLAYER2
1076
CallFunction(Player_UpdatePhysicsState)
1077
1078
player[SLOT_PLAYER2].hitboxTop = C_BOX
1079
player[SLOT_PLAYER2].hitboxBottom = C_BOX
1080
player[SLOT_PLAYER2].hitboxLeft = C_BOX
1081
player[SLOT_PLAYER2].hitboxRight = C_BOX
1082
1083
#platform: USE_ORIGINS
1084
camera[1].enabled = true
1085
camera[1].style = CAMERASTYLE_FOLLOW
1086
camera[1].target = SLOT_PLAYER2
1087
camera[1].xpos = player[SLOT_PLAYER2].ixpos
1088
camera[1].ypos = player[SLOT_PLAYER2].iypos
1089
#endplatform
1090
1091
switch vs.player2Type
1092
case PLAYER_SONIC_A
1093
LoadAnimation("Sonic.ani")
1094
player[SLOT_PLAYER2].character = PLAYER_SONIC_A
1095
player[SLOT_PLAYER2].jumpOffset = -5
1096
player[SLOT_PLAYER2].jumpAbility = Player_Action_DblJumpSonic
1097
ANI_PEELOUT = ANI_RUNNING
1098
break
1099
1100
case PLAYER_TAILS_A
1101
LoadAnimation("Tails.ani")
1102
player[SLOT_PLAYER2].character = PLAYER_TAILS_A
1103
player[SLOT_PLAYER2].jumpOffset = -1
1104
player[SLOT_PLAYER2].jumpAbility = Player_Action_DblJumpTails
1105
stage.player2Enabled = false
1106
break
1107
1108
case PLAYER_KNUCKLES_A
1109
LoadAnimation("Knuckles.ani")
1110
player[SLOT_PLAYER2].character = PLAYER_KNUCKLES_A
1111
player[SLOT_PLAYER2].jumpOffset = -5
1112
player[SLOT_PLAYER2].jumpAbility = Player_Action_DblJumpKnux
1113
ANI_PEELOUT = ANI_RUNNING
1114
break
1115
1116
#platform: USE_ORIGINS
1117
case PLAYER_AMY_A
1118
LoadAnimation("Amy.ani")
1119
player[SLOT_PLAYER2].character = PLAYER_AMY
1120
player[SLOT_PLAYER2].jumpOffset = -4
1121
player[SLOT_PLAYER2].jumpAbility = Player_Action_DblJumpAmy
1122
ANI_PEELOUT = ANI_RUNNING
1123
break
1124
#endplatform
1125
end switch
1126
1127
stage.player2Enabled = false
1128
playerCount = 2
1129
temp7 = true
1130
end if
1131
1132
if stage.player2Enabled == true
1133
ResetObjectEntity(SLOT_PLAYER2, TypeName[Player 2 Object], PLAYER_TAILS_A, player[SLOT_PLAYER1].xpos, player[SLOT_PLAYER1].ypos)
1134
if starPostID == 0
1135
// If at a level's start, then make Tails be 16 pixels left of Sonic
1136
player[SLOT_PLAYER2].xpos -= 0x100000
1137
end if
1138
1139
LoadAnimation("Tails.ani")
1140
player[SLOT_PLAYER2].groupID = GROUP_PLAYERS
1141
player[SLOT_PLAYER2].character = PLAYER_TAILS_A // Small note - this is redundant to the ResetObjectEntity line as that already sets Tails's character, it doesn't matter too much though
1142
#platform: USE_STANDALONE
1143
player[SLOT_PLAYER2].state = Player_State_Air
1144
#endplatform
1145
#platform: USE_ORIGINS
1146
player[SLOT_PLAYER2].state = Player_State_Air_NoDropDash
1147
#endplatform
1148
player[SLOT_PLAYER2].priority = PRIORITY_ACTIVE
1149
#platform: USE_STANDALONE
1150
player[SLOT_PLAYER2].controlMode = CONTROLMODE_P1
1151
#endplatform
1152
#platform: USE_ORIGINS
1153
player[SLOT_PLAYER2].controlMode = CONTROLMODE_P2
1154
#endplatform
1155
player[SLOT_PLAYER2].drawOrder = DRAWORDER_PLAYER
1156
player[SLOT_PLAYER2].sortedDrawOrder = 4
1157
1158
currentPlayer = SLOT_PLAYER2
1159
CallFunction(Player_UpdatePhysicsState)
1160
1161
player[SLOT_PLAYER2].rollingDeceleration = 0x2000
1162
player[SLOT_PLAYER2].jumpOffset = -1
1163
player[SLOT_PLAYER2].isSidekick = true
1164
player[SLOT_PLAYER2].jumpAbility = Player2_Action_DblJumpTailsAI
1165
player[SLOT_PLAYER2].spindashFunction = Player_Action_Spindash
1166
1167
CheckCurrentStageFolder("Continue")
1168
if checkResult == true
1169
player[SLOT_PLAYER2].p2InputFunction = Player2_Input_None
1170
else
1171
player[SLOT_PLAYER2].p2InputFunction = Player2_Input_AI_Follow
1172
end if
1173
1174
temp0 = 0
1175
while temp0 < 16
1176
SetTableValue(player[SLOT_PLAYER1].xpos, temp0, Player2Object_leaderPosBufferX)
1177
SetTableValue(player[SLOT_PLAYER1].ypos, temp0, Player2Object_leaderPosBufferY)
1178
temp0++
1179
loop
1180
1181
player[SLOT_PLAYER2].hitboxTop = C_BOX
1182
player[SLOT_PLAYER2].hitboxBottom = C_BOX
1183
player[SLOT_PLAYER2].hitboxLeft = C_BOX
1184
player[SLOT_PLAYER2].hitboxRight = C_BOX
1185
1186
temp7 = true
1187
1188
#platform: USE_ORIGINS
1189
AssignInputSlotToDevice(2, -1)
1190
#endplatform
1191
end if
1192
1193
if temp7 == true
1194
LoadSpriteSheet("Players/Tails1.gif")
1195
SpriteFrame(-22, -8, 16, 24, 82, 199)
1196
SpriteFrame(-26, -8, 20, 24, 99, 199)
1197
SpriteFrame(-26, -8, 20, 24, 120, 199)
1198
SpriteFrame(-26, -8, 20, 24, 141, 199)
1199
SpriteFrame(-26, -8, 20, 24, 162, 199)
1200
SpriteFrame(-35, -8, 24, 16, 231, 166)
1201
SpriteFrame(-35, -8, 24, 16, 231, 183)
1202
SpriteFrame(-35, -8, 24, 16, 231, 200)
1203
SpriteFrame(-25, 9, 20, 16, 235, 217)
1204
SpriteFrame(-25, 9, 18, 16, 237, 234)
1205
SpriteFrame(-25, 9, 20, 16, 216, 234)
1206
SpriteFrame(-30, -6, 24, 16, 231, 166)
1207
SpriteFrame(-30, -6, 24, 16, 231, 183)
1208
SpriteFrame(-30, -6, 24, 16, 231, 200)
1209
end if
1210
end event
1211
1212
1213
// ========================
1214
// Editor Events
1215
// ========================
1216
1217
event RSDKDraw
1218
DrawSprite(0)
1219
end event
1220
1221
1222
event RSDKLoad
1223
LoadSpriteSheet("Players/Tails1.gif")
1224
SpriteFrame(-16, -12, 24, 32, 1, 1)
1225
1226
// used in-game, but shouldn't be set from the editor
1227
SetVariableAlias(ALIAS_VAR_PROPVAL, "unused")
1228
end event
1229
1230