2017-07-26 19:35:56 +02:00
local mod_mcl_hunger = minetest.get_modpath ( " mcl_hunger " )
local mod_awards = minetest.get_modpath ( " awards " ) and minetest.get_modpath ( " mcl_achievements " )
2018-05-07 23:10:49 +02:00
minetest.register_craftitem ( " mcl_bows:arrow " , {
2015-06-29 19:55:56 +02:00
description = " Arrow " ,
2018-05-07 17:06:00 +02:00
_doc_items_longdesc = [ [ Arrows are ammunition for bows and dispensers .
An arrow fired from a bow has a regular damage of 1 - 9. At full charge , there ' s a 20% chance of a critical hit dealing 10 damage instead. An arrow fired from a dispenser always deals 3 damage.]],
_doc_items_usagehelp = " To use arrows as ammunition for a bow, just put them anywhere in your inventory, they will be used up automatically. To use arrows as ammunition for a dispenser, place them in the dispenser's inventory. " ,
2018-05-07 23:10:49 +02:00
inventory_image = " mcl_bows_arrow_inv.png " ,
2017-01-16 14:29:41 +01:00
groups = { ammo = 1 , ammo_bow = 1 } ,
2018-02-01 22:45:19 +01:00
_on_dispense = function ( itemstack , dispenserpos , droppos , dropnode , dropdir )
-- Shoot arrow
local shootpos = vector.add ( dispenserpos , vector.multiply ( dropdir , 0.51 ) )
local yaw = math.atan2 ( dropdir.z , dropdir.x ) - math.pi / 2
2018-05-07 23:10:49 +02:00
mcl_bows.shoot_arrow ( itemstack : get_name ( ) , shootpos , dropdir , yaw , nil , 19 , 3 )
2018-02-01 22:45:19 +01:00
end ,
2015-06-29 19:55:56 +02:00
} )
2018-05-07 23:10:49 +02:00
minetest.register_node ( " mcl_bows:arrow_box " , {
2015-06-29 19:55:56 +02:00
drawtype = " nodebox " ,
2017-01-04 22:36:51 +01:00
is_ground_content = false ,
2015-06-29 19:55:56 +02:00
node_box = {
type = " fixed " ,
fixed = {
-- Shaft
{ - 6.5 / 17 , - 1.5 / 17 , - 1.5 / 17 , 6.5 / 17 , 1.5 / 17 , 1.5 / 17 } ,
--Spitze
{ - 4.5 / 17 , 2.5 / 17 , 2.5 / 17 , - 3.5 / 17 , - 2.5 / 17 , - 2.5 / 17 } ,
{ - 8.5 / 17 , 0.5 / 17 , 0.5 / 17 , - 6.5 / 17 , - 0.5 / 17 , - 0.5 / 17 } ,
--Federn
{ 6.5 / 17 , 1.5 / 17 , 1.5 / 17 , 7.5 / 17 , 2.5 / 17 , 2.5 / 17 } ,
{ 7.5 / 17 , - 2.5 / 17 , 2.5 / 17 , 6.5 / 17 , - 1.5 / 17 , 1.5 / 17 } ,
{ 7.5 / 17 , 2.5 / 17 , - 2.5 / 17 , 6.5 / 17 , 1.5 / 17 , - 1.5 / 17 } ,
{ 6.5 / 17 , - 1.5 / 17 , - 1.5 / 17 , 7.5 / 17 , - 2.5 / 17 , - 2.5 / 17 } ,
{ 7.5 / 17 , 2.5 / 17 , 2.5 / 17 , 8.5 / 17 , 3.5 / 17 , 3.5 / 17 } ,
{ 8.5 / 17 , - 3.5 / 17 , 3.5 / 17 , 7.5 / 17 , - 2.5 / 17 , 2.5 / 17 } ,
{ 8.5 / 17 , 3.5 / 17 , - 3.5 / 17 , 7.5 / 17 , 2.5 / 17 , - 2.5 / 17 } ,
{ 7.5 / 17 , - 2.5 / 17 , - 2.5 / 17 , 8.5 / 17 , - 3.5 / 17 , - 3.5 / 17 } ,
}
} ,
2018-05-07 23:10:49 +02:00
tiles = { " mcl_bows_arrow.png^[transformFX " , " mcl_bows_arrow.png^[transformFX " , " mcl_bows_arrow_back.png " , " mcl_bows_arrow_front.png " , " mcl_bows_arrow.png " , " mcl_bows_arrow.png^[transformFX " } ,
2015-06-29 19:55:56 +02:00
groups = { not_in_creative_inventory = 1 } ,
} )
local THROWING_ARROW_ENTITY = {
physical = false ,
visual = " wielditem " ,
visual_size = { x = 0.4 , y = 0.4 } ,
2018-05-07 23:10:49 +02:00
textures = { " mcl_bows:arrow_box " } ,
2015-06-29 19:55:56 +02:00
collisionbox = { 0 , 0 , 0 , 0 , 0 , 0 } ,
2017-02-21 22:51:07 +01:00
_lastpos = { } ,
2017-03-06 01:02:30 +01:00
_startpos = nil ,
2017-02-21 22:51:07 +01:00
_damage = 1 , -- Damage on impact
_shooter = nil , -- ObjectRef of player or mob who shot it
2015-06-29 19:55:56 +02:00
}
THROWING_ARROW_ENTITY.on_step = function ( self , dtime )
local pos = self.object : getpos ( )
2017-01-11 18:21:46 +01:00
local node = minetest.get_node ( pos )
2015-06-29 19:55:56 +02:00
2017-05-27 00:27:56 +02:00
-- Check for object collision. Done every tick (hopefully this is not too stressing)
do
2017-05-26 23:10:18 +02:00
local objs = minetest.get_objects_inside_radius ( pos , 2 )
local closest_object
local closest_distance
local ok = false
-- Iterate through all objects and remember the closest attackable object
2015-06-29 19:55:56 +02:00
for k , obj in pairs ( objs ) do
2017-07-25 01:14:32 +02:00
-- Arrows can only damage players and mobs
if obj ~= self._shooter and obj : is_player ( ) then
ok = true
elseif obj : get_luaentity ( ) ~= nil then
if obj ~= self._shooter and obj : get_luaentity ( ) . _cmi_is_mob then
2017-05-26 23:10:18 +02:00
ok = true
end
end
if ok then
local dist = vector.distance ( pos , obj : getpos ( ) )
if not closest_object or not closest_distance then
closest_object = obj
closest_distance = dist
elseif dist < closest_distance then
closest_object = obj
closest_distance = dist
end
end
end
-- If an attackable object was found, we will damage the closest one only
if closest_object ~= nil then
local obj = closest_object
2017-07-25 01:14:32 +02:00
local is_player = obj : is_player ( )
local lua = obj : get_luaentity ( )
if obj ~= self._shooter and ( is_player or ( lua and lua._cmi_is_mob ) ) then
obj : punch ( self.object , 1.0 , {
full_punch_interval = 1.0 ,
damage_groups = { fleshy = self._damage } ,
} , nil )
2018-05-07 22:23:15 +02:00
if is_player then
if self._shooter and self._shooter : is_player ( ) then
-- “Ding” sound for hitting another player
2018-05-07 23:10:49 +02:00
minetest.sound_play ( { name = " mcl_bows_hit_player " , gain = 0.1 } , { to_player = self._shooter } )
2018-05-07 22:23:15 +02:00
end
if mod_mcl_hunger then
mcl_hunger.exhaust ( obj : get_player_name ( ) , mcl_hunger.EXHAUST_DAMAGE )
end
2017-07-25 01:14:32 +02:00
end
2017-03-06 01:02:30 +01:00
2017-07-25 01:14:32 +02:00
if lua then
local entity_name = lua.name
2017-03-06 01:02:30 +01:00
-- Achievement for hitting skeleton, wither skeleton or stray (TODO) with an arrow at least 50 meters away
2017-05-27 00:37:25 +02:00
-- NOTE: Range has been reduced because mobs unload much earlier than that ... >_>
2017-03-06 01:02:30 +01:00
-- TODO: This achievement should be given for the kill, not just a hit
2017-05-27 00:37:25 +02:00
if self._shooter and self._shooter : is_player ( ) and vector.distance ( pos , self._startpos ) >= 20 then
2017-07-26 19:35:56 +02:00
if mod_awards and ( entity_name == " mobs_mc:skeleton " or entity_name == " mobs_mc:stray " or entity_name == " mobs_mc:witherskeleton " ) then
2017-03-06 01:02:30 +01:00
awards.unlock ( self._shooter : get_player_name ( ) , " mcl:snipeSkeleton " )
end
end
2017-05-21 05:55:55 +02:00
end
2015-06-29 19:55:56 +02:00
self.object : remove ( )
end
end
end
2017-05-27 00:27:56 +02:00
-- Check for node collision
2017-02-21 22:51:07 +01:00
if self._lastpos . x ~= nil then
2017-01-26 19:05:25 +01:00
local def = minetest.registered_nodes [ node.name ]
if ( def and def.walkable ) or not def then
2017-08-09 16:17:00 +02:00
if not minetest.settings : get_bool ( " creative_mode " ) then
2018-05-07 23:10:49 +02:00
minetest.add_item ( self._lastpos , ' mcl_bows:arrow ' )
2017-05-26 23:34:25 +02:00
end
2015-06-29 19:55:56 +02:00
self.object : remove ( )
2018-05-08 00:02:07 +02:00
elseif ( def and def.liquidtype ~= " none " ) then
-- Slow down arrow in liquids
local v = def.liquid_viscosity
if not v then
v = 0
end
local vpenalty = math.max ( 0.1 , 0.98 - 0.1 * v )
local vel = self.object : get_velocity ( )
if math.abs ( vel.x ) > 0.001 then
vel.x = vel.x * vpenalty
end
if math.abs ( vel.z ) > 0.001 then
vel.z = vel.z * vpenalty
end
self.object : set_velocity ( vel )
2015-06-29 19:55:56 +02:00
end
end
2017-05-27 00:27:56 +02:00
-- Update internal variable
2017-02-21 22:51:07 +01:00
self._lastpos = { x = pos.x , y = pos.y , z = pos.z }
2015-06-29 19:55:56 +02:00
end
2018-05-07 23:10:49 +02:00
minetest.register_entity ( " mcl_bows:arrow_entity " , THROWING_ARROW_ENTITY )
2015-06-29 19:55:56 +02:00
2017-07-26 19:35:56 +02:00
if minetest.get_modpath ( " mcl_core " ) and minetest.get_modpath ( " mcl_mobitems " ) then
minetest.register_craft ( {
2018-05-07 23:10:49 +02:00
output = ' mcl_bows:arrow 4 ' ,
2017-07-26 19:35:56 +02:00
recipe = {
{ ' mcl_core:flint ' } ,
{ ' mcl_core:stick ' } ,
{ ' mcl_mobitems:feather ' }
}
} )
end