Path: blob/master/Sonic 1/Scripts/GHZ/CheckeredBall.txt
1481 views
// ----------------------------------1// RSDK Project: Sonic 12// Script Description: Checkered Ball Object3// Script Author: Christian Whitehead/Simon Thomley4// Unpacked by Rubberduckycooly's script unpacker5// ----------------------------------67// While the rest of GHZ is structed like v3-esque objects, this one was *definitely* made afterwards, given how it is8// Makes sense though, since it's just a little bonus added in post910// ========================11// Aliases12// ========================1314private alias object.value1 : object.roundedPos.x15private alias object.value2 : object.roundedPos.y16private alias object.value3 : object.ballAngle17private alias object.value4 : object.groundAngle18private alias object.value5 : object.angleVel19private alias object.value6 : object.playerControlled20private alias object.value7 : object.startPos.x21private alias object.value8 : object.startPos.y22// value9 is unused23private alias object.value10 : object.activePlayers24private alias object.value11 : object.badnikBonus25private alias object.value12 : object.collisionOffset.x26private alias object.value13 : object.collisionOffset.y27private alias object.value14 : object.wreckingBallPos.x28private alias object.value15 : object.wreckingBallPos.y2930// Player Aliases31private alias object.xpos : player.xpos32private alias object.ypos : player.ypos33private alias object.xvel : player.xvel34private alias object.yvel : player.yvel35private alias object.speed : player.speed36private alias object.right : player.right37private alias object.left : player.left38private alias object.gravity : player.gravity39private alias object.pushing : player.pushing40private alias object.controlLock : player.controlLock41private alias object.controlMode : player.controlMode42private alias object.collisionLeft : player.collisionLeft43private alias object.collisionRight : player.collisionRight4445private alias object.value20 : player.topSpeed46private alias object.value21 : player.acceleration4748// Super States49private alias 1 : SUPERSTATE_SUPER50private alias 2 : SUPERSTATE_UNTRANSFORM5152// Newtron Fly Aliases53private alias 2 : NEWTRONFLY_APPEARED54private alias 3 : NEWTRONFLY_MOVING5556// Newtron Shoot Aliases57private alias 2 : NEWTRONSHOOT_SHOOT58private alias 3 : NEWTRONSHOOT_SHOOTDELAY5960// Monitor Aliases61private alias object.value0 : monitor.contentsPos.y62private alias object.value1 : monitor.timer6364private alias 0 : MONITOR_STATE_IDLE6566// Spring Aliases67private alias object.value0 : spring.timer68private alias object.value1 : spring.active69private alias object.value2 : spring.extraVelocity7071// Plane Sw V Aliases72private alias object.value0 : planeSwV.extendTop73private alias object.value1 : planeSwV.extendBottom74private alias object.value2 : planeSwV.planeR75private alias object.value3 : planeSwV.planeL76private alias object.value4 : planeSwV.drawOrderR77private alias object.value5 : planeSwV.drawOrderL78private alias object.value6 : planeSwV.onGround7980private alias object.value0 : planeSwV.extendLeft81private alias object.value1 : planeSwV.extendRight8283// Plane Sw H Aliases84private alias object.value0 : planeSwH.extendLeft85private alias object.value1 : planeSwH.extendRight86private alias object.value2 : planeSwH.planeR87private alias object.value3 : planeSwH.planeL88private alias object.value4 : planeSwH.drawOrderR89private alias object.value5 : planeSwH.drawOrderL90private alias object.value6 : planeSwH.onGround9192// CLedge Aliases93private alias 0 : CLEDGE_ACTIVE94private alias 1 : CLEDGE_COLLAPSE95private alias 3 : CLEDGE_NONE9697// Bridge Aliases98private alias object.value0 : bridge.activePlayerCount99private alias object.value1 : bridge.timer100private alias object.value2 : bridge.stoodPos101private alias object.value3 : bridge.depression102private alias object.value4 : bridge.bridgeDepth103private alias object.value5 : bridge.playerID104private alias object.value6 : bridge.startPos105private alias object.value7 : bridge.endPos106107// FallPlatform Aliases108private alias object.value0 : fallPlatform.stood109private alias object.value1 : fallPlatform.collisionOffset.y110111// HPlatform Aliases112private alias object.value0 : hPlatform.stood113private alias object.value3 : hPlatform.collisionOffset.x114private alias object.value4 : hPlatform.collisionOffset.y115116// VPlatform Aliases117private alias object.value1 : vPlatform.collisionOffset.y118119// VPlatform2 Aliases120private alias object.value1 : vPlatform2.collisionOffset.y121122// SwingPlatform123private alias object.value1 : swingPlatform.drawPos.x124private alias object.value2 : swingPlatform.drawPos.y125private alias object.value3 : swingPlatform.collisionOffset.x126private alias object.value4 : swingPlatform.collisionOffset.y127128// GHZEggman Aliases129private alias object.value0 : ghzEggman.timer130private alias object.value1 : ghzEggman.health131private alias object.value4 : ghzEggman.invincibilityTimer132private alias object.value6 : ghzEggman.flameAnim133134private alias 4 : GHZEGGMAN_INITIALSWING135private alias 5 : GHZEGGMAN_MOVERIGHT136private alias 6 : GHZEGGMAN_MOVELEFT137private alias 7 : GHZEGGMAN_EXPLODE138139private alias 3 : GHZEGGANI_HIT140private alias 4 : GHZEGGANI_DEFEATED141142private alias 0 : FLAME_INACTIVE143private alias 2 : FLAME_EXPLODE144145// Wrecking Ball Aliases146private alias 1 : WRECKINGBALL_ACTIVE147private alias 2 : WRECKINGBALL_EXPLODE148149// Animal Prison Aliases150private alias 0 : ANIMALPRISON_AWAITOPEN151private alias 1 : ANIMALPRISON_OPENED152153154// ========================155// Function Declarations156// ========================157158reserve function CheckeredBall_DebugDraw159reserve function CheckeredBall_DebugSpawn160reserve function CheckeredBall_HandlePlayerMove161reserve function CheckeredBall_PlayerInteraction162reserve function CheckeredBall_BadnikBreak163reserve function CheckeredBall_ReflectProjectile164reserve function CheckeredBall_SpringBounce165reserve function CheckeredBall_CLedgeCollapse166reserve function CheckeredBall_HandlePhysics167168169// ========================170// Tables171// ========================172173private table CheckeredBall_heightArray1740, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 6, 7, 8, 9, 10, 12, 14, 16, 20175end table176177// Seems to be unused, and as such, its purpose is unknown...178// 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 object179private table CheckeredBall_unusedTable180253, 251, 248, 245, 243, 240, 237, 235, 232, 229, 226, 224, 221, 219, 216, 213, 210, 208, 205, 203, 200, 197, 195, 192181end table182183184// ========================185// Function Definitions186// ========================187188private function CheckeredBall_DebugDraw189DrawSprite(1)190end function191192193private function CheckeredBall_DebugSpawn194CreateTempObject(TypeName[Checkered Ball], 0, object.xpos, object.ypos)195object[tempObjectPos].gravity = GRAVITY_AIR196object[tempObjectPos].startPos.x = object.xpos197object[tempObjectPos].startPos.y = object.ypos198object[tempObjectPos].roundedPos.x = object.xpos199object[tempObjectPos].roundedPos.y = object.ypos200end function201202203private function CheckeredBall_HandlePlayerMove204object.activePlayers = 0205temp2 = 0206foreach (GROUP_PLAYERS, currentPlayer, ACTIVE_ENTITIES)207// This object is never placed into a level, at least in the final game, so this attract mode check never returns true...208CheckEqual(options.attractMode, true)209temp1 = checkResult210CheckEqual(currentPlayer, 1)211temp1 &= checkResult212213temp0 = player[currentPlayer].acceleration214temp0 >>= 1215if player[currentPlayer].gravity == GRAVITY_GROUND216if player[currentPlayer].xvel < 0217BoxCollisionTest(C_TOUCH, object.entityPos, 0, -22, 23, 22, currentPlayer, C_BOX, C_BOX, C_BOX, C_BOX)218if checkResult == true219if player[currentPlayer].left == true220if temp1 == false221SetBit(object.activePlayers, temp2, true)222temp1 = player[currentPlayer].topSpeed223FlipSign(temp1)224if object.speed > temp1225object.speed -= temp0226end if227object.playerControlled = true228end if229230player[currentPlayer].xpos = player[currentPlayer].collisionRight231player[currentPlayer].xpos += 22232player[currentPlayer].xpos <<= 16233player[currentPlayer].xpos += object.roundedPos.x234235if object.xvel < 0236if player[currentPlayer].speed < object.speed237player[currentPlayer].xvel = object.xvel238player[currentPlayer].speed = object.speed239end if240end if241242player[currentPlayer].pushing = 2243end if244end if245else246if player[currentPlayer].xvel > 0247BoxCollisionTest(C_TOUCH, object.entityPos, -23, -22, 0, 22, currentPlayer, C_BOX, C_BOX, C_BOX, C_BOX)248if checkResult == true249if player[currentPlayer].right == true250if temp1 == false251SetBit(object.activePlayers, temp2, true)252if object.speed < player[currentPlayer].topSpeed253object.speed += temp0254end if255object.playerControlled = true256end if257258player[currentPlayer].xpos = player[currentPlayer].collisionLeft259player[currentPlayer].xpos += -22260player[currentPlayer].xpos <<= 16261player[currentPlayer].xpos += object.roundedPos.x262263if object.xvel > 0264if player[currentPlayer].speed > object.speed265player[currentPlayer].xvel = object.xvel266player[currentPlayer].speed = object.speed267end if268end if269270player[currentPlayer].pushing = 2271end if272end if273end if274end if275end if276277temp2++278next279end function280281282private function CheckeredBall_PlayerInteraction283temp6 = object.xpos284temp6 &= 0xFFFF0000285temp6 -= object.roundedPos.x286287temp7 = object.ypos288temp7 &= 0xFFFF0000289temp7 -= object.roundedPos.y290291temp4 = object.xpos292temp5 = object.ypos293294object.xpos = object.roundedPos.x295object.ypos = object.roundedPos.y296297temp2 = 0298foreach (GROUP_PLAYERS, currentPlayer, ACTIVE_ENTITIES)299GetBit(temp0, object.activePlayers, temp2)300if temp0 == true301if player[currentPlayer].xpos < object.xpos302temp1 = player[currentPlayer].collisionRight303FlipSign(temp1)304temp1 -= 22305else306temp1 = player[currentPlayer].collisionLeft307FlipSign(temp1)308temp1 += 22309end if310temp1 <<= 16311312player[currentPlayer].xpos = temp1313player[currentPlayer].xpos += temp4314else315BoxCollisionTest(C_SOLID, object.entityPos, -22, -22, 22, 22, currentPlayer, C_BOX, C_BOX, C_BOX, C_BOX)316if checkResult == COL_TOP317player[currentPlayer].xpos += temp6318temp0 = temp6319temp0 >>= 1320player[currentPlayer].xpos += temp0321player[currentPlayer].ypos += temp7322if player[currentPlayer].xvel != 0323temp0 = player[currentPlayer].acceleration324temp0 >>= 2325if player[currentPlayer].xvel > 0326FlipSign(temp0)327end if328else329temp0 = 0330end if331object.speed += temp0332333if temp0 != 0334object.playerControlled = true335end if336337object.xpos = temp4338object.ypos = temp5339BoxCollisionTest(C_SOLID, object.entityPos, -22, -22, 22, 22, currentPlayer, C_BOX, C_BOX, C_BOX, C_BOX)340object.xpos = object.roundedPos.x341object.ypos = object.roundedPos.y342if checkResult == COL_NONE343temp0 = temp6344temp1 = temp6345temp0 >>= 1346temp1 += temp0347player[currentPlayer].speed += temp0348player[currentPlayer].xvel = player[currentPlayer].speed349player[currentPlayer].gravity = GRAVITY_AIR350player[currentPlayer].controlLock = 15351end if352end if353354if checkResult == COL_BOTTOM355if object.yvel >= 0356if player[currentPlayer].gravity == GRAVITY_GROUND357// The Ball's falling downwards on top of the player, crush them358CallFunction(Player_Kill)359end if360end if361end if362end if363temp2++364next365366object.xpos = temp4367object.ypos = temp5368end function369370371private function CheckeredBall_BadnikBreak372temp0 = object.xvel373temp0 |= object.yvel374375if temp0 != 0376ResetObjectEntity(object[arrayPos0].entityPos, TypeName[Blank Object], 0, object[arrayPos0].xpos, object[arrayPos0].ypos)377Rand(checkResult, 32)378if checkResult >= 16379CreateTempObject(animalType1, 0, object[arrayPos0].xpos, object[arrayPos0].ypos)380else381CreateTempObject(animalType2, 0, object[arrayPos0].xpos, object[arrayPos0].ypos)382end if383object[tempObjectPos].priority = PRIORITY_ACTIVE_SMALL384385CreateTempObject(TypeName[Smoke Puff], 0, object[arrayPos0].xpos, object[arrayPos0].ypos)386object[tempObjectPos].drawOrder = 4387388CreateTempObject(TypeName[Object Score], object.badnikBonus, object[arrayPos0].xpos, object[arrayPos0].ypos)389object[tempObjectPos].drawOrder = 4390391PlaySfx(SfxName[Destroy], false)392393switch object.badnikBonus394case 0395player.score += 100396break397398case 1399player.score += 200400break401402case 2403player.score += 500404break405406case 3 // Fall through407case 4408case 5409case 6410case 7411case 8412case 9413case 10414case 11415case 12416case 13417case 14418player.score += 1000419break420421case 15422player.score += 10000423break424425end switch426427if object.badnikBonus < 15428object.badnikBonus++429end if430end if431end function432433434private function CheckeredBall_ReflectProjectile435// Do some maths to find where the projectile should go now436temp0 = object.xpos437temp0 -= object[arrayPos0].xpos438temp1 = object.ypos439temp1 -= object[arrayPos0].ypos440441ATan2(temp2, temp0, temp1)442Sin256(temp0, temp2)443Cos256(temp1, temp2)444445object[arrayPos0].xvel = temp1446object[arrayPos0].xvel *= -0x800447object[arrayPos0].yvel = temp0448object[arrayPos0].yvel *= -0x800449end function450451452private function CheckeredBall_SpringBounce453switch object[arrayPos0].propertyValue454case 0455// Upwards Spring456457temp0 = spring[arrayPos0].active458if object.gravity == GRAVITY_AIR459temp0 = true460end if461462if object.collisionMode > CMODE_FLOOR463if object.yvel < 0464temp0 = true465end if466end if467468if temp0 == false469BoxCollisionTest(C_SOLID, object[arrayPos0].entityPos, -14, -8, 14, 8, object.entityPos, -22, -22, 22, 22)470BoxCollisionTest(C_TOUCH, object[arrayPos0].entityPos, -14, -10, 14, -6, object.entityPos, -22, -22, 22, 22)471if checkResult == true472spring[arrayPos0].timer = 1473object.tileCollisions = true474object.gravity = GRAVITY_AIR475object.speed = object.xvel476object.yvel = temp7477FlipSign(object.yvel)478479object.yvel += spring[arrayPos0].extraVelocity480PlaySfx(SfxName[Spring], false)481end if482else483if object.yvel >= 0484BoxCollisionTest(C_PLATFORM, object[arrayPos0].entityPos, -14, -8, 14, 8, object.entityPos, -22, -22, 22, 22)485BoxCollisionTest(C_TOUCH, object[arrayPos0].entityPos, -14, -10, 14, -6, object.entityPos, -22, -22, 22, 22)486if checkResult == true487spring[arrayPos0].timer = 1488object.tileCollisions = true489object.gravity = GRAVITY_AIR490object.speed = object.xvel491object.yvel = temp7492FlipSign(object.yvel)493494object.yvel += spring[arrayPos0].extraVelocity495PlaySfx(SfxName[Spring], false)496end if497end if498end if499break500501case 1502// Spring facing Right503504BoxCollisionTest(C_SOLID, object[arrayPos0].entityPos, -8, -14, 8, 14, object.entityPos, -22, -22, 22, 22)505if object.gravity == GRAVITY_GROUND506BoxCollisionTest(C_TOUCH, object[arrayPos0].entityPos, 6, -14, 10, 14, object.entityPos, -22, -22, 22, 22)507if checkResult == true508spring[arrayPos0].timer = 1509object.tileCollisions = true510object.speed = temp7511object.collisionMode = CMODE_FLOOR512object.direction = FACING_RIGHT // The Checkered Ball's direction doesn't matter too much, but sure513PlaySfx(SfxName[Spring], false)514end if515end if516break517518case 2519// Spring facing Left520521BoxCollisionTest(C_SOLID, object[arrayPos0].entityPos, -8, -14, 8, 14, object.entityPos, -22, -22, 22, 22)522if object.gravity == GRAVITY_GROUND523BoxCollisionTest(C_TOUCH, object[arrayPos0].entityPos, -10, -14, -6, 14, object.entityPos, -22, -22, 22, 22)524if checkResult == true525spring[arrayPos0].timer = 1526object.tileCollisions = true527object.speed = temp7528FlipSign(object.speed)529object.collisionMode = CMODE_FLOOR530object.direction = FACING_LEFT // I mean if you really wanna ig?531PlaySfx(SfxName[Spring], false)532end if533end if534break535536case 3537// Downwards Spring538539BoxCollisionTest(C_SOLID, object[arrayPos0].entityPos, -14, -8, 14, 8, object.entityPos, -22, -22, 22, 22)540BoxCollisionTest(C_TOUCH, object[arrayPos0].entityPos, -14, 6, 14, 10, object.entityPos, -22, -22, 22, 22)541if checkResult == true542spring[arrayPos0].timer = 1543if object.collisionMode == CMODE_ROOF544FlipSign(object.speed)545FlipSign(object.xvel)546end if547object.tileCollisions = true548object.gravity = GRAVITY_AIR549object.speed = object.xvel550object.yvel = temp7551PlaySfx(SfxName[Spring], true)552end if553break554555end switch556end function557558559private function CheckeredBall_CLedgeCollapse560if object[arrayPos0].state < CLEDGE_NONE561if object.yvel >= 0562temp0 = object.xpos563temp0 -= object[arrayPos0].xpos564temp0 >>= 17565temp0 += 24566if temp0 < 0567temp0 = 0568end if569570if temp0 > 47571temp0 = 47572end if573574if temp7 == false575// Ledge is facing Right576GetTableValue(temp1, temp0, CLedgeLeft_heightArray)577else578// Ledge is facing Left, invert the value to fetch579temp2 = 47580temp2 -= temp0581GetTableValue(temp1, temp2, CLedgeLeft_heightArray)582end if583584temp1 -= 84585temp0 = temp1586temp0 += 32587BoxCollisionTest(C_PLATFORM, arrayPos0, -48, temp1, 48, temp0, object.entityPos, -18, -22, 18, 22)588if checkResult == true589object.ypos += 0x40000590if object[arrayPos0].state == CLEDGE_ACTIVE591object[arrayPos0].state = CLEDGE_COLLAPSE592end if593end if594end if595end if596end function597598599private function CheckeredBall_HandlePhysics600if object.gravity == GRAVITY_AIR601object.yvel += 0x3800602object.speed = object.xvel603else604Sin256(temp0, object.groundAngle)605temp0 *= 0x2000606temp0 >>= 8607object.speed += temp0608object.angleVel = object.speed609if temp0 == 0610if object.playerControlled == false611if object.speed > 0612object.speed -= 0x400613if object.speed < 0614object.speed = 0615end if616else617object.speed += 0x400618if object.speed > 0619object.speed = 0620end if621end if622end if623end if624625Cos256(temp0, object.groundAngle)626temp0 *= object.speed627temp0 >>= 8628object.xvel = temp0629630Sin256(temp0, object.groundAngle)631temp0 *= object.speed632temp0 >>= 8633object.yvel = temp0634end if635636object.playerControlled = false637end function638639640// ========================641// Events642// ========================643644event ObjectUpdate645if object.priority != PRIORITY_XBOUNDS_DESTROY646object.priority = PRIORITY_ACTIVE647end if648649CallFunction(CheckeredBall_HandlePlayerMove)650651object.ballAngle += object.angleVel652653// These don't actually do anything - the engine doesn't support direct setting of these values by script654// Instead, the Checkered Ball's collision values are set with the ani file655object.collisionLeft = -22656object.collisionTop = -22657object.collisionRight = 22658object.collisionBottom = 22659660CallFunction(CheckeredBall_HandlePhysics)661662ProcessObjectMovement()663664object.groundAngle = object.angle665666// 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 interactions667// Later, however, Taxman updated this code to use separate, individual foreach checks for every interaction instead of the old giant foreach + case-switch668// 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)669670foreach (TypeName[Motobug], arrayPos0, ACTIVE_ENTITIES)671BoxCollisionTest(C_TOUCH, object.entityPos, -22, -22, 22, 22, arrayPos0, -14, -14, 14, 14)672if checkResult == true673CallFunction(CheckeredBall_BadnikBreak)674end if675next676677foreach (TypeName[Buzz Bomber], arrayPos0, ACTIVE_ENTITIES)678// The Buzz Bomber's hitbox is normally -24, -12, 24, 12...679BoxCollisionTest(C_TOUCH, object.entityPos, -22, -22, 22, 22, arrayPos0, -16, -7, 16, 7)680if checkResult == true681CallFunction(CheckeredBall_BadnikBreak)682end if683next684685foreach (TypeName[Crabmeat], arrayPos0, ACTIVE_ENTITIES)686BoxCollisionTest(C_TOUCH, object.entityPos, -22, -22, 22, 22, arrayPos0, -14, -14, 14, 14)687if checkResult == true688CallFunction(CheckeredBall_BadnikBreak)689end if690next691692foreach (TypeName[Chopper], arrayPos0, ACTIVE_ENTITIES)693BoxCollisionTest(C_TOUCH, object.entityPos, -22, -22, 22, 22, arrayPos0, -12, -14, 12, 14)694if checkResult == true695CallFunction(CheckeredBall_BadnikBreak)696end if697next698699foreach (TypeName[Splats], arrayPos0, ACTIVE_ENTITIES)700// A fellow unused object, go ahead and interact with Splats too701// Something interesting - this interaction didn't even exist in the original S1 release,702// it was only added later in an update703// Why they decided to update an unused object to add an unused interaction for an unused enemy is beyond me, though...704705BoxCollisionTest(C_TOUCH, object.entityPos, -22, -22, 22, 22, arrayPos0, -10, -20, 6, 20)706if checkResult == true707CallFunction(CheckeredBall_BadnikBreak)708end if709next710711foreach (TypeName[Newtron Fly], arrayPos0, ACTIVE_ENTITIES)712// Only hurt Newtrons when they're active, not in their hidden states713switch object[arrayPos0].state714case NEWTRONFLY_APPEARED715case NEWTRONFLY_MOVING716BoxCollisionTest(C_TOUCH, object.entityPos, -22, -22, 22, 22, arrayPos0, -16, -8, 16, 8)717if checkResult == true718CallFunction(CheckeredBall_BadnikBreak)719end if720break721722end switch723next724725foreach (TypeName[Newtron Shoot], arrayPos0, ACTIVE_ENTITIES)726// Only hurt Newtrons when they're active, not in their hidden states727switch object[arrayPos0].state728case NEWTRONSHOOT_SHOOT729case NEWTRONSHOOT_SHOOTDELAY730BoxCollisionTest(C_TOUCH, object.entityPos, -22, -22, 22, 22, arrayPos0, -12, -14, 12, 14)731if checkResult == true732CallFunction(CheckeredBall_BadnikBreak)733end if734break735736end switch737next738739foreach (TypeName[Buzz Bomber Shot], arrayPos0, ACTIVE_ENTITIES)740BoxCollisionTest(C_TOUCH, object.entityPos, -22, -22, 22, 22, arrayPos0, -6, -6, 6, 6)741if checkResult == true742CallFunction(CheckeredBall_ReflectProjectile)743end if744next745746foreach (TypeName[Crabmeat Shot], arrayPos0, ACTIVE_ENTITIES)747BoxCollisionTest(C_TOUCH, object.entityPos, -22, -22, 22, 22, arrayPos0, -6, -6, 6, 6)748if checkResult == true749CallFunction(CheckeredBall_ReflectProjectile)750end if751next752753foreach (TypeName[Newtron Shot], arrayPos0, ACTIVE_ENTITIES)754BoxCollisionTest(C_TOUCH, object.entityPos, -22, -22, 22, 22, arrayPos0, -6, -6, 6, 6)755if checkResult == true756CallFunction(CheckeredBall_ReflectProjectile)757end if758next759760foreach (TypeName[Monitor], arrayPos0, ACTIVE_ENTITIES)761BoxCollisionTest(C_TOUCH, object.entityPos, -22, -22, 22, 22, arrayPos0, -16, -14, 16, 16)762if checkResult == true763object[arrayPos0].state = MONITOR_STATE_IDLE764CreateTempObject(TypeName[Smoke Puff], 0, object[arrayPos0].xpos, object[arrayPos0].ypos)765object[tempObjectPos].drawOrder = 4766object[arrayPos0].type = TypeName[Broken Monitor]767768if object[arrayPos0].priority != PRIORITY_XBOUNDS_DESTROY769object[arrayPos0].priority = PRIORITY_ACTIVE770end if771772object[arrayPos0].alpha = 0xFF773monitor[arrayPos0].contentsPos.y = object[arrayPos0].ypos774monitor[arrayPos0].timer = -0x30000775776PlaySfx(SfxName[Destroy], false)777end if778next779780foreach (TypeName[Rock], arrayPos0, ACTIVE_ENTITIES)781// 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 second782BoxCollisionTest(C_SOLID, arrayPos0, -16, -16, 16, 16, object.entityPos, -22, -22, 22, 22)783switch checkResult784case COL_TOP785object.gravity = GRAVITY_GROUND786break787788case COL_LEFT789if object.speed > 0790object.speed = 0791end if792break793794case COL_RIGHT795if object.speed < 0796object.speed = 0797end if798break799800end switch801next802803foreach (TypeName[Spikes], arrayPos0, ACTIVE_ENTITIES)804// Have different tests for each of the Spike types805switch object[arrayPos0].propertyValue806case 0807// 3 Spikes (Up)808BoxCollisionTest(C_SOLID, arrayPos0, -20, -16, 20, 16, object.entityPos, -22, -22, 22, 22)809break810811case 1812// 3 Spikes (Right)813BoxCollisionTest(C_SOLID, arrayPos0, -16, -20, 15, 20, object.entityPos, -22, -22, 22, 22)814break815816case 2817// 3 Spikes (Left)818BoxCollisionTest(C_SOLID, arrayPos0, -15, -20, 16, 20, object.entityPos, -22, -22, 22, 22)819break820821case 3822// 3 Spikes (Down)823BoxCollisionTest(C_SOLID, arrayPos0, -20, -16, 20, 15, object.entityPos, -22, -22, 22, 22)824break825826case 4827// 1 Spike (Up)828BoxCollisionTest(C_SOLID, arrayPos0, -4, -16, 4, 16, object.entityPos, -22, -22, 22, 22)829break830831case 5832// 1 Spike (Right)833BoxCollisionTest(C_SOLID, arrayPos0, -16, -4, 15, 4, object.entityPos, -22, -22, 22, 22)834break835836case 6837// 1 Spike (Left)838BoxCollisionTest(C_SOLID, arrayPos0, -15, -4, 16, 4, object.entityPos, -22, -22, 22, 22)839break840841case 7842// 1 Spike (Down)843BoxCollisionTest(C_SOLID, arrayPos0, -4, -16, 4, 15, object.entityPos, -22, -22, 22, 22)844break845846case 8847// 3 Spikes (Spaced Out) (Up)848BoxCollisionTest(C_SOLID, arrayPos0, -28, -16, 28, 16, object.entityPos, -22, -22, 22, 22)849break850851case 9852// 3 Spikes (Spaced Out) (Right)853BoxCollisionTest(C_SOLID, arrayPos0, -16, -28, 15, 28, object.entityPos, -22, -22, 22, 22)854break855856case 10857// 3 Spikes (Spaced Out) (Left)858BoxCollisionTest(C_SOLID, arrayPos0, -15, -28, 16, 28, object.entityPos, -22, -22, 22, 22)859break860861case 11862// 3 Spikes (Spaced Out) (Down)863BoxCollisionTest(C_SOLID, arrayPos0, -28, -16, 28, 15, object.entityPos, -22, -22, 22, 22)864break865866case 12867// 6 Spikes (Spaced Out) (Up)868BoxCollisionTest(C_SOLID, arrayPos0, -64, -16, 64, 16, object.entityPos, -22, -22, 22, 22)869break870871case 13872// 6 Spikes (Spaced Out) (Right)873BoxCollisionTest(C_SOLID, arrayPos0, -16, -64, 15, 64, object.entityPos, -22, -22, 22, 22)874break875876case 14877// 6 Spikes (Spaced Out) (Left)878BoxCollisionTest(C_SOLID, arrayPos0, -15, -64, 16, 64, object.entityPos, -22, -22, 22, 22)879break880881case 15882// 6 Spikes (Spaced Out) (Down)883BoxCollisionTest(C_SOLID, arrayPos0, -64, -16, 64, 15, object.entityPos, -22, -22, 22, 22)884break885886end switch887888switch checkResult889case COL_TOP890object.gravity = GRAVITY_GROUND891break892893case COL_LEFT894if object.speed > 0895object.speed = 0896end if897break898899case COL_RIGHT900if object.speed < 0901object.speed = 0902end if903break904905end switch906next907908foreach (TypeName[Breakable Wall], arrayPos0, ACTIVE_ENTITIES)909// Only interact with solid walls, not wall fragments910if object[arrayPos0].propertyValue < 3911912// Get the absolute version of this object's speed913temp0 = object.speed914Abs(temp0)915916// 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 frame917if temp0 >= 0x20000918BoxCollisionTest(C_TOUCH, arrayPos0, -17, -32, 17, 32, object.entityPos, -22, -22, 22, 22)919if checkResult == true920// Destroy the wall921922// Delete the wall object923object[arrayPos0].type = TypeName[Blank Object]924925// Bug Details:926// -> Although this worked in initial versions of S1, it now plays the jump sound instead927// 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]928// -> This use of SfxName was neglected to be updated, which is why this now invalid TypeName plays sfx ID 0 (the jump sound) instead929PlaySfx(SfxName[Ledge Break], false)930931temp0 = object[arrayPos0].propertyValue932temp0 <<= 1933temp0 += 3934935temp1 = temp0936temp1++937938temp2 = object[arrayPos0].xpos939temp2 -= 0x80000940941temp3 = object[arrayPos0].xpos942temp3 += 0x80000943944temp4 = object[arrayPos0].ypos945temp4 -= 0x180000946947// Determine which way to blow wall fragments based on which way the ball is "facing"948if object.xpos < object[arrayPos0].xpos949// Sending the fragments left950951CreateTempObject(TypeName[Breakable Wall], temp0, temp2, temp4)952object[tempObjectPos].xvel = -0x60000953object[tempObjectPos].yvel = -0x60000954object[tempObjectPos].drawOrder = 4955956CreateTempObject(TypeName[Breakable Wall], temp1, temp3, temp4)957object[tempObjectPos].xvel = -0x40000958object[tempObjectPos].yvel = -0x50000959object[tempObjectPos].drawOrder = 4960961temp4 += 0x100000962963CreateTempObject(TypeName[Breakable Wall], temp0, temp2, temp4)964object[tempObjectPos].xvel = -0x80000965object[tempObjectPos].yvel = -0x20000966object[tempObjectPos].drawOrder = 4967968CreateTempObject(TypeName[Breakable Wall], temp1, temp3, temp4)969object[tempObjectPos].xvel = -0x60000970object[tempObjectPos].yvel = -0x10000971object[tempObjectPos].drawOrder = 4972973temp4 += 0x100000974975CreateTempObject(TypeName[Breakable Wall], temp0, temp2, temp4)976object[tempObjectPos].xvel = -0x80000977object[tempObjectPos].yvel = 0x20000978object[tempObjectPos].drawOrder = 4979980CreateTempObject(TypeName[Breakable Wall], temp1, temp3, temp4)981object[tempObjectPos].xvel = -0x60000982object[tempObjectPos].yvel = 0x10000983object[tempObjectPos].drawOrder = 4984985temp4 += 0x100000986987CreateTempObject(TypeName[Breakable Wall], temp0, temp2, temp4)988object[tempObjectPos].xvel = -0x60000989object[tempObjectPos].yvel = 0x60000990object[tempObjectPos].drawOrder = 4991992CreateTempObject(TypeName[Breakable Wall], temp1, temp3, temp4)993object[tempObjectPos].xvel = -0x40000994object[tempObjectPos].yvel = 0x50000995object[tempObjectPos].drawOrder = 4996else997// Sending the fragments right998999CreateTempObject(TypeName[Breakable Wall], temp0, temp2, temp4)1000object[tempObjectPos].xvel = 0x400001001object[tempObjectPos].yvel = -0x500001002object[tempObjectPos].drawOrder = 410031004CreateTempObject(TypeName[Breakable Wall], temp1, temp3, temp4)1005object[tempObjectPos].xvel = 0x600001006object[tempObjectPos].yvel = -0x600001007object[tempObjectPos].drawOrder = 410081009temp4 += 0x10000010101011CreateTempObject(TypeName[Breakable Wall], temp0, temp2, temp4)1012object[tempObjectPos].xvel = 0x600001013object[tempObjectPos].yvel = -0x100001014object[tempObjectPos].drawOrder = 410151016CreateTempObject(TypeName[Breakable Wall], temp1, temp3, temp4)1017object[tempObjectPos].xvel = 0x800001018object[tempObjectPos].yvel = -0x200001019object[tempObjectPos].drawOrder = 410201021temp4 += 0x10000010221023CreateTempObject(TypeName[Breakable Wall], temp0, temp2, temp4)1024object[tempObjectPos].xvel = 0x600001025object[tempObjectPos].yvel = 0x100001026object[tempObjectPos].drawOrder = 410271028CreateTempObject(TypeName[Breakable Wall], temp1, temp3, temp4)1029object[tempObjectPos].xvel = 0x800001030object[tempObjectPos].yvel = 0x200001031object[tempObjectPos].drawOrder = 410321033temp4 += 0x10000010341035CreateTempObject(TypeName[Breakable Wall], temp0, temp2, temp4)1036object[tempObjectPos].xvel = 0x400001037object[tempObjectPos].yvel = 0x500001038object[tempObjectPos].drawOrder = 410391040CreateTempObject(TypeName[Breakable Wall], temp1, temp3, temp4)1041object[tempObjectPos].xvel = 0x600001042object[tempObjectPos].yvel = 0x600001043object[tempObjectPos].drawOrder = 41044end if1045end if1046else1047BoxCollisionTest(C_SOLID, arrayPos0, -17, -32, 17, 32, object.entityPos, -22, -22, 22, 22)1048switch checkResult1049case COL_TOP1050object.gravity = GRAVITY_GROUND1051break10521053case COL_LEFT1054if object.speed > 01055object.speed = 01056end if1057break10581059case COL_RIGHT1060if object.speed < 01061object.speed = 01062end if1063break10641065end switch1066end if1067end if1068next10691070foreach (TypeName[Bridge], arrayPos0, ACTIVE_ENTITIES)1071if object.xpos > bridge[arrayPos0].startPos1072if object.xpos < bridge[arrayPos0].endPos1073if object.entityPos == bridge[arrayPos0].playerID1074bridge[arrayPos0].stoodPos = object.xpos1075bridge[arrayPos0].stoodPos -= bridge[arrayPos0].startPos1076temp0 = bridge[arrayPos0].stoodPos1077temp0 >>= 81078temp1 = bridge[arrayPos0].endPos1079temp1 -= bridge[arrayPos0].startPos1080temp2 = temp11081temp2 >>= 161082temp0 /= temp21083Sin(bridge[arrayPos0].depression, temp0)1084temp1 >>= 131085bridge[arrayPos0].depression *= temp11086temp0 = object[arrayPos0].ypos1087temp0 -= 0x3000001088if object.ypos > temp01089if object.yvel >= 01090temp2 = object.collisionBottom1091FlipSign(temp2)1092temp2 <<= 161093temp2 += bridge[arrayPos0].bridgeDepth1094temp2 -= 0x800001095bridge[arrayPos0].activePlayerCount++1096object.ypos = object[arrayPos0].ypos1097object.ypos += temp21098object.gravity = GRAVITY_GROUND1099object.yvel = 01100object.floorSensorL = true1101object.floorSensorC = true1102object.floorSensorR = true1103else1104bridge[arrayPos0].playerID = -21105end if1106end if1107else1108if object.yvel >= 01109temp0 = object.xpos1110temp0 -= bridge[arrayPos0].startPos1111if temp0 > bridge[arrayPos0].stoodPos1112temp0 = bridge[arrayPos0].endPos1113temp0 -= object.xpos1114temp3 = bridge[arrayPos0].endPos1115temp3 -= bridge[arrayPos0].startPos1116temp3 -= bridge[arrayPos0].stoodPos1117temp1 = temp01118temp1 <<= 71119temp1 /= temp31120else1121temp1 = temp01122temp1 <<= 71123temp1 /= bridge[arrayPos0].stoodPos1124end if1125Sin(temp2, temp1)1126temp2 *= bridge[arrayPos0].bridgeDepth1127temp2 >>= 91128temp2 -= 0x800001129if object.yvel < 0x80001130temp3 = temp21131temp3 >>= 161132temp4 = temp31133temp3 -= 81134else1135temp3 = temp21136temp3 >>= 161137temp4 = temp31138temp4 += 81139end if11401141BoxCollisionTest(C_TOUCH, object[arrayPos0].entityPos, -0x400, temp3, 0x400, temp4, object.entityPos, -18, -22, 18, 22)1142if checkResult == true1143bridge[arrayPos0].activePlayerCount++1144object.ypos = object.collisionBottom1145FlipSign(object.ypos)1146object.ypos <<= 161147object.ypos += object[arrayPos0].ypos1148object.ypos += temp21149object.floorSensorL = true1150object.floorSensorC = true1151object.floorSensorR = true1152bridge[arrayPos0].playerID = object.entityPos1153object.gravity = GRAVITY_GROUND1154object.yvel = 01155end if1156end if1157end if1158else1159if object.entityPos == bridge[arrayPos0].playerID1160bridge[arrayPos0].playerID = -21161bridge[arrayPos0].stoodPos = 321162end if1163end if1164else1165if object.entityPos == bridge[arrayPos0].playerID1166bridge[arrayPos0].playerID = -21167bridge[arrayPos0].stoodPos = 321168end if1169end if1170next11711172foreach (TypeName[Yellow Spring], arrayPos0, ACTIVE_ENTITIES)1173temp7 = 0xA00001174CallFunction(CheckeredBall_SpringBounce)1175next11761177foreach (TypeName[Red Spring], arrayPos0, ACTIVE_ENTITIES)1178temp7 = 0x1000001179CallFunction(CheckeredBall_SpringBounce)1180next11811182foreach (TypeName[Fall Platform], arrayPos0, ACTIVE_ENTITIES)1183object[arrayPos0].ypos -= fallPlatform[arrayPos0].collisionOffset.y1184BoxCollisionTest(C_PLATFORM, object[arrayPos0].entityPos, -32, -8, 32, 0, object.entityPos, -18, -22, 18, 22)1185if checkResult == true1186fallPlatform[arrayPos0].stood = true1187object.collisionOffset.y = fallPlatform[arrayPos0].collisionOffset.y1188end if1189object[arrayPos0].ypos += fallPlatform[arrayPos0].collisionOffset.y1190next11911192foreach (TypeName[H Platform], arrayPos0, ACTIVE_ENTITIES)1193object[arrayPos0].xpos -= hPlatform[arrayPos0].collisionOffset.x1194object[arrayPos0].ypos -= hPlatform[arrayPos0].collisionOffset.y1195BoxCollisionTest(C_PLATFORM, object[arrayPos0].entityPos, -32, -8, 32, 12, object.entityPos, -18, -22, 18, 22)1196if checkResult == true1197hPlatform[arrayPos0].stood = true1198object.collisionOffset.x = hPlatform[arrayPos0].collisionOffset.x1199object.collisionOffset.y = hPlatform[arrayPos0].collisionOffset.y1200end if1201object[arrayPos0].xpos += hPlatform[arrayPos0].collisionOffset.x1202object[arrayPos0].ypos += hPlatform[arrayPos0].collisionOffset.y1203next12041205foreach (TypeName[V Platform], arrayPos0, ACTIVE_ENTITIES)1206object[arrayPos0].ypos -= vPlatform[arrayPos0].collisionOffset.y1207BoxCollisionTest(C_PLATFORM, object[arrayPos0].entityPos, -32, -8, 32, 12, object.entityPos, -18, -22, 18, 22)1208if checkResult == true1209object.collisionOffset.y = vPlatform[arrayPos0].collisionOffset.y1210end if1211object[arrayPos0].ypos += vPlatform[arrayPos0].collisionOffset.y1212next12131214foreach (TypeName[V Platform 2], arrayPos0, ACTIVE_ENTITIES)1215object[arrayPos0].ypos -= vPlatform2[arrayPos0].collisionOffset.y1216BoxCollisionTest(C_PLATFORM, object[arrayPos0].entityPos, -32, -2, 32, 12, object.entityPos, -18, -22, 18, 22)1217if checkResult == true1218object.collisionOffset.y = vPlatform2[arrayPos0].collisionOffset.y1219end if1220object[arrayPos0].ypos += vPlatform2[arrayPos0].collisionOffset.y1221next12221223foreach (TypeName[Swing Platform], arrayPos0, ACTIVE_ENTITIES)1224temp0 = object[arrayPos0].xpos1225temp1 = object[arrayPos0].ypos1226object[arrayPos0].xpos = swingPlatform[arrayPos0].drawPos.x1227object[arrayPos0].ypos = swingPlatform[arrayPos0].drawPos.y1228object[arrayPos0].xpos -= swingPlatform[arrayPos0].collisionOffset.x1229object[arrayPos0].ypos -= swingPlatform[arrayPos0].collisionOffset.y1230BoxCollisionTest(C_PLATFORM, object[arrayPos0].entityPos, -24, -8, 24, 8, object.entityPos, -18, -22, 18, 22)1231if checkResult == true1232object.collisionOffset.x = swingPlatform[arrayPos0].collisionOffset.x1233object.collisionOffset.y = swingPlatform[arrayPos0].collisionOffset.y1234end if1235object[arrayPos0].xpos = temp01236object[arrayPos0].ypos = temp11237next12381239foreach (TypeName[C Ledge Left], arrayPos0, ACTIVE_ENTITIES)1240temp7 = true1241CallFunction(CheckeredBall_CLedgeCollapse)1242next12431244foreach (TypeName[C Ledge Right], arrayPos0, ACTIVE_ENTITIES)1245temp7 = false1246CallFunction(CheckeredBall_CLedgeCollapse)1247next12481249foreach (TypeName[Plane Sw V], arrayPos0, ACTIVE_ENTITIES)1250CheckEqual(planeSwV[arrayPos0].onGround, false)1251temp0 = checkResult1252CheckEqual(object.gravity, GRAVITY_GROUND)1253temp0 |= checkResult1254if temp0 == true1255BoxCollisionTest(C_TOUCH, object[arrayPos0].entityPos, -12, planeSwV[arrayPos0].extendTop, 12, planeSwV[arrayPos0].extendBottom, object.entityPos, -10, -22, 10, 22)1256if checkResult == true1257if object.xvel > 01258object.collisionPlane = planeSwV[arrayPos0].planeL1259object.drawOrder = planeSwV[arrayPos0].drawOrderL1260else1261object.collisionPlane = planeSwV[arrayPos0].planeR1262object.drawOrder = planeSwV[arrayPos0].drawOrderR1263end if1264end if1265end if1266next12671268// Bug Details:1269// -> This is supposed to check for Plane Sw H, not V again...1270// -> This was only broken in an update, during the giant case-switch to individual foreach transfer1271// Earlier versions of the script correcty used [Plane Sw H] here, though the latest versions don't and those are what we're sticking with1272foreach (TypeName[Plane Sw V], arrayPos0, ACTIVE_ENTITIES)1273CheckEqual(planeSwV[arrayPos0].onGround, false)1274temp0 = checkResult1275CheckEqual(object.gravity, GRAVITY_GROUND)1276temp0 |= checkResult1277if temp0 == true1278// This is looking at a Sw H but using its values as a Sw V, this only works perchance1279BoxCollisionTest(C_TOUCH, object[arrayPos0].entityPos, planeSwV[arrayPos0].extendLeft, -12, planeSwV[arrayPos0].extendRight, 12, object.entityPos, -22, -10, 22, 10)1280if checkResult == true1281if object.yvel > 01282object.collisionPlane = planeSwV[arrayPos0].planeL1283object.drawOrder = planeSwV[arrayPos0].drawOrderL1284else1285object.collisionPlane = planeSwV[arrayPos0].planeL1286object.drawOrder = planeSwV[arrayPos0].drawOrderR1287end if1288end if1289end if1290next12911292foreach (TypeName[Eggman], arrayPos0, ACTIVE_ENTITIES)1293arrayPos1 = arrayPos01294arrayPos1--1295if ghzEggman[arrayPos1].invincibilityTimer == 01296switch object[arrayPos0].state1297case GHZEGGMAN_INITIALSWING1298case GHZEGGMAN_MOVELEFT1299case GHZEGGMAN_MOVERIGHT1300BoxCollisionTest(C_TOUCH, arrayPos0, -20, -16, 20, 16, object.entityPos, -22, -22, 22, 22)1301if checkResult == true1302ghzEggman[arrayPos0].health--1303if ghzEggman[arrayPos0].health == 01304// Sonic Team forgot to add the boss callbacks here LOL1305player.score += 10001306object[arrayPos0].animationTimer = 01307object[arrayPos0].animation = GHZEGGANI_DEFEATED1308object[arrayPos1].state = WRECKINGBALL_EXPLODE1309ghzEggman[arrayPos1].flameAnim = FLAME_INACTIVE1310arrayPos1--1311ResetObjectEntity(arrayPos1, TypeName[Explosion], 0, object[arrayPos1].xpos, object[arrayPos1].ypos)1312arrayPos1--1313ResetObjectEntity(arrayPos1, TypeName[Explosion], 0, object[arrayPos1].xpos, object[arrayPos1].ypos)1314arrayPos1--1315ResetObjectEntity(arrayPos1, TypeName[Explosion], 0, object[arrayPos1].xpos, object[arrayPos1].ypos)1316arrayPos1--1317ResetObjectEntity(arrayPos1, TypeName[Explosion], 0, object[arrayPos1].xpos, object[arrayPos1].ypos)1318arrayPos1--1319ResetObjectEntity(arrayPos1, TypeName[Explosion], 0, object[arrayPos1].xpos, object[arrayPos1].ypos)1320ghzEggman[arrayPos0].timer = 01321object[arrayPos0].state = GHZEGGMAN_EXPLODE1322else1323object[arrayPos0].animationTimer = 01324object[arrayPos0].animation = GHZEGGANI_HIT1325ghzEggman[arrayPos1].invincibilityTimer = 321326PlaySfx(SfxName[Boss Hit], false)1327end if1328end if1329break1330end switch1331end if1332next13331334foreach (TypeName[Wrecking Ball], arrayPos0, ACTIVE_ENTITIES)1335if object[arrayPos0].state == WRECKINGBALL_ACTIVE1336BoxCollisionTest(C_TOUCH, arrayPos0, -22, -22, 22, 22, object.entityPos, -22, -22, 22, 22)1337if checkResult == true1338temp0 = object[arrayPos0].xpos1339temp0 -= object.wreckingBallPos.x13401341temp1 = object[arrayPos0].ypos1342temp1 -= object.wreckingBallPos.y13431344if object.xvel == 01345object.xvel = temp01346object.speed = object.xvel1347else1348if object.xvel < 01349if temp0 > 01350temp2 = temp01351temp2 >>= 11352temp0 += temp21353object.xvel = temp01354object.speed = object.xvel1355end if1356else1357if temp0 < 01358temp2 = temp01359temp2 >>= 11360temp0 += temp21361object.xvel = temp01362object.speed = object.xvel1363end if1364end if1365end if13661367if object.yvel == 01368object.yvel = temp11369else1370if object.yvel < 01371if temp1 > 01372temp2 = temp11373temp2 >>= 11374temp1 += temp21375object.yvel = temp11376end if1377else1378if temp1 < 01379temp2 = temp11380temp2 >>= 11381temp1 += temp21382object.yvel = temp11383end if1384end if1385end if1386end if1387end if13881389// Store the Wrecking Ball's position for next frame1390object.wreckingBallPos.x = object[arrayPos0].xpos1391object.wreckingBallPos.y = object[arrayPos0].ypos1392next13931394foreach (TypeName[Checkered Ball], arrayPos0, ACTIVE_ENTITIES)1395// It can interact with other checkered balls, too!1396if arrayPos0 != object.entityPos // (Check to make sure this object isn't interacting with itself)1397temp0 = object.xpos1398temp0 -= object[arrayPos0].xpos1399Abs(temp0)1400temp0 >>= 171401if temp0 >= 241402temp0 = 231403end if1404GetTableValue(temp6, temp0, CheckeredBall_heightArray)14051406temp0 = temp61407temp0 >>= 11408temp6 += temp01409temp6 -= 221410temp7 = temp61411FlipSign(temp7)1412temp0 = object.xvel1413temp1 = object.yvel1414temp2 = object.speed1415BoxCollisionTest(C_SOLID, arrayPos0, -22, temp6, 22, temp7, object.entityPos, -22, -22, 22, 22)1416switch checkResult1417case COL_LEFT1418case COL_RIGHT1419CheckGreater(temp0, 0)1420temp3 = checkResult1421CheckLower(object.xpos, object[arrayPos0].xpos)1422temp3 &= checkResult1423CheckLower(temp0, 0)1424temp4 = checkResult1425CheckGreater(object.xpos, object[arrayPos0].xpos)1426temp4 &= checkResult1427temp3 |= temp41428if temp3 != false1429object.xvel = object[arrayPos0].xvel1430object.speed = object[arrayPos0].speed1431object[arrayPos0].xvel = temp01432object[arrayPos0].speed = temp21433end if1434break14351436case COL_TOP1437if object.xpos < object[arrayPos0].xpos1438object.speed -= 0xC001439object.xvel -= 0xC001440object[arrayPos0].speed += 0xC001441object[arrayPos0].xvel += 0xC001442object[arrayPos0].angleVel += 0xC001443else1444object.speed += 0xC001445object.xvel += 0xC001446object[arrayPos0].speed -= 0xC001447object[arrayPos0].xvel -= 0xC001448object[arrayPos0].angleVel -= 0xC001449end if1450// [Fallthrough]1451case COL_BOTTOM1452CheckGreater(temp1, 0)1453temp3 = checkResult1454CheckLower(object.ypos, object[arrayPos0].ypos)1455temp3 &= checkResult1456CheckLower(temp1, 0)1457temp4 = checkResult1458CheckGreater(object.ypos, object[arrayPos0].ypos)1459temp4 &= checkResult1460temp3 |= temp41461if temp3 != false1462object.yvel = object[arrayPos0].yvel1463object[arrayPos0].yvel = temp11464end if1465break14661467end switch14681469BoxCollisionTest(C_TOUCH, arrayPos0, -22, temp6, 22, temp7, object.entityPos, -22, -22, 22, 22)1470if checkResult == true1471if object.xpos < object[arrayPos0].xpos1472object.xpos -= 0x100001473else1474object.xpos += 0x100001475end if14761477if object.ypos < object[arrayPos0].ypos1478object.ypos -= 0x100001479else1480object.ypos += 0x100001481end if1482end if1483end if1484next14851486foreach (TypeName[Animal Prison], arrayPos0, ACTIVE_ENTITIES)1487switch object[arrayPos0].state1488case ANIMALPRISON_AWAITOPEN1489BoxCollisionTest(C_SOLID, arrayPos0, -32, -24, 32, 32, object.entityPos, -18, -22, 18, 22)1490BoxCollisionTest(C_SOLID, arrayPos0, -11, -48, 11, -24, object.entityPos, -18, -22, 18, 22)1491if checkResult == COL_TOP1492// Open the prison1493object[arrayPos0].state = ANIMALPRISON_OPENED1494stage.timeEnabled = false1495if Player_superState == SUPERSTATE_SUPER1496Player_superState = SUPERSTATE_UNTRANSFORM1497end if14981499player[0].controlMode = CONTROLMODE_NONE15001501// 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 fun1502end if1503break15041505case ANIMALPRISON_OPENED1506BoxCollisionTest(C_SOLID, arrayPos0, -32, -24, 32, 32, object.entityPos, -18, -22, 18, 22)1507BoxCollisionTest(C_SOLID, arrayPos0, -11, -40, 11, -24, object.entityPos, -18, -22, 18, 22)1508break15091510end switch1511next15121513CallFunction(CheckeredBall_PlayerInteraction)15141515temp0 = object.collisionOffset.x1516temp0 |= object.collisionOffset.y1517if temp0 != 01518foreach (GROUP_PLAYERS, currentPlayer, ACTIVE_ENTITIES)1519BoxCollisionTest(C_SOLID, object.entityPos, -22, -22, 22, 22, currentPlayer, C_BOX, C_BOX, C_BOX, C_BOX)1520if checkResult == COL_TOP1521player[currentPlayer].xpos += object.collisionOffset.x1522player[currentPlayer].ypos += object.collisionOffset.y1523end if1524next1525object.xpos += object.collisionOffset.x1526object.ypos += object.collisionOffset.y1527object.collisionOffset.x = 01528object.collisionOffset.y = 01529end if15301531if object.outOfBounds == true1532// 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 started15331534// Store the ball's current position and move it to its origin pos1535temp0 = object.xpos1536temp1 = object.ypos1537object.xpos = object.startPos.x1538object.ypos = object.startPos.y15391540// Is its starting position out of bounds too?1541if object.outOfBounds == true1542object.roundedPos.x = object.xpos1543object.roundedPos.y = object.ypos1544object.xvel = 01545object.yvel = 01546object.speed = 01547object.badnikBonus = 01548object.groundAngle = 01549object.activePlayers = 01550object.ballAngle = 01551object.angleVel = 01552object.playerControlled = 01553if object.priority != PRIORITY_XBOUNDS_DESTROY1554object.priority = PRIORITY_BOUNDS1555end if1556object.state = 01557else1558object.xpos = temp01559object.ypos = temp11560end if1561end if15621563object.roundedPos.x = object.xpos1564object.roundedPos.x &= 0xFFFF00001565object.roundedPos.y = object.ypos1566object.roundedPos.y &= 0xFFFF00001567end event156815691570event ObjectDraw1571object.rotation = object.ballAngle1572object.rotation >>= 1415731574temp0 = object.rotation1575temp0 += 81576temp0 >>= 41577temp0 &= 71578temp0++15791580DrawSprite(temp0)15811582// Draw the shine on top of the ball too1583object.inkEffect = INK_ADD1584object.alpha = 1601585DrawSpriteFX(0, FX_INK, object.xpos, object.ypos)1586end event158715881589event ObjectStartup1590LoadSpriteSheet("GHZ/Objects2.gif")15911592// Ball frames1593SpriteFrame(-24, -24, 48, 48, 1, 77)1594SpriteFrame(-24, -24, 48, 48, 50, 77)1595SpriteFrame(-24, -24, 48, 48, 148, 126)1596SpriteFrame(-24, -24, 48, 48, 99, 126)1597SpriteFrame(-24, -24, 48, 48, 50, 126)1598SpriteFrame(-24, -24, 48, 48, 1, 126)1599SpriteFrame(-24, -24, 48, 48, 197, 77)1600SpriteFrame(-24, -24, 48, 48, 148, 77)1601SpriteFrame(-24, -24, 48, 48, 99, 77)16021603// Load the animation file1604// - Note that, even if loaded, the object is never drawn with this animation1605// - A script-based animation and drawing system is used, instead16061607// A note from RDC: this isn't here for sprites, it's here to provide the inner/outer boxes for ProcessObjectMovement()1608// since that requires the animation file to work with what's been setup here16091610// A note from Lave: this isn't here for hitboxes, it seems actually serve no purpose at all instead1611// This didn't even exist in initial S1 releases - it was only added after S2 (and its similar OOZ ball) were released1612// Hitboxes are set via script, instead16131614// TODO: Remove/"steamline" the above two comment note sections, I thought it would be funny but nah it hardly works at all :(1615// Anyway, that's enough notes, I hope you're ready for your quiz tomorrow16161617LoadAnimation("WreckingBall.ani")16181619// Cycle through all Checkered Ball objects and init their values1620// Note that this never actually does anything, as no Checkered Ball objects exist in S1's levels1621foreach (TypeName[Checkered Ball], arrayPos0, ALL_ENTITIES)1622object[arrayPos0].gravity = GRAVITY_AIR16231624object[arrayPos0].startPos.x = object.xpos1625object[arrayPos0].startPos.y = object.ypos1626next16271628SetTableValue(TypeName[Checkered Ball], DebugMode_ObjCount, DebugMode_TypesTable)1629SetTableValue(CheckeredBall_DebugDraw, DebugMode_ObjCount, DebugMode_DrawTable)1630SetTableValue(CheckeredBall_DebugSpawn, DebugMode_ObjCount, DebugMode_SpawnTable)1631DebugMode_ObjCount++1632end event163316341635// ========================1636// Editor Events1637// ========================16381639event RSDKDraw1640DrawSprite(1)1641object.inkEffect = INK_ADD1642object.alpha = 1601643DrawSpriteFX(0, FX_INK, object.xpos, object.ypos)1644end event164516461647event RSDKLoad1648LoadSpriteSheet("GHZ/Objects2.gif")1649SpriteFrame(-24, -24, 48, 48, 1, 77)1650SpriteFrame(-24, -24, 48, 48, 50, 77)16511652SetVariableAlias(ALIAS_VAR_PROPVAL, "unused")1653end event165416551656