Module:ItemEffects

From Fallen London Wiki

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

local p = {}

--[[
Table of contents
 - 10-25 Universal stuff for both
 - 27-278 Item page effect display and BiS message calculations
 - 280- Item Effects template functions
--]]

-- Menaces only need to be added here if they appear as an equipment's effect in an increases/reduces way.
menaces = {
	["Nightmares"] = true,
	["Scandal"] = true,
	["Suspicion"] = true,
	["Wounds"] = true,
	["Plagued by a Popular Song"] = true,
	["Troubled Waters"] = true,
	["Hearts' Game: Counterplay"] = true,
	["Poison Tolerance of Your Target"] = true
}

menace_msg = {
	[-4] = "Massively reduces",
	[-2] = "Greatly reduces",
	[-1] = "Reduces",
	[1] = "Increases",
	[2] = "Greatly increases"
}

function ask_minmax(quality, slot, pageID, minmax, extra)
	local limit = 0
	if pageID == nil then
		pageID = 0
	end
	local ask = mw.smw.ask{
		'[[Modifies quality::' .. quality .. ']][[-Has effect::<q>[[Has effect::' .. quality .. ']][[Equips in slot::Category:' .. slot .. ']]' .. extra .. '[[Page ID::!' .. pageID .. ']]</q>]]',
		'?Modifies by=',
		sort = 'Modifies by',order = minmax,limit = 1,searchlabel = '',mainlabel = '-'}
	if ask ~= nil then limit = ask[1][1] end
	return limit
end

function ask_minmax_bdr(slot, mimax, extra)
	local limit = 0
	local ask = mw.smw.ask{
		'[[Equips in slot::Category:' .. slot .. ']]' .. extra .. '[[Page ID::!' .. pageID .. ']]',
		'?Total BDR=',
		sort = 'Total BDR',order = minmax,limit = 1,searchlabel = '',mainlabel = '-'}
	if ask ~= nil then limit = ask[1][1] end
	return limit
end

function msg_logic(value, limit_f, limit_nf, is_fate)
	local out = ''
	
	if value > 0 then -- BiS
		if value > limit_nf and value ~= limit_f then
			out = out .. 'Strict'
		elseif value == limit_nf or (value == limit_f and limit_nf <= limit_f) then
			out = out .. 'Shared'
		end
		
		if out ~= '' then
			out = out .. ' Best-in-Slot'
			if value < limit_f and not is_fate then
				out = out .. ' non-Fate'
			end
		end
	elseif value < 0 then -- WiS
		if value < limit_nf and value ~= limit_f then
			out = out .. 'Strict'
		elseif value == limit_nf or (value == limit_f and limit_nf >= limit_f) then
			out = out .. 'Shared'
		end
		
		if out ~= '' then
			out = out .. ' Worst-in-Slot'
			if value > limit_f and not is_fate then
				out = out .. ' non-Fate'
			end
		end
	end
	
	return out
end

function bis_msg(value, quality, slot, pageID, minmax, is_fate, state)
	if state ~= "Normal" then
		return ''	
	end
	local attributes = {
        ["Watchful"] = true,
        ["Shadowy"] = true,
        ["Persuasive"] = true,
        ["Dangerous"] = true,
        ["Bizarre"] = true,
        ["Dreaded"] = true,
        ["Respectable"] = true,
        ["A Player of Chess"] = true,
        ["Artisan of the Red Science"] = true,
        ["Chthonosophy"] = true,
        ["Glasswork"] = true,
        ["Kataleptic Toxicology"] = true,
        ["Inerrant"] = true,
        ["Insubstantial"] = true,
        ["Mithridacy"] = true,
        ["Monstrous Anatomy"] = true,
        ["Shapeling Arts"] = true,
        ["Neathproofed"] = true,
        ["Zeefaring"] = true,
        ["Steward of the Discordance"] = true,
    }
    
    local item_slot = {
        ["Burden"] = true,   	
        ["Hat"] = true,
        ["Clothing"] = true,
        ["Gloves"] = true,
        ["Weapon"] = true,
        ["Boots"] = true,
        ["Companion"] = true,
        ["Treasure"] = true,        
        ["Destiny"] = true,
        ["Affiliation"] = true,
        ["Transport"] = true,
        ["Home Comfort"] = true,
        ["Ship"] = true,
        ["Spouse"] = true,
        ["Club"] = true,
        ["Tools of the Trade"] = true,
        ["Adornment"] = true,
        ["Luggage"] = true,
        ["Crew"] = true,
        ["Airship"] = true,
        ["Accoutrement"] = true
    }
    
    if (quality == nil) or (not item_slot[slot]) then
    	return '[[Category:Items with Malformed Effects Field]]'
    end

	if not attributes[quality] then
		return ''
	end
	
	local out_bis = ''
	
	local limit_f = 0
	local limit_nf = 0
	
	if not is_fate then
		limit_f = ask_minmax(quality, slot, pageID, minmax, '[[Equipment status::Normal]][[Is Fate::true]]')
		limit_nf = ask_minmax(quality, slot, pageID, minmax, '[[Equipment status::Normal]][[Is Fate::false]]')
	else
		limit_nf = ask_minmax(quality, slot, pageID, minmax, '[[Equipment status::Normal]]')
	end
	
	out_bis = msg_logic(value, limit_f, limit_nf, is_fate)
	
	if out_bis ~= '' then
		out_bis = out_bis .. ' item'
	end
	
	return out_bis
