diff --git a/API.md b/API.md index 24de94b..d062769 100644 --- a/API.md +++ b/API.md @@ -301,6 +301,14 @@ A map of all compressed item groups, indexed by stereotypes. ### Miscellaneous +#### `i3.hud_notif(name, msg[, img])` + +Shows a Steam-like HUD notification on the bottom-right corner of the screen (experimental). + +- `name` is the player name. +- `msg` is the HUD message to show. +- `img` (optional) is the HUD image to show (preferably 16x16 px). + #### `i3.get_recipes(item)` Returns a table of recipes and usages of `item`. diff --git a/init.lua b/init.lua index 9dc5055..6f57912 100644 --- a/init.lua +++ b/init.lua @@ -16,6 +16,9 @@ i3 = { MIN_FORMSPEC_VERSION = 4, SAVE_INTERVAL = 600, -- Player data save interval (in seconds) + HUD_TIMER_MAX = 1.5, + HUD_SPEED = 1, + SUBCAT = { "bag", "armor", @@ -57,6 +60,7 @@ i3 = { detached = lf("/src/detached_inv.lua"), groups = lf("/src/groups.lua"), gui = lf("/src/gui.lua"), + hud = lf("/src/hud.lua"), model_alias = lf("/src/model_aliases.lua"), progressive = lf("/src/progressive.lua"), styles = lf("/src/styles.lua"), @@ -82,6 +86,7 @@ i3.data = dslz(storage:get_string"data") or {} local init_bags = i3.files.bags() local init_inventories = i3.files.detached() local fill_caches = i3.files.caches() +local init_hud = i3.files.hud() local function get_lang_code(info) return info and info.lang_code @@ -183,13 +188,6 @@ local function init_waypoints(player) end end -local function init_hudbar(player) - core.after(0, function() - player:hud_set_hotbar_itemcount(i3.HOTBAR_LEN) - player:hud_set_hotbar_image"i3_hotbar.png" - end) -end - local function save_data(player_name) local _data = copy(i3.data) @@ -225,7 +223,7 @@ core.register_on_joinplayer(function(player) init_bags(player) init_inventories(player) init_waypoints(player) - init_hudbar(player) + init_hud(player) end) core.register_on_leaveplayer(function(player) diff --git a/src/api.lua b/src/api.lua index 685db0b..59c42ed 100644 --- a/src/api.lua +++ b/src/api.lua @@ -298,6 +298,27 @@ function i3.compress(item, def) end end +function i3.hud_notif(name, msg, img) + if not true_str(name) then + return err "i3.hud_notif: player name missing" + elseif not true_str(msg) then + return err "i3.hud_notif: message missing" + end + + local data = i3.data[name] + + if not data then + return err "i3.hud_notif: no player data initialized" + end + + data.show_hud = true + data.hud_msg = msg + + if img then + data.hud_img = fmt("%s^[resize:16x16", img) + end +end + function i3.add_sorting_method(name, def) if not true_str(name) then return err "i3.add_sorting_method: name missing" diff --git a/src/common.lua b/src/common.lua index 3345092..38b7b0a 100644 --- a/src/common.lua +++ b/src/common.lua @@ -410,10 +410,12 @@ local function safe_teleport(player, pos) local name = player:get_player_name() play_sound(name, "i3_teleport", 0.8) - local p = vec_new(pos) - p.y = p.y + 0.25 local vel = player:get_velocity() player:add_velocity(vec_mul(vel, -1)) + + local p = vec_new(pos) + p.y = p.y + 0.25 + player:set_pos(p) end @@ -638,6 +640,7 @@ local _ = { pos_to_str = core.pos_to_string, str_to_pos = core.string_to_pos, check_privs = core.check_player_privs, + get_player_by_name = core.get_player_by_name, -- Inventory get_stack = get_stack, diff --git a/src/hud.lua b/src/hud.lua new file mode 100644 index 0000000..d05898d --- /dev/null +++ b/src/hud.lua @@ -0,0 +1,101 @@ +local get_player_by_name = i3.get("get_player_by_name") + +local function init_hud(player) + local name = player:get_player_name() + local data = i3.data[name] + + data.hud = { + bg = player:hud_add { + hud_elem_type = "image", + position = {x = 0.78, y = 1}, + alignment = {x = 1, y = 1}, + scale = {x = 370, y = 112}, + text = "i3_bg.png", + z_index = 0xDEAD, + }, + + img = player:hud_add { + hud_elem_type = "image", + position = {x = 0.79, y = 1.02}, + alignment = {x = 1, y = 1}, + scale = {x = 4, y = 4}, + text = "", + z_index = 0xDEAD, + }, + + text = player:hud_add { + hud_elem_type = "text", + position = {x = 0.84, y = 1.04}, + alignment = {x = 1, y = 1}, + number = 0xffffff, + text = "", + z_index = 0xDEAD, + style = 1, + }, + } + + core.after(0, function() + player:hud_set_hotbar_itemcount(i3.HOTBAR_LEN) + player:hud_set_hotbar_image"i3_hotbar.png" + end) +end + +local function show_hud(player, data) + -- It would better to have an engine function `hud_move` to only need + -- 2 calls for the notification's back and forth. + + local hud_info_bg = player:hud_get(data.hud.bg) + local dt = 0.016 + + if hud_info_bg.position.y <= 0.9 then + data.show_hud = false + data.hud_timer = (data.hud_timer or 0) + dt + end + + player:hud_change(data.hud.text, "text", data.hud_msg) + + if data.hud_img then + player:hud_change(data.hud.img, "text", data.hud_img) + end + + if data.show_hud then + for _, def in pairs(data.hud) do + local hud_info = player:hud_get(def) + + player:hud_change(def, "position", { + x = hud_info.position.x, + y = hud_info.position.y - ((dt / 5) * i3.HUD_SPEED) + }) + end + + elseif data.show_hud == false then + if data.hud_timer >= i3.HUD_TIMER_MAX then + for _, def in pairs(data.hud) do + local hud_info = player:hud_get(def) + + player:hud_change(def, "position", { + x = hud_info.position.x, + y = hud_info.position.y + ((dt / 5) * i3.HUD_SPEED) + }) + end + + if hud_info_bg.position.y >= 1 then + data.show_hud = nil + data.hud_timer = nil + data.hud_msg = nil + data.hud_img = nil + end + end + end +end + +core.register_globalstep(function() + for name, data in pairs(i3.data) do + if data.show_hud ~= nil then + local player = get_player_by_name(name) + show_hud(player, data) + end + end +end) + +return init_hud diff --git a/src/progressive.lua b/src/progressive.lua index 08d1758..d9860f0 100644 --- a/src/progressive.lua +++ b/src/progressive.lua @@ -1,14 +1,12 @@ -local singleplayer = core.is_singleplayer() - local set_fs = i3.set_fs +local hud_notif = i3.hud_notif + local fmt, search, table_merge, array_diff = i3.get("fmt", "search", "table_merge", "array_diff") local is_group, extract_groups, item_has_groups, apply_recipe_filters = i3.get("is_group", "extract_groups", "item_has_groups", "apply_recipe_filters") local POLL_FREQ = 0.25 -local HUD_TIMER_MAX = 1.5 -local HUD_SPEED = 1 local function get_filtered_items(player, data) local items, known, c = {}, 0, 0 @@ -118,85 +116,6 @@ local function get_inv_items(player) return inv_items end -local function init_hud(player, data) - data.hud = { - bg = player:hud_add { - hud_elem_type = "image", - position = {x = 0.78, y = 1}, - alignment = {x = 1, y = 1}, - scale = {x = 370, y = 112}, - text = "i3_bg.png", - z_index = 0xDEAD, - }, - - book = player:hud_add { - hud_elem_type = "image", - position = {x = 0.79, y = 1.02}, - alignment = {x = 1, y = 1}, - scale = {x = 4, y = 4}, - text = "i3_book.png", - z_index = 0xDEAD, - }, - - text = player:hud_add { - hud_elem_type = "text", - position = {x = 0.84, y = 1.04}, - alignment = {x = 1, y = 1}, - number = 0xffffff, - text = "", - z_index = 0xDEAD, - style = 1, - }, - } -end - -local function show_hud_success(player, data) - -- It'd better to have an engine function `hud_move` to only need - -- 2 calls for the notification's back and forth. - - local hud_info_bg = player:hud_get(data.hud.bg) - local dt = 0.016 - - if hud_info_bg.position.y <= 0.9 then - data.show_hud = false - data.hud_timer = (data.hud_timer or 0) + dt - end - - local discovered = data.tot_discovered or data.discovered - - player:hud_change(data.hud.text, "text", - fmt("%u new recipe%s unlocked!", discovered, discovered > 1 and "s" or "")) - - if data.show_hud then - for _, def in pairs(data.hud) do - local hud_info = player:hud_get(def) - - player:hud_change(def, "position", { - x = hud_info.position.x, - y = hud_info.position.y - ((dt / 5) * HUD_SPEED) - }) - end - - elseif data.show_hud == false then - if data.hud_timer >= HUD_TIMER_MAX then - for _, def in pairs(data.hud) do - local hud_info = player:hud_get(def) - - player:hud_change(def, "position", { - x = hud_info.position.x, - y = hud_info.position.y + ((dt / 5) * HUD_SPEED) - }) - end - - if hud_info_bg.position.y >= 1 then - data.show_hud = nil - data.hud_timer = nil - data.tot_discovered = nil - end - end - end -end - -- Workaround. Need an engine call to detect when the contents of -- the player inventory changed, instead. local function poll_new_items(player, data, join) @@ -210,11 +129,8 @@ local function poll_new_items(player, data, join) data.discovered = data.known_recipes - oldknown if data.discovered > 0 then - data.tot_discovered = (data.tot_discovered or 0) + data.discovered - - if data.show_hud == nil then - data.show_hud = true - end + local msg = fmt("%u new recipe%s unlocked!", data.discovered, data.discovered > 1 and "s" or "") + hud_notif(data.player_name, msg, "i3_book.png") end data.items_raw = items @@ -227,18 +143,6 @@ local function poll_new_items(player, data, join) core.after(POLL_FREQ, poll_new_items, player, data) end -if singleplayer then - core.register_globalstep(function() - local name = "singleplayer" - local player = core.get_player_by_name(name) - local data = i3.data[name] - - if data and data.show_hud ~= nil then - show_hud_success(player, data) - end - end) -end - i3.add_recipe_filter("Default progressive filter", progressive_filter) core.register_on_joinplayer(function(player) @@ -251,8 +155,4 @@ core.register_on_joinplayer(function(player) data.discovered = data.discovered or 0 poll_new_items(player, data, true) - - if singleplayer then - init_hud(player, data) - end end)