Posts for RetroEdit


1 2
5 6
RetroEdit
Any
Editor, Experienced Forum User, Reviewer, Player (166)
Joined: 8/8/2019
Posts: 131
I recently remembered this game again, and I'm interested in TASing it. I'm particularly interested in routing out a 100% run, because the optimal route isn't entirely clear. Because you have to enter most early levels twice to take out the police men for that mission, comparisons will have to be made to determine whether collecting all the medals on the first time or second time around is faster (still, this is irrelevant for most levels, because some of the medals are usually ability-locked and could only be accessed in the second playthrough anyway). More broadly, routing the order of the medals will be interesting. I recently did a blind 100% playthrough and finished in a highly suboptimal 3 hours. I wonder how fast a TAS could go, since there are no recorded speedruns on SRC at least. This video finishes in just under 2 hours, but it's probably not anywhere close to optimal (I haven't watched it through). As for any%, an SRC board was made since 2015 and several runners have brought the time down. The current world record is 37m 32s, set more than two years ago. Edit: As of January 2024, there's a 100% completion time of 1:25:13 posted on the board.
RetroEdit
Any
Editor, Experienced Forum User, Reviewer, Player (166)
Joined: 8/8/2019
Posts: 131
Cool TAS! Very neat movement with the Diddy levels and floating between platforms like it was nothing. Also was nice to be able to listen to the commentary live. I also posted this on the YouTube encode's comments, but ThunderAxe31 suggested I posted it here.
RetroEdit
Any
Editor, Experienced Forum User, Reviewer, Player (166)
Joined: 8/8/2019
Posts: 131
Very nice! I thought my custom ROM idea was a bit hokey, and a LUA script or address freezing would definitely be more straightforward. I'll be curious to look at that address you froze to understand why it works. EDIT: you mentioned writing a LUA script would generally be an available option, and I guess I underestimate the power of LUA scripts. How could a LUA script affect something like sound effects playing if it can only indirectly observe the execution model through frame-by-frame memory snapshots? Is it just a general rule of thumb that loading something like a sound effect will leave some usfeul trace in memory somewhere along the line? Or I assume in this case you might have looped into the beep timer, or something similar?
RetroEdit
Any
Editor, Experienced Forum User, Reviewer, Player (166)
Joined: 8/8/2019
Posts: 131
g0goTBC wrote:
You guys asked it, you guys get it. In PiePusher's TAS, he takes a hit off of an enemy early on in his run, and it makes it so that you could hear the beeping sound of having low health for the majority of his run. People complained about it when his TAS got published, so I chose to not do that in my TAS, at the cost of losing half a second.
I have a solution for this tradeoff: make two encodings, one which is normal for accurate representation, and a separate encoding that uses a custom ROM where the beep sound doesn't play. To show this is possible, I encoded an alternative version of this movie where the beep noise is disabled (the beeping would have normally started at 15:41 in this particular movie): Link to video This is not unprecedented in my opinion: http://tasvideos.org/6314S.html added an alternative encoding for out-of-bounds display (though they used an overlay to accomplish the effect, and it served a pratical purpose for routing). As long there's an authentic version of the movie that people can watch if they're interested, I see no reason why an additional alternate version with minor tweaks shouldn't be acceptable. I also tested my custom ROM on PiePusher11's old TAS. Of course, I wouldn't rely on it for reliable re-recording when constructing a TAS, but I think it will be sufficient for alternate encodings so that optimal strats can be pursued without the viewer having to suffer through the beeping.
RetroEdit
Any
Editor, Experienced Forum User, Reviewer, Player (166)
Joined: 8/8/2019
Posts: 131
Fire Modern Introduction In Fire Modern, there are two ways to improve the speed: spawning characters well through RNG manipulation, and bouncing characters as early as possible to allow more characters to spawn. These are sometimes at odds. Eggs appear to give two points on their initial hatch bounce, regardless of whether they hatch as a Moon or Bob-omb, and Moons give 5 points on the two subsequent bounces, totaling to 12 points. Regular characters give only 1 points per bounce, so moons are basically four times as worthwhile as regular characters. Through reboot-based RNG manipulation, a moon can be spawned at any point where a character spawns, but the frame cost may be more expensive in some cases than simply allowing less favorable spawns to occur. I generally understand how the spawning working in Fire Modern. I still have yet to completely explore the physics (and lag, which can occur if there are multiple characters on the screen). Once I understand the physics enough to reliably predict where characters will be with precise timing, I will write some scripts to automate the process of TASing. I currently have a short luck-manipulation proof-of-concept movie, and a related watchfile. Spawn mechanics part I: when & who The Python-esque pseudocode below covers the basics of spawning. However, there is one component I will explain in more detail below: character-specific spawn chances (I previously referred to this as the characters' "spawn determinant".)
Language: python

TOAD = 0 YOSHI = 1 BABY_DK = 2 EGG = 3 MOON = 4 BOB_OMB = 5 # Called every frame def attempt_spawn(): # 49-frame timer spawn_timer += 1 if (spawn_timer == 49) or (num_characters == 0): spawn_timer = 0 if ( # 41/90 (45.55%) chance to spawn ((rand() % 90) <= 40) or \ (num_characters == 0) or \ (difficulty == 2) ) and (num_characters != max_characters): num_characters += 1 character = find_available_character_slot() character.type = TOAD character_type_chosen = False if random_spawn(yoshi_spawn_chance) or (yoshi_spawn_chance == 0xFF): character.type = YOSHI character_type_chosen = True if (random_spawn(baby_dk_spawn_chance) or (baby_dk_spawn_chance == 0xFF))) and (not character_type_chosen): character.type = BABY_DK character_type_chosen = True if (random_spawn(egg_spawn_chance) or (egg_spawn_chance == 0xFF)) and (not character_type_chosen): character.type = EGG # Sub-part of attempt_spawn above def random_spawn(spawn_chance): if rand() <= math.floor(spawn_chance * 2/3): return True else: return False def find_available_character_slot(): # TODO - not analyzed in depth pass # Called whenever an egg collides with the trampoline (the first bounce) def hatch_egg(character): # 31/64 (48.4%) chance to be a moon if ((rand() & 0x3F) > 0x20): character.type = MOON else: character.type = BOB_OMB
Basically, a character will spawn whenever there are 0 characters in play, or with a 41/90 (45.55%) when the 49-frame spawn timer runs out (assuming the number of characters isn't maxed out). When it's time to spawn a character, Toad is the default, and then three checks are made in succession to determine whether the character should be converted to a Yoshi, Baby DK, or Egg. There's an important detail here: all three spawn checks are always run, but if an earlier check succeeds, later checks cannot succeed because there's a character_type_chosen. Therefore, spawning an egg is doubly complicated: not only does the random egg spawning check have to succeed, but both of the prior alternate character's checks have to fail. Spawn mechanics part 2: character spawn chances One important detail is missing from the above code: how are the character spawn chances set? For Easy and Hard mode, the spawn chances are updated at specific score thresholds. When the score is >= the score threshold, multiple variables are updated, including the spawn chances, the max_characters variable and two other currently unknown variables. The score-threshold and related data are hardcoded in 9-byte blocks starting at 0x080d389c for Easy mode and 0x080d3b12 for Hard mode. There are 70 such blocks for Easy mode, and 65 blocks for Hard mode. The block format is as follows: Byte 0-2: score threshold, byte 3:speed , byte 4: max_characters, byte 5: baby_dk_spawn_chance, byte 6: yoshi_spawn_chance, byte 7: egg_spawn_chance, byte 8: unknown. The score threshold is one base-10 score digit per byte in big endian. The speed controls the magnitude by which individual character movement timers will increase per frame. Once a character's movement timer reaches >= 180, the character will have the movement physics applied; otherwise it will just stay in place for another frame. Therefore, the practical update speed can be calculated as a movement update every 180 / speed frames (e.g. with a speed of 180 falling characters will move every frame, with 90 every two frames, etc.) Below I have included a selection from the spawn probabilities in the format <score threshold>: <yoshi_spawn_chance>, <baby_dk_spawn_chance>, <egg_spawn_chance> (max: <max_characters>, speed: <speed>) Note that although the score thresholds stop at 999, specific score pre-filtering code prevents further advancement after the 999 score values are reached for each difficulty.
Easy:

0: 0x0, 0x0, 0x0 (max: 1, speed: 66),   6: 0xff, 0x0, 0x0 (max: 1, speed: 66),   12: 0x0, 0xff, 0x0 (max: 1, speed: 66),   18: 0x0, 0x0, 0xff (max: 1, speed: 66),   ...,   999: 0x40, 0x40, 0x40 (max: 6, speed: 106)

Hard:

0: 0x20, 0x0, 0x0 (max: 2, speed: 80),   10: 0x0, 0x0, 0x40 (max: 2, speed: 82),   20: 0x0, 0x0, 0xff (max: 1, speed: 82),   27: 0x50, 0x20, 0x0 (max: 4, speed: 84),   ...,   999: 0x40, 0x40, 0x20 (max: 6, speed: 116)
For Very Hard mode ("Star" mode), there is no score-based threshold, and instead the character spawn probabilities are all set to 0x2a, max_characters is set to 7, and speed is set to 120. Physics (UNFINISHED) This script is the living document for Fire's physics. The first "fc-" functions show offsets for important values. My eventual goal is to create a script that can accurately simulate score-related behavior for Fire given a starting seed and inputs. I still have one major detail missing, which is the collision handling for bounces. Besides that, I've made fairly good progress, though there's still a few details that I will probably need to understand before a full simulation will be possible. For instance, while I understand when characters will spawn in theory, there are sometimes longer delays where a character slot is sitting in the spawn-location that I don't understand. Also, the variable I'm using to check if a character is active activates position-tracking a bit early and may need to be better specified (the current variable activates after attempt_spawn() has been successful, so it raises the question of how the delay before the character actually starts moving is calculated). (Old tidbit: the only difference between the different falling character types is how the velocity and velocity_max variables get set when a bounce occurs. Otherwise, the characters are basically treated identically with regards to physics, sharing the same acceleration value and position/velocity/etc. updating code.)
RetroEdit
Any
Editor, Experienced Forum User, Reviewer, Player (166)
Joined: 8/8/2019
Posts: 131
This is my master-post for Game & Watch Gallery 4 analysis. As I discover more, I will link to separate post detailing the specific games. Index Randomness General operation The game appears to use a linear congruential generator for its randomness. Here is some Python code that shows its basic operation when called:
Language: python

# The RNG; an LCG def rand(): LCG_STORAGE = (LCG_STORAGE * 0x5D588B65 + 1) & 0xFFFFFFFF return LCG_STORAGE >> 0x10
When rand() is used in the pseudocode of later posts, it refers to this. The variable LCG_STORAGE is stored at the four-byte address 0x030014D0. It doesn't appear to explicity set a seed, so it simply begins operation with the default 0 stored in memory. LCG update scenarios The LCG is updated in a variety of situations. It updates once-per-frame frame on the title screen. It is updated 2-4 times when transitioning between screens (it varies a bit depending on the screen, and I will probably provide more precise details later). It updates when changing the selected game on the Game Select screen. It updates once when pausing, and once when unpausing (perhaps not consistently? More investigation required.) Each game will use the LCG for its operations, usually when deciding how long to delay certain events or which things to spawn. Practical use Without game-specific context, the value stored at this address is not very useful. However, once a specific game is better understood, the value of this address will become extremely useful in optimizing luck manipulation for that game. One important detail about the LCG storage address for TASing: the address always contains the value of the previous generated random number. So to set it up to generate a specific value, your goal is to have it be equal to the value that precedes the desired value in the LCG cycle. In general, the goal is to delay the LCG until it arrives at a useful number. There are two direct ways to affect this in all games: pausing and rebooting. Rebooting is an easy way to set the LCG to a precise frame by waiting a specific number of frames on the title screen. However, the downside is that rebooting is expensive, costing at least 491 frames plus the additional frames on the menu to cycle the LCG to the desired position. Thanks to a suggestion by jlun2, rebooting is probably unnecessary. Soft-resetting through Start-Select-A-B is sufficient, and net saves 244 frames over rebooting, totalling in to a mere 247 frames. Pausing advances the LCG two cycles and costs 97 frames. Therefore, at baseline, soft-resetting is a bit more than 2.5 times more expensive than pausing, but the extra frames to manipulate the LCG precisely may significantly worsen that ratio. For instance, in Fire, it costs an additional 283 frames to advance the LCG enough to spawn a star in the worst conditions (which the game starts near). Physics (UNFINISHED) Displayed character format More details to come about Fire Modern displayed object formats, which has a lot of potential to be generally useful in understanding all of the games if they all use the same format for organizing objects displayed on the screen.
1 2
5 6