Module:DiceUtils: Difference between revisions

From bg3.wiki
Jump to navigation Jump to search
(Lua module test for dice damage calculation with multiple dice/damage types)
 
No edit summary
 
(18 intermediate revisions by the same user not shown)
Line 1: Line 1:
local p = {}
local p = {}


function p.calculateDamage(frame)
-- For internal use only
args = frame.args
function p._parseDiceInfo(diceStr)
    local dice = string.gmatch(diceStr, "([^,]+)")
result = {}
    local result = {}
damage = {
Acid = {},
Cold = {},
Fire = {},
Force = {},
Healing = {},
Lightning = {},
Necrotic = {},
Poison = {},
Radiant = {},
Thunder = {},
Psychic = {},
Physical = {},
Piercing = {},
Bludgeoning = {},
Slashing = {}
}
for damage_die in string.gmatch(args.dice, "([^,]+)") do
idx = string.find(damage_die, ":")
die = string.sub(damage_die, 1, idx - 1)
d_type = string.sub(damage_die, idx + 1)
table.insert(damage[d_type], die)
end
for d_type, dice in pairs(damage) do
if not next(dice) == nil then
min_damage = 0
max_damage = 0
avg_str = ""
for i, die in ipairs(dice) do
idx = string.find(die, "d")
count = tonumber(string.sub(die, 1, idx -1))
value = tonumber(string.sub(die, idx + 1))
min_damage = min_damage + count
max_damage = max_damage + value * count
avg_str = string.format("(%d - %d)", min_damage, max_damage)
end
damage_str = string.format("%s %s %s", table.concat(dice, " + "), d_type, avg_str)
table.insert(damage_str)
end
end
return table.concat(result, " ")


    for die in dice do
        -- Search for modifier info
        local modIdx = string.find(die, "+") or string.find(die, "-")
        local dieMod = modIdx and tonumber(string.sub(die, modIdx)) or 0
        local die_ = modIdx and string.sub(die, 1, modIdx - 1) or die
        local idx = string.find(die_, "d")
local dieCount = string.sub(die_, 1, idx - 1) -- Holds the value before 'd' (die count)
local dieType = string.sub(die_, idx + 1) -- Holds the value after 'd' (die type)
local info = {
    count = dieCount,
    type_ = dieType,
    mod_ = dieMod
}
table.insert(result, info)
    end
    return result
end
-- For internal use only
function p._average(diceInfo, modifier)
    local minDamage = 0
    local maxDamage = 0
    for i, info in ipairs(diceInfo) do
        -- Minimum damage cannot be below 0
        if ((info.count + info.mod_) > 0) then
            minDamage = minDamage + info.count + info.mod_
        end
        maxDamage = maxDamage + info.count * info.type_ + info.mod_
    end
    if ((minDamage + modifier) < 0) then
        minDamage = 0
    else
        minDamage = minDamage + modifier
    end
    if ((maxDamage + modifier) < 0) then
        maxDamage = 0
    else
        maxDamage = maxDamage + modifier
    end
    return string.format("(%d~%d)", minDamage, maxDamage)
end
-- For internal use only
function p._diceInfoText(diceInfo, modifier)
    local diceText = ""
    local modText = ""
    for i, info in ipairs(diceInfo) do
        if diceText == "" then
            diceText = info.count .. "d" .. info.type_
        else
            diceText = diceText .. " + " .. info.count .. "d" .. info.type_
        end
        local modText_ = (info.mod_ == 0) and
            "" or ((info.mod_ > 0 and " + " or " - ") .. math.abs(info.mod_))
        if modText == "" then
            modText = modText_
        else
            modText = modText .. modText_
        end
    end
    if not (modText == "") then
        diceText = diceText .. modText
    end
    return diceText .. ((modifier == 0) and
            "" or ((modifier > 0 and " + " or " - ") .. math.abs(modifier)))
end
function p.average(frame)
    local args = frame.args
    local dice = args.dice
    local modifier = tonumber(args.modifier) or 0
    if dice == nil then return "" end
    local diceInfo = p._parseDiceInfo(dice)
    return p._average(diceInfo, modifier)
