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