Post subject: Harry Potter and the Prisoner of Azkaban
Player (30)
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 (1742)
Joined: 9/17/2009
Posts: 4986
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 (723)
Joined: 2/5/2012
Posts: 1804
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.
Player (30)
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 (723)
Joined: 2/5/2012
Posts: 1804
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.
Player (30)
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 (723)
Joined: 2/5/2012
Posts: 1804
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 (1742)
Joined: 9/17/2009
Posts: 4986
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:
Player (30)
Joined: 5/31/2013
Posts: 42
So essentially the entire battle is determined before it even starts?
Skilled player (1742)
Joined: 9/17/2009
Posts: 4986
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.
Player (30)
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.
Player (30)
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 (1742)
Joined: 9/17/2009
Posts: 4986
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?
Player (30)
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.
Player (30)
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 (1742)
Joined: 9/17/2009
Posts: 4986
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 (1742)
Joined: 9/17/2009
Posts: 4986
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, 150) 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, Lumos_pointer1 = 0x03001C0C, --only when not cast; value + 0x80 Lumos_pointer2 = 0x03001C1C, --only when cast; value + 0x80 Harry_SP = 0x030024F4, Harry_MP = 0x030024F6, Harry_XP = 0x030024F8, --XP to next level Harry_Level = 0x030024FA, Harry_Spells_Unlocked = 0x030024FB, --What tier of spell unlocked Harry_Flipendo_Level = 0x030024FC, Harry_Informus_Level = 0x030024FD, --doesnt normal go above 1 Harry_Vermdimillous_Level = 0x030024FE, Harry_Diffindo_Level = 0x030024FF, --doesnt normal go above 1 Harry_Incendio_Level = 0x03002500, Harry_Wingardium_Level = 0x03002501, --doesnt normal go above 1 Harry_Petrificus_Level = 0x03002502, --doesnt normal go above 1 --How many times cast. Duo counts as 2 Harry_Flipendo_XP = 0x03002506, Harry_Vermdimillous_XP = 0x03002508, Harry_Incendio_XP = 0x0300250A, Harry_Petrificus_XP = 0x0300250C, Harry_Max_SP = 0x03002510, Harry_Max_MP = 0x03002512, Harry_Agility = 0x03002516, Harry_Defense = 0x0300251A, Harry_Magic_Defense = 0x0300251B, Hermione_SP = 0x0300253C, Hermione_MP = 0x0300253E, Hermione_XP = 0x03002540, --XP to next level Hermione_Level = 0x03002542, Hermione_Spells_Unlocked = 0x03002543, --What tier of spell unlocked Hermione_Flipendo_Level = 0x03002544, Hermione_Informus_Level = 0x03002545, --doesnt normal go above 1 Hermione_Vermdimillous_Level = 0x03002546, Hermione_Incendio_Level = 0x03002548, Hermione_Wingardium_Level = 0x03002549, --doesnt normal go above 1 Hermione_Petrificus_Level = 0x0300254A, Hermione_Glacius_Level = 0x0300254B, Hermione_Fumos_Level = 0x0300254C, --How many times cast. Duo counts as 2 Hermione_Flipendo_XP = 0x0300254E, Hermione_Vermdimillous_XP = 0x03002550, Hermione_Incendio_XP = 0x03002552, Hermione_Petrificus_XP = 0x03002554, Hermione_Glacius_XP = 0x03002555, Hermione_Fumos_XP = 0x03002556, Ron_SP = 0x03002584, Ron_MP = 0x03002586, Ron_Level = 0x0300258A, --What tier of spell unlocked Ron_Flipendo_Level = 0x0300258C, Ron_Informus_Level = 0x0300258D, --doesnt normal go above 1 Ron_Vermdimillous_Level = 0x0300258E, Ron_Incendio_Level = 0x03002590, Ron_Wingardium_Level = 0x03002591, --doesnt normal go above 1 Ron_Petrificus_Level = 0x03002592, Ron_Spongify_Level = 0x03002595, --doesnt normal go above 1 --How many times cast. Duo counts as 2 Ron_Flipendo_XP = 0x03002596, Ron_Vermdimillous_XP = 0x03002598, Ron_Incendio_XP = 0x0300259A, Ron_Petrificus_XP = 0x0300259C, Miss_Counter = 0x03002749, Damage_dealt = 0x0300274A, Story = 0x030027B9, Sickles = 0x03003180, Frames = 0x03003189, --increments 1 every 2 frames Seconds = 0x03003188, Minutes = 0x3003187, Hours = 0x3003186, Wiggenweld_Potion = 0x030037E8, Area = 0x03003B50, Game_State1 = 0x03003EF4, Game_State2 = 0x03003F18, Overworld_Spell = 0x0300338F } local Harry = {ptr = 0x03002118, x = 0x000000, y = 0x000000, lumos = 0x000000} 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"} local Story = { [0] = "Talk to Cornelius Fudge", [1] = "Find Harry's room", [2] = "Greet the Weasleys", [3] = "Talk to Tom", [4] = "Find the Rat Tonic", [5] = "Deliver the Rat Tonic to Ron", [6] = "Find Scabbers", [7] = "Find Crookshanks", [8] = "Leave the cellar", [9] = "Find your seat", [10] = "Find Trevor", [11] = "Block the doors", [12] = "Find chocolate", [13] = "Find the conductor", [14] = "Find the Gryffindor common room", [15] = "Go to Transfiguration class", [16] = "Find McGonagall", [17] = "Go to Care of Magical Creatures class", [18] = "Find the five escaped books", [19] = "Go to Potions class", [20] = "Find the five potion ingredients", [21] = "Return the ingredients to Snape", [22] = "Go to the staff room", [23] = "Go to the Gryffindor common room", [24] = "Find Scabbers", [25] = "Find the Fat Lady", [26] = "Go to Defense Against the Dark Arts class", [27] = "Go to the library", [28] = "Find the five book pages", [29] = "Return to Defense Against the Dark Arts class", [30] = "Go to the Gryffindor common room", [31] = "Go to Hagrid's hut", [32] = "Go to the library", [33] = "Find Hermione", [34] = "Go to the Great Hall", [35] = "Go to Professor Lupin's office", [36] = "Go to the Gryffindor common room", [37] = "Go to the Gryffindor boy's dormitory", [38] = "Go to the Gryffindor common room", [39] = "Go to the Gryffindor boy's dormitory", [40] = "Go to the Entrance Hall", [41] = "Return to the Gryffindor common room", [42] = "Go to the Gryffindor boy's dormitory", [43] = "Find Ron and Hermione", [44] = "Go to Hagrid's hut", [45] = "Go to the Whomping Willow", [46] = "Find the path beneath the Whomping Willow", [47] = "Follow the path to the Shrieking Shack", [48] = "Return to Hogwarts", [49] = "Walk to the lake", [50] = "Take the secret path to Hagrid's hut", [51] = "Go to Hagrid's hut", [52] = "Go back to the lake", [53] = "Go to the Hogwarts rooftop", [54] = "Speak to the Weasleys", [55] = "Find Ron", [56] = "Return to Lupin", [57] = "Rescue Sirius Black", [58] = "Find the book on Hippogriff-baiting", [59] = "Flipendo", [60] = "Informus", [61] = "Vermdimillous", [62] = "Diffindo", [63] = "Incendio", [64] = "Wingardium Leviosa", [65] = "Petrificus Totalus", [66] = "Glacius", [67] = "Fumos", [68] = "Spongify", [69] = "Uno", [70] = "Duo", [71] = "Tria", [72] = "Harry casts a spell:", [73] = "Hermione casts a spell:", [74] = "Ron casts a spell:", [75] = "Buckbeak attacks!", [76] = "Harry performs a Special Move:", [77] = "Hermione performs a Special Move:", [78] = "Ron performs a Special Move:", [79] = "Harry uses a potion:", [80] = "Hermione uses a potion:", [81] = "Ron uses a potion:", [82] = "Harry is poisoned.", [83] = "Hermione is poisoned.", [84] = "Ron is poisoned.", [85] = "Buckbeak is poisoned.", [86] = "Harry is paralyzed.", [87] = "Hermione is paralyzed.", [88] = "Ron is paralyzed.", [89] = "Buckbeak is paralyzed.", [90] = "Harry can't move.", [91] = "Hermione can't move.", [92] = "Ron can't move.", [93] = "Harry can move again!", [94] = "Hermione can move again!", [95] = "Ron can move again!", [96] = "Buckbeak can move again!", } local Area = { [0] = "Defence Against the Dark Arts Classroom", [1] = "Potions Classroom", [2] = "Potions Classroom Maze", [3] = "Transfiguration Classroom", [4] = "Transfiguration Classroom Maze", [5] = "Hogwarts Express - Baggage Car", [6] = "Hogwarts Express - Passenger Car", [7] = "Hogwarts Express - Buffet Car", [8] = "Hogwarts Grounds - Castle Doors", [9] = "Hogwarts Grounds - Boathouse", [10] = "Hogwarts Grounds - Greenhouses", [11] = "Hagrid's Hut", [12] = "Hagrid's Garden Maze", [13] = "Hogwarts Grounds - Lake", [14] = "Path to Hagrid's Hut", [15] = "Hogwarts Grounds - Whomping Willow", [16] = "Entrance Hall", [17] = "Great Hall", [18] = "Hogwarts Dungeons", [19] = "Second Floor", [20] = "Third Floor", [21] = "Fourth Floor", [22] = "Fifth Floor", [23] = "Sixth Floor", [24] = "Seventh Floor", [25] = "Rooftop", [26] = "Lupin's Office", [27] = "Staff Room", [28] = "Gryffindor Boys' Dormitory", [29] = "Gryffindor Common Room", [30] = "Grand Staircase", [31] = "Portrait Room", [32] = "Portrait Room Passage", [33] = "Hospital Wing", [34] = "Library", [35] = "Library", [36] = "Fred and George's Shop", [37] = "Wizard Card Collectors' Club", [38] = "Leaky Cauldron - Cellar 1", [39] = "Leaky Cauldron - Cellar 2", [40] = "Leaky Cauldron - Hallway", [41] = "Leaky Cauldron - Harry's Room", [42] = "Leaky Cauldron (Main)", [43] = "Shrieking Shack Interior", [44] = "Shrieking Shack Path", [45] = "Shrieking Shack - Path 2", [46] = "Shrieking Shack - Path 3", [47] = "Shrieking Shack - Path 4", [48] = "Shrieking Shack - Path 5", [49] = "Shrieking Shack - Path 6", [50] = "Diagon Alley Test Map1", [51] = "Diagon Alley Test Map 2", [52] = "Diagon Alley Test Map 3", [53] = "Diagon Alley Test Map 4", [54] = "Diagon Alley Test Map 5" } local Overworld_Spell = { [0] = "Flipendo", [1] = "Lumos", [2] = "Diffindo", [3] = "Flipendo", [4] = "Reparo", [5] = "Glacius", [6] = "Flipendo", [7] = "Alohomora", [8] = "Spongify" } function update() Harry.ptr = read32(Addresses.Harry_pointer_x) Harry.lumos = Harry.ptr - 0x16A0 Harry.x = Harry.ptr + 0x2C Harry.y = Harry.ptr + 0x30 end function update_lumos() Harry.lumos = read32(Addresses.Lumos_pointer1) end local Spell = { [0] = { --Flippendo [0] = {Name = "Flippendo Uno", Minimum_damage = 10, Multiplier = 4, MP = 0}, [1] = {Name = "Flippendo Duo", Minimum_damage = 20, Multiplier = 8, MP = 10}, [2] = {Name = "Flippendo Tria", Minimum_damage = 15, Multiplier = 10, MP = 20} }, [1] = { --Informus [0] = {Name = "Informus", Minimum_damage = 0, Multiplier = 0, MP = 0}, [1] = {Name = "Informus", Minimum_damage = 0, Multiplier = 0, MP = 0}, [2] = {Name = "Informus", Minimum_damage = 0, Multiplier = 0, MP = 0} }, [2] = { --Verdimillious [0] = {Name = "Verdimillious Uno", Minimum_damage = 15, Multiplier = 6, MP = 3}, [1] = {Name = "Verdimillious Duo", Minimum_damage = 25, Multiplier = 12, MP = 15}, [2] = {Name = "Verdimillious Tria", Minimum_damage = 20, Multiplier = 14, MP = 25} }, [3] = { --Diffindo [0] = {Name = "Diffindo", Minimum_damage = 30, Multiplier = 18, MP = 10}, [1] = {Name = "Diffindo", Minimum_damage = 30, Multiplier = 19, MP = 0}, [2] = {Name = "Diffindo", Minimum_damage = 40, Multiplier = 20, MP = 0} }, [4] = { --Incendio [0] = {Name = "Incendio Uno", Minimum_damage = 23, Multiplier = 8, MP = 6}, [1] = {Name = "Incendio Duo", Minimum_damage = 35, Multiplier = 16, MP = 20}, [2] = {Name = "Incendio Tria", Minimum_damage = 45, Multiplier = 18, MP = 30} }, [5] = { --Wingardium Leviosa [0] = {Name = "Wingardium Leviosa", Minimum_damage = 35, Multiplier = 20, MP = 20}, [1] = {Name = "Wingardium Leviosa", Minimum_damage = 45, Multiplier = 21, MP = 30}, [2] = {Name = "Wingardium Leviosa", Minimum_damage = 55, Multiplier = 22, MP = 40} }, [6] = { --Petrificus Totalus [0] = {Name = "Petrificus Totalus Uno", Minimum_damage = 0, Multiplier = 0, MP = 10}, [1] = {Name = "Petrificus Totalus Duo", Minimum_damage = 0, Multiplier = 0, MP = 15}, [2] = {Name = "Petrificus Totalus Tria", Minimum_damage = 0, Multiplier = 0, MP = 20} }, [7] = { --Glacius [0] = {Name = "Glacius Uno", Minimum_damage = 30, Multiplier = 18, MP = 15}, [1] = {Name = "Glacius Duo", Minimum_damage = 40, Multiplier = 20, MP = 25}, [2] = {Name = "Glacius Tria", Minimum_damage = 45, Multiplier = 20, MP = 0} }, [8] = { --Fumos [0] = {Name = "Fumos Uno", Minimum_damage = 0, Multiplier = 0, MP = 8}, [1] = {Name = "Fumos Duo", Minimum_damage = 0, Multiplier = 0, MP = 30}, [2] = {Name = "Fumos Tria", Minimum_damage = 0, Multiplier = 0, MP = 0} }, [9] = { --Spongify [0] = {Name = "Spongify", Minimum_damage = 0, Multiplier = 0, MP = 10}, [1] = {Name = "Spongify", Minimum_damage = 0, Multiplier = 0, MP = 0}, [2] = {Name = "Spongify", Minimum_damage = 0, Multiplier = 0, MP = 0} } } 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}, Attack_Type = {0,0,0,0,0,0}, Spell = {0,0,0,0,0,0}, Spell_Tier = {0,0,0,0,0,0}, Status = {0,0,0,0,0,0}, Status_Meter = {0,0,0,0,0,0,}, Current_Turn = 0, Amount = 0 } function update_battle() local ptr_battle = read32(Addresses.Battle_pointer) Battle.Amount = read8(ptr_battle+ 0x106F) --number of fighters for i = 1, Battle.Amount do Battle.Address[i] = read32(ptr_battle+4) + (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.Spells_Unlocked[i] = read8(Battle.Address[i]+ 0xF) --number of spells you can use. max 7 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.Attack_Type[i] = read8(Battle.Address[i]+ 0x3B) --[[ 0 Spells 1 Potion 2 Special move 3 Flee 4 Informus ]]-- Battle.Spell[i] = read8(Battle.Address[i]+ 0x3C) --[[ 0 Flippendo 1 Informus 2 Verdimillious 3 Diffindo 4 Incendio 5 Wingardium 6 Petrificus 7 Glacius 8 Fumos 9 Spongify 10+ is bugged. Address doesn't apply for npcs ]]-- Battle.Spell_Tier[i] = read8(Battle.Address[i]+ 0x3D) --0 Uno, 1 Duo, 2 Tria Battle.Status[i] = read8(Battle.Address[i]+ 0x42) --binary flags Battle.Status_Meter[i] = read8(Battle.Address[i]+ 0x44) --was for petrified end Battle.Current_Turn = read8(ptr_battle+ 0x106C) --current battler's turn; uses different format than above end function Status(value) --[[ Status 0 0 0 0 0 0 0 0 7 6 5 4 3 2 1 0 So print the above in binary Followed by Status? 0 = Fumos 1 = Poisoned 2 = ? 3 = Spongify 4 = Petrified 5 = Be more careful 6 = Proper wand technique 7 = immune to petrified ]]-- --2CE38 local temp = "" for i = 0, 7 do if bit.check(value, i) == true then temp = 1 .. temp else temp = 0 .. temp end end return temp end function divide_4a2fc(param1, param2) local var1, var2, var3 = 0,0,0; var1 = 0; var2 = 1; var3 = param1 ~ param2; if param2 == 0 then return 0 end param1 = math.abs(param1) param2 = math.abs(param2) if param2 <= param1 then while (param2 < 0x10000000 and param2 < param1) do param2 = param2 << 4 var2 = var2 << 4 end while (param2 < 0x80000000 and param2 < param1) do param2 = param2 << 1 var2 = var2 << 1 end while true do if (param2 <= param1) then param1 = param1 - param2 var1 = var1 | var2 end for i = 1, 3, 1 do if (param2 >> i <= param1) then param1 = param1 - (param2 >> i) var1 = var1 | var2 >> i end end if (param1 == 0) then break end var2 = var2 >> 4 if (var2 == 0) then break end param2 = param2 >> 4 end end if var3 < 0 then var1 = -1 * var1 end return var1 end function divide_4a464(param1, param2) local var1, var2 = 0,0; var1 = 0; var2 = 1; if param2 == 0 then return 0 end if param2 <= param1 then while (param2 < 0x10000000 and param2 < param1) do param2 = param2 << 4 var2 = var2 << 4 end while (param2 < 0x80000000 and param2 < param1) do param2 = param2 << 1 var2 = var2 << 1 end while true do if (param2 <= param1) then param1 = param1 - param2 var1 = var1 | var2 end for i = 1, 3, 1 do if (param2 >> i <= param1) then param1 = param1 - (param2 >> i) var1 = var1 | var2 >> i end end if (param1 == 0) then break end var2 = var2 >> 4 if (var2 == 0) then break end param2 = param2 >> 4 end end return var1 end update_battle() local multi_offset = {[0] = 0x34, 0, 0x36, 0x39, 0x35, 0x37, 0, 0x38, 0, 0} function spell_damage() --use after update_battle() --[[ 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) So spells are 0 Flippendo 1 Informus 2 Verdimillious 3 Diffindo 4 Incendio 5 Wingardium 6 Petrificus 7 Glacius 8 Fumos 9 Spongify 0 -> 0x34 2 -> 0x36 3 -> 0x39 4 -> 0x35 5 -> 0x37 7 -> 0x38 ]]--Battle.Attack_Type[i] == 0 local current_turn = Battle.Current_Turn + 1 local current_id = Battle.Is_NPC[Battle.Current_Turn + 1] local spell = Battle.Spell[current_turn] local text_y = 216 local text_x = 0 local min_damage, multi, damage, damage_2 = 0, 0, 0, 0 if current_id < 3 then --check if current turn is me or npc if Battle.Attack_Type[current_turn] == 0 then --I'm actually using a spell first if spell < 8 and spell ~= 1 and spell ~= 6 then min_damage = Spell[Battle.Spell[current_turn]][Battle.Spell_Tier[current_turn]].Minimum_damage multi = Spell[Battle.Spell[current_turn]][Battle.Spell_Tier[current_turn]].Multiplier damage = min_damage + divide_4a2fc((Battle.Level[current_turn] * multi),9) if current_id == 1 then --If Hermione damage = divide_4a464(17 * damage,16) elseif current_id == 2 then --If Ron damage = divide_4a464(15 * damage,16) end end text(text_x, text_y, string.format('%s used %s\nMin: %d Mult: %d Base damage: %d', Is_NPC[Battle.Is_NPC[current_turn]], Spell[Battle.Spell[current_turn]][Battle.Spell_Tier[current_turn]].Name,min_damage, multi, damage)) text_y = text_y + 16 end for i = 1, Battle.Amount do if Battle.Is_NPC[i] == 255 then if spell < 8 and spell ~= 1 and spell ~= 6 then damage_2 = divide_4a464(damage * read8(Battle.Address[i]+ multi_offset[spell]), 100) + 1 --using read again, so i can use multi offset table text(text_x, text_y, string.format('(%d) %s takes %d damage', Battle.ID[i], NPC[Battle.ID[i]], damage_2)) text_y = text_y + 8 end end end end if current_id == 3 then text(text_x, text_y, string.format('Buckbeak does %d amount of damage!',(read8(Addresses.Harry_Level) >> 1) + 30)) end end function display_battle() update_battle() spell_damage() local text_y = 0 local text_x = 240 local l_text = "" --[[ 1. check if your turn 2. record what you selected 3. as you go through the rest of the fighters, make a list of ]]-- for i = 1, Battle.Amount do if Battle.Is_NPC[i] < 4 then text(text_x,text_y, Is_NPC[Battle.Is_NPC[i]] .. " " .. bizstring.hex(Battle.Address[i])) if Battle.Current_Turn == i-1 and Battle.Attack_Type[i] == 0 then text(0,216, l_text) end 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('Status %s (%d)', Status(Battle.Status[i]), Battle.Status_Meter[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 local i = 4 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) local story = read8(Addresses.Story) local area = read8(Addresses.Area) local text_y = 160 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 text(0, text_y, string.format("%02d:%02d:%02d.%02d",read8(Addresses.Hours), read8(Addresses.Minutes), read8(Addresses.Seconds), read8(Addresses.Frames))) text_y = text_y + 8 if Story[story] ~= nil then text(0, text_y, story .. ": " .. Story[story]) else text(0, text_y, story) end text_y = text_y + 8 if Area[area] ~= nil then text(0, text_y, area .. ": " .. Area[area]) else text(0, text_y, area) end text_y = text_y + 8 text(0,text_y,string.format('%.6f,%.6f\nPTR: %08X\nX: %08X\nY: %08X',read32(Harry.x)/65536.0, read32(Harry.y)/65536.0,read32(Addresses.Harry_pointer_x), Harry.x, Harry.y)) if (state == 9) then display_battle() end emu.frameadvance() end

1733955172