News:

As a consequence of the forum being updated and repaired, the chatbox has been lost.
However, you can still come say hi on our Discord server!

Main Menu

More RNG Questions

Started by Plexa, 28, August, 2017, 10:21:09 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Plexa

Thinking of seriously rerouting GS2 any% next week and there's two things that will make that a lot easier.

1) Randomly Generated Stats on File Generation

When creating a new file, Felix's party's stats are generated upon loading the rename character box. Isaac's party's stats and djinn are generated upon confirming that no PW is required. It would be convenient to know how the game uses the GRN seed to do this, so that I can use external scripts to find the ideal stats/djinn combination.

For reference, me and Zetonegi both have 'good' setups as is. Mine is easier but generates worse stats for Jenna which ends up making a difference at Serpent. Zetonegi's is pretty good but takes a long time to set up. Finding a happy intermediate or a strict improvement would be desirable.

2) Attacks First/Caught By Surprise

Zetonegi wrote a script to dump the first 2000 or so BRN seeds that give attacks first or caught by surprise. I'd prefer to just read the BRN directly and determine if the next fight has either of these properties.

By cross checking his list of numbers, it looks like it is necessary (but not sufficient) for the last three hex digits of the BRN to be less than or equal to 0x0FF. While caught by surprise must be less than or equal to 0x00FF. But beyond this check I haven't been able to work out how to predict attacks first or caught by surprise.

Daddy Poi's Oily Gorillas

#1
I guess we can start with #2, since I kinda have it already...

Quote from: From my GS2 Documentation08119AD0 = if [0200048B]=00, it's checked randomly (below); if 06, your party is caught by surprise:
1/16 chance for your party to attack first.
1/32 chance for your party to be caught by surprise.

So that's generate number. (16-bit) & 0xF ; If that's 0, you attack first... if not.... then generate another number (16-bit) & 0x1F, if that's 0, your party is caught by surprise. (This second number is not generated if you are attacking first; and these checks are not made if [0200048B] is not 00.)

Pseudo-code: (To show similar formatting of GS's code.)
if ([0200048B] == 00)
{
    if ((brn16() & 0xF) == 0)
    {
        You attack first.
    }
    else if ((brn16() & 0x1F) == 0)
    {
        You are caught by surprise.
    }
}
else if ([0200048B] == 06)
{
    You are caught by surprise.
}


And as always, where I say 16-bit just means the bytes on the left/right of the 32-bit are always ignored/removed for the actual calculations. (Except for calculating the seed, but anyway.)


@0200048B = This is also in my documentation:
Quote0200048B = Battle: Flee / Battle Type
00 = Normal
- 1/16 chance for your party to attack first.
- 1/32 chance for your party to be caught by surprise.
01 = ?
02 = No Flee option.
03/04 = "This is no time to be running away!"
06 = Your party is caught by surprise.
So it just goes to show you don't get the chance to attack first with bosses and stuff...


--

And #1... Hm...
Going to review code... some of which was doc'd in the image in this post:
http://forum.goldensunhacking.net/index.php?topic=2214.msg39054#msg39054
(Except that I may have to follow the function calls.)
But otherwise will have to get back to you on that.

It does looks like Isaac's party stats are generated with Felix's as well. (At first?) ... Hm.... So I guess it's generated twice? (Probably the same calculations as normal when you level up? Will need to check.) (EDIT:
EDIT: I think I know now... ALL PCs have their stats generated at once.... but djinn have stats, so Party 1's team is updated again only by the djinn stats (And not PC levels)?

Rename Felix:
  For each PC (all 8), level to (whatever level)

Rename Isaac:
  For each Party 1 PC.... Hmm....


level up function... (psuedo)


level += 1
if (level == 1)
{
    stats are the first values of stat growths....
}
level / 20 (Determines which value of stat growth to get)

current stat += ((upper stat growth - lower stat growth) + ((grn16 * 20) >> 16))  / 20

Note:  (grn16 * 20) >> 16 basically means a random number from 0-19.
Note 2: / is supose to be integral division. (Remove decimal places.)
----

for each pc
{
    for each level
    {
        for each stat
        {
            raise stat
        }
    }
}


080AF79C = PC Starting Data
PC * 0xB4
... and for the growths ( To calculate the address location of them.)
+0x50
+0x5C
+0x68
+0x74
+0x80
+0x8C
... and then for which in each..
+(level / 20) should get you the idea.

Alternately, you can make a table for them in the script.

(Would like to test to see if I missed something, though.)



How djinn are picked...

(Flint and Fizz are 100% obtained prior to checks.)
element = (grn16() * 4) >> 16
djinni (of element) = (grn16() * 7) >> 16
If we already have this djinni, do the above two again until we don't.
If the minimum and maximum between elements is greater than 1 (if this djinni were added), generate a new djinni.... (Go back up.)
(grn16() * 100) >> 16 ; Basically check against percents to add a djinni (Table at 080B1290) , If failed, go back up.)


