Difference between revisions of "Module:Sandbox/Arcangelus"
Arcangelus (talk | contribs) m |
Arcangelus (talk | contribs) m |
||
(116 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
− | local p = {} | + | --[[ |
− | + | ||
− | function p. | + | This module provides a number of basic mathematical operations. |
− | + | ||
+ | ]] | ||
+ | |||
+ | local p = {} -- Holds functions to be returned from #invoke, and functions to make available to other Lua modules.0. | ||
+ | local wrap = {} -- Holds wrapper functions that process arguments from #invoke. These act as intemediary between functions meant for #invoke and functions meant for Lua. | ||
+ | local getArgs = require('Module:Arguments').getArgs | ||
+ | local yesno | ||
+ | |||
+ | --[[ | ||
+ | Helper functions used to avoid redundant code. | ||
+ | ]] | ||
+ | |||
+ | function p.main(frame) | ||
+ | local args = getArgs(frame) | ||
+ | -- args[1] is Material, args[2] is quality | ||
+ | local Type,Base_DG,Base_AT,Base_Cooldown,Base_chance = {},{},{},{},{} | ||
+ | for i=1, 12 do --Tables with values from these sections. Easier to parse. | ||
+ | table.insert(Type, i, args[5*i-2] or "") | ||
+ | table.insert(Base_DG, i, args[5*i-1] or 0) | ||
+ | table.insert(Base_AT, i, args[5*i] or 0) | ||
+ | table.insert(Base_Cooldown, i, args[5*i+1] or 0) | ||
+ | table.insert(Base_chance, i, args[5*i+2] or 0) | ||
+ | end | ||
+ | |||
+ | -- return "Type:"..Type[1]..Type[2]..Type[3]..Type[4]..Type[5]..Type[6].." Base_DG:"..Base_DG[1]..Base_DG[2]..Base_DG[3]..Base_DG[4]..Base_DG[5]..Base_DG[6].." Base_AT: "..Base_AT[1]..Base_AT[2]..Base_AT[3]..Base_AT[4]..Base_AT[5]..Base_AT[6].." Base_Cooldown:"..Base_Cooldown[1]..Base_Cooldown[2]..Base_Cooldown[3]..Base_Cooldown[4]..Base_Cooldown[5]..Base_Cooldown[6].." Base_chance:"..Base_chance[1]..Base_chance[2]..Base_chance[3]..Base_chance[4]..Base_chance[5]..Base_chance[6].." END" | ||
+ | return p._DPS2(args[1], args[2], Type, Base_DG, Base_AT, Base_Cooldown, Base_chance) | ||
+ | end | ||
+ | |||
+ | function p._DPS2(material, quality, Type, Base_DG, Base_AT, Base_Cooldown, Base_chance) | ||
+ | local tablas = mw.loadData("Module:Arcangel/Testing"); | ||
+ | local cooldownFactor=tablas.material_tbl[material]["Cooldown speed factor"] or 1 | ||
+ | local BQFactor=(tablas.qualitytbl[quality] or 1)*(tablas.material_tbl[material]["Damage factor (Sharp)"] or 1) | ||
+ | local SQFactor=(tablas.qualitytbl[quality] or 1)*(tablas.material_tbl[material]["Damage factor (Blunt)"] or 1) | ||
+ | local ISW, Damage, Pierce, Cooldowns, ATKchance, valores = {},{},{},{},{}, {} | ||
+ | local ISW_X, maxSelectionWeight, best, mid, cool = 0,0,0,0,0 | ||
+ | local attackDamage, attackAP = 0,0 | ||
+ | local WeightedDamage, WeightedCooldown, WeightedAP = 0,0,0 | ||
+ | |||
+ | for i=1, 12 do -- check the default values of attacks 5-12 | ||
+ | if Type[i]~=nil and Type[i]~="" then | ||
+ | if tablas.blunt_damage[Type[i]] then | ||
+ | attackDamage = Base_DG[i] * BQFactor | ||
+ | attackAP = (Base_AT[i] * BQFactor) --or attackDamage*1.5 Removed as this value always comes defined from "Infobox main". | ||
+ | else | ||
+ | attackDamage = Base_DG[i] * SQFactor | ||
+ | attackAP = (Base_AT[i] * SQFactor) --or attackDamage*1.5 | ||
+ | end | ||
+ | ISW_X = attackDamage * (1 + attackAP/100) * Base_chance[i] / (Base_Cooldown[i]*cooldownFactor) --The attackAP/100 comes from the fact that "Armor Penetration" is a percentage. | ||
+ | cool = Base_Cooldown[i]*cooldownFactor | ||
+ | else | ||
+ | ISW_X = 0 | ||
+ | attackDamage=0 | ||
+ | attackAP=0 | ||
+ | cool = 1 | ||
+ | end | ||
+ | if ISW_X ~= ISW_X then ISW_X=0 end --This removes Nan. The are better methods, but this is easier. May be redundant. | ||
+ | if ISW_X>maxSelectionWeight then | ||
+ | maxSelectionWeight=ISW_X | ||
+ | end | ||
+ | table.insert(ISW, ISW_X) --Removed the position "i" as it doesn't work as I expected. It pushes the values on "i" and above 1 index above rather than replacing that position. | ||
+ | table.insert(Damage, attackDamage) | ||
+ | table.insert(Pierce, attackAP) | ||
+ | table.insert(Cooldowns, Base_Cooldown[i]*cooldownFactor) | ||
+ | end | ||
+ | |||
+ | for key, value in pairs(ISW) do --This determines the quality of the attacks and how may of each category there are. | ||
+ | if value/maxSelectionWeight>=0.25 then | ||
+ | if value/maxSelectionWeight>=0.95 then | ||
+ | best=best+1 | ||
+ | valores[#valores+1]=2 | ||
+ | else | ||
+ | mid=mid+1 | ||
+ | valores[#valores+1]=1 | ||
+ | end | ||
+ | else | ||
+ | valores[#valores+1]=0 | ||
+ | end | ||
+ | end | ||
+ | |||
+ | if mid==0 then -- No mid attacks | ||
+ | for i=1, 12 do | ||
+ | if valores[i]~=0 then | ||
+ | WeightedDamage=WeightedDamage+Damage[i] | ||
+ | WeightedCooldown=WeightedCooldown+Cooldowns[i] | ||
+ | WeightedAP=WeightedAP+Pierce[i] | ||
+ | end | ||
+ | end | ||
+ | -- With only "best" atacks, all have equal weight. No point in complicating the formula. | ||
+ | WeightedDamage=WeightedDamage/best | ||
+ | WeightedCooldown=WeightedCooldown/best | ||
+ | WeightedAP=WeightedAP/best | ||
+ | else | ||
+ | for i=1, 12 do | ||
+ | if valores[i]==1 then --mid attacks are 25% of the weight | ||
+ | WeightedDamage=WeightedDamage+Damage[i]/(4*mid) | ||
+ | WeightedCooldown=WeightedCooldown+Cooldowns[i]/(4*mid) | ||
+ | WeightedAP=WeightedAP+Pierce[i]/(4*mid) | ||
+ | elseif valores[i]==2 then --best attacks are 75% of the weight | ||
+ | WeightedDamage=WeightedDamage+Damage[i]*0.75/best | ||
+ | WeightedCooldown=WeightedCooldown+Cooldowns[i]*0.75/best | ||
+ | WeightedAP=WeightedAP+Pierce[i]*0.75/best | ||
+ | end | ||
+ | end | ||
+ | end | ||
+ | |||
+ | TrueDPS = WeightedDamage/WeightedCooldown | ||
+ | TrueAP = WeightedAP --Not used right now. | ||
+ | return TrueDPS | ||
+ | -- return tostring(TrueDPS).." WD:"..tostring(WeightedDamage).." WC:"..tostring(WeightedCooldown).." WAP:"..tostring(WeightedAP) | ||
+ | |||
+ | --[[ local a="" -- I leave this here in case I need to test the input. | ||
+ | for key,value in ipairs(Type) do | ||
+ | a=a..value..", " | ||
+ | end | ||
+ | a="<br/>Type: "..a.." <br/>Base_DG: " | ||
+ | for key,value in ipairs(Base_DG) do | ||
+ | a=a..value..", " | ||
+ | end | ||
+ | a=a.." <br/>Base_AT: " | ||
+ | for key,value in ipairs(Base_AT) do | ||
+ | a=a..value..", " | ||
+ | end | ||
+ | a=a.." <br/>Base_Cooldown: " | ||
+ | for key,value in ipairs(Base_Cooldown) do | ||
+ | a=a..value..", " | ||
+ | end | ||
+ | a=a.." <br/>Base_chance: " | ||
+ | for key,value in ipairs(Base_chance) do | ||
+ | a=a..value..", " | ||
+ | end | ||
+ | a=a.." <br/>Initial Selection Weight: " --These one look weird. | ||
+ | for key,value in ipairs(ISW) do | ||
+ | a=a..value..", " | ||
+ | end | ||
+ | return "DPS:"..tostring(TrueDPS).." WD:"..tostring(WeightedDamage).." WC:"..tostring(WeightedCooldown).." WA:"..tostring(WeightedAP).." "..a ]] | ||
end | end | ||
− | |||
− | return | + | local function makeArgArray(...) |
+ | -- Makes an array of arguments from a list of arguments that might include nils. | ||
+ | local args = {...} -- Table of arguments. It might contain nils or non-number values, so we can't use ipairs. | ||
+ | local nums = {} -- Stores the numbers of valid numerical arguments. | ||
+ | local ret = {} | ||
+ | for k, v in pairs(args) do | ||
+ | v = p._cleanNumber(v) | ||
+ | if v then | ||
+ | nums[#nums + 1] = k | ||
+ | args[k] = v | ||
+ | end | ||
+ | end | ||
+ | table.sort(nums) | ||
+ | for i, num in ipairs(nums) do | ||
+ | ret[#ret + 1] = args[num] | ||
+ | end | ||
+ | return ret | ||
+ | end | ||
+ | |||
+ | local function fold(func, ...) | ||
+ | -- Use a function on all supplied arguments, and return the result. The function must accept two numbers as parameters, | ||
+ | -- and must return a number as an output. This number is then supplied as input to the next function call. | ||
+ | local vals = makeArgArray(...) | ||
+ | local count = #vals -- The number of valid arguments | ||
+ | if count == 0 then return | ||
+ | -- Exit if we have no valid args, otherwise removing the first arg would cause an error. | ||
+ | nil, 0 | ||
+ | end | ||
+ | local ret = table.remove(vals, 1) | ||
+ | for _, val in ipairs(vals) do | ||
+ | ret = func(ret, val) | ||
+ | end | ||
+ | return ret, count | ||
+ | end | ||
+ | |||
+ | --[[ | ||
+ | Fold arguments by selectively choosing values (func should return when to choose the current "dominant" value). | ||
+ | ]] | ||
+ | local function binary_fold(func, ...) | ||
+ | local value = fold((function(a, b) if func(a, b) then return a else return b end end), ...) | ||
+ | return value | ||
+ | end | ||
+ | |||
+ | return p | ||
+ | --return setmetatable(p, mt) |
Latest revision as of 15:53, 31 January 2025
Welcome to the RimWorld Wiki sandbox!
This sandbox is where you can experiment and practice working on a wiki page. This page will usually have little or no content. Feel free to add content or to make changes and save them to see the results.
To learn about editing and formatting start here: Help:Contents. Just start with the basics... enter some text, and learn the other pieces as you go.
Your content contributions are welcome and important. The wiki is a collaborative effort and others can help with formatting and other improvements.]
Best wishes!
Description[edit]
This is a doc attached to my sandbox. I'll use it to see the effects of my changes W/o messing something important
NOTE: LUA is usually slower than ParserFunctions for short statements. The factor varies from 7-1 to 2-1.
Lua only is an advantage to long statements, nested logic, loops (maybe others case i don't see right now).
expr only uses 1 Preprocessor visited node count, in general. Variables may change that.
function p._TableRow(skillBase, skillBonus, statMin, statMax, capImportance, capLimit, resultCols, LV, Ln)
--[[ This module provides a number of basic mathematical operations. ]] local p = {} -- Holds functions to be returned from #invoke, and functions to make available to other Lua modules.0. local wrap = {} -- Holds wrapper functions that process arguments from #invoke. These act as intemediary between functions meant for #invoke and functions meant for Lua. local getArgs = require('Module:Arguments').getArgs local yesno --[[ Helper functions used to avoid redundant code. ]] function p.main(frame) local args = getArgs(frame) -- args[1] is Material, args[2] is quality local Type,Base_DG,Base_AT,Base_Cooldown,Base_chance = {},{},{},{},{} for i=1, 12 do --Tables with values from these sections. Easier to parse. table.insert(Type, i, args[5*i-2] or "") table.insert(Base_DG, i, args[5*i-1] or 0) table.insert(Base_AT, i, args[5*i] or 0) table.insert(Base_Cooldown, i, args[5*i+1] or 0) table.insert(Base_chance, i, args[5*i+2] or 0) end -- return "Type:"..Type[1]..Type[2]..Type[3]..Type[4]..Type[5]..Type[6].." Base_DG:"..Base_DG[1]..Base_DG[2]..Base_DG[3]..Base_DG[4]..Base_DG[5]..Base_DG[6].." Base_AT: "..Base_AT[1]..Base_AT[2]..Base_AT[3]..Base_AT[4]..Base_AT[5]..Base_AT[6].." Base_Cooldown:"..Base_Cooldown[1]..Base_Cooldown[2]..Base_Cooldown[3]..Base_Cooldown[4]..Base_Cooldown[5]..Base_Cooldown[6].." Base_chance:"..Base_chance[1]..Base_chance[2]..Base_chance[3]..Base_chance[4]..Base_chance[5]..Base_chance[6].." END" return p._DPS2(args[1], args[2], Type, Base_DG, Base_AT, Base_Cooldown, Base_chance) end function p._DPS2(material, quality, Type, Base_DG, Base_AT, Base_Cooldown, Base_chance) local tablas = mw.loadData("Module:Arcangel/Testing"); local cooldownFactor=tablas.material_tbl[material]["Cooldown speed factor"] or 1 local BQFactor=(tablas.qualitytbl[quality] or 1)*(tablas.material_tbl[material]["Damage factor (Sharp)"] or 1) local SQFactor=(tablas.qualitytbl[quality] or 1)*(tablas.material_tbl[material]["Damage factor (Blunt)"] or 1) local ISW, Damage, Pierce, Cooldowns, ATKchance, valores = {},{},{},{},{}, {} local ISW_X, maxSelectionWeight, best, mid, cool = 0,0,0,0,0 local attackDamage, attackAP = 0,0 local WeightedDamage, WeightedCooldown, WeightedAP = 0,0,0 for i=1, 12 do -- check the default values of attacks 5-12 if Type[i]~=nil and Type[i]~="" then if tablas.blunt_damage[Type[i]] then attackDamage = Base_DG[i] * BQFactor attackAP = (Base_AT[i] * BQFactor) --or attackDamage*1.5 Removed as this value always comes defined from "Infobox main". else attackDamage = Base_DG[i] * SQFactor attackAP = (Base_AT[i] * SQFactor) --or attackDamage*1.5 end ISW_X = attackDamage * (1 + attackAP/100) * Base_chance[i] / (Base_Cooldown[i]*cooldownFactor) --The attackAP/100 comes from the fact that "Armor Penetration" is a percentage. cool = Base_Cooldown[i]*cooldownFactor else ISW_X = 0 attackDamage=0 attackAP=0 cool = 1 end if ISW_X ~= ISW_X then ISW_X=0 end --This removes Nan. The are better methods, but this is easier. May be redundant. if ISW_X>maxSelectionWeight then maxSelectionWeight=ISW_X end table.insert(ISW, ISW_X) --Removed the position "i" as it doesn't work as I expected. It pushes the values on "i" and above 1 index above rather than replacing that position. table.insert(Damage, attackDamage) table.insert(Pierce, attackAP) table.insert(Cooldowns, Base_Cooldown[i]*cooldownFactor) end for key, value in pairs(ISW) do --This determines the quality of the attacks and how may of each category there are. if value/maxSelectionWeight>=0.25 then if value/maxSelectionWeight>=0.95 then best=best+1 valores[#valores+1]=2 else mid=mid+1 valores[#valores+1]=1 end else valores[#valores+1]=0 end end if mid==0 then -- No mid attacks for i=1, 12 do if valores[i]~=0 then WeightedDamage=WeightedDamage+Damage[i] WeightedCooldown=WeightedCooldown+Cooldowns[i] WeightedAP=WeightedAP+Pierce[i] end end -- With only "best" atacks, all have equal weight. No point in complicating the formula. WeightedDamage=WeightedDamage/best WeightedCooldown=WeightedCooldown/best WeightedAP=WeightedAP/best else for i=1, 12 do if valores[i]==1 then --mid attacks are 25% of the weight WeightedDamage=WeightedDamage+Damage[i]/(4*mid) WeightedCooldown=WeightedCooldown+Cooldowns[i]/(4*mid) WeightedAP=WeightedAP+Pierce[i]/(4*mid) elseif valores[i]==2 then --best attacks are 75% of the weight WeightedDamage=WeightedDamage+Damage[i]*0.75/best WeightedCooldown=WeightedCooldown+Cooldowns[i]*0.75/best WeightedAP=WeightedAP+Pierce[i]*0.75/best end end end TrueDPS = WeightedDamage/WeightedCooldown TrueAP = WeightedAP --Not used right now. return TrueDPS -- return tostring(TrueDPS).." WD:"..tostring(WeightedDamage).." WC:"..tostring(WeightedCooldown).." WAP:"..tostring(WeightedAP) --[[ local a="" -- I leave this here in case I need to test the input. for key,value in ipairs(Type) do a=a..value..", " end a="<br/>Type: "..a.." <br/>Base_DG: " for key,value in ipairs(Base_DG) do a=a..value..", " end a=a.." <br/>Base_AT: " for key,value in ipairs(Base_AT) do a=a..value..", " end a=a.." <br/>Base_Cooldown: " for key,value in ipairs(Base_Cooldown) do a=a..value..", " end a=a.." <br/>Base_chance: " for key,value in ipairs(Base_chance) do a=a..value..", " end a=a.." <br/>Initial Selection Weight: " --These one look weird. for key,value in ipairs(ISW) do a=a..value..", " end return "DPS:"..tostring(TrueDPS).." WD:"..tostring(WeightedDamage).." WC:"..tostring(WeightedCooldown).." WA:"..tostring(WeightedAP).." "..a ]] end local function makeArgArray(...) -- Makes an array of arguments from a list of arguments that might include nils. local args = {...} -- Table of arguments. It might contain nils or non-number values, so we can't use ipairs. local nums = {} -- Stores the numbers of valid numerical arguments. local ret = {} for k, v in pairs(args) do v = p._cleanNumber(v) if v then nums[#nums + 1] = k args[k] = v end end table.sort(nums) for i, num in ipairs(nums) do ret[#ret + 1] = args[num] end return ret end local function fold(func, ...) -- Use a function on all supplied arguments, and return the result. The function must accept two numbers as parameters, -- and must return a number as an output. This number is then supplied as input to the next function call. local vals = makeArgArray(...) local count = #vals -- The number of valid arguments if count == 0 then return -- Exit if we have no valid args, otherwise removing the first arg would cause an error. nil, 0 end local ret = table.remove(vals, 1) for _, val in ipairs(vals) do ret = func(ret, val) end return ret, count end --[[ Fold arguments by selectively choosing values (func should return when to choose the current "dominant" value). ]] local function binary_fold(func, ...) local value = fold((function(a, b) if func(a, b) then return a else return b end end), ...) return value end return p --return setmetatable(p, mt)