mods that hopefully work for a TechAge-based pack

This commit is contained in:
2026-09-09 06:27:51 -06:00
parent 4e6b08d194
commit c27db2a537
6234 changed files with 375578 additions and 0 deletions
+19
View File
@@ -0,0 +1,19 @@
Ancient Bones
=====
Adds randomly generated bones with some "loot" to generated dungeons.
Only works if dungeons are actually enabled in mapgen flags.
Based on the vanilla minetest game's dungeon_loot mod, with the bones textures
from the bones mod.
The pool of possible loot has more tools than the normal chests.
License information can be found in license.txt
Authors of source code
----------------------
Original dungeon_loot mod by sfan5 (MIT)
Modified by karlexceed
Authors of media (textures)
---------------------------
All textures: paramat (CC BY-SA 3.0)
+85
View File
@@ -0,0 +1,85 @@
-- ancient_bones/ancient_bones.lua
-- Load support for MT game translation.
local S = core.get_translator("ancient_bones")
ancient_bones_object = {}
local bones_formspec =
"size[8,9]" ..
"list[current_name;main;0,0.3;8,4;]" ..
"list[current_player;main;0,4.85;8,1;]" ..
"list[current_player;main;0,6.08;8,3;8]" ..
"listring[current_name;main]" ..
"listring[current_player;main]" ..
default.get_hotbar_bg(0,4.85)
local bones_def = {
description = S("Ancient Bones"),
tiles = {
"bones_top.png^[transform2",
"bones_bottom.png",
"bones_side.png",
"bones_side.png",
"bones_rear.png",
"bones_front.png"
},
paramtype2 = "facedir",
groups = {dig_immediate = 2},
sounds = default.node_sound_gravel_defaults(),
on_metadata_inventory_take = function(pos, listname, index, stack, player)
local meta = core.get_meta(pos)
if meta:get_inventory():is_empty("main") then
local inv = player:get_inventory()
if inv:room_for_item("main", {name = "bones:bones"}) then
inv:add_item("main", {name = "bones:bones"})
else
core.add_item(pos, "bones:bones")
end
core.remove_node(pos)
end
end,
on_punch = function(pos, node, player)
local inv = core.get_meta(pos):get_inventory()
local player_inv = player:get_inventory()
local has_space = true
for i = 1, inv:get_size("main") do
local stk = inv:get_stack("main", i)
if player_inv:room_for_item("main", stk) then
inv:set_stack("main", i, nil)
player_inv:add_item("main", stk)
else
has_space = false
break
end
end
-- remove bones if player emptied them
if has_space then
if player_inv:room_for_item("main", {name = "bones:bones"}) then
player_inv:add_item("main", {name = "bones:bones"})
else
core.add_item(pos,"bones:bones")
end
core.remove_node(pos)
end
end,
}
function ancient_bones_object.register_ancient_bones(d)
local def = table.copy(d)
def.on_construct = function(pos)
local meta = core.get_meta(pos)
meta:set_string("infotext", S("Ancient Bones"))
meta:set_string("formspec", bones_formspec)
local inv = meta:get_inventory()
inv:set_size("main", 8*4)
end
core.register_node("ancient_bones:ancient_bones", def)
end
ancient_bones_object.register_ancient_bones(bones_def)
+9
View File
@@ -0,0 +1,9 @@
ancient_bones = {}
ancient_bones.modpath = core.get_modpath("ancient_bones")
dofile(ancient_bones.modpath .. "/settings.lua")
dofile(ancient_bones.modpath .. "/ancient_bones.lua")
dofile(ancient_bones.modpath .. "/loot.lua")
dofile(ancient_bones.modpath .. "/mapgen.lua")
+9
View File
@@ -0,0 +1,9 @@
The code is licensed under MIT License (MIT): https://spdx.org/licenses/MIT.html
Based on original code from:
dungeon_loot by sfan5 (MIT)
bones by PilzAdam and Various Minetest developers and contributors (MIT)
The art is licensed under CC-BY-SA-3.0: https://spdx.org/licenses/CC-BY-SA-3.0.html
The textures are copied from the bones mod, made by paramat (CC BY-SA 3.0)
+66
View File
@@ -0,0 +1,66 @@
-- Loot from the `default` mod is registered here,
-- with the rest being registered in the respective mods
ancient_bones.registered_loot = {
-- various items
{name = "default:stick", chance = 0.6, count = {3, 8}},
{name = "default:flint", chance = 0.4, count = {1, 3}},
-- farming / consumable
{name = "default:apple", chance = 0.4, count = {1, 4}},
{name = "default:cactus", chance = 0.4, count = {1, 4},
types = {"sandstone", "desert"}},
-- minerals
{name = "default:coal_lump", chance = 0.9, count = {1, 12}},
{name = "default:gold_ingot", chance = 0.5},
{name = "default:steel_ingot", chance = 0.4, count = {1, 6}},
{name = "default:mese_crystal", chance = 0.1, count = {2, 3}},
-- tools
{name = "default:sword_wood", chance = 0.6},
{name = "default:sword_steel", chance = 0.3},
{name = "default:sword_diamond", chance = 0.05},
{name = "default:pick_stone", chance = 0.4},
{name = "default:pick_steel", chance = 0.2},
{name = "default:pick_diamond", chance = 0.05},
{name = "default:axe_stone", chance = 0.4},
{name = "default:axe_steel", chance = 0.2},
{name = "default:axe_diamond", chance = 0.05},
-- natural materials
{name = "default:sand", chance = 0.8, count = {4, 32}, y = {-64, 32768},
types = {"normal"}},
{name = "default:desert_sand", chance = 0.8, count = {4, 32}, y = {-64, 32768},
types = {"sandstone"}},
{name = "default:desert_cobble", chance = 0.8, count = {4, 32},
types = {"desert"}},
{name = "default:snow", chance = 0.8, count = {8, 64}, y = {-64, 32768},
types = {"ice"}},
{name = "default:dirt", chance = 0.6, count = {2, 16}, y = {-64, 32768},
types = {"normal", "sandstone", "desert"}},
{name = "default:obsidian", chance = 0.25, count = {1, 3}, y = {-32768, -512}},
{name = "default:mese", chance = 0.15, y = {-32768, -512}},
}
function ancient_bones.register(t)
if t.name ~= nil then
t = {t} -- single entry
end
for _, loot in ipairs(t) do
table.insert(ancient_bones.registered_loot, loot)
end
end
function ancient_bones._internal_get_loot(pos_y, dungeontype)
-- filter by y pos and type
local ret = {}
for _, l in ipairs(ancient_bones.registered_loot) do
if l.y == nil or (pos_y >= l.y[1] and pos_y <= l.y[2]) then
if l.types == nil or table.indexof(l.types, dungeontype) ~= -1 then
table.insert(ret, l)
end
end
end
return ret
end
+173
View File
@@ -0,0 +1,173 @@
core.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 function random_sample(rand, list, count)
local ret = {}
for n = 1, count do
local idx = rand:next(1, #list)
table.insert(ret, list[idx])
table.remove(list, idx)
end
return ret
end
local function find_walls(cpos, is_temple)
local is_wall = function(node)
return node.name ~= "air" and node.name ~= "ignore"
end
local dirs = {{x=1, z=0}, {x=-1, z=0}, {x=0, z=1}, {x=0, z=-1}}
local get_node = core.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
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
local biome = core.get_biome_data(cpos)
biome = biome and core.get_biome_name(biome.biome) or ""
local type = "normal"
if is_temple or biome:find("desert") == 1 then
type = "desert"
elseif biome:find("sandstone_desert") == 1 then
type = "sandstone"
elseif biome:find("icesheet") == 1 then
type = "ice"
end
return {
walls = ret,
size = {x=mindist.x*2, z=mindist.z*2},
type = type,
}
end
local function populate_bones(pos, rand, dungeontype)
--core.chat_send_all("bones placed at " .. core.pos_to_string(pos) .. " [" .. dungeontype .. "]")
--core.add_node(vector.add(pos, {x=0, y=1, z=0}), {name="default:torch", param2=1})
local item_list = ancient_bones._internal_get_loot(pos.y, dungeontype)
-- take random (partial) sample of all possible items
local sample_n = math.min(#item_list, ancient_bones.config.stacks_per_bones)
item_list = random_sample(rand, item_list, sample_n)
-- apply chances / randomized amounts and collect resulting items
local items = {}
for _, loot in ipairs(item_list) do
if rand:next(0, 1000) / 1000 <= loot.chance then
local itemdef = core.registered_items[loot.name]
local amount = 1
if loot.count ~= nil then
amount = rand:next(loot.count[1], loot.count[2])
end
if not itemdef then
core.log("warning", "Registered loot item " .. loot.name .. " does not exist")
elseif itemdef.tool_capabilities then
for n = 1, amount do
local wear = rand:next(0.20 * 65535, 0.75 * 65535) -- 20% to 75% wear
table.insert(items, ItemStack({name = loot.name, wear = wear}))
end
elseif itemdef.stack_max == 1 then
-- not stackable, add separately
for n = 1, amount do
table.insert(items, loot.name)
end
else
table.insert(items, ItemStack({name = loot.name, count = amount}))
end
end
end
-- place items at random places in bones
local inv = core.get_meta(pos):get_inventory()
local listsz = inv:get_size("main")
assert(listsz >= #items)
for _, item in ipairs(items) do
local index = rand:next(1, listsz)
if inv:get_stack("main", index):is_empty() then
inv:set_stack("main", index, item)
else
inv:add_item("main", item) -- space occupied, just put it anywhere
end
end
end
core.register_on_generated(function(minp, maxp, blockseed)
local gennotify = core.get_mapgen_object("gennotify")
local poslist = gennotify["dungeon"] or {}
local n_dungeons = #poslist
-- Add MGv6 desert temples to the list too
for _, entry in ipairs(gennotify["temple"] or {}) do
table.insert(poslist, entry)
end
if #poslist == 0 then return end
local noise = core.get_perlin(10115, 4, 0.5, 1)
local rand = PcgRandom(noise3d_integer(noise, poslist[1]))
local candidates = {}
-- 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], i > n_dungeons)
-- 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(candidates, room)
end
end
local num_bones = rand:next(ancient_bones.config.min_bones, ancient_bones.config.max_bones)
num_bones = math.min(#candidates, num_bones)
local rooms = random_sample(rand, candidates, num_bones)
for _, room in ipairs(rooms) do
-- 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 bonespos = vector.add(wall.pos, wall.facing)
local off = rand:next(-room.size[vi]/2 + 1, room.size[vi]/2 - 1)
bonespos = vector.add(bonespos, vector.multiply(v, off))
if core.get_node(bonespos).name == "air" then
-- make it face inwards to the room
local facedir = core.dir_to_facedir(vector.multiply(wall.facing, -1))
core.add_node(bonespos, {name = "ancient_bones:ancient_bones", param2 = facedir})
populate_bones(bonespos, PcgRandom(noise3d_integer(noise, bonespos)), room.type)
end
end
end)
+5
View File
@@ -0,0 +1,5 @@
name = ancient_bones
description = Adds bones with loot to dungeons
depends = default, bones
title = Ancient Bones
author = karlexceed
Binary file not shown.

After

Width:  |  Height:  |  Size: 233 KiB

+26
View File
@@ -0,0 +1,26 @@
ancient_bones.config = {}
local function setting(name, tp, default)
local full_name = "ancient_bones." .. name
local value
value = tonumber(core.settings:get(full_name))
local v, other = default:match("^(%S+) (.+)")
default = value == nil and tonumber(other and v or default)
if value == nil then
value = default
assert(default ~= nil, "Cannot parse default for " .. full_name)
end
ancient_bones.config[name] = value
end
local file = io.open(ancient_bones.modpath .. "/settingtypes.txt", "r")
for line in file:lines() do
local name, tp, value = line:match("^ancient_bones%.(%S+) %(.*%) (%S+) (.*)")
if value then
setting(name, tp, value)
end
end
file:close()
+8
View File
@@ -0,0 +1,8 @@
# Minimum bones: The minimum number of bones per mapgen chunk
ancient_bones.min_bones (Minimum bones count) int 0
# Maximum bones: The maximum number of bones per mapgen chunk
ancient_bones.max_bones (Maximum bones count) int 2
# Maximum loot stacks: The maximum number of loot stacks per bones (32 max)
ancient_bones.stacks_per_bones (Maximum loot stacks count) int 8
Binary file not shown.

After

Width:  |  Height:  |  Size: 349 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 339 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 341 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 338 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 333 B