Merge branch 'master' into Axolotl

This commit is contained in:
TheOnlyJoeEnderman 2022-10-28 07:18:37 +00:00
commit b1355513dd
279 changed files with 3328 additions and 1105 deletions

View file

@ -33,6 +33,7 @@
* RandomLegoBrick * RandomLegoBrick
* SumianVoice * SumianVoice
* MrRar * MrRar
* talamh
## Contributors ## Contributors
* Laurent Rocher * Laurent Rocher
@ -66,7 +67,6 @@
* Benjamin Schötz * Benjamin Schötz
* Doloment * Doloment
* Sydney Gems * Sydney Gems
* talamh
* Emily2255 * Emily2255
* Emojigit * Emojigit
* FinishedFragment * FinishedFragment
@ -85,6 +85,10 @@
* opfromthestart * opfromthestart
* snowyu * snowyu
* FaceDeer * FaceDeer
* Faerraven / Michieal
* FossFanatic
* Herbert West
* GuyLiner
## MineClone5 ## MineClone5
* kay27 * kay27
@ -95,7 +99,7 @@
* chmodsayshello * chmodsayshello
* 3raven * 3raven
* PrairieWind * PrairieWind
* Gustavo1 * Gustavo6046 / wallabra
* CableGuy67 * CableGuy67
* MrRar * MrRar

View file

@ -2,7 +2,7 @@
An unofficial Minecraft-like game for Minetest. Forked from MineClone by davedevils. An unofficial Minecraft-like game for Minetest. Forked from MineClone by davedevils.
Developed by many people. Not developed or endorsed by Mojang AB. Developed by many people. Not developed or endorsed by Mojang AB.
Version: 0.80 (in development) Version: 0.81 (in development)
### Gameplay ### Gameplay
You start in a randomly-generated world made entirely of cubes. You can explore You start in a randomly-generated world made entirely of cubes. You can explore

View file

@ -5,6 +5,8 @@
-- Nodes in group "supported_node" can be placed on any node that does not -- Nodes in group "supported_node" can be placed on any node that does not
-- have the "airlike" drawtype. Carpets are an example of this type. -- have the "airlike" drawtype. Carpets are an example of this type.
local pairs = pairs
local math = math
local vector = vector local vector = vector
local facedir_to_dir = minetest.facedir_to_dir local facedir_to_dir = minetest.facedir_to_dir
@ -22,15 +24,17 @@ local add_item = minetest.add_item
-- We need this to do the exact same dropping node handling in our override -- We need this to do the exact same dropping node handling in our override
-- minetest.check_single_for_falling() function as in the builtin function. -- minetest.check_single_for_falling() function as in the builtin function.
-- --
---@param p Vector
local function drop_attached_node(p) local function drop_attached_node(p)
local n = get_node(p) local n = get_node(p)
local drops = get_node_drops(n, "") local drops = get_node_drops(n, "")
local def = registered_nodes[n.name] local def = registered_nodes[n.name]
if def and def.preserve_metadata then if def and def.preserve_metadata then
local oldmeta = get_meta(p):to_table().fields local oldmeta = get_meta(p):to_table().fields
-- Copy pos and node because the callback can modify them. -- Copy pos and node because the callback can modify them.
local pos_copy = vector.new(p) local pos_copy = vector.copy(p)
local node_copy = {name=n.name, param1=n.param1, param2=n.param2} local node_copy = { name = n.name, param1 = n.param1, param2 = n.param2 }
local drop_stacks = {} local drop_stacks = {}
for k, v in pairs(drops) do for k, v in pairs(drops) do
drop_stacks[k] = ItemStack(v) drop_stacks[k] = ItemStack(v)
@ -38,16 +42,18 @@ local function drop_attached_node(p)
drops = drop_stacks drops = drop_stacks
def.preserve_metadata(pos_copy, node_copy, oldmeta, drops) def.preserve_metadata(pos_copy, node_copy, oldmeta, drops)
end end
if def and def.sounds and def.sounds.fall then if def and def.sounds and def.sounds.fall then
core.sound_play(def.sounds.fall, {pos = p}, true) minetest.sound_play(def.sounds.fall, { pos = p }, true)
end end
remove_node(p) remove_node(p)
for _, item in pairs(drops) do for _, item in pairs(drops) do
local pos = { local pos = vector.offset(p,
x = p.x + math.random()/2 - 0.25, math.random() / 2 - 0.25,
y = p.y + math.random()/2 - 0.25, math.random() / 2 - 0.25,
z = p.z + math.random()/2 - 0.25, math.random() / 2 - 0.25
} )
add_item(pos, item) add_item(pos, item)
end end
end end
@ -90,4 +96,3 @@ function minetest.check_single_for_falling(pos)
return false return false
end end

View file

