Path: blob/master/Sonic 2/Scripts/HTZ/Eggman.txt
1480 views
// ----------------------------------1// RSDK Project: Sonic 22// Script Description: Eggman Object3// Script Author: Christian Whitehead/Simon Thomley4// Unpacked by Rubberduckycooly's script unpacker5// ----------------------------------67// Using HTZEggman as a prefix here because there's like 12 "Eggman" objects in the game so its less confusing this way89// ========================10// Aliases11// ========================1213// value0 is, suprisingly, unused14private alias object.value1 : object.originPos.y15private alias object.value2 : object.oscillationAngle16// value3 is unused too17private alias object.value4 : object.timer18private alias object.value5 : object.flamethrowerFrame19private alias object.value6 : object.flamethrowerTimer2021private alias object.value7 : object.health22private alias object.value8 : object.invincibilityTimer23private alias object.value9 : object.exploding2425// Position values used for boss behaviours, see the init state26private alias object.value10 : object.pits.halfpoint2728private alias object.value11 : object.pitL.x29private alias object.value13 : object.pitL.y3031private alias object.value12 : object.pitR.x32private alias object.value14 : object.pitR.y3334private alias object.value15 : object.cannonFrame35private alias object.value16 : object.nonStopBopCount3637// States38private alias 0 : HTZEGGMAN_AWAITPLAYER39private alias 1 : HTZEGGMAN_RISE40private alias 2 : HTZEGGMAN_HOVER41private alias 3 : HTZEGGMAN_SINK42private alias 4 : HTZEGGMAN_EXPLODING43private alias 5 : HTZEGGMAN_DESTROYED4445// Animations46private alias 1 : HTZEGGANI_IDLE47private alias 2 : HTZEGGANI_LAUGH48private alias 3 : HTZEGGANI_HIT49private alias 4 : HTZEGGANI_DEFEATED50private alias 5 : HTZEGGANI_TOASTED5152// Music Events53private alias 26 : SLOT_MUSICEVENT_BOSS5455private alias 0 : MUSICEVENT_FADETOBOSS56private alias 1 : MUSICEVENT_FADETOSTAGE5758// Player Aliases59private alias object.xpos : player.xpos60private alias object.xvel : player.xvel61private alias object.speed : player.speed62private alias object.gravity : player.gravity63private alias object.animation : player.animation64private alias object.collisionRight : player.collisionRight6566private alias object.value40 : player.hitboxLeft67private alias object.value38 : player.hitboxTop68private alias object.value41 : player.hitboxRight69private alias object.value39 : player.hitboxBottom7071// Achievement Aliases72private alias 5 : ACHIEVEMENT_BOBNONSTOP737475// ========================76// Function Declarations77// ========================7879reserve function HTZEggman_Oscillate808182// ========================83// Tables84// ========================8586private table HTZEggman_FlameThrowerHitboxes87-32, -40, -48, -64, -80, -96, -112, -120, -119, -12088end table899091// ========================92// Function Definitions93// ========================9495private function HTZEggman_Oscillate96// Used when hovering in order to make Robotnik bounce a bit9798object.ypos = object.originPos.y99Sin256(temp0, object.oscillationAngle)100temp0 <<= 9101object.ypos += temp0102object.oscillationAngle += 4103object.oscillationAngle &= 255104end function105106107// ========================108// Events109// ========================110111event ObjectUpdate112switch object.state113case HTZEGGMAN_AWAITPLAYER114temp0 = object.ixpos115temp0 -= 352116stage.newXBoundary1 = temp0117118temp0 = object.ixpos119temp0 += 96120stage.newXBoundary2 = temp0121122temp0 = object.xpos123temp0 -= 0xC00000124if player[0].xpos >= temp0 // Only activate when the player's past the trigger point125object.animation = HTZEGGANI_IDLE126ResetObjectEntity(SLOT_MUSICEVENT_BOSS, TypeName[Music Event], MUSICEVENT_FADETOBOSS, 0, 0)127object[SLOT_MUSICEVENT_BOSS].priority = PRIORITY_ACTIVE128object.originPos.y = object.ypos129130// Init arena values131132// X Position of right lava pit133object.pitR.x = object.xpos134135// X Position of left lava pit136object.pitL.x = object.pitR.x137object.pitL.x -= 0x1000000138139// Halfpoint between the two140object.pits.halfpoint = object.pitL.x141object.pits.halfpoint += 0x800000142143// Y Position to start from when in left lava pit144object.pitL.y = object.ypos145object.pitL.y += 0x260000146147// Y Position of where to start from when in right lava pit148object.pitR.y = object.ypos149object.pitR.y += 0xF0000150151object.timer = 144152object.oscillationAngle = 128153object.cannonFrame = 7154155#platform: USE_STANDALONE156object.health = 8157#endplatform158#platform: USE_ORIGINS159if game.bossOneLife == false160object.health = 8161else162object.health = 1163end if164#endplatform165166object.priority = PRIORITY_ACTIVE167object.state++168end if169break170171case HTZEGGMAN_RISE172// Rising from a lava pit173object.originPos.y -= 0xE000174object.ypos -= 0xE000175176object.timer--177if object.timer == 0178object.state = HTZEGGMAN_HOVER179end if180break181182case HTZEGGMAN_HOVER183// Hovering above a lava pit, firing the flamethrower184CallFunction(HTZEggman_Oscillate)185if object.oscillationAngle == 64186if object.timer == 0187object.timer++188else189object.state = HTZEGGMAN_SINK190end if191end if192193if object.timer == 1194object.flamethrowerTimer++195switch object.flamethrowerTimer196case 1197PlaySfx(SfxName[Fire Dash], false)198object.flamethrowerFrame = 9199break200201case 3202object.flamethrowerFrame = 10203break204205case 6206object.flamethrowerFrame = 11207break208209case 9210object.flamethrowerFrame = 12211break212213case 13214object.flamethrowerFrame = 13215break216217case 17218object.flamethrowerFrame = 14219break220221case 22222object.flamethrowerFrame = 15223break224225case 25226CreateTempObject(TypeName[Eggman Fireball1], 0, object.xpos, object.ypos)227if object.direction == FLIP_NONE228object[tempObjectPos].xpos -= 0x680000229object[tempObjectPos].xvel = -0x40000230else231object[tempObjectPos].xpos += 0x680000232object[tempObjectPos].xvel = 0x40000233end if234object[tempObjectPos].ypos -= 0x1D0000235object[tempObjectPos].direction = object.direction236break237238case 27239object.flamethrowerFrame = 16240break241242case 33243object.flamethrowerFrame = 17244break245246case 39247object.flamethrowerFrame = 18248break249250case 46251object.timer = 2252object.flamethrowerTimer = 0253break254end switch255end if256break257258case HTZEGGMAN_SINK259// Sinking back into the lava, not to be confused with his defeat sink state260object.originPos.y += 0xE000261object.ypos += 0xE000262object.timer++263264if object.xpos < object.pits.halfpoint265temp0 = 36266temp1 = -0x54000267else268temp0 = 84269temp1 = -0x64000270end if271272if object.timer == temp0273PlaySfx(SfxName[Small Fireball], false)274CreateTempObject(TypeName[Eggman Fireball2], 0, object.xpos, object.ypos)275object[tempObjectPos].xvel = -0x1C000276object[tempObjectPos].yvel = temp1277CreateTempObject(TypeName[Eggman Fireball2], 0, object.xpos, object.ypos)278object[tempObjectPos].xvel = 0x1C000279object[tempObjectPos].yvel = temp1280end if281282if object.timer == 160283if player[0].xpos < object.pits.halfpoint284object.xpos = object.pitL.x285object.ypos = object.pitL.y286object.originPos.y = object.pitL.y287else288object.xpos = object.pitR.x289object.ypos = object.pitR.y290object.originPos.y = object.pitR.y291end if292293if player[0].xpos < object.xpos294object.direction = FLIP_NONE295else296object.direction = FLIP_X297end if298299object.oscillationAngle = 128300object.state = HTZEGGMAN_RISE301end if302break303304case HTZEGGMAN_EXPLODING305object.timer++306if object.timer == 120307// Turn the cannon frame into the broken variant308object.cannonFrame = 8309end if310311if object.timer == 180312object.timer = 0313object.animation = HTZEGGANI_TOASTED314object.exploding = false315object.state++316ResetObjectEntity(SLOT_MUSICEVENT_BOSS, TypeName[Music Event], MUSICEVENT_FADETOSTAGE, 0, 0)317object[SLOT_MUSICEVENT_BOSS].priority = PRIORITY_ACTIVE318319// Restore normal stage XBounds320temp0 = tileLayer[0].xsize321temp0 <<= 7322stage.newXBoundary2 = temp0323end if324break325326case HTZEGGMAN_DESTROYED327// Taking one final dip in the lava before disappearing one final time, object deletion gets done here328object.originPos.y += 0x10000329CallFunction(HTZEggman_Oscillate)330if object.outOfBounds == true331object.type = TypeName[Blank Object]332object.priority = PRIORITY_BOUNDS333end if334break335336end switch337338if player[0].gravity == GRAVITY_GROUND339// If the player's touched the ground, they are have stopped Non-Stop Bopping340object.nonStopBopCount = 0341end if342343if object.health != 0344if object.invincibilityTimer > 0345object.invincibilityTimer--346GetBit(temp0, object.invincibilityTimer, 0)347if temp0 == true348SetPaletteEntry(0, 192, 0xE0E0E0)349else350SetPaletteEntry(0, 192, 0x000000)351end if352end if353354foreach (GROUP_PLAYERS, currentPlayer, ACTIVE_ENTITIES)355if object.invincibilityTimer == 0356CheckEqual(player[currentPlayer].animation, ANI_HURT)357temp0 = checkResult358CheckEqual(player[currentPlayer].animation, ANI_DYING)359temp0 |= checkResult360CheckEqual(player[currentPlayer].animation, ANI_DROWNING)361temp0 |= checkResult362if temp0 != false363if object.animation != HTZEGGANI_LAUGH364object.animation = HTZEGGANI_LAUGH365object.animationTimer = 0366end if367end if368369BoxCollisionTest(C_TOUCH, object.entityPos, -24, -24, 24, 22, currentPlayer, player[currentPlayer].hitboxLeft, player[currentPlayer].hitboxTop, player[currentPlayer].hitboxRight, player[currentPlayer].hitboxBottom)370if checkResult == true371CallFunction(Player_CheckHit)372if checkResult == true373object.health--374if object.health == 0375#platform: USE_ORIGINS376CallNativeFunction2(NotifyCallback, NOTIFY_KILL_BOSS, 0)377CallNativeFunction2(NotifyCallback, NOTIFY_BOSS_END, 1)378#endplatform379380player.score += 1000381object.animation = HTZEGGANI_DEFEATED382object.animationTimer = 0383object.exploding = true384object.originPos.y = object.ypos385object.state = HTZEGGMAN_EXPLODING386object.flamethrowerTimer = 0387object.flamethrowerFrame = 0388389if object.nonStopBopCount >= 7390if stage.debugMode == false391// Grant the "Bob Non-stop" Achievement392CallNativeFunction2(SetAchievement, ACHIEVEMENT_BOBNONSTOP, 100)393end if394end if395else396object.animation = HTZEGGANI_HIT397object.animationTimer = 0398object.invincibilityTimer = 32399PlaySfx(SfxName[Boss Hit], false)400401if currentPlayer == 0402if player[0].gravity == GRAVITY_AIR403object.nonStopBopCount++404end if405end if406end if407end if408else409if object.flamethrowerTimer != 0410temp1 = object.flamethrowerFrame411temp1 -= 8412if temp1 <= 7413GetTableValue(temp0, temp1, HTZEggman_FlameThrowerHitboxes)414if object.direction == FLIP_NONE415BoxCollisionTest(C_TOUCH, object.entityPos, temp0, -32, -24, -29, currentPlayer, C_BOX, C_BOX, C_BOX, C_BOX)416else417FlipSign(temp0)418BoxCollisionTest(C_TOUCH, object.entityPos, 24, -32, temp0, -29, currentPlayer, C_BOX, C_BOX, C_BOX, C_BOX)419end if420421if checkResult == true422CallFunction(Player_FireHit)423end if424end if425end if426end if427end if428next429end if430431if object.state != HTZEGGMAN_DESTROYED432// Enforce the arena right wall on players433foreach (GROUP_PLAYERS, currentPlayer, ACTIVE_ENTITIES)434temp0 = player[currentPlayer].collisionRight435temp0 <<= 16436temp0 += player[currentPlayer].xpos437temp1 = stage.curXBoundary2438temp1 <<= 16439if temp0 > temp1440player[currentPlayer].xvel = 0441player[currentPlayer].speed = 0442player[currentPlayer].xpos = temp1443temp0 = player[currentPlayer].collisionRight444temp0 <<= 16445player[currentPlayer].xpos -= temp0446end if447next448end if449450if object.exploding != false451temp0 = oscillation452temp0 &= 7453if temp0 == 0454Rand(temp0, 48)455temp0 -= 24456temp0 <<= 16457temp0 += object.xpos458Rand(temp1, 48)459temp1 -= 24460temp1 <<= 16461temp1 += object.ypos462CreateTempObject(TypeName[Explosion], 0, temp0, temp1)463object[tempObjectPos].drawOrder = 5464PlaySfx(SfxName[Explosion], false)465end if466end if467468if object.cannonFrame == 8469// If the cannon's destroyed, then spawn Smoke Puffs too470temp0 = oscillation471temp0 &= 31472if temp0 == 0473CreateTempObject(TypeName[Eggman SmokePuff], 0, object.xpos, object.ypos)474object[tempObjectPos].ypos -= 0x280000475object[tempObjectPos].xvel -= 0x6000476object[tempObjectPos].yvel -= 0xC000477end if478end if479end event480481482event ObjectDraw483if object.flamethrowerTimer != 0484DrawSpriteFX(object.flamethrowerFrame, FX_FLIP, object.xpos, object.ypos)485end if486487switch object.animation488case HTZEGGANI_IDLE489temp0 = object.animationTimer490temp0 >>= 3491object.animationTimer++492object.animationTimer &= 15493DrawSpriteFX(temp0, FX_FLIP, object.xpos, object.ypos)494break495496case HTZEGGANI_LAUGH497temp0 = object.animationTimer498temp0 &= 15499temp0 >>= 3500temp0 += 2501object.animationTimer++502if object.animationTimer == 50503object.animationTimer = 0504505if player[0].animation != ANI_DYING506object.animation = HTZEGGANI_IDLE507end if508end if509DrawSpriteFX(temp0, FX_FLIP, object.xpos, object.ypos)510break511512case HTZEGGANI_HIT513temp0 = object.animationTimer514temp0 &= 1515temp0 += 2516object.animationTimer++517if object.animationTimer == 50518object.animationTimer = 0519object.animation = HTZEGGANI_IDLE520end if521DrawSpriteFX(4, FX_FLIP, object.xpos, object.ypos)522break523524case HTZEGGANI_DEFEATED525temp0 = object.animationTimer526temp0 >>= 5527temp0 += 4528temp0 %= 5529object.animationTimer++530object.animationTimer &= 63531DrawSpriteFX(temp0, FX_FLIP, object.xpos, object.ypos)532break533534case HTZEGGANI_TOASTED535DrawSpriteFX(5, FX_FLIP, object.xpos, object.ypos)536break537538end switch539540DrawSpriteFX(6, FX_FLIP, object.xpos, object.ypos)541DrawSpriteFX(object.cannonFrame, FX_FLIP, object.xpos, object.ypos)542end event543544545event ObjectStartup546CheckCurrentStageFolder("Zone05")547548if checkResult == true549LoadSpriteSheet("HTZ/Objects.gif")550551SpriteFrame(-15, -10, 17, 7, 66, 108) // #0 - Visor frame 1552SpriteFrame(-15, -10, 17, 7, 66, 116) // #1 - Visor frame 2 (seems to be a duplicate?)553SpriteFrame(-15, -10, 17, 7, 66, 124) // #2 - Laugh frame 1554SpriteFrame(-15, -10, 17, 7, 66, 132) // #3 - Laugh frame 2555SpriteFrame(-15, -10, 17, 7, 66, 140) // #4 - Hurt frame556SpriteFrame(-15, -10, 17, 7, 66, 148) // #5 - Burnt frame557SpriteFrame(-32, -12, 64, 45, 1, 210) // #6 - Eggmobile main frame (cropped from larger sprite)558SpriteFrame(-24, -36, 40, 24, 9, 186) // #7 - Eggmobile cannon (croped from same larger sprite as above)559SpriteFrame(-16, -20, 32, 8, 17, 132) // #8 - Destroyed Eggmobile cannon (again cropped frome larger sprite)560561// #9 -> #18 - Flamethrower frames562SpriteFrame(-32, -32, 8, 6, 1, 124)563SpriteFrame(-40, -33, 16, 7, 10, 124)564SpriteFrame(-48, -33, 24, 8, 1, 54)565SpriteFrame(-64, -33, 40, 8, 1, 63)566SpriteFrame(-80, -33, 56, 8, 1, 72)567SpriteFrame(-96, -33, 72, 8, 1, 81)568SpriteFrame(-112, -33, 88, 8, 1, 90)569SpriteFrame(-120, -33, 88, 8, 1, 99)570SpriteFrame(-119, -33, 63, 8, 1, 108)571SpriteFrame(-120, -32, 31, 6, 1, 117)572573if options.vsMode == true574foreach (TypeName[Eggman], arrayPos0, ALL_ENTITIES)575// No Eggmen to interfere in 2P mode576object[arrayPos0].type = TypeName[Blank Object]577next578end if579else580LoadSpriteSheet("MBZ/Objects.gif")581582SpriteFrame(-15, -10, 17, 7, 1007, 34) // #0 - Visor frame 1583SpriteFrame(-15, -10, 17, 7, 1007, 42) // #1 - Visor frame 2 (seems to be a duplicate?)584SpriteFrame(-15, -10, 17, 7, 1007, 50) // #2 - Laugh frame 1585SpriteFrame(-15, -10, 17, 7, 1007, 58) // #3 - Laugh frame 2586SpriteFrame(-15, -10, 17, 7, 1007, 66) // #4 - Hurt frame587SpriteFrame(-15, -10, 17, 7, 1007, 74) // #5 - Burnt frame588589// While the flame and visor sprites are all the way on the left of the sheet, these Eggmobile ones are over in the middle, separated...590SpriteFrame(-32, -12, 64, 45, 415, 154) // #6 - Eggmobile main frame (cropped from larger sprite)591SpriteFrame(-24, -36, 40, 24, 423, 130) // #7 - Eggmobile cannon (croped from same larger sprite as above)592593// Broken cannon frame with another fun difference - while the HTZ sheet has a duplicate Eggmobile attached to this sprite, MBZ optimises it and crops the unnecessary sprite off594SpriteFrame(-16, -20, 32, 8, 480, 170) // #8 - Destroyed Eggmobile cannon (again cropped frome larger sprite)595596// #9 -> #18 - Flamethrower frames597SpriteFrame(-32, -32, 8, 6, 877, 116)598SpriteFrame(-40, -33, 16, 7, 886, 116)599SpriteFrame(-48, -33, 24, 8, 982, 46)600SpriteFrame(-64, -33, 40, 8, 966, 55)601SpriteFrame(-80, -33, 56, 8, 950, 64)602SpriteFrame(-96, -33, 72, 8, 934, 73)603SpriteFrame(-112, -33, 88, 8, 919, 82)604SpriteFrame(-120, -33, 88, 8, 919, 91)605SpriteFrame(-119, -33, 63, 8, 877, 100)606SpriteFrame(-120, -32, 31, 6, 877, 109)607end if608end event609610611// ========================612// Editor Events613// ========================614615event RSDKDraw616DrawSprite(0)617DrawSprite(1)618DrawSprite(2)619620if editor.showGizmos == true621editor.drawingOverlay = true622623// We're gonna draw out all the arena details here624625// First, draw the overall boss arena bounds626temp0 = 352; temp1 = 272; temp2 = 96; temp3 = 32627CallFunction(EditorHelpers_DrawHitbox)628629// X Position of right lava pit630object.pitR.x = object.xpos631632// X Position of left lava pit633object.pitL.x = object.pitR.x634object.pitL.x -= 0x1000000635636// Y Position to start from when in left lava pit637object.pitL.y = object.ypos638object.pitL.y += 0x260000639640// Y Position of where to start from when in right lava pit641object.pitR.y = object.ypos642object.pitR.y += 0xF0000643644// Lava->Sky on left lava pit645temp0 = object.pitL.y646temp0 -= 0x8C0000647DrawArrow(object.pitL.x, object.pitL.y, object.pitL.x, temp0, 0, 255, 0)648649// Lava->Sky on right lava pit650temp0 = object.pitR.y651temp0 -= 0x8C0000652DrawArrow(object.pitR.x, object.pitR.y, object.pitR.x, temp0, 0, 255, 0)653654DrawLine(object.pitL.x, object.pitL.y, object.pitR.x, object.pitR.y, 0, 255, 0)655656editor.drawingOverlay = false657end if658end event659660661event RSDKLoad662CheckCurrentStageFolder("Zone05")663if checkResult == true664LoadSpriteSheet("HTZ/Objects.gif")665SpriteFrame(-15, -10, 17, 7, 66, 108) // Eggman peeking through the visor frame666SpriteFrame(-32, -12, 64, 45, 1, 210) // Eggmobile667SpriteFrame(-24, -36, 40, 24, 9, 186) // Cannon668669// The last two SpriteFrames could be combined here to simply use the entire sprite, but for the sake of clarity (+ MBZ support), they shall be left alone...670else671LoadSpriteSheet("MBZ/Objects.gif")672SpriteFrame(-15, -10, 17, 7, 1007, 34)673SpriteFrame(-32, -12, 64, 45, 415, 154)674SpriteFrame(-24, -36, 40, 24, 423, 130)675end if676677SetVariableAlias(ALIAS_VAR_PROPVAL, "unused")678end event679680681