end

function bis_msg_bdr(total_bdr, slot, pageID, is_fate, state)
	if state ~= "Normal" then
		return ''	
	end
	
	local out_bdr = ''
	if total_bdr > 0 then minmax = 'desc'
	elseif total_bdr < 0 then minmax = 'asc'
  	else return '' end
	local limit_f = 0
	local limit_nf = 0
	
	if is_fate then
		limit_nf = ask_minmax_bdr(slot, minmax, '')
	else
		limit_f = ask_minmax_bdr(slot, minmax, '[[Is Fate::true]]')
		limit_nf = ask_minmax_bdr(slot, minmax, '[[Is Fate::false]]')
	end
	
	out_bdr = msg_logic(total_bdr, limit_f, limit_nf, is_fate, 0)
	
	if out_bdr ~= '' then
		out_bdr = out_bdr .. ' [[BDR]] item'
	end
	
	return out_bdr
end

-- Original 'smw_set' function by [[User:Asarta]]
function smw_set(quality, value, bis)
	if quality and value then
		local propertyname = "Has effect"
		mw.smw.set({[propertyname] = quality .. ";" .. value})
		if bis ~= '' then
			mw.smw.set({["Is Best in Slot"] = quality .. ";" .. bis})
		end
	end
end

-- Original 'quality_from_effect' function and multiple effect sorting by [[User:Adnoam]]
function quality_from_effect(effect)
    local quality, sign, value = string.match(effect, "%[%[File:.*link=([^%|]*)%|alt=%]%] %[%[%1%]%]%<%/span%>%s+([%+-]?)%D*(%d+)")
    value = tonumber(value)
    if sign == '-' then
        value = value * -1
    end
    return quality, value
end

function p.effects(frame)
	targs = frame:getParent().args
	list = {}
	slot = frame.args.slot
	out = ''
	ask = nil
	total_bdr = 0
	has_bis = false
	is_fate = false
	if frame.args.fate ~= 'no' then is_fate = true end
	
	pageID = 0
	title = mw.title.getCurrentTitle()
	ask = mw.smw.ask{'[[' .. title.prefixedText .. ']]','?Page ID=',mainlabel = '-'}
	if ask ~= nil then pageID = ask[1][1] end
	
	for k, v in pairs(targs) do
        num = string.match(k, "^Effects(%d+)$")
        if (num) then
            table.insert(list, tonumber(num))
        end
	end
	table.sort(list)
	
	local bdr = {
		["Bizarre"] = true,
		["Dreaded"] = true,
       	["Respectable"] = true
    }
	
	for _, num in ipairs(list) do
    	local effect = targs["Effects" .. num]
  	    local quality, value = quality_from_effect(effect)
  	    
  	    if (bdr[quality]) then
            total_bdr = total_bdr + value
        end
  	    
  	    minmax = ''
  	    if value > 0 then minmax = 'desc'
  	    elseif value < 0 then minmax = 'asc' 
  	    else return '' end
		
		if menaces[quality] then
			out = out ..  '*'
			if menace_msg[value] then
				out = out .. menace_msg[value] .. ' ' .. string.gsub(effect, '[+-]%d', 'build up.<sup>[[Menaces (Guide)#Menace Equipment|What does this mean?]]</sup>')
			else
				out = out .. '<span class="error">Invalid menace input!</span>'
			end
		else
			out = out .. '*' .. effect
		end
		
		out_bis = ''
		out_bis = bis_msg(value, quality, slot, pageID, minmax, is_fate, frame.args.state)
		if out_bis ~= '' then
			has_bis = true
			out = out .. ' (' .. out_bis .. ')'
		end
		
		smw_set(quality, value, out_bis)
		
		out = out .. '[[Category:' .. quality .. ' Items]]\n'
	end
	
	if total_bdr ~= 0 then
		out_bdr = bis_msg_bdr(total_bdr, slot, pageID, is_fate, frame.args.state)
		if out_bdr ~= '' then
			out = out .. ':* '
			if has_bis then out = out .. 'Also: ' end
			out = out .. out_bdr
			out = out .. '\n'
		end
	end
	
	return out
end

