Advertisement
Guest User

Untitled

a guest
Dec 14th, 2019
169
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 16.58 KB | None | 0 0
  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
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement