diff --git a/README.md b/README.md index bae3f57..66b978b 100644 --- a/README.md +++ b/README.md @@ -97,6 +97,8 @@ groups: sword Cause mobs to drop more items. This value is not used in the engine; it is the responsibility of the game/mod code to implement this. +Supported: mobs_monster, mobs_animal + groups: sword #### Power diff --git a/init.lua b/init.lua index a4d4932..4d16b1b 100644 --- a/init.lua +++ b/init.lua @@ -7,18 +7,96 @@ local mod_start_time = minetest.get_us_time() dofile(path .. '/api.lua') dofile(path .. '/table.lua') +---Check if string X starts with string Y +---@param str string +---@param start string +---@return boolean +local function starts_with(str, start) + return str:sub(1, #start) == start +end + minetest.register_on_mods_loaded(function() + -- Tools override for name, tool_def in pairs(minetest.registered_tools) do if XEnchanting:has_tool_group(name) then XEnchanting:set_tool_enchantability(tool_def) end end + -- Ores override for _, def in pairs(minetest.registered_ores) do if not XEnchanting.registered_ores[def.ore] then XEnchanting.registered_ores[def.ore] = true end end + + -- Entities override + for name, def in pairs(minetest.registered_entities) do + if starts_with(name, 'mobs_animal:') + or starts_with(name, 'mobs_monster:') + then + if def.on_punch and def.drops then + local prev_on_punch = def.on_punch + + ---@param self table + ---@param puncher ObjectRef|nil + ---@param time_from_last_punch number|integer|nil + ---@param tool_capabilities ToolCapabilitiesDef|nil + ---@param dir Vector + ---@param damage number|integer + ---@return boolean|nil + def.on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir, damage) + if not self + or not self.object + or not self.object:get_luaentity() + or not puncher + or not tool_capabilities + then + return prev_on_punch(self, puncher, time_from_last_punch, tool_capabilities, dir, damage) + end + + local wield_stack = puncher:get_wielded_item() + local wield_stack_meta = wield_stack:get_meta() + local looting = wield_stack_meta:get_float('is_looting') + + if looting == 0 then + return prev_on_punch(self, puncher, time_from_last_punch, tool_capabilities, dir, damage) + end + + local pos = self.object:get_pos() + + prev_on_punch(self, puncher, time_from_last_punch, tool_capabilities, dir, damage) + + if self.health and self.health <= 0 then + local death_by_player = self.cause_of_death + and self.cause_of_death.puncher + and self.cause_of_death.puncher:is_player() + + if death_by_player and pos then + for _, drop in ipairs(def.drops) do + if math.random(1, 2) == 1 then + local drop_min = drop.min or 0 + local drop_max = drop.max or 0 + local count = math.random(drop_min, drop_max) + local stack = ItemStack({ + name = drop.name, + count = count + }) + local chance = math.random(1, tool_capabilities.max_drop_level) + + stack:set_count(stack:get_count() * chance) + + if stack:get_count() > 0 then + minetest.item_drop(stack, puncher, pos) + end + end + end + end + end + end + end + end + end end) minetest.register_on_joinplayer(function(player, last_login) @@ -99,7 +177,6 @@ minetest.register_on_player_hpchange(function(player, hp_change, reason) if (player:get_hp() + hp_change) <= 0 then -- Going to die local player_inv = player:get_inventory() --[[@as InvRef]] - local player_inventory_lists = { 'main', 'craft' } for _, list_name in ipairs(player_inventory_lists) do diff --git a/types/entity.type.lua b/types/entity.type.lua index bb2c9c3..37e8092 100644 --- a/types/entity.type.lua +++ b/types/entity.type.lua @@ -14,3 +14,4 @@ ---@field on_detach_child fun(self: table, child: ObjectRef): nil Function receive a "luaentity" table as `self`. `child`: an `ObjectRef` of the child that detaches ---@field on_detach fun(self: table, parent: ObjectRef|nil): nil Function receive a "luaentity" table as `self`. `parent`: an `ObjectRef` (can be `nil`) from where it got detached. This happens before the parent object is removed from the world. ---@field get_staticdata fun(self: table) Function receive a "luaentity" table as `self`. Should return a string that will be passed to `on_activate` when the object is instantiated the next time. +---@field drops table Custom for mob drops diff --git a/types/minetest.type.lua b/types/minetest.type.lua index 9e8919c..85db7dc 100644 --- a/types/minetest.type.lua +++ b/types/minetest.type.lua @@ -88,7 +88,7 @@ ---@field place_node fun(pos: Vector, node: SetNodeTable): nil Place node with the same effects that a player would cause ---@field add_particle fun(def: ParticleDef): nil ---@field registered_tools table Map of registered tool definitions, indexed by name ----@field registered_entities table Map of registered entity definitions, indexed by name +---@field registered_entities table Map of registered entity definitions, indexed by name ---@field has_feature fun(args: table | string): boolean | table returns `boolean, missing_features`, `arg`: string or table in format `{foo=true, bar=true}`, `missing_features`: `{foo=true, bar=true}` ---@field handle_node_drops fun(pos: Vector, drops: string[], digger: ObjectRef) `drops`: list of itemstrings. Handles drops from nodes after digging: Default action is to put them into digger's inventory. Can be overridden to get different functionality (e.g. dropping items on ground) ---@field register_on_dieplayer fun(func: fun(player: ObjectRef, reason?: string)): nil Called when a player dies. `reason`: a PlayerHPChangeReason table, see register_on_player_hpchange