From 000c16d2920aae65c43253c1cb3eb02f06919e63 Mon Sep 17 00:00:00 2001 From: upsilon Date: Wed, 21 Jun 2017 17:08:32 +0200 Subject: [PATCH] Extend throwing.register_bow, change params order --- README.md | 13 +++++++------ init.lua | 42 ++++++++++++++++++++++++++++-------------- registration.lua | 28 ++++++++++++++++------------ 3 files changed, 51 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 0ddff7a..e7df14b 100644 --- a/README.md +++ b/README.md @@ -39,11 +39,12 @@ Definition: definition table, containing: * texture (essential): texture of the bow, shown in inventory. * groups (optional): groups of the item. * uses: number of uses of the bow (default is 50). - * allow_shot (optional): function(player, itemstack): + * allow_shot (optional): function(player, itemstack, index): - player: the player using the bow - itemstack: the itemstack of the bow - should return true if the shot can be made, and false otherwise - - default for this is function(player, itemstack) return throwing.is_arrow(itemstack) end + - the default function checks that the arrow to be thrown is a registered arrow + - it can return a second return value, which is the new itemstack * throw_itself (optional): whether the bow should throw itself instead of the arrow next to it in the inventory. If present, allow_shot is ignored. Default is false. @@ -69,7 +70,7 @@ Definition: definition table, containing: * target (optional, defaulting to throwing.target_both): what the arrow is able to hit (throwing.target_node, throwing.target_object, throwing.target_both). * allow_protected (optional, defaulting to false): whether the arrow can be throw in a protected area * on_hit_sound (optional): sound played when the arrow hits a node or an object. - * on_hit(pos, last_pos, node, object, hitter, data, self) (optional but very useful): callback function: + * on_hit(self, pos, last_pos, node, object, hitter, data) (optional but very useful): callback function: - pos: the position of the hit node or object. - last_pos: the last air node where the arrow was - node and object: hit node or object. Either node or object is nil, depending @@ -79,15 +80,15 @@ Definition: definition table, containing: - self: the arrow entity table (it allows you to hack a lot!) - If it fails, it should return: false[, reason] - * on_throw(pos, thrower, next_index, data, self) (optional): callback function: on_throw: + * on_throw(self, pos, thrower, itemstack, index, data) (optional): callback function: on_throw: - pos: the position from where the arrow is throw (which a bit higher than the hitter position) - thrower: an ObjectRef to the thrower player - next_index: the index next to the arrow in the "main" inventory - data: a data table associated to the entity where you can store what you want - self: the arrow entity table - - If the arrow shouldn't be throw, it should return false. + - If the arrow shouldn't be thrown, it should return false. * on_throw_sound (optional, there is a default sound, specify "" for no sound): sound to be played when the arrow is throw - * on_hit_fails(pos, thrower, data, self) (optional): callback function called if the hit failed (e.g. because on_hit returned false or because the area was protected) + * on_hit_fails(self, pos, thrower, data) (optional): callback function called if the hit failed (e.g. because on_hit returned false or because the area was protected) ]] -- Example: diff --git a/init.lua b/init.lua index 523677b..87173cc 100644 --- a/init.lua +++ b/init.lua @@ -32,14 +32,17 @@ function throwing.spawn_arrow_entity(pos, arrow, player) end end -local function shoot_arrow(itemstack, player, throw_itself) +local function shoot_arrow(itemstack, player, throw_itself, new_stack) local inventory = player:get_inventory() - local arrow - if throw_itself then - arrow = player:get_wielded_item():get_name() - else - arrow = inventory:get_stack("main", player:get_wield_index()+1):get_name() + local index = player:get_wield_index() + if not throw_itself then + if index >= player:get_inventory():get_size("main") then + return false + end + index = index + 1 end + local arrow_stack = inventory:get_stack("main", index) + local arrow = arrow_stack:get_name() local playerpos = player:getpos() local pos = {x=playerpos.x,y=playerpos.y+1.5,z=playerpos.z} @@ -52,7 +55,7 @@ local function shoot_arrow(itemstack, player, throw_itself) end if luaentity.on_throw then - if luaentity.on_throw(pos, player, ((player:get_wield_index()+1) % inventory:get_size("main")) + 1, luaentity.data, luaentity) == false then + if luaentity:on_throw(pos, player, arrow_stack, index, luaentity.data) == false then obj:remove() return false end @@ -72,7 +75,13 @@ local function shoot_arrow(itemstack, player, throw_itself) end if not minetest.setting_getbool("creative_mode") then - inventory:remove_item("main", arrow) + if new_stack then + inventory:set_stack("main", index, new_stack) + else + local stack = inventory:get_stack("main", index) + stack:take_item() + inventory:set_stack("main", index, stack) + end end return true @@ -106,7 +115,7 @@ local function arrow_step(self, dtime) player:get_inventory():add_item("main", self.item) end if self.on_hit_fails then - self.on_hit_fails(pos, player, self.data, self) + self:on_hit_fails(pos, player, self.data) end end @@ -123,7 +132,7 @@ local function arrow_step(self, dtime) end if self.on_hit then - local ret, reason = self.on_hit(pos, self.last_pos, node, obj, player, self.data, self) + local ret, reason = self:on_hit(pos, self.last_pos, node, obj, player, self.data) if ret == false then if reason then logging(": on_hit function failed for reason: "..reason) @@ -310,7 +319,10 @@ function throwing.register_bow(name, def) end if not def.allow_shot then - def.allow_shot = function(player, itemstack) + def.allow_shot = function(player, itemstack, index) + if index >= player:get_inventory():get_size("main") and not def.throw_itself then + return false + end return throwing.is_arrow(itemstack) end end @@ -326,13 +338,15 @@ function throwing.register_bow(name, def) return end + local index = (def.throw_itself and user:get_wield_index()) or user:get_wield_index()+1 + local res, new_stack = def.allow_shot(user, user:get_inventory():get_stack("main", index), index) -- Throw itself? - if not def.throw_itself and not def.allow_shot(user, user:get_inventory():get_stack("main", user:get_wield_index()+1)) then - return itemstack + if not res then + return new_stack or itemstack end -- Shoot arrow - if shoot_arrow(itemstack, user, def.throw_itself) then + if shoot_arrow(itemstack, user, def.throw_itself, new_stack) then if not minetest.setting_getbool("creative_mode") then itemstack:add_wear(65535 / (def.uses or 50)) end diff --git a/registration.lua b/registration.lua index 867b1ea..44f91d1 100644 --- a/registration.lua +++ b/registration.lua @@ -59,7 +59,7 @@ if get_setting("arrow") then target = throwing.target_both, allow_protected = true, on_hit_sound = "throwing_arrow", - on_hit = function(pos, _, node, object, hitter) + on_hit = function(self, pos, _, node, object, hitter) if object then object:punch(hitter, 1, { full_punch_interval = 1, @@ -83,7 +83,7 @@ if get_setting("golden_arrow") then target = throwing.target_object, allow_protected = true, on_hit_sound = "throwing_arrow", - on_hit = function(pos, _, _, object, hitter) + on_hit = function(self, pos, _, _, object, hitter) object:punch(hitter, 1, { full_punch_interval = 1, damage_groups = {fleshy = 5} @@ -99,7 +99,7 @@ if get_setting("dig_arrow") then tiles = {"throwing_arrow_dig.png", "throwing_arrow_dig.png", "throwing_arrow_dig_back.png", "throwing_arrow_dig_front.png", "throwing_arrow_dig_2.png", "throwing_arrow_dig.png"}, target = throwing.target_node, on_hit_sound = "throwing_dig_arrow", - on_hit = function(pos, _, node, _, hitter) + on_hit = function(self, pos, _, node, _, hitter) return minetest.dig_node(pos) end }) @@ -110,7 +110,7 @@ if get_setting("dig_arrow_admin") then description = "Admin Dig Arrow", tiles = {"throwing_arrow_dig.png", "throwing_arrow_dig.png", "throwing_arrow_dig_back.png", "throwing_arrow_dig_front.png", "throwing_arrow_dig_2.png", "throwing_arrow_dig.png"}, target = throwing.target_node, - on_hit = function(pos, _, node, _, _) + on_hit = function(self, pos, _, node, _, _) minetest.remove_node(pos) end, groups = {not_in_creative_inventory = 1} @@ -124,7 +124,7 @@ if get_setting("teleport_arrow") then tiles = {"throwing_arrow_teleport.png", "throwing_arrow_teleport.png", "throwing_arrow_teleport_back.png", "throwing_arrow_teleport_front.png", "throwing_arrow_teleport_2.png", "throwing_arrow_teleport.png"}, allow_protected = true, on_hit_sound = "throwing_teleport_arrow", - on_hit = function(_, last_pos, _, _, hitter) + on_hit = function(self, _, last_pos, _, _, hitter) if minetest.get_node(last_pos).name ~= "air" then minetest.log("warning", "[throwing] BUG: node at last_pos was not air") return @@ -145,7 +145,7 @@ if get_setting("fire_arrow") then description = "Torch Arrow", tiles = {"throwing_arrow_fire.png", "throwing_arrow_fire.png", "throwing_arrow_fire_back.png", "throwing_arrow_fire_front.png", "throwing_arrow_fire_2.png", "throwing_arrow_fire.png"}, on_hit_sound = "default_place_node", - on_hit = function(pos, last_pos, _, _, hitter) + on_hit = function(self, pos, last_pos, _, _, hitter) if minetest.get_node(last_pos).name ~= "air" then minetest.log("warning", "[throwing] BUG: node at last_pos was not air") return @@ -173,7 +173,7 @@ if get_setting("build_arrow") then description = "Build Arrow", tiles = {"throwing_arrow_build.png", "throwing_arrow_build.png", "throwing_arrow_build_back.png", "throwing_arrow_build_front.png", "throwing_arrow_build_2.png", "throwing_arrow_build.png"}, on_hit_sound = "throwing_build_arrow", - on_hit = function(_, last_pos, _, _, hitter) + on_hit = function(self, _, last_pos, _, _, hitter) if minetest.get_node(last_pos).name ~= "air" then minetest.log("warning", "[throwing] BUG: node at last_pos was not air") return @@ -196,12 +196,16 @@ if get_setting("drop_arrow") then tiles = {"throwing_arrow_drop.png", "throwing_arrow_drop.png", "throwing_arrow_drop_back.png", "throwing_arrow_drop_front.png", "throwing_arrow_drop_2.png", "throwing_arrow_drop.png"}, on_hit_sound = "throwing_build_arrow", allow_protected = true, - on_throw = function(_, thrower, next_index, data) - data.itemstack = thrower:get_inventory():get_stack("main", next_index) - data.index = next_index - thrower:get_inventory():set_stack("main", next_index, nil) + on_throw = function(self, _, thrower, _, index, data) + local inventory = thrower:get_inventory() + if index >= inventory:get_size("main") or inventory:get_stack("main", index+1):get_name() == "" then + return false, "nothing to drop" + end + data.itemstack = inventory:get_stack("main", index+1) + data.index = index+1 + thrower:get_inventory():set_stack("main", index+1, nil) end, - on_hit = function(_, last_pos, _, _, hitter, data) + on_hit = function(self, _, last_pos, _, _, hitter, data) minetest.item_drop(ItemStack(data.itemstack), hitter, last_pos) end, on_hit_fails = function(_, thrower, data)