Line data Source code
1 : /*
2 : Minetest
3 : Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4 :
5 : This program is free software; you can redistribute it and/or modify
6 : it under the terms of the GNU Lesser General Public License as published by
7 : the Free Software Foundation; either version 2.1 of the License, or
8 : (at your option) any later version.
9 :
10 : This program is distributed in the hope that it will be useful,
11 : but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 : GNU Lesser General Public License for more details.
14 :
15 : You should have received a copy of the GNU Lesser General Public License along
16 : with this program; if not, write to the Free Software Foundation, Inc.,
17 : 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 : */
19 :
20 : #include "tool.h"
21 : #include "itemgroup.h"
22 : #include "log.h"
23 : #include "inventory.h"
24 : #include "exceptions.h"
25 : #include "util/serialize.h"
26 : #include "util/numeric.h"
27 :
28 0 : void ToolCapabilities::serialize(std::ostream &os, u16 protocol_version) const
29 : {
30 0 : if(protocol_version <= 17)
31 0 : writeU8(os, 1); // version
32 : else
33 0 : writeU8(os, 2); // version
34 0 : writeF1000(os, full_punch_interval);
35 0 : writeS16(os, max_drop_level);
36 0 : writeU32(os, groupcaps.size());
37 0 : for(std::map<std::string, ToolGroupCap>::const_iterator
38 0 : i = groupcaps.begin(); i != groupcaps.end(); i++){
39 0 : const std::string *name = &i->first;
40 0 : const ToolGroupCap *cap = &i->second;
41 0 : os<<serializeString(*name);
42 0 : writeS16(os, cap->uses);
43 0 : writeS16(os, cap->maxlevel);
44 0 : writeU32(os, cap->times.size());
45 0 : for(std::map<int, float>::const_iterator
46 0 : i = cap->times.begin(); i != cap->times.end(); i++){
47 0 : writeS16(os, i->first);
48 0 : writeF1000(os, i->second);
49 : }
50 : }
51 0 : if(protocol_version > 17){
52 0 : writeU32(os, damageGroups.size());
53 0 : for(std::map<std::string, s16>::const_iterator
54 0 : i = damageGroups.begin(); i != damageGroups.end(); i++){
55 0 : os<<serializeString(i->first);
56 0 : writeS16(os, i->second);
57 : }
58 : }
59 0 : }
60 :
61 42 : void ToolCapabilities::deSerialize(std::istream &is)
62 : {
63 42 : int version = readU8(is);
64 42 : if(version != 1 && version != 2) throw SerializationError(
65 0 : "unsupported ToolCapabilities version");
66 42 : full_punch_interval = readF1000(is);
67 42 : max_drop_level = readS16(is);
68 42 : groupcaps.clear();
69 42 : u32 groupcaps_size = readU32(is);
70 95 : for(u32 i=0; i<groupcaps_size; i++){
71 106 : std::string name = deSerializeString(is);
72 106 : ToolGroupCap cap;
73 53 : cap.uses = readS16(is);
74 53 : cap.maxlevel = readS16(is);
75 53 : u32 times_size = readU32(is);
76 178 : for(u32 i=0; i<times_size; i++){
77 125 : int level = readS16(is);
78 125 : float time = readF1000(is);
79 125 : cap.times[level] = time;
80 : }
81 53 : groupcaps[name] = cap;
82 : }
83 42 : if(version == 2)
84 : {
85 42 : u32 damage_groups_size = readU32(is);
86 76 : for(u32 i=0; i<damage_groups_size; i++){
87 68 : std::string name = deSerializeString(is);
88 34 : s16 rating = readS16(is);
89 34 : damageGroups[name] = rating;
90 : }
91 : }
92 42 : }
93 :
94 0 : DigParams getDigParams(const ItemGroupList &groups,
95 : const ToolCapabilities *tp, float time_from_last_punch)
96 : {
97 : //infostream<<"getDigParams"<<std::endl;
98 : /* Check group dig_immediate */
99 0 : switch(itemgroup_get(groups, "dig_immediate")){
100 : case 2:
101 : //infostream<<"dig_immediate=2"<<std::endl;
102 0 : return DigParams(true, 0.5, 0, "dig_immediate");
103 : case 3:
104 : //infostream<<"dig_immediate=3"<<std::endl;
105 0 : return DigParams(true, 0.0, 0, "dig_immediate");
106 : default:
107 0 : break;
108 : }
109 :
110 : // Values to be returned (with a bit of conversion)
111 0 : bool result_diggable = false;
112 0 : float result_time = 0.0;
113 0 : float result_wear = 0.0;
114 0 : std::string result_main_group = "";
115 :
116 0 : int level = itemgroup_get(groups, "level");
117 : //infostream<<"level="<<level<<std::endl;
118 0 : for(std::map<std::string, ToolGroupCap>::const_iterator
119 0 : i = tp->groupcaps.begin(); i != tp->groupcaps.end(); i++){
120 0 : const std::string &name = i->first;
121 : //infostream<<"group="<<name<<std::endl;
122 0 : const ToolGroupCap &cap = i->second;
123 0 : int rating = itemgroup_get(groups, name);
124 0 : float time = 0;
125 0 : bool time_exists = cap.getTime(rating, &time);
126 0 : if(!result_diggable || time < result_time){
127 0 : if(cap.maxlevel >= level && time_exists){
128 0 : result_diggable = true;
129 0 : int leveldiff = cap.maxlevel - level;
130 0 : result_time = time / MYMAX(1, leveldiff);
131 0 : if(cap.uses != 0)
132 0 : result_wear = 1.0 / cap.uses / pow(3.0, (double)leveldiff);
133 : else
134 0 : result_wear = 0;
135 0 : result_main_group = name;
136 : }
137 : }
138 : }
139 : //infostream<<"result_diggable="<<result_diggable<<std::endl;
140 : //infostream<<"result_time="<<result_time<<std::endl;
141 : //infostream<<"result_wear="<<result_wear<<std::endl;
142 :
143 0 : if(time_from_last_punch < tp->full_punch_interval){
144 0 : float f = time_from_last_punch / tp->full_punch_interval;
145 : //infostream<<"f="<<f<<std::endl;
146 0 : result_time /= f;
147 0 : result_wear /= f;
148 : }
149 :
150 0 : u16 wear_i = 65535.*result_wear;
151 0 : return DigParams(result_diggable, result_time, wear_i, result_main_group);
152 : }
153 :
154 0 : DigParams getDigParams(const ItemGroupList &groups,
155 : const ToolCapabilities *tp)
156 : {
157 0 : return getDigParams(groups, tp, 1000000);
158 : }
159 :
160 0 : HitParams getHitParams(const ItemGroupList &armor_groups,
161 : const ToolCapabilities *tp, float time_from_last_punch)
162 : {
163 0 : s16 damage = 0;
164 0 : float full_punch_interval = tp->full_punch_interval;
165 :
166 0 : for(std::map<std::string, s16>::const_iterator
167 0 : i = tp->damageGroups.begin(); i != tp->damageGroups.end(); i++){
168 0 : s16 armor = itemgroup_get(armor_groups, i->first);
169 0 : damage += i->second * rangelim(time_from_last_punch / full_punch_interval, 0.0, 1.0)
170 0 : * armor / 100.0;
171 : }
172 :
173 0 : return HitParams(damage, 0);
174 : }
175 :
176 0 : HitParams getHitParams(const ItemGroupList &armor_groups,
177 : const ToolCapabilities *tp)
178 : {
179 0 : return getHitParams(armor_groups, tp, 1000000);
180 : }
181 :
182 0 : PunchDamageResult getPunchDamage(
183 : const ItemGroupList &armor_groups,
184 : const ToolCapabilities *toolcap,
185 : const ItemStack *punchitem,
186 : float time_from_last_punch
187 : ){
188 0 : bool do_hit = true;
189 : {
190 0 : if(do_hit && punchitem){
191 0 : if(itemgroup_get(armor_groups, "punch_operable") &&
192 0 : (toolcap == NULL || punchitem->name == ""))
193 0 : do_hit = false;
194 : }
195 0 : if(do_hit){
196 0 : if(itemgroup_get(armor_groups, "immortal"))
197 0 : do_hit = false;
198 : }
199 : }
200 :
201 0 : PunchDamageResult result;
202 0 : if(do_hit)
203 : {
204 : HitParams hitparams = getHitParams(armor_groups, toolcap,
205 0 : time_from_last_punch);
206 0 : result.did_punch = true;
207 0 : result.wear = hitparams.wear;
208 0 : result.damage = hitparams.hp;
209 : }
210 :
211 0 : return result;
212 3 : }
213 :
214 :
|