forked from VoxeLibre/VoxeLibre
Merge pull request 'Add ability to fight and kill mobs' (#1603) from jordan4ibanez/MineClone2:mineclone5 into mineclone5
Reviewed-on: MineClone2/MineClone2#1603
This commit is contained in:
commit
53d3de7dd3
|
@ -120,7 +120,7 @@ end
|
||||||
|
|
||||||
-- creative check
|
-- creative check
|
||||||
function mobs.is_creative(name)
|
function mobs.is_creative(name)
|
||||||
return minetest.is_creative_enabled(name)
|
return minetest_is_creative_enabled(name)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -159,6 +159,7 @@ dofile(api_path .. "movement.lua")
|
||||||
dofile(api_path .. "set_up.lua")
|
dofile(api_path .. "set_up.lua")
|
||||||
dofile(api_path .. "attack_type_instructions.lua")
|
dofile(api_path .. "attack_type_instructions.lua")
|
||||||
dofile(api_path .. "sound_handling.lua")
|
dofile(api_path .. "sound_handling.lua")
|
||||||
|
dofile(api_path .. "death_logic.lua")
|
||||||
|
|
||||||
|
|
||||||
mobs.spawning_mobs = {}
|
mobs.spawning_mobs = {}
|
||||||
|
@ -326,6 +327,7 @@ function mobs:register_mob(name, def)
|
||||||
visual_size_origin = def.visual_size or {x = 1, y = 1, z = 1},
|
visual_size_origin = def.visual_size or {x = 1, y = 1, z = 1},
|
||||||
punch_timer_cooloff = def.punch_timer_cooloff or 0.5,
|
punch_timer_cooloff = def.punch_timer_cooloff or 0.5,
|
||||||
projectile_cooldown = def.projectile_cooldown or 2,
|
projectile_cooldown = def.projectile_cooldown or 2,
|
||||||
|
death_animation_timer = 0,
|
||||||
--end j4i stuff
|
--end j4i stuff
|
||||||
|
|
||||||
-- MCL2 extensions
|
-- MCL2 extensions
|
||||||
|
|
|
@ -610,13 +610,33 @@ mobs.mob_step = function(self, dtime)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--do death logic (animation, poof, explosion, etc)
|
||||||
|
if self.health <= 0 then
|
||||||
|
|
||||||
|
mobs.death_logic(self, dtime)
|
||||||
|
|
||||||
|
--this is here because the mob must continue to move
|
||||||
|
--while stunned before coming to a complete halt even during
|
||||||
|
--the death tilt
|
||||||
|
if self.pause_timer > 0 then
|
||||||
|
self.pause_timer = self.pause_timer - dtime
|
||||||
|
--perfectly reset pause_timer
|
||||||
|
if self.pause_timer < 0 then
|
||||||
|
self.pause_timer = 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
local attacking = nil
|
local attacking = nil
|
||||||
|
|
||||||
|
--scan for players within eyesight
|
||||||
if self.hostile then
|
if self.hostile then
|
||||||
--true for line_of_sight is debug
|
--true for line_of_sight is debug
|
||||||
attacking = mobs.detect_closest_player_within_radius(self,true,self.view_range,self.eye_height)
|
attacking = mobs.detect_closest_player_within_radius(self,true,self.view_range,self.eye_height)
|
||||||
|
|
||||||
--go get the closest player ROAR >:O
|
--go get the closest player
|
||||||
if attacking then
|
if attacking then
|
||||||
|
|
||||||
--set initial punch timer
|
--set initial punch timer
|
||||||
|
@ -650,28 +670,42 @@ mobs.mob_step = function(self, dtime)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--mob is stunned after being hit
|
||||||
|
if self.pause_timer > 0 then
|
||||||
|
self.pause_timer = self.pause_timer - dtime
|
||||||
|
--don't break eye contact
|
||||||
|
if self.hostile and self.attacking then
|
||||||
|
mobs.set_yaw_while_attacking(self)
|
||||||
|
end
|
||||||
|
|
||||||
--jump only (like slimes)
|
--perfectly reset pause_timer
|
||||||
if self.jump_only then
|
if self.pause_timer < 0 then
|
||||||
jump_state_switch(self, dtime)
|
self.pause_timer = 0
|
||||||
jump_state_execution(self, dtime)
|
end
|
||||||
--swimming
|
|
||||||
elseif self.swim then
|
return -- don't allow collision detection
|
||||||
swim_state_switch(self, dtime)
|
--do normal ai
|
||||||
swim_state_execution(self, dtime)
|
|
||||||
--flying
|
|
||||||
elseif self.fly then
|
|
||||||
fly_state_switch(self, dtime)
|
|
||||||
fly_state_execution(self,dtime)
|
|
||||||
--regular mobs that walk around
|
|
||||||
else
|
else
|
||||||
land_state_switch(self, dtime)
|
--jump only (like slimes)
|
||||||
land_state_execution(self,dtime)
|
if self.jump_only then
|
||||||
|
jump_state_switch(self, dtime)
|
||||||
|
jump_state_execution(self, dtime)
|
||||||
|
--swimming
|
||||||
|
elseif self.swim then
|
||||||
|
swim_state_switch(self, dtime)
|
||||||
|
swim_state_execution(self, dtime)
|
||||||
|
--flying
|
||||||
|
elseif self.fly then
|
||||||
|
fly_state_switch(self, dtime)
|
||||||
|
fly_state_execution(self,dtime)
|
||||||
|
--regular mobs that walk around
|
||||||
|
else
|
||||||
|
land_state_switch(self, dtime)
|
||||||
|
land_state_execution(self,dtime)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- can mob be pushed, if so calculate direction -- do this last (overrides everything)
|
-- can mob be pushed, if so calculate direction -- do this last (overrides everything)
|
||||||
if self.pushable then
|
if self.pushable then
|
||||||
mobs.collision(self)
|
mobs.collision(self)
|
||||||
|
|
|
@ -175,10 +175,9 @@ mobs.set_static_pitch = function(self)
|
||||||
local current_rotation = self.object:get_rotation()
|
local current_rotation = self.object:get_rotation()
|
||||||
|
|
||||||
current_rotation.x = 0
|
current_rotation.x = 0
|
||||||
current_rotation.z = 0
|
|
||||||
|
|
||||||
self.object:set_rotation(current_rotation)
|
self.object:set_rotation(current_rotation)
|
||||||
self.pitch_switchfdas = "static"
|
self.pitch_switch = "static"
|
||||||
end
|
end
|
||||||
|
|
||||||
--this is a helper function for mobs explosion animation
|
--this is a helper function for mobs explosion animation
|
||||||
|
|
|
@ -971,84 +971,7 @@ local update_tag = function(self)
|
||||||
update_roll(self)
|
update_roll(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- drop items
|
|
||||||
local item_drop = function(self, cooked, looting_level)
|
|
||||||
|
|
||||||
-- no drops if disabled by setting
|
|
||||||
if not mobs_drop_items then return end
|
|
||||||
|
|
||||||
looting_level = looting_level or 0
|
|
||||||
|
|
||||||
-- no drops for child mobs (except monster)
|
|
||||||
if (self.child and self.type ~= "monster") then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local obj, item, num
|
|
||||||
local pos = self.object:get_pos()
|
|
||||||
|
|
||||||
self.drops = self.drops or {} -- nil check
|
|
||||||
|
|
||||||
for n = 1, #self.drops do
|
|
||||||
local dropdef = self.drops[n]
|
|
||||||
local chance = 1 / dropdef.chance
|
|
||||||
local looting_type = dropdef.looting
|
|
||||||
|
|
||||||
if looting_level > 0 then
|
|
||||||
local chance_function = dropdef.looting_chance_function
|
|
||||||
if chance_function then
|
|
||||||
chance = chance_function(looting_level)
|
|
||||||
elseif looting_type == "rare" then
|
|
||||||
chance = chance + (dropdef.looting_factor or 0.01) * looting_level
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local num = 0
|
|
||||||
local do_common_looting = (looting_level > 0 and looting_type == "common")
|
|
||||||
if math_random() < chance then
|
|
||||||
num = math_random(dropdef.min or 1, dropdef.max or 1)
|
|
||||||
elseif not dropdef.looting_ignore_chance then
|
|
||||||
do_common_looting = false
|
|
||||||
end
|
|
||||||
|
|
||||||
if do_common_looting then
|
|
||||||
num = num + math_floor(math_random(0, looting_level) + 0.5)
|
|
||||||
end
|
|
||||||
|
|
||||||
if num > 0 then
|
|
||||||
item = dropdef.name
|
|
||||||
|
|
||||||
-- cook items when true
|
|
||||||
if cooked then
|
|
||||||
|
|
||||||
local output = minetest_get_craft_result({
|
|
||||||
method = "cooking", width = 1, items = {item}})
|
|
||||||
|
|
||||||
if output and output.item and not output.item:is_empty() then
|
|
||||||
item = output.item:get_name()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- add item if it exists
|
|
||||||
for x = 1, num do
|
|
||||||
obj = minetest_add_item(pos, ItemStack(item .. " " .. 1))
|
|
||||||
end
|
|
||||||
|
|
||||||
if obj and obj:get_luaentity() then
|
|
||||||
|
|
||||||
obj:set_velocity({
|
|
||||||
x = math_random(-10, 10) / 9,
|
|
||||||
y = 6,
|
|
||||||
z = math_random(-10, 10) / 9,
|
|
||||||
})
|
|
||||||
elseif obj then
|
|
||||||
obj:remove() -- item does not exist
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
self.drops = {}
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-- check if mob is dead or only hurt
|
-- check if mob is dead or only hurt
|
||||||
|
|
|
@ -0,0 +1,165 @@
|
||||||
|
local minetest_add_item = minetest.add_item
|
||||||
|
local minetest_add_particlespawner = minetest.add_particlespawner
|
||||||
|
local minetest_sound_play = minetest.sound_play
|
||||||
|
|
||||||
|
local math_pi = math.pi
|
||||||
|
local math_random = math.random
|
||||||
|
local math_floor = math.floor
|
||||||
|
local HALF_PI = math_pi / 2
|
||||||
|
|
||||||
|
local vector_new = vector.new
|
||||||
|
|
||||||
|
|
||||||
|
local death_effect = function(self)
|
||||||
|
|
||||||
|
local pos = self.object:get_pos()
|
||||||
|
local yaw = self.object:get_yaw()
|
||||||
|
local collisionbox = self.object:get_properties().collisionbox
|
||||||
|
|
||||||
|
local min, max
|
||||||
|
|
||||||
|
if collisionbox then
|
||||||
|
min = {x=collisionbox[1], y=collisionbox[2], z=collisionbox[3]}
|
||||||
|
max = {x=collisionbox[4], y=collisionbox[5], z=collisionbox[6]}
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest_add_particlespawner({
|
||||||
|
amount = 50,
|
||||||
|
time = 0.001,
|
||||||
|
minpos = vector.add(pos, min),
|
||||||
|
maxpos = vector.add(pos, max),
|
||||||
|
minvel = vector.new(-0.5,0.5,-0.5),
|
||||||
|
maxvel = vector.new(0.5,1,0.5),
|
||||||
|
minexptime = 1.1,
|
||||||
|
maxexptime = 1.5,
|
||||||
|
minsize = 1,
|
||||||
|
maxsize = 2,
|
||||||
|
collisiondetection = false,
|
||||||
|
vertical = false,
|
||||||
|
texture = "mcl_particles_mob_death.png", -- this particle looks strange
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- drop items
|
||||||
|
local item_drop = function(self, cooked, looting_level)
|
||||||
|
|
||||||
|
looting_level = looting_level or 0
|
||||||
|
|
||||||
|
-- no drops for child mobs (except monster)
|
||||||
|
if (self.child and self.type ~= "monster") then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local obj, item, num
|
||||||
|
local pos = self.object:get_pos()
|
||||||
|
|
||||||
|
self.drops = self.drops or {} -- nil check
|
||||||
|
|
||||||
|
for n = 1, #self.drops do
|
||||||
|
local dropdef = self.drops[n]
|
||||||
|
local chance = 1 / dropdef.chance
|
||||||
|
local looting_type = dropdef.looting
|
||||||
|
|
||||||
|
if looting_level > 0 then
|
||||||
|
local chance_function = dropdef.looting_chance_function
|
||||||
|
if chance_function then
|
||||||
|
chance = chance_function(looting_level)
|
||||||
|
elseif looting_type == "rare" then
|
||||||
|
chance = chance + (dropdef.looting_factor or 0.01) * looting_level
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local num = 0
|
||||||
|
local do_common_looting = (looting_level > 0 and looting_type == "common")
|
||||||
|
if math_random() < chance then
|
||||||
|
num = math_random(dropdef.min or 1, dropdef.max or 1)
|
||||||
|
elseif not dropdef.looting_ignore_chance then
|
||||||
|
do_common_looting = false
|
||||||
|
end
|
||||||
|
|
||||||
|
if do_common_looting then
|
||||||
|
num = num + math_floor(math_random(0, looting_level) + 0.5)
|
||||||
|
end
|
||||||
|
|
||||||
|
if num > 0 then
|
||||||
|
item = dropdef.name
|
||||||
|
|
||||||
|
-- cook items when true
|
||||||
|
if cooked then
|
||||||
|
|
||||||
|
local output = minetest_get_craft_result({
|
||||||
|
method = "cooking", width = 1, items = {item}})
|
||||||
|
|
||||||
|
if output and output.item and not output.item:is_empty() then
|
||||||
|
item = output.item:get_name()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- add item if it exists
|
||||||
|
for x = 1, num do
|
||||||
|
obj = minetest_add_item(pos, ItemStack(item .. " " .. 1))
|
||||||
|
end
|
||||||
|
|
||||||
|
if obj and obj:get_luaentity() then
|
||||||
|
|
||||||
|
obj:set_velocity({
|
||||||
|
x = math_random(-10, 10) / 9,
|
||||||
|
y = 6,
|
||||||
|
z = math_random(-10, 10) / 9,
|
||||||
|
})
|
||||||
|
elseif obj then
|
||||||
|
obj:remove() -- item does not exist
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
self.drops = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
mobs.death_logic = function(self, dtime)
|
||||||
|
self.death_animation_timer = self.death_animation_timer + dtime
|
||||||
|
|
||||||
|
|
||||||
|
--the final POOF of a mob despawning
|
||||||
|
if self.death_animation_timer >= 1.25 then
|
||||||
|
|
||||||
|
item_drop(self,false,1)
|
||||||
|
|
||||||
|
death_effect(self)
|
||||||
|
|
||||||
|
self.object:remove()
|
||||||
|
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
--I'm sure there's a more efficient way to do this
|
||||||
|
--but this is the easiest, easier to work with 1 variable synced
|
||||||
|
--this is also not smooth
|
||||||
|
local death_animation_roll = self.death_animation_timer * 2 -- * 2 to make it faster
|
||||||
|
if death_animation_roll > 1 then
|
||||||
|
death_animation_roll = 1
|
||||||
|
end
|
||||||
|
|
||||||
|
local rot = self.object:get_rotation() --(no pun intended)
|
||||||
|
|
||||||
|
rot.z = death_animation_roll * HALF_PI
|
||||||
|
|
||||||
|
self.object:set_rotation(rot)
|
||||||
|
|
||||||
|
mobs.set_mob_animation(self,"stand", true)
|
||||||
|
|
||||||
|
|
||||||
|
--flying and swimming mobs just fall down
|
||||||
|
if self.fly or self.swim then
|
||||||
|
if self.object:get_acceleration().y ~= -self.gravity then
|
||||||
|
self.object:set_acceleration(vector_new(0,-self.gravity,0))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--when landing allow mob to slow down and just fall if in air
|
||||||
|
if self.pause_timer <= 0 then
|
||||||
|
mobs.set_velocity(self,0)
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,5 +1,12 @@
|
||||||
local math_floor = math.floor
|
local minetest_after = minetest.after
|
||||||
|
local minetest_sound_play = minetest.sound_play
|
||||||
|
|
||||||
|
local math_floor = math.floor
|
||||||
|
local math_min = math.min
|
||||||
|
local math_random = math.random
|
||||||
|
|
||||||
local vector_direction = vector.direction
|
local vector_direction = vector.direction
|
||||||
|
local vector_multiply = vector.multiply
|
||||||
|
|
||||||
mobs.feed_tame = function(self)
|
mobs.feed_tame = function(self)
|
||||||
return nil
|
return nil
|
||||||
|
@ -36,6 +43,10 @@ end
|
||||||
-- I have no idea what this does
|
-- I have no idea what this does
|
||||||
mobs.create_mob_on_rightclick = function(on_rightclick)
|
mobs.create_mob_on_rightclick = function(on_rightclick)
|
||||||
return function(self, clicker)
|
return function(self, clicker)
|
||||||
|
--don't allow rightclicking dead mobs
|
||||||
|
if self.health <= 0 then
|
||||||
|
return
|
||||||
|
end
|
||||||
local stop = on_rightclick_prefix(self, clicker)
|
local stop = on_rightclick_prefix(self, clicker)
|
||||||
if (not stop) and (on_rightclick) then
|
if (not stop) and (on_rightclick) then
|
||||||
on_rightclick(self, clicker)
|
on_rightclick(self, clicker)
|
||||||
|
@ -47,6 +58,11 @@ end
|
||||||
-- deal damage and effects when mob punched
|
-- deal damage and effects when mob punched
|
||||||
mobs.mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
|
mobs.mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
|
||||||
|
|
||||||
|
--don't do anything if the mob is already dead
|
||||||
|
if self.health <= 0 then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
--neutral passive mobs switch to neutral hostile
|
--neutral passive mobs switch to neutral hostile
|
||||||
if self.neutral then
|
if self.neutral then
|
||||||
|
|
||||||
|
@ -65,37 +81,33 @@ mobs.mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--[[
|
|
||||||
-- custom punch function
|
-- custom punch function
|
||||||
if self.do_punch then
|
if self.do_punch then
|
||||||
|
|
||||||
-- when false skip going any further
|
-- when false skip going any further
|
||||||
if self.do_punch(self, hitter, tflp, tool_capabilities, dir) == false then
|
if self.do_punch(self, hitter, tflp, tool_capabilities, dir) == false then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- error checking when mod profiling is enabled
|
--don't do damage until pause timer resets
|
||||||
if not tool_capabilities then
|
if self.pause_timer > 0 then
|
||||||
minetest.log("warning", "[mobs] Mod profiling enabled, damage not enabled")
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local is_player = hitter:is_player()
|
|
||||||
|
|
||||||
if is_player then
|
-- error checking when mod profiling is enabled
|
||||||
-- is mob protected?
|
if not tool_capabilities then
|
||||||
if self.protected and minetest_is_protected(self.object:get_pos(), hitter:get_player_name()) then
|
minetest.log("warning", "[mobs_mc] Mod profiling enabled, damage not enabled")
|
||||||
return
|
return
|
||||||
end
|
|
||||||
|
|
||||||
-- set/update 'drop xp' timestamp if hitted by player
|
|
||||||
self.xp_timestamp = minetest_get_us_time()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local is_player = hitter:is_player()
|
||||||
|
|
||||||
|
|
||||||
-- punch interval
|
-- punch interval
|
||||||
local weapon = hitter:get_wielded_item()
|
local weapon = hitter:get_wielded_item()
|
||||||
|
|
||||||
local punch_interval = 1.4
|
local punch_interval = 1.4
|
||||||
|
|
||||||
-- exhaust attacker
|
-- exhaust attacker
|
||||||
|
@ -108,28 +120,9 @@ mobs.mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
|
||||||
local armor = self.object:get_armor_groups() or {}
|
local armor = self.object:get_armor_groups() or {}
|
||||||
local tmp
|
local tmp
|
||||||
|
|
||||||
-- quick error check incase it ends up 0 (serialize.h check test)
|
--calculate damage groups
|
||||||
if tflp == 0 then
|
for group,_ in pairs( (tool_capabilities.damage_groups or {}) ) do
|
||||||
tflp = 0.2
|
damage = damage + (tool_capabilities.damage_groups[group] or 0) * ((armor[group] or 0) / 100.0)
|
||||||
end
|
|
||||||
|
|
||||||
if use_cmi then
|
|
||||||
damage = cmi.calculate_damage(self.object, hitter, tflp, tool_capabilities, dir)
|
|
||||||
else
|
|
||||||
|
|
||||||
for group,_ in pairs( (tool_capabilities.damage_groups or {}) ) do
|
|
||||||
|
|
||||||
tmp = tflp / (tool_capabilities.full_punch_interval or 1.4)
|
|
||||||
|
|
||||||
if tmp < 0 then
|
|
||||||
tmp = 0.0
|
|
||||||
elseif tmp > 1 then
|
|
||||||
tmp = 1.0
|
|
||||||
end
|
|
||||||
|
|
||||||
damage = damage + (tool_capabilities.damage_groups[group] or 0)
|
|
||||||
* tmp * ((armor[group] or 0) / 100.0)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if weapon then
|
if weapon then
|
||||||
|
@ -141,9 +134,7 @@ mobs.mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
|
||||||
|
|
||||||
-- check for tool immunity or special damage
|
-- check for tool immunity or special damage
|
||||||
for n = 1, #self.immune_to do
|
for n = 1, #self.immune_to do
|
||||||
|
|
||||||
if self.immune_to[n][1] == weapon:get_name() then
|
if self.immune_to[n][1] == weapon:get_name() then
|
||||||
|
|
||||||
damage = self.immune_to[n][2] or 0
|
damage = self.immune_to[n][2] or 0
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
|
@ -155,21 +146,14 @@ mobs.mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if use_cmi then
|
|
||||||
|
|
||||||
local cancel = cmi.notify_punch(self.object, hitter, tflp, tool_capabilities, dir, damage)
|
|
||||||
|
|
||||||
if cancel then return end
|
|
||||||
end
|
|
||||||
|
|
||||||
if tool_capabilities then
|
if tool_capabilities then
|
||||||
punch_interval = tool_capabilities.full_punch_interval or 1.4
|
punch_interval = tool_capabilities.full_punch_interval or 1.4
|
||||||
end
|
end
|
||||||
|
|
||||||
-- add weapon wear manually
|
-- add weapon wear manually
|
||||||
-- Required because we have custom health handling ("health" property)
|
-- Required because we have custom health handling ("health" property)
|
||||||
if minetest_is_creative_enabled("") ~= true
|
--minetest_is_creative_enabled("") ~= true --removed for now
|
||||||
and tool_capabilities then
|
if tool_capabilities then
|
||||||
if tool_capabilities.punch_attack_uses then
|
if tool_capabilities.punch_attack_uses then
|
||||||
-- Without this delay, the wear does not work. Quite hacky ...
|
-- Without this delay, the wear does not work. Quite hacky ...
|
||||||
minetest_after(0, function(name)
|
minetest_after(0, function(name)
|
||||||
|
@ -207,65 +191,73 @@ mobs.mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
|
||||||
}, true)
|
}, true)
|
||||||
end
|
end
|
||||||
|
|
||||||
damage_effect(self, damage)
|
--damage_effect(self, damage)
|
||||||
|
|
||||||
-- do damage
|
-- do damage
|
||||||
self.health = self.health - damage
|
self.health = self.health - damage
|
||||||
|
|
||||||
-- skip future functions if dead, except alerting others
|
-- skip future functions if dead, except alerting others
|
||||||
if check_for_death(self, "hit", {type = "punch", puncher = hitter}) then
|
--if check_for_death(self, "hit", {type = "punch", puncher = hitter}) then
|
||||||
die = true
|
-- die = true
|
||||||
|
--end
|
||||||
|
|
||||||
|
-- knock back effect
|
||||||
|
local velocity = self.object:get_velocity()
|
||||||
|
|
||||||
|
--2d direction
|
||||||
|
local pos1 = self.object:get_pos()
|
||||||
|
pos1.y = 0
|
||||||
|
local pos2 = hitter:get_pos()
|
||||||
|
pos2.y = 0
|
||||||
|
|
||||||
|
local dir = vector.direction(pos2,pos1)
|
||||||
|
|
||||||
|
local up = 3
|
||||||
|
|
||||||
|
-- if already in air then dont go up anymore when hit
|
||||||
|
if velocity.y ~= 0 then
|
||||||
|
up = 0
|
||||||
end
|
end
|
||||||
|
|
||||||
-- knock back effect (only on full punch)
|
|
||||||
if not die
|
|
||||||
and self.knock_back
|
|
||||||
and tflp >= punch_interval then
|
|
||||||
|
|
||||||
local v = self.object:get_velocity()
|
--0.75 for perfect distance to not be too easy, and not be too hard
|
||||||
local r = 1.4 - math_min(punch_interval, 1.4)
|
local multiplier = 0.75
|
||||||
local kb = r * 2.0
|
|
||||||
local up = 2
|
|
||||||
|
|
||||||
-- if already in air then dont go up anymore when hit
|
-- check if tool already has specific knockback value
|
||||||
if v.y ~= 0
|
local knockback_enchant = mcl_enchanting.get_enchantment(hitter:get_wielded_item(), "knockback")
|
||||||
or self.fly then
|
if knockback_enchant and knockback_enchant > 0 then
|
||||||
up = 0
|
multiplier = knockback_enchant + 1 --(starts from 1, 1 would be no change)
|
||||||
end
|
|
||||||
|
|
||||||
-- direction error check
|
|
||||||
dir = dir or {x = 0, y = 0, z = 0}
|
|
||||||
|
|
||||||
-- check if tool already has specific knockback value
|
|
||||||
if tool_capabilities.damage_groups["knockback"] then
|
|
||||||
kb = tool_capabilities.damage_groups["knockback"]
|
|
||||||
else
|
|
||||||
kb = kb * 1.5
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
local luaentity
|
|
||||||
if hitter then
|
|
||||||
luaentity = hitter:get_luaentity()
|
|
||||||
end
|
|
||||||
if hitter and is_player then
|
|
||||||
local wielditem = hitter:get_wielded_item()
|
|
||||||
kb = kb + 3 * mcl_enchanting.get_enchantment(wielditem, "knockback")
|
|
||||||
elseif luaentity and luaentity._knockback then
|
|
||||||
kb = kb + luaentity._knockback
|
|
||||||
end
|
|
||||||
|
|
||||||
self.object:set_velocity({
|
|
||||||
x = dir.x * kb,
|
|
||||||
y = dir.y * kb + up * 2,
|
|
||||||
z = dir.z * kb
|
|
||||||
})
|
|
||||||
|
|
||||||
self.pause_timer = 0.25
|
|
||||||
end
|
end
|
||||||
end -- END if damage
|
|
||||||
|
|
||||||
|
local luaentity
|
||||||
|
|
||||||
|
--[[ --why does this multiply it again???
|
||||||
|
if hitter then
|
||||||
|
luaentity = hitter:get_luaentity()
|
||||||
|
end
|
||||||
|
if hitter and is_player then
|
||||||
|
local wielditem = hitter:get_wielded_item()
|
||||||
|
kb = kb + 3 * mcl_enchanting.get_enchantment(wielditem, "knockback")
|
||||||
|
elseif luaentity and luaentity._knockback then
|
||||||
|
kb = kb + luaentity._knockback
|
||||||
|
end
|
||||||
|
]]--
|
||||||
|
|
||||||
|
dir = vector_multiply(dir,multiplier)
|
||||||
|
|
||||||
|
dir.y = up
|
||||||
|
|
||||||
|
--add velocity breaks momentum - use set velocity
|
||||||
|
self.object:set_velocity(dir)
|
||||||
|
|
||||||
|
--0.4 seconds until you can hurt the mob again
|
||||||
|
self.pause_timer = 0.4
|
||||||
|
end
|
||||||
|
-- END if damage
|
||||||
|
|
||||||
-- if skittish then run away
|
-- if skittish then run away
|
||||||
|
--[[
|
||||||
if not die and self.runaway == true and self.state ~= "flop" then
|
if not die and self.runaway == true and self.state ~= "flop" then
|
||||||
|
|
||||||
local lp = hitter:get_pos()
|
local lp = hitter:get_pos()
|
||||||
|
@ -288,54 +280,6 @@ mobs.mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
|
||||||
self.following = nil
|
self.following = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
local name = hitter:get_player_name() or ""
|
|
||||||
|
|
||||||
-- attack puncher and call other mobs for help
|
|
||||||
if self.passive == false
|
|
||||||
and self.state ~= "flop"
|
|
||||||
and (self.child == false or self.type == "monster")
|
|
||||||
and hitter:get_player_name() ~= self.owner
|
|
||||||
and not mobs.invis[ name ] then
|
|
||||||
|
|
||||||
if not die then
|
|
||||||
-- attack whoever punched mob
|
|
||||||
self.state = ""
|
|
||||||
do_attack(self, hitter)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- alert others to the attack
|
|
||||||
local objs = minetest_get_objects_inside_radius(hitter:get_pos(), self.view_range)
|
|
||||||
local obj = nil
|
|
||||||
|
|
||||||
for n = 1, #objs do
|
|
||||||
|
|
||||||
obj = objs[n]:get_luaentity()
|
|
||||||
|
|
||||||
if obj then
|
|
||||||
|
|
||||||
-- only alert members of same mob or friends
|
|
||||||
if obj.group_attack
|
|
||||||
and obj.state ~= "attack"
|
|
||||||
and obj.owner ~= name then
|
|
||||||
if obj.name == self.name then
|
|
||||||
do_attack(obj, hitter)
|
|
||||||
elseif type(obj.group_attack) == "table" then
|
|
||||||
for i=1, #obj.group_attack do
|
|
||||||
if obj.name == obj.group_attack[i] then
|
|
||||||
do_attack(obj, hitter)
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- have owned mobs attack player threat
|
|
||||||
if obj.owner == name and obj.owner_loyal then
|
|
||||||
do_attack(obj, self.object)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
]]--
|
]]--
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue