WIP -- squash later
This commit is contained in:
parent
b1054b6b07
commit
c7fba06b74
@ -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
|
||||
} )
|
@ -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 ()
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -385,6 +385,11 @@ end
|
||||
|
||||
-- set animation speed relative to velocity
|
||||
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
|
||||
|
@ -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),
|
||||
|
@ -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
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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",
|
||||
|
@ -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 = {
|
||||
|
@ -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,
|
||||
|
@ -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 = {
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -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,
|
||||
|
@ -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",
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -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,
|
||||
|
@ -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",
|
||||
|
@ -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)
|
||||
|
@ -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 = {
|
||||
|
@ -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),
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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"},
|
||||
|
@ -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")
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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" },
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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"},
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
})
|
||||
|
||||
|
@ -309,4 +309,5 @@ minetest.register_node("mcl_flowers:waterlily", {
|
||||
return itemstack
|
||||
end,
|
||||
on_rotate = screwdriver.rotate_simple,
|
||||
_pathfinding_class = "TRAPDOOR",
|
||||
})
|
||||
|
@ -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
|
||||
|
@ -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},
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user