ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/socket/item.C
Revision: 1.3
Committed: Tue Aug 29 08:01:38 2006 UTC (17 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.2: +283 -283 lines
Log Message:
expand initial tabs to spaces

File Contents

# User Rev Content
1 elmex 1.1
2     /*
3     * static char *rcsid_item_c =
4 root 1.3 * "$Id: item.C,v 1.2 2006-08-29 07:34:01 root Exp $";
5 elmex 1.1 */
6    
7     /*
8     CrossFire, A Multiplayer game for X-windows
9    
10     Copyright (C) 2002 Mark Wedel & Crossfire Development Team
11     Copyright (C) 1992 Frank Tore Johansen
12    
13     This program is free software; you can redistribute it and/or modify
14     it under the terms of the GNU General Public License as published by
15     the Free Software Foundation; either version 2 of the License, or
16     (at your option) any later version.
17    
18     This program is distributed in the hope that it will be useful,
19     but WITHOUT ANY WARRANTY; without even the implied warranty of
20     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21     GNU General Public License for more details.
22    
23     You should have received a copy of the GNU General Public License
24     along with this program; if not, write to the Free Software
25     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26    
27     The author can be reached via e-mail to crossfire-devel@real-time.com
28     */
29    
30     /**
31     * \file
32     * Client/server logic.
33     *
34     * \date 2003-12-02
35     *
36     * This containes item logic for client/server. It doesn't contain
37     * the actual commands that send the data, but does contain
38     * the logic for what items should be sent.
39     */
40    
41    
42     #include <global.h>
43     #include <object.h> /* LOOK_OBJ */
44     #include <newclient.h>
45     #include <newserver.h>
46     #include <sproto.h>
47    
48     /** This is the maximum number of bytes we expect any one item to take up */
49     #define MAXITEMLEN 300
50    
51     /*******************************************************************************
52     *
53     * Functions related to sending object data to the client.
54     *
55     ******************************************************************************/
56    
57     /**
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     */
65     inline 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
78     * to be sended to client.
79     */
80     unsigned int query_flags (object *op)
81     {
82     unsigned int flags = 0;
83    
84     if(QUERY_FLAG(op,FLAG_APPLIED)) {
85 root 1.3 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 elmex 1.1 }
116     if (op->type == CONTAINER && ((op->env && op->env->container == op) ||
117 root 1.3 (!op->env && QUERY_FLAG(op,FLAG_APPLIED))))
118     flags |= F_OPEN;
119 elmex 1.1
120     if (QUERY_FLAG(op,FLAG_KNOWN_CURSED)) {
121 root 1.3 if(QUERY_FLAG(op,FLAG_DAMNED))
122     flags |= F_DAMNED;
123     else if(QUERY_FLAG(op,FLAG_CURSED))
124     flags |= F_CURSED;
125 elmex 1.1 }
126     if (QUERY_FLAG(op,FLAG_KNOWN_MAGICAL) && !QUERY_FLAG(op,FLAG_IDENTIFIED))
127 root 1.3 flags |= F_MAGIC;
128 elmex 1.1 if (QUERY_FLAG(op,FLAG_UNPAID))
129 root 1.3 flags |= F_UNPAID;
130 elmex 1.1 if (QUERY_FLAG(op,FLAG_INV_LOCKED))
131 root 1.3 flags |= F_LOCKED;
132 elmex 1.1
133     return flags;
134     }
135    
136     /* Used in the send_look to put object head into SockList
137     * sl for socket ns. Need socket to know if we need to send
138     * animation of face to the client.
139     */
140     static void add_object_to_socklist(NewSocket *ns, SockList *sl, object *head)
141     {
142     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 root 1.3 flags |= F_NOPICK;
149 elmex 1.1
150     if (!(ns->faces_sent[head->face->number] & NS_FACESENT_FACE))
151 root 1.3 esrv_send_face(ns, head->face->number,0);
152 elmex 1.1
153     if (QUERY_FLAG(head,FLAG_ANIMATE) && !ns->anims_sent[head->animation_id])
154 root 1.3 esrv_send_animation(ns, head->animation_id);
155 elmex 1.1
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 root 1.3 strncpy(item_n,query_base_name(head, 0),127);
163     item_n[127]=0;
164     len=strlen(item_n);
165     item_p=query_base_name(head, 1);
166 elmex 1.1 } else {
167 root 1.3 strncpy(item_n,head->custom_name,127);
168     item_n[127]=0;
169     len=strlen(item_n);
170     item_p=head->custom_name;
171 elmex 1.1 }
172     strncpy(item_n+len+1, item_p, 127);
173     item_n[254]=0;
174     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    
179     SockList_AddShort(sl,head->animation_id);
180     anim_speed=0;
181     if (QUERY_FLAG(head,FLAG_ANIMATE)) {
182 root 1.3 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 elmex 1.1 }
190     SockList_AddChar(sl, (char) anim_speed);
191     SockList_AddInt(sl, head->nrof);
192    
193     if (ns->itemcmd == 2)
194 root 1.3 SockList_AddShort(sl, head->client_type);
195 elmex 1.1
196     SET_FLAG(head, FLAG_CLIENT_SENT);
197     }
198    
199    
200     /**
201     * 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
203     * because object ordering would otherwise be inconsistent
204     */
205    
206     void esrv_draw_look(object *pl)
207     {
208     object *tmp, *last;
209     int got_one=0,start_look=0, end_look=0;
210     SockList sl;
211     char buf[MAX_BUF];
212    
213     if (!pl->contr->socket.update_look) {
214 root 1.3 LOG(llevDebug,"esrv_draw_look called when update_look was not set\n");
215     return;
216 elmex 1.1 } else {
217 root 1.3 pl->contr->socket.update_look=0;
218 elmex 1.1 }
219    
220     if(QUERY_FLAG(pl, FLAG_REMOVED) || pl->map == NULL ||
221     pl->map->in_memory != MAP_IN_MEMORY || out_of_map(pl->map,pl->x,pl->y))
222 root 1.3 return;
223 elmex 1.1
224 root 1.2 for (tmp=get_map_ob(pl->map,pl->x,pl->y); tmp && tmp->above;tmp=tmp->above) ;
225 elmex 1.1
226     sl.buf= (unsigned char *) malloc(MAXSOCKBUF);
227    
228     Write_String_To_Socket(&pl->contr->socket, "delinv 0", strlen("delinv 0"));
229     sprintf((char*)sl.buf,"item%d ", pl->contr->socket.itemcmd);
230     sl.len=strlen((char*)sl.buf);
231    
232     SockList_AddInt(&sl, 0);
233    
234     if (!(pl->contr->socket.faces_sent[empty_face->number]&NS_FACESENT_FACE))
235 root 1.3 esrv_send_face(&pl->contr->socket, empty_face->number,0);
236 elmex 1.1
237     if (pl->contr->socket.look_position) {
238 root 1.3 SockList_AddInt(&sl, 0x80000000 | (pl->contr->socket.look_position- NUM_LOOK_OBJECTS));
239     SockList_AddInt(&sl, 0);
240     SockList_AddInt(&sl, (uint32) -1);
241     SockList_AddInt(&sl, empty_face->number);
242     sprintf(buf,"Click here to see %d previous items", NUM_LOOK_OBJECTS);
243     add_stringlen_to_sockbuf(buf, &sl);
244     SockList_AddShort(&sl,0);
245     SockList_AddChar(&sl, 0);
246     SockList_AddInt(&sl, 0);
247     if (pl->contr->socket.itemcmd == 2)
248     SockList_AddShort(&sl, 0);
249 elmex 1.1 }
250    
251     for (last=NULL; tmp!=last; tmp=tmp->below) {
252 root 1.3 object *head;
253 elmex 1.1
254 root 1.3 if (QUERY_FLAG(tmp, FLAG_IS_FLOOR) && !last) {
255     last = tmp->below; /* assumes double floor mode */
256     if (last && QUERY_FLAG(last, FLAG_IS_FLOOR))
257     last = last->below;
258     }
259     if (LOOK_OBJ(tmp)) {
260     if (++start_look < pl->contr->socket.look_position) continue;
261     end_look++;
262     if (end_look > NUM_LOOK_OBJECTS) {
263     /* 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.
265     */
266     SockList_AddInt(&sl, 0x80000000 | (pl->contr->socket.look_position+ NUM_LOOK_OBJECTS));
267     SockList_AddInt(&sl, 0);
268     SockList_AddInt(&sl, (uint32) -1);
269     SockList_AddInt(&sl, empty_face->number);
270     sprintf(buf,"Click here to see next group of items");
271     add_stringlen_to_sockbuf(buf, &sl);
272     SockList_AddShort(&sl,0);
273     SockList_AddChar(&sl, 0);
274     SockList_AddInt(&sl, 0);
275     if (pl->contr->socket.itemcmd == 2)
276     SockList_AddShort(&sl, 0);
277     break;
278     }
279     if (tmp->head) head = tmp->head;
280     else head = tmp;
281    
282     add_object_to_socklist(&pl->contr->socket, &sl, head);
283     got_one++;
284    
285     if (sl.len >= (MAXSOCKBUF-MAXITEMLEN)) {
286     Send_With_Handling(&pl->contr->socket, &sl);
287     sprintf((char*)sl.buf,"item%d ", pl->contr->socket.itemcmd);
288     sl.len=strlen((char*)sl.buf);
289     SockList_AddInt(&sl, 0);
290     got_one=0;
291     }
292     } /* If LOOK_OBJ() */
293 elmex 1.1 }
294     if (got_one)
295 root 1.3 Send_With_Handling(&pl->contr->socket, &sl);
296 elmex 1.1
297     free(sl.buf);
298     }
299    
300     /**
301     * Sends whole inventory.
302     */
303     void esrv_send_inventory(object *pl, object *op)
304     {
305     object *tmp;
306     int got_one=0;
307     SockList sl;
308    
309     sl.buf= (unsigned char *) malloc(MAXSOCKBUF);
310    
311     sprintf((char*)sl.buf,"delinv %d", op->count);
312     sl.len=strlen((char*)sl.buf);
313     Send_With_Handling(&pl->contr->socket, &sl);
314    
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 root 1.3 object *head;
322 elmex 1.1
323 root 1.3 if (tmp->head) head = tmp->head;
324     else head = tmp;
325 elmex 1.1
326 root 1.3 if (LOOK_OBJ(head)) {
327     add_object_to_socklist(&pl->contr->socket, &sl, head);
328 elmex 1.1
329 root 1.3 got_one++;
330 elmex 1.1
331 root 1.3 /* 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 elmex 1.1 }
344     if (got_one)
345 root 1.3 Send_With_Handling(&pl->contr->socket, &sl);
346 elmex 1.1 free(sl.buf);
347     }
348    
349     /**
350     * Updates object *op for player *pl.
351     *
352     * flags is a list of values to update
353     * to the client (as defined in newclient.h - might as well use the
354     * same value both places.
355     */
356    
357     void esrv_update_item(int flags, object *pl, object *op)
358     {
359     SockList sl;
360    
361     /* If we have a request to send the player item, skip a few checks. */
362     if (op!=pl) {
363 root 1.3 if (! LOOK_OBJ(op))
364     return;
365     /* we remove the check for op->env, because in theory, the object
366     * is hopefully in the same place, so the client should preserve
367     * order.
368     */
369 elmex 1.1 }
370     if (!QUERY_FLAG(op, FLAG_CLIENT_SENT)) {
371 root 1.3 /* 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
373     * and track back the call.
374     */
375     LOG(llevDebug,"We have not sent item %s (%d)\n", op->name, op->count);
376 elmex 1.1 }
377     sl.buf= (unsigned char *) malloc(MAXSOCKBUF);
378    
379     strcpy((char*)sl.buf,"upditem ");
380     sl.len=strlen((char*)sl.buf);
381    
382     SockList_AddChar(&sl, (char) flags);
383    
384     if (op->head) op=op->head;
385    
386     SockList_AddInt(&sl, op->count);
387    
388     if (flags & UPD_LOCATION)
389 root 1.3 SockList_AddInt(&sl, op->env? op->env->count:0);
390 elmex 1.1
391     if (flags & UPD_FLAGS)
392 root 1.3 SockList_AddInt(&sl, query_flags(op));
393 elmex 1.1
394     if (flags & UPD_WEIGHT) {
395 root 1.3 sint32 weight = WEIGHT(op);
396 elmex 1.1
397 root 1.3 SockList_AddInt(&sl, QUERY_FLAG(op, FLAG_NO_PICK) ? -1 : weight);
398     if (pl == op) {
399     op->contr->last_weight = weight;
400     }
401 elmex 1.1 }
402    
403     if (flags & UPD_FACE) {
404 root 1.3 if (!(pl->contr->socket.faces_sent[op->face->number] & NS_FACESENT_FACE))
405     esrv_send_face(&pl->contr->socket, op->face->number,0);
406     SockList_AddInt(&sl, op->face->number);
407 elmex 1.1 }
408     if (flags & UPD_NAME) {
409 root 1.3 int len;
410     const char *item_p;
411 elmex 1.1 char item_n[MAX_BUF];
412    
413 root 1.3 if (!op->custom_name) {
414     strncpy(item_n,query_base_name(op, 0),127);
415     item_n[127]=0;
416     len=strlen(item_n);
417     item_p=query_base_name(op, 1);
418     }
419     else {
420     strncpy(item_n,op->custom_name,127);
421     item_n[127]=0;
422     len=strlen(item_n);
423     item_p=op->custom_name;
424     }
425    
426     strncpy(item_n+len+1, item_p, 127);
427     item_n[254]=0;
428     len += strlen(item_n+1+len) + 1;
429     SockList_AddChar(&sl, (char)len);
430     memcpy(sl.buf+sl.len, item_n, len);
431     sl.len += len;
432 elmex 1.1 }
433     if (flags & UPD_ANIM)
434 root 1.3 SockList_AddShort(&sl,op->animation_id);
435 elmex 1.1
436     if (flags & UPD_ANIMSPEED) {
437 root 1.3 int anim_speed=0;
438     if (QUERY_FLAG(op,FLAG_ANIMATE)) {
439     if (op->anim_speed) anim_speed=op->anim_speed;
440     else {
441     if (FABS(op->speed)<0.001) anim_speed=255;
442     else if (FABS(op->speed)>=1.0) anim_speed=1;
443     else anim_speed = (int) (1.0/FABS(op->speed));
444     }
445     if (anim_speed>255) anim_speed=255;
446     }
447     SockList_AddChar(&sl, (char)anim_speed);
448 elmex 1.1 }
449     if (flags & UPD_NROF)
450 root 1.3 SockList_AddInt(&sl, op->nrof);
451 elmex 1.1
452     Send_With_Handling(&pl->contr->socket, &sl);
453     free(sl.buf);
454     }
455    
456     /**
457     * Sends item's info to player.
458     */
459     void esrv_send_item(object *pl, object*op)
460     {
461     SockList sl;
462    
463     /* If this is not the player object, do some more checks */
464     if (op!=pl) {
465 root 1.3 /* We only send 'visibile' objects to the client */
466     if (! LOOK_OBJ(op))
467     return;
468     /* if the item is on the ground, mark that the look needs to
469     * be updated.
470     */
471     if (!op->env) {
472     pl->contr->socket.update_look=1;
473     return;
474     }
475 elmex 1.1 }
476    
477     sl.buf= (unsigned char *) malloc(MAXSOCKBUF);
478    
479     sprintf((char*)sl.buf,"item%d ", pl->contr->socket.itemcmd);
480     sl.len=strlen((char*)sl.buf);
481    
482     if (op->head) op=op->head;
483    
484     SockList_AddInt(&sl, op->env? op->env->count:0);
485    
486     add_object_to_socklist(&pl->contr->socket, &sl, op);
487    
488     Send_With_Handling(&pl->contr->socket, &sl);
489     SET_FLAG(op, FLAG_CLIENT_SENT);
490     free(sl.buf);
491     }
492    
493     /**
494     * Tells the client to delete an item. Uses the item
495     * command with a -1 location.
496     */
497    
498     void esrv_del_item(player *pl, int tag)
499     {
500     SockList sl;
501    
502     sl.buf= (unsigned char *) malloc(MAXSOCKBUF);
503    
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);
509     free(sl.buf);
510     }
511    
512    
513     /*******************************************************************************
514     *
515     * Client has requested us to do something with an object.
516     *
517     ******************************************************************************/
518    
519     /**
520     * Takes a player and object count (tag) and returns the actual object
521     * pointer, or null if it can't be found.
522     */
523    
524     object *esrv_get_ob_from_count(object *pl, tag_t count)
525     {
526     object *op, *tmp;
527    
528     if (pl->count == count)
529 root 1.3 return pl;
530 elmex 1.1
531     for(op = pl->inv; op; op = op->below)
532 root 1.3 if (op->count == count)
533     return op;
534     else if (op->type == CONTAINER && pl->container == op)
535     for(tmp = op->inv; tmp; tmp = tmp->below)
536     if (tmp->count == count)
537     return tmp;
538 elmex 1.1
539     for(op = get_map_ob (pl->map, pl->x, pl->y); op; op = op->above)
540 root 1.3 if (op->head != NULL && op->head->count == count)
541     return op;
542     else if (op->count == count)
543     return op;
544     else if (op->type == CONTAINER && pl->container == op)
545     for(tmp = op->inv; tmp; tmp = tmp->below)
546     if (tmp->count == count)
547     return tmp;
548 elmex 1.1
549     return NULL;
550     }
551    
552    
553     /** Client wants to examine some object. So lets do so. */
554     void ExamineCmd(char *buf, int len,player *pl)
555     {
556     long tag = atoi(buf);
557     object *op = esrv_get_ob_from_count(pl->ob, tag);
558    
559     if (!op) {
560 root 1.3 LOG(llevDebug, "Player '%s' tried to examine the unknown object (%ld)\n",
561     pl->ob->name, tag);
562     return;
563 elmex 1.1 }
564     examine (pl->ob, op);
565     }
566    
567     /** Client wants to apply some object. Lets do so. */
568     void ApplyCmd(char *buf, int len,player *pl)
569     {
570     uint32 tag = atoi(buf);
571     object *op = esrv_get_ob_from_count(pl->ob, tag);
572    
573     /* 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.
575     */
576     if (QUERY_FLAG(pl->ob, FLAG_REMOVED)) return;
577    
578     /* If the high bit is set, player applied a pseudo object. */
579     if (tag & 0x80000000) {
580 root 1.3 pl->socket.look_position = tag & 0x7fffffff;
581     pl->socket.update_look = 1;
582     return;
583 elmex 1.1 }
584    
585     if (!op) {
586 root 1.3 LOG(llevDebug, "Player '%s' tried to apply the unknown object (%d)\n",
587     pl->ob->name, tag);
588     return;
589 elmex 1.1 }
590     player_apply (pl->ob, op, 0, 0);
591     }
592    
593     /** Client wants to apply some object. Lets do so. */
594     void LockItem(uint8 *data, int len,player *pl)
595     {
596     int flag, tag;
597     object *op;
598    
599     flag = data[0];
600     tag = GetInt_String(data+1);
601     op = esrv_get_ob_from_count(pl->ob, tag);
602    
603     if (!op) {
604 root 1.3 new_draw_info(NDI_UNIQUE, 0, pl->ob,"Could not find object to lock/unlock");
605     return;
606 elmex 1.1 }
607     if (!flag)
608 root 1.3 CLEAR_FLAG(op,FLAG_INV_LOCKED);
609 elmex 1.1 else
610 root 1.3 SET_FLAG(op,FLAG_INV_LOCKED);
611 elmex 1.1 esrv_update_item(UPD_FLAGS, pl->ob, op);
612     }
613    
614     /** Client wants to apply some object. Lets do so. */
615     void MarkItem(uint8 *data, int len,player *pl)
616     {
617     int tag;
618     object *op;
619    
620     tag = GetInt_String(data);
621     op = esrv_get_ob_from_count(pl->ob, tag);
622     if (!op) {
623 root 1.3 new_draw_info(NDI_UNIQUE, 0, pl->ob,"Could not find object to mark");
624     return;
625 elmex 1.1 }
626     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));
629     }
630    
631    
632     /**
633     * look_at prints items on the specified square.
634     *
635     * [ removed EARTHWALL check and added check for containers inventory.
636     * Tero.Haatanen@lut.fi ]
637     */
638     void look_at(object *op,int dx,int dy) {
639     object *tmp;
640     int flag=0;
641     sint16 x,y;
642     mapstruct *m;
643    
644     x = op->x + dx;
645     y = op->y + dy;
646    
647     if (out_of_map(op->map, x, y)) return;
648    
649     m = get_map_from_coord(op->map, &x, &y);
650     if (!m) return;
651    
652     for(tmp=get_map_ob(m, x ,y);tmp!=NULL&&tmp->above!=NULL;
653 root 1.3 tmp=tmp->above);
654 elmex 1.1
655     for ( ; tmp != NULL; tmp=tmp->below ) {
656 root 1.3 if (tmp->invisible && !QUERY_FLAG(op, FLAG_WIZ)) continue;
657 elmex 1.1
658 root 1.3 if(!flag) {
659     if(dx||dy)
660     new_draw_info(NDI_UNIQUE, 0,op,"There you see:");
661     else {
662     clear_win_info(op);
663     new_draw_info(NDI_UNIQUE, 0,op,"You see:");
664     }
665     flag=1;
666     }
667    
668     if (QUERY_FLAG(op, FLAG_WIZ))
669     new_draw_info_format(NDI_UNIQUE,0, op, "- %s (%d).",query_name(tmp),tmp->count);
670     else
671     new_draw_info_format(NDI_UNIQUE,0, op, "- %s.",query_name(tmp));
672    
673     if (((tmp->inv!=NULL || (tmp->head && tmp->head->inv)) &&
674     (tmp->type != CONTAINER && tmp->type!=FLESH)) || QUERY_FLAG(op, FLAG_WIZ))
675     inventory(op,tmp->head==NULL?tmp:tmp->head);
676 elmex 1.1
677 root 1.3 if(QUERY_FLAG(tmp, FLAG_IS_FLOOR)&&!QUERY_FLAG(op, FLAG_WIZ)) /* don't continue under the floor */
678     break;
679 elmex 1.1 }
680    
681     if(!flag) {
682 root 1.3 if(dx||dy)
683     new_draw_info(NDI_UNIQUE, 0,op,"You see nothing there.");
684     else
685     new_draw_info(NDI_UNIQUE, 0,op,"You see nothing.");
686 elmex 1.1 }
687     }
688    
689    
690    
691     /** Client wants to look at some object. Lets do so. */
692     void LookAt(char *buf, int len,player *pl)
693     {
694     int dx, dy;
695     char *cp;
696    
697     dx=atoi(buf);
698     if (!(cp=strchr(buf,' '))) {
699 root 1.3 return;
700 elmex 1.1 }
701     dy=atoi(cp);
702    
703     if (FABS(dx) > pl->socket.mapx / 2 || FABS(dy) > pl->socket.mapy / 2)
704     return;
705    
706     if(pl->blocked_los[dx + pl->socket.mapx / 2][dy + pl->socket.mapy / 2])
707     return;
708    
709     look_at(pl->ob, dx, dy);
710     }
711    
712     /** Move an object to a new location */
713     void esrv_move_object (object *pl, tag_t to, tag_t tag, long nrof)
714     {
715     object *op, *env;
716    
717     op = esrv_get_ob_from_count(pl, tag);
718     if (!op) {
719 root 1.3 LOG(llevDebug, "Player '%s' tried to move an unknown object (%ld)\n",
720     pl->name, tag);
721     return;
722 elmex 1.1 }
723    
724 root 1.2 if (!to) { /* drop it to the ground */
725 elmex 1.1 /* LOG(llevDebug, "Drop it on the ground.\n");*/
726    
727 root 1.3 if (op->map && !op->env) {
728 elmex 1.1 /* LOG(llevDebug,"Dropping object to ground that is already on ground\n");*/
729 root 1.3 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     }
740     esrv_update_item(UPD_WEIGHT, pl, op);
741     }
742     else {
743     drop_object (pl, op, nrof);
744     }
745     return;
746 elmex 1.1 } else if (to == pl->count) { /* pick it up to the inventory */
747 root 1.3 /* return if player has already picked it up */
748     if (op->env == pl) return;
749 elmex 1.1
750 root 1.3 pl->contr->count = nrof;
751     pick_up(pl, op);
752     return ;
753 elmex 1.1 }
754 root 1.2 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;
760     }
761     /* put_object_in_sack presumes that necessary sanity checking
762     * 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
764     * an make sure env is in fact a container for that matter.
765     */
766     if (env->type == CONTAINER
767     && can_pick(pl, op) && sack_can_hold(pl, env, op, nrof)) {
768     put_object_in_sack (pl, env, op, nrof);
769 elmex 1.1 }
770     }
771    
772