Compare commits
101 Commits
evokers_sp
...
master
Author | SHA1 | Date |
---|---|---|
cora | 04f0ea260d | |
NO11 | 5974b6f609 | |
NO411 | 148be4ea39 | |
NO411 | 6afe7cfb58 | |
cora | 8e24e6edfe | |
AFCMS | 909b77ce4d | |
cora | 1dde51dd0b | |
NO11 | 63a156c30c | |
cora | 1c9f0c3238 | |
cora | 50e99f470e | |
NO411 | aeff7cf1a4 | |
cora | bc723616ea | |
kabou | 46ee5aaa59 | |
cora | 3dd4eec4e8 | |
NO411 | 019dd45381 | |
NO411 | d481f7b720 | |
NO411 | c94964d10a | |
kabou | a9a3f01a0e | |
kabou | ae6bea73fd | |
kabou | 2002872af8 | |
kabou | 8518ce2c19 | |
NO411 | 6158e4e50d | |
NO411 | 7c0a48bebf | |
NO411 | 5bdf83cbfc | |
NO411 | 976cfba53a | |
NO411 | fc9e83c059 | |
NO411 | 60d877b718 | |
cora | 81a1b9973a | |
kabou | 9eba0e4860 | |
kabou | 90311da514 | |
kabou | e9ff2ba32a | |
cora | 0b89149fe2 | |
cora | 7df6c8739e | |
cora | cd725137ae | |
NO411 | 0f8f5a41d2 | |
NO411 | db68c0e26b | |
NO11 | 627da6d305 | |
cora | 1803cc560d | |
kabou | 3f787f8305 | |
epCode | 9534624b21 | |
epCode | 4483f4b6b6 | |
cora | d3bfdb190e | |
AFCMS | 47b1eeda74 | |
cora | ba0e2cbf29 | |
Freedom | f430aec0cd | |
NO11 | a44846a82c | |
cora | 22edd08387 | |
kabou | 17b8eab368 | |
cora | 119b4aa82c | |
cora | 181c3f0c0f | |
cora | 21e7ab1f2a | |
cora | 6f284c0c95 | |
cora | e0801ba7e4 | |
cora | 267031793d | |
MysticTempest | de3cdee09e | |
cora | c5993a60ae | |
Nils Dagsson Moskopp | 77f8ecd6e8 | |
Nils Dagsson Moskopp | 4da5084daf | |
cora | dca653651c | |
kabou | deed231f28 | |
kabou | 11ee1d133f | |
kabou | 1326b9e7e7 | |
kabou | 6a69f49fa0 | |
kabou | f5a8d6d17a | |
kabou | 3f4dafc68f | |
kabou | 9bac0da01a | |
kabou | 818cbb2f48 | |
kabou | 88f7a150c7 | |
kabou | 962500b189 | |
kabou | 95cfa43483 | |
kabou | 4a1b93bbfa | |
kabou | b9c2c3bd0a | |
cora | 52333cea0f | |
Dieter44 | f8c60b5f75 | |
cora | bcf302ceb0 | |
MysticTempest | 7a53ea8b70 | |
cora | e8ff33a741 | |
Elias Åström | 3c10f0e970 | |
cora | f7d712543f | |
kabou | c3e0996902 | |
kabou | d424d4f10e | |
kabou | e80006f4ea | |
kabou | b17776699e | |
kabou | 86a4ece7d2 | |
kabou | df5d24104d | |
cora | 8dd540269c | |
kabou | 56b63463a5 | |
cora | c2ae28aec1 | |
Nils Dagsson Moskopp | 66bb209ad1 | |
cora | a3e01e6dbe | |
AFCMS | 5a7b1cc382 | |
AFCMS | 210a0d8ee1 | |
AFCMS | eae8effd57 | |
AFCMS | b51e322304 | |
AFCMS | 096d46152e | |
AFCMS | d89687984b | |
AFCMS | c6f72c473f | |
AFCMS | 540b72f1d6 | |
AFCMS | 7449725a56 | |
AFCMS | 9e7a525a0a | |
AFCMS | 4bd91750bc |
21
CREDITS.md
|
@ -6,10 +6,14 @@
|
||||||
## Creator of MineClone2
|
## Creator of MineClone2
|
||||||
* Wuzzy
|
* Wuzzy
|
||||||
|
|
||||||
|
|
||||||
## Maintainers
|
## Maintainers
|
||||||
* Fleckenstein
|
|
||||||
* Nicu
|
* Nicu
|
||||||
* kay27
|
* cora
|
||||||
|
|
||||||
|
## Previous Maintainers
|
||||||
|
* Fleckenstein
|
||||||
|
* jordan4ibanez
|
||||||
|
|
||||||
## Developers
|
## Developers
|
||||||
* bzoss
|
* bzoss
|
||||||
|
@ -22,8 +26,7 @@
|
||||||
* aligator
|
* aligator
|
||||||
* Code-Sploit
|
* Code-Sploit
|
||||||
* NO11
|
* NO11
|
||||||
* cora
|
* kabou
|
||||||
* jordan4ibanez
|
|
||||||
|
|
||||||
## Contributors
|
## Contributors
|
||||||
* Laurent Rocher
|
* Laurent Rocher
|
||||||
|
@ -75,6 +78,16 @@
|
||||||
* epCode
|
* epCode
|
||||||
* NO11
|
* NO11
|
||||||
* j45
|
* j45
|
||||||
|
* 3raven
|
||||||
|
* PrarieWind
|
||||||
|
* Gustavo1
|
||||||
|
* CableGuy67
|
||||||
|
|
||||||
|
## Mineclonia
|
||||||
|
* erlehmann
|
||||||
|
* Li0n
|
||||||
|
* E
|
||||||
|
* n_to
|
||||||
|
|
||||||
## Original Mod Authors
|
## Original Mod Authors
|
||||||
* Wuzzy
|
* Wuzzy
|
||||||
|
|
|
@ -56,6 +56,7 @@ Please read <http://minecraft.gamepedia.com/Breaking> to learn how digging times
|
||||||
* `no_eat_delay=1`: Only for foodstuffs. When eating this, all eating delays are ignored.
|
* `no_eat_delay=1`: Only for foodstuffs. When eating this, all eating delays are ignored.
|
||||||
* `can_eat_when_full=1`: Only for foodstuffs. This item can be eaten when the user has a full hunger bar
|
* `can_eat_when_full=1`: Only for foodstuffs. This item can be eaten when the user has a full hunger bar
|
||||||
* `attached_node_facedir=1`: Like `attached_node`, but for facedir nodes
|
* `attached_node_facedir=1`: Like `attached_node`, but for facedir nodes
|
||||||
|
* `supported_node=1`: Like `attached_node`, but can be placed on any nodes that do not have the `drawtype="airlike"` attribute.
|
||||||
* `cauldron`: Cauldron. 1: Empty. 2-4: Water height
|
* `cauldron`: Cauldron. 1: Empty. 2-4: Water height
|
||||||
* `anvil`: Anvil. 1: No damage. 2-3: Higher damage levels
|
* `anvil`: Anvil. 1: No damage. 2-3: Higher damage levels
|
||||||
* `no_rename=1`: Item cannot be renamed by anvil
|
* `no_rename=1`: Item cannot be renamed by anvil
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
An unofficial Minecraft-like game for Minetest. Forked from MineClone by davedevils.
|
An unofficial Minecraft-like game for Minetest. Forked from MineClone by davedevils.
|
||||||
Developed by many people. Not developed or endorsed by Mojang AB.
|
Developed by many people. Not developed or endorsed by Mojang AB.
|
||||||
|
|
||||||
Version: 0.72.0 (in development)
|
Version: 0.73.0 (in development)
|
||||||
|
|
||||||
### Gameplay
|
### Gameplay
|
||||||
You start in a randomly-generated world made entirely of cubes. You can explore
|
You start in a randomly-generated world made entirely of cubes. You can explore
|
||||||
|
@ -66,7 +66,7 @@ Use the `/giveme` chat command to obtain them. See the in-game help for
|
||||||
an explanation.
|
an explanation.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
This game requires [Minetest](http://minetest.net) to run (version 5.3.0 or
|
This game requires [Minetest](http://minetest.net) to run (version 5.4.1 or
|
||||||
later). So you need to install Minetest first. Only stable versions of Minetest
|
later). So you need to install Minetest first. Only stable versions of Minetest
|
||||||
are officially supported.
|
are officially supported.
|
||||||
There is no support for running MineClone2 in development versions of Minetest.
|
There is no support for running MineClone2 in development versions of Minetest.
|
||||||
|
|
|
@ -1,29 +1,93 @@
|
||||||
|
-- Overrides the builtin minetest.check_single_for_falling.
|
||||||
|
-- We need to do this in order to handle nodes in mineclone specific groups
|
||||||
|
-- "supported_node" and "attached_node_facedir".
|
||||||
|
--
|
||||||
|
-- Nodes in group "supported_node" can be placed on any node that does not
|
||||||
|
-- have the "airlike" drawtype. Carpets are an example of this type.
|
||||||
|
|
||||||
local vector = vector
|
local vector = vector
|
||||||
|
|
||||||
local facedir_to_dir = minetest.facedir_to_dir
|
local facedir_to_dir = minetest.facedir_to_dir
|
||||||
local get_item_group = minetest.get_item_group
|
local get_item_group = minetest.get_item_group
|
||||||
local remove_node = minetest.remove_node
|
local remove_node = minetest.remove_node
|
||||||
local get_node = minetest.get_node
|
local get_node = minetest.get_node
|
||||||
|
local get_meta = minetest.get_meta
|
||||||
|
local registered_nodes = minetest.registered_nodes
|
||||||
|
local get_node_drops = minetest.get_node_drops
|
||||||
|
local add_item = minetest.add_item
|
||||||
|
|
||||||
|
-- drop_attached_node(p)
|
||||||
|
--
|
||||||
|
-- This function is copied verbatim from minetest/builtin/game/falling.lua
|
||||||
|
-- We need this to do the exact same dropping node handling in our override
|
||||||
|
-- minetest.check_single_for_falling() function as in the builtin function.
|
||||||
|
--
|
||||||
|
local function drop_attached_node(p)
|
||||||
|
local n = get_node(p)
|
||||||
|
local drops = get_node_drops(n, "")
|
||||||
|
local def = registered_nodes[n.name]
|
||||||
|
if def and def.preserve_metadata then
|
||||||
|
local oldmeta = get_meta(p):to_table().fields
|
||||||
|
-- Copy pos and node because the callback can modify them.
|
||||||
|
local pos_copy = vector.new(p)
|
||||||
|
local node_copy = {name=n.name, param1=n.param1, param2=n.param2}
|
||||||
|
local drop_stacks = {}
|
||||||
|
for k, v in pairs(drops) do
|
||||||
|
drop_stacks[k] = ItemStack(v)
|
||||||
|
end
|
||||||
|
drops = drop_stacks
|
||||||
|
def.preserve_metadata(pos_copy, node_copy, oldmeta, drops)
|
||||||
|
end
|
||||||
|
if def and def.sounds and def.sounds.fall then
|
||||||
|
core.sound_play(def.sounds.fall, {pos = p}, true)
|
||||||
|
end
|
||||||
|
remove_node(p)
|
||||||
|
for _, item in pairs(drops) do
|
||||||
|
local pos = {
|
||||||
|
x = p.x + math.random()/2 - 0.25,
|
||||||
|
y = p.y + math.random()/2 - 0.25,
|
||||||
|
z = p.z + math.random()/2 - 0.25,
|
||||||
|
}
|
||||||
|
add_item(pos, item)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- minetest.check_single_for_falling(pos)
|
||||||
|
--
|
||||||
|
-- * causes an unsupported `group:falling_node` node to fall and causes an
|
||||||
|
-- unattached `group:attached_node` or `group:attached_node_facedir` node
|
||||||
|
-- or unsupported `group:supported_node` node to drop.
|
||||||
|
-- * does not spread these updates to neighbours.
|
||||||
|
--
|
||||||
|
-- Returns true if the node at <pos> has spawned a falling node or has been
|
||||||
|
-- dropped as item(s).
|
||||||
|
--
|
||||||
local original_function = minetest.check_single_for_falling
|
local original_function = minetest.check_single_for_falling
|
||||||
|
|
||||||
function minetest.check_single_for_falling(pos)
|
function minetest.check_single_for_falling(pos)
|
||||||
local ret_o = original_function(pos)
|
if original_function(pos) then
|
||||||
local ret = false
|
return true
|
||||||
local node = minetest.get_node(pos)
|
end
|
||||||
|
|
||||||
|
local node = get_node(pos)
|
||||||
if get_item_group(node.name, "attached_node_facedir") ~= 0 then
|
if get_item_group(node.name, "attached_node_facedir") ~= 0 then
|
||||||
local dir = facedir_to_dir(node.param2)
|
local dir = facedir_to_dir(node.param2)
|
||||||
if dir then
|
if dir then
|
||||||
if get_item_group(get_node(vector.add(pos, dir)).name, "solid") == 0 then
|
if get_item_group(get_node(vector.add(pos, dir)).name, "solid") == 0 then
|
||||||
remove_node(pos)
|
drop_attached_node(pos)
|
||||||
local drops = minetest.get_node_drops(node.name, "")
|
return true
|
||||||
for dr=1, #drops do
|
|
||||||
minetest.add_item(pos, drops[dr])
|
|
||||||
end
|
|
||||||
ret = true
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return ret_o or ret
|
|
||||||
|
if get_item_group(node.name, "supported_node") ~= 0 then
|
||||||
|
local def = registered_nodes[get_node(vector.offset(pos, 0, -1, 0)).name]
|
||||||
|
if def and def.drawtype == "airlike" then
|
||||||
|
drop_attached_node(pos)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -84,7 +84,7 @@ function image:encode()
|
||||||
end
|
end
|
||||||
|
|
||||||
function image:save(filename)
|
function image:save(filename)
|
||||||
local f = assert(io.open(filename, "w"))
|
local f = assert(io.open(filename, "wb"))
|
||||||
f:write(self.data)
|
f:write(self.data)
|
||||||
f:close()
|
f:close()
|
||||||
end
|
end
|
||||||
|
|
|
@ -26,20 +26,64 @@ function mcl_burning.get_collisionbox(obj, smaller, storage)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local find_nodes_in_area = minetest.find_nodes_in_area
|
||||||
|
|
||||||
function mcl_burning.get_touching_nodes(obj, nodenames, storage)
|
function mcl_burning.get_touching_nodes(obj, nodenames, storage)
|
||||||
local pos = obj:get_pos()
|
local pos = obj:get_pos()
|
||||||
local minp, maxp = mcl_burning.get_collisionbox(obj, true, storage)
|
local minp, maxp = mcl_burning.get_collisionbox(obj, true, storage)
|
||||||
local nodes = minetest.find_nodes_in_area(vector.add(pos, minp), vector.add(pos, maxp), nodenames)
|
local nodes = find_nodes_in_area(vector.add(pos, minp), vector.add(pos, maxp), nodenames)
|
||||||
return nodes
|
return nodes
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Manages the fire animation on a burning player's HUD
|
||||||
|
--
|
||||||
|
-- Parameters:
|
||||||
|
-- player - a valid player object;
|
||||||
|
--
|
||||||
|
-- If the player already has a fire HUD, updates the burning animation.
|
||||||
|
-- If the fire does not have a fire HUD, initializes the HUD.
|
||||||
|
--
|
||||||
|
function mcl_burning.update_hud(player)
|
||||||
|
local animation_frames = tonumber(minetest.settings:get("fire_animation_frames")) or 8
|
||||||
|
local hud_flame_animated = "mcl_burning_hud_flame_animated.png^[opacity:180^[verticalframe:" .. animation_frames .. ":"
|
||||||
|
|
||||||
|
local storage = mcl_burning.get_storage(player)
|
||||||
|
if not storage.fire_hud_id then
|
||||||
|
storage.animation_frame = 1
|
||||||
|
storage.fire_hud_id = player:hud_add({
|
||||||
|
hud_elem_type = "image",
|
||||||
|
position = {x = 0.5, y = 0.5},
|
||||||
|
scale = {x = -100, y = -100},
|
||||||
|
text = hud_flame_animated .. storage.animation_frame,
|
||||||
|
z_index = 1000,
|
||||||
|
})
|
||||||
|
else
|
||||||
|
storage.animation_frame = storage.animation_frame + 1
|
||||||
|
if storage.animation_frame > animation_frames - 1 then
|
||||||
|
storage.animation_frame = 0
|
||||||
|
end
|
||||||
|
player:hud_change(storage.fire_hud_id, "text", hud_flame_animated .. storage.animation_frame)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Sets and object state as burning and adds a fire animation to the object.
|
||||||
|
--
|
||||||
|
-- Parameters:
|
||||||
|
-- obj - may be a player or a lua_entity;
|
||||||
|
-- burn_time - sets the object's burn duration;
|
||||||
|
--
|
||||||
|
-- If obj is a player, adds a fire animation to the HUD, if obj is a
|
||||||
|
-- lua_entity, adds an animated fire entity to obj.
|
||||||
|
-- The effective burn duration is modified by obj's armor protection.
|
||||||
|
-- If obj was already burning, its burn duration is updated if the current
|
||||||
|
-- duration is less than burn_time.
|
||||||
|
-- If obj is dead, fireproof or a creative player, this function does nothing.
|
||||||
|
--
|
||||||
function mcl_burning.set_on_fire(obj, burn_time)
|
function mcl_burning.set_on_fire(obj, burn_time)
|
||||||
if obj:get_hp() < 0 then
|
if obj:get_hp() < 0 then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local storage = mcl_burning.get_storage(obj)
|
|
||||||
|
|
||||||
local luaentity = obj:get_luaentity()
|
local luaentity = obj:get_luaentity()
|
||||||
if luaentity and luaentity.fire_resistant then
|
if luaentity and luaentity.fire_resistant then
|
||||||
return
|
return
|
||||||
|
@ -60,44 +104,32 @@ function mcl_burning.set_on_fire(obj, burn_time)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if max_fire_prot_lvl > 0 then
|
if max_fire_prot_lvl > 0 then
|
||||||
burn_time = burn_time - math.floor(burn_time * max_fire_prot_lvl * 0.15)
|
burn_time = burn_time - math.floor(burn_time * max_fire_prot_lvl * 0.15)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if not storage.burn_time or burn_time >= storage.burn_time then
|
local storage = mcl_burning.get_storage(obj)
|
||||||
if obj:is_player() then
|
if storage.burn_time then
|
||||||
mcl_burning.channels[obj]:send_all(tostring(mcl_burning.animation_frames))
|
if burn_time > storage.burn_time then
|
||||||
mcl_burning.channels[obj]:send_all("start")
|
storage.burn_time = burn_time
|
||||||
|
end
|
||||||
|
return
|
||||||
end
|
end
|
||||||
storage.burn_time = burn_time
|
storage.burn_time = burn_time
|
||||||
storage.fire_damage_timer = 0
|
storage.fire_damage_timer = 0
|
||||||
|
|
||||||
local fire_entity = minetest.add_entity(obj:get_pos(), "mcl_burning:fire")
|
|
||||||
local minp, maxp = mcl_burning.get_collisionbox(obj, false, storage)
|
local minp, maxp = mcl_burning.get_collisionbox(obj, false, storage)
|
||||||
local obj_size = obj:get_properties().visual_size
|
|
||||||
|
|
||||||
local vertical_grow_factor = 1.2
|
|
||||||
local horizontal_grow_factor = 1.1
|
|
||||||
local grow_vector = vector.new(horizontal_grow_factor, vertical_grow_factor, horizontal_grow_factor)
|
|
||||||
|
|
||||||
local size = vector.subtract(maxp, minp)
|
local size = vector.subtract(maxp, minp)
|
||||||
size = vector.multiply(size, grow_vector)
|
size = vector.multiply(size, vector.new(1.1, 1.2, 1.1))
|
||||||
size = vector.divide(size, obj_size)
|
size = vector.divide(size, obj:get_properties().visual_size)
|
||||||
local offset = vector.new(0, size.y * 10 / 2, 0)
|
|
||||||
|
|
||||||
|
local fire_entity = minetest.add_entity(obj:get_pos(), "mcl_burning:fire")
|
||||||
fire_entity:set_properties({visual_size = size})
|
fire_entity:set_properties({visual_size = size})
|
||||||
fire_entity:set_attach(obj, "", offset, {x = 0, y = 0, z = 0})
|
fire_entity:set_attach(obj, "", vector.new(0, size.y * 5, 0), vector.new(0, 0, 0))
|
||||||
local fire_luaentity = fire_entity:get_luaentity()
|
|
||||||
|
|
||||||
for _, other in pairs(minetest.get_objects_inside_radius(fire_entity:get_pos(), 0)) do
|
if obj:is_player() then
|
||||||
local other_luaentity = other:get_luaentity()
|
mcl_burning.update_hud(obj)
|
||||||
if other_luaentity and other_luaentity.name == "mcl_burning:fire" and other_luaentity ~= fire_luaentity then
|
|
||||||
other:remove()
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -105,7 +137,9 @@ function mcl_burning.extinguish(obj)
|
||||||
if mcl_burning.is_burning(obj) then
|
if mcl_burning.is_burning(obj) then
|
||||||
local storage = mcl_burning.get_storage(obj)
|
local storage = mcl_burning.get_storage(obj)
|
||||||
if obj:is_player() then
|
if obj:is_player() then
|
||||||
mcl_burning.channels[obj]:send_all("stop")
|
if storage.fire_hud_id then
|
||||||
|
obj:hud_remove(storage.fire_hud_id)
|
||||||
|
end
|
||||||
mcl_burning.storage[obj] = {}
|
mcl_burning.storage[obj] = {}
|
||||||
else
|
else
|
||||||
storage.burn_time = nil
|
storage.burn_time = nil
|
||||||
|
|
|
@ -1,18 +1,27 @@
|
||||||
local modpath = minetest.get_modpath(minetest.get_current_modname())
|
local modpath = minetest.get_modpath(minetest.get_current_modname())
|
||||||
|
|
||||||
local pairs = pairs
|
|
||||||
|
|
||||||
local get_connected_players = minetest.get_connected_players
|
|
||||||
local get_item_group = minetest.get_item_group
|
|
||||||
|
|
||||||
mcl_burning = {
|
mcl_burning = {
|
||||||
storage = {},
|
-- the storage table holds a list of objects (players,luaentities) and tables
|
||||||
channels = {},
|
-- associated with these objects. These tables have the following attributes:
|
||||||
animation_frames = tonumber(minetest.settings:get("fire_animation_frames")) or 8
|
-- burn_time:
|
||||||
|
-- Remaining time that object will burn.
|
||||||
|
-- fire_damage_timer:
|
||||||
|
-- Timer for dealing damage every second while burning.
|
||||||
|
-- fire_hud_id:
|
||||||
|
-- HUD id of the flames animation on a burning player's HUD.
|
||||||
|
-- animation_frame:
|
||||||
|
-- The HUD's current animation frame, used by update_hud().
|
||||||
|
-- collisionbox_cache:
|
||||||
|
-- Used by mcl_burning.get_collisionbox() to avoid recalculations.
|
||||||
|
storage = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
dofile(modpath .. "/api.lua")
|
dofile(modpath .. "/api.lua")
|
||||||
|
|
||||||
|
local pairs = pairs
|
||||||
|
local get_connected_players = minetest.get_connected_players
|
||||||
|
local get_item_group = minetest.get_item_group
|
||||||
|
|
||||||
minetest.register_globalstep(function(dtime)
|
minetest.register_globalstep(function(dtime)
|
||||||
for _, player in pairs(get_connected_players()) do
|
for _, player in pairs(get_connected_players()) do
|
||||||
local storage = mcl_burning.storage[player]
|
local storage = mcl_burning.storage[player]
|
||||||
|
@ -44,25 +53,36 @@ minetest.register_on_respawnplayer(function(player)
|
||||||
mcl_burning.extinguish(player)
|
mcl_burning.extinguish(player)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
function mcl_burning.init_player(player)
|
minetest.register_on_joinplayer(function(player)
|
||||||
local meta = player:get_meta()
|
local storage = {}
|
||||||
-- NOTE: mcl_burning:data may be "return nil" (which deserialize into nil) for reasons unknown.
|
local burn_data = player:get_meta():get_string("mcl_burning:data")
|
||||||
if meta:get_string("mcl_burning:data"):find("return nil", 1, true) then
|
if burn_data ~= "" then
|
||||||
minetest.log("warning", "[mcl_burning] 'mcl_burning:data' player meta field is invalid! Please report this bug")
|
storage = minetest.deserialize(burn_data) or storage
|
||||||
end
|
end
|
||||||
mcl_burning.storage[player] = meta:contains("mcl_burning:data") and minetest.deserialize(meta:get_string("mcl_burning:data")) or {}
|
mcl_burning.storage[player] = storage
|
||||||
mcl_burning.channels[player] = minetest.mod_channel_join("mcl_burning:" .. player:get_player_name())
|
if storage.burn_time and storage.burn_time > 0 then
|
||||||
|
mcl_burning.update_hud(player)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
local function on_leaveplayer(player)
|
||||||
|
local storage = mcl_burning.storage[player]
|
||||||
|
storage.fire_hud_id = nil
|
||||||
|
player:get_meta():set_string("mcl_burning:data", minetest.serialize(storage))
|
||||||
|
mcl_burning.storage[player] = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
minetest.register_on_joinplayer(function(player)
|
|
||||||
mcl_burning.init_player(player)
|
|
||||||
end)
|
|
||||||
|
|
||||||
minetest.register_on_leaveplayer(function(player)
|
minetest.register_on_leaveplayer(function(player)
|
||||||
player:get_meta():set_string("mcl_burning:data", minetest.serialize(mcl_burning.storage[player]))
|
on_leaveplayer(player)
|
||||||
mcl_burning.storage[player] = nil
|
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
minetest.register_on_shutdown(function()
|
||||||
|
for _,player in ipairs(minetest.get_connected_players()) do
|
||||||
|
on_leaveplayer(player)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
local animation_frames = tonumber(minetest.settings:get("fire_animation_frames")) or 8
|
||||||
|
|
||||||
minetest.register_entity("mcl_burning:fire", {
|
minetest.register_entity("mcl_burning:fire", {
|
||||||
initial_properties = {
|
initial_properties = {
|
||||||
|
@ -70,42 +90,35 @@ minetest.register_entity("mcl_burning:fire", {
|
||||||
collisionbox = {0, 0, 0, 0, 0, 0},
|
collisionbox = {0, 0, 0, 0, 0, 0},
|
||||||
visual = "upright_sprite",
|
visual = "upright_sprite",
|
||||||
textures = {
|
textures = {
|
||||||
name = "mcl_burning_entity_flame_animated.png",
|
"mcl_burning_entity_flame_animated.png",
|
||||||
animation = {
|
"mcl_burning_entity_flame_animated.png"
|
||||||
type = "vertical_frames",
|
|
||||||
aspect_w = 16,
|
|
||||||
aspect_h = 16,
|
|
||||||
length = 1.0,
|
|
||||||
},
|
},
|
||||||
},
|
spritediv = {x = 1, y = animation_frames},
|
||||||
spritediv = {x = 1, y = mcl_burning.animation_frames},
|
|
||||||
pointable = false,
|
pointable = false,
|
||||||
glow = -1,
|
glow = -1,
|
||||||
backface_culling = false,
|
backface_culling = false,
|
||||||
},
|
},
|
||||||
animation_frame = 0,
|
_mcl_animation_timer = 0,
|
||||||
animation_timer = 0,
|
|
||||||
on_activate = function(self)
|
on_activate = function(self)
|
||||||
self.object:set_sprite({x = 0, y = 0}, mcl_burning.animation_frames, 1.0 / mcl_burning.animation_frames)
|
self.object:set_sprite({x = 0, y = 0}, animation_frames, 1.0 / animation_frames)
|
||||||
end,
|
end,
|
||||||
on_step = function(self)
|
on_step = function(self, dtime)
|
||||||
if not self:sanity_check() then
|
|
||||||
self.object:remove()
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
sanity_check = function(self)
|
|
||||||
local parent = self.object:get_attach()
|
local parent = self.object:get_attach()
|
||||||
|
|
||||||
if not parent then
|
if not parent then
|
||||||
return false
|
self.object:remove()
|
||||||
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local storage = mcl_burning.get_storage(parent)
|
local storage = mcl_burning.get_storage(parent)
|
||||||
|
|
||||||
if not storage or not storage.burn_time then
|
if not storage or not storage.burn_time then
|
||||||
return false
|
self.object:remove()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if parent:is_player() then
|
||||||
|
self._mcl_animation_timer = self._mcl_animation_timer + dtime
|
||||||
|
if self._mcl_animation_timer >= 0.1 then
|
||||||
|
self._mcl_animation_timer = 0
|
||||||
|
mcl_burning.update_hud(parent)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return true
|
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
|
@ -110,7 +110,7 @@ minetest.register_globalstep(function(dtime)
|
||||||
if tick == true and pool[name] > 0 then
|
if tick == true and pool[name] > 0 then
|
||||||
minetest.sound_play("item_drop_pickup", {
|
minetest.sound_play("item_drop_pickup", {
|
||||||
pos = pos,
|
pos = pos,
|
||||||
gain = 0.7,
|
gain = 0.3,
|
||||||
max_hear_distance = 16,
|
max_hear_distance = 16,
|
||||||
pitch = math.random(70,110)/100
|
pitch = math.random(70,110)/100
|
||||||
})
|
})
|
||||||
|
@ -256,6 +256,8 @@ function minetest.handle_node_drops(pos, drops, digger)
|
||||||
|
|
||||||
local silk_touch_drop = false
|
local silk_touch_drop = false
|
||||||
local nodedef = minetest.registered_nodes[dug_node.name]
|
local nodedef = minetest.registered_nodes[dug_node.name]
|
||||||
|
if not nodedef then return end
|
||||||
|
|
||||||
if shearsy_level and shearsy_level > 0 and nodedef._mcl_shears_drop then
|
if shearsy_level and shearsy_level > 0 and nodedef._mcl_shears_drop then
|
||||||
if nodedef._mcl_shears_drop == true then
|
if nodedef._mcl_shears_drop == true then
|
||||||
drops = { dug_node.name }
|
drops = { dug_node.name }
|
||||||
|
|
|
@ -432,7 +432,8 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o
|
||||||
-- Slow down or speed up
|
-- Slow down or speed up
|
||||||
local acc = dir.y * -1.8
|
local acc = dir.y * -1.8
|
||||||
local friction = 0.4
|
local friction = 0.4
|
||||||
local speed_mod = minetest.registered_nodes[minetest.get_node(pos).name]._rail_acceleration
|
local ndef = minetest.registered_nodes[minetest.get_node(pos).name]
|
||||||
|
local speed_mod = ndef and ndef._rail_acceleration
|
||||||
|
|
||||||
acc = acc - friction
|
acc = acc - friction
|
||||||
|
|
||||||
|
|
|
@ -222,8 +222,8 @@ local collision = function(self)
|
||||||
|
|
||||||
for _,object in pairs(minetest.get_objects_inside_radius(pos, width)) do
|
for _,object in pairs(minetest.get_objects_inside_radius(pos, width)) do
|
||||||
|
|
||||||
if object:is_player()
|
local ent = object:get_luaentity()
|
||||||
or (object:get_luaentity()._cmi_is_mob == true and object ~= self.object) then
|
if object:is_player() or (ent and ent._cmi_is_mob and object ~= self.object) then
|
||||||
|
|
||||||
local pos2 = object:get_pos()
|
local pos2 = object:get_pos()
|
||||||
local vec = {x = pos.x - pos2.x, z = pos.z - pos2.z}
|
local vec = {x = pos.x - pos2.x, z = pos.z - pos2.z}
|
||||||
|
@ -1328,8 +1328,8 @@ local do_jump = function(self)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.walk_chance == 0
|
local ndef = minetest.registered_nodes[nod.name]
|
||||||
or minetest.registered_items[nod.name].walkable then
|
if self.walk_chance == 0 or ndef and ndef.walkable then
|
||||||
|
|
||||||
if minetest.get_item_group(nod.name, "fence") == 0
|
if minetest.get_item_group(nod.name, "fence") == 0
|
||||||
and minetest.get_item_group(nod.name, "fence_gate") == 0
|
and minetest.get_item_group(nod.name, "fence_gate") == 0
|
||||||
|
|
|
@ -570,12 +570,22 @@ if mobs_spawn then
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
|
|
||||||
local gotten_node = get_node(spawning_position).name
|
local gotten_node = get_node(spawning_position)
|
||||||
|
local gotten_node_name = gotten_node.name
|
||||||
|
local gotten_node_def = minetest.registered_nodes[gotten_node_name]
|
||||||
|
|
||||||
if not gotten_node or gotten_node == "air" then --skip air nodes
|
if not gotten_node_name or not gotten_node_def or gotten_node_name == "air" then --skip air nodes
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if gotten_node_def.use_texture_alpha and gotten_node_def.use_texture_alpha ~= "opaque" then
|
||||||
|
break
|
||||||
|
end --don't spawn on nonopaque nodes
|
||||||
|
|
||||||
|
local leaf = minetest.get_item_group(gotten_node_name,"leaves")
|
||||||
|
if leaf ~= 0 then
|
||||||
|
break end --don't spawn on treetops
|
||||||
|
|
||||||
local gotten_biome = minetest.get_biome_data(spawning_position)
|
local gotten_biome = minetest.get_biome_data(spawning_position)
|
||||||
|
|
||||||
if not gotten_biome then
|
if not gotten_biome then
|
||||||
|
@ -616,8 +626,8 @@ if mobs_spawn then
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
|
|
||||||
local is_water = get_item_group(gotten_node, "water") ~= 0
|
local is_water = get_item_group(gotten_node_name, "water") ~= 0
|
||||||
local is_lava = get_item_group(gotten_node, "lava") ~= 0
|
local is_lava = get_item_group(gotten_node_name, "lava") ~= 0
|
||||||
|
|
||||||
if mob_def.type_of_spawning == "ground" and is_water then
|
if mob_def.type_of_spawning == "ground" and is_water then
|
||||||
break
|
break
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
-- NOTE: Most strings intentionally not marked for translation, other mods already have these items.
|
-- NOTE: Most strings intentionally not marked for translation, other mods already have these items.
|
||||||
-- TODO: Remove this file eventually, most items are already outsourced in other mods.
|
-- TODO: Remove this file eventually, most items are already outsourced in other mods.
|
||||||
|
|
||||||
local S = minetest.get_translator("mobs_mc")
|
local S = minetest.get_translator(minetest.get_current_modname())
|
||||||
|
|
||||||
local c = mobs_mc.is_item_variable_overridden
|
local c = mobs_mc.is_item_variable_overridden
|
||||||
|
|
||||||
|
@ -234,8 +234,8 @@ end
|
||||||
if c("ender_eye") and c("blaze_powder") and c("blaze_rod") then
|
if c("ender_eye") and c("blaze_powder") and c("blaze_rod") then
|
||||||
minetest.register_craft({
|
minetest.register_craft({
|
||||||
type = "shapeless",
|
type = "shapeless",
|
||||||
output = 'mobs_mc:ender_eye',
|
output = "mobs_mc:ender_eye",
|
||||||
recipe = { 'mobs_mc:blaze_powder', 'mobs_mc:blaze_rod'},
|
recipe = { "mobs_mc:blaze_powder", "mobs_mc:blaze_rod"},
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -525,7 +525,7 @@ if c("totem") then
|
||||||
inventory_image = "mcl_totems_totem.png",
|
inventory_image = "mcl_totems_totem.png",
|
||||||
wield_image = "mcl_totems_totem.png",
|
wield_image = "mcl_totems_totem.png",
|
||||||
stack_max = 1,
|
stack_max = 1,
|
||||||
groups = {combat_item=1},
|
groups = {combat_item = 1, offhand_item = 1},
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -50,8 +50,10 @@ mobs_mc.make_owner_teleport_function = function(dist, teleport_check_interval)
|
||||||
local telepos_below = {x=telepos.x, y=telepos.y-1, z=telepos.z}
|
local telepos_below = {x=telepos.x, y=telepos.y-1, z=telepos.z}
|
||||||
table.remove(check_offsets, r)
|
table.remove(check_offsets, r)
|
||||||
-- Long story short, spawn on a platform
|
-- Long story short, spawn on a platform
|
||||||
if minetest.registered_nodes[minetest.get_node(telepos).name].walkable == false and
|
local trynode = minetest.registered_nodes[minetest.get_node(telepos).name]
|
||||||
minetest.registered_nodes[minetest.get_node(telepos_below).name].walkable == true then
|
local trybelownode = minetest.registered_nodes[minetest.get_node(telepos_below).name]
|
||||||
|
if trynode and not trynode.walkable and
|
||||||
|
trybelownode and trybelownode.walkable then
|
||||||
-- Correct position found! Let's teleport.
|
-- Correct position found! Let's teleport.
|
||||||
self.object:set_pos(telepos)
|
self.object:set_pos(telepos)
|
||||||
return
|
return
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
|
|
||||||
local S = minetest.get_translator("mobs_mc")
|
local S = minetest.get_translator("mobs_mc")
|
||||||
|
|
||||||
|
local mod_target = minetest.get_modpath("mcl_target")
|
||||||
|
|
||||||
--###################
|
--###################
|
||||||
--################### BLAZE
|
--################### BLAZE
|
||||||
--###################
|
--###################
|
||||||
|
@ -178,17 +180,20 @@ mobs:register_arrow("mobs_mc:blaze_fireball", {
|
||||||
|
|
||||||
-- Node hit, make fire
|
-- Node hit, make fire
|
||||||
hit_node = function(self, pos, node)
|
hit_node = function(self, pos, node)
|
||||||
if node.name == "air" then
|
if node == "air" then
|
||||||
minetest.set_node(pos_above, {name=mobs_mc.items.fire})
|
minetest.set_node(pos, {name = mobs_mc.items.fire})
|
||||||
else
|
else
|
||||||
local v = self.object:get_velocity()
|
if self._shot_from_dispenser and mod_target and node == "mcl_target:target_off" then
|
||||||
v = vector.normalize(v)
|
mcl_target.hit(vector.round(pos), 0.4) --4 redstone ticks
|
||||||
|
end
|
||||||
|
local v = vector.normalize(self.object:get_velocity())
|
||||||
local crashpos = vector.subtract(pos, v)
|
local crashpos = vector.subtract(pos, v)
|
||||||
local crashnode = minetest.get_node(crashpos)
|
local crashnode = minetest.get_node(crashpos)
|
||||||
|
local cndef = minetest.registered_nodes[crashnode.name]
|
||||||
-- Set fire if node is air, or a replacable flammable node (e.g. a plant)
|
-- Set fire if node is air, or a replacable flammable node (e.g. a plant)
|
||||||
if crashnode.name == "air" or
|
if crashnode.name == "air" or
|
||||||
(minetest.registered_nodes[crashnode.name].buildable_to and minetest.get_item_group(crashnode.name, "flammable") >= 1) then
|
(cndef and cndef.buildable_to and minetest.get_item_group(crashnode.name, "flammable") >= 1) then
|
||||||
minetest.set_node(crashpos, {name=mobs_mc.items.fire})
|
minetest.set_node(crashpos, {name = mobs_mc.items.fire})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -106,22 +106,42 @@ mobs:spawn_specific(
|
||||||
"overworld",
|
"overworld",
|
||||||
"ground",
|
"ground",
|
||||||
{
|
{
|
||||||
"FlowerForest",
|
"flat",
|
||||||
"Swampland",
|
"IcePlainsSpikes",
|
||||||
"Taiga",
|
"ColdTaiga",
|
||||||
"ExtremeHills",
|
"ColdTaiga_beach",
|
||||||
"BirchForest",
|
"ColdTaiga_beach_water",
|
||||||
"MegaSpruceTaiga",
|
"MegaTaiga",
|
||||||
"MegaTaiga",
|
"MegaSpruceTaiga",
|
||||||
"ExtremeHills+",
|
"ExtremeHills",
|
||||||
"Forest",
|
"ExtremeHills_beach",
|
||||||
"Plains",
|
"ExtremeHillsM",
|
||||||
"ColdTaiga",
|
"ExtremeHills+",
|
||||||
"SunflowerPlains",
|
"ExtremeHills+_snowtop",
|
||||||
"RoofedForest",
|
"StoneBeach",
|
||||||
"MesaPlateauFM_grasstop",
|
"Plains",
|
||||||
"ExtremeHillsM",
|
"Plains_beach",
|
||||||
"BirchForestM",
|
"SunflowerPlains",
|
||||||
|
"Taiga",
|
||||||
|
"Taiga_beach",
|
||||||
|
"Forest",
|
||||||
|
"Forest_beach",
|
||||||
|
"FlowerForest",
|
||||||
|
"FlowerForest_beach",
|
||||||
|
"BirchForest",
|
||||||
|
"BirchForestM",
|
||||||
|
"RoofedForest",
|
||||||
|
"Savanna",
|
||||||
|
"Savanna_beach",
|
||||||
|
"SavannaM",
|
||||||
|
"Jungle",
|
||||||
|
"Jungle_shore",
|
||||||
|
"JungleM",
|
||||||
|
"JungleM_shore",
|
||||||
|
"JungleEdge",
|
||||||
|
"JungleEdgeM",
|
||||||
|
"Swampland",
|
||||||
|
"Swampland_shore"
|
||||||
},
|
},
|
||||||
9,
|
9,
|
||||||
minetest.LIGHT_MAX+1,
|
minetest.LIGHT_MAX+1,
|
||||||
|
|
|
@ -151,22 +151,42 @@ mobs:spawn_specific(
|
||||||
"overworld",
|
"overworld",
|
||||||
"ground",
|
"ground",
|
||||||
{
|
{
|
||||||
"FlowerForest",
|
"flat",
|
||||||
"Swampland",
|
"IcePlainsSpikes",
|
||||||
"Taiga",
|
"ColdTaiga",
|
||||||
"ExtremeHills",
|
"ColdTaiga_beach",
|
||||||
"BirchForest",
|
"ColdTaiga_beach_water",
|
||||||
"MegaSpruceTaiga",
|
"MegaTaiga",
|
||||||
"MegaTaiga",
|
"MegaSpruceTaiga",
|
||||||
"ExtremeHills+",
|
"ExtremeHills",
|
||||||
"Forest",
|
"ExtremeHills_beach",
|
||||||
"Plains",
|
"ExtremeHillsM",
|
||||||
"ColdTaiga",
|
"ExtremeHills+",
|
||||||
"SunflowerPlains",
|
"ExtremeHills+_snowtop",
|
||||||
"RoofedForest",
|
"StoneBeach",
|
||||||
"MesaPlateauFM_grasstop",
|
"Plains",
|
||||||
"ExtremeHillsM",
|
"Plains_beach",
|
||||||
"BirchForestM",
|
"SunflowerPlains",
|
||||||
|
"Taiga",
|
||||||
|
"Taiga_beach",
|
||||||
|
"Forest",
|
||||||
|
"Forest_beach",
|
||||||
|
"FlowerForest",
|
||||||
|
"FlowerForest_beach",
|
||||||
|
"BirchForest",
|
||||||
|
"BirchForestM",
|
||||||
|
"RoofedForest",
|
||||||
|
"Savanna",
|
||||||
|
"Savanna_beach",
|
||||||
|
"SavannaM",
|
||||||
|
"Jungle",
|
||||||
|
"Jungle_shore",
|
||||||
|
"JungleM",
|
||||||
|
"JungleM_shore",
|
||||||
|
"JungleEdge",
|
||||||
|
"JungleEdgeM",
|
||||||
|
"Swampland",
|
||||||
|
"Swampland_shore"
|
||||||
},
|
},
|
||||||
9,
|
9,
|
||||||
minetest.LIGHT_MAX+1,
|
minetest.LIGHT_MAX+1,
|
||||||
|
|
|
@ -478,7 +478,8 @@ mobs:register_mob("mobs_mc:enderman", {
|
||||||
-- Selected node needs to have 3 nodes of free space above
|
-- Selected node needs to have 3 nodes of free space above
|
||||||
for u=1, 3 do
|
for u=1, 3 do
|
||||||
local node = minetest.get_node({x=nodepos.x, y=nodepos.y+u, z=nodepos.z})
|
local node = minetest.get_node({x=nodepos.x, y=nodepos.y+u, z=nodepos.z})
|
||||||
if minetest.registered_nodes[node.name].walkable then
|
local ndef = minetest.registered_nodes[node.name]
|
||||||
|
if ndef and ndef.walkable then
|
||||||
node_ok = false
|
node_ok = false
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
|
@ -512,7 +513,8 @@ mobs:register_mob("mobs_mc:enderman", {
|
||||||
node_ok = true
|
node_ok = true
|
||||||
for u=1, 3 do
|
for u=1, 3 do
|
||||||
local node = minetest.get_node({x=nodepos.x, y=nodepos.y+u, z=nodepos.z})
|
local node = minetest.get_node({x=nodepos.x, y=nodepos.y+u, z=nodepos.z})
|
||||||
if minetest.registered_nodes[node.name].walkable then
|
local ndef = minetest.registered_nodes[node.name]
|
||||||
|
if ndef and ndef.walkable then
|
||||||
node_ok = false
|
node_ok = false
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
|
|
|
@ -520,22 +520,42 @@ mobs:spawn_specific(
|
||||||
"overworld",
|
"overworld",
|
||||||
"ground",
|
"ground",
|
||||||
{
|
{
|
||||||
"FlowerForest",
|
"flat",
|
||||||
"Swampland",
|
"IcePlainsSpikes",
|
||||||
"Taiga",
|
"ColdTaiga",
|
||||||
"ExtremeHills",
|
"ColdTaiga_beach",
|
||||||
"BirchForest",
|
"ColdTaiga_beach_water",
|
||||||
"MegaSpruceTaiga",
|
"MegaTaiga",
|
||||||
"MegaTaiga",
|
"MegaSpruceTaiga",
|
||||||
"ExtremeHills+",
|
"ExtremeHills",
|
||||||
"Forest",
|
"ExtremeHills_beach",
|
||||||
"Plains",
|
"ExtremeHillsM",
|
||||||
"ColdTaiga",
|
"ExtremeHills+",
|
||||||
"SunflowerPlains",
|
"ExtremeHills+_snowtop",
|
||||||
"RoofedForest",
|
"StoneBeach",
|
||||||
"MesaPlateauFM_grasstop",
|
"Plains",
|
||||||
"ExtremeHillsM",
|
"Plains_beach",
|
||||||
"BirchForestM",
|
"SunflowerPlains",
|
||||||
|
"Taiga",
|
||||||
|
"Taiga_beach",
|
||||||
|
"Forest",
|
||||||
|
"Forest_beach",
|
||||||
|
"FlowerForest",
|
||||||
|
"FlowerForest_beach",
|
||||||
|
"BirchForest",
|
||||||
|
"BirchForestM",
|
||||||
|
"RoofedForest",
|
||||||
|
"Savanna",
|
||||||
|
"Savanna_beach",
|
||||||
|
"SavannaM",
|
||||||
|
"Jungle",
|
||||||
|
"Jungle_shore",
|
||||||
|
"JungleM",
|
||||||
|
"JungleM_shore",
|
||||||
|
"JungleEdge",
|
||||||
|
"JungleEdgeM",
|
||||||
|
"Swampland",
|
||||||
|
"Swampland_shore"
|
||||||
},
|
},
|
||||||
0,
|
0,
|
||||||
minetest.LIGHT_MAX+1,
|
minetest.LIGHT_MAX+1,
|
||||||
|
|
|
@ -223,12 +223,18 @@ mobs:spawn_specific(
|
||||||
"overworld",
|
"overworld",
|
||||||
"ground",
|
"ground",
|
||||||
{
|
{
|
||||||
"Mesa",
|
"Mesa",
|
||||||
"MesaPlateauFM_grasstop",
|
"MesaPlateauFM_grasstop",
|
||||||
"MesaPlateauF",
|
"MesaPlateauF",
|
||||||
"MesaPlateauFM",
|
"MesaPlateauFM",
|
||||||
"MesaPlateauF_grasstop",
|
"MesaPlateauF_grasstop",
|
||||||
"MesaBryce",
|
"MesaBryce",
|
||||||
|
"Jungle",
|
||||||
|
"Jungle_shore",
|
||||||
|
"JungleM",
|
||||||
|
"JungleM_shore",
|
||||||
|
"JungleEdge",
|
||||||
|
"JungleEdgeM",
|
||||||
},
|
},
|
||||||
0,
|
0,
|
||||||
minetest.LIGHT_MAX+1,
|
minetest.LIGHT_MAX+1,
|
||||||
|
|
|
@ -188,22 +188,42 @@ mobs:spawn_specific(
|
||||||
"overworld",
|
"overworld",
|
||||||
"ground",
|
"ground",
|
||||||
{
|
{
|
||||||
"FlowerForest",
|
"flat",
|
||||||
"Swampland",
|
"IcePlainsSpikes",
|
||||||
"Taiga",
|
"ColdTaiga",
|
||||||
"ExtremeHills",
|
"ColdTaiga_beach",
|
||||||
"BirchForest",
|
"ColdTaiga_beach_water",
|
||||||
"MegaSpruceTaiga",
|
"MegaTaiga",
|
||||||
"MegaTaiga",
|
"MegaSpruceTaiga",
|
||||||
"ExtremeHills+",
|
"ExtremeHills",
|
||||||
"Forest",
|
"ExtremeHills_beach",
|
||||||
"Plains",
|
"ExtremeHillsM",
|
||||||
"ColdTaiga",
|
"ExtremeHills+",
|
||||||
"SunflowerPlains",
|
"ExtremeHills+_snowtop",
|
||||||
"RoofedForest",
|
"StoneBeach",
|
||||||
"MesaPlateauFM_grasstop",
|
"Plains",
|
||||||
"ExtremeHillsM",
|
"Plains_beach",
|
||||||
"BirchForestM",
|
"SunflowerPlains",
|
||||||
|
"Taiga",
|
||||||
|
"Taiga_beach",
|
||||||
|
"Forest",
|
||||||
|
"Forest_beach",
|
||||||
|
"FlowerForest",
|
||||||
|
"FlowerForest_beach",
|
||||||
|
"BirchForest",
|
||||||
|
"BirchForestM",
|
||||||
|
"RoofedForest",
|
||||||
|
"Savanna",
|
||||||
|
"Savanna_beach",
|
||||||
|
"SavannaM",
|
||||||
|
"Jungle",
|
||||||
|
"Jungle_shore",
|
||||||
|
"JungleM",
|
||||||
|
"JungleM_shore",
|
||||||
|
"JungleEdge",
|
||||||
|
"JungleEdgeM",
|
||||||
|
"Swampland",
|
||||||
|
"Swampland_shore"
|
||||||
},
|
},
|
||||||
9,
|
9,
|
||||||
minetest.LIGHT_MAX+1,
|
minetest.LIGHT_MAX+1,
|
||||||
|
|
|
@ -309,22 +309,42 @@ mobs:spawn_specific(
|
||||||
"overworld",
|
"overworld",
|
||||||
"ground",
|
"ground",
|
||||||
{
|
{
|
||||||
"FlowerForest",
|
"flat",
|
||||||
"Swampland",
|
"IcePlainsSpikes",
|
||||||
"Taiga",
|
"ColdTaiga",
|
||||||
"ExtremeHills",
|
"ColdTaiga_beach",
|
||||||
"BirchForest",
|
"ColdTaiga_beach_water",
|
||||||
"MegaSpruceTaiga",
|
"MegaTaiga",
|
||||||
"MegaTaiga",
|
"MegaSpruceTaiga",
|
||||||
"ExtremeHills+",
|
"ExtremeHills",
|
||||||
"Forest",
|
"ExtremeHills_beach",
|
||||||
"Plains",
|
"ExtremeHillsM",
|
||||||
"ColdTaiga",
|
"ExtremeHills+",
|
||||||
"SunflowerPlains",
|
"ExtremeHills+_snowtop",
|
||||||
"RoofedForest",
|
"StoneBeach",
|
||||||
"MesaPlateauFM_grasstop",
|
"Plains",
|
||||||
"ExtremeHillsM",
|
"Plains_beach",
|
||||||
"BirchForestM",
|
"SunflowerPlains",
|
||||||
|
"Taiga",
|
||||||
|
"Taiga_beach",
|
||||||
|
"Forest",
|
||||||
|
"Forest_beach",
|
||||||
|
"FlowerForest",
|
||||||
|
"FlowerForest_beach",
|
||||||
|
"BirchForest",
|
||||||
|
"BirchForestM",
|
||||||
|
"RoofedForest",
|
||||||
|
"Savanna",
|
||||||
|
"Savanna_beach",
|
||||||
|
"SavannaM",
|
||||||
|
"Jungle",
|
||||||
|
"Jungle_shore",
|
||||||
|
"JungleM",
|
||||||
|
"JungleM_shore",
|
||||||
|
"JungleEdge",
|
||||||
|
"JungleEdgeM",
|
||||||
|
"Swampland",
|
||||||
|
"Swampland_shore"
|
||||||
},
|
},
|
||||||
0,
|
0,
|
||||||
minetest.LIGHT_MAX+1,
|
minetest.LIGHT_MAX+1,
|
||||||
|
|
|
@ -16,7 +16,8 @@ local spawn_children_on_die = function(child_mob, children_count, spawn_distance
|
||||||
if not eject_speed then
|
if not eject_speed then
|
||||||
eject_speed = 1
|
eject_speed = 1
|
||||||
end
|
end
|
||||||
local mother_stuck = minetest.registered_nodes[minetest.get_node(pos).name].walkable
|
local mndef = minetest.registered_nodes[minetest.get_node(pos).name]
|
||||||
|
local mother_stuck = mndef and mndef.walkable
|
||||||
angle = math.random(0, math.pi*2)
|
angle = math.random(0, math.pi*2)
|
||||||
local children = {}
|
local children = {}
|
||||||
for i=1,children_count do
|
for i=1,children_count do
|
||||||
|
@ -26,7 +27,8 @@ local spawn_children_on_die = function(child_mob, children_count, spawn_distance
|
||||||
-- If child would end up in a wall, use position of the "mother", unless
|
-- If child would end up in a wall, use position of the "mother", unless
|
||||||
-- the "mother" was stuck as well
|
-- the "mother" was stuck as well
|
||||||
local speed_penalty = 1
|
local speed_penalty = 1
|
||||||
if (not mother_stuck) and minetest.registered_nodes[minetest.get_node(newpos).name].walkable then
|
local cndef = minetest.registered_nodes[minetest.get_node(newpos).name]
|
||||||
|
if (not mother_stuck) and cndef and cndef.walkable then
|
||||||
newpos = pos
|
newpos = pos
|
||||||
speed_penalty = 0.5
|
speed_penalty = 0.5
|
||||||
end
|
end
|
||||||
|
|
|
@ -548,7 +548,7 @@ local function get_recipe_fs(data, iY)
|
||||||
shapeless and "shapeless" or "furnace"
|
shapeless and "shapeless" or "furnace"
|
||||||
|
|
||||||
if recipe.type == "cooking" then
|
if recipe.type == "cooking" then
|
||||||
icon = "default_furnace_front_active.png"
|
icon = "craftguide_furnace.png"
|
||||||
elseif not custom_recipe then
|
elseif not custom_recipe then
|
||||||
icon = fmt("craftguide_%s.png", icon)
|
icon = fmt("craftguide_%s.png", icon)
|
||||||
end
|
end
|
||||||
|
|
After Width: | Height: | Size: 300 B |
|
@ -76,8 +76,6 @@ function tt.reload_itemstack_description(itemstack)
|
||||||
orig_desc = minetest.colorize(tt.NAME_COLOR, meta:get_string("name"))
|
orig_desc = minetest.colorize(tt.NAME_COLOR, meta:get_string("name"))
|
||||||
end
|
end
|
||||||
local desc = apply_snippets(orig_desc, itemstring, toolcaps or def.tool_capabilities, itemstack)
|
local desc = apply_snippets(orig_desc, itemstring, toolcaps or def.tool_capabilities, itemstack)
|
||||||
if desc ~= orig_desc then
|
|
||||||
meta:set_string("description", desc)
|
meta:set_string("description", desc)
|
||||||
end
|
end
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
local S = minetest.get_translator(minetest.get_current_modname())
|
local S = minetest.get_translator(minetest.get_current_modname())
|
||||||
|
|
||||||
|
local mod_target = minetest.get_modpath("mcl_target")
|
||||||
|
|
||||||
minetest.register_entity("mcl_experience:bottle",{
|
minetest.register_entity("mcl_experience:bottle",{
|
||||||
textures = {"mcl_experience_bottle.png"},
|
textures = {"mcl_experience_bottle.png"},
|
||||||
hp_max = 1,
|
hp_max = 1,
|
||||||
|
@ -30,6 +32,9 @@ minetest.register_entity("mcl_experience:bottle",{
|
||||||
vertical = false,
|
vertical = false,
|
||||||
texture = "mcl_particles_effect.png^[colorize:blue:127",
|
texture = "mcl_particles_effect.png^[colorize:blue:127",
|
||||||
})
|
})
|
||||||
|
if mod_target and n == "mcl_target:target_off" then
|
||||||
|
mcl_target.hit(vector.round(pos), 0.4) --4 redstone ticks
|
||||||
|
end
|
||||||
self.object:remove()
|
self.object:remove()
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
|
|
|
@ -363,6 +363,10 @@ function mcl_inventory.set_creative_formspec(player, start_i, pagenum, inv_size,
|
||||||
armor_slot_imgs = armor_slot_imgs .. "image[5.5,2.75;1,1;mcl_inventory_empty_armor_slot_boots.png]"
|
armor_slot_imgs = armor_slot_imgs .. "image[5.5,2.75;1,1;mcl_inventory_empty_armor_slot_boots.png]"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if inv:get_stack("offhand", 1):is_empty() then
|
||||||
|
armor_slot_imgs = armor_slot_imgs .. "image[1.5,2.025;1,1;mcl_inventory_empty_armor_slot_shield.png]"
|
||||||
|
end
|
||||||
|
|
||||||
local stack_size = get_stack_size(player)
|
local stack_size = get_stack_size(player)
|
||||||
|
|
||||||
-- Survival inventory slots
|
-- Survival inventory slots
|
||||||
|
@ -377,6 +381,8 @@ function mcl_inventory.set_creative_formspec(player, start_i, pagenum, inv_size,
|
||||||
mcl_formspec.get_itemslot_bg(2.5,2.75,1,1)..
|
mcl_formspec.get_itemslot_bg(2.5,2.75,1,1)..
|
||||||
mcl_formspec.get_itemslot_bg(5.5,1.3,1,1)..
|
mcl_formspec.get_itemslot_bg(5.5,1.3,1,1)..
|
||||||
mcl_formspec.get_itemslot_bg(5.5,2.75,1,1)..
|
mcl_formspec.get_itemslot_bg(5.5,2.75,1,1)..
|
||||||
|
"list[current_player;offhand;1.5,2.025;1,1]"..
|
||||||
|
mcl_formspec.get_itemslot_bg(1.5,2.025,1,1)..
|
||||||
armor_slot_imgs..
|
armor_slot_imgs..
|
||||||
-- player preview
|
-- player preview
|
||||||
player_preview..
|
player_preview..
|
||||||
|
|
|
@ -76,6 +76,10 @@ local function set_inventory(player, armor_change_only)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if inv:get_stack("offhand", 1):is_empty() then
|
||||||
|
armor_slot_imgs = armor_slot_imgs .. "image[3,2;1,1;mcl_inventory_empty_armor_slot_shield.png]"
|
||||||
|
end
|
||||||
|
|
||||||
local form = "size[9,8.75]"..
|
local form = "size[9,8.75]"..
|
||||||
"background[-0.19,-0.25;9.41,9.49;crafting_formspec_bg.png]"..
|
"background[-0.19,-0.25;9.41,9.49;crafting_formspec_bg.png]"..
|
||||||
player_preview..
|
player_preview..
|
||||||
|
@ -88,6 +92,8 @@ local function set_inventory(player, armor_change_only)
|
||||||
mcl_formspec.get_itemslot_bg(0,1,1,1)..
|
mcl_formspec.get_itemslot_bg(0,1,1,1)..
|
||||||
mcl_formspec.get_itemslot_bg(0,2,1,1)..
|
mcl_formspec.get_itemslot_bg(0,2,1,1)..
|
||||||
mcl_formspec.get_itemslot_bg(0,3,1,1)..
|
mcl_formspec.get_itemslot_bg(0,3,1,1)..
|
||||||
|
"list[current_player;offhand;3,2;1,1]"..
|
||||||
|
mcl_formspec.get_itemslot_bg(3,2,1,1)..
|
||||||
armor_slot_imgs..
|
armor_slot_imgs..
|
||||||
-- craft and inventory
|
-- craft and inventory
|
||||||
"label[0,4;"..F(minetest.colorize("#313131", S("Inventory"))).."]"..
|
"label[0,4;"..F(minetest.colorize("#313131", S("Inventory"))).."]"..
|
||||||
|
@ -148,8 +154,10 @@ end)
|
||||||
|
|
||||||
minetest.register_on_joinplayer(function(player)
|
minetest.register_on_joinplayer(function(player)
|
||||||
--init inventory
|
--init inventory
|
||||||
player:get_inventory():set_width("main", 9)
|
local inv = player:get_inventory()
|
||||||
player:get_inventory():set_size("main", 36)
|
inv:set_width("main", 9)
|
||||||
|
inv:set_size("main", 36)
|
||||||
|
inv:set_size("offhand", 1)
|
||||||
|
|
||||||
--set hotbar size
|
--set hotbar size
|
||||||
player:hud_set_hotbar_itemcount(9)
|
player:hud_set_hotbar_itemcount(9)
|
||||||
|
|
|
@ -0,0 +1,171 @@
|
||||||
|
local minetest, math = minetest, math
|
||||||
|
mcl_offhand = {}
|
||||||
|
|
||||||
|
local max_offhand_px = 128
|
||||||
|
-- only supports up to 128px textures
|
||||||
|
|
||||||
|
function mcl_offhand.get_offhand(player)
|
||||||
|
return player:get_inventory():get_stack("offhand", 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function offhand_get_wear(player)
|
||||||
|
return mcl_offhand.get_offhand(player):get_wear()
|
||||||
|
end
|
||||||
|
|
||||||
|
local function offhand_get_count(player)
|
||||||
|
return mcl_offhand.get_offhand(player):get_count()
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.register_on_joinplayer(function(player, last_login)
|
||||||
|
mcl_offhand[player] = {
|
||||||
|
hud = {},
|
||||||
|
last_wear = offhand_get_wear(player),
|
||||||
|
last_count = offhand_get_count(player),
|
||||||
|
}
|
||||||
|
end)
|
||||||
|
|
||||||
|
local function remove_hud(player, hud)
|
||||||
|
local offhand_hud = mcl_offhand[player].hud[hud]
|
||||||
|
if offhand_hud then
|
||||||
|
player:hud_remove(offhand_hud)
|
||||||
|
mcl_offhand[player].hud[hud] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function rgb_to_hex(r, g, b)
|
||||||
|
return string.format("%02x%02x%02x", r, g, b)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function update_wear_bar(player, itemstack)
|
||||||
|
local wear_bar_percent = (65535 - offhand_get_wear(player)) / 65535
|
||||||
|
|
||||||
|
local color = {255, 255, 255}
|
||||||
|
local wear = itemstack:get_wear() / 65535;
|
||||||
|
local wear_i = math.min(math.floor(wear * 600), 511);
|
||||||
|
wear_i = math.min(wear_i + 10, 511);
|
||||||
|
if wear_i <= 255 then
|
||||||
|
color = {wear_i, 255, 0}
|
||||||
|
else
|
||||||
|
color = {255, 511 - wear_i, 0}
|
||||||
|
end
|
||||||
|
local wear_bar = mcl_offhand[player].hud.wear_bar
|
||||||
|
player:hud_change(wear_bar, "text", "mcl_wear_bar.png^[colorize:#" .. rgb_to_hex(color[1], color[2], color[3]))
|
||||||
|
player:hud_change(wear_bar, "scale", {x = 40 * wear_bar_percent, y = 3})
|
||||||
|
player:hud_change(wear_bar, "offset", {x = -320 - (20 - player:hud_get(wear_bar).scale.x / 2), y = -13})
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.register_globalstep(function(dtime)
|
||||||
|
for _, player in pairs(minetest.get_connected_players()) do
|
||||||
|
local itemstack = mcl_offhand.get_offhand(player)
|
||||||
|
local offhand_item = itemstack:get_name()
|
||||||
|
local offhand_hud = mcl_offhand[player].hud
|
||||||
|
if offhand_item ~= "" then
|
||||||
|
local item_texture = minetest.registered_items[offhand_item].inventory_image .. "^[resize:" .. max_offhand_px .. "x" .. max_offhand_px
|
||||||
|
local position = {x = 0.5, y = 1}
|
||||||
|
local offset = {x = -320, y = -32}
|
||||||
|
|
||||||
|
if not offhand_hud.slot then
|
||||||
|
offhand_hud.slot = player:hud_add({
|
||||||
|
hud_elem_type = "image",
|
||||||
|
position = position,
|
||||||
|
offset = offset,
|
||||||
|
scale = {x = 2.75, y = 2.75},
|
||||||
|
text = "mcl_offhand_slot.png",
|
||||||
|
z_index = 0,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
if not offhand_hud.item then
|
||||||
|
offhand_hud.item = player:hud_add({
|
||||||
|
hud_elem_type = "image",
|
||||||
|
position = position,
|
||||||
|
offset = offset,
|
||||||
|
scale = {x = 0.4, y = 0.4},
|
||||||
|
text = item_texture,
|
||||||
|
z_index = 1,
|
||||||
|
})
|
||||||
|
else
|
||||||
|
player:hud_change(offhand_hud.item, "text", item_texture)
|
||||||
|
end
|
||||||
|
if not offhand_hud.wear_bar_bg and minetest.registered_tools[offhand_item] then
|
||||||
|
if offhand_get_wear(player) > 0 then
|
||||||
|
local texture = "mcl_wear_bar.png^[colorize:#000000"
|
||||||
|
offhand_hud.wear_bar_bg = player:hud_add({
|
||||||
|
hud_elem_type = "image",
|
||||||
|
position = {x = 0.5, y = 1},
|
||||||
|
offset = {x = -320, y = -13},
|
||||||
|
scale = {x = 40, y = 3},
|
||||||
|
text = texture,
|
||||||
|
z_index = 2,
|
||||||
|
})
|
||||||
|
offhand_hud.wear_bar = player:hud_add({
|
||||||
|
hud_elem_type = "image",
|
||||||
|
position = {x = 0.5, y = 1},
|
||||||
|
offset = {x = -320, y = -13},
|
||||||
|
scale = {x = 10, y = 3},
|
||||||
|
text = texture,
|
||||||
|
z_index = 3,
|
||||||
|
})
|
||||||
|
update_wear_bar(player, itemstack)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if not offhand_hud.item_count and offhand_get_count(player) > 1 then
|
||||||
|
offhand_hud.item_count = player:hud_add({
|
||||||
|
hud_elem_type = "text",
|
||||||
|
position = {x = 0.5, y = 1},
|
||||||
|
offset = {x = -298, y = -18},
|
||||||
|
scale = {x = 1, y = 1},
|
||||||
|
alignment = {x = -1, y = 0},
|
||||||
|
text = offhand_get_count(player),
|
||||||
|
z_index = 4,
|
||||||
|
number = 0xFFFFFF,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
if offhand_hud.wear_bar then
|
||||||
|
if offhand_hud.last_wear ~= offhand_get_wear(player) then
|
||||||
|
update_wear_bar(player, itemstack)
|
||||||
|
offhand_hud.last_wear = offhand_get_wear(player)
|
||||||
|
end
|
||||||
|
if offhand_get_wear(player) <= 0 or not minetest.registered_tools[offhand_item] then
|
||||||
|
remove_hud(player, "wear_bar_bg")
|
||||||
|
remove_hud(player, "wear_bar")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if offhand_hud.item_count then
|
||||||
|
if offhand_hud.last_count ~= offhand_get_count(player) then
|
||||||
|
player:hud_change(offhand_hud.item_count, "text", offhand_get_count(player))
|
||||||
|
offhand_hud.last_count = offhand_get_count(player)
|
||||||
|
end
|
||||||
|
if offhand_get_count(player) <= 1 then
|
||||||
|
remove_hud(player, "item_count")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif offhand_hud.slot then
|
||||||
|
for index, _ in pairs(mcl_offhand[player].hud) do
|
||||||
|
remove_hud(player, index)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
minetest.register_allow_player_inventory_action(function(player, action, inventory, inventory_info)
|
||||||
|
if action == "move" and inventory_info.to_list == "offhand" then
|
||||||
|
local itemstack = inventory:get_stack(inventory_info.from_list, inventory_info.from_index)
|
||||||
|
if not (minetest.get_item_group(itemstack:get_name(), "offhand_item") > 0) then
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
return itemstack:get_stack_max()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
minetest.register_on_player_inventory_action(function(player, action, inventory, inventory_info)
|
||||||
|
local from_offhand = inventory_info.from_list == "offhand"
|
||||||
|
local to_offhand = inventory_info.to_list == "offhand"
|
||||||
|
if action == "move" and from_offhand or to_offhand then
|
||||||
|
mcl_inventory.update_inventory_formspec(player)
|
||||||
|
end
|
||||||
|
end)
|
|
@ -0,0 +1,3 @@
|
||||||
|
name = mcl_offhand
|
||||||
|
author = NO11
|
||||||
|
depends = mcl_inventory
|
After Width: | Height: | Size: 8.6 KiB |
After Width: | Height: | Size: 168 B |
|
@ -0,0 +1,70 @@
|
||||||
|
local S = minetest.get_translator("mcl_target")
|
||||||
|
|
||||||
|
local mod_farming = minetest.get_modpath("mcl_farming")
|
||||||
|
|
||||||
|
mcl_target = {}
|
||||||
|
|
||||||
|
function mcl_target.hit(pos, time)
|
||||||
|
minetest.set_node(pos, {name="mcl_target:target_on"})
|
||||||
|
mesecon.receptor_on(pos, mesecon.rules.alldirs)
|
||||||
|
|
||||||
|
local timer = minetest.get_node_timer(pos)
|
||||||
|
timer:start(time)
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.register_node("mcl_target:target_off", {
|
||||||
|
description = S("Target"),
|
||||||
|
_doc_items_longdesc = S("A target is a block that provides a temporary redstone charge when hit by a projectile."),
|
||||||
|
_doc_items_usagehelp = S("Throw a projectile on the target to activate it."),
|
||||||
|
tiles = {"mcl_target_target_top.png", "mcl_target_target_top.png", "mcl_target_target_side.png"},
|
||||||
|
groups = {hoey = 1},
|
||||||
|
sounds = mcl_sounds.node_sound_dirt_defaults({
|
||||||
|
footstep = {name="default_grass_footstep", gain=0.1},
|
||||||
|
}),
|
||||||
|
mesecons = {
|
||||||
|
receptor = {
|
||||||
|
state = mesecon.state.off,
|
||||||
|
rules = mesecon.rules.alldirs,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
_mcl_blast_resistance = 0.5,
|
||||||
|
_mcl_hardness = 0.5,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_node("mcl_target:target_on", {
|
||||||
|
description = S("Target"),
|
||||||
|
_doc_items_create_entry = false,
|
||||||
|
tiles = {"mcl_target_target_top.png", "mcl_target_target_top.png", "mcl_target_target_side.png"},
|
||||||
|
groups = {hoey = 1, not_in_creative_inventory = 1},
|
||||||
|
drop = "mcl_target:target_off",
|
||||||
|
sounds = mcl_sounds.node_sound_dirt_defaults({
|
||||||
|
footstep = {name="default_grass_footstep", gain=0.1},
|
||||||
|
}),
|
||||||
|
on_timer = function(pos, elapsed)
|
||||||
|
local node = minetest.get_node(pos)
|
||||||
|
if node.name == "mcl_target:target_on" then --has not been dug
|
||||||
|
minetest.set_node(pos, {name="mcl_target:target_off"})
|
||||||
|
mesecon.receptor_off(pos, mesecon.rules.alldirs)
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
mesecons = {
|
||||||
|
receptor = {
|
||||||
|
state = mesecon.state.on,
|
||||||
|
rules = mesecon.rules.alldirs,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
_mcl_blast_resistance = 0.5,
|
||||||
|
_mcl_hardness = 0.5,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
if mod_farming then
|
||||||
|
minetest.register_craft({
|
||||||
|
output = "mcl_target:target_off",
|
||||||
|
recipe = {
|
||||||
|
{"", "mesecons:redstone", ""},
|
||||||
|
{"mesecons:redstone", "mcl_farming:hay_block", "mesecons:redstone"},
|
||||||
|
{"", "mesecons:redstone", ""},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
end
|
|
@ -0,0 +1,4 @@
|
||||||
|
# textdomain: mcl_target
|
||||||
|
Target=Cible
|
||||||
|
A target is a block that provides a temporary redstone charge when hit by a projectile.=La cible est un bloc qui se comporte comme une source d'énergie temporaire quand elle est frappée par un projectile.
|
||||||
|
Throw a projectile on the target to activate it.=Lancer un projectile sur la cible pour l'activer.
|
|
@ -0,0 +1,4 @@
|
||||||
|
# textdomain: mcl_target
|
||||||
|
Target=
|
||||||
|
A target is a block that provides a temporary redstone charge when hit by a projectile.=
|
||||||
|
Throw a projectile on the target to activate it.=
|
|
@ -0,0 +1,3 @@
|
||||||
|
name = mcl_target
|
||||||
|
author = AFCMS
|
||||||
|
depends = mesecons, mcl_sounds
|
After Width: | Height: | Size: 752 B |
After Width: | Height: | Size: 752 B |
|
@ -1,5 +1,69 @@
|
||||||
local S = minetest.get_translator(minetest.get_current_modname())
|
local S = minetest.get_translator(minetest.get_current_modname())
|
||||||
|
|
||||||
|
local function path_to_sunlight_exists(position, light_level)
|
||||||
|
local neighbours = {
|
||||||
|
{ x = 0, y = 0, z =-1 },
|
||||||
|
{ x = 0, y = 0, z = 1 },
|
||||||
|
{ x = 0, y =-1, z = 0 },
|
||||||
|
{ x = 0, y = 1, z = 0 },
|
||||||
|
{ x =-1, y = 0, z = 0 },
|
||||||
|
{ x = 1, y = 0, z = 0 },
|
||||||
|
}
|
||||||
|
for i=1, #neighbours do
|
||||||
|
local offset = neighbours[i]
|
||||||
|
local position_new = vector.add(
|
||||||
|
position,
|
||||||
|
offset
|
||||||
|
)
|
||||||
|
local light_level_new = minetest.get_node_light(
|
||||||
|
position_new,
|
||||||
|
nil
|
||||||
|
)
|
||||||
|
if 15 == light_level_new then
|
||||||
|
-- found the sunlight
|
||||||
|
return true
|
||||||
|
elseif light_level_new > light_level then
|
||||||
|
-- search where light is brighter
|
||||||
|
if path_to_sunlight_exists(
|
||||||
|
position_new,
|
||||||
|
light_level_new
|
||||||
|
) then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function sunlight_visible(position)
|
||||||
|
local light_level
|
||||||
|
-- Minetest 5.4.0+ can measure the daylight level at a position
|
||||||
|
if nil ~= minetest.get_natural_light then
|
||||||
|
light_level = minetest.get_natural_light(
|
||||||
|
position,
|
||||||
|
nil
|
||||||
|
)
|
||||||
|
if light_level >= 12 then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
else -- Minetest 5.3.0 or less can only measure the light level
|
||||||
|
local time = minetest.get_timeofday() * 24000
|
||||||
|
-- only check light level during day
|
||||||
|
if time > 6000 and time < 18000 then
|
||||||
|
light_level = minetest.get_node_light(
|
||||||
|
position,
|
||||||
|
nil
|
||||||
|
)
|
||||||
|
if light_level >= 12 then
|
||||||
|
return path_to_sunlight_exists(
|
||||||
|
position,
|
||||||
|
12
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
local boxes = { -8/16, -8/16, -8/16, 8/16, -2/16, 8/16 }
|
local boxes = { -8/16, -8/16, -8/16, 8/16, -2/16, 8/16 }
|
||||||
|
|
||||||
-- Daylight Sensor
|
-- Daylight Sensor
|
||||||
|
@ -95,9 +159,7 @@ minetest.register_abm({
|
||||||
interval = 1,
|
interval = 1,
|
||||||
chance = 1,
|
chance = 1,
|
||||||
action = function(pos, node, active_object_count, active_object_count_wider)
|
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||||
local light = minetest.get_node_light(pos, nil)
|
if sunlight_visible(pos) then
|
||||||
|
|
||||||
if light >= 12 and minetest.get_timeofday() > 0.2 and minetest.get_timeofday() < 0.8 then
|
|
||||||
minetest.set_node(pos, {name="mesecons_solarpanel:solar_panel_on", param2=node.param2})
|
minetest.set_node(pos, {name="mesecons_solarpanel:solar_panel_on", param2=node.param2})
|
||||||
mesecon.receptor_on(pos, mesecon.rules.pplate)
|
mesecon.receptor_on(pos, mesecon.rules.pplate)
|
||||||
end
|
end
|
||||||
|
@ -110,9 +172,7 @@ minetest.register_abm({
|
||||||
interval = 1,
|
interval = 1,
|
||||||
chance = 1,
|
chance = 1,
|
||||||
action = function(pos, node, active_object_count, active_object_count_wider)
|
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||||
local light = minetest.get_node_light(pos, nil)
|
if not sunlight_visible(pos) then
|
||||||
|
|
||||||
if light < 12 then
|
|
||||||
minetest.set_node(pos, {name="mesecons_solarpanel:solar_panel_off", param2=node.param2})
|
minetest.set_node(pos, {name="mesecons_solarpanel:solar_panel_off", param2=node.param2})
|
||||||
mesecon.receptor_off(pos, mesecon.rules.pplate)
|
mesecon.receptor_off(pos, mesecon.rules.pplate)
|
||||||
end
|
end
|
||||||
|
@ -202,9 +262,7 @@ minetest.register_abm({
|
||||||
interval = 1,
|
interval = 1,
|
||||||
chance = 1,
|
chance = 1,
|
||||||
action = function(pos, node, active_object_count, active_object_count_wider)
|
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||||
local light = minetest.get_node_light(pos, nil)
|
if not sunlight_visible(pos) then
|
||||||
|
|
||||||
if light < 12 then
|
|
||||||
minetest.set_node(pos, {name="mesecons_solarpanel:solar_panel_inverted_on", param2=node.param2})
|
minetest.set_node(pos, {name="mesecons_solarpanel:solar_panel_inverted_on", param2=node.param2})
|
||||||
mesecon.receptor_on(pos, mesecon.rules.pplate)
|
mesecon.receptor_on(pos, mesecon.rules.pplate)
|
||||||
end
|
end
|
||||||
|
@ -217,9 +275,7 @@ minetest.register_abm({
|
||||||
interval = 1,
|
interval = 1,
|
||||||
chance = 1,
|
chance = 1,
|
||||||
action = function(pos, node, active_object_count, active_object_count_wider)
|
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||||
local light = minetest.get_node_light(pos, nil)
|
if sunlight_visible(pos) then
|
||||||
|
|
||||||
if light >= 12 and minetest.get_timeofday() > 0.8 and minetest.get_timeofday() < 0.2 then
|
|
||||||
minetest.set_node(pos, {name="mesecons_solarpanel:solar_panel_inverted_off", param2=node.param2})
|
minetest.set_node(pos, {name="mesecons_solarpanel:solar_panel_inverted_off", param2=node.param2})
|
||||||
mesecon.receptor_off(pos, mesecon.rules.pplate)
|
mesecon.receptor_off(pos, mesecon.rules.pplate)
|
||||||
end
|
end
|
||||||
|
|
|
@ -88,6 +88,10 @@ for k,v in pairs(mcl_banners.colors) do
|
||||||
colors_reverse["mcl_banners:banner_item_"..v[1]] = k
|
colors_reverse["mcl_banners:banner_item_"..v[1]] = k
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function mcl_banners.color_reverse(itemname)
|
||||||
|
return colors_reverse[itemname]
|
||||||
|
end
|
||||||
|
|
||||||
-- Add pattern/emblazoning crafting recipes
|
-- Add pattern/emblazoning crafting recipes
|
||||||
dofile(modpath.."/patterncraft.lua")
|
dofile(modpath.."/patterncraft.lua")
|
||||||
|
|
||||||
|
@ -149,7 +153,7 @@ local function on_destruct_hanging_banner(pos)
|
||||||
return on_destruct_banner(pos, true)
|
return on_destruct_banner(pos, true)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function make_banner_texture(base_color, layers)
|
function mcl_banners.make_banner_texture(base_color, layers)
|
||||||
local colorize
|
local colorize
|
||||||
if mcl_banners.colors[base_color] then
|
if mcl_banners.colors[base_color] then
|
||||||
colorize = mcl_banners.colors[base_color][4]
|
colorize = mcl_banners.colors[base_color][4]
|
||||||
|
@ -171,11 +175,11 @@ local function make_banner_texture(base_color, layers)
|
||||||
|
|
||||||
finished_banner = finished_banner .. "^" .. layer
|
finished_banner = finished_banner .. "^" .. layer
|
||||||
end
|
end
|
||||||
return { finished_banner }
|
return finished_banner
|
||||||
end
|
end
|
||||||
return { base }
|
return base
|
||||||
else
|
else
|
||||||
return { "mcl_banners_banner_base.png" }
|
return "mcl_banners_banner_base.png"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -192,7 +196,7 @@ local function spawn_banner_entity(pos, hanging, itemstack)
|
||||||
local imeta = itemstack:get_meta()
|
local imeta = itemstack:get_meta()
|
||||||
local layers_raw = imeta:get_string("layers")
|
local layers_raw = imeta:get_string("layers")
|
||||||
local layers = minetest.deserialize(layers_raw)
|
local layers = minetest.deserialize(layers_raw)
|
||||||
local colorid = colors_reverse[itemstack:get_name()]
|
local colorid = mcl_banners.color_reverse(itemstack:get_name())
|
||||||
banner:get_luaentity():_set_textures(colorid, layers)
|
banner:get_luaentity():_set_textures(colorid, layers)
|
||||||
local mname = imeta:get_string("name")
|
local mname = imeta:get_string("name")
|
||||||
if mname and mname ~= "" then
|
if mname and mname ~= "" then
|
||||||
|
@ -604,7 +608,7 @@ local entity_standing = {
|
||||||
visual = "mesh",
|
visual = "mesh",
|
||||||
mesh = "amc_banner.b3d",
|
mesh = "amc_banner.b3d",
|
||||||
visual_size = { x=2.499, y=2.499 },
|
visual_size = { x=2.499, y=2.499 },
|
||||||
textures = make_banner_texture(),
|
textures = {mcl_banners.make_banner_texture()},
|
||||||
pointable = false,
|
pointable = false,
|
||||||
|
|
||||||
_base_color = nil, -- base color of banner
|
_base_color = nil, -- base color of banner
|
||||||
|
@ -624,7 +628,7 @@ local entity_standing = {
|
||||||
self._layers = inp._layers
|
self._layers = inp._layers
|
||||||
self._name = inp._name
|
self._name = inp._name
|
||||||
self.object:set_properties({
|
self.object:set_properties({
|
||||||
textures = make_banner_texture(self._base_color, self._layers),
|
textures = {mcl_banners.make_banner_texture(self._base_color, self._layers)},
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
-- Make banner slowly swing
|
-- Make banner slowly swing
|
||||||
|
@ -635,7 +639,7 @@ local entity_standing = {
|
||||||
-- Set the banner textures. This function can be used by external mods.
|
-- Set the banner textures. This function can be used by external mods.
|
||||||
-- Meaning of parameters:
|
-- Meaning of parameters:
|
||||||
-- * self: Lua entity reference to entity.
|
-- * self: Lua entity reference to entity.
|
||||||
-- * other parameters: Same meaning as in make_banner_texture
|
-- * other parameters: Same meaning as in mcl_banners.make_banner_texture
|
||||||
_set_textures = function(self, base_color, layers)
|
_set_textures = function(self, base_color, layers)
|
||||||
if base_color then
|
if base_color then
|
||||||
self._base_color = base_color
|
self._base_color = base_color
|
||||||
|
@ -643,7 +647,7 @@ local entity_standing = {
|
||||||
if layers then
|
if layers then
|
||||||
self._layers = layers
|
self._layers = layers
|
||||||
end
|
end
|
||||||
self.object:set_properties({textures = make_banner_texture(self._base_color, self._layers)})
|
self.object:set_properties({textures = {mcl_banners.make_banner_texture(self._base_color, self._layers)}})
|
||||||
end,
|
end,
|
||||||
}
|
}
|
||||||
minetest.register_entity("mcl_banners:standing_banner", entity_standing)
|
minetest.register_entity("mcl_banners:standing_banner", entity_standing)
|
||||||
|
|
|
@ -14,6 +14,27 @@ local function on_blast(pos)
|
||||||
minetest.remove_node(pos)
|
minetest.remove_node(pos)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Simple protection checking functions
|
||||||
|
local function protection_check_move(pos, from_list, from_index, to_list, to_index, count, player)
|
||||||
|
local name = player:get_player_name()
|
||||||
|
if minetest.is_protected(pos, name) then
|
||||||
|
minetest.record_protection_violation(pos, name)
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
return count
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function protection_check_put_take(pos, listname, index, stack, player)
|
||||||
|
local name = player:get_player_name()
|
||||||
|
if minetest.is_protected(pos, name) then
|
||||||
|
minetest.record_protection_violation(pos, name)
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
return stack:get_count()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local function barrel_open(pos, node, clicker)
|
local function barrel_open(pos, node, clicker)
|
||||||
local name = minetest.get_meta(pos):get_string("name")
|
local name = minetest.get_meta(pos):get_string("name")
|
||||||
|
|
||||||
|
@ -82,7 +103,6 @@ minetest.register_node("mcl_barrels:barrel_closed", {
|
||||||
tiles = {"mcl_barrels_barrel_top.png^[transformR270", "mcl_barrels_barrel_bottom.png", "mcl_barrels_barrel_side.png"},
|
tiles = {"mcl_barrels_barrel_top.png^[transformR270", "mcl_barrels_barrel_bottom.png", "mcl_barrels_barrel_side.png"},
|
||||||
paramtype = "light",
|
paramtype = "light",
|
||||||
paramtype2 = "facedir",
|
paramtype2 = "facedir",
|
||||||
--on_place = mcl_util.rotate_axis,
|
|
||||||
on_place = function(itemstack, placer, pointed_thing)
|
on_place = function(itemstack, placer, pointed_thing)
|
||||||
minetest.rotate_and_place(itemstack, placer, pointed_thing, minetest.is_creative_enabled(placer:get_player_name()), {}, false)
|
minetest.rotate_and_place(itemstack, placer, pointed_thing, minetest.is_creative_enabled(placer:get_player_name()), {}, false)
|
||||||
return itemstack
|
return itemstack
|
||||||
|
@ -98,6 +118,21 @@ minetest.register_node("mcl_barrels:barrel_closed", {
|
||||||
after_place_node = function(pos, placer, itemstack, pointed_thing)
|
after_place_node = function(pos, placer, itemstack, pointed_thing)
|
||||||
minetest.get_meta(pos):set_string("name", itemstack:get_meta():get_string("name"))
|
minetest.get_meta(pos):set_string("name", itemstack:get_meta():get_string("name"))
|
||||||
end,
|
end,
|
||||||
|
allow_metadata_inventory_move = protection_check_move,
|
||||||
|
allow_metadata_inventory_take = protection_check_put_take,
|
||||||
|
allow_metadata_inventory_put = protection_check_put_take,
|
||||||
|
on_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
|
||||||
|
minetest.log("action", player:get_player_name()..
|
||||||
|
" moves stuff in barrel at "..minetest.pos_to_string(pos))
|
||||||
|
end,
|
||||||
|
on_metadata_inventory_put = function(pos, listname, index, stack, player)
|
||||||
|
minetest.log("action", player:get_player_name()..
|
||||||
|
" moves stuff to barrel at "..minetest.pos_to_string(pos))
|
||||||
|
end,
|
||||||
|
on_metadata_inventory_take = function(pos, listname, index, stack, player)
|
||||||
|
minetest.log("action", player:get_player_name()..
|
||||||
|
" takes stuff from barrel at "..minetest.pos_to_string(pos))
|
||||||
|
end,
|
||||||
after_dig_node = drop_content,
|
after_dig_node = drop_content,
|
||||||
on_blast = on_blast,
|
on_blast = on_blast,
|
||||||
on_rightclick = barrel_open,
|
on_rightclick = barrel_open,
|
||||||
|
@ -119,6 +154,21 @@ minetest.register_node("mcl_barrels:barrel_open", {
|
||||||
stack_max = 64,
|
stack_max = 64,
|
||||||
sounds = mcl_sounds.node_sound_wood_defaults(),
|
sounds = mcl_sounds.node_sound_wood_defaults(),
|
||||||
groups = {handy = 1, axey = 1, container = 2, material_wood = 1, flammable = -1, deco_block = 1, not_in_creative_inventory = 1},
|
groups = {handy = 1, axey = 1, container = 2, material_wood = 1, flammable = -1, deco_block = 1, not_in_creative_inventory = 1},
|
||||||
|
allow_metadata_inventory_move = protection_check_move,
|
||||||
|
allow_metadata_inventory_take = protection_check_put_take,
|
||||||
|
allow_metadata_inventory_put = protection_check_put_take,
|
||||||
|
on_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
|
||||||
|
minetest.log("action", player:get_player_name()..
|
||||||
|
" moves stuff in barrel at "..minetest.pos_to_string(pos))
|
||||||
|
end,
|
||||||
|
on_metadata_inventory_put = function(pos, listname, index, stack, player)
|
||||||
|
minetest.log("action", player:get_player_name()..
|
||||||
|
" moves stuff to barrel at "..minetest.pos_to_string(pos))
|
||||||
|
end,
|
||||||
|
on_metadata_inventory_take = function(pos, listname, index, stack, player)
|
||||||
|
minetest.log("action", player:get_player_name()..
|
||||||
|
" takes stuff from barrel at "..minetest.pos_to_string(pos))
|
||||||
|
end,
|
||||||
after_dig_node = drop_content,
|
after_dig_node = drop_content,
|
||||||
on_blast = on_blast,
|
on_blast = on_blast,
|
||||||
on_rightclick = barrel_open,
|
on_rightclick = barrel_open,
|
||||||
|
@ -146,3 +196,9 @@ minetest.register_craft({
|
||||||
{"group:wood", "group:wood_slab", "group:wood"},
|
{"group:wood", "group:wood_slab", "group:wood"},
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
minetest.register_craft({
|
||||||
|
type = "fuel",
|
||||||
|
recipe = "mcl_barrels:barrel_closed",
|
||||||
|
burntime = 15,
|
||||||
|
})
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
local S = minetest.get_translator(minetest.get_current_modname())
|
local S = minetest.get_translator(minetest.get_current_modname())
|
||||||
|
|
||||||
|
local mod_target = minetest.get_modpath("mcl_target")
|
||||||
|
|
||||||
local math = math
|
local math = math
|
||||||
local vector = vector
|
local vector = vector
|
||||||
|
|
||||||
|
@ -74,6 +76,7 @@ local ARROW_ENTITY={
|
||||||
_shooter=nil, -- ObjectRef of player or mob who shot it
|
_shooter=nil, -- ObjectRef of player or mob who shot it
|
||||||
_is_arrow = true,
|
_is_arrow = true,
|
||||||
_in_player = false,
|
_in_player = false,
|
||||||
|
_blocked = false,
|
||||||
_viscosity=0, -- Viscosity of node the arrow is currently in
|
_viscosity=0, -- Viscosity of node the arrow is currently in
|
||||||
_deflection_cooloff=0, -- Cooloff timer after an arrow deflection, to prevent many deflections in quick succession
|
_deflection_cooloff=0, -- Cooloff timer after an arrow deflection, to prevent many deflections in quick succession
|
||||||
}
|
}
|
||||||
|
@ -82,7 +85,7 @@ local ARROW_ENTITY={
|
||||||
local function spawn_item(self, pos)
|
local function spawn_item(self, pos)
|
||||||
if not minetest.is_creative_enabled("") then
|
if not minetest.is_creative_enabled("") then
|
||||||
local item = minetest.add_item(pos, "mcl_bows:arrow")
|
local item = minetest.add_item(pos, "mcl_bows:arrow")
|
||||||
item:set_velocity({x=0, y=0, z=0})
|
item:set_velocity(vector.new(0, 0, 0))
|
||||||
item:set_yaw(self.object:get_yaw())
|
item:set_yaw(self.object:get_yaw())
|
||||||
end
|
end
|
||||||
mcl_burning.extinguish(self.object)
|
mcl_burning.extinguish(self.object)
|
||||||
|
@ -94,12 +97,10 @@ local function damage_particles(pos, is_critical)
|
||||||
minetest.add_particlespawner({
|
minetest.add_particlespawner({
|
||||||
amount = 15,
|
amount = 15,
|
||||||
time = 0.1,
|
time = 0.1,
|
||||||
minpos = {x=pos.x-0.5, y=pos.y-0.5, z=pos.z-0.5},
|
minpos = vector.offset(pos, -0.5, -0.5, -0.5),
|
||||||
maxpos = {x=pos.x+0.5, y=pos.y+0.5, z=pos.z+0.5},
|
maxpos = vector.offset(pos, 0.5, 0.5, 0.5),
|
||||||
minvel = {x=-0.1, y=-0.1, z=-0.1},
|
minvel = vector.new(-0.1, -0.1, -0.1),
|
||||||
maxvel = {x=0.1, y=0.1, z=0.1},
|
maxvel = vector.new(0.1, 0.1, 0.1),
|
||||||
minacc = {x=0, y=0, z=0},
|
|
||||||
maxacc = {x=0, y=0, z=0},
|
|
||||||
minexptime = 1,
|
minexptime = 1,
|
||||||
maxexptime = 2,
|
maxexptime = 2,
|
||||||
minsize = 1.5,
|
minsize = 1.5,
|
||||||
|
@ -117,8 +118,7 @@ function ARROW_ENTITY.on_step(self, dtime)
|
||||||
self._time_in_air = self._time_in_air + .001
|
self._time_in_air = self._time_in_air + .001
|
||||||
|
|
||||||
local pos = self.object:get_pos()
|
local pos = self.object:get_pos()
|
||||||
local dpos = table.copy(pos) -- digital pos
|
local dpos = vector.round(vector.new(pos)) -- digital pos
|
||||||
dpos = vector.round(dpos)
|
|
||||||
local node = minetest.get_node(dpos)
|
local node = minetest.get_node(dpos)
|
||||||
|
|
||||||
if self._stuck then
|
if self._stuck then
|
||||||
|
@ -248,18 +248,19 @@ function ARROW_ENTITY.on_step(self, dtime)
|
||||||
|
|
||||||
-- Punch target object but avoid hurting enderman.
|
-- Punch target object but avoid hurting enderman.
|
||||||
if not lua or lua.name ~= "mobs_mc:enderman" then
|
if not lua or lua.name ~= "mobs_mc:enderman" then
|
||||||
if self._in_player == false then
|
if not self._in_player then
|
||||||
damage_particles(self.object:get_pos(), self._is_critical)
|
damage_particles(self.object:get_pos(), self._is_critical)
|
||||||
end
|
end
|
||||||
if mcl_burning.is_burning(self.object) then
|
if mcl_burning.is_burning(self.object) then
|
||||||
mcl_burning.set_on_fire(obj, 5)
|
mcl_burning.set_on_fire(obj, 5)
|
||||||
end
|
end
|
||||||
if self._in_player == false then
|
if not self._in_player and not self._blocked then
|
||||||
obj:punch(self.object, 1.0, {
|
obj:punch(self.object, 1.0, {
|
||||||
full_punch_interval=1.0,
|
full_punch_interval=1.0,
|
||||||
damage_groups={fleshy=self._damage},
|
damage_groups={fleshy=self._damage},
|
||||||
}, self.object:get_velocity())
|
}, self.object:get_velocity())
|
||||||
if obj:is_player() then
|
if obj:is_player() then
|
||||||
|
if not mcl_shields.is_blocking(obj) then
|
||||||
local placement
|
local placement
|
||||||
self._placement = math.random(1, 2)
|
self._placement = math.random(1, 2)
|
||||||
if self._placement == 1 then
|
if self._placement == 1 then
|
||||||
|
@ -291,7 +292,15 @@ function ARROW_ENTITY.on_step(self, dtime)
|
||||||
end
|
end
|
||||||
self._z_rotation = math.random(-30, 30)
|
self._z_rotation = math.random(-30, 30)
|
||||||
self._y_rotation = math.random( -30, 30)
|
self._y_rotation = math.random( -30, 30)
|
||||||
self.object:set_attach(obj, self._attach_parent, {x=self._x_position,y=self._y_position,z=random_arrow_positions("z", placement)}, {x=0,y=self._rotation_station + self._y_rotation,z=self._z_rotation})
|
self.object:set_attach(
|
||||||
|
obj, self._attach_parent,
|
||||||
|
vector.new(self._x_position, self._y_position, random_arrow_positions("z", placement)),
|
||||||
|
vector.new(0, self._rotation_station + self._y_rotation, self._z_rotation)
|
||||||
|
)
|
||||||
|
else
|
||||||
|
self._blocked = true
|
||||||
|
self.object:set_velocity(vector.multiply(self.object:get_velocity(), -0.25))
|
||||||
|
end
|
||||||
minetest.after(150, function()
|
minetest.after(150, function()
|
||||||
self.object:remove()
|
self.object:remove()
|
||||||
end)
|
end)
|
||||||
|
@ -301,7 +310,7 @@ function ARROW_ENTITY.on_step(self, dtime)
|
||||||
|
|
||||||
|
|
||||||
if is_player then
|
if is_player then
|
||||||
if self._shooter and self._shooter:is_player() and self._in_player == false then
|
if self._shooter and self._shooter:is_player() and not self._in_player and not self._blocked then
|
||||||
-- “Ding” sound for hitting another player
|
-- “Ding” sound for hitting another player
|
||||||
minetest.sound_play({name="mcl_bows_hit_player", gain=0.1}, {to_player=self._shooter:get_player_name()}, true)
|
minetest.sound_play({name="mcl_bows_hit_player", gain=0.1}, {to_player=self._shooter:get_player_name()}, true)
|
||||||
end
|
end
|
||||||
|
@ -318,7 +327,7 @@ function ARROW_ENTITY.on_step(self, dtime)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if self._in_player == false then
|
if not self._in_player and not self._blocked then
|
||||||
minetest.sound_play({name="mcl_bows_hit_other", gain=0.3}, {pos=self.object:get_pos(), max_hear_distance=16}, true)
|
minetest.sound_play({name="mcl_bows_hit_other", gain=0.3}, {pos=self.object:get_pos(), max_hear_distance=16}, true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -344,9 +353,9 @@ function ARROW_ENTITY.on_step(self, dtime)
|
||||||
local dir
|
local dir
|
||||||
if math.abs(vel.y) < 0.00001 then
|
if math.abs(vel.y) < 0.00001 then
|
||||||
if self._lastpos.y < pos.y then
|
if self._lastpos.y < pos.y then
|
||||||
dir = {x=0, y=1, z=0}
|
dir = vector.new(0, 1, 0)
|
||||||
else
|
else
|
||||||
dir = {x=0, y=-1, z=0}
|
dir = vector.new(0, -1, 0)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
dir = minetest.facedir_to_dir(minetest.dir_to_facedir(minetest.yaw_to_dir(self.object:get_yaw()-YAW_OFFSET)))
|
dir = minetest.facedir_to_dir(minetest.dir_to_facedir(minetest.yaw_to_dir(self.object:get_yaw()-YAW_OFFSET)))
|
||||||
|
@ -374,8 +383,8 @@ function ARROW_ENTITY.on_step(self, dtime)
|
||||||
self._stucktimer = 0
|
self._stucktimer = 0
|
||||||
self._stuckrechecktimer = 0
|
self._stuckrechecktimer = 0
|
||||||
|
|
||||||
self.object:set_velocity({x=0, y=0, z=0})
|
self.object:set_velocity(vector.new(0, 0, 0))
|
||||||
self.object:set_acceleration({x=0, y=0, z=0})
|
self.object:set_acceleration(vector.new(0, 0, 0))
|
||||||
|
|
||||||
minetest.sound_play({name="mcl_bows_hit_other", gain=0.3}, {pos=self.object:get_pos(), max_hear_distance=16}, true)
|
minetest.sound_play({name="mcl_bows_hit_other", gain=0.3}, {pos=self.object:get_pos(), max_hear_distance=16}, true)
|
||||||
|
|
||||||
|
@ -383,6 +392,11 @@ function ARROW_ENTITY.on_step(self, dtime)
|
||||||
tnt.ignite(self._stuckin)
|
tnt.ignite(self._stuckin)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Activate target
|
||||||
|
if mod_target and snode.name == "mcl_target:target_off" then
|
||||||
|
mcl_target.hit(self._stuckin, 1) --10 redstone ticks
|
||||||
|
end
|
||||||
|
|
||||||
-- Push the button! Push, push, push the button!
|
-- Push the button! Push, push, push the button!
|
||||||
if mod_button and minetest.get_item_group(node.name, "button") > 0 and minetest.get_item_group(node.name, "button_push_by_arrow") == 1 then
|
if mod_button and minetest.get_item_group(node.name, "button") > 0 and minetest.get_item_group(node.name, "button_push_by_arrow") == 1 then
|
||||||
local bdir = minetest.wallmounted_to_dir(node.param2)
|
local bdir = minetest.wallmounted_to_dir(node.param2)
|
||||||
|
@ -420,7 +434,7 @@ function ARROW_ENTITY.on_step(self, dtime)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Update internal variable
|
-- Update internal variable
|
||||||
self._lastpos={x=pos.x, y=pos.y, z=pos.z}
|
self._lastpos = pos
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Force recheck of stuck arrows when punched.
|
-- Force recheck of stuck arrows when punched.
|
||||||
|
|
|
@ -116,7 +116,7 @@ end
|
||||||
|
|
||||||
-- Bow item, uncharged state
|
-- Bow item, uncharged state
|
||||||
minetest.register_tool("mcl_bows:crossbow", {
|
minetest.register_tool("mcl_bows:crossbow", {
|
||||||
description = S("Corssbow"),
|
description = S("Crossbow"),
|
||||||
_tt_help = S("Launches arrows"),
|
_tt_help = S("Launches arrows"),
|
||||||
_doc_items_longdesc = S("Bows are ranged weapons to shoot arrows at your foes.").."\n"..
|
_doc_items_longdesc = S("Bows are ranged weapons to shoot arrows at your foes.").."\n"..
|
||||||
S("The speed and damage of the arrow increases the longer you charge. The regular damage of the arrow is between 1 and 9. At full charge, there's also a 20% of a critical hit, dealing 10 damage instead."),
|
S("The speed and damage of the arrow increases the longer you charge. The regular damage of the arrow is between 1 and 9. At full charge, there's also a 20% of a critical hit, dealing 10 damage instead."),
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
name = mcl_bows
|
name = mcl_bows
|
||||||
author = Arcelmi
|
author = Arcelmi
|
||||||
description = This mod adds bows and arrows for MineClone 2.
|
description = This mod adds bows and arrows for MineClone 2.
|
||||||
depends = controls, mcl_particles, mcl_enchanting, mcl_init
|
depends = controls, mcl_particles, mcl_enchanting, mcl_init, mcl_util, mcl_shields
|
||||||
optional_depends = awards, mcl_achievements, mcl_core, mcl_mobitems, playerphysics, doc, doc_identifier, mesecons_button
|
optional_depends = awards, mcl_achievements, mcl_core, mcl_mobitems, playerphysics, doc, doc_identifier, mesecons_button
|
||||||
|
|
||||||
|
|
|
@ -18,20 +18,6 @@ local function dir_to_pitch(dir)
|
||||||
return -math.atan2(-dir.y, xz)
|
return -math.atan2(-dir.y, xz)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function random_arrow_positions(positions, placement)
|
|
||||||
if positions == "x" then
|
|
||||||
return math.random(-4, 4)
|
|
||||||
elseif positions == "y" then
|
|
||||||
return math.random(0, 10)
|
|
||||||
end
|
|
||||||
if placement == "front" and positions == "z" then
|
|
||||||
return 3
|
|
||||||
elseif placement == "back" and positions == "z" then
|
|
||||||
return -3
|
|
||||||
end
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
|
|
||||||
local function damage_explosion(self, damagemulitplier)
|
local function damage_explosion(self, damagemulitplier)
|
||||||
mcl_explosions.explode(self.object:get_pos(), 3, {})
|
mcl_explosions.explode(self.object:get_pos(), 3, {})
|
||||||
local objects = minetest.get_objects_inside_radius(self.object:get_pos(), 8)
|
local objects = minetest.get_objects_inside_radius(self.object:get_pos(), 8)
|
||||||
|
@ -49,10 +35,10 @@ end
|
||||||
|
|
||||||
local function particle_explosion(self)
|
local function particle_explosion(self)
|
||||||
local particle_pattern = math.random(1, 3)
|
local particle_pattern = math.random(1, 3)
|
||||||
local fpitch = 0
|
local fpitch
|
||||||
local true_type = ""
|
--local true_type
|
||||||
local type = math.random(1,2)
|
local type = math.random(1, 2)
|
||||||
local size = math.random(1,3)
|
local size = math.random(1, 3)
|
||||||
local colors = {"red", "yellow", "blue", "green", "white"}
|
local colors = {"red", "yellow", "blue", "green", "white"}
|
||||||
local this_colors = {colors[math.random(#colors)], colors[math.random(#colors)], colors[math.random(#colors)]}
|
local this_colors = {colors[math.random(#colors)], colors[math.random(#colors)], colors[math.random(#colors)]}
|
||||||
|
|
||||||
|
@ -64,11 +50,11 @@ local function particle_explosion(self)
|
||||||
fpitch = math.random(60, 70)
|
fpitch = math.random(60, 70)
|
||||||
end
|
end
|
||||||
|
|
||||||
if type == 1 then
|
--[[if type == 1 then
|
||||||
true_type = "Popper"
|
true_type = "Popper"
|
||||||
else
|
else
|
||||||
true_type = "Floof"
|
true_type = "Floof"
|
||||||
end
|
end]]
|
||||||
|
|
||||||
if type == 1 then
|
if type == 1 then
|
||||||
minetest.sound_play("mcl_bows_firework", {
|
minetest.sound_play("mcl_bows_firework", {
|
||||||
|
@ -243,6 +229,7 @@ end
|
||||||
|
|
||||||
local mod_awards = minetest.get_modpath("awards") and minetest.get_modpath("mcl_achievements")
|
local mod_awards = minetest.get_modpath("awards") and minetest.get_modpath("mcl_achievements")
|
||||||
local mod_button = minetest.get_modpath("mesecons_button")
|
local mod_button = minetest.get_modpath("mesecons_button")
|
||||||
|
local mod_target = minetest.get_modpath("mcl_target")
|
||||||
|
|
||||||
minetest.register_craftitem("mcl_bows:rocket", {
|
minetest.register_craftitem("mcl_bows:rocket", {
|
||||||
description = S("Arrow"),
|
description = S("Arrow"),
|
||||||
|
@ -578,6 +565,11 @@ function ARROW_ENTITY.on_step(self, dtime)
|
||||||
tnt.ignite(self._stuckin)
|
tnt.ignite(self._stuckin)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Activate target
|
||||||
|
if mod_target and snode.name == "mcl_target:target_off" then
|
||||||
|
mcl_target.hit(self._stuckin, 1) --10 redstone ticks
|
||||||
|
end
|
||||||
|
|
||||||
-- Push the button! Push, push, push the button!
|
-- Push the button! Push, push, push the button!
|
||||||
if mod_button and minetest.get_item_group(node.name, "button") > 0 and minetest.get_item_group(node.name, "button_push_by_arrow") == 1 then
|
if mod_button and minetest.get_item_group(node.name, "button") > 0 and minetest.get_item_group(node.name, "button_push_by_arrow") == 1 then
|
||||||
local bdir = minetest.wallmounted_to_dir(node.param2)
|
local bdir = minetest.wallmounted_to_dir(node.param2)
|
||||||
|
|
|
@ -32,6 +32,12 @@ minetest.register_craft({
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
minetest.register_craft({
|
||||||
|
type = "fuel",
|
||||||
|
recipe = "mcl_composters:composter",
|
||||||
|
burntime = 15,
|
||||||
|
})
|
||||||
|
|
||||||
local compostability = {
|
local compostability = {
|
||||||
["mcl_cake:cake"] = 100,
|
["mcl_cake:cake"] = 100,
|
||||||
["mcl_farming:pumpkin_pie"] = 100,
|
["mcl_farming:pumpkin_pie"] = 100,
|
||||||
|
|
|
@ -210,7 +210,8 @@ minetest.register_abm({
|
||||||
end
|
end
|
||||||
local posses = { { 1, 0 }, { -1, 0 }, { 0, 1 }, { 0, -1 } }
|
local posses = { { 1, 0 }, { -1, 0 }, { 0, 1 }, { 0, -1 } }
|
||||||
for _, p in pairs(posses) do
|
for _, p in pairs(posses) do
|
||||||
if minetest.registered_nodes[minetest.get_node(vector.new(pos.x + p[1], pos.y, pos.z + p[2])).name].walkable then
|
local ndef = minetest.registered_nodes[minetest.get_node(vector.new(pos.x + p[1], pos.y, pos.z + p[2])).name]
|
||||||
|
if ndef and ndef.walkable then
|
||||||
local posy = pos.y
|
local posy = pos.y
|
||||||
while minetest.get_node(vector.new(pos.x, posy, pos.z)).name == "mcl_core:cactus" do
|
while minetest.get_node(vector.new(pos.x, posy, pos.z)).name == "mcl_core:cactus" do
|
||||||
local pos = vector.new(pos.x, posy, pos.z)
|
local pos = vector.new(pos.x, posy, pos.z)
|
||||||
|
@ -841,7 +842,7 @@ minetest.register_abm({
|
||||||
-- If this was mycelium, uproot plant above
|
-- If this was mycelium, uproot plant above
|
||||||
if n2.name == "mcl_core:mycelium" then
|
if n2.name == "mcl_core:mycelium" then
|
||||||
local tad = minetest.registered_nodes[minetest.get_node(above).name]
|
local tad = minetest.registered_nodes[minetest.get_node(above).name]
|
||||||
if tad.groups and tad.groups.non_mycelium_plant then
|
if tad and tad.groups and tad.groups.non_mycelium_plant then
|
||||||
minetest.dig_node(above)
|
minetest.dig_node(above)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1333,7 +1334,7 @@ minetest.register_abm({
|
||||||
function mcl_core.supports_vines(nodename)
|
function mcl_core.supports_vines(nodename)
|
||||||
local def = minetest.registered_nodes[nodename]
|
local def = minetest.registered_nodes[nodename]
|
||||||
-- Rules: 1) walkable 2) full cube
|
-- Rules: 1) walkable 2) full cube
|
||||||
return def.walkable and
|
return def and def.walkable and
|
||||||
(def.node_box == nil or def.node_box.type == "regular") and
|
(def.node_box == nil or def.node_box.type == "regular") and
|
||||||
(def.collision_box == nil or def.collision_box.type == "regular")
|
(def.collision_box == nil or def.collision_box.type == "regular")
|
||||||
end
|
end
|
||||||
|
|
|
@ -54,7 +54,7 @@ minetest.register_node("mcl_core:reeds", {
|
||||||
_doc_items_usagehelp = S("Sugar canes can only be placed top of other sugar canes and on top of blocks on which they would grow."),
|
_doc_items_usagehelp = S("Sugar canes can only be placed top of other sugar canes and on top of blocks on which they would grow."),
|
||||||
drawtype = "plantlike",
|
drawtype = "plantlike",
|
||||||
paramtype2 = "color",
|
paramtype2 = "color",
|
||||||
tiles = {"default_papyrus.png"},
|
tiles = {"mcl_core_papyrus.png"},
|
||||||
palette = "mcl_core_palette_grass.png",
|
palette = "mcl_core_palette_grass.png",
|
||||||
palette_index = 0,
|
palette_index = 0,
|
||||||
inventory_image = "mcl_core_reeds.png",
|
inventory_image = "mcl_core_reeds.png",
|
||||||
|
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
|
@ -389,6 +389,7 @@ mcl_experience.register_on_add_xp(function(player, xp)
|
||||||
{list = "armor", index = 3},
|
{list = "armor", index = 3},
|
||||||
{list = "armor", index = 4},
|
{list = "armor", index = 4},
|
||||||
{list = "armor", index = 5},
|
{list = "armor", index = 5},
|
||||||
|
{list = "offhand", index = 1},
|
||||||
}
|
}
|
||||||
|
|
||||||
local final_candidates = {}
|
local final_candidates = {}
|
||||||
|
|
|
@ -74,8 +74,12 @@ function mcl_enchanting.is_enchanted(itemname)
|
||||||
return minetest.get_item_group(itemname, "enchanted") > 0
|
return minetest.get_item_group(itemname, "enchanted") > 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function mcl_enchanting.not_enchantable_on_enchanting_table(itemname)
|
||||||
|
return mcl_enchanting.get_enchantability(itemname) == -1
|
||||||
|
end
|
||||||
|
|
||||||
function mcl_enchanting.is_enchantable(itemname)
|
function mcl_enchanting.is_enchantable(itemname)
|
||||||
return mcl_enchanting.get_enchantability(itemname) > 0
|
return mcl_enchanting.get_enchantability(itemname) > 0 or mcl_enchanting.not_enchantable_on_enchanting_table(itemname)
|
||||||
end
|
end
|
||||||
|
|
||||||
function mcl_enchanting.can_enchant_freshly(itemname)
|
function mcl_enchanting.can_enchant_freshly(itemname)
|
||||||
|
@ -328,7 +332,7 @@ end
|
||||||
function mcl_enchanting.generate_random_enchantments(itemstack, enchantment_level, treasure, no_reduced_bonus_chance, ignore_already_enchanted, pr)
|
function mcl_enchanting.generate_random_enchantments(itemstack, enchantment_level, treasure, no_reduced_bonus_chance, ignore_already_enchanted, pr)
|
||||||
local itemname = itemstack:get_name()
|
local itemname = itemstack:get_name()
|
||||||
|
|
||||||
if not mcl_enchanting.can_enchant_freshly(itemname) and not ignore_already_enchanted then
|
if (not mcl_enchanting.can_enchant_freshly(itemname) and not ignore_already_enchanted) or mcl_enchanting.not_enchantable_on_enchanting_table(itemname) then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -454,7 +458,7 @@ function mcl_enchanting.generate_random_table_slots(itemstack, num_bookshelves)
|
||||||
end
|
end
|
||||||
|
|
||||||
function mcl_enchanting.get_table_slots(player, itemstack, num_bookshelves)
|
function mcl_enchanting.get_table_slots(player, itemstack, num_bookshelves)
|
||||||
if not mcl_enchanting.can_enchant_freshly(itemstack:get_name()) then
|
if (not mcl_enchanting.can_enchant_freshly(itemstack:get_name())) or mcl_enchanting.not_enchantable_on_enchanting_table(itemname) then
|
||||||
return {false, false, false}
|
return {false, false, false}
|
||||||
end
|
end
|
||||||
local itemname = itemstack:get_name()
|
local itemname = itemstack:get_name()
|
||||||
|
|
|
@ -106,7 +106,8 @@ minetest.register_node("mcl_nether:magma", {
|
||||||
sounds = mcl_sounds.node_sound_stone_defaults(),
|
sounds = mcl_sounds.node_sound_stone_defaults(),
|
||||||
-- From walkover mod
|
-- From walkover mod
|
||||||
on_walk_over = function(loc, nodeiamon, player)
|
on_walk_over = function(loc, nodeiamon, player)
|
||||||
if player and player:get_player_control().sneak or minetest.global_exists("mcl_potions") and mcl_potions.player_has_effect(player, "fire_proof") then
|
local armor_feet = player:get_inventory():get_stack("armor", 5)
|
||||||
|
if player and player:get_player_control().sneak or (minetest.global_exists("mcl_enchanting") and mcl_enchanting.has_enchantment(armor_feet, "frost_walker")) or (minetest.global_exists("mcl_potions") and mcl_potions.player_has_effect(player, "fire_proof")) then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
-- Hurt players standing on top of this block
|
-- Hurt players standing on top of this block
|
||||||
|
|
|
@ -204,37 +204,52 @@ local function get_target(p)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Destroy portal if pos (portal frame or portal node) got destroyed
|
-- Destroy a nether portal. Connected portal nodes are searched and removed
|
||||||
|
-- using 'bulk_set_node'. This function is called from 'after_destruct' of
|
||||||
|
-- nether portal nodes. The flag 'destroying_portal' is used to avoid this
|
||||||
|
-- function being called recursively through callbacks in 'bulk_set_node'.
|
||||||
|
local destroying_portal = false
|
||||||
local function destroy_nether_portal(pos, node)
|
local function destroy_nether_portal(pos, node)
|
||||||
if not node then return end
|
if destroying_portal then
|
||||||
local nn, orientation = node.name, node.param2
|
|
||||||
local obsidian = nn == OBSIDIAN
|
|
||||||
|
|
||||||
local function check_remove(pos, orientation)
|
|
||||||
local node = get_node(pos)
|
|
||||||
if node and (node.name == PORTAL and (orientation == nil or (node.param2 == orientation))) then
|
|
||||||
minetest.remove_node(pos)
|
|
||||||
remove_exit(pos)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if obsidian then -- check each of 6 sides of it and destroy every portal:
|
|
||||||
check_remove({x = pos.x - 1, y = pos.y, z = pos.z}, 0)
|
|
||||||
check_remove({x = pos.x + 1, y = pos.y, z = pos.z}, 0)
|
|
||||||
check_remove({x = pos.x, y = pos.y, z = pos.z - 1}, 1)
|
|
||||||
check_remove({x = pos.x, y = pos.y, z = pos.z + 1}, 1)
|
|
||||||
check_remove({x = pos.x, y = pos.y - 1, z = pos.z})
|
|
||||||
check_remove({x = pos.x, y = pos.y + 1, z = pos.z})
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
destroying_portal = true
|
||||||
|
|
||||||
|
local orientation = node.param2
|
||||||
|
local checked_tab = { [minetest.hash_node_position(pos)] = true }
|
||||||
|
local nodes = { pos }
|
||||||
|
|
||||||
|
local function check_remove(pos)
|
||||||
|
local h = minetest.hash_node_position(pos)
|
||||||
|
if checked_tab[h] then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local node = minetest.get_node(pos)
|
||||||
|
if node and node.name == PORTAL and (orientation == nil or node.param2 == orientation) then
|
||||||
|
table.insert(nodes, pos)
|
||||||
|
checked_tab[h] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local i = 1
|
||||||
|
while i <= #nodes do
|
||||||
|
pos = nodes[i]
|
||||||
if orientation == 0 then
|
if orientation == 0 then
|
||||||
check_remove({x = pos.x - 1, y = pos.y, z = pos.z}, 0)
|
check_remove({x = pos.x - 1, y = pos.y, z = pos.z})
|
||||||
check_remove({x = pos.x + 1, y = pos.y, z = pos.z}, 0)
|
check_remove({x = pos.x + 1, y = pos.y, z = pos.z})
|
||||||
else
|
else
|
||||||
check_remove({x = pos.x, y = pos.y, z = pos.z - 1}, 1)
|
check_remove({x = pos.x, y = pos.y, z = pos.z - 1})
|
||||||
check_remove({x = pos.x, y = pos.y, z = pos.z + 1}, 1)
|
check_remove({x = pos.x, y = pos.y, z = pos.z + 1})
|
||||||
end
|
end
|
||||||
check_remove({x = pos.x, y = pos.y - 1, z = pos.z})
|
check_remove({x = pos.x, y = pos.y - 1, z = pos.z})
|
||||||
check_remove({x = pos.x, y = pos.y + 1, z = pos.z})
|
check_remove({x = pos.x, y = pos.y + 1, z = pos.z})
|
||||||
|
remove_exit(pos)
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.bulk_set_node(nodes, { name = "air" })
|
||||||
|
destroying_portal = false
|
||||||
end
|
end
|
||||||
|
|
||||||
local on_rotate
|
local on_rotate
|
||||||
|
@ -817,7 +832,23 @@ local usagehelp = S("To open a Nether portal, place an upright frame of obsidian
|
||||||
minetest.override_item(OBSIDIAN, {
|
minetest.override_item(OBSIDIAN, {
|
||||||
_doc_items_longdesc = longdesc,
|
_doc_items_longdesc = longdesc,
|
||||||
_doc_items_usagehelp = usagehelp,
|
_doc_items_usagehelp = usagehelp,
|
||||||
after_destruct = destroy_nether_portal,
|
after_destruct = function(pos, node)
|
||||||
|
local function check_remove(pos, orientation)
|
||||||
|
local node = get_node(pos)
|
||||||
|
if node and node.name == PORTAL then
|
||||||
|
minetest.remove_node(pos)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- check each of 6 sides of it and destroy every portal
|
||||||
|
check_remove({x = pos.x - 1, y = pos.y, z = pos.z})
|
||||||
|
check_remove({x = pos.x + 1, y = pos.y, z = pos.z})
|
||||||
|
check_remove({x = pos.x, y = pos.y, z = pos.z - 1})
|
||||||
|
check_remove({x = pos.x, y = pos.y, z = pos.z + 1})
|
||||||
|
check_remove({x = pos.x, y = pos.y - 1, z = pos.z})
|
||||||
|
check_remove({x = pos.x, y = pos.y + 1, z = pos.z})
|
||||||
|
end,
|
||||||
|
|
||||||
_on_ignite = function(user, pointed_thing)
|
_on_ignite = function(user, pointed_thing)
|
||||||
local x, y, z = pointed_thing.under.x, pointed_thing.under.y, pointed_thing.under.z
|
local x, y, z = pointed_thing.under.x, pointed_thing.under.y, pointed_thing.under.z
|
||||||
-- Check empty spaces around obsidian and light all frames found:
|
-- Check empty spaces around obsidian and light all frames found:
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
local S = minetest.get_translator(minetest.get_current_modname())
|
local S = minetest.get_translator(minetest.get_current_modname())
|
||||||
|
|
||||||
|
local mod_target = minetest.get_modpath("mcl_target")
|
||||||
|
|
||||||
local function lingering_image(colorstring, opacity)
|
local function lingering_image(colorstring, opacity)
|
||||||
if not opacity then
|
if not opacity then
|
||||||
opacity = 127
|
opacity = 127
|
||||||
|
@ -125,11 +127,11 @@ function mcl_potions.register_lingering(name, descr, color, def)
|
||||||
obj:set_velocity({x=dropdir.x*velocity,y=dropdir.y*velocity,z=dropdir.z*velocity})
|
obj:set_velocity({x=dropdir.x*velocity,y=dropdir.y*velocity,z=dropdir.z*velocity})
|
||||||
obj:set_acceleration({x=dropdir.x*-3, y=-9.8, z=dropdir.z*-3})
|
obj:set_acceleration({x=dropdir.x*-3, y=-9.8, z=dropdir.z*-3})
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
local w = 0.7
|
local w = 0.7
|
||||||
|
|
||||||
minetest.register_entity(id.."_flying",{
|
minetest.register_entity(id.."_flying",{
|
||||||
textures = {lingering_image(color)},
|
textures = {lingering_image(color)},
|
||||||
hp_max = 1,
|
hp_max = 1,
|
||||||
visual_size = {x=w/2,y=w/2},
|
visual_size = {x=w/2,y=w/2},
|
||||||
|
@ -141,6 +143,9 @@ minetest.register_entity(id.."_flying",{
|
||||||
local n = node.name
|
local n = node.name
|
||||||
local g = minetest.get_item_group(n, "liquid")
|
local g = minetest.get_item_group(n, "liquid")
|
||||||
local d = 4
|
local d = 4
|
||||||
|
if mod_target and n == "mcl_target:target_off" then
|
||||||
|
mcl_target.hit(vector.round(pos), 0.4) --4 redstone ticks
|
||||||
|
end
|
||||||
if n ~= "air" and n ~= "mcl_portals:portal" and n ~= "mcl_portals:portal_end" and g == 0 or mcl_potions.is_obj_hit(self, pos) then
|
if n ~= "air" and n ~= "mcl_portals:portal" and n ~= "mcl_portals:portal_end" and g == 0 or mcl_potions.is_obj_hit(self, pos) then
|
||||||
minetest.sound_play("mcl_potions_breaking_glass", {pos = pos, max_hear_distance = 16, gain = 1})
|
minetest.sound_play("mcl_potions_breaking_glass", {pos = pos, max_hear_distance = 16, gain = 1})
|
||||||
add_lingering_effect(pos, color, def, name == "water")
|
add_lingering_effect(pos, color, def, name == "water")
|
||||||
|
@ -161,5 +166,5 @@ minetest.register_entity(id.."_flying",{
|
||||||
self.object:remove()
|
self.object:remove()
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
local S = minetest.get_translator(minetest.get_current_modname())
|
local S = minetest.get_translator(minetest.get_current_modname())
|
||||||
local GRAVITY = tonumber(minetest.settings:get("movement_gravity"))
|
local GRAVITY = tonumber(minetest.settings:get("movement_gravity"))
|
||||||
|
|
||||||
|
local mod_target = minetest.get_modpath("mcl_target")
|
||||||
|
|
||||||
local function splash_image(colorstring, opacity)
|
local function splash_image(colorstring, opacity)
|
||||||
if not opacity then
|
if not opacity then
|
||||||
opacity = 127
|
opacity = 127
|
||||||
|
@ -66,6 +68,9 @@ function mcl_potions.register_splash(name, descr, color, def)
|
||||||
local g = minetest.get_item_group(n, "liquid")
|
local g = minetest.get_item_group(n, "liquid")
|
||||||
local d = 0.1
|
local d = 0.1
|
||||||
local redux_map = {7/8,0.5,0.25}
|
local redux_map = {7/8,0.5,0.25}
|
||||||
|
if mod_target and n == "mcl_target:target_off" then
|
||||||
|
mcl_target.hit(vector.round(pos), 0.4) --4 redstone ticks
|
||||||
|
end
|
||||||
if n ~= "air" and n ~= "mcl_portals:portal" and n ~= "mcl_portals:portal_end" and g == 0 or mcl_potions.is_obj_hit(self, pos) then
|
if n ~= "air" and n ~= "mcl_portals:portal" and n ~= "mcl_portals:portal_end" and g == 0 or mcl_potions.is_obj_hit(self, pos) then
|
||||||
minetest.sound_play("mcl_potions_breaking_glass", {pos = pos, max_hear_distance = 16, gain = 1})
|
minetest.sound_play("mcl_potions_breaking_glass", {pos = pos, max_hear_distance = 16, gain = 1})
|
||||||
local texture, acc
|
local texture, acc
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
local S = minetest.get_translator(minetest.get_current_modname())
|
local S = minetest.get_translator(minetest.get_current_modname())
|
||||||
|
|
||||||
|
local mod_target = minetest.get_modpath("mcl_target")
|
||||||
|
|
||||||
local math = math
|
local math = math
|
||||||
|
|
||||||
-- Time in seconds after which a stuck arrow is deleted
|
-- Time in seconds after which a stuck arrow is deleted
|
||||||
|
@ -342,6 +344,11 @@ function mcl_potions.register_arrow(name, desc, color, def)
|
||||||
self.object:set_velocity({x=0, y=0, z=0})
|
self.object:set_velocity({x=0, y=0, z=0})
|
||||||
self.object:set_acceleration({x=0, y=0, z=0})
|
self.object:set_acceleration({x=0, y=0, z=0})
|
||||||
|
|
||||||
|
-- Activate target
|
||||||
|
if mod_target and snode.name == "mcl_target:target_off" then
|
||||||
|
mcl_target.hit(self._stuckin, 1) --10 redstone ticks
|
||||||
|
end
|
||||||
|
|
||||||
-- Push the button! Push, push, push the button!
|
-- Push the button! Push, push, push the button!
|
||||||
if mod_button and minetest.get_item_group(node.name, "button") > 0 and minetest.get_item_group(node.name, "button_push_by_arrow") == 1 then
|
if mod_button and minetest.get_item_group(node.name, "button") > 0 and minetest.get_item_group(node.name, "button_push_by_arrow") == 1 then
|
||||||
local bdir = minetest.wallmounted_to_dir(node.param2)
|
local bdir = minetest.wallmounted_to_dir(node.param2)
|
||||||
|
|
|
@ -0,0 +1,510 @@
|
||||||
|
local minetest, math, vector = minetest, math, vector
|
||||||
|
local modname = minetest.get_current_modname()
|
||||||
|
local S = minetest.get_translator(modname)
|
||||||
|
|
||||||
|
mcl_shields = {
|
||||||
|
types = {
|
||||||
|
mob = true,
|
||||||
|
player = true,
|
||||||
|
arrow = true,
|
||||||
|
generic = true,
|
||||||
|
explosion = true, -- ghasts don't work
|
||||||
|
dragon_breath = true,
|
||||||
|
},
|
||||||
|
enchantments = {"mending", "unbreaking"},
|
||||||
|
players = {},
|
||||||
|
}
|
||||||
|
|
||||||
|
local interact_priv = minetest.registered_privileges.interact
|
||||||
|
interact_priv.give_to_singleplayer = false
|
||||||
|
interact_priv.give_to_admin = false
|
||||||
|
|
||||||
|
local overlay = mcl_enchanting.overlay
|
||||||
|
local hud = "mcl_shield_hud.png"
|
||||||
|
|
||||||
|
minetest.register_tool("mcl_shields:shield", {
|
||||||
|
description = S("Shield"),
|
||||||
|
_doc_items_longdesc = S("A shield is a tool used for protecting the player against attacks."),
|
||||||
|
inventory_image = "mcl_shield.png",
|
||||||
|
stack_max = 1,
|
||||||
|
groups = {
|
||||||
|
shield = 1,
|
||||||
|
weapon = 1,
|
||||||
|
enchantability = -1,
|
||||||
|
no_wieldview = 1,
|
||||||
|
offhand_item = 1,
|
||||||
|
},
|
||||||
|
sound = {breaks = "default_tool_breaks"},
|
||||||
|
_repair_material = "group:wood",
|
||||||
|
wield_scale = vector.new(2, 2, 2),
|
||||||
|
})
|
||||||
|
|
||||||
|
local function wielded_item(obj, i)
|
||||||
|
local itemstack = obj:get_wielded_item()
|
||||||
|
if i == 1 then
|
||||||
|
itemstack = obj:get_inventory():get_stack("offhand", 1)
|
||||||
|
end
|
||||||
|
return itemstack:get_name()
|
||||||
|
end
|
||||||
|
|
||||||
|
function mcl_shields.wielding_shield(obj, i)
|
||||||
|
return wielded_item(obj, i):find("mcl_shields:shield")
|
||||||
|
end
|
||||||
|
|
||||||
|
local function shield_is_enchanted(obj, i)
|
||||||
|
return mcl_enchanting.is_enchanted(wielded_item(obj, i))
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.register_entity("mcl_shields:shield_entity", {
|
||||||
|
initial_properties = {
|
||||||
|
visual = "mesh",
|
||||||
|
mesh = "mcl_shield.obj",
|
||||||
|
physical = false,
|
||||||
|
pointable = false,
|
||||||
|
collide_with_objects = false,
|
||||||
|
textures = {"mcl_shield_base_nopattern.png"},
|
||||||
|
visual_size = vector.new(1, 1, 1),
|
||||||
|
},
|
||||||
|
_blocking = false,
|
||||||
|
_shield_number = 2,
|
||||||
|
_texture_copy = "",
|
||||||
|
on_step = function(self, dtime, moveresult)
|
||||||
|
local player = self.object:get_attach()
|
||||||
|
if not player then
|
||||||
|
self.object:remove()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local shield_texture = "mcl_shield_base_nopattern.png"
|
||||||
|
local i = self._shield_number
|
||||||
|
local item = wielded_item(player, i)
|
||||||
|
|
||||||
|
if item ~= "mcl_shields:shield" and item ~= "mcl_shields:shield_enchanted" then
|
||||||
|
local itemstack = player:get_wielded_item()
|
||||||
|
if i == 1 then
|
||||||
|
itemstack = player:get_inventory():get_stack("offhand", 1)
|
||||||
|
end
|
||||||
|
local meta_texture = itemstack:get_meta():get_string("mcl_shields:shield_custom_pattern_texture")
|
||||||
|
if meta_texture ~= "" then
|
||||||
|
shield_texture = meta_texture
|
||||||
|
else
|
||||||
|
local color = minetest.registered_items[item]._shield_color
|
||||||
|
if color then
|
||||||
|
shield_texture = "mcl_shield_base_nopattern.png^(mcl_shield_pattern_base.png^[colorize:" .. color .. ")"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if shield_is_enchanted(player, i) then
|
||||||
|
shield_texture = shield_texture .. overlay
|
||||||
|
end
|
||||||
|
|
||||||
|
if self._texture_copy ~= shield_texture then
|
||||||
|
self.object:set_properties({textures = {shield_texture}})
|
||||||
|
end
|
||||||
|
|
||||||
|
self._texture_copy = shield_texture
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
for _, e in pairs(mcl_shields.enchantments) do
|
||||||
|
mcl_enchanting.enchantments[e].secondary.shield = true
|
||||||
|
end
|
||||||
|
|
||||||
|
function mcl_shields.is_blocking(obj)
|
||||||
|
if not obj:is_player() then return end
|
||||||
|
local blocking = mcl_shields.players[obj].blocking
|
||||||
|
if blocking <= 0 then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local shieldstack = obj:get_wielded_item()
|
||||||
|
if blocking == 1 then
|
||||||
|
shieldstack = obj:get_inventory():get_stack("offhand", 1)
|
||||||
|
end
|
||||||
|
return blocking, shieldstack
|
||||||
|
end
|
||||||
|
|
||||||
|
mcl_damage.register_modifier(function(obj, damage, reason)
|
||||||
|
local type = reason.type
|
||||||
|
local damager = reason.direct
|
||||||
|
local blocking, shieldstack = mcl_shields.is_blocking(obj)
|
||||||
|
if not (obj:is_player() and blocking and mcl_shields.types[type] and damager) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local entity = damager:get_luaentity()
|
||||||
|
if entity and (type == "arrow" or type == "generic") then
|
||||||
|
damager = entity._shooter
|
||||||
|
end
|
||||||
|
|
||||||
|
if not damager then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if vector.dot(obj:get_look_dir(), vector.subtract(damager:get_pos(), obj:get_pos())) < 0 then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local durability = 336
|
||||||
|
local unbreaking = mcl_enchanting.get_enchantment(shieldstack, mcl_shields.enchantments[2])
|
||||||
|
if unbreaking > 0 then
|
||||||
|
durability = durability * (unbreaking + 1)
|
||||||
|
end
|
||||||
|
if not minetest.is_creative_enabled(obj:get_player_name()) and damage >= 3 then
|
||||||
|
shieldstack:add_wear(65535 / durability)
|
||||||
|
if blocking == 2 then
|
||||||
|
obj:set_wielded_item(shieldstack)
|
||||||
|
else
|
||||||
|
obj:get_inventory():set_stack("offhand", 1, shieldstack)
|
||||||
|
mcl_inventory.update_inventory_formspec(obj)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
minetest.sound_play({name = "mcl_block"})
|
||||||
|
return 0
|
||||||
|
end)
|
||||||
|
|
||||||
|
local function modify_shield(player, vpos, vrot, i)
|
||||||
|
local arm = "Right"
|
||||||
|
if i == 1 then
|
||||||
|
arm = "Left"
|
||||||
|
end
|
||||||
|
local shield = mcl_shields.players[player].shields[i]
|
||||||
|
if shield then
|
||||||
|
shield:set_attach(player, "Arm_" .. arm, vpos, vrot, false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function set_shield(player, block, i)
|
||||||
|
if block then
|
||||||
|
if i == 1 then
|
||||||
|
modify_shield(player, vector.new(-9, 4, 0.5), vector.new(80, 100, 0), i) -- TODO
|
||||||
|
else
|
||||||
|
modify_shield(player, vector.new(-8, 4, -2.5), vector.new(80, 80, 0), i)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if i == 1 then
|
||||||
|
modify_shield(player, vector.new(-3, -5, 0), vector.new(0, 180, 0), i)
|
||||||
|
else
|
||||||
|
modify_shield(player, vector.new(3, -5, 0), vector.new(0, 0, 0), i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local shield = mcl_shields.players[player].shields[i]
|
||||||
|
if not shield then return end
|
||||||
|
|
||||||
|
local luaentity = shield:get_luaentity()
|
||||||
|
if not luaentity then return end
|
||||||
|
|
||||||
|
luaentity._blocking = block
|
||||||
|
end
|
||||||
|
|
||||||
|
local function set_interact(player, interact)
|
||||||
|
local player_name = player:get_player_name()
|
||||||
|
local privs = minetest.get_player_privs(player_name)
|
||||||
|
if privs.interact == interact then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local meta = player:get_meta()
|
||||||
|
if meta:get_int("mcl_privs:interact_revoked") ~= 1 then
|
||||||
|
privs.interact = interact
|
||||||
|
minetest.set_player_privs(player_name, privs)
|
||||||
|
meta:set_int("mcl_privs:interact_revoked",0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local shield_hud = {}
|
||||||
|
|
||||||
|
local function remove_shield_hud(player)
|
||||||
|
if shield_hud[player] then
|
||||||
|
player:hud_remove(shield_hud[player])
|
||||||
|
shield_hud[player] = nil
|
||||||
|
set_shield(player, false, 1)
|
||||||
|
set_shield(player, false, 2)
|
||||||
|
end
|
||||||
|
|
||||||
|
local hf = player:hud_get_flags()
|
||||||
|
if not hf.wielditem then
|
||||||
|
player:hud_set_flags({wielditem = true})
|
||||||
|
end
|
||||||
|
|
||||||
|
playerphysics.remove_physics_factor(player, "speed", "shield_speed")
|
||||||
|
set_interact(player, true)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function add_shield_entity(player, i)
|
||||||
|
local shield = minetest.add_entity(player:get_pos(), "mcl_shields:shield_entity")
|
||||||
|
shield:get_luaentity()._shield_number = i
|
||||||
|
mcl_shields.players[player].shields[i] = shield
|
||||||
|
set_shield(player, false, i)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function remove_shield_entity(player, i)
|
||||||
|
local shields = mcl_shields.players[player].shields
|
||||||
|
if shields[i] then
|
||||||
|
shields[i]:remove()
|
||||||
|
shields[i] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function handle_blocking(player)
|
||||||
|
local player_shield = mcl_shields.players[player]
|
||||||
|
local rmb = player:get_player_control().RMB
|
||||||
|
if not rmb then
|
||||||
|
player_shield.blocking = 0
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local shield_in_offhand = mcl_shields.wielding_shield(player, 1)
|
||||||
|
local shield_in_hand = mcl_shields.wielding_shield(player)
|
||||||
|
local not_blocking = player_shield.blocking == 0
|
||||||
|
|
||||||
|
local pos = player:get_pos()
|
||||||
|
if shield_in_hand then
|
||||||
|
if not_blocking then
|
||||||
|
minetest.after(0.25, function()
|
||||||
|
if (not_blocking or not shield_in_offhand) and shield_in_hand and rmb then
|
||||||
|
player_shield.blocking = 2
|
||||||
|
set_shield(player, true, 2)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
elseif not shield_in_offhand then
|
||||||
|
player_shield.blocking = 2
|
||||||
|
end
|
||||||
|
elseif shield_in_offhand then
|
||||||
|
local offhand_can_block = (wielded_item(player) == "" or not mcl_util.get_pointed_thing(player, true))
|
||||||
|
and (minetest.get_item_group(wielded_item(player), "bow") ~= 1 and minetest.get_item_group(wielded_item(player), "crossbow") ~= 1)
|
||||||
|
|
||||||
|
if not offhand_can_block then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if not_blocking then
|
||||||
|
minetest.after(0.25, function()
|
||||||
|
if (not_blocking or not shield_in_hand) and shield_in_offhand and rmb and offhand_can_block then
|
||||||
|
player_shield.blocking = 1
|
||||||
|
set_shield(player, true, 1)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
elseif not shield_in_hand then
|
||||||
|
player_shield.blocking = 1
|
||||||
|
end
|
||||||
|
else
|
||||||
|
player_shield.blocking = 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function update_shield_entity(player, blocking, i)
|
||||||
|
local shield = mcl_shields.players[player].shields[i]
|
||||||
|
if mcl_shields.wielding_shield(player, i) then
|
||||||
|
if not shield then
|
||||||
|
add_shield_entity(player, i)
|
||||||
|
else
|
||||||
|
if blocking == i then
|
||||||
|
if shield:get_luaentity() and not shield:get_luaentity()._blocking then
|
||||||
|
set_shield(player, true, i)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
set_shield(player, false, i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif shield then
|
||||||
|
remove_shield_entity(player, i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function add_shield_hud(shieldstack, player, blocking)
|
||||||
|
local texture = hud
|
||||||
|
if mcl_enchanting.is_enchanted(shieldstack:get_name()) then
|
||||||
|
texture = texture .. overlay
|
||||||
|
end
|
||||||
|
local offset = 100
|
||||||
|
if blocking == 1 then
|
||||||
|
texture = texture .. "^[transform4"
|
||||||
|
offset = -100
|
||||||
|
else
|
||||||
|
player:hud_set_flags({wielditem = false})
|
||||||
|
end
|
||||||
|
shield_hud[player] = player:hud_add({
|
||||||
|
hud_elem_type = "image",
|
||||||
|
position = {x = 0.5, y = 0.5},
|
||||||
|
scale = {x = -101, y = -101},
|
||||||
|
offset = {x = offset, y = 0},
|
||||||
|
text = texture,
|
||||||
|
z_index = -200,
|
||||||
|
})
|
||||||
|
playerphysics.add_physics_factor(player, "speed", "shield_speed", 0.5)
|
||||||
|
set_interact(player, nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function update_shield_hud(player, blocking, shieldstack)
|
||||||
|
local shieldhud = shield_hud[player]
|
||||||
|
if not shieldhud then
|
||||||
|
add_shield_hud(shieldstack, player, blocking)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local wielditem = player:hud_get_flags().wielditem
|
||||||
|
if blocking == 1 then
|
||||||
|
if not wielditem then
|
||||||
|
player:hud_change(shieldhud, "text", hud .. "^[transform4")
|
||||||
|
player:hud_change(shieldhud, "offset", {x = -100, y = 0})
|
||||||
|
player:hud_set_flags({wielditem = true})
|
||||||
|
end
|
||||||
|
elseif wielditem then
|
||||||
|
player:hud_change(shieldhud, "text", hud)
|
||||||
|
player:hud_change(shieldhud, "offset", {x = 100, y = 0})
|
||||||
|
player:hud_set_flags({wielditem = false})
|
||||||
|
end
|
||||||
|
|
||||||
|
local image = player:hud_get(shieldhud).text
|
||||||
|
local enchanted = hud .. overlay
|
||||||
|
local enchanted1 = image == enchanted
|
||||||
|
local enchanted2 = image == enchanted .. "^[transform4"
|
||||||
|
if mcl_enchanting.is_enchanted(shieldstack:get_name()) then
|
||||||
|
if not enchanted1 and not enchanted2 then
|
||||||
|
if blocking == 1 then
|
||||||
|
player:hud_change(shieldhud, "text", hud .. overlay .. "^[transform4")
|
||||||
|
else
|
||||||
|
player:hud_change(shieldhud, "text", hud .. overlay)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif enchanted1 or enchanted2 then
|
||||||
|
if blocking == 1 then
|
||||||
|
player:hud_change(shieldhud, "text", hud .. "^[transform4")
|
||||||
|
else
|
||||||
|
player:hud_change(shieldhud, "text", hud)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.register_globalstep(function(dtime)
|
||||||
|
for _, player in pairs(minetest.get_connected_players()) do
|
||||||
|
|
||||||
|
handle_blocking(player)
|
||||||
|
|
||||||
|
local blocking, shieldstack = mcl_shields.is_blocking(player)
|
||||||
|
|
||||||
|
if blocking then
|
||||||
|
update_shield_hud(player, blocking, shieldstack)
|
||||||
|
else
|
||||||
|
remove_shield_hud(player)
|
||||||
|
end
|
||||||
|
|
||||||
|
for i = 1, 2 do
|
||||||
|
update_shield_entity(player, blocking, i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
minetest.register_on_dieplayer(function(player)
|
||||||
|
remove_shield_hud(player)
|
||||||
|
if not minetest.settings:get_bool("mcl_keepInventory") then
|
||||||
|
remove_shield_entity(player, 1)
|
||||||
|
remove_shield_entity(player, 2)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
minetest.register_on_leaveplayer(function(player)
|
||||||
|
shield_hud[player] = nil
|
||||||
|
mcl_shields.players[player] = nil
|
||||||
|
end)
|
||||||
|
|
||||||
|
minetest.register_craft({
|
||||||
|
output = "mcl_shields:shield",
|
||||||
|
recipe = {
|
||||||
|
{"group:wood", "mcl_core:iron_ingot", "group:wood"},
|
||||||
|
{"group:wood", "group:wood", "group:wood"},
|
||||||
|
{"", "group:wood", ""},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
for _, colortab in pairs(mcl_banners.colors) do
|
||||||
|
local color = colortab[1]
|
||||||
|
minetest.register_tool("mcl_shields:shield_" .. color, {
|
||||||
|
description = S(colortab[6] .. " Shield"),
|
||||||
|
_doc_items_longdesc = S("A shield is a tool used for protecting the player against attacks."),
|
||||||
|
inventory_image = "mcl_shield.png^(mcl_shield_item_overlay.png^[colorize:" .. colortab[4] ..")",
|
||||||
|
stack_max = 1,
|
||||||
|
groups = {
|
||||||
|
shield = 1,
|
||||||
|
weapon = 1,
|
||||||
|
enchantability = -1,
|
||||||
|
no_wieldview = 1,
|
||||||
|
not_in_creative_inventory = 1,
|
||||||
|
offhand_item = 1,
|
||||||
|
},
|
||||||
|
sound = {breaks = "default_tool_breaks"},
|
||||||
|
_repair_material = "group:wood",
|
||||||
|
wield_scale = vector.new(2, 2, 2),
|
||||||
|
_shield_color = colortab[4],
|
||||||
|
})
|
||||||
|
|
||||||
|
local banner = "mcl_banners:banner_item_" .. color
|
||||||
|
minetest.register_craft({
|
||||||
|
type = "shapeless",
|
||||||
|
output = "mcl_shields:shield_" .. color,
|
||||||
|
recipe = {"mcl_shields:shield", banner},
|
||||||
|
})
|
||||||
|
minetest.register_craft({
|
||||||
|
type = "shapeless",
|
||||||
|
output = "mcl_shields:shield_" .. color .. "_enchanted",
|
||||||
|
recipe = {"mcl_shields:shield_enchanted", banner},
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
local function to_shield_texture(banner_texture)
|
||||||
|
return banner_texture
|
||||||
|
:gsub("mcl_banners_base_inverted.png", "mcl_shield_base_nopattern.png^mcl_shield_pattern_base.png")
|
||||||
|
:gsub("mcl_banners_banner_base.png", "mcl_shield_base_nopattern.png^mcl_shield_pattern_base.png")
|
||||||
|
:gsub("mcl_banners_base", "mcl_shield_pattern_base")
|
||||||
|
:gsub("mcl_banners", "mcl_shield_pattern")
|
||||||
|
end
|
||||||
|
|
||||||
|
local function craft_banner_on_shield(itemstack, player, old_craft_grid, craft_inv)
|
||||||
|
if not string.find(itemstack:get_name(), "mcl_shields:shield_") then
|
||||||
|
return itemstack
|
||||||
|
end
|
||||||
|
|
||||||
|
local shield_stack
|
||||||
|
for i = 1, player:get_inventory():get_size("craft") do
|
||||||
|
local stack = old_craft_grid[i]
|
||||||
|
local name = stack:get_name()
|
||||||
|
if minetest.get_item_group(name, "shield") then
|
||||||
|
shield_stack = stack
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for i = 1, player:get_inventory():get_size("craft") do
|
||||||
|
local banner_stack = old_craft_grid[i]
|
||||||
|
local banner_name = banner_stack:get_name()
|
||||||
|
if string.find(banner_name, "mcl_banners:banner") and shield_stack then
|
||||||
|
local banner_meta = banner_stack:get_meta()
|
||||||
|
local layers_meta = banner_meta:get_string("layers")
|
||||||
|
local new_shield_meta = itemstack:get_meta()
|
||||||
|
if layers_meta ~= "" then
|
||||||
|
local color = mcl_banners.color_reverse(banner_name)
|
||||||
|
local layers = minetest.deserialize(layers_meta)
|
||||||
|
local texture = mcl_banners.make_banner_texture(color, layers)
|
||||||
|
new_shield_meta:set_string("description", mcl_banners.make_advanced_banner_description(itemstack:get_description(), layers))
|
||||||
|
new_shield_meta:set_string("mcl_shields:shield_custom_pattern_texture", to_shield_texture(texture))
|
||||||
|
end
|
||||||
|
itemstack:set_wear(shield_stack:get_wear())
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.register_craft_predict(function(itemstack, player, old_craft_grid, craft_inv)
|
||||||
|
return craft_banner_on_shield(itemstack, player, old_craft_grid, craft_inv)
|
||||||
|
end)
|
||||||
|
|
||||||
|
minetest.register_on_craft(function(itemstack, player, old_craft_grid, craft_inv)
|
||||||
|
return craft_banner_on_shield(itemstack, player, old_craft_grid, craft_inv)
|
||||||
|
end)
|
||||||
|
|
||||||
|
minetest.register_on_joinplayer(function(player)
|
||||||
|
mcl_shields.players[player] = {
|
||||||
|
shields = {},
|
||||||
|
blocking = 0,
|
||||||
|
}
|
||||||
|
remove_shield_hud(player)
|
||||||
|
end)
|
|
@ -0,0 +1,19 @@
|
||||||
|
# textdomain: mcl_shields
|
||||||
|
Shield=Schild
|
||||||
|
A shield is a tool used for protecting the player against attacks.=Der Schild ist eine Schutzwaffe, die den Spieler vor Angriffen schützt.
|
||||||
|
White Shield=Weißer Schild
|
||||||
|
Grey Shield=Grauer Schild
|
||||||
|
Light Grey Shield=Hellgrauer Schild
|
||||||
|
Black Shield=Schwarzer Schild
|
||||||
|
Red Shield=Roter Schild
|
||||||
|
Yellow Shield=Gelber Schild
|
||||||
|
Green Shield=Grüner Schild
|
||||||
|
Cyan Shield=Türkiser Schild
|
||||||
|
Blue Shield=Blauer Schild
|
||||||
|
Magenta Shield=Magenta Schild
|
||||||
|
Orange Shield=Oranger Schild
|
||||||
|
Purple Shield=Violetter Schild
|
||||||
|
Brown Shield=Brauner Schild
|
||||||
|
Pink Shield=Rosa Schild
|
||||||
|
Lime Shield=Hellgrüner Schild
|
||||||
|
Light Blue Shield=Hellblauer Schild
|
|
@ -0,0 +1,19 @@
|
||||||
|
# textdomain: mcl_shields
|
||||||
|
Shield=
|
||||||
|
A shield is a tool used for protecting the player against attacks.=
|
||||||
|
White Shield=
|
||||||
|
Grey Shield=
|
||||||
|
Light Grey Shield=
|
||||||
|
Black Shield=
|
||||||
|
Red Shield=
|
||||||
|
Yellow Shield=
|
||||||
|
Green Shield=
|
||||||
|
Cyan Shield=
|
||||||
|
Blue Shield=
|
||||||
|
Magenta Shield=
|
||||||
|
Orange Shield=
|
||||||
|
Purple Shield=
|
||||||
|
Brown Shield=
|
||||||
|
Pink Shield=
|
||||||
|
Lime Shield=
|
||||||
|
Light Blue Shield=
|
|
@ -0,0 +1,3 @@
|
||||||
|
name = mcl_shields
|
||||||
|
author = NO11
|
||||||
|
depends = mcl_damage, mcl_enchanting, mcl_banners, mcl_util, playerphysics
|
|
@ -0,0 +1,88 @@
|
||||||
|
# Blender v3.0.0 OBJ File: ''
|
||||||
|
# www.blender.org
|
||||||
|
mtllib mcl_shield.mtl
|
||||||
|
o Cube.002_Cube.003
|
||||||
|
v 4.663009 11.096291 6.387994
|
||||||
|
v 4.663009 4.596560 5.241916
|
||||||
|
v 5.213008 4.596560 5.241916
|
||||||
|
v 5.213008 11.096291 6.387994
|
||||||
|
v 5.213007 13.197435 -5.528180
|
||||||
|
v 5.213007 6.697705 -6.674258
|
||||||
|
v 4.663008 6.697705 -6.674258
|
||||||
|
v 4.663008 13.197435 -5.528180
|
||||||
|
v 4.663008 8.641873 -1.863572
|
||||||
|
v 4.663008 8.068833 1.386293
|
||||||
|
v 1.363008 8.068833 1.386294
|
||||||
|
v 1.363008 8.641873 -1.863572
|
||||||
|
v 1.363008 9.152122 1.577307
|
||||||
|
v 1.363008 9.725162 -1.672559
|
||||||
|
v 4.663008 9.152122 1.577306
|
||||||
|
v 4.663008 9.725162 -1.672559
|
||||||
|
vt 0.015625 0.984375
|
||||||
|
vt 0.203125 0.984375
|
||||||
|
vt 0.203125 1.000000
|
||||||
|
vt 0.015625 1.000000
|
||||||
|
vt 0.203125 0.640625
|
||||||
|
vt 0.203125 0.984375
|
||||||
|
vt 0.015625 0.984375
|
||||||
|
vt 0.015625 0.640625
|
||||||
|
vt 0.015625 0.984375
|
||||||
|
vt 0.015625 0.640625
|
||||||
|
vt -0.000000 0.640625
|
||||||
|
vt -0.000000 0.984375
|
||||||
|
vt 0.203125 0.984375
|
||||||
|
vt 0.390625 0.984375
|
||||||
|
vt 0.390625 1.000000
|
||||||
|
vt 0.203125 1.000000
|
||||||
|
vt 0.203125 0.984375
|
||||||
|
vt 0.203125 0.640625
|
||||||
|
vt 0.218750 0.640625
|
||||||
|
vt 0.218750 0.984375
|
||||||
|
vt 0.406250 0.640625
|
||||||
|
vt 0.406250 0.984375
|
||||||
|
vt 0.218750 0.984375
|
||||||
|
vt 0.218750 0.640625
|
||||||
|
vt 0.531250 0.812500
|
||||||
|
vt 0.625000 0.812500
|
||||||
|
vt 0.625000 0.906250
|
||||||
|
vt 0.531250 0.906250
|
||||||
|
vt 0.500000 0.906250
|
||||||
|
vt 0.500000 0.812500
|
||||||
|
vt 0.531250 0.812500
|
||||||
|
vt 0.531250 0.906250
|
||||||
|
vt 0.406250 0.812500
|
||||||
|
vt 0.500000 0.812500
|
||||||
|
vt 0.500000 0.906250
|
||||||
|
vt 0.406250 0.906250
|
||||||
|
vt 0.625000 0.812500
|
||||||
|
vt 0.656250 0.812500
|
||||||
|
vt 0.656250 0.906250
|
||||||
|
vt 0.625000 0.906250
|
||||||
|
vt 0.562500 1.000000
|
||||||
|
vt 0.531250 1.000000
|
||||||
|
vt 0.531250 0.906250
|
||||||
|
vt 0.562500 0.906250
|
||||||
|
vt 0.531250 1.000000
|
||||||
|
vt 0.500000 1.000000
|
||||||
|
vt 0.500000 0.906250
|
||||||
|
vt 0.531250 0.906250
|
||||||
|
vn 0.0000 -0.1736 0.9848
|
||||||
|
vn 1.0000 0.0000 -0.0000
|
||||||
|
vn 0.0000 -0.9848 -0.1736
|
||||||
|
vn 0.0000 0.1736 -0.9848
|
||||||
|
vn 0.0000 0.9848 0.1736
|
||||||
|
vn -1.0000 -0.0000 0.0000
|
||||||
|
usemtl Material.002
|
||||||
|
s 1
|
||||||
|
f 1/1/1 2/2/1 3/3/1 4/4/1
|
||||||
|
f 5/5/2 4/6/2 3/7/2 6/8/2
|
||||||
|
f 6/9/3 3/10/3 2/11/3 7/12/3
|
||||||
|
f 7/13/4 8/14/4 5/15/4 6/16/4
|
||||||
|
f 8/17/5 1/18/5 4/19/5 5/20/5
|
||||||
|
f 7/21/6 2/22/6 1/23/6 8/24/6
|
||||||
|
f 9/25/3 10/26/3 11/27/3 12/28/3
|
||||||
|
f 12/29/6 11/30/6 13/31/6 14/32/6
|
||||||
|
f 14/33/5 13/34/5 15/35/5 16/36/5
|
||||||
|
f 16/37/2 15/38/2 10/39/2 9/40/2
|
||||||
|
f 12/41/4 14/42/4 16/43/4 9/44/4
|
||||||
|
f 13/45/1 11/46/1 10/47/1 15/48/1
|
After Width: | Height: | Size: 5.5 KiB |
After Width: | Height: | Size: 5.3 KiB |
After Width: | Height: | Size: 639 KiB |
After Width: | Height: | Size: 3.4 KiB |
After Width: | Height: | Size: 878 B |
After Width: | Height: | Size: 4.6 KiB |
After Width: | Height: | Size: 6.6 KiB |
After Width: | Height: | Size: 4.2 KiB |
After Width: | Height: | Size: 4.6 KiB |
After Width: | Height: | Size: 5.6 KiB |
After Width: | Height: | Size: 6.0 KiB |
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 4.9 KiB |
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 4.9 KiB |
After Width: | Height: | Size: 5.9 KiB |
After Width: | Height: | Size: 5.6 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 4.4 KiB |
After Width: | Height: | Size: 5.7 KiB |
After Width: | Height: | Size: 5.2 KiB |
After Width: | Height: | Size: 3.9 KiB |
After Width: | Height: | Size: 3.9 KiB |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 4.5 KiB |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 4.1 KiB |
After Width: | Height: | Size: 5.4 KiB |
After Width: | Height: | Size: 5.2 KiB |
After Width: | Height: | Size: 3.9 KiB |
After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 3.9 KiB |