--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 } ]]--