Module:Sandbox/User:Artoire/1: Difference between revisions

From Brighter Shores Wiki
Jump to navigation Jump to search
Content added Content deleted
mNo edit summary
mNo edit summary
 
(One intermediate revision by the same user not shown)
Line 3: Line 3:
current_xp = 24,
current_xp = 24,
target_xp = 37,
target_xp = 37,
ingot = 'Maloic Adathril Ingot',
ingot = 'Coarse Deathstone (Etched)',
profession = 'Stonemason', -- 'Bonewright'/'Stonemason'/'Blacksmith'
ore_buy = 'true',
pole_buy = 'none', -- 'none'/'logs'/'pole'
})
})
]]
]]
Line 10: Line 13:
require('Module:Mw.html extension')
require('Module:Mw.html extension')
local xp = require('Module:Experience')
local xp = require('Module:Experience')
local cache = require('Module:Break Isolation').get_module_store('Module:Sandbox/User:Artoire/1')
local currency = require('Module:Currency')
local currency = require('Module:Currency')
local lang = mw.language.getContentLanguage()
local lang = mw.language.getContentLanguage()


local function lookup_ingots()
local _ingots = {}
local function lookup_ingots(profession)
if cache.ingots then return cache.ingots end
if _ingots[profession] then
local ingots = {
return _ingots[profession]
end
_ingots[profession] = {
recipes = {},
recipes = {},
order = {}
order = {}
}
}
cache.ingots = ingots
for _, result in ipairs(mw.smw.ask{
for _, result in ipairs(mw.smw.ask{
({
'[[Uses facility::Goblin Smelter||Gnome Smelter]]',
Blacksmith = '[[Uses facility::Goblin Smelter||Gnome Smelter]]',
Stonemason = '[[Uses facility::T.E.A. Machine]]',
Bonewright = '[[Uses facility::B.R.E.W.S. Vat]]'
})[profession],
['?Recipe JSON'] = '',
['?Recipe JSON'] = '',
mainlabel = '-',
mainlabel = '-',
Line 30: Line 38:
result = mw.text.jsonDecode(result[1])
result = mw.text.jsonDecode(result[1])
local ingot = result.output[1].name
local ingot = result.output[1].name
ingots.recipes[ingot] = {
_ingots[profession].recipes[ingot] = {
xp = result.xp,
xp = result.xp,
facility = result.facility,
facility = result.facility,
Line 37: Line 45:
level = result.level
level = result.level
}
}
table.insert(ingots.order, ingot)
table.insert(_ingots[profession].order, ingot)
end
end
return ingots
return _ingots[profession]
end
end


local function lookup_weapons()
local function lookup_weapons(profession)
local ingots = lookup_ingots(profession)
if cache.weapons then return cache.weapons end
local ingots = lookup_ingots()
local weapons = {}
local weapons = {}
cache.weapons = weapons
for _, result in ipairs(mw.smw.ask{
for _, result in ipairs(mw.smw.ask{
({
'[[Uses facility::Goblin Forge||Gnome Forge]]',
Blacksmith = '[[Uses facility::Goblin Forge||Gnome Forge]]',
Stonemason = '[[Category:Stonemason]][[Category:Pages with recipes]][[Uses facility::!T.E.A. Machine]]',
Bonewright = '[[Category:Bonewright]][[Category:Pages with recipes]][[Uses facility::!B.R.E.W.S. Vat]]'
})[profession],
['?Recipe JSON'] = '',
['?Recipe JSON'] = '',
mainlabel = '-',
mainlabel = '-',
Line 56: Line 66:
local lvl = result['Profession Level A']
local lvl = result['Profession Level A']
result = mw.text.jsonDecode(result[1])
result = mw.text.jsonDecode(result[1])
if not result.passive and result.profession == profession then
local ingot
local pole
local ingot
local pole
for _, material in ipairs(result.materials) do
if ingots.recipes[material.name] then
for _, material in ipairs(result.materials) do
if ingots.recipes[material.name] then
assert(not ingot)
ingot = material
assert(not ingot)
ingot = material
else
else
assert(not pole)
pole = material
assert(not pole)
pole = material
end
end
end
weapons[ingot.name] = weapons[ingot.name] or {}
table.insert(weapons[ingot.name], {
facility = result.facility,
level = result.level,
ingot = ingot,
pole = pole,
name = result.output[1].name,
xp = result.xp
})
end
end
weapons[ingot.name] = weapons[ingot.name] or {}
table.insert(weapons[ingot.name], {
facility = result.facility,
level = result.level,
ingot = ingot,
pole = pole,
name = result.output[1].name,
xp = result.xp
})
end
end
return weapons
return weapons
Line 93: Line 105:
end
end


local _lookup_price_cache = {}
cache.lookup_price = cache.lookup_price or {}
local function lookup_price(item)
local function lookup_price(item)
cache.lookup_price[item] = cache.lookup_price[item] or _lookup_price_uncached(item)
_lookup_price_cache[item] = _lookup_price_cache[item] or _lookup_price_uncached(item)
return cache.lookup_price[item]
return _lookup_price_cache[item]
end
end


Line 119: Line 131:
end
end


local _lookup_pole_cache = {}
cache.lookup_pole = cache.lookup_pole or {}
local function lookup_pole(pole)
local function lookup_pole(pole)
cache.lookup_pole[pole] = cache.lookup_pole[pole] or _lookup_pole_uncached(pole)
_lookup_pole_cache[pole] = _lookup_pole_cache[pole] or _lookup_pole_uncached(pole)
return cache.lookup_pole[pole]
return _lookup_pole_cache[pole]
end
end


Line 136: Line 148:
end
end


local _lookup_ore_cache = {}
cache.lookup_ore = cache.lookup_ore or {}
local function lookup_ore(ore)
local function lookup_ore(ore)
cache.lookup_ore[ore] = cache.lookup_ore[ore] or _lookup_ore_uncached(ore)
_lookup_ore_cache[ore] = _lookup_ore_cache[ore] or _lookup_ore_uncached(ore)
return cache.lookup_ore[ore]
return _lookup_ore_cache[ore]
end
end


Line 153: Line 165:
end
end


local _lookup_log_cache = {}
cache.lookup_log = cache.lookup_log or {}
local function lookup_log(log)
local function lookup_log(log)
cache.lookup_log[log] = cache.lookup_log[log] or _lookup_log_uncached(log)
_lookup_log_cache[log] = _lookup_log_cache[log] or _lookup_log_uncached(log)
return cache.lookup_log[log]
return _lookup_log_cache[log]
end
end


Line 163: Line 175:
local p = {}
local p = {}


function p.ingots()
function p.ingots(frame)
return table.concat(lookup_ingots().order, ',')
return table.concat(lookup_ingots(frame.args.profession).order, ',')
end
end


Line 170: Line 182:
return p._main(frame:getParent().args)
return p._main(frame:getParent().args)
end
end

p.w = lookup_weapons


function p._main(args)
function p._main(args)
local profession = args.profession

local current_xp = tonumber(args.current_xp) or 0
local current_xp = tonumber(args.current_xp) or 0
local current_lvl
local current_lvl
Line 201: Line 213:
buying_poles = not (buying_logs or chopping_logs)
buying_poles = not (buying_logs or chopping_logs)


local ingot = lookup_ingots().recipes[args.ingot]
local ingot = lookup_ingots(profession).recipes[args.ingot]


local result = mw.html.create()
local result = mw.html.create()
Line 224: Line 236:
tbl
tbl
:tag('tr')
:tag('tr')
:th(skillclickpic('Miner')):done()
:th(skillclickpic(({
Blacksmith = 'Miner',
:th{ 'Ore', attr = { colspan = '3' } }:done()
Stonemason = 'Miner',
:th{ 'Ingot', attr = { colspan = '2' } }:done()
Bonewright = 'Gatherer'
})[profession])):done()
:th{ ({
Blacksmith = 'Ore',
Stonemason = 'Rock',
Bonewright = 'Bone'
})[profession], attr = { colspan = '3' } }:done()
:th{ ({
Blacksmith = 'Ingot',
Stonemason = 'Etched',
Bonewright = 'Brewed'
})[profession], attr = { colspan = '2' } }:done()
:IF(chopping_logs)
:IF(chopping_logs)
:th(skillclickpic('Woodcutter')):done()
:th(skillclickpic('Woodcutter')):done()
Line 235: Line 259:
:END()
:END()
:th{ 'Pole', attr = { colspan = '3' } }:done()
:th{ 'Pole', attr = { colspan = '3' } }:done()
:th(skillclickpic('Blacksmith')):done()
:th(skillclickpic(profession)):done()
:th{ 'Product', attr = { colspan = '3' } }:done()
:th{ 'Product', attr = { colspan = '3' } }:done()
:th{ 'Cost', attr = { colspan = '10' } }:done()
:th{ 'Cost', attr = { colspan = '10' } }:done()
:done()
:done()


for _, weapon in ipairs(lookup_weapons()[ingot.ingot]) do
for _, weapon in ipairs(lookup_weapons(profession)[ingot.ingot]) do
if not ingot.xp then
if not ingot.xp then
tbl
tbl
:tr()
:tr()
:td{
:td{
'Missing XP for smelting [[' .. ingot.ingot .. ']]; Please [' .. tostring(mw.uri.fullUrl(ingot.ingot, 'action=edit&section=1')) .. ' edit the page] to add the experience earned (after |exp =)',
'Missing XP for preparing [[' .. ingot.ingot .. ']]; Please [' .. tostring(mw.uri.fullUrl(ingot.ingot, 'action=edit&section=1')) .. ' edit the page] to add the experience earned (after |exp =)',
attr = { colspan = colspan }
attr = { colspan = colspan }
}
}
Line 319: Line 343:


local cost = needed_ores * lookup_price(ingot.ore)[buying_ores and 'buy' or 'sell']
local cost = needed_ores * lookup_price(ingot.ore)[buying_ores and 'buy' or 'sell']
local dbg = { args = args, needed_ores = needed_ores, lookup_ore = lookup_price(ingot.ore) }
if chopping_logs then
if chopping_logs then
if needed_logs then
if needed_logs then
dbg.needed_logs = needed_logs
dbg.lookup_chop_log = lookup_price(pole_info.log)
cost = cost + needed_logs * lookup_price(pole_info.log).sell
cost = cost + needed_logs * lookup_price(pole_info.log).sell
end
end
elseif buying_logs then
elseif buying_logs then
if needed_logs then
if needed_logs then
dbg.needed_logs = needed_logs
dbg.lookup_buy_log = lookup_price(pole_info.log)
cost = cost + needed_logs * lookup_price(pole_info.log).buy
cost = cost + needed_logs * lookup_price(pole_info.log).buy
end
end
else
else
if weapon.pole then
if weapon.pole then
dbg.needed_poles = needed_poles
dbg.lookup_buy_poles = lookup_price(weapon.pole.name)
cost = cost + needed_poles * lookup_price(weapon.pole.name).buy
cost = cost + needed_poles * lookup_price(weapon.pole.name).buy
end
end
end
end


row:node(currency._cell(cost, { html = 'yes' }))
if args.debug then
dbg.cost = cost
row
:td{ mw.text.jsonEncode(dbg), attr = { colspan = "10" } }
else
row:node(currency._cell(cost, { html = 'yes' }))
end
end
end
end
end

Latest revision as of 20:30, 21 December 2024

Documentation for this module may be created at Module:Sandbox/User:Artoire/1/doc

--[[
mw.log(p._main{
	current_xp = 24,
	target_xp = 37,
	ingot = 'Coarse Deathstone (Etched)',
	profession = 'Stonemason',  -- 'Bonewright'/'Stonemason'/'Blacksmith'
	ore_buy = 'true',
	pole_buy = 'none',  -- 'none'/'logs'/'pole'
})
]]

require('strict')
require('Module:Mw.html extension')
local xp = require('Module:Experience')
local currency = require('Module:Currency')
local lang = mw.language.getContentLanguage()

local _ingots = {}
local function lookup_ingots(profession)
	if _ingots[profession] then
		return _ingots[profession]
	end
	_ingots[profession] = {
		recipes = {},
		order = {}
	}
	for _, result in ipairs(mw.smw.ask{
		({
			Blacksmith = '[[Uses facility::Goblin Smelter||Gnome Smelter]]',
			Stonemason = '[[Uses facility::T.E.A. Machine]]',
			Bonewright = '[[Uses facility::B.R.E.W.S. Vat]]'
		})[profession],
		['?Recipe JSON'] = '',
		mainlabel = '-',
		sort = 'Profession Level A',
		limit = '500'
	}) do
		result = mw.text.jsonDecode(result[1])
		local ingot = result.output[1].name
		_ingots[profession].recipes[ingot] = {
			xp = result.xp,
			facility = result.facility,
			ingot = result.output[1].name,
			ore = result.materials[1].name,
			level = result.level
		}
		table.insert(_ingots[profession].order, ingot)
	end
	return _ingots[profession]
end

local function lookup_weapons(profession)
	local ingots = lookup_ingots(profession)
	local weapons = {}
	for _, result in ipairs(mw.smw.ask{
		({
			Blacksmith = '[[Uses facility::Goblin Forge||Gnome Forge]]',
			Stonemason = '[[Category:Stonemason]][[Category:Pages with recipes]][[Uses facility::!T.E.A. Machine]]',
			Bonewright = '[[Category:Bonewright]][[Category:Pages with recipes]][[Uses facility::!B.R.E.W.S. Vat]]'
		})[profession],
		['?Recipe JSON'] = '',
		mainlabel = '-',
		sort = 'Profession Level A',
		limit = '500'
	}) do
		local lvl = result['Profession Level A']
		result = mw.text.jsonDecode(result[1])
		if not result.passive and result.profession == profession then
			local ingot
			local pole
			for _, material in ipairs(result.materials) do
				if ingots.recipes[material.name] then
					assert(not ingot)
					ingot = material
				else
					assert(not pole)
					pole = material
				end
			end
			weapons[ingot.name] = weapons[ingot.name] or {}
			table.insert(weapons[ingot.name], {
				facility = result.facility,
				level = result.level,
				ingot = ingot,
				pole = pole,
				name = result.output[1].name,
				xp = result.xp
			})
		end
	end
	return weapons
end

local function _lookup_price_uncached(item)
	local result = mw.smw.ask{
		('[[Sold item::%s]]'):format(item),
		['?Shop buy price'] = 'buy',
		['?Shop sell price'] = 'sell',
		mainlabel = '-'
	}[1]
	return {
		buy = tonumber(result.buy),
		sell = tonumber(result.sell)
	}
end

local _lookup_price_cache = {}
local function lookup_price(item)
	_lookup_price_cache[item] = _lookup_price_cache[item] or _lookup_price_uncached(item)
	return _lookup_price_cache[item]
end

local function _lookup_pole_uncached(pole)
	local pole_data = mw.text.jsonDecode(mw.smw.ask{
		('[[%s]]'):format(pole),
		['?Recipe JSON'] = '',
		mainlabel = '-'
	}[1][1])
	local post = pole_data.materials[1].name
	local post_data = mw.text.jsonDecode(mw.smw.ask{
		('[[%s]]'):format(post),
		['?Recipe JSON'] = '',
		mainlabel = '-'
	}[1][1])
	return {
		level = pole_data.level,
		pole = pole,
		post = post,
		log = post_data.materials[1].name
	}
end

local _lookup_pole_cache = {}
local function lookup_pole(pole)
	_lookup_pole_cache[pole] = _lookup_pole_cache[pole] or _lookup_pole_uncached(pole)
	return _lookup_pole_cache[pole]
end

local function _lookup_ore_uncached(ore)
	local data = mw.smw.ask{
		('[[%s]]'):format(ore),
		['?Profession Level A'] = '',
		mainlabel = '-'
	}[1]
	return {
		level = tonumber(data[1])
	}
end

local _lookup_ore_cache = {}
local function lookup_ore(ore)
	_lookup_ore_cache[ore] = _lookup_ore_cache[ore] or _lookup_ore_uncached(ore)
	return _lookup_ore_cache[ore]
end

local function _lookup_log_uncached(log)
	local data = mw.smw.ask{
		('[[%s]]'):format(log),
		['?Profession Level A'] = '',
		mainlabel = '-'
	}[1]
	return {
		level = tonumber(data[1])
	}
end

local _lookup_log_cache = {}
local function lookup_log(log)
	_lookup_log_cache[log] = _lookup_log_cache[log] or _lookup_log_uncached(log)
	return _lookup_log_cache[log]
end

local p = {}

local p = {}

function p.ingots(frame)
	return table.concat(lookup_ingots(frame.args.profession).order, ',')
end

function p.main(frame)
	return p._main(frame:getParent().args)
end

function p._main(args)
	local profession = args.profession

	local current_xp = tonumber(args.current_xp) or 0
	local current_lvl
	if current_xp <= 500 then
		current_lvl = current_xp
		current_xp = xp._total_xp(current_lvl)
	else
		current_lvl = xp._level_at(current_xp)
	end

	local target_xp = tonumber(args.target_xp) or 0	
	local target_lvl
	if target_xp <= 500 then
		target_lvl = target_xp
		target_xp = xp._total_xp(target_lvl)
	else
		target_lvl = xp._level_at(target_xp)
	end

	local remaining_xp = target_xp - current_xp

	local buying_ores = args.ore_buy ~= 'false'

	local buying_poles = args.pole_buy
	local chopping_logs = buying_poles == 'none'
	local buying_logs = buying_poles == 'logs'
	buying_poles = not (buying_logs or chopping_logs)

	local ingot = lookup_ingots(profession).recipes[args.ingot]

	local result = mw.html.create()

	result:wikitext(('To get from %s xp (level %s) to %s xp (level %s) requires %s experience'):format(lang:formatNum(current_xp), current_lvl, lang:formatNum(target_xp), target_lvl, lang:formatNum(remaining_xp)))

	local tbl = result:tag('table')
		:addClass('wikitable sortable')

	local function skillclickpic(profession)
		return ('[[File:%s small icon.png|15px|link=%s|%s level]]'):format(profession, profession, profession)
	end
	
	local colspan = 23
	if chopping_logs then
		colspan = colspan + 1
	end
	if chopping_logs or buying_logs then
		colspan = colspan + 3
	end

	tbl
		:tag('tr')
			:th(skillclickpic(({
				Blacksmith = 'Miner',
				Stonemason = 'Miner',
				Bonewright = 'Gatherer'
			})[profession])):done()
			:th{ ({
				Blacksmith = 'Ore',
				Stonemason = 'Rock',
				Bonewright = 'Bone'
			})[profession], attr = { colspan = '3' } }:done()
			:th{ ({
				Blacksmith = 'Ingot',
				Stonemason = 'Etched',
				Bonewright = 'Brewed'
			})[profession], attr = { colspan = '2' } }:done()
			:IF(chopping_logs)
				:th(skillclickpic('Woodcutter')):done()
			:END()
			:IF(chopping_logs or buying_logs)
				:th{ 'Log', attr = { colspan = '3' } }:done()
				:th(skillclickpic('Carpenter')):done()
			:END()
			:th{ 'Pole', attr = { colspan = '3' } }:done()
			:th(skillclickpic(profession)):done()
			:th{ 'Product', attr = { colspan = '3' } }:done()
			:th{ 'Cost', attr = { colspan = '10' } }:done()
		:done()

	for _, weapon in ipairs(lookup_weapons(profession)[ingot.ingot]) do
		if not ingot.xp then
			tbl
				:tr()
					:td{
						'Missing XP for preparing [[' .. ingot.ingot .. ']]; Please [' .. tostring(mw.uri.fullUrl(ingot.ingot, 'action=edit&section=1')) .. ' edit the page] to add the experience earned (after |exp =)',
						attr = { colspan = colspan }
					}
				:done()
			break
		end
		if not weapon.xp then
			tbl
				:tr()
					:td{
						'Missing XP for creating [[' .. weapon.name .. ']]; Please ['.. tostring(mw.uri.fullUrl(weapon.name, 'action=edit&section=1')) .. ' edit the page] to add the experience earned (after |exp =)',
						attr = { colspan = colspan }
					}
				:done()
		else
			local xp_per = weapon.xp + ingot.xp * weapon.ingot.quantity
			local needed = math.ceil(remaining_xp / xp_per)

			local needed_ores = needed * weapon.ingot.quantity
			local row = tbl
				:tag('tr')
					:td(lookup_ore(ingot.ore).level):done()
					:td{ needed_ores .. '&times;', css = { ['border-right'] = '0', ['padding-right'] = '0', ['text-align'] = 'right', ['data-sort-value'] = needed_ores } }:done()
					:td{ ('[[File:%s.png|link=%s|30px]]'):format(ingot.ore, ingot.ore), css = { ['border-left'] = '0', ['padding-left'] = '0' }, addClass = 'plinkt-image no-border' }:done()
					:td{ '[[' .. ingot.ore .. ']]', addClass = 'plinkt-link no-border' }:done()
					:td{ ('[[File:%s.png|link=%s|30px]]'):format(ingot.ingot, ingot.ingot), css = { ['border-left'] = '0', ['padding-left'] = '0' }, addClass = 'plinkt-image no-border', ['data-sort-value'] = needed_ores }:done()
					:td{ '[[' .. ingot.ingot .. ']]', addClass = 'plinkt-link no-border' }:done()

			local pole_info
			local needed_logs, needed_poles

			if weapon.pole then
				needed_poles = needed * weapon.pole.quantity
				if chopping_logs or buying_logs then
					pole_info = lookup_pole(weapon.pole.name)
					needed_logs = math.ceil(needed_poles / 2)
				end
				if chopping_logs then
					row
						:td(lookup_log(pole_info.log).level):done()
				end
				if chopping_logs or buying_logs then
					row
						:td{ needed_logs .. '&times;', css = { ['border-right'] = '0', ['padding-right'] = '0', ['text-align'] = 'right' }, attr = { ['data-sort-value'] = needed_logs } }:done()
						:td{ ('[[File:%s.png|link=%s|30px]]'):format(pole_info.log, pole_info.log), css = { ['border-left'] = '0', ['padding-left'] = '0' }, addClass = 'plinkt-image no-border' }:done()
						:td{ '[[' .. pole_info.log .. ']]', addClass = 'plinkt-link no-border' }:done()
						:td(pole_info.level):done()
				end

				row
					:td{ needed_poles .. '&times;', css = { ['border-right'] = '0', ['padding-right'] = '0', ['text-align'] = 'right' }, attr = { ['data-sort-value'] = needed_poles } }:done()
					:td{ ('[[File:%s.png|link=%s|30px]]'):format(weapon.pole.name, weapon.pole.name), css = { ['border-left'] = '0', ['padding-left'] = '0' }, addClass = 'plinkt-image no-border' }:done()
					:td{ '[[' .. weapon.pole.name .. ']]', addClass = 'plinkt-link no-border' }:done()
			else
				if chopping_logs then
					row
						:na()
				end
				if chopping_logs or buying_logs then
					row
						:td{ '<small>N/A</small>', addClass = 'table-na', attr = { ['data-sort-value'] = '0', colspan = '3' } }:done()
						:na()
				end
				row
					:td{ '<small>N/A</small>', addClass = 'table-na', attr = { ['data-sort-value'] = '0', colspan = '3' } }:done()
			end

			row
				:td(weapon.level)
				:td{ needed .. '&times;', css = { ['border-right'] = '0', ['padding-right'] = '0', ['text-align'] = 'right' }, attr = { ['data-sort-value'] = needed } }:done()
				:td{ ('[[File:%s.png|link=%s|30px]]'):format(weapon.name, weapon.name), css = { ['border-left'] = '0', ['padding-left'] = '0' }, addClass = 'plinkt-image no-border' }:done()
				:td{ '[[' .. weapon.name .. ']]', addClass = 'plinkt-link no-border' }

			local cost = needed_ores * lookup_price(ingot.ore)[buying_ores and 'buy' or 'sell']
			if chopping_logs then
				if needed_logs then
					cost = cost + needed_logs * lookup_price(pole_info.log).sell
				end
			elseif buying_logs then
				if needed_logs then
					cost = cost + needed_logs * lookup_price(pole_info.log).buy
				end
			else
				if weapon.pole then
					cost = cost + needed_poles * lookup_price(weapon.pole.name).buy
				end
			end

			row:node(currency._cell(cost, { html = 'yes' }))
		end
	end

	return result
end

return p