From 098ea0d10a181ea1bcc98d72766969b5c94cd945 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Wed, 27 Apr 2016 20:15:52 -0700 Subject: [PATCH] TNT: Allow mods to override entity physics. Introduces an `on_blast(luaobj, damage)` callback that mods can attach to an entity def. The function will get called with the damage that TNT would make. The function should return three values: bool do_damage, bool do_knockback, table drops do_damage allows the mod to tell the TNT code to perform damage on the entity for the mod. The mod code should not do anything with the entity HP. The entity should not be immortal. If false, then the entity will not be damaged by the TNT mod. do_knockback allows the mod to tell the TNT mod to perform an entity knockback effect. If false, no knockback effect is applied to the entity. the drops table is a list of items to drop. It may be nil. E.g. { "wool:red" }. I've documented both on_blast() API methods in game_api.txt. It is a better place than lua_api.txt. --- game_api.txt | 22 ++++++++++++++++++++++ mods/tnt/init.lua | 39 +++++++++++++++++++++++++++++---------- 2 files changed, 51 insertions(+), 10 deletions(-) diff --git a/game_api.txt b/game_api.txt index 02ee58e..8e621c8 100644 --- a/game_api.txt +++ b/game_api.txt @@ -258,6 +258,28 @@ parameter, and drops is not reinitialized so you can call it several times in a row to add more inventory items to it. +`on_blast` callbacks: + +Both nodedefs and entitydefs can provide an `on_blast()` callback + +`nodedef.on_blast(pos, intensity)` +^ Allow drop and node removal overriding +* `pos` - node position +* `intensity` - TNT explosion measure. larger or equal to 1.0 +^ Should return a list of drops (e.g. {"default:stone"}) +^ Should perform node removal itself. If callback exists in the nodedef +^ then the TNT code will not destroy this node. + +`entitydef.on_blast(luaobj, damage)` +^ Allow TNT effects on entities to be overridden +* `luaobj` - LuaEntityRef of the entity +* `damage` - suggested HP damage value +^ Should return a list of (bool do_damage, bool do_knockback, table drops) +* `do_damage` - if true then TNT mod wil damage the entity +* `do_knockback` - if true then TNT mod will knock the entity away +* `drops` - a list of drops, e.g. {"wool:red"} + + Screwdriver API --------------- diff --git a/mods/tnt/init.lua b/mods/tnt/init.lua index d61cbf1..d3efd7b 100644 --- a/mods/tnt/init.lua +++ b/mods/tnt/init.lua @@ -138,7 +138,7 @@ local function calc_velocity(pos1, pos2, old_vel, power) return vel end -local function entity_physics(pos, radius) +local function entity_physics(pos, radius, drops) local objs = minetest.get_objects_inside_radius(pos, radius) for _, obj in pairs(objs) do local obj_pos = obj:getpos() @@ -157,14 +157,31 @@ local function entity_physics(pos, radius) obj:set_hp(obj:get_hp() - damage) else - local obj_vel = obj:getvelocity() - obj:setvelocity(calc_velocity(pos, obj_pos, - obj_vel, radius * 10)) - if not obj:get_armor_groups().immortal then - obj:punch(obj, 1.0, { - full_punch_interval = 1.0, - damage_groups = {fleshy = damage}, - }, nil) + local do_damage = true + local do_knockback = true + local entity_drops = {} + local luaobj = obj:get_luaentity() + local objdef = minetest.registered_entities[luaobj.name] + + if objdef and objdef.on_blast then + do_damage, do_knockback, entity_drops = objdef.on_blast(luaobj, damage) + end + + if do_knockback then + local obj_vel = obj:getvelocity() + obj:setvelocity(calc_velocity(pos, obj_pos, + obj_vel, radius * 10)) + end + if do_damage then + if not obj:get_armor_groups().immortal then + obj:punch(obj, 1.0, { + full_punch_interval = 1.0, + damage_groups = {fleshy = damage}, + }, nil) + end + end + for _, item in ipairs(entity_drops) do + add_drop(drops, item) end end end @@ -303,7 +320,9 @@ function tnt.boom(pos, def) minetest.set_node(pos, {name = "tnt:boom"}) local drops = tnt_explode(pos, def.radius, def.ignore_protection, def.ignore_on_blast) - entity_physics(pos, def.damage_radius) + -- append entity drops + entity_physics(pos, def.damage_radius, drops) + if not def.disable_drops then eject_drops(drops, pos, def.radius) end