ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/socket/item.C
(Generate patch)

Comparing deliantra/server/socket/item.C (file contents):
Revision 1.2 by root, Tue Aug 29 07:34:01 2006 UTC vs.
Revision 1.16 by root, Thu Dec 14 01:21:58 2006 UTC

1
2/*
3 * static char *rcsid_item_c =
4 * "$Id: item.C,v 1.2 2006/08/29 07:34:01 root Exp $";
5 */
6
7/* 1/*
8 CrossFire, A Multiplayer game for X-windows 2 CrossFire, A Multiplayer game for X-windows
9 3
10 Copyright (C) 2002 Mark Wedel & Crossfire Development Team 4 Copyright (C) 2002 Mark Wedel & Crossfire Development Team
11 Copyright (C) 1992 Frank Tore Johansen 5 Copyright (C) 1992 Frank Tore Johansen
22 16
23 You should have received a copy of the GNU General Public License 17 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software 18 along with this program; if not, write to the Free Software
25 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 20
27 The author can be reached via e-mail to crossfire-devel@real-time.com 21 The author can be reached via e-mail to <crossfire@schmorp.de>
28*/ 22*/
29 23
30/** 24/**
31 * \file 25 * \file
32 * Client/server logic. 26 * Client/server logic.
38 * the logic for what items should be sent. 32 * the logic for what items should be sent.
39 */ 33 */
40 34
41 35
42#include <global.h> 36#include <global.h>
43#include <object.h> /* LOOK_OBJ */ 37#include <object.h> /* LOOK_OBJ */
44#include <newclient.h> 38#include <newclient.h>
45#include <newserver.h> 39#include <newserver.h>
46#include <sproto.h> 40#include <sproto.h>
47 41
48/** This is the maximum number of bytes we expect any one item to take up */ 42/** This is the maximum number of bytes we expect any one item to take up */
53 * Functions related to sending object data to the client. 47 * Functions related to sending object data to the client.
54 * 48 *
55 ******************************************************************************/ 49 ******************************************************************************/
56 50
57/** 51/**
58 * Adds string to socklist.
59 *
60 * This is a simple function that we use a lot here. It basically
61 * adds the specified buffer into the socklist, but prepends a
62 * single byte in length. If the data is longer than that byte, it is
63 * truncated approprately.
64 */
65inline void add_stringlen_to_sockbuf(const char *buf, SockList *sl)
66{
67 int len;
68
69 len=strlen(buf);
70 if (len>255) len=255;
71 SockList_AddChar(sl, (char) len);
72 strncpy((char*)sl->buf+sl->len, buf,len);
73 sl->len += len;
74}
75
76/**
77 * This is a similar to query_name, but returns flags 52 * This is a similar to query_name, but returns flags
78 * to be sended to client. 53 * to be sended to client.
79 */ 54 */
55unsigned int
80unsigned int query_flags (object *op) 56query_flags (object *op)
81{ 57{
82 unsigned int flags = 0; 58 unsigned int flags = 0;
83 59
84 if(QUERY_FLAG(op,FLAG_APPLIED)) { 60 if (QUERY_FLAG (op, FLAG_APPLIED))
85 switch(op->type) {
86 case BOW:
87 case WAND:
88 case ROD:
89 case HORN:
90 flags = a_readied;
91 break;
92 case WEAPON:
93 flags = a_wielded;
94 break;
95 case SKILL:
96 case ARMOUR:
97 case HELMET:
98 case SHIELD:
99 case RING:
100 case BOOTS:
101 case GLOVES:
102 case AMULET:
103 case GIRDLE:
104 case BRACERS:
105 case CLOAK:
106 flags = a_worn;
107 break;
108 case CONTAINER:
109 flags = a_active;
110 break;
111 default:
112 flags = a_applied;
113 break;
114 }
115 }
116 if (op->type == CONTAINER && ((op->env && op->env->container == op) ||
117 (!op->env && QUERY_FLAG(op,FLAG_APPLIED))))
118 flags |= F_OPEN;
119 61 {
62 switch (op->type)
63 {
64 case BOW:
65 case WAND:
66 case ROD:
67 case HORN:
68 flags = a_readied;
69 break;
70 case WEAPON:
71 flags = a_wielded;
72 break;
73 case SKILL:
74 case ARMOUR:
75 case HELMET:
76 case SHIELD:
77 case RING:
78 case BOOTS:
79 case GLOVES:
80 case AMULET:
81 case GIRDLE:
82 case BRACERS:
83 case CLOAK:
84 flags = a_worn;
85 break;
86 case CONTAINER:
87 flags = a_active;
88 break;
89 default:
90 flags = a_applied;
91 break;
92 }
93 }
94 if (op->type == CONTAINER && ((op->env && op->env->container == op) || (!op->env && QUERY_FLAG (op, FLAG_APPLIED))))
95 flags |= F_OPEN;
96
120 if (QUERY_FLAG(op,FLAG_KNOWN_CURSED)) { 97 if (QUERY_FLAG (op, FLAG_KNOWN_CURSED))
98 {
121 if(QUERY_FLAG(op,FLAG_DAMNED)) 99 if (QUERY_FLAG (op, FLAG_DAMNED))
122 flags |= F_DAMNED; 100 flags |= F_DAMNED;
123 else if(QUERY_FLAG(op,FLAG_CURSED)) 101 else if (QUERY_FLAG (op, FLAG_CURSED))
124 flags |= F_CURSED; 102 flags |= F_CURSED;
125 } 103 }
126 if (QUERY_FLAG(op,FLAG_KNOWN_MAGICAL) && !QUERY_FLAG(op,FLAG_IDENTIFIED)) 104 if (QUERY_FLAG (op, FLAG_KNOWN_MAGICAL) && !QUERY_FLAG (op, FLAG_IDENTIFIED))
127 flags |= F_MAGIC; 105 flags |= F_MAGIC;
128 if (QUERY_FLAG(op,FLAG_UNPAID)) 106 if (QUERY_FLAG (op, FLAG_UNPAID))
129 flags |= F_UNPAID; 107 flags |= F_UNPAID;
130 if (QUERY_FLAG(op,FLAG_INV_LOCKED)) 108 if (QUERY_FLAG (op, FLAG_INV_LOCKED))
131 flags |= F_LOCKED; 109 flags |= F_LOCKED;
132 110
133 return flags; 111 return flags;
134} 112}
135 113
136/* Used in the send_look to put object head into SockList 114/* Used in the send_look to put object head into packet
137 * sl for socket ns. Need socket to know if we need to send 115 * sl for socket ns. Need socket to know if we need to send
138 * animation of face to the client. 116 * animation of face to the client.
139 */ 117 */
118static void
140static void add_object_to_socklist(NewSocket *ns, SockList *sl, object *head) 119add_object_to_socklist (NewSocket &ns, packet &sl, object *head)
141{ 120{
142 int flags, len, anim_speed; 121 int flags, len, anim_speed;
143 char item_n[MAX_BUF]; 122 char item_n[MAX_BUF];
144 const char *item_p; 123 const char *item_p;
145 124
146 flags = query_flags (head); 125 flags = query_flags (head);
147 if (QUERY_FLAG(head, FLAG_NO_PICK)) 126 if (QUERY_FLAG (head, FLAG_NO_PICK))
148 flags |= F_NOPICK; 127 flags |= F_NOPICK;
149 128
150 if (!(ns->faces_sent[head->face->number] & NS_FACESENT_FACE)) 129 if (!(ns.faces_sent[head->face->number] & NS_FACESENT_FACE))
151 esrv_send_face(ns, head->face->number,0); 130 esrv_send_face (&ns, head->face->number, 0);
152 131
153 if (QUERY_FLAG(head,FLAG_ANIMATE) && !ns->anims_sent[head->animation_id]) 132 if (QUERY_FLAG (head, FLAG_ANIMATE) && !ns.anims_sent[head->animation_id])
154 esrv_send_animation(ns, head->animation_id); 133 esrv_send_animation (&ns, head->animation_id);
155 134
156 SockList_AddInt(sl, head->count); 135 sl << uint32 (head->count)
157 SockList_AddInt(sl, flags); 136 << uint32 (flags)
158 SockList_AddInt(sl, QUERY_FLAG(head, FLAG_NO_PICK) ? -1 : WEIGHT(head)); 137 << uint32 (QUERY_FLAG (head, FLAG_NO_PICK) ? -1 : WEIGHT (head))
159 SockList_AddInt(sl, head->face->number); 138 << uint32 (head->face->number);
160 139
161 if (!head->custom_name) { 140 if (!head->custom_name)
141 {
162 strncpy(item_n,query_base_name(head, 0),127); 142 strncpy (item_n, query_base_name (head, 0), 127);
163 item_n[127]=0; 143 item_n[127] = 0;
164 len=strlen(item_n); 144 len = strlen (item_n);
165 item_p=query_base_name(head, 1); 145 item_p = query_base_name (head, 1);
166 } else { 146 }
147 else
148 {
167 strncpy(item_n,head->custom_name,127); 149 strncpy (item_n, head->custom_name, 127);
168 item_n[127]=0; 150 item_n[127] = 0;
169 len=strlen(item_n); 151 len = strlen (item_n);
170 item_p=head->custom_name; 152 item_p = head->custom_name;
171 } 153 }
154
172 strncpy(item_n+len+1, item_p, 127); 155 strncpy (item_n + len + 1, item_p, 127);
173 item_n[254]=0; 156 item_n[254] = 0;
174 len += strlen(item_n+1+len) + 1; 157 len += strlen (item_n + 1 + len) + 1;
175 SockList_AddChar(sl, (char ) len);
176 memcpy(sl->buf+sl->len, item_n, len);
177 sl->len += len;
178 158
179 SockList_AddShort(sl,head->animation_id); 159 sl << data8 (item_n, len)
160 << uint16 (head->animation_id);
161
180 anim_speed=0; 162 anim_speed = 0;
181 if (QUERY_FLAG(head,FLAG_ANIMATE)) { 163 if (QUERY_FLAG (head, FLAG_ANIMATE))
182 if (head->anim_speed) anim_speed=head->anim_speed;
183 else {
184 if (FABS(head->speed)<0.001) anim_speed=255;
185 else if (FABS(head->speed)>=1.0) anim_speed=1;
186 else anim_speed = (int) (1.0/FABS(head->speed));
187 }
188 if (anim_speed>255) anim_speed=255;
189 } 164 {
190 SockList_AddChar(sl, (char) anim_speed); 165 if (head->anim_speed)
191 SockList_AddInt(sl, head->nrof); 166 anim_speed = head->anim_speed;
167 else
168 {
169 if (FABS (head->speed) < 0.001)
170 anim_speed = 255;
171 else if (FABS (head->speed) >= 1.0)
172 anim_speed = 1;
173 else
174 anim_speed = (int) (1.0 / FABS (head->speed));
175 }
192 176
177 if (anim_speed > 255)
178 anim_speed = 255;
179 }
180
181 sl << uint8 (anim_speed)
182 << uint32 (head->nrof);
183
193 if (ns->itemcmd == 2) 184 if (ns.itemcmd == 2)
194 SockList_AddShort(sl, head->client_type); 185 sl << uint16 (head->client_type);
195 186
196 SET_FLAG(head, FLAG_CLIENT_SENT); 187 SET_FLAG (head, FLAG_CLIENT_SENT);
197} 188}
198 189
199 190
200/** 191/**
201 * Send the look window. Don't need to do animations here 192 * Send the look window. Don't need to do animations here
202 * This sends all the faces to the client, not just updates. This is 193 * This sends all the faces to the client, not just updates. This is
203 * because object ordering would otherwise be inconsistent 194 * because object ordering would otherwise be inconsistent
204 */ 195 */
205 196
197void
206void esrv_draw_look(object *pl) 198esrv_draw_look (object *pl)
207{ 199{
208 object *tmp, *last; 200 object *tmp, *last;
209 int got_one=0,start_look=0, end_look=0; 201 int got_one = 0, start_look = 0, end_look = 0;
210 SockList sl;
211 char buf[MAX_BUF]; 202 char buf[MAX_BUF];
212 203
213 if (!pl->contr->socket.update_look) { 204 if (!pl->contr->socket.update_look)
205 {
214 LOG(llevDebug,"esrv_draw_look called when update_look was not set\n"); 206 LOG (llevDebug, "esrv_draw_look called when update_look was not set\n");
215 return; 207 return;
216 } else { 208 }
209 else
217 pl->contr->socket.update_look=0; 210 pl->contr->socket.update_look = 0;
218 }
219 211
220 if(QUERY_FLAG(pl, FLAG_REMOVED) || pl->map == NULL || 212 if (QUERY_FLAG (pl, FLAG_REMOVED)
221 pl->map->in_memory != MAP_IN_MEMORY || out_of_map(pl->map,pl->x,pl->y)) 213 || !pl->map
214 || pl->map->in_memory != MAP_IN_MEMORY
215 || out_of_map (pl->map, pl->x, pl->y))
222 return; 216 return;
223 217
224 for (tmp=get_map_ob(pl->map,pl->x,pl->y); tmp && tmp->above;tmp=tmp->above) ; 218 for (tmp = get_map_ob (pl->map, pl->x, pl->y); tmp && tmp->above; tmp = tmp->above)
219 ;
225 220
226 sl.buf= (unsigned char *) malloc(MAXSOCKBUF); 221 packet sl;
227 222
228 Write_String_To_Socket(&pl->contr->socket, "delinv 0", strlen("delinv 0")); 223 pl->contr->socket.send_packet ("delinv 0");
224
229 sprintf((char*)sl.buf,"item%d ", pl->contr->socket.itemcmd); 225 sl.printf ("item%d ", pl->contr->socket.itemcmd);
230 sl.len=strlen((char*)sl.buf);
231 226
232 SockList_AddInt(&sl, 0); 227 sl << uint32 (0);
233 228
234 if (!(pl->contr->socket.faces_sent[empty_face->number]&NS_FACESENT_FACE)) 229 if (!(pl->contr->socket.faces_sent[empty_face->number] & NS_FACESENT_FACE))
235 esrv_send_face(&pl->contr->socket, empty_face->number,0); 230 esrv_send_face (&pl->contr->socket, empty_face->number, 0);
236 231
237 if (pl->contr->socket.look_position) { 232 if (pl->contr->socket.look_position)
233 {
238 SockList_AddInt(&sl, 0x80000000 | (pl->contr->socket.look_position- NUM_LOOK_OBJECTS)); 234 sl << uint32 (0x80000000 | (pl->contr->socket.look_position - NUM_LOOK_OBJECTS))
239 SockList_AddInt(&sl, 0); 235 << uint32 (0)
240 SockList_AddInt(&sl, (uint32) -1); 236 << sint32 (-1)
241 SockList_AddInt(&sl, empty_face->number); 237 << uint32 (empty_face->number);
238
242 sprintf(buf,"Click here to see %d previous items", NUM_LOOK_OBJECTS); 239 sl.printf ("Click here to see %d previous items", NUM_LOOK_OBJECTS);
243 add_stringlen_to_sockbuf(buf, &sl); 240
244 SockList_AddShort(&sl,0); 241 sl << uint16 (0)
245 SockList_AddChar(&sl, 0); 242 << uint8 (0)
246 SockList_AddInt(&sl, 0); 243 << uint32 (0);
244
247 if (pl->contr->socket.itemcmd == 2) 245 if (pl->contr->socket.itemcmd == 2)
248 SockList_AddShort(&sl, 0); 246 sl << uint16 (0);
249 } 247 }
250 248
251 for (last=NULL; tmp!=last; tmp=tmp->below) { 249 for (last = NULL; tmp != last; tmp = tmp->below)
250 {
252 object *head; 251 object *head;
253 252
254 if (QUERY_FLAG(tmp, FLAG_IS_FLOOR) && !last) { 253 if (QUERY_FLAG (tmp, FLAG_IS_FLOOR) && !last)
254 {
255 last = tmp->below; /* assumes double floor mode */ 255 last = tmp->below; /* assumes double floor mode */
256 if (last && QUERY_FLAG(last, FLAG_IS_FLOOR)) 256 if (last && QUERY_FLAG (last, FLAG_IS_FLOOR))
257 last = last->below; 257 last = last->below;
258 } 258 }
259
259 if (LOOK_OBJ(tmp)) { 260 if (LOOK_OBJ (tmp))
261 {
260 if (++start_look < pl->contr->socket.look_position) continue; 262 if (++start_look < pl->contr->socket.look_position)
263 continue;
264
261 end_look++; 265 end_look++;
266
262 if (end_look > NUM_LOOK_OBJECTS) { 267 if (end_look > NUM_LOOK_OBJECTS)
268 {
263 /* What we basically do is make a 'fake' object - when the user applies it, 269 /* What we basically do is make a 'fake' object - when the user applies it,
264 * we notice the special tag the object has, and act accordingly. 270 * we notice the special tag the object has, and act accordingly.
265 */ 271 */
266 SockList_AddInt(&sl, 0x80000000 | (pl->contr->socket.look_position+ NUM_LOOK_OBJECTS)); 272 sl << uint32 (0x80000000 | (pl->contr->socket.look_position + NUM_LOOK_OBJECTS))
267 SockList_AddInt(&sl, 0); 273 << uint32 (0)
268 SockList_AddInt(&sl, (uint32) -1); 274 << uint32 ((uint32) - 1)
269 SockList_AddInt(&sl, empty_face->number); 275 << uint32 (empty_face->number);
276
270 sprintf(buf,"Click here to see next group of items"); 277 sl.printf ("Click here to see next group of items");
271 add_stringlen_to_sockbuf(buf, &sl); 278
272 SockList_AddShort(&sl,0); 279 sl << uint16 (0)
273 SockList_AddChar(&sl, 0); 280 << uint8 (0)
274 SockList_AddInt(&sl, 0); 281 << uint32 (0);
282
275 if (pl->contr->socket.itemcmd == 2) 283 if (pl->contr->socket.itemcmd == 2)
276 SockList_AddShort(&sl, 0); 284 sl << uint16 (0);
277 break;
278 }
279 if (tmp->head) head = tmp->head;
280 else head = tmp;
281 285
286 break;
287 }
288
289 if (tmp->head)
290 head = tmp->head;
291 else
292 head = tmp;
293
282 add_object_to_socklist(&pl->contr->socket, &sl, head); 294 add_object_to_socklist (pl->contr->socket, sl, head);
283 got_one++; 295 got_one++;
284 296
285 if (sl.len >= (MAXSOCKBUF-MAXITEMLEN)) { 297 if (sl.len >= (MAXSOCKBUF - MAXITEMLEN))
298 {
286 Send_With_Handling(&pl->contr->socket, &sl); 299 Send_With_Handling (&pl->contr->socket, &sl);
287 sprintf((char*)sl.buf,"item%d ", pl->contr->socket.itemcmd); 300
288 sl.len=strlen((char*)sl.buf); 301 sl.reset ();
289 SockList_AddInt(&sl, 0); 302 sl.printf ("item%d ", pl->contr->socket.itemcmd);
290 got_one=0; 303 sl << uint32 (0);
304 got_one = 0;
305 }
306 } /* If LOOK_OBJ() */
291 } 307 }
292 } /* If LOOK_OBJ() */ 308
293 }
294 if (got_one) 309 if (got_one)
295 Send_With_Handling(&pl->contr->socket, &sl); 310 Send_With_Handling (&pl->contr->socket, &sl);
296 311
297 free(sl.buf);
298} 312}
299 313
300/** 314/**
301 * Sends whole inventory. 315 * Sends whole inventory.
302 */ 316 */
317void
303void esrv_send_inventory(object *pl, object *op) 318esrv_send_inventory (object *pl, object *op)
304{ 319{
305 object *tmp; 320 object *tmp;
306 int got_one=0; 321 int got_one = 0;
307 SockList sl; 322
323 packet sl;
324
325 sl.printf ("delinv %d", op->count);
326 Send_With_Handling (&pl->contr->socket, &sl);
327
328 sl.reset ();
329 sl.printf ("item%d ", pl->contr->socket.itemcmd);
330
331 sl << uint32 (op->count);
332
333 for (tmp = op->inv; tmp; tmp = tmp->below)
308 334 {
309 sl.buf= (unsigned char *) malloc(MAXSOCKBUF); 335 object *head;
310 336
311 sprintf((char*)sl.buf,"delinv %d", op->count); 337 if (tmp->head)
338 head = tmp->head;
339 else
340 head = tmp;
341
342 if (LOOK_OBJ (head))
343 {
344 add_object_to_socklist (pl->contr->socket, sl, head);
345
346 got_one++;
347
348 /* IT is possible for players to accumulate a huge amount of
349 * items (especially with some of the bags out there) to
350 * overflow the buffer. IF so, send multiple item commands.
351 */
352 if (sl.len >= (MAXSOCKBUF - MAXITEMLEN))
353 {
354 Send_With_Handling (&pl->contr->socket, &sl);
355 sprintf ((char *) sl.buf, "item%d ", pl->contr->socket.itemcmd);
312 sl.len=strlen((char*)sl.buf); 356 sl.len = strlen ((char *) sl.buf);
357 sl << uint32 (op->count);
358 got_one = 0;
359 }
360 } /* If LOOK_OBJ() */
361 }
362
363 if (got_one)
313 Send_With_Handling(&pl->contr->socket, &sl); 364 Send_With_Handling (&pl->contr->socket, &sl);
314 365
315 sprintf((char*)sl.buf,"item%d ", pl->contr->socket.itemcmd);
316 sl.len=strlen((char*)sl.buf);
317
318 SockList_AddInt(&sl, op->count);
319
320 for (tmp=op->inv; tmp; tmp=tmp->below) {
321 object *head;
322
323 if (tmp->head) head = tmp->head;
324 else head = tmp;
325
326 if (LOOK_OBJ(head)) {
327 add_object_to_socklist(&pl->contr->socket, &sl, head);
328
329 got_one++;
330
331 /* IT is possible for players to accumulate a huge amount of
332 * items (especially with some of the bags out there) to
333 * overflow the buffer. IF so, send multiple item commands.
334 */
335 if (sl.len >= (MAXSOCKBUF-MAXITEMLEN)) {
336 Send_With_Handling(&pl->contr->socket, &sl);
337 sprintf((char*)sl.buf,"item%d ", pl->contr->socket.itemcmd);
338 sl.len=strlen((char*)sl.buf);
339 SockList_AddInt(&sl, op->count);
340 got_one=0;
341 }
342 } /* If LOOK_OBJ() */
343 }
344 if (got_one)
345 Send_With_Handling(&pl->contr->socket, &sl);
346 free(sl.buf);
347} 366}
348 367
349/** 368/**
350 * Updates object *op for player *pl. 369 * Updates object *op for player *pl.
351 * 370 *
352 * flags is a list of values to update 371 * flags is a list of values to update
353 * to the client (as defined in newclient.h - might as well use the 372 * to the client (as defined in newclient.h - might as well use the
354 * same value both places. 373 * same value both places.
355 */ 374 */
356 375
376void
357void esrv_update_item(int flags, object *pl, object *op) 377esrv_update_item (int flags, object *pl, object *op)
358{ 378{
359 SockList sl;
360
361 /* If we have a request to send the player item, skip a few checks. */ 379 /* If we have a request to send the player item, skip a few checks. */
362 if (op!=pl) { 380 if (op != pl)
381 {
363 if (! LOOK_OBJ(op)) 382 if (!LOOK_OBJ (op))
364 return; 383 return;
365 /* we remove the check for op->env, because in theory, the object 384 /* we remove the check for op->env, because in theory, the object
366 * is hopefully in the same place, so the client should preserve 385 * is hopefully in the same place, so the client should preserve
367 * order. 386 * order.
368 */ 387 */
369 } 388 }
389
370 if (!QUERY_FLAG(op, FLAG_CLIENT_SENT)) { 390 if (!QUERY_FLAG (op, FLAG_CLIENT_SENT))
391 {
371 /* FLAG_CLIENT_SENT is debug only. We are using it to see where 392 /* FLAG_CLIENT_SENT is debug only. We are using it to see where
372 * this is happening - we can set a breakpoint here in the debugger 393 * this is happening - we can set a breakpoint here in the debugger
373 * and track back the call. 394 * and track back the call.
374 */ 395 */
375 LOG(llevDebug,"We have not sent item %s (%d)\n", op->name, op->count); 396 LOG (llevDebug, "We have not sent item %s (%d)\n", &op->name, op->count);
376 } 397 }
377 sl.buf= (unsigned char *) malloc(MAXSOCKBUF);
378 398
379 strcpy((char*)sl.buf,"upditem "); 399 packet sl;
380 sl.len=strlen((char*)sl.buf);
381 400
382 SockList_AddChar(&sl, (char) flags); 401 sl << "upditem "
402 << uint8 (flags);
383 403
384 if (op->head) op=op->head; 404 if (op->head)
405 op = op->head;
385 406
386 SockList_AddInt(&sl, op->count); 407 sl << uint32 (op->count);
387 408
388 if (flags & UPD_LOCATION) 409 if (flags & UPD_LOCATION)
389 SockList_AddInt(&sl, op->env? op->env->count:0); 410 sl << uint32 (op->env ? op->env->count : 0);
390 411
391 if (flags & UPD_FLAGS) 412 if (flags & UPD_FLAGS)
392 SockList_AddInt(&sl, query_flags(op)); 413 sl << uint32 (query_flags (op));
393 414
394 if (flags & UPD_WEIGHT) { 415 if (flags & UPD_WEIGHT)
416 {
395 sint32 weight = WEIGHT(op); 417 sint32 weight = WEIGHT (op);
396 418
397 SockList_AddInt(&sl, QUERY_FLAG(op, FLAG_NO_PICK) ? -1 : weight); 419 sl << uint32 (QUERY_FLAG (op, FLAG_NO_PICK) ? -1 : weight);
398 if (pl == op) { 420
421 if (pl == op)
399 op->contr->last_weight = weight; 422 op->contr->last_weight = weight;
400 }
401 } 423 }
402 424
403 if (flags & UPD_FACE) { 425 if (flags & UPD_FACE)
426 {
404 if (!(pl->contr->socket.faces_sent[op->face->number] & NS_FACESENT_FACE)) 427 if (!(pl->contr->socket.faces_sent[op->face->number] & NS_FACESENT_FACE))
405 esrv_send_face(&pl->contr->socket, op->face->number,0); 428 esrv_send_face (&pl->contr->socket, op->face->number, 0);
406 SockList_AddInt(&sl, op->face->number); 429
430 sl << uint32 (op->face->number);
407 } 431 }
432
408 if (flags & UPD_NAME) { 433 if (flags & UPD_NAME)
409 int len; 434 {
435 int len;
410 const char *item_p; 436 const char *item_p;
411 char item_n[MAX_BUF]; 437 char item_n[MAX_BUF];
412 438
413 if (!op->custom_name) { 439 if (!op->custom_name)
440 {
414 strncpy(item_n,query_base_name(op, 0),127); 441 strncpy (item_n, query_base_name (op, 0), 127);
415 item_n[127]=0; 442 item_n[127] = 0;
416 len=strlen(item_n); 443 len = strlen (item_n);
417 item_p=query_base_name(op, 1); 444 item_p = query_base_name (op, 1);
418 } 445 }
419 else { 446 else
447 {
420 strncpy(item_n,op->custom_name,127); 448 strncpy (item_n, op->custom_name, 127);
421 item_n[127]=0; 449 item_n[127] = 0;
422 len=strlen(item_n); 450 len = strlen (item_n);
423 item_p=op->custom_name; 451 item_p = op->custom_name;
424 } 452 }
425 453
426 strncpy(item_n+len+1, item_p, 127); 454 strncpy (item_n + len + 1, item_p, 127);
427 item_n[254]=0; 455 item_n[254] = 0;
428 len += strlen(item_n+1+len) + 1; 456 len += strlen (item_n + 1 + len) + 1;
429 SockList_AddChar(&sl, (char)len); 457
430 memcpy(sl.buf+sl.len, item_n, len); 458 sl << data8 (item_n, len);
431 sl.len += len;
432 } 459 }
460
433 if (flags & UPD_ANIM) 461 if (flags & UPD_ANIM)
434 SockList_AddShort(&sl,op->animation_id); 462 sl << uint16 (op->animation_id);
435 463
436 if (flags & UPD_ANIMSPEED) { 464 if (flags & UPD_ANIMSPEED)
465 {
437 int anim_speed=0; 466 int anim_speed = 0;
467
438 if (QUERY_FLAG(op,FLAG_ANIMATE)) { 468 if (QUERY_FLAG (op, FLAG_ANIMATE))
439 if (op->anim_speed) anim_speed=op->anim_speed; 469 {
440 else { 470 if (op->anim_speed)
441 if (FABS(op->speed)<0.001) anim_speed=255; 471 anim_speed = op->anim_speed;
442 else if (FABS(op->speed)>=1.0) anim_speed=1; 472 else
473 {
474 if (FABS (op->speed) < 0.001)
475 anim_speed = 255;
476 else if (FABS (op->speed) >= 1.0)
477 anim_speed = 1;
478 else
443 else anim_speed = (int) (1.0/FABS(op->speed)); 479 anim_speed = (int) (1.0 / FABS (op->speed));
480 }
481
482 if (anim_speed > 255)
483 anim_speed = 255;
484 }
485
486 sl << uint8 (anim_speed);
444 } 487 }
445 if (anim_speed>255) anim_speed=255; 488
446 }
447 SockList_AddChar(&sl, (char)anim_speed);
448 }
449 if (flags & UPD_NROF) 489 if (flags & UPD_NROF)
450 SockList_AddInt(&sl, op->nrof); 490 sl << uint32 (op->nrof);
451 491
452 Send_With_Handling(&pl->contr->socket, &sl); 492 Send_With_Handling (&pl->contr->socket, &sl);
453 free(sl.buf);
454} 493}
455 494
456/** 495/**
457 * Sends item's info to player. 496 * Sends item's info to player.
458 */ 497 */
498void
459void esrv_send_item(object *pl, object*op) 499esrv_send_item (object *pl, object *op)
460{ 500{
461 SockList sl;
462
463 /* If this is not the player object, do some more checks */ 501 /* If this is not the player object, do some more checks */
464 if (op!=pl) { 502 if (op != pl)
503 {
465 /* We only send 'visibile' objects to the client */ 504 /* We only send 'visibile' objects to the client */
466 if (! LOOK_OBJ(op)) 505 if (!LOOK_OBJ (op))
467 return; 506 return;
468 /* if the item is on the ground, mark that the look needs to 507 /* if the item is on the ground, mark that the look needs to
469 * be updated. 508 * be updated.
470 */ 509 */
471 if (!op->env) { 510 if (!op->env)
511 {
472 pl->contr->socket.update_look=1; 512 pl->contr->socket.update_look = 1;
473 return; 513 return;
474 } 514 }
475 } 515 }
476 516
477 sl.buf= (unsigned char *) malloc(MAXSOCKBUF); 517 packet sl;
478 518
479 sprintf((char*)sl.buf,"item%d ", pl->contr->socket.itemcmd); 519 sl.printf ("item%d ", pl->contr->socket.itemcmd);
480 sl.len=strlen((char*)sl.buf);
481 520
482 if (op->head) op=op->head; 521 if (op->head)
522 op = op->head;
483 523
484 SockList_AddInt(&sl, op->env? op->env->count:0); 524 sl << uint32 (op->env ? op->env->count : 0);
485 525
486 add_object_to_socklist(&pl->contr->socket, &sl, op); 526 add_object_to_socklist (pl->contr->socket, sl, op);
487 527
488 Send_With_Handling(&pl->contr->socket, &sl); 528 Send_With_Handling (&pl->contr->socket, &sl);
489 SET_FLAG(op, FLAG_CLIENT_SENT); 529 SET_FLAG (op, FLAG_CLIENT_SENT);
490 free(sl.buf); 530
491} 531}
492 532
493/** 533/**
494 * Tells the client to delete an item. Uses the item 534 * Tells the client to delete an item. Uses the item
495 * command with a -1 location. 535 * command with a -1 location.
496 */ 536 */
497 537
538void
498void esrv_del_item(player *pl, int tag) 539esrv_del_item (player *pl, int tag)
499{ 540{
500 SockList sl; 541 packet sl;
501 542
502 sl.buf= (unsigned char *) malloc(MAXSOCKBUF); 543 sl << "delitem "
544 << uint32 (tag);
503 545
504 strcpy((char*)sl.buf,"delitem ");
505 sl.len=strlen((char*)sl.buf);
506 SockList_AddInt(&sl, tag);
507
508 Send_With_Handling(&pl->socket, &sl); 546 Send_With_Handling (&pl->socket, &sl);
509 free(sl.buf);
510} 547}
511 548
512 549
513/******************************************************************************* 550/*******************************************************************************
514 * 551 *
519/** 556/**
520 * Takes a player and object count (tag) and returns the actual object 557 * Takes a player and object count (tag) and returns the actual object
521 * pointer, or null if it can't be found. 558 * pointer, or null if it can't be found.
522 */ 559 */
523 560
561object *
524object *esrv_get_ob_from_count(object *pl, tag_t count) 562esrv_get_ob_from_count (object *pl, tag_t count)
525{ 563{
526 object *op, *tmp; 564 object *op, *tmp;
527 565
528 if (pl->count == count) 566 if (pl->count == count)
529 return pl; 567 return pl;
530 568
531 for(op = pl->inv; op; op = op->below) 569 for (op = pl->inv; op; op = op->below)
532 if (op->count == count) 570 if (op->count == count)
533 return op; 571 return op;
534 else if (op->type == CONTAINER && pl->container == op) 572 else if (op->type == CONTAINER && pl->container == op)
535 for(tmp = op->inv; tmp; tmp = tmp->below) 573 for (tmp = op->inv; tmp; tmp = tmp->below)
536 if (tmp->count == count) 574 if (tmp->count == count)
537 return tmp; 575 return tmp;
538 576
539 for(op = get_map_ob (pl->map, pl->x, pl->y); op; op = op->above) 577 for (op = get_map_ob (pl->map, pl->x, pl->y); op; op = op->above)
540 if (op->head != NULL && op->head->count == count) 578 if (op->head != NULL && op->head->count == count)
541 return op; 579 return op;
542 else if (op->count == count) 580 else if (op->count == count)
543 return op; 581 return op;
544 else if (op->type == CONTAINER && pl->container == op) 582 else if (op->type == CONTAINER && pl->container == op)
545 for(tmp = op->inv; tmp; tmp = tmp->below) 583 for (tmp = op->inv; tmp; tmp = tmp->below)
546 if (tmp->count == count) 584 if (tmp->count == count)
547 return tmp; 585 return tmp;
548 586
549 return NULL; 587 return NULL;
550} 588}
551 589
552 590
553/** Client wants to examine some object. So lets do so. */ 591/** Client wants to examine some object. So lets do so. */
592void
554void ExamineCmd(char *buf, int len,player *pl) 593ExamineCmd (char *buf, int len, player *pl)
555{ 594{
556 long tag = atoi(buf); 595 tag_t tag = atoi (buf);
596
597 /* If the high bit is set, player examined a pseudo object. */
598 if (tag & 0x80000000)
599 return;
600
557 object *op = esrv_get_ob_from_count(pl->ob, tag); 601 object *op = esrv_get_ob_from_count (pl->ob, tag);
558 602
559 if (!op) { 603 if (!op)
604 {
560 LOG(llevDebug, "Player '%s' tried to examine the unknown object (%ld)\n", 605 LOG (llevDebug, "Player '%s' tried to examine the unknown object (%ld)\n", &pl->ob->name, tag);
561 pl->ob->name, tag); 606 return;
562 return;
563 } 607 }
608
564 examine (pl->ob, op); 609 examine (pl->ob, op);
565} 610}
566 611
567/** Client wants to apply some object. Lets do so. */ 612/** Client wants to apply some object. Lets do so. */
613void
568void ApplyCmd(char *buf, int len,player *pl) 614ApplyCmd (char *buf, int len, player *pl)
569{ 615{
570 uint32 tag = atoi(buf); 616 tag_t tag = atoi (buf);
571 object *op = esrv_get_ob_from_count(pl->ob, tag);
572 617
573 /* sort of a hack, but if the player saves and the player then manually 618 /* sort of a hack, but if the player saves and the player then manually
574 * applies a savebed (or otherwise tries to do stuff), we run into trouble. 619 * applies a savebed (or otherwise tries to do stuff), we run into trouble.
575 */ 620 */
576 if (QUERY_FLAG(pl->ob, FLAG_REMOVED)) return; 621 if (QUERY_FLAG (pl->ob, FLAG_REMOVED))
622 return;
577 623
578 /* If the high bit is set, player applied a pseudo object. */ 624 /* If the high bit is set, player applied a pseudo object. */
579 if (tag & 0x80000000) { 625 if (tag & 0x80000000)
626 {
580 pl->socket.look_position = tag & 0x7fffffff; 627 pl->socket.look_position = tag & 0x7fffffff;
581 pl->socket.update_look = 1; 628 pl->socket.update_look = 1;
582 return; 629 return;
583 } 630 }
584 631
632 object *op = esrv_get_ob_from_count (pl->ob, tag);
633
585 if (!op) { 634 if (!op)
635 {
586 LOG(llevDebug, "Player '%s' tried to apply the unknown object (%d)\n", 636 LOG (llevDebug, "Player '%s' tried to apply the unknown object (%d)\n", &pl->ob->name, tag);
587 pl->ob->name, tag); 637 return;
588 return;
589 } 638 }
639
590 player_apply (pl->ob, op, 0, 0); 640 player_apply (pl->ob, op, 0, 0);
591} 641}
592 642
593/** Client wants to apply some object. Lets do so. */ 643/** Client wants to apply some object. Lets do so. */
644void
594void LockItem(uint8 *data, int len,player *pl) 645LockItem (uint8 *data, int len, player *pl)
595{ 646{
596 int flag, tag;
597 object *op;
598
599 flag = data[0]; 647 int flag = data[0];
600 tag = GetInt_String(data+1); 648 tag_t tag = net_uint32 (data + 1);
601 op = esrv_get_ob_from_count(pl->ob, tag); 649 object *op = esrv_get_ob_from_count (pl->ob, tag);
602 650
603 if (!op) { 651 if (!op)
652 {
604 new_draw_info(NDI_UNIQUE, 0, pl->ob,"Could not find object to lock/unlock"); 653 new_draw_info (NDI_UNIQUE, 0, pl->ob, "Could not find object to lock/unlock");
605 return; 654 return;
606 } 655 }
656
607 if (!flag) 657 if (!flag)
608 CLEAR_FLAG(op,FLAG_INV_LOCKED); 658 CLEAR_FLAG (op, FLAG_INV_LOCKED);
609 else 659 else
610 SET_FLAG(op,FLAG_INV_LOCKED); 660 SET_FLAG (op, FLAG_INV_LOCKED);
661
611 esrv_update_item(UPD_FLAGS, pl->ob, op); 662 esrv_update_item (UPD_FLAGS, pl->ob, op);
612} 663}
613 664
614/** Client wants to apply some object. Lets do so. */ 665/** Client wants to apply some object. Lets do so. */
666void
615void MarkItem(uint8 *data, int len,player *pl) 667MarkItem (uint8 * data, int len, player *pl)
616{ 668{
617 int tag; 669 tag_t tag = net_uint32 (data);
618 object *op;
619
620 tag = GetInt_String(data);
621 op = esrv_get_ob_from_count(pl->ob, tag); 670 object *op = esrv_get_ob_from_count (pl->ob, tag);
671
622 if (!op) { 672 if (!op)
673 {
623 new_draw_info(NDI_UNIQUE, 0, pl->ob,"Could not find object to mark"); 674 new_draw_info (NDI_UNIQUE, 0, pl->ob, "Could not find object to mark");
624 return; 675 return;
625 } 676 }
677
626 pl->mark = op; 678 pl->mark = op;
627 pl->mark_count = op->count;
628 new_draw_info_format(NDI_UNIQUE, 0, pl->ob, "Marked item %s", query_name(op)); 679 new_draw_info_format (NDI_UNIQUE, 0, pl->ob, "Marked item %s", query_name (op));
629} 680}
630
631 681
632/** 682/**
633 * look_at prints items on the specified square. 683 * look_at prints items on the specified square.
634 * 684 *
635 * [ removed EARTHWALL check and added check for containers inventory. 685 * [ removed EARTHWALL check and added check for containers inventory.
636 * Tero.Haatanen@lut.fi ] 686 * Tero.Haatanen@lut.fi ]
637 */ 687 */
688void
638void look_at(object *op,int dx,int dy) { 689look_at (object *op, int dx, int dy)
690{
639 object *tmp; 691 object *tmp;
640 int flag=0; 692 int flag = 0;
641 sint16 x,y; 693 sint16 x, y;
642 mapstruct *m; 694 maptile *m;
643 695
644 x = op->x + dx; 696 x = op->x + dx;
645 y = op->y + dy; 697 y = op->y + dy;
646 698
647 if (out_of_map(op->map, x, y)) return; 699 if (out_of_map (op->map, x, y))
700 return;
648 701
649 m = get_map_from_coord(op->map, &x, &y); 702 m = get_map_from_coord (op->map, &x, &y);
650 if (!m) return; 703 if (!m)
704 return;
651 705
652 for(tmp=get_map_ob(m, x ,y);tmp!=NULL&&tmp->above!=NULL; 706 for (tmp = get_map_ob (m, x, y); tmp != NULL && tmp->above != NULL; tmp = tmp->above);
653 tmp=tmp->above);
654 707
655 for ( ; tmp != NULL; tmp=tmp->below ) { 708 for (; tmp != NULL; tmp = tmp->below)
709 {
656 if (tmp->invisible && !QUERY_FLAG(op, FLAG_WIZ)) continue; 710 if (tmp->invisible && !QUERY_FLAG (op, FLAG_WIZ))
711 continue;
657 712
658 if(!flag) { 713 if (!flag)
659 if(dx||dy) 714 {
715 if (dx || dy)
660 new_draw_info(NDI_UNIQUE, 0,op,"There you see:"); 716 new_draw_info (NDI_UNIQUE, 0, op, "There you see:");
661 else { 717 else
662 clear_win_info(op); 718 {
719 clear_win_info (op);
663 new_draw_info(NDI_UNIQUE, 0,op,"You see:"); 720 new_draw_info (NDI_UNIQUE, 0, op, "You see:");
664 } 721 }
665 flag=1; 722 flag = 1;
666 } 723 }
667 724
668 if (QUERY_FLAG(op, FLAG_WIZ)) 725 if (QUERY_FLAG (op, FLAG_WIZ))
669 new_draw_info_format(NDI_UNIQUE,0, op, "- %s (%d).",query_name(tmp),tmp->count); 726 new_draw_info_format (NDI_UNIQUE, 0, op, "- %s (%d).", query_name (tmp), tmp->count);
670 else 727 else
671 new_draw_info_format(NDI_UNIQUE,0, op, "- %s.",query_name(tmp)); 728 new_draw_info_format (NDI_UNIQUE, 0, op, "- %s.", query_name (tmp));
672 729
673 if (((tmp->inv!=NULL || (tmp->head && tmp->head->inv)) && 730 if (((tmp->inv != NULL || (tmp->head && tmp->head->inv)) &&
674 (tmp->type != CONTAINER && tmp->type!=FLESH)) || QUERY_FLAG(op, FLAG_WIZ)) 731 (tmp->type != CONTAINER && tmp->type != FLESH)) || QUERY_FLAG (op, FLAG_WIZ))
675 inventory(op,tmp->head==NULL?tmp:tmp->head); 732 inventory (op, tmp->head == NULL ? tmp : tmp->head);
676 733
677 if(QUERY_FLAG(tmp, FLAG_IS_FLOOR)&&!QUERY_FLAG(op, FLAG_WIZ)) /* don't continue under the floor */ 734 if (QUERY_FLAG (tmp, FLAG_IS_FLOOR) && !QUERY_FLAG (op, FLAG_WIZ)) /* don't continue under the floor */
678 break; 735 break;
679 } 736 }
680 737
681 if(!flag) { 738 if (!flag)
682 if(dx||dy) 739 {
740 if (dx || dy)
683 new_draw_info(NDI_UNIQUE, 0,op,"You see nothing there."); 741 new_draw_info (NDI_UNIQUE, 0, op, "You see nothing there.");
684 else 742 else
685 new_draw_info(NDI_UNIQUE, 0,op,"You see nothing."); 743 new_draw_info (NDI_UNIQUE, 0, op, "You see nothing.");
686 } 744 }
687} 745}
688 746
689 747
690 748
691/** Client wants to look at some object. Lets do so. */ 749/** Client wants to look at some object. Lets do so. */
750void
692void LookAt(char *buf, int len,player *pl) 751LookAt (char *buf, int len, player *pl)
693{ 752{
694 int dx, dy; 753 int dx, dy;
695 char *cp; 754 char *cp;
696 755
697 dx=atoi(buf); 756 dx = atoi (buf);
698 if (!(cp=strchr(buf,' '))) { 757 if (!(cp = strchr (buf, ' ')))
699 return;
700 } 758 {
759 return;
760 }
701 dy=atoi(cp); 761 dy = atoi (cp);
702 762
703 if (FABS(dx) > pl->socket.mapx / 2 || FABS(dy) > pl->socket.mapy / 2) 763 if (FABS (dx) > pl->socket.mapx / 2 || FABS (dy) > pl->socket.mapy / 2)
704 return; 764 return;
705 765
706 if(pl->blocked_los[dx + pl->socket.mapx / 2][dy + pl->socket.mapy / 2]) 766 if (pl->blocked_los[dx + pl->socket.mapx / 2][dy + pl->socket.mapy / 2])
707 return; 767 return;
708 768
709 look_at(pl->ob, dx, dy); 769 look_at (pl->ob, dx, dy);
710} 770}
711 771
712/** Move an object to a new location */ 772/** Move an object to a new location */
773void
713void esrv_move_object (object *pl, tag_t to, tag_t tag, long nrof) 774esrv_move_object (object *pl, tag_t to, tag_t tag, long nrof)
714{ 775{
715 object *op, *env; 776 object *op, *env;
716 777
717 op = esrv_get_ob_from_count(pl, tag); 778 op = esrv_get_ob_from_count (pl, tag);
718 if (!op) { 779 if (!op)
780 {
719 LOG(llevDebug, "Player '%s' tried to move an unknown object (%ld)\n", 781 LOG (llevDebug, "Player '%s' tried to move an unknown object (%ld)\n", &pl->name, tag);
720 pl->name, tag);
721 return;
722 }
723
724 if (!to) { /* drop it to the ground */
725/* LOG(llevDebug, "Drop it on the ground.\n");*/
726
727 if (op->map && !op->env) {
728/* LOG(llevDebug,"Dropping object to ground that is already on ground\n");*/
729 return; 782 return;
730 }
731 /* If it is an active container, then we should drop all objects
732 * in the container and not the container itself.
733 */
734 if (op->inv && QUERY_FLAG(op, FLAG_APPLIED)) {
735 object *current, *next;
736 for (current=op->inv; current!=NULL; current=next) {
737 next=current->below;
738 drop_object(pl, current, 0);
739 } 783 }
740 esrv_update_item(UPD_WEIGHT, pl, op);
741 }
742 else {
743 drop_object (pl, op, nrof);
744 }
745 return;
746 } else if (to == pl->count) { /* pick it up to the inventory */
747 /* return if player has already picked it up */
748 if (op->env == pl) return;
749 784
750 pl->contr->count = nrof; 785 if (!to)
751 pick_up(pl, op); 786 { /* drop it to the ground */
752 return ; 787 if (op->map && !op->env)
753 }
754 env = esrv_get_ob_from_count(pl, to);
755 if (!env) {
756 LOG(llevDebug,
757 "Player '%s' tried to move object to the unknown location (%d)\n",
758 pl->name, to);
759 return; 788 return;
789
790 /* If it is an active container, then we should drop all objects
791 * in the container and not the container itself.
792 */
793 if (op->inv && QUERY_FLAG (op, FLAG_APPLIED))
794 {
795 object *current, *next;
796
797 for (current = op->inv; current != NULL; current = next)
798 {
799 next = current->below;
800 drop_object (pl, current, 0);
801 }
802
803 esrv_update_item (UPD_WEIGHT, pl, op);
804 }
805 else
806 {
807 drop_object (pl, op, nrof);
808 }
809 return;
810 }
811 else if (to == pl->count)
812 { /* pick it up to the inventory */
813 /* return if player has already picked it up */
814 if (op->env == pl)
815 return;
816
817 pl->contr->count = nrof;
818 pick_up (pl, op);
819 return;
820 }
821
822 env = esrv_get_ob_from_count (pl, to);
823 if (!env)
760 } 824 {
825 LOG (llevDebug, "Player '%s' tried to move object to the unknown location (%d)\n", &pl->name, to);
826 return;
827 }
828
761 /* put_object_in_sack presumes that necessary sanity checking 829 /* put_object_in_sack presumes that necessary sanity checking
762 * has already been done (eg, it can be picked up and fits in 830 * has already been done (eg, it can be picked up and fits in
763 * in a sack, so check for those things. We should also check 831 * in a sack, so check for those things. We should also check
764 * an make sure env is in fact a container for that matter. 832 * an make sure env is in fact a container for that matter.
765 */ 833 */
766 if (env->type == CONTAINER
767 && can_pick(pl, op) && sack_can_hold(pl, env, op, nrof)) { 834 if (env->type == CONTAINER && can_pick (pl, op) && sack_can_hold (pl, env, op, nrof))
835 {
768 put_object_in_sack (pl, env, op, nrof); 836 put_object_in_sack (pl, env, op, nrof);
769 } 837 }
770} 838}
771 839
772

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines