WIP -- squash later

This commit is contained in:
Po Lu 2024-09-27 15:54:12 +08:00 committed by cora
parent b1054b6b07
commit c7fba06b74
No known key found for this signature in database
56 changed files with 1226 additions and 848 deletions

View File

@ -1,232 +0,0 @@
--[[
PriorityQueue - v1.0.1 - public domain Lua priority queue
implemented with indirect binary heap
no warranty implied; use at your own risk
based on binaryheap library (github.com/iskolbin/binaryheap)
author: Ilya Kolbin (iskolbin@gmail.com)
url: github.com/iskolbin/priorityqueue
See documentation in README file.
COMPATIBILITY
Lua 5.1, 5.2, 5.3, LuaJIT 1, 2
LICENSE
This software is dual-licensed to the public domain and under the following
license: you are granted a perpetual, irrevocable license to copy, modify,
publish, and distribute this file as you see fit.
--]]
local floor, setmetatable = math.floor, setmetatable
local function siftup( self, from )
local items, priorities, indices, higherpriority = self, self._priorities, self._indices, self._higherpriority
local index = from
local parent = floor( index / 2 )
while index > 1 and higherpriority( priorities[index], priorities[parent] ) do
priorities[index], priorities[parent] = priorities[parent], priorities[index]
items[index], items[parent] = items[parent], items[index]
indices[items[index]], indices[items[parent]] = index, parent
index = parent
parent = floor( index / 2 )
end
return index
end
local function siftdown( self, limit )
local items, priorities, indices, higherpriority, size = self, self._priorities, self._indices, self._higherpriority, self._size
for index = limit, 1, -1 do
local left = index + index
local right = left + 1
while left <= size do
local smaller = left
if right <= size and higherpriority( priorities[right], priorities[left] ) then
smaller = right
end
if higherpriority( priorities[smaller], priorities[index] ) then
items[index], items[smaller] = items[smaller], items[index]
priorities[index], priorities[smaller] = priorities[smaller], priorities[index]
indices[items[index]], indices[items[smaller]] = index, smaller
else
break
end
index = smaller
left = index + index
right = left + 1
end
end
end
local PriorityQueueMt
PriorityQueue = {}
local function minishigher( a, b )
return a < b
end
local function maxishigher( a, b )
return a > b
end
function PriorityQueue.new( priority_or_array )
local t = type( priority_or_array )
local higherpriority = minishigher
if t == 'table' then
higherpriority = priority_or_array.higherpriority or higherpriority
elseif t == 'function' or t == 'string' then
higherpriority = priority_or_array
elseif t ~= 'nil' then
local msg = 'Wrong argument type to PriorityQueue.new, it must be table or function or string, has: %q'
error( msg:format( t ))
end
if type( higherpriority ) == 'string' then
if higherpriority == 'min' then
higherpriority = minishigher
elseif higherpriority == 'max' then
higherpriority = maxishigher
else
local msg = 'Wrong string argument to PriorityQueue.new, it must be "min" or "max", has: %q'
error( msg:format( tostring( higherpriority )))
end
end
local self = setmetatable( {
_priorities = {},
_indices = {},
_size = 0,
_higherpriority = higherpriority or minishigher
}, PriorityQueueMt )
if t == 'table' then
self:batchenq( priority_or_array )
end
return self
end
function PriorityQueue:enqueue( item, priority )
local items, priorities, indices = self, self._priorities, self._indices
if indices[item] ~= nil then
error( 'Item ' .. tostring(indices[item]) .. ' is already in the heap' )
end
local size = self._size + 1
self._size = size
items[size], priorities[size], indices[item] = item, priority, size
siftup( self, size )
return self
end
function PriorityQueue:remove( item )
local index = self._indices[item]
if index ~= nil then
local size = self._size
local items, priorities, indices = self, self._priorities, self._indices
indices[item] = nil
if size == index then
items[size], priorities[size] = nil, nil
self._size = size - 1
else
local lastitem = items[size]
items[index], priorities[index] = items[size], priorities[size]
items[size], priorities[size] = nil, nil
indices[lastitem] = index
size = size - 1
self._size = size
if size > 1 then
siftdown( self, siftup( self, index ))
end
end
return true
else
return false
end
end
function PriorityQueue:contains( item )
return self._indices[item] ~= nil
end
function PriorityQueue:update( item, priority )
local ok = self:remove( item )
if ok then
self:enqueue( item, priority )
return true
else
return false
end
end
function PriorityQueue:dequeue()
local size = self._size
assert( size > 0, 'Heap is empty' )
local items, priorities, indices = self, self._priorities, self._indices
local item, priority = items[1], priorities[1]
indices[item] = nil
if size > 1 then
local newitem = items[size]
items[1], priorities[1] = newitem, priorities[size]
items[size], priorities[size] = nil, nil
indices[newitem] = 1
size = size - 1
self._size = size
siftdown( self, 1 )
else
items[1], priorities[1] = nil, nil
self._size = 0
end
return item, priority
end
function PriorityQueue:peek()
return self[1], self._priorities[1]
end
function PriorityQueue:len()
return self._size
end
function PriorityQueue:empty()
return self._size <= 0
end
function PriorityQueue:batchenq( iparray )
local items, priorities, indices = self, self._priorities, self._indices
local size = self._size
for i = 1, #iparray, 2 do
local item, priority = iparray[i], iparray[i+1]
if indices[item] ~= nil then
error( 'Item ' .. tostring(indices[item]) .. ' is already in the heap' )
end
size = size + 1
items[size], priorities[size] = item, priority
indices[item] = size
end
self._size = size
if size > 1 then
siftdown( self, floor( size / 2 ))
end
end
PriorityQueueMt = {
__index = PriorityQueue,
__len = PriorityQueue.len,
}
return setmetatable( PriorityQueue, {
__call = function( _, ... )
return PriorityQueue.new( ... )
end
} )

View File

@ -360,7 +360,7 @@ end
function mob_class:on_step(dtime, moveresult)
local pos = self.object:get_pos()
if not mcl_mobs.check_vector(pos) or self.removed then
if not mcl_mobs.check_vector(pos) or self.removed or not moveresult then
self:safe_remove()
return
end
@ -373,21 +373,20 @@ function mob_class:on_step(dtime, moveresult)
if not (moveresult and moveresult.touching_ground) and self:falling(pos) then return end
-- Get nodes early for use in other functions
local cbox = self.object:get_properties().collisionbox
local y_level = cbox[2]
if self.child then
y_level = cbox[2] * 0.5
local cbox = self.collisionbox
local feet = vector.copy (pos)
local bbase = pos.y + self.collisionbox[2] + 0.5
feet.y = math.floor (bbase + 1.0e-2)
if bbase - feet.y <= 1.0e-2 then
self.standing_in = mcl_mobs.node_ok (feet, "air").name
feet.y = feet.y - 1
self.standing_on = mcl_mobs.node_ok (feet, "air").name
else
self.standing_in = mcl_mobs.node_ok (feet, "air").name
self.standing_on = self.standing_in
end
local p = vector.copy(pos)
p.y = p.y + y_level + 0.25 -- foot level
local pos2 = vector.offset(pos, 0, -1, 0)
self.standing_in = mcl_mobs.node_ok(p, "air").name
self.standing_on = mcl_mobs.node_ok(pos2, "air").name
local pos_head = vector.offset(p, 0, cbox[5] - 0.5, 0)
self.head_in = mcl_mobs.node_ok(pos_head, "air").name
local pos_head = vector.offset(pos, 0, cbox[5] - 0.5, 0)
self.head_in = mcl_mobs.node_ok(pos_head, "air").name
self:falling (pos)
self:check_dying ()

View File

@ -253,7 +253,9 @@ function mob_class:check_breeding (pos)
return false
end
local matepos = self.mate:get_pos ()
if vector.distance (pos, matepos) < 3.0 and self.hornytimer
if vector.distance (pos, matepos) < 3.0
and self:target_visible (pos, self.mate)
and self.hornytimer
and not self.begetting then
self.begetting = true
minetest.after (5, mob_class.beget_child, self, pos)
@ -287,6 +289,7 @@ function mob_class:check_breeding (pos)
-- Interrupt other activities.
self.herd_following = nil
self.pacing = nil
self.following = nil
return true
end
end
@ -358,7 +361,6 @@ end
function mob_class:stay()
self.order = "sit"
self.walk_chance = 0
self.jump = false
if self.animation.sit_start then
self:set_animation("sit")
@ -369,7 +371,6 @@ end
function mob_class:roam()
self.order = "roam"
self.walk_chance = 50
self.jump = true
self:set_animation("stand")
end

View File

@ -4,14 +4,6 @@ local damage_enabled = minetest.settings:get_bool("enable_damage", true)
local peaceful_mode = minetest.settings:get_bool("only_peaceful_mobs", false)
local mobs_griefing = minetest.settings:get_bool("mobs_griefing", true)
local function atan(x)
if not x or minetest.is_nan(x) then
return 0
else
return math.atan(x)
end
end
-- check if daytime and also if mob is docile during daylight hours
function mob_class:day_docile()
if self.docile_by_day and self.time_of_day > 0.2 and self.time_of_day < 0.8 then
@ -23,7 +15,7 @@ end
local SIGHT_PERSISTENCE = 3.0
function mob_class:do_attack(obj)
if self.dead then
if self.dead or obj == self.obj or obj == self.attack then
return
end
-- No longer idle. Interrupt other
@ -65,8 +57,8 @@ end
function mob_class:entity_physics(pos,radius) return blast_damage(pos,radius, self.object) end
function mob_class:attack_players_allowed ()
-- TODO
function mob_class:attack_player_allowed ()
-- TODO: creative mode
return true
end
@ -137,26 +129,23 @@ end
-- Apply projectile knockback.
function mob_class:projectile_knockback (factor, dir)
local v = self.object:get_velocity ()
local kb, up = 1, 2
self._kb_turn = true
self._turn_to=self.object:get_yaw()-1.57
if self.animation.run_end then
self:set_animation ("run")
elseif self.animation.walk_end then
self:set_animation ("walk")
end
self.frame_speed_multiplier=2.3
self.object:set_velocity({
x = v.x / 2.0 + dir.x * factor * 2.5,
y = v.y / 2.0 + 2,
z = v.z / 2.0 + dir.z * factor * 2.5,
})
minetest.after(0.2, function()
if self and self.object then
self.frame_speed_multiplier=1
self._kb_turn = false
end
end)
self.object:set_velocity({
x = v.x / 2.0 + dir.x * factor * 2.5,
y = v.y / 2.0 + up*2,
z = v.z / 2.0 + dir.z * factor * 2.5,
})
self.pause_timer = 0.25
end
@ -356,8 +345,6 @@ function mob_class:on_punch(hitter, tflp, tool_capabilities, dir)
elseif luaentity and luaentity._knockback then
kb = kb + luaentity._knockback
end
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
self:set_animation( "run")
@ -367,7 +354,6 @@ function mob_class:on_punch(hitter, tflp, tool_capabilities, dir)
minetest.after(0.2, function()
if self and self.object then
self.frame_speed_multiplier=1
self._kb_turn = false
end
end)
@ -451,21 +437,21 @@ function mob_class:should_attack (object)
if table.indexof (specific, entity.name) ~= -1 then
return true
end
elseif object:is_player () and self:attack_players_allowed () then
return self.type == "monster" or table.indexof (specific, "player")
elseif object:is_player () and self:attack_player_allowed (object) then
return self.type == "monster" or table.indexof (specific, "player") ~= -1
end
return false
end
function mob_class:should_continue_to_attack (object)
if object:is_player () and not self:attack_players_allowed () then
if object:is_player () and not self:attack_player_allowed (object) then
return false
end
return object:get_hp () > 0
end
function mob_class:attack_bowshoot (self_pos, dtime, target_pos)
function mob_class:attack_bowshoot (self_pos, dtime, target_pos, line_of_sight)
if not self.attacking then
-- Initialize parameters consulted during the attack.
self._target_visible_time = 0
@ -490,7 +476,6 @@ function mob_class:attack_bowshoot (self_pos, dtime, target_pos)
y = target_pos.y + (collisionbox[5] - collisionbox[2]) * 0.33,
z = target_pos.z,
}
local line_of_sight = self:line_of_sight (shoot_pos, target)
if line_of_sight then
if vistime < 0 then
@ -532,7 +517,7 @@ function mob_class:attack_bowshoot (self_pos, dtime, target_pos)
-- too far.
if dist > 15 * 0.75 then
self._z_strafe = 1
elseif dist < 15 * 0.25 then
elseif dist < 15 * 0.55 then
self._z_strafe = -1
end
@ -541,14 +526,20 @@ function mob_class:attack_bowshoot (self_pos, dtime, target_pos)
self.strafe_direction = { x = self._x_strafe * 0.5,
z = self._z_strafe * 0.5, }
self:look_at (target_pos)
self:set_animation ("run")
if not self._shoot_time then
self:set_animation ("run")
else
self:set_animation ("shoot")
end
end
if not self._shoot_time then
if self._shoot_timer <= 0 and vistime >= -3 then
self:set_animation ("shoot")
self._shoot_time = 0
self._shoot_timer = 0
if line_of_sight then
self:set_animation ("shoot")
self._shoot_time = 0
self._shoot_timer = 0
end
else
self._shoot_timer = self._shoot_timer - dtime
end
@ -557,7 +548,7 @@ function mob_class:attack_bowshoot (self_pos, dtime, target_pos)
if not line_of_sight and vistime < -3 then
self:set_animation ("run")
self.shoot_time = nil
elseif self._shoot_time > 1 then
elseif line_of_sight and self._shoot_time > 1 then
-- Fire arrow.
self._shoot_time = nil
self._shoot_timer = self.shoot_interval or 1
@ -569,9 +560,6 @@ function mob_class:attack_bowshoot (self_pos, dtime, target_pos)
z = target.z - shoot_pos.z,
}
local target_bb = self.attack:get_properties ()
local collisionbox = target_bb.collisionbox
-- Offset by distance.
vec.y = vec.y + 0.12 * vector.length (vec)
@ -604,7 +592,7 @@ function mob_class:custom_attack ()
attack:punch (self.object, 1.0, damage, nil)
end
function mob_class:attack_melee (self_pos, dtime, target_pos)
function mob_class:attack_melee (self_pos, dtime, target_pos, line_of_sight)
if not self.attacking then
-- Initialize attack parameters.
self._target_pos = nil
@ -617,13 +605,14 @@ function mob_class:attack_melee (self_pos, dtime, target_pos)
local distance = vector.distance (self_pos, target_pos)
-- If the target is detectable...
if (self.esp or self:target_visible (self_pos, self.attack))
if (self.esp or line_of_sight)
-- ...and the navigation timeout has elapsed...
and delay == 0
-- ..and this mob has yet to arrive at its target, or
-- the path should be recomputed...
and (not self._target_pos
or vector.distance (self_pos, target_pos) >= 1) then
or vector.distance (target_pos, self._target_pos) >= 1
or math.random (100) <= 5) then
self._target_pos = target_pos
delay = (4 + math.random (8) - 1) / 20.0
@ -638,14 +627,13 @@ function mob_class:attack_melee (self_pos, dtime, target_pos)
-- Try to pathfind.
if not self:gopath (target_pos, nil, true) then
delay = delay + 0.75
self:set_animation ("stand")
end
end
self._gopath_delay = delay
-- Can the target be attacked?
local delay = math.max (self._attack_delay - dtime, 0)
if distance < self.reach and delay == 0 then
if distance <= self.reach and delay == 0 then
self:look_at (target_pos)
self:custom_attack ()
delay = self.melee_interval
@ -678,7 +666,7 @@ function mob_class:check_attack (self_pos, dtime)
local distance = vector.distance (self_pos, pos)
if distance <= self.view_range * factor
and (not max_distance or distance < max_distance)
and (self.attack_esp or self:target_visible (self_pos, object)) then
and (self.esp or self:target_visible (self_pos, object)) then
target = object
max_distance = distance
end
@ -691,7 +679,7 @@ function mob_class:check_attack (self_pos, dtime)
end
end
else
local line_of_sight, target_pos
local target_pos
if not self.attack:is_valid () then
self.attack = nil
self:set_animation ("stand")
@ -711,8 +699,8 @@ function mob_class:check_attack (self_pos, dtime)
self:set_animation ("stand")
return true
end
if not self.esp
and not self:target_visible (self_pos, self.attack) then
local line_of_sight = self:target_visible (self_pos, self.attack)
if not self.esp and not line_of_sight then
local t = self.target_invisible_time
self.target_invisible_time = t - dtime
@ -721,14 +709,18 @@ function mob_class:check_attack (self_pos, dtime)
self:set_animation ("stand")
return true
end
else
self.target_invisible_time = SIGHT_PERSISTENCE
end
if self.attack_type == "bowshoot" then
self:attack_bowshoot (self_pos, dtime, target_pos)
self:attack_bowshoot (self_pos, dtime, target_pos,
line_of_sight)
elseif self.attack_type == "ranged" then
-- TODO
elseif self.attack_type == "melee" then
self:attack_melee (self_pos, dtime, target_pos)
self:attack_melee (self_pos, dtime, target_pos,
line_of_sight)
else
minetest.log ("warning", "unknown attack type " .. self.attack_type)
end