Psuedo-code: (May not be exact, but should be enough... but this is mainly an example anyway, so...)

haveDjinni[0, 0] == 1; //add Flint
haveDjinni[1, 0] == 1; //add Fizz
int[] djinnCounts = {1, 1, 0, 0} //For each element: Venus, Mercury, Mars, Jupiter

int djinnToAdd = 0x10
while (djinnToAdd > 0)
{
    int element = (grn16() * 4) >> 16;
    int djinni = (grn16() * 7) >> 16;
    if (haveDjinni[element, djinni] == 0)
    {
        djinnCounts[element] += 1;
        int low = 9;
        int high = 0;
        //High/low calculations/checks
        for (int e = 0; e < 4; e++)
        {
            if (djinnCounts[e] < low)
            {
                low = djinnCounts[e];
            }
            if (djinnCounts[e] > high)
            {
                high = djinnCounts[e];
            }
        }
        djinnCounts[element] -= 1;
        if ((high - low) < = 1)
        {
            //Percents calculations
            if (((grn16() * 100) >> 16) < djinnPercents[element, djinni])
            {
                haveDjinni[element, djinni] = 1;
                djinnCounts[element] += 1;
                djinnToAdd -= 1;
            }
        }
    }
}


---
Might see if I can put all this (Level up calculations and Djinn picker) in LUA soon? But I'm a bit rusty with LUA... so I don't even know if I'll go on with it.
Golden Sun Docs: Broken Seal - The Lost Age - Dark Dawn | Mario Sports Docs: Mario Golf & Mario Tennis | Misc. Docs
Refer to Yoshi's Lighthouse for any M&L hacking needs...

