diff --git a/README.md b/README.md index 044f998..c620d50 100644 --- a/README.md +++ b/README.md @@ -40,22 +40,28 @@ Groups: optional groups. throwing.register_bow("bow_stone", "default:cobble", "Stone Bow", "throwing_bow_stone.png") -function throwing.register_arrow(name, itemcraft, craft_quantity, description, tiles, on_hit_sound, on_hit[, groups]) +function throwing.register_arrow(name, itemcraft, craft_quantity, description, tiles, on_hit_sound, on_hit[, on_throw[, groups]]) --[[ Name: Arrow name (in second part of the itemstring). Itemcraft: item used to craft the arrow (nil if uncraftable). Craft_quantity: quantity of arrows in the craft output. Tiles: tiles of the arrow. On_hit_sound: sound played when the arrow hits a node or an object (nil if no sound). -On_hit: callback function: on_hit(pos, last_pos, node, object, hitter) where: +On_hit: callback function: on_hit(pos, last_pos, node, object, hitter, self) where: * Pos: the position of the hitted node or object * Last_pos: the last air node where the arrow was (used by the build_arrow, for example) - * Node and object: hitted node or object. Either node or object is nil, depending - whether the arrow hitted a node or an object (you should always check for that). + * Node and object: hit node or object. Either node or object is nil, depending + whether the arrow hit a node or an object (you should always check for that). An object can be a player or a luaentity. - * Hitter: the ObjectRef of the player who throwed the arrow. + * Hitter: the ObjectRef of the player who threw the arrow. + * Self: the arrow entity table (it allows you to hack a lot!) * When it fails, it should return: false[, reason] +On_throw: option callback function: on_throw(pos, thrower, self) where: + * Pos: the position from where the arrow is throw (which a bit higher than the hitter position) + * Thrower: the ObjectRef of the thrower + * Self: the arrow entity table + * Should return false if the arrow should not be throw ]] -- Examples: diff --git a/init.lua b/init.lua index 3caa1a0..43404a0 100644 --- a/init.lua +++ b/init.lua @@ -8,13 +8,20 @@ throwing.modname = minetest.get_current_modname() local function shoot_arrow(itemstack, player) for _,arrow in ipairs(throwing.arrows) do if player:get_inventory():get_stack("main", player:get_wield_index()+1):get_name() == arrow then - if not minetest.setting_getbool("creative_mode") then - player:get_inventory():remove_item("main", arrow) - end local playerpos = player:getpos() - local obj = minetest.add_entity({x=playerpos.x,y=playerpos.y+1.5,z=playerpos.z}, arrow.."_entity") - local dir = player:get_look_dir() + local pos = {x=playerpos.x,y=playerpos.y+1.5,z=playerpos.z} + local obj = minetest.add_entity(pos, arrow.."_entity") + local luaentity = obj:get_luaentity() + luaentity.player = player:get_player_name() + + if luaentity.on_throw then + if luaentity.on_throw(pos, player, luaentity) == false then + return false + end + end + + local dir = player:get_look_dir() local velocity_factor = tonumber(minetest.setting_get("throwing.velocity_factor")) or 19 local horizontal_acceleration_factor = tonumber(minetest.setting_get("throwing.horizontal_acceleration_factor")) or -3 local vertical_acceleration = tonumber(minetest.setting_get("throwing.vertical_acceleration")) or -10 @@ -23,7 +30,11 @@ local function shoot_arrow(itemstack, player) obj:setacceleration({x=dir.x*horizontal_acceleration_factor, y=vertical_acceleration, z=dir.z*horizontal_acceleration_factor}) obj:setyaw(player:get_look_horizontal()-math.pi/2) minetest.sound_play("throwing_sound", {pos=playerpos, gain = 0.5}) - obj:get_luaentity().player = player:get_player_name() + + if not minetest.setting_getbool("creative_mode") then + player:get_inventory():remove_item("main", arrow) + end + return true end end @@ -73,7 +84,7 @@ local function arrow_step(self, dtime) return end - local ret, reason = self.on_hit(pos, self.last_pos, node, obj, player) + local ret, reason = self.on_hit(pos, self.last_pos, node, obj, player, self) if ret == false then if reason then logging(": on_hit function failed for reason: "..reason) @@ -132,8 +143,11 @@ on_hit(pos, last_pos, node, object, hitter) Either node or object is nil, depending whether the arrow collided with an object (luaentity or player) or with a node. No log message is needed in this function (a generic log message is automatically emitted), except on error or warning. Should return false or false, reason on failure. + +on_throw(pos, hitter) +Unlike on_hit, it is optional. ]] -function throwing.register_arrow(name, itemcraft, craft_quantity, description, tiles, on_hit_sound, on_hit, groups) +function throwing.register_arrow(name, itemcraft, craft_quantity, description, tiles, on_hit_sound, on_hit, on_throw, groups) table.insert(throwing.arrows, throwing.modname..":"..name) local _groups = {dig_immediate = 3} @@ -197,6 +211,7 @@ function throwing.register_arrow(name, itemcraft, craft_quantity, description, t collisionbox = {0, 0, 0, 0, 0, 0}, on_hit = on_hit, on_hit_sound = on_hit_sound, + on_throw = on_throw, node = throwing.modname..":"..name, player = "", on_step = arrow_step diff --git a/registration.lua b/registration.lua index 6003d19..b809819 100644 --- a/registration.lua +++ b/registration.lua @@ -61,7 +61,7 @@ if get_setting("dig_arrow_admin") then return end minetest.remove_node(pos) - end, {not_in_creative_inventory = 1}) + end, nil, {not_in_creative_inventory = 1}) end if get_setting("teleport_arrow") then