Prevent collisions with entities until projectile is at least one node from where it started (to prevent always hitting yourself), modify mcl_bows.shoot_arrow() and mcl_bows_s.shoot_arrow_crossbow() to use vl_projectile.create(), fix projectiles damaging players
This commit is contained in:
parent
6d838e7fbd
commit
52946b3a26
|
@ -137,6 +137,8 @@ local arrow_entity = {
|
||||||
vl_projectile.raycast_collides_with_entities,
|
vl_projectile.raycast_collides_with_entities,
|
||||||
},
|
},
|
||||||
allow_punching = function(self, entity_def, projectile_def, object)
|
allow_punching = function(self, entity_def, projectile_def, object)
|
||||||
|
if not self._allow_punch then return false end
|
||||||
|
|
||||||
local lua = object:get_luaentity()
|
local lua = object:get_luaentity()
|
||||||
if lua and lua.name == "mobs_mc:rover" then return false end
|
if lua and lua.name == "mobs_mc:rover" then return false end
|
||||||
|
|
||||||
|
@ -145,7 +147,7 @@ local arrow_entity = {
|
||||||
sounds = {
|
sounds = {
|
||||||
on_entity_collision = function(self, _, _, _, obj)
|
on_entity_collision = function(self, _, _, _, obj)
|
||||||
if obj:is_player() then
|
if obj:is_player() then
|
||||||
return {{name="mcl_bows_hit_player", gain=0.1}, {to_player=self._shooter:get_player_name()}, true}
|
return {{name="mcl_bows_hit_player", gain=0.1}, {to_player=obj:get_player_name()}, true}
|
||||||
end
|
end
|
||||||
|
|
||||||
return {{name="mcl_bows_hit_other", gain=0.3}, {pos=self.object:get_pos(), max_hear_distance=16}, true}
|
return {{name="mcl_bows_hit_other", gain=0.3}, {pos=self.object:get_pos(), max_hear_distance=16}, true}
|
||||||
|
@ -223,13 +225,9 @@ local arrow_entity = {
|
||||||
local lua = obj:get_luaentity()
|
local lua = obj:get_luaentity()
|
||||||
|
|
||||||
-- Make sure collision is valid
|
-- Make sure collision is valid
|
||||||
if obj == self._shooter then
|
|
||||||
if self._time_in_air < 1.02 then return end
|
|
||||||
else
|
|
||||||
if not (is_player or (lua and (lua.is_mob or lua._hittable_by_projectile))) then
|
if not (is_player or (lua and (lua.is_mob or lua._hittable_by_projectile))) then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
if obj:get_hp() > 0 then
|
if obj:get_hp() > 0 then
|
||||||
-- Check if there is no solid node between arrow and object
|
-- Check if there is no solid node between arrow and object
|
||||||
|
@ -256,9 +254,10 @@ local arrow_entity = {
|
||||||
-- Achievement for hitting skeleton, wither skeleton or stray (TODO) with an arrow at least 50 meters away
|
-- Achievement for hitting skeleton, wither skeleton or stray (TODO) with an arrow at least 50 meters away
|
||||||
-- NOTE: Range has been reduced because mobs unload much earlier than that ... >_>
|
-- NOTE: Range has been reduced because mobs unload much earlier than that ... >_>
|
||||||
-- TODO: This achievement should be given for the kill, not just a hit
|
-- TODO: This achievement should be given for the kill, not just a hit
|
||||||
if self._shooter and self._shooter:is_player() and vector.distance(pos, self._startpos) >= 20 then
|
local shooter = self._vl_projectile.owner
|
||||||
|
if shooter and shooter:is_player() and vector.distance(pos, self._startpos) >= 20 then
|
||||||
if mod_awards and (entity_name == "mobs_mc:skeleton" or entity_name == "mobs_mc:stray" or entity_name == "mobs_mc:witherskeleton") then
|
if mod_awards and (entity_name == "mobs_mc:skeleton" or entity_name == "mobs_mc:stray" or entity_name == "mobs_mc:witherskeleton") then
|
||||||
awards.unlock(self._shooter:get_player_name(), "mcl:snipeSkeleton")
|
awards.unlock(shooter:get_player_name(), "mcl:snipeSkeleton")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -298,8 +297,9 @@ local arrow_entity = {
|
||||||
end
|
end
|
||||||
|
|
||||||
local pos = self.object:get_pos()
|
local pos = self.object:get_pos()
|
||||||
--local dpos = vector.round(vector.new(pos)) -- digital pos
|
if not self._start_pos or pos and vector.distance(self._start_pos, pos) > 1 then
|
||||||
--local node = minetest.get_node(dpos)
|
self._allow_punch = true
|
||||||
|
end
|
||||||
|
|
||||||
if self._stuck then
|
if self._stuck then
|
||||||
return stuck_arrow_on_step(self, dtime)
|
return stuck_arrow_on_step(self, dtime)
|
||||||
|
@ -357,9 +357,10 @@ local arrow_entity = {
|
||||||
out.stuckstarttime = minetest.get_gametime() - self._stucktimer
|
out.stuckstarttime = minetest.get_gametime() - self._stucktimer
|
||||||
end
|
end
|
||||||
|
|
||||||
if self._shooter and self._shooter:is_player() then
|
if self._owner then
|
||||||
out.shootername = self._shooter:get_player_name()
|
out._owner = self._owner:get_player_name()
|
||||||
end
|
end
|
||||||
|
|
||||||
return minetest.serialize(out)
|
return minetest.serialize(out)
|
||||||
end,
|
end,
|
||||||
on_activate = function(self, staticdata, dtime_s)
|
on_activate = function(self, staticdata, dtime_s)
|
||||||
|
@ -385,6 +386,11 @@ local arrow_entity = {
|
||||||
-- Perform a stuck recheck on the next step.
|
-- Perform a stuck recheck on the next step.
|
||||||
self._stuckrechecktimer = STUCK_RECHECK_TIME
|
self._stuckrechecktimer = STUCK_RECHECK_TIME
|
||||||
|
|
||||||
|
local vl_projectile_data = {}
|
||||||
|
if data._owner then
|
||||||
|
vl_projectile_data.owner = minetest.get_player_by_name(data._owner)
|
||||||
|
end
|
||||||
|
|
||||||
if data.shootername then
|
if data.shootername then
|
||||||
local shooter = minetest.get_player_by_name(data.shootername)
|
local shooter = minetest.get_player_by_name(data.shootername)
|
||||||
if shooter and shooter:is_player() then
|
if shooter and shooter:is_player() then
|
||||||
|
|
|
@ -37,13 +37,16 @@ mcl_fovapi.register_modifier({
|
||||||
})
|
})
|
||||||
|
|
||||||
function mcl_bows.shoot_arrow(arrow_item, pos, dir, yaw, shooter, power, damage, is_critical, bow_stack, collectable)
|
function mcl_bows.shoot_arrow(arrow_item, pos, dir, yaw, shooter, power, damage, is_critical, bow_stack, collectable)
|
||||||
local obj = minetest.add_entity(pos, "mcl_bows:arrow_entity")
|
power = power or BOW_MAX_SPEED
|
||||||
if power == nil then
|
damage = damage or 3
|
||||||
power = BOW_MAX_SPEED --19
|
|
||||||
end
|
local obj = vl_projectile.create("mcl_bows:arrow_entity", {
|
||||||
if damage == nil then
|
pos = pos,
|
||||||
damage = 3
|
dir = dir,
|
||||||
end
|
velocity = power,
|
||||||
|
owner = shooter,
|
||||||
|
})
|
||||||
|
|
||||||
local knockback
|
local knockback
|
||||||
if bow_stack then
|
if bow_stack then
|
||||||
local enchantments = mcl_enchanting.get_enchantments(bow_stack)
|
local enchantments = mcl_enchanting.get_enchantments(bow_stack)
|
||||||
|
@ -59,11 +62,7 @@ function mcl_bows.shoot_arrow(arrow_item, pos, dir, yaw, shooter, power, damage,
|
||||||
mcl_burning.set_on_fire(obj, math.huge)
|
mcl_burning.set_on_fire(obj, math.huge)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
obj:set_velocity({x=dir.x*power, y=dir.y*power, z=dir.z*power})
|
|
||||||
obj:set_acceleration({x=0, y=-GRAVITY, z=0})
|
|
||||||
obj:set_yaw(yaw-math.pi/2)
|
|
||||||
local le = obj:get_luaentity()
|
local le = obj:get_luaentity()
|
||||||
le._shooter = shooter
|
|
||||||
le._source_object = shooter
|
le._source_object = shooter
|
||||||
le._damage = damage
|
le._damage = damage
|
||||||
le._is_critical = is_critical
|
le._is_critical = is_critical
|
||||||
|
@ -77,10 +76,10 @@ function mcl_bows.shoot_arrow(arrow_item, pos, dir, yaw, shooter, power, damage,
|
||||||
end
|
end
|
||||||
minetest.sound_play("mcl_bows_bow_shoot", {pos=pos, max_hear_distance=16}, true)
|
minetest.sound_play("mcl_bows_bow_shoot", {pos=pos, max_hear_distance=16}, true)
|
||||||
if shooter and shooter:is_player() then
|
if shooter and shooter:is_player() then
|
||||||
if obj:get_luaentity().player == "" then
|
if le.player == "" then
|
||||||
obj:get_luaentity().player = shooter
|
le.player = shooter
|
||||||
end
|
end
|
||||||
obj:get_luaentity().node = shooter:get_inventory():get_stack("main", 1):get_name()
|
le.node = shooter:get_inventory():get_stack("main", 1):get_name()
|
||||||
end
|
end
|
||||||
return obj
|
return obj
|
||||||
end
|
end
|
||||||
|
|
|
@ -41,13 +41,15 @@ local bow_load = {}
|
||||||
local bow_index = {}
|
local bow_index = {}
|
||||||
|
|
||||||
function mcl_bows_s.shoot_arrow_crossbow(arrow_item, pos, dir, yaw, shooter, power, damage, is_critical, crossbow_stack, collectable)
|
function mcl_bows_s.shoot_arrow_crossbow(arrow_item, pos, dir, yaw, shooter, power, damage, is_critical, crossbow_stack, collectable)
|
||||||
local obj = minetest.add_entity({x=pos.x,y=pos.y,z=pos.z}, arrow_item.."_entity")
|
power = power or BOW_MAX_SPEED
|
||||||
if power == nil then
|
damage = damage or 3
|
||||||
power = BOW_MAX_SPEED --19
|
|
||||||
end
|
local obj = vl_projectile.create("mcl_bows:arrow_entity", {
|
||||||
if damage == nil then
|
pos = pos,
|
||||||
damage = 3
|
dir = dir,
|
||||||
end
|
velocity = power,
|
||||||
|
owner = shooter,
|
||||||
|
})
|
||||||
local knockback = 4.875
|
local knockback = 4.875
|
||||||
if crossbow_stack then
|
if crossbow_stack then
|
||||||
local enchantments = mcl_enchanting.get_enchantments(crossbow_stack)
|
local enchantments = mcl_enchanting.get_enchantments(crossbow_stack)
|
||||||
|
@ -57,17 +59,14 @@ function mcl_bows_s.shoot_arrow_crossbow(arrow_item, pos, dir, yaw, shooter, pow
|
||||||
obj:get_luaentity()._piercing = 0
|
obj:get_luaentity()._piercing = 0
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
obj:set_velocity({x=dir.x*power, y=dir.y*power, z=dir.z*power})
|
|
||||||
obj:set_acceleration({x=0, y=-GRAVITY, z=0})
|
|
||||||
obj:set_yaw(yaw-math.pi/2)
|
|
||||||
local le = obj:get_luaentity()
|
local le = obj:get_luaentity()
|
||||||
le._shooter = shooter
|
|
||||||
le._source_object = shooter
|
le._source_object = shooter
|
||||||
le._damage = damage
|
le._damage = damage
|
||||||
le._is_critical = is_critical
|
le._is_critical = is_critical
|
||||||
le._startpos = pos
|
le._startpos = pos
|
||||||
le._knockback = knockback
|
le._knockback = knockback
|
||||||
le._collectable = collectable
|
le._collectable = collectable
|
||||||
|
le._arrow_item = arrow_item
|
||||||
minetest.sound_play("mcl_bows_crossbow_shoot", {pos=pos, max_hear_distance=16}, true)
|
minetest.sound_play("mcl_bows_crossbow_shoot", {pos=pos, max_hear_distance=16}, true)
|
||||||
if shooter and shooter:is_player() then
|
if shooter and shooter:is_player() then
|
||||||
if obj:get_luaentity().player == "" then
|
if obj:get_luaentity().player == "" then
|
||||||
|
|
|
@ -3,6 +3,7 @@ vl_projectile = mod
|
||||||
|
|
||||||
local vl_physics_path = minetest.get_modpath("vl_physics")
|
local vl_physics_path = minetest.get_modpath("vl_physics")
|
||||||
|
|
||||||
|
local DEBUG = false
|
||||||
local YAW_OFFSET = -math.pi/2
|
local YAW_OFFSET = -math.pi/2
|
||||||
local GRAVITY = tonumber(minetest.settings:get("movement_gravity"))
|
local GRAVITY = tonumber(minetest.settings:get("movement_gravity"))
|
||||||
local enable_pvp = minetest.settings:get_bool("enable_pvp")
|
local enable_pvp = minetest.settings:get_bool("enable_pvp")
|
||||||
|
@ -49,7 +50,7 @@ function mod.projectile_physics(obj, entity_def, v, a)
|
||||||
-- Update projectile yaw to match velocity direction
|
-- Update projectile yaw to match velocity direction
|
||||||
if v and le and not le._stuck then
|
if v and le and not le._stuck then
|
||||||
local yaw = minetest.dir_to_yaw(v) + YAW_OFFSET
|
local yaw = minetest.dir_to_yaw(v) + YAW_OFFSET
|
||||||
local pitch = math.asin(vector.normalize(dir).y)
|
local pitch = math.asin(vector.normalize(v).y)
|
||||||
obj:set_rotation(vector.new(0,yaw,pitch))
|
obj:set_rotation(vector.new(0,yaw,pitch))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -232,6 +233,14 @@ function mod.collides_with_solids(self, dtime, entity_def, projectile_def)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function handle_entity_collision(self, entity_def, projectile_def, object)
|
local function handle_entity_collision(self, entity_def, projectile_def, object)
|
||||||
|
if DEBUG then
|
||||||
|
minetest.log("handle_enity_collision("..dump({
|
||||||
|
self = self,
|
||||||
|
entity_def = entity_def,
|
||||||
|
object = object,
|
||||||
|
luaentity = object:get_luaentity(),
|
||||||
|
})..")")
|
||||||
|
end
|
||||||
local pos = self.object:get_pos()
|
local pos = self.object:get_pos()
|
||||||
local dir = vector.normalize(self.object:get_velocity())
|
local dir = vector.normalize(self.object:get_velocity())
|
||||||
local self_vl_projectile = self._vl_projectile
|
local self_vl_projectile = self._vl_projectile
|
||||||
|
@ -254,11 +263,11 @@ local function handle_entity_collision(self, entity_def, projectile_def, object)
|
||||||
-- Apply damage
|
-- Apply damage
|
||||||
-- Note: Damage blocking for shields is handled in mcl_shields with an mcl_damage modifier
|
-- Note: Damage blocking for shields is handled in mcl_shields with an mcl_damage modifier
|
||||||
local do_damage = false
|
local do_damage = false
|
||||||
if object:is_player() and projectile_def.damanges_players and self_vl_projectile.owner ~= object:get_player_name() then
|
if object:is_player() and projectile_def.damages_players then
|
||||||
do_damage = true
|
do_damage = true
|
||||||
|
|
||||||
handle_player_sticking(self, entity_def, projectile_def, object)
|
handle_player_sticking(self, entity_def, projectile_def, object)
|
||||||
elseif object_lua and (object_lua.is_mob or object_lua._hittable_by_projectile) and self_vl_projectile.owner ~= object then
|
elseif object_lua and (object_lua.is_mob or object_lua._hittable_by_projectile) then
|
||||||
do_damage = true
|
do_damage = true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -308,7 +317,6 @@ function mod.collides_with_entities(self, dtime, entity_def, projectile_def)
|
||||||
local pos = self.object:get_pos()
|
local pos = self.object:get_pos()
|
||||||
|
|
||||||
local hit = nil
|
local hit = nil
|
||||||
local owner = self._vl_projectile.owner
|
|
||||||
|
|
||||||
local objects = minetest.get_objects_inside_radius(pos, 1.5)
|
local objects = minetest.get_objects_inside_radius(pos, 1.5)
|
||||||
for i = 1,#objects do
|
for i = 1,#objects do
|
||||||
|
@ -316,9 +324,9 @@ function mod.collides_with_entities(self, dtime, entity_def, projectile_def)
|
||||||
local entity = object:get_luaentity()
|
local entity = object:get_luaentity()
|
||||||
|
|
||||||
if entity and entity.name ~= self.object:get_luaentity().name then
|
if entity and entity.name ~= self.object:get_luaentity().name then
|
||||||
if object:is_player() and owner ~= object:get_player_name() then
|
if object:is_player() then
|
||||||
return handle_entity_collision(self, entity_def, projectile_def, object)
|
return handle_entity_collision(self, entity_def, projectile_def, object)
|
||||||
elseif (entity.is_mob or entity._hittable_by_projectile) and owner ~= object then
|
elseif (entity.is_mob or entity._hittable_by_projectile) then
|
||||||
return handle_entity_collision(self, entity_def, projectile_def, object)
|
return handle_entity_collision(self, entity_def, projectile_def, object)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -358,7 +366,7 @@ function mod.create(entity_id, options)
|
||||||
local a, v
|
local a, v
|
||||||
if options.dir then
|
if options.dir then
|
||||||
v = vector.multiply(options.dir, options.velocity or 0)
|
v = vector.multiply(options.dir, options.velocity or 0)
|
||||||
a = vector.multiply(v, -math.abs(options.drag))
|
a = vector.multiply(v, -math.abs(options.drag or 0))
|
||||||
else
|
else
|
||||||
a = vector.zero()
|
a = vector.zero()
|
||||||
v = a
|
v = a
|
||||||
|
@ -367,8 +375,8 @@ function mod.create(entity_id, options)
|
||||||
|
|
||||||
-- Update projectile parameters
|
-- Update projectile parameters
|
||||||
local luaentity = obj:get_luaentity()
|
local luaentity = obj:get_luaentity()
|
||||||
|
luaentity._owner = options.owner
|
||||||
luaentity._vl_projectile = {
|
luaentity._vl_projectile = {
|
||||||
owner = options.owner,
|
|
||||||
extra = options.extra,
|
extra = options.extra,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue