Unknown nodes can be dug
[oweals/minetest.git] / src / tool.cpp
index d45556269743d6d878b83e93ec5a27877f94f2bf..40bcdc69a59616825d1607a925544164e691897d 100644 (file)
@@ -18,70 +18,172 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 */
 
 #include "tool.h"
-#include "irrlichttypes.h"
+#include "utility.h"
+#include "itemdef.h" // For itemgroup_get()
 #include "log.h"
-#include <ostream>
+#include "inventory.h"
 
-class CToolDefManager: public IToolDefManager
+void ToolCapabilities::serialize(std::ostream &os) const
 {
-public:
-       virtual ~CToolDefManager()
-       {
-               for(core::map<std::string, ToolDefinition*>::Iterator
-                               i = m_tool_definitions.getIterator();
-                               i.atEnd() == false; i++){
-                       delete i.getNode()->getValue();
+       writeU8(os, 0); // version
+       writeF1000(os, full_punch_interval);
+       writeS16(os, max_drop_level);
+       writeU32(os, groupcaps.size());
+       for(std::map<std::string, ToolGroupCap>::const_iterator
+                       i = groupcaps.begin(); i != groupcaps.end(); i++){
+               const std::string *name = &i->first;
+               const ToolGroupCap *cap = &i->second;
+               os<<serializeString(*name);
+               writeF1000(os, cap->maxwear);
+               writeF1000(os, cap->maxlevel);
+               writeU32(os, cap->times.size());
+               for(std::map<int, float>::const_iterator
+                               i = cap->times.begin(); i != cap->times.end(); i++){
+                       writeS16(os, i->first);
+                       writeF1000(os, i->second);
                }
        }
-       virtual bool registerTool(std::string toolname, const ToolDefinition &def)
-       {
-               infostream<<"registerTool: registering tool \""<<toolname<<"\""<<std::endl;
-               core::map<std::string, ToolDefinition*>::Node *n;
-               n = m_tool_definitions.find(toolname);
-               if(n != NULL){
-                       errorstream<<"registerTool: registering tool \""<<toolname
-                                       <<"\" failed: name is already registered"<<std::endl;
-                       return false;
+}
+
+void ToolCapabilities::deSerialize(std::istream &is)
+{
+       int version = readU8(is);
+       if(version != 0) throw SerializationError(
+                       "unsupported ToolCapabilities version");
+       full_punch_interval = readF1000(is);
+       max_drop_level = readS16(is);
+       groupcaps.clear();
+       u32 groupcaps_size = readU32(is);
+       for(u32 i=0; i<groupcaps_size; i++){
+               std::string name = deSerializeString(is);
+               ToolGroupCap cap;
+               cap.maxwear = readF1000(is);
+               cap.maxlevel = readF1000(is);
+               u32 times_size = readU32(is);
+               for(u32 i=0; i<times_size; i++){
+                       int level = readS16(is);
+                       float time = readF1000(is);
+                       cap.times[level] = time;
                }
-               m_tool_definitions[toolname] = new ToolDefinition(def);
-               return true;
+               groupcaps[name] = cap;
        }
-       virtual ToolDefinition* getToolDefinition(const std::string &toolname)
-       {
-               core::map<std::string, ToolDefinition*>::Node *n;
-               n = m_tool_definitions.find(toolname);
-               if(n == NULL)
-                       return NULL;
-               return n->getValue();
+}
+
+DigParams getDigParams(const ItemGroupList &groups,
+               const ToolCapabilities *tp, float time_from_last_punch)
+{
+       //infostream<<"getDigParams"<<std::endl;
+       /* Check group dig_immediate */
+       switch(itemgroup_get(groups, "dig_immediate")){
+       case 2:
+               //infostream<<"dig_immediate=2"<<std::endl;
+               return DigParams(true, 0.5, 0);
+       case 3:
+               //infostream<<"dig_immediate=3"<<std::endl;
+               return DigParams(true, 0.0, 0);
+       default:
+               break;
        }
-       virtual std::string getImagename(const std::string &toolname)
-       {
-               ToolDefinition *def = getToolDefinition(toolname);
-               if(def == NULL)
-                       return "";
-               return def->imagename;
+       
+       // Values to be returned (with a bit of conversion)
+       bool result_diggable = false;
+       float result_time = 0.0;
+       float result_wear = 0.0;
+
+       int level = itemgroup_get(groups, "level");
+       //infostream<<"level="<<level<<std::endl;
+       for(std::map<std::string, ToolGroupCap>::const_iterator
+                       i = tp->groupcaps.begin(); i != tp->groupcaps.end(); i++){
+               const std::string &name = i->first;
+               //infostream<<"group="<<name<<std::endl;
+               const ToolGroupCap &cap = i->second;
+               int rating = itemgroup_get(groups, name);
+               float time = 0;
+               bool time_exists = cap.getTime(rating, &time);
+               if(!result_diggable || time < result_time){
+                       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);
+                       }
+               }
        }
-       virtual ToolDiggingProperties getDiggingProperties(
-                       const std::string &toolname)
+       //infostream<<"result_diggable="<<result_diggable<<std::endl;
+       //infostream<<"result_time="<<result_time<<std::endl;
+       //infostream<<"result_wear="<<result_wear<<std::endl;
+
+       if(time_from_last_punch < tp->full_punch_interval){
+               float f = time_from_last_punch / tp->full_punch_interval;
+               //infostream<<"f="<<f<<std::endl;
+               result_time /= f;
+               result_wear /= f;
+       }
+
+       u16 wear_i = 65535.*result_wear;
+       return DigParams(result_diggable, result_time, wear_i);
+}
+
+DigParams getDigParams(const ItemGroupList &groups,
+               const ToolCapabilities *tp)
+{
+       return getDigParams(groups, tp, 1000000);
+}
+
+HitParams getHitParams(const ItemGroupList &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);
+}
+
+HitParams getHitParams(const ItemGroupList &groups,
+               const ToolCapabilities *tp)
+{
+       return getHitParams(groups, tp, 1000000);
+}
+
+PunchDamageResult getPunchDamage(
+               const ItemGroupList &armor_groups,
+               const ToolCapabilities *toolcap,
+               const ItemStack *punchitem,
+               float time_from_last_punch
+){
+       bool do_hit = true;
        {
-               ToolDefinition *def = getToolDefinition(toolname);
-               // If tool does not exist, just return an impossible
-               if(def == NULL){
-                       // If tool does not exist, try empty name
-                       ToolDefinition *def = getToolDefinition("");
-                       if(def == NULL) // If that doesn't exist either, return default
-                               return ToolDiggingProperties();
-                       return def->properties;
+               if(do_hit && punchitem){
+                       if(itemgroup_get(armor_groups, "punch_operable") &&
+                                       (toolcap == NULL || punchitem->name == ""))
+                               do_hit = false;
+               }
+               if(do_hit){
+                       if(itemgroup_get(armor_groups, "immortal"))
+                               do_hit = false;
                }
-               return def->properties;
        }
-private:
-       // Key is name
-       core::map<std::string, ToolDefinition*> m_tool_definitions;
-};
+       
+       PunchDamageResult result;
+       if(do_hit)
+       {
+               HitParams hitparams = getHitParams(armor_groups, toolcap,
+                               time_from_last_punch);
+               result.did_punch = true;
+               result.wear = hitparams.wear;
+               result.damage = hitparams.hp;
+       }
 
-IToolDefManager* createToolDefManager()
-{
-       return new CToolDefManager();
+       return result;
 }
 
+