Difference between revisions of "Module:Sandbox/Arcangelus"

From RimWorld Wiki
Jump to navigation Jump to search
m
m (Full replacement. Revert later.)
 
Line 1: Line 1:
--[[
+
--local getArgs -- lazily initialized
 
+
local getArgs = require('Module:Arguments').getArgs
This module provides a number of basic mathematical operations.
+
local p = {}
 
 
]]
 
 
 
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 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
 
-- local smw = require('mw.smw') -- This potential solution requires SemanticScribunto. This also requires PHP 7.3 (done), MediaWiki 1.39 and Semantic MediaWiki 4.0.2 (or later on all accounts)
 
-- At the time of writing (20/02/2025) the wiki has: PHP 7.4.33 (fpm-fcgi), MediaWiki 1.35.8, Semantic MediaWiki 3.2.3.
 
-- local askResult = smw.ask(/'[[Category:YourCategory]]|?Property1|?Property2') This is an example as to how to use it. This is a ipair
 
 
--[[
 
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, tonumber(args[5*i-1]) or 0)
 
table.insert(Base_AT, i, tonumber(args[5*i]) or 0)
 
table.insert(Base_Cooldown, i, tonumber(args[5*i+1]) or 0)
 
table.insert(Base_chance, i, tonumber(args[5*i+2]) or 0)
 
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 unpackNumberArgs(args)
 
local function unpackNumberArgs(args)
 
-- Returns an unpacked list of arguments specified with numerical keys.
 
-- Returns an unpacked list of arguments specified with numerical keys.
Line 152: Line 14:
 
return unpack(ret)
 
return unpack(ret)
 
end
 
end
 +
 +
--Stat Factors Table Row
  
 
function wrap.TableRow(args)
 
function wrap.TableRow(args)
Line 203: Line 67:
 
end
 
end
  
--------------------------------------------------------------------------------
+
-- Deep Drill Speed custom version. Includes Time in minutes (at x1 speed)
 +
function wrap.Table_DDS(frame) --The normal unpacking is giving me issues, so this is a potential if ugly work around.
 +
-- return p._Table_DDS(unpackNumberArgs(args))
 +
local args = getArgs(frame)
 +
return p._Table_DDS(tonumber(args[1]),tonumber(args[2]),tonumber(args[3]))
 +
end
 +
function p._Table_DDS(skillBase, skillBonus, capImportance)
 +
--statMin=0 so omitted, skill uncapped so statMax omitted.
 +
local argumentos={skillBase, skillBonus, capImportance}
  
function p.Apparel_AP_Calculation(frame)
+
for i = 1,3 do --This should prevent errors if a number is not defined.
local AP=math.max((tonumber(frame.args.ap) or 0), 0)
+
if type(argumentos[i])~='number' then
local armor = {tonumber(frame.args.armor1), tonumber(frame.args.armor2), tonumber(frame.args.armor3), tonumber(frame.args.armor4)}
+
argumentos[i]=0
return p._Apparel_AP_Calculation(armor, AP)
 
end
 
function p._Apparel_AP_Calculation(armor, AP)
 
local value = 100
 
for i=1, #armor do
 
if armor[i]~=nil then
 
EFFarmor = math.max(armor[i] - AP, 0)
 
value = value * ( math.max(0, 100-EFFarmor) + math.min(EFFarmor, 200-EFFarmor)/4 ) / 100
 
 
end
 
end
 
end
 
end
return value
+
skillBase,skillBonus,capImportance = argumentos[1],argumentos[2],argumentos[3]
-- return value.." "..(armor[1] or "nil").." "..(armor[2] or "nil").." "..(armor[3] or "nil").." "..(armor[4] or "nil").." "..(A or "nil")
+
 
end
+
-- If needed, the Header can be moved outside
 +
local Header = '{| class = "mw-collapsible wikitable" width="180" style="text-align: center;"\r\n' -- May just call it from outside.
 +
Header = Header..'! rowspan=2 | Mining Skill Level'..'\r\n'
 +
Header = Header..'! colspan=3 | Deep Drilling Speed<br/>(Real time at 1x speed)'..'\r\n'
 +
Header = Header..'|-\r\n'
 +
Header = Header..'! 100% Manipulation !! 125% Manipulation !! 150% Manipulation'..'\r\n'
 +
local line, cuerpo = "", ""
 +
local factor = 0
 +
local val1, val2, val3 = 0,0,0
 +
local time1, time2, time3 = 0,0,0
 +
 +
for i = 0, 20 do --This creates the table itself.
 +
line = "|-\r\n!"..i.."\r\n|" --Just for order
 +
factor = skillBase + tonumber(skillBonus) * i
 +
val1 = math.max(factor, 0)
 +
time1 = 14000/(val1*3600) -- This is time in minutes. Because factor is a percentage, I need to multiply this by 100 to compensate.
 +
-- This formats the number as a percent value with X decimals, rounded up. Change to %.0f for no decimals.
 +
R_Pval= string.format("%.0f", val1*100).."% <br/>"..string.format("(%.2f min)", time1)
 +
 
 +
val2 = factor * ( 1 + capImportance * 0.25)
 +
val2 = math.max(val2, 0)
 +
time2 = 14000/(val2*3600)
 +
R_Sval= string.format("<td>%.0f", val2*100).."% <br/>"..string.format("(%.2f min)", time2).."</td>"
  
local function makeArgArray(...)
+
val3 = factor * ( 1 + capImportance * 0.5)
-- Makes an array of arguments from a list of arguments that might include nils.
+
val3 = math.max(val3, 0)
local args = {...} -- Table of arguments. It might contain nils or non-number values, so we can't use ipairs.
+
time3 = 14000/(val3*3600)
local nums = {} -- Stores the numbers of valid numerical arguments.
+
R_Tval= string.format("<td>%.0f", val3*100).."% <br/>"..string.format("(%.2f min)", time3).."</td>"
local ret = {}
+
for k, v in pairs(args) do
+
cuerpo = cuerpo..line..R_Pval..R_Sval..R_Tval.."\r\n"
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
 
end
return ret
 
end
 
  
local function fold(func, ...)
+
return Header..cuerpo.."|}" --This should be the entire table. I may be a space short.
-- 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
 
end
  
 
--[[
 
--[[
Fold arguments by selectively choosing values (func should return when to choose the current "dominant" value).
+
Wrapper function that does basic argument processing. This ensures that all functions from #invoke can use either the current
 +
frame or the parent frame, and it also trims whitespace for all arguments and removes blank arguments.
 
]]
 
]]
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
+
local mt = { __index = function(t, k)
--return setmetatable(p, mt)
+
return function(frame)
 +
if not getArgs then
 +
getArgs = require('Module:Arguments').getArgs
 +
end
 +
return wrap[k](getArgs(frame))  -- Argument processing is left to Module:Arguments. Whitespace is trimmed and blank arguments are removed.
 +
end
 +
end }
 +
 
 +
return setmetatable(p, mt)
 +
 
 +
 
 +
-- END OF MODULE

Latest revision as of 20:27, 6 March 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)



