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.)