-
-
Save CelticMinstrel/d4262f02688e05c39f1b to your computer and use it in GitHub Desktop.
A Lua implementation of Wesnoth's [message] WML tag
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local helper = wesnoth.require "lua/helper.lua" | |
local location_set = wesnoth.require "lua/location_set.lua" | |
local wml_actions = wesnoth.wml_actions | |
local function get_image(cfg, speaker) | |
local image = cfg.image | |
if speaker and image == nil then | |
image = speaker.profile | |
end | |
if image == "none" or image == nil then | |
return "" | |
end | |
return image | |
end | |
local function get_caption(cfg, speaker) | |
local caption = cfg.caption | |
if not caption and speaker ~= nil then | |
caption = speaker.name or speaker.type_name | |
end | |
return caption | |
end | |
local function get_speaker(cfg) | |
local speaker | |
local context = wesnoth.current.event_context | |
if cfg.speaker == "narrator" then | |
speaker = "narrator" | |
elseif cfg.speaker == "unit" then | |
speaker = wesnoth.get_units({x=context.x1, y=context.y1}) | |
elseif cfg.speaker == "second_unit" then | |
speaker = wesnoth.get_units({x=context.x2, y=context.y2}) | |
else | |
speaker = wesnoth.get_units(cfg) | |
end | |
if speaker ~= "narrator" and #speaker > 0 then | |
speaker = speaker[1].__cfg -- ??? | |
else | |
speaker = nil | |
end | |
return speaker | |
end | |
local function message_user_choice(cfg) | |
return function() | |
local option_chosen, ti_content = wesnoth.show_message_dialog(cfg[1], cfg[2], cfg[3]) | |
if option_chosen == -2 then -- Pressed Escape (only if no input) | |
wesnoth.context_skip_messages = true | |
end | |
local result_cfg = {} | |
if #options > 0 then | |
result_cfg.value = option_chosen | |
end | |
if text_input ~= nil then | |
result_cfg.text = ti_content | |
end | |
return result_cfg | |
end | |
end | |
local function build_message_dialog(cfg, speaker, options, text_input) | |
local image = get_image(cfg, speaker) | |
local caption = get_caption(cfg, speaker) | |
local left_side = true | |
-- If this doesn't work, might need tostring() | |
if string.find(image, "~RIGHT()") then | |
left_side = false | |
image = string.gsub(image, "~RIGHT()", "") | |
end | |
local msg_cfg = {{ | |
left_side = left_side, | |
title = caption, | |
message = cfg.message, | |
portrait = image, | |
}} | |
if #options > 0 then | |
table.insert(msg_cfg, options) | |
end | |
-- Parse input text, if not available all fields are empty | |
if text_input then | |
local input_max_size = tonumber(text_input.max_length) or 256 | |
if input_max_size > 1024 or input_max_size < 1 then | |
wml_actions.wml_message({message = "Invalid maximum size for input " .. input_max_size, logger = "warning"}) | |
input_max_size = 256 | |
end | |
table.insert(msg_cfg, { | |
label = text_input.label or "", | |
text = text_input.text or "", | |
max_length = input_max_size, | |
}) | |
end | |
return msg_cfg | |
end | |
function wml_actions.message(cfg) | |
local show_if = helper.get_child(cfg, "show_if") or {} | |
if not wesnoth.eval_conditional(show_if) then | |
return | |
end | |
-- Only the first text_input tag is considered | |
local text_input | |
for cfg in helper.child_range(cfg, "text_input") do | |
if text_input ~= nil then | |
wml_actions.wml_message({message = "Too many [text_input] tags, only one accepted", logger = "warning"}) | |
break | |
end | |
text_input = cfg | |
end | |
local options, option_events = {}, {} | |
for option in helper.child_range(cfg, "option") do | |
local condition = helper.get_child(cfg, "show_if") or {} | |
if wesnoth.eval_conditional(condition) then | |
table.insert(options, option.message) | |
table.insert(option_events, {}) | |
for cmd in helper.child_range(option, "command") do | |
table.insert(option_events[#option_events], cmd) | |
end | |
end | |
end | |
-- Check if there is any input to be made, if not the message may be skipped | |
local has_input = text_input ~= nil or #options > 0 | |
if not has_input and (wesnoth.is_skipping_replay or wesnoth.context_skip_messages) then | |
-- No input to get and the user is not interested either | |
return | |
end | |
local sides_for = cfg.side_for | |
if sides_for and not has_input then | |
local show_for_side = false | |
-- Sanity checks on side number and controller | |
for side in split(sides_for) do | |
side = tonumber(side) | |
if side > 0 and side < #wesnoth.sides and wesnoth.sides[side].controller == "human" then | |
show_for_side = true | |
break | |
end | |
end | |
if not show_for_side then | |
-- Player isn't controlling side which should see the message | |
return | |
end | |
end | |
local speaker = get_speaker(cfg) | |
if not speaker then | |
-- No matching unit found, continue onto the next message | |
return | |
elseif speaker == "narrator" then | |
-- Narrator, so deselect units | |
-- wesnoth.deselect_hex() | |
-- The speaker is expected to be either nil or a unit later | |
speaker = nil | |
else | |
if cfg.scroll then | |
wesnoth.scroll_to_tile(speaker.x, speaker.y) | |
end | |
wesnoth.select_hex(speaker.x, speaker.y, false) | |
end | |
if cfg.sound then wesnoth.play_sound(cfg.sound) end | |
local msg_cfg = build_message_dialog(cfg, speaker, options, text_input) | |
local option_chosen | |
if not has_input then | |
-- Always show the dialog if it has no input, whether we are replaying or not | |
message_user_choice(msg_cfg) | |
else | |
local choice = wesnoth.synchronize_choice(message_user_choice(msg_cfg)) | |
local var_name = text_input.variable or "input" | |
option_chosen = tonumber(choice.value) | |
if text_input ~= nil then | |
-- Implement the consequences of the choice | |
wesnoth.set_variable(var_name, choice.text) | |
end | |
end | |
if #options > 0 then | |
if option_chosen > #options then | |
wesnoth.wml_message({message = "invalid choice (" .. option_chosen .. | |
") was specified, choice 1 to " .. #options .. " was expected", | |
logger="debug"}) | |
return | |
end | |
for i, cmd in ipairs(option_events[option_chosen]) do | |
handle_event_commands(cmd) | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment