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/GHZ/CheckeredBall.txt
1481 views
1
// ----------------------------------
2
// RSDK Project: Sonic 1
3
// Script Description: Checkered Ball Object
4
// Script Author: Christian Whitehead/Simon Thomley
5
// Unpacked by Rubberduckycooly's script unpacker
6
// ----------------------------------
7
8
// While the rest of GHZ is structed like v3-esque objects, this one was *definitely* made afterwards, given how it is
9
// Makes sense though, since it's just a little bonus added in post
10
11
// ========================
12
// Aliases
13
// ========================
14
15
private alias object.value1 : object.roundedPos.x
16
private alias object.value2 : object.roundedPos.y
17
private alias object.value3 : object.ballAngle
18
private alias object.value4 : object.groundAngle
19
private alias object.value5 : object.angleVel
20
private alias object.value6 : object.playerControlled
21
private alias object.value7 : object.startPos.x
22
private alias object.value8 : object.startPos.y
23
// value9 is unused
24
private alias object.value10 : object.activePlayers
25
private alias object.value11 : object.badnikBonus
26
private alias object.value12 : object.collisionOffset.x
27
private alias object.value13 : object.collisionOffset.y
28
private alias object.value14 : object.wreckingBallPos.x
29
private alias object.value15 : object.wreckingBallPos.y
30
31
// Player Aliases
32
private alias object.xpos : player.xpos
33
private alias object.ypos : player.ypos
34
private alias object.xvel : player.xvel
35
private alias object.yvel : player.yvel
36
private alias object.speed : player.speed
37
private alias object.right : player.right
38
private alias object.left : player.left
39
private alias object.gravity : player.gravity
40
private alias object.pushing : player.pushing
41
private alias object.controlLock : player.controlLock
42
private alias object.controlMode : player.controlMode
43
private alias object.collisionLeft : player.collisionLeft
44
private alias object.collisionRight : player.collisionRight
45
46
private alias object.value20 : player.topSpeed
47
private alias object.value21 : player.acceleration
48
49
// Super States
50
private alias 1 : SUPERSTATE_SUPER
51
private alias 2 : SUPERSTATE_UNTRANSFORM
52
53
// Newtron Fly Aliases
54
private alias 2 : NEWTRONFLY_APPEARED
55
private alias 3 : NEWTRONFLY_MOVING
56
57
// Newtron Shoot Aliases
58
private alias 2 : NEWTRONSHOOT_SHOOT
59
private alias 3 : NEWTRONSHOOT_SHOOTDELAY
60
61
// Monitor Aliases
62
private alias object.value0 : monitor.contentsPos.y
63
private alias object.value1 : monitor.timer
64
65
private alias 0 : MONITOR_STATE_IDLE
66
67
// Spring Aliases
68
private alias object.value0 : spring.timer
69
private alias object.value1 : spring.active
70
private alias object.value2 : spring.extraVelocity
71
72
// Plane Sw V Aliases
73
private alias object.value0 : planeSwV.extendTop
74
private alias object.value1 : planeSwV.extendBottom
75
private alias object.value2 : planeSwV.planeR
76
private alias object.value3 : planeSwV.planeL
77
private alias object.value4 : planeSwV.drawOrderR
78
private alias object.value5 : planeSwV.drawOrderL
79
private alias object.value6 : planeSwV.onGround
80
81
private alias object.value0 : planeSwV.extendLeft
82
private alias object.value1 : planeSwV.extendRight
83
84
// Plane Sw H Aliases
85
private alias object.value0 : planeSwH.extendLeft
86
private alias object.value1 : planeSwH.extendRight
87
private alias object.value2 : planeSwH.planeR
88
private alias object.value3 : planeSwH.planeL
89
private alias object.value4 : planeSwH.drawOrderR
90
private alias object.value5 : planeSwH.drawOrderL
91
private alias object.value6 : planeSwH.onGround
92
93
// CLedge Aliases
94
private alias 0 : CLEDGE_ACTIVE
95
private alias 1 : CLEDGE_COLLAPSE
96
private alias 3 : CLEDGE_NONE
97
98
// Bridge Aliases
99
private alias object.value0 : bridge.activePlayerCount
100
private alias object.value1 : bridge.timer
101
private alias object.value2 : bridge.stoodPos
102
private alias object.value3 : bridge.depression
103
private alias object.value4 : bridge.bridgeDepth
104
private alias object.value5 : bridge.playerID
105
private alias object.value6 : bridge.startPos
106
private alias object.value7 : bridge.endPos
107
108
// FallPlatform Aliases
109
private alias object.value0 : fallPlatform.stood
110
private alias object.value1 : fallPlatform.collisionOffset.y
111
112
// HPlatform Aliases
113
private alias object.value0 : hPlatform.stood
114
private alias object.value3 : hPlatform.collisionOffset.x
115
private alias object.value4 : hPlatform.collisionOffset.y
116
117
// VPlatform Aliases
118
private alias object.value1 : vPlatform.collisionOffset.y
119
120
// VPlatform2 Aliases
121
private alias object.value1 : vPlatform2.collisionOffset.y
122
123
// SwingPlatform
124
private alias object.value1 : swingPlatform.drawPos.x
125
private alias object.value2 : swingPlatform.drawPos.y
126
private alias object.value3 : swingPlatform.collisionOffset.x
127
private alias object.value4 : swingPlatform.collisionOffset.y
128
129
// GHZEggman Aliases
130
private alias object.value0 : ghzEggman.timer
131
private alias object.value1 : ghzEggman.health
132
private alias object.value4 : ghzEggman.invincibilityTimer
133
private alias object.value6 : ghzEggman.flameAnim
134
135
private alias 4 : GHZEGGMAN_INITIALSWING
136
private alias 5 : GHZEGGMAN_MOVERIGHT
137
private alias 6 : GHZEGGMAN_MOVELEFT
138
private alias 7 : GHZEGGMAN_EXPLODE
139
140
private alias 3 : GHZEGGANI_HIT
141
private alias 4 : GHZEGGANI_DEFEATED
142
143
private alias 0 : FLAME_INACTIVE
144
private alias 2 : FLAME_EXPLODE
145
146
// Wrecking Ball Aliases
147
private alias 1 : WRECKINGBALL_ACTIVE
148
private alias 2 : WRECKINGBALL_EXPLODE
149
150
// Animal Prison Aliases
151
private alias 0 : ANIMALPRISON_AWAITOPEN
152
private alias 1 : ANIMALPRISON_OPENED
153
154
155
// ========================
156
// Function Declarations
157
// ========================
158
159
reserve function CheckeredBall_DebugDraw
160
reserve function CheckeredBall_DebugSpawn
161
reserve function CheckeredBall_HandlePlayerMove
162
reserve function CheckeredBall_PlayerInteraction
163
reserve function CheckeredBall_BadnikBreak
164
reserve function CheckeredBall_ReflectProjectile
165
reserve function CheckeredBall_SpringBounce
166
reserve function CheckeredBall_CLedgeCollapse
167
reserve function CheckeredBall_HandlePhysics
168
169
170
// ========================
171
// Tables
172
// ========================
173
174
private table CheckeredBall_heightArray
175
0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 6, 7, 8, 9, 10, 12, 14, 16, 20
176
end table
177
178
// Seems to be unused, and as such, its purpose is unknown...
179
// This table also exists (and is still unused) in S2's OOZ Checkered Ball and Mania's CheckerBall, both of which are based on this object
180
private table CheckeredBall_unusedTable
181
253, 251, 248, 245, 243, 240, 237, 235, 232, 229, 226, 224, 221, 219, 216, 213, 210, 208, 205, 203, 200, 197, 195, 192
182
end table
183
184
185
// ========================
186
// Function Definitions
187
// ========================
188
189
private function CheckeredBall_DebugDraw
190
DrawSprite(1)
191
end function
192
193
194
private function CheckeredBall_DebugSpawn
195
CreateTempObject(TypeName[Checkered Ball], 0, object.xpos, object.ypos)
196
object[tempObjectPos].gravity = GRAVITY_AIR
197
object[tempObjectPos].startPos.x = object.xpos
198
object[tempObjectPos].startPos.y = object.ypos
199
object[tempObjectPos].roundedPos.x = object.xpos
200
object[tempObjectPos].roundedPos.y = object.ypos
201
end function
202
203
204
private function CheckeredBall_HandlePlayerMove
205
object.activePlayers = 0
206
temp2 = 0
207
foreach (GROUP_PLAYERS, currentPlayer, ACTIVE_ENTITIES)
208
// This object is never placed into a level, at least in the final game, so this attract mode check never returns true...
209
CheckEqual(options.attractMode, true)
210
temp1 = checkResult
211
CheckEqual(currentPlayer, 1)
212
temp1 &= checkResult
213
214
temp0 = player[currentPlayer].acceleration
215
temp0 >>= 1
216
if player[currentPlayer].gravity == GRAVITY_GROUND
217
if player[currentPlayer].xvel < 0
218
BoxCollisionTest(C_TOUCH, object.entityPos, 0, -22, 23, 22, currentPlayer, C_BOX, C_BOX, C_BOX, C_BOX)
219
if checkResult == true
220
if player[currentPlayer].left == true
221
if temp1 == false
222
SetBit(object.activePlayers, temp2, true)
223
temp1 = player[currentPlayer].topSpeed
224
FlipSign(temp1)
225
if object.speed > temp1
226
object.speed -= temp0
227
end if
228
object.playerControlled = true
229
end if
230
231
player[currentPlayer].xpos = player[currentPlayer].collisionRight
232
player[currentPlayer].xpos += 22
233
player[currentPlayer].xpos <<= 16
234
player[currentPlayer].xpos += object.roundedPos.x
235
236
if object.xvel < 0
237
if player[currentPlayer].speed < object.speed
238
player[currentPlayer].xvel = object.xvel
239
player[currentPlayer].speed = object.speed
240
end if
241
end if
242
243
player[currentPlayer].pushing = 2
244
end if
245
end if
246
else
247
if player[currentPlayer].xvel > 0
248
BoxCollisionTest(C_TOUCH, object.entityPos, -23, -22, 0, 22, currentPlayer, C_BOX, C_BOX, C_BOX, C_BOX)
249
if checkResult == true
250
if player[currentPlayer].right == true
251
if temp1 == false
252
SetBit(object.activePlayers, temp2, true)
253
if object.speed < player[currentPlayer].topSpeed
254
object.speed += temp0
255
end if
256
object.playerControlled = true
257
end if
258
259
player[currentPlayer].xpos = player[currentPlayer].collisionLeft
260
player[currentPlayer].xpos += -22
261
player[currentPlayer].xpos <<= 16
262
player[currentPlayer].xpos += object.roundedPos.x
263
264
if object.xvel > 0
265
if player[currentPlayer].speed > object.speed
266
player[currentPlayer].xvel = object.xvel
267
player[currentPlayer].speed = object.speed
268
end if
269
end if
270
271
player[currentPlayer].pushing = 2
272
end if
273
end if
274
end if
275
end if
276
end if
277
278
temp2++
279
next
280
end function
281
282
283
private function CheckeredBall_PlayerInteraction
284
temp6 = object.xpos
285
temp6 &= 0xFFFF0000
286
temp6 -= object.roundedPos.x
287
288
temp7 = object.ypos
289
temp7 &= 0xFFFF0000
290
temp7 -= object.roundedPos.y
291
292
temp4 = object.xpos
293
temp5 = object.ypos
294
295
object.xpos = object.roundedPos.x
296
object.ypos = object.roundedPos.y
297
298
temp2 = 0
299
foreach (GROUP_PLAYERS, currentPlayer, ACTIVE_ENTITIES)
300
GetBit(temp0, object.activePlayers, temp2)
301
if temp0 == true
302
if player[currentPlayer].xpos < object.xpos
303
temp1 = player[currentPlayer].collisionRight
304
FlipSign(temp1)
305
temp1 -= 22
306
else
307
temp1 = player[currentPlayer].collisionLeft
308
FlipSign(temp1)
309
temp1 += 22
310
end if
311
temp1 <<= 16
312
313
player[currentPlayer].xpos = temp1
314
player[currentPlayer].xpos += temp4
315
else
316
BoxCollisionTest(C_SOLID, object.entityPos, -22, -22, 22, 22, currentPlayer, C_BOX, C_BOX, C_BOX, C_BOX)
317
if checkResult == COL_TOP
318
player[currentPlayer].xpos += temp6
319
temp0 = temp6
320
temp0 >>= 1
321
player[currentPlayer].xpos += temp0
322
player[currentPlayer].ypos += temp7
323
if player[currentPlayer].xvel != 0
324
temp0 = player[currentPlayer].acceleration
325
temp0 >>= 2
326
if player[currentPlayer].xvel > 0
327
FlipSign(temp0)
328
end if
329
else
330
temp0 = 0
331
end if
332
object.speed += temp0
333
334
if temp0 != 0
335
object.playerControlled = true
336
end if
337
338
object.xpos = temp4
339
object.ypos = temp5
340
BoxCollisionTest(C_SOLID, object.entityPos, -22, -22, 22, 22, currentPlayer, C_BOX, C_BOX, C_BOX, C_BOX)
341
object.xpos = object.roundedPos.x
342
object.ypos = object.roundedPos.y
343
if checkResult == COL_NONE
344
temp0 = temp6
345
temp1 = temp6
346
temp0 >>= 1
347
temp1 += temp0
348
player[currentPlayer].speed += temp0
349
player[currentPlayer].xvel = player[currentPlayer].speed
350
player[currentPlayer].gravity = GRAVITY_AIR
351
player[currentPlayer].controlLock = 15
352
end if
353
end if
354
355
if checkResult == COL_BOTTOM
356
if object.yvel >= 0
357
if player[currentPlayer].gravity == GRAVITY_GROUND
358
// The Ball's falling downwards on top of the player, crush them
359
CallFunction(Player_Kill)
360
end if
361
end if
362
end if
363
end if
364
temp2++
365
next
366
367
object.xpos = temp4
368
object.ypos = temp5
369
end function
370
371
372
private function CheckeredBall_BadnikBreak
373
temp0 = object.xvel
374
temp0 |= object.yvel
375
376
if temp0 != 0
377
ResetObjectEntity(object[arrayPos0].entityPos, TypeName[Blank Object], 0, object[arrayPos0].xpos, object[arrayPos0].ypos)
378
Rand(checkResult, 32)
379
if checkResult >= 16
380
CreateTempObject(animalType1, 0, object[arrayPos0].xpos, object[arrayPos0].ypos)
381
else
382
CreateTempObject(animalType2, 0, object[arrayPos0].xpos, object[arrayPos0].ypos)
383
end if
384
object[tempObjectPos].priority = PRIORITY_ACTIVE_SMALL
385
386
CreateTempObject(TypeName[Smoke Puff], 0, object[arrayPos0].xpos, object[arrayPos0].ypos)
387
object[tempObjectPos].drawOrder = 4
388
389
CreateTempObject(TypeName[Object Score], object.badnikBonus, object[arrayPos0].xpos, object[arrayPos0].ypos)
390
object[tempObjectPos].drawOrder = 4
391
392
PlaySfx(SfxName[Destroy], false)
393
394
switch object.badnikBonus
395
case 0
396
player.score += 100
397
break
398
399
case 1
400
player.score += 200
401
break
402
403
case 2
404
player.score += 500
405
break
406
407
case 3 // Fall through
408
case 4
409
case 5
410
case 6
411
case 7
412
case 8
413
case 9
414
case 10
415
case 11
416
case 12
417
case 13
418
case 14
419
player.score += 1000
420
break
421
422
case 15
423
player.score += 10000
424
break
425
426
end switch
427
428
if object.badnikBonus < 15
429
object.badnikBonus++
430
end if
431
end if
432
end function
433
434
435
private function CheckeredBall_ReflectProjectile
436
// Do some maths to find where the projectile should go now
437
temp0 = object.xpos
438
temp0 -= object[arrayPos0].xpos
439
temp1 = object.ypos
440
temp1 -= object[arrayPos0].ypos
441
442
ATan2(temp2, temp0, temp1)
443
Sin256(temp0, temp2)
444
Cos256(temp1, temp2)
445
446
object[arrayPos0].xvel = temp1
447
object[arrayPos0].xvel *= -0x800
448
object[arrayPos0].yvel = temp0
449
object[arrayPos0].yvel *= -0x800
450
end function
451
452
453
private function CheckeredBall_SpringBounce
454
switch object[arrayPos0].propertyValue
455
case 0
456
// Upwards Spring
457
458
temp0 = spring[arrayPos0].active
459
if object.gravity == GRAVITY_AIR
460
temp0 = true
461
end if
462
463
if object.collisionMode > CMODE_FLOOR
464
if object.yvel < 0
465
temp0 = true
466
end if
467
end if
468
469
if temp0 == false
470
BoxCollisionTest(C_SOLID, object[arrayPos0].entityPos, -14, -8, 14, 8, object.entityPos, -22, -22, 22, 22)
471
BoxCollisionTest(C_TOUCH, object[arrayPos0].entityPos, -14, -10, 14, -6, object.entityPos, -22, -22, 22, 22)
472
if checkResult == true
473
spring[arrayPos0].timer = 1
474
object.tileCollisions = true
475
object.gravity = GRAVITY_AIR
476
object.speed = object.xvel
477
object.yvel = temp7
478
FlipSign(object.yvel)
479
480
object.yvel += spring[arrayPos0].extraVelocity
481
PlaySfx(SfxName[Spring], false)
482
end if
483
else
484
if object.yvel >= 0
485
BoxCollisionTest(C_PLATFORM, object[arrayPos0].entityPos, -14, -8, 14, 8, object.entityPos, -22, -22, 22, 22)
486
BoxCollisionTest(C_TOUCH, object[arrayPos0].entityPos, -14, -10, 14, -6, object.entityPos, -22, -22, 22, 22)
487
if checkResult == true
488
spring[arrayPos0].timer = 1
489
object.tileCollisions = true
490
object.gravity = GRAVITY_AIR
491
object.speed = object.xvel
492
object.yvel = temp7
493
FlipSign(object.yvel)
494
495
object.yvel += spring[arrayPos0].extraVelocity
496
PlaySfx(SfxName[Spring], false)
497
end if
498
end if
499
end if
500
break
501
502
case 1
503
// Spring facing Right
504
505
BoxCollisionTest(C_SOLID, object[arrayPos0].entityPos, -8, -14, 8, 14, object.entityPos, -22, -22, 22, 22)
506
if object.gravity == GRAVITY_GROUND
507
BoxCollisionTest(C_TOUCH, object[arrayPos0].entityPos, 6, -14, 10, 14, object.entityPos, -22, -22, 22, 22)
508
if checkResult == true
509
spring[arrayPos0].timer = 1
510
object.tileCollisions = true
511
object.speed = temp7
512
object.collisionMode = CMODE_FLOOR
513
object.direction = FACING_RIGHT // The Checkered Ball's direction doesn't matter too much, but sure
514
PlaySfx(SfxName[Spring], false)
515
end if
516
end if
517
break
518
519
case 2
520
// Spring facing Left
521
522
BoxCollisionTest(C_SOLID, object[arrayPos0].entityPos, -8, -14, 8, 14, object.entityPos, -22, -22, 22, 22)
523
if object.gravity == GRAVITY_GROUND
524
BoxCollisionTest(C_TOUCH, object[arrayPos0].entityPos, -10, -14, -6, 14, object.entityPos, -22, -22, 22, 22)
525
if checkResult == true
526
spring[arrayPos0].timer = 1
527
object.tileCollisions = true
528
object.speed = temp7
529
FlipSign(object.speed)
530
object.collisionMode = CMODE_FLOOR
531
object.direction = FACING_LEFT // I mean if you really wanna ig?
532
PlaySfx(SfxName[Spring], false)
533
end if
534
end if
535
break
536
537
case 3
538
// Downwards Spring
539
540
BoxCollisionTest(C_SOLID, object[arrayPos0].entityPos, -14, -8, 14, 8, object.entityPos, -22, -22, 22, 22)
541
BoxCollisionTest(C_TOUCH, object[arrayPos0].entityPos, -14, 6, 14, 10, object.entityPos, -22, -22, 22, 22)
542
if checkResult == true
543
spring[arrayPos0].timer = 1
544
if object.collisionMode == CMODE_ROOF
545
FlipSign(object.speed)
546
FlipSign(object.xvel)
547
end if
548
object.tileCollisions = true
549
object.gravity = GRAVITY_AIR
550
object.speed = object.xvel
551
object.yvel = temp7
552
PlaySfx(SfxName[Spring], true)
553
end if
554
break
555
556
end switch
557
end function
558
559
560
private function CheckeredBall_CLedgeCollapse
561
if object[arrayPos0].state < CLEDGE_NONE
562
if object.yvel >= 0
563
temp0 = object.xpos
564
temp0 -= object[arrayPos0].xpos
565
temp0 >>= 17
566
temp0 += 24
567
if temp0 < 0
568
temp0 = 0
569
end if
570
571
if temp0 > 47
572
temp0 = 47
573
end if
574
575
if temp7 == false
576
// Ledge is facing Right
577
GetTableValue(temp1, temp0, CLedgeLeft_heightArray)
578
else
579
// Ledge is facing Left, invert the value to fetch
580
temp2 = 47
581
temp2 -= temp0
582
GetTableValue(temp1, temp2, CLedgeLeft_heightArray)
583
end if
584
585
temp1 -= 84
586
temp0 = temp1
587
temp0 += 32
588
BoxCollisionTest(C_PLATFORM, arrayPos0, -48, temp1, 48, temp0, object.entityPos, -18, -22, 18, 22)
589
if checkResult == true
590
object.ypos += 0x40000
591
if object[arrayPos0].state == CLEDGE_ACTIVE
592
object[arrayPos0].state = CLEDGE_COLLAPSE
593
end if
594
end if
595
end if
596
end if
597
end function
598
599
600
private function CheckeredBall_HandlePhysics
601
if object.gravity == GRAVITY_AIR
602
object.yvel += 0x3800
603
object.speed = object.xvel
604
else
605
Sin256(temp0, object.groundAngle)
606
temp0 *= 0x2000
607
temp0 >>= 8
608
object.speed += temp0
609
object.angleVel = object.speed
610
if temp0 == 0
611
if object.playerControlled == false
612
if object.speed > 0
613
object.speed -= 0x400
614
if object.speed < 0
615
object.speed = 0
616
end if
617
else
618
object.speed += 0x400
619
if object.speed > 0
620
object.speed = 0
621
end if
622
end if
623
end if
624
end if
625
626
Cos256(temp0, object.groundAngle)
627
temp0 *= object.speed
628
temp0 >>= 8
629
object.xvel = temp0
630
631
Sin256(temp0, object.groundAngle)
632
temp0 *= object.speed
633
temp0 >>= 8
634
object.yvel = temp0
635
end if
636
637
object.playerControlled = false
638
end function
639
640
641
// ========================
642
// Events
643
// ========================
644
645
event ObjectUpdate
646
if object.priority != PRIORITY_XBOUNDS_DESTROY
647
object.priority = PRIORITY_ACTIVE
648
end if
649
650
CallFunction(CheckeredBall_HandlePlayerMove)
651
652
object.ballAngle += object.angleVel
653
654
// These don't actually do anything - the engine doesn't support direct setting of these values by script
655
// Instead, the Checkered Ball's collision values are set with the ani file
656
object.collisionLeft = -22
657
object.collisionTop = -22
658
object.collisionRight = 22
659
object.collisionBottom = 22
660
661
CallFunction(CheckeredBall_HandlePhysics)
662
663
ProcessObjectMovement()
664
665
object.groundAngle = object.angle
666
667
// Originally, this whole interaction system would cycle though *all* objects in the stage and use a giant case-switch statement for object type, containing all possible interactions
668
// Later, however, Taxman updated this code to use separate, individual foreach checks for every interaction instead of the old giant foreach + case-switch
669
// This updated script was never implemented into the mobile version of Sonic 1, but it was in Origins (and Mania's followed the same structure as well)
670
671
foreach (TypeName[Motobug], arrayPos0, ACTIVE_ENTITIES)
672
BoxCollisionTest(C_TOUCH, object.entityPos, -22, -22, 22, 22, arrayPos0, -14, -14, 14, 14)
673
if checkResult == true
674
CallFunction(CheckeredBall_BadnikBreak)
675
end if
676
next
677
678
foreach (TypeName[Buzz Bomber], arrayPos0, ACTIVE_ENTITIES)
679
// The Buzz Bomber's hitbox is normally -24, -12, 24, 12...
680
BoxCollisionTest(C_TOUCH, object.entityPos, -22, -22, 22, 22, arrayPos0, -16, -7, 16, 7)
681
if checkResult == true
682
CallFunction(CheckeredBall_BadnikBreak)
683
end if
684
next
685
686
foreach (TypeName[Crabmeat], arrayPos0, ACTIVE_ENTITIES)
687
BoxCollisionTest(C_TOUCH, object.entityPos, -22, -22, 22, 22, arrayPos0, -14, -14, 14, 14)
688
if checkResult == true
689
CallFunction(CheckeredBall_BadnikBreak)
690
end if
691
next
692
693
foreach (TypeName[Chopper], arrayPos0, ACTIVE_ENTITIES)
694
BoxCollisionTest(C_TOUCH, object.entityPos, -22, -22, 22, 22, arrayPos0, -12, -14, 12, 14)
695
if checkResult == true
696
CallFunction(CheckeredBall_BadnikBreak)
697
end if
698
next
699
700
foreach (TypeName[Splats], arrayPos0, ACTIVE_ENTITIES)
701
// A fellow unused object, go ahead and interact with Splats too
702
// Something interesting - this interaction didn't even exist in the original S1 release,
703
// it was only added later in an update
704
// Why they decided to update an unused object to add an unused interaction for an unused enemy is beyond me, though...
705
706
BoxCollisionTest(C_TOUCH, object.entityPos, -22, -22, 22, 22, arrayPos0, -10, -20, 6, 20)
707
if checkResult == true
708
CallFunction(CheckeredBall_BadnikBreak)
709
end if
710
next
711
712
foreach (TypeName[Newtron Fly], arrayPos0, ACTIVE_ENTITIES)
713
// Only hurt Newtrons when they're active, not in their hidden states
714
switch object[arrayPos0].state
715
case NEWTRONFLY_APPEARED
716
case NEWTRONFLY_MOVING
717
BoxCollisionTest(C_TOUCH, object.entityPos, -22, -22, 22, 22, arrayPos0, -16, -8, 16, 8)
718
if checkResult == true
719
CallFunction(CheckeredBall_BadnikBreak)
720
end if
721
break
722
723
end switch
724
next
725
726
foreach (TypeName[Newtron Shoot], arrayPos0, ACTIVE_ENTITIES)
727
// Only hurt Newtrons when they're active, not in their hidden states
728
switch object[arrayPos0].state
729
case NEWTRONSHOOT_SHOOT
730
case NEWTRONSHOOT_SHOOTDELAY
731
BoxCollisionTest(C_TOUCH, object.entityPos, -22, -22, 22, 22, arrayPos0, -12, -14, 12, 14)
732
if checkResult == true
733
CallFunction(CheckeredBall_BadnikBreak)
734
end if
735
break
736
737
end switch
738
next
739
740
foreach (TypeName[Buzz Bomber Shot], arrayPos0, ACTIVE_ENTITIES)
741
BoxCollisionTest(C_TOUCH, object.entityPos, -22, -22, 22, 22, arrayPos0, -6, -6, 6, 6)
742
if checkResult == true
743
CallFunction(CheckeredBall_ReflectProjectile)
744
end if
745
next
746
747
foreach (TypeName[Crabmeat Shot], arrayPos0, ACTIVE_ENTITIES)
748
BoxCollisionTest(C_TOUCH, object.entityPos, -22, -22, 22, 22, arrayPos0, -6, -6, 6, 6)
749
if checkResult == true
750
CallFunction(CheckeredBall_ReflectProjectile)
751
end if
752
next
753
754
foreach (TypeName[Newtron Shot], arrayPos0, ACTIVE_ENTITIES)
755
BoxCollisionTest(C_TOUCH, object.entityPos, -22, -22, 22, 22, arrayPos0, -6, -6, 6, 6)
756
if checkResult == true
757
CallFunction(CheckeredBall_ReflectProjectile)
758
end if
759
next
760
761
foreach (TypeName[Monitor], arrayPos0, ACTIVE_ENTITIES)
762
BoxCollisionTest(C_TOUCH, object.entityPos, -22, -22, 22, 22, arrayPos0, -16, -14, 16, 16)
763
if checkResult == true
764
object[arrayPos0].state = MONITOR_STATE_IDLE
765
CreateTempObject(TypeName[Smoke Puff], 0, object[arrayPos0].xpos, object[arrayPos0].ypos)
766
object[tempObjectPos].drawOrder = 4
767
object[arrayPos0].type = TypeName[Broken Monitor]
768
769
if object[arrayPos0].priority != PRIORITY_XBOUNDS_DESTROY
770
object[arrayPos0].priority = PRIORITY_ACTIVE
771
end if
772
773
object[arrayPos0].alpha = 0xFF
774
monitor[arrayPos0].contentsPos.y = object[arrayPos0].ypos
775
monitor[arrayPos0].timer = -0x30000
776
777
PlaySfx(SfxName[Destroy], false)
778
end if
779
next
780
781
foreach (TypeName[Rock], arrayPos0, ACTIVE_ENTITIES)
782
// Do note that here the order in this collision test function is switched, the Rock is in the first slot and then the Ball's in the second
783
BoxCollisionTest(C_SOLID, arrayPos0, -16, -16, 16, 16, object.entityPos, -22, -22, 22, 22)
784
switch checkResult
785
case COL_TOP
786
object.gravity = GRAVITY_GROUND
787
break
788
789
case COL_LEFT
790
if object.speed > 0
791
object.speed = 0
792
end if
793
break
794
795
case COL_RIGHT
796
if object.speed < 0
797
object.speed = 0
798
end if
799
break
800
801
end switch
802
next
803
804
foreach (TypeName[Spikes], arrayPos0, ACTIVE_ENTITIES)
805
// Have different tests for each of the Spike types
806
switch object[arrayPos0].propertyValue
807
case 0
808
// 3 Spikes (Up)
809
BoxCollisionTest(C_SOLID, arrayPos0, -20, -16, 20, 16, object.entityPos, -22, -22, 22, 22)
810
break
811
812
case 1
813
// 3 Spikes (Right)
814
BoxCollisionTest(C_SOLID, arrayPos0, -16, -20, 15, 20, object.entityPos, -22, -22, 22, 22)
815
break
816
817
case 2
818
// 3 Spikes (Left)
819
BoxCollisionTest(C_SOLID, arrayPos0, -15, -20, 16, 20, object.entityPos, -22, -22, 22, 22)
820
break
821
822
case 3
823
// 3 Spikes (Down)
824
BoxCollisionTest(C_SOLID, arrayPos0, -20, -16, 20, 15, object.entityPos, -22, -22, 22, 22)
825
break
826
827
case 4
828
// 1 Spike (Up)
829
BoxCollisionTest(C_SOLID, arrayPos0, -4, -16, 4, 16, object.entityPos, -22, -22, 22, 22)
830
break
831
832
case 5
833
// 1 Spike (Right)
834
BoxCollisionTest(C_SOLID, arrayPos0, -16, -4, 15, 4, object.entityPos, -22, -22, 22, 22)
835
break
836
837
case 6
838
// 1 Spike (Left)
839
BoxCollisionTest(C_SOLID, arrayPos0, -15, -4, 16, 4, object.entityPos, -22, -22, 22, 22)
840
break
841
842
case 7
843
// 1 Spike (Down)
844
BoxCollisionTest(C_SOLID, arrayPos0, -4, -16, 4, 15, object.entityPos, -22, -22, 22, 22)
845
break
846
847
case 8
848
// 3 Spikes (Spaced Out) (Up)
849
BoxCollisionTest(C_SOLID, arrayPos0, -28, -16, 28, 16, object.entityPos, -22, -22, 22, 22)
850
break
851
852
case 9
853
// 3 Spikes (Spaced Out) (Right)
854
BoxCollisionTest(C_SOLID, arrayPos0, -16, -28, 15, 28, object.entityPos, -22, -22, 22, 22)
855
break
856
857
case 10
858
// 3 Spikes (Spaced Out) (Left)
859
BoxCollisionTest(C_SOLID, arrayPos0, -15, -28, 16, 28, object.entityPos, -22, -22, 22, 22)
860
break
861
862
case 11
863
// 3 Spikes (Spaced Out) (Down)
864
BoxCollisionTest(C_SOLID, arrayPos0, -28, -16, 28, 15, object.entityPos, -22, -22, 22, 22)
865
break
866
867
case 12
868
// 6 Spikes (Spaced Out) (Up)
869
BoxCollisionTest(C_SOLID, arrayPos0, -64, -16, 64, 16, object.entityPos, -22, -22, 22, 22)
870
break
871
872
case 13
873
// 6 Spikes (Spaced Out) (Right)
874
BoxCollisionTest(C_SOLID, arrayPos0, -16, -64, 15, 64, object.entityPos, -22, -22, 22, 22)
875
break
876
877
case 14
878
// 6 Spikes (Spaced Out) (Left)
879
BoxCollisionTest(C_SOLID, arrayPos0, -15, -64, 16, 64, object.entityPos, -22, -22, 22, 22)
880
break
881
882
case 15
883
// 6 Spikes (Spaced Out) (Down)
884
BoxCollisionTest(C_SOLID, arrayPos0, -64, -16, 64, 15, object.entityPos, -22, -22, 22, 22)
885
break
886
887
end switch
888
889
switch checkResult
890
case COL_TOP
891
object.gravity = GRAVITY_GROUND
892
break
893
894
case COL_LEFT
895
if object.speed > 0
896
object.speed = 0
897
end if
898
break
899
900
case COL_RIGHT
901
if object.speed < 0
902
object.speed = 0
903
end if
904
break
905
906
end switch
907
next
908
909
foreach (TypeName[Breakable Wall], arrayPos0, ACTIVE_ENTITIES)
910
// Only interact with solid walls, not wall fragments
911
if object[arrayPos0].propertyValue < 3
912
913
// Get the absolute version of this object's speed
914
temp0 = object.speed
915
Abs(temp0)
916
917
// Unlike Players, who need to be going at a speed of 4.5 pixels per frame, the Checkered Ball's speed requirement is only 2px per frame
918
if temp0 >= 0x20000
919
BoxCollisionTest(C_TOUCH, arrayPos0, -17, -32, 17, 32, object.entityPos, -22, -22, 22, 22)
920
if checkResult == true
921
// Destroy the wall
922
923
// Delete the wall object
924
object[arrayPos0].type = TypeName[Blank Object]
925
926
// Bug Details:
927
// -> Although this worked in initial versions of S1, it now plays the jump sound instead
928
// This is because the earliest revisions of S1 only had sfx [Ledge Break], as opposed to later versions where it was split into [Ledge Break L] and [Ledge Break R]
929
// -> This use of SfxName was neglected to be updated, which is why this now invalid TypeName plays sfx ID 0 (the jump sound) instead
930
PlaySfx(SfxName[Ledge Break], false)
931
932
temp0 = object[arrayPos0].propertyValue
933
temp0 <<= 1
934
temp0 += 3
935
936
temp1 = temp0
937
temp1++
938
939
temp2 = object[arrayPos0].xpos
940
temp2 -= 0x80000
941
942
temp3 = object[arrayPos0].xpos
943
temp3 += 0x80000
944
945
temp4 = object[arrayPos0].ypos
946
temp4 -= 0x180000
947
948
// Determine which way to blow wall fragments based on which way the ball is "facing"
949
if object.xpos < object[arrayPos0].xpos
950
// Sending the fragments left
951
952
CreateTempObject(TypeName[Breakable Wall], temp0, temp2, temp4)
953
object[tempObjectPos].xvel = -0x60000
954
object[tempObjectPos].yvel = -0x60000
955
object[tempObjectPos].drawOrder = 4
956
957
CreateTempObject(TypeName[Breakable Wall], temp1, temp3, temp4)
958
object[tempObjectPos].xvel = -0x40000
959
object[tempObjectPos].yvel = -0x50000
960
object[tempObjectPos].drawOrder = 4
961
962
temp4 += 0x100000
963
964
CreateTempObject(TypeName[Breakable Wall], temp0, temp2, temp4)
965
object[tempObjectPos].xvel = -0x80000
966
object[tempObjectPos].yvel = -0x20000
967
object[tempObjectPos].drawOrder = 4
968
969
CreateTempObject(TypeName[Breakable Wall], temp1, temp3, temp4)
970
object[tempObjectPos].xvel = -0x60000
971
object[tempObjectPos].yvel = -0x10000
972
object[tempObjectPos].drawOrder = 4
973
974
temp4 += 0x100000
975
976
CreateTempObject(TypeName[Breakable Wall], temp0, temp2, temp4)
977
object[tempObjectPos].xvel = -0x80000
978
object[tempObjectPos].yvel = 0x20000
979
object[tempObjectPos].drawOrder = 4
980
981
CreateTempObject(TypeName[Breakable Wall], temp1, temp3, temp4)
982
object[tempObjectPos].xvel = -0x60000
983
object[tempObjectPos].yvel = 0x10000
984
object[tempObjectPos].drawOrder = 4
985
986
temp4 += 0x100000
987
988
CreateTempObject(TypeName[Breakable Wall], temp0, temp2, temp4)
989
object[tempObjectPos].xvel = -0x60000
990
object[tempObjectPos].yvel = 0x60000
991
object[tempObjectPos].drawOrder = 4
992
993
CreateTempObject(TypeName[Breakable Wall], temp1, temp3, temp4)
994
object[tempObjectPos].xvel = -0x40000
995
object[tempObjectPos].yvel = 0x50000
996
object[tempObjectPos].drawOrder = 4
997
else
998
// Sending the fragments right
999
1000
CreateTempObject(TypeName[Breakable Wall], temp0, temp2, temp4)
1001
object[tempObjectPos].xvel = 0x40000
1002
object[tempObjectPos].yvel = -0x50000
1003
object[tempObjectPos].drawOrder = 4
1004
1005
CreateTempObject(TypeName[Breakable Wall], temp1, temp3, temp4)
1006
object[tempObjectPos].xvel = 0x60000
1007
object[tempObjectPos].yvel = -0x60000
1008
object[tempObjectPos].drawOrder = 4
1009
1010
temp4 += 0x100000
1011
1012
CreateTempObject(TypeName[Breakable Wall], temp0, temp2, temp4)
1013
object[tempObjectPos].xvel = 0x60000
1014
object[tempObjectPos].yvel = -0x10000
1015
object[tempObjectPos].drawOrder = 4
1016
1017
CreateTempObject(TypeName[Breakable Wall], temp1, temp3, temp4)
1018
object[tempObjectPos].xvel = 0x80000
1019
object[tempObjectPos].yvel = -0x20000
1020
object[tempObjectPos].drawOrder = 4
1021
1022
temp4 += 0x100000
1023
1024
CreateTempObject(TypeName[Breakable Wall], temp0, temp2, temp4)
1025
object[tempObjectPos].xvel = 0x60000
1026
object[tempObjectPos].yvel = 0x10000
1027
object[tempObjectPos].drawOrder = 4
1028
1029
CreateTempObject(TypeName[Breakable Wall], temp1, temp3, temp4)
1030
object[tempObjectPos].xvel = 0x80000
1031
object[tempObjectPos].yvel = 0x20000
1032
object[tempObjectPos].drawOrder = 4
1033
1034
temp4 += 0x100000
1035
1036
CreateTempObject(TypeName[Breakable Wall], temp0, temp2, temp4)
1037
object[tempObjectPos].xvel = 0x40000
1038
object[tempObjectPos].yvel = 0x50000
1039
object[tempObjectPos].drawOrder = 4
1040
1041
CreateTempObject(TypeName[Breakable Wall], temp1, temp3, temp4)
1042
object[tempObjectPos].xvel = 0x60000
1043
object[tempObjectPos].yvel = 0x60000
1044
object[tempObjectPos].drawOrder = 4
1045
end if
1046
end if
1047
else
1048
BoxCollisionTest(C_SOLID, arrayPos0, -17, -32, 17, 32, object.entityPos, -22, -22, 22, 22)
1049
switch checkResult
1050
case COL_TOP
1051
object.gravity = GRAVITY_GROUND
1052
break
1053
1054
case COL_LEFT
1055
if object.speed > 0
1056
object.speed = 0
1057
end if
1058
break
1059
1060
case COL_RIGHT
1061
if object.speed < 0
1062
object.speed = 0
1063
end if
1064
break
1065
1066
end switch
1067
end if
1068
end if
1069
next
1070
1071
foreach (TypeName[Bridge], arrayPos0, ACTIVE_ENTITIES)
1072
if object.xpos > bridge[arrayPos0].startPos
1073
if object.xpos < bridge[arrayPos0].endPos
1074
if object.entityPos == bridge[arrayPos0].playerID
1075
bridge[arrayPos0].stoodPos = object.xpos
1076
bridge[arrayPos0].stoodPos -= bridge[arrayPos0].startPos
1077
temp0 = bridge[arrayPos0].stoodPos
1078
temp0 >>= 8
1079
temp1 = bridge[arrayPos0].endPos
1080
temp1 -= bridge[arrayPos0].startPos
1081
temp2 = temp1
1082
temp2 >>= 16
1083
temp0 /= temp2
1084
Sin(bridge[arrayPos0].depression, temp0)
1085
temp1 >>= 13
1086
bridge[arrayPos0].depression *= temp1
1087
temp0 = object[arrayPos0].ypos
1088
temp0 -= 0x300000
1089
if object.ypos > temp0
1090
if object.yvel >= 0
1091
temp2 = object.collisionBottom
1092
FlipSign(temp2)
1093
temp2 <<= 16
1094
temp2 += bridge[arrayPos0].bridgeDepth
1095
temp2 -= 0x80000
1096
bridge[arrayPos0].activePlayerCount++
1097
object.ypos = object[arrayPos0].ypos
1098
object.ypos += temp2
1099
object.gravity = GRAVITY_GROUND
1100
object.yvel = 0
1101
object.floorSensorL = true
1102
object.floorSensorC = true
1103
object.floorSensorR = true
1104
else
1105
bridge[arrayPos0].playerID = -2
1106
end if
1107
end if
1108
else
1109
if object.yvel >= 0
1110
temp0 = object.xpos
1111
temp0 -= bridge[arrayPos0].startPos
1112
if temp0 > bridge[arrayPos0].stoodPos
1113
temp0 = bridge[arrayPos0].endPos
1114
temp0 -= object.xpos
1115
temp3 = bridge[arrayPos0].endPos
1116
temp3 -= bridge[arrayPos0].startPos
1117
temp3 -= bridge[arrayPos0].stoodPos
1118
temp1 = temp0
1119
temp1 <<= 7
1120
temp1 /= temp3
1121
else
1122
temp1 = temp0
1123
temp1 <<= 7
1124
temp1 /= bridge[arrayPos0].stoodPos
1125
end if
1126
Sin(temp2, temp1)
1127
temp2 *= bridge[arrayPos0].bridgeDepth
1128
temp2 >>= 9
1129
temp2 -= 0x80000
1130
if object.yvel < 0x8000
1131
temp3 = temp2
1132
temp3 >>= 16
1133
temp4 = temp3
1134
temp3 -= 8
1135
else
1136
temp3 = temp2
1137
temp3 >>= 16
1138
temp4 = temp3
1139
temp4 += 8
1140
end if
1141
1142
BoxCollisionTest(C_TOUCH, object[arrayPos0].entityPos, -0x400, temp3, 0x400, temp4, object.entityPos, -18, -22, 18, 22)
1143
if checkResult == true
1144
bridge[arrayPos0].activePlayerCount++
1145
object.ypos = object.collisionBottom
1146
FlipSign(object.ypos)
1147
object.ypos <<= 16
1148
object.ypos += object[arrayPos0].ypos
1149
object.ypos += temp2
1150
object.floorSensorL = true
1151
object.floorSensorC = true
1152
object.floorSensorR = true
1153
bridge[arrayPos0].playerID = object.entityPos
1154
object.gravity = GRAVITY_GROUND
1155
object.yvel = 0
1156
end if
1157
end if
1158
end if
1159
else
1160
if object.entityPos == bridge[arrayPos0].playerID
1161
bridge[arrayPos0].playerID = -2
1162
bridge[arrayPos0].stoodPos = 32
1163
end if
1164
end if
1165
else
1166
if object.entityPos == bridge[arrayPos0].playerID
1167
bridge[arrayPos0].playerID = -2
1168
bridge[arrayPos0].stoodPos = 32
1169
end if
1170
end if
1171
next
1172
1173
foreach (TypeName[Yellow Spring], arrayPos0, ACTIVE_ENTITIES)
1174
temp7 = 0xA0000
1175
CallFunction(CheckeredBall_SpringBounce)
1176
next
1177
1178
foreach (TypeName[Red Spring], arrayPos0, ACTIVE_ENTITIES)
1179
temp7 = 0x100000
1180
CallFunction(CheckeredBall_SpringBounce)
1181
next
1182
1183
foreach (TypeName[Fall Platform], arrayPos0, ACTIVE_ENTITIES)
1184
object[arrayPos0].ypos -= fallPlatform[arrayPos0].collisionOffset.y
1185
BoxCollisionTest(C_PLATFORM, object[arrayPos0].entityPos, -32, -8, 32, 0, object.entityPos, -18, -22, 18, 22)
1186
if checkResult == true
1187
fallPlatform[arrayPos0].stood = true
1188
object.collisionOffset.y = fallPlatform[arrayPos0].collisionOffset.y
1189
end if
1190
object[arrayPos0].ypos += fallPlatform[arrayPos0].collisionOffset.y
1191
next
1192
1193
foreach (TypeName[H Platform], arrayPos0, ACTIVE_ENTITIES)
1194
object[arrayPos0].xpos -= hPlatform[arrayPos0].collisionOffset.x
1195
object[arrayPos0].ypos -= hPlatform[arrayPos0].collisionOffset.y
1196
BoxCollisionTest(C_PLATFORM, object[arrayPos0].entityPos, -32, -8, 32, 12, object.entityPos, -18, -22, 18, 22)
1197
if checkResult == true
1198
hPlatform[arrayPos0].stood = true
1199
object.collisionOffset.x = hPlatform[arrayPos0].collisionOffset.x
1200
object.collisionOffset.y = hPlatform[arrayPos0].collisionOffset.y
1201
end if
1202
object[arrayPos0].xpos += hPlatform[arrayPos0].collisionOffset.x
1203
object[arrayPos0].ypos += hPlatform[arrayPos0].collisionOffset.y
1204
next
1205
1206
foreach (TypeName[V Platform], arrayPos0, ACTIVE_ENTITIES)
1207
object[arrayPos0].ypos -= vPlatform[arrayPos0].collisionOffset.y
1208
BoxCollisionTest(C_PLATFORM, object[arrayPos0].entityPos, -32, -8, 32, 12, object.entityPos, -18, -22, 18, 22)
1209
if checkResult == true
1210
object.collisionOffset.y = vPlatform[arrayPos0].collisionOffset.y
1211
end if
1212
object[arrayPos0].ypos += vPlatform[arrayPos0].collisionOffset.y
1213
next
1214
1215
foreach (TypeName[V Platform 2], arrayPos0, ACTIVE_ENTITIES)
1216
object[arrayPos0].ypos -= vPlatform2[arrayPos0].collisionOffset.y
1217
BoxCollisionTest(C_PLATFORM, object[arrayPos0].entityPos, -32, -2, 32, 12, object.entityPos, -18, -22, 18, 22)
1218
if checkResult == true
1219
object.collisionOffset.y = vPlatform2[arrayPos0].collisionOffset.y
1220
end if
1221
object[arrayPos0].ypos += vPlatform2[arrayPos0].collisionOffset.y
1222
next
1223
1224
foreach (TypeName[Swing Platform], arrayPos0, ACTIVE_ENTITIES)
1225
temp0 = object[arrayPos0].xpos
1226
temp1 = object[arrayPos0].ypos
1227
object[arrayPos0].xpos = swingPlatform[arrayPos0].drawPos.x
1228
object[arrayPos0].ypos = swingPlatform[arrayPos0].drawPos.y
1229
object[arrayPos0].xpos -= swingPlatform[arrayPos0].collisionOffset.x
1230
object[arrayPos0].ypos -= swingPlatform[arrayPos0].collisionOffset.y
1231
BoxCollisionTest(C_PLATFORM, object[arrayPos0].entityPos, -24, -8, 24, 8, object.entityPos, -18, -22, 18, 22)
1232
if checkResult == true
1233
object.collisionOffset.x = swingPlatform[arrayPos0].collisionOffset.x
1234
object.collisionOffset.y = swingPlatform[arrayPos0].collisionOffset.y
1235
end if
1236
object[arrayPos0].xpos = temp0
1237
object[arrayPos0].ypos = temp1
1238
next
1239
1240
foreach (TypeName[C Ledge Left], arrayPos0, ACTIVE_ENTITIES)
1241
temp7 = true
1242
CallFunction(CheckeredBall_CLedgeCollapse)
1243
next
1244
1245
foreach (TypeName[C Ledge Right], arrayPos0, ACTIVE_ENTITIES)
1246
temp7 = false
1247
CallFunction(CheckeredBall_CLedgeCollapse)
1248
next
1249
1250
foreach (TypeName[Plane Sw V], arrayPos0, ACTIVE_ENTITIES)
1251
CheckEqual(planeSwV[arrayPos0].onGround, false)
1252
temp0 = checkResult
1253
CheckEqual(object.gravity, GRAVITY_GROUND)
1254
temp0 |= checkResult
1255
if temp0 == true
1256
BoxCollisionTest(C_TOUCH, object[arrayPos0].entityPos, -12, planeSwV[arrayPos0].extendTop, 12, planeSwV[arrayPos0].extendBottom, object.entityPos, -10, -22, 10, 22)
1257
if checkResult == true
1258
if object.xvel > 0
1259
object.collisionPlane = planeSwV[arrayPos0].planeL
1260
object.drawOrder = planeSwV[arrayPos0].drawOrderL
1261
else
1262
object.collisionPlane = planeSwV[arrayPos0].planeR
1263
object.drawOrder = planeSwV[arrayPos0].drawOrderR
1264
end if
1265
end if
1266
end if
1267
next
1268
1269
// Bug Details:
1270
// -> This is supposed to check for Plane Sw H, not V again...
1271
// -> This was only broken in an update, during the giant case-switch to individual foreach transfer
1272
// Earlier versions of the script correcty used [Plane Sw H] here, though the latest versions don't and those are what we're sticking with
1273
foreach (TypeName[Plane Sw V], arrayPos0, ACTIVE_ENTITIES)
1274
CheckEqual(planeSwV[arrayPos0].onGround, false)
1275
temp0 = checkResult
1276
CheckEqual(object.gravity, GRAVITY_GROUND)
1277
temp0 |= checkResult
1278
if temp0 == true
1279
// This is looking at a Sw H but using its values as a Sw V, this only works perchance
1280
BoxCollisionTest(C_TOUCH, object[arrayPos0].entityPos, planeSwV[arrayPos0].extendLeft, -12, planeSwV[arrayPos0].extendRight, 12, object.entityPos, -22, -10, 22, 10)
1281
if checkResult == true
1282
if object.yvel > 0
1283
object.collisionPlane = planeSwV[arrayPos0].planeL
1284
object.drawOrder = planeSwV[arrayPos0].drawOrderL
1285
else
1286
object.collisionPlane = planeSwV[arrayPos0].planeL
1287
object.drawOrder = planeSwV[arrayPos0].drawOrderR
1288
end if
1289
end if
1290
end if
1291
next
1292
1293
foreach (TypeName[Eggman], arrayPos0, ACTIVE_ENTITIES)
1294
arrayPos1 = arrayPos0
1295
arrayPos1--
1296
if ghzEggman[arrayPos1].invincibilityTimer == 0
1297
switch object[arrayPos0].state
1298
case GHZEGGMAN_INITIALSWING
1299
case GHZEGGMAN_MOVELEFT
1300
case GHZEGGMAN_MOVERIGHT
1301
BoxCollisionTest(C_TOUCH, arrayPos0, -20, -16, 20, 16, object.entityPos, -22, -22, 22, 22)
1302
if checkResult == true
1303
ghzEggman[arrayPos0].health--
1304
if ghzEggman[arrayPos0].health == 0
1305
// Sonic Team forgot to add the boss callbacks here LOL
1306
player.score += 1000
1307
object[arrayPos0].animationTimer = 0
1308
object[arrayPos0].animation = GHZEGGANI_DEFEATED
1309
object[arrayPos1].state = WRECKINGBALL_EXPLODE
1310
ghzEggman[arrayPos1].flameAnim = FLAME_INACTIVE
1311
arrayPos1--
1312
ResetObjectEntity(arrayPos1, TypeName[Explosion], 0, object[arrayPos1].xpos, object[arrayPos1].ypos)
1313
arrayPos1--
1314
ResetObjectEntity(arrayPos1, TypeName[Explosion], 0, object[arrayPos1].xpos, object[arrayPos1].ypos)
1315
arrayPos1--
1316
ResetObjectEntity(arrayPos1, TypeName[Explosion], 0, object[arrayPos1].xpos, object[arrayPos1].ypos)
1317
arrayPos1--
1318
ResetObjectEntity(arrayPos1, TypeName[Explosion], 0, object[arrayPos1].xpos, object[arrayPos1].ypos)
1319
arrayPos1--
1320
ResetObjectEntity(arrayPos1, TypeName[Explosion], 0, object[arrayPos1].xpos, object[arrayPos1].ypos)
1321
ghzEggman[arrayPos0].timer = 0
1322
object[arrayPos0].state = GHZEGGMAN_EXPLODE
1323
else
1324
object[arrayPos0].animationTimer = 0
1325
object[arrayPos0].animation = GHZEGGANI_HIT
1326
ghzEggman[arrayPos1].invincibilityTimer = 32
1327
PlaySfx(SfxName[Boss Hit], false)
1328
end if
1329
end if
1330
break
1331
end switch
1332
end if
1333
next
1334
1335
foreach (TypeName[Wrecking Ball], arrayPos0, ACTIVE_ENTITIES)
1336
if object[arrayPos0].state == WRECKINGBALL_ACTIVE
1337
BoxCollisionTest(C_TOUCH, arrayPos0, -22, -22, 22, 22, object.entityPos, -22, -22, 22, 22)
1338
if checkResult == true
1339
temp0 = object[arrayPos0].xpos
1340
temp0 -= object.wreckingBallPos.x
1341
1342
temp1 = object[arrayPos0].ypos
1343
temp1 -= object.wreckingBallPos.y
1344
1345
if object.xvel == 0
1346
object.xvel = temp0
1347
object.speed = object.xvel
1348
else
1349
if object.xvel < 0
1350
if temp0 > 0
1351
temp2 = temp0
1352
temp2 >>= 1
1353
temp0 += temp2
1354
object.xvel = temp0
1355
object.speed = object.xvel
1356
end if
1357
else
1358
if temp0 < 0
1359
temp2 = temp0
1360
temp2 >>= 1
1361
temp0 += temp2
1362
object.xvel = temp0
1363
object.speed = object.xvel
1364
end if
1365
end if
1366
end if
1367
1368
if object.yvel == 0
1369
object.yvel = temp1
1370
else
1371
if object.yvel < 0
1372
if temp1 > 0
1373
temp2 = temp1
1374
temp2 >>= 1
1375
temp1 += temp2
1376
object.yvel = temp1
1377
end if
1378
else
1379
if temp1 < 0
1380
temp2 = temp1
1381
temp2 >>= 1
1382
temp1 += temp2
1383
object.yvel = temp1
1384
end if
1385
end if
1386
end if
1387
end if
1388
end if
1389
1390
// Store the Wrecking Ball's position for next frame
1391
object.wreckingBallPos.x = object[arrayPos0].xpos
1392
object.wreckingBallPos.y = object[arrayPos0].ypos
1393
next
1394
1395
foreach (TypeName[Checkered Ball], arrayPos0, ACTIVE_ENTITIES)
1396
// It can interact with other checkered balls, too!
1397
if arrayPos0 != object.entityPos // (Check to make sure this object isn't interacting with itself)
1398
temp0 = object.xpos
1399
temp0 -= object[arrayPos0].xpos
1400
Abs(temp0)
1401
temp0 >>= 17
1402
if temp0 >= 24
1403
temp0 = 23
1404
end if
1405
GetTableValue(temp6, temp0, CheckeredBall_heightArray)
1406
1407
temp0 = temp6
1408
temp0 >>= 1
1409
temp6 += temp0
1410
temp6 -= 22
1411
temp7 = temp6
1412
FlipSign(temp7)
1413
temp0 = object.xvel
1414
temp1 = object.yvel
1415
temp2 = object.speed
1416
BoxCollisionTest(C_SOLID, arrayPos0, -22, temp6, 22, temp7, object.entityPos, -22, -22, 22, 22)
1417
switch checkResult
1418
case COL_LEFT
1419
case COL_RIGHT
1420
CheckGreater(temp0, 0)
1421
temp3 = checkResult
1422
CheckLower(object.xpos, object[arrayPos0].xpos)
1423
temp3 &= checkResult
1424
CheckLower(temp0, 0)
1425
temp4 = checkResult
1426
CheckGreater(object.xpos, object[arrayPos0].xpos)
1427
temp4 &= checkResult
1428
temp3 |= temp4
1429
if temp3 != false
1430
object.xvel = object[arrayPos0].xvel
1431
object.speed = object[arrayPos0].speed
1432
object[arrayPos0].xvel = temp0
1433
object[arrayPos0].speed = temp2
1434
end if
1435
break
1436
1437
case COL_TOP
1438
if object.xpos < object[arrayPos0].xpos
1439
object.speed -= 0xC00
1440
object.xvel -= 0xC00
1441
object[arrayPos0].speed += 0xC00
1442
object[arrayPos0].xvel += 0xC00
1443
object[arrayPos0].angleVel += 0xC00
1444
else
1445
object.speed += 0xC00
1446
object.xvel += 0xC00
1447
object[arrayPos0].speed -= 0xC00
1448
object[arrayPos0].xvel -= 0xC00
1449
object[arrayPos0].angleVel -= 0xC00
1450
end if
1451
// [Fallthrough]
1452
case COL_BOTTOM
1453
CheckGreater(temp1, 0)
1454
temp3 = checkResult
1455
CheckLower(object.ypos, object[arrayPos0].ypos)
1456
temp3 &= checkResult
1457
CheckLower(temp1, 0)
1458
temp4 = checkResult
1459
CheckGreater(object.ypos, object[arrayPos0].ypos)
1460
temp4 &= checkResult
1461
temp3 |= temp4
1462
if temp3 != false
1463
object.yvel = object[arrayPos0].yvel
1464
object[arrayPos0].yvel = temp1
1465
end if
1466
break
1467
1468
end switch
1469
1470
BoxCollisionTest(C_TOUCH, arrayPos0, -22, temp6, 22, temp7, object.entityPos, -22, -22, 22, 22)
1471
if checkResult == true
1472
if object.xpos < object[arrayPos0].xpos
1473
object.xpos -= 0x10000
1474
else
1475
object.xpos += 0x10000
1476
end if
1477
1478
if object.ypos < object[arrayPos0].ypos
1479
object.ypos -= 0x10000
1480
else
1481
object.ypos += 0x10000
1482
end if
1483
end if
1484
end if
1485
next
1486
1487
foreach (TypeName[Animal Prison], arrayPos0, ACTIVE_ENTITIES)
1488
switch object[arrayPos0].state
1489
case ANIMALPRISON_AWAITOPEN
1490
BoxCollisionTest(C_SOLID, arrayPos0, -32, -24, 32, 32, object.entityPos, -18, -22, 18, 22)
1491
BoxCollisionTest(C_SOLID, arrayPos0, -11, -48, 11, -24, object.entityPos, -18, -22, 18, 22)
1492
if checkResult == COL_TOP
1493
// Open the prison
1494
object[arrayPos0].state = ANIMALPRISON_OPENED
1495
stage.timeEnabled = false
1496
if Player_superState == SUPERSTATE_SUPER
1497
Player_superState = SUPERSTATE_UNTRANSFORM
1498
end if
1499
1500
player[0].controlMode = CONTROLMODE_NONE
1501
1502
// Origins's NOTIFY_BOSS_END isn't called here, so if you ended a level in the Boss Rush with a Checkered Ball + Animal Prison for... some reason, then you could have a little fun
1503
end if
1504
break
1505
1506
case ANIMALPRISON_OPENED
1507
BoxCollisionTest(C_SOLID, arrayPos0, -32, -24, 32, 32, object.entityPos, -18, -22, 18, 22)
1508
BoxCollisionTest(C_SOLID, arrayPos0, -11, -40, 11, -24, object.entityPos, -18, -22, 18, 22)
1509
break
1510
1511
end switch
1512
next
1513
1514
CallFunction(CheckeredBall_PlayerInteraction)
1515
1516
temp0 = object.collisionOffset.x
1517
temp0 |= object.collisionOffset.y
1518
if temp0 != 0
1519
foreach (GROUP_PLAYERS, currentPlayer, ACTIVE_ENTITIES)
1520
BoxCollisionTest(C_SOLID, object.entityPos, -22, -22, 22, 22, currentPlayer, C_BOX, C_BOX, C_BOX, C_BOX)
1521
if checkResult == COL_TOP
1522
player[currentPlayer].xpos += object.collisionOffset.x
1523
player[currentPlayer].ypos += object.collisionOffset.y
1524
end if
1525
next
1526
object.xpos += object.collisionOffset.x
1527
object.ypos += object.collisionOffset.y
1528
object.collisionOffset.x = 0
1529
object.collisionOffset.y = 0
1530
end if
1531
1532
if object.outOfBounds == true
1533
// The usual OOB checks here, where if the object is off screen and its starting position is too, we can safely teleport back to where we started
1534
1535
// Store the ball's current position and move it to its origin pos
1536
temp0 = object.xpos
1537
temp1 = object.ypos
1538
object.xpos = object.startPos.x
1539
object.ypos = object.startPos.y
1540
1541
// Is its starting position out of bounds too?
1542
if object.outOfBounds == true
1543
object.roundedPos.x = object.xpos
1544
object.roundedPos.y = object.ypos
1545
object.xvel = 0
1546
object.yvel = 0
1547
object.speed = 0
1548
object.badnikBonus = 0
1549
object.groundAngle = 0
1550
object.activePlayers = 0
1551
object.ballAngle = 0
1552
object.angleVel = 0
1553
object.playerControlled = 0
1554
if object.priority != PRIORITY_XBOUNDS_DESTROY
1555
object.priority = PRIORITY_BOUNDS
1556
end if
1557
object.state = 0
1558
else
1559
object.xpos = temp0
1560
object.ypos = temp1
1561
end if
1562
end if
1563
1564
object.roundedPos.x = object.xpos
1565
object.roundedPos.x &= 0xFFFF0000
1566
object.roundedPos.y = object.ypos
1567
object.roundedPos.y &= 0xFFFF0000
1568
end event
1569
1570
1571
event ObjectDraw
1572
object.rotation = object.ballAngle
1573
object.rotation >>= 14
1574
1575
temp0 = object.rotation
1576
temp0 += 8
1577
temp0 >>= 4
1578
temp0 &= 7
1579
temp0++
1580
1581
DrawSprite(temp0)
1582
1583
// Draw the shine on top of the ball too
1584
object.inkEffect = INK_ADD
1585
object.alpha = 160
1586
DrawSpriteFX(0, FX_INK, object.xpos, object.ypos)
1587
end event
1588
1589
1590
event ObjectStartup
1591
LoadSpriteSheet("GHZ/Objects2.gif")
1592
1593
// Ball frames
1594
SpriteFrame(-24, -24, 48, 48, 1, 77)
1595
SpriteFrame(-24, -24, 48, 48, 50, 77)
1596
SpriteFrame(-24, -24, 48, 48, 148, 126)
1597
SpriteFrame(-24, -24, 48, 48, 99, 126)
1598
SpriteFrame(-24, -24, 48, 48, 50, 126)
1599
SpriteFrame(-24, -24, 48, 48, 1, 126)
1600
SpriteFrame(-24, -24, 48, 48, 197, 77)
1601
SpriteFrame(-24, -24, 48, 48, 148, 77)
1602
SpriteFrame(-24, -24, 48, 48, 99, 77)
1603
1604
// Load the animation file
1605
// - Note that, even if loaded, the object is never drawn with this animation
1606
// - A script-based animation and drawing system is used, instead
1607
1608
// A note from RDC: this isn't here for sprites, it's here to provide the inner/outer boxes for ProcessObjectMovement()
1609
// since that requires the animation file to work with what's been setup here
1610
1611
// A note from Lave: this isn't here for hitboxes, it seems actually serve no purpose at all instead
1612
// This didn't even exist in initial S1 releases - it was only added after S2 (and its similar OOZ ball) were released
1613
// Hitboxes are set via script, instead
1614
1615
// TODO: Remove/"steamline" the above two comment note sections, I thought it would be funny but nah it hardly works at all :(
1616
// Anyway, that's enough notes, I hope you're ready for your quiz tomorrow
1617
1618
LoadAnimation("WreckingBall.ani")
1619
1620
// Cycle through all Checkered Ball objects and init their values
1621
// Note that this never actually does anything, as no Checkered Ball objects exist in S1's levels
1622
foreach (TypeName[Checkered Ball], arrayPos0, ALL_ENTITIES)
1623
object[arrayPos0].gravity = GRAVITY_AIR
1624
1625
object[arrayPos0].startPos.x = object.xpos
1626
object[arrayPos0].startPos.y = object.ypos
1627
next
1628
1629
SetTableValue(TypeName[Checkered Ball], DebugMode_ObjCount, DebugMode_TypesTable)
1630
SetTableValue(CheckeredBall_DebugDraw, DebugMode_ObjCount, DebugMode_DrawTable)
1631
SetTableValue(CheckeredBall_DebugSpawn, DebugMode_ObjCount, DebugMode_SpawnTable)
1632
DebugMode_ObjCount++
1633
end event
1634
1635
1636
// ========================
1637
// Editor Events
1638
// ========================
1639
1640
event RSDKDraw
1641
DrawSprite(1)
1642
object.inkEffect = INK_ADD
1643
object.alpha = 160
1644
DrawSpriteFX(0, FX_INK, object.xpos, object.ypos)
1645
end event
1646
1647
1648
event RSDKLoad
1649
LoadSpriteSheet("GHZ/Objects2.gif")
1650
SpriteFrame(-24, -24, 48, 48, 1, 77)
1651
SpriteFrame(-24, -24, 48, 48, 50, 77)
1652
1653
SetVariableAlias(ALIAS_VAR_PROPVAL, "unused")
1654
end event
1655
1656