end
function p.diceInfoText(frame)
    local args = frame.args
    local dice = args.dice
    local modifier = tonumber(args.modifier) or 0
    if dice == nil then return "" end
    local diceInfo = p._parseDiceInfo(dice)
    return p._diceInfoText(diceInfo, modifier)
end
function p.diceInfoTextWithAvg(frame)
    local args = frame.args
    local dice = args.dice
    local modifier = tonumber(args.modifier) or 0
    if dice == nil then return "" end
    local diceInfo = p._parseDiceInfo(dice)
    return p._diceInfoText(diceInfo, modifier) .. " " .. p._average(diceInfo, modifier)
end
end


return p
return p

Latest revision as of 06:33, 21 July 2023

Documentation for this module may be created at Module:DiceUtils/doc

local p = {}

-- For internal use only
function p._parseDiceInfo(diceStr)
    local dice = string.gmatch(diceStr, "([^,]+)")
    local result = {}

    for die in dice do
        -- Search for modifier info
        local modIdx = string.find(die, "+") or string.find(die, "-")
        local dieMod = modIdx and tonumber(string.sub(die, modIdx)) or 0
        local die_ = modIdx and string.sub(die, 1, modIdx - 1) or die

        local idx = string.find(die_, "d")
		local dieCount = string.sub(die_, 1, idx - 1) -- Holds the value before 'd' (die count)
		local dieType = string.sub(die_, idx + 1) -- Holds the value after 'd' (die type)

		local info = {
		    count = dieCount,
		    type_ = dieType,
		    mod_ = dieMod
		}

		table.insert(result, info)
    end

    return result
end

-- For internal use only
function p._average(diceInfo, modifier)
    local minDamage = 0
    local maxDamage = 0

    for i, info in ipairs(diceInfo) do
        -- Minimum damage cannot be below 0
        if ((info.count + info.mod_) > 0) then
            minDamage = minDamage + info.count + info.mod_
        end
        maxDamage = maxDamage + info.count * info.type_ + info.mod_
    end

    if ((minDamage + modifier) < 0) then
        minDamage = 0
    else
        minDamage = minDamage + modifier
    end

    if ((maxDamage + modifier) < 0) then
        maxDamage = 0
    else
        maxDamage = maxDamage + modifier
    end


    return string.format("(%d~%d)", minDamage, maxDamage)
end

-- For internal use only
function p._diceInfoText(diceInfo, modifier)
    local diceText = ""
    local modText = ""

    for i, info in ipairs(diceInfo) do
        if diceText == "" then
            diceText = info.count .. "d" .. info.type_
        else
            diceText = diceText .. " + " .. info.count .. "d" .. info.type_
        end

        local modText_ = (info.mod_ == 0) and
            "" or ((info.mod_ > 0 and " + " or " - ") .. math.abs(info.mod_))

        if modText == "" then
            modText = modText_
        else
            modText = modText .. modText_
        end
    end

    if not (modText == "") then
        diceText = diceText .. modText
    end

    return diceText .. ((modifier == 0) and
            "" or ((modifier > 0 and " + " or " - ") .. math.abs(modifier)))
end

function p.average(frame)
    local args = frame.args
    local dice = args.dice
    local modifier = tonumber(args.modifier) or 0

    if dice == nil then return "" end

    local diceInfo = p._parseDiceInfo(dice)

    return p._average(diceInfo, modifier)
end

function p.diceInfoText(frame)
    local args = frame.args
    local dice = args.dice
    local modifier = tonumber(args.modifier) or 0

    if dice == nil then return "" end

    local diceInfo = p._parseDiceInfo(dice)

    return p._diceInfoText(diceInfo, modifier)
end

function p.diceInfoTextWithAvg(frame)
    local args = frame.args
    local dice = args.dice
    local modifier = tonumber(args.modifier) or 0

    if dice == nil then return "" end

    local diceInfo = p._parseDiceInfo(dice)

    return p._diceInfoText(diceInfo, modifier) .. " " .. p._average(diceInfo, modifier)
end

return p