Difference between revisions of "Module:Thought"

From RimWorld Wiki
Jump to navigation Jump to search
m (Tailcalls are faster.)
m
 
(29 intermediate revisions by the same user not shown)
Line 1: Line 1:
 
--[[
 
--[[
Template: Preprocessor visited node count 969/1,000,000
+
This module implements the functions of Template:Thought
Module:  Preprocessor visited node count 508/1,000,000
 
With tailcalls.
 
Now that it's working properly, let's see if I can improve it.
 
 
]]
 
]]
 +
 
local p = {}
 
local p = {}
 
local getArgs = require('Module:Arguments').getArgs
 
local getArgs = require('Module:Arguments').getArgs
local valores_ingresados={"value", "value2", "value3", "value4", "value5", "value6", "value7", "value8", "value9" }
 
  
 +
--[[ The template argument goes to "main"
 +
Only this function 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)
 
function p.main(frame)
 
local args = getArgs(frame)
 
local args = getArgs(frame)
-- Los valores están en args en la forma { "value" = A, "value2"= B....}
 
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
 
-- local valores = {args["value"], args["value2"], args["value3"], args["value4"], args["value5"], args["value6"], args["value7"], args["value8"], args["value9"]}
 
 
local valores = {}
 
local valores = {}
valores[#valores+1]=args["value"]
+
 
valores[#valores+1]=args["value2"]
+
if tonumber(args["value"]) then --Trow error early if value is undefined/invalid
valores[#valores+1]=args["value3"]
+
valores = { tonumber(args["value"]) }
valores[#valores+1]=args["value4"]
+
else
valores[#valores+1]=args["value5"]
+
return "<big><b>Missing 'value' argument. Please, define a numerical value to use.</b></big>"
valores[#valores+1]=args["value6"]
 
valores[#valores+1]=args["value7"]
 
valores[#valores+1]=args["value8"]
 
valores[#valores+1]=args["value9"]
 
-- I believe args calls something very different on subsecuent functions.
 
if tonumber(args["value"]) then
 
return p._main(desc, label, duration, stack, multi, valores)
 
else
 
return "Missing value field."
 
 
end
 
end
 +
 +
local multi = tonumber(args["multi"]) or 1
 +
 +
--[[ This will add all values to a list. Undefined values will be overwritten by valid ones.
 +
This also means that values don't have to be consecutive.
 +
EX: value9 is valid w/o defining value2 to value8.
 +
]]
 +
valores[#valores+1]=tonumber(args["value2"])
 +
valores[#valores+1]=tonumber(args["value3"])
 +
valores[#valores+1]=tonumber(args["value4"])
 +
valores[#valores+1]=tonumber(args["value5"])
 +
valores[#valores+1]=tonumber(args["value6"])
 +
valores[#valores+1]=tonumber(args["value7"])
 +
valores[#valores+1]=tonumber(args["value8"])
 +
valores[#valores+1]=tonumber(args["value9"])
 +
 +
-- return p._main(tostring(args["desc"]), tostring(args["label"]), tonumber(args["duration"]), tonumber(args["stack"]), multi, valores)
 +
return p._main(args["desc"], args["label"], tonumber(args["duration"]), tonumber(args["stack"]), multi, valores)
 
end
 
end
 +
 +
--[[
 +
_main function decides the kind of thought this will be and returns the final output
 +
If the are several defined 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)
 
function p._main(desc, label, duration, stack, multi, valores)
 
local final_string = duration and " [[mood]] for "..duration.." [[Time|days]]" or " [[mood]]"
 
local final_string = duration and " [[mood]] for "..duration.." [[Time|days]]" or " [[mood]]"
 
+
local middle_string ='<abbr title="'..desc..'"><i>'..(label:gsub("^%l", string.upper))..'</i></abbr>'
 +
-- middle_string is pure convenience. It makes reading the output easier.
 
-- "valores" is a list of all values given to the function.
 
-- "valores" is a list of all values given to the function.
-- This checks if the second value exist
+
if valores[2] then -- This checks if there is more than 1 value.
if valores[2] then
+
return p.Thought(valores)..middle_string..final_string
-- return p.Thought(valores)..'<abbr title="'..desc..'">'..(label:gsub("^%l", string.upper))..'</abbr>'..final_string
+
else
return p.Thought(valores)
+
local value = valores[1]
else --Only one value
+
local formated_value = formato(value)
-- return p.stacks(stack, multi, valores[1])..'<abbr title="'..desc..'">'..(label:gsub("^%l", string.upper))..'</abbr>'..final_string
+
return p.stacks(stack, multi, valores[1])
+
if (stack==1 and multi==1) then
 +
if value>0 then
 +
return '<b><font color="forestgreen">'..formated_value..'</font></b> '..middle_string..final_string
 +
elseif value == 0 then
 +
return '<b>'..formated_value..'</b> '..middle_string..final_string
 +
else
 +
return '<b><font color="firebrick">'..formated_value..'</font></b> '..middle_string..final_string
 +
end
 +
end
 +
return p.stacks(stack, multi, value)..middle_string..final_string
 
end
 
end
 
end
 
end
  
function p.Thought(valores)--This is just the value section.
+
--[[
 +
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={}
 
local valores_buscados={}
 
for i, j in ipairs(valores) do
 
for i, j in ipairs(valores) do
local vx = valores[i]
+
local vx = j
 
local vy = ""
 
local vy = ""
if tonumber(vx) then -- A number.
+
vy = vx<0 and '<font color="firebrick">'..vx.."</font>" or vx>0 and '<font color="forestgreen">'..vx.."</font>" or '<b>0</b>'
if tonumber(vx)<0 then vy='<b><font color="firebrick">'..vx.."</font></b>" else vy='<b><font color="forestgreen">'..vx.."</font></b>" end
+
-- vy='<big><b>'..vx.."</b></big>" --The idea is to prevent a hard to track error
else
 
vy='<b>'..vx.."</b>" --The idea is to prevent a hard to track error
 
end
 
 
valores_buscados[#valores_buscados+1]=vy
 
valores_buscados[#valores_buscados+1]=vy
 
end
 
end
return "<b>"..table.concat(valores_buscados,"<b>/</b>").."</b> "..'<abbr title="'..desc..'">'..(label:gsub("^%l", string.upper))..'</abbr>'..final_string
+
return string.gsub("<b>"..table.concat(valores_buscados,"<b>/</b>").."</b> ", "-", "")
 
end
 
end
  
function p.stacks(stack, multi, value)--This is just the stacking section.
+
--[[
 +
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=""
 
local text=""
-- multi = tonumber(multi) or 1 -- Now has a default value of 1.
+
if stack then --stack is defined
if stack then
+
if multi == 1 and stack ~= 1 then  
if mumlti == 1 then
+
text = "Stacking "..stack.." times for a maximum of "..tostring(value*stack)
text= "Stacking "..stack.." times for a maximum of "..tostring(value*stack)
 
 
else
 
else
text= "Stacking "..stack.." times with a "..multi.." multiplier for maximum of "..tostring(value*( 1 - multi^stack)/(1 - multi))
+
text = "Stacking "..stack.." times with a "..multi.." multiplier for maximum of "..string.format("%.2f", value*( 1 - multi^stack)/(1 - multi) + 0.001)
 
end
 
end
 
else
 
else
Line 78: Line 125:
 
text = "Stacking infinitely"
 
text = "Stacking infinitely"
 
else
 
else
text = "Stacking with a "..multi.." multiplier for maximum of "..tostring(value*( 1 - multi^100)/(1 - multi) )
+
text = "Stacking with a "..multi.." multiplier for maximum of "..string.format("%.2f", value*( 1 - multi^100)/(1 - multi) + 0.001)
 
end
 
end
 
end
 
end
 +
local formated_value = formato(value)
 +
if value>0 then
 +
return '<abbr title="'..text..'"><b><font color="forestgreen">'..formated_value..'</font></b></abbr> '
 +
elseif value == 0 then
 +
return '<abbr title="'..text..'"><b>'..formated_value..'</b></abbr> '
 +
else
 +
return '<abbr title="'..text..'"><b><font color="firebrick">'..formated_value..'</font></b></abbr> '
 +
end
 +
end
  
if tonumber(value)>0 then
+
function formato(numero)
return '<abbr title="'..text..'"><b><font color="forestgreen">'..value..'</font></b></abbr> '..'<abbr title="'..desc..'">'..(label:gsub("^%l", string.upper))..'</abbr>'..final_string
+
if numero>0 then
elseif tonumber(value) == 0 then
+
return "+"..tostring(numero)
return '<abbr title="'..text..'"><br>'..value..'</br></abbr> '..'<abbr title="'..desc..'">'..(label:gsub("^%l", string.upper))..'</abbr>'..final_string
+
elseif numero <0 then
else
+
return string.gsub(numero, "-", "")
return '<abbr title="'..text..'"><b><font color="firebrick">'..value..'</font></b></abbr> '..'<abbr title="'..desc..'">'..(label:gsub("^%l", string.upper))..'</abbr>'..final_string
 
 
end
 
end
 
end
 
end
  
 +
--This last part outputs the actual result. W/O it, it gives an error.
 
return p
 
return p

Latest revision as of 16:31, 7 March 2025

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

--[[
This module implements the functions of Template:Thought
]]

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

--[[ The template argument goes to "main" 
Only this function 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 valores = {}

	if tonumber(args["value"]) then --Trow error early if value is undefined/invalid
		valores = { tonumber(args["value"]) }
	else
		return "<big><b>Missing 'value' argument. Please, define a numerical value to use.</b></big>"
	end

	local multi = tonumber(args["multi"]) or 1

--[[ This will add all values to a list. Undefined values will be overwritten by valid ones.
	This also means that values don't have to be consecutive.
	EX: value9 is valid w/o defining value2 to value8.
	]]
	valores[#valores+1]=tonumber(args["value2"])
	valores[#valores+1]=tonumber(args["value3"])
	valores[#valores+1]=tonumber(args["value4"])
	valores[#valores+1]=tonumber(args["value5"])
	valores[#valores+1]=tonumber(args["value6"])
	valores[#valores+1]=tonumber(args["value7"])
	valores[#valores+1]=tonumber(args["value8"])
	valores[#valores+1]=tonumber(args["value9"])

--	return p._main(tostring(args["desc"]), tostring(args["label"]), tonumber(args["duration"]), tonumber(args["stack"]), multi, valores)
	return p._main(args["desc"], args["label"], tonumber(args["duration"]), tonumber(args["stack"]), multi, valores)
end

--[[
_main function decides the kind of thought this will be and returns the final output
If the are several defined 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 " [[mood]] for "..duration.." [[Time|days]]" or " [[mood]]"
	local middle_string ='<abbr title="'..desc..'"><i>'..(label:gsub("^%l", string.upper))..'</i></abbr>'
	-- middle_string is pure convenience. It makes reading the output easier.
	-- "valores" is a list of all values given to the function.
	if valores[2] then -- This checks if there is more than 1 value.
		return p.Thought(valores)..middle_string..final_string
	else
		local value = valores[1]
		local formated_value = formato(value)
		
		if (stack==1 and multi==1) then
			if value>0 then
				return '<b><font color="forestgreen">'..formated_value..'</font></b> '..middle_string..final_string
			elseif value == 0 then
				return '<b>'..formated_value..'</b> '..middle_string..final_string
			else
				return '<b><font color="firebrick">'..formated_value..'</font></b> '..middle_string..final_string
			end
		end
		return p.stacks(stack, multi, value)..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 = j
		local vy = ""
		vy = vx<0 and '<font color="firebrick">'..vx.."</font>" or vx>0 and '<font color="forestgreen">'..vx.."</font>" or '<b>0</b>'
--			vy='<big><b>'..vx.."</b></big>" --The idea is to prevent a hard to track error
		valores_buscados[#valores_buscados+1]=vy
	end
	return string.gsub("<b>"..table.concat(valores_buscados,"<b>/</b>").."</b> ", "-", "−")
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 --stack is defined
		if multi == 1 and stack ~= 1 then 
			text = "Stacking "..stack.." times for a maximum of "..tostring(value*stack)
		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
	local formated_value = formato(value)
	if value>0 then
		return '<abbr title="'..text..'"><b><font color="forestgreen">'..formated_value..'</font></b></abbr> '
	elseif value == 0 then
		return '<abbr title="'..text..'"><b>'..formated_value..'</b></abbr> '
	else
		return '<abbr title="'..text..'"><b><font color="firebrick">'..formated_value..'</font></b></abbr> '
	end
end

function formato(numero)
	if numero>0 then
		return "+"..tostring(numero)
	elseif numero <0 then
		return string.gsub(numero, "-", "−")
	end
end

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