From 7392937d8d2b548e1038f958a58cb7344fd01a7e Mon Sep 17 00:00:00 2001 From: Abigail Read Date: Fri, 27 Mar 2026 19:09:22 -0700 Subject: [PATCH 01/13] Fix libox log issues --- mods/libox | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/libox b/mods/libox index 08d49da4..a6b356d4 160000 --- a/mods/libox +++ b/mods/libox @@ -1 +1 @@ -Subproject commit 08d49da483cc56e8852ce9d941a57867e11074d1 +Subproject commit a6b356d46b6fdaf186f3fdb99e527724aeb2423e From de7cef5aebe7e042f0d4af47d9bb30cdb0dbf9d3 Mon Sep 17 00:00:00 2001 From: Abigail Read Date: Fri, 27 Mar 2026 19:38:19 -0700 Subject: [PATCH 02/13] Improve libox log fixes --- mods/libox | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/libox b/mods/libox index a6b356d4..e160bab3 160000 --- a/mods/libox +++ b/mods/libox @@ -1 +1 @@ -Subproject commit a6b356d46b6fdaf186f3fdb99e527724aeb2423e +Subproject commit e160bab3c485610605247fef680b563093f9c138 From 6ef68931cd87b1064d30648023280770eb938bf0 Mon Sep 17 00:00:00 2001 From: Abigail Read Date: Fri, 27 Mar 2026 19:38:45 -0700 Subject: [PATCH 03/13] Alleviate sbz_audio undeclared warning --- mods/sbz_audio/init.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mods/sbz_audio/init.lua b/mods/sbz_audio/init.lua index bb5a42c3..bcab534a 100644 --- a/mods/sbz_audio/init.lua +++ b/mods/sbz_audio/init.lua @@ -1,5 +1,6 @@ -- sbz_api.sounds is gone. Replace with sbz_audio wherever used. -sbz_audio = sbz_audio or {} +-- Ensure global exists without triggering undeclared-global warning +sbz_audio = rawget(_G, "sbz_audio") or {} -- Use as a template (include fade if needed on any) function sbz_audio.blank() From 13000640556c3e1a207a7db3f83b8929b668fe46 Mon Sep 17 00:00:00 2001 From: Abigail Read Date: Fri, 27 Mar 2026 20:21:46 -0700 Subject: [PATCH 04/13] Alleviate warning by specifying a size The health bar is in a weird position already, and specifying a size doesn't change that. I couldn't find anything online as far as if this was ever resolved, so I just assume it eventually became enforced displacement. We'll want to figure this out at some point for our hud bars to look right when the player is damaged. But for now at least, we can silence this particular warning (that's gone unheeded for years). --- mods/hudbars/init.lua | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/mods/hudbars/init.lua b/mods/hudbars/init.lua index a07cc1af..e93633c6 100644 --- a/mods/hudbars/init.lua +++ b/mods/hudbars/init.lua @@ -3,7 +3,7 @@ local NS = function(s) return s end --- Boilerplate for compatibiliity with pre-5.9.0 +-- Boilerplate for compatibility with pre-5.9.0 -- versions of minetest local hud_def_type_field if minetest.features.hud_def_type_field then @@ -237,13 +237,7 @@ function hb.register_hudbar( local bar_image, bgicon, bar_size if hb.settings.bar_type == 'progress_bar' then bar_image = textures.bar - -- NOTE: Intentionally set to nil. For some reason, on some systems, - -- the progress bar is displaced when the bar_size is set explicitly here. - -- On the other hand, setting this to nil is deprecated in MT 5.0.0 due to - -- a debug log warning, but nothing is explained in lua_api.txt. - -- This section is a potential bug magnet, please watch with care! - -- The size of the bar image is expected to be exactly 2×16 pixels. - bar_size = nil + bar_size = { x = 2, y = 16 } elseif hb.settings.bar_type == 'statbar_classic' or hb.settings.bar_type == 'statbar_modern' then bar_image = textures.icon bgicon = textures.bgicon From 5ae12dc839c9b9650c7111037418e1099c504706 Mon Sep 17 00:00:00 2001 From: Abigail Read Date: Fri, 27 Mar 2026 22:01:13 -0700 Subject: [PATCH 05/13] Refactor airbrush and the extended palette I needed something that would allow me to change the extended palette to something that doesn't go over 256 pixels. There's no getting around the log warning when you do, and I wanted to prevent that without changing anything from a player's standpoint. I know this is nuts, but when the engine doesn't let me silence these warnings, I go crazy. --- mods/unifieddyes/airbrush.lua | 70 +++++++++++------- .../textures/unifieddyes_palette_extended.png | Bin 292 -> 5353 bytes 2 files changed, 44 insertions(+), 26 deletions(-) diff --git a/mods/unifieddyes/airbrush.lua b/mods/unifieddyes/airbrush.lua index 815d3737..5033b0ed 100644 --- a/mods/unifieddyes/airbrush.lua +++ b/mods/unifieddyes/airbrush.lua @@ -24,21 +24,17 @@ with this program; if not, see . ]=] local function sheet(t, sx, sy, x, y) - sx = sx + 1 - sy = sy + 1 return ("%s^[sheet:%sx%s:%s,%s"):format(t, sx, sy, x, y) end +-- cols/rows: tile counts in the source image +-- leftover: missing tiles from the last row local palette_sizes = { - ["unifieddyes_palette_colorfacedir.png"] = vector.new(8, 1, 0), -- im using vectors cuz z will be "how much is left off the last row" if that makes sense - ["unifieddyes_palette_extended.png"] = vector.new(24, 11, 8), - ["unifieddyes_palette_colorwallmounted.png"] = vector.new(8, 4, 0), + ["unifieddyes_palette_colorfacedir.png"] = { cols = 8, rows = 1, leftover = 0 }, + ["unifieddyes_palette_extended.png"] = { cols = 256, rows = 1, leftover = 0 }, + ["unifieddyes_palette_colorwallmounted.png"] = { cols = 8, rows = 4, leftover = 0 }, } -for k, v in pairs(palette_sizes) do - palette_sizes[k] = vector.subtract(v, vector.new(1, 1, 1)) -end - local function show_fs(user, palette) local size = palette_sizes[palette] if size == nil then @@ -46,37 +42,59 @@ local function show_fs(user, palette) return end - local button_size = 0.8 + local button_size = 0.8 local button_spacing = 0.9 + local wrap = 24 -- columns to wrap 1D palettes into + local is_strip = (size.rows == 1) + local total = size.cols * size.rows - size.leftover + + local display_cols, display_rows + if is_strip then + display_cols = math.min(total, wrap) + display_rows = math.ceil(total / wrap) + else + display_cols = size.cols + display_rows = size.rows + end local fs = { ([[ formspec_version[7] size[%s,%s] - ]]):format((size.x * button_spacing) + 1.2, 1.2 + (size.y * button_spacing)), -- 1.5 spacing for the rest + ]]):format( + ((display_cols - 1) * button_spacing) + 1.2, + ((display_rows - 1) * button_spacing) + 1.2 + ), } local head = #fs + 1 - local idx = 0 - - for y = 0, size.y do - for x = 0, size.x do - idx = idx + 1 - if y == size.y and x >= (size.x - size.z) then - break - end - fs[head] = string.format("image_button[%s,%s;%s,%s;%s;%s;]", - (x * button_spacing) + 0.2, (y * button_spacing) + 0.2, - button_size, button_size, - minetest.formspec_escape(sheet(palette, size.x, size.y, x, y)), idx) - head = head + 1 + for idx = 0, total - 1 do + local src_x, src_y, screen_x, screen_y + if is_strip then + src_x, src_y = idx, 0 + screen_x = idx % wrap + screen_y = math.floor(idx / wrap) + else + src_x = idx % size.cols + src_y = math.floor(idx / size.cols) + screen_x, screen_y = src_x, src_y end + + fs[head] = string.format( + "image_button[%s,%s;%s,%s;%s;%s;]", + (screen_x * button_spacing) + 0.2, + (screen_y * button_spacing) + 0.2, + button_size, button_size, + minetest.formspec_escape(sheet(palette, size.cols, size.rows, src_x, src_y)), + idx + 1 + ) + head = head + 1 end - minetest.show_formspec(user:get_player_name(), "color_dialog", - table.concat(fs)) + minetest.show_formspec(user:get_player_name(), "color_dialog", table.concat(fs)) end + minetest.register_on_player_receive_fields(function(player, formname, fields) if formname ~= "color_dialog" then return end diff --git a/mods/unifieddyes/textures/unifieddyes_palette_extended.png b/mods/unifieddyes/textures/unifieddyes_palette_extended.png index 596e5e38ff3be8786445c58adac1910d80149a10..06c5f938fb2815dc7e0f43ae195d6f8f5f2e4d2f 100644 GIT binary patch literal 5353 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 Pk}Jy7&4*p!61MU`w7NRc literal 292 zcmV+<0o(qGP)Q~yD0002%NklCDDSPmJ;pVOL!dE)#@b6^W2;hN0%Wx?l#B&CunA7$>$t}i}boZIi)aSfe>mO5yNvzaTd?e8U@n!BNs&{FB`GQ{arpCKc0V8I*jERYFF z4MZt~IGMQRrrBJxXJkT4C7p+el9D@06;D)DvZ1A<5UR2?qR+@~*nD(<%Y>wccIoXR zJYsy@tK)K^r4AY%#$!D$Da68tH5*pQgro{l3gI3Fy{4>Lvtlh9T1pC`EDC3I=!jig q&3=#xNp;1f+fdgvzW#kgf1Y1uinP*eCWc`E0000 Date: Fri, 27 Mar 2026 22:03:40 -0700 Subject: [PATCH 06/13] Update minetest to core --- mods/unifieddyes/airbrush.lua | 36 +++++++-------- mods/unifieddyes/api.lua | 86 +++++++++++++++++------------------ mods/unifieddyes/init.lua | 2 +- 3 files changed, 62 insertions(+), 62 deletions(-) diff --git a/mods/unifieddyes/airbrush.lua b/mods/unifieddyes/airbrush.lua index 5033b0ed..8838748e 100644 --- a/mods/unifieddyes/airbrush.lua +++ b/mods/unifieddyes/airbrush.lua @@ -38,7 +38,7 @@ local palette_sizes = { local function show_fs(user, palette) local size = palette_sizes[palette] if size == nil then - minetest.chat_send_player(user:get_player_name(), "Node not supported!") + core.chat_send_player(user:get_player_name(), "Node not supported!") return end @@ -86,16 +86,16 @@ size[%s,%s] (screen_x * button_spacing) + 0.2, (screen_y * button_spacing) + 0.2, button_size, button_size, - minetest.formspec_escape(sheet(palette, size.cols, size.rows, src_x, src_y)), + core.formspec_escape(sheet(palette, size.cols, size.rows, src_x, src_y)), idx + 1 ) head = head + 1 end - minetest.show_formspec(user:get_player_name(), "color_dialog", table.concat(fs)) + core.show_formspec(user:get_player_name(), "color_dialog", table.concat(fs)) end -minetest.register_on_player_receive_fields(function(player, formname, fields) +core.register_on_player_receive_fields(function(player, formname, fields) if formname ~= "color_dialog" then return end local wield_item = player:get_wielded_item() @@ -109,8 +109,8 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) wield_item:get_meta():set_int("selected_index", idx) player:set_wielded_item(wield_item) - minetest.chat_send_player(player:get_player_name(), "Updated the tool succesfully") - minetest.show_formspec(player:get_player_name(), "color_dialog", "") + core.chat_send_player(player:get_player_name(), "Updated the tool succesfully") + core.show_formspec(player:get_player_name(), "color_dialog", "") end) _G.show_fs = show_fs @@ -120,10 +120,10 @@ _G.show_fs = show_fs local function load_into(stack, player, pointed) if pointed.type ~= "node" then return end local pos = pointed.under - local n = minetest.get_node(pos) - local def = minetest.registered_nodes[n.name] or {} + local n = core.get_node(pos) + local def = core.registered_nodes[n.name] or {} if not palette_sizes[def.palette or "no"] then - minetest.chat_send_player(player:get_player_name(), "Node not supported!") + core.chat_send_player(player:get_player_name(), "Node not supported!") return end show_fs(player, def.palette) @@ -134,8 +134,8 @@ end local function color_block(stack, player, pointed) if pointed.type ~= "node" then return end local pos = pointed.under - if minetest.is_protected(pos, player:get_player_name()) then - minetest.chat_send_player(player:get_player_name(), + if core.is_protected(pos, player:get_player_name()) then + core.chat_send_player(player:get_player_name(), "PROTECTED!!!!!") return end @@ -145,24 +145,24 @@ local function color_block(stack, player, pointed) local pinv = player:get_inventory() if not pinv:contains_item("main", "unifieddyes:colorium 1") then - minetest.chat_send_player(player:get_player_name(), "You don't have the required colorium") + core.chat_send_player(player:get_player_name(), "You don't have the required colorium") return end - local n = minetest.get_node(pos) - local def = minetest.registered_nodes[n.name] or {} + local n = core.get_node(pos) + local def = core.registered_nodes[n.name] or {} local pal = def.palette local meta = stack:get_meta() local stack_pal = meta:get_string("palette") if pal ~= stack_pal then - minetest.chat_send_player(player:get_player_name(), "Palette mismatch, need to re-configure again") + core.chat_send_player(player:get_player_name(), "Palette mismatch, need to re-configure again") return load_into(stack, player, pointed) end local indx = meta:get_int("selected_index") local paramtype = def.paramtype2 local rotation = 0 - rotation = n.param2 - minetest.strip_param2_color(n.param2, paramtype) + rotation = n.param2 - core.strip_param2_color(n.param2, paramtype) local mul = 1 if paramtype == "colorfacedir" then @@ -175,12 +175,12 @@ local function color_block(stack, player, pointed) mul = 32 end indx = indx - 1 - minetest.swap_node(pos, { name = n.name, param2 = rotation + (math.floor(indx * mul)) }) + core.swap_node(pos, { name = n.name, param2 = rotation + (math.floor(indx * mul)) }) pinv:remove_item("main", "unifieddyes:colorium 1") end -minetest.register_tool("unifieddyes:coloring_tool", { +core.register_tool("unifieddyes:coloring_tool", { description = "Coloring Tool", inventory_image = "color_tool.png", liquids_pointable = false, -- colorable liquids probably wont exist but they would be funny diff --git a/mods/unifieddyes/api.lua b/mods/unifieddyes/api.lua index 7cd27347..82b668f5 100644 --- a/mods/unifieddyes/api.lua +++ b/mods/unifieddyes/api.lua @@ -35,8 +35,8 @@ unifieddyes.player_showall = {} -- but the itemstack used to place it has no palette_index (color byte), -- create something appropriate to make it officially white. -minetest.register_on_placenode(function(pos, newnode, placer, oldnode, itemstack, pointed_thing) - local def = minetest.registered_items[newnode.name] +core.register_on_placenode(function(pos, newnode, placer, oldnode, itemstack, pointed_thing) + local def = core.registered_items[newnode.name] if not def or not def.palette or def.after_place_node or not placer then return false end @@ -54,8 +54,8 @@ minetest.register_on_placenode(function(pos, newnode, placer, oldnode, itemstack end if param2 and not (core.get_item_group(newnode.name, 'falling_node') == 1) then - minetest.swap_node(pos, { name = newnode.name, param2 = param2 }) - minetest.get_meta(pos):set_int('palette_index', color) + core.swap_node(pos, { name = newnode.name, param2 = param2 }) + core.get_meta(pos):set_int('palette_index', color) end end end) @@ -70,23 +70,23 @@ local function node_dig_without_color(pos, node, digger) local def = ItemStack(node.name):get_definition() -- Copy pos because the callback could modify it if not def.diggable or (def.can_dig and not def.can_dig(vector.copy(pos), digger)) then - minetest.log( + core.log( 'info', - diggername .. ' tried to dig ' .. node.name .. ' which is not diggable ' .. minetest.pos_to_string(pos) + diggername .. ' tried to dig ' .. node.name .. ' which is not diggable ' .. core.pos_to_string(pos) ) return false end - if minetest.is_protected(pos, diggername) then - minetest.log( + if core.is_protected(pos, diggername) then + core.log( 'action', - diggername .. ' tried to dig ' .. node.name .. ' at protected position ' .. minetest.pos_to_string(pos) + diggername .. ' tried to dig ' .. node.name .. ' at protected position ' .. core.pos_to_string(pos) ) - minetest.record_protection_violation(pos, diggername) + core.record_protection_violation(pos, diggername) return false end - minetest.log('action', diggername .. ' digs ' .. node.name .. ' at ' .. minetest.pos_to_string(pos)) + core.log('action', diggername .. ' digs ' .. node.name .. ' at ' .. core.pos_to_string(pos)) local wielded = digger and digger:get_wielded_item() local drops = { node.name } -- this is instead of asking minetest to generate the node drops @@ -94,15 +94,15 @@ local function node_dig_without_color(pos, node, digger) if wielded then local wdef = wielded:get_definition() local tp = wielded:get_tool_capabilities() - local dp = minetest.get_dig_params(def and def.groups, tp, wielded:get_wear()) + local dp = core.get_dig_params(def and def.groups, tp, wielded:get_wear()) if wdef and wdef.after_use then wielded = wdef.after_use(wielded, digger, node, dp) or wielded else -- Wear out tool - if not minetest.is_creative_enabled(diggername) then + if not core.is_creative_enabled(diggername) then wielded:add_wear(dp.wear) if wielded:get_count() == 0 and wdef.sound and wdef.sound.breaks then - minetest.sound_play(wdef.sound.breaks, { + core.sound_play(wdef.sound.breaks, { pos = pos, gain = 0.5, }, true) @@ -114,7 +114,7 @@ local function node_dig_without_color(pos, node, digger) -- Check to see if metadata should be preserved. if def and def.preserve_metadata then - local oldmeta = minetest.get_meta(pos):to_table().fields + local oldmeta = core.get_meta(pos):to_table().fields -- Copy pos and node because the callback can modify them. local pos_copy = vector.copy(pos) local node_copy = { name = node.name, param1 = node.param1, param2 = node.param2 } @@ -127,17 +127,17 @@ local function node_dig_without_color(pos, node, digger) end -- Handle drops - minetest.handle_node_drops(pos, drops, digger) + core.handle_node_drops(pos, drops, digger) local oldmetadata - if def and def.after_dig_node then oldmetadata = minetest.get_meta(pos):to_table() end + if def and def.after_dig_node then oldmetadata = core.get_meta(pos):to_table() end -- Remove node and update - minetest.remove_node(pos) + core.remove_node(pos) -- Play sound if it was done by a player if diggername ~= '' and def and def.sounds and def.sounds.dug then - minetest.sound_play(def.sounds.dug, { + core.sound_play(def.sounds.dug, { pos = pos, exclude_player = diggername, }, true) @@ -152,9 +152,9 @@ local function node_dig_without_color(pos, node, digger) end -- Run script hook - for _, callback in ipairs(minetest.registered_on_dignodes) do - local origin = minetest.callback_origins[callback] - minetest.set_last_run_mod(origin.mod) + for _, callback in ipairs(core.registered_on_dignodes) do + local origin = core.callback_origins[callback] + core.set_last_run_mod(origin.mod) -- Copy pos and node because callback can modify them local pos_copy = vector.copy(pos) @@ -166,15 +166,15 @@ local function node_dig_without_color(pos, node, digger) end function unifieddyes.on_dig(pos, node, digger) - local param2 = minetest.get_node(pos).param2 - local def = minetest.registered_items[node.name] + local param2 = core.get_node(pos).param2 + local def = core.registered_items[node.name] local del_color if def.paramtype2 == 'color' and param2 == 240 and def.palette == 'unifieddyes_palette_extended.png' then del_color = true elseif (def.paramtype2 == 'colorwallmounted' or def.paramtype2 == 'colorfacedir') - and minetest.strip_param2_color(param2, def.paramtype2) == 0 + and core.strip_param2_color(param2, def.paramtype2) == 0 and string.find(def.palette, 'unifieddyes_palette_') then del_color = true @@ -183,7 +183,7 @@ function unifieddyes.on_dig(pos, node, digger) if del_color then return node_dig_without_color(pos, node, digger) else - return minetest.node_dig(pos, node, digger) + return core.node_dig(pos, node, digger) end end @@ -220,7 +220,7 @@ function unifieddyes.generate_split_palette_nodes(name, def, drop) } end - minetest.register_node(':' .. name .. '_' .. color, def2) + core.register_node(':' .. name .. '_' .. color, def2) end end @@ -250,10 +250,10 @@ local function register_c(craft, h, sat, val) end local dye = 'dye:' .. color - local recipe = minetest.serialize(craft.recipe) + local recipe = core.serialize(craft.recipe) recipe = string.gsub(recipe, 'MAIN_DYE', dye) recipe = string.gsub(recipe, 'NEUTRAL_NODE', craft.neutral_node) - local newrecipe = minetest.deserialize(recipe) + local newrecipe = core.deserialize(recipe) local coutput = craft.output or '' local output = coutput @@ -274,7 +274,7 @@ local function register_c(craft, h, sat, val) local colored_itemstack = unifieddyes.make_colored_itemstack(output, craft.palette, dye) - minetest.register_craft { + core.register_craft { output = colored_itemstack, type = craft.type, recipe = newrecipe, @@ -318,34 +318,34 @@ end -- call this function to reset the rotation of a "wallmounted" object on place function unifieddyes.fix_rotation(pos, placer, itemstack, pointed_thing) - local node = minetest.get_node(pos) + local node = core.get_node(pos) local colorbits = node.param2 - (node.param2 % 8) local yaw = placer:get_look_horizontal() - local dir = minetest.yaw_to_dir(yaw) -- -1.5) + local dir = core.yaw_to_dir(yaw) -- -1.5) local pitch = placer:get_look_vertical() - local fdir = minetest.dir_to_wallmounted(dir) + local fdir = core.dir_to_wallmounted(dir) if pitch < -(math.pi / 8) then fdir = 0 elseif pitch > math.pi / 8 then fdir = 1 end - minetest.swap_node(pos, { name = node.name, param2 = fdir + colorbits }) + core.swap_node(pos, { name = node.name, param2 = fdir + colorbits }) end -- use this when you have a "wallmounted" node that should never be oriented -- to floor or ceiling... function unifieddyes.fix_rotation_nsew(pos, placer, itemstack, pointed_thing) - local node = minetest.get_node(pos) + local node = core.get_node(pos) local colorbits = node.param2 - (node.param2 % 8) local yaw = placer:get_look_horizontal() - local dir = minetest.yaw_to_dir(yaw + 1.5) - local fdir = minetest.dir_to_wallmounted(dir) + local dir = core.yaw_to_dir(yaw + 1.5) + local fdir = core.dir_to_wallmounted(dir) - minetest.swap_node(pos, { name = node.name, param2 = fdir + colorbits }) + core.swap_node(pos, { name = node.name, param2 = fdir + colorbits }) end -- ... and use this one to force that kind of node off of floor/ceiling @@ -356,16 +356,16 @@ function unifieddyes.fix_after_screwdriver_nsew(pos, node, user, mode, new_param local color = new_param2 - new_fdir if new_fdir < 2 then new_fdir = 2 - minetest.swap_node(pos, { name = node.name, param2 = new_fdir + color }) + core.swap_node(pos, { name = node.name, param2 = new_fdir + color }) return true end end function unifieddyes.is_buildable_to(placer_name, ...) for _, pos in ipairs { ... } do - local node = minetest.get_node_or_nil(pos) - local def = node and minetest.registered_nodes[node.name] - if not (def and def.buildable_to) or minetest.is_protected(pos, placer_name) then return false end + local node = core.get_node_or_nil(pos) + local def = node and core.registered_nodes[node.name] + if not (def and def.buildable_to) or core.is_protected(pos, placer_name) then return false end end return true end @@ -503,7 +503,7 @@ function unifieddyes.get_color_from_dye_name(name) elseif name == 'dye:white' then return 'ffffff' end - local item = minetest.registered_items[name] + local item = core.registered_items[name] if not item then return end local inv_image = item.inventory_image if not inv_image then return end diff --git a/mods/unifieddyes/init.lua b/mods/unifieddyes/init.lua index 6e7eae05..ea9b4d5d 100644 --- a/mods/unifieddyes/init.lua +++ b/mods/unifieddyes/init.lua @@ -36,7 +36,7 @@ with this program; if not, see . unifieddyes = {} -local modpath = minetest.get_modpath(minetest.get_current_modname()) +local modpath = core.get_modpath(core.get_current_modname()) dofile(modpath .. "/color-tables.lua") dofile(modpath .. "/api.lua") From ec31c6803646145979199e8910ceb4a0aab11190 Mon Sep 17 00:00:00 2001 From: Coma Berenices Date: Fri, 20 Mar 2026 20:07:33 +0000 Subject: [PATCH 07/13] set Dirt as unlock condition for Bricks --- mods/sbz_progression/quests/Decorator.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/sbz_progression/quests/Decorator.md b/mods/sbz_progression/quests/Decorator.md index cd45a553..75279a31 100644 --- a/mods/sbz_progression/quests/Decorator.md +++ b/mods/sbz_progression/quests/Decorator.md @@ -185,7 +185,7 @@ More fancy traditional bricks to build with. ### Meta -Requires: Clay +Requires: Dirt ## Mystery Terrarium From 8fabe8466f4e93e55af42d78fff2e368ba1f6977 Mon Sep 17 00:00:00 2001 From: Coma Berenices Date: Fri, 20 Mar 2026 20:06:45 +0000 Subject: [PATCH 08/13] fix Refined Firmament recipe Blast Furnace needs three ingredients to craft, adding an empty value fixes this --- mods/sbz_resources/wormhole.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/mods/sbz_resources/wormhole.lua b/mods/sbz_resources/wormhole.lua index 7aacac41..52da76a4 100644 --- a/mods/sbz_resources/wormhole.lua +++ b/mods/sbz_resources/wormhole.lua @@ -104,6 +104,7 @@ sbz_api.recipe.register_craft { items = { "sbz_resources:unrefined_firmament", "sbz_resources:gravitational_lens", + "", }, } From 6040d564aebd966b902e9ed648f45edde6854f4b Mon Sep 17 00:00:00 2001 From: JaneJuice Date: Sun, 29 Mar 2026 17:51:38 +0200 Subject: [PATCH 09/13] Update sbz_api.explode to use fibonacci sphere ray distribution --- mods/sbz_base/init.lua | 163 +++++++++++++++++++++++++++++------------ 1 file changed, 117 insertions(+), 46 deletions(-) diff --git a/mods/sbz_base/init.lua b/mods/sbz_base/init.lua index e8dcd33a..9e00d60a 100644 --- a/mods/sbz_base/init.lua +++ b/mods/sbz_base/init.lua @@ -573,61 +573,57 @@ function sbz_api.punch(target, hitter, time_from_last_punch, tool_caps, dir) end end ---- Async is todo, and it wont be true async, just the function would be delayed, useful for something like a detonator ----@param pos vector ----@param power number ----@param r number ----@param async boolean -sbz_api.explode = function(pos, r, power, async, owner, extra_damage, knockback_strength, sound) - if async then - sbz_api.delay_if_laggy(function() - sbz_api.explode(pos, r, power, false, owner, extra_damage, knockback_strength, sound) - end) - return +local fib_cache = {} +-- refer to: https://stackoverflow.com/questions/9600801/evenly-distributing-n-points-on-a-sphere +local function fibonacci_sphere_points(samples) + if fib_cache[samples] then + return fib_cache[samples] end - extra_damage = extra_damage or power - knockback_strength = knockback_strength or 2.5 - owner = owner or '' - for _ = 1, 500 do - local raycast = core.raycast(pos, pos + vector.random_direction() * r, false, true) - local wear = 0 - for pointed in raycast do - if pointed.type == 'node' then - local target_pos = pointed.under - local nodename = core.get_node(target_pos).name - local ndef = core.registered_nodes[nodename] - if not ndef then break end - wear = wear + (1 / core.get_item_group(nodename, 'explody')) - --the explody group hence signifies roughly how many such nodes in a straight line it can break before stopping - --although this is very random - if wear > power or core.is_protected(target_pos, owner) then break end - if ndef.on_blast then - ndef.on_blast(target_pos, power, pos, owner, r) - else - core.set_node(target_pos, { name = ndef._exploded or 'air' }) - end - end - end + local points = {} + local phi = math.pi * (3 - math.sqrt(5)) + + for i = 0, samples - 1 do + local y = 1 - (i / (samples - 1)) * 2 + local radius = math.sqrt(math.max(0, 1 - y * y)) + local theta = phi * i + local x = math.cos(theta) * radius + local z = math.sin(theta) * radius + points[i + 1] = vector.new(x, y, z) end - for _, obj in ipairs(core.get_objects_inside_radius(pos, r)) do - -- this is all messed up - -- TODO: improve - local dir = obj:get_pos() - pos + + fib_cache[samples] = points + return points +end + +sbz_api._start_explosion = function(ctx) + local MAX_ENTITIES = 9 -- finely tuned by means of divine revelation + local entity_count = 0 + + -- Damage & knockback to objects + for _, obj in ipairs(core.get_objects_inside_radius(ctx.pos, math.sqrt(ctx.r))) do + if entity_count >= MAX_ENTITIES then + break + end + entity_count = entity_count + 1 + + local dir = obj:get_pos() - ctx.pos local len = vector.length(dir) + + if len == 0 then dir = vector.new(0, 1, 0) len = 0.01 end + if sbz_api.can_move_object(obj:get_armor_groups()) then - obj:add_velocity(vector.normalize(dir) * (r - vector.length(dir)) * knockback_strength) + obj:add_velocity(vector.normalize(dir) * (ctx.r - len) * ctx.knockback_strength) end - -- this is intentional. HP is only removed when there is line of sight, but velocity is added anyway - if sbz_api.line_of_sight(pos, obj:get_pos()) == true then - local dmg = math.abs(vector.length(vector.normalize(dir) * (r - vector.length(dir))) * extra_damage) + + if sbz_api.line_of_sight(ctx.pos, obj:get_pos()) then + local dmg = math.abs((ctx.r - len) * ctx.extra_damage) local groups = obj:get_armor_groups() local tool_caps = { full_punch_interval = 0, damage_groups = {}, } - -- pick whichever damage group is more protected if (groups.matter or 0) <= (groups.antimatter or 0) then tool_caps.damage_groups.matter = dmg else @@ -637,15 +633,90 @@ sbz_api.explode = function(pos, r, power, async, owner, extra_damage, knockback_ sbz_api.punch(obj, nil, 100, tool_caps, dir) end end - if sound then + + if ctx.sound then core.sound_play('gen_explosion_with_reverb', { gain = 2.5, - max_hear_distance = 128, - pos = pos, + max_hear_distance = ctx.r * ctx.r, + pos = ctx.pos, }, true) end end +local function process_explosion_batch(ctx) + local batch_size = 50 + local processed = 0 + + while ctx.i <= ctx.total and processed < batch_size do + local dir = ctx.ray_dirs[ctx.i] + local raycast = core.raycast( + ctx.pos, + ctx.pos + dir * ctx.r, + false, + true + ) + + local wear = 0 + for pointed in raycast do + if pointed.type == 'node' then + local target_pos = pointed.under + local nodename = core.get_node(target_pos).name + local ndef = core.registered_nodes[nodename] + if not ndef then break end + + wear = wear + (1 / core.get_item_group(nodename, 'explody')) + + if wear > ctx.power or core.is_protected(target_pos, ctx.owner) then + break + end + + if ndef.on_blast then + ndef.on_blast(target_pos, ctx.power, ctx.pos, ctx.owner, ctx.r) + else + core.set_node(target_pos, { name = ndef._exploded or 'air' }) + end + end + end + + ctx.i = ctx.i + 1 + processed = processed + 1 + end + + if ctx.i <= ctx.total then + sbz_api.delay_if_laggy(function() + process_explosion_batch(ctx) + end) + end +end + +sbz_api.explode = function(pos, r, power, async, owner, extra_damage, knockback_strength, sound) + local total_rays = math.min(math.pi * r * r, 3000) + + local ctx = { + pos = pos, + r = r, + power = power, + owner = owner or '', + extra_damage = extra_damage or power, + knockback_strength = knockback_strength or 2.5, + sound = sound, + i = 1, + total = total_rays, + ray_dirs = fibonacci_sphere_points(total_rays), + } + + if async then + sbz_api.delay_if_laggy(function() + sbz_api.explode(pos, r, power, false, owner, extra_damage, knockback_strength, sound) + end) + else + -- 1. Trigger the start effects (Damage, Sound, Knockback) + sbz_api._start_explosion(ctx) + -- 2. Batched raycasting for nodes + process_explosion_batch(ctx) + end +end + sbz_api.on_place_recharge = function(charge_per_1_wear, after) return function(stack, user, pointed) if pointed.type ~= 'node' then return end From 6d05a27a11605389178a699fc6a11e14d0d1a4d5 Mon Sep 17 00:00:00 2001 From: JaneJuice Date: Sun, 29 Mar 2026 17:53:12 +0200 Subject: [PATCH 10/13] Fission bomb textures --- mods/sbz_resources/textures/fission_bomb.png | Bin 0 -> 216 bytes mods/sbz_resources/textures/fission_bomb_top.png | Bin 0 -> 120 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 mods/sbz_resources/textures/fission_bomb.png create mode 100644 mods/sbz_resources/textures/fission_bomb_top.png diff --git a/mods/sbz_resources/textures/fission_bomb.png b/mods/sbz_resources/textures/fission_bomb.png new file mode 100644 index 0000000000000000000000000000000000000000..30e1682082cff141fe5310a4df33087e63bc870b GIT binary patch literal 216 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|CV9FzhFJ72 zoxGRtkO5DNz4H1!%tLcSiX}wCeyshFu P*D-jy`njxgN@xNA;>=SO literal 0 HcmV?d00001 diff --git a/mods/sbz_resources/textures/fission_bomb_top.png b/mods/sbz_resources/textures/fission_bomb_top.png new file mode 100644 index 0000000000000000000000000000000000000000..6cc38c5285e940d6628dc8ffb57cb63735346697 GIT binary patch literal 120 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|j67W&Lo9le zLxK!`o_AnONK8mb*iqTpsdM&K)qjZ-mpfV9cqL2|t}t)_r5c`S6)`eQTF(0B2D9rE Ppl$|FS3j3^P6 Date: Sun, 29 Mar 2026 17:55:57 +0200 Subject: [PATCH 11/13] Add fission bomb --- mods/sbz_resources/bomb.lua | 96 +++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/mods/sbz_resources/bomb.lua b/mods/sbz_resources/bomb.lua index 58132567..204334e0 100644 --- a/mods/sbz_resources/bomb.lua +++ b/mods/sbz_resources/bomb.lua @@ -153,3 +153,99 @@ core.register_node("sbz_resources:bomb", { core.add_entity(pos, "sbz_resources:bomb_entity", owner) end }) + +local function fission_bomb_detonate(obj, owner) + sbz_api.explode(obj:get_pos(), 256, 0.9, true, owner or "", 2.5, nil, true) + obj:remove() +end + +local fission_time = 5 + +core.register_entity("sbz_resources:fission_bomb_entity", { + initial_properties = { + physical = true, + collide_with_objects = false, + visual = "cube", + textures = { + "fission_bomb_top.png^[brighten", + "fission_bomb_top.png^[brighten", + "fission_bomb.png^[brighten", + "fission_bomb.png^[brighten", + "fission_bomb.png^[brighten", + "fission_bomb.png^[brighten", + }, + static_save = false, + pointable = true + }, + + on_activate = function(self, staticdata) + self.object:set_armor_groups({ immortal = 1, can_move = 1 }) + self.time = fission_time + self.owner = staticdata + self.object:add_velocity(vector.new(0, 1, 0)) + self.object:set_acceleration(vector.new(0, -sbz_api.gravity, 0)) + end, + + on_step = function(self, dtime, moveresult) + self.time = self.time - dtime + self.object:set_acceleration(vector.new(0, -sbz_api.gravity, 0)) + + if moveresult.touching_ground or moveresult.standing_on_object then + self.object:set_velocity(self.object:get_velocity() * 0.9) + end + + if self.time <= 0 then + fission_bomb_detonate(self.object, self.owner) + end + end, +}) + +core.register_node("sbz_resources:fission_bomb", { + description = "Fission Bomb", + tiles = { + "fission_bomb_top.png", + "fission_bomb_top.png", + "fission_bomb.png" + }, + groups = { matter = 1, explody = 100 }, + sounds = { + footstep = { name = 'gen_full_container_thunk', gain = 0.2, pitch = 0.5 }, + dig = { name = 'gen_pew_waveform', gain = 0.2, pitch = 0.1 }, + dug = { name = 'gen_pew_flange', gain = 1.0, pitch = 1.0 }, + place = { name = 'gen_full_container_thunk', gain = 0.7, pitch = 1.0 }, + }, + + on_rightclick = function(pos, node, player) + local name = player:get_player_name() + + if core.is_protected(pos, name) then + return core.record_protection_violation(pos, name) + end + + core.remove_node(pos) + core.add_entity(pos, "sbz_resources:fission_bomb_entity", name) + + core.sound_play("gen_noise_fuse", { + pos = pos, + gain = 1.2, + fade = 10.0, + pitch = 0.8, -- deeper sound? + }) + end, + + on_blast = function(pos, power, original_pos, owner) + if core.is_protected(pos, owner) then return end + + core.remove_node(pos) + core.add_entity(pos, "sbz_resources:fission_bomb_entity", owner) + end +}) + +core.register_craft({ + output = "sbz_resources:fission_bomb", + recipe = { + { "sbz_resources:bomb", "sbz_chem:lead_block", "sbz_resources:bomb" }, + { "sbz_resources:heating_element", "sbz_chem:plutonium_fuel_rod", "sbz_resources:heating_element" }, + { "sbz_resources:bomb", "sbz_chem:lead_block", "sbz_resources:bomb" } + } +}) From 41e8f39a127ff789812ee9dad5ba836fa6c55c36 Mon Sep 17 00:00:00 2001 From: JaneJuice Date: Sun, 29 Mar 2026 18:02:04 +0200 Subject: [PATCH 12/13] Readd accidentally removed comment --- mods/sbz_base/init.lua | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mods/sbz_base/init.lua b/mods/sbz_base/init.lua index 9e00d60a..f85671a6 100644 --- a/mods/sbz_base/init.lua +++ b/mods/sbz_base/init.lua @@ -689,6 +689,11 @@ local function process_explosion_batch(ctx) end end +--- Async is todo, and it wont be true async, just the function would be delayed, useful for something like a detonator +---@param pos vector +---@param power number +---@param r number +---@param async boolean sbz_api.explode = function(pos, r, power, async, owner, extra_damage, knockback_strength, sound) local total_rays = math.min(math.pi * r * r, 3000) From 4c9d3a2d61c9a42b1a47658bc2406ff7006c46e0 Mon Sep 17 00:00:00 2001 From: JaneJuice Date: Sun, 29 Mar 2026 18:18:19 +0200 Subject: [PATCH 13/13] Readd accidentally removed comments --- mods/sbz_base/init.lua | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mods/sbz_base/init.lua b/mods/sbz_base/init.lua index f85671a6..34a93af9 100644 --- a/mods/sbz_base/init.lua +++ b/mods/sbz_base/init.lua @@ -615,7 +615,7 @@ sbz_api._start_explosion = function(ctx) if sbz_api.can_move_object(obj:get_armor_groups()) then obj:add_velocity(vector.normalize(dir) * (ctx.r - len) * ctx.knockback_strength) end - + -- this is intentional. HP is only removed when there is line of sight, but velocity is added anyway if sbz_api.line_of_sight(ctx.pos, obj:get_pos()) then local dmg = math.abs((ctx.r - len) * ctx.extra_damage) local groups = obj:get_armor_groups() @@ -623,7 +623,7 @@ sbz_api._start_explosion = function(ctx) full_punch_interval = 0, damage_groups = {}, } - + -- pick whichever damage group is more protected if (groups.matter or 0) <= (groups.antimatter or 0) then tool_caps.damage_groups.matter = dmg else @@ -665,7 +665,8 @@ local function process_explosion_batch(ctx) if not ndef then break end wear = wear + (1 / core.get_item_group(nodename, 'explody')) - + --the explody group hence signifies roughly how many such nodes in a straight line it can break before stopping + --although this is very random if wear > ctx.power or core.is_protected(target_pos, ctx.owner) then break end