mirror of
https://github.com/minetest/minetest.git
synced 2024-12-02 12:33:45 +01:00
Fix number of tool uses being off by 1..32767 (#11110)
This commit is contained in:
parent
38ba813c55
commit
6910c8d920
@ -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)
|
||||||
{}
|
{}
|
||||||
|
101
src/tool.cpp
101
src/tool.cpp
@ -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;
|
||||||
|
18
src/tool.h
18
src/tool.h
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user