Path: blob/master/Sonic 2/Scripts/CPZ/Water.txt
1480 views
// ----------------------------------1// RSDK Project: Sonic 22// Script Description: Water Object3// Script Author: Christian Whitehead/Simon Thomley4// Unpacked by Rubberduckycooly's script unpacker5// ----------------------------------67// Any water objects in the scene should be followed by THREE blank objects, these manage player stuff89// ========================10// Aliases11// ========================1213private alias object.value1 : object.constBubbleTimer14private alias object.value2 : object.randBubbleTimer15private alias object.value3 : object.proccessActEffects16private alias object.value8 : object.nextTrackID // stores the track that should play after the drowning one stops1718private alias 0 : CPZSETUP_WATERINITIAL19private alias 1 : CPZSETUP_WATERMOVED2021// AirBubble Aliases22private alias object.value1 : airBubble.originPos.x23private alias object.value2 : airBubble.targetPlayer2425// CountdownBubble Aliases26private alias object.value1 : countdownBubble.drawPos.x27private alias object.value2 : countdownBubble.drawPos.y2829// Player Aliases30private alias object.type : player.type31private alias object.state : player.state32private alias object.xpos : player.xpos33private alias object.ypos : player.ypos34private alias object.xvel : player.xvel35private alias object.yvel : player.yvel36private alias object.speed : player.speed37private alias object.direction : player.direction38private alias object.gravity : player.gravity39private alias object.animation : player.animation40private alias object.interaction : player.interaction41private alias object.tileCollisions : player.tileCollisions42private alias object.value1 : player.timer43private alias object.value3 : player.drownTimer44private alias object.value4 : player.drownLevel45private alias object.value7 : player.invincibleTimer46private alias object.value18 : player.sortedDrawOrder47private alias object.value20 : player.topSpeed48private alias object.value21 : player.acceleration49private alias object.value22 : player.deceleration50private alias object.value23 : player.airAcceleration51private alias object.value24 : player.airDeceleration52private alias object.value25 : player.gravityStrength53private alias object.value27 : player.jumpStrength54private alias object.value28 : player.jumpCap55private alias object.value37 : player.shield5657private alias 1 : SUPERSTATE_SUPER5859// Shields60private alias 0 : SHIELD_NONE61private alias 2 : SHIELD_BUBBLE62private alias 3 : SHIELD_FIRE63private alias 4 : SHIELD_LIGHTNING6465// Tracks66private alias 0 : TRACK_STAGE67private alias 2 : TRACK_INVINCIBLE68private alias 6 : TRACK_DROWNING697071// ========================72// Function Declarations73// ========================7475reserve function Water_ProcessCPZAct176reserve function Water_ProcessCPZAct277reserve function Water_SpawnSmallAirBubble78reserve function Water_SpawnCountDownBubble79reserve function Water_ResetDrownMusic808182// ========================83// Static Values84// ========================8586private value Water_waterSlotID = 087private value Water_activateFlag = 0888990// ========================91// Tables92// ========================9394private table Water_processActTable[3]959697// ========================98// Function Definitions99// ========================100101private function Water_ProcessCPZAct1102// Called to update water position, when in Act 1103104// Preconditions:105// - temp0 is the player's x position, 1:1106// - temp1 is the player's y position, 1:1107108// With that all out of the way though, Water doesn't do anything in Act 1, so no code!109end function110111112private function Water_ProcessCPZAct2113// Called to update water position, when in Act 2114115// Just like above...116// Preconditions:117// - temp0 is the player's x position, 1:1118// - temp1 is the player's y position, 1:1119120// Only check this all if we haven't touched the water yet121if object.state == CPZSETUP_WATERINITIAL122stage.newWaterLevel = 0x7100000123124// 7808 is around where the vertical block climbing section starts (you know what i'm talking about)125if temp0 >= 7808126stage.newWaterLevel = 0x5100000127128// Mark the flag, now that we've moved the Water129object.state++130end if131end if132end function133134135private function Water_SpawnSmallAirBubble136if object[+currentPlayer].constBubbleTimer > 0137object[+currentPlayer].constBubbleTimer--138139if object[+currentPlayer].randBubbleTimer > 0140object[+currentPlayer].randBubbleTimer--141else142CreateTempObject(TypeName[Air Bubble], 2, player[currentPlayer].xpos, player[currentPlayer].ypos)143object[tempObjectPos].drawOrder = 4144object[tempObjectPos].yvel = -0x8800145airBubble[tempObjectPos].targetPlayer = currentPlayer146if player[currentPlayer].direction == FACING_RIGHT147object[tempObjectPos].xpos += 0x60000148else149object[tempObjectPos].xpos -= 0x60000150object[tempObjectPos].angle = 256151end if152airBubble[tempObjectPos].originPos.x = object[tempObjectPos].xpos153object[+currentPlayer].randBubbleTimer = 512154end if155else156Rand(temp0, 3)157if temp0 == 1158Rand(object[+currentPlayer].randBubbleTimer, 16)159object[+currentPlayer].randBubbleTimer += 8160else161object[+currentPlayer].randBubbleTimer = 512162end if163164object[+currentPlayer].constBubbleTimer = 60165CreateTempObject(TypeName[Air Bubble], 2, player[currentPlayer].xpos, player[currentPlayer].ypos)166object[tempObjectPos].drawOrder = 4167object[tempObjectPos].yvel = -0x8800168airBubble[tempObjectPos].targetPlayer = currentPlayer169if player[currentPlayer].direction == FACING_RIGHT170object[tempObjectPos].xpos += 0x60000171else172object[tempObjectPos].xpos -= 0x60000173object[tempObjectPos].angle = 256174end if175176airBubble[tempObjectPos].originPos.x = object[tempObjectPos].xpos177end if178end function179180181private function Water_SpawnCountDownBubble182CreateTempObject(TypeName[Countdown Bubble], temp0, player[currentPlayer].xpos, player[currentPlayer].ypos)183object[tempObjectPos].drawOrder = 5184object[tempObjectPos].yvel = -0x8800185countdownBubble[tempObjectPos].drawPos.y = currentPlayer // this is odd... this is drawPos.y, not "targetPlayer", likely a leftover from AirBubble spawning186if player[currentPlayer].direction == FACING_RIGHT187object[tempObjectPos].xpos += 0x60000188else189object[tempObjectPos].xpos -= 0x60000190object[tempObjectPos].angle = 256191end if192193countdownBubble[tempObjectPos].drawPos.x = object[tempObjectPos].xpos194end function195196197private function Water_ResetDrownMusic198if currentPlayer == 0199arrayPos0 = Water_waterSlotID200arrayPos0 += currentPlayer201if player[currentPlayer].type != TypeName[Death Event]202if music.currentTrack == TRACK_DROWNING203if object[arrayPos0].nextTrackID == TRACK_INVINCIBLE204arrayPos1 = currentPlayer205arrayPos1 += playerCount206if object[arrayPos1].type != TypeName[Invincibility]207if Player_superState != SUPERSTATE_SUPER208object[arrayPos0].nextTrackID = TRACK_STAGE209end if210end if211end if212213PlayMusic(object[arrayPos0].nextTrackID)214end if215end if216end if217end function218219220// ========================221// Events222// ========================223224event ObjectUpdate225temp0 = player[0].xpos226temp0 >>= 16227temp1 = player[0].ypos228temp1 >>= 16229230arrayPos0 = object.entityPos231CallFunction(object.proccessActEffects)232233if object.ypos < stage.newWaterLevel234object.ypos += 0x10000235end if236if object.ypos > stage.newWaterLevel237object.ypos -= 0x10000238end if239240temp0 = oscillation241temp0 <<= 1242Sin(stage.waterLevel, temp0)243stage.waterLevel <<= 10244stage.waterLevel += object.ypos245temp7 = stage.waterLevel246stage.waterLevel >>= 16247248currentPlayer = 0249while currentPlayer < playerCount250if player[currentPlayer].gravityStrength == 0x3800251CheckNotEqual(player[currentPlayer].type, TypeName[Debug Mode])252temp0 = checkResult253CheckNotEqual(player[currentPlayer].state, Player_State_Death)254temp0 &= checkResult255CheckNotEqual(player[currentPlayer].state, Player_State_Static)256temp0 &= checkResult257CheckGreater(player[currentPlayer].ypos, temp7)258temp0 &= checkResult259if temp0 == true260if player[currentPlayer].yvel > 0261player[currentPlayer].yvel >>= 2262end if263264if object.ypos < stage.newWaterLevel265player[currentPlayer].yvel += 0x10000266end if267268if player[currentPlayer].state == Player_State_Fly269StopSfx(SfxName[Flying])270StopSfx(SfxName[Jump])271end if272273player[currentPlayer].xvel >>= 1274player[currentPlayer].speed >>= 1275276CallFunction(Player_UpdatePhysicsState)277if currentPlayer == 0278CPZSetup_enteredWater = true279end if280281if player[currentPlayer].yvel != 0282CreateTempObject(TypeName[Water Splash], 0, player[currentPlayer].xpos, temp7)283object[tempObjectPos].drawOrder = 4284player[currentPlayer].sortedDrawOrder = 4285PlaySfx(SfxName[Water Splash], false)286end if287288object[+currentPlayer].constBubbleTimer = 52289player[currentPlayer].drownTimer = 0290end if291else292if player[currentPlayer].invincibleTimer == 0293if player[currentPlayer].shield == SHIELD_FIRE294temp2 = 0295while temp2 < 8296Rand(temp0, 32)297Rand(temp1, 32)298temp0 -= 16299temp0 <<= 16300temp0 += player[currentPlayer].xpos301temp1 -= 16302temp1 <<= 16303temp1 += player[currentPlayer].ypos304CreateTempObject(TypeName[Dust Puff], 0, temp0, temp1)305object[tempObjectPos].drawOrder = player[currentPlayer].sortedDrawOrder306object[tempObjectPos].drawOrder++307object[tempObjectPos].xvel = player[currentPlayer].xvel308object[tempObjectPos].yvel = player[currentPlayer].yvel309temp2++310loop311312player[currentPlayer].shield = SHIELD_NONE313arrayPos0 = currentPlayer314arrayPos0 += playerCount315CallFunction(Player_ApplyShield)316end if317318// Player hit the water with a lightning shield - take their shield and electrocute the water319if player[currentPlayer].shield == SHIELD_LIGHTNING320player[currentPlayer].shield = SHIELD_NONE321arrayPos0 = currentPlayer322arrayPos0 += playerCount323CallFunction(Player_ApplyShield)324Water_flashTimer = 4325end if326end if327328if player[currentPlayer].shield != SHIELD_BUBBLE329if player[currentPlayer].drownTimer == 0330player[currentPlayer].drownLevel = 0331CallFunction(Water_ResetDrownMusic)332end if333334switch player[currentPlayer].drownLevel335case 0336CallFunction(Water_SpawnSmallAirBubble)337player[currentPlayer].drownTimer++338if player[currentPlayer].drownTimer == 360339if currentPlayer == 0340PlaySfx(SfxName[Drown Alert], false)341end if342player[currentPlayer].drownLevel++343end if344break345346case 1347CallFunction(Water_SpawnSmallAirBubble)348player[currentPlayer].drownTimer++349if player[currentPlayer].drownTimer == 660350if currentPlayer == 0351PlaySfx(SfxName[Drown Alert], false)352end if353player[currentPlayer].drownLevel++354end if355break356357case 2358CallFunction(Water_SpawnSmallAirBubble)359player[currentPlayer].drownTimer++360if player[currentPlayer].drownTimer == 960361if currentPlayer == 0362PlaySfx(SfxName[Drown Alert], false)363end if364player[currentPlayer].drownLevel++365end if366break367368case 3369CallFunction(Water_SpawnSmallAirBubble)370player[currentPlayer].drownTimer++371if player[currentPlayer].drownTimer == 1080372if currentPlayer == 0373object.nextTrackID = music.currentTrack374PlayMusic(TRACK_DROWNING)375end if376377temp0 = 0378CallFunction(Water_SpawnCountDownBubble)379player[currentPlayer].drownLevel++380end if381break382383case 4384CallFunction(Water_SpawnSmallAirBubble)385player[currentPlayer].drownTimer++386if player[currentPlayer].drownTimer == 1200387temp0 = 1388CallFunction(Water_SpawnCountDownBubble)389player[currentPlayer].drownLevel++390end if391break392393case 5394CallFunction(Water_SpawnSmallAirBubble)395player[currentPlayer].drownTimer++396if player[currentPlayer].drownTimer == 1320397temp0 = 2398CallFunction(Water_SpawnCountDownBubble)399player[currentPlayer].drownLevel++400end if401break402403case 6404CallFunction(Water_SpawnSmallAirBubble)405player[currentPlayer].drownTimer++406if player[currentPlayer].drownTimer == 1440407temp0 = 3408CallFunction(Water_SpawnCountDownBubble)409player[currentPlayer].drownLevel++410end if411break412413case 7414CallFunction(Water_SpawnSmallAirBubble)415player[currentPlayer].drownTimer++416if player[currentPlayer].drownTimer == 1560417temp0 = 4418CallFunction(Water_SpawnCountDownBubble)419player[currentPlayer].drownLevel++420end if421break422423case 8424CallFunction(Water_SpawnSmallAirBubble)425player[currentPlayer].drownTimer++426if player[currentPlayer].drownTimer == 1680427temp0 = 5428CallFunction(Water_SpawnCountDownBubble)429player[currentPlayer].drownLevel++430end if431break432433case 9434CallFunction(Water_SpawnSmallAirBubble)435player[currentPlayer].drownTimer++436if player[currentPlayer].drownTimer == 1800437if player[currentPlayer].state != Player_State_Death438if currentPlayer == 0439stage.timeEnabled = false440camera[0].enabled = false441end if442player[currentPlayer].state = Player_State_Drown443player[currentPlayer].animation = ANI_DROWNING444player[currentPlayer].speed = 0445player[currentPlayer].xvel = 0446player[currentPlayer].yvel = 0447player[currentPlayer].tileCollisions = false448player[currentPlayer].interaction = false449player[currentPlayer].sortedDrawOrder = 5450object[+currentPlayer].constBubbleTimer = 2451PlaySfx(SfxName[Drowning], false)452player[currentPlayer].drownLevel++453end if454end if455break456457case 10458player[currentPlayer].drownTimer++459if player[currentPlayer].drownTimer == 1860460player[currentPlayer].drownLevel++461end if462463if object[+currentPlayer].constBubbleTimer > 0464object[+currentPlayer].constBubbleTimer--465if object[+currentPlayer].randBubbleTimer > 0466object[+currentPlayer].randBubbleTimer--467else468Rand(temp1, 2)469temp1 += 2470CreateTempObject(TypeName[Air Bubble], temp1, player[currentPlayer].xpos, player[currentPlayer].ypos)471object[tempObjectPos].drawOrder = 5472object[tempObjectPos].yvel = -0x8800473object[tempObjectPos].ypos -= 0x60000474airBubble[tempObjectPos].targetPlayer = currentPlayer475Rand(object[tempObjectPos].angle, 256)476airBubble[tempObjectPos].originPos.x = object[tempObjectPos].xpos477object[+currentPlayer].randBubbleTimer = 512478end if479else480Rand(temp0, 5)481if temp0 == 1482object[+currentPlayer].randBubbleTimer = 2483else484object[+currentPlayer].randBubbleTimer = 512485end if486object[+currentPlayer].constBubbleTimer = 6487488Rand(temp1, 2)489temp1 += 2490CreateTempObject(TypeName[Air Bubble], temp1, player[currentPlayer].xpos, player[currentPlayer].ypos)491object[tempObjectPos].drawOrder = 5492object[tempObjectPos].yvel = -0x8800493object[tempObjectPos].ypos -= 0x60000494airBubble[tempObjectPos].targetPlayer = currentPlayer495Rand(object[tempObjectPos].angle, 0x100)496airBubble[tempObjectPos].originPos.x = object[tempObjectPos].xpos497end if498break499end switch500end if501502CheckEqual(player[currentPlayer].type, TypeName[Debug Mode])503temp0 = checkResult504CheckLower(player[currentPlayer].ypos, temp7)505temp0 |= checkResult506if temp0 == true507if player[currentPlayer].state != Player_State_Death508player[currentPlayer].yvel <<= 1509if player[currentPlayer].yvel < -0x100000510player[currentPlayer].yvel = -0x100000511end if512513#platform: USE_STANDALONE514// Fixes a bug where jumping at the surface of the water will set your velocity too high515// Also yep this fix isn't in Origins, this is taken from the Sega Forever releases of the game516if player[currentPlayer].animation == ANI_JUMPING517if player[currentPlayer].timer > 0518if player[currentPlayer].yvel < -0x68000519player[currentPlayer].yvel = -0x68000520end if521end if522end if523#endplatform524525if player[currentPlayer].state == Player_State_Fly526if player[currentPlayer].timer < 480527PlaySfx(SfxName[Flying], true)528else529PlaySfx(SfxName[Jump], true)530end if531end if532533534CallFunction(Player_UpdatePhysicsState)535if player[currentPlayer].yvel != 0536temp0 = object.ypos537temp0 -= player[currentPlayer].ypos538if temp0 < 0xF00000539CreateTempObject(TypeName[Water Splash], 0, player[currentPlayer].xpos, temp7)540object[tempObjectPos].drawOrder = 4541player[currentPlayer].sortedDrawOrder = 4542PlaySfx(SfxName[Water Splash], false)543end if544end if545546player[currentPlayer].drownTimer = 0547CallFunction(Water_ResetDrownMusic)548end if549end if550end if551552currentPlayer++553loop554555object.animationTimer++556object.animationTimer &= 31557object.frame = object.animationTimer558object.frame >>= 3559end event560561562event ObjectDraw563temp0 = screen.xoffset564Sin(temp1, oscillation)565temp1 >>= 5566temp0 += temp1567temp0 &= 63568FlipSign(temp0)569570temp1 = stage.waterLevel571temp1 -= screen.yoffset572DrawSpriteScreenFX(object.frame, FX_INK, temp0, temp1)573574temp0 += 256575DrawSpriteScreenFX(object.frame, FX_INK, temp0, temp1)576end event577578579event ObjectStartup580SetTableValue(Water_ProcessCPZAct1, 1, Water_processActTable)581SetTableValue(Water_ProcessCPZAct2, 2, Water_processActTable)582583if options.vsMode == true584foreach (TypeName[Water], arrayPos0, ALL_ENTITIES)585object[arrayPos0].type = TypeName[Blank Object]586next587end if588589foreach (TypeName[Water], arrayPos0, ALL_ENTITIES)590object[arrayPos0].priority = PRIORITY_ACTIVE591object[arrayPos0].drawOrder = 5592object[arrayPos0].inkEffect = INK_ALPHA593object[arrayPos0].alpha = 0xA0594595// Huh? In-game credits?596// This is just a leftover from the S1 LZ Water script, where Water would be specially set up for the credits demo597// In this game there's no such thing though, this never really hits598if credits.screen == 0599stage.newWaterLevel = object[arrayPos0].ypos600else601stage.waterState = 1602stage.newWaterLevel = 0x4C80000603temp0 = player[0].xpos604temp0 >>= 16605temp1 = player[0].ypos606temp1 >>= 16607end if608Water_waterSlotID = arrayPos0609GetTableValue(object[arrayPos0].proccessActEffects, stage.actNum, Water_processActTable)610CallFunction(object[arrayPos0].proccessActEffects)611stage.waterLevel = stage.newWaterLevel612stage.waterLevel >>= 16613object[arrayPos0].ypos = stage.newWaterLevel614615if starPostID >= 32616stage.waterState = recWaterState617stage.waterLevel = recWaterLevel618stage.newWaterLevel = recWaterLevel619stage.newWaterLevel <<= 16620arrayPos0 = Water_waterSlotID621object[arrayPos0].ypos = stage.newWaterLevel622else623if credits.screen == 0624stage.waterState = 0625end if626end if627next628629Water_activateFlag = false630631foreach (GROUP_PLAYERS, currentPlayer, ALL_ENTITIES)632player[currentPlayer].drownTimer = 0633if player[currentPlayer].ypos > stage.newWaterLevel634player[currentPlayer].yvel >>= 2635player[currentPlayer].xvel >>= 1636player[currentPlayer].speed >>= 1637player[currentPlayer].topSpeed >>= 1638player[currentPlayer].acceleration >>= 1639player[currentPlayer].deceleration >>= 1640player[currentPlayer].airAcceleration >>= 1641player[currentPlayer].airDeceleration >>= 1642player[currentPlayer].gravityStrength = 0x1000643if stage.playerListPos == PLAYER_KNUCKLES_A644player[currentPlayer].jumpStrength = 0x30000645else646player[currentPlayer].jumpStrength = 0x38000647end if648player[currentPlayer].jumpCap = -0x20000649arrayPos0 = Water_waterSlotID650arrayPos0 += currentPlayer651object[arrayPos0].constBubbleTimer = 52652end if653next654655LoadSpriteSheet("CPZ/Objects2.gif")656SpriteFrame(0, -8, 256, 16, 0, 0)657SpriteFrame(0, -8, 256, 16, 0, 16)658SpriteFrame(0, -8, 256, 16, 0, 32)659SpriteFrame(0, -8, 256, 16, 0, 48)660661BrokenMonitor_ResetDrownMusic = Water_ResetDrownMusic662end event663664665// ========================666// Editor Events667// ========================668669event RSDKDraw670DrawSprite(0)671end event672673674event RSDKLoad675LoadSpriteSheet("CPZ/Objects2.gif")676SpriteFrame(0, -8, 256, 16, 0, 0)677678SetVariableAlias(ALIAS_VAR_PROPVAL, "unused")679end event680681682