local wrap_bis_pre = {
	['none'] = '',
	['italic'] = '<i>',
	['bold'] = '<b>',
	['underline'] = '<u>',
	['text'] = ''
}
local wrap_bis_post = {
	['none'] = '',
	['italic'] = '</i>',
	['bold'] = '</b>',
	['underline'] = '</u>',
	['text'] = ''
}
local wrap_full_pre = {
	['tablelist'] = '<ul style="list-style-type: none; margin-left: 0;">',
	['ul'] = '<ul>',
	['tight'] = ''
}
local wrap_full_post = {
	['tablelist'] = '</ul>',
	['ul'] = '</ul>',
	['tight'] = ''
}
local wrap_effects_pre = {
	['tablelist'] = '<li>',
	['ul'] = '<li>',
	['tight'] = ''
}
local wrap_effects_post = {
	['tablelist'] = '</li>',
	['ul'] = '</li>',
	['tight'] = '<br>'
}

local function handle_effect(frame, full, out, style)
	local ret = out
	local quality, value = string.match(full, '%[%[:(.-)%|.-%]%]% %((.-)%)')
	local icon = '[[File:Question.png]]'
	local icon_q = mw.smw.ask{
    	'[[' .. quality .. ']]', '?Has icon=icon',
    	mainlabel = '-'
	}
	if icon_q ~= nil then
		icon = icon_q[1]['icon']
	end
	icon = string.gsub(icon, '%|frameless%|border%|text%-top%|', '|20px|link=' .. quality .. '|alt=')
	if menaces[quality] then
		ret = ret .. wrap_effects_pre[style] .. menace_msg[tonumber(value)] .. ' ' .. icon .. ' [[' .. quality .. ']]' ..  ' build up.<sup>[[Menaces (Guide)#Menace Equipment|?]]</sup>' .. wrap_effects_post[style]
	else
		if tonumber(value) > 0 then value = '+' .. value  end
		ret = ret .. wrap_effects_pre[style] .. icon .. ' [[' .. quality .. ']] ' .. value .. wrap_effects_post[style]
	end
	return ret
end

local function handle_bis(full, out, strict, shared)
	local ret = out
	local quality, bis = string.match(full, '(.-)% %((.-)%)')
	if string.sub(bis, 1, 6) == 'Strict' then
		if strict == 'text' then
			bis = string.gsub(bis, '(%u)[eo][sr].-%-in%-Slot', '%1iS')
			ret = string.gsub(ret, '%[%[' .. quality .. '%]%]% ([+-]%d+)', '[[' .. quality .. ']]</span> %1 (' .. bis .. ')')
		else
			ret = string.gsub(ret, '%[%[' .. quality .. '%]%]', wrap_bis_pre[strict] .. '[[' .. quality .. ']]' .. wrap_bis_post[strict])
		end
	elseif string.sub(bis, 1, 6) == 'Shared' then
		if shared == 'text' then
			bis = string.gsub(bis, '(%u)[eo][sr].-%-in%-Slot', '%1iS')
			ret = string.gsub(ret, '%[%[' .. quality .. '%]%]% ([+-]%d+)', '[[' .. quality .. ']]</span> %1 (' .. bis .. ')')
		else
			ret = string.gsub(ret, '%[%[' .. quality .. '%]%]', wrap_bis_pre[shared] .. '[[' .. quality .. ']]' .. wrap_bis_post[shared])
		end
	end
	return ret
end

function p.effects_template(frame)
	local args = frame.args
	if args[1] == nil then
		return '<span class="error">Item Effects error, no parameter was given.</span>'
	end
	local item = args[1]
	local style = args.style or 'tablelist'
	local style_strict = args.bis_strict or 'none'
	local style_shared = args.bis_shared or 'none'
	
	local query = mw.smw.ask{
    	'[[' .. item .. ']]', '?Has Game Type=gt', '?Has effect=effects', '?Is Best in Slot=bis', 
    	mainlabel = '-'
	}
	if query == nil then
		return '<span class="error">Item Effects error, query returned no results.</span>'
	end
	if query[1]['gt'] ~= 'Item' then
		return '<span class="error">Item Effects error, given page is not an item.</span>'
	end
	
	local ret = ''
	ret = ret .. wrap_full_pre[style]
	
	if query[1]['effects'] then
		if type(query[1]['effects']) == 'string' then
			ret = handle_effect(frame, query[1]['effects'], ret, style)
		else
			for _,r in ipairs(query[1]['effects']) do
				ret = handle_effect(frame, r, ret, style)
			end
		end
	end
	
	if query[1]['bis'] then
		if type(query[1]['bis']) == 'string' then
			ret = handle_bis(query[1]['bis'], ret, style_strict, style_shared)
		else
			for _,r in ipairs(query[1]['bis']) do
				ret = handle_bis(r, ret, style_strict, style_shared)
			end
		end
	end
	
	ret = ret .. wrap_full_post[style]
	
	return ret
end

return p