User File #41463754103379844

Upload All User Files

#41463754103379844 - GBA D&D: Eye of the Beholder - Incomplete first battle script

EotB_Sim.lua
657 downloads
Uploaded 9/2/2017 7:32 AM by FatRatKnight (see all 245)
Nonfunctional. Do not run.
Been looking over my older stuff to find this script. It is an attempt at botting (or more accurately, simulating) the first battle, so that I can see this fight perfected, but it is decidedly incomplete, and it is not structured to treat the fodder with ambiguous stats, so it needs a redesign anyway.
Note that the script shouldn't be running emulator functions. It's just a scripted simulator, not a savestate bot.
--Combat Simulator Express; Specific one-shot conditions.
--Snap, man. I snapping hate it. Beat me out of my comfort zone, I say.

--#############################################################################
--#############################################################################
--Base level RNG functions

--*****************************************************************************
local function Roll1(R) --0x0000LLLL * 0x00004650 + 0x0000HHHH
--*****************************************************************************
    return bit.band(R,0xFFFF)*0x4650 + bit.rshift(R,16)
end
--*****************************************************************************
local function Roll2(R) --0x0000LLLL * 0x000078B7 + 0x0000HHHH
--*****************************************************************************
    return bit.band(R,0xFFFF)*0x78B7 + bit.rshift(R,16)
end
--*****************************************************************************
local function Calc(r1,r2)
--*****************************************************************************
    return bit.band(0xFFFF,r1)*16 + bit.band(0xFFFF,r2)
end
--*****************************************************************************
local function RollT(t,d)
--*****************************************************************************
--This takes a table. Table must have special indeces in it: r1, r2
--If given a number as well (d-sided die to be thrown), returns die value.
    t.r1,t.r2= Roll1(t.r1),Roll2(t.r2)
    return d and ( (Calc(t.r1,t.r2)%d)+1 )
end

--*****************************************************************************
local function StepT(t)
--*****************************************************************************
--Simulates the RNG rolls of walking one step.
--There is a 5% chance that an additional call is needed.
--Reason being environmental noises.
    if RollT(t,20) == 1 then RollT(t) end
end

--#############################################################################
--#############################################################################
--Player stats

--Produce a player table from this... Somehow.
--Garon, Cleric  HP:    AC:   Dmg:1d6+0 Hit:+1 Hide:+6 Init:+2
--Wobby, Wizard  HP:    AC:   Dmg:      Hit:   Hide:+6 Init:+2  Magic Missile!
--N    , Fodder  HP:2   AC:15 Dmg:1d4-4 Hit:-3 Hide:10 Init:+4  Magic Missile!
--O    , Fodder  HP:2   AC:11 Dmg:1d4-2 Hit:-1 Hide:+6 Init:+0  Magic Missile!

--Kobold stats:  HP:1d4 AC:15                          Init:+3

--name       Flavor, really.
--purpose    Intention of target
--ally       Friend or foe? True if friend
--HP         Hit points, of course
--AC         How hard to be hit
--Atk        How easy to hit
--Hide       Need to be hidden if this luck manipulation will work
--Init       Who's likely to go first?


--*****************************************************************************
local function f()
--*****************************************************************************
end

--*****************************************************************************
local function Formations(T,index)
--*****************************************************************************
-- This is where we move player stats where we need them.
-- Develop two tables: Player stats, and desired formations
end

--*****************************************************************************
local function InitializeCombatOne(T)
--*****************************************************************************
-- Fill out our table of character stats.
-- Assumes the first battle: Four players vs. five Kobold Swordsmen + InitBonus
-- Also assume player information is already provided in the tables.
-- ... Take it piecewise. This part is easy, right? Then do it.

-- Player stats. If Hide is known to fail, forget it. We're done.
    for pl= 1, 4 do  -- Players get Initiative, Hide_check_1, and Hide_check_2

--No fail condition for Initiative. Just add it into the player data.
        T.player[pl].Init= T.player[pl].Init + RollT(T,20)

--Hide_check_1; Apparently, it checks against a constant.
        if RollT(T,20) <= 5 then return false end  --We must pass or abort!

--Hide_check_2; Versus DC 20, my character had better hide, darn it!
        if (RollT(T,20) + T.Player[pl].Hide) < 20 then return false end
    end