View File

@ -384,7 +384,12 @@ function mob_class:check_head_swivel(dtime, clear)
end
-- set animation speed relative to velocity
function mob_class:set_animation_speed(custom_speed)
function mob_class:set_animation_speed(custom_speed)
if self._current_animation ~= "walk"
and self._current_animation ~= "run" then
self.object:set_animation_frame_speed (self.animation.walk_speed)
return
end
local speed = custom_speed or self.animation.walk_speed or 25
local v = self:get_velocity ()
local scaled_speed = speed * self.frame_speed_multiplier

View File

@ -58,7 +58,6 @@ mcl_mobs.mob_class = {
sounds = {},
animation = {},
jump = true,
walk_chance = 50,
attacks_monsters = false,
group_attack = false,
passive = false,
@ -97,7 +96,7 @@ mcl_mobs.mob_class = {
dogshoot_count2_max = 5,
attack_animals = false,
attack_npcs = false,
attack_esp = false,
esp = false,
facing_fence = false,
is_mob = true,
pushable = true,
@ -173,7 +172,6 @@ dofile(path .. "/movement.lua")
-- items: item management for mobs
dofile(path .. "/items.lua")
-- pathfinding: pathfinding to target positions
dofile(path .. "/PriorityQueue.lua")
dofile(path .. "/pathfinding.lua")
-- combat: attack logic
dofile(path .. "/combat.lua")
@ -304,11 +302,17 @@ function mcl_mobs.register_mob(name, def)
init_props.hp_max = scale_difficulty(init_props.hp_max, 10, 1)
init_props.collisionbox = init_props.collisionbox or mcl_mobs.mob_class.initial_properties.collisionbox
init_props.selectionbox = init_props.selectionbox or init_props.collisionbox or mcl_mobs.mob_class.initial_properties.selectionbox
local eye_height = init_props.head_eye_height
if not eye_height then
eye_height = init_props.collisionbox[5] - init_props.collisionbox[2]
eye_height = eye_height * 0.75 + init_props.collisionbox[2]
end
local final_def = setmetatable(table.merge(def,{
initial_properties = table.merge(mcl_mobs.mob_class.initial_properties,init_props),
can_despawn = can_despawn,
rotate = math.rad(def.rotate or 0), -- 0=front, 90=side, 180=back, 270=side2
head_eye_height = eye_height,
hp_min = scale_difficulty(def.hp_min, 5, 1),
on_rightclick = create_mob_on_rightclick(def.on_rightclick),
dogshoot_count2_max = def.dogshoot_count2_max or (def.dogshoot_count_max or 5),

View File

@ -1,15 +1,6 @@
local mob_class = mcl_mobs.mob_class
local mobs_griefing = minetest.settings:get_bool("mobs_griefing") ~= false
local atann = math.atan
local function atan(x)
if not x or x ~= x then
return 0
else
return atann(x)
end
end
-- Returns true is node can deal damage to self
function mob_class:is_node_dangerous(nodename)
local nn = nodename
@ -66,82 +57,211 @@ function mob_class:target_visible(origin, target)
local origin_eye_pos = vector.offset(origin, 0, self.head_eye_height, 0)
local targ_head_height, targ_feet_height
local targ_head_height
local cbox = self.object:get_properties().collisionbox
if target:is_player () then
targ_head_height = vector.offset(target_pos, 0, cbox[5], 0)
targ_feet_height = target_pos -- Cbox would put feet under ground which interferes with ray
local eye = target:get_properties ().eye_height
targ_head_height = vector.offset(target_pos, 0, eye, 0)
else
targ_head_height = vector.offset(target_pos, 0, cbox[5], 0)
targ_feet_height = vector.offset(target_pos, 0, cbox[2], 0)
end
if self:line_of_sight(origin_eye_pos, targ_head_height) then
if self:line_of_sight (origin_eye_pos, targ_head_height) then
return true
end
if self:line_of_sight(origin_eye_pos, targ_feet_height) then
return true
end
-- TODO mid way between feet and head
return false
end
-- check line of sight (BrunoMine)
function mob_class:line_of_sight(pos1, pos2, stepsize)
stepsize = stepsize or 1
local s, _ = minetest.line_of_sight(pos1, pos2, stepsize)
-- Check line of sight:
-- http://www.cse.yorku.ca/~amana/research/grid.pdf
-- The ubiquitous slab method of intersecting rays with
-- AABBs.
-- normal walking and flying mobs can see you through air
if s then return true end
local function signum (number)
return number == 0.0 and 0 or number < 0 and -1 or 1
end
-- New pos1 to be analyzed
local npos1 = vector.copy(pos1)
local r, pos = minetest.line_of_sight(npos1, pos2, stepsize)
local function genbox (box, node)
box[1] = box[1] + node.x
box[2] = box[2] + node.y
box[3] = box[3] + node.z
box[4] = box[4] + node.x
box[5] = box[5] + node.y
box[6] = box[6] + node.z
end
if r == true then return true end
local nn = minetest.get_node(pos).name
local td = vector.distance(pos1, pos2)
local ad = 0
local function maxnum (a, b)
return math.max (a, b)
end
-- It continues to advance in the line of sight in search of a real
-- obstruction which counts as 'normal' nodebox.
while minetest.registered_nodes[nn]
and minetest.registered_nodes[nn].walkable == false do
local function minnum (a, b)
return math.min (a, b)
end
-- Check if you can still move forward
if td < ad + stepsize then
return true -- Reached the target
end
-- Moves the analyzed pos
local d = vector.distance(pos1, pos2)
npos1.x = ((pos2.x - pos1.x) / d * stepsize) + pos1.x
npos1.y = ((pos2.y - pos1.y) / d * stepsize) + pos1.y
npos1.z = ((pos2.z - pos1.z) / d * stepsize) + pos1.z
-- NaN checks
if d == 0
or npos1.x ~= npos1.x
or npos1.y ~= npos1.y
or npos1.z ~= npos1.z then
local function aabb_clear (node, origin, pos2, direction, d)
local node_type = minetest.get_node (node)
if node_type.name == "air" then
return true
else
local def = minetest.registered_nodes[node_type.name]
if def and not def.walkable then
return true
elseif not def then
return false
end
end
local boxes = minetest.get_node_boxes ("collision_box", node)
ad = ad + stepsize
for _, box in ipairs (boxes) do
genbox (box, node)
local x1, y1, z1, x2, y2, z2
= box[1], box[2], box[3], box[4], box[5], box[6]
-- scan again
r, pos = minetest.line_of_sight(npos1, pos2, stepsize)
local min, max = -1/0, 1/0
-- X face.
local n1 = (x1 - origin.x) * direction.x
local f1 = (x2 - origin.x) * direction.x
if n1 > f1 then
n1, f1 = f1, n1
end
min = maxnum (min, n1)
max = minnum (max, f1)
if r == true then return true end
-- New Nodename found
nn = minetest.get_node(pos).name
-- Y face.
local n2 = (y1 - origin.y) * direction.y
local f2 = (y2 - origin.y) * direction.y
if n2 > f2 then
n2, f2 = f2, n2
end
min = maxnum (min, n2)
max = minnum (max, f2)
-- Z face.
local n3 = (z1 - origin.z) * direction.z
local f3 = (z2 - origin.z) * direction.z
if n3 > f3 then
n3, f3 = f3, n3
end
min = maxnum (min, n3)
max = minnum (max, f3)
-- Intersection with furthest near face is within the
-- vector.
if ((min < 0 and max or min) <= d)
-- Intersection with closest far face
-- falls after the origin.
and (max >= 0)
-- luacheck: push ignore 581
and not (max <= min) then
-- luacheck: pop
return false
end
end
return true
end
local line_of_sight_scratch = vector.zero ()
local function mod (x)
return x - math.floor (x)
end
local scale_poses_scratch = vector.zero ()
local scale_poses_scratch_1 = vector.zero ()
local function scale_poses (pos1, pos2)
local v1, v2 = scale_poses_scratch, scale_poses_scratch_1
v1.x = pos1.x + 1.0e-7
v1.y = pos1.y + 1.0e-7
v1.z = pos1.z + 1.0e-7
v2.x = pos2.x + -1.0e-7
v2.y = pos2.y + -1.0e-7
v2.z = pos2.z + -1.0e-7
return v1, v2
end
function mob_class:line_of_sight (pos1, pos2)
-- Move pos1 and pos2 by minuscule values to avoid generating
-- Inf or NaN.
pos1, pos2 = scale_poses (pos1, pos2)
local traveledx = mod (pos1.x + 0.5)
local traveledy = mod (pos1.y + 0.5)
local traveledz = mod (pos1.z + 0.5)
local x = math.floor (pos1.x + 0.5)
local y = math.floor (pos1.y + 0.5)
local z = math.floor (pos1.z + 0.5)
local dx, dy, dz = pos2.x - pos1.x, pos2.y - pos1.y, pos2.z - pos1.z
local sx, sy, sz = signum (dx), signum (dy), signum (dz)
local stepx, stepy, stepz = sx / dx, sy / dy, sz / dz
local direction = vector.direction (pos1, pos2)
local distance = vector.distance (pos1, pos2)
-- Precompute reciprocal.
direction.x = 1.0 / direction.x
direction.y = 1.0 / direction.y
direction.z = 1.0 / direction.z
if sx == 0 then
traveledx = 1.0
elseif sx > 0 then
traveledx = stepx * (1.0 - traveledx)
else
traveledx = stepx * (traveledx)
end
if sy == 0 then
traveledy = 1.0
elseif sy > 0 then
traveledy = stepy * (1.0 - traveledy)
else
traveledy = stepy * (traveledy)
end
if sz == 0 then
traveledz = 1.0
elseif sz > 0 then
traveledz = stepz * (1.0 - traveledz)
else
traveledz = stepz * (traveledz)
end
return false
local v = line_of_sight_scratch
v.x = x
v.y = y
v.z = z
if not aabb_clear (v, pos1, pos2, direction, distance) then
return false
end
while (traveledx <= 1.0)
or (traveledy <= 1.0)
or (traveledz <= 1.0) do
if traveledx < traveledy then
if traveledx < traveledz then
x = x + sx
traveledx = traveledx + stepx
else
z = z + sz
traveledz = traveledz + stepz
end
else
if traveledy < traveledz then
y = y + sy
traveledy = traveledy + stepy
else
z = z + sz
traveledz = traveledz + stepz
end
end
v.x = x
v.y = y
v.z = z
if not aabb_clear (v, pos1, pos2, direction, distance) then
return false
end
end
return true
end
function mob_class:can_jump_cliff()
@ -181,64 +301,6 @@ function mob_class:can_jump_cliff()
end
end
-- is mob facing a cliff or danger
function mob_class:is_at_cliff_or_danger()
if self.fear_height == 0 or self._jumping_cliff or not self.object:get_luaentity() then -- 0 for no falling protection!
return false
end
local cbox = self.object:get_properties().collisionbox
local dir_x, dir_z = self:forward_directions()
local pos = self.object:get_pos()
local free_fall, blocker = minetest.line_of_sight(
vector.offset(pos, dir_x, cbox[2], dir_z),
vector.offset(pos, dir_x, -self.fear_height, dir_z))
if free_fall then
return true
else
local bnode = minetest.get_node(blocker)
local danger = self:is_node_dangerous(bnode.name)
if danger then
return true
else
local def = minetest.registered_nodes[bnode.name]
if def and def.walkable then
return false
end
end
end
return false
end
function mob_class:is_at_water_danger()
if self._jumping_cliff or self.swims or self.fly or self.object:get_properties().breath_max == -1 then
return false
end
local cbox = self.object:get_properties().collisionbox
local pos = self.object:get_pos()
local infront = self:node_infront_ok(pos, -1)
local height = cbox[5] - cbox[2]
if self:is_node_waterhazard(infront.name) then
-- if short then mob can drown in a single node
if height <= 1.0 then
return true
else
-- else it's only dangerous if two nodes deep
local below_infront = self:node_infront_ok(pos, -2)
if self:is_node_waterhazard(below_infront.name) then
return true
end
end
end
return false
end
function mob_class:check_jump (self_pos, moveresult)
local max_y = nil
local dir = vector.zero ()
@ -278,70 +340,6 @@ local function in_list(list, what)
return type(list) == "table" and table.indexof(list, what) ~= -1
end
function mob_class:is_object_in_view(object_list, object_range, node_range, turn_around)
local s = self.object:get_pos()
local min_dist = object_range + 1
local object_pos
for object in minetest.objects_inside_radius(s, object_range) do
local name = ""
if object:is_player() then
if not (mcl_mobs.invis[ object:get_player_name() ]
or self.owner == object:get_player_name()
or (not self:object_in_range(object))) then
name = "player"
if not (name ~= self.name
and in_list(object_list, name)) then
local item = object:get_wielded_item()
name = item:get_name() or ""
end
end
else
local ent = object:get_luaentity()
if ent then
object = ent.object
name = ent.name or ""
end
end
-- find specific mob to avoid or runaway from
if name ~= "" and name ~= self.name
and in_list(object_list, name) then
local p = object:get_pos()
local dist = vector.distance(p, s)
-- choose closest player/mob to avoid or runaway from
if dist < min_dist
-- aim higher to make looking up hills more realistic
and self:line_of_sight(vector.offset(s, 0,1,0), vector.offset(p, 0,1,0)) == true then
min_dist = dist
object_pos = p
end
end
end
if not object_pos then
-- find specific node to avoid or runaway from
local p = minetest.find_node_near(s, node_range, object_list, true)
local dist = p and vector.distance(p, s)
if dist and dist < min_dist
and self:line_of_sight(s, p) == true then
object_pos = p
end
end
if object_pos and turn_around then
local vec = vector.subtract(object_pos, s)
local yaw = (atan(vec.z / vec.x) + 3 *math.pi/ 2) - self.rotate
if object_pos.x > s.x then yaw = yaw + math.pi end
self:set_yaw(yaw, 4)
end
return object_pos ~= nil
end
-- should mob follow what I'm holding ?
function mob_class:follow_holding(clicker)
local item = clicker:get_wielded_item()
@ -400,11 +398,9 @@ function mob_class:replace(pos)
end
function mob_class:look_at(b)
local s=self.object:get_pos()
local v = { x = b.x - s.x, z = b.z - s.z }
local yaw = (atann(v.z / v.x) +math.pi/ 2) - self.rotate
if b.x > s.x then yaw = yaw +math.pi end
self.object:set_yaw(yaw)
local s = self.object:get_pos()
local yaw = (math.atan2 (b.z - s.z, b.x - s.x) - math.pi / 2) - self.rotate
self.object:set_yaw (yaw)
end
function mob_class:go_to_pos (b, velocity, animation)
@ -424,9 +420,6 @@ end
function mob_class:check_smooth_rotation(dtime)
-- smooth rotation by ThomasMonroe314
if self._turn_to and self.order ~= "sleep" then
self:set_yaw( self._turn_to, .1)
end
if self.delay and self.delay > 0 then
local yaw = self.object:get_yaw() or 0
if self.delay == 1 then
@ -475,9 +468,16 @@ function mob_class:do_go_pos (dtime, moveresult)
self:look_at (target)
self:set_velocity (vel)
-- Jump if the mob is obstructed.
if self:check_jump (pos, moveresult) then
self.order = "jump"
if self.should_jump and self.should_jump > 2 then
self.order = "jump"
self.should_jump = 0
else
-- Jump again if the collision remains after
-- the next step.
local i = self.should_jump or 0
self.should_jump = i + 1
end
return
end
end
@ -494,15 +494,23 @@ function mob_class:do_strafe (dtime, moveresult)
-- Don't jump off ledges or head into unwalkable nodes if
-- strafing in reverse or to the sides.
local node, def, est_delta
local node, est_delta
local v = { x = sx * vel, y = 0, z = sz * vel, }
est_delta = self:accelerate_relative (v, vel)
est_delta.y = -0.25
node = minetest.get_node (vector.add (self.object:get_pos (), est_delta))
def = minetest.registered_nodes[node.name]
if def and not def.walkable then
sx = 0
sz = 1
node = vector.add (self.object:get_pos (),
-- Scale the delta to
-- reflect the quantity
-- of movement applied
-- in one Minecraft
-- tick.
est_delta * 0.05)
node.x = math.floor (node.x + 0.5)
node.y = math.floor (node.y + 0.5)
node.z = math.floor (node.z + 0.5)
if self:gwp_classify_for_movement (node) ~= "WALKABLE" then
self.strafe_direction.x, sx = 0, 0
self.strafe_direction.z, sz = 1, 1
end
-- Begin strafing.
@ -525,6 +533,11 @@ function mob_class:halt_in_tracks (immediate)
self.movement_goal = nil
self:cancel_navigation ()
if self._current_animation == "walk"
or self._current_animation == "run" then
self:set_animation ("stand")
end
if immediate then
self.object:set_acceleration(vector.new(0,0,0))
self.object:set_velocity(vector.new(0,0,0))
@ -577,7 +590,7 @@ end
function mob_class:navigation_step (dtime, moveresult)
if self.waypoints or self.pathfinding_context then
self:next_waypoint ()
self:next_waypoint (dtime)
elseif self.stupid_target then
self:go_to_pos (self.stupid_target, self.stupid_velocity)
end
@ -690,7 +703,7 @@ function mob_class:check_following (self_pos, dtime)
if self.following then
-- check_head_swivel is responsible for
-- looking at the target.
self:go_to_stupidly (pos, self.movement_speed * self.follow_bonus)
self:go_to_stupidly (pos)
end
return true
elseif self.follow and not self.follow_cooldown then

File diff suppressed because it is too large Load Diff

View File

@ -162,9 +162,9 @@ function mob_class:collision()
or (self.mob_pushable and ent and ent.is_mob and object ~= self.object) then
local pos2 = object:get_pos()
local vec = {x = pos.x - pos2.x, z = pos.z - pos2.z}
local force = width - vector.distance(
local force = vector.distance(
{x = pos.x, y = 0, z = pos.z},
{x = pos2.x, y = 0, z = pos2.z})
{x = pos2.x, y = 0, z = pos2.z}) / width
x = x + (vec.x * force)
z = z + (vec.z * force)
@ -597,8 +597,9 @@ function mob_class:do_env_damage()
drowning = true
end
elseif head_nodedef.drowning > 0 then
-- TODO: immersion depth
drowning = true
if self._immersion_depth > self.head_eye_height then
drowning = true
end
end
if drowning then
self.breath = math.max(0, self.breath - 1)
@ -804,9 +805,8 @@ function mob_class:check_water_flow ()
end
function mob_class:check_dying(reason, cmi_cause)
if ((self.state and self.state == "die")
or self:check_for_death(reason, cmi_cause))
and not self.animation.die_end then
if (self.dead or self:check_for_death(reason, cmi_cause))
and not self.animation.die_end then
if self.object then
local rot = self.object:get_rotation()
rot.z = ((math.pi/2-rot.z)*.2)+rot.z
@ -923,8 +923,6 @@ local function horiz_collision (v, moveresult)
return moveresult.collides and not (moveresult.standing_on_object or moveresult.touching_ground)
end
--- TODO: melee combat
--- TODO: skelly combat
--- TODO: flying and swimming mobs
--- TODO: correct uses of fall_speed and other modified fields
--- TODO: mob mounting
@ -948,9 +946,7 @@ function mob_class:immersion_depth (liquidgroup, pos, max)
if def.liquidtype == "flowing" then
height = 0.1 + node.param2 * 0.1
end
ymax = math.round (i) + height - 0.5
else
break
ymax = math.floor (i + 0.5) + height - 0.5
end
i = i + 1
end
@ -982,11 +978,9 @@ function mob_class:motion_step (dtime, moveresult)
local climbing = false
if self.floats == 1 and math.random (10) < 8 then
if standin.groups.water then
local depth = self._immersion_depth or 0
if depth > LIQUID_JUMP_THRESHOLD then
local depth = self._immersion_depth or 0
if depth > LIQUID_JUMP_THRESHOLD then
jumping = true
end
end
end
@ -994,8 +988,6 @@ function mob_class:motion_step (dtime, moveresult)
self.jump_timer = math.max (0, self.jump_timer - dtime)
end
self:check_collision ()
p = pow_by_step (AIR_DRAG, dtime)
acc_dir.x = acc_dir.x * p
acc_dir.z = acc_dir.z * p
@ -1021,10 +1013,28 @@ function mob_class:motion_step (dtime, moveresult)
self.reset_fall_damage = 1
end
local deferred_jump
if jumping then
if standin.groups.water or standin.groups.lava then
if self.floats then
deferred_jump = LIQUID_JUMP_FORCE
else
v.y = v.y + LIQUID_JUMP_FORCE_ONESHOT
end
else
if touching_ground and (not self.jump_timer or self.jump_timer <= 0) then
v = self:jump_actual (v)
self.jump_timer = 0.2
end
end
end
local water_vec = self:check_water_flow ()
local velocity_factor = standon._mcl_velocity_factor or 1
if standin.groups.water then
local friction = self.water_friction
local friction = self.water_friction * velocity_factor
local speed = self.water_velocity
-- Apply depth strider.
@ -1059,6 +1069,12 @@ function mob_class:motion_step (dtime, moveresult)
v.y = -0.06
end
-- Apply any ascent force, now that v_scale is
-- available.
if deferred_jump then
v.y = v.y + deferred_jump * v_scale
end
if horiz_collision (v, moveresult) then
-- Climb water as if it were a ladder.
v.y = 3.0
@ -1069,10 +1085,18 @@ function mob_class:motion_step (dtime, moveresult)
local r, z = pow_by_step (LAVA_FRICTION, dtime), LAVA_FRICTION
h_scale = (1 - r) / (1 - z)
speed = speed * h_scale
local fv = self:accelerate_relative (acc_dir, speed)
v = vector.multiply (v, r)
v_scale = h_scale
v.y = v.y + fall_speed * v_scale
-- Apply any ascent force, now that v_scale is
-- available.
if deferred_jump then
v.y = v.y + deferred_jump * v_scale
end
v = vector.add (v, fv)
else
-- If not standing on air, apply slippery to a base value of
@ -1095,7 +1119,11 @@ function mob_class:motion_step (dtime, moveresult)
else
speed = 0.4 -- 0.4 blocks/s
end
friction = friction * AIR_FRICTION
-- Apply friction (velocity_factor) from Soul Sand and
-- the like. NOTE: this friction is supposed to be
-- applied after movement, just as with standard
-- friction.
friction = friction * AIR_FRICTION * velocity_factor
-- Adjust speed by friction. Minecraft applies
-- friction to acceleration (speed), not just the
@ -1132,22 +1160,8 @@ function mob_class:motion_step (dtime, moveresult)
v.y = v.y * f
end
if jumping then
if standin.groups.water or standin.groups.lava then
if self.floats then
v.y = v.y + LIQUID_JUMP_FORCE * v_scale
else
v.y = v.y + LIQUID_JUMP_FORCE_ONESHOT
end
else
if touching_ground and (not self.jump_timer or self.jump_timer <= 0) then
v = self:jump_actual (v)
self.jump_timer = 0.2
end
end
end
-- Clear the jump flag even when jumping is not yet possible.
self.order = ""
self.object:set_velocity (v)
self:check_collision ()
end

View File

@ -27,6 +27,7 @@ mcl_mobs.register_mob("mobs_mc:bat", {
passive = true,
hp_min = 6,
hp_max = 6,
head_eye_height = 0.45,
collisionbox = {-0.25, -0.01, -0.25, 0.25, 0.89, 0.25},
visual = "mesh",
mesh = "mobs_mc_bat.b3d",
@ -57,7 +58,6 @@ mcl_mobs.register_mob("mobs_mc:bat", {
die_end = 80,
die_loop = false,
},
walk_chance = 100,
fall_damage = 0,
view_range = 16,
fear_height = 0,

View File

@ -22,7 +22,7 @@ mcl_mobs.register_mob("mobs_mc:chicken", {
floats = 1,
head_swivel = "head.control",
bone_eye_height = 4,
head_eye_height = 1.5,
head_eye_height = 0.644,
horizontal_head_height = -.3,
curiosity = 10,
head_yaw="z",

View File

@ -25,6 +25,7 @@ local cod = {
spawn_in_group = 8,
tilt_swim = true,
collisionbox = {-0.3, 0.0, -0.3, 0.3, 0.79, 0.3},
head_eye_height = 0.195,
visual = "mesh",
mesh = "extra_mobs_cod.b3d",
textures = {

View File

@ -22,13 +22,12 @@ local cow_def = {
}, },
head_swivel = "head.control",
bone_eye_height = 10,
head_eye_height = 1.1,
head_eye_height = 1.3,
horizontal_head_height=-1.8,
curiosity = 2,
head_yaw="z",
makes_footstep_sound = true,
movement_speed = 4.0,
walk_chance = 15,
drops = {
{name = "mcl_mobitems:beef",
chance = 1,

View File

@ -17,13 +17,13 @@ mcl_mobs.register_mob("mobs_mc:dolphin", {
xp_min = 1,
xp_max = 3,
armor = 100,
walk_chance = 100,
breath_max = 120,
rotate = 180,
spawn_in_group_min = 3,
spawn_in_group = 5,
tilt_swim = true,
collisionbox = {-0.3, 0.0, -0.3, 0.3, 0.79, 0.3},
head_eye_height = 0.3,
visual = "mesh",
mesh = "extra_mobs_dolphin.b3d",
textures = {

View File

@ -51,7 +51,6 @@ mcl_mobs.register_mob("mobs_mc:enderdragon", {
persist_in_peaceful = true,
pathfinding = 1,
attacks_animals = true,
walk_chance = 100,
hp_max = 200,
hp_min = 200,
xp_min = 500,

View File

@ -261,6 +261,7 @@ mcl_mobs.register_mob("mobs_mc:enderman", {
makes_footstep_sound = true,
can_despawn = true,
spawn_in_group = 2,
head_eye_height = 2.55,
on_spawn = function(self)
local spider_eyes=false
for n = 1, #self.object:get_children() do

View File

@ -39,6 +39,7 @@ mcl_mobs.register_mob("mobs_mc:endermite", {
view_range = 16,
damage = 2,
reach = 1,
head_eye_height = 0.13,
})
mcl_mobs.register_egg("mobs_mc:endermite", S("Endermite"), "#161616", "#6d6d6d", 0)

View File

@ -57,6 +57,7 @@ mcl_mobs.register_mob("mobs_mc:ghast", {
passive = false,
jump = true,
jump_height = 4,
head_eye_height = 2.6,
floats=1,
fly = true,
makes_footstep_sound = false,

View File

@ -22,6 +22,7 @@ mcl_mobs.register_mob("mobs_mc:guardian", {
movement_speed = 10,
damage = 6,
reach = 3,
head_eye_height = 0.425,
collisionbox = {-0.425, 0.25, -0.425, 0.425, 1.1, 0.425},
doll_size_override = { x = 0.6, y = 0.6 },
visual = "mesh",

View File

@ -22,6 +22,7 @@ mcl_mobs.register_mob("mobs_mc:guardian_elder", {
movement_speed = 6.0,
damage = 8,
reach = 3,
head_eye_height = 0.99875,
collisionbox = {-0.99875, 0.5, -0.99875, 0.99875, 2.4975, 0.99875},
doll_size_override = { x = 0.72, y = 0.72 },
visual = "mesh",

View File

@ -125,7 +125,6 @@ local horse = {
},
fear_height = 4,
fly = false,
walk_chance = 60,
view_range = 16,
steer_class = "controls",
follow = {
@ -150,6 +149,7 @@ local horse = {
jump = true,
jump_height = 15,
drops = { base_drop },
head_eye_height = 1.52,
should_drive = function (self)
return self._saddle and mob_class.should_drive (self)
end,
@ -477,6 +477,7 @@ local donkey = table.merge(horse, {
spawn_in_group = 3,
spawn_in_group_min = 1,
movement_speed = 3.5,
head_eye_height = 1.425,
animation = {
stand_start = 0, stand_end = 0,
walk_start = 0, walk_end = 40,
@ -513,6 +514,7 @@ mcl_mobs.register_mob("mobs_mc:mule", table.merge(donkey, {
sounds = table.merge(donkey.sounds, {
base_pitch = 1.15,
}),
head_eye_height = 1.52,
collisionbox = {
horse.collisionbox[1] * m,
horse.collisionbox[2] * m,

View File

@ -64,7 +64,7 @@ mcl_mobs.register_mob("mobs_mc:llama", {
head_swivel = "head.control",
bone_eye_height = 11,
head_eye_height = 3,
head_eye_height = 1.7765,
horizontal_head_height=0,
curiosity = 60,
head_yaw = "z",

View File

@ -34,7 +34,7 @@ local ocelot = {
xp_max = 3,
head_swivel = "head.control",
bone_eye_height = 6.2,
head_eye_height = 0.4,
head_eye_height = 0.35,
horizontal_head_height=-0,
head_yaw="z",
curiosity = 4,
@ -43,7 +43,6 @@ local ocelot = {
mesh = "mobs_mc_cat.b3d",
textures = {"mobs_mc_cat_ocelot.png"},
makes_footstep_sound = true,
walk_chance = default_walk_chance,
movement_speed = 6.0,
floats = 1,
runaway = true,
@ -138,13 +137,11 @@ table.update(cat,{
if not self.order or self.order == "" or self.order == "sit" then
self.order = "roam"
self.walk_chance = default_walk_chance
self.jump = true
else
-- “Sit!”
-- TODO: Add sitting model
self.order = "sit"
self.walk_chance = 0
self.jump = false
end
end,

View File

@ -135,6 +135,7 @@ mcl_mobs.register_mob("mobs_mc:parrot", {
head_swivel = "head.control",
bone_eye_height = 1.1,
horizontal_head_height=0,
head_eye_height = 0.54,
curiosity = 10,
collisionbox = {-0.25, -0.01, -0.25, 0.25, 0.89, 0.25},
visual = "mesh",
@ -172,7 +173,6 @@ mcl_mobs.register_mob("mobs_mc:parrot", {
physical = true,
movement_speed = 4.0,
fly = true,
walk_chance = 75,
fly_chance = 50,
makes_footstep_sound = false,
fear_height = 0,

View File

@ -50,6 +50,7 @@ local piglin = {
hp_max = 16,
xp_min = 9,
xp_max = 9,
head_eye_height = 1.79,
armor = {fleshy = 90},
damage = 4,
reach = 3,
@ -241,7 +242,7 @@ mcl_mobs.register_mob("mobs_mc:zombified_piglin",table.merge(piglin,{
reach = 2,
head_swivel = "head.control",
bone_eye_height = 2.4,
head_eye_height = 1.4,
head_eye_height = 1.79,
curiosity = 15,
collisionbox = {-0.3, -0.01, -0.3, 0.3, 1.94, 0.3},
jump = true,

View File

@ -22,6 +22,7 @@ local salmon = {
armor = 100,
spawn_in_group = 5,
tilt_swim = true,
head_eye_height = 0.26,
collisionbox = {-0.4, 0.0, -0.4, 0.4, 0.79, 0.4},
visual = "mesh",
mesh = "extra_mobs_salmon.b3d",

View File

@ -52,7 +52,7 @@ mcl_mobs.register_mob("mobs_mc:sheep", {
collisionbox = {-0.45, -0.01, -0.45, 0.45, 1.29, 0.45},
head_swivel = "head.control",
bone_eye_height = 3.3,
head_eye_height = 1.1,
head_eye_height = 1.235,
horizontal_head_height=-.7,
curiosity = 6,
head_yaw="z",

View File

@ -67,7 +67,6 @@ mcl_mobs.register_mob("mobs_mc:shulker", {
mob_pushable = false,
-- TODO: sounds
visual_size = {x=3, y=3},
walk_chance = 10,
knock_back = false,
jump = false,
can_despawn = false,

View File

@ -24,6 +24,7 @@ mcl_mobs.register_mob("mobs_mc:silverfish", {
xp_min = 5,
xp_max = 5,
armor = {fleshy = 100, arthropod = 100},
head_eye_height = 0.13,
collisionbox = {-0.4, -0.01, -0.4, 0.4, 0.44, 0.4},
visual = "mesh",
mesh = "mobs_mc_silverfish.b3d",

View File

@ -113,7 +113,7 @@ local skeleton = {
mcl_bows.shoot_arrow("mcl_bows:arrow", pos, dir, self.object:get_yaw(), self.object, nil, dmg)
end
end,
shoot_interval = 2,
shoot_interval = 1,
shoot_offset = 1.5,
harmed_by_heal = true,
on_die = function(self, pos, cmi_cause)

View File

@ -25,6 +25,7 @@ mcl_mobs.register_mob("mobs_mc:witherskeleton", {
visual = "mesh",
mesh = "mobs_mc_witherskeleton.b3d",
head_swivel = "head.control",
head_eye_height = 2.1,
bone_eye_height = 2.38,
curiosity = 60,
textures = {

View File

@ -135,7 +135,6 @@ local slime_big = {
passive = false,
jump = true,
movement_speed = 12, -- (0.3 + 0.1 * size) * 20
walk_chance = 0,
jump_height = 8, -- (was 5.8) JUMP!
fear_height = 0,
spawn_small_alternative = "mobs_mc:slime_small",
@ -323,7 +322,6 @@ local magma_cube_big = {
passive = false,
jump = true,
jump_height = 8,
walk_chance = 0,
fear_height = 0,
spawn_small_alternative = "mobs_mc:magma_cube_small",
on_die = spawn_children_on_die("mobs_mc:magma_cube_small", 0.8, 1.5),

View File

@ -32,6 +32,7 @@ mcl_mobs.register_mob("mobs_mc:snowman", {
fall_damage = 0,
water_damage = 4,
_mcl_freeze_damage = 0,
head_eye_height = 1.7,
rain_damage = 4,
armor = { fleshy = 100, water_vulnerable = 100 },
attacks_monsters = true,

View File

@ -45,6 +45,7 @@ local spider = {
hp_max = 16,
xp_min = 5,
xp_max = 5,
head_eye_height = 0.65,
armor = {fleshy = 100, arthropod = 100},
on_spawn = function(self)
self.object:set_properties({visual_size={x=1,y=1}})
@ -119,6 +120,7 @@ cave_spider.textures = { {"mobs_mc_cave_spider.png^(mobs_mc_spider_eyes.png^[mak
cave_spider.damage = 2
cave_spider.hp_min = 1
cave_spider.hp_max = 12
cave_spider.head_eye_height = 0.5625
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)

View File

@ -42,6 +42,7 @@ local squid_defs = {
xp_min = 1,
xp_max = 3,
armor = 100,
head_eye_height = 0.4,
spawn_in_group_min = 2,
spawn_in_group = 4,
-- FIXME: If the squid is near the floor, it turns black

View File

@ -68,6 +68,7 @@ local tropical_fish = {
xp_min = 1,
xp_max = 3,
armor = 100,
head_eye_height = 0.26,
spawn_in_group = 9,
tilt_swim = true,
movement_speed = 14,

View File

@ -21,6 +21,7 @@ mcl_mobs.register_mob("mobs_mc:vex", {
hp_max = 14,
xp_min = 6,
xp_max = 6,
head_eye_height = 0.51875,
collisionbox = {-0.2, 0.2, -0.2, 0.2, 1.0, 0.2}, --bat
visual = "mesh",
mesh = "mobs_mc_vex.b3d",

View File

@ -117,7 +117,6 @@ function mobs_mc.villager_mob:stand_near_players()
if table.count(minetest.get_objects_inside_radius(self.object:get_pos(), PLAYER_SCAN_RADIUS), function(_, pl) return pl:is_player() end) > 0 then
self:stand_still()
else
self.walk_chance = DEFAULT_WALK_CHANCE
self.jump = true
end
end
@ -205,7 +204,7 @@ table.update(mobs_mc.villager_mob, {
hp_max = 20,
head_swivel = "head.control",
bone_eye_height = 6.3,
head_eye_height = 2.2,
head_eye_height = 1.62,
curiosity = 10,
runaway = true,
collisionbox = {-0.25, -0.01, -0.25, 0.25, 1.94, 0.25},
@ -216,7 +215,7 @@ table.update(mobs_mc.villager_mob, {
"mobs_mc_villager.png", --hat
},
makes_footstep_sound = true,
movement_speed = 10,
movement_speed = 5.0,
drops = {},
can_despawn = false,
-- TODO: sounds
@ -242,7 +241,6 @@ table.update(mobs_mc.villager_mob, {
view_range = 16,
fear_height = 4,
jump = true,
walk_chance = DEFAULT_WALK_CHANCE,
_bed = nil,
_id = nil,
_profession = "unemployed",

View File

@ -38,7 +38,7 @@ mcl_mobs.register_mob("mobs_mc:evoker", {
} },
makes_footstep_sound = true,
damage = 6,
movement_speed = 10,
movement_speed = 5.0,
group_attack = true,
attack_type = "melee",
custom_attack_interval = 15,

View File

@ -42,7 +42,7 @@ mcl_mobs.register_mob("mobs_mc:illusioner", {
distance = 16,
},
visual_size = {x=2.75, y=2.75},
movement_speed = 10,
movement_speed = 5.0,
jump = true,
animation = {
stand_speed = 25,

View File

@ -43,6 +43,7 @@ mcl_mobs.register_mob("mobs_mc:villager_zombie", {
mesh = "mobs_mc_villager_zombie.b3d",
head_swivel = "Head_Control",
bone_eye_height = 2.35,
head_eye_height = 1.74,
curiosity = 2,
textures = {
{"mobs_mc_zombie_butcher.png"},

View File

@ -24,7 +24,6 @@ local GATHERING = "gathering"
local RUNAWAY = "runaway"
function mobs_mc.villager_mob:stand_still()
self.walk_chance = 0
self.jump = false
self:halt_in_tracks (true)
-- self:set_state("stand")

View File

@ -153,6 +153,7 @@ mcl_mobs.register_mob("mobs_mc:witch", {
{"mobs_mc_witch.png"},
},
visual_size = {x=2.75, y=2.75},
head_eye_height = 1.62,
makes_footstep_sound = true,
damage = 2,
reach = 2,
@ -201,8 +202,7 @@ mcl_mobs.register_mob("mobs_mc:witch", {
attack_players_and_npcs = function (self)
end,
attack_custom = function (self)
local attack_players = self:attack_players_allowed ()
if self.state == "attack" then
if self.attacking then
-- A target has already been selected.
return
end
@ -215,9 +215,9 @@ mcl_mobs.register_mob("mobs_mc:witch", {
local objs = minetest.get_objects_inside_radius (pos, self.view_range)
table.shuffle (objs)
for _, obj in pairs (objs) do
if self:line_of_sight (pos, obj:get_pos(), 2) then
if self:line_of_sight (pos, obj:get_pos()) then
local l = obj:get_luaentity ()
if attack_players and obj:is_player () and (not self._player_cooldown or not self.raidmob) then
if obj:is_player () and self:attack_players_allowed (obj) and (not self._player_cooldown or not self.raidmob) then
self:do_attack (obj)
break
elseif self.raidmob and l and l.raidmob and (l.name == "mobs_mc:pillager" or l.name == "mobs_mc:vindicator" or l.name == "mobs_mc:evoker") then

View File

@ -75,7 +75,7 @@ local wolf = {
makes_footstep_sound = true,
head_swivel = "head.control",
bone_eye_height = 3.5,
head_eye_height = 1.1,
head_eye_height = 0.68,
horizontal_head_height=0,
curiosity = 3,
head_yaw="z",
@ -90,7 +90,6 @@ local wolf = {
pathfinding = 1,
floats = 1,
view_range = 16,
walk_chance = default_walk_chance,
movement_speed = 6.0,
damage = 4,
reach = 2,
@ -121,7 +120,6 @@ local wolf = {
ent.owner = clicker:get_player_name()
ent.tamed = true
ent:set_animation("sit")
ent.walk_chance = 0
ent.jump = false
ent.health = self.health
-- cornfirm taming

View File

@ -140,7 +140,7 @@ function mcl_beds.register_bed(name, def)
paramtype2 = "facedir",
is_ground_content = false,
stack_max = 1,
groups = {handy=1, bed = 1, dig_by_piston=1, bouncy=66, fall_damage_add_percent=-50, deco_block = 1, flammable=-1, unsticky = 1},
groups = {handy=1, bed = 1, dig_by_piston=1, bouncy=66, fall_damage_add_percent=-50, deco_block = 1, flammable=-1, unsticky = 1, _mcl_partial=2},
_mcl_hardness = 0.2,
_mcl_blast_resistance = 1,
sounds = def.sounds or default_sounds,

View File

@ -128,7 +128,7 @@ core.register_node("mcl_cauldrons:cauldron", {
drawtype = "nodebox",
paramtype = "light",
is_ground_content = false,
groups = {pickaxey=1, deco_block=1, cauldron=1, comparator_signal=0},
groups = {pickaxey=1, deco_block=1, cauldron=1, comparator_signal=0, _mcl_partial=2},
node_box = create_cauldron_nodebox(0),
selection_box = { type = "regular" },
tiles = {
@ -166,7 +166,7 @@ local function register_filled_cauldron(water_level, description, liquid)
paramtype = "light",
light_source = light_level,
is_ground_content = false,
groups = {pickaxey=1, not_in_creative_inventory=1, cauldron=(1+water_level), cauldron_filled=water_level, comparator_signal=water_level, cauldron_water = cauldron_water},
groups = {pickaxey=1, not_in_creative_inventory=1, cauldron=(1+water_level), cauldron_filled=water_level, comparator_signal=water_level, cauldron_water = cauldron_water, _mcl_partial = 2},
node_box = create_cauldron_nodebox(water_level),
collision_box = create_cauldron_nodebox(0),
selection_box = { type = "regular" },

View File

@ -44,6 +44,7 @@ minetest.register_node("mcl_core:water_flowing", {
waving = 3,
post_effect_color = {a=60, r=0x03, g=0x3C, b=0x5C},
groups = { water=3, liquid=3, puts_out_fire=1, not_in_creative_inventory=1, freezes=1, melt_around=1, dig_by_piston=1, unsticky = 1},
_pathfinding_class = "WATER",
_mcl_blast_resistance = 100,
-- Hardness intentionally set to infinite instead of 100 (Minecraft value) to avoid problems in creative mode
_mcl_hardness = -1,
@ -89,6 +90,7 @@ S("• When water is directly below lava, the water turns into stone."),
liquid_range = 7,
post_effect_color = {a=60, r=0x03, g=0x3C, b=0x5C},
groups = { water=3, liquid=3, puts_out_fire=1, freezes=1, not_in_creative_inventory=1, dig_by_piston=1, unsticky = 1},
_pathfinding_class = "WATER",
_mcl_blast_resistance = 100,
-- Hardness intentionally set to infinite instead of 100 (Minecraft value) to avoid problems in creative mode
_mcl_hardness = -1,
@ -135,6 +137,7 @@ minetest.register_node("mcl_core:lava_flowing", {
damage_per_second = 4*2,
post_effect_color = {a=245, r=208, g=73, b=10},
groups = { lava=3, liquid=2, destroys_items=1, not_in_creative_inventory=1, dig_by_piston=1, set_on_fire=15, unsticky = 1},
_pathfinding_class = "LAVA",
_mcl_blast_resistance = 100,
-- Hardness intentionally set to infinite instead of 100 (Minecraft value) to avoid problems in creative mode
_mcl_hardness = -1,
@ -189,6 +192,7 @@ S("• When lava is directly above water, the water turns into stone."),
damage_per_second = 4*2,
post_effect_color = {a=245, r=208, g=73, b=10},
groups = { lava=3, lava_source=1, liquid=2, destroys_items=1, not_in_creative_inventory=1, dig_by_piston=1, set_on_fire=15, fire_damage=1, unsticky = 1},
_pathfinding_class = "LAVA",
_mcl_blast_resistance = 100,
-- Hardness intentionally set to infinite instead of 100 (Minecraft value) to avoid problems in creative mode
_mcl_hardness = -1,

View File

@ -190,6 +190,7 @@ function mcl_doors:register_trapdoor(name, def)
end
return true
end,
_pathfinding_class = "TRAPDOOR",
})
-- Open trapdoor
@ -246,6 +247,7 @@ function mcl_doors:register_trapdoor(name, def)
end
return true
end,
_pathfinding_class = "TRAPDOOR",
})
if minetest.get_modpath("doc") then

View File

@ -6,7 +6,7 @@ mcl_doors:register_door("mcl_doors:iron_door", {
_doc_items_longdesc = S("Iron doors are 2-block high barriers which can only be opened or closed by a redstone signal, but not by hand."),
_doc_items_usagehelp = S("To open or close an iron door, supply its lower half with a redstone signal."),
inventory_image = "doors_item_steel.png",
groups = {pickaxey=1},
groups = {pickaxey=1, door_iron=1},
_mcl_hardness = 5,
_mcl_blast_resistance = 5,
tiles_bottom = {"mcl_doors_door_iron_lower.png^[transformFX", "mcl_doors_door_iron_side_lower.png"},

View File

@ -207,7 +207,8 @@ function mcl_fences.register_fence_def(name, definitions)
if not definitions.groups then definitions.groups = {} end
definitions.groups.fence = 1
definitions.groups.fence = 1
definitions._pathfinding_class = "FENCE"
definitions.groups.deco_block = 1
if not definitions.connects_to then
@ -248,6 +249,7 @@ function mcl_fences.register_fence_gate_def(name, definitions)
if not definitions.groups then definitions.groups = {} end
definitions.groups.fence_gate = 1
definitions._pathfinding_class = "FENCE"
definitions.groups.deco_block = 1
if definitions.tiles and definitions.tiles[1] then
@ -262,7 +264,7 @@ function mcl_fences.register_fence_gate_def(name, definitions)
opendefinitions.wield_image = nil
opendefinitions._mcl_burntime = nil
opendefinitions.groups = table.copy (definitions.groups)
opendefinitions.groups.fence_gate_open = 1
opendefinitions._pathfinding_class = "OPEN"
opendefinitions.groups.not_in_creative_inventory = 1
opendefinitions.mesecon_ignore_opaque_dig = 1

View File

@ -102,6 +102,7 @@ minetest.register_node("mcl_fire:fire", {
mcl_portals.light_nether_portal(pos)
end
end,
_pathfinding_class = "DAMAGE_FIRE",
_mcl_blast_resistance = 0,
})
@ -142,6 +143,7 @@ minetest.register_node("mcl_fire:eternal_fire", {
end,
sounds = {},
drop = "",
_pathfinding_class = "DAMAGE_FIRE",
_mcl_blast_resistance = 0,
})

View File

@ -309,4 +309,5 @@ minetest.register_node("mcl_flowers:waterlily", {
return itemstack
end,
on_rotate = screwdriver.rotate_simple,
_pathfinding_class = "TRAPDOOR",
})

View File

@ -156,7 +156,7 @@ minetest.register_node("mcl_nether:soul_sand", {
_tt_help = S("Reduces walking speed"),
_doc_items_longdesc = S("Soul sand is a block from the Nether. One can only slowly walk on soul sand. The slowing effect is amplified when the soul sand is on top of ice, packed ice or a slime block."),
tiles = {"mcl_nether_soul_sand.png"},
groups = {handy = 1, shovely = 1, building_block = 1, soil_nether_wart = 1, material_sand = 1, soul_block = 1 },
groups = {handy = 1, shovely = 1, building_block = 1, soil_nether_wart = 1, material_sand = 1, soul_block = 1, _mcl_partial = 2 },
collision_box = {
type = "fixed",
fixed = { -0.5, -0.5, -0.5, 0.5, 0.5 - 2/16, 0.5 },
@ -164,13 +164,14 @@ minetest.register_node("mcl_nether:soul_sand", {
sounds = mcl_sounds.node_sound_sand_defaults(),
_mcl_blast_resistance = 0.5,
_mcl_hardness = 0.5,
-- Mobs only.
_mcl_velocity_factor = 0.4,
})
mcl_player.register_globalstep_slow(function(player)
-- Standing on soul sand or soul soil?
if minetest.get_item_group(mcl_player.players[player].nodes.stand, "soul_block") > 0 then
-- TODO: Tweak walk speed
-- TODO: Also slow down mobs
local boots = player:get_inventory():get_stack("armor", 5)
local soul_speed = mcl_enchanting.get_enchantment(boots, "soul_speed")
-- If player wears Soul Speed boots, increase speed

View File

@ -106,6 +106,7 @@ function mcl_panes.register_pane(name, def)
end
flatgroups.pane = 1
flatgroups.deco_block = 1
flatgroups._mcl_partial = 2
minetest.register_node(":mcl_panes:" .. name .. "_flat", {
description = def.description,
_doc_items_create_entry = def._doc_items_create_entry,
@ -141,6 +142,7 @@ function mcl_panes.register_pane(name, def)
local groups = table.copy(def.groups)
groups.pane = 1
groups.not_in_creative_inventory = 1
groups._mcl_partial = 2
minetest.register_node(":mcl_panes:" .. name, {
drawtype = "nodebox",
paramtype = "light",
@ -210,7 +212,7 @@ local function pane(description, node, append)
inventory_image = texture1,
wield_image = texture1,
sounds = mcl_sounds.node_sound_glass_defaults(),
groups = {handy=1, material_glass=1},
groups = {handy=1, material_glass=1, _mcl_partial=2},
recipe = {
{node, node, node},
{node, node, node},

View File

@ -172,6 +172,7 @@ local function register_stair(subname, stairdef)
stairdef.groups.stair = 1
stairdef.groups.building_block = 1
stairdef.groups._mcl_partial = 2
local image_table = {}
for i, image in pairs(stairdef.tiles) do
@ -390,6 +391,7 @@ local function register_slab(subname, stairdef)
-- e.g. upper sandstone slabs look completely wrong.
local topdef = table.copy(nodedef)
topdef.groups.slab = 1
topdef.groups._mcl_partial = 2
topdef.groups.slab_top = 1
topdef.groups.not_in_creative_inventory = 1
topdef.groups.not_in_craft_guide = 1

View File

@ -173,6 +173,7 @@ function mcl_walls.register_wall(nodename, description, source, tiles, inventory
_mcl_hardness = 2,
_mcl_stonecutter_recipes = {source},
_mcl_baseitem = nodename,
_pathfinding_class = "FENCE",
}, overrides or {}))
-- Add entry alias for the Help
@ -203,6 +204,7 @@ function mcl_walls.register_wall(nodename, description, source, tiles, inventory
_mcl_hardness = 2,
_mcl_stonecutter_recipes = {source},
_mcl_baseitem = nodename,
_pathfinding_class = "FENCE",
}, overrides or {}))
-- Add entry alias for the Help
if minetest.get_modpath("doc") then
@ -230,6 +232,7 @@ function mcl_walls.register_wall(nodename, description, source, tiles, inventory
_mcl_blast_resistance = 6,
_mcl_hardness = 2,
_mcl_baseitem = nodename,
_pathfinding_class = "FENCE"
}, overrides or {}))
-- Add entry alias for the Help
if minetest.get_modpath("doc") then