Difference between revisions of "Beetlejuice (NES)/Game Mechanics and Techniques"
From SDA Knowledge Base
(→Enemies and objects) |
m (→Sweepers) |
||
(81 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
==Animations== | ==Animations== | ||
===Movement mechanics=== | ===Movement mechanics=== | ||
+ | * 3BF/3BE/3BD - Big/Small/Sub x-position | ||
+ | * 3C4/3C3 - Small/Sub x-speed | ||
+ | * 3C2/3C1/3C0 - Big/Small/Sub y-position | ||
+ | * 3C7/3C6 - Small/Sub y-speed | ||
+ | <br /> | ||
+ | |||
+ | Beetlejuice accelerates in the x-direction with 32 sub-pixels/frame^2 up to a speed of 2 pixels/frame. The acceleration is the same on the ground as in the air. However, jumping has a wind-up frame, so it's slightly slower to jump when accelerating. Letting go of the direction button will make him stop immediately when on the ground, while momentum is kept (no brake effect) when jumping. "Braking" in the air decelerates Beetlejuice with 64 sub-pixels/frame^2. | ||
+ | <br /> | ||
+ | |||
===Time cost comparisons=== | ===Time cost comparisons=== | ||
+ | * A continue screen costs from 45 frames and upwards, depending on how quickly it's clicked away, on top of the other costs associated with a death. | ||
+ | <br /> | ||
+ | <u>Side view levels</u> | ||
+ | * A knockback costs 54 frames | ||
+ | * Falling into a pit from roughly half the screen's height costs ~140 frames. 30-40 of those are from the fall itself, the rest from re-spawning. On top of that, 8 frames more will be lost from having to accelerate from 0 when re-spawning. | ||
+ | * Losing the last health from taking a hit in the same position as above and triggering the "skeleton" death animation costs ~20 frames more | ||
+ | * Entering a shop and purchase one item costs 3.4s | ||
+ | * A menu trip and selecting the highlighted or an adjacent scare is 1.1s | ||
+ | <br /> | ||
+ | |||
+ | <u>Overhead levels</u> | ||
+ | * A death from mid-screen costs ~120 frames | ||
+ | <br /> | ||
==Scares== | ==Scares== | ||
Line 64: | Line 86: | ||
==RNG== | ==RNG== | ||
− | The RNG-addresses in RAM are $24-$27. | + | The RNG-addresses in RAM are $24-$27. There are three different algorithms that are used to update their values. |
− | + | # Starting at $99A8, various logical operations on and between the RNG-addresses are done, with the previous set of RNG and the global timer ($3BB) as seeds. | |
− | + | # Starting at $DFA5, a similar algorithm to the first. | |
− | + | # Starting at $909A, only two of the RNG-values are updated. This is done based on Beetlejuice's x- and y-position (influencing $24 and $25, respectively). | |
− | + | ||
− | + | ||
− | + | ||
+ | The first two algorithms are used throughout the game with what appears to be a room-dependent frequency (usually every 2-8 frames), with additional calls if there are RNG-dependent enemies present. The sub-routine for the third algorithm is only used in the side-scrolling levels and only called every 256 frames. Room 0x09 (the very first overhead room in the game) is special in the sense that the RNG is never updated in this room.<br /><br /> | ||
+ | There is no indication that the RNG-values would be possible to manipulate in real-time. In TAS-conditions, the RNG is fairly "stiff" and can only be manipulated to a certain extent (unless introducing waiting frames is considered). In the side-view levels, it's done by changing Beetlejuice's position before '3' is called. In the overhead levels, it's mainly done by throwing a potion at different times or in some cases defeating enemies on different frames. In the room with Delia (0x19), picking up the mouse and scaring off Delia on different frames can also be used to influence the RNG. These methods have in common that they influence the number of calls to the RNG sub-routine.<br /><br /> | ||
==Enemies and objects== | ==Enemies and objects== | ||
Line 83: | Line 104: | ||
<br /> | <br /> | ||
− | When the shot flag is not set, the RNG function is called every 16 frames, based on the global timer ($3BB). One of the results is compared with 0x46 (instruction $C8F9). If it's less, the boss will shoot a puff of | + | When the shot flag is not set, the RNG function is called every 16 frames, based on the global timer ($3BB). One of the results is compared with 0x46 (instruction $C8F9). If it's less, the boss will shoot a puff of spray. Since the player neither knows the global timer, nor the RNG values, shots can be considered random and outside player control with a probability of (1/16)*(70/256) ~ 1/59 per frame. The fastest method to defeat the boss is to run straight at him and fire off three quick shots. This way, a typical fight takes ~80 frames, which will allow 5 or 6 opportunities for the boss to fire. The success rate will therefore be between (186/256)^6 ~15% and (186/256)^5 ~20%. A slightly more consistent method is to introduce a jump after the first scare attack, regardless of if the boss has actually fired or not. The fight will then typically take ~100 frames. It's not as straight-forward to calculate the success rate in this case and has not been attempted, but it's noticeably more consistent.<br /><br /> |
− | The speed of the puff is either 1 or 2 pixels/frame and with a sub-speed that is a multiple of 0x40 (a sub-speed >0 slows down the puffs). | + | The speed of the puff is either 1 or 2 pixels/frame and with a sub-speed that is a multiple of 0x40 (a sub-speed >0 slows down the puffs). Both the main and sub speeds directly depend on $24 (the first RNG-address) and should therefore be equally distributed with no possibility to predict in real-time.<br /> |
===2nd boss (Level 2)=== | ===2nd boss (Level 2)=== | ||
[[File:2nd_boss.PNG|75px]]<br /> | [[File:2nd_boss.PNG|75px]]<br /> | ||
− | This boss works in essentially the same way as the first one, but with a few different parameters. The ball speed is always 1 pixel/frame (instruction $C95D). | + | This boss works in essentially the same way as the first one, but with a few different parameters. The ball speed is always 1 pixel/frame (instruction $C95D). When the shot flag is not set, the boss will kick a ball based on a check every 16 frames (based on the global timer in $3BB) with a 50% chance (instruction $C93C).<br /> |
===3rd boss (Level 3-4)=== | ===3rd boss (Level 3-4)=== | ||
Line 100: | Line 121: | ||
===Delia's art pieces=== | ===Delia's art pieces=== | ||
[[File:Art_piece1.PNG]] [[File:Art_piece2.PNG]] [[File:Art_piece3.PNG]]<br /> | [[File:Art_piece1.PNG]] [[File:Art_piece2.PNG]] [[File:Art_piece3.PNG]]<br /> | ||
− | The following description refers to the art pieces' x-position, the y-position works in an | + | * $59A+X – Health (starting at 2 for the art pieces in room 0xD and 4 in 0xF) |
+ | <br /> | ||
+ | |||
+ | The following description refers to the art pieces' x-position, the y-position works in an analog way. The description is applicable to both the objects in room 0xD and 0xF (from $55).<br /><br /> | ||
Every 16th frame, the RNG function is called and through various calculations updates [$5CA+X]. This address has double purposes. First it determines a base movement of the object for the next 16 frames. This base movement is either move left or stand still. Then through logical manipulations, it adds a number to [$5D0+X] every frame (always the same number during the 16 frames). The new x-position (5AC+X) is then calculated by taking ”move left or standstill” plus if there was a carry in the calculation of the new [$5D0+X].<br /><br /> | Every 16th frame, the RNG function is called and through various calculations updates [$5CA+X]. This address has double purposes. First it determines a base movement of the object for the next 16 frames. This base movement is either move left or stand still. Then through logical manipulations, it adds a number to [$5D0+X] every frame (always the same number during the 16 frames). The new x-position (5AC+X) is then calculated by taking ”move left or standstill” plus if there was a carry in the calculation of the new [$5D0+X].<br /><br /> | ||
Line 106: | Line 130: | ||
Several steps have been skipped in the description above, but the end result and conclusion are that the game achieves something similar to a sub-pixel movement. During 16 frames, the art piece will move 0 or 1 pixel every frame, depending on how often the carry is produced in the calculation of [$5D0+X].<br /><br /> | Several steps have been skipped in the description above, but the end result and conclusion are that the game achieves something similar to a sub-pixel movement. During 16 frames, the art piece will move 0 or 1 pixel every frame, depending on how often the carry is produced in the calculation of [$5D0+X].<br /><br /> | ||
− | With the art pieces' movement at the core relying on RNG, it's difficult to see how any manipulation would be possible.<br /> | + | With the art pieces' movement at the core relying on RNG, it's difficult to see how any real-time manipulation would be possible.<br /> |
===Beetles (side view levels)=== | ===Beetles (side view levels)=== | ||
[[File:Beetle_(side_view_levels).PNG]]<br /> | [[File:Beetle_(side_view_levels).PNG]]<br /> | ||
− | * $ | + | * $414+X/$411+X - Big/Small x-position |
+ | * $41D+X/$41A+X/$417+X - Big/Small/Sub y-position | ||
+ | * $426+X/$423+X/$420+X - Big/Small/Sub y-speed | ||
+ | * $429+X - Movement state (0x01 - idling, 0x02 - moving right, 0x42 - moving left) | ||
+ | * $42C+X - Sub y-acceleration | ||
* $42F+X - Beetle type (0 – 10, 1 – 25, 2 – 50, 3 – 75) | * $42F+X - Beetle type (0 – 10, 1 – 25, 2 – 50, 3 – 75) | ||
<br /> | <br /> | ||
Line 116: | Line 144: | ||
Every 4 frames, the RNG function is called and a result is compared with 0x32 (instruction $A835). If it's smaller, another check is done with a 1/4 chance of passing per active beetle hole on screen (instruction $A83F). A beetle will then spawn from the corresponding hole.<br /><br /> | Every 4 frames, the RNG function is called and a result is compared with 0x32 (instruction $A835). If it's smaller, another check is done with a 1/4 chance of passing per active beetle hole on screen (instruction $A83F). A beetle will then spawn from the corresponding hole.<br /><br /> | ||
− | The type of | + | The type of beetle is again determined by running the RNG function. The result is this time compared with 0x50 (instruction $A875). If it's smaller, a red beetle (worth 10 vouchers) will spawn. If it's greater, another check is done with equal probability of the remaining 3 types (instruction $A879).<br /><br /> |
− | In summary, as long as the three available beetle memory addresses aren't filled, the probability of one of the 3 more valuable types spawning per second and per hole is 15*(48/256)*(1/4)*(166/256) ~ 46%.<br /> | + | In summary, as long as the three available beetle memory addresses aren't filled, the probability of one of the 3 more valuable types spawning per second and per hole is 15*(48/256)*(1/4)*(166/256) ~ 46%.<br /><br /> |
+ | |||
+ | Once a beetle has spawned and is in idle state, it has a 1/16 chance to initiate a jump every frame. The x-speed is always +-1 pixel/frame, depending on the movement state (which is determined by RNG). The beetle types 0 and 1 will start with a small y-speed of 0xFE. The beetle types 2 and 3 will start with a small y-speed between 0xFE and 0xFA (random). The sub y-acceleration remains constant during a jump and the calculation is the same for all beetle types, 0x32+[random value between 0 and F]+[random carry].<br /> | ||
===Beetles (overhead levels)=== | ===Beetles (overhead levels)=== | ||
Line 126: | Line 156: | ||
* $610/$60F – Small/Sub x-speed | * $610/$60F – Small/Sub x-speed | ||
* $619/$616/$615 – Big/Small/Sub y-position | * $619/$616/$615 – Big/Small/Sub y-position | ||
− | * $617/$618 – Small/Sub | + | * $617/$618 – Small/Sub y-speed |
<br /> | <br /> | ||
Line 132: | Line 162: | ||
The speed is recalculated every second frame as the current speed and an addition based on a result from calling the RNG function (see e.g. Instruction $BD50). | The speed is recalculated every second frame as the current speed and an addition based on a result from calling the RNG function (see e.g. Instruction $BD50). | ||
+ | <br /> | ||
+ | |||
+ | ===Buzzsaw=== | ||
+ | [[File:Buzzsaw.PNG]]<br /> | ||
+ | * $7DD/$7E6+X – x/y-position | ||
+ | * $7F5/$7F8 – x/y-movement timer | ||
+ | <br /> | ||
+ | |||
+ | The buzzsaws move with 1 pixel/frame in the same direction until the movement timer has run out, after which it changes direction. The initial positions and movement patterns are read from look-up tables when the room loads, based on room parameters. Playing a room consistently will therefore result in predictable position(s) of the buzzsaw(s). | ||
<br /> | <br /> | ||
Line 141: | Line 180: | ||
* $5F2/$5F1 - Small/Sub y-speed of shots | * $5F2/$5F1 - Small/Sub y-speed of shots | ||
* $5F4 – Shoot timer | * $5F4 – Shoot timer | ||
+ | * $795 - Health | ||
+ | * $5F8 - Flag that is set after defeating the monster and unset once the screen has been centered around Beetlejuice again. | ||
<br /> | <br /> | ||
The shoot timer counts down from 0x3F. When it reaches 0, the current shot disappears and a new one appears. The speed (0-4 pixels/frame + sub-pixel speed) depends on Beetlejuice's position and the RNG. The x- and y-speeds are calculated independently. The monsters will always fire in the direction of Beetlejuice. However, when the main x-speed is 0, the sub x-speed can make the shots fly in the opposite direction from Beetlejuice. Those shots will therefore always be slow, while shots in Beetlejuice's direction can be faster.<br /><br /> | The shoot timer counts down from 0x3F. When it reaches 0, the current shot disappears and a new one appears. The speed (0-4 pixels/frame + sub-pixel speed) depends on Beetlejuice's position and the RNG. The x- and y-speeds are calculated independently. The monsters will always fire in the direction of Beetlejuice. However, when the main x-speed is 0, the sub x-speed can make the shots fly in the opposite direction from Beetlejuice. Those shots will therefore always be slow, while shots in Beetlejuice's direction can be faster.<br /><br /> | ||
− | A full disassembly of the direction of shots hasn't been done, but a preliminary investigation did not find any manipulation possibilities. | + | A full disassembly of the direction of shots hasn't been done, but a preliminary investigation did not find any manipulation possibilities.<br /><br /> |
+ | |||
+ | When the monster has been defeated, the game will try to center the screen around Beetlejuice (checks at instructions $911F and $9124, for the y- and x-directions, respectively). Until then, the game doesn't take player inputs, freezing Beetlejuice in place when on the ground. However, the speed is not reset, so if Beetlejuice is in the air when the last attack connects, he'll continue jumping. If the screen catches up and centers around Beetlejuice during this jump, the flag in $5F8 is unset and Beetlejuice will be able to continue without being frozen in place upon landing. The conditions for this to happen are fairly strict though and not trivial to set up even in a TAS, as it requires a correct combination of positioning (including sub-pixels) and speed. The time save is only counted in frames, but still mentioned here for its applications in TASes. | ||
<br /> | <br /> | ||
Line 154: | Line 197: | ||
<br /> | <br /> | ||
− | $463 runs in the background when entering the house (level 1). When a switch is flipped, the corresponding elevator will teleport to wherever in the cycle $463 is and starts to move from there.<br /> | + | $463 runs in the background when entering the house (level 1). When a switch is flipped, the corresponding elevator will teleport to wherever in the cycle $463 is and starts to move from there. A cloud cycle is 192 frames.<br /> |
==="Fish in cauldron"=== | ==="Fish in cauldron"=== | ||
Line 168: | Line 211: | ||
* $5AC/$5B2+X – x/y-position (relative to the window position) | * $5AC/$5B2+X – x/y-position (relative to the window position) | ||
* $5BE/$5C4+X – x/y-speed (relative to the window position) | * $5BE/$5C4+X – x/y-speed (relative to the window position) | ||
+ | * $59A+X - Health/Status (0xFF - alive; 0 - dead) | ||
+ | <br /> | ||
+ | |||
+ | The flies get a 1 pixel/frame speed change every 4 frames (instruction $A1CB and onwards). The speed is capped at 3 pixels/frame in both directions. The calculation is only based on the RNG. It's therefore difficult to see how their movement could be possible to manipulate in real-time. It's worth noting that the speed is relative to the window position. Unless Beetlejuice moves without the screen moving with him (so when he is near the edge of the room border), there is no point trying to dodge the flies since they will just be "dragged" along with the window. When Beetlejuice is hit, the flies will only follow the screen during the invincibility period, which can allow for free hits by aligning flies with the swatter. | ||
+ | The RNG is updated before each speed calculation, so each fly moves independently of the others.<br /><br /> | ||
+ | |||
+ | Flies can only be destroyed by the swatter or by colliding with Beetlejuice (the hammer or the potion scares don't touch them).<br /> | ||
+ | |||
+ | ===Flies/Frogs/Golden beetles/Octopus/Scorpions (side view)=== | ||
+ | [[File:Fly_side.PNG]] [[File:Frog.PNG]] [[File:Golden_beetle.PNG]] [[File:Octopus_side.PNG]] [[File:Scorpion.PNG]]<br /> | ||
+ | * $7A0/$7AC+X - x/y-position | ||
+ | * $7C0+X - movement timer x | ||
+ | * $7BC+X - "y status" (shows the frogs' jump status | ||
<br /> | <br /> | ||
− | + | These enemies are activated by the screen having scrolled sufficiently close to them (Beetlejuice's position doesn't matter). They always spawn in the same locations and move predictably, according to their timers. | |
− | + | ||
===Flowers=== | ===Flowers=== | ||
[[File:Flower.PNG|50px]]<br /> | [[File:Flower.PNG|50px]]<br /> | ||
− | Not yet fully understood | + | Not yet fully understood. The addresses $6B-$6F appear to be linked to the flower cycle, but the exact relationship has not been described.<br /><br /> |
Purely based on empirical observations, the flowers seem to bloom roughly every 8-9s and each blooming lasts for around 2s on average. It can be worth mentioning that if the RNG addresses are frozen, the flowers will bloom every 256 frames.<br /> | Purely based on empirical observations, the flowers seem to bloom roughly every 8-9s and each blooming lasts for around 2s on average. It can be worth mentioning that if the RNG addresses are frozen, the flowers will bloom every 256 frames.<br /> | ||
Line 181: | Line 236: | ||
===Footballer's legs=== | ===Footballer's legs=== | ||
[[File:Legs.PNG]]<br /> | [[File:Legs.PNG]]<br /> | ||
− | Same mechanics as the [[Beetlejuice_(NES)/Game_Mechanics_and_Techniques#Sweepers|sweepers]], but with 4 (iso 2) consecutive direction changes towards the player every 64 frames. As a result, any random movement changes are more likely to be cancelled and replaced by movements homing in on Beetlejuice. | + | Same mechanics as the [[Beetlejuice_(NES)/Game_Mechanics_and_Techniques#Sweepers|sweepers]], but with 4 (iso 2) consecutive direction changes towards the player every 64 frames. As a result, any random movement changes are more likely to be cancelled and replaced by movements homing in on Beetlejuice. The legs therefore tend to follow Beetlejuice more closely around than the sweepers do. |
<br /> | <br /> | ||
===Lights=== | ===Lights=== | ||
[[File:Light.PNG|25px]]<br /> | [[File:Light.PNG|25px]]<br /> | ||
− | $62B increases by one every 2 or 4 frames (not fully understood what determines the delay). Every 4 increases of $62B, $628 | + | $62B increases by one every 2 or 4 frames (not fully understood what determines the delay). Every 4 increases of $62B, a bit is set in $628 (0->1->3->7->0xF) and one of the lights is lit. When all lights are lit, the bits are instead unset, one at a time (0xE->0xC->8->0). The lower leftmost light is lit when the first bit of $628 is set and is unlit when the first bit is unset. The other lights are shifted by one and two (lower middle and right) and three (the upper light) bits, respectively, in the cycle. |
<br /> | <br /> | ||
===Mouse=== | ===Mouse=== | ||
+ | [[File:Mouse.PNG]]<br /> | ||
+ | * $62D/$63B - x/y-position | ||
+ | * $673 - Movement direction (x or y) | ||
+ | <br /> | ||
+ | |||
+ | The mouse always starts in the same position in the right side of room 0x18 (see $55) and always starts moving up when entering the room. A new movement direction is then calculated (or keeping the current) every time the global timer in $3BB is divisible by 32. If the mouse hits a wall, it will continue in the opposite direction until the next direction calculation is due. Input to the calculation of a new direction comes directly from the RNG-addresses in $24-$27, meaning real-time manipulation is not possible.<br /><br /> | ||
+ | |||
+ | The best (/fastest) scenario occurs when the mouse enters the narrow corridor and moves towards the left room. Given the fairly stiff mechanics of the mouse movements, this is not always immediately possible. A more detailed description of how the mouse can enter the narrow corridor can be found in https://tasvideos.org/6440S. | ||
+ | <br /> | ||
===Octopus=== | ===Octopus=== | ||
[[File:Octopus.PNG|75px]]<br /> | [[File:Octopus.PNG|75px]]<br /> | ||
− | When Beetlejuice has a scare equipped, he can with a 50% chance jump through an octopus without dying by using the invincibility frames. The invincibility ($1AD) decreases every 4 frames, depending on the global timer ($3BB). | + | When Beetlejuice has a scare equipped, he can with a 50% chance jump through an octopus without dying by using the invincibility frames. The invincibility ($1AD) decreases every 4 frames, depending on the global timer ($3BB), while the game checks for Beetlejuice getting hit every second frame. |
− | * If the first decrease of the invincibility timer is after 2 frames, | + | * If Beetlejuice is hit so the first decrease of the invincibility timer is after 2 frames, he will take damage from the octopus and die before jumping out of its hitbox. |
− | * If | + | * If the first decrease is after 4 frames, Beetlejuice will be outside the octopus's hitbox before the invincibility wears off. |
− | Since there is no indication of value of the global timer, it's in practice random | + | Since there is no indication of the value of the global timer, it's in practice random if Beetlejuice can jump through the octopus or not in a real-time attempt. |
+ | <br /> | ||
+ | |||
+ | ===Potions=== | ||
+ | [[File:Potion.PNG]] [[File:Potion_scare.PNG|47px]]<br /> | ||
+ | * $585/$588 - x/y.position | ||
+ | * $58D - Potion timer – starts at 0x14 and decreases when the operation AND(global timer in $3BB, 0xF) results in 0 | ||
+ | * $58E – Movement direction (1 - NE; 3 - SE; 5 - SW; 7 - NW) | ||
+ | <br /> | ||
+ | |||
+ | The initial movement direction when throwing a potion is determined entirely by the RNG, with equal probability of the four possible movement directions. Once the initial direction has been calculated, the potion will continue in that direction until hitting an obstacle. It will then bounce according to ”everyday logic/physics”. A part from the initialization, the rest of the trajectory is therefore deterministic. By throwing potions in locations where the 4 possible trajectories have been tested beforehand, one can therefore to some extent control the movements of the potion. | ||
<br /> | <br /> | ||
Line 205: | Line 279: | ||
===Spiders=== | ===Spiders=== | ||
+ | [[File:Spider.PNG]]<br /> | ||
+ | * $7DF/$7DC/$7D9+X - Big/Small/Sub x-position | ||
+ | * $7E8/$7E5/$7E2+X - Big/Small/Sub y-position | ||
+ | * $7EB+X - Determines movement direction and speed | ||
+ | <br /> | ||
+ | |||
+ | The game calls the RNG-function every second frame to first do a 4/32 check (instruction $8E57) and then selects a number in the range 0-3 based on the global timer in $3BB. If the result is 0-2 (instruction $8E61) and the corresponding object index is not already occupied (instruction $8E67), a spider spawns.<br /><br /> | ||
+ | |||
+ | The spider's initial x- and y-positions are found through look-up tables, while the address for movement direction and speed is calculated based on the RNG-addresses and the global timer ($3BB). | ||
+ | <br /> | ||
+ | |||
===Sweepers=== | ===Sweepers=== | ||
+ | [[File:Sweeper.PNG|50px]]<br /> | ||
+ | * $5BE/$5AC+X – Big/Small x-position | ||
+ | * $5C4/$5B2+X – Big/Small y-position | ||
+ | * $5D0+X – Movement direction, x | ||
+ | * $5D6+X – Movement direction, y | ||
+ | * $59A+X – Health (starting at 3) | ||
+ | <br /> | ||
− | ==="Urn with bouncing | + | The RNG-function is called every 4 frames for a 1/32 probability of a random movement direction change (instruction $9CC6).<br /><br /> |
+ | |||
+ | There is also a check every 8th frame which only depends on the global timer ($3BB) and the object index of the sweeper (instruction $9C5F). When this comparison branches, a new direction is calculated towards the player. Skipping the code details, the end result is that each sweeper gets two consecutive (8 frames apart) direction changes every 64 frames and they will be in the direction of the player.<br /><br /> | ||
+ | |||
+ | When Beetlejuice has been hit and the invincibility timer ($1AD) runs, the sweepers' movements are inversed.<br /><br /> | ||
+ | |||
+ | The object index dependence and the random direction changes (calculated independently for each sweeper) ensure they move independently of each other.<br /><br /> | ||
+ | |||
+ | The sweepers can only be damaged by potion scares (they don't interact with the hammer or the swatter). | ||
+ | |||
+ | ==="Urn with bouncing smiley"=== | ||
+ | [[File:Urn_and_smiley.PNG|35px]]<br /> | ||
+ | * $5F9/$5F8 – Small/Sub y-position of smiley | ||
+ | * $5FC/$5FB – Small/Sub y-speed of smiley | ||
+ | |||
+ | The smiley starts moving when entering the house and then follows a set pattern. However, when it falls back into the urn, it will only bounce back out wih a 1/8 chance every frame, based on a check of the RNG-function (instruction $A36F). The position is therefore largely random when reaching the top of the house. A statistical analysis could probably reveal positions that are more likely, depending on in which platform cycle Beetlejuice has reached the top of the house, but this has not been attempted. | ||
+ | <br /><br /> | ||
==Buffered inputs== | ==Buffered inputs== | ||
+ | Below are examples of situations where buffered inputs can be used: | ||
+ | * Hold up to enter a door while jumping | ||
+ | * Hold A to buffer a jump after getting hit (useful to e.g. damage boost past an octopus) | ||
+ | * Hold A/start to buffer a jump/open the menu after a death. There are some deaths where this doesn't work. For example when riding the raft in the storm drains. | ||
+ | * Hold any button when the screen turns black before the map screen to click it away on the first possible frame | ||
+ | * Hold A (and up/down) while opening the inventory to select a scare | ||
+ | * Three inputs can be buffered at once when entering a shop. Hold select (+ left/right) + down while to buy an item (, to the left/right of the default position) and exit the shop on the first possible frame. | ||
+ | * Hold any button during the "skeleton" death animation to respawn on the first possible frame (the same does not work falling into a pit). Note that this works in both the side view as well as the overhead levels. | ||
+ | <br /> | ||
==Glitches== | ==Glitches== | ||
===Screen warping in the overhead levels (TAS-only)=== | ===Screen warping in the overhead levels (TAS-only)=== | ||
+ | By simultaneously pressing all directions on the same frame when in the overhead levels, Beetlejuice is teleported one screen to the right (256 pixels). This allows for bypassing some of the triggers in the game for significant time saves. Since it involves illegal inputs, it's only used in TASes though. | ||
+ | |||
===Softlocks=== | ===Softlocks=== | ||
* The second door in room 0x15 (see $55) did not open, despite having destroyed all art pieces (reported by 'ktwo' on console, no recording available) | * The second door in room 0x15 (see $55) did not open, despite having destroyed all art pieces (reported by 'ktwo' on console, no recording available) | ||
<br /> | <br /> | ||
− | ==Additional game mechanics== | + | ==Additional game mechanics and tricks== |
+ | ==="Platform attraction"=== | ||
+ | With a precise jump to a platform from below, Beetlejuice can be "sucked" up to the platform, gaining 6-7 pixels for free. Since time is spent scrolling the screen in these sections, getting the "platform attaction" saves time. However, it's a small time gain for a relatively precise trick, so it should be considered an advanced technique. But if done consistently, it can impact the pattern in which platforms are jumped to. It's then better to make many small jumps instead of one big. | ||
+ | |||
===Free scare at the cavern monsters=== | ===Free scare at the cavern monsters=== | ||
If Beetlejuice doesn't have any scares when the screen is locked around a cavern monster, an umbrella head scare will spawn to the right of it within 64 frames (check done at instruction $9A9C), based on the global counter ($3BB). This is likely to avoid soft-locking the game since the game locks the screen around the monster and it's not possible to escape the fight. | If Beetlejuice doesn't have any scares when the screen is locked around a cavern monster, an umbrella head scare will spawn to the right of it within 64 frames (check done at instruction $9A9C), based on the global counter ($3BB). This is likely to avoid soft-locking the game since the game locks the screen around the monster and it's not possible to escape the fight. | ||
+ | |||
+ | ===Flaw in the flies' hit detection (overhead sections)=== | ||
+ | The sub-routine for checking if a fly is hit by the swatter does not check for the big value of the y-positions. This can be used in room 0x1A (see $55) by letting the swatter bounce off-screen and still keep decimating the number of flies. This trick was presumably found by 'Bassguy'. Various tests have been done on other objects, but this has not (yet) revealed similar flaws in the code. | ||
+ | |||
+ | ===Quest dialog skips (overhead sections)=== | ||
+ | By dropping the quest item just in front of the character blocking the path, they will move without triggering a dialog. There is a 6-pixel window when delivering the quest item horizontally for this to work and a 20-pixel window when delivering vertically. | ||
===Open locked doors without killing all enemies=== | ===Open locked doors without killing all enemies=== | ||
Line 236: | Line 364: | ||
<br /> | <br /> | ||
− | === | + | ===Timing of flowers=== |
− | + | A full description of how the timing of [[Beetlejuice_(NES)/Game_Mechanics_and_Techniques#Flowers|flowers]] works is still missing. | |
+ | <br /> | ||
+ | |||
+ | ===Timing of lights=== | ||
+ | A full description of how the timing of [[Beetlejuice_(NES)/Game_Mechanics_and_Techniques#Lights|lights]] works is still missing. | ||
+ | <br /> | ||
+ | |||
+ | ===Are there any more scares with special abilities?=== | ||
+ | Three of the scares don't appear to give Beetlejuice any special abilities. Intentional or could there be secret abilities yet to be discovered? The descriptions in the game manual could be read as hints about special abilities for at least one of them (the umbrella scare). | ||
<br /><br /> | <br /><br /> | ||
==Selection of known RAM-addresses== | ==Selection of known RAM-addresses== | ||
+ | More addresses for objects and enemies are listed under the respective sections above | ||
+ | * 24-27 - RNG-addresses | ||
+ | * 28 - Controller input/buttons held down | ||
+ | * 29 - New buttons pressed this frame (value then added to $28, before $29 is reset) | ||
+ | * 2D/2C - Big/Small x-position, window | ||
+ | * 2F/2E - Big/Small y-position, window | ||
+ | * 55 - Room number | ||
+ | * 85 - Tickets collected in the Afterlife level (the six rightmost bits correspond to the six different tickets - the value is 0x3F when all tickets have been collected) | ||
+ | * 1AA - Health, Beetlejuice (BJ) | ||
+ | * 1AD - Invincibility timer, BJ | ||
+ | * 1FE - Potions | ||
+ | * 3BB - Global timer | ||
+ | * 3D2/3D1 - Big/Small vouchers | ||
+ | * 3D3 - Lives remaining | ||
+ | * 3D4-3DB - Medusa head/Birdman/Two-headed man/Skeleton/Umbrella man/Ogre/Ghost/Snakeman scares | ||
+ | * 581 - Remaining scare attacks | ||
+ | * 649+X - Quest items in the current room | ||
+ | * 656+X - Quest items in the inventory (1 - Hammer; 2 - Book; 3 - Spray can; 4 - Paper roll; 5 - Ring; 6 - Rubber duck; 7 - Swatter; 8 - Fire extinguisher; 9 - Glasses; 0xA - Brick; 0xB - Mouse) | ||
+ | * 65E - Number of quest items in the inventory (used as an offset to $656 to keep track of which address contains the latest collected item) |
Latest revision as of 15:05, 8 May 2023
Contents
- 1 Animations
- 2 Scares
- 3 RNG
- 4 Enemies and objects
- 4.1 1st boss (Level 1)
- 4.2 2nd boss (Level 2)
- 4.3 3rd boss (Level 3-4)
- 4.4 Delia's art pieces
- 4.5 Beetles (side view levels)
- 4.6 Beetles (overhead levels)
- 4.7 Buzzsaw
- 4.8 Cavern monsters
- 4.9 Cloud elevators
- 4.10 "Fish in cauldron"
- 4.11 Flies (overhead sections)
- 4.12 Flies/Frogs/Golden beetles/Octopus/Scorpions (side view)
- 4.13 Flowers
- 4.14 Footballer's legs
- 4.15 Lights
- 4.16 Mouse
- 4.17 Octopus
- 4.18 Potions
- 4.19 Shops
- 4.20 Spiders
- 4.21 Sweepers
- 4.22 "Urn with bouncing smiley"
- 5 Buffered inputs
- 6 Glitches
- 7 Additional game mechanics and tricks
- 8 Open questions
- 9 Selection of known RAM-addresses
Animations
Movement mechanics
- 3BF/3BE/3BD - Big/Small/Sub x-position
- 3C4/3C3 - Small/Sub x-speed
- 3C2/3C1/3C0 - Big/Small/Sub y-position
- 3C7/3C6 - Small/Sub y-speed
Beetlejuice accelerates in the x-direction with 32 sub-pixels/frame^2 up to a speed of 2 pixels/frame. The acceleration is the same on the ground as in the air. However, jumping has a wind-up frame, so it's slightly slower to jump when accelerating. Letting go of the direction button will make him stop immediately when on the ground, while momentum is kept (no brake effect) when jumping. "Braking" in the air decelerates Beetlejuice with 64 sub-pixels/frame^2.
Time cost comparisons
- A continue screen costs from 45 frames and upwards, depending on how quickly it's clicked away, on top of the other costs associated with a death.
Side view levels
- A knockback costs 54 frames
- Falling into a pit from roughly half the screen's height costs ~140 frames. 30-40 of those are from the fall itself, the rest from re-spawning. On top of that, 8 frames more will be lost from having to accelerate from 0 when re-spawning.
- Losing the last health from taking a hit in the same position as above and triggering the "skeleton" death animation costs ~20 frames more
- Entering a shop and purchase one item costs 3.4s
- A menu trip and selecting the highlighted or an adjacent scare is 1.1s
Overhead levels
- A death from mid-screen costs ~120 frames
Scares
RNG
The RNG-addresses in RAM are $24-$27. There are three different algorithms that are used to update their values.
- Starting at $99A8, various logical operations on and between the RNG-addresses are done, with the previous set of RNG and the global timer ($3BB) as seeds.
- Starting at $DFA5, a similar algorithm to the first.
- Starting at $909A, only two of the RNG-values are updated. This is done based on Beetlejuice's x- and y-position (influencing $24 and $25, respectively).
The first two algorithms are used throughout the game with what appears to be a room-dependent frequency (usually every 2-8 frames), with additional calls if there are RNG-dependent enemies present. The sub-routine for the third algorithm is only used in the side-scrolling levels and only called every 256 frames. Room 0x09 (the very first overhead room in the game) is special in the sense that the RNG is never updated in this room.
There is no indication that the RNG-values would be possible to manipulate in real-time. In TAS-conditions, the RNG is fairly "stiff" and can only be manipulated to a certain extent (unless introducing waiting frames is considered). In the side-view levels, it's done by changing Beetlejuice's position before '3' is called. In the overhead levels, it's mainly done by throwing a potion at different times or in some cases defeating enemies on different frames. In the room with Delia (0x19), picking up the mouse and scaring off Delia on different frames can also be used to influence the RNG. These methods have in common that they influence the number of calls to the RNG sub-routine.
Enemies and objects
1st boss (Level 1)
- $5E9/$5E8 - Small/Sub x-position of shots
- $5EC/$5EB - Small/Sub x-speed of shots
- $535/$536 - x/y boss
- $5E7 – Shot flag
When the shot flag is not set, the RNG function is called every 16 frames, based on the global timer ($3BB). One of the results is compared with 0x46 (instruction $C8F9). If it's less, the boss will shoot a puff of spray. Since the player neither knows the global timer, nor the RNG values, shots can be considered random and outside player control with a probability of (1/16)*(70/256) ~ 1/59 per frame. The fastest method to defeat the boss is to run straight at him and fire off three quick shots. This way, a typical fight takes ~80 frames, which will allow 5 or 6 opportunities for the boss to fire. The success rate will therefore be between (186/256)^6 ~15% and (186/256)^5 ~20%. A slightly more consistent method is to introduce a jump after the first scare attack, regardless of if the boss has actually fired or not. The fight will then typically take ~100 frames. It's not as straight-forward to calculate the success rate in this case and has not been attempted, but it's noticeably more consistent.
The speed of the puff is either 1 or 2 pixels/frame and with a sub-speed that is a multiple of 0x40 (a sub-speed >0 slows down the puffs). Both the main and sub speeds directly depend on $24 (the first RNG-address) and should therefore be equally distributed with no possibility to predict in real-time.
2nd boss (Level 2)
This boss works in essentially the same way as the first one, but with a few different parameters. The ball speed is always 1 pixel/frame (instruction $C95D). When the shot flag is not set, the boss will kick a ball based on a check every 16 frames (based on the global timer in $3BB) with a 50% chance (instruction $C93C).
3rd boss (Level 3-4)
- $537 - Magic timer
If the boss isn't already casting magic, the game calls the RNG function every second frame. The check that follows has a 5/256 ~ 1/51 chance to pass (instruction $C85A), resulting in the boss casting magic. The duration of the spell is always 22 or 24 frames.
Delia's art pieces
- $59A+X – Health (starting at 2 for the art pieces in room 0xD and 4 in 0xF)
The following description refers to the art pieces' x-position, the y-position works in an analog way. The description is applicable to both the objects in room 0xD and 0xF (from $55).
Every 16th frame, the RNG function is called and through various calculations updates [$5CA+X]. This address has double purposes. First it determines a base movement of the object for the next 16 frames. This base movement is either move left or stand still. Then through logical manipulations, it adds a number to [$5D0+X] every frame (always the same number during the 16 frames). The new x-position (5AC+X) is then calculated by taking ”move left or standstill” plus if there was a carry in the calculation of the new [$5D0+X].
Several steps have been skipped in the description above, but the end result and conclusion are that the game achieves something similar to a sub-pixel movement. During 16 frames, the art piece will move 0 or 1 pixel every frame, depending on how often the carry is produced in the calculation of [$5D0+X].
With the art pieces' movement at the core relying on RNG, it's difficult to see how any real-time manipulation would be possible.
Beetles (side view levels)
- $414+X/$411+X - Big/Small x-position
- $41D+X/$41A+X/$417+X - Big/Small/Sub y-position
- $426+X/$423+X/$420+X - Big/Small/Sub y-speed
- $429+X - Movement state (0x01 - idling, 0x02 - moving right, 0x42 - moving left)
- $42C+X - Sub y-acceleration
- $42F+X - Beetle type (0 – 10, 1 – 25, 2 – 50, 3 – 75)
Every 4 frames, the RNG function is called and a result is compared with 0x32 (instruction $A835). If it's smaller, another check is done with a 1/4 chance of passing per active beetle hole on screen (instruction $A83F). A beetle will then spawn from the corresponding hole.
The type of beetle is again determined by running the RNG function. The result is this time compared with 0x50 (instruction $A875). If it's smaller, a red beetle (worth 10 vouchers) will spawn. If it's greater, another check is done with equal probability of the remaining 3 types (instruction $A879).
In summary, as long as the three available beetle memory addresses aren't filled, the probability of one of the 3 more valuable types spawning per second and per hole is 15*(48/256)*(1/4)*(166/256) ~ 46%.
Once a beetle has spawned and is in idle state, it has a 1/16 chance to initiate a jump every frame. The x-speed is always +-1 pixel/frame, depending on the movement state (which is determined by RNG). The beetle types 0 and 1 will start with a small y-speed of 0xFE. The beetle types 2 and 3 will start with a small y-speed between 0xFE and 0xFA (random). The sub y-acceleration remains constant during a jump and the calculation is the same for all beetle types, 0x32+[random value between 0 and F]+[random carry].
Beetles (overhead levels)
- $60C – Beetle flag
- $611/$60E/$60D – Big/Small/Sub x-position
- $610/$60F – Small/Sub x-speed
- $619/$616/$615 – Big/Small/Sub y-position
- $617/$618 – Small/Sub y-speed
There is a 75% chance that an enemy drops a beetle (instruction $9E8C, when enemy health goes to 0). Same for all enemy types. There can however only be one beetle at a time (controlled by the beetle flag).
The speed is recalculated every second frame as the current speed and an addition based on a result from calling the RNG function (see e.g. Instruction $BD50).
Buzzsaw
- $7DD/$7E6+X – x/y-position
- $7F5/$7F8 – x/y-movement timer
The buzzsaws move with 1 pixel/frame in the same direction until the movement timer has run out, after which it changes direction. The initial positions and movement patterns are read from look-up tables when the room loads, based on room parameters. Playing a room consistently will therefore result in predictable position(s) of the buzzsaw(s).
Cavern monsters
- $5E9/$5E8 - Small/Sub x-position of shots
- $5EC/$5EB - Small/Sub x-speed of shots
- $5EF/$5EE - Small/Sub y-position of shots
- $5F2/$5F1 - Small/Sub y-speed of shots
- $5F4 – Shoot timer
- $795 - Health
- $5F8 - Flag that is set after defeating the monster and unset once the screen has been centered around Beetlejuice again.
The shoot timer counts down from 0x3F. When it reaches 0, the current shot disappears and a new one appears. The speed (0-4 pixels/frame + sub-pixel speed) depends on Beetlejuice's position and the RNG. The x- and y-speeds are calculated independently. The monsters will always fire in the direction of Beetlejuice. However, when the main x-speed is 0, the sub x-speed can make the shots fly in the opposite direction from Beetlejuice. Those shots will therefore always be slow, while shots in Beetlejuice's direction can be faster.
A full disassembly of the direction of shots hasn't been done, but a preliminary investigation did not find any manipulation possibilities.
When the monster has been defeated, the game will try to center the screen around Beetlejuice (checks at instructions $911F and $9124, for the y- and x-directions, respectively). Until then, the game doesn't take player inputs, freezing Beetlejuice in place when on the ground. However, the speed is not reset, so if Beetlejuice is in the air when the last attack connects, he'll continue jumping. If the screen catches up and centers around Beetlejuice during this jump, the flag in $5F8 is unset and Beetlejuice will be able to continue without being frozen in place upon landing. The conditions for this to happen are fairly strict though and not trivial to set up even in a TAS, as it requires a correct combination of positioning (including sub-pixels) and speed. The time save is only counted in frames, but still mentioned here for its applications in TASes.
Cloud elevators
- $463 - Elevator counter
- $5D - y-position of the elevator currently on screen, an offset of $463
$463 runs in the background when entering the house (level 1). When a switch is flipped, the corresponding elevator will teleport to wherever in the cycle $463 is and starts to move from there. A cloud cycle is 192 frames.
"Fish in cauldron"
- $5B2+X - y-position
- $5A6+X - y-speed
Every 16 frames, the game calls the RNG function and calculates a number between 0 and 7. If the number is in the range 0-4 (instruction $AC82) and the corresponding fish is in its cauldron (instruction $AC85), it will initiate a jump of that fish with a set trajectory.
Flies (overhead sections)
- $5AC/$5B2+X – x/y-position (relative to the window position)
- $5BE/$5C4+X – x/y-speed (relative to the window position)
- $59A+X - Health/Status (0xFF - alive; 0 - dead)
The flies get a 1 pixel/frame speed change every 4 frames (instruction $A1CB and onwards). The speed is capped at 3 pixels/frame in both directions. The calculation is only based on the RNG. It's therefore difficult to see how their movement could be possible to manipulate in real-time. It's worth noting that the speed is relative to the window position. Unless Beetlejuice moves without the screen moving with him (so when he is near the edge of the room border), there is no point trying to dodge the flies since they will just be "dragged" along with the window. When Beetlejuice is hit, the flies will only follow the screen during the invincibility period, which can allow for free hits by aligning flies with the swatter.
The RNG is updated before each speed calculation, so each fly moves independently of the others.
Flies can only be destroyed by the swatter or by colliding with Beetlejuice (the hammer or the potion scares don't touch them).
Flies/Frogs/Golden beetles/Octopus/Scorpions (side view)
- $7A0/$7AC+X - x/y-position
- $7C0+X - movement timer x
- $7BC+X - "y status" (shows the frogs' jump status
These enemies are activated by the screen having scrolled sufficiently close to them (Beetlejuice's position doesn't matter). They always spawn in the same locations and move predictably, according to their timers.
Flowers
Not yet fully understood. The addresses $6B-$6F appear to be linked to the flower cycle, but the exact relationship has not been described.
Purely based on empirical observations, the flowers seem to bloom roughly every 8-9s and each blooming lasts for around 2s on average. It can be worth mentioning that if the RNG addresses are frozen, the flowers will bloom every 256 frames.
Footballer's legs
Same mechanics as the sweepers, but with 4 (iso 2) consecutive direction changes towards the player every 64 frames. As a result, any random movement changes are more likely to be cancelled and replaced by movements homing in on Beetlejuice. The legs therefore tend to follow Beetlejuice more closely around than the sweepers do.
Lights
$62B increases by one every 2 or 4 frames (not fully understood what determines the delay). Every 4 increases of $62B, a bit is set in $628 (0->1->3->7->0xF) and one of the lights is lit. When all lights are lit, the bits are instead unset, one at a time (0xE->0xC->8->0). The lower leftmost light is lit when the first bit of $628 is set and is unlit when the first bit is unset. The other lights are shifted by one and two (lower middle and right) and three (the upper light) bits, respectively, in the cycle.
Mouse
- $62D/$63B - x/y-position
- $673 - Movement direction (x or y)
The mouse always starts in the same position in the right side of room 0x18 (see $55) and always starts moving up when entering the room. A new movement direction is then calculated (or keeping the current) every time the global timer in $3BB is divisible by 32. If the mouse hits a wall, it will continue in the opposite direction until the next direction calculation is due. Input to the calculation of a new direction comes directly from the RNG-addresses in $24-$27, meaning real-time manipulation is not possible.
The best (/fastest) scenario occurs when the mouse enters the narrow corridor and moves towards the left room. Given the fairly stiff mechanics of the mouse movements, this is not always immediately possible. A more detailed description of how the mouse can enter the narrow corridor can be found in https://tasvideos.org/6440S.
Octopus
When Beetlejuice has a scare equipped, he can with a 50% chance jump through an octopus without dying by using the invincibility frames. The invincibility ($1AD) decreases every 4 frames, depending on the global timer ($3BB), while the game checks for Beetlejuice getting hit every second frame.
- If Beetlejuice is hit so the first decrease of the invincibility timer is after 2 frames, he will take damage from the octopus and die before jumping out of its hitbox.
- If the first decrease is after 4 frames, Beetlejuice will be outside the octopus's hitbox before the invincibility wears off.
Since there is no indication of the value of the global timer, it's in practice random if Beetlejuice can jump through the octopus or not in a real-time attempt.
Potions
- $585/$588 - x/y.position
- $58D - Potion timer – starts at 0x14 and decreases when the operation AND(global timer in $3BB, 0xF) results in 0
- $58E – Movement direction (1 - NE; 3 - SE; 5 - SW; 7 - NW)
The initial movement direction when throwing a potion is determined entirely by the RNG, with equal probability of the four possible movement directions. Once the initial direction has been calculated, the potion will continue in that direction until hitting an obstacle. It will then bounce according to ”everyday logic/physics”. A part from the initialization, the rest of the trajectory is therefore deterministic. By throwing potions in locations where the 4 possible trajectories have been tested beforehand, one can therefore to some extent control the movements of the potion.
Shops
Some shops have different sets of inventory. Which set is loaded depends on which x-pixel the shop is entered on. This is hard-coded and therefore possible to predict.
Spiders
- $7DF/$7DC/$7D9+X - Big/Small/Sub x-position
- $7E8/$7E5/$7E2+X - Big/Small/Sub y-position
- $7EB+X - Determines movement direction and speed
The game calls the RNG-function every second frame to first do a 4/32 check (instruction $8E57) and then selects a number in the range 0-3 based on the global timer in $3BB. If the result is 0-2 (instruction $8E61) and the corresponding object index is not already occupied (instruction $8E67), a spider spawns.
The spider's initial x- and y-positions are found through look-up tables, while the address for movement direction and speed is calculated based on the RNG-addresses and the global timer ($3BB).
Sweepers
- $5BE/$5AC+X – Big/Small x-position
- $5C4/$5B2+X – Big/Small y-position
- $5D0+X – Movement direction, x
- $5D6+X – Movement direction, y
- $59A+X – Health (starting at 3)
The RNG-function is called every 4 frames for a 1/32 probability of a random movement direction change (instruction $9CC6).
There is also a check every 8th frame which only depends on the global timer ($3BB) and the object index of the sweeper (instruction $9C5F). When this comparison branches, a new direction is calculated towards the player. Skipping the code details, the end result is that each sweeper gets two consecutive (8 frames apart) direction changes every 64 frames and they will be in the direction of the player.
When Beetlejuice has been hit and the invincibility timer ($1AD) runs, the sweepers' movements are inversed.
The object index dependence and the random direction changes (calculated independently for each sweeper) ensure they move independently of each other.
The sweepers can only be damaged by potion scares (they don't interact with the hammer or the swatter).
"Urn with bouncing smiley"
- $5F9/$5F8 – Small/Sub y-position of smiley
- $5FC/$5FB – Small/Sub y-speed of smiley
The smiley starts moving when entering the house and then follows a set pattern. However, when it falls back into the urn, it will only bounce back out wih a 1/8 chance every frame, based on a check of the RNG-function (instruction $A36F). The position is therefore largely random when reaching the top of the house. A statistical analysis could probably reveal positions that are more likely, depending on in which platform cycle Beetlejuice has reached the top of the house, but this has not been attempted.
Buffered inputs
Below are examples of situations where buffered inputs can be used:
- Hold up to enter a door while jumping
- Hold A to buffer a jump after getting hit (useful to e.g. damage boost past an octopus)
- Hold A/start to buffer a jump/open the menu after a death. There are some deaths where this doesn't work. For example when riding the raft in the storm drains.
- Hold any button when the screen turns black before the map screen to click it away on the first possible frame
- Hold A (and up/down) while opening the inventory to select a scare
- Three inputs can be buffered at once when entering a shop. Hold select (+ left/right) + down while to buy an item (, to the left/right of the default position) and exit the shop on the first possible frame.
- Hold any button during the "skeleton" death animation to respawn on the first possible frame (the same does not work falling into a pit). Note that this works in both the side view as well as the overhead levels.
Glitches
Screen warping in the overhead levels (TAS-only)
By simultaneously pressing all directions on the same frame when in the overhead levels, Beetlejuice is teleported one screen to the right (256 pixels). This allows for bypassing some of the triggers in the game for significant time saves. Since it involves illegal inputs, it's only used in TASes though.
Softlocks
- The second door in room 0x15 (see $55) did not open, despite having destroyed all art pieces (reported by 'ktwo' on console, no recording available)
Additional game mechanics and tricks
"Platform attraction"
With a precise jump to a platform from below, Beetlejuice can be "sucked" up to the platform, gaining 6-7 pixels for free. Since time is spent scrolling the screen in these sections, getting the "platform attaction" saves time. However, it's a small time gain for a relatively precise trick, so it should be considered an advanced technique. But if done consistently, it can impact the pattern in which platforms are jumped to. It's then better to make many small jumps instead of one big.
Free scare at the cavern monsters
If Beetlejuice doesn't have any scares when the screen is locked around a cavern monster, an umbrella head scare will spawn to the right of it within 64 frames (check done at instruction $9A9C), based on the global counter ($3BB). This is likely to avoid soft-locking the game since the game locks the screen around the monster and it's not possible to escape the fight.
Flaw in the flies' hit detection (overhead sections)
The sub-routine for checking if a fly is hit by the swatter does not check for the big value of the y-positions. This can be used in room 0x1A (see $55) by letting the swatter bounce off-screen and still keep decimating the number of flies. This trick was presumably found by 'Bassguy'. Various tests have been done on other objects, but this has not (yet) revealed similar flaws in the code.
Quest dialog skips (overhead sections)
By dropping the quest item just in front of the character blocking the path, they will move without triggering a dialog. There is a 6-pixel window when delivering the quest item horizontally for this to work and a 20-pixel window when delivering vertically.
Open locked doors without killing all enemies
Doors in the overhead levels that are unlocked by killing all sweepers in the room, will open after a set amount of time. The room timer in $675/$674 is reset upon entering a new room. When it has cycled 14 times ($675 = 0xE), the door will automatically unlock. This is likely to avoid soft-locking the game since the sweepers can only be damaged by potions, which are in limited supply.
This game mechanic is unlikely to find any use in a speedrun since it will be much slower than killing the sweepers in the rooms where this applies.
Open questions
Toilet paper
This item is found at the top of room 0xF (see $55). Upon collection, the game hints about some kind of secret use for it. However, there doesn't seem to be any claims on the internet of people having found any use for this item.
Brick
This item is found at the top of room 0x10 (see $55). Upon collection, the game hints about using it against the football players. There are footballer's legs in that room, but there doesn't appear to be any evidence of the brick actually doing anything to the legs.
Timing of flowers
A full description of how the timing of flowers works is still missing.
Timing of lights
A full description of how the timing of lights works is still missing.
Are there any more scares with special abilities?
Three of the scares don't appear to give Beetlejuice any special abilities. Intentional or could there be secret abilities yet to be discovered? The descriptions in the game manual could be read as hints about special abilities for at least one of them (the umbrella scare).
Selection of known RAM-addresses
More addresses for objects and enemies are listed under the respective sections above
- 24-27 - RNG-addresses
- 28 - Controller input/buttons held down
- 29 - New buttons pressed this frame (value then added to $28, before $29 is reset)
- 2D/2C - Big/Small x-position, window
- 2F/2E - Big/Small y-position, window
- 55 - Room number
- 85 - Tickets collected in the Afterlife level (the six rightmost bits correspond to the six different tickets - the value is 0x3F when all tickets have been collected)
- 1AA - Health, Beetlejuice (BJ)
- 1AD - Invincibility timer, BJ
- 1FE - Potions
- 3BB - Global timer
- 3D2/3D1 - Big/Small vouchers
- 3D3 - Lives remaining
- 3D4-3DB - Medusa head/Birdman/Two-headed man/Skeleton/Umbrella man/Ogre/Ghost/Snakeman scares
- 581 - Remaining scare attacks
- 649+X - Quest items in the current room
- 656+X - Quest items in the inventory (1 - Hammer; 2 - Book; 3 - Spray can; 4 - Paper roll; 5 - Ring; 6 - Rubber duck; 7 - Swatter; 8 - Fire extinguisher; 9 - Glasses; 0xA - Brick; 0xB - Mouse)
- 65E - Number of quest items in the inventory (used as an offset to $656 to keep track of which address contains the latest collected item)