Update beds, boats, dye, fire, flowers, wool. Add player_api, new dungeon_loot.

master
Maksim 2019-05-08 20:04:40 +02:00
parent 95c8ff7c83
commit c3e80cf0e3
46 changed files with 1025 additions and 935 deletions

View File

@ -74,7 +74,7 @@ armor.update_player_visuals = function(self, player)
end
local name = player:get_player_name()
if self.textures[name] then
default.player_set_textures(player, {
player_api.set_textures(player, {
self.textures[name].skin,
self.textures[name].armor,
self.textures[name].wielditem,
@ -268,7 +268,7 @@ end]]
-- Register Player Model
default.player_register_model("3d_armor_character.b3d", {
player_api.register_model("3d_armor_character.b3d", {
animation_speed = 30,
textures = {
armor.default_skin..".png",
@ -306,7 +306,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
end)
minetest.register_on_joinplayer(function(player)
default.player_set_model(player, "3d_armor_character.b3d")
player_api.set_model(player, "3d_armor_character.b3d")
local name = player:get_player_name()
local player_inv = player:get_inventory()
local armor_inv = minetest.create_detached_inventory(name.."_armor",{

View File

@ -109,7 +109,7 @@ function beds.register_bed(name, def)
return itemstack
end,
on_rotate = function(pos, node, user, mode, new_param2)
on_rotate = function(pos, node, user, _, new_param2)
local dir = minetest.facedir_to_dir(node.param2)
local p = vector.add(pos, dir)
local node2 = minetest.get_node_or_nil(p)
@ -121,7 +121,7 @@ function beds.register_bed(name, def)
minetest.record_protection_violation(p, user:get_player_name())
return false
end
if mode ~= screwdriver.ROTATE_FACE then
if new_param2 % 32 > 3 then
return false
end
local newp = vector.add(pos, minetest.facedir_to_dir(new_param2))
@ -141,6 +141,9 @@ function beds.register_bed(name, def)
minetest.set_node(newp, {name = name .. "_top", param2 = new_param2})
return true
end,
can_dig = function(pos, player)
return beds.can_dig(pos)
end,
})
minetest.register_node(name .. "_top", {
@ -160,6 +163,12 @@ function beds.register_bed(name, def)
on_destruct = function(pos)
destruct_bed(pos, 2)
end,
can_dig = function(pos, player)
local node = minetest.get_node(pos)
local dir = minetest.facedir_to_dir(node.param2)
local p = vector.add(pos, dir)
return beds.can_dig(p)
end,
})
minetest.register_alias(name, name .. "_bottom")

View File

@ -1,5 +1,4 @@
local pi = math.pi
local player_in_bed = 0
local is_sp = minetest.is_singleplayer()
local enable_respawn = minetest.settings:get_bool("enable_bed_respawn")
if enable_respawn == nil then
@ -9,15 +8,18 @@ end
-- Helper functions
local function get_look_yaw(pos)
local n = minetest.get_node(pos)
if n.param2 == 1 then
return pi / 2, n.param2
elseif n.param2 == 3 then
return -pi / 2, n.param2
elseif n.param2 == 0 then
return pi, n.param2
local rotation = minetest.get_node(pos).param2
if rotation > 3 then
rotation = rotation % 4 -- Mask colorfacedir values
end
if rotation == 1 then
return pi / 2, rotation
elseif rotation == 3 then
return -pi / 2, rotation
elseif rotation == 0 then
return pi, rotation
else
return 0, n.param2
return 0, rotation
end
end
@ -56,10 +58,8 @@ local function lay_down(player, pos, bed_pos, state, skip)
-- stand up
if state ~= nil and not state then
local p = beds.pos[name] or nil
if beds.player[name] ~= nil then
beds.player[name] = nil
player_in_bed = player_in_bed - 1
end
beds.bed_position[name] = nil
-- skip here to prevent sending player specific changes (used for leaving players)
if skip then
return
@ -71,16 +71,16 @@ local function lay_down(player, pos, bed_pos, state, skip)
-- physics, eye_offset, etc
player:set_eye_offset({x = 0, y = 0, z = 0}, {x = 0, y = 0, z = 0})
player:set_look_horizontal(math.random(1, 180) / 100)
default.player_attached[name] = false
player_api.player_attached[name] = false
player:set_physics_override(1, 1, 1)
hud_flags.wielditem = true
default.player_set_animation(player, "stand" , 30)
player_api.set_animation(player, "stand" , 30)
-- lay down
else
beds.player[name] = 1
beds.pos[name] = pos
player_in_bed = player_in_bed + 1
beds.bed_position[name] = bed_pos
beds.player[name] = 1
-- physics, eye_offset, etc
player:set_eye_offset({x = 0, y = -13, z = 0}, {x = 0, y = 0, z = 0})
@ -90,26 +90,35 @@ local function lay_down(player, pos, bed_pos, state, skip)
local p = {x = bed_pos.x + dir.x / 2, y = bed_pos.y, z = bed_pos.z + dir.z / 2}
player:set_physics_override(0, 0, 0)
player:set_pos(p)
default.player_attached[name] = true
player_api.player_attached[name] = true
hud_flags.wielditem = false
default.player_set_animation(player, "lay" , 0)
player_api.set_animation(player, "lay" , 0)
end
player:hud_set_flags(hud_flags)
end
local function get_player_in_bed_count()
local c = 0
for _, _ in pairs(beds.player) do
c = c + 1
end
return c
end
local function update_formspecs(finished)
local ges = #minetest.get_connected_players()
local form_n
local player_in_bed = get_player_in_bed_count()
local is_majority = (ges / 2) < player_in_bed
if finished then
form_n = beds.formspec .. "label[2.7,11; Good morning.]"
form_n = beds.formspec .. "label[2.7,9; Good morning.]"
else
form_n = beds.formspec .. "label[2.2,11;" .. tostring(player_in_bed) ..
form_n = beds.formspec .. "label[2.2,9;" .. tostring(player_in_bed) ..
" of " .. tostring(ges) .. " players are in bed]"
if is_majority and is_night_skip_enabled() then
form_n = form_n .. "button_exit[2,8;4,0.75;force;Force night skip]"
form_n = form_n .. "button_exit[2,6;4,0.75;force;Force night skip]"
end
end
@ -171,6 +180,15 @@ function beds.on_rightclick(pos, player)
end
end
function beds.can_dig(bed_pos)
-- Check all players in bed which one is at the expected position
for _, player_bed_pos in pairs(beds.bed_position) do
if vector.equals(bed_pos, player_bed_pos) then
return false
end
end
return true
end
-- Callbacks
-- Only register respawn callback if respawn enabled
@ -205,16 +223,25 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname ~= "beds_form" then
return
end
-- Because "Force night skip" button is a button_exit, it will set fields.quit
-- and lay_down call will change value of player_in_bed, so it must be taken
-- earlier.
local last_player_in_bed = get_player_in_bed_count()
if fields.quit or fields.leave then
lay_down(player, nil, nil, false)
update_formspecs(false)
end
if fields.force then
update_formspecs(is_night_skip_enabled())
if is_night_skip_enabled() then
local is_majority = (#minetest.get_connected_players() / 2) < last_player_in_bed
if is_majority and is_night_skip_enabled() then
update_formspecs(true)
beds.skip_night()
beds.kick_players()
else
update_formspecs(false)
end
end
end)

View File

@ -1,11 +1,13 @@
beds = {}
beds.player = {}
beds.bed_position = {}
beds.pos = {}
beds.spawn = {}
beds.formspec = "size[8,15;true]" ..
"bgcolor[#080808BB; true]" ..
"button_exit[2,12;4,0.75;leave;Leave Bed]"
beds.formspec = "size[8,11;true]" ..
"no_prepend[]" ..
"bgcolor[#080808BB;true]" ..
"button_exit[2,10;4,0.75;leave;Leave Bed]"
local modpath = minetest.get_modpath("beds")

View File

@ -30,6 +30,7 @@ Licenses of media (textures)
Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0)
Copyright (C) 2014-2016 BlockMen
Copyright (C) 2018 TumeniNodes
You are free to:
Share — copy and redistribute the material in any medium or format.

View File

@ -1,20 +1,21 @@
MultiCraft mod: boats
=======================
by PilzAdam, slightly modified for NeXt
========================
See license.txt for license information.
Authors of source code
----------------------
Originally by PilzAdam (MIT)
Various Minetest developers and contributors (MIT)
Authors of model:
-----------------------
Model: thetoon and Zeg9,
modified by PavelS(SokolovPavel) (CC BY-SA 3.0),
changed by TenPlus1 to add some new features
- boat is destroyed when crashing (drops 3 wood)
- boat turns faster
- used model from ds_rowboat mod
License of source code:
-----------------------
WTFPL
License of media (textures and sounds):
---------------------------------------
WTFPL
Authors of media files:
-----------------------
textures: Zeg9
model: thetoon and Zeg9, modified by PavelS(SokolovPavel)
- boat is destroyed when crashing at speed (drops 3 wood)
- boats drop after 10 seconds if no driver
- boats can be damaged by mobs attacking player
- Improve physics of boat by implementing drag force (thanks gnag65)
- nil player check functions by misterskullz

View File

@ -1,2 +1 @@
default
mobs?

View File

@ -1,20 +1,14 @@
handlers = {}
minetest.register_on_leaveplayer(function(player)
handlers[player:get_player_name()] = nil
end)
--
-- Helper functions
--
local function is_water(pos)
return minetest.get_item_group(minetest.get_node(pos).name, "water") ~= 0
local function is_water(pos, nodename)
local nn = nodename or minetest.get_node(pos).name
return minetest.get_item_group(nn, "water") ~= 0, nn
end
local function get_sign(i)
local function get_sign(i)
if i == 0 then
return 0
else
@ -22,21 +16,41 @@ local function get_sign(i)
end
end
local function get_velocity(v, yaw, y)
local function get_velocity(v, yaw, y)
local x = -math.sin(yaw) * v
local z = math.cos(yaw) * v
return {x = x, y = y, z = z}
end
local square = math.sqrt
local function get_v(v)
return square(v.x *v.x + v.z *v.z)
return math.sqrt(v.x ^ 2 + v.z ^ 2)
end
local function after_detach(name, pos)
local player = minetest.get_player_by_name(name)
if player then
player:set_pos(pos)
end
end
local function after_attach(name)
local player = minetest.get_player_by_name(name)
if player then
player_api.set_animation(player, "sit" , 30)
end
end
local function after_remove(object)
if object then
object:remove()
end
end
--
-- Boat entity
--
@ -47,278 +61,273 @@ local boat = {
visual = "mesh",
mesh = "rowboat.x",
textures = {"default_wood.png"},
driver = nil,
v = 0,
last_v = 0,
removed = false
removed = false,
auto = false
}
function boat.on_rightclick(self, clicker)
function boat.on_rightclick(self, clicker)
if not clicker or not clicker:is_player() then
return
end
local name = clicker:get_player_name()
if self.driver and clicker == self.driver then
handlers[name] = nil
if self.driver and name == self.driver then
self.driver = nil
self.auto = false
clicker:set_detach()
default.player_attached[name] = false
default.player_set_animation(clicker, "stand" , 30)
local pos = clicker:getpos()
minetest.after(0.1, function()
clicker:setpos({x=pos.x, y=pos.y+0.2, z=pos.z})
end)
player_api.player_attached[name] = false
player_api.set_animation(clicker, "stand" , 30)
local pos = clicker:get_pos()
pos = {x = pos.x, y = pos.y + 0.2, z = pos.z}
minetest.after(0.1, after_detach, name, pos)
elseif not self.driver then
if handlers[name] and handlers[name].driver then
handlers[name].driver = nil
local attach = clicker:get_attach()
if attach and attach:get_luaentity() then
local luaentity = attach:get_luaentity()
if luaentity.driver then
luaentity.driver = nil
end
clicker:set_detach()
end
handlers[name] = self.object:get_luaentity()
self.driver = clicker
self.driver = name
clicker:set_attach(self.object, "",
{x = 0, y = 11, z = -3}, {x = 0, y = 0, z = 0})
default.player_attached[name] = true
minetest.after(0.2, function()
default.player_set_animation(clicker, "sit" , 30)
end)
self.object:setyaw(clicker:get_look_yaw() - math.pi / 2)
{x = 0.5, y = 11, z = -3}, {x = 0, y = 0, z = 0})
player_api.player_attached[name] = true
minetest.after(0.2, after_attach, name)
clicker:set_look_horizontal(self.object:get_yaw())
end
end
function boat.on_detach_child(self, child)
self.driver = nil
self.auto = false
end
function boat.on_activate(self, staticdata, dtime_s)
if (mobs and mobs.entity and mobs.entity == false)
or not self then
self.object:remove()
return
self.object:set_armor_groups({fleshy = 100}) -- {immortal = 1}
if staticdata then
self.v = tonumber(staticdata)
end
self.object:set_armor_groups({immortal = 1})
self.v = 0
self.v2 = self.v
self.last_v = self.v
self.count = 0
end
function boat.on_punch(self, puncher)
function boat.get_staticdata(self)
return tostring(self.v)
end
function boat.on_punch(self, puncher)
if not puncher or not puncher:is_player() or self.removed then
return
end
if self.driver and puncher == self.driver then
local name = puncher:get_player_name()
puncher:set_detach()
local name = puncher:get_player_name()
if self.driver and name == self.driver then
self.driver = nil
handlers[name] = nil
default.player_attached[name] = false
puncher:set_detach()
player_api.player_attached[name] = false
end
if not self.driver then
self.removed = true
if not minetest.setting_getbool("creative_mode") then
local inv = puncher:get_inventory()
if inv:room_for_item("main", "boats:boat") then
inv:add_item("main", "boats:boat")
else
minetest.add_item(self.object:getpos(), "boats:boat")
if not (creative and creative.is_enabled_for
and creative.is_enabled_for(name))
or not inv:contains_item("main", "boats:boat") then
local leftover = inv:add_item("main", "boats:boat")
-- if no room in inventory add a replacement boat to the world
if not leftover:is_empty() then
minetest.add_item(self.object:get_pos(), leftover)
end
end
self.object:remove()
-- delay remove to ensure player is detached
minetest.after(0.1, after_remove, self.object)
end
end
function boat.on_step(self, dtime)
-- after 30 seconds remove boat and drop as item if not boarded
self.count = self.count + dtime
self.count = (self.count or 0) + dtime
if self.count > 30 then
minetest.add_item(self.object:getpos(), "boats:boat")
-- after 30 seconds remove boat and drop as item if not boarded
--[[ if self.count > 10 then
minetest.add_item(self.object:get_pos(), "boats:boat")
self.object:remove()
return
end
end]]--
self.v = get_v(self.object:get_velocity()) * get_sign(self.v)
if self.driver then
self.count = 0
local ctrl = self.driver:get_player_control()
local yaw = self.object:get_yaw()
if ctrl.up then
self.v = self.v + 0.1
elseif ctrl.down then
self.v = self.v - 0.1
end
local driver_objref = minetest.get_player_by_name(self.driver)
if driver_objref then
local ctrl = driver_objref:get_player_control()
if ctrl.up and ctrl.down then
if not self.auto then
self.auto = true
minetest.chat_send_player(self.driver, "[boats] Cruise on")
end
elseif ctrl.down then
self.v = self.v - dtime * 2.0
if self.auto then
self.auto = false
minetest.chat_send_player(self.driver, "[boats] Cruise off")
end
elseif ctrl.up or self.auto then
self.v = self.v + dtime * 2.0
end
if ctrl.left then
if self.v < 0 then
self.object:setyaw(yaw - (1 + dtime) * 0.08) -- 0.03 changed to speed up turning
else
self.object:setyaw(yaw + (1 + dtime) * 0.08) -- 0.03
end
elseif ctrl.right then
if self.v < 0 then
self.object:setyaw(yaw + (1 + dtime) * 0.08) -- 0.03
else
self.object:setyaw(yaw - (1 + dtime) * 0.08) -- 0.03
if self.v < -0.001 then
self.object:set_yaw(self.object:get_yaw() - dtime * 0.9)
else
self.object:set_yaw(self.object:get_yaw() + dtime * 0.9)
end
elseif ctrl.right then
if self.v < -0.001 then
self.object:set_yaw(self.object:get_yaw() + dtime * 0.9)
else
self.object:set_yaw(self.object:get_yaw() - dtime * 0.9)
end
end
else
-- If driver leaves server while driving 'driver' is present
-- but driver objectref is nil. Reset boat properties.
self.driver = nil
self.auto = false
end
end
local velo = self.object:get_velocity()
if self.v == 0 and velo.x == 0 and velo.y == 0 and velo.z == 0 then
--self.object:setpos(self.object:getpos())
self.object:set_pos(self.object:get_pos())
return
end
local s = get_sign(self.v)
self.v = self.v - 0.02 * s
if s ~= get_sign(self.v) then
self.object:setvelocity({x = 0, y = 0, z = 0})
-- We need to multiple by abs to not loose sign of velocity
local drag = dtime * 0.08 * self.v * math.abs(self.v)
-- If drag is larger than velocity, then stop horizontal move.
if math.abs(self.v) <= math.abs(drag) then
self.v = 0
return
else
self.v = self.v - drag
end
if math.abs(self.v) > 6.0 then
self.v = 6.0 * get_sign(self.v)
end
local p = self.object:getpos()
local new_velo = {x = 0, y = 0, z = 0}
local new_acce = {x = 0, y = 0, z = 0}
local p = self.object:get_pos()
p.y = p.y - 0.5
if not is_water(p) then
local nodedef = minetest.registered_nodes[minetest.get_node(p).name]
local new_velo
local new_acce = {x = 0, y = 0, z = 0}
local iswater, nodename = is_water(p)
if not iswater then
local nodedef = minetest.registered_nodes[nodename]
if (not nodedef) or nodedef.walkable then
self.v = 0
new_acce = {x = 0, y = 0, z = 0} -- y was 1
new_acce = {x = 0, y = 1, z = 0}
else
new_acce = {x = 0, y = -9.8, z = 0}
end
new_velo = get_velocity(self.v, self.object:get_yaw(), self.object:get_velocity().y)
--self.object:setpos(self.object:getpos())
new_velo = get_velocity(self.v, self.object:get_yaw(),
self.object:get_velocity().y)
self.object:set_pos(self.object:get_pos())
else
p.y = p.y + 1
if is_water(p) then
local y = self.object:get_velocity().y
if y >= 6.0 then
y = 6.0
if y >= 5 then
y = 5
elseif y < 0 then
new_acce = {x = 0, y = 20, z = 0}
else
new_acce = {x = 0, y = 5, z = 0}
end
new_velo = get_velocity(self.v, self.object:get_yaw(), y)
--self.object:setpos(self.object:getpos())
self.object:set_pos(self.object:get_pos())
else
new_acce = {x = 0, y = 0, z = 0}
if math.abs(self.object:get_velocity().y) < 1 then
local pos = self.object:getpos()
local pos = self.object:get_pos()
pos.y = math.floor(pos.y) + 0.5
self.object:setpos(pos)
self.object:set_pos(pos)
new_velo = get_velocity(self.v, self.object:get_yaw(), 0)
else
new_velo = get_velocity(self.v, self.object:get_yaw(), self.object:get_velocity().y)
--self.object:setpos(self.object:getpos())
new_velo = get_velocity(self.v, self.object:get_yaw(),
self.object:get_velocity().y)
self.object:set_pos(self.object:get_pos())
end
end
end
self.object:setvelocity(new_velo)
self.object:set_velocity(new_velo)
self.object:set_acceleration(new_acce)
-- if boat comes to sudden stop then it has crashed, destroy boat and drop 3x wood
if self.v2 - self.v >= 3 then
-- if boat comes to sudden stop then destroy boat and drop 3x wood
if (self.v2 or 0) - self.v >= 3 then
if self.driver then
--print ("Crash! with driver", self.v2 - self.v)
self.driver:set_detach()
default.player_attached[self.driver:get_player_name()] = false
default.player_set_animation(self.driver, "stand" , 30)
local driver_objref = minetest.get_player_by_name(self.driver)
player_api.player_attached[self.driver] = false
driver_objref:set_detach()
player_api.set_animation(driver_objref, "stand" , 30)
else
--print ("Crash! no driver")
end
minetest.add_item(self.object:getpos(), "default:wood 3")
minetest.add_item(self.object:get_pos(), "default:wood 3")
self.object:remove()
return
end
self.v2 = self.v
end
minetest.register_entity("boats:boat", boat)
minetest.register_craftitem("boats:boat", {
description = "Boat",
inventory_image = "rowboat_inventory.png",
wield_image = "rowboat_inventory.png",
inventory_image = "boats_inventory.png",
wield_scale = {x = 2, y = 2, z = 1},
liquids_pointable = true,
groups = {rail = 1},
groups = {rail = 1, flammable = 2},
on_place = function(itemstack, placer, pointed_thing)
if pointed_thing.type ~= "node"
or not is_water(pointed_thing.under) then
return
local under = pointed_thing.under
local node = minetest.get_node(under)
local udef = minetest.registered_nodes[node.name]
if udef and udef.on_rightclick and
not (placer and placer:is_player() and
placer:get_player_control().sneak) then
return udef.on_rightclick(under, node, placer, itemstack,
pointed_thing) or itemstack
end
if pointed_thing.type ~= "node" then
return itemstack
end
if not is_water(pointed_thing.under) then
return itemstack
end
pointed_thing.under.y = pointed_thing.under.y + 0.5
minetest.add_entity(pointed_thing.under, "boats:boat")
if not minetest.setting_getbool("creative_mode") then
itemstack:take_item()
boat = minetest.add_entity(pointed_thing.under, "boats:boat")
if boat then
if placer then
boat:set_yaw(placer:get_look_horizontal())
end
local player_name = placer and placer:get_player_name() or ""
if not (creative and creative.is_enabled_for and
creative.is_enabled_for(player_name)) then
itemstack:take_item()
end
end
return itemstack
end,
})
minetest.register_craft({
output = "boats:boat",
recipe = {
@ -328,4 +337,8 @@ minetest.register_craft({
},
})
minetest.register_alias("ds_rowboat:ds_rowboat", "boats:boat")
minetest.register_craft({
type = "fuel",
recipe = "boats:boat",
burntime = 20,
})

View File

@ -1,9 +1,9 @@
License of source code and media (textures and model)
-----------------------------------------------------
License of source code
----------------------
The MIT License (MIT)
Copyright (C) 2012-2016 PilzAdam (source code)
Copyright (C) 2012-2016 Zeg9, thetoon, PavelS(SokolovPavel) (media)
Copyright (C) 2012-2016 PilzAdam
Copyright (C) 2012-2016 Various Minetest developers and contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
@ -23,3 +23,40 @@ DEALINGS IN THE SOFTWARE.
For more details:
https://opensource.org/licenses/MIT
Licenses of model
--------------------------------------
Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0)
Copyright (C) 2012-2016 Zeg9
Copyright (C) 2012-2016 thetoon
Copyright (C) 2012-2016 PavelS(SokolovPavel)
You are free to:
Share — copy and redistribute the material in any medium or format.
Adapt — remix, transform, and build upon the material for any purpose, even commercially.
The licensor cannot revoke these freedoms as long as you follow the license terms.
Under the following terms:
Attribution — You must give appropriate credit, provide a link to the license, and
indicate if changes were made. You may do so in any reasonable manner, but not in any way
that suggests the licensor endorses you or your use.
ShareAlike — If you remix, transform, or build upon the material, you must distribute
your contributions under the same license as the original.
No additional restrictions — You may not apply legal terms or technological measures that
legally restrict others from doing anything the license permits.
Notices:
You do not have to comply with the license for elements of the material in the public
domain or where your use is permitted by an applicable exception or limitation.
No warranties are given. The license may not give you all of the permissions necessary
for your intended use. For example, other rights such as publicity, privacy, or moral
rights may limit how you use the material.
For more details:
http://creativecommons.org/licenses/by-sa/3.0/

View File

Before

Width:  |  Height:  |  Size: 634 B

After

Width:  |  Height:  |  Size: 634 B

View File

@ -1,7 +1,6 @@
-- Format of each item:
-- {item_name, minimum, maximum}
-- Sample registration
local items_ore = {
{"default:diamond", 1, 2},
{"default:emerald", 1, 2},

View File

@ -180,7 +180,7 @@ local function get_creative_formspec(player_name, start_i, pagenum, page, pagema
"image_button[-0.1,0;1,1;"..bg["blocks"].."^default_grass_side.png;build;]".. --build blocks
"image_button[1.15,0;1,1;"..bg["deco"].."^creative_deko.png;deco;]".. --decoration blocks
"image_button[2.415,0;1,1;"..bg["mese"].."^creative_mese.png;mese;]".. --bluestone
"image_button[3.693,0;1,1;"..bg["rail"].."^rowboat_inventory.png;rail;]".. --transportation
"image_button[3.693,0;1,1;"..bg["rail"].."^boats_inventory.png;rail;]".. --transportation
"image_button[4.93,0;1,1;"..bg["misc"].."^bucket_water.png;misc;]".. --miscellaneous
"image_button[9.19,0;1,1;"..bg["all"].."^creative_all.png;default;]".. --search
"image[0,1;5,0.75;fnt_"..name..".png]"..

View File

@ -9,18 +9,19 @@ default = {}
default.LIGHT_MAX = 14
-- Load files
dofile(minetest.get_modpath("default").."/functions.lua")
dofile(minetest.get_modpath("default").."/nodes.lua")
dofile(minetest.get_modpath("default").."/tools.lua")
dofile(minetest.get_modpath("default").."/craftitems.lua")
dofile(minetest.get_modpath("default").."/crafting.lua")
dofile(minetest.get_modpath("default").."/mapgen.lua")
dofile(minetest.get_modpath("default").."/player.lua")
dofile(minetest.get_modpath("default").."/trees.lua")
dofile(minetest.get_modpath("default").."/aliases.lua")
dofile(minetest.get_modpath("default").."/furnace.lua")
dofile(minetest.get_modpath("default").."/workbench.lua")
dofile(minetest.get_modpath("default").."/chest.lua")
local default_path = minetest.get_modpath("default")
dofile(default_path.."/functions.lua")
dofile(default_path.."/trees.lua")
dofile(default_path.."/nodes.lua")
dofile(default_path.."/chests.lua")
dofile(default_path.."/furnace.lua")
dofile(default_path.."/tools.lua")
dofile(default_path.."/craftitems.lua")
dofile(default_path.."/crafting.lua")
dofile(default_path.."/mapgen.lua")
dofile(default_path.."/aliases.lua")
dofile(default_path.."/workbench.lua")
if not minetest.setting_getbool("creative_mode") then
minetest.register_on_newplayer(function (player)

View File

@ -1,20 +1,24 @@
Copyright (c) 2015 BlockMen <blockmen2015@gmail.com>
License of source code
----------------------
The MIT License (MIT)
Copyright (C) 2017 sfan5
This software is provided 'as-is', without any express or implied warranty. In no
event will the authors be held liable for any damages arising from the use of
this software.
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit
persons to whom the Software is furnished to do so, subject to the following conditions:
Permission is granted to anyone to use this software for any purpose, including
commercial applications, and to alter it and redistribute it freely, subject to the
following restrictions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software in a
product, an acknowledgment in the product documentation is required.
2. Altered source versions must be plainly marked as such, and must not
be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
For more details:
https://opensource.org/licenses/MIT

View File

@ -1,37 +1,11 @@
Mod "Dungeon Loot" [dungeon_loot]
=================================
Copyright (c) 2015 BlockMen <blockmen2015@gmail.com>
and Amoeba <amoeba@iki.fi>
Minetest Game mod: dungeon_loot
===============================
Adds randomly generated chests with some "loot" to generated dungeons,
an API to register additional loot is provided.
Only works if dungeons are actually enabled in mapgen flags.
Version: 1.1 alpha
License information can be found in license.txt
A simple mod that add to dungeons chests that contain some loot.
Configurable in many aspects, see "config.lua" for more details.
In MultiCraft Project this code has been changed:
Changed the drop in a few lines.
License:
~~~~~~~~
Code:
(c) Copyright 2015 BlockMen; modified zlib-License
see "LICENSE.txt" for details.
Media(if not stated differently):
(c) Copyright (2014-2015) BlockMen; CC-BY-SA 3.0
Github:
~~~~~~~
https://github.com/BlockMen/dungeon_loot
Forum:
~~~~~~
https://forum.minetest.net/viewtopic.php?id=13487
Changelog:
~~~~~~~~~~
-
Authors of source code
----------------------
Originally by sfan5 (MIT)

View File

@ -1,104 +0,0 @@
-- "Dungeon Loot" [dungeon_loot]
-- Original by BlockMen, this entire file by Amoeba
--
-- config.lua
--
-- Note: All positive heights (above water level) are treated as depth 0.
-- Also, no comma after the item of a list.
-- Minimum number of rooms a dungeon should have for a chest to be generated
dungeon_loot.min_num_of_rooms = 4
-- Items on basic lists have three depth ranges for their listed amount
-- maximums; they get max/2 before first increase point (minimum of 1 if
-- amount is >0), the given max between the 1st and 2nd increase point,
-- and max*2 after the 2nd.
dungeon_loot.depth_first_basic_increase = 200
dungeon_loot.depth_second_basic_increase = 2000
-- The master list of loot types
-- Note that tools and weapons should always have max_amount = 1.
-- Chance is a probability between 0 (practically never) and 1 (always),
-- so change a chance to 0 if you don't want a type (eg. weapons) included
-- in your game (or -0.001 if you want to be REALLY sure).
dungeon_loot.loot_types = {
{name="treasure", max_amount = 10, chance = 0.7, type = "depth_cutoff"},
{name="tools", max_amount = 1, chance = 0.5, type = "depth_cutoff"},
{name="weapons", max_amount = 1, chance = 0.1, type = "depth_cutoff"},
{name="consumables", max_amount = 80, chance = 0.9, type = "basic_list"},
{name="seedlings", max_amount = 5, chance = 0.3, type = "basic_list"}
}
-- Loot type lists; these names MUST be exactly of the format:
-- "dungeon_loot.name_list" where "name" is in the above list
-- Depth cutoff lists
-- These must be in order of increasing depth (but can include the same item
-- more than once). Method: a random number between 1 and chest depth is
-- chosen, and the item in that range is added to the loot. Then, there's
-- a chance additional items of the same type are added to stack; if the
-- random number is much greater than the item's min_depth, the amount
-- can grow pretty big.
dungeon_loot.treasure_list = {
{name="default:steel_ingot", min_depth = 0},
{name="default:bronze_ingot", min_depth = 20},
{name="default:gold_ingot", min_depth = 45},
{name="default:diamond", min_depth = 150},
{name="default:gold_block", min_depth = 777},
{name="default:emerald", min_depth = 800},
{name="default:diamond_block", min_depth = 1800},
{name="default:emerald", min_depth = 2000}
}
dungeon_loot.tools_list = {
{name="default:pick_steel", min_depth = 0},
{name="default:shovel_diamond", min_depth = 38},
{name="default:pick_bronze", min_depth = 40},
{name="default:axe_diamond", min_depth = 95},
{name="default:pick_diamond", min_depth = 100}
}
dungeon_loot.weapons_list = {
{name="default:sword_steel", min_depth = 0},
{name="default:sword_bronze", min_depth = 50},
{name="default:sword_diamond", min_depth = 250}
}
-- Basic lists
-- These can be of two types, either with combined chance and amount,
-- or with the two variables separated. "chance" means each item has a
-- N/M chance of being chosen, where N is it's own chance and M is the
-- total sum of chances on the list. "amount" is the maximum amount of
-- items given at the middle depth range.
dungeon_loot.consumables_list = {
{name="default:apple", chance_and_amount = 20},
{name="default:torch", chance_and_amount = 30},
{name="default:stick", chance_and_amount = 10}
}
dungeon_loot.seedlings_list = {
{name="default:sapling", chance = 5, amount = 2},
{name="default:pine_sapling", chance = 10, amount = 2},
{name="default:junglesapling", chance = 15, amount = 2},
{name="default:acacia_sapling", chance = 15, amount = 2}
}
-- Add items from other mods here inside the appropriate
-- "if ... then ... end" test
-- For basic lists, just using insert without a value works fine.
-- For depth cutoff lists, you can use insert with a table index, eg.
-- table.insert(dungeon_loot.treasure_list, 5, {name="your_mod:platinum_ingot", min_depth = 120}
-- The above would add a new item to the treasure list as the 5th item,
-- moving diamond and all below it one down in the list. Just make sure
-- that the increasing min_depth order is kept.
-- Tips: With multiple insertions in a depth cutoff list, start from the
-- last item and work towards the beginning, then you don't have to calculate
-- your number of additions. Also, trying to make sure too many different
-- mods work together in a single list will probably give you a headache;
-- just create a new list (or two) for mods with lots of additions.
if minetest.get_modpath("farming") then
table.insert(dungeon_loot.consumables_list, {name="farming:bread", chance_and_amount = 10})
table.insert(dungeon_loot.seedlings_list, {name="farming:seed_wheat", chance = 1, amount = 10})
-- table.insert(dungeon_loot.seedlings_list, {name="farming:seed_cotton", chance = 20, amount = 5})
end

View File

@ -1,2 +0,0 @@
default
farming?

View File

@ -1,183 +1,8 @@
-- "Dungeon Loot" [dungeon_loot]
-- Copyright (c) 2015 BlockMen <blockmen2015@gmail.com>
--
-- init.lua
--
-- This software is provided 'as-is', without any express or implied warranty. In no
-- event will the authors be held liable for any damages arising from the use of
-- this software.
--
-- Permission is granted to anyone to use this software for any purpose, including
-- commercial applications, and to alter it and redistribute it freely, subject to the
-- following restrictions:
--
-- 1. The origin of this software must not be misrepresented; you must not
-- claim that you wrote the original software. If you use this software in a
-- product, an acknowledgment in the product documentation is required.
-- 2. Altered source versions must be plainly marked as such, and must not
-- be misrepresented as being the original software.
-- 3. This notice may not be removed or altered from any source distribution.
--
-- Following Code (everything before fill_chest) by Amoeba <amoeba@iki.fi>
dungeon_loot = {}
dungeon_loot.version = 1.2
-- Load other file(s)
local modpath = minetest.get_modpath(minetest.get_current_modname())
dofile(modpath.."/config.lua") -- All the constants for simple tuning
dungeon_loot.CHESTS_MIN = 1
dungeon_loot.CHESTS_MAX = 3
dungeon_loot.STACKS_PER_CHEST_MAX = 8
local function get_max_loot(loot_list, depth)
local loot_type = loot_list[1].name
local loot_min_depth = loot_list[1].min_depth
for i,v in ipairs(loot_list) do
if v.min_depth < depth then
loot_type = v.name
loot_min_depth = v.min_depth
else
break
end
end
return loot_type, loot_min_depth
end
local function get_basic_loot(loot_list, depth)
local loot_type = ""
local loot_amount = 0
local total_chance = 0
for i,v in ipairs(loot_list) do
if v.chance_and_amount then
total_chance = total_chance + v.chance_and_amount
elseif v.chance then
total_chance = total_chance + v.chance
else
error("No chance_and_amount or chance found in basic_list table.")
return nil, 0
end
end
local leftover = math.random(1,total_chance)
local type_amount = 0
for i,v in ipairs(loot_list) do
if v.chance_and_amount then
leftover = leftover - v.chance_and_amount
elseif v.chance then
leftover = leftover - v.chance
end
if leftover < 1 then
loot_type = v.name
if v.chance_and_amount then
type_amount = v.chance_and_amount
else
type_amount = v.amount
end
break
end
end
if loot_type == "" then -- Paranoia
error("Unable to choose a loot_type from basic_list table.")
return nil, 0
end
loot_amount = math.random(1,math.ceil(type_amount/2))
if depth > dungeon_loot.depth_first_basic_increase then
loot_amount = math.random(1,type_amount)
end
if depth > dungeon_loot.depth_second_basic_increase then
loot_amount = math.random(1,type_amount*2)
end
return loot_type, loot_amount
end
local function get_item_and_amount(list_item, actual_depth)
if list_item.chance < math.random() then
return nil, 0
end
-- Suspicious trickery
list_name = nil
list_name_string = "dungeon_loot." .. list_item.name .. "_list"
-- list_name = _G[list_name_string]
lsf = loadstring("list_name = " .. list_name_string)
lsf()
if list_name == nil then
error("Unable to connect " .. list_name_string .. " to actual table")
return nil, 0
end
local amount = 0
local loot_type = ""
local loot_depth = 0
local max_depth = 1
if actual_depth < 0 then
max_depth = math.ceil(math.abs(actual_depth))
end
if list_item.type == "depth_cutoff" then
local rnd_depth = math.random(1,max_depth)
loot_type, loot_depth = get_max_loot(list_name, rnd_depth)
if list_item.max_amount == 1 then -- For tools & weapons
amount = 1
else
-- Stop large amounts of the first item
if loot_depth < 1 then
loot_depth = 5
end
local leftover = rnd_depth
while leftover > 0 do
amount = amount + 1
leftover = leftover - math.random(1,loot_depth)
leftover = leftover - math.ceil(loot_depth/2)
end
end
elseif list_item.type == "basic_list" then
loot_type, amount = get_basic_loot(list_name, max_depth)
else
error("Got unknown loot table type " .. list_item.type)
loot_type = nil
end
-- Hey, if you leave out the max_amount, you deserve what you get
if list_item.max_amount and amount > list_item.max_amount then
amount = list_item.max_amount
end
return loot_type, amount
end
local function fill_chest(pos)
minetest.after(2, function()
local n = minetest.get_node(pos)
if n and n.name and n.name == "default:chest" then
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
--inv:set_size("main", 8*4)
for i,v in ipairs(dungeon_loot.loot_types) do
local item, num = get_item_and_amount(v,pos.y)
if item then
local stack = ItemStack({name = item, count = num, wear = 0, metadata = ""})
inv:set_stack("main",i,stack)
end
end
end
end)
end
-- Place chest in dungeons
local function place_spawner(tab)
if tab == nil or #tab < 1 then
return
end
local pos = tab[math.random(1, #tab)]
pos.y = pos.y - 1
local below = core.get_node_or_nil(pos)
if below and below.name ~= "air" then
pos.y = pos.y + 1
core.set_node(pos, {name = "default:chest"})
fill_chest(pos)
end
end
core.set_gen_notify("dungeon")
core.register_on_generated(function(minp, maxp, blockseed)
local ntf = core.get_mapgen_object("gennotify")
if ntf and ntf.dungeon and #ntf.dungeon >= dungeon_loot.min_num_of_rooms then
core.after(3, place_spawner, table.copy(ntf.dungeon))
end
end)
dofile(minetest.get_modpath("dungeon_loot") .. "/loot.lua")
dofile(minetest.get_modpath("dungeon_loot") .. "/mapgen.lua")

View File

@ -0,0 +1,81 @@
dungeon_loot.registered_loot = {
-- buckets
{name = "bucket:bucket_empty", chance = 0.55},
-- water in deserts or above ground, lava otherwise
{name = "bucket:bucket_water", chance = 0.45, types = {"sandstone", "desert"}},
{name = "bucket:bucket_water", chance = 0.45, y = {0, 256}, types = {"normal"}},
{name = "bucket:bucket_lava", chance = 0.45, y = {-64, -1}, types = {"normal"}},
-- various items
{name = "default:stick", chance = 0.6, count = {3, 6}},
{name = "default:flint", chance = 0.4, count = {1, 3}},
{name = "vessels:glass_bottle", chance = 0.35, count = {1, 4}},
-- {name = "carts:rail", chance = 0.35, count = {1, 6}},
-- farming / consumable
{name = "farming:string", chance = 0.5, count = {1, 8}},
{name = "farming:wheat", chance = 0.5, count = {2, 5}},
{name = "default:apple", chance = 0.4, count = {1, 4}},
-- {name = "farming:seed_cotton", chance = 0.4, count = {1, 4}, types = {"normal"}},
{name = "default:cactus", chance = 0.4, count = {1, 4}, types = {"sandstone", "desert"}},
-- trees sappling
{name = "default:sapling", chance = 0.5, count = {1, 2}},
{name = "default:pine_sapling", chance = 0.5, count = {1, 2}},
{name = "default:junglesapling", chance = 0.5, count = {1, 2}},
{name = "default:acacia_sapling", chance = 0.5, count = {1, 2}},
-- 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:diamond", chance = 0.15, count = {1, 2}},
{name = "default:emerald", chance = 0.1, count = {1, 2}},
-- tools
{name = "default:sword_steel", chance = 0.6},
{name = "default:sword_gold", chance = 0.3},
{name = "default:sword_diamond", chance = 0.05},
{name = "default:pick_steel", chance = 0.3},
{name = "default:pick_gold", chance = 0.2},
{name = "default:pick_diamond", chance = 0.05},
{name = "default:shovel_steel", chance = 0.3},
{name = "default:shovel_gold", chance = 0.2},
{name = "default:shovel_diamond", chance = 0.05},
{name = "default:axe_steel", chance = 0.4},
{name = "default:axe_gold", chance = 0.2},
{name = "default:axe_diamond", chance = 0.05},
-- natural materials
{name = "default:sand", chance = 0.8, count = {4, 32}, y = {-64, 256}, types = {"normal"}},
{name = "default:sandstonesmooth", chance = 0.8, count = {4, 32}, y = {-64, 256}, types = {"sandstone"}},
{name = "default:mossycobble", chance = 0.8, count = {4, 32}, types = {"desert"}},
{name = "default:dirt", chance = 0.6, count = {2, 16}, y = {-64, 256}},
{name = "default:obsidian", chance = 0.25, count = {1, 3}, y = {-64, -512}},
}
function dungeon_loot.register(t)
if t.name ~= nil then
t = {t} -- single entry
end
for _, loot in ipairs(t) do
table.insert(dungeon_loot.registered_loot, loot)
end
end
function dungeon_loot._internal_get_loot(pos_y, dungeontype)
-- filter by y pos and type
local ret = {}
for _, l in ipairs(dungeon_loot.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

View File

@ -0,0 +1,170 @@
minetest.set_gen_notify({dungeon = true, temple = true})
local function noise3d_integer(noise, pos)
return math.abs(math.floor(noise:get3d(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)
local wall = minetest.registered_aliases["mapgen_cobble"]
local wall_alt = minetest.registered_aliases["mapgen_mossycobble"]
local wall_ss = minetest.registered_aliases["mapgen_sandstonebrick"]
local wall_ds = minetest.registered_aliases["mapgen_desert_stone"]
local is_wall = function(node)
return table.indexof({wall, wall_alt, wall_ss, wall_ds}, node.name) ~= -1
end
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
local wallnode
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
wallnode = node.name
end
-- abort even if it wasn't a wall cause something is in the way
break
end
end
end
local mapping = {
[wall_ss] = "sandstone",
[wall_ds] = "desert"
}
return {
walls = ret,
size = {x=mindist.x*2, z=mindist.z*2},
type = mapping[wallnode] or "normal"
}
end
local function populate_chest(pos, rand, dungeontype)
--minetest.chat_send_all("chest placed at " .. minetest.pos_to_string(pos) .. " [" .. dungeontype .. "]")
--minetest.add_node(vector.add(pos, {x=0, y=1, z=0}), {name="default:torch", param2=1})
local item_list = dungeon_loot._internal_get_loot(pos.y, dungeontype)
-- take random (partial) sample of all possible items
assert(#item_list >= dungeon_loot.STACKS_PER_CHEST_MAX)
item_list = random_sample(rand, item_list, dungeon_loot.STACKS_PER_CHEST_MAX)
-- 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 = minetest.registered_items[loot.name]
local amount = 1
if loot.count ~= nil then
amount = rand:next(loot.count[1], loot.count[2])
end
if itemdef then
if 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
end
-- place items at random places in chest
local inv = minetest.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
minetest.register_on_generated(function(minp, maxp, blockseed)
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(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])
-- skip small rooms and everything that doesn't at least have 3 walls
if math.min(room.size.x, room.size.z) >= 2 and #room.walls >= 3 then
table.insert(candidates, room)
end
end
local num_chests = rand:next(dungeon_loot.CHESTS_MIN, dungeon_loot.CHESTS_MAX)
num_chests = math.min(#candidates, num_chests)
local rooms = random_sample(rand, candidates, num_chests)
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 chestpos = vector.add(wall.pos, wall.facing)
local off = rand:next(-room.size[vi]/2 + 1, room.size[vi]/2 - 1)
chestpos = vector.add(chestpos, vector.multiply(v, off))
if minetest.get_node(chestpos).name == "air" then
-- make it face inwards to the room
local facedir = minetest.dir_to_facedir(vector.multiply(wall.facing, -1))
minetest.add_node(chestpos, {name = "default:chest", param2 = facedir})
populate_chest(chestpos, PcgRandom(noise3d_integer(noise, chestpos)), room.type)
end
end
end)

View File

@ -35,18 +35,20 @@ for _, row in ipairs(dye.dyes) do
})
minetest.register_craft({
type = "shapeless",
output = "dye:" .. name .. " 4",
recipe = {"group:flower,color_" .. name},
recipe = {
{"group:flower,color_" .. name}
},
})
end
-- Manually add coal -> black dye
minetest.register_craft({
type = "shapeless",
output = "dye:black 4",
recipe = {"group:coal"},
recipe = {
{"group:coal"}
},
})
-- Mix recipes

View File

@ -1,28 +1,37 @@
-- Global namespace for functions
fire = {}
fire = {
mod = "redo",
}
-- 'Enable fire' setting
-- Particle effects
local fire_enabled = minetest.settings:get_bool("enable_fire")
if fire_enabled == nil then
-- enable_fire setting not specified, check for disable_fire
local fire_disabled = minetest.settings:get_bool("disable_fire")
if fire_disabled == nil then
-- Neither setting specified, check whether singleplayer
fire_enabled = minetest.is_singleplayer()
else
fire_enabled = not fire_disabled
end
end
local function add_effect(pos)
--
-- Items
--
minetest.add_particlespawner({
amount = 1,
time = 0.25,
minpos = pos,
maxpos = pos,
minvel = {x = -1, y = 2, z = -1},
maxvel = {x = 1, y = 4, z = 1},
minacc = {x = 0, y = 0, z = 0},
maxacc = {x = 0, y = 0, z = 0},
minexptime = 1,
maxexptime = 3,
minsize = 2,
maxsize = 5,
texture = "tnt_smoke.png",
})
-- Flood flame function
local function flood_flame(pos, oldnode, newnode)
-- Play flame extinguish sound if liquid is not an 'igniter'
local nodedef = minetest.registered_items[newnode.name]
if not (nodedef and nodedef.groups and
nodedef.groups.igniter and nodedef.groups.igniter > 0) then
minetest.sound_play("fire_extinguish_flame",
{pos = pos, max_hear_distance = 16, gain = 0.15})
end
-- Remove the flame
return false
end
-- Flame nodes
@ -46,14 +55,15 @@ minetest.register_node("fire:basic_flame", {
walkable = false,
buildable_to = true,
sunlight_propagates = true,
floodable = true,
damage_per_second = 4,
groups = {igniter = 2, dig_immediate = 3, not_in_creative_inventory = 1},
drop = {},
drop = "",
on_timer = function(pos)
local f = minetest.find_node_near(pos, 1, {"group:flammable"})
if not f then
-- minetest.remove_node(pos)
minetest.swap_node(pos, {name = "air"})
if not fire_enabled or not f then
minetest.remove_node(pos)
return
end
-- Restart timer
@ -61,16 +71,14 @@ minetest.register_node("fire:basic_flame", {
end,
on_construct = function(pos)
minetest.get_node_timer(pos):start(math.random(30, 60))
-- minetest.after(0, fire.update_sounds_around, pos)
if not fire_enabled then
minetest.remove_node(pos)
else
minetest.get_node_timer(pos):start(math.random(30, 60))
end
end,
-- on_destruct = function(pos)
-- minetest.after(0, fire.update_sounds_around, pos)
-- end,
on_blast = function()
end, -- unaffected by explosions
on_flood = flood_flame,
})
minetest.register_node("fire:permanent_flame", {
@ -93,14 +101,15 @@ minetest.register_node("fire:permanent_flame", {
walkable = false,
buildable_to = true,
sunlight_propagates = true,
floodable = true,
damage_per_second = 4,
groups = {igniter = 2, dig_immediate = 3},
drop = {},
drop = "",
on_blast = function()
end,
on_flood = flood_flame,
})
-- Flint and steel
minetest.register_tool("fire:flint_and_steel", {
@ -153,130 +162,154 @@ minetest.register_craft({
}
})
-- Override coalblock to enable permanent flame above
-- Coalblock is non-flammable to avoid unwanted basic_flame nodes
--minetest.override_item("default:coalblock", {
-- after_destruct = function(pos, oldnode)
-- pos.y = pos.y + 1
-- if minetest.get_node(pos).name == "fire:permanent_flame" then
-- minetest.remove_node(pos)
-- minetest.swap_node(pos, {name = "air"})
-- end
-- end,
--})
--[[minetest.override_item("default:coalblock", {
after_destruct = function(pos, oldnode)
pos.y = pos.y + 1
if minetest.get_node(pos).name == "fire:permanent_flame" then
minetest.remove_node(pos)
end
end,
on_ignite = function(pos, igniter)
local flame_pos = {x = pos.x, y = pos.y + 1, z = pos.z}
if minetest.get_node(flame_pos).name == "air" then
minetest.set_node(flame_pos, {name = "fire:permanent_flame"})
end
end,
})]]--
-- Get sound area of position
--
-- Sound
--
fire.D = 6 -- size of sound areas
local flame_sound = minetest.settings:get_bool("flame_sound")
if flame_sound == nil then
-- Enable if no setting present
flame_sound = true
end
function fire.get_area_p0p1(pos)
local p0 = {
x = math.floor(pos.x / fire.D) * fire.D,
y = math.floor(pos.y / fire.D) * fire.D,
z = math.floor(pos.z / fire.D) * fire.D,
}
local p1 = {
x = p0.x + fire.D - 1,
y = p0.y + fire.D - 1,
z = p0.z + fire.D - 1
}
return p0, p1
if flame_sound then
local handles = {}
local timer = 0
-- Parameters
local radius = 8 -- Flame node search radius around player
local cycle = 3 -- Cycle time for sound updates
-- Update sound for player
function fire.update_player_sound(player)
local player_name = player:get_player_name()
-- Search for flame nodes in radius around player
local ppos = player:get_pos()
local areamin = vector.subtract(ppos, radius)
local areamax = vector.add(ppos, radius)
local fpos, num = minetest.find_nodes_in_area(
areamin,
areamax,
{"fire:basic_flame", "fire:permanent_flame"}
)
-- Total number of flames in radius
local flames = (num["fire:basic_flame"] or 0) +
(num["fire:permanent_flame"] or 0)
-- Stop previous sound
if handles[player_name] then
minetest.sound_stop(handles[player_name])
handles[player_name] = nil
end
-- If flames
if flames > 0 then
-- Find centre of flame positions
local fposmid = fpos[1]
-- If more than 1 flame
if #fpos > 1 then
local fposmin = areamax
local fposmax = areamin
for i = 1, #fpos do
local fposi = fpos[i]
if fposi.x > fposmax.x then
fposmax.x = fposi.x
end
if fposi.y > fposmax.y then
fposmax.y = fposi.y
end
if fposi.z > fposmax.z then
fposmax.z = fposi.z
end
if fposi.x < fposmin.x then
fposmin.x = fposi.x
end
if fposi.y < fposmin.y then
fposmin.y = fposi.y
end
if fposi.z < fposmin.z then
fposmin.z = fposi.z
end
end
fposmid = vector.divide(vector.add(fposmin, fposmax), 2)
end
-- Play sound
local handle = minetest.sound_play(
"fire_fire",
{
pos = fposmid,
to_player = player_name,
gain = math.min(0.06 * (1 + flames * 0.125), 0.18),
max_hear_distance = 32,
loop = true, -- In case of lag
}
)
-- Store sound handle for this player
if handle then
handles[player_name] = handle
end
end
end
-- Cycle for updating players sounds
minetest.register_globalstep(function(dtime)
timer = timer + dtime
if timer < cycle then
return
end
timer = 0
local players = minetest.get_connected_players()
for n = 1, #players do
fire.update_player_sound(players[n])
end
end)
-- Stop sound and clear handle on player leave
minetest.register_on_leaveplayer(function(player)
local player_name = player:get_player_name()
if handles[player_name] then
minetest.sound_stop(handles[player_name])
handles[player_name] = nil
end
end)
end
-- Fire sounds table
-- key: position hash of low corner of area
-- value: {handle=sound handle, name=sound name}
fire.sounds = {}
-- Update fire sounds in sound area of position
-- Deprecated function kept temporarily to avoid crashes if mod fire nodes call it
function fire.update_sounds_around(pos)
local p0, p1 = fire.get_area_p0p1(pos)
local cp = {x = (p0.x + p1.x) / 2, y = (p0.y + p1.y) / 2, z = (p0.z + p1.z) / 2}
local flames_p = minetest.find_nodes_in_area(p0, p1, {"fire:basic_flame"})
--print("number of flames at "..minetest.pos_to_string(p0).."/"
-- ..minetest.pos_to_string(p1)..": "..#flames_p)
local should_have_sound = (#flames_p > 0)
local wanted_sound = nil
if #flames_p >= 9 then
wanted_sound = {name = "fire_large", gain = 0.7}
elseif #flames_p > 0 then
wanted_sound = {name = "fire_small", gain = 0.9}
end
local p0_hash = minetest.hash_node_position(p0)
local sound = fire.sounds[p0_hash]
if not sound then
if should_have_sound then
fire.sounds[p0_hash] = {
handle = minetest.sound_play(wanted_sound,
{pos = cp, max_hear_distance = 16, loop = true}),
name = wanted_sound.name,
}
end
else
if not wanted_sound then
minetest.sound_stop(sound.handle)
fire.sounds[p0_hash] = nil
elseif sound.name ~= wanted_sound.name then
minetest.sound_stop(sound.handle)
fire.sounds[p0_hash] = {
handle = minetest.sound_play(wanted_sound,
{pos = cp, max_hear_distance = 16, loop = true}),
name = wanted_sound.name,
}
end
end
end
-- Extinguish all flames quickly with water, snow, ice
--
-- ABMs
--
minetest.register_abm({
label = "Extinguish flame",
nodenames = {"fire:basic_flame", "fire:permanent_flame"},
neighbors = {"group:puts_out_fire"},
interval = 3,
chance = 1,
catch_up = false,
action = function(pos, node, active_object_count, active_object_count_wider)
-- minetest.remove_node(pos)
minetest.swap_node(pos, {name = "air"})
minetest.sound_play("fire_extinguish_flame",
{pos = pos, max_hear_distance = 16, gain = 0.25})
end,
})
-- Enable the following ABMs according to 'enable fire' setting
local fire_enabled = minetest.setting_getbool("enable_fire")
if fire_enabled == nil then
-- New setting not specified, check for old setting.
-- If old setting is also not specified, 'not nil' is true.
fire_enabled = not minetest.setting_getbool("disable_fire")
end
if not fire_enabled then
-- Remove basic flames only
minetest.register_abm({
label = "Remove disabled fire",
nodenames = {"fire:basic_flame"},
interval = 7,
chance = 1,
catch_up = false,
action = function(pos, node, active_object_count, active_object_count_wider)
-- minetest.remove_node(pos)
minetest.swap_node(pos, {name = "air"})
end,
})
else -- Fire enabled
if fire_enabled then
-- Ignite neighboring nodes, add basic flames
@ -287,20 +320,15 @@ else -- Fire enabled
interval = 7,
chance = 12,
catch_up = false,
action = function(pos, node, active_object_count, active_object_count_wider)
-- If there is water or stuff like that around node, don't ignite
if minetest.find_node_near(pos, 1, {"group:puts_out_fire"}) then
return
end
action = function(pos)
local p = minetest.find_node_near(pos, 1, {"air"})
if p then
minetest.swap_node(p, {name = "fire:basic_flame"})
-- minetest.set_node(p, {name = "fire:basic_flame"})
minetest.set_node(p, {name = "fire:basic_flame"})
end
end,
})
-- Remove flammable nodes
-- Remove flammable nodes around basic flame
minetest.register_abm({
label = "Remove flammable nodes",
@ -309,85 +337,34 @@ else -- Fire enabled
interval = 5,
chance = 18,
catch_up = false,
action = function(pos, node, active_object_count, active_object_count_wider)
local p = minetest.find_node_near(pos, 1, {"group:flammable"})
if p then
-- remove flammable nodes around flame
action = function(pos)
local p = minetest.find_node_near(pos, 1, {"group:flammable"})
if not p then
return
end
local flammable_node = minetest.get_node(p)
local def = minetest.registered_nodes[flammable_node.name]
if def.on_burn then
def.on_burn(p)
else
-- minetest.remove_node(p)
add_effect(p)
minetest.swap_node(p, {name = "air"})
nodeupdate(p)
minetest.remove_node(p)
minetest.add_particlespawner({
amount = 3,
time = 0.1,
minpos = {x = p.x - 0.1, y = p.y + 0.1, z = p.z - 0.1 },
maxpos = {x = p.x + 0.1, y = p.y + 0.2, z = p.z + 0.1 },
minvel = {x = 0, y = 2.5, z = 0},
maxvel = {x = 0, y = 2.5, z = 0},
minacc = {x = -0.15, y = -0.02, z = -0.15},
maxacc = {x = 0.15, y = -0.01, z = 0.15},
minexptime = 4,
maxexptime = 6,
minsize = 2,
maxsize = 4,
})
minetest.check_for_falling(p)
end
end
end,
})
end
-- Rarely ignite things from far
--[[ Currently disabled to reduce the chance of uncontrollable spreading
fires that disrupt servers. Also for less lua processing load.
minetest.register_abm({
nodenames = {"group:igniter"},
neighbors = {"air"},
interval = 5,
chance = 10,
action = function(pos, node, active_object_count, active_object_count_wider)
local reg = minetest.registered_nodes[node.name]
if not reg or not reg.groups.igniter or reg.groups.igniter < 2 then
return
end
local d = reg.groups.igniter
local p = minetest.find_node_near(pos, d, {"group:flammable"})
if p then
-- If there is water or stuff like that around flame, don't ignite
if fire.flame_should_extinguish(p) then
return
end
local p2 = fire.find_pos_for_flame_around(p)
if p2 then
minetest.set_node(p2, {name = "fire:basic_flame"})
end
end
end,
})
--]]
-- used to drop items inside a chest or container
function fire.drop_items(pos, invstring)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
for i = 1, inv:get_size(invstring) do
local m_stack = inv:get_stack(invstring, i)
local obj = minetest.add_item(pos, m_stack)
if obj then
obj:set_velocity({
x = math.random(-10, 10) / 9,
y = 1,
z = math.random(-10, 10) / 9
})
end
end
end
-- override chest node so that it's flammable
minetest.override_item("default:chest", {
groups = {choppy = 2, oddly_breakable_by_hand = 2, flammable = 3},
on_burn = function(p)
fire.drop_items(p, "main")
minetest.remove_node(p)
end,
})

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -142,11 +142,14 @@ function flowers.flower_spread(pos, node)
if num_soils >= 1 then
for si = 1, math.min(3, num_soils) do
local soil = soils[math.random(num_soils)]
local soil_name = minetest.get_node(soil).name
local soil_above = {x = soil.x, y = soil.y + 1, z = soil.z}
light = minetest.get_node_light(soil_above)
if light and light >= 13 and
-- Only spread to same surface node
soil_name == under.name and
-- Desert sand is in the soil group
minetest.get_node(soil).name ~= "default:desert_sand" then
soil_name ~= "default:desert_sand" then
minetest.set_node(soil_above, {name = node.name})
end
end
@ -197,7 +200,7 @@ minetest.register_node("flowers:mushroom_brown", {
sunlight_propagates = true,
walkable = false,
buildable_to = true,
groups = {snappy = 3, attached_node = 1, flammable = 1},
groups = {food_mushroom = 1, snappy = 3, attached_node = 1, flammable = 1},
sounds = default.node_sound_leaves_defaults(),
on_use = minetest.item_eat(1),
selection_box = {
@ -210,8 +213,10 @@ minetest.register_node("flowers:mushroom_brown", {
-- Mushroom spread and death
function flowers.mushroom_spread(pos, node)
if minetest.get_node_light(pos, 0.5) > 3 then
if minetest.get_node_light(pos, nil) == 15 then
minetest.remove_node(pos)
end
return
end
local positions = minetest.find_nodes_in_area_under_air(
@ -223,8 +228,7 @@ function flowers.mushroom_spread(pos, node)
end
local pos2 = positions[math.random(#positions)]
pos2.y = pos2.y + 1
if minetest.get_node_light(pos, 0.5) <= 3 and
minetest.get_node_light(pos2, 0.5) <= 3 then
if minetest.get_node_light(pos2, 0.5) <= 3 then
minetest.set_node(pos2, {name = node.name})
end
end
@ -265,7 +269,6 @@ minetest.register_node("flowers:waterlily", {
liquids_pointable = true,
walkable = false,
buildable_to = true,
sunlight_propagates = true,
floodable = true,
groups = {snappy = 3, flower = 1, flammable = 1},
sounds = default.node_sound_leaves_defaults(),

View File

@ -32,6 +32,7 @@ Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0)
Copyright (C) 2014-2016 RHRhino
Copyright (C) 2015-2016 Gambit
Copyright (C) 2016 yyt16384
Copyright (C) 2017 paramat
You are free to:
Share — copy and redistribute the material in any medium or format.

View File

@ -2,8 +2,9 @@
-- Mgv6
--
local function register_mgv6_flower(name)
local function register_mgv6_flower(flower_name)
minetest.register_decoration({
name = "flowers:"..flower_name,
deco_type = "simple",
place_on = {"default:dirt_with_grass"},
sidelen = 16,
@ -15,14 +16,15 @@ local function register_mgv6_flower(name)
octaves = 3,
persist = 0.6
},
y_min = 1,
y_max = 30,
decoration = "flowers:"..name,
y_min = 1,
decoration = "flowers:"..flower_name,
})
end
local function register_mgv6_mushroom(name)
local function register_mgv6_mushroom(mushroom_name)
minetest.register_decoration({
name = "flowers:"..mushroom_name,
deco_type = "simple",
place_on = {"default:dirt_with_grass"},
sidelen = 16,
@ -34,9 +36,9 @@ local function register_mgv6_mushroom(name)
octaves = 3,
persist = 0.6
},
y_min = 1,
y_max = 30,
decoration = "flowers:"..name,
y_min = 1,
decoration = "flowers:"..mushroom_name,
spawn_by = "default:tree",
num_spawn_by = 1,
})
@ -44,7 +46,8 @@ end
local function register_mgv6_waterlily()
minetest.register_decoration({
deco_type = "schematic",
name = "flowers:waterlily",
deco_type = "simple",
place_on = {"default:dirt"},
sidelen = 16,
noise_params = {
@ -55,10 +58,12 @@ local function register_mgv6_waterlily()
octaves = 3,
persist = 0.7
},
y_min = 0,
y_max = 0,
schematic = minetest.get_modpath("flowers").."/schematics/waterlily.mts",
rotation = "random",
y_min = 0,
decoration = "flowers:waterlily",
param2 = 0,
param2_max = 3,
place_offset_y = 1,
})
end
@ -81,14 +86,15 @@ end
-- All other biome API mapgens
--
local function register_flower(seed, name)
local function register_flower(seed, flower_name)
minetest.register_decoration({
name = "flowers:"..flower_name,
deco_type = "simple",
place_on = {"default:dirt_with_grass"},
sidelen = 16,
noise_params = {
offset = -0.015,
scale = 0.025,
offset = -0.02,
scale = 0.04,
spread = {x = 200, y = 200, z = 200},
seed = seed,
octaves = 3,
@ -96,14 +102,15 @@ local function register_flower(seed, name)
},
biomes = {"stone_grassland", "sandstone_grassland",
"deciduous_forest", "coniferous_forest", "floatland_grassland", "floatland_coniferous_forest"},
y_min = 1,
y_max = 31000,
decoration = "flowers:"..name,
y_min = 1,
decoration = "flowers:"..flower_name,
})
end
local function register_mushroom(name)
local function register_mushroom(mushroom_name)
minetest.register_decoration({
name = "flowers:"..mushroom_name,
deco_type = "simple",
place_on = {"default:dirt_with_grass"},
sidelen = 16,
@ -117,15 +124,16 @@ local function register_mushroom(name)
},
biomes = {"deciduous_forest", "coniferous_forest",
"floatland_coniferous_forest"},
y_min = 1,
y_max = 31000,
decoration = "flowers:"..name,
y_min = 1,
decoration = "flowers:"..mushroom_name,
})
end
local function register_waterlily()
minetest.register_decoration({
deco_type = "schematic",
name = "default:waterlily",
deco_type = "simple",
place_on = {"default:dirt"},
sidelen = 16,
noise_params = {
@ -137,10 +145,12 @@ local function register_waterlily()
persist = 0.7
},
biomes = {"rainforest_swamp", "savanna_shore", "deciduous_forest_shore"},
y_min = 0,
y_max = 0,
schematic = minetest.get_modpath("flowers").."/schematics/waterlily.mts",
rotation = "random",
y_min = 0,
decoration = "flowers:waterlily",
param2 = 0,
param2_max = 3,
place_offset_y = 1,
})
end

View File

@ -208,7 +208,7 @@ mobs:spawn({
nodes = {"default:dirt", "default:sand", "default:redsand", "default:snow", "default:snowblock", "default:dirt_with_snow", "default:dirt_with_grass"},
min_light = 5,
interval = 30,
chance = 20000,
chance = 30000,
min_height = 0,
max_height = 31000,
day_toggle = true,
@ -219,7 +219,7 @@ mobs:spawn({
nodes = {"default:dirt", "default:sand", "default:redsand", "default:snow", "default:snowblock", "default:dirt_with_snow", "default:dirt_with_grass"},
min_light = 5,
interval = 30,
chance = 20000,
chance = 30000,
min_height = 0,
max_height = 31000,
day_toggle = true,
@ -229,7 +229,7 @@ mobs:spawn({
name = "mobs_animal:sheep_dark_grey",
nodes = {"default:dirt", "default:sand", "default:redsand", "default:snow", "default:snowblock", "default:dirt_with_snow", "default:dirt_with_grass"},
interval = 30,
chance = 20000,
chance = 30000,
min_height = 0,
max_height = 31000,
day_toggle = true,
@ -240,7 +240,7 @@ mobs:spawn({
nodes = {"default:dirt", "default:sand", "default:redsand", "default:snow", "default:snowblock", "default:dirt_with_snow", "default:dirt_with_grass"},
min_light = 5,
interval = 30,
chance = 20000,
chance = 30000,
min_height = 0,
max_height = 31000,
day_toggle = true,
@ -251,7 +251,7 @@ mobs:spawn({
nodes = {"default:dirt", "default:sand", "default:redsand", "default:snow", "default:snowblock", "default:dirt_with_snow", "default:dirt_with_grass"},
min_light = 5,
interval = 30,
chance = 20000,
chance = 30000,
min_height = 0,
max_height = 31000,
day_toggle = true,

View File

@ -1,6 +1,8 @@
-- Mobs Api
local use_cmi = minetest.global_exists("cmi")
mobs = {
mod = "redo",
version = "20190402",
@ -777,7 +779,7 @@ function mob_class:check_for_death(cmi_cause)
self.object:remove()
end
-- effect(pos, 20, "tnt_smoke.png")
-- effect(pos, 20, "item_smoke.png")
return true
end
@ -859,8 +861,10 @@ function mob_class:do_env_damage()
and light <= self.light_damage_max then
self.health = self.health - self.light_damage
-- effect(pos, 5, "tnt_smoke.png")
pos.y = pos.y + 0.75 -- for particle effect position
effect(pos, 5, "heart.png")
self.nametag = "Health: " .. self.health .. " / " .. self.hp_max
self:update_tag()
if self:check_for_death({type = "light"}) then return end
end
@ -906,7 +910,7 @@ function mob_class:do_env_damage()
self.health = self.health - nodef.damage_per_second
effect(pos, 5, "tnt_smoke.png")
effect(pos, 5, "item_smoke.png")
if self:check_for_death({type = "environment",
pos = pos, node = self.standing_in}) then return end
@ -1211,7 +1215,7 @@ function mob_class:breed()
return
end
else
effect(pos, 15, "tnt_smoke.png", 1, 2, 2, 15, 5)
effect(pos, 15, "item_smoke.png", 1, 2, 2, 15, 5)
end
local mob = minetest.add_entity(pos, self.name)
@ -2528,7 +2532,7 @@ function mob_class:falling(pos)
self.health = self.health - floor(d - 5)
-- effect(pos, 5, "tnt_smoke.png", 1, 2, 2, nil)
-- effect(pos, 5, "item_smoke.png", 1, 2, 2, nil)
if self:check_for_death({type = "fall"}) then
return
@ -3046,7 +3050,7 @@ function mob_class:mob_expire(pos, dtime)
-- minetest.log("action",
-- "lifetimer expired, removed @1", self.name)
-- effect(pos, 15, "tnt_smoke.png", 2, 4, 2, 0)
-- effect(pos, 15, "item_smoke.png", 2, 4, 2, 0)
self.object:remove()
@ -3684,7 +3688,7 @@ function mobs:safe_boom(self, pos, radius)
entity_physics(pos, radius)
-- effect(pos, 32, "tnt_smoke.png", radius * 3, radius * 5, radius, 1, 0)
-- effect(pos, 32, "item_smoke.png", radius * 3, radius * 5, radius, 1, 0)
end

View File

@ -0,0 +1,21 @@
Minetest Game mod: player_api
=============================
See license.txt for license information.
Provides an API to allow multiple mods to set player models and textures.
Also sets the default model, texture, and player flags.
Authors of source code
----------------------
Originally by celeron55, Perttu Ahola <celeron55@gmail.com> (LGPLv3.0+)
Various Minetest developers and contributors (LGPLv3.0+)
Authors of media (textures, models and sounds)
----------------------------------------------
stujones11 (CC BY-SA 3.0):
character.b3d
character.blend -- Both derived from a model by MirceaKitsune (CC BY-SA 3.0)
sonictechtonic (CC BY 3.0):
https://www.freesound.org/people/sonictechtonic/sounds/241872/
player_damage.ogg

View File

@ -1,43 +1,29 @@
-- MultiCraft mod: player
-- See README.txt for licensing and other information.
player_api = {}
-- Player animation blending
-- Note: This is currently broken due to a bug in Irrlicht, leave at 0
local animation_blend = 0
default.registered_player_models = { }
player_api.registered_models = { }
-- Local for speed.
local models = default.registered_player_models
local models = player_api.registered_models
function default.player_register_model(name, def)
function player_api.register_model(name, def)
models[name] = def
end
-- Default player appearance
default.player_register_model("character.b3d", {
animation_speed = 30,
textures = {"character.png", },
animations = {
-- Standard animations.
stand = { x= 0, y= 79, },
lay = { x=162, y=166, },
walk = { x=168, y=187, },
mine = { x=189, y=198, },
walk_mine = { x=200, y=219, },
-- Extra animations (not currently used by the game).
sit = { x= 81, y=160, },
},
})
-- Player stats and animations
local player_model = {}
local player_textures = {}
local player_anim = {}
local player_sneak = {}
default.player_attached = {}
player_api.player_attached = {}
function default.player_get_animation(player)
function player_api.get_animation(player)
local name = player:get_player_name()
return {
model = player_model[name],
@ -47,7 +33,7 @@ function default.player_get_animation(player)
end
-- Called when a player's appearance needs to be updated
function default.player_set_model(player, model_name)
function player_api.set_model(player, model_name)
local name = player:get_player_name()
local model = models[model_name]
if model then
@ -58,25 +44,32 @@ function default.player_set_model(player, model_name)
mesh = model_name,
textures = player_textures[name] or model.textures,
visual = "mesh",
visual_size = model.visual_size or {x=1, y=1},
visual_size = model.visual_size or {x = 1, y = 1},
collisionbox = model.collisionbox or {-0.3, 0.0, -0.3, 0.3, 1.7, 0.3},
stepheight = model.stepheight or 0.6,
eye_height = model.eye_height or 1.47,
})
default.player_set_animation(player, "stand")
player_api.set_animation(player, "stand")
else
player:set_properties({
textures = { "player.png", "player_back.png", },
visual = "upright_sprite",
collisionbox = {-0.3, 0.0, -0.3, 0.3, 1.75, 0.3},
stepheight = 0.6,
eye_height = 1.625,
})
end
player_model[name] = model_name
end
function default.player_set_textures(player, textures)
function player_api.set_textures(player, textures)
local name = player:get_player_name()
player_textures[name] = textures
player:set_properties({textures = textures,})
local model = models[player_model[name]]
local model_textures = model and model.textures or nil
player_textures[name] = textures or model_textures
player:set_properties({textures = textures or model_textures,})
end
function default.player_set_animation(player, anim_name, speed)
function player_api.set_animation(player, anim_name, speed)
local name = player:get_player_name()
if player_anim[name] == anim_name then
return
@ -90,15 +83,6 @@ function default.player_set_animation(player, anim_name, speed)
player:set_animation(anim, speed or model.animation_speed, animation_blend)
end
-- Update appearance when the player joins
minetest.register_on_joinplayer(function(player)
default.player_attached[player:get_player_name()] = false
default.player_set_model(player, "character.b3d")
player:set_local_animation({x=0, y=79}, {x=168, y=187}, {x=189, y=198}, {x=200, y=219}, 30)
player:hud_set_hotbar_image("hotbar.png")
player:hud_set_hotbar_selected_image("hotbar_selected.png")
end)
minetest.register_on_leaveplayer(function(player)
local name = player:get_player_name()
player_model[name] = nil
@ -107,8 +91,8 @@ minetest.register_on_leaveplayer(function(player)
end)
-- Localize for better performance.
local player_set_animation = default.player_set_animation
local player_attached = default.player_attached
local player_set_animation = player_api.set_animation
local player_attached = player_api.player_attached
-- Check each player and apply animations
minetest.register_globalstep(function(dtime)
@ -152,4 +136,3 @@ minetest.register_globalstep(function(dtime)
end
end
end)

View File

@ -0,0 +1,34 @@
dofile(minetest.get_modpath("player_api") .. "/api.lua")
-- Default player appearance
player_api.register_model("character.b3d", {
animation_speed = 30,
textures = {"character.png", },
animations = {
-- Standard animations.
stand = {x = 0, y = 79},
lay = {x = 162, y = 166},
walk = {x = 168, y = 187},
mine = {x = 189, y = 198},
walk_mine = {x = 200, y = 219},
sit = {x = 81, y = 160},
},
collisionbox = {-0.3, 0.0, -0.3, 0.3, 1.7, 0.3},
stepheight = 0.6,
eye_height = 1.47,
})
-- Update appearance when the player joins
minetest.register_on_joinplayer(function(player)
player_api.player_attached[player:get_player_name()] = false
player_api.set_model(player, "character.b3d")
player:set_local_animation(
{x = 0, y = 79},
{x = 168, y = 187},
{x = 189, y = 198},
{x = 200, y = 219},
30
)
player:hud_set_hotbar_image("gui_hotbar.png")
player:hud_set_hotbar_selected_image("gui_hotbar_selected.png")
end)

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 380 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 B

View File

@ -97,9 +97,7 @@ minetest.register_globalstep(function(dtime)
end
-- set player physics
if not monoids and not pova_mod then
player:set_physics_override(def.speed, def.jump, def.gravity)
end
player:set_physics_override(def.speed, def.jump, def.gravity)
--[[
print ("Speed: " .. def.speed
.. " / Jump: " .. def.jump

View File

@ -103,7 +103,7 @@ end
function TNT:on_step(dtime)
local pos = self.object:getpos()
minetest.add_particle({x=pos.x,y=pos.y+0.5,z=pos.z}, {x=math.random(-.1,.1),y=math.random(1,2),z=math.random(-.1,.1)}, {x=0,y=-0.1,z=0}, math.random(.5,1),math.random(1,2), false, "tnt_smoke.png")
minetest.add_particle({x=pos.x,y=pos.y+0.5,z=pos.z}, {x=math.random(-.1,.1),y=math.random(1,2),z=math.random(-.1,.1)}, {x=0,y=-0.1,z=0}, math.random(.5,1),math.random(1,2), false, "item_smoke.png")
self.timer = self.timer + dtime
self.blinktimer = self.blinktimer + dtime
if self.timer>3 then

View File

@ -1,9 +0,0 @@
MultiCraft mod: Wool
by TenPlus1
Yep, it's a simple replacement for the wool mod that allows you to dye any
wool any colour including white, and I've also added a wool sound when walking
on top of the wool blocks to replace the leaves sound.
Sound is from freeSFX.co.uk and has a creative-commons license

View File

@ -0,0 +1,10 @@
MultiCraft mod: wool
=======================
See license.txt for license information.
Authors of source code
----------------------
Originally by Perttu Ahola (celeron55) <celeron55@gmail.com> (MIT)
TenPlus1
Various Minetest developers and contributors (MIT)
Sound is from freeSFX.co.uk and has a creative-commons license

View File

@ -1,26 +1,4 @@
minetest.register_alias("wool:dark_blue", "wool:blue")
minetest.register_alias("wool:gold", "wool:yellow")
function default.node_wool_defaults(table)
table = table or {}
table.footstep = table.footstep or
{name = "wool_coat_movement", gain = 1.0}
table.dug = table.dug or
{name = "wool_coat_movement", gain = 0.25}
table.place = table.place or
{name = "default_place_node", gain = 1.0}
return table
end
local wool_sound = default.node_wool_defaults()
--local wool_sound = default.node_sound_leaves_defaults()
local wool_dyes = {
local dyes = {
{"white", "White"},
{"grey", "Grey"},
{"black", "Black"},
@ -38,22 +16,38 @@ local wool_dyes = {
{"dark_green", "Dark Green"},
}
for _, row in pairs(wool_dyes) do
function default.node_wool_defaults(table)
table = table or {}
table.footstep = table.footstep or
{name = "wool_coat_movement", gain = 1.0}
table.dug = table.dug or
{name = "wool_coat_movement", gain = 0.25}
table.place = table.place or
{name = "default_place_node", gain = 1.0}
return table
end
minetest.register_node("wool:" .. row[1], {
description = row[2] .. " Wool",
tiles = {"wool_" .. row[1] .. ".png"},
groups = {
snappy = 2, choppy = 2, oddly_breakable_by_hand = 3,
flammable = 3, wool = 1
},
local wool_sound = default.node_wool_defaults()
for i = 1, #dyes do
local name, desc = unpack(dyes[i])
minetest.register_node("wool:" .. name, {
description = desc .. " Wool",
tiles = {"wool_" .. name .. ".png"},
is_ground_content = false,
groups = {snappy = 2, choppy = 2, oddly_breakable_by_hand = 3,
flammable = 3, wool = 1},
sounds = wool_sound,
})
minetest.register_craft({
minetest.register_craft{
type = "shapeless",
output = "wool:" .. row[1],
recipe = {"dye:" .. row[1], "group:wool"},
})
output = "wool:" .. name,
recipe = {"group:dye,color_" .. name, "group:wool"},
}
end
end
-- Legacy
minetest.register_alias("wool:dark_blue", "wool:blue")
minetest.register_alias("wool:gold", "wool:yellow")

View File

@ -0,0 +1,25 @@
License of source code
----------------------
The MIT License (MIT)
Copyright (C) 2012-2016 Perttu Ahola (celeron55) <celeron55@gmail.com>
Copyright (C) 2012-2016 Various Minetest developers and contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit
persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
For more details:
https://opensource.org/licenses/MIT