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

View File

@ -2,7 +2,7 @@
An unofficial Minecraft-like game for Minetest. Forked from MineClone by davedevils.
Developed by many people. Not developed or endorsed by Mojang AB.
Version: 0.80 (in development)
Version: 0.81 (in development)
### Gameplay
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
-- have the "airlike" drawtype. Carpets are an example of this type.
local pairs = pairs
local math = math
local vector = vector
local facedir_to_dir = minetest.facedir_to_dir
@ -22,14 +24,16 @@ local add_item = minetest.add_item
-- 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.
--
---@param p Vector
local function drop_attached_node(p)
local n = get_node(p)
local drops = get_node_drops(n, "")
local def = registered_nodes[n.name]
if def and def.preserve_metadata then
local oldmeta = get_meta(p):to_table().fields
-- Copy pos and node because the callback can modify them.
local pos_copy = vector.new(p)
local pos_copy = vector.copy(p)
local node_copy = { name = n.name, param1 = n.param1, param2 = n.param2 }
local drop_stacks = {}
for k, v in pairs(drops) do
@ -38,16 +42,18 @@ local function drop_attached_node(p)
drops = drop_stacks
def.preserve_metadata(pos_copy, node_copy, oldmeta, drops)
end
if def and def.sounds and def.sounds.fall then
core.sound_play(def.sounds.fall, {pos = p}, true)
minetest.sound_play(def.sounds.fall, { pos = p }, true)
end
remove_node(p)
for _, item in pairs(drops) do
local pos = {
x = p.x + math.random()/2 - 0.25,
y = p.y + math.random()/2 - 0.25,
z = p.z + math.random()/2 - 0.25,
}
local pos = vector.offset(p,
math.random() / 2 - 0.25,
math.random() / 2 - 0.25,
math.random() / 2 - 0.25
)
add_item(pos, item)
end
end
@ -90,4 +96,3 @@ function minetest.check_single_for_falling(pos)
return false
end

View File

