Forked from CelticMinstrel/wml_action_message.lua
Last active
September 16, 2015 15:40
-
-
Save Vultraz/f9d668976ddd8d18b0f8 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_unit(context.x1, context.y1) | |
elseif cfg.speaker == "second_unit" then | |
speaker = wesnoth.get_unit(context.x2, context.y2) | |
else | |
speaker = wesnoth.get_units(cfg)[1].__cfg | |
end | |
return speaker | |
end | |
local function message_user_choice(msg_cfg) | |
return function() | |
local dlg_result, option_chosen, ti_content = wesnoth.show_message_dialog(msg_cfg) | |
if dlg_result == -2 then -- Cancelled (not quite sure of the right value) | |
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, | |
} | |
-- 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 | |
-- lg::wml_error << "Invalid maximum size for input " << input_max_size | |
input_max_size = 256 | |
end | |
table.insert(msg_cfg, {"text_input", { | |
label = text_input.label or "", | |
text = text_input.text or "", | |
max_length = input_max_size, | |
}}) | |
end | |
for i,opt in ipairs(options) do | |
table.insert(msg_cfg, {"option", {value = opt}}) | |
end | |
return msg_cfg | |
end | |
function wml_actions.message(cfg) | |
-- Only the first text_input tag is considered | |
local text_input = helper.get_child(cfg, "text_input") or nil | |
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]) | |
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 and options ~= nil | |
if not (#options > 0 or 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 tonumber(side) in split(sides_for) do | |
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.select_hex(-1000, -1000) | |
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) | |
-- Implement the consequences of the choice | |
wesnoth.set_variable(var_name, choice.text) | |
end | |
if #options > 0 then | |
if option_chosen > #options then | |
--[[ replace::process_error("invalid choice (" .. option_chosen .. | |
") was specified, choice 1 to " .. #options .. | |
" was expected") ]] | |
return | |
end | |
for i, cmd in ipairs(option_events[option_chosen]) do | |
local action = handle_event_commands(cmd) | |
if action == "continue" then | |
helper.wml_error("[continue] encountered outside a loop scope") | |
elseif action == "break" then | |
return | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment