From: Perttu Ahola Date: Thu, 29 Mar 2012 10:35:20 +0000 (+0300) Subject: Rework tool_capabilities a bit (maxwear->uses, scale dig time according to leveldiff) X-Git-Url: http://81.2.79.47:8989/gitweb/?a=commitdiff_plain;h=440e9cdbef19d154f134a85c7e2601f0aff63459;p=zefram%2Fminetest%2Fminetest_engine.git Rework tool_capabilities a bit (maxwear->uses, scale dig time according to leveldiff) --- diff --git a/doc/lua_api.txt b/doc/lua_api.txt index a8386406..c09a5815 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -255,8 +255,8 @@ Groups of items can define what kind of an item it is (eg. wool). Groups of nodes ---------------- -In addition to the general item things, whether a node is diggable and how -long it takes is defined by using groups. +In addition to the general item things, groups are used to define whether +a node is destroyable and how long it takes to destroy by a tool. Groups of entities ------------------- @@ -292,6 +292,7 @@ Special groups damage, and get weared out much faster, or not be able to get drops from destroyed nodes. - 0 is something that is directly accessible at the start of gameplay + - There is no upper limit - dig_immediate: (player can always pick up node without tool wear) - 2: node is removed without tool wear after 0.5 seconds or so (rail, sign) @@ -299,6 +300,7 @@ Special groups Known damage and digging time defining groups ---------------------------------------------- +Valid ratings for these are 0, 1, 2 and 3, unless otherwise stated. - crumbly: dirt, sand - cracky: tough but crackable stuff like stone. - snappy: something that can be cut using fine tools; eg. leaves, small @@ -334,59 +336,105 @@ Groups such as **crumbly**, **cracky** and **snappy** are used for this purpose. Rating is 1, 2 or 3. A higher rating for such a group implies faster digging time. -Also, the **level** group is used. +The **level** group is used to limit the toughness of nodes a tool can dig +and to scale the digging times / damage to a greater extent. + +^ PLEASE DO UNDERSTAND THIS, otherwise you cannot use the system to it's + full potential. Tools define their properties by a list of parameters for groups. They cannot dig other groups; thus it is important to use a standard bunch of groups to enable interaction with tools. -**Example definition of the digging capabilities of a tool:** +**Tools define:** + * Full punch interval + * Maximum drop level + * For an arbitrary list of groups: + * Uses (until the tool breaks) + * Maximum level (usually 0, 1, 2 or 3) + * Digging times + +**Full punch interval**: +When used as a weapon, the tool will do full damage if this time is spent +between punches. If eg. half the time is spent, the tool will do half +damage. + +**Maximum drop level** +Suggests the maximum level of node, when dug with the tool, that will drop +it's useful item. (eg. iron ore to drop a lump of iron). +- This is not automated; it is the responsibility of the node definition + to implement this + +**Uses** +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 +is multiplied by 3^leveldiff. +- uses=10, leveldiff=0 -> actual_uses=10 +- uses=10, leveldiff=1 -> actual_uses=30 +- uses=10, leveldiff=2 -> actual_uses=90 + +**Maximum level** +Tells what is the maximum level of a node of this group that the tool will +be able to dig. + +**Digging times** +List of digging times for different ratings of the group, for nodes of the +maximum level. + * For example, as a lua table, ''times={2=2.00, 3=0.70}''. This would + result the tool to be able to dig nodes that have a rating of 2 or 3 + for this group, and unable to dig the rating 1, which is the toughest. + Unless there is a matching group that enables digging otherwise. + * For entities, damage equals the amount of nodes dug in the time spent + between hits, with a maximum time of ''full_punch_interval''. + +Example definition of the capabilities of a tool +------------------------------------------------- tool_capabilities = { full_punch_interval=1.5, max_drop_level=1, groupcaps={ - crumbly={maxwear=0.01, maxlevel=2, times={[1]=0.80, [2]=0.60, [3]=0.40}} + crumbly={maxlevel=2, uses=20, times={[1]=1.60, [2]=1.20, [3]=0.80}} } } -**Tools define:** - * Full punch interval Maximum drop level For an arbitrary list of groups: - * Maximum level (usually 0, 1, 2 or 3) Maximum wear (0...1) Digging times - -**Full punch interval**: When used as a weapon, the tool will do full -damage if this time is spent between punches. If eg. half the time is -spent, the tool will do half damage. - -**Maximum drop level** suggests the maximum level of node, when dug with -the tool, that will drop it's useful item. (eg. iron ore to drop a lump of -iron). - -**Maximum level** tells what is the maximum level of a node of this group -that the tool will be able to dig. - -**Maximum wear** determines how much the tool wears out when it is used for -digging a node, of this group, of the maximum level. For lower leveled -tools, the wear is divided by //4// to the exponent //level difference//. -This means for a maximum wear of 0.1, a level difference 1 will result in -wear=0.1/4=0.025, and a level difference of 2 will result in -wear=0.1/(4*4)=0.00625. - -**Digging times** is basically a list of digging times for different -ratings of the group. It also determines the damage done to entities, based -on their "armor groups". - * For example, as a lua table, ''times={2=2.00, 3=0.70}''. This would - * result the tool to be able to dig nodes that have a rating of 2 or 3 - * for this group, and unable to dig the rating 1, which is the toughest. - * Unless there is a matching group that enables digging otherwise. For - * entities, damage equals the amount of nodes dug in the time spent - * between hits, with a maximum of ''full_punch_interval''. +This makes the tool be able to dig nodes that fullfill both of these: +- Have the **crumbly** group +- Have a **level** group less or equal to 2 + +Table of resulting digging times: +crumbly 0 1 2 3 4 <- level + -> 0 - - - - - + 1 0.80 1.60 1.60 - - + 2 0.60 1.20 1.20 - - + 3 0.40 0.80 0.80 - - + +level diff: 2 1 0 -1 -2 + +Table of resulting tool uses: + -> 0 - - - - - + 1 180 60 20 - - + 2 180 60 20 - - + 3 180 60 20 - - + +Notes: +- At crumbly=0, the node is not diggable. +- At crumbly=3, the level difference digging time divider kicks in and makes + easy nodes to be quickly breakable. +- At level > 2, the node is not diggable, because it's level > maxlevel Entity damage mechanism ------------------------ +Damage calculation: +- Take the time spent after the last hit +- Limit time to full_punch_interval +- Take the damage groups, assume a node has them +- Damage in HP is the amount of nodes destroyed in this time. + Client predicts damage based on damage groups. Because of this, it is able to give an immediate response when an entity is damaged or dies; the response is pre-defined somehow (eg. by defining a sprite animation) (not implemented; TODO). +- Currently a smoke puff will appear when an entity dies. The group **immortal** will completely disable normal damage. diff --git a/games/minimal/mods/default/init.lua b/games/minimal/mods/default/init.lua index 932e90de..b408e8cc 100644 --- a/games/minimal/mods/default/init.lua +++ b/games/minimal/mods/default/init.lua @@ -24,10 +24,10 @@ minetest.register_item(":", { full_punch_interval = 1.0, max_drop_level = 0, groupcaps = { - fleshy = {times={[2]=2.00, [3]=1.00}, maxwear=0, maxlevel=1}, - crumbly = {times={[3]=0.70}, maxwear=0, maxlevel=1}, - snappy = {times={[3]=0.40}, maxwear=0, maxlevel=1}, - oddly_breakable_by_hand = {times={[1]=3.50,[2]=2.00,[3]=0.70}, maxwear=0, maxlevel=3}, + fleshy = {times={[2]=2.00, [3]=1.00}, uses=0, maxlevel=1}, + crumbly = {times={[2]=3.00, [3]=0.70}, uses=0, maxlevel=1}, + snappy = {times={[3]=0.40}, uses=0, maxlevel=1}, + oddly_breakable_by_hand = {times={[1]=7.00,[2]=4.00,[3]=1.40}, uses=0, maxlevel=3}, } } }) @@ -38,7 +38,7 @@ minetest.register_tool("default:pick_wood", { tool_capabilities = { max_drop_level=0, groupcaps={ - cracky={times={[2]=1.50, [3]=0.80}, maxwear=0.1, maxlevel=1} + cracky={times={[2]=2.00, [3]=1.20}, uses=10, maxlevel=1} } }, }) @@ -48,7 +48,7 @@ minetest.register_tool("default:pick_stone", { tool_capabilities = { max_drop_level=0, groupcaps={ - cracky={times={[1]=1.50, [2]=0.80, [3]=0.60}, maxwear=0.05, maxlevel=1} + cracky={times={[1]=2.00, [2]=1.20, [3]=0.80}, uses=20, maxlevel=1} } }, }) @@ -58,7 +58,7 @@ minetest.register_tool("default:pick_steel", { tool_capabilities = { max_drop_level=1, groupcaps={ - cracky={times={[1]=1.00, [2]=0.60, [3]=0.40}, maxwear=0.1, maxlevel=2} + cracky={times={[1]=4.00, [2]=1.60, [3]=1.00}, uses=10, maxlevel=2} } }, }) @@ -69,9 +69,9 @@ minetest.register_tool("default:pick_mese", { full_punch_interval = 1.0, max_drop_level=3, groupcaps={ - cracky={times={[1]=0.2, [2]=0.2, [3]=0.2}, maxwear=0.05, maxlevel=3}, - crumbly={times={[1]=0.2, [2]=0.2, [3]=0.2}, maxwear=0.05, maxlevel=3}, - snappy={times={[1]=0.2, [2]=0.2, [3]=0.2}, maxwear=0.05, maxlevel=3} + cracky={times={[1]=2.0, [2]=1.0, [3]=0.5}, uses=20, maxlevel=3}, + crumbly={times={[1]=2.0, [2]=1.0, [3]=0.5}, uses=20, maxlevel=3}, + snappy={times={[1]=2.0, [2]=1.0, [3]=0.5}, uses=20, maxlevel=3} } }, }) @@ -81,7 +81,7 @@ minetest.register_tool("default:shovel_wood", { tool_capabilities = { max_drop_level=0, groupcaps={ - crumbly={times={[1]=1.50, [2]=0.80, [3]=0.50}, maxwear=0.1, maxlevel=1} + crumbly={times={[1]=2.00, [2]=0.80, [3]=0.50}, uses=10, maxlevel=1} } }, }) @@ -91,7 +91,7 @@ minetest.register_tool("default:shovel_stone", { tool_capabilities = { max_drop_level=0, groupcaps={ - crumbly={times={[1]=0.80, [2]=0.50, [3]=0.30}, maxwear=0.05, maxlevel=1} + crumbly={times={[1]=1.20, [2]=0.50, [3]=0.30}, uses=20, maxlevel=1} } }, }) @@ -101,7 +101,7 @@ minetest.register_tool("default:shovel_steel", { tool_capabilities = { max_drop_level=1, groupcaps={ - crumbly={times={[1]=0.50, [2]=0.35, [3]=0.30}, maxwear=0.1, maxlevel=2} + crumbly={times={[1]=1.00, [2]=0.70, [3]=0.60}, uses=10, maxlevel=2} } }, }) @@ -111,8 +111,8 @@ minetest.register_tool("default:axe_wood", { tool_capabilities = { max_drop_level=0, groupcaps={ - choppy={times={[2]=1.40, [3]=0.80}, maxwear=0.1, maxlevel=1}, - fleshy={times={[2]=1.50, [3]=0.80}, maxwear=0.1, maxlevel=1} + choppy={times={[2]=1.40, [3]=0.80}, uses=10, maxlevel=1}, + fleshy={times={[2]=1.50, [3]=0.80}, uses=10, maxlevel=1} } }, }) @@ -122,8 +122,8 @@ minetest.register_tool("default:axe_stone", { tool_capabilities = { max_drop_level=0, groupcaps={ - choppy={times={[1]=1.50, [2]=1.00, [3]=0.60}, maxwear=0.05, maxlevel=1}, - fleshy={times={[2]=1.30, [3]=0.70}, maxwear=0.05, maxlevel=1} + choppy={times={[1]=1.50, [2]=1.00, [3]=0.60}, uses=20, maxlevel=1}, + fleshy={times={[2]=1.30, [3]=0.70}, uses=20, maxlevel=1} } }, }) @@ -133,8 +133,8 @@ minetest.register_tool("default:axe_steel", { tool_capabilities = { max_drop_level=1, groupcaps={ - choppy={times={[1]=1.00, [2]=0.80, [3]=0.50}, maxwear=0.1, maxlevel=2}, - fleshy={times={[2]=1.10, [3]=0.60}, maxwear=0.03, maxlevel=1} + choppy={times={[1]=2.00, [2]=1.60, [3]=1.00}, uses=10, maxlevel=2}, + fleshy={times={[2]=1.10, [3]=0.60}, uses=40, maxlevel=1} } }, }) @@ -145,9 +145,9 @@ minetest.register_tool("default:sword_wood", { full_punch_interval = 1.0, max_drop_level=0, groupcaps={ - fleshy={times={[2]=1.10, [3]=0.60}, maxwear=0.1, maxlevel=1}, - snappy={times={[2]=1.00, [3]=0.50}, maxwear=0.1, maxlevel=1}, - choppy={times={[3]=1.00}, maxwear=0.05, maxlevel=0} + fleshy={times={[2]=1.10, [3]=0.60}, uses=10, maxlevel=1}, + snappy={times={[2]=1.00, [3]=0.50}, uses=10, maxlevel=1}, + choppy={times={[3]=1.00}, uses=20, maxlevel=0} } } }) @@ -158,9 +158,9 @@ minetest.register_tool("default:sword_stone", { full_punch_interval = 1.0, max_drop_level=0, groupcaps={ - fleshy={times={[2]=0.80, [3]=0.40}, maxwear=0.05, maxlevel=1}, - snappy={times={[2]=0.80, [3]=0.40}, maxwear=0.05, maxlevel=1}, - choppy={times={[3]=0.90}, maxwear=0.05, maxlevel=0} + fleshy={times={[2]=0.80, [3]=0.40}, uses=20, maxlevel=1}, + snappy={times={[2]=0.80, [3]=0.40}, uses=20, maxlevel=1}, + choppy={times={[3]=0.90}, uses=20, maxlevel=0} } } }) @@ -171,9 +171,9 @@ minetest.register_tool("default:sword_steel", { full_punch_interval = 1.0, max_drop_level=1, groupcaps={ - fleshy={times={[1]=1.00, [2]=0.40, [3]=0.20}, maxwear=0.1, maxlevel=2}, - snappy={times={[2]=0.70, [3]=0.30}, maxwear=0.03, maxlevel=1}, - choppy={times={[3]=0.70}, maxwear=0.03, maxlevel=0} + fleshy={times={[1]=2.00, [2]=0.80, [3]=0.40}, uses=10, maxlevel=2}, + snappy={times={[2]=0.70, [3]=0.30}, uses=40, maxlevel=1}, + choppy={times={[3]=0.70}, uses=40, maxlevel=0} } } }) @@ -962,7 +962,7 @@ minetest.register_node("default:mese", { description = "Mese", tile_images = {"default_mese.png"}, is_ground_content = true, - groups = {cracky=1}, + groups = {cracky=1,level=2}, sounds = default.node_sound_defaults(), }) diff --git a/src/scriptapi.cpp b/src/scriptapi.cpp index 38d681e9..863e2ba2 100644 --- a/src/scriptapi.cpp +++ b/src/scriptapi.cpp @@ -670,8 +670,19 @@ static ToolCapabilities read_tool_capabilities( // This will be created ToolGroupCap groupcap; // Read simple parameters - getfloatfield(L, table_groupcap, "maxwear", groupcap.maxwear); getintfield(L, table_groupcap, "maxlevel", groupcap.maxlevel); + getintfield(L, table_groupcap, "uses", groupcap.uses); + // DEPRECATED: maxwear + float maxwear = 0; + if(getfloatfield(L, table_groupcap, "maxwear", maxwear)){ + if(maxwear != 0) + groupcap.uses = 1.0/maxwear; + else + groupcap.uses = 0; + infostream<first; const ToolGroupCap *cap = &i->second; os<maxwear); - writeF1000(os, cap->maxlevel); + writeS16(os, cap->uses); + writeS16(os, cap->maxlevel); writeU32(os, cap->times.size()); for(std::map::const_iterator i = cap->times.begin(); i != cap->times.end(); i++){ @@ -48,7 +48,7 @@ void ToolCapabilities::serialize(std::ostream &os) const void ToolCapabilities::deSerialize(std::istream &is) { int version = readU8(is); - if(version != 0) throw SerializationError( + if(version != 1) throw SerializationError( "unsupported ToolCapabilities version"); full_punch_interval = readF1000(is); max_drop_level = readS16(is); @@ -57,8 +57,8 @@ void ToolCapabilities::deSerialize(std::istream &is) for(u32 i=0; i level && time_exists){ + if(cap.maxlevel >= level && time_exists){ result_diggable = true; - result_time = time; int leveldiff = cap.maxlevel - level; - result_wear = cap.maxwear / pow(4.0, (double)leveldiff); + result_time = time / MYMAX(1, leveldiff); + if(cap.uses != 0) + result_wear = 1.0 / cap.uses / pow(3.0, (double)leveldiff); + else + result_wear = 0; result_main_group = name; } } diff --git a/src/tool.h b/src/tool.h index a92a7729..32f1962d 100644 --- a/src/tool.h +++ b/src/tool.h @@ -29,12 +29,12 @@ with this program; if not, write to the Free Software Foundation, Inc., struct ToolGroupCap { std::map times; - float maxwear; int maxlevel; + int uses; ToolGroupCap(): - maxwear(0.05), - maxlevel(1) + maxlevel(1), + uses(20) {} bool getTime(int rating, float *time) const