Remove most items
|
@ -1,173 +0,0 @@
|
|||
function mcl_burning.get_storage(obj)
|
||||
return obj:is_player() and mcl_burning.storage[obj] or obj:get_luaentity()
|
||||
end
|
||||
|
||||
function mcl_burning.is_burning(obj)
|
||||
return mcl_burning.get_storage(obj).burn_time
|
||||
end
|
||||
|
||||
function mcl_burning.is_affected_by_rain(obj)
|
||||
return mcl_weather.get_weather() == "rain" and mcl_weather.is_outdoor(obj:get_pos())
|
||||
end
|
||||
|
||||
function mcl_burning.get_collisionbox(obj, smaller, storage)
|
||||
local cache = storage.collisionbox_cache
|
||||
if cache then
|
||||
local box = cache[smaller and 2 or 1]
|
||||
return box[1], box[2]
|
||||
else
|
||||
local box = obj:get_properties().collisionbox
|
||||
local minp, maxp = vector.new(box[1], box[2], box[3]), vector.new(box[4], box[5], box[6])
|
||||
local s_vec = vector.new(0.1, 0.1, 0.1)
|
||||
local s_minp = vector.add(minp, s_vec)
|
||||
local s_maxp = vector.subtract(maxp, s_vec)
|
||||
storage.collisionbox_cache = {{minp, maxp}, {s_minp, s_maxp}}
|
||||
return minp, maxp
|
||||
end
|
||||
end
|
||||
|
||||
local find_nodes_in_area = minetest.find_nodes_in_area
|
||||
|
||||
function mcl_burning.get_touching_nodes(obj, nodenames, storage)
|
||||
local pos = obj:get_pos()
|
||||
local minp, maxp = mcl_burning.get_collisionbox(obj, true, storage)
|
||||
local nodes = find_nodes_in_area(vector.add(pos, minp), vector.add(pos, maxp), nodenames)
|
||||
return nodes
|
||||
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)
|
||||
if obj:get_hp() < 0 then
|
||||
return
|
||||
end
|
||||
|
||||
local luaentity = obj:get_luaentity()
|
||||
if luaentity and luaentity.fire_resistant then
|
||||
return
|
||||
end
|
||||
|
||||
if obj:is_player() and minetest.is_creative_enabled(obj:get_player_name()) then
|
||||
burn_time = 0
|
||||
else
|
||||
local max_fire_prot_lvl = 0
|
||||
local inv = mcl_util.get_inventory(obj)
|
||||
local armor_list = inv and inv:get_list("armor")
|
||||
|
||||
if armor_list then
|
||||
for _, stack in pairs(armor_list) do
|
||||
local fire_prot_lvl = mcl_enchanting.get_enchantment(stack, "fire_protection")
|
||||
if fire_prot_lvl > max_fire_prot_lvl then
|
||||
max_fire_prot_lvl = fire_prot_lvl
|
||||
end
|
||||
end
|
||||
end
|
||||
if max_fire_prot_lvl > 0 then
|
||||
burn_time = burn_time - math.floor(burn_time * max_fire_prot_lvl * 0.15)
|
||||
end
|
||||
end
|
||||
|
||||
local storage = mcl_burning.get_storage(obj)
|
||||
if storage.burn_time then
|
||||
if burn_time > storage.burn_time then
|
||||
storage.burn_time = burn_time
|
||||
end
|
||||
return
|
||||
end
|
||||
storage.burn_time = burn_time
|
||||
storage.fire_damage_timer = 0
|
||||
|
||||
local minp, maxp = mcl_burning.get_collisionbox(obj, false, storage)
|
||||
local size = vector.subtract(maxp, minp)
|
||||
size = vector.multiply(size, vector.new(1.1, 1.2, 1.1))
|
||||
size = vector.divide(size, obj:get_properties().visual_size)
|
||||
|
||||
local fire_entity = minetest.add_entity(obj:get_pos(), "mcl_burning:fire")
|
||||
fire_entity:set_properties({visual_size = size})
|
||||
fire_entity:set_attach(obj, "", vector.new(0, size.y * 5, 0), vector.new(0, 0, 0))
|
||||
|
||||
if obj:is_player() then
|
||||
mcl_burning.update_hud(obj)
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_burning.extinguish(obj)
|
||||
if not obj:get_pos() then return end
|
||||
if mcl_burning.is_burning(obj) then
|
||||
local storage = mcl_burning.get_storage(obj)
|
||||
if obj:is_player() then
|
||||
if storage.fire_hud_id then
|
||||
obj:hud_remove(storage.fire_hud_id)
|
||||
end
|
||||
mcl_burning.storage[obj] = {}
|
||||
else
|
||||
storage.burn_time = nil
|
||||
storage.fire_damage_timer = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_burning.tick(obj, dtime, storage)
|
||||
if storage.burn_time then
|
||||
storage.burn_time = storage.burn_time - dtime
|
||||
|
||||
if storage.burn_time <= 0 or mcl_burning.is_affected_by_rain(obj) or #mcl_burning.get_touching_nodes(obj, "group:puts_out_fire", storage) > 0 then
|
||||
mcl_burning.extinguish(obj)
|
||||
return true
|
||||
else
|
||||
storage.fire_damage_timer = storage.fire_damage_timer + dtime
|
||||
|
||||
if storage.fire_damage_timer >= 1 then
|
||||
storage.fire_damage_timer = 0
|
||||
|
||||
local luaentity = obj:get_luaentity()
|
||||
|
||||
if not luaentity or not luaentity.fire_damage_resistant then
|
||||
mcl_util.deal_damage(obj, 1, {type = "on_fire"})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,131 +0,0 @@
|
|||
local modpath = minetest.get_modpath(minetest.get_current_modname())
|
||||
|
||||
mcl_burning = {
|
||||
-- the storage table holds a list of objects (players,luaentities) and tables
|
||||
-- associated with these objects. These tables have the following attributes:
|
||||
-- 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")
|
||||
|
||||
local pairs = pairs
|
||||
local get_connected_players = minetest.get_connected_players
|
||||
local get_item_group = minetest.get_item_group
|
||||
|
||||
minetest.register_globalstep(function(dtime)
|
||||
for _, player in pairs(get_connected_players()) do
|
||||
local storage = mcl_burning.storage[player]
|
||||
if not mcl_burning.tick(player, dtime, storage) and not mcl_burning.is_affected_by_rain(player) then
|
||||
local nodes = mcl_burning.get_touching_nodes(player, {"group:puts_out_fire", "group:set_on_fire"}, storage)
|
||||
local burn_time = 0
|
||||
|
||||
for _, pos in pairs(nodes) do
|
||||
local node = minetest.get_node(pos)
|
||||
if get_item_group(node.name, "puts_out_fire") > 0 then
|
||||
burn_time = 0
|
||||
break
|
||||
end
|
||||
|
||||
local value = get_item_group(node.name, "set_on_fire")
|
||||
if value > burn_time then
|
||||
burn_time = value
|
||||
end
|
||||
end
|
||||
|
||||
if burn_time > 0 then
|
||||
mcl_burning.set_on_fire(player, burn_time)
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
minetest.register_on_respawnplayer(function(player)
|
||||
mcl_burning.extinguish(player)
|
||||
end)
|
||||
|
||||
minetest.register_on_joinplayer(function(player)
|
||||
local storage = {}
|
||||
local burn_data = player:get_meta():get_string("mcl_burning:data")
|
||||
if burn_data ~= "" then
|
||||
storage = minetest.deserialize(burn_data) or storage
|
||||
end
|
||||
mcl_burning.storage[player] = storage
|
||||
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]
|
||||
if not storage then
|
||||
-- For some unexplained reasons, mcl_burning.storage can be `nil` here.
|
||||
-- Logging this exception to assist in finding the cause of this.
|
||||
minetest.log("warning", "on_leaveplayer: missing mcl_burning.storage "
|
||||
.. "for player " .. player:get_player_name())
|
||||
storage = {}
|
||||
end
|
||||
storage.fire_hud_id = nil
|
||||
player:get_meta():set_string("mcl_burning:data", minetest.serialize(storage))
|
||||
mcl_burning.storage[player] = nil
|
||||
end
|
||||
|
||||
minetest.register_on_leaveplayer(function(player)
|
||||
on_leaveplayer(player)
|
||||
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", {
|
||||
initial_properties = {
|
||||
physical = false,
|
||||
collisionbox = {0, 0, 0, 0, 0, 0},
|
||||
visual = "upright_sprite",
|
||||
textures = {
|
||||
"mcl_burning_entity_flame_animated.png",
|
||||
"mcl_burning_entity_flame_animated.png"
|
||||
},
|
||||
spritediv = {x = 1, y = animation_frames},
|
||||
pointable = false,
|
||||
glow = -1,
|
||||
backface_culling = false,
|
||||
},
|
||||
_mcl_animation_timer = 0,
|
||||
on_activate = function(self)
|
||||
self.object:set_sprite({x = 0, y = 0}, animation_frames, 1.0 / animation_frames)
|
||||
end,
|
||||
on_step = function(self, dtime)
|
||||
local parent = self.object:get_attach()
|
||||
if not parent then
|
||||
self.object:remove()
|
||||
return
|
||||
end
|
||||
local storage = mcl_burning.get_storage(parent)
|
||||
if not storage or not storage.burn_time then
|
||||
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,
|
||||
})
|
|
@ -1,3 +0,0 @@
|
|||
name = mcl_burning
|
||||
description = Burning Objects for MineClone2
|
||||
author = Fleckenstein
|
|
@ -1,31 +0,0 @@
|
|||
# lightning
|
||||
Lightning mod for MineClone2 with the following API:
|
||||
|
||||
## lightning.register_on_strike(function(pos, pos2, objects))
|
||||
Custom function called when a lightning strikes.
|
||||
|
||||
* `pos`: impact position
|
||||
* `pos2`: rounded node position where fire is placed
|
||||
* `objects`: table with ObjectRefs of all objects within a radius of 3.5 around pos2
|
||||
|
||||
## lightning.strike(pos)
|
||||
Let a lightning strike.
|
||||
|
||||
* `pos`: optional, if not given a random pos will be chosen
|
||||
* `returns`: bool - success if a strike happened
|
||||
|
||||
|
||||
### Examples:
|
||||
|
||||
```
|
||||
lightning.register_on_strike(function(pos, pos2, objects)
|
||||
for _, obj in pairs(objects) do
|
||||
obj:remove()
|
||||
end
|
||||
minetest.add_entity(pos, "mobs_mc:sheep")
|
||||
end)
|
||||
|
||||
minetest.register_on_respawnplayer(function(player)
|
||||
lightning.strike(player:get_pos())
|
||||
end)
|
||||
```
|
|
@ -1,21 +0,0 @@
|
|||
|
||||
Lightning mod for minetest
|
||||
|
||||
|
||||
Copyright (C) 2016 - Auke Kok <sofar@foo-projects.org>
|
||||
|
||||
"lightning" is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1
|
||||
of the license, or (at your option) any later version.
|
||||
|
||||
|
||||
Textures: CC-BY-SA-4.0 by sofar
|
||||
lightning_1.png
|
||||
lightning_2.png
|
||||
lightning_3.png
|
||||
|
||||
Sounds:
|
||||
thunder.1.ogg - CC-BY-SA - hantorio - http://www.freesound.org/people/hantorio/sounds/121945/
|
||||
thunder.2.ogg - CC-BY-SA - juskiddink - http://www.freesound.org/people/juskiddink/sounds/101948/
|
||||
thunder.3.ogg - CC-BY-SA - IllusiaProductions - http://www.freesound.org/people/IllusiaProductions/sounds/249950/
|
|
@ -1,268 +0,0 @@
|
|||
--[[
|
||||
|
||||
Copyright (C) 2016 - Auke Kok <sofar@foo-projects.org>
|
||||
Adapted by MineClone2 contributors
|
||||
|
||||
"lightning" is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1
|
||||
of the license, or (at your option) any later version.
|
||||
|
||||
--]]
|
||||
|
||||
local S = minetest.get_translator(minetest.get_current_modname())
|
||||
|
||||
local get_connected_players = minetest.get_connected_players
|
||||
local line_of_sight = minetest.line_of_sight
|
||||
local get_node = minetest.get_node
|
||||
local set_node = minetest.set_node
|
||||
local sound_play = minetest.sound_play
|
||||
local add_particlespawner = minetest.add_particlespawner
|
||||
local after = minetest.after
|
||||
local add_entity = minetest.add_entity
|
||||
local get_objects_inside_radius = minetest.get_objects_inside_radius
|
||||
local get_item_group = minetest.get_item_group
|
||||
|
||||
lightning = {
|
||||
interval_low = 17,
|
||||
interval_high = 503,
|
||||
range_h = 100,
|
||||
range_v = 50,
|
||||
size = 100,
|
||||
-- disable this to stop lightning mod from striking
|
||||
auto = true,
|
||||
on_strike_functions = {},
|
||||
}
|
||||
|
||||
local rng = PcgRandom(32321123312123)
|
||||
|
||||
local ps = {}
|
||||
local ttl = -1
|
||||
|
||||
local function revertsky(dtime)
|
||||
if ttl == 0 then
|
||||
return
|
||||
end
|
||||
ttl = ttl - dtime
|
||||
if ttl > 0 then
|
||||
return
|
||||
end
|
||||
|
||||
mcl_weather.skycolor.remove_layer("lightning")
|
||||
|
||||
ps = {}
|
||||
end
|
||||
|
||||
minetest.register_globalstep(revertsky)
|
||||
|
||||
-- lightning strike API
|
||||
|
||||
-- See API.md
|
||||
--[[
|
||||
lightning.register_on_strike(function(pos, pos2, objects)
|
||||
-- code
|
||||
end)
|
||||
]]
|
||||
function lightning.register_on_strike(func)
|
||||
table.insert(lightning.on_strike_functions, func)
|
||||
end
|
||||
|
||||
-- select a random strike point, midpoint
|
||||
local function choose_pos(pos)
|
||||
if not pos then
|
||||
local playerlist = get_connected_players()
|
||||
local playercount = table.getn(playerlist)
|
||||
|
||||
-- nobody on
|
||||
if playercount == 0 then
|
||||
return nil, nil
|
||||
end
|
||||
|
||||
local r = rng:next(1, playercount)
|
||||
local randomplayer = playerlist[r]
|
||||
pos = randomplayer:get_pos()
|
||||
|
||||
-- avoid striking underground
|
||||
if pos.y < -20 then
|
||||
return nil, nil
|
||||
end
|
||||
|
||||
pos.x = math.floor(pos.x - (lightning.range_h / 2) + rng:next(1, lightning.range_h))
|
||||
pos.y = pos.y + (lightning.range_v / 2)
|
||||
pos.z = math.floor(pos.z - (lightning.range_h / 2) + rng:next(1, lightning.range_h))
|
||||
end
|
||||
|
||||
local b, pos2 = line_of_sight(pos, { x = pos.x, y = pos.y - lightning.range_v, z = pos.z }, 1)
|
||||
|
||||
-- nothing but air found
|
||||
if b then
|
||||
return nil, nil
|
||||
end
|
||||
|
||||
local n = get_node({ x = pos2.x, y = pos2.y - 1/2, z = pos2.z })
|
||||
if n.name == "air" or n.name == "ignore" then
|
||||
return nil, nil
|
||||
end
|
||||
|
||||
return pos, pos2
|
||||
end
|
||||
|
||||
-- * pos: optional, if not given a random pos will be chosen
|
||||
-- * returns: bool - success if a strike happened
|
||||
function lightning.strike(pos)
|
||||
if lightning.auto then
|
||||
after(rng:next(lightning.interval_low, lightning.interval_high), lightning.strike)
|
||||
end
|
||||
|
||||
local pos2
|
||||
pos, pos2 = choose_pos(pos)
|
||||
|
||||
if not pos then
|
||||
return false
|
||||
end
|
||||
local objects = get_objects_inside_radius(pos2, 3.5)
|
||||
if lightning.on_strike_functions then
|
||||
for _, func in pairs(lightning.on_strike_functions) do
|
||||
func(pos, pos2, objects)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
lightning.register_on_strike(function(pos, pos2, objects)
|
||||
local particle_pos = vector.offset(pos2, 0, (lightning.size / 2) + 0.5, 0)
|
||||
local particle_size = lightning.size * 10
|
||||
local time = 0.2
|
||||
add_particlespawner({
|
||||
amount = 1,
|
||||
time = time,
|
||||
-- make it hit the top of a block exactly with the bottom
|
||||
minpos = particle_pos,
|
||||
maxpos = particle_pos,
|
||||
minexptime = time,
|
||||
maxexptime = time,
|
||||
minsize = particle_size,
|
||||
maxsize = particle_size,
|
||||
collisiondetection = true,
|
||||
vertical = true,
|
||||
-- to make it appear hitting the node that will get set on fire, make sure
|
||||
-- to make the texture lightning bolt hit exactly in the middle of the
|
||||
-- texture (e.g. 127/128 on a 256x wide texture)
|
||||
texture = "lightning_lightning_" .. rng:next(1,3) .. ".png",
|
||||
glow = minetest.LIGHT_MAX,
|
||||
})
|
||||
|
||||
sound_play({ name = "lightning_thunder", gain = 10 }, { pos = pos, max_hear_distance = 500 }, true)
|
||||
|
||||
-- damage nearby objects, transform mobs
|
||||
for _, obj in pairs(objects) do
|
||||
local lua = obj:get_luaentity()
|
||||
if lua and lua._on_strike then
|
||||
lua._on_strike(lua, pos, pos2, objects)
|
||||
end
|
||||
-- remove this when mob API is done
|
||||
if lua and lua.name == "mobs_mc:pig" then
|
||||
mcl_util.replace_mob(obj, "mobs_mc:pigman")
|
||||
elseif lua and lua.name == "mobs_mc:mooshroom" then
|
||||
if lua.base_texture[1] == "mobs_mc_mooshroom.png" then
|
||||
lua.base_texture = { "mobs_mc_mooshroom_brown.png", "mobs_mc_mushroom_brown.png" }
|
||||
else
|
||||
lua.base_texture = { "mobs_mc_mooshroom.png", "mobs_mc_mushroom_red.png" }
|
||||
end
|
||||
obj:set_properties({ textures = lua.base_texture })
|
||||
elseif lua and lua.name == "mobs_mc:villager" then
|
||||
mcl_util.replace_mob(obj, "mobs_mc:witch")
|
||||
elseif lua and lua.name == "mobs_mc:creeper" then
|
||||
mcl_util.replace_mob(obj, "mobs_mc:creeper_charged")
|
||||
else
|
||||
mcl_util.deal_damage(obj, 5, { type = "lightning_bolt" })
|
||||
end
|
||||
end
|
||||
|
||||
local playerlist = get_connected_players()
|
||||
for i = 1, #playerlist do
|
||||
local player = playerlist[i]
|
||||
local sky = {}
|
||||
|
||||
sky.bgcolor, sky.type, sky.textures = player:get_sky()
|
||||
|
||||
local name = player:get_player_name()
|
||||
if ps[name] == nil then
|
||||
ps[name] = {p = player, sky = sky}
|
||||
mcl_weather.skycolor.add_layer("lightning", { { r = 255, g = 255, b = 255 } }, true)
|
||||
mcl_weather.skycolor.active = true
|
||||
end
|
||||
end
|
||||
|
||||
-- trigger revert of skybox
|
||||
ttl = 0.1
|
||||
|
||||
-- Events caused by the lightning strike: Fire, damage, mob transformations, rare skeleton spawn
|
||||
|
||||
pos2.y = pos2.y + 1/2
|
||||
local skeleton_lightning = false
|
||||
if rng:next(1,100) <= 3 then
|
||||
skeleton_lightning = true
|
||||
end
|
||||
if get_item_group(get_node({ x = pos2.x, y = pos2.y - 1, z = pos2.z }).name, "liquid") < 1 then
|
||||
if get_node(pos2).name == "air" then
|
||||
-- Low chance for a lightning to spawn skeleton horse + skeletons
|
||||
if skeleton_lightning then
|
||||
add_entity(pos2, "mobs_mc:skeleton_horse")
|
||||
|
||||
local angle, posadd
|
||||
angle = math.random(0, math.pi*2)
|
||||
for i=1,3 do
|
||||
posadd = { x=math.cos(angle),y=0,z=math.sin(angle) }
|
||||
posadd = vector.normalize(posadd)
|
||||
local mob = add_entity(vector.add(pos2, posadd), "mobs_mc:skeleton")
|
||||
if mob then
|
||||
mob:set_yaw(angle-math.pi/2)
|
||||
end
|
||||
angle = angle + (math.pi*2) / 3
|
||||
end
|
||||
|
||||
-- Cause a fire
|
||||
else
|
||||
set_node(pos2, { name = "mcl_fire:fire" })
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
-- if other mods disable auto lightning during initialization, don't trigger the first lightning.
|
||||
after(5, function(dtime)
|
||||
if lightning.auto then
|
||||
after(rng:next(lightning.interval_low,
|
||||
lightning.interval_high), lightning.strike)
|
||||
end
|
||||
end)
|
||||
|
||||
minetest.register_chatcommand("lightning", {
|
||||
params = "[<X> <Y> <Z>]",
|
||||
description = S("Let lightning strike at the specified position or yourself"),
|
||||
privs = { maphack = true },
|
||||
func = function(name, param)
|
||||
local pos = {}
|
||||
pos.x, pos.y, pos.z = string.match(param, "^([%d.-]+)[, ] *([%d.-]+)[, ] *([%d.-]+)$")
|
||||
pos.x = tonumber(pos.x)
|
||||
pos.y = tonumber(pos.y)
|
||||
pos.z = tonumber(pos.z)
|
||||
if not (pos.x and pos.y and pos.z) then
|
||||
pos = nil
|
||||
end
|
||||
if name == "" and pos == nil then
|
||||
return false, "No position specified and unknown player"
|
||||
end
|
||||
if pos then
|
||||
lightning.strike(pos)
|
||||
else
|
||||
local player = minetest.get_player_by_name(name)
|
||||
if player then
|
||||
lightning.strike(player:get_pos())
|
||||
else
|
||||
return false, S("No position specified and unknown player")
|
||||
end
|
||||
end
|
||||
return true
|
||||
end,
|
||||
})
|
|
@ -1,4 +0,0 @@
|
|||
# textdomain: lightning
|
||||
@1 was struck by lightning.=@1 wurde vom Blitz getroffen.
|
||||
Let lightning strike at the specified position or yourself=Lassen Sie einen Blitz an die gegebene Position oder auf sich selbst einschlagen.
|
||||
No position specified and unknown player=Keine Position angegeben und Spieler nicht bekannt
|
|
@ -1,4 +0,0 @@
|
|||
# textdomain: lightning
|
||||
@1 was struck by lightning.=@ 1 fue alcanzado por un rayo.
|
||||
Let lightning strike at the specified position or yourself=Deje que un rayo golpee en la posición especificada o sobre usted mismo.
|
||||
No position specified and unknown player=Ninguna posición especificada y jugador desconocido
|
|
@ -1,4 +0,0 @@
|
|||
# textdomain: lightning
|
||||
@1 was struck by lightning.=@1 a été frappé par la foudre.
|
||||
Let lightning strike at the specified position or yourself=Laissez la foudre frapper à la position spécifiée ou sur vous-même
|
||||
No position specified and unknown player=Aucune position spécifiée et joueur inconnu
|
|
@ -1,4 +0,0 @@
|
|||
# textdomain: lightning
|
||||
@1 was struck by lightning.=@1 została trafiona przez piorun.
|
||||
Let lightning strike at the specified position or yourself=Pozwala by piorun uderzył we wskazaną pozycję lub ciebie
|
||||
No position specified and unknown player=Nie wskazano pozycji i nieznany gracz
|
|
@ -1,4 +0,0 @@
|
|||
# textdomain: lightning
|
||||
@1 was struck by lightning.=@1 убило молнией.
|
||||
Let lightning strike at the specified position or yourself=Позволяет молнии бить в заданную позицию или в вас
|
||||
No position specified and unknown player=Позиция не задана и игрок неизвестен
|
|
@ -1,4 +0,0 @@
|
|||
# textdomain: lightning
|
||||
@1 was struck by lightning.=@1 被閃電擊斃。
|
||||
Let lightning strike at the specified position or yourself=讓閃電擊中指定位置或自己
|
||||
No position specified and unknown player=未指定位置且玩家未知
|
|
@ -1,4 +0,0 @@
|
|||
# textdomain: lightning
|
||||
@1 was struck by lightning.=
|
||||
Let lightning strike at the specified position or yourself=
|
||||
No position specified and unknown player=
|
|
@ -1,5 +0,0 @@
|
|||
name = lightning
|
||||
author = sofar
|
||||
description = A mod that adds thunder and lightning effects.
|
||||
depends = mcl_fire
|
||||
|
Before Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 3.9 KiB |
|
@ -1,47 +0,0 @@
|
|||
`mcl_weather`
|
||||
=======================
|
||||
Weather mod for MineClone 2. Forked from the `weather_pack` mod by xeranas.
|
||||
|
||||
Weathers included
|
||||
-----------------------
|
||||
* rain
|
||||
* snow
|
||||
* thunder
|
||||
|
||||
Commands
|
||||
-----------------------
|
||||
`weather <weather>`, requires `weather_manager` privilege.
|
||||
|
||||
Dependencies
|
||||
-----------------------
|
||||
Thunder weather requres [lightning](https://github.com/minetest-mods/lightning) mod.
|
||||
|
||||
Configuration prope, ties
|
||||
-----------------------
|
||||
Weather mod for indoor check depends on sunlight propogation check. Some nodes (e.g. glass block) propogates sunlight and thus weather particles will go through it. To change that set `weather_allow_override_nodes=true` in `minetest.conf` file. Be aware that just few nodes will be override and these blocks needs to be re-builded to take effect. Maybe in future other 'cheap' way to check indoor will be available.
|
||||
|
||||
Weather mod mostly relies on particles generation however for some small things ABM may be used. Users which do not want it can disable ABM with property `weather_allow_abm=false`.
|
||||
|
||||
License of source code:
|
||||
-----------------------
|
||||
LGPL 2.1+
|
||||
|
||||
Authors of media files:
|
||||
-----------------------
|
||||
|
||||
TeddyDesTodes:
|
||||
Snowflakes licensed under CC-BY-SA 3.0 by from weather branch at https://github.com/TeddyDesTodes/minetest/tree/weather
|
||||
|
||||
* `weather_pack_snow_snowflake1.png` - CC-BY-SA 3.0
|
||||
* `weather_pack_snow_snowflake2.png` - CC-BY-SA 3.0
|
||||
|
||||
xeranas:
|
||||
|
||||
* `weather_pack_rain_raindrop_1.png` - CC-0
|
||||
* `weather_pack_rain_raindrop_2.png` - CC-0
|
||||
* `weather_pack_rain_raindrop_3.png` - CC-0
|
||||
|
||||
inchadney (http://freesound.org/people/inchadney/):
|
||||
|
||||
* `weather_rain.ogg` - CC-BY-SA 3.0 (cut from http://freesound.org/people/inchadney/sounds/58835/)
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
local modpath = minetest.get_modpath(minetest.get_current_modname())
|
||||
|
||||
mcl_weather = {}
|
||||
|
||||
-- If not located then embeded skycolor mod version will be loaded.
|
||||
if minetest.get_modpath("skycolor") == nil then
|
||||
dofile(modpath.."/skycolor.lua")
|
||||
end
|
||||
|
||||
dofile(modpath.."/weather_core.lua")
|
||||
dofile(modpath.."/snow.lua")
|
||||
dofile(modpath.."/rain.lua")
|
||||
dofile(modpath.."/nether_dust.lua")
|
||||
|
||||
if minetest.get_modpath("lightning") then
|
||||
dofile(modpath.."/thunder.lua")
|
||||
end
|
|
@ -1,8 +0,0 @@
|
|||
# textdomain: mcl_weather
|
||||
Gives ability to control weather=Fähigkeit, das Wetter zu beeinflussen
|
||||
Changes the weather to the specified parameter.=Ändert das Wetter.
|
||||
Error: No weather specified.=Fehler: Kein Wetter angegeben.
|
||||
Error: Invalid parameters.=Fehler: Ungültige Parameter.
|
||||
Error: Duration can't be less than 1 second.=Fehler: Dauer darf nicht weniger als 1 Sekunde sein.
|
||||
Error: Invalid weather specified. Use “clear”, “rain”, “snow” or “thunder”.=Fehler. Ungültiges Wetter. Benutzen Sie „clear“ (klar), „rain“ (Regen), „snow“ (Schnee) oder „thunder“ (Gewittersturm).
|
||||
Toggles between clear weather and weather with downfall (randomly rain, thunderstorm or snow)=Wechselt das Wetter zwischem klaren Wetter und Wetter mit Niederschlag (zufällig Regen, Gewittersturm oder Schnee)
|
|
@ -1,8 +0,0 @@
|
|||
# textdomain: mcl_weather
|
||||
Gives ability to control weather=Da la capacidad de controlar el clima
|
||||
Changes the weather to the specified parameter.=Cambia el clima al parámetro especificado.
|
||||
Error: No weather specified.=Error: no se especificó el clima.
|
||||
Error: Invalid parameters.=Error: parámetros no válidos.
|
||||
Error: Duration can't be less than 1 second.=Error: la duración no puede ser inferior a 1 segundo.
|
||||
Error: Invalid weather specified. Use “clear”, “rain”, “snow” or “thunder”.=Error: tiempo especificado no válido. Utilice "clear", "rain", "snow" o "thunder".
|
||||
Toggles between clear weather and weather with downfall (randomly rain, thunderstorm or snow)=Alterna entre clima despejado y clima con caída (lluvia al azar, tormenta o nieve)
|
|
@ -1,8 +0,0 @@
|
|||
# textdomain: mcl_weather
|
||||
Gives ability to control weather=Donne la capacité de contrôler la météo
|
||||
Changes the weather to the specified parameter.=Modifie la météo au paramètre spécifié.
|
||||
Error: No weather specified.=Erreur: Aucune météo spécifiée.
|
||||
Error: Invalid parameters.=Erreur: Paramètres non valides.
|
||||
Error: Duration can't be less than 1 second.=Erreur: La durée ne peut pas être inférieure à 1 seconde.
|
||||
Error: Invalid weather specified. Use “clear”, “rain”, “snow” or “thunder”.=Erreur: Météo non valide spécifiée. Utilisez "clear" (clair), "rain" (pluie), "snow" (neige) ou "thunder" (tonnerre).
|
||||
Toggles between clear weather and weather with downfall (randomly rain, thunderstorm or snow)=Bascule entre temps clair et temps avec chute (au hasard entre pluie, orage ou neige)
|
|
@ -1,8 +0,0 @@
|
|||
# textdomain: mcl_weather
|
||||
Gives ability to control weather=Daje możliwość kontrolowania pogody
|
||||
Changes the weather to the specified parameter.=Zmienia pogodę na wskazany parametr
|
||||
Error: No weather specified.=Błąd: nie wskazano pogody.
|
||||
Error: Invalid parameters.=Błąd: nieprawidłowy parametr.
|
||||
Error: Duration can't be less than 1 second.=Błąd: Czas trwania nie może być mniejszy niż 1 sekunda.
|
||||
Error: Invalid weather specified. Use “clear”, “rain”, “snow” or “thunder”.=Błąd: wskazano nieprawidłową pogodę. Użyj "clear", "rain", "snow" lub "thunder".
|
||||
Toggles between clear weather and weather with downfall (randomly rain, thunderstorm or snow)=Zmienia pomiędzy czystą pogodą i pogodą z opadami (losowo deszcz, burza lub śnieg)
|
|
@ -1,9 +0,0 @@
|
|||
# textdomain: mcl_weather
|
||||
Gives ability to control weather=Предоставляет возможность управлять погодой
|
||||
Changes the weather to the specified parameter.=Меняет погоду на заданное значение.
|
||||
Error: No weather specified.=Ошибка: Не указана погода.
|
||||
Error: Invalid parameters.=Ошибка: Недопустимые параметры.
|
||||
Error: Duration can't be less than 1 second.=Ошибка: длительность не может быть менее 1 секунды.
|
||||
Error: Invalid weather specified. Use “clear”, “rain”, “snow” or “thunder”.=Ошибка: Указана неправильная погода. Возможны варианты: “clear” (ясная), “rain” (дождь), “snow” (снег) или “thunder” (гроза).
|
||||
Toggles between clear weather and weather with downfall (randomly rain, thunderstorm or snow)=Переключает между ясной погодой и осадками (случайно выбирается дождь, грозовой шторм или снег)
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
# textdomain: mcl_weather
|
||||
Gives ability to control weather=賦予控制天氣的能力
|
||||
Changes the weather to the specified parameter.=將天氣改為指定的參數。
|
||||
Error: No weather specified.=錯誤:未指定天氣。
|
||||
Error: Invalid parameters.=錯誤:無效參數。
|
||||
Error: Duration can't be less than 1 second.=錯誤:延續時間不可以短於1秒。
|
||||
Error: Invalid weather specified. Use “clear”, “rain”, “snow” or “thunder”.=錯誤:不明天氣。請使用「clear」、「rain」、「snow」或「thunder」。
|
||||
Toggles between clear weather and weather with downfall (randomly rain, thunderstorm or snow)=在晴朗的天氣和降雨天氣之間切換(隨機選擇雨、雷暴或雪)。
|
|
@ -1,8 +0,0 @@
|
|||
# textdomain: mcl_weather
|
||||
Gives ability to control weather=
|
||||
Changes the weather to the specified parameter.=
|
||||
Error: No weather specified.=
|
||||
Error: Invalid parameters.=
|
||||
Error: Duration can't be less than 1 second.=
|
||||
Error: Invalid weather specified. Use “clear”, “rain”, “snow” or “thunder”.=
|
||||
Toggles between clear weather and weather with downfall (randomly rain, thunderstorm or snow)=
|
|
@ -1,5 +0,0 @@
|
|||
name = mcl_weather
|
||||
author = xeranas
|
||||
description = Weather and sky handling: Rain, snow, thunderstorm, End and Nether ambience
|
||||
depends = mcl_init, mcl_worlds
|
||||
optional_depends = lightning
|
|
@ -1,66 +0,0 @@
|
|||
mcl_weather.nether_dust = {}
|
||||
mcl_weather.nether_dust.particlespawners = {}
|
||||
|
||||
local psdef= {
|
||||
amount = 150,
|
||||
time = 0,
|
||||
minpos = vector.new(-15,-15,-15),
|
||||
maxpos =vector.new(15,15,15),
|
||||
minvel = vector.new(-0.3,-0.15,-1),
|
||||
maxvel = vector.new(0.3,0.15,0.3),
|
||||
minacc = vector.new(-1,-0.4,-1),
|
||||
maxacc = vector.new(1,0.4,1),
|
||||
minexptime = 1,
|
||||
maxexptime = 10,
|
||||
minsize = 0.2,
|
||||
maxsize = 0.7,
|
||||
collisiondetection = false,
|
||||
collision_removal = false,
|
||||
object_collision = false,
|
||||
vertical = false
|
||||
}
|
||||
|
||||
local function check_player(player)
|
||||
local name=player:get_player_name()
|
||||
if mcl_worlds.has_dust(player:get_pos()) and not mcl_weather.nether_dust.particlespawners[name] then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
mcl_weather.nether_dust.add_particlespawners = function(player)
|
||||
local name=player:get_player_name()
|
||||
mcl_weather.nether_dust.particlespawners[name]={}
|
||||
psdef.playername = name
|
||||
psdef.attached = player
|
||||
psdef.glow = math.random(0,minetest.LIGHT_MAX)
|
||||
for i=1,3 do
|
||||
psdef.texture="mcl_particles_nether_dust"..i..".png"
|
||||
mcl_weather.nether_dust.particlespawners[name][i]=minetest.add_particlespawner(psdef)
|
||||
end
|
||||
end
|
||||
|
||||
mcl_weather.nether_dust.delete_particlespawners = function(player)
|
||||
local name=player:get_player_name()
|
||||
if mcl_weather.nether_dust.particlespawners[name] then
|
||||
for i=1,3 do
|
||||
minetest.delete_particlespawner(mcl_weather.nether_dust.particlespawners[name][i])
|
||||
end
|
||||
mcl_weather.nether_dust.particlespawners[name]=nil
|
||||
end
|
||||
end
|
||||
|
||||
mcl_worlds.register_on_dimension_change(function(player, dimension)
|
||||
if check_player(player) then
|
||||
return mcl_weather.nether_dust.add_particlespawners(player)
|
||||
end
|
||||
mcl_weather.nether_dust.delete_particlespawners(player)
|
||||
end)
|
||||
|
||||
minetest.register_on_joinplayer(function(player)
|
||||
if check_player(player) then
|
||||
mcl_weather.nether_dust.add_particlespawners(player)
|
||||
end
|
||||
end)
|
||||
minetest.register_on_leaveplayer(function(player)
|
||||
mcl_weather.nether_dust.delete_particlespawners(player)
|
||||
end)
|
|
@ -1,274 +0,0 @@
|
|||
local PARTICLES_COUNT_RAIN = 800
|
||||
local PARTICLES_COUNT_THUNDER = 1200
|
||||
|
||||
local get_connected_players = minetest.get_connected_players
|
||||
|
||||
mcl_weather.rain = {
|
||||
-- max rain particles created at time
|
||||
particles_count = PARTICLES_COUNT_RAIN,
|
||||
|
||||
-- flag to turn on/off extinguish fire for rain
|
||||
extinguish_fire = true,
|
||||
|
||||
-- flag useful when mixing weathers
|
||||
raining = false,
|
||||
|
||||
-- keeping last timeofday value (rounded).
|
||||
-- Defaulted to non-existing value for initial comparing.
|
||||
sky_last_update = -1,
|
||||
|
||||
init_done = false,
|
||||
}
|
||||
local update_sound={}
|
||||
local vel=math.random(0,3)
|
||||
local falling_speed=math.random(10,15)
|
||||
local size = math.random(1,3)
|
||||
local psdef= {
|
||||
amount = mcl_weather.rain.particles_count,
|
||||
time=0,
|
||||
minpos = vector.new(-15,20,-15),
|
||||
maxpos = vector.new(15,25,15),
|
||||
minvel = vector.new(-2,-falling_speed-2,-2),
|
||||
maxvel = vector.new(2,-falling_speed+2,2),
|
||||
minacc = vector.new(0,0,0),
|
||||
maxacc = vector.new(0,-0.5,0),
|
||||
minexptime = 15,
|
||||
maxexptime = 30,
|
||||
minsize = size,
|
||||
maxsize= size*2,
|
||||
collisiondetection = true,
|
||||
collision_removal = true,
|
||||
vertical = true,
|
||||
}
|
||||
|
||||
local textures = {"weather_pack_rain_raindrop_1.png", "weather_pack_rain_raindrop_2.png"}
|
||||
|
||||
function mcl_weather.rain.sound_handler(player)
|
||||
return minetest.sound_play("weather_rain", {
|
||||
to_player = player:get_player_name(),
|
||||
loop = true,
|
||||
})
|
||||
end
|
||||
|
||||
-- set skybox based on time (uses skycolor api)
|
||||
function mcl_weather.rain.set_sky_box()
|
||||
if mcl_weather.state == "rain" then
|
||||
mcl_weather.skycolor.add_layer(
|
||||
"weather-pack-rain-sky",
|
||||
{{r=0, g=0, b=0},
|
||||
{r=85, g=86, b=98},
|
||||
{r=135, g=135, b=151},
|
||||
{r=85, g=86, b=98},
|
||||
{r=0, g=0, b=0}})
|
||||
mcl_weather.skycolor.active = true
|
||||
for _, player in pairs(get_connected_players()) do
|
||||
player:set_clouds({color="#5D5D5FE8"})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- no no no NO NO f*.. no. no manual particle creatin' PLS!! this sends EVERY particle over the net.
|
||||
function mcl_weather.rain.add_rain_particles(player)
|
||||
mcl_weather.rain.last_rp_count = mcl_weather.rain.particles_count
|
||||
for k,v in pairs(textures) do
|
||||
psdef.texture=v
|
||||
mcl_weather.add_spawner_player(player,"rain"..k,psdef)
|
||||
end
|
||||
if l then
|
||||
update_sound[player:get_player_name()]=true
|
||||
end
|
||||
end
|
||||
|
||||
-- register player for rain weather.
|
||||
-- basically needs for origin sky reference and rain sound controls.
|
||||
function mcl_weather.rain.add_player(player)
|
||||
if mcl_weather.players[player:get_player_name()] == nil then
|
||||
local player_meta = {}
|
||||
player_meta.origin_sky = {player:get_sky()}
|
||||
mcl_weather.players[player:get_player_name()] = player_meta
|
||||
update_sound[player:get_player_name()]=true
|
||||
end
|
||||
end
|
||||
|
||||
-- remove player from player list effected by rain.
|
||||
-- be sure to remove sound before removing player otherwise soundhandler reference will be lost.
|
||||
function mcl_weather.rain.remove_player(player)
|
||||
local player_meta = mcl_weather.players[player:get_player_name()]
|
||||
if player_meta and player_meta.origin_sky then
|
||||
player:set_clouds({color="#FFF0F0E5"})
|
||||
mcl_weather.players[player:get_player_name()] = nil
|
||||
update_sound[player:get_player_name()]=true
|
||||
end
|
||||
end
|
||||
|
||||
-- adds and removes rain sound depending how much rain particles around player currently exist.
|
||||
-- have few seconds delay before each check to avoid on/off sound too often
|
||||
-- when player stay on 'edge' where sound should play and stop depending from random raindrop appearance.
|
||||
function mcl_weather.rain.update_sound(player)
|
||||
if not update_sound[player:get_player_name()] then return end
|
||||
local player_meta = mcl_weather.players[player:get_player_name()]
|
||||
if player_meta then
|
||||
if player_meta.sound_updated and player_meta.sound_updated + 5 > minetest.get_gametime() then
|
||||
return false
|
||||
end
|
||||
|
||||
if player_meta.sound_handler then
|
||||
if mcl_weather.rain.last_rp_count == 0 then
|
||||
minetest.sound_fade(player_meta.sound_handler, -0.5, 0.0)
|
||||
player_meta.sound_handler = nil
|
||||
end
|
||||
elseif mcl_weather.rain.last_rp_count > 0 then
|
||||
player_meta.sound_handler = mcl_weather.rain.sound_handler(player)
|
||||
end
|
||||
|
||||
player_meta.sound_updated = minetest.get_gametime()
|
||||
end
|
||||
update_sound[player:get_player_name()]=false
|
||||
end
|
||||
|
||||
-- rain sound removed from player.
|
||||
function mcl_weather.rain.remove_sound(player)
|
||||
local player_meta = mcl_weather.players[player:get_player_name()]
|
||||
if player_meta and player_meta.sound_handler then
|
||||
minetest.sound_fade(player_meta.sound_handler, -0.5, 0.0)
|
||||
player_meta.sound_handler = nil
|
||||
player_meta.sound_updated = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- callback function for removing rain
|
||||
function mcl_weather.rain.clear()
|
||||
mcl_weather.rain.raining = false
|
||||
mcl_weather.rain.sky_last_update = -1
|
||||
mcl_weather.rain.init_done = false
|
||||
mcl_weather.rain.set_particles_mode("rain")
|
||||
mcl_weather.skycolor.remove_layer("weather-pack-rain-sky")
|
||||
for _, player in pairs(get_connected_players()) do
|
||||
mcl_weather.rain.remove_sound(player)
|
||||
mcl_weather.rain.remove_player(player)
|
||||
mcl_weather.remove_spawners_player(player)
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_globalstep(function(dtime)
|
||||
if mcl_weather.state ~= "rain" then
|
||||
return false
|
||||
end
|
||||
mcl_weather.rain.make_weather()
|
||||
end)
|
||||
|
||||
function mcl_weather.rain.make_weather()
|
||||
if mcl_weather.rain.init_done == false then
|
||||
mcl_weather.rain.raining = true
|
||||
mcl_weather.rain.set_sky_box()
|
||||
mcl_weather.rain.set_particles_mode(mcl_weather.mode)
|
||||
mcl_weather.rain.init_done = true
|
||||
end
|
||||
|
||||
for _, player in pairs(get_connected_players()) do
|
||||
local pos=player:get_pos()
|
||||
if mcl_weather.is_underwater(player) or not mcl_worlds.has_weather(pos) then
|
||||
mcl_weather.rain.remove_sound(player)
|
||||
mcl_weather.remove_spawners_player(player)
|
||||
else
|
||||
mcl_weather.rain.add_player(player)
|
||||
mcl_weather.rain.add_rain_particles(player)
|
||||
mcl_weather.rain.update_sound(player)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Switch the number of raindrops: "thunder" for many raindrops, otherwise for normal raindrops
|
||||
function mcl_weather.rain.set_particles_mode(mode)
|
||||
if mode == "thunder" then
|
||||
psdef.amount=PARTICLES_COUNT_THUNDER
|
||||
mcl_weather.rain.particles_count = PARTICLES_COUNT_THUNDER
|
||||
else
|
||||
psdef.amount=PARTICLES_COUNT_RAIN
|
||||
mcl_weather.rain.particles_count = PARTICLES_COUNT_RAIN
|
||||
end
|
||||
end
|
||||
|
||||
if mcl_weather.allow_abm then
|
||||
-- ABM for extinguish fire
|
||||
minetest.register_abm({
|
||||
label = "Rain extinguishes fire",
|
||||
nodenames = {"mcl_fire:fire"},
|
||||
interval = 2.0,
|
||||
chance = 2,
|
||||
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||
-- Fire is extinguished if in rain or one of 4 neighbors is in rain
|
||||
if mcl_weather.rain.raining and mcl_weather.rain.extinguish_fire then
|
||||
local around = {
|
||||
{ x = 0, y = 0, z = 0 },
|
||||
{ x = -1, y = 0, z = 0 },
|
||||
{ x = 1, y = 0, z = 0 },
|
||||
{ x = 0, y = 0, z = -1 },
|
||||
{ x = 0, y = 0, z = 1 },
|
||||
}
|
||||
for a=1, #around do
|
||||
local apos = vector.add(pos, around[a])
|
||||
if mcl_weather.is_outdoor(apos) then
|
||||
minetest.remove_node(pos)
|
||||
minetest.sound_play("fire_extinguish_flame", {pos = pos, max_hear_distance = 8, gain = 0.1}, true)
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
-- Slowly fill up cauldrons
|
||||
minetest.register_abm({
|
||||
label = "Rain fills cauldrons with water",
|
||||
nodenames = {"mcl_cauldrons:cauldron", "mcl_cauldrons:cauldron_1", "mcl_cauldrons:cauldron_2"},
|
||||
interval = 56.0,
|
||||
chance = 1,
|
||||
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||
-- Rain is equivalent to a water bottle
|
||||
if mcl_weather.rain.raining and mcl_weather.is_outdoor(pos) then
|
||||
if node.name == "mcl_cauldrons:cauldron" then
|
||||
minetest.set_node(pos, {name="mcl_cauldrons:cauldron_1"})
|
||||
elseif node.name == "mcl_cauldrons:cauldron_1" then
|
||||
minetest.set_node(pos, {name="mcl_cauldrons:cauldron_2"})
|
||||
elseif node.name == "mcl_cauldrons:cauldron_2" then
|
||||
minetest.set_node(pos, {name="mcl_cauldrons:cauldron_3"})
|
||||
elseif node.name == "mcl_cauldrons:cauldron_1r" then
|
||||
minetest.set_node(pos, {name="mcl_cauldrons:cauldron_2r"})
|
||||
elseif node.name == "mcl_cauldrons:cauldron_2r" then
|
||||
minetest.set_node(pos, {name="mcl_cauldrons:cauldron_3r"})
|
||||
end
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
-- Wetten the soil
|
||||
minetest.register_abm({
|
||||
label = "Rain hydrates farmland",
|
||||
nodenames = {"mcl_farming:soil"},
|
||||
interval = 22.0,
|
||||
chance = 3,
|
||||
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||
if mcl_weather.rain.raining and mcl_weather.is_outdoor(pos) then
|
||||
if node.name == "mcl_farming:soil" then
|
||||
minetest.set_node(pos, {name="mcl_farming:soil_wet"})
|
||||
end
|
||||
end
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
if mcl_weather.reg_weathers.rain == nil then
|
||||
mcl_weather.reg_weathers.rain = {
|
||||
clear = mcl_weather.rain.clear,
|
||||
light_factor = 0.6,
|
||||
-- 10min - 20min
|
||||
min_duration = 600,
|
||||
max_duration = 1200,
|
||||
transitions = {
|
||||
[65] = "none",
|
||||
[70] = "snow",
|
||||
[100] = "thunder",
|
||||
}
|
||||
}
|
||||
end
|
|
@ -1,255 +0,0 @@
|
|||
local mods_loaded = false
|
||||
local NIGHT_VISION_RATIO = 0.45
|
||||
|
||||
mcl_weather.skycolor = {
|
||||
-- Should be activated before do any effect.
|
||||
active = true,
|
||||
|
||||
-- To skip update interval
|
||||
force_update = true,
|
||||
|
||||
-- Update interval.
|
||||
update_interval = 15,
|
||||
|
||||
-- Main sky colors: starts from midnight to midnight.
|
||||
-- Please do not set directly. Use add_layer instead.
|
||||
colors = {},
|
||||
|
||||
-- min value which will be used in color gradient, usualy its first user given color in 'pure' color.
|
||||
min_val = 0,
|
||||
|
||||
-- number of colors while constructing gradient of user given colors
|
||||
max_val = 1000,
|
||||
|
||||
-- Table for tracking layer order
|
||||
layer_names = {},
|
||||
|
||||
-- To layer to colors table
|
||||
add_layer = function(layer_name, layer_color, instant_update)
|
||||
mcl_weather.skycolor.colors[layer_name] = layer_color
|
||||
table.insert(mcl_weather.skycolor.layer_names, layer_name)
|
||||
mcl_weather.skycolor.force_update = true
|
||||
end,
|
||||
|
||||
current_layer_name = function()
|
||||
return mcl_weather.skycolor.layer_names[#mcl_weather.skycolor.layer_names]
|
||||
end,
|
||||
|
||||
-- Retrieve layer from colors table
|
||||
retrieve_layer = function()
|
||||
local last_layer = mcl_weather.skycolor.current_layer_name()
|
||||
return mcl_weather.skycolor.colors[last_layer]
|
||||
end,
|
||||
|
||||
-- Remove layer from colors table
|
||||
remove_layer = function(layer_name)
|
||||
for k, name in pairs(mcl_weather.skycolor.layer_names) do
|
||||
if name == layer_name then
|
||||
table.remove(mcl_weather.skycolor.layer_names, k)
|
||||
mcl_weather.skycolor.force_update = true
|
||||
return
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
-- Wrapper for updating day/night ratio that respects night vision
|
||||
override_day_night_ratio = function(player, ratio)
|
||||
local meta = player:get_meta()
|
||||
local has_night_vision = meta:get_int("night_vision") == 1
|
||||
local arg
|
||||
-- Apply night vision only for dark sky
|
||||
local is_dark = minetest.get_timeofday() > 0.8 or minetest.get_timeofday() < 0.2 or mcl_weather.state ~= "none"
|
||||
local pos = player:get_pos()
|
||||
local dim = mcl_worlds.pos_to_dimension(pos)
|
||||
if has_night_vision and is_dark and dim ~= "nether" and dim ~= "end" then
|
||||
if ratio == nil then
|
||||
arg = NIGHT_VISION_RATIO
|
||||
else
|
||||
arg = math.max(ratio, NIGHT_VISION_RATIO)
|
||||
end
|
||||
else
|
||||
arg = ratio
|
||||
end
|
||||
player:override_day_night_ratio(arg)
|
||||
end,
|
||||
|
||||
-- Update sky color. If players not specified update sky for all players.
|
||||
update_sky_color = function(players)
|
||||
-- Override day/night ratio as well
|
||||
players = mcl_weather.skycolor.utils.get_players(players)
|
||||
for _, player in ipairs(players) do
|
||||
local pos = player:get_pos()
|
||||
local dim = mcl_worlds.pos_to_dimension(pos)
|
||||
if dim == "overworld" then
|
||||
if (mcl_weather.state == "none") then
|
||||
-- Clear weather
|
||||
player:set_sky({
|
||||
type = "regular",
|
||||
sky_color = {
|
||||
day_sky = "#92B9FF",
|
||||
day_horizon = "#B4D0FF",
|
||||
dawn_sky = "#B4BAFA",
|
||||
dawn_horizon = "#BAC1F0",
|
||||
night_sky = "#006AFF",
|
||||
night_horizon = "#4090FF",
|
||||
},
|
||||
clouds = true,
|
||||
})
|
||||
player:set_sun({visible = true, sunrise_visible = true})
|
||||
player:set_moon({visible = true})
|
||||
player:set_stars({visible = true})
|
||||
mcl_weather.skycolor.override_day_night_ratio(player, nil)
|
||||
else
|
||||
-- Weather skies
|
||||
local day_color = mcl_weather.skycolor.get_sky_layer_color(0.5)
|
||||
local dawn_color = mcl_weather.skycolor.get_sky_layer_color(0.75)
|
||||
local night_color = mcl_weather.skycolor.get_sky_layer_color(0)
|
||||
player:set_sky({ type = "regular",
|
||||
sky_color = {
|
||||
day_sky = day_color,
|
||||
day_horizon = day_color,
|
||||
dawn_sky = dawn_color,
|
||||
dawn_horizon = dawn_color,
|
||||
night_sky = night_color,
|
||||
night_horizon = night_color,
|
||||
},
|
||||
clouds = true,
|
||||
})
|
||||
player:set_sun({visible = false, sunrise_visible = false})
|
||||
player:set_moon({visible = false})
|
||||
player:set_stars({visible = false})
|
||||
|
||||
local lf = mcl_weather.get_current_light_factor()
|
||||
if mcl_weather.skycolor.current_layer_name() == "lightning" then
|
||||
mcl_weather.skycolor.override_day_night_ratio(player, 1)
|
||||
elseif lf then
|
||||
local w = minetest.get_timeofday()
|
||||
local light = (w * (lf*2))
|
||||
if light > 1 then
|
||||
light = 1 - (light - 1)
|
||||
end
|
||||
light = (light * lf) + 0.15
|
||||
mcl_weather.skycolor.override_day_night_ratio(player, light)
|
||||
else
|
||||
mcl_weather.skycolor.override_day_night_ratio(player, nil)
|
||||
end
|
||||
end
|
||||
elseif dim == "end" then
|
||||
local t = "mcl_playerplus_end_sky.png"
|
||||
player:set_sky({ type = "skybox",
|
||||
base_color = "#000000",
|
||||
textures = {t,t,t,t,t,t},
|
||||
clouds = false,
|
||||
})
|
||||
player:set_sun({visible = false , sunrise_visible = false})
|
||||
player:set_moon({visible = false})
|
||||
player:set_stars({visible = false})
|
||||
mcl_weather.skycolor.override_day_night_ratio(player, 0.5)
|
||||
elseif dim == "nether" then
|
||||
player:set_sky({ type = "plain",
|
||||
base_color = "#300808",
|
||||
clouds = false,
|
||||
})
|
||||
player:set_sun({visible = false , sunrise_visible = false})
|
||||
player:set_moon({visible = false})
|
||||
player:set_stars({visible = false})
|
||||
mcl_weather.skycolor.override_day_night_ratio(player, nil)
|
||||
elseif dim == "void" then
|
||||
player:set_sky({ type = "plain",
|
||||
base_color = "#000000",
|
||||
clouds = false,
|
||||
})
|
||||
player:set_sun({visible = false, sunrise_visible = false})
|
||||
player:set_moon({visible = false})
|
||||
player:set_stars({visible = false})
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
-- Returns current layer color in {r, g, b} format
|
||||
get_sky_layer_color = function(timeofday)
|
||||
if #mcl_weather.skycolor.layer_names == 0 then
|
||||
return nil
|
||||
end
|
||||
|
||||
-- min timeofday value 0; max timeofday value 1. So sky color gradient range will be between 0 and 1 * mcl_weather.skycolor.max_val.
|
||||
local rounded_time = math.floor(timeofday * mcl_weather.skycolor.max_val)
|
||||
local color = mcl_weather.skycolor.utils.convert_to_rgb(mcl_weather.skycolor.min_val, mcl_weather.skycolor.max_val, rounded_time, mcl_weather.skycolor.retrieve_layer())
|
||||
return color
|
||||
end,
|
||||
|
||||
utils = {
|
||||
convert_to_rgb = function(minval, maxval, current_val, colors)
|
||||
local max_index = #colors - 1
|
||||
local val = (current_val-minval) / (maxval-minval) * max_index + 1.0
|
||||
local index1 = math.floor(val)
|
||||
local index2 = math.min(math.floor(val)+1, max_index + 1)
|
||||
local f = val - index1
|
||||
local c1 = colors[index1]
|
||||
local c2 = colors[index2]
|
||||
return {r=math.floor(c1.r + f*(c2.r - c1.r)), g=math.floor(c1.g + f*(c2.g-c1.g)), b=math.floor(c1.b + f*(c2.b - c1.b))}
|
||||
end,
|
||||
|
||||
-- Simply getter. Ether returns user given players list or get all connected players if none provided
|
||||
get_players = function(players)
|
||||
if players == nil or #players == 0 then
|
||||
if mods_loaded then
|
||||
players = minetest.get_connected_players()
|
||||
elseif players == nil then
|
||||
players = {}
|
||||
end
|
||||
end
|
||||
return players
|
||||
end,
|
||||
|
||||
-- Returns first player sky color. I assume that all players are in same color layout.
|
||||
get_current_bg_color = function()
|
||||
local players = mcl_weather.skycolor.utils.get_players(nil)
|
||||
if players[1] then
|
||||
return players[1]:get_sky()
|
||||
end
|
||||
return nil
|
||||
end
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
local timer = 0
|
||||
minetest.register_globalstep(function(dtime)
|
||||
if mcl_weather.skycolor.active ~= true or #minetest.get_connected_players() == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
if mcl_weather.skycolor.force_update then
|
||||
mcl_weather.skycolor.update_sky_color()
|
||||
mcl_weather.skycolor.force_update = false
|
||||
return
|
||||
end
|
||||
|
||||
-- regular updates based on iterval
|
||||
timer = timer + dtime;
|
||||
if timer >= mcl_weather.skycolor.update_interval then
|
||||
mcl_weather.skycolor.update_sky_color()
|
||||
timer = 0
|
||||
end
|
||||
|
||||
end)
|
||||
|
||||
local function initsky(player)
|
||||
if (mcl_weather.skycolor.active) then
|
||||
mcl_weather.skycolor.force_update = true
|
||||
end
|
||||
|
||||
player:set_clouds(mcl_worlds:get_cloud_parameters() or {height=mcl_worlds.layer_to_y(127), speed={x=-2, z=0}, thickness=4, color="#FFF0FEF"})
|
||||
end
|
||||
|
||||
minetest.register_on_joinplayer(initsky)
|
||||
minetest.register_on_respawnplayer(initsky)
|
||||
|
||||
mcl_worlds.register_on_dimension_change(function(player)
|
||||
mcl_weather.skycolor.update_sky_color({player})
|
||||
end)
|
||||
|
||||
minetest.register_on_mods_loaded(function()
|
||||
mods_loaded = true
|
||||
end)
|
|
@ -1,98 +0,0 @@
|
|||
local get_connected_players = minetest.get_connected_players
|
||||
|
||||
mcl_weather.snow = {}
|
||||
|
||||
mcl_weather.snow.particles_count = 15
|
||||
mcl_weather.snow.init_done = false
|
||||
|
||||
local psdef= {
|
||||
amount = 99,
|
||||
time = 0, --stay on til we turn it off
|
||||
minpos = vector.new(-25,20,-25),
|
||||
maxpos =vector.new(25,25,25),
|
||||
minvel = vector.new(-0.2,-1,-0.2),
|
||||
maxvel = vector.new(0.2,-4,0.2),
|
||||
minacc = vector.new(0,-1,0),
|
||||
maxacc = vector.new(0,-4,0),
|
||||
minexptime = 15,
|
||||
maxexptime = 30,
|
||||
minsize = 0.5,
|
||||
maxsize = 5,
|
||||
collisiondetection = true,
|
||||
collision_removal = true,
|
||||
object_collision = true,
|
||||
vertical = true,
|
||||
glow = 1
|
||||
}
|
||||
|
||||
function mcl_weather.snow.set_sky_box()
|
||||
mcl_weather.skycolor.add_layer(
|
||||
"weather-pack-snow-sky",
|
||||
{{r=0, g=0, b=0},
|
||||
{r=85, g=86, b=86},
|
||||
{r=135, g=135, b=135},
|
||||
{r=85, g=86, b=86},
|
||||
{r=0, g=0, b=0}})
|
||||
mcl_weather.skycolor.active = true
|
||||
for _, player in pairs(get_connected_players()) do
|
||||
player:set_clouds({color="#ADADADE8"})
|
||||
end
|
||||
mcl_weather.skycolor.active = true
|
||||
end
|
||||
|
||||
function mcl_weather.snow.clear()
|
||||
mcl_weather.skycolor.remove_layer("weather-pack-snow-sky")
|
||||
mcl_weather.snow.init_done = false
|
||||
mcl_weather.remove_all_spawners()
|
||||
end
|
||||
|
||||
-- Simple random texture getter
|
||||
function mcl_weather.snow.get_texture()
|
||||
return "weather_pack_snow_snowflake"..math.random(1,2)..".png"
|
||||
end
|
||||
|
||||
local timer = 0
|
||||
minetest.register_globalstep(function(dtime)
|
||||
if mcl_weather.state ~= "snow" then
|
||||
return false
|
||||
end
|
||||
|
||||
timer = timer + dtime;
|
||||
if timer >= 0.5 then
|
||||
timer = 0
|
||||
else
|
||||
return
|
||||
end
|
||||
|
||||
if mcl_weather.snow.init_done == false then
|
||||
mcl_weather.snow.set_sky_box()
|
||||
mcl_weather.snow.init_done = true
|
||||
end
|
||||
|
||||
for _, player in pairs(get_connected_players()) do
|
||||
if mcl_weather.is_underwater(player) or not mcl_worlds.has_weather(player:get_pos()) then
|
||||
mcl_weather.remove_spawners_player(player)
|
||||
else
|
||||
for i=1,2 do
|
||||
psdef.texture="weather_pack_snow_snowflake"..i..".png"
|
||||
mcl_weather.add_spawner_player(player,"snow"..i,psdef)
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
-- register snow weather
|
||||
if mcl_weather.reg_weathers.snow == nil then
|
||||
mcl_weather.reg_weathers.snow = {
|
||||
clear = mcl_weather.snow.clear,
|
||||
light_factor = 0.6,
|
||||
-- 10min - 20min
|
||||
min_duration = 600,
|
||||
max_duration = 1200,
|
||||
transitions = {
|
||||
[65] = "none",
|
||||
[80] = "rain",
|
||||
[100] = "thunder",
|
||||
}
|
||||
}
|
||||
end
|
Before Width: | Height: | Size: 99 B |
Before Width: | Height: | Size: 99 B |
Before Width: | Height: | Size: 101 B |
Before Width: | Height: | Size: 296 B |
Before Width: | Height: | Size: 209 B |
Before Width: | Height: | Size: 220 B |
Before Width: | Height: | Size: 192 B |
Before Width: | Height: | Size: 195 B |
|
@ -1,61 +0,0 @@
|
|||
local get_connected_players = minetest.get_connected_players
|
||||
|
||||
-- turn off lightning mod 'auto mode'
|
||||
lightning.auto = false
|
||||
|
||||
mcl_weather.thunder = {
|
||||
next_strike = 0,
|
||||
min_delay = 3,
|
||||
max_delay = 12,
|
||||
init_done = false,
|
||||
}
|
||||
|
||||
minetest.register_globalstep(function(dtime)
|
||||
if mcl_weather.get_weather() ~= "thunder" then
|
||||
return false
|
||||
end
|
||||
|
||||
mcl_weather.rain.set_particles_mode("thunder")
|
||||
mcl_weather.rain.make_weather()
|
||||
|
||||
if mcl_weather.thunder.init_done == false then
|
||||
mcl_weather.skycolor.add_layer("weather-pack-thunder-sky", {
|
||||
{r=0, g=0, b=0},
|
||||
{r=40, g=40, b=40},
|
||||
{r=85, g=86, b=86},
|
||||
{r=40, g=40, b=40},
|
||||
{r=0, g=0, b=0},
|
||||
})
|
||||
mcl_weather.skycolor.active = true
|
||||
for _, player in pairs(get_connected_players()) do
|
||||
player:set_clouds({color="#3D3D3FE8"})
|
||||
end
|
||||
mcl_weather.thunder.init_done = true
|
||||
end
|
||||
if (mcl_weather.thunder.next_strike <= minetest.get_gametime()) then
|
||||
lightning.strike()
|
||||
local delay = math.random(mcl_weather.thunder.min_delay, mcl_weather.thunder.max_delay)
|
||||
mcl_weather.thunder.next_strike = minetest.get_gametime() + delay
|
||||
end
|
||||
end)
|
||||
|
||||
function mcl_weather.thunder.clear()
|
||||
mcl_weather.rain.clear()
|
||||
mcl_weather.skycolor.remove_layer("weather-pack-thunder-sky")
|
||||
mcl_weather.skycolor.remove_layer("lightning")
|
||||
mcl_weather.thunder.init_done = false
|
||||
end
|
||||
|
||||
-- register thunderstorm weather
|
||||
if mcl_weather.reg_weathers.thunder == nil then
|
||||
mcl_weather.reg_weathers.thunder = {
|
||||
clear = mcl_weather.thunder.clear,
|
||||
light_factor = 0.33333,
|
||||
-- 10min - 20min
|
||||
min_duration = 600,
|
||||
max_duration = 1200,
|
||||
transitions = {
|
||||
[100] = "rain",
|
||||
},
|
||||
}
|
||||
end
|
|
@ -1,292 +0,0 @@
|
|||
local S = minetest.get_translator(minetest.get_current_modname())
|
||||
|
||||
local math = math
|
||||
|
||||
-- weather states, 'none' is default, other states depends from active mods
|
||||
mcl_weather.state = "none"
|
||||
|
||||
-- player list for saving player meta info
|
||||
mcl_weather.players = {}
|
||||
|
||||
-- default weather check interval for global step
|
||||
mcl_weather.check_interval = 5
|
||||
|
||||
-- weather min duration
|
||||
mcl_weather.min_duration = 600
|
||||
|
||||
-- weather max duration
|
||||
mcl_weather.max_duration = 9000
|
||||
|
||||
-- weather calculated end time
|
||||
mcl_weather.end_time = nil
|
||||
|
||||
-- registered weathers
|
||||
mcl_weather.reg_weathers = {}
|
||||
|
||||
-- global flag to disable/enable ABM logic.
|
||||
mcl_weather.allow_abm = true
|
||||
|
||||
mcl_weather.reg_weathers["none"] = {
|
||||
min_duration = mcl_weather.min_duration,
|
||||
max_duration = mcl_weather.max_duration,
|
||||
light_factor = nil,
|
||||
transitions = {
|
||||
[50] = "rain",
|
||||
[100] = "snow",
|
||||
},
|
||||
clear = function() end,
|
||||
}
|
||||
|
||||
local storage = minetest.get_mod_storage()
|
||||
-- Save weather into mod storage, so it can be loaded after restarting the server
|
||||
local function save_weather()
|
||||
if not mcl_weather.end_time then return end
|
||||
storage:set_string("mcl_weather_state", mcl_weather.state)
|
||||
storage:set_int("mcl_weather_end_time", mcl_weather.end_time)
|
||||
minetest.log("verbose", "[mcl_weather] Weather data saved: state="..mcl_weather.state.." end_time="..mcl_weather.end_time)
|
||||
end
|
||||
minetest.register_on_shutdown(save_weather)
|
||||
|
||||
local particlespawners={}
|
||||
function mcl_weather.add_spawner_player(pl,id,ps)
|
||||
local name=pl:get_player_name()
|
||||
if not particlespawners[name] then
|
||||
particlespawners[name] = {}
|
||||
end
|
||||
if not particlespawners[name][id] then
|
||||
ps.playername =name
|
||||
ps.attached = pl
|
||||
particlespawners[name][id]=minetest.add_particlespawner(ps)
|
||||
return particlespawners[name][id]
|
||||
end
|
||||
end
|
||||
function mcl_weather.remove_spawners_player(pl)
|
||||
local name=pl:get_player_name()
|
||||
if not particlespawners[name] then return end
|
||||
for k,v in pairs(particlespawners[name]) do
|
||||
minetest.delete_particlespawner(v)
|
||||
end
|
||||
particlespawners[name] = nil
|
||||
return true
|
||||
end
|
||||
|
||||
function mcl_weather.remove_all_spawners()
|
||||
for k,v in pairs(minetest.get_connected_players()) do
|
||||
mcl_weather.remove_spawners_player(v)
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_weather.get_rand_end_time(min_duration, max_duration)
|
||||
local r
|
||||
if min_duration and max_duration then
|
||||
r = math.random(min_duration, max_duration)
|
||||
else
|
||||
r = math.random(mcl_weather.min_duration, mcl_weather.max_duration)
|
||||
end
|
||||
return minetest.get_gametime() + r
|
||||
end
|
||||
|
||||
function mcl_weather.get_current_light_factor()
|
||||
if mcl_weather.state == "none" then
|
||||
return nil
|
||||
else
|
||||
return mcl_weather.reg_weathers[mcl_weather.state].light_factor
|
||||
end
|
||||
end
|
||||
|
||||
-- Returns true if pos is outdoor.
|
||||
-- Outdoor is defined as any node in the Overworld under open sky.
|
||||
-- FIXME: Nodes below glass also count as “outdoor”, this should not be the case.
|
||||
function mcl_weather.is_outdoor(pos)
|
||||
local cpos = {x=pos.x, y=pos.y+1, z=pos.z}
|
||||
local dim = mcl_worlds.pos_to_dimension(cpos)
|
||||
if minetest.get_node_light(cpos, 0.5) == 15 and dim == "overworld" then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- checks if player is undewater. This is needed in order to
|
||||
-- turn off weather particles generation.
|
||||
function mcl_weather.is_underwater(player)
|
||||
local ppos = player:get_pos()
|
||||
local offset = player:get_eye_offset()
|
||||
local player_eye_pos = {x = ppos.x + offset.x,
|
||||
y = ppos.y + offset.y + 1.5,
|
||||
z = ppos.z + offset.z}
|
||||
local node_level = minetest.get_node_level(player_eye_pos)
|
||||
if node_level == 8 or node_level == 7 then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local t, wci = 0, mcl_weather.check_interval
|
||||
|
||||
minetest.register_globalstep(function(dtime)
|
||||
t = t + dtime
|
||||
if t < wci then return end
|
||||
t = 0
|
||||
|
||||
if mcl_weather.end_time == nil then
|
||||
mcl_weather.end_time = mcl_weather.get_rand_end_time()
|
||||
end
|
||||
-- recalculate weather
|
||||
if mcl_weather.end_time <= minetest.get_gametime() then
|
||||
local changeWeather = minetest.settings:get_bool("mcl_doWeatherCycle")
|
||||
if changeWeather == nil then
|
||||
changeWeather = true
|
||||
end
|
||||
if changeWeather then
|
||||
mcl_weather.set_random_weather(mcl_weather.state, mcl_weather.reg_weathers[mcl_weather.state])
|
||||
else
|
||||
mcl_weather.end_time = mcl_weather.get_rand_end_time()
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
-- Sets random weather (which could be 'none' (no weather)).
|
||||
function mcl_weather.set_random_weather(weather_name, weather_meta)
|
||||
if weather_meta == nil then return end
|
||||
local transitions = weather_meta.transitions
|
||||
local random_roll = math.random(0,100)
|
||||
local new_weather
|
||||
for v, weather in pairs(transitions) do
|
||||
if random_roll < v then
|
||||
new_weather = weather
|
||||
break
|
||||
end
|
||||
end
|
||||
if new_weather then
|
||||
mcl_weather.change_weather(new_weather)
|
||||
end
|
||||
end
|
||||
|
||||
-- Change weather to new_weather.
|
||||
-- * explicit_end_time is OPTIONAL. If specified, explicitly set the
|
||||
-- gametime (minetest.get_gametime) in which the weather ends.
|
||||
-- * changer is OPTIONAL, for logging purposes.
|
||||
function mcl_weather.change_weather(new_weather, explicit_end_time, changer_name)
|
||||
local changer_name = changer_name or debug.getinfo(2).name.."()"
|
||||
|
||||
if (mcl_weather.reg_weathers and mcl_weather.reg_weathers[new_weather]) then
|
||||
if (mcl_weather.state and mcl_weather.reg_weathers[mcl_weather.state]) then
|
||||
mcl_weather.reg_weathers[mcl_weather.state].clear()
|
||||
end
|
||||
|
||||
local old_weather = mcl_weather.state
|
||||
|
||||
mcl_weather.state = new_weather
|
||||
|
||||
if old_weather == "none" then
|
||||
old_weather = "clear"
|
||||
end
|
||||
if new_weather == "none" then
|
||||
new_weather = "clear"
|
||||
end
|
||||
minetest.log("action", "[mcl_weather] " .. changer_name .. " changed the weather from " .. old_weather .. " to " .. new_weather)
|
||||
|
||||
local weather_meta = mcl_weather.reg_weathers[mcl_weather.state]
|
||||
if explicit_end_time then
|
||||
mcl_weather.end_time = explicit_end_time
|
||||
else
|
||||
mcl_weather.end_time = mcl_weather.get_rand_end_time(weather_meta.min_duration, weather_meta.max_duration)
|
||||
end
|
||||
mcl_weather.skycolor.update_sky_color()
|
||||
save_weather()
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function mcl_weather.get_weather()
|
||||
return mcl_weather.state
|
||||
end
|
||||
|
||||
minetest.register_privilege("weather_manager", {
|
||||
description = S("Gives ability to control weather"),
|
||||
give_to_singleplayer = false
|
||||
})
|
||||
|
||||
-- Weather command definition. Set
|
||||
minetest.register_chatcommand("weather", {
|
||||
params = "(clear | rain | snow | thunder) [<duration>]",
|
||||
description = S("Changes the weather to the specified parameter."),
|
||||
privs = {weather_manager = true},
|
||||
func = function(name, param)
|
||||
if (param == "") then
|
||||
return false, S("Error: No weather specified.")
|
||||
end
|
||||
local new_weather, end_time
|
||||
local parse1, parse2 = string.match(param, "(%w+) ?(%d*)")
|
||||
if parse1 then
|
||||
if parse1 == "clear" then
|
||||
new_weather = "none"
|
||||
else
|
||||
new_weather = parse1
|
||||
end
|
||||
else
|
||||
return false, S("Error: Invalid parameters.")
|
||||
end
|
||||
if parse2 then
|
||||
if type(tonumber(parse2)) == "number" then
|
||||
local duration = tonumber(parse2)
|
||||
if duration < 1 then
|
||||
return false, S("Error: Duration can't be less than 1 second.")
|
||||
end
|
||||
end_time = minetest.get_gametime() + duration
|
||||
end
|
||||
end
|
||||
|
||||
local success = mcl_weather.change_weather(new_weather, end_time, name)
|
||||
if success then
|
||||
return true
|
||||
else
|
||||
return false, S("Error: Invalid weather specified. Use “clear”, “rain”, “snow” or “thunder”.")
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("toggledownfall", {
|
||||
params = "",
|
||||
description = S("Toggles between clear weather and weather with downfall (randomly rain, thunderstorm or snow)"),
|
||||
privs = {weather_manager = true},
|
||||
func = function(name, param)
|
||||
-- Currently rain/thunder/snow: Set weather to clear
|
||||
if mcl_weather.state ~= "none" then
|
||||
return mcl_weather.change_weather("none", nil, name)
|
||||
|
||||
-- Currently clear: Set weather randomly to rain/thunder/snow
|
||||
else
|
||||
local new = { "rain", "thunder", "snow" }
|
||||
local r = math.random(1, #new)
|
||||
return mcl_weather.change_weather(new[r], nil, name)
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
-- Configuration setting which allows user to disable ABM for weathers (if they use it).
|
||||
-- Weather mods expected to be use this flag before registering ABM.
|
||||
local weather_allow_abm = minetest.settings:get_bool("weather_allow_abm")
|
||||
if weather_allow_abm == false then
|
||||
mcl_weather.allow_abm = false
|
||||
end
|
||||
|
||||
|
||||
local function load_weather()
|
||||
local weather = storage:get_string("mcl_weather_state")
|
||||
if weather and weather ~= "" then
|
||||
mcl_weather.state = weather
|
||||
mcl_weather.end_time = storage:get_int("mcl_weather_end_time")
|
||||
mcl_weather.change_weather(weather, mcl_weather.end_time)
|
||||
if type(mcl_weather.end_time) ~= "number" then
|
||||
-- Fallback in case of corrupted end time
|
||||
mcl_weather.end_time = mcl_weather.min_duration
|
||||
end
|
||||
minetest.log("action", "[mcl_weather] Weather restored.")
|
||||
else
|
||||
minetest.log("action", "[mcl_weather] No weather data found. Starting with clear weather.")
|
||||
end
|
||||
end
|
||||
|
||||
load_weather()
|
|
@ -1,12 +0,0 @@
|
|||
unused_args = false
|
||||
allow_defined_top = true
|
||||
|
||||
read_globals = {
|
||||
"minetest",
|
||||
"default",
|
||||
"sfinv",
|
||||
"sfinv_buttons",
|
||||
"vector",
|
||||
"string",
|
||||
"table",
|
||||
}
|
|
@ -1,171 +0,0 @@
|
|||
## API
|
||||
|
||||
### Custom recipes
|
||||
|
||||
#### Registering a custom crafting type (example)
|
||||
|
||||
```Lua
|
||||
mcl_craftguide.register_craft_type("digging", {
|
||||
description = "Digging",
|
||||
icon = "default_tool_steelpick.png",
|
||||
})
|
||||
```
|
||||
|
||||
#### Registering a custom crafting recipe (example)
|
||||
|
||||
```Lua
|
||||
mcl_craftguide.register_craft({
|
||||
type = "digging",
|
||||
width = 1,
|
||||
output = "default:cobble 2",
|
||||
items = {"default:stone"},
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Recipe filters
|
||||
|
||||
Recipe filters can be used to filter the recipes shown to players. Progressive
|
||||
mode is implemented as a recipe filter.
|
||||
|
||||
#### `mcl_craftguide.add_recipe_filter(name, function(recipes, player))`
|
||||
|
||||
Adds a recipe filter with the given name. The filter function should return the
|
||||
recipes to be displayed, given the available recipes and an `ObjectRef` to the
|
||||
user. Each recipe is a table of the form returned by
|
||||
`minetest.get_craft_recipe`.
|
||||
|
||||
Example function to hide recipes for items from a mod called "secretstuff":
|
||||
|
||||
```lua
|
||||
mcl_craftguide.add_recipe_filter("Hide secretstuff", function(recipes)
|
||||
local filtered = {}
|
||||
for _, recipe in ipairs(recipes) do
|
||||
if recipe.output:sub(1,12) ~= "secretstuff:" then
|
||||
filtered[#filtered + 1] = recipe
|
||||
end
|
||||
end
|
||||
|
||||
return filtered
|
||||
end)
|
||||
```
|
||||
|
||||
#### `mcl_craftguide.remove_recipe_filter(name)`
|
||||
|
||||
Removes the recipe filter with the given name.
|
||||
|
||||
#### `mcl_craftguide.set_recipe_filter(name, function(recipe, player))`
|
||||
|
||||
Removes all recipe filters and adds a new one.
|
||||
|
||||
#### `mcl_craftguide.get_recipe_filters()`
|
||||
|
||||
Returns a map of recipe filters, indexed by name.
|
||||
|
||||
---
|
||||
|
||||
### Search filters
|
||||
|
||||
Search filters are used to perform specific searches inside the search field.
|
||||
They can be used like so: `<optional name>+<filter name>=<value1>,<value2>,<...>`
|
||||
|
||||
Examples:
|
||||
|
||||
- `+groups=cracky,crumbly`: search for groups `cracky` and `crumbly` in all items.
|
||||
- `sand+groups=falling_node`: search for group `falling_node` for items which contain `sand` in their names.
|
||||
|
||||
Notes:
|
||||
- If `optional name` is omitted, the search filter will apply to all items, without pre-filtering.
|
||||
- Filters can be combined.
|
||||
- The `groups` filter is currently implemented by default.
|
||||
|
||||
#### `mcl_craftguide.add_search_filter(name, function(item, values))`
|
||||
|
||||
Adds a search filter with the given name.
|
||||
The search function should return a boolean value (whether the given item should be listed or not).
|
||||
|
||||
Example function to show items which contain at least a recipe of given width(s):
|
||||
|
||||
```lua
|
||||
mcl_craftguide.add_search_filter("widths", function(item, widths)
|
||||
local has_width
|
||||
local recipes = recipes_cache[item]
|
||||
|
||||
if recipes then
|
||||
for i = 1, #recipes do
|
||||
local recipe_width = recipes[i].width
|
||||
for j = 1, #widths do
|
||||
local width = tonumber(widths[j])
|
||||
if width == recipe_width then
|
||||
has_width = true
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return has_width
|
||||
end)
|
||||
```
|
||||
|
||||
#### `mcl_craftguide.remove_search_filter(name)`
|
||||
|
||||
Removes the search filter with the given name.
|
||||
|
||||
#### `mcl_craftguide.get_search_filters()`
|
||||
|
||||
Returns a map of search filters, indexed by name.
|
||||
|
||||
---
|
||||
|
||||
### Custom formspec elements
|
||||
|
||||
#### `mcl_craftguide.add_formspec_element(name, def)`
|
||||
|
||||
Adds a formspec element to the current formspec.
|
||||
Supported types: `box`, `label`, `image`, `button`, `tooltip`, `item_image`, `image_button`, `item_image_button`
|
||||
|
||||
Example:
|
||||
|
||||
```lua
|
||||
mcl_craftguide.add_formspec_element("export", {
|
||||
type = "button",
|
||||
element = function(data)
|
||||
-- Should return a table of parameters according to the formspec element type.
|
||||
-- Note: for all buttons, the 'name' parameter *must not* be specified!
|
||||
if data.recipes then
|
||||
return {
|
||||
data.iX - 3.7, -- X
|
||||
sfinv_only and 7.9 or 8, -- Y
|
||||
1.6, -- W
|
||||
1, -- H
|
||||
ESC(S("Export")) -- label
|
||||
}
|
||||
end
|
||||
end,
|
||||
-- Optional.
|
||||
action = function(player, data)
|
||||
-- When the button is pressed.
|
||||
print("Exported!")
|
||||
end
|
||||
})
|
||||
```
|
||||
|
||||
#### `mcl_craftguide.remove_formspec_element(name)`
|
||||
|
||||
Removes the formspec element with the given name.
|
||||
|
||||
#### `mcl_craftguide.get_formspec_elements()`
|
||||
|
||||
Returns a map of formspec elements, indexed by name.
|
||||
|
||||
---
|
||||
|
||||
### Miscellaneous
|
||||
|
||||
#### `mcl_craftguide.show(player_name, item, show_usages)`
|
||||
|
||||
Opens the Crafting Guide with the current filter applied.
|
||||
|
||||
* `player_name`: string param.
|
|
@ -1,11 +0,0 @@
|
|||
# Crafting Guide (MineClone 2 edition)
|
||||
|
||||
#### `mcl_craftguide` is based on, `craftguide` the most comprehensive crafting guide on Minetest.
|
||||
#### Consult the [Minetest Wiki](http://wiki.minetest.net/Crafting_guide) for more details.
|
||||
|
||||
This crafting guide can be accessed from the invenotory menu (book icon).
|
||||
|
||||
Crafting guide starts out empty and will be filled with more recipes whenever you hold on
|
||||
to a new items that you can use to new recipes.
|
||||
|
||||
For developers, there's a modding API (see `API.md`).
|
|
@ -1,58 +0,0 @@
|
|||
License of source code
|
||||
----------------------
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015-2019 Jean-Patrick Guerrero and contributors.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
|
||||
Licenses of media (textures)
|
||||
----------------------------
|
||||
|
||||
Copyright © Diego Martínez (kaeza): craftguide_*_icon.png (CC BY-SA 3.0)
|
||||
|
||||
You are free to:
|
||||
Share — copy and redistribute the material in any medium or format.
|
||||
Adapt — remix, transform, and build upon the material for any purpose, even commercially.
|
||||
The licensor cannot revoke these freedoms as long as you follow the license terms.
|
||||
|
||||
Under the following terms:
|
||||
|
||||
Attribution — You must give appropriate credit, provide a link to the license, and
|
||||
indicate if changes were made. You may do so in any reasonable manner, but not in any way
|
||||
that suggests the licensor endorses you or your use.
|
||||
|
||||
ShareAlike — If you remix, transform, or build upon the material, you must distribute
|
||||
your contributions under the same license as the original.
|
||||
|
||||
No additional restrictions — You may not apply legal terms or technological measures that
|
||||
legally restrict others from doing anything the license permits.
|
||||
|
||||
Notices:
|
||||
|
||||
You do not have to comply with the license for elements of the material in the public
|
||||
domain or where your use is permitted by an applicable exception or limitation.
|
||||
No warranties are given. The license may not give you all of the permissions necessary
|
||||
for your intended use. For example, other rights such as publicity, privacy, or moral
|
||||
rights may limit how you use the material.
|
||||
|
||||
For more details:
|
||||
http://creativecommons.org/licenses/by-sa/3.0/
|
|
@ -1,37 +0,0 @@
|
|||
# textdomain: mcl_craftguide
|
||||
Any shulker box=Beliebige Schulkerkiste
|
||||
Any wool=Beliebige Wolle
|
||||
Any wood planks=Beliebige Holzplanken
|
||||
Any wood=Beliebiges Holz
|
||||
Any sand=Beliebiger Sand
|
||||
Any normal sandstone=Beliebiger normaler Sandstein
|
||||
Any red sandstone=Beliebiger roter Sandstein
|
||||
Any carpet=Beliebiger Teppich
|
||||
Any dye=Beliebiger Farbstoff
|
||||
Any water bucket=Beliebiger Wassereimer
|
||||
Any flower=Beliebige Blume
|
||||
Any mushroom=Beliebiger Pilz
|
||||
Any wooden slab=Beliebige Holzplatte
|
||||
Any wooden stairs=Beliebgie Holztreppe
|
||||
Any coal=Beliebige Kohle
|
||||
Any kind of quartz block=Beliebiger Quarzblock
|
||||
Any kind of purpur block=Beliebiger Purpurblock
|
||||
Any stone bricks=Beliebige Steinziegel
|
||||
Any stick=Beliebiger Stock
|
||||
Any item belonging to the @1 group=Beliebiger Gegenstand aus Gruppe: @1
|
||||
Any item belonging to the groups: @1=Beliebiger Gegenstand aus den Gruppen: @1
|
||||
Search=Suche
|
||||
Reset=Zurücksetzen
|
||||
Previous page=Vorherige Seite
|
||||
Next page=Nächste Seite
|
||||
Usage @1 of @2=Verwendung @1 von @2
|
||||
Recipe @1 of @2=Rezept @1 von @2
|
||||
Burning time: @1=Brennzeit: @1
|
||||
Cooking time: @1=Kochzeit: @1
|
||||
Recipe is too big to be displayed (@1×@2)=Rezept ist zu groß für die Anzeige (@1×@2)
|
||||
Shapeless=Formlos
|
||||
Cooking=Kochen
|
||||
Increase window size=Fenster vergrößern
|
||||
Decrease window size=Fenster verkleinern
|
||||
No item to show=Nichts anzuzeigen
|
||||
Collect items to reveal more recipes=Gegenstände aufsammeln, um mehr Rezepte aufzudecken
|
|
@ -1,37 +0,0 @@
|
|||
# textdomain: mcl_craftguide
|
||||
Any shulker box=Toutes boîtes shulker
|
||||
Any wool=Toutes laines
|
||||
Any wood planks=Toutes planches de bois
|
||||
Any wood=Tout bois
|
||||
Any sand=Tout sable
|
||||
Any normal sandstone=Tout grès normal
|
||||
Any red sandstone=Tout grès rouge
|
||||
Any carpet=Tout tapis
|
||||
Any dye=Tout colorant
|
||||
Any water bucket=Tout seau d'eau
|
||||
Any flower=Toute fleur
|
||||
Any mushroom=Tout Champignon
|
||||
Any wooden slab=Toute dalle de bois
|
||||
Any wooden stairs=Tout escalier de bois
|
||||
Any coal=Tout charbon
|
||||
Any kind of quartz block=Toute sorte de bloc de quartz
|
||||
Any kind of purpur block=Toute sorte de bloc de purpur
|
||||
Any stone bricks=Tout brique de pierre
|
||||
Any stick=Tout bâton
|
||||
Any item belonging to the @1 group=Tout élément appartenant au groupe @1
|
||||
Any item belonging to the groups: @1=Tout élément appartenant aux groupes: @1
|
||||
Search=Rechercher
|
||||
Reset=Réinitialiser
|
||||
Previous page=Page précédente
|
||||
Next page=Page suivante
|
||||
Usage @1 of @2=Usage @1 de @2
|
||||
Recipe @1 of @2=Recette @1 de @2
|
||||
Burning time: @1=Temps de combustion : @1
|
||||
Cooking time: @1=Temps de cuisson : @1
|
||||
Recipe is too big to be displayed (@1×@2)=La recette est trop grande pour être affichée (@1x@2)
|
||||
Shapeless=Sans forme
|
||||
Cooking=Cuisson
|
||||
Increase window size=Agrandir la fenêtre
|
||||
Decrease window size=Réduire la fenêtre
|
||||
No item to show=Aucun item à afficher
|
||||
Collect items to reveal more recipes=Collecte des items pour révéler plus de recettes
|
|
@ -1,38 +0,0 @@
|
|||
# textdomain: mcl_craftguide
|
||||
Any shulker box=Dowolna skrzynia shulkerowa
|
||||
Any wool=Dowolna wełna
|
||||
Any wood planks=Dowolne deski
|
||||
Any wood=Dowolne drewno
|
||||
Any sand=Dowolny piasek
|
||||
Any normal sandstone=Dowolny zwykły piaskowiec
|
||||
Any red sandstone=Dowolny czerwony piaskowiec
|
||||
Any carpet=Dowolny dywan
|
||||
Any dye=Dowolna farba
|
||||
Any water bucket=Dowolne wiadro wody
|
||||
Any flower=Dowolny kwiat
|
||||
Any mushroom=Dowolny grzyb
|
||||
Any wooden slab=Dowolny drewniana płyta
|
||||
Any wooden stairs=Dowolne drewniane schody
|
||||
Any coal=Dowolny węgiel
|
||||
Any kind of quartz block=Dowolny typ bloku kwarcu
|
||||
Any kind of purpur block=Dowolny typ bloku purpury
|
||||
Any stone bricks=Dowolne kamienne cegły
|
||||
Any stick=Dowolny patyk
|
||||
Any item belonging to the @1 group=Dowolny przedmiot z grupy @1
|
||||
Any item belonging to the groups: @1=Dowolny przedmiot należący do grup: @1
|
||||
Search=Wyszukaj
|
||||
Reset=Zresetuj
|
||||
Previous page=Poprzednia strona
|
||||
Next page=Następna strona
|
||||
Usage @1 of @2=Użycie @1 z @2
|
||||
Recipe @1 of @2=Receptura @1 z @2
|
||||
Burning time: @1=Czas wypalenia: @1
|
||||
Cooking time: @1=Czas pieczenia: @1
|
||||
Recipe is too big to be displayed (@1×@2)=Receptura jest zbyt długa do wyświetlenia (@1×@2)
|
||||
Shapeless=Bezkształtne
|
||||
Cooking=Pieczenie
|
||||
Increase window size=Zwiększ rozmiar okna
|
||||
Decrease window size=Zmniejsz rozmiar okna
|
||||
No item to show=Brak przedmiotów do pokazania
|
||||
Collect items to reveal more recipes=Zbierz przedmioty by odkryć więcej receptur
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
# textdomain: mcl_craftguide
|
||||
Any shulker box=Любой ящик шалкера
|
||||
Any wool=Любая шерсть
|
||||
Any wood planks=Любые доски
|
||||
Any wood=Любое дерево
|
||||
Any sand=Любой песок
|
||||
Any normal sandstone=Любой обычный песчаник
|
||||
Any red sandstone=Любой красный песчаник
|
||||
Any carpet=Любое покрытие
|
||||
Any dye=Любой краситель
|
||||
Any water bucket=Любое ведро воды
|
||||
Any flower=Любой цветок
|
||||
Any mushroom=Любой гриб
|
||||
Any wooden slab=Любая деревянная плита
|
||||
Any wooden stairs=Любые деревянные ступеньки
|
||||
Any coal=Любой уголь
|
||||
Any kind of quartz block=Любой кварцевый блок
|
||||
Any kind of purpur block=Любой фиолетовый блок
|
||||
Any stone bricks=Любые каменные блоки
|
||||
Any stick=Любая палка
|
||||
Any item belonging to the @1 group=Любой предмет, относящийся к группе @1
|
||||
Any item belonging to the groups: @1=Любой предмет, относящийся к группам: @1
|
||||
Search=Поиск
|
||||
Reset=Сброс
|
||||
Previous page=Предыдущая страница
|
||||
Next page=Следующая страница
|
||||
Usage @1 of @2=Использование @1 из @2
|
||||
Recipe @1 of @2=Рецепт @1 из @2
|
||||
Burning time: @1=Время горения: @1
|
||||
Cooking time: @1=Время приготовления: @1
|
||||
Recipe is too big to be displayed (@1×@2)=Рецепт слишком большой для отображения (@1×@2)
|
||||
Shapeless=Бесформенный
|
||||
Cooking=Приготовление
|
||||
Increase window size=Увеличить окно
|
||||
Decrease window size=Уменьшить окно
|
||||
No item to show=Нет элемента для показа
|
||||
Collect items to reveal more recipes=Для рецептов нужны предметы
|
|
@ -1,37 +0,0 @@
|
|||
# textdomain: craftguide
|
||||
Any shulker box=
|
||||
Any wool=
|
||||
Any wood planks=
|
||||
Any wood=
|
||||
Any sand=
|
||||
Any normal sandstone=
|
||||
Any red sandstone=
|
||||
Any carpet=
|
||||
Any dye=
|
||||
Any water bucket=
|
||||
Any flower=
|
||||
Any mushroom=
|
||||
Any wooden slab=
|
||||
Any wooden stairs=
|
||||
Any coal=
|
||||
Any kind of quartz block=
|
||||
Any kind of purpur block=
|
||||
Any stone bricks=
|
||||
Any stick=
|
||||
Any item belonging to the @1 group=
|
||||
Any item belonging to the groups: @1=
|
||||
Search=
|
||||
Reset=
|
||||
Previous page=
|
||||
Next page=
|
||||
Usage @1 of @2=
|
||||
Recipe @1 of @2=
|
||||
Burning time: @1=
|
||||
Cooking time: @1=
|
||||
Recipe is too big to be displayed (@1×@2)=
|
||||
Shapeless=
|
||||
Cooking=
|
||||
Increase window size=
|
||||
Decrease window size=
|
||||
No item to show=
|
||||
Collect items to reveal more recipes=
|
|
@ -1,5 +0,0 @@
|
|||
name = mcl_craftguide
|
||||
author = kilbith
|
||||
description = The most comprehensive Crafting Guide on Minetest.
|
||||
depends = mcl_core, mcl_compass, mcl_clock, doc, mcl_colors
|
||||
optional_depends = sfinv, sfinv_buttons
|
|
@ -1,4 +0,0 @@
|
|||
# If enabled, the recipe book will progressively be filled with new recipes that can be crafted from all items you ever have had in your inventory.
|
||||
# Recommended for new players and for a spoiler-free gameplay experience.
|
||||
# If disabled, all recipes will be shown.
|
||||
mcl_craftguide_progressive_mode (Learn crafting recipes progressively) bool true
|
Before Width: | Height: | Size: 136 B |
Before Width: | Height: | Size: 192 B |
Before Width: | Height: | Size: 708 B |
Before Width: | Height: | Size: 300 B |
Before Width: | Height: | Size: 727 B |
Before Width: | Height: | Size: 728 B |
Before Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 169 B |
Before Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 188 B |
|
@ -1,28 +0,0 @@
|
|||
-- |\ /| ____ ____ ____ _____ ____ _____
|
||||
-- | \ / | | | | | | | |\ | |
|
||||
-- | \/ | |___ ____ |___ | | | | \ | |____
|
||||
-- | | | | | | | | | \ | |
|
||||
-- | | |___ ____| |___ |____ |____| | \| ____|
|
||||
-- by Jeija and contributors
|
||||
|
||||
Credits:
|
||||
Jeija: main developer
|
||||
VanessaE: Awesome textures & design, coding
|
||||
sfan5: coding, textures
|
||||
temperest: coding, textures
|
||||
Jordach: Sounds for the noteblock
|
||||
minerd247: Some textures
|
||||
suzenako: Piston sounds
|
||||
...other contributors
|
||||
|
||||
This is a mod for minetest-c55.
|
||||
Copy the minetest-mod-mesecons directory into you game's mod folder
|
||||
(e.g. games/minetest_game/mods/minetest-mod-mesecons)
|
||||
|
||||
You can remove modules of this mod by deleting the mesecons_*
|
||||
folders in the minetest-mod-mesecons directory.
|
||||
|
||||
Mod dependencies: none
|
||||
|
||||
Code license: LGPLv3 or later
|
||||
Media license: CC BY-SA 3.0 <https://creativecommons.org/licenses/by-sa/3.0/>
|
|
@ -1,365 +0,0 @@
|
|||
local S = minetest.get_translator(minetest.get_current_modname())
|
||||
|
||||
-- Functions that get the input/output rules of the comparator
|
||||
|
||||
local function comparator_get_output_rules(node)
|
||||
local rules = {{x = -1, y = 0, z = 0, spread=true}}
|
||||
for i = 0, node.param2 do
|
||||
rules = mesecon.rotate_rules_left(rules)
|
||||
end
|
||||
return rules
|
||||
end
|
||||
|
||||
|
||||
local function comparator_get_input_rules(node)
|
||||
local rules = {
|
||||
-- we rely on this order in update_self below
|
||||
{x = 1, y = 0, z = 0}, -- back
|
||||
{x = 0, y = 0, z = -1}, -- side
|
||||
{x = 0, y = 0, z = 1}, -- side
|
||||
}
|
||||
for i = 0, node.param2 do
|
||||
rules = mesecon.rotate_rules_left(rules)
|
||||
end
|
||||
return rules
|
||||
end
|
||||
|
||||
|
||||
-- Functions that are called after the delay time
|
||||
|
||||
local function comparator_turnon(params)
|
||||
local rules = comparator_get_output_rules(params.node)
|
||||
mesecon.receptor_on(params.pos, rules)
|
||||
end
|
||||
|
||||
|
||||
local function comparator_turnoff(params)
|
||||
local rules = comparator_get_output_rules(params.node)
|
||||
mesecon.receptor_off(params.pos, rules)
|
||||
end
|
||||
|
||||
|
||||
-- Functions that set the correct node type an schedule a turnon/off
|
||||
|
||||
local function comparator_activate(pos, node)
|
||||
local def = minetest.registered_nodes[node.name]
|
||||
local onstate = def.comparator_onstate
|
||||
if onstate then
|
||||
minetest.swap_node(pos, { name = onstate, param2 = node.param2 })
|
||||
end
|
||||
minetest.after(0.1, comparator_turnon , {pos = pos, node = node})
|
||||
end
|
||||
|
||||
|
||||
local function comparator_deactivate(pos, node)
|
||||
local def = minetest.registered_nodes[node.name]
|
||||
local offstate = def.comparator_offstate
|
||||
if offstate then
|
||||
minetest.swap_node(pos, { name = offstate, param2 = node.param2 })
|
||||
end
|
||||
minetest.after(0.1, comparator_turnoff, {pos = pos, node = node})
|
||||
end
|
||||
|
||||
|
||||
-- weather pos has an inventory that contains at least one item
|
||||
local function container_inventory_nonempty(pos)
|
||||
local invnode = minetest.get_node(pos)
|
||||
local invnodedef = minetest.registered_nodes[invnode.name]
|
||||
-- Ignore stale nodes
|
||||
if not invnodedef then return false end
|
||||
|
||||
-- Only accept containers. When a container is dug, it's inventory
|
||||
-- seems to stay. and we don't want to accept the inventory of an air
|
||||
-- block
|
||||
if not invnodedef.groups.container then return false end
|
||||
|
||||
local inv = minetest.get_inventory({type="node", pos=pos})
|
||||
if not inv then return false end
|
||||
|
||||
for listname, _ in pairs(inv:get_lists()) do
|
||||
if not inv:is_empty(listname) then return true end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
-- weather pos has an constant signal output for the comparator
|
||||
local function static_signal_output(pos)
|
||||
local node = minetest.get_node(pos)
|
||||
local g = minetest.get_item_group(node.name, "comparator_signal")
|
||||
return g > 0
|
||||
end
|
||||
|
||||
-- whether the comparator should be on according to its inputs
|
||||
local function comparator_desired_on(pos, node)
|
||||
local my_input_rules = comparator_get_input_rules(node);
|
||||
local back_rule = my_input_rules[1]
|
||||
local state
|
||||
if back_rule then
|
||||
local back_pos = vector.add(pos, back_rule)
|
||||
state = mesecon.is_power_on(back_pos) or container_inventory_nonempty(back_pos) or static_signal_output(back_pos)
|
||||
end
|
||||
|
||||
-- if back input if off, we don't need to check side inputs
|
||||
if not state then return false end
|
||||
|
||||
-- without power levels, side inputs have no influence on output in compare
|
||||
-- mode
|
||||
local mode = minetest.registered_nodes[node.name].comparator_mode
|
||||
if mode == "comp" then return state end
|
||||
|
||||
-- subtract mode, subtract max(side_inputs) from back input
|
||||
local side_state = false
|
||||
for ri = 2,3 do
|
||||
if my_input_rules[ri] then
|
||||
side_state = mesecon.is_power_on(vector.add(pos, my_input_rules[ri]))
|
||||
end
|
||||
if side_state then break end
|
||||
end
|
||||
-- state is known to be true
|
||||
return not side_state
|
||||
end
|
||||
|
||||
|
||||
-- update comparator state, if needed
|
||||
local function update_self(pos, node)
|
||||
node = node or minetest.get_node(pos)
|
||||
local old_state = mesecon.is_receptor_on(node.name)
|
||||
local new_state = comparator_desired_on(pos, node)
|
||||
if new_state ~= old_state then
|
||||
if new_state then
|
||||
comparator_activate(pos, node)
|
||||
else
|
||||
comparator_deactivate(pos, node)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- compute tile depending on state and mode
|
||||
local function get_tiles(state, mode)
|
||||
local top = "mcl_comparators_"..state..".png^"..
|
||||
"mcl_comparators_"..mode..".png"
|
||||
local sides = "mcl_comparators_sides_"..state..".png^"..
|
||||
"mcl_comparators_sides_"..mode..".png"
|
||||
local ends = "mcl_comparators_ends_"..state..".png^"..
|
||||
"mcl_comparators_ends_"..mode..".png"
|
||||
return {
|
||||
top, "mcl_stairs_stone_slab_top.png",
|
||||
sides, sides.."^[transformFX",
|
||||
ends, ends,
|
||||
}
|
||||
end
|
||||
|
||||
-- Given one mode, get the other mode
|
||||
local function flipmode(mode)
|
||||
if mode == "comp" then return "sub"
|
||||
elseif mode == "sub" then return "comp"
|
||||
end
|
||||
end
|
||||
|
||||
local function make_rightclick_handler(state, mode)
|
||||
local newnodename =
|
||||
"mcl_comparators:comparator_"..state.."_"..flipmode(mode)
|
||||
return function (pos, node, clicker)
|
||||
local protname = clicker:get_player_name()
|
||||
if minetest.is_protected(pos, protname) then
|
||||
minetest.record_protection_violation(pos, protname)
|
||||
return
|
||||
end
|
||||
minetest.swap_node(pos, {name = newnodename, param2 = node.param2 })
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Register the 2 (states) x 2 (modes) comparators
|
||||
|
||||
local icon = "mcl_comparators_item.png"
|
||||
|
||||
local node_boxes = {
|
||||
comp = {
|
||||
{ -8/16, -8/16, -8/16,
|
||||
8/16, -6/16, 8/16 }, -- the main slab
|
||||
{ -1/16, -6/16, 6/16,
|
||||
1/16, -4/16, 4/16 }, -- front torch
|
||||
{ -4/16, -6/16, -5/16,
|
||||
-2/16, -1/16, -3/16 }, -- left back torch
|
||||
{ 2/16, -6/16, -5/16,
|
||||
4/16, -1/16, -3/16 }, -- right back torch
|
||||
},
|
||||
sub = {
|
||||
{ -8/16, -8/16, -8/16,
|
||||
8/16, -6/16, 8/16 }, -- the main slab
|
||||
{ -1/16, -6/16, 6/16,
|
||||
1/16, -3/16, 4/16 }, -- front torch (active)
|
||||
{ -4/16, -6/16, -5/16,
|
||||
-2/16, -1/16, -3/16 }, -- left back torch
|
||||
{ 2/16, -6/16, -5/16,
|
||||
4/16, -1/16, -3/16 }, -- right back torch
|
||||
},
|
||||
}
|
||||
|
||||
local collision_box = {
|
||||
type = "fixed",
|
||||
fixed = { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 },
|
||||
}
|
||||
|
||||
local state_strs = {
|
||||
[ mesecon.state.on ] = "on",
|
||||
[ mesecon.state.off ] = "off",
|
||||
}
|
||||
|
||||
local groups = {
|
||||
dig_immediate = 3,
|
||||
dig_by_water = 1,
|
||||
destroy_by_lava_flow = 1,
|
||||
dig_by_piston = 1,
|
||||
attached_node = 1,
|
||||
}
|
||||
|
||||
local on_rotate
|
||||
if minetest.get_modpath("screwdriver") then
|
||||
on_rotate = screwdriver.disallow
|
||||
end
|
||||
|
||||
for _, mode in pairs{"comp", "sub"} do
|
||||
for _, state in pairs{mesecon.state.on, mesecon.state.off} do
|
||||
local state_str = state_strs[state]
|
||||
local nodename =
|
||||
"mcl_comparators:comparator_"..state_str.."_"..mode
|
||||
|
||||
-- Help
|
||||
local longdesc, usagehelp, use_help
|
||||
if state_str == "off" and mode == "comp" then
|
||||
longdesc = S("Redstone comparators are multi-purpose redstone components.").."\n"..
|
||||
S("They can transmit a redstone signal, detect whether a block contains any items and compare multiple signals.")
|
||||
|
||||
usagehelp = S("A redstone comparator has 1 main input, 2 side inputs and 1 output. The output is in arrow direction, the main input is in the opposite direction. The other 2 sides are the side inputs.").."\n"..
|
||||
S("The main input can powered in 2 ways: First, it can be powered directly by redstone power like any other component. Second, it is powered if, and only if a container (like a chest) is placed in front of it and the container contains at least one item.").."\n"..
|
||||
S("The side inputs are only powered by normal redstone power. The redstone comparator can operate in two modes: Transmission mode and subtraction mode. It starts in transmission mode and the mode can be changed by using the block.").."\n\n"..
|
||||
S("Transmission mode:\nThe front torch is unlit and lowered. The output is powered if, and only if the main input is powered. The two side inputs are ignored.").."\n"..
|
||||
S("Subtraction mode:\nThe front torch is lit. The output is powered if, and only if the main input is powered and none of the side inputs is powered.")
|
||||
else
|
||||
use_help = false
|
||||
end
|
||||
|
||||
local nodedef = {
|
||||
description = S("Redstone Comparator"),
|
||||
inventory_image = icon,
|
||||
wield_image = icon,
|
||||
_doc_items_create_entry = use_help,
|
||||
_doc_items_longdesc = longdesc,
|
||||
_doc_items_usagehelp = usagehelp,
|
||||
drawtype = "nodebox",
|
||||
tiles = get_tiles(state_str, mode),
|
||||
use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "opaque" or false,
|
||||
--wield_image = "mcl_comparators_off.png",
|
||||
walkable = true,
|
||||
selection_box = collision_box,
|
||||
collision_box = collision_box,
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = node_boxes[mode],
|
||||
},
|
||||
groups = groups,
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
sunlight_propagates = false,
|
||||
is_ground_content = false,
|
||||
drop = "mcl_comparators:comparator_off_comp",
|
||||
on_construct = update_self,
|
||||
on_rightclick =
|
||||
make_rightclick_handler(state_str, mode),
|
||||
comparator_mode = mode,
|
||||
comparator_onstate = "mcl_comparators:comparator_on_"..mode,
|
||||
comparator_offstate = "mcl_comparators:comparator_off_"..mode,
|
||||
sounds = mcl_sounds.node_sound_stone_defaults(),
|
||||
mesecons = {
|
||||
receptor = {
|
||||
state = state,
|
||||
rules = comparator_get_output_rules,
|
||||
},
|
||||
effector = {
|
||||
rules = comparator_get_input_rules,
|
||||
action_change = update_self,
|
||||
}
|
||||
},
|
||||
on_rotate = on_rotate,
|
||||
}
|
||||
|
||||
if mode == "comp" and state == mesecon.state.off then
|
||||
-- This is the prototype
|
||||
nodedef._doc_items_create_entry = true
|
||||
else
|
||||
nodedef.groups = table.copy(nodedef.groups)
|
||||
nodedef.groups.not_in_creative_inventory = 1
|
||||
--local extra_desc = {}
|
||||
if mode == "sub" or state == mesecon.state.on then
|
||||
nodedef.inventory_image = nil
|
||||
end
|
||||
local desc = nodedef.description
|
||||
if mode ~= "sub" and state == mesecon.state.on then
|
||||
desc = S("Redstone Comparator (Powered)")
|
||||
elseif mode == "sub" and state ~= mesecon.state.on then
|
||||
desc = S("Redstone Comparator (Subtract)")
|
||||
elseif mode == "sub" and state == mesecon.state.on then
|
||||
desc = S("Redstone Comparator (Subtract, Powered)")
|
||||
end
|
||||
nodedef.description = desc
|
||||
end
|
||||
|
||||
minetest.register_node(nodename, nodedef)
|
||||
mcl_wip.register_wip_item(nodename)
|
||||
end
|
||||
end
|
||||
|
||||
-- Register recipies
|
||||
local rstorch = "mesecons_torch:mesecon_torch_on"
|
||||
local quartz = "mcl_nether:quartz"
|
||||
local stone = "mcl_core:stone"
|
||||
|
||||
minetest.register_craft({
|
||||
output = "mcl_comparators:comparator_off_comp",
|
||||
recipe = {
|
||||
{ "", rstorch, "" },
|
||||
{ rstorch, quartz, rstorch },
|
||||
{ stone, stone, stone },
|
||||
}
|
||||
})
|
||||
|
||||
-- Register active block handlers
|
||||
minetest.register_abm({
|
||||
label = "Comparator signal input check (comparator is off)",
|
||||
nodenames = {
|
||||
"mcl_comparators:comparator_off_comp",
|
||||
"mcl_comparators:comparator_off_sub",
|
||||
},
|
||||
neighbors = {"group:container", "group:comparator_signal"},
|
||||
interval = 1,
|
||||
chance = 1,
|
||||
action = update_self,
|
||||
})
|
||||
|
||||
minetest.register_abm({
|
||||
label = "Comparator signal input check (comparator is on)",
|
||||
nodenames = {
|
||||
"mcl_comparators:comparator_on_comp",
|
||||
"mcl_comparators:comparator_on_sub",
|
||||
},
|
||||
-- needs to run regardless of neighbors to make sure we detect when a
|
||||
-- container is dug
|
||||
interval = 1,
|
||||
chance = 1,
|
||||
action = update_self,
|
||||
})
|
||||
|
||||
|
||||
-- Add entry aliases for the Help
|
||||
if minetest.get_modpath("doc") then
|
||||
doc.add_entry_alias("nodes", "mcl_comparators:comparator_off_comp",
|
||||
"nodes", "mcl_comparators:comparator_off_sub")
|
||||
doc.add_entry_alias("nodes", "mcl_comparators:comparator_off_comp",
|
||||
"nodes", "mcl_comparators:comparator_on_comp")
|
||||
doc.add_entry_alias("nodes", "mcl_comparators:comparator_off_comp",
|
||||
"nodes", "mcl_comparators:comparator_on_sub")
|
||||
end
|
|
@ -1,12 +0,0 @@
|
|||
# textdomain: mcl_comparators
|
||||
Redstone comparators are multi-purpose redstone components.=Redstonekomparatoren sind Redstonekomponenten mit vielen Verwendungszwecken.
|
||||
They can transmit a redstone signal, detect whether a block contains any items and compare multiple signals.=Sie können ein Redstonesignal übertragen, erkennen, ob ein Block Gegenstände enthält und mehrere Signale vergleichen.
|
||||
A redstone comparator has 1 main input, 2 side inputs and 1 output. The output is in arrow direction, the main input is in the opposite direction. The other 2 sides are the side inputs.=Ein Redstonekomparator hat 1 Haupteingang, 2 Seiteneingänge und 1 Ausgang. Der Ausgang ist in Pfeilrichtung, der Haupteingang ist in der gegenüberliegenden Richtung. Die anderen 2 Seiten sind die Seiteneingänge.
|
||||
The main input can powered in 2 ways: First, it can be powered directly by redstone power like any other component. Second, it is powered if, and only if a container (like a chest) is placed in front of it and the container contains at least one item.=Der Haupteingang kann auf 2 Weisen versorgt werden: Erstens, kann er direkt von Redstoneenergie wie bei jeder anderen Komponente versorgt werden. Zweitens wird er versorgt, wenn, und nur wenn ein Behälter (wie eine Truhe) vor dem Komporator platziert wurde und der Behälter mindestens einen Gegenstand enthält.
|
||||
The side inputs are only powered by normal redstone power. The redstone comparator can operate in two modes: Transmission mode and subtraction mode. It starts in transmission mode and the mode can be changed by using the block.=Die Seiteneingänge akzeptieren nur normale Redstoneenergie. Der Redstonekomparator kann in zwei Modi agieren: Übertragungsmodus und Subtraktionsmodus. Er fängt im Übertragungsmodus an. Der Modus wird beim Benutzen des Blocks geändert.
|
||||
Transmission mode:@nThe front torch is unlit and lowered. The output is powered if, and only if the main input is powered. The two side inputs are ignored.=Übertragungsmodus:@nDie vordere Fackel ist eingefahren und leuchtet nicht auf. Die Ausgabe gibt ein Signal, wenn, nur nur wenn der Haupteingang bestromt wird. Die zwei Seiteneingänge werden ignoriert.
|
||||
Subtraction mode:@nThe front torch is lit. The output is powered if, and only if the main input is powered and none of the side inputs is powered.=Subtraktionsmodus:@nDie vordere Fackel leuchtet auf. Die Ausgabe gibt ein Signal wenn, nur nur wenn der Haupteingang versorgt wird und keiner der Seiteneingänge bestromt ist.
|
||||
Redstone Comparator=Redstonekomparator
|
||||
Redstone Comparator (Subtract)=Redstonekomparator (subtrahieren)
|
||||
Redstone Comparator (Powered)=Redstonekomparator (bestromt)
|
||||
Redstone Comparator (Subtract, Powered)=Redstonekomparator (subtrahieren, bestromt)
|
|
@ -1,12 +0,0 @@
|
|||
# textdomain: mcl_comparators
|
||||
Redstone comparators are multi-purpose redstone components.=Los comparadores de Redstone son componentes multipropósito de redstone.
|
||||
They can transmit a redstone signal, detect whether a block contains any items and compare multiple signals.=Pueden transmitir una señal de redstone, detectar si un bloque contiene algún elemento y comparar múltiples señales.
|
||||
A redstone comparator has 1 main input, 2 side inputs and 1 output. The output is in arrow direction, the main input is in the opposite direction. The other 2 sides are the side inputs.=Un comparador redstone tiene 1 entrada principal, 2 entradas laterales y 1 salida. La salida está en la dirección de la flecha, la entrada principal está en la dirección opuesta. Los otros 2 lados son las entradas laterales.
|
||||
The main input can powered in 2 ways: First, it can be powered directly by redstone power like any other component. Second, it is powered if, and only if a container (like a chest) is placed in front of it and the container contains at least one item.=La entrada principal puede alimentarse de 2 maneras: en primer lugar, puede alimentarse directamente mediante redstone como cualquier otro componente. En segundo lugar, se alimenta si, y solo si se coloca un contenedor (como un cofre) frente a él y el contenedor contiene al menos un elemento.
|
||||
The side inputs are only powered by normal redstone power. The redstone comparator can operate in two modes: Transmission mode and subtraction mode. It starts in transmission mode and the mode can be changed by using the block.=Las entradas laterales solo están alimentadas por la alimentación normal de redstone. El comparador de redstone puede funcionar en dos modos: modo de transmisión y modo de resta. Comienza en modo de transmisión y el modo se puede cambiar usando el bloque.
|
||||
Transmission mode:@nThe front torch is unlit and lowered. The output is powered if, and only if the main input is powered. The two side inputs are ignored.=Modo de transmisión: @nLa antorcha delantera está apagada y baja. La salida se alimenta solo si se alimenta la entrada principal. Las dos entradas laterales se ignoran.
|
||||
Subtraction mode:@nThe front torch is lit. The output is powered if, and only if the main input is powered and none of the side inputs is powered.=Modo de resta: @nLa antorcha delantera está encendida. La salida se alimenta si, y solo si la entrada principal está alimentada y ninguna de las entradas laterales está alimentada.
|
||||
Redstone Comparator=Comparador de redstone
|
||||
Redstone Comparator (Subtract)=Comparador de redstone (Negativo)
|
||||
Redstone Comparator (Powered)=Comparador de redstone (Motorizado)
|
||||
Redstone Comparator (Subtract, Powered)=Redstonekomparator (Negativo, Motorizado)
|
|
@ -1,12 +0,0 @@
|
|||
# textdomain: mcl_comparators
|
||||
Redstone comparators are multi-purpose redstone components.=Les comparateurs Redstone sont des composants Redstone polyvalents.
|
||||
They can transmit a redstone signal, detect whether a block contains any items and compare multiple signals.=Ils peuvent transmettre un signal redstone, détecter si un bloc contient des éléments et comparer plusieurs signaux.
|
||||
A redstone comparator has 1 main input, 2 side inputs and 1 output. The output is in arrow direction, the main input is in the opposite direction. The other 2 sides are the side inputs.=Un comparateur redstone a 1 entrée principale, 2 entrées latérales et 1 sortie. La sortie est dans le sens de la flèche, l'entrée principale est dans le sens opposé. Les 2 autres côtés sont les entrées latérales.
|
||||
The main input can powered in 2 ways: First, it can be powered directly by redstone power like any other component. Second, it is powered if, and only if a container (like a chest) is placed in front of it and the container contains at least one item.=L'entrée principale peut être alimentée de 2 manières: Premièrement, elle peut être alimentée directement par une alimentation redstone comme n'importe quel autre composant. Deuxièmement, il est alimenté si et seulement si un conteneur (comme un coffre) est placé devant lui et que le conteneur contient au moins un article.
|
||||
The side inputs are only powered by normal redstone power. The redstone comparator can operate in two modes: Transmission mode and subtraction mode. It starts in transmission mode and the mode can be changed by using the block.=Les entrées latérales sont uniquement alimentées par une alimentation Redstone normale. Le comparateur redstone peut fonctionner en deux modes: le mode de transmission et le mode de soustraction. Il démarre en mode transmission et le mode peut être changé en utilisant le bloc.
|
||||
Transmission mode:@nThe front torch is unlit and lowered. The output is powered if, and only if the main input is powered. The two side inputs are ignored.=Mode de transmission: @nLa torche avant est éteinte et abaissée. La sortie est alimentée si et seulement si l'entrée principale est alimentée. Les deux entrées latérales sont ignorées.
|
||||
Subtraction mode:@nThe front torch is lit. The output is powered if, and only if the main input is powered and none of the side inputs is powered.=Mode de soustraction: @nLa torche avant est allumée. La sortie est alimentée si et seulement si l'entrée principale est alimentée et qu'aucune des entrées latérales n'est alimentée.
|
||||
Redstone Comparator=Comparateur Redstone
|
||||
Redstone Comparator (Subtract)=Comparateur Redstone (Soustraction)
|
||||
Redstone Comparator (Powered)=Comparateur Redstone (Alimenté)
|
||||
Redstone Comparator (Subtract, Powered)=Comparateur Redstone (Soustraction, Alimenté)
|
|
@ -1,13 +0,0 @@
|
|||
# textdomain: mcl_comparators
|
||||
Redstone comparators are multi-purpose redstone components.=Komparatory są wielofunkcyjnymi mechanizmami czerwienitowymi.
|
||||
They can transmit a redstone signal, detect whether a block contains any items and compare multiple signals.=Mogą one przesyłać sygnał czerwienitowy, wykrywać czy blok zawiera przedmioty i porównywać wiele sygnałów.
|
||||
A redstone comparator has 1 main input, 2 side inputs and 1 output. The output is in arrow direction, the main input is in the opposite direction. The other 2 sides are the side inputs.=Komparator ma jedno główne wejście, 2 wejścia poboczne i jedno wyjście. Wyjście jest wskazywane przez strzałkę, wejście jest na przeciwko. Pozostałe dwa wejścia są poboczne.
|
||||
The main input can powered in 2 ways: First, it can be powered directly by redstone power like any other component. Second, it is powered if, and only if a container (like a chest) is placed in front of it and the container contains at least one item.=Główny wejście można zasilać na 2 sposoby: Może być zasilany bezpośrednio energią czerwienitową jak każdy inny komponent, lub gdy przed nim postawiony jest kontener zawierający przynajmniej jeden przedmiot.
|
||||
The side inputs are only powered by normal redstone power. The redstone comparator can operate in two modes: Transmission mode and subtraction mode. It starts in transmission mode and the mode can be changed by using the block.=Wejścia poboczne są aktywowane przez zwykłą energię czerwienitową. Komparator może działać w dwóch trybach: tryb przekazywania oraz tryb odejmowania. Początkowo jest w trybie przekazywania, a tryb może być zmienione przez użycie go.
|
||||
Transmission mode:@nThe front torch is unlit and lowered. The output is powered if, and only if the main input is powered. The two side inputs are ignored.=Tryb przekazywania:@nPrzednia pochodnia jest niezaświecona i obniżona. Wyjście jest zasilane wtedy i tylko wtedy gdy wejście główne jest zasilane. Wejścia boczne są ignorowane.
|
||||
Subtraction mode:@nThe front torch is lit. The output is powered if, and only if the main input is powered and none of the side inputs is powered.=Tryb odejmowania:@nPrzednia pochodnia jest zaświecona. Wyjście jest zasilane wtedy i tylko gdy zasilane jest główne wejście, a wejścia boczne nie są.
|
||||
Redstone Comparator=Komparator
|
||||
Redstone Comparator (Subtract)=Komparator (odejmowanie)
|
||||
Redstone Comparator (Powered)=Komparator (zasilony)
|
||||
Redstone Comparator (Subtract, Powered)=Komparator (odejmowanie, zasilony)
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
# textdomain: mcl_comparators
|
||||
Redstone comparators are multi-purpose redstone components.=Компаратор это многофункциональный элемент редстоуна.
|
||||
They can transmit a redstone signal, detect whether a block contains any items and compare multiple signals.=Он может передавать сигнал редстоуна, определять, содержит ли блок какой-либо предмет, и сравнивать сигналы.
|
||||
A redstone comparator has 1 main input, 2 side inputs and 1 output. The output is in arrow direction, the main input is in the opposite direction. The other 2 sides are the side inputs.=Компаратор имеет 1 основной вход, 2 боковых входа и 1 выход. Выход расположен по направлению стрелки, основной вход в противоположном направлении. Оставшиеся 2 стороны это боковые входы.
|
||||
The main input can powered in 2 ways: First, it can be powered directly by redstone power like any other component. Second, it is powered if, and only if a container (like a chest) is placed in front of it and the container contains at least one item.=Основной вход можно подключать 2 способами: 1) напрямую к энергии редстоуна, как и любой другой компонент; 2) перед компаратором можно установить контейнер (например, сундук), тогда сигнал будет поступать, если в нём содержится хотя бы один предмет.
|
||||
The side inputs are only powered by normal redstone power. The redstone comparator can operate in two modes: Transmission mode and subtraction mode. It starts in transmission mode and the mode can be changed by using the block.=К боковым входам можно подводить только обычную энергию редстоуна. Компаратор может работать в двух режимах: ПЕРЕДАЧА и ВЫЧИТАНИЕ. Он изначально находится в режиме передачи; режим меняется при [Использовании] данного блока.
|
||||
Transmission mode:@nThe front torch is unlit and lowered. The output is powered if, and only if the main input is powered. The two side inputs are ignored.=Режим ПЕРЕДАЧИ:@nПередний индикатор погашен. На выходе появляется энергия редстоуна, только если она подаётся на основной вход. Состояние боковых входов при этом игнорируются.
|
||||
Subtraction mode:@nThe front torch is lit. The output is powered if, and only if the main input is powered and none of the side inputs is powered.=Режим ВЫЧИТАНИЯ:@nПередний индикатор светится. На выходе есть сигнал только в том случае, если сигнал есть на основной входе, но при этом его нет ни на одном из боковых входов.
|
||||
Redstone Comparator=Компаратор
|
||||
Redstone Comparator (Subtract)=Компаратор (ВЫЧИТАНИЕ)
|
||||
Redstone Comparator (Powered)=Компаратор (ВКЛЮЧЁН)
|
||||
Redstone Comparator (Subtract, Powered)=Компаратор (ВЫЧИТАНИЕ, ВКЛЮЧЁН)
|
|
@ -1,12 +0,0 @@
|
|||
# textdomain: mcl_comparators
|
||||
Redstone comparators are multi-purpose redstone components.=
|
||||
They can transmit a redstone signal, detect whether a block contains any items and compare multiple signals.=
|
||||
A redstone comparator has 1 main input, 2 side inputs and 1 output. The output is in arrow direction, the main input is in the opposite direction. The other 2 sides are the side inputs.=
|
||||
The main input can powered in 2 ways: First, it can be powered directly by redstone power like any other component. Second, it is powered if, and only if a container (like a chest) is placed in front of it and the container contains at least one item.=
|
||||
The side inputs are only powered by normal redstone power. The redstone comparator can operate in two modes: Transmission mode and subtraction mode. It starts in transmission mode and the mode can be changed by using the block.=
|
||||
Transmission mode:@nThe front torch is unlit and lowered. The output is powered if, and only if the main input is powered. The two side inputs are ignored.=
|
||||
Subtraction mode:@nThe front torch is lit. The output is powered if, and only if the main input is powered and none of the side inputs is powered.=
|
||||
Redstone Comparator=
|
||||
Redstone Comparator (Subtract)=
|
||||
Redstone Comparator (Powered)=
|
||||
Redstone Comparator (Subtract, Powered)=
|
|
@ -1,3 +0,0 @@
|
|||
name = mcl_comparators
|
||||
depends = mcl_wip, mesecons, mcl_sounds
|
||||
optional_depends = doc, screwdriver
|
Before Width: | Height: | Size: 102 B |
Before Width: | Height: | Size: 145 B |
Before Width: | Height: | Size: 167 B |
Before Width: | Height: | Size: 167 B |
Before Width: | Height: | Size: 155 B |
Before Width: | Height: | Size: 278 B |
Before Width: | Height: | Size: 233 B |
Before Width: | Height: | Size: 562 B |
Before Width: | Height: | Size: 140 B |
Before Width: | Height: | Size: 167 B |
Before Width: | Height: | Size: 167 B |
Before Width: | Height: | Size: 154 B |
Before Width: | Height: | Size: 102 B |
|
@ -1,221 +0,0 @@
|
|||
--[[ This mod registers 3 nodes:
|
||||
- One node for the horizontal-facing dropper (mcl_droppers:dropper)
|
||||
- One node for the upwards-facing droppers (mcl_droppers:dropper_up)
|
||||
- One node for the downwards-facing droppers (mcl_droppers:dropper_down)
|
||||
|
||||
3 node definitions are needed because of the way the textures are defined.
|
||||
All node definitions share a lot of code, so this is the reason why there
|
||||
are so many weird tables below.
|
||||
]]
|
||||
|
||||
local S = minetest.get_translator(minetest.get_current_modname())
|
||||
|
||||
-- For after_place_node
|
||||
local function setup_dropper(pos)
|
||||
-- Set formspec and inventory
|
||||
local form = "size[9,8.75]"..
|
||||
"label[0,4.0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Inventory"))).."]"..
|
||||
"list[current_player;main;0,4.5;9,3;9]"..
|
||||
mcl_formspec.get_itemslot_bg(0,4.5,9,3)..
|
||||
"list[current_player;main;0,7.74;9,1;]"..
|
||||
mcl_formspec.get_itemslot_bg(0,7.74,9,1)..
|
||||
"label[3,0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Dropper"))).."]"..
|
||||
"list[context;main;3,0.5;3,3;]"..
|
||||
mcl_formspec.get_itemslot_bg(3,0.5,3,3)..
|
||||
"listring[context;main]"..
|
||||
"listring[current_player;main]"
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_string("formspec", form)
|
||||
local inv = meta:get_inventory()
|
||||
inv:set_size("main", 9)
|
||||
end
|
||||
|
||||
local function orientate_dropper(pos, placer)
|
||||
-- Not placed by player
|
||||
if not placer then return end
|
||||
|
||||
-- Pitch in degrees
|
||||
local pitch = placer:get_look_vertical() * (180 / math.pi)
|
||||
|
||||
if pitch > 55 then
|
||||
minetest.swap_node(pos, {name="mcl_droppers:dropper_up"})
|
||||
elseif pitch < -55 then
|
||||
minetest.swap_node(pos, {name="mcl_droppers:dropper_down"})
|
||||
end
|
||||
end
|
||||
|
||||
local on_rotate
|
||||
if minetest.get_modpath("screwdriver") then
|
||||
on_rotate = screwdriver.rotate_simple
|
||||
end
|
||||
|
||||
-- Shared core definition table
|
||||
local dropperdef = {
|
||||
is_ground_content = false,
|
||||
sounds = mcl_sounds.node_sound_stone_defaults(),
|
||||
after_dig_node = function(pos, oldnode, oldmetadata, digger)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local meta2 = meta:to_table()
|
||||
meta:from_table(oldmetadata)
|
||||
local inv = meta:get_inventory()
|
||||
for i=1, inv:get_size("main") do
|
||||
local stack = inv:get_stack("main", i)
|
||||
if not stack:is_empty() then
|
||||
local p = {x=pos.x+math.random(0, 10)/10-0.5, y=pos.y, z=pos.z+math.random(0, 10)/10-0.5}
|
||||
minetest.add_item(p, stack)
|
||||
end
|
||||
end
|
||||
meta:from_table(meta2)
|
||||
end,
|
||||
allow_metadata_inventory_move = function(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,
|
||||
allow_metadata_inventory_take = function(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,
|
||||
allow_metadata_inventory_put = function(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,
|
||||
_mcl_blast_resistance = 3.5,
|
||||
_mcl_hardness = 3.5,
|
||||
mesecons = {effector = {
|
||||
-- Drop random item when triggered
|
||||
action_on = function(pos, node)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local inv = meta:get_inventory()
|
||||
local droppos
|
||||
if node.name == "mcl_droppers:dropper" then
|
||||
droppos = vector.subtract(pos, minetest.facedir_to_dir(node.param2))
|
||||
elseif node.name == "mcl_droppers:dropper_up" then
|
||||
droppos = {x=pos.x, y=pos.y+1, z=pos.z}
|
||||
elseif node.name == "mcl_droppers:dropper_down" then
|
||||
droppos = {x=pos.x, y=pos.y-1, z=pos.z}
|
||||
end
|
||||
local dropnode = minetest.get_node(droppos)
|
||||
-- Do not drop into solid nodes, unless they are containers
|
||||
local dropnodedef = minetest.registered_nodes[dropnode.name]
|
||||
if dropnodedef.walkable and not dropnodedef.groups.container then
|
||||
return
|
||||
end
|
||||
local stacks = {}
|
||||
for i=1,inv:get_size("main") do
|
||||
local stack = inv:get_stack("main", i)
|
||||
if not stack:is_empty() then
|
||||
table.insert(stacks, {stack = stack, stackpos = i})
|
||||
end
|
||||
end
|
||||
if #stacks >= 1 then
|
||||
local r = math.random(1, #stacks)
|
||||
local stack = stacks[r].stack
|
||||
local dropitem = ItemStack(stack)
|
||||
dropitem:set_count(1)
|
||||
local stack_id = stacks[r].stackpos
|
||||
|
||||
-- If it's a container, attempt to put it into the container
|
||||
local dropped = mcl_util.move_item_container(pos, droppos, nil, stack_id)
|
||||
-- No container?
|
||||
if not dropped and not dropnodedef.groups.container then
|
||||
-- Drop item normally
|
||||
minetest.add_item(droppos, dropitem)
|
||||
stack:take_item()
|
||||
inv:set_stack("main", stack_id, stack)
|
||||
end
|
||||
end
|
||||
end,
|
||||
rules = mesecon.rules.alldirs,
|
||||
}},
|
||||
on_rotate = on_rotate,
|
||||
}
|
||||
|
||||
-- Horizontal dropper
|
||||
|
||||
local horizontal_def = table.copy(dropperdef)
|
||||
horizontal_def.description = S("Dropper")
|
||||
horizontal_def._tt_help = S("9 inventory slots").."\n"..S("Drops item when powered by redstone power")
|
||||
horizontal_def._doc_items_longdesc = S("A dropper is a redstone component and a container with 9 inventory slots which, when supplied with redstone power, drops an item or puts it into a container in front of it.")
|
||||
horizontal_def._doc_items_usagehelp = S("Droppers can be placed in 6 possible directions, items will be dropped out of the hole. Use the dropper to access its inventory. Supply it with redstone energy once to make the dropper drop or transfer a random item.")
|
||||
function horizontal_def.after_place_node(pos, placer, itemstack, pointed_thing)
|
||||
setup_dropper(pos)
|
||||
orientate_dropper(pos, placer)
|
||||
end
|
||||
horizontal_def.tiles = {
|
||||
"default_furnace_top.png", "default_furnace_bottom.png",
|
||||
"default_furnace_side.png", "default_furnace_side.png",
|
||||
"default_furnace_side.png", "mcl_droppers_dropper_front_horizontal.png"
|
||||
}
|
||||
horizontal_def.paramtype2 = "facedir"
|
||||
horizontal_def.groups = {pickaxey=1, container=2, material_stone=1}
|
||||
|
||||
minetest.register_node("mcl_droppers:dropper", horizontal_def)
|
||||
|
||||
-- Down dropper
|
||||
local down_def = table.copy(dropperdef)
|
||||
down_def.description = S("Downwards-Facing Dropper")
|
||||
down_def.after_place_node = setup_dropper
|
||||
down_def.tiles = {
|
||||
"default_furnace_top.png", "mcl_droppers_dropper_front_vertical.png",
|
||||
"default_furnace_side.png", "default_furnace_side.png",
|
||||
"default_furnace_side.png", "default_furnace_side.png"
|
||||
}
|
||||
down_def.groups = {pickaxey=1, container=2,not_in_creative_inventory=1, material_stone=1}
|
||||
down_def._doc_items_create_entry = false
|
||||
down_def.drop = "mcl_droppers:dropper"
|
||||
minetest.register_node("mcl_droppers:dropper_down", down_def)
|
||||
|
||||
-- Up dropper
|
||||
-- The up dropper is almost identical to the down dropper, it only differs in textures
|
||||
local up_def = table.copy(down_def)
|
||||
up_def.description = S("Upwards-Facing Dropper")
|
||||
up_def.tiles = {
|
||||
"mcl_droppers_dropper_front_vertical.png", "default_furnace_bottom.png",
|
||||
"default_furnace_side.png", "default_furnace_side.png",
|
||||
"default_furnace_side.png", "default_furnace_side.png"
|
||||
}
|
||||
minetest.register_node("mcl_droppers:dropper_up", up_def)
|
||||
|
||||
|
||||
|
||||
-- Ladies and gentlemen, I present to you: the crafting recipe!
|
||||
minetest.register_craft({
|
||||
output = "mcl_droppers:dropper",
|
||||
recipe = {
|
||||
{"mcl_core:cobble", "mcl_core:cobble", "mcl_core:cobble",},
|
||||
{"mcl_core:cobble", "", "mcl_core:cobble",},
|
||||
{"mcl_core:cobble", "mesecons:redstone", "mcl_core:cobble",},
|
||||
}
|
||||
})
|
||||
|
||||
-- Add entry aliases for the Help
|
||||
if minetest.get_modpath("doc") then
|
||||
doc.add_entry_alias("nodes", "mcl_droppers:dropper", "nodes", "mcl_droppers:dropper_down")
|
||||
doc.add_entry_alias("nodes", "mcl_droppers:dropper", "nodes", "mcl_droppers:dropper_up")
|
||||
end
|
||||
|
||||
-- Legacy
|
||||
minetest.register_lbm({
|
||||
label = "Update dropper formspecs (0.60.0)",
|
||||
name = "mcl_droppers:update_formspecs_0_60_0",
|
||||
nodenames = { "mcl_droppers:dropper", "mcl_droppers:dropper_down", "mcl_droppers:dropper_up" },
|
||||
action = function(pos, node)
|
||||
setup_dropper(pos)
|
||||
minetest.log("action", "[mcl_droppers] Node formspec updated at "..minetest.pos_to_string(pos))
|
||||
end,
|
||||
})
|
|
@ -1,9 +0,0 @@
|
|||
# textdomain: mcl_droppers
|
||||
Dropper=Spender
|
||||
A dropper is a redstone component and a container with 9 inventory slots which, when supplied with redstone power, drops an item or puts it into a container in front of it.=Ein Spender ist eine Redstonekomponente und ein Behälter mit 9 Inventarplätzen. Er wird, wenn mit Redstoneenergie versorgt, einen Gegenstand abwerfen oder in einen Behälter, auf den er zeigt, ablegen.
|
||||
Droppers can be placed in 6 possible directions, items will be dropped out of the hole. Use the dropper to access its inventory. Supply it with redstone energy once to make the dropper drop or transfer a random item.=Spender können in 6 mögliche Richtungen platziert werden, Gegenstände fallen aus dem Loch hinaus. Benutzen Sie den Spender, um auf sein Inventar zuzugreifen. Versorgen Sie ihn mit Redstoneenergie, um den Spender einen Gegenstand abwerfen oder in einen Behälter ablegen zu lassen.
|
||||
Downwards-Facing Dropper=Nach unten zeigender Spender
|
||||
Upwards-Facing Dropper=Nach oben zeigender Spender
|
||||
Inventory=Inventar
|
||||
9 inventory slots=9 Inventarplätze
|
||||
Drops item when powered by redstone power=Gibt einen Gegenstand aus, wenn mit Redstoneenergie versorgt
|
|
@ -1,7 +0,0 @@
|
|||
# textdomain: mcl_droppers
|
||||
Dropper=Soltador
|
||||
A dropper is a redstone component and a container with 9 inventory slots which, when supplied with redstone power, drops an item or puts it into a container in front of it.=Un Soltador es un componente de redstone y un contenedor con 9 ranuras de inventario que, cuando se suministra con redstone power, deja caer un artículo o lo coloca en un contenedor frente a él.
|
||||
Droppers can be placed in 6 possible directions, items will be dropped out of the hole. Use the dropper to access its inventory. Supply it with redstone energy once to make the dropper drop or transfer a random item.=Los soltadores se pueden colocar en 6 direcciones posibles, los artículos se sacarán del agujero. Usa el cuentagotas para acceder a su inventario. Proporcione energía de redstone una vez para hacer que el soltador caiga o transfiera un elemento aleatorio.
|
||||
Downwards-Facing Dropper=Soltador orientado hacia abajo
|
||||
Upwards-Facing Dropper=Soltador orientado hacia arriba
|
||||
Inventory=Inventario
|
|
@ -1,9 +0,0 @@
|
|||
# textdomain: mcl_droppers
|
||||
Dropper=Dropper
|
||||
A dropper is a redstone component and a container with 9 inventory slots which, when supplied with redstone power, drops an item or puts it into a container in front of it.=Un dropper est un composant redstone et un conteneur avec 9 emplacements d'inventaire qui, lorsqu'ils sont alimentés en puissance redstone, déposent un objet ou le placent dans un conteneur en face de lui.
|
||||
Droppers can be placed in 6 possible directions, items will be dropped out of the hole. Use the dropper to access its inventory. Supply it with redstone energy once to make the dropper drop or transfer a random item.=Les droppers peuvent être placés dans 6 directions possibles, les objets seront déposés hors du trou. Utilisez le dropper pour accéder à son inventaire. Fournissez-lui de l'énergie redstone pour faire tomber un élement ou transférer un élément aléatoire.
|
||||
Downwards-Facing Dropper=Dropper orienté vers le bas
|
||||
Upwards-Facing Dropper=Dropper orienté vers le haut
|
||||
Inventory=Inventaire
|
||||
9 inventory slots=9 emplacements d'inventaire
|
||||
Drops item when powered by redstone power=Obtient un objet lorsqu'il est alimenté par la puissance Redstone
|
|
@ -1,9 +0,0 @@
|
|||
# textdomain: mcl_droppers
|
||||
Dropper=Podajnik
|
||||
A dropper is a redstone component and a container with 9 inventory slots which, when supplied with redstone power, drops an item or puts it into a container in front of it.=Podajnik jest urządzeniem czerwienitowym i pojemnikiem z 9 miejscami, który po dostarczeniu energii czerwienitowej wyrzuca przedmiot lub umieszcza go w pojemniku przed nim.
|
||||
Droppers can be placed in 6 possible directions, items will be dropped out of the hole. Use the dropper to access its inventory. Supply it with redstone energy once to make the dropper drop or transfer a random item.=Podajniki mogą być skierowane w 6 możliwych kierunkach, przedmioty będą wyrzucane z dziury. Użyj podajnika aby zyskać dostęp do jego ekwipunku. Dostarcz do niego energii czerwienitowej aby sprawić by wyrzucił lub przeniósł losowy przedmiot.
|
||||
Downwards-Facing Dropper=Podajnik skierowany w dół
|
||||
Upwards-Facing Dropper=Podajnik skierowany w górę
|
||||
Inventory=Ekwipunek
|
||||
9 inventory slots=9 miejsc ekwipunku
|
||||
Drops item when powered by redstone power=Wyrzuca przedmiot gdy zasilony czerwienitem
|
|
@ -1,9 +0,0 @@
|
|||
# textdomain: mcl_droppers
|
||||
Dropper=Выбрасыватель
|
||||
A dropper is a redstone component and a container with 9 inventory slots which, when supplied with redstone power, drops an item or puts it into a container in front of it.=Выбрасыватель это элемент редстоуна и контейнер с 9 отсеками инвентаря, срабатывающий по сигналу редстоуна и выбрасывающий предмет, либо выталкивающий его в контейнер, стоящий перед ним.
|
||||
Droppers can be placed in 6 possible directions, items will be dropped out of the hole. Use the dropper to access its inventory. Supply it with redstone energy once to make the dropper drop or transfer a random item.=Выбрасыватель может быть установлен в 6 возможных направлениях, предметы будут выбрасываться в соответствующем направлении из отверстия. [Используйте] выбрасыватель для доступа к его инвентарю. Подайте на него энергию редстоуна однократно, чтобы заставить его выбросить либо предать один случайный предмет.
|
||||
Downwards-Facing Dropper=Выбрасыватель, смотрящий вниз
|
||||
Upwards-Facing Dropper=Выбрасыватель, смотрящий вверх
|
||||
Inventory=Инвентарь
|
||||
9 inventory slots=9 отсеков инвентаря
|
||||
Drops item when powered by redstone power=Выбрасывает предмет при подаче энергии редстоуна
|
|
@ -1,9 +0,0 @@
|
|||
# textdomain: mcl_droppers
|
||||
Dropper=
|
||||
A dropper is a redstone component and a container with 9 inventory slots which, when supplied with redstone power, drops an item or puts it into a container in front of it.=
|
||||
Droppers can be placed in 6 possible directions, items will be dropped out of the hole. Use the dropper to access its inventory. Supply it with redstone energy once to make the dropper drop or transfer a random item.=
|
||||
Downwards-Facing Dropper=
|
||||
Upwards-Facing Dropper=
|
||||
Inventory=
|
||||
9 inventory slots=
|
||||
Drops item when powered by redstone power=
|
|
@ -1,3 +0,0 @@
|
|||
name = mcl_droppers
|
||||
depends = mcl_init, mcl_formspec, mesecons, mcl_util
|
||||
optional_depends = doc, screwdriver
|
Before Width: | Height: | Size: 265 B |
Before Width: | Height: | Size: 251 B |