fix mergeconflicts
134
game_api.txt
|
@ -40,7 +40,7 @@ Beds API
|
||||||
* `beds.kick_players()` Forces all players to leave bed
|
* `beds.kick_players()` Forces all players to leave bed
|
||||||
* `beds.skip_night()` Sets world time to morning and saves respawn position of all players currently sleeping
|
* `beds.skip_night()` Sets world time to morning and saves respawn position of all players currently sleeping
|
||||||
|
|
||||||
###Bed definition
|
### Bed definition
|
||||||
|
|
||||||
{
|
{
|
||||||
description = "Simple Bed",
|
description = "Simple Bed",
|
||||||
|
@ -87,9 +87,9 @@ The doors mod allows modders to register custom doors and trapdoors.
|
||||||
`doors.get(pos)`
|
`doors.get(pos)`
|
||||||
|
|
||||||
* `pos` A position as a table, e.g `{x = 1, y = 1, z = 1}`
|
* `pos` A position as a table, e.g `{x = 1, y = 1, z = 1}`
|
||||||
* Returns an ObjecRef to a door, or nil if the position does not contain a door
|
* Returns an ObjectRef to a door, or nil if the position does not contain a door
|
||||||
|
|
||||||
###Methods
|
### Methods
|
||||||
|
|
||||||
:open(player) -- Open the door object, returns if door was opened
|
:open(player) -- Open the door object, returns if door was opened
|
||||||
:close(player) -- Close the door object, returns if door was closed
|
:close(player) -- Close the door object, returns if door was closed
|
||||||
|
@ -101,7 +101,7 @@ The doors mod allows modders to register custom doors and trapdoors.
|
||||||
has the permissions needed to open this door. If omitted then no
|
has the permissions needed to open this door. If omitted then no
|
||||||
permission checks are performed.
|
permission checks are performed.
|
||||||
|
|
||||||
###Door definition
|
### Door definition
|
||||||
|
|
||||||
description = "Door description",
|
description = "Door description",
|
||||||
inventory_image = "mod_door_inv.png",
|
inventory_image = "mod_door_inv.png",
|
||||||
|
@ -113,7 +113,7 @@ The doors mod allows modders to register custom doors and trapdoors.
|
||||||
sound_close = sound play for close door, -- optional
|
sound_close = sound play for close door, -- optional
|
||||||
protected = false, -- If true, only placer can open the door (locked for others)
|
protected = false, -- If true, only placer can open the door (locked for others)
|
||||||
|
|
||||||
###Trapdoor definition
|
### Trapdoor definition
|
||||||
|
|
||||||
description = "Trapdoor description",
|
description = "Trapdoor description",
|
||||||
inventory_image = "mod_trapdoor_inv.png",
|
inventory_image = "mod_trapdoor_inv.png",
|
||||||
|
@ -125,7 +125,7 @@ The doors mod allows modders to register custom doors and trapdoors.
|
||||||
sound_close = sound play for close door, -- optional
|
sound_close = sound play for close door, -- optional
|
||||||
protected = false, -- If true, only placer can open the door (locked for others)
|
protected = false, -- If true, only placer can open the door (locked for others)
|
||||||
|
|
||||||
###Fence gate definition
|
### Fence gate definition
|
||||||
|
|
||||||
description = "Wooden Fence Gate",
|
description = "Wooden Fence Gate",
|
||||||
texture = "default_wood.png",
|
texture = "default_wood.png",
|
||||||
|
@ -135,6 +135,7 @@ The doors mod allows modders to register custom doors and trapdoors.
|
||||||
|
|
||||||
Fence API
|
Fence API
|
||||||
---------
|
---------
|
||||||
|
|
||||||
Allows creation of new fences with "fencelike" drawtype.
|
Allows creation of new fences with "fencelike" drawtype.
|
||||||
|
|
||||||
`default.register_fence(name, item definition)`
|
`default.register_fence(name, item definition)`
|
||||||
|
@ -144,7 +145,7 @@ Allows creation of new fences with "fencelike" drawtype.
|
||||||
nodedef fields here except drawtype. The fence group will always be added
|
nodedef fields here except drawtype. The fence group will always be added
|
||||||
for this node.
|
for this node.
|
||||||
|
|
||||||
###fence definition
|
### fence definition
|
||||||
|
|
||||||
name = "default:fence_wood",
|
name = "default:fence_wood",
|
||||||
description = "Wooden Fence",
|
description = "Wooden Fence",
|
||||||
|
@ -153,8 +154,9 @@ Allows creation of new fences with "fencelike" drawtype.
|
||||||
groups = {choppy = 2, oddly_breakable_by_hand = 2, flammable = 2},
|
groups = {choppy = 2, oddly_breakable_by_hand = 2, flammable = 2},
|
||||||
sounds = default.node_sound_wood_defaults(),
|
sounds = default.node_sound_wood_defaults(),
|
||||||
|
|
||||||
#Walls API
|
Walls API
|
||||||
---------
|
---------
|
||||||
|
|
||||||
The walls API allows easy addition of stone auto-connecting wall nodes.
|
The walls API allows easy addition of stone auto-connecting wall nodes.
|
||||||
|
|
||||||
walls.register(name, desc, texture, mat, sounds)
|
walls.register(name, desc, texture, mat, sounds)
|
||||||
|
@ -175,7 +177,7 @@ The farming API allows you to easily register plants and hoes.
|
||||||
`farming.register_plant(name, Plant definition)`
|
`farming.register_plant(name, Plant definition)`
|
||||||
* Register a new growing plant, see [#Plant definition]
|
* Register a new growing plant, see [#Plant definition]
|
||||||
|
|
||||||
###Hoe Definition
|
### Hoe Definition
|
||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -190,7 +192,7 @@ The farming API allows you to easily register plants and hoes.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
###Plant definition
|
### Plant definition
|
||||||
|
|
||||||
{
|
{
|
||||||
description = "", -- Description of seed item
|
description = "", -- Description of seed item
|
||||||
|
@ -204,11 +206,115 @@ The farming API allows you to easily register plants and hoes.
|
||||||
Fire API
|
Fire API
|
||||||
--------
|
--------
|
||||||
|
|
||||||
|
New node def property:
|
||||||
|
|
||||||
`on_burn(pos)`
|
`on_burn(pos)`
|
||||||
|
|
||||||
* Called when fire attempts to remove a burning node.
|
* Called when fire attempts to remove a burning node.
|
||||||
* `pos` Position of the burning node.
|
* `pos` Position of the burning node.
|
||||||
|
|
||||||
|
Give Initial Stuff API
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
`give_initial_stuff.give(player)`
|
||||||
|
|
||||||
|
^ Give initial stuff to "player"
|
||||||
|
|
||||||
|
`give_initial_stuff.add(stack)`
|
||||||
|
|
||||||
|
^ Add item to the initial stuff
|
||||||
|
^ Stack can be an ItemStack or a item name eg: "default:dirt 99"
|
||||||
|
^ Can be called after the game has loaded
|
||||||
|
|
||||||
|
`give_initial_stuff.clear()`
|
||||||
|
|
||||||
|
^ Removes all items from the initial stuff
|
||||||
|
^ Can be called after the game has loaded
|
||||||
|
|
||||||
|
`give_initial_stuff.get_list()`
|
||||||
|
|
||||||
|
^ returns list of item stacks
|
||||||
|
|
||||||
|
`give_initial_stuff.set_list(list)`
|
||||||
|
|
||||||
|
^ List of initial items with numeric indices.
|
||||||
|
|
||||||
|
`give_initial_stuff.add_from_csv(str)`
|
||||||
|
|
||||||
|
^ str is a comma separated list of initial stuff
|
||||||
|
^ Adds items to the list of items to be given
|
||||||
|
|
||||||
|
|
||||||
|
TNT API
|
||||||
|
----------
|
||||||
|
|
||||||
|
`tnt.register_tnt(definition)`
|
||||||
|
|
||||||
|
^ Register a new type of tnt.
|
||||||
|
|
||||||
|
* `name` The name of the node. If no prefix is given `tnt` is used.
|
||||||
|
* `description` A description for your TNT.
|
||||||
|
* `radius` The radius within which the TNT can destroy nodes. The default is 3.
|
||||||
|
* `damage_radius` The radius within which the TNT can damage players and mobs. By default it is twice the `radius`.
|
||||||
|
* `disable_drops` Disable drops. By default it is set to false.
|
||||||
|
* `ignore_protection` Don't check `minetest.is_protected` before removing a node.
|
||||||
|
* `ignore_on_blast` Don't call `on_blast` even if a node has one.
|
||||||
|
* `tiles` Textures for node
|
||||||
|
* `side` Side tiles. By default the name of the tnt with a suffix of `_side.png`.
|
||||||
|
* `top` Top tile. By default the name of the tnt with a suffix of `_top.png`.
|
||||||
|
* `bottom` Bottom tile. By default the name of the tnt with a suffix of `_bottom.png`.
|
||||||
|
* `burning` Top tile when lit. By default the name of the tnt with a suffix of `_top_burning_animated.png".
|
||||||
|
|
||||||
|
`tnt.boom(position, definition)`
|
||||||
|
|
||||||
|
^ Create an explosion.
|
||||||
|
|
||||||
|
* `position` The center of explosion.
|
||||||
|
* `definition` The TNT definion as passed to `tnt.register`
|
||||||
|
|
||||||
|
`tnt.burn(position)`
|
||||||
|
|
||||||
|
^ Ignite TNT at position
|
||||||
|
|
||||||
|
|
||||||
|
To make dropping items from node inventories easier, you can use the
|
||||||
|
following helper function from 'default':
|
||||||
|
|
||||||
|
default.get_inventory_drops(pos, inventory, drops)
|
||||||
|
|
||||||
|
^ Return drops from node inventory "inventory" in drops.
|
||||||
|
|
||||||
|
* `pos` - the node position
|
||||||
|
* `inventory` - the name of the inventory (string)
|
||||||
|
* `drops` - an initialized list
|
||||||
|
|
||||||
|
The function returns no values. The drops are returned in the `drops`
|
||||||
|
parameter, and drops is not reinitialized so you can call it several
|
||||||
|
times in a row to add more inventory items to it.
|
||||||
|
|
||||||
|
|
||||||
|
`on_blast` callbacks:
|
||||||
|
|
||||||
|
Both nodedefs and entitydefs can provide an `on_blast()` callback
|
||||||
|
|
||||||
|
`nodedef.on_blast(pos, intensity)`
|
||||||
|
^ Allow drop and node removal overriding
|
||||||
|
* `pos` - node position
|
||||||
|
* `intensity` - TNT explosion measure. larger or equal to 1.0
|
||||||
|
^ Should return a list of drops (e.g. {"default:stone"})
|
||||||
|
^ Should perform node removal itself. If callback exists in the nodedef
|
||||||
|
^ then the TNT code will not destroy this node.
|
||||||
|
|
||||||
|
`entitydef.on_blast(luaobj, damage)`
|
||||||
|
^ Allow TNT effects on entities to be overridden
|
||||||
|
* `luaobj` - LuaEntityRef of the entity
|
||||||
|
* `damage` - suggested HP damage value
|
||||||
|
^ Should return a list of (bool do_damage, bool do_knockback, table drops)
|
||||||
|
* `do_damage` - if true then TNT mod wil damage the entity
|
||||||
|
* `do_knockback` - if true then TNT mod will knock the entity away
|
||||||
|
* `drops` - a list of drops, e.g. {"wool:red"}
|
||||||
|
|
||||||
|
|
||||||
Screwdriver API
|
Screwdriver API
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
|
@ -270,7 +376,7 @@ Creates panes that automatically connect to each other
|
||||||
* `subname`: used for nodename. Result: "xpanes:subname" and "xpanes:subname_{2..15}"
|
* `subname`: used for nodename. Result: "xpanes:subname" and "xpanes:subname_{2..15}"
|
||||||
* `def`: See [#Pane definition]
|
* `def`: See [#Pane definition]
|
||||||
|
|
||||||
###Pane definition
|
### Pane definition
|
||||||
|
|
||||||
{
|
{
|
||||||
textures = {"texture_Bottom_top", "texture_left_right", "texture_front_back"}, -- More tiles aren't supported
|
textures = {"texture_Bottom_top", "texture_left_right", "texture_front_back"}, -- More tiles aren't supported
|
||||||
|
@ -356,7 +462,7 @@ default.player_get_animation(player)
|
||||||
* Any of the fields of the returned table may be nil.
|
* Any of the fields of the returned table may be nil.
|
||||||
* player: PlayerRef
|
* player: PlayerRef
|
||||||
|
|
||||||
###Model Definition
|
### Model Definition
|
||||||
|
|
||||||
{
|
{
|
||||||
animation_speed = 30, -- Default animation speed, in FPS.
|
animation_speed = 30, -- Default animation speed, in FPS.
|
||||||
|
@ -395,7 +501,7 @@ To make recipes that will work with any dye ever made by anybody, define
|
||||||
them based on groups. You can select any group of groups, based on your need for
|
them based on groups. You can select any group of groups, based on your need for
|
||||||
amount of colors.
|
amount of colors.
|
||||||
|
|
||||||
###Color groups
|
### Color groups
|
||||||
|
|
||||||
Base color groups:
|
Base color groups:
|
||||||
|
|
||||||
|
@ -450,7 +556,7 @@ Example of one shapeless recipe using a color group:
|
||||||
recipe = {'<mod>:item_no_color', 'group:basecolor_yellow'},
|
recipe = {'<mod>:item_no_color', 'group:basecolor_yellow'},
|
||||||
})
|
})
|
||||||
|
|
||||||
###Color lists
|
### Color lists
|
||||||
|
|
||||||
* `dye.basecolors` are an array containing the names of available base colors
|
* `dye.basecolors` are an array containing the names of available base colors
|
||||||
|
|
||||||
|
|
|
@ -18,8 +18,9 @@
|
||||||
# 'permanent flame' nodes will remain with either setting
|
# 'permanent flame' nodes will remain with either setting
|
||||||
#disable_fire = false
|
#disable_fire = false
|
||||||
|
|
||||||
# Whether steel tools, torches and cobblestone should be given to new players
|
# Whether the stuff in initial_stuff should be given to new players
|
||||||
#give_initial_stuff = false
|
#give_initial_stuff = false
|
||||||
|
#initial_stuff = default:pick_steel,default:axe_steel,default:shovel_steel,default:torch 99,default:cobble 99
|
||||||
|
|
||||||
# Whether the TNT mod should be enabled
|
# Whether the TNT mod should be enabled
|
||||||
#enable_tnt = <true in singleplayer, false in multiplayer>
|
#enable_tnt = <true in singleplayer, false in multiplayer>
|
||||||
|
|
|
@ -41,10 +41,12 @@ function beds.save_spawns()
|
||||||
if not beds.spawn then
|
if not beds.spawn then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
local data = {}
|
||||||
local output = io.open(org_file, "w")
|
local output = io.open(org_file, "w")
|
||||||
for i, v in pairs(beds.spawn) do
|
for k, v in pairs(beds.spawn) do
|
||||||
output:write(v.x .. " " .. v.y .. " " .. v.z .. " " .. i .. "\n")
|
table.insert(data, string.format("%.1f %.1f %.1f %s\n", v.x, v.y, v.z, k))
|
||||||
end
|
end
|
||||||
|
output:write(table.concat(data))
|
||||||
io.close(output)
|
io.close(output)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
Subproject commit ffaf921ce4a5644c62eced2754bffe1a41950e73
|
|
|
@ -123,6 +123,8 @@ minetest.register_node("bones:bones", {
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
|
on_blast = function(pos)
|
||||||
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
local function may_replace(pos, player)
|
local function may_replace(pos, player)
|
||||||
|
|
|
@ -144,7 +144,6 @@ BlockMen (CC BY-SA 3.0):
|
||||||
default_mineral_mese.png
|
default_mineral_mese.png
|
||||||
default_meselamp.png
|
default_meselamp.png
|
||||||
bubble.png
|
bubble.png
|
||||||
heart.png
|
|
||||||
gui_*.png
|
gui_*.png
|
||||||
|
|
||||||
sofar (CC BY-SA 3.0):
|
sofar (CC BY-SA 3.0):
|
||||||
|
@ -222,3 +221,6 @@ Mito551 (sounds) (CC BY-SA):
|
||||||
default_dirt_footstep.1.ogg
|
default_dirt_footstep.1.ogg
|
||||||
default_dirt_footstep.2.ogg
|
default_dirt_footstep.2.ogg
|
||||||
default_glass_footstep.ogg
|
default_glass_footstep.ogg
|
||||||
|
|
||||||
|
KevDoy (CC BY-SA 3.0)
|
||||||
|
heart.png
|
||||||
|
|
|
@ -11,21 +11,30 @@ minetest.register_craftitem("default:paper", {
|
||||||
inventory_image = "default_paper.png",
|
inventory_image = "default_paper.png",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
local lpp = 14 -- Lines per book's page
|
||||||
local function book_on_use(itemstack, user)
|
local function book_on_use(itemstack, user)
|
||||||
local player_name = user:get_player_name()
|
local player_name = user:get_player_name()
|
||||||
local data = minetest.deserialize(itemstack:get_metadata())
|
local data = minetest.deserialize(itemstack:get_metadata())
|
||||||
local formspec, title, text, owner = "", "", "", player_name
|
local formspec, title, text, owner = "", "", "", player_name
|
||||||
local page, page_max, cpp = 1, 1, 650
|
local page, page_max, lines, string = 1, 1, {}, ""
|
||||||
|
|
||||||
if data then
|
if data then
|
||||||
title = data.title
|
title = data.title
|
||||||
text = data.text
|
text = data.text
|
||||||
owner = data.owner
|
owner = data.owner
|
||||||
|
|
||||||
|
for str in (text .. "\n"):gmatch("([^\n]*)[\n]") do
|
||||||
|
lines[#lines+1] = str
|
||||||
|
end
|
||||||
|
|
||||||
if data.page then
|
if data.page then
|
||||||
page = data.page
|
page = data.page
|
||||||
page_max = data.page_max
|
page_max = data.page_max
|
||||||
cpp = data.chars_per_page
|
|
||||||
|
for i = ((lpp * page) - lpp) + 1, lpp * page do
|
||||||
|
if not lines[i] then break end
|
||||||
|
string = string .. lines[i] .. "\n"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -44,8 +53,8 @@ local function book_on_use(itemstack, user)
|
||||||
"tablecolumns[color;text]" ..
|
"tablecolumns[color;text]" ..
|
||||||
"tableoptions[background=#00000000;highlight=#00000000;border=false]" ..
|
"tableoptions[background=#00000000;highlight=#00000000;border=false]" ..
|
||||||
"table[0.4,0;7,0.5;title;#FFFF00," .. minetest.formspec_escape(title) .. "]" ..
|
"table[0.4,0;7,0.5;title;#FFFF00," .. minetest.formspec_escape(title) .. "]" ..
|
||||||
"textarea[0.5,1.5;7.5,7;;" .. minetest.formspec_escape(text:sub(
|
"textarea[0.5,1.5;7.5,7;;" ..
|
||||||
(cpp * page) - cpp, cpp * page)) .. ";]" ..
|
minetest.formspec_escape(string ~= "" and string or text) .. ";]" ..
|
||||||
"button[2.4,7.6;0.8,0.8;book_prev;<]" ..
|
"button[2.4,7.6;0.8,0.8;book_prev;<]" ..
|
||||||
"label[3.2,7.7;Page " .. page .. " of " .. page_max .. "]" ..
|
"label[3.2,7.7;Page " .. page .. " of " .. page_max .. "]" ..
|
||||||
"button[4.9,7.6;0.8,0.8;book_next;>]"
|
"button[4.9,7.6;0.8,0.8;book_next;>]"
|
||||||
|
@ -76,10 +85,9 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
if not data then data = {} end
|
if not data then data = {} end
|
||||||
data.title = fields.title
|
data.title = fields.title
|
||||||
data.text = fields.text
|
data.text = fields.text
|
||||||
data.text_len = fields.text:len()
|
data.text_len = #data.text
|
||||||
data.page = 1
|
data.page = 1
|
||||||
data.chars_per_page = 650
|
data.page_max = math.ceil((#data.text:gsub("[^\n]", "") + 1) / lpp)
|
||||||
data.page_max = math.ceil(data.text_len / data.chars_per_page)
|
|
||||||
data.owner = player:get_player_name()
|
data.owner = player:get_player_name()
|
||||||
local data_str = minetest.serialize(data)
|
local data_str = minetest.serialize(data)
|
||||||
|
|
||||||
|
@ -94,8 +102,6 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
stack:set_metadata(data_str)
|
stack:set_metadata(data_str)
|
||||||
end
|
end
|
||||||
|
|
||||||
player:set_wielded_item(stack)
|
|
||||||
|
|
||||||
elseif fields.book_next or fields.book_prev then
|
elseif fields.book_next or fields.book_prev then
|
||||||
local data = minetest.deserialize(stack:get_metadata())
|
local data = minetest.deserialize(stack:get_metadata())
|
||||||
if not data.page then return end
|
if not data.page then return end
|
||||||
|
@ -116,6 +122,8 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
stack:set_metadata(data_str)
|
stack:set_metadata(data_str)
|
||||||
book_on_use(stack, player)
|
book_on_use(stack, player)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
player:set_wielded_item(stack)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
minetest.register_craftitem("default:book", {
|
minetest.register_craftitem("default:book", {
|
||||||
|
|
|
@ -49,6 +49,18 @@ function default.node_sound_sand_defaults(table)
|
||||||
return table
|
return table
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function default.node_sound_gravel_defaults(table)
|
||||||
|
table = table or {}
|
||||||
|
table.footstep = table.footstep or
|
||||||
|
{name = "default_gravel_footstep", gain = 0.5}
|
||||||
|
table.dug = table.dug or
|
||||||
|
{name = "default_gravel_footstep", gain = 1.0}
|
||||||
|
table.place = table.place or
|
||||||
|
{name = "default_place_node", gain = 1.0}
|
||||||
|
default.node_sound_defaults(table)
|
||||||
|
return table
|
||||||
|
end
|
||||||
|
|
||||||
function default.node_sound_wood_defaults(table)
|
function default.node_sound_wood_defaults(table)
|
||||||
table = table or {}
|
table = table or {}
|
||||||
table.footstep = table.footstep or
|
table.footstep = table.footstep or
|
||||||
|
@ -110,6 +122,21 @@ minetest.register_abm({
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- optimized helper to put all items in an inventory into a drops list
|
||||||
|
--
|
||||||
|
function default.get_inventory_drops(pos, inventory, drops)
|
||||||
|
local inv = minetest.get_meta(pos):get_inventory()
|
||||||
|
local n = #drops
|
||||||
|
for i = 1, inv:get_size(inventory) do
|
||||||
|
local stack = inv:get_stack(inventory, i)
|
||||||
|
if stack:get_count() > 0 then
|
||||||
|
drops[n+1] = stack:to_table()
|
||||||
|
n = n + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Papyrus and cactus growing
|
-- Papyrus and cactus growing
|
||||||
--
|
--
|
||||||
|
@ -342,38 +369,71 @@ minetest.register_abm({
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Grass growing on well-lit dirt
|
-- Convert dirt to something that fits the environment
|
||||||
--
|
--
|
||||||
|
|
||||||
minetest.register_abm({
|
minetest.register_abm({
|
||||||
nodenames = {"default:dirt"},
|
nodenames = {"default:dirt"},
|
||||||
neighbors = {"air"},
|
neighbors = {
|
||||||
|
"default:dirt_with_grass",
|
||||||
|
"default:dirt_with_dry_grass",
|
||||||
|
"default:dirt_with_snow",
|
||||||
|
"group:grass",
|
||||||
|
"group:dry_grass",
|
||||||
|
"default:snow",
|
||||||
|
},
|
||||||
interval = 6,
|
interval = 6,
|
||||||
chance = 67,
|
chance = 67,
|
||||||
catch_up = false,
|
catch_up = false,
|
||||||
action = function(pos, node)
|
action = function(pos, node)
|
||||||
|
-- Most likely case, half the time it's too dark for this.
|
||||||
local above = {x = pos.x, y = pos.y + 1, z = pos.z}
|
local above = {x = pos.x, y = pos.y + 1, z = pos.z}
|
||||||
local name = minetest.get_node(above).name
|
if (minetest.get_node_light(above) or 0) < 13 then
|
||||||
local nodedef = minetest.registered_nodes[name]
|
return
|
||||||
if nodedef and (nodedef.sunlight_propagates or nodedef.paramtype == "light") and
|
end
|
||||||
nodedef.liquidtype == "none" and
|
|
||||||
(minetest.get_node_light(above) or 0) >= 13 then
|
-- Look for likely neighbors.
|
||||||
if name == "default:snow" or name == "default:snowblock" then
|
local p2 = minetest.find_node_near(pos, 1, {"default:dirt_with_grass",
|
||||||
minetest.set_node(pos, {name = "default:dirt_with_snow"})
|
"default:dirt_with_dry_grass", "default:dirt_with_snow"})
|
||||||
else
|
if p2 then
|
||||||
minetest.set_node(pos, {name = "default:dirt_with_grass"})
|
-- But the node needs to be under air in this case.
|
||||||
|
local n2 = minetest.get_node(above)
|
||||||
|
if n2 and n2.name == "air" then
|
||||||
|
local n3 = minetest.get_node(p2)
|
||||||
|
minetest.set_node(pos, {name = n3.name})
|
||||||
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Anything on top?
|
||||||
|
local n2 = minetest.get_node(above)
|
||||||
|
if not n2 then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local name = n2.name
|
||||||
|
-- Snow check is cheapest, so comes first.
|
||||||
|
if name == "default:snow" then
|
||||||
|
minetest.set_node(pos, {name = "default:dirt_with_snow"})
|
||||||
|
-- Most likely case first.
|
||||||
|
elseif minetest.get_item_group(name, "grass") ~= 0 then
|
||||||
|
minetest.set_node(pos, {name = "default:dirt_with_grass"})
|
||||||
|
elseif minetest.get_item_group(name, "dry_grass") ~= 0 then
|
||||||
|
minetest.set_node(pos, {name = "default:dirt_with_dry_grass"})
|
||||||
|
end
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Grass and dry grass removed in darkness
|
-- Grass and dry grass removed in darkness
|
||||||
--
|
--
|
||||||
|
|
||||||
minetest.register_abm({
|
minetest.register_abm({
|
||||||
nodenames = {"default:dirt_with_grass", "default:dirt_with_dry_grass"},
|
nodenames = {
|
||||||
|
"default:dirt_with_grass",
|
||||||
|
"default:dirt_with_dry_grass",
|
||||||
|
"default:dirt_with_snow",
|
||||||
|
},
|
||||||
interval = 8,
|
interval = 8,
|
||||||
chance = 50,
|
chance = 50,
|
||||||
catch_up = false,
|
catch_up = false,
|
||||||
|
|
|
@ -90,6 +90,137 @@ local function allow_metadata_inventory_take(pos, listname, index, stack, player
|
||||||
return stack:get_count()
|
return stack:get_count()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function swap_node(pos, name)
|
||||||
|
local node = minetest.get_node(pos)
|
||||||
|
if node.name == name then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
node.name = name
|
||||||
|
minetest.swap_node(pos, node)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function furnace_node_timer(pos, elapsed)
|
||||||
|
--
|
||||||
|
-- Inizialize metadata
|
||||||
|
--
|
||||||
|
local meta = minetest.get_meta(pos)
|
||||||
|
local fuel_time = meta:get_float("fuel_time") or 0
|
||||||
|
local src_time = meta:get_float("src_time") or 0
|
||||||
|
local fuel_totaltime = meta:get_float("fuel_totaltime") or 0
|
||||||
|
|
||||||
|
local inv = meta:get_inventory()
|
||||||
|
local srclist = inv:get_list("src")
|
||||||
|
local fuellist = inv:get_list("fuel")
|
||||||
|
local dstlist = inv:get_list("dst")
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Cooking
|
||||||
|
--
|
||||||
|
|
||||||
|
-- Check if we have cookable content
|
||||||
|
local cooked, aftercooked = minetest.get_craft_result({method = "cooking", width = 1, items = srclist})
|
||||||
|
local cookable = true
|
||||||
|
|
||||||
|
if cooked.time == 0 then
|
||||||
|
cookable = false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check if we have enough fuel to burn
|
||||||
|
if fuel_time < fuel_totaltime then
|
||||||
|
-- The furnace is currently active and has enough fuel
|
||||||
|
fuel_time = fuel_time + 1
|
||||||
|
|
||||||
|
-- If there is a cookable item then check if it is ready yet
|
||||||
|
if cookable then
|
||||||
|
src_time = src_time + 1
|
||||||
|
if src_time >= cooked.time then
|
||||||
|
-- Place result in dst list if possible
|
||||||
|
if inv:room_for_item("dst", cooked.item) then
|
||||||
|
inv:add_item("dst", cooked.item)
|
||||||
|
inv:set_stack("src", 1, aftercooked.items[1])
|
||||||
|
src_time = 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- Furnace ran out of fuel
|
||||||
|
if cookable then
|
||||||
|
-- We need to get new fuel
|
||||||
|
local fuel, afterfuel = minetest.get_craft_result({method = "fuel", width = 1, items = fuellist})
|
||||||
|
|
||||||
|
if fuel.time == 0 then
|
||||||
|
-- No valid fuel in fuel list
|
||||||
|
fuel_totaltime = 0
|
||||||
|
fuel_time = 0
|
||||||
|
src_time = 0
|
||||||
|
else
|
||||||
|
-- Take fuel from fuel list
|
||||||
|
inv:set_stack("fuel", 1, afterfuel.items[1])
|
||||||
|
|
||||||
|
fuel_totaltime = fuel.time
|
||||||
|
fuel_time = 0
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- We don't need to get new fuel since there is no cookable item
|
||||||
|
fuel_totaltime = 0
|
||||||
|
fuel_time = 0
|
||||||
|
src_time = 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Update formspec, infotext and node
|
||||||
|
--
|
||||||
|
local formspec = inactive_formspec
|
||||||
|
local item_state = ""
|
||||||
|
local item_percent = 0
|
||||||
|
if cookable then
|
||||||
|
item_percent = math.floor(src_time / cooked.time * 100)
|
||||||
|
item_state = item_percent .. "%"
|
||||||
|
else
|
||||||
|
if srclist[1]:is_empty() then
|
||||||
|
item_state = "Empty"
|
||||||
|
else
|
||||||
|
item_state = "Not cookable"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local fuel_state = "Empty"
|
||||||
|
local active = "inactive "
|
||||||
|
local result = false
|
||||||
|
|
||||||
|
if fuel_time <= fuel_totaltime and fuel_totaltime ~= 0 then
|
||||||
|
active = "active "
|
||||||
|
local fuel_percent = math.floor(fuel_time / fuel_totaltime * 100)
|
||||||
|
fuel_state = fuel_percent .. "%"
|
||||||
|
formspec = active_formspec(fuel_percent, item_percent)
|
||||||
|
swap_node(pos, "default:furnace_active")
|
||||||
|
-- make sure timer restarts automatically
|
||||||
|
result = true
|
||||||
|
else
|
||||||
|
if not fuellist[1]:is_empty() then
|
||||||
|
fuel_state = "0%"
|
||||||
|
end
|
||||||
|
swap_node(pos, "default:furnace")
|
||||||
|
-- stop timer on the inactive furnace
|
||||||
|
local timer = minetest.get_node_timer(pos)
|
||||||
|
timer:stop()
|
||||||
|
end
|
||||||
|
|
||||||
|
local infotext = "Furnace " .. active .. "(Item: " .. item_state .. "; Fuel: " .. fuel_state .. ")"
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Set meta values
|
||||||
|
--
|
||||||
|
meta:set_float("fuel_totaltime", fuel_totaltime)
|
||||||
|
meta:set_float("fuel_time", fuel_time)
|
||||||
|
meta:set_float("src_time", src_time)
|
||||||
|
meta:set_string("formspec", formspec)
|
||||||
|
meta:set_string("infotext", infotext)
|
||||||
|
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Node definitions
|
-- Node definitions
|
||||||
--
|
--
|
||||||
|
@ -109,7 +240,37 @@ minetest.register_node("default:furnace", {
|
||||||
|
|
||||||
can_dig = can_dig,
|
can_dig = can_dig,
|
||||||
|
|
||||||
allow_metadata_inventory_put = allow_metadata_inventory_put,
|
on_timer = furnace_node_timer,
|
||||||
|
|
||||||
|
on_construct = function(pos)
|
||||||
|
local meta = minetest.get_meta(pos)
|
||||||
|
meta:set_string("formspec", inactive_formspec)
|
||||||
|
local inv = meta:get_inventory()
|
||||||
|
inv:set_size('src', 1)
|
||||||
|
inv:set_size('fuel', 1)
|
||||||
|
inv:set_size('dst', 4)
|
||||||
|
end,
|
||||||
|
|
||||||
|
on_metadata_inventory_move = function(pos)
|
||||||
|
local timer = minetest.get_node_timer(pos)
|
||||||
|
timer:start(1.0)
|
||||||
|
end,
|
||||||
|
on_metadata_inventory_put = function(pos)
|
||||||
|
-- start timer function, it will sort out whether furnace can burn or not.
|
||||||
|
local timer = minetest.get_node_timer(pos)
|
||||||
|
timer:start(1.0)
|
||||||
|
end,
|
||||||
|
on_blast = function(pos)
|
||||||
|
local drops = {}
|
||||||
|
default.get_inventory_drops(pos, "src", drops)
|
||||||
|
default.get_inventory_drops(pos, "fuel", drops)
|
||||||
|
default.get_inventory_drops(pos, "dst", drops)
|
||||||
|
drops[#drops+1] = "default:furnace"
|
||||||
|
minetest.remove_node(pos)
|
||||||
|
return drops
|
||||||
|
end,
|
||||||
|
|
||||||
|
allow_metadata_inventory_put = allow_metadata_inventory_put,
|
||||||
allow_metadata_inventory_move = allow_metadata_inventory_move,
|
allow_metadata_inventory_move = allow_metadata_inventory_move,
|
||||||
allow_metadata_inventory_take = allow_metadata_inventory_take,
|
allow_metadata_inventory_take = allow_metadata_inventory_take,
|
||||||
})
|
})
|
||||||
|
@ -138,6 +299,7 @@ minetest.register_node("default:furnace_active", {
|
||||||
legacy_facedir_simple = true,
|
legacy_facedir_simple = true,
|
||||||
is_ground_content = false,
|
is_ground_content = false,
|
||||||
sounds = default.node_sound_stone_defaults(),
|
sounds = default.node_sound_stone_defaults(),
|
||||||
|
on_timer = furnace_node_timer,
|
||||||
|
|
||||||
can_dig = can_dig,
|
can_dig = can_dig,
|
||||||
|
|
||||||
|
@ -146,146 +308,3 @@ minetest.register_node("default:furnace_active", {
|
||||||
allow_metadata_inventory_take = allow_metadata_inventory_take,
|
allow_metadata_inventory_take = allow_metadata_inventory_take,
|
||||||
})
|
})
|
||||||
|
|
||||||
--
|
|
||||||
-- ABM
|
|
||||||
--
|
|
||||||
|
|
||||||
local function swap_node(pos, name)
|
|
||||||
local node = minetest.get_node(pos)
|
|
||||||
if node.name == name then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
node.name = name
|
|
||||||
minetest.swap_node(pos, node)
|
|
||||||
end
|
|
||||||
|
|
||||||
minetest.register_abm({
|
|
||||||
nodenames = {"default:furnace", "default:furnace_active"},
|
|
||||||
interval = 1.0,
|
|
||||||
chance = 1,
|
|
||||||
action = function(pos, node, active_object_count, active_object_count_wider)
|
|
||||||
--
|
|
||||||
-- Inizialize metadata
|
|
||||||
--
|
|
||||||
local meta = minetest.get_meta(pos)
|
|
||||||
local fuel_time = meta:get_float("fuel_time") or 0
|
|
||||||
local src_time = meta:get_float("src_time") or 0
|
|
||||||
local fuel_totaltime = meta:get_float("fuel_totaltime") or 0
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Inizialize inventory
|
|
||||||
--
|
|
||||||
local inv = meta:get_inventory()
|
|
||||||
for listname, size in pairs({
|
|
||||||
src = 1,
|
|
||||||
fuel = 1,
|
|
||||||
dst = 4,
|
|
||||||
}) do
|
|
||||||
if inv:get_size(listname) ~= size then
|
|
||||||
inv:set_size(listname, size)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
local srclist = inv:get_list("src")
|
|
||||||
local fuellist = inv:get_list("fuel")
|
|
||||||
local dstlist = inv:get_list("dst")
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Cooking
|
|
||||||
--
|
|
||||||
|
|
||||||
-- Check if we have cookable content
|
|
||||||
local cooked, aftercooked = minetest.get_craft_result({method = "cooking", width = 1, items = srclist})
|
|
||||||
local cookable = true
|
|
||||||
|
|
||||||
if cooked.time == 0 then
|
|
||||||
cookable = false
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Check if we have enough fuel to burn
|
|
||||||
if fuel_time < fuel_totaltime then
|
|
||||||
-- The furnace is currently active and has enough fuel
|
|
||||||
fuel_time = fuel_time + 1
|
|
||||||
|
|
||||||
-- If there is a cookable item then check if it is ready yet
|
|
||||||
if cookable then
|
|
||||||
src_time = src_time + 1
|
|
||||||
if src_time >= cooked.time then
|
|
||||||
-- Place result in dst list if possible
|
|
||||||
if inv:room_for_item("dst", cooked.item) then
|
|
||||||
inv:add_item("dst", cooked.item)
|
|
||||||
inv:set_stack("src", 1, aftercooked.items[1])
|
|
||||||
src_time = 0
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
-- Furnace ran out of fuel
|
|
||||||
if cookable then
|
|
||||||
-- We need to get new fuel
|
|
||||||
local fuel, afterfuel = minetest.get_craft_result({method = "fuel", width = 1, items = fuellist})
|
|
||||||
|
|
||||||
if fuel.time == 0 then
|
|
||||||
-- No valid fuel in fuel list
|
|
||||||
fuel_totaltime = 0
|
|
||||||
fuel_time = 0
|
|
||||||
src_time = 0
|
|
||||||
else
|
|
||||||
-- Take fuel from fuel list
|
|
||||||
inv:set_stack("fuel", 1, afterfuel.items[1])
|
|
||||||
|
|
||||||
fuel_totaltime = fuel.time
|
|
||||||
fuel_time = 0
|
|
||||||
|
|
||||||
end
|
|
||||||
else
|
|
||||||
-- We don't need to get new fuel since there is no cookable item
|
|
||||||
fuel_totaltime = 0
|
|
||||||
fuel_time = 0
|
|
||||||
src_time = 0
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Update formspec, infotext and node
|
|
||||||
--
|
|
||||||
local formspec = inactive_formspec
|
|
||||||
local item_state = ""
|
|
||||||
local item_percent = 0
|
|
||||||
if cookable then
|
|
||||||
item_percent = math.floor(src_time / cooked.time * 100)
|
|
||||||
item_state = item_percent .. "%"
|
|
||||||
else
|
|
||||||
if srclist[1]:is_empty() then
|
|
||||||
item_state = "Empty"
|
|
||||||
else
|
|
||||||
item_state = "Not cookable"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local fuel_state = "Empty"
|
|
||||||
local active = "inactive "
|
|
||||||
if fuel_time <= fuel_totaltime and fuel_totaltime ~= 0 then
|
|
||||||
active = "active "
|
|
||||||
local fuel_percent = math.floor(fuel_time / fuel_totaltime * 100)
|
|
||||||
fuel_state = fuel_percent .. "%"
|
|
||||||
formspec = active_formspec(fuel_percent, item_percent)
|
|
||||||
swap_node(pos, "default:furnace_active")
|
|
||||||
else
|
|
||||||
if not fuellist[1]:is_empty() then
|
|
||||||
fuel_state = "0%"
|
|
||||||
end
|
|
||||||
swap_node(pos, "default:furnace")
|
|
||||||
end
|
|
||||||
|
|
||||||
local infotext = "Furnace " .. active .. "(Item: " .. item_state .. "; Fuel: " .. fuel_state .. ")"
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Set meta values
|
|
||||||
--
|
|
||||||
meta:set_float("fuel_totaltime", fuel_totaltime)
|
|
||||||
meta:set_float("fuel_time", fuel_time)
|
|
||||||
meta:set_float("src_time", src_time)
|
|
||||||
meta:set_string("formspec", formspec)
|
|
||||||
meta:set_string("infotext", infotext)
|
|
||||||
end,
|
|
||||||
})
|
|
||||||
|
|
|
@ -353,10 +353,7 @@ minetest.register_node("default:gravel", {
|
||||||
description = "Gravel",
|
description = "Gravel",
|
||||||
tiles = {"default_gravel.png"},
|
tiles = {"default_gravel.png"},
|
||||||
groups = {crumbly = 2, falling_node = 1},
|
groups = {crumbly = 2, falling_node = 1},
|
||||||
sounds = default.node_sound_dirt_defaults({
|
sounds = default.node_sound_gravel_defaults(),
|
||||||
footstep = {name = "default_gravel_footstep", gain = 0.5},
|
|
||||||
dug = {name = "default_gravel_footstep", gain = 1.0},
|
|
||||||
}),
|
|
||||||
drop = {
|
drop = {
|
||||||
max_items = 1,
|
max_items = 1,
|
||||||
items = {
|
items = {
|
||||||
|
@ -947,7 +944,7 @@ minetest.register_node("default:junglegrass", {
|
||||||
sunlight_propagates = true,
|
sunlight_propagates = true,
|
||||||
walkable = false,
|
walkable = false,
|
||||||
buildable_to = true,
|
buildable_to = true,
|
||||||
groups = {snappy = 3, flora = 1, attached_node = 1},
|
groups = {snappy = 3, flora = 1, attached_node = 1, grass = 1},
|
||||||
sounds = default.node_sound_leaves_defaults(),
|
sounds = default.node_sound_leaves_defaults(),
|
||||||
selection_box = {
|
selection_box = {
|
||||||
type = "fixed",
|
type = "fixed",
|
||||||
|
@ -968,7 +965,7 @@ minetest.register_node("default:grass_1", {
|
||||||
sunlight_propagates = true,
|
sunlight_propagates = true,
|
||||||
walkable = false,
|
walkable = false,
|
||||||
buildable_to = true,
|
buildable_to = true,
|
||||||
groups = {snappy = 3, flora = 1, attached_node = 1},
|
groups = {snappy = 3, flora = 1, attached_node = 1, grass = 1},
|
||||||
sounds = default.node_sound_leaves_defaults(),
|
sounds = default.node_sound_leaves_defaults(),
|
||||||
selection_box = {
|
selection_box = {
|
||||||
type = "fixed",
|
type = "fixed",
|
||||||
|
@ -998,7 +995,7 @@ for i = 2, 5 do
|
||||||
buildable_to = true,
|
buildable_to = true,
|
||||||
drop = "default:grass_1",
|
drop = "default:grass_1",
|
||||||
groups = {snappy = 3, flora = 1, attached_node = 1,
|
groups = {snappy = 3, flora = 1, attached_node = 1,
|
||||||
not_in_creative_inventory = 1},
|
not_in_creative_inventory = 1, grass = 1},
|
||||||
sounds = default.node_sound_leaves_defaults(),
|
sounds = default.node_sound_leaves_defaults(),
|
||||||
selection_box = {
|
selection_box = {
|
||||||
type = "fixed",
|
type = "fixed",
|
||||||
|
@ -1019,7 +1016,8 @@ minetest.register_node("default:dry_grass_1", {
|
||||||
sunlight_propagates = true,
|
sunlight_propagates = true,
|
||||||
walkable = false,
|
walkable = false,
|
||||||
buildable_to = true,
|
buildable_to = true,
|
||||||
groups = {snappy = 3, flammable = 3, flora = 1, attached_node = 1},
|
groups = {snappy = 3, flammable = 3, flora = 1,
|
||||||
|
attached_node = 1, dry_grass = 1},
|
||||||
sounds = default.node_sound_leaves_defaults(),
|
sounds = default.node_sound_leaves_defaults(),
|
||||||
selection_box = {
|
selection_box = {
|
||||||
type = "fixed",
|
type = "fixed",
|
||||||
|
@ -1047,8 +1045,8 @@ for i = 2, 5 do
|
||||||
sunlight_propagates = true,
|
sunlight_propagates = true,
|
||||||
walkable = false,
|
walkable = false,
|
||||||
buildable_to = true,
|
buildable_to = true,
|
||||||
groups = {snappy = 3, flammable = 3, flora = 1,
|
groups = {snappy = 3, flammable = 3, flora = 1, attached_node = 1,
|
||||||
attached_node = 1, not_in_creative_inventory=1},
|
not_in_creative_inventory=1, dry_grass = 1},
|
||||||
drop = "default:dry_grass_1",
|
drop = "default:dry_grass_1",
|
||||||
sounds = default.node_sound_leaves_defaults(),
|
sounds = default.node_sound_leaves_defaults(),
|
||||||
selection_box = {
|
selection_box = {
|
||||||
|
@ -1473,6 +1471,13 @@ minetest.register_node("default:chest", {
|
||||||
" takes " .. stack:get_name() ..
|
" takes " .. stack:get_name() ..
|
||||||
" from chest at " .. minetest.pos_to_string(pos))
|
" from chest at " .. minetest.pos_to_string(pos))
|
||||||
end,
|
end,
|
||||||
|
on_blast = function(pos)
|
||||||
|
local drops = {}
|
||||||
|
default.get_inventory_drops(pos, "main", drops)
|
||||||
|
drops[#drops+1] = "default:chest"
|
||||||
|
minetest.remove_node(pos)
|
||||||
|
return drops
|
||||||
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_node("default:chest_locked", {
|
minetest.register_node("default:chest_locked", {
|
||||||
|
@ -1596,6 +1601,13 @@ minetest.register_node("default:bookshelf", {
|
||||||
minetest.log("action", player:get_player_name() ..
|
minetest.log("action", player:get_player_name() ..
|
||||||
" takes stuff from bookshelf at " .. minetest.pos_to_string(pos))
|
" takes stuff from bookshelf at " .. minetest.pos_to_string(pos))
|
||||||
end,
|
end,
|
||||||
|
on_blast = function(pos)
|
||||||
|
local drops = {}
|
||||||
|
default.get_inventory_drops(pos, "books", drops)
|
||||||
|
drops[#drops+1] = "default:bookshelf"
|
||||||
|
minetest.remove_node(pos)
|
||||||
|
return drops
|
||||||
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
local function register_sign(material, desc, def)
|
local function register_sign(material, desc, def)
|
||||||
|
@ -1757,7 +1769,7 @@ minetest.register_node("default:obsidian_glass", {
|
||||||
is_ground_content = false,
|
is_ground_content = false,
|
||||||
sunlight_propagates = true,
|
sunlight_propagates = true,
|
||||||
sounds = default.node_sound_glass_defaults(),
|
sounds = default.node_sound_glass_defaults(),
|
||||||
groups = {cracky = 3, oddly_breakable_by_hand = 3},
|
groups = {cracky = 3},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
Before Width: | Height: | Size: 777 B After Width: | Height: | Size: 377 B |
Before Width: | Height: | Size: 490 B After Width: | Height: | Size: 771 B |
Before Width: | Height: | Size: 293 B After Width: | Height: | Size: 14 KiB |
|
@ -203,11 +203,10 @@ function doors.register(name, def)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- replace old doors of this type automatically
|
-- replace old doors of this type automatically
|
||||||
minetest.register_abm({
|
minetest.register_lbm({
|
||||||
|
name = ":doors:replace_" .. name:gsub(":", "_"),
|
||||||
nodenames = {name.."_b_1", name.."_b_2"},
|
nodenames = {name.."_b_1", name.."_b_2"},
|
||||||
interval = 7.0,
|
action = function(pos, node)
|
||||||
chance = 1,
|
|
||||||
action = function(pos, node, active_object_count, active_object_count_wider)
|
|
||||||
local l = tonumber(node.name:sub(-1))
|
local l = tonumber(node.name:sub(-1))
|
||||||
local meta = minetest.get_meta(pos)
|
local meta = minetest.get_meta(pos)
|
||||||
local h = meta:get_int("right") + 1
|
local h = meta:get_int("right") + 1
|
||||||
|
|
|
@ -220,9 +220,14 @@ farming.register_plant = function(name, def)
|
||||||
fixed = {-0.5, -0.5, -0.5, 0.5, -5/16, 0.5},
|
fixed = {-0.5, -0.5, -0.5, 0.5, -5/16, 0.5},
|
||||||
},
|
},
|
||||||
fertility = def.fertility,
|
fertility = def.fertility,
|
||||||
|
sounds = default.node_sound_dirt_defaults({
|
||||||
|
dug = {name = "default_grass_footstep", gain = 0.2},
|
||||||
|
place = {name = "default_place_node", gain = 0.25},
|
||||||
|
}),
|
||||||
|
|
||||||
on_place = function(itemstack, placer, pointed_thing)
|
on_place = function(itemstack, placer, pointed_thing)
|
||||||
return farming.place_seed(itemstack, placer, pointed_thing, mname .. ":seed_" .. pname)
|
return farming.place_seed(itemstack, placer, pointed_thing, mname .. ":seed_" .. pname)
|
||||||
end
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
-- Register harvest
|
-- Register harvest
|
||||||
|
|
|
@ -263,7 +263,7 @@ else
|
||||||
minetest.remove_node(p0)
|
minetest.remove_node(p0)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
if math.random(1, 4) == 1 then
|
if math.random(1, 3) == 1 then
|
||||||
-- remove flammable nodes around flame
|
-- remove flammable nodes around flame
|
||||||
local node = minetest.get_node(p)
|
local node = minetest.get_node(p)
|
||||||
local def = minetest.registered_nodes[node.name]
|
local def = minetest.registered_nodes[node.name]
|
||||||
|
|
|
@ -71,50 +71,52 @@ end
|
||||||
|
|
||||||
|
|
||||||
-- Flower spread
|
-- Flower spread
|
||||||
|
-- Public function to enable override by mods
|
||||||
|
|
||||||
minetest.register_abm({
|
function flowers.flower_spread(pos, node)
|
||||||
nodenames = {"group:flora"},
|
pos.y = pos.y - 1
|
||||||
neighbors = {"default:dirt_with_grass", "default:desert_sand"},
|
local under = minetest.get_node(pos)
|
||||||
interval = 13,
|
pos.y = pos.y + 1
|
||||||
chance = 96,
|
if under.name == "default:desert_sand" then
|
||||||
action = function(pos, node)
|
minetest.set_node(pos, {name = "default:dry_shrub"})
|
||||||
pos.y = pos.y - 1
|
return
|
||||||
local under = minetest.get_node(pos)
|
elseif under.name ~= "default:dirt_with_grass" and
|
||||||
pos.y = pos.y + 1
|
under.name ~= "default:dirt_with_dry_grass" then
|
||||||
if under.name == "default:desert_sand" then
|
return
|
||||||
minetest.set_node(pos, {name = "default:dry_shrub"})
|
end
|
||||||
elseif under.name ~= "default:dirt_with_grass" then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local light = minetest.get_node_light(pos)
|
local light = minetest.get_node_light(pos)
|
||||||
|
if not light or light < 13 then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local pos0 = vector.subtract(pos, 4)
|
||||||
|
local pos1 = vector.add(pos, 4)
|
||||||
|
if #minetest.find_nodes_in_area(pos0, pos1, "group:flora") > 3 then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local seedling = minetest.find_nodes_in_area_under_air(pos0, pos1,
|
||||||
|
{"default:dirt_with_grass", "default:dirt_with_dry_grass"})
|
||||||
|
if #seedling > 0 then
|
||||||
|
seedling = seedling[math.random(#seedling)]
|
||||||
|
seedling.y = seedling.y + 1
|
||||||
|
light = minetest.get_node_light(seedling)
|
||||||
if not light or light < 13 then
|
if not light or light < 13 then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
minetest.set_node(seedling, {name = node.name})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local pos0 = {x = pos.x - 4, y = pos.y - 4, z = pos.z - 4}
|
minetest.register_abm({
|
||||||
local pos1 = {x = pos.x + 4, y = pos.y + 4, z = pos.z + 4}
|
nodenames = {"group:flora"},
|
||||||
if #minetest.find_nodes_in_area(pos0, pos1, "group:flora_block") > 0 then
|
neighbors = {"default:dirt_with_grass", "default:dirt_with_dry_grass",
|
||||||
return
|
"default:desert_sand"},
|
||||||
end
|
interval = 13,
|
||||||
|
chance = 96,
|
||||||
local flowers = minetest.find_nodes_in_area(pos0, pos1, "group:flora")
|
action = function(...)
|
||||||
if #flowers > 3 then
|
flowers.flower_spread(...)
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local seedling = minetest.find_nodes_in_area(pos0, pos1, "default:dirt_with_grass")
|
|
||||||
if #seedling > 0 then
|
|
||||||
seedling = seedling[math.random(#seedling)]
|
|
||||||
seedling.y = seedling.y + 1
|
|
||||||
light = minetest.get_node_light(seedling)
|
|
||||||
if not light or light < 13 then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
if minetest.get_node(seedling).name == "air" then
|
|
||||||
minetest.set_node(seedling, {name = node.name})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -161,7 +163,9 @@ minetest.register_node("flowers:mushroom_brown", {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
-- mushroom spread and death
|
|
||||||
|
-- Mushroom spread and death
|
||||||
|
|
||||||
minetest.register_abm({
|
minetest.register_abm({
|
||||||
nodenames = {"flowers:mushroom_brown", "flowers:mushroom_red"},
|
nodenames = {"flowers:mushroom_brown", "flowers:mushroom_red"},
|
||||||
interval = 11,
|
interval = 11,
|
||||||
|
@ -169,17 +173,15 @@ minetest.register_abm({
|
||||||
action = function(pos, node)
|
action = function(pos, node)
|
||||||
if minetest.get_node_light(pos, nil) == 15 then
|
if minetest.get_node_light(pos, nil) == 15 then
|
||||||
minetest.remove_node(pos)
|
minetest.remove_node(pos)
|
||||||
end
|
|
||||||
local random = {
|
|
||||||
x = pos.x + math.random(-2,2),
|
|
||||||
y = pos.y + math.random(-1,1),
|
|
||||||
z = pos.z + math.random(-2,2)
|
|
||||||
}
|
|
||||||
local random_node = minetest.get_node_or_nil(random)
|
|
||||||
if not random_node then
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
if random_node.name ~= "air" then
|
local random = {
|
||||||
|
x = pos.x + math.random(-2, 2),
|
||||||
|
y = pos.y + math.random(-1, 1),
|
||||||
|
z = pos.z + math.random(-2, 2)
|
||||||
|
}
|
||||||
|
local random_node = minetest.get_node_or_nil(random)
|
||||||
|
if not random_node or random_node.name ~= "air" then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local node_under = minetest.get_node_or_nil({x = random.x,
|
local node_under = minetest.get_node_or_nil({x = random.x,
|
||||||
|
@ -187,15 +189,19 @@ minetest.register_abm({
|
||||||
if not node_under then
|
if not node_under then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
if minetest.get_item_group(node_under.name, "soil") ~= 0 and
|
|
||||||
minetest.get_node_light(pos, nil) <= 9 and
|
if (minetest.get_item_group(node_under.name, "soil") ~= 0 or
|
||||||
minetest.get_node_light(random, nil) <= 9 then
|
minetest.get_item_group(node_under.name, "tree") ~= 0) and
|
||||||
|
minetest.get_node_light(pos, 0.5) <= 3 and
|
||||||
|
minetest.get_node_light(random, 0.5) <= 3 then
|
||||||
minetest.set_node(random, {name = node.name})
|
minetest.set_node(random, {name = node.name})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
-- these old mushroom related nodes can be simplified now
|
|
||||||
|
-- These old mushroom related nodes can be simplified now
|
||||||
|
|
||||||
minetest.register_alias("flowers:mushroom_spores_brown", "flowers:mushroom_brown")
|
minetest.register_alias("flowers:mushroom_spores_brown", "flowers:mushroom_brown")
|
||||||
minetest.register_alias("flowers:mushroom_spores_red", "flowers:mushroom_red")
|
minetest.register_alias("flowers:mushroom_spores_red", "flowers:mushroom_red")
|
||||||
minetest.register_alias("flowers:mushroom_fertile_brown", "flowers:mushroom_brown")
|
minetest.register_alias("flowers:mushroom_fertile_brown", "flowers:mushroom_brown")
|
||||||
|
@ -220,6 +226,7 @@ minetest.register_node("flowers:waterlily", {
|
||||||
sunlight_propagates = true,
|
sunlight_propagates = true,
|
||||||
groups = {snappy = 3, flower = 1},
|
groups = {snappy = 3, flower = 1},
|
||||||
sounds = default.node_sound_leaves_defaults(),
|
sounds = default.node_sound_leaves_defaults(),
|
||||||
|
node_placement_prediction = "",
|
||||||
node_box = {
|
node_box = {
|
||||||
type = "fixed",
|
type = "fixed",
|
||||||
fixed = {-0.5, -0.5, -0.5, 0.5, -0.46875, 0.5}
|
fixed = {-0.5, -0.5, -0.5, 0.5, -0.46875, 0.5}
|
||||||
|
@ -229,12 +236,22 @@ minetest.register_node("flowers:waterlily", {
|
||||||
fixed = {-0.5, -0.5, -0.5, 0.5, -0.4375, 0.5}
|
fixed = {-0.5, -0.5, -0.5, 0.5, -0.4375, 0.5}
|
||||||
},
|
},
|
||||||
|
|
||||||
on_place = function(_, _, pointed_thing)
|
on_place = function(itemstack, placer, pointed_thing)
|
||||||
local pos = pointed_thing.above
|
local pos = pointed_thing.above
|
||||||
local node = minetest.get_node(pointed_thing.under).name
|
local node = minetest.get_node(pointed_thing.under).name
|
||||||
local def = minetest.registered_nodes[node]
|
local def = minetest.registered_nodes[node]
|
||||||
|
local player_name = placer:get_player_name()
|
||||||
|
|
||||||
if def and def.liquidtype == "source" and minetest.get_item_group(node, "water") > 0 then
|
if def and def.liquidtype == "source" and minetest.get_item_group(node, "water") > 0 then
|
||||||
minetest.set_node(pos, {name = "flowers:waterlily", param2 = math.random(0, 3)})
|
if not minetest.is_protected(pos, player_name) then
|
||||||
|
minetest.set_node(pos, {name = "flowers:waterlily", param2 = math.random(0, 3)})
|
||||||
|
else
|
||||||
|
minetest.chat_send_player(player_name, "This area is protected")
|
||||||
|
end
|
||||||
|
if not minetest.setting_getbool("creative_mode") then
|
||||||
|
itemstack:take_item()
|
||||||
|
return itemstack
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,15 +1,6 @@
|
||||||
-- TNT will need privilege!
|
tnt = {}
|
||||||
core.register_privilege("trusted_player", "special grantings, used for tnt for example")
|
core.register_privilege("trusted_player", "special grantings, used for tnt for example")
|
||||||
|
|
||||||
---We want to use it on server, so this is commented
|
|
||||||
-- Default to enabled in singleplayer and disabled in multiplayer
|
|
||||||
-- local singleplayer = minetest.is_singleplayer()
|
|
||||||
-- local setting = minetest.setting_getbool("enable_tnt")
|
|
||||||
-- if (not singleplayer and setting ~= true) or
|
|
||||||
-- (singleplayer and setting == false) then
|
|
||||||
-- return
|
|
||||||
-- end
|
|
||||||
|
|
||||||
-- loss probabilities array (one in X will be lost)
|
-- loss probabilities array (one in X will be lost)
|
||||||
local loss_prob = {}
|
local loss_prob = {}
|
||||||
|
|
||||||
|
@ -52,23 +43,22 @@ local function eject_drops(drops, pos, radius)
|
||||||
local drop_pos = vector.new(pos)
|
local drop_pos = vector.new(pos)
|
||||||
for _, item in pairs(drops) do
|
for _, item in pairs(drops) do
|
||||||
local count = item:get_count()
|
local count = item:get_count()
|
||||||
local max = item:get_stack_max()
|
|
||||||
if count > max then
|
|
||||||
item:set_count(max)
|
|
||||||
end
|
|
||||||
while count > 0 do
|
while count > 0 do
|
||||||
if count < max then
|
local take = math.max(1,math.min(radius * radius,
|
||||||
item:set_count(count)
|
item:get_count(),
|
||||||
end
|
item:get_stack_max()))
|
||||||
rand_pos(pos, drop_pos, radius)
|
rand_pos(pos, drop_pos, radius)
|
||||||
local obj = minetest.add_item(drop_pos, item)
|
local dropitem = ItemStack(item)
|
||||||
|
dropitem:set_count(take)
|
||||||
|
local obj = minetest.add_item(drop_pos, dropitem)
|
||||||
if obj then
|
if obj then
|
||||||
obj:get_luaentity().collect = true
|
obj:get_luaentity().collect = true
|
||||||
obj:setacceleration({x=0, y=-10, z=0})
|
obj:setacceleration({x = 0, y = -10, z = 0})
|
||||||
obj:setvelocity({x=math.random(-3, 3), y=10,
|
obj:setvelocity({x = math.random(-3, 3),
|
||||||
z=math.random(-3, 3)})
|
y = math.random(0, 10),
|
||||||
|
z = math.random(-3, 3)})
|
||||||
end
|
end
|
||||||
count = count - max
|
count = count - take
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -88,27 +78,27 @@ local function add_drop(drops, item)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local fire_node = {name="fire:basic_flame"}
|
|
||||||
|
|
||||||
local function destroy(drops, pos, cid)
|
local function destroy(drops, npos, cid, c_air, c_fire, on_blast_queue, ignore_protection, ignore_on_blast)
|
||||||
if minetest.is_protected(pos, "") then
|
if not ignore_protection and minetest.is_protected(npos, "") then
|
||||||
return
|
return cid
|
||||||
end
|
end
|
||||||
|
|
||||||
local def = cid_data[cid]
|
local def = cid_data[cid]
|
||||||
if def and def.on_blast then
|
|
||||||
def.on_blast(vector.new(pos), 1)
|
if not def then
|
||||||
return
|
return c_air
|
||||||
end
|
elseif not ignore_on_blast and def.on_blast then
|
||||||
if def and def.flammable then
|
on_blast_queue[#on_blast_queue + 1] = {pos = vector.new(npos), on_blast = def.on_blast}
|
||||||
minetest.set_node(pos, fire_node)
|
return cid
|
||||||
|
elseif def.flammable then
|
||||||
|
return c_fire
|
||||||
else
|
else
|
||||||
minetest.remove_node(pos)
|
local node_drops = minetest.get_node_drops(def.name, "")
|
||||||
if def then
|
for _, item in ipairs(node_drops) do
|
||||||
local node_drops = minetest.get_node_drops(def.name, "")
|
add_drop(drops, item)
|
||||||
for _, item in ipairs(node_drops) do
|
|
||||||
add_drop(drops, item)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
return c_air
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -125,61 +115,179 @@ local function calc_velocity(pos1, pos2, old_vel, power)
|
||||||
|
|
||||||
-- Add old velocity
|
-- Add old velocity
|
||||||
vel = vector.add(vel, old_vel)
|
vel = vector.add(vel, old_vel)
|
||||||
|
|
||||||
|
-- randomize it a bit
|
||||||
|
vel = vector.add(vel, {
|
||||||
|
x = math.random() - 0.5,
|
||||||
|
y = math.random() - 0.5,
|
||||||
|
z = math.random() - 0.5,
|
||||||
|
})
|
||||||
|
|
||||||
|
-- Limit to terminal velocity
|
||||||
|
dist = vector.length(vel)
|
||||||
|
if dist > 250 then
|
||||||
|
vel = vector.divide(vel, dist / 250)
|
||||||
|
end
|
||||||
return vel
|
return vel
|
||||||
end
|
end
|
||||||
|
|
||||||
local function entity_physics(pos, radius)
|
local function entity_physics(pos, radius, drops)
|
||||||
-- Make the damage radius larger than the destruction radius
|
|
||||||
radius = radius * 2
|
|
||||||
local objs = minetest.get_objects_inside_radius(pos, radius)
|
local objs = minetest.get_objects_inside_radius(pos, radius)
|
||||||
for _, obj in pairs(objs) do
|
for _, obj in pairs(objs) do
|
||||||
local obj_pos = obj:getpos()
|
local obj_pos = obj:getpos()
|
||||||
local obj_vel = obj:getvelocity()
|
|
||||||
local dist = math.max(1, vector.distance(pos, obj_pos))
|
local dist = math.max(1, vector.distance(pos, obj_pos))
|
||||||
|
|
||||||
if obj_vel ~= nil then
|
|
||||||
obj:setvelocity(calc_velocity(pos, obj_pos,
|
|
||||||
obj_vel, radius * 10))
|
|
||||||
end
|
|
||||||
|
|
||||||
local damage = (4 / dist) * radius
|
local damage = (4 / dist) * radius
|
||||||
obj:set_hp(obj:get_hp() - damage)
|
if obj:is_player() then
|
||||||
|
-- currently the engine has no method to set
|
||||||
|
-- player velocity. See #2960
|
||||||
|
-- instead, we knock the player back 1.0 node, and slightly upwards
|
||||||
|
local dir = vector.normalize(vector.subtract(obj_pos, pos))
|
||||||
|
local moveoff = vector.multiply(dir, dist + 1.0)
|
||||||
|
local newpos = vector.add(pos, moveoff)
|
||||||
|
local newpos = vector.add(newpos, {x = 0, y = 0.2, z = 0})
|
||||||
|
obj:setpos(newpos)
|
||||||
|
|
||||||
|
obj:set_hp(obj:get_hp() - damage)
|
||||||
|
else
|
||||||
|
local do_damage = true
|
||||||
|
local do_knockback = true
|
||||||
|
local entity_drops = {}
|
||||||
|
local luaobj = obj:get_luaentity()
|
||||||
|
local objdef = minetest.registered_entities[luaobj.name]
|
||||||
|
|
||||||
|
if objdef and objdef.on_blast then
|
||||||
|
do_damage, do_knockback, entity_drops = objdef.on_blast(luaobj, damage)
|
||||||
|
end
|
||||||
|
|
||||||
|
if do_knockback then
|
||||||
|
local obj_vel = obj:getvelocity()
|
||||||
|
obj:setvelocity(calc_velocity(pos, obj_pos,
|
||||||
|
obj_vel, radius * 10))
|
||||||
|
end
|
||||||
|
if do_damage then
|
||||||
|
if not obj:get_armor_groups().immortal then
|
||||||
|
obj:punch(obj, 1.0, {
|
||||||
|
full_punch_interval = 1.0,
|
||||||
|
damage_groups = {fleshy = damage},
|
||||||
|
}, nil)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for _, item in ipairs(entity_drops) do
|
||||||
|
add_drop(drops, item)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function add_effects(pos, radius)
|
local function add_effects(pos, radius, drops)
|
||||||
|
minetest.add_particle({
|
||||||
|
pos = pos,
|
||||||
|
velocity = vector.new(),
|
||||||
|
acceleration = vector.new(),
|
||||||
|
expirationtime = 0.4,
|
||||||
|
size = radius * 10,
|
||||||
|
collisiondetection = false,
|
||||||
|
vertical = false,
|
||||||
|
texture = "tnt_boom.png",
|
||||||
|
})
|
||||||
minetest.add_particlespawner({
|
minetest.add_particlespawner({
|
||||||
amount = 128,
|
amount = 64,
|
||||||
time = 1,
|
time = 0.5,
|
||||||
minpos = vector.subtract(pos, radius / 2),
|
minpos = vector.subtract(pos, radius / 2),
|
||||||
maxpos = vector.add(pos, radius / 2),
|
maxpos = vector.add(pos, radius / 2),
|
||||||
minvel = {x=-20, y=-20, z=-20},
|
minvel = {x = -10, y = -10, z = -10},
|
||||||
maxvel = {x=20, y=20, z=20},
|
maxvel = {x = 10, y = 10, z = 10},
|
||||||
minacc = vector.new(),
|
minacc = vector.new(),
|
||||||
maxacc = vector.new(),
|
maxacc = vector.new(),
|
||||||
minexptime = 1,
|
minexptime = 1,
|
||||||
maxexptime = 3,
|
maxexptime = 2.5,
|
||||||
minsize = 8,
|
minsize = radius * 3,
|
||||||
maxsize = 16,
|
maxsize = radius * 5,
|
||||||
texture = "tnt_smoke.png",
|
texture = "tnt_smoke.png",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
-- we just dropped some items. Look at the items entities and pick
|
||||||
|
-- one of them to use as texture
|
||||||
|
local texture = "tnt_blast.png" --fallback texture
|
||||||
|
local most = 0
|
||||||
|
for name, stack in pairs(drops) do
|
||||||
|
local count = stack:get_count()
|
||||||
|
if count > most then
|
||||||
|
most = count
|
||||||
|
local def = minetest.registered_nodes[name]
|
||||||
|
if def and def.tiles and def.tiles[1] then
|
||||||
|
texture = def.tiles[1]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.add_particlespawner({
|
||||||
|
amount = 64,
|
||||||
|
time = 0.1,
|
||||||
|
minpos = vector.subtract(pos, radius / 2),
|
||||||
|
maxpos = vector.add(pos, radius / 2),
|
||||||
|
minvel = {x = -3, y = 0, z = -3},
|
||||||
|
maxvel = {x = 3, y = 5, z = 3},
|
||||||
|
minacc = {x = 0, y = -10, z = 0},
|
||||||
|
maxacc = {x = 0, y = -10, z = 0},
|
||||||
|
minexptime = 0.8,
|
||||||
|
maxexptime = 2.0,
|
||||||
|
minsize = radius * 0.66,
|
||||||
|
maxsize = radius * 2,
|
||||||
|
texture = texture,
|
||||||
|
collisiondetection = true,
|
||||||
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
local function burn(pos)
|
function tnt.burn(pos)
|
||||||
local name = minetest.get_node(pos).name
|
local name = minetest.get_node(pos).name
|
||||||
if name == "tnt:tnt" then
|
local group = minetest.get_item_group(name, "tnt")
|
||||||
minetest.sound_play("tnt_ignite", {pos=pos})
|
if group > 0 then
|
||||||
minetest.set_node(pos, {name="tnt:tnt_burning"})
|
minetest.sound_play("tnt_ignite", {pos = pos})
|
||||||
|
minetest.set_node(pos, {name = name .. "_burning"})
|
||||||
minetest.get_node_timer(pos):start(1)
|
minetest.get_node_timer(pos):start(1)
|
||||||
elseif name == "tnt:gunpowder" then
|
elseif name == "tnt:gunpowder" then
|
||||||
minetest.sound_play("tnt_gunpowder_burning", {pos=pos, gain=2})
|
minetest.set_node(pos, {name = "tnt:gunpowder_burning"})
|
||||||
minetest.set_node(pos, {name="tnt:gunpowder_burning"})
|
|
||||||
minetest.get_node_timer(pos):start(1)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function explode(pos, radius)
|
local function tnt_explode(pos, radius, ignore_protection, ignore_on_blast)
|
||||||
local pos = vector.round(pos)
|
local pos = vector.round(pos)
|
||||||
|
-- scan for adjacent TNT nodes first, and enlarge the explosion
|
||||||
|
local vm1 = VoxelManip()
|
||||||
|
local p1 = vector.subtract(pos, 2)
|
||||||
|
local p2 = vector.add(pos, 2)
|
||||||
|
local minp, maxp = vm1:read_from_map(p1, p2)
|
||||||
|
local a = VoxelArea:new({MinEdge = minp, MaxEdge = maxp})
|
||||||
|
local data = vm1:get_data()
|
||||||
|
local count = 0
|
||||||
|
local c_tnt = minetest.get_content_id("tnt:tnt")
|
||||||
|
local c_tnt_burning = minetest.get_content_id("tnt:tnt_burning")
|
||||||
|
local c_tnt_boom = minetest.get_content_id("tnt:boom")
|
||||||
|
local c_air = minetest.get_content_id("air")
|
||||||
|
|
||||||
|
for z = pos.z - 2, pos.z + 2 do
|
||||||
|
for y = pos.y - 2, pos.y + 2 do
|
||||||
|
local vi = a:index(pos.x - 2, y, z)
|
||||||
|
for x = pos.x - 2, pos.x + 2 do
|
||||||
|
local cid = data[vi]
|
||||||
|
if cid == c_tnt or cid == c_tnt_boom or cid == c_tnt_burning then
|
||||||
|
count = count + 1
|
||||||
|
data[vi] = c_air
|
||||||
|
end
|
||||||
|
vi = vi + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
vm1:set_data(data)
|
||||||
|
vm1:write_to_map()
|
||||||
|
|
||||||
|
-- recalculate new radius
|
||||||
|
radius = math.floor(radius * math.pow(count, 1/3))
|
||||||
|
|
||||||
|
-- perform the explosion
|
||||||
local vm = VoxelManip()
|
local vm = VoxelManip()
|
||||||
local pr = PseudoRandom(os.time())
|
local pr = PseudoRandom(os.time())
|
||||||
local p1 = vector.subtract(pos, radius)
|
local p1 = vector.subtract(pos, radius)
|
||||||
|
@ -189,22 +297,21 @@ local function explode(pos, radius)
|
||||||
local data = vm:get_data()
|
local data = vm:get_data()
|
||||||
|
|
||||||
local drops = {}
|
local drops = {}
|
||||||
local p = {}
|
local on_blast_queue = {}
|
||||||
|
|
||||||
local c_air = minetest.get_content_id("air")
|
|
||||||
|
|
||||||
|
local c_fire = minetest.get_content_id("fire:basic_flame")
|
||||||
for z = -radius, radius do
|
for z = -radius, radius do
|
||||||
for y = -radius, radius do
|
for y = -radius, radius do
|
||||||
local vi = a:index(pos.x + (-radius), pos.y + y, pos.z + z)
|
local vi = a:index(pos.x + (-radius), pos.y + y, pos.z + z)
|
||||||
for x = -radius, radius do
|
for x = -radius, radius do
|
||||||
if (x * x) + (y * y) + (z * z) <=
|
local r = vector.length(vector.new(x, y, z))
|
||||||
(radius * radius) + pr:next(-radius, radius) then
|
if (radius * radius) / (r * r) >= (pr:next(80, 125) / 100) then
|
||||||
local cid = data[vi]
|
local cid = data[vi]
|
||||||
p.x = pos.x + x
|
local p = {x = pos.x + x, y = pos.y + y, z = pos.z + z}
|
||||||
p.y = pos.y + y
|
|
||||||
p.z = pos.z + z
|
|
||||||
if cid ~= c_air then
|
if cid ~= c_air then
|
||||||
destroy(drops, p, cid)
|
data[vi] = destroy(drops, p, cid, c_air, c_fire,
|
||||||
|
on_blast_queue, ignore_protection,
|
||||||
|
ignore_on_blast)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
vi = vi + 1
|
vi = vi + 1
|
||||||
|
@ -212,71 +319,61 @@ local function explode(pos, radius)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return drops
|
vm:set_data(data)
|
||||||
end
|
vm:write_to_map()
|
||||||
|
vm:update_map()
|
||||||
|
vm:update_liquids()
|
||||||
|
|
||||||
|
-- call nodeupdate for everything within 1.5x blast radius
|
||||||
|
for z = -radius * 1.5, radius * 1.5 do
|
||||||
|
for x = -radius * 1.5, radius * 1.5 do
|
||||||
|
for y = -radius * 1.5, radius * 1.5 do
|
||||||
|
local s = vector.add(pos, {x = x, y = y, z = z})
|
||||||
|
local r = vector.distance(pos, s)
|
||||||
|
if r / radius < 1.4 then
|
||||||
|
nodeupdate(s)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local function boom(pos)
|
for _, data in ipairs(on_blast_queue) do
|
||||||
minetest.sound_play("tnt_explode", {pos=pos, gain=1.5, max_hear_distance=2*64})
|
local dist = math.max(1, vector.distance(data.pos, pos))
|
||||||
minetest.set_node(pos, {name="tnt:boom"})
|
local intensity = (radius * radius) / (dist * dist)
|
||||||
minetest.get_node_timer(pos):start(0.5)
|
local node_drops = data.on_blast(data.pos, intensity)
|
||||||
|
if node_drops then
|
||||||
local drops = explode(pos, radius)
|
for _, item in ipairs(node_drops) do
|
||||||
entity_physics(pos, radius)
|
add_drop(drops, item)
|
||||||
eject_drops(drops, pos, radius)
|
|
||||||
add_effects(pos, radius)
|
|
||||||
end
|
|
||||||
|
|
||||||
minetest.register_node("tnt:tnt", {
|
|
||||||
description = "TNT",
|
|
||||||
tiles = {"tnt_top.png", "tnt_bottom.png", "tnt_side.png"},
|
|
||||||
is_ground_content = false,
|
|
||||||
groups = {dig_immediate=2},
|
|
||||||
sounds = default.node_sound_wood_defaults(),
|
|
||||||
on_punch = function(pos, node, puncher)
|
|
||||||
if puncher:get_wielded_item():get_name() == "default:torch" then
|
|
||||||
if(minetest.check_player_privs(puncher:get_player_name(), {trusted_player=true})) then
|
|
||||||
minetest.sound_play("tnt_ignite", {pos=pos})
|
|
||||||
minetest.set_node(pos, {name="tnt:tnt_burning"})
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end,
|
end
|
||||||
on_blast = function(pos, intensity)
|
|
||||||
burn(pos)
|
|
||||||
end,
|
|
||||||
--mesecons = {effector = {action_on = boom}},
|
|
||||||
})
|
|
||||||
|
|
||||||
minetest.register_node("tnt:tnt_burning", {
|
return drops, radius
|
||||||
tiles = {
|
end
|
||||||
{
|
|
||||||
name = "tnt_top_burning_animated.png",
|
function tnt.boom(pos, def)
|
||||||
animation = {
|
minetest.sound_play("tnt_explode", {pos = pos, gain = 1.5, max_hear_distance = 2*64})
|
||||||
type = "vertical_frames",
|
minetest.set_node(pos, {name = "tnt:boom"})
|
||||||
aspect_w = 16,
|
local drops, radius = tnt_explode(pos, def.radius, def.ignore_protection,
|
||||||
aspect_h = 16,
|
def.ignore_on_blast)
|
||||||
length = 1,
|
-- append entity drops
|
||||||
}
|
local damage_radius = (radius / def.radius) * def.damage_radius
|
||||||
},
|
entity_physics(pos, damage_radius, drops)
|
||||||
"tnt_bottom.png", "tnt_side.png"},
|
if not def.disable_drops then
|
||||||
light_source = 5,
|
eject_drops(drops, pos, radius)
|
||||||
drop = "",
|
end
|
||||||
sounds = default.node_sound_wood_defaults(),
|
add_effects(pos, radius, drops)
|
||||||
on_construct = function(pos)
|
end
|
||||||
minetest.get_node_timer(pos):start(4)
|
|
||||||
end,
|
|
||||||
on_timer = boom,
|
|
||||||
-- unaffected by explosions
|
|
||||||
on_blast = function() end,
|
|
||||||
})
|
|
||||||
|
|
||||||
minetest.register_node("tnt:boom", {
|
minetest.register_node("tnt:boom", {
|
||||||
drawtype = "plantlike",
|
drawtype = "airlike",
|
||||||
tiles = {"tnt_boom.png"},
|
|
||||||
light_source = default.LIGHT_MAX,
|
light_source = default.LIGHT_MAX,
|
||||||
walkable = false,
|
walkable = false,
|
||||||
drop = "",
|
drop = "",
|
||||||
groups = {dig_immediate=3},
|
groups = {dig_immediate = 3},
|
||||||
|
on_construct = function(pos)
|
||||||
|
minetest.get_node_timer(pos):start(0.4)
|
||||||
|
end,
|
||||||
on_timer = function(pos, elapsed)
|
on_timer = function(pos, elapsed)
|
||||||
minetest.remove_node(pos)
|
minetest.remove_node(pos)
|
||||||
end,
|
end,
|
||||||
|
@ -298,18 +395,18 @@ minetest.register_node("tnt:gunpowder", {
|
||||||
type = "fixed",
|
type = "fixed",
|
||||||
fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2},
|
fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2},
|
||||||
},
|
},
|
||||||
groups = {dig_immediate=2,attached_node=1,connect_to_raillike=minetest.raillike_group("gunpowder")},
|
groups = {dig_immediate = 2, attached_node = 1, connect_to_raillike = minetest.raillike_group("gunpowder")},
|
||||||
sounds = default.node_sound_leaves_defaults(),
|
sounds = default.node_sound_leaves_defaults(),
|
||||||
|
|
||||||
on_punch = function(pos, node, puncher)
|
on_punch = function(pos, node, puncher)
|
||||||
if puncher:get_wielded_item():get_name() == "default:torch" then
|
if puncher:get_wielded_item():get_name() == "default:torch" then
|
||||||
if(minetest.check_player_privs(puncher:get_player_name(), {trusted_player=true})) then
|
if(minetest.check_player_privs(puncher:get_player_name(), {trusted_player=true})) then
|
||||||
burn(pos)
|
tnt.burn(pos)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
on_blast = function(pos, intensity)
|
on_blast = function(pos, intensity)
|
||||||
burn(pos)
|
tnt.burn(pos)
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -360,14 +457,14 @@ minetest.register_node("tnt:gunpowder_burning", {
|
||||||
fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2},
|
fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2},
|
||||||
},
|
},
|
||||||
drop = "",
|
drop = "",
|
||||||
groups = {dig_immediate=2,attached_node=1,connect_to_raillike=minetest.raillike_group("gunpowder")},
|
groups = {dig_immediate = 2, attached_node = 1, connect_to_raillike = minetest.raillike_group("gunpowder")},
|
||||||
sounds = default.node_sound_leaves_defaults(),
|
sounds = default.node_sound_leaves_defaults(),
|
||||||
on_timer = function(pos, elapsed)
|
on_timer = function(pos, elapsed)
|
||||||
for dx = -1, 1 do
|
for dx = -1, 1 do
|
||||||
for dz = -1, 1 do
|
for dz = -1, 1 do
|
||||||
for dy = -1, 1 do
|
for dy = -1, 1 do
|
||||||
if not (dx == 0 and dz == 0) then
|
if not (dx == 0 and dz == 0) then
|
||||||
burn({
|
tnt.burn({
|
||||||
x = pos.x + dx,
|
x = pos.x + dx,
|
||||||
y = pos.y + dy,
|
y = pos.y + dy,
|
||||||
z = pos.z + dz,
|
z = pos.z + dz,
|
||||||
|
@ -380,14 +477,18 @@ minetest.register_node("tnt:gunpowder_burning", {
|
||||||
end,
|
end,
|
||||||
-- unaffected by explosions
|
-- unaffected by explosions
|
||||||
on_blast = function() end,
|
on_blast = function() end,
|
||||||
|
on_construct = function(pos)
|
||||||
|
minetest.sound_play("tnt_gunpowder_burning", {pos = pos, gain = 2})
|
||||||
|
minetest.get_node_timer(pos):start(1)
|
||||||
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_abm({
|
minetest.register_abm({
|
||||||
nodenames = {"tnt:tnt", "tnt:gunpowder"},
|
nodenames = {"group:tnt", "tnt:gunpowder"},
|
||||||
neighbors = {"fire:basic_flame", "default:lava_source", "default:lava_flowing"},
|
neighbors = {"fire:basic_flame", "default:lava_source", "default:lava_flowing"},
|
||||||
interval = 4,
|
interval = 4,
|
||||||
chance = 1,
|
chance = 1,
|
||||||
action = burn,
|
action = tnt.burn,
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_craft({
|
minetest.register_craft({
|
||||||
|
@ -404,3 +505,82 @@ minetest.register_craft({
|
||||||
{"", "group:wood", ""}
|
{"", "group:wood", ""}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
function tnt.register_tnt(def)
|
||||||
|
local name = ""
|
||||||
|
if not def.name:find(':') then
|
||||||
|
name = "tnt:" .. def.name
|
||||||
|
else
|
||||||
|
name = def.name
|
||||||
|
def.name = def.name:match(":([%w_]+)")
|
||||||
|
end
|
||||||
|
if not def.tiles then def.tiles = {} end
|
||||||
|
local tnt_top = def.tiles.top or def.name .. "_top.png"
|
||||||
|
local tnt_bottom = def.tiles.bottom or def.name .. "_bottom.png"
|
||||||
|
local tnt_side = def.tiles.side or def.name .. "_side.png"
|
||||||
|
local tnt_burning = def.tiles.burning or def.name .. "_top_burning_animated.png"
|
||||||
|
if not def.damage_radius then def.damage_radius = def.radius * 2 end
|
||||||
|
|
||||||
|
minetest.register_node(":" .. name, {
|
||||||
|
description = def.description,
|
||||||
|
tiles = {tnt_top, tnt_bottom, tnt_side},
|
||||||
|
is_ground_content = false,
|
||||||
|
groups = {dig_immediate = 2, mesecon = 2, tnt = 1},
|
||||||
|
sounds = default.node_sound_wood_defaults(),
|
||||||
|
on_punch = function(pos, node, puncher)
|
||||||
|
if puncher:get_wielded_item():get_name() == "default:torch" then
|
||||||
|
if(minetest.check_player_privs(puncher:get_player_name(), {trusted_player=true})) then
|
||||||
|
minetest.set_node(pos, {name = name .. "_burning"})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
on_blast = function(pos, intensity)
|
||||||
|
minetest.after(0.1, function()
|
||||||
|
tnt.boom(pos, def)
|
||||||
|
end)
|
||||||
|
end,
|
||||||
|
--mesecons = {effector =
|
||||||
|
-- {action_on =
|
||||||
|
-- function(pos)
|
||||||
|
-- tnt.boom(pos, def)
|
||||||
|
-- end
|
||||||
|
-- }
|
||||||
|
--},
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_node(":" .. name .. "_burning", {
|
||||||
|
tiles = {
|
||||||
|
{
|
||||||
|
name = tnt_burning,
|
||||||
|
animation = {
|
||||||
|
type = "vertical_frames",
|
||||||
|
aspect_w = 16,
|
||||||
|
aspect_h = 16,
|
||||||
|
length = 1,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tnt_bottom, tnt_side
|
||||||
|
},
|
||||||
|
light_source = 5,
|
||||||
|
drop = "",
|
||||||
|
sounds = default.node_sound_wood_defaults(),
|
||||||
|
groups = {falling_node = 1},
|
||||||
|
on_timer = function(pos, elapsed)
|
||||||
|
tnt.boom(pos, def)
|
||||||
|
end,
|
||||||
|
-- unaffected by explosions
|
||||||
|
on_blast = function() end,
|
||||||
|
on_construct = function(pos)
|
||||||
|
minetest.sound_play("tnt_ignite", {pos = pos})
|
||||||
|
minetest.get_node_timer(pos):start(4)
|
||||||
|
nodeupdate(pos)
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
tnt.register_tnt({
|
||||||
|
name = "tnt:tnt",
|
||||||
|
description = "TNT",
|
||||||
|
radius = radius,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
BIN
mods/tnt/textures/tnt_blast.png
Normal file
After Width: | Height: | Size: 855 B |
|
@ -15,7 +15,7 @@ local vessels_shelf_formspec =
|
||||||
|
|
||||||
minetest.register_node("vessels:shelf", {
|
minetest.register_node("vessels:shelf", {
|
||||||
description = "Vessels shelf",
|
description = "Vessels shelf",
|
||||||
tiles = {"default_wood.png", "default_wood.png", "default_wood.png^vessels_shelf.png"},
|
tiles = {"default_wood.png", "default_wood.png", "vessels_shelf.png"},
|
||||||
is_ground_content = false,
|
is_ground_content = false,
|
||||||
groups = {choppy=3,oddly_breakable_by_hand=2,flammable=3},
|
groups = {choppy=3,oddly_breakable_by_hand=2,flammable=3},
|
||||||
sounds = default.node_sound_wood_defaults(),
|
sounds = default.node_sound_wood_defaults(),
|
||||||
|
@ -48,6 +48,13 @@ minetest.register_node("vessels:shelf", {
|
||||||
minetest.log("action", player:get_player_name() ..
|
minetest.log("action", player:get_player_name() ..
|
||||||
" takes stuff from vessels shelf at ".. minetest.pos_to_string(pos))
|
" takes stuff from vessels shelf at ".. minetest.pos_to_string(pos))
|
||||||
end,
|
end,
|
||||||
|
on_blast = function(pos)
|
||||||
|
local drops = {}
|
||||||
|
default.get_inventory_drops(pos, "vessels", drops)
|
||||||
|
drops[#drops+1] = "vessels:shelf"
|
||||||
|
minetest.remove_node(pos)
|
||||||
|
return drops
|
||||||
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_craft({
|
minetest.register_craft({
|
||||||
|
|