Module:SoulUnlock

Revision as of 22:03, 12 May 2025 by Gammaton32 (talk | contribs) (add 400 to initial soul value)

Overview

Data for what is unlocked at each increment of Souls. Data is stored and loaded from Data:SoulUnlockData.json.

The data is accumulated into another format that is used by the currently written functions.

Functions

get_max

Retrieve's maximum value for a given key in the accumulated data

Examples

{{#invoke:SoulUnlock|get_max|RequiredSouls}} 49000
{{#invoke:SoulUnlock|get_max|PowerIncrease}} 35
{{#invoke:SoulUnlock|get_max|AbilityUnlocks}} 4
{{#invoke:SoulUnlock|get_max|AbilityPoints}} 32

localize

Localize a key as its stored to the current language using Module:Lang.

Examples

{{#invoke:SoulUnlock|localize|RequiredSouls}} Souls
{{#invoke:SoulUnlock|localize|PowerIncrease}} Boons
{{#invoke:SoulUnlock|localize|AbilityUnlocks}} Ability Unlock
{{#invoke:SoulUnlock|localize|AbilityPoints}} Ability Points

write_accumulated

Writes the accumulated data to wikitext. Not a format that is ready to be displayed on a wiki page yet. Used for debugging for any lua editors working off of the accumulated data as opposed to the original data.

Note: the keys outputted are localized to english. See the localization map at the top of the Module source.

Example

{{#invoke:SoulUnlock|write_accumulated}}
Index1: Souls:400, Ability Unlock:1,
Index2: Ability Unlock:1, Boons:1, Souls:600, Ability Points:1,
Index3: Ability Unlock:2, Boons:2, Souls:900, Ability Points:1,
Index4: Ability Unlock:2, Boons:3, Souls:1300, Ability Points:2,
Index5: Ability Unlock:3, Boons:4, Souls:1800, Ability Points:2,
Index6: Ability Unlock:3, Boons:5, Souls:2400, Ability Points:3,
Index7: Ability Unlock:3, Boons:6, Souls:3000, Ability Points:4,
Index8: Ability Unlock:4, Boons:7, Souls:3600, Ability Points:4,
Index9: Ability Unlock:4, Boons:8, Souls:4300, Ability Points:5,
Index10: Ability Unlock:4, Boons:9, Souls:5000, Ability Points:6,
Index11: Ability Unlock:4, Boons:10, Souls:5700, Ability Points:7,
Index12: Ability Unlock:4, Boons:11, Souls:6400, Ability Points:8,
Index13: Ability Unlock:4, Boons:12, Souls:7200, Ability Points:9,
Index14: Ability Unlock:4, Boons:13, Souls:8000, Ability Points:10,
Index15: Ability Unlock:4, Boons:14, Souls:8800, Ability Points:11,
Index16: Ability Unlock:4, Boons:15, Souls:9600, Ability Points:12,
Index17: Ability Unlock:4, Boons:16, Souls:10500, Ability Points:13,
Index18: Ability Unlock:4, Boons:17, Souls:11400, Ability Points:14,
Index19: Ability Unlock:4, Boons:18, Souls:12300, Ability Points:15,
Index20: Ability Unlock:4, Boons:19, Souls:13200, Ability Points:16,
Index21: Ability Unlock:4, Boons:20, Souls:14200, Ability Points:17,
Index22: Ability Unlock:4, Boons:21, Souls:15300, Ability Points:18,
Index23: Ability Unlock:4, Boons:22, Souls:16500, Ability Points:19,
Index24: Ability Unlock:4, Boons:23, Souls:17800, Ability Points:20,
Index25: Ability Unlock:4, Boons:24, Souls:19300, Ability Points:21,
Index26: Ability Unlock:4, Boons:25, Souls:21000, Ability Points:22,
Index27: Ability Unlock:4, Boons:26, Souls:22900, Ability Points:23,
Index28: Ability Unlock:4, Boons:27, Souls:25000, Ability Points:24,
Index29: Ability Unlock:4, Boons:28, Souls:27300, Ability Points:25,
Index30: Ability Unlock:4, Boons:29, Souls:29800, Ability Points:26,
Index31: Ability Unlock:4, Boons:30, Souls:32500, Ability Points:27,
Index32: Ability Unlock:4, Boons:31, Souls:35400, Ability Points:28,
Index33: Ability Unlock:4, Boons:32, Souls:38500, Ability Points:29,
Index34: Ability Unlock:4, Boons:33, Souls:41800, Ability Points:30,
Index35: Ability Unlock:4, Boons:34, Souls:45300, Ability Points:31,
Index36: Ability Unlock:4, Boons:35, Souls:49000, Ability Points:32,

write_table

Example

IndividualAccumulative
SoulsBoonsAbility UnlockAbility PointsBoonsAbility UnlockAbility Points
{{Souls|400}}{{Tick}}1
{{Souls|600}}{{Tick}}{{Tick}}111
{{Souls|900}}{{Tick}}{{Tick}}221
{{Souls|1300}}{{Tick}}{{Tick}}322
{{Souls|1800}}{{Tick}}{{Tick}}432
{{Souls|2400}}{{Tick}}{{Tick}}533
{{Souls|3000}}{{Tick}}{{Tick}}634
{{Souls|3600}}{{Tick}}{{Tick}}744
{{Souls|4300}}{{Tick}}{{Tick}}845
{{Souls|5000}}{{Tick}}{{Tick}}946
{{Souls|5700}}{{Tick}}{{Tick}}1047
{{Souls|6400}}{{Tick}}{{Tick}}1148
{{Souls|7200}}{{Tick}}{{Tick}}1249
{{Souls|8000}}{{Tick}}{{Tick}}13410
{{Souls|8800}}{{Tick}}{{Tick}}14411
{{Souls|9600}}{{Tick}}{{Tick}}15412
{{Souls|10500}}{{Tick}}{{Tick}}16413
{{Souls|11400}}{{Tick}}{{Tick}}17414
{{Souls|12300}}{{Tick}}{{Tick}}18415
{{Souls|13200}}{{Tick}}{{Tick}}19416
{{Souls|14200}}{{Tick}}{{Tick}}20417
{{Souls|15300}}{{Tick}}{{Tick}}21418
{{Souls|16500}}{{Tick}}{{Tick}}22419
{{Souls|17800}}{{Tick}}{{Tick}}23420
{{Souls|19300}}{{Tick}}{{Tick}}24421
{{Souls|21000}}{{Tick}}{{Tick}}25422
{{Souls|22900}}{{Tick}}{{Tick}}26423
{{Souls|25000}}{{Tick}}{{Tick}}27424
{{Souls|27300}}{{Tick}}{{Tick}}28425
{{Souls|29800}}{{Tick}}{{Tick}}29426
{{Souls|32500}}{{Tick}}{{Tick}}30427
{{Souls|35400}}{{Tick}}{{Tick}}31428
{{Souls|38500}}{{Tick}}{{Tick}}32429
{{Souls|41800}}{{Tick}}{{Tick}}33430
{{Souls|45300}}{{Tick}}{{Tick}}34431
{{Souls|49000}}{{Tick}}{{Tick}}35432
IndividualAccumulative
SoulsBoonsAbility UnlockAbility PointsBoonsAbility UnlockAbility Points
Souls400Yes1
Souls600YesYes111
Souls900YesYes221
Souls1300YesYes322
Souls1800YesYes432
Souls2400YesYes533
Souls3000YesYes634
Souls3600YesYes744
Souls4300YesYes845
Souls5000YesYes946
Souls5700YesYes1047
Souls6400YesYes1148
Souls7200YesYes1249
Souls8000YesYes13410
Souls8800YesYes14411
Souls9600YesYes15412
Souls10500YesYes16413
Souls11400YesYes17414
Souls12300YesYes18415
Souls13200YesYes19416
Souls14200YesYes20417
Souls15300YesYes21418
Souls16500YesYes22419
Souls17800YesYes23420
Souls19300YesYes24421
Souls21000YesYes25422
Souls22900YesYes26423
Souls25000YesYes27424
Souls27300YesYes28425
Souls29800YesYes29426
Souls32500YesYes30427
Souls35400YesYes31428
Souls38500YesYes32429
Souls41800YesYes33430
Souls45300YesYes34431
Souls49000YesYes35432

local p = {}
local util_module = require('Module:Utilities')
local dictionary_module = require('Module:Dictionary')
local soul_unlocks_data = mw.loadJsonData("Data:SoulUnlockData.json")
local localization_map = {
	["RequiredSouls"] = "Citadel_Hero_Stats_Souls",
	["AbilityUnlocks"] = "Citadel_Player_Level_AbilityUnlock",
	["AbilityPoints"] = "guide_upgrades_killing_guardians_header",
	["PowerIncrease"] = "Citadel_Player_Level_PowerIncreases"
}
local lang_module = require('Module:Lang')

-- Accumulate the data from a list of entries of unlocks, AP, and PI's, to a hash with the # of each
local function accumulate() 
	local accumulated_data = {} --holds the sum at each gold count
	local sums = {} --holds only the current sums
	
	for i, su_data in ipairs(soul_unlocks_data) do
		for key, value in pairs(su_data) do
			-- Determine how many to increase sum by
			local num
			if type(value) == 'boolean' then 
				if value == true then
					num = 1
				else
					num = 0
				end
			elseif type(value) == 'number' then 
				num = value 
			else
				return "Module:SoulUnlock.accumulate() error, invalid value type"
			end
			
			
			-- Start at 0
			if sums[key] == nil then sums[key] = 0 end
			
			-- Sum the value, but not for gold because its already summed
			if key == 'RequiredSouls' then
				sums[key] = num
			else
				sums[key] = sums[key] + num
			end
		end
		
		-- Add the current sum to accumulated_data
		table.insert(accumulated_data, util_module.deep_copy(sums))
	end
	
	return accumulated_data
end

local accumulated_data = accumulate()

function p.localize(soul_unlock_key)
	-- If called internally (direct Lua call), args will be passed directly.
    -- If called from wikitext, `soul_unlock_key` will be the `frame` object, and we get args from `frame.args`.

    -- Handle the case where it's called via #invoke (i.e., from wikitext)
    if type(soul_unlock_key) == "table" and soul_unlock_key.args then
        local frame = soul_unlock_key
        soul_unlock_key = frame.args[1]
    end
	
	localization_key = localization_map[soul_unlock_key]
	if localization_key == nil then 
		return string.format("soul_unlock_key %s not in localization_map", soul_unlock_key)
	end
	
	-- Localize, nil for lang override, english string for fallback
	return lang_module.get_string(localization_key, nil, 'en')
end

function p.write_accumulated()
	ret = ""
	for i, data in pairs(accumulated_data) do
		ret = ret .. "Index" .. i .. ": "
		for key, value in pairs(data) do
			local display_value = value
			--Add 400
                if key == "RequiredSouls" then
                	display_value = display_value + 400
                end
            ret = ret .. string.format("  %s:%s, ", p.localize(key), display_value)	
		end
		ret = ret .. '<br>'
	end
	return ret
	--return accumulated_data['0']['AbilityUnlocks']
end

-- Retrieve a certain stat's value at max souls
function p.get_max(soul_unlock_key)
	-- If called internally (direct Lua call), args will be passed directly.
    -- If called from wikitext, `soul_unlock_key` will be the `frame` object, and we get args from `frame.args`.

    -- Handle the case where it's called via #invoke (i.e., from wikitext)
    if type(soul_unlock_key) == "table" and soul_unlock_key.args then
        local frame = soul_unlock_key
        soul_unlock_key = frame.args[1]
    end
	
	last_index = #accumulated_data
	last_value = accumulated_data[last_index][soul_unlock_key]
    	--Add 400
    	if soul_unlock_key == "RequiredSouls" then
        	return last_value + 400
        else
        	return last_value
        end
end

function to_tick(bool)
	if bool == nil or not bool then
		return ''
	else
		return '{{Tick}}'
	end
end

function p.write_table(frame)
	local debug_mode = frame.args['debug_mode']
	if debug_mode == nil then debug_mode = false end
	
	local ret = ''
	
	-- Add header categories
	local tr = ''
	tr = tr .. '<th>' .. '' .. '</th>'
	tr = tr .. '<th colspan="3">' .. dictionary_module.translate('Individual') .. '</th>'
	tr = tr .. '<th colspan="3">' .. dictionary_module.translate('Accumulative') .. '</th>'
	ret = ret .. '<tr>' .. tr .. '</tr>'
	
	-- Add header record, will be soul + each other record twice
	local required_souls_header = '<th>' .. p.localize('RequiredSouls') .. '</th>'
	local non_souls_tr = ''
	for su_key, lang_key in pairs(localization_map) do
		if su_key ~= 'RequiredSouls' then
			non_souls_tr = non_souls_tr .. '<th>' .. p.localize(su_key) .. '</th>'
		end
	end
	local tr = '<tr>' .. required_souls_header .. non_souls_tr .. non_souls_tr .. '</tr>'
	ret = ret .. tr
	
	-- Add data agg_records
	for i, agg_record in ipairs(accumulated_data) do
		local tr = ''
		
		-- Retrieve souls agg_record
		local required_souls = agg_record['RequiredSouls']
		--Add 400
		local souls_str = '{{Souls|' .. (required_souls + 400) .. '}}'
		tr = tr .. '<td>' .. souls_str .. '</td>'
		
		-- Retrieve non-aggregate agg_record
		local non_agg_record = soul_unlocks_data[i]
		for su_key, lang_key in pairs(localization_map) do
			if su_key ~= 'RequiredSouls' then
				local value = to_tick(non_agg_record[su_key])
				
				td = '<td>' .. value .. '</td>'
				tr = tr .. td
			end
		end
		
		-- Retrieve aggregate agg_record
		for su_key, lang_key in pairs(localization_map) do
			if su_key ~= 'RequiredSouls' then
				local value = agg_record[su_key]
				
				-- Display blank instead of nil if missing
				if value == nil then value = '' end
				
				td = '<td>' .. value .. '</td>'
				tr = tr .. td
			end
		end
		
		ret	= ret .. '<tr>' .. tr .. '</tr>'
	end
	
	ret = '<table class="wikitable defaultcenter" style="text-align:center">' .. ret .. '</table>'
	
	if debug_mode then
		return ret
	else
		return frame:preprocess(ret)
	end
end

return p