ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/player.C
Revision: 1.118
Committed: Mon Apr 30 04:25:30 2007 UTC (17 years, 1 month ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.117: +55 -52 lines
Log Message:
This is the first rough cut of the skill use system (use the STABLE tag).

Details will likely change, and combat skills do not work very well, but
it works quite well.

Players no longer have a shoottype or range slots, instead, each player
has these members:

   combat_skill/combat_ob  the currently selected skill (and weapon)
                           for direct attacks.
   ranged_skill/ranged_ob  the currently selected ranged skill (and
                           bow/spell/item)
   golem                   the currently-controlled golem, if any.

File Contents

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