ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/socket/item.C
Revision: 1.10
Committed: Wed Sep 27 00:36:09 2006 UTC (17 years, 8 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.9: +11 -3 lines
Log Message:
* nuke op->contr when players log out, to avoid dereferencing them later :(
* also rename free to destroy
* do not create weird messages when people examine pseudo inventory objects

File Contents

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