-- Kobold stats. Initiative and HP are the only things to worry about.
    for ko= 1, 5 do  -- Shove in Kobold Swordsman stats.
        T.kobold[ko].Init= RollT(T,20)+3
        T.kobold[ko].HP  = RollT(T, 4)
    end

--If we're here, nothing went wrong. True is my "all clear" flag.
    return true
end

--*****************************************************************************
local function InitiativeOrder(T)
--*****************************************************************************
--

end

--*****************************************************************************
local function ConfirmInitiative(T)
--*****************************************************************************
--Figure out what order the characters are in.
--player[pl].order, and our own Order table.
--Kobold (#3, #4, #5)
--Player (not front fodder)
--Kobold (#3, #4, #5)
--Front Fodder
--Other players (floating)
--Remaining Kobolds must be dead and all.

--Ask whether fodder is in slot 1. We need to know if Kobold #3 can reach.
   local FirstKobold= 3
   if T.player[1].purpose == "fodder" then FirstKobold= 4 end


T.kobold[ko].purpose= "killer"


--Alright, we're good!
    return true
end

--#############################################################################
--#############################################################################

--*****************************************************************************
local function OptionElf(chr)
--*****************************************************************************
--The default is Halfling due to good Hide.
--However, if we don't need the Hide, Elf is much better for combat.

    chr.HP     = 1              --Elves get worse Constitution. An advantage
    chr.AC     = chr.AC-1       --Medium size is easier to hit
    chr.DamageB= chr.DamageB+1  --Halflings do reduced damage. Not Elf
    chr.Hide   = chr.Hide-4     --Lose out on Hide, though
    chr.Race   = "Elf"          --Ahoy, Elf!
end

--*****************************************************************************
local function Attack(chr,state)
--*****************************************************************************
--Spits out Attack roll and, assuming your hit, the damage output.
--Consumes 3 RNG rolls on successful hit.

    local Hit= RollT(state,20) + chr.Attack
    local Damage= math.max(RollT(state,chr.DamageD)+chr.DamageB,1)
    RollT(state)
    return Hit,Damage
end

--*****************************************************************************
local function MagicMissile(state)
--*****************************************************************************
--Magic Missile can't miss. It only deals 1d4+1 damage.

    local Damage= RollT(state,4)+1
    RollT(state)
    return Damage
end

--*****************************************************************************
local function Chr_Die(Me)
--*****************************************************************************
    Me.Alive= false
    Me.Ready= false
end

--*****************************************************************************
local function Chr_Acted(Me)
--*****************************************************************************
    Me.Hide = false
    Me.Ready= true
end

--true = We're good. Continue simulation
--false = Bad news. Abort, new tactic.
--*****************************************************************************
local function Task_FwdFodder(Me,CbtState)
--*****************************************************************************
--This guy must die. It must also kill something.

--So, first. Let's kill something. Check our mighty dagger attack!
    local Hit,Damage= Attack(Me,CbtState)
    local TryMissile= true
    if Hit >= 14 then  -- Enough to hit a flatfooted kobold

        --If there's a kobold in our way, we must attack and kill it.
--        local target= 

        --if target.killed, TryMissile= false end
    end

    if TryMissile then
        --Abort if kobold 1 or 2 can use attack of opportunity
        if CbtState.Enemy[1].Ready or CbtState.Enemy[2].Ready then return false end

        local Damage= MagicMissile(CbtState)
        local 
        --loop
            if target.killed
        --endloop
        if not TryMissile then
    end

--If we're here, we successfully killed something, and want to die now.
--At least two kobolds must be ready. 5 and 4 are always valid.
--3 is only valid if we're in position B.


end

--*****************************************************************************
local function Task_Wizard(Me,CbtState)
--*****************************************************************************
--Wizard casts Magic Missile. End of story.
    local Damage= MagicMissile(CbtState)
end

--*****************************************************************************
local function Task_Cleric(Me,CbtState)
--*****************************************************************************
--The Cleric needs to bash something dead. Nothing else necessary.
    local Hit,Damage= Attack(Me,CbtState)
    if Hit < 14 then return false end -- If we don't hit, bad news.
end
--

--*****************************************************************************
local function Task_Kobold(Me,CbtState)
--*****************************************************************************
--These guys have a number of tasks to do.

--We're fine if every player is hidden or dead.
    --Playerscan

--FwdFodder must have died first.
    if CbtState.Player.FwdFodder.Alive then return false end

--Now figure out which player.
    local Pl
    if     Me.Formation == 1 then return false
    elseif Me.Formation == 2 then return false
    elseif Me.Formation == 3 then Pl= CbtState.Player[1]
    elseif Me.Formation == 4 then
        if not CbtState.Enemy[5].Alive then return false end
        Pl= CbtState.Player[1]
    elseif Me.Formation == 5 then
        if not CbtState.Enemy[4].Alive then return false end
        Pl= CbtState.Player[2]
    else   error("Formation bad!")  --Something really bad happened.
    end

--
    if Pl.Name ~= "Garon" then return false end  --Must be Garon
    if not Pl.Ready       then return false end  --Must have acted
    local Hit,Damage = Attack(Pl,CbtState)
    if Hit < 15           then return false end  --Must hit
    if Damage < Me.HP     then return false end  --Must kill

    Me:Die()        --We only get here if we actually die.
    Pl.Ready= false --Spent Garon's opportunity.
    return true
end

--#############################################################################
--#############################################################################

local PlayerBase= {
  {Name="Garon", Class="Cleric", HP=9, AC=16, dd=6, db= 0, Hide= 6, Init= 2
  },
  {Name="Wobby", Class="Wizard", HP=5, AC=12, dd=4, db= 0, Hide= 6, Init= 2
  },
  {Name="N"    , Class="Wizard", HP=2, AC=15, dd=4, db=-4, Hide=10, Init= 4
  },
  {Name="O"    , Class="Wizard", HP=2, AC=11, dd=4, db=-2, Hide= 6, Init= 0
  }
}

local KoboldBase= {
  Name
}

local MainTable= {
    r1,r2= 0,0
    player= {{},{},{},{}}
    kobold= {{},{},{},{},{}}
}

local IdealFormations= {
    
}

--*****************************************************************************
local function CpyTbl(a,b) for k,v in a do b[k]=v end end
--*****************************************************************************

--*****************************************************************************
local function CoRoutine_Formations()
--*****************************************************************************
--Returns a formation 16 times.
--NCOW CNOW NCWO NCOW, our four formations
--Applies Improved Initiative as well.

    local Player= {}
    for Formation= 1, 4 do
        coroutine.yield(Player)
    end
    return false
end

--*****************************************************************************
local function Reset()
--*****************************************************************************
    local T= {
        Player= {},
        Enemy = {}
    }
    for Pl= 1, 4 do
        local v= {}
        CpyTbl(PlayerBase[Pl],v)
        v.Hide= true
        v.Alive= true
        v.Formation= Pl
        T.Player[Pl]= v
    end
    for 
end

local R1= 0x1F123BB5  -- Initial RNG
--0x000002DD, 0x00000400
--*****************************************************************************
local function Main()
--*****************************************************************************
--What's the next step, man? Here's the overhead!

--loop: RNG timer
-- loop: RNG steps
--  loop: Formations
--   InitiateCombat
--   EnsureGoodInitiative
--   CombatSteps
--  end Formations
-- end RNG steps
--end RNG timer
end

--[[
Table character{
    Name     :Character name
    Class    :Character class
    HP       :Hit points. Matters for FwdFodder and all kobolds
    AC       :Difficulty to be hit
    Attack   :Bonus/penalty to chance to hit
    DamageD  :Die used in physical damage
    DamageB  :Flat bonus/penalty to physical damage
    Init     :Initiative
    Order    :Character takes nth turn this round

    Hide     :Player is hidden
    Alive    :Haven't died yet
    Formation:Which position? Normally, an index is used, but we might want it
    Ready    :Capable of attack of opportunity, and has Dex bonus

    Acted    :Method where player did something
    Die      :Method to self-terminate
}
Table CbtState{
    Player{
        [index]=   {character}Player by formation
        FwdFodder= {character}Player intended to die
        Cleric   = {character}Garon
        BckFodder= {}Surviving fodder
        Wizard   = {}Wobby
    }
    Enemy{ [index] } Our five kobolds
    Order{ [index] } Who goes in what order
}
]]--