From cf85317c7e0055babc63aabc0cee6f0fd6f3de30 Mon Sep 17 00:00:00 2001 From: tenplus1 Date: Sun, 9 May 2021 15:35:01 +0100 Subject: [PATCH] update to increase speed levels --- README.md | 37 ++++--- init.lua | 205 +++++++++++++++++++++-------------- locale/toolranks.en.tr | 11 ++ locale/toolranks.fr.tr | 11 ++ mod.conf | 2 - settingtypes.txt | 8 ++ sounds/toolranks_levelup.ogg | Bin 8712 -> 10632 bytes 7 files changed, 178 insertions(+), 96 deletions(-) create mode 100644 locale/toolranks.en.tr create mode 100644 locale/toolranks.fr.tr create mode 100644 settingtypes.txt diff --git a/README.md b/README.md index 43516ec..4f30c9f 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,27 @@ -# minetest-toolranks +# minetest-toolranks [toolranks] + Minetest tool ranks mod -## Original mod by lisacvuk -https://github.com/lisacvuk/minetest-toolranks - -Tool gains levels for digging nodes. Higher level tools take longer to -wear out. +Tools gain levels for digging nodes. Higher level tools dig faster and take longer to wear out. ## Are you a mod developer? -Does one of your mods add new tools? -If so, to support this mod, check if it is loaded with -```minetest.get_modpath("toolranks")``` -and then replace all after_use definitions with toolranks.new_afteruse. -Optionaly, you can also replace tools description with -```toolranks.create_description("Tool Name", 0, 1)``` -and then set original_description to your tools name. -### This is a fork -Yep, this is a simplified version of toolranks with lesser dependencies. +Does one of your mods add new tools? +If so, to support this mod, add this code to your mod, after your tool's code: + +```lua +if minetest.get_modpath("toolranks") then + minetest.override_item("mymod:mytool", { + original_description = "My Tool", + description = toolranks.create_description("My Tool"), + after_use = toolranks.new_afteruse + }) + end +end +``` + +Or alternatively, you can use the helper function: + +```lua +toolranks.add_tool("mymod:mytool") +``` diff --git a/init.lua b/init.lua index 64e0f6d..d05c733 100644 --- a/init.lua +++ b/init.lua @@ -1,5 +1,8 @@ +local S = minetest.get_translator("toolranks") + toolranks = { + colors = { grey = minetest.get_color_escape_sequence("#9d9d9d"), green = minetest.get_color_escape_sequence("#1eff00"), @@ -9,130 +12,174 @@ toolranks = { } -function toolranks.create_description(name, uses, level) - - return toolranks.colors.green .. (name or "") .. "\n" - .. toolranks.colors.gold .. "Level: " .. (level or 1) .. "\n" - .. toolranks.colors.grey .. "Used: " .. (uses or 0) .. " times" -end +local max_speed = tonumber(minetest.settings:get("toolranks_speed_multiplier")) or 1.5--2.0 +local max_use = tonumber(minetest.settings:get("toolranks_use_multiplier")) or 2.0 +local max_level = tonumber(minetest.settings:get("toolranks_levels")) or 10 +local level_digs = tonumber(minetest.settings:get("toolranks_level_digs")) or 500 +local level_multiplier = 1 / max_level function toolranks.get_level(uses) - if uses >= 3200 then - return 6 - elseif uses >= 2000 then - return 5 - elseif uses >= 1000 then - return 4 - elseif uses >= 400 then - return 3 - elseif uses >= 200 then - return 2 - else - return 1 + if type(uses) == "number" and uses > 0 then + return math.min(max_level, math.floor(uses / level_digs)) end + + return 0 +end + + +function toolranks.create_description(name, uses) + + local description = name + local newdesc = S( + "@1@2\n@3Level @4 @5\n@6@Node dug: @7", + toolranks.colors.green, + description, + toolranks.colors.gold, + toolranks.get_level(uses), + "", -- was tooltype + toolranks.colors.grey, + (type(uses) == "number" and uses or 0) + ) + + return newdesc end function toolranks.new_afteruse(itemstack, user, node, digparams) - -- Get tool metadata and number of times used + local pname = user:get_player_name() + + if not pname then return itemstack end -- player nil check + local itemmeta = itemstack:get_meta() local dugnodes = tonumber(itemmeta:get_string("dug")) or 0 - -- Only count nodes that spend the tool - if digparams.wear > 0 then + if digparams.wear > 0 then -- Only count nodes that spend the tool dugnodes = dugnodes + 1 itemmeta:set_string("dug", dugnodes) - else - return end - -- Get tool description and last level - local itemdef = itemstack:get_definition() - local itemdesc = itemdef.original_description or itemdef.description or "Tool" - local lastlevel = tonumber(itemmeta:get_string("lastlevel")) or 1 - local name = user:get_player_name() + if itemstack:get_wear() > 60135 then - -- Warn player when tool is almost broken - if itemstack:get_wear() > 60100 then - - minetest.chat_send_player(name, - toolranks.colors.gold .. "Your tool is almost broken!") + minetest.chat_send_player(pname, + toolranks.colors.gold .. S("Your tool is about to break!")) minetest.sound_play("default_tool_breaks", { - to_player = name, - gain = 1.0 + to_player = pname, + gain = 2.0, }) end + local itemdef = itemstack:get_definition() + local itemdesc = itemdef.original_description or "" + local lastlevel = tonumber(itemmeta:get_string("lastlevel")) or 0 local level = toolranks.get_level(dugnodes) - -- Alert player when tool has leveled up if lastlevel < level then - minetest.chat_send_player(name, "Your " - .. toolranks.colors.green .. itemdesc - .. toolranks.colors.white .. " just leveled up!") + local levelup_text = S( + "Your @1@2@3 just leveled up!", + toolranks.colors.green, + itemdesc, + toolranks.colors.white + ) + + minetest.chat_send_player(pname, levelup_text) minetest.sound_play("toolranks_levelup", { - to_player = name, - gain = 1.0 + to_player = pname, + gain = 2.0, }) - itemmeta:set_string("lastlevel", level) + -- Make tool better by modifying tool_capabilities (if defined) + if itemdef.tool_capabilities then + + local speed_multiplier = 1 + (level * level_multiplier * (max_speed - 1)) + local use_multiplier = 1 + (level * level_multiplier * (max_use - 1)) + local caps = table.copy(itemdef.tool_capabilities) + + caps.full_punch_interval = caps.full_punch_interval and + (caps.full_punch_interval / speed_multiplier) + + caps.punch_attack_uses = caps.punch_attack_uses and + (caps.punch_attack_uses * use_multiplier) + + for _,c in pairs(caps.groupcaps) do + + c.uses = c.uses * use_multiplier + + for i,t in ipairs(c.times) do + c.times[i] = t / speed_multiplier + end + end + + itemmeta:set_tool_capabilities(caps) + end end - -- Set new meta - itemmeta:set_string("description", - toolranks.create_description(itemdesc, dugnodes, level)) - + -- Old method for compatibility with tools without tool_capabilities defined local wear = digparams.wear - -- Set wear level - if level > 1 then - wear = digparams.wear * 4 / (4 + level) + if level > 0 and not itemdef.tool_capabilities then + + local use_multiplier = 1 + (level * level_multiplier * (max_use - 1)) + + wear = wear / use_multiplier end + itemmeta:set_string("lastlevel", level) + itemmeta:set_string("description", toolranks.create_description(itemdesc, dugnodes)) itemstack:add_wear(wear) return itemstack end --- Default tool list -local tools = { +-- Helper function +function toolranks.add_tool(name) - "default:sword_wood", "default:sword_stone", "default:sword_steel", - "default:sword_bronze", "default:sword_mese", "default:sword_diamond", + local desc = ItemStack(name):get_definition().description - "default:pick_wood", "default:pick_stone", "default:pick_steel", - "default:pick_bronze", "default:pick_mese", "default:pick_diamond", - - "default:axe_wood", "default:axe_stone", "default:axe_steel", - "default:axe_bronze", "default:axe_mese", "default:axe_diamond", - - "default:shovel_wood", "default:shovel_stone", "default:shovel_steel", - "default:shovel_bronze", "default:shovel_mese", "default:shovel_diamond" -} - - --- Loop through tool list and add new toolranks description -for n = 1, #tools do - - local name = tools[n] - local def = minetest.registered_tools[name] - local desc = def and def.description - - if desc then - - minetest.override_item(name, { - original_description = desc, - description = toolranks.create_description(desc), - after_use = toolranks.new_afteruse - }) - end + minetest.override_item(name, { + original_description = desc, + description = toolranks.create_description(desc), + after_use = toolranks.new_afteruse + }) end + + +-- Sword +toolranks.add_tool("default:sword_wood") +toolranks.add_tool("default:sword_stone") +toolranks.add_tool("default:sword_steel") +toolranks.add_tool("default:sword_bronze") +toolranks.add_tool("default:sword_mese") +toolranks.add_tool("default:sword_diamond") + +-- Pickaxe +toolranks.add_tool("default:pick_wood") +toolranks.add_tool("default:pick_stone") +toolranks.add_tool("default:pick_steel") +toolranks.add_tool("default:pick_bronze") +toolranks.add_tool("default:pick_mese") +toolranks.add_tool("default:pick_diamond") + +-- Axe +toolranks.add_tool("default:axe_wood") +toolranks.add_tool("default:axe_stone") +toolranks.add_tool("default:axe_steel") +toolranks.add_tool("default:axe_bronze") +toolranks.add_tool("default:axe_mese") +toolranks.add_tool("default:axe_diamond") + +-- Shovel +toolranks.add_tool("default:shovel_wood") +toolranks.add_tool("default:shovel_stone") +toolranks.add_tool("default:shovel_steel") +toolranks.add_tool("default:shovel_bronze") +toolranks.add_tool("default:shovel_mese") +toolranks.add_tool("default:shovel_diamond") diff --git a/locale/toolranks.en.tr b/locale/toolranks.en.tr new file mode 100644 index 0000000..9e6b7d8 --- /dev/null +++ b/locale/toolranks.en.tr @@ -0,0 +1,11 @@ +# textdomain: toolranks +@1@2@n@3Level @4 @5@n@6Node dug: @7=@1@2@n@3Level @4 @5@n@6Node dug: @7 +pickaxe=pickaxe +axe=axe +shovel=shovel +hoe=hoe +sword=sword +tool=tool +Most used tool is now a @1@2@3 owned by @4 with @5 uses.=Most used tool is now a @1@2@3 owned by @4 with @5 uses. +Your tool is about to break!=Your tool is about to break! +Your @1@2@3 just leveled up!=Your @1@2@3 just leveled up! diff --git a/locale/toolranks.fr.tr b/locale/toolranks.fr.tr new file mode 100644 index 0000000..2fbefcd --- /dev/null +++ b/locale/toolranks.fr.tr @@ -0,0 +1,11 @@ +# textdomain: toolranks +@1@2@n@3Level @4 @5@n@6Node dug: @7=@1@2@n@3@5 niveau @4@n@6Blocks minés : @7 +pickaxe=pioche +axe=hache +shovel=pelle +hoe=houe +sword=épée +tool=outil +Most used tool is now a @1@2@3 owned by @4 with @5 uses.=L’outil le plus utilisé est désormais @1@2@3 appartenant à @4 avec @5 utilisations. +Your tool is about to break!=Votre outil va se casser ! +Your @1@2@3 just leveled up!=Votre @1@2@3 a gagné un niveau ! diff --git a/mod.conf b/mod.conf index 5cc00b0..9b53588 100644 --- a/mod.conf +++ b/mod.conf @@ -1,4 +1,2 @@ name = toolranks depends = default -optional_depends = -description = Add ability to level up tools to make them last longer. diff --git a/settingtypes.txt b/settingtypes.txt new file mode 100644 index 0000000..5535a20 --- /dev/null +++ b/settingtypes.txt @@ -0,0 +1,8 @@ +# Number of tool levels +toolranks_levels (Levels) int 10 +# Number of nodes that need to be dug to reach the next tool level +toolranks_level_digs (Digs per level) int 500 +# Dig speed multiplier at maximum tool level (1.0 to disable) +toolranks_speed_multiplier (Dig speed multiplier) float 2.0 1.0 10.0 +# Durability multiplier at maximum tool level (1.0 to disable) +toolranks_use_multiplier (Durability multiplier) float 2.0 1.0 10.0 diff --git a/sounds/toolranks_levelup.ogg b/sounds/toolranks_levelup.ogg index 03b5b174d5c81fd2231f518af4be8c1877b73975..603f7dcefd57efc8b49ab9c5e51dc061442fe5bb 100644 GIT binary patch literal 10632 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 F{|gO)7oq?F literal 8712 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