Post subject: Harry Potter and the Prisoner of Azkaban
Joined: 5/31/2013
Posts: 42
Just started a TAS of this game, but having trouble finding any memory addresses in the game, and working out which ones indicate critical hits
Skilled player (1738)
Joined: 9/17/2009
Posts: 4980
Location: ̶C̶a̶n̶a̶d̶a̶ "Kanatah"
If it helps, the X/Y addresses (for the very first room, at least) are in "Combined WRAM" in BizHawk, and they are 00B944 - 4 byte unsigned - X 00B948 - 4 byte unsigned - Y Unfortunately, every time I go up and down stairs, the address changes by -0x128, so it becomes something like 00B948 -> 00B820 -> 00B6F8 -> 00B5D0 -> 00B380 00B4A8 is skipped for some reason. Not very informative, sorry. Never played this game. Edit: I think I found how it moves. All in Combined Wram: 042118 043358 043380 All seem to point at an address minus 0x02000000 near the X/Y values. Uh...In fact here's a lua script that displays X/Y at the very top, plus the pointer just in case Download Harry.lua
Language: lua

memory.usememorydomain("Combined WRAM") local Harry = {ptr = 0x042118, x = 0x000000, y = 0x000000} function update() local char = memory.read_s32_le(Harry.ptr) - 0x02000000 Harry.x = char + 0x2C Harry.y = char + 0x30 end while true do local pointer = memory.read_s32_le(Harry.ptr) if (pointer ~= Harry.x-0x2c+0x02000000 and pointer ~= 0) then --this will happen if changed rooms or just started script update() --placing this here as to not lag my computer :P end gui.text(0,0,string.format('%.6f',memory.read_u32_le(Harry.x)/65536.0)..","..string.format('%.6f',memory.read_u32_le(Harry.y)/65536.0)) gui.text(0,90,"Pointer: 0x"..bizstring.hex(memory.read_s32_le(Harry.ptr))) --debug emu.frameadvance() end
Tested in BizHawk 1.11.6. Please post if something goes wrong.
Experienced player (689)
Joined: 2/5/2012
Posts: 1794
Location: Brasil
if the game is similar to predecessors,then you can look for information about these things in the older game too
I want all good TAS inside TASvideos, it's my motto. TAS i'm interested: Megaman series, specially the RPGs! Where is the mmbn1 all chips TAS we deserve? Where is the Command Mission TAS? i'm slowly moving away from TASing fighting games for speed, maybe it's time to start finding some entertainment value in TASing.
Joined: 5/31/2013
Posts: 42
Lua script works perfectly, still trying to find what advances the RNG to manip things like criticals, damage enemies give, turn order in battles and enemy placement on overworld maps. Also, I don't think this game follows on from the GBC games in terms of RNG, as they run slightly differently in terms of battles
Experienced player (689)
Joined: 2/5/2012
Posts: 1794
Location: Brasil
StarrlightSims wrote:
Lua script works perfectly, still trying to find what advances the RNG to manip things like criticals, damage enemies give, turn order in battles and enemy placement on overworld maps. Also, I don't think this game follows on from the GBC games in terms of RNG, as they run slightly differently in terms of battles
. oh no,i meant the gba games which came before this,i'm aware the gbc games are rpg while this is an action game,but there's also a sorcerer stone for gba,for example,and it has been TASed: http://tasvideos.org/4564S.html
I want all good TAS inside TASvideos, it's my motto. TAS i'm interested: Megaman series, specially the RPGs! Where is the mmbn1 all chips TAS we deserve? Where is the Command Mission TAS? i'm slowly moving away from TASing fighting games for speed, maybe it's time to start finding some entertainment value in TASing.
Joined: 5/31/2013
Posts: 42
This game actually follows on from the gbc games, and is an RPG in the same style, so it's completely different from the first two gba games
Experienced player (689)
Joined: 2/5/2012
Posts: 1794
Location: Brasil
i just assumed they would go with the same formula,sorry
I want all good TAS inside TASvideos, it's my motto. TAS i'm interested: Megaman series, specially the RPGs! Where is the mmbn1 all chips TAS we deserve? Where is the Command Mission TAS? i'm slowly moving away from TASing fighting games for speed, maybe it's time to start finding some entertainment value in TASing.
Skilled player (1738)
Joined: 9/17/2009
Posts: 4980
Location: ̶C̶a̶n̶a̶d̶a̶ "Kanatah"
Ok, from what I gathered, the damage is "set" based on what you do; say casting Flippendo causes a rat to miss on their turn. Well, no matter how much delay you add before you use flippendo, that attack will still cause the rat to miss. Same with other spell/action outcomes. I haven't figured out the RNG yet, but I suspect it may be possible to delay before a battle starts (manipulate everything before hand). Also this has nothing much to do with the run, but apparently 003340 in Combined Wram is dialogue/spell text. Just posting that in case it is ever need it. Edit: 04339C 0433B8 Both in Combined WRAM. No idea what it does, but freezing them makes your partner suddenly walk off the screen. Battle Addresses - 2 bytes Combined Wram 0328E0 - First turn's ID 032928 - Second turn's ID 032970 - Third turn's ID 0329B8 - Fourth turn's ID 032A00 - Fifth turn's ID It's not the RNG, but at least using these addresses it would help immediately knowing what the order is. Casting Informas using cheats for example:
Joined: 5/31/2013
Posts: 42
So essentially the entire battle is determined before it even starts?
Skilled player (1738)
Joined: 9/17/2009
Posts: 4980
Location: ̶C̶a̶n̶a̶d̶a̶ "Kanatah"
StarrlightSims wrote:
So essentially the entire battle is determined before it even starts?
Seems like it. Also I found out that the battle ID's also change between locations; by the time I get to the train the addresses are different. I suspect the RNG (havent found yet) may be like that too, but I'm not sure.
Joined: 5/31/2013
Posts: 42
So just done some further testing into the RNG for the game, and what I found was that if you press New Game on the same frame every time, no matter what actions/flags/movement you do afterwards, and no matter how many frames pass, the Monster Book fight is exactly the same, so it seems that RNG is set from pressing New Game, still need to do more testing though.
Joined: 5/31/2013
Posts: 42
After some recent testing, the RNG in this game finally seems to make sense. The way RNG seems to work is that the frame you press Start on the first main menu determines two seeds that the game can choose between, and then the frame on which you select Load Game/New Game then determines which of those 2 seeds the game selects. Therefore, if we press start on the right frame, we should be able to completely predict what will happen in the battle. In the overworld, the only thing that seems to affect the RNG is the number of frames that the random enemies are on screen. In battle, the only things that effect RNG are which spells you choose each turn, and opening the help menu. We can open the help menu for the same amount of time by holding down a and b, so it closes as soon as it opens. So, it's a case of finding a good seed and then working out a battle from that seed. Now it's a case of finding good seeds, which is going to take forever.
Skilled player (1738)
Joined: 9/17/2009
Posts: 4980
Location: ̶C̶a̶n̶a̶d̶a̶ "Kanatah"
That's nice! Is that for just the first battle, or does that apply to that battle + rest of the game? Ie. RNG never changes after pressing start at new/load game?
Joined: 5/31/2013
Posts: 42
It works that way for the first battle, and then after that you can either manipulate it using the encounters on screen, or if you reset the game you can actually reset the seed, so by resetting just before a boss battle, you can actually manipulate the RNG, which is helpful for both TAS and RTA.
Joined: 5/31/2013
Posts: 42
Getting back into working on this, trying to find the point in the data where it says whether an attack will be a critical hit, but struggling to use RAM watch to actually find the section, seems like every time I think I have the right part its not, if anyone has any experience with using RAM watch it''d be greatly appreciated https://drive.google.com/file/d/1Vt7qiW6tHYKxhrwb1KsWPL7TCzqf20oG/view?usp=sharing Here's a state if anyone feels like messing around with it, the fight starts with a non-crit, but if you flash the help menu twice (Press A whilst holding B), it makes it a crit
Skilled player (1738)
Joined: 9/17/2009
Posts: 4980
Location: ̶C̶a̶n̶a̶d̶a̶ "Kanatah"
About your savestate, as soon as I load it in 2.4, it goes into battle, then immediately resets. Which BizHawk version did you use, and if it's also 2.4 can you please upload a new one? Edit: In 2.3, got the message: Core rejected the state. This appeared to be the first battle, so I can probably go try going there. I can see what you meant by the help menu now; managed to get NPC to miss as well; nice find! 0x274A in IWRAM is damage dealt. A tracelog of that reveals 0x5574, 0x5580, 0x5584 is changed before 0x274A is determined. Freezing 0x5580 appeared to make it constant; eg. freezing 0x5580 to 33564852 made the book always miss for me so far. Maybe the RNG? It appears to have an effect on other battles as well. That value also changed during the title screen because of the wand selector's sparkles when moving through options. That probably explained why the RNG advanced in the help screen; the wand's sparkle effect is random.
Skilled player (1738)
Joined: 9/17/2009
Posts: 4980
Location: ̶C̶a̶n̶a̶d̶a̶ "Kanatah"
I decided to investigate addresses again. Turns out battles also move around. There are 2 IDs First one can be values at 0, 1, 2, 255 Second one ranges from 0 to 68. First ID means if it's the player, or npc. 0 = Harry 1 = Hermione 2 = Ron 255 = NPC List of npcs and areas here https://docs.google.com/spreadsheets/d/196AiBW0Mi_z_8V6ZsxTuXqWkpQGUyHCaEuziBEyWhmM/edit?usp=sharing I updated the script, incomplete, to add battle. Will edit this post. Download Harry3.lua
Language: lua

