ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/player.c
Revision: 1.1.1.1 (vendor branch)
Committed: Fri Feb 3 07:14:35 2006 UTC (18 years, 3 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     * static char *rcsid_player_c =
3     * "$Id: player.c,v 1.190 2006/01/08 23:57:19 qal21 Exp $";
4     */
5    
6     /*
7     CrossFire, A Multiplayer game for X-windows
8    
9     Copyright (C) 2002 Mark Wedel & Crossfire Development Team
10     Copyright (C) 1992 Frank Tore Johansen
11    
12     This program is free software; you can redistribute it and/or modify
13     it under the terms of the GNU General Public License as published by
14     the Free Software Foundation; either version 2 of the License, or
15     (at your option) any later version.
16    
17     This program is distributed in the hope that it will be useful,
18     but WITHOUT ANY WARRANTY; without even the implied warranty of
19     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20     GNU General Public License for more details.
21    
22     You should have received a copy of the GNU General Public License
23     along with this program; if not, write to the Free Software
24     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25    
26     The author can be reached via e-mail to crossfire-devel@real-time.com
27     */
28    
29     #include <global.h>
30     #ifndef WIN32 /* ---win32 remove headers */
31     #include <pwd.h>
32     #endif
33     #ifndef __CEXTRACT__
34     #include <sproto.h>
35     #endif
36     #include <sounds.h>
37     #include <living.h>
38     #include <object.h>
39     #include <spells.h>
40     #include <skills.h>
41     #include <newclient.h>
42    
43     player *find_player(const char *plname)
44     {
45     player *pl;
46     for(pl=first_player;pl!=NULL;pl=pl->next)
47     {
48     if(pl->ob != NULL && !strcmp(query_name(pl->ob),plname))
49     return pl;
50     };
51     return NULL;
52     }
53    
54     player* find_player_partial_name( const char* plname )
55     {
56     player* pl;
57     player* found = NULL;
58     size_t namelen = strlen( plname );
59     for ( pl = first_player; pl != NULL; pl = pl->next )
60     {
61     if ( strlen( pl->ob->name ) < namelen )
62     continue;
63    
64     if ( !strcmp( pl->ob->name, plname) )
65     return pl;
66    
67     if ( !strncasecmp( pl->ob->name, plname, namelen ) )
68     {
69     if ( found )
70     return NULL;
71    
72     found = pl;
73     }
74     }
75     return found;
76     }
77    
78     void display_motd(object *op) {
79     char buf[MAX_BUF];
80     char motd[HUGE_BUF];
81     FILE *fp;
82     int comp;
83     int size;
84    
85     sprintf(buf, "%s/%s", settings.confdir, settings.motd);
86     if ((fp=open_and_uncompress(buf, 0, &comp)) == NULL) {
87     return;
88     }
89     motd[0]='\0';
90     size=0;
91     while (fgets(buf, MAX_BUF, fp) != NULL) {
92     if( *buf == '#')
93     continue;
94     strncat(motd+size,buf,HUGE_BUF-size);
95     size+=strlen(buf);
96     }
97     draw_ext_info(NDI_UNIQUE | NDI_GREEN, 0, op, MSG_TYPE_MOTD, MSG_SUBTYPE_NONE, motd, NULL);
98     close_and_delete(fp, comp);
99     }
100    
101     void send_rules(object *op) {
102     char buf[MAX_BUF];
103     char rules[HUGE_BUF];
104     FILE *fp;
105     int comp;
106     int size;
107    
108     sprintf(buf, "%s/%s", settings.confdir, settings.rules);
109     if ((fp=open_and_uncompress(buf, 0, &comp)) == NULL) {
110     return;
111     }
112     rules[0]='\0';
113     size=0;
114     while (fgets(buf, MAX_BUF, fp) != NULL) {
115     if( *buf == '#')
116     continue;
117     if (size + strlen(buf)>=HUGE_BUF)
118     {
119     LOG(llevDebug, "Warning, rules size is > %d bytes.\n", HUGE_BUF);
120     break;
121     }
122     strncat(rules+size,buf,HUGE_BUF-size);
123     size+=strlen(buf);
124     }
125     draw_ext_info(NDI_UNIQUE | NDI_GREEN, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_RULES, rules, NULL);
126     close_and_delete(fp, comp);
127     }
128    
129     void send_news(object *op) {
130     char buf[MAX_BUF];
131     char news[HUGE_BUF];
132     char subject[MAX_BUF];
133     FILE *fp;
134     int comp;
135     int size;
136    
137     sprintf(buf, "%s/%s", settings.confdir, settings.news);
138     if ((fp=open_and_uncompress(buf, 0, &comp)) == NULL)
139     return;
140     news[0]='\0';
141     subject[0]='\0';
142     size=0;
143     while (fgets(buf, MAX_BUF, fp) != NULL) {
144     if( *buf == '#')
145     continue;
146     if ( *buf =='%'){ /* send one news */
147     if (size>0)
148     draw_ext_info_format(NDI_UNIQUE | NDI_GREEN, 0, op,
149     MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_NEWS,
150     "!! informations: %s\n%s",
151     "%s\n%s",
152     subject, news); /*send previously read news*/
153     strcpy(subject,buf+1);
154     strip_endline(subject);
155     size=0;
156     news[0]='\0';
157     }
158     else{
159     if (size + strlen(buf)>=HUGE_BUF)
160     {
161     LOG(llevDebug, "Warning, one news item has size > %d bytes.\n", HUGE_BUF);
162     break;
163     }
164     strncat(news+size,buf,HUGE_BUF-size);
165     size+=strlen(buf);
166     }
167     }
168    
169     draw_ext_info_format(NDI_UNIQUE | NDI_GREEN, 0, op,
170     MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_NEWS,
171     "!! informations: %s\n%s\n",
172     "%s\n%s",
173     subject, news);
174     close_and_delete(fp, comp);
175     }
176    
177     int playername_ok(const char *cp) {
178     /* Don't allow - or _ as first character in the name */
179     if (*cp == '-' || *cp == '_') return 0;
180    
181     for(;*cp!='\0';cp++)
182     if(!((*cp>='a'&&*cp<='z')||(*cp>='A'&&*cp<='Z'))&&*cp!='-'&&*cp!='_')
183     return 0;
184     return 1;
185     }
186    
187     /* This no longer sets the player map. Also, it now updates
188     * all the pointers so the caller doesn't need to do that.
189     * Caller is responsible for setting the correct map.
190     */
191    
192     /* Redo this to do both get_player_ob and get_player.
193     * Hopefully this will be less bugfree and simpler.
194     * Returns the player structure. If 'p' is null,
195     * we create a new one. Otherwise, we recycle
196     * the one that is passed.
197     */
198     static player* get_player(player *p) {
199     object *op=arch_to_object(get_player_archetype(NULL));
200     int i;
201    
202     if (!p) {
203     player *tmp;
204    
205     p = (player *) malloc(sizeof(player));
206     if(p==NULL)
207     fatal(OUT_OF_MEMORY);
208    
209     /* This adds the player in the linked list. There is extra
210     * complexity here because we want to add the new player at the
211     * end of the list - there is in fact no compelling reason that
212     * that needs to be done except for things like output of
213     * 'who'.
214     */
215     tmp=first_player;
216     while(tmp!=NULL&&tmp->next!=NULL)
217     tmp=tmp->next;
218     if(tmp!=NULL)
219     tmp->next=p;
220     else
221     first_player=p;
222    
223     p->next = NULL;
224     }
225    
226     /* Clears basically the entire player structure except
227     * for next and socket.
228     */
229     memset((void*)((char*)p + offsetof(player, maplevel)), 0,
230     sizeof(player) - offsetof(player, maplevel));
231    
232     /* There are some elements we want initialized to non zero value -
233     * we deal with that below this point.
234     */
235     p->party=NULL;
236     p->outputs_sync=16; /* Every 2 seconds */
237     p->outputs_count=1; /* Keeps present behaviour */
238     p->unapply = unapply_nochoice;
239     p->Swap_First = -1;
240    
241     #ifdef AUTOSAVE
242     p->last_save_tick = 9999999;
243     #endif
244    
245     strcpy(p->savebed_map, first_map_path); /* Init. respawn position */
246    
247     op->contr=p; /* this aren't yet in archetype */
248     p->ob = op;
249     op->speed_left=0.5;
250     op->speed=1.0;
251     op->direction=5; /* So player faces south */
252     op->stats.wc=2;
253     op->run_away = 25; /* Then we panick... */
254    
255     roll_stats(op);
256     p->state=ST_ROLL_STAT;
257     clear_los(op);
258    
259     p->gen_sp_armour=10;
260     p->last_speed= -1;
261     p->shoottype=range_none;
262     p->bowtype=bow_normal;
263     p->petmode=pet_normal;
264     p->listening=9;
265     p->last_weapon_sp= -1;
266     p->peaceful=1; /* default peaceful */
267     p->do_los=1;
268     p->explore=0;
269     p->no_shout=0; /* default can shout */
270    
271     strncpy(p->title, op->arch->clone.name, sizeof(p->title)-1);
272     p->title[sizeof(p->title)-1] = '\0';
273     op->race = add_string (op->arch->clone.race);
274    
275     CLEAR_FLAG(op,FLAG_READY_SKILL);
276    
277     /* we need to clear these to -1 and not zero - otherwise,
278     * if a player quits and starts a new character, we wont
279     * send new values to the client, as things like exp start
280     * at zero.
281     */
282     for (i=0; i < NUM_SKILLS; i++) {
283     p->last_skill_exp[i] = -1;
284     p->last_skill_ob[i] = NULL;
285     }
286     for (i=0; i < NROFATTACKS; i++) {
287     p->last_resist[i] = -1;
288     }
289     p->last_stats.exp = -1;
290     p->last_weight = (uint32)-1;
291    
292     p->socket.update_look=0;
293     p->socket.look_position=0;
294     return p;
295     }
296    
297    
298     /* This loads the first map an puts the player on it. */
299     static void set_first_map(object *op)
300     {
301     strcpy(op->contr->maplevel, first_map_path);
302     op->x = -1;
303     op->y = -1;
304     enter_exit(op, NULL);
305     }
306    
307     /* Tries to add player on the connection passwd in ns.
308     * All we can really get in this is some settings like host and display
309     * mode.
310     */
311    
312     int add_player(NewSocket *ns) {
313     player *p;
314    
315     p=get_player(NULL);
316     memcpy(&p->socket, ns, sizeof(NewSocket));
317     p->socket.faces_sent = malloc(p->socket.faces_sent_len*sizeof(*p->socket.faces_sent));
318     if(p->socket.faces_sent == NULL)
319     fatal(OUT_OF_MEMORY);
320     memcpy(p->socket.faces_sent, ns->faces_sent, p->socket.faces_sent_len*sizeof(*p->socket.faces_sent));
321     /* Needed because the socket we just copied over needs to be cleared.
322     * Note that this can result in a client reset if there is partial data
323     * on the uncoming socket.
324     */
325     p->socket.inbuf.len = 0;
326     set_first_map(p->ob);
327    
328     CLEAR_FLAG(p->ob, FLAG_FRIENDLY);
329     add_friendly_object(p->ob);
330     send_rules(p->ob);
331     send_news(p->ob);
332     display_motd(p->ob);
333     get_name(p->ob);
334     return 0;
335     }
336    
337     /*
338     * get_player_archetype() return next player archetype from archetype
339     * list. Not very efficient routine, but used only creating new players.
340     * Note: there MUST be at least one player archetype!
341     */
342     archetype *get_player_archetype(archetype* at)
343     {
344     archetype *start = at;
345     for (;;) {
346     if (at==NULL || at->next==NULL)
347     at=first_archetype;
348     else
349     at=at->next;
350     if(at->clone.type==PLAYER)
351     return at;
352     if (at == start) {
353     LOG (llevError, "No Player archetypes\n");
354     exit (-1);
355     }
356     }
357     }
358    
359    
360     object *get_nearest_player(object *mon) {
361     object *op = NULL;
362     player *pl = NULL;
363     objectlink *ol;
364     unsigned lastdist;
365     rv_vector rv;
366    
367     for(ol=first_friendly_object,lastdist=1000;ol!=NULL;ol=ol->next) {
368     /* We should not find free objects on this friendly list, but it
369     * does periodically happen. Given that, lets deal with it.
370     * While unlikely, it is possible the next object on the friendly
371     * list is also free, so encapsulate this in a while loop.
372     */
373     while (QUERY_FLAG(ol->ob, FLAG_FREED) || !QUERY_FLAG(ol->ob, FLAG_FRIENDLY)) {
374     object *tmp=ol->ob;
375    
376     /* Can't do much more other than log the fact, because the object
377     * itself will have been cleared.
378     */
379     LOG(llevDebug,"get_nearest_player: Found free/non friendly object on friendly list\n");
380     ol = ol->next;
381     remove_friendly_object(tmp);
382     if (!ol) return op;
383     }
384    
385     /* Remove special check for player from this. First, it looks to cause
386     * some crashes (ol->ob->contr not set properly?), but secondly, a more
387     * complicated method of state checking would be needed in any case -
388     * as it was, a clever player could type quit, and the function would
389     * skip them over while waiting for confirmation. Remove
390     * on_same_map check, as can_detect_enemy also does this
391     */
392     if (!can_detect_enemy(mon,ol->ob,&rv))
393     continue;
394    
395     if(lastdist>rv.distance) {
396     op=ol->ob;
397     lastdist=rv.distance;
398     }
399     }
400     for (pl=first_player; pl != NULL; pl=pl->next) {
401     if (on_same_map(mon, pl->ob)&& can_detect_enemy(mon, pl->ob,&rv)) {
402    
403     if(lastdist>rv.distance) {
404     op=pl->ob;
405     lastdist=rv.distance;
406     }
407     }
408     }
409     #if 0
410     LOG(llevDebug,"get_nearest_player() finds player: %s\n",op?op->name:"(null)");
411     #endif
412     return op;
413     }
414    
415     /* I believe this can safely go to 2, 3 is questionable, 4 will likely
416     * result in a monster paths backtracking. It basically determines how large a
417     * detour a monster will take from the direction path when looking
418     * for a path to the player. The values are in the amount of direction
419     * the deviation is
420     */
421     #define DETOUR_AMOUNT 2
422    
423     /* This is used to prevent infinite loops. Consider a case where the
424     * player is in a chamber (with gate closed), and monsters are outside.
425     * with DETOUR_AMOUNT==2, the function will turn each corner, trying to
426     * find a path into the chamber. This is a good thing, but since there
427     * is no real path, it will just keep circling the chamber for
428     * ever (this could be a nice effect for monsters, but not for the function
429     * to get stuck in. I think for the monsters, if max is reached and
430     * we return the first direction the creature could move would result in the
431     * circling behaviour. Unfortunately, this function is also used to determined
432     * if the creature should cast a spell, so returning a direction in that case
433     * is probably not a good thing.
434     */
435     #define MAX_SPACES 50
436    
437    
438     /*
439     * Returns the direction to the player, if valid. Returns 0 otherwise.
440     * modified to verify there is a path to the player. Does this by stepping towards
441     * player and if path is blocked then see if blockage is close enough to player that
442     * direction to player is changed (ie zig or zag). Continue zig zag until either
443     * reach player or path is blocked. Thus, will only return true if there is a free
444     * path to player. Though path may not be a straight line. Note that it will find
445     * player hiding along a corridor at right angles to the corridor with the monster.
446     *
447     * Modified by MSW 2001-08-06 to handle tiled maps. Various notes:
448     * 1) With DETOUR_AMOUNT being 2, it should still go and find players hiding
449     * down corriders.
450     * 2) I think the old code was broken if the first direction the monster
451     * should move was blocked - the code would store the first direction without
452     * verifying that the player can actually move in that direction. The new
453     * code does not store anything in firstdir until we have verified that the
454     * monster can in fact move one space in that direction.
455     * 3) I'm not sure how good this code will be for moving multipart monsters,
456     * since only simple checks to blocked are being called, which could mean the monster
457     * is blocking itself.
458     */
459     int path_to_player(object *mon, object *pl, unsigned mindiff) {
460     rv_vector rv;
461     sint16 x,y;
462     int lastx,lasty,dir,i,diff, firstdir=0,lastdir, max=MAX_SPACES, mflags, blocked;
463     mapstruct *m ,*lastmap;
464    
465     get_rangevector(mon, pl, &rv, 0);
466    
467     if (rv.distance<mindiff) return 0;
468    
469     x=mon->x;
470     y=mon->y;
471     m=mon->map;
472     dir = rv.direction;
473     lastdir = firstdir = rv.direction; /* perhaps we stand next to pl, init firstdir too */
474     diff = FABS(rv.distance_x)>FABS(rv.distance_y)?FABS(rv.distance_x):FABS(rv.distance_y);
475     /* If we can't solve it within the search distance, return now. */
476     if (diff>max) return 0;
477     while (diff >1 && max>0) {
478     lastx = x;
479     lasty = y;
480     lastmap = m;
481     x = lastx + freearr_x[dir];
482     y = lasty + freearr_y[dir];
483    
484     mflags = get_map_flags(m, &m, x, y, &x, &y);
485     blocked = (mflags & P_OUT_OF_MAP) ? MOVE_ALL : GET_MAP_MOVE_BLOCK(m, x, y);
486    
487     /* Space is blocked - try changing direction a little */
488     if ((mflags & P_OUT_OF_MAP) || ((OB_TYPE_MOVE_BLOCK(mon, blocked))
489     && (m == mon->map && blocked_link(mon, m, x, y)))) {
490     /* recalculate direction from last good location. Possible
491     * we were not traversing ideal location before.
492     */
493     get_rangevector_from_mapcoord(lastmap, lastx, lasty, pl, &rv, 0);
494     if (rv.direction != dir) {
495     /* OK - says direction should be different - lets reset the
496     * the values so it will try again.
497     */
498     x = lastx;
499     y = lasty;
500     m = lastmap;
501     dir = firstdir = rv.direction;
502     } else {
503     /* direct path is blocked - try taking a side step to
504     * either the left or right.
505     * Note increase the values in the loop below to be
506     * more than -1/1 respectively will mean the monster takes
507     * bigger detour. Have to be careful about these values getting
508     * too big (3 or maybe 4 or higher) as the monster may just try
509     * stepping back and forth
510     */
511     for (i=-DETOUR_AMOUNT; i<=DETOUR_AMOUNT; i++) {
512     if (i==0) continue; /* already did this, so skip it */
513     /* Use lastdir here - otherwise,
514     * since the direction that the creature should move in
515     * may change, you could get infinite loops.
516     * ie, player is northwest, but monster can only
517     * move west, so it does that. It goes some distance,
518     * gets blocked, finds that it should move north,
519     * can't do that, but now finds it can move east, and
520     * gets back to its original point. lastdir contains
521     * the last direction the creature has successfully
522     * moved.
523     */
524    
525     x = lastx + freearr_x[absdir(lastdir+i)];
526     y = lasty + freearr_y[absdir(lastdir+i)];
527     m = lastmap;
528     mflags = get_map_flags(m, &m, x, y, &x, &y);
529     if (mflags & P_OUT_OF_MAP) continue;
530     blocked = GET_MAP_MOVE_BLOCK(m, x, y);
531     if (OB_TYPE_MOVE_BLOCK(mon, blocked)) continue;
532    
533     if (m == mon->map && blocked_link(mon, m, x, y)) break;
534     }
535     /* go through entire loop without finding a valid
536     * sidestep to take - thus, no valid path.
537     */
538     if (i==(DETOUR_AMOUNT+1))
539     return 0;
540     diff--;
541     lastdir=dir;
542     max--;
543     if (!firstdir) firstdir = dir+i;
544     } /* else check alternate directions */
545     } /* if blocked */
546     else {
547     /* we moved towards creature, so diff is less */
548     diff--;
549     max--;
550     lastdir=dir;
551     if (!firstdir) firstdir = dir;
552     }
553     if (diff<=1) {
554     /* Recalculate diff (distance) because we may not have actually
555     * headed toward player for entire distance.
556     */
557     get_rangevector_from_mapcoord(m, x, y, pl, &rv, 0);
558     diff = FABS(rv.distance_x)>FABS(rv.distance_y)?FABS(rv.distance_x):FABS(rv.distance_y);
559     }
560     if (diff>max) return 0;
561     }
562     /* If we reached the max, didn't find a direction in time */
563     if (!max) return 0;
564    
565     return firstdir;
566     }
567    
568     void give_initial_items(object *pl,treasurelist *items) {
569     object *op,*next=NULL;
570    
571     if(pl->randomitems!=NULL)
572     create_treasure(items,pl,GT_STARTEQUIP | GT_ONLY_GOOD,1,0);
573    
574     for (op=pl->inv; op; op=next) {
575     next = op->below;
576    
577     /* Forces get applied per default, unless they have the
578     * flag "neutral" set. Sorry but I can't think of a better way
579     */
580     if(op->type==FORCE && !QUERY_FLAG(op, FLAG_NEUTRAL))
581     SET_FLAG(op,FLAG_APPLIED);
582    
583     /* we never give weapons/armour if these cannot be used
584     * by this player due to race restrictions
585     */
586     if (pl->type == PLAYER) {
587     if ((!QUERY_FLAG(pl, FLAG_USE_ARMOUR) &&
588     (op->type == ARMOUR || op->type == BOOTS ||
589     op->type == CLOAK || op->type == HELMET ||
590     op->type == SHIELD || op->type == GLOVES ||
591     op->type == BRACERS || op->type == GIRDLE)) ||
592     (!QUERY_FLAG(pl, FLAG_USE_WEAPON) && op->type == WEAPON)) {
593     remove_ob (op);
594     free_object (op);
595     continue;
596     }
597     }
598    
599     /* This really needs to be better - we should really give
600     * a substitute spellbook. The problem is that we don't really
601     * have a good idea what to replace it with (need something like
602     * a first level treasurelist for each skill.)
603     * remove duplicate skills also
604     */
605     if(op->type==SPELLBOOK || op->type == SKILL) {
606     object *tmp;
607    
608     for (tmp=op->below; tmp; tmp=tmp->below)
609     if (tmp->type == op->type && tmp->name == op->name) break;
610    
611     if (tmp) {
612     remove_ob(op);
613     free_object(op);
614     LOG(llevError,"give_initial_items: Removing duplicate object %s\n",
615     tmp->name);
616     continue;
617     }
618     if (op->nrof > 1) op->nrof = 1;
619     }
620    
621     if (op->type == SPELLBOOK && op->inv) {
622     CLEAR_FLAG(op->inv, FLAG_STARTEQUIP);
623     }
624    
625     /* Give starting characters identified, uncursed, and undamned
626     * items. Just don't identify gold or silver, or it won't be
627     * merged properly.
628     */
629     if (need_identify(op)) {
630     SET_FLAG(op, FLAG_IDENTIFIED);
631     CLEAR_FLAG(op, FLAG_CURSED);
632     CLEAR_FLAG(op, FLAG_DAMNED);
633     }
634     if(op->type==SPELL) {
635     remove_ob(op);
636     free_object(op);
637     continue;
638     }
639     if(op->type==SKILL) {
640     SET_FLAG(op, FLAG_CAN_USE_SKILL);
641     op->stats.exp = 0;
642     op->level = 1;
643     }
644     } /* for loop of objects in player inv */
645    
646     /* Need to set up the skill pointers */
647     link_player_skills(pl);
648     }
649    
650     void get_name(object *op) {
651     op->contr->write_buf[0]='\0';
652     op->contr->state=ST_GET_NAME;
653     send_query(&op->contr->socket,0,"What is your name?\n:");
654     }
655    
656     void get_password(object *op) {
657     op->contr->write_buf[0]='\0';
658     op->contr->state=ST_GET_PASSWORD;
659     send_query(&op->contr->socket,CS_QUERY_HIDEINPUT, "What is your password?\n:");
660     }
661    
662     void play_again(object *op)
663     {
664     op->contr->state=ST_PLAY_AGAIN;
665     op->chosen_skill = NULL;
666     send_query(&op->contr->socket, CS_QUERY_SINGLECHAR, "Do you want to play again (a/q)?");
667     /* a bit of a hack, but there are various places early in th
668     * player creation process that a user can quit (eg, roll
669     * stats) that isn't removing the player. Taking a quick
670     * look, there are many places that call play_again without
671     * removing the player - it probably makes more sense
672     * to leave it to play_again to remove the object in all
673     * cases.
674     */
675     if (!QUERY_FLAG(op, FLAG_REMOVED))
676     remove_ob(op);
677     /* Need to set this to null - otherwise, it could point to garbage,
678     * and draw() doesn't check to see if the player is removed, only if
679     * the map is null or not swapped out.
680     */
681     op->map = NULL;
682     }
683    
684    
685     int receive_play_again(object *op, char key)
686     {
687     if(key=='q'||key=='Q') {
688     remove_friendly_object(op);
689     leave(op->contr,0); /* ericserver will draw the message */
690     return 2;
691     }
692     else if(key=='a'||key=='A') {
693     player *pl = op->contr;
694     const char *name = op->name;
695    
696     add_refcount(name);
697     remove_friendly_object(op);
698     free_object(op);
699     pl = get_player(pl);
700     op = pl->ob;
701     add_friendly_object(op);
702     op->contr->password[0]='~';
703     FREE_AND_CLEAR_STR(op->name);
704     FREE_AND_CLEAR_STR(op->name_pl);
705    
706     /* Lets put a space in here */
707     new_draw_info(NDI_UNIQUE, 0, op, "\n");
708     get_name(op);
709     op->name = name; /* Alrady added a refcount above */
710     op->name_pl = add_string(name);
711     set_first_map(op);
712     } else {
713     /* user pressed something else so just ask again... */
714     play_again(op);
715     }
716     return 0;
717     }
718    
719     void confirm_password(object *op) {
720    
721     op->contr->write_buf[0]='\0';
722     op->contr->state=ST_CONFIRM_PASSWORD;
723     send_query(&op->contr->socket, CS_QUERY_HIDEINPUT, "Please type your password again.\n:");
724     }
725    
726     void get_party_password(object *op, partylist *party) {
727     if (party == NULL) {
728     LOG(llevError, "get_party_password(): tried to make player %s join a NULL party", op->name);
729     return;
730     }
731     op->contr->write_buf[0]='\0';
732     op->contr->state=ST_GET_PARTY_PASSWORD;
733     op->contr->party_to_join = party;
734     send_query(&op->contr->socket, CS_QUERY_HIDEINPUT, "What is the password?\n:");
735     }
736    
737    
738     /* This rolls four 1-6 rolls and sums the best 3 of the 4. */
739     int roll_stat(void) {
740     int a[4],i,j,k;
741    
742     for(i=0;i<4;i++)
743     a[i]=(int)RANDOM()%6+1;
744    
745     for(i=0,j=0,k=7;i<4;i++)
746     if(a[i]<k)
747     k=a[i],j=i;
748    
749     for(i=0,k=0;i<4;i++) {
750     if(i!=j)
751     k+=a[i];
752     }
753     return k;
754     }
755    
756     void roll_stats(object *op) {
757     int sum=0;
758     int i = 0, j = 0;
759     int statsort[7];
760    
761     do {
762     op->stats.Str=roll_stat();
763     op->stats.Dex=roll_stat();
764     op->stats.Int=roll_stat();
765     op->stats.Con=roll_stat();
766     op->stats.Wis=roll_stat();
767     op->stats.Pow=roll_stat();
768     op->stats.Cha=roll_stat();
769     sum=op->stats.Str+op->stats.Dex+op->stats.Int+
770     op->stats.Con+op->stats.Wis+op->stats.Pow+
771     op->stats.Cha;
772     } while(sum<82||sum>116);
773    
774     /* Sort the stats so that rerolling is easier... */
775     statsort[0] = op->stats.Str;
776     statsort[1] = op->stats.Dex;
777     statsort[2] = op->stats.Int;
778     statsort[3] = op->stats.Con;
779     statsort[4] = op->stats.Wis;
780     statsort[5] = op->stats.Pow;
781     statsort[6] = op->stats.Cha;
782    
783     /* a quick and dirty bubblesort? */
784     do {
785     if (statsort[i] < statsort[i + 1]) {
786     j = statsort[i];
787     statsort[i] = statsort[i + 1];
788     statsort[i + 1] = j;
789     i = 0;
790     } else {
791     i++;
792     }
793     } while (i < 6);
794    
795     op->stats.Str = statsort[0];
796     op->stats.Dex = statsort[1];
797     op->stats.Con = statsort[2];
798     op->stats.Int = statsort[3];
799     op->stats.Wis = statsort[4];
800     op->stats.Pow = statsort[5];
801     op->stats.Cha = statsort[6];
802    
803    
804     op->contr->orig_stats.Str=op->stats.Str;
805     op->contr->orig_stats.Dex=op->stats.Dex;
806     op->contr->orig_stats.Int=op->stats.Int;
807     op->contr->orig_stats.Con=op->stats.Con;
808     op->contr->orig_stats.Wis=op->stats.Wis;
809     op->contr->orig_stats.Pow=op->stats.Pow;
810     op->contr->orig_stats.Cha=op->stats.Cha;
811    
812     op->level=1;
813     op->stats.exp=0;
814     op->stats.ac=0;
815    
816     op->contr->levhp[1] = 9;
817     op->contr->levsp[1] = 6;
818     op->contr->levgrace[1] = 3;
819    
820     fix_player(op);
821     op->stats.hp = op->stats.maxhp;
822     op->stats.sp = op->stats.maxsp;
823     op->stats.grace = op->stats.maxgrace;
824     op->contr->orig_stats=op->stats;
825     }
826    
827     void Roll_Again(object *op)
828     {
829     esrv_new_player(op->contr, 0);
830     send_query(&op->contr->socket,CS_QUERY_SINGLECHAR,"[y] to roll new stats [n] to use stats\n[1-7] [1-7] to swap stats.\nRoll again (y/n/1-7)? ");
831     }
832    
833     void Swap_Stat(object *op,int Swap_Second)
834     {
835     signed char tmp;
836     char buf[MAX_BUF];
837    
838     if ( op->contr->Swap_First == -1 ) {
839     new_draw_info(NDI_UNIQUE, 0,op,"How the hell did you get here?!?!!!");
840     new_draw_info(NDI_UNIQUE, 0,op,"Error in Swap_Stat code,");
841     new_draw_info(NDI_UNIQUE, 0,op,"mail korg@rdt.monash.edu.au");
842     return;
843     }
844    
845     tmp = get_attr_value(&op->contr->orig_stats, op->contr->Swap_First);
846    
847     set_attr_value(&op->contr->orig_stats, op->contr->Swap_First,
848     get_attr_value(&op->contr->orig_stats, Swap_Second));
849    
850     set_attr_value(&op->contr->orig_stats, Swap_Second, tmp);
851    
852     sprintf(buf,"%s done\n", short_stat_name[Swap_Second]);
853     new_draw_info(NDI_UNIQUE, 0,op, buf);
854     op->stats.Str = op->contr->orig_stats.Str;
855     op->stats.Dex = op->contr->orig_stats.Dex;
856     op->stats.Con = op->contr->orig_stats.Con;
857     op->stats.Int = op->contr->orig_stats.Int;
858     op->stats.Wis = op->contr->orig_stats.Wis;
859     op->stats.Pow = op->contr->orig_stats.Pow;
860     op->stats.Cha = op->contr->orig_stats.Cha;
861     op->stats.ac=0;
862    
863     op->level=1;
864     op->stats.exp=0;
865     op->stats.ac=0;
866    
867     op->contr->levhp[1] = 9;
868     op->contr->levsp[1] = 6;
869     op->contr->levgrace[1] = 3;
870    
871     fix_player(op);
872     op->stats.hp = op->stats.maxhp;
873     op->stats.sp = op->stats.maxsp;
874     op->stats.grace = op->stats.maxgrace;
875     op->contr->orig_stats=op->stats;
876     op->contr->Swap_First=-1;
877     }
878    
879    
880     /* This code has been greatly reduced, because with set_attr_value
881     * and get_attr_value, the stats can be accessed just numeric
882     * ids. stat_trans is a table that translate the number entered
883     * into the actual stat. It is needed because the order the stats
884     * are displayed in the stat window is not the same as how
885     * the number's access that stat. The table does that translation.
886     */
887     int key_roll_stat(object *op, char key)
888     {
889     int keynum = key -'0';
890     char buf[MAX_BUF];
891     static sint8 stat_trans[] = {-1, STR, DEX, CON, INT, WIS, POW, CHA};
892    
893     if (keynum>0 && keynum<=7) {
894     if (op->contr->Swap_First==-1) {
895     op->contr->Swap_First=stat_trans[keynum];
896     sprintf(buf,"%s ->", short_stat_name[stat_trans[keynum]]);
897     new_draw_info(NDI_UNIQUE, 0,op,buf);
898     }
899     else
900     Swap_Stat(op,stat_trans[keynum]);
901    
902     send_query(&op->contr->socket,CS_QUERY_SINGLECHAR,"");
903     return 1;
904     }
905     switch (key) {
906     case 'n':
907     case 'N': {
908     SET_FLAG(op, FLAG_WIZ);
909     if(op->map==NULL) {
910     LOG(llevError,"Map == NULL in state 2\n");
911     break;
912     }
913    
914     #if 0
915     /* So that enter_exit will put us at startx/starty */
916     op->x= -1;
917    
918     enter_exit(op,NULL);
919     #endif
920     SET_ANIMATION(op, 2); /* So player faces south */
921     /* Enter exit adds a player otherwise */
922     add_statbonus(op);
923     send_query(&op->contr->socket,CS_QUERY_SINGLECHAR,"Now choose a character.\nPress any key to change outlook.\nPress `d' when you're pleased.\n");
924     op->contr->state = ST_CHANGE_CLASS;
925     if (op->msg)
926     new_draw_info(NDI_BLUE, 0, op, op->msg);
927     return 0;
928     }
929     case 'y':
930     case 'Y':
931     roll_stats(op);
932     send_query(&op->contr->socket,CS_QUERY_SINGLECHAR,"");
933     return 1;
934    
935     case 'q':
936     case 'Q':
937     play_again(op);
938     return 1;
939    
940     default:
941     send_query(&op->contr->socket,CS_QUERY_SINGLECHAR,"Yes, No, Quit or 1-6. Roll again?");
942     return 0;
943     }
944     return 0;
945     }
946    
947     /* This function takes the key that is passed, and does the
948     * appropriate action with it (change class, or other things.
949     */
950    
951     int key_change_class(object *op, char key)
952     {
953     int tmp_loop;
954    
955     if(key=='q'||key=='Q') {
956     remove_ob(op);
957     play_again(op);
958     return 0;
959     }
960     if(key=='d'||key=='D') {
961     char buf[MAX_BUF];
962    
963     /* this must before then initial items are given */
964     esrv_new_player(op->contr, op->weight+op->carrying);
965     create_treasure(find_treasurelist("starting_wealth"),op, 0, 0, 0);
966    
967     /* Lauwenmark : Here we handle the BORN global event */
968     execute_global_event(EVENT_BORN, op);
969    
970     /* Lauwenmark : We then generate a LOGIN event */
971     execute_global_event(EVENT_LOGIN, op->contr, op->contr->socket.host);
972     op->contr->state=ST_PLAYING;
973    
974     if (op->msg) {
975     free_string(op->msg);
976     op->msg=NULL;
977     }
978    
979     /* We create this now because some of the unique maps will need it
980     * to save here.
981     */
982     sprintf(buf,"%s/%s/%s",settings.localdir,settings.playerdir,op->name);
983     make_path_to_file(buf);
984    
985     #ifdef AUTOSAVE
986     op->contr->last_save_tick = pticks;
987     #endif
988     start_info(op);
989     CLEAR_FLAG(op, FLAG_WIZ);
990     give_initial_items(op,op->randomitems);
991     link_player_skills(op);
992     esrv_send_inventory(op, op);
993     fix_player(op);
994     return 0;
995     }
996    
997     /* Following actually changes the class - this is the default command
998     * if we don't match with one of the options above.
999     */
1000    
1001     tmp_loop = 0;
1002     while(!tmp_loop) {
1003     const char *name = add_string (op->name);
1004     int x = op->x, y = op->y;
1005     remove_statbonus(op);
1006     remove_ob (op);
1007     op->arch = get_player_archetype(op->arch);
1008     copy_object (&op->arch->clone, op);
1009     op->stats = op->contr->orig_stats;
1010     free_string (op->name);
1011     op->name = name;
1012     free_string(op->name_pl);
1013     op->name_pl = add_string(name);
1014     op->x = x;
1015     op->y = y;
1016     SET_ANIMATION(op, 2); /* So player faces south */
1017     insert_ob_in_map (op, op->map, op,0);
1018     strncpy(op->contr->title, op->arch->clone.name, sizeof(op->contr->title)-1);
1019     op->contr->title[sizeof(op->contr->title)-1] = '\0';
1020     add_statbonus(op);
1021     tmp_loop=allowed_class(op);
1022     }
1023     update_object(op,UP_OBJ_FACE);
1024     esrv_update_item(UPD_FACE,op,op);
1025     fix_player(op);
1026     op->stats.hp=op->stats.maxhp;
1027     op->stats.sp=op->stats.maxsp;
1028     op->stats.grace=0;
1029     if (op->msg)
1030     new_draw_info(NDI_BLUE, 0, op, op->msg);
1031     send_query(&op->contr->socket,CS_QUERY_SINGLECHAR,"Press any key for the next race.\nPress `d' to play this race.\n");
1032     return 0;
1033     }
1034    
1035     int key_confirm_quit(object *op, char key)
1036     {
1037     char buf[MAX_BUF];
1038    
1039     if(key!='y'&&key!='Y'&&key!='q'&&key!='Q') {
1040     op->contr->state=ST_PLAYING;
1041     new_draw_info(NDI_UNIQUE, 0,op,"OK, continuing to play.");
1042     return 1;
1043     }
1044    
1045     /* Lauwenmark : Here we handle the REMOVE global event */
1046     execute_global_event(EVENT_REMOVE, op);
1047     terminate_all_pets(op);
1048     leave_map(op);
1049     op->direction=0;
1050     new_draw_info_format(NDI_UNIQUE | NDI_ALL, 5, NULL,
1051     "%s quits the game.",op->name);
1052    
1053     strcpy(op->contr->killer,"quit");
1054     check_score(op);
1055     op->contr->party=NULL;
1056     if (settings.set_title == TRUE)
1057     op->contr->own_title[0]='\0';
1058    
1059     if(!QUERY_FLAG(op,FLAG_WAS_WIZ)) {
1060     mapstruct *mp, *next;
1061    
1062     /* We need to hunt for any per player unique maps in memory and
1063     * get rid of them. The trailing slash in the path is intentional,
1064     * so that players named 'Ab' won't match against players 'Abe' pathname
1065     */
1066     sprintf(buf,"%s/%s/%s/", settings.localdir, settings.playerdir, op->name);
1067     for (mp=first_map; mp!=NULL; mp=next) {
1068     next = mp->next;
1069     if (!strncmp(mp->path, buf, strlen(buf)))
1070     delete_map(mp);
1071     }
1072    
1073     delete_character(op->name, 1);
1074     }
1075     play_again(op);
1076     return 1;
1077     }
1078    
1079     void flee_player(object *op) {
1080     int dir,diff;
1081     rv_vector rv;
1082    
1083     if(op->stats.hp < 0) {
1084     LOG(llevDebug, "Fleeing player is dead.\n");
1085     CLEAR_FLAG(op, FLAG_SCARED);
1086     return;
1087     }
1088    
1089     if(op->enemy==NULL) {
1090     LOG(llevDebug,"Fleeing player had no enemy.\n");
1091     CLEAR_FLAG(op, FLAG_SCARED);
1092     return;
1093     }
1094    
1095     /* Seen some crashes here. Since we don't store an
1096     * op->enemy_count, it is possible that something destroys the
1097     * actual enemy, and the object is recycled.
1098     */
1099     if (op->enemy->map == NULL) {
1100     CLEAR_FLAG(op, FLAG_SCARED);
1101     op->enemy=NULL;
1102     return;
1103     }
1104    
1105     if(!(random_roll(0, 4, op, PREFER_LOW)) && did_make_save(op, op->level, 0)) {
1106     op->enemy=NULL;
1107     CLEAR_FLAG(op, FLAG_SCARED);
1108     return;
1109     }
1110     get_rangevector(op, op->enemy, &rv, 0);
1111    
1112     dir=absdir(4+rv.direction);
1113     for(diff=0;diff<3;diff++) {
1114     int m=1-(RANDOM()&2);
1115     if(move_ob(op,absdir(dir+diff*m),op)||
1116     (diff==0 && move_ob(op,absdir(dir-diff*m),op))) {
1117     return;
1118     }
1119     }
1120     /* Cornered, get rid of scared */
1121     CLEAR_FLAG(op, FLAG_SCARED);
1122     op->enemy=NULL;
1123     }
1124    
1125    
1126     /* check_pick sees if there is stuff to be picked up/picks up stuff.
1127     * IT returns 1 if the player should keep on moving, 0 if he should
1128     * stop.
1129     */
1130     int check_pick(object *op) {
1131     object *tmp, *next;
1132     tag_t next_tag=0, op_tag;
1133     int stop = 0;
1134     int j, k, wvratio;
1135     char putstring[128], tmpstr[16];
1136    
1137    
1138     /* if you're flying, you cna't pick up anything */
1139     if (op->move_type & MOVE_FLYING)
1140     return 1;
1141    
1142     op_tag = op->count;
1143    
1144     next = op->below;
1145     if (next)
1146     next_tag = next->count;
1147    
1148     /* loop while there are items on the floor that are not marked as
1149     * destroyed */
1150     while (next && ! was_destroyed (next, next_tag))
1151     {
1152     tmp = next;
1153     next = tmp->below;
1154     if (next)
1155     next_tag = next->count;
1156    
1157     if (was_destroyed (op, op_tag))
1158     return 0;
1159    
1160     if ( ! can_pick (op, tmp))
1161     continue;
1162    
1163     if (op->contr->search_str[0]!='\0' && settings.search_items == TRUE)
1164     {
1165     if (item_matched_string (op, tmp, op->contr->search_str))
1166     pick_up (op, tmp);
1167     continue;
1168     }
1169    
1170     /* high not bit set? We're using the old autopickup model */
1171     if(!(op->contr->mode & PU_NEWMODE)) {
1172     switch (op->contr->mode) {
1173     case 0: return 1; /* don't pick up */
1174     case 1: pick_up (op, tmp);
1175     return 1;
1176     case 2: pick_up (op, tmp);
1177     return 0;
1178     case 3: return 0; /* stop before pickup */
1179     case 4: pick_up (op, tmp);
1180     break;
1181     case 5: pick_up (op, tmp);
1182     stop = 1;
1183     break;
1184     case 6:
1185     if (QUERY_FLAG (tmp, FLAG_KNOWN_MAGICAL) &&
1186     ! QUERY_FLAG(tmp, FLAG_KNOWN_CURSED))
1187     pick_up(op, tmp);
1188     break;
1189    
1190     case 7:
1191     if (tmp->type == MONEY || tmp->type == GEM)
1192     pick_up(op, tmp);
1193     break;
1194    
1195     default:
1196     /* use value density */
1197     if ( ! QUERY_FLAG (tmp, FLAG_UNPAID)
1198     && (query_cost (tmp, op, F_TRUE) * 100
1199     / (tmp->weight * MAX (tmp->nrof, 1)))
1200     >= op->contr->mode)
1201     pick_up(op,tmp);
1202     }
1203     }
1204     else { /* old model */
1205     /* NEW pickup handling */
1206     if(op->contr->mode & PU_DEBUG)
1207     {
1208     /* some debugging code to figure out item information */
1209     if(tmp->name!=NULL)
1210     sprintf(putstring,"item name: %s item type: %d weight/value: %d",
1211     tmp->name, tmp->type,
1212     (int)(query_cost(tmp, op, F_TRUE)*100 / (tmp->weight * MAX(tmp->nrof,1))));
1213     else
1214     sprintf(putstring,"item name: %s item type: %d weight/value: %d",
1215     tmp->arch->name, tmp->type,
1216     (int)(query_cost(tmp, op, F_TRUE)*100 / (tmp->weight * MAX(tmp->nrof,1))));
1217     new_draw_info(NDI_UNIQUE, 0,op,putstring);
1218    
1219     sprintf(putstring,"...flags: ");
1220     for(k=0;k<4;k++)
1221     {
1222     for(j=0;j<32;j++)
1223     {
1224     if((tmp->flags[k]>>j)&0x01)
1225     {
1226     sprintf(tmpstr,"%d ",k*32+j);
1227     strcat(putstring, tmpstr);
1228     }
1229     }
1230     }
1231     new_draw_info(NDI_UNIQUE, 0,op,putstring);
1232    
1233     #if 0
1234     /* print the flags too */
1235     for(k=0;k<4;k++)
1236     {
1237     fprintf(stderr,"%d [%d] ", k, k*32+31);
1238     for(j=0;j<32;j++)
1239     {
1240     fprintf(stderr,"%d",tmp->flags[k]>>(31-j)&0x01);
1241     if(!((j+1)%4))fprintf(stderr," ");
1242     }
1243     fprintf(stderr," [%d]\n", k*32);
1244     }
1245     #endif
1246     }
1247     /* philosophy:
1248     * It's easy to grab an item type from a pile, as long as it's
1249     * generic. This takes no game-time. For more detailed pickups
1250     * and selections, select-items shoul dbe used. This is a
1251     * grab-as-you-run type mode that's really useful for arrows for
1252     * example.
1253     * The drawback: right now it has no frontend, so you need to
1254     * stick the bits you want into a calculator in hex mode and then
1255     * convert to decimal and then 'pickup <#>
1256     */
1257    
1258     /* the first two modes are exclusive: if NOTHING we return, if
1259     * STOP then we stop. All the rest are applied sequentially,
1260     * meaning if any test passes, the item gets picked up. */
1261    
1262     /* if mode is set to pick nothing up, return */
1263    
1264     if(op->contr->mode & PU_NOTHING) return 1;
1265    
1266     /* if mode is set to stop when encountering objects, return */
1267     /* take STOP before INHIBIT since it doesn't actually pick
1268     * anything up */
1269    
1270     if(op->contr->mode & PU_STOP) return 0;
1271    
1272     /* useful for going into stores and not losing your settings... */
1273     /* and for battles wher you don't want to get loaded down while
1274     * fighting */
1275     if(op->contr->mode & PU_INHIBIT) return 1;
1276    
1277     /* prevent us from turning into auto-thieves :) */
1278     if (QUERY_FLAG (tmp, FLAG_UNPAID)) continue;
1279    
1280     /* ignore known cursed objects */
1281     if (QUERY_FLAG (tmp, FLAG_KNOWN_CURSED) && op->contr->mode & PU_NOT_CURSED) continue;
1282    
1283     /* all food and drink if desired */
1284     /* question: don't pick up known-poisonous stuff? */
1285     if(op->contr->mode & PU_FOOD)
1286     if (tmp->type == FOOD)
1287     { pick_up(op, tmp); if(0)fprintf(stderr,"FOOD\n"); continue; }
1288     if(op->contr->mode & PU_DRINK)
1289     if (tmp->type == DRINK || (tmp->type == POISON && !QUERY_FLAG(tmp, FLAG_KNOWN_CURSED)))
1290     { pick_up(op, tmp); if(0)fprintf(stderr,"DRINK\n"); continue; }
1291    
1292     if(op->contr->mode & PU_POTION)
1293     if (tmp->type == POTION)
1294     { pick_up(op, tmp); if(0)fprintf(stderr,"POTION\n"); continue; }
1295    
1296     /* spellbooks, skillscrolls and normal books/scrolls */
1297     if(op->contr->mode & PU_SPELLBOOK)
1298     if (tmp->type == SPELLBOOK)
1299     { pick_up(op, tmp); if(0)fprintf(stderr,"SPELLBOOK\n"); continue; }
1300     if(op->contr->mode & PU_SKILLSCROLL)
1301     if (tmp->type == SKILLSCROLL)
1302     { pick_up(op, tmp); if(0)fprintf(stderr,"SKILLSCROLL\n"); continue; }
1303     if(op->contr->mode & PU_READABLES)
1304     if (tmp->type == BOOK || tmp->type == SCROLL)
1305     { pick_up(op, tmp); if(0)fprintf(stderr,"READABLES\n"); continue; }
1306    
1307     /* wands/staves/rods/horns */
1308     if (op->contr->mode & PU_MAGIC_DEVICE)
1309     if (tmp->type == WAND || tmp->type == ROD || tmp->type == HORN)
1310     { pick_up(op, tmp); if(0)fprintf(stderr,"MAGIC_DEVICE\n"); continue; }
1311    
1312     /* pick up all magical items */
1313     if(op->contr->mode & PU_MAGICAL)
1314     if (QUERY_FLAG (tmp, FLAG_KNOWN_MAGICAL) && ! QUERY_FLAG(tmp, FLAG_KNOWN_CURSED))
1315     { pick_up(op, tmp); if(0)fprintf(stderr,"MAGICAL\n"); continue; }
1316    
1317     if(op->contr->mode & PU_VALUABLES)
1318     {
1319     if (tmp->type == MONEY || tmp->type == GEM)
1320     { pick_up(op, tmp); if(0)fprintf(stderr,"MONEY/GEM\n"); continue; }
1321     }
1322    
1323     /* rings & amulets - talismans seems to be typed AMULET */
1324     if(op->contr->mode & PU_JEWELS)
1325     if (tmp->type == RING || tmp->type == AMULET)
1326     { pick_up(op, tmp); if(0)fprintf(stderr,"JEWELS\n"); continue; }
1327    
1328     /* bows and arrows. Bows are good for selling! */
1329     if(op->contr->mode & PU_BOW)
1330     if (tmp->type == BOW)
1331     { pick_up(op, tmp); if(0)fprintf(stderr,"BOW\n"); continue; }
1332     if(op->contr->mode & PU_ARROW)
1333     if (tmp->type == ARROW)
1334     { pick_up(op, tmp); if(0)fprintf(stderr,"ARROW\n"); continue; }
1335    
1336     /* all kinds of armor etc. */
1337     if(op->contr->mode & PU_ARMOUR)
1338     if (tmp->type == ARMOUR)
1339     { pick_up(op, tmp); if(0)fprintf(stderr,"ARMOUR\n"); continue; }
1340     if(op->contr->mode & PU_HELMET)
1341     if (tmp->type == HELMET)
1342     { pick_up(op, tmp); if(0)fprintf(stderr,"HELMET\n"); continue; }
1343     if(op->contr->mode & PU_SHIELD)
1344     if (tmp->type == SHIELD)
1345     { pick_up(op, tmp); if(0)fprintf(stderr,"SHIELD\n"); continue; }
1346     if(op->contr->mode & PU_BOOTS)
1347     if (tmp->type == BOOTS)
1348     { pick_up(op, tmp); if(0)fprintf(stderr,"BOOTS\n"); continue; }
1349     if(op->contr->mode & PU_GLOVES)
1350     if (tmp->type == GLOVES)
1351     { pick_up(op, tmp); if(0)fprintf(stderr,"GLOVES\n"); continue; }
1352     if(op->contr->mode & PU_CLOAK)
1353     if (tmp->type == CLOAK)
1354     { pick_up(op, tmp); if(0)fprintf(stderr,"GLOVES\n"); continue; }
1355    
1356     /* hoping to catch throwing daggers here */
1357     if(op->contr->mode & PU_MISSILEWEAPON)
1358     if(tmp->type == WEAPON && QUERY_FLAG(tmp, FLAG_IS_THROWN))
1359     { pick_up(op, tmp); if(0)fprintf(stderr,"MISSILEWEAPON\n"); continue; }
1360    
1361     /* careful: chairs and tables are weapons! */
1362     if(op->contr->mode & PU_ALLWEAPON)
1363     {
1364     if(tmp->type == WEAPON && tmp->name!=NULL)
1365     {
1366     if(strstr(tmp->name,"table")==NULL && strstr(tmp->arch->name,"table")==NULL &&
1367     strstr(tmp->name,"chair") && strstr(tmp->arch->name,"chair")==NULL)
1368     { pick_up(op, tmp); if(0)fprintf(stderr,"WEAPON\n"); continue; }
1369     }
1370     if(tmp->type == WEAPON && tmp->name==NULL)
1371     {
1372     if(strstr(tmp->arch->name,"table")==NULL &&
1373     strstr(tmp->arch->name,"chair")==NULL)
1374     { pick_up(op, tmp); if(0)fprintf(stderr,"WEAPON\n"); continue; }
1375     }
1376     }
1377    
1378     /* misc stuff that's useful */
1379     if(op->contr->mode & PU_KEY)
1380     if (tmp->type == KEY || tmp->type == SPECIAL_KEY)
1381     { pick_up(op, tmp); if(0)fprintf(stderr,"KEY\n"); continue; }
1382    
1383     /* any of the last 4 bits set means we use the ratio for value
1384     * pickups */
1385     if(op->contr->mode & PU_RATIO)
1386     {
1387     /* use value density to decide what else to grab */
1388     /* >=7 was >= op->contr->mode */
1389     /* >=7 is the old standard setting. Now we take the last 4 bits
1390     * and multiply them by 5, giving 0..15*5== 5..75 */
1391     wvratio=(op->contr->mode & PU_RATIO) * 5;
1392     if ((query_cost(tmp, op, F_TRUE)*100 / (tmp->weight * MAX(tmp->nrof, 1))) >= wvratio)
1393     {
1394     pick_up(op, tmp);
1395     #if 0
1396     fprintf(stderr,"HIGH WEIGHT/VALUE [");
1397     if(tmp->name!=NULL) {
1398     fprintf(stderr,"%s", tmp->name);
1399     }
1400     else fprintf(stderr,"%s",tmp->arch->name);
1401     fprintf(stderr,",%d] = ", tmp->type);
1402     fprintf(stderr,"%d\n",(int)(query_cost(tmp,op,F_TRUE)*100 / (tmp->weight * MAX(tmp->nrof,1))));
1403     #endif
1404     continue;
1405     }
1406     }
1407     } /* the new pickup model */
1408     }
1409     return ! stop;
1410     }
1411    
1412     /*
1413     * Find an arrow in the inventory and after that
1414     * in the right type container (quiver). Pointer to the
1415     * found object is returned.
1416     */
1417     object *find_arrow(object *op, const char *type)
1418     {
1419     object *tmp = NULL;
1420    
1421     for(op=op->inv; op; op=op->below)
1422     if(!tmp && op->type==CONTAINER && op->race==type &&
1423     QUERY_FLAG(op,FLAG_APPLIED))
1424     tmp = find_arrow (op, type);
1425     else if (op->type==ARROW && op->race==type)
1426     return op;
1427     return tmp;
1428     }
1429    
1430     /*
1431     * Similar to find_arrow, but looks for (roughly) the best arrow to use
1432     * against the target. A full test is not performed, simply a basic test
1433     * of resistances. The archer is making a quick guess at what he sees down
1434     * the hall. Failing that it does it's best to pick the highest plus arrow.
1435     */
1436    
1437     object *find_better_arrow(object *op, object *target, const char *type, int *better)
1438     {
1439     object *tmp = NULL, *arrow, *ntmp;
1440     int attacknum, attacktype, betterby=0, i;
1441    
1442     if (!type)
1443     return NULL;
1444    
1445     for (arrow=op->inv; arrow; arrow=arrow->below) {
1446     if (arrow->type==CONTAINER && arrow->race==type &&
1447     QUERY_FLAG(arrow, FLAG_APPLIED)) {
1448     i = 0;
1449     ntmp = find_better_arrow(arrow, target, type, &i);
1450     if (i > betterby) {
1451     tmp = ntmp;
1452     betterby = i;
1453     }
1454     } else if (arrow->type==ARROW && arrow->race==type) {
1455     /* allways prefer assasination/slaying */
1456     if (target->race != NULL && arrow->slaying != NULL &&
1457     strstr(arrow->slaying, target->race)) {
1458     if (arrow->attacktype & AT_DEATH) {
1459     *better = 100;
1460     return arrow;
1461     } else {
1462     tmp = arrow;
1463     betterby = (arrow->magic + arrow->stats.dam) * 2;
1464     }
1465     } else {
1466     for (attacknum=0; attacknum < NROFATTACKS; attacknum++) {
1467     attacktype = 1<<attacknum;
1468     if ((arrow->attacktype & attacktype) && (target->arch->clone.resist[attacknum]) < 0)
1469     if (((arrow->magic + arrow->stats.dam)*(100-target->arch->clone.resist[attacknum])/100) > betterby) {
1470     tmp = arrow;
1471     betterby = (arrow->magic + arrow->stats.dam)*(100-target->arch->clone.resist[attacknum])/100;
1472     }
1473     }
1474     if ((2 + arrow->magic + arrow->stats.dam) > betterby) {
1475     tmp = arrow;
1476     betterby = 2 + arrow->magic + arrow->stats.dam;
1477     }
1478     if (arrow->title && (1 + arrow->magic + arrow->stats.dam) > betterby) {
1479     tmp = arrow;
1480     betterby = 1 + arrow->magic + arrow->stats.dam;
1481     }
1482     }
1483     }
1484     }
1485     if (tmp == NULL && arrow == NULL)
1486     return find_arrow(op, type);
1487    
1488     *better = betterby;
1489     return tmp;
1490     }
1491    
1492     /* looks in a given direction, finds the first valid target, and calls
1493     * find_better_arrow to find a decent arrow to use.
1494     * op = the shooter
1495     * type = bow->race
1496     * dir = fire direction
1497     */
1498    
1499     object *pick_arrow_target(object *op, const char *type, int dir)
1500     {
1501     object *tmp = NULL;
1502     mapstruct *m;
1503     int i, mflags, found, number;
1504     sint16 x, y;
1505    
1506     if (op->map == NULL)
1507     return find_arrow(op, type);
1508    
1509     /* do a dex check */
1510     number = (die_roll(2, 40, op, PREFER_LOW)-2)/2;
1511     if (number > (op->stats.Dex + (op->chosen_skill?op->chosen_skill->level:op->level)))
1512     return find_arrow(op, type);
1513    
1514     m = op->map;
1515     x = op->x;
1516     y = op->y;
1517    
1518     /* find the first target */
1519     for (i=0, found=0; i<20; i++) {
1520     x += freearr_x[dir];
1521     y += freearr_y[dir];
1522     mflags = get_map_flags(m, &m, x, y, &x, &y);
1523     if (mflags & P_OUT_OF_MAP || mflags & P_BLOCKSVIEW) {
1524     tmp = NULL;
1525     break;
1526     } else if (GET_MAP_MOVE_BLOCK(m, x, y) == MOVE_FLY_LOW) {
1527     /* This block presumes arrows and the like are MOVE_FLY_SLOW -
1528     * perhaps a bad assumption.
1529     */
1530     tmp = NULL;
1531     break;
1532     }
1533     if (mflags & P_IS_ALIVE) {
1534     for (tmp = GET_MAP_OB(m, x, y); tmp; tmp=tmp->above)
1535     if (QUERY_FLAG(tmp, FLAG_ALIVE)) {
1536     found++;
1537     break;
1538     }
1539     if (found)
1540     break;
1541     }
1542     }
1543     if (tmp == NULL)
1544     return find_arrow(op, type);
1545    
1546     if (tmp->head)
1547     tmp = tmp->head;
1548    
1549     return find_better_arrow(op, tmp, type, &i);
1550     }
1551    
1552     /*
1553     * Creature fires a bow - op can be monster or player. Returns
1554     * 1 if bow was actually fired, 0 otherwise.
1555     * op is the object firing the bow.
1556     * part is for multipart creatures - the part firing the bow.
1557     * dir is the direction of fire.
1558     * wc_mod is any special modifier to give (used in special player fire modes)
1559     * sx, sy are coordinates to fire arrow from - also used in some of the special
1560     * player fire modes.
1561     */
1562     int fire_bow(object *op, object *part, object *arrow, int dir, int wc_mod,
1563     sint16 sx, sint16 sy)
1564     {
1565     object *left, *bow;
1566     tag_t left_tag, tag;
1567     int bowspeed, mflags;
1568     mapstruct *m;
1569    
1570     if (!dir) {
1571     new_draw_info(NDI_UNIQUE, 0, op, "You can't shoot yourself!");
1572     return 0;
1573     }
1574     if (op->type == PLAYER)
1575     bow=op->contr->ranges[range_bow];
1576     else {
1577     for(bow=op->inv; bow; bow=bow->below)
1578     /* Don't check for applied - monsters don't apply bows - in that way, they
1579     * don't need to switch back and forth between bows and weapons.
1580     */
1581     if(bow->type==BOW)
1582     break;
1583    
1584     if (!bow) {
1585     LOG (llevError, "Range: bow without activated bow (%s).\n", op->name);
1586     return 0;
1587     }
1588     }
1589     if( !bow->race || !bow->skill) {
1590     new_draw_info_format(NDI_UNIQUE, 0, op, "Your %s is broken.", bow->name);
1591     return 0;
1592     }
1593    
1594     bowspeed = bow->stats.sp + dex_bonus[op->stats.Dex];
1595    
1596     /* penalize ROF for bestarrow */
1597     if (op->type == PLAYER && op->contr->bowtype == bow_bestarrow)
1598     bowspeed -= dex_bonus[op->stats.Dex] + 5;
1599     if (bowspeed < 1)
1600     bowspeed = 1;
1601    
1602     if (arrow == NULL) {
1603     if ((arrow=find_arrow(op, bow->race)) == NULL) {
1604     if (op->type == PLAYER)
1605     new_draw_info_format(NDI_UNIQUE, 0, op,
1606     "You have no %s left.", bow->race);
1607     /* FLAG_READY_BOW will get reset if the monsters picks up some arrows */
1608     else
1609     CLEAR_FLAG(op, FLAG_READY_BOW);
1610     return 0;
1611     }
1612     }
1613     mflags = get_map_flags(op->map, &m, sx, sy, &sx, &sy);
1614     if (mflags & P_OUT_OF_MAP) {
1615     return 0;
1616     }
1617     if (GET_MAP_MOVE_BLOCK(m, sx, sy) == MOVE_FLY_LOW) {
1618     new_draw_info(NDI_UNIQUE, 0,op,"Something is in the way.");
1619     return 0;
1620     }
1621    
1622     /* this should not happen, but sometimes does */
1623     if (arrow->nrof==0) {
1624     remove_ob(arrow);
1625     free_object(arrow);
1626     return 0;
1627     }
1628    
1629     left = arrow; /* these are arrows left to the player */
1630     left_tag = left->count;
1631     arrow = get_split_ob(arrow, 1);
1632     if (arrow == NULL) {
1633     new_draw_info_format(NDI_UNIQUE, 0, op, "You have no %s left.",
1634     bow->race);
1635     return 0;
1636     }
1637     set_owner(arrow, op);
1638     if (arrow->skill) free_string(arrow->skill);
1639     arrow->skill = add_refcount(bow->skill);
1640    
1641     arrow->direction=dir;
1642     arrow->x = sx;
1643     arrow->y = sy;
1644    
1645     if (op->type == PLAYER) {
1646     op->speed_left = 0.01 - (float)FABS(op->speed) * 100 / bowspeed;
1647     fix_player(op);
1648     }
1649    
1650     SET_ANIMATION(arrow, arrow->direction);
1651     arrow->stats.sp = arrow->stats.wc; /* save original wc and dam */
1652     arrow->stats.hp = arrow->stats.dam;
1653     arrow->stats.grace = arrow->attacktype;
1654     if (arrow->slaying != NULL)
1655     arrow->spellarg = strdup_local(arrow->slaying);
1656    
1657     /* Note that this was different for monsters - they got their level
1658     * added to the damage. I think the strength bonus is more proper.
1659     */
1660    
1661     arrow->stats.dam += (QUERY_FLAG(bow, FLAG_NO_STRENGTH) ?
1662     0 : dam_bonus[op->stats.Str]) +
1663     bow->stats.dam + bow->magic + arrow->magic;
1664    
1665     /* update the speed */
1666     arrow->speed = (float)((QUERY_FLAG(bow, FLAG_NO_STRENGTH) ?
1667     0 : dam_bonus[op->stats.Str]) +
1668     bow->magic + arrow->magic) / 5.0 +
1669     (float)bow->stats.dam / 7.0;
1670    
1671     if (arrow->speed < 1.0)
1672     arrow->speed = 1.0;
1673     update_ob_speed(arrow);
1674     arrow->speed_left = 0;
1675    
1676     if (op->type == PLAYER) {
1677     arrow->stats.wc = 20 - bow->magic - arrow->magic -
1678     (op->chosen_skill?op->chosen_skill->level:op->level) -
1679     dex_bonus[op->stats.Dex] - thaco_bonus[op->stats.Str] -
1680     arrow->stats.wc - bow->stats.wc + wc_mod;
1681    
1682     arrow->level = op->chosen_skill?op->chosen_skill->level:op->level;
1683     } else {
1684     arrow->stats.wc= op->stats.wc - bow->magic - arrow->magic -
1685     arrow->stats.wc + wc_mod;
1686    
1687     arrow->level = op->level;
1688     }
1689     if (arrow->attacktype == AT_PHYSICAL)
1690     arrow->attacktype |= bow->attacktype;
1691     if (bow->slaying != NULL)
1692     arrow->slaying = add_string(bow->slaying);
1693    
1694     arrow->map = m;
1695     arrow->move_type = MOVE_FLY_LOW;
1696     arrow->move_on = MOVE_FLY_LOW | MOVE_WALK;
1697    
1698     play_sound_map(op->map, op->x, op->y, SOUND_FIRE_ARROW);
1699     tag = arrow->count;
1700     insert_ob_in_map(arrow, m, op, 0);
1701    
1702     if (!was_destroyed(arrow, tag))
1703     move_arrow(arrow);
1704    
1705     if (op->type == PLAYER) {
1706     if (was_destroyed (left, left_tag))
1707     esrv_del_item(op->contr, left_tag);
1708     else
1709     esrv_send_item(op, left);
1710     }
1711     return 1;
1712     }
1713    
1714     /* Special fire code for players - this takes into
1715     * account the special fire modes players can have
1716     * but monsters can't. Putting that code here
1717     * makes the fire_bow code much cleaner.
1718     * this function should only be called if 'op' is a player,
1719     * hence the function name.
1720     */
1721     int player_fire_bow(object *op, int dir)
1722     {
1723     int ret=0, wcmod=0;
1724    
1725     if (op->contr->bowtype == bow_bestarrow) {
1726     ret = fire_bow(op, op,
1727     pick_arrow_target(op, op->contr->ranges[range_bow]->race, dir),
1728     dir, 0, op->x, op->y);
1729     } else if (op->contr->bowtype >= bow_n && op->contr->bowtype <= bow_nw) {
1730     if (!similar_direction(dir, op->contr->bowtype - bow_n + 1))
1731     wcmod =-1;
1732     ret = fire_bow(op, op, NULL, op->contr->bowtype - bow_n + 1, wcmod,
1733     op->x, op->y);
1734     } else if (op->contr->bowtype == bow_threewide) {
1735     ret = fire_bow(op, op, NULL, dir, 0, op->x, op->y);
1736     ret |= fire_bow(op, op, NULL, dir, -5, op->x + freearr_x[absdir(dir+2)], op->y + freearr_y[absdir(dir+2)]);
1737     ret |= fire_bow(op, op, NULL, dir, -5, op->x + freearr_x[absdir(dir-2)], op->y + freearr_y[absdir(dir-2)]);
1738     } else if (op->contr->bowtype == bow_spreadshot) {
1739     ret |= fire_bow(op, op, NULL, dir, 0, op->x, op->y);
1740     ret |= fire_bow(op, op, NULL, absdir(dir-1), -5, op->x, op->y);
1741     ret |= fire_bow(op, op, NULL, absdir(dir+1), -5, op->x, op->y);
1742    
1743     } else {
1744     /* Simple case */
1745     ret = fire_bow(op, op, NULL, dir, 0, op->x, op->y);
1746     }
1747     return ret;
1748     }
1749    
1750    
1751     /* Fires a misc (wand/rod/horn) object in 'dir'.
1752     * Broken apart from 'fire' to keep it more readable.
1753     */
1754     void fire_misc_object(object *op, int dir)
1755     {
1756     object *item;
1757    
1758     if (!op->contr->ranges[range_misc]) {
1759     new_draw_info(NDI_UNIQUE, 0,op,"You have range item readied.");
1760     return;
1761     }
1762    
1763     item = op->contr->ranges[range_misc];
1764     if (!item->inv) {
1765     LOG(llevError,"Object %s lacks a spell\n", item->name);
1766     return;
1767     }
1768     if (item->type == WAND) {
1769     if(item->stats.food<=0) {
1770     play_sound_player_only(op->contr, SOUND_WAND_POOF,0,0);
1771     new_draw_info_format(NDI_UNIQUE, 0,op,"The %s goes poof.", query_base_name(item, 0));
1772     return;
1773     }
1774     } else if (item->type == ROD || item->type==HORN) {
1775     if(item->stats.hp<MAX(item->inv->stats.sp, item->inv->stats.grace)) {
1776     play_sound_player_only(op->contr, SOUND_WAND_POOF,0,0);
1777     if (item->type== ROD)
1778     new_draw_info_format(NDI_UNIQUE, 0,op,
1779     "The %s whines for a while, but nothing happens.", query_base_name(item,0));
1780     else
1781     new_draw_info_format(NDI_UNIQUE, 0,op,
1782     "The %s needs more time to charge.", query_base_name(item,0));
1783     return;
1784     }
1785     }
1786    
1787     if(cast_spell(op,item,dir,item->inv,NULL)) {
1788     SET_FLAG(op, FLAG_BEEN_APPLIED); /* You now know something about it */
1789     if (item->type == WAND) {
1790     if (!(--item->stats.food)) {
1791     object *tmp;
1792     if (item->arch) {
1793     CLEAR_FLAG(item, FLAG_ANIMATE);
1794     item->face = item->arch->clone.face;
1795     item->speed = 0;
1796     update_ob_speed(item);
1797     }
1798     if ((tmp=is_player_inv(item)))
1799     esrv_update_item(UPD_ANIM, tmp, item);
1800     }
1801     }
1802     else if (item->type == ROD || item->type==HORN) {
1803     drain_rod_charge(item);
1804     }
1805     }
1806     }
1807    
1808     /* Received a fire command for the player - go and do it.
1809     */
1810     void fire(object *op,int dir) {
1811     int spellcost=0;
1812    
1813     /* check for loss of invisiblity/hide */
1814     if (action_makes_visible(op)) make_visible(op);
1815    
1816     switch(op->contr->shoottype) {
1817     case range_none:
1818     return;
1819    
1820     case range_bow:
1821     player_fire_bow(op, dir);
1822     return;
1823    
1824     case range_magic: /* Casting spells */
1825     spellcost=(cast_spell(op,op,dir,op->contr->ranges[range_magic],op->contr->spellparam[0]?op->contr->spellparam:NULL));
1826     return;
1827    
1828     case range_misc:
1829     fire_misc_object(op, dir);
1830     return;
1831    
1832     case range_golem: /* Control summoned monsters from scrolls */
1833     if(op->contr->ranges[range_golem]==NULL ||
1834     op->contr->golem_count != op->contr->ranges[range_golem]->count) {
1835     op->contr->ranges[range_golem] = NULL;
1836     op->contr->shoottype=range_none;
1837     op->contr->golem_count = 0;
1838     }
1839     else
1840     control_golem(op->contr->ranges[range_golem], dir);
1841     return;
1842    
1843     case range_skill:
1844     if(!op->chosen_skill) {
1845     if(op->type==PLAYER)
1846     new_draw_info(NDI_UNIQUE, 0,op,"You have no applicable skill to use.");
1847     return;
1848     }
1849     (void) do_skill(op,op,op->chosen_skill,dir,NULL);
1850     return;
1851     case range_builder:
1852     apply_map_builder( op, dir );
1853     return;
1854     default:
1855     new_draw_info(NDI_UNIQUE, 0,op,"Illegal shoot type.");
1856     return;
1857     }
1858     }
1859    
1860    
1861    
1862     /* find_key
1863     * We try to find a key for the door as passed. If we find a key
1864     * and successfully use it, we return the key, otherwise NULL
1865     * This function merges both normal and locked door, since the logic
1866     * for both is the same - just the specific key is different.
1867     * pl is the player,
1868     * inv is the objects inventory to searched
1869     * door is the door we are trying to match against.
1870     * This function can be called recursively to search containers.
1871     */
1872    
1873     object * find_key(object *pl, object *container, object *door)
1874     {
1875     object *tmp,*key;
1876    
1877     /* Should not happen, but sanity checking is never bad */
1878     if (container->inv == NULL) return NULL;
1879    
1880     /* First, lets try to find a key in the top level inventory */
1881     for (tmp=container->inv; tmp!=NULL; tmp=tmp->below) {
1882     if (door->type==DOOR && tmp->type==KEY) break;
1883     /* For sanity, we should really check door type, but other stuff
1884     * (like containers) can be locked with special keys
1885     */
1886     if (tmp->slaying && tmp->type==SPECIAL_KEY &&
1887     tmp->slaying==door->slaying) break;
1888     }
1889     /* No key found - lets search inventories now */
1890     /* If we find and use a key in an inventory, return at that time.
1891     * otherwise, if we search all the inventories and still don't find
1892     * a key, return
1893     */
1894     if (!tmp) {
1895     for (tmp=container->inv; tmp!=NULL; tmp=tmp->below) {
1896     /* No reason to search empty containers */
1897     if (tmp->type==CONTAINER && tmp->inv) {
1898     if ((key=find_key(pl, tmp, door))!=NULL) return key;
1899     }
1900     }
1901     if (!tmp) return NULL;
1902     }
1903     /* We get down here if we have found a key. Now if its in a container,
1904     * see if we actually want to use it
1905     */
1906     if (pl!=container) {
1907     /* Only let players use keys in containers */
1908     if (!pl->contr) return NULL;
1909     /* cases where this fails:
1910     * If we only search the player inventory, return now since we
1911     * are not in the players inventory.
1912     * If the container is not active, return now since only active
1913     * containers can be used.
1914     * If we only search keyrings and the container does not have
1915     * a race/isn't a keyring.
1916     * No checking for all containers - to fall through past here,
1917     * inv must have been an container and must have been active.
1918     *
1919     * Change the color so that the message doesn't disappear with
1920     * all the others.
1921     */
1922     if (pl->contr->usekeys == key_inventory ||
1923     !QUERY_FLAG(container, FLAG_APPLIED) ||
1924     (pl->contr->usekeys == keyrings &&
1925     (!container->race || strcmp(container->race, "keys")))
1926     ) {
1927     new_draw_info_format(NDI_UNIQUE|NDI_BROWN, 0, pl,
1928     "The %s in your %s vibrates as you approach the door",
1929     query_name(tmp), query_name(container));
1930     return NULL;
1931     }
1932     }
1933     return tmp;
1934     }
1935    
1936     /* moved door processing out of move_player_attack.
1937     * returns 1 if player has opened the door with a key
1938     * such that the caller should not do anything more,
1939     * 0 otherwise
1940     */
1941     static int player_attack_door(object *op, object *door)
1942     {
1943    
1944     /* If its a door, try to find a use a key. If we do destroy the door,
1945     * might as well return immediately as there is nothing more to do -
1946     * otherwise, we fall through to the rest of the code.
1947     */
1948     object *key=find_key(op, op, door);
1949    
1950     /* IF we found a key, do some extra work */
1951     if (key) {
1952     object *container=key->env;
1953    
1954     play_sound_map(op->map, op->x, op->y, SOUND_OPEN_DOOR);
1955     if(action_makes_visible(op)) make_visible(op);
1956     if(door->inv &&(door->inv->type ==RUNE || door->inv->type ==TRAP)) spring_trap(door->inv,op);
1957     if (door->type == DOOR) {
1958     hit_player(door,9998,op,AT_PHYSICAL,1); /* Break through the door */
1959     }
1960     else if(door->type==LOCKED_DOOR) {
1961     new_draw_info_format(NDI_UNIQUE, NDI_BROWN, op,
1962     "You open the door with the %s", query_short_name(key));
1963     remove_door2(door); /* remove door without violence ;-) */
1964     }
1965     /* Do this after we print the message */
1966     decrease_ob(key); /* Use up one of the keys */
1967     /* Need to update the weight the container the key was in */
1968     if (container != op)
1969     esrv_update_item(UPD_WEIGHT, op, container);
1970     return 1; /* Nothing more to do below */
1971     } else if (door->type==LOCKED_DOOR) {
1972     /* Might as well return now - no other way to open this */
1973     new_draw_info(NDI_UNIQUE | NDI_NAVY, 0, op, door->msg);
1974     return 1;
1975     }
1976     return 0;
1977     }
1978    
1979     /* This function is just part of a breakup from move_player.
1980     * It should keep the code cleaner.
1981     * When this is called, the players direction has been updated
1982     * (taking into account confusion.) The player is also actually
1983     * going to try and move (not fire weapons).
1984     */
1985    
1986     void move_player_attack(object *op, int dir)
1987     {
1988     object *tmp, *mon;
1989     sint16 nx=freearr_x[dir]+op->x,ny=freearr_y[dir]+op->y;
1990     int on_battleground;
1991     mapstruct *m;
1992    
1993     on_battleground = op_on_battleground(op, NULL, NULL);
1994    
1995     /* If braced, or can't move to the square, and it is not out of the
1996     * map, attack it. Note order of if statement is important - don't
1997     * want to be calling move_ob if braced, because move_ob will move the
1998     * player. This is a pretty nasty hack, because if we could
1999     * move to some space, it then means that if we are braced, we should
2000     * do nothing at all. As it is, if we are braced, we go through
2001     * quite a bit of processing. However, it probably is less than what
2002     * move_ob uses.
2003     */
2004     if ((op->contr->braced || !move_ob(op,dir,op)) && !out_of_map(op->map,nx,ny)) {
2005     if (OUT_OF_REAL_MAP(op->map, nx, ny)) {
2006     m = get_map_from_coord(op->map, &nx, &ny);
2007     if (!m) return; /* Don't think this should happen */
2008     }
2009     else m =op->map;
2010    
2011     if ((tmp=get_map_ob(m,nx,ny))==NULL) {
2012     /* LOG(llevError,"player_move_attack: get_map_ob returns NULL, but player can not more there.\n");*/
2013     return;
2014     }
2015    
2016     mon = NULL;
2017     /* Go through all the objects, and find ones of interest. Only stop if
2018     * we find a monster - that is something we know we want to attack.
2019     * if its a door or barrel (can roll) see if there may be monsters
2020     * on the space
2021     */
2022     while (tmp!=NULL) {
2023     if (tmp == op) {
2024     tmp=tmp->above;
2025     continue;
2026     }
2027     if (QUERY_FLAG(tmp,FLAG_ALIVE)) {
2028     mon = tmp;
2029     break;
2030     }
2031     if (tmp->type==LOCKED_DOOR || QUERY_FLAG(tmp,FLAG_CAN_ROLL))
2032     mon = tmp;
2033     tmp=tmp->above;
2034     }
2035    
2036     if (mon==NULL) /* This happens anytime the player tries to move */
2037     return; /* into a wall */
2038    
2039     if(mon->head != NULL)
2040     mon = mon->head;
2041    
2042     if ((mon->type==DOOR && mon->stats.hp>=0) || (mon->type==LOCKED_DOOR))
2043     if (player_attack_door(op, mon)) return;
2044    
2045     /* The following deals with possibly attacking peaceful
2046     * or frienddly creatures. Basically, all players are considered
2047     * unaggressive. If the moving player has peaceful set, then the
2048     * object should be pushed instead of attacked. It is assumed that
2049     * if you are braced, you will not attack friends accidently,
2050     * and thus will not push them.
2051     */
2052    
2053     /* If the creature is a pet, push it even if the player is not
2054     * peaceful. Our assumption is the creature is a pet if the
2055     * player owns it and it is either friendly or unagressive.
2056     */
2057     if ((op->type==PLAYER) && get_owner(mon)==op &&
2058     (QUERY_FLAG(mon,FLAG_UNAGGRESSIVE) || QUERY_FLAG(mon, FLAG_FRIENDLY)))
2059     {
2060     /* If we're braced, we don't want to switch places with it */
2061     if (op->contr->braced) return;
2062     play_sound_map(op->map, op->x, op->y, SOUND_PUSH_PLAYER);
2063     (void) push_ob(mon,dir,op);
2064     if(op->contr->tmp_invis||op->hide) make_visible(op);
2065     return;
2066     }
2067    
2068     /* in certain circumstances, you shouldn't attack friendly
2069     * creatures. Note that if you are braced, you can't push
2070     * someone, but put it inside this loop so that you won't
2071     * attack them either.
2072     */
2073     if ((mon->type==PLAYER || mon->enemy != op) &&
2074     (mon->type==PLAYER || QUERY_FLAG(mon,FLAG_UNAGGRESSIVE) || QUERY_FLAG(mon, FLAG_FRIENDLY)) &&
2075     (op->contr->peaceful && !on_battleground)) {
2076     if (!op->contr->braced) {
2077     play_sound_map(op->map, op->x, op->y, SOUND_PUSH_PLAYER);
2078     (void) push_ob(mon,dir,op);
2079     } else {
2080     new_draw_info(0, 0,op,"You withhold your attack");
2081     }
2082     if(op->contr->tmp_invis||op->hide) make_visible(op);
2083     }
2084    
2085     /* If the object is a boulder or other rollable object, then
2086     * roll it if not braced. You can't roll it if you are braced.
2087     */
2088     else if(QUERY_FLAG(mon,FLAG_CAN_ROLL)&&(!op->contr->braced)) {
2089     recursive_roll(mon,dir,op);
2090     if(action_makes_visible(op)) make_visible(op);
2091     }
2092    
2093     /* Any generic living creature. Including things like doors.
2094     * Way it works is like this: First, it must have some hit points
2095     * and be living. Then, it must be one of the following:
2096     * 1) Not a player, 2) A player, but of a different party. Note
2097     * that party_number -1 is no party, so attacks can still happen.
2098     */
2099    
2100     else if ((mon->stats.hp>=0) && QUERY_FLAG(mon, FLAG_ALIVE) &&
2101     ((mon->type!=PLAYER || op->contr->party==NULL ||
2102     op->contr->party!=mon->contr->party))) {
2103    
2104     /* If the player hasn't hit something this tick, and does
2105     * so, give them speed boost based on weapon speed. Doing
2106     * it here is better than process_players2, which basically
2107     * incurred a 1 tick offset.
2108     */
2109     if (!op->contr->has_hit) {
2110     op->speed_left += op->speed / op->contr->weapon_sp;
2111    
2112     op->contr->has_hit = 1; /* The last action was to hit, so use weapon_sp */
2113     }
2114    
2115     skill_attack(mon, op, 0, NULL, NULL);
2116    
2117     /* If attacking another player, that player gets automatic
2118     * hitback, and doesn't loose luck either.
2119     * Disable hitback on the battleground or if the target is
2120     * the wiz.
2121     */
2122     if (mon->type == PLAYER && mon->stats.hp >= 0 && !mon->contr->has_hit &&
2123     !on_battleground && !QUERY_FLAG(mon, FLAG_WIZ)) {
2124     short luck = mon->stats.luck;
2125     mon->contr->has_hit = 1;
2126     skill_attack(op, mon, 0, NULL, NULL);
2127     mon->stats.luck = luck;
2128     }
2129     if(action_makes_visible(op)) make_visible(op);
2130     }
2131     } /* if player should attack something */
2132     }
2133    
2134     int move_player(object *op,int dir) {
2135     int pick;
2136    
2137     if(op->map == NULL || op->map->in_memory != MAP_IN_MEMORY)
2138     return 0;
2139    
2140     /* Sanity check: make sure dir is valid */
2141     if ( ( dir < 0 ) || ( dir >= 9 ) ) {
2142     LOG( llevError, "move_player: invalid direction %d\n", dir);
2143     return 0;
2144     }
2145    
2146     /* peterm: added following line */
2147     if(QUERY_FLAG(op,FLAG_CONFUSED) && dir)
2148     dir = absdir(dir + RANDOM()%3 + RANDOM()%3 - 2);
2149    
2150     op->facing = dir;
2151    
2152     if(op->hide) do_hidden_move(op);
2153    
2154     if(op->contr->fire_on) {
2155     fire(op,dir);
2156     }
2157     else move_player_attack(op,dir);
2158    
2159     pick = check_pick(op);
2160    
2161    
2162     /* Add special check for newcs players and fire on - this way, the
2163     * server can handle repeat firing.
2164     */
2165     if (op->contr->fire_on || (op->contr->run_on && pick!=0)) {
2166     op->direction = dir;
2167     } else {
2168     op->direction=0;
2169     }
2170     /* Update how the player looks. Use the facing, so direction may
2171     * get reset to zero. This allows for full animation capabilities
2172     * for players.
2173     */
2174     animate_object(op, op->facing);
2175     return 0;
2176     }
2177    
2178     /* This is similar to handle_player, below, but is only used by the
2179     * new client/server stuff.
2180     * This is sort of special, in that the new client/server actually uses
2181     * the new speed values for commands.
2182     *
2183     * Returns true if there are more actions we can do.
2184     */
2185     int handle_newcs_player(object *op)
2186     {
2187     if (op->contr->hidden) {
2188     op->invisible = 1000;
2189     /* the socket code flasehs the player visible/invisible
2190     * depending on the value if invisible, so we need to
2191     * alternate it here for it to work correctly.
2192     */
2193     if (pticks & 2) op->invisible--;
2194     }
2195     else if(op->invisible&&!(QUERY_FLAG(op,FLAG_MAKE_INVIS))) {
2196     op->invisible--;
2197     if(!op->invisible) {
2198     make_visible(op);
2199     new_draw_info(NDI_UNIQUE, 0, op, "Your invisibility spell runs out.");
2200     }
2201     }
2202    
2203     if (QUERY_FLAG(op, FLAG_SCARED)) {
2204     flee_player(op);
2205     /* If player is still scared, that is his action for this tick */
2206     if (QUERY_FLAG(op, FLAG_SCARED)) {
2207     op->speed_left--;
2208     return 0;
2209     }
2210     }
2211    
2212     /* I've been seeing crashes where the golem has been destroyed, but
2213     * the player object still points to the defunct golem. The code that
2214     * destroys the golem looks correct, and it doesn't always happen, so
2215     * put this in a a workaround to clean up the golem pointer.
2216     */
2217     if (op->contr->ranges[range_golem] &&
2218     ((op->contr->golem_count != op->contr->ranges[range_golem]->count) ||
2219     QUERY_FLAG(op->contr->ranges[range_golem], FLAG_REMOVED))) {
2220     op->contr->ranges[range_golem] = NULL;
2221     op->contr->golem_count = 0;
2222     }
2223    
2224     /* call this here - we also will call this in do_ericserver, but
2225     * the players time has been increased when doericserver has been
2226     * called, so we recheck it here.
2227     */
2228     HandleClient(&op->contr->socket, op->contr);
2229     if (op->speed_left<0) return 0;
2230    
2231     if(op->direction && (op->contr->run_on || op->contr->fire_on)) {
2232     /* All move commands take 1 tick, at least for now */
2233     op->speed_left--;
2234    
2235     /* Instead of all the stuff below, let move_player take care
2236     * of it. Also, some of the skill stuff is only put in
2237     * there, as well as the confusion stuff.
2238     */
2239     move_player(op, op->direction);
2240     if (op->speed_left>0) return 1;
2241     else return 0;
2242     }
2243     return 0;
2244     }
2245    
2246     int save_life(object *op) {
2247     object *tmp;
2248    
2249     if(!QUERY_FLAG(op,FLAG_LIFESAVE))
2250     return 0;
2251    
2252     for(tmp=op->inv;tmp!=NULL;tmp=tmp->below)
2253     if(QUERY_FLAG(tmp, FLAG_APPLIED)&&QUERY_FLAG(tmp,FLAG_LIFESAVE)) {
2254     play_sound_map(op->map, op->x, op->y, SOUND_OB_EVAPORATE);
2255     new_draw_info_format(NDI_UNIQUE, 0,op,
2256     "Your %s vibrates violently, then evaporates.",
2257     query_name(tmp));
2258     if (op->contr)
2259     esrv_del_item(op->contr, tmp->count);
2260     remove_ob(tmp);
2261     free_object(tmp);
2262     CLEAR_FLAG(op, FLAG_LIFESAVE);
2263     if(op->stats.hp<0)
2264     op->stats.hp = op->stats.maxhp;
2265     if(op->stats.food<0)
2266     op->stats.food = 999;
2267     fix_player(op);
2268     return 1;
2269     }
2270     LOG(llevError,"Error: LIFESAVE set without applied object.\n");
2271     CLEAR_FLAG(op, FLAG_LIFESAVE);
2272     enter_player_savebed(op); /* bring him home. */
2273     return 0;
2274     }
2275    
2276     /* This goes throws the inventory and removes unpaid objects, and puts them
2277     * back in the map (location and map determined by values of env). This
2278     * function will descend into containers. op is the object to start the search
2279     * from.
2280     */
2281     void remove_unpaid_objects(object *op, object *env)
2282     {
2283     object *next;
2284    
2285     while (op) {
2286     next=op->below; /* Make sure we have a good value, in case
2287     * we remove object 'op'
2288     */
2289     if (QUERY_FLAG(op, FLAG_UNPAID)) {
2290     remove_ob(op);
2291     op->x = env->x;
2292     op->y = env->y;
2293     if (env->type == PLAYER)
2294     esrv_del_item(env->contr, op->count);
2295     insert_ob_in_map(op, env->map, NULL,0);
2296     }
2297     else if (op->inv) remove_unpaid_objects(op->inv, env);
2298     op=next;
2299     }
2300     }
2301    
2302    
2303     /*
2304     * Returns pointer a static string containing gravestone text
2305     * Moved from apply.c to player.c - player.c is what
2306     * actually uses this function. player.c may not be quite the
2307     * best, a misc file for object actions is probably better,
2308     * but there isn't one in the server directory.
2309     */
2310     char *gravestone_text (object *op)
2311     {
2312     static char buf2[MAX_BUF];
2313     char buf[MAX_BUF];
2314     time_t now = time (NULL);
2315    
2316     strcpy (buf2, " R.I.P.\n\n");
2317     if (op->type == PLAYER)
2318     sprintf (buf, "%s the %s\n", op->name, op->contr->title);
2319     else
2320     sprintf (buf, "%s\n", op->name);
2321     strncat (buf2, " ", 20 - strlen (buf) / 2);
2322     strcat (buf2, buf);
2323     if (op->type == PLAYER)
2324     sprintf (buf, "who was in level %d when killed\n", op->level);
2325     else
2326     sprintf (buf, "who was in level %d when died.\n\n", op->level);
2327     strncat (buf2, " ", 20 - strlen (buf) / 2);
2328     strcat (buf2, buf);
2329     if (op->type == PLAYER) {
2330     sprintf (buf, "by %s.\n\n", op->contr->killer);
2331     strncat (buf2, " ", 21 - strlen (buf) / 2);
2332     strcat (buf2, buf);
2333     }
2334     strftime (buf, MAX_BUF, "%b %d %Y\n", localtime (&now));
2335     strncat (buf2, " ", 20 - strlen (buf) / 2);
2336     strcat (buf2, buf);
2337     return buf2;
2338     }
2339    
2340    
2341    
2342     void do_some_living(object *op) {
2343     int last_food=op->stats.food;
2344     int gen_hp, gen_sp, gen_grace;
2345     int over_hp, over_sp, over_grace;
2346     int i;
2347     int rate_hp = 1200;
2348     int rate_sp = 2500;
2349     int rate_grace = 2000;
2350     const int max_hp = 1;
2351     const int max_sp = 1;
2352     const int max_grace = 1;
2353    
2354     if (op->contr->outputs_sync) {
2355     for (i=0; i<NUM_OUTPUT_BUFS; i++)
2356     if (op->contr->outputs[i].buf!=NULL &&
2357     (op->contr->outputs[i].first_update+op->contr->outputs_sync)<pticks)
2358     flush_output_element(op, &op->contr->outputs[i]);
2359     }
2360    
2361     if(op->contr->state==ST_PLAYING) {
2362    
2363     /* these next three if clauses make it possible to SLOW DOWN
2364     hp/grace/spellpoint regeneration. */
2365     if(op->contr->gen_hp >= 0 )
2366     gen_hp=(op->contr->gen_hp+1)*op->stats.maxhp;
2367     else {
2368     gen_hp = op->stats.maxhp;
2369     rate_hp -= rate_hp/2 * op->contr->gen_hp;
2370     }
2371     if(op->contr->gen_sp >= 0 )
2372     gen_sp=(op->contr->gen_sp+1)*op->stats.maxsp;
2373     else {
2374     gen_sp = op->stats.maxsp;
2375     rate_sp -= rate_sp/2 * op->contr->gen_sp;
2376     }
2377     if(op->contr->gen_grace >= 0)
2378     gen_grace=(op->contr->gen_grace+1)*op->stats.maxgrace;
2379     else {
2380     gen_grace = op->stats.maxgrace;
2381     rate_grace -= rate_grace/2 * op->contr->gen_grace;
2382     }
2383    
2384     /* Regenerate Spell Points */
2385     if(op->contr->ranges[range_golem]==NULL && --op->last_sp<0) {
2386     gen_sp = gen_sp * 10 / (op->contr->gen_sp_armour < 10? 10 : op->contr->gen_sp_armour);
2387     if(op->stats.sp<op->stats.maxsp) {
2388     op->stats.sp++;
2389     /* dms do not consume food */
2390     if (!QUERY_FLAG(op,FLAG_WIZ)) {
2391     op->stats.food--;
2392     if(op->contr->digestion<0)
2393     op->stats.food+=op->contr->digestion;
2394     else if(op->contr->digestion>0 &&
2395     random_roll(0, op->contr->digestion, op, PREFER_HIGH))
2396     op->stats.food=last_food;
2397     }
2398     }
2399     if (max_sp>1) {
2400     over_sp = (gen_sp+10)/rate_sp;
2401     if (over_sp > 0) {
2402     if(op->stats.sp<op->stats.maxsp) {
2403     op->stats.sp += over_sp>max_sp ? max_sp : over_sp;
2404     if(random_roll(0, rate_sp-1, op, PREFER_LOW) > ((gen_sp+10)%rate_sp))
2405     op->stats.sp--;
2406     if(op->stats.sp>op->stats.maxsp)
2407     op->stats.sp=op->stats.maxsp;
2408     }
2409     op->last_sp=0;
2410     } else {
2411     op->last_sp=rate_sp/(gen_sp<20 ? 30 : gen_sp+10);
2412     }
2413     } else {
2414     op->last_sp=rate_sp/(gen_sp<20 ? 30 : gen_sp+10);
2415     }
2416     }
2417    
2418     /* Regenerate Grace */
2419     /* I altered this a little - maximum grace is ony achieved through prayer -b.t.*/
2420     if(--op->last_grace<0) {
2421     if(op->stats.grace<op->stats.maxgrace/2)
2422     op->stats.grace++; /* no penalty in food for regaining grace */
2423     if(max_grace>1) {
2424     over_grace = (gen_grace<20 ? 30 : gen_grace+10)/rate_grace;
2425     if (over_grace > 0) {
2426     op->stats.sp += over_grace
2427     + (random_roll(0, rate_grace-1, op, PREFER_HIGH) > ((gen_grace<20 ? 30 : gen_grace+10)%rate_grace))? -1 : 0;
2428     op->last_grace=0;
2429     } else {
2430     op->last_grace=rate_grace/(gen_grace<20 ? 30 : gen_grace+10);
2431     }
2432     } else {
2433     op->last_grace=rate_grace/(gen_grace<20 ? 30 : gen_grace+10);
2434     }
2435     /* wearing stuff doesn't detract from grace generation. */
2436     }
2437    
2438     /* Regenerate Hit Points */
2439     if(--op->last_heal<0) {
2440     if(op->stats.hp<op->stats.maxhp) {
2441     op->stats.hp++;
2442     /* dms do not consume food */
2443     if (!QUERY_FLAG(op,FLAG_WIZ)) {
2444     op->stats.food--;
2445     if(op->contr->digestion<0)
2446     op->stats.food+=op->contr->digestion;
2447     else if(op->contr->digestion>0 &&
2448     random_roll(0, op->contr->digestion, op, PREFER_HIGH))
2449     op->stats.food=last_food;
2450     }
2451     }
2452     if(max_hp>1) {
2453     over_hp = (gen_hp<20 ? 30 : gen_hp+10)/rate_hp;
2454     if (over_hp > 0) {
2455     op->stats.sp += over_hp
2456     + (RANDOM()%rate_hp > ((gen_hp<20 ? 30 : gen_hp+10)%rate_hp))? -1 : 0;
2457     op->last_heal=0;
2458     } else {
2459     op->last_heal=rate_hp/(gen_hp<20 ? 30 : gen_hp+10);
2460     }
2461     } else {
2462     op->last_heal=rate_hp/(gen_hp<20 ? 30 : gen_hp+10);
2463     }
2464     }
2465    
2466     /* Digestion */
2467     if(--op->last_eat<0) {
2468     int bonus=op->contr->digestion>0?op->contr->digestion:0,
2469     penalty=op->contr->digestion<0?-op->contr->digestion:0;
2470     if(op->contr->gen_hp > 0)
2471     op->last_eat=25*(1+bonus)/(op->contr->gen_hp+penalty+1);
2472     else
2473     op->last_eat=25*(1+bonus)/(penalty +1);
2474     /* dms do not consume food */
2475     if (!QUERY_FLAG(op,FLAG_WIZ)) op->stats.food--;
2476     }
2477     }
2478    
2479     if(op->contr->state==ST_PLAYING&&op->stats.food<0&&op->stats.hp>=0) {
2480     object *tmp, *flesh=NULL;
2481    
2482     for(tmp=op->inv;tmp!=NULL;tmp=tmp->below) {
2483     if(!QUERY_FLAG(tmp, FLAG_UNPAID)) {
2484     if (tmp->type==FOOD || tmp->type==DRINK || tmp->type==POISON) {
2485     new_draw_info(NDI_UNIQUE, 0,op,"You blindly grab for a bite of food.");
2486     manual_apply(op,tmp,0);
2487     if(op->stats.food>=0||op->stats.hp<0)
2488     break;
2489     }
2490     else if (tmp->type==FLESH) flesh=tmp;
2491     } /* End if paid for object */
2492     } /* end of for loop */
2493     /* If player is still starving, it means they don't have any food, so
2494     * eat flesh instead.
2495     */
2496     if (op->stats.food<0 && op->stats.hp>=0 && flesh) {
2497     new_draw_info(NDI_UNIQUE, 0,op,"You blindly grab for a bite of food.");
2498     manual_apply(op,flesh,0);
2499     }
2500     } /* end if player is starving */
2501    
2502     while(op->stats.food<0&&op->stats.hp>0)
2503     op->stats.food++,op->stats.hp--;
2504    
2505     if (!op->contr->state&&!QUERY_FLAG(op,FLAG_WIZ)&&(op->stats.hp<0||op->stats.food<0))
2506     kill_player(op);
2507     }
2508    
2509    
2510    
2511     /* If the player should die (lack of hp, food, etc), we call this.
2512     * op is the player in jeopardy. If the player can not be saved (not
2513     * permadeath, no lifesave), this will take care of removing the player
2514     * file.
2515     */
2516     void kill_player(object *op)
2517     {
2518     char buf[MAX_BUF];
2519     int x,y,i;
2520     mapstruct *map; /* this is for resurrection */
2521     int z;
2522     int num_stats_lose;
2523     int lost_a_stat;
2524     int lose_this_stat;
2525     int this_stat;
2526     int will_kill_again;
2527     archetype *at;
2528     object *tmp;
2529    
2530     if(save_life(op))
2531     return;
2532    
2533    
2534     /* If player dies on BATTLEGROUND, no stat/exp loss! For Combat-Arenas
2535     * in cities ONLY!!! It is very important that this doesn't get abused.
2536     * Look at op_on_battleground() for more info --AndreasV
2537     */
2538     if (op_on_battleground(op, &x, &y)) {
2539     new_draw_info(NDI_UNIQUE | NDI_NAVY, 0,op,
2540     "You have been defeated in combat!");
2541     new_draw_info(NDI_UNIQUE | NDI_NAVY, 0,op,
2542     "Local medics have saved your life...");
2543    
2544     /* restore player */
2545     at = find_archetype("poisoning");
2546     tmp=present_arch_in_ob(at,op);
2547     if (tmp) {
2548     remove_ob(tmp);
2549     free_object(tmp);
2550     new_draw_info(NDI_UNIQUE, 0,op, "Your body feels cleansed");
2551     }
2552    
2553     at = find_archetype("confusion");
2554     tmp=present_arch_in_ob(at,op);
2555     if (tmp) {
2556     remove_ob(tmp);
2557     free_object(tmp);
2558     new_draw_info(NDI_UNIQUE, 0,tmp, "Your mind feels clearer");
2559     }
2560    
2561     cure_disease(op,0); /* remove any disease */
2562     op->stats.hp=op->stats.maxhp;
2563     if (op->stats.food<=0) op->stats.food=999;
2564    
2565     /* create a bodypart-trophy to make the winner happy */
2566     tmp=arch_to_object(find_archetype("finger"));
2567     if (tmp != NULL)
2568     {
2569     sprintf(buf,"%s's finger",op->name);
2570     tmp->name = add_string(buf);
2571     sprintf(buf," This finger has been cut off %s\n"
2572     " the %s, when he was defeated at\n level %d by %s.\n",
2573     op->name, op->contr->title, (int)(op->level),
2574     op->contr->killer);
2575     tmp->msg=add_string(buf);
2576     tmp->value=0, tmp->material=0, tmp->type=0;
2577     tmp->materialname = NULL;
2578     tmp->x = op->x, tmp->y = op->y;
2579     insert_ob_in_map(tmp,op->map,op,0);
2580     }
2581    
2582     /* teleport defeated player to new destination*/
2583     transfer_ob(op, x, y, 0, NULL);
2584     op->contr->braced=0;
2585     return;
2586     }
2587    
2588     /* Lauwenmark: Handle for plugin death event */
2589     if (execute_event(op, EVENT_DEATH,NULL,NULL,NULL,SCRIPT_FIX_ALL) != 0)
2590     return;
2591    
2592     /* Lauwenmark: Handle for the global death event */
2593     execute_global_event(EVENT_PLAYER_DEATH, op);
2594     if(op->stats.food<0) {
2595     if (op->contr->explore) {
2596     new_draw_info(NDI_UNIQUE, 0,op,"You would have starved, but you are");
2597     new_draw_info(NDI_UNIQUE, 0,op,"in explore mode, so...");
2598     op->stats.food=999;
2599     return;
2600     }
2601     sprintf(buf,"%s starved to death.",op->name);
2602     strcpy(op->contr->killer,"starvation");
2603     }
2604     else {
2605     if (op->contr->explore) {
2606     new_draw_info(NDI_UNIQUE, 0,op,"You would have died, but you are");
2607     new_draw_info(NDI_UNIQUE, 0,op,"in explore mode, so...");
2608     op->stats.hp=op->stats.maxhp;
2609     return;
2610     }
2611     sprintf(buf,"%s died.",op->name);
2612     }
2613     play_sound_player_only(op->contr, SOUND_PLAYER_DIES,0,0);
2614    
2615     /* save the map location for corpse, gravestone*/
2616     x=op->x;y=op->y;map=op->map;
2617    
2618    
2619     if (settings.not_permadeth == TRUE) {
2620     /* NOT_PERMADEATH code. This basically brings the character back to
2621     * life if they are dead - it takes some exp and a random stat.
2622     * See the config.h file for a little more in depth detail about this.
2623     */
2624    
2625     /* Basically two ways to go - remove a stat permanently, or just
2626     * make it depletion. This bunch of code deals with that aspect
2627     * of death.
2628     */
2629    
2630     if (settings.balanced_stat_loss) {
2631     /* If stat loss is permanent, lose one stat only. */
2632     /* Lower level chars don't lose as many stats because they suffer
2633     more if they do. */
2634     /* Higher level characters can afford things such as potions of
2635     restoration, or better, stat potions. So we slug them that
2636     little bit harder. */
2637     /* GD */
2638     if (settings.stat_loss_on_death)
2639     num_stats_lose = 1;
2640     else
2641     num_stats_lose = 1 + op->level/BALSL_NUMBER_LOSSES_RATIO;
2642     } else {
2643     num_stats_lose = 1;
2644     }
2645     lost_a_stat = 0;
2646    
2647     for (z=0; z<num_stats_lose; z++) {
2648     if (settings.stat_loss_on_death) {
2649     /* Pick a random stat and take a point off it. Tell the player
2650     * what he lost.
2651     */
2652     i = RANDOM() % 7;
2653     change_attr_value(&(op->stats), i,-1);
2654     check_stat_bounds(&(op->stats));
2655     change_attr_value(&(op->contr->orig_stats), i,-1);
2656     check_stat_bounds(&(op->contr->orig_stats));
2657     new_draw_info(NDI_UNIQUE, 0,op, lose_msg[i]);
2658     lost_a_stat = 1;
2659     } else {
2660     /* deplete a stat */
2661     archetype *deparch=find_archetype("depletion");
2662     object *dep;
2663    
2664     i = RANDOM() % 7;
2665     dep = present_arch_in_ob(deparch,op);
2666     if(!dep) {
2667     dep = arch_to_object(deparch);
2668     insert_ob_in_ob(dep, op);
2669     }
2670     lose_this_stat = 1;
2671     if (settings.balanced_stat_loss) {
2672     /* GD */
2673     /* Get the stat that we're about to deplete. */
2674     this_stat = get_attr_value(&(dep->stats), i);
2675     if (this_stat < 0) {
2676     int loss_chance = 1 + op->level/BALSL_LOSS_CHANCE_RATIO;
2677     int keep_chance = this_stat * this_stat;
2678     /* Yes, I am paranoid. Sue me. */
2679     if (keep_chance < 1)
2680     keep_chance = 1;
2681    
2682     /* There is a maximum depletion total per level. */
2683     if (this_stat < -1 - op->level/BALSL_MAX_LOSS_RATIO) {
2684     lose_this_stat = 0;
2685     /* Take loss chance vs keep chance to see if we
2686     retain the stat. */
2687     } else {
2688     if (random_roll(0, loss_chance + keep_chance-1,
2689     op, PREFER_LOW) < keep_chance)
2690     lose_this_stat = 0;
2691     /* LOG(llevDebug, "Determining stat loss. Stat: %d Keep: %d Lose: %d Result: %s.\n",
2692     this_stat, keep_chance, loss_chance,
2693     lose_this_stat?"LOSE":"KEEP"); */
2694     }
2695     }
2696     }
2697    
2698     if (lose_this_stat) {
2699     this_stat = get_attr_value(&(dep->stats), i);
2700     /* We could try to do something clever like find another
2701     * stat to reduce if this fails. But chances are, if
2702     * stats have been depleted to -50, all are pretty low
2703     * and should be roughly the same, so it shouldn't make a
2704     * difference.
2705     */
2706     if (this_stat>=-50) {
2707     change_attr_value(&(dep->stats), i, -1);
2708     SET_FLAG(dep, FLAG_APPLIED);
2709     new_draw_info(NDI_UNIQUE, 0,op, lose_msg[i]);
2710     fix_player(op);
2711     lost_a_stat = 1;
2712     }
2713     }
2714     }
2715     }
2716     /* If no stat lost, tell the player. */
2717     if (!lost_a_stat)
2718     {
2719     /* determine_god() seems to not work sometimes... why is this?
2720     Should I be using something else? GD */
2721     const char *god = determine_god(op);
2722     if (god && (strcmp(god, "none")))
2723     new_draw_info_format(NDI_UNIQUE, 0, op, "For a brief "
2724     "moment you feel the holy presence of %s protecting"
2725     " you.", god);
2726     else
2727     new_draw_info(NDI_UNIQUE, 0, op, "For a brief moment you"
2728     " feel a holy presence protecting you.");
2729     }
2730    
2731     /* Put a gravestone up where the character 'almost' died. List the
2732     * exp loss on the stone.
2733     */
2734     tmp=arch_to_object(find_archetype("gravestone"));
2735     sprintf(buf,"%s's gravestone",op->name);
2736     FREE_AND_COPY(tmp->name, buf);
2737     sprintf(buf,"%s's gravestones",op->name);
2738     FREE_AND_COPY(tmp->name_pl, buf);
2739     sprintf(buf,"RIP\nHere rests the hero %s the %s,\n"
2740     "who was killed\n"
2741     "by %s.\n",
2742     op->name, op->contr->title,
2743     op->contr->killer);
2744     tmp->msg = add_string(buf);
2745     tmp->x=op->x,tmp->y=op->y;
2746     insert_ob_in_map (tmp, op->map, NULL,0);
2747    
2748     /**************************************/
2749     /* */
2750     /* Subtract the experience points, */
2751     /* if we died cause of food, give us */
2752     /* food, and reset HP's... */
2753     /* */
2754     /**************************************/
2755    
2756     /* remove any poisoning and confusion the character may be suffering.*/
2757     /* restore player */
2758     at = find_archetype("poisoning");
2759     tmp=present_arch_in_ob(at,op);
2760     if (tmp) {
2761     remove_ob(tmp);
2762     free_object(tmp);
2763     new_draw_info(NDI_UNIQUE, 0,op, "Your body feels cleansed");
2764     }
2765    
2766     at = find_archetype("confusion");
2767     tmp=present_arch_in_ob(at,op);
2768     if (tmp) {
2769     remove_ob(tmp);
2770     free_object(tmp);
2771     new_draw_info(NDI_UNIQUE, 0,tmp, "Your mind feels clearer");
2772     }
2773     cure_disease(op,0); /* remove any disease */
2774    
2775     /*add_exp(op, (op->stats.exp * -0.20)); */
2776     apply_death_exp_penalty(op);
2777     if(op->stats.food < 100) op->stats.food = 900;
2778     op->stats.hp = op->stats.maxhp;
2779     op->stats.sp = MAX(op->stats.sp, op->stats.maxsp);
2780     op->stats.grace = MAX(op->stats.grace, op->stats.maxgrace);
2781    
2782     /*
2783     * Check to see if the player is in a shop. IF so, then check to see if
2784     * the player has any unpaid items. If so, remove them and put them back
2785     * in the map.
2786     */
2787    
2788     for (tmp= get_map_ob(op->map, op->x, op->y); tmp; tmp=tmp->above) {
2789     if (tmp->type == SHOP_FLOOR) {
2790     remove_unpaid_objects(op->inv, op);
2791     break;
2792     }
2793     }
2794    
2795    
2796     /****************************************/
2797     /* */
2798     /* Move player to his current respawn- */
2799     /* position (usually last savebed) */
2800     /* */
2801     /****************************************/
2802    
2803     enter_player_savebed(op);
2804    
2805     /* Save the player before inserting the force to reduce
2806     * chance of abuse.
2807     */
2808     op->contr->braced=0;
2809     save_player(op,1);
2810    
2811     /* it is possible that the player has blown something up
2812     * at his savebed location, and that can have long lasting
2813     * spell effects. So first see if there is a spell effect
2814     * on the space that might harm the player.
2815     */
2816     will_kill_again=0;
2817     for (tmp= get_map_ob(op->map, op->x, op->y); tmp; tmp=tmp->above) {
2818     if (tmp->type ==SPELL_EFFECT)
2819     will_kill_again|=tmp->attacktype;
2820     }
2821     if (will_kill_again) {
2822     object *force;
2823     int at;
2824    
2825     force=get_archetype(FORCE_NAME);
2826     /* 50 ticks should be enough time for the spell to abate */
2827     force->speed=0.1;
2828     force->speed_left=-5.0;
2829     SET_FLAG(force, FLAG_APPLIED);
2830     for (at=0; at<NROFATTACKS; at++) {
2831     if (will_kill_again & (1 << at))
2832     force->resist[at] = 100;
2833     }
2834     insert_ob_in_ob(force, op);
2835     fix_player(op);
2836    
2837     }
2838     /**************************************/
2839     /* */
2840     /* Repaint the characters inv, and */
2841     /* stats, and show a nasty message ;) */
2842     /* */
2843     /**************************************/
2844    
2845     new_draw_info(NDI_UNIQUE, 0,op,"YOU HAVE DIED.");
2846     return;
2847     } /* NOT_PERMADETH */
2848     else {
2849     /* If NOT_PERMADETH is set, then the rest of this is not reachable. This
2850     * should probably be embedded in an else statement.
2851     */
2852    
2853     op->contr->party=NULL;
2854     if (settings.set_title == TRUE)
2855     op->contr->own_title[0]='\0';
2856     new_draw_info(NDI_UNIQUE|NDI_ALL, 0,NULL, buf);
2857     check_score(op);
2858     if(op->contr->ranges[range_golem]!=NULL) {
2859     remove_friendly_object(op->contr->ranges[range_golem]);
2860     remove_ob(op->contr->ranges[range_golem]);
2861     free_object(op->contr->ranges[range_golem]);
2862     op->contr->ranges[range_golem]=NULL;
2863     op->contr->golem_count=0;
2864     }
2865     loot_object(op); /* Remove some of the items for good */
2866     remove_ob(op);
2867     op->direction=0;
2868    
2869     if(!QUERY_FLAG(op,FLAG_WAS_WIZ)&&op->stats.exp) {
2870     delete_character(op->name,0);
2871     if (settings.resurrection == TRUE) {
2872     /* save playerfile sans equipment when player dies
2873     ** then save it as player.pl.dead so that future resurrection
2874     ** type spells will work on them nicely
2875     */
2876     delete_character(op->name,0);
2877     op->stats.hp = op->stats.maxhp;
2878     op->stats.food = 999;
2879    
2880     /* set the location of where the person will reappear when */
2881     /* maybe resurrection code should fix map also */
2882     strcpy(op->contr->maplevel, settings.emergency_mapname);
2883     if(op->map!=NULL)
2884     op->map = NULL;
2885     op->x = settings.emergency_x;
2886     op->y = settings.emergency_y;
2887     save_player(op,0);
2888     op->map = map;
2889     /* please see resurrection.c: peterm */
2890     dead_player(op);
2891     } else {
2892     delete_character(op->name,1);
2893     }
2894     }
2895     play_again(op);
2896    
2897     /* peterm: added to create a corpse at deathsite. */
2898     tmp=arch_to_object(find_archetype("corpse_pl"));
2899     sprintf(buf,"%s", op->name);
2900     FREE_AND_COPY(tmp->name, buf);
2901     FREE_AND_COPY(tmp->name_pl, buf);
2902     tmp->level=op->level;
2903     tmp->x=x;tmp->y=y;
2904     if (tmp->msg)
2905     free_string(tmp->msg);
2906     tmp->msg = add_string (gravestone_text(op));
2907     SET_FLAG (tmp, FLAG_UNIQUE);
2908     insert_ob_in_map (tmp, map, NULL,0);
2909     }
2910     }
2911    
2912    
2913     void loot_object(object *op) { /* Grab and destroy some treasure */
2914     object *tmp,*tmp2,*next;
2915    
2916     if (op->container) { /* close open sack first */
2917     esrv_apply_container (op, op->container);
2918     }
2919    
2920     for(tmp=op->inv;tmp!=NULL;tmp=next) {
2921     next=tmp->below;
2922     if (tmp->type==EXPERIENCE || tmp->invisible) continue;
2923     remove_ob(tmp);
2924     tmp->x=op->x,tmp->y=op->y;
2925     if (tmp->type == CONTAINER) { /* empty container to ground */
2926     loot_object(tmp);
2927     }
2928     if(!QUERY_FLAG(tmp, FLAG_UNIQUE) && (QUERY_FLAG(tmp, FLAG_STARTEQUIP)
2929     || QUERY_FLAG(tmp,FLAG_NO_DROP) || !(RANDOM()%3))) {
2930     if(tmp->nrof>1) {
2931     tmp2=get_split_ob(tmp,1+RANDOM()%(tmp->nrof-1));
2932     free_object(tmp2);
2933     insert_ob_in_map(tmp,op->map,NULL,0);
2934     } else
2935     free_object(tmp);
2936     } else
2937     insert_ob_in_map(tmp,op->map,NULL,0);
2938     }
2939     }
2940    
2941     /*
2942     * fix_weight(): Check recursively the weight of all players, and fix
2943     * what needs to be fixed. Refresh windows and fix speed if anything
2944     * was changed.
2945     */
2946    
2947     void fix_weight(void) {
2948     player *pl;
2949     for (pl = first_player; pl != NULL; pl = pl->next) {
2950     int old = pl->ob->carrying, sum = sum_weight(pl->ob);
2951     if(old == sum)
2952     continue;
2953     fix_player(pl->ob);
2954     LOG(llevDebug,"Fixed inventory in %s (%d -> %d)\n",
2955     pl->ob->name, old, sum);
2956     }
2957     }
2958    
2959     void fix_luck(void) {
2960     player *pl;
2961     for (pl = first_player; pl != NULL; pl = pl->next)
2962     if (!pl->ob->contr->state)
2963     change_luck(pl->ob, 0);
2964     }
2965    
2966    
2967     /* cast_dust() - handles op throwing objects of type 'DUST'.
2968     * This is much simpler in the new spell code - we basically
2969     * just treat this as any other spell casting object.
2970     */
2971    
2972     void cast_dust (object *op, object *throw_ob, int dir) {
2973     object *skop, *spob;
2974    
2975     skop = find_skill_by_name(op, throw_ob->skill);
2976    
2977     /* casting POTION 'dusts' is really a use_magic_item skill */
2978     if(op->type==PLAYER && throw_ob->type==POTION && !skop) {
2979     LOG(llevError,"Player %s lacks critical skill use_magic_item!\n",
2980     op->name);
2981     return;
2982     }
2983     spob = throw_ob->inv;
2984     if (op->type==PLAYER && spob)
2985     new_draw_info_format(NDI_UNIQUE, 0,op,"You cast %s.",spob->name);
2986    
2987     cast_spell(op, throw_ob, dir, spob, NULL);
2988    
2989     if(!QUERY_FLAG(throw_ob,FLAG_REMOVED)) remove_ob(throw_ob);
2990     free_object(throw_ob);
2991     }
2992    
2993     void make_visible (object *op) {
2994     op->hide = 0;
2995     op->invisible = 0;
2996     if(op->type==PLAYER) {
2997     op->contr->tmp_invis = 0;
2998     if (op->contr->invis_race) FREE_AND_CLEAR_STR(op->contr->invis_race);
2999     }
3000     update_object(op,UP_OBJ_FACE);
3001     }
3002    
3003     int is_true_undead(object *op) {
3004     object *tmp=NULL;
3005    
3006     if(QUERY_FLAG(&op->arch->clone,FLAG_UNDEAD)) return 1;
3007    
3008     if(op->type==PLAYER)
3009     for(tmp=op->inv;tmp;tmp=tmp->below)
3010     if(tmp->type==EXPERIENCE && tmp->stats.Wis)
3011     if(QUERY_FLAG(tmp,FLAG_UNDEAD)) return 1;
3012     return 0;
3013     }
3014    
3015     /* look at the surrounding terrain to determine
3016     * the hideability of this object. Positive levels
3017     * indicate greater hideability.
3018     */
3019    
3020     int hideability(object *ob) {
3021     int i,level=0, mflag;
3022     sint16 x,y;
3023    
3024     if(!ob||!ob->map) return 0;
3025    
3026     /* so, on normal lighted maps, its hard to hide */
3027     level=ob->map->darkness - 2;
3028    
3029     /* this also picks up whether the object is glowing.
3030     * If you carry a light on a non-dark map, its not
3031     * as bad as carrying a light on a pitch dark map */
3032     if(has_carried_lights(ob)) level =- (10 + (2*ob->map->darkness));
3033    
3034     /* scan through all nearby squares for terrain to hide in */
3035     for(i=0,x=ob->x,y=ob->y;i<9;i++,x=ob->x+freearr_x[i],y=ob->y+freearr_y[i]) {
3036     mflag = get_map_flags(ob->map, NULL, x, y, NULL, NULL);
3037     if (mflag & P_OUT_OF_MAP) { continue; }
3038     if(mflag & P_BLOCKSVIEW) /* something to hide near! */
3039     level += 2;
3040     else /* open terrain! */
3041     level -= 1;
3042     }
3043    
3044     #if 0
3045     LOG(llevDebug,"hideability of %s is %d\n",ob->name,level);
3046     #endif
3047     return level;
3048     }
3049    
3050     /* For Hidden creatures - a chance of becoming 'unhidden'
3051     * every time they move - as we subtract off 'invisibility'
3052     * AND, for players, if they move into a ridiculously unhideable
3053     * spot (surrounded by clear terrain in broad daylight). -b.t.
3054     */
3055    
3056     void do_hidden_move (object *op) {
3057     int hide=0, num=random_roll(0, 19, op, PREFER_LOW);
3058     object *skop;
3059    
3060     if(!op || !op->map) return;
3061    
3062     skop = find_obj_by_type_subtype(op, SKILL, SK_HIDING);
3063    
3064     /* its *extremely* hard to run and sneak/hide at the same time! */
3065     if(op->type==PLAYER && op->contr->run_on) {
3066     if(!skop || num >= skop->level) {
3067     new_draw_info(NDI_UNIQUE,0,op,"You ran too much! You are no longer hidden!");
3068     make_visible(op);
3069     return;
3070     } else num += 20;
3071     }
3072     num += op->map->difficulty;
3073     hide = hideability(op); /* modify by terrain hidden level */
3074     num -= hide;
3075     if((op->type==PLAYER && hide<-10) || ((op->invisible-=num)<=0)) {
3076     make_visible(op);
3077     if(op->type==PLAYER) new_draw_info(NDI_UNIQUE, 0,op,
3078     "You moved out of hiding! You are visible!");
3079     }
3080     else if (op->type == PLAYER && skop) {
3081     change_exp(op, calc_skill_exp(op, NULL, skop), skop->skill, 0);
3082     }
3083     }
3084    
3085     /* determine if who is standing near a hostile creature. */
3086    
3087     int stand_near_hostile( object *who ) {
3088     object *tmp=NULL;
3089     int i,friendly=0,player=0, mflags;
3090     mapstruct *m;
3091     sint16 x,y;
3092    
3093     if(!who) return 0;
3094    
3095     if(who->type==PLAYER) player=1;
3096     else friendly = QUERY_FLAG(who,FLAG_FRIENDLY);
3097    
3098     /* search adjacent squares */
3099     for(i=1;i<9;i++) {
3100     x = who->x+freearr_x[i];
3101     y = who->y+freearr_y[i];
3102     m = who->map;
3103     mflags = get_map_flags(m, &m, x, y, &x, &y);
3104     /* space must be blocked if there is a monster. If not
3105     * blocked, don't need to check this space.
3106     */
3107     if (mflags & P_OUT_OF_MAP) continue;
3108     if (OB_TYPE_MOVE_BLOCK(who, GET_MAP_MOVE_BLOCK(m, x, y))) continue;
3109    
3110     for(tmp=get_map_ob(m,x,y);tmp;tmp=tmp->above) {
3111     if((player||friendly)
3112     &&QUERY_FLAG(tmp,FLAG_MONSTER)&&!QUERY_FLAG(tmp,FLAG_UNAGGRESSIVE))
3113     return 1;
3114     else if(tmp->type==PLAYER)
3115     {
3116     /*don't let a hidden DM prevent you from hiding*/
3117     if(!QUERY_FLAG(tmp, FLAG_WIZ) || tmp->contr->hidden == 0)
3118     return 1;
3119     }
3120     }
3121     }
3122     return 0;
3123     }
3124    
3125     /* check the player los field for viewability of the
3126     * object op. This function works fine for monsters,
3127     * but we dont worry if the object isnt the top one in
3128     * a pile (say a coin under a table would return "viewable"
3129     * by this routine). Another question, should we be
3130     * concerned with the direction the player is looking
3131     * in? Realistically, most of use cant see stuff behind
3132     * our backs...on the other hand, does the "facing" direction
3133     * imply the way your head, or body is facing? Its possible
3134     * for them to differ. Sigh, this fctn could get a bit more complex.
3135     * -b.t.
3136     * This function is now map tiling safe.
3137     */
3138    
3139     int player_can_view (object *pl,object *op) {
3140     rv_vector rv;
3141     int dx,dy;
3142    
3143     if(pl->type!=PLAYER) {
3144     LOG(llevError,"player_can_view() called for non-player object\n");
3145     return -1;
3146     }
3147     if (!pl || !op) return 0;
3148    
3149     if(op->head) { op = op->head; }
3150     get_rangevector(pl, op, &rv, 0x1);
3151    
3152     /* starting with the 'head' part, lets loop
3153     * through the object and find if it has any
3154     * part that is in the los array but isnt on
3155     * a blocked los square.
3156     * we use the archetype to figure out offsets.
3157     */
3158     while(op) {
3159     dx = rv.distance_x + op->arch->clone.x;
3160     dy = rv.distance_y + op->arch->clone.y;
3161    
3162     /* only the viewable area the player sees is updated by LOS
3163     * code, so we need to restrict ourselves to that range of values
3164     * for any meaningful values.
3165     */
3166     if (FABS(dx) <= (pl->contr->socket.mapx/2) &&
3167     FABS(dy) <= (pl->contr->socket.mapy/2) &&
3168     !pl->contr->blocked_los[dx + (pl->contr->socket.mapx/2)][dy+(pl->contr->socket.mapy/2)] )
3169     return 1;
3170     op = op->more;
3171     }
3172     return 0;
3173     }
3174    
3175     /* routine for both players and monsters. We call this when
3176     * there is a possibility for our action distrubing our hiding
3177     * place or invisiblity spell. Artefact invisiblity is not
3178     * effected by this. If we arent invisible to begin with, we
3179     * return 0.
3180     */
3181     int action_makes_visible (object *op) {
3182    
3183     if(op->invisible && QUERY_FLAG(op,FLAG_ALIVE)) {
3184     if(QUERY_FLAG(op,FLAG_MAKE_INVIS))
3185     return 0;
3186    
3187     if (op->contr && op->contr->tmp_invis == 0) return 0;
3188    
3189     /* If monsters, they should become visible */
3190     if(op->hide || !op->contr || (op->contr && op->contr->tmp_invis)) {
3191     new_draw_info_format(NDI_UNIQUE, 0,op,"You become %s!",op->hide?"unhidden":"visible");
3192     return 1;
3193     }
3194     }
3195     return 0;
3196     }
3197    
3198     /* op_on_battleground - checks if the given object op (usually
3199     * a player) is standing on a valid battleground-tile,
3200     * function returns TRUE/FALSE. If true x, y returns the battleground
3201     * -exit-coord. (and if x, y not NULL)
3202     * 19 March 2005 - josh@woosworld.net modifed to check if the battleground also has slaying, maxhp, and maxsp set
3203     * and if those are all set and the player has a marker that matches the slaying send them to a different x, y
3204     * Default is to do the same as before, so only people wanting to have different points need worry about this
3205     */
3206     int op_on_battleground (object *op, int *x, int *y) {
3207     object *tmp;
3208    
3209     /* A battleground-tile needs the following attributes to be valid:
3210     * is_floor 1 (has to be the FIRST floor beneath the player's feet),
3211     * name="battleground", no_pick 1, type=58 (type BATTLEGROUND)
3212     * and the exit-coordinates sp/hp must both be > 0.
3213     * => The intention here is to prevent abuse of the battleground-
3214     * feature (like pickable or hidden battleground tiles). */
3215     for (tmp=op->below; tmp!=NULL; tmp=tmp->below) {
3216     if (QUERY_FLAG (tmp, FLAG_IS_FLOOR)) {
3217     if (QUERY_FLAG (tmp, FLAG_NO_PICK) &&
3218     strcmp(tmp->name, "battleground")==0 &&
3219     tmp->type == BATTLEGROUND && EXIT_X(tmp) && EXIT_Y(tmp)) {
3220     /*before we assign the exit, check if this is a teambattle*/
3221     if ( EXIT_ALT_X(tmp) && EXIT_ALT_Y(tmp) && EXIT_PATH(tmp) ){
3222     object *invtmp;
3223     for(invtmp=op->inv; invtmp != NULL; invtmp=invtmp->below) {
3224     if(invtmp->type==FORCE && invtmp->slaying &&
3225     !strcmp(EXIT_PATH(tmp), invtmp->slaying)){
3226     if (x != NULL && y != NULL)
3227     *x=EXIT_ALT_X(tmp), *y=EXIT_ALT_Y(tmp);
3228     return 1;
3229     }
3230     }
3231     }
3232     if (x != NULL && y != NULL)
3233     *x=EXIT_X(tmp), *y=EXIT_Y(tmp);
3234     return 1;
3235     }
3236     }
3237     }
3238     /* If we got here, did not find a battleground */
3239     return 0;
3240     }
3241    
3242     /*
3243     * When a dragon-player gains a new stage of evolution,
3244     * he gets some treasure
3245     *
3246     * attributes:
3247     * object *who the dragon player
3248     * int atnr the attack-number of the ability focus
3249     * int level ability level
3250     */
3251     void dragon_ability_gain(object *who, int atnr, int level) {
3252     treasurelist *trlist = NULL; /* treasurelist */
3253     treasure *tr; /* treasure */
3254     object *tmp,*skop; /* tmp. object */
3255     object *item; /* treasure object */
3256     char buf[MAX_BUF]; /* tmp. string buffer */
3257     int i=0, j=0;
3258    
3259     /* get the appropriate treasurelist */
3260     if (atnr == ATNR_FIRE)
3261     trlist = find_treasurelist("dragon_ability_fire");
3262     else if (atnr == ATNR_COLD)
3263     trlist = find_treasurelist("dragon_ability_cold");
3264     else if (atnr == ATNR_ELECTRICITY)
3265     trlist = find_treasurelist("dragon_ability_elec");
3266     else if (atnr == ATNR_POISON)
3267     trlist = find_treasurelist("dragon_ability_poison");
3268    
3269     if (trlist == NULL || who->type != PLAYER)
3270     return;
3271    
3272     for (i=0, tr = trlist->items; tr != NULL && i<level-1;
3273     tr = tr->next, i++);
3274    
3275     if (tr == NULL || tr->item == NULL) {
3276     /* LOG(llevDebug, "-> no more treasure for %s\n", change_resist_msg[atnr]); */
3277     return;
3278     }
3279    
3280     /* everything seems okay - now bring on the gift: */
3281     item = &(tr->item->clone);
3282    
3283     if (item->type == SPELL) {
3284     if (check_spell_known (who, item->name))
3285     return;
3286    
3287     new_draw_info_format(NDI_UNIQUE|NDI_BLUE, 0, who, "You gained the ability of %s", item->name);
3288     do_learn_spell (who, item, 0);
3289     return;
3290     }
3291    
3292     /* grant direct spell */
3293     if (item->type == SPELLBOOK) {
3294     if (!item->inv) {
3295     LOG(llevDebug,"dragon_ability_gain: Broken spellbook %s\n",
3296     item->name);
3297     return;
3298     }
3299     if (check_spell_known (who, item->inv->name))
3300     return;
3301     if (item->invisible) {
3302     new_draw_info_format(NDI_UNIQUE|NDI_BLUE, 0, who, "You gained the ability of %s", item->inv->name);
3303     do_learn_spell (who, item->inv, 0);
3304     return;
3305     }
3306     }
3307     else if (item->type == SKILL_TOOL && item->invisible) {
3308     if (item->subtype == SK_CLAWING && (skop=find_skill_by_name(who, item->skill))!=NULL) {
3309    
3310     /* should this perhaps be (skop->attackyp & item->attacktype)!=item->attacktype ...
3311     * in this way, if the player is missing any of the attacktypes, he gets
3312     * them. As it is now, if the player has any that match the granted skill,
3313     * but not all of them, he gets nothing.
3314     */
3315     if (!(skop->attacktype & item->attacktype)) {
3316     /* Give new attacktype */
3317     skop->attacktype |= item->attacktype;
3318    
3319     /* always add physical if there's none */
3320     skop->attacktype |= AT_PHYSICAL;
3321    
3322     if (item->msg != NULL)
3323     new_draw_info(NDI_UNIQUE|NDI_BLUE, 0, who, item->msg);
3324    
3325     /* Give player new face */
3326     if (item->animation_id) {
3327     who->face = skop->face;
3328     who->animation_id = item->animation_id;
3329     who->anim_speed = item->anim_speed;
3330     who->last_anim = 0;
3331     who->state = 0;
3332     animate_object(who, who->direction);
3333     }
3334     }
3335     }
3336     }
3337     else if (item->type == FORCE) {
3338     /* forces in the treasurelist can alter the player's stats */
3339     object *skin;
3340     /* first get the dragon skin force */
3341     for (skin=who->inv; skin!=NULL && strcmp(skin->arch->name, "dragon_skin_force")!=0;
3342     skin=skin->below);
3343     if (skin == NULL) return;
3344    
3345     /* adding new spellpath attunements */
3346     if (item->path_attuned > 0 && !(skin->path_attuned & item->path_attuned)) {
3347     skin->path_attuned |= item->path_attuned; /* add attunement to skin */
3348    
3349     /* print message */
3350     sprintf(buf, "You feel attuned to ");
3351     for(i=0, j=0; i<NRSPELLPATHS; i++) {
3352     if(item->path_attuned & (1<<i)) {
3353     if (j)
3354     strcat(buf," and ");
3355     else
3356     j = 1;
3357     strcat(buf, spellpathnames[i]);
3358     }
3359     }
3360     strcat(buf,".");
3361     new_draw_info(NDI_UNIQUE|NDI_BLUE, 0, who, buf);
3362     }
3363    
3364     /* evtl. adding flags: */
3365     if(QUERY_FLAG(item, FLAG_XRAYS))
3366     SET_FLAG(skin, FLAG_XRAYS);
3367     if(QUERY_FLAG(item, FLAG_STEALTH))
3368     SET_FLAG(skin, FLAG_STEALTH);
3369     if(QUERY_FLAG(item, FLAG_SEE_IN_DARK))
3370     SET_FLAG(skin, FLAG_SEE_IN_DARK);
3371    
3372     /* print message if there is one */
3373     if (item->msg != NULL)
3374     new_draw_info(NDI_UNIQUE|NDI_BLUE, 0, who, item->msg);
3375     }
3376     else {
3377     /* generate misc. treasure */
3378     tmp = arch_to_object (tr->item);
3379     new_draw_info_format(NDI_UNIQUE|NDI_BLUE, 0, who, "You gained %s", query_short_name(tmp));
3380     tmp = insert_ob_in_ob (tmp, who);
3381     if (who->type == PLAYER)
3382     esrv_send_item(who, tmp);
3383     }
3384     }
3385    
3386     /**
3387     * Unready an object for a player. This function does nothing if the object was
3388     * not readied.
3389     */
3390     void player_unready_range_ob(player *pl, object *ob) {
3391     rangetype i;
3392    
3393     for (i = 0; i < range_size; i++) {
3394     if (pl->ranges[i] == ob) {
3395     pl->ranges[i] = NULL;
3396     if (pl->shoottype == i) {
3397     pl->shoottype = range_none;
3398     }
3399     }
3400     }
3401     }