New damage system, add damageGroups to ToolCapabilities, bump protocol version
authorPilzAdam <pilzadam@minetest.net>
Thu, 28 Mar 2013 20:40:44 +0000 (21:40 +0100)
committerPilzAdam <pilzadam@minetest.net>
Fri, 29 Mar 2013 19:14:09 +0000 (20:14 +0100)
doc/lua_api.txt
src/clientserver.h
src/content_sao.cpp
src/itemdef.cpp
src/itemdef.h
src/scriptapi_common.cpp
src/server.cpp
src/server.h
src/tool.cpp
src/tool.h

index 8ef92bdf3b6e509d20076dd8bda5d14c8337ab4d..42ca58239374928ea70246d1c2df335964c476dc 100644 (file)
@@ -471,9 +471,11 @@ a node is destroyable and how long it takes to destroy by a tool.
 Groups of entities
 -------------------
 For entities, groups are, as of now, used only for calculating damage.
+The rating is the percentage of damage caused by tools with this damage group.
+See "Entity damage mechanism".
 
-object.get_armor_groups() -> a group-rating table (eg. {fleshy=3})
-object.set_armor_groups({level=2, fleshy=2, cracky=2})
+object.get_armor_groups() -> a group-rating table (eg. {fleshy=100})
+object.set_armor_groups({fleshy=30, cracky=80})
 
 Groups of tools
 ----------------
@@ -522,7 +524,6 @@ 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
@@ -575,6 +576,7 @@ groups to enable interaction with tools.
     * Uses (until the tool breaks)
     * Maximum level (usually 0, 1, 2 or 3)
     * Digging times
+    * Damage groups
 
 **Full punch interval**:
 When used as a weapon, the tool will do full damage if this time is spent
@@ -606,8 +608,9 @@ maximum level.
     result in 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''.
+
+**Damage groups**
+List of damage for groups of entities. See "Entity damage mechanism".
 
 Example definition of the capabilities of a tool
 -------------------------------------------------
@@ -617,6 +620,7 @@ tool_capabilities = {
     groupcaps={
         crumbly={maxlevel=2, uses=20, times={[1]=1.60, [2]=1.20, [3]=0.80}}
     }
+    damage_groups = {fleshy=2},
 }
 
 This makes the tool be able to dig nodes that fullfill both of these:
@@ -647,10 +651,12 @@ Notes:
 Entity damage mechanism
 ------------------------
 Damage calculation:
-- Take the time spent after the last hit
-- Limit time to full_punch_interval
-- Take the damage groups and imagine a bunch of nodes that have them
-- Damage in HP is the amount of nodes destroyed in this time.
+damage = 0
+foreach group in cap.damage_groups:
+    damage += cap.damage_groups[group] * limit(actual_interval / cap.full_punch_interval, 0.0, 1.0)
+        * (object.armor_groups[group] / 100.0)
+        -- Where object.armor_groups[group] is 0 for inexisting values
+return damage
 
 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
@@ -1496,10 +1502,10 @@ Item definition (register_node, register_craftitem, register_tool)
         max_drop_level=0,
         groupcaps={
             -- For example:
-            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}
-        }
+        },
+        damage_groups = {groupname=damage},
     }
     node_placement_prediction = nil,
     ^ If nil and item is node, prediction is made automatically
index 535fc04d8a7f52d8d81b6797e35ead0cdd69a389..aba84fb311c0012f509b3dee30ff184c0d400fdf 100644 (file)
@@ -85,9 +85,11 @@ SharedBuffer<u8> makePacket_TOCLIENT_TIME_OF_DAY(u16 time, float time_speed);
                TOCLIENT_SPAWN_PARTICLE
                TOCLIENT_ADD_PARTICLESPAWNER
                TOCLIENT_DELETE_PARTICLESPAWNER
+       PROTOCOL_VERSION 18:
+               damageGroups added to ToolCapabilities
 */
 
-#define LATEST_PROTOCOL_VERSION 17
+#define LATEST_PROTOCOL_VERSION 18
 
 // Server's supported network protocol range
 #define SERVER_PROTOCOL_VERSION_MIN 13
index 468dfd218e4fe805bd73c12500880fa70c22dcec..ae08b4260385fb9b4f253b7ff81fc2dd9482094f 100644 (file)
@@ -381,8 +381,7 @@ LuaEntitySAO::LuaEntitySAO(ServerEnvironment *env, v3f pos,
        }
        
        // Initialize something to armor groups
-       m_armor_groups["fleshy"] = 3;
-       m_armor_groups["snappy"] = 2;
+       m_armor_groups["fleshy"] = 100;
 }
 
 LuaEntitySAO::~LuaEntitySAO()
@@ -942,8 +941,7 @@ PlayerSAO::PlayerSAO(ServerEnvironment *env_, Player *player_, u16 peer_id_,
        assert(m_peer_id != 0);
        setBasePosition(m_player->getPosition());
        m_inventory = &m_player->inventory;
-       m_armor_groups["choppy"] = 2;
-       m_armor_groups["fleshy"] = 3;
+       m_armor_groups["fleshy"] = 100;
 
        m_prop.hp_max = PLAYER_MAX_HP;
        m_prop.physical = false;
index 4bd4181f991f4f6c53adc2a19c64df229c5f2132..98d7ce0a8dce0dfe6808818441f02c5ebd8ac523 100644 (file)
@@ -111,7 +111,7 @@ void ItemDefinition::reset()
        node_placement_prediction = "";
 }
 
-void ItemDefinition::serialize(std::ostream &os) const
+void ItemDefinition::serialize(std::ostream &os, u16 protocol_version) const
 {
        writeU8(os, 1); // version
        writeU8(os, type);
@@ -126,7 +126,7 @@ void ItemDefinition::serialize(std::ostream &os) const
        std::string tool_capabilities_s = "";
        if(tool_capabilities){
                std::ostringstream tmp_os(std::ios::binary);
-               tool_capabilities->serialize(tmp_os);
+               tool_capabilities->serialize(tmp_os, protocol_version);
                tool_capabilities_s = tmp_os.str();
        }
        os<<serializeString(tool_capabilities_s);
@@ -547,7 +547,7 @@ public:
                        m_aliases[name] = convert_to;
                }
        }
-       void serialize(std::ostream &os)
+       void serialize(std::ostream &os, u16 protocol_version)
        {
                writeU8(os, 0); // version
                u16 count = m_item_definitions.size();
@@ -559,7 +559,7 @@ public:
                        ItemDefinition *def = i->second;
                        // Serialize ItemDefinition and write wrapped in a string
                        std::ostringstream tmp_os(std::ios::binary);
-                       def->serialize(tmp_os);
+                       def->serialize(tmp_os, protocol_version);
                        os<<serializeString(tmp_os.str());
                }
                writeU16(os, m_aliases.size());
index dd20ba353a403476de70da40d7431af6ab80ff1d..cbbe7e2adcf844ba35db37c9c582bf8f7ac07c61 100644 (file)
@@ -80,7 +80,7 @@ struct ItemDefinition
        ItemDefinition& operator=(const ItemDefinition &def);
        ~ItemDefinition();
        void reset();
-       void serialize(std::ostream &os) const;
+       void serialize(std::ostream &os, u16 protocol_version) const;
        void deSerialize(std::istream &is);
 private:
        void resetInitial();
@@ -109,7 +109,7 @@ public:
                IGameDef *gamedef) const=0;
 #endif
 
-       virtual void serialize(std::ostream &os)=0;
+       virtual void serialize(std::ostream &os, u16 protocol_version)=0;
 };
 
 class IWritableItemDefManager : public IItemDefManager
@@ -146,7 +146,7 @@ public:
        virtual void registerAlias(const std::string &name,
                        const std::string &convert_to)=0;
 
-       virtual void serialize(std::ostream &os)=0;
+       virtual void serialize(std::ostream &os, u16 protocol_version)=0;
        virtual void deSerialize(std::istream &is)=0;
 
        // Do stuff asked by threads that can only be done in the main thread
index 8ee8d6a845a2059c4877b55cd97024e38b3d7a1d..2d6f6c72b8c27b39694ae4797954a2d1ec4a04d8 100644 (file)
@@ -117,6 +117,20 @@ ToolCapabilities read_tool_capabilities(
                }
        }
        lua_pop(L, 1);
+       lua_getfield(L, table, "damage_groups");
+       if(lua_istable(L, -1)){
+               int table_damage_groups = lua_gettop(L);
+               lua_pushnil(L);
+               while(lua_next(L, table_damage_groups) != 0){
+                       // key at index -2 and value at index -1
+                       std::string groupname = luaL_checkstring(L, -2);
+                       u16 value = luaL_checkinteger(L, -1);
+                       toolcap.damageGroups[groupname] = value;
+                       // removes value, keeps key for next iteration
+                       lua_pop(L, 1);
+               }
+       }
+       lua_pop(L, 1);
        return toolcap;
 }
 
@@ -154,6 +168,16 @@ void set_tool_capabilities(lua_State *L, int table,
        }
        // Set groupcaps table
        lua_setfield(L, -2, "groupcaps");
+       //Create damage_groups table
+       lua_newtable(L);
+       // For each damage group
+       for(std::map<std::string, s16>::const_iterator
+                       i = toolcap.damageGroups.begin(); i != toolcap.damageGroups.end(); i++){
+               // Create damage group table
+               lua_pushinteger(L, i->second);
+               lua_setfield(L, -2, i->first.c_str());
+       }
+       lua_setfield(L, -2, "damage_groups");
 }
 
 void push_tool_capabilities(lua_State *L,
index db05b95ccc10eef2fc2012e70b9eb021296694bf..6bdebcec4d9d956ed3e9a23e6aa61d1454b66417 100644 (file)
@@ -2080,7 +2080,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                SendMovement(m_con, peer_id);
 
                // Send item definitions
-               SendItemDef(m_con, peer_id, m_itemdef);
+               SendItemDef(m_con, peer_id, m_itemdef, client->net_proto_version);
 
                // Send node definitions
                SendNodeDef(m_con, peer_id, m_nodedef, client->net_proto_version);
@@ -3342,7 +3342,7 @@ void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
 }
 
 void Server::SendItemDef(con::Connection &con, u16 peer_id,
-               IItemDefManager *itemdef)
+               IItemDefManager *itemdef, u16 protocol_version)
 {
        DSTACK(__FUNCTION_NAME);
        std::ostringstream os(std::ios_base::binary);
@@ -3354,7 +3354,7 @@ void Server::SendItemDef(con::Connection &con, u16 peer_id,
        */
        writeU16(os, TOCLIENT_ITEMDEF);
        std::ostringstream tmp_os(std::ios::binary);
-       itemdef->serialize(tmp_os);
+       itemdef->serialize(tmp_os, protocol_version);
        std::ostringstream tmp_os2(std::ios::binary);
        compressZlib(tmp_os.str(), tmp_os2);
        os<<serializeLongString(tmp_os2.str());
index 813dc9828dc6fc4d67e9427dde21e9b6a8e166eb..04e693fc884994fd1938a80080bfb5a4cabc3444 100644 (file)
@@ -556,7 +556,7 @@ private:
        static void SendDeathscreen(con::Connection &con, u16 peer_id,
                        bool set_camera_point_target, v3f camera_point_target);
        static void SendItemDef(con::Connection &con, u16 peer_id,
-                       IItemDefManager *itemdef);
+                       IItemDefManager *itemdef, u16 protocol_version);
        static void SendNodeDef(con::Connection &con, u16 peer_id,
                        INodeDefManager *nodedef, u16 protocol_version);
 
index 04f19749c9332c4c059b49d28b31a3817c70444a..4d809e2c44ffc75e3e1e374a439004b19a2d8462 100644 (file)
@@ -24,9 +24,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "util/serialize.h"
 #include "util/numeric.h"
 
-void ToolCapabilities::serialize(std::ostream &os) const
+void ToolCapabilities::serialize(std::ostream &os, u16 protocol_version) const
 {
-       writeU8(os, 1); // version
+       if(protocol_version <= 17)
+               writeU8(os, 1); // version
+       else
+               writeU8(os, 2); // version
        writeF1000(os, full_punch_interval);
        writeS16(os, max_drop_level);
        writeU32(os, groupcaps.size());
@@ -44,12 +47,20 @@ void ToolCapabilities::serialize(std::ostream &os) const
                        writeF1000(os, i->second);
                }
        }
+       if(protocol_version > 17){
+               writeU32(os, damageGroups.size());
+               for(std::map<std::string, s16>::const_iterator
+                               i = damageGroups.begin(); i != damageGroups.end(); i++){
+                       os<<serializeString(i->first);
+                       writeS16(os, i->second);
+               }
+       }
 }
 
 void ToolCapabilities::deSerialize(std::istream &is)
 {
        int version = readU8(is);
-       if(version != 1) throw SerializationError(
+       if(version != 1 && version != 2) throw SerializationError(
                        "unsupported ToolCapabilities version");
        full_punch_interval = readF1000(is);
        max_drop_level = readS16(is);
@@ -68,6 +79,15 @@ void ToolCapabilities::deSerialize(std::istream &is)
                }
                groupcaps[name] = cap;
        }
+       if(version == 2)
+       {
+               u32 damage_groups_size = readU32(is);
+               for(u32 i=0; i<damage_groups_size; i++){
+                       std::string name = deSerializeString(is);
+                       s16 rating = readS16(is);
+                       damageGroups[name] = rating;
+               }
+       }
 }
 
 DigParams getDigParams(const ItemGroupList &groups,
@@ -136,28 +156,26 @@ DigParams getDigParams(const ItemGroupList &groups,
        return getDigParams(groups, tp, 1000000);
 }
 
-HitParams getHitParams(const ItemGroupList &groups,
+HitParams getHitParams(const ItemGroupList &armor_groups,
                const ToolCapabilities *tp, float time_from_last_punch)
 {
-       DigParams digprop = getDigParams(groups, tp,
-                       time_from_last_punch);
-       
-       if(time_from_last_punch > tp->full_punch_interval)
-               time_from_last_punch = tp->full_punch_interval;
-       // Damage in hp is equivalent to nodes dug in time_from_last_punch
-       s16 hp = 0;
-       if(digprop.diggable)
-               hp = time_from_last_punch / digprop.time;
-       // Wear is the same as for digging a single node
-       s16 wear = (float)digprop.wear;
-
-       return HitParams(hp, wear, digprop.main_group);
+       s16 damage = 0;
+       float full_punch_interval = tp->full_punch_interval;
+
+       for(std::map<std::string, s16>::const_iterator
+                       i = tp->damageGroups.begin(); i != tp->damageGroups.end(); i++){
+               s16 armor = itemgroup_get(armor_groups, i->first);
+               damage += i->second * rangelim(time_from_last_punch * full_punch_interval, 0.0, 1.0)
+                               * armor / 100.0;
+       }
+
+       return HitParams(damage, 0);
 }
 
-HitParams getHitParams(const ItemGroupList &groups,
+HitParams getHitParams(const ItemGroupList &armor_groups,
                const ToolCapabilities *tp)
 {
-       return getHitParams(groups, tp, 1000000);
+       return getHitParams(armor_groups, tp, 1000000);
 }
 
 PunchDamageResult getPunchDamage(
@@ -187,7 +205,6 @@ PunchDamageResult getPunchDamage(
                result.did_punch = true;
                result.wear = hitparams.wear;
                result.damage = hitparams.hp;
-               result.main_group = hitparams.main_group;
        }
 
        return result;
index e812a9e368c88cdd6889281c4da770cc0c41009e..509561a1645466f9381833714a65621466c3f035 100644 (file)
@@ -52,6 +52,7 @@ struct ToolGroupCap
 
 // CLANG SUCKS DONKEY BALLS
 typedef std::map<std::string, struct ToolGroupCap> ToolGCMap;
+typedef std::map<std::string, s16> DamageGroup;
 
 struct ToolCapabilities
 {
@@ -59,19 +60,22 @@ struct ToolCapabilities
        int max_drop_level;
        // CLANG SUCKS DONKEY BALLS
        ToolGCMap groupcaps;
+       DamageGroup damageGroups;
 
        ToolCapabilities(
                        float full_punch_interval_=1.4,
                        int max_drop_level_=1,
                        // CLANG SUCKS DONKEY BALLS
-                       ToolGCMap groupcaps_=ToolGCMap()
+                       ToolGCMap groupcaps_=ToolGCMap(),
+                       DamageGroup damageGroups_=DamageGroup()
        ):
                full_punch_interval(full_punch_interval_),
                max_drop_level(max_drop_level_),
-               groupcaps(groupcaps_)
+               groupcaps(groupcaps_),
+               damageGroups(damageGroups_)
        {}
 
-       void serialize(std::ostream &os) const;
+       void serialize(std::ostream &os, u16 version) const;
        void deSerialize(std::istream &is);
 };
 
@@ -103,19 +107,17 @@ struct HitParams
 {
        s16 hp;
        s16 wear;
-       std::string main_group;
 
-       HitParams(s16 hp_=0, s16 wear_=0, std::string main_group_=""):
+       HitParams(s16 hp_=0, s16 wear_=0):
                hp(hp_),
-               wear(wear_),
-               main_group(main_group_)
+               wear(wear_)
        {}
 };
 
-HitParams getHitParams(const ItemGroupList &groups,
+HitParams getHitParams(const ItemGroupList &armor_groups,
                const ToolCapabilities *tp, float time_from_last_punch);
 
-HitParams getHitParams(const ItemGroupList &groups,
+HitParams getHitParams(const ItemGroupList &armor_groups,
                const ToolCapabilities *tp);
 
 struct PunchDamageResult
@@ -123,7 +125,6 @@ struct PunchDamageResult
        bool did_punch;
        int damage;
        int wear;
-       std::string main_group;
 
        PunchDamageResult():
                did_punch(false),