@ -12,6 +12,7 @@ mcl_damage = {
drown = {bypasses_armor = true},
starve = {bypasses_armor = true, bypasses_magic = true},
cactus = {},
sweet_berry = {},
fall = {bypasses_armor = true},
fly_into_wall = {bypasses_armor = true}, -- unused
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,
minpos = pos,
maxpos = pos,
minvel = {x = -radius, y = -radius, z = -radius},
maxvel = {x = radius, y = radius, z = radius},
minacc = vector.new(),
maxacc = vector.new(),
minvel = vector.new(-radius, -radius, -radius),
maxvel = vector.new(radius, radius, radius),
minacc = vector.zero(),
maxacc = vector.zero(),
minexptime = 0.5,
maxexptime = 1.0,
minsize = radius * 0.5,
@ -333,7 +333,8 @@ local function trace_explode(pos, strength, raydirs, radius, info, direct, sourc
end
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
return
end
@ -396,15 +397,16 @@ local function trace_explode(pos, strength, raydirs, radius, info, direct, sourc
-- Update falling nodes
for a = 1, #airs do
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
for f = 1, #fires do
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
-- 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
-- Create an explosion with strength at pos.
@ -428,6 +430,11 @@ end
-- griefing - If true, the explosion will destroy nodes (default: true)
-- grief_protected - If true, the explosion will also destroy nodes which have
-- 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)
if info == nil then
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
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 = {
velocity = vector.new(0,0,0),
velocity = vector.zero(),
collision_removal = false,
}
local t = math.random() + math.random(1, interval)
minetest.after(t, function()
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.acceleration = vector.zero()
pt.collisiondetection = false
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.after(t, function()
pt.acceleration = vector.new(0, -5, 0)
pt.collisiondetection = true
pt.expirationtime = math.random() + math.random(1, interval / 2)
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
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({
label = "Create drops",
nodenames = nodes,
neighbors = {"group:" .. liquid},
interval = interval,
chance = chance,
nodenames = def.nodes,
neighbors = { "group:" .. def.liquid },
interval = def.interval,
chance = def.chance,
action = function(pos)
local r = math.ceil(interval / 20)
local nn=minetest.find_nodes_in_area(vector.offset(pos,-r,0,-r),vector.offset(pos,r,0,r),nodes)
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), def.nodes)
--start a bunch of particle cycles to be able to get away
--with longer abm cycles
table.shuffle(nn)
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
make_drop(nn[i],liquid,sound,interval)
make_drop(nn[i], def.liquid, def.sound, def.interval, def.texture)
end
end
end,
})
end
register_drop("water", 1, "", {"group:opaque", "group:leaves"},60,10)
register_drop("lava", math.max(7, minetest.registered_nodes["mcl_core:lava_source"].light_source - 3), "lava", {"group:opaque"},60,10)
mcl_dripping.register_drop({
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 CRAMMING_DAMAGE = 3
local PATHFINDING = "gowp"
-- Localize
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)
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._kb_turn then
self._turn_to = yaw
end
--clamp our yaw to a 360 range
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
self.object:set_yaw(math.rad(350))
self.object:set_yaw(math.rad(359))
end
--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)
--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
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
@ -435,8 +444,14 @@ local set_yaw = function(self, yaw, delay, dtime)
if math.abs(target_shortest_path) > 280*ddtime then
if target_shortest_path > 0 then
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
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
@ -1059,17 +1074,87 @@ local function within_limits(pos, radius)
return true
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
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
end
if not self.object:get_luaentity() then
return false
end
local yaw = self.object:get_yaw()
local dir_x = -sin(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)
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
end
local yaw = self.object:get_yaw()
@ -1136,20 +1221,6 @@ local is_at_water_danger = function(self)
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.)
local do_env_damage = function(self)
@ -1205,6 +1276,7 @@ local do_env_damage = function(self)
end
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.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
mcl_burning.set_on_fire(self.object, 10)
else
@ -1212,6 +1284,7 @@ local do_env_damage = function(self)
return true
end
end
end
local y_level = self.collisionbox[2]
@ -1415,8 +1488,8 @@ local do_jump = function(self)
end
-- where is front
local dir_x = -sin(yaw) * (self.collisionbox[4] + 0.5)*jump_c_multiplier+.4
local dir_z = cos(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+0.6
-- what is in front of mob?
nod = node_ok({
@ -1433,8 +1506,9 @@ local do_jump = function(self)
z = pos.z + dir_z
}, "air")
-- 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
end
@ -1444,7 +1518,7 @@ local do_jump = function(self)
end
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
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
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
self.object:set_velocity(v)
@ -1562,6 +1640,7 @@ end
-- find two animals of same type and breed if nearby and horny
local breed = function(self)
--mcl_log("In breed function")
-- child takes a long time before growing into adult
if self.child == true then
@ -1619,6 +1698,8 @@ local breed = function(self)
if self.horny == true
and self.hornytimer <= HORNY_TIME then
mcl_log("In breed function. All good. Do the magic.")
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)
@ -1653,6 +1734,8 @@ local breed = function(self)
end
end
if canmate then mcl_log("In breed function. Can mate.") end
if ent
and canmate == true
and ent.horny == true
@ -1667,6 +1750,8 @@ local breed = function(self)
ent.hornytimer = HORNY_TIME + 1
-- spawn baby
minetest.after(5, function(parent1, parent2, pos)
if not parent1.object:get_luaentity() then
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 yaw = (atann(v.z / v.x) + pi / 2) - entity.rotate
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)
mcl_mobs:set_animation(entity, "walk")
end
@ -2463,10 +2548,11 @@ local function check_doors(self)
if n.name:find("_b_") then
local def = minetest.registered_nodes[n.name]
local closed = n.name:find("_b_1")
if t < 0.3 or t > 0.8 then
if not closed and def.on_rightclick then def.on_rightclick(d,n,self) end
else
if self.state == PATHFINDING then
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
@ -2477,37 +2563,106 @@ local gowp_etime = 0
local function check_gowp(self,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
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._target = nil
self.current_target = nil
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
return true
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)
--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)
return
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)
-- 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
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 not self.waypoints then self.state = "walk" end --give up
--if self.current_target and not minetest.line_of_sight(self.object:get_pos(),self.current_target) then
if self.current_target and (self.waypoints and #self.waypoints == 0) then
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
--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
end
if not self.current_target then
--minetest.log("no path")
self.state = "walk"
end
--if not self.current_target then
--mcl_log("no path. Give up")
--self.state = "walk"
--end
end
-- execute current state (stand, walk, run, attacks)
@ -2556,9 +2711,9 @@ local do_states = function(self, dtime)
end
-- npc's ordered to stand stay standing
if self.type ~= "npc"
or self.order ~= "stand" then
if self.order == "stand" or self.order == "sleep" or self.order == "work" then
else
if self.walk_chance ~= 0
and self.facing_fence ~= true
and random(1, 100) <= self.walk_chance
@ -2570,7 +2725,7 @@ local do_states = function(self, dtime)
end
end
elseif self.state == "gowp" then
elseif self.state == PATHFINDING then
check_gowp(self,dtime)
elseif self.state == "walk" then
@ -3025,7 +3180,7 @@ local do_states = function(self, dtime)
if 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
self.timer = 0
@ -3071,6 +3226,8 @@ local do_states = function(self, dtime)
end
end
end
else
end
end
end
@ -3085,23 +3242,50 @@ local plane_adjacents = {
local gopath_last = os.time()
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()
--minetest.log("gowp")
self.order = nil
mcl_log("gowp target: " .. minetest.pos_to_string(target))
local p = self.object:get_pos()
local t = vector.offset(target,0,1,0)
local wp = minetest.find_path(p,t,150,1,4)
--Path to door first
if not wp then
--mcl_log("gowp. no wp. Look for door")
local d = minetest.find_node_near(target,16,{"group:door"})
if d then
--mcl_log("Found a door near")
for _,v in pairs(plane_adjacents) do
local pos = vector.add(d,v)
local n = minetest.get_node(pos)
if n.name == "air" then
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
else
--mcl_log("Block is not air, it is: ".. n.name)
end
end
else
mcl_log("No door found")
end
end
if wp and #wp > 0 then
@ -3109,7 +3293,7 @@ function mcl_mobs:gopath(self,target,callback_arrived)
self.callback_arrived = callback_arrived
table.remove(wp,1)
self.waypoints = wp
self.state = "gowp"
self.state = PATHFINDING
return true
else
self.state = "walk"
@ -3125,18 +3309,89 @@ local function player_near(pos)
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)
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()
for _,o in pairs(minetest.get_objects_inside_radius(p,2)) do
local l=o:get_luaentity()
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
if not player_near(p) and self.on_pick_up and l.itemstring:find(v) then
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()
else
elseif r and r.is_empty and r:is_empty() then
o:remove()
end
end
@ -3145,6 +3400,7 @@ local function check_item_pickup(self)
end
end
end
end
local check_herd_timer = 0
local function check_herd(self,dtime)
@ -3498,7 +3754,7 @@ local mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
elseif luaentity and luaentity._knockback then
kb = kb + luaentity._knockback
end
--self._kb_turn = false
self._kb_turn = true
self._turn_to=self.object:get_yaw()-1.57
self.frame_speed_multiplier=2.3
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()
if self and self.object then
self.frame_speed_multiplier=1
self._kb_turn = true
self._kb_turn = false
end
end)
self.object:add_velocity({
@ -3525,7 +3781,7 @@ local mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
-- 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
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()
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())))
@ -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
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
if def.after_activate then
def.after_activate(self, staticdata, def, dtime)
end
end
@ -3931,7 +4194,11 @@ local mob_step = function(self, dtime)
if not self.animation.walk_speed then
self.animation.walk_speed = 25
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)
else
self.object:set_animation_frame_speed(25)
end
end
--set_speed
@ -3989,12 +4256,13 @@ local mob_step = function(self, dtime)
-- end rotation
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)
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 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
end
else
@ -4005,8 +4273,8 @@ local mob_step = function(self, dtime)
end
end
if self.attack then
self._locked_object = self.attack
if self.attack or self.following then
self._locked_object = self.attack or self.following
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
@ -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 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
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))
elseif self.attack and self.type == "monster" then
if (mob_yaw < -60 or mob_yaw > 60) and not (self.attack and self.state == "attack" and not self.runaway) 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
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
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
else
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
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
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
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
mcl_util.set_bone_position(self.object,self.head_swivel, vector.new(0,self.bone_eye_height,self.horrizonatal_head_height), final_rotation)
end
-- run custom function (defined in mob lua file)
if self.do_custom then
@ -4070,7 +4344,7 @@ local mob_step = function(self, dtime)
-- attack timer
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
return
end
@ -4121,6 +4395,8 @@ local mob_step = function(self, dtime)
do_jump(self)
set_armor_texture(self)
runaway_from(self)
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
head_yaw = def.head_yaw or "y", -- axis to rotate head on
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,
name = name,
description = def.description,
@ -4330,6 +4607,7 @@ minetest.register_entity(name, {
nofollow = def.nofollow,
can_open_doors = def.can_open_doors,
jump = def.jump ~= false,
automatic_face_movement_max_rotation_per_sec = 300,
walk_chance = def.walk_chance or 50,
attacks_monsters = def.attacks_monsters or false,
group_attack = def.group_attack or false,
@ -4439,6 +4717,7 @@ minetest.register_entity(name, {
self.object:set_properties({
collide_with_objects = false,
})
return mob_activate(self, staticdata, def, dtime)
end,

View File

@ -6,6 +6,7 @@ local cow_def = {
description = S("Cow"),
type = "animal",
spawn_class = "passive",
passive = true,
hp_min = 10,
hp_max = 10,
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)
minetest.register_entity("mobs_mc:spider_eyes", {
pointable = false,
visual = "mesh",
mesh = "mobs_mc_spider.b3d",
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.hp_min = 1
cave_spider.hp_max = 12
cave_spider.collisionbox = {-0.35, -0.01, -0.35, 0.35, 0.49, 0.35}
cave_spider.visual_size = {x=1.66666, y=1.5}
cave_spider.collisionbox = {-0.35, -0.01, -0.35, 0.35, 0.46, 0.35}
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.run_velocity = 3.2
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: Schedule stuff (work,sleep,father)
local weather_mod = minetest.get_modpath("mcl_weather")
local S = minetest.get_translator("mobs_mc")
local N = function(s) return s end
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_RADIUS = 4 -- scan radius for looking for nearby players
local PATHFINDING = "gowp"
--[=======[ TRADING ]=======]
-- 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
-- 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"
if minetest.registered_aliases[COMPASS] then
COMPASS = minetest.registered_aliases[COMPASS]
@ -492,15 +504,34 @@ local professions = {
}
}
local WORK = "work"
local SLEEP = "sleep"
local profession_names = {}
for id, _ in pairs(professions) do
table.insert(profession_names, id)
end
local jobsites={}
for _,n in pairs(profession_names) do
table.insert(jobsites,professions[n].jobsite)
local function populate_jobsites (profession)
if profession then
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
jobsites = populate_jobsites()
local spawnable_bed={}
table.insert(spawnable_bed, "mcl_beds:bed_red_bottom")
local function stand_still(self)
self.walk_chance = 0
@ -521,6 +552,11 @@ end
local function get_badge_textures(self)
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
local tier = self._max_trade_tier or 1
return {
@ -529,27 +565,137 @@ local function get_badge_textures(self)
end
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
local function go_home(entity)
entity.state = "go_home"
function get_activity(tod)
-- night hours = tod > 18541 or tod < 5458
if not tod then
tod = minetest.get_timeofday()
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
mcl_mobs:gopath(entity,b,function(entity,b)
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
entity.state = "stand"
set_velocity(entity,0)
entity.object:set_pos(b)
local n=minetest.get_node(b)
if n and n.name ~= "mcl_beds:bed_red_bottom" then
entity._bed=nil --the stormtroopers have killed uncle owen
if sleep then
entity.order = SLEEP
mcl_log("Sleep time!")
end
else
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
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
else
--minetest.log("Need to walk to home")
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
local function has_golem(pos)
local r = false
@ -596,6 +742,43 @@ local function check_summon(self,dtime)
self._summon_timer = self._summon_timer + dtime
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
local function get_profession_by_jobsite(js)
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 p = get_profession_by_jobsite(n.name)
if p and m:get_string("villager") == "" then
self._profession=p
mcl_log("Taking this jobsite")
m:set_string("villager",self._id)
self._jobsite = jobsite_pos
if not has_traded(self) then
self._profession=p
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
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
local p = self.object:get_pos()
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
--mcl_log("Time for work")
-- Don't try if looking_for_work, or gowp possibly
if validate_jobsite(self) then
--mcl_log("My jobsite is valid. Do i need to travel?")
local jobsite2 = retrieve_my_jobsite (self)
local jobsite = self._jobsite
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
local function check_jobsite(self)
if self._traded or not self._jobsite then 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
self._profession = "unemployed"
self._trades = nil
set_textures(self)
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
@ -724,7 +1069,7 @@ local function set_trade(trader, player, inv, concrete_tradenum)
init_trades(trader)
trades = minetest.deserialize(trader._trades)
if not trades then
minetest.log("error", "[mobs_mc] Failed to select villager trade!")
--minetest.log("error", "Failed to select villager trade!")
return
end
end
@ -1118,6 +1463,7 @@ local trade_inventory = {
-- END OF SPECIAL HANDLING FOR COMPASS
local trader = player_trading_with[name]
local tradenum = player_tradenum[name]
local trades
trader._traded = true
if trader and trader._trades then
@ -1233,6 +1579,7 @@ mcl_mobs:register_mob("mobs_mc:villager", {
description = S("Villager"),
type = "npc",
spawn_class = "passive",
passive = true,
hp_min = 20,
hp_max = 20,
head_swivel = "head.control",
@ -1299,14 +1646,31 @@ mcl_mobs:register_mob("mobs_mc:villager", {
return it
end,
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()
--minetest.log("arrived at jobsite")
end)
else
self.state = "stand" -- cancel gowp in case it has messed up
self.order = nil -- cancel work if working
end
if self.child or self._profession == "unemployed" or self._profession == "nitwit" then
return
end
-- Initiate trading
init_trader_vars(self)
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)
do_custom = function(self, dtime)
check_summon(self,dtime)
-- Stand still if player is nearby.
if not self._player_scan_timer then
self._player_scan_timer = 0
end
self._player_scan_timer = self._player_scan_timer + dtime
-- Check infrequently to keep CPU load low
if self._player_scan_timer > PLAYER_SCAN_INTERVAL then
self._player_scan_timer = 0
local selfpos = self.object:get_pos()
local objects = minetest.get_objects_inside_radius(selfpos, PLAYER_SCAN_RADIUS)
local has_player = false
for o, obj in pairs(objects) do
if obj:is_player() then
has_player = true
@ -1367,18 +1734,48 @@ mcl_mobs:register_mob("mobs_mc:villager", {
minetest.log("verbose", "[mobs_mc] Player near villager found!")
stand_still(self)
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.jump = true
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
if self._profession == "unemployed" then
get_a_job(self)
else
check_jobsite(self)
--mcl_log("check bed failed ")
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,
@ -1408,6 +1805,19 @@ mcl_mobs:register_mob("mobs_mc:villager", {
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,
})

View File

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

View File

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

View File

@ -54,7 +54,6 @@ local entity_animations = {
minetest.register_entity("mcl_chests:chest", {
initial_properties = {
visual = "mesh",
visual_size = {x = 3, y = 3},
pointable = false,
physical = false,
static_save = false,
@ -140,7 +139,6 @@ minetest.register_entity("mcl_chests:chest", {
local function get_entity_pos(pos, dir, double)
pos = vector.new(pos)
pos.y = pos.y - 0.49
if double then
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))
@ -363,7 +361,7 @@ local function register_chest(basename, desc, longdesc, usagehelp, tt_help, tile
_doc_items_usagehelp = usagehelp,
_doc_items_hidden = hidden,
drawtype = "mesh",
mesh = "mcl_chests_chest.obj",
mesh = "mcl_chests_chest.b3d",
tiles = small_textures,
use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "opaque" or false,
paramtype = "light",
@ -401,7 +399,7 @@ local function register_chest(basename, desc, longdesc, usagehelp, tt_help, tile
type = "fixed",
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,
_chest_entity_textures = small_textures,
_chest_entity_sound = "default_chest",
@ -527,7 +525,7 @@ local function register_chest(basename, desc, longdesc, usagehelp, tt_help, tile
type = "fixed",
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,
_chest_entity_textures = left_textures,
_chest_entity_sound = "default_chest",
@ -684,7 +682,7 @@ local function register_chest(basename, desc, longdesc, usagehelp, tt_help, tile
type = "fixed",
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,
groups = {handy=1,axey=1, container=6,not_in_creative_inventory=1, material_wood=1,flammable=-1,double_chest=2},
drop = drop,
@ -842,15 +840,6 @@ register_chest("chest",
{
small = tiles_chest_normal_small,
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
)
@ -858,15 +847,6 @@ register_chest("chest",
local traptiles = {
small = tiles_chest_trapped_small,
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",
@ -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_usagehelp = S("Rightclick the ender chest to access your personal interdimensional inventory."),
drawtype = "mesh",
mesh = "mcl_chests_chest.obj",
mesh = "mcl_chests_chest.b3d",
tiles = tiles_chest_ender_small,
use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "opaque" or false,
paramtype = "light",
@ -1034,11 +1014,8 @@ minetest.register_node("mcl_chests:ender_chest_small", {
_chest_entity_sound = "mcl_chests_enderchest",
_chest_entity_mesh = "mcl_chests_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,
--[[{"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
-- have an inventory on its own
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},
use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "opaque" or false,
drawtype = "mesh",
mesh = "mcl_chests_shulker.obj",
--[["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]]--
mesh = "mcl_chests_shulker.b3d",
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,
sounds = mcl_sounds.node_sound_stone_defaults(),
@ -1250,7 +1221,7 @@ for color, desc in pairs(boxtypes) do
_doc_items_longdesc = longdesc,
_doc_items_usagehelp = usagehelp,
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,
_chest_entity_textures = {mob_texture},
_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 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"})
local t = minetest.get_node_timer(pos)
t:start(redstone_timer)
if puncher and pointed_thing then
return minetest.node_punch(pos, node, puncher, pointed_thing)
end
end
minetest.register_node("mcl_core:stone_with_redstone", {
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)
t:start(redstone_timer)
if puncher and pointed_thing then
return minetest.node_punch(pos, node, puncher, pointed_thing)
end
end
-- Light the redstone ore up when it has been touched
minetest.register_node("mcl_core:stone_with_redstone_lit", {

View File

@ -116,15 +116,21 @@ end
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" })
local t = minetest.get_node_timer(pos)
t:start(redstone_timer)
if puncher and pointed_thing then
return minetest.node_punch(pos, node, puncher, pointed_thing)
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)
t:start(redstone_timer)
if puncher and pointed_thing then
return minetest.node_punch(pos, node, puncher, pointed_thing)
end
end
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
return mcl_farming:grow_plant("plant_beetroot", pos, n, 1, true)
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
mcl_dye.add_bone_meal_particle(pos)
-- Cocoa: Advance by 1 stage

View File

@ -27,3 +27,6 @@ dofile(minetest.get_modpath("mcl_farming").."/potatoes.lua")
-- ========= BEETROOT =========
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_3.ogg`: “Eastern Feeling” 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_7.ogg`: “Synthgroove (Jordach's Mix)” by HeroOfTheWinds (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("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("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("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")

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
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)
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)
Models author: 22i.
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 modpath = minetest.get_modpath(modname)
-- Signs API
dofile(modpath .. "/signs_api.lua")
-- LOCALIZATION
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)
if formname:find("mcl_signs:set_text_") == 1 then
local x, y, z = formname:match("mcl_signs:set_text_(.-)_(.-)_(.*)")
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
update_sign(pos, fields, player)
if not pos or not pos.x or not pos.y or not pos.z then
return
end
mcl_signs:update_sign(pos, fields, player)
end
end)
local node_sounds
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)
-- This defines the text entity for the lettering of the sign.
-- FIXME: Prevent entity destruction by /clearobjects
minetest.register_entity("mcl_signs:text", {
pointable = false,
@ -523,58 +37,103 @@ minetest.register_entity("mcl_signs:text", {
_signnodename = nil, -- node name of sign node to which the text belongs
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
local des = minetest.deserialize(staticdata)
if des then
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
local meta = minetest.get_meta(self.object:get_pos())
local text = meta:get_string("text")
end
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({
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 })
end,
get_staticdata = function(self)
local out = { _signnodename = self._signnodename }
local out = {
_signnodename = self._signnodename,
}
return minetest.serialize(out)
end,
})
minetest.register_craft({
type = "fuel",
recipe = "mcl_signs:wall_sign",
burntime = 10,
})
-- Build the signs x,y,z & rotations so that they work. (IE, do not remove!)
mcl_signs.build_signs_info()
if minetest.get_modpath("mcl_core") then
minetest.register_craft({
output = "mcl_signs:wall_sign 3",
recipe = {
{"group:wood", "group:wood", "group:wood"},
{"group:wood", "group:wood", "group:wood"},
{"", "mcl_core:stick", ""},
}
})
end
-- ---------------------------- --
-- Register Signs for use. --
-- ---------------------------- --
if minetest.get_modpath("doc") then
doc.add_entry_alias("nodes", "mcl_signs:wall_sign", "nodes", "mcl_signs:standing_sign")
doc.add_entry_alias("nodes", "mcl_signs:wall_sign", "nodes", "mcl_signs:standing_sign22_5")
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
-- Standard (original) Sign
mcl_signs.register_sign("mcl_core", "#ffffff", "", "Sign")
mcl_signs.register_sign_craft("mcl_core", "mcl_core:wood", "")
-- 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_yard", "mcl_signs:standing_sign")
minetest.register_lbm({
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,
})
minetest.register_alias("mcl_signs:wall_sign_dark", "mcl_signs:wall_sign_sprucewood")
minetest.register_alias("mcl_signs:standing_sign_dark", "mcl_signs:standing_sign_sprucewood")

View File

@ -1,7 +1,7 @@
# textdomain: mcl_signs
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.=
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:=
Maximum line length: 15=
Maximum lines: 4=

View File

@ -1,2 +1,4 @@
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