Path: blob/main/Scripts/R7/Hotaru.txt
1319 views
//-------------------Sonic CD Hotaru Script-------------------//1//--------Scripted by Christian Whitehead 'The Taxman'--------//2//-------Unpacked By Rubberduckycooly's Script Unpacker-------//34// Some notes:5// - This single "Hotaru" Object controls two Hotaru badniks in gameplay6// - Both of these Hotarus are localised entirely within this single "Hotaru" Object7// - However, even with this, "Hotaru" Object in the scene should be followed by two Blank Objects8// - This is needed for spawning flowers, since each individual Hotaru drops its own Flower9// - This base Hotaru object will never become a Flower, but it will become a Blank Object if its Hotarus are both destroyed1011// Aliases1213#alias Object.Value0 : Object.Timer1415#alias Object.Value1 : Object.StartPosX16#alias Object.Value2 : Object.StartPosY1718// Stored as offsets from the base Hotaru object, not complete positions19#alias Object.Value3 : Object.Hotaru1X20#alias Object.Value4 : Object.Hotaru2X2122// (Y distance remains the same between both, see Object.HotaruRadius)2324// Bit-field that represents the state of the active Hotarus, bit 0 is Hotaru 1 and bit 1 is Hotaru 225#alias Object.Value5 : Object.ActiveHotarus2627// True or false, for if the floating sparks connecting the Hotarus are active28#alias Object.Value6 : Object.EletricityActive2930// Y-Offset, half the distance between the two Hotarus31#alias Object.Value7 : Object.HotaruRadius3233#alias Object.PropertyValue : Object.Quality3435// Player Aliases36#alias Player.Value4 : Player.InvincibleTimer3738// Object Score Alias39#alias Object[26].Value0 : ObjectScore.Timer4041// Hotaru States42#alias 0 : HOTARU_IDLE143#alias 1 : HOTARU_IDLE244#alias 2 : HOTARU_TRACKPLAYER45#alias 3 : HOTARU_PAUSE46#alias 4 : HOTARU_LIGHTSON147#alias 5 : HOTARU_LIGHTSOFF148#alias 6 : HOTARU_LIGHTSON249#alias 7 : HOTARU_LIGHTSOFF250#alias 8 : HOTARU_LIGHTSON351#alias 9 : HOTARU_LIGHTSOFF352#alias 10 : HOTARU_FLASHING53#alias 11 : HOTARU_FLYAWAY54#alias 12 : HOTARU_OFFSCREEN5556// Global SFX57#alias 8 : SFX_G_DESTROY5859// Badnik Quality / Property Values60#alias 0 : GOOD_QUALITY61#alias 1 : BAD_QUALITY6263// Priority64#alias 0 : PRIORITY_BOUNDS65#alias 1 : PRIORITY_ACTIVE666768// Function declarations69#function Hotaru_HotaruBreak707172function Hotaru_HotaruBreak7374// This function is called to see if the individual Hotaru being checked should break7576// Preconditions:77// - Object.XPos & Object.YPos are set to the positions of the Hotaru being checked (not the base Hotaru object!)78// - ArrayPos1 is the EntityNo of where to spawn the Hotaru, if it needs to be broken7980// This wasn't updated for Plus, so no amount of hammers or knuckles will ever work on Hotarus :(8182CheckEqual(Player.Animation, ANI_JUMPING)83TempValue0 = CheckResult84CheckEqual(Player.Animation, ANI_SPINDASH)85TempValue0 |= CheckResult8687if Player.Animation == ANI_FLYING88CheckGreater(Player.YPos, Object.YPos)89TempValue0 |= CheckResult90end if9192// Notably, the invincibility granted by time warping isn't granted here...9394if TempValue0 == true95ResetObjectEntity(ArrayPos1, Flower_TypeNo, 0, Object.XPos, Object.YPos)96Object[ArrayPos1].DrawOrder = 49798CreateTempObject(TypeName[Smoke Puff], 0, Object.XPos, Object.YPos)99Object[TempObjectPos].DrawOrder = 4100101CreateTempObject(TypeName[Object Score], ObjectScore.Timer, Object.XPos, Object.YPos)102Object[TempObjectPos].DrawOrder = 4103104PlaySfx(SFX_G_DESTROY, false)105106if Player.YVelocity > 0107FlipSign(Player.YVelocity)108else109Player.YVelocity += 0xC000110end if111112// Grant the player some score113switch ObjectScore.Timer114case 0115Player.Score += 100116break117118case 1119Player.Score += 200120break121122case 2123Player.Score += 500124break125126case 3127Player.Score += 1000128break129130end switch131else132ArrayPos0 = Player.EntityNo133ArrayPos0 += 2134if Object[ArrayPos0].Type == TypeName[Invincibility]135ResetObjectEntity(ArrayPos1, Flower_TypeNo, 0, Object.XPos, Object.YPos)136Object[ArrayPos1].DrawOrder = 4137138CreateTempObject(TypeName[Smoke Puff], 0, Object.XPos, Object.YPos)139Object[TempObjectPos].DrawOrder = 4140141CreateTempObject(TypeName[Object Score], ObjectScore.Timer, Object.XPos, Object.YPos)142Object[TempObjectPos].DrawOrder = 4143144PlaySfx(SFX_G_DESTROY, false)145146if Player.YVelocity > 0147FlipSign(Player.YVelocity)148end if149150// Grant the player's score151switch ObjectScore.Timer152case 0153Player.Score += 100154break155156case 1157Player.Score += 200158break159160case 2161Player.Score += 500162break163164case 3165Player.Score += 1000166break167168end switch169else170if Object.State > HOTARU_LIGHTSOFF3171if Player.InvincibleTimer == 0172Player.State = Player_State_GotHit173if Player.XPos > Object.XPos174Player.Speed = 0x20000175else176Player.Speed = -0x20000177end if178end if179end if180end if181end if182183end function184185186sub ObjectMain187if Object.OutOfBounds == true188Object.State = HOTARU_OFFSCREEN189Object.Timer = 0190191// Set the object back to its starting position192// Note that the Hotarus' state being set to HOTARU_OFFSCREEN means that there won't be any visible teleporting193Object.XPos = Object.StartPosX194Object.YPos = Object.StartPosY195196// Reset the Hotarus to be 70 pixels apart197// (Regardless of their Property Value, since that's already been reset...)198Object.Hotaru1X = -0x230000199Object.Hotaru2X = 0x230000200201Object.EletricityActive = false202end if203204// Even if there are really only small differences between the two's behaviours, the GOOD and BAD badnik types just have entirely different205if Object.Quality == GOOD_QUALITY206switch Object.State207case HOTARU_IDLE1208Object.Priority = PRIORITY_ACTIVE209210// Right range of 43 pixels for Hotaru 1211if Object.Hotaru1X < 0x2B0000212// Move both Hotarus in their respective directions by a pixel213Object.Hotaru1X += 0x10000214Object.Hotaru2X -= 0x10000215else216// Turn around217Object.State = HOTARU_IDLE2218end if219break220221case HOTARU_IDLE2222// Left range of 115 pixels for Hotaru 1223if Object.Hotaru1X > -0x730000224// Move both Hotarus in their respective directions by a pixel225Object.Hotaru1X -= 0x10000226Object.Hotaru2X += 0x10000227else228// Turn around229Object.State = HOTARU_IDLE1230end if231break232233case HOTARU_TRACKPLAYER234// Make the Hotarus follow the screen235236TempValue0 = Screen.XOffset237TempValue0 += Screen.CenterX238TempValue0 <<= 16239TempValue1 = false240if Object.XPos < TempValue0241Object.XPos += 0x20000242if Object.XPos >= TempValue0243Object.XPos = TempValue0244TempValue1 = true245end if246else247Object.XPos -= 0x20000248if Object.XPos <= TempValue0249Object.XPos = TempValue0250TempValue1 = true251end if252end if253254TempValue0 = Screen.YOffset255TempValue0 += 104256TempValue0 <<= 16257if Object.YPos < TempValue0258Object.YPos += 0x20000259if Object.YPos >= TempValue0260Object.YPos = TempValue0261if TempValue1 == true262// In a good position, advance states263Object.State++264end if265end if266else267Object.YPos -= 0x20000268if Object.YPos <= TempValue0269Object.YPos = TempValue0270if TempValue1 == true271// In a good position, advance states272Object.State++273end if274end if275end if276break277278case HOTARU_PAUSE279if Object.Timer < 100280Object.Timer++281else282Object.Timer = 0283Object.State++284end if285Object.Frame = Object.Timer286Object.Frame %= 20287Object.Frame /= 10288Object.Frame++289break290291// A series of very small and similar states - each frame in the flicker animation is its own state292293case HOTARU_LIGHTSON1294if Object.Timer < 4295Object.Timer++296else297Object.Timer = 0298Object.State++299end if300break301302case HOTARU_LIGHTSOFF1303if Object.Timer < 12304Object.Timer++305else306Object.Timer = 0307Object.State++308end if309break310311case HOTARU_LIGHTSON2312if Object.Timer < 8313Object.Timer++314else315Object.Timer = 0316Object.State++317end if318break319320case HOTARU_LIGHTSOFF2321if Object.Timer < 8322Object.Timer++323else324Object.Timer = 0325Object.State++326end if327break328329case HOTARU_LIGHTSON3330if Object.Timer < 12331Object.Timer++332else333Object.Timer = 0334Object.State++335end if336break337338case HOTARU_LIGHTSOFF3339if Object.Timer < 4340Object.Timer++341else342Object.Timer = 0343Object.AnimationTimer = 0344Object.State++345end if346break347348case HOTARU_FLASHING349// This is the state where the Sparks are active, although none of them are managed here350// Head over to ObjectDraw and ObjectPlayerInteraction for that351352if Object.Timer < 100353Object.Timer++354else355Object.Timer = 0356Object.State++357end if358Object.Frame = Object.Timer359Object.Frame %= 20360Object.Frame /= 10361Object.Frame++362break363364case HOTARU_FLYAWAY365// Ascend at a rate of 2 pixels per second366// (This is rather slow, isn't it?)367Object.YPos -= 0x20000368369// Animate the Object370Object.Timer++371Object.Timer %= 20372Object.Frame = Object.Timer373Object.Frame /= 10374Object.Frame++375376if Object.OutOfBounds == true377Object.State = HOTARU_OFFSCREEN378Object.Timer = 0379380// Place the Hotaru back at its starting position381// Since state is being set to HOTARU_OFFSCREEN, there won't be any visible teleporting382Object.XPos = Object.StartPosX383Object.YPos = Object.StartPosY384385// Reset the Hotarus to be 70 pixels apart386// (Regardless of their initial Property Value, since that's already been reset)387Object.Hotaru1X = -0x230000388Object.Hotaru2X = 0x230000389end if390break391392case HOTARU_OFFSCREEN393// This state is here so that, if the Hotarus' start position is within bounds, they won't just suddently teleport in front of the player394if Object.OutOfBounds == true395Object.State = HOTARU_IDLE1396Object.Priority = PRIORITY_BOUNDS397Object.Frame = 0398end if399break400401end switch402else403switch Object.State404case HOTARU_IDLE1405Object.Priority = PRIORITY_ACTIVE406407Object.Frame = 3408409// Right range of 43 pixels for Hotaru 1410if Object.Hotaru1X < 0x2B0000411// Move both Hotarus in their respective directions by a half pixel412Object.Hotaru1X += 0x8000413Object.Hotaru2X -= 0x8000414else415// Turn around416Object.State = HOTARU_IDLE2417end if418break419420case HOTARU_IDLE2421// Left range of 115 pixels for Hotaru 1422if Object.Hotaru1X > -0x730000423// Move both Hotarus in their respective directions by a half pixel424Object.Hotaru1X -= 0x8000425Object.Hotaru2X += 0x8000426else427// Turn around again428Object.State = HOTARU_IDLE1429end if430break431432case HOTARU_TRACKPLAYER433// Make the Hotarus follow the screen434435TempValue0 = Screen.XOffset436TempValue0 += Screen.CenterX437TempValue0 <<= 16438TempValue1 = false439if Object.XPos < TempValue0440Object.XPos += 0x10000441if Object.XPos >= TempValue0442Object.XPos = TempValue0443TempValue1 = true444end if445else446Object.XPos -= 0x10000447if Object.XPos <= TempValue0448Object.XPos = TempValue0449TempValue1 = true450end if451end if452453TempValue0 = Screen.YOffset454TempValue0 += 104455TempValue0 <<= 16456if Object.YPos < TempValue0457Object.YPos += 0x10000458if Object.YPos >= TempValue0459Object.YPos = TempValue0460if TempValue1 == true461Object.State++462end if463end if464else465Object.YPos -= 0x10000466if Object.YPos <= TempValue0467Object.YPos = TempValue0468if TempValue1 == true469Object.State++470end if471end if472end if473break474475case HOTARU_PAUSE476if Object.Timer < 100477Object.Timer++478else479Object.Timer = 0480Object.State++481end if482Object.Frame = Object.Timer483Object.Frame %= 40484Object.Frame /= 20485Object.Frame += 4486break487488// A series of very small and similar states - each frame in the flicker animation is its own state489490case HOTARU_LIGHTSON1491if Object.Timer < 10492Object.Timer++493else494Object.Timer = 0495Object.State++496end if497break498499case HOTARU_LIGHTSOFF1500if Object.Timer < 30501Object.Timer++502else503Object.Timer = 0504Object.State++505end if506break507508case HOTARU_LIGHTSON2509if Object.Timer < 20510Object.Timer++511else512Object.Timer = 0513Object.State++514end if515break516517case HOTARU_LIGHTSOFF2518if Object.Timer < 20519Object.Timer++520else521Object.Timer = 0522Object.State++523end if524break525526case HOTARU_LIGHTSON3527if Object.Timer < 30528Object.Timer++529else530Object.Timer = 0531Object.State++532end if533break534535case HOTARU_LIGHTSOFF3536if Object.Timer < 10537Object.Timer++538else539Object.Timer = 0540Object.AnimationTimer = 0541Object.State++542end if543break544545case HOTARU_FLASHING546// This is the state where the Sparks should be active, but Bad Hotarus have broken bulbs so they don't get to light up...547548if Object.Timer < 200549Object.Timer++550else551Object.Timer = 0552Object.State++553end if554Object.Frame = Object.Timer555Object.Frame %= 40556Object.Frame /= 20557Object.Frame += 4558break559560case HOTARU_FLYAWAY561// Ascend at a rate of 2 pixels per second562// (This is rather slow, isn't it?)563Object.YPos -= 0x20000564565// Animate the Object566Object.Timer++567Object.Timer %= 40568Object.Frame = Object.Timer569Object.Frame /= 20570Object.Frame += 4571572if Object.OutOfBounds == true573Object.State = HOTARU_OFFSCREEN574Object.Timer = 0575576// Place the Hotarus back at their starting positions577// Because the State's set to HOTARU_OFFSCREEN, that there won't be any visible teleporting578Object.XPos = Object.StartPosX579Object.YPos = Object.StartPosY580581// Reset the Hotarus to be 70 pixels apart582// (Ignoring their Property Value, since it got replaced by Hotaru Condition during startup)583Object.Hotaru1X = -0x230000584Object.Hotaru2X = 0x230000585end if586break587588case HOTARU_OFFSCREEN589// This state is here so that, if the Hotarus' start position is within bounds, they won't just visibly teleport in front of the player590if Object.OutOfBounds == true591Object.State = HOTARU_IDLE1592Object.Priority = PRIORITY_BOUNDS593Object.Frame = 0594end if595break596597end switch598end if599600CallFunction(StageSetup_CheckGoodFuture)601602if Object.ActiveHotarus == 0603// If this object doesn't have any more alive Hotarus, than just unload now as it serves no purpose604ResetObjectEntity(Object.EntityNo, TypeName[Blank Object], 0, 0, 0)605end if606607end sub608609610sub ObjectPlayerInteraction611switch Object.State612case HOTARU_IDLE1613case HOTARU_IDLE2614// Wandering around aimlessly, just check to see if the player's entered the Hotarus' general range yet615PlayerObjectCollision(C_TOUCH, -64, -64, 64, 64)616if CheckResult == true617// Player stepped within range, start following them...618Object.State = HOTARU_TRACKPLAYER619end if620break621622case HOTARU_LIGHTSON2623case HOTARU_LIGHTSOFF2624case HOTARU_LIGHTSON3625case HOTARU_LIGHTSOFF3626if Object.Quality == GOOD_QUALITY627// Broken Hotarus don't have functional lights...628629if Object.Hotaru1X < 0630TempValue0 = Object.Hotaru1X631TempValue0 >>= 16632633TempValue1 = Object.Hotaru2X634TempValue1 >>= 16635else636TempValue0 = Object.Hotaru2X637TempValue0 >>= 16638639TempValue1 = Object.Hotaru1X640TempValue1 >>= 16641end if642643TempValue0 += 8644TempValue1 -= 8645646PlayerObjectCollision(C_TOUCH, TempValue0, -60, TempValue1, 60)647if CheckResult == true648// Player's within the sensor range, turn on the lights649Object.EletricityActive = true650end if651652end if653654// No break?655// Well, I suppose it's not too important...656657end switch658659// Don't do any of these further checks if the Hotaru's not even existent660if Object.State < HOTARU_OFFSCREEN661662// Backup the base object's position663TempValue6 = Object.XPos664TempValue7 = Object.YPos665666// Check collision for Hotaru 1667GetBit(TempValue1, Object.ActiveHotarus, 0)668if TempValue1 == true669670// Adjust the object's position to match that of Hotaru 1671Object.XPos += Object.Hotaru1X672Object.YPos -= Object.HotaruRadius673674// Check if there was collision675PlayerObjectCollision(C_TOUCH, -8, -8, 8, 8)676if CheckResult == true677// Check if the Hotaru should be broken678679ArrayPos1 = Object.EntityNo680ArrayPos1++681CallFunction(Hotaru_HotaruBreak)682683if Object[+1].Type == Flower_TypeNo684// The Hotaru was destroyed, blank its according bit685SetBit(Object.ActiveHotarus, 0, false)686end if687end if688689// Restore the Object's position to what it was before690Object.XPos = TempValue6691Object.YPos = TempValue7692end if693694// Check collision for Hotaru 2695GetBit(TempValue1, Object.ActiveHotarus, 1)696if TempValue1 == true697698// Adjust the Object's Position to be where Hotaru 2 is699Object.XPos += Object.Hotaru2X700Object.YPos += Object.HotaruRadius701702// Check for collision against this Hotaru703PlayerObjectCollision(C_TOUCH, -8, -8, 8, 8)704if CheckResult == true705// Check if the Hotaru should be destroyed or hurt the player706707ArrayPos1 = Object.EntityNo708ArrayPos1 += 2709CallFunction(Hotaru_HotaruBreak)710711if Object[+2].Type == Flower_TypeNo712// The Hotaru has been destroyed, so set its bit to zero713SetBit(Object.ActiveHotarus, 1, false)714end if715end if716end if717718// If needed, check for the Sparks719if Object.State == HOTARU_FLASHING720if Object.EletricityActive == true721722// That is to say, are both Hotarus active? (3 is 0b11 in bits)723if Object.ActiveHotarus == 3724725// Check collision for the Sparks726727// First, backup the object's position728Object.XPos = TempValue6729Object.YPos = TempValue7730731// Check collision for the middle Spark732PlayerObjectCollision(C_TOUCH, -12, -12, 12, 12)733if CheckResult == true734CallFunction(Player_Hit)735end if736737// Check collision for the left Spark738739Object.XPos = TempValue6740Object.XPos >>= 1741742TempValue1 = TempValue6743TempValue1 += Object.Hotaru1X744TempValue1 >>= 1745746Object.XPos += TempValue1747Object.YPos = TempValue7748Object.YPos >>= 1749750TempValue1 = TempValue7751TempValue1 -= Object.HotaruRadius752TempValue1 >>= 1753754Object.YPos += TempValue1755756PlayerObjectCollision(C_TOUCH, -12, -12, 12, 12)757if CheckResult == true758CallFunction(Player_Hit)759end if760761// Check collision for the right Spark762763Object.XPos = TempValue6764Object.XPos >>= 1765766TempValue1 = TempValue6767TempValue1 += Object.Hotaru2X768TempValue1 >>= 1769770Object.XPos += TempValue1771Object.YPos = TempValue7772Object.YPos >>= 1773774TempValue1 = TempValue7775TempValue1 += Object.HotaruRadius776TempValue1 >>= 1777778Object.YPos += TempValue1779780PlayerObjectCollision(C_TOUCH, -12, -12, 12, 12)781if CheckResult == true782CallFunction(Player_Hit)783end if784785end if786end if787end if788789// Restore the base object's position to what it should be790Object.XPos = TempValue6791Object.YPos = TempValue7792793end if794795end sub796797798sub ObjectDraw799switch Object.State800case HOTARU_IDLE1801GetBit(CheckResult, Object.ActiveHotarus, 0)802if CheckResult == true803TempValue0 = Object.Hotaru1X804TempValue0 += Object.XPos805TempValue1 = Object.YPos806TempValue1 -= Object.HotaruRadius807Object.Direction = FACING_LEFT808DrawSpriteFX(Object.Frame, FX_FLIP, TempValue0, TempValue1)809end if810811GetBit(CheckResult, Object.ActiveHotarus, 1)812if CheckResult == true813TempValue0 = Object.Hotaru2X814TempValue0 += Object.XPos815TempValue1 = Object.YPos816TempValue1 += Object.HotaruRadius817Object.Direction = FACING_RIGHT818DrawSpriteFX(Object.Frame, FX_FLIP, TempValue0, TempValue1)819end if820break821822case HOTARU_IDLE2823GetBit(CheckResult, Object.ActiveHotarus, 0)824if CheckResult == true825TempValue0 = Object.Hotaru1X826TempValue0 += Object.XPos827TempValue1 = Object.YPos828TempValue1 -= Object.HotaruRadius829Object.Direction = FACING_RIGHT830DrawSpriteFX(Object.Frame, FX_FLIP, TempValue0, TempValue1)831end if832833GetBit(CheckResult, Object.ActiveHotarus, 1)834if CheckResult == true835TempValue0 = Object.Hotaru2X836TempValue0 += Object.XPos837TempValue1 = Object.YPos838TempValue1 += Object.HotaruRadius839Object.Direction = FACING_LEFT840DrawSpriteFX(Object.Frame, FX_FLIP, TempValue0, TempValue1)841end if842break843844case HOTARU_TRACKPLAYER845// Always face the Player846if Player.XPos < Object.XPos847Object.Direction = FACING_RIGHT848else849Object.Direction = FACING_LEFT850end if851852GetBit(CheckResult, Object.ActiveHotarus, 0)853if CheckResult == true854TempValue0 = Object.Hotaru1X855TempValue0 += Object.XPos856TempValue1 = Object.YPos857TempValue1 -= Object.HotaruRadius858DrawSpriteFX(Object.Frame, FX_FLIP, TempValue0, TempValue1)859end if860861GetBit(CheckResult, Object.ActiveHotarus, 1)862if CheckResult == true863TempValue0 = Object.Hotaru2X864TempValue0 += Object.XPos865TempValue1 = Object.YPos866TempValue1 += Object.HotaruRadius867DrawSpriteFX(Object.Frame, FX_FLIP, TempValue0, TempValue1)868end if869break870871case HOTARU_PAUSE872Object.XPos = Screen.XOffset873Object.XPos += Screen.CenterX874Object.XPos <<= 16875Object.YPos = Screen.YOffset876Object.YPos += 104877Object.YPos <<= 16878879GetBit(CheckResult, Object.ActiveHotarus, 0)880if CheckResult == true881TempValue0 = Object.Hotaru1X882TempValue0 += Object.XPos883TempValue1 = Object.YPos884TempValue1 -= Object.HotaruRadius885DrawSpriteFX(Object.Frame, FX_FLIP, TempValue0, TempValue1)886end if887888GetBit(CheckResult, Object.ActiveHotarus, 1)889if CheckResult == true890TempValue0 = Object.Hotaru2X891TempValue0 += Object.XPos892TempValue1 = Object.YPos893TempValue1 += Object.HotaruRadius894DrawSpriteFX(Object.Frame, FX_FLIP, TempValue0, TempValue1)895end if896break897898case HOTARU_LIGHTSON1899case HOTARU_LIGHTSON2900case HOTARU_LIGHTSON3901case HOTARU_FLYAWAY902GetBit(CheckResult, Object.ActiveHotarus, 0)903if CheckResult == true904TempValue0 = Object.Hotaru1X905TempValue0 += Object.XPos906TempValue1 = Object.YPos907TempValue1 -= Object.HotaruRadius908DrawSpriteFX(6, FX_FLIP, TempValue0, TempValue1)909DrawSpriteFX(Object.Frame, FX_FLIP, TempValue0, TempValue1)910end if911912GetBit(CheckResult, Object.ActiveHotarus, 1)913if CheckResult == true914TempValue0 = Object.Hotaru2X915TempValue0 += Object.XPos916TempValue1 = Object.YPos917TempValue1 += Object.HotaruRadius918DrawSpriteFX(6, FX_FLIP, TempValue0, TempValue1)919DrawSpriteFX(Object.Frame, FX_FLIP, TempValue0, TempValue1)920end if921break922923case HOTARU_LIGHTSOFF1924case HOTARU_LIGHTSOFF2925case HOTARU_LIGHTSOFF3926GetBit(CheckResult, Object.ActiveHotarus, 0)927if CheckResult == true928TempValue0 = Object.Hotaru1X929TempValue0 += Object.XPos930TempValue1 = Object.YPos931TempValue1 -= Object.HotaruRadius932DrawSpriteFX(Object.Frame, FX_FLIP, TempValue0, TempValue1)933end if934935GetBit(CheckResult, Object.ActiveHotarus, 1)936if CheckResult == true937TempValue0 = Object.Hotaru2X938TempValue0 += Object.XPos939TempValue1 = Object.YPos940TempValue1 += Object.HotaruRadius941DrawSpriteFX(Object.Frame, FX_FLIP, TempValue0, TempValue1)942end if943break944945case HOTARU_FLASHING946GetBit(CheckResult, Object.ActiveHotarus, 0)947if CheckResult == true948TempValue0 = Object.Hotaru1X949TempValue0 += Object.XPos950TempValue1 = Object.YPos951TempValue1 -= Object.HotaruRadius952DrawSpriteFX(6, FX_FLIP, TempValue0, TempValue1)953DrawSpriteFX(Object.Frame, FX_FLIP, TempValue0, TempValue1)954end if955956GetBit(CheckResult, Object.ActiveHotarus, 1)957if CheckResult == true958TempValue0 = Object.Hotaru2X959TempValue0 += Object.XPos960TempValue1 = Object.YPos961TempValue1 += Object.HotaruRadius962DrawSpriteFX(6, FX_FLIP, TempValue0, TempValue1)963DrawSpriteFX(Object.Frame, FX_FLIP, TempValue0, TempValue1)964end if965966if Object.EletricityActive == true967if Object.ActiveHotarus == 3 // Both bits in the number active, meaning that both Hotarus are alive and well968969// Draw the Middle Spark970TempValue0 = Object.AnimationTimer971TempValue0 >>= 1972TempValue0 += 7973DrawSprite(TempValue0)974975// Draw the Left Spark976977TempValue1 = Object.XPos978TempValue1 >>= 1979980TempValue3 = Object.XPos981TempValue3 += Object.Hotaru1X982TempValue3 >>= 1983984TempValue1 += TempValue3985986TempValue2 = Object.YPos987TempValue2 >>= 1988989TempValue3 = Object.YPos990TempValue3 -= Object.HotaruRadius991TempValue3 >>= 1992993TempValue2 += TempValue3994995DrawSpriteXY(TempValue0, TempValue1, TempValue2)996997// Draw the Right Spark998999TempValue1 = Object.XPos1000TempValue1 >>= 110011002TempValue3 = Object.XPos1003TempValue3 += Object.Hotaru2X1004TempValue3 >>= 110051006TempValue1 += TempValue310071008TempValue2 = Object.YPos1009TempValue2 >>= 110101011TempValue3 = Object.YPos1012TempValue3 += Object.HotaruRadius1013TempValue3 >>= 110141015TempValue2 += TempValue310161017DrawSpriteXY(TempValue0, TempValue1, TempValue2)10181019// Animate the Sparks1020Object.AnimationTimer++1021Object.AnimationTimer %= 610221023end if1024end if1025break10261027end switch10281029end sub103010311032sub ObjectStartup10331034LoadSpriteSheet("R7/Objects.gif")10351036// Hotaru Frames10371038// "Good" type frames (normal lightbulb)1039SpriteFrame(-20, -12, 40, 24, 182, 121)1040SpriteFrame(-12, -20, 24, 40, 231, 119)1041SpriteFrame(-12, -20, 24, 40, 231, 160)10421043// "Bad" type frames (broken lightbulb)1044SpriteFrame(-20, -12, 40, 24, 182, 146)1045SpriteFrame(-12, -20, 24, 40, 231, 201)1046SpriteFrame(-12, -20, 24, 40, 206, 215)10471048// blulb1049SpriteFrame(-11, -7, 24, 24, 175, 196)10501051// Eletricity Frames1052SpriteFrame(-12, -12, 24, 24, 150, 171)1053SpriteFrame(-12, -12, 24, 24, 175, 171)1054SpriteFrame(-12, -12, 24, 24, 150, 196)10551056// Cycle through all Hotaru objects in the level1057ArrayPos0 = 321058while ArrayPos0 < 10561059if Object[ArrayPos0].Type == TypeName[Hotaru]10601061// First, set their starting positions1062Object[ArrayPos0].StartPosX = Object[ArrayPos0].XPos1063Object[ArrayPos0].StartPosY = Object[ArrayPos0].YPos10641065// Hotarus draw above other objects, including the Player1066Object[ArrayPos0].DrawOrder = 510671068// Setup the Hotarus' type and initial positions1069switch Object[ArrayPos0].Quality1070case 01071// Properties of:1072// Radius of 60 pixels1073// Good variant, with a functioning Light1074// Start the Hotarus 70 pixels apart (35 pixels from the base Pos)1075Object[ArrayPos0].HotaruRadius = 0x3C00001076Object[ArrayPos0].Quality = GOOD_QUALITY1077Object[ArrayPos0].Hotaru1X = -0x2300001078Object[ArrayPos0].Hotaru2X = 0x2300001079break10801081case 11082// Properties of:1083// Radius of 60 pixels1084// Bad variant, with a broken Light1085// Start the Hotarus 70 pixels apart (35 pixels from the base Pos)1086Object[ArrayPos0].HotaruRadius = 0x3C00001087Object[ArrayPos0].Quality = BAD_QUALITY1088Object[ArrayPos0].Hotaru1X = -0x2300001089Object[ArrayPos0].Hotaru2X = 0x2300001090break10911092case 41093// Properties of:1094// Radius of 68 pixels1095// Good variant, with a functioning Light1096// Start the Hotarus 100 pixels apart (50 pixels from the base Pos)1097Object[ArrayPos0].HotaruRadius = 0x4400001098Object[ArrayPos0].Quality = GOOD_QUALITY1099Object[ArrayPos0].Hotaru1X = -0x3200001100Object[ArrayPos0].Hotaru2X = 0x3200001101break11021103case 51104// Properties of:1105// Radius of 68 pixels1106// Bad variant, with a broken Light1107// Start the Hotarus 100 pixels apart (50 pixels from the base Pos)1108Object[ArrayPos0].HotaruRadius = 0x4400001109Object[ArrayPos0].Quality = BAD_QUALITY1110Object[ArrayPos0].Hotaru1X = -0x3200001111Object[ArrayPos0].Hotaru2X = 0x3200001112break11131114case 81115// Properties of:1116// Radius of 56 pixels1117// Good variant, with a functioning Light1118// Start the Hotarus 140 pixels apart (70 pixels from the base Pos)1119Object[ArrayPos0].HotaruRadius = 0x3800001120Object[ArrayPos0].Quality = GOOD_QUALITY1121Object[ArrayPos0].Hotaru1X = -0x4600001122Object[ArrayPos0].Hotaru2X = 0x4600001123break11241125case 91126// Properties of:1127// Radius of 56 pixels1128// Bad variant, with a broken Light1129// Start the Hotarus 140 pixels apart (70 pixels from the base Pos)1130Object[ArrayPos0].HotaruRadius = 0x3800001131Object[ArrayPos0].Quality = BAD_QUALITY1132Object[ArrayPos0].Hotaru1X = -0x4600001133Object[ArrayPos0].Hotaru2X = 0x4600001134break11351136case 121137// Properties of:1138// Radius of 18 pixels1139// Good variant, with a functioning Light1140// Start the Hotarus 192 pixels apart (96 pixels from the base Pos)1141Object[ArrayPos0].HotaruRadius = 0x1200001142Object[ArrayPos0].Quality = GOOD_QUALITY1143Object[ArrayPos0].Hotaru1X = -0x6000001144Object[ArrayPos0].Hotaru2X = 0x6000001145break11461147case 131148// Properties of:1149// Radius of 18 pixels1150// Bad variant, with a broken Light1151// Start the Hotarus 192 pixels apart (96 pixels from the base Pos)1152Object[ArrayPos0].HotaruRadius = 0x1200001153Object[ArrayPos0].Quality = BAD_QUALITY1154Object[ArrayPos0].Hotaru1X = -0x6000001155Object[ArrayPos0].Hotaru2X = 0x6000001156break11571158end switch11591160// Set both of the Object's Hotarus to active1161SetBit(Object[ArrayPos0].ActiveHotarus, 0, true)1162SetBit(Object[ArrayPos0].ActiveHotarus, 1, true)1163end if11641165ArrayPos0++1166loop11671168end sub116911701171// ========================1172// Editor Subs1173// ========================11741175sub RSDKEdit1176if Editor.ReturnVariable == true1177switch Editor.VariableID1178case EDIT_VAR_PROPVAL // Property Value1179CheckResult = Object.PropertyValue1180break1181case 0 // Condition1182CheckResult = Object.PropertyValue1183CheckResult &= 11184break1185case 1 // Formation1186CheckResult = Object.PropertyValue1187CheckResult &= 2541188break1189end switch1190else1191switch Editor.VariableID1192case EDIT_VAR_PROPVAL // Property Value1193Object.PropertyValue = Editor.VariableValue1194break1195case 0 // Condition1196CheckNotEqual(Editor.VariableValue, false)1197SetBit(Object.PropertyValue, 0, CheckResult)1198break1199case 1 // Formation1200Object.PropertyValue &= 11201Editor.VariableValue &= 2541202Object.PropertyValue |= Editor.VariableValue1203break1204end switch1205end if1206end sub120712081209sub RSDKDraw1210// We got a whole lot to do, we're essentially setting up a new Hotaru every time since we can't depend on values from the last frame12111212// First, get the sprite to be used1213GetBit(TempValue5, Object.Quality, 0)12141215// Then, get the movement values based on the Hotaru's designated Formation1216TempValue0 = Object.Quality1217TempValue0 &= 25412181219switch TempValue01220case 01221default // inaccurate to how it'll be in-game if given an invalid formation, but it doesn't matter too much1222TempValue2 = 0x3C00001223TempValue3 = -0x2300001224break1225case 41226TempValue2 = 0x4400001227TempValue3 = -0x3200001228break1229case 81230TempValue2 = 0x3800001231TempValue3 = -0x4600001232break1233case 121234TempValue2 = 0x1200001235TempValue3 = -0x6000001236break1237end switch12381239TempValue4 = TempValue31240FlipSign(TempValue4)12411242TempValue0 = TempValue31243TempValue0 += Object.XPos1244TempValue1 = Object.YPos1245TempValue1 -= TempValue21246Object.Direction = FACING_LEFT1247DrawSpriteFX(TempValue5, FX_FLIP, TempValue0, TempValue1)12481249TempValue6 = TempValue41250TempValue6 += Object.XPos1251TempValue7 = Object.YPos1252TempValue7 += TempValue21253Object.Direction = FACING_RIGHT1254DrawSpriteFX(TempValue5, FX_FLIP, TempValue6, TempValue7)12551256if Editor.ShowGizmos == true1257Editor.DrawingOverlay = true12581259// First, draw the Hotaru's movement ranges1260DrawLine(TempValue0, TempValue1, TempValue6, TempValue1, 255, 255, 255)1261DrawLine(TempValue6, TempValue7, TempValue0, TempValue7, 255, 255, 255)12621263Object.InkEffect = 112641265// Then, draw some lines to indicate this Hotaru's following Flower entities1266DrawArrow(Object.XPos, Object.YPos, Object[+1].XPos, Object[+1].YPos, 255, 255, 0)1267DrawArrow(Object.XPos, Object.YPos, Object[+2].XPos, Object[+2].YPos, 255, 255, 0)12681269Object.InkEffect = 012701271Editor.DrawingOverlay = false1272end if1273end sub127412751276sub RSDKLoad1277LoadSpriteSheet("R7/Objects.gif")1278SpriteFrame(-20, -12, 40, 24, 182, 121)1279SpriteFrame(-20, -12, 40, 24, 182, 146)12801281AddEditorVariable("Condition")1282SetActiveVariable("Condition")1283AddEnumVariable("Good", GOOD_QUALITY)1284AddEnumVariable("Bad", BAD_QUALITY)12851286AddEditorVariable("Formation")1287SetActiveVariable("Formation")1288AddEnumVariable("Formation A", 0)1289AddEnumVariable("Formation B", 4)1290AddEnumVariable("Formation C", 8)1291AddEnumVariable("Formation D", 12)1292end sub129312941295