Golden Sun Hacking Community
November 17, 2018, 05:05:36 PM *
Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length
News:
 
  Home   Forum   DC Wiki Help Search Calendar Downloads Login Register  
Pages: [1]   Go Down
  Print  
Author Topic: More RNG Questions  (Read 1166 times)
0 Members and 1 Guest are viewing this topic.

Regular Member
**

Coins: 2
Offline Offline

Posts: 135

« on: August 29, 2017, 02:21:09 AM »

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.
Logged
View Profile
Fox
Fox McCloud, the Hacking Doctor
Mercury Clan

Prodigy
*

Coins: 29
Offline Offline

I am: certainly not a Gallant!
Clan Position: Head Gallant
Posts: 2431

« Reply #1 on: August 29, 2017, 07:02:47 AM »

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

Quote from: From my GS2 Documentation
08119AD0 = 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.)
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:
Quote
0200048B = 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.
« Last Edit: August 29, 2017, 10:56:56 PM by Fox » Logged

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...

Remember kids! Before you go on that interview, remember to wash your hands in teawater! *Coughs on hand* (Excuse me, I just coughed up a little teawater, so they're still clean!) You wouldn't want that hiring manager to be unimpressed.

May the force be with you!
Shoo! Why does it smell in here?
Maybe that's the wrong kind of force. *smirk*
View Profile

Regular Member
**

Coins: 2
Offline Offline

Posts: 135

« Reply #2 on: August 30, 2017, 01:27:41 AM »

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)
Logged
View Profile
Fox
Fox McCloud, the Hacking Doctor
Mercury Clan

Prodigy
*

Coins: 29
Offline Offline

I am: certainly not a Gallant!
Clan Position: Head Gallant
Posts: 2431

« Reply #3 on: August 30, 2017, 01:41:55 AM »

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...
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 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
« Last Edit: August 30, 2017, 04:37:11 AM by Fox, Reason: When your code can get mistakened for something like BBCode, then it needs a fix... So there. » Logged

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...

