From 27c35f551d2ae24d8a94f71fcf204368f7ee36d6 Mon Sep 17 00:00:00 2001 From: Juraj Vajda Date: Mon, 14 Nov 2022 14:29:15 -0500 Subject: [PATCH] Add looting and make fortune drop more stuff, implement incompatible enchantments --- README.md | 12 +++++++- api.lua | 58 ++++++++++++++++++++++++++++++++------ init.lua | 56 ++++++++++++++++++++++++++++++------ types/minetest.type.lua | 1 + types/node.type.lua | 1 + types/table.type.lua | 1 + types/xenchanting.type.lua | 3 ++ 7 files changed, 115 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 1a82b71..bae3f57 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,9 @@ groups: sword #### Fortune -Increases the number and/or chances of specific item drops. This value is not used in the engine; it is the responsibility of the game/mod code to implement this. +Increases the number and/or chances of specific item drops. Works with groups: stone, soil, sand, snowy, slippery, tree, leaves and all registered ores. + +Incompatible: Silk Touch groups: pickaxe, shovel, axe @@ -75,6 +77,8 @@ groups: pickaxe, shovel, axe Causes certain blocks to drop themselves as items instead of their usual drops when mined. Mods can prevent this behaviour with adding group `{ no_silktouch = 1 }` to the nodes. +Incompatible: Fortune + groups: pickaxe, shovel, axe #### Curse of Vanishing @@ -89,6 +93,12 @@ Increases knockback (players only). groups: sword +#### Looting + +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. + +groups: sword + #### Power Increases arrow damage. diff --git a/api.lua b/api.lua index f2fddce..7917231 100644 --- a/api.lua +++ b/api.lua @@ -67,6 +67,25 @@ XEnchanting = { 'sword' } }, + looting = { + name = S('Looting'), + -- what level should be taken, `level = min/max values` + final_level_range = { + [1] = { 15, 65 }, + [2] = { 24, 74 }, + [3] = { 33, 83 } + }, + -- level definition, `level = number to add` + level_def = { + [1] = 1, + [2] = 2, + [3] = 3 + }, + weight = 2, + groups = { + 'sword' + } + }, fortune = { name = S('Fortune'), -- what level should be taken, `level = min/max values` @@ -86,7 +105,8 @@ XEnchanting = { 'pickaxe', 'shovel', 'axe' - } + }, + incompatible = { 'silk_touch' } }, unbreaking = { name = S('Unbreaking'), @@ -145,7 +165,8 @@ XEnchanting = { 'pickaxe', 'shovel', 'axe' - } + }, + incompatible = { 'fortune' } }, curse_of_vanishing = { name = S('Curse of Vanishing'), @@ -244,7 +265,8 @@ XEnchanting = { scroll_close = { { x = 45, y = 84 }, 80, 0, false }, scroll_open_idle = { { x = 41, y = 42 }, 0, 0, false }, scroll_closed_idle = { { x = 43, y = 44 }, 0, 0, false } - } + }, + registered_ores = {} } ---Merge two tables with key/value pair @@ -408,7 +430,7 @@ function XEnchanting.get_enchanted_tool_capabilities(self, tool_def, enchantment end -- Fortune - if enchantment.id == 'fortune' and tool_capabilities.max_drop_level then + if enchantment.id == 'fortune' or enchantment.id == 'looting' and tool_capabilities.max_drop_level then local old_max_drop_level = tool_capabilities.max_drop_level local new_max_drop_level = old_max_drop_level + enchantment.value @@ -610,7 +632,8 @@ function XEnchanting.get_enchantment_data(self, player, nr_of_bookshelfs, tool_d id = enchantment_name, value = enchantment_def.level_def[level], level = level, - secondary = enchantment_def.secondary + secondary = enchantment_def.secondary, + incompatible = enchantment_def.incompatible }) end end @@ -628,10 +651,11 @@ function XEnchanting.get_enchantment_data(self, player, nr_of_bookshelfs, tool_d total_weight = total_weight + self.enchantment_defs[enchantment.id].weight end - -- Pick a random integer in the half range [0; total_weight] as a number `rand_weight` + -- Pick a random integer in the half range [0; total_weight / 2] as a number `rand_weight` local rand_weight = math.random(0, total_weight / 2) -- local probability = (final_level + 1) / 50 local probability_level = final_level + ---@type Enchantment[] local possible_enchantments_excl_secodnary = {} for _, enchantment in pairs(possible_enchantments) do @@ -648,22 +672,40 @@ function XEnchanting.get_enchantment_data(self, player, nr_of_bookshelfs, tool_d local rand_ench = possible_enchantments[rand_ench_idx] if j == 1 then + -- First pick -- Dont add cursed/secondary enchantment as first pick rand_ench_idx = math.random(1, #possible_enchantments_excl_secodnary) rand_ench = possible_enchantments_excl_secodnary[rand_ench_idx] + table.insert(final_enchantments, rand_ench) + for idx, value in pairs(possible_enchantments) do if rand_ench.id == value.id then table.remove(possible_enchantments, idx) end + + -- remove incomaptible enchantments + if rand_ench.incompatible + and table.indexof(rand_ench.incompatible, value.id) ~= -1 + then + table.remove(possible_enchantments, idx) + end end - table.insert(final_enchantments, rand_ench) else local probability = (probability_level + 1) / 50 - table.remove(possible_enchantments, rand_ench_idx) table.insert(final_enchantments, rand_ench) + table.remove(possible_enchantments, rand_ench_idx) + + for idx, value in pairs(possible_enchantments) do + -- remove incomaptible enchantments + if rand_ench.incompatible + and table.indexof(rand_ench.incompatible, value.id) ~= -1 + then + table.remove(possible_enchantments, idx) + end + end -- With probability (`final_level` + 1) / 50, keep going. Otherwise, stop picking bonus enchantments. local rand_probability = math.random() diff --git a/init.lua b/init.lua index 0f734a2..f2192bd 100644 --- a/init.lua +++ b/init.lua @@ -13,6 +13,12 @@ minetest.register_on_mods_loaded(function() XEnchanting:set_tool_enchantability(tool_def) end end + + for _, def in pairs(minetest.registered_ores) do + if not XEnchanting.registered_ores[def.ore] then + XEnchanting.registered_ores[def.ore] = true + end + end end) minetest.register_on_joinplayer(function(player, last_login) @@ -27,7 +33,6 @@ minetest.register_on_leaveplayer(function(player, timed_out) XEnchanting.form_context[player:get_player_name()] = nil end) --- Silk Touch local old_handle_node_drops = minetest.handle_node_drops function minetest.handle_node_drops(pos, drops, digger) @@ -37,29 +42,64 @@ function minetest.handle_node_drops(pos, drops, digger) return old_handle_node_drops(pos, drops, digger) end + local node = minetest.get_node(pos) local wield_stack = digger:get_wielded_item() local wield_stack_meta = wield_stack:get_meta() - if wield_stack_meta:get_float('is_silk_touch') == 0 then + -- Fortune + local fortune = wield_stack_meta:get_float('is_fortune') + + if fortune > 0 then + local new_drops = {} + + for _, itemstring in ipairs(drops) do + if XEnchanting.registered_ores[node.name] + or minetest.get_item_group(node.name, 'stone') > 0 + or minetest.get_item_group(node.name, 'soil') > 0 + or minetest.get_item_group(node.name, 'sand') > 0 + or minetest.get_item_group(node.name, 'snowy') > 0 + or minetest.get_item_group(node.name, 'slippery') > 0 + or minetest.get_item_group(node.name, 'tree') > 0 + or minetest.get_item_group(node.name, 'leaves') > 0 + then + local tool_capabilities = wield_stack:get_tool_capabilities() + local stack = ItemStack(itemstring) + local chance = math.random(1, tool_capabilities.max_drop_level) + + stack:set_count(stack:get_count() * chance) + + if stack:get_count() > 0 then + table.insert(new_drops, stack) + end + end + end + + if #new_drops > 0 then + return old_handle_node_drops(pos, new_drops, digger) + end + return old_handle_node_drops(pos, drops, digger) end - local node = minetest.get_node(pos) + -- Silk Touch + local silk_touch = wield_stack_meta:get_float('is_silk_touch') - if minetest.get_item_group(node.name, 'no_silktouch') == 1 then - return old_handle_node_drops(pos, drops, digger) + if silk_touch > 0 + and minetest.get_item_group(node.name, 'no_silktouch') == 0 + then + -- drop raw item/node + return old_handle_node_drops(pos, { ItemStack(node.name) }, digger) end - -- drop raw item/node - return old_handle_node_drops(pos, { ItemStack(node.name) }, digger) + return old_handle_node_drops(pos, drops, digger) end minetest.register_on_player_hpchange(function(player, hp_change, reason) + -- Curse of Vanishing if (player:get_hp() + hp_change) <= 0 then -- Going to die local player_inv = player:get_inventory() --[[@as InvRef]] - -- Curse of Vanishing local player_inventory_lists = { 'main', 'craft' } for _, list_name in ipairs(player_inventory_lists) do diff --git a/types/minetest.type.lua b/types/minetest.type.lua index c7a5a8a..9e8919c 100644 --- a/types/minetest.type.lua +++ b/types/minetest.type.lua @@ -15,6 +15,7 @@ ---@field add_entity fun(pos: Vector, name: string, staticdata?: string): ObjectRef|nil Spawn Lua-defined entity at position. Returns `ObjectRef`, or `nil` if failed. ---@field get_node fun(pos: Vector): NodeDef Returns the node at the given position as table in the format `{name="node_name", param1=0, param2=0}`, returns `{name="ignore", param1=0, param2=0}` for unloaded areas. ---@field registered_nodes table Map of registered node definitions, indexed by name +---@field registered_ores table Map of registered ore definitions, indexed by name ---@field after fun(time: number|integer, func: fun(...), ...): JobTable Call the function `func` after `time` seconds, may be fractional. Optional: Variable number of arguments that are passed to `func`. ---@field sound_play fun(spec: SimpleSoundSpec|string, parameters: SoundParamDef, ephemeral?: boolean): any Returns a `handle`. Ephemeral sounds will not return a handle and can't be stopped or faded. It is recommend to use this for short sounds that happen in response to player actions (e.g. door closing). ---@field add_particlespawner fun(particlespawner_definition: ParticlespawnerDef): number|integer Add a `ParticleSpawner`, an object that spawns an amount of particles over `time` seconds. Returns an `id`, and -1 if adding didn't succeed. diff --git a/types/node.type.lua b/types/node.type.lua index 4c4111e..3b39076 100644 --- a/types/node.type.lua +++ b/types/node.type.lua @@ -27,6 +27,7 @@ ---@field on_destruct fun(pos: Vector) Node destructor; called before removing node. Not called for bulk node placement. default: nil ---@field on_blast fun(pos: Vector, intensity?: number): nil intensity: 1.0 = mid range of regular TNT. If defined, called when an explosion touches the node, instead of removing the node. ---@field on_timer fun(pos: Vector, elapsed: number): boolean | nil default: nil, called by NodeTimers, see minetest.get_node_timer and NodeTimerRef. elapsed is the total time passed since the timer was started. return true to run the timer for another cycle with the same timeout value. +---@field _next_state string Only for x_farming composter ---Textures of node; +Y, -Y, +X, -X, +Z, -Z. List can be shortened to needed length. ---@class NodeTilesDef diff --git a/types/table.type.lua b/types/table.type.lua index f8acf47..905f0af 100644 --- a/types/table.type.lua +++ b/types/table.type.lua @@ -6,3 +6,4 @@ ---Table helpers ---@class TableAbstract ---@field copy fun(table: table): table returns a deep copy of `table` +---@field indexof fun(list: table, value: any): number returns the smallest numerical index containing the value `val` in the table `list`. Non-numerical indices are ignored. If `val` could not be found, `-1` is returned. `list` must not have negative indices. diff --git a/types/xenchanting.type.lua b/types/xenchanting.type.lua index 37a03b6..0e17593 100644 --- a/types/xenchanting.type.lua +++ b/types/xenchanting.type.lua @@ -14,6 +14,7 @@ ---@field form_context table Additional form data for player. ---@field scroll_animations table Parameters for `ObjectRef` `set_animation` method ---@field player_seeds table +---@field registered_ores table Table with registered ores, `key` ore name ---Enchantment definition @@ -24,6 +25,7 @@ ---@field weight number Enchantment weight ---@field secondary boolean Will not appear in masked description and can be applied only as additional enchantment by probability chance. ---@field groups string[] | nil List of groups for items what are compatible with this enchantment. If `nil` then all groups are compatible. +---@field incompatible string[] | nil List of incompatible enchantments ---Form context @@ -41,6 +43,7 @@ ---@field value number Value of the enchantment based on level ---@field level number Level of the enchantment ---@field secondary boolean | nil Will not appear in masked description and can be applied only as additional enchantment by probability chance. +---@field incompatible string[] | nil List of incompatible enchantments ---@class EnchantmentDataSlot