ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/socket/item.C
Revision: 1.1
Committed: Sun Aug 13 17:16:06 2006 UTC (17 years, 9 months ago) by elmex
Content type: text/plain
Branch: MAIN
Log Message:
Made server compile with C++.
Removed cfanim plugin and crossedit.
C++ here we come.

File Contents

# User Rev Content
1 elmex 1.1
2     /*
3     * static char *rcsid_item_c =
4     * "$Id$";
5     */
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     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    
120     if (QUERY_FLAG(op,FLAG_KNOWN_CURSED)) {
121     if(QUERY_FLAG(op,FLAG_DAMNED))
122     flags |= F_DAMNED;
123     else if(QUERY_FLAG(op,FLAG_CURSED))
124     flags |= F_CURSED;
125     }
126     if (QUERY_FLAG(op,FLAG_KNOWN_MAGICAL) && !QUERY_FLAG(op,FLAG_IDENTIFIED))
127     flags |= F_MAGIC;
128     if (QUERY_FLAG(op,FLAG_UNPAID))
129     flags |= F_UNPAID;
130     if (QUERY_FLAG(op,FLAG_INV_LOCKED))
131     flags |= F_LOCKED;
132    
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     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     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     } else {
167     strncpy(item_n,head->custom_name,127);
168     item_n[127]=0;
169     len=strlen(item_n);
170     item_p=head->custom_name;
171     }
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     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     }
190     SockList_AddChar(sl, (char) anim_speed);
191     SockList_AddInt(sl, head->nrof);
192    
193     if (ns->itemcmd == 2)
194     SockList_AddShort(sl, head->client_type);
195    
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     LOG(llevDebug,"esrv_draw_look called when update_look was not set\n");
215     return;
216     } else {
217     pl->contr->socket.update_look=0;
218     }
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     return;
223    
224     if (pl->contr->transport)
225     for (tmp=pl->contr->transport->inv; tmp && tmp->above;tmp=tmp->above) ;
226     else
227     for (tmp=get_map_ob(pl->map,pl->x,pl->y); tmp && tmp->above;tmp=tmp->above) ;
228    
229     sl.buf= (unsigned char *) malloc(MAXSOCKBUF);
230    
231     Write_String_To_Socket(&pl->contr->socket, "delinv 0", strlen("delinv 0"));
232     sprintf((char*)sl.buf,"item%d ", pl->contr->socket.itemcmd);
233     sl.len=strlen((char*)sl.buf);
234    
235     SockList_AddInt(&sl, 0);
236    
237     if (!(pl->contr->socket.faces_sent[empty_face->number]&NS_FACESENT_FACE))
238     esrv_send_face(&pl->contr->socket, empty_face->number,0);
239    
240     if (pl->contr->socket.look_position) {
241     SockList_AddInt(&sl, 0x80000000 | (pl->contr->socket.look_position- NUM_LOOK_OBJECTS));
242     SockList_AddInt(&sl, 0);
243     SockList_AddInt(&sl, (uint32) -1);
244     SockList_AddInt(&sl, empty_face->number);
245     sprintf(buf,"Click here to see %d previous items", NUM_LOOK_OBJECTS);
246     add_stringlen_to_sockbuf(buf, &sl);
247     SockList_AddShort(&sl,0);
248     SockList_AddChar(&sl, 0);
249     SockList_AddInt(&sl, 0);
250     if (pl->contr->socket.itemcmd == 2)
251     SockList_AddShort(&sl, 0);
252     }
253    
254     if (pl->contr->transport) {
255     add_object_to_socklist(&pl->contr->socket, &sl, pl->contr->transport);
256     got_one++;
257     }
258    
259     for (last=NULL; tmp!=last; tmp=tmp->below) {
260     object *head;
261    
262     if (QUERY_FLAG(tmp, FLAG_IS_FLOOR) && !last) {
263     last = tmp->below; /* assumes double floor mode */
264     if (last && QUERY_FLAG(last, FLAG_IS_FLOOR))
265     last = last->below;
266     }
267     if (LOOK_OBJ(tmp)) {
268     if (++start_look < pl->contr->socket.look_position) continue;
269     end_look++;
270     if (end_look > NUM_LOOK_OBJECTS) {
271     /* What we basically do is make a 'fake' object - when the user applies it,
272     * we notice the special tag the object has, and act accordingly.
273     */
274     SockList_AddInt(&sl, 0x80000000 | (pl->contr->socket.look_position+ NUM_LOOK_OBJECTS));
275     SockList_AddInt(&sl, 0);
276     SockList_AddInt(&sl, (uint32) -1);
277     SockList_AddInt(&sl, empty_face->number);
278     sprintf(buf,"Click here to see next group of items");
279     add_stringlen_to_sockbuf(buf, &sl);
280     SockList_AddShort(&sl,0);
281     SockList_AddChar(&sl, 0);
282     SockList_AddInt(&sl, 0);
283     if (pl->contr->socket.itemcmd == 2)
284     SockList_AddShort(&sl, 0);
285     break;
286     }
287     if (tmp->head) head = tmp->head;
288     else head = tmp;
289    
290     add_object_to_socklist(&pl->contr->socket, &sl, head);
291     got_one++;
292    
293     if (sl.len >= (MAXSOCKBUF-MAXITEMLEN)) {
294     Send_With_Handling(&pl->contr->socket, &sl);
295     sprintf((char*)sl.buf,"item%d ", pl->contr->socket.itemcmd);
296     sl.len=strlen((char*)sl.buf);
297     SockList_AddInt(&sl, 0);
298     got_one=0;
299     }
300     } /* If LOOK_OBJ() */
301     }
302     if (got_one)
303     Send_With_Handling(&pl->contr->socket, &sl);
304    
305     free(sl.buf);
306     }
307    
308     /**
309     * Sends whole inventory.
310     */
311     void esrv_send_inventory(object *pl, object *op)
312     {
313     object *tmp;
314     int got_one=0;
315     SockList sl;
316    
317     sl.buf= (unsigned char *) malloc(MAXSOCKBUF);
318    
319     sprintf((char*)sl.buf,"delinv %d", op->count);
320     sl.len=strlen((char*)sl.buf);
321     Send_With_Handling(&pl->contr->socket, &sl);
322    
323     sprintf((char*)sl.buf,"item%d ", pl->contr->socket.itemcmd);
324     sl.len=strlen((char*)sl.buf);
325    
326     SockList_AddInt(&sl, op->count);
327    
328     for (tmp=op->inv; tmp; tmp=tmp->below) {
329     object *head;
330    
331     if (tmp->head) head = tmp->head;
332     else head = tmp;
333    
334     if (LOOK_OBJ(head)) {
335     add_object_to_socklist(&pl->contr->socket, &sl, head);
336    
337     got_one++;
338    
339     /* IT is possible for players to accumulate a huge amount of
340     * items (especially with some of the bags out there) to
341     * overflow the buffer. IF so, send multiple item commands.
342     */
343     if (sl.len >= (MAXSOCKBUF-MAXITEMLEN)) {
344     Send_With_Handling(&pl->contr->socket, &sl);
345     sprintf((char*)sl.buf,"item%d ", pl->contr->socket.itemcmd);
346     sl.len=strlen((char*)sl.buf);
347     SockList_AddInt(&sl, op->count);
348     got_one=0;
349     }
350     } /* If LOOK_OBJ() */
351     }
352     if (got_one)
353     Send_With_Handling(&pl->contr->socket, &sl);
354     free(sl.buf);
355     }
356    
357     /**
358     * Updates object *op for player *pl.
359     *
360     * flags is a list of values to update
361     * to the client (as defined in newclient.h - might as well use the
362     * same value both places.
363     */
364    
365     void esrv_update_item(int flags, object *pl, object *op)
366     {
367     SockList sl;
368    
369     /* If we have a request to send the player item, skip a few checks. */
370     if (op!=pl) {
371     if (! LOOK_OBJ(op))
372     return;
373     /* we remove the check for op->env, because in theory, the object
374     * is hopefully in the same place, so the client should preserve
375     * order.
376     */
377     }
378     if (!QUERY_FLAG(op, FLAG_CLIENT_SENT)) {
379     /* FLAG_CLIENT_SENT is debug only. We are using it to see where
380     * this is happening - we can set a breakpoint here in the debugger
381     * and track back the call.
382     */
383     LOG(llevDebug,"We have not sent item %s (%d)\n", op->name, op->count);
384     }
385     sl.buf= (unsigned char *) malloc(MAXSOCKBUF);
386    
387     strcpy((char*)sl.buf,"upditem ");
388     sl.len=strlen((char*)sl.buf);
389    
390     SockList_AddChar(&sl, (char) flags);
391    
392     if (op->head) op=op->head;
393    
394     SockList_AddInt(&sl, op->count);
395    
396     if (flags & UPD_LOCATION)
397     SockList_AddInt(&sl, op->env? op->env->count:0);
398    
399     if (flags & UPD_FLAGS)
400     SockList_AddInt(&sl, query_flags(op));
401    
402     if (flags & UPD_WEIGHT) {
403     sint32 weight = WEIGHT(op);
404    
405     /* TRANSPORTS are odd - they sort of look like containers, yet can't be
406     * picked up. So we don't to send the weight, as it is odd that you see
407     * weight sometimes and not other (the draw_look won't send it
408     * for example.
409     */
410     SockList_AddInt(&sl, QUERY_FLAG(op, FLAG_NO_PICK) ? -1 : weight);
411     if (pl == op) {
412     op->contr->last_weight = weight;
413     }
414     }
415    
416     if (flags & UPD_FACE) {
417     if (!(pl->contr->socket.faces_sent[op->face->number] & NS_FACESENT_FACE))
418     esrv_send_face(&pl->contr->socket, op->face->number,0);
419     SockList_AddInt(&sl, op->face->number);
420     }
421     if (flags & UPD_NAME) {
422     int len;
423     const char *item_p;
424     char item_n[MAX_BUF];
425    
426     if (!op->custom_name) {
427     strncpy(item_n,query_base_name(op, 0),127);
428     item_n[127]=0;
429     len=strlen(item_n);
430     item_p=query_base_name(op, 1);
431     }
432     else {
433     strncpy(item_n,op->custom_name,127);
434     item_n[127]=0;
435     len=strlen(item_n);
436     item_p=op->custom_name;
437     }
438    
439     strncpy(item_n+len+1, item_p, 127);
440     item_n[254]=0;
441     len += strlen(item_n+1+len) + 1;
442     SockList_AddChar(&sl, (char)len);
443     memcpy(sl.buf+sl.len, item_n, len);
444     sl.len += len;
445     }
446     if (flags & UPD_ANIM)
447     SockList_AddShort(&sl,op->animation_id);
448    
449     if (flags & UPD_ANIMSPEED) {
450     int anim_speed=0;
451     if (QUERY_FLAG(op,FLAG_ANIMATE)) {
452     if (op->anim_speed) anim_speed=op->anim_speed;
453     else {
454     if (FABS(op->speed)<0.001) anim_speed=255;
455     else if (FABS(op->speed)>=1.0) anim_speed=1;
456     else anim_speed = (int) (1.0/FABS(op->speed));
457     }
458     if (anim_speed>255) anim_speed=255;
459     }
460     SockList_AddChar(&sl, (char)anim_speed);
461     }
462     if (flags & UPD_NROF)
463     SockList_AddInt(&sl, op->nrof);
464    
465     Send_With_Handling(&pl->contr->socket, &sl);
466     free(sl.buf);
467     }
468    
469     /**
470     * Sends item's info to player.
471     */
472     void esrv_send_item(object *pl, object*op)
473     {
474     SockList sl;
475    
476     /* If this is not the player object, do some more checks */
477     if (op!=pl) {
478     /* We only send 'visibile' objects to the client */
479     if (! LOOK_OBJ(op))
480     return;
481     /* if the item is on the ground, mark that the look needs to
482     * be updated.
483     */
484     if (!op->env) {
485     pl->contr->socket.update_look=1;
486     return;
487     }
488     }
489    
490     sl.buf= (unsigned char *) malloc(MAXSOCKBUF);
491    
492     sprintf((char*)sl.buf,"item%d ", pl->contr->socket.itemcmd);
493     sl.len=strlen((char*)sl.buf);
494    
495     if (op->head) op=op->head;
496    
497     SockList_AddInt(&sl, op->env? op->env->count:0);
498    
499     add_object_to_socklist(&pl->contr->socket, &sl, op);
500    
501     Send_With_Handling(&pl->contr->socket, &sl);
502     SET_FLAG(op, FLAG_CLIENT_SENT);
503     free(sl.buf);
504     }
505    
506     /**
507     * Tells the client to delete an item. Uses the item
508     * command with a -1 location.
509     */
510    
511     void esrv_del_item(player *pl, int tag)
512     {
513     SockList sl;
514    
515     sl.buf= (unsigned char *) malloc(MAXSOCKBUF);
516    
517     strcpy((char*)sl.buf,"delitem ");
518     sl.len=strlen((char*)sl.buf);
519     SockList_AddInt(&sl, tag);
520    
521     Send_With_Handling(&pl->socket, &sl);
522     free(sl.buf);
523     }
524    
525    
526     /*******************************************************************************
527     *
528     * Client has requested us to do something with an object.
529     *
530     ******************************************************************************/
531    
532     /**
533     * Takes a player and object count (tag) and returns the actual object
534     * pointer, or null if it can't be found.
535     */
536    
537     object *esrv_get_ob_from_count(object *pl, tag_t count)
538     {
539     object *op, *tmp;
540    
541     if (pl->count == count)
542     return pl;
543    
544     for(op = pl->inv; op; op = op->below)
545     if (op->count == count)
546     return op;
547     else if (op->type == CONTAINER && pl->container == op)
548     for(tmp = op->inv; tmp; tmp = tmp->below)
549     if (tmp->count == count)
550     return tmp;
551    
552     for(op = get_map_ob (pl->map, pl->x, pl->y); op; op = op->above)
553     if (op->head != NULL && op->head->count == count)
554     return op;
555     else if (op->count == count)
556     return op;
557     else if (op->type == CONTAINER && pl->container == op)
558     for(tmp = op->inv; tmp; tmp = tmp->below)
559     if (tmp->count == count)
560     return tmp;
561    
562     if (pl->contr->transport) {
563     for(tmp = pl->contr->transport->inv; tmp; tmp = tmp->below)
564     if (tmp->count == count)
565     return tmp;
566     }
567     return NULL;
568     }
569    
570    
571     /** Client wants to examine some object. So lets do so. */
572     void ExamineCmd(char *buf, int len,player *pl)
573     {
574     long tag = atoi(buf);
575     object *op = esrv_get_ob_from_count(pl->ob, tag);
576    
577     if (!op) {
578     LOG(llevDebug, "Player '%s' tried to examine the unknown object (%ld)\n",
579     pl->ob->name, tag);
580     return;
581     }
582     examine (pl->ob, op);
583     }
584    
585     /** Client wants to apply some object. Lets do so. */
586     void ApplyCmd(char *buf, int len,player *pl)
587     {
588     uint32 tag = atoi(buf);
589     object *op = esrv_get_ob_from_count(pl->ob, tag);
590    
591     /* sort of a hack, but if the player saves and the player then manually
592     * applies a savebed (or otherwise tries to do stuff), we run into trouble.
593     */
594     if (QUERY_FLAG(pl->ob, FLAG_REMOVED)) return;
595    
596     /* If the high bit is set, player applied a pseudo object. */
597     if (tag & 0x80000000) {
598     pl->socket.look_position = tag & 0x7fffffff;
599     pl->socket.update_look = 1;
600     return;
601     }
602    
603     if (!op) {
604     LOG(llevDebug, "Player '%s' tried to apply the unknown object (%d)\n",
605     pl->ob->name, tag);
606     return;
607     }
608     player_apply (pl->ob, op, 0, 0);
609     }
610    
611     /** Client wants to apply some object. Lets do so. */
612     void LockItem(uint8 *data, int len,player *pl)
613     {
614     int flag, tag;
615     object *op;
616    
617     flag = data[0];
618     tag = GetInt_String(data+1);
619     op = esrv_get_ob_from_count(pl->ob, tag);
620    
621     if (!op) {
622     new_draw_info(NDI_UNIQUE, 0, pl->ob,"Could not find object to lock/unlock");
623     return;
624     }
625     if (!flag)
626     CLEAR_FLAG(op,FLAG_INV_LOCKED);
627     else
628     SET_FLAG(op,FLAG_INV_LOCKED);
629     esrv_update_item(UPD_FLAGS, pl->ob, op);
630     }
631    
632     /** Client wants to apply some object. Lets do so. */
633     void MarkItem(uint8 *data, int len,player *pl)
634     {
635     int tag;
636     object *op;
637    
638     tag = GetInt_String(data);
639     op = esrv_get_ob_from_count(pl->ob, tag);
640     if (!op) {
641     new_draw_info(NDI_UNIQUE, 0, pl->ob,"Could not find object to mark");
642     return;
643     }
644     pl->mark = op;
645     pl->mark_count = op->count;
646     new_draw_info_format(NDI_UNIQUE, 0, pl->ob, "Marked item %s", query_name(op));
647     }
648    
649    
650     /**
651     * look_at prints items on the specified square.
652     *
653     * [ removed EARTHWALL check and added check for containers inventory.
654     * Tero.Haatanen@lut.fi ]
655     */
656     void look_at(object *op,int dx,int dy) {
657     object *tmp;
658     int flag=0;
659     sint16 x,y;
660     mapstruct *m;
661    
662     x = op->x + dx;
663     y = op->y + dy;
664    
665     if (out_of_map(op->map, x, y)) return;
666    
667     m = get_map_from_coord(op->map, &x, &y);
668     if (!m) return;
669    
670     for(tmp=get_map_ob(m, x ,y);tmp!=NULL&&tmp->above!=NULL;
671     tmp=tmp->above);
672    
673     for ( ; tmp != NULL; tmp=tmp->below ) {
674     if (tmp->invisible && !QUERY_FLAG(op, FLAG_WIZ)) continue;
675    
676     if(!flag) {
677     if(dx||dy)
678     new_draw_info(NDI_UNIQUE, 0,op,"There you see:");
679     else {
680     clear_win_info(op);
681     new_draw_info(NDI_UNIQUE, 0,op,"You see:");
682     }
683     flag=1;
684     }
685    
686     if (QUERY_FLAG(op, FLAG_WIZ))
687     new_draw_info_format(NDI_UNIQUE,0, op, "- %s (%d).",query_name(tmp),tmp->count);
688     else
689     new_draw_info_format(NDI_UNIQUE,0, op, "- %s.",query_name(tmp));
690    
691     if (((tmp->inv!=NULL || (tmp->head && tmp->head->inv)) &&
692     (tmp->type != CONTAINER && tmp->type!=FLESH)) || QUERY_FLAG(op, FLAG_WIZ))
693     inventory(op,tmp->head==NULL?tmp:tmp->head);
694    
695     if(QUERY_FLAG(tmp, FLAG_IS_FLOOR)&&!QUERY_FLAG(op, FLAG_WIZ)) /* don't continue under the floor */
696     break;
697     }
698    
699     if(!flag) {
700     if(dx||dy)
701     new_draw_info(NDI_UNIQUE, 0,op,"You see nothing there.");
702     else
703     new_draw_info(NDI_UNIQUE, 0,op,"You see nothing.");
704     }
705     }
706    
707    
708    
709     /** Client wants to look at some object. Lets do so. */
710     void LookAt(char *buf, int len,player *pl)
711     {
712     int dx, dy;
713     char *cp;
714    
715     dx=atoi(buf);
716     if (!(cp=strchr(buf,' '))) {
717     return;
718     }
719     dy=atoi(cp);
720    
721     if (FABS(dx) > pl->socket.mapx / 2 || FABS(dy) > pl->socket.mapy / 2)
722     return;
723    
724     if(pl->blocked_los[dx + pl->socket.mapx / 2][dy + pl->socket.mapy / 2])
725     return;
726    
727     look_at(pl->ob, dx, dy);
728     }
729    
730     /** Move an object to a new location */
731     void esrv_move_object (object *pl, tag_t to, tag_t tag, long nrof)
732     {
733     object *op, *env;
734    
735     op = esrv_get_ob_from_count(pl, tag);
736     if (!op) {
737     LOG(llevDebug, "Player '%s' tried to move an unknown object (%ld)\n",
738     pl->name, tag);
739     return;
740     }
741    
742     /* If on a transport, you don't drop to the ground - you drop to the
743     * transport.
744     */
745     if (!to && !pl->contr->transport) { /* drop it to the ground */
746     /* LOG(llevDebug, "Drop it on the ground.\n");*/
747    
748     if (op->map && !op->env) {
749     /* LOG(llevDebug,"Dropping object to ground that is already on ground\n");*/
750     return;
751     }
752     /* If it is an active container, then we should drop all objects
753     * in the container and not the container itself.
754     */
755     if (op->inv && QUERY_FLAG(op, FLAG_APPLIED)) {
756     object *current, *next;
757     for (current=op->inv; current!=NULL; current=next) {
758     next=current->below;
759     drop_object(pl, current, 0);
760     }
761     esrv_update_item(UPD_WEIGHT, pl, op);
762     }
763     else {
764     drop_object (pl, op, nrof);
765     }
766     return;
767     } else if (to == pl->count) { /* pick it up to the inventory */
768     /* return if player has already picked it up */
769     if (op->env == pl) return;
770    
771     pl->contr->count = nrof;
772     pick_up(pl, op);
773     return ;
774     }
775     /* If not dropped or picked up, we are putting it into a sack */
776     if (pl->contr->transport) {
777     if (can_pick(pl, op) && transport_can_hold(pl->contr->transport, op, nrof)) {
778     put_object_in_sack (pl, pl->contr->transport, op, nrof);
779     }
780     } else {
781     env = esrv_get_ob_from_count(pl, to);
782     if (!env) {
783     LOG(llevDebug,
784     "Player '%s' tried to move object to the unknown location (%d)\n",
785     pl->name, to);
786     return;
787     }
788     /* put_object_in_sack presumes that necessary sanity checking
789     * has already been done (eg, it can be picked up and fits in
790     * in a sack, so check for those things. We should also check
791     * an make sure env is in fact a container for that matter.
792     */
793     if (env->type == CONTAINER
794     && can_pick(pl, op) && sack_can_hold(pl, env, op, nrof)) {
795     put_object_in_sack (pl, env, op, nrof);
796     }
797     }
798     }
799    
800