Remember kids! Before you go on that interview, remember to wash your hands in teawater! *Coughs on hand* (Excuse me, I just coughed up a little teawater, so they're still clean!) You wouldn't want that hiring manager to be unimpressed.

May the force be with you!
Shoo! Why does it smell in here?
Maybe that's the wrong kind of force. *smirk*
View Profile

Regular Member
**

Coins: 2
Offline Offline

Posts: 135

« Reply #4 on: August 30, 2017, 04:07:29 AM »

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!
Logged
View Profile
Fox
Fox McCloud, the Hacking Doctor
Mercury Clan

Prodigy
*

Coins: 29
Offline Offline

I am: certainly not a Gallant!
Clan Position: Head Gallant
Posts: 2431

« Reply #5 on: August 31, 2017, 06:38:40 AM »

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:
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.


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
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.
« Last Edit: August 31, 2017, 11:33:47 AM by Fox » Logged

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...

Remember kids! Before you go on that interview, remember to wash your hands in teawater! *Coughs on hand* (Excuse me, I just coughed up a little teawater, so they're still clean!) You wouldn't want that hiring manager to be unimpressed.

May the force be with you!
Shoo! Why does it smell in here?
Maybe that's the wrong kind of force. *smirk*
View Profile

Regular Member
**

Coins: 2
Offline Offline

Posts: 135

« Reply #6 on: September 06, 2017, 07:56:43 PM »

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.
« Last Edit: September 06, 2017, 08:28:59 PM by Plexa » Logged
View Profile
Fox
Fox McCloud, the Hacking Doctor
Mercury Clan

Prodigy
*

Coins: 29
Offline Offline

I am: certainly not a Gallant!
Clan Position: Head Gallant
Posts: 2431

« Reply #7 on: September 06, 2017, 08:41:57 PM »

Quote
The 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.
« Last Edit: September 06, 2017, 09:27:44 PM by Fox » Logged

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...

Remember kids! Before you go on that interview, remember to wash your hands in teawater! *Coughs on hand* (Excuse me, I just coughed up a little teawater, so they're still clean!) You wouldn't want that hiring manager to be unimpressed.

May the force be with you!
Shoo! Why does it smell in here?
Maybe that's the wrong kind of force. *smirk*
View Profile

Regular Member
**

Coins: 2
Offline Offline

Posts: 135

« Reply #8 on: September 06, 2017, 09:09:12 PM »

That'd be the cause.
Logged
View Profile
Fox
Fox McCloud, the Hacking Doctor
Mercury Clan

Prodigy
*

Coins: 29
Offline Offline

I am: certainly not a Gallant!
Clan Position: Head Gallant
Posts: 2431

« Reply #9 on: September 06, 2017, 09:45:35 PM »

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:
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)
« Last Edit: September 07, 2017, 11:55:06 AM by Fox » Logged

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...

Remember kids! Before you go on that interview, remember to wash your hands in teawater! *Coughs on hand* (Excuse me, I just coughed up a little teawater, so they're still clean!) You wouldn't want that hiring manager to be unimpressed.

May the force be with you!
Shoo! Why does it smell in here?
Maybe that's the wrong kind of force. *smirk*
View Profile
Pages: [1]   Go Up
  Print  
 
Jump to:  

Cbox
October 30, 2018, 09:45:58 PM
Atrius: There used to be where I got the battle sprites for Kraden, but that site doesn't exist any more.
October 26, 2018, 01:31:40 PM
Infitek: Do you know if there any custom Alex battle sprites available on the internet ?
October 26, 2018, 01:31:01 PM
Infitek: Hey everyone
October 13, 2018, 03:23:06 AM
Salanewt: Updated it to provide more info that I forgot to mention.
October 13, 2018, 03:16:48 AM
Salanewt: I'm still trying to iron out IQ 2 but I'm pretty sure it's entirely random targeting.
October 13, 2018, 03:16:29 AM
Salanewt: Oh yeah, I posted some more info about enemy IQ.
October 12, 2018, 09:51:27 PM
FoxThe HTML5 project is too small to count
October 12, 2018, 06:19:48 AM
Luna_blade: there is jjppof's html5 project...
October 12, 2018, 06:19:17 AM
Luna_blade: Though Momo rings a bell it seems I came here after you left
October 11, 2018, 12:49:41 AM
Fox: (If that makes sense.)
October 11, 2018, 12:48:33 AM
Fox: Yeah, I guess so.  More just saying that's a good place to get answers to GS related questions at the moment.
October 11, 2018, 12:42:28 AM
Crystal Sonata: I did before, but I guess I could try it again
October 11, 2018, 12:41:32 AM
Fox: Not much at the moment. This forum seems pretty quiet. Perhaps you'd be interested in joining the Discord for GSHC that seems to have more activity?
October 10, 2018, 11:16:53 PM
Crystal Sonata: Any projects going on? I need a distraction from the daily grind and I'm interested in hacking GS again.
October 10, 2018, 10:02:53 PM
Fox: Thanks, and good to see you too!
October 10, 2018, 10:02:10 PM
Fox: A few people I'm sure... Most likely the regulars of the past. Such as Atrius, Charon, Role, Salanewt....
October 10, 2018, 03:11:17 AM
Crystal Sonata: I find myself wondering who still remembers me here. Obvs you do (Good to see ya Tea)
October 10, 2018, 12:46:11 AM
Fox: On second thought, it might be because you haven't posted much as Crystal Sonata.
October 10, 2018, 12:41:12 AM
Fox: And your intro isn't that bad. - I imagine most people would say the same about theirs?
October 10, 2018, 12:39:39 AM
Fox: :O - You've been gone so long, I think I forgot you were Momo.  Interesting.

Affiliates
Temple of Kraden Golden Sunrise
Powered by MySQL Powered by PHP Powered by SMF 1.1.21 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!
Page created in 0.131 seconds with 22 queries.