SHARE
TWEET

Untitled

a guest Dec 14th, 2019 86 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1.  
  2. -- 2 bytes
  3. local numEntitiesInCombatAddr = 0x030067F6
  4.  
  5. -- 0x0300055C
  6. local playerPtrAddr = 0x0300055C
  7. -- see : https://pastebin.com/WEzL29NV for what I've mapped conclusively.
  8. -- note: every 'entity' in combat (enemies \ the player,  not projecitles, or it could be, but i've no idea if it is)
  9. -- will use a structure like this. size 0x32C.
  10. -- so to get to the next 'entity' just add from 0x0300055C +0x32C and continue stepping until you reach
  11. -- the value at 0x030067F6, which is the number of entities in combat.
  12.  
  13. -- if you just want the first entity that isn't the player, just start at 0x03000888 and then step @ 0x32C increments.
  14.  
  15. -- 0x02000028
  16. --  the random seed used outside of combat.
  17. -- It changes when you:
  18. --  get an item
  19. -- leave dialogue (except talking to summon beast)
  20. -- enter combat
  21. -- exit combat
  22. -- enter transition
  23. -- exit transition
  24. -- ??
  25.  
  26. local itemGetAddr   =  0x0028
  27.  
  28. -- 0x03002ED4
  29. -- The counter the game increments used for RNG.
  30. local frameIncAddr =  0x2ED4
  31.  
  32. -- 0x0200FDF0
  33. -- Number of steps until you will encounter an enemy.
  34. local encounterTimerAddr = 0xFDF0
  35.  
  36. - 0x02001528
  37. -- Pointer to current area name using bytes that equate to how it interprets glyph fonts.
  38. local currentAreaNameAddr = 0x02001528
  39.  
  40.  
  41. local itemGet=0
  42. local prevItemGet=0
  43. local frameInc=0
  44. local encounterTimer=0
  45. local GameTransitionState=0
  46. local encounterTimerDisplay=0
  47. local GameFrameEnemyEncountered=0
  48. local areaName = ""
  49. local lastFacedMonsterIDRange=0x0
  50. local lastFacedMonsterNames=""
  51. local currentItemIDRange = 0x0
  52. local breakableType=0x0
  53. local framesToBreakFromType=0x0
  54.  
  55. -- Just your standard rand() LCG.
  56. function ChanceForItem(prevItem, frameCount)
  57.  
  58.        local r0 = prevItem
  59.        local r1 = frameCount
  60.        local r5 = r0 + r1
  61.  
  62.        
  63.        r0 = 0x343FD
  64.        r0 = r0 * r5
  65.  
  66.        
  67.        r0 = bit.band(r0,0xFFFFFFFF);
  68.  
  69.        r0 = r0 + 0x269EC3
  70.  
  71.        return bit.rshift(r0,16)
  72. end
  73.  
  74.  
  75.  
  76. -- 0x00 = BARRELS\BOXES, Entry Woods Area(s)
  77. -- 0x01 = LEAFS, Entry Woods Area(s)
  78. -- 0x02 = TREE STUMPS, Entry Woods Area(s)
  79.  
  80. -- area name determines breakType
  81. function ItemIDRangeToName(id)
  82.    
  83.     if string.find(areaName, "Entry Woods", 1, true) then
  84.  
  85.        if breakableType == 0x0 then
  86.           if id < 0x0F then
  87.              return "Iron Ore"
  88.           elseif id >= 0x0F and id < 0x14 then
  89.              return "Tough Leather"
  90.           elseif id >= 0x14 and id < 0x19 then
  91.              return "5B"
  92.           else
  93.              return "Small worm (probably)"
  94.           end
  95.        elseif  breakableType == 0x01 then
  96.             if id < 0x04 then
  97.                return "Zasso Leaf"
  98.            elseif id > 0x04 and id < 0x0E then
  99.                return "Flat Stone"
  100.            elseif id >= 0x0F and id <= 0x13 then
  101.                return "2B"
  102.           else
  103.                return "Nothing"
  104.           end
  105.        elseif  breakableType == 0x02 then
  106.        
  107.           -- 0x00 - 0x0E = tough leather
  108.           -- 0x0F - 0x31 = flat stone
  109.           -- 0x32 - 0x4F = small worm
  110.           -- 0x50 - 0x54 = tree branch
  111.          
  112.             if id <= 0x0E then
  113.                return "Tough Leather"
  114.            elseif id >= 0x0F and id <= 0x31 then
  115.                return "Flat Stone"
  116.            elseif id >= 0x32 and id <= 0x4F then
  117.                return " Small Worm"
  118.            elseif id >= 0x50 and id <= 0x54 then
  119.                return "Tree Branch"
  120.            else
  121.                return "Nothing"
  122.            end
  123.        elseif  breakableType == 0x03 then
  124.          
  125.        end
  126.        
  127.     end
  128.    
  129.     return "Not documented (check your area.)"
  130. end
  131.  
  132. -- What the game uses for converting a 'seed'  to a range of possibilities on a step increment.
  133. -- Usually passes in 0x64 (100 dec)
  134. function ChanceFromStep(randItem, step)
  135.     local uVar1 = 0
  136.     local uVar2 = 0
  137.     local uVar3 = 0
  138.     local temp = 0
  139.     local temp2 = 0
  140.     local temp3 = 0
  141.     local temp4 = 0
  142.    
  143.     uVar3 = 1
  144.    
  145.     if step == 0 then
  146.        return 0
  147.     end
  148.    
  149.     if step < 0 then
  150.       step = math.abs(step)
  151.     end
  152.    
  153.     uVar1 = randItem
  154.     if randItem < 0 then
  155.         uVar1 = math.abs(randItem)
  156.     end
  157.    
  158.    
  159.     if step <= uVar1 then
  160.        while step <  0x10000000 and step < uVar1 do
  161.                 step = bit.lshift(step, 0x4)
  162.                 uVar3 = bit.lshift(uVar3, 0x4)
  163.        end
  164.  
  165.        while step < 0x80000000 and step < uVar1 do
  166.                  step = bit.lshift(step, 0x1)
  167.                  uVar3 = bit.lshift(uVar3, 0x1)
  168.        end
  169.        
  170.  
  171.        
  172.        while true do
  173.             uVar2 = 0
  174.             if step <= uVar1 then
  175.                uVar1 = uVar1 - step
  176.             end
  177.            
  178.  
  179.            
  180.             if bit.rshift(step, 0x1) <= uVar1 then
  181.                 uVar1 = uVar1 - bit.rshift(step, 0x1)
  182.                
  183.                                
  184.                 temp =  bit.rshift(uVar3, 0x1)
  185.                 temp2 = bit.lshift(uVar3, 0x1f)
  186.                
  187.                 uVar2 =  bit.bor(temp, temp2)
  188.             end
  189.            
  190.             if bit.rshift(step, 0x2) <= uVar1 then
  191.            
  192.                 uVar1 = uVar1 - bit.rshift(step, 0x2)
  193.  
  194.                
  195.                 temp = bit.rshift(uVar3, 0x2)
  196.                 temp2 = bit.lshift(uVar3, 0x1e)
  197.                
  198.                 temp3 = bit.bor(uVar2,  temp)
  199.                 temp3 = bit.bor(temp3, temp2)
  200.                
  201.                 uVar2 = temp3
  202.             end
  203.            
  204.             if bit.rshift(step, 0x3) <= uVar1 then
  205.            
  206.                uVar1 = uVar1 - bit.rshift(step, 0x3)
  207.                
  208.                temp = bit.lshift(uVar3, 0x1d)
  209.                
  210.                uVar2 = bit.bor(uVar2, temp)
  211.                
  212.             end
  213.            
  214.             if uVar1 == 0 or bit.rshift(uVar3, 0x4) == 0 then
  215.                 break
  216.             end
  217.            
  218.             step = bit.rshift(step, 0x4)
  219.             uVar3 = bit.rshift(uVar3, 0x4)
  220.            
  221.        end
  222.        
  223.          
  224.          -- stop @ PAK SRAM
  225.          uVar2 = bit.band(uVar2, 0xe0000000)
  226.  
  227.          -- wasn't cleanly divisible, add back up until we are
  228.          if uVar2 ~= 0 then
  229.  
  230.             if bit.band(bit.lshift(uVar3, 0x1d), uVar2) ~= 0 then
  231.                uVar1 = uVar1 + bit.rshift(step, 0x3)
  232.             end
  233.            
  234.             temp3 = bit.lshift(uVar3, 0x1e)
  235.             temp4 = bit.rshift(uVar3, 0x2)
  236.            
  237.             temp2 = bit.bor(temp4, temp3)
  238.            
  239.             if bit.band(uVar2, temp2) ~= 0 then
  240.                uVar1 = uVar1 + bit.rshift(step, 0x2)
  241.             end
  242.            
  243.             temp3 = bit.lshift(uVar3, 0x1f)
  244.             temp4 = bit.rshift(uVar3, 0x2)
  245.            
  246.             temp2 = bit.bor(temp4, temp3)
  247.            
  248.             if bit.band(uVar2, temp2) ~= 0 then
  249.                uVar1 = uVar1 + bit.rshift(step, 0x1)
  250.             end
  251.            
  252.          end
  253.          
  254.     end
  255.    
  256.    
  257.     if randItem < 0 then
  258.        uVar1 = -uVar1
  259.     end
  260.    
  261.     return  uVar1
  262. end
  263.  
  264. -- Scrapped usage because calculation for crit is done based on VCOUNT I/O register.
  265. --function FUN_0803070C()
  266. function ThrowForCritChance()
  267.     local result  = 0
  268.     local bUnk=0
  269.    
  270.     result = memory.read_u32_le(0x0004, "IWRAM");
  271.    
  272.     -- not sure what this byte is
  273.     bUnk = memory.read_u8(0x000F, "IWRAM");
  274.  
  275.     if bUnk == 0 then
  276.        result = result + 0x02
  277.     end
  278.    
  279.     return result
  280. end
  281.  
  282. -- Can't work properly because of VCOUNT I/O register changing mid-frame.
  283. -- Scrapped usage.
  284. -- 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.
  285. function WillCrit(chance, frameCount)
  286.  
  287. local bResult=false
  288. local result = 0
  289.  
  290. local prevRand =  memory.read_u16_le(0x001E, "IWRAM");
  291. local scanLineResult = memory.read_u8(0x04000006);
  292. local bIncreasedCritChance = memory.read_u8(0x03000631);
  293.  
  294. local comparator  = 0x64
  295.  
  296. if bIncreasedCritChance then
  297.     -- so we have a larger number to compare <= to
  298.     comparator  = comparator + 0x64
  299. end
  300.  
  301.  
  302. scanLineResult = bit.band(scanLineResult, 0xFF);
  303. result = chance;
  304.  
  305. result = ((prevRand + result) * 0x343FD) + 0x00269EC3;
  306. result = bit.rshift(result, 16);
  307. result = (scanLineResult + frameCount) + result;
  308.  
  309.  
  310. result = ChanceFromStep(result, 1000);
  311.  
  312.  if result <= comparator then
  313.     bResult=true
  314.  end
  315.  
  316. return bResult
  317. end
  318.  
  319.  
  320. -- 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.
  321. -- needs an adjustment for the increment of startFrame+i+(here) because different objects take differing amounts of frames to break.
  322. -- i didn't get around to changing it but it should be simple to adjust.
  323. function ItemList_FromFrameRange(seed, startFrame, range, itemWanted, framesToBreak)
  324.    local resultTable = { }
  325.  
  326.     for i = 0, range do
  327.          -- from startFrame to range. do startFrame+i+framesToBreak
  328.          if string.find(ItemIDRangeToName(ChanceFromStep(ChanceForItem(seed,  startFrame+i+framesToBreak), 0x64)), itemWanted) ~= nil then
  329.             table.insert(resultTable, startFrame+i)
  330.          end
  331.     end
  332.    
  333.    return resultTable
  334. end
  335.  
  336.  
  337. -- 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
  338. -- and the transition cannot be 0x08.
  339.  
  340. function GetFacingMonsterOnFrame(prevSeed, theFrame)
  341.       local result = 0
  342.      
  343.  
  344.       local seed = prevSeed
  345.  
  346.       -- just more usage of rand() LCG constants
  347.       result = (seed + theFrame) * 0x343FD + 0x00269EC3;
  348.       result = bit.rshift(result, 0x10)
  349.      
  350.       -- 0x64 for step.
  351.       result = ChanceFromStep(result, 0x64);
  352.      
  353.       return result;
  354. end
  355.  
  356.  
  357.  
  358. local keysPrev = {}
  359. local fromAttackFrame=0
  360. local lockPrevSeed=false
  361. local seedForEncounteredEnemy=0
  362.  
  363.  
  364. -- Objects that are breakable and that may give items take differing amount of frames to 'break' before it rolls RNG to determine
  365. -- 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
  366. -- return the frames the object takes to break.
  367.  
  368. function GetFramesToBreakFromType()
  369.      if string.find(areaName, "Entry Woods", 1, true) then
  370.          if breakableType == 0x0 then
  371.             return 40
  372.          elseif breakableType == 0x01 then
  373.             return 34
  374.          elseif breakableType == 0x02 then
  375.             return 37
  376.          end
  377.      end
  378.      
  379.      return 40
  380. end
  381.      
  382.  
  383. -- I made this for determining what area I was in because I couldn't find the area\roomID in memory.
  384. -- Worked well enough, lol.
  385. function MapGlyphToAscii(startAddr, n)
  386.  
  387.     -- our halfword, to read in
  388.     local hw = 0
  389.     local lsr = 0
  390.     local letter=0
  391.    
  392.     -- result string to return
  393.     local result = ""
  394.    
  395.     for i = 0, n, 0x02 do
  396.          hw = memory.read_u16_le(startAddr+i)
  397.          
  398.          -- check outliers first.
  399.  
  400.          -- 0x4081 = ' '
  401.          -- 0x9781 = ' '
  402.          -- 0x6681 = Apostrophe ( ' )
  403.          -- 0x6781 = Quotes ( " )
  404.          
  405.          -- +0x100 per character
  406.          -- 0x6082 - 0x7982 = 'A' - 'Z'
  407.          -- 0x8182 - 0x9A82 = 'a' - 'z'
  408.          
  409.          
  410.          
  411.          -- A = 0x6082
  412.          -- e = 0x8582
  413.          -- r  = 0x9282
  414.          -- a = 0x8182
  415.          
  416.          if hw == 0x00 then
  417.             -- kill the loop, we have our ASCII representation.
  418.             break
  419.         end
  420.        
  421.         lsr = bit.rshift(hw, 0x0C);
  422.        
  423.         -- i think 0x9781 is some weird single char tab space, but it doesn't matter, translate it to space
  424.          if hw == 0x4081 or hw == 0x9781 then
  425.             result = result .. ' ';
  426.         elseif hw == 0x6681 then
  427.             result = result .. "'";
  428.         elseif hw == 0x6781 then
  429.            result = result .. "\"";
  430.         else
  431.        
  432.            
  433.            if lsr == 0x04 or lsr == 0x05 then
  434.               letter = '0'
  435.              
  436.               -- do numerals
  437.               for i = 0x4F82, 0x5882, 0x100 do
  438.                  if hw == i then
  439.                     result = result .. letter
  440.                     break
  441.                  else
  442.                     letter = string.char(string.byte(letter)+1);
  443.                  end
  444.                end
  445.            elseif lsr == 0x06 or lsr == 0x07 then
  446.              
  447.                letter = 'A'
  448.                -- do uppercase
  449.                for i = 0x6082, 0x7982, 0x100 do
  450.                
  451.                    if hw == i then
  452.                       result = result .. letter
  453.                       break
  454.                    else                  
  455.                                        -- increment letter
  456.                      letter = string.char(string.byte(letter)+1);
  457.                    end
  458.                end
  459.            
  460.            elseif lsr == 0x08 or lsr == 0x09 then
  461.              
  462.                letter = 'a'
  463.                -- do lowercase
  464.                for i = 0x8182, 0x9A82, 0x100 do
  465.                
  466.                    if hw == i then
  467.  
  468.                       result = result .. letter
  469.                       break
  470.                   else
  471.                                    -- increment letter
  472.                     letter = string.char(string.byte(letter)+1);
  473.                   end
  474.                end
  475.                
  476.  
  477.            end
  478.  
  479.         end
  480.        
  481.     end
  482.    
  483.     return result
  484. end
  485.  
  486. -- This crap is awful, and would take far too much work to map out entirely.
  487. -- Basically scrapped it.
  488. function GetEnemyNameFromRangeID(areaName, rid)
  489.    
  490.     local result =  "Not documented";
  491.     if areaName == "Entry Woods Area 3" then
  492.  
  493.         if rid >= 0x02 and rid <= 0x0D then
  494.             result = "Spirit (right)";
  495.         elseif rid  >= 0x11 and rid <= 0x1F then
  496.             result = "Hopdog (right)";
  497.         elseif rid >= 0x22 and rid <= 0x29 then
  498.             result = "Slime (2 right)";
  499.         elseif rid == 0x2A then
  500.             result = "Slime (left), Slime (right)";
  501.         elseif rid == 0x2C then
  502.             result = "Slime (2 right)";
  503.         elseif rid >=  0x2F and rid <= 0x33 then
  504.             result = "Slime (3) (1 left, 2 right)";
  505.         elseif rid >= 0x34 and rid <= 0x3C then
  506.             result = "Slime (3) (3 right)";
  507.         elseif rid >= 0x3F and rid <= 0x4B then
  508.             result = "Hopdog (2) (2 right)";
  509.         elseif rid >= 0x50 and rid <= 0x53  then
  510.             result = "Hopdog, Cuckoo, Cuckoo (right)";
  511.         elseif rid >= 0x56 and rid <= 0x5D then
  512.             result = "Spirit (right), Hopdog (right)";
  513.         elseif rid == 0x5E then
  514.             result = "Spirit (left), Hopdog (right)";
  515.         elseif rid >= 0x61 and rid <= 0x62 then
  516.             result = "Spirit (right)";
  517.         end
  518.        
  519.     end
  520.    
  521.     return result;
  522. end
  523.  
  524.  
  525. while true do
  526.    
  527.     prevItemGet=itemGet
  528.  
  529.     itemGet = memory.read_u16_le(itemGetAddr, "EWRAM");
  530.     frameInc = memory.read_u32_le(frameIncAddr, "IWRAM");
  531.     encounterTimer = memory.read_u16_le(encounterTimerAddr, "EWRAM");
  532.    
  533.     -- This has possible values of 0x02, 0x03, 0x05 and 0x08.
  534.     -- 0x02 is used when transitioning between rooms and other states.
  535.     -- 0x03 is used while in combat.
  536.     -- 0x05 is used when transitioning between rooms and while in dialogue.
  537.     -- 0x08 is when have control of your character outside of combat.
  538.     GameTransitionState = memory.read_u8(0x030065DC);
  539.    
  540.     gui.text(70,40, "GameFrame: " .. frameInc)
  541.    
  542.     encounterTimerDisplay = encounterTimer /  16;
  543.    
  544.     areaName = MapGlyphToAscii(currentAreaNameAddr , 0x60);
  545.     gui.text(70,60, string.format("Area: %s", areaName));
  546.    
  547.     -- Some quirks, but it'll work.
  548.     if GameTransitionState ~= 3 then
  549.         gui.text(70,80, "EncounterStepTimer: " .. string.format("%d", encounterTimerDisplay));
  550.     end
  551.  
  552.     -- So, this  is actually just a direct read to something like combatEntity->m_CharFlags
  553.     -- I only really documented what was set when a crit set to these, so you could have a 3 frame
  554.     -- heads up on if you crit or not (without waiting for the animation)
  555.    local charFlags = memory.read_u32_le(0x03000564);
  556.    
  557.    -- 0x2010           = Is Attack Flag
  558.    -- 0x40000000  = Is Crit Flag
  559.    
  560.    if GameTransitionState == 3 and bit.band(charFlags, 0x2010) > 0 and bit.band(charFlags, 0x40000000) > 0 then
  561.       gui.text(70, 120, "Crit")
  562.    end
  563.    
  564.    
  565.     local kCheck = {"X", "Y", "B", "N"}
  566.     local keys = input.get()
  567.    
  568.     for i, v in ipairs(kCheck) do
  569.  
  570.          if v == "Y" and keys[v] == true and keysPrev[v] ~= true then
  571.                   -- needs an adjustment to work again (see the comment(s) above the function definition)
  572.                   -- seed, startFrame, range, itemWanted
  573.                   -- console.log(ItemList_FromFrameRange(itemGet, frameInc, 30, "Iron Ore"))
  574.          end
  575.          
  576.          -- Increment once on breakable type.
  577.          if v == "B" and keys[v] == true and keysPrev[v] ~= true then
  578.                  breakableType = breakableType + 1
  579.          end
  580.          
  581.          -- Decrement once on breakable type.
  582.          if v == "N" and keys[v] == true and keysPrev[v] ~= true then
  583.                if breakableType ~= 0 then
  584.                   breakableType = breakableType - 1
  585.                end
  586.          end
  587.          
  588.     end
  589.    
  590.     gui.text(70, 140, string.format("BreakableType = %d", breakableType));
  591.    
  592.     if GameTransitionState ~=3 then
  593.    
  594.        framesToBreakFromType = GetFramesToBreakFromType()
  595.        currentItemIDRange = ChanceFromStep(ChanceForItem(prevItemGet, frameInc + framesToBreakFromType), 0x64)
  596.        
  597.        gui.text(70,160, "Item (if swing on next frame): " .. string.format("Item=%s", ItemIDRangeToName(currentItemIDRange)));
  598.  
  599.     end
  600.    
  601.     if encounterTimerDisplay == 0 and GameTransitionState == 0x05 and GameFrameEnemyEncountered == 0 then
  602.    
  603.          -- one frame earlier's seed for encountered enemy.
  604.          seedForEncounteredEnemy = prevItemGet
  605.          GameFrameEnemyEncountered=frameInc-0x01
  606.          
  607.     end
  608.  
  609.     -- HaveControl and EncounterTimer reset
  610.     if GameTransitionState == 0x08 and encounterTimerDisplay ~= 0 then
  611.  
  612.        seedForEncounteredEnemy=0
  613.        GameFrameEnemyEncountered = 0
  614.        
  615.     end
  616.    
  617.     -- All of these check for no control or in-combat
  618.     if GameTransitionState == 0x05 or GameTransitionState == 0x06 or GameTransitionState == 0x03 then
  619.        
  620.         -- Make sure we have an encounter frame.
  621.         if GameFrameEnemyEncountered ~= 0 then
  622.        
  623.             lastFacedMonsterIDRange = GetFacingMonsterOnFrame(seedForEncounteredEnemy, GameFrameEnemyEncountered);
  624.             lastFacedMonsterNames = GetEnemyNameFromRangeID(areaName, lastFacedMonsterIDRange);
  625.             gui.text(70, 180, string.format("GFE: %d, EnemyRangeID: %x, Name: %s", GameFrameEnemyEncountered, lastFacedMonsterIDRange, lastFacedMonsterNames))
  626.            
  627.         end
  628.        
  629.     end
  630.  
  631.    
  632.    emu.frameadvance();
  633. end
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top