mirror of
https://git.minetest.land/VoxeLibre/VoxeLibre.git
synced 2024-11-16 16:11:06 +01:00
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
ca8570e639
commit
c0ab6830fc
4 changed files with 58 additions and 46 deletions
|
@ -137,6 +137,8 @@ local arrow_entity = {
|
|||
vl_projectile.raycast_collides_with_entities,
|
||||
},
|
||||
allow_punching = function(self, entity_def, projectile_def, object)
|
||||
if not self._allow_punch then return false end
|
||||
|
||||
local lua = object:get_luaentity()
|
||||
if lua and lua.name == "mobs_mc:rover" then return false end
|
||||
|
||||
|
@ -145,7 +147,7 @@ local arrow_entity = {
|
|||
sounds = {
|
||||
on_entity_collision = function(self, _, _, _, obj)
|
||||
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
|
||||
|
||||
return {{name="mcl_bows_hit_other", gain=0.3}, {pos=self.object:get_pos(), max_hear_distance=16}, true}
|
||||
|
@ -223,12 +225,8 @@ local arrow_entity = {
|
|||
local lua = obj:get_luaentity()
|
||||
|
||||
-- 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
|
||||
return
|
||||
end
|
||||
if not (is_player or (lua and (lua.is_mob or lua._hittable_by_projectile))) then
|
||||
return
|
||||
end
|
||||
|
||||
if obj:get_hp() > 0 then
|
||||
|
@ -256,9 +254,10 @@ local arrow_entity = {
|
|||
-- 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 ... >_>
|
||||
-- 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
|
||||
awards.unlock(self._shooter:get_player_name(), "mcl:snipeSkeleton")
|
||||
awards.unlock(shooter:get_player_name(), "mcl:snipeSkeleton")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -298,8 +297,9 @@ local arrow_entity = {
|
|||
end
|
||||
|
||||
local pos = self.object:get_pos()
|
||||
--local dpos = vector.round(vector.new(pos)) -- digital pos
|
||||
--local node = minetest.get_node(dpos)
|
||||
if not self._start_pos or pos and vector.distance(self._start_pos, pos) > 1 then
|
||||
self._allow_punch = true
|
||||
end
|
||||
|
||||
if self._stuck then
|
||||
return stuck_arrow_on_step(self, dtime)
|
||||
|
@ -357,9 +357,10 @@ local arrow_entity = {
|
|||
out.stuckstarttime = minetest.get_gametime() - self._stucktimer
|
||||
end
|
||||
|
||||
if self._shooter and self._shooter:is_player() then
|
||||
out.shootername = self._shooter:get_player_name()
|
||||
if self._owner then
|
||||
out._owner = self._owner:get_player_name()
|
||||
end
|
||||
|
||||
return minetest.serialize(out)
|
||||
end,
|
||||
on_activate = function(self, staticdata, dtime_s)
|
||||
|
@ -385,6 +386,11 @@ local arrow_entity = {
|
|||
-- Perform a stuck recheck on the next step.
|
||||
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
|
||||
local shooter = minetest.get_player_by_name(data.shootername)
|
||||
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)
|
||||
local obj = minetest.add_entity(pos, "mcl_bows:arrow_entity")
|
||||
if power == nil then
|
||||
power = BOW_MAX_SPEED --19
|
||||
end
|
||||
if damage == nil then
|
||||
damage = 3
|
||||
end
|
||||
power = power or BOW_MAX_SPEED
|
||||
damage = damage or 3
|
||||
|
||||
local obj = vl_projectile.create("mcl_bows:arrow_entity", {
|
||||
pos = pos,
|
||||
dir = dir,
|
||||
velocity = power,
|
||||
owner = shooter,
|
||||
})
|
||||
|
||||
local knockback
|
||||
if bow_stack then
|
||||
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)
|
||||
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()
|
||||
le._shooter = shooter
|
||||
le._source_object = shooter
|
||||
le._damage = damage
|
||||
le._is_critical = is_critical
|
||||
|
@ -77,10 +76,10 @@ function mcl_bows.shoot_arrow(arrow_item, pos, dir, yaw, shooter, power, damage,
|
|||
end
|
||||
minetest.sound_play("mcl_bows_bow_shoot", {pos=pos, max_hear_distance=16}, true)
|
||||
if shooter and shooter:is_player() then
|
||||
if obj:get_luaentity().player == "" then
|
||||
obj:get_luaentity().player = shooter
|
||||
if le.player == "" then
|
||||
le.player = shooter
|
||||
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
|
||||
return obj
|
||||
end
|
||||
|
|
|
@ -41,13 +41,15 @@ local bow_load = {}
|
|||
local bow_index = {}
|
||||
|
||||
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")
|
||||
if power == nil then
|
||||
power = BOW_MAX_SPEED --19
|
||||
end
|
||||
if damage == nil then
|
||||
damage = 3
|
||||
end
|
||||
power = power or BOW_MAX_SPEED
|
||||
damage = damage or 3
|
||||
|
||||
local obj = vl_projectile.create("mcl_bows:arrow_entity", {
|
||||
pos = pos,
|
||||
dir = dir,
|
||||
velocity = power,
|
||||
owner = shooter,
|
||||
})
|
||||
local knockback = 4.875
|
||||
if crossbow_stack then
|
||||
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
|
||||
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()
|
||||
le._shooter = shooter
|
||||
le._source_object = shooter
|
||||
le._damage = damage
|
||||
le._is_critical = is_critical
|
||||
le._startpos = pos
|
||||
le._knockback = knockback
|
||||
le._collectable = collectable
|
||||
le._arrow_item = arrow_item
|
||||
minetest.sound_play("mcl_bows_crossbow_shoot", {pos=pos, max_hear_distance=16}, true)
|
||||
if shooter and shooter:is_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 DEBUG = false
|
||||
local YAW_OFFSET = -math.pi/2
|
||||
local GRAVITY = tonumber(minetest.settings:get("movement_gravity"))
|
||||
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
|
||||
if v and le and not le._stuck then
|
||||
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))
|
||||
end
|
||||
end
|
||||
|
@ -232,6 +233,14 @@ function mod.collides_with_solids(self, dtime, entity_def, projectile_def)
|
|||
end
|
||||
|
||||
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 dir = vector.normalize(self.object:get_velocity())
|
||||
local self_vl_projectile = self._vl_projectile
|
||||
|
@ -254,11 +263,11 @@ local function handle_entity_collision(self, entity_def, projectile_def, object)
|
|||
-- Apply damage
|
||||
-- Note: Damage blocking for shields is handled in mcl_shields with an mcl_damage modifier
|
||||
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
|
||||
|
||||
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
|
||||
end
|
||||
|
||||
|
@ -308,7 +317,6 @@ function mod.collides_with_entities(self, dtime, entity_def, projectile_def)
|
|||
local pos = self.object:get_pos()
|
||||
|
||||
local hit = nil
|
||||
local owner = self._vl_projectile.owner
|
||||
|
||||
local objects = minetest.get_objects_inside_radius(pos, 1.5)
|
||||
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()
|
||||
|
||||
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)
|
||||
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)
|
||||
end
|
||||
end
|
||||
|
@ -358,7 +366,7 @@ function mod.create(entity_id, options)
|
|||
local a, v
|
||||
if options.dir then
|
||||
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
|
||||
a = vector.zero()
|
||||
v = a
|
||||
|
@ -367,8 +375,8 @@ function mod.create(entity_id, options)
|
|||
|
||||
-- Update projectile parameters
|
||||
local luaentity = obj:get_luaentity()
|
||||
luaentity._owner = options.owner
|
||||
luaentity._vl_projectile = {
|
||||
owner = options.owner,
|
||||
extra = options.extra,
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue