ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/socket/item.c
Revision: 1.1.1.1 (vendor branch)
Committed: Fri Feb 3 07:14:44 2006 UTC (18 years, 4 months ago) by root
Content type: text/plain
Branch: UPSTREAM
CVS Tags: UPSTREAM_2006_02_03
Changes since 1.1: +0 -0 lines
Log Message:
initial import

File Contents

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