Sometimes I like to compare apples to oranges. (Figuratively) ... They are both fruits, but which one would you eat more? (If taken literally, I'd probably choose apples.)
Maybe it is over-analyzing, but it doesn't mean the information is useless.


The only GS Discord servers with significance are:
Golden Sun Hacking Community
GS Speedrunning
/r/Golden Sun
GS United Nations
Temple of Kraden

Can you believe how small the Golden Sun Community is?

2+2=5 Don't believe me? Those are rounded decimal numbers. Take that, flat earth theorists! :)

Plexa

It'll take me some time to implement something which is able to utilise the stat generation code. Probably will have to write a script to search for combinations which gives us what we want, or at worst an excel/google sheet to calculate arbitrary combinations.

The attacks first/caught by surprise stuff can be implemented immediately though.

Let me just check my understanding, if 0xNMOPWRST is a hex number, then BRN16 returns 0xWR? or 0xOPWR? (I suppose it doesn't matter if you are & with 0xF or 0x1F though)

Daddy Poi's Oily Gorillas

#3
It would return OPWR.

WR is 8-bit, OPWR is 16-bit...


By the way, the Djinn Picker's done. Still got to do stat regeneration, though... but if using this script, it'll draw 1's for the djinn you'll get on next reroll...
local grnseed = 0
local brnseed = 0

function reset()
   grnseed = memory.readdword(0x030011BC)
   brnseed = memory.readdword(0x020054C8)
end
function grn16()
   g = grnseed
   m1 = 0x4e6d
   m2 = 0x41c6
   g1 = g*m1
   g2 = g*m2
   g2 = bit.band(g2,0xFFFF)
   g = g1 + g2*0x10000
   c=0x3039
   g = g+c
   g = bit.band(g,0xFFFFFFFF)
   grnseed = g
   g = bit.lshift(g,8)
   g = bit.rshift(g,16)
   return g
end
function brn16()
   g = brnseed
   m1 = 0x4e6d
   m2 = 0x41c6
   g1 = g*m1
   g2 = g*m2
   g2 = bit.band(g2,0xFFFF)
   g = g1 + g2*0x10000
   c=0x3039
   g = g+c
   g = bit.band(g,0xFFFFFFFF)
   brnseed = g
   g = bit.lshift(g,8)
   g = bit.rshift(g,16)
   return g
end
function djinnPercents(element, djinni)
   return memory.readword(0x080B1290 + ((element - 1) * 14) + ((djinni - 1) * 2))
end
function rollDjinn()
   reset()
   haveDjinni = {}
   haveDjinni[1] = {1, 0, 0, 0, 0, 0, 0}
   haveDjinni[2] = {1, 0, 0, 0, 0, 0, 0}
   haveDjinni[3] = {0, 0, 0, 0, 0, 0, 0}
   haveDjinni[4] = {0, 0, 0, 0, 0, 0, 0}
   djinnCounts = {1, 1, 0, 0}
   djinnToAdd = 16
   while djinnToAdd > 0 do
       element = 1 + bit.rshift(grn16() * 4, 16)
       djinni = 1 + bit.rshift(grn16() * 7, 16)
       if haveDjinni[element][djinni] == 0 then
           djinnCounts[element] = djinnCounts[element] + 1
           low = 9
           high = 0
           for i=1,4 do
               if djinnCounts[i] < low then
                   low = djinnCounts[i]
               end
               if djinnCounts[i] > high then
                   high = djinnCounts[i]
               end
           end
           djinnCounts[element] = djinnCounts[element] - 1
           if (high - low) <= 1 then
               if bit.rshift(grn16() * 100, 16) < djinnPercents(element, djinni) then
                   haveDjinni[element][djinni] = 1
                   djinnCounts[element] = djinnCounts[element] + 1
                   djinnToAdd = djinnToAdd - 1
               end
           end
       end
   end
   for i=1,4 do
       for j=1,7 do
           gui.text(195 + j * 5 ,0 + i * 6,haveDjinni[i][j])
       end
   end
   return
end

while true do
   rollDjinn()
   vba.frameadvance();
end
Golden Sun Docs: Broken Seal - The Lost Age - Dark Dawn | Mario Sports Docs: Mario Golf & Mario Tennis | Misc. Docs
Refer to Yoshi's Lighthouse for any M&L hacking needs...

Sometimes I like to compare apples to oranges. (Figuratively) ... They are both fruits, but which one would you eat more? (If taken literally, I'd probably choose apples.)
Maybe it is over-analyzing, but it doesn't mean the information is useless.


The only GS Discord servers with significance are:
Golden Sun Hacking Community
GS Speedrunning
/r/Golden Sun
GS United Nations
Temple of Kraden

Can you believe how small the Golden Sun Community is?

2+2=5 Don't believe me? Those are rounded decimal numbers. Take that, flat earth theorists! :)

Plexa

Yeah I was pretty sure that it was 0xOPWR, always good to get that confirmed!

Very nice of you to write out the code for determining djinn. Thanks!

Daddy Poi's Oily Gorillas

#5
Okay.

And you are welcome...


I've been working on the calculations for stats.... and I'm currently at this point.
The code's there, sort of, but I'm not getting the right results, so I shall look into this!

WIP code:
local grnseed = 0
local brnseed = 0

function reset()
    grnseed = memory.readdword(0x030011BC)
    brnseed = memory.readdword(0x020054C8)
end
function grn16()
    g = grnseed
    m1 = 0x4e6d
    m2 = 0x41c6
    g1 = g*m1
    g2 = g*m2
    g2 = bit.band(g2,0xFFFF)
    g = g1 + g2*0x10000
    c=0x3039
    g = g+c
    g = bit.band(g,0xFFFFFFFF)
    grnseed = g
    g = bit.lshift(g,8)
    g = bit.rshift(g,16)
    return g
end
function brn16()
    g = brnseed
    m1 = 0x4e6d
    m2 = 0x41c6
    g1 = g*m1
    g2 = g*m2
    g2 = bit.band(g2,0xFFFF)
    g = g1 + g2*0x10000
    c=0x3039
    g = g+c
    g = bit.band(g,0xFFFFFFFF)
    brnseed = g
    g = bit.lshift(g,8)
    g = bit.rshift(g,16)
    return g
end
function startingStats()
    stat = {}
    stat[1] = {0, 0, 0, 0, 0, 0, 0, 0}
    stat[2] = {0, 0, 0, 0, 0, 0, 0, 0}
    stat[3] = {0, 0, 0, 0, 0, 0, 0, 0}
    stat[4] = {0, 0, 0, 0, 0, 0, 0, 0}
    stat[5] = {0, 0, 0, 0, 0, 0, 0, 0}
    stat[6] = {0, 0, 0, 0, 0, 0, 0, 0}
    for pc=0,7 do
        dLv = memory.readbyte(0x080C0F4C + (pc * 0xB4) + 0x96)
        lv = 0
        while lv < dLv do
            lv = lv + 1
            if (lv == 1) then
                stat[1][pc + 1] = memory.readword(0x080C0F4C + (pc * 0xB4) + 0x50)
                stat[2][pc + 1] = memory.readword(0x080C0F4C + (pc * 0xB4) + 0x5C)
                stat[3][pc + 1] = memory.readword(0x080C0F4C + (pc * 0xB4) + 0x68)
                stat[4][pc + 1] = memory.readword(0x080C0F4C + (pc * 0xB4) + 0x74)
                stat[5][pc + 1] = memory.readword(0x080C0F4C + (pc * 0xB4) + 0x80)
                stat[6][pc + 1] = memory.readbyte(0x080C0F4C + (pc * 0xB4) + 0x8C)
            end

            statGrowthI = bit.band(lv / 20, 0xFF)

            v = 0x080C0F4C + (pc * 0xB4) + 0x50 + (statGrowthI * 2)
            v = memory.readword(v + 2) - memory.readword(v)
            v = v + bit.rshift(grn16() * 20, 16)
            stat[1][pc + 1] = stat[1][pc + 1] + bit.band(v / 20, 0xFFFF)

            v = 0x080C0F4C + (pc * 0xB4) + 0x5C + (statGrowthI * 2)
            v = memory.readword(v + 2) - memory.readword(v)
            v = v + bit.rshift(grn16() * 20, 16)
            stat[2][pc + 1] = stat[2][pc + 1] + bit.band(v / 20, 0xFFFF)

            v = 0x080C0F4C + (pc * 0xB4) + 0x68 + (statGrowthI * 2)
            v = memory.readword(v + 2) - memory.readword(v)
            v = v + bit.rshift(grn16() * 20, 16)
            stat[3][pc + 1] = stat[3][pc + 1] + bit.band(v / 20, 0xFFFF)

            v = 0x080C0F4C + (pc * 0xB4) + 0x74 + (statGrowthI * 2)
            v = memory.readword(v + 2) - memory.readword(v)
            v = v + bit.rshift(grn16() * 20, 16)
            stat[4][pc + 1] = stat[4][pc + 1] + bit.band(v / 20, 0xFFFF)

            v = 0x080C0F4C + (pc * 0xB4) + 0x80 + (statGrowthI * 2)
            v = memory.readword(v + 2) - memory.readword(v)
            v = v + bit.rshift(grn16() * 20, 16)
            stat[5][pc + 1] = stat[5][pc + 1] + bit.band(v / 20, 0xFFFF)

            v = 0x080C0F4C + (pc * 0xB4) + 0x8C + (statGrowthI)
            v = memory.readbyte(v + 1) - memory.readbyte(v)
            v = v + bit.rshift(grn16() * 20, 16)
            stat[6][pc + 1] = stat[6][pc + 1] + bit.band(v / 20, 0xFF)
-- current stat += ((upper stat growth - lower stat growth) + ((grn16 * 20) >> 16))  / 20
        end
    end
    for i=1,6 do
        for j=1,8 do
            gui.text(100 + j * 20 ,0 + i * 6,stat[i][j])
        end
    end
end
function djinnPercents(element, djinni)
    return memory.readword(0x080B1290 + ((element - 1) * 14) + ((djinni - 1) * 2))
end
function rollDjinn()
    haveDjinni = {}
    haveDjinni[1] = {1, 0, 0, 0, 0, 0, 0}
    haveDjinni[2] = {1, 0, 0, 0, 0, 0, 0}
    haveDjinni[3] = {0, 0, 0, 0, 0, 0, 0}
    haveDjinni[4] = {0, 0, 0, 0, 0, 0, 0}
    djinnCounts = {1, 1, 0, 0}
    djinnToAdd = 16
    while djinnToAdd > 0 do
        element = 1 + bit.rshift(grn16() * 4, 16)
        djinni = 1 + bit.rshift(grn16() * 7, 16)
        if haveDjinni[element][djinni] == 0 then
            djinnCounts[element] = djinnCounts[element] + 1
            low = 9
            high = 0
            for i=1,4 do
                if djinnCounts[i] < low then
                    low = djinnCounts[i]
                end
                if djinnCounts[i] > high then
                    high = djinnCounts[i]
                end
            end
            djinnCounts[element] = djinnCounts[element] - 1
            if (high - low) <= 1 then
                if bit.rshift(grn16() * 100, 16) < djinnPercents(element, djinni) then
                    haveDjinni[element][djinni] = 1
                    djinnCounts[element] = djinnCounts[element] + 1
                    djinnToAdd = djinnToAdd - 1
                end
            end
        end
    end
    for i=1,4 do
        for j=1,7 do
            gui.text(195 + j * 5 ,0 + i * 6,haveDjinni[i][j])
        end
    end
    return
end

while true do
    reset()
    startingStats()
    --rollDjinn()
    vba.frameadvance();
end
LUA is hard to use. :/ It's like... even worse than assembly. :P (Assembly is cool, though... but it often looks bloated.)
Better yet, to the majority of programmers who are familiar with how bad VB sucks... I kinda want to say LUA is just as bad or worse. :P

Well, at least I learned something this pass week about LUA = Indexes (in lists/arrays) start at 1 instead of 0... So that also adds more unnecessary bloat to my code.


@Isaac's Luck = Hmm.. why does my script generate Luck at ~17, when it can only be 3... Huh. - Luck stats always stay the same for starting stats = I could possibly comment it out....


@ bit.band(v / 20, 0xFF)
I expected that to return a 0 when v is 19... but it can return a 1? Wha? ... Hmmmm...... Probably cuz nasty floats. :/  (I'm an integer type of guy. Which is good, b/c most of the time I don't need decimal places, and  in some ways the rarity of it can make me think it shouldn't hurt to use a second integer as the denominator. :P But it depends.)... maybe math.floor(a/b) works.


local grnseed = 0
local brnseed = 0

function reset()
    grnseed = memory.readdword(0x030011BC)
    brnseed = memory.readdword(0x020054C8)
end
function grn16()
    g = grnseed
    m1 = 0x4e6d
    m2 = 0x41c6
    g1 = g*m1
    g2 = g*m2
    g2 = bit.band(g2,0xFFFF)
    g = g1 + g2*0x10000
    c=0x3039
    g = g+c
    g = bit.band(g,0xFFFFFFFF)
    grnseed = g
    g = bit.lshift(g,8)
    g = bit.rshift(g,16)
    --g = bit.band(g,0xFFFF)
    return g
end
function brn16()
    g = brnseed
    m1 = 0x4e6d
    m2 = 0x41c6
    g1 = g*m1
    g2 = g*m2
    g2 = bit.band(g2,0xFFFF)
    g = g1 + g2*0x10000
    c=0x3039
    g = g+c
    g = bit.band(g,0xFFFFFFFF)
    brnseed = g
    g = bit.lshift(g,8)
    g = bit.rshift(g,16)
    return g
end
function startingStats()
    stat = {}
    stat[1] = {0, 0, 0, 0, 0, 0, 0, 0}
    stat[2] = {0, 0, 0, 0, 0, 0, 0, 0}
    stat[3] = {0, 0, 0, 0, 0, 0, 0, 0}
    stat[4] = {0, 0, 0, 0, 0, 0, 0, 0}
    stat[5] = {0, 0, 0, 0, 0, 0, 0, 0}
    stat[6] = {0, 0, 0, 0, 0, 0, 0, 0}
    for pc=0,7 do
        dLv = memory.readbyte(0x080C0F4C + (pc * 0xB4) + 0x96)
        lv = 0
        while lv < dLv do
            lv = lv + 1
            if (lv == 1) then
                stat[1][pc + 1] = memory.readword(0x080C0F4C + (pc * 0xB4) + 0x50)
                stat[2][pc + 1] = memory.readword(0x080C0F4C + (pc * 0xB4) + 0x5C)
                stat[3][pc + 1] = memory.readword(0x080C0F4C + (pc * 0xB4) + 0x68)
                stat[4][pc + 1] = memory.readword(0x080C0F4C + (pc * 0xB4) + 0x74)
                stat[5][pc + 1] = memory.readword(0x080C0F4C + (pc * 0xB4) + 0x80)
                stat[6][pc + 1] = memory.readbyte(0x080C0F4C + (pc * 0xB4) + 0x8C)
            end

            statGrowthI = math.floor(lv / 20)

            v = 0x080C0F4C + (pc * 0xB4) + 0x50 + (statGrowthI * 2)
            v = memory.readword(v + 2) - memory.readword(v)
            v = v + bit.rshift(grn16() * 20, 16)
            stat[1][pc + 1] = stat[1][pc + 1] + math.floor(v / 20)

            v = 0x080C0F4C + (pc * 0xB4) + 0x5C + (statGrowthI * 2)
            v = memory.readword(v + 2) - memory.readword(v)
            v = v + bit.rshift(grn16() * 20, 16)
            stat[2][pc + 1] = stat[2][pc + 1] + math.floor(v / 20)

            v = 0x080C0F4C + (pc * 0xB4) + 0x68 + (statGrowthI * 2)
            v = memory.readword(v + 2) - memory.readword(v)
            v = v + bit.rshift(grn16() * 20, 16)
            stat[3][pc + 1] = stat[3][pc + 1] + math.floor(v / 20)

            v = 0x080C0F4C + (pc * 0xB4) + 0x74 + (statGrowthI * 2)
            v = memory.readword(v + 2) - memory.readword(v)
            v = v + bit.rshift(grn16() * 20, 16)
            stat[4][pc + 1] = stat[4][pc + 1] + math.floor(v / 20)

            v = 0x080C0F4C + (pc * 0xB4) + 0x80 + (statGrowthI * 2)
            v = memory.readword(v + 2) - memory.readword(v)
            v = v + bit.rshift(grn16() * 20, 16)
            stat[5][pc + 1] = stat[5][pc + 1] + math.floor(v / 20)

            v = 0x080C0F4C + (pc * 0xB4) + 0x8C + (statGrowthI)
            v = memory.readbyte(v + 1) - memory.readbyte(v)
            v = v + bit.rshift(grn16() * 20, 16)
            stat[6][pc + 1] = stat[6][pc + 1] + math.floor(v / 20)

-- current stat += ((upper stat growth - lower stat growth) + ((grn16 * 20) >> 16))  / 20
        end
    end
    for i=1,6 do
        for j=1,8 do
            gui.text(90 + j * 16 ,112 + i * 6,stat[i][j])
        end
    end
end
function djinnPercents(element, djinni)
    return memory.readword(0x080B1290 + ((element - 1) * 14) + ((djinni - 1) * 2))
end
function rollDjinn()
    haveDjinni = {}
    haveDjinni[1] = {1, 0, 0, 0, 0, 0, 0}
    haveDjinni[2] = {1, 0, 0, 0, 0, 0, 0}
    haveDjinni[3] = {0, 0, 0, 0, 0, 0, 0}
    haveDjinni[4] = {0, 0, 0, 0, 0, 0, 0}
    djinnCounts = {1, 1, 0, 0}
    djinnToAdd = 16
    while djinnToAdd > 0 do
        element = 1 + bit.rshift(grn16() * 4, 16)
        djinni = 1 + bit.rshift(grn16() * 7, 16)
        if haveDjinni[element][djinni] == 0 then
            djinnCounts[element] = djinnCounts[element] + 1
            low = 9
            high = 0
            for i=1,4 do
                if djinnCounts[i] < low then
                    low = djinnCounts[i]
                end
                if djinnCounts[i] > high then
                    high = djinnCounts[i]
                end
            end
            djinnCounts[element] = djinnCounts[element] - 1
            if (high - low) <= 1 then
                if bit.rshift(grn16() * 100, 16) < djinnPercents(element, djinni) then
                    haveDjinni[element][djinni] = 1
                    djinnCounts[element] = djinnCounts[element] + 1
                    djinnToAdd = djinnToAdd - 1
                end
            end
        end
    end
    for i=1,4 do
        for j=1,7 do
            gui.text(195 + j * 5 ,0 + i * 6,haveDjinni[i][j])
        end
    end
    return
end

while true do
    reset()
    startingStats()
    reset()
    rollDjinn()
    vba.frameadvance();
end

^How does it look? I think the calculations looking better now. (Calculates base stats and not current stats, when comparing to memory viewer.)
Stat table's in a pretty bad spot = It's a bit big.... so not sure what to do with it. - I guess that's up to you.
Golden Sun Docs: Broken Seal - The Lost Age - Dark Dawn | Mario Sports Docs: Mario Golf & Mario Tennis | Misc. Docs
Refer to Yoshi's Lighthouse for any M&L hacking needs...

Sometimes I like to compare apples to oranges. (Figuratively) ... They are both fruits, but which one would you eat more? (If taken literally, I'd probably choose apples.)
Maybe it is over-analyzing, but it doesn't mean the information is useless.


The only GS Discord servers with significance are:
Golden Sun Hacking Community
GS Speedrunning
/r/Golden Sun
GS United Nations
Temple of Kraden

Can you believe how small the Golden Sun Community is?

2+2=5 Don't believe me? Those are rounded decimal numbers. Take that, flat earth theorists! :)

Plexa

#6
Well I've been attempting to do this all night but am failing spectacularly at it. I'm trying to search through the different combinations of "Felix Cancelling" and "Isaac cancelling" that gets me my desired stats/djinn.

In particular, Isaac rolling 120+ atk, Jenna rolling high agility, djinn: kite, breeze, zephyr, flash ground, granite. bonus: mist/squall/hail

Best I could find (by brute force) is 9 Felix Cancels which gets everything except that Isaac rolls 117 attack. Jennas agility could be higher as well.

EDIT: FC FC IC IC FC FC IC also works, and gets a better agility roll for Jenna.

The frustrating thing is that FC IC =/= IC FC for some reason.

Daddy Poi's Oily Gorillas

#7
QuoteThe frustrating thing is that FC IC =/= IC FC for some reason.
It's probably because of the way the djinn picker code works. (Chance to fail at picking one, and pick another.)

So while it is possible Felix Cancels (Stat generation) might always generate the same number of random numbers, the Isaac Cancels (Djinn Picker) are variable based on (un)successful picks.
Golden Sun Docs: Broken Seal - The Lost Age - Dark Dawn | Mario Sports Docs: Mario Golf & Mario Tennis | Misc. Docs
Refer to Yoshi's Lighthouse for any M&L hacking needs...

Sometimes I like to compare apples to oranges. (Figuratively) ... They are both fruits, but which one would you eat more? (If taken literally, I'd probably choose apples.)
Maybe it is over-analyzing, but it doesn't mean the information is useless.


The only GS Discord servers with significance are:
Golden Sun Hacking Community
GS Speedrunning
/r/Golden Sun
GS United Nations
Temple of Kraden

Can you believe how small the Golden Sun Community is?

2+2=5 Don't believe me? Those are rounded decimal numbers. Take that, flat earth theorists! :)

Plexa


Daddy Poi's Oily Gorillas

#9
Yes. So, have you changed my script to do anything, or are simply looking at the numbers I added?

Since if there's a priority for the stats/djinn... I suppose it could be possible to develope the script further...

And making a recursive function for this could be a perfect fit! (I think? Depends.)

I'm kind of thinking something like this:

findBestWhatever(0)

function findBestWhatever(depth)
    if depth >= 10 then return --Important to avoid endless calls.
    rng = grnseed --rng needs to be a function-level variable.
    statregen()
    findBestWhatever(depth + 1)
    grnseed = rng
    djinnpicker()
    findBestWhatever(depth + 1)
end

Incomplete, ofcourse.... but I hope I did the base example correctly? Erm...
As you can see, it kind of mimics a data tree... and it's also easy to add more conditions if needed.

--
Going to see what I can do with putting in Isaac's Attack in a bit, but who knows if it'll work out/execute fast enough.


WIP code:
local grnseed = 0
local brnseed = 0
function reset()
    grnseed = memory.readdword(0x030011BC)
    brnseed = memory.readdword(0x020054C8)
end
function grn16()
    g = grnseed
    m1 = 0x4e6d
    m2 = 0x41c6
    g1 = g*m1
    g2 = g*m2
    g2 = bit.band(g2,0xFFFF)
    g = g1 + g2*0x10000
    c=0x3039
    g = g+c
    g = bit.band(g,0xFFFFFFFF)
    grnseed = g
    g = bit.lshift(g,8)
    g = bit.rshift(g,16)
    --g = bit.band(g,0xFFFF)
    return g
end
function brn16()
    g = brnseed
    m1 = 0x4e6d
    m2 = 0x41c6
    g1 = g*m1
    g2 = g*m2
    g2 = bit.band(g2,0xFFFF)
    g = g1 + g2*0x10000
    c=0x3039
    g = g+c
    g = bit.band(g,0xFFFFFFFF)
    brnseed = g
    g = bit.lshift(g,8)
    g = bit.rshift(g,16)
    return g
end
    stat = {}
    stat[1] = {0, 0, 0, 0, 0, 0, 0, 0}
    stat[2] = {0, 0, 0, 0, 0, 0, 0, 0}
    stat[3] = {0, 0, 0, 0, 0, 0, 0, 0}
    stat[4] = {0, 0, 0, 0, 0, 0, 0, 0}
    stat[5] = {0, 0, 0, 0, 0, 0, 0, 0}
    stat[6] = {0, 0, 0, 0, 0, 0, 0, 0}
function startingStats()
    stat[1] = {0, 0, 0, 0, 0, 0, 0, 0}
    stat[2] = {0, 0, 0, 0, 0, 0, 0, 0}
    stat[3] = {0, 0, 0, 0, 0, 0, 0, 0}
    stat[4] = {0, 0, 0, 0, 0, 0, 0, 0}
    stat[5] = {0, 0, 0, 0, 0, 0, 0, 0}
    stat[6] = {0, 0, 0, 0, 0, 0, 0, 0}
    for pc=0,7 do
        dLv = memory.readbyte(0x080C0F4C + (pc * 0xB4) + 0x96)
        lv = 0
        while lv < dLv do
            lv = lv + 1
            if (lv == 1) then
                stat[1][pc + 1] = memory.readword(0x080C0F4C + (pc * 0xB4) + 0x50)
                stat[2][pc + 1] = memory.readword(0x080C0F4C + (pc * 0xB4) + 0x5C)
                stat[3][pc + 1] = memory.readword(0x080C0F4C + (pc * 0xB4) + 0x68)
                stat[4][pc + 1] = memory.readword(0x080C0F4C + (pc * 0xB4) + 0x74)
                stat[5][pc + 1] = memory.readword(0x080C0F4C + (pc * 0xB4) + 0x80)
                stat[6][pc + 1] = memory.readbyte(0x080C0F4C + (pc * 0xB4) + 0x8C)
            end

            statGrowthI = math.floor(lv / 20)

            v = 0x080C0F4C + (pc * 0xB4) + 0x50 + (statGrowthI * 2)
            v = memory.readword(v + 2) - memory.readword(v)
            v = v + bit.rshift(grn16() * 20, 16)
            stat[1][pc + 1] = stat[1][pc + 1] + math.floor(v / 20)

            v = 0x080C0F4C + (pc * 0xB4) + 0x5C + (statGrowthI * 2)
            v = memory.readword(v + 2) - memory.readword(v)
            v = v + bit.rshift(grn16() * 20, 16)
            stat[2][pc + 1] = stat[2][pc + 1] + math.floor(v / 20)

            v = 0x080C0F4C + (pc * 0xB4) + 0x68 + (statGrowthI * 2)
            v = memory.readword(v + 2) - memory.readword(v)
            v = v + bit.rshift(grn16() * 20, 16)
            stat[3][pc + 1] = stat[3][pc + 1] + math.floor(v / 20)

            v = 0x080C0F4C + (pc * 0xB4) + 0x74 + (statGrowthI * 2)
            v = memory.readword(v + 2) - memory.readword(v)
            v = v + bit.rshift(grn16() * 20, 16)
            stat[4][pc + 1] = stat[4][pc + 1] + math.floor(v / 20)

            v = 0x080C0F4C + (pc * 0xB4) + 0x80 + (statGrowthI * 2)
            v = memory.readword(v + 2) - memory.readword(v)
            v = v + bit.rshift(grn16() * 20, 16)
            stat[5][pc + 1] = stat[5][pc + 1] + math.floor(v / 20)

            v = 0x080C0F4C + (pc * 0xB4) + 0x8C + (statGrowthI)
            v = memory.readbyte(v + 1) - memory.readbyte(v)
            v = v + bit.rshift(grn16() * 20, 16)
            stat[6][pc + 1] = stat[6][pc + 1] + math.floor(v / 20)

-- current stat += ((upper stat growth - lower stat growth) + ((grn16 * 20) >> 16))  / 20
        end
    end
--    for i=1,6 do
--        for j=1,8 do
--            gui.text(90 + j * 16 ,112 + i * 6,stat[i][j])
--        end
--    end
end
function djinnPercents(element, djinni)
    return memory.readword(0x080B1290 + ((element - 1) * 14) + ((djinni - 1) * 2))
end
function rollDjinn()
    haveDjinni = {}
    haveDjinni[1] = {1, 0, 0, 0, 0, 0, 0}
    haveDjinni[2] = {1, 0, 0, 0, 0, 0, 0}
    haveDjinni[3] = {0, 0, 0, 0, 0, 0, 0}
    haveDjinni[4] = {0, 0, 0, 0, 0, 0, 0}
    djinnCounts = {1, 1, 0, 0}
    djinnToAdd = 16
    while djinnToAdd > 0 do
        element = 1 + bit.rshift(grn16() * 4, 16)
        djinni = 1 + bit.rshift(grn16() * 7, 16)
        if haveDjinni[element][djinni] == 0 then
            djinnCounts[element] = djinnCounts[element] + 1
            low = 9
            high = 0
            for i=1,4 do
                if djinnCounts[i] < low then
                    low = djinnCounts[i]
                end
                if djinnCounts[i] > high then
                    high = djinnCounts[i]
                end
            end
            djinnCounts[element] = djinnCounts[element] - 1
            if (high - low) <= 1 then
                if bit.rshift(grn16() * 100, 16) < djinnPercents(element, djinni) then
                    haveDjinni[element][djinni] = 1
                    djinnCounts[element] = djinnCounts[element] + 1
                    djinnToAdd = djinnToAdd - 1
                end
            end
        end
    end
--    for i=1,4 do
--        for j=1,7 do
--            gui.text(195 + j * 5 ,0 + i * 6,haveDjinni[i][j])
--        end
--    end
    return
end

hAtk = 0
hAtk2 = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0} --0 --
atk = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0} --0
tree = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
hTree = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
function savetree()
    for i=1,10 do
        hTree[i] = tree[i]
        hAtk2[i] = atk[i]
    end
    return
end
function findBest(depth)
    if depth >= 4 then return end --Important to avoid endless calls.
    rng = grnseed --rng needs to be a function-level variable.
    tree[depth] = 1
    startingStats() --statregen()
    atk[depth] = stat[3][1]
    if hAtk < stat[3][1] then
        hAtk = stat[3][1]
        savetree()
    end
    findBest(depth + 1)

    tree[depth] = 2
    grnseed = rng
    rollDjinn() --djinnpicker()
    findBest(depth + 1)

    tree[depth] = 0
    --atk[depth] = 0;
    return
end

while true do
    reset()
    hAtk = 0
    --gui.text(200, 10, "!")
    findBest(1)
    for i=1,3 do --10 do
        gui.text(150 + i * 20, 0, hTree[i])
        gui.text(150 + i * 20, 10, hAtk2[i])
    end
    --startingStats()
    --reset()
    --rollDjinn()
    vba.frameadvance();
end
Was not fully tested, so there may or may not be errors.

Here, shows 6 numbers... (Columns represent each cycle= 1st, 2nd, or 3rd action.)

The top row is:
0 = Nothing/Ignore
1 = Do a Felix Cancel
2 = Do an Isaac Cancel

The bottom row is Isaac's base attack at each stage. (So if the same column is switched to a 1/"Felix Cancel" in case of 2 (not tested, though.), you'd get this value.)


TODO = I want to add in a map/door check... as well as a check to a certain pointer in the stack. (So the info is only generated when necessary instead of every frame. = Would appear to increase the speed of searches of larger depths a great deal.


*Takes a look at your script at pastebin, and then becmes curous if something similar to "return (bit.band(g,0xF) == 0) or ((bit.band(g2,0x1F) ==0) * 2)" can be done. (All those if statements as a one liner.)
Except operationss as such can't be done on boolean values in LUA.... ... but one can still make a hack for that, and use a dictionary.
EX:
    t = {}
    t[true] = 1
    t[false] = 0
    gui.text(200, 20, t[0==0] * 2)


    t = {[false]=0, [true]=1}
    gui.text(200, 20, t[0==0] * 3)
Golden Sun Docs: Broken Seal - The Lost Age - Dark Dawn | Mario Sports Docs: Mario Golf & Mario Tennis | Misc. Docs
Refer to Yoshi's Lighthouse for any M&L hacking needs...

Sometimes I like to compare apples to oranges. (Figuratively) ... They are both fruits, but which one would you eat more? (If taken literally, I'd probably choose apples.)
Maybe it is over-analyzing, but it doesn't mean the information is useless.


The only GS Discord servers with significance are:
Golden Sun Hacking Community
GS Speedrunning
/r/Golden Sun
GS United Nations
Temple of Kraden

Can you believe how small the Golden Sun Community is?

2+2=5 Don't believe me? Those are rounded decimal numbers. Take that, flat earth theorists! :)