Crossfire Server, Trunk
player.c
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2014 Mark Wedel and the Crossfire Development Team
5  * Copyright (c) 1992 Frank Tore Johansen
6  *
7  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
8  * welcome to redistribute it under certain conditions. For details, please
9  * see COPYING and LICENSE.
10  *
11  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
12  */
13 
20 #include "global.h"
21 
22 #include <assert.h>
23 #include <ctype.h>
24 #include <stddef.h>
25 #include <stdlib.h>
26 #include <string.h>
27 
28 #ifndef WIN32 /* ---win32 remove headers */
29 #include <pwd.h>
30 #endif
31 
32 #include "server.h"
33 #include "living.h"
34 #include "object.h"
35 #include "shared/newclient.h"
36 #include "shop.h"
37 #include "skills.h"
38 #include "sounds.h"
39 #include "spells.h"
40 #include "sproto.h"
41 
43 
44 static void kill_player_not_permadeath(object *op);
45 static void kill_player_permadeath(object *op);
46 static int action_makes_visible(object *op);
47 
56 player *find_player(const char *plname) {
57  return find_player_options(plname, 0, NULL);
58 }
59 
67 player *find_player_options(const char *plname, int options, const mapstruct *map) {
68  player *pl;
69  player *found = NULL;
70  size_t namelen = strlen(plname);
71  char name[MAX_BUF];
72 
73  for (pl = first_player; pl != NULL; pl = pl->next) {
75  continue;
76 
77  if (map != NULL && pl->ob->map != map)
78  continue;
79 
81  query_name(pl->ob, name, sizeof(name));
82  if (!strcmp(name, plname))
83  return pl;
84  continue;
85  }
86 
87  if (strlen(pl->ob->name) < namelen)
88  continue;
89 
90  if (!strcmp(pl->ob->name, plname))
91  return pl;
92 
93  if (!strncasecmp(pl->ob->name, plname, namelen)) {
94  if (found)
95  return NULL;
96 
97  found = pl;
98  }
99  }
100  return found;
101 }
102 
111 player *find_player_partial_name(const char *plname) {
112  return find_player_options(plname, FIND_PLAYER_PARTIAL_NAME, NULL);
113 }
114 
121  player *pl;
122 
123  for (pl = first_player; pl != NULL; pl = pl->next) {
124  if (&pl->socket == ns)
125  return pl;
126  }
127  return NULL;
128 }
129 
136 void display_motd(const object *op) {
137  char buf[MAX_BUF];
138  char motd[HUGE_BUF];
139  FILE *fp;
140  size_t size;
141 
142  snprintf(buf, sizeof(buf), "%s/%s", settings.confdir, settings.motd);
143  fp = fopen(buf, "r");
144  if (fp == NULL) {
145  return;
146  }
147  motd[0] = '\0';
148  size = 0;
149 
150  while (fgets(buf, MAX_BUF, fp) != NULL) {
151  if (*buf != '#') {
152  safe_strcat(motd, buf, &size, sizeof(motd));
153  }
154  }
155 
157  motd);
158  fclose(fp);
159 }
160 
167 void send_rules(const object *op) {
168  char buf[MAX_BUF];
169  char rules[HUGE_BUF];
170  FILE *fp;
171  size_t size;
172 
173  snprintf(buf, sizeof(buf), "%s/%s", settings.confdir, settings.rules);
174  fp = fopen(buf, "r");
175  if (fp == NULL) {
176  return;
177  }
178  rules[0] = '\0';
179  size = 0;
180 
181  while (fgets(buf, MAX_BUF, fp) != NULL) {
182  if (size+strlen(buf) >= HUGE_BUF) {
183  LOG(llevDebug, "Warning, rules size is > %d bytes.\n", HUGE_BUF);
184  break;
185  }
186 
187  if (*buf != '#') {
188  safe_strcat(rules, buf, &size, sizeof(rules));
189  }
190  }
191 
193  MSG_TYPE_ADMIN_RULES, rules);
194  fclose(fp);
195 }
196 
203 void send_news(const object *op) {
204  char buf[MAX_BUF];
205  char news[HUGE_BUF];
206  char subject[MAX_BUF];
207  FILE *fp;
208  size_t size;
209 
210  snprintf(buf, sizeof(buf), "%s/%s", settings.confdir, settings.news);
211  fp = fopen(buf, "r");
212  if (fp == NULL)
213  return;
214  news[0] = '\0';
215  subject[0] = '\0';
216  size = 0;
217  while (fgets(buf, MAX_BUF, fp) != NULL) {
218  if (*buf == '#')
219  continue;
220  if (*buf == '%') { /* send one news */
221  if (size > 0)
224  "%s:\n%s",
225  subject, news); /*send previously read news*/
226  safe_strncpy(subject, buf + 1, sizeof(subject));
227  strip_endline(subject);
228  size = 0;
229  news[0] = '\0';
230  } else {
231  if (size+strlen(buf) >= HUGE_BUF) {
232  LOG(llevDebug, "Warning, one news item has size > %d bytes.\n", HUGE_BUF);
233  break;
234  }
235  safe_strcat(news, buf, &size, sizeof(news));
236  }
237  }
238 
241  "%s:\n%s",
242  subject, news);
243  fclose(fp);
244 }
245 
254 int playername_ok(const char *cp) {
255  /* Don't allow - or _ as first character in the name */
256  if (*cp == '-' || *cp == '_')
257  return 0;
258 
259  for (; *cp != '\0'; cp++)
260  if (!isalnum(*cp)
261  && *cp != '-'
262  && *cp != '_')
263  return 0;
264  return 1;
265 }
266 
283  object *op = arch_to_object(get_player_archetype(NULL));
284  int i;
285 
286  if (!p) {
287  player *tmp;
288 
289  p = (player *)malloc(sizeof(player));
290  if (p == NULL)
292 
293  /* This adds the player in the linked list. There is extra
294  * complexity here because we want to add the new player at the
295  * end of the list - there is in fact no compelling reason that
296  * that needs to be done except for things like output of
297  * 'who'.
298  */
299  tmp = first_player;
300  while (tmp != NULL && tmp->next != NULL)
301  tmp = tmp->next;
302  if (tmp != NULL)
303  tmp->next = p;
304  else
305  first_player = p;
306 
307  p->next = NULL;
308  /* This only needs to be done on initial creation of player
309  * object. the callers of get_player() will copy over the
310  * socket structure to p->socket, and if this is an existing
311  * player object, that has been done. The call to
312  * roll_stats() below will try to send spell information to
313  * the client - if this is non zero (eg, garbage from not
314  * being cleared), that will cause problems. So just clear
315  * it, and no spell data is sent.
316  */
317  p->socket.monitor_spells = 0;
318  p->socket.account_chars = 0;
319  } else {
320  /* Only needed when reusing existing player. */
321  clear_player(p);
322  }
323 
324  /* Clears basically the entire player structure except
325  * for next and socket.
326  */
327  memset((void *)((char *)p+offsetof(player, maplevel)), 0, sizeof(player)-offsetof(player, maplevel));
328 
329  /* There are some elements we want initialized to non zero value -
330  * we deal with that below this point.
331  */
332  p->party = NULL;
335  p->swap_first = -1;
336 
337 #ifdef AUTOSAVE
338  p->last_save_tick = 9999999;
339 #endif
340 
341  strcpy(p->savebed_map, first_map_path); /* Init. respawn position */
342 
343  op->contr = p; /* this aren't yet in archetype */
344  p->ob = op;
345  op->speed_left = 0.5;
346  op->speed = 1.0;
347  op->direction = 5; /* So player faces south */
348  op->stats.wc = 2;
349  op->run_away = 25; /* Then we panic... */
350 
351  roll_stats(op);
353  clear_los(p);
354 
355  p->gen_sp_armour = 10;
356  p->last_speed = -1;
357  p->shoottype = range_none;
358  p->bowtype = bow_normal;
359  p->petmode = pet_normal;
360  p->listening = 10;
361  p->last_weapon_sp = -1;
362  p->peaceful = 1; /* default peaceful */
363  p->do_los = 1;
364  p->no_shout = 0; /* default can shout */
365  p->language = -1; // find default language
366  p->unarmed_skill = NULL;
367  p->ticks_played = 0;
368 
369  strncpy(p->title, op->arch->clone.name, sizeof(p->title)-1);
370  p->title[sizeof(p->title)-1] = '\0';
371  op->race = add_string(op->arch->clone.race);
372 
374 
375  /* we need to clear these to -1 and not zero - otherwise,
376  * if a player quits and starts a new character, we wont
377  * send new values to the client, as things like exp start
378  * at zero.
379  */
380  for (i = 0; i < MAX_SKILLS; i++) {
381  p->last_skill_exp[i] = -1;
382  p->last_skill_ob[i] = NULL;
383  }
384  for (i = 0; i < NROFATTACKS; i++) {
385  p->last_resist[i] = -1;
386  }
387  p->last_stats.exp = -1;
388  p->last_weight = (uint32_t)-1;
389 
390  p->socket.update_look = 0;
391  p->socket.look_position = 0;
392  return p;
393 }
394 
401 void set_first_map(object *op) {
402  strcpy(op->contr->maplevel, first_map_path);
403  op->x = -1;
404  op->y = -1;
406 }
407 
420 static void set_player_socket(player *p, socket_struct *ns) {
421  if (p->socket.account_chars) {
423  }
424 
425  memcpy(&p->socket, ns, sizeof(socket_struct));
426 
427  /* The memcpy above copies the reference to faces sent. So we need to clear
428  * that pointer in ns, otherwise we get a double free.
429  */
430  ns->faces_sent = NULL;
431  ns->host = strdup_local("");
432  ns->account_name = strdup_local("");
433  ns->account_chars = NULL; // If not NULL, the reference is now kept by p
434 
435  if (p->socket.faces_sent == NULL)
437 
438  /* Needed because the socket we just copied over needs to be cleared.
439  * Note that this can result in a client reset if there is partial data
440  * on the incoming socket.
441  */
443 
444 
445 }
446 
464  player *p;
465 
466  p = get_player(NULL);
467  ns->status = Ns_Avail;
468  set_player_socket(p, ns);
469 
471 
472  if (!(flags & ADD_PLAYER_NO_MAP))
473  set_first_map(p->ob);
474 
476 
477  /* In this case, the client is provide all the informatin for the
478  * new character, so just return it. Do not display any messages,
479  * etc
480  */
482  return p;
483 
484  if (flags & ADD_PLAYER_NEW) {
485  roll_again(p->ob);
487  } else {
488  send_rules(p->ob);
489  send_news(p->ob);
490  display_motd(p->ob);
491  get_name(p->ob);
492  }
493  return p;
494 }
495 
507  archetype *start = at;
508 
509  for (;;) {
510  at = get_next_archetype(at);
511  if (at == NULL) {
512  at = get_next_archetype(at);
513  }
514  if (at->clone.type == PLAYER)
515  return at;
516  if (at == start) {
517  LOG(llevError, "No Player archetypes\n");
518  exit(-1);
519  }
520  }
521 }
522 
531 object *get_nearest_player(object *mon) {
532  object *op = NULL;
533  player *pl = NULL;
534  objectlink *list, *ol;
535  unsigned lastdist;
536  rv_vector rv;
537 
538  list = get_friends_of(NULL);
539  if (!list) {
540  return NULL;
541  }
542 
543  for (ol = list, lastdist = 1000; ol != NULL; ol = ol->next) {
544  if (QUERY_FLAG(ol->ob, FLAG_FREED) || !QUERY_FLAG(ol->ob, FLAG_FRIENDLY)) {
545  continue;
546  }
547 
548  /* Remove special check for player from this. First, it looks to cause
549  * some crashes (ol->ob->contr not set properly?), but secondly, a more
550  * complicated method of state checking would be needed in any case -
551  * as it was, a clever player could type quit, and the function would
552  * skip them over while waiting for confirmation. Remove
553  * on_same_map check, as monster_can_detect_enemy() also does this
554  */
555  if (!monster_can_detect_enemy(mon, ol->ob, &rv))
556  continue;
557 
558  if (lastdist > rv.distance) {
559  op = ol->ob;
560  lastdist = rv.distance;
561  }
562  }
564  for (pl = first_player; pl != NULL; pl = pl->next) {
565  if (monster_can_detect_enemy(mon, pl->ob, &rv)) {
566  if (lastdist > rv.distance) {
567  op = pl->ob;
568  lastdist = rv.distance;
569  }
570  }
571  }
572  return op;
573 }
574 
575 object *get_nearest_criminal(object *mon) {
576  object *op = NULL;
577  for (player *pl = first_player; pl != NULL; pl = pl->next) {
578  rv_vector rv;
579  if (monster_can_detect_enemy(mon, pl->ob, &rv) && is_criminal(pl->ob)) {
580  op = pl->ob;
581  }
582  }
583  return op;
584 }
585 
595 #define DETOUR_AMOUNT 2
596 
610 #define MAX_SPACES 50
611 
643 int path_to_player(object *mon, object *pl, unsigned mindiff) {
644  rv_vector rv;
645  int16_t x, y;
646  int lastx, lasty, dir, i, diff, firstdir = 0, lastdir, max = MAX_SPACES, mflags, blocked;
647  mapstruct *m, *lastmap;
648 
649  if (!get_rangevector(mon, pl, &rv, 0))
650  return 0;
651 
652  if (rv.distance < mindiff)
653  return 0;
654 
655  x = mon->x;
656  y = mon->y;
657  m = mon->map;
658  dir = rv.direction;
659  lastdir = firstdir = rv.direction; /* perhaps we stand next to pl, init firstdir too */
660  diff = MAX(FABS(rv.distance_x), FABS(rv.distance_y));
661  /* If we can't solve it within the search distance, return now. */
662  if (diff > max)
663  return 0;
664  while (diff > 1 && max > 0) {
665  lastx = x;
666  lasty = y;
667  lastmap = m;
668  x = lastx+freearr_x[dir];
669  y = lasty+freearr_y[dir];
670 
671  mflags = get_map_flags(m, &m, x, y, &x, &y);
672  blocked = (mflags&P_OUT_OF_MAP) ? MOVE_ALL : GET_MAP_MOVE_BLOCK(m, x, y);
673 
674  /* Space is blocked - try changing direction a little */
675  if ((mflags&P_OUT_OF_MAP)
676  || ((OB_TYPE_MOVE_BLOCK(mon, blocked) || (mflags&P_IS_ALIVE))
677  && (m == mon->map && blocked_link(mon, m, x, y)))) {
678  /* recalculate direction from last good location. Possible
679  * we were not traversing ideal location before.
680  */
681  if (get_rangevector_from_mapcoord(lastmap, lastx, lasty, pl, &rv, 0) && rv.direction != dir) {
682  /* OK - says direction should be different - lets reset the
683  * the values so it will try again.
684  */
685  x = lastx;
686  y = lasty;
687  m = lastmap;
688  dir = firstdir = rv.direction;
689  } else {
690  /* direct path is blocked - try taking a side step to
691  * either the left or right.
692  * Note increase the values in the loop below to be
693  * more than -1/1 respectively will mean the monster takes
694  * bigger detour. Have to be careful about these values getting
695  * too big (3 or maybe 4 or higher) as the monster may just try
696  * stepping back and forth
697  */
698  for (i = -DETOUR_AMOUNT; i <= DETOUR_AMOUNT; i++) {
699  if (i == 0)
700  continue; /* already did this, so skip it */
701  /* Use lastdir here - otherwise,
702  * since the direction that the creature should move in
703  * may change, you could get infinite loops.
704  * ie, player is northwest, but monster can only
705  * move west, so it does that. It goes some distance,
706  * gets blocked, finds that it should move north,
707  * can't do that, but now finds it can move east, and
708  * gets back to its original point. lastdir contains
709  * the last direction the creature has successfully
710  * moved.
711  */
712 
713  x = lastx+freearr_x[absdir(lastdir+i)];
714  y = lasty+freearr_y[absdir(lastdir+i)];
715  m = lastmap;
716  mflags = get_map_flags(m, &m, x, y, &x, &y);
717  if (mflags&P_OUT_OF_MAP)
718  continue;
719  blocked = GET_MAP_MOVE_BLOCK(m, x, y);
720  if (OB_TYPE_MOVE_BLOCK(mon, blocked))
721  continue;
722  if (mflags&P_IS_ALIVE)
723  continue;
724 
725  if (m == mon->map && blocked_link(mon, m, x, y))
726  break;
727  }
728  /* go through entire loop without finding a valid
729  * sidestep to take - thus, no valid path.
730  */
731  if (i == (DETOUR_AMOUNT+1))
732  return 0;
733  diff--;
734  lastdir = dir;
735  max--;
736  if (!firstdir)
737  firstdir = dir+i;
738  } /* else check alternate directions */
739  } /* if blocked */
740  else {
741  /* we moved towards creature, so diff is less */
742  diff--;
743  max--;
744  lastdir = dir;
745  if (!firstdir)
746  firstdir = dir;
747  }
748  if (diff <= 1) {
749  /* Recalculate diff (distance) because we may not have actually
750  * headed toward player for entire distance.
751  */
752  if (!get_rangevector_from_mapcoord(m, x, y, pl, &rv, 0))
753  return 0;
754  diff = MAX(FABS(rv.distance_x), FABS(rv.distance_y));
755  }
756  if (diff > max)
757  return 0;
758  }
759  /* If we reached the max, didn't find a direction in time */
760  if (!max)
761  return 0;
762 
763  return firstdir;
764 }
765 
776 void give_initial_items(object *pl, treasurelist *items) {
777  if (pl->randomitems != NULL)
779 
780  FOR_INV_PREPARE(pl, op) {
781  /* Forces get applied per default, unless they have the
782  * flag "neutral" set. Sorry but I can't think of a better way
783  */
784  if (op->type == FORCE && !QUERY_FLAG(op, FLAG_NEUTRAL))
786 
787  /* we never give weapons/armour if these cannot be used
788  * by this player due to race restrictions
789  */
790  if (pl->type == PLAYER) {
793  || (!QUERY_FLAG(pl, FLAG_USE_SHIELD) && IS_SHIELD(op))) {
794  object_remove(op);
796  continue;
797  }
798  }
799 
800  /* This really needs to be better - we should really give
801  * a substitute spellbook. The problem is that we don't really
802  * have a good idea what to replace it with (need something like
803  * a first level treasurelist for each skill.)
804  * remove duplicate skills also
805  */
806  if (op->type == SPELLBOOK || op->type == SKILL) {
807  int found;
808 
809  found = 0;
810  // Make sure we set flags that are checked by object_can_merge
811  // *before* we run object_can_merge. Otherwise, we can get two
812  // entries of the same skill.
813  if (op->type == SKILL) {
815  op->stats.exp = 0;
816  op->level = 1;
817  // Since this also happens to the invisible skills, we need this so that the flags match.
819  }
821  if (object_can_merge(op, tmp)) {
822  found = 1;
823  break;
824  }
826  if (found) {
827  LOG(llevError, "give_initial_items: Removing duplicate object %s\n", op->name);
828  object_remove(op);
830  continue;
831  }
832  if (op->nrof > 1)
833  op->nrof = 1;
834  }
835 
836  if (op->type == SPELLBOOK && op->inv) {
838  }
839 
840  /* Give starting characters identified, uncursed, and undamned
841  * items. Just don't identify gold or silver, or it won't be
842  * merged properly.
843  */
844  if (is_identifiable_type(op)) {
848  }
849  /* lock all 'normal items by default */
850  else
852  } FOR_INV_FINISH(); /* for loop of objects in player inv */
853 
854  /* Need to set up the skill pointers */
856 
864  FOR_INV_FINISH();
865 }
866 
873 void get_name(object *op) {
875  send_query(&op->contr->socket, 0, i18n(op, "What is your name?\n:"));
876 }
877 
884 void get_password(object *op) {
886  send_query(&op->contr->socket, CS_QUERY_HIDEINPUT, i18n(op, "What is your password?\n:"));
887 }
888 
895 void play_again(object *op) {
896  SockList sl;
897 
898  op->contr->socket.status = Ns_Add;
900  op->chosen_skill = NULL;
901 
902  /*
903  * For old clients, ask if they want to play again.
904  * For clients with account support, just return to character seletion (see below).
905  */
906  if (op->contr->socket.login_method == 0) {
907  send_query(&op->contr->socket, CS_QUERY_SINGLECHAR, i18n(op, "Do you want to play again (a/q)?"));
908  }
909  /* a bit of a hack, but there are various places early in th
910  * player creation process that a user can quit (eg, roll
911  * stats) that isn't removing the player. Taking a quick
912  * look, there are many places that call play_again without
913  * removing the player - it probably makes more sense
914  * to leave it to play_again to remove the object in all
915  * cases.
916  */
917  if (!QUERY_FLAG(op, FLAG_REMOVED))
918  object_remove(op);
919  /* Need to set this to null - otherwise, it could point to garbage,
920  * and draw() doesn't check to see if the player is removed, only if
921  * the map is null or not swapped out.
922  */
923  op->map = NULL;
924 
925  SockList_Init(&sl);
926  SockList_AddString(&sl, "player ");
927  SockList_AddInt(&sl, 0);
928  SockList_AddInt(&sl, 0);
929  SockList_AddInt(&sl, 0);
930  SockList_AddChar(&sl, 0);
931 
932  Send_With_Handling(&op->contr->socket, &sl);
933  SockList_Term(&sl);
934 
935  if (op->contr->socket.login_method > 0) {
936  receive_play_again(op, 'a');
937  }
938 }
939 
948 void receive_play_again(object *op, char key) {
949  if (key == 'q' || key == 'Q') {
951  leave(op->contr, 0); /* ericserver will draw the message */
952  return;
953  } else if (key == 'a' || key == 'A') {
954  player *pl = op->contr;
955  const char *name = op->name;
956 
960  pl = get_player(pl);
961  op = pl->ob;
963  op->contr->password[0] = '~';
964  FREE_AND_CLEAR_STR(op->name);
965  FREE_AND_CLEAR_STR(op->name_pl);
966  if (pl->socket.login_method >= 1 && pl->socket.account_name != NULL) {
967  /* If we are using new login, we send the
968  * list of characters to the client - this should
969  * result in the client popping up this list so
970  * the player can choose which one to play - better
971  * than going to legacy login code.
972  * If the account_name is NULL, it means the client
973  * says it uses account but started playing without logging in.
974  */
977  } else {
978  /* Lets put a space in here */
980  "\n");
981  get_name(op);
982  set_first_map(op);
983  }
984  op->name = name; /* Already added a refcount above */
985  op->name_pl = add_string(name);
986  } else {
987  /* user pressed something else so just ask again... */
988  play_again(op);
989  }
990 }
991 
998 void confirm_password(object *op) {
1000  send_query(&op->contr->socket, CS_QUERY_HIDEINPUT, i18n(op, "Please type your password again.\n:"));
1001 }
1002 
1013 int get_party_password(object *op, partylist *party) {
1014  if (*party_get_password(party) == '\0') {
1015  return 0;
1016  }
1017 
1019  op->contr->party_to_join = party;
1020  send_query(&op->contr->socket, CS_QUERY_HIDEINPUT, i18n(op, "What is the password?\n:"));
1021  return 1;
1022 }
1023 
1030 int roll_stat(void) {
1031  int roll[4], i, low_index, k;
1032 
1033  for (i = 0; i < 4; ++i)
1034  roll[i] = (int)RANDOM()%6+1;
1035 
1036  for (i = 0, low_index = 0, k = 7; i < 4; ++i)
1037  if (roll[i] < k)
1038  k = roll[i],
1039  low_index = i;
1040 
1041  for (i = 0, k = 0; i < 4; ++i) {
1042  if (i != low_index)
1043  k += roll[i];
1044  }
1045  return k;
1046 }
1047 
1054 void roll_stats(object *op) {
1055  int sum = 0;
1056  int i = 0, j = 0;
1057  int statsort[7];
1058 
1059  do {
1060  op->stats.Str = roll_stat();
1061  op->stats.Dex = roll_stat();
1062  op->stats.Int = roll_stat();
1063  op->stats.Con = roll_stat();
1064  op->stats.Wis = roll_stat();
1065  op->stats.Pow = roll_stat();
1066  op->stats.Cha = roll_stat();
1067  sum = op->stats.Str+op->stats.Dex+op->stats.Int+op->stats.Con+op->stats.Wis+op->stats.Pow+op->stats.Cha;
1068  } while (sum != settings.roll_stat_points);
1069 
1070  /* Sort the stats so that rerolling is easier... */
1071  statsort[0] = op->stats.Str;
1072  statsort[1] = op->stats.Dex;
1073  statsort[2] = op->stats.Int;
1074  statsort[3] = op->stats.Con;
1075  statsort[4] = op->stats.Wis;
1076  statsort[5] = op->stats.Pow;
1077  statsort[6] = op->stats.Cha;
1078 
1079  /* a quick and dirty bubblesort? */
1080  do {
1081  if (statsort[i] < statsort[i+1]) {
1082  j = statsort[i];
1083  statsort[i] = statsort[i+1];
1084  statsort[i+1] = j;
1085  i = 0;
1086  } else {
1087  i++;
1088  }
1089  } while (i < 6);
1090 
1091  op->stats.Str = statsort[0];
1092  op->stats.Dex = statsort[1];
1093  op->stats.Con = statsort[2];
1094  op->stats.Int = statsort[3];
1095  op->stats.Wis = statsort[4];
1096  op->stats.Pow = statsort[5];
1097  op->stats.Cha = statsort[6];
1098 
1099  op->contr->orig_stats.Str = op->stats.Str;
1100  op->contr->orig_stats.Dex = op->stats.Dex;
1101  op->contr->orig_stats.Int = op->stats.Int;
1102  op->contr->orig_stats.Con = op->stats.Con;
1103  op->contr->orig_stats.Wis = op->stats.Wis;
1104  op->contr->orig_stats.Pow = op->stats.Pow;
1105  op->contr->orig_stats.Cha = op->stats.Cha;
1106 
1107  op->level = 1;
1108  op->stats.exp = 0;
1109  op->stats.ac = 0;
1110 
1111  op->contr->levhp[1] = 9;
1112  op->contr->levsp[1] = 6;
1113  op->contr->levgrace[1] = 3;
1114 
1115  fix_object(op);
1116  op->stats.hp = op->stats.maxhp;
1117  op->stats.sp = op->stats.maxsp;
1118  op->stats.grace = op->stats.maxgrace;
1119  op->contr->orig_stats = op->stats;
1120 }
1121 
1128 void roll_again(object *op) {
1129  esrv_new_player(op->contr, 0);
1130  send_query(&op->contr->socket, CS_QUERY_SINGLECHAR, i18n(op, "<y> to roll new stats <n> to use stats\n<1-7> <1-7> to swap stats.\nRoll again (y/n/1-7)? "));
1131 }
1132 
1142 static void swap_stat(object *op, int swap_second) {
1143  signed char tmp;
1144 
1145  if (op->contr->swap_first == -1) {
1146  LOG(llevError, "player.c:swap_stat() - swap_first is -1\n");
1147  return;
1148  }
1149 
1150  tmp = get_attr_value(&op->contr->orig_stats, op->contr->swap_first);
1151 
1152  set_attr_value(&op->contr->orig_stats, op->contr->swap_first, get_attr_value(&op->contr->orig_stats, swap_second));
1153 
1154  set_attr_value(&op->contr->orig_stats, swap_second, tmp);
1155 
1157  "%s done\n",
1158  short_stat_name[swap_second]);
1159 
1160  op->stats.Str = op->contr->orig_stats.Str;
1161  op->stats.Dex = op->contr->orig_stats.Dex;
1162  op->stats.Con = op->contr->orig_stats.Con;
1163  op->stats.Int = op->contr->orig_stats.Int;
1164  op->stats.Wis = op->contr->orig_stats.Wis;
1165  op->stats.Pow = op->contr->orig_stats.Pow;
1166  op->stats.Cha = op->contr->orig_stats.Cha;
1167  op->stats.ac = 0;
1168 
1169  op->level = 1;
1170  op->stats.exp = 0;
1171  op->stats.ac = 0;
1172 
1173  op->contr->levhp[1] = 9;
1174  op->contr->levsp[1] = 6;
1175  op->contr->levgrace[1] = 3;
1176 
1177  fix_object(op);
1178  op->stats.hp = op->stats.maxhp;
1179  op->stats.sp = op->stats.maxsp;
1180  op->stats.grace = op->stats.maxgrace;
1181  op->contr->orig_stats = op->stats;
1182  op->contr->swap_first = -1;
1183 }
1184 
1200 void key_roll_stat(object *op, char key) {
1201  int keynum = key-'0';
1202  static const int8_t stat_trans[] = {
1203  -1,
1204  STRENGTH,
1205  DEXTERITY,
1206  CONSTITUTION,
1207  INTELLIGENCE,
1208  WISDOM,
1209  POWER,
1210  CHARISMA,
1211  };
1212 
1213  if (keynum > 0 && keynum <= 7) {
1214  if (op->contr->swap_first == -1) {
1215  op->contr->swap_first = stat_trans[keynum];
1217  "%s ->",
1218  short_stat_name[stat_trans[keynum]]);
1219  } else
1220  swap_stat(op, stat_trans[keynum]);
1221 
1222  send_query(&op->contr->socket, CS_QUERY_SINGLECHAR, "");
1223  return;
1224  }
1225  switch (key) {
1226  case 'n':
1227  case 'N': {
1228  SET_FLAG(op, FLAG_WIZ);
1229  if (op->map == NULL) {
1230  LOG(llevError, "Map == NULL in state 2\n");
1231  break;
1232  }
1233 
1234  SET_ANIMATION(op, 2); /* So player faces south */
1235  /* Enter exit adds a player otherwise */
1236  add_statbonus(op);
1237  send_query(&op->contr->socket, CS_QUERY_SINGLECHAR, i18n(op, "Now choose a character.\nPress any key to change outlook.\nPress `d' when you're pleased.\n"));
1239  if (op->msg)
1242  op->msg);
1243  return;
1244  }
1245  case 'y':
1246  case 'Y':
1247  roll_stats(op);
1248  send_query(&op->contr->socket, CS_QUERY_SINGLECHAR, "");
1249  return;
1250 
1251  case 'q':
1252  case 'Q':
1253  play_again(op);
1254  return;
1255 
1256  default:
1257  send_query(&op->contr->socket, CS_QUERY_SINGLECHAR, i18n(op, "Yes, No, Quit or 1-6. Roll again?"));
1258  return;
1259  }
1260  return;
1261 }
1262 
1276 void key_change_class(object *op, char key) {
1277  int tmp_loop;
1278 
1279  if (key == 'q' || key == 'Q') {
1280  object_remove(op);
1281  play_again(op);
1282  return;
1283  }
1284  if (key == 'd' || key == 'D') {
1285  char buf[MAX_BUF];
1286 
1287  /* this must before then initial items are given */
1288  esrv_new_player(op->contr, op->weight+op->carrying);
1289  create_treasure(find_treasurelist("starting_wealth"), op, 0, 0, 0);
1290 
1291  /* Here we handle the BORN global event */
1293 
1294  /* We then generate a LOGIN event */
1295  events_execute_global_event(EVENT_LOGIN, op->contr, op->contr->socket.host);
1296  player_set_state(op->contr, ST_PLAYING);
1297 
1298  object_set_msg(op, NULL);
1299 
1300  /* We create this now because some of the unique maps will need it
1301  * to save here.
1302  */
1303  snprintf(buf, sizeof(buf), "%s/%s/%s", settings.localdir, settings.playerdir, op->name);
1305 
1306 #ifdef AUTOSAVE
1307  op->contr->last_save_tick = pticks;
1308 #endif
1311  "Welcome to Crossfire!\n Press `?' for help\n");
1312 
1315  "%s entered the game.", op->name);
1316 
1318  give_initial_items(op, op->randomitems);
1321  fix_object(op);
1322 
1323  /* This moves the player to a different start map, if there
1324  * is one for this race
1325  */
1326  if (*first_map_ext_path) {
1327  object *tmp;
1328  char mapname[MAX_BUF];
1329  mapstruct *oldmap;
1330 
1331  oldmap = op->map;
1332 
1333  snprintf(mapname, MAX_BUF-1, "%s/%s", first_map_ext_path, op->arch->name);
1334  /*printf("%s\n", mapname);*/
1335  tmp = object_new();
1337  EXIT_X(tmp) = op->x;
1338  EXIT_Y(tmp) = op->y;
1339  enter_exit(op, tmp);
1340 
1341  if (oldmap != op->map) {
1342  /* map exists, update bed of reality location, in case player dies */
1343  op->contr->bed_x = op->x;
1344  op->contr->bed_y = op->y;
1345  strlcpy(op->contr->savebed_map, mapname, sizeof(op->contr->savebed_map));
1346  }
1347 
1349  } else {
1350  LOG(llevDebug, "first_map_ext_path not set\n");
1351  }
1352  return;
1353  }
1354 
1355  /* Following actually changes the race - this is the default command
1356  * if we don't match with one of the options above.
1357  */
1358 
1359  tmp_loop = 0;
1360  while (!tmp_loop) {
1361  const char *name = add_string(op->name);
1362  int x = op->x, y = op->y;
1363 
1365  object_remove(op);
1366  /* get_player_archetype() is really misnamed - it will
1367  * get the next archetype from the list.
1368  */
1369  op->arch = get_player_archetype(op->arch);
1370  object_copy(&op->arch->clone, op);
1371  op->stats = op->contr->orig_stats;
1372  free_string(op->name);
1373  op->name = name;
1374  free_string(op->name_pl);
1375  op->name_pl = add_string(name);
1376  SET_ANIMATION(op, 2); /* So player faces south */
1377  object_insert_in_map_at(op, op->map, op, 0, x, y);
1378  strncpy(op->contr->title, op->arch->clone.name, sizeof(op->contr->title)-1);
1379  op->contr->title[sizeof(op->contr->title)-1] = '\0';
1380  add_statbonus(op);
1381  tmp_loop = allowed_class(op);
1382  }
1385  fix_object(op);
1386  op->stats.hp = op->stats.maxhp;
1387  op->stats.sp = op->stats.maxsp;
1388  op->stats.grace = 0;
1389  if (op->msg)
1391  op->msg);
1392  send_query(&op->contr->socket, CS_QUERY_SINGLECHAR, i18n(op, "Press any key for the next race.\nPress `d' to play this race.\n"));
1393 }
1394 
1416 int check_race_and_class(living *stats, archetype *race, archetype *opclass)
1417 {
1418  int i, stat, failure=0;
1419 
1420  for (i = 0; i < NUM_STATS; i++) {
1421  stat = get_attr_value(stats, i);
1422  if (race)
1423  stat += get_attr_value(&race->clone.stats, i);
1424 
1425  if (opclass)
1426  stat += get_attr_value(&opclass->clone.stats, i);
1427 
1428  set_attr_value(stats, i, stat);
1429 
1430  /* We process all stats, regardless if there is a failure
1431  * or not.
1432  */
1433  if (stat < MIN_STAT) failure=1;
1434 
1435  /* Maybe this should be an error? Player is losing
1436  * some stats points here, but it is legal.
1437  */
1438  if (stat > settings.max_stat) stat = settings.max_stat;
1439  }
1440  return failure;
1441 
1442 }
1443 
1466 int apply_race_and_class(object *op, archetype *race, archetype *opclass, living *stats)
1467 {
1468  const char *name = add_string(op->name);
1469  char buf[MAX_BUF];
1470  object *inv;
1471 
1472  /* Free any objects in character inventory - they
1473  * shouldn't have any, but there is the potential that
1474  * we give them objects below and then get a creation
1475  * failure (stat out of range), in which case
1476  * those objects would be in the inventory.
1477  */
1478  while (op->inv) {
1479  inv = op->inv;
1480  object_remove(inv);
1481  object_free(inv, 0);
1482  }
1483 
1484  object_copy(&race->clone, op);
1485  free_string(op->name);
1486  op->name = name;
1487  free_string(op->name_pl);
1488  op->name_pl = add_string(name);
1489  SET_ANIMATION(op, 2); /* So player faces south */
1490  strlcpy(op->contr->title, op->arch->clone.name, sizeof(op->contr->title));
1491 
1492  if (stats) {
1493  /* Copy over the stats. Use this instead a memcpy because
1494  * we only want to copy over a few specific stats, and
1495  * leave things like maxhp, maxsp, etc, unchanged.
1496  */
1497  int i, stat;
1498  for (i = 0; i < NUM_STATS; i++) {
1499  stat = get_attr_value(stats, i);
1500  set_attr_value(&op->stats, i, stat);
1501  set_attr_value(&op->contr->orig_stats, i, stat);
1502  }
1503  } else {
1504  /* Note that this will repeated increase the stat values
1505  * if the caller does not reset them. Only do this
1506  * if stats is not provided - if stats is provided, those
1507  * are already adjusted.
1508  */
1509  add_statbonus(op);
1510 
1511  /* Checks that all stats are greater than 1. Once again,
1512  * only do this if stats are not provided
1513  */
1514  if (!allowed_class(op)) return 1;
1515  }
1516 
1518  op->stats.hp = op->stats.maxhp;
1519  op->stats.sp = op->stats.maxsp;
1520  op->stats.grace = 0;
1521 
1522  /* this must before then initial items are given */
1523  esrv_new_player(op->contr, op->weight+op->carrying);
1524  create_treasure(find_treasurelist("starting_wealth"), op, 0, 0, 0);
1525 
1526  /* This has to be done before class, otherwise the NOCLASSFACECHANGE
1527  * object is not in the inventory, and racial face will get overwritten.
1528  */
1529  give_initial_items(op, op->randomitems);
1530 
1531  if (stats) {
1532  /* Apply class information */
1534  } else {
1535  apply_changes_to_player(op, &opclass->clone, 0);
1536 
1537  /* Checks that all stats are greater than 1 */
1538  if (!allowed_class(op)) return 2;
1539  }
1540 
1541  /* Here we handle the BORN global event */
1543 
1544  /* We then generate a LOGIN event */
1545  events_execute_global_event(EVENT_LOGIN, op->contr, op->contr->socket.host);
1546 
1547  object_set_msg(op, NULL);
1548 
1549  /* We create this now because some of the unique maps will need it
1550  * to save here.
1551  */
1552  snprintf(buf, sizeof(buf), "%s/%s/%s", settings.localdir, settings.playerdir, op->name);
1554 
1555 #ifdef AUTOSAVE
1556  op->contr->last_save_tick = pticks;
1557 #endif
1558 
1561  fix_object(op);
1562 
1565  esrv_add_spells(op->contr, NULL);
1566 
1567  return 0;
1568 
1569 }
1570 
1579 void key_confirm_quit(object *op, char key) {
1580  char buf[MAX_BUF];
1581  mapstruct *mp, *next;
1582 
1583  // this was tested when 'quit' command was issued, but better safe than sorry.
1584  if (QUERY_FLAG(op, FLAG_WIZ)) {
1585  player_set_state(op->contr, ST_PLAYING);
1586  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_LOGIN, "Can't quit when in DM mode.");
1587  return;
1588  }
1589 
1590  if (key != 'y' && key != 'Y' && key != 'q' && key != 'Q') {
1591  player_set_state(op->contr, ST_PLAYING);
1593  "OK, continuing to play.");
1594  return;
1595  }
1596 
1599  object_remove(op);
1600  op->direction = 0;
1602  "%s quits the game.",
1603  op->name);
1604 
1605  strcpy(op->contr->killer, "quit");
1606  hiscore_check(op, 0);
1607  party_leave(op);
1608  if (settings.set_title == TRUE)
1609  player_set_own_title(op->contr, "");
1610 
1611 
1612  /* We need to hunt for any per player unique maps in memory and
1613  * get rid of them. The trailing slash in the path is intentional,
1614  * so that players named 'Ab' won't match against players 'Abe' pathname
1615  */
1616  snprintf(buf, sizeof(buf), "%s/%s/%s/", settings.localdir, settings.playerdir, op->name);
1617  for (mp = first_map; mp != NULL; mp = next) {
1618  next = mp->next;
1619  if (!strncmp(mp->path, buf, strlen(buf)))
1620  delete_map(mp);
1621  }
1622 
1623  delete_character(op->name);
1624 
1625  /* Remove player from account list and send back data if needed */
1626  if (op->contr->socket.account_chars != NULL) {
1627  account_char_remove(op->contr->socket.account_chars, op->name);
1628  account_char_save(op->contr->socket.account_chars);
1629  /* char information is reloaded in send_account_players below */
1630  account_char_free(op->contr->socket.account_chars);
1631  op->contr->socket.account_chars = NULL;
1632  account_remove_player(op->contr->socket.account_name, op->name);
1633  send_account_players(&op->contr->socket);
1634  }
1635 
1636  play_again(op);
1637 }
1638 
1645 static void flee_player(object *op) {
1646  int dir, diff;
1647  rv_vector rv;
1648 
1649  if (op->stats.hp < 0) {
1650  LOG(llevDebug, "Fleeing player is dead.\n");
1652  return;
1653  }
1654 
1655  if (op->enemy == NULL) {
1656  LOG(llevDebug, "Fleeing player had no enemy.\n");
1658  return;
1659  }
1660 
1661  /* Seen some crashes here. Since we don't store an
1662  * op->enemy_count, it is possible that something destroys the
1663  * actual enemy, and the object is recycled.
1664  */
1665  if (op->enemy->map == NULL) {
1667  object_set_enemy(op, NULL);
1668  return;
1669  }
1670 
1671  if (!(random_roll(0, 4, op, PREFER_LOW)) && did_make_save(op, op->level, 0)) {
1672  object_set_enemy(op, NULL);
1674  return;
1675  }
1676  if (!get_rangevector(op, op->enemy, &rv, 0)) {
1677  object_set_enemy(op, NULL);
1679  return;
1680  }
1681 
1682  dir = absdir(4+rv.direction);
1683  for (diff = 0; diff < 3; diff++) {
1684  int m = 1-(RANDOM()&2);
1685  if (move_ob(op, absdir(dir+diff*m), op)
1686  || (diff == 0 && move_ob(op, absdir(dir-diff*m), op))) {
1687  return;
1688  }
1689  }
1690  /* Cornered, get rid of scared */
1692  object_set_enemy(op, NULL);
1693 }
1694 
1704 int check_pick(object *op) {
1705  tag_t op_tag;
1706  int stop = 0;
1707  int j, k, wvratio, current_ratio;
1708  char putstring[128], tmpstr[16];
1709 
1710  /* if you're flying, you can't pick up anything */
1711  if (op->move_type&MOVE_FLYING)
1712  return 1;
1713  /* If not a player, don't check anything. */
1714  if (!op->contr) {
1715  return 1;
1716  }
1717 
1718  op_tag = op->count;
1719 
1721  if (object_was_destroyed(op, op_tag))
1722  return 0;
1723 
1724  if (!object_can_pick(op, tmp))
1725  continue;
1726 
1727  if (op->contr->search_str[0] != '\0' && settings.search_items == TRUE) {
1728  if (object_matches_string(op, tmp, op->contr->search_str))
1729  pick_up(op, tmp);
1730  continue;
1731  }
1732 
1733  /* high not bit set? We're using the old autopickup model */
1734  if (!(op->contr->mode&PU_NEWMODE)) {
1735  switch (op->contr->mode) {
1736  case 0:
1737  return 1; /* don't pick up */
1738 
1739  case 1:
1740  pick_up(op, tmp);
1741  return 1;
1742 
1743  case 2:
1744  pick_up(op, tmp);
1745  return 0;
1746 
1747  case 3:
1748  return 0; /* stop before pickup */
1749 
1750  case 4:
1751  pick_up(op, tmp);
1752  break;
1753 
1754  case 5:
1755  pick_up(op, tmp);
1756  stop = 1;
1757  break;
1758 
1759  case 6:
1762  pick_up(op, tmp);
1763  break;
1764 
1765  case 7:
1766  if (tmp->type == MONEY || tmp->type == GEM)
1767  pick_up(op, tmp);
1768  break;
1769 
1770  default:
1771  /* use value density */
1772  if (!QUERY_FLAG(tmp, FLAG_UNPAID)
1773  && (price_base(tmp)*100/(tmp->weight*MAX(tmp->nrof, 1))) >= op->contr->mode)
1774  pick_up(op, tmp);
1775  }
1776  } else { /* old model */
1777  /* NEW pickup handling */
1778  if (op->contr->mode&PU_DEBUG) {
1779  /* some debugging code to figure out item information */
1781  "item name: %s item type: %d weight/value: %d",
1782  tmp->name ? tmp->name : tmp->arch->name, tmp->type,
1783  (int)(price_base(tmp)*100/(tmp->weight*MAX(tmp->nrof, 1))));
1784 
1785 
1786  snprintf(putstring, sizeof(putstring), "...flags: ");
1787  for (k = 0; k < 4; k++) {
1788  for (j = 0; j < 32; j++) {
1789  if ((tmp->flags[k]>>j)&0x01) {
1790  snprintf(tmpstr, sizeof(tmpstr), "%d ", k*32+j);
1791  strcat(putstring, tmpstr);
1792  }
1793  }
1794  }
1796  putstring);
1797  }
1798  /* philosophy:
1799  * It's easy to grab an item type from a pile, as long as it's
1800  * generic. This takes no game-time. For more detailed pickups
1801  * and selections, select-items should be used. This is a
1802  * grab-as-you-run type mode that's really useful for arrows for
1803  * example.
1804  * The drawback: right now it has no frontend, so you need to
1805  * stick the bits you want into a calculator in hex mode and then
1806  * convert to decimal and then 'pickup <#>
1807  */
1808 
1809  /* the first two modes are exclusive: if NOTHING we return, if
1810  * STOP then we stop. All the rest are applied sequentially,
1811  * meaning if any test passes, the item gets picked up. */
1812 
1813  /* if mode is set to pick nothing up, return */
1814 
1815  if (op->contr->mode == PU_NOTHING)
1816  return 1;
1817 
1818  /* if mode is set to stop when encountering objects, return.
1819  * Take STOP before INHIBIT since it doesn't actually pick
1820  * anything up */
1821 
1822  if (op->contr->mode&PU_STOP)
1823  return 0;
1824 
1825  /* useful for going into stores and not losing your settings... */
1826  /* and for battles where you don't want to get loaded down while
1827  * fighting */
1828  if (op->contr->mode&PU_INHIBIT)
1829  return 1;
1830 
1831  /* prevent us from turning into auto-thieves :) */
1832  if (QUERY_FLAG(tmp, FLAG_UNPAID))
1833  continue;
1834 
1835  /* ignore known cursed objects */
1836  if (QUERY_FLAG(tmp, FLAG_KNOWN_CURSED) && op->contr->mode&PU_NOT_CURSED)
1837  continue;
1838 
1839  static int checks[] = {
1840  PU_FOOD,
1841  PU_DRINK,
1842  PU_FLESH,
1843  PU_POTION,
1844  PU_SPELLBOOK,
1846  PU_READABLES,
1848  PU_MAGICAL,
1849  PU_VALUABLES,
1850  PU_JEWELS,
1851  PU_BOW,
1852  PU_ARROW,
1853  PU_ARMOUR,
1854  PU_HELMET,
1855  PU_SHIELD,
1856  PU_BOOTS,
1857  PU_GLOVES,
1858  PU_CLOAK,
1861  PU_KEY,
1862  PU_CONTAINER,
1863  PU_CURSED,
1864  0
1865  };
1866  int found = 0;
1867  for (int m = 0; checks[m] != 0; m++) {
1868  if (op->contr->mode & checks[m] && object_matches_pickup_mode(tmp, checks[m])) {
1869  pick_up(op, tmp);
1870  found = 1;
1871  break;
1872  }
1873  }
1874  if (found) {
1875  continue;
1876  }
1877 
1878  /* any of the last 4 bits set means we use the ratio for value
1879  * pickups */
1880  if (op->contr->mode&PU_RATIO) {
1881  /* use value density to decide what else to grab.
1882  * >=7 was >= op->contr->mode
1883  * >=7 is the old standard setting. Now we take the last 4 bits
1884  * and multiply them by 5, giving 0..15*5== 5..75 */
1885  wvratio = (op->contr->mode&PU_RATIO)*5;
1886  current_ratio = price_base(tmp)*100/(tmp->weight*MAX(tmp->nrof, 1));
1887  if (current_ratio >= wvratio) {
1888  pick_up(op, tmp);
1889  continue;
1890  }
1891  }
1892  } /* the new pickup model */
1893  } FOR_BELOW_FINISH();
1894  return !stop;
1895 }
1896 
1909 static object *find_arrow(object *op, const char *type) {
1910  object *tmp = NULL;
1911 
1913  if (!tmp
1914  && inv->type == CONTAINER
1915  && inv->race == type
1917  tmp = find_arrow(inv, type);
1918  else if (inv->type == ARROW && inv->race == type)
1919  return inv;
1920  FOR_INV_FINISH();
1921  return tmp;
1922 }
1923 
1941 static object *find_better_arrow(object *op, object *target, const char *type, int *better) {
1942  object *tmp = NULL, *ntmp;
1943  int attacknum, attacktype, betterby = 0, i;
1944 
1945  if (!type)
1946  return NULL;
1947 
1948  FOR_INV_PREPARE(op, arrow) {
1949  if (arrow->type == CONTAINER
1950  && arrow->race == type
1951  && QUERY_FLAG(arrow, FLAG_APPLIED)) {
1952  i = 0;
1953  ntmp = find_better_arrow(arrow, target, type, &i);
1954  if (i > betterby) {
1955  tmp = ntmp;
1956  betterby = i;
1957  }
1958  } else if (arrow->type == ARROW && arrow->race == type) {
1959  /* always prefer assassination/slaying */
1960  if (target->race != NULL
1961  && arrow->slaying != NULL
1962  && strstr(arrow->slaying, target->race)) {
1963  if (arrow->attacktype&AT_DEATH) {
1964  if (better)
1965  *better = 100;
1966  return arrow;
1967  } else {
1968  tmp = arrow;
1969  betterby = (arrow->magic+arrow->stats.dam)*2;
1970  }
1971  } else {
1972  for (attacknum = 0; attacknum < NROFATTACKS; attacknum++) {
1973  attacktype = 1<<attacknum;
1974  if ((arrow->attacktype&attacktype) && (target->arch->clone.resist[attacknum]) < 0)
1975  if (((arrow->magic+arrow->stats.dam)*(100-target->arch->clone.resist[attacknum])/100) > betterby) {
1976  tmp = arrow;
1977  betterby = (arrow->magic+arrow->stats.dam)*(100-target->arch->clone.resist[attacknum])/100;
1978  }
1979  }
1980  if ((2+arrow->magic+arrow->stats.dam) > betterby) {
1981  tmp = arrow;
1982  betterby = 2+arrow->magic+arrow->stats.dam;
1983  }
1984  if (arrow->title && (1+arrow->magic+arrow->stats.dam) > betterby) {
1985  tmp = arrow;
1986  betterby = 1+arrow->magic+arrow->stats.dam;
1987  }
1988  }
1989  }
1990  } FOR_INV_FINISH();
1991  if (tmp == NULL)
1992  return find_arrow(op, type);
1993 
1994  if (better)
1995  *better = betterby;
1996  return tmp;
1997 }
1998 
2011 static object *pick_arrow_target(object *op, const char *type, int dir) {
2012  object *tmp = NULL;
2013  mapstruct *m;
2014  int i, mflags, found, number;
2015  int16_t x, y;
2016 
2017  if (op->map == NULL)
2018  return find_arrow(op, type);
2019 
2020  /* do a dex check */
2021  number = (die_roll(2, 40, op, PREFER_LOW)-2)/2;
2022  if (number > (op->stats.Dex+(op->chosen_skill ? op->chosen_skill->level : op->level)))
2023  return find_arrow(op, type);
2024 
2025  m = op->map;
2026  x = op->x;
2027  y = op->y;
2028 
2029  /* find the first target */
2030  for (i = 0, found = 0; i < 20; i++) {
2031  x += freearr_x[dir];
2032  y += freearr_y[dir];
2033  mflags = get_map_flags(m, &m, x, y, &x, &y);
2034  if (mflags&P_OUT_OF_MAP || mflags&P_BLOCKSVIEW) {
2035  tmp = NULL;
2036  break;
2037  } else if (GET_MAP_MOVE_BLOCK(m, x, y) == MOVE_FLY_LOW) {
2038  /* This block presumes arrows and the like are MOVE_FLY_SLOW -
2039  * perhaps a bad assumption.
2040  */
2041  tmp = NULL;
2042  break;
2043  }
2044  if (mflags&P_IS_ALIVE) {
2045  FOR_MAP_PREPARE(m, x, y, tmp2)
2046  if (QUERY_FLAG(tmp2, FLAG_ALIVE)) {
2047  tmp = tmp2;
2048  found++;
2049  break;
2050  }
2051  FOR_MAP_FINISH();
2052  if (found)
2053  break;
2054  }
2055  }
2056  if (tmp == NULL)
2057  return find_arrow(op, type);
2058 
2059  return find_better_arrow(op, HEAD(tmp), type, NULL);
2060 }
2061 
2080 int fire_bow(object *op, object *arrow, int dir, int wc_mod, int16_t sx, int16_t sy) {
2081  object *bow;
2082  tag_t tag;
2083  int bowspeed, mflags;
2084  mapstruct *m;
2085 
2086  if (!dir) {
2088  "You can't shoot yourself!");
2089  return 0;
2090  }
2091  if (op->type == PLAYER)
2092  bow = op->contr->ranges[range_bow];
2093  else {
2094  /* Don't check for applied - monsters don't apply bows - in that way, they
2095  * don't need to switch back and forth between bows and weapons.
2096  */
2097  bow = object_find_by_type(op, BOW);
2098  if (!bow) {
2099  LOG(llevError, "Range: bow without activated bow (%s).\n", op->name);
2100  return 0;
2101  }
2102  }
2103  if (!bow->race || !bow->skill) {
2105  "Your %s is broken.",
2106  bow->name);
2107  return 0;
2108  }
2109 
2110  bowspeed = bow->stats.sp+get_dex_bonus(op->stats.Dex);
2111 
2112  /* penalize ROF for bestarrow */
2113  if (op->type == PLAYER && op->contr->bowtype == bow_bestarrow)
2114  bowspeed -= get_dex_bonus(op->stats.Dex)+5;
2115  if (bowspeed < 1)
2116  bowspeed = 1;
2117 
2118  if (arrow == NULL) {
2119  arrow = find_arrow(op, bow->race);
2120  if (arrow == NULL) {
2121  if (op->type == PLAYER)
2124  "You have no %s left.",
2125  bow->race);
2126  /* FLAG_READY_BOW will get reset if the monsters picks up some arrows */
2127  else
2129  return 0;
2130  }
2131  }
2132  mflags = get_map_flags(op->map, &m, sx, sy, &sx, &sy);
2133  if (mflags&P_OUT_OF_MAP) {
2134  return 0;
2135  }
2136  if (GET_MAP_MOVE_BLOCK(m, sx, sy)&MOVE_FLY_LOW) {
2137  return 0;
2138  }
2139 
2140  /* this should not happen, but sometimes does */
2141  if (arrow->nrof == 0) {
2142  object_remove(arrow);
2144  return 0;
2145  }
2146 
2147  arrow = object_split(arrow, 1, NULL, 0);
2148  if (arrow == NULL) {
2150  "You have no %s left.",
2151  bow->race);
2152  return 0;
2153  }
2154  object_set_owner(arrow, op);
2155  if (arrow->skill)
2156  free_string(arrow->skill);
2157  arrow->skill = add_refcount(bow->skill);
2158 
2159  arrow->direction = dir;
2160 
2161  if (op->type == PLAYER) {
2162  op->speed_left = 0.01-(float)FABS(op->speed)*100/bowspeed;
2163  fix_object(op);
2164  }
2165 
2166  if (bow->anim_suffix != NULL)
2168 
2169 /* SET_ANIMATION(arrow, arrow->direction);*/
2170  object_update_turn_face(arrow);
2171  arrow->stats.sp = arrow->stats.wc; /* save original wc and dam */
2172  arrow->stats.hp = arrow->stats.dam;
2173  arrow->stats.grace = arrow->attacktype;
2174  if (arrow->slaying != NULL)
2175  arrow->spellarg = strdup_local(arrow->slaying);
2176 
2177  /* Note that this was different for monsters - they got their level
2178  * added to the damage. I think the strength bonus is more proper.
2179  */
2180 
2181  arrow->stats.dam += (QUERY_FLAG(bow, FLAG_NO_STRENGTH) ? 0 : get_dam_bonus(op->stats.Str))
2182  +bow->stats.dam
2183  +bow->magic
2184  +arrow->magic;
2185 
2186  /* update the speed */
2187  arrow->speed = (float)((QUERY_FLAG(bow, FLAG_NO_STRENGTH) ? 0 : get_dam_bonus(op->stats.Str))+bow->magic+arrow->magic)/5.0
2188  +(float)bow->stats.dam/7.0;
2189 
2190  if (arrow->speed < 1.0)
2191  arrow->speed = 1.0;
2192  object_update_speed(arrow);
2193  arrow->speed_left = 0;
2194 
2195  if (op->type == PLAYER) {
2196  /* we don't want overflows of wc (sint), so cap the value - mod and pl should be subtracted */
2197  int mod = bow->magic
2198  +arrow->magic
2199  +get_dex_bonus(op->stats.Dex)
2200  +get_thaco_bonus(op->stats.Str)
2201  +arrow->stats.wc
2202  +bow->stats.wc
2203  -wc_mod;
2204  int plmod = (op->chosen_skill ? op->chosen_skill->level : op->level);
2205  if (plmod+mod > 140)
2206  plmod = 140-mod;
2207  else if (plmod+mod < -100)
2208  plmod = -100-mod;
2209  arrow->stats.wc = 20-(int8_t)plmod-(int8_t)mod;
2210 
2211  arrow->level = op->chosen_skill ? op->chosen_skill->level : op->level;
2212  } else {
2213  arrow->stats.wc = op->stats.wc
2214  -bow->magic
2215  -arrow->magic
2216  -arrow->stats.wc
2217  +wc_mod;
2218 
2219  arrow->level = op->level;
2220  }
2221  if (arrow->attacktype == AT_PHYSICAL)
2222  arrow->attacktype |= bow->attacktype;
2223  if (bow->slaying != NULL)
2224  arrow->slaying = add_string(bow->slaying);
2225 
2226  /* If move_type is ever changed, monster.c:monster_use_bow() needs to be changed too. */
2227  arrow->move_type = MOVE_FLY_LOW;
2228  arrow->move_on = MOVE_FLY_LOW|MOVE_WALK;
2229 
2230  tag = arrow->count;
2231  object_insert_in_map_at(arrow, m, op, 0, sx, sy);
2232 
2233  if (!object_was_destroyed(arrow, tag)) {
2234  play_sound_map(SOUND_TYPE_ITEM, arrow, arrow->direction, "fire");
2235  ob_process(arrow);
2236  }
2237 
2238  return 1;
2239 }
2240 
2251 static int similar_direction(int a, int b) {
2252  /* shortcut the obvious */
2253  if (a == b)
2254  return 1;
2255  /* Made this cleaner using modulus instead of a switch statement
2256  * We only needed the direction and the two adjacent to it
2257  * (8 is adjacent to 1 here) to return true, so a - 1, a, and a + 1
2258  * are the three directions that get "similar" affirmed.
2259  * -- Daniel Hawkins 2015-05-28
2260  */
2261  // The last one for the offset is added afterwards so we get
2262  // 1-8 instead of 0-7 (specifically, 0 becomes 8 without changing
2263  // the other values).
2264  if ((a % 8) + 1 == b || (a + 6 % 8) + 1 == b)
2265  return 1;
2266  return 0;
2267 }
2268 
2285 static int player_fire_bow(object *op, int dir) {
2286  int ret = 0, wcmod = 0;
2287 
2288  if (op->contr->bowtype == bow_bestarrow) {
2289  ret = fire_bow(op, pick_arrow_target(op, op->contr->ranges[range_bow]->race, dir), dir, 0, op->x, op->y);
2290  } else if (op->contr->bowtype >= bow_n && op->contr->bowtype <= bow_nw) {
2291  if (!similar_direction(dir, op->contr->bowtype-bow_n+1))
2292  wcmod = -1;
2293  ret = fire_bow(op, NULL, op->contr->bowtype-bow_n+1, wcmod, op->x, op->y);
2294  } else if (op->contr->bowtype == bow_threewide) {
2295  ret = fire_bow(op, NULL, dir, 0, op->x, op->y);
2296  ret |= fire_bow(op, NULL, dir, -5, op->x+freearr_x[absdir(dir+2)], op->y+freearr_y[absdir(dir+2)]);
2297  ret |= fire_bow(op, NULL, dir, -5, op->x+freearr_x[absdir(dir-2)], op->y+freearr_y[absdir(dir-2)]);
2298  } else if (op->contr->bowtype == bow_spreadshot) {
2299  ret |= fire_bow(op, NULL, dir, 0, op->x, op->y);
2300  ret |= fire_bow(op, NULL, absdir(dir-1), -5, op->x, op->y);
2301  ret |= fire_bow(op, NULL, absdir(dir+1), -5, op->x, op->y);
2302  } else {
2303  /* Simple case */
2304  ret = fire_bow(op, NULL, dir, 0, op->x, op->y);
2305  }
2306  return ret;
2307 }
2308 
2321 static void fire_misc_object(object *op, int dir) {
2322  object *item;
2323  char name[MAX_BUF];
2324 
2325  item = op->contr->ranges[range_misc];
2326  if (!item) {
2328  "You have no range item readied.");
2329  return;
2330  }
2331  if (!item->inv) {
2332  LOG(llevError, "Object %s lacks a spell\n", item->name);
2333  return;
2334  }
2335  if (item->type == WAND) {
2336  if (item->stats.food <= 0) {
2337  play_sound_player_only(op->contr, SOUND_TYPE_ITEM, item, 0, "poof");
2340  "The %s goes poof.",
2341  name);
2342  return;
2343  }
2344  } else if (item->type == ROD) {
2345  if (item->stats.hp < SP_level_spellpoint_cost(item, item->inv, SPELL_HIGHEST)) {
2346  play_sound_player_only(op->contr, SOUND_TYPE_ITEM, item, 0, "poof");
2349  "The %s whines for a while, but nothing happens.",
2350  name);
2351  return;
2352  }
2353  }
2354 
2355  if (cast_spell(op, item, dir, item->inv, NULL)) {
2356  SET_FLAG(op, FLAG_BEEN_APPLIED); /* You now know something about it */
2357  if (item->type == WAND) {
2359  } else if (item->type == ROD) {
2361  }
2362  }
2363 }
2364 
2373 void fire(object *op, int dir) {
2374 
2375  /* check for loss of invisiblity/hide */
2376  if (action_makes_visible(op))
2377  make_visible(op);
2378 
2379  switch (op->contr->shoottype) {
2380  case range_none:
2381  return;
2382 
2383  case range_bow:
2384  player_fire_bow(op, dir);
2385  return;
2386 
2387  case range_magic: /* Casting spells */
2388  cast_spell(op, op, dir, op->contr->ranges[range_magic], op->contr->spellparam[0] ? op->contr->spellparam : NULL);
2389  return;
2390 
2391  case range_misc:
2392  fire_misc_object(op, dir);
2393  return;
2394 
2395  case range_golem: /* Control summoned monsters from scrolls */
2396  if (op->contr->ranges[range_golem] == NULL
2397  || op->contr->golem_count != op->contr->ranges[range_golem]->count) {
2398  op->contr->ranges[range_golem] = NULL;
2399  op->contr->shoottype = range_none;
2400  op->contr->golem_count = 0;
2401  } else
2402  pets_control_golem(op->contr->ranges[range_golem], dir);
2403  return;
2404 
2405  case range_skill:
2406  if (!op->chosen_skill) {
2407  if (op->type == PLAYER)
2409  "You have no applicable skill to use.");
2410  return;
2411  }
2412  (void)do_skill(op, op, op->chosen_skill, dir, NULL);
2413  return;
2414 
2415  case range_builder:
2416  apply_map_builder(op, dir);
2417  return;
2418 
2419  default:
2421  "Illegal shoot type.");
2422  return;
2423  }
2424 }
2425 
2445 object *find_key(object *pl, object *container, object *door) {
2446  object *tmp, *key;
2447 
2448  /* Should not happen, but sanity checking is never bad */
2449  if (container->inv == NULL)
2450  return NULL;
2451 
2452  /* First, lets try to find a key in the top level inventory */
2453  tmp = NULL;
2454  if (door->type == DOOR) {
2455  int flag = FLAG_UNPAID;
2456  tmp = object_find_by_type_without_flags(container, KEY, &flag, 1);
2457  }
2458  /* For sanity, we should really check door type, but other stuff
2459  * (like containers) can be locked with special keys
2460  */
2461  if (!tmp && door->slaying != NULL) {
2463  }
2464  /* No key found - lets search inventories now */
2465  /* If we find and use a key in an inventory, return at that time.
2466  * otherwise, if we search all the inventories and still don't find
2467  * a key, return
2468  */
2469  if (!tmp) {
2470  FOR_INV_PREPARE(container, tmp) {
2471  /* No reason to search empty containers */
2472  if (tmp->type == CONTAINER && tmp->inv) {
2473  key = find_key(pl, tmp, door);
2474  if (key != NULL)
2475  return key;
2476  }
2477  } FOR_INV_FINISH();
2478  return NULL;
2479  }
2480  /* We get down here if we have found a key. Now if its in a container,
2481  * see if we actually want to use it
2482  */
2483  if (pl != container) {
2484  /* Only let players use keys in containers */
2485  if (!pl->contr)
2486  return NULL;
2487  /* cases where this fails:
2488  * If we only search the player inventory, return now since we
2489  * are not in the players inventory.
2490  * If the container is not active, return now since only active
2491  * containers can be used.
2492  * If we only search keyrings and the container does not have
2493  * a race/isn't a keyring.
2494  * No checking for all containers - to fall through past here,
2495  * inv must have been an container and must have been active.
2496  *
2497  * Change the color so that the message doesn't disappear with
2498  * all the others.
2499  */
2500  if (pl->contr->usekeys == key_inventory
2501  || !QUERY_FLAG(container, FLAG_APPLIED)
2502  || (pl->contr->usekeys == keyrings && (!container->race || strcmp(container->race, "keys")))) {
2503  char name_tmp[MAX_BUF], name_cont[MAX_BUF];
2504 
2505  query_name(tmp, name_tmp, MAX_BUF);
2506  query_name(container, name_cont, MAX_BUF);
2509  "The %s in your %s vibrates as you approach the door",
2510  name_tmp, name_cont);
2511  return NULL;
2512  }
2513  }
2514  return tmp;
2515 }
2516 
2527 static int player_attack_door(object *op, object *door) {
2528  /* If its a door, try to find a use a key. If we do destroy the door,
2529  * might as well return immediately as there is nothing more to do -
2530  * otherwise, we fall through to the rest of the code.
2531  */
2532  object *key = find_key(op, op, door);
2533 
2534  assert(door->type == DOOR || door->type == LOCKED_DOOR);
2535 
2536  /* IF we found a key, do some extra work */
2537  if (key) {
2538  char name[HUGE_BUF];
2539 
2540  play_sound_map(SOUND_TYPE_GROUND, door, 0, "open");
2541  if (action_makes_visible(op))
2542  make_visible(op);
2543  if (door->inv && (door->inv->type == RUNE || door->inv->type == TRAP))
2544  spring_trap(door->inv, op);
2545 
2549  "You open the door with the %s",
2550  name);
2551 
2552  if (door->type == DOOR)
2553  remove_door(door);
2554  else
2555  remove_locked_door(door); /* remove door without violence ;-) */
2556 
2557  /* Do this after we print the message */
2558  object_decrease_nrof_by_one(key); /* Use up one of the keys */
2559 
2560  return 1; /* Nothing more to do below */
2561 
2562  }
2563 
2564  if (door->type == LOCKED_DOOR) {
2565  /* Might as well return now - no other way to open this */
2567  door->msg);
2568  return 1;
2569  }
2570 
2571  if (door->type == DOOR && op->contr && !op->contr->run_on) {
2572  /* Player so try to pick the door */
2573  object *lock = find_skill_by_name(op, "lockpicking");
2574  if (lock) {
2575  /* Even if the lockpicking failed, don't go on moving, player should explicitely attack or run
2576  * to bash the door. */
2577  do_skill(op, op, lock, op->facing, NULL);
2578  return 1;
2579  }
2580  }
2581 
2582  return 0;
2583 }
2584 
2598 void move_player_attack(object *op, int dir) {
2599  object *mon, *tpl, *mon_owner;
2600  int16_t nx, ny;
2601  int on_battleground;
2602  mapstruct *m;
2603 
2604  if (op->contr->transport)
2605  tpl = op->contr->transport;
2606  else
2607  tpl = op;
2608  assert(tpl->map != NULL); // op must be on a map in order to move it
2609  nx = freearr_x[dir]+tpl->x;
2610  ny = freearr_y[dir]+tpl->y;
2611 
2612  on_battleground = op_on_battleground(tpl, NULL, NULL, NULL);
2613 
2614  // Temporarily store the map we are on before movement.
2615  mapstruct *bef = tpl->map;
2616 
2617  /* If braced, or can't move to the square, and it is not out of the
2618  * map, attack it. Note order of if statement is important - don't
2619  * want to be calling move_ob if braced, because move_ob will move the
2620  * player. This is a pretty nasty hack, because if we could
2621  * move to some space, it then means that if we are braced, we should
2622  * do nothing at all. As it is, if we are braced, we go through
2623  * quite a bit of processing. However, it probably is less than what
2624  * move_ob uses.
2625  */
2626  if ((op->contr->braced || !move_ob(tpl, dir, tpl)) && !out_of_map(tpl->map, nx, ny)) {
2627  if (OUT_OF_REAL_MAP(tpl->map, nx, ny)) {
2628  m = get_map_from_coord(tpl->map, &nx, &ny);
2629  if (!m)
2630  return; /* Don't think this should happen */
2631  } else
2632  m = tpl->map;
2633 
2634  if (GET_MAP_OB(m, nx, ny) == NULL) {
2635  /* LOG(llevError, "player_move_attack: GET_MAP_OB returns NULL, but player can not move there.\n");*/
2636  return;
2637  }
2638 
2639  mon = NULL;
2640  /* Go through all the objects, and find ones of interest. Only stop if
2641  * we find a monster - that is something we know we want to attack.
2642  * if its a door or barrel (can roll) see if there may be monsters
2643  * on the space
2644  */
2645  FOR_MAP_PREPARE(m, nx, ny, tmp) {
2646  if (tmp == op) {
2647  continue;
2648  }
2649  if (QUERY_FLAG(tmp, FLAG_ALIVE)) {
2650  mon = tmp;
2651  /* Gros: Objects like (pass-through) doors are alive, but haven't
2652  * their monster flag set - so this is a good way attack real
2653  * monsters in priority.
2654  */
2655  if (QUERY_FLAG(tmp, FLAG_MONSTER))
2656  break;
2657  }
2658  if (tmp->type == LOCKED_DOOR || QUERY_FLAG(tmp, FLAG_CAN_ROLL))
2659  mon = tmp;
2660  } FOR_MAP_FINISH();
2661 
2662  if (mon == NULL) /* This happens anytime the player tries to move */
2663  return; /* into a wall */
2664 
2665  mon = HEAD(mon);
2666  if ((mon->type == DOOR && mon->stats.hp >= 0) || (mon->type == LOCKED_DOOR))
2667  if (player_attack_door(op, mon))
2668  return;
2669 
2670  /* The following deals with possibly attacking peaceful
2671  * or friendly creatures. Basically, all players are considered
2672  * unaggressive. If the moving player has peaceful set, then the
2673  * object should be pushed instead of attacked. It is assumed that
2674  * if you are braced, you will not attack friends accidently,
2675  * and thus will not push them.
2676  */
2677 
2678  /* If the creature is a pet, push it even if the player is not
2679  * peaceful. Our assumption is the creature is a pet if the
2680  * player owns it and it is either friendly or unaggressive.
2681  */
2682  mon_owner = object_get_owner(mon);
2683  if ((op->type == PLAYER)
2684  && (mon_owner == op || (mon_owner != NULL && mon_owner->type == PLAYER && mon_owner->contr->party != NULL && mon_owner->contr->party == op->contr->party))
2686  /* If we're braced, we don't want to switch places with it */
2687  if (op->contr->braced)
2688  return;
2689  play_sound_map(SOUND_TYPE_LIVING, mon, dir, "push");
2690  (void)push_ob(mon, dir, op);
2691  if (op->contr->tmp_invis || op->hide)
2692  make_visible(op);
2693  return;
2694  }
2695 
2696  /* in certain circumstances, you shouldn't attack friendly
2697  * creatures. Note that if you are braced, you can't push
2698  * someone, but put it inside this loop so that you won't
2699  * attack them either.
2700  */
2701  if ((mon->type == PLAYER || mon->enemy != op)
2703  && (op->contr->peaceful && !on_battleground)) {
2704  if (!op->contr->braced) {
2705  play_sound_map(SOUND_TYPE_LIVING, mon, dir, "push");
2706  (void)push_ob(mon, dir, op);
2707  } else {
2709  "You withhold your attack");
2710  }
2711  if (op->contr->tmp_invis || op->hide)
2712  make_visible(op);
2713  }
2714 
2715  /* If the object is a boulder or other rollable object, then
2716  * roll it if not braced. You can't roll it if you are braced.
2717  */
2718  else if (QUERY_FLAG(mon, FLAG_CAN_ROLL) && (!op->contr->braced)) {
2719  recursive_roll(mon, dir, op);
2720  if (action_makes_visible(op))
2721  make_visible(op);
2722 
2723  /* Any generic living creature. Including things like doors.
2724  * Way it works is like this: First, it must have some hit points
2725  * and be living. Then, it must be one of the following:
2726  * 1) Not a player, 2) A player, but of a different party. Note
2727  * that party_number -1 is no party, so attacks can still happen.
2728  */
2729  } else if ((mon->stats.hp >= 0)
2731  && ((mon->type != PLAYER || op->contr->party == NULL || op->contr->party != mon->contr->party))) {
2732  /* If the player hasn't hit something this tick, and does
2733  * so, give them speed boost based on weapon speed. Doing
2734  * it here is better than process_players2, which basically
2735  * incurred a 1 tick offset.
2736  */
2737  if (op->weapon_speed_left < 0) {
2738  op->speed_left = -0.01;
2739  return;
2740  }
2741  op->weapon_speed_left -= 1.0;
2742 
2743  skill_attack(mon, op, 0, NULL, NULL);
2744 
2745  /* If attacking another player, that player gets automatic
2746  * hitback, and doesn't loose luck either.
2747  * Disable hitback on the battleground or if the target is
2748  * the wiz.
2749  */
2750  if (mon->type == PLAYER
2751  && mon->stats.hp >= 0
2752  && !mon->contr->has_hit
2753  && !on_battleground
2754  && !QUERY_FLAG(mon, FLAG_WIZ)) {
2755  short luck = mon->stats.luck;
2756  mon->contr->has_hit = 1;
2757  skill_attack(op, mon, 0, NULL, NULL);
2758  mon->stats.luck = luck;
2759  }
2760  if (action_makes_visible(op))
2761  make_visible(op);
2762  }
2763  } /* if player should attack something */
2764  else if (bef != tpl->map) {
2765  player_map_change_common(op, bef, tpl->map);
2766  }
2767 }
2768 
2775 static void update_transport_block(object *transport, int dir) {
2776  object *part;
2777  int sx, sy, x, y;
2778 
2779  object_get_multi_size(transport, &sx, &sy, NULL, NULL);
2780  assert(sx == sy);
2781 
2782  if (dir == 1 || dir == 5) {
2783  part = transport;
2784  for (y = 0; y <= sy; y++) {
2785  for (x = 0; x < sx; x++) {
2786  part->move_type = transport->move_type;
2787  part = part->more;
2788  }
2789  part->move_type = 0;
2790  part = part->more;
2791  }
2792  } else if (dir == 3 || dir == 7) {
2793  part = transport;
2794  for (y = 0; y < sy; y++) {
2795  for (x = 0; x <= sx; x++) {
2796  part->move_type = transport->move_type;
2797  part = part->more;
2798  }
2799  }
2800  while (part) {
2801  part->move_type = 0;
2802  part = part->more;
2803  }
2804  } else {
2805  for (part = transport; part; part = part->more) {
2806  part->move_type = transport->move_type;
2807  }
2808  }
2809 }
2810 
2820 static int turn_one_transport(object *transport, object *captain, int dir) {
2821  int x, y, scroll_dir = 0;
2822 
2823  assert(transport->type == TRANSPORT);
2824 
2825  x = transport->x;
2826  y = transport->y;
2827 
2828  if (transport->direction == 1 && dir == 8) {
2829  x--;
2830  } else if (transport->direction == 2 && dir == 3) {
2831  y++;
2832  } else if (transport->direction == 3 && dir == 2) {
2833  y--;
2834  } else if (transport->direction == 5 && dir == 6) {
2835  x--;
2836  } else if (transport->direction == 6 && dir == 5) {
2837  x++;
2838  } else if (transport->direction == 7 && dir == 8) {
2839  y--;
2840  } else if (transport->direction == 8 && dir == 7) {
2841  y++;
2842  } else if (transport->direction == 8 && dir == 1) {
2843  x++;
2844  }
2845 
2846  update_transport_block(transport, dir);
2847  object_remove(transport);
2848  if (ob_blocked(transport, transport->map, x, y)) {
2849  update_transport_block(transport, transport->direction);
2850  object_insert_in_map_at(transport, transport->map, NULL, 0, x, y);
2851  return 2;
2852  }
2853 
2854  if (x != transport->x || y != transport->y) {
2855 /* assert(scroll_dir != 0);*/
2856 
2857  FOR_INV_PREPARE(transport, pl) {
2858  if (pl->type == PLAYER) {
2859  pl->contr->do_los = 1;
2860  pl->map = transport->map;
2861  pl->x = x;
2862  pl->y = y;
2863  esrv_map_scroll(&pl->contr->socket, freearr_x[scroll_dir], freearr_y[scroll_dir]);
2864  pl->contr->socket.update_look = 1;
2865  pl->contr->socket.look_position = 0;
2866  }
2867  } FOR_INV_FINISH();
2868  }
2869 
2870  object_insert_in_map_at(transport, transport->map, NULL, 0, x, y);
2871  transport->direction = dir;
2872  transport->facing = dir;
2873  animate_object(transport, dir);
2874  captain->direction = dir;
2875  return 1;
2876 }
2877 
2890 static int turn_transport(object *transport, object *captain, int dir) {
2891  assert(transport->type == TRANSPORT);
2892 
2893  if (object_value_set(transport, "turnable_transport") == false) {
2894  transport->direction = dir;
2895  transport->facing = dir;
2896  if (QUERY_FLAG(transport, FLAG_ANIMATE)) {
2897  animate_object(transport, dir);
2898  }
2899  captain->direction = dir;
2900  return 0;
2901  }
2902 
2903  if (transport->direction == dir)
2904  return 0;
2905 
2906  if (absdir(transport->direction-dir) > 2)
2907  return turn_one_transport(transport, captain, absdir(transport->direction+1));
2908  else
2909  return turn_one_transport(transport, captain, absdir(transport->direction-1));
2910 }
2911 
2923 int move_player(object *op, int dir) {
2924  object *transport = op->contr->transport; //< Transport player is in
2925 
2926  if (!transport && (op->map == NULL || op->map->in_memory != MAP_IN_MEMORY))
2927  return 0;
2928 
2929  /* Sanity check: make sure dir is valid */
2930  if ((dir < 0) || (dir >= 9)) {
2931  LOG(llevError, "move_player: invalid direction %d\n", dir);
2932  return 0;
2933  }
2934 
2935  if (QUERY_FLAG(op, FLAG_CONFUSED) && dir)
2936  dir = get_randomized_dir(dir);
2937 
2938  op->facing = dir;
2939 
2940  if (transport) {
2941  /* transport->contr is set up for the person in charge of the boat.
2942  * if that isn't this person, he can't steer it, etc
2943  */
2944  if (transport->contr != op->contr)
2945  return 0;
2946 
2947  /* Transport is out of movement. But update dir so it at least
2948  * will point in the same direction if player is running.
2949  */
2950  if (transport->speed_left < 0.0) {
2951  return 0;
2952  }
2953  /* Remove transport speed. Give player just a little speed -
2954  * enough so that they will get an action again quickly.
2955  */
2956  transport->speed_left -= 1.0;
2957  if (op->speed_left < 0.0)
2958  op->speed_left = -0.01;
2959 
2960  int turn = turn_transport(transport, op, dir);
2961  if (turn != 0)
2962  return 0;
2963  } else {
2964  if (op->hide) {
2965  do_hidden_move(op);
2966  }
2967 
2968  /* it is important to change the animation now, as fire or move_player_attack can start a compound animation,
2969  * and leave us with state = 0, which we don't want to change again. */
2970  op->state++; /* player moved, so change animation. */
2971  animate_object(op, op->facing);
2972  }
2973 
2974  if (op->contr->fire_on) {
2975  fire(op, dir);
2976  } else
2977  move_player_attack(op, dir);
2978 
2979  int pick = check_pick(op);
2980 
2981  /* Add special check for newcs players and fire on - this way, the
2982  * server can handle repeat firing.
2983  */
2984  if (op->contr->fire_on || (op->contr->run_on && pick != 0)) {
2985  op->direction = dir;
2986  } else {
2987  op->direction = 0;
2988  }
2989  return 0;
2990 }
2991 
3002 int face_player(object *op, int dir) {
3003  object *transport = op->contr->transport; //< Transport player is in
3004 
3005  if (!transport && (op->map == NULL || op->map->in_memory != MAP_IN_MEMORY))
3006  return 0;
3007 
3008  /* Sanity check: make sure dir is valid */
3009  if ((dir < 0) || (dir >= 9)) {
3010  LOG(llevError, "move_player: invalid direction %d\n", dir);
3011  return 0;
3012  }
3013 
3014  if (QUERY_FLAG(op, FLAG_CONFUSED) && dir)
3015  dir = get_randomized_dir(dir);
3016 
3017  op->facing = dir;
3018 
3019  if (transport) {
3020  /* transport->contr is set up for the person in charge of the boat.
3021  * if that isn't this person, he can't steer it, etc
3022  */
3023  if (transport->contr != op->contr)
3024  return 0;
3025 
3026  turn_transport(transport, op, dir);
3027  } else {
3028  if (op->hide) {
3029  do_hidden_move(op);
3030  }
3031 
3032  /* it is important to change the animation now, as fire or move_player_attack can start a compound animation,
3033  * and leave us with state = 0, which we don't want to change again. */
3034  op->state++; /* player moved, so change animation. */
3035  animate_object(op, op->facing);
3036  }
3037 
3038  /* Add special check for newcs players and fire on - this way, the
3039  * server can handle repeat firing.
3040  */
3041  if (op->contr->fire_on || op->contr->run_on) {
3042  op->direction = dir;
3043  } else {
3044  op->direction = 0;
3045  }
3046  return 0;
3047 }
3048 
3061 int handle_newcs_player(object *op) {
3062  if (op->contr->hidden) {
3063  op->invisible = 1000;
3064  /* the socket code flashes the player visible/invisible
3065  * depending on the value if invisible, so we need to
3066  * alternate it here for it to work correctly.
3067  */
3068  if (pticks&2)
3069  op->invisible--;
3070  } else if (op->invisible && !(QUERY_FLAG(op, FLAG_MAKE_INVIS))) {
3071  op->invisible--;
3072  if (!op->invisible) {
3073  make_visible(op);
3075  "Your invisibility spell runs out.");
3076  }
3077  }
3078 
3079  if (QUERY_FLAG(op, FLAG_SCARED)) {
3080  flee_player(op);
3081  /* If player is still scared, that is his action for this tick */
3082  if (QUERY_FLAG(op, FLAG_SCARED)) {
3083  op->speed_left--;
3084  return 0;
3085  }
3086  }
3087 
3088  /* I've been seeing crashes where the golem has been destroyed, but
3089  * the player object still points to the defunct golem. The code that
3090  * destroys the golem looks correct, and it doesn't always happen, so
3091  * put this in a a workaround to clean up the golem pointer.
3092  */
3093  if (op->contr->ranges[range_golem]
3094  && ((op->contr->golem_count != op->contr->ranges[range_golem]->count) || QUERY_FLAG(op->contr->ranges[range_golem], FLAG_REMOVED))) {
3095  op->contr->ranges[range_golem] = NULL;
3096  op->contr->golem_count = 0;
3097  }
3098 
3099  /*
3100  * If the player has been paralyzed, we unmark the flag and give a message to the player
3101  */
3102  if (QUERY_FLAG(op, FLAG_PARALYZED)) {
3104  // TODO: Is this check necessary? We are in player.c, after all.
3105  if (op->type == PLAYER)
3106  {
3108  "You can stretch your stiff joints once more.");
3109  }
3110  }
3111 
3112  if (op->direction && (op->contr->run_on || op->contr->fire_on)) {
3113  /* All move commands take 1 tick, at least for now */
3114  op->speed_left--;
3115 
3116  /* Instead of all the stuff below, let move_player take care
3117  * of it. Also, some of the skill stuff is only put in
3118  * there, as well as the confusion stuff.
3119  */
3120  move_player(op, op->direction);
3121  if (op->speed_left > 0)
3122  return 1;
3123  else
3124  return 0;
3125  }
3126  return 0;
3127 }
3128 
3139 static int save_life(object *op) {
3140  object *tmp;
3141 
3142  if (!QUERY_FLAG(op, FLAG_LIFESAVE))
3143  return 0;
3144 
3146  if (tmp != NULL) {
3147  char name[MAX_BUF];
3148 
3150  play_sound_map(SOUND_TYPE_ITEM, tmp, 0, "evaporate");
3152  "Your %s vibrates violently, then evaporates.",
3153  name);
3154  object_remove(tmp);
3157  if (op->stats.hp < 0)
3158  op->stats.hp = op->stats.maxhp;
3159  if (op->stats.food < 0)
3160  op->stats.food = MAX_FOOD;
3161  fix_object(op);
3162  return 1;
3163  }
3164  LOG(llevError, "Error: LIFESAVE set without applied object.\n");
3166  enter_player_savebed(op); /* bring him home. */
3167  return 0;
3168 }
3169 
3182 void remove_unpaid_objects(object *op, object *env, int free_items) {
3184  if (QUERY_FLAG(op, FLAG_UNPAID)) {
3185  object_remove(op);
3186  if (free_items)
3188  else
3189  object_insert_in_map_at(op, env->map, NULL, 0, env->x, env->y);
3190  } else if (op->inv)
3191  remove_unpaid_objects(op->inv, env, free_items);
3193 }
3194 
3212 static const char *gravestone_text(object *op, char *buf2, int len) {
3213  char buf[MAX_BUF];
3214  time_t now = time(NULL);
3215 
3216  strncpy(buf2, " R.I.P.\n\n", len);
3217  if (op->type == PLAYER)
3218  snprintf(buf, sizeof(buf), "%s the %s\n", op->name, op->contr->title);
3219  else
3220  snprintf(buf, sizeof(buf), "%s\n", op->name);
3221  strncat(buf2, " ", 20-strlen(buf)/2);
3222  strncat(buf2, buf, len-strlen(buf2)-1);
3223  if (op->type == PLAYER)
3224  snprintf(buf, sizeof(buf), "who was in level %d when killed\n", op->level);
3225  else
3226  snprintf(buf, sizeof(buf), "who was in level %d when died.\n\n", op->level);
3227  strncat(buf2, " ", 20-strlen(buf)/2);
3228  strncat(buf2, buf, len-strlen(buf2)-1);
3229  if (op->type == PLAYER) {
3230  snprintf(buf, sizeof(buf), "by %s.\n\n", op->contr->killer);
3231  strncat(buf2, " ", 21-strlen(buf)/2);
3232  strncat(buf2, buf, len-strlen(buf2)-1);
3233  }
3234  strftime(buf, MAX_BUF, "%b %d %Y\n", localtime(&now));
3235  strncat(buf2, " ", 20-strlen(buf)/2);
3236  strncat(buf2, buf, len-strlen(buf2)-1);
3237  return buf2;
3238 }
3239 
3247 void do_some_living(object *op) {
3248  int last_food = op->stats.food;
3249  int gen_hp, gen_sp, gen_grace;
3250  int rate_hp = 1200;
3251  int rate_sp = 2500;
3252  int rate_grace = 2000;
3253 
3254  if (op->contr->state == ST_PLAYING) {
3255  /* these next three if clauses make it possible to SLOW DOWN
3256  hp/grace/spellpoint regeneration. */
3257  if (op->contr->gen_hp >= 0)
3258  gen_hp = (op->contr->gen_hp+1)*op->stats.maxhp;
3259  else {
3260  gen_hp = op->stats.maxhp;
3261  rate_hp -= rate_hp/2*op->contr->gen_hp;
3262  }
3263  if (op->contr->gen_sp >= 0)
3264  gen_sp = (op->contr->gen_sp+1)*op->stats.maxsp;
3265  else {
3266  gen_sp = op->stats.maxsp;
3267  rate_sp -= rate_sp/2*op->contr->gen_sp;
3268  }
3269  if (op->contr->gen_grace >= 0)
3270  gen_grace = (op->contr->gen_grace+1)*op->stats.maxgrace;
3271  else {
3272  gen_grace = op->stats.maxgrace;
3273  rate_grace -= rate_grace/2*op->contr->gen_grace;
3274  }
3275 
3276  /* Regenerate Spell Points */
3277  if (op->contr->ranges[range_golem] == NULL && --op->last_sp < 0) {
3278  gen_sp = gen_sp*10/MAX(op->contr->gen_sp_armour, 10);
3279  if (op->stats.sp < op->stats.maxsp) {
3280  op->stats.sp++;
3281  /* dms do not consume food */
3282  if (!QUERY_FLAG(op, FLAG_WIZ)) {
3283  op->stats.food--;
3284  if (op->contr->digestion < 0)
3285  op->stats.food += op->contr->digestion;
3286  else if (op->contr->digestion > 0
3287  && random_roll(0, op->contr->digestion, op, PREFER_HIGH))
3288  op->stats.food = last_food;
3289  }
3290  }
3291  op->last_sp = rate_sp/(MAX(gen_sp, 20)+10);
3292  }
3293 
3294  /* Regenerate Grace */
3295  /* I altered this a little - maximum grace is only achieved through prayer -b.t.*/
3296  if (--op->last_grace < 0) {
3297  if (op->stats.grace < op->stats.maxgrace/2)
3298  op->stats.grace++; /* no penalty in food for regaining grace */
3299  op->last_grace = rate_grace/(MAX(gen_grace, 20)+10);
3300  /* wearing stuff doesn't detract from grace generation. */
3301  }
3302 
3303  /* Regenerate Hit Points (unless you are a wraith player) */
3304  if (--op->last_heal < 0 && !is_wraith_pl(op)) {
3305  if (op->stats.hp < op->stats.maxhp) {
3306  op->stats.hp++;
3307  /* dms do not consume food */
3308  if (!QUERY_FLAG(op, FLAG_WIZ)) {
3309  op->stats.food--;
3310  if (op->contr->digestion < 0)
3311  op->stats.food += op->contr->digestion;
3312  else if (op->contr->digestion > 0
3313  && random_roll(0, op->contr->digestion, op, PREFER_HIGH))
3314  op->stats.food = last_food;
3315  }
3316  }
3317  op->last_heal = rate_hp/(MAX(gen_hp, 20)+10);
3318  }
3319 
3320  /* Digestion */
3321  if (--op->last_eat < 0) {
3322  int bonus = MAX(op->contr->digestion, 0);
3323  int penalty = MAX(-op->contr->digestion, 0);
3324  if (op->contr->gen_hp > 0)
3325  op->last_eat = 25*(1+bonus)/(op->contr->gen_hp+penalty+1);
3326  else
3327  op->last_eat = 25*(1+bonus)/(penalty+1);
3328  /* dms do not consume food */
3329  if (!QUERY_FLAG(op, FLAG_WIZ))
3330  op->stats.food--;
3331  }
3332  }
3333 
3334  if (op->contr->state == ST_PLAYING && op->stats.food < 0 && op->stats.hp >= 0) {
3335  if (is_wraith_pl(op))
3336  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ITEM, MSG_TYPE_ITEM_REMOVE, "You feel a hunger for living flesh.");
3337  /* Only allow eat if not paralyzed. Otherwise our paralyzed player is "moving" to eat.
3338  * Daniel Hawkins 2017-08-23
3339  */
3340  else if (!QUERY_FLAG(op, FLAG_PARALYZED)){
3341  object *flesh = NULL;
3342 
3343  FOR_INV_PREPARE(op, tmp) {
3344  if (!QUERY_FLAG(tmp, FLAG_UNPAID)) {
3345  if (tmp->type == FOOD || tmp->type == DRINK || tmp->type == POISON) {
3347  "You blindly grab for a bite of food.");
3348  apply_manual(op, tmp, 0);
3349  if (op->stats.food >= 0 || op->stats.hp < 0)
3350  break;
3351  } else if (tmp->type == FLESH)
3352  flesh = tmp;
3353  } /* End if paid for object */
3354  } FOR_INV_FINISH(); /* end of for loop */
3355  /* If player is still starving, it means they don't have any food, so
3356  * eat flesh instead.
3357  */
3358  if (op->stats.food < 0 && op->stats.hp >= 0 && flesh) {
3360  "You blindly grab for a bite of food.");
3361  apply_manual(op, flesh, 0);
3362  }
3363  } /* end not wraith and not paralyzed */
3364  else { // Print a message for when the player is starving and paralyzed
3365  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ITEM, MSG_TYPE_ITEM_REMOVE, "Your stomach rumbles, but you can't reach your food.");
3366  } /* end not wraith and is paralyzed */
3367  } /* end if player is starving */
3368 
3369  if (op->stats.food < 0 && op->stats.hp > 0){
3370  // We know food < 0, so we want the absolute value of food
3371  int32_t adjust_by = MIN(-(op->stats.food), op->stats.hp);
3372  op->stats.food += adjust_by;
3373  op->stats.hp -= adjust_by;
3374  }
3375 
3376  if (!op->contr->state && !QUERY_FLAG(op, FLAG_WIZ) && (op->stats.hp < 0 || op->stats.food < 0))
3377  kill_player(op, NULL);
3378 }
3379 
3386 static void loot_object(object *op) {
3387  object *tmp2;
3388 
3389  if (op->container) { /* close open sack first */
3390  apply_container(op, op->container, AP_NULL);
3391  }
3392 
3393  FOR_INV_PREPARE(op, tmp) {
3394  if (tmp->invisible)
3395  continue;
3396  object_remove(tmp);
3397  tmp->x = op->x,
3398  tmp->y = op->y;
3399  if (tmp->type == CONTAINER) { /* empty container to ground */
3400  loot_object(tmp);
3401  }
3402  if (!QUERY_FLAG(tmp, FLAG_UNIQUE)
3404  if (tmp->nrof > 1) {
3405  tmp2 = object_split(tmp, 1+RANDOM()%(tmp->nrof-1), NULL, 0);
3407  object_insert_in_map_at(tmp, op->map, NULL, 0, op->x, op->y);
3408  } else
3410  } else
3411  object_insert_in_map_at(tmp, op->map, NULL, 0, op->x, op->y);
3412  } FOR_INV_FINISH();
3413 }
3414 
3425 static void restore_player(object *op) {
3426  object *tmp;
3427  archetype *at = find_archetype("poisoning");
3428  if (at != NULL) {
3429  tmp = arch_present_in_ob(at, op);
3430  if (tmp) {
3431  object_remove(tmp);
3434  "Your body feels cleansed");
3435  }
3436  }
3437 
3438  at = find_archetype("confusion");
3439  if (at != NULL) {
3440  tmp = arch_present_in_ob(at, op);
3441  if (tmp) {
3442  object_remove(tmp);
3445  "Your mind feels clearer");
3446  }
3447  }
3448 
3449  cure_disease(op, NULL, NULL); /* remove any disease */
3450 }
3451 
3463 void kill_player(object *op, const object *killer) {
3464  char buf[MAX_BUF];
3465  int x, y;
3466  object *tmp;
3467  archetype *trophy = NULL;
3468 
3469  /* Don't die if the player's life can be saved. */
3470  if (save_life(op)) {
3471  return;
3472  }
3473 
3474  /* If player dies on BATTLEGROUND, no stat/exp loss! For Combat-Arenas
3475  * in cities ONLY!!! It is very important that this doesn't get abused.
3476  * Look at op_on_battleground() for more info --AndreasV
3477  */
3478  if (op_on_battleground(op, &x, &y, &trophy)) {
3479  assert(trophy != NULL);
3481  "You have been defeated in combat!\n"
3482  "Local medics have saved your life...");
3483 
3484  /* restore player */
3485  restore_player(op);
3486 
3487  op->stats.hp = op->stats.maxhp;
3488  if (op->stats.food <= 0)
3489  op->stats.food = MAX_FOOD;
3490 
3491  /* create a bodypart-trophy to make the winner happy */
3492  tmp = arch_to_object(trophy);
3493  if (tmp != NULL) {
3494  snprintf(buf, sizeof(buf), "%s's %s", op->name, tmp->name);
3495  tmp->name = add_string(buf);
3496 
3497  snprintf(buf, sizeof(buf),
3498  "This %s was %s %s the %s, who was defeated at level %d by %s.\n",
3499  tmp->name, tmp->type == FLESH ? "cut off" : "taken from",
3500  op->name, op->contr->title,
3501  (int)(op->level), op->contr->killer);
3502 
3504  tmp->type = 0;
3505  tmp->value = 0;
3506  tmp->material = 0;
3507  tmp->materialname = NULL;
3508  object_insert_in_map_at(tmp, op->map, op, 0, op->x, op->y);
3509  }
3510 
3511  /* teleport defeated player to new destination*/
3512  transfer_ob(op, x, y, 0, NULL);
3513  op->contr->braced = 0;
3514  return;
3515  }
3516 
3517  if (events_execute_object_event(op, EVENT_DEATH, NULL, NULL, NULL, SCRIPT_FIX_ALL) != 0)
3518  return;
3519 
3521  if (op->stats.food < 0) {
3522  snprintf(buf, sizeof(buf), "%s starved to death.", op->name);
3523  strcpy(op->contr->killer, "starvation");
3524  } else {
3525  snprintf(buf, sizeof(buf), "%s died.", op->name);
3526  }
3527  play_sound_player_only(op->contr, SOUND_TYPE_LIVING, op, 0, "death");
3528 
3529  if (settings.not_permadeth == TRUE) {
3531  } else {
3533  }
3534 }
3535 
3544 static void kill_player_not_permadeath(object *op) {
3545  int num_stats_lose;
3546  int will_kill_again;
3547  int lost_a_stat;
3548  int z;
3549  object *tmp;
3550  char buf[MAX_BUF];
3551  archetype *at;
3552 
3553  /* Basically two ways to go - remove a stat permanently, or just
3554  * make it depletion. This bunch of code deals with that aspect
3555  * of death.
3556  */
3558  /* If stat loss is permanent, lose one stat only. */
3559  /* Lower level chars don't lose as many stats because they suffer
3560  more if they do. */
3561  /* Higher level characters can afford things such as potions of
3562  restoration, or better, stat potions. So we slug them that
3563  little bit harder. */
3564  /* GD */
3566  num_stats_lose = 1;
3567  else
3568  num_stats_lose = 1+op->level/BALSL_NUMBER_LOSSES_RATIO;
3569  } else {
3570  num_stats_lose = 1;
3571  }
3572  lost_a_stat = 0;
3573 
3574  for (z = 0; z < num_stats_lose; z++) {
3576  int i;
3577 
3578  /* Pick a random stat and take a point off it. Tell the player
3579  * what he lost.
3580  */
3581  i = RANDOM()%7;
3582  change_attr_value(&(op->stats), i, -1);
3584  change_attr_value(&(op->contr->orig_stats), i, -1);
3585  check_stat_bounds(&(op->contr->orig_stats), MIN_STAT, settings.max_stat);
3588  lose_msg[i]);
3589  lost_a_stat = 1;
3590  } else {
3591  /* deplete a stat */
3593  if (deparch == NULL) {
3594  continue;
3595  }
3596  object *dep;
3597  int lose_this_stat;
3598  int i;
3599 
3600  i = RANDOM()%7;
3601  dep = arch_present_in_ob(deparch, op);
3602  if (!dep) {
3603  dep = arch_to_object(deparch);
3604  object_insert_in_ob(dep, op);
3605  }
3606  lose_this_stat = 1;
3608  int this_stat;
3609 
3610  /* GD */
3611  /* Get the stat that we're about to deplete. */
3612  this_stat = get_attr_value(&(dep->stats), i);
3613  if (this_stat < 0) {
3614  int loss_chance = 1+op->level/BALSL_LOSS_CHANCE_RATIO;
3615  int keep_chance = this_stat*this_stat;
3616  /* Yes, I am paranoid. Sue me. */
3617  if (keep_chance < 1)
3618  keep_chance = 1;
3619 
3620  /* There is a maximum depletion total per level. */
3621  if (this_stat < -1-op->level/BALSL_MAX_LOSS_RATIO) {
3622  lose_this_stat = 0;
3623  /* Take loss chance vs keep chance to see if we
3624  retain the stat. */
3625  } else {
3626  if (random_roll(0, loss_chance+keep_chance-1, op, PREFER_LOW) < keep_chance)
3627  lose_this_stat = 0;
3628  /* 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"); */
3629  }
3630  }
3631  }
3632 
3633  if (lose_this_stat) {
3634  int this_stat;
3635 
3636  this_stat = get_attr_value(&(dep->stats), i);
3637  /* We could try to do something clever like find another
3638  * stat to reduce if this fails. But chances are, if
3639  * stats have been depleted to -50, all are pretty low
3640  * and should be roughly the same, so it shouldn't make a
3641  * difference.
3642  */
3643  if (this_stat >= -50) {
3644  change_attr_value(&(dep->stats), i, -1);
3645  SET_FLAG(dep, FLAG_APPLIED);
3647  drain_msg[i]);
3648  fix_object(op);
3649  lost_a_stat = 1;
3650  }
3651  }
3652  }
3653  }
3654  /* If no stat lost, tell the player. */
3655  if (!lost_a_stat) {
3656  /* determine_god() seems to not work sometimes... why is this? Should I be using something else? GD */
3657  const char *god = determine_god(op);
3658 
3659  if (god && (strcmp(god, "none")))
3662  "For a brief moment you feel the holy presence of %s protecting you",
3663  god);
3664  else
3667  "For a brief moment you feel a holy presence protecting you.");
3668  }
3669 
3670  /* Put a gravestone up where the character 'almost' died. List the
3671  * exp loss on the stone.
3672  */
3673  at = find_archetype("gravestone");
3674  if (at != NULL) {
3675  tmp = arch_to_object(at);
3676  snprintf(buf, sizeof(buf), "%s's gravestone", op->name);
3677  FREE_AND_COPY(tmp->name, buf);
3678  snprintf(buf, sizeof(buf), "%s's gravestones", op->name);
3679  FREE_AND_COPY(tmp->name_pl, buf);
3680  snprintf(buf, sizeof(buf), "RIP\nHere rests the hero %s the %s,\n"
3681  "who was killed\n"
3682  "by %s.\n",
3683  op->name, op->contr->title,
3684  op->contr->killer);
3686  object_insert_in_map_at(tmp, op->map, NULL, 0, op->x, op->y);
3687  }
3688 
3689  /* restore player: remove any poisoning, disease and confusion the
3690  * character may be suffering.*/
3691  restore_player(op);
3692 
3693  /* Subtract the experience points, if we died cause of food, give
3694  * us food, and reset HP's...
3695  */
3697  if (op->stats.food < 100)
3698  op->stats.food = 900;
3699  op->stats.hp = op->stats.maxhp;
3700  op->stats.sp = MAX(op->stats.sp, op->stats.maxsp);
3701  op->stats.grace = MAX(op->stats.grace, op->stats.maxgrace);
3702 
3703  /* Check to see if the player is in a shop. IF so, then check to see if
3704  * the player has any unpaid items. If so, remove them and put them back
3705  * in the map.
3706  *
3707  * If they are not in a shop, just free the unpaid items instead of
3708  * putting them back on map.
3709  */
3710  if (shop_contains(op))
3711  remove_unpaid_objects(op->inv, op, 0);
3712  else
3713  remove_unpaid_objects(op->inv, op, 1);
3714 
3715  /* Move player to his current respawn-position (usually last savebed) */
3717 
3718  /* Save the player before inserting the force to reduce chance of abuse. */
3719  op->contr->braced = 0;
3720  /* don't pick up in apartment */
3721  if (op->contr->mode & PU_NEWMODE) {
3722  op->contr->mode = op->contr->mode | PU_INHIBIT;
3723  esrv_send_pickup(op->contr);
3724  } else {
3725  op->contr->mode = 0;
3726  }
3727  if ( op->contr->search_str[0] ) command_search_items(op,NULL); /* turn off search-items */
3728  save_player(op, 1);
3729 
3730  /* it is possible that the player has blown something up
3731  * at his savebed location, and that can have long lasting
3732  * spell effects. So first see if there is a spell effect
3733  * on the space that might harm the player.
3734  */
3735  will_kill_again = 0;
3736  FOR_MAP_PREPARE(op->map, op->x, op->y, tmp)
3737  if (tmp->type == SPELL_EFFECT)
3738  will_kill_again |= tmp->attacktype;
3739  FOR_MAP_FINISH();
3740  if (will_kill_again) {
3741  object *force;
3742  int at;
3743 
3745  /* 50 ticks should be enough time for the spell to abate */
3746  force->speed = 0.1;
3747  force->speed_left = -5.0;
3749  for (at = 0; at < NROFATTACKS; at++) {
3750  if (will_kill_again&(1<<at))
3751  force->resist[at] = 100;
3752  }
3754  fix_object(op);
3755  }
3756 
3757  /* Tell the player they have died */
3759  "YOU HAVE DIED.");
3760 }
3761 
3768 static void kill_player_permadeath(object *op) {
3769  char buf[MAX_BUF];
3770  char ac_buf[MAX_BUF];
3771  int x, y;
3772  mapstruct *map;
3773  object *tmp;
3774  archetype *at;
3775 
3776  /* save the map location for corpse, gravestone*/
3777  x = op->x;
3778  y = op->y;
3779  map = op->map;
3780 
3781  party_leave(op);
3782  if (settings.set_title == TRUE)
3783  player_set_own_title(op->contr, "");
3784 
3785  /* buf should be the kill message */
3787  buf);
3788  hiscore_check(op, 0);
3789  if (op->contr->ranges[range_golem] != NULL) {
3790  remove_friendly_object(op->contr->ranges[range_golem]);
3791  object_remove(op->contr->ranges[range_golem]);
3792  object_free_drop_inventory(op->contr->ranges[range_golem]);
3793  op->contr->ranges[range_golem] = NULL;
3794  op->contr->golem_count = 0;
3795  }
3796  loot_object(op); /* Remove some of the items for good */
3797  object_remove(op);
3798  op->direction = 0;
3799 
3800  if (!QUERY_FLAG(op, FLAG_WAS_WIZ) && op->stats.exp) {
3801  if (settings.resurrection == TRUE) {
3802  /* save playerfile sans equipment when player dies
3803  * -then save it as player.pl.dead so that future resurrection
3804  * -type spells will work on them nicely
3805  */
3806  op->stats.hp = op->stats.maxhp;
3807  op->stats.food = MAX_FOOD;
3808 
3809  /* set the location of where the person will reappear when */
3810  /* maybe resurrection code should fix map also */
3811  safe_strncpy(op->contr->maplevel, settings.emergency_mapname,
3812  sizeof(op->contr->maplevel));
3813  if (op->map != NULL)
3814  op->map = NULL;
3815  op->x = settings.emergency_x;
3816  op->y = settings.emergency_y;
3817  save_player(op, 0);
3818  op->map = map;
3819  /* please see resurrection.c: peterm */
3820  dead_player(op);
3821  } else {
3822  delete_character(op->name);
3823  }
3824  }
3825  play_again(op);
3826 
3827  /* peterm: added to create a corpse at deathsite. */
3828  at = find_archetype("corpse_pl");
3829  if (at != NULL) {
3830  tmp = arch_to_object(at);
3831  snprintf(buf, sizeof(buf), "%s", op->name);
3832  FREE_AND_COPY(tmp->name, buf);
3833  FREE_AND_COPY(tmp->name_pl, buf);
3834  tmp->level = op->level;
3835  object_set_msg(tmp, gravestone_text(op, buf, sizeof(buf)));
3837  /*
3838  * Put the account name under slaying.
3839  * Does not seem to cause weird effects, but more testing may ensure this.
3840  */
3841  snprintf(ac_buf, sizeof(ac_buf), "%s", op->contr->socket.account_name);
3842  FREE_AND_COPY(tmp->slaying, ac_buf);
3843  object_insert_in_map_at(tmp, map, NULL, 0, x, y);
3844  }
3845 }
3846 
3854 void fix_weight(void) {
3855  player *pl;
3856 
3857  for (pl = first_player; pl != NULL; pl = pl->next) {
3858  int old = pl->ob->carrying, sum = object_sum_weight(pl->ob);
3859 
3860  if (old == sum)
3861  continue;
3862  fix_object(pl->ob);
3863  LOG(llevDebug, "Fixed inventory in %s (%d -> %d)\n", pl->ob->name, old, sum);
3864  }
3865 }
3866 
3870 void fix_luck(void) {
3871  player *pl;
3872 
3873  for (pl = first_player; pl != NULL; pl = pl->next)
3874  if (!pl->ob->contr->state)
3875  change_luck(pl->ob, 0);
3876 }
3877 
3878 
3891 void cast_dust(object *op, object *throw_ob, int dir) {
3892  object *skop, *spob;
3893 
3894  skop = find_skill_by_name(op, throw_ob->skill);
3895 
3896  /* casting POTION 'dusts' is really a use_magic_item skill */
3897  if (op->type == PLAYER && throw_ob->type == POTION && !skop) {
3898  LOG(llevError, "Player %s lacks critical skill use_magic_item!\n", op->name);
3899  return;
3900  }
3901  spob = throw_ob->inv;
3902  if (op->type == PLAYER && spob)
3904  "You cast %s.",
3905  spob->name);
3906 
3907  cast_spell(op, throw_ob, dir, spob, NULL);
3908 
3909  if (!QUERY_FLAG(throw_ob, FLAG_REMOVED))
3910  object_remove(throw_ob);
3911  object_free_drop_inventory(throw_ob);
3912 }
3913 
3920 void make_visible(object *op) {
3921  op->hide = 0;
3922  op->invisible = 0;
3923  if (op->type == PLAYER) {
3924  op->contr->tmp_invis = 0;
3925  if (op->contr->invis_race)
3926  FREE_AND_CLEAR_STR(op->contr->invis_race);
3927  }
3929 }
3930 
3940 int is_true_undead(object *op) {
3941  if (QUERY_FLAG(&op->arch->clone, FLAG_UNDEAD))
3942  return 1;
3943 
3944  if (op->type == PLAYER) {
3945  FOR_INV_PREPARE(op, tmp) {
3946  if (tmp->type == 44 && tmp->stats.Wis)
3947  if (QUERY_FLAG(tmp, FLAG_UNDEAD))
3948  return 1;
3949  } FOR_INV_FINISH();
3950  }
3951  return 0;
3952 }
3953 
3964 int hideability(object *ob) {
3965  int i, level = 0, mflag;
3966  int16_t x, y;
3967 
3968  if (!ob || !ob->map)
3969  return 0;
3970 
3971  /* so, on normal lighted maps, its hard to hide */
3972  level = ob->map->darkness-2;
3973 
3974  /* this also picks up whether the object is glowing.
3975  * If you carry a light on a non-dark map, its not
3976  * as bad as carrying a light on a pitch dark map
3977  */
3978  if (has_carried_lights(ob))
3979  level = -(10+(2*ob->map->darkness));
3980 
3981  /* scan through all nearby squares for terrain to hide in */
3982  for (i = 0, x = ob->x, y = ob->y; i < 9; i++, x = ob->x+freearr_x[i], y = ob->y+freearr_y[i]) {
3983  mflag = get_map_flags(ob->map, NULL, x, y, NULL, NULL);
3984  if (mflag&P_OUT_OF_MAP) {
3985  continue;
3986  }
3987  if (mflag&P_BLOCKSVIEW) /* something to hide near! */
3988  level += 2;
3989  else /* open terrain! */
3990  level -= 1;
3991  }
3992 
3993  return level;
3994 }
3995 
4005 void do_hidden_move(object *op) {
4006  int hide = 0, num = random_roll(0, 19, op, PREFER_LOW);
4007  object *skop;
4008 
4009  if (!op || !op->map)
4010  return;
4011 
4013 
4014  /* its *extremely *hard to run and sneak/hide at the same time! */
4015  if (op->type == PLAYER && op->contr->run_on) {
4016  if (!skop || num >= skop->level) {
4018  "You ran too much! You are no longer hidden!");
4019  make_visible(op);
4020  return;
4021  } else
4022  num += 20;
4023  }
4024  num += op->map->difficulty;
4025  hide = hideability(op); /* modify by terrain hidden level */
4026  num -= hide;
4027  if ((op->type == PLAYER && hide < -10)
4028  || ((op->invisible -= num) <= 0)) {
4029  make_visible(op);
4030  if (op->type == PLAYER)
4032  "You moved out of hiding! You are visible!");
4033  } else if (op->type == PLAYER && skop) {
4034  change_exp(op, calc_skill_exp(op, NULL, skop), skop->skill, 0);
4035  }
4036 }
4037 
4046 int stand_near_hostile(object *who) {
4047  int i, friendly = 0, player = 0, mflags;
4048  mapstruct *m;
4049  int16_t x, y;
4050 
4051  if (!who)
4052  return 0;
4053 
4054  if (who->type == PLAYER)
4055  player = 1;
4056  else
4057  friendly = QUERY_FLAG(who, FLAG_FRIENDLY);
4058 
4059  /* search adjacent squares */
4060  for (i = 1; i < 9; i++) {
4061  x = who->x+freearr_x[i];
4062  y = who->y+freearr_y[i];
4063  m = who->map;
4064  mflags = get_map_flags(m, &m, x, y, &x, &y);
4065  /* space must be blocked if there is a monster. If not
4066  * blocked, don't need to check this space.
4067  */
4068  if (mflags&P_OUT_OF_MAP)
4069  continue;
4071  continue;
4072 
4073  FOR_MAP_PREPARE(m, x, y, tmp) {
4074  if ((player || friendly)
4077  return 1;
4078  else if (tmp->type == PLAYER) {
4079  /*don't let a hidden DM prevent you from hiding*/
4080  if (!QUERY_FLAG(tmp, FLAG_WIZ) || tmp->contr->hidden == 0)
4081  return 1;
4082  }
4083  } FOR_MAP_FINISH();
4084  }
4085  return 0;
4086 }
4087 
4114 int player_can_view(object *pl, object *op) {
4115  rv_vector rv;
4116  int dx, dy;
4117 
4118  if (!pl || !op)
4119  return 0;
4120 
4121  if (pl->type != PLAYER) {
4122  LOG(llevError, "player_can_view() called for non-player object\n");
4123  return -1;
4124  }
4125 
4126  op = HEAD(op);
4127  if (!get_rangevector(pl, op, &rv, 0x1))
4128  return 0;
4129 
4130  /* starting with the 'head' part, lets loop
4131  * through the object and find if it has any
4132  * part that is in the los array but isnt on
4133  * a blocked los square.
4134  * we use the archetype to figure out offsets.
4135  */
4136  while (op) {
4137  dx = rv.distance_x+op->arch->clone.x;
4138  dy = rv.distance_y+op->arch->clone.y;
4139 
4140  /* only the viewable area the player sees is updated by LOS
4141  * code, so we need to restrict ourselves to that range of values
4142  * for any meaningful values.
4143  */
4144  if (FABS(dx) <= (pl->contr->socket.mapx/2)
4145  && FABS(dy) <= (pl->contr->socket.mapy/2)
4146  && !pl->contr->blocked_los[dx+(pl->contr->socket.mapx/2)][dy+(pl->contr->socket.mapy/2)])
4147  return 1;
4148  op = op->more;
4149  }
4150  return 0;
4151 }
4152 
4166 static int action_makes_visible(object *op) {
4167  if (op->invisible && QUERY_FLAG(op, FLAG_ALIVE)) {
4169  return 0;
4170 
4171  if (op->contr && op->contr->tmp_invis == 0)
4172  return 0;
4173 
4174  /* If monsters, they should become visible */
4175  if (op->hide || !op->contr || (op->contr && op->contr->tmp_invis)) {
4177  "You become %s!",
4178  op->hide ? "unhidden" : "visible");
4179  return 1;
4180  }
4181  }
4182  return 0;
4183 }
4184 
4213 int op_on_battleground(object *op, int *x, int *y, archetype **trophy) {
4215  if (QUERY_FLAG(tmp, FLAG_IS_FLOOR)) {
4217  && strcmp(tmp->name, "battleground") == 0
4218  && tmp->type == BATTLEGROUND
4219  && EXIT_X(tmp)
4220  && EXIT_Y(tmp)) {
4221  /*before we assign the exit, check if this is a teambattle*/
4222  if (EXIT_ALT_X(tmp) && EXIT_ALT_Y(tmp) && EXIT_PATH(tmp)) {
4223  object *invtmp;
4224 
4226  if (invtmp != NULL) {
4227  if (x != NULL && y != NULL)
4228  *x = EXIT_ALT_X(tmp),
4229  *y = EXIT_ALT_Y(tmp);
4230  return 1;
4231  }
4232  }
4233  if (x != NULL && y != NULL)
4234  *x = EXIT_X(tmp),
4235  *y = EXIT_Y(tmp);
4236 
4237  /* If 'other_arch' is not specified, give a finger. */
4238  if (trophy != NULL) {
4239  if (tmp->other_arch) {
4240  *trophy = tmp->other_arch;
4241  } else {
4242  *trophy = find_archetype("finger");
4243  }
4244  }
4245  return 1;
4246  }
4247  }
4248  } FOR_BELOW_FINISH();
4249  /* If we got here, did not find a battleground */
4250  return 0;
4251 }
4252 
4263 void dragon_ability_gain(object *who, int atnr, int level) {
4264  treasurelist *trlist = NULL; /* treasurelist */
4265  treasure *tr; /* treasure */
4266  object *tmp, *skop; /* tmp. object */
4267  object *item; /* treasure object */
4268  char buf[MAX_BUF]; /* tmp. string buffer */
4269  int i = 0, j = 0;
4270 
4271  /* get the appropriate treasurelist */
4272  if (atnr == ATNR_FIRE)
4273  trlist = find_treasurelist("dragon_ability_fire");
4274  else if (atnr == ATNR_COLD)
4275  trlist = find_treasurelist("dragon_ability_cold");
4276  else if (atnr == ATNR_ELECTRICITY)
4277  trlist = find_treasurelist("dragon_ability_elec");
4278  else if (atnr == ATNR_POISON)
4279  trlist = find_treasurelist("dragon_ability_poison");
4280 
4281  if (trlist == NULL || who->type != PLAYER)
4282  return;
4283 
4284  // tr->magic is being used to define what level of the metabolism the ability is gained at.
4285  for (tr = trlist->items; tr != NULL && tr->magic != level; tr = tr->next)
4286  ;
4287  if (tr == NULL || tr->item == NULL) {
4288  /* LOG(llevDebug, "-> no more treasure for %s\n", change_resist_msg[atnr]); */
4289  return;
4290  }
4291 
4292  /* everything seems okay - now bring on the gift: */
4293  item = &(tr->item->clone);
4294 
4295  if (item->type == SPELL) {
4296  if (check_spell_known(who, item->name))
4297  return;
4298 
4301  "You gained the ability of %s",
4302  item->name);
4303  do_learn_spell(who, item, 0);
4304  return;
4305  }
4306 
4307  /* grant direct spell */
4308  if (item->type == SPELLBOOK) {
4309  if (!item->inv) {
4310  LOG(llevDebug, "dragon_ability_gain: Broken spellbook %s\n", item->name);
4311  return;
4312  }
4313  if (check_spell_known(who, item->inv->name))
4314  return;
4315  if (item->invisible) {
4318  "You gained the ability of %s",
4319  item->inv->name);
4320  do_learn_spell(who, item->inv, 0);
4321  return;
4322  }
4323  } else if (item->type == SKILL_TOOL && item->invisible) {
4324  if (item->subtype == SK_CLAWING && (skop = find_skill_by_name(who, item->skill)) != NULL) {
4325  /* should this perhaps be (skop->attackyp&item->attacktype) != item->attacktype ...
4326  * in this way, if the player is missing any of the attacktypes, he gets
4327  * them. As it is now, if the player has any that match the granted skill,
4328  * but not all of them, he gets nothing.
4329  */
4330  if (!(skop->attacktype&item->attacktype)) {
4331  /* Give new attacktype */
4332  skop->attacktype |= item->attacktype;
4333 
4334  /* always add physical if there's none */
4335  skop->attacktype |= AT_PHYSICAL;
4336 
4337  if (item->msg != NULL)
4340  item->msg);
4341 
4342  /* Give player new face */
4343  if (item->animation) {
4344  who->face = skop->face;
4345  who->animation = item->animation;
4346  who->anim_speed = item->anim_speed;
4347  who->last_anim = 0;
4348  who->state = 0;
4349  animate_object(who, who->direction);
4350  }
4351  }
4352  }
4353  } else if (item->type == FORCE) {
4354  /* forces in the treasurelist can alter the player's stats */
4355  object *skin;
4356 
4357  /* first get the dragon skin force */
4358  skin = object_find_by_arch_name(who, "dragon_skin_force");
4359  if (skin == NULL)
4360  return;
4361 
4362  /* adding new spellpath attunements */
4363  if (item->path_attuned > 0 && !(skin->path_attuned&item->path_attuned)) {
4364  skin->path_attuned |= item->path_attuned; /* add attunement to skin */
4365 
4366  /* print message */
4367  snprintf(buf, sizeof(buf), "You feel attuned to ");
4368  for (i = 0, j = 0; i < NRSPELLPATHS; i++) {
4369  if (item->path_attuned&(1<<i)) {
4370  if (j)
4371  strcat(buf, " and ");
4372  else
4373  j = 1;
4374  strcat(buf, spellpathnames[i]);
4375  }
4376  }
4377  strcat(buf, ".");
4380  buf);
4381  }
4382 
4383  /* evtl. adding flags: */
4384  if (QUERY_FLAG(item, FLAG_XRAYS))
4385  SET_FLAG(skin, FLAG_XRAYS);
4387  SET_FLAG(skin, FLAG_STEALTH);
4389  SET_FLAG(skin, FLAG_SEE_IN_DARK);
4390 
4391  /* print message if there is one */
4392  if (item->msg != NULL)
4395  item->msg);
4396  } else {
4397  /* generate misc. treasure */
4398  char name[HUGE_BUF];
4399 
4400  tmp = arch_to_object(tr->item);
4404  "You gained %s",
4405  name);
4407  if (who->type == PLAYER)
4409  }
4410 }
4411 
4422  rangetype i;
4423 
4424  for (i = 0; i < range_size; i++) {
4425  if (pl->ranges[i] == ob) {
4426  pl->ranges[i] = NULL;
4427  if (pl->shoottype == i) {
4428  pl->shoottype = range_none;
4429  }
4430  }
4431  }
4432 }
4433 
4439 void player_set_state(player *pl, uint8_t state) {
4440 
4441  assert(pl);
4442  assert(state <= ST_CHANGE_PASSWORD_CONFIRM);
4443  pl->state = state;
4444 }
4445 
4453  SockList *sl;
4454  assert(pl);
4458  if (!pl->delayed_buffers) {
4459  LOG(llevError, "Unable to allocated %d delayed buffers, aborting\n", pl->delayed_buffers_allocated);
4461  }
4462  for (uint8_t s = pl->delayed_buffers_allocated - 5; s < pl->delayed_buffers_allocated; s++) {
4463  pl->delayed_buffers[s] = calloc(1, sizeof(SockList));
4464  }
4465  }
4468  SockList_Init(sl);
4469  return sl;
4470 }
object_was_destroyed
#define object_was_destroyed(op, old_tag)
Definition: object.h:68
ADD_PLAYER_NO_STATS_ROLL
#define ADD_PLAYER_NO_STATS_ROLL
Definition: player.h:246
treasurestruct::item
struct archt * item
Definition: treasure.h:64
give.next
def next
Definition: give.py:44
stand_near_hostile
int stand_near_hostile(object *who)
Definition: player.c:4046
GET_MAP_OB
#define GET_MAP_OB(M, X, Y)
Definition: map.h:173
MSG_TYPE_COMMAND_NEWPLAYER
#define MSG_TYPE_COMMAND_NEWPLAYER
Definition: newclient.h:536
do_skill
int do_skill(object *op, object *part, object *skill, int dir, const char *string)
Definition: skill_util.c:422
apply_changes_to_player
void apply_changes_to_player(object *pl, object *change, int limit_stats)
Definition: apply.c:1668
UP_OBJ_FACE
#define UP_OBJ_FACE
Definition: object.h:519
pl::delayed_buffers
SockList ** delayed_buffers
Definition: player.h:225
PLAYER
@ PLAYER
Definition: object.h:107
PU_BOOTS
#define PU_BOOTS
Definition: define.h:125
receive_play_again
void receive_play_again(object *op, char key)
Definition: player.c:948
do_hidden_move
void do_hidden_move(object *op)
Definition: player.c:4005
SockList_AddInt
void SockList_AddInt(SockList *sl, uint32_t data)
Definition: lowlevel.c:124
global.h
FLAG_NEUTRAL
#define FLAG_NEUTRAL
Definition: define.h:354
UPD_FACE
#define UPD_FACE
Definition: newclient.h:317
add_refcount
sstring add_refcount(sstring str)
Definition: shstr.c:210
bow_nw
@ bow_nw
Definition: player.h:52
SOUND_TYPE_ITEM
#define SOUND_TYPE_ITEM
Definition: newclient.h:335
liv::dam
int16_t dam
Definition: living.h:46
object_free
void object_free(object *ob, int flags)
Definition: object.c:1578
fix_weight
void fix_weight(void)
Definition: player.c:3854
add_string
sstring add_string(const char *str)
Definition: shstr.c:124
object_find_by_flag_applied
object * object_find_by_flag_applied(const object *who, int flag)
Definition: object.c:4200
object_remove
void object_remove(object *op)
Definition: object.c:1819
safe_strncpy
#define safe_strncpy
Definition: compat.h:27
FOR_MAP_FINISH
#define FOR_MAP_FINISH()
Definition: define.h:730
remove_friendly_object
void remove_friendly_object(object *op)
Definition: friend.cpp:56
pets_terminate_all
void pets_terminate_all(object *owner)
Definition: pets.c:225
object_sum_weight
signed long object_sum_weight(object *op)
Definition: object.c:572
get_player
player * get_player(player *p)
Definition: player.c:282
kill_player
void kill_player(object *op, const object *killer)
Definition: player.c:3463
object_set_enemy
void object_set_enemy(object *op, object *enemy)
Definition: object.c:919
obj::face
const Face * face
Definition: object.h:336
ST_GET_PASSWORD
#define ST_GET_PASSWORD
Definition: define.h:547
MSG_TYPE_COMMAND_SUCCESS
#define MSG_TYPE_COMMAND_SUCCESS
Definition: newclient.h:530
FLAG_CONFUSED
#define FLAG_CONFUSED
Definition: define.h:311
BOW
@ BOW
Definition: object.h:118
Settings::emergency_y
uint16_t emergency_y
Definition: global.h:295
remove_statbonus
void remove_statbonus(object *op)
Definition: living.c:846
llevError
@ llevError
Definition: logger.h:11
FABS
#define FABS(x)
Definition: define.h:22
MOVE_ALL
#define MOVE_ALL
Definition: define.h:398
command_search_items
void command_search_items(object *op, const char *params)
Definition: c_object.c:2328
WAND
@ WAND
Definition: object.h:220
range_bow
@ range_bow
Definition: player.h:31
MSG_TYPE_ADMIN_PLAYER
#define MSG_TYPE_ADMIN_PLAYER
Definition: newclient.h:496
FLAG_UNDEAD
#define FLAG_UNDEAD
Definition: define.h:270
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:224
similar_direction
static int similar_direction(int a, int b)
Definition: player.c:2251
FLESH
@ FLESH
Definition: object.h:187
monster_can_detect_enemy
int monster_can_detect_enemy(object *op, object *enemy, rv_vector *rv)
Definition: monster.c:2569
roll_again
void roll_again(object *op)
Definition: player.c:1128
PU_ARROW
#define PU_ARROW
Definition: define.h:120
PU_NOT_CURSED
#define PU_NOT_CURSED
Definition: define.h:140
esrv_map_scroll
void esrv_map_scroll(socket_struct *ns, int dx, int dy)
Definition: request.c:1613
display_motd
void display_motd(const object *op)
Definition: player.c:136
strdup_local
#define strdup_local
Definition: compat.h:29
Settings::resurrection
uint8_t resurrection
Definition: global.h:261
recursive_roll
void recursive_roll(object *op, int dir, object *pusher)
Definition: move.c:293
socket_struct::look_position
uint16_t look_position
Definition: newserver.h:114
object_update
void object_update(object *op, int action)
Definition: object.c:1420
diamondslots.x
x
Definition: diamondslots.py:15
FLAG_STARTEQUIP
#define FLAG_STARTEQUIP
Definition: define.h:268
obj::count
tag_t count
Definition: object.h:302
obj::map
struct mapdef * map
Definition: object.h:300
MSG_TYPE_SKILL
#define MSG_TYPE_SKILL
Definition: newclient.h:407
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
obj::race
sstring race
Definition: object.h:321
get_next_archetype
archetype * get_next_archetype(archetype *current)
Definition: assets.cpp:280
Settings::set_title
uint8_t set_title
Definition: global.h:260
remove_locked_door
void remove_locked_door(object *op)
Definition: time.c:64
pl::peaceful
uint32_t peaceful
Definition: player.h:146
SK_CLAWING
@ SK_CLAWING
Definition: skills.h:50
ARCH_DEPLETION
#define ARCH_DEPLETION
Definition: object.h:576
NDI_GREEN
#define NDI_GREEN
Definition: newclient.h:249
liv::wc
int8_t wc
Definition: living.h:37
KEY
@ KEY
Definition: object.h:127
PU_INHIBIT
#define PU_INHIBIT
Definition: define.h:109
do_learn_spell
void do_learn_spell(object *op, object *spell, int special_prayer)
Definition: apply.c:484
socket_struct
Definition: newserver.h:89
socket_struct::mapx
uint8_t mapx
Definition: newserver.h:116
MAX_SPACES
#define MAX_SPACES
Definition: player.c:610
ST_GET_NAME
#define ST_GET_NAME
Definition: define.h:546
player_get_delayed_buffer
SockList * player_get_delayed_buffer(player *pl)
Definition: player.c:4452
out_of_map
int out_of_map(mapstruct *m, int x, int y)
Definition: map.c:2312
esrv_new_player
void esrv_new_player(player *pl, uint32_t weight)
Definition: request.c:942
FLAG_SEE_IN_DARK
#define FLAG_SEE_IN_DARK
Definition: define.h:337
Settings::not_permadeth
uint8_t not_permadeth
Definition: global.h:257
price_base
uint64_t price_base(const object *obj)
Definition: shop.c:75
lose_msg
const char *const lose_msg[NUM_STATS]
Definition: living.c:173
get_friends_of
objectlink * get_friends_of(const object *owner)
Definition: friend.cpp:121
object_new
object * object_new(void)
Definition: object.c:1255
esrv_send_inventory
void esrv_send_inventory(object *pl, object *op)
Definition: item.c:315
key_roll_stat
void key_roll_stat(object *op, char key)
Definition: player.c:1200
AT_PHYSICAL
#define AT_PHYSICAL
Definition: attack.h:76
cast_spell
int cast_spell(object *op, object *caster, int dir, object *spell_ob, char *stringarg)
Definition: spell_util.c:1420
disinfect.a
a
Definition: disinfect.py:13
object_find_by_arch_name
object * object_find_by_arch_name(const object *who, const char *name)
Definition: object.c:4223
get_player_archetype
static archetype * get_player_archetype(archetype *at)
Definition: player.c:506
obj::path_attuned
uint32_t path_attuned
Definition: object.h:348
SockList_AddString
void SockList_AddString(SockList *sl, const char *data)
Definition: lowlevel.c:154
pl::socket
socket_struct socket
Definition: player.h:107
FOR_BELOW_PREPARE
#define FOR_BELOW_PREPARE(op_, it_)
Definition: define.h:704
GEM
@ GEM
Definition: object.h:167
FLAG_UNIQUE
#define FLAG_UNIQUE
Definition: define.h:287
pl::shoottype
rangetype shoottype
Definition: player.h:112
pl
Definition: player.h:105
MSG_TYPE_VICTIM_DIED
#define MSG_TYPE_VICTIM_DIED
Definition: newclient.h:656
EXIT_PATH
#define EXIT_PATH(xyz)
Definition: define.h:439
TRAP
@ TRAP
Definition: object.h:241
pl::blocked_los
int8_t blocked_los[MAP_CLIENT_X][MAP_CLIENT_Y]
Definition: player.h:177
fire
void fire(object *op, int dir)
Definition: player.c:2373
spring_trap
void spring_trap(object *trap, object *victim)
Definition: rune.c:205
guildoracle.list
list
Definition: guildoracle.py:87
apply_map_builder
void apply_map_builder(object *pl, int dir)
Definition: build_map.c:959
PREFER_LOW
#define PREFER_LOW
Definition: define.h:564
PU_FOOD
#define PU_FOOD
Definition: define.h:115
arch_present_in_ob
object * arch_present_in_ob(const archetype *at, const object *op)
Definition: object.c:3193
pl::swap_first
int swap_first
Definition: player.h:165
object_matches_string
int object_matches_string(object *pl, object *op, const char *name)
Definition: object.c:4545
esrv_send_pickup
void esrv_send_pickup(player *pl)
Definition: request.c:1740
guildjoin.ob
ob
Definition: guildjoin.py:42
PU_BOW
#define PU_BOW
Definition: define.h:118
liv::hp
int16_t hp
Definition: living.h:40
MSG_TYPE_ATTRIBUTE
#define MSG_TYPE_ATTRIBUTE
Definition: newclient.h:405
GT_ONLY_GOOD
@ GT_ONLY_GOOD
Definition: treasure.h:34
range_none
@ range_none
Definition: player.h:30
PU_MAGIC_DEVICE
#define PU_MAGIC_DEVICE
Definition: define.h:138
commongive.inv
inv
Definition: commongive.py:28
find_player_socket
player * find_player_socket(const socket_struct *ns)
Definition: player.c:120
SET_ANIMATION
#define SET_ANIMATION(ob, newanim)
Definition: global.h:159
CHARISMA
@ CHARISMA
Definition: living.h:15
party_rejoin_if_exists
@ party_rejoin_if_exists
Definition: player.h:100
set_first_map
void set_first_map(object *op)
Definition: player.c:401
blocked_link
int blocked_link(object *ob, mapstruct *m, int16_t sx, int16_t sy)
Definition: map.c:345
MIN
#define MIN(x, y)
Definition: compat.h:21
CS_QUERY_SINGLECHAR
#define CS_QUERY_SINGLECHAR
Definition: newclient.h:67
pl::ob
object * ob
Definition: player.h:176
play_sound_player_only
void play_sound_player_only(player *pl, int8_t sound_type, object *emitter, int dir, const char *action)
Definition: sounds.c:51
bow_threewide
@ bow_threewide
Definition: player.h:43
SKILL
@ SKILL
Definition: object.h:143
pl::delayed_buffers_used
uint8_t delayed_buffers_used
Definition: player.h:224
play_sound_map
void play_sound_map(int8_t sound_type, object *emitter, int dir, const char *action)
Definition: sounds.c:113
object_can_merge
int object_can_merge(object *ob1, object *ob2)
Definition: object.c:433
RUNE
@ RUNE
Definition: object.h:240
pl::bowtype
bowtype_t bowtype
Definition: player.h:114
FLAG_SCARED
#define FLAG_SCARED
Definition: define.h:271
Settings::roll_stat_points
uint8_t roll_stat_points
Definition: global.h:318
ob_blocked
int ob_blocked(const object *ob, mapstruct *m, int16_t x, int16_t y)
Definition: map.c:488
find_treasurelist
treasurelist * find_treasurelist(const char *name)
Definition: assets.cpp:263
Ice.tmp
int tmp
Definition: Ice.py:207
PU_MISSILEWEAPON
#define PU_MISSILEWEAPON
Definition: define.h:130
apply_race_and_class
int apply_race_and_class(object *op, archetype *race, archetype *opclass, living *stats)
Definition: player.c:1466
NDI_NAVY
#define NDI_NAVY
Definition: newclient.h:244
Settings::emergency_x
uint16_t emergency_x
Definition: global.h:295
action_makes_visible
static int action_makes_visible(object *op)
Definition: player.c:4166
TRANSPORT
@ TRANSPORT
Definition: object.h:108
SOUND_TYPE_LIVING
#define SOUND_TYPE_LIVING
Definition: newclient.h:333
socket_struct::inbuf
SockList inbuf
Definition: newserver.h:99
flags
static const flag_definition flags[]
Definition: gridarta-types-convert.c:101
PU_FLESH
#define PU_FLESH
Definition: define.h:142
player_set_own_title
void player_set_own_title(struct pl *pl, const char *title)
Definition: player.c:272
NROFATTACKS
#define NROFATTACKS
Definition: attack.h:17
obj::msg
sstring msg
Definition: object.h:325
PU_READABLES
#define PU_READABLES
Definition: define.h:137
first_map_path
EXTERN char first_map_path[MAX_BUF]
Definition: global.h:141
roll_stats
void roll_stats(object *op)
Definition: player.c:1054
get_rangevector
int get_rangevector(object *op1, const object *op2, rv_vector *retval, int flags)
Definition: map.c:2545
move_player
int move_player(object *op, int dir)
Definition: player.c:2923
BALSL_LOSS_CHANCE_RATIO
#define BALSL_LOSS_CHANCE_RATIO
Definition: config.h:142
send_account_players
void send_account_players(socket_struct *ns)
Definition: request.c:1981
skills.h
pl::last_resist
int16_t last_resist[NROFATTACKS]
Definition: player.h:173
PU_POTION
#define PU_POTION
Definition: define.h:133
MSG_TYPE_COMMAND_ERROR
#define MSG_TYPE_COMMAND_ERROR
Definition: newclient.h:529
roll_stat
int roll_stat(void)
Definition: player.c:1030
esrv_add_spells
void esrv_add_spells(player *pl, object *spell)
Definition: request.c:1854
range_golem
@ range_golem
Definition: player.h:34
pl::last_weapon_sp
float last_weapon_sp
Definition: player.h:156
first_map
EXTERN mapstruct * first_map
Definition: global.h:116
FLAG_INV_LOCKED
#define FLAG_INV_LOCKED
Definition: define.h:329
apply_manual
int apply_manual(object *op, object *tmp, int aflag)
Definition: apply.c:597
create_treasure
void create_treasure(treasurelist *t, object *op, int flag, int difficulty, int tries)
Definition: treasure.c:241
P_IS_ALIVE
#define P_IS_ALIVE
Definition: map.h:238
MSG_TYPE_MISC
#define MSG_TYPE_MISC
Definition: newclient.h:413
get_dex_bonus
int get_dex_bonus(int stat)
Definition: living.c:2354
FLAG_APPLIED
#define FLAG_APPLIED
Definition: define.h:235
NDI_BLUE
#define NDI_BLUE
Definition: newclient.h:247
FLAG_STEALTH
#define FLAG_STEALTH
Definition: define.h:312
face_player
int face_player(object *op, int dir)
Definition: player.c:3002
events_execute_object_event
int events_execute_object_event(object *op, int eventcode, object *activator, object *third, const char *message, int fix)
Definition: events.cpp:274
BALSL_MAX_LOSS_RATIO
#define BALSL_MAX_LOSS_RATIO
Definition: config.h:144
GT_STARTEQUIP
@ GT_STARTEQUIP
Definition: treasure.h:33
pl::last_speed
float last_speed
Definition: player.h:172
Moving_Fog.z
z
Definition: Moving_Fog.py:17
hiscore_check
void hiscore_check(object *op, int quiet)
Definition: hiscore.c:346
HUGE_BUF
#define HUGE_BUF
Definition: define.h:37
treasurestruct
Definition: treasure.h:63
make_path_to_file
void make_path_to_file(const char *filename)
Definition: porting.c:162
MSG_TYPE_VICTIM
#define MSG_TYPE_VICTIM
Definition: newclient.h:415
ob_process
method_ret ob_process(object *op)
Definition: ob_methods.c:67
MSG_TYPE_COMMAND
#define MSG_TYPE_COMMAND
Definition: newclient.h:404
MAX
#define MAX(x, y)
Definition: compat.h:24
WISDOM
@ WISDOM
Definition: living.h:14
player_set_state
void player_set_state(player *pl, uint8_t state)
Definition: player.c:4439
freearr_x
short freearr_x[SIZEOFFREE]
Definition: object.c:299
AT_DEATH
#define AT_DEATH
Definition: attack.h:93
obj::nrof
uint32_t nrof
Definition: object.h:337
FLAG_NO_PICK
#define FLAG_NO_PICK
Definition: define.h:239
freearr_y
short freearr_y[SIZEOFFREE]
Definition: object.c:305
MSG_TYPE_SPELL_END
#define MSG_TYPE_SPELL_END
Definition: newclient.h:634
playername_ok
int playername_ok(const char *cp)
Definition: player.c:254
FOR_BELOW_FINISH
#define FOR_BELOW_FINISH()
Definition: define.h:711
MIN_STAT
#define MIN_STAT
Definition: define.h:33
archt
Definition: object.h:469
settings
struct Settings settings
Definition: init.c:39
FLAG_ALIVE
#define FLAG_ALIVE
Definition: define.h:230
check_race_and_class
int check_race_and_class(living *stats, archetype *race, archetype *opclass)
Definition: player.c:1416
MSG_TYPE_MOTD
#define MSG_TYPE_MOTD
Definition: newclient.h:401
animate_object
void animate_object(object *op, int dir)
Definition: anim.c:43
range_builder
@ range_builder
Definition: player.h:36
esrv_send_item
void esrv_send_item(object *pl, object *op)
Definition: main.c:355
socket_struct::update_look
uint32_t update_look
Definition: newserver.h:104
rv_vector::distance_y
int distance_y
Definition: map.h:376
MSG_TYPE_COMMAND_DEBUG
#define MSG_TYPE_COMMAND_DEBUG
Definition: newclient.h:528
obj::slaying
sstring slaying
Definition: object.h:322
AP_NULL
#define AP_NULL
Definition: define.h:573
free_string
void free_string(sstring str)
Definition: shstr.c:280
PU_GLOVES
#define PU_GLOVES
Definition: define.h:126
remove_door
void remove_door(object *op)
Definition: time.c:38
PU_CONTAINER
#define PU_CONTAINER
Definition: define.h:143
m
static event_registration m
Definition: citylife.cpp:427
liv::luck
int8_t luck
Definition: living.h:39
handle_newcs_player
int handle_newcs_player(object *op)
Definition: player.c:3061
rv_vector::distance_x
int distance_x
Definition: map.h:375
socket_struct::account_chars
Account_Chars * account_chars
Definition: newserver.h:127
autojail.who
who
Definition: autojail.py:3
has_carried_lights
int has_carried_lights(const object *op)
Definition: los.c:315
socket_struct::mapy
uint8_t mapy
Definition: newserver.h:116
pl::savebed_map
char savebed_map[MAX_BUF]
Definition: player.h:110
MAP_IN_MEMORY
#define MAP_IN_MEMORY
Definition: map.h:131
object_find_by_type_subtype
object * object_find_by_type_subtype(const object *who, int type, int subtype)
Definition: object.c:4272
liv::exp
int64_t exp
Definition: living.h:47
Ns_Avail
@ Ns_Avail
Definition: newserver.h:65
object_find_by_type_without_flags
object * object_find_by_type_without_flags(const object *who, int type, int *flags, int num_flags)
Definition: object.c:3975
pl::next
struct pl * next
Definition: player.h:106
PREFER_HIGH
#define PREFER_HIGH
Definition: define.h:563
EVENT_LOGIN
#define EVENT_LOGIN
Definition: events.h:43
remove_unpaid_objects
void remove_unpaid_objects(object *op, object *env, int free_items)
Definition: player.c:3182
save_life
static int save_life(object *op)
Definition: player.c:3139
disinfect.map
map
Definition: disinfect.py:4
object_decrease_nrof_by_one
#define object_decrease_nrof_by_one(xyz)
Definition: compat.h:32
POISON
@ POISON
Definition: object.h:113
link_player_skills
void link_player_skills(object *op)
Definition: player.c:287
PU_RATIO
#define PU_RATIO
Definition: define.h:113
Settings::balanced_stat_loss
uint8_t balanced_stat_loss
Definition: global.h:256
BALSL_NUMBER_LOSSES_RATIO
#define BALSL_NUMBER_LOSSES_RATIO
Definition: config.h:143
object_find_by_type_and_slaying
object * object_find_by_type_and_slaying(const object *who, int type, const char *slaying)
Definition: object.c:4129
oblnk::next
struct oblnk * next
Definition: object.h:448
MSG_TYPE_ATTRIBUTE_STAT_LOSS
#define MSG_TYPE_ATTRIBUTE_STAT_LOSS
Definition: newclient.h:569
FLAG_WAS_WIZ
#define FLAG_WAS_WIZ
Definition: define.h:234
MSG_TYPE_ADMIN_NEWS
#define MSG_TYPE_ADMIN_NEWS
Definition: newclient.h:495
make_visible
void make_visible(object *op)
Definition: player.c:3920
bow_n
@ bow_n
Definition: player.h:45
obj::name
sstring name
Definition: object.h:314
strip_endline
void strip_endline(char *buf)
Definition: utils.c:324
cast_dust
void cast_dust(object *op, object *throw_ob, int dir)
Definition: player.c:3891
enter_player_savebed
void enter_player_savebed(object *op)
Definition: server.c:138
PU_KEY
#define PU_KEY
Definition: define.h:128
determine_god
const char * determine_god(object *op)
Definition: gods.c:55
MSG_TYPE_ATTRIBUTE_RACE
#define MSG_TYPE_ATTRIBUTE_RACE
Definition: newclient.h:564
pl::state
uint8_t state
Definition: player.h:131
move_player_attack
void move_player_attack(object *op, int dir)
Definition: player.c:2598
is_identifiable_type
int is_identifiable_type(const object *op)
Definition: item.c:1312
bow_bestarrow
@ bow_bestarrow
Definition: player.h:53
ST_CHANGE_PASSWORD_CONFIRM
#define ST_CHANGE_PASSWORD_CONFIRM
Definition: define.h:552
object_copy
void object_copy(const object *src_ob, object *dest_ob)
Definition: object.c:1064
range_size
@ range_size
Definition: player.h:37
move_ob
int move_ob(object *op, int dir, object *originator)
Definition: move.c:58
MSG_TYPE_APPLY_SUCCESS
#define MSG_TYPE_APPLY_SUCCESS
Definition: newclient.h:603
player_can_view
int player_can_view(object *pl, object *op)
Definition: player.c:4114
query_name
void query_name(const object *op, char *buf, size_t size)
Definition: item.c:585
confirm_password
void confirm_password(object *op)
Definition: player.c:998
treasurestruct::magic
uint8_t magic
Definition: treasure.h:71
mon
object * mon
Definition: comet_perf.c:75
pl::unarmed_skill
const char * unarmed_skill
Definition: player.h:220
POTION
@ POTION
Definition: object.h:111
object_update_turn_face
void object_update_turn_face(object *op)
Definition: object.c:1313
pet_normal
@ pet_normal
Definition: player.h:58
MOVE_WALK
#define MOVE_WALK
Definition: define.h:392
FLAG_KNOWN_CURSED
#define FLAG_KNOWN_CURSED
Definition: define.h:320
ST_PLAY_AGAIN
#define ST_PLAY_AGAIN
Definition: define.h:542
ADD_PLAYER_NO_MAP
#define ADD_PLAYER_NO_MAP
Definition: player.h:245
calc_skill_exp
int64_t calc_skill_exp(const object *who, const object *op, const object *skill)
Definition: skill_util.c:658
account_char_free
void account_char_free(Account_Chars *chars)
Definition: account_char.c:362
get_randomized_dir
int get_randomized_dir(int dir)
Definition: utils.c:422
pl::petmode
petmode_t petmode
Definition: player.h:115
key_confirm_quit
void key_confirm_quit(object *op, char key)
Definition: player.c:1579
party_leave
void party_leave(object *op)
Definition: party.c:123
account_remove_player
int account_remove_player(const char *account_name, const char *player_name)
Definition: account.c:479
FOR_OB_AND_BELOW_FINISH
#define FOR_OB_AND_BELOW_FINISH()
Definition: define.h:754
HEAD
#define HEAD(op)
Definition: object.h:593
fatal
void fatal(enum fatal_error err)
Definition: utils.c:580
range_magic
@ range_magic
Definition: player.h:32
apply_container
int apply_container(object *op, object *sack, int aflags)
Definition: apply.c:222
ROD
@ ROD
Definition: object.h:109
object_can_pick
int object_can_pick(const object *who, const object *item)
Definition: object.c:3838
player_unready_range_ob
void player_unready_range_ob(player *pl, object *ob)
Definition: player.c:4421
CONTAINER
@ CONTAINER
Definition: object.h:231
enter_player_maplevel
void enter_player_maplevel(object *op)
Definition: server.c:687
swap_stat
static void swap_stat(object *op, int swap_second)
Definition: player.c:1142
obj::speed_left
float speed_left
Definition: object.h:333
loot_object
static void loot_object(object *op)
Definition: player.c:3386
SockList_AddChar
void SockList_AddChar(SockList *sl, unsigned char c)
Definition: lowlevel.c:103
PU_STOP
#define PU_STOP
Definition: define.h:110
PU_VALUABLES
#define PU_VALUABLES
Definition: define.h:117
find_player
player * find_player(const char *plname)
Definition: player.c:56
FLAG_FREED
#define FLAG_FREED
Definition: define.h:233
delete_character
void delete_character(const char *name)
Definition: login.c:88
Settings::motd
char motd[MAX_BUF]
Definition: global.h:273
LOCKED_DOOR
@ LOCKED_DOOR
Definition: object.h:123
MSG_TYPE_ITEM
#define MSG_TYPE_ITEM
Definition: newclient.h:412
socket_struct::host
char * host
Definition: newserver.h:100
SCRIPT_FIX_ALL
#define SCRIPT_FIX_ALL
Definition: global.h:377
MSG_TYPE_ATTACK
#define MSG_TYPE_ATTACK
Definition: newclient.h:409
query_short_name
void query_short_name(const object *op, char *buf, size_t size)
Definition: item.c:510
FLAG_MAKE_INVIS
#define FLAG_MAKE_INVIS
Definition: define.h:328
Settings::rules
const char * rules
Definition: global.h:274
SPECIAL_KEY
@ SPECIAL_KEY
Definition: object.h:124
absdir
int absdir(int d)
Definition: object.c:3685
MOVE_FLYING
#define MOVE_FLYING
Definition: define.h:395
obj::spellarg
char * spellarg
Definition: object.h:414
socket_struct::account_name
char * account_name
Definition: newserver.h:126
get_dam_bonus
int get_dam_bonus(int stat)
Definition: living.c:2378
POWER
@ POWER
Definition: living.h:17
SPELL_HIGHEST
#define SPELL_HIGHEST
Definition: spells.h:60
obj::carrying
int32_t carrying
Definition: object.h:372
FREE_AND_COPY
#define FREE_AND_COPY(sv, nv)
Definition: global.h:201
Settings::news
const char * news
Definition: global.h:275
Ice.b
b
Definition: Ice.py:48
get_party_password
int get_party_password(object *op, partylist *party)
Definition: player.c:1013
pl::no_shout
uint32_t no_shout
Definition: player.h:148
first_player
EXTERN player * first_player
Definition: global.h:115
EVENT_BORN
#define EVENT_BORN
Definition: events.h:38
guild_questpoints_apply.mapname
mapname
Definition: guild_questpoints_apply.py:8
obj::x
int16_t x
Definition: object.h:330
DETOUR_AMOUNT
#define DETOUR_AMOUNT
Definition: player.c:595
FLAG_DAMNED
#define FLAG_DAMNED
Definition: define.h:317
socket_struct::monitor_spells
uint32_t monitor_spells
Definition: newserver.h:110
fix_object
void fix_object(object *op)
Definition: living.c:1126
FLAG_PARALYZED
#define FLAG_PARALYZED
Definition: define.h:371
Settings::stat_loss_on_death
uint8_t stat_loss_on_death
Definition: global.h:251
CFweardisguise.tag
tag
Definition: CFweardisguise.py:25
FLAG_USE_SHIELD
#define FLAG_USE_SHIELD
Definition: define.h:237
key_change_class
void key_change_class(object *op, char key)
Definition: player.c:1276
update_transport_block
static void update_transport_block(object *transport, int dir)
Definition: player.c:2775
leave
void leave(player *pl, int draw_exit)
Definition: server.c:1302
GET_MAP_MOVE_BLOCK
#define GET_MAP_MOVE_BLOCK(M, X, Y)
Definition: map.h:193
FOR_INV_FINISH
#define FOR_INV_FINISH()
Definition: define.h:677
FLAG_CAN_ROLL
#define FLAG_CAN_ROLL
Definition: define.h:254
pl::has_hit
uint32_t has_hit
Definition: player.h:144
clear_player
void clear_player(player *pl)
Definition: player.c:33
PU_SPELLBOOK
#define PU_SPELLBOOK
Definition: define.h:135
find_arrow
static object * find_arrow(object *op, const char *type)
Definition: player.c:1909
FLAG_UNAGGRESSIVE
#define FLAG_UNAGGRESSIVE
Definition: define.h:272
obj::speed
float speed
Definition: object.h:332
say.max
dictionary max
Definition: say.py:148
rangetype
rangetype
Definition: player.h:28
is_criminal
bool is_criminal(object *op)
Definition: player.c:312
tag_t
uint32_t tag_t
Definition: object.h:12
op_on_battleground
int op_on_battleground(object *op, int *x, int *y, archetype **trophy)
Definition: player.c:4213
PU_MELEEWEAPON
#define PU_MELEEWEAPON
Definition: define.h:131
ATNR_POISON
#define ATNR_POISON
Definition: attack.h:59
find_better_arrow
static object * find_better_arrow(object *op, object *target, const char *type, int *better)
Definition: player.c:1941
Settings::confdir
const char * confdir
Definition: global.h:242
FLAG_USE_WEAPON
#define FLAG_USE_WEAPON
Definition: define.h:296
sproto.h
ARROW
@ ARROW
Definition: object.h:117
FLAG_NO_DROP
#define FLAG_NO_DROP
Definition: define.h:288
get_name
void get_name(object *op)
Definition: player.c:873
IS_SHIELD
#define IS_SHIELD(op)
Definition: define.h:170
MAX_SKILLS
#define MAX_SKILLS
Definition: skills.h:70
kill_player_not_permadeath
static void kill_player_not_permadeath(object *op)
Definition: player.c:3544
FIND_PLAYER_PARTIAL_NAME
#define FIND_PLAYER_PARTIAL_NAME
Definition: player.h:234
AC_PLAYER_STAT_NO_CHANGE
#define AC_PLAYER_STAT_NO_CHANGE
Definition: define.h:597
FLAG_CAN_USE_SKILL
#define FLAG_CAN_USE_SKILL
Definition: define.h:321
PU_MAGICAL
#define PU_MAGICAL
Definition: define.h:132
apply_death_exp_penalty
void apply_death_exp_penalty(object *op)
Definition: living.c:2233
obj::enemy
struct obj * enemy
Definition: object.h:386
FOR_OB_AND_BELOW_PREPARE
#define FOR_OB_AND_BELOW_PREPARE(op_)
Definition: define.h:750
mapdef
Definition: map.h:317
MSG_TYPE_SPELL
#define MSG_TYPE_SPELL
Definition: newclient.h:411
SP_level_spellpoint_cost
int16_t SP_level_spellpoint_cost(object *caster, object *spell, int flags)
Definition: spell_util.c:235
MSG_SUBTYPE_NONE
#define MSG_SUBTYPE_NONE
Definition: newclient.h:420
delete_map
void delete_map(mapstruct *m)
Definition: map.c:1722
DEXTERITY
@ DEXTERITY
Definition: living.h:12
pl::unapply
unapplymode unapply
Definition: player.h:121
liv
Definition: living.h:35
SockList_Init
void SockList_Init(SockList *sl)
Definition: lowlevel.c:52
PU_HELMET
#define PU_HELMET
Definition: define.h:121
nlohmann::detail::void
j template void())
Definition: json.hpp:4099
player_fire_bow
static int player_fire_bow(object *op, int dir)
Definition: player.c:2285
set_player_socket
static void set_player_socket(player *p, socket_struct *ns)
Definition: player.c:420
FLAG_MONSTER
#define FLAG_MONSTER
Definition: define.h:245
party_struct
Definition: party.h:10
push_ob
int push_ob(object *who, int dir, object *pusher)
Definition: move.c:434
key_inventory
@ key_inventory
Definition: player.h:66
object_set_owner
void object_set_owner(object *op, object *owner)
Definition: object.c:844
find_skill_by_name
object * find_skill_by_name(object *who, const char *name)
Definition: skill_util.c:202
strlcpy
size_t strlcpy(char *dst, const char *src, size_t size)
Definition: porting.c:220
pl::listening
uint8_t listening
Definition: player.h:133
P_OUT_OF_MAP
#define P_OUT_OF_MAP
Definition: map.h:250
turn_transport
static int turn_transport(object *transport, object *captain, int dir)
Definition: player.c:2890
env
static std::shared_ptr< inja::Environment > env
Definition: mapper.cpp:2216
EXIT_X
#define EXIT_X(xyz)
Definition: define.h:441
MAX_BUF
#define MAX_BUF
Definition: define.h:35
object_get_multi_size
void object_get_multi_size(const object *ob, int *sx, int *sy, int *hx, int *hy)
Definition: object.c:4714
Ns_Add
@ Ns_Add
Definition: newserver.h:66
ADD_PLAYER_NEW
#define ADD_PLAYER_NEW
Definition: player.h:244
create_archetype
object * create_archetype(const char *name)
Definition: arch.cpp:281
IS_WEAPON
#define IS_WEAPON(op)
Definition: define.h:163
hideability
int hideability(object *ob)
Definition: player.c:3964
pl::last_weight
int32_t last_weight
Definition: player.h:158
bow_normal
@ bow_normal
Definition: player.h:42
clear_los
void clear_los(player *pl)
Definition: los.c:252
transfer_ob
int transfer_ob(object *op, int x, int y, int randomly, object *originator)
Definition: move.c:163
offsetof
#define offsetof(type, member)
Definition: shstr.h:37
Settings::playerdir
const char * playerdir
Definition: global.h:245
RANDOM
#define RANDOM()
Definition: define.h:644
SockList_Term
void SockList_Term(SockList *sl)
Definition: lowlevel.c:62
SK_HIDING
@ SK_HIDING
Definition: skills.h:21
FREE_AND_CLEAR_STR
#define FREE_AND_CLEAR_STR(xyz)
Definition: global.h:195
MOVE_FLY_LOW
#define MOVE_FLY_LOW
Definition: define.h:393
EVENT_PLAYER_DEATH
#define EVENT_PLAYER_DEATH
Definition: events.h:52
dead_player
void dead_player(object *op)
Definition: resurrection.c:297
ATNR_FIRE
#define ATNR_FIRE
Definition: attack.h:51
random_roll
int random_roll(int min, int max, const object *op, int goodbad)
Definition: utils.c:42
MSG_TYPE_ITEM_ADD
#define MSG_TYPE_ITEM_ADD
Definition: newclient.h:643
is_valid_types_gen.found
found
Definition: is_valid_types_gen.py:39
MSG_TYPE_COMMAND_FAILURE
#define MSG_TYPE_COMMAND_FAILURE
Definition: newclient.h:531
FOR_MAP_PREPARE
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Definition: define.h:723
obj::y
int16_t y
Definition: object.h:330
FLAG_KNOWN_MAGICAL
#define FLAG_KNOWN_MAGICAL
Definition: define.h:319
FIND_PLAYER_NO_HIDDEN_DM
#define FIND_PLAYER_NO_HIDDEN_DM
Definition: player.h:235
is_wraith_pl
int is_wraith_pl(object *op)
Definition: player.c:173
OUT_OF_REAL_MAP
#define OUT_OF_REAL_MAP(M, X, Y)
Definition: map.h:218
ST_PLAYING
#define ST_PLAYING
Definition: define.h:541
player_attack_door
static int player_attack_door(object *op, object *door)
Definition: player.c:2527
obj::arch
struct archt * arch
Definition: object.h:417
treasureliststruct::items
struct treasurestruct * items
Definition: treasure.h:89
object_set_msg
void object_set_msg(object *op, const char *msg)
Definition: object.c:4781
range_misc
@ range_misc
Definition: player.h:33
FLAG_READY_SKILL
#define FLAG_READY_SKILL
Definition: define.h:333
FLAG_READY_BOW
#define FLAG_READY_BOW
Definition: define.h:299
sounds.h
FLAG_REMOVED
#define FLAG_REMOVED
Definition: define.h:232
ST_CHANGE_CLASS
#define ST_CHANGE_CLASS
Definition: define.h:544
FLAG_WIZ
#define FLAG_WIZ
Definition: define.h:231
Settings::emergency_mapname
char * emergency_mapname
Definition: global.h:294
obj::type
uint8_t type
Definition: object.h:343
NDI_UNIQUE
#define NDI_UNIQUE
Definition: newclient.h:262
pticks
uint32_t pticks
Definition: time.c:47
roll-o-matic.stop
def stop()
Definition: roll-o-matic.py:78
FLAG_FRIENDLY
#define FLAG_FRIENDLY
Definition: define.h:246
spells.h
die_roll
int die_roll(int num, int size, const object *op, int goodbad)
Definition: utils.c:122
spellpathnames
const char *const spellpathnames[NRSPELLPATHS]
Definition: init.c:107
EVENT_DEATH
#define EVENT_DEATH
Definition: events.h:24
obj::stats
living stats
Definition: object.h:373
find_player_options
player * find_player_options(const char *plname, int options, const mapstruct *map)
Definition: player.c:67
PU_CLOAK
#define PU_CLOAK
Definition: define.h:127
bow_spreadshot
@ bow_spreadshot
Definition: player.h:44
BATTLEGROUND
@ BATTLEGROUND
Definition: object.h:163
MSG_TYPE_SKILL_FAILURE
#define MSG_TYPE_SKILL_FAILURE
Definition: newclient.h:590
obj::direction
int8_t direction
Definition: object.h:339
find_player_partial_name
player * find_player_partial_name(const char *plname)
Definition: player.c:111
archt::clone
object clone
Definition: object.h:473
pl::language
int language
Definition: player.h:219
party_get_password
const char * party_get_password(const partylist *party)
Definition: party.c:232
get_nearest_player
object * get_nearest_player(object *mon)
Definition: player.c:531
obj::contr
struct pl * contr
Definition: object.h:279
obj::facing
int8_t facing
Definition: object.h:340
pl::gen_sp_armour
int16_t gen_sp_armour
Definition: player.h:128
add_friendly_object
void add_friendly_object(object *op)
Definition: friend.cpp:36
fire_bow
int fire_bow(object *op, object *arrow, int dir, int wc_mod, int16_t sx, int16_t sy)
Definition: player.c:2080
ST_CONFIRM_PASSWORD
#define ST_CONFIRM_PASSWORD
Definition: define.h:548
IS_ARMOR
#define IS_ARMOR(op)
Definition: define.h:166
unapply_nochoice
@ unapply_nochoice
Definition: player.h:76
apply_anim_suffix
void apply_anim_suffix(object *who, const char *suffix)
Definition: anim.c:149
SOUND_TYPE_GROUND
#define SOUND_TYPE_GROUND
Definition: newclient.h:336
FLAG_USE_ARMOUR
#define FLAG_USE_ARMOUR
Definition: define.h:295
PU_JEWELS
#define PU_JEWELS
Definition: define.h:141
item
Definition: item.py:1
MSG_TYPE_ITEM_REMOVE
#define MSG_TYPE_ITEM_REMOVE
Definition: newclient.h:642
LOG
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:51
pl::last_skill_exp
int64_t last_skill_exp[MAX_SKILLS]
Definition: player.h:154
did_make_save
int did_make_save(const object *op, int level, int bonus)
Definition: living.c:2282
enter_exit
void enter_exit(object *op, object *exit_ob)
Definition: server.c:732
check_spell_known
object * check_spell_known(object *op, const char *name)
Definition: spell_util.c:393
pl::delayed_buffers_allocated
uint8_t delayed_buffers_allocated
Definition: player.h:223
liv::grace
int16_t grace
Definition: living.h:44
check_pick
int check_pick(object *op)
Definition: player.c:1704
give.op
op
Definition: give.py:33
NDI_ALL
#define NDI_ALL
Definition: newclient.h:263
socket_struct::status
enum Sock_Status status
Definition: newserver.h:90
get_password
void get_password(object *op)
Definition: player.c:884
STRENGTH
@ STRENGTH
Definition: living.h:11
object_value_set
bool object_value_set(const object *op, const char *const key)
Definition: object.c:4347
pl::do_los
uint32_t do_los
Definition: player.h:141
find_archetype
archetype * find_archetype(const char *name)
Definition: assets.cpp:284
pl::last_skill_ob
object * last_skill_ob[MAX_SKILLS]
Definition: player.h:153
shop.h
dragon_ability_gain
void dragon_ability_gain(object *who, int atnr, int level)
Definition: player.c:4263
check_stat_bounds
void check_stat_bounds(living *stats, int8_t min_stat, int8_t max_stat)
Definition: living.c:355
gravestone_text
static const char * gravestone_text(object *op, char *buf2, int len)
Definition: player.c:3212
EXIT_ALT_X
#define EXIT_ALT_X(xyz)
Definition: define.h:443
MSG_TYPE_ATTRIBUTE_GOD
#define MSG_TYPE_ATTRIBUTE_GOD
Definition: newclient.h:575
send_news
void send_news(const object *op)
Definition: player.c:203
PU_ARMOUR
#define PU_ARMOUR
Definition: define.h:123
esrv_update_item
void esrv_update_item(int flags, object *pl, object *op)
Definition: main.c:360
query_base_name
void query_base_name(const object *op, int plural, char *buf, size_t size)
Definition: item.c:686
Settings::max_stat
uint8_t max_stat
Definition: global.h:319
SPELL_EFFECT
@ SPELL_EFFECT
Definition: object.h:215
drain_msg
const char *const drain_msg[NUM_STATS]
Definition: living.c:140
PU_NEWMODE
#define PU_NEWMODE
Definition: define.h:111
rv_vector
Definition: map.h:373
MSG_TYPE_ADMIN_RULES
#define MSG_TYPE_ADMIN_RULES
Definition: newclient.h:494
SKILL_TOOL
@ SKILL_TOOL
Definition: object.h:189
pl::rejoin_party
party_rejoin_mode rejoin_party
Definition: player.h:209
options
static struct Command_Line_Options options[]
Definition: init.c:379
EXIT_Y
#define EXIT_Y(xyz)
Definition: define.h:442
diamondslots.y
y
Definition: diamondslots.py:16
oblnk::ob
object * ob
Definition: object.h:447
FLAG_BEEN_APPLIED
#define FLAG_BEEN_APPLIED
Definition: define.h:323
CLEAR_FLAG
#define CLEAR_FLAG(xyz, p)
Definition: define.h:225
allowed_class
int allowed_class(const object *op)
Definition: living.c:1652
NDI_BROWN
#define NDI_BROWN
Definition: newclient.h:253
object_find_by_type
object * object_find_by_type(const object *who, int type)
Definition: object.c:3951
buf
StringBuffer * buf
Definition: readable.c:1610
AP_NOPRINT
#define AP_NOPRINT
Definition: define.h:585
pl::hidden
uint32_t hidden
Definition: player.h:147
set_attr_value
void set_attr_value(living *stats, int attr, int8_t value)
Definition: living.c:219
change_exp
void change_exp(object *op, int64_t exp, const char *skill_name, int flag)
Definition: living.c:2168
EVENT_REMOVE
#define EVENT_REMOVE
Definition: events.h:53
pl::last_stats
living last_stats
Definition: player.h:167
object_insert_in_ob
object * object_insert_in_ob(object *op, object *where)
Definition: object.c:2833
SockList_ResetRead
void SockList_ResetRead(SockList *sl)
Definition: lowlevel.c:80
short_stat_name
const char *const short_stat_name[NUM_STATS]
Definition: living.c:195
guild_entry.x1
int x1
Definition: guild_entry.py:33
NDI_DK_ORANGE
#define NDI_DK_ORANGE
Definition: newclient.h:248
object_update_speed
void object_update_speed(object *op)
Definition: object.c:1330
obj::more
struct obj * more
Definition: object.h:298
socket_struct::faces_sent
uint8_t * faces_sent
Definition: newserver.h:96
obj::move_type
MoveType move_type
Definition: object.h:429
arch_to_object
object * arch_to_object(archetype *at)
Definition: arch.cpp:232
pl::ranges
object * ranges[range_size]
Definition: player.h:116
send_rules
void send_rules(const object *op)
Definition: player.c:167
keyrings
@ keyrings
Definition: player.h:67
castle_read.key
key
Definition: castle_read.py:64
MSG_TYPE_ADMIN_LOGIN
#define MSG_TYPE_ADMIN_LOGIN
Definition: newclient.h:500
FLAG_ANIMATE
#define FLAG_ANIMATE
Definition: define.h:242
restore_player
static void restore_player(object *op)
Definition: player.c:3425
MSG_TYPE_ATTRIBUTE_BAD_EFFECT_END
#define MSG_TYPE_ATTRIBUTE_BAD_EFFECT_END
Definition: newclient.h:567
obj::skill
sstring skill
Definition: object.h:324
treasurestruct::next
struct treasurestruct * next
Definition: treasure.h:66
newclient.h
save_player
int save_player(object *op, int flag)
Definition: login.c:230
object_insert_in_map_at
object * object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
Definition: object.c:2080
ST_GET_PARTY_PASSWORD
#define ST_GET_PARTY_PASSWORD
Definition: define.h:549
draw_ext_info
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
Definition: main.c:309
get_attr_value
int8_t get_attr_value(const living *stats, int attr)
Definition: living.c:314
object_free_drop_inventory
void object_free_drop_inventory(object *ob)
Definition: object.c:1546
object_matches_pickup_mode
int object_matches_pickup_mode(const object *item, int mode)
Definition: c_object.c:656
FOOD
@ FOOD
Definition: object.h:112
pl::ticks_played
uint32_t ticks_played
Definition: player.h:221
do_some_living
void do_some_living(object *op)
Definition: player.c:3247
add_statbonus
void add_statbonus(object *op)
Definition: living.c:869
i18n
const char * i18n(const object *who, const char *code)
Definition: languages.c:55
get_thaco_bonus
int get_thaco_bonus(int stat)
Definition: living.c:2358
first_map_ext_path
EXTERN char first_map_ext_path[MAX_BUF]
Definition: global.h:142
cure_disease
int cure_disease(object *sufferer, object *caster, sstring skill)
Definition: disease.c:685
pick_arrow_target
static object * pick_arrow_target(object *op, const char *type, int dir)
Definition: player.c:2011
DOOR
@ DOOR
Definition: object.h:126
FLAG_UNPAID
#define FLAG_UNPAID
Definition: define.h:236
FLAG_NO_STRENGTH
#define FLAG_NO_STRENGTH
Definition: define.h:306
quest.state
state
Definition: quest.py:13
fix_luck
void fix_luck(void)
Definition: player.c:3870
PU_NOTHING
#define PU_NOTHING
Definition: define.h:106
OB_TYPE_MOVE_BLOCK
#define OB_TYPE_MOVE_BLOCK(ob1, type)
Definition: define.h:432
level
int level
Definition: readable.c:1608
path_to_player
int path_to_player(object *mon, object *pl, unsigned mindiff)
Definition: player.c:643
socket_struct::login_method
uint8_t login_method
Definition: newserver.h:128
is_true_undead
int is_true_undead(object *op)
Definition: player.c:3940
MSG_TYPE_ATTACK_NOATTACK
#define MSG_TYPE_ATTACK_NOATTACK
Definition: newclient.h:618
play_again
void play_again(object *op)
Definition: player.c:895
DRINK
@ DRINK
Definition: object.h:157
PU_CURSED
#define PU_CURSED
Definition: define.h:144
ATNR_COLD
#define ATNR_COLD
Definition: attack.h:53
FLAG_XRAYS
#define FLAG_XRAYS
Definition: define.h:300
kill_player_permadeath
static void kill_player_permadeath(object *op)
Definition: player.c:3768
say.item
dictionary item
Definition: say.py:149
give_initial_items
void give_initial_items(object *pl, treasurelist *items)
Definition: player.c:776
Settings::search_items
uint8_t search_items
Definition: global.h:262
turn_one_transport
static int turn_one_transport(object *transport, object *captain, int dir)
Definition: player.c:2820
obj::anim_suffix
sstring anim_suffix
Definition: object.h:319
add_player
player * add_player(socket_struct *ns, int flags)
Definition: player.c:463
obj::move_on
MoveType move_on
Definition: object.h:432
drain_rod_charge
void drain_rod_charge(object *rod)
Definition: spell_util.c:775
range_skill
@ range_skill
Definition: player.h:35
obj::attacktype
uint32_t attacktype
Definition: object.h:347
server.h
oblnk
Definition: object.h:446
PU_DRINK
#define PU_DRINK
Definition: define.h:116
mapdef::path
char path[HUGE_BUF]
Definition: map.h:358
INTELLIGENCE
@ INTELLIGENCE
Definition: living.h:16
shop_contains
bool shop_contains(object *ob)
Definition: shop.c:1276
reputation.killer
def killer
Definition: reputation.py:13
hide
int hide(object *op, object *skill)
Definition: skills.c:494
pl::party
partylist * party
Definition: player.h:202
TRUE
#define TRUE
Definition: compat.h:11
pl::usekeys
usekeytype usekeys
Definition: player.h:120
ATNR_ELECTRICITY
#define ATNR_ELECTRICITY
Definition: attack.h:52
ST_ROLL_STAT
#define ST_ROLL_STAT
Definition: define.h:543
get_map_flags
int get_map_flags(mapstruct *oldmap, mapstruct **newmap, int16_t x, int16_t y, int16_t *nx, int16_t *ny)
Definition: map.c:301
pets_control_golem
void pets_control_golem(object *op, int dir)
Definition: pets.c:630
PU_SHIELD
#define PU_SHIELD
Definition: define.h:122
SPELL
@ SPELL
Definition: object.h:214
liv::sp
int16_t sp
Definition: living.h:42
MSG_TYPE_APPLY
#define MSG_TYPE_APPLY
Definition: newclient.h:408
player_map_change_common
void player_map_change_common(object *op, mapstruct *const oldmap, mapstruct *const newmap)
Definition: server.c:276
account_char_save
void account_char_save(Account_Chars *chars)
Definition: account_char.c:179
OUT_OF_MEMORY
@ OUT_OF_MEMORY
Definition: define.h:48
FLAG_CURSED
#define FLAG_CURSED
Definition: define.h:316
find_key
object * find_key(object *pl, object *container, object *door)
Definition: player.c:2445
pick_up
void pick_up(object *op, object *alt)
Definition: c_object.c:519
rv_vector::direction
int direction
Definition: map.h:377
altar_valkyrie.pl
pl
Definition: altar_valkyrie.py:28
living.h
obj::magic
int8_t magic
Definition: object.h:353
obj::resist
int16_t resist[NROFATTACKS]
Definition: object.h:346
send_query
void send_query(socket_struct *ns, uint8_t flags, const char *text)
Definition: request.c:679
Send_With_Handling
void Send_With_Handling(socket_struct *ns, SockList *sl)
Definition: lowlevel.c:440
if
if(!(yy_init))
Definition: loader.c:2626
get_map_from_coord
mapstruct * get_map_from_coord(mapstruct *m, int16_t *x, int16_t *y)
Definition: map.c:2385
mapdef::next
struct mapdef * next
Definition: map.h:318
object_split
object * object_split(object *orig_ob, uint32_t nr, char *err, size_t size)
Definition: object.c:2613
MSG_TYPE_ADMIN
#define MSG_TYPE_ADMIN
Definition: newclient.h:402
SockList
Definition: newclient.h:681
rv_vector::distance
unsigned int distance
Definition: map.h:374
SPELLBOOK
@ SPELLBOOK
Definition: object.h:203
NUM_STATS
@ NUM_STATS
Definition: living.h:18
MSG_TYPE_ITEM_INFO
#define MSG_TYPE_ITEM_INFO
Definition: newclient.h:645
change_attr_value
void change_attr_value(living *stats, int attr, int8_t value)
Definition: living.c:265
flee_player
static void flee_player(object *op)
Definition: player.c:1645
FOR_INV_PREPARE
#define FOR_INV_PREPARE(op_, it_)
Definition: define.h:670
MAX_FOOD
static const int32_t MAX_FOOD
Definition: define.h:461
drain_wand_charge
void drain_wand_charge(object *wand)
Definition: spell_util.c:785
FORCE
@ FORCE
Definition: object.h:224
get_rangevector_from_mapcoord
int get_rangevector_from_mapcoord(const mapstruct *m, int x, int y, const object *op2, rv_vector *retval, int flags)
Definition: map.c:2618
account_char_remove
void account_char_remove(Account_Chars *chars, const char *pl_name)
Definition: account_char.c:328
EXIT_ALT_Y
#define EXIT_ALT_Y(xyz)
Definition: define.h:444
pl::title
char title[BIG_NAME]
Definition: player.h:183
get_nearest_criminal
object * get_nearest_criminal(object *mon)
Definition: player.c:575
draw_ext_info_format
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...)
Definition: main.c:319
safe_strcat
void safe_strcat(char *dest, const char *orig, size_t *curlen, size_t maxlen)
Definition: porting.c:200
object.h
obj::level
int16_t level
Definition: object.h:356
events_execute_global_event
void events_execute_global_event(int eventcode,...)
Definition: events.cpp:29
CONSTITUTION
@ CONSTITUTION
Definition: living.h:13
llevDebug
@ llevDebug
Definition: logger.h:13
FLAG_LIFESAVE
#define FLAG_LIFESAVE
Definition: define.h:305
MONEY
@ MONEY
Definition: object.h:137
change_luck
void change_luck(object *op, int value)
Definition: living.c:797
treasureliststruct
Definition: treasure.h:82
NRSPELLPATHS
#define NRSPELLPATHS
Definition: spells.h:40
is_valid_types_gen.type
list type
Definition: is_valid_types_gen.py:25
FLAG_IS_FLOOR
#define FLAG_IS_FLOOR
Definition: define.h:302
P_BLOCKSVIEW
#define P_BLOCKSVIEW
Definition: map.h:227
FORCE_NAME
#define FORCE_NAME
Definition: spells.h:169
obj::inv
struct obj * inv
Definition: object.h:293
FLAG_IDENTIFIED
#define FLAG_IDENTIFIED
Definition: define.h:261
give.name
name
Definition: give.py:27
skill_attack
void skill_attack(object *tmp, object *pl, int dir, const char *string, object *skill)
Definition: skill_util.c:1272
fire_misc_object
static void fire_misc_object(object *op, int dir)
Definition: player.c:2321
PU_DEBUG
#define PU_DEBUG
Definition: define.h:108
dragon_attune.force
force
Definition: dragon_attune.py:45
object_get_owner
object * object_get_owner(object *op)
Definition: object.c:808
CS_QUERY_HIDEINPUT
#define CS_QUERY_HIDEINPUT
Definition: newclient.h:68
PU_SKILLSCROLL
#define PU_SKILLSCROLL
Definition: define.h:136
level
Definition: level.py:1
Settings::localdir
const char * localdir
Definition: global.h:244