Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-1-Sonic-2-2013-Script-Decompilation
Path: blob/master/Sonic 1/Scripts/Players/Player2Object.txt
1480 views
1
// ----------------------------------
2
// RSDK Project: Sonic 1
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.state : player.state
15
private alias object.visible : player.visible
16
private alias object.propertyValue : player.character
17
private alias object.priority : player.priority
18
private alias object.xpos : player.xpos
19
private alias object.ypos : player.ypos
20
private alias object.iypos : player.iypos
21
private alias object.lookPosY : player.lookPosY
22
private alias object.xvel : player.xvel
23
private alias object.yvel : player.yvel
24
private alias object.speed : player.speed
25
private alias object.rotation : player.rotation
26
private alias object.angle : player.angle
27
private alias object.direction : player.direction
28
private alias object.gravity : player.gravity
29
private alias object.frame : player.frame
30
private alias object.animation : player.animation
31
private alias object.prevAnimation : player.prevAnimation
32
private alias object.animationSpeed : player.animationSpeed
33
private alias object.animationTimer : player.animationTimer
34
private alias object.drawOrder : player.drawOrder
35
private alias object.controlLock : player.controlLock
36
private alias object.controlMode : player.controlMode
37
private alias object.interaction : player.interaction
38
private alias object.collisionPlane : player.collisionPlane
39
private alias object.tileCollisions : player.tileCollisions
40
private alias object.outOfBounds : player.outOfBounds
41
42
private alias object.jumpPress : player.jumpPress
43
private alias object.jumpHold : player.jumpHold
44
private alias object.up : player.up
45
private alias object.down : player.down
46
private alias object.left : player.left
47
private alias object.right : player.right
48
49
// The majority of these are the same as the Player Object, though a couple - namely the last few - are different
50
private alias object.value1 : player.timer
51
private alias object.value3 : player.drownTimer
52
private alias object.value4 : player.drownLevel
53
private alias object.value7 : player.invincibleTimer
54
private alias object.value8 : player.blinkTimer
55
private alias object.value12 : player.tailFrame
56
private alias object.value13 : player.tailAnim
57
private alias object.value16 : player.isSidekick
58
private alias object.value18 : player.sortedDrawOrder
59
private alias object.value19 : player.badnikBonus
60
private alias object.value25 : player.gravityStrength
61
private alias object.value26 : player.flightVelocity
62
private alias object.value30 : player.jumpOffset
63
private alias object.value31 : player.rollingDeceleration
64
private alias object.value32 : player.jumpAbility
65
private alias object.value33 : player.actionSpindash
66
private alias object.value34 : player.collisionDisabled
67
private alias object.value40 : player.hitboxLeft
68
private alias object.value38 : player.hitboxTop
69
private alias object.value41 : player.hitboxRight
70
private alias object.value39 : player.hitboxBottom
71
private alias object.value42 : player.prevGravity
72
73
// These following values are exclusive to the Player 2 Object
74
// (Neat trivia - did you know that in the initial versions of the game, Origins's Drop Dash overlapped with these values?
75
// That's why Tails wouldn't respawn a lot of the time, since every time he jumped his Drop Dash timer,
76
// which overlapped with his respawn timer, would also reset. Nowadays though, the Drop Dash is a global var instead)
77
private alias object.value43 : player.jumpInTimer
78
private alias object.value44 : player.stateInputP2
79
private alias object.value45 : player.autoJumpTimer
80
private alias object.value46 : player.targetLeaderPos.x
81
private alias object.value47 : player.targetLeaderPos.y
82
83
// Draw Order Aliases
84
private alias -1 : DRAWORDER_PLAYER
85
86
// player.character Aliases
87
private alias 1 : CHARACTER_TAILS
88
89
// Reserved Object Slots
90
private alias 0 : SLOT_PLAYER1
91
private alias 1 : SLOT_PLAYER2
92
93
94
// ========================
95
// Function Declarations
96
// ========================
97
98
reserve function Player2_GetDelayedInput
99
reserve function Player2_Input_GamepadAssist
100
reserve function Player2_Input_AI_Follow
101
reserve function Player2_Input_AI_SpindashPt1
102
reserve function Player2_Input_AI_SpindashPt2
103
reserve function Player2_State_FlyToPlayer
104
reserve function Player2_HandleSidekickRespawn
105
reserve function Player2_ProcessUpdateP2
106
reserve function Player2_Input_None
107
reserve function Player2_Action_DblJumpTailsAI
108
109
110
// ========================
111
// Static Values
112
// ========================
113
114
public value Player2_stateUp = 0
115
public value Player2_stateDown = 0
116
public value Player2_stateLeft = 0
117
public value Player2_stateRight = 0
118
public value Player2_stateJumpPress = 0
119
public value Player2_stateJumpHold = 0
120
public value Player2_nextLeaderPosID = 0
121
public value Player2_lastLeaderPosID = 0
122
123
124
// ========================
125
// Tables
126
// ========================
127
128
public table Player2_leaderPosBufferX[16]
129
public table Player2_leaderPosBufferY[16]
130
131
132
// ========================
133
// Function Definitions
134
// ========================
135
136
public function Player2_Input_None
137
temp0 = 0
138
end function
139
140
141
public function Player2_Action_DblJumpTailsAI
142
CheckNotEqual(player.stateInputP2, Player2_Input_None)
143
temp0 = checkResult
144
#platform: USE_ORIGINS
145
CheckNotEqual(player.stateInputP2, Player2_Input_GamepadAssist)
146
temp0 &= checkResult
147
#endplatform
148
CheckNotEqual(player.up, true)
149
temp0 &= checkResult
150
if temp0 == false
151
CallFunction(Player_Action_DblJumpTails)
152
end if
153
end function
154
155
156
public function Player2_GetDelayedInput
157
if player.controlMode > CONTROLMODE_NONE
158
Player2_stateUp <<= 1
159
Player2_stateUp |= player[SLOT_PLAYER1].up
160
Player2_stateUp &= 0xFFFF
161
Player2_stateDown <<= 1
162
Player2_stateDown |= player[SLOT_PLAYER1].down
163
Player2_stateDown &= 0xFFFF
164
Player2_stateLeft <<= 1
165
Player2_stateLeft |= player[SLOT_PLAYER1].left
166
Player2_stateLeft &= 0xFFFF
167
Player2_stateRight <<= 1
168
Player2_stateRight |= player[SLOT_PLAYER1].right
169
Player2_stateRight &= 0xFFFF
170
Player2_stateJumpPress <<= 1
171
Player2_stateJumpPress |= player[SLOT_PLAYER1].jumpPress
172
Player2_stateJumpPress &= 0xFFFF
173
Player2_stateJumpHold <<= 1
174
Player2_stateJumpHold |= player[SLOT_PLAYER1].jumpHold
175
Player2_stateJumpHold &= 0xFFFF
176
177
if player[SLOT_PLAYER1].state == Player_State_Carried
178
Player2_stateDown <<= 15
179
Player2_stateLeft <<= 15
180
Player2_stateRight <<= 15
181
Player2_stateJumpPress <<= 15
182
Player2_stateJumpHold <<= 15
183
end if
184
185
temp0 = Player2_stateUp
186
temp0 >>= 15
187
player.up = temp0
188
189
temp0 = Player2_stateDown
190
temp0 >>= 15
191
player.down = temp0
192
193
temp0 = Player2_stateLeft
194
temp0 >>= 15
195
player.left = temp0
196
197
temp0 = Player2_stateRight
198
temp0 >>= 15
199
player.right = temp0
200
201
temp0 = Player2_stateJumpPress
202
temp0 >>= 15
203
player.jumpPress = temp0
204
205
temp0 = Player2_stateJumpHold
206
temp0 >>= 15
207
player.jumpHold = temp0
208
else
209
Player2_stateUp = 0
210
Player2_stateDown = 0
211
Player2_stateLeft = 0
212
Player2_stateRight = 0
213
Player2_stateJumpPress = 0
214
Player2_stateJumpHold = 0
215
end if
216
217
if player[SLOT_PLAYER1].state != Player_State_Death
218
if player[SLOT_PLAYER1].type != TypeName[Death Event]
219
SetTableValue(player[SLOT_PLAYER1].xpos, Player2_lastLeaderPosID, Player2_leaderPosBufferX)
220
SetTableValue(player[SLOT_PLAYER1].ypos, Player2_lastLeaderPosID, Player2_leaderPosBufferY)
221
Player2_lastLeaderPosID++
222
Player2_lastLeaderPosID &= 15
223
Player2_nextLeaderPosID++
224
Player2_nextLeaderPosID &= 15
225
226
// (check if P1's in the air this frame while they weren't last frame)
227
CheckEqual(player[SLOT_PLAYER1].gravity, GRAVITY_AIR)
228
temp0 = checkResult
229
CheckEqual(player[SLOT_PLAYER1].prevGravity, GRAVITY_GROUND)
230
temp0 &= checkResult
231
if temp0 == false
232
GetTableValue(player.targetLeaderPos.x, Player2_nextLeaderPosID, Player2_leaderPosBufferX)
233
GetTableValue(player.targetLeaderPos.y, Player2_nextLeaderPosID, Player2_leaderPosBufferY)
234
else
235
player.targetLeaderPos.x = player[SLOT_PLAYER1].xpos
236
player.targetLeaderPos.y = player[SLOT_PLAYER1].ypos
237
end if
238
else
239
temp0 = Player2_lastLeaderPosID
240
temp0--
241
if temp0 < 0
242
temp0 += 16
243
end if
244
245
GetTableValue(player.targetLeaderPos.x, temp0, Player2_leaderPosBufferX)
246
GetTableValue(player.targetLeaderPos.y, temp0, Player2_leaderPosBufferY)
247
end if
248
else
249
temp0 = Player2_lastLeaderPosID
250
temp0--
251
if temp0 < 0
252
temp0 += 16
253
end if
254
255
GetTableValue(player.targetLeaderPos.x, temp0, Player2_leaderPosBufferX)
256
GetTableValue(player.targetLeaderPos.y, temp0, Player2_leaderPosBufferY)
257
end if
258
end function
259
260
261
public function Player2_Input_GamepadAssist
262
#platform: USE_ORIGINS
263
IsInputSlotAssigned(2)
264
if checkResult == false
265
player.stateInputP2 = Player2_Input_AI_Follow
266
AssignInputSlotToDevice(2, -1)
267
return
268
end if
269
270
ProcessObjectControl()
271
272
temp0 = player.up
273
temp0 |= player.down
274
temp0 |= player.left
275
temp0 |= player.right
276
temp0 |= player.jumpHold
277
if temp0 == false
278
player.autoJumpTimer++
279
if player.autoJumpTimer >= 600
280
player.stateInputP2 = Player2_Input_AI_Follow
281
AssignInputSlotToDevice(2, -1)
282
end if
283
else
284
player.autoJumpTimer = 0
285
end if
286
#endplatform
287
end function
288
289
290
public function Player2_Input_AI_Follow
291
CallFunction(Player2_GetDelayedInput)
292
if player[SLOT_PLAYER1].type == TypeName[Player Object]
293
temp0 = player.angle
294
temp0 += 16
295
temp0 &= 0xE0
296
if temp0 == 0
297
if player.left == true
298
temp0 = player[SLOT_PLAYER1].xpos
299
temp0 -= 0x80000
300
if player.xpos < temp0
301
if player.xvel <= 0
302
player.left = false
303
end if
304
end if
305
end if
306
307
if player.right == true
308
temp0 = player[SLOT_PLAYER1].xpos
309
temp0 += 0x80000
310
if player.xpos > temp0
311
if player.yvel <= 0
312
player.right = false
313
end if
314
end if
315
end if
316
end if
317
318
if player[SLOT_PLAYER1].state != Player_State_Carried
319
temp0 = player.targetLeaderPos.x
320
temp1 = player[SLOT_PLAYER1].gravity
321
temp1 |= player[SLOT_PLAYER1].prevGravity
322
if temp1 == GRAVITY_GROUND
323
if player[SLOT_PLAYER1].speed < 0x20000
324
if player[SLOT_PLAYER1].speed > -0x20000
325
if player[SLOT_PLAYER1].direction == FACING_RIGHT
326
temp0 -= 0x200000
327
else
328
temp0 += 0x200000
329
end if
330
end if
331
end if
332
end if
333
334
temp0 -= player.xpos
335
if temp0 != 0
336
if temp0 < 0
337
if temp0 <= -0x300000
338
player.right = false
339
player.left = true
340
end if
341
342
if player.speed != 0
343
if player.direction == FACING_LEFT
344
Cos256(temp1, player.angle)
345
temp1 *= 0xC0
346
player.xpos -= temp1
347
end if
348
end if
349
else
350
if temp0 >= 0x300000
351
player.left = false
352
player.right = true
353
end if
354
355
if player.speed != 0
356
if player.direction == FACING_RIGHT
357
Cos256(temp1, player.angle)
358
temp1 *= 0xC0
359
player.xpos += temp1
360
end if
361
end if
362
end if
363
end if
364
365
if player.animation == ANI_PUSHING
366
player.autoJumpTimer++
367
if player[SLOT_PLAYER1].direction == player.direction
368
if player[SLOT_PLAYER1].animation == ANI_PUSHING
369
player.autoJumpTimer = 0
370
end if
371
end if
372
373
if player.autoJumpTimer >= 30
374
if player.gravity == GRAVITY_GROUND
375
CallFunction(Player_Action_Jump)
376
end if
377
player.timer = 0
378
player.autoJumpTimer = 0
379
end if
380
else
381
temp0 = player.ypos
382
temp0 -= player.targetLeaderPos.y
383
if temp0 > 0x200000
384
player.autoJumpTimer++
385
if player.autoJumpTimer >= 64
386
if player.gravity == GRAVITY_GROUND
387
CallFunction(Player_Action_Jump)
388
end if
389
player.timer = 0
390
player.autoJumpTimer = 0
391
end if
392
else
393
player.autoJumpTimer = 0
394
end if
395
end if
396
397
if player.controlLock > 0
398
if player.speed < 0x8000
399
if player.speed > -0x8000
400
player.stateInputP2 = Player2_Input_AI_SpindashPt1
401
end if
402
end if
403
end if
404
end if
405
end if
406
407
#platform: USE_ORIGINS
408
// Look for any input from controller 2
409
temp0 = keyDown[2].up
410
temp0 |= keyDown[2].down
411
temp0 |= keyDown[2].left
412
temp0 |= keyDown[2].right
413
temp0 |= keyDown[2].buttonA
414
temp0 |= keyDown[2].buttonB
415
temp0 |= keyDown[2].buttonC
416
417
if temp0 == true
418
// Enable P2 controls
419
player.autoJumpTimer = 0
420
player.stateInputP2 = Player2_Input_GamepadAssist
421
end if
422
#endplatform
423
end function
424
425
426
public function Player2_Input_AI_SpindashPt1
427
player.up = false
428
player.down = false
429
player.left = false
430
player.right = false
431
player.jumpPress = false
432
player.jumpHold = false
433
if player.controlLock == 0
434
if player.gravity == GRAVITY_GROUND
435
if player.speed < 0x4000
436
if player.speed > -0x4000
437
player.stateInputP2 = Player2_Input_AI_SpindashPt2
438
player.autoJumpTimer = 1
439
if player.animation != ANI_SPINDASH
440
if player.xpos < player.targetLeaderPos.x
441
player.direction = FACING_RIGHT
442
else
443
player.direction = FACING_LEFT
444
end if
445
446
player.down = true
447
end if
448
end if
449
end if
450
end if
451
end if
452
end function
453
454
455
public function Player2_Input_AI_SpindashPt2
456
if player.autoJumpTimer < 64
457
player.down = true
458
temp0 = player.autoJumpTimer
459
temp0 &= 15
460
if temp0 == 0
461
player.jumpPress = true
462
else
463
player.jumpPress = false
464
end if
465
player.autoJumpTimer++
466
else
467
player.autoJumpTimer = 0
468
player.down = false
469
player.jumpPress = false
470
player.stateInputP2 = Player2_Input_AI_Follow
471
end if
472
end function
473
474
475
public function Player2_State_FlyToPlayer
476
CallFunction(Player2_GetDelayedInput)
477
if player.gravityStrength == 0x3800
478
player.animation = ANI_FLYING
479
else
480
player.animation = ANI_SWIMMING
481
end if
482
483
temp0 = player.targetLeaderPos.x
484
temp0 -= player.xpos
485
temp1 = temp0
486
temp0 >>= 4
487
488
if player.xpos < player.targetLeaderPos.x
489
player.direction = FACING_RIGHT
490
if temp0 > 0xC0000
491
temp0 = 0xC0000
492
end if
493
494
if player[SLOT_PLAYER1].xvel > 0
495
temp0 += player[SLOT_PLAYER1].xvel
496
end if
497
498
temp0 += 0x10000
499
if temp0 > temp1
500
temp0 = temp1
501
temp1 = 0
502
end if
503
else
504
player.direction = FACING_LEFT
505
if temp0 < -0xC0000
506
temp0 = -0xC0000
507
end if
508
509
if player[SLOT_PLAYER1].xvel < 0
510
temp0 += player[SLOT_PLAYER1].xvel
511
end if
512
513
temp0 -= 0x10000
514
if temp0 < temp1
515
temp0 = temp1
516
temp1 = 0
517
end if
518
end if
519
player.xpos += temp0
520
521
if player.ypos < player.targetLeaderPos.y
522
player.ypos += 0x10000
523
end if
524
525
if player.ypos > player.targetLeaderPos.y
526
player.ypos -= 0x10000
527
end if
528
529
if player[SLOT_PLAYER1].type != TypeName[Death Event]
530
if player[SLOT_PLAYER1].state != Player_State_Death
531
if player[SLOT_PLAYER1].state != Player_State_Drown
532
if player[SLOT_PLAYER1].state != Player_State_TubeRoll
533
if temp1 == 0
534
temp0 = player.targetLeaderPos.y
535
temp0 -= player.ypos
536
if temp0 < 0
537
FlipSign(temp0)
538
end if
539
540
if temp0 < 0x20000
541
#platform: USE_STANDALONE
542
player.state = Player_State_Air
543
#endplatform
544
#platform: USE_ORIGINS
545
player.state = Player_State_Air_NoDropDash
546
#endplatform
547
548
player.animation = ANI_JUMPING
549
player.gravity = GRAVITY_AIR
550
player.tileCollisions = true
551
player.interaction = true
552
player.controlMode = CONTROLMODE_P2
553
player.controlLock = 0
554
player.angle = 0
555
player.stateInputP2 = Player2_Input_AI_Follow
556
player.collisionPlane = player[SLOT_PLAYER1].collisionPlane
557
Player2_stateUp = 0
558
Player2_stateDown = 0
559
Player2_stateLeft = 0
560
Player2_stateRight = 0
561
Player2_stateJumpPress = 0
562
Player2_stateJumpHold = 0
563
end if
564
end if
565
end if
566
end if
567
end if
568
end if
569
end function
570
571
572
public function Player2_HandleSidekickRespawn
573
if player[SLOT_PLAYER1].type == TypeName[Player Object]
574
if player.outOfBounds == true
575
player.jumpInTimer++
576
else
577
player.jumpInTimer = 0
578
end if
579
580
if player.jumpInTimer >= 240
581
player.jumpInTimer = 0
582
player.state = Player2_State_FlyToPlayer
583
player.xpos = player[SLOT_PLAYER1].xpos
584
player.ypos = screen.yoffset
585
player.ypos -= 128
586
player.ypos <<= 16
587
player.xvel = 0
588
player.yvel = 0
589
player.speed = 0
590
player.tileCollisions = false
591
player.interaction = false
592
player.controlMode = CONTROLMODE_P2
593
player.sortedDrawOrder = 4
594
player.drownTimer = 0
595
player.drownLevel = 0
596
end if
597
598
CheckEqual(player[SLOT_PLAYER1].state, Player_State_Death)
599
temp0 = checkResult
600
CheckEqual(player[SLOT_PLAYER1].type, TypeName[Death Event])
601
temp0 |= checkResult
602
CheckNotEqual(player.state, Player_State_Hurt)
603
temp0 &= checkResult
604
CheckNotEqual(player.state, Player_State_Death)
605
temp0 &= checkResult
606
if temp0 == true
607
player.jumpInTimer = 0
608
player.state = Player2_State_FlyToPlayer
609
player.xvel = 0
610
player.yvel = 0
611
player.speed = 0
612
player.tileCollisions = false
613
player.interaction = false
614
end if
615
end if
616
end function
617
618
619
public function Player2_ProcessUpdateP2
620
if player.state == Player_State_Death
621
player.stateInputP2 = Player2_Input_None
622
end if
623
624
if player.state == Player_State_Drown
625
player.stateInputP2 = Player2_Input_None
626
end if
627
628
CallFunction(player.stateInputP2)
629
630
if player.state != Player_State_Hurt
631
if player.blinkTimer > 0
632
player.blinkTimer--
633
GetBit(temp0, player.blinkTimer, 2)
634
if temp0 == true
635
player.visible = false
636
else
637
player.visible = true
638
end if
639
end if
640
end if
641
642
if player.invincibleTimer > 0
643
if player.state != Player_State_Hurt
644
if player.invincibleTimer > 2000
645
player.invincibleTimer = 120
646
player.blinkTimer = 3
647
end if
648
end if
649
650
player.invincibleTimer--
651
if player.invincibleTimer == 0
652
player.blinkTimer = 0
653
player.visible = true
654
end if
655
end if
656
657
if player.state != Player_State_LookUp
658
if player.state != Player_State_Crouch
659
// P2 is never a camera target so this doesn't matter much anyways, but may as well
660
661
if player.lookPosY > 0
662
player.lookPosY -= 2
663
end if
664
665
if player.lookPosY < 0
666
player.lookPosY += 2
667
end if
668
end if
669
end if
670
671
if player.state != Player_State_Fly
672
if player.flightVelocity != 0
673
StopSfx(SfxName[Flying])
674
StopSfx(SfxName[Tired])
675
player.flightVelocity = 0
676
end if
677
end if
678
end function
679
680
681
// ========================
682
// Events
683
// ========================
684
685
event ObjectUpdate
686
CallFunction(Player2_ProcessUpdateP2)
687
CallFunction(player.state)
688
ProcessAnimation()
689
CallFunction(TailsObject_ProcessTailSprite)
690
691
if player.collisionDisabled == false
692
temp0 = player.prevGravity
693
player.prevGravity = player.gravity
694
ProcessObjectMovement()
695
player.prevGravity ^= GRAVITY_AIR
696
CheckEqual(player.gravity, GRAVITY_GROUND)
697
player.prevGravity |= checkResult
698
player.prevGravity ^= GRAVITY_AIR
699
if temp0 == GRAVITY_AIR
700
if player.prevGravity == GRAVITY_GROUND
701
player.badnikBonus = 0
702
if player.animation == ANI_JUMPING
703
if player.down == false
704
if player.state != Player_State_Roll
705
if player.state != Player_State_TubeRoll
706
player.animation = ANI_WALKING
707
player.iypos += player.jumpOffset
708
end if
709
end if
710
end if
711
end if
712
end if
713
end if
714
else
715
player.collisionDisabled = false
716
end if
717
718
CallFunction(Player2_HandleSidekickRespawn)
719
end event
720
721
722
event ObjectDraw
723
if player.animation != player.prevAnimation
724
player.prevAnimation = player.animation
725
player.frame = 0
726
player.animationTimer = 0
727
player.animationSpeed = 0
728
end if
729
730
if player.tailAnim != player.animation
731
if player.animation > 4 // worth noting that it uses the raw number directly rather than the ANI_* variables... (for ref - note that 4 is ANI_LOOKINGDOWN)
732
player.tailFrame = 0
733
end if
734
735
if player.tailAnim > 4
736
player.tailFrame = 0
737
end if
738
739
player.tailAnim = player.animation
740
end if
741
742
// Draw the Tails part of Tails
743
switch player.tailAnim
744
case 0 // ANI_STOPPED
745
if player.frame == 0
746
temp0 = player.tailFrame
747
temp0 >>= 3
748
if player.visible == true
749
DrawSpriteFX(temp0, FX_FLIP, player.xpos, player.ypos)
750
end if
751
end if
752
break
753
754
case 1 // ANI_WAITING
755
case 3 // ANI_LOOKINGUP
756
case 4 // ANI_LOOKINGDOWN
757
case 37 // ANI_CONTINUE_UP
758
temp0 = player.tailFrame
759
temp0 >>= 3
760
if player.visible == true
761
DrawSpriteFX(temp0, FX_FLIP, player.xpos, player.ypos)
762
end if
763
break
764
765
case 7 // ANI_SKIDDING
766
case 9 // ANI_SPINDASH
767
temp0 = player.tailFrame
768
temp0 >>= 2
769
temp0 += 11
770
if player.visible == true
771
DrawSpriteFX(temp0, FX_FLIP, player.xpos, player.ypos)
772
end if
773
break
774
775
case 10 // ANI_JUMPING
776
case 43 // Unknown, this was probably "SSRoll" before it got moved to its own ani file
777
temp0 = player.tailFrame
778
temp0 >>= 2
779
CheckEqual(player.xvel, 0)
780
temp1 = checkResult
781
CheckEqual(player.yvel, 0)
782
temp1 &= checkResult
783
temp2 = player.rotation
784
if temp1 == 0
785
ATan2(player.rotation, player.xvel, player.yvel)
786
player.rotation += 16
787
player.rotation &= 255
788
player.rotation >>= 5
789
switch player.rotation
790
case 0
791
case 8
792
temp0 += 5
793
player.rotation = 0x00
794
break
795
796
case 1
797
temp0 += 8
798
if player.direction == FACING_RIGHT
799
player.rotation = 0x40
800
else
801
player.rotation = 0x00
802
end if
803
break
804
805
case 2
806
temp0 += 5
807
player.rotation = 0x40
808
break
809
810
case 3
811
temp0 += 8
812
if player.direction == FACING_RIGHT
813
player.rotation = 0x80
814
else
815
player.rotation = 0x40
816
end if
817
break
818
819
case 4
820
temp0 += 5
821
player.rotation = 0x80
822
break
823
824
case 5
825
temp0 += 8
826
if player.direction == FACING_RIGHT
827
player.rotation = 0xC0
828
else
829
player.rotation = 0x80
830
end if
831
break
832
833
case 6
834
temp0 += 5
835
player.rotation = 0xC0
836
break
837
838
case 7
839
temp0 += 8
840
if player.direction == FACING_RIGHT
841
player.rotation = 0x00
842
else
843
player.rotation = 0xC0
844
end if
845
break
846
end switch
847
848
if player.direction == FACING_LEFT
849
player.rotation += 128
850
end if
851
else
852
temp0 += 5
853
player.rotation = 0x00
854
end if
855
856
player.rotation <<= 1
857
if player.visible == true
858
DrawSpriteFX(temp0, FX_ROTATE, player.xpos, player.ypos)
859
end if
860
player.rotation = temp2
861
break
862
863
case 17 // ANI_PUSHING
864
temp0 = player.tailFrame
865
temp0 /= 10
866
temp0 += 11
867
if player.visible == true
868
DrawSpriteFX(temp0, FX_FLIP, player.xpos, player.ypos)
869
end if
870
break
871
872
end switch
873
874
// Draw Tails himself
875
// (Separate tails are drawn in the process above)
876
DrawObjectAnimation()
877
end event
878
879
880
event ObjectStartup
881
Player2_nextLeaderPosID = 1
882
Player2_lastLeaderPosID = 0
883
Player2_stateUp = 0
884
Player2_stateDown = 0
885
Player2_stateLeft = 0
886
Player2_stateRight = 0
887
Player2_stateJumpPress = 0
888
Player2_stateJumpHold = 0
889
890
if stage.player2Enabled == true
891
// Always make P2 start 16 pixels to the left of P1, regardless of if a P2 object is placed in the scene or not
892
// (It should never be anyway, but MZ1 does a few way OOB for some reason...)
893
ResetObjectEntity(SLOT_PLAYER2, TypeName[Player 2 Object], 1, player[SLOT_PLAYER1].xpos, player[SLOT_PLAYER1].ypos)
894
player[SLOT_PLAYER2].xpos -= 0x100000
895
896
// We're using the ani for Tails's main sprites, and the Sprite Frames for his Tails
897
LoadSpriteSheet("Players/Tails1.gif")
898
LoadAnimation("Tails.ani")
899
900
SpriteFrame(-22, -8, 16, 24, 82, 199)
901
SpriteFrame(-26, -8, 20, 24, 99, 199)
902
SpriteFrame(-26, -8, 20, 24, 120, 199)
903
SpriteFrame(-26, -8, 20, 24, 141, 199)
904
SpriteFrame(-26, -8, 20, 24, 162, 199)
905
SpriteFrame(-35, -8, 24, 16, 231, 166)
906
SpriteFrame(-35, -8, 24, 16, 231, 183)
907
SpriteFrame(-35, -8, 24, 16, 231, 200)
908
SpriteFrame(-25, 9, 20, 16, 235, 217)
909
SpriteFrame(-25, 9, 18, 16, 237, 234)
910
SpriteFrame(-25, 9, 20, 16, 216, 234)
911
SpriteFrame(-30, -6, 24, 16, 231, 166)
912
SpriteFrame(-30, -6, 24, 16, 231, 183)
913
SpriteFrame(-30, -6, 24, 16, 231, 200)
914
915
player[SLOT_PLAYER2].groupID = GROUP_PLAYERS
916
player[SLOT_PLAYER2].character = CHARACTER_TAILS
917
#platform: USE_STANDALONE
918
player[SLOT_PLAYER2].state = Player_State_Air
919
#endplatform
920
#platform: USE_ORIGINS
921
player[SLOT_PLAYER2].state = Player_State_Air_NoDropDash
922
#endplatform
923
player[SLOT_PLAYER2].priority = PRIORITY_ACTIVE
924
#platform: USE_STANDALONE
925
player[SLOT_PLAYER2].controlMode = CONTROLMODE_P1
926
#endplatform
927
#platform: USE_ORIGINS
928
player[SLOT_PLAYER2].controlMode = CONTROLMODE_P2
929
#endplatform
930
player[SLOT_PLAYER2].drawOrder = DRAWORDER_PLAYER
931
player[SLOT_PLAYER2].sortedDrawOrder = 4
932
currentPlayer = SLOT_PLAYER2
933
CallFunction(Player_UpdatePhysicsState)
934
player[SLOT_PLAYER2].rollingDeceleration = 0x2000
935
player[SLOT_PLAYER2].jumpOffset = -1
936
player[SLOT_PLAYER2].isSidekick = true
937
player[SLOT_PLAYER2].jumpAbility = Player2_Action_DblJumpTailsAI
938
939
if options.spindash == true
940
player[SLOT_PLAYER2].actionSpindash = Player_Action_Spindash
941
else
942
player[SLOT_PLAYER2].actionSpindash = Player_Action_Jump
943
end if
944
945
CheckCurrentStageFolder("Continue")
946
if checkResult == true
947
player[SLOT_PLAYER2].stateInputP2 = Player2_Input_None
948
else
949
player[SLOT_PLAYER2].stateInputP2 = Player2_Input_AI_Follow
950
end if
951
952
// Reset the position buffer table, fill it up with P1's starting position for now
953
temp0 = 0
954
while temp0 < 16
955
SetTableValue(player[SLOT_PLAYER1].xpos, temp0, Player2_leaderPosBufferX)
956
SetTableValue(player[SLOT_PLAYER1].ypos, temp0, Player2_leaderPosBufferY)
957
temp0++
958
loop
959
960
// Set player hitboxes
961
player[SLOT_PLAYER2].hitboxLeft = C_BOX
962
player[SLOT_PLAYER2].hitboxRight = C_BOX
963
player[SLOT_PLAYER2].hitboxTop = C_BOX
964
player[SLOT_PLAYER2].hitboxBottom = C_BOX
965
966
#platform: USE_ORIGINS
967
AssignInputSlotToDevice(2, -1)
968
#endplatform
969
end if
970
end event
971
972
973
// ========================
974
// Editor Events
975
// ========================
976
977
event RSDKDraw
978
DrawSprite(0)
979
end event
980
981
982
event RSDKLoad
983
LoadSpriteSheet("Players/Tails1.gif")
984
SpriteFrame(-22, -8, 16, 24, 82, 199) // snip
985
986
SetVariableAlias(ALIAS_VAR_PROPVAL, "unused")
987
end event
988
989