Crossfire Server, Trunk
player.cpp
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 <math.h>
25 #include <stddef.h>
26 #include <stdlib.h>
27 #include <string.h>
28 
29 #ifndef WIN32 /* ---win32 remove headers */
30 #include <pwd.h>
31 #endif
32 
33 #include "server.h"
34 #include "living.h"
35 #include "object.h"
36 #include "shared/newclient.h"
37 #include "shop.h"
38 #include "skills.h"
39 #include "sounds.h"
40 #include "spells.h"
41 #include "sproto.h"
42 
44 
45 static void kill_player_not_permadeath(object *op);
46 static void kill_player_permadeath(object *op);
47 static int action_makes_visible(object *op);
48 
57 player *find_player(const char *plname) {
58  return find_player_options(plname, 0, NULL);
59 }
60 
68 player *find_player_options(const char *plname, int options, const mapstruct *map) {
69  player *pl;
70  player *found = NULL;
71  size_t namelen = strlen(plname);
72  char name[MAX_BUF];
73 
74  for (pl = first_player; pl != NULL; pl = pl->next) {
76  continue;
77 
78  if (map != NULL && pl->ob->map != map)
79  continue;
80 
82  query_name(pl->ob, name, sizeof(name));
83  if (!strcmp(name, plname))
84  return pl;
85  continue;
86  }
87 
88  if (strlen(pl->ob->name) < namelen)
89  continue;
90 
91  if (!strcmp(pl->ob->name, plname))
92  return pl;
93 
94  if (!strncasecmp(pl->ob->name, plname, namelen)) {
95  if (found)
96  return NULL;
97 
98  found = pl;
99  }
100  }
101  return found;
102 }
103 
112 player *find_player_partial_name(const char *plname) {
113  return find_player_options(plname, FIND_PLAYER_PARTIAL_NAME, NULL);
114 }
115 
122  player *pl;
123 
124  for (pl = first_player; pl != NULL; pl = pl->next) {
125  if (pl->socket == ns)
126  return pl;
127  }
128  return NULL;
129 }
130 
137 void display_motd(const object *op) {
138  char buf[MAX_BUF];
139  char motd[HUGE_BUF];
140  FILE *fp;
141  size_t size;
142 
143  snprintf(buf, sizeof(buf), "%s/%s", settings.confdir, settings.motd);
144  fp = fopen(buf, "r");
145  if (fp == NULL) {
146  return;
147  }
148  motd[0] = '\0';
149  size = 0;
150 
151  while (fgets(buf, MAX_BUF, fp) != NULL) {
152  if (*buf != '#') {
153  safe_strcat(motd, buf, &size, sizeof(motd));
154  }
155  }
156 
158  motd);
159  fclose(fp);
160 }
161 
168 void send_rules(const object *op) {
169  char buf[MAX_BUF];
170  char rules[HUGE_BUF];
171  FILE *fp;
172  size_t size;
173 
174  snprintf(buf, sizeof(buf), "%s/%s", settings.confdir, settings.rules);
175  fp = fopen(buf, "r");
176  if (fp == NULL) {
177  return;
178  }
179  rules[0] = '\0';
180  size = 0;
181 
182  while (fgets(buf, MAX_BUF, fp) != NULL) {
183  if (size+strlen(buf) >= HUGE_BUF) {
184  LOG(llevDebug, "Warning, rules size is > %d bytes.\n", HUGE_BUF);
185  break;
186  }
187 
188  if (*buf != '#') {
189  safe_strcat(rules, buf, &size, sizeof(rules));
190  }
191  }
192 
194  MSG_TYPE_ADMIN_RULES, rules);
195  fclose(fp);
196 }
197 
204 void send_news(const object *op) {
205  char buf[MAX_BUF];
206  char news[HUGE_BUF];
207  char subject[MAX_BUF];
208  FILE *fp;
209  size_t size;
210 
211  snprintf(buf, sizeof(buf), "%s/%s", settings.confdir, settings.news);
212  fp = fopen(buf, "r");
213  if (fp == NULL)
214  return;
215  news[0] = '\0';
216  subject[0] = '\0';
217  size = 0;
218  while (fgets(buf, MAX_BUF, fp) != NULL) {
219  if (*buf == '#')
220  continue;
221  if (*buf == '%') { /* send one news */
222  if (size > 0)
225  "%s:\n%s",
226  subject, news); /*send previously read news*/
227  safe_strncpy(subject, buf + 1, sizeof(subject));
228  strip_endline(subject);
229  size = 0;
230  news[0] = '\0';
231  } else {
232  if (size+strlen(buf) >= HUGE_BUF) {
233  LOG(llevDebug, "Warning, one news item has size > %d bytes.\n", HUGE_BUF);
234  break;
235  }
236  safe_strcat(news, buf, &size, sizeof(news));
237  }
238  }
239 
242  "%s:\n%s",
243  subject, news);
244  fclose(fp);
245 }
246 
255 int playername_ok(const char *cp) {
256  /* Don't allow - or _ as first character in the name */
257  if (*cp == '-' || *cp == '_')
258  return 0;
259 
260  for (; *cp != '\0'; cp++)
261  if (!isalnum(*cp)
262  && *cp != '-'
263  && *cp != '_')
264  return 0;
265  return 1;
266 }
267 
284  object *op = arch_to_object(get_player_archetype(NULL));
285  int i;
286 
287  if (!p) {
288  player *tmp;
289 
290  p = (player *)calloc(1, sizeof(player));
291  if (p == NULL)
293 
294  /* This adds the player in the linked list. There is extra
295  * complexity here because we want to add the new player at the
296  * end of the list - there is in fact no compelling reason that
297  * that needs to be done except for things like output of
298  * 'who'.
299  */
300  tmp = first_player;
301  while (tmp != NULL && tmp->next != NULL)
302  tmp = tmp->next;
303  if (tmp != NULL)
304  tmp->next = p;
305  else
306  first_player = p;
307  } else {
308  /* Only needed when reusing existing player. */
309  clear_player(p);
310  }
311 
312  /* Clears basically the entire player structure except
313  * for next and socket.
314  */
315  memset((void *)((char *)p+offsetof(player, maplevel)), 0, sizeof(player)-offsetof(player, maplevel));
316 
317  /* There are some elements we want initialized to non zero value -
318  * we deal with that below this point.
319  */
320  p->party = NULL;
323  p->swap_first = -1;
324 
325 #ifdef AUTOSAVE
326  p->last_save_tick = 9999999;
327 #endif
328 
329  strcpy(p->savebed_map, first_map_path); /* Init. respawn position */
330 
331  op->contr = p; /* this aren't yet in archetype */
332  p->ob = op;
333  op->speed_left = 0.5;
334  op->speed = 1.0;
335  op->direction = 5; /* So player faces south */
336  op->stats.wc = 2;
337  op->run_away = 25; /* Then we panic... */
338 
339  roll_stats(op);
341  clear_los(p);
342 
343  p->gen_sp_armour = 10;
344  p->last_speed = -1;
345  p->shoottype = range_none;
346  p->bowtype = bow_normal;
347  p->petmode = pet_normal;
348  p->listening = 10;
349  p->last_weapon_sp = -1;
350  p->peaceful = 1; /* default peaceful */
351  p->do_los = 1;
352  p->no_shout = 0; /* default can shout */
353  p->language = -1; // find default language
354  p->unarmed_skill = NULL;
355  p->ticks_played = 0;
356 
357  strncpy(p->title, op->arch->clone.name, sizeof(p->title)-1);
358  p->title[sizeof(p->title)-1] = '\0';
359  op->race = add_string(op->arch->clone.race);
360 
362 
363  /* we need to clear these to -1 and not zero - otherwise,
364  * if a player quits and starts a new character, we wont
365  * send new values to the client, as things like exp start
366  * at zero.
367  */
368  for (i = 0; i < MAX_SKILLS; i++) {
369  p->last_skill_exp[i] = -1;
370  p->last_skill_ob[i] = NULL;
371  }
372  for (i = 0; i < NROFATTACKS; i++) {
373  p->last_resist[i] = -1;
374  }
375  p->last_stats.exp = -1;
376  p->last_weight = (uint32_t)-1;
377  return p;
378 }
379 
386 void set_first_map(object *op) {
387  strcpy(op->contr->maplevel, first_map_path);
388  op->x = -1;
389  op->y = -1;
391 }
392 
406  if (p->socket && p->socket->account_chars) {
408  }
409 
410  p->socket = static_cast<socket_struct *>(malloc(sizeof(socket_struct)));
411  if (!p->socket) {
413  }
414  memcpy(p->socket, ns, sizeof(socket_struct));
415 
416  /* The memcpy above copies the reference to faces sent. So we need to clear
417  * that pointer in ns, otherwise we get a double free.
418  */
419  ns->faces_sent = NULL;
420  ns->host = strdup_local("");
421  ns->account_name = strdup_local("");
422  ns->account_chars = NULL; // If not NULL, the reference is now kept by p
423 
424  if (p->socket->faces_sent == NULL)
426 
427  /* Needed because the socket we just copied over needs to be cleared.
428  * Note that this can result in a client reset if there is partial data
429  * on the incoming socket.
430  */
432 
433 
434 }
435 
453  player *p;
454 
455  p = get_player(NULL);
456  set_player_socket(p, ns);
457  ns->status = Ns_Avail;
458 
460 
461  if (!(flags & ADD_PLAYER_NO_MAP))
462  set_first_map(p->ob);
463 
465 
466  /* In this case, the client is provide all the informatin for the
467  * new character, so just return it. Do not display any messages,
468  * etc
469  */
471  return p;
472 
473  if (flags & ADD_PLAYER_NEW) {
474  roll_again(p->ob);
476  } else {
477  send_rules(p->ob);
478  send_news(p->ob);
479  display_motd(p->ob);
480  get_name(p->ob);
481  }
482  return p;
483 }
484 
496  archetype *start = at;
497 
498  for (;;) {
499  at = get_next_archetype(at);
500  if (at == NULL) {
501  at = get_next_archetype(at);
502  }
503  if (at->clone.type == PLAYER)
504  return at;
505  if (at == start) {
506  LOG(llevError, "No Player archetypes\n");
507  exit(-1);
508  }
509  }
510 }
511 
520 object *get_nearest_player(object *mon) {
521  object *op = NULL;
522  player *pl = NULL;
523  objectlink *list, *ol;
524  unsigned lastdist;
525  rv_vector rv;
526 
527  list = get_friends_of(NULL);
528 
529  for (ol = list, lastdist = 1000; ol != NULL; ol = ol->next) {
530  if (QUERY_FLAG(ol->ob, FLAG_FREED) || !QUERY_FLAG(ol->ob, FLAG_FRIENDLY)) {
531  continue;
532  }
533 
534  /* Remove special check for player from this. First, it looks to cause
535  * some crashes (ol->ob->contr not set properly?), but secondly, a more
536  * complicated method of state checking would be needed in any case -
537  * as it was, a clever player could type quit, and the function would
538  * skip them over while waiting for confirmation. Remove
539  * on_same_map check, as monster_can_detect_enemy() also does this
540  */
541  if (!monster_can_detect_enemy(mon, ol->ob, &rv))
542  continue;
543 
544  if (lastdist > rv.distance) {
545  op = ol->ob;
546  lastdist = rv.distance;
547  }
548  }
549  if (list) {
551  }
552  for (pl = first_player; pl != NULL; pl = pl->next) {
553  if (monster_can_detect_enemy(mon, pl->ob, &rv)) {
554  if (lastdist > rv.distance) {
555  op = pl->ob;
556  lastdist = rv.distance;
557  }
558  }
559  }
560  return op;
561 }
562 
563 object *get_nearest_criminal(object *mon) {
564  object *op = NULL;
565  for (player *pl = first_player; pl != NULL; pl = pl->next) {
566  rv_vector rv;
567  if (monster_can_detect_enemy(mon, pl->ob, &rv) && is_criminal(pl->ob)) {
568  op = pl->ob;
569  }
570  }
571  return op;
572 }
573 
583 #define DETOUR_AMOUNT 2
584 
598 #define MAX_SPACES 50
599 
631 int path_to_player(object *mon, object *pl, unsigned mindiff) {
632  rv_vector rv;
633  int16_t x, y;
634  int lastx, lasty, dir, i, diff, firstdir = 0, lastdir, max = MAX_SPACES, mflags, blocked;
635  mapstruct *m, *lastmap;
636 
637  if (!get_rangevector(mon, pl, &rv, 0))
638  return 0;
639 
640  if (rv.distance < mindiff)
641  return 0;
642 
643  x = mon->x;
644  y = mon->y;
645  m = mon->map;
646  dir = rv.direction;
647  lastdir = firstdir = rv.direction; /* perhaps we stand next to pl, init firstdir too */
648  diff = MAX(FABS(rv.distance_x), FABS(rv.distance_y));
649  /* If we can't solve it within the search distance, return now. */
650  if (diff > max)
651  return 0;
652  while (diff > 1 && max > 0) {
653  lastx = x;
654  lasty = y;
655  lastmap = m;
656  x = lastx+freearr_x[dir];
657  y = lasty+freearr_y[dir];
658 
659  mflags = get_map_flags(m, &m, x, y, &x, &y);
660  blocked = (mflags&P_OUT_OF_MAP) ? MOVE_ALL : GET_MAP_MOVE_BLOCK(m, x, y);
661 
662  /* Space is blocked - try changing direction a little */
663  if ((mflags&P_OUT_OF_MAP)
664  || ((OB_TYPE_MOVE_BLOCK(mon, blocked) || (mflags&P_IS_ALIVE))
665  && (m == mon->map && blocked_link(mon, m, x, y)))) {
666  /* recalculate direction from last good location. Possible
667  * we were not traversing ideal location before.
668  */
669  if (get_rangevector_from_mapcoord(lastmap, lastx, lasty, pl, &rv, 0) && rv.direction != dir) {
670  /* OK - says direction should be different - lets reset the
671  * the values so it will try again.
672  */
673  x = lastx;
674  y = lasty;
675  m = lastmap;
676  dir = firstdir = rv.direction;
677  } else {
678  /* direct path is blocked - try taking a side step to
679  * either the left or right.
680  * Note increase the values in the loop below to be
681  * more than -1/1 respectively will mean the monster takes
682  * bigger detour. Have to be careful about these values getting
683  * too big (3 or maybe 4 or higher) as the monster may just try
684  * stepping back and forth
685  */
686  for (i = -DETOUR_AMOUNT; i <= DETOUR_AMOUNT; i++) {
687  if (i == 0)
688  continue; /* already did this, so skip it */
689  /* Use lastdir here - otherwise,
690  * since the direction that the creature should move in
691  * may change, you could get infinite loops.
692  * ie, player is northwest, but monster can only
693  * move west, so it does that. It goes some distance,
694  * gets blocked, finds that it should move north,
695  * can't do that, but now finds it can move east, and
696  * gets back to its original point. lastdir contains
697  * the last direction the creature has successfully
698  * moved.
699  */
700 
701  x = lastx+freearr_x[absdir(lastdir+i)];
702  y = lasty+freearr_y[absdir(lastdir+i)];
703  m = lastmap;
704  mflags = get_map_flags(m, &m, x, y, &x, &y);
705  if (mflags&P_OUT_OF_MAP)
706  continue;
707  blocked = GET_MAP_MOVE_BLOCK(m, x, y);
708  if (OB_TYPE_MOVE_BLOCK(mon, blocked))
709  continue;
710  if (mflags&P_IS_ALIVE)
711  continue;
712 
713  if (m == mon->map && blocked_link(mon, m, x, y))
714  break;
715  }
716  /* go through entire loop without finding a valid
717  * sidestep to take - thus, no valid path.
718  */
719  if (i == (DETOUR_AMOUNT+1))
720  return 0;
721  diff--;
722  lastdir = dir;
723  max--;
724  if (!firstdir)
725  firstdir = dir+i;
726  } /* else check alternate directions */
727  } /* if blocked */
728  else {
729  /* we moved towards creature, so diff is less */
730  diff--;
731  max--;
732  lastdir = dir;
733  if (!firstdir)
734  firstdir = dir;
735  }
736  if (diff <= 1) {
737  /* Recalculate diff (distance) because we may not have actually
738  * headed toward player for entire distance.
739  */
740  if (!get_rangevector_from_mapcoord(m, x, y, pl, &rv, 0))
741  return 0;
742  diff = MAX(FABS(rv.distance_x), FABS(rv.distance_y));
743  }
744  if (diff > max)
745  return 0;
746  }
747  /* If we reached the max, didn't find a direction in time */
748  if (!max)
749  return 0;
750 
751  return firstdir;
752 }
753 
764 void give_initial_items(object *pl, treasurelist *items) {
765  if (pl->randomitems != NULL)
767 
768  FOR_INV_PREPARE(pl, op) {
769  /* Forces get applied per default, unless they have the
770  * flag "neutral" set. Sorry but I can't think of a better way
771  */
772  if (op->type == FORCE && !QUERY_FLAG(op, FLAG_NEUTRAL))
774 
775  /* we never give weapons/armour if these cannot be used
776  * by this player due to race restrictions
777  */
778  if (pl->type == PLAYER) {
781  || (!QUERY_FLAG(pl, FLAG_USE_SHIELD) && IS_SHIELD(op))) {
782  object_remove(op);
784  continue;
785  }
786  }
787 
788  /* This really needs to be better - we should really give
789  * a substitute spellbook. The problem is that we don't really
790  * have a good idea what to replace it with (need something like
791  * a first level treasurelist for each skill.)
792  * remove duplicate skills also
793  */
794  if (op->type == SPELLBOOK || op->type == SKILL) {
795  int found;
796 
797  found = 0;
798  // Make sure we set flags that are checked by object_can_merge
799  // *before* we run object_can_merge. Otherwise, we can get two
800  // entries of the same skill.
801  if (op->type == SKILL) {
803  op->stats.exp = 0;
804  op->level = 1;
805  // Since this also happens to the invisible skills, we need this so that the flags match.
807  }
809  if (object_can_merge(op, tmp)) {
810  found = 1;
811  break;
812  }
814  if (found) {
815  LOG(llevError, "give_initial_items: Removing duplicate object %s\n", op->name);
816  object_remove(op);
818  continue;
819  }
820  if (op->nrof > 1)
821  op->nrof = 1;
822  }
823 
824  if (op->type == SPELLBOOK && op->inv) {
826  }
827 
828  /* Give starting characters identified, uncursed, and undamned
829  * items. Just don't identify gold or silver, or it won't be
830  * merged properly.
831  */
832  if (is_identifiable_type(op)) {
836  }
837  /* lock all 'normal items by default */
838  else
840  } FOR_INV_FINISH(); /* for loop of objects in player inv */
841 
842  /* Need to set up the skill pointers */
844 
852  FOR_INV_FINISH();
853 }
854 
861 void get_name(object *op) {
863  send_query(op->contr->socket, 0, i18n(op, "What is your name?\n:"));
864 }
865 
872 void get_password(object *op) {
874  send_query(op->contr->socket, CS_QUERY_HIDEINPUT, i18n(op, "What is your password?\n:"));
875 }
876 
883 void play_again(object *op) {
884  SockList sl;
885 
886  op->contr->socket->status = Ns_Add;
888  op->chosen_skill = NULL;
889 
890  /*
891  * For old clients, ask if they want to play again.
892  * For clients with account support, just return to character seletion (see below).
893  */
894  if (op->contr->socket->login_method == 0) {
895  send_query(op->contr->socket, CS_QUERY_SINGLECHAR, i18n(op, "Do you want to play again (a/q)?"));
896  }
897  /* a bit of a hack, but there are various places early in th
898  * player creation process that a user can quit (eg, roll
899  * stats) that isn't removing the player. Taking a quick
900  * look, there are many places that call play_again without
901  * removing the player - it probably makes more sense
902  * to leave it to play_again to remove the object in all
903  * cases.
904  */
905  if (!QUERY_FLAG(op, FLAG_REMOVED))
906  object_remove(op);
907  /* Need to set this to null - otherwise, it could point to garbage,
908  * and draw() doesn't check to see if the player is removed, only if
909  * the map is null or not swapped out.
910  */
911  op->map = NULL;
912 
913  SockList_Init(&sl);
914  SockList_AddString(&sl, "player ");
915  SockList_AddInt(&sl, 0);
916  SockList_AddInt(&sl, 0);
917  SockList_AddInt(&sl, 0);
918  SockList_AddChar(&sl, 0);
919 
920  Send_With_Handling(op->contr->socket, &sl);
921  SockList_Term(&sl);
922 
923  if (op->contr->socket->login_method > 0) {
924  receive_play_again(op, 'a');
925  }
926 }
927 
936 void receive_play_again(object *op, char key) {
937  if (key == 'q' || key == 'Q') {
939  leave(op->contr, 0); /* ericserver will draw the message */
940  return;
941  } else if (key == 'a' || key == 'A') {
942  player *pl = op->contr;
943  const char *name = op->name;
944 
948  pl = get_player(pl);
949  op = pl->ob;
951  op->contr->password[0] = '~';
952  FREE_AND_CLEAR_STR(op->name);
953  FREE_AND_CLEAR_STR(op->name_pl);
954  if (pl->socket->login_method >= 1 && pl->socket->account_name != NULL) {
955  /* If we are using new login, we send the
956  * list of characters to the client - this should
957  * result in the client popping up this list so
958  * the player can choose which one to play - better
959  * than going to legacy login code.
960  * If the account_name is NULL, it means the client
961  * says it uses account but started playing without logging in.
962  */
965  } else {
966  /* Lets put a space in here */
968  "\n");
969  get_name(op);
970  set_first_map(op);
971  }
972  op->name = name; /* Already added a refcount above */
973  op->name_pl = add_string(name);
974  } else {
975  /* user pressed something else so just ask again... */
976  play_again(op);
977  }
978 }
979 
986 void confirm_password(object *op) {
988  send_query(op->contr->socket, CS_QUERY_HIDEINPUT, i18n(op, "Please type your password again.\n:"));
989 }
990 
1001 int get_party_password(object *op, partylist *party) {
1002  if (*party_get_password(party) == '\0') {
1003  return 0;
1004  }
1005 
1007  op->contr->party_to_join = party;
1008  send_query(op->contr->socket, CS_QUERY_HIDEINPUT, i18n(op, "What is the password?\n:"));
1009  return 1;
1010 }
1011 
1018 int roll_stat(void) {
1019  int roll[4], i, low_index, k;
1020 
1021  for (i = 0; i < 4; ++i)
1022  roll[i] = (int)RANDOM()%6+1;
1023 
1024  for (i = 0, low_index = 0, k = 7; i < 4; ++i)
1025  if (roll[i] < k)
1026  k = roll[i],
1027  low_index = i;
1028 
1029  for (i = 0, k = 0; i < 4; ++i) {
1030  if (i != low_index)
1031  k += roll[i];
1032  }
1033  return k;
1034 }
1035 
1042 void roll_stats(object *op) {
1043  int i = 0, j = 0;
1044  int statsort[7];
1045 
1046  op->stats.Str = roll_stat();
1047  op->stats.Dex = roll_stat();
1048  op->stats.Int = roll_stat();
1049  op->stats.Con = roll_stat();
1050  op->stats.Wis = roll_stat();
1051  op->stats.Pow = roll_stat();
1052  op->stats.Cha = roll_stat();
1053  int sum = op->stats.Str+op->stats.Dex+op->stats.Int+op->stats.Con+op->stats.Wis+op->stats.Pow+op->stats.Cha;
1054  float scale = settings.roll_stat_points / sum;
1055  op->stats.Str = roundf(scale * op->stats.Str);
1056  op->stats.Dex = roundf(scale * op->stats.Dex);
1057  op->stats.Int = roundf(scale * op->stats.Int);
1058  op->stats.Con = roundf(scale * op->stats.Con);
1059  op->stats.Wis = roundf(scale * op->stats.Wis);
1060  op->stats.Pow = roundf(scale * op->stats.Pow);
1061  op->stats.Cha = roundf(scale * op->stats.Cha);
1062 
1063  /* Sort the stats so that rerolling is easier... */
1064  statsort[0] = op->stats.Str;
1065  statsort[1] = op->stats.Dex;
1066  statsort[2] = op->stats.Int;
1067  statsort[3] = op->stats.Con;
1068  statsort[4] = op->stats.Wis;
1069  statsort[5] = op->stats.Pow;
1070  statsort[6] = op->stats.Cha;
1071 
1072  /* a quick and dirty bubblesort? */
1073  do {
1074  if (statsort[i] < statsort[i+1]) {
1075  j = statsort[i];
1076  statsort[i] = statsort[i+1];
1077  statsort[i+1] = j;
1078  i = 0;
1079  } else {
1080  i++;
1081  }
1082  } while (i < 6);
1083 
1084  op->stats.Str = statsort[0];
1085  op->stats.Dex = statsort[1];
1086  op->stats.Con = statsort[2];
1087  op->stats.Int = statsort[3];
1088  op->stats.Wis = statsort[4];
1089  op->stats.Pow = statsort[5];
1090  op->stats.Cha = statsort[6];
1091 
1092  op->contr->orig_stats.Str = op->stats.Str;
1093  op->contr->orig_stats.Dex = op->stats.Dex;
1094  op->contr->orig_stats.Int = op->stats.Int;
1095  op->contr->orig_stats.Con = op->stats.Con;
1096  op->contr->orig_stats.Wis = op->stats.Wis;
1097  op->contr->orig_stats.Pow = op->stats.Pow;
1098  op->contr->orig_stats.Cha = op->stats.Cha;
1099 
1100  op->level = 1;
1101  op->stats.exp = 0;
1102  op->stats.ac = 0;
1103 
1104  op->contr->levhp[1] = 9;
1105  op->contr->levsp[1] = 6;
1106  op->contr->levgrace[1] = 3;
1107 
1108  fix_object(op);
1109  op->stats.hp = op->stats.maxhp;
1110  op->stats.sp = op->stats.maxsp;
1111  op->stats.grace = op->stats.maxgrace;
1112  op->contr->orig_stats = op->stats;
1113 }
1114 
1121 void roll_again(object *op) {
1122  esrv_new_player(op->contr, 0);
1123  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)? "));
1124 }
1125 
1135 static void swap_stat(object *op, int swap_second) {
1136  signed char tmp;
1137 
1138  if (op->contr->swap_first == -1) {
1139  LOG(llevError, "player.c:swap_stat() - swap_first is -1\n");
1140  return;
1141  }
1142 
1143  tmp = get_attr_value(&op->contr->orig_stats, op->contr->swap_first);
1144 
1145  set_attr_value(&op->contr->orig_stats, op->contr->swap_first, get_attr_value(&op->contr->orig_stats, swap_second));
1146 
1147  set_attr_value(&op->contr->orig_stats, swap_second, tmp);
1148 
1150  "%s done\n",
1151  short_stat_name[swap_second]);
1152 
1153  op->stats.Str = op->contr->orig_stats.Str;
1154  op->stats.Dex = op->contr->orig_stats.Dex;
1155  op->stats.Con = op->contr->orig_stats.Con;
1156  op->stats.Int = op->contr->orig_stats.Int;
1157  op->stats.Wis = op->contr->orig_stats.Wis;
1158  op->stats.Pow = op->contr->orig_stats.Pow;
1159  op->stats.Cha = op->contr->orig_stats.Cha;
1160  op->stats.ac = 0;
1161 
1162  op->level = 1;
1163  op->stats.exp = 0;
1164  op->stats.ac = 0;
1165 
1166  op->contr->levhp[1] = 9;
1167  op->contr->levsp[1] = 6;
1168  op->contr->levgrace[1] = 3;
1169 
1170  fix_object(op);
1171  op->stats.hp = op->stats.maxhp;
1172  op->stats.sp = op->stats.maxsp;
1173  op->stats.grace = op->stats.maxgrace;
1174  op->contr->orig_stats = op->stats;
1175  op->contr->swap_first = -1;
1176 }
1177 
1193 void key_roll_stat(object *op, char key) {
1194  int keynum = key-'0';
1195  static const int8_t stat_trans[] = {
1196  -1,
1197  STRENGTH,
1198  DEXTERITY,
1199  CONSTITUTION,
1200  INTELLIGENCE,
1201  WISDOM,
1202  POWER,
1203  CHARISMA,
1204  };
1205 
1206  if (keynum > 0 && keynum <= 7) {
1207  if (op->contr->swap_first == -1) {
1208  op->contr->swap_first = stat_trans[keynum];
1210  "%s ->",
1211  short_stat_name[stat_trans[keynum]]);
1212  } else
1213  swap_stat(op, stat_trans[keynum]);
1214 
1215  send_query(op->contr->socket, CS_QUERY_SINGLECHAR, "");
1216  return;
1217  }
1218  switch (key) {
1219  case 'n':
1220  case 'N': {
1221  SET_FLAG(op, FLAG_WIZ);
1222  if (op->map == NULL) {
1223  LOG(llevError, "Map == NULL in state 2\n");
1224  break;
1225  }
1226 
1227  SET_ANIMATION(op, 2); /* So player faces south */
1228  /* Enter exit adds a player otherwise */
1229  add_statbonus(op);
1230  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"));
1232  if (op->msg)
1235  op->msg);
1236  return;
1237  }
1238  case 'y':
1239  case 'Y':
1240  roll_stats(op);
1241  send_query(op->contr->socket, CS_QUERY_SINGLECHAR, "");
1242  return;
1243 
1244  case 'q':
1245  case 'Q':
1246  play_again(op);
1247  return;
1248 
1249  default:
1250  send_query(op->contr->socket, CS_QUERY_SINGLECHAR, i18n(op, "Yes, No, Quit or 1-6. Roll again?"));
1251  return;
1252  }
1253  return;
1254 }
1255 
1269 void key_change_class(object *op, char key) {
1270  int tmp_loop;
1271 
1272  if (key == 'q' || key == 'Q') {
1273  object_remove(op);
1274  play_again(op);
1275  return;
1276  }
1277  if (key == 'd' || key == 'D') {
1278  char buf[MAX_BUF];
1279 
1280  /* this must before then initial items are given */
1281  esrv_new_player(op->contr, op->weight+op->carrying);
1282  create_treasure(find_treasurelist("starting_wealth"), op, 0, 0, 0);
1283 
1284  /* Here we handle the BORN global event */
1286 
1287  /* We then generate a LOGIN event */
1288  events_execute_global_event(EVENT_LOGIN, op->contr, op->contr->socket->host);
1289  player_set_state(op->contr, ST_PLAYING);
1290 
1291  object_set_msg(op, NULL);
1292 
1293  /* We create this now because some of the unique maps will need it
1294  * to save here.
1295  */
1296  snprintf(buf, sizeof(buf), "%s/%s/%s", settings.localdir, settings.playerdir, op->name);
1298 
1299 #ifdef AUTOSAVE
1300  op->contr->last_save_tick = pticks;
1301 #endif
1304  "Welcome to Crossfire!\n Press `?' for help\n");
1305 
1308  "%s entered the game.", op->name);
1309 
1311  give_initial_items(op, op->randomitems);
1314  fix_object(op);
1315 
1316  /* This moves the player to a different start map, if there
1317  * is one for this race
1318  */
1319  if (*first_map_ext_path) {
1320  object *tmp;
1321  char mapname[MAX_BUF];
1322  mapstruct *oldmap;
1323 
1324  oldmap = op->map;
1325 
1326  snprintf(mapname, MAX_BUF-1, "%s/%s", first_map_ext_path, op->arch->name);
1327  /*printf("%s\n", mapname);*/
1328  tmp = object_new();
1330  EXIT_X(tmp) = op->x;
1331  EXIT_Y(tmp) = op->y;
1332  enter_exit(op, tmp);
1333 
1334  if (oldmap != op->map) {
1335  /* map exists, update bed of reality location, in case player dies */
1336  op->contr->bed_x = op->x;
1337  op->contr->bed_y = op->y;
1338  strlcpy(op->contr->savebed_map, mapname, sizeof(op->contr->savebed_map));
1339  }
1340 
1342  } else {
1343  LOG(llevDebug, "first_map_ext_path not set\n");
1344  }
1345  return;
1346  }
1347 
1348  /* Following actually changes the race - this is the default command
1349  * if we don't match with one of the options above.
1350  */
1351 
1352  tmp_loop = 0;
1353  while (!tmp_loop) {
1354  const char *name = add_string(op->name);
1355  int x = op->x, y = op->y;
1356 
1358  object_remove(op);
1359  /* get_player_archetype() is really misnamed - it will
1360  * get the next archetype from the list.
1361  */
1362  op->arch = get_player_archetype(op->arch);
1363  object_copy(&op->arch->clone, op);
1364  op->stats = op->contr->orig_stats;
1365  free_string(op->name);
1366  op->name = name;
1367  free_string(op->name_pl);
1368  op->name_pl = add_string(name);
1369  SET_ANIMATION(op, 2); /* So player faces south */
1370  object_insert_in_map_at(op, op->map, op, 0, x, y);
1371  strncpy(op->contr->title, op->arch->clone.name, sizeof(op->contr->title)-1);
1372  op->contr->title[sizeof(op->contr->title)-1] = '\0';
1373  add_statbonus(op);
1374  tmp_loop = allowed_class(op);
1375  }
1378  fix_object(op);
1379  op->stats.hp = op->stats.maxhp;
1380  op->stats.sp = op->stats.maxsp;
1381  op->stats.grace = 0;
1382  if (op->msg)
1384  op->msg);
1385  send_query(op->contr->socket, CS_QUERY_SINGLECHAR, i18n(op, "Press any key for the next race.\nPress `d' to play this race.\n"));
1386 }
1387 
1409 int check_race_and_class(living *stats, archetype *race, archetype *opclass)
1410 {
1411  int i, stat, failure=0;
1412 
1413  for (i = 0; i < NUM_STATS; i++) {
1414  stat = get_attr_value(stats, i);
1415  if (race)
1416  stat += get_attr_value(&race->clone.stats, i);
1417 
1418  if (opclass)
1419  stat += get_attr_value(&opclass->clone.stats, i);
1420 
1421  set_attr_value(stats, i, stat);
1422 
1423  /* We process all stats, regardless if there is a failure
1424  * or not.
1425  */
1426  if (stat < MIN_STAT) failure=1;
1427 
1428  /* Maybe this should be an error? Player is losing
1429  * some stats points here, but it is legal.
1430  */
1431  if (stat > settings.max_stat) stat = settings.max_stat;
1432  }
1433  return failure;
1434 
1435 }
1436 
1459 int apply_race_and_class(object *op, archetype *race, archetype *opclass, living *stats)
1460 {
1461  const char *name = add_string(op->name);
1462  char buf[MAX_BUF];
1463  object *inv;
1464 
1465  /* Free any objects in character inventory - they
1466  * shouldn't have any, but there is the potential that
1467  * we give them objects below and then get a creation
1468  * failure (stat out of range), in which case
1469  * those objects would be in the inventory.
1470  */
1471  while (op->inv) {
1472  inv = op->inv;
1473  object_remove(inv);
1474  object_free(inv, 0);
1475  }
1476 
1477  object_copy(&race->clone, op);
1478  free_string(op->name);
1479  op->name = name;
1480  free_string(op->name_pl);
1481  op->name_pl = add_string(name);
1482  SET_ANIMATION(op, 2); /* So player faces south */
1483  strlcpy(op->contr->title, op->arch->clone.name, sizeof(op->contr->title));
1484 
1485  if (stats) {
1486  /* Copy over the stats. Use this instead a memcpy because
1487  * we only want to copy over a few specific stats, and
1488  * leave things like maxhp, maxsp, etc, unchanged.
1489  */
1490  int i, stat;
1491  for (i = 0; i < NUM_STATS; i++) {
1492  stat = get_attr_value(stats, i);
1493  set_attr_value(&op->stats, i, stat);
1494  set_attr_value(&op->contr->orig_stats, i, stat);
1495  }
1496  } else {
1497  /* Note that this will repeated increase the stat values
1498  * if the caller does not reset them. Only do this
1499  * if stats is not provided - if stats is provided, those
1500  * are already adjusted.
1501  */
1502  add_statbonus(op);
1503 
1504  /* Checks that all stats are greater than 1. Once again,
1505  * only do this if stats are not provided
1506  */
1507  if (!allowed_class(op)) return 1;
1508  }
1509 
1511  op->stats.hp = op->stats.maxhp;
1512  op->stats.sp = op->stats.maxsp;
1513  op->stats.grace = 0;
1514 
1515  /* this must before then initial items are given */
1516  esrv_new_player(op->contr, op->weight+op->carrying);
1517  create_treasure(find_treasurelist("starting_wealth"), op, 0, 0, 0);
1518 
1519  /* This has to be done before class, otherwise the NOCLASSFACECHANGE
1520  * object is not in the inventory, and racial face will get overwritten.
1521  */
1522  give_initial_items(op, op->randomitems);
1523 
1524  if (stats) {
1525  /* Apply class information */
1527  } else {
1528  apply_changes_to_player(op, &opclass->clone, 0);
1529 
1530  /* Checks that all stats are greater than 1 */
1531  if (!allowed_class(op)) return 2;
1532  }
1533 
1534  /* Here we handle the BORN global event */
1536 
1537  /* We then generate a LOGIN event */
1538  events_execute_global_event(EVENT_LOGIN, op->contr, op->contr->socket->host);
1539 
1540  object_set_msg(op, NULL);
1541 
1542  /* We create this now because some of the unique maps will need it
1543  * to save here.
1544  */
1545  snprintf(buf, sizeof(buf), "%s/%s/%s", settings.localdir, settings.playerdir, op->name);
1547 
1548 #ifdef AUTOSAVE
1549  op->contr->last_save_tick = pticks;
1550 #endif
1551 
1554  fix_object(op);
1555 
1558  esrv_add_spells(op->contr, NULL);
1559 
1560  return 0;
1561 
1562 }
1563 
1572 void key_confirm_quit(object *op, char key) {
1573  char buf[MAX_BUF];
1574  mapstruct *mp, *next;
1575 
1576  // this was tested when 'quit' command was issued, but better safe than sorry.
1577  if (QUERY_FLAG(op, FLAG_WIZ)) {
1578  player_set_state(op->contr, ST_PLAYING);
1579  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_LOGIN, "Can't quit when in DM mode.");
1580  return;
1581  }
1582 
1583  if (key != 'y' && key != 'Y' && key != 'q' && key != 'Q') {
1584  player_set_state(op->contr, ST_PLAYING);
1586  "OK, continuing to play.");
1587  return;
1588  }
1589 
1592  object_remove(op);
1593  op->direction = 0;
1595  "%s quits the game.",
1596  op->name);
1597 
1598  strcpy(op->contr->killer, "quit");
1599  hiscore_check(op, 0);
1600  party_leave(op);
1601  if (settings.set_title == TRUE)
1602  player_set_own_title(op->contr, "");
1603 
1604 
1605  /* We need to hunt for any per player unique maps in memory and
1606  * get rid of them. The trailing slash in the path is intentional,
1607  * so that players named 'Ab' won't match against players 'Abe' pathname
1608  */
1609  snprintf(buf, sizeof(buf), "%s/%s/%s/", settings.localdir, settings.playerdir, op->name);
1610  for (mp = first_map; mp != NULL; mp = next) {
1611  next = mp->next;
1612  if (!strncmp(mp->path, buf, strlen(buf)))
1613  delete_map(mp);
1614  }
1615 
1616  delete_character(op->name);
1617 
1618  /* Remove player from account list and send back data if needed */
1619  if (op->contr->socket->account_chars != NULL) {
1620  account_char_remove(op->contr->socket->account_chars, op->name);
1621  account_char_save(op->contr->socket->account_chars);
1622  /* char information is reloaded in send_account_players below */
1623  account_char_free(op->contr->socket->account_chars);
1624  op->contr->socket->account_chars = NULL;
1625  account_remove_player(op->contr->socket->account_name, op->name);
1626  send_account_players(op->contr->socket);
1627  }
1628 
1629  play_again(op);
1630 }
1631 
1638 static void flee_player(object *op) {
1639  int dir, diff;
1640  rv_vector rv;
1641 
1642  if (op->stats.hp < 0) {
1643  LOG(llevDebug, "Fleeing player is dead.\n");
1645  return;
1646  }
1647 
1648  if (op->enemy == NULL) {
1649  LOG(llevDebug, "Fleeing player had no enemy.\n");
1651  return;
1652  }
1653 
1654  /* Seen some crashes here. Since we don't store an
1655  * op->enemy_count, it is possible that something destroys the
1656  * actual enemy, and the object is recycled.
1657  */
1658  if (op->enemy->map == NULL) {
1660  object_set_enemy(op, NULL);
1661  return;
1662  }
1663 
1664  if (!(random_roll(0, 4, op, PREFER_LOW)) && did_make_save(op, op->level, 0)) {
1665  object_set_enemy(op, NULL);
1667  return;
1668  }
1669  if (!get_rangevector(op, op->enemy, &rv, 0)) {
1670  object_set_enemy(op, NULL);
1672  return;
1673  }
1674 
1675  dir = absdir(4+rv.direction);
1676  for (diff = 0; diff < 3; diff++) {
1677  int m = 1-(RANDOM()&2);
1678  if (move_ob(op, absdir(dir+diff*m), op)
1679  || (diff == 0 && move_ob(op, absdir(dir-diff*m), op))) {
1680  return;
1681  }
1682  }
1683  /* Cornered, get rid of scared */
1685  object_set_enemy(op, NULL);
1686 }
1687 
1697 int check_pick(object *op) {
1698  tag_t op_tag;
1699  int stop = 0;
1700  int j, k, wvratio, current_ratio;
1701  char putstring[128], tmpstr[16];
1702 
1703  /* if you're flying, you can't pick up anything */
1704  if (op->move_type&MOVE_FLYING)
1705  return 1;
1706  /* If not a player, don't check anything. */
1707  if (!op->contr) {
1708  return 1;
1709  }
1710 
1711  op_tag = op->count;
1712 
1714  if (object_was_destroyed(op, op_tag))
1715  return 0;
1716 
1717  if (!object_can_pick(op, tmp))
1718  continue;
1719 
1720  if (op->contr->search_str[0] != '\0' && settings.search_items == TRUE) {
1721  if (object_matches_string(op, tmp, op->contr->search_str))
1722  pick_up(op, tmp);
1723  continue;
1724  }
1725 
1726  /* high not bit set? We're using the old autopickup model */
1727  if (!(op->contr->mode&PU_NEWMODE)) {
1728  switch (op->contr->mode) {
1729  case 0:
1730  return 1; /* don't pick up */
1731 
1732  case 1:
1733  pick_up(op, tmp);
1734  return 1;
1735 
1736  case 2:
1737  pick_up(op, tmp);
1738  return 0;
1739 
1740  case 3:
1741  return 0; /* stop before pickup */
1742 
1743  case 4:
1744  pick_up(op, tmp);
1745  break;
1746 
1747  case 5:
1748  pick_up(op, tmp);
1749  stop = 1;
1750  break;
1751 
1752  case 6:
1755  pick_up(op, tmp);
1756  break;
1757 
1758  case 7:
1759  if (tmp->type == MONEY || tmp->type == GEM)
1760  pick_up(op, tmp);
1761  break;
1762 
1763  default:
1764  /* use value density */
1765  if (!QUERY_FLAG(tmp, FLAG_UNPAID)
1766  && (price_base(tmp)*100/(tmp->weight*MAX(tmp->nrof, 1))) >= op->contr->mode)
1767  pick_up(op, tmp);
1768  }
1769  } else { /* old model */
1770  /* NEW pickup handling */
1771  if (op->contr->mode&PU_DEBUG) {
1772  /* some debugging code to figure out item information */
1774  "item name: %s item type: %d weight/value: %d",
1775  tmp->name ? tmp->name : tmp->arch->name, tmp->type,
1776  (int)(price_base(tmp)*100/(tmp->weight*MAX(tmp->nrof, 1))));
1777 
1778 
1779  snprintf(putstring, sizeof(putstring), "...flags: ");
1780  for (k = 0; k < 4; k++) {
1781  for (j = 0; j < 32; j++) {
1782  if ((tmp->flags[k]>>j)&0x01) {
1783  snprintf(tmpstr, sizeof(tmpstr), "%d ", k*32+j);
1784  strcat(putstring, tmpstr);
1785  }
1786  }
1787  }
1789  putstring);
1790  }
1791  /* philosophy:
1792  * It's easy to grab an item type from a pile, as long as it's
1793  * generic. This takes no game-time. For more detailed pickups
1794  * and selections, select-items should be used. This is a
1795  * grab-as-you-run type mode that's really useful for arrows for
1796  * example.
1797  * The drawback: right now it has no frontend, so you need to
1798  * stick the bits you want into a calculator in hex mode and then
1799  * convert to decimal and then 'pickup <#>
1800  */
1801 
1802  /* the first two modes are exclusive: if NOTHING we return, if
1803  * STOP then we stop. All the rest are applied sequentially,
1804  * meaning if any test passes, the item gets picked up. */
1805 
1806  /* if mode is set to pick nothing up, return */
1807 
1808  if (op->contr->mode == PU_NOTHING)
1809  return 1;
1810 
1811  /* if mode is set to stop when encountering objects, return.
1812  * Take STOP before INHIBIT since it doesn't actually pick
1813  * anything up */
1814 
1815  if (op->contr->mode&PU_STOP)
1816  return 0;
1817 
1818  /* useful for going into stores and not losing your settings... */
1819  /* and for battles where you don't want to get loaded down while
1820  * fighting */
1821  if (op->contr->mode&PU_INHIBIT)
1822  return 1;
1823 
1824  /* prevent us from turning into auto-thieves :) */
1825  if (QUERY_FLAG(tmp, FLAG_UNPAID))
1826  continue;
1827 
1828  /* ignore known cursed objects */
1829  if (QUERY_FLAG(tmp, FLAG_KNOWN_CURSED) && op->contr->mode&PU_NOT_CURSED)
1830  continue;
1831 
1832  static int checks[] = {
1833  PU_FOOD,
1834  PU_DRINK,
1835  PU_FLESH,
1836  PU_POTION,
1837  PU_SPELLBOOK,
1839  PU_READABLES,
1841  PU_MAGICAL,
1842  PU_VALUABLES,
1843  PU_JEWELS,
1844  PU_BOW,
1845  PU_ARROW,
1846  PU_ARMOUR,
1847  PU_HELMET,
1848  PU_SHIELD,
1849  PU_BOOTS,
1850  PU_GLOVES,
1851  PU_CLOAK,
1854  PU_KEY,
1855  PU_CONTAINER,
1856  PU_CURSED,
1857  0
1858  };
1859  int found = 0;
1860  for (int m = 0; checks[m] != 0; m++) {
1861  if (op->contr->mode & checks[m] && object_matches_pickup_mode(tmp, checks[m])) {
1862  pick_up(op, tmp);
1863  found = 1;
1864  break;
1865  }
1866  }
1867  if (found) {
1868  continue;
1869  }
1870 
1871  /* any of the last 4 bits set means we use the ratio for value
1872  * pickups */
1873  if (op->contr->mode&PU_RATIO) {
1874  /* use value density to decide what else to grab.
1875  * >=7 was >= op->contr->mode
1876  * >=7 is the old standard setting. Now we take the last 4 bits
1877  * and multiply them by 5, giving 0..15*5== 5..75 */
1878  wvratio = (op->contr->mode&PU_RATIO)*5;
1879  current_ratio = price_base(tmp)*100/(tmp->weight*MAX(tmp->nrof, 1));
1880  if (current_ratio >= wvratio) {
1881  pick_up(op, tmp);
1882  continue;
1883  }
1884  }
1885  } /* the new pickup model */
1886  } FOR_BELOW_FINISH();
1887  return !stop;
1888 }
1889 
1902 static object *find_arrow(object *op, const char *type) {
1903  object *tmp = NULL;
1904 
1906  if (!tmp
1907  && inv->type == CONTAINER
1908  && inv->race == type
1910  tmp = find_arrow(inv, type);
1911  else if (inv->type == ARROW && inv->race == type)
1912  return inv;
1913  FOR_INV_FINISH();
1914  return tmp;
1915 }
1916 
1934 static object *find_better_arrow(object *op, object *target, const char *type, int *better) {
1935  object *tmp = NULL, *ntmp;
1936  int attacknum, attacktype, betterby = 0, i;
1937 
1938  if (!type)
1939  return NULL;
1940 
1941  FOR_INV_PREPARE(op, arrow) {
1942  if (arrow->type == CONTAINER
1943  && arrow->race == type
1944  && QUERY_FLAG(arrow, FLAG_APPLIED)) {
1945  i = 0;
1946  ntmp = find_better_arrow(arrow, target, type, &i);
1947  if (i > betterby) {
1948  tmp = ntmp;
1949  betterby = i;
1950  }
1951  } else if (arrow->type == ARROW && arrow->race == type) {
1952  /* always prefer assassination/slaying */
1953  if (target->race != NULL
1954  && arrow->slaying != NULL
1955  && strstr(arrow->slaying, target->race)) {
1956  if (arrow->attacktype&AT_DEATH) {
1957  if (better)
1958  *better = 100;
1959  return arrow;
1960  } else {
1961  tmp = arrow;
1962  betterby = (arrow->magic+arrow->stats.dam)*2;
1963  }
1964  } else {
1965  for (attacknum = 0; attacknum < NROFATTACKS; attacknum++) {
1966  attacktype = 1<<attacknum;
1967  if ((arrow->attacktype&attacktype) && (target->arch->clone.resist[attacknum]) < 0)
1968  if (((arrow->magic+arrow->stats.dam)*(100-target->arch->clone.resist[attacknum])/100) > betterby) {
1969  tmp = arrow;
1970  betterby = (arrow->magic+arrow->stats.dam)*(100-target->arch->clone.resist[attacknum])/100;
1971  }
1972  }
1973  if ((2+arrow->magic+arrow->stats.dam) > betterby) {
1974  tmp = arrow;
1975  betterby = 2+arrow->magic+arrow->stats.dam;
1976  }
1977  if (arrow->title && (1+arrow->magic+arrow->stats.dam) > betterby) {
1978  tmp = arrow;
1979  betterby = 1+arrow->magic+arrow->stats.dam;
1980  }
1981  }
1982  }
1983  } FOR_INV_FINISH();
1984  if (tmp == NULL)
1985  return find_arrow(op, type);
1986 
1987  if (better)
1988  *better = betterby;
1989  return tmp;
1990 }
1991 
2004 static object *pick_arrow_target(object *op, const char *type, int dir) {
2005  object *tmp = NULL;
2006  mapstruct *m;
2007  int i, mflags, found, number;
2008  int16_t x, y;
2009 
2010  if (op->map == NULL)
2011  return find_arrow(op, type);
2012 
2013  /* do a dex check */
2014  number = (die_roll(2, 40, op, PREFER_LOW)-2)/2;
2015  if (number > (op->stats.Dex+(op->chosen_skill ? op->chosen_skill->level : op->level)))
2016  return find_arrow(op, type);
2017 
2018  m = op->map;
2019  x = op->x;
2020  y = op->y;
2021 
2022  /* find the first target */
2023  for (i = 0, found = 0; i < 20; i++) {
2024  x += freearr_x[dir];
2025  y += freearr_y[dir];
2026  mflags = get_map_flags(m, &m, x, y, &x, &y);
2027  if (mflags&P_OUT_OF_MAP || mflags&P_BLOCKSVIEW) {
2028  tmp = NULL;
2029  break;
2030  } else if (GET_MAP_MOVE_BLOCK(m, x, y) == MOVE_FLY_LOW) {
2031  /* This block presumes arrows and the like are MOVE_FLY_SLOW -
2032  * perhaps a bad assumption.
2033  */
2034  tmp = NULL;
2035  break;
2036  }
2037  if (mflags&P_IS_ALIVE) {
2038  FOR_MAP_PREPARE(m, x, y, tmp2)
2039  if (QUERY_FLAG(tmp2, FLAG_ALIVE)) {
2040  tmp = tmp2;
2041  found++;
2042  break;
2043  }
2044  FOR_MAP_FINISH();
2045  if (found)
2046  break;
2047  }
2048  }
2049  if (tmp == NULL)
2050  return find_arrow(op, type);
2051 
2052  return find_better_arrow(op, HEAD(tmp), type, NULL);
2053 }
2054 
2073 int fire_bow(object *op, object *arrow, int dir, int wc_mod, int16_t sx, int16_t sy) {
2074  object *bow;
2075  tag_t tag;
2076  int bowspeed, mflags;
2077  mapstruct *m;
2078 
2079  if (!dir) {
2081  "You can't shoot yourself!");
2082  return 0;
2083  }
2084  if (op->type == PLAYER)
2085  bow = op->contr->ranges[range_bow];
2086  else {
2087  /* Don't check for applied - monsters don't apply bows - in that way, they
2088  * don't need to switch back and forth between bows and weapons.
2089  */
2090  bow = object_find_by_type(op, BOW);
2091  if (!bow) {
2092  LOG(llevError, "Range: bow without activated bow (%s).\n", op->name);
2093  return 0;
2094  }
2095  }
2096  if (!bow->race || !bow->skill) {
2098  "Your %s is broken.",
2099  bow->name);
2100  return 0;
2101  }
2102 
2103  bowspeed = bow->stats.sp+get_dex_bonus(op->stats.Dex);
2104 
2105  /* penalize ROF for bestarrow */
2106  if (op->type == PLAYER && op->contr->bowtype == bow_bestarrow)
2107  bowspeed -= get_dex_bonus(op->stats.Dex)+5;
2108  if (bowspeed < 1)
2109  bowspeed = 1;
2110 
2111  if (arrow == NULL) {
2112  arrow = find_arrow(op, bow->race);
2113  if (arrow == NULL) {
2114  if (op->type == PLAYER)
2117  "You have no %s left.",
2118  bow->race);
2119  /* FLAG_READY_BOW will get reset if the monsters picks up some arrows */
2120  else
2122  return 0;
2123  }
2124  }
2125  mflags = get_map_flags(op->map, &m, sx, sy, &sx, &sy);
2126  if (mflags&P_OUT_OF_MAP) {
2127  return 0;
2128  }
2129  if (GET_MAP_MOVE_BLOCK(m, sx, sy)&MOVE_FLY_LOW) {
2130  return 0;
2131  }
2132 
2133  /* this should not happen, but sometimes does */
2134  if (arrow->nrof == 0) {
2135  object_remove(arrow);
2137  return 0;
2138  }
2139 
2140  arrow = object_split(arrow, 1, NULL, 0);
2141  if (arrow == NULL) {
2143  "You have no %s left.",
2144  bow->race);
2145  return 0;
2146  }
2147  object_set_owner(arrow, op);
2148  if (arrow->skill)
2149  free_string(arrow->skill);
2150  arrow->skill = add_refcount(bow->skill);
2151 
2152  arrow->direction = dir;
2153 
2154  if (op->type == PLAYER) {
2155  op->speed_left = 0.01-(float)FABS(op->speed)*100/bowspeed;
2156  fix_object(op);
2157  }
2158 
2159  if (bow->anim_suffix != NULL)
2161 
2162 /* SET_ANIMATION(arrow, arrow->direction);*/
2163  object_update_turn_face(arrow);
2164  arrow->stats.sp = arrow->stats.wc; /* save original wc and dam */
2165  arrow->stats.hp = arrow->stats.dam;
2166  arrow->stats.grace = arrow->attacktype;
2167  if (arrow->slaying != NULL)
2168  arrow->spellarg = strdup_local(arrow->slaying);
2169 
2170  /* Note that this was different for monsters - they got their level
2171  * added to the damage. I think the strength bonus is more proper.
2172  */
2173 
2174  arrow->stats.dam += (QUERY_FLAG(bow, FLAG_NO_STRENGTH) ? 0 : get_dam_bonus(op->stats.Str))
2175  +bow->stats.dam
2176  +bow->magic
2177  +arrow->magic;
2178 
2179  /* update the speed */
2180  arrow->speed = (float)((QUERY_FLAG(bow, FLAG_NO_STRENGTH) ? 0 : get_dam_bonus(op->stats.Str))+bow->magic+arrow->magic)/5.0
2181  +(float)bow->stats.dam/7.0;
2182 
2183  if (arrow->speed < 1.0)
2184  arrow->speed = 1.0;
2185  object_update_speed(arrow);
2186  arrow->speed_left = 0;
2187 
2188  if (op->type == PLAYER) {
2189  /* we don't want overflows of wc (sint), so cap the value - mod and pl should be subtracted */
2190  int mod = bow->magic
2191  +arrow->magic
2192  +get_dex_bonus(op->stats.Dex)
2193  +get_thaco_bonus(op->stats.Str)
2194  +arrow->stats.wc
2195  +bow->stats.wc
2196  -wc_mod;
2197  int plmod = (op->chosen_skill ? op->chosen_skill->level : op->level);
2198  if (plmod+mod > 140)
2199  plmod = 140-mod;
2200  else if (plmod+mod < -100)
2201  plmod = -100-mod;
2202  arrow->stats.wc = 20-(int8_t)plmod-(int8_t)mod;
2203 
2204  arrow->level = op->chosen_skill ? op->chosen_skill->level : op->level;
2205  } else {
2206  arrow->stats.wc = op->stats.wc
2207  -bow->magic
2208  -arrow->magic
2209  -arrow->stats.wc
2210  +wc_mod;
2211 
2212  arrow->level = op->level;
2213  }
2214  if (arrow->attacktype == AT_PHYSICAL)
2215  arrow->attacktype |= bow->attacktype;
2216  if (bow->slaying != NULL)
2217  arrow->slaying = add_string(bow->slaying);
2218 
2219  /* If move_type is ever changed, monster.c:monster_use_bow() needs to be changed too. */
2220  arrow->move_type = MOVE_FLY_LOW;
2221  arrow->move_on = MOVE_FLY_LOW|MOVE_WALK;
2222 
2223  tag = arrow->count;
2224  object_insert_in_map_at(arrow, m, op, 0, sx, sy);
2225 
2226  if (!object_was_destroyed(arrow, tag)) {
2227  play_sound_map(SOUND_TYPE_ITEM, arrow, arrow->direction, "fire");
2228  ob_process(arrow);
2229  }
2230 
2231  return 1;
2232 }
2233 
2244 static int similar_direction(int a, int b) {
2245  /* shortcut the obvious */
2246  if (a == b)
2247  return 1;
2248  /* Made this cleaner using modulus instead of a switch statement
2249  * We only needed the direction and the two adjacent to it
2250  * (8 is adjacent to 1 here) to return true, so a - 1, a, and a + 1
2251  * are the three directions that get "similar" affirmed.
2252  * -- Daniel Hawkins 2015-05-28
2253  */
2254  // The last one for the offset is added afterwards so we get
2255  // 1-8 instead of 0-7 (specifically, 0 becomes 8 without changing
2256  // the other values).
2257  if ((a % 8) + 1 == b || (a + 6 % 8) + 1 == b)
2258  return 1;
2259  return 0;
2260 }
2261 
2278 static int player_fire_bow(object *op, int dir) {
2279  int ret = 0, wcmod = 0;
2280 
2281  if (op->contr->bowtype == bow_bestarrow) {
2282  ret = fire_bow(op, pick_arrow_target(op, op->contr->ranges[range_bow]->race, dir), dir, 0, op->x, op->y);
2283  } else if (op->contr->bowtype >= bow_n && op->contr->bowtype <= bow_nw) {
2284  if (!similar_direction(dir, op->contr->bowtype-bow_n+1))
2285  wcmod = -1;
2286  ret = fire_bow(op, NULL, op->contr->bowtype-bow_n+1, wcmod, op->x, op->y);
2287  } else if (op->contr->bowtype == bow_threewide) {
2288  ret = fire_bow(op, NULL, dir, 0, op->x, op->y);
2289  ret |= fire_bow(op, NULL, dir, -5, op->x+freearr_x[absdir(dir+2)], op->y+freearr_y[absdir(dir+2)]);
2290  ret |= fire_bow(op, NULL, dir, -5, op->x+freearr_x[absdir(dir-2)], op->y+freearr_y[absdir(dir-2)]);
2291  } else if (op->contr->bowtype == bow_spreadshot) {
2292  ret |= fire_bow(op, NULL, dir, 0, op->x, op->y);
2293  ret |= fire_bow(op, NULL, absdir(dir-1), -5, op->x, op->y);
2294  ret |= fire_bow(op, NULL, absdir(dir+1), -5, op->x, op->y);
2295  } else {
2296  /* Simple case */
2297  ret = fire_bow(op, NULL, dir, 0, op->x, op->y);
2298  }
2299  return ret;
2300 }
2301 
2314 static void fire_misc_object(object *op, int dir) {
2315  object *item;
2316  char name[MAX_BUF];
2317 
2318  item = op->contr->ranges[range_misc];
2319  if (!item) {
2321  "You have no range item readied.");
2322  return;
2323  }
2324  if (!item->inv) {
2325  LOG(llevError, "Object %s lacks a spell\n", item->name);
2326  return;
2327  }
2328  if (item->type == WAND) {
2329  if (item->stats.food <= 0) {
2330  play_sound_player_only(op->contr, SOUND_TYPE_ITEM, item, 0, "poof");
2333  "The %s goes poof.",
2334  name);
2335  return;
2336  }
2337  } else if (item->type == ROD) {
2338  if (item->stats.hp < SP_level_spellpoint_cost(item, item->inv, SPELL_HIGHEST)) {
2339  play_sound_player_only(op->contr, SOUND_TYPE_ITEM, item, 0, "poof");
2342  "The %s whines for a while, but nothing happens.",
2343  name);
2344  return;
2345  }
2346  }
2347 
2348  if (cast_spell(op, item, dir, item->inv, NULL)) {
2349  SET_FLAG(op, FLAG_BEEN_APPLIED); /* You now know something about it */
2350  if (item->type == WAND) {
2352  } else if (item->type == ROD) {
2354  }
2355  }
2356 }
2357 
2366 void fire(object *op, int dir) {
2367 
2368  /* check for loss of invisiblity/hide */
2369  if (action_makes_visible(op))
2370  make_visible(op);
2371 
2372  switch (op->contr->shoottype) {
2373  case range_none:
2374  return;
2375 
2376  case range_bow:
2377  player_fire_bow(op, dir);
2378  return;
2379 
2380  case range_magic: /* Casting spells */
2381  cast_spell(op, op, dir, op->contr->ranges[range_magic], op->contr->spellparam[0] ? op->contr->spellparam : NULL);
2382  return;
2383 
2384  case range_misc:
2385  fire_misc_object(op, dir);
2386  return;
2387 
2388  case range_golem: /* Control summoned monsters from scrolls */
2389  if (op->contr->ranges[range_golem] == NULL
2390  || op->contr->golem_count != op->contr->ranges[range_golem]->count) {
2391  op->contr->ranges[range_golem] = NULL;
2392  op->contr->shoottype = range_none;
2393  op->contr->golem_count = 0;
2394  } else
2395  pets_control_golem(op->contr->ranges[range_golem], dir);
2396  return;
2397 
2398  case range_skill:
2399  if (!op->chosen_skill) {
2400  if (op->type == PLAYER)
2402  "You have no applicable skill to use.");
2403  return;
2404  }
2405  (void)do_skill(op, op, op->chosen_skill, dir, NULL);
2406  return;
2407 
2408  case range_builder:
2409  apply_map_builder(op, dir);
2410  return;
2411 
2412  default:
2414  "Illegal shoot type.");
2415  return;
2416  }
2417 }
2418 
2438 object *find_key(object *pl, object *container, object *door) {
2439  object *tmp, *key;
2440 
2441  /* Should not happen, but sanity checking is never bad */
2442  if (container->inv == NULL)
2443  return NULL;
2444 
2445  /* First, lets try to find a key in the top level inventory */
2446  tmp = NULL;
2447  if (door->type == DOOR) {
2448  int flag = FLAG_UNPAID;
2449  tmp = object_find_by_type_without_flags(container, KEY, &flag, 1);
2450  }
2451  /* For sanity, we should really check door type, but other stuff
2452  * (like containers) can be locked with special keys
2453  */
2454  if (!tmp && door->slaying != NULL) {
2456  }
2457  /* No key found - lets search inventories now */
2458  /* If we find and use a key in an inventory, return at that time.
2459  * otherwise, if we search all the inventories and still don't find
2460  * a key, return
2461  */
2462  if (!tmp) {
2463  FOR_INV_PREPARE(container, tmp) {
2464  /* No reason to search empty containers */
2465  if (tmp->type == CONTAINER && tmp->inv) {
2466  key = find_key(pl, tmp, door);
2467  if (key != NULL)
2468  return key;
2469  }
2470  } FOR_INV_FINISH();
2471  return NULL;
2472  }
2473  /* We get down here if we have found a key. Now if its in a container,
2474  * see if we actually want to use it
2475  */
2476  if (pl != container) {
2477  /* Only let players use keys in containers */
2478  if (!pl->contr)
2479  return NULL;
2480  /* cases where this fails:
2481  * If we only search the player inventory, return now since we
2482  * are not in the players inventory.
2483  * If the container is not active, return now since only active
2484  * containers can be used.
2485  * If we only search keyrings and the container does not have
2486  * a race/isn't a keyring.
2487  * No checking for all containers - to fall through past here,
2488  * inv must have been an container and must have been active.
2489  *
2490  * Change the color so that the message doesn't disappear with
2491  * all the others.
2492  */
2493  if (pl->contr->usekeys == key_inventory
2494  || !QUERY_FLAG(container, FLAG_APPLIED)
2495  || (pl->contr->usekeys == keyrings && (!container->race || strcmp(container->race, "keys")))) {
2496  char name_tmp[MAX_BUF], name_cont[MAX_BUF];
2497 
2498  query_name(tmp, name_tmp, MAX_BUF);
2499  query_name(container, name_cont, MAX_BUF);
2502  "The %s in your %s vibrates as you approach the door",
2503  name_tmp, name_cont);
2504  return NULL;
2505  }
2506  }
2507  return tmp;
2508 }
2509 
2520 static int player_attack_door(object *op, object *door) {
2521  /* If its a door, try to find a use a key. If we do destroy the door,
2522  * might as well return immediately as there is nothing more to do -
2523  * otherwise, we fall through to the rest of the code.
2524  */
2525  object *key = find_key(op, op, door);
2526 
2527  assert(door->type == DOOR || door->type == LOCKED_DOOR);
2528 
2529  /* IF we found a key, do some extra work */
2530  if (key) {
2531  char name[HUGE_BUF];
2532 
2533  play_sound_map(SOUND_TYPE_GROUND, door, 0, "open");
2534  if (action_makes_visible(op))
2535  make_visible(op);
2536  if (door->inv && (door->inv->type == RUNE || door->inv->type == TRAP))
2537  spring_trap(door->inv, op);
2538 
2542  "You open the door with the %s",
2543  name);
2544 
2545  if (door->type == DOOR)
2546  remove_door(door);
2547  else
2548  remove_locked_door(door); /* remove door without violence ;-) */
2549 
2550  /* Do this after we print the message */
2551  object_decrease_nrof_by_one(key); /* Use up one of the keys */
2552 
2553  return 1; /* Nothing more to do below */
2554 
2555  }
2556 
2557  if (door->type == LOCKED_DOOR) {
2558  /* Might as well return now - no other way to open this */
2560  door->msg);
2561  return 1;
2562  }
2563 
2564  if (door->type == DOOR && op->contr && !op->contr->run_on) {
2565  /* Player so try to pick the door */
2566  object *lock = find_skill_by_name(op, "lockpicking");
2567  if (lock) {
2568  /* Even if the lockpicking failed, don't go on moving, player should explicitely attack or run
2569  * to bash the door. */
2570  do_skill(op, op, lock, op->facing, NULL);
2571  return 1;
2572  }
2573  }
2574 
2575  return 0;
2576 }
2577 
2591 void move_player_attack(object *op, int dir) {
2592  object *mon, *tpl, *mon_owner;
2593  int16_t nx, ny;
2594  int on_battleground;
2595  mapstruct *m;
2596 
2597  if (op->contr->transport)
2598  tpl = op->contr->transport;
2599  else
2600  tpl = op;
2601  assert(tpl->map != NULL); // op must be on a map in order to move it
2602  nx = freearr_x[dir]+tpl->x;
2603  ny = freearr_y[dir]+tpl->y;
2604 
2605  on_battleground = op_on_battleground(tpl, NULL, NULL, NULL);
2606 
2607  // Temporarily store the map we are on before movement.
2608  mapstruct *bef = tpl->map;
2609 
2610  /* If braced, or can't move to the square, and it is not out of the
2611  * map, attack it. Note order of if statement is important - don't
2612  * want to be calling move_ob if braced, because move_ob will move the
2613  * player. This is a pretty nasty hack, because if we could
2614  * move to some space, it then means that if we are braced, we should
2615  * do nothing at all. As it is, if we are braced, we go through
2616  * quite a bit of processing. However, it probably is less than what
2617  * move_ob uses.
2618  */
2619  if ((op->contr->braced || !move_ob(tpl, dir, tpl)) && !out_of_map(tpl->map, nx, ny)) {
2620  if (OUT_OF_REAL_MAP(tpl->map, nx, ny)) {
2621  m = get_map_from_coord(tpl->map, &nx, &ny);
2622  if (!m)
2623  return; /* Don't think this should happen */
2624  } else
2625  m = tpl->map;
2626 
2627  if (GET_MAP_OB(m, nx, ny) == NULL) {
2628  /* LOG(llevError, "player_move_attack: GET_MAP_OB returns NULL, but player can not move there.\n");*/
2629  return;
2630  }
2631 
2632  mon = NULL;
2633  /* Go through all the objects, and find ones of interest. Only stop if
2634  * we find a monster - that is something we know we want to attack.
2635  * if its a door or barrel (can roll) see if there may be monsters
2636  * on the space
2637  */
2638  FOR_MAP_PREPARE(m, nx, ny, tmp) {
2639  if (tmp == op) {
2640  continue;
2641  }
2642  if (QUERY_FLAG(tmp, FLAG_ALIVE)) {
2643  mon = tmp;
2644  /* Gros: Objects like (pass-through) doors are alive, but haven't
2645  * their monster flag set - so this is a good way attack real
2646  * monsters in priority.
2647  */
2648  if (QUERY_FLAG(tmp, FLAG_MONSTER))
2649  break;
2650  }
2651  if (tmp->type == LOCKED_DOOR || QUERY_FLAG(tmp, FLAG_CAN_ROLL))
2652  mon = tmp;
2653  } FOR_MAP_FINISH();
2654 
2655  if (mon == NULL) /* This happens anytime the player tries to move */
2656  return; /* into a wall */
2657 
2658  mon = HEAD(mon);
2659  if ((mon->type == DOOR && mon->stats.hp >= 0) || (mon->type == LOCKED_DOOR))
2660  if (player_attack_door(op, mon))
2661  return;
2662 
2663  /* The following deals with possibly attacking peaceful
2664  * or friendly creatures. Basically, all players are considered
2665  * unaggressive. If the moving player has peaceful set, then the
2666  * object should be pushed instead of attacked. It is assumed that
2667  * if you are braced, you will not attack friends accidently,
2668  * and thus will not push them.
2669  */
2670 
2671  /* If the creature is a pet, push it even if the player is not
2672  * peaceful. Our assumption is the creature is a pet if the
2673  * player owns it and it is either friendly or unaggressive.
2674  */
2675  mon_owner = object_get_owner(mon);
2676  if ((op->type == PLAYER)
2677  && (mon_owner == op || (mon_owner != NULL && mon_owner->type == PLAYER && mon_owner->contr->party != NULL && mon_owner->contr->party == op->contr->party))
2679  /* If we're braced, we don't want to switch places with it */
2680  if (op->contr->braced)
2681  return;
2682  play_sound_map(SOUND_TYPE_LIVING, mon, dir, "push");
2683  (void)push_ob(mon, dir, op);
2684  if (op->contr->tmp_invis || op->hide)
2685  make_visible(op);
2686  return;
2687  }
2688 
2689  /* in certain circumstances, you shouldn't attack friendly
2690  * creatures. Note that if you are braced, you can't push
2691  * someone, but put it inside this loop so that you won't
2692  * attack them either.
2693  */
2694  if ((mon->type == PLAYER || mon->enemy != op)
2696  && (op->contr->peaceful && !on_battleground)) {
2697  if (!op->contr->braced) {
2698  play_sound_map(SOUND_TYPE_LIVING, mon, dir, "push");
2699  (void)push_ob(mon, dir, op);
2700  } else {
2702  "You withhold your attack");
2703  }
2704  if (op->contr->tmp_invis || op->hide)
2705  make_visible(op);
2706  }
2707 
2708  /* If the object is a boulder or other rollable object, then
2709  * roll it if not braced. You can't roll it if you are braced.
2710  */
2711  else if (QUERY_FLAG(mon, FLAG_CAN_ROLL) && (!op->contr->braced)) {
2712  recursive_roll(mon, dir, op);
2713  if (action_makes_visible(op))
2714  make_visible(op);
2715 
2716  /* Any generic living creature. Including things like doors.
2717  * Way it works is like this: First, it must have some hit points
2718  * and be living. Then, it must be one of the following:
2719  * 1) Not a player, 2) A player, but of a different party. Note
2720  * that party_number -1 is no party, so attacks can still happen.
2721  */
2722  } else if ((mon->stats.hp >= 0)
2724  && ((mon->type != PLAYER || op->contr->party == NULL || op->contr->party != mon->contr->party))) {
2725  /* If the player hasn't hit something this tick, and does
2726  * so, give them speed boost based on weapon speed. Doing
2727  * it here is better than process_players2, which basically
2728  * incurred a 1 tick offset.
2729  */
2730  if (op->weapon_speed_left < 0) {
2731  op->speed_left = -0.01;
2732  return;
2733  }
2734  op->weapon_speed_left -= 1.0;
2735 
2736  skill_attack(mon, op, 0, NULL, NULL);
2737 
2738  /* If attacking another player, that player gets automatic
2739  * hitback, and doesn't loose luck either.
2740  * Disable hitback on the battleground or if the target is
2741  * the wiz.
2742  */
2743  if (mon->type == PLAYER
2744  && mon->stats.hp >= 0
2745  && !mon->contr->has_hit
2746  && !on_battleground
2747  && !QUERY_FLAG(mon, FLAG_WIZ)) {
2748  short luck = mon->stats.luck;
2749  mon->contr->has_hit = 1;
2750  skill_attack(op, mon, 0, NULL, NULL);
2751  mon->stats.luck = luck;
2752  }
2753  if (action_makes_visible(op))
2754  make_visible(op);
2755  }
2756  } /* if player should attack something */
2757  else if (bef != tpl->map) {
2758  player_map_change_common(op, bef, tpl->map);
2759  }
2760 }
2761 
2768 static void update_transport_block(object *transport, int dir) {
2769  object *part;
2770  int sx, sy, x, y;
2771 
2772  object_get_multi_size(transport, &sx, &sy, NULL, NULL);
2773  assert(sx == sy);
2774 
2775  if (dir == 1 || dir == 5) {
2776  part = transport;
2777  for (y = 0; y <= sy; y++) {
2778  for (x = 0; x < sx; x++) {
2779  part->move_type = transport->move_type;
2780  part = part->more;
2781  }
2782  part->move_type = 0;
2783  part = part->more;
2784  }
2785  } else if (dir == 3 || dir == 7) {
2786  part = transport;
2787  for (y = 0; y < sy; y++) {
2788  for (x = 0; x <= sx; x++) {
2789  part->move_type = transport->move_type;
2790  part = part->more;
2791  }
2792  }
2793  while (part) {
2794  part->move_type = 0;
2795  part = part->more;
2796  }
2797  } else {
2798  for (part = transport; part; part = part->more) {
2799  part->move_type = transport->move_type;
2800  }
2801  }
2802 }
2803 
2813 static int turn_one_transport(object *transport, object *captain, int dir) {
2814  int x, y, scroll_dir = 0;
2815 
2816  assert(transport->type == TRANSPORT);
2817 
2818  x = transport->x;
2819  y = transport->y;
2820 
2821  if (transport->direction == 1 && dir == 8) {
2822  x--;
2823  } else if (transport->direction == 2 && dir == 3) {
2824  y++;
2825  } else if (transport->direction == 3 && dir == 2) {
2826  y--;
2827  } else if (transport->direction == 5 && dir == 6) {
2828  x--;
2829  } else if (transport->direction == 6 && dir == 5) {
2830  x++;
2831  } else if (transport->direction == 7 && dir == 8) {
2832  y--;
2833  } else if (transport->direction == 8 && dir == 7) {
2834  y++;
2835  } else if (transport->direction == 8 && dir == 1) {
2836  x++;
2837  }
2838 
2839  update_transport_block(transport, dir);
2840  object_remove(transport);
2841  if (ob_blocked(transport, transport->map, x, y)) {
2842  update_transport_block(transport, transport->direction);
2843  object_insert_in_map_at(transport, transport->map, NULL, 0, x, y);
2844  return 2;
2845  }
2846 
2847  if (x != transport->x || y != transport->y) {
2848 /* assert(scroll_dir != 0);*/
2849 
2850  FOR_INV_PREPARE(transport, pl) {
2851  if (pl->type == PLAYER) {
2852  pl->contr->do_los = 1;
2853  pl->map = transport->map;
2854  pl->x = x;
2855  pl->y = y;
2856  esrv_map_scroll(pl->contr->socket, freearr_x[scroll_dir], freearr_y[scroll_dir]);
2857  pl->contr->socket->update_look = 1;
2858  pl->contr->socket->look_position = 0;
2859  }
2860  } FOR_INV_FINISH();
2861  }
2862 
2863  object_insert_in_map_at(transport, transport->map, NULL, 0, x, y);
2864  transport->direction = dir;
2865  transport->facing = dir;
2866  animate_object(transport, dir);
2867  captain->direction = dir;
2868  return 1;
2869 }
2870 
2883 static int turn_transport(object *transport, object *captain, int dir) {
2884  assert(transport->type == TRANSPORT);
2885 
2886  if (object_value_set(transport, "turnable_transport") == false) {
2887  transport->direction = dir;
2888  transport->facing = dir;
2889  if (QUERY_FLAG(transport, FLAG_ANIMATE)) {
2890  animate_object(transport, dir);
2891  }
2892  captain->direction = dir;
2893  return 0;
2894  }
2895 
2896  if (transport->direction == dir)
2897  return 0;
2898 
2899  if (absdir(transport->direction-dir) > 2)
2900  return turn_one_transport(transport, captain, absdir(transport->direction+1));
2901  else
2902  return turn_one_transport(transport, captain, absdir(transport->direction-1));
2903 }
2904 
2916 int move_player(object *op, int dir) {
2917  object *transport = op->contr->transport; //< Transport player is in
2918 
2919  if (!transport && (op->map == NULL || op->map->in_memory != MAP_IN_MEMORY))
2920  return 0;
2921 
2922  /* Sanity check: make sure dir is valid */
2923  if ((dir < 0) || (dir >= 9)) {
2924  LOG(llevError, "move_player: invalid direction %d\n", dir);
2925  return 0;
2926  }
2927 
2928  if (QUERY_FLAG(op, FLAG_CONFUSED) && dir)
2929  dir = get_randomized_dir(dir);
2930 
2931  op->facing = dir;
2932 
2933  if (transport) {
2934  /* transport->contr is set up for the person in charge of the boat.
2935  * if that isn't this person, he can't steer it, etc
2936  */
2937  if (transport->contr != op->contr)
2938  return 0;
2939 
2940  /* Transport is out of movement. But update dir so it at least
2941  * will point in the same direction if player is running.
2942  */
2943  if (transport->speed_left < 0.0) {
2944  return 0;
2945  }
2946  /* Remove transport speed. Give player just a little speed -
2947  * enough so that they will get an action again quickly.
2948  */
2949  transport->speed_left -= 1.0;
2950  if (op->speed_left < 0.0)
2951  op->speed_left = -0.01;
2952 
2953  int turn = turn_transport(transport, op, dir);
2954  if (turn != 0)
2955  return 0;
2956  } else {
2957  if (op->hide) {
2958  do_hidden_move(op);
2959  }
2960 
2961  /* it is important to change the animation now, as fire or move_player_attack can start a compound animation,
2962  * and leave us with state = 0, which we don't want to change again. */
2963  op->state++; /* player moved, so change animation. */
2964  animate_object(op, op->facing);
2965  }
2966 
2967  if (op->contr->fire_on) {
2968  fire(op, dir);
2969  } else
2970  move_player_attack(op, dir);
2971 
2972  int pick = check_pick(op);
2973 
2974  /* Add special check for newcs players and fire on - this way, the
2975  * server can handle repeat firing.
2976  */
2977  if (op->contr->fire_on || (op->contr->run_on && pick != 0)) {
2978  op->direction = dir;
2979  } else {
2980  op->direction = 0;
2981  }
2982  return 0;
2983 }
2984 
2995 int face_player(object *op, int dir) {
2996  object *transport = op->contr->transport; //< Transport player is in
2997 
2998  if (!transport && (op->map == NULL || op->map->in_memory != MAP_IN_MEMORY))
2999  return 0;
3000 
3001  /* Sanity check: make sure dir is valid */
3002  if ((dir < 0) || (dir >= 9)) {
3003  LOG(llevError, "move_player: invalid direction %d\n", dir);
3004  return 0;
3005  }
3006 
3007  if (QUERY_FLAG(op, FLAG_CONFUSED) && dir)
3008  dir = get_randomized_dir(dir);
3009 
3010  op->facing = dir;
3011 
3012  if (transport) {
3013  /* transport->contr is set up for the person in charge of the boat.
3014  * if that isn't this person, he can't steer it, etc
3015  */
3016  if (transport->contr != op->contr)
3017  return 0;
3018 
3019  turn_transport(transport, op, dir);
3020  } else {
3021  if (op->hide) {
3022  do_hidden_move(op);
3023  }
3024 
3025  /* it is important to change the animation now, as fire or move_player_attack can start a compound animation,
3026  * and leave us with state = 0, which we don't want to change again. */
3027  op->state++; /* player moved, so change animation. */
3028  animate_object(op, op->facing);
3029  }
3030 
3031  /* Add special check for newcs players and fire on - this way, the
3032  * server can handle repeat firing.
3033  */
3034  if (op->contr->fire_on || op->contr->run_on) {
3035  op->direction = dir;
3036  } else {
3037  op->direction = 0;
3038  }
3039  return 0;
3040 }
3041 
3054 int handle_newcs_player(object *op) {
3055  if (op->contr->hidden) {
3056  op->invisible = 1000;
3057  /* the socket code flashes the player visible/invisible
3058  * depending on the value if invisible, so we need to
3059  * alternate it here for it to work correctly.
3060  */
3061  if (pticks&2)
3062  op->invisible--;
3063  } else if (op->invisible && !(QUERY_FLAG(op, FLAG_MAKE_INVIS))) {
3064  op->invisible--;
3065  if (!op->invisible) {
3066  make_visible(op);
3068  "Your invisibility spell runs out.");
3069  }
3070  }
3071 
3072  if (QUERY_FLAG(op, FLAG_SCARED)) {
3073  flee_player(op);
3074  /* If player is still scared, that is his action for this tick */
3075  if (QUERY_FLAG(op, FLAG_SCARED)) {
3076  op->speed_left--;
3077  return 0;
3078  }
3079  }
3080 
3081  /* I've been seeing crashes where the golem has been destroyed, but
3082  * the player object still points to the defunct golem. The code that
3083  * destroys the golem looks correct, and it doesn't always happen, so
3084  * put this in a a workaround to clean up the golem pointer.
3085  */
3086  if (op->contr->ranges[range_golem]
3087  && ((op->contr->golem_count != op->contr->ranges[range_golem]->count) || QUERY_FLAG(op->contr->ranges[range_golem], FLAG_REMOVED))) {
3088  op->contr->ranges[range_golem] = NULL;
3089  op->contr->golem_count = 0;
3090  }
3091 
3092  /*
3093  * If the player has been paralyzed, we unmark the flag and give a message to the player
3094  */
3095  if (QUERY_FLAG(op, FLAG_PARALYZED)) {
3097  // TODO: Is this check necessary? We are in player.c, after all.
3098  if (op->type == PLAYER)
3099  {
3101  "You can stretch your stiff joints once more.");
3102  }
3103  }
3104 
3105  if (op->direction && (op->contr->run_on || op->contr->fire_on)) {
3106  /* All move commands take 1 tick, at least for now */
3107  op->speed_left--;
3108 
3109  /* Instead of all the stuff below, let move_player take care
3110  * of it. Also, some of the skill stuff is only put in
3111  * there, as well as the confusion stuff.
3112  */
3113  move_player(op, op->direction);
3114  if (op->speed_left > 0)
3115  return 1;
3116  else
3117  return 0;
3118  }
3119  return 0;
3120 }
3121 
3132 static int save_life(object *op) {
3133  object *tmp;
3134 
3135  if (!QUERY_FLAG(op, FLAG_LIFESAVE))
3136  return 0;
3137 
3139  if (tmp != NULL) {
3140  char name[MAX_BUF];
3141 
3143  play_sound_map(SOUND_TYPE_ITEM, tmp, 0, "evaporate");
3145  "Your %s vibrates violently, then evaporates.",
3146  name);
3147  object_remove(tmp);
3150  if (op->stats.hp < 0)
3151  op->stats.hp = op->stats.maxhp;
3152  if (op->stats.food < 0)
3153  op->stats.food = MAX_FOOD;
3154  fix_object(op);
3155  return 1;
3156  }
3157  LOG(llevError, "Error: LIFESAVE set without applied object.\n");
3159  enter_player_savebed(op); /* bring him home. */
3160  return 0;
3161 }
3162 
3175 void remove_unpaid_objects(object *op, object *env, int free_items) {
3177  if (QUERY_FLAG(op, FLAG_UNPAID)) {
3178  object_remove(op);
3179  if (free_items)
3181  else
3182  object_insert_in_map_at(op, env->map, NULL, 0, env->x, env->y);
3183  } else if (op->inv)
3184  remove_unpaid_objects(op->inv, env, free_items);
3186 }
3187 
3205 static const char *gravestone_text(object *op, char *buf2, int len) {
3206  char buf[MAX_BUF];
3207  time_t now = time(NULL);
3208 
3209  strncpy(buf2, " R.I.P.\n\n", len);
3210  if (op->type == PLAYER)
3211  snprintf(buf, sizeof(buf), "%s the %s\n", op->name, op->contr->title);
3212  else
3213  snprintf(buf, sizeof(buf), "%s\n", op->name);
3214  strncat(buf2, " ", 20-strlen(buf)/2);
3215  strncat(buf2, buf, len-strlen(buf2)-1);
3216  if (op->type == PLAYER)
3217  snprintf(buf, sizeof(buf), "who was in level %d when killed\n", op->level);
3218  else
3219  snprintf(buf, sizeof(buf), "who was in level %d when died.\n\n", op->level);
3220  strncat(buf2, " ", 20-strlen(buf)/2);
3221  strncat(buf2, buf, len-strlen(buf2)-1);
3222  if (op->type == PLAYER) {
3223  snprintf(buf, sizeof(buf), "by %s.\n\n", op->contr->killer);
3224  strncat(buf2, " ", 21-strlen(buf)/2);
3225  strncat(buf2, buf, len-strlen(buf2)-1);
3226  }
3227  strftime(buf, MAX_BUF, "%b %d %Y\n", localtime(&now));
3228  strncat(buf2, " ", 20-strlen(buf)/2);
3229  strncat(buf2, buf, len-strlen(buf2)-1);
3230  return buf2;
3231 }
3232 
3240 void do_some_living(object *op) {
3241  int last_food = op->stats.food;
3242  int gen_hp, gen_sp, gen_grace;
3243  int rate_hp = 1200;
3244  int rate_sp = 2500;
3245  int rate_grace = 2000;
3246 
3247  if (op->contr->state == ST_PLAYING) {
3248  /* these next three if clauses make it possible to SLOW DOWN
3249  hp/grace/spellpoint regeneration. */
3250  if (op->contr->gen_hp >= 0)
3251  gen_hp = (op->contr->gen_hp+1)*op->stats.maxhp;
3252  else {
3253  gen_hp = op->stats.maxhp;
3254  rate_hp -= rate_hp/2*op->contr->gen_hp;
3255  }
3256  if (op->contr->gen_sp >= 0)
3257  gen_sp = (op->contr->gen_sp+1)*op->stats.maxsp;
3258  else {
3259  gen_sp = op->stats.maxsp;
3260  rate_sp -= rate_sp/2*op->contr->gen_sp;
3261  }
3262  if (op->contr->gen_grace >= 0)
3263  gen_grace = (op->contr->gen_grace+1)*op->stats.maxgrace;
3264  else {
3265  gen_grace = op->stats.maxgrace;
3266  rate_grace -= rate_grace/2*op->contr->gen_grace;
3267  }
3268 
3269  /* Regenerate Spell Points */
3270  if (op->contr->ranges[range_golem] == NULL && --op->last_sp < 0) {
3271  gen_sp = gen_sp*10/MAX(op->contr->gen_sp_armour, 10);
3272  if (op->stats.sp < op->stats.maxsp) {
3273  op->stats.sp++;
3274  /* dms do not consume food */
3275  if (!QUERY_FLAG(op, FLAG_WIZ)) {
3276  op->stats.food--;
3277  if (op->contr->digestion < 0)
3278  op->stats.food += op->contr->digestion;
3279  else if (op->contr->digestion > 0
3280  && random_roll(0, op->contr->digestion, op, PREFER_HIGH))
3281  op->stats.food = last_food;
3282  }
3283  }
3284  op->last_sp = rate_sp/(MAX(gen_sp, 20)+10);
3285  }
3286 
3287  /* Regenerate Grace */
3288  /* I altered this a little - maximum grace is only achieved through prayer -b.t.*/
3289  if (--op->last_grace < 0) {
3290  if (op->stats.grace < op->stats.maxgrace/2)
3291  op->stats.grace++; /* no penalty in food for regaining grace */
3292  op->last_grace = rate_grace/(MAX(gen_grace, 20)+10);
3293  /* wearing stuff doesn't detract from grace generation. */
3294  }
3295 
3296  /* Regenerate Hit Points (unless you are a wraith player) */
3297  if (--op->last_heal < 0 && !is_wraith_pl(op)) {
3298  if (op->stats.hp < op->stats.maxhp) {
3299  op->stats.hp++;
3300  /* dms do not consume food */
3301  if (!QUERY_FLAG(op, FLAG_WIZ)) {
3302  op->stats.food--;
3303  if (op->contr->digestion < 0)
3304  op->stats.food += op->contr->digestion;
3305  else if (op->contr->digestion > 0
3306  && random_roll(0, op->contr->digestion, op, PREFER_HIGH))
3307  op->stats.food = last_food;
3308  }
3309  }
3310  op->last_heal = rate_hp/(MAX(gen_hp, 20)+10);
3311  }
3312 
3313  /* Digestion */
3314  if (--op->last_eat < 0) {
3315  int bonus = MAX(op->contr->digestion, 0);
3316  int penalty = MAX(-op->contr->digestion, 0);
3317  if (op->contr->gen_hp > 0)
3318  op->last_eat = 25*(1+bonus)/(op->contr->gen_hp+penalty+1);
3319  else
3320  op->last_eat = 25*(1+bonus)/(penalty+1);
3321  /* dms do not consume food */
3322  if (!QUERY_FLAG(op, FLAG_WIZ))
3323  op->stats.food--;
3324  }
3325  }
3326 
3327  if (op->contr->state == ST_PLAYING && op->stats.food < 0 && op->stats.hp >= 0) {
3328  if (is_wraith_pl(op))
3329  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ITEM, MSG_TYPE_ITEM_REMOVE, "You feel a hunger for living flesh.");
3330  /* Only allow eat if not paralyzed. Otherwise our paralyzed player is "moving" to eat.
3331  * Daniel Hawkins 2017-08-23
3332  */
3333  else if (!QUERY_FLAG(op, FLAG_PARALYZED)){
3334  object *flesh = NULL;
3335 
3336  FOR_INV_PREPARE(op, tmp) {
3337  if (!QUERY_FLAG(tmp, FLAG_UNPAID)) {
3338  if (tmp->type == FOOD || tmp->type == DRINK || tmp->type == POISON) {
3340  "You blindly grab for a bite of food.");
3341  apply_manual(op, tmp, 0);
3342  if (op->stats.food >= 0 || op->stats.hp < 0)
3343  break;
3344  } else if (tmp->type == FLESH)
3345  flesh = tmp;
3346  } /* End if paid for object */
3347  } FOR_INV_FINISH(); /* end of for loop */
3348  /* If player is still starving, it means they don't have any food, so
3349  * eat flesh instead.
3350  */
3351  if (op->stats.food < 0 && op->stats.hp >= 0 && flesh) {
3353  "You blindly grab for a bite of food.");
3354  apply_manual(op, flesh, 0);
3355  }
3356  } /* end not wraith and not paralyzed */
3357  else { // Print a message for when the player is starving and paralyzed
3358  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ITEM, MSG_TYPE_ITEM_REMOVE, "Your stomach rumbles, but you can't reach your food.");
3359  } /* end not wraith and is paralyzed */
3360  } /* end if player is starving */
3361 
3362  if (op->stats.food < 0 && op->stats.hp > 0){
3363  // We know food < 0, so we want the absolute value of food
3364  int32_t adjust_by = MIN(-(op->stats.food), op->stats.hp);
3365  op->stats.food += adjust_by;
3366  op->stats.hp -= adjust_by;
3367  }
3368 
3369  if (!op->contr->state && !QUERY_FLAG(op, FLAG_WIZ) && (op->stats.hp < 0 || op->stats.food < 0))
3370  kill_player(op, NULL);
3371 }
3372 
3379 static void loot_object(object *op) {
3380  object *tmp2;
3381 
3382  if (op->container) { /* close open sack first */
3383  apply_container(op, op->container, AP_NULL);
3384  }
3385 
3386  FOR_INV_PREPARE(op, tmp) {
3387  if (tmp->invisible)
3388  continue;
3389  object_remove(tmp);
3390  tmp->x = op->x,
3391  tmp->y = op->y;
3392  if (tmp->type == CONTAINER) { /* empty container to ground */
3393  loot_object(tmp);
3394  }
3395  if (!QUERY_FLAG(tmp, FLAG_UNIQUE)
3397  if (tmp->nrof > 1) {
3398  tmp2 = object_split(tmp, 1+RANDOM()%(tmp->nrof-1), NULL, 0);
3400  object_insert_in_map_at(tmp, op->map, NULL, 0, op->x, op->y);
3401  } else
3403  } else
3404  object_insert_in_map_at(tmp, op->map, NULL, 0, op->x, op->y);
3405  } FOR_INV_FINISH();
3406 }
3407 
3418 static void restore_player(object *op) {
3419  object *tmp;
3420  archetype *at = find_archetype("poisoning");
3421  if (at != NULL) {
3422  tmp = arch_present_in_ob(at, op);
3423  if (tmp) {
3424  object_remove(tmp);
3427  "Your body feels cleansed");
3428  }
3429  }
3430 
3431  at = find_archetype("confusion");
3432  if (at != NULL) {
3433  tmp = arch_present_in_ob(at, op);
3434  if (tmp) {
3435  object_remove(tmp);
3438  "Your mind feels clearer");
3439  }
3440  }
3441 
3442  cure_disease(op, NULL, NULL); /* remove any disease */
3443 }
3444 
3456 void kill_player(object *op, const object *killer) {
3457  char buf[MAX_BUF];
3458  int x, y;
3459  object *tmp;
3460  archetype *trophy = NULL;
3461 
3462  /* Don't die if the player's life can be saved. */
3463  if (save_life(op)) {
3464  return;
3465  }
3466 
3467  /* If player dies on BATTLEGROUND, no stat/exp loss! For Combat-Arenas
3468  * in cities ONLY!!! It is very important that this doesn't get abused.
3469  * Look at op_on_battleground() for more info --AndreasV
3470  */
3471  if (op_on_battleground(op, &x, &y, &trophy)) {
3472  assert(trophy != NULL);
3474  "You have been defeated in combat!\n"
3475  "Local medics have saved your life...");
3476 
3477  /* restore player */
3478  restore_player(op);
3479 
3480  op->stats.hp = op->stats.maxhp;
3481  if (op->stats.food <= 0)
3482  op->stats.food = MAX_FOOD;
3483 
3484  /* create a bodypart-trophy to make the winner happy */
3485  tmp = arch_to_object(trophy);
3486  if (tmp != NULL) {
3487  snprintf(buf, sizeof(buf), "%s's %s", op->name, tmp->name);
3488  tmp->name = add_string(buf);
3489 
3490  snprintf(buf, sizeof(buf),
3491  "This %s was %s %s the %s, who was defeated at level %d by %s.\n",
3492  tmp->name, tmp->type == FLESH ? "cut off" : "taken from",
3493  op->name, op->contr->title,
3494  (int)(op->level), op->contr->killer);
3495 
3497  tmp->type = 0;
3498  tmp->value = 0;
3499  tmp->material = 0;
3500  tmp->materialname = NULL;
3501  object_insert_in_map_at(tmp, op->map, op, 0, op->x, op->y);
3502  }
3503 
3504  /* teleport defeated player to new destination*/
3505  transfer_ob(op, x, y, 0, NULL);
3506  op->contr->braced = 0;
3507  return;
3508  }
3509 
3510  if (events_execute_object_event(op, EVENT_DEATH, NULL, NULL, NULL, SCRIPT_FIX_ALL) != 0)
3511  return;
3512 
3514  if (op->stats.food < 0) {
3515  snprintf(buf, sizeof(buf), "%s starved to death.", op->name);
3516  strcpy(op->contr->killer, "starvation");
3517  } else {
3518  snprintf(buf, sizeof(buf), "%s died.", op->name);
3519  }
3520  play_sound_player_only(op->contr, SOUND_TYPE_LIVING, op, 0, "death");
3521 
3522  if (settings.not_permadeth == TRUE) {
3524  } else {
3526  }
3527 }
3528 
3537 static void kill_player_not_permadeath(object *op) {
3538  int num_stats_lose;
3539  int will_kill_again;
3540  int lost_a_stat;
3541  int z;
3542  object *tmp;
3543  char buf[MAX_BUF];
3544  archetype *at;
3545 
3546  /* Basically two ways to go - remove a stat permanently, or just
3547  * make it depletion. This bunch of code deals with that aspect
3548  * of death.
3549  */
3551  /* If stat loss is permanent, lose one stat only. */
3552  /* Lower level chars don't lose as many stats because they suffer
3553  more if they do. */
3554  /* Higher level characters can afford things such as potions of
3555  restoration, or better, stat potions. So we slug them that
3556  little bit harder. */
3557  /* GD */
3559  num_stats_lose = 1;
3560  else
3561  num_stats_lose = 1+op->level/BALSL_NUMBER_LOSSES_RATIO;
3562  } else {
3563  num_stats_lose = 1;
3564  }
3565  lost_a_stat = 0;
3566 
3567  for (z = 0; z < num_stats_lose; z++) {
3569  int i;
3570 
3571  /* Pick a random stat and take a point off it. Tell the player
3572  * what he lost.
3573  */
3574  i = RANDOM()%7;
3575  change_attr_value(&(op->stats), i, -1);
3577  change_attr_value(&(op->contr->orig_stats), i, -1);
3578  check_stat_bounds(&(op->contr->orig_stats), MIN_STAT, settings.max_stat);
3581  lose_msg[i]);
3582  lost_a_stat = 1;
3583  } else {
3584  /* deplete a stat */
3586  if (deparch == NULL) {
3587  continue;
3588  }
3589  object *dep;
3590  int lose_this_stat;
3591  int i;
3592 
3593  i = RANDOM()%7;
3594  dep = arch_present_in_ob(deparch, op);
3595  if (!dep) {
3596  dep = arch_to_object(deparch);
3597  object_insert_in_ob(dep, op);
3598  }
3599  lose_this_stat = 1;
3601  int this_stat;
3602 
3603  /* GD */
3604  /* Get the stat that we're about to deplete. */
3605  this_stat = get_attr_value(&(dep->stats), i);
3606  if (this_stat < 0) {
3607  int loss_chance = 1+op->level/BALSL_LOSS_CHANCE_RATIO;
3608  int keep_chance = this_stat*this_stat;
3609  /* Yes, I am paranoid. Sue me. */
3610  if (keep_chance < 1)
3611  keep_chance = 1;
3612 
3613  /* There is a maximum depletion total per level. */
3614  if (this_stat < -1-op->level/BALSL_MAX_LOSS_RATIO) {
3615  lose_this_stat = 0;
3616  /* Take loss chance vs keep chance to see if we
3617  retain the stat. */
3618  } else {
3619  if (random_roll(0, loss_chance+keep_chance-1, op, PREFER_LOW) < keep_chance)
3620  lose_this_stat = 0;
3621  /* 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"); */
3622  }
3623  }
3624  }
3625 
3626  if (lose_this_stat) {
3627  int this_stat;
3628 
3629  this_stat = get_attr_value(&(dep->stats), i);
3630  /* We could try to do something clever like find another
3631  * stat to reduce if this fails. But chances are, if
3632  * stats have been depleted to -50, all are pretty low
3633  * and should be roughly the same, so it shouldn't make a
3634  * difference.
3635  */
3636  if (this_stat >= -50) {
3637  change_attr_value(&(dep->stats), i, -1);
3638  SET_FLAG(dep, FLAG_APPLIED);
3640  drain_msg[i]);
3641  fix_object(op);
3642  lost_a_stat = 1;
3643  }
3644  }
3645  }
3646  }
3647  /* If no stat lost, tell the player. */
3648  if (!lost_a_stat) {
3649  /* determine_god() seems to not work sometimes... why is this? Should I be using something else? GD */
3650  const char *god = determine_god(op);
3651 
3652  if (god && (strcmp(god, "none")))
3655  "For a brief moment you feel the holy presence of %s protecting you",
3656  god);
3657  else
3660  "For a brief moment you feel a holy presence protecting you.");
3661  }
3662 
3663  /* Put a gravestone up where the character 'almost' died. List the
3664  * exp loss on the stone.
3665  */
3666  at = find_archetype("gravestone");
3667  if (at != NULL) {
3668  tmp = arch_to_object(at);
3669  snprintf(buf, sizeof(buf), "%s's gravestone", op->name);
3670  FREE_AND_COPY(tmp->name, buf);
3671  snprintf(buf, sizeof(buf), "%s's gravestones", op->name);
3672  FREE_AND_COPY(tmp->name_pl, buf);
3673  snprintf(buf, sizeof(buf), "RIP\nHere rests the hero %s the %s,\n"
3674  "who was killed\n"
3675  "by %s.\n",
3676  op->name, op->contr->title,
3677  op->contr->killer);
3679  object_insert_in_map_at(tmp, op->map, NULL, 0, op->x, op->y);
3680  }
3681 
3682  /* restore player: remove any poisoning, disease and confusion the
3683  * character may be suffering.*/
3684  restore_player(op);
3685 
3686  /* Subtract the experience points, if we died cause of food, give
3687  * us food, and reset HP's...
3688  */
3690  if (op->stats.food < 100)
3691  op->stats.food = 900;
3692  op->stats.hp = op->stats.maxhp;
3693  op->stats.sp = MAX(op->stats.sp, op->stats.maxsp);
3694  op->stats.grace = MAX(op->stats.grace, op->stats.maxgrace);
3695 
3696  /* Check to see if the player is in a shop. IF so, then check to see if
3697  * the player has any unpaid items. If so, remove them and put them back
3698  * in the map.
3699  *
3700  * If they are not in a shop, just free the unpaid items instead of
3701  * putting them back on map.
3702  */
3703  if (shop_contains(op))
3704  remove_unpaid_objects(op->inv, op, 0);
3705  else
3706  remove_unpaid_objects(op->inv, op, 1);
3707 
3708  /* Move player to his current respawn-position (usually last savebed) */
3710 
3711  /* Save the player before inserting the force to reduce chance of abuse. */
3712  op->contr->braced = 0;
3713  /* don't pick up in apartment */
3714  if (op->contr->mode & PU_NEWMODE) {
3715  op->contr->mode = op->contr->mode | PU_INHIBIT;
3716  esrv_send_pickup(op->contr);
3717  } else {
3718  op->contr->mode = 0;
3719  }
3720  if ( op->contr->search_str[0] ) command_search_items(op,NULL); /* turn off search-items */
3721  save_player(op, 1);
3722 
3723  /* it is possible that the player has blown something up
3724  * at his savebed location, and that can have long lasting
3725  * spell effects. So first see if there is a spell effect
3726  * on the space that might harm the player.
3727  */
3728  will_kill_again = 0;
3729  FOR_MAP_PREPARE(op->map, op->x, op->y, tmp)
3730  if (tmp->type == SPELL_EFFECT)
3731  will_kill_again |= tmp->attacktype;
3732  FOR_MAP_FINISH();
3733  if (will_kill_again) {
3734  object *force;
3735  int at;
3736 
3738  /* 50 ticks should be enough time for the spell to abate */
3739  force->speed = 0.1;
3740  force->speed_left = -5.0;
3742  for (at = 0; at < NROFATTACKS; at++) {
3743  if (will_kill_again&(1<<at))
3744  force->resist[at] = 100;
3745  }
3747  fix_object(op);
3748  }
3749 
3750  /* Tell the player they have died */
3752  "YOU HAVE DIED.");
3753 }
3754 
3761 static void kill_player_permadeath(object *op) {
3762  char buf[MAX_BUF];
3763  char ac_buf[MAX_BUF];
3764  int x, y;
3765  mapstruct *map;
3766  object *tmp;
3767  archetype *at;
3768 
3769  /* save the map location for corpse, gravestone*/
3770  x = op->x;
3771  y = op->y;
3772  map = op->map;
3773 
3774  party_leave(op);
3775  if (settings.set_title == TRUE)
3776  player_set_own_title(op->contr, "");
3777 
3778  /* buf should be the kill message */
3780  buf);
3781  hiscore_check(op, 0);
3782  if (op->contr->ranges[range_golem] != NULL) {
3783  remove_friendly_object(op->contr->ranges[range_golem]);
3784  object_remove(op->contr->ranges[range_golem]);
3785  object_free_drop_inventory(op->contr->ranges[range_golem]);
3786  op->contr->ranges[range_golem] = NULL;
3787  op->contr->golem_count = 0;
3788  }
3789  loot_object(op); /* Remove some of the items for good */
3790  object_remove(op);
3791  op->direction = 0;
3792 
3793  if (!QUERY_FLAG(op, FLAG_WAS_WIZ) && op->stats.exp) {
3794  if (settings.resurrection == TRUE) {
3795  /* save playerfile sans equipment when player dies
3796  * -then save it as player.pl.dead so that future resurrection
3797  * -type spells will work on them nicely
3798  */
3799  op->stats.hp = op->stats.maxhp;
3800  op->stats.food = MAX_FOOD;
3801 
3802  /* set the location of where the person will reappear when */
3803  /* maybe resurrection code should fix map also */
3804  safe_strncpy(op->contr->maplevel, settings.emergency_mapname,
3805  sizeof(op->contr->maplevel));
3806  if (op->map != NULL)
3807  op->map = NULL;
3808  op->x = settings.emergency_x;
3809  op->y = settings.emergency_y;
3810  save_player(op, 0);
3811  op->map = map;
3812  /* please see resurrection.c: peterm */
3813  dead_player(op);
3814  } else {
3815  delete_character(op->name);
3816  }
3817  }
3818  play_again(op);
3819 
3820  /* peterm: added to create a corpse at deathsite. */
3821  at = find_archetype("corpse_pl");
3822  if (at != NULL) {
3823  tmp = arch_to_object(at);
3824  snprintf(buf, sizeof(buf), "%s", op->name);
3825  FREE_AND_COPY(tmp->name, buf);
3826  FREE_AND_COPY(tmp->name_pl, buf);
3827  tmp->level = op->level;
3828  object_set_msg(tmp, gravestone_text(op, buf, sizeof(buf)));
3830  /*
3831  * Put the account name under slaying.
3832  * Does not seem to cause weird effects, but more testing may ensure this.
3833  */
3834  snprintf(ac_buf, sizeof(ac_buf), "%s", op->contr->socket->account_name);
3835  FREE_AND_COPY(tmp->slaying, ac_buf);
3836  object_insert_in_map_at(tmp, map, NULL, 0, x, y);
3837  }
3838 }
3839 
3847 void fix_weight(void) {
3848  player *pl;
3849 
3850  for (pl = first_player; pl != NULL; pl = pl->next) {
3851  int old = pl->ob->carrying, sum = object_sum_weight(pl->ob);
3852 
3853  if (old == sum)
3854  continue;
3855  fix_object(pl->ob);
3856  LOG(llevDebug, "Fixed inventory in %s (%d -> %d)\n", pl->ob->name, old, sum);
3857  }
3858 }
3859 
3863 void fix_luck(void) {
3864  player *pl;
3865 
3866  for (pl = first_player; pl != NULL; pl = pl->next)
3867  if (!pl->ob->contr->state)
3868  change_luck(pl->ob, 0);
3869 }
3870 
3871 
3884 void cast_dust(object *op, object *throw_ob, int dir) {
3885  object *skop, *spob;
3886 
3887  skop = find_skill_by_name(op, throw_ob->skill);
3888 
3889  /* casting POTION 'dusts' is really a use_magic_item skill */
3890  if (op->type == PLAYER && throw_ob->type == POTION && !skop) {
3891  LOG(llevError, "Player %s lacks critical skill use_magic_item!\n", op->name);
3892  return;
3893  }
3894  spob = throw_ob->inv;
3895  if (op->type == PLAYER && spob)
3897  "You cast %s.",
3898  spob->name);
3899 
3900  cast_spell(op, throw_ob, dir, spob, NULL);
3901 
3902  if (!QUERY_FLAG(throw_ob, FLAG_REMOVED))
3903  object_remove(throw_ob);
3904  object_free_drop_inventory(throw_ob);
3905 }
3906 
3913 void make_visible(object *op) {
3914  op->hide = 0;
3915  op->invisible = 0;
3916  if (op->type == PLAYER) {
3917  op->contr->tmp_invis = 0;
3918  if (op->contr->invis_race)
3919  FREE_AND_CLEAR_STR(op->contr->invis_race);
3920  }
3922 }
3923 
3933 int is_true_undead(object *op) {
3934  if (QUERY_FLAG(&op->arch->clone, FLAG_UNDEAD))
3935  return 1;
3936 
3937  if (op->type == PLAYER) {
3938  FOR_INV_PREPARE(op, tmp) {
3939  if (tmp->type == 44 && tmp->stats.Wis)
3940  if (QUERY_FLAG(tmp, FLAG_UNDEAD))
3941  return 1;
3942  } FOR_INV_FINISH();
3943  }
3944  return 0;
3945 }
3946 
3957 int hideability(object *ob) {
3958  int i, level = 0, mflag;
3959  int16_t x, y;
3960 
3961  if (!ob || !ob->map)
3962  return 0;
3963 
3964  /* so, on normal lighted maps, its hard to hide */
3965  level = ob->map->darkness-2;
3966 
3967  /* this also picks up whether the object is glowing.
3968  * If you carry a light on a non-dark map, its not
3969  * as bad as carrying a light on a pitch dark map
3970  */
3971  if (has_carried_lights(ob))
3972  level = -(10+(2*ob->map->darkness));
3973 
3974  /* scan through all nearby squares for terrain to hide in */
3975  for (i = 0, x = ob->x, y = ob->y; i < 9; i++, x = ob->x+freearr_x[i], y = ob->y+freearr_y[i]) {
3976  mflag = get_map_flags(ob->map, NULL, x, y, NULL, NULL);
3977  if (mflag&P_OUT_OF_MAP) {
3978  continue;
3979  }
3980  if (mflag&P_BLOCKSVIEW) /* something to hide near! */
3981  level += 2;
3982  else /* open terrain! */
3983  level -= 1;
3984  }
3985 
3986  return level;
3987 }
3988 
3998 void do_hidden_move(object *op) {
3999  int hide = 0, num = random_roll(0, 19, op, PREFER_LOW);
4000  object *skop;
4001 
4002  if (!op || !op->map)
4003  return;
4004 
4006 
4007  /* its *extremely *hard to run and sneak/hide at the same time! */
4008  if (op->type == PLAYER && op->contr->run_on) {
4009  if (!skop || num >= skop->level) {
4011  "You ran too much! You are no longer hidden!");
4012  make_visible(op);
4013  return;
4014  } else
4015  num += 20;
4016  }
4017  num += op->map->difficulty;
4018  hide = hideability(op); /* modify by terrain hidden level */
4019  num -= hide;
4020  if ((op->type == PLAYER && hide < -10)
4021  || ((op->invisible -= num) <= 0)) {
4022  make_visible(op);
4023  if (op->type == PLAYER)
4025  "You moved out of hiding! You are visible!");
4026  } else if (op->type == PLAYER && skop) {
4027  change_exp(op, calc_skill_exp(op, NULL, skop), skop->skill, 0);
4028  }
4029 }
4030 
4039 int stand_near_hostile(object *who) {
4040  int i, friendly = 0, player = 0, mflags;
4041  mapstruct *m;
4042  int16_t x, y;
4043 
4044  if (!who)
4045  return 0;
4046 
4047  if (who->type == PLAYER)
4048  player = 1;
4049  else
4050  friendly = QUERY_FLAG(who, FLAG_FRIENDLY);
4051 
4052  /* search adjacent squares */
4053  for (i = 1; i < 9; i++) {
4054  x = who->x+freearr_x[i];
4055  y = who->y+freearr_y[i];
4056  m = who->map;
4057  mflags = get_map_flags(m, &m, x, y, &x, &y);
4058  /* space must be blocked if there is a monster. If not
4059  * blocked, don't need to check this space.
4060  */
4061  if (mflags&P_OUT_OF_MAP)
4062  continue;
4064  continue;
4065 
4066  FOR_MAP_PREPARE(m, x, y, tmp) {
4067  if ((player || friendly)
4070  return 1;
4071  else if (tmp->type == PLAYER) {
4072  /*don't let a hidden DM prevent you from hiding*/
4073  if (!QUERY_FLAG(tmp, FLAG_WIZ) || tmp->contr->hidden == 0)
4074  return 1;
4075  }
4076  } FOR_MAP_FINISH();
4077  }
4078  return 0;
4079 }
4080 
4107 int player_can_view(object *pl, object *op) {
4108  rv_vector rv;
4109  int dx, dy;
4110 
4111  if (!pl || !op)
4112  return 0;
4113 
4114  if (pl->type != PLAYER) {
4115  LOG(llevError, "player_can_view() called for non-player object\n");
4116  return -1;
4117  }
4118 
4119  op = HEAD(op);
4120  if (!get_rangevector(pl, op, &rv, 0x1))
4121  return 0;
4122 
4123  /* starting with the 'head' part, lets loop
4124  * through the object and find if it has any
4125  * part that is in the los array but isnt on
4126  * a blocked los square.
4127  * we use the archetype to figure out offsets.
4128  */
4129  while (op) {
4130  dx = rv.distance_x+op->arch->clone.x;
4131  dy = rv.distance_y+op->arch->clone.y;
4132 
4133  /* only the viewable area the player sees is updated by LOS
4134  * code, so we need to restrict ourselves to that range of values
4135  * for any meaningful values.
4136  */
4137  if (FABS(dx) <= (pl->contr->socket->mapx/2)
4138  && FABS(dy) <= (pl->contr->socket->mapy/2)
4139  && !pl->contr->blocked_los[dx+(pl->contr->socket->mapx/2)][dy+(pl->contr->socket->mapy/2)])
4140  return 1;
4141  op = op->more;
4142  }
4143  return 0;
4144 }
4145 
4159 static int action_makes_visible(object *op) {
4160  if (op->invisible && QUERY_FLAG(op, FLAG_ALIVE)) {
4162  return 0;
4163 
4164  if (op->contr && op->contr->tmp_invis == 0)
4165  return 0;
4166 
4167  /* If monsters, they should become visible */
4168  if (op->hide || !op->contr || (op->contr && op->contr->tmp_invis)) {
4170  "You become %s!",
4171  op->hide ? "unhidden" : "visible");
4172  return 1;
4173  }
4174  }
4175  return 0;
4176 }
4177 
4206 int op_on_battleground(object *op, int *x, int *y, archetype **trophy) {
4208  if (QUERY_FLAG(tmp, FLAG_IS_FLOOR)) {
4210  && strcmp(tmp->name, "battleground") == 0
4211  && tmp->type == BATTLEGROUND
4212  && EXIT_X(tmp)
4213  && EXIT_Y(tmp)) {
4214  /*before we assign the exit, check if this is a teambattle*/
4215  if (EXIT_ALT_X(tmp) && EXIT_ALT_Y(tmp) && EXIT_PATH(tmp)) {
4216  object *invtmp;
4217 
4219  if (invtmp != NULL) {
4220  if (x != NULL && y != NULL)
4221  *x = EXIT_ALT_X(tmp),
4222  *y = EXIT_ALT_Y(tmp);
4223  return 1;
4224  }
4225  }
4226  if (x != NULL && y != NULL)
4227  *x = EXIT_X(tmp),
4228  *y = EXIT_Y(tmp);
4229 
4230  /* If 'other_arch' is not specified, give a finger. */
4231  if (trophy != NULL) {
4232  if (tmp->other_arch) {
4233  *trophy = tmp->other_arch;
4234  } else {
4235  *trophy = find_archetype("finger");
4236  }
4237  }
4238  return 1;
4239  }
4240  }
4241  } FOR_BELOW_FINISH();
4242  /* If we got here, did not find a battleground */
4243  return 0;
4244 }
4245 
4256 void dragon_ability_gain(object *who, int atnr, int level) {
4257  treasurelist *trlist = NULL; /* treasurelist */
4258  treasure *tr; /* treasure */
4259  object *tmp, *skop; /* tmp. object */
4260  object *item; /* treasure object */
4261  char buf[MAX_BUF]; /* tmp. string buffer */
4262  int i = 0, j = 0;
4263 
4264  /* get the appropriate treasurelist */
4265  if (atnr == ATNR_FIRE)
4266  trlist = find_treasurelist("dragon_ability_fire");
4267  else if (atnr == ATNR_COLD)
4268  trlist = find_treasurelist("dragon_ability_cold");
4269  else if (atnr == ATNR_ELECTRICITY)
4270  trlist = find_treasurelist("dragon_ability_elec");
4271  else if (atnr == ATNR_POISON)
4272  trlist = find_treasurelist("dragon_ability_poison");
4273 
4274  if (trlist == NULL || who->type != PLAYER)
4275  return;
4276 
4277  // tr->magic is being used to define what level of the metabolism the ability is gained at.
4278  for (tr = trlist->items; tr != NULL && tr->magic != level; tr = tr->next)
4279  ;
4280  if (tr == NULL || tr->item == NULL) {
4281  /* LOG(llevDebug, "-> no more treasure for %s\n", change_resist_msg[atnr]); */
4282  return;
4283  }
4284 
4285  /* everything seems okay - now bring on the gift: */
4286  item = &(tr->item->clone);
4287 
4288  if (item->type == SPELL) {
4289  if (check_spell_known(who, item->name))
4290  return;
4291 
4294  "You gained the ability of %s",
4295  item->name);
4296  do_learn_spell(who, item, 0);
4297  return;
4298  }
4299 
4300  /* grant direct spell */
4301  if (item->type == SPELLBOOK) {
4302  if (!item->inv) {
4303  LOG(llevDebug, "dragon_ability_gain: Broken spellbook %s\n", item->name);
4304  return;
4305  }
4306  if (check_spell_known(who, item->inv->name))
4307  return;
4308  if (item->invisible) {
4311  "You gained the ability of %s",
4312  item->inv->name);
4313  do_learn_spell(who, item->inv, 0);
4314  return;
4315  }
4316  } else if (item->type == SKILL_TOOL && item->invisible) {
4317  if (item->subtype == SK_CLAWING && (skop = find_skill_by_name(who, item->skill)) != NULL) {
4318  /* should this perhaps be (skop->attackyp&item->attacktype) != item->attacktype ...
4319  * in this way, if the player is missing any of the attacktypes, he gets
4320  * them. As it is now, if the player has any that match the granted skill,
4321  * but not all of them, he gets nothing.
4322  */
4323  if (!(skop->attacktype&item->attacktype)) {
4324  /* Give new attacktype */
4325  skop->attacktype |= item->attacktype;
4326 
4327  /* always add physical if there's none */
4328  skop->attacktype |= AT_PHYSICAL;
4329 
4330  if (item->msg != NULL)
4333  item->msg);
4334 
4335  /* Give player new face */
4336  if (item->animation) {
4337  who->face = skop->face;
4338  who->animation = item->animation;
4339  who->anim_speed = item->anim_speed;
4340  who->last_anim = 0;
4341  who->state = 0;
4342  animate_object(who, who->direction);
4343  }
4344  }
4345  }
4346  } else if (item->type == FORCE) {
4347  /* forces in the treasurelist can alter the player's stats */
4348  object *skin;
4349 
4350  /* first get the dragon skin force */
4351  skin = object_find_by_arch_name(who, "dragon_skin_force");
4352  if (skin == NULL)
4353  return;
4354 
4355  /* adding new spellpath attunements */
4356  if (item->path_attuned > 0 && !(skin->path_attuned&item->path_attuned)) {
4357  skin->path_attuned |= item->path_attuned; /* add attunement to skin */
4358 
4359  /* print message */
4360  snprintf(buf, sizeof(buf), "You feel attuned to ");
4361  for (i = 0, j = 0; i < NRSPELLPATHS; i++) {
4362  if (item->path_attuned&(1<<i)) {
4363  if (j)
4364  strcat(buf, " and ");
4365  else
4366  j = 1;
4367  strcat(buf, spellpathnames[i]);
4368  }
4369  }
4370  strcat(buf, ".");
4373  buf);
4374  }
4375 
4376  /* evtl. adding flags: */
4377  if (QUERY_FLAG(item, FLAG_XRAYS))
4378  SET_FLAG(skin, FLAG_XRAYS);
4380  SET_FLAG(skin, FLAG_STEALTH);
4382  SET_FLAG(skin, FLAG_SEE_IN_DARK);
4383 
4384  /* print message if there is one */
4385  if (item->msg != NULL)
4388  item->msg);
4389  } else {
4390  /* generate misc. treasure */
4391  char name[HUGE_BUF];
4392 
4393  tmp = arch_to_object(tr->item);
4397  "You gained %s",
4398  name);
4400  if (who->type == PLAYER)
4402  }
4403 }
4404 
4415  int i;
4416 
4417  for (i = 0; i < static_cast<int>(range_size); i++) {
4418  if (pl->ranges[i] == ob) {
4419  pl->ranges[i] = NULL;
4420  if (pl->shoottype == i) {
4421  pl->shoottype = range_none;
4422  }
4423  }
4424  }
4425 }
4426 
4432 void player_set_state(player *pl, uint8_t state) {
4433 
4434  assert(pl);
4435  assert(state <= ST_CHANGE_PASSWORD_CONFIRM);
4436  pl->state = state;
4437 }
4438 
4446  SockList *sl;
4447  assert(pl);
4450  pl->delayed_buffers = static_cast<SockList **>(realloc(pl->delayed_buffers, pl->delayed_buffers_allocated * sizeof(pl->delayed_buffers[0])));
4451  if (!pl->delayed_buffers) {
4452  LOG(llevError, "Unable to allocated %d delayed buffers, aborting\n", pl->delayed_buffers_allocated);
4454  }
4455  for (uint8_t s = pl->delayed_buffers_allocated - 5; s < pl->delayed_buffers_allocated; s++) {
4456  pl->delayed_buffers[s] = static_cast<SockList *>(calloc(1, sizeof(SockList)));
4457  }
4458  }
4461  SockList_Init(sl);
4462  return sl;
4463 }
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
object_value_set
bool object_value_set(const object *op, const char *const key)
Definition: object.cpp:4369
op_on_battleground
int op_on_battleground(object *op, int *x, int *y, archetype **trophy)
Definition: player.cpp:4206
treasurestruct::item
struct archt * item
Definition: treasure.h:64
give.next
def next
Definition: give.py:44
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.cpp:422
apply_changes_to_player
void apply_changes_to_player(object *pl, object *change, int limit_stats)
Definition: apply.cpp:1668
UP_OBJ_FACE
#define UP_OBJ_FACE
Definition: object.h:522
pl::delayed_buffers
SockList ** delayed_buffers
Definition: player.h:225
check_pick
int check_pick(object *op)
Definition: player.cpp:1697
make_visible
void make_visible(object *op)
Definition: player.cpp:3913
PLAYER
@ PLAYER
Definition: object.h:110
PU_BOOTS
#define PU_BOOTS
Definition: define.h:125
object_get_owner
object * object_get_owner(object *op)
Definition: object.cpp:804
kill_player_permadeath
static void kill_player_permadeath(object *op)
Definition: player.cpp:3761
SockList_AddInt
void SockList_AddInt(SockList *sl, uint32_t data)
Definition: lowlevel.cpp:124
global.h
FLAG_NEUTRAL
#define FLAG_NEUTRAL
Definition: define.h:354
UPD_FACE
#define UPD_FACE
Definition: newclient.h:317
object_find_by_type_subtype
object * object_find_by_type_subtype(const object *who, int type, int subtype)
Definition: object.cpp:4294
first_player
player * first_player
Definition: init.cpp:106
settings
struct Settings settings
Definition: init.cpp:139
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_update_turn_face
void object_update_turn_face(object *op)
Definition: object.cpp:1332
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:54
pets_terminate_all
void pets_terminate_all(object *owner)
Definition: pets.cpp:225
face_player
int face_player(object *op, int dir)
Definition: player.cpp:2995
options
static struct Command_Line_Options options[]
Definition: init.cpp:379
obj::face
const Face * face
Definition: object.h:339
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:121
player_fire_bow
static int player_fire_bow(object *op, int dir)
Definition: player.cpp:2278
Settings::emergency_y
uint16_t emergency_y
Definition: global.h:300
kill_player
void kill_player(object *op, const object *killer)
Definition: player.cpp:3456
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.cpp:2331
WAND
@ WAND
Definition: object.h:223
range_bow
@ range_bow
Definition: player.h:31
get_player_archetype
static archetype * get_player_archetype(archetype *at)
Definition: player.cpp:495
MSG_TYPE_ADMIN_PLAYER
#define MSG_TYPE_ADMIN_PLAYER
Definition: newclient.h:496
LOG
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.cpp:51
FLAG_UNDEAD
#define FLAG_UNDEAD
Definition: define.h:270
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:224
FLESH
@ FLESH
Definition: object.h:190
monster_can_detect_enemy
int monster_can_detect_enemy(object *op, object *enemy, rv_vector *rv)
Definition: monster.cpp:2579
PU_ARROW
#define PU_ARROW
Definition: define.h:120
PU_NOT_CURSED
#define PU_NOT_CURSED
Definition: define.h:140
path_to_player
int path_to_player(object *mon, object *pl, unsigned mindiff)
Definition: player.cpp:631
esrv_map_scroll
void esrv_map_scroll(socket_struct *ns, int dx, int dy)
Definition: request.cpp:1614
blocked_link
int blocked_link(object *ob, mapstruct *m, int16_t sx, int16_t sy)
Definition: map.cpp:345
strdup_local
#define strdup_local
Definition: compat.h:29
Settings::resurrection
uint8_t resurrection
Definition: global.h:266
recursive_roll
void recursive_roll(object *op, int dir, object *pusher)
Definition: move.cpp:293
socket_struct::look_position
uint16_t look_position
Definition: newserver.h:114
safe_strcat
void safe_strcat(char *dest, const char *orig, size_t *curlen, size_t maxlen)
Definition: porting.cpp:202
diamondslots.x
x
Definition: diamondslots.py:15
FLAG_STARTEQUIP
#define FLAG_STARTEQUIP
Definition: define.h:268
obj::count
tag_t count
Definition: object.h:305
obj::map
struct mapdef * map
Definition: object.h:303
first_map_path
char first_map_path[MAX_BUF]
Definition: init.cpp:120
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:324
get_next_archetype
archetype * get_next_archetype(archetype *current)
Definition: assets.cpp:266
Settings::set_title
uint8_t set_title
Definition: global.h:265
remove_locked_door
void remove_locked_door(object *op)
Definition: time.cpp:64
pl::peaceful
uint32_t peaceful
Definition: player.h:146
spellpathnames
const char *const spellpathnames[NRSPELLPATHS]
Definition: init.cpp:239
SK_CLAWING
@ SK_CLAWING
Definition: skills.h:50
ARCH_DEPLETION
#define ARCH_DEPLETION
Definition: object.h:579
NDI_GREEN
#define NDI_GREEN
Definition: newclient.h:249
liv::wc
int8_t wc
Definition: living.h:37
KEY
@ KEY
Definition: object.h:130
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.cpp:484
socket_struct
Definition: newserver.h:89
socket_struct::mapx
uint8_t mapx
Definition: newserver.h:116
ST_GET_NAME
#define ST_GET_NAME
Definition: define.h:546
first_map_ext_path
char first_map_ext_path[MAX_BUF]
Definition: init.cpp:121
esrv_new_player
void esrv_new_player(player *pl, uint32_t weight)
Definition: request.cpp:943
FLAG_SEE_IN_DARK
#define FLAG_SEE_IN_DARK
Definition: define.h:337
Settings::not_permadeth
uint8_t not_permadeth
Definition: global.h:262
price_base
uint64_t price_base(const object *obj)
Definition: shop.cpp:75
player_get_delayed_buffer
SockList * player_get_delayed_buffer(player *pl)
Definition: player.cpp:4445
get_friends_of
objectlink * get_friends_of(const object *owner)
Definition: friend.cpp:119
esrv_send_inventory
void esrv_send_inventory(object *pl, object *op)
Definition: item.cpp:316
roll_again
void roll_again(object *op)
Definition: player.cpp:1121
find_player_socket
player * find_player_socket(const socket_struct *ns)
Definition: player.cpp:121
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.cpp:1420
find_better_arrow
static object * find_better_arrow(object *op, object *target, const char *type, int *better)
Definition: player.cpp:1934
disinfect.a
a
Definition: disinfect.py:13
absdir
int absdir(int d)
Definition: object.cpp:3707
obj::path_attuned
uint32_t path_attuned
Definition: object.h:351
SockList_AddString
void SockList_AddString(SockList *sl, const char *data)
Definition: lowlevel.cpp:154
FOR_BELOW_PREPARE
#define FOR_BELOW_PREPARE(op_, it_)
Definition: define.h:704
object_set_enemy
void object_set_enemy(object *op, object *enemy)
Definition: object.cpp:915
GEM
@ GEM
Definition: object.h:170
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:244
pl::blocked_los
int8_t blocked_los[MAP_CLIENT_X][MAP_CLIENT_Y]
Definition: player.h:177
turn_transport
static int turn_transport(object *transport, object *captain, int dir)
Definition: player.cpp:2883
spring_trap
void spring_trap(object *trap, object *victim)
Definition: rune.cpp:205
get_nearest_player
object * get_nearest_player(object *mon)
Definition: player.cpp:520
guildoracle.list
list
Definition: guildoracle.py:87
apply_map_builder
void apply_map_builder(object *pl, int dir)
Definition: build_map.cpp:960
PREFER_LOW
#define PREFER_LOW
Definition: define.h:564
PU_FOOD
#define PU_FOOD
Definition: define.h:115
pl::swap_first
int swap_first
Definition: player.h:165
arch_present_in_ob
object * arch_present_in_ob(const archetype *at, const object *op)
Definition: object.cpp:3215
object_set_owner
void object_set_owner(object *op, object *owner)
Definition: object.cpp:840
esrv_send_pickup
void esrv_send_pickup(player *pl)
Definition: request.cpp:1741
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
fix_weight
void fix_weight(void)
Definition: player.cpp:3847
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
SET_ANIMATION
#define SET_ANIMATION(ob, newanim)
Definition: global.h:162
CHARISMA
@ CHARISMA
Definition: living.h:15
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,...) PRINTF_ARGS(6
party_rejoin_if_exists
@ party_rejoin_if_exists
Definition: player.h:100
mon
object * mon
Definition: comet_perf.cpp:75
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.cpp:51
bow_threewide
@ bow_threewide
Definition: player.h:43
allowed_class
int allowed_class(const object *op)
Definition: living.cpp:1650
SKILL
@ SKILL
Definition: object.h:146
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.cpp:113
RUNE
@ RUNE
Definition: object.h:243
object_copy
void object_copy(const object *src_ob, object *dest_ob)
Definition: object.cpp:1192
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:323
find_treasurelist
treasurelist * find_treasurelist(const char *name)
Definition: assets.cpp:253
fix_object
void fix_object(object *op)
Definition: living.cpp:1125
object_find_by_flag_applied
object * object_find_by_flag_applied(const object *who, int flag)
Definition: object.cpp:4222
Ice.tmp
int tmp
Definition: Ice.py:207
PU_MISSILEWEAPON
#define PU_MISSILEWEAPON
Definition: define.h:130
player_can_view
int player_can_view(object *pl, object *op)
Definition: player.cpp:4107
confirm_password
void confirm_password(object *op)
Definition: player.cpp:986
NDI_NAVY
#define NDI_NAVY
Definition: newclient.h:244
Settings::emergency_x
uint16_t emergency_x
Definition: global.h:300
player_set_own_title
void player_set_own_title(struct pl *pl, const char *title)
Definition: player.cpp:272
get_name
void get_name(object *op)
Definition: player.cpp:861
TRANSPORT
@ TRANSPORT
Definition: object.h:111
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
NROFATTACKS
#define NROFATTACKS
Definition: attack.h:17
obj::msg
sstring msg
Definition: object.h:328
PU_READABLES
#define PU_READABLES
Definition: define.h:137
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.cpp:1982
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
esrv_add_spells
void esrv_add_spells(player *pl, object *spell)
Definition: request.cpp:1855
range_golem
@ range_golem
Definition: player.h:34
pl::last_weapon_sp
float last_weapon_sp
Definition: player.h:156
FLAG_INV_LOCKED
#define FLAG_INV_LOCKED
Definition: define.h:329
apply_manual
int apply_manual(object *op, object *tmp, int aflag)
Definition: apply.cpp:597
create_treasure
void create_treasure(treasurelist *t, object *op, int flag, int difficulty, int tries)
Definition: treasure.cpp:256
P_IS_ALIVE
#define P_IS_ALIVE
Definition: map.h:238
MSG_TYPE_MISC
#define MSG_TYPE_MISC
Definition: newclient.h:413
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
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:292
BALSL_MAX_LOSS_RATIO
#define BALSL_MAX_LOSS_RATIO
Definition: config.h:144
pticks
uint32_t pticks
Definition: time.cpp:47
GT_STARTEQUIP
@ GT_STARTEQUIP
Definition: treasure.h:33
pl::last_speed
float last_speed
Definition: player.h:172
buf
StringBuffer * buf
Definition: readable.cpp:1611
Moving_Fog.z
z
Definition: Moving_Fog.py:17
hiscore_check
void hiscore_check(object *op, int quiet)
Definition: hiscore.cpp:348
object_insert_in_ob
object * object_insert_in_ob(object *op, object *where)
Definition: object.cpp:2851
HUGE_BUF
#define HUGE_BUF
Definition: define.h:37
treasurestruct
Definition: treasure.h:63
MSG_TYPE_VICTIM
#define MSG_TYPE_VICTIM
Definition: newclient.h:415
MSG_TYPE_COMMAND
#define MSG_TYPE_COMMAND
Definition: newclient.h:404
MAX
#define MAX(x, y)
Definition: compat.h:24
handle_newcs_player
int handle_newcs_player(object *op)
Definition: player.cpp:3054
WISDOM
@ WISDOM
Definition: living.h:14
AT_DEATH
#define AT_DEATH
Definition: attack.h:93
obj::nrof
uint32_t nrof
Definition: object.h:340
FLAG_NO_PICK
#define FLAG_NO_PICK
Definition: define.h:239
MSG_TYPE_SPELL_END
#define MSG_TYPE_SPELL_END
Definition: newclient.h:634
lose_msg
const char *const lose_msg[NUM_STATS]
Definition: living.cpp:172
player_set_state
void player_set_state(player *pl, uint8_t state)
Definition: player.cpp:4432
FOR_BELOW_FINISH
#define FOR_BELOW_FINISH()
Definition: define.h:711
MIN_STAT
#define MIN_STAT
Definition: define.h:33
archt
Definition: object.h:472
FLAG_ALIVE
#define FLAG_ALIVE
Definition: define.h:230
add_statbonus
void add_statbonus(object *op)
Definition: living.cpp:868
MSG_TYPE_MOTD
#define MSG_TYPE_MOTD
Definition: newclient.h:401
range_builder
@ range_builder
Definition: player.h:36
esrv_send_item
void esrv_send_item(object *pl, object *op)
Definition: main.cpp:354
socket_struct::update_look
uint32_t update_look
Definition: newserver.h:104
rv_vector::distance_y
int distance_y
Definition: map.h:376
short_stat_name
const char *const short_stat_name[NUM_STATS]
Definition: living.cpp:194
MSG_TYPE_COMMAND_DEBUG
#define MSG_TYPE_COMMAND_DEBUG
Definition: newclient.h:528
obj::slaying
sstring slaying
Definition: object.h:325
AP_NULL
#define AP_NULL
Definition: define.h:573
PU_GLOVES
#define PU_GLOVES
Definition: define.h:126
set_player_socket
void set_player_socket(player *p, socket_struct *ns)
Definition: player.cpp:405
remove_door
void remove_door(object *op)
Definition: time.cpp:38
PU_CONTAINER
#define PU_CONTAINER
Definition: define.h:143
m
static event_registration m
Definition: citylife.cpp:425
liv::luck
int8_t luck
Definition: living.h:39
clear_los
void clear_los(player *pl)
Definition: los.cpp:252
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
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
liv::exp
int64_t exp
Definition: living.h:47
Ns_Avail
@ Ns_Avail
Definition: newserver.h:65
object_free_drop_inventory
void object_free_drop_inventory(object *ob)
Definition: object.cpp:1560
turn_one_transport
static int turn_one_transport(object *transport, object *captain, int dir)
Definition: player.cpp:2813
object_update
void object_update(object *op, int action)
Definition: object.cpp:1434
get_party_password
int get_party_password(object *op, partylist *party)
Definition: player.cpp:1001
pl::next
struct pl * next
Definition: player.h:106
player_unready_range_ob
void player_unready_range_ob(player *pl, object *ob)
Definition: player.cpp:4414
PREFER_HIGH
#define PREFER_HIGH
Definition: define.h:563
EVENT_LOGIN
#define EVENT_LOGIN
Definition: events.h:44
disinfect.map
map
Definition: disinfect.py:4
object_decrease_nrof_by_one
#define object_decrease_nrof_by_one(xyz)
Definition: compat.h:32
MAX_SPACES
#define MAX_SPACES
Definition: player.cpp:598
POISON
@ POISON
Definition: object.h:116
PU_RATIO
#define PU_RATIO
Definition: define.h:113
Settings::balanced_stat_loss
uint8_t balanced_stat_loss
Definition: global.h:261
BALSL_NUMBER_LOSSES_RATIO
#define BALSL_NUMBER_LOSSES_RATIO
Definition: config.h:143
flee_player
static void flee_player(object *op)
Definition: player.cpp:1638
oblnk::next
struct oblnk * next
Definition: object.h:451
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
bow_n
@ bow_n
Definition: player.h:45
is_criminal
bool is_criminal(object *op)
Definition: player.cpp:312
obj::name
sstring name
Definition: object.h:317
add_refcount
sstring add_refcount(sstring str)
Definition: shstr.cpp:210
check_race_and_class
int check_race_and_class(living *stats, archetype *race, archetype *opclass)
Definition: player.cpp:1409
enter_player_savebed
void enter_player_savebed(object *op)
Definition: server.cpp:138
PU_KEY
#define PU_KEY
Definition: define.h:128
determine_god
const char * determine_god(object *op)
Definition: gods.cpp:55
MSG_TYPE_ATTRIBUTE_RACE
#define MSG_TYPE_ATTRIBUTE_RACE
Definition: newclient.h:564
pl::state
uint8_t state
Definition: player.h:131
freearr_y
short freearr_y[SIZEOFFREE]
Definition: object.cpp:305
bow_bestarrow
@ bow_bestarrow
Definition: player.h:53
ST_CHANGE_PASSWORD_CONFIRM
#define ST_CHANGE_PASSWORD_CONFIRM
Definition: define.h:552
range_size
@ range_size
Definition: player.h:37
move_ob
int move_ob(object *op, int dir, object *originator)
Definition: move.cpp:58
MSG_TYPE_APPLY_SUCCESS
#define MSG_TYPE_APPLY_SUCCESS
Definition: newclient.h:603
query_name
void query_name(const object *op, char *buf, size_t size)
Definition: item.cpp:585
treasurestruct::magic
uint8_t magic
Definition: treasure.h:74
pl::unarmed_skill
const char * unarmed_skill
Definition: player.h:220
POTION
@ POTION
Definition: object.h:114
find_player_options
player * find_player_options(const char *plname, int options, const mapstruct *map)
Definition: player.cpp:68
do_hidden_move
void do_hidden_move(object *op)
Definition: player.cpp:3998
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
pick_arrow_target
static object * pick_arrow_target(object *op, const char *type, int dir)
Definition: player.cpp:2004
ST_PLAY_AGAIN
#define ST_PLAY_AGAIN
Definition: define.h:542
action_makes_visible
static int action_makes_visible(object *op)
Definition: player.cpp:4159
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.cpp:658
account_char_free
void account_char_free(Account_Chars *chars)
Definition: account_char.cpp:374
pl::petmode
petmode_t petmode
Definition: player.h:115
fire_misc_object
static void fire_misc_object(object *op, int dir)
Definition: player.cpp:2314
loot_object
static void loot_object(object *op)
Definition: player.cpp:3379
party_leave
void party_leave(object *op)
Definition: party.cpp:123
add_string
sstring add_string(const char *str)
Definition: shstr.cpp:124
account_remove_player
int account_remove_player(const char *account_name, const char *player_name)
Definition: account.cpp:493
apply_anim_suffix
void apply_anim_suffix(object *who, const char *suffix)
Definition: anim.cpp:150
first_map
mapstruct * first_map
Definition: init.cpp:107
FOR_OB_AND_BELOW_FINISH
#define FOR_OB_AND_BELOW_FINISH()
Definition: define.h:754
object_get_multi_size
void object_get_multi_size(const object *ob, int *sx, int *sy, int *hx, int *hy)
Definition: object.cpp:4737
HEAD
#define HEAD(op)
Definition: object.h:596
range_magic
@ range_magic
Definition: player.h:32
apply_container
int apply_container(object *op, object *sack, int aflags)
Definition: apply.cpp:222
similar_direction
static int similar_direction(int a, int b)
Definition: player.cpp:2244
ROD
@ ROD
Definition: object.h:112
CONTAINER
@ CONTAINER
Definition: object.h:234
enter_player_maplevel
void enter_player_maplevel(object *op)
Definition: server.cpp:687
obj::speed_left
float speed_left
Definition: object.h:336
query_short_name
void query_short_name(const object *op, char *buf, size_t size)
Definition: item.cpp:510
SockList_AddChar
void SockList_AddChar(SockList *sl, unsigned char c)
Definition: lowlevel.cpp:103
PU_STOP
#define PU_STOP
Definition: define.h:110
PU_VALUABLES
#define PU_VALUABLES
Definition: define.h:117
set_attr_value
void set_attr_value(living *stats, int attr, int8_t value)
Definition: living.cpp:218
FLAG_FREED
#define FLAG_FREED
Definition: define.h:233
delete_character
void delete_character(const char *name)
Definition: login.cpp:88
Settings::motd
char motd[MAX_BUF]
Definition: global.h:278
LOCKED_DOOR
@ LOCKED_DOOR
Definition: object.h:126
MSG_TYPE_ITEM
#define MSG_TYPE_ITEM
Definition: newclient.h:412
out_of_map
int out_of_map(mapstruct *m, int x, int y)
Definition: map.cpp:2320
socket_struct::host
char * host
Definition: newserver.h:100
SCRIPT_FIX_ALL
#define SCRIPT_FIX_ALL
Definition: global.h:382
MSG_TYPE_ATTACK
#define MSG_TYPE_ATTACK
Definition: newclient.h:409
FLAG_MAKE_INVIS
#define FLAG_MAKE_INVIS
Definition: define.h:328
Settings::rules
const char * rules
Definition: global.h:279
SPECIAL_KEY
@ SPECIAL_KEY
Definition: object.h:127
MOVE_FLYING
#define MOVE_FLYING
Definition: define.h:395
obj::spellarg
char * spellarg
Definition: object.h:417
socket_struct::account_name
char * account_name
Definition: newserver.h:126
has_carried_lights
int has_carried_lights(const object *op)
Definition: los.cpp:315
POWER
@ POWER
Definition: living.h:17
object_update_speed
void object_update_speed(object *op)
Definition: object.cpp:1349
SPELL_HIGHEST
#define SPELL_HIGHEST
Definition: spells.h:60
obj::carrying
int32_t carrying
Definition: object.h:375
FREE_AND_COPY
#define FREE_AND_COPY(sv, nv)
Definition: global.h:204
Settings::news
const char * news
Definition: global.h:280
Ice.b
b
Definition: Ice.py:48
pl::no_shout
uint32_t no_shout
Definition: player.h:148
EVENT_BORN
#define EVENT_BORN
Definition: events.h:39
guild_questpoints_apply.mapname
mapname
Definition: guild_questpoints_apply.py:8
obj::x
int16_t x
Definition: object.h:333
FLAG_DAMNED
#define FLAG_DAMNED
Definition: define.h:317
do_some_living
void do_some_living(object *op)
Definition: player.cpp:3240
FLAG_PARALYZED
#define FLAG_PARALYZED
Definition: define.h:371
Settings::stat_loss_on_death
uint8_t stat_loss_on_death
Definition: global.h:256
CFweardisguise.tag
tag
Definition: CFweardisguise.py:25
gravestone_text
static const char * gravestone_text(object *op, char *buf2, int len)
Definition: player.cpp:3205
FLAG_USE_SHIELD
#define FLAG_USE_SHIELD
Definition: define.h:237
hideability
int hideability(object *ob)
Definition: player.cpp:3957
leave
void leave(player *pl, int draw_exit)
Definition: server.cpp:1302
object_free
void object_free(object *ob, int flags)
Definition: object.cpp:1592
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
find_player
player * find_player(const char *plname)
Definition: player.cpp:57
FLAG_CAN_ROLL
#define FLAG_CAN_ROLL
Definition: define.h:254
find_arrow
static object * find_arrow(object *op, const char *type)
Definition: player.cpp:1902
pl::has_hit
uint32_t has_hit
Definition: player.h:144
kill_player_not_permadeath
static void kill_player_not_permadeath(object *op)
Definition: player.cpp:3537
PU_SPELLBOOK
#define PU_SPELLBOOK
Definition: define.h:135
change_exp
void change_exp(object *op, int64_t exp, const char *skill_name, int flag)
Definition: living.cpp:2166
FLAG_UNAGGRESSIVE
#define FLAG_UNAGGRESSIVE
Definition: define.h:272
obj::speed
float speed
Definition: object.h:335
say.max
dictionary max
Definition: say.py:148
tag_t
uint32_t tag_t
Definition: object.h:12
display_motd
void display_motd(const object *op)
Definition: player.cpp:137
object_matches_string
int object_matches_string(object *pl, object *op, const char *name)
Definition: object.cpp:4567
PU_MELEEWEAPON
#define PU_MELEEWEAPON
Definition: define.h:131
ATNR_POISON
#define ATNR_POISON
Definition: attack.h:59
Settings::confdir
const char * confdir
Definition: global.h:247
FLAG_USE_WEAPON
#define FLAG_USE_WEAPON
Definition: define.h:296
sproto.h
drain_msg
const char *const drain_msg[NUM_STATS]
Definition: living.cpp:139
ARROW
@ ARROW
Definition: object.h:120
FLAG_NO_DROP
#define FLAG_NO_DROP
Definition: define.h:288
IS_SHIELD
#define IS_SHIELD(op)
Definition: define.h:170
MAX_SKILLS
#define MAX_SKILLS
Definition: skills.h:70
FIND_PLAYER_PARTIAL_NAME
#define FIND_PLAYER_PARTIAL_NAME
Definition: player.h:234
get_map_from_coord
mapstruct * get_map_from_coord(mapstruct *m, int16_t *x, int16_t *y)
Definition: map.cpp:2393
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
DETOUR_AMOUNT
#define DETOUR_AMOUNT
Definition: player.cpp:583
obj::enemy
struct obj * enemy
Definition: object.h:389
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.cpp:235
delete_map
void delete_map(mapstruct *m)
Definition: map.cpp:1730
random_roll
int random_roll(int min, int max, const object *op, int goodbad)
Definition: utils.cpp:42
MSG_SUBTYPE_NONE
#define MSG_SUBTYPE_NONE
Definition: newclient.h:420
get_dam_bonus
int get_dam_bonus(int stat)
Definition: living.cpp:2376
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.cpp:52
PU_HELMET
#define PU_HELMET
Definition: define.h:121
ob_blocked
int ob_blocked(const object *ob, mapstruct *m, int16_t x, int16_t y)
Definition: map.cpp:488
nlohmann::detail::void
j template void())
Definition: json.hpp:4099
receive_play_again
void receive_play_again(object *op, char key)
Definition: player.cpp:936
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.cpp:3997
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.cpp:2098
FLAG_MONSTER
#define FLAG_MONSTER
Definition: define.h:245
party_struct
Definition: party.h:10
fire
void fire(object *op, int dir)
Definition: player.cpp:2366
push_ob
int push_ob(object *who, int dir, object *pusher)
Definition: move.cpp:434
key_inventory
@ key_inventory
Definition: player.h:66
fatal
void fatal(enum fatal_error err)
Definition: utils.cpp:580
find_skill_by_name
object * find_skill_by_name(object *who, const char *name)
Definition: skill_util.cpp:202
pl::listening
uint8_t listening
Definition: player.h:133
apply_death_exp_penalty
void apply_death_exp_penalty(object *op)
Definition: living.cpp:2231
get_dex_bonus
int get_dex_bonus(int stat)
Definition: living.cpp:2352
P_OUT_OF_MAP
#define P_OUT_OF_MAP
Definition: map.h:250
move_player_attack
void move_player_attack(object *op, int dir)
Definition: player.cpp:2591
env
static std::shared_ptr< inja::Environment > env
Definition: mapper.cpp:2226
EXIT_X
#define EXIT_X(xyz)
Definition: define.h:441
MAX_BUF
#define MAX_BUF
Definition: define.h:35
Ns_Add
@ Ns_Add
Definition: newserver.h:66
strlcpy
size_t strlcpy(char *dst, const char *src, size_t size)
Definition: porting.cpp:222
object_new
object * object_new(void)
Definition: object.cpp:1273
is_wraith_pl
int is_wraith_pl(object *op)
Definition: player.cpp:173
ADD_PLAYER_NEW
#define ADD_PLAYER_NEW
Definition: player.h:244
create_archetype
object * create_archetype(const char *name)
Definition: arch.cpp:279
IS_WEAPON
#define IS_WEAPON(op)
Definition: define.h:163
pl::last_weight
int32_t last_weight
Definition: player.h:158
bow_normal
@ bow_normal
Definition: player.h:42
cast_dust
void cast_dust(object *op, object *throw_ob, int dir)
Definition: player.cpp:3884
free_string
void free_string(sstring str)
Definition: shstr.cpp:280
transfer_ob
int transfer_ob(object *op, int x, int y, int randomly, object *originator)
Definition: move.cpp:163
set_first_map
void set_first_map(object *op)
Definition: player.cpp:386
key_confirm_quit
void key_confirm_quit(object *op, char key)
Definition: player.cpp:1572
offsetof
#define offsetof(type, member)
Definition: shstr.h:37
remove_unpaid_objects
void remove_unpaid_objects(object *op, object *env, int free_items)
Definition: player.cpp:3175
Settings::playerdir
const char * playerdir
Definition: global.h:250
RANDOM
#define RANDOM()
Definition: define.h:644
SockList_Term
void SockList_Term(SockList *sl)
Definition: lowlevel.cpp:62
SK_HIDING
@ SK_HIDING
Definition: skills.h:21
FREE_AND_CLEAR_STR
#define FREE_AND_CLEAR_STR(xyz)
Definition: global.h:198
MOVE_FLY_LOW
#define MOVE_FLY_LOW
Definition: define.h:393
EVENT_PLAYER_DEATH
#define EVENT_PLAYER_DEATH
Definition: events.h:53
dead_player
void dead_player(object *op)
Definition: resurrection.cpp:297
ATNR_FIRE
#define ATNR_FIRE
Definition: attack.h:51
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:333
key_change_class
void key_change_class(object *op, char key)
Definition: player.cpp:1269
FLAG_KNOWN_MAGICAL
#define FLAG_KNOWN_MAGICAL
Definition: define.h:319
stand_near_hostile
int stand_near_hostile(object *who)
Definition: player.cpp:4039
FIND_PLAYER_NO_HIDDEN_DM
#define FIND_PLAYER_NO_HIDDEN_DM
Definition: player.h:235
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
obj::arch
struct archt * arch
Definition: object.h:420
roll_stat
int roll_stat(void)
Definition: player.cpp:1018
treasureliststruct::items
struct treasurestruct * items
Definition: treasure.h:92
get_nearest_criminal
object * get_nearest_criminal(object *mon)
Definition: player.cpp:563
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
object_find_by_type_and_slaying
object * object_find_by_type_and_slaying(const object *who, int type, const char *slaying)
Definition: object.cpp:4151
FLAG_WIZ
#define FLAG_WIZ
Definition: define.h:231
Settings::emergency_mapname
char * emergency_mapname
Definition: global.h:299
obj::type
uint8_t type
Definition: object.h:346
NDI_UNIQUE
#define NDI_UNIQUE
Definition: newclient.h:262
roll-o-matic.stop
def stop()
Definition: roll-o-matic.py:78
FLAG_FRIENDLY
#define FLAG_FRIENDLY
Definition: define.h:246
spells.h
EVENT_DEATH
#define EVENT_DEATH
Definition: events.h:25
ob_process
method_ret ob_process(object *op)
Definition: ob_methods.cpp:67
obj::stats
living stats
Definition: object.h:376
PU_CLOAK
#define PU_CLOAK
Definition: define.h:127
bow_spreadshot
@ bow_spreadshot
Definition: player.h:44
BATTLEGROUND
@ BATTLEGROUND
Definition: object.h:166
MSG_TYPE_SKILL_FAILURE
#define MSG_TYPE_SKILL_FAILURE
Definition: newclient.h:590
obj::direction
int8_t direction
Definition: object.h:342
object_find_by_arch_name
object * object_find_by_arch_name(const object *who, const char *name)
Definition: object.cpp:4245
archt::clone
object clone
Definition: object.h:476
pl::language
int language
Definition: player.h:219
party_get_password
const char * party_get_password(const partylist *party)
Definition: party.cpp:232
get_thaco_bonus
int get_thaco_bonus(int stat)
Definition: living.cpp:2356
obj::contr
struct pl * contr
Definition: object.h:282
obj::facing
int8_t facing
Definition: object.h:343
pl::gen_sp_armour
int16_t gen_sp_armour
Definition: player.h:128
object_can_pick
int object_can_pick(const object *who, const object *item)
Definition: object.cpp:3860
add_friendly_object
void add_friendly_object(object *op)
Definition: friend.cpp:34
key_roll_stat
void key_roll_stat(object *op, char key)
Definition: player.cpp:1193
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
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.cpp:301
object_find_by_type
object * object_find_by_type(const object *who, int type)
Definition: object.cpp:3973
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
pl::last_skill_exp
int64_t last_skill_exp[MAX_SKILLS]
Definition: player.h:154
is_identifiable_type
int is_identifiable_type(const object *op)
Definition: item.cpp:1312
change_attr_value
void change_attr_value(living *stats, int attr, int8_t value)
Definition: living.cpp:264
enter_exit
void enter_exit(object *op, object *exit_ob)
Definition: server.cpp:732
check_spell_known
object * check_spell_known(object *op, const char *name)
Definition: spell_util.cpp:393
pl::delayed_buffers_allocated
uint8_t delayed_buffers_allocated
Definition: player.h:223
liv::grace
int16_t grace
Definition: living.h:44
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
fire_bow
int fire_bow(object *op, object *arrow, int dir, int wc_mod, int16_t sx, int16_t sy)
Definition: player.cpp:2073
save_life
static int save_life(object *op)
Definition: player.cpp:3132
STRENGTH
@ STRENGTH
Definition: living.h:11
animate_object
void animate_object(object *op, int dir)
Definition: anim.cpp:44
pl::do_los
uint32_t do_los
Definition: player.h:141
find_archetype
archetype * find_archetype(const char *name)
Definition: assets.cpp:270
pl::last_skill_ob
object * last_skill_ob[MAX_SKILLS]
Definition: player.h:153
shop.h
object_split
object * object_split(object *orig_ob, uint32_t nr, char *err, size_t size)
Definition: object.cpp:2631
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
dragon_ability_gain
void dragon_ability_gain(object *who, int atnr, int level)
Definition: player.cpp:4256
change_luck
void change_luck(object *op, int value)
Definition: living.cpp:796
restore_player
static void restore_player(object *op)
Definition: player.cpp:3418
PU_ARMOUR
#define PU_ARMOUR
Definition: define.h:123
object_set_msg
void object_set_msg(object *op, const char *msg)
Definition: object.cpp:4804
esrv_update_item
void esrv_update_item(int flags, object *pl, object *op)
Definition: main.cpp:359
did_make_save
int did_make_save(const object *op, int level, int bonus)
Definition: living.cpp:2280
send_rules
void send_rules(const object *op)
Definition: player.cpp:168
Settings::max_stat
uint8_t max_stat
Definition: global.h:324
SPELL_EFFECT
@ SPELL_EFFECT
Definition: object.h:218
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:192
send_news
void send_news(const object *op)
Definition: player.cpp:204
pl::rejoin_party
party_rejoin_mode rejoin_party
Definition: player.h:209
EXIT_Y
#define EXIT_Y(xyz)
Definition: define.h:442
get_randomized_dir
int get_randomized_dir(int dir)
Definition: utils.cpp:422
diamondslots.y
y
Definition: diamondslots.py:16
oblnk::ob
object * ob
Definition: object.h:450
FLAG_BEEN_APPLIED
#define FLAG_BEEN_APPLIED
Definition: define.h:323
CLEAR_FLAG
#define CLEAR_FLAG(xyz, p)
Definition: define.h:225
NDI_BROWN
#define NDI_BROWN
Definition: newclient.h:253
AP_NOPRINT
#define AP_NOPRINT
Definition: define.h:585
pl::hidden
uint32_t hidden
Definition: player.h:147
EVENT_REMOVE
#define EVENT_REMOVE
Definition: events.h:54
pl::last_stats
living last_stats
Definition: player.h:167
SockList_ResetRead
void SockList_ResetRead(SockList *sl)
Definition: lowlevel.cpp:80
guild_entry.x1
int x1
Definition: guild_entry.py:33
NDI_DK_ORANGE
#define NDI_DK_ORANGE
Definition: newclient.h:248
strip_endline
void strip_endline(char *buf)
Definition: utils.cpp:324
obj::more
struct obj * more
Definition: object.h:301
die_roll
int die_roll(int num, int size, const object *op, int goodbad)
Definition: utils.cpp:122
socket_struct::faces_sent
uint8_t * faces_sent
Definition: newserver.h:96
get_password
void get_password(object *op)
Definition: player.cpp:872
obj::move_type
MoveType move_type
Definition: object.h:432
arch_to_object
object * arch_to_object(archetype *at)
Definition: arch.cpp:230
level
int level
Definition: readable.cpp:1609
get_rangevector
int get_rangevector(object *op1, const object *op2, rv_vector *retval, int flags)
Definition: map.cpp:2553
pl::ranges
object * ranges[range_size]
Definition: player.h:116
keyrings
@ keyrings
Definition: player.h:67
castle_read.key
key
Definition: castle_read.py:64
play_again
void play_again(object *op)
Definition: player.cpp:883
get_player
player * get_player(player *p)
Definition: player.cpp:283
MSG_TYPE_ADMIN_LOGIN
#define MSG_TYPE_ADMIN_LOGIN
Definition: newclient.h:500
FLAG_ANIMATE
#define FLAG_ANIMATE
Definition: define.h:242
MSG_TYPE_ATTRIBUTE_BAD_EFFECT_END
#define MSG_TYPE_ATTRIBUTE_BAD_EFFECT_END
Definition: newclient.h:567
obj::skill
sstring skill
Definition: object.h:327
treasurestruct::next
struct treasurestruct * next
Definition: treasure.h:69
newclient.h
fix_luck
void fix_luck(void)
Definition: player.cpp:3863
save_player
int save_player(object *op, int flag)
Definition: login.cpp:230
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.cpp:308
object_matches_pickup_mode
int object_matches_pickup_mode(const object *item, int mode)
Definition: c_object.cpp:656
FOOD
@ FOOD
Definition: object.h:115
pl::ticks_played
uint32_t ticks_played
Definition: player.h:221
object_remove
void object_remove(object *op)
Definition: object.cpp:1833
cure_disease
int cure_disease(object *sufferer, object *caster, sstring skill)
Definition: disease.cpp:685
DOOR
@ DOOR
Definition: object.h:129
object_sum_weight
signed long object_sum_weight(object *op)
Definition: object.cpp:568
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
PU_NOTHING
#define PU_NOTHING
Definition: define.h:106
OB_TYPE_MOVE_BLOCK
#define OB_TYPE_MOVE_BLOCK(ob1, type)
Definition: define.h:432
move_player
int move_player(object *op, int dir)
Definition: player.cpp:2916
socket_struct::login_method
uint8_t login_method
Definition: newserver.h:128
remove_statbonus
void remove_statbonus(object *op)
Definition: living.cpp:845
MSG_TYPE_ATTACK_NOATTACK
#define MSG_TYPE_ATTACK_NOATTACK
Definition: newclient.h:618
make_path_to_file
void make_path_to_file(const char *filename)
Definition: porting.cpp:164
DRINK
@ DRINK
Definition: object.h:160
PU_CURSED
#define PU_CURSED
Definition: define.h:144
find_player_partial_name
player * find_player_partial_name(const char *plname)
Definition: player.cpp:112
roll_stats
void roll_stats(object *op)
Definition: player.cpp:1042
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.cpp:2626
ATNR_COLD
#define ATNR_COLD
Definition: attack.h:53
FLAG_XRAYS
#define FLAG_XRAYS
Definition: define.h:300
add_player
player * add_player(socket_struct *ns, int flags)
Definition: player.cpp:452
say.item
dictionary item
Definition: say.py:149
query_base_name
void query_base_name(const object *op, int plural, char *buf, size_t size)
Definition: item.cpp:686
Settings::search_items
uint8_t search_items
Definition: global.h:267
obj::anim_suffix
sstring anim_suffix
Definition: object.h:322
obj::move_on
MoveType move_on
Definition: object.h:435
get_attr_value
int8_t get_attr_value(const living *stats, int attr)
Definition: living.cpp:313
drain_rod_charge
void drain_rod_charge(object *rod)
Definition: spell_util.cpp:775
range_skill
@ range_skill
Definition: player.h:35
obj::attacktype
uint32_t attacktype
Definition: object.h:350
server.h
freearr_x
short freearr_x[SIZEOFFREE]
Definition: object.cpp:299
oblnk
Definition: object.h:449
PU_DRINK
#define PU_DRINK
Definition: define.h:116
mapdef::path
char path[HUGE_BUF]
Definition: map.h:358
player_attack_door
static int player_attack_door(object *op, object *door)
Definition: player.cpp:2520
INTELLIGENCE
@ INTELLIGENCE
Definition: living.h:16
shop_contains
bool shop_contains(object *ob)
Definition: shop.cpp:1296
reputation.killer
def killer
Definition: reputation.py:13
hide
int hide(object *op, object *skill)
Definition: skills.cpp:496
pl::party
partylist * party
Definition: player.h:202
swap_stat
static void swap_stat(object *op, int swap_second)
Definition: player.cpp:1135
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
clear_player
void clear_player(player *pl)
Definition: player.cpp:33