--local getArgs -- lazily initialized
local getArgs = require('Module:Arguments').getArgs
local p = {}
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 function unpackNumberArgs(args)
	-- Returns an unpacked list of arguments specified with numerical keys.
	local ret = {}
	for k, v in pairs(args) do
		if type(k) == 'number' then
			table.insert(ret, v)
		end
	end
	return unpack(ret)
end

--Stat Factors Table Row

function wrap.TableRow(args)
	return p._TableRow(unpackNumberArgs(args))
end
function p._TableRow(skillBase, skillBonus, statMin, statMax, capImportance, capLimit, resultCols, LV, Ln)
	--Remove local if these variables are to be used somewhere else. 
	local argumentos={skillBase,skillBonus,statMin,statMax,capImportance,capLimit,resultCols,LV,Ln}
	
	for i = 1,8 do --This should prevent errors if a number is not defined.
		if type(argumentos[i])~='number' then
			if i == 6 then -- In case capLimit is not correctly set.
				argumentos[6]=1000
			else
				argumentos[i]=0
			end
		else 
			argumentos[i]=tonumber(argumentos[i])
		end
	end
--	skillBase,skillBonus,statMin,statMax,capImportance,capLimit,resultCols,LV,Ln = argumentos[1],argumentos[2],argumentos[3],argumentos[4],argumentos[5],argumentos[6],argumentos[7],argumentos[8]
	-- Do note that statMin, statMax are handled by "Template:Stat Factors Table" (including defaults)

	if tonumber(Ln)==nil then --Sanitizes input and allows for Ln=0.
		factor = skillBase + (tonumber(skillBonus) or 0) * LV
	else
		factor = tonumber(Ln)
	end

	local Pval = math.min(math.max(factor,statMin),statMax)
	R_Pval = tostring(math.floor(Pval*10000+0.5)/100).."%" -- This formats the number as a 2 digit percent value, rounded up.
