Fix number of tool uses being off by 1..32767 (#11110)

This commit is contained in:
Wuzzy 2021-10-31 22:33:33 +00:00 committed by GitHub
parent 38ba813c55
commit 6910c8d920
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 229 additions and 71 deletions

@ -613,7 +613,7 @@ function core.node_dig(pos, node, digger)
if wielded then if wielded then
local wdef = wielded:get_definition() local wdef = wielded:get_definition()
local tp = wielded:get_tool_capabilities() local tp = wielded:get_tool_capabilities()
local dp = core.get_dig_params(def and def.groups, tp) local dp = core.get_dig_params(def and def.groups, tp, wielded:get_wear())
if wdef and wdef.after_use then if wdef and wdef.after_use then
wielded = wdef.after_use(wielded, digger, node, dp) or wielded wielded = wdef.after_use(wielded, digger, node, dp) or wielded
else else

@ -1953,8 +1953,9 @@ to implement this.
### Uses (tools only) ### Uses (tools only)
Determines how many uses the tool has when it is used for digging a node, Determines how many uses the tool has when it is used for digging a node,
of this group, of the maximum level. For lower leveled nodes, the use count of this group, of the maximum level. The maximum supported number of
is multiplied by `3^leveldiff`. uses is 65535. The special number 0 is used for infinite uses.
For lower leveled nodes, the use count is multiplied by `3^leveldiff`.
`leveldiff` is the difference of the tool's `maxlevel` `groupcaps` and the `leveldiff` is the difference of the tool's `maxlevel` `groupcaps` and the
node's `level` group. The node cannot be dug if `leveldiff` is less than zero. node's `level` group. The node cannot be dug if `leveldiff` is less than zero.
@ -3475,8 +3476,8 @@ Helper functions
* `minetest.pointed_thing_to_face_pos(placer, pointed_thing)`: returns a * `minetest.pointed_thing_to_face_pos(placer, pointed_thing)`: returns a
position. position.
* returns the exact position on the surface of a pointed node * returns the exact position on the surface of a pointed node
* `minetest.get_dig_params(groups, tool_capabilities)`: Simulates an item * `minetest.get_dig_params(groups, tool_capabilities [, wear])`:
that digs a node. Simulates an item that digs a node.
Returns a table with the following fields: Returns a table with the following fields:
* `diggable`: `true` if node can be dug, `false` otherwise. * `diggable`: `true` if node can be dug, `false` otherwise.
* `time`: Time it would take to dig the node. * `time`: Time it would take to dig the node.
@ -3485,7 +3486,8 @@ Helper functions
Parameters: Parameters:
* `groups`: Table of the node groups of the node that would be dug * `groups`: Table of the node groups of the node that would be dug
* `tool_capabilities`: Tool capabilities table of the item * `tool_capabilities`: Tool capabilities table of the item
* `minetest.get_hit_params(groups, tool_capabilities [, time_from_last_punch])`: * `wear`: Amount of wear the tool starts with (default: 0)
* `minetest.get_hit_params(groups, tool_capabilities [, time_from_last_punch [, wear]])`:
Simulates an item that punches an object. Simulates an item that punches an object.
Returns a table with the following fields: Returns a table with the following fields:
* `hp`: How much damage the punch would cause. * `hp`: How much damage the punch would cause.
@ -3494,6 +3496,7 @@ Helper functions
* `groups`: Damage groups of the object * `groups`: Damage groups of the object
* `tool_capabilities`: Tool capabilities table of the item * `tool_capabilities`: Tool capabilities table of the item
* `time_from_last_punch`: time in seconds since last punch action * `time_from_last_punch`: time in seconds since last punch action
* `wear`: Amount of wear the item starts with (default: 0)

@ -16,11 +16,11 @@ Tool types:
Tool materials: Tool materials:
* Dirt: dig nodes of rating 3, one use only
* Wood: dig nodes of rating 3 * Wood: dig nodes of rating 3
* Stone: dig nodes of rating 3 or 2 * Stone: dig nodes of rating 3 or 2
* Steel: dig nodes of rating 3, 2 or 1 * Steel: dig nodes of rating 3, 2 or 1
* Mese: dig "everything" instantly * Mese: dig "everything" instantly
* n-Uses: can be used n times before breaking
]] ]]
-- The hand -- The hand
@ -92,20 +92,6 @@ minetest.register_tool("basetools:pick_mese", {
-- Pickaxes: Dig cracky -- Pickaxes: Dig cracky
-- --
-- This should break after only 1 use
minetest.register_tool("basetools:pick_dirt", {
description = "Dirt Pickaxe".."\n"..
"Digs cracky=3".."\n"..
"1 use only",
inventory_image = "basetools_dirtpick.png",
tool_capabilities = {
max_drop_level=0,
groupcaps={
cracky={times={[3]=2.00}, uses=1, maxlevel=0}
},
},
})
minetest.register_tool("basetools:pick_wood", { minetest.register_tool("basetools:pick_wood", {
description = "Wooden Pickaxe".."\n".. description = "Wooden Pickaxe".."\n"..
"Digs cracky=3", "Digs cracky=3",
@ -348,3 +334,31 @@ minetest.register_tool("basetools:dagger_steel", {
damage_groups = {fleshy=2}, damage_groups = {fleshy=2},
} }
}) })
-- Test tool uses and punch_attack_uses
local uses = { 1, 2, 3, 5, 10, 50, 100, 1000, 10000, 65535 }
for i=1, #uses do
local u = uses[i]
local color = string.format("#FF00%02X", math.floor(((i-1)/#uses) * 255))
minetest.register_tool("basetools:pick_uses_"..string.format("%05d", u), {
description = u.."-Uses Pickaxe".."\n"..
"Digs cracky=3",
inventory_image = "basetools_steelpick.png^[colorize:"..color..":127",
tool_capabilities = {
max_drop_level=0,
groupcaps={
cracky={times={[3]=0.1, [2]=0.2, [1]=0.3}, uses=u, maxlevel=0}
},
},
})
minetest.register_tool("basetools:sword_uses_"..string.format("%05d", u), {
description = u.."-Uses Sword".."\n"..
"Damage: fleshy=1",
inventory_image = "basetools_woodsword.png^[colorize:"..color..":127",
tool_capabilities = {
damage_groups = {fleshy=1},
punch_attack_uses = u,
},
})
end

Binary file not shown.

Before

Width:  |  Height:  |  Size: 307 B

@ -114,6 +114,59 @@ minetest.register_chatcommand("detach", {
end, end,
}) })
minetest.register_chatcommand("use_tool", {
params = "(dig <group> <leveldiff>) | (hit <damage_group> <time_from_last_punch>) [<uses>]",
description = "Apply tool wear a number of times, as if it were used for digging",
func = function(name, param)
local player = minetest.get_player_by_name(name)
if not player then
return false, "No player."
end
local mode, group, level, uses = string.match(param, "([a-z]+) ([a-z0-9]+) (-?%d+) (%d+)")
if not mode then
mode, group, level = string.match(param, "([a-z]+) ([a-z0-9]+) (-?%d+)")
uses = 1
end
if not mode or not group or not level then
return false
end
if mode ~= "dig" and mode ~= "hit" then
return false
end
local tool = player:get_wielded_item()
local caps = tool:get_tool_capabilities()
if not caps or tool:get_count() == 0 then
return false, "No tool in hand."
end
local actual_uses = 0
for u=1, uses do
local wear = tool:get_wear()
local dp
if mode == "dig" then
dp = minetest.get_dig_params({[group]=3, level=level}, caps, wear)
else
dp = minetest.get_hit_params({[group]=100}, caps, level, wear)
end
tool:add_wear(dp.wear)
actual_uses = actual_uses + 1
if tool:get_count() == 0 then
break
end
end
player:set_wielded_item(tool)
if tool:get_count() == 0 then
return true, string.format("Tool used %d time(s). "..
"The tool broke after %d use(s).", uses, actual_uses)
else
local wear = tool:get_wear()
return true, string.format("Tool used %d time(s). "..
"Final wear=%d", uses, wear)
end
end,
})
-- Use this to test waypoint capabilities -- Use this to test waypoint capabilities
minetest.register_chatcommand("test_waypoints", { minetest.register_chatcommand("test_waypoints", {
params = "[change_immediate]", params = "[change_immediate]",

@ -1870,7 +1870,8 @@ bool GenericCAO::directReportPunch(v3f dir, const ItemStack *punchitem,
m_armor_groups, m_armor_groups,
toolcap, toolcap,
punchitem, punchitem,
time_from_last_punch); time_from_last_punch,
punchitem->wear);
if(result.did_punch && result.damage != 0) if(result.did_punch && result.damage != 0)
{ {

@ -3619,7 +3619,8 @@ void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos,
// cheat detection. // cheat detection.
// Get digging parameters // Get digging parameters
DigParams params = getDigParams(nodedef_manager->get(n).groups, DigParams params = getDigParams(nodedef_manager->get(n).groups,
&selected_item.getToolCapabilities(itemdef_manager)); &selected_item.getToolCapabilities(itemdef_manager),
selected_item.wear);
// If can't dig, try hand // If can't dig, try hand
if (!params.diggable) { if (!params.diggable) {

@ -1119,8 +1119,8 @@ void Server::handleCommand_Interact(NetworkPacket *pkt)
float time_from_last_punch = float time_from_last_punch =
playersao->resetTimeFromLastPunch(); playersao->resetTimeFromLastPunch();
u16 wear = pointed_object->punch(dir, &toolcap, playersao, u32 wear = pointed_object->punch(dir, &toolcap, playersao,
time_from_last_punch); time_from_last_punch, tool_item.wear);
// Callback may have changed item, so get it again // Callback may have changed item, so get it again
playersao->getWieldedItem(&selected_item); playersao->getWieldedItem(&selected_item);
@ -1173,7 +1173,8 @@ void Server::handleCommand_Interact(NetworkPacket *pkt)
// Get diggability and expected digging time // Get diggability and expected digging time
DigParams params = getDigParams(m_nodedef->get(n).groups, DigParams params = getDigParams(m_nodedef->get(n).groups,
&selected_item.getToolCapabilities(m_itemdef)); &selected_item.getToolCapabilities(m_itemdef),
selected_item.wear);
// If can't dig, try hand // If can't dig, try hand
if (!params.diggable) { if (!params.diggable) {
params = getDigParams(m_nodedef->get(n).groups, params = getDigParams(m_nodedef->get(n).groups,

@ -174,7 +174,7 @@ int ObjectRef::l_punch(lua_State *L)
v3f dir = readParam<v3f>(L, 5, sao->getBasePosition() - puncher->getBasePosition()); v3f dir = readParam<v3f>(L, 5, sao->getBasePosition() - puncher->getBasePosition());
dir.normalize(); dir.normalize();
u16 wear = sao->punch(dir, &toolcap, puncher, time_from_last_punch); u32 wear = sao->punch(dir, &toolcap, puncher, time_from_last_punch);
lua_pushnumber(L, wear); lua_pushnumber(L, wear);
return 1; return 1;

@ -160,28 +160,33 @@ int ModApiUtil::l_write_json(lua_State *L)
return 1; return 1;
} }
// get_dig_params(groups, tool_capabilities) // get_dig_params(groups, tool_capabilities[, wear])
int ModApiUtil::l_get_dig_params(lua_State *L) int ModApiUtil::l_get_dig_params(lua_State *L)
{ {
NO_MAP_LOCK_REQUIRED; NO_MAP_LOCK_REQUIRED;
ItemGroupList groups; ItemGroupList groups;
read_groups(L, 1, groups); read_groups(L, 1, groups);
ToolCapabilities tp = read_tool_capabilities(L, 2); ToolCapabilities tp = read_tool_capabilities(L, 2);
push_dig_params(L, getDigParams(groups, &tp)); if (lua_isnoneornil(L, 3)) {
push_dig_params(L, getDigParams(groups, &tp));
} else {
u16 wear = readParam<int>(L, 3);
push_dig_params(L, getDigParams(groups, &tp, wear));
}
return 1; return 1;
} }
// get_hit_params(groups, tool_capabilities[, time_from_last_punch]) // get_hit_params(groups, tool_capabilities[, time_from_last_punch, [, wear]])
int ModApiUtil::l_get_hit_params(lua_State *L) int ModApiUtil::l_get_hit_params(lua_State *L)
{ {
NO_MAP_LOCK_REQUIRED; NO_MAP_LOCK_REQUIRED;
std::unordered_map<std::string, int> groups; std::unordered_map<std::string, int> groups;
read_groups(L, 1, groups); read_groups(L, 1, groups);
ToolCapabilities tp = read_tool_capabilities(L, 2); ToolCapabilities tp = read_tool_capabilities(L, 2);
if(lua_isnoneornil(L, 3)) float time_from_last_punch = readParam<float>(L, 3, 1000000);
push_hit_params(L, getHitParams(groups, &tp)); int wear = readParam<int>(L, 4, 0);
else push_hit_params(L, getHitParams(groups, &tp,
push_hit_params(L, getHitParams(groups, &tp, readParam<float>(L, 3))); time_from_last_punch, wear));
return 1; return 1;
} }

@ -50,10 +50,10 @@ private:
// write_json(data[, styled]) // write_json(data[, styled])
static int l_write_json(lua_State *L); static int l_write_json(lua_State *L);
// get_dig_params(groups, tool_capabilities[, time_from_last_punch]) // get_dig_params(groups, tool_capabilities[, wear])
static int l_get_dig_params(lua_State *L); static int l_get_dig_params(lua_State *L);
// get_hit_params(groups, tool_capabilities[, time_from_last_punch]) // get_hit_params(groups, tool_capabilities[, time_from_last_punch[, wear]])
static int l_get_hit_params(lua_State *L); static int l_get_hit_params(lua_State *L);
// check_password_entry(name, entry, password) // check_password_entry(name, entry, password)

@ -305,10 +305,11 @@ void LuaEntitySAO::getStaticData(std::string *result) const
*result = os.str(); *result = os.str();
} }
u16 LuaEntitySAO::punch(v3f dir, u32 LuaEntitySAO::punch(v3f dir,
const ToolCapabilities *toolcap, const ToolCapabilities *toolcap,
ServerActiveObject *puncher, ServerActiveObject *puncher,
float time_from_last_punch) float time_from_last_punch,
u16 initial_wear)
{ {
if (!m_registered) { if (!m_registered) {
// Delete unknown LuaEntities when punched // Delete unknown LuaEntities when punched
@ -326,7 +327,8 @@ u16 LuaEntitySAO::punch(v3f dir,
m_armor_groups, m_armor_groups,
toolcap, toolcap,
&tool_item, &tool_item,
time_from_last_punch); time_from_last_punch,
initial_wear);
bool damage_handled = m_env->getScriptIface()->luaentity_Punch(m_id, puncher, bool damage_handled = m_env->getScriptIface()->luaentity_Punch(m_id, puncher,
time_from_last_punch, toolcap, dir, result.did_punch ? result.damage : 0); time_from_last_punch, toolcap, dir, result.did_punch ? result.damage : 0);

@ -44,9 +44,10 @@ public:
bool isStaticAllowed() const { return m_prop.static_save; } bool isStaticAllowed() const { return m_prop.static_save; }
bool shouldUnload() const { return true; } bool shouldUnload() const { return true; }
void getStaticData(std::string *result) const; void getStaticData(std::string *result) const;
u16 punch(v3f dir, const ToolCapabilities *toolcap = nullptr, u32 punch(v3f dir, const ToolCapabilities *toolcap = nullptr,
ServerActiveObject *puncher = nullptr, ServerActiveObject *puncher = nullptr,
float time_from_last_punch = 1000000.0f); float time_from_last_punch = 1000000.0f,
u16 initial_wear = 0);
void rightClick(ServerActiveObject *clicker); void rightClick(ServerActiveObject *clicker);
void setPos(const v3f &pos); void setPos(const v3f &pos);
void moveTo(v3f pos, bool continuous); void moveTo(v3f pos, bool continuous);

@ -409,10 +409,11 @@ void PlayerSAO::setLookPitchAndSend(const float pitch)
m_env->getGameDef()->SendMovePlayer(m_peer_id); m_env->getGameDef()->SendMovePlayer(m_peer_id);
} }
u16 PlayerSAO::punch(v3f dir, u32 PlayerSAO::punch(v3f dir,
const ToolCapabilities *toolcap, const ToolCapabilities *toolcap,
ServerActiveObject *puncher, ServerActiveObject *puncher,
float time_from_last_punch) float time_from_last_punch,
u16 initial_wear)
{ {
if (!toolcap) if (!toolcap)
return 0; return 0;
@ -430,7 +431,7 @@ u16 PlayerSAO::punch(v3f dir,
s32 old_hp = getHP(); s32 old_hp = getHP();
HitParams hitparams = getHitParams(m_armor_groups, toolcap, HitParams hitparams = getHitParams(m_armor_groups, toolcap,
time_from_last_punch); time_from_last_punch, initial_wear);
PlayerSAO *playersao = m_player->getPlayerSAO(); PlayerSAO *playersao = m_player->getPlayerSAO();

@ -109,8 +109,8 @@ public:
Interaction interface Interaction interface
*/ */
u16 punch(v3f dir, const ToolCapabilities *toolcap, ServerActiveObject *puncher, u32 punch(v3f dir, const ToolCapabilities *toolcap, ServerActiveObject *puncher,
float time_from_last_punch); float time_from_last_punch, u16 initial_wear = 0);
void rightClick(ServerActiveObject *clicker); void rightClick(ServerActiveObject *clicker);
void setHP(s32 hp, const PlayerHPChangeReason &reason) override void setHP(s32 hp, const PlayerHPChangeReason &reason) override
{ {

@ -145,11 +145,12 @@ public:
virtual bool shouldUnload() const virtual bool shouldUnload() const
{ return true; } { return true; }
// Returns tool wear // Returns added tool wear
virtual u16 punch(v3f dir, virtual u32 punch(v3f dir,
const ToolCapabilities *toolcap = nullptr, const ToolCapabilities *toolcap = nullptr,
ServerActiveObject *puncher = nullptr, ServerActiveObject *puncher = nullptr,
float time_from_last_punch = 1000000.0f) float time_from_last_punch = 1000000.0f,
u16 initial_wear = 0)
{ return 0; } { return 0; }
virtual void rightClick(ServerActiveObject *clicker) virtual void rightClick(ServerActiveObject *clicker)
{} {}

@ -183,9 +183,74 @@ void ToolCapabilities::deserializeJson(std::istream &is)
} }
} }
DigParams getDigParams(const ItemGroupList &groups, static u32 calculateResultWear(const u32 uses, const u16 initial_wear)
const ToolCapabilities *tp)
{ {
if (uses == 0) {
// Trivial case: Infinite uses
return 0;
}
/* Finite uses. This is not trivial,
as the maximum wear is not neatly evenly divisible by
most possible uses numbers. For example, for 128
uses, the calculation of wear is trivial, as
65536 / 128 uses = 512 wear,
so the tool will get 512 wear 128 times in its lifetime.
But for a number like 130, this does not work:
65536 / 130 uses = 504.123... wear.
Since wear must be an integer, we will get
504*130 = 65520, which would lead to the wrong number
of uses.
Instead, we partition the "wear range" into blocks:
A block represents a single use and can be
of two possible sizes: normal and oversized.
A normal block is equal to floor(65536 / uses).
An oversized block is a normal block plus 1.
Then we determine how many oversized and normal
blocks we need and finally, whether we add
the normal wear or the oversized wear.
Example for 130 uses:
* Normal wear = 504
* Number of normal blocks = 114
* Oversized wear = 505
* Number of oversized blocks = 16
If we add everything together, we get:
114*504 + 16*505 = 65536
*/
u32 result_wear;
u32 wear_normal = ((U16_MAX+1) / uses);
// Will be non-zero if its not evenly divisible
u16 blocks_oversize = (U16_MAX+1) % uses;
// Whether to add one extra wear point in case
// of oversized wear.
u16 wear_extra = 0;
if (blocks_oversize > 0) {
u16 blocks_normal = uses - blocks_oversize;
/* When the wear has reached this value, we
know that wear_normal has been applied
for blocks_normal times, therefore,
only oversized blocks remain.
This also implies the raw tool wear number
increases a bit faster after this point,
but this should be barely noticable by the
player.
*/
u16 wear_extra_at = blocks_normal * wear_normal;
if (initial_wear >= wear_extra_at) {
wear_extra = 1;
}
}
result_wear = wear_normal + wear_extra;
return result_wear;
}
DigParams getDigParams(const ItemGroupList &groups,
const ToolCapabilities *tp,
const u16 initial_wear)
{
// Group dig_immediate defaults to fixed time and no wear // Group dig_immediate defaults to fixed time and no wear
if (tp->groupcaps.find("dig_immediate") == tp->groupcaps.cend()) { if (tp->groupcaps.find("dig_immediate") == tp->groupcaps.cend()) {
switch (itemgroup_get(groups, "dig_immediate")) { switch (itemgroup_get(groups, "dig_immediate")) {
@ -201,7 +266,7 @@ DigParams getDigParams(const ItemGroupList &groups,
// Values to be returned (with a bit of conversion) // Values to be returned (with a bit of conversion)
bool result_diggable = false; bool result_diggable = false;
float result_time = 0.0; float result_time = 0.0;
float result_wear = 0.0; u32 result_wear = 0;
std::string result_main_group; std::string result_main_group;
int level = itemgroup_get(groups, "level"); int level = itemgroup_get(groups, "level");
@ -224,20 +289,22 @@ DigParams getDigParams(const ItemGroupList &groups,
if (!result_diggable || time < result_time) { if (!result_diggable || time < result_time) {
result_time = time; result_time = time;
result_diggable = true; result_diggable = true;
if (cap.uses != 0) // The actual number of uses increases
result_wear = 1.0 / cap.uses / pow(3.0, leveldiff); // exponentially with leveldiff.
else // If the levels are equal, real_uses equals cap.uses.
result_wear = 0; u32 real_uses = cap.uses * pow(3.0, leveldiff);
real_uses = MYMIN(real_uses, U16_MAX);
result_wear = calculateResultWear(real_uses, initial_wear);
result_main_group = groupname; result_main_group = groupname;
} }
} }
u16 wear_i = U16_MAX * result_wear; return DigParams(result_diggable, result_time, result_wear, result_main_group);
return DigParams(result_diggable, result_time, wear_i, result_main_group);
} }
HitParams getHitParams(const ItemGroupList &armor_groups, HitParams getHitParams(const ItemGroupList &armor_groups,
const ToolCapabilities *tp, float time_from_last_punch) const ToolCapabilities *tp, float time_from_last_punch,
u16 initial_wear)
{ {
s16 damage = 0; s16 damage = 0;
float result_wear = 0.0f; float result_wear = 0.0f;
@ -249,10 +316,12 @@ HitParams getHitParams(const ItemGroupList &armor_groups,
damage += damageGroup.second * punch_interval_multiplier * armor / 100.0; damage += damageGroup.second * punch_interval_multiplier * armor / 100.0;
} }
if (tp->punch_attack_uses > 0) if (tp->punch_attack_uses > 0) {
result_wear = 1.0f / tp->punch_attack_uses * punch_interval_multiplier; result_wear = calculateResultWear(tp->punch_attack_uses, initial_wear);
result_wear *= punch_interval_multiplier;
}
u16 wear_i = U16_MAX * result_wear; u32 wear_i = (u32) result_wear;
return {damage, wear_i}; return {damage, wear_i};
} }
@ -266,7 +335,8 @@ PunchDamageResult getPunchDamage(
const ItemGroupList &armor_groups, const ItemGroupList &armor_groups,
const ToolCapabilities *toolcap, const ToolCapabilities *toolcap,
const ItemStack *punchitem, const ItemStack *punchitem,
float time_from_last_punch float time_from_last_punch,
u16 initial_wear
){ ){
bool do_hit = true; bool do_hit = true;
{ {
@ -286,7 +356,8 @@ PunchDamageResult getPunchDamage(
if(do_hit) if(do_hit)
{ {
HitParams hitparams = getHitParams(armor_groups, toolcap, HitParams hitparams = getHitParams(armor_groups, toolcap,
time_from_last_punch); time_from_last_punch,
punchitem->wear);
result.did_punch = true; result.did_punch = true;
result.wear = hitparams.wear; result.wear = hitparams.wear;
result.damage = hitparams.hp; result.damage = hitparams.hp;

@ -88,10 +88,10 @@ struct DigParams
// Digging time in seconds // Digging time in seconds
float time; float time;
// Caused wear // Caused wear
u16 wear; u32 wear; // u32 because wear could be 65536 (single-use tool)
std::string main_group; std::string main_group;
DigParams(bool a_diggable = false, float a_time = 0.0f, u16 a_wear = 0, DigParams(bool a_diggable = false, float a_time = 0.0f, u32 a_wear = 0,
const std::string &a_main_group = ""): const std::string &a_main_group = ""):
diggable(a_diggable), diggable(a_diggable),
time(a_time), time(a_time),
@ -101,21 +101,24 @@ struct DigParams
}; };
DigParams getDigParams(const ItemGroupList &groups, DigParams getDigParams(const ItemGroupList &groups,
const ToolCapabilities *tp); const ToolCapabilities *tp,
const u16 initial_wear = 0);
struct HitParams struct HitParams
{ {
s16 hp; s16 hp;
u16 wear; // Caused wear
u32 wear; // u32 because wear could be 65536 (single-use weapon)
HitParams(s16 hp_ = 0, u16 wear_ = 0): HitParams(s16 hp_ = 0, u32 wear_ = 0):
hp(hp_), hp(hp_),
wear(wear_) wear(wear_)
{} {}
}; };
HitParams getHitParams(const ItemGroupList &armor_groups, HitParams getHitParams(const ItemGroupList &armor_groups,
const ToolCapabilities *tp, float time_from_last_punch); const ToolCapabilities *tp, float time_from_last_punch,
u16 initial_wear = 0);
HitParams getHitParams(const ItemGroupList &armor_groups, HitParams getHitParams(const ItemGroupList &armor_groups,
const ToolCapabilities *tp); const ToolCapabilities *tp);
@ -135,7 +138,8 @@ PunchDamageResult getPunchDamage(
const ItemGroupList &armor_groups, const ItemGroupList &armor_groups,
const ToolCapabilities *toolcap, const ToolCapabilities *toolcap,
const ItemStack *punchitem, const ItemStack *punchitem,
float time_from_last_punch float time_from_last_punch,
u16 initial_wear = 0
); );
f32 getToolRange(const ItemDefinition &def_selected, const ItemDefinition &def_hand); f32 getToolRange(const ItemDefinition &def_selected, const ItemDefinition &def_hand);