From 406defae022e1729c6faa8d6eec11e2d5af86bdc Mon Sep 17 00:00:00 2001 From: Jean-Patrick Guerrero Date: Fri, 22 Jan 2021 00:42:48 +0100 Subject: [PATCH] WIP bags --- init.lua | 340 ++++++++++++++++++++++++++----------- textures/i3_bag_large.png | Bin 0 -> 2634 bytes textures/i3_bag_medium.png | Bin 0 -> 2632 bytes textures/i3_bag_small.png | Bin 0 -> 2546 bytes 4 files changed, 239 insertions(+), 101 deletions(-) create mode 100644 textures/i3_bag_large.png create mode 100644 textures/i3_bag_medium.png create mode 100644 textures/i3_bag_small.png diff --git a/init.lua b/init.lua index 8b4cf6a..ca5216c 100644 --- a/init.lua +++ b/init.lua @@ -44,6 +44,7 @@ local slz, dslz = core.serialize, core.deserialize local on_mods_loaded = core.register_on_mods_loaded local on_leaveplayer = core.register_on_leaveplayer local get_player_info = core.get_player_information +local create_inventory = core.create_detached_inventory local on_receive_fields = core.register_on_player_receive_fields local ESC = core.formspec_escape @@ -73,12 +74,22 @@ local IPP = ROWS * LINES local MAX_FAVS = 6 local ITEM_BTN_SIZE = 1.1 +local INV_SIZE = 8*4 + -- Progressive mode local POLL_FREQ = 0.25 local HUD_TIMER_MAX = 1.5 local MIN_FORMSPEC_VERSION = 4 +local META_SAVES = {"bag_size", "skin_id"} + +local BAG_SIZES = { + small = INV_SIZE + 8, + medium = INV_SIZE + 16, + large = INV_SIZE + 24, +} + local PNG = { bg = "i3_bg.png", bg_full = "i3_bg_full.png", @@ -1093,6 +1104,15 @@ local function get_stack_max(inv, data, is_recipe, rcp) return max_stacks end +local function spawn_item(player, stack) + local dir = player:get_look_dir() + local ppos = player:get_pos() + ppos.y = ppos.y + 1.625 + local look_at = vec_add(ppos, vec_mul(dir, 1)) + + core.add_item(look_at, stack) +end + local function get_stack(player, pname, stack, message) local inv = player:get_inventory() @@ -1100,12 +1120,7 @@ local function get_stack(player, pname, stack, message) inv:add_item("main", stack) msg(pname, fmt("%s added in your inventory", message)) else - local dir = player:get_look_dir() - local ppos = player:get_pos() - ppos.y = ppos.y + 1.625 - local look_at = vec_add(ppos, vec_mul(dir, 1)) - - core.add_item(look_at, stack) + spawn_item(player, stack) msg(pname, fmt("%s spawned", message)) end end @@ -1647,7 +1662,7 @@ local function get_export_fs(fs, data, is_recipe, is_usage, max_stacks_rcp, max_ fmt("scrollbaroptions[min=1;max=%u;smallstep=1]", craft_max), fmt("scrollbar", data.xoffset + 8.1, data.yoffset, 3, 0.35, fmt("scrbar_%s", name), stack_fs), fmt("button", data.xoffset + 8.1, data.yoffset + 0.4, 3, 0.7, fmt("craft_%s", name), - fmt("%s", fmt(ES"Craft x %u", stack_fs)))) + fmt("%s", fmt(ES"Craft (x%u)", stack_fs)))) end local function get_rcp_extra(player, data, fs, panel, is_recipe, is_usage) @@ -1735,11 +1750,13 @@ local function get_panels(player, data, fs) end local function add_subtitle(fs, title, x, y, ctn_len, font_size) + font_size = font_size or "+2" + fs(fmt("style_type[label;font=bold;font_size=%s]", font_size), fmt("label", x, y, title), "style_type[label;font=normal;font_size=+0]", fmt("box", x, y + 0.3, ctn_len, 0.045, "#bababa50")) end -local function get_award_list(fs, ctn_len, yextra, award_list, awards_unlocked, award_list_nb) +local function get_award_list(data, fs, ctn_len, yextra, award_list, awards_unlocked, award_list_nb) if (__3darmor and __skinsdb) or __skinsdb then yextra = yextra + 1.8 elseif __3darmor then @@ -1749,7 +1766,7 @@ local function get_award_list(fs, ctn_len, yextra, award_list, awards_unlocked, local percent = fmt("%.1f%%", (awards_unlocked * 100) / award_list_nb):gsub(".0", "") add_subtitle(fs, fmt("%s: %u of %u (%s)", ES"Achievements", - awards_unlocked, award_list_nb, percent), 0, yextra, ctn_len, "+2") + awards_unlocked, award_list_nb, percent), 0, yextra, ctn_len) for i = 1, award_list_nb do local award = award_list[i] @@ -1836,15 +1853,18 @@ local function get_ctn_content(fs, data, player, xoffset, yoffset, ctn_len, awar local yextra = 5.6 - if __3darmor then - add_subtitle(fs, ES"Armor", 0, yextra, ctn_len, "+2") + add_subtitle(fs, ES"Backpack", 0, yextra, ctn_len) + fs(fmt("list[detached:%s_backpack;main;0,%f;1,1;]", ESC(name), yextra + 0.6)) - fs(fmt("list[detached:%s_armor;armor;0,%f;3,2;]", ESC(name), yextra + 0.6)) + if __3darmor then + add_subtitle(fs, ES"Armor", 0, yextra + 2.2, ctn_len) + + fs(fmt("list[detached:%s_armor;armor;0,%f;3,2;]", ESC(name), yextra + 2.8)) local armor_def = armor.def[name] - fs(fmt("label", 3.75, yextra + 1.55, fmt("%s: %s", ES"Level", armor_def.level)), - fmt("label", 3.75, yextra + 1.95, fmt("%s: %s", ES"Heal", armor_def.heal))) + fs(fmt("label", 3.75, yextra + 3.75, fmt("%s: %s", ES"Level", armor_def.level)), + fmt("label", 3.75, yextra + 4.25, fmt("%s: %s", ES"Heal", armor_def.heal))) end if __skinsdb then @@ -1855,16 +1875,16 @@ local function get_ctn_content(fs, data, player, xoffset, yoffset, ctn_len, awar t[#t + 1] = skin.name end - yextra = __3darmor and (yextra + 3.5) or yextra + yextra = __3darmor and (yextra + 5.7) or yextra + 2.2 - add_subtitle(fs, ES"Skins", 0, yextra, ctn_len, "+2") + add_subtitle(fs, ES"Skins", 0, yextra, ctn_len) fs(fmt("dropdown[0,%f;3.55,0.6;skins;%s;%u;true]", yextra + 0.6, concat(t, ","), data.skin_id or 1)) end if __awards then - get_award_list(fs, ctn_len, yextra, award_list, awards_unlocked, award_list_nb) + get_award_list(data, fs, ctn_len, yextra, award_list, awards_unlocked, award_list_nb) end end @@ -2008,8 +2028,8 @@ function i3.delete_tab(name) end end -local function init_data(player, name) - local info = get_player_info(name) +local function init_data(player, info) + local name = player:get_player_name() pdata[name] = { filter = "", @@ -2020,18 +2040,17 @@ local function init_data(player, name) export_counts = {}, current_tab = 1, lang_code = get_lang_code(info), - fs_version = get_formspec_version(info), } local data = pdata[name] + local meta = player:get_meta() + + data.bag_size = dslz(meta:get_string "bag_size") if __skinsdb then - local meta = player:get_meta() data.skin_id = tonum(dslz(meta:get_string "skin_id") or 1) end - if data.fs_version < MIN_FORMSPEC_VERSION then return end - after(0, set_fs, player) end @@ -2102,17 +2121,46 @@ local function panel_fields(player, data, fields) end end -local function get_inventory_fs(player, data, fs) +local function get_inv_slots(data, fs) local inv_x = 0.234 + local bag = data.bag_size - for i = 0, 7 do - fs(fmt("image", i + inv_x + (i * 0.25), 6.1, 1, 1, "i3_hb_bg.png")) + if bag then + local max_value = 38 + + if data.bag_size == "small" then + max_value = 12 + elseif data.bag_size == "medium" then + max_value = 25 + end + + fs(fmt([[ + scrollbaroptions[arrows=hide;thumbsize=6;max=%u] + scrollbar[-2,6.09;0.3,4.83;vertical;scrbar_inv2;] + scrollbaroptions[arrows=default;thumbsize=0;max=1000] + ]], max_value)) + + fs(fmt("scroll_container[%f,6.09;10,4.83;scrbar_inv2;vertical]", inv_x)) + inv_x = 0 end - fs("listcolors[#bababa50;#bababa99]", - "listring[current_player;main]", - fmt("list[current_player;main;%f,6.1;8,1;]", inv_x), - fmt("list[current_player;main;%f,7.4;8,3;8]", inv_x)) + for i = 0, 7 do + fs(fmt("image", i + inv_x + (i * 0.25), bag and 0 or 6.1, 1, 1, "i3_hb_bg.png")) + end + + fs(fmt("list[current_player;main;%f,%f;8,1;]", inv_x, bag and 0 or 6.1), + fmt("list[current_player;main;%f,%f;8,%u;8]", inv_x, bag and 1.3 or 7.4, + (bag and BAG_SIZES[data.bag_size] or INV_SIZE) / 8)) + + if bag then + fs("scroll_container_end[]") + end +end + +local function get_inventory_fs(player, data, fs) + fs("listcolors[#bababa50;#bababa99]listring[current_player;main]") + + get_inv_slots(data, fs) local props = player:get_properties() local name = player:get_player_name() @@ -2129,57 +2177,54 @@ local function get_inventory_fs(player, data, fs) fs(fmt("image", 0.7, 0.2, size, size * props.visual_size.y, props.textures[1])) end - local extras = __3darmor or __skinsdb or __awards - local ctn_len = 5.6 - local xoffset = extras and 0 or 4.4 - local yoffset = extras and 0 or 0.2 + local xoffset, yoffset = 0, 0 local award_list, award_list_nb local awards_unlocked = 0 - if extras then - local max_val = 15 + local max_val = 20 - if __3darmor then - max_val = max_val + 15 + if __3darmor then + max_val = max_val + 33 - if __skinsdb then - max_val = max_val + 20 - end + if __skinsdb then + max_val = max_val + 3 end - - if __awards then - award_list = awards.get_award_states(name) - award_list_nb = #award_list - - for i = 1, award_list_nb do - local award = award_list[i] - - if award.unlocked then - awards_unlocked = awards_unlocked + 1 - end - end - - max_val = max_val + (award_list_nb * (12.9 + ((__3darmor or __skinsdb) and 0.25 or 0))) - end - - fs(fmt([[ - scrollbaroptions[arrows=hide;thumbsize=%u;max=%u] - scrollbar[9.69,0.2;0.3,5.5;vertical;scrbar_inv;%u] - scrollbaroptions[arrows=default;thumbsize=0;max=1000] - ]], - (max_val * 3) / 15, max_val, data.scrbar_inv or 0)) - - fs(fmt("scroll_container[3.9,0.2;%f,5.5;scrbar_inv;vertical]", ctn_len)) end + if __skinsdb then + max_val = max_val + 16 + end + + if __awards then + award_list = awards.get_award_states(name) + award_list_nb = #award_list + + for i = 1, award_list_nb do + local award = award_list[i] + + if award.unlocked then + awards_unlocked = awards_unlocked + 1 + end + end + + max_val = max_val + (award_list_nb * (12.9 + ((__3darmor or __skinsdb) and 0.25 or 0))) + end + + fs(fmt([[ + scrollbaroptions[arrows=hide;thumbsize=%u;max=%u] + scrollbar[%f,0.2;0.3,5.5;vertical;scrbar_inv;%u] + scrollbaroptions[arrows=default;thumbsize=0;max=1000] + ]], + (max_val * 3) / 15, max_val, 9.69, data.scrbar_inv or 0)) + + fs(fmt("scroll_container[3.9,0.2;%f,5.5;scrbar_inv;vertical]", ctn_len)) + get_ctn_content(fs, data, player, xoffset, yoffset, ctn_len, award_list, awards_unlocked, award_list_nb) - if extras then - fs("scroll_container_end[]") - end + fs("scroll_container_end[]") local btn = { {"trash", ES"Trash all items"}, @@ -2330,7 +2375,7 @@ i3.new_tab { end, } -local trash = core.create_detached_inventory("i3_trash", { +local trash = create_inventory("i3_trash", { allow_put = function(inv, listname, index, stack) return stack:get_count() end, @@ -2365,14 +2410,7 @@ end if rawget(_G, "skins") then __skinsdb = true - - on_shutdown(function() - local players = get_players() - for i = 1, #players do - local player = players[i] - save_meta(player, {"skin_id"}) - end - end) + insert(META_SAVES, "skin_id") end if rawget(_G, "awards") then @@ -2572,13 +2610,92 @@ on_mods_loaded(function() end end) -on_joinplayer(function(player) +local function init_backpack(player) local name = player:get_player_name() - init_data(player, name) local data = pdata[name] - if data.fs_version < MIN_FORMSPEC_VERSION then - outdated(name) + local player_inv = player:get_inventory() + player_inv:set_size("main", INV_SIZE) + + data.bag = create_inventory(fmt("%s_backpack", name), { + allow_put = function(inv, listname, _, stack) + local empty = inv:get_stack(listname, 1):is_empty() + + if empty and sub(stack:get_name(), 1, 7) == "i3:bag_" then + return 1 + end + + return 0 + end, + + on_put = function(_, _, _, stack) + data.bag_size = match(stack:get_name(), "_(%w+)$") + player_inv:set_size("main", BAG_SIZES[data.bag_size]) + set_fs(player) + end, + + on_take = function() + for i = INV_SIZE + 1, BAG_SIZES[data.bag_size] do + local stack = player_inv:get_stack("main", i) + + if not stack:is_empty() then + spawn_item(player, stack) + end + end + + data.bag_size = nil + player_inv:set_size("main", INV_SIZE) + + set_fs(player) + end, + }) + + data.bag:set_size("main", 1) + + if data.bag_size then + data.bag:set_stack("main", 1, fmt("i3:bag_%s", data.bag_size)) + player_inv:set_size("main", BAG_SIZES[data.bag_size]) + end +end + +on_joinplayer(function(player) + local name = player:get_player_name() + local info = get_player_info(name) + + if get_formspec_version(info) < MIN_FORMSPEC_VERSION then + return outdated(name) + end + + init_data(player, info) + init_backpack(player) +end) + +core.register_on_dieplayer(function(player) + local name = player:get_player_name() + local data = pdata[name] + + data.bag_size = nil + data.bag:set_list("main", {}) + + local inv = player:get_inventory() + inv:set_size("main", INV_SIZE) + + set_fs(player) +end) + +on_leaveplayer(function(player) + save_meta(player, META_SAVES) + + local name = player:get_player_name() + pdata[name] = nil +end) + +on_shutdown(function() + local players = get_players() + + for i = 1, #players do + local player = players[i] + save_meta(player, META_SAVES) end end) @@ -2586,6 +2703,7 @@ on_receive_fields(function(player, formname, fields) if formname ~= "" then return false end local name = player:get_player_name() local data = pdata[name] + if not data then return end for f in pairs(fields) do if sub(f, 1, 4) == "tab_" then @@ -2838,29 +2956,49 @@ if progressive_mode then end end) - local to_save = {"inv_items", "known_recipes"} - - on_leaveplayer(function(player) - save_meta(player, to_save) - end) - - on_shutdown(function() - local players = get_players() - for i = 1, #players do - local player = players[i] - save_meta(player, to_save) - end - end) + table_merge(META_SAVES, {"inv_items", "known_recipes"}) end -on_leaveplayer(function(player) - if __skinsdb then - save_meta(player, {"skin_id"}) - end +for _, size in ipairs({"small", "medium", "large"}) do + local bagname = fmt("i3:bag_%s", size) - local name = player:get_player_name() - pdata[name] = nil -end) + core.register_craftitem(bagname, { + description = fmt("%s Backpack", size:gsub("^%l", upper)), + inventory_image = fmt("i3_bag_%s.png", size), + stack_max = 1, + }) + + core.register_craft { + type = "fuel", + recipe = bagname, + burntime = 3 + } +end + +core.register_craft { + output = "i3:bag_small", + recipe = { + {"", "farming:string", ""}, + {"group:wool", "group:wool", "group:wool"}, + {"group:wool", "group:wool", "group:wool"}, + } +} + +core.register_craft { + output = "i3:bag_medium", + recipe = { + {"farming:string", "i3:bag_small", "farming:string"}, + {"farming:string", "i3:bag_small", "farming:string"}, + } +} + +core.register_craft { + output = "i3:bag_large", + recipe = { + {"farming:string", "i3:bag_medium", "farming:string"}, + {"farming:string", "i3:bag_medium", "farming:string"}, + } +} --dofile(core.get_modpath("i3") .. "/test_tabs.lua") --dofile(core.get_modpath("i3") .. "/test_custom_recipes.lua") diff --git a/textures/i3_bag_large.png b/textures/i3_bag_large.png new file mode 100644 index 0000000000000000000000000000000000000000..bfeb875ee14053862e0c6d18a3e2ce4f0da3919d GIT binary patch literal 2634 zcmV-Q3bpl#P) zaB^>EX>4U6ba`-PAZ2)IW&i+q+O1bvvMj3&{AU$j0z!<-VT|w&ynH91qN=Cs`y$*G zr=i6pl&Mr5)&KMFq5g%BVbaRF5PkAq<71OeCZiMe{-pIy+OBW;p|8%1U7Y~~6Qkw* zGh~^cVR!d}>kKNdb`@pBMA?YW#_PlLcY=(fmT<-)>KLhj<{jzF%Ou9#sq#}``XrgdJWh?5&(sv&F!bbmkUPlNyDQDf8@BGU21 z3VxZ%EVwa|o8OoPKxhbVZUy*y1b+SC52y+R-3oKW1+y-Di{j|!7B8F`^BmfpLZm{I z4G&G5g6hZf4^SgP%`Bwmyl_y1 zRfTYEK~qlL#0-cTOF%qK1VCsrG1HN(H50jsnN9{t;S8K~6C2fNA_fR;C*uYk>~7@# z3OD8AU*Tr{7jkMs_y0gn0lH7zzM$4-ovRD6orN=|nvs1N?=dSA^DJulYuj61y}@y~ zc&v6?d*j-5US_~AovSsik#*!EAqmm3sHWa+Tk~ONqH;vI=ehAkk#7DzFarlP&WG>DRHolU9BP1=U-vE+QMsV zFeC?Tvpq>BlpO4IR*ARX?2D9CD|m5Y0s=R2IP!HPaAR#+vDEF8nyNi~i?b8QQQ36| zOBZ(54ikU4taOtoB!EpjqMEtKu+6n|^D{fvuWUPC=W>lg17wd@U4B*D!TGl5VdNl<$wB>A0C=fc}#C<-^X@7M{2k#m--)SmTX_G1;-db?|{ z;I!Di$p?*oh#I#Iads-DA*7;;xUdXageVxdSD15W0AKUF&peTv9(4;mUt?v2Y!+Ge zk$|;7d0F>V^>uCuJJ1?_UPOWarfh#Rl&{g9K^Yh*p<5jS>+(LaEdO-2NAb2oj{;XG z`k-tapZQU}T%X2;FJA$H%-z?%T~~kUdz9q&sfQ$9;AJZwIxFxQ?xvf@fqCzoZ%;c5 zDS*Qr$fG6(ekn=AcBf&Mlr&RjhR`^NbW4jrEXIY!1qB}*79Z^#&+GY3$Xc8IAVKjr z34oJ&rPd39wg6m&(fN-oS8rra^>G(3Kjx4YC0!$Dd2l-pffOOqT{3-3T-yt@N1@x@ zm`X|lbOqE&>{?~64J1{=rR3jN9X-nu zs?_jrgvgni$s?M7^laRDMSttD`tI^^y$Bglzk7>kvAzp{81W9-uDFuF=pXw1x*_>$ zN{lFMc>8${=`*D4$)cLS*P@4LJnMEg?U@m({Q;Ao7tSw%Tk40}k5n+vs`o3t*GtR? z-LFuU^8f$=g=s@WP)S2WAaHVTW@&6? z004NLeUUpz!%!54|E7u$Dh^f<>5!p1Sr8R*)G8FALZ}s5buhW<3z{?}DK3tJYr(t zyIv8%Ai{{CM`o5WCrL^8*4I6CQ{BaQmVe)$)u-kx1_VUnS!S3v@dokqrfqQECl0fs ztP-CSkC}8q;zzD49=~xexGeC@u$fNH6Nib#LK`b>%!;N)JVhK;HJ$Q>jK?bHEzVlG z%9{7&FAU}Mm1VBeiXeeSEJ1<@1yz(#hK(5QIw=-XbRPHd54(PeTnf2LVB}ap1sY`6 z5B>+gXKUprC%mLk9O!&;oR1NpYZqwL9OwJkaT+H;@EN$$TmDKNnE52V*3zO!K>s#y zaoy6CJ>YT&79Co(Tgr1xCeIMTM_j$hG_kDEy6IZ-~3^2Kr*5ngJ)Th*66Sp z>982_y9DM|(@1%(PuB;1Y8R@OqZVYpOVF4%7i>d5?(-=G74WmW zSGn`#jS3J&5xrhdHk;-B&z(AgNTx=@z46PuUHrwRGkuuNX3SeEU)LPKe4|{;Q7ZWuRcdL6}xRFB&k54)5=tGll{U_(faiE2ms-kZvd3bWm2hB z9UvZ$lh`N#%4-+^#s`iu`taqx6-LkXG80`?&mND5L`|paD^#Yf+h)S)bOI2GtpJcK sp$-&4z66zl($x+V|B1|=c9a4B0_m*Kdu68o2LJ#707*qoM6N<$f+qLfA^-pY literal 0 HcmV?d00001 diff --git a/textures/i3_bag_medium.png b/textures/i3_bag_medium.png new file mode 100644 index 0000000000000000000000000000000000000000..0b4c11d8c89a95d9f7cac16730ed2dd5308293ad GIT binary patch literal 2632 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 IM6N<$f}mr_LjV8( literal 0 HcmV?d00001