User:Senthe/sandbox/Module:ExperimentalEmbeddedOption
local p = {}
local EMBEDDED_OPTIONS_FORMAT = '|%sEmbeddedOption|heading=%s|caption=%s|SmallHeading=%s%s|' -- Taken from FATE so we don't have to call out to the template local FONT_FATE = "FATE"
--Pre-declare options so it can be called from find_options local options
local function get_arg_or_nil(args, name) local arg = args[name] if arg == then return nil end return arg end
local function get_arg(args, parent_args, name, default) return get_arg_or_nil(args, name) or get_arg_or_nil(parent_args, name) or default end
local function get_title_from_heading(heading, default) if heading then return heading:gsub('|.+', , 1) end return default end
local function get_page_contents(frame, title) local title_obj = mw.title.new(title, ) local full_title = title_obj.nsText .. ':' .. title_obj.text return frame:expandTemplate{title = full_title, args = {}} end
--[[ Find embedded options in the "pseudo-template" format and expand into list items.
Input parameters: @frame: frame object @contents: a string with the contents of the page being embedded
Returns a string of all expanded options, wrapped in list items. ]] local function find_options(frame, contents) local search_pattern = string.format( EMBEDDED_OPTIONS_FORMAT, '%%%%', '(.-)', '(.-)', '(.-)', '%%%%') local actions = for heading, caption, small_heading in mw.ustring.gmatch(contents, search_pattern) do local use_small_heading = small_heading == 'yes'
actions = actions .. '
' end return actions end --[==[ Find the main page image. The expected default image specification is "
". Any
additional parameters specified should appear after the "|right", not before.
Input parameters: @contents: a string with the contents of the page being embedded
Returns a string with the image name, including the leading "File:" and trailing ".png". ]==] local function get_img(contents) img = contents:match('File:([^%]]-png)%|right[^%[]-%]%]') or 'Question.png' return 'File:' .. img end
--[[ Find the ID, if it's recorded. Appears in a hidden div for gadget use. (See Action of Storylet templates) Some editors leave an empty filed for the parameter but this isn't always the case.
Input parameters: @contents: a string with the contents of the page being embedded
Returns a string with ID or an empty string if it wasn't found. ]] local function get_id(contents) return contents:match('(%d+.-)') or end
--[[ Invert {{{1}}} effects.
Since info lines are bolded when unembedded but not bolded in embedcontext, keeping {{{1}}} unaltered creates unbalanced tags that leak past the info line. Inverting them solves this while maintaining the intended emphasis effect.
We do this here instead of by testing embedcontext in {{{1}}} because {{{1}}}s used outside of info lines should not be altered.
Input parameters: @str: a string with the info line
Returns a string with the detected {{{1}}}s inverted. ]] local function invert_unb(str) --[[ NB: This approach sacrifices edge case support for simplicity. In particular: * Weird stuff like "text"" will convert even more weirdly * The first that doesn't correspond to an earlier will stop further conversion, so something like "1 2 3" will become "1 2 3" whereas "X Y" will be completely unaltered. Neither case is expected to be necessary, but a more complex approach can be considered if that expectation ever proves incorrect. ]] if (str:find('') or str:len()) < (str:find('') or 0) then return str :gsub('(.-)', '%1') end return str end
local function get_info_line(contents, heading)
local info_line = contents:match('(' .. heading .. ' .-)')
if not info_line then
return
end
return invert_unb(info_line)
:gsub('\n%*', ', ') -- condense lists to one line
:gsub('%[%[Category:.-%]%]', ) -- remove categories
.. '
' -- break between lines
end
local function transform_action_contents(frame, contents) -- Scale down small images from 40px to 20px local pc = contents:gsub('small%.png', 'small.png|20px') -- Remove paragraphs pc = pc:gsub('^.-(==+ ?)', '\n \n%1') -- Remove Success/Failure Instructions pc = pc:gsub('...[SF]?[au]?.- Instructions.-\'+', ) -- Remove categories pc = pc:gsub('%[%[Category:.-%]%]', ) -- Remove SMW sets (but preserve SMW tags) pc = pc:gsub('%[%[.-[^S][^M][^W]::.-%]%]', ) pc = pc:gsub('%{%{#set:.-%}%}', ) -- Trim down carriage returns pc = pc:gsub('\n\n', '\n') -- Trim trailing whitespace pc = pc:gsub('\n+%s*$', ) -- Change table pointer to page pc = pc:gsub('%[See below%]', '%[See page%]')
-- Replace headers (
-) with fake headers (<xh2>-<xh6>)
for i = 6, 2, -1 do
-- HTML headers
local tag = 'h' .. i
pc = pc:gsub('<%s*' .. tag .. '%s*>', '<x' .. tag .. '>')
pc = pc:gsub('</%s*' .. tag .. '%s*>', '</x' .. tag .. '>')
-- Wikitext headers
local pat =
for j = 1, i do
pat = pat .. '='
end
pc = pc:gsub(
pat .. '%s*([^\n]-)%s*' .. pat,
'<x' .. tag .. '>%1</x' .. tag .. '>'
)
-- Now fake headers must be expanded as tag extensions
tag = 'x' .. tag
while pc:find('<' .. tag .. '>.-</' .. tag .. '>') do
local _, header
_, _, header = pc:find('<' .. tag .. '>(.-)</' .. tag .. '>')
local header_clean = mw.text.trim(
mw.text.killMarkers(header)
)
-- `header` will be used in a pattern, escaping non-word characters
header = header:gsub('(%W)', '%%%1')
pc = pc:gsub(
'<' .. tag .. '>' .. header .. '</' .. tag .. '>',
frame:extensionTag(tag, header_clean)
)
end
end
return pc
end
local function format_heading(heading, caption, use_small_heading)
local out =
if use_small_heading then
out = out .. '' .. heading .. ''
else
out = out .. '' .. heading .. ''
end
if caption and caption ~= then
out = out .. ' ' .. caption .. ''
end
return out
end
local function make_option(heading, caption, use_small_heading, title, img, contents, id)
return '' ..
'' .. format_heading(heading, caption, use_small_heading) ..
'- ' ..
' Spoiler ' ..
'' .. contents ..
'\n^
'
end
--[[
Turn Options into a "pseudo-template" format for use in Embed.
This is a sort of hack to prevent needing to fully re-render Options multiple times.
Input parameters:
@heading: A string with the options heading, potentially including an alternate appearance
@caption: A string with the non-linkified caption
@use_small_heading: A boolean, true if the heading should be rendered small
Returns a string with the formatted pseudo-template.
]]
local function embedded_options(heading, caption, use_small_heading)
local small_heading =
if use_small_heading then
small_heading = 'yes'
end
return string.format(
EMBEDDED_OPTIONS_FORMAT, '%%', heading, caption, small_heading, '%%')
end
--[[
Render an [[]]
- Spoiler Unlocked with
1 x Key to a Handsome Townhouse and,
Renown: Bohemians 10,
Renown: Society 10,
Renown: The Church 5,
Renown: Tomb-Colonies 5,
5 x Favours: Bohemians,
5 x Favours: Society,
3 x Favours: Hell,
3 x Favours: Revolutionaries,
Connected: Benthic 3,
Connected: Summerset 3,
Connected: The Duchess 3,
Connected: The Masters of the Bazaar 1,
5000 x Penny,
50 x Scrap of Incendiary Gossip,
4 x Favour in High Places,
2 x Cellar of Wine,
2 x Personal Recommendation,
A Member in Good Standing - - Known at the Door,
Scandal 3,
A Person of Some Importance -
Locked with
1 x A Salon or
1 x An Orphanage
Success
A blaze of light!
Success Instructions: You can dispose of your Salon at any time by using the Key to your Handsome Townhouse. IMPORTANT! If you ever lose your Townhouse, your Salon will go with it.
You've lost 4 x Favour in High Places
You've lost 5000 x Penny
You've lost 2 x Cellar of Wine
You've lost 50 x Scrap of Incendiary Gossip
You've lost 2 x Personal Recommendation
You've lost 3 x Favours: Hell
You've lost 5 x Favours: Bohemians
You've lost 3 x Favours: Revolutionaries
You've lost 5 x Favours: Society
You now have 1 x A Salon
Making Waves is increasing… (+20 CP)
Redirects to: Record the Name of your Ship or Spouse
^
Input parameters:
@frame: frame object
@heading: A string with the options heading, potentially including an alternate appearance
@caption: A string with the non-linkified caption
@use_small_heading: A boolean, true if the heading should be rendered small
@only_contents: A boolean, true if the HTML of make_options() is undesired
A string with the fully rendered [[]]
- Spoiler Unlocked with
1 x Key to a Handsome Townhouse and,
Renown: Bohemians 10,
Renown: Society 10,
Renown: The Church 5,
Renown: Tomb-Colonies 5,
5 x Favours: Bohemians,
5 x Favours: Society,
3 x Favours: Hell,
3 x Favours: Revolutionaries,
Connected: Benthic 3,
Connected: Summerset 3,
Connected: The Duchess 3,
Connected: The Masters of the Bazaar 1,
5000 x Penny,
50 x Scrap of Incendiary Gossip,
4 x Favour in High Places,
2 x Cellar of Wine,
2 x Personal Recommendation,
A Member in Good Standing - - Known at the Door,
Scandal 3,
A Person of Some Importance -
Locked with
1 x A Salon or
1 x An Orphanage
Success
A blaze of light!
Success Instructions: You can dispose of your Salon at any time by using the Key to your Handsome Townhouse. IMPORTANT! If you ever lose your Townhouse, your Salon will go with it.
You've lost 4 x Favour in High Places
You've lost 5000 x Penny
You've lost 2 x Cellar of Wine
You've lost 50 x Scrap of Incendiary Gossip
You've lost 2 x Personal Recommendation
You've lost 3 x Favours: Hell
You've lost 5 x Favours: Bohemians
You've lost 3 x Favours: Revolutionaries
You've lost 5 x Favours: Society
You now have 1 x A Salon
Making Waves is increasing… (+20 CP)
Redirects to: Record the Name of your Ship or Spouse
^
]]
options = function(frame, heading, caption, use_small_heading, only_contents)
local title = get_title_from_heading(heading, 'Scheme: Set up a Salon')
heading = heading or
caption = caption or
if caption == then
-- Automatically format Fate costs when possible
local name, cost = mw.ustring.match(title, '^(.-) %((%d+) FATE%)$')
if name then
caption = '(' .. cost .. ' ' .. FONT_FATE .. ')'
if heading == title then
heading = title .. '|' .. name
end
end
end
local success, contents = pcall(get_page_contents, frame, title)
if not success then
return make_option(heading, caption, use_small_heading, title, 'File:Question.png', , 'NaN')
end
local id = get_id(contents)
local img = get_img(contents)
local action_cost = get_info_line(contents, 'Action Cost:')
local unlocked_with = get_info_line(contents, 'Unlocked with')
local locked_with = get_info_line(contents, 'Locked with')
local friend_unlocked_with = get_info_line(contents, 'Your friend needs')
local transformed = transform_action_contents(frame, contents)
if id == then
id = 'MISSING'
end
local inner = 'right'
inner = inner .. action_cost .. unlocked_with .. locked_with ..
friend_unlocked_with .. transformed
if only_contents then
return inner
else
return make_option(heading, caption, use_small_heading, title, img, inner, id)
end
end
--[[
Render an [[]]
- Spoiler Card drawn in
Fallen London
Unlocked with
Shadowy 81
Occurs with Unusual Frequency (20% as common as Standard)
Options:
Go hunting for caches
- Spoiler
Challenge information
Broad,
Shadowy 81 || 56 - very chancy (41%) || 69 - chancy (51%) || 83 - modest (61%) || 96 - very modest (71%) || 110 - low-risk (81%) || 123 - straightforward (91%) || 135 - straightforward (100%)
Success
Beggars and books
Shadowy is increasing…
You've gained 30 x Proscribed Material
Rare Success
An extraordinary find
Shadowy is increasing…
You've gained 1 x Book of Hidden Bodies
You've gained 10 x Proscribed Material
Failure
Mobbed!
^
Spy on the Raggedy Men (
Shadowy challenge)
- Spoiler Locked with
Ambition: Heart's Desire!
Challenge information
Broad,
Shadowy 96 || 66 - very chancy (41%) || 82 - chancy (51%) || 98 - modest (61%) || 114 - very modest (71%) || 130 - low-risk (81%) || 146 - straightforward (91%) || 160 - straightforward (100%)
Success
The King
Shadowy is increasing…
You've gained 60 x Cryptic Clue
Rare Success
A once-great scholar?
Shadowy is increasing…
You've gained 1 x Favour in High Places
Failure
Nothing
^
Spy on the Raggedy Men (with
Ambition: Heart's Desire - the Topsy King)
- Spoiler Unlocked with
Ambition: Heart's Desire - the Topsy King exactly 3
Challenge information
Broad,
Shadowy 96 || 66 - very chancy (41%) || 82 - chancy (51%) || 98 - modest (61%) || 114 - very modest (71%) || 130 - low-risk (81%) || 146 - straightforward (91%) || 160 - straightforward (100%)
Success
The King
Shadowy is increasing…
Ambition: Heart's Desire - the Topsy King is increasing… (+2 CP)
Failure
Nothing
^
^
Input parameters:
@frame: frame object
@heading: A string with the embed heading, potentially including an alternate appearance
@caption: A string with the non-linkified caption
@use_small_heading: A boolean, true if the heading should be rendered small
A string with the fully rendered [[]]
- Spoiler Card drawn in
Fallen London
Unlocked with
Shadowy 81
Occurs with Unusual Frequency (20% as common as Standard)
Options:
Go hunting for caches
- Spoiler
Challenge information
Broad,
Shadowy 81 || 56 - very chancy (41%) || 69 - chancy (51%) || 83 - modest (61%) || 96 - very modest (71%) || 110 - low-risk (81%) || 123 - straightforward (91%) || 135 - straightforward (100%)
Success
Beggars and books
Shadowy is increasing…
You've gained 30 x Proscribed Material
Rare Success
An extraordinary find
Shadowy is increasing…
You've gained 1 x Book of Hidden Bodies
You've gained 10 x Proscribed Material
Failure
Mobbed!
^
Spy on the Raggedy Men (
Shadowy challenge)
- Spoiler Locked with
Ambition: Heart's Desire!
Challenge information
Broad,
Shadowy 96 || 66 - very chancy (41%) || 82 - chancy (51%) || 98 - modest (61%) || 114 - very modest (71%) || 130 - low-risk (81%) || 146 - straightforward (91%) || 160 - straightforward (100%)
Success
The King
Shadowy is increasing…
You've gained 60 x Cryptic Clue
Rare Success
A once-great scholar?
Shadowy is increasing…
You've gained 1 x Favour in High Places
Failure
Nothing
^
Spy on the Raggedy Men (with
Ambition: Heart's Desire - the Topsy King)
- Spoiler Unlocked with
Ambition: Heart's Desire - the Topsy King exactly 3
Challenge information
Broad,
Shadowy 96 || 66 - very chancy (41%) || 82 - chancy (51%) || 98 - modest (61%) || 114 - very modest (71%) || 130 - low-risk (81%) || 146 - straightforward (91%) || 160 - straightforward (100%)
Success
The King
Shadowy is increasing…
Ambition: Heart's Desire - the Topsy King is increasing… (+2 CP)
Failure
Nothing
^
^
]]
local function embed(frame, heading, caption, use_small_heading)
local title = get_title_from_heading(heading, 'A fine day in the Flit')
heading = heading or
local success, contents = pcall(get_page_contents, frame, title)
if not success then
return make_option(heading, caption, use_small_heading, title, 'File:Question.png', , 'NaN')
end
local id = get_id(contents)
local img = get_img(contents)
if id == then
id = 'MISSING'
end
local success, options_list = pcall(find_options, frame, contents)
if not success then
return make_option(heading, caption, use_small_heading, title, img, contents, id)
end
local appears_in = get_info_line(contents, 'Storylet appears in')
local drawn_in = get_info_line(contents, 'Card drawn in')
local unlocked_with = get_info_line(contents, 'Unlocked with')
local locked_with = get_info_line(contents, 'Locked with')
local frequency = get_info_line(contents, 'Occurs with')
--local inner = 'right'
local inner = appears_in .. drawn_in .. unlocked_with .. locked_with .. frequency
inner = inner .. 'Options:
'
inner = inner .. '' ..
find_options(frame, contents) .. '
'
return make_option(heading, caption, use_small_heading, title, img, inner, id)
end
function p.options(frame)
local args = frame.args
local parent_args = frame:getParent().args
local heading = get_arg(args, parent_args, 1, nil)
local caption = get_arg(args, parent_args, 2, nil)
local use_small_heading = get_arg(args, parent_args, 'SmallHeading', false)
local only_contents = get_arg(args, parent_args, 'OnlyContents', false)
local embedded = frame:callParserFunction('#var', 'embeddedoptions') ~=
if embedded then
return embedded_options(heading or , caption or , use_small_heading)
end
return options(frame, heading, caption, use_small_heading, only_contents)
end
function p.embed(frame)
local args = frame.args
local parent_args = frame:getParent().args
local heading = get_arg(args, parent_args, 1, nil)
local caption = get_arg(args, parent_args, 2, nil)
local use_small_heading = get_arg(args, parent_args, 'SmallHeading', false)
return embed(frame, heading, caption, use_small_heading)
end
return p
' ..
'' .. format_heading(heading, caption, use_small_heading) ..
'- ' ..
' Spoiler ' ..
'' .. contents .. '\n^
[[]]
- Spoiler Unlocked with
1 x Key to a Handsome Townhouse and,
Renown: Bohemians 10,
Renown: Society 10,
Renown: The Church 5,
Renown: Tomb-Colonies 5,
5 x Favours: Bohemians,
5 x Favours: Society,
3 x Favours: Hell,
3 x Favours: Revolutionaries,
Connected: Benthic 3,
Connected: Summerset 3,
Connected: The Duchess 3,
Connected: The Masters of the Bazaar 1,
5000 x Penny,
50 x Scrap of Incendiary Gossip,
4 x Favour in High Places,
2 x Cellar of Wine,
2 x Personal Recommendation,
A Member in Good Standing - - Known at the Door,
Scandal 3,
A Person of Some Importance -
Locked with
1 x A Salon or
1 x An Orphanage
Success
A blaze of light!
Success Instructions: You can dispose of your Salon at any time by using the Key to your Handsome Townhouse. IMPORTANT! If you ever lose your Townhouse, your Salon will go with it.
You've lost 4 x Favour in High Places
You've lost 5000 x Penny
You've lost 2 x Cellar of Wine
You've lost 50 x Scrap of Incendiary Gossip
You've lost 2 x Personal Recommendation
You've lost 3 x Favours: Hell
You've lost 5 x Favours: Bohemians
You've lost 3 x Favours: Revolutionaries
You've lost 5 x Favours: Society
You now have 1 x A Salon
Making Waves is increasing… (+20 CP)
Redirects to: Record the Name of your Ship or Spouse
^
[[]]
- Spoiler Unlocked with
1 x Key to a Handsome Townhouse and,
Renown: Bohemians 10,
Renown: Society 10,
Renown: The Church 5,
Renown: Tomb-Colonies 5,
5 x Favours: Bohemians,
5 x Favours: Society,
3 x Favours: Hell,
3 x Favours: Revolutionaries,
Connected: Benthic 3,
Connected: Summerset 3,
Connected: The Duchess 3,
Connected: The Masters of the Bazaar 1,
5000 x Penny,
50 x Scrap of Incendiary Gossip,
4 x Favour in High Places,
2 x Cellar of Wine,
2 x Personal Recommendation,
A Member in Good Standing - - Known at the Door,
Scandal 3,
A Person of Some Importance -
Locked with
1 x A Salon or
1 x An Orphanage
Success
A blaze of light!
Success Instructions: You can dispose of your Salon at any time by using the Key to your Handsome Townhouse. IMPORTANT! If you ever lose your Townhouse, your Salon will go with it.
You've lost 4 x Favour in High Places
You've lost 5000 x Penny
You've lost 2 x Cellar of Wine
You've lost 50 x Scrap of Incendiary Gossip
You've lost 2 x Personal Recommendation
You've lost 3 x Favours: Hell
You've lost 5 x Favours: Bohemians
You've lost 3 x Favours: Revolutionaries
You've lost 5 x Favours: Society
You now have 1 x A Salon
Making Waves is increasing… (+20 CP)
Redirects to: Record the Name of your Ship or Spouse
^
[[]]
- Spoiler Card drawn in
Fallen London
Unlocked with
Shadowy 81
Occurs with Unusual Frequency (20% as common as Standard)Options:
Go hunting for caches
- Spoiler
Challenge information
Broad,
Shadowy 81 || 56 - very chancy (41%) || 69 - chancy (51%) || 83 - modest (61%) || 96 - very modest (71%) || 110 - low-risk (81%) || 123 - straightforward (91%) || 135 - straightforward (100%)Success
Beggars and books
Shadowy is increasing…
You've gained 30 x Proscribed Material
Rare Success
An extraordinary find
Shadowy is increasing…
You've gained 1 x Book of Hidden Bodies
You've gained 10 x Proscribed Material
Failure
Mobbed!
^
- Spoiler
Spy on the Raggedy Men (
Shadowy challenge)- Spoiler Locked with
Ambition: Heart's Desire!
Challenge information
Broad,
Shadowy 96 || 66 - very chancy (41%) || 82 - chancy (51%) || 98 - modest (61%) || 114 - very modest (71%) || 130 - low-risk (81%) || 146 - straightforward (91%) || 160 - straightforward (100%)Success
The King
Shadowy is increasing…
You've gained 60 x Cryptic Clue
Rare Success
A once-great scholar?
Shadowy is increasing…
You've gained 1 x Favour in High Places
Failure
Nothing
^
- Spoiler
Spy on the Raggedy Men (with
Ambition: Heart's Desire - the Topsy King)- Spoiler Unlocked with
Ambition: Heart's Desire - the Topsy King exactly 3
Challenge information
Broad,
Shadowy 96 || 66 - very chancy (41%) || 82 - chancy (51%) || 98 - modest (61%) || 114 - very modest (71%) || 130 - low-risk (81%) || 146 - straightforward (91%) || 160 - straightforward (100%)Success
The King
Shadowy is increasing…
Ambition: Heart's Desire - the Topsy King is increasing… (+2 CP)
Failure
Nothing
^
- Spoiler
Input parameters: @frame: frame object @heading: A string with the embed heading, potentially including an alternate appearance @caption: A string with the non-linkified caption @use_small_heading: A boolean, true if the heading should be rendered small
[[]]
- Spoiler Card drawn in
Fallen London
Unlocked with
Shadowy 81
Occurs with Unusual Frequency (20% as common as Standard)Options:
Go hunting for caches
- Spoiler
Challenge information
Broad,
Shadowy 81 || 56 - very chancy (41%) || 69 - chancy (51%) || 83 - modest (61%) || 96 - very modest (71%) || 110 - low-risk (81%) || 123 - straightforward (91%) || 135 - straightforward (100%)Success
Beggars and books
Shadowy is increasing…
You've gained 30 x Proscribed Material
Rare Success
An extraordinary find
Shadowy is increasing…
You've gained 1 x Book of Hidden Bodies
You've gained 10 x Proscribed Material
Failure
Mobbed!
^
- Spoiler
Spy on the Raggedy Men (
Shadowy challenge)- Spoiler Locked with
Ambition: Heart's Desire!
Challenge information
Broad,
Shadowy 96 || 66 - very chancy (41%) || 82 - chancy (51%) || 98 - modest (61%) || 114 - very modest (71%) || 130 - low-risk (81%) || 146 - straightforward (91%) || 160 - straightforward (100%)Success
The King
Shadowy is increasing…
You've gained 60 x Cryptic Clue
Rare Success
A once-great scholar?
Shadowy is increasing…
You've gained 1 x Favour in High Places
Failure
Nothing
^
- Spoiler
Spy on the Raggedy Men (with
Ambition: Heart's Desire - the Topsy King)- Spoiler Unlocked with
Ambition: Heart's Desire - the Topsy King exactly 3
Challenge information
Broad,
Shadowy 96 || 66 - very chancy (41%) || 82 - chancy (51%) || 98 - modest (61%) || 114 - very modest (71%) || 130 - low-risk (81%) || 146 - straightforward (91%) || 160 - straightforward (100%)Success
The King
Shadowy is increasing…
Ambition: Heart's Desire - the Topsy King is increasing… (+2 CP)
Failure
Nothing
^
- Spoiler