@ -12,6 +12,7 @@ mcl_damage = {
drown = {bypasses_armor = true}, drown = {bypasses_armor = true},
starve = {bypasses_armor = true, bypasses_magic = true}, starve = {bypasses_armor = true, bypasses_magic = true},
cactus = {}, cactus = {},
sweet_berry = {},
fall = {bypasses_armor = true}, fall = {bypasses_armor = true},
fly_into_wall = {bypasses_armor = true}, -- unused fly_into_wall = {bypasses_armor = true}, -- unused
out_of_world = {bypasses_armor = true, bypasses_magic = true, bypasses_invulnerability = true, bypasses_totem = true}, out_of_world = {bypasses_armor = true, bypasses_magic = true, bypasses_invulnerability = true, bypasses_totem = true},

View file

@ -130,10 +130,10 @@ local function add_particles(pos, radius)
time = 0.125, time = 0.125,
minpos = pos, minpos = pos,
maxpos = pos, maxpos = pos,
minvel = {x = -radius, y = -radius, z = -radius}, minvel = vector.new(-radius, -radius, -radius),
maxvel = {x = radius, y = radius, z = radius}, maxvel = vector.new(radius, radius, radius),
minacc = vector.new(), minacc = vector.zero(),
maxacc = vector.new(), maxacc = vector.zero(),
minexptime = 0.5, minexptime = 0.5,
maxexptime = 1.0, maxexptime = 1.0,
minsize = radius * 0.5, minsize = radius * 0.5,
@ -288,7 +288,7 @@ local function trace_explode(pos, strength, raydirs, radius, info, direct, sourc
rdir_y = rdir_y / rdir_len rdir_y = rdir_y / rdir_len
rdir_z = rdir_z / rdir_len rdir_z = rdir_z / rdir_len
for i=0, rdir_len / STEP_LENGTH do for i = 0, rdir_len / STEP_LENGTH do
rpos_x = rpos_x + rdir_x * STEP_LENGTH rpos_x = rpos_x + rdir_x * STEP_LENGTH
rpos_y = rpos_y + rdir_y * STEP_LENGTH rpos_y = rpos_y + rdir_y * STEP_LENGTH
rpos_z = rpos_z + rdir_z * STEP_LENGTH rpos_z = rpos_z + rdir_z * STEP_LENGTH
@ -333,16 +333,17 @@ local function trace_explode(pos, strength, raydirs, radius, info, direct, sourc
end end
if sleep_formspec_doesnt_close_mt53 then if sleep_formspec_doesnt_close_mt53 then
minetest.after(0.3, function() -- 0.2 is minimum delay for closing old formspec and open died formspec -- TODO: REMOVE THIS IN THE FUTURE minetest.after(0.3,
function() -- 0.2 is minimum delay for closing old formspec and open died formspec -- TODO: REMOVE THIS IN THE FUTURE
if not obj:is_player() then if not obj:is_player() then
return return
end end
mcl_util.deal_damage(obj, damage, {type = "explosion", direct = direct, source = source}) mcl_util.deal_damage(obj, damage, { type = "explosion", direct = direct, source = source })
obj:add_velocity(vector.multiply(punch_dir, impact * 20)) obj:add_velocity(vector.multiply(punch_dir, impact * 20))
end) end)
else else
mcl_util.deal_damage(obj, damage, {type = "explosion", direct = direct, source = source}) mcl_util.deal_damage(obj, damage, { type = "explosion", direct = direct, source = source })
if obj:is_player() or ent.tnt_knockback then if obj:is_player() or ent.tnt_knockback then
obj:add_velocity(vector.multiply(punch_dir, impact * 20)) obj:add_velocity(vector.multiply(punch_dir, impact * 20))
@ -388,23 +389,24 @@ local function trace_explode(pos, strength, raydirs, radius, info, direct, sourc
-- We use bulk_set_node instead of LVM because we want to have on_destruct and -- We use bulk_set_node instead of LVM because we want to have on_destruct and
-- on_construct being called -- on_construct being called
if #airs > 0 then if #airs > 0 then
bulk_set_node(airs, {name="air"}) bulk_set_node(airs, { name = "air" })
end end
if #fires > 0 then if #fires > 0 then
bulk_set_node(fires, {name="mcl_fire:fire"}) bulk_set_node(fires, { name = "mcl_fire:fire" })
end end
-- Update falling nodes -- Update falling nodes
for a=1, #airs do for a = 1, #airs do
local p = airs[a] local p = airs[a]
check_for_falling({x=p.x, y=p.y+1, z=p.z}) check_for_falling(vector.offset(p, 0, 1, 0))
end end
for f=1, #fires do for f = 1, #fires do
local p = fires[f] local p = fires[f]
check_for_falling({x=p.x, y=p.y+1, z=p.z}) check_for_falling(vector.offset(p, 0, 1, 0))
end end
-- Log explosion -- Log explosion
minetest.log("action", "Explosion at "..pos_to_string(pos).." with strength "..strength.." and radius "..radius) minetest.log("action", "Explosion at " .. pos_to_string(pos) .. " with strength " .. strength .. " and radius " ..
radius)
end end
-- Create an explosion with strength at pos. -- Create an explosion with strength at pos.
@ -428,6 +430,11 @@ end
-- griefing - If true, the explosion will destroy nodes (default: true) -- griefing - If true, the explosion will destroy nodes (default: true)
-- grief_protected - If true, the explosion will also destroy nodes which have -- grief_protected - If true, the explosion will also destroy nodes which have
-- been protected (default: false) -- been protected (default: false)
---@param pos Vector
---@param strength number
---@param info {drop_chance: number, max_blast_resistance: number, sound: boolean, particles: boolean, fire: boolean, griefing: boolean, grief_protected: boolean}
---@param direct? ObjectRef
---@param source? ObjectRef
function mcl_explosions.explode(pos, strength, info, direct, source) function mcl_explosions.explode(pos, strength, info, direct, source)
if info == nil then if info == nil then
info = {} info = {}

View file

@ -0,0 +1,36 @@
# mcl_dripping
Dripping Mod by kddekadenz, modified for MineClone 2 by Wuzzy, NO11 and AFCM
## Manual
- drops are generated rarely under solid nodes
- they will stay some time at the generated block and than they fall down
- when they collide with the ground, a sound is played and they are destroyed
Water and Lava have builtin drops registered.
## License
code & sounds: CC0
## API
```lua
mcl_dripping.register_drop({
-- The group the liquid's nodes belong to
liquid = "water",
-- The texture used (particles will take a random 2x2 area of it)
texture = "default_water_source_animated.png",
-- Define particle glow, ranges from `0` to `minetest.LIGHT_MAX`
light = 1,
-- The nodes (or node group) the particles will spawn under
nodes = { "group:opaque", "group:leaves" },
-- The sound that will be played then the particle detaches from the roof, see SimpleSoundSpec in lua_api.txt
sound = "drippingwater_drip",
-- The interval for the ABM to run
interval = 60,
-- The chance of the ABM
chance = 10,
})
```

View file

@ -3,53 +3,98 @@
-- License of code, textures & sounds: CC0 -- License of code, textures & sounds: CC0
local math = math local math = math
local function make_drop(pos,liquid,sound,interval)
mcl_dripping = {}
---@param pos Vector
---@param liquid string
---@param sound SimpleSoundSpec
---@param interval integer
---@param texture string
local function make_drop(pos, liquid, sound, interval, texture)
local pt = { local pt = {
velocity = vector.new(0,0,0), velocity = vector.zero(),
collision_removal = false, collision_removal = false,
} }
local t = math.random() + math.random(1, interval) local t = math.random() + math.random(1, interval)
minetest.after(t,function()
minetest.after(t, function()
local x, z = math.random(-45, 45) / 100, math.random(-45, 45) / 100 local x, z = math.random(-45, 45) / 100, math.random(-45, 45) / 100
pt.pos = vector.offset(pos,x,-0.52,z)
pt.acceleration = vector.new(0,0,0) pt.pos = vector.offset(pos, x, -0.52, z)
pt.acceleration = vector.zero()
pt.collisiondetection = false pt.collisiondetection = false
pt.expirationtime = t pt.expirationtime = t
pt.texture="[combine:2x2:" .. -math.random(1, 16) .. "," .. -math.random(1, 16) .. "=default_" .. liquid .. "_source_animated.png" pt.texture = "[combine:2x2:" ..
-math.random(1, 16) .. "," .. -math.random(1, 16) .. "=" .. texture
minetest.add_particle(pt) minetest.add_particle(pt)
minetest.after(t,function()
pt.acceleration = vector.new(0,-5,0) minetest.after(t, function()
pt.acceleration = vector.new(0, -5, 0)
pt.collisiondetection = true pt.collisiondetection = true
pt.expirationtime = math.random() + math.random(1, interval/2) pt.expirationtime = math.random() + math.random(1, interval / 2)
minetest.add_particle(pt) minetest.add_particle(pt)
minetest.sound_play({name = "drippingwater_" .. sound .. "drip"}, {pos = pos, gain = 0.5, max_hear_distance = 8}, true)
minetest.sound_play(sound, { pos = pos, gain = 0.5, max_hear_distance = 8 },
true)
end) end)
end) end)
end end
local function register_drop(liquid, glow, sound, nodes, interval, chance) ---@class mcl_dripping_drop_definition
---@field liquid string The group the liquid's nodes belong to
---@field texture string The texture used (particles will take a random 2x2 area of it)
---@field light integer Define particle glow, ranges from `0` to `minetest.LIGHT_MAX`
---@field nodes string[] The nodes (or node group) the particles will spawn under
---@field interval integer The interval for the ABM to run
---@field chance integer The chance of the ABM
---@field sound SimpleSoundSpec The sound that will be played then the particle detaches from the roof
---@param def mcl_dripping_drop_definition
function mcl_dripping.register_drop(def)
minetest.register_abm({ minetest.register_abm({
label = "Create drops", label = "Create drops",
nodenames = nodes, nodenames = def.nodes,
neighbors = {"group:" .. liquid}, neighbors = { "group:" .. def.liquid },
interval = interval, interval = def.interval,
chance = chance, chance = def.chance,
action = function(pos) action = function(pos)
local r = math.ceil(interval / 20) local r = math.ceil(def.interval / 20)
local nn=minetest.find_nodes_in_area(vector.offset(pos,-r,0,-r),vector.offset(pos,r,0,r),nodes) local nn = minetest.find_nodes_in_area(vector.offset(pos, -r, 0, -r), vector.offset(pos, r, 0, r), def.nodes)
--start a bunch of particle cycles to be able to get away --start a bunch of particle cycles to be able to get away
--with longer abm cycles --with longer abm cycles
table.shuffle(nn) table.shuffle(nn)
for i=1,math.random(#nn) do for i = 1, math.random(#nn) do
if minetest.get_item_group(minetest.get_node(vector.offset(nn[i], 0, 1, 0)).name, liquid) ~= 0 if minetest.get_item_group(minetest.get_node(vector.offset(nn[i], 0, 1, 0)).name, def.liquid) ~= 0
and minetest.get_node(vector.offset(nn[i], 0, -1, 0)).name == "air" then and minetest.get_node(vector.offset(nn[i], 0, -1, 0)).name == "air" then
make_drop(nn[i],liquid,sound,interval) make_drop(nn[i], def.liquid, def.sound, def.interval, def.texture)
end end
end end
end, end,
}) })
end end
register_drop("water", 1, "", {"group:opaque", "group:leaves"},60,10) mcl_dripping.register_drop({
register_drop("lava", math.max(7, minetest.registered_nodes["mcl_core:lava_source"].light_source - 3), "lava", {"group:opaque"},60,10) liquid = "water",
texture = "default_water_source_animated.png",
light = 1,
nodes = { "group:opaque", "group:leaves" },
sound = "drippingwater_drip",
interval = 60,
chance = 10,
})
mcl_dripping.register_drop({
liquid = "lava",
texture = "default_lava_source_animated.png",
light = math.max(7, minetest.registered_nodes["mcl_core:lava_source"].light_source - 3),
nodes = { "group:opaque" },
sound = "drippingwater_lavadrip",
interval = 60,
chance = 10,
})

View file

@ -1,29 +0,0 @@
Dripping Mod
by kddekadenz
modified for MineClone 2 by Wuzzy and NO11
Installing instructions:
1. Copy the mcl_dripping mod folder into games/gamemode/mods
2. Start game and enjoy :)
Manual:
-> drops are generated rarely under solid nodes
-> they will stay some time at the generated block and than they fall down
-> when they collide with the ground, a sound is played and they are destroyed
License:
code & sounds: CC0
Changelog:
16.04.2012 - first release
28.04.2012 - drops are now 3D; added lava drops; fixed generating of drops (not at edges now)

View file

@ -13,9 +13,19 @@ local FLOP_HOR_SPEED = 1.5
local ENTITY_CRAMMING_MAX = 24 local ENTITY_CRAMMING_MAX = 24
local CRAMMING_DAMAGE = 3 local CRAMMING_DAMAGE = 3
local PATHFINDING = "gowp"
-- Localize -- Localize
local S = minetest.get_translator("mcl_mobs") local S = minetest.get_translator("mcl_mobs")
local LOGGING_ON = minetest.settings:get_bool("mcl_logging_mobs_villager",false)
local LOG_MODULE = "[Mobs]"
local function mcl_log (message)
if LOGGING_ON and message then
minetest.log(LOG_MODULE .. " " .. message)
end
end
local function shortest_term_of_yaw_rotatoin(self, rot_origin, rot_target, nums) local function shortest_term_of_yaw_rotatoin(self, rot_origin, rot_target, nums)
if not rot_origin or not rot_target then if not rot_origin or not rot_target then
@ -404,21 +414,20 @@ local set_yaw = function(self, yaw, delay, dtime)
if self.noyaw then return end if self.noyaw then return end
if self._kb_turn then
self._turn_to = yaw self._turn_to = yaw
end
--clamp our yaw to a 360 range --clamp our yaw to a 360 range
if math.deg(self.object:get_yaw()) > 360 then if math.deg(self.object:get_yaw()) > 360 then
self.object:set_yaw(math.rad(10)) self.object:set_yaw(math.rad(1))
elseif math.deg(self.object:get_yaw()) < 0 then elseif math.deg(self.object:get_yaw()) < 0 then
self.object:set_yaw(math.rad(350)) self.object:set_yaw(math.rad(359))
end end
--calculate the shortest way to turn to find our target --calculate the shortest way to turn to find our target
local target_shortest_path = shortest_term_of_yaw_rotatoin(self, self.object:get_yaw(), yaw, true) local target_shortest_path = shortest_term_of_yaw_rotatoin(self, self.object:get_yaw(), yaw, true)
--turn in the shortest path possible toward our target. if we are attacking, don't dance. --turn in the shortest path possible toward our target. if we are attacking, don't dance.
if math.abs(target_shortest_path) > 100 and (self.attack and self.attack:get_pos() or self.following and self.following:get_pos()) then if (math.abs(target_shortest_path) > 50 and not self._kb_turn) and (self.attack and self.attack:get_pos() or self.following and self.following:get_pos()) then
if self.following then if self.following then
target_shortest_path = shortest_term_of_yaw_rotatoin(self, self.object:get_yaw(), minetest.dir_to_yaw(vector.direction(self.object:get_pos(), self.following:get_pos())), true) target_shortest_path = shortest_term_of_yaw_rotatoin(self, self.object:get_yaw(), minetest.dir_to_yaw(vector.direction(self.object:get_pos(), self.following:get_pos())), true)
else else
@ -435,8 +444,14 @@ local set_yaw = function(self, yaw, delay, dtime)
if math.abs(target_shortest_path) > 280*ddtime then if math.abs(target_shortest_path) > 280*ddtime then
if target_shortest_path > 0 then if target_shortest_path > 0 then
self.object:set_yaw(self.object:get_yaw()+3.6*ddtime) self.object:set_yaw(self.object:get_yaw()+3.6*ddtime)
if self.acc then
self.acc=vector.rotate_around_axis(self.acc,vector.new(0,1,0), 3.6*ddtime)
end
else else
self.object:set_yaw(self.object:get_yaw()-3.6*ddtime) self.object:set_yaw(self.object:get_yaw()-3.6*ddtime)
if self.acc then
self.acc=vector.rotate_around_axis(self.acc,vector.new(0,1,0), -3.6*ddtime)
end
end end
end end
@ -1059,17 +1074,87 @@ local function within_limits(pos, radius)
return true return true
end end
-- get node but use fallback for nil or unknown
local node_ok = function(pos, fallback)
fallback = fallback or mcl_mobs.fallback_node
local node = minetest.get_node_or_nil(pos)
if node and minetest.registered_nodes[node.name] then
return node
end
return minetest.registered_nodes[fallback]
end
local can_jump_cliff = function(self)
local yaw = self.object:get_yaw()
local pos = self.object:get_pos()
local v = self.object:get_velocity()
local v2 = abs(v.x)+abs(v.z)*.833
local jump_c_multiplier = 1
if v2/self.walk_velocity/2>1 then
jump_c_multiplier = v2/self.walk_velocity/2
end
-- where is front
local dir_x = -sin(yaw) * (self.collisionbox[4] + 0.5)*jump_c_multiplier+0.6
local dir_z = cos(yaw) * (self.collisionbox[4] + 0.5)*jump_c_multiplier+0.6
--is there nothing under the block in front? if so jump the gap.
local nodLow = node_ok({
x = pos.x + dir_x-0.6,
y = pos.y - 0.5,
z = pos.z + dir_z-0.6
}, "air")
local nodFar = node_ok({
x = pos.x + dir_x*2,
y = pos.y - 0.5,
z = pos.z + dir_z*2
}, "air")
local nodFar2 = node_ok({
x = pos.x + dir_x*2.5,
y = pos.y - 0.5,
z = pos.z + dir_z*2.5
}, "air")
if minetest.registered_nodes[nodLow.name]
and minetest.registered_nodes[nodLow.name].walkable ~= true
and (minetest.registered_nodes[nodFar.name]
and minetest.registered_nodes[nodFar.name].walkable == true
or minetest.registered_nodes[nodFar2.name]
and minetest.registered_nodes[nodFar2.name].walkable == true)
then
--disable fear heigh while we make our jump
self._jumping_cliff = true
minetest.after(1, function()
if self and self.object then
self._jumping_cliff = false
end
end)
return true
else
return false
end
end
-- is mob facing a cliff or danger -- is mob facing a cliff or danger
local is_at_cliff_or_danger = function(self) local is_at_cliff_or_danger = function(self)
if self.fear_height == 0 then -- 0 for no falling protection! if self.fear_height == 0 or can_jump_cliff(self) or self._jumping_cliff or not self.object:get_luaentity() then -- 0 for no falling protection!
return false return false
end end
if not self.object:get_luaentity() then
return false
end
local yaw = self.object:get_yaw() local yaw = self.object:get_yaw()
local dir_x = -sin(yaw) * (self.collisionbox[4] + 0.5) local dir_x = -sin(yaw) * (self.collisionbox[4] + 0.5)
local dir_z = cos(yaw) * (self.collisionbox[4] + 0.5) local dir_z = cos(yaw) * (self.collisionbox[4] + 0.5)
@ -1102,7 +1187,7 @@ end
local is_at_water_danger = function(self) local is_at_water_danger = function(self)
if not self.object:get_luaentity() then if not self.object:get_luaentity() or can_jump_cliff(self) or self._jumping_cliff then
return false return false
end end
local yaw = self.object:get_yaw() local yaw = self.object:get_yaw()
@ -1136,20 +1221,6 @@ local is_at_water_danger = function(self)
end end
-- get node but use fallback for nil or unknown
local node_ok = function(pos, fallback)
fallback = fallback or mcl_mobs.fallback_node
local node = minetest.get_node_or_nil(pos)
if node and minetest.registered_nodes[node.name] then
return node
end
return minetest.registered_nodes[fallback]
end
-- environmental damage (water, lava, fire, light etc.) -- environmental damage (water, lava, fire, light etc.)
local do_env_damage = function(self) local do_env_damage = function(self)
@ -1205,6 +1276,7 @@ local do_env_damage = function(self)
end end
local _, dim = mcl_worlds.y_to_layer(pos.y) local _, dim = mcl_worlds.y_to_layer(pos.y)
if (self.sunlight_damage ~= 0 or self.ignited_by_sunlight) and (sunlight or 0) >= minetest.LIGHT_MAX and dim == "overworld" then if (self.sunlight_damage ~= 0 or self.ignited_by_sunlight) and (sunlight or 0) >= minetest.LIGHT_MAX and dim == "overworld" then
if self.armor_list and not self.armor_list.helmet or not self.armor_list or self.armor_list and self.armor_list.helmet and self.armor_list.helmet == "" then
if self.ignited_by_sunlight then if self.ignited_by_sunlight then
mcl_burning.set_on_fire(self.object, 10) mcl_burning.set_on_fire(self.object, 10)
else else
@ -1212,6 +1284,7 @@ local do_env_damage = function(self)
return true return true
end end
end end
end
local y_level = self.collisionbox[2] local y_level = self.collisionbox[2]
@ -1415,8 +1488,8 @@ local do_jump = function(self)
end end
-- where is front -- where is front
local dir_x = -sin(yaw) * (self.collisionbox[4] + 0.5)*jump_c_multiplier+.4 local dir_x = -sin(yaw) * (self.collisionbox[4] + 0.5)*jump_c_multiplier+0.6
local dir_z = cos(yaw) * (self.collisionbox[4] + 0.5)*jump_c_multiplier+.4 local dir_z = cos(yaw) * (self.collisionbox[4] + 0.5)*jump_c_multiplier+0.6
-- what is in front of mob? -- what is in front of mob?
nod = node_ok({ nod = node_ok({
@ -1433,8 +1506,9 @@ local do_jump = function(self)
z = pos.z + dir_z z = pos.z + dir_z
}, "air") }, "air")
-- we don't attempt to jump if there's a stack of blocks blocking -- we don't attempt to jump if there's a stack of blocks blocking
if minetest.registered_nodes[nodTop.name].walkable == true then if minetest.registered_nodes[nodTop.name].walkable == true and not (self.attack and self.state == "attack") then
return false return false
end end
@ -1444,7 +1518,7 @@ local do_jump = function(self)
end end
local ndef = minetest.registered_nodes[nod.name] local ndef = minetest.registered_nodes[nod.name]
if self.walk_chance == 0 or ndef and ndef.walkable then if self.walk_chance == 0 or ndef and ndef.walkable or can_jump_cliff(self) then
if minetest.get_item_group(nod.name, "fence") == 0 if minetest.get_item_group(nod.name, "fence") == 0
and minetest.get_item_group(nod.name, "fence_gate") == 0 and minetest.get_item_group(nod.name, "fence_gate") == 0
@ -1454,6 +1528,10 @@ local do_jump = function(self)
v.y = self.jump_height + 0.1 * 3 v.y = self.jump_height + 0.1 * 3
if can_jump_cliff(self) then
v=vector.multiply(v, vector.new(2.8,1,2.8))
end
set_animation(self, "jump") -- only when defined set_animation(self, "jump") -- only when defined
self.object:set_velocity(v) self.object:set_velocity(v)
@ -1562,6 +1640,7 @@ end
-- find two animals of same type and breed if nearby and horny -- find two animals of same type and breed if nearby and horny
local breed = function(self) local breed = function(self)
--mcl_log("In breed function")
-- child takes a long time before growing into adult -- child takes a long time before growing into adult
if self.child == true then if self.child == true then
@ -1619,6 +1698,8 @@ local breed = function(self)
if self.horny == true if self.horny == true
and self.hornytimer <= HORNY_TIME then and self.hornytimer <= HORNY_TIME then
mcl_log("In breed function. All good. Do the magic.")
local pos = self.object:get_pos() local pos = self.object:get_pos()
effect({x = pos.x, y = pos.y + 1, z = pos.z}, 8, "heart.png", 3, 4, 1, 0.1) effect({x = pos.x, y = pos.y + 1, z = pos.z}, 8, "heart.png", 3, 4, 1, 0.1)
@ -1653,6 +1734,8 @@ local breed = function(self)
end end
end end
if canmate then mcl_log("In breed function. Can mate.") end
if ent if ent
and canmate == true and canmate == true
and ent.horny == true and ent.horny == true
@ -1667,6 +1750,8 @@ local breed = function(self)
ent.hornytimer = HORNY_TIME + 1 ent.hornytimer = HORNY_TIME + 1
-- spawn baby -- spawn baby
minetest.after(5, function(parent1, parent2, pos) minetest.after(5, function(parent1, parent2, pos)
if not parent1.object:get_luaentity() then if not parent1.object:get_luaentity() then
return return
@ -2449,7 +2534,7 @@ local function go_to_pos(entity,b)
local v = { x = b.x - s.x, z = b.z - s.z } local v = { x = b.x - s.x, z = b.z - s.z }
local yaw = (atann(v.z / v.x) + pi / 2) - entity.rotate local yaw = (atann(v.z / v.x) + pi / 2) - entity.rotate
if b.x > s.x then yaw = yaw + pi end if b.x > s.x then yaw = yaw + pi end
entity.object:set_yaw(yaw) --entity.object:set_yaw(yaw)
set_velocity(entity,entity.follow_velocity) set_velocity(entity,entity.follow_velocity)
mcl_mobs:set_animation(entity, "walk") mcl_mobs:set_animation(entity, "walk")
end end
@ -2463,10 +2548,11 @@ local function check_doors(self)
if n.name:find("_b_") then if n.name:find("_b_") then
local def = minetest.registered_nodes[n.name] local def = minetest.registered_nodes[n.name]
local closed = n.name:find("_b_1") local closed = n.name:find("_b_1")
if t < 0.3 or t > 0.8 then if self.state == PATHFINDING then
if not closed and def.on_rightclick then def.on_rightclick(d,n,self) end
else
if closed and def.on_rightclick then def.on_rightclick(d,n,self) end if closed and def.on_rightclick then def.on_rightclick(d,n,self) end
--if not closed and def.on_rightclick then def.on_rightclick(d,n,self) end
else
end end
end end
@ -2477,37 +2563,106 @@ local gowp_etime = 0
local function check_gowp(self,dtime) local function check_gowp(self,dtime)
gowp_etime = gowp_etime + dtime gowp_etime = gowp_etime + dtime
if gowp_etime < 0.2 then return end if gowp_etime < 0.1 then return end
gowp_etime = 0 gowp_etime = 0
local p = self.object:get_pos() local p = self.object:get_pos()
if not p or not self._target then return end
if vector.distance(p,self._target) < 1 then -- no destination
if not p or not self._target then
mcl_log("p: ".. tostring(p))
mcl_log("self._target: ".. tostring(self._target))
return
end
-- arrived at location, finish gowp
local distance_to_targ = vector.distance(p,self._target)
mcl_log("Distance to targ: ".. tostring(distance_to_targ))
if distance_to_targ < 2 then
mcl_log("Arrived at _target")
self.waypoints = nil self.waypoints = nil
self._target = nil self._target = nil
self.current_target = nil self.current_target = nil
self.state = "stand" self.state = "stand"
self.order = "stand"
self.object:set_velocity({x = 0, y = 0, z = 0})
self.object:set_acceleration({x = 0, y = 0, z = 0})
if self.callback_arrived then return self.callback_arrived(self) end if self.callback_arrived then return self.callback_arrived(self) end
return true return true
end end
if self.waypoints and ( not self.current_target or vector.distance(p,self.current_target) < 2 ) then
-- More pathing to be done
if self.waypoints and #self.waypoints > 0 and ( not self.current_target or vector.distance(p,self.current_target) < 2 ) then
-- We have waypoints, and no current target, or we're at it. We need a new current_target.
if not self.current_target then
for i, j in pairs (self.waypoints) do
mcl_log("Val: ".. tostring(j))
end
end
self.current_target = table.remove(self.waypoints, 1) self.current_target = table.remove(self.waypoints, 1)
--minetest.log("nextwp:".. tostring(self.current_target) ) mcl_log("current target:".. minetest.pos_to_string(self.current_target) )
--mcl_log("type:".. type(self.current_target) )
go_to_pos(self,self.current_target) go_to_pos(self,self.current_target)
return return
elseif self.current_target then elseif self.current_target then
-- No waypoints left, but have current target. Potentially last waypoint to go to.
mcl_log("self.current_target: ".. minetest.pos_to_string(self.current_target))
mcl_log("pos: ".. minetest.pos_to_string(p))
go_to_pos(self,self.current_target) go_to_pos(self,self.current_target)
-- Do i just delete current_target, and return so we can find final path.
else
-- Not at target, no current waypoints or current_target. Through the door and should be able to path to target.
-- Is a little sensitive and could take 1 - 7 times. A 10 fail count might be a good exit condition.
mcl_log("We don't have waypoints or a current target. Let's try to path to target")
local final_wp = minetest.find_path(p,self._target,150,1,4)
if final_wp then
mcl_log("We might be able to get to target here.")
self.waypoints = final_wp
--go_to_pos(self,self._target)
else
mcl_log("Cannot plot final route to target")
end
end end
if self.current_target and not minetest.line_of_sight(self.object:get_pos(),self.current_target) then --if self.current_target and not minetest.line_of_sight(self.object:get_pos(),self.current_target) then
self.waypoints=minetest.find_path(p,self._target,150,1,4) if self.current_target and (self.waypoints and #self.waypoints == 0) then
if not self.waypoints then self.state = "walk" end --give up local updated_p = self.object:get_pos()
local distance_to_cur_targ = vector.distance(updated_p,self.current_target)
mcl_log("Distance to current target: ".. tostring(distance_to_cur_targ))
mcl_log("Current p: ".. minetest.pos_to_string(updated_p))
--if not minetest.line_of_sight(self.object:get_pos(),self._target) then
-- 1.6 is good. is 1.9 better? It could fail less, but will it path to door when it isn't after door
if distance_to_cur_targ > 1.9 then
mcl_log("no LOS to target: ".. minetest.pos_to_string(self.current_target))
go_to_pos(self,self._current_target)
else
mcl_log("Let's go to target: ".. minetest.pos_to_string(self.current_target))
self.current_target = nil self.current_target = nil
--go_to_pos(self,self._target)
self.waypoints=minetest.find_path(updated_p,self._target,150,1,4)
--if not self.waypoints then
--mcl_log("Give up ")
--self.state = "walk"
--end --give up
end
--self.waypoints=minetest.find_path(p,self._target,150,1,4)
--if not self.waypoints then
--mcl_log("Give up ")
--self.state = "walk"
--end --give up
--self.current_target = nil
return return
end end
if not self.current_target then --if not self.current_target then
--minetest.log("no path") --mcl_log("no path. Give up")
self.state = "walk" --self.state = "walk"
end --end
end end
-- execute current state (stand, walk, run, attacks) -- execute current state (stand, walk, run, attacks)
@ -2556,9 +2711,9 @@ local do_states = function(self, dtime)
end end
-- npc's ordered to stand stay standing -- npc's ordered to stand stay standing
if self.type ~= "npc" if self.order == "stand" or self.order == "sleep" or self.order == "work" then
or self.order ~= "stand" then
else
if self.walk_chance ~= 0 if self.walk_chance ~= 0
and self.facing_fence ~= true and self.facing_fence ~= true
and random(1, 100) <= self.walk_chance and random(1, 100) <= self.walk_chance
@ -2570,7 +2725,7 @@ local do_states = function(self, dtime)
end end
end end
elseif self.state == "gowp" then elseif self.state == PATHFINDING then
check_gowp(self,dtime) check_gowp(self,dtime)
elseif self.state == "walk" then elseif self.state == "walk" then
@ -3025,7 +3180,7 @@ local do_states = function(self, dtime)
if self.shoot_interval if self.shoot_interval
and self.timer > self.shoot_interval and self.timer > self.shoot_interval
and not minetest.raycast(p, self.attack:get_pos(), false, false):next() and not minetest.raycast(vector.add(p, vector.new(0,self.shoot_offset,0)), vector.add(self.attack:get_pos(), vector.new(0,1.5,0)), false, false):next()
and random(1, 100) <= 60 then and random(1, 100) <= 60 then
self.timer = 0 self.timer = 0
@ -3071,6 +3226,8 @@ local do_states = function(self, dtime)
end end
end end
end end
else
end end
end end
end end
@ -3085,23 +3242,50 @@ local plane_adjacents = {
local gopath_last = os.time() local gopath_last = os.time()
function mcl_mobs:gopath(self,target,callback_arrived) function mcl_mobs:gopath(self,target,callback_arrived)
if os.time() - gopath_last < 15 then return end if self.state == PATHFINDING then mcl_log("Already set as gowp, don't set another path until done.") return end
if os.time() - gopath_last < 15 then
mcl_log("Not ready to path yet")
return
end
gopath_last = os.time() gopath_last = os.time()
--minetest.log("gowp")
self.order = nil
mcl_log("gowp target: " .. minetest.pos_to_string(target))
local p = self.object:get_pos() local p = self.object:get_pos()
local t = vector.offset(target,0,1,0) local t = vector.offset(target,0,1,0)
local wp = minetest.find_path(p,t,150,1,4) local wp = minetest.find_path(p,t,150,1,4)
--Path to door first
if not wp then if not wp then
--mcl_log("gowp. no wp. Look for door")
local d = minetest.find_node_near(target,16,{"group:door"}) local d = minetest.find_node_near(target,16,{"group:door"})
if d then if d then
--mcl_log("Found a door near")
for _,v in pairs(plane_adjacents) do for _,v in pairs(plane_adjacents) do
local pos = vector.add(d,v) local pos = vector.add(d,v)
local n = minetest.get_node(pos) local n = minetest.get_node(pos)
if n.name == "air" then if n.name == "air" then
wp = minetest.find_path(p,pos,150,1,4) wp = minetest.find_path(p,pos,150,1,4)
if wp then break end if wp then
mcl_log("Found a path to next to door".. minetest.pos_to_string(pos))
local other_side_of_door = vector.add(d,-v)
mcl_log("Opposite is: ".. minetest.pos_to_string(other_side_of_door))
table.insert(wp, other_side_of_door)
break
else
--mcl_log("This block next to door doesn't work.")
end end
else
--mcl_log("Block is not air, it is: ".. n.name)
end end
end
else
mcl_log("No door found")
end end
end end
if wp and #wp > 0 then if wp and #wp > 0 then
@ -3109,7 +3293,7 @@ function mcl_mobs:gopath(self,target,callback_arrived)
self.callback_arrived = callback_arrived self.callback_arrived = callback_arrived
table.remove(wp,1) table.remove(wp,1)
self.waypoints = wp self.waypoints = wp
self.state = "gowp" self.state = PATHFINDING
return true return true
else else
self.state = "walk" self.state = "walk"
@ -3125,18 +3309,89 @@ local function player_near(pos)
end end
end end
local function get_armor_texture(armor_name)
if armor_name == "" then
return ""
end
if armor_name=="blank.png" then
return "blank.png"
end
local seperator = string.find(armor_name, ":")
return "mcl_armor_"..string.sub(armor_name, seperator+1, -1)..".png^"
end
local function set_armor_texture(self)
if self.armor_list then
local chestplate=minetest.registered_items[self.armor_list.chestplate] or {name=""}
local boots=minetest.registered_items[self.armor_list.boots] or {name=""}
local leggings=minetest.registered_items[self.armor_list.leggings] or {name=""}
local helmet=minetest.registered_items[self.armor_list.helmet] or {name=""}
if helmet.name=="" and chestplate.name=="" and leggings.name=="" and boots.name=="" then
helmet={name="blank.png"}
end
local texture = get_armor_texture(chestplate.name)..get_armor_texture(helmet.name)..get_armor_texture(boots.name)..get_armor_texture(leggings.name)
if string.sub(texture, -1,-1) == "^" then
texture=string.sub(texture,1,-2)
end
if self.textures[self.wears_armor] then
self.textures[self.wears_armor]=texture
end
self.object:set_properties({textures=self.textures})
local armor_
if type(self.armor) == "table" then
armor_ = table.copy(self.armor)
armor_.immortal = 1
else
armor_ = {immortal=1, fleshy = self.armor}
end
for _,item in pairs(self.armor_list) do
if not item then return end
if type(minetest.get_item_group(item, "mcl_armor_points")) == "number" then
armor_.fleshy=armor_.fleshy-(minetest.get_item_group(item, "mcl_armor_points")*3.5)
end
end
self.object:set_armor_groups(armor_)
end
end
local function check_item_pickup(self) local function check_item_pickup(self)
if self.pick_up and #self.pick_up > 0 then if self.pick_up and #self.pick_up > 0 or self.wears_armor then
local p = self.object:get_pos() local p = self.object:get_pos()
for _,o in pairs(minetest.get_objects_inside_radius(p,2)) do for _,o in pairs(minetest.get_objects_inside_radius(p,2)) do
local l=o:get_luaentity() local l=o:get_luaentity()
if l and l.name == "__builtin:item" then if l and l.name == "__builtin:item" then
if not player_near(p) and l.itemstring:find("mcl_armor") and self.wears_armor then
local armor_type
if l.itemstring:find("chestplate") then
armor_type = "chestplate"
elseif l.itemstring:find("boots") then
armor_type = "boots"
elseif l.itemstring:find("leggings") then
armor_type = "leggings"
elseif l.itemstring:find("helmet") then
armor_type = "helmet"
end
if not armor_type then
return
end
if not self.armor_list then
self.armor_list={helmet="",chestplate="",boots="",leggings=""}
elseif self.armor_list[armor_type] and self.armor_list[armor_type] ~= "" then
return
end
self.armor_list[armor_type]=ItemStack(l.itemstring):get_name()
o:remove()
end
if self.pick_up then
for k,v in pairs(self.pick_up) do for k,v in pairs(self.pick_up) do
if not player_near(p) and self.on_pick_up and l.itemstring:find(v) then if not player_near(p) and self.on_pick_up and l.itemstring:find(v) then
local r = self.on_pick_up(self,l) local r = self.on_pick_up(self,l)
if r and r:get_count() > 0 then if r and r.is_empty and not r:is_empty() then
l.itemstring = r:to_string() l.itemstring = r:to_string()
else elseif r and r.is_empty and r:is_empty() then
o:remove() o:remove()
end end
end end
@ -3144,6 +3399,7 @@ local function check_item_pickup(self)
end end
end end
end end
end
end end
local check_herd_timer = 0 local check_herd_timer = 0
@ -3498,7 +3754,7 @@ local mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
elseif luaentity and luaentity._knockback then elseif luaentity and luaentity._knockback then
kb = kb + luaentity._knockback kb = kb + luaentity._knockback
end end
--self._kb_turn = false self._kb_turn = true
self._turn_to=self.object:get_yaw()-1.57 self._turn_to=self.object:get_yaw()-1.57
self.frame_speed_multiplier=2.3 self.frame_speed_multiplier=2.3
if self.animation.run_end then if self.animation.run_end then
@ -3509,7 +3765,7 @@ local mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
minetest.after(0.2, function() minetest.after(0.2, function()
if self and self.object then if self and self.object then
self.frame_speed_multiplier=1 self.frame_speed_multiplier=1
self._kb_turn = true self._kb_turn = false
end end
end) end)
self.object:add_velocity({ self.object:add_velocity({
@ -3525,7 +3781,7 @@ local mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
-- if skittish then run away -- if skittish then run away
if hitter and is_player and hitter:get_pos() and not die and self.runaway == true and self.state ~= "flop" then if hitter and is_player and hitter:get_pos() and not die and self.runaway == true and self.state ~= "flop" then
yaw = set_yaw(self, minetest.dir_to_yaw(vector.direction(hitter:get_pos(), self.object:get_pos()))) local yaw = set_yaw(self, minetest.dir_to_yaw(vector.direction(hitter:get_pos(), self.object:get_pos())))
minetest.after(0.2,function() minetest.after(0.2,function()
if self and self.object and self.object:get_pos() and hitter and is_player and hitter:get_pos() then if self and self.object and self.object:get_pos() and hitter and is_player and hitter:get_pos() then
yaw = set_yaw(self, minetest.dir_to_yaw(vector.direction(hitter:get_pos(), self.object:get_pos()))) yaw = set_yaw(self, minetest.dir_to_yaw(vector.direction(hitter:get_pos(), self.object:get_pos())))
@ -3814,9 +4070,16 @@ local mob_activate = function(self, staticdata, def, dtime)
self.on_spawn_run = true -- if true, set flag to run once only self.on_spawn_run = true -- if true, set flag to run once only
end end
end end
if not self._run_armor_init then
self.armor_list={helmet="",chestplate="",boots="",leggings=""}
set_armor_texture(self)
self._run_armor_init = true
end
-- run after_activate -- run after_activate
if def.after_activate then if def.after_activate then
def.after_activate(self, staticdata, def, dtime) def.after_activate(self, staticdata, def, dtime)
end end
end end
@ -3931,7 +4194,11 @@ local mob_step = function(self, dtime)
if not self.animation.walk_speed then if not self.animation.walk_speed then
self.animation.walk_speed = 25 self.animation.walk_speed = 25
end end
if abs(v.x)+abs(v.z) > 0.5 then
self.object:set_animation_frame_speed((v2/math.max(1,self.run_velocity))*self.animation.walk_speed*self.frame_speed_multiplier) self.object:set_animation_frame_speed((v2/math.max(1,self.run_velocity))*self.animation.walk_speed*self.frame_speed_multiplier)
else
self.object:set_animation_frame_speed(25)
end
end end
--set_speed --set_speed
@ -3989,12 +4256,13 @@ local mob_step = function(self, dtime)
-- end rotation -- end rotation
if self.head_swivel and type(self.head_swivel) == "string" then if self.head_swivel and type(self.head_swivel) == "string" then
local final_rotation = vector.new(0,0,0)
local oldp,oldr = self.object:get_bone_position(self.head_swivel) local oldp,oldr = self.object:get_bone_position(self.head_swivel)
for _, obj in pairs(minetest.get_objects_inside_radius(pos, 10)) do for _, obj in pairs(minetest.get_objects_inside_radius(pos, 10)) do
if obj:is_player() and not self.attack or obj:get_luaentity() and obj:get_luaentity().name == self.name and self ~= obj:get_luaentity() then if obj:is_player() and not self.attack or obj:get_luaentity() and obj:get_luaentity().name == self.name and self ~= obj:get_luaentity() then
if not self._locked_object then if not self._locked_object then
if math.random(5000/self.curiosity) == 1 then if math.random(5000/self.curiosity) == 1 or vector.distance(pos,obj:get_pos())<4 and obj:is_player() then
self._locked_object = obj self._locked_object = obj
end end
else else
@ -4005,8 +4273,8 @@ local mob_step = function(self, dtime)
end end
end end
if self.attack then if self.attack or self.following then
self._locked_object = self.attack self._locked_object = self.attack or self.following
end end
if self._locked_object and (self._locked_object:is_player() or self._locked_object:get_luaentity()) and self._locked_object:get_hp() > 0 then if self._locked_object and (self._locked_object:is_player() or self._locked_object:get_luaentity()) and self._locked_object:get_hp() > 0 then
@ -4026,30 +4294,36 @@ local mob_step = function(self, dtime)
local direction_player = vector.direction(vector.add(self.object:get_pos(), vector.new(0, self.head_eye_height*.7, 0)), vector.add(player_pos, vector.new(0, _locked_object_eye_height, 0))) local direction_player = vector.direction(vector.add(self.object:get_pos(), vector.new(0, self.head_eye_height*.7, 0)), vector.add(player_pos, vector.new(0, _locked_object_eye_height, 0)))
local mob_yaw = math.deg(-(-(self_rot.y)-(-minetest.dir_to_yaw(direction_player))))+self.head_yaw_offset local mob_yaw = math.deg(-(-(self_rot.y)-(-minetest.dir_to_yaw(direction_player))))+self.head_yaw_offset
local mob_pitch = math.deg(-dir_to_pitch(direction_player))*self.head_pitch_multiplier local mob_pitch = math.deg(-dir_to_pitch(direction_player))*self.head_pitch_multiplier
if (mob_yaw < -60 or mob_yaw > 60) and not (self.attack and self.type == "monster") then
mcl_util.set_bone_position(self.object,self.head_swivel, vector.new(0,self.bone_eye_height,self.horrizonatal_head_height), vector.multiply(oldr, 0.9)) if (mob_yaw < -60 or mob_yaw > 60) and not (self.attack and self.state == "attack" and not self.runaway) then
elseif self.attack and self.type == "monster" then final_rotation = vector.multiply(oldr, 0.9)
elseif self.attack and self.state == "attack" and not self.runaway then
if self.head_yaw == "y" then if self.head_yaw == "y" then
mcl_util.set_bone_position(self.object,self.head_swivel, vector.new(0,self.bone_eye_height,self.horrizonatal_head_height), vector.new(mob_pitch, mob_yaw, 0)) final_rotation = vector.new(mob_pitch, mob_yaw, 0)
elseif self.head_yaw == "z" then elseif self.head_yaw == "z" then
mcl_util.set_bone_position(self.object,self.head_swivel, vector.new(0,self.bone_eye_height,self.horrizonatal_head_height), vector.new(mob_pitch, 0, -mob_yaw)) final_rotation = vector.new(mob_pitch, 0, -mob_yaw)
end end
else else
if self.head_yaw == "y" then if self.head_yaw == "y" then
mcl_util.set_bone_position(self.object,self.head_swivel, vector.new(0,self.bone_eye_height,self.horrizonatal_head_height), vector.new(((mob_pitch-oldr.x)*.3)+oldr.x, ((mob_yaw-oldr.y)*.3)+oldr.y, 0)) final_rotation = vector.new(((mob_pitch-oldr.x)*.3)+oldr.x, ((mob_yaw-oldr.y)*.3)+oldr.y, 0)
elseif self.head_yaw == "z" then elseif self.head_yaw == "z" then
mcl_util.set_bone_position(self.object,self.head_swivel, vector.new(0,self.bone_eye_height,self.horrizonatal_head_height), vector.new(((mob_pitch-oldr.x)*.3)+oldr.x, 0, -(((mob_yaw-oldr.y)*.3)+oldr.y)*3)) final_rotation = vector.new(((mob_pitch-oldr.x)*.3)+oldr.x, 0, -(((mob_yaw-oldr.y)*.3)+oldr.y)*3)
end end
end end
end end
elseif not self._locked_object and math.abs(oldr.y) > 3 and math.abs(oldr.x) < 3 then elseif not self._locked_object and math.abs(oldr.y) > 3 and math.abs(oldr.x) < 3 then
mcl_util.set_bone_position(self.object,self.head_swivel, vector.new(0,self.bone_eye_height,self.horrizonatal_head_height), vector.multiply(oldr, 0.9)) final_rotation = vector.multiply(oldr, 0.9)
else else
mcl_util.set_bone_position(self.object,self.head_swivel, vector.new(0,self.bone_eye_height,self.horrizonatal_head_height), vector.new(0,0,0)) final_rotation = vector.new(0,0,0)
end end
mcl_util.set_bone_position(self.object,self.head_swivel, vector.new(0,self.bone_eye_height,self.horrizonatal_head_height), final_rotation)
end end
-- run custom function (defined in mob lua file) -- run custom function (defined in mob lua file)
if self.do_custom then if self.do_custom then
@ -4070,7 +4344,7 @@ local mob_step = function(self, dtime)
-- attack timer -- attack timer
self.timer = self.timer + dtime self.timer = self.timer + dtime
if self.state ~= "attack" and self.state ~= "gowp" then if self.state ~= "attack" and self.state ~= PATHFINDING then
if self.timer < 1 then if self.timer < 1 then
return return
end end
@ -4121,6 +4395,8 @@ local mob_step = function(self, dtime)
do_jump(self) do_jump(self)
set_armor_texture(self)
runaway_from(self) runaway_from(self)
if is_at_water_danger(self) and self.state ~= "attack" then if is_at_water_danger(self) and self.state ~= "attack" then
@ -4277,6 +4553,7 @@ minetest.register_entity(name, {
curiosity = def.curiosity or 1, -- how often mob will look at player on idle curiosity = def.curiosity or 1, -- how often mob will look at player on idle
head_yaw = def.head_yaw or "y", -- axis to rotate head on head_yaw = def.head_yaw or "y", -- axis to rotate head on
horrizonatal_head_height = def.horrizonatal_head_height or 0, horrizonatal_head_height = def.horrizonatal_head_height or 0,
wears_armor = def.wears_armor, -- a number value used to index texture slot for armor
stepheight = def.stepheight or 0.6, stepheight = def.stepheight or 0.6,
name = name, name = name,
description = def.description, description = def.description,
@ -4330,6 +4607,7 @@ minetest.register_entity(name, {
nofollow = def.nofollow, nofollow = def.nofollow,
can_open_doors = def.can_open_doors, can_open_doors = def.can_open_doors,
jump = def.jump ~= false, jump = def.jump ~= false,
automatic_face_movement_max_rotation_per_sec = 300,
walk_chance = def.walk_chance or 50, walk_chance = def.walk_chance or 50,
attacks_monsters = def.attacks_monsters or false, attacks_monsters = def.attacks_monsters or false,
group_attack = def.group_attack or false, group_attack = def.group_attack or false,
@ -4439,6 +4717,7 @@ minetest.register_entity(name, {
self.object:set_properties({ self.object:set_properties({
collide_with_objects = false, collide_with_objects = false,
}) })
return mob_activate(self, staticdata, def, dtime) return mob_activate(self, staticdata, def, dtime)
end, end,

View file

@ -6,6 +6,7 @@ local cow_def = {
description = S("Cow"), description = S("Cow"),
type = "animal", type = "animal",
spawn_class = "passive", spawn_class = "passive",
passive = true,
hp_min = 10, hp_min = 10,
hp_max = 10, hp_max = 10,
xp_min = 1, xp_min = 1,

View file

@ -12,6 +12,7 @@ local S = minetest.get_translator("mobs_mc")
-- Spider by AspireMint (fishyWET (CC-BY-SA 3.0 license for texture) -- Spider by AspireMint (fishyWET (CC-BY-SA 3.0 license for texture)
minetest.register_entity("mobs_mc:spider_eyes", { minetest.register_entity("mobs_mc:spider_eyes", {
pointable = false,
visual = "mesh", visual = "mesh",
mesh = "mobs_mc_spider.b3d", mesh = "mobs_mc_spider.b3d",
visual_size = {x=1.01/3, y=1.01/3}, visual_size = {x=1.01/3, y=1.01/3},
@ -121,8 +122,21 @@ cave_spider.textures = { {"mobs_mc_cave_spider.png^(mobs_mc_spider_eyes.png^[mak
cave_spider.damage = 3 -- damage increased to undo non-existing poison cave_spider.damage = 3 -- damage increased to undo non-existing poison
cave_spider.hp_min = 1 cave_spider.hp_min = 1
cave_spider.hp_max = 12 cave_spider.hp_max = 12
cave_spider.collisionbox = {-0.35, -0.01, -0.35, 0.35, 0.49, 0.35} cave_spider.collisionbox = {-0.35, -0.01, -0.35, 0.35, 0.46, 0.35}
cave_spider.visual_size = {x=1.66666, y=1.5} cave_spider.visual_size = {x=0.55,y=0.5}
cave_spider.on_spawn = function(self)
self.object:set_properties({visual_size={x=0.55,y=0.5}})
local spider_eyes=false
for n = 1, #self.object:get_children() do
local obj = self.object:get_children()[n]
if obj:get_luaentity() and self.object:get_luaentity().name == "mobs_mc:spider_eyes" then
spider_eyes = true
end
end
if not spider_eyes then
minetest.add_entity(self.object:get_pos(), "mobs_mc:spider_eyes"):set_attach(self.object, "body.head", vector.new(0,-0.98,2), vector.new(90,180,180))
end
end
cave_spider.walk_velocity = 1.3 cave_spider.walk_velocity = 1.3
cave_spider.run_velocity = 3.2 cave_spider.run_velocity = 3.2
cave_spider.sounds = table.copy(spider.sounds) cave_spider.sounds = table.copy(spider.sounds)

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View file

@ -15,6 +15,8 @@
-- TODO: Internal inventory, trade with other villagers -- TODO: Internal inventory, trade with other villagers
-- TODO: Schedule stuff (work,sleep,father) -- TODO: Schedule stuff (work,sleep,father)
local weather_mod = minetest.get_modpath("mcl_weather")
local S = minetest.get_translator("mobs_mc") local S = minetest.get_translator("mobs_mc")
local N = function(s) return s end local N = function(s) return s end
local F = minetest.formspec_escape local F = minetest.formspec_escape
@ -28,6 +30,8 @@ local DEFAULT_WALK_CHANCE = 33 -- chance to walk in percent, if no player nearby
local PLAYER_SCAN_INTERVAL = 5 -- every X seconds, villager looks for players nearby local PLAYER_SCAN_INTERVAL = 5 -- every X seconds, villager looks for players nearby
local PLAYER_SCAN_RADIUS = 4 -- scan radius for looking for nearby players local PLAYER_SCAN_RADIUS = 4 -- scan radius for looking for nearby players
local PATHFINDING = "gowp"
--[=======[ TRADING ]=======] --[=======[ TRADING ]=======]
-- LIST OF VILLAGER PROFESSIONS AND TRADES -- LIST OF VILLAGER PROFESSIONS AND TRADES
@ -40,6 +44,14 @@ local PLAYER_SCAN_RADIUS = 4 -- scan radius for looking for nearby players
-- these items should be implemented as single items, then everything -- these items should be implemented as single items, then everything
-- will be much easier. -- will be much easier.
local LOGGING_ON = minetest.settings:get_bool("mcl_logging_mobs_villager",false)
local LOG_MODULE = "[Mobs - Villager]"
local function mcl_log (message)
if LOGGING_ON and message then
minetest.log(LOG_MODULE .. " " .. message)
end
end
local COMPASS = "mcl_compass:compass" local COMPASS = "mcl_compass:compass"
if minetest.registered_aliases[COMPASS] then if minetest.registered_aliases[COMPASS] then
COMPASS = minetest.registered_aliases[COMPASS] COMPASS = minetest.registered_aliases[COMPASS]
@ -492,16 +504,35 @@ local professions = {
} }
} }
local WORK = "work"
local SLEEP = "sleep"
local profession_names = {} local profession_names = {}
for id, _ in pairs(professions) do for id, _ in pairs(professions) do
table.insert(profession_names, id) table.insert(profession_names, id)
end end
local jobsites={} local function populate_jobsites (profession)
for _,n in pairs(profession_names) do if profession then
table.insert(jobsites,professions[n].jobsite) mcl_log("populate_jobsites: ".. tostring(profession))
end
local jobsites_requested={}
for _,n in pairs(profession_names) do
if n and professions[n].jobsite then
if not profession or (profession and profession == n) then
--minetest.log("populate_jobsites. Adding: ".. tostring(n))
table.insert(jobsites_requested,professions[n].jobsite)
end
end
end
return jobsites_requested
end end
jobsites = populate_jobsites()
local spawnable_bed={}
table.insert(spawnable_bed, "mcl_beds:bed_red_bottom")
local function stand_still(self) local function stand_still(self)
self.walk_chance = 0 self.walk_chance = 0
self.jump = false self.jump = false
@ -521,6 +552,11 @@ end
local function get_badge_textures(self) local function get_badge_textures(self)
local t = professions[self._profession].texture local t = professions[self._profession].texture
if self._profession == "unemployed" then
t = professions[self._profession].textures -- ideally both scenarios should be textures with a list containing 1 or multiple
--mcl_log("t: " .. tostring(t))
end
if self._profession == "unemployed" or self._profession == "nitwit" then return t end if self._profession == "unemployed" or self._profession == "nitwit" then return t end
local tier = self._max_trade_tier or 1 local tier = self._max_trade_tier or 1
return { return {
@ -529,26 +565,136 @@ local function get_badge_textures(self)
end end
local function set_textures(self) local function set_textures(self)
self.object:set_properties({textures=get_badge_textures(self)}) local badge_textures = get_badge_textures(self)
--mcl_log("Setting textures: " .. tostring(badge_textures))
self.object:set_properties({textures=badge_textures})
end end
local function go_home(entity) function get_activity(tod)
entity.state = "go_home" -- night hours = tod > 18541 or tod < 5458
local b=entity._bed if not tod then
if not b then return end tod = minetest.get_timeofday()
mcl_mobs:gopath(entity,b,function(entity,b) end
tod = ( tod * 24000 ) % 24000
local lunch_start = 12000
local lunch_end = 13500
local work_start = 8500
local work_end = 16500
local activity = nil
if (tod > work_start and tod < lunch_start) or (tod > lunch_end and tod < work_end) then
activity = WORK
elseif mcl_beds.is_night() then
activity = SLEEP
elseif tod > lunch_start and tod < lunch_end then
activity = "lunch"
else
activity = "chill"
end
mcl_log("Time is " .. tod ..". Activity is: ".. activity)
return activity
end
local function go_home(entity, sleep)
local b = entity._bed
if not b then
return
end
local bed_node = minetest.get_node(b)
if not bed_node then
entity._bed = nil
mcl_log("Cannot find bed. Unset it")
return
end
if vector.distance(entity.object:get_pos(),b) < 2 then if vector.distance(entity.object:get_pos(),b) < 2 then
entity.state = "stand" if sleep then
set_velocity(entity,0) entity.order = SLEEP
entity.object:set_pos(b) mcl_log("Sleep time!")
local n=minetest.get_node(b) end
if n and n.name ~= "mcl_beds:bed_red_bottom" then else
entity._bed=nil --the stormtroopers have killed uncle owen if sleep and entity.order == SLEEP then
entity.order = nil
return
end
mcl_mobs:gopath(entity,b,function(entity,b)
local b = entity._bed
if not b then
--minetest.log("NO BED, problem")
return false return false
end end
if not minetest.get_node(b) then
--minetest.log("NO BED NODE, problem")
return false
end
if vector.distance(entity.object:get_pos(),b) < 2 then
--minetest.log("Managed to walk home callback!")
return true return true
else
--minetest.log("Need to walk to home")
end end
end) end)
end
end
local function check_bed (entity)
local b = entity._bed
if not b then
--minetest.log("No bed set on villager")
return false
end
local n = minetest.get_node(b)
if n and n.name ~= "mcl_beds:bed_red_bottom" then
mcl_log("Where did my bed go?!")
entity._bed = nil --the stormtroopers have killed uncle owen
return false
else
return true
end
end
local function take_bed (entity)
if not entity then return end
local p = entity.object:get_pos()
local nn = minetest.find_nodes_in_area(vector.offset(p,-48,-48,-48), vector.offset(p,48,48,48), spawnable_bed)
for _,n in pairs(nn) do
local m=minetest.get_meta(n)
--mcl_log("Bed owner: ".. m:get_string("villager"))
if m:get_string("villager") == "" and not (entity.state == PATHFINDING) then
mcl_log("Can we path to bed: "..minetest.pos_to_string(n) )
local gp = mcl_mobs:gopath(entity,n,function(self)
if self then
self.order = "sleep"
mcl_log("Sleepy time" )
else
mcl_log("Can't sleep, no self in the callback" )
end
end)
if gp then
mcl_log("Nice bed. I'll defintely take it as I can path")
m:set_string("villager", entity._id)
entity._bed = n
break
else
mcl_log("Awww. I can't find my bed.")
end
else
mcl_log("Currently gowp, or it's taken: ".. m:get_string("villager"))
end
end
end end
local function has_golem(pos) local function has_golem(pos)
@ -596,6 +742,43 @@ local function check_summon(self,dtime)
self._summon_timer = self._summon_timer + dtime self._summon_timer = self._summon_timer + dtime
end end
local function has_traded (self)
--mcl_log("Checking name: " .. self._trades)
if not self._trades then
mcl_log("No trades set. has_traded is false")
return false
end
local cur_trades_tab = minetest.deserialize(self._trades)
if cur_trades_tab and type(cur_trades_tab) == "table" then
for trader, trades in pairs(cur_trades_tab) do
--mcl_log("Current record: ".. tostring(trader))
--for tr3, tr4 in pairs (tab_val) do
--mcl_log("Key: ".. tostring(tr3))
--mcl_log("Value: ".. tostring(tr4))
--end
--mcl_log("traded once: ".. tostring(trades.traded_once))
if trades.traded_once then
mcl_log("Villager has traded before. Returning true")
return true
end
end
end
mcl_log("Villager has not traded before")
return false
end
local function unlock_trades (self)
if self then
--mcl_log("We should now try to unlock trades")
else
mcl_log("Missing self")
end
end
----- JOBSITE LOGIC ----- JOBSITE LOGIC
local function get_profession_by_jobsite(js) local function get_profession_by_jobsite(js)
for k,v in pairs(professions) do for k,v in pairs(professions) do
@ -608,47 +791,209 @@ local function employ(self,jobsite_pos)
local m = minetest.get_meta(jobsite_pos) local m = minetest.get_meta(jobsite_pos)
local p = get_profession_by_jobsite(n.name) local p = get_profession_by_jobsite(n.name)
if p and m:get_string("villager") == "" then if p and m:get_string("villager") == "" then
self._profession=p mcl_log("Taking this jobsite")
m:set_string("villager",self._id) m:set_string("villager",self._id)
self._jobsite = jobsite_pos self._jobsite = jobsite_pos
if not has_traded(self) then
self._profession=p
set_textures(self) set_textures(self)
end
return true
else
mcl_log("I can not steal someone's job!")
end
end
local function look_for_job(self, requested_jobsites)
--if self.last_jobhunt and os.time() - self.last_jobhunt < 15 then
-- mcl_log("Is time less than 40?" .. tostring(os.time() - self.last_jobhunt))
-- return
--end
--self.last_jobhunt = os.time() + math.random(0,30)
mcl_log("Looking for jobs")
local looking_for_type = jobsites
if requested_jobsites then
--mcl_log("Looking for jobs of my type: " .. tostring(requested_jobsites))
looking_for_type = requested_jobsites
else
mcl_log("Looking for any job type")
end
local p = self.object:get_pos()
local nn = minetest.find_nodes_in_area(vector.offset(p,-48,-48,-48),vector.offset(p,48,48,48), looking_for_type)
for _,n in pairs(nn) do
local m = minetest.get_meta(n)
--mcl_log("Job owner: ".. m:get_string("villager"))
if m:get_string("villager") == "" then
mcl_log("It's a free job for me (".. minetest.pos_to_string(p) .. ")! I might be interested: "..minetest.pos_to_string(n) )
local gp = mcl_mobs:gopath(self,n,function(self)
mcl_log("Arrived at block callback")
if self and self.state == "stand" then
self.order = WORK
else
mcl_log("no self. passing param to callback failed")
end
end)
if gp then
if n then
mcl_log("We can path to this block.. " .. tostring(n))
end
return n
else
mcl_log("We could not path to block or it's not ready to path yet.")
end
end
end
return nil
end
local function get_a_job(self)
mcl_log("I'm unemployed or lost my job block and have traded. Can I get a job?")
--self.order = JOB_HUNTING
local requested_jobsites = jobsites
if has_traded (self) then
mcl_log("Has traded so look for job of my type")
requested_jobsites = populate_jobsites(self._profession)
-- Only pass in my jobsite to two functions here
else
mcl_log("Has not traded")
end
local p = self.object:get_pos()
local n = minetest.find_node_near(p,1,requested_jobsites)
--Ideally should check for closest available. It'll make pathing easier.
--local n = look_for_job(self)
if not n then
--mcl_log("Job hunt failed. Could not find block I have walked to")
end
if n and employ(self,n) then return true end
if self.state ~= PATHFINDING then
mcl_log("Nothing near. Need to look for a job")
look_for_job(self, requested_jobsites)
end
end
local function retrieve_my_jobsite (self)
if not self or not self._jobsite then
--mcl_log("find_jobsite. Invalid params")
return
end
local n = mcl_vars.get_node(self._jobsite)
local m = minetest.get_meta(self._jobsite)
if m:get_string("villager") == self._id then
--mcl_log("find_jobsite. is my job.")
return n
else
--mcl_log("find_jobsite. Not my job")
end
return
end
local function validate_jobsite(self)
if self._profession == "unemployed" then return false end
if not retrieve_my_jobsite (self) then
self._jobsite = nil
if self.order == WORK then
self.order = nil
end
if not has_traded(self) then
mcl_log("Cannot retrieve my jobsite. I am now unemployed.")
self._profession = "unemployed"
self._trades = nil
set_textures(self)
else
mcl_log("Cannot retrieve my jobsite but I've traded so only remove jobsite.")
end
return false
else
return true return true
end end
end end
local function look_for_job(self)
if self.last_jobhunt and os.time() - self.last_jobhunt < 360 then return end
self.last_jobhunt = os.time() + math.random(0,60)
local p = self.object:get_pos()
local nn = minetest.find_nodes_in_area(vector.offset(p,-48,-48,-48),vector.offset(p,48,48,48),jobsites)
for _,n in pairs(nn) do
local m=minetest.get_meta(n)
if m:get_string("villager") == "" then
--minetest.log("goingt to jobsite "..minetest.pos_to_string(n) )
local gp = mcl_mobs:gopath(self,n,function()
--minetest.log("arrived jobsite "..minetest.pos_to_string(n) )
end)
if gp then return end
end
end
end
local function get_a_job(self)
local function do_work (self)
if self.child then return end if self.child then return end
local p = self.object:get_pos() --mcl_log("Time for work")
local n = minetest.find_node_near(p,1,jobsites)
if n and employ(self,n) then return true end
if self.state ~= "gowp" then look_for_job(self) end
end
local function check_jobsite(self) -- Don't try if looking_for_work, or gowp possibly
if self._traded or not self._jobsite then return end if validate_jobsite(self) then
local n = mcl_vars.get_node(self._jobsite) --mcl_log("My jobsite is valid. Do i need to travel?")
local m = minetest.get_meta(self._jobsite)
if m:get_string("villager") ~= self._id then local jobsite2 = retrieve_my_jobsite (self)
self._profession = "unemployed" local jobsite = self._jobsite
self._trades = nil
set_textures(self) if self and jobsite2 and self._jobsite then
--mcl_log("Villager: ".. minetest.pos_to_string(self.object:get_pos()) .. ", jobsite: " .. minetest.pos_to_string(self._jobsite))
if vector.distance(self.object:get_pos(),self._jobsite) < 2 then
--mcl_log("Made it to work ok!")
if not (self.state == PATHFINDING) then
--mcl_log("Setting order to work.")
self.order = WORK
else
mcl_log("Not gowp. What is it: " .. self.state)
end
-- Once we arrive at job block, we should unlock trades
unlock_trades(self)
--self.state = "stand"
--self.object:set_velocity({x = 0, y = 0, z = 0})
else
mcl_log("Not at job block. Need to commute.")
if self.order == WORK then
self.order = nil
return
end
--self.state = "go_to_work"
mcl_mobs:gopath(self, jobsite, function(self,jobsite)
if not self then
--mcl_log("missing self. not good")
return false
end
if not self._jobsite then
--mcl_log("Jobsite not valid")
return false
end
if vector.distance(self.object:get_pos(),self._jobsite) < 2 then
--mcl_log("Made it to work ok callback!")
return true
else
--mcl_log("Need to walk to work. Not sure we can get here.")
end
end)
end
end
elseif self._profession == "unemployed" then
get_a_job(self)
elseif has_traded(self) then
mcl_log("My job site is invalid or gone. I cannot work.")
if self.order == WORK then self.order = nil end
get_a_job(self)
end end
end end
@ -724,7 +1069,7 @@ local function set_trade(trader, player, inv, concrete_tradenum)
init_trades(trader) init_trades(trader)
trades = minetest.deserialize(trader._trades) trades = minetest.deserialize(trader._trades)
if not trades then if not trades then
minetest.log("error", "[mobs_mc] Failed to select villager trade!") --minetest.log("error", "Failed to select villager trade!")
return return
end end
end end
@ -1118,6 +1463,7 @@ local trade_inventory = {
-- END OF SPECIAL HANDLING FOR COMPASS -- END OF SPECIAL HANDLING FOR COMPASS
local trader = player_trading_with[name] local trader = player_trading_with[name]
local tradenum = player_tradenum[name] local tradenum = player_tradenum[name]
local trades local trades
trader._traded = true trader._traded = true
if trader and trader._trades then if trader and trader._trades then
@ -1233,6 +1579,7 @@ mcl_mobs:register_mob("mobs_mc:villager", {
description = S("Villager"), description = S("Villager"),
type = "npc", type = "npc",
spawn_class = "passive", spawn_class = "passive",
passive = true,
hp_min = 20, hp_min = 20,
hp_max = 20, hp_max = 20,
head_swivel = "head.control", head_swivel = "head.control",
@ -1299,14 +1646,31 @@ mcl_mobs:register_mob("mobs_mc:villager", {
return it return it
end, end,
on_rightclick = function(self, clicker) on_rightclick = function(self, clicker)
if self._jobsite then if self.child or self._profession == "unemployed" or self._profession == "nitwit" then
self.order = nil
return
end
if self.state == PATHFINDING then
self.state = "stand"
end
-- Can we remove now we possibly have fixed root cause
if self.state == "attack" then
mcl_log("Somehow villager got into an invalid attack state. Removed attack state.")
-- Need to stop villager getting in attack state. This is a workaround to allow players to fix broken villager.
self.state = "stand"
self.attack = nil
end
-- Don't do at night. Go to bed? Maybe do_activity needs it's own method
if validate_jobsite(self) then
mcl_mobs:gopath(self,self._jobsite,function() mcl_mobs:gopath(self,self._jobsite,function()
--minetest.log("arrived at jobsite") --minetest.log("arrived at jobsite")
end) end)
else
self.state = "stand" -- cancel gowp in case it has messed up
self.order = nil -- cancel work if working
end end
if self.child or self._profession == "unemployed" or self._profession == "nitwit" then
return
end
-- Initiate trading -- Initiate trading
init_trader_vars(self) init_trader_vars(self)
local name = clicker:get_player_name() local name = clicker:get_player_name()
@ -1345,18 +1709,21 @@ mcl_mobs:register_mob("mobs_mc:villager", {
_trading_players = {}, -- list of playernames currently trading with villager (open formspec) _trading_players = {}, -- list of playernames currently trading with villager (open formspec)
do_custom = function(self, dtime) do_custom = function(self, dtime)
check_summon(self,dtime) check_summon(self,dtime)
-- Stand still if player is nearby. -- Stand still if player is nearby.
if not self._player_scan_timer then if not self._player_scan_timer then
self._player_scan_timer = 0 self._player_scan_timer = 0
end end
self._player_scan_timer = self._player_scan_timer + dtime self._player_scan_timer = self._player_scan_timer + dtime
-- Check infrequently to keep CPU load low -- Check infrequently to keep CPU load low
if self._player_scan_timer > PLAYER_SCAN_INTERVAL then if self._player_scan_timer > PLAYER_SCAN_INTERVAL then
self._player_scan_timer = 0 self._player_scan_timer = 0
local selfpos = self.object:get_pos() local selfpos = self.object:get_pos()
local objects = minetest.get_objects_inside_radius(selfpos, PLAYER_SCAN_RADIUS) local objects = minetest.get_objects_inside_radius(selfpos, PLAYER_SCAN_RADIUS)
local has_player = false local has_player = false
for o, obj in pairs(objects) do for o, obj in pairs(objects) do
if obj:is_player() then if obj:is_player() then
has_player = true has_player = true
@ -1367,18 +1734,48 @@ mcl_mobs:register_mob("mobs_mc:villager", {
minetest.log("verbose", "[mobs_mc] Player near villager found!") minetest.log("verbose", "[mobs_mc] Player near villager found!")
stand_still(self) stand_still(self)
else else
minetest.log("verbose", "[mobs_mc] No player near villager found!") --minetest.log("verbose", "[mobs_mc] No player near villager found!")
self.walk_chance = DEFAULT_WALK_CHANCE self.walk_chance = DEFAULT_WALK_CHANCE
self.jump = true self.jump = true
end end
if self._bed and ( self.state ~= "go_home" and vector.distance(self.object:get_pos(),self._bed) > 50 ) then
go_home(self) if not self._bed then
--mcl_log("Villager has no bed. Currently at location: "..minetest.pos_to_string(self.object:get_pos()))
take_bed (self)
end
-- Only check in day or during thunderstorm but wandered_too_far code won't work
if check_bed (self) then
--self.state ~= "go_home"
local wandered_too_far = ( self.state ~= PATHFINDING ) and (vector.distance(self.object:get_pos(),self._bed) > 50 )
--if wandered_too_far then minetest.log("Wandered too far! Return home ") end
if wandered_too_far then
go_home(self, false)
return
elseif mcl_beds.is_night() or (weather_mod and mcl_weather.get_weather() == "thunder") then
mcl_log("It's night or thunderstorm. Better get to bed. Weather is: " .. mcl_weather.get_weather())
go_home(self, true)
return
end end
if self._profession == "unemployed" then
get_a_job(self)
else else
check_jobsite(self) --mcl_log("check bed failed ")
end end
-- Daytime is work and play time
if not mcl_beds.is_night() then
if self.order == SLEEP then self.order = nil end
if get_activity() == WORK then
do_work(self)
else
-- gossip at town bell or stroll around
self.order = nil
end
else
if self.order == WORK then self.order = nil end
end
end end
end, end,
@ -1408,6 +1805,19 @@ mcl_mobs:register_mob("mobs_mc:villager", {
end end
end end
end end
local bed = self._bed
if bed then
local bed_meta = minetest.get_meta(bed)
bed_meta:set_string("villager", nil)
mcl_log("Died, so bye bye bed")
end
local jobsite = self._jobsite
if jobsite then
local jobsite_meta = minetest.get_meta(jobsite)
jobsite_meta:set_string("villager", nil)
mcl_log("Died, so bye bye jobsite")
end
end, end,
}) })

View file

@ -59,6 +59,7 @@ local zombie = {
curiosity = 7, curiosity = 7,
head_pitch_multiplier=-1, head_pitch_multiplier=-1,
breath_max = -1, breath_max = -1,
wears_armor = 1,
armor = {undead = 90, fleshy = 90}, armor = {undead = 90, fleshy = 90},
collisionbox = {-0.3, -0.01, -0.3, 0.3, 1.8, 0.3}, collisionbox = {-0.3, -0.01, -0.3, 0.3, 1.8, 0.3},
visual = "mesh", visual = "mesh",

View file

@ -34,6 +34,7 @@ return {
"RandomLegoBrick", "RandomLegoBrick",
"SumianVoice", "SumianVoice",
"MrRar", "MrRar",
"talamh",
}}, }},
{S("Contributors"), 0x52FF00, { {S("Contributors"), 0x52FF00, {
"Laurent Rocher", "Laurent Rocher",
@ -67,7 +68,6 @@ return {
"Benjamin Schötz", "Benjamin Schötz",
"Doloment", "Doloment",
"Sydney Gems", "Sydney Gems",
"talamh",
"Emily2255", "Emily2255",
"Emojigit", "Emojigit",
"FinishedFragment", "FinishedFragment",
@ -86,6 +86,10 @@ return {
"opfromthestart", "opfromthestart",
"snowyu", "snowyu",
"FaceDeer", "FaceDeer",
"Faerraven / Michieal",
"FossFanatic",
"Herbert West",
"GuyLiner",
}}, }},
{S("MineClone5"), 0xA60014, { {S("MineClone5"), 0xA60014, {
"kay27", "kay27",
@ -96,7 +100,7 @@ return {
"chmodsayshello", "chmodsayshello",
"3raven", "3raven",
"PrairieWind", "PrairieWind",
"Gustavo1", "Gustavo6046 / wallabra",
"CableGuy67", "CableGuy67",
"MrRar", "MrRar",
}}, }},

View file

@ -54,7 +54,6 @@ local entity_animations = {
minetest.register_entity("mcl_chests:chest", { minetest.register_entity("mcl_chests:chest", {
initial_properties = { initial_properties = {
visual = "mesh", visual = "mesh",
visual_size = {x = 3, y = 3},
pointable = false, pointable = false,
physical = false, physical = false,
static_save = false, static_save = false,
@ -140,7 +139,6 @@ minetest.register_entity("mcl_chests:chest", {
local function get_entity_pos(pos, dir, double) local function get_entity_pos(pos, dir, double)
pos = vector.new(pos) pos = vector.new(pos)
pos.y = pos.y - 0.49
if double then if double then
local add, mul, vec, cross = vector.add, vector.multiply, vector.new, vector.cross local add, mul, vec, cross = vector.add, vector.multiply, vector.new, vector.cross
pos = add(pos, mul(cross(dir, vec(0, 1, 0)), -0.5)) pos = add(pos, mul(cross(dir, vec(0, 1, 0)), -0.5))
@ -363,7 +361,7 @@ local function register_chest(basename, desc, longdesc, usagehelp, tt_help, tile
_doc_items_usagehelp = usagehelp, _doc_items_usagehelp = usagehelp,
_doc_items_hidden = hidden, _doc_items_hidden = hidden,
drawtype = "mesh", drawtype = "mesh",
mesh = "mcl_chests_chest.obj", mesh = "mcl_chests_chest.b3d",
tiles = small_textures, tiles = small_textures,
use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "opaque" or false, use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "opaque" or false,
paramtype = "light", paramtype = "light",
@ -401,7 +399,7 @@ local function register_chest(basename, desc, longdesc, usagehelp, tt_help, tile
type = "fixed", type = "fixed",
fixed = {-0.4375, -0.5, -0.4375, 0.4375, 0.375, 0.4375}, fixed = {-0.4375, -0.5, -0.4375, 0.4375, 0.375, 0.4375},
}, },
tiles = {"mcl_chests_blank.png"}, tiles = {"blank.png^[resize:16x16"},
use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "clip" or true, use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "clip" or true,
_chest_entity_textures = small_textures, _chest_entity_textures = small_textures,
_chest_entity_sound = "default_chest", _chest_entity_sound = "default_chest",
@ -527,7 +525,7 @@ local function register_chest(basename, desc, longdesc, usagehelp, tt_help, tile
type = "fixed", type = "fixed",
fixed = {-0.4375, -0.5, -0.4375, 0.5, 0.375, 0.4375}, fixed = {-0.4375, -0.5, -0.4375, 0.5, 0.375, 0.4375},
}, },
tiles = {"mcl_chests_blank.png"}, tiles = {"blank.png^[resize:16x16"},
use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "clip" or true, use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "clip" or true,
_chest_entity_textures = left_textures, _chest_entity_textures = left_textures,
_chest_entity_sound = "default_chest", _chest_entity_sound = "default_chest",
@ -684,7 +682,7 @@ local function register_chest(basename, desc, longdesc, usagehelp, tt_help, tile
type = "fixed", type = "fixed",
fixed = {-0.5, -0.5, -0.4375, 0.4375, 0.375, 0.4375}, fixed = {-0.5, -0.5, -0.4375, 0.4375, 0.375, 0.4375},
}, },
tiles = {"mcl_chests_blank.png"}, tiles = {"blank.png^[resize:16x16"},
use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "clip" or true, use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "clip" or true,
groups = {handy=1,axey=1, container=6,not_in_creative_inventory=1, material_wood=1,flammable=-1,double_chest=2}, groups = {handy=1,axey=1, container=6,not_in_creative_inventory=1, material_wood=1,flammable=-1,double_chest=2},
drop = drop, drop = drop,
@ -842,15 +840,6 @@ register_chest("chest",
{ {
small = tiles_chest_normal_small, small = tiles_chest_normal_small,
double = tiles_chest_normal_double, double = tiles_chest_normal_double,
inv = {"default_chest_top.png", "mcl_chests_chest_bottom.png",
"mcl_chests_chest_right.png", "mcl_chests_chest_left.png",
"mcl_chests_chest_back.png", "default_chest_front.png"},
--[[left = {"default_chest_top_big.png", "default_chest_top_big.png",
"mcl_chests_chest_right.png", "mcl_chests_chest_left.png",
"default_chest_side_big.png^[transformFX", "default_chest_front_big.png"},
right = {"default_chest_top_big.png^[transformFX", "default_chest_top_big.png^[transformFX",
"mcl_chests_chest_right.png", "mcl_chests_chest_left.png",
"default_chest_side_big.png", "default_chest_front_big.png^[transformFX"},]]--
}, },
false false
) )
@ -858,15 +847,6 @@ register_chest("chest",
local traptiles = { local traptiles = {
small = tiles_chest_trapped_small, small = tiles_chest_trapped_small,
double = tiles_chest_trapped_double, double = tiles_chest_trapped_double,
inv = {"mcl_chests_chest_trapped_top.png", "mcl_chests_chest_trapped_bottom.png",
"mcl_chests_chest_trapped_right.png", "mcl_chests_chest_trapped_left.png",
"mcl_chests_chest_trapped_back.png", "mcl_chests_chest_trapped_front.png"},
--[[left = {"mcl_chests_chest_trapped_top_big.png", "mcl_chests_chest_trapped_top_big.png",
"mcl_chests_chest_trapped_right.png", "mcl_chests_chest_trapped_left.png",
"mcl_chests_chest_trapped_side_big.png^[transformFX", "mcl_chests_chest_trapped_front_big.png"},
right = {"mcl_chests_chest_trapped_top_big.png^[transformFX", "mcl_chests_chest_trapped_top_big.png^[transformFX",
"mcl_chests_chest_trapped_right.png", "mcl_chests_chest_trapped_left.png",
"mcl_chests_chest_trapped_side_big.png", "mcl_chests_chest_trapped_front_big.png^[transformFX"},]]--
} }
register_chest("trapped_chest", register_chest("trapped_chest",
@ -992,7 +972,7 @@ minetest.register_node("mcl_chests:ender_chest", {
_doc_items_longdesc = S("Ender chests grant you access to a single personal interdimensional inventory with 27 slots. This inventory is the same no matter from which ender chest you access it from. If you put one item into one ender chest, you will find it in all other ender chests. Each player will only see their own items, but not the items of other players."), _doc_items_longdesc = S("Ender chests grant you access to a single personal interdimensional inventory with 27 slots. This inventory is the same no matter from which ender chest you access it from. If you put one item into one ender chest, you will find it in all other ender chests. Each player will only see their own items, but not the items of other players."),
_doc_items_usagehelp = S("Rightclick the ender chest to access your personal interdimensional inventory."), _doc_items_usagehelp = S("Rightclick the ender chest to access your personal interdimensional inventory."),
drawtype = "mesh", drawtype = "mesh",
mesh = "mcl_chests_chest.obj", mesh = "mcl_chests_chest.b3d",
tiles = tiles_chest_ender_small, tiles = tiles_chest_ender_small,
use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "opaque" or false, use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "opaque" or false,
paramtype = "light", paramtype = "light",
@ -1034,11 +1014,8 @@ minetest.register_node("mcl_chests:ender_chest_small", {
_chest_entity_sound = "mcl_chests_enderchest", _chest_entity_sound = "mcl_chests_enderchest",
_chest_entity_mesh = "mcl_chests_chest", _chest_entity_mesh = "mcl_chests_chest",
_chest_entity_animation_type = "chest", _chest_entity_animation_type = "chest",
tiles = {"mcl_chests_blank.png"}, tiles = {"blank.png^[resize:16x16"},
use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "clip" or true, use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "clip" or true,
--[[{"mcl_chests_ender_chest_top.png", "mcl_chests_ender_chest_bottom.png",
"mcl_chests_ender_chest_right.png", "mcl_chests_ender_chest_left.png",
"mcl_chests_ender_chest_back.png", "mcl_chests_ender_chest_front.png"},]]--
-- Note: The “container” group is missing here because the ender chest does not -- Note: The “container” group is missing here because the ender chest does not
-- have an inventory on its own -- have an inventory on its own
groups = {pickaxey=1, deco_block=1, material_stone=1, chest_entity=1, not_in_creative_inventory=1}, groups = {pickaxey=1, deco_block=1, material_stone=1, chest_entity=1, not_in_creative_inventory=1},
@ -1188,13 +1165,7 @@ for color, desc in pairs(boxtypes) do
tiles = {mob_texture}, tiles = {mob_texture},
use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "opaque" or false, use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "opaque" or false,
drawtype = "mesh", drawtype = "mesh",
mesh = "mcl_chests_shulker.obj", mesh = "mcl_chests_shulker.b3d",
--[["mcl_chests_"..color.."_shulker_box_top.png", -- top
"[combine:16x16:-32,-28="..mob_texture, -- bottom
"[combine:16x16:0,-36="..mob_texture..":0,-16="..mob_texture, -- side
"[combine:16x16:-32,-36="..mob_texture..":-32,-16="..mob_texture, -- side
"[combine:16x16:-16,-36="..mob_texture..":-16,-16="..mob_texture, -- side
"[combine:16x16:-48,-36="..mob_texture..":-48,-16="..mob_texture, -- side]]--
groups = {handy=1,pickaxey=1, container=3, deco_block=1, dig_by_piston=1, shulker_box=1, old_shulker_box_node=1}, groups = {handy=1,pickaxey=1, container=3, deco_block=1, dig_by_piston=1, shulker_box=1, old_shulker_box_node=1},
is_ground_content = false, is_ground_content = false,
sounds = mcl_sounds.node_sound_stone_defaults(), sounds = mcl_sounds.node_sound_stone_defaults(),
@ -1250,7 +1221,7 @@ for color, desc in pairs(boxtypes) do
_doc_items_longdesc = longdesc, _doc_items_longdesc = longdesc,
_doc_items_usagehelp = usagehelp, _doc_items_usagehelp = usagehelp,
drawtype = "nodebox", drawtype = "nodebox",
tiles = {"mcl_chests_blank.png"}, tiles = {"blank.png^[resize:16x16"},
use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "clip" or true, use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "clip" or true,
_chest_entity_textures = {mob_texture}, _chest_entity_textures = {mob_texture},
_chest_entity_sound = "mcl_chests_shulker", _chest_entity_sound = "mcl_chests_shulker",

View file

@ -1,91 +0,0 @@
# Blender v2.76 (sub 0) OBJ File: 'chest.small.facedir.blend'
# www.blender.org
mtllib chest.small.facedir.mtl
o chest_upper_upper
v 0.062513 -0.063134 -0.500468
v 0.062513 0.186920 -0.500468
v 0.062514 -0.063134 -0.437955
v 0.062514 0.186920 -0.437955
v -0.062514 -0.063134 -0.500468
v -0.062514 0.186920 -0.500468
v -0.062514 -0.063134 -0.437955
v -0.062514 0.186920 -0.437955
v 0.437907 0.061263 -0.438085
v 0.437907 0.373830 -0.438085
v 0.437907 0.061263 0.437729
v 0.437907 0.373830 0.437729
v -0.437907 0.061263 -0.438085
v -0.437907 0.373830 -0.438085
v -0.437907 0.061263 0.437729
v -0.437907 0.373830 0.437729
v 0.437595 -0.500754 -0.437772
v 0.437595 0.124381 -0.437772
v 0.437595 -0.500754 0.437417
v 0.437595 0.124381 0.437417
v -0.437595 -0.500754 -0.437772
v -0.437595 0.124381 -0.437772
v -0.437595 -0.500754 0.437417
v -0.437595 0.124381 0.437417
vt 0.015625 0.921875
vt 0.015625 0.984375
vt 0.000000 0.984375
vt 0.000000 0.921875
vt 0.093750 0.921875
vt 0.093750 0.984375
vt 0.062500 0.984375
vt 0.062500 0.921875
vt 0.046875 0.984375
vt 0.046875 0.921875
vt 0.078125 0.984375
vt 0.078125 1.000000
vt 0.046875 1.000000
vt 0.015625 1.000000
vt 0.218750 0.703125
vt 0.218750 0.781250
vt 0.000000 0.781250
vt 0.000000 0.703125
vt 0.875000 0.703125
vt 0.875000 0.781250
vt 0.656250 0.781250
vt 0.656250 0.703125
vt 0.437500 0.781250
vt 0.437500 0.703125
vt 0.656250 1.000000
vt 0.437500 1.000000
vt 0.218750 1.000000
vt 0.218750 0.328125
vt 0.218750 0.484375
vt -0.000000 0.484375
vt -0.000000 0.328125
vt 0.875000 0.328125
vt 0.875000 0.484375
vt 0.656250 0.484375
vt 0.656250 0.328125
vt 0.437500 0.484375
vt 0.437500 0.328125
vn 1.000000 0.000000 -0.000000
vn 0.000000 0.000000 1.000000
vn -1.000000 0.000000 0.000000
vn 0.000000 0.000000 -1.000000
vn 0.000000 -1.000000 0.000000
vn 0.000000 1.000000 0.000000
usemtl None
s off
f 1/1/1 2/2/1 4/3/1 3/4/1
f 3/5/2 4/6/2 8/7/2 7/8/2
f 7/8/3 8/7/3 6/9/3 5/10/3
f 5/10/4 6/9/4 2/2/4 1/1/4
f 3/9/5 7/11/5 5/12/5 1/13/5
f 8/13/6 4/14/6 2/2/6 6/9/6
f 9/15/1 10/16/1 12/17/1 11/18/1
f 11/19/2 12/20/2 16/21/2 15/22/2
f 15/22/3 16/21/3 14/23/3 13/24/3
f 13/24/4 14/23/4 10/16/4 9/15/4
f 11/25/5 15/26/5 13/23/5 9/21/5
f 16/26/6 12/27/6 10/16/6 14/23/6
f 17/28/1 18/29/1 20/30/1 19/31/1
f 19/32/2 20/33/2 24/34/2 23/35/2
f 23/35/3 24/34/3 22/36/3 21/37/3
f 21/37/4 22/36/4 18/29/4 17/28/4
f 19/22/5 23/24/5 21/36/5 17/34/5
f 24/24/6 20/15/6 18/29/6 22/36/6

View file

@ -1,159 +0,0 @@
# Blender v2.79 (sub 0) OBJ File: 'shulkerbox2.blend'
# www.blender.org
mtllib shulkerbox2.mtl
o low1_Cube.006
v -0.500000 -0.500001 0.500000
v -0.500000 0.062499 0.500000
v -0.500000 -0.500001 -0.500000
v -0.500000 0.062499 -0.500000
v 0.500000 -0.500001 0.500000
v 0.500000 0.062499 0.500000
v 0.500000 -0.500001 -0.500000
v 0.500000 0.062499 -0.500000
vt 0.250000 0.187500
vt -0.000000 0.187500
vt -0.000000 0.312500
vt 0.250000 0.312500
vt 1.000000 0.187500
vt 0.750000 0.187500
vt 0.750000 0.312500
vt 1.000000 0.312500
vt 0.500000 0.187500
vt 0.500000 0.312500
vt 0.750000 0.562500
vt 0.750000 0.312500
vt 0.500000 0.312500
vt 0.500000 0.562500
vt 0.500000 0.562500
vt 0.250000 0.562500
vn 1.0000 0.0000 0.0000
vn 0.0000 0.0000 1.0000
vn -1.0000 0.0000 0.0000
vn 0.0000 0.0000 -1.0000
vn 0.0000 1.0000 0.0000
vn 0.0000 -1.0000 0.0000
usemtl None
s off
f 1/1/1 3/2/1 4/3/1 2/4/1
f 3/5/2 7/6/2 8/7/2 4/8/2
f 7/6/3 5/9/3 6/10/3 8/7/3
f 5/9/4 1/1/4 2/4/4 6/10/4
f 3/11/5 1/12/5 5/13/5 7/14/5
f 8/15/6 6/10/6 2/4/6 4/16/6
o top1_Cube.005
v -0.500313 -0.220552 0.500313
v -0.500313 0.530073 0.500313
v -0.500313 -0.220552 -0.500313
v -0.500313 0.530073 -0.500313
v 0.500313 -0.220552 0.500313
v 0.500313 0.530073 0.500313
v 0.500313 -0.220552 -0.500313
v 0.500313 0.530073 -0.500313
vt 0.250000 0.562500
vt -0.000000 0.562500
vt -0.000000 0.750000
vt 0.250000 0.750000
vt 1.000000 0.562500
vt 0.750000 0.562500
vt 0.750000 0.750000
vt 1.000000 0.750000
vt 0.500000 0.562500
vt 0.500000 0.750000
vt 0.750000 1.000000
vt 0.750000 0.750000
vt 0.500000 0.750000
vt 0.500000 1.000000
vt 0.500000 1.000000
vt 0.250000 1.000000
vn 1.0000 0.0000 0.0000
vn 0.0000 0.0000 1.0000
vn -1.0000 0.0000 0.0000
vn 0.0000 0.0000 -1.0000
vn 0.0000 1.0000 0.0000
vn 0.0000 -1.0000 0.0000
usemtl None
s off
f 9/17/7 11/18/7 12/19/7 10/20/7
f 11/21/8 15/22/8 16/23/8 12/24/8
f 15/22/9 13/25/9 14/26/9 16/23/9
f 13/25/10 9/17/10 10/20/10 14/26/10
f 11/27/11 9/28/11 13/29/11 15/30/11
f 16/31/12 14/26/12 10/20/12 12/32/12
o top2_Cube.002
v -0.500247 -0.220392 0.500247
v -0.500247 0.530234 0.500247
v -0.500247 -0.220392 -0.500378
v -0.500247 0.530234 -0.500378
v 0.500378 -0.220392 0.500247
v 0.500378 0.530234 0.500247
v 0.500378 -0.220392 -0.500378
v 0.500378 0.530234 -0.500378
vt 0.250000 0.562500
vt 0.250000 0.750000
vt -0.000000 0.750000
vt -0.000000 0.562500
vt 1.000000 0.562500
vt 1.000000 0.750000
vt 0.750000 0.750000
vt 0.750000 0.562500
vt 0.500000 0.750000
vt 0.500000 0.562500
vt 0.750000 1.000000
vt 0.500000 1.000000
vt 0.500000 0.750000
vt 0.750000 0.750000
vt 0.500000 1.000000
vt 0.250000 1.000000
vn -1.0000 0.0000 0.0000
vn 0.0000 0.0000 -1.0000
vn 1.0000 0.0000 0.0000
vn 0.0000 0.0000 1.0000
vn 0.0000 -1.0000 0.0000
vn 0.0000 1.0000 0.0000
usemtl None
s off
f 17/33/13 18/34/13 20/35/13 19/36/13
f 19/37/14 20/38/14 24/39/14 23/40/14
f 23/40/15 24/39/15 22/41/15 21/42/15
f 21/42/16 22/41/16 18/34/16 17/33/16
f 19/43/17 23/44/17 21/45/17 17/46/17
f 24/47/18 20/48/18 18/34/18 22/41/18
o low2_Cube.001
v -0.499935 -0.499936 0.499935
v -0.499935 0.062565 0.499935
v -0.499935 -0.499936 -0.500066
v -0.499935 0.062565 -0.500066
v 0.500066 -0.499936 0.499935
v 0.500066 0.062565 0.499935
v 0.500066 -0.499936 -0.500066
v 0.500066 0.062565 -0.500066
vt 0.250000 0.187500
vt 0.250000 0.312500
vt -0.000000 0.312500
vt -0.000000 0.187500
vt 1.000000 0.187500
vt 1.000000 0.312500
vt 0.750000 0.312500
vt 0.750000 0.187500
vt 0.500000 0.312500
vt 0.500000 0.187500
vt 0.750000 0.562500
vt 0.500000 0.562500
vt 0.500000 0.312500
vt 0.750000 0.312500
vt 0.500000 0.562500
vt 0.250000 0.562500
vn -1.0000 0.0000 0.0000
vn 0.0000 0.0000 -1.0000
vn 1.0000 0.0000 0.0000
vn 0.0000 0.0000 1.0000
vn 0.0000 -1.0000 0.0000
vn 0.0000 1.0000 0.0000
usemtl None
s off
f 25/49/19 26/50/19 28/51/19 27/52/19
f 27/53/20 28/54/20 32/55/20 31/56/20
f 31/56/21 32/55/21 30/57/21 29/58/21
f 29/58/22 30/57/22 26/50/22 25/49/22
f 27/59/23 31/60/23 29/61/23 25/62/23
f 32/63/24 28/64/24 26/50/24 30/57/24

Binary file not shown.

Before

Width:  |  Height:  |  Size: 220 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 224 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 210 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 194 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 200 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 570 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 218 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 168 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 196 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 209 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 218 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 168 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 239 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 239 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 196 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 209 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 210 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 194 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 200 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 189 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 161 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 199 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 189 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 189 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 191 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 B

View file

@ -88,10 +88,13 @@ minetest.register_node("mcl_core:stone_with_gold", {
}) })
local redstone_timer = 68.28 local redstone_timer = 68.28
local function redstone_ore_activate(pos) local function redstone_ore_activate(pos, node, puncher, pointed_thing)
minetest.swap_node(pos, {name="mcl_core:stone_with_redstone_lit"}) minetest.swap_node(pos, {name="mcl_core:stone_with_redstone_lit"})
local t = minetest.get_node_timer(pos) local t = minetest.get_node_timer(pos)
t:start(redstone_timer) t:start(redstone_timer)
if puncher and pointed_thing then
return minetest.node_punch(pos, node, puncher, pointed_thing)
end
end end
minetest.register_node("mcl_core:stone_with_redstone", { minetest.register_node("mcl_core:stone_with_redstone", {
description = S("Redstone Ore"), description = S("Redstone Ore"),
@ -126,9 +129,12 @@ minetest.register_node("mcl_core:stone_with_redstone", {
} }
}) })
local function redstone_ore_reactivate(pos) local function redstone_ore_reactivate(pos, node, puncher, pointed_thing)
local t = minetest.get_node_timer(pos) local t = minetest.get_node_timer(pos)
t:start(redstone_timer) t:start(redstone_timer)
if puncher and pointed_thing then
return minetest.node_punch(pos, node, puncher, pointed_thing)
end
end end
-- Light the redstone ore up when it has been touched -- Light the redstone ore up when it has been touched
minetest.register_node("mcl_core:stone_with_redstone_lit", { minetest.register_node("mcl_core:stone_with_redstone_lit", {

View file

@ -116,15 +116,21 @@ end
local redstone_timer = 68.28 local redstone_timer = 68.28
local function redstone_ore_activate(pos) local function redstone_ore_activate(pos, node, puncher, pointed_thing)
minetest.swap_node(pos, { name = "mcl_deepslate:deepslate_with_redstone_lit" }) minetest.swap_node(pos, { name = "mcl_deepslate:deepslate_with_redstone_lit" })
local t = minetest.get_node_timer(pos) local t = minetest.get_node_timer(pos)
t:start(redstone_timer) t:start(redstone_timer)
if puncher and pointed_thing then
return minetest.node_punch(pos, node, puncher, pointed_thing)
end
end end
local function redstone_ore_reactivate(pos) local function redstone_ore_reactivate(pos, node, puncher, pointed_thing)
local t = minetest.get_node_timer(pos) local t = minetest.get_node_timer(pos)
t:start(redstone_timer) t:start(redstone_timer)
if puncher and pointed_thing then
return minetest.node_punch(pos, node, puncher, pointed_thing)
end
end end
minetest.register_node("mcl_deepslate:deepslate_with_redstone", { minetest.register_node("mcl_deepslate:deepslate_with_redstone", {

View file

@ -281,6 +281,13 @@ local function apply_bone_meal(pointed_thing)
if math.random(1, 100) <= 75 then if math.random(1, 100) <= 75 then
return mcl_farming:grow_plant("plant_beetroot", pos, n, 1, true) return mcl_farming:grow_plant("plant_beetroot", pos, n, 1, true)
end end
elseif string.find(n.name, "mcl_farming:sweet_berry_bush_") then
mcl_dye.add_bone_meal_particle(pos)
if n.name == "mcl_farming:sweet_berry_bush_3" then
return minetest.add_item(vector.offset(pos,math.random()-0.5,math.random()-0.5,math.random()-0.5),"mcl_farming:sweet_berry")
else
return mcl_farming:grow_plant("plant_sweet_berry_bush", pos, n, 1, true)
end
elseif n.name == "mcl_cocoas:cocoa_1" or n.name == "mcl_cocoas:cocoa_2" then elseif n.name == "mcl_cocoas:cocoa_1" or n.name == "mcl_cocoas:cocoa_2" then
mcl_dye.add_bone_meal_particle(pos) mcl_dye.add_bone_meal_particle(pos)
-- Cocoa: Advance by 1 stage -- Cocoa: Advance by 1 stage

View file

@ -27,3 +27,6 @@ dofile(minetest.get_modpath("mcl_farming").."/potatoes.lua")
-- ========= BEETROOT ========= -- ========= BEETROOT =========
dofile(minetest.get_modpath("mcl_farming").."/beetroot.lua") dofile(minetest.get_modpath("mcl_farming").."/beetroot.lua")
-- ========= SWEET BERRY =========
dofile(minetest.get_modpath("mcl_farming").."/sweet_berry.lua")

View file

@ -0,0 +1,87 @@
local S = minetest.get_translator(minetest.get_current_modname())
local planton = {"mcl_core:dirt_with_grass", "mcl_core:dirt", "mcl_core:podzol", "mcl_core:coarse_dirt", "mcl_farming:soil", "mcl_farming:soil_wet", "mcl_moss:moss"}
for i=0, 3 do
local texture = "mcl_farming_sweet_berry_bush_" .. i .. ".png"
local node_name = "mcl_farming:sweet_berry_bush_" .. i
local groups = {sweet_berry=1, dig_immediate=3, not_in_creative_inventory=1,plant=1,attached_node=1,dig_by_water=1,destroy_by_lava_flow=1,dig_by_piston=1, flammable=3, fire_encouragement=60, fire_flammability=20, compostability=30}
if i > 0 then
groups.sweet_berry_thorny = 1
end
minetest.register_node(node_name, {
drawtype = "plantlike",
tiles = {texture},
description = S("Sweet Berry Bush (Stage @1)", i),
paramtype = "light",
sunlight_propagates = true,
paramtype2 = "meshoptions",
place_param2 = 3,
liquid_viscosity = 15,
liquidtype = "source",
liquid_alternative_flowing = node_name,
liquid_alternative_source = node_name,
liquid_renewable = false,
liquid_range = 0,
walkable = false,
drop = (i>=2) and ("mcl_farming:sweet_berry" .. (i==3 and " 3" or "")) or "",
selection_box = {
type = "fixed",
fixed = {-6 / 16, -0.5, -6 / 16, 6 / 16, (-0.30 + (i*0.25)), 6 / 16},
},
inventory_image = texture,
wield_image = texture,
groups = groups,
sounds = mcl_sounds.node_sound_leaves_defaults(),
_mcl_blast_resistance = 0,
_mcl_hardness = 0,
})
minetest.register_alias("mcl_sweet_berry:sweet_berry_bush_" .. i, node_name)
end
minetest.register_craftitem("mcl_farming:sweet_berry", {
description = S("Sweet Berry"),
inventory_image = "mcl_farming_sweet_berry.png",
_mcl_saturation = 0.4,
groups = { food = 2, eatable = 1, compostability=30 },
on_secondary_use = minetest.item_eat(1),
on_place = function(itemstack, placer, pointed_thing)
if pointed_thing.type == "node" and table.indexof(planton,minetest.get_node(pointed_thing.under).name) ~= -1 and minetest.get_node(pointed_thing.above).name == "air" then
minetest.set_node(pointed_thing.above,{name="mcl_farming:sweet_berry_bush_0"})
if not minetest.is_creative_enabled(placer:get_player_name()) then
itemstack:take_item()
end
return itemstack
end
return minetest.do_item_eat(1, nil, itemstack, placer, pointed_thing)
end,
})
minetest.register_alias("mcl_sweet_berry:sweet_berry", "mcl_farming:sweet_berry")
-- TODO: Find proper interval and chance values for sweet berry bushes. Current interval and chance values are copied from mcl_farming:beetroot which has similar growth stages.
mcl_farming:add_plant("plant_sweet_berry_bush", "mcl_farming:sweet_berry_bush_3", {"mcl_farming:sweet_berry_bush_0", "mcl_farming:sweet_berry_bush_1", "mcl_farming:sweet_berry_bush_2"}, 68, 3)
local function berry_damage_check(obj)
local p = obj:get_pos()
if not p then return end
if not minetest.find_node_near(p,0.4,{"group:sweet_berry_thorny"},true) then return end
local v = obj:get_velocity()
if v.x < 0.1 and v.y < 0.1 and v.z < 0.1 then return end
mcl_util.deal_damage(obj, 0.5, {type = "sweet_berry"})
end
local etime = 0
minetest.register_globalstep(function(dtime)
etime = dtime + etime
if etime < 0.5 then return end
etime = 0
for _,pl in pairs(minetest.get_connected_players()) do
berry_damage_check(pl)
end
for _,ent in pairs(minetest.luaentities) do
if ent.is_mob then
berry_damage_check(ent.object)
end
end
end)

Binary file not shown.

After

Width:  |  Height:  |  Size: 462 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 759 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 800 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 858 B

View file

@ -10,7 +10,7 @@ to play. And that's it!
`mcl_jukebox_track_2.ogg`: “The Energetic Rat (Jordach's Mix)” by SoundHelix (CC0) `mcl_jukebox_track_2.ogg`: “The Energetic Rat (Jordach's Mix)” by SoundHelix (CC0)
`mcl_jukebox_track_3.ogg`: “Eastern Feeling” by Jordach (CC0) `mcl_jukebox_track_3.ogg`: “Eastern Feeling” by Jordach (CC0)
`mcl_jukebox_track_4.ogg`: “Minetest” by Jordach (CC0) `mcl_jukebox_track_4.ogg`: “Minetest” by Jordach (CC0)
`mcl_jukebox_track_5.ogg`: “Credit Roll (Jordach's HD Mix)” by Junichi Masuda (CC0) `mcl_jukebox_track_5.ogg`: "Soaring over the sea" by mactonite http://ccmixter.org/files/mactonite/65379 (CC-BY)
`mcl_jukebox_track_6.ogg`: “Winter Feeling" by Tom Peter (CC BY-SA 3.0) `mcl_jukebox_track_6.ogg`: “Winter Feeling" by Tom Peter (CC BY-SA 3.0)
`mcl_jukebox_track_7.ogg`: “Synthgroove (Jordach's Mix)” by HeroOfTheWinds (CC0) `mcl_jukebox_track_7.ogg`: “Synthgroove (Jordach's Mix)” by HeroOfTheWinds (CC0)
`mcl_jukebox_track_8.ogg`: “The Clueless Frog (Jordach's Mix)” by SoundHelix (CC0) `mcl_jukebox_track_8.ogg`: “The Clueless Frog (Jordach's Mix)” by SoundHelix (CC0)

View file

@ -234,7 +234,7 @@ mcl_jukebox.register_record("The Evil Sister (Jordach's Mix)", "SoundHelix", "13
mcl_jukebox.register_record("The Energetic Rat (Jordach's Mix)", "SoundHelix", "wait", "mcl_jukebox_record_wait.png", "mcl_jukebox_track_2") mcl_jukebox.register_record("The Energetic Rat (Jordach's Mix)", "SoundHelix", "wait", "mcl_jukebox_record_wait.png", "mcl_jukebox_track_2")
mcl_jukebox.register_record("Eastern Feeling", "Jordach", "blocks", "mcl_jukebox_record_blocks.png", "mcl_jukebox_track_3") mcl_jukebox.register_record("Eastern Feeling", "Jordach", "blocks", "mcl_jukebox_record_blocks.png", "mcl_jukebox_track_3")
mcl_jukebox.register_record("Minetest", "Jordach", "far", "mcl_jukebox_record_far.png", "mcl_jukebox_track_4") mcl_jukebox.register_record("Minetest", "Jordach", "far", "mcl_jukebox_record_far.png", "mcl_jukebox_track_4")
mcl_jukebox.register_record("Credit Roll (Jordach's HD Mix)", "Junichi Masuda", "chirp", "mcl_jukebox_record_chirp.png", "mcl_jukebox_track_5") mcl_jukebox.register_record("Soaring over the sea", "mactonite", "chirp", "mcl_jukebox_record_chirp.png", "mcl_jukebox_track_5")
mcl_jukebox.register_record("Winter Feeling", "Tom Peter", "strad", "mcl_jukebox_record_strad.png", "mcl_jukebox_track_6") mcl_jukebox.register_record("Winter Feeling", "Tom Peter", "strad", "mcl_jukebox_record_strad.png", "mcl_jukebox_track_6")
mcl_jukebox.register_record("Synthgroove (Jordach's Mix)", "HeroOfTheWinds", "mellohi", "mcl_jukebox_record_mellohi.png", "mcl_jukebox_track_7") mcl_jukebox.register_record("Synthgroove (Jordach's Mix)", "HeroOfTheWinds", "mellohi", "mcl_jukebox_record_mellohi.png", "mcl_jukebox_track_7")
mcl_jukebox.register_record("The Clueless Frog (Jordach's Mix)", "SoundHelix", "mall", "mcl_jukebox_record_mall.png", "mcl_jukebox_track_8") mcl_jukebox.register_record("The Clueless Frog (Jordach's Mix)", "SoundHelix", "mall", "mcl_jukebox_record_mall.png", "mcl_jukebox_track_8")

View file

@ -1,4 +1,21 @@
Mod based on reworked signs mod by PilzAdam:
---
# Mineclone2-Signs
---
A reworking of MineClone 2's mcl_signs to be colorable and made to glow. Rquires Minetest and Mineclone2.
---
Created by Michieal (FaerRaven) @ DateTime: 10/14/22 4:05 PM
Reworked to be an API and to allow players to color, and/or make the lettering for the signs glow (be bright at night).
Reworked by Michieal (FaerRaven), including the sign textures batch changed to be white instead of the original black.
A special thanks to Cora for pointing me in the right direction (as always).
The original Mod, MCL_SIGNS is based on reworked signs mod by PilzAdam:
https://forum.minetest.net/viewtopic.php?t=3289 https://forum.minetest.net/viewtopic.php?t=3289
License of code and font: MIT License License of code and font: MIT License
@ -6,8 +23,22 @@ License of code and font: MIT License
Font source: 04.jp.org, some modifications and additions were made (added support for Latin-1 Supplement) Font source: 04.jp.org, some modifications and additions were made (added support for Latin-1 Supplement)
Original font license text states: “YOU MAY USE THEM AS YOU LIKE” (in about.gif file distributed with the font) Original font license text states: “YOU MAY USE THEM AS YOU LIKE” (in about.gif file distributed with the font)
License of textures: See README.md in top directory of MineClone 2. License of textures: See README.md in top directory of MineClone 2, with the exception of the following:
default_sign.png, default_sign_dark.png, default_sign_greyscale.png, mcl_signs_sign_dark.png,
mcl_signs_sign_greyscale.png are licensed as follows:
Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) (https://creativecommons.org/licenses/by-sa/4.0/).
Credit Michieal (Faerraven). The extra sign textures are provided for you to use, modify, etc., with the goal being to
make the game better. (All of these textures were changed / created by me, to make them usable / better.)
License of models: GPLv3 (https://www.gnu.org/licenses/gpl-3.0.html) License of models: GPLv3 (https://www.gnu.org/licenses/gpl-3.0.html)
Models author: 22i. Models author: 22i.
Source: https://github.com/22i/amc Source: https://github.com/22i/amc
Mineclone 2 source code:
https://git.minetest.land/MineClone2/MineClone2
---
NOTE: This MODule requires Glow Squids in order for all features to work 100% correctly. Glow Squids are currently
in review by the MineClone 2 Team, and should be available soon after this initial release of the new signs.

View file

@ -0,0 +1,122 @@
---
--- Generated by EmmyLua.
--- Created by Michieal (FaerRaven).
--- DateTime: 10/22/22 3:44 PM
---
SIGNS API
--- How to Use:
The simplest way to create a new sign is to use mcl_signs.register_sign [mcl_signs.register_sign (modname, color, _name,
ttsign)]. It's an all-in-one sign creator. It makes use of the standard textures for the signs, and colors them based on
the color code that you give it, and names it "mcl_signs:wall_sign" + _name. So, using the spruce sign to illustrate, it
would be named "mcl_signs:wall_sign_sprucewood", as we made _name equal to "_sprucewood" after the name of the
registered wood.
To create a sign with specific textures: use the mcl_signs.register_sign_custom [mcl_signs.register_sign_custom
(modname, _name, tiles, color, inventory_image, wield_image, ttsign)]. Like the register_sign() function, this is also an
all-in-one sign creation function. With this function you can designate what textures to use, and give them a specified
color. This function follows the same naming conventions.
If you wish to override / recreate one of the predefined signs, you may also do that. The reregister_sign() and
reregister_sign_custom() functions will replace an existing sign's definition with a new one. Caution, ONLY use this on
existing signs. If the sign doesn't exist, use the regular register_sign* functions.
--- What the parameters mean, and what they do:
* modname: optional (pass "" or "false" to ignore), for using mcl_signs with other mods to allow the creation of a sign
from the mod's wood (if installed). Use this to prevent failures of the specific mod is not installed that has the needed
information (textures, wood, etc.) Setting this is important, because it prevents items from being registered if the
mod in not installed.
* tiles: the texture file to use for the sign's node.
* color: color the texture file to use with this color. Use white (#FFFFFF) to negate the color, and just use the
texture as is.
* inventory_image: the texture file to use for the sign's display in inventory.
* wield_image: the texture file to use for the sign's weilded (in hand) object.
* _name: the sign's name suffix, such as "_dark" or "_sprucewood", etc., appended to "wall_sign" or "standing_sign"
* ttsign: the tool tip of the sign that gets translated. Shown when the mouse hovers the inventory sign. ttsign stands
for translated tooltip sign.
* wood_item_string: example: "mcl_core:wood", "mcl_core:sprucewood" or "mymod:mywood". This is used when defining the
recipe for the sign.
--- Other Functions of Importance:
* register_dye [mcl_signs.register_dye (modname, item_name, color_code)] -- this registers a new dye that the sign knows
about so that the player can color their signs with the dye.
Parameters:
modname: your mod / module's name. make sure to use this for compatibility.
item_name: the item_string of the dye to register.
color_code: the hex code for the color to make the lettering. Also called HTML color code. Ex. "#FFFFFF" is white.
* register_sign_craft [mcl_signs.register_sign_craft(modname, wood_item_string, _name)] -- this is what creates the
recipes for the sign, and makes the sign "burnable". Typically called right after the register_sign* functions.
Parameters:
_name: MUST be the same name as used for the sign. So, if your sign _name is "_sprucewood" then this should be too.
wood_item_string: the item_string of the wood to use for the sign's recipe. Example: "mcl_core:wood" (default oak).
modname: like with the other functions that has this parameter, used to make sure that nothing breaks.
* make_lbm() [mcl_signs.make_lbm()] -- This innocuous function is very important. This is the function that makes the
signs work after reloading the game. This function is the last to be called in your sign creation work flow. Note, you
do not need to call this function after every definition, just at the end of the last definition.
(See Example WorkFlow below.)
--- Example Workflow for sign creation.
* these are, at the time of writing, a selection of the actual signs' definitions. Note the functions called, and when.
-- ---------------------------- --
-- Register Signs for use. --
-- ---------------------------- --
-- sprucewood Sign
mcl_signs.register_sign_custom("mcl_core", "_sprucewood",
"mcl_signs_sign_dark.png","#ffffff", "default_sign_dark.png",
"default_sign_dark.png", "Spruce Sign"
)
mcl_signs.register_sign_craft("mcl_core", "mcl_core:sprucewood", "_sprucewood")
-- darkwood Sign
mcl_signs.register_sign_custom("mcl_core", "_darkwood",
"mcl_signs_sign_greyscale.png","#856443", "default_sign_greyscale.png",
"default_sign_greyscale.png", "Dark Oak Sign"
)
mcl_signs.register_sign_craft("mcl_core", "mcl_core:darkwood", "_darkwood")
-- acaciawood Sign
mcl_signs.register_sign("mcl_core", "#ea7479", "_acaciawood", "Acacia Sign")
mcl_signs.register_sign_craft("mcl_core", "mcl_core:acaciawood", "_acaciawood")
-- junglewood Sign
mcl_signs.register_sign("mcl_core", "#866249", "_junglewood", "Jungle Sign")
mcl_signs.register_sign_craft("mcl_core", "mcl_core:junglewood", "_junglewood")
-- Register the LBMs for the created signs.
mcl_signs.make_lbm()
--- -----------------------------------------------------------------------------
* If you wish to use a recipe other than the standard sign recipe, you will need to define your own recipe. In doing so,
use this output line:
output = "mcl_signs:wall_sign" .. _name .. " 3",
where _name is the same string that you have used throughout your sign's workflow. That way, when players make the recipe,
they get your sign (x3).
--- Future landmarks on the horizon for the Signs API:
* Once the forthcoming Hanging Signs are in Minecraft, and we implement the code for them in here, hanging signs will
automatically exist as part of the signs' package. You won't have to change any of your code, it'll just be more
functional. :)
* if you have suggestions, comments, etc., please contact me on MineClone 2's Discord server.
And that... is all there is to it!
-- written by Michieal.

View file

@ -1,517 +1,31 @@
---
--- Generated by EmmyLua.
--- Created by Michieal (FaerRaven).
--- DateTime: 10/14/22 4:05 PM
---
local modname = minetest.get_current_modname() local modname = minetest.get_current_modname()
local modpath = minetest.get_modpath(modname) local modpath = minetest.get_modpath(modname)
-- Signs API
dofile(modpath .. "/signs_api.lua")
-- LOCALIZATION
local S = minetest.get_translator(modname) local S = minetest.get_translator(modname)
local F = minetest.formspec_escape
local table = table
-- Load the characters map (characters.txt)
--[[ File format of characters.txt:
It's an UTF-8 encoded text file that contains metadata for all supported characters. It contains a sequence of info blocks, one for each character. Each info block is made out of 3 lines:
Line 1: The literal UTF-8 encoded character
Line 2: Name of the texture file for this character minus the .png suffix; found in the textures/ sub-directory
Line 3: Currently ignored. Previously this was for the character width in pixels
After line 3, another info block may follow. This repeats until the end of the file.
All character files must be 5 or 6 pixels wide (5 pixels are preferred)
]]
local chars_file = io.open(modpath.."/characters.txt", "r")
-- FIXME: Support more characters (many characters are missing). Currently ASCII and Latin-1 Supplement are supported.
local charmap = {}
if not chars_file then
minetest.log("error", "[mcl_signs] : character map file not found")
else
while true do
local char = chars_file:read("*l")
if char == nil then
break
end
local img = chars_file:read("*l")
chars_file:read("*l")
charmap[char] = img
end
end
-- CONSTANTS
local SIGN_WIDTH = 115
local LINE_LENGTH = 15
local NUMBER_OF_LINES = 4
local LINE_HEIGHT = 14
local CHAR_WIDTH = 5
-- Helper functions
local function round(num, idp)
local mult = 10^(idp or 0)
return math.floor(num * mult + 0.5) / mult
end
local function string_to_array(str)
local tab = {}
for i=1,string.len(str) do
table.insert(tab, string.sub(str, i,i))
end
return tab
end
local function string_to_line_array(str)
local tab = {}
local current = 1
local linechar = 1
tab[1] = ""
for _,char in ipairs(string_to_array(str)) do
-- New line
if char == "\n" then
current = current + 1
tab[current] = ""
linechar = 1
else
tab[current] = tab[current]..char
linechar = linechar + 1
end
end
return tab
end
local function create_lines(text)
local line_num = 1
local tab = {}
for _, line in ipairs(string_to_line_array(text)) do
if line_num > NUMBER_OF_LINES then
break
end
table.insert(tab, line)
line_num = line_num + 1
end
return tab
end
local function generate_line(s, ypos)
local i = 1
local parsed = {}
local width = 0
local chars = 0
local printed_char_width = CHAR_WIDTH + 1
while chars < LINE_LENGTH and i <= #s do
local file
-- Get and render character
if charmap[s:sub(i, i)] then
file = charmap[s:sub(i, i)]
i = i + 1
elseif i < #s and charmap[s:sub(i, i + 1)] then
file = charmap[s:sub(i, i + 1)]
i = i + 2
else
-- No character image found.
-- Use replacement character:
file = "_rc"
i = i + 1
minetest.log("verbose", "[mcl_signs] Unknown symbol in '"..s.."' at "..i)
end
if file then
width = width + printed_char_width
table.insert(parsed, file)
chars = chars + 1
end
end
width = width - 1
local texture = ""
local xpos = math.floor((SIGN_WIDTH - width) / 2)
for i = 1, #parsed do
texture = texture..":"..xpos..","..ypos.."="..parsed[i]..".png"
xpos = xpos + printed_char_width
end
return texture
end
local function generate_texture(lines, signnodename)
local texture = "[combine:"..SIGN_WIDTH.."x"..SIGN_WIDTH
local ypos
if signnodename == "mcl_signs:wall_sign" then
ypos = 30
else
ypos = 0
end
for i = 1, #lines do
texture = texture..generate_line(lines[i], ypos)
ypos = ypos + LINE_HEIGHT
end
return texture
end
local n = 23/56 - 1/128
local signtext_info_wall = {
{delta = {x = 0, y = 0, z = n}, yaw = 0},
{delta = {x = n, y = 0, z = 0}, yaw = math.pi / -2},
{delta = {x = 0, y = 0, z = -n}, yaw = math.pi},
{delta = {x = -n, y = 0, z = 0}, yaw = math.pi / 2},
}
local signtext_info_standing = {}
local m = -1/16 + 1/64
for rot=0, 15 do
local yaw = math.pi*2 - (((math.pi*2) / 16) * rot)
local delta = vector.multiply(minetest.yaw_to_dir(yaw), m)
-- Offset because sign is a bit above node boundaries
delta.y = delta.y + 2/28
table.insert(signtext_info_standing, { delta = delta, yaw = yaw })
end
local function get_rotation_level(facedir, nodename)
local rl = facedir * 4
if nodename == "mcl_signs:standing_sign22_5" then
rl = rl + 1
elseif nodename == "mcl_signs:standing_sign45" then
rl = rl + 2
elseif nodename == "mcl_signs:standing_sign67_5" then
rl = rl + 3
end
return rl
end
local function get_wall_signtext_info(param2, nodename)
local dir = minetest.wallmounted_to_dir(param2)
if dir.x > 0 then
return 2
elseif dir.z > 0 then
return 1
elseif dir.x < 0 then
return 4
else
return 3
end
end
local sign_groups = {handy=1,axey=1, deco_block=1, material_wood=1, attached_node=1, dig_by_piston=1, flammable=-1}
local function destruct_sign(pos)
local objects = minetest.get_objects_inside_radius(pos, 0.5)
for _, v in ipairs(objects) do
local ent = v:get_luaentity()
if ent and ent.name == "mcl_signs:text" then
v:remove()
end
end
local players = minetest.get_connected_players()
for p=1, #players do
if vector.distance(players[p]:get_pos(), pos) <= 30 then
minetest.close_formspec(players[p]:get_player_name(), "mcl_signs:set_text_"..pos.x.."_"..pos.y.."_"..pos.z)
end
end
end
local function update_sign(pos, fields, sender, force_remove)
local meta = minetest.get_meta(pos)
if not meta then
return
end
local text = meta:get_string("text")
if fields and (text == "" and fields.text) then
meta:set_string("text", fields.text)
text = fields.text
end
if text == nil then
text = ""
end
local sign_info
local n = minetest.get_node(pos)
local nn = n.name
if nn == "mcl_signs:standing_sign" or nn == "mcl_signs:standing_sign22_5" or nn == "mcl_signs:standing_sign45" or nn == "mcl_signs:standing_sign67_5" then
sign_info = signtext_info_standing[get_rotation_level(n.param2, nn) + 1]
elseif nn == "mcl_signs:wall_sign" then
sign_info = signtext_info_wall[get_wall_signtext_info(n.param2)]
end
if sign_info == nil then
minetest.log("error", "[mcl_signs] Missing sign_info!")
return
end
local objects = minetest.get_objects_inside_radius(pos, 0.5)
local text_entity
for _, v in ipairs(objects) do
local ent = v:get_luaentity()
if ent and ent.name == "mcl_signs:text" then
if force_remove then
v:remove()
else
text_entity = v
break
end
end
end
if not text_entity then
text_entity = minetest.add_entity({
x = pos.x + sign_info.delta.x,
y = pos.y + sign_info.delta.y,
z = pos.z + sign_info.delta.z}, "mcl_signs:text")
end
text_entity:get_luaentity()._signnodename = nn
text_entity:set_properties({textures={generate_texture(create_lines(text), nn)}})
text_entity:set_yaw(sign_info.yaw)
end
local function show_formspec(player, pos)
minetest.show_formspec(
player:get_player_name(),
"mcl_signs:set_text_"..pos.x.."_"..pos.y.."_"..pos.z,
"size[6,3]textarea[0.25,0.25;6,1.5;text;"..F(S("Enter sign text:"))..";]label[0,1.5;"..F(S("Maximum line length: 15")).."\n"..F(S("Maximum lines: 4")).."]button_exit[0,2.5;6,1;submit;"..F(S("Done")).."]"
)
end
-- HANDLE THE FORMSPEC CALLBACK
minetest.register_on_player_receive_fields(function(player, formname, fields) minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname:find("mcl_signs:set_text_") == 1 then if formname:find("mcl_signs:set_text_") == 1 then
local x, y, z = formname:match("mcl_signs:set_text_(.-)_(.-)_(.*)") local x, y, z = formname:match("mcl_signs:set_text_(.-)_(.-)_(.*)")
local pos = {x=tonumber(x), y=tonumber(y), z=tonumber(z)} local pos = { x = tonumber(x), y = tonumber(y), z = tonumber(z) }
if not pos or not pos.x or not pos.y or not pos.z then return end if not pos or not pos.x or not pos.y or not pos.z then
update_sign(pos, fields, player) return
end
mcl_signs:update_sign(pos, fields, player)
end end
end) end)
local node_sounds -- This defines the text entity for the lettering of the sign.
if minetest.get_modpath("mcl_sounds") then
node_sounds = mcl_sounds.node_sound_wood_defaults()
end
minetest.register_node("mcl_signs:wall_sign", {
description = S("Sign"),
_tt_help = S("Can be written"),
_doc_items_longdesc = S("Signs can be written and come in two variants: Wall sign and sign on a sign post. Signs can be placed on the top and the sides of other blocks, but not below them."),
_doc_items_usagehelp = S("After placing the sign, you can write something on it. You have 4 lines of text with up to 15 characters for each line; anything beyond these limits is lost. Not all characters are supported. The text can not be changed once it has been written; you have to break and place the sign again."),
inventory_image = "default_sign.png",
walkable = false,
is_ground_content = false,
wield_image = "default_sign.png",
node_placement_prediction = "",
paramtype = "light",
sunlight_propagates = true,
paramtype2 = "wallmounted",
drawtype = "mesh",
mesh = "mcl_signs_signonwallmount.obj",
selection_box = {type = "wallmounted", wall_side = {-0.5, -7/28, -0.5, -23/56, 7/28, 0.5}},
tiles = {"mcl_signs_sign.png"},
use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "opaque" or false,
groups = sign_groups,
stack_max = 16,
sounds = node_sounds,
on_place = function(itemstack, placer, pointed_thing)
local above = pointed_thing.above
local under = pointed_thing.under
-- Use pointed node's on_rightclick function first, if present
local node_under = minetest.get_node(under)
if placer and not placer:get_player_control().sneak then
if minetest.registered_nodes[node_under.name] and minetest.registered_nodes[node_under.name].on_rightclick then
return minetest.registered_nodes[node_under.name].on_rightclick(under, node_under, placer, itemstack) or itemstack
end
end
local dir = vector.subtract(under, above)
-- Only build when it's legal
local abovenodedef = minetest.registered_nodes[minetest.get_node(above).name]
if not abovenodedef or abovenodedef.buildable_to == false then
return itemstack
end
local wdir = minetest.dir_to_wallmounted(dir)
--local placer_pos = placer:get_pos()
local fdir = minetest.dir_to_facedir(dir)
local sign_info
local nodeitem = ItemStack(itemstack)
-- Ceiling
if wdir == 0 then
--how would you add sign to ceiling?
return itemstack
-- Floor
elseif wdir == 1 then
-- Standing sign
-- Determine the sign rotation based on player's yaw
local yaw = math.pi*2 - placer:get_look_horizontal()
-- Select one of 16 possible rotations (0-15)
local rotation_level = round((yaw / (math.pi*2)) * 16)
if rotation_level > 15 then
rotation_level = 0
elseif rotation_level < 0 then
rotation_level = 15
end
-- The actual rotation is a combination of predefined mesh and facedir (see node definition)
if rotation_level % 4 == 0 then
nodeitem:set_name("mcl_signs:standing_sign")
elseif rotation_level % 4 == 1 then
nodeitem:set_name("mcl_signs:standing_sign22_5")
elseif rotation_level % 4 == 2 then
nodeitem:set_name("mcl_signs:standing_sign45")
elseif rotation_level % 4 == 3 then
nodeitem:set_name("mcl_signs:standing_sign67_5")
end
fdir = math.floor(rotation_level / 4)
-- Place the node!
local _, success = minetest.item_place_node(nodeitem, placer, pointed_thing, fdir)
if not success then
return itemstack
end
if not minetest.is_creative_enabled(placer:get_player_name()) then
itemstack:take_item()
end
sign_info = signtext_info_standing[rotation_level + 1]
-- Side
else
-- Wall sign
local _, success = minetest.item_place_node(itemstack, placer, pointed_thing, wdir)
if not success then
return itemstack
end
sign_info = signtext_info_wall[fdir + 1]
end
-- Determine spawn position of entity
local place_pos
if minetest.registered_nodes[node_under.name].buildable_to then
place_pos = under
else
place_pos = above
end
local text_entity = minetest.add_entity({
x = place_pos.x + sign_info.delta.x,
y = place_pos.y + sign_info.delta.y,
z = place_pos.z + sign_info.delta.z}, "mcl_signs:text")
text_entity:set_yaw(sign_info.yaw)
text_entity:get_luaentity()._signnodename = nodeitem:get_name()
minetest.sound_play({name="default_place_node_hard", gain=1.0}, {pos = place_pos}, true)
show_formspec(placer, place_pos)
return itemstack
end,
on_destruct = destruct_sign,
on_punch = function(pos, node, puncher)
update_sign(pos)
end,
on_rotate = function(pos, node, user, mode)
if mode == screwdriver.ROTATE_FACE then
local r = screwdriver.rotate.wallmounted(pos, node, mode)
node.param2 = r
minetest.swap_node(pos, node)
update_sign(pos, nil, nil, true)
return true
else
return false
end
end,
_mcl_hardness = 1,
_mcl_blast_resistance = 1,
})
-- Standing sign nodes.
-- 4 rotations at 0°, 22.5°, 45° and 67.5°.
-- These are 4 out of 16 possible rotations.
-- With facedir the remaining 12 rotations are constructed.
-- 0°
local ssign = {
paramtype = "light",
use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "opaque" or false,
sunlight_propagates = true,
walkable = false,
is_ground_content = false,
paramtype2 = "facedir",
drawtype = "mesh",
mesh = "mcl_signs_sign.obj",
selection_box = {type = "fixed", fixed = {-0.2, -0.5, -0.2, 0.2, 0.5, 0.2}},
tiles = {"mcl_signs_sign.png"},
groups = sign_groups,
drop = "mcl_signs:wall_sign",
stack_max = 16,
sounds = node_sounds,
on_destruct = destruct_sign,
on_punch = function(pos, node, puncher)
update_sign(pos)
end,
on_rotate = function(pos, node, user, mode)
if mode == screwdriver.ROTATE_FACE then
node.name = "mcl_signs:standing_sign22_5"
minetest.swap_node(pos, node)
elseif mode == screwdriver.ROTATE_AXIS then
return false
end
update_sign(pos, nil, nil, true)
return true
end,
_mcl_hardness = 1,
_mcl_blast_resistance = 1,
}
minetest.register_node("mcl_signs:standing_sign", ssign)
-- 22.5°
local ssign22_5 = table.copy(ssign)
ssign22_5.mesh = "mcl_signs_sign22.5.obj"
ssign22_5.on_rotate = function(pos, node, user, mode)
if mode == screwdriver.ROTATE_FACE then
node.name = "mcl_signs:standing_sign45"
minetest.swap_node(pos, node)
elseif mode == screwdriver.ROTATE_AXIS then
return false
end
update_sign(pos, nil, nil, true)
return true
end
minetest.register_node("mcl_signs:standing_sign22_5", ssign22_5)
-- 45°
local ssign45 = table.copy(ssign)
ssign45.mesh = "mcl_signs_sign45.obj"
ssign45.on_rotate = function(pos, node, user, mode)
if mode == screwdriver.ROTATE_FACE then
node.name = "mcl_signs:standing_sign67_5"
minetest.swap_node(pos, node)
elseif mode == screwdriver.ROTATE_AXIS then
return false
end
update_sign(pos, nil, nil, true)
return true
end
minetest.register_node("mcl_signs:standing_sign45", ssign45)
-- 67.5°
local ssign67_5 = table.copy(ssign)
ssign67_5.mesh = "mcl_signs_sign67.5.obj"
ssign67_5.on_rotate = function(pos, node, user, mode)
if mode == screwdriver.ROTATE_FACE then
node.name = "mcl_signs:standing_sign"
node.param2 = (node.param2 + 1) % 4
minetest.swap_node(pos, node)
elseif mode == screwdriver.ROTATE_AXIS then
return false
end
update_sign(pos, nil, nil, true)
return true
end
minetest.register_node("mcl_signs:standing_sign67_5", ssign67_5)
-- FIXME: Prevent entity destruction by /clearobjects -- FIXME: Prevent entity destruction by /clearobjects
minetest.register_entity("mcl_signs:text", { minetest.register_entity("mcl_signs:text", {
pointable = false, pointable = false,
@ -523,58 +37,103 @@ minetest.register_entity("mcl_signs:text", {
_signnodename = nil, -- node name of sign node to which the text belongs _signnodename = nil, -- node name of sign node to which the text belongs
on_activate = function(self, staticdata) on_activate = function(self, staticdata)
local meta = minetest.get_meta(self.object:get_pos())
local text = meta:get_string("text")
local text_color = meta:get_string("mcl_signs:text_color")
local glowing_sign = meta:get_string("mcl_signs:glowing_sign")
if staticdata and staticdata ~= "" then if staticdata and staticdata ~= "" then
local des = minetest.deserialize(staticdata) local des = minetest.deserialize(staticdata)
if des then if des then
self._signnodename = des._signnodename self._signnodename = des._signnodename
if des._text_color ~= nil and des._text_color ~= "" then
self.text_color = des._text_color
end
if des._glowing_sign ~= nil and des._glowing_sign ~= "" then
self.glowing_sign = des._glowing_sign
end end
end end
local meta = minetest.get_meta(self.object:get_pos()) end
local text = meta:get_string("text")
if text_color == "" or text_color == nil then
text_color = "#000000" -- default to black text.
meta:set_string("mcl_signs:text_color", text_color)
end
if glowing_sign == "" or glowing_sign == nil then
glowing_sign = "false" -- default to not glowing.
meta:set_string("mcl_signs:glowing_sign", glowing_sign)
end
self.object:set_properties({ self.object:set_properties({
textures={generate_texture(create_lines(text), self._signnodename)}, textures = { mcl_signs:create_lettering(text, self._signnodename, text_color) },
}) })
if glowing_sign == "true" then
self.object:set_properties({
glow = 6, --sign_glow,
})
end
self.object:set_armor_groups({ immortal = 1 }) self.object:set_armor_groups({ immortal = 1 })
end, end,
get_staticdata = function(self) get_staticdata = function(self)
local out = { _signnodename = self._signnodename } local out = {
_signnodename = self._signnodename,
}
return minetest.serialize(out) return minetest.serialize(out)
end, end,
}) })
minetest.register_craft({ -- Build the signs x,y,z & rotations so that they work. (IE, do not remove!)
type = "fuel", mcl_signs.build_signs_info()
recipe = "mcl_signs:wall_sign",
burntime = 10,
})
if minetest.get_modpath("mcl_core") then -- ---------------------------- --
minetest.register_craft({ -- Register Signs for use. --
output = "mcl_signs:wall_sign 3", -- ---------------------------- --
recipe = {
{"group:wood", "group:wood", "group:wood"},
{"group:wood", "group:wood", "group:wood"},
{"", "mcl_core:stick", ""},
}
})
end
if minetest.get_modpath("doc") then -- Standard (original) Sign
doc.add_entry_alias("nodes", "mcl_signs:wall_sign", "nodes", "mcl_signs:standing_sign") mcl_signs.register_sign("mcl_core", "#ffffff", "", "Sign")
doc.add_entry_alias("nodes", "mcl_signs:wall_sign", "nodes", "mcl_signs:standing_sign22_5") mcl_signs.register_sign_craft("mcl_core", "mcl_core:wood", "")
doc.add_entry_alias("nodes", "mcl_signs:wall_sign", "nodes", "mcl_signs:standing_sign45")
doc.add_entry_alias("nodes", "mcl_signs:wall_sign", "nodes", "mcl_signs:standing_sign67_5")
end
-- birchwood Sign "#d5cb8d" / "#ffdba7"
mcl_signs.register_sign_custom("mcl_core", "_birchwood",
"mcl_signs_sign_greyscale.png","#ffdba7", "default_sign_greyscale.png",
"default_sign_greyscale.png", "Birch Sign"
)
mcl_signs.register_sign_craft("mcl_core", "mcl_core:birchwood", "_birchwood")
-- sprucewood Sign
mcl_signs.register_sign_custom("mcl_core", "_sprucewood",
"mcl_signs_sign_dark.png","#ffffff", "default_sign_dark.png",
"default_sign_dark.png", "Spruce Sign"
)
mcl_signs.register_sign_craft("mcl_core", "mcl_core:sprucewood", "_sprucewood")
-- darkwood Sign "#291f1a" / "#856443"
mcl_signs.register_sign_custom("mcl_core", "_darkwood",
"mcl_signs_sign_greyscale.png","#856443", "default_sign_greyscale.png",
"default_sign_greyscale.png", "Dark Oak Sign"
)
mcl_signs.register_sign_craft("mcl_core", "mcl_core:darkwood", "_darkwood")
-- junglewood Sign
mcl_signs.register_sign("mcl_core", "#866249", "_junglewood", "Jungle Sign")
mcl_signs.register_sign_craft("mcl_core", "mcl_core:junglewood", "_junglewood")
-- acaciawood Sign "b8693d"
mcl_signs.register_sign("mcl_core", "#ea7479", "_acaciawood", "Acacia Sign")
mcl_signs.register_sign_craft("mcl_core", "mcl_core:acaciawood", "_acaciawood")
-- mangrove_wood Sign "#c7545c"
mcl_signs.register_sign("mcl_core", "#b8693d", "_mangrove_wood", "Mangrove Sign")
mcl_signs.register_sign_craft("mcl_core", "mcl_core:mangrove_wood", "_mangrove_wood")
-- Register the LBMs for the created signs.
mcl_signs.make_lbm()
-- really ancient compatibility.
minetest.register_alias("signs:sign_wall", "mcl_signs:wall_sign") minetest.register_alias("signs:sign_wall", "mcl_signs:wall_sign")
minetest.register_alias("signs:sign_yard", "mcl_signs:standing_sign") minetest.register_alias("signs:sign_yard", "mcl_signs:standing_sign")
minetest.register_alias("mcl_signs:wall_sign_dark", "mcl_signs:wall_sign_sprucewood")
minetest.register_lbm({ minetest.register_alias("mcl_signs:standing_sign_dark", "mcl_signs:standing_sign_sprucewood")
name = "mcl_signs:respawn_entities",
label = "Respawn sign text entities",
run_at_every_load = true,
nodenames = { "mcl_signs:wall_sign", "mcl_signs:standing_sign", "mcl_signs:standing_sign22_5", "mcl_signs:standing_sign45", "mcl_signs:standing_sign67_5" },
action = function(pos, node)
update_sign(pos)
end,
})

View file

@ -1,7 +1,7 @@
# textdomain: mcl_signs # textdomain: mcl_signs
Sign= Sign=
Signs can be written and come in two variants: Wall sign and sign on a sign post. Signs can be placed on the top and the sides of other blocks, but not below them.= Signs can be written and come in two variants: Wall sign and sign on a sign post. Signs can be placed on the top and the sides of other blocks, but not below them.=
After placing the sign, you can write something on it. You have 4 lines of text with up to 15 characters for each line; anything beyond these limits is lost. Not all characters are supported. The text can not be changed once it has been written; you have to break and place the sign again.= After placing the sign, you can write something on it. You have 4 lines of text with up to 15 characters for each line; anything beyond these limits is lost. Not all characters are supported. The text can not be changed once it has been written; you have to break and place the sign again. Can be colored and made to glow.=
Enter sign text:= Enter sign text:=
Maximum line length: 15= Maximum line length: 15=
Maximum lines: 4= Maximum lines: 4=

View file

@ -1,2 +1,4 @@
name = mcl_signs name = mcl_signs
optional_depends = mcl_sounds, mcl_core, doc description = New and Improved signs - can be colored and made to glow.
depends = mcl_core, mcl_sounds, mcl_dye, mcl_colors
optional_depends = doc

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 877 B

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 883 B

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 876 B

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 881 B

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 868 B

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 876 B

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 865 B

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 882 B

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 886 B

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 863 B

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 B

After

Width:  |  Height:  |  Size: 294 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 886 B

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 891 B

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 889 B

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 874 B

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 886 B

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 B

After

Width:  |  Height:  |  Size: 292 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 B

After

Width:  |  Height:  |  Size: 298 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 862 B

After

Width:  |  Height:  |  Size: 1.8 KiB

Some files were not shown because too many files have changed in this diff Show more