Update beds, boats, dye, fire, flowers, wool. Add player_api, new dungeon_loot.
parent
95c8ff7c83
commit
c3e80cf0e3
|
@ -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",{
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,2 +1 @@
|
|||
default
|
||||
mobs?
|
|
@ -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,
|
||||
})
|
|
@ -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/
|
||||
|
|
Before Width: | Height: | Size: 634 B After Width: | Height: | Size: 634 B |
|
@ -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},
|
||||
|
|
|
@ -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]"..
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
|
@ -1,2 +0,0 @@
|
|||
default
|
||||
farming?
|
|
@ -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")
|
||||
|
|
|
@ -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
|
|
@ -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)
|
|
@ -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
|
||||
|
|
|
@ -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.
Binary file not shown.
|
@ -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(),
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Binary file not shown.
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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)
|
||||
|
|
@ -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.
Binary file not shown.
After Width: | Height: | Size: 380 B |
Binary file not shown.
After Width: | Height: | Size: 236 B |
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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")
|
|
@ -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
|
Loading…
Reference in New Issue