Posts for jdaster64

jdaster64
He/Him
Experienced Forum User
Joined: 12/1/2012
Posts: 103
Location: New Donk City
The starting addresses for all the in-battle data are different in (U), but the enemy's level is a single byte, 0x1E bytes after its current HP. Also, I don't have any save files handy, so I wasn't actually able to test the effects of Lucky Badges (A) in the Japanese version; as such, I can't guarantee they still double and quadruple Lucky chance.
jdaster64
He/Him
Experienced Forum User
Joined: 12/1/2012
Posts: 103
Location: New Donk City
Don't know if anyone's still working on this, but BIS (U) uses the same RNG advancement and Lucky! chance formulas as Partners in Time. RNG address (U) - 0x0205bac2 (16-bit) RNG advance formula: next_rng(x) = floor(x * 41 / 2) & 0x7fff, + 0x8000 if x was odd. Lucky chance = floor(Attacker STACHE / 4 - Enemy Level / 8), clamped to [1, 99]; you get a lucky hit with RNG value seed iff next_rng(seed) % 100 < Lucky chance.
jdaster64
He/Him
Experienced Forum User
Joined: 12/1/2012
Posts: 103
Location: New Donk City
Both the RNG and lucky chance formulas seem the same in (J) as in (U), from what I can tell. The RNG address for (J) is 0x02060de6, incidentally. EDIT: Bowser's Inside Story (U) uses the same formulas; posted the address in its thread. Would be curious to find out if the same formula applies to the 3DS games too...
jdaster64
He/Him
Experienced Forum User
Joined: 12/1/2012
Posts: 103
Location: New Donk City
Is (E) equivalent to (J) in terms of stats? I have the latter and I can check it later, if so; else, I'll need to get the (E) version. I forgot the versions were different since they're not as night-and-day as Superstar Saga. Also, I'll post some sheets of enemy data (including levels) probably later this weekend; I plan on getting all my findings for this, MLSS, TTYD, etc. all in one place.
jdaster64
He/Him
Experienced Forum User
Joined: 12/1/2012
Posts: 103
Location: New Donk City
All right; here's how to predict the RNG effectively (using Python for these formulas):
next_rng(x) = lambda x: ((x*41//2)&0x7fff)+0x8000*(x%2) if x else 0x3ff3

def irng(x): (inverse rng):
  for z in range(0,41):
    ix = math.ceil(((x&0x7fff)+(z*0x10000))/20.5)&0xffff
    if next_rng(int(ix)) == x: return ix
  return -1
To determine whether the next hit will be Lucky!, the formula given a current seed is next_rng(seed) % 100 < lucky_chance. Testing a standard jump on a Koopeleon, that chance is 24 at 100 STACHE; going to try to see if that varies based on attack / enemy. EDIT: Lucky chance = floor((Attacker STACHE / 4) - (Enemy Level / 8)), clamped to [1,99]. Lucky Badge doubles the chance, and Lucky Badge A quadruples it.
jdaster64
He/Him
Experienced Forum User
Joined: 12/1/2012
Posts: 103
Location: New Donk City
Dang it man, I was literally about to post the RNG address. For (U), the RNG seed is indeed 0x02060a86, only 16-bits (unlike Superstar Saga's ~2KB). The formula as best as I can tell: RNG(x+1) = (x * 41 / 2) & 0x7fff, + 0x8000 if x was odd. Trying to figure out a consistent inverse to the formula and determine how Lucky hits are determined; for some reason, the attack I was testing rolled the RNG 2 or 3 times depending on whether I got a Lucky hit. EDIT: Looks like standard jumps only roll the RNG once per hit, I guess the extras came from the death animation. In any case, I've still yet to figure out how the RNG is actually used in the calculation; 0x8348 produced a Lucky hit with 100 STACHE, but 0x0029 did not.
jdaster64
He/Him
Experienced Forum User
Joined: 12/1/2012
Posts: 103
Location: New Donk City
Fruits in Ms. Pac-Man appear after eating two specific numbers of dots (64 and 176, iirc); I think it works the same in this version. In any case, if you hit the second trigger while the first (or its score) is still visible, you won't trigger the second. Happened all the time on certain boards when I played casually on the SNES version, notably Strange-4. I'm curious if there are any major differences between the NES version and the others; SNES / Genesis are identical except for the graphical style on Strange-32.
jdaster64
He/Him
Experienced Forum User
Joined: 12/1/2012
Posts: 103
Location: New Donk City
High scores don't save unless you beat the game / Game Over in the US version. Mario and Luigi are no different, but it doesn't lose time to switch between levels. Not sure why the firework is needed in 1-1, seems like it would waste less time to just wait until 370. Notably, left+right wasn't used, and that allows you to accelerate a bit faster. Also, FWIW, album completion requires you to play against another player in VS. mode.
jdaster64
He/Him
Experienced Forum User
Joined: 12/1/2012
Posts: 103
Location: New Donk City
Well, I feel silly. The thing I thought was a damage rounding error was when I used Thunder Bros., then noticed the value that showed afterwards was wrong; I failed to notice that the enemy's DEF dropped, and the value shown originally was correct. Also, I didn't mention this explicitly before, but the script already supports calculating the total damage for any number of hits on a multi-hit attack; it just shows the damage for the first hit in the test script. I'll probably try add JP / EU support to the damage script and write the item price script within the next couple of weeks. I don't think I'll bother doing proper Great Force checking; it works in most cases, and since that's the last thing in the damage calculation, it's easy enough to work around in the ones that it doesn't.
jdaster64
He/Him
Experienced Forum User
Joined: 12/1/2012
Posts: 103
Location: New Donk City
Was browsing this thread a lot beforehand, but somehow I didn't know the Twitch chat sections in the Brain Age run were actual chat excerpts; I'd assumed they were mocks. Really impressive showing overall; I think the race could've been explained a lot better before the run (in general, TASBot was better explained at AGDQ'15), but that aside, glad to see it was well received. SMB3 had me laughing pretty much nonstop.
jdaster64
He/Him
Experienced Forum User
Joined: 12/1/2012
Posts: 103
Location: New Donk City
I was wondering which levels they'd cut to fit in the 32(+1) level limit; didn't expect them to change the ROM to fit them all. Hopefully they'll port all the levels to the international versions of the game!
jdaster64
He/Him
Experienced Forum User
Joined: 12/1/2012
Posts: 103
Location: New Donk City
I could finish the damage calculation and item price scripts, though it'll probably be a couple of weeks before I have the time. Don't really know anything about how warping / screen transitions work, but I might look into it.
jdaster64
He/Him
Experienced Forum User
Joined: 12/1/2012
Posts: 103
Location: New Donk City
Finished the first draft of the damage-calculation script: https://dl.dropboxusercontent.com/u/64507723/mlss_dmg_calculator.lua Known issues: - Only supports (U) version thus far. - No way to filter out attacks that aren't available. - Doesn't handle Great Force properly if the wearer is not in-battle or is dead. - Rare off-by-one errors. - Might have forgotten some attack immunity cases? Screenshot of the script in action: Shows the next four RNG values, and the damage of every attack on the first enemy. First two columns: Mario / Luigi solo jump, hammer, hand, jump-counter, hammer-counter Third column: Splash Bros., Chopper Bros. (1st hit), Fire Bros. (1 ball), Swing Bros. (perfect hit) Fourth column: Splash Adv., Chopper Adv. (1st hit), Fire Adv. (1 ball), Swing Adv. (perfect + extra hit) Fifth column: Bounce Bros., Knockback Bros., Thunder Bros., Cyclone Bros. (1 hit) Sixth column: Bounce Adv. (1 hit), Knockback Adv. (1st hit), Thunder Adv., Cyclone Adv. (1 hit + extra hit) Each move has a calculation function, like mariojump(M) or chopperbrosadv(M, N); M is the enemy targeted (0-5), and N is the total damage from the first N hits.
jdaster64
He/Him
Experienced Forum User
Joined: 12/1/2012
Posts: 103
Location: New Donk City
Huh. I was wondering why the RNG ran four times when you use a solo-hammer attack instead of just twice (once for the Lucky! roll and once for the hammer damage if that fails). Turns out it does three separate rolls, and calculates the following three values (for Luigi, Mario's are somewhat different): 1.0 + 0.15 * rand1[0, 3), 0.9 + 0.23 * rand2[0, 3), 0.8 + 0.30 * rand3[0, 3). But then it just ignores the former two and always uses the third one. So when doing a solo-hammer, if the first RNG value won't get you a Lucky!, the fourth value is the one that determines the amount of damage you do. EDIT: Agh, scratch that, the solo-hammer damage ranges change based on Normal / Super / Ultra Hammers!!! I'll have to find out a bunch of these constants again. At least the Bros. Attacks' constants appear to not vary. EDIT again: Yeah, solo Hammer constants in all versions (Lucky doesn't change): Normal Hammers = xE6 / x100 / x119 (M), x100 / x126 / x14C (L), 2nd RNG value Super Hammers = xCC / x100 / x133 (M), xE6 / x121 / x15C (L), 3rd RNG value Ultra Hammers = xCC / x10C / x14C (M), xCC / x119 / x166 (L), 4th RNG value Funny that Luigi's average damage output actually drops with the "stronger" hammers. Updated constants guide: https://dl.dropboxusercontent.com/u/64507723/mlss_damage_disassembly.txt I might try to put together a script to calculate damage in the (U) version later tonight or tomorrow.
jdaster64
He/Him
Experienced Forum User
Joined: 12/1/2012
Posts: 103
Location: New Donk City
OK, found a bit more stuff. Battle data is arranged in eight blocks of 0x130 bytes, starting at the address in 0x03000FDC (U,E) / 0x03000FE0 (J). There are also pointers in 0x03003FA4-C0 (C4-E0 in (J)) to each of the actors' battle data. Mario and Luigi are always the last two blocks, and the enemies take up some number of the first six. Some of the addresses above, relative to the start of a block:
addr  size value
--------------------
0x018 word current xpos
0x01c word current ypos
0x020 word current altitude
0x0d8 word starting xpos
0x0dc word starting ypos
0x0e0 word starting altitude
0x0ec half enemy ID
0x0f5 byte level
0x0f6 half current HP
0x0f8 half max HP
0x0fa half HP - old value, when changing
0x0fc half current BP
0x0fe half max BP
0x100 half BP - old value, when changing
0x102 half pow (Bros. only)
0x104 half def
0x106 half speed
0x108 half stache (includes Lucky Mushroom)
0x10a half pow multiplier
0x10c half def multiplier
0x11c half speed multiplier
0x11e half status effect flags
0x12b byte badge effect +1
0x12c byte gear effect +1
0x12d byte pin effect +1

As for turn order stuff, this appears to be the formula: When choosing an actor to move, all eight actor slots are considered (I believe dead actors are treated the same as live ones). The following are special cases: - If the actor doesn't exist, nothing happens. - If the actor has already moved this turn, they are not considered. If the actor is eligible for a move this turn (i.e., it does not meet those two criteria): - Their (spd * spd multiplier) >> 8 is compared with the highest thus far. - If it is higher (or the first eligible actor), they will be the next to move. - If it is lower, ignore the actor, it cannot be the next to move. - If it is the same, generate a number N in range [0, # of actors thus far with that value); the N'th of those actors (0-indexed, in actor order) will be the next to move. As an example, given the start of a battle on (U) with three Paratroopeas, Mario (speed 120), and Luigi (speed 20): - Paratroopea 1 considered (speed = 80). First actor to be considered, so it is the next to move by default. - Paratroopea 2 considered (speed = 80). Tie with the current highest speed, so RNG is rolled for range [0, 2). Result is 1, so second Paratroopea becomes the next to move. - Paratroopea 3 considered (speed = 80). Tie with the current highest speed, so RNG is rolled for range [0, 3). Result is 0, so first Paratroopea again becomes the next to move. - <skips next three actors> - Mario considered (speed = 120). His speed is highest, so he becomes the next to move. - Luigi considered (speed = 20). His speed is lower than the current highest (Mario's), so he is ignored. - All actors have been considered; Mario gets to move next, and will not be considered again until all actors have taken a turn. I presume there are special cases for the Mario Follow / Mario Ahead effects that skip Luigi and make him move before / after Mario in the event he is selected.
jdaster64
He/Him
Experienced Forum User
Joined: 12/1/2012
Posts: 103
Location: New Donk City
All badges can be used by both Bros. in both versions, I believe. EDIT: Updated my RNG script with correct use of locals, and a couple more functions. untwist(n) takes a hex value, and returns the random seed required to produce that value. getseedfornum(x,mx) is similar, returning a random seed that gives the value x when rand-ranged on [0, mx). For example, getseedfornum(10,100) gives the seed 0x4B72A7A8; if you replace the currently pointed-to RNG seed with that one, the next RNG will be 0x1999999A, which is the smallest value that comes out to 10 in the range [0, 100). Calling untwist(0x1999999A) gives the same seed, but I thought the extra layer of abstraction would be more useful. RNG viewer script: https://dl.dropboxusercontent.com/u/64507723/mlss_rng_viewer.lua
jdaster64
He/Him
Experienced Forum User
Joined: 12/1/2012
Posts: 103
Location: New Donk City
Finished the script; this shows the next ten RNG values, as well as the corresponding rand_range(0,100) value. At the very least, I'm able to predict whether the next hit will be Lucky! or not using the formulas on the previous page! It works on both (U) and (J), I presume it works the same on (E). Here's the script; feel free to integrate it into the next version of your big M&L script. https://dl.dropboxusercontent.com/u/64507723/mlss_rng_viewer.lua Preview: EDIT: It appears that the random seeds to reset every time a battle starts, probably seeded based on a global timer or something; I set the whole random page to 0's during a battle, and it stayed that way until the next time I started one. I may look into it, but barring special conditions like that, the next several values should be completely deterministic. EDIT again: Apparently the minecart mini-game uses the RNG, but does not reset it before starting. Starting with a full page of zeroes has... interesting effects. No other replayable mini-game uses the RNG, as far as I can find.
jdaster64
He/Him
Experienced Forum User
Joined: 12/1/2012
Posts: 103
Location: New Donk City
Don't know how much of this is known already, but here's the formula for calculating the result of a rand[0, N): x2001e60 = rand steps left before restarting / regenerating random buffer (counts down from x270) x2001e64 = address of current random seed (x2001e60 - 4 * number in x2001e60) Given variable X = the value pointed by x2001e64: X ^= (X >> 11) X ^= (X << 7) & x9D2C5680 X ^= (X << 15) & xEFC60000 X ^= (X >> 18) The result of this calculation is multiplied by N to produce a 64-bit integer, then shifted right 32 bits to yield a number between 0 and N-1. Not sure how the random numbers are regenerated when the they're exhausted, but for most cases, this should be useful for determining the result of a single RNG roll on a frame (e.g. Lucky! attacks). EDIT: A cursory Google search suggests this is the MT-19937 random engine, if that's of any use. Here's a C implementation that looks identical to the one used in the game (besides the initial seeding, potentially). I'll see if I can't write a lua script to predict the next ten or so random numbers later.
jdaster64
He/Him
Experienced Forum User
Joined: 12/1/2012
Posts: 103
Location: New Donk City
The enemy data's position is somewhat dynamic; the battles I tested on had the enemy data in the 9500-9700 range. I'm pretty sure Mario and Luigi's data moves around as well, unfortunately. POW, DEF (and SPD?) modifiers are two bytes, with 0x100 = normal. I don't think item drop data is stored in the enemy's battle RAM data, at least not in the same format as in the ROM's enemy data. I can look into exact positions for some of this stuff, enemy ID, and so forth later tonight. Edit: Here's all the stuff I know about. The enemy I tested on's current health is at x020096AA for reference; everything is 2 bytes except the level. Enemy ID = 96A0. Level = 96A9 (1 byte) Current HP = 96AA Max HP = 96AC (Base) DEF = 96B8 SPEED = 96BA STACHE = 96BC POW Multiplier = 96BE DEF Multiplier = 96C0 SPEED Multiplier = 96D0 Not sure how SPEED affects turn order, but it's definitely taken into account before the "end" of the turn; e.g. if Mario SPD > Luigi SPD > Tanoomba SPD and it's Mario's turn, if I hex edit Tanoomba's SPD / SPD multiplier to something above Mario's, it will move after Mario and before Luigi, and then before Mario on subsequent turns. Editing the enemy ID doesn't seem to have any effect, but you can use it as an index into the enemy data in the ROM to get EXP, coins, and item drop info: EXP = (Starting address) + 0x2C * (Enemy ID) + 0x24 Coins = (Starting address) + 0x2C * (Enemy ID) + 0x26 Item 1 = (Starting address) + 0x2C * (Enemy ID) + 0x28 Item 2 = (Starting address) + 0x2C * (Enemy ID) + 0x2A The starting address is x08500A98 in (U), and x083E97F0 in (J). Not sure about (E), but the stats should be the same as in (U). The Item 1 / 2 data contains both the type and drop rate of the item. The first four bits are the item category (0 = nothing, 1 = badge, 2 = gear, 3 = bean, 4 = item), the next seven are the item type (starting with 0 = Mushroom, Bean Badge, Work Pants, Woo Bean; order is the same as my guide), and the last five are the drop rate out of 31. Example: Super Syrup with drop rate 15/31 = 412F = binary [0100][0001001][01111].
jdaster64
He/Him
Experienced Forum User
Joined: 12/1/2012
Posts: 103
Location: New Donk City
Yeah, they do; the stat progressions are in the "Bro Stats" tab in the Excel sheet. Not sure how bonuses work, though.
jdaster64
He/Him
Experienced Forum User
Joined: 12/1/2012
Posts: 103
Location: New Donk City
Seems plausible, I don't know the exact locations of the item slots in RAM, but I'd imagine the order's the same as in the game data. Also, as I mentioned before, the addresses for the Bros.' stats (max hp+bp, pow, def, spd, sta) on that page are all including equipment; the base stats are all 2 bytes beforehand, and changes to them are permanent.
jdaster64
He/Him
Experienced Forum User
Joined: 12/1/2012
Posts: 103
Location: New Donk City
Huh, I don't know; it pulled those values directly from the game data, and as far as I know there's no difference between those and any other gear with the same effects. Maybe they used to have +3 / +15 in the other stat, then had their effect changed later. I moved the "Raw Data" and "Lookup Values" sheets to the end in the Excel doc, btw, so that's why the item stats show up first now. If you're using Chrome and the Dropbox site to view it, there should be a series of tabs at the bottom of the page where you can switch to "Bro Stats", "Enemy Stats", or "Stache Discounts".
jdaster64
He/Him
Experienced Forum User
Joined: 12/1/2012
Posts: 103
Location: New Donk City
Turns out enemy STACHE is more complicated than just double the level; it's actually the average of the sum of the Bros.' level-up stats up through the enemy's level (I added the values to the Excel sheet above). As for the Japanese Lucky! calculation, given Enemy Level EL, Enemy Stache ES, Attacker Level AL, and Attacker Stache AS: If EL = 99, chance = 0. If (EL * xE7 - 1 < AL * x100 < EL * x119 + 1) (AL is within ~10% of EL): chance = (((AS - ES) * x1000000) / int(ES * x10000 * 1.2)) * xB + xA00, clamped to [6, 22]. If (EL * xC0 - 2 < AL * x100 < EL * x140 + 2) (AL is within ~25% of EL): chance = (((AS - ES) * x1000000) / int(ES * x10000 * 1.3)) * xB + xA00, clamped to [10, 30]. Else, chance = (((AS - ES) * x1000000) / int(ES * x10000 * 1.3)) * xB + xA00, clamped to [4, 15]. If the attacker's badge has the Lucky Attack effect, chance increases by 15, to a max of 40. The random chance from 0-99 is generated the same way as in the international version. Interestingly, there doesn't seem to be an overflow check for if (AS - ES) > 255, which I don't think is a problem in the international formula.
jdaster64
He/Him
Experienced Forum User
Joined: 12/1/2012
Posts: 103
Location: New Donk City
If you're allowing the Swing Bros. Game Over exploit to count as multiple items, the only one-timers are the initial pants and badge, Bros. Rock, High-End Badge, Wool Trousers, Iron Pants, Casual Coral, Harhall's Pants, and Soulful Bros. from minigames, and Piranha Swing (exclusive-or Piranha Suit in (U)) from Piranha Bean. There are some gear and badges that can't be obtained at all, though, like Bros. Respect. I guess I didn't make it clear, but that .xlsx file has multiple worksheets; the 'Raw Data' and 'Lookup Values' aren't meant to be human-readable, but the rest should be relatively straightforward, and it all includes (U) and (J) stats. If the issue is not having access to Excel or Google Sheets, I could put it in image or text form, but most of the data looks best in a spreadsheet. I don't believe you can get Lucky+Critical; I didn't even know you could get a Lucky hit on Hand attacks until the other day, since I pretty much only used them when I knew they'd critical before. [Edit: You definitely can't.] Incidentally, still working on the Japanese Lucky! chance formula, there was some really weird math stuff that ended up being double-precision floating point calculations, so I should be able to finish figuring it out now.
jdaster64
He/Him
Experienced Forum User
Joined: 12/1/2012
Posts: 103
Location: New Donk City
This guide here has far better information than the old one, including enemy stats, item stats, the Bros.' level-up gains, and STACHE discounts in both versions: https://www.dropbox.com/s/beg7ugxqc5kerqq/mlss_uj_allstats.xlsx?dl=0 This doc has the Bros.' exact attack constants in both versions: https://www.dropbox.com/s/578nae1sdqddh3x/mlss_damage_disassembly.txt?dl=0 I'll probably do a better write-up on this on my blog in the near future, but the basic formula is max(x66 x Pow x Pow-modifier - x33 x Def x Def-modifier, x200) x (additional modifiers) / x100, with some slight variations. As for your questions: 1) Prices in my guide are the base buying prices in the game; the base SELL price is that divided by 4, rounded down. 2) I think there are some, that's all in my guide in this post. 3) Golden Mushrooms are limited, and any boss drops and sidequest rewards are obviously limited. Also, in the (U) version, you can only get one of either the Piranha Swing and Piranha Suit. Just found out the Lucky hit chance formula is a bit different in the Japanese version (of course), looking into that at the moment.