From 7a4951f48c739cec2041a8c11be1d7e663834f83 Mon Sep 17 00:00:00 2001 From: FaceDeer Date: Sun, 29 Dec 2019 23:55:15 -0700 Subject: [PATCH] add mapgen for goblin and undermarket, add protection settings for all market nodes --- default_markets.lua | 50 ++++++++++++ init.lua | 2 + mapgen_dungeon_markets.lua | 153 +++++++++++++++++++++++++++++++++++++ settingtypes.txt | 18 ++++- 4 files changed, 222 insertions(+), 1 deletion(-) create mode 100644 mapgen_dungeon_markets.lua diff --git a/default_markets.lua b/default_markets.lua index 99d1f2b..2671f7e 100644 --- a/default_markets.lua +++ b/default_markets.lua @@ -39,6 +39,12 @@ gold_coins_required = true commoditymarket.register_market("kings", kings_def) +local kings_protect = minetest.settings:get_bool("commoditymarket_protect_kings_market", true) +local on_blast +if kings_protect then + on_blast = function() end +end + minetest.register_node("commoditymarket:kings_market", { description = kings_def.description, _doc_items_longdesc = kings_def.long_description, @@ -59,6 +65,10 @@ minetest.register_node("commoditymarket:kings_market", { minetest.sound_play({name = "commoditymarket_error", gain = 0.1}, {to_player=clicker:get_player_name()}) end end, + can_dig = function(pos, player) + return not kings_protect or minetest.check_player_privs(player, "protection_bypass") + end, + on_blast = on_blast, }) end ------------------------------------------------------------------------------- @@ -83,6 +93,12 @@ gold_coins_required = true commoditymarket.register_market("night", night_def) +local night_protect = minetest.settings:get_bool("commoditymarket_protect_night_market", true) +local on_blast +if night_protect then + on_blast = function() end +end + minetest.register_node("commoditymarket:night_market", { description = night_def.description, _doc_items_longdesc = night_def.long_description, @@ -103,6 +119,10 @@ minetest.register_node("commoditymarket:night_market", { minetest.sound_play({name = "commoditymarket_error", gain = 0.1}, {to_player=clicker:get_player_name()}) end end, + can_dig = function(pos, player) + return not night_protect or minetest.check_player_privs(player, "protection_bypass") + end, + on_blast = on_blast, }) end @@ -246,6 +266,12 @@ tiles = { } })) +local caravan_protect = minetest.settings:get_bool("commoditymarket_protect_caravan_market", true) +local on_blast +if caravan_protect then + on_blast = function() end +end + -- This one doesn't delete itself, server admins can place a permanent instance of it that way. Maybe inside towns next to bigger stationary markets. minetest.register_node("commoditymarket:caravan_market_permanent", { description = caravan_def.description, @@ -281,6 +307,10 @@ minetest.register_node("commoditymarket:caravan_market_permanent", { on_rightclick = function(pos, node, clicker, itemstack, pointed_thing) commoditymarket.show_market("caravan", clicker:get_player_name()) end, + can_dig = function(pos, player) + return not caravan_protect or minetest.check_player_privs(player, "protection_bypass") + end, + on_blast = on_blast, }) -- is a 5x3 area centered around pos clear of obstruction and has usable ground? @@ -413,6 +443,12 @@ local goblin_def = { commoditymarket.register_market("goblin", goblin_def) +local goblin_protect = minetest.settings:get_bool("commoditymarket_protect_goblin_market", true) +local on_blast +if goblin_protect then + on_blast = function() end +end + minetest.register_node("commoditymarket:goblin_market", { description = goblin_def.description, _doc_items_longdesc = goblin_def.long_description, @@ -427,6 +463,10 @@ minetest.register_node("commoditymarket:goblin_market", { on_rightclick = function(pos, node, clicker, itemstack, pointed_thing) commoditymarket.show_market("goblin", clicker:get_player_name()) end, + can_dig = function(pos, player) + return not goblin_protect or minetest.check_player_privs(player, "protection_bypass") + end, + on_blast = on_blast, }) end -------------------------------------------------------------------------------- @@ -447,6 +487,12 @@ local undermarket_def = { commoditymarket.register_market("under", undermarket_def) +local under_protect = minetest.settings:get_bool("commoditymarket_protect_under_market", true) +local on_blast +if under_protect then + on_blast = function() end +end + minetest.register_node("commoditymarket:under_market", { description = undermarket_def.description, _doc_items_longdesc = undermarket_def.long_description, @@ -460,6 +506,10 @@ minetest.register_node("commoditymarket:under_market", { on_rightclick = function(pos, node, clicker, itemstack, pointed_thing) commoditymarket.show_market("under", clicker:get_player_name()) end, + can_dig = function(pos, player) + return not under_protect or minetest.check_player_privs(player, "protection_bypass") + end, + on_blast = on_blast, }) end ------------------------------------------------------------------ diff --git a/init.lua b/init.lua index 51b5d16..7bffcd5 100644 --- a/init.lua +++ b/init.lua @@ -5,6 +5,8 @@ dofile(MP.."/formspecs.lua") dofile(MP.."/market.lua") dofile(MP.."/default_markets.lua") +dofile(MP.."/mapgen_dungeon_markets.lua") + minetest.register_chatcommand("market.show", { params = "marketname", privs = {server=true}, diff --git a/mapgen_dungeon_markets.lua b/mapgen_dungeon_markets.lua new file mode 100644 index 0000000..43c3add --- /dev/null +++ b/mapgen_dungeon_markets.lua @@ -0,0 +1,153 @@ +local goblin_enabled = minetest.settings:get_bool("commoditymarket_enable_goblin_market") +local under_enabled = minetest.settings:get_bool("commoditymarket_enable_under_market") +local goblin_prob = minetest.settings:get("commoditymarket_goblin_market_dungeon_prob") or 0.25 +local under_prob = minetest.settings:get("commoditymarket_under_market_dungeon_prob") or 0.1 + +local goblin_max = minetest.settings:get("commoditymarket_goblin_market_dungeon_max") or -100 +local goblin_min = minetest.settings:get("commoditymarket_goblin_market_dungeon_min") or -300 +local under_max = minetest.settings:get("commoditymarket_under_market_dungeon_max") or -500 +local under_min = minetest.settings:get("commoditymarket_under_market_dungeon_min") or -31000 + +local bad_goblin_range = goblin_min >= goblin_max +local bad_under_range = under_min >= under_max + +if bad_goblin_range then + minetest.log("error", "[commoditymarket] Goblin market dungeon generation range has a higher minimum y than maximum y") +end +if bad_under_range then + minetest.log("error", "[commoditymarket] Undermarket dungeon generation range has a higher minimum y than maximum y") +end + +local gen_goblin = goblin_enabled and goblin_prob > 0 and not bad_goblin_range +local gen_under = under_enabled and under_prob > 0 and not bad_under_range + +if not (gen_goblin or gen_under) then + return +end + + +------------------------------------------------------- +-- The following is shamelessly copied from dungeon_loot and tweaked for placing markets instead of chests +--Licensed under the MIT License (MIT) Copyright (C) 2017 sfan5 + +minetest.set_gen_notify({dungeon = true, temple = true}) + +local function noise3d_integer(noise, pos) + return math.abs(math.floor(noise:get_3d(pos) * 0x7fffffff)) +end + +local is_wall = function(node) + return node.name ~= "air" and node.name ~= "ignore" +end + +local function find_walls(cpos) + local dirs = {{x=1, z=0}, {x=-1, z=0}, {x=0, z=1}, {x=0, z=-1}} + local get_node = minetest.get_node + + local ret = {} + local mindist = {x=0, z=0} + local min = function(a, b) return a ~= 0 and math.min(a, b) or b end + for _, dir in ipairs(dirs) do + for i = 1, 9 do -- 9 = max room size / 2 + local pos = vector.add(cpos, {x=dir.x*i, y=0, z=dir.z*i}) + + -- continue in that direction until we find a wall-like node + local node = get_node(pos) + if is_wall(node) then + local front_below = vector.subtract(pos, {x=dir.x, y=1, z=dir.z}) + local above = vector.add(pos, {x=0, y=1, z=0}) + + -- check that it: + --- is at least 2 nodes high (not a staircase) + --- has a floor + if is_wall(get_node(front_below)) and is_wall(get_node(above)) then + pos = vector.subtract(pos, {x=dir.x, y=0, z=dir.z}) -- move goblin markets one node away from the wall + table.insert(ret, {pos = pos, facing = {x=-dir.x, y=0, z=-dir.z}}) + if dir.z == 0 then + mindist.x = min(mindist.x, i-1) + else + mindist.z = min(mindist.z, i-1) + end + end + -- abort even if it wasn't a wall cause something is in the way + break + end + end + end + + return { + walls = ret, + size = {x=mindist.x*2, z=mindist.z*2}, + cpos = cpos, + } +end + +minetest.register_on_generated(function(minp, maxp, blockseed) + local min_y = minp.y + local max_y = maxp.y + + local gen_goblin_range = gen_goblin and not (min_y > goblin_max or max_y < goblin_min) + local gen_under_range = gen_under and not (min_y > under_max or max_y < under_min) + + if not (gen_goblin_range or gen_under_range) then + -- out of both ranges + return + end + + local gennotify = minetest.get_mapgen_object("gennotify") + local poslist = gennotify["dungeon"] or {} + for _, entry in ipairs(gennotify["temple"] or {}) do + table.insert(poslist, entry) + end + if #poslist == 0 then return end + + local noise = minetest.get_perlin(151994, 4, 0.5, 1) + local rand = PcgRandom(noise3d_integer(noise, poslist[1])) + + local rooms = {} + -- process at most 8 rooms to keep runtime of this predictable + local num_process = math.min(#poslist, 8) + for i = 1, num_process do + local room = find_walls(poslist[i]) + -- skip small rooms and everything that doesn't at least have 3 walls + if math.min(room.size.x, room.size.z) >= 4 and #room.walls >= 3 then + table.insert(rooms, room) + end + end + if #rooms == 0 then return end + + if gen_under_range and rand:next(0, 2147483647)/2147483647 < under_prob then + -- choose a random room + local room = rooms[rand:next(1, #rooms)] + local under_loc = room.cpos + + -- put undermarkets in the center of the room + if minetest.get_node(under_loc).name == "air" + and is_wall(vector.subtract(under_loc, {x=0, y=1, z=0})) then + minetest.add_node(under_loc, {name="commoditymarket:under_market"}) + end + end + + if gen_goblin_range and rand:next(0, 2147483647)/2147483647 < goblin_prob then + -- choose a random room + local room = rooms[rand:next(1, #rooms)] + + -- choose place somewhere in front of any of the walls + local wall = room.walls[rand:next(1, #room.walls)] + local v, vi -- vector / axis that runs alongside the wall + if wall.facing.x ~= 0 then + v, vi = {x=0, y=0, z=1}, "z" + else + v, vi = {x=1, y=0, z=0}, "x" + end + local marketpos = vector.add(wall.pos, wall.facing) + local off = rand:next(-room.size[vi]/2 + 1, room.size[vi]/2 - 1) + marketpos = vector.add(marketpos, vector.multiply(v, off)) + + if minetest.get_node(marketpos).name == "air" then + -- make it face inwards to the room + local facedir = minetest.dir_to_facedir(vector.multiply(wall.facing, -1)) + minetest.add_node(marketpos, {name = "commoditymarket:goblin_market", param2 = facedir}) + end + end +end) \ No newline at end of file diff --git a/settingtypes.txt b/settingtypes.txt index 86e9f2c..edbecda 100644 --- a/settingtypes.txt +++ b/settingtypes.txt @@ -1,5 +1,21 @@ +[Enable default markets] commoditymarket_enable_kings_market (Enable King's Market) bool false commoditymarket_enable_night_market (Enable Night Market) bool false commoditymarket_enable_caravan_market (Enable Trader's Caravan) bool true commoditymarket_enable_goblin_market (Enable Goblin Exchange) bool false -commoditymarket_enable_under_market (Enable Under Market) bool false \ No newline at end of file +commoditymarket_enable_under_market (Enable Undermarket) bool false + +[Market node protection] +commoditymarket_protect_kings_market (Protect King's Market node) bool true +commoditymarket_protect_night_market (Protect Night Market node) bool true +commoditymarket_protect_caravan_market (Protect permanent Caravan node) bool true +commoditymarket_protect_goblin_market (Protect Goblin Market node) bool true +commoditymarket_protect_under_market (Protect Undermarket node) bool true + +[Dungeon market generation] +commoditymarket_goblin_market_dungeon_prob (Goblin market probability per dungeon mapblock) float 0.25 0 1 +commoditymarket_goblin_market_dungeon_max (Upper y limit of goblin markets) int -100 +commoditymarket_goblin_market_dungeon_min (Lower y limit of goblin markets) int -300 +commoditymarket_under_market_dungeon_prob (Undermarket probability per dungeon mapblock) float 0.1 0 1 +commoditymarket_under_market_dungeon_max (Upper y limit of undermarkets) int -500 +commoditymarket_under_market_dungeon_min (Lower y limit of undermarkets) int -31000