Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- 2 bytes
- local numEntitiesInCombatAddr = 0x030067F6
- -- 0x0300055C
- local playerPtrAddr = 0x0300055C
- -- see : https://pastebin.com/WEzL29NV for what I've mapped conclusively.
- -- note: every 'entity' in combat (enemies \ the player, not projecitles, or it could be, but i've no idea if it is)
- -- will use a structure like this. size 0x32C.
- -- so to get to the next 'entity' just add from 0x0300055C +0x32C and continue stepping until you reach
- -- the value at 0x030067F6, which is the number of entities in combat.
- -- if you just want the first entity that isn't the player, just start at 0x03000888 and then step @ 0x32C increments.
- -- 0x02000028
- -- the random seed used outside of combat.
- -- It changes when you:
- -- get an item
- -- leave dialogue (except talking to summon beast)
- -- enter combat
- -- exit combat
- -- enter transition
- -- exit transition
- -- ??
- local itemGetAddr = 0x0028
- -- 0x03002ED4
- -- The counter the game increments used for RNG.
- local frameIncAddr = 0x2ED4
- -- 0x0200FDF0
- -- Number of steps until you will encounter an enemy.
- local encounterTimerAddr = 0xFDF0
- - 0x02001528
- -- Pointer to current area name using bytes that equate to how it interprets glyph fonts.
- local currentAreaNameAddr = 0x02001528
- local itemGet=0
- local prevItemGet=0
- local frameInc=0
- local encounterTimer=0
- local GameTransitionState=0
- local encounterTimerDisplay=0
- local GameFrameEnemyEncountered=0
- local areaName = ""
- local lastFacedMonsterIDRange=0x0
- local lastFacedMonsterNames=""
- local currentItemIDRange = 0x0
- local breakableType=0x0
- local framesToBreakFromType=0x0
- -- Just your standard rand() LCG.
- function ChanceForItem(prevItem, frameCount)
- local r0 = prevItem
- local r1 = frameCount
- local r5 = r0 + r1
- r0 = 0x343FD
- r0 = r0 * r5
- r0 = bit.band(r0,0xFFFFFFFF);
- r0 = r0 + 0x269EC3
- return bit.rshift(r0,16)
- end
- -- 0x00 = BARRELS\BOXES, Entry Woods Area(s)
- -- 0x01 = LEAFS, Entry Woods Area(s)
- -- 0x02 = TREE STUMPS, Entry Woods Area(s)
- -- area name determines breakType
- function ItemIDRangeToName(id)
- if string.find(areaName, "Entry Woods", 1, true) then
- if breakableType == 0x0 then
- if id < 0x0F then
- return "Iron Ore"
- elseif id >= 0x0F and id < 0x14 then
- return "Tough Leather"
- elseif id >= 0x14 and id < 0x19 then
- return "5B"
- else
- return "Small worm (probably)"
- end
- elseif breakableType == 0x01 then
- if id < 0x04 then
- return "Zasso Leaf"
- elseif id > 0x04 and id < 0x0E then
- return "Flat Stone"
- elseif id >= 0x0F and id <= 0x13 then
- return "2B"
- else
- return "Nothing"
- end
- elseif breakableType == 0x02 then
- -- 0x00 - 0x0E = tough leather
- -- 0x0F - 0x31 = flat stone
- -- 0x32 - 0x4F = small worm
- -- 0x50 - 0x54 = tree branch
- if id <= 0x0E then
- return "Tough Leather"
- elseif id >= 0x0F and id <= 0x31 then
- return "Flat Stone"
- elseif id >= 0x32 and id <= 0x4F then
- return " Small Worm"
- elseif id >= 0x50 and id <= 0x54 then
- return "Tree Branch"
- else
- return "Nothing"
- end
- elseif breakableType == 0x03 then
- end
- end
- return "Not documented (check your area.)"
- end
- -- What the game uses for converting a 'seed' to a range of possibilities on a step increment.
- -- Usually passes in 0x64 (100 dec)
- function ChanceFromStep(randItem, step)
- local uVar1 = 0
- local uVar2 = 0
- local uVar3 = 0
- local temp = 0
- local temp2 = 0
- local temp3 = 0
- local temp4 = 0
- uVar3 = 1
- if step == 0 then
- return 0
- end
- if step < 0 then
- step = math.abs(step)
- end
- uVar1 = randItem
- if randItem < 0 then
- uVar1 = math.abs(randItem)
- end
- if step <= uVar1 then
- while step < 0x10000000 and step < uVar1 do
- step = bit.lshift(step, 0x4)
- uVar3 = bit.lshift(uVar3, 0x4)
- end
- while step < 0x80000000 and step < uVar1 do
- step = bit.lshift(step, 0x1)
- uVar3 = bit.lshift(uVar3, 0x1)
- end
- while true do
- uVar2 = 0
- if step <= uVar1 then
- uVar1 = uVar1 - step
- end
- if bit.rshift(step, 0x1) <= uVar1 then
- uVar1 = uVar1 - bit.rshift(step, 0x1)
- temp = bit.rshift(uVar3, 0x1)
- temp2 = bit.lshift(uVar3, 0x1f)
- uVar2 = bit.bor(temp, temp2)
- end
- if bit.rshift(step, 0x2) <= uVar1 then
- uVar1 = uVar1 - bit.rshift(step, 0x2)
- temp = bit.rshift(uVar3, 0x2)
- temp2 = bit.lshift(uVar3, 0x1e)
- temp3 = bit.bor(uVar2, temp)
- temp3 = bit.bor(temp3, temp2)
- uVar2 = temp3
- end
- if bit.rshift(step, 0x3) <= uVar1 then
- uVar1 = uVar1 - bit.rshift(step, 0x3)
- temp = bit.lshift(uVar3, 0x1d)
- uVar2 = bit.bor(uVar2, temp)
- end
- if uVar1 == 0 or bit.rshift(uVar3, 0x4) == 0 then
- break
- end
- step = bit.rshift(step, 0x4)
- uVar3 = bit.rshift(uVar3, 0x4)
- end
- -- stop @ PAK SRAM
- uVar2 = bit.band(uVar2, 0xe0000000)
- -- wasn't cleanly divisible, add back up until we are
- if uVar2 ~= 0 then
- if bit.band(bit.lshift(uVar3, 0x1d), uVar2) ~= 0 then
- uVar1 = uVar1 + bit.rshift(step, 0x3)
- end
- temp3 = bit.lshift(uVar3, 0x1e)
- temp4 = bit.rshift(uVar3, 0x2)
- temp2 = bit.bor(temp4, temp3)
- if bit.band(uVar2, temp2) ~= 0 then
- uVar1 = uVar1 + bit.rshift(step, 0x2)
- end
- temp3 = bit.lshift(uVar3, 0x1f)
- temp4 = bit.rshift(uVar3, 0x2)
- temp2 = bit.bor(temp4, temp3)
- if bit.band(uVar2, temp2) ~= 0 then
- uVar1 = uVar1 + bit.rshift(step, 0x1)
- end
- end
- end
- if randItem < 0 then
- uVar1 = -uVar1
- end
- return uVar1
- end
- -- Scrapped usage because calculation for crit is done based on VCOUNT I/O register.
- --function FUN_0803070C()
- function ThrowForCritChance()
- local result = 0
- local bUnk=0
- result = memory.read_u32_le(0x0004, "IWRAM");
- -- not sure what this byte is
- bUnk = memory.read_u8(0x000F, "IWRAM");
- if bUnk == 0 then
- result = result + 0x02
- end
- return result
- end
- -- Can't work properly because of VCOUNT I/O register changing mid-frame.
- -- Scrapped usage.
- -- I started checking for character combat flags instead (usage shown in main while true loop) this way there was a 3 frame heads up to know if you crit.
- function WillCrit(chance, frameCount)
- local bResult=false
- local result = 0
- local prevRand = memory.read_u16_le(0x001E, "IWRAM");
- local scanLineResult = memory.read_u8(0x04000006);
- local bIncreasedCritChance = memory.read_u8(0x03000631);
- local comparator = 0x64
- if bIncreasedCritChance then
- -- so we have a larger number to compare <= to
- comparator = comparator + 0x64
- end
- scanLineResult = bit.band(scanLineResult, 0xFF);
- result = chance;
- result = ((prevRand + result) * 0x343FD) + 0x00269EC3;
- result = bit.rshift(result, 16);
- result = (scanLineResult + frameCount) + result;
- result = ChanceFromStep(result, 1000);
- if result <= comparator then
- bResult=true
- end
- return bResult
- end
- -- returns a table that will tell you which frames (assuming you attack on that frame) you can get an item from a breakable object that would contain one.
- -- needs an adjustment for the increment of startFrame+i+(here) because different objects take differing amounts of frames to break.
- -- i didn't get around to changing it but it should be simple to adjust.
- function ItemList_FromFrameRange(seed, startFrame, range, itemWanted, framesToBreak)
- local resultTable = { }
- for i = 0, range do
- -- from startFrame to range. do startFrame+i+framesToBreak
- if string.find(ItemIDRangeToName(ChanceFromStep(ChanceForItem(seed, startFrame+i+framesToBreak), 0x64)), itemWanted) ~= nil then
- table.insert(resultTable, startFrame+i)
- end
- end
- return resultTable
- end
- -- Determines which rangeID of a monster you will face on a given frame (assuming you are to encounter one on that frame, so encounterTimer must be 0
- -- and the transition cannot be 0x08.
- function GetFacingMonsterOnFrame(prevSeed, theFrame)
- local result = 0
- local seed = prevSeed
- -- just more usage of rand() LCG constants
- result = (seed + theFrame) * 0x343FD + 0x00269EC3;
- result = bit.rshift(result, 0x10)
- -- 0x64 for step.
- result = ChanceFromStep(result, 0x64);
- return result;
- end
- local keysPrev = {}
- local fromAttackFrame=0
- local lockPrevSeed=false
- local seedForEncounteredEnemy=0
- -- Objects that are breakable and that may give items take differing amount of frames to 'break' before it rolls RNG to determine
- -- the item you will get. I made this so you could cycle through a 'type' based on the area name you are in and then it will
- -- return the frames the object takes to break.
- function GetFramesToBreakFromType()
- if string.find(areaName, "Entry Woods", 1, true) then
- if breakableType == 0x0 then
- return 40
- elseif breakableType == 0x01 then
- return 34
- elseif breakableType == 0x02 then
- return 37
- end
- end
- return 40
- end
- -- I made this for determining what area I was in because I couldn't find the area\roomID in memory.
- -- Worked well enough, lol.
- function MapGlyphToAscii(startAddr, n)
- -- our halfword, to read in
- local hw = 0
- local lsr = 0
- local letter=0
- -- result string to return
- local result = ""
- for i = 0, n, 0x02 do
- hw = memory.read_u16_le(startAddr+i)
- -- check outliers first.
- -- 0x4081 = ' '
- -- 0x9781 = ' '
- -- 0x6681 = Apostrophe ( ' )
- -- 0x6781 = Quotes ( " )
- -- +0x100 per character
- -- 0x6082 - 0x7982 = 'A' - 'Z'
- -- 0x8182 - 0x9A82 = 'a' - 'z'
- -- A = 0x6082
- -- e = 0x8582
- -- r = 0x9282
- -- a = 0x8182
- if hw == 0x00 then
- -- kill the loop, we have our ASCII representation.
- break
- end
- lsr = bit.rshift(hw, 0x0C);
- -- i think 0x9781 is some weird single char tab space, but it doesn't matter, translate it to space
- if hw == 0x4081 or hw == 0x9781 then
- result = result .. ' ';
- elseif hw == 0x6681 then
- result = result .. "'";
- elseif hw == 0x6781 then
- result = result .. "\"";
- else
- if lsr == 0x04 or lsr == 0x05 then
- letter = '0'
- -- do numerals
- for i = 0x4F82, 0x5882, 0x100 do
- if hw == i then
- result = result .. letter
- break
- else
- letter = string.char(string.byte(letter)+1);
- end
- end
- elseif lsr == 0x06 or lsr == 0x07 then
- letter = 'A'
- -- do uppercase
- for i = 0x6082, 0x7982, 0x100 do
- if hw == i then
- result = result .. letter
- break
- else
- -- increment letter
- letter = string.char(string.byte(letter)+1);
- end
- end
- elseif lsr == 0x08 or lsr == 0x09 then
- letter = 'a'
- -- do lowercase
- for i = 0x8182, 0x9A82, 0x100 do
- if hw == i then
- result = result .. letter
- break
- else
- -- increment letter
- letter = string.char(string.byte(letter)+1);
- end
- end
- end
- end
- end
- return result
- end
- -- This crap is awful, and would take far too much work to map out entirely.
- -- Basically scrapped it.
- function GetEnemyNameFromRangeID(areaName, rid)
- local result = "Not documented";
- if areaName == "Entry Woods Area 3" then
- if rid >= 0x02 and rid <= 0x0D then
- result = "Spirit (right)";
- elseif rid >= 0x11 and rid <= 0x1F then
- result = "Hopdog (right)";
- elseif rid >= 0x22 and rid <= 0x29 then
- result = "Slime (2 right)";
- elseif rid == 0x2A then
- result = "Slime (left), Slime (right)";
- elseif rid == 0x2C then
- result = "Slime (2 right)";
- elseif rid >= 0x2F and rid <= 0x33 then
- result = "Slime (3) (1 left, 2 right)";
- elseif rid >= 0x34 and rid <= 0x3C then
- result = "Slime (3) (3 right)";
- elseif rid >= 0x3F and rid <= 0x4B then
- result = "Hopdog (2) (2 right)";
- elseif rid >= 0x50 and rid <= 0x53 then
- result = "Hopdog, Cuckoo, Cuckoo (right)";
- elseif rid >= 0x56 and rid <= 0x5D then
- result = "Spirit (right), Hopdog (right)";
- elseif rid == 0x5E then
- result = "Spirit (left), Hopdog (right)";
- elseif rid >= 0x61 and rid <= 0x62 then
- result = "Spirit (right)";
- end
- end
- return result;
- end
- while true do
- prevItemGet=itemGet
- itemGet = memory.read_u16_le(itemGetAddr, "EWRAM");
- frameInc = memory.read_u32_le(frameIncAddr, "IWRAM");
- encounterTimer = memory.read_u16_le(encounterTimerAddr, "EWRAM");
- -- This has possible values of 0x02, 0x03, 0x05 and 0x08.
- -- 0x02 is used when transitioning between rooms and other states.
- -- 0x03 is used while in combat.
- -- 0x05 is used when transitioning between rooms and while in dialogue.
- -- 0x08 is when have control of your character outside of combat.
- GameTransitionState = memory.read_u8(0x030065DC);
- gui.text(70,40, "GameFrame: " .. frameInc)
- encounterTimerDisplay = encounterTimer / 16;
- areaName = MapGlyphToAscii(currentAreaNameAddr , 0x60);
- gui.text(70,60, string.format("Area: %s", areaName));
- -- Some quirks, but it'll work.
- if GameTransitionState ~= 3 then
- gui.text(70,80, "EncounterStepTimer: " .. string.format("%d", encounterTimerDisplay));
- end
- -- So, this is actually just a direct read to something like combatEntity->m_CharFlags
- -- I only really documented what was set when a crit set to these, so you could have a 3 frame
- -- heads up on if you crit or not (without waiting for the animation)
- local charFlags = memory.read_u32_le(0x03000564);
- -- 0x2010 = Is Attack Flag
- -- 0x40000000 = Is Crit Flag
- if GameTransitionState == 3 and bit.band(charFlags, 0x2010) > 0 and bit.band(charFlags, 0x40000000) > 0 then
- gui.text(70, 120, "Crit")
- end
- local kCheck = {"X", "Y", "B", "N"}
- local keys = input.get()
- for i, v in ipairs(kCheck) do
- if v == "Y" and keys[v] == true and keysPrev[v] ~= true then
- -- needs an adjustment to work again (see the comment(s) above the function definition)
- -- seed, startFrame, range, itemWanted
- -- console.log(ItemList_FromFrameRange(itemGet, frameInc, 30, "Iron Ore"))
- end
- -- Increment once on breakable type.
- if v == "B" and keys[v] == true and keysPrev[v] ~= true then
- breakableType = breakableType + 1
- end
- -- Decrement once on breakable type.
- if v == "N" and keys[v] == true and keysPrev[v] ~= true then
- if breakableType ~= 0 then
- breakableType = breakableType - 1
- end
- end
- end
- gui.text(70, 140, string.format("BreakableType = %d", breakableType));
- if GameTransitionState ~=3 then
- framesToBreakFromType = GetFramesToBreakFromType()
- currentItemIDRange = ChanceFromStep(ChanceForItem(prevItemGet, frameInc + framesToBreakFromType), 0x64)
- gui.text(70,160, "Item (if swing on next frame): " .. string.format("Item=%s", ItemIDRangeToName(currentItemIDRange)));
- end
- if encounterTimerDisplay == 0 and GameTransitionState == 0x05 and GameFrameEnemyEncountered == 0 then
- -- one frame earlier's seed for encountered enemy.
- seedForEncounteredEnemy = prevItemGet
- GameFrameEnemyEncountered=frameInc-0x01
- end
- -- HaveControl and EncounterTimer reset
- if GameTransitionState == 0x08 and encounterTimerDisplay ~= 0 then
- seedForEncounteredEnemy=0
- GameFrameEnemyEncountered = 0
- end
- -- All of these check for no control or in-combat
- if GameTransitionState == 0x05 or GameTransitionState == 0x06 or GameTransitionState == 0x03 then
- -- Make sure we have an encounter frame.
- if GameFrameEnemyEncountered ~= 0 then
- lastFacedMonsterIDRange = GetFacingMonsterOnFrame(seedForEncounteredEnemy, GameFrameEnemyEncountered);
- lastFacedMonsterNames = GetEnemyNameFromRangeID(areaName, lastFacedMonsterIDRange);
- gui.text(70, 180, string.format("GFE: %d, EnemyRangeID: %x, Name: %s", GameFrameEnemyEncountered, lastFacedMonsterIDRange, lastFacedMonsterNames))
- end
- end
- emu.frameadvance();
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement