Difference between revisions of "Module:Sandbox/Arcangelus"

From RimWorld Wiki
Jump to navigation Jump to search
m
m (Thought testing. Again.)
Line 1: Line 1:
local yesno, getArgs -- lazily initialized
+
--[[
 +
This module implements the functions of Template:Thought
 +
]]
 +
 
 
local p = {}
 
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 getArgs = require('Module:Arguments').getArgs
  
--Copied from https://en.wikipedia.org/wiki/Module:Math
+
--[[ The template argument goes to "main"
local function err(msg)
+
Only this funcion will work when invoked. This is case sensitive.
-- Generates wikitext error messages.
+
What it does is obtain the data from the wiki to a fomrat readable by other functions]]
return mw.ustring.format('<strong class="error">Formatting error: %s</strong>', msg)
 
end
 
  
local function unpackNumberArgs(args)
+
function p.main(frame)
-- Returns an unpacked list of arguments specified with numerical keys.
+
local args = getArgs(frame)
local ret = {}
+
local desc = tostring(args["desc"])
for k, v in pairs(args) do
+
local label = tostring(args["label"])
if type(k) == 'number' then
+
local duration = tonumber(args["duration"])
table.insert(ret, v)
+
local stack = tonumber(args["stack"])
end
+
local multi = tonumber(args["multi"]) or 1
 +
--[[ The advantage of adding values to an empty list rather than defining a list
 +
with the correct values is that no nil values will get into the list this way.
 +
This means that values don't have to be consecutive.
 +
EX: value9 is valid w/o defining value2 to value8.
 +
]]
 +
local valores = {}
 +
valores[#valores+1]=args["value"]
 +
valores[#valores+1]=args["value2"]
 +
valores[#valores+1]=args["value3"]
 +
valores[#valores+1]=args["value4"]
 +
valores[#valores+1]=args["value5"]
 +
valores[#valores+1]=args["value6"]
 +
valores[#valores+1]=args["value7"]
 +
valores[#valores+1]=args["value8"]
 +
valores[#valores+1]=args["value9"]
 +
if tonumber(args["value"]) then
 +
return p._main(desc, label, duration, stack, multi, valores)
 +
else
 +
return "<big><b>Missing value. Please, define a numerical value to use.</b></big>"
 
end
 
end
return unpack(ret)
 
 
end
 
end
  
local function makeArgArray(...)
+
--[[
-- Makes an array of arguments from a list of arguments that might include nils.
+
_main function decides the kind of thought this will be and returns the final output
local args = {...} -- Table of arguments. It might contain nils or non-number values, so we can't use ipairs.
+
If the are several defines values, then it uses the Thought function
local nums = {} -- Stores the numbers of valid numerical arguments.
+
If only value is defined, then:
local ret = {}
+
- If both stack and the multiplier "multi" are 1, it gives a result early.
for k, v in pairs(args) do
+
multi defaults to 1 when not defined (or invalid)
v = p._cleanNumber(v)
+
- Otherwise, it calls the stacks function.
if v then
+
]]
nums[#nums + 1] = k
+
 
args[k] = v
+
function p._main(desc, label, duration, stack, multi, valores)
 +
local final_string = duration and {duration, " [[mood]] for ", duration, " [[Time|days]]" } or {" [[mood]]"}
 +
local middle_string = {'<abbr title="', desc, '"><i>', (label:gsub("^%l", string.upper)), '</i></abbr>' }
 +
-- "valores" is a list of all values given to the function.
 +
-- This checks if a second value exist
 +
if valores[2] then
 +
return p.Thought(valores) --..middle_string..final_string
 +
else --Only initial value defined
 +
if stack==1 and multi==1 then
 +
local value = valores[1]
 +
if tonumber(value)>0 then
 +
return '<b><font color="forestgreen">'..value..'</font></b> '..middle_string..final_string
 +
elseif tonumber(value) == 0 then
 +
return '<b>'..value..'</b> '..middle_string..final_string
 +
else
 +
return '<b><font color="firebrick">'..value..'</font></b> '..middle_string..final_string
 +
end
 
end
 
end
 +
return p.stacks(stack, multi, valores[1])..middle_string..final_string
 
end
 
end
table.sort(nums)
 
for i, num in ipairs(nums) do
 
ret[#ret + 1] = args[num]
 
end
 
return ret
 
 
end
 
end
  
local function fold(func, ...)
+
--[[
-- Use a function on all supplied arguments, and return the result. The function must accept two numbers as parameters,
+
The "Thought" function returns a string if more than 1 value was defined.
-- and must return a number as an output. This number is then supplied as input to the next function call.
+
It iterates through all the values defined (contained on the list "valores")
local vals = makeArgArray(...)
+
For each element:
local count = #vals -- The number of valid arguments
+
1.- If it is a valid number, then it valuates what kind of number it is.
if count == 0 then return
+
1.2.- If it is, it then decides what color it need. Currently, it returns:
-- Exit if we have no valid args, otherwise removing the first arg would cause an error.
+
Green for positive, Red for negative, None for 0.
nil, 0
+
2.- It it is not a valid number, it returns the value bolded and large. The idea is to make the mistake obvious.
 +
3.- Once all values are checked, it concatenates all results, with some extras to make sense.
 +
This last part is what it returns.
 +
]]
 +
 
 +
function p.Thought(valores)
 +
local valores_buscados={}
 +
for i, j in ipairs(valores) do
 +
local vx = valores[i]
 +
local vy = ""
 +
if tonumber(vx) then -- A number.
 +
vy = tonumber(vx)<0 and '<b><font color="firebrick">'..vx.."</font></b>" or tonumber(vx)>0 and '<b><font color="forestgreen">'..vx.."</font></b>" or '<b>0</b>'
 +
else
 +
vy='<big><b>'..vx.."</b></big>" --The idea is to prevent a hard to track error
 +
end
 +
valores_buscados[#valores_buscados+1]=vy
 
end
 
end
local ret = table.remove(vals, 1)
+
return "<b>"..table.concat(valores_buscados,"<b>/</b>").."</b> "..table.concat(middle_string,"")..table.concat(final_string,"")
for _, val in ipairs(vals) do
 
ret = func(ret, val)
 
end
 
return ret, count
 
end
 
 
 
function p.test(frame)
 
parent=frame:getParent()--equal to frame.getParent(frame)
 
return parent.args
 
 
end
 
end
  
 
--[[
 
--[[
function p.hello()
+
The "stacks" function return a string for the case that only 1 value was defined.
    return 'Hola'
+
1.  If a stack value was defined:
end
+
1.1 Is stack equal to 1
 
+
1.2 Any other case.
aname=string.match("Blood Filtration Limit",' %(.*)% ')
+
2. If a stack was not defined, then check the multiplier
 +
2.1 If the multiplier is equal or above one
 +
2.2 If the multiplier is below 1.
  
return p
+
Finally, some final code to decide what color to use.
]]
+
1. Green (forestgreen) for positive.
 
+
2. None for 0.
--[[
+
3. Red (firebrick) for negatives.
Fold arguments by selectively choosing values (func should return when to choose the current "dominant" value).
+
The retuned value is rounded half-down. (Meaning 0.5 -> 0 )
 +
string.format("%.2f", number))
 +
To combat that, I add 0.001 to the number calculated. It should be enough.
 
]]
 
]]
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
 
 
--TEST AREA
 
Quality={ Quality_general, Quality_building, Quality_Apparel, Quality_Weapons }
 
 
Quality_general={
 
--{ Beauty, Market Value, Max Increment, Deterioration Rate, Psychic Sensitivity }
 
awful={ -0.1, 0.50, 0, 2.00, 0.5 },
 
poor={ 0.5, 0.75, 0, 1.50, 0.66 },
 
normal={ 1.0, 1.00, 0, 1.00, 0.83 },
 
good={ 2.0, 1.25, 500, 0.80, 1.00 },
 
excellent={ 3.0, 1.5, 1000, 0.60, 1.16 },
 
masterwork={ 5.0, 2.5, 2000, 0.30, 1.32 },
 
legendary={ 8.0, 5, 3000, 0.10, 1.50 }
 
}
 
  
Quality_building={
+
function p.stacks(stack, multi, value)
--{ Comfort, Rest Effectiveness, Surgery Success, Recreation Power, Meditation Psyfocus+, Meditation Psyfocus+ }
+
local text=""
awful={ 0.76, 0.86, 0.90, 0.76, 0.12, 0 },
+
if stack then
poor={ 0.88, 0.92, 0.95, 0.88, 0.16, 0 },
+
if multi == 1 then
normal={ 1.00, 1.00, 1.00, 1.00, 0.20, 0.01 },
+
if stack ~= 1 then
good={ 1.12, 1.08, 1.05, 1.12, 0.22, 0.01 },
+
text = "Stacking "..stack.." times for a maximum of "..tostring(value*stack)
excellent={ 1.24, 1.14, 1.10, 1.24, 0.24, 0.01 },
+
end
masterwork={ 1.45, 1.25, 1.15, 1.40, 0.26, 0.02 },
+
else
legendary={ 1.70, 1.60, 1.30, 1.80, 0.28, 0.02 }
+
text = "Stacking "..stack.." times with a "..multi.." multiplier for maximum of "..string.format("%.2f", value*( 1 - multi^stack)/(1 - multi) + 0.001)
}
 
 
 
Quality_Apparel={
 
--{ Protection, Insulation, Smokepop Pack Radius, Shield Max Energy, Shield Recharge Rate, Jump Range }
 
awful={ 0.60, 0.80, 0.84, 0.60, 0.90, 0.75 },
 
poor={ 0.80, 0.90, 0.92, 0.80, 0.95, 0.90 },
 
normal={ 1.00, 1.00, 1.00, 1.00, 1.00, 1.00 },
 
good={ 1.15, 1.10, 1.08, 1.20, 1.05, 1.06 },
 
excellent={ 1.30, 1.20, 1.16, 1.40, 1.10, 1.13 },
 
masterwork={ 1.45, 1.50, 1.30, 1.70, 1.20, 1.19 },
 
legendary={ 1.80, 1.80, 1.50, 2.10, 1.30, 1.25 }
 
}
 
 
 
Quality_Weapons={
 
--{ Melee Damage, Melee AP, Ranged Accuracy, Ranged Damage, Ranged AP }
 
awful={ 0.80, 0.80, 0.80, 0.9, 0.90 },
 
poor={ 0.90, 0.90, 0.90, 1, 1 },
 
normal={ 1.00, 1.00, 1, 1, 1 },
 
good={ 1.10, 1.10, 1.1, 1, 1 },
 
excellent={ 1.20, 1.20, 1.2, 1, 1 },
 
masterwork={ 1.45, 1.45, 1.35, 1.25, 1.25 },
 
legendary={ 1.65, 1.65, 1.5, 1.5, 1.5 }
 
}
 
 
 
--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)
 
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
 
argumentos[i]=0
 
 
end
 
end
end
 
-- Do note that statMin, statMax are handled by "Template:Stat Factors Table".
 
-- While I could set fallbacks, I decided against it.
 
 
if tonumber(Ln)==nil then --Sanitizes input and allows for 0.
 
factor = skillBase + skillBonus * LV
 
 
else
 
else
factor = Ln
+
if multi >= 1 then --I want to avoid the case of really large numbers.
 +
text = "Stacking infinitely"
 +
else
 +
text = "Stacking with a "..multi.." multiplier for maximum of "..string.format("%.2f", value*( 1 - multi^100)/(1 - multi) + 0.001)
 +
end
 
end
 
end
  
local Pval = math.min(math.max(factor,statMin),statMax)
+
if tonumber(value)>0 then
R_Pval = tostring(math.floor(Pval*10000+0.5)/100).."%" -- This formats the number as a 2 digit percent value, rounded up.
+
return '<abbr title="'..text..'"><b><font color="forestgreen">'..value..'</font></b></abbr> '
if tonumber(resultCols)>1 then
+
elseif tonumber(value) == 0 then
Pval = factor * ( 1 + capImportance * math.min(capLimit-1, 0.25))
+
return '<abbr title="'..text..'"><b>'..value..'</b></abbr> '
Pval = math.min(math.max(Pval,statMin),statMax)
 
R_Sval="<td>"..tostring(math.floor(Pval*10000+0.5)/100).."% </td>"
 
 
else
 
else
R_Sval=""
+
return '<abbr title="'..text..'"><b><font color="firebrick">'..value..'</font></b></abbr> '
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
 
----------------
 
function Melee_HCC(frame)
 
local baseScore=frame.args[1]
 
local a = math.floor(baseScore/10)
 
return frame
 
--[[ if a < -2 then
 
return 0.05 --0.05
 
end
 
if a == -2 then
 
return (baseScore + 20) * 0.005 + 0.05 -- 0.05 / 0.1
 
end
 
if a == -1 then
 
return (baseScore + 10) * 0.04 + 0.1 -- 0.1 / 0.5
 
end
 
if a == 0 then
 
return baseScore * 0.03 + 0.5 -- 0.5 / 0.8
 
 
end
 
end
if a == 1 then
 
return (baseScore - 10)* 0.01 + 0.8 -- 0.8 / 0.9
 
end
 
if a<=3 then -- 2 and 3
 
return (baseScore - 20) * 0.003 + 0.9 --0.9 / 0.96
 
end
 
if a<=5 then -- 4 and 5
 
return (baseScore - 40) * 0.001 + 0.96 -- 0.96/ 0.98
 
else
 
return 0.98
 
end]]
 
 
end
 
end
  
----------------
+
--This last part outputs the actual result. W/O it, it gives an error.
--Inspired by some fandom site.
+
return p
----------------
 
--[[function spliting(frame)
 
local texto = frame.args[1]
 
local sep = frame.args[2]
 
local N = frame.args[3]
 
sep = sep or "%s"
 
local A = {}
 
for str in string.gmatch(texto, "([^"..sep.."]+)") do
 
table.insert(A, str)
 
end
 
N=N or 0
 
return A[N]
 
end
 
]]
 
 
 
 
 
--[[ Taken from some fandom site
 
local text = "And if you tolerate this"
 
local tab = mw.text.split( text, " ")
 
print(tab[3])
 
]]
 
 
 
--[[
 
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.
 
]]
 
 
 
--[[ Comented out to test some things.
 
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)
 
]]
 

Revision as of 17:56, 17 August 2024

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

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 implements the functions of Template:Thought
]]

local p = {}
local getArgs = require('Module:Arguments').getArgs

--[[ The template argument goes to "main" 
Only this funcion will work when invoked. This is case sensitive.
What it does is obtain the data from the wiki to a fomrat readable by other functions]]

function p.main(frame)
	local args = getArgs(frame)
	local desc = tostring(args["desc"])
	local label = tostring(args["label"])
	local duration = tonumber(args["duration"])
	local stack = tonumber(args["stack"])
	local multi = tonumber(args["multi"]) or 1
--[[ The advantage of adding values to an empty list rather than defining a list
	with the correct values is that no nil values will get into the list this way.
	This means that values don't have to be consecutive.
	EX: value9 is valid w/o defining value2 to value8.
	]]
	local valores = {}
	valores[#valores+1]=args["value"]
	valores[#valores+1]=args["value2"]
	valores[#valores+1]=args["value3"]
	valores[#valores+1]=args["value4"]
	valores[#valores+1]=args["value5"]
	valores[#valores+1]=args["value6"]
	valores[#valores+1]=args["value7"]
	valores[#valores+1]=args["value8"]
	valores[#valores+1]=args["value9"]
	if tonumber(args["value"]) then
		return p._main(desc, label, duration, stack, multi, valores)
		else
			return "<big><b>Missing value. Please, define a numerical value to use.</b></big>"
	end
end

--[[
_main function decides the kind of thought this will be and returns the final output
If the are several defines values, then it uses the Thought function
If only value is defined, then:
	- If both stack and the multiplier "multi" are 1, it gives a result early.
		multi defaults to 1 when not defined (or invalid)
	- Otherwise, it calls the stacks function.
]]

function p._main(desc, label, duration, stack, multi, valores)
	local final_string = duration and {duration, " [[mood]] for ", duration, " [[Time|days]]" } or {" [[mood]]"}
	local middle_string = {'<abbr title="', desc, '"><i>', (label:gsub("^%l", string.upper)), '</i></abbr>' }
	-- "valores" is a list of all values given to the function.
	-- This checks if a second value exist
	if valores[2] then
		return p.Thought(valores) --..middle_string..final_string
	else --Only initial value defined
		if stack==1 and multi==1 then
			local value = valores[1]
			if tonumber(value)>0 then
				return '<b><font color="forestgreen">'..value..'</font></b> '..middle_string..final_string
			elseif tonumber(value) == 0 then
				return '<b>'..value..'</b> '..middle_string..final_string
			else
				return '<b><font color="firebrick">'..value..'</font></b> '..middle_string..final_string
			end
		end
		return p.stacks(stack, multi, valores[1])..middle_string..final_string
	end
end

--[[
The "Thought" function returns a string if more than 1 value was defined.
It iterates through all the values defined (contained on the list "valores") 
For each element:
1.- If it is a valid number, then it valuates what kind of number it is.
1.2.- If it is, it then decides what color it need. Currently, it returns:
	Green for positive, Red for negative, None for 0.
2.- It it is not a valid number, it returns the value bolded and large. The idea is to make the mistake obvious.
3.- Once all values are checked, it concatenates all results, with some extras to make sense.
This last part is what it returns.
]]

function p.Thought(valores)
	local valores_buscados={}
	for i, j in ipairs(valores) do
		local vx = valores[i]
		local vy = ""
		if tonumber(vx) then -- A number.
			vy = tonumber(vx)<0 and '<b><font color="firebrick">'..vx.."</font></b>" or tonumber(vx)>0 and '<b><font color="forestgreen">'..vx.."</font></b>" or '<b>0</b>'
		else
			vy='<big><b>'..vx.."</b></big>" --The idea is to prevent a hard to track error
		end
		valores_buscados[#valores_buscados+1]=vy
	end
	return "<b>"..table.concat(valores_buscados,"<b>/</b>").."</b> "..table.concat(middle_string,"")..table.concat(final_string,"")
end

--[[
The "stacks" function return a string for the case that only 1 value was defined.
1.  If a stack value was defined:
1.1 Is stack equal to 1
1.2 Any other case.
2.  If a stack was not defined, then check the multiplier
2.1 If the multiplier is equal or above one
2.2 If the multiplier is below 1.

Finally, some final code to decide what color to use.
1. Green (forestgreen) for positive.
2. None for 0.
3. Red (firebrick) for negatives.
The retuned value is rounded half-down. (Meaning 0.5 -> 0 )
	string.format("%.2f", number))
To combat that, I add 0.001 to the number calculated. It should be enough.
]]

function p.stacks(stack, multi, value)
	local text=""
	if stack then
		if multi == 1 then
			if stack ~= 1 then 
				text = "Stacking "..stack.." times for a maximum of "..tostring(value*stack)
			end
		else
			text = "Stacking "..stack.." times with a "..multi.." multiplier for maximum of "..string.format("%.2f", value*( 1 - multi^stack)/(1 - multi) + 0.001)
		end
	else
		if multi >= 1 then --I want to avoid the case of really large numbers.
			text = "Stacking infinitely"
		else
			text = "Stacking with a "..multi.." multiplier for maximum of "..string.format("%.2f", value*( 1 - multi^100)/(1 - multi) + 0.001)
		end
	end

	if tonumber(value)>0 then
		return '<abbr title="'..text..'"><b><font color="forestgreen">'..value..'</font></b></abbr> '
	elseif tonumber(value) == 0 then
		return '<abbr title="'..text..'"><b>'..value..'</b></abbr> '
	else
		return '<abbr title="'..text..'"><b><font color="firebrick">'..value..'</font></b></abbr> '
	end
end

--This last part outputs the actual result. W/O it, it gives an error.
return p