]> git.lizzy.rs Git - minetest.git/blob - src/serverremoteplayer.cpp
Fix player double damage
[minetest.git] / src / serverremoteplayer.cpp
1 /*
2 Minetest-c55
3 Copyright (C) 2010-2011 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 General Public License as published by
7 the Free Software Foundation; either version 2 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 General Public License for more details.
14
15 You should have received a copy of the GNU 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 "serverremoteplayer.h"
21 #include "main.h" // For g_settings
22 #include "settings.h"
23 #include "log.h"
24 #include "gamedef.h"
25 #include "tooldef.h"
26 #include "environment.h"
27 #include "materials.h"
28
29 ServerRemotePlayer::ServerRemotePlayer(ServerEnvironment *env):
30         Player(env->getGameDef()),
31         ServerActiveObject(env, v3f(0,0,0)),
32         m_last_good_position(0,0,0),
33         m_last_good_position_age(0),
34         m_additional_items(),
35         m_inventory_not_sent(false),
36         m_hp_not_sent(false),
37         m_respawn_active(false),
38         m_is_in_environment(false),
39         m_position_not_sent(false)
40 {
41 }
42 ServerRemotePlayer::ServerRemotePlayer(ServerEnvironment *env, v3f pos_, u16 peer_id_,
43                 const char *name_):
44         Player(env->getGameDef()),
45         ServerActiveObject(env, pos_),
46         m_inventory_not_sent(false),
47         m_hp_not_sent(false),
48         m_is_in_environment(false),
49         m_position_not_sent(false)
50 {
51         setPosition(pos_);
52         peer_id = peer_id_;
53         updateName(name_);
54 }
55 ServerRemotePlayer::~ServerRemotePlayer()
56 {
57         clearAddToInventoryLater();
58 }
59
60 void ServerRemotePlayer::setPosition(const v3f &position)
61 {
62         Player::setPosition(position);
63         ServerActiveObject::setBasePosition(position);
64         m_position_not_sent = true;
65 }
66
67 InventoryItem* ServerRemotePlayer::getWieldedItem()
68 {
69         InventoryList *list = inventory.getList("main");
70         if (list)
71                 return list->getItem(m_selected_item);
72         return NULL;
73 }
74
75 /* ServerActiveObject interface */
76
77 void ServerRemotePlayer::addedToEnvironment()
78 {
79         assert(!m_is_in_environment);
80         m_is_in_environment = true;
81 }
82
83 void ServerRemotePlayer::removingFromEnvironment()
84 {
85         assert(m_is_in_environment);
86         m_is_in_environment = false;
87 }
88
89 bool ServerRemotePlayer::unlimitedTransferDistance() const
90 {
91         return true;
92 }
93
94 void ServerRemotePlayer::step(float dtime, bool send_recommended)
95 {
96         if(send_recommended == false)
97                 return;
98         
99         if(m_position_not_sent)
100         {
101                 m_position_not_sent = false;
102
103                 std::ostringstream os(std::ios::binary);
104                 // command (0 = update position)
105                 writeU8(os, 0);
106                 // pos
107                 writeV3F1000(os, getPosition());
108                 // yaw
109                 writeF1000(os, getYaw());
110                 // create message and add to list
111                 ActiveObjectMessage aom(getId(), false, os.str());
112                 m_messages_out.push_back(aom);
113         }
114 }
115
116 std::string ServerRemotePlayer::getClientInitializationData()
117 {
118         std::ostringstream os(std::ios::binary);
119         // version
120         writeU8(os, 0);
121         // name
122         os<<serializeString(getName());
123         // pos
124         writeV3F1000(os, getPosition());
125         // yaw
126         writeF1000(os, getYaw());
127         return os.str();
128 }
129
130 std::string ServerRemotePlayer::getStaticData()
131 {
132         assert(0);
133         return "";
134 }
135
136 void ServerRemotePlayer::punch(ServerActiveObject *puncher,
137                 float time_from_last_punch)
138 {
139         if(!puncher)
140                 return;
141         
142         // "Material" properties of a player
143         MaterialProperties mp;
144         mp.diggability = DIGGABLE_NORMAL;
145         mp.crackiness = -0.5;
146         mp.cuttability = 0.5;
147
148         ToolDiggingProperties tp;
149         puncher->getWieldDiggingProperties(&tp);
150
151         HittingProperties hitprop = getHittingProperties(&mp, &tp,
152                         time_from_last_punch);
153         
154         setHP(getHP() - hitprop.hp);
155         puncher->damageWieldedItem(hitprop.wear);
156
157         {
158                 std::ostringstream os(std::ios::binary);
159                 // command (1 = punched)
160                 writeU8(os, 1);
161                 // damage
162                 writeS16(os, hitprop.hp);
163                 // create message and add to list
164                 ActiveObjectMessage aom(getId(), false, os.str());
165                 m_messages_out.push_back(aom);
166         }
167 }
168
169 void ServerRemotePlayer::rightClick(ServerActiveObject *clicker)
170 {
171 }
172
173 void ServerRemotePlayer::setPos(v3f pos)
174 {
175         setPosition(pos);
176         // Movement caused by this command is always valid
177         m_last_good_position = pos;
178         m_last_good_position_age = 0;
179 }
180 void ServerRemotePlayer::moveTo(v3f pos, bool continuous)
181 {
182         setPosition(pos);
183         // Movement caused by this command is always valid
184         m_last_good_position = pos;
185         m_last_good_position_age = 0;
186 }
187
188 void ServerRemotePlayer::getWieldDiggingProperties(ToolDiggingProperties *dst)
189 {
190         IGameDef *gamedef = m_env->getGameDef();
191         IToolDefManager *tdef = gamedef->tdef();
192
193         InventoryItem *item = getWieldedItem();
194         if(item == NULL || std::string(item->getName()) != "ToolItem"){
195                 *dst = ToolDiggingProperties();
196                 return;
197         }
198         ToolItem *titem = (ToolItem*)item;
199         *dst = tdef->getDiggingProperties(titem->getToolName());
200 }
201
202 void ServerRemotePlayer::damageWieldedItem(u16 amount)
203 {
204         infostream<<"Damaging "<<getName()<<"'s wielded item for amount="
205                         <<amount<<std::endl;
206         InventoryList *list = inventory.getList("main");
207         if(!list)
208                 return;
209         InventoryItem *item = list->getItem(m_selected_item);
210         if(item && (std::string)item->getName() == "ToolItem"){
211                 ToolItem *titem = (ToolItem*)item;
212                 bool weared_out = titem->addWear(amount);
213                 if(weared_out)
214                         list->deleteItem(m_selected_item);
215         }
216 }
217 bool ServerRemotePlayer::addToInventory(InventoryItem *item)
218 {
219         infostream<<"Adding "<<item->getName()<<" into "<<getName()
220                         <<"'s inventory"<<std::endl;
221         
222         InventoryList *ilist = inventory.getList("main");
223         if(ilist == NULL)
224                 return false;
225         
226         // In creative mode, just delete the item
227         if(g_settings->getBool("creative_mode")){
228                 return false;
229         }
230
231         // Skip if inventory has no free space
232         if(ilist->roomForItem(item) == false)
233         {
234                 infostream<<"Player inventory has no free space"<<std::endl;
235                 return false;
236         }
237
238         // Add to inventory
239         InventoryItem *leftover = ilist->addItem(item);
240         assert(!leftover);
241         
242         m_inventory_not_sent = true;
243
244         return true;
245 }
246 void ServerRemotePlayer::addToInventoryLater(InventoryItem *item)
247 {
248         infostream<<"Adding (later) "<<item->getName()<<" into "<<getName()
249                         <<"'s inventory"<<std::endl;
250         m_additional_items.push_back(item);
251 }
252 void ServerRemotePlayer::clearAddToInventoryLater()
253 {
254         for (std::vector<InventoryItem*>::iterator
255                         i = m_additional_items.begin();
256                         i != m_additional_items.end(); i++)
257         {
258                 delete *i;
259         }
260         m_additional_items.clear();
261 }
262 void ServerRemotePlayer::completeAddToInventoryLater(u16 preferred_index)
263 {
264         InventoryList *ilist = inventory.getList("main");
265         if(ilist == NULL)
266         {
267                 clearAddToInventoryLater();
268                 return;
269         }
270         
271         // In creative mode, just delete the items
272         if(g_settings->getBool("creative_mode"))
273         {
274                 clearAddToInventoryLater();
275                 return;
276         }
277         
278         for (std::vector<InventoryItem*>::iterator
279                         i = m_additional_items.begin();
280                         i != m_additional_items.end(); i++)
281         {
282                 InventoryItem *item = *i;
283                 InventoryItem *leftover = item;
284                 leftover = ilist->addItem(preferred_index, leftover);
285                 leftover = ilist->addItem(leftover);
286                 delete leftover;
287         }
288         m_additional_items.clear();
289         m_inventory_not_sent = true;
290 }
291 void ServerRemotePlayer::setHP(s16 hp_)
292 {
293         s16 oldhp = hp;
294
295         // FIXME: don't hardcode maximum HP, make configurable per object
296         if(hp_ < 0)
297                 hp_ = 0;
298         else if(hp_ > 20)
299                 hp_ = 20;
300         hp = hp_;
301
302         if(hp != oldhp)
303                 m_hp_not_sent = true;
304 }
305 s16 ServerRemotePlayer::getHP()
306 {
307         return hp;
308 }
309
310