client.SetGameExtraPadding(0, 0, 200, 100) console.clear() local text local read8 local read16 local read32 if vba then text = text read8 = memory.readbyteunsigned read16 = memory.readwordunsigned read32 = memory.readlongunsigned else text = gui.pixelText memory.usememorydomain("System Bus") read8 = memory.read_u8 read16 = memory.read_u16_le read24 = memory.read_u24_be read32 = memory.read_u32_le end local Addresses = { Harry_pointer_x = 0x03002118, Battle_pointer = 0x030024E8, Harry_SP = 0x030024F6, Harry_XP = 0x030024F8, --XP to next level Harry_Level = 0x030024FA, Harry_Flipendo = 0x03002506, --how many times cast Harry_Vermdimillous = 0x03002508, Harry_Incendio = 0x0300250A, Harry_Petrificus = 0x0300250C, Hermione_Flipendo = 0x0300254E, Hermione_Vermdimillous = 0x03002550, Hermione_Incendio = 0x03002552, Hermione_Petrificus = 0x03002554, Hermione_Glacius = 0x03002555, Hermione_Fumos = 0x03002556, Ron_SP = 0x03002584, Ron_MP = 0x03002586, Ron_Level = 0x0300258A, --What tier of spell unlocked Ron_Flipendo_Lv = 0x0300258C, Ron_Vermdimillous_Lv = 0x0300258E, Ron_Incendio_Lv = 0x03002590, Ron_Petrificus_Lv = 0x03002592, Ron_Flipendo_XP = 0x03002596, --How many times cast. Duo counts as 2 Ron_Vermdimillous_XP = 0x03002598, Ron_Incendio_XP = 0x0300259A, Ron_Petrificus_XP = 0x0300259C, Damage_dealt = 0x0300274A, Area = 0x03003B50, Game_State1 = 0x03003EF4, Game_State2 = 0x03003F18 } local Harry = {ptr = 0x03002118, x = 0x000000, y = 0x000000} local Battle = { Address = {0,0,0,0,0,0}, Is_NPC = {0,0,0,0,0,0}, ID = {0,0,0,0,0,0}, SP = {0,0,0,0,0,0}, MP = {0,0,0,0,0,0}, Level = {0,0,0,0,0,0}, Max_SP = {0,0,0,0,0,0}, Max_MP = {0,0,0,0,0,0}, Flipendo_Multiplier = {0,0,0,0,0,0}, Incendio_Multiplier = {0,0,0,0,0,0}, Verdimillious_Multiplier = {0,0,0,0,0,0}, Wingardium_Multiplier = {0,0,0,0,0,0}, Glacius_Multiplier = {0,0,0,0,0,0}, Diffindo_Multiplier = {0,0,0,0,0,0}, Status = {0,0,0,0,0,0}, Status_Meter = {0,0,0,0,0,0} } local NPC = { [0] = 'Ruby Fire Crab', [1] = 'Emerald Fire Crab', [2] = 'Sapphire Fire Crab', [3] = 'Cornish Pixie', [4] = 'Rat', [5] = 'Albino Rat', [6] = 'Plague Rat', [7] = 'Clabbert', [8] = 'Suit of Armor (Footman)', [9] = 'Suit of Armor (Cavalier)', [10] = 'Suit of Armor (Paladin)', [11] = 'Suit of Armor (Squire)', [12] = 'Suit of Armor (Swordsman)', [13] = 'Suit of Armor (Crusader)', [14] = 'Suit of Armor (Knight)', [15] = 'Funnelweb Spider', [16] = 'Brown Recluse Spider', [17] = 'Large Spider', [18] = 'Redback Spider', [19] = 'Giant Spider', [20] = 'Cocoon Spider', [21] = 'Whitetail Spider', [22] = 'Flobberworm', [23] = 'Snail', [24] = 'Large Orange Snail', [25] = 'Flailtail Snail', [26] = 'Bat', [27] = 'Fruitbat', [28] = 'Mortis Bat', [29] = 'Dragonfly', [30] = 'Imperial Dragonfly', [31] = 'Horklump', [32] = 'Snake', [33] = 'Spitting Snake', [34] = 'Wasp', [35] = 'Tarantula Hawk Wasp', [36] = 'Bowtruckle', [37] = 'Oaken Bowtruckle', [38] = 'Doxy', [39] = 'Doxy Queen', [40] = 'Hinkypunk', [41] = 'Gytrash', [42] = 'Grindylow', [43] = 'Red Cap', [44] = 'Armored Red Cap', [45] = 'Salamander', [46] = 'Amazonian Salamander', [47] = 'Peruvian Salamander', [48] = 'Charmed Skeleton', [49] = 'Jinxed Skeleton', [50] = 'Tree Frog', [51] = 'Wide-mouth Toad', [52] = 'Bullfrog', [53] = 'Flesh-eating Slug (not in game, needs to be in file for coders - no need to translate)', [54] = 'Whomping Willow', [55] = 'Forest Troll', [56] = 'River Troll', [57] = 'Venemous Tentacula', [58] = "The Monster Book of Monsters'", [59] = 'Giant Rat', [60] = 'Crabbe', [61] = 'Draco', [62] = 'Goyle', [63] = 'Lupin Werewolf', [64] = 'Snake', [65] = 'Brown Recluse Spider', [66] = "The Monster Book of Monsters'", [67] = "The Monster Book of Monsters'", [68] = 'Native of Fiji. Has a heavily jeweled shell.' } local Is_NPC = {[0] = "Harry", "Hermione", "Ron", "Buckbeak", [255] = "Yes"} function update() local ptr_x = read32(Addresses.Harry_pointer_x) Harry.x = ptr_x + 0x2C Harry.y = ptr_x + 0x30 end function update_battle() local ptr_battle = read32(Addresses.Battle_pointer) for i = 1, 6 do Battle.Address[i] = ptr_battle + 0x14E0 + (0x48 * (i-1)) Battle.Is_NPC[i] = read8(Battle.Address[i]) Battle.ID[i] = read8(Battle.Address[i]+ 0x1) Battle.SP[i] = read16(Battle.Address[i]+ 0x8) Battle.MP[i] = read16(Battle.Address[i]+ 0xA) Battle.Level[i] = read8(Battle.Address[i]+ 0xE) Battle.Max_SP[i] = read16(Battle.Address[i]+ 0x24) Battle.Max_MP[i] = read16(Battle.Address[i]+ 0x26) Battle.Flipendo_Multiplier[i] = read8(Battle.Address[i]+ 0x34) Battle.Incendio_Multiplier[i] = read8(Battle.Address[i]+ 0x35) Battle.Verdimillious_Multiplier[i] = read8(Battle.Address[i]+ 0x36) Battle.Wingardium_Multiplier[i] = read8(Battle.Address[i]+ 0x37) Battle.Glacius_Multiplier[i] = read8(Battle.Address[i]+ 0x38) Battle.Diffindo_Multiplier[i] = read8(Battle.Address[i]+ 0x39) Battle.Status[i] = read8(Battle.Address[i]+ 0x42) --binary flags Battle.Status_Meter[i] = read8(Battle.Address[i]+ 0x44) --was for petrified end end --[[ Status 0 0 0 0 0 0 0 0 7 6 5 4 3 2 1 0 0 = ? 1 = ? 2 = ? 3 = Spongify 4 = Petrified 5 = ? 6 = ? 7 = immune to petrified ]]-- --2CE38 update_battle() local i = 3 console.log(string.format("%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t",Battle.Level[i],Battle.Max_SP[i],Battle.Flipendo_Multiplier[i], Battle.Verdimillious_Multiplier[i], Battle.Incendio_Multiplier[i], Battle.Wingardium_Multiplier[i], Battle.Diffindo_Multiplier[i], Battle.Glacius_Multiplier[i])) while true do local pointer = read32(Addresses.Harry_pointer_x) local state = read8(Addresses.Game_State2) if (pointer ~= Harry.x-0x2c and pointer ~= 0 and state ~= 9) then --this will happen if changed rooms or just started script update() --placing this here as to not lag my computer :P end local text_x = 240 if (state == 8) then text(text_x,0,string.format('%.6f,%.6f',read32(Harry.x)/65536.0, read32(Harry.y)/65536.0)) end if (state == 9) then update_battle() local text_y = 0 for i = 1, 6 do if Battle.Is_NPC[i] < 4 then text(text_x,text_y, Is_NPC[Battle.Is_NPC[i]] .. " " .. bizstring.hex(Battle.Address[i])) elseif Battle.Is_NPC[i] == 255 then text(text_x,text_y, "(" .. Battle.ID[i] .. ") " .. NPC[Battle.ID[i]] .. " " .. bizstring.hex(Battle.Address[i]), "red") end text_y = text_y + 8 text(text_x,text_y, string.format('LV: %d SP: %d/%d MP: %d/%d', Battle.Level[i], Battle.SP[i], Battle.Max_SP[i], Battle.MP[i], Battle.Max_MP[i])) text_y = text_y + 8 text(text_x,text_y, string.format('Flip: %d Verd: %d Ince: %d', Battle.Flipendo_Multiplier[i], Battle.Verdimillious_Multiplier[i], Battle.Incendio_Multiplier[i])) text_y = text_y + 8 text(text_x,text_y, string.format('Wing: %d Diff: %d Glac: %d', Battle.Wingardium_Multiplier[i], Battle.Diffindo_Multiplier[i], Battle.Glacius_Multiplier[i])) text_y = text_y + 8 end end emu.frameadvance() end

1731604790