--	R_Pval = string.format("%.2f", Pval*100).."%" -- While Easier to parse, this has the issue of forcing 2 decimals for all numbers.
	if tonumber(resultCols)>1 then
		Pval = factor * ( 1 + capImportance * math.min(capLimit-1, 0.25))
		Pval = math.min(math.max(Pval,statMin),statMax)
		R_Sval="<td>"..tostring(math.floor(Pval*10000+0.5)/100).."% </td>"
	else
		R_Sval=""
	end

	if tonumber(resultCols)>2 then
		Pval = factor * ( 1 + capImportance * math.min(capLimit-1, 0.5))
		Pval = math.min(math.max(Pval,statMin),statMax)
		R_Tval="<td>"..tostring(math.floor(Pval*10000+0.5)/100).."% </td>"
	else
		R_Tval=""
	end
	
	return "|-\r\n!"..LV.."\r\n|"..R_Pval..R_Sval..R_Tval
	-- There are more efficient ways, but this works.
end

-- Deep Drill Speed custom version. Includes Time in minutes (at x1 speed)
function wrap.Table_DDS(frame) --The normal unpacking is giving me issues, so this is a potential if ugly work around.
--	return p._Table_DDS(unpackNumberArgs(args))
	local args = getArgs(frame)
	return p._Table_DDS(tonumber(args[1]),tonumber(args[2]),tonumber(args[3]))
end
function p._Table_DDS(skillBase, skillBonus, capImportance)
	--statMin=0 so omitted, skill uncapped so statMax omitted.
	local argumentos={skillBase, skillBonus, capImportance}

	for i = 1,3 do --This should prevent errors if a number is not defined.
		if type(argumentos[i])~='number' then
			argumentos[i]=0
		end
	end
	skillBase,skillBonus,capImportance = argumentos[1],argumentos[2],argumentos[3]

	-- If needed, the Header can be moved outside
	local Header = '{| class = "mw-collapsible wikitable" width="180" style="text-align: center;"\r\n' -- May just call it from outside.
	Header = Header..'! rowspan=2 | Mining Skill Level'..'\r\n'
	Header = Header..'! colspan=3 | Deep Drilling Speed<br/>(Real time at 1x speed)'..'\r\n'
	Header = Header..'|-\r\n'
	Header = Header..'! 100% Manipulation !! 125% Manipulation !! 150% Manipulation'..'\r\n'
	local line, cuerpo = "", ""
	local factor = 0
	local val1, val2, val3 = 0,0,0
	local time1, time2, time3 = 0,0,0
	
	for i = 0, 20 do --This creates the table itself.
		line = "|-\r\n!"..i.."\r\n|" --Just for order
		factor = skillBase + tonumber(skillBonus) * i
		val1 = math.max(factor, 0)
		time1 = 14000/(val1*3600) -- This is time in minutes. Because factor is a percentage, I need to multiply this by 100 to compensate.
		-- This formats the number as a percent value with X decimals, rounded up. Change to %.0f for no decimals.
		R_Pval= string.format("%.0f", val1*100).."% <br/>"..string.format("(%.2f min)", time1)

		val2 = factor * ( 1 + capImportance * 0.25)
		val2 = math.max(val2, 0)
		time2 = 14000/(val2*3600)
		R_Sval= string.format("<td>%.0f", val2*100).."% <br/>"..string.format("(%.2f min)", time2).."</td>"

		val3 = factor * ( 1 + capImportance * 0.5)
		val3 = math.max(val3, 0)
		time3 = 14000/(val3*3600)
		R_Tval= string.format("<td>%.0f", val3*100).."% <br/>"..string.format("(%.2f min)", time3).."</td>"
		
		cuerpo = cuerpo..line..R_Pval..R_Sval..R_Tval.."\r\n"
	end

	return Header..cuerpo.."|}" --This should be the entire table. I may be a space short.
end

--[[
Wrapper function that does basic argument processing. This ensures that all functions from #invoke can use either the current
frame or the parent frame, and it also trims whitespace for all arguments and removes blank arguments.
]]

local mt = { __index = function(t, k)
	return function(frame)
		if not getArgs then
			getArgs = require('Module:Arguments').getArgs
		end
		return wrap[k](getArgs(frame))  -- Argument processing is left to Module:Arguments. Whitespace is trimmed and blank arguments are removed.
	end
end }

return setmetatable(p, mt)


-- END OF MODULE