Crossfire Server, Branches 1.12  R18729
player.c
Go to the documentation of this file.
1 /*
2  * static char *rcsid_player_c =
3  * "$Id: player.c 11578 2009-02-23 22:02:27Z lalo $";
4  */
5 
6 /*
7  CrossFire, A Multiplayer game for X-windows
8 
9  Copyright (C) 2002,2006-2007 Mark Wedel & Crossfire Development Team
10  Copyright (C) 1992 Frank Tore Johansen
11 
12  This program is free software; you can redistribute it and/or modify
13  it under the terms of the GNU General Public License as published by
14  the Free Software Foundation; either version 2 of the License, or
15  (at your option) any later version.
16 
17  This program is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  GNU General Public License for more details.
21 
22  You should have received a copy of the GNU General Public License
23  along with this program; if not, write to the Free Software
24  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 
26  The author can be reached via e-mail to crossfire-devel@real-time.com
27 */
28 
35 #include <global.h>
36 #include <assert.h>
37 #ifndef WIN32 /* ---win32 remove headers */
38 #include <pwd.h>
39 #endif
40 #ifndef __CEXTRACT__
41 #include <sproto.h>
42 #endif
43 #include <sounds.h>
44 #include <living.h>
45 #include <object.h>
46 #include <spells.h>
47 #include <skills.h>
48 #include <newclient.h>
49 
51 
52 static int action_makes_visible(object *op);
53 
62 player *find_player(const char *plname) {
63  player *pl;
64  char name[MAX_BUF];
65 
66  for (pl = first_player; pl != NULL; pl = pl->next) {
67  if (pl->ob != NULL) {
68  query_name(pl->ob, name, MAX_BUF);
69  if (!strcmp(name, plname))
70  return pl;
71  }
72  }
73  return NULL;
74 }
75 
84 player *find_player_partial_name(const char *plname) {
85  player *pl;
86  player *found = NULL;
87  size_t namelen = strlen(plname);
88 
89  for (pl = first_player; pl != NULL; pl = pl->next) {
90  if (strlen(pl->ob->name) < namelen)
91  continue;
92 
93  if (!strcmp(pl->ob->name, plname))
94  return pl;
95 
96  if (!strncasecmp(pl->ob->name, plname, namelen)) {
97  if (found)
98  return NULL;
99 
100  found = pl;
101  }
102  }
103  return found;
104 }
105 
112 void display_motd(const object *op) {
113  char buf[MAX_BUF];
114  char motd[HUGE_BUF];
115  FILE *fp;
116  int comp;
117  int size;
118 
119  snprintf(buf, sizeof(buf), "%s/%s", settings.confdir, settings.motd);
120  if ((fp = open_and_uncompress(buf, 0, &comp)) == NULL) {
121  return;
122  }
123  motd[0] = '\0';
124  size = 0;
125  while (fgets(buf, MAX_BUF, fp) != NULL) {
126  if (*buf == '#')
127  continue;
128  strncat(motd+size, buf, HUGE_BUF-size);
129  size += strlen(buf);
130  }
132  motd, NULL);
133  close_and_delete(fp, comp);
134 }
135 
142 void send_rules(const object *op) {
143  char buf[MAX_BUF];
144  char rules[HUGE_BUF];
145  FILE *fp;
146  int comp;
147  int size;
148 
149  snprintf(buf, sizeof(buf), "%s/%s", settings.confdir, settings.rules);
150  if ((fp = open_and_uncompress(buf, 0, &comp)) == NULL) {
151  return;
152  }
153  rules[0] = '\0';
154  size = 0;
155  while (fgets(buf, MAX_BUF, fp) != NULL) {
156  if (*buf == '#')
157  continue;
158  if (size+strlen(buf) >= HUGE_BUF) {
159  LOG(llevDebug, "Warning, rules size is > %d bytes.\n", HUGE_BUF);
160  break;
161  }
162  strncat(rules+size, buf, HUGE_BUF-size);
163  size += strlen(buf);
164  }
166  rules, NULL);
167  close_and_delete(fp, comp);
168 }
169 
176 void send_news(const object *op) {
177  char buf[MAX_BUF];
178  char news[HUGE_BUF];
179  char subject[MAX_BUF];
180  FILE *fp;
181  int comp;
182  int size;
183 
184  snprintf(buf, sizeof(buf), "%s/%s", settings.confdir, settings.news);
185  if ((fp = open_and_uncompress(buf, 0, &comp)) == NULL)
186  return;
187  news[0] = '\0';
188  subject[0] = '\0';
189  size = 0;
190  while (fgets(buf, MAX_BUF, fp) != NULL) {
191  if (*buf == '#')
192  continue;
193  if (*buf == '%') { /* send one news */
194  if (size > 0)
197  "%s:\n%s",
198  "%s:\n%s",
199  subject, news); /*send previously read news*/
200  strcpy(subject, buf+1);
201  strip_endline(subject);
202  size = 0;
203  news[0] = '\0';
204  } else {
205  if (size+strlen(buf) >= HUGE_BUF) {
206  LOG(llevDebug, "Warning, one news item has size > %d bytes.\n", HUGE_BUF);
207  break;
208  }
209  strncat(news+size, buf, HUGE_BUF-size);
210  size += strlen(buf);
211  }
212  }
213 
216  "%s:\n%s",
217  "%s:\n%s",
218  subject, news);
219  close_and_delete(fp, comp);
220 }
221 
230 int playername_ok(const char *cp) {
231  /* Don't allow - or _ as first character in the name */
232  if (*cp == '-' || *cp == '_')
233  return 0;
234 
235  for (; *cp != '\0'; cp++)
236  if (!((*cp >= 'a' && *cp <= 'z') || (*cp >= 'A' && *cp <= 'Z'))
237  && *cp != '-'
238  && *cp != '_')
239  return 0;
240  return 1;
241 }
242 
258 static player *get_player(player *p) {
259  object *op = arch_to_object(get_player_archetype(NULL));
260  int i;
261 
262  if (!p) {
263  player *tmp;
264 
265  p = (player *)malloc(sizeof(player));
266  if (p == NULL)
268 
269  /* This adds the player in the linked list. There is extra
270  * complexity here because we want to add the new player at the
271  * end of the list - there is in fact no compelling reason that
272  * that needs to be done except for things like output of
273  * 'who'.
274  */
275  tmp = first_player;
276  while (tmp != NULL && tmp->next != NULL)
277  tmp = tmp->next;
278  if (tmp != NULL)
279  tmp->next = p;
280  else
281  first_player = p;
282 
283  p->next = NULL;
284  } else {
285  /* Only needed when reusing existing player. */
286  clear_player(p);
287  }
288 
289  /* Clears basically the entire player structure except
290  * for next and socket.
291  */
292  memset((void *)((char *)p+offsetof(player, maplevel)), 0, sizeof(player)-offsetof(player, maplevel));
293 
294  /* There are some elements we want initialized to non zero value -
295  * we deal with that below this point.
296  */
297  p->party = NULL;
299  p->outputs_sync = 16; /* Every 2 seconds */
300  p->outputs_count = 1; /* Keeps present behaviour */
302  p->Swap_First = -1;
303 
304 #ifdef AUTOSAVE
305  p->last_save_tick = 9999999;
306 #endif
307 
308  strcpy(p->savebed_map, first_map_path); /* Init. respawn position */
309 
310  op->contr = p; /* this aren't yet in archetype */
311  p->ob = op;
312  op->speed_left = 0.5;
313  op->speed = 1.0;
314  op->direction = 5; /* So player faces south */
315  op->stats.wc = 2;
316  op->run_away = 25; /* Then we panick... */
317  p->socket.monitor_spells = 0; /* this needs to be set before roll_stats() as it calls fix_object() that sends the spells. */
318 
319  roll_stats(op);
320  p->state = ST_ROLL_STAT;
321  clear_los(op);
322 
323  p->gen_sp_armour = 10;
324  p->last_speed = -1;
325  p->shoottype = range_none;
326  p->bowtype = bow_normal;
327  p->petmode = pet_normal;
328  p->listening = 10;
329  p->last_weapon_sp = -1;
330  p->peaceful = 1; /* default peaceful */
331  p->do_los = 1;
332  p->explore = 0;
333  p->no_shout = 0; /* default can shout */
334  p->language = 0;
335 
336  strncpy(p->title, op->arch->clone.name, sizeof(p->title)-1);
337  p->title[sizeof(p->title)-1] = '\0';
338  op->race = add_string(op->arch->clone.race);
339 
341 
342  /* we need to clear these to -1 and not zero - otherwise,
343  * if a player quits and starts a new character, we wont
344  * send new values to the client, as things like exp start
345  * at zero.
346  */
347  for (i = 0; i < NUM_SKILLS; i++) {
348  p->last_skill_exp[i] = -1;
349  p->last_skill_ob[i] = NULL;
350  }
351  for (i = 0; i < NROFATTACKS; i++) {
352  p->last_resist[i] = -1;
353  }
354  p->last_stats.exp = -1;
355  p->last_weight = (uint32)-1;
356 
357  p->socket.update_look = 0;
358  p->socket.look_position = 0;
359  return p;
360 }
361 
368 static void set_first_map(object *op) {
369  strcpy(op->contr->maplevel, first_map_path);
370  op->x = -1;
371  op->y = -1;
372  enter_exit(op, NULL);
373 }
374 
384  player *p;
385 
386  p = get_player(NULL);
387  memcpy(&p->socket, ns, sizeof(socket_struct));
388 
389  /* The memcpy above copies the reference to faces sent. So we need to clear
390  * that pointer in ns, otherwise we get a double free.
391  */
392  ns->faces_sent = NULL;
393 
394  if (p->socket.faces_sent == NULL)
396 
397  /* Needed because the socket we just copied over needs to be cleared.
398  * Note that this can result in a client reset if there is partial data
399  * on the uncoming socket.
400  */
402  set_first_map(p->ob);
403 
406  send_rules(p->ob);
407  send_news(p->ob);
408  display_motd(p->ob);
409  get_name(p->ob);
410 }
411 
423  archetype *start = at;
424 
425  for (;;) {
426  if (at == NULL || at->next == NULL)
427  at = first_archetype;
428  else
429  at = at->next;
430  if (at->clone.type == PLAYER)
431  return at;
432  if (at == start) {
433  LOG(llevError, "No Player archetypes\n");
434  exit(-1);
435  }
436  }
437 }
438 
447 object *get_nearest_player(object *mon) {
448  object *op = NULL;
449  player *pl = NULL;
450  objectlink *ol;
451  unsigned lastdist;
452  rv_vector rv;
453 
454  for (ol = first_friendly_object, lastdist = 1000; ol != NULL; ol = ol->next) {
455  /* We should not find free objects on this friendly list, but it
456  * does periodically happen. Given that, lets deal with it.
457  * While unlikely, it is possible the next object on the friendly
458  * list is also free, so encapsulate this in a while loop.
459  */
460  while (QUERY_FLAG(ol->ob, FLAG_FREED) || !QUERY_FLAG(ol->ob, FLAG_FRIENDLY)) {
461  object *tmp = ol->ob;
462 
463  /* Can't do much more other than log the fact, because the object
464  * itself will have been cleared.
465  */
466  LOG(llevDebug, "get_nearest_player: Found free/non friendly object on friendly list\n");
467  ol = ol->next;
469  if (!ol)
470  return op;
471  }
472 
473  /* Remove special check for player from this. First, it looks to cause
474  * some crashes (ol->ob->contr not set properly?), but secondly, a more
475  * complicated method of state checking would be needed in any case -
476  * as it was, a clever player could type quit, and the function would
477  * skip them over while waiting for confirmation. Remove
478  * on_same_map check, as can_detect_enemy also does this
479  */
480  if (!can_detect_enemy(mon, ol->ob, &rv))
481  continue;
482 
483  if (lastdist > rv.distance) {
484  op = ol->ob;
485  lastdist = rv.distance;
486  }
487  }
488  for (pl = first_player; pl != NULL; pl = pl->next) {
489  if (can_detect_enemy(mon, pl->ob, &rv)) {
490  if (lastdist > rv.distance) {
491  op = pl->ob;
492  lastdist = rv.distance;
493  }
494  }
495  }
496  return op;
497 }
498 
508 #define DETOUR_AMOUNT 2
509 
523 #define MAX_SPACES 50
524 
556 int path_to_player(object *mon, object *pl, unsigned mindiff) {
557  rv_vector rv;
558  sint16 x, y;
559  int lastx, lasty, dir, i, diff, firstdir = 0, lastdir, max = MAX_SPACES, mflags, blocked;
560  mapstruct *m, *lastmap;
561 
562  get_rangevector(mon, pl, &rv, 0);
563 
564  if (rv.distance < mindiff)
565  return 0;
566 
567  x = mon->x;
568  y = mon->y;
569  m = mon->map;
570  dir = rv.direction;
571  lastdir = firstdir = rv.direction; /* perhaps we stand next to pl, init firstdir too */
572  diff = MAX(FABS(rv.distance_x), FABS(rv.distance_y));
573  /* If we can't solve it within the search distance, return now. */
574  if (diff > max)
575  return 0;
576  while (diff > 1 && max > 0) {
577  lastx = x;
578  lasty = y;
579  lastmap = m;
580  x = lastx+freearr_x[dir];
581  y = lasty+freearr_y[dir];
582 
583  mflags = get_map_flags(m, &m, x, y, &x, &y);
584  blocked = (mflags&P_OUT_OF_MAP) ? MOVE_ALL : GET_MAP_MOVE_BLOCK(m, x, y);
585 
586  /* Space is blocked - try changing direction a little */
587  if ((mflags&P_OUT_OF_MAP)
588  || ((OB_TYPE_MOVE_BLOCK(mon, blocked) || (mflags&P_IS_ALIVE))
589  && (m == mon->map && blocked_link(mon, m, x, y)))) {
590  /* recalculate direction from last good location. Possible
591  * we were not traversing ideal location before.
592  */
593  get_rangevector_from_mapcoord(lastmap, lastx, lasty, pl, &rv, 0);
594  if (rv.direction != dir) {
595  /* OK - says direction should be different - lets reset the
596  * the values so it will try again.
597  */
598  x = lastx;
599  y = lasty;
600  m = lastmap;
601  dir = firstdir = rv.direction;
602  } else {
603  /* direct path is blocked - try taking a side step to
604  * either the left or right.
605  * Note increase the values in the loop below to be
606  * more than -1/1 respectively will mean the monster takes
607  * bigger detour. Have to be careful about these values getting
608  * too big (3 or maybe 4 or higher) as the monster may just try
609  * stepping back and forth
610  */
611  for (i = -DETOUR_AMOUNT; i <= DETOUR_AMOUNT; i++) {
612  if (i == 0)
613  continue; /* already did this, so skip it */
614  /* Use lastdir here - otherwise,
615  * since the direction that the creature should move in
616  * may change, you could get infinite loops.
617  * ie, player is northwest, but monster can only
618  * move west, so it does that. It goes some distance,
619  * gets blocked, finds that it should move north,
620  * can't do that, but now finds it can move east, and
621  * gets back to its original point. lastdir contains
622  * the last direction the creature has successfully
623  * moved.
624  */
625 
626  x = lastx+freearr_x[absdir(lastdir+i)];
627  y = lasty+freearr_y[absdir(lastdir+i)];
628  m = lastmap;
629  mflags = get_map_flags(m, &m, x, y, &x, &y);
630  if (mflags&P_OUT_OF_MAP)
631  continue;
632  blocked = GET_MAP_MOVE_BLOCK(m, x, y);
633  if (OB_TYPE_MOVE_BLOCK(mon, blocked))
634  continue;
635  if (mflags&P_IS_ALIVE)
636  continue;
637 
638  if (m == mon->map && blocked_link(mon, m, x, y))
639  break;
640  }
641  /* go through entire loop without finding a valid
642  * sidestep to take - thus, no valid path.
643  */
644  if (i == (DETOUR_AMOUNT+1))
645  return 0;
646  diff--;
647  lastdir = dir;
648  max--;
649  if (!firstdir)
650  firstdir = dir+i;
651  } /* else check alternate directions */
652  } /* if blocked */
653  else {
654  /* we moved towards creature, so diff is less */
655  diff--;
656  max--;
657  lastdir = dir;
658  if (!firstdir)
659  firstdir = dir;
660  }
661  if (diff <= 1) {
662  /* Recalculate diff (distance) because we may not have actually
663  * headed toward player for entire distance.
664  */
665  get_rangevector_from_mapcoord(m, x, y, pl, &rv, 0);
666  diff = MAX(FABS(rv.distance_x), FABS(rv.distance_y));
667  }
668  if (diff > max)
669  return 0;
670  }
671  /* If we reached the max, didn't find a direction in time */
672  if (!max)
673  return 0;
674 
675  return firstdir;
676 }
677 
688 void give_initial_items(object *pl, treasurelist *items) {
689  object *op, *next = NULL;
690 
691  if (pl->randomitems != NULL)
692  create_treasure(items, pl, GT_STARTEQUIP|GT_ONLY_GOOD, 1, 0);
693 
694  for (op = pl->inv; op; op = next) {
695  next = op->below;
696 
697  /* Forces get applied per default, unless they have the
698  * flag "neutral" set. Sorry but I can't think of a better way
699  */
700  if (op->type == FORCE && !QUERY_FLAG(op, FLAG_NEUTRAL))
701  SET_FLAG(op, FLAG_APPLIED);
702 
703  /* we never give weapons/armour if these cannot be used
704  * by this player due to race restrictions
705  */
706  if (pl->type == PLAYER) {
707  if ((!QUERY_FLAG(pl, FLAG_USE_ARMOUR) && IS_ARMOR(op))
708  || (!QUERY_FLAG(pl, FLAG_USE_WEAPON) && IS_WEAPON(op))
709  || (!QUERY_FLAG(pl, FLAG_USE_SHIELD) && IS_SHIELD(op))) {
710  remove_ob(op);
711  free_object(op);
712  continue;
713  }
714  }
715 
716  /* This really needs to be better - we should really give
717  * a substitute spellbook. The problem is that we don't really
718  * have a good idea what to replace it with (need something like
719  * a first level treasurelist for each skill.)
720  * remove duplicate skills also
721  */
722  if (op->type == SPELLBOOK || op->type == SKILL) {
723  object *tmp;
724 
725  for (tmp = op->below; tmp; tmp = tmp->below)
726  if (tmp->type == op->type && tmp->name == op->name)
727  break;
728 
729  if (tmp) {
730  remove_ob(op);
731  free_object(op);
732  LOG(llevError, "give_initial_items: Removing duplicate object %s\n", tmp->name);
733  continue;
734  }
735  if (op->nrof > 1)
736  op->nrof = 1;
737  }
738 
739  if (op->type == SPELLBOOK && op->inv) {
741  }
742 
743  /* Give starting characters identified, uncursed, and undamned
744  * items. Just don't identify gold or silver, or it won't be
745  * merged properly.
746  */
747  if (need_identify(op)) {
749  CLEAR_FLAG(op, FLAG_CURSED);
750  CLEAR_FLAG(op, FLAG_DAMNED);
751  }
752  if (op->type == SPELL) {
753  remove_ob(op);
754  free_object(op);
755  continue;
756  } else if (op->type == SKILL) {
758  op->stats.exp = 0;
759  op->level = 1;
760  }
761  /* lock all 'normal items by default */
762  else
764  } /* for loop of objects in player inv */
765 
766  /* Need to set up the skill pointers */
767  link_player_skills(pl);
768 
773  for (op = pl->inv; op; op = next) {
774  next = op->below;
775  if ((IS_ARMOR(op) || IS_WEAPON(op) || IS_SHIELD(op)) && !QUERY_FLAG(op, FLAG_APPLIED))
776  manual_apply(pl, op, AP_NOPRINT);
777  }
778 }
779 
786 void get_name(object *op) {
787  op->contr->write_buf[0] = '\0';
788  op->contr->state = ST_GET_NAME;
789  send_query(&op->contr->socket, 0, "What is your name?\n:");
790 }
791 
798 void get_password(object *op) {
799  op->contr->write_buf[0] = '\0';
800  op->contr->state = ST_GET_PASSWORD;
801  send_query(&op->contr->socket, CS_QUERY_HIDEINPUT, "What is your password?\n:");
802 }
803 
810 void play_again(object *op) {
811  op->contr->state = ST_PLAY_AGAIN;
812  op->chosen_skill = NULL;
813  send_query(&op->contr->socket, CS_QUERY_SINGLECHAR, "Do you want to play again (a/q)?");
814  /* a bit of a hack, but there are various places early in th
815  * player creation process that a user can quit (eg, roll
816  * stats) that isn't removing the player. Taking a quick
817  * look, there are many places that call play_again without
818  * removing the player - it probably makes more sense
819  * to leave it to play_again to remove the object in all
820  * cases.
821  */
822  if (!QUERY_FLAG(op, FLAG_REMOVED))
823  remove_ob(op);
824  /* Need to set this to null - otherwise, it could point to garbage,
825  * and draw() doesn't check to see if the player is removed, only if
826  * the map is null or not swapped out.
827  */
828  op->map = NULL;
829 }
830 
839 void receive_play_again(object *op, char key) {
840  if (key == 'q' || key == 'Q') {
842  leave(op->contr, 0); /* ericserver will draw the message */
843  return;
844  } else if (key == 'a' || key == 'A') {
845  player *pl = op->contr;
846  const char *name = op->name;
847 
848  add_refcount(name);
850  free_object(op);
851  pl = get_player(pl);
852  op = pl->ob;
854  op->contr->password[0] = '~';
857 
858  /* Lets put a space in here */
860  "\n", "\n");
861  get_name(op);
862  op->name = name; /* Already added a refcount above */
863  op->name_pl = add_string(name);
864  set_first_map(op);
865  } else {
866  /* user pressed something else so just ask again... */
867  play_again(op);
868  }
869 }
870 
877 void confirm_password(object *op) {
878  op->contr->write_buf[0] = '\0';
880  send_query(&op->contr->socket, CS_QUERY_HIDEINPUT, "Please type your password again.\n:");
881 }
882 
891 void get_party_password(object *op, partylist *party) {
892  if (party == NULL) {
893  LOG(llevError, "get_party_password(): tried to make player %s join a NULL party\n", op->name);
894  return;
895  }
896  op->contr->write_buf[0] = '\0';
898  op->contr->party_to_join = party;
899  send_query(&op->contr->socket, CS_QUERY_HIDEINPUT, "What is the password?\n:");
900 }
901 
908 int roll_stat(void) {
909  int a[4], i, j, k;
910 
911  for (i = 0; i < 4; i++)
912  a[i] = (int)RANDOM()%6+1;
913 
914  for (i = 0, j = 0, k = 7; i < 4; i++)
915  if (a[i] < k)
916  k = a[i],
917  j = i;
918 
919  for (i = 0, k = 0; i < 4; i++) {
920  if (i != j)
921  k += a[i];
922  }
923  return k;
924 }
925 
932 void roll_stats(object *op) {
933  int sum = 0;
934  int i = 0, j = 0;
935  int statsort[7];
936 
937  do {
938  op->stats.Str = roll_stat();
939  op->stats.Dex = roll_stat();
940  op->stats.Int = roll_stat();
941  op->stats.Con = roll_stat();
942  op->stats.Wis = roll_stat();
943  op->stats.Pow = roll_stat();
944  op->stats.Cha = roll_stat();
945  sum = op->stats.Str+op->stats.Dex+op->stats.Int+op->stats.Con+op->stats.Wis+op->stats.Pow+op->stats.Cha;
946  } while (sum != 105); /* 116 used to be best possible character */
947 
948  /* Sort the stats so that rerolling is easier... */
949  statsort[0] = op->stats.Str;
950  statsort[1] = op->stats.Dex;
951  statsort[2] = op->stats.Int;
952  statsort[3] = op->stats.Con;
953  statsort[4] = op->stats.Wis;
954  statsort[5] = op->stats.Pow;
955  statsort[6] = op->stats.Cha;
956 
957  /* a quick and dirty bubblesort? */
958  do {
959  if (statsort[i] < statsort[i+1]) {
960  j = statsort[i];
961  statsort[i] = statsort[i+1];
962  statsort[i+1] = j;
963  i = 0;
964  } else {
965  i++;
966  }
967  } while (i < 6);
968 
969  op->stats.Str = statsort[0];
970  op->stats.Dex = statsort[1];
971  op->stats.Con = statsort[2];
972  op->stats.Int = statsort[3];
973  op->stats.Wis = statsort[4];
974  op->stats.Pow = statsort[5];
975  op->stats.Cha = statsort[6];
976 
977  op->contr->orig_stats.Str = op->stats.Str;
978  op->contr->orig_stats.Dex = op->stats.Dex;
979  op->contr->orig_stats.Int = op->stats.Int;
980  op->contr->orig_stats.Con = op->stats.Con;
981  op->contr->orig_stats.Wis = op->stats.Wis;
982  op->contr->orig_stats.Pow = op->stats.Pow;
983  op->contr->orig_stats.Cha = op->stats.Cha;
984 
985  op->level = 1;
986  op->stats.exp = 0;
987  op->stats.ac = 0;
988 
989  op->contr->levhp[1] = 9;
990  op->contr->levsp[1] = 6;
991  op->contr->levgrace[1] = 3;
992 
993  fix_object(op);
994  op->stats.hp = op->stats.maxhp;
995  op->stats.sp = op->stats.maxsp;
996  op->stats.grace = op->stats.maxgrace;
997  op->contr->orig_stats = op->stats;
998 }
999 
1006 void roll_again(object *op) {
1007  esrv_new_player(op->contr, 0);
1008  send_query(&op->contr->socket, CS_QUERY_SINGLECHAR, "[y] to roll new stats [n] to use stats\n[1-7] [1-7] to swap stats.\nRoll again (y/n/1-7)? ");
1009 }
1010 
1020 static void swap_stat(object *op, int Swap_Second) {
1021  signed char tmp;
1022 
1023  if (op->contr->Swap_First == -1) {
1024  LOG(llevError, "player.c:swap_stat() - Swap_First is -1\n");
1025  return;
1026  }
1027 
1028  tmp = get_attr_value(&op->contr->orig_stats, op->contr->Swap_First);
1029 
1030  set_attr_value(&op->contr->orig_stats, op->contr->Swap_First, get_attr_value(&op->contr->orig_stats, Swap_Second));
1031 
1032  set_attr_value(&op->contr->orig_stats, Swap_Second, tmp);
1033 
1035  "%s done\n",
1036  "%s done\n",
1037  short_stat_name[Swap_Second]);
1038 
1039  op->stats.Str = op->contr->orig_stats.Str;
1040  op->stats.Dex = op->contr->orig_stats.Dex;
1041  op->stats.Con = op->contr->orig_stats.Con;
1042  op->stats.Int = op->contr->orig_stats.Int;
1043  op->stats.Wis = op->contr->orig_stats.Wis;
1044  op->stats.Pow = op->contr->orig_stats.Pow;
1045  op->stats.Cha = op->contr->orig_stats.Cha;
1046  op->stats.ac = 0;
1047 
1048  op->level = 1;
1049  op->stats.exp = 0;
1050  op->stats.ac = 0;
1051 
1052  op->contr->levhp[1] = 9;
1053  op->contr->levsp[1] = 6;
1054  op->contr->levgrace[1] = 3;
1055 
1056  fix_object(op);
1057  op->stats.hp = op->stats.maxhp;
1058  op->stats.sp = op->stats.maxsp;
1059  op->stats.grace = op->stats.maxgrace;
1060  op->contr->orig_stats = op->stats;
1061  op->contr->Swap_First = -1;
1062 }
1063 
1079 void key_roll_stat(object *op, char key) {
1080  int keynum = key-'0';
1081  static const sint8 stat_trans[] = {
1082  -1,
1083  STR,
1084  DEX,
1085  CON,
1086  INT,
1087  WIS,
1088  POW,
1089  CHA
1090  };
1091 
1092  if (keynum > 0 && keynum <= 7) {
1093  if (op->contr->Swap_First == -1) {
1094  op->contr->Swap_First = stat_trans[keynum];
1096  "%s ->",
1097  "%s ->",
1098  short_stat_name[stat_trans[keynum]]);
1099  } else
1100  swap_stat(op, stat_trans[keynum]);
1101 
1103  return;
1104  }
1105  switch (key) {
1106  case 'n':
1107  case 'N': {
1108  SET_FLAG(op, FLAG_WIZ);
1109  if (op->map == NULL) {
1110  LOG(llevError, "Map == NULL in state 2\n");
1111  break;
1112  }
1113 
1114  SET_ANIMATION(op, 2); /* So player faces south */
1115  /* Enter exit adds a player otherwise */
1116  add_statbonus(op);
1117  send_query(&op->contr->socket, CS_QUERY_SINGLECHAR, "Now choose a character.\nPress any key to change outlook.\nPress `d' when you're pleased.\n");
1118  op->contr->state = ST_CHANGE_CLASS;
1119  if (op->msg)
1120  draw_ext_info(NDI_BLUE, 0, op,
1122  op->msg, op->msg);
1123  return;
1124  }
1125  case 'y':
1126  case 'Y':
1127  roll_stats(op);
1129  return;
1130 
1131  case 'q':
1132  case 'Q':
1133  play_again(op);
1134  return;
1135 
1136  default:
1137  send_query(&op->contr->socket, CS_QUERY_SINGLECHAR, "Yes, No, Quit or 1-6. Roll again?");
1138  return;
1139  }
1140  return;
1141 }
1142 
1156 void key_change_class(object *op, char key) {
1157  int tmp_loop;
1158 
1159  if (key == 'q' || key == 'Q') {
1160  remove_ob(op);
1161  play_again(op);
1162  return;
1163  }
1164  if (key == 'd' || key == 'D') {
1165  char buf[MAX_BUF];
1166 
1167  /* this must before then initial items are given */
1168  esrv_new_player(op->contr, op->weight+op->carrying);
1169  create_treasure(find_treasurelist("starting_wealth"), op, 0, 0, 0);
1170 
1171  /* Lauwenmark : Here we handle the BORN global event */
1173 
1174  /* Lauwenmark : We then generate a LOGIN event */
1176  op->contr->state = ST_PLAYING;
1177 
1178  if (op->msg) {
1179  free_string(op->msg);
1180  op->msg = NULL;
1181  }
1182 
1183  /* We create this now because some of the unique maps will need it
1184  * to save here.
1185  */
1186  snprintf(buf, sizeof(buf), "%s/%s/%s", settings.localdir, settings.playerdir, op->name);
1187  make_path_to_file(buf);
1188 
1189 #ifdef AUTOSAVE
1190  op->contr->last_save_tick = pticks;
1191 #endif
1192  start_info(op);
1193  CLEAR_FLAG(op, FLAG_WIZ);
1195  link_player_skills(op);
1196  esrv_send_inventory(op, op);
1197  fix_object(op);
1198 
1199  /* This moves the player to a different start map, if there
1200  * is one for this race
1201  */
1202  if (*first_map_ext_path) {
1203  object *tmp;
1204  char mapname[MAX_BUF];
1205  mapstruct *oldmap;
1206 
1207  oldmap = op->map;
1208 
1209  snprintf(mapname, MAX_BUF-1, "%s/%s", first_map_ext_path, op->arch->name);
1210  /*printf("%s\n", mapname);*/
1211  tmp = get_object();
1212  EXIT_PATH(tmp) = add_string(mapname);
1213  EXIT_X(tmp) = op->x;
1214  EXIT_Y(tmp) = op->y;
1215  enter_exit(op, tmp);
1216 
1217  if (oldmap != op->map) {
1218  /* map exists, update bed of reality location, in case player dies */
1219  op->contr->bed_x = op->x;
1220  op->contr->bed_y = op->y;
1221  snprintf(op->contr->savebed_map, sizeof(op->contr->savebed_map), "%s", mapname);
1222  }
1223 
1224  free_object(tmp);
1225  } else {
1226  LOG(llevDebug, "first_map_ext_path not set\n");
1227  }
1228  return;
1229  }
1230 
1231  /* Following actually changes the race - this is the default command
1232  * if we don't match with one of the options above.
1233  */
1234 
1235  tmp_loop = 0;
1236  while (!tmp_loop) {
1237  const char *name = add_string(op->name);
1238  int x = op->x, y = op->y;
1239 
1240  remove_statbonus(op);
1241  remove_ob(op);
1242  op->arch = get_player_archetype(op->arch);
1243  copy_object(&op->arch->clone, op);
1244  op->stats = op->contr->orig_stats;
1245  free_string(op->name);
1246  op->name = name;
1247  free_string(op->name_pl);
1248  op->name_pl = add_string(name);
1249  op->x = x;
1250  op->y = y;
1251  SET_ANIMATION(op, 2); /* So player faces south */
1252  insert_ob_in_map(op, op->map, op, 0);
1253  strncpy(op->contr->title, op->arch->clone.name, sizeof(op->contr->title)-1);
1254  op->contr->title[sizeof(op->contr->title)-1] = '\0';
1255  add_statbonus(op);
1256  tmp_loop = allowed_class(op);
1257  }
1259  esrv_update_item(UPD_FACE, op, op);
1260  fix_object(op);
1261  op->stats.hp = op->stats.maxhp;
1262  op->stats.sp = op->stats.maxsp;
1263  op->stats.grace = 0;
1264  if (op->msg)
1266  op->msg, op->msg);
1267  send_query(&op->contr->socket, CS_QUERY_SINGLECHAR, "Press any key for the next race.\nPress `d' to play this race.\n");
1268 }
1269 
1278 void key_confirm_quit(object *op, char key) {
1279  char buf[MAX_BUF];
1280 
1281  if (key != 'y' && key != 'Y' && key != 'q' && key != 'Q') {
1282  op->contr->state = ST_PLAYING;
1284  "OK, continuing to play.", NULL);
1285  return;
1286  }
1287 
1288  /* Lauwenmark : Here we handle the REMOVE global event */
1290  terminate_all_pets(op);
1291  remove_ob(op);
1292  op->direction = 0;
1294  "%s quits the game.",
1295  "%s quits the game.",
1296  op->name);
1297 
1298  strcpy(op->contr->killer, "quit");
1299  check_score(op, 0);
1300  op->contr->party = NULL;
1301  if (settings.set_title == TRUE)
1302  op->contr->own_title[0] = '\0';
1303 
1304  if (!QUERY_FLAG(op, FLAG_WAS_WIZ)) {
1305  mapstruct *mp, *next;
1306 
1307  /* We need to hunt for any per player unique maps in memory and
1308  * get rid of them. The trailing slash in the path is intentional,
1309  * so that players named 'Ab' won't match against players 'Abe' pathname
1310  */
1311  snprintf(buf, sizeof(buf), "%s/%s/%s/", settings.localdir, settings.playerdir, op->name);
1312  for (mp = first_map; mp != NULL; mp = next) {
1313  next = mp->next;
1314  if (!strncmp(mp->path, buf, strlen(buf)))
1315  delete_map(mp);
1316  }
1317 
1318  delete_character(op->name);
1319  }
1320  play_again(op);
1321 }
1322 
1329 static void flee_player(object *op) {
1330  int dir, diff;
1331  rv_vector rv;
1332 
1333  if (op->stats.hp < 0) {
1334  LOG(llevDebug, "Fleeing player is dead.\n");
1335  CLEAR_FLAG(op, FLAG_SCARED);
1336  return;
1337  }
1338 
1339  if (op->enemy == NULL) {
1340  LOG(llevDebug, "Fleeing player had no enemy.\n");
1341  CLEAR_FLAG(op, FLAG_SCARED);
1342  return;
1343  }
1344 
1345  /* Seen some crashes here. Since we don't store an
1346  * op->enemy_count, it is possible that something destroys the
1347  * actual enemy, and the object is recycled.
1348  */
1349  if (op->enemy->map == NULL) {
1350  CLEAR_FLAG(op, FLAG_SCARED);
1351  op->enemy = NULL;
1352  return;
1353  }
1354 
1355  if (!(random_roll(0, 4, op, PREFER_LOW)) && did_make_save(op, op->level, 0)) {
1356  op->enemy = NULL;
1357  CLEAR_FLAG(op, FLAG_SCARED);
1358  return;
1359  }
1360  get_rangevector(op, op->enemy, &rv, 0);
1361 
1362  dir = absdir(4+rv.direction);
1363  for (diff = 0; diff < 3; diff++) {
1364  int m = 1-(RANDOM()&2);
1365  if (move_ob(op, absdir(dir+diff*m), op)
1366  || (diff == 0 && move_ob(op, absdir(dir-diff*m), op))) {
1367  return;
1368  }
1369  }
1370  /* Cornered, get rid of scared */
1371  CLEAR_FLAG(op, FLAG_SCARED);
1372  op->enemy = NULL;
1373 }
1374 
1384 int check_pick(object *op) {
1385  object *tmp, *next;
1386  tag_t next_tag = 0, op_tag;
1387  int stop = 0;
1388  int j, k, wvratio;
1389  char putstring[128], tmpstr[16];
1390 
1391  /* if you're flying, you can't pick up anything */
1392  if (op->move_type&MOVE_FLYING)
1393  return 1;
1394 
1395  op_tag = op->count;
1396 
1397  next = op->below;
1398  if (next)
1399  next_tag = next->count;
1400 
1401  /* loop while there are items on the floor that are not marked as
1402  * destroyed */
1403  while (next && !was_destroyed(next, next_tag)) {
1404  tmp = next;
1405  next = tmp->below;
1406  if (next)
1407  next_tag = next->count;
1408 
1409  if (was_destroyed(op, op_tag))
1410  return 0;
1411 
1412  if (!can_pick(op, tmp))
1413  continue;
1414 
1415  if (op->contr->search_str[0] != '\0' && settings.search_items == TRUE) {
1416  if (item_matched_string(op, tmp, op->contr->search_str))
1417  pick_up(op, tmp);
1418  continue;
1419  }
1420 
1421  /* high not bit set? We're using the old autopickup model */
1422  if (!(op->contr->mode&PU_NEWMODE)) {
1423  switch (op->contr->mode) {
1424  case 0:
1425  return 1; /* don't pick up */
1426 
1427  case 1:
1428  pick_up(op, tmp);
1429  return 1;
1430 
1431  case 2:
1432  pick_up(op, tmp);
1433  return 0;
1434 
1435  case 3:
1436  return 0; /* stop before pickup */
1437 
1438  case 4:
1439  pick_up(op, tmp);
1440  break;
1441 
1442  case 5:
1443  pick_up(op, tmp);
1444  stop = 1;
1445  break;
1446 
1447  case 6:
1448  if (QUERY_FLAG(tmp, FLAG_KNOWN_MAGICAL)
1449  && !QUERY_FLAG(tmp, FLAG_KNOWN_CURSED))
1450  pick_up(op, tmp);
1451  break;
1452 
1453  case 7:
1454  if (tmp->type == MONEY || tmp->type == GEM)
1455  pick_up(op, tmp);
1456  break;
1457 
1458  default:
1459  /* use value density */
1460  if (!QUERY_FLAG(tmp, FLAG_UNPAID)
1461  && (query_cost(tmp, op, F_TRUE)*100/(tmp->weight*MAX(tmp->nrof, 1))) >= op->contr->mode)
1462  pick_up(op, tmp);
1463  }
1464  } else { /* old model */
1465  /* NEW pickup handling */
1466  if (op->contr->mode&PU_DEBUG) {
1467  /* some debugging code to figure out item information */
1469  "item name: %s item type: %d weight/value: %d",
1470  "item name: %s item type: %d weight/value: %d",
1471  tmp->name ? tmp->name : tmp->arch->name, tmp->type,
1472  (int)(query_cost(tmp, op, F_TRUE)*100/(tmp->weight*MAX(tmp->nrof, 1))));
1473 
1474 
1475  snprintf(putstring, sizeof(putstring), "...flags: ");
1476  for (k = 0; k < 4; k++) {
1477  for (j = 0; j < 32; j++) {
1478  if ((tmp->flags[k]>>j)&0x01) {
1479  snprintf(tmpstr, sizeof(tmpstr), "%d ", k*32+j);
1480  strcat(putstring, tmpstr);
1481  }
1482  }
1483  }
1485  putstring, putstring);
1486  }
1487  /* philosophy:
1488  * It's easy to grab an item type from a pile, as long as it's
1489  * generic. This takes no game-time. For more detailed pickups
1490  * and selections, select-items should be used. This is a
1491  * grab-as-you-run type mode that's really useful for arrows for
1492  * example.
1493  * The drawback: right now it has no frontend, so you need to
1494  * stick the bits you want into a calculator in hex mode and then
1495  * convert to decimal and then 'pickup <#>
1496  */
1497 
1498  /* the first two modes are exclusive: if NOTHING we return, if
1499  * STOP then we stop. All the rest are applied sequentially,
1500  * meaning if any test passes, the item gets picked up. */
1501 
1502  /* if mode is set to pick nothing up, return */
1503 
1504  if (op->contr->mode&PU_NOTHING)
1505  return 1;
1506 
1507  /* if mode is set to stop when encountering objects, return.
1508  * Take STOP before INHIBIT since it doesn't actually pick
1509  * anything up */
1510 
1511  if (op->contr->mode&PU_STOP)
1512  return 0;
1513 
1514  /* useful for going into stores and not losing your settings... */
1515  /* and for battles wher you don't want to get loaded down while
1516  * fighting */
1517  if (op->contr->mode&PU_INHIBIT)
1518  return 1;
1519 
1520  /* prevent us from turning into auto-thieves :) */
1521  if (QUERY_FLAG(tmp, FLAG_UNPAID))
1522  continue;
1523 
1524  /* ignore known cursed objects */
1526  continue;
1527 
1528  /* all food and drink if desired */
1529  /* question: don't pick up known-poisonous stuff? */
1530  if (op->contr->mode&PU_FOOD)
1531  if (tmp->type == FOOD) {
1532  pick_up(op, tmp);
1533  if (0)
1534  fprintf(stderr, "FOOD\n");
1535  continue;
1536  }
1537  if (op->contr->mode&PU_DRINK)
1538  if (tmp->type == DRINK || (tmp->type == POISON && !QUERY_FLAG(tmp, FLAG_KNOWN_CURSED))) {
1539  pick_up(op, tmp);
1540  if (0)
1541  fprintf(stderr, "DRINK\n");
1542  continue;
1543  }
1544  /* we don't forget dragon food */
1545  if (op->contr->mode&PU_FLESH)
1546  if (tmp->type == FLESH) {
1547  pick_up(op, tmp);
1548  if (0)
1549  fprintf(stderr, "FLESH\n");
1550  continue;
1551  }
1552  if (op->contr->mode&PU_POTION)
1553  if (tmp->type == POTION) {
1554  pick_up(op, tmp);
1555  if (0)
1556  fprintf(stderr, "POTION\n");
1557  continue;
1558  }
1559 
1560  /* spellbooks, skillscrolls and normal books/scrolls */
1561  if (op->contr->mode&PU_SPELLBOOK)
1562  if (tmp->type == SPELLBOOK) {
1563  pick_up(op, tmp);
1564  if (0)
1565  fprintf(stderr, "SPELLBOOK\n");
1566  continue;
1567  }
1568  if (op->contr->mode&PU_SKILLSCROLL)
1569  if (tmp->type == SKILLSCROLL) {
1570  pick_up(op, tmp);
1571  if (0)
1572  fprintf(stderr, "SKILLSCROLL\n");
1573  continue;
1574  }
1575  if (op->contr->mode&PU_READABLES)
1576  if (tmp->type == BOOK || tmp->type == SCROLL) {
1577  pick_up(op, tmp);
1578  if (0)
1579  fprintf(stderr, "READABLES\n");
1580  continue;
1581  }
1582 
1583  /* wands/staves/rods/horns */
1584  if (op->contr->mode&PU_MAGIC_DEVICE)
1585  if (tmp->type == WAND || tmp->type == ROD || tmp->type == HORN) {
1586  pick_up(op, tmp);
1587  if (0)
1588  fprintf(stderr, "MAGIC_DEVICE\n");
1589  continue;
1590  }
1591 
1592  /* pick up all magical items */
1593  if (op->contr->mode&PU_MAGICAL)
1595  pick_up(op, tmp);
1596  if (0)
1597  fprintf(stderr, "MAGICAL\n");
1598  continue;
1599  }
1600 
1601  if (op->contr->mode&PU_VALUABLES) {
1602  if (tmp->type == MONEY || tmp->type == GEM) {
1603  pick_up(op, tmp);
1604  if (0)
1605  fprintf(stderr, "MONEY/GEM\n");
1606  continue;
1607  }
1608  }
1609 
1610  /* rings & amulets - talismans seems to be typed AMULET */
1611  if (op->contr->mode&PU_JEWELS)
1612  if (tmp->type == RING || tmp->type == AMULET) {
1613  pick_up(op, tmp);
1614  if (0)
1615  fprintf(stderr, "JEWELS\n");
1616  continue;
1617  }
1618 
1619  /* bows and arrows. Bows are good for selling! */
1620  if (op->contr->mode&PU_BOW)
1621  if (tmp->type == BOW) {
1622  pick_up(op, tmp);
1623  if (0)
1624  fprintf(stderr, "BOW\n");
1625  continue;
1626  }
1627  if (op->contr->mode&PU_ARROW)
1628  if (tmp->type == ARROW) {
1629  pick_up(op, tmp);
1630  if (0)
1631  fprintf(stderr, "ARROW\n");
1632  continue;
1633  }
1634 
1635  /* all kinds of armor etc. */
1636  if (op->contr->mode&PU_ARMOUR)
1637  if (tmp->type == ARMOUR) {
1638  pick_up(op, tmp);
1639  if (0)
1640  fprintf(stderr, "ARMOUR\n");
1641  continue;
1642  }
1643  if (op->contr->mode&PU_HELMET)
1644  if (tmp->type == HELMET) {
1645  pick_up(op, tmp);
1646  if (0)
1647  fprintf(stderr, "HELMET\n");
1648  continue;
1649  }
1650  if (op->contr->mode&PU_SHIELD)
1651  if (tmp->type == SHIELD) {
1652  pick_up(op, tmp);
1653  if (0)
1654  fprintf(stderr, "SHIELD\n");
1655  continue;
1656  }
1657  if (op->contr->mode&PU_BOOTS)
1658  if (tmp->type == BOOTS) {
1659  pick_up(op, tmp);
1660  if (0)
1661  fprintf(stderr, "BOOTS\n");
1662  continue;
1663  }
1664  if (op->contr->mode&PU_GLOVES)
1665  if (tmp->type == GLOVES) {
1666  pick_up(op, tmp);
1667  if (0)
1668  fprintf(stderr, "GLOVES\n");
1669  continue;
1670  }
1671  if (op->contr->mode&PU_CLOAK)
1672  if (tmp->type == CLOAK) {
1673  pick_up(op, tmp);
1674  if (0)
1675  fprintf(stderr, "GLOVES\n");
1676  continue;
1677  }
1678 
1679  /* hoping to catch throwing daggers here */
1680  if (op->contr->mode&PU_MISSILEWEAPON)
1681  if (tmp->type == WEAPON && QUERY_FLAG(tmp, FLAG_IS_THROWN)) {
1682  pick_up(op, tmp);
1683  if (0)
1684  fprintf(stderr, "MISSILEWEAPON\n");
1685  continue;
1686  }
1687 
1688  /* careful: chairs and tables are weapons! */
1689  if (op->contr->mode&PU_ALLWEAPON) {
1690  if (tmp->type == WEAPON && tmp->name != NULL) {
1691  if (strstr(tmp->name, "table") == NULL
1692  && strstr(tmp->arch->name, "table") == NULL
1693  && strstr(tmp->name, "chair")
1694  && strstr(tmp->arch->name, "chair") == NULL) {
1695  pick_up(op, tmp);
1696  if (0)
1697  fprintf(stderr, "WEAPON\n");
1698  continue;
1699  }
1700  }
1701  if (tmp->type == WEAPON && tmp->name == NULL) {
1702  if (strstr(tmp->arch->name, "table") == NULL
1703  && strstr(tmp->arch->name, "chair") == NULL) {
1704  pick_up(op, tmp);
1705  if (0)
1706  fprintf(stderr, "WEAPON\n");
1707  continue;
1708  }
1709  }
1710  }
1711 
1712  /* misc stuff that's useful */
1713  if (op->contr->mode&PU_KEY)
1714  if (tmp->type == KEY || tmp->type == SPECIAL_KEY) {
1715  pick_up(op, tmp);
1716  if (0)
1717  fprintf(stderr, "KEY\n");
1718  continue;
1719  }
1720 
1721  /* any of the last 4 bits set means we use the ratio for value
1722  * pickups */
1723  if (op->contr->mode&PU_RATIO) {
1724  /* use value density to decide what else to grab.
1725  * >=7 was >= op->contr->mode
1726  * >=7 is the old standard setting. Now we take the last 4 bits
1727  * and multiply them by 5, giving 0..15*5== 5..75 */
1728  wvratio = (op->contr->mode&PU_RATIO)*5;
1729  if ((query_cost(tmp, op, F_TRUE)*100/(tmp->weight*MAX(tmp->nrof, 1))) >= wvratio) {
1730  pick_up(op, tmp);
1731  continue;
1732  }
1733  }
1734  } /* the new pickup model */
1735  }
1736  return !stop;
1737 }
1738 
1751 static object *find_arrow(object *op, const char *type) {
1752  object *tmp = NULL;
1753 
1754  for (op = op->inv; op; op = op->below)
1755  if (!tmp
1756  && op->type == CONTAINER
1757  && op->race == type
1758  && QUERY_FLAG(op, FLAG_APPLIED))
1759  tmp = find_arrow(op, type);
1760  else if (op->type == ARROW && op->race == type)
1761  return op;
1762  return tmp;
1763 }
1764 
1782 static object *find_better_arrow(object *op, object *target, const char *type, int *better) {
1783  object *tmp = NULL, *arrow, *ntmp;
1784  int attacknum, attacktype, betterby = 0, i;
1785 
1786  if (!type)
1787  return NULL;
1788 
1789  for (arrow = op->inv; arrow; arrow = arrow->below) {
1790  if (arrow->type == CONTAINER
1791  && arrow->race == type
1792  && QUERY_FLAG(arrow, FLAG_APPLIED)) {
1793  i = 0;
1794  ntmp = find_better_arrow(arrow, target, type, &i);
1795  if (i > betterby) {
1796  tmp = ntmp;
1797  betterby = i;
1798  }
1799  } else if (arrow->type == ARROW && arrow->race == type) {
1800  /* allways prefer assasination/slaying */
1801  if (target->race != NULL
1802  && arrow->slaying != NULL
1803  && strstr(arrow->slaying, target->race)) {
1804  if (arrow->attacktype&AT_DEATH) {
1805  if (better)
1806  *better = 100;
1807  return arrow;
1808  } else {
1809  tmp = arrow;
1810  betterby = (arrow->magic+arrow->stats.dam)*2;
1811  }
1812  } else {
1813  for (attacknum = 0; attacknum < NROFATTACKS; attacknum++) {
1814  attacktype = 1<<attacknum;
1815  if ((arrow->attacktype&attacktype) && (target->arch->clone.resist[attacknum]) < 0)
1816  if (((arrow->magic+arrow->stats.dam)*(100-target->arch->clone.resist[attacknum])/100) > betterby) {
1817  tmp = arrow;
1818  betterby = (arrow->magic+arrow->stats.dam)*(100-target->arch->clone.resist[attacknum])/100;
1819  }
1820  }
1821  if ((2+arrow->magic+arrow->stats.dam) > betterby) {
1822  tmp = arrow;
1823  betterby = 2+arrow->magic+arrow->stats.dam;
1824  }
1825  if (arrow->title && (1+arrow->magic+arrow->stats.dam) > betterby) {
1826  tmp = arrow;
1827  betterby = 1+arrow->magic+arrow->stats.dam;
1828  }
1829  }
1830  }
1831  }
1832  if (tmp == NULL && arrow == NULL)
1833  return find_arrow(op, type);
1834 
1835  if (better)
1836  *better = betterby;
1837  return tmp;
1838 }
1839 
1852 static object *pick_arrow_target(object *op, const char *type, int dir) {
1853  object *tmp = NULL;
1854  mapstruct *m;
1855  int i, mflags, found, number;
1856  sint16 x, y;
1857 
1858  if (op->map == NULL)
1859  return find_arrow(op, type);
1860 
1861  /* do a dex check */
1862  number = (die_roll(2, 40, op, PREFER_LOW)-2)/2;
1863  if (number > (op->stats.Dex+(op->chosen_skill ? op->chosen_skill->level : op->level)))
1864  return find_arrow(op, type);
1865 
1866  m = op->map;
1867  x = op->x;
1868  y = op->y;
1869 
1870  /* find the first target */
1871  for (i = 0, found = 0; i < 20; i++) {
1872  x += freearr_x[dir];
1873  y += freearr_y[dir];
1874  mflags = get_map_flags(m, &m, x, y, &x, &y);
1875  if (mflags&P_OUT_OF_MAP || mflags&P_BLOCKSVIEW) {
1876  tmp = NULL;
1877  break;
1878  } else if (GET_MAP_MOVE_BLOCK(m, x, y) == MOVE_FLY_LOW) {
1879  /* This block presumes arrows and the like are MOVE_FLY_SLOW -
1880  * perhaps a bad assumption.
1881  */
1882  tmp = NULL;
1883  break;
1884  }
1885  if (mflags&P_IS_ALIVE) {
1886  for (tmp = GET_MAP_OB(m, x, y); tmp; tmp = tmp->above)
1887  if (QUERY_FLAG(tmp, FLAG_ALIVE)) {
1888  found++;
1889  break;
1890  }
1891  if (found)
1892  break;
1893  }
1894  }
1895  if (tmp == NULL)
1896  return find_arrow(op, type);
1897 
1898  if (tmp->head)
1899  tmp = tmp->head;
1900 
1901  return find_better_arrow(op, tmp, type, NULL);
1902 }
1903 
1922 int fire_bow(object *op, object *arrow, int dir, int wc_mod, sint16 sx, sint16 sy) {
1923  object *left, *bow;
1924  tag_t left_tag, tag;
1925  int bowspeed, mflags;
1926  mapstruct *m;
1927 
1928  if (!dir) {
1930  "You can't shoot yourself!", NULL);
1931  return 0;
1932  }
1933  if (op->type == PLAYER)
1934  bow = op->contr->ranges[range_bow];
1935  else {
1936  for (bow = op->inv; bow; bow = bow->below)
1937  /* Don't check for applied - monsters don't apply bows - in that way, they
1938  * don't need to switch back and forth between bows and weapons.
1939  */
1940  if (bow->type == BOW)
1941  break;
1942 
1943  if (!bow) {
1944  LOG(llevError, "Range: bow without activated bow (%s).\n", op->name);
1945  return 0;
1946  }
1947  }
1948  if (!bow->race || !bow->skill) {
1950  "Your %s is broken.",
1951  "Your %s is broken.",
1952  bow->name);
1953  return 0;
1954  }
1955 
1956  bowspeed = bow->stats.sp+dex_bonus[op->stats.Dex];
1957 
1958  /* penalize ROF for bestarrow */
1959  if (op->type == PLAYER && op->contr->bowtype == bow_bestarrow)
1960  bowspeed -= dex_bonus[op->stats.Dex]+5;
1961  if (bowspeed < 1)
1962  bowspeed = 1;
1963 
1964  if (arrow == NULL) {
1965  if ((arrow = find_arrow(op, bow->race)) == NULL) {
1966  if (op->type == PLAYER)
1969  "You have no %s left.",
1970  "You have no %s left.",
1971  bow->race);
1972  /* FLAG_READY_BOW will get reset if the monsters picks up some arrows */
1973  else
1975  return 0;
1976  }
1977  }
1978  mflags = get_map_flags(op->map, &m, sx, sy, &sx, &sy);
1979  if (mflags&P_OUT_OF_MAP) {
1980  return 0;
1981  }
1982  if (GET_MAP_MOVE_BLOCK(m, sx, sy)&MOVE_FLY_LOW) {
1983  return 0;
1984  }
1985 
1986  /* this should not happen, but sometimes does */
1987  if (arrow->nrof == 0) {
1988  remove_ob(arrow);
1989  free_object(arrow);
1990  return 0;
1991  }
1992 
1993  left = arrow; /* these are arrows left to the player */
1994  /* BUG? The value in left_tag doesn't seem to be used. */
1995  left_tag = left->count;
1996  arrow = get_split_ob(arrow, 1, NULL, 0);
1997  if (arrow == NULL) {
1999  "You have no %s left.",
2000  "You have no %s left.",
2001  bow->race);
2002  return 0;
2003  }
2004  set_owner(arrow, op);
2005  if (arrow->skill)
2006  free_string(arrow->skill);
2007  arrow->skill = add_refcount(bow->skill);
2008 
2009  arrow->direction = dir;
2010  arrow->x = sx;
2011  arrow->y = sy;
2012 
2013  if (op->type == PLAYER) {
2014  op->speed_left = 0.01-(float)FABS(op->speed)*100/bowspeed;
2015  fix_object(op);
2016  }
2017 
2018  SET_ANIMATION(arrow, arrow->direction);
2019  arrow->stats.sp = arrow->stats.wc; /* save original wc and dam */
2020  arrow->stats.hp = arrow->stats.dam;
2021  arrow->stats.grace = arrow->attacktype;
2022  if (arrow->slaying != NULL)
2023  arrow->spellarg = strdup_local(arrow->slaying);
2024 
2025  /* Note that this was different for monsters - they got their level
2026  * added to the damage. I think the strength bonus is more proper.
2027  */
2028 
2029  arrow->stats.dam += (QUERY_FLAG(bow, FLAG_NO_STRENGTH) ? 0 : dam_bonus[op->stats.Str])
2030  +bow->stats.dam
2031  +bow->magic
2032  +arrow->magic;
2033 
2034  /* update the speed */
2035  arrow->speed = (float)((QUERY_FLAG(bow, FLAG_NO_STRENGTH) ? 0 : dam_bonus[op->stats.Str])+bow->magic+arrow->magic)/5.0
2036  +(float)bow->stats.dam/7.0;
2037 
2038  if (arrow->speed < 1.0)
2039  arrow->speed = 1.0;
2040  update_ob_speed(arrow);
2041  arrow->speed_left = 0;
2042 
2043  if (op->type == PLAYER) {
2044  /* we don't want overflows of wc (sint), so cap the value - mod and pl should be substracted */
2045  int mod = bow->magic
2046  +arrow->magic
2047  +dex_bonus[op->stats.Dex]
2048  +thaco_bonus[op->stats.Str]
2049  +arrow->stats.wc
2050  +bow->stats.wc
2051  -wc_mod;
2052  int plmod = (op->chosen_skill ? op->chosen_skill->level : op->level);
2053  if (plmod+mod > 140)
2054  plmod = 140-mod;
2055  else if (plmod+mod < -100)
2056  plmod = -100-mod;
2057  arrow->stats.wc = 20-(sint8)plmod-(sint8)mod;
2058 
2059  arrow->level = op->chosen_skill ? op->chosen_skill->level : op->level;
2060  } else {
2061  arrow->stats.wc = op->stats.wc
2062  -bow->magic
2063  -arrow->magic
2064  -arrow->stats.wc
2065  +wc_mod;
2066 
2067  arrow->level = op->level;
2068  }
2069  if (arrow->attacktype == AT_PHYSICAL)
2070  arrow->attacktype |= bow->attacktype;
2071  if (bow->slaying != NULL)
2072  arrow->slaying = add_string(bow->slaying);
2073 
2074  arrow->map = m;
2075  /* If move_type is ever changed, monster.c:monster_use_bow() needs to be changed too. */
2076  arrow->move_type = MOVE_FLY_LOW;
2077  arrow->move_on = MOVE_FLY_LOW|MOVE_WALK;
2078 
2079  tag = arrow->count;
2080  insert_ob_in_map(arrow, m, op, 0);
2081 
2082  if (!was_destroyed(arrow, tag)) {
2083  play_sound_map(SOUND_TYPE_ITEM, arrow, arrow->direction, "fire");
2084  ob_process(arrow);
2085  }
2086 
2087  return 1;
2088 }
2089 
2106 static int player_fire_bow(object *op, int dir) {
2107  int ret = 0, wcmod = 0;
2108 
2109  if (op->contr->bowtype == bow_bestarrow) {
2110  ret = fire_bow(op, pick_arrow_target(op, op->contr->ranges[range_bow]->race, dir), dir, 0, op->x, op->y);
2111  } else if (op->contr->bowtype >= bow_n && op->contr->bowtype <= bow_nw) {
2112  if (!similar_direction(dir, op->contr->bowtype-bow_n+1))
2113  wcmod = -1;
2114  ret = fire_bow(op, NULL, op->contr->bowtype-bow_n+1, wcmod, op->x, op->y);
2115  } else if (op->contr->bowtype == bow_threewide) {
2116  ret = fire_bow(op, NULL, dir, 0, op->x, op->y);
2117  ret |= fire_bow(op, NULL, dir, -5, op->x+freearr_x[absdir(dir+2)], op->y+freearr_y[absdir(dir+2)]);
2118  ret |= fire_bow(op, NULL, dir, -5, op->x+freearr_x[absdir(dir-2)], op->y+freearr_y[absdir(dir-2)]);
2119  } else if (op->contr->bowtype == bow_spreadshot) {
2120  ret |= fire_bow(op, NULL, dir, 0, op->x, op->y);
2121  ret |= fire_bow(op, NULL, absdir(dir-1), -5, op->x, op->y);
2122  ret |= fire_bow(op, NULL, absdir(dir+1), -5, op->x, op->y);
2123 
2124  } else {
2125  /* Simple case */
2126  ret = fire_bow(op, NULL, dir, 0, op->x, op->y);
2127  }
2128  return ret;
2129 }
2130 
2143 static void fire_misc_object(object *op, int dir) {
2144  object *item;
2145  char name[MAX_BUF];
2146 
2147  if (!op->contr->ranges[range_misc]) {
2149  "You have no range item readied.", NULL);
2150  return;
2151  }
2152 
2153  item = op->contr->ranges[range_misc];
2154  if (!item->inv) {
2155  LOG(llevError, "Object %s lacks a spell\n", item->name);
2156  return;
2157  }
2158  if (item->type == WAND) {
2159  if (item->stats.food <= 0) {
2160  play_sound_player_only(op->contr, SOUND_TYPE_ITEM, item, 0, "poof");
2161  query_base_name(item, 0, name, MAX_BUF);
2163  "The %s goes poof.",
2164  "The %s goes poof.",
2165  name);
2166  return;
2167  }
2168  } else if (item->type == ROD || item->type == HORN) {
2169  if (item->stats.hp < SP_level_spellpoint_cost(item, item->inv, SPELL_HIGHEST)) {
2170  play_sound_player_only(op->contr, SOUND_TYPE_ITEM, item, 0, "poof");
2171  query_base_name(item, 0, name, MAX_BUF);
2172  if (item->type == ROD)
2174  "The %s whines for a while, but nothing happens.",
2175  "The %s whines for a while, but nothing happens.",
2176  name);
2177  else
2179  "The %s needs more time to charge.",
2180  "The %s needs more time to charge.",
2181  name);
2182  return;
2183  }
2184  }
2185 
2186  if (cast_spell(op, item, dir, item->inv, NULL)) {
2187  SET_FLAG(op, FLAG_BEEN_APPLIED); /* You now know something about it */
2188  if (item->type == WAND) {
2189  drain_wand_charge(item);
2190  } else if (item->type == ROD || item->type == HORN) {
2191  drain_rod_charge(item);
2192  }
2193  }
2194 }
2195 
2204 void fire(object *op, int dir) {
2205  int spellcost = 0;
2206 
2207  /* check for loss of invisiblity/hide */
2208  if (action_makes_visible(op))
2209  make_visible(op);
2210 
2211  switch (op->contr->shoottype) {
2212  case range_none:
2213  return;
2214 
2215  case range_bow:
2216  player_fire_bow(op, dir);
2217  return;
2218 
2219  case range_magic: /* Casting spells */
2220  /* BUG? The value in spellcost is never used again it seems. */
2221  spellcost = (cast_spell(op, op, dir, op->contr->ranges[range_magic], op->contr->spellparam[0] ? op->contr->spellparam : NULL));
2222  return;
2223 
2224  case range_misc:
2225  fire_misc_object(op, dir);
2226  return;
2227 
2228  case range_golem: /* Control summoned monsters from scrolls */
2229  if (op->contr->ranges[range_golem] == NULL
2230  || op->contr->golem_count != op->contr->ranges[range_golem]->count) {
2231  op->contr->ranges[range_golem] = NULL;
2232  op->contr->shoottype = range_none;
2233  op->contr->golem_count = 0;
2234  } else
2235  control_golem(op->contr->ranges[range_golem], dir);
2236  return;
2237 
2238  case range_skill:
2239  if (!op->chosen_skill) {
2240  if (op->type == PLAYER)
2242  "You have no applicable skill to use.", NULL);
2243  return;
2244  }
2245  (void)do_skill(op, op, op->chosen_skill, dir, NULL);
2246  return;
2247 
2248  case range_builder:
2249  apply_map_builder(op, dir);
2250  return;
2251 
2252  default:
2254  "Illegal shoot type.", NULL);
2255  return;
2256  }
2257 }
2258 
2278 object *find_key(object *pl, object *container, object *door) {
2279  object *tmp, *key;
2280 
2281  /* Should not happen, but sanity checking is never bad */
2282  if (container->inv == NULL)
2283  return NULL;
2284 
2285  /* First, lets try to find a key in the top level inventory */
2286  for (tmp = container->inv; tmp != NULL; tmp = tmp->below) {
2287  if (door->type == DOOR && tmp->type == KEY)
2288  break;
2289  /* For sanity, we should really check door type, but other stuff
2290  * (like containers) can be locked with special keys
2291  */
2292  if (tmp->slaying
2293  && tmp->type == SPECIAL_KEY
2294  && tmp->slaying == door->slaying)
2295  break;
2296  }
2297  /* No key found - lets search inventories now */
2298  /* If we find and use a key in an inventory, return at that time.
2299  * otherwise, if we search all the inventories and still don't find
2300  * a key, return
2301  */
2302  if (!tmp) {
2303  for (tmp = container->inv; tmp != NULL; tmp = tmp->below) {
2304  /* No reason to search empty containers */
2305  if (tmp->type == CONTAINER && tmp->inv) {
2306  if ((key = find_key(pl, tmp, door)) != NULL)
2307  return key;
2308  }
2309  }
2310  if (!tmp)
2311  return NULL;
2312  }
2313  /* We get down here if we have found a key. Now if its in a container,
2314  * see if we actually want to use it
2315  */
2316  if (pl != container) {
2317  /* Only let players use keys in containers */
2318  if (!pl->contr)
2319  return NULL;
2320  /* cases where this fails:
2321  * If we only search the player inventory, return now since we
2322  * are not in the players inventory.
2323  * If the container is not active, return now since only active
2324  * containers can be used.
2325  * If we only search keyrings and the container does not have
2326  * a race/isn't a keyring.
2327  * No checking for all containers - to fall through past here,
2328  * inv must have been an container and must have been active.
2329  *
2330  * Change the color so that the message doesn't disappear with
2331  * all the others.
2332  */
2333  if (pl->contr->usekeys == key_inventory
2334  || !QUERY_FLAG(container, FLAG_APPLIED)
2335  || (pl->contr->usekeys == keyrings && (!container->race || strcmp(container->race, "keys")))) {
2336  char name_tmp[MAX_BUF], name_cont[MAX_BUF];
2337 
2338  query_name(tmp, name_tmp, MAX_BUF);
2339  query_name(container, name_cont, MAX_BUF);
2342  "The %s in your %s vibrates as you approach the door",
2343  "The %s in your %s vibrates as you approach the door",
2344  name_tmp, name_cont);
2345  return NULL;
2346  }
2347  }
2348  return tmp;
2349 }
2350 
2361 static int player_attack_door(object *op, object *door) {
2362 
2363  /* If its a door, try to find a use a key. If we do destroy the door,
2364  * might as well return immediately as there is nothing more to do -
2365  * otherwise, we fall through to the rest of the code.
2366  */
2367  object *key = find_key(op, op, door);
2368 
2369  /* IF we found a key, do some extra work */
2370  if (key) {
2371  object *container = key->env;
2372 
2373  play_sound_map(SOUND_TYPE_GROUND, door, 0, "open");
2374  if (action_makes_visible(op))
2375  make_visible(op);
2376  if (door->inv && (door->inv->type == RUNE || door->inv->type == TRAP))
2377  spring_trap(door->inv, op);
2378  if (door->type == DOOR) {
2379  hit_player(door, 9998, op, AT_PHYSICAL, 1); /* Break through the door */
2380  } else if (door->type == LOCKED_DOOR) {
2381  char name[HUGE_BUF];
2382 
2383  query_short_name(key, name, HUGE_BUF);
2386  "You open the door with the %s",
2387  "You open the door with the %s",
2388  name);
2389  remove_locked_door(door); /* remove door without violence ;-) */
2390  }
2391  /* Do this after we print the message */
2392  decrease_ob(key); /* Use up one of the keys */
2393  /* Need to update the weight the container the key was in */
2394  if (container != op)
2395  esrv_update_item(UPD_WEIGHT, op, container);
2396  return 1; /* Nothing more to do below */
2397  } else if (door->type == LOCKED_DOOR) {
2398  /* Might as well return now - no other way to open this */
2400  door->msg, door->msg);
2401  return 1;
2402  }
2403  return 0;
2404 }
2405 
2419 void move_player_attack(object *op, int dir) {
2420  object *tmp, *mon, *tpl, *mon_owner;
2421  sint16 nx, ny;
2422  int on_battleground;
2423  mapstruct *m;
2424 
2425  if (op->contr->transport)
2426  tpl = op->contr->transport;
2427  else
2428  tpl = op;
2429  nx = freearr_x[dir]+tpl->x;
2430  ny = freearr_y[dir]+tpl->y;
2431 
2432  on_battleground = op_on_battleground(tpl, NULL, NULL, NULL);
2433 
2434  /* If braced, or can't move to the square, and it is not out of the
2435  * map, attack it. Note order of if statement is important - don't
2436  * want to be calling move_ob if braced, because move_ob will move the
2437  * player. This is a pretty nasty hack, because if we could
2438  * move to some space, it then means that if we are braced, we should
2439  * do nothing at all. As it is, if we are braced, we go through
2440  * quite a bit of processing. However, it probably is less than what
2441  * move_ob uses.
2442  */
2443  if ((op->contr->braced || !move_ob(tpl, dir, tpl)) && !out_of_map(tpl->map, nx, ny)) {
2444  if (OUT_OF_REAL_MAP(tpl->map, nx, ny)) {
2445  m = get_map_from_coord(tpl->map, &nx, &ny);
2446  if (!m)
2447  return; /* Don't think this should happen */
2448  } else
2449  m = tpl->map;
2450 
2451  if ((tmp = GET_MAP_OB(m, nx, ny)) == NULL) {
2452  /* LOG(llevError, "player_move_attack: GET_MAP_OB returns NULL, but player can not more there.\n");*/
2453  return;
2454  }
2455 
2456  mon = NULL;
2457  /* Go through all the objects, and find ones of interest. Only stop if
2458  * we find a monster - that is something we know we want to attack.
2459  * if its a door or barrel (can roll) see if there may be monsters
2460  * on the space
2461  */
2462  while (tmp != NULL) {
2463  if (tmp == op) {
2464  tmp = tmp->above;
2465  continue;
2466  }
2467  if (QUERY_FLAG(tmp, FLAG_ALIVE)) {
2468  mon = tmp;
2469  /* Gros: Objects like (pass-through) doors are alive, but haven't
2470  * their monster flag set - so this is a good way attack real
2471  * monsters in priority.
2472  */
2473  if (QUERY_FLAG(tmp, FLAG_MONSTER))
2474  break;
2475  }
2476  if (tmp->type == LOCKED_DOOR || QUERY_FLAG(tmp, FLAG_CAN_ROLL))
2477  mon = tmp;
2478  tmp = tmp->above;
2479  }
2480 
2481  if (mon == NULL) /* This happens anytime the player tries to move */
2482  return; /* into a wall */
2483 
2484  if (mon->head != NULL)
2485  mon = mon->head;
2486 
2487  if ((mon->type == DOOR && mon->stats.hp >= 0) || (mon->type == LOCKED_DOOR))
2488  if (player_attack_door(op, mon))
2489  return;
2490 
2491  /* The following deals with possibly attacking peaceful
2492  * or frienddly creatures. Basically, all players are considered
2493  * unaggressive. If the moving player has peaceful set, then the
2494  * object should be pushed instead of attacked. It is assumed that
2495  * if you are braced, you will not attack friends accidently,
2496  * and thus will not push them.
2497  */
2498 
2499  /* If the creature is a pet, push it even if the player is not
2500  * peaceful. Our assumption is the creature is a pet if the
2501  * player owns it and it is either friendly or unagressive.
2502  */
2503  mon_owner = get_owner(mon);
2504  if ((op->type == PLAYER)
2505  && (mon_owner == op || (mon_owner != NULL && mon_owner->type == PLAYER && mon_owner->contr->party != NULL && mon_owner->contr->party == op->contr->party))
2506  && (QUERY_FLAG(mon, FLAG_UNAGGRESSIVE) || QUERY_FLAG(mon, FLAG_FRIENDLY))) {
2507  /* If we're braced, we don't want to switch places with it */
2508  if (op->contr->braced)
2509  return;
2510  play_sound_map(SOUND_TYPE_LIVING, mon, dir, "push");
2511  (void)push_ob(mon, dir, op);
2512  if (op->contr->tmp_invis || op->hide)
2513  make_visible(op);
2514  return;
2515  }
2516 
2517  /* in certain circumstances, you shouldn't attack friendly
2518  * creatures. Note that if you are braced, you can't push
2519  * someone, but put it inside this loop so that you won't
2520  * attack them either.
2521  */
2522  if ((mon->type == PLAYER || mon->enemy != op)
2523  && (mon->type == PLAYER || QUERY_FLAG(mon, FLAG_UNAGGRESSIVE) || QUERY_FLAG(mon, FLAG_FRIENDLY))
2524  && (op->contr->peaceful && !on_battleground)) {
2525  if (!op->contr->braced) {
2526  play_sound_map(SOUND_TYPE_LIVING, mon, dir, "push");
2527  (void)push_ob(mon, dir, op);
2528  } else {
2530  "You withhold your attack", NULL);
2531  }
2532  if (op->contr->tmp_invis || op->hide)
2533  make_visible(op);
2534  }
2535 
2536  /* If the object is a boulder or other rollable object, then
2537  * roll it if not braced. You can't roll it if you are braced.
2538  */
2539  else if (QUERY_FLAG(mon, FLAG_CAN_ROLL) && (!op->contr->braced)) {
2540  recursive_roll(mon, dir, op);
2541  if (action_makes_visible(op))
2542  make_visible(op);
2543 
2544  /* Any generic living creature. Including things like doors.
2545  * Way it works is like this: First, it must have some hit points
2546  * and be living. Then, it must be one of the following:
2547  * 1) Not a player, 2) A player, but of a different party. Note
2548  * that party_number -1 is no party, so attacks can still happen.
2549  */
2550 
2551  } else if ((mon->stats.hp >= 0)
2552  && QUERY_FLAG(mon, FLAG_ALIVE)
2553  && ((mon->type != PLAYER || op->contr->party == NULL || op->contr->party != mon->contr->party))) {
2554  /* If the player hasn't hit something this tick, and does
2555  * so, give them speed boost based on weapon speed. Doing
2556  * it here is better than process_players2, which basically
2557  * incurred a 1 tick offset.
2558  */
2559  if (!op->contr->has_hit) {
2560  op->speed_left += op->speed / op->contr->weapon_sp;
2561 
2562  op->contr->has_hit = 1; /* The last action was to hit, so use weapon_sp */
2563  }
2564 
2565  skill_attack(mon, op, 0, NULL, NULL);
2566 
2567  /* If attacking another player, that player gets automatic
2568  * hitback, and doesn't loose luck either.
2569  * Disable hitback on the battleground or if the target is
2570  * the wiz.
2571  */
2572  if (mon->type == PLAYER
2573  && mon->stats.hp >= 0
2574  && !mon->contr->has_hit
2575  && !on_battleground
2576  && !QUERY_FLAG(mon, FLAG_WIZ)) {
2577  short luck = mon->stats.luck;
2578  mon->contr->has_hit = 1;
2579  skill_attack(op, mon, 0, NULL, NULL);
2580  mon->stats.luck = luck;
2581  }
2582  if (action_makes_visible(op))
2583  make_visible(op);
2584  }
2585  } /* if player should attack something */
2586 }
2587 
2594 static void update_transport_block(object *transport, int dir) {
2595  object *part;
2596  int sx, sy, x, y;
2597 
2598  get_multi_size(transport, &sx, &sy, NULL, NULL);
2599  assert(sx == sy);
2600 
2601  if (dir == 1 || dir == 5) {
2602  part = transport;
2603  for (y = 0; y <= sy; y++) {
2604  for (x = 0; x < sx; x++) {
2605  part->move_type = transport->move_type;
2606  part = part->more;
2607  }
2608  part->move_type = 0;
2609  part = part->more;
2610  }
2611  } else if (dir == 3 || dir == 7) {
2612  part = transport;
2613  for (y = 0; y < sy; y++) {
2614  for (x = 0; x <= sx; x++) {
2615  part->move_type = transport->move_type;
2616  part = part->more;
2617  }
2618  }
2619  while (part) {
2620  part->move_type = 0;
2621  part = part->more;
2622  }
2623  } else {
2624  for (part = transport; part; part = part->more) {
2625  part->move_type = transport->move_type;
2626  }
2627  }
2628 }
2629 
2639 static int turn_one_transport(object *transport, object *captain, int dir) {
2640  int x, y, scroll_dir = 0;
2641 
2642  assert(transport->type == TRANSPORT);
2643 
2644  x = transport->x;
2645  y = transport->y;
2646 
2647  if (transport->direction == 1 && dir == 8) {
2648  x--;
2649  } else if (transport->direction == 2 && dir == 3) {
2650  y++;
2651  } else if (transport->direction == 3 && dir == 2) {
2652  y--;
2653  } else if (transport->direction == 5 && dir == 6) {
2654  x--;
2655  } else if (transport->direction == 6 && dir == 5) {
2656  x++;
2657  } else if (transport->direction == 7 && dir == 8) {
2658  y--;
2659  } else if (transport->direction == 8 && dir == 7) {
2660  y++;
2661  } else if (transport->direction == 8 && dir == 1) {
2662  x++;
2663  }
2664 
2665  update_transport_block(transport, dir);
2666  remove_ob(transport);
2667  if (ob_blocked(transport, transport->map, x, y)) {
2668  update_transport_block(transport, transport->direction);
2669  insert_ob_in_map(transport, transport->map, NULL, 0);
2670  return 2;
2671  }
2672 
2673  if (x != transport->x || y != transport->y) {
2674  object *pl;
2675 
2676 /* assert(scroll_dir != 0);*/
2677 
2678  for (pl = transport->inv; pl; pl = pl->below) {
2679  if (pl->type == PLAYER) {
2680  pl->contr->do_los = 1;
2681  pl->map = transport->map;
2682  pl->x = x;
2683  pl->y = y;
2684  esrv_map_scroll(&pl->contr->socket, freearr_x[scroll_dir], freearr_y[scroll_dir]);
2685  pl->contr->socket.update_look = 1;
2686  pl->contr->socket.look_position = 0;
2687  }
2688  }
2689  }
2690 
2691  insert_ob_in_map_at(transport, transport->map, NULL, 0, x, y);
2692  transport->direction = dir;
2693  transport->facing = dir;
2694  animate_object(transport, dir);
2695  captain->direction = dir;
2696  return 1;
2697 }
2698 
2711 static int turn_transport(object *transport, object *captain, int dir) {
2712  assert(transport->type == TRANSPORT);
2713 
2714  if (get_ob_key_value(transport, "turnable_transport") == NULL) {
2715  transport->direction = dir;
2716  transport->facing = dir;
2717  animate_object(transport, dir);
2718  captain->direction = dir;
2719  return 0;
2720  }
2721 
2722  if (transport->direction == dir)
2723  return 0;
2724 
2725  if (absdir(transport->direction-dir) > 2)
2726  return turn_one_transport(transport, captain, absdir(transport->direction+1));
2727  else
2728  return turn_one_transport(transport, captain, absdir(transport->direction-1));
2729 }
2730 
2741 int move_player(object *op, int dir) {
2742  int pick;
2743  object *transport = op->contr->transport;
2744 
2745  if (!transport && (op->map == NULL || op->map->in_memory != MAP_IN_MEMORY))
2746  return 0;
2747 
2748  /* Sanity check: make sure dir is valid */
2749  if ((dir < 0) || (dir >= 9)) {
2750  LOG(llevError, "move_player: invalid direction %d\n", dir);
2751  return 0;
2752  }
2753 
2754  /* peterm: added following line */
2755  if (QUERY_FLAG(op, FLAG_CONFUSED) && dir)
2756  dir = absdir(dir+RANDOM()%3+RANDOM()%3-2);
2757 
2758  op->facing = dir;
2759 
2760  if (!transport && op->hide)
2761  do_hidden_move(op);
2762 
2763  if (transport) {
2764  int turn;
2765 
2766  /* transport->contr is set up for the person in charge of the boat.
2767  * if that isn't this person, he can't steer it, etc
2768  */
2769  if (transport->contr != op->contr)
2770  return 0;
2771 
2772  /* Transport can't move. But update dir so it at least
2773  * will point in the same direction if player is running.
2774  */
2775  if (transport->speed_left < 0.0) {
2776  return 0;
2777  }
2778  /* Remove transport speed. Give player just a little speed -
2779  * enough so that they will get an action again quickly.
2780  */
2781  transport->speed_left -= 1.0;
2782  if (op->speed_left < 0.0)
2783  op->speed_left = -0.01;
2784 
2785  turn = turn_transport(transport, op, dir);
2786  if (turn != 0)
2787  return 0;
2788  } else {
2789  /* it is important to change the animation now, as fire or move_player_attack can start a compound animation,
2790  * and leave us with state = 0, which we don't want to change again. */
2791  op->state++; /* player moved, so change animation. */
2792  animate_object(op, op->facing);
2793  }
2794 
2795  if (op->contr->fire_on) {
2796  fire(op, dir);
2797  } else
2798  move_player_attack(op, dir);
2799 
2800  pick = check_pick(op);
2801 
2802 
2803  /* Add special check for newcs players and fire on - this way, the
2804  * server can handle repeat firing.
2805  */
2806  if (op->contr->fire_on || (op->contr->run_on && pick != 0)) {
2807  op->direction = dir;
2808  } else {
2809  op->direction = 0;
2810  }
2811  return 0;
2812 }
2813 
2826 int handle_newcs_player(object *op) {
2827  if (op->contr->hidden) {
2828  op->invisible = 1000;
2829  /* the socket code flasehs the player visible/invisible
2830  * depending on the value if invisible, so we need to
2831  * alternate it here for it to work correctly.
2832  */
2833  if (pticks&2)
2834  op->invisible--;
2835  } else if (op->invisible && !(QUERY_FLAG(op, FLAG_MAKE_INVIS))) {
2836  op->invisible--;
2837  if (!op->invisible) {
2838  make_visible(op);
2840  "Your invisibility spell runs out.", NULL);
2841  }
2842  }
2843 
2844  if (QUERY_FLAG(op, FLAG_SCARED)) {
2845  flee_player(op);
2846  /* If player is still scared, that is his action for this tick */
2847  if (QUERY_FLAG(op, FLAG_SCARED)) {
2848  op->speed_left--;
2849  return 0;
2850  }
2851  }
2852 
2853  /* I've been seeing crashes where the golem has been destroyed, but
2854  * the player object still points to the defunct golem. The code that
2855  * destroys the golem looks correct, and it doesn't always happen, so
2856  * put this in a a workaround to clean up the golem pointer.
2857  */
2858  if (op->contr->ranges[range_golem]
2860  op->contr->ranges[range_golem] = NULL;
2861  op->contr->golem_count = 0;
2862  }
2863 
2864  /* call this here - we also will call this in do_ericserver, but
2865  * the players time has been increased when doericserver has been
2866  * called, so we recheck it here.
2867  */
2868  handle_client(&op->contr->socket, op->contr);
2869  if (op->speed_left < 0)
2870  return 0;
2871 
2872  if (op->direction && (op->contr->run_on || op->contr->fire_on)) {
2873  /* All move commands take 1 tick, at least for now */
2874  op->speed_left--;
2875 
2876  /* Instead of all the stuff below, let move_player take care
2877  * of it. Also, some of the skill stuff is only put in
2878  * there, as well as the confusion stuff.
2879  */
2880  move_player(op, op->direction);
2881  if (op->speed_left > 0)
2882  return 1;
2883  else
2884  return 0;
2885  }
2886  return 0;
2887 }
2888 
2899 static int save_life(object *op) {
2900  object *tmp;
2901 
2902  if (!QUERY_FLAG(op, FLAG_LIFESAVE))
2903  return 0;
2904 
2905  for (tmp = op->inv; tmp != NULL; tmp = tmp->below)
2906  if (QUERY_FLAG(tmp, FLAG_APPLIED) && QUERY_FLAG(tmp, FLAG_LIFESAVE)) {
2907  char name[MAX_BUF];
2908 
2909  query_name(tmp, name, MAX_BUF);
2910  play_sound_map(SOUND_TYPE_ITEM, tmp, 0, "evaporate");
2912  "Your %s vibrates violently, then evaporates.",
2913  "Your %s vibrates violently, then evaporates.",
2914  name);
2915  remove_ob(tmp);
2916  free_object(tmp);
2918  if (op->stats.hp < 0)
2919  op->stats.hp = op->stats.maxhp;
2920  if (op->stats.food < 0)
2921  op->stats.food = 999;
2922  fix_object(op);
2923  return 1;
2924  }
2925  LOG(llevError, "Error: LIFESAVE set without applied object.\n");
2927  enter_player_savebed(op); /* bring him home. */
2928  return 0;
2929 }
2930 
2943 void remove_unpaid_objects(object *op, object *env, int free_items) {
2944  object *next;
2945 
2946  while (op) {
2947  next = op->below; /* Make sure we have a good value, in case
2948  * we remove object 'op'
2949  */
2950  if (QUERY_FLAG(op, FLAG_UNPAID)) {
2951  remove_ob(op);
2952  if (free_items)
2953  free_object(op);
2954  else {
2955  op->x = env->x;
2956  op->y = env->y;
2957  insert_ob_in_map(op, env->map, NULL, 0);
2958  }
2959  } else if (op->inv)
2960  remove_unpaid_objects(op->inv, env, free_items);
2961  op = next;
2962  }
2963 }
2964 
2982 static const char *gravestone_text(object *op, char *buf2, int len) {
2983  char buf[MAX_BUF];
2984  time_t now = time(NULL);
2985 
2986  strncpy(buf2, " R.I.P.\n\n", len);
2987  if (op->type == PLAYER)
2988  snprintf(buf, sizeof(buf), "%s the %s\n", op->name, op->contr->title);
2989  else
2990  snprintf(buf, sizeof(buf), "%s\n", op->name);
2991  strncat(buf2, " ", 20-strlen(buf)/2);
2992  strncat(buf2, buf, len-strlen(buf2)-1);
2993  if (op->type == PLAYER)
2994  snprintf(buf, sizeof(buf), "who was in level %d when killed\n", op->level);
2995  else
2996  snprintf(buf, sizeof(buf), "who was in level %d when died.\n\n", op->level);
2997  strncat(buf2, " ", 20-strlen(buf)/2);
2998  strncat(buf2, buf, len-strlen(buf2)-1);
2999  if (op->type == PLAYER) {
3000  snprintf(buf, sizeof(buf), "by %s.\n\n", op->contr->killer);
3001  strncat(buf2, " ", 21-strlen(buf)/2);
3002  strncat(buf2, buf, len-strlen(buf2)-1);
3003  }
3004  strftime(buf, MAX_BUF, "%b %d %Y\n", localtime(&now));
3005  strncat(buf2, " ", 20-strlen(buf)/2);
3006  strncat(buf2, buf, len-strlen(buf2)-1);
3007  return buf2;
3008 }
3009 
3017 void do_some_living(object *op) {
3018  int last_food = op->stats.food;
3019  int gen_hp, gen_sp, gen_grace;
3020  int over_hp, over_sp, over_grace;
3021  int i;
3022  int rate_hp = 1200;
3023  int rate_sp = 2500;
3024  int rate_grace = 2000;
3025  const int max_hp = 1;
3026  const int max_sp = 1;
3027  const int max_grace = 1;
3028 
3029  if (op->contr->outputs_sync) {
3030  for (i = 0; i < NUM_OUTPUT_BUFS; i++)
3031  if (op->contr->outputs[i].buf != NULL
3032  && (op->contr->outputs[i].first_update+op->contr->outputs_sync) < pticks)
3033  flush_output_element(op, &op->contr->outputs[i]);
3034  }
3035 
3036  if (op->contr->state == ST_PLAYING) {
3037  /* these next three if clauses make it possible to SLOW DOWN
3038  hp/grace/spellpoint regeneration. */
3039  if (op->contr->gen_hp >= 0)
3040  gen_hp = (op->contr->gen_hp+1)*op->stats.maxhp;
3041  else {
3042  gen_hp = op->stats.maxhp;
3043  rate_hp -= rate_hp/2*op->contr->gen_hp;
3044  }
3045  if (op->contr->gen_sp >= 0)
3046  gen_sp = (op->contr->gen_sp+1)*op->stats.maxsp;
3047  else {
3048  gen_sp = op->stats.maxsp;
3049  rate_sp -= rate_sp/2*op->contr->gen_sp;
3050  }
3051  if (op->contr->gen_grace >= 0)
3052  gen_grace = (op->contr->gen_grace+1)*op->stats.maxgrace;
3053  else {
3054  gen_grace = op->stats.maxgrace;
3055  rate_grace -= rate_grace/2*op->contr->gen_grace;
3056  }
3057 
3058  /* Regenerate Spell Points */
3059  if (op->contr->ranges[range_golem] == NULL && --op->last_sp < 0) {
3060  gen_sp = gen_sp*10/MAX(op->contr->gen_sp_armour, 10);
3061  if (op->stats.sp < op->stats.maxsp) {
3062  op->stats.sp++;
3063  /* dms do not consume food */
3064  if (!QUERY_FLAG(op, FLAG_WIZ)) {
3065  op->stats.food--;
3066  if (op->contr->digestion < 0)
3067  op->stats.food += op->contr->digestion;
3068  else if (op->contr->digestion > 0
3069  && random_roll(0, op->contr->digestion, op, PREFER_HIGH))
3070  op->stats.food = last_food;
3071  }
3072  }
3073  if (max_sp > 1) {
3074  over_sp = (gen_sp+10)/rate_sp;
3075  if (over_sp > 0) {
3076  if (op->stats.sp < op->stats.maxsp) {
3077  op->stats.sp += MIN(over_sp, max_sp);
3078  if (random_roll(0, rate_sp-1, op, PREFER_LOW) > ((gen_sp+10)%rate_sp))
3079  op->stats.sp--;
3080  if (op->stats.sp > op->stats.maxsp)
3081  op->stats.sp = op->stats.maxsp;
3082  }
3083  op->last_sp = 0;
3084  } else {
3085  op->last_sp = rate_sp/(MAX(gen_sp, 20)+10);
3086  }
3087  } else {
3088  op->last_sp = rate_sp/(MAX(gen_sp, 20)+10);
3089  }
3090  }
3091 
3092  /* Regenerate Grace */
3093  /* I altered this a little - maximum grace is ony achieved through prayer -b.t.*/
3094  if (--op->last_grace < 0) {
3095  if (op->stats.grace < op->stats.maxgrace/2)
3096  op->stats.grace++; /* no penalty in food for regaining grace */
3097  if (max_grace > 1) {
3098  over_grace = (MAX(gen_grace, 20)+10)/rate_grace;
3099  if (over_grace > 0) {
3100  op->stats.sp += over_grace+(random_roll(0, rate_grace-1, op, PREFER_HIGH) > ((MAX(gen_grace, 20)+10)%rate_grace)) ? -1 : 0;
3101  op->last_grace = 0;
3102  } else {
3103  op->last_grace = rate_grace/(MAX(gen_grace, 20)+10);
3104  }
3105  } else {
3106  op->last_grace = rate_grace/(MAX(gen_grace, 20)+10);
3107  }
3108  /* wearing stuff doesn't detract from grace generation. */
3109  }
3110 
3111  /* Regenerate Hit Points (unless you are a wraith player) */
3112  if (--op->last_heal < 0 && !is_wraith_pl(op)) {
3113  if (op->stats.hp < op->stats.maxhp) {
3114  op->stats.hp++;
3115  /* dms do not consume food */
3116  if (!QUERY_FLAG(op, FLAG_WIZ)) {
3117  op->stats.food--;
3118  if (op->contr->digestion < 0)
3119  op->stats.food += op->contr->digestion;
3120  else if (op->contr->digestion > 0
3121  && random_roll(0, op->contr->digestion, op, PREFER_HIGH))
3122  op->stats.food = last_food;
3123  }
3124  }
3125  if (max_hp > 1 && !is_wraith_pl(op)) {
3126  over_hp = (MAX(gen_hp, 20)+10)/rate_hp;
3127  if (over_hp > 0) {
3128  op->stats.sp += over_hp+(RANDOM()%rate_hp > ((MAX(gen_hp, 20)+10)%rate_hp)) ? -1 : 0;
3129  op->last_heal = 0;
3130  } else {
3131  op->last_heal = rate_hp/(MAX(gen_hp, 20)+10);
3132  }
3133  } else {
3134  op->last_heal = rate_hp/(MAX(gen_hp, 20)+10);
3135  }
3136  }
3137 
3138  /* Digestion */
3139  if (--op->last_eat < 0) {
3140  int bonus = MAX(op->contr->digestion, 0);
3141  int penalty = MAX(-op->contr->digestion, 0);
3142  if (op->contr->gen_hp > 0)
3143  op->last_eat = 25*(1+bonus)/(op->contr->gen_hp+penalty+1);
3144  else
3145  op->last_eat = 25*(1+bonus)/(penalty+1);
3146  /* dms do not consume food */
3147  if (!QUERY_FLAG(op, FLAG_WIZ))
3148  op->stats.food--;
3149  }
3150  }
3151 
3152  if (op->contr->state == ST_PLAYING && op->stats.food < 0 && op->stats.hp >= 0) {
3153  if (is_wraith_pl(op))
3154  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ITEM, MSG_TYPE_ITEM_REMOVE, "You feel a hunger for living flesh.", NULL);
3155  else {
3156  object *tmp, *flesh = NULL;
3157 
3158  for (tmp = op->inv; tmp != NULL; tmp = tmp->below) {
3159  if (!QUERY_FLAG(tmp, FLAG_UNPAID)) {
3160  if (tmp->type == FOOD || tmp->type == DRINK || tmp->type == POISON) {
3162  "You blindly grab for a bite of food.", NULL);
3163  manual_apply(op, tmp, 0);
3164  if (op->stats.food >= 0 || op->stats.hp < 0)
3165  break;
3166  } else if (tmp->type == FLESH)
3167  flesh = tmp;
3168  } /* End if paid for object */
3169  } /* end of for loop */
3170  /* If player is still starving, it means they don't have any food, so
3171  * eat flesh instead.
3172  */
3173  if (op->stats.food < 0 && op->stats.hp >= 0 && flesh) {
3175  "You blindly grab for a bite of food.", NULL);
3176  manual_apply(op, flesh, 0);
3177  }
3178  } /* end not wraith */
3179  } /* end if player is starving */
3180 
3181  while (op->stats.food < 0 && op->stats.hp > 0)
3182  op->stats.food++,
3183  op->stats.hp--;
3184 
3185  if (!op->contr->state && !QUERY_FLAG(op, FLAG_WIZ) && (op->stats.hp < 0 || op->stats.food < 0))
3186  kill_player(op);
3187 }
3188 
3195 static void loot_object(object *op) {
3196  object *tmp, *tmp2, *next;
3197 
3198  if (op->container) { /* close open sack first */
3199  apply_container(op, op->container);
3200  }
3201 
3202  for (tmp = op->inv; tmp != NULL; tmp = next) {
3203  next = tmp->below;
3204  if (tmp->type == EXPERIENCE || tmp->invisible)
3205  continue;
3206  remove_ob(tmp);
3207  tmp->x = op->x,
3208  tmp->y = op->y;
3209  if (tmp->type == CONTAINER) { /* empty container to ground */
3210  loot_object(tmp);
3211  }
3212  if (!QUERY_FLAG(tmp, FLAG_UNIQUE)
3213  && (QUERY_FLAG(tmp, FLAG_STARTEQUIP) || QUERY_FLAG(tmp, FLAG_NO_DROP) || !(RANDOM()%3))) {
3214  if (tmp->nrof > 1) {
3215  tmp2 = get_split_ob(tmp, 1+RANDOM()%(tmp->nrof-1), NULL, 0);
3216  free_object(tmp2);
3217  insert_ob_in_map(tmp, op->map, NULL, 0);
3218  } else
3219  free_object(tmp);
3220  } else
3221  insert_ob_in_map(tmp, op->map, NULL, 0);
3222  }
3223 }
3224 
3238 void kill_player(object *op) {
3239  char buf[MAX_BUF];
3240  int x, y, i;
3241  mapstruct *map; /* this is for resurrection */
3242  int z;
3243  int num_stats_lose;
3244  int lost_a_stat;
3245  int lose_this_stat;
3246  int this_stat;
3247  int will_kill_again;
3248  archetype *at;
3249  object *tmp;
3250  archetype *trophy;
3251 
3252  if (save_life(op))
3253  return;
3254 
3255  /* If player dies on BATTLEGROUND, no stat/exp loss! For Combat-Arenas
3256  * in cities ONLY!!! It is very important that this doesn't get abused.
3257  * Look at op_on_battleground() for more info --AndreasV
3258  */
3259  if (op_on_battleground(op, &x, &y, &trophy)) {
3261  "You have been defeated in combat!\n"
3262  "Local medics have saved your life...",
3263  NULL);
3264 
3265  /* restore player */
3266  at = find_archetype("poisoning");
3267  tmp = present_arch_in_ob(at, op);
3268  if (tmp) {
3269  remove_ob(tmp);
3270  free_object(tmp);
3272  "Your body feels cleansed", NULL);
3273  }
3274 
3275  at = find_archetype("confusion");
3276  tmp = present_arch_in_ob(at, op);
3277  if (tmp) {
3278  remove_ob(tmp);
3279  free_object(tmp);
3281  "Your mind feels clearer", NULL);
3282  }
3283 
3284  cure_disease(op, NULL); /* remove any disease */
3285  op->stats.hp = op->stats.maxhp;
3286  if (op->stats.food <= 0)
3287  op->stats.food = 999;
3288 
3289  /* create a bodypart-trophy to make the winner happy */
3290  tmp = arch_to_object(trophy);
3291  if (tmp != NULL) {
3292  snprintf(buf, sizeof(buf), "%s's %s", op->name, tmp->name);
3293  tmp->name = add_string(buf);
3294  if (tmp->type == FLESH)
3295  snprintf(buf, sizeof(buf), " This %s has been cut off %s\n"
3296  " the %s, when he was defeated at\n"
3297  " level %d by %s.\n",
3298  tmp->name, op->name, op->contr->title,
3299  (int)(op->level), op->contr->killer);
3300  else
3301  snprintf(buf, sizeof(buf), " This %s has been taken from %s\n"
3302  " the %s, when he was defeated at\n"
3303  " level %d by %s.\n",
3304  tmp->name, op->name, op->contr->title,
3305  (int)(op->level), op->contr->killer);
3306  tmp->msg = add_string(buf);
3307  tmp->type = 0;
3308  tmp->value = 0;
3309  tmp->material = 0;
3310  tmp->materialname = NULL;
3311  tmp->x = op->x,
3312  tmp->y = op->y;
3313  insert_ob_in_map(tmp, op->map, op, 0);
3314  }
3315 
3316  /* teleport defeated player to new destination*/
3317  transfer_ob(op, x, y, 0, NULL);
3318  op->contr->braced = 0;
3319  return;
3320  }
3321 
3322  /* Lauwenmark: Handle for plugin death event */
3323  if (execute_event(op, EVENT_DEATH, NULL, NULL, NULL, SCRIPT_FIX_ALL) != 0)
3324  return;
3325 
3326  /* Lauwenmark: Handle for the global death event */
3328  if (op->stats.food < 0) {
3329  if (op->contr->explore) {
3330  draw_ext_info(NDI_UNIQUE, 0, op,
3332  "You would have starved, but you are "
3333  "in explore mode, so...", NULL);
3334  op->stats.food = 999;
3335  return;
3336  }
3337  snprintf(buf, sizeof(buf), "%s starved to death.", op->name);
3338  strcpy(op->contr->killer, "starvation");
3339  } else {
3340  if (op->contr->explore) {
3341  draw_ext_info(NDI_UNIQUE, 0, op,
3343  "You would have died, but you are "
3344  "in explore mode, so...", NULL);
3345  op->stats.hp = op->stats.maxhp;
3346  return;
3347  }
3348  snprintf(buf, sizeof(buf), "%s died.", op->name);
3349  }
3350  play_sound_player_only(op->contr, SOUND_TYPE_LIVING, op, 0, "death");
3351 
3352  /* save the map location for corpse, gravestone*/
3353  x = op->x;
3354  y = op->y;
3355  map = op->map;
3356 
3357  if (settings.not_permadeth == TRUE) {
3358  /* NOT_PERMADEATH code. This basically brings the character back to
3359  * life if they are dead - it takes some exp and a random stat.
3360  * See the config.h file for a little more in depth detail about this.
3361  */
3362 
3363  /* Basically two ways to go - remove a stat permanently, or just
3364  * make it depletion. This bunch of code deals with that aspect
3365  * of death.
3366  */
3367 
3369  /* If stat loss is permanent, lose one stat only. */
3370  /* Lower level chars don't lose as many stats because they suffer
3371  more if they do. */
3372  /* Higher level characters can afford things such as potions of
3373  restoration, or better, stat potions. So we slug them that
3374  little bit harder. */
3375  /* GD */
3377  num_stats_lose = 1;
3378  else
3379  num_stats_lose = 1+op->level/BALSL_NUMBER_LOSSES_RATIO;
3380  } else {
3381  num_stats_lose = 1;
3382  }
3383  lost_a_stat = 0;
3384 
3385  for (z = 0; z < num_stats_lose; z++) {
3387  /* Pick a random stat and take a point off it. Tell the player
3388  * what he lost.
3389  */
3390  i = RANDOM()%7;
3391  change_attr_value(&(op->stats), i, -1);
3392  check_stat_bounds(&(op->stats));
3393  change_attr_value(&(op->contr->orig_stats), i, -1);
3395  draw_ext_info(NDI_UNIQUE, 0, op,
3397  lose_msg[i], lose_msg[i]);
3398  lost_a_stat = 1;
3399  } else {
3400  /* deplete a stat */
3401  archetype *deparch = find_archetype("depletion");
3402  object *dep;
3403 
3404  i = RANDOM()%7;
3405  dep = present_arch_in_ob(deparch, op);
3406  if (!dep) {
3407  dep = arch_to_object(deparch);
3408  insert_ob_in_ob(dep, op);
3409  }
3410  lose_this_stat = 1;
3412  /* GD */
3413  /* Get the stat that we're about to deplete. */
3414  this_stat = get_attr_value(&(dep->stats), i);
3415  if (this_stat < 0) {
3416  int loss_chance = 1+op->level/BALSL_LOSS_CHANCE_RATIO;
3417  int keep_chance = this_stat*this_stat;
3418  /* Yes, I am paranoid. Sue me. */
3419  if (keep_chance < 1)
3420  keep_chance = 1;
3421 
3422  /* There is a maximum depletion total per level. */
3423  if (this_stat < -1-op->level/BALSL_MAX_LOSS_RATIO) {
3424  lose_this_stat = 0;
3425  /* Take loss chance vs keep chance to see if we
3426  retain the stat. */
3427  } else {
3428  if (random_roll(0, loss_chance+keep_chance-1, op, PREFER_LOW) < keep_chance)
3429  lose_this_stat = 0;
3430  /* LOG(llevDebug, "Determining stat loss. Stat: %d Keep: %d Lose: %d Result: %s.\n", this_stat, keep_chance, loss_chance, lose_this_stat ? "LOSE" : "KEEP"); */
3431  }
3432  }
3433  }
3434 
3435  if (lose_this_stat) {
3436  this_stat = get_attr_value(&(dep->stats), i);
3437  /* We could try to do something clever like find another
3438  * stat to reduce if this fails. But chances are, if
3439  * stats have been depleted to -50, all are pretty low
3440  * and should be roughly the same, so it shouldn't make a
3441  * difference.
3442  */
3443  if (this_stat >= -50) {
3444  change_attr_value(&(dep->stats), i, -1);
3445  SET_FLAG(dep, FLAG_APPLIED);
3447  lose_msg[i], lose_msg[i]);
3448  fix_object(op);
3449  lost_a_stat = 1;
3450  }
3451  }
3452  }
3453  }
3454  /* If no stat lost, tell the player. */
3455  if (!lost_a_stat) {
3456  /* determine_god() seems to not work sometimes... why is this? Should I be using something else? GD */
3457  const char *god = determine_god(op);
3458 
3459  if (god && (strcmp(god, "none")))
3462  "For a brief moment you feel the holy presence of %s protecting you",
3463  "For a brief moment you feel the holy presence of %s protecting you",
3464  god);
3465  else
3466  draw_ext_info(NDI_UNIQUE, 0, op,
3468  "For a brief moment you feel a holy presence protecting you.",
3469  NULL);
3470  }
3471 
3472  /* Put a gravestone up where the character 'almost' died. List the
3473  * exp loss on the stone.
3474  */
3475  tmp = arch_to_object(find_archetype("gravestone"));
3476  snprintf(buf, sizeof(buf), "%s's gravestone", op->name);
3477  FREE_AND_COPY(tmp->name, buf);
3478  snprintf(buf, sizeof(buf), "%s's gravestones", op->name);
3479  FREE_AND_COPY(tmp->name_pl, buf);
3480  snprintf(buf, sizeof(buf), "RIP\nHere rests the hero %s the %s,\n"
3481  "who was killed\n"
3482  "by %s.\n",
3483  op->name, op->contr->title,
3484  op->contr->killer);
3485  tmp->msg = add_string(buf);
3486  tmp->x = op->x,
3487  tmp->y = op->y;
3488  insert_ob_in_map(tmp, op->map, NULL, 0);
3489 
3490  /* restore player: remove any poisoning, disease and confusion the
3491  * character may be suffering.*/
3492  at = find_archetype("poisoning");
3493  tmp = present_arch_in_ob(at, op);
3494  if (tmp) {
3495  remove_ob(tmp);
3496  free_object(tmp);
3498  "Your body feels cleansed", NULL);
3499  }
3500 
3501  at = find_archetype("confusion");
3502  tmp = present_arch_in_ob(at, op);
3503  if (tmp) {
3504  remove_ob(tmp);
3505  free_object(tmp);
3507  "Your mind feels clearer", NULL);
3508  }
3509  cure_disease(op, NULL); /* remove any disease */
3510 
3511  /* Subtract the experience points, if we died cause of food, give
3512  * us food, and reset HP's...
3513  */
3515  if (op->stats.food < 100)
3516  op->stats.food = 900;
3517  op->stats.hp = op->stats.maxhp;
3518  op->stats.sp = MAX(op->stats.sp, op->stats.maxsp);
3519  op->stats.grace = MAX(op->stats.grace, op->stats.maxgrace);
3520 
3521  /* Check to see if the player is in a shop. IF so, then check to see if
3522  * the player has any unpaid items. If so, remove them and put them back
3523  * in the map.
3524  *
3525  * If they are not in a shop, just free the unpaid items instead of
3526  * putting them back on map.
3527  */
3528  if (is_in_shop(op))
3529  remove_unpaid_objects(op->inv, op, 0);
3530  else
3531  remove_unpaid_objects(op->inv, op, 1);
3532 
3533  /* Move player to his current respawn-position (usually last savebed) */
3535 
3536  /* Save the player before inserting the force to reduce chance of abuse. */
3537  op->contr->braced = 0;
3538  save_player(op, 1);
3539 
3540  /* it is possible that the player has blown something up
3541  * at his savebed location, and that can have long lasting
3542  * spell effects. So first see if there is a spell effect
3543  * on the space that might harm the player.
3544  */
3545  will_kill_again = 0;
3546  for (tmp = GET_MAP_OB(op->map, op->x, op->y); tmp; tmp = tmp->above) {
3547  if (tmp->type == SPELL_EFFECT)
3548  will_kill_again |= tmp->attacktype;
3549  }
3550  if (will_kill_again) {
3551  object *force;
3552  int at;
3553 
3554  force = create_archetype(FORCE_NAME);
3555  /* 50 ticks should be enough time for the spell to abate */
3556  force->speed = 0.1;
3557  force->speed_left = -5.0;
3558  SET_FLAG(force, FLAG_APPLIED);
3559  for (at = 0; at < NROFATTACKS; at++) {
3560  if (will_kill_again&(1<<at))
3561  force->resist[at] = 100;
3562  }
3563  insert_ob_in_ob(force, op);
3564  fix_object(op);
3565  }
3566 
3567  /* Tell the player they have died */
3569  "YOU HAVE DIED.", NULL);
3570  return;
3571  } /* NOT_PERMADETH */
3572  else {
3573  /* If NOT_PERMADETH is set, then the rest of this is not reachable. This
3574  * should probably be embedded in an else statement.
3575  */
3576 
3577  op->contr->party = NULL;
3578  if (settings.set_title == TRUE)
3579  op->contr->own_title[0] = '\0';
3580 
3581  /* buf should be the kill message */
3583  buf, buf);
3584  check_score(op, 0);
3585  if (op->contr->ranges[range_golem] != NULL) {
3589  op->contr->ranges[range_golem] = NULL;
3590  op->contr->golem_count = 0;
3591  }
3592  loot_object(op); /* Remove some of the items for good */
3593  remove_ob(op);
3594  op->direction = 0;
3595 
3596  if (!QUERY_FLAG(op, FLAG_WAS_WIZ) && op->stats.exp) {
3597  if (settings.resurrection == TRUE) {
3598  /* save playerfile sans equipment when player dies
3599  * -then save it as player.pl.dead so that future resurrection
3600  * -type spells will work on them nicely
3601  */
3602  op->stats.hp = op->stats.maxhp;
3603  op->stats.food = 999;
3604 
3605  /* set the location of where the person will reappear when */
3606  /* maybe resurrection code should fix map also */
3607  strcpy(op->contr->maplevel, settings.emergency_mapname);
3608  if (op->map != NULL)
3609  op->map = NULL;
3610  op->x = settings.emergency_x;
3611  op->y = settings.emergency_y;
3612  save_player(op, 0);
3613  op->map = map;
3614  /* please see resurrection.c: peterm */
3615  dead_player(op);
3616  } else {
3617  delete_character(op->name);
3618  }
3619  }
3620  play_again(op);
3621 
3622  /* peterm: added to create a corpse at deathsite. */
3623  tmp = arch_to_object(find_archetype("corpse_pl"));
3624  snprintf(buf, sizeof(buf), "%s", op->name);
3625  FREE_AND_COPY(tmp->name, buf);
3626  FREE_AND_COPY(tmp->name_pl, buf);
3627  tmp->level = op->level;
3628  tmp->x = x;
3629  tmp->y = y;
3630  if (tmp->msg)
3631  free_string(tmp->msg);
3632  tmp->msg = add_string(gravestone_text(op, buf, sizeof(buf)));
3633  SET_FLAG(tmp, FLAG_UNIQUE);
3634  insert_ob_in_map(tmp, map, NULL, 0);
3635  }
3636 }
3637 
3645 void fix_weight(void) {
3646  player *pl;
3647 
3648  for (pl = first_player; pl != NULL; pl = pl->next) {
3649  int old = pl->ob->carrying, sum = sum_weight(pl->ob);
3650 
3651  if (old == sum)
3652  continue;
3653  fix_object(pl->ob);
3654  LOG(llevDebug, "Fixed inventory in %s (%d -> %d)\n", pl->ob->name, old, sum);
3655  }
3656 }
3657 
3661 void fix_luck(void) {
3662  player *pl;
3663 
3664  for (pl = first_player; pl != NULL; pl = pl->next)
3665  if (!pl->ob->contr->state)
3666  change_luck(pl->ob, 0);
3667 }
3668 
3669 
3682 void cast_dust(object *op, object *throw_ob, int dir) {
3683  object *skop, *spob;
3684 
3685  skop = find_skill_by_name(op, throw_ob->skill);
3686 
3687  /* casting POTION 'dusts' is really a use_magic_item skill */
3688  if (op->type == PLAYER && throw_ob->type == POTION && !skop) {
3689  LOG(llevError, "Player %s lacks critical skill use_magic_item!\n", op->name);
3690  return;
3691  }
3692  spob = throw_ob->inv;
3693  if (op->type == PLAYER && spob)
3695  "You cast %s.",
3696  "You cast %s.",
3697  spob->name);
3698 
3699  cast_spell(op, throw_ob, dir, spob, NULL);
3700 
3701  if (!QUERY_FLAG(throw_ob, FLAG_REMOVED))
3702  remove_ob(throw_ob);
3703  free_object(throw_ob);
3704 }
3705 
3712 void make_visible(object *op) {
3713  op->hide = 0;
3714  op->invisible = 0;
3715  if (op->type == PLAYER) {
3716  op->contr->tmp_invis = 0;
3717  if (op->contr->invis_race)
3719  }
3721 }
3722 
3731 int is_true_undead(object *op) {
3732  object *tmp = NULL;
3733 
3734  if (QUERY_FLAG(&op->arch->clone, FLAG_UNDEAD))
3735  return 1;
3736 
3737  if (op->type == PLAYER)
3738  for (tmp = op->inv; tmp; tmp = tmp->below)
3739  if (tmp->type == EXPERIENCE && tmp->stats.Wis)
3740  if (QUERY_FLAG(tmp, FLAG_UNDEAD))
3741  return 1;
3742  return 0;
3743 }
3744 
3755 int hideability(object *ob) {
3756  int i, level = 0, mflag;
3757  sint16 x, y;
3758 
3759  if (!ob || !ob->map)
3760  return 0;
3761 
3762  /* so, on normal lighted maps, its hard to hide */
3763  level = ob->map->darkness-2;
3764 
3765  /* this also picks up whether the object is glowing.
3766  * If you carry a light on a non-dark map, its not
3767  * as bad as carrying a light on a pitch dark map
3768  */
3769  if (has_carried_lights(ob))
3770  level = -(10+(2*ob->map->darkness));
3771 
3772  /* scan through all nearby squares for terrain to hide in */
3773  for (i = 0, x = ob->x, y = ob->y; i < 9; i++, x = ob->x+freearr_x[i], y = ob->y+freearr_y[i]) {
3774  mflag = get_map_flags(ob->map, NULL, x, y, NULL, NULL);
3775  if (mflag&P_OUT_OF_MAP) {
3776  continue;
3777  }
3778  if (mflag&P_BLOCKSVIEW) /* something to hide near! */
3779  level += 2;
3780  else /* open terrain! */
3781  level -= 1;
3782  }
3783 
3784  return level;
3785 }
3786 
3796 void do_hidden_move(object *op) {
3797  int hide = 0, num = random_roll(0, 19, op, PREFER_LOW);
3798  object *skop;
3799 
3800  if (!op || !op->map)
3801  return;
3802 
3804 
3805  /* its *extremely *hard to run and sneak/hide at the same time! */
3806  if (op->type == PLAYER && op->contr->run_on) {
3807  if (!skop || num >= skop->level) {
3809  "You ran too much! You are no longer hidden!", NULL);
3810  make_visible(op);
3811  return;
3812  } else
3813  num += 20;
3814  }
3815  num += op->map->difficulty;
3816  hide = hideability(op); /* modify by terrain hidden level */
3817  num -= hide;
3818  if ((op->type == PLAYER && hide < -10)
3819  || ((op->invisible -= num) <= 0)) {
3820  make_visible(op);
3821  if (op->type == PLAYER)
3823  "You moved out of hiding! You are visible!", NULL);
3824  } else if (op->type == PLAYER && skop) {
3825  change_exp(op, calc_skill_exp(op, NULL, skop), skop->skill, 0);
3826  }
3827 }
3828 
3837 int stand_near_hostile(object *who) {
3838  object *tmp = NULL;
3839  int i, friendly = 0, player = 0, mflags;
3840  mapstruct *m;
3841  sint16 x, y;
3842 
3843  if (!who)
3844  return 0;
3845 
3846  if (who->type == PLAYER)
3847  player = 1;
3848  else
3849  friendly = QUERY_FLAG(who, FLAG_FRIENDLY);
3850 
3851  /* search adjacent squares */
3852  for (i = 1; i < 9; i++) {
3853  x = who->x+freearr_x[i];
3854  y = who->y+freearr_y[i];
3855  m = who->map;
3856  mflags = get_map_flags(m, &m, x, y, &x, &y);
3857  /* space must be blocked if there is a monster. If not
3858  * blocked, don't need to check this space.
3859  */
3860  if (mflags&P_OUT_OF_MAP)
3861  continue;
3862  if (OB_TYPE_MOVE_BLOCK(who, GET_MAP_MOVE_BLOCK(m, x, y)))
3863  continue;
3864 
3865  for (tmp = GET_MAP_OB(m, x, y); tmp; tmp = tmp->above) {
3866  if ((player || friendly)
3867  && QUERY_FLAG(tmp, FLAG_MONSTER)
3868  && !QUERY_FLAG(tmp, FLAG_UNAGGRESSIVE))
3869  return 1;
3870  else if (tmp->type == PLAYER) {
3871  /*don't let a hidden DM prevent you from hiding*/
3872  if (!QUERY_FLAG(tmp, FLAG_WIZ) || tmp->contr->hidden == 0)
3873  return 1;
3874  }
3875  }
3876  }
3877  return 0;
3878 }
3879 
3906 int player_can_view(object *pl, object *op) {
3907  rv_vector rv;
3908  int dx, dy;
3909 
3910  if (pl->type != PLAYER) {
3911  LOG(llevError, "player_can_view() called for non-player object\n");
3912  return -1;
3913  }
3914  if (!pl || !op)
3915  return 0;
3916 
3917  if (op->head) {
3918  op = op->head;
3919  }
3920  get_rangevector(pl, op, &rv, 0x1);
3921 
3922  /* starting with the 'head' part, lets loop
3923  * through the object and find if it has any
3924  * part that is in the los array but isnt on
3925  * a blocked los square.
3926  * we use the archetype to figure out offsets.
3927  */
3928  while (op) {
3929  dx = rv.distance_x+op->arch->clone.x;
3930  dy = rv.distance_y+op->arch->clone.y;
3931 
3932  /* only the viewable area the player sees is updated by LOS
3933  * code, so we need to restrict ourselves to that range of values
3934  * for any meaningful values.
3935  */
3936  if (FABS(dx) <= (pl->contr->socket.mapx/2)
3937  && FABS(dy) <= (pl->contr->socket.mapy/2)
3938  && !pl->contr->blocked_los[dx+(pl->contr->socket.mapx/2)][dy+(pl->contr->socket.mapy/2)])
3939  return 1;
3940  op = op->more;
3941  }
3942  return 0;
3943 }
3944 
3958 static int action_makes_visible(object *op) {
3959  if (op->invisible && QUERY_FLAG(op, FLAG_ALIVE)) {
3960  if (QUERY_FLAG(op, FLAG_MAKE_INVIS))
3961  return 0;
3962 
3963  if (op->contr && op->contr->tmp_invis == 0)
3964  return 0;
3965 
3966  /* If monsters, they should become visible */
3967  if (op->hide || !op->contr || (op->contr && op->contr->tmp_invis)) {
3969  "You become %s!",
3970  "You become %s!",
3971  op->hide ? "unhidden" : "visible");
3972  return 1;
3973  }
3974  }
3975  return 0;
3976 }
3977 
4002 int op_on_battleground(object *op, int *x, int *y, archetype **trophy) {
4003  object *tmp;
4004 
4005  /* A battleground-tile needs the following attributes to be valid:
4006  * is_floor 1 (has to be the FIRST floor beneath the player's feet),
4007  * name="battleground", no_pick 1, type=58 (type BATTLEGROUND)
4008  * and the exit-coordinates sp/hp must both be > 0.
4009  * => The intention here is to prevent abuse of the battleground-
4010  * feature (like pickable or hidden battleground tiles). */
4011  for (tmp = op->below; tmp != NULL; tmp = tmp->below) {
4012  if (QUERY_FLAG(tmp, FLAG_IS_FLOOR)) {
4013  if (QUERY_FLAG(tmp, FLAG_NO_PICK)
4014  && strcmp(tmp->name, "battleground") == 0
4015  && tmp->type == BATTLEGROUND
4016  && EXIT_X(tmp)
4017  && EXIT_Y(tmp)) {
4018  /*before we assign the exit, check if this is a teambattle*/
4019  if (EXIT_ALT_X(tmp) && EXIT_ALT_Y(tmp) && EXIT_PATH(tmp)) {
4020  object *invtmp;
4021 
4022  for (invtmp = op->inv; invtmp != NULL; invtmp = invtmp->below) {
4023  if (invtmp->type == FORCE
4024  && invtmp->slaying
4025  && !strcmp(EXIT_PATH(tmp), invtmp->slaying)) {
4026  if (x != NULL && y != NULL)
4027  *x = EXIT_ALT_X(tmp),
4028  *y = EXIT_ALT_Y(tmp);
4029  return 1;
4030  }
4031  }
4032  }
4033  if (x != NULL && y != NULL)
4034  *x = EXIT_X(tmp),
4035  *y = EXIT_Y(tmp);
4036  if (trophy != NULL) {
4037  if (tmp->other_arch)
4038  *trophy = tmp->other_arch;
4039  else
4040  *trophy = find_archetype("finger");
4041  }
4042  return 1;
4043  }
4044  }
4045  }
4046  /* If we got here, did not find a battleground */
4047  return 0;
4048 }
4049 
4060 void dragon_ability_gain(object *who, int atnr, int level) {
4061  treasurelist *trlist = NULL; /* treasurelist */
4062  treasure *tr; /* treasure */
4063  object *tmp, *skop; /* tmp. object */
4064  object *item; /* treasure object */
4065  char buf[MAX_BUF]; /* tmp. string buffer */
4066  int i = 0, j = 0;
4067 
4068  /* get the appropriate treasurelist */
4069  if (atnr == ATNR_FIRE)
4070  trlist = find_treasurelist("dragon_ability_fire");
4071  else if (atnr == ATNR_COLD)
4072  trlist = find_treasurelist("dragon_ability_cold");
4073  else if (atnr == ATNR_ELECTRICITY)
4074  trlist = find_treasurelist("dragon_ability_elec");
4075  else if (atnr == ATNR_POISON)
4076  trlist = find_treasurelist("dragon_ability_poison");
4077 
4078  if (trlist == NULL || who->type != PLAYER)
4079  return;
4080 
4081  for (i = 0, tr = trlist->items; tr != NULL && i < level-1; tr = tr->next, i++)
4082  ;
4083  if (tr == NULL || tr->item == NULL) {
4084  /* LOG(llevDebug, "-> no more treasure for %s\n", change_resist_msg[atnr]); */
4085  return;
4086  }
4087 
4088  /* everything seems okay - now bring on the gift: */
4089  item = &(tr->item->clone);
4090 
4091  if (item->type == SPELL) {
4092  if (check_spell_known(who, item->name))
4093  return;
4094 
4097  "You gained the ability of %s",
4098  "You gained the ability of %s",
4099  item->name);
4100  do_learn_spell(who, item, 0);
4101  return;
4102  }
4103 
4104  /* grant direct spell */
4105  if (item->type == SPELLBOOK) {
4106  if (!item->inv) {
4107  LOG(llevDebug, "dragon_ability_gain: Broken spellbook %s\n", item->name);
4108  return;
4109  }
4110  if (check_spell_known(who, item->inv->name))
4111  return;
4112  if (item->invisible) {
4115  "You gained the ability of %s",
4116  "You gained the ability of %s",
4117  item->inv->name);
4118  do_learn_spell(who, item->inv, 0);
4119  return;
4120  }
4121  } else if (item->type == SKILL_TOOL && item->invisible) {
4122  if (item->subtype == SK_CLAWING && (skop = find_skill_by_name(who, item->skill)) != NULL) {
4123  /* should this perhaps be (skop->attackyp&item->attacktype) != item->attacktype ...
4124  * in this way, if the player is missing any of the attacktypes, he gets
4125  * them. As it is now, if the player has any that match the granted skill,
4126  * but not all of them, he gets nothing.
4127  */
4128  if (!(skop->attacktype&item->attacktype)) {
4129  /* Give new attacktype */
4130  skop->attacktype |= item->attacktype;
4131 
4132  /* always add physical if there's none */
4133  skop->attacktype |= AT_PHYSICAL;
4134 
4135  if (item->msg != NULL)
4138  item->msg, item->msg);
4139 
4140  /* Give player new face */
4141  if (item->animation_id) {
4142  who->face = skop->face;
4143  who->animation_id = item->animation_id;
4144  who->anim_speed = item->anim_speed;
4145  who->last_anim = 0;
4146  who->state = 0;
4147  animate_object(who, who->direction);
4148  }
4149  }
4150  }
4151  } else if (item->type == FORCE) {
4152  /* forces in the treasurelist can alter the player's stats */
4153  object *skin;
4154 
4155  /* first get the dragon skin force */
4156  for (skin = who->inv; skin != NULL && strcmp(skin->arch->name, "dragon_skin_force") != 0; skin = skin->below)
4157  ;
4158  if (skin == NULL)
4159  return;
4160 
4161  /* adding new spellpath attunements */
4162  if (item->path_attuned > 0 && !(skin->path_attuned&item->path_attuned)) {
4163  skin->path_attuned |= item->path_attuned; /* add attunement to skin */
4164 
4165  /* print message */
4166  snprintf(buf, sizeof(buf), "You feel attuned to ");
4167  for (i = 0, j = 0; i < NRSPELLPATHS; i++) {
4168  if (item->path_attuned&(1<<i)) {
4169  if (j)
4170  strcat(buf, " and ");
4171  else
4172  j = 1;
4173  strcat(buf, spellpathnames[i]);
4174  }
4175  }
4176  strcat(buf, ".");
4179  buf, buf);
4180  }
4181 
4182  /* evtl. adding flags: */
4183  if (QUERY_FLAG(item, FLAG_XRAYS))
4184  SET_FLAG(skin, FLAG_XRAYS);
4185  if (QUERY_FLAG(item, FLAG_STEALTH))
4186  SET_FLAG(skin, FLAG_STEALTH);
4187  if (QUERY_FLAG(item, FLAG_SEE_IN_DARK))
4188  SET_FLAG(skin, FLAG_SEE_IN_DARK);
4189 
4190  /* print message if there is one */
4191  if (item->msg != NULL)
4194  item->msg, item->msg);
4195  } else {
4196  /* generate misc. treasure */
4197  char name[HUGE_BUF];
4198 
4199  tmp = arch_to_object(tr->item);
4200  query_short_name(tmp, name, HUGE_BUF);
4203  "You gained %s",
4204  "You gained %s",
4205  name);
4206  tmp = insert_ob_in_ob(tmp, who);
4207  if (who->type == PLAYER)
4208  esrv_send_item(who, tmp);
4209  }
4210 }
4211 
4221 void player_unready_range_ob(player *pl, object *ob) {
4222  rangetype i;
4223 
4224  for (i = 0; i < range_size; i++) {
4225  if (pl->ranges[i] == ob) {
4226  pl->ranges[i] = NULL;
4227  if (pl->shoottype == i) {
4228  pl->shoottype = range_none;
4229  }
4230  }
4231  }
4232 }
#define MSG_TYPE_MOTD
Definition: newclient.h:323
sint16 bed_x
Definition: player.h:152
static int player_fire_bow(object *op, int dir)
Definition: player.c:2106
void spring_trap(object *trap, object *victim)
Definition: rune.c:227
char path[HUGE_BUF]
Definition: map.h:384
static void swap_stat(object *op, int Swap_Second)
Definition: player.c:1020
#define SKILLSCROLL
Definition: define.h:313
int player_can_view(object *pl, object *op)
Definition: player.c:3906
static int player_attack_door(object *op, object *door)
Definition: player.c:2361
#define FOOD
Definition: define.h:118
#define RING
Definition: define.h:232
const char * rules
Definition: global.h:367
signed char sint8
Definition: global.h:80
int get_map_flags(mapstruct *oldmap, mapstruct **newmap, sint16 x, sint16 y, sint16 *nx, sint16 *ny)
Definition: map.c:330
#define FLAG_NO_DROP
Definition: define.h:585
sint8 Int
Definition: living.h:78
Definition: player.h:146
#define FLAG_SEE_IN_DARK
Definition: define.h:634
const char * determine_god(object *op)
Definition: gods.c:118
uint16 emergency_y
Definition: global.h:389
archetype * find_archetype(const char *name)
Definition: arch.c:700
#define FLAG_DAMNED
Definition: define.h:614
#define FLAG_IS_FLOOR
Definition: define.h:599
#define FLAG_UNPAID
Definition: define.h:532
sint8 ac
Definition: living.h:79
#define MOVE_WALK
Definition: define.h:700
#define UP_OBJ_FACE
Definition: object.h:356
#define ST_GET_PARTY_PASSWORD
Definition: define.h:894
int is_in_shop(object *ob)
Definition: shop.c:1414
MoveType move_type
Definition: object.h:277
#define MSG_TYPE_ATTRIBUTE_GOD
Definition: newclient.h:488
#define EVENT_REMOVE
Definition: plugin.h:89
const char * get_ob_key_value(const object *op, const char *const key)
Definition: object.c:3701
#define DETOUR_AMOUNT
Definition: player.c:508
#define OUT_OF_MEMORY
Definition: define.h:94
MoveType move_on
Definition: object.h:280
signed short sint16
Definition: global.h:72
uint32 pticks
Definition: time.c:56
void enter_exit(object *op, object *exit_ob)
Definition: server.c:740
Definition: map.h:399
Definition: player.h:76
object * find_obj_by_type_subtype(const object *who, int type, int subtype)
Definition: object.c:3656
void esrv_new_player(player *pl, uint32 weight)
Definition: request.c:868
void change_exp(object *op, sint64 exp, const char *skill_name, int flag)
Definition: living.c:2015
void leave(player *pl, int draw_exit)
Definition: server.c:1234
#define MSG_SUBTYPE_NONE
Definition: newclient.h:339
static void loot_object(object *op)
Definition: player.c:3195
object * check_spell_known(object *op, const char *name)
Definition: spell_util.c:408
Definition: object.h:298
const char * race
Definition: object.h:171
void set_owner(object *op, object *owner)
Definition: object.c:564
const int dam_bonus[MAX_STAT+1]
Definition: living.c:119
uint16 emergency_x
Definition: global.h:389
void esrv_send_item(object *pl, object *op)
Definition: standalone.c:197
#define SET_FLAG(xyz, p)
Definition: define.h:510
sstring add_refcount(sstring str)
Definition: shstr.c:202
#define EXIT_ALT_Y(xyz)
Definition: define.h:753
int similar_direction(int a, int b)
Definition: weather.c:132
#define NDI_ALL
Definition: newclient.h:220
#define PU_DEBUG
Definition: define.h:396
char title[BIG_NAME]
Definition: player.h:216
#define FABS(x)
Definition: define.h:61
#define EVENT_DEATH
Definition: plugin.h:64
void SockList_ResetRead(SockList *sl)
Definition: lowlevel.c:94
void get_name(object *op)
Definition: player.c:786
void make_path_to_file(const char *filename)
Definition: porting.c:764
char spellparam[MAX_BUF]
Definition: player.h:154
#define TRAP
Definition: define.h:326
#define WAND
Definition: define.h:291
uint16 material
Definition: object.h:198
#define FLAG_USE_ARMOUR
Definition: define.h:592
void send_news(const object *op)
Definition: player.c:176
#define BALSL_NUMBER_LOSSES_RATIO
Definition: config.h:118
void drain_wand_charge(object *wand)
Definition: spell_util.c:753
EXTERN objectlink * first_friendly_object
Definition: global.h:196
struct obj * container
Definition: object.h:149
#define EVENT_LOGIN
Definition: plugin.h:84
#define PU_STOP
Definition: define.h:398
#define FLAG_FRIENDLY
Definition: define.h:542
int push_ob(object *who, int dir, object *pusher)
Definition: move.c:492
#define MONEY
Definition: define.h:148
#define PU_SHIELD
Definition: define.h:410
char motd[MAX_BUF]
Definition: global.h:366
#define MSG_TYPE_ITEM
Definition: newclient.h:334
object * mon
Definition: comet_perf.c:74
#define NDI_BROWN
Definition: newclient.h:207
object * insert_ob_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
Definition: object.c:1761
int op_on_battleground(object *op, int *x, int *y, archetype **trophy)
Definition: player.c:4002
#define DOOR
Definition: define.h:135
static int turn_transport(object *transport, object *captain, int dir)
Definition: player.c:2711
#define SOUND_TYPE_GROUND
Definition: sounds.h:38
treasurelist * find_treasurelist(const char *name)
Definition: treasure.c:295
int save_player(object *op, int flag)
Definition: login.c:223
void dragon_ability_gain(object *who, int atnr, int level)
Definition: player.c:4060
const int dex_bonus[MAX_STAT+1]
Definition: living.c:104
const char * playerdir
Definition: global.h:336
sint8 get_attr_value(const living *stats, int attr)
Definition: living.c:377
sint16 maxgrace
Definition: living.h:86
void free_string(sstring str)
Definition: shstr.c:272
#define MSG_TYPE_ATTACK_NOATTACK
Definition: newclient.h:533
#define PU_KEY
Definition: define.h:416
#define HUGE_BUF
Definition: define.h:83
#define SET_ANIMATION(ob, newanim)
Definition: global.h:247
void esrv_update_item(int flags, object *pl, object *op)
Definition: standalone.c:200
#define MSG_TYPE_SKILL_FAILURE
Definition: newclient.h:504
struct treasureliststruct * randomitems
Definition: object.h:236
void pick_up(object *op, object *alt)
Definition: c_object.c:462
#define NDI_BLUE
Definition: newclient.h:200
#define MSG_TYPE_COMMAND_SUCCESS
Definition: newclient.h:448
int item_matched_string(object *pl, object *op, const char *name)
Definition: object.c:3901
void query_base_name(const object *op, int plural, char *buf, size_t size)
Definition: item.c:732
object clone
Definition: object.h:326
uint8 set_title
Definition: global.h:353
socket_struct socket
Definition: player.h:148
sint16 invisible
Definition: object.h:211
short freearr_x[SIZEOFFREE]
Definition: object.c:75
#define PREFER_LOW
Definition: define.h:909
#define POTION
Definition: define.h:117
uint8 last_anim
Definition: object.h:269
#define ST_CONFIRM_PASSWORD
Definition: define.h:893
rangetype shoottype
Definition: player.h:153
#define MSG_TYPE_ADMIN_PLAYER
Definition: newclient.h:414
void draw_ext_info(int flags, int pri, const object *pl, uint8 type, uint8 subtype, const char *message, const char *oldmessage)
Definition: standalone.c:171
const char * slaying
Definition: object.h:172
#define IS_WEAPON(op)
Definition: define.h:449
void esrv_send_inventory(object *pl, object *op)
Definition: item.c:307
#define FLAG_CONFUSED
Definition: define.h:608
Output_Buf outputs[NUM_OUTPUT_BUFS]
Definition: player.h:244
#define SCROLL
Definition: define.h:293
#define FLAG_STEALTH
Definition: define.h:609
uint32 mode
Definition: player.h:164
static object * pick_arrow_target(object *op, const char *type, int dir)
Definition: player.c:1852
object * ranges[range_size]
Definition: player.h:157
void update_object(object *op, int action)
Definition: object.c:1112
uint8 subtype
Definition: object.h:190
#define MSG_TYPE_SPELL
Definition: newclient.h:333
uint32 run_on
Definition: player.h:182
void send_rules(const object *op)
Definition: player.c:142
#define EXPERIENCE
Definition: define.h:158
#define SOUND_TYPE_LIVING
Definition: sounds.h:35
#define FLAG_USE_WEAPON
Definition: define.h:593
sint64 exp
Definition: living.h:88
void fix_luck(void)
Definition: player.c:3661
#define RUNE
Definition: define.h:325
uint32 in_memory
Definition: map.h:366
struct obj * above
Definition: object.h:146
void control_golem(object *op, int dir)
Definition: pets.c:648
void play_again(object *op)
Definition: player.c:810
void close_and_delete(FILE *fp, int compressed)
Definition: porting.c:748
void change_luck(object *op, int value)
Definition: living.c:791
method_ret ob_process(object *op)
Definition: ob_methods.c:79
#define BOOTS
Definition: define.h:281
#define OUT_OF_REAL_MAP(M, X, Y)
Definition: map.h:238
int language
Definition: player.h:255
#define PU_NOTHING
Definition: define.h:394
#define PU_FLESH
Definition: define.h:430
void handle_client(socket_struct *ns, player *pl)
Definition: loop.c:200
#define PU_FOOD
Definition: define.h:403
int manual_apply(object *op, object *tmp, int aflag)
Definition: apply.c:512
#define MSG_TYPE_ADMIN_RULES
Definition: newclient.h:412
void do_some_living(object *op)
Definition: player.c:3017
#define CLOAK
Definition: define.h:268
void give_initial_items(object *pl, treasurelist *items)
Definition: player.c:688
sint16 x
Definition: object.h:179
void remove_friendly_object(object *op)
Definition: friend.c:69
signed long sum_weight(object *op)
Definition: object.c:317
uint8 search_items
Definition: global.h:355
sint8 levsp[11]
Definition: player.h:219
uint32 path_attuned
Definition: object.h:194
#define F_TRUE
Definition: define.h:777
void get_multi_size(object *ob, int *sx, int *sy, int *hx, int *hy)
Definition: object.c:4066
void dead_player(object *op)
Definition: resurrection.c:291
sint16 sp
Definition: living.h:83
void change_attr_value(living *stats, int attr, sint8 value)
Definition: living.c:336
EXTERN char first_map_ext_path[MAX_BUF]
Definition: global.h:230
void strip_endline(char *buf)
Definition: utils.c:431
int path_to_player(object *mon, object *pl, unsigned mindiff)
Definition: player.c:556
void get_password(object *op)
Definition: player.c:798
uint8 balanced_stat_loss
Definition: global.h:349
int is_true_undead(object *op)
Definition: player.c:3731
#define SCRIPT_FIX_ALL
Definition: global.h:450
player * find_player_partial_name(const char *plname)
Definition: player.c:84
void draw_ext_info_format(int flags, int pri, const object *pl, uint8 type, uint8 subtype, const char *new_format, const char *old_format,...)
Definition: standalone.c:175
#define PU_NEWMODE
Definition: define.h:399
static const char * gravestone_text(object *op, char *buf2, int len)
Definition: player.c:2982
#define FLAG_USE_SHIELD
Definition: define.h:533
sint64 last_skill_exp[NUM_SKILLS]
Definition: player.h:192
struct obj * enemy
Definition: object.h:232
object * get_nearest_player(object *mon)
Definition: player.c:447
struct archt * other_arch
Definition: object.h:264
void terminate_all_pets(object *owner)
Definition: pets.c:250
#define ST_ROLL_STAT
Definition: define.h:888
#define ARMOUR
Definition: define.h:128
int distance_y
Definition: map.h:402
int absdir(int d)
Definition: object.c:3417
Definition: object.h:321
#define ST_PLAYING
Definition: define.h:886
#define PU_MISSILEWEAPON
Definition: define.h:418
char savebed_map[MAX_BUF]
Definition: player.h:151
#define NDI_DK_ORANGE
Definition: newclient.h:201
char * host
Definition: newserver.h:125
sint16 gen_hp
Definition: player.h:167
uint8 not_permadeth
Definition: global.h:350
uint16 outputs_sync
Definition: player.h:245
uint16 outputs_count
Definition: player.h:246
#define PLAYER
Definition: define.h:113
const char *const spellpathnames[NRSPELLPATHS]
Definition: init.c:126
struct archt * item
Definition: treasure.h:93
#define MSG_TYPE_COMMAND_FAILURE
Definition: newclient.h:449
#define NUM_OUTPUT_BUFS
Definition: player.h:38
static int turn_one_transport(object *transport, object *captain, int dir)
Definition: player.c:2639
#define PU_CLOAK
Definition: define.h:415
#define MSG_TYPE_COMMAND_NEWPLAYER
Definition: newclient.h:454
#define MSG_TYPE_ATTRIBUTE_BAD_EFFECT_END
Definition: newclient.h:481
sint16 maxsp
Definition: living.h:84
sint8 Con
Definition: living.h:78
void kill_player(object *op)
Definition: player.c:3238
#define FLAG_REMOVED
Definition: define.h:528
sint16 hp
Definition: living.h:81
int check_pick(object *op)
Definition: player.c:1384
#define FLAG_CAN_ROLL
Definition: define.h:550
short freearr_y[SIZEOFFREE]
Definition: object.c:81
partylist * party
Definition: player.h:237
#define FLAG_KNOWN_MAGICAL
Definition: define.h:616
Definition: player.h:69
#define CON
Definition: living.h:43
#define SOUND_TYPE_ITEM
Definition: sounds.h:37
#define NDI_NAVY
Definition: newclient.h:197
#define SPECIAL_KEY
Definition: define.h:133
void create_treasure(treasurelist *t, object *op, int flag, int difficulty, int tries)
Definition: treasure.c:499
uint8 resurrection
Definition: global.h:354
object * ob
Definition: object.h:299
#define MOVE_ALL
Definition: define.h:706
uint32 flags[4]
Definition: object.h:266
#define AMULET
Definition: define.h:153
#define FLAG_UNDEAD
Definition: define.h:566
const char * news
Definition: global.h:368
#define FLAG_READY_SKILL
Definition: define.h:630
uint32 tag_t
Definition: object.h:40
#define MAP_IN_MEMORY
Definition: map.h:151
struct obj * chosen_skill
Definition: object.h:237
object * find_key(object *pl, object *container, object *door)
Definition: player.c:2278
void clear_player(player *pl)
Definition: player.c:45
void remove_ob(object *op)
Definition: object.c:1515
sint16 maxhp
Definition: living.h:82
static void fire_misc_object(object *op, int dir)
Definition: player.c:2143
uint8 * faces_sent
Definition: newserver.h:121
#define POISON
Definition: define.h:119
void get_rangevector_from_mapcoord(const mapstruct *m, int x, int y, const object *op2, rv_vector *retval, int flags)
Definition: map.c:2573
#define PU_BOOTS
Definition: define.h:413
#define MSG_TYPE_ITEM_REMOVE
Definition: newclient.h:557
int stand_near_hostile(object *who)
Definition: player.c:3837
#define FLAG_ALIVE
Definition: define.h:526
#define TRANSPORT
Definition: define.h:114
uint32 golem_count
Definition: player.h:160
const char * name_pl
Definition: object.h:168
object * create_archetype(const char *name)
Definition: arch.c:625
float speed_left
Definition: object.h:182
unapplymode unapply
Definition: player.h:162
int is_wraith_pl(object *op)
Definition: player.c:173
sint16 gen_sp_armour
Definition: player.h:169
uint32 hidden
Definition: player.h:186
int blocked_link(object *ob, mapstruct *m, int sx, int sy)
Definition: map.c:373
#define PU_SKILLSCROLL
Definition: define.h:424
#define MSG_TYPE_VICTIM
Definition: newclient.h:336
const char * materialname
Definition: object.h:197
const int thaco_bonus[MAX_STAT+1]
Definition: living.c:124
int skill_attack(object *tmp, object *pl, int dir, const char *string, object *skill)
Definition: skill_util.c:1126
sint32 weight
Definition: object.h:216
#define FLAG_CAN_USE_SKILL
Definition: define.h:618
#define MOVE_FLY_LOW
Definition: define.h:701
uint8 stat_loss_on_death
Definition: global.h:344
uint32 peaceful
Definition: player.h:185
void drain_rod_charge(object *rod)
Definition: spell_util.c:743
sint8 Wis
Definition: living.h:78
int hide(object *op, object *skill)
Definition: skills.c:498
#define FLAG_UNAGGRESSIVE
Definition: define.h:568
#define MSG_TYPE_ITEM_INFO
Definition: newclient.h:560
void receive_play_again(object *op, char key)
Definition: player.c:839
#define PU_ARROW
Definition: define.h:408
struct mapdef * map
Definition: object.h:155
char search_str[MAX_BUF]
Definition: player.h:243
#define KEY
Definition: define.h:136
void set_attr_value(living *stats, int attr, sint8 value)
Definition: living.c:296
void get_rangevector(object *op1, const object *op2, rv_vector *retval, int flags)
Definition: map.c:2504
#define HORN
Definition: define.h:147
void add_player(socket_struct *ns)
Definition: player.c:383
object * transport
Definition: player.h:249
#define FLAG_IDENTIFIED
Definition: define.h:557
#define SK_CLAWING
Definition: skills.h:78
#define MOVE_FLYING
Definition: define.h:703
float weapon_sp
Definition: player.h:194
sint16 dam
Definition: living.h:87
sint64 calc_skill_exp(object *who, object *op, object *skill)
Definition: skill_util.c:599
uint32 monitor_spells
Definition: newserver.h:135
int die_roll(int num, int size, const object *op, int goodbad)
Definition: utils.c:134
void add_friendly_object(object *op)
Definition: friend.c:43
sint32 carrying
Definition: object.h:218
int cure_disease(object *sufferer, object *caster)
Definition: disease.c:715
#define NDI_GREEN
Definition: newclient.h:202
#define MSG_TYPE_ATTRIBUTE
Definition: newclient.h:327
const char * name
Definition: object.h:167
living orig_stats
Definition: player.h:203
#define PU_INHIBIT
Definition: define.h:397
struct obj * env
Definition: object.h:151
#define SPELL
Definition: define.h:283
uint32 tmp_invis
Definition: player.h:179
int fire_bow(object *op, object *arrow, int dir, int wc_mod, sint16 sx, sint16 sy)
Definition: player.c:1922
int distance_x
Definition: map.h:401
uint8 state
Definition: player.h:172
uint16 run_away
Definition: object.h:235
#define PU_BOW
Definition: define.h:406
int allowed_class(const object *op)
Definition: living.c:1543
#define FLESH
Definition: define.h:234
object * get_owner(object *op)
Definition: object.c:524
#define ST_PLAY_AGAIN
Definition: define.h:887
struct obj * below
Definition: object.h:145
void roll_again(object *op)
Definition: player.c:1006
int execute_global_event(int eventcode,...)
Definition: standalone.c:229
uint16 difficulty
Definition: map.h:364
#define POW
Definition: living.h:47
#define EXIT_PATH(xyz)
Definition: define.h:748
void send_query(socket_struct *ns, uint8 flags, const char *text)
Definition: request.c:727
void display_motd(const object *op)
Definition: player.c:112
void fatal(int err)
Definition: glue.c:60
#define BATTLEGROUND
Definition: define.h:195
#define offsetof(type, member)
Definition: shstr.h:37
#define CS_QUERY_SINGLECHAR
Definition: newclient.h:77
static player * get_player(player *p)
Definition: player.c:258
void flush_output_element(const object *pl, Output_Buf *outputs)
Definition: info.c:108
#define TRUE
Definition: exp.c:41
#define PU_RATIO
Definition: define.h:401
int can_detect_enemy(object *op, object *enemy, rv_vector *rv)
Definition: monster.c:2020
sint32 last_weight
Definition: player.h:197
uint32 nrof
Definition: object.h:184
void fire(object *op, int dir)
Definition: player.c:2204
sint8 Cha
Definition: living.h:78
#define DEX
Definition: living.h:42
#define OB_TYPE_MOVE_BLOCK(ob1, type)
Definition: define.h:740
#define AP_NOPRINT
Definition: define.h:1020
void check_score(object *op, int quiet)
Definition: hiscore.c:289
void remove_locked_door(object *op)
Definition: time.c:80
#define P_OUT_OF_MAP
Definition: map.h:272
mapstruct * get_map_from_coord(mapstruct *m, sint16 *x, sint16 *y)
Definition: map.c:2366
#define GET_MAP_MOVE_BLOCK(M, X, Y)
Definition: map.h:213
int do_skill(object *op, object *part, object *skill, int dir, const char *string)
Definition: skill_util.c:373
int move_ob(object *op, int dir, object *originator)
Definition: move.c:72
#define EXIT_X(xyz)
Definition: define.h:750
sint8 facing
Definition: object.h:186
void do_learn_spell(object *op, object *spell, int special_prayer)
Definition: apply.c:398
sint16 y
Definition: object.h:179
#define LOCKED_DOOR
Definition: define.h:132
struct pl * contr
Definition: object.h:134
#define PU_DRINK
Definition: define.h:404
static void flee_player(object *op)
Definition: player.c:1329
#define WEAPON
Definition: define.h:127
int can_pick(const object *who, const object *item)
Definition: object.c:3569
void add_statbonus(object *op)
Definition: living.c:863
#define FLAG_SCARED
Definition: define.h:567
void play_sound_map(sint8 sound_type, object *emitter, int dir, const char *action)
Definition: sounds.c:90
#define CHA
Definition: living.h:45
#define FLAG_XRAYS
Definition: define.h:597
#define FREE_AND_CLEAR_STR(xyz)
Definition: global.h:283
char * spellarg
Definition: object.h:260
#define MAX(x, y)
Definition: define.h:70
sint8 luck
Definition: living.h:80
#define ATNR_ELECTRICITY
Definition: attack.h:80
#define MSG_TYPE_SKILL
Definition: newclient.h:329
#define ATNR_POISON
Definition: attack.h:87
#define AT_PHYSICAL
Definition: attack.h:104
float speed
Definition: object.h:181
#define QUERY_FLAG(xyz, p)
Definition: define.h:514
uint8 state
Definition: object.h:200
#define CLEAR_FLAG(xyz, p)
Definition: define.h:512
uint32 first_update
Definition: player.h:42
char * strdup_local(const char *str)
Definition: porting.c:310
#define MSG_TYPE_MISC
Definition: newclient.h:335
#define MSG_TYPE_APPLY
Definition: newclient.h:330
party_rejoin_mode rejoin_party
Definition: player.h:242
void clear_los(object *op)
Definition: los.c:258
#define FLAG_WIZ
Definition: define.h:527
#define GEM
Definition: define.h:202
#define FLAG_BEEN_APPLIED
Definition: define.h:620
#define EXIT_ALT_X(xyz)
Definition: define.h:752
object * insert_ob_in_ob(object *op, object *where)
Definition: object.c:2510
#define BALSL_LOSS_CHANCE_RATIO
Definition: config.h:117
#define EXIT_Y(xyz)
Definition: define.h:751
void delete_character(const char *name)
Definition: login.c:97
#define MAX_BUF
Definition: define.h:81
#define NRSPELLPATHS
Definition: spells.h:68
#define GLOVES
Definition: define.h:282
#define MSG_TYPE_ADMIN
Definition: newclient.h:324
#define IS_SHIELD(op)
Definition: define.h:456
#define PU_READABLES
Definition: define.h:425
object * get_object(void)
Definition: object.c:921
void start_info(object *op)
Definition: server.c:97
void do_hidden_move(object *op)
Definition: player.c:3796
char own_title[MAX_NAME]
Definition: player.h:214
#define MSG_TYPE_COMMAND_DEBUG
Definition: newclient.h:446
int strncasecmp(const char *s1, const char *s2, int n)
Definition: porting.c:402
object * insert_ob_in_map(object *op, mapstruct *m, object *originator, int flag)
Definition: object.c:1992
#define BOOK
Definition: define.h:120
struct treasurestruct * items
Definition: treasure.h:119
const char * skill
Definition: object.h:174
void fix_weight(void)
Definition: player.c:3645
void esrv_map_scroll(socket_struct *ns, int dx, int dy)
Definition: request.c:1432
#define NUM_SKILLS
Definition: skills.h:95
sint8 wc
Definition: living.h:79
int roll_stat(void)
Definition: player.c:908
uint16 look_position
Definition: newserver.h:142
const char * confdir
Definition: global.h:333
#define FLAG_IS_THROWN
Definition: define.h:545
void get_party_password(object *op, partylist *party)
Definition: player.c:891
uint32 explore
Definition: player.h:187
#define MIN(x, y)
Definition: define.h:67
sint8 Str
Definition: living.h:78
void animate_object(object *op, int dir)
Definition: anim.c:186
sint16 resist[NROFATTACKS]
Definition: object.h:192
uint8 darkness
Definition: map.h:369
#define FLAG_KNOWN_CURSED
Definition: define.h:617
object * ob
Definition: player.h:207
int has_carried_lights(const object *op)
Definition: los.c:322
#define MSG_TYPE_ATTRIBUTE_STAT_LOSS
Definition: newclient.h:483
int need_identify(const object *op)
Definition: item.c:1401
const char *const lose_msg[NUM_STATS]
Definition: living.c:262
#define FLAG_CURSED
Definition: define.h:613
#define SHIELD
Definition: define.h:145
uint64 query_cost(const object *tmp, object *who, int flag)
Definition: shop.c:121
#define MSG_TYPE_ATTRIBUTE_RACE
Definition: newclient.h:479
int snprintf(char *dest, int max, const char *format,...)
Definition: porting.c:498
sint16 bed_y
Definition: player.h:152
#define decrease_ob(xyz)
Definition: global.h:276
bowtype_t bowtype
Definition: player.h:155
#define WIS
Definition: living.h:44
int move_player(object *op, int dir)
Definition: player.c:2741
char killer[BIG_NAME]
Definition: player.h:222
#define FORCE
Definition: define.h:296
void key_roll_stat(object *op, char key)
Definition: player.c:1079
#define MSG_TYPE_APPLY_SUCCESS
Definition: newclient.h:518
#define PREFER_HIGH
Definition: define.h:908
uint32 attacktype
Definition: object.h:193
sint16 last_resist[NROFATTACKS]
Definition: player.h:206
sint8 direction
Definition: object.h:185
float last_speed
Definition: player.h:205
#define CONTAINER
Definition: define.h:306
#define FLAG_NEUTRAL
Definition: define.h:658
uint32 update_look
Definition: newserver.h:131
living last_stats
Definition: player.h:204
int handle_newcs_player(object *op)
Definition: player.c:2826
const char * invis_race
Definition: player.h:189
#define FREE_AND_COPY(sv, nv)
Definition: global.h:288
sint16 grace
Definition: living.h:85
#define SK_HIDING
Definition: skills.h:49
#define MAX_SPACES
Definition: player.c:523
const char * localdir
Definition: global.h:335
char password[16]
Definition: player.h:227
tag_t count
Definition: object.h:157
void recursive_roll(object *op, int dir, object *pusher)
Definition: move.c:340
living stats
Definition: object.h:219
static int save_life(object *op)
Definition: player.c:2899
sint8 Dex
Definition: living.h:78
struct archt * arch
Definition: object.h:263
float last_weapon_sp
Definition: player.h:195
struct oblnk * next
Definition: object.h:300
int playername_ok(const char *cp)
Definition: player.c:230
int apply_container(object *op, object *sack)
Definition: apply.c:230
object * present_arch_in_ob(const archetype *at, const object *op)
Definition: object.c:2859
void make_visible(object *op)
Definition: player.c:3712
static archetype * get_player_archetype(archetype *at)
Definition: player.c:422
#define SPELL_HIGHEST
Definition: spells.h:88
uint32 do_los
Definition: player.h:180
unsigned int distance
Definition: map.h:400
#define SKILL
Definition: define.h:157
sint8 levgrace[11]
Definition: player.h:220
void move_player_attack(object *op, int dir)
Definition: player.c:2419
struct Settings settings
Definition: init.c:48
int Swap_First
Definition: player.h:202
struct archt * next
Definition: object.h:323
int direction
Definition: map.h:403
rangetype
Definition: player.h:52
#define SPELL_EFFECT
Definition: define.h:284
#define FLAG_NO_STRENGTH
Definition: define.h:603
#define FLAG_APPLIED
Definition: define.h:531
#define NROFATTACKS
Definition: attack.h:45
void query_short_name(const object *op, char *buf, size_t size)
Definition: item.c:551
#define PU_SPELLBOOK
Definition: define.h:423
int out_of_map(mapstruct *m, int x, int y)
Definition: map.c:2300
int execute_event(object *op, int eventcode, object *activator, object *third, const char *message, int fix)
Definition: standalone.c:225
#define FLAG_LIFESAVE
Definition: define.h:602
#define MSG_TYPE_COMMAND
Definition: newclient.h:326
void remove_unpaid_objects(object *op, object *env, int free_items)
Definition: player.c:2943
sint16 SP_level_spellpoint_cost(object *caster, object *spell, int flags)
Definition: spell_util.c:281
void delete_map(mapstruct *m)
Definition: map.c:1745
void check_stat_bounds(living *stats)
Definition: living.c:404
#define ST_CHANGE_CLASS
Definition: define.h:889
#define MSG_TYPE_SPELL_END
Definition: newclient.h:549
const char * msg
Definition: object.h:175
EXTERN char first_map_path[MAX_BUF]
Definition: global.h:229
uint32 fire_on
Definition: player.h:181
#define FLAG_MAKE_INVIS
Definition: define.h:625
uint16 animation_id
Definition: object.h:267
void apply_death_exp_penalty(object *op)
Definition: living.c:2073
#define FLAG_STARTEQUIP
Definition: define.h:564
#define FORCE_NAME
Definition: spells.h:196
#define PU_VALUABLES
Definition: define.h:405
void update_ob_speed(object *op)
Definition: object.c:1008
#define BOW
Definition: define.h:126
#define PU_MAGICAL
Definition: define.h:420
sstring add_string(const char *str)
Definition: shstr.c:116
EXTERN player * first_player
Definition: global.h:190
void link_player_skills(object *op)
Definition: skill_util.c:112
#define MSG_TYPE_VICTIM_DIED
Definition: newclient.h:570
#define DRINK
Definition: define.h:187
struct pl * next
Definition: player.h:147
sint16 gen_sp
Definition: player.h:168
#define UPD_WEIGHT
Definition: newclient.h:256
void play_sound_player_only(player *pl, sint8 sound_type, object *emitter, int dir, const char *action)
Definition: sounds.c:40
#define GET_MAP_OB(M, X, Y)
Definition: map.h:193
player * find_player(const char *plname)
Definition: player.c:62
void confirm_password(object *op)
Definition: player.c:877
#define PU_JEWELS
Definition: define.h:429
#define FLAG_MONSTER
Definition: define.h:541
#define INT
Definition: living.h:46
uint8 anim_speed
Definition: object.h:268
#define EVENT_PLAYER_DEATH
Definition: plugin.h:82
sint8 Pow
Definition: living.h:78
struct obj * inv
Definition: object.h:148
petmode_t petmode
Definition: player.h:156
#define NDI_UNIQUE
Definition: newclient.h:219
#define HELMET
Definition: define.h:146
char maplevel[MAX_BUF]
Definition: player.h:150
struct obj * head
Definition: object.h:154
uint32 no_shout
Definition: player.h:188
#define FLAG_READY_BOW
Definition: define.h:596
#define SPELLBOOK
Definition: define.h:266
usekeytype usekeys
Definition: player.h:161
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:63
#define CS_QUERY_HIDEINPUT
Definition: newclient.h:78
object * get_split_ob(object *orig_ob, uint32 nr, char *err, size_t size)
Definition: object.c:2313
static int action_makes_visible(object *op)
Definition: player.c:3958
#define PU_GLOVES
Definition: define.h:414
#define ARROW
Definition: define.h:125
int did_make_save(const object *op, int level, int bonus)
Definition: living.c:2121
unsigned int uint32
Definition: global.h:58
#define ROD
Definition: define.h:115
#define FLAG_WAS_WIZ
Definition: define.h:530
#define was_destroyed(op, old_tag)
Definition: object.h:94
int transfer_ob(object *op, int x, int y, int randomly, object *originator)
Definition: move.c:197
void player_unready_range_ob(player *pl, object *ob)
Definition: player.c:4221
sint8 levhp[11]
Definition: player.h:218
void roll_stats(object *op)
Definition: player.c:932
#define IS_ARMOR(op)
Definition: define.h:452
#define MSG_TYPE_ADMIN_NEWS
Definition: newclient.h:413
object * last_skill_ob[NUM_SKILLS]
Definition: player.h:191
void key_change_class(object *op, char key)
Definition: player.c:1156
#define SKILL_TOOL
Definition: define.h:236
struct mapdef * next
Definition: map.h:347
#define P_BLOCKSVIEW
Definition: map.h:247
static void update_transport_block(object *transport, int dir)
Definition: player.c:2594
#define MSG_TYPE_ATTACK_NOKEY
Definition: newclient.h:532
#define ATNR_COLD
Definition: attack.h:81
uint8 listening
Definition: player.h:174
void copy_object(object *op2, object *op)
Definition: object.c:758
#define UPD_FACE
Definition: newclient.h:257
void query_name(const object *op, char *buf, size_t size)
Definition: item.c:628
#define PU_ARMOUR
Definition: define.h:411
void apply_map_builder(object *pl, int dir)
Definition: build_map.c:978
void remove_statbonus(object *op)
Definition: living.c:840
void free_object(object *ob)
Definition: object.c:1238
char * emergency_mapname
Definition: global.h:388
Definition: map.h:346
#define P_IS_ALIVE
Definition: map.h:258
uint32 braced
Definition: player.h:178
int random_roll(int min, int max, const object *op, int goodbad)
Definition: utils.c:51
#define ST_GET_NAME
Definition: define.h:891
New_Face * face
Definition: object.h:183
char write_buf[MAX_BUF]
Definition: player.h:225
#define FLAG_UNIQUE
Definition: define.h:584
#define FLAG_NO_PICK
Definition: define.h:535
static object * find_better_arrow(object *op, object *target, const char *type, int *better)
Definition: player.c:1782
#define PU_POTION
Definition: define.h:421
const char *const short_stat_name[NUM_STATS]
Definition: living.c:278
#define MSG_TYPE_ADMIN_LOGIN
Definition: newclient.h:418
void enter_player_savebed(object *op)
Definition: server.c:175
partylist * party_to_join
Definition: player.h:238
#define PU_HELMET
Definition: define.h:409
sint16 level
Definition: object.h:202
#define FLAG_INV_LOCKED
Definition: define.h:626
void fix_object(object *op)
Definition: living.c:900
#define PU_ALLWEAPON
Definition: define.h:419
#define BALSL_MAX_LOSS_RATIO
Definition: config.h:119
EXTERN mapstruct * first_map
Definition: global.h:191
#define MSG_TYPE_COMMAND_ERROR
Definition: newclient.h:447
void cast_dust(object *op, object *throw_ob, int dir)
Definition: player.c:3682
#define AT_DEATH
Definition: attack.h:121
#define PU_NOT_CURSED
Definition: define.h:428
EXTERN archetype * first_archetype
Definition: global.h:195
#define MSG_TYPE_ITEM_ADD
Definition: newclient.h:558
object * find_skill_by_name(object *who, const char *name)
Definition: skill_util.c:207
struct obj * more
Definition: object.h:153
object * arch_to_object(archetype *at)
Definition: arch.c:576
FILE * open_and_uncompress(const char *name, int flag, int *compressed)
Definition: porting.c:724
uint32 has_hit
Definition: player.h:183
static void set_first_map(object *op)
Definition: player.c:368
#define STR
Definition: living.h:41
sint32 value
Definition: object.h:201
sint8 magic
Definition: object.h:199
static object * find_arrow(object *op, const char *type)
Definition: player.c:1751
const char * name
Definition: object.h:322
#define EVENT_BORN
Definition: plugin.h:79
int hit_player(object *op, int dam, object *hitter, uint32 type, int full_hit)
Definition: attack.c:1868
#define MSG_TYPE_ATTACK
Definition: newclient.h:331
int cast_spell(object *op, object *caster, int dir, object *spell_ob, char *stringarg)
Definition: spell_util.c:1308
SockList inbuf
Definition: newserver.h:124
uint8 type
Definition: object.h:189
const char * buf
Definition: player.h:41
sint8 blocked_los[MAP_CLIENT_X][MAP_CLIENT_Y]
Definition: player.h:210
int hideability(object *ob)
Definition: player.c:3755
int ob_blocked(const object *ob, mapstruct *m, sint16 x, sint16 y)
Definition: map.c:525
#define PU_MAGIC_DEVICE
Definition: define.h:426
#define ST_GET_PASSWORD
Definition: define.h:892
sint32 food
Definition: living.h:89
#define FLAG_FREED
Definition: define.h:529
void key_confirm_quit(object *op, char key)
Definition: player.c:1278
#define ATNR_FIRE
Definition: attack.h:79
uint32 hide
Definition: object.h:238