Update mainmenu/init.lua
This commit is contained in:
parent
a577b070e9
commit
e4bea7c082
1 changed files with 196 additions and 88 deletions
|
|
@ -12,18 +12,17 @@ size = window.max_formspec_size
|
||||||
default_textures = minetest.get_texturepath_share().."/base/pack/"
|
default_textures = minetest.get_texturepath_share().."/base/pack/"
|
||||||
|
|
||||||
--FIXME: Assets
|
--FIXME: Assets
|
||||||
local assets = "/Users/iboettcher/eclipse-workspace/mods/mtmenu/"
|
local assets = os.getenv("HOME").."/eclipse-workspace/mods/mtmenu/"
|
||||||
|
|
||||||
local version = minetest.get_version()
|
local version = minetest.get_version()
|
||||||
|
|
||||||
-- Holds all the interface parts
|
-- This is where all view-specific state information goes.
|
||||||
state = {}
|
state = {}
|
||||||
|
|
||||||
local fe = minetest.formspec_escape
|
local fe = minetest.formspec_escape
|
||||||
local hte = minetest.hypertext_escape
|
local hte = minetest.hypertext_escape
|
||||||
|
|
||||||
--FIXME: Replace with /content because pause menu
|
dofile(minetest.get_builtin_path().."common/settings/settingtypes.lua")
|
||||||
dofile(minetest.get_builtin_path().."mainmenu/settings/settingtypes.lua")
|
|
||||||
|
|
||||||
---[[
|
---[[
|
||||||
|
|
||||||
|
|
@ -37,7 +36,6 @@ minetest.set_formspec_prepend("\
|
||||||
style[nobg,nobg:hovered,nobg:focused,nobg:hovered+focused;border=false;bgimg="..default_textures.."blank.png;bgimg_middle=0]\
|
style[nobg,nobg:hovered,nobg:focused,nobg:hovered+focused;border=false;bgimg="..default_textures.."blank.png;bgimg_middle=0]\
|
||||||
")
|
")
|
||||||
|
|
||||||
-- Prepended to the meta menu's formspec.
|
|
||||||
local meta_header = "formspec_version[8]\
|
local meta_header = "formspec_version[8]\
|
||||||
size["..size.x..","..size.y.."]\
|
size["..size.x..","..size.y.."]\
|
||||||
padding[0,0]\
|
padding[0,0]\
|
||||||
|
|
@ -47,7 +45,6 @@ local meta_header = "formspec_version[8]\
|
||||||
"
|
"
|
||||||
-- box[0,0;"..size.x..","..size.y..";]\
|
-- box[0,0;"..size.x..","..size.y..";]\
|
||||||
|
|
||||||
-- Prepended to game menus' formspecs.
|
|
||||||
local game_header = "formspec_version[8]\
|
local game_header = "formspec_version[8]\
|
||||||
size["..size.x..","..size.y.."]\
|
size["..size.x..","..size.y.."]\
|
||||||
padding[0,0]\
|
padding[0,0]\
|
||||||
|
|
@ -65,16 +62,20 @@ local content_header = "formspec_version[8]\
|
||||||
bgcolor[#0000;true;#151618]\
|
bgcolor[#0000;true;#151618]\
|
||||||
"
|
"
|
||||||
|
|
||||||
-- The default main menu for games.
|
|
||||||
local default_game_menu = [[
|
local default_game_menu = [[
|
||||||
<meta>
|
<meta>
|
||||||
enable_clouds = true
|
enable_clouds = true
|
||||||
</meta>
|
</meta>
|
||||||
<main>
|
<main>
|
||||||
@set:test:Hello
|
@if:@selected_world:fi2
|
||||||
label[2,2;Test]
|
@set:list_width:@WIDTH * 0.3
|
||||||
scroll_container[1,6;4,2;worldscroll;vertical;;0,0]
|
@else:fi2
|
||||||
@foreach:$WORLDS:worlds
|
@set:list_width:@WIDTH * 0.8
|
||||||
|
@endif:fi2
|
||||||
|
|
||||||
|
image[${@WIDTH * 0.1 +-0.1},${@HEIGHT * 0.1 +-0.1};${@WIDTH * 0.8 + 0.2},${@HEIGHT * 0.8 + 0.2};$DEFAULT_ASSET_PATH/bg_translucent.png;8,8]
|
||||||
|
scroll_container[${@WIDTH * 0.1},${@HEIGHT * 0.1};${@list_width},${@HEIGHT * 0.8};worldscroll;vertical;;0,0]
|
||||||
|
@foreach:@WORLDS:worlds
|
||||||
@if:@i % 2:sel
|
@if:@i % 2:sel
|
||||||
style[.select_world_${@name};bgimg=$DEFAULT_ASSET_PATH/white.png;bgimg_middle=0;bgcolor=#373530]
|
style[.select_world_${@name};bgimg=$DEFAULT_ASSET_PATH/white.png;bgimg_middle=0;bgcolor=#373530]
|
||||||
style[.select_world_${@name}:hovered;bgimg=$DEFAULT_ASSET_PATH/white.png;bgimg_middle=0;bgcolor=#373530]
|
style[.select_world_${@name}:hovered;bgimg=$DEFAULT_ASSET_PATH/white.png;bgimg_middle=0;bgcolor=#373530]
|
||||||
|
|
@ -84,9 +85,21 @@ local default_game_menu = [[
|
||||||
style[.select_world_${@name}:hovered;bgimg=$DEFAULT_ASSET_PATH/white.png;bgimg_middle=0;bgcolor=#403e39]
|
style[.select_world_${@name}:hovered;bgimg=$DEFAULT_ASSET_PATH/white.png;bgimg_middle=0;bgcolor=#403e39]
|
||||||
style[.select_world_${@name}:hovered+focused;bgimg=$DEFAULT_ASSET_PATH/white.png;bgimg_middle=0;bgcolor=#403e39]
|
style[.select_world_${@name}:hovered+focused;bgimg=$DEFAULT_ASSET_PATH/white.png;bgimg_middle=0;bgcolor=#403e39]
|
||||||
@endif:sel
|
@endif:sel
|
||||||
button[0,${@i * 0.5};4,0.5;.select_world_${@name};${@test}]
|
button[0,${(@i +-1) * 0.5};${@list_width},0.5;.select_world_${@name};${@name}]
|
||||||
@endforeach:worlds
|
@endforeach:worlds
|
||||||
scroll_container_end[]
|
scroll_container_end[]
|
||||||
|
|
||||||
|
@if:@selected_world:fi
|
||||||
|
box[${@WIDTH * 0.4 +-0.05},${@HEIGHT * 0.1};0.1,${@HEIGHT * 0.8};#292d2fff]
|
||||||
|
scroll_container[${@WIDTH * 0.4},${@HEIGHT * 0.1};${@WIDTH * 0.8},${@HEIGHT * 0.8};worldmodsscroll;vertical;;0,0]
|
||||||
|
@foreach:@WORLDMODS:wm
|
||||||
|
label[0,${@i};${@name}]
|
||||||
|
@endforeach:wm
|
||||||
|
scroll_container_end[]
|
||||||
|
scrollbar[-800,6;0,2;vertical;worldmodsscroll;]
|
||||||
|
@else:fi
|
||||||
|
|
||||||
|
@endif:fi
|
||||||
scrollbaroptions[arrows=hide]
|
scrollbaroptions[arrows=hide]
|
||||||
scrollbar[-800,6;0,2;vertical;worldscroll;]
|
scrollbar[-800,6;0,2;vertical;worldscroll;]
|
||||||
</main>
|
</main>
|
||||||
|
|
@ -117,11 +130,6 @@ end
|
||||||
minetest.async_event_handler = handle_job
|
minetest.async_event_handler = handle_job
|
||||||
|
|
||||||
function minetest.handle_async(func, parameter, callback)
|
function minetest.handle_async(func, parameter, callback)
|
||||||
-- Serialize function
|
|
||||||
local serialized_func = string.dump(func)
|
|
||||||
|
|
||||||
assert(serialized_func ~= nil)
|
|
||||||
|
|
||||||
-- Serialize parameters
|
-- Serialize parameters
|
||||||
local serialized_param = minetest.serialize(parameter)
|
local serialized_param = minetest.serialize(parameter)
|
||||||
|
|
||||||
|
|
@ -129,7 +137,7 @@ function minetest.handle_async(func, parameter, callback)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
local jobid = minetest.do_async_callback(serialized_func, serialized_param)
|
local jobid = minetest.do_async_callback(func, serialized_param)
|
||||||
|
|
||||||
minetest.async_jobs[jobid] = callback
|
minetest.async_jobs[jobid] = callback
|
||||||
|
|
||||||
|
|
@ -173,13 +181,44 @@ local function get_worlds_for_game(id)
|
||||||
local out = {}
|
local out = {}
|
||||||
for _, x in ipairs(minetest.get_worlds()) do
|
for _, x in ipairs(minetest.get_worlds()) do
|
||||||
if x.gameid == id then
|
if x.gameid == id then
|
||||||
if math.random() > 0.5 then x.selected = true end
|
|
||||||
out[#out +1] = x
|
out[#out +1] = x
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return out
|
return out
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function get_mods_for_game(id)
|
||||||
|
local out = {}
|
||||||
|
for _, x in ipairs(get_all_mods()) do
|
||||||
|
local conf = Settings(x.path.."mod.conf")
|
||||||
|
local unsupported_games = conf:get("unsupported_games")
|
||||||
|
if unsupported_games then
|
||||||
|
if table.indexof(unsupported_games:trim():split(","), id) == -1 then
|
||||||
|
out[#out +1] = x
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local supported_games = conf:get("supported_games")
|
||||||
|
if supported_games then
|
||||||
|
if table.indexof(supported_games:trim():split(","), id) ~= -1 then
|
||||||
|
out[#out +1] = x
|
||||||
|
end
|
||||||
|
else
|
||||||
|
out[#out +1] = x
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return out
|
||||||
|
end
|
||||||
|
|
||||||
|
function get_mods_for_world(world)
|
||||||
|
local config = minetest.check_mod_configuration(world)
|
||||||
|
for _, x in ipairs(config.unsatisfied_mods) do
|
||||||
|
x.unsatisfied = true
|
||||||
|
config.satisfied_mods[#config.satisfied_mods +1] = x
|
||||||
|
end
|
||||||
|
return config.satisfied_mods
|
||||||
|
end
|
||||||
|
|
||||||
-- Returns a list of content available for download.
|
-- Returns a list of content available for download.
|
||||||
function get_available_content()
|
function get_available_content()
|
||||||
local version = minetest.get_version()
|
local version = minetest.get_version()
|
||||||
|
|
@ -357,6 +396,10 @@ will define a dialog named 'main', with a label in it, and a dialog named 'other
|
||||||
with a button in it. Every menu file must have a dialog named 'main', which serves
|
with a button in it. Every menu file must have a dialog named 'main', which serves
|
||||||
as the entry point of the game's menu.
|
as the entry point of the game's menu.
|
||||||
|
|
||||||
|
Note that to prevent dialog definitions from conflicting with the contents of
|
||||||
|
hypertext[] elements, they must not have leading whitespace before the opening
|
||||||
|
delimiter.
|
||||||
|
|
||||||
Being able to define these other dialogs would be pretty pointless if they couldn't
|
Being able to define these other dialogs would be pretty pointless if they couldn't
|
||||||
be used for anything. Accordingly, you can use standard formspec actions, e.g. buttons,
|
be used for anything. Accordingly, you can use standard formspec actions, e.g. buttons,
|
||||||
to segue to a different dialog. To do this, set the action name to
|
to segue to a different dialog. To do this, set the action name to
|
||||||
|
|
@ -393,9 +436,13 @@ file's top-level object will correspond to a variable. (Note that variable names
|
||||||
only contain letters or numbers, even if mapped from a JSON file.)
|
only contain letters or numbers, even if mapped from a JSON file.)
|
||||||
|
|
||||||
The menu-provided lists are:
|
The menu-provided lists are:
|
||||||
- $WORLDS: The list of worlds for this game. Exposes @name (the world name),
|
- @WORLDS: The list of worlds for this game. Exposes @name (the world name),
|
||||||
@path (the world's full absolute path), @gameid (the ID of the current game),
|
@path (the world's full absolute path), @gameid (the ID of the current game),
|
||||||
and @selected (whether the world is currently selected).
|
and @selected (whether the world is currently selected).
|
||||||
|
- @MODS: The list of installed mods that are not incompatible with this game.
|
||||||
|
Exposes @name, @title, @description, @author, @path, @depends, and @optional_depends.
|
||||||
|
- @WORLDMODS: The list of mods installed on the current world. No-op if no world
|
||||||
|
is selected.
|
||||||
|
|
||||||
Expressions also support rudimentary mathematical operations, namely addition (+),
|
Expressions also support rudimentary mathematical operations, namely addition (+),
|
||||||
subtraction (+-), multiplication (*), division (/), and exponentiation (^). Trying
|
subtraction (+-), multiplication (*), division (/), and exponentiation (^). Trying
|
||||||
|
|
@ -436,6 +483,12 @@ Example:
|
||||||
@endif:<name>
|
@endif:<name>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
- The only uniqueness requirements for the name of a block is that it not be
|
||||||
|
the name of a statment of the same type contained in the body of that block.
|
||||||
|
This is so that the parser knows which `end` belongs to which block without
|
||||||
|
having to manage state.
|
||||||
|
|
||||||
Note: Because of the way the main menu works, image paths must be specified in full.
|
Note: Because of the way the main menu works, image paths must be specified in full.
|
||||||
To make this non-painful, when referencing images use '$ASSET_PATH/<image name>'
|
To make this non-painful, when referencing images use '$ASSET_PATH/<image name>'
|
||||||
instead of just the image name. $ASSET_PATH will be replaced with the actual path
|
instead of just the image name. $ASSET_PATH will be replaced with the actual path
|
||||||
|
|
@ -444,7 +497,7 @@ there. You can use $ASSET_PATH in any context. Additionally, $DEFAULT_ASSET_PATH
|
||||||
the path to the builtin assets folder, and $NO_IMAGE is the path to blank.png, in
|
the path to the builtin assets folder, and $NO_IMAGE is the path to blank.png, in
|
||||||
case you need to stylistically unset a background image defined by a global style.
|
case you need to stylistically unset a background image defined by a global style.
|
||||||
--]]
|
--]]
|
||||||
local function build_template_dialog(fs)
|
local function build_template_dialog(fs, depth)
|
||||||
if fs:trim() == "" then return end
|
if fs:trim() == "" then return end
|
||||||
local dialog = {}
|
local dialog = {}
|
||||||
local i = 0
|
local i = 0
|
||||||
|
|
@ -452,41 +505,42 @@ local function build_template_dialog(fs)
|
||||||
-- Extract foreach loops
|
-- Extract foreach loops
|
||||||
local prev = 1
|
local prev = 1
|
||||||
while i < 1000 do
|
while i < 1000 do
|
||||||
|
local unfound = 0
|
||||||
local a, b, pattern, name, content = fs:find("@foreach:([^:]+):(%w*)\n(.-)\n%s-@endforeach:%2", prev)
|
local a, b, pattern, name, content = fs:find("@foreach:([^:]+):(%w*)\n(.-)\n%s-@endforeach:%2", prev)
|
||||||
if not a then break end
|
-- print(string.rep("-", 20)..(depth or 0))
|
||||||
|
if a then
|
||||||
-- print("for each "..pattern.." ("..name..")\n"..content.."\nend for each ("..name..")")
|
-- print("for each "..pattern.." ("..name..")\n"..content.."\nend for each ("..name..")")
|
||||||
dialog[#dialog +1] = build_template_dialog(fs:sub(prev +1, a -1))
|
dialog[#dialog +1] = build_template_dialog(fs:sub(prev, a -1), (depth or 0) +1)
|
||||||
dialog[#dialog +1] = {
|
dialog[#dialog +1] = {
|
||||||
foreach = pattern:trim(),
|
foreach = pattern:trim(),
|
||||||
name = name,
|
name = name,
|
||||||
content = build_template_dialog(content:trim())
|
content = build_template_dialog(content:trim(), (depth or 0) +1)
|
||||||
}
|
}
|
||||||
prev = b
|
prev = b
|
||||||
i = i +1
|
i = i +1
|
||||||
end
|
|
||||||
|
|
||||||
if i > 0 then
|
|
||||||
dialog[#dialog +1] = build_template_dialog(fs:sub(prev +1))
|
|
||||||
else
|
else
|
||||||
-- Extract conditionals
|
unfound = unfound +1
|
||||||
prev = 0
|
end
|
||||||
while i < 1000 do
|
|
||||||
local a, b, expr, name, content, else_content = fs:find("@if:([^:]+):(%w*)\n(.-)\n%s-@else:%2\n(.-\n?)@endif:%2", prev)
|
local a, b, expr, name, content, else_content = fs:find("@if:([^:]+):(%w*)\n(.-)\n%s-@else:%2\n(.-\n?)@endif:%2", prev)
|
||||||
if not a then break end
|
if a then
|
||||||
-- print("for each "..pattern.." ("..name..")\n"..content.."\nend for each ("..name..")")
|
-- print("if "..expr.." ("..name..")\n"..content.."\nend if ("..name..")")
|
||||||
dialog[#dialog +1] = fs:sub(prev +1, a -1)
|
dialog[#dialog +1] = build_template_dialog(fs:sub(prev +1, a -1), (depth or 0) +1)
|
||||||
dialog[#dialog +1] = {
|
dialog[#dialog +1] = {
|
||||||
condition = expr:trim(),
|
condition = expr:trim(),
|
||||||
name = name,
|
name = name,
|
||||||
content = build_template_dialog(content:trim()),
|
content = build_template_dialog(content:trim(), (depth or 0) +1),
|
||||||
else_content = build_template_dialog(else_content:trim())
|
else_content = build_template_dialog(else_content:trim(), (depth or 0) +1)
|
||||||
}
|
}
|
||||||
prev = b
|
prev = b
|
||||||
i = i +1
|
i = i +1
|
||||||
|
else
|
||||||
|
unfound = unfound +1
|
||||||
end
|
end
|
||||||
if i > 0 then
|
if unfound > 1 then break end
|
||||||
dialog[#dialog +1] = fs:sub(prev +1)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if prev > 1 then
|
||||||
|
dialog[#dialog +1] = build_template_dialog(fs:sub(prev +1))
|
||||||
end
|
end
|
||||||
|
|
||||||
if #dialog == 1 then dialog = dialog[1] end
|
if #dialog == 1 then dialog = dialog[1] end
|
||||||
|
|
@ -497,19 +551,20 @@ end
|
||||||
|
|
||||||
local function build_game_menu(input)
|
local function build_game_menu(input)
|
||||||
-- MARK: Environment variables
|
-- MARK: Environment variables
|
||||||
input = input
|
input = "\n"..input
|
||||||
:gsub("%$ASSET_PATH", fe(state.current_game.path.."/menu"))
|
:gsub("%$ASSET_PATH", fe(state.current_game.path.."/menu"))
|
||||||
:gsub("%$DEFAULT_ASSET_PATH", fe(assets:sub(1, #assets -1)))
|
:gsub("%$DEFAULT_ASSET_PATH", fe(assets:sub(1, #assets -1)))
|
||||||
:gsub("%$NO_IMAGE", fe(default_textures.."blank.png"))
|
:gsub("%$NO_IMAGE", fe(default_textures.."blank.png"))
|
||||||
:gsub("/%*.-%*/", "")
|
:gsub("/%*.-%*/", "")
|
||||||
local menu = {}
|
local menu = {}
|
||||||
for name, fs in input:gmatch("<(%l+)>(.-)</%1>") do
|
for name, fs in input:gmatch("%f[^\n]<(%l+)>(.-)%f[^\n]</%1>") do
|
||||||
if name == "meta" then
|
if name == "meta" then
|
||||||
menu[name] = parse_conf_text(fs)
|
menu[name] = parse_conf_text(fs)
|
||||||
else
|
else
|
||||||
menu[name] = build_template_dialog(fs)
|
menu[name] = build_template_dialog(fs)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
-- print(dump(menu, " "))
|
||||||
return menu
|
return menu
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -629,13 +684,25 @@ local function evaluate_template_expression(expr, vars, depth)
|
||||||
-- Expand all variables so we can deal with a constexpr.
|
-- Expand all variables so we can deal with a constexpr.
|
||||||
local offset = 1
|
local offset = 1
|
||||||
while offset < 100000 do
|
while offset < 100000 do
|
||||||
local a, b, name = expr:find("@([%a]+)", offset)
|
local a, b, name = expr:find("@([%a_]+)", offset)
|
||||||
if not a then break end
|
if not a then break end
|
||||||
-- If referencing an undefined variable, default to 0 because it's safest that way.
|
-- If referencing an undefined variable, default to 0 because it's safest that way.
|
||||||
local result = minetest.formspec_escape(tostring(vars[name] or "0"))
|
local result = minetest.formspec_escape(tostring(vars[name] or "0"))
|
||||||
expr = expr:sub(1, a -1)..result..expr:sub(b +1)
|
expr = expr:sub(1, a -1)..result..expr:sub(b +1)
|
||||||
offset = a +#result
|
offset = a +#result
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Condense sub-expressions.
|
||||||
|
local offset = 1
|
||||||
|
while offset < 100000 do
|
||||||
|
local a, b, se = expr:find("(%b())", offset)
|
||||||
|
if not a then break end
|
||||||
|
se = se:gsub("^%((.*)%)$", "%1")
|
||||||
|
local result = evaluate_template_expression(se, vars, depth +1)
|
||||||
|
expr = expr:sub(1, a -1)..result..expr:sub(b +1)
|
||||||
|
offset = a +#result
|
||||||
|
end
|
||||||
|
|
||||||
-- If there are no operators, this is a constant expression and we can just return.
|
-- If there are no operators, this is a constant expression and we can just return.
|
||||||
if not expr:find("%p") then return expr end
|
if not expr:find("%p") then return expr end
|
||||||
|
|
||||||
|
|
@ -649,7 +716,7 @@ local function evaluate_template_block(fs, vars)
|
||||||
-- Assignment statements
|
-- Assignment statements
|
||||||
local offset = 1
|
local offset = 1
|
||||||
while offset < #fs do
|
while offset < #fs do
|
||||||
local a, b, name, expr = fs:find("@set:(%w+):(.-)\n", offset)
|
local a, b, name, expr = fs:find("@set:([%a_]+):([^\n]+)", offset)
|
||||||
if not a then break end
|
if not a then break end
|
||||||
vars[name] = evaluate_template_expression(expr, vars)
|
vars[name] = evaluate_template_expression(expr, vars)
|
||||||
fs = fs:sub(1, a -1)..fs:sub(b +1)
|
fs = fs:sub(1, a -1)..fs:sub(b +1)
|
||||||
|
|
@ -673,8 +740,17 @@ local function evaluate_template_foreach(loop, vars)
|
||||||
local list = {}
|
local list = {}
|
||||||
if loop.foreach:sub(1,1) == "[" then
|
if loop.foreach:sub(1,1) == "[" then
|
||||||
list = loop.foreach:gsub("^%[(.*)%]$", "%1"):split(",")
|
list = loop.foreach:gsub("^%[(.*)%]$", "%1"):split(",")
|
||||||
elseif loop.foreach == "$WORLDS" then
|
elseif loop.foreach:sub(1, 1) == "@" then
|
||||||
|
local var = loop.foreach:sub(2)
|
||||||
|
if var == "WORLDS" then
|
||||||
list = get_worlds_for_game(state.current_game.id)
|
list = get_worlds_for_game(state.current_game.id)
|
||||||
|
elseif var == "MODS" then
|
||||||
|
list = get_mods_for_game(state.current_game.id)
|
||||||
|
elseif var == "WORLDMODS" then
|
||||||
|
list = state.current_world and get_mods_for_world(state.current_world) or {}
|
||||||
|
else
|
||||||
|
list = vars[var]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
for i, x in ipairs(list) do
|
for i, x in ipairs(list) do
|
||||||
local vars2 = {}
|
local vars2 = {}
|
||||||
|
|
@ -704,23 +780,21 @@ local function evaluate_template_conditional(cond, vars)
|
||||||
return out
|
return out
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Game dialogs might contain e.g. foreach loops, so build those if needed.
|
-- Process the syntax tree for a game dialog and output the resulting string.
|
||||||
function evaluate_game_dialog(dialog, vars)
|
function evaluate_game_dialog(dialog, vars)
|
||||||
local out = ""
|
local out = ""
|
||||||
if type(dialog) == "string" then return evaluate_template_block(dialog, vars) end
|
if not dialog then return out end
|
||||||
for _, x in ipairs(dialog) do
|
if type(dialog) == "string" then
|
||||||
if type(x) == "string" then
|
return evaluate_template_block(dialog, vars)
|
||||||
out = out..evaluate_template_block(x, vars)
|
elseif dialog.condition then
|
||||||
elseif x.condition then
|
out = out..evaluate_template_conditional(dialog, vars)
|
||||||
out = out..evaluate_template_conditional(x, vars)
|
elseif dialog.foreach then
|
||||||
elseif x.foreach then
|
out = out..evaluate_template_foreach(dialog, vars)
|
||||||
out = out..evaluate_template_foreach(x, vars)
|
|
||||||
else
|
else
|
||||||
for _, c in ipairs(x) do
|
for _, c in ipairs(dialog) do
|
||||||
out = out..evaluate_game_dialog(c, vars)
|
out = out..evaluate_game_dialog(c, vars)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
return out
|
return out
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -763,12 +837,9 @@ function show_meta_menu(v)
|
||||||
local dist = i -idx
|
local dist = i -idx
|
||||||
local scale = 4 /(math.abs(dist) +1)
|
local scale = 4 /(math.abs(dist) +1)
|
||||||
if scale > 0.1 then
|
if scale > 0.1 then
|
||||||
--This looks cool, but is useless for UI purposes: center +10^(1 /math.abs(dist)) *math.sign(dist)
|
--This looks neat, but is useless for UI purposes: center +10^(1 /math.abs(dist)) *math.sign(dist)
|
||||||
local lc = center +math.abs(dist *10)^0.55 *math.sign(dist)
|
local lc = center +math.abs(dist *10)^0.55 *math.sign(dist)
|
||||||
local test = io.open(x.menuicon_path)
|
if x.menuicon_path == "" then
|
||||||
if test then
|
|
||||||
test:close()
|
|
||||||
else
|
|
||||||
x.menuicon_path = assets.."games.png"
|
x.menuicon_path = assets.."games.png"
|
||||||
end
|
end
|
||||||
--TODO: Do these need some kind of background?
|
--TODO: Do these need some kind of background?
|
||||||
|
|
@ -898,6 +969,7 @@ function show_game_menu(args)
|
||||||
for i, x in ipairs(state.menu_current) do
|
for i, x in ipairs(state.menu_current) do
|
||||||
fs = fs..evaluate_game_dialog(game.menu[x], setmetatable({WIDTH = size.x, HEIGHT = size.y}, {__index = state.menu_vars}))
|
fs = fs..evaluate_game_dialog(game.menu[x], setmetatable({WIDTH = size.x, HEIGHT = size.y}, {__index = state.menu_vars}))
|
||||||
end
|
end
|
||||||
|
-- print(fs)
|
||||||
|
|
||||||
minetest.update_formspec(game_header..fs.."\
|
minetest.update_formspec(game_header..fs.."\
|
||||||
button[0,"..(size.y -1)..";1,1;to_meta_menu;<]\
|
button[0,"..(size.y -1)..";1,1;to_meta_menu;<]\
|
||||||
|
|
@ -912,6 +984,23 @@ function add_favorite_server(address, port)
|
||||||
f:close()
|
f:close()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function remove_favorite_server(address, port)
|
||||||
|
local idx
|
||||||
|
for i, x in pairs(state.favorite_servers) do
|
||||||
|
if x.address == address and x.port == port then
|
||||||
|
idx = i
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if idx then
|
||||||
|
table.remove(state.favorite_servers, idx)
|
||||||
|
local f = io.open(minetest.get_user_path().."/client/serverlist/favoriteservers.json", "w")
|
||||||
|
f:write(minetest.write_json(state.favorite_servers))
|
||||||
|
f:flush()
|
||||||
|
f:close()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function refresh_server_list()
|
function refresh_server_list()
|
||||||
minetest.handle_async(
|
minetest.handle_async(
|
||||||
function(param)
|
function(param)
|
||||||
|
|
@ -934,6 +1023,9 @@ function refresh_server_list()
|
||||||
local list = table.copy(state.favorite_servers)
|
local list = table.copy(state.favorite_servers)
|
||||||
table.insert_all(list, result)
|
table.insert_all(list, result)
|
||||||
state.serverlist = list
|
state.serverlist = list
|
||||||
|
if state.serverlist_filtered then
|
||||||
|
state.serverlist_filtered = search_server_list(state.servers_filter)
|
||||||
|
end
|
||||||
if state.loc == "servers" then
|
if state.loc == "servers" then
|
||||||
show_servers_menu()
|
show_servers_menu()
|
||||||
end
|
end
|
||||||
|
|
@ -1363,15 +1455,18 @@ function show_content_menu()
|
||||||
fs = fs.."\
|
fs = fs.."\
|
||||||
box[0,0;"..size.x..",1;#403e39ff]\
|
box[0,0;"..size.x..",1;#403e39ff]\
|
||||||
box[0,1;"..size.x..",0.1;#292d2fff]\
|
box[0,1;"..size.x..",0.1;#292d2fff]\
|
||||||
style[content_search,content_cancel;bgimg="..assets.."btn_bg_2.png;bgimg_middle=8,8]\
|
style[content_search,content_cancel;bgimg="..assets.."btn_bg_2_dark.png;bgimg_middle=8,8]\
|
||||||
image_button[0.125,0.125;0.75,0.75;"..assets.."search.png;content_search;]\
|
image_button[0.125,0.125;0.75,0.75;"..assets.."search.png;content_search;]\
|
||||||
|
tooltip[content_search;Search;#444;#aaa]\
|
||||||
image_button[1,0.125;0.75,0.75;"..assets.."cancel.png;content_cancel;]\
|
image_button[1,0.125;0.75,0.75;"..assets.."cancel.png;content_cancel;]\
|
||||||
|
tooltip[content_cancel;Cancel;#444;#aaa]\
|
||||||
style[test;bgimg="..assets.."white.png;bgimg_middle=0;bgcolor=#403e39ff]\
|
style[test;bgimg="..assets.."white.png;bgimg_middle=0;bgcolor=#403e39ff]\
|
||||||
style[test:hovered;bgimg="..assets.."white.png;bgimg_middle=0]\
|
style[test:hovered;bgimg="..assets.."white.png;bgimg_middle=0]\
|
||||||
image[2,0.125;"..(size.x -9)..",0.75;"..assets.."btn_bg_2_light.png;8,8]\
|
image[2,0.125;"..(size.x -9)..",0.75;"..assets.."btn_bg_2_light.png;8,8]\
|
||||||
field[2.1,0.125;"..(size.x -9.2)..",0.75;content_filter;;]\
|
field[2.1,0.125;"..(size.x -9.2)..",0.75;content_filter;;]\
|
||||||
button["..(w -7)..",0;4,1;test;Browse Online Content...]\
|
button["..(w -6)..",0;4,1;test;Browse Online Content...]\
|
||||||
button["..(w -3)..",0;3,1;test;Add Content...]\
|
image_button["..(w -1.5)..",0.125;0.75,0.75;"..assets.."new_package.png;new_package;]\
|
||||||
|
tooltip[new_package;New Package...;#444;#aaa]\
|
||||||
"
|
"
|
||||||
|
|
||||||
local start = w /2 -(pages *0.125)
|
local start = w /2 -(pages *0.125)
|
||||||
|
|
@ -1392,7 +1487,8 @@ function show_content_menu()
|
||||||
end
|
end
|
||||||
|
|
||||||
function minetest.button_handler(data)
|
function minetest.button_handler(data)
|
||||||
state.menu_vars = data
|
if not state.menu_vars then state.menu_vars = {} end
|
||||||
|
setmetatable(state.menu_vars, {__index = data})
|
||||||
if state.loc == "games" then
|
if state.loc == "games" then
|
||||||
if data.content or data.ht == "action:content" then
|
if data.content or data.ht == "action:content" then
|
||||||
if state.loc ~= "content" then show_content() end
|
if state.loc ~= "content" then show_content() end
|
||||||
|
|
@ -1422,11 +1518,16 @@ function minetest.button_handler(data)
|
||||||
if data.servers_refresh then
|
if data.servers_refresh then
|
||||||
refresh_server_list()
|
refresh_server_list()
|
||||||
elseif data.servers_search or data.key_enter_field == "servers_filter" then
|
elseif data.servers_search or data.key_enter_field == "servers_filter" then
|
||||||
|
state.servers_filter = data.servers_filter
|
||||||
state.serverlist_filtered = search_server_list(data.servers_filter)
|
state.serverlist_filtered = search_server_list(data.servers_filter)
|
||||||
show_servers_menu()
|
show_servers_menu()
|
||||||
elseif data.servers_cancel then
|
elseif data.servers_cancel then
|
||||||
state.serverlist_filtered = nil
|
state.serverlist_filtered = nil
|
||||||
show_servers_menu()
|
show_servers_menu()
|
||||||
|
elseif data.unfavorite_server then
|
||||||
|
state.current_server.favorite = nil
|
||||||
|
remove_favorite_server(state.current_server.address, state.current_server.port)
|
||||||
|
show_servers_menu()
|
||||||
elseif data.show_server_mods then
|
elseif data.show_server_mods then
|
||||||
state.showing_server_mods = true
|
state.showing_server_mods = true
|
||||||
show_servers_menu()
|
show_servers_menu()
|
||||||
|
|
@ -1449,6 +1550,9 @@ function minetest.button_handler(data)
|
||||||
show_servers_menu()
|
show_servers_menu()
|
||||||
elseif data.confirm_join_server or data.key_enter_field == "server_username" or data.key_enter_field == "server_password" or data.key_enter_field == "server_address" then
|
elseif data.confirm_join_server or data.key_enter_field == "server_username" or data.key_enter_field == "server_password" or data.key_enter_field == "server_address" then
|
||||||
minetest.settings:set("name", data.server_username)
|
minetest.settings:set("name", data.server_username)
|
||||||
|
local address
|
||||||
|
local port
|
||||||
|
if state.connecting_to_server then
|
||||||
if not tonumber(data.server_port) then
|
if not tonumber(data.server_port) then
|
||||||
state.server_connection_error = {
|
state.server_connection_error = {
|
||||||
msg = "Invalid port.",
|
msg = "Invalid port.",
|
||||||
|
|
@ -1458,14 +1562,11 @@ function minetest.button_handler(data)
|
||||||
state.server_connection_error = nil
|
state.server_connection_error = nil
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local address
|
|
||||||
local port
|
|
||||||
if state.connecting_to_server then
|
|
||||||
address = data.server_address:lower()
|
address = data.server_address:lower()
|
||||||
port = data.server_port:lower()
|
port = data.server_port:lower()
|
||||||
else
|
else
|
||||||
address = state.current_server.address:lower()
|
address = state.current_server.address:lower()
|
||||||
port = state.current_server.port:lower()
|
port = state.current_server.port
|
||||||
end
|
end
|
||||||
local is_favorite = false
|
local is_favorite = false
|
||||||
for _, x in ipairs(state.favorite_servers) do
|
for _, x in ipairs(state.favorite_servers) do
|
||||||
|
|
@ -1523,10 +1624,17 @@ function minetest.button_handler(data)
|
||||||
show_game_menu {
|
show_game_menu {
|
||||||
overlay_dialog = k:sub(string.len(".overlay_dialog_>"))
|
overlay_dialog = k:sub(string.len(".overlay_dialog_>"))
|
||||||
}
|
}
|
||||||
|
elseif k:sub(1, string.len(".select_world_")) == ".select_world_" then
|
||||||
|
state.menu_vars.selected_world = k:sub(string.len(".select_world_>"))
|
||||||
|
show_game_menu()
|
||||||
elseif k == ".unoverlay_dialog" then
|
elseif k == ".unoverlay_dialog" then
|
||||||
show_game_menu {
|
show_game_menu {
|
||||||
unoverlay_dialog = true
|
unoverlay_dialog = true
|
||||||
}
|
}
|
||||||
|
elseif k:sub(1, string.len(".set_")) == ".set_" then
|
||||||
|
local name, value = k:match "%.set_(.-)_to_(.*)"
|
||||||
|
state.menu_vars[name] = value == "" and "0" or value
|
||||||
|
show_game_menu()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue