Crossfire Server, Trunk  R21670
player.c
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2014 Mark Wedel and the Crossfire Development Team
5  * Copyright (c) 1992 Frank Tore Johansen
6  *
7  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
8  * welcome to redistribute it under certain conditions. For details, please
9  * see COPYING and LICENSE.
10  *
11  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
12  */
13 
20 #include "global.h"
21 
22 #include <assert.h>
23 #include <stddef.h>
24 #include <stdlib.h>
25 #include <string.h>
26 
27 #ifndef WIN32 /* ---win32 remove headers */
28 #include <pwd.h>
29 #endif
30 
31 #include "server.h"
32 #include "living.h"
33 #include "object.h"
34 #include "shared/newclient.h"
35 #include "shop.h"
36 #include "skills.h"
37 #include "sounds.h"
38 #include "spells.h"
39 #include "sproto.h"
40 
42 
43 static void kill_player_not_permadeath(object *op);
44 static void kill_player_permadeath(object *op);
45 static int action_makes_visible(object *op);
46 
55 player *find_player(const char *plname) {
56  return find_player_options(plname, 0, NULL);
57 }
58 
66 player *find_player_options(const char *plname, int options, const mapstruct *map) {
67  player *pl;
68  player *found = NULL;
69  size_t namelen = strlen(plname);
70  char name[MAX_BUF];
71 
72  for (pl = first_player; pl != NULL; pl = pl->next) {
73  if ((options & FIND_PLAYER_NO_HIDDEN_DM) && (QUERY_FLAG(pl->ob, FLAG_WIZ) && pl->ob->contr->hidden))
74  continue;
75 
76  if (map != NULL && pl->ob->map != map)
77  continue;
78 
79  if (!(options & FIND_PLAYER_PARTIAL_NAME)) {
80  query_name(pl->ob, name, sizeof(name));
81  if (!strcmp(name, plname))
82  return pl;
83  continue;
84  }
85 
86  if (strlen(pl->ob->name) < namelen)
87  continue;
88 
89  if (!strcmp(pl->ob->name, plname))
90  return pl;
91 
92  if (!strncasecmp(pl->ob->name, plname, namelen)) {
93  if (found)
94  return NULL;
95 
96  found = pl;
97  }
98  }
99  return found;
100 }
101 
110 player *find_player_partial_name(const char *plname) {
111  return find_player_options(plname, FIND_PLAYER_PARTIAL_NAME, NULL);
112 }
113 
120  player *pl;
121 
122  for (pl = first_player; pl != NULL; pl = pl->next) {
123  if (&pl->socket == ns)
124  return pl;
125  }
126  return NULL;
127 }
128 
135 void display_motd(const object *op) {
136  char buf[MAX_BUF];
137  char motd[HUGE_BUF];
138  FILE *fp;
139  size_t size;
140 
141  snprintf(buf, sizeof(buf), "%s/%s", settings.confdir, settings.motd);
142  fp = fopen(buf, "r");
143  if (fp == NULL) {
144  return;
145  }
146  motd[0] = '\0';
147  size = 0;
148 
149  while (fgets(buf, MAX_BUF, fp) != NULL) {
150  if (*buf != '#') {
151  safe_strcat(motd, buf, &size, sizeof(motd));
152  }
153  }
154 
156  motd);
157  fclose(fp);
158 }
159 
166 void send_rules(const object *op) {
167  char buf[MAX_BUF];
168  char rules[HUGE_BUF];
169  FILE *fp;
170  size_t size;
171 
172  snprintf(buf, sizeof(buf), "%s/%s", settings.confdir, settings.rules);
173  fp = fopen(buf, "r");
174  if (fp == NULL) {
175  return;
176  }
177  rules[0] = '\0';
178  size = 0;
179 
180  while (fgets(buf, MAX_BUF, fp) != NULL) {
181  if (size+strlen(buf) >= HUGE_BUF) {
182  LOG(llevDebug, "Warning, rules size is > %d bytes.\n", HUGE_BUF);
183  break;
184  }
185 
186  if (*buf != '#') {
187  safe_strcat(rules, buf, &size, sizeof(rules));
188  }
189  }
190 
192  MSG_TYPE_ADMIN_RULES, rules);
193  fclose(fp);
194 }
195 
202 void send_news(const object *op) {
203  char buf[MAX_BUF];
204  char news[HUGE_BUF];
205  char subject[MAX_BUF];
206  FILE *fp;
207  size_t size;
208 
209  snprintf(buf, sizeof(buf), "%s/%s", settings.confdir, settings.news);
210  fp = fopen(buf, "r");
211  if (fp == NULL)
212  return;
213  news[0] = '\0';
214  subject[0] = '\0';
215  size = 0;
216  while (fgets(buf, MAX_BUF, fp) != NULL) {
217  if (*buf == '#')
218  continue;
219  if (*buf == '%') { /* send one news */
220  if (size > 0)
223  "%s:\n%s",
224  subject, news); /*send previously read news*/
225  safe_strncpy(subject, buf + 1, sizeof(subject));
226  strip_endline(subject);
227  size = 0;
228  news[0] = '\0';
229  } else {
230  if (size+strlen(buf) >= HUGE_BUF) {
231  LOG(llevDebug, "Warning, one news item has size > %d bytes.\n", HUGE_BUF);
232  break;
233  }
234  safe_strcat(news, buf, &size, sizeof(news));
235  }
236  }
237 
240  "%s:\n%s",
241  subject, news);
242  fclose(fp);
243 }
244 
253 int playername_ok(const char *cp) {
254  /* Don't allow - or _ as first character in the name */
255  if (*cp == '-' || *cp == '_')
256  return 0;
257 
258  for (; *cp != '\0'; cp++)
259  if (!((*cp >= 'a' && *cp <= 'z') || (*cp >= 'A' && *cp <= 'Z'))
260  && *cp != '-'
261  && *cp != '_')
262  return 0;
263  return 1;
264 }
265 
282  object *op = arch_to_object(get_player_archetype(NULL));
283  int i;
284 
285  if (!p) {
286  player *tmp;
287 
288  p = (player *)malloc(sizeof(player));
289  if (p == NULL)
291 
292  /* This adds the player in the linked list. There is extra
293  * complexity here because we want to add the new player at the
294  * end of the list - there is in fact no compelling reason that
295  * that needs to be done except for things like output of
296  * 'who'.
297  */
298  tmp = first_player;
299  while (tmp != NULL && tmp->next != NULL)
300  tmp = tmp->next;
301  if (tmp != NULL)
302  tmp->next = p;
303  else
304  first_player = p;
305 
306  p->next = NULL;
307  /* This only needs to be done on initial creation of player
308  * object. the callers of get_player() will copy over the
309  * socket structure to p->socket, and if this is an existing
310  * player object, that has been done. The call to
311  * roll_stats() below will try to send spell information to
312  * the client - if this is non zero (eg, garbage from not
313  * being cleared), that will cause problems. So just clear
314  * it, and no spell data is sent.
315  */
316  p->socket.monitor_spells = 0;
317  } else {
318  /* Only needed when reusing existing player. */
319  clear_player(p);
320  }
321 
322  /* Clears basically the entire player structure except
323  * for next and socket.
324  */
325  memset((void *)((char *)p+offsetof(player, maplevel)), 0, sizeof(player)-offsetof(player, maplevel));
326 
327  /* There are some elements we want initialized to non zero value -
328  * we deal with that below this point.
329  */
330  p->party = NULL;
333  p->swap_first = -1;
334 
335 #ifdef AUTOSAVE
336  p->last_save_tick = 9999999;
337 #endif
338 
339  strcpy(p->savebed_map, first_map_path); /* Init. respawn position */
340 
341  op->contr = p; /* this aren't yet in archetype */
342  p->ob = op;
343  op->speed_left = 0.5;
344  op->speed = 1.0;
345  op->direction = 5; /* So player faces south */
346  op->stats.wc = 2;
347  op->run_away = 25; /* Then we panic... */
348 
349  roll_stats(op);
351  clear_los(p);
352 
353  p->gen_sp_armour = 10;
354  p->last_speed = -1;
355  p->shoottype = range_none;
356  p->bowtype = bow_normal;
357  p->petmode = pet_normal;
358  p->listening = 10;
359  p->last_weapon_sp = -1;
360  p->peaceful = 1; /* default peaceful */
361  p->do_los = 1;
362  p->no_shout = 0; /* default can shout */
363  p->language = -1; // find default language
364  p->unarmed_skill = NULL;
365  p->ticks_played = 0;
366 
367  strncpy(p->title, op->arch->clone.name, sizeof(p->title)-1);
368  p->title[sizeof(p->title)-1] = '\0';
369  op->race = add_string(op->arch->clone.race);
370 
372 
373  /* we need to clear these to -1 and not zero - otherwise,
374  * if a player quits and starts a new character, we wont
375  * send new values to the client, as things like exp start
376  * at zero.
377  */
378  for (i = 0; i < MAX_SKILLS; i++) {
379  p->last_skill_exp[i] = -1;
380  p->last_skill_ob[i] = NULL;
381  }
382  for (i = 0; i < NROFATTACKS; i++) {
383  p->last_resist[i] = -1;
384  }
385  p->last_stats.exp = -1;
386  p->last_weight = (uint32_t)-1;
387 
388  p->socket.update_look = 0;
389  p->socket.look_position = 0;
390  return p;
391 }
392 
399 void set_first_map(object *op) {
400  strcpy(op->contr->maplevel, first_map_path);
401  op->x = -1;
402  op->y = -1;
404 }
405 
418 static void set_player_socket(player *p, socket_struct *ns) {
419  memcpy(&p->socket, ns, sizeof(socket_struct));
420 
421  /* The memcpy above copies the reference to faces sent. So we need to clear
422  * that pointer in ns, otherwise we get a double free.
423  */
424  ns->faces_sent = NULL;
425 
426  if (p->socket.faces_sent == NULL)
428 
429  /* Needed because the socket we just copied over needs to be cleared.
430  * Note that this can result in a client reset if there is partial data
431  * on the incoming socket.
432  */
434 
435 
436 }
437 
455  player *p;
456 
457  p = get_player(NULL);
458  ns->status = Ns_Avail;
459  set_player_socket(p, ns);
460 
462 
463  if (!(flags & ADD_PLAYER_NO_MAP))
464  set_first_map(p->ob);
465 
467 
468  /* In this case, the client is provide all the informatin for the
469  * new character, so just return it. Do not display any messages,
470  * etc
471  */
472  if (flags & ADD_PLAYER_NO_STATS_ROLL)
473  return p;
474 
475  if (flags & ADD_PLAYER_NEW) {
476  roll_again(p->ob);
478  } else {
479  send_rules(p->ob);
480  send_news(p->ob);
481  display_motd(p->ob);
482  get_name(p->ob);
483  }
484  return p;
485 }
486 
498  archetype *start = at;
499 
500  for (;;) {
501  if (at == NULL || at->next == NULL)
502  at = first_archetype;
503  else
504  at = at->next;
505  if (at->clone.type == PLAYER)
506  return at;
507  if (at == start) {
508  LOG(llevError, "No Player archetypes\n");
509  exit(-1);
510  }
511  }
512 }
513 
522 object *get_nearest_player(object *mon) {
523  object *op = NULL;
524  player *pl = NULL;
525  objectlink *ol;
526  unsigned lastdist;
527  rv_vector rv;
528 
529  for (ol = first_friendly_object, lastdist = 1000; ol != NULL; ol = ol->next) {
530  /* We should not find free objects on this friendly list, but it
531  * does periodically happen. Given that, lets deal with it.
532  * While unlikely, it is possible the next object on the friendly
533  * list is also free, so encapsulate this in a while loop.
534  */
535  while (QUERY_FLAG(ol->ob, FLAG_FREED) || !QUERY_FLAG(ol->ob, FLAG_FRIENDLY)) {
536  object *tmp = ol->ob;
537 
538  /* Can't do much more other than log the fact, because the object
539  * itself will have been cleared.
540  */
541  LOG(llevDebug, "get_nearest_player: Found free/non friendly object on friendly list\n");
542  ol = ol->next;
544  if (!ol)
545  return op;
546  }
547 
548  /* Remove special check for player from this. First, it looks to cause
549  * some crashes (ol->ob->contr not set properly?), but secondly, a more
550  * complicated method of state checking would be needed in any case -
551  * as it was, a clever player could type quit, and the function would
552  * skip them over while waiting for confirmation. Remove
553  * on_same_map check, as monster_can_detect_enemy() also does this
554  */
555  if (!monster_can_detect_enemy(mon, ol->ob, &rv))
556  continue;
557 
558  if (lastdist > rv.distance) {
559  op = ol->ob;
560  lastdist = rv.distance;
561  }
562  }
563  for (pl = first_player; pl != NULL; pl = pl->next) {
564  if (monster_can_detect_enemy(mon, pl->ob, &rv)) {
565  if (lastdist > rv.distance) {
566  op = pl->ob;
567  lastdist = rv.distance;
568  }
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)
766  create_treasure(items, pl, GT_STARTEQUIP|GT_ONLY_GOOD, 1, 0);
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))
773  SET_FLAG(op, FLAG_APPLIED);
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) {
779  if ((!QUERY_FLAG(pl, FLAG_USE_ARMOUR) && IS_ARMOR(op))
780  || (!QUERY_FLAG(pl, FLAG_USE_WEAPON) && IS_WEAPON(op))
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  FOR_BELOW_PREPARE(op, tmp)
799  if (object_can_merge(op, tmp)) {
800  found = 1;
801  break;
802  }
804  if (found) {
805  LOG(llevError, "give_initial_items: Removing duplicate object %s\n", op->name);
806  object_remove(op);
808  continue;
809  }
810  if (op->nrof > 1)
811  op->nrof = 1;
812  }
813 
814  if (op->type == SPELLBOOK && op->inv) {
815  CLEAR_FLAG(op->inv, FLAG_STARTEQUIP);
816  }
817 
818  /* Give starting characters identified, uncursed, and undamned
819  * items. Just don't identify gold or silver, or it won't be
820  * merged properly.
821  */
822  if (is_identifiable_type(op)) {
824  CLEAR_FLAG(op, FLAG_CURSED);
825  CLEAR_FLAG(op, FLAG_DAMNED);
826  }
827  if (op->type == SKILL) {
829  op->stats.exp = 0;
830  op->level = 1;
831  }
832  /* lock all 'normal items by default */
833  else
835  } FOR_INV_FINISH(); /* for loop of objects in player inv */
836 
837  /* Need to set up the skill pointers */
838  link_player_skills(pl);
839 
844  FOR_INV_PREPARE(pl, op)
845  if ((IS_ARMOR(op) || IS_WEAPON(op) || IS_SHIELD(op)) && !QUERY_FLAG(op, FLAG_APPLIED))
846  apply_manual(pl, op, AP_NOPRINT);
847  FOR_INV_FINISH();
848 }
849 
856 void get_name(object *op) {
857  op->contr->write_buf[0] = '\0';
859  send_query(&op->contr->socket, 0, "What is your name?\n:");
860 }
861 
868 void get_password(object *op) {
869  op->contr->write_buf[0] = '\0';
871  send_query(&op->contr->socket, CS_QUERY_HIDEINPUT, "What is your password?\n:");
872 }
873 
880 void play_again(object *op) {
881  SockList sl;
882 
883  op->contr->socket.status = Ns_Add;
885  op->chosen_skill = NULL;
886 
887  /*
888  * For old clients, ask if they want to play again.
889  * For clients with account support, just return to character seletion (see below).
890  */
891  if (op->contr->socket.login_method == 0) {
892  send_query(&op->contr->socket, CS_QUERY_SINGLECHAR, "Do you want to play again (a/q)?");
893  }
894  /* a bit of a hack, but there are various places early in th
895  * player creation process that a user can quit (eg, roll
896  * stats) that isn't removing the player. Taking a quick
897  * look, there are many places that call play_again without
898  * removing the player - it probably makes more sense
899  * to leave it to play_again to remove the object in all
900  * cases.
901  */
902  if (!QUERY_FLAG(op, FLAG_REMOVED))
903  object_remove(op);
904  /* Need to set this to null - otherwise, it could point to garbage,
905  * and draw() doesn't check to see if the player is removed, only if
906  * the map is null or not swapped out.
907  */
908  op->map = NULL;
909 
910  SockList_Init(&sl);
911  SockList_AddString(&sl, "player ");
912  SockList_AddInt(&sl, 0);
913  SockList_AddInt(&sl, 0);
914  SockList_AddInt(&sl, 0);
915  SockList_AddChar(&sl, 0);
916 
917  Send_With_Handling(&op->contr->socket, &sl);
918  SockList_Term(&sl);
919 
920  if (op->contr->socket.login_method > 0) {
921  receive_play_again(op, 'a');
922  }
923 }
924 
933 void receive_play_again(object *op, char key) {
934  if (key == 'q' || key == 'Q') {
936  leave(op->contr, 0); /* ericserver will draw the message */
937  return;
938  } else if (key == 'a' || key == 'A') {
939  player *pl = op->contr;
940  const char *name = op->name;
941 
942  add_refcount(name);
945  pl = get_player(pl);
946  op = pl->ob;
948  op->contr->password[0] = '~';
951  if (pl->socket.login_method >= 1 && pl->socket.account_name != NULL) {
952  /* If we are using new login, we send the
953  * list of characters to the client - this should
954  * result in the client popping up this list so
955  * the player can choose which one to play - better
956  * than going to legacy login code.
957  * If the account_name is NULL, it means the client
958  * says it uses account but started playing without logging in.
959  */
962  } else {
963  /* Lets put a space in here */
965  "\n");
966  get_name(op);
967  set_first_map(op);
968  }
969  op->name = name; /* Already added a refcount above */
970  op->name_pl = add_string(name);
971  } else {
972  /* user pressed something else so just ask again... */
973  play_again(op);
974  }
975 }
976 
983 void confirm_password(object *op) {
984  op->contr->write_buf[0] = '\0';
986  send_query(&op->contr->socket, CS_QUERY_HIDEINPUT, "Please type your password again.\n:");
987 }
988 
999 int get_party_password(object *op, partylist *party) {
1000  if (*party_get_password(party) == '\0') {
1001  return 0;
1002  }
1003 
1004  op->contr->write_buf[0] = '\0';
1006  op->contr->party_to_join = party;
1007  send_query(&op->contr->socket, CS_QUERY_HIDEINPUT, "What is the password?\n:");
1008  return 1;
1009 }
1010 
1017 int roll_stat(void) {
1018  int roll[4], i, low_index, k;
1019 
1020  for (i = 0; i < 4; ++i)
1021  roll[i] = (int)RANDOM()%6+1;
1022 
1023  for (i = 0, low_index = 0, k = 7; i < 4; ++i)
1024  if (roll[i] < k)
1025  k = roll[i],
1026  low_index = i;
1027 
1028  for (i = 0, k = 0; i < 4; ++i) {
1029  if (i != low_index)
1030  k += roll[i];
1031  }
1032  return k;
1033 }
1034 
1041 void roll_stats(object *op) {
1042  int sum = 0;
1043  int i = 0, j = 0;
1044  int statsort[7];
1045 
1046  do {
1047  op->stats.Str = roll_stat();
1048  op->stats.Dex = roll_stat();
1049  op->stats.Int = roll_stat();
1050  op->stats.Con = roll_stat();
1051  op->stats.Wis = roll_stat();
1052  op->stats.Pow = roll_stat();
1053  op->stats.Cha = roll_stat();
1054  sum = op->stats.Str+op->stats.Dex+op->stats.Int+op->stats.Con+op->stats.Wis+op->stats.Pow+op->stats.Cha;
1055  } while (sum != settings.roll_stat_points);
1056 
1057  /* Sort the stats so that rerolling is easier... */
1058  statsort[0] = op->stats.Str;
1059  statsort[1] = op->stats.Dex;
1060  statsort[2] = op->stats.Int;
1061  statsort[3] = op->stats.Con;
1062  statsort[4] = op->stats.Wis;
1063  statsort[5] = op->stats.Pow;
1064  statsort[6] = op->stats.Cha;
1065 
1066  /* a quick and dirty bubblesort? */
1067  do {
1068  if (statsort[i] < statsort[i+1]) {
1069  j = statsort[i];
1070  statsort[i] = statsort[i+1];
1071  statsort[i+1] = j;
1072  i = 0;
1073  } else {
1074  i++;
1075  }
1076  } while (i < 6);
1077 
1078  op->stats.Str = statsort[0];
1079  op->stats.Dex = statsort[1];
1080  op->stats.Con = statsort[2];
1081  op->stats.Int = statsort[3];
1082  op->stats.Wis = statsort[4];
1083  op->stats.Pow = statsort[5];
1084  op->stats.Cha = statsort[6];
1085 
1086  op->contr->orig_stats.Str = op->stats.Str;
1087  op->contr->orig_stats.Dex = op->stats.Dex;
1088  op->contr->orig_stats.Int = op->stats.Int;
1089  op->contr->orig_stats.Con = op->stats.Con;
1090  op->contr->orig_stats.Wis = op->stats.Wis;
1091  op->contr->orig_stats.Pow = op->stats.Pow;
1092  op->contr->orig_stats.Cha = op->stats.Cha;
1093 
1094  op->level = 1;
1095  op->stats.exp = 0;
1096  op->stats.ac = 0;
1097 
1098  op->contr->levhp[1] = 9;
1099  op->contr->levsp[1] = 6;
1100  op->contr->levgrace[1] = 3;
1101 
1102  fix_object(op);
1103  op->stats.hp = op->stats.maxhp;
1104  op->stats.sp = op->stats.maxsp;
1105  op->stats.grace = op->stats.maxgrace;
1106  op->contr->orig_stats = op->stats;
1107 }
1108 
1115 void roll_again(object *op) {
1116  esrv_new_player(op->contr, 0);
1117  send_query(&op->contr->socket, CS_QUERY_SINGLECHAR, "<y> to roll new stats <n> to use stats\n<1-7> <1-7> to swap stats.\nRoll again (y/n/1-7)? ");
1118 }
1119 
1129 static void swap_stat(object *op, int swap_second) {
1130  signed char tmp;
1131 
1132  if (op->contr->swap_first == -1) {
1133  LOG(llevError, "player.c:swap_stat() - swap_first is -1\n");
1134  return;
1135  }
1136 
1137  tmp = get_attr_value(&op->contr->orig_stats, op->contr->swap_first);
1138 
1139  set_attr_value(&op->contr->orig_stats, op->contr->swap_first, get_attr_value(&op->contr->orig_stats, swap_second));
1140 
1141  set_attr_value(&op->contr->orig_stats, swap_second, tmp);
1142 
1144  "%s done\n",
1145  short_stat_name[swap_second]);
1146 
1147  op->stats.Str = op->contr->orig_stats.Str;
1148  op->stats.Dex = op->contr->orig_stats.Dex;
1149  op->stats.Con = op->contr->orig_stats.Con;
1150  op->stats.Int = op->contr->orig_stats.Int;
1151  op->stats.Wis = op->contr->orig_stats.Wis;
1152  op->stats.Pow = op->contr->orig_stats.Pow;
1153  op->stats.Cha = op->contr->orig_stats.Cha;
1154  op->stats.ac = 0;
1155 
1156  op->level = 1;
1157  op->stats.exp = 0;
1158  op->stats.ac = 0;
1159 
1160  op->contr->levhp[1] = 9;
1161  op->contr->levsp[1] = 6;
1162  op->contr->levgrace[1] = 3;
1163 
1164  fix_object(op);
1165  op->stats.hp = op->stats.maxhp;
1166  op->stats.sp = op->stats.maxsp;
1167  op->stats.grace = op->stats.maxgrace;
1168  op->contr->orig_stats = op->stats;
1169  op->contr->swap_first = -1;
1170 }
1171 
1187 void key_roll_stat(object *op, char key) {
1188  int keynum = key-'0';
1189  static const int8_t stat_trans[] = {
1190  -1,
1191  STRENGTH,
1192  DEXTERITY,
1193  CONSTITUTION,
1194  INTELLIGENCE,
1195  WISDOM,
1196  POWER,
1197  CHARISMA,
1198  };
1199 
1200  if (keynum > 0 && keynum <= 7) {
1201  if (op->contr->swap_first == -1) {
1202  op->contr->swap_first = stat_trans[keynum];
1204  "%s ->",
1205  short_stat_name[stat_trans[keynum]]);
1206  } else
1207  swap_stat(op, stat_trans[keynum]);
1208 
1210  return;
1211  }
1212  switch (key) {
1213  case 'n':
1214  case 'N': {
1215  SET_FLAG(op, FLAG_WIZ);
1216  if (op->map == NULL) {
1217  LOG(llevError, "Map == NULL in state 2\n");
1218  break;
1219  }
1220 
1221  SET_ANIMATION(op, 2); /* So player faces south */
1222  /* Enter exit adds a player otherwise */
1223  add_statbonus(op);
1224  send_query(&op->contr->socket, CS_QUERY_SINGLECHAR, "Now choose a character.\nPress any key to change outlook.\nPress `d' when you're pleased.\n");
1226  if (op->msg)
1227  draw_ext_info(NDI_BLUE, 0, op,
1229  op->msg);
1230  return;
1231  }
1232  case 'y':
1233  case 'Y':
1234  roll_stats(op);
1236  return;
1237 
1238  case 'q':
1239  case 'Q':
1240  play_again(op);
1241  return;
1242 
1243  default:
1244  send_query(&op->contr->socket, CS_QUERY_SINGLECHAR, "Yes, No, Quit or 1-6. Roll again?");
1245  return;
1246  }
1247  return;
1248 }
1249 
1263 void key_change_class(object *op, char key) {
1264  int tmp_loop;
1265 
1266  if (key == 'q' || key == 'Q') {
1267  object_remove(op);
1268  play_again(op);
1269  return;
1270  }
1271  if (key == 'd' || key == 'D') {
1272  char buf[MAX_BUF];
1273 
1274  /* this must before then initial items are given */
1275  esrv_new_player(op->contr, op->weight+op->carrying);
1276  create_treasure(find_treasurelist("starting_wealth"), op, 0, 0, 0);
1277 
1278  /* Lauwenmark : Here we handle the BORN global event */
1280 
1281  /* Lauwenmark : We then generate a LOGIN event */
1284 
1285  object_set_msg(op, NULL);
1286 
1287  /* We create this now because some of the unique maps will need it
1288  * to save here.
1289  */
1290  snprintf(buf, sizeof(buf), "%s/%s/%s", settings.localdir, settings.playerdir, op->name);
1291  make_path_to_file(buf);
1292 
1293 #ifdef AUTOSAVE
1294  op->contr->last_save_tick = pticks;
1295 #endif
1298  "Welcome to Crossfire!\n Press `?' for help\n");
1299 
1302  "%s entered the game.", op->name);
1303 
1304  CLEAR_FLAG(op, FLAG_WIZ);
1306  link_player_skills(op);
1307  esrv_send_inventory(op, op);
1308  fix_object(op);
1309 
1310  /* This moves the player to a different start map, if there
1311  * is one for this race
1312  */
1313  if (*first_map_ext_path) {
1314  object *tmp;
1315  char mapname[MAX_BUF];
1316  mapstruct *oldmap;
1317 
1318  oldmap = op->map;
1319 
1320  snprintf(mapname, MAX_BUF-1, "%s/%s", first_map_ext_path, op->arch->name);
1321  /*printf("%s\n", mapname);*/
1322  tmp = object_new();
1323  EXIT_PATH(tmp) = add_string(mapname);
1324  EXIT_X(tmp) = op->x;
1325  EXIT_Y(tmp) = op->y;
1326  enter_exit(op, tmp);
1327 
1328  if (oldmap != op->map) {
1329  /* map exists, update bed of reality location, in case player dies */
1330  op->contr->bed_x = op->x;
1331  op->contr->bed_y = op->y;
1332  strlcpy(op->contr->savebed_map, mapname, sizeof(op->contr->savebed_map));
1333  }
1334 
1336  } else {
1337  LOG(llevDebug, "first_map_ext_path not set\n");
1338  }
1339  return;
1340  }
1341 
1342  /* Following actually changes the race - this is the default command
1343  * if we don't match with one of the options above.
1344  */
1345 
1346  tmp_loop = 0;
1347  while (!tmp_loop) {
1348  const char *name = add_string(op->name);
1349  int x = op->x, y = op->y;
1350 
1351  remove_statbonus(op);
1352  object_remove(op);
1353  /* get_player_archetype() is really misnamed - it will
1354  * get the next archetype from the list.
1355  */
1356  op->arch = get_player_archetype(op->arch);
1357  object_copy(&op->arch->clone, op);
1358  op->stats = op->contr->orig_stats;
1359  free_string(op->name);
1360  op->name = name;
1361  free_string(op->name_pl);
1362  op->name_pl = add_string(name);
1363  SET_ANIMATION(op, 2); /* So player faces south */
1364  object_insert_in_map_at(op, op->map, op, 0, x, y);
1365  strncpy(op->contr->title, op->arch->clone.name, sizeof(op->contr->title)-1);
1366  op->contr->title[sizeof(op->contr->title)-1] = '\0';
1367  add_statbonus(op);
1368  tmp_loop = allowed_class(op);
1369  }
1371  esrv_update_item(UPD_FACE, op, op);
1372  fix_object(op);
1373  op->stats.hp = op->stats.maxhp;
1374  op->stats.sp = op->stats.maxsp;
1375  op->stats.grace = 0;
1376  if (op->msg)
1378  op->msg);
1379  send_query(&op->contr->socket, CS_QUERY_SINGLECHAR, "Press any key for the next race.\nPress `d' to play this race.\n");
1380 }
1381 
1403 int check_race_and_class(living *stats, archetype *race, archetype *opclass)
1404 {
1405  int i, stat, failure=0;
1406 
1407  for (i = 0; i < NUM_STATS; i++) {
1408  stat = get_attr_value(stats, i);
1409  if (race)
1410  stat += get_attr_value(&race->clone.stats, i);
1411 
1412  if (opclass)
1413  stat += get_attr_value(&opclass->clone.stats, i);
1414 
1415  set_attr_value(stats, i, stat);
1416 
1417  /* We process all stats, regardless if there is a failure
1418  * or not.
1419  */
1420  if (stat < MIN_STAT) failure=1;
1421 
1422  /* Maybe this should be an error? Player is losing
1423  * some stats points here, but it is legal.
1424  */
1425  if (stat > settings.max_stat) stat = settings.max_stat;
1426  }
1427  return failure;
1428 
1429 }
1430 
1453 int apply_race_and_class(object *op, archetype *race, archetype *opclass, living *stats)
1454 {
1455  const char *name = add_string(op->name);
1456  char buf[MAX_BUF];
1457  object *inv;
1458 
1459  /* Free any objects in character inventory - they
1460  * shouldn't have any, but there is the potential that
1461  * we give them objects below and then get a creation
1462  * failure (stat out of range), in which case
1463  * those objects would be in the inventory.
1464  */
1465  while (op->inv) {
1466  inv = op->inv;
1467  object_remove(inv);
1468  object_free(inv, 0);
1469  }
1470 
1471  object_copy(&race->clone, op);
1472  free_string(op->name);
1473  op->name = name;
1474  free_string(op->name_pl);
1475  op->name_pl = add_string(name);
1476  SET_ANIMATION(op, 2); /* So player faces south */
1477  strlcpy(op->contr->title, op->arch->clone.name, sizeof(op->contr->title));
1478 
1479  if (stats) {
1480  /* Copy over the stats. Use this instead a memcpy because
1481  * we only want to copy over a few specific stats, and
1482  * leave things like maxhp, maxsp, etc, unchanged.
1483  */
1484  int i, stat;
1485  for (i = 0; i < NUM_STATS; i++) {
1486  stat = get_attr_value(stats, i);
1487  set_attr_value(&op->stats, i, stat);
1488  set_attr_value(&op->contr->orig_stats, i, stat);
1489  }
1490  } else {
1491  /* Note that this will repeated increase the stat values
1492  * if the caller does not reset them. Only do this
1493  * if stats is not provided - if stats is provided, those
1494  * are already adjusted.
1495  */
1496  add_statbonus(op);
1497 
1498  /* Checks that all stats are greater than 1. Once again,
1499  * only do this if stats are not provided
1500  */
1501  if (!allowed_class(op)) return 1;
1502  }
1503 
1505  op->stats.hp = op->stats.maxhp;
1506  op->stats.sp = op->stats.maxsp;
1507  op->stats.grace = 0;
1508 
1509  /* this must before then initial items are given */
1510  esrv_new_player(op->contr, op->weight+op->carrying);
1511  create_treasure(find_treasurelist("starting_wealth"), op, 0, 0, 0);
1512 
1513  /* This has to be done before class, otherwise the NOCLASSFACECHANGE
1514  * object is not in the inventory, and racial face will get overwritten.
1515  */
1517 
1518  if (stats) {
1519  /* Apply class information */
1521  } else {
1522  apply_changes_to_player(op, &opclass->clone, 0);
1523 
1524  /* Checks that all stats are greater than 1 */
1525  if (!allowed_class(op)) return 2;
1526  }
1527 
1528  /* Lauwenmark : Here we handle the BORN global event */
1530 
1531  /* Lauwenmark : We then generate a LOGIN event */
1533 
1534  object_set_msg(op, NULL);
1535 
1536  /* We create this now because some of the unique maps will need it
1537  * to save here.
1538  */
1539  snprintf(buf, sizeof(buf), "%s/%s/%s", settings.localdir, settings.playerdir, op->name);
1540  make_path_to_file(buf);
1541 
1542 #ifdef AUTOSAVE
1543  op->contr->last_save_tick = pticks;
1544 #endif
1545 
1546  CLEAR_FLAG(op, FLAG_WIZ);
1547  link_player_skills(op);
1548  fix_object(op);
1549 
1550  esrv_send_inventory(op, op);
1551  esrv_update_item(UPD_FACE, op, op);
1552 
1553  return 0;
1554 
1555 }
1556 
1565 void key_confirm_quit(object *op, char key) {
1566  char buf[MAX_BUF];
1567  mapstruct *mp, *next;
1568 
1569  // this was tested when 'quit' command was issued, but better safe than sorry.
1570  if (QUERY_FLAG(op, FLAG_WAS_WIZ)) {
1572  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_LOGIN, "Can't quit when in DM mode.");
1573  return;
1574  }
1575 
1576  if (key != 'y' && key != 'Y' && key != 'q' && key != 'Q') {
1579  "OK, continuing to play.");
1580  return;
1581  }
1582 
1583  /* Lauwenmark : Here we handle the REMOVE global event */
1585  pets_terminate_all(op);
1586  object_remove(op);
1587  op->direction = 0;
1589  "%s quits the game.",
1590  op->name);
1591 
1592  strcpy(op->contr->killer, "quit");
1593  hiscore_check(op, 0);
1594  party_leave(op);
1595  if (settings.set_title == TRUE)
1596  player_set_own_title(op->contr, "");
1597 
1598 
1599  /* We need to hunt for any per player unique maps in memory and
1600  * get rid of them. The trailing slash in the path is intentional,
1601  * so that players named 'Ab' won't match against players 'Abe' pathname
1602  */
1603  snprintf(buf, sizeof(buf), "%s/%s/%s/", settings.localdir, settings.playerdir, op->name);
1604  for (mp = first_map; mp != NULL; mp = next) {
1605  next = mp->next;
1606  if (!strncmp(mp->path, buf, strlen(buf)))
1607  delete_map(mp);
1608  }
1609 
1610  delete_character(op->name);
1611 
1612  /* Remove player from account list and send back data if needed */
1613  if (op->contr->socket.account_chars != NULL) {
1616  /* char information is reloaded in send_account_players below */
1618  op->contr->socket.account_chars = NULL;
1621  }
1622 
1623  play_again(op);
1624 }
1625 
1632 static void flee_player(object *op) {
1633  int dir, diff;
1634  rv_vector rv;
1635 
1636  if (op->stats.hp < 0) {
1637  LOG(llevDebug, "Fleeing player is dead.\n");
1638  CLEAR_FLAG(op, FLAG_SCARED);
1639  return;
1640  }
1641 
1642  if (op->enemy == NULL) {
1643  LOG(llevDebug, "Fleeing player had no enemy.\n");
1644  CLEAR_FLAG(op, FLAG_SCARED);
1645  return;
1646  }
1647 
1648  /* Seen some crashes here. Since we don't store an
1649  * op->enemy_count, it is possible that something destroys the
1650  * actual enemy, and the object is recycled.
1651  */
1652  if (op->enemy->map == NULL) {
1653  CLEAR_FLAG(op, FLAG_SCARED);
1654  object_set_enemy(op, NULL);
1655  return;
1656  }
1657 
1658  if (!(random_roll(0, 4, op, PREFER_LOW)) && did_make_save(op, op->level, 0)) {
1659  object_set_enemy(op, NULL);
1660  CLEAR_FLAG(op, FLAG_SCARED);
1661  return;
1662  }
1663  if (!get_rangevector(op, op->enemy, &rv, 0)) {
1664  object_set_enemy(op, NULL);
1665  CLEAR_FLAG(op, FLAG_SCARED);
1666  return;
1667  }
1668 
1669  dir = absdir(4+rv.direction);
1670  for (diff = 0; diff < 3; diff++) {
1671  int m = 1-(RANDOM()&2);
1672  if (move_ob(op, absdir(dir+diff*m), op)
1673  || (diff == 0 && move_ob(op, absdir(dir-diff*m), op))) {
1674  return;
1675  }
1676  }
1677  /* Cornered, get rid of scared */
1678  CLEAR_FLAG(op, FLAG_SCARED);
1679  object_set_enemy(op, NULL);
1680 }
1681 
1691 int check_pick(object *op) {
1692  tag_t op_tag;
1693  int stop = 0;
1694  int j, k, wvratio, current_ratio;
1695  char putstring[128], tmpstr[16];
1696 
1697  /* if you're flying, you can't pick up anything */
1698  if (op->move_type&MOVE_FLYING)
1699  return 1;
1700  /* If not a player, don't check anything. */
1701  if (!op->contr) {
1702  return 1;
1703  }
1704 
1705  op_tag = op->count;
1706 
1707  FOR_BELOW_PREPARE(op, tmp) {
1708  if (object_was_destroyed(op, op_tag))
1709  return 0;
1710 
1711  if (!object_can_pick(op, tmp))
1712  continue;
1713 
1714  if (op->contr->search_str[0] != '\0' && settings.search_items == TRUE) {
1715  if (object_matches_string(op, tmp, op->contr->search_str))
1716  pick_up(op, tmp);
1717  continue;
1718  }
1719 
1720  /* high not bit set? We're using the old autopickup model */
1721  if (!(op->contr->mode&PU_NEWMODE)) {
1722  switch (op->contr->mode) {
1723  case 0:
1724  return 1; /* don't pick up */
1725 
1726  case 1:
1727  pick_up(op, tmp);
1728  return 1;
1729 
1730  case 2:
1731  pick_up(op, tmp);
1732  return 0;
1733 
1734  case 3:
1735  return 0; /* stop before pickup */
1736 
1737  case 4:
1738  pick_up(op, tmp);
1739  break;
1740 
1741  case 5:
1742  pick_up(op, tmp);
1743  stop = 1;
1744  break;
1745 
1746  case 6:
1747  if (QUERY_FLAG(tmp, FLAG_KNOWN_MAGICAL)
1748  && !QUERY_FLAG(tmp, FLAG_KNOWN_CURSED))
1749  pick_up(op, tmp);
1750  break;
1751 
1752  case 7:
1753  if (tmp->type == MONEY || tmp->type == GEM)
1754  pick_up(op, tmp);
1755  break;
1756 
1757  default:
1758  /* use value density */
1759  if (!QUERY_FLAG(tmp, FLAG_UNPAID)
1760  && (price_base(tmp)*100/(tmp->weight*MAX(tmp->nrof, 1))) >= op->contr->mode)
1761  pick_up(op, tmp);
1762  }
1763  } else { /* old model */
1764  /* NEW pickup handling */
1765  if (op->contr->mode&PU_DEBUG) {
1766  /* some debugging code to figure out item information */
1768  "item name: %s item type: %d weight/value: %d",
1769  tmp->name ? tmp->name : tmp->arch->name, tmp->type,
1770  (int)(price_base(tmp)*100/(tmp->weight*MAX(tmp->nrof, 1))));
1771 
1772 
1773  snprintf(putstring, sizeof(putstring), "...flags: ");
1774  for (k = 0; k < 4; k++) {
1775  for (j = 0; j < 32; j++) {
1776  if ((tmp->flags[k]>>j)&0x01) {
1777  snprintf(tmpstr, sizeof(tmpstr), "%d ", k*32+j);
1778  strcat(putstring, tmpstr);
1779  }
1780  }
1781  }
1783  putstring);
1784  }
1785  /* philosophy:
1786  * It's easy to grab an item type from a pile, as long as it's
1787  * generic. This takes no game-time. For more detailed pickups
1788  * and selections, select-items should be used. This is a
1789  * grab-as-you-run type mode that's really useful for arrows for
1790  * example.
1791  * The drawback: right now it has no frontend, so you need to
1792  * stick the bits you want into a calculator in hex mode and then
1793  * convert to decimal and then 'pickup <#>
1794  */
1795 
1796  /* the first two modes are exclusive: if NOTHING we return, if
1797  * STOP then we stop. All the rest are applied sequentially,
1798  * meaning if any test passes, the item gets picked up. */
1799 
1800  /* if mode is set to pick nothing up, return */
1801 
1802  if (op->contr->mode == PU_NOTHING)
1803  return 1;
1804 
1805  /* if mode is set to stop when encountering objects, return.
1806  * Take STOP before INHIBIT since it doesn't actually pick
1807  * anything up */
1808 
1809  if (op->contr->mode&PU_STOP)
1810  return 0;
1811 
1812  /* useful for going into stores and not losing your settings... */
1813  /* and for battles where you don't want to get loaded down while
1814  * fighting */
1815  if (op->contr->mode&PU_INHIBIT)
1816  return 1;
1817 
1818  /* prevent us from turning into auto-thieves :) */
1819  if (QUERY_FLAG(tmp, FLAG_UNPAID))
1820  continue;
1821 
1822  /* ignore known cursed objects */
1824  continue;
1825 
1826  /* all food and drink if desired */
1827  /* question: don't pick up known-poisonous stuff? */
1828  if (op->contr->mode&PU_FOOD)
1829  if (tmp->type == FOOD) {
1830  pick_up(op, tmp);
1831  continue;
1832  }
1833  if (op->contr->mode&PU_DRINK)
1834  if (tmp->type == DRINK || (tmp->type == POISON && !QUERY_FLAG(tmp, FLAG_KNOWN_CURSED))) {
1835  pick_up(op, tmp);
1836  continue;
1837  }
1838  /* we don't forget dragon food */
1839  if (op->contr->mode&PU_FLESH)
1840  if (tmp->type == FLESH) {
1841  pick_up(op, tmp);
1842  continue;
1843  }
1844  if (op->contr->mode&PU_POTION)
1845  if (tmp->type == POTION) {
1846  pick_up(op, tmp);
1847  continue;
1848  }
1849 
1850  /* spellbooks, skillscrolls and normal books/scrolls */
1851  if (op->contr->mode&PU_SPELLBOOK)
1852  if (tmp->type == SPELLBOOK) {
1853  pick_up(op, tmp);
1854  continue;
1855  }
1856  if (op->contr->mode&PU_SKILLSCROLL)
1857  if (tmp->type == SKILLSCROLL) {
1858  pick_up(op, tmp);
1859  continue;
1860  }
1861  if (op->contr->mode&PU_READABLES)
1862  if (tmp->type == BOOK || tmp->type == SCROLL) {
1863  pick_up(op, tmp);
1864  continue;
1865  }
1866 
1867  /* wands/staves/rods/horns/skill tools */
1868  if (op->contr->mode&PU_MAGIC_DEVICE)
1869  if (tmp->type == WAND || tmp->type == ROD || tmp->type == WEAPON_IMPROVER || tmp->type == ARMOUR_IMPROVER || tmp->type == SKILL_TOOL) {
1870  pick_up(op, tmp);
1871  continue;
1872  }
1873 
1874  /* pick up all magical items */
1875  if (op->contr->mode&PU_MAGICAL)
1877  pick_up(op, tmp);
1878  continue;
1879  }
1880 
1881  if (op->contr->mode&PU_VALUABLES) {
1882  if (tmp->type == MONEY || tmp->type == GEM) {
1883  pick_up(op, tmp);
1884  continue;
1885  }
1886  }
1887 
1888  /* rings & amulets - talismans seems to be typed AMULET */
1889  if (op->contr->mode&PU_JEWELS)
1890  if (tmp->type == RING || tmp->type == AMULET) {
1891  pick_up(op, tmp);
1892  continue;
1893  }
1894 
1895  /* bows and arrows. Bows are good for selling! */
1896  if (op->contr->mode&PU_BOW)
1897  if (tmp->type == BOW) {
1898  pick_up(op, tmp);
1899  continue;
1900  }
1901  if (op->contr->mode&PU_ARROW)
1902  if (tmp->type == ARROW) {
1903  pick_up(op, tmp);
1904  continue;
1905  }
1906 
1907  /* all kinds of armor etc. */
1908  if (op->contr->mode&PU_ARMOUR)
1909  if (tmp->type == ARMOUR) {
1910  pick_up(op, tmp);
1911  continue;
1912  }
1913  if (op->contr->mode&PU_HELMET)
1914  if (tmp->type == HELMET) {
1915  pick_up(op, tmp);
1916  continue;
1917  }
1918  if (op->contr->mode&PU_SHIELD)
1919  if (tmp->type == SHIELD) {
1920  pick_up(op, tmp);
1921  continue;
1922  }
1923  if (op->contr->mode&PU_BOOTS)
1924  if (tmp->type == BOOTS) {
1925  pick_up(op, tmp);
1926  continue;
1927  }
1928  if (op->contr->mode&PU_GLOVES)
1929  if (tmp->type == GLOVES) {
1930  pick_up(op, tmp);
1931  continue;
1932  }
1933  if (op->contr->mode&PU_CLOAK)
1934  if (tmp->type == CLOAK) {
1935  pick_up(op, tmp);
1936  continue;
1937  }
1938 
1939  /* hoping to catch throwing daggers here */
1940  if (op->contr->mode&PU_MISSILEWEAPON)
1941  if (tmp->type == WEAPON && QUERY_FLAG(tmp, FLAG_IS_THROWN)) {
1942  pick_up(op, tmp);
1943  continue;
1944  }
1945 
1946  /* careful: chairs and tables are weapons! */
1947  /* Note that tables and chairs have been changed to not be weapons as of 2011. */
1948  if (op->contr->mode&PU_MELEEWEAPON) {
1949  // The code here used to handle avoiding tables and chairs.
1950  // Since there have been many server-arch prerequisites since the change,
1951  // we should be good not handling them here.
1952  // SilverNexus 2018-12-30
1953  if (tmp->type == WEAPON) {
1954  pick_up(op, tmp);
1955  continue;
1956  }
1957  }
1958 
1959  /* misc stuff that's useful */
1960  if (op->contr->mode&PU_KEY)
1961  if (tmp->type == KEY || tmp->type == SPECIAL_KEY) {
1962  pick_up(op, tmp);
1963  continue;
1964  }
1965 
1966  if (op->contr->mode&PU_CONTAINER && tmp->type == CONTAINER) {
1967  pick_up(op, tmp);
1968  continue;
1969  }
1970 
1971  /* any of the last 4 bits set means we use the ratio for value
1972  * pickups */
1973  if (op->contr->mode&PU_RATIO) {
1974  /* use value density to decide what else to grab.
1975  * >=7 was >= op->contr->mode
1976  * >=7 is the old standard setting. Now we take the last 4 bits
1977  * and multiply them by 5, giving 0..15*5== 5..75 */
1978  wvratio = (op->contr->mode&PU_RATIO)*5;
1979  current_ratio = price_base(tmp)*100/(tmp->weight*MAX(tmp->nrof, 1));
1980  if (current_ratio >= wvratio) {
1981  pick_up(op, tmp);
1982  continue;
1983  }
1984  }
1985  } /* the new pickup model */
1986  } FOR_BELOW_FINISH();
1987  return !stop;
1988 }
1989 
2002 static object *find_arrow(object *op, const char *type) {
2003  object *tmp = NULL;
2004 
2005  FOR_INV_PREPARE(op, inv)
2006  if (!tmp
2007  && inv->type == CONTAINER
2008  && inv->race == type
2009  && QUERY_FLAG(inv, FLAG_APPLIED))
2010  tmp = find_arrow(inv, type);
2011  else if (inv->type == ARROW && inv->race == type)
2012  return inv;
2013  FOR_INV_FINISH();
2014  return tmp;
2015 }
2016 
2034 static object *find_better_arrow(object *op, object *target, const char *type, int *better) {
2035  object *tmp = NULL, *ntmp;
2036  int attacknum, attacktype, betterby = 0, i;
2037 
2038  if (!type)
2039  return NULL;
2040 
2041  FOR_INV_PREPARE(op, arrow) {
2042  if (arrow->type == CONTAINER
2043  && arrow->race == type
2044  && QUERY_FLAG(arrow, FLAG_APPLIED)) {
2045  i = 0;
2046  ntmp = find_better_arrow(arrow, target, type, &i);
2047  if (i > betterby) {
2048  tmp = ntmp;
2049  betterby = i;
2050  }
2051  } else if (arrow->type == ARROW && arrow->race == type) {
2052  /* always prefer assassination/slaying */
2053  if (target->race != NULL
2054  && arrow->slaying != NULL
2055  && strstr(arrow->slaying, target->race)) {
2056  if (arrow->attacktype&AT_DEATH) {
2057  if (better)
2058  *better = 100;
2059  return arrow;
2060  } else {
2061  tmp = arrow;
2062  betterby = (arrow->magic+arrow->stats.dam)*2;
2063  }
2064  } else {
2065  for (attacknum = 0; attacknum < NROFATTACKS; attacknum++) {
2066  attacktype = 1<<attacknum;
2067  if ((arrow->attacktype&attacktype) && (target->arch->clone.resist[attacknum]) < 0)
2068  if (((arrow->magic+arrow->stats.dam)*(100-target->arch->clone.resist[attacknum])/100) > betterby) {
2069  tmp = arrow;
2070  betterby = (arrow->magic+arrow->stats.dam)*(100-target->arch->clone.resist[attacknum])/100;
2071  }
2072  }
2073  if ((2+arrow->magic+arrow->stats.dam) > betterby) {
2074  tmp = arrow;
2075  betterby = 2+arrow->magic+arrow->stats.dam;
2076  }
2077  if (arrow->title && (1+arrow->magic+arrow->stats.dam) > betterby) {
2078  tmp = arrow;
2079  betterby = 1+arrow->magic+arrow->stats.dam;
2080  }
2081  }
2082  }
2083  } FOR_INV_FINISH();
2084  if (tmp == NULL)
2085  return find_arrow(op, type);
2086 
2087  if (better)
2088  *better = betterby;
2089  return tmp;
2090 }
2091 
2104 static object *pick_arrow_target(object *op, const char *type, int dir) {
2105  object *tmp = NULL;
2106  mapstruct *m;
2107  int i, mflags, found, number;
2108  int16_t x, y;
2109 
2110  if (op->map == NULL)
2111  return find_arrow(op, type);
2112 
2113  /* do a dex check */
2114  number = (die_roll(2, 40, op, PREFER_LOW)-2)/2;
2115  if (number > (op->stats.Dex+(op->chosen_skill ? op->chosen_skill->level : op->level)))
2116  return find_arrow(op, type);
2117 
2118  m = op->map;
2119  x = op->x;
2120  y = op->y;
2121 
2122  /* find the first target */
2123  for (i = 0, found = 0; i < 20; i++) {
2124  x += freearr_x[dir];
2125  y += freearr_y[dir];
2126  mflags = get_map_flags(m, &m, x, y, &x, &y);
2127  if (mflags&P_OUT_OF_MAP || mflags&P_BLOCKSVIEW) {
2128  tmp = NULL;
2129  break;
2130  } else if (GET_MAP_MOVE_BLOCK(m, x, y) == MOVE_FLY_LOW) {
2131  /* This block presumes arrows and the like are MOVE_FLY_SLOW -
2132  * perhaps a bad assumption.
2133  */
2134  tmp = NULL;
2135  break;
2136  }
2137  if (mflags&P_IS_ALIVE) {
2138  FOR_MAP_PREPARE(m, x, y, tmp2)
2139  if (QUERY_FLAG(tmp2, FLAG_ALIVE)) {
2140  tmp = tmp2;
2141  found++;
2142  break;
2143  }
2144  FOR_MAP_FINISH();
2145  if (found)
2146  break;
2147  }
2148  }
2149  if (tmp == NULL)
2150  return find_arrow(op, type);
2151 
2152  return find_better_arrow(op, HEAD(tmp), type, NULL);
2153 }
2154 
2173 int fire_bow(object *op, object *arrow, int dir, int wc_mod, int16_t sx, int16_t sy) {
2174  object *bow;
2175  tag_t tag;
2176  int bowspeed, mflags;
2177  mapstruct *m;
2178 
2179  if (!dir) {
2181  "You can't shoot yourself!");
2182  return 0;
2183  }
2184  if (op->type == PLAYER)
2185  bow = op->contr->ranges[range_bow];
2186  else {
2187  /* Don't check for applied - monsters don't apply bows - in that way, they
2188  * don't need to switch back and forth between bows and weapons.
2189  */
2190  bow = object_find_by_type(op, BOW);
2191  if (!bow) {
2192  LOG(llevError, "Range: bow without activated bow (%s).\n", op->name);
2193  return 0;
2194  }
2195  }
2196  if (!bow->race || !bow->skill) {
2198  "Your %s is broken.",
2199  bow->name);
2200  return 0;
2201  }
2202 
2203  bowspeed = bow->stats.sp+get_dex_bonus(op->stats.Dex);
2204 
2205  /* penalize ROF for bestarrow */
2206  if (op->type == PLAYER && op->contr->bowtype == bow_bestarrow)
2207  bowspeed -= get_dex_bonus(op->stats.Dex)+5;
2208  if (bowspeed < 1)
2209  bowspeed = 1;
2210 
2211  if (arrow == NULL) {
2212  arrow = find_arrow(op, bow->race);
2213  if (arrow == NULL) {
2214  if (op->type == PLAYER)
2217  "You have no %s left.",
2218  bow->race);
2219  /* FLAG_READY_BOW will get reset if the monsters picks up some arrows */
2220  else
2222  return 0;
2223  }
2224  }
2225  mflags = get_map_flags(op->map, &m, sx, sy, &sx, &sy);
2226  if (mflags&P_OUT_OF_MAP) {
2227  return 0;
2228  }
2229  if (GET_MAP_MOVE_BLOCK(m, sx, sy)&MOVE_FLY_LOW) {
2230  return 0;
2231  }
2232 
2233  /* this should not happen, but sometimes does */
2234  if (arrow->nrof == 0) {
2235  object_remove(arrow);
2237  return 0;
2238  }
2239 
2240  arrow = object_split(arrow, 1, NULL, 0);
2241  if (arrow == NULL) {
2243  "You have no %s left.",
2244  bow->race);
2245  return 0;
2246  }
2247  object_set_owner(arrow, op);
2248  if (arrow->skill)
2249  free_string(arrow->skill);
2250  arrow->skill = add_refcount(bow->skill);
2251 
2252  arrow->direction = dir;
2253 
2254  if (op->type == PLAYER) {
2255  op->speed_left = 0.01-(float)FABS(op->speed)*100/bowspeed;
2256  fix_object(op);
2257  }
2258 
2259  if (bow->anim_suffix != NULL)
2260  apply_anim_suffix(op, bow->anim_suffix);
2261 
2262 /* SET_ANIMATION(arrow, arrow->direction);*/
2263  object_update_turn_face(arrow);
2264  arrow->stats.sp = arrow->stats.wc; /* save original wc and dam */
2265  arrow->stats.hp = arrow->stats.dam;
2266  arrow->stats.grace = arrow->attacktype;
2267  if (arrow->slaying != NULL)
2268  arrow->spellarg = strdup_local(arrow->slaying);
2269 
2270  /* Note that this was different for monsters - they got their level
2271  * added to the damage. I think the strength bonus is more proper.
2272  */
2273 
2274  arrow->stats.dam += (QUERY_FLAG(bow, FLAG_NO_STRENGTH) ? 0 : get_dam_bonus(op->stats.Str))
2275  +bow->stats.dam
2276  +bow->magic
2277  +arrow->magic;
2278 
2279  /* update the speed */
2280  arrow->speed = (float)((QUERY_FLAG(bow, FLAG_NO_STRENGTH) ? 0 : get_dam_bonus(op->stats.Str))+bow->magic+arrow->magic)/5.0
2281  +(float)bow->stats.dam/7.0;
2282 
2283  if (arrow->speed < 1.0)
2284  arrow->speed = 1.0;
2285  object_update_speed(arrow);
2286  arrow->speed_left = 0;
2287 
2288  if (op->type == PLAYER) {
2289  /* we don't want overflows of wc (sint), so cap the value - mod and pl should be subtracted */
2290  int mod = bow->magic
2291  +arrow->magic
2292  +get_dex_bonus(op->stats.Dex)
2293  +get_thaco_bonus(op->stats.Str)
2294  +arrow->stats.wc
2295  +bow->stats.wc
2296  -wc_mod;
2297  int plmod = (op->chosen_skill ? op->chosen_skill->level : op->level);
2298  if (plmod+mod > 140)
2299  plmod = 140-mod;
2300  else if (plmod+mod < -100)
2301  plmod = -100-mod;
2302  arrow->stats.wc = 20-(int8_t)plmod-(int8_t)mod;
2303 
2304  arrow->level = op->chosen_skill ? op->chosen_skill->level : op->level;
2305  } else {
2306  arrow->stats.wc = op->stats.wc
2307  -bow->magic
2308  -arrow->magic
2309  -arrow->stats.wc
2310  +wc_mod;
2311 
2312  arrow->level = op->level;
2313  }
2314  if (arrow->attacktype == AT_PHYSICAL)
2315  arrow->attacktype |= bow->attacktype;
2316  if (bow->slaying != NULL)
2317  arrow->slaying = add_string(bow->slaying);
2318 
2319  /* If move_type is ever changed, monster.c:monster_use_bow() needs to be changed too. */
2320  arrow->move_type = MOVE_FLY_LOW;
2321  arrow->move_on = MOVE_FLY_LOW|MOVE_WALK;
2322 
2323  tag = arrow->count;
2324  object_insert_in_map_at(arrow, m, op, 0, sx, sy);
2325 
2326  if (!object_was_destroyed(arrow, tag)) {
2327  play_sound_map(SOUND_TYPE_ITEM, arrow, arrow->direction, "fire");
2328  ob_process(arrow);
2329  }
2330 
2331  return 1;
2332 }
2333 
2344 static int similar_direction(int a, int b) {
2345  /* shortcut the obvious */
2346  if (a == b)
2347  return 1;
2348  /* Made this cleaner using modulus instead of a switch statement
2349  * We only needed the direction and the two adjacent to it
2350  * (8 is adjacent to 1 here) to return true, so a - 1, a, and a + 1
2351  * are the three directions that get "similar" affirmed.
2352  * -- Daniel Hawkins 2015-05-28
2353  */
2354  // The last one for the offset is added afterwards so we get
2355  // 1-8 instead of 0-7 (specifically, 0 becomes 8 without changing
2356  // the other values).
2357  if ((a % 8) + 1 == b || (a + 6 % 8) + 1 == b)
2358  return 1;
2359  return 0;
2360 }
2361 
2378 static int player_fire_bow(object *op, int dir) {
2379  int ret = 0, wcmod = 0;
2380 
2381  if (op->contr->bowtype == bow_bestarrow) {
2382  ret = fire_bow(op, pick_arrow_target(op, op->contr->ranges[range_bow]->race, dir), dir, 0, op->x, op->y);
2383  } else if (op->contr->bowtype >= bow_n && op->contr->bowtype <= bow_nw) {
2384  if (!similar_direction(dir, op->contr->bowtype-bow_n+1))
2385  wcmod = -1;
2386  ret = fire_bow(op, NULL, op->contr->bowtype-bow_n+1, wcmod, op->x, op->y);
2387  } else if (op->contr->bowtype == bow_threewide) {
2388  ret = fire_bow(op, NULL, dir, 0, op->x, op->y);
2389  ret |= fire_bow(op, NULL, dir, -5, op->x+freearr_x[absdir(dir+2)], op->y+freearr_y[absdir(dir+2)]);
2390  ret |= fire_bow(op, NULL, dir, -5, op->x+freearr_x[absdir(dir-2)], op->y+freearr_y[absdir(dir-2)]);
2391  } else if (op->contr->bowtype == bow_spreadshot) {
2392  ret |= fire_bow(op, NULL, dir, 0, op->x, op->y);
2393  ret |= fire_bow(op, NULL, absdir(dir-1), -5, op->x, op->y);
2394  ret |= fire_bow(op, NULL, absdir(dir+1), -5, op->x, op->y);
2395  } else {
2396  /* Simple case */
2397  ret = fire_bow(op, NULL, dir, 0, op->x, op->y);
2398  }
2399  return ret;
2400 }
2401 
2414 static void fire_misc_object(object *op, int dir) {
2415  object *item;
2416  char name[MAX_BUF];
2417 
2418  item = op->contr->ranges[range_misc];
2419  if (!item) {
2421  "You have no range item readied.");
2422  return;
2423  }
2424  if (!item->inv) {
2425  LOG(llevError, "Object %s lacks a spell\n", item->name);
2426  return;
2427  }
2428  if (item->type == WAND) {
2429  if (item->stats.food <= 0) {
2430  play_sound_player_only(op->contr, SOUND_TYPE_ITEM, item, 0, "poof");
2431  query_base_name(item, 0, name, MAX_BUF);
2433  "The %s goes poof.",
2434  name);
2435  return;
2436  }
2437  } else if (item->type == ROD) {
2438  if (item->stats.hp < SP_level_spellpoint_cost(item, item->inv, SPELL_HIGHEST)) {
2439  play_sound_player_only(op->contr, SOUND_TYPE_ITEM, item, 0, "poof");
2440  query_base_name(item, 0, name, MAX_BUF);
2442  "The %s whines for a while, but nothing happens.",
2443  name);
2444  return;
2445  }
2446  }
2447 
2448  if (cast_spell(op, item, dir, item->inv, NULL)) {
2449  SET_FLAG(op, FLAG_BEEN_APPLIED); /* You now know something about it */
2450  if (item->type == WAND) {
2451  drain_wand_charge(item);
2452  } else if (item->type == ROD) {
2453  drain_rod_charge(item);
2454  }
2455  }
2456 }
2457 
2466 void fire(object *op, int dir) {
2467 
2468  /* check for loss of invisiblity/hide */
2469  if (action_makes_visible(op))
2470  make_visible(op);
2471 
2472  switch (op->contr->shoottype) {
2473  case range_none:
2474  return;
2475 
2476  case range_bow:
2477  player_fire_bow(op, dir);
2478  return;
2479 
2480  case range_magic: /* Casting spells */
2481  cast_spell(op, op, dir, op->contr->ranges[range_magic], op->contr->spellparam[0] ? op->contr->spellparam : NULL);
2482  return;
2483 
2484  case range_misc:
2485  fire_misc_object(op, dir);
2486  return;
2487 
2488  case range_golem: /* Control summoned monsters from scrolls */
2489  if (op->contr->ranges[range_golem] == NULL
2490  || op->contr->golem_count != op->contr->ranges[range_golem]->count) {
2491  op->contr->ranges[range_golem] = NULL;
2492  op->contr->shoottype = range_none;
2493  op->contr->golem_count = 0;
2494  } else
2496  return;
2497 
2498  case range_skill:
2499  if (!op->chosen_skill) {
2500  if (op->type == PLAYER)
2502  "You have no applicable skill to use.");
2503  return;
2504  }
2505  (void)do_skill(op, op, op->chosen_skill, dir, NULL);
2506  return;
2507 
2508  case range_builder:
2509  apply_map_builder(op, dir);
2510  return;
2511 
2512  default:
2514  "Illegal shoot type.");
2515  return;
2516  }
2517 }
2518 
2538 object *find_key(object *pl, object *container, object *door) {
2539  object *tmp, *key;
2540 
2541  /* Should not happen, but sanity checking is never bad */
2542  if (container->inv == NULL)
2543  return NULL;
2544 
2545  /* First, lets try to find a key in the top level inventory */
2546  tmp = NULL;
2547  if (door->type == DOOR) {
2548  int flag = FLAG_UNPAID;
2549  tmp = object_find_by_type_without_flags(container, KEY, &flag, 1);
2550  }
2551  /* For sanity, we should really check door type, but other stuff
2552  * (like containers) can be locked with special keys
2553  */
2554  if (!tmp && door->slaying != NULL) {
2555  tmp = object_find_by_type_and_slaying(container, SPECIAL_KEY, door->slaying);
2556  }
2557  /* No key found - lets search inventories now */
2558  /* If we find and use a key in an inventory, return at that time.
2559  * otherwise, if we search all the inventories and still don't find
2560  * a key, return
2561  */
2562  if (!tmp) {
2563  FOR_INV_PREPARE(container, tmp) {
2564  /* No reason to search empty containers */
2565  if (tmp->type == CONTAINER && tmp->inv) {
2566  key = find_key(pl, tmp, door);
2567  if (key != NULL)
2568  return key;
2569  }
2570  } FOR_INV_FINISH();
2571  return NULL;
2572  }
2573  /* We get down here if we have found a key. Now if its in a container,
2574  * see if we actually want to use it
2575  */
2576  if (pl != container) {
2577  /* Only let players use keys in containers */
2578  if (!pl->contr)
2579  return NULL;
2580  /* cases where this fails:
2581  * If we only search the player inventory, return now since we
2582  * are not in the players inventory.
2583  * If the container is not active, return now since only active
2584  * containers can be used.
2585  * If we only search keyrings and the container does not have
2586  * a race/isn't a keyring.
2587  * No checking for all containers - to fall through past here,
2588  * inv must have been an container and must have been active.
2589  *
2590  * Change the color so that the message doesn't disappear with
2591  * all the others.
2592  */
2593  if (pl->contr->usekeys == key_inventory
2594  || !QUERY_FLAG(container, FLAG_APPLIED)
2595  || (pl->contr->usekeys == keyrings && (!container->race || strcmp(container->race, "keys")))) {
2596  char name_tmp[MAX_BUF], name_cont[MAX_BUF];
2597 
2598  query_name(tmp, name_tmp, MAX_BUF);
2599  query_name(container, name_cont, MAX_BUF);
2602  "The %s in your %s vibrates as you approach the door",
2603  name_tmp, name_cont);
2604  return NULL;
2605  }
2606  }
2607  return tmp;
2608 }
2609 
2620 static int player_attack_door(object *op, object *door) {
2621  /* If its a door, try to find a use a key. If we do destroy the door,
2622  * might as well return immediately as there is nothing more to do -
2623  * otherwise, we fall through to the rest of the code.
2624  */
2625  object *key = find_key(op, op, door);
2626 
2627  assert(door->type == DOOR || door->type == LOCKED_DOOR);
2628 
2629  /* IF we found a key, do some extra work */
2630  if (key) {
2631  char name[HUGE_BUF];
2632 
2633  play_sound_map(SOUND_TYPE_GROUND, door, 0, "open");
2634  if (action_makes_visible(op))
2635  make_visible(op);
2636  if (door->inv && (door->inv->type == RUNE || door->inv->type == TRAP))
2637  spring_trap(door->inv, op);
2638 
2639  query_short_name(key, name, HUGE_BUF);
2642  "You open the door with the %s",
2643  name);
2644 
2645  if (door->type == DOOR)
2646  remove_door(door);
2647  else
2648  remove_locked_door(door); /* remove door without violence ;-) */
2649 
2650  /* Do this after we print the message */
2651  object_decrease_nrof_by_one(key); /* Use up one of the keys */
2652 
2653  return 1; /* Nothing more to do below */
2654 
2655  }
2656 
2657  if (door->type == LOCKED_DOOR) {
2658  /* Might as well return now - no other way to open this */
2660  door->msg);
2661  return 1;
2662  }
2663 
2664  if (door->type == DOOR && op->contr && !op->contr->run_on) {
2665  /* Player so try to pick the door */
2666  object *lock = find_skill_by_name(op, "lockpicking");
2667  if (lock) {
2668  /* Even if the lockpicking failed, don't go on moving, player should explicitely attack or run
2669  * to bash the door. */
2670  do_skill(op, op, lock, op->facing, NULL);
2671  return 1;
2672  }
2673  }
2674 
2675  return 0;
2676 }
2677 
2691 void move_player_attack(object *op, int dir) {
2692  object *mon, *tpl, *mon_owner;
2693  int16_t nx, ny;
2694  int on_battleground;
2695  mapstruct *m;
2696 
2697  if (op->contr->transport)
2698  tpl = op->contr->transport;
2699  else
2700  tpl = op;
2701  assert(tpl->map != NULL); // op must be on a map in order to move it
2702  nx = freearr_x[dir]+tpl->x;
2703  ny = freearr_y[dir]+tpl->y;
2704 
2705  on_battleground = op_on_battleground(tpl, NULL, NULL, NULL);
2706 
2707  // Temporarily store the map we are on before movement.
2708  mapstruct *bef = tpl->map;
2709 
2710  /* If braced, or can't move to the square, and it is not out of the
2711  * map, attack it. Note order of if statement is important - don't
2712  * want to be calling move_ob if braced, because move_ob will move the
2713  * player. This is a pretty nasty hack, because if we could
2714  * move to some space, it then means that if we are braced, we should
2715  * do nothing at all. As it is, if we are braced, we go through
2716  * quite a bit of processing. However, it probably is less than what
2717  * move_ob uses.
2718  */
2719  if ((op->contr->braced || !move_ob(tpl, dir, tpl)) && !out_of_map(tpl->map, nx, ny)) {
2720  if (OUT_OF_REAL_MAP(tpl->map, nx, ny)) {
2721  m = get_map_from_coord(tpl->map, &nx, &ny);
2722  if (!m)
2723  return; /* Don't think this should happen */
2724  } else
2725  m = tpl->map;
2726 
2727  if (GET_MAP_OB(m, nx, ny) == NULL) {
2728  /* LOG(llevError, "player_move_attack: GET_MAP_OB returns NULL, but player can not move there.\n");*/
2729  return;
2730  }
2731 
2732  mon = NULL;
2733  /* Go through all the objects, and find ones of interest. Only stop if
2734  * we find a monster - that is something we know we want to attack.
2735  * if its a door or barrel (can roll) see if there may be monsters
2736  * on the space
2737  */
2738  FOR_MAP_PREPARE(m, nx, ny, tmp) {
2739  if (tmp == op) {
2740  continue;
2741  }
2742  if (QUERY_FLAG(tmp, FLAG_ALIVE)) {
2743  mon = tmp;
2744  /* Gros: Objects like (pass-through) doors are alive, but haven't
2745  * their monster flag set - so this is a good way attack real
2746  * monsters in priority.
2747  */
2748  if (QUERY_FLAG(tmp, FLAG_MONSTER))
2749  break;
2750  }
2751  if (tmp->type == LOCKED_DOOR || QUERY_FLAG(tmp, FLAG_CAN_ROLL))
2752  mon = tmp;
2753  } FOR_MAP_FINISH();
2754 
2755  if (mon == NULL) /* This happens anytime the player tries to move */
2756  return; /* into a wall */
2757 
2758  mon = HEAD(mon);
2759  if ((mon->type == DOOR && mon->stats.hp >= 0) || (mon->type == LOCKED_DOOR))
2760  if (player_attack_door(op, mon))
2761  return;
2762 
2763  /* The following deals with possibly attacking peaceful
2764  * or friendly creatures. Basically, all players are considered
2765  * unaggressive. If the moving player has peaceful set, then the
2766  * object should be pushed instead of attacked. It is assumed that
2767  * if you are braced, you will not attack friends accidently,
2768  * and thus will not push them.
2769  */
2770 
2771  /* If the creature is a pet, push it even if the player is not
2772  * peaceful. Our assumption is the creature is a pet if the
2773  * player owns it and it is either friendly or unaggressive.
2774  */
2775  mon_owner = object_get_owner(mon);
2776  if ((op->type == PLAYER)
2777  && (mon_owner == op || (mon_owner != NULL && mon_owner->type == PLAYER && mon_owner->contr->party != NULL && mon_owner->contr->party == op->contr->party))
2778  && (QUERY_FLAG(mon, FLAG_UNAGGRESSIVE) || QUERY_FLAG(mon, FLAG_FRIENDLY))) {
2779  /* If we're braced, we don't want to switch places with it */
2780  if (op->contr->braced)
2781  return;
2782  play_sound_map(SOUND_TYPE_LIVING, mon, dir, "push");
2783  (void)push_ob(mon, dir, op);
2784  if (op->contr->tmp_invis || op->hide)
2785  make_visible(op);
2786  return;
2787  }
2788 
2789  /* in certain circumstances, you shouldn't attack friendly
2790  * creatures. Note that if you are braced, you can't push
2791  * someone, but put it inside this loop so that you won't
2792  * attack them either.
2793  */
2794  if ((mon->type == PLAYER || mon->enemy != op)
2795  && (mon->type == PLAYER || QUERY_FLAG(mon, FLAG_UNAGGRESSIVE) || QUERY_FLAG(mon, FLAG_FRIENDLY))
2796  && (op->contr->peaceful && !on_battleground)) {
2797  if (!op->contr->braced) {
2798  play_sound_map(SOUND_TYPE_LIVING, mon, dir, "push");
2799  (void)push_ob(mon, dir, op);
2800  } else {
2802  "You withhold your attack");
2803  }
2804  if (op->contr->tmp_invis || op->hide)
2805  make_visible(op);
2806  }
2807 
2808  /* If the object is a boulder or other rollable object, then
2809  * roll it if not braced. You can't roll it if you are braced.
2810  */
2811  else if (QUERY_FLAG(mon, FLAG_CAN_ROLL) && (!op->contr->braced)) {
2812  recursive_roll(mon, dir, op);
2813  if (action_makes_visible(op))
2814  make_visible(op);
2815 
2816  /* Any generic living creature. Including things like doors.
2817  * Way it works is like this: First, it must have some hit points
2818  * and be living. Then, it must be one of the following:
2819  * 1) Not a player, 2) A player, but of a different party. Note
2820  * that party_number -1 is no party, so attacks can still happen.
2821  */
2822  } else if ((mon->stats.hp >= 0)
2823  && QUERY_FLAG(mon, FLAG_ALIVE)
2824  && ((mon->type != PLAYER || op->contr->party == NULL || op->contr->party != mon->contr->party))) {
2825  /* If the player hasn't hit something this tick, and does
2826  * so, give them speed boost based on weapon speed. Doing
2827  * it here is better than process_players2, which basically
2828  * incurred a 1 tick offset.
2829  */
2830  if (op->weapon_speed_left < 0) {
2831  op->speed_left = -0.01;
2832  return;
2833  }
2834  op->weapon_speed_left -= 1.0;
2835 
2836  skill_attack(mon, op, 0, NULL, NULL);
2837 
2838  /* If attacking another player, that player gets automatic
2839  * hitback, and doesn't loose luck either.
2840  * Disable hitback on the battleground or if the target is
2841  * the wiz.
2842  */
2843  if (mon->type == PLAYER
2844  && mon->stats.hp >= 0
2845  && !mon->contr->has_hit
2846  && !on_battleground
2847  && !QUERY_FLAG(mon, FLAG_WIZ)) {
2848  short luck = mon->stats.luck;
2849  mon->contr->has_hit = 1;
2850  skill_attack(op, mon, 0, NULL, NULL);
2851  mon->stats.luck = luck;
2852  }
2853  if (action_makes_visible(op))
2854  make_visible(op);
2855  }
2856  } /* if player should attack something */
2857  else if (bef != tpl->map) {
2858  player_map_change_common(op, bef, tpl->map);
2859  }
2860 }
2861 
2868 static void update_transport_block(object *transport, int dir) {
2869  object *part;
2870  int sx, sy, x, y;
2871 
2872  object_get_multi_size(transport, &sx, &sy, NULL, NULL);
2873  assert(sx == sy);
2874 
2875  if (dir == 1 || dir == 5) {
2876  part = transport;
2877  for (y = 0; y <= sy; y++) {
2878  for (x = 0; x < sx; x++) {
2879  part->move_type = transport->move_type;
2880  part = part->more;
2881  }
2882  part->move_type = 0;
2883  part = part->more;
2884  }
2885  } else if (dir == 3 || dir == 7) {
2886  part = transport;
2887  for (y = 0; y < sy; y++) {
2888  for (x = 0; x <= sx; x++) {
2889  part->move_type = transport->move_type;
2890  part = part->more;
2891  }
2892  }
2893  while (part) {
2894  part->move_type = 0;
2895  part = part->more;
2896  }
2897  } else {
2898  for (part = transport; part; part = part->more) {
2899  part->move_type = transport->move_type;
2900  }
2901  }
2902 }
2903 
2913 static int turn_one_transport(object *transport, object *captain, int dir) {
2914  int x, y, scroll_dir = 0;
2915 
2916  assert(transport->type == TRANSPORT);
2917 
2918  x = transport->x;
2919  y = transport->y;
2920 
2921  if (transport->direction == 1 && dir == 8) {
2922  x--;
2923  } else if (transport->direction == 2 && dir == 3) {
2924  y++;
2925  } else if (transport->direction == 3 && dir == 2) {
2926  y--;
2927  } else if (transport->direction == 5 && dir == 6) {
2928  x--;
2929  } else if (transport->direction == 6 && dir == 5) {
2930  x++;
2931  } else if (transport->direction == 7 && dir == 8) {
2932  y--;
2933  } else if (transport->direction == 8 && dir == 7) {
2934  y++;
2935  } else if (transport->direction == 8 && dir == 1) {
2936  x++;
2937  }
2938 
2939  update_transport_block(transport, dir);
2940  object_remove(transport);
2941  if (ob_blocked(transport, transport->map, x, y)) {
2942  update_transport_block(transport, transport->direction);
2943  object_insert_in_map_at(transport, transport->map, NULL, 0, x, y);
2944  return 2;
2945  }
2946 
2947  if (x != transport->x || y != transport->y) {
2948 /* assert(scroll_dir != 0);*/
2949 
2950  FOR_INV_PREPARE(transport, pl) {
2951  if (pl->type == PLAYER) {
2952  pl->contr->do_los = 1;
2953  pl->map = transport->map;
2954  pl->x = x;
2955  pl->y = y;
2956  esrv_map_scroll(&pl->contr->socket, freearr_x[scroll_dir], freearr_y[scroll_dir]);
2957  pl->contr->socket.update_look = 1;
2958  pl->contr->socket.look_position = 0;
2959  }
2960  } FOR_INV_FINISH();
2961  }
2962 
2963  object_insert_in_map_at(transport, transport->map, NULL, 0, x, y);
2964  transport->direction = dir;
2965  transport->facing = dir;
2966  animate_object(transport, dir);
2967  captain->direction = dir;
2968  return 1;
2969 }
2970 
2983 static int turn_transport(object *transport, object *captain, int dir) {
2984  assert(transport->type == TRANSPORT);
2985 
2986  if (object_get_value(transport, "turnable_transport") == NULL) {
2987  transport->direction = dir;
2988  transport->facing = dir;
2989  if (QUERY_FLAG(transport, FLAG_ANIMATE)) {
2990  animate_object(transport, dir);
2991  }
2992  captain->direction = dir;
2993  return 0;
2994  }
2995 
2996  if (transport->direction == dir)
2997  return 0;
2998 
2999  if (absdir(transport->direction-dir) > 2)
3000  return turn_one_transport(transport, captain, absdir(transport->direction+1));
3001  else
3002  return turn_one_transport(transport, captain, absdir(transport->direction-1));
3003 }
3004 
3016 int move_player(object *op, int dir) {
3017  object *transport = op->contr->transport; //< Transport player is in
3018 
3019  if (!transport && (op->map == NULL || op->map->in_memory != MAP_IN_MEMORY))
3020  return 0;
3021 
3022  /* Sanity check: make sure dir is valid */
3023  if ((dir < 0) || (dir >= 9)) {
3024  LOG(llevError, "move_player: invalid direction %d\n", dir);
3025  return 0;
3026  }
3027 
3028  if (QUERY_FLAG(op, FLAG_CONFUSED) && dir)
3029  dir = get_randomized_dir(dir);
3030 
3031  op->facing = dir;
3032 
3033  if (transport) {
3034  /* transport->contr is set up for the person in charge of the boat.
3035  * if that isn't this person, he can't steer it, etc
3036  */
3037  if (transport->contr != op->contr)
3038  return 0;
3039 
3040  /* Transport is out of movement. But update dir so it at least
3041  * will point in the same direction if player is running.
3042  */
3043  if (transport->speed_left < 0.0) {
3044  return 0;
3045  }
3046  /* Remove transport speed. Give player just a little speed -
3047  * enough so that they will get an action again quickly.
3048  */
3049  transport->speed_left -= 1.0;
3050  if (op->speed_left < 0.0)
3051  op->speed_left = -0.01;
3052 
3053  int turn = turn_transport(transport, op, dir);
3054  if (turn != 0)
3055  return 0;
3056  } else {
3057  if (op->hide) {
3058  do_hidden_move(op);
3059  }
3060 
3061  /* it is important to change the animation now, as fire or move_player_attack can start a compound animation,
3062  * and leave us with state = 0, which we don't want to change again. */
3063  op->state++; /* player moved, so change animation. */
3064  animate_object(op, op->facing);
3065  }
3066 
3067  if (op->contr->fire_on) {
3068  fire(op, dir);
3069  } else
3070  move_player_attack(op, dir);
3071 
3072  int pick = check_pick(op);
3073 
3074  /* Add special check for newcs players and fire on - this way, the
3075  * server can handle repeat firing.
3076  */
3077  if (op->contr->fire_on || (op->contr->run_on && pick != 0)) {
3078  op->direction = dir;
3079  } else {
3080  op->direction = 0;
3081  }
3082  return 0;
3083 }
3084 
3095 int face_player(object *op, int dir) {
3096  object *transport = op->contr->transport; //< Transport player is in
3097 
3098  if (!transport && (op->map == NULL || op->map->in_memory != MAP_IN_MEMORY))
3099  return 0;
3100 
3101  /* Sanity check: make sure dir is valid */
3102  if ((dir < 0) || (dir >= 9)) {
3103  LOG(llevError, "move_player: invalid direction %d\n", dir);
3104  return 0;
3105  }
3106 
3107  if (QUERY_FLAG(op, FLAG_CONFUSED) && dir)
3108  dir = get_randomized_dir(dir);
3109 
3110  op->facing = dir;
3111 
3112  if (transport) {
3113  /* transport->contr is set up for the person in charge of the boat.
3114  * if that isn't this person, he can't steer it, etc
3115  */
3116  if (transport->contr != op->contr)
3117  return 0;
3118 
3119  turn_transport(transport, op, dir);
3120  } else {
3121  if (op->hide) {
3122  do_hidden_move(op);
3123  }
3124 
3125  /* it is important to change the animation now, as fire or move_player_attack can start a compound animation,
3126  * and leave us with state = 0, which we don't want to change again. */
3127  op->state++; /* player moved, so change animation. */
3128  animate_object(op, op->facing);
3129  }
3130 
3131  /* Add special check for newcs players and fire on - this way, the
3132  * server can handle repeat firing.
3133  */
3134  if (op->contr->fire_on || op->contr->run_on) {
3135  op->direction = dir;
3136  } else {
3137  op->direction = 0;
3138  }
3139  return 0;
3140 }
3141 
3154 int handle_newcs_player(object *op) {
3155  if (op->contr->hidden) {
3156  op->invisible = 1000;
3157  /* the socket code flashes the player visible/invisible
3158  * depending on the value if invisible, so we need to
3159  * alternate it here for it to work correctly.
3160  */
3161  if (pticks&2)
3162  op->invisible--;
3163  } else if (op->invisible && !(QUERY_FLAG(op, FLAG_MAKE_INVIS))) {
3164  op->invisible--;
3165  if (!op->invisible) {
3166  make_visible(op);
3168  "Your invisibility spell runs out.");
3169  }
3170  }
3171 
3172  if (QUERY_FLAG(op, FLAG_SCARED)) {
3173  flee_player(op);
3174  /* If player is still scared, that is his action for this tick */
3175  if (QUERY_FLAG(op, FLAG_SCARED)) {
3176  op->speed_left--;
3177  return 0;
3178  }
3179  }
3180 
3181  /* I've been seeing crashes where the golem has been destroyed, but
3182  * the player object still points to the defunct golem. The code that
3183  * destroys the golem looks correct, and it doesn't always happen, so
3184  * put this in a a workaround to clean up the golem pointer.
3185  */
3186  if (op->contr->ranges[range_golem]
3188  op->contr->ranges[range_golem] = NULL;
3189  op->contr->golem_count = 0;
3190  }
3191 
3192  /*
3193  * If the player has been paralyzed, we unmark the flag and give a message to the player
3194  */
3195  if (QUERY_FLAG(op, FLAG_PARALYZED)) {
3197  // TODO: Is this check necessary? We are in player.c, after all.
3198  if (op->type == PLAYER)
3199  {
3201  "You can stretch your stiff joints once more.");
3202  }
3203  }
3204 
3205  if (op->direction && (op->contr->run_on || op->contr->fire_on)) {
3206  /* All move commands take 1 tick, at least for now */
3207  op->speed_left--;
3208 
3209  /* Instead of all the stuff below, let move_player take care
3210  * of it. Also, some of the skill stuff is only put in
3211  * there, as well as the confusion stuff.
3212  */
3213  move_player(op, op->direction);
3214  if (op->speed_left > 0)
3215  return 1;
3216  else
3217  return 0;
3218  }
3219  return 0;
3220 }
3221 
3232 static int save_life(object *op) {
3233  object *tmp;
3234 
3235  if (!QUERY_FLAG(op, FLAG_LIFESAVE))
3236  return 0;
3237 
3239  if (tmp != NULL) {
3240  char name[MAX_BUF];
3241 
3242  query_name(tmp, name, MAX_BUF);
3243  play_sound_map(SOUND_TYPE_ITEM, tmp, 0, "evaporate");
3245  "Your %s vibrates violently, then evaporates.",
3246  name);
3247  object_remove(tmp);
3250  if (op->stats.hp < 0)
3251  op->stats.hp = op->stats.maxhp;
3252  if (op->stats.food < 0)
3253  op->stats.food = MAX_FOOD;
3254  fix_object(op);
3255  return 1;
3256  }
3257  LOG(llevError, "Error: LIFESAVE set without applied object.\n");
3259  enter_player_savebed(op); /* bring him home. */
3260  return 0;
3261 }
3262 
3275 void remove_unpaid_objects(object *op, object *env, int free_items) {
3277  if (QUERY_FLAG(op, FLAG_UNPAID)) {
3278  object_remove(op);
3279  if (free_items)
3281  else
3282  object_insert_in_map_at(op, env->map, NULL, 0, env->x, env->y);
3283  } else if (op->inv)
3284  remove_unpaid_objects(op->inv, env, free_items);
3286 }
3287 
3305 static const char *gravestone_text(object *op, char *buf2, int len) {
3306  char buf[MAX_BUF];
3307  time_t now = time(NULL);
3308 
3309  strncpy(buf2, " R.I.P.\n\n", len);
3310  if (op->type == PLAYER)
3311  snprintf(buf, sizeof(buf), "%s the %s\n", op->name, op->contr->title);
3312  else
3313  snprintf(buf, sizeof(buf), "%s\n", op->name);
3314  strncat(buf2, " ", 20-strlen(buf)/2);
3315  strncat(buf2, buf, len-strlen(buf2)-1);
3316  if (op->type == PLAYER)
3317  snprintf(buf, sizeof(buf), "who was in level %d when killed\n", op->level);
3318  else
3319  snprintf(buf, sizeof(buf), "who was in level %d when died.\n\n", op->level);
3320  strncat(buf2, " ", 20-strlen(buf)/2);
3321  strncat(buf2, buf, len-strlen(buf2)-1);
3322  if (op->type == PLAYER) {
3323  snprintf(buf, sizeof(buf), "by %s.\n\n", op->contr->killer);
3324  strncat(buf2, " ", 21-strlen(buf)/2);
3325  strncat(buf2, buf, len-strlen(buf2)-1);
3326  }
3327  strftime(buf, MAX_BUF, "%b %d %Y\n", localtime(&now));
3328  strncat(buf2, " ", 20-strlen(buf)/2);
3329  strncat(buf2, buf, len-strlen(buf2)-1);
3330  return buf2;
3331 }
3332 
3340 void do_some_living(object *op) {
3341  int last_food = op->stats.food;
3342  int gen_hp, gen_sp, gen_grace;
3343  int rate_hp = 1200;
3344  int rate_sp = 2500;
3345  int rate_grace = 2000;
3346 
3347  if (op->contr->state == ST_PLAYING) {
3348  /* these next three if clauses make it possible to SLOW DOWN
3349  hp/grace/spellpoint regeneration. */
3350  if (op->contr->gen_hp >= 0)
3351  gen_hp = (op->contr->gen_hp+1)*op->stats.maxhp;
3352  else {
3353  gen_hp = op->stats.maxhp;
3354  rate_hp -= rate_hp/2*op->contr->gen_hp;
3355  }
3356  if (op->contr->gen_sp >= 0)
3357  gen_sp = (op->contr->gen_sp+1)*op->stats.maxsp;
3358  else {
3359  gen_sp = op->stats.maxsp;
3360  rate_sp -= rate_sp/2*op->contr->gen_sp;
3361  }
3362  if (op->contr->gen_grace >= 0)
3363  gen_grace = (op->contr->gen_grace+1)*op->stats.maxgrace;
3364  else {
3365  gen_grace = op->stats.maxgrace;
3366  rate_grace -= rate_grace/2*op->contr->gen_grace;
3367  }
3368 
3369  /* Regenerate Spell Points */
3370  if (op->contr->ranges[range_golem] == NULL && --op->last_sp < 0) {
3371  gen_sp = gen_sp*10/MAX(op->contr->gen_sp_armour, 10);
3372  if (op->stats.sp < op->stats.maxsp) {
3373  op->stats.sp++;
3374  /* dms do not consume food */
3375  if (!QUERY_FLAG(op, FLAG_WIZ)) {
3376  op->stats.food--;
3377  if (op->contr->digestion < 0)
3378  op->stats.food += op->contr->digestion;
3379  else if (op->contr->digestion > 0
3380  && random_roll(0, op->contr->digestion, op, PREFER_HIGH))
3381  op->stats.food = last_food;
3382  }
3383  }
3384  op->last_sp = rate_sp/(MAX(gen_sp, 20)+10);
3385  }
3386 
3387  /* Regenerate Grace */
3388  /* I altered this a little - maximum grace is only achieved through prayer -b.t.*/
3389  if (--op->last_grace < 0) {
3390  if (op->stats.grace < op->stats.maxgrace/2)
3391  op->stats.grace++; /* no penalty in food for regaining grace */
3392  op->last_grace = rate_grace/(MAX(gen_grace, 20)+10);
3393  /* wearing stuff doesn't detract from grace generation. */
3394  }
3395 
3396  /* Regenerate Hit Points (unless you are a wraith player) */
3397  if (--op->last_heal < 0 && !is_wraith_pl(op)) {
3398  if (op->stats.hp < op->stats.maxhp) {
3399  op->stats.hp++;
3400  /* dms do not consume food */
3401  if (!QUERY_FLAG(op, FLAG_WIZ)) {
3402  op->stats.food--;
3403  if (op->contr->digestion < 0)
3404  op->stats.food += op->contr->digestion;
3405  else if (op->contr->digestion > 0
3406  && random_roll(0, op->contr->digestion, op, PREFER_HIGH))
3407  op->stats.food = last_food;
3408  }
3409  }
3410  op->last_heal = rate_hp/(MAX(gen_hp, 20)+10);
3411  }
3412 
3413  /* Digestion */
3414  if (--op->last_eat < 0) {
3415  int bonus = MAX(op->contr->digestion, 0);
3416  int penalty = MAX(-op->contr->digestion, 0);
3417  if (op->contr->gen_hp > 0)
3418  op->last_eat = 25*(1+bonus)/(op->contr->gen_hp+penalty+1);
3419  else
3420  op->last_eat = 25*(1+bonus)/(penalty+1);
3421  /* dms do not consume food */
3422  if (!QUERY_FLAG(op, FLAG_WIZ))
3423  op->stats.food--;
3424  }
3425  }
3426 
3427  if (op->contr->state == ST_PLAYING && op->stats.food < 0 && op->stats.hp >= 0) {
3428  if (is_wraith_pl(op))
3429  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ITEM, MSG_TYPE_ITEM_REMOVE, "You feel a hunger for living flesh.");
3430  /* Only allow eat if not paralyzed. Otherwise our paralyzed player is "moving" to eat.
3431  * Daniel Hawkins 2017-08-23
3432  */
3433  else if (!QUERY_FLAG(op, FLAG_PARALYZED)){
3434  object *flesh = NULL;
3435 
3436  FOR_INV_PREPARE(op, tmp) {
3437  if (!QUERY_FLAG(tmp, FLAG_UNPAID)) {
3438  if (tmp->type == FOOD || tmp->type == DRINK || tmp->type == POISON) {
3440  "You blindly grab for a bite of food.");
3441  apply_manual(op, tmp, 0);
3442  if (op->stats.food >= 0 || op->stats.hp < 0)
3443  break;
3444  } else if (tmp->type == FLESH)
3445  flesh = tmp;
3446  } /* End if paid for object */
3447  } FOR_INV_FINISH(); /* end of for loop */
3448  /* If player is still starving, it means they don't have any food, so
3449  * eat flesh instead.
3450  */
3451  if (op->stats.food < 0 && op->stats.hp >= 0 && flesh) {
3453  "You blindly grab for a bite of food.");
3454  apply_manual(op, flesh, 0);
3455  }
3456  } /* end not wraith and not paralyzed */
3457  else { // Print a message for when the player is starving and paralyzed
3458  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ITEM, MSG_TYPE_ITEM_REMOVE, "Your stomach rumbles, but you can't reach your food.");
3459  } /* end not wraith and is paralyzed */
3460  } /* end if player is starving */
3461 
3462  if (op->stats.food < 0 && op->stats.hp > 0){
3463  // We know food < 0, so we want the absolute value of food
3464  int32_t adjust_by = MIN(-(op->stats.food), op->stats.hp);
3465  op->stats.food += adjust_by;
3466  op->stats.hp -= adjust_by;
3467  }
3468 
3469  if (!op->contr->state && !QUERY_FLAG(op, FLAG_WIZ) && (op->stats.hp < 0 || op->stats.food < 0))
3470  kill_player(op, NULL);
3471 }
3472 
3479 static void loot_object(object *op) {
3480  object *tmp2;
3481 
3482  if (op->container) { /* close open sack first */
3483  apply_container(op, op->container, AP_NULL);
3484  }
3485 
3486  FOR_INV_PREPARE(op, tmp) {
3487  if (tmp->invisible)
3488  continue;
3489  object_remove(tmp);
3490  tmp->x = op->x,
3491  tmp->y = op->y;
3492  if (tmp->type == CONTAINER) { /* empty container to ground */
3493  loot_object(tmp);
3494  }
3495  if (!QUERY_FLAG(tmp, FLAG_UNIQUE)
3496  && (QUERY_FLAG(tmp, FLAG_STARTEQUIP) || QUERY_FLAG(tmp, FLAG_NO_DROP) || !(RANDOM()%3))) {
3497  if (tmp->nrof > 1) {
3498  tmp2 = object_split(tmp, 1+RANDOM()%(tmp->nrof-1), NULL, 0);
3500  object_insert_in_map_at(tmp, op->map, NULL, 0, op->x, op->y);
3501  } else
3503  } else
3504  object_insert_in_map_at(tmp, op->map, NULL, 0, op->x, op->y);
3505  } FOR_INV_FINISH();
3506 }
3507 
3518 static void restore_player(object *op) {
3519  object *tmp;
3520  archetype *at = find_archetype("poisoning");
3521  if (at != NULL) {
3522  tmp = arch_present_in_ob(at, op);
3523  if (tmp) {
3524  object_remove(tmp);
3527  "Your body feels cleansed");
3528  }
3529  }
3530 
3531  at = find_archetype("confusion");
3532  if (at != NULL) {
3533  tmp = arch_present_in_ob(at, op);
3534  if (tmp) {
3535  object_remove(tmp);
3538  "Your mind feels clearer");
3539  }
3540  }
3541 
3542  cure_disease(op, NULL, NULL); /* remove any disease */
3543 }
3544 
3556 void kill_player(object *op, const object *killer) {
3557  char buf[MAX_BUF];
3558  int x, y;
3559  object *tmp;
3560  archetype *trophy = NULL;
3561 
3562  /* Don't die if the player's life can be saved. */
3563  if (save_life(op)) {
3564  return;
3565  }
3566 
3567  /* If player dies on BATTLEGROUND, no stat/exp loss! For Combat-Arenas
3568  * in cities ONLY!!! It is very important that this doesn't get abused.
3569  * Look at op_on_battleground() for more info --AndreasV
3570  */
3571  if (op_on_battleground(op, &x, &y, &trophy)) {
3572  assert(trophy != NULL);
3574  "You have been defeated in combat!\n"
3575  "Local medics have saved your life...");
3576 
3577  /* restore player */
3578  restore_player(op);
3579 
3580  op->stats.hp = op->stats.maxhp;
3581  if (op->stats.food <= 0)
3582  op->stats.food = MAX_FOOD;
3583 
3584  /* create a bodypart-trophy to make the winner happy */
3585  tmp = arch_to_object(trophy);
3586  if (tmp != NULL) {
3587  snprintf(buf, sizeof(buf), "%s's %s", op->name, tmp->name);
3588  tmp->name = add_string(buf);
3589 
3590  snprintf(buf, sizeof(buf),
3591  "This %s was %s %s the %s, who was defeated at level %d by %s.\n",
3592  tmp->name, tmp->type == FLESH ? "cut off" : "taken from",
3593  op->name, op->contr->title,
3594  (int)(op->level), op->contr->killer);
3595 
3596  object_set_msg(tmp, buf);
3597  tmp->type = 0;
3598  tmp->value = 0;
3599  tmp->material = 0;
3600  tmp->materialname = NULL;
3601  object_insert_in_map_at(tmp, op->map, op, 0, op->x, op->y);
3602  }
3603 
3604  /* teleport defeated player to new destination*/
3605  transfer_ob(op, x, y, 0, NULL);
3606  op->contr->braced = 0;
3607  return;
3608  }
3609 
3610  /* Lauwenmark: Handle for plugin death event */
3611  if (execute_event(op, EVENT_DEATH, NULL, NULL, NULL, SCRIPT_FIX_ALL) != 0)
3612  return;
3613 
3614  /* Lauwenmark: Handle for the global death event */
3616  if (op->stats.food < 0) {
3617  snprintf(buf, sizeof(buf), "%s starved to death.", op->name);
3618  strcpy(op->contr->killer, "starvation");
3619  } else {
3620  snprintf(buf, sizeof(buf), "%s died.", op->name);
3621  }
3622  play_sound_player_only(op->contr, SOUND_TYPE_LIVING, op, 0, "death");
3623 
3624  if (settings.not_permadeth == TRUE) {
3626  } else {
3628  }
3629 }
3630 
3639 static void kill_player_not_permadeath(object *op) {
3640  int num_stats_lose;
3641  int will_kill_again;
3642  int lost_a_stat;
3643  int z;
3644  object *tmp;
3645  char buf[MAX_BUF];
3646  archetype *at;
3647 
3648  /* Basically two ways to go - remove a stat permanently, or just
3649  * make it depletion. This bunch of code deals with that aspect
3650  * of death.
3651  */
3653  /* If stat loss is permanent, lose one stat only. */
3654  /* Lower level chars don't lose as many stats because they suffer
3655  more if they do. */
3656  /* Higher level characters can afford things such as potions of
3657  restoration, or better, stat potions. So we slug them that
3658  little bit harder. */
3659  /* GD */
3661  num_stats_lose = 1;
3662  else
3663  num_stats_lose = 1+op->level/BALSL_NUMBER_LOSSES_RATIO;
3664  } else {
3665  num_stats_lose = 1;
3666  }
3667  lost_a_stat = 0;
3668 
3669  for (z = 0; z < num_stats_lose; z++) {
3671  int i;
3672 
3673  /* Pick a random stat and take a point off it. Tell the player
3674  * what he lost.
3675  */
3676  i = RANDOM()%7;
3677  change_attr_value(&(op->stats), i, -1);
3679  change_attr_value(&(op->contr->orig_stats), i, -1);
3681  draw_ext_info(NDI_UNIQUE, 0, op,
3683  lose_msg[i]);
3684  lost_a_stat = 1;
3685  } else {
3686  /* deplete a stat */
3688  if (deparch == NULL) {
3689  continue;
3690  }
3691  object *dep;
3692  int lose_this_stat;
3693  int i;
3694 
3695  i = RANDOM()%7;
3696  dep = arch_present_in_ob(deparch, op);
3697  if (!dep) {
3698  dep = arch_to_object(deparch);
3699  object_insert_in_ob(dep, op);
3700  }
3701  lose_this_stat = 1;
3703  int this_stat;
3704 
3705  /* GD */
3706  /* Get the stat that we're about to deplete. */
3707  this_stat = get_attr_value(&(dep->stats), i);
3708  if (this_stat < 0) {
3709  int loss_chance = 1+op->level/BALSL_LOSS_CHANCE_RATIO;
3710  int keep_chance = this_stat*this_stat;
3711  /* Yes, I am paranoid. Sue me. */
3712  if (keep_chance < 1)
3713  keep_chance = 1;
3714 
3715  /* There is a maximum depletion total per level. */
3716  if (this_stat < -1-op->level/BALSL_MAX_LOSS_RATIO) {
3717  lose_this_stat = 0;
3718  /* Take loss chance vs keep chance to see if we
3719  retain the stat. */
3720  } else {
3721  if (random_roll(0, loss_chance+keep_chance-1, op, PREFER_LOW) < keep_chance)
3722  lose_this_stat = 0;
3723  /* 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"); */
3724  }
3725  }
3726  }
3727 
3728  if (lose_this_stat) {
3729  int this_stat;
3730 
3731  this_stat = get_attr_value(&(dep->stats), i);
3732  /* We could try to do something clever like find another
3733  * stat to reduce if this fails. But chances are, if
3734  * stats have been depleted to -50, all are pretty low
3735  * and should be roughly the same, so it shouldn't make a
3736  * difference.
3737  */
3738  if (this_stat >= -50) {
3739  change_attr_value(&(dep->stats), i, -1);
3740  SET_FLAG(dep, FLAG_APPLIED);
3742  drain_msg[i]);
3743  fix_object(op);
3744  lost_a_stat = 1;
3745  }
3746  }
3747  }
3748  }
3749  /* If no stat lost, tell the player. */
3750  if (!lost_a_stat) {
3751  /* determine_god() seems to not work sometimes... why is this? Should I be using something else? GD */
3752  const char *god = determine_god(op);
3753 
3754  if (god && (strcmp(god, "none")))
3757  "For a brief moment you feel the holy presence of %s protecting you",
3758  god);
3759  else
3760  draw_ext_info(NDI_UNIQUE, 0, op,
3762  "For a brief moment you feel a holy presence protecting you.");
3763  }
3764 
3765  /* Put a gravestone up where the character 'almost' died. List the
3766  * exp loss on the stone.
3767  */
3768  at = find_archetype("gravestone");
3769  if (at != NULL) {
3770  tmp = arch_to_object(at);
3771  snprintf(buf, sizeof(buf), "%s's gravestone", op->name);
3772  FREE_AND_COPY(tmp->name, buf);
3773  snprintf(buf, sizeof(buf), "%s's gravestones", op->name);
3774  FREE_AND_COPY(tmp->name_pl, buf);
3775  snprintf(buf, sizeof(buf), "RIP\nHere rests the hero %s the %s,\n"
3776  "who was killed\n"
3777  "by %s.\n",
3778  op->name, op->contr->title,
3779  op->contr->killer);
3780  object_set_msg(tmp, buf);
3781  object_insert_in_map_at(tmp, op->map, NULL, 0, op->x, op->y);
3782  }
3783 
3784  /* restore player: remove any poisoning, disease and confusion the
3785  * character may be suffering.*/
3786  restore_player(op);
3787 
3788  /* Subtract the experience points, if we died cause of food, give
3789  * us food, and reset HP's...
3790  */
3792  if (op->stats.food < 100)
3793  op->stats.food = 900;
3794  op->stats.hp = op->stats.maxhp;
3795  op->stats.sp = MAX(op->stats.sp, op->stats.maxsp);
3796  op->stats.grace = MAX(op->stats.grace, op->stats.maxgrace);
3797 
3798  /* Check to see if the player is in a shop. IF so, then check to see if
3799  * the player has any unpaid items. If so, remove them and put them back
3800  * in the map.
3801  *
3802  * If they are not in a shop, just free the unpaid items instead of
3803  * putting them back on map.
3804  */
3805  if (shop_contains(op))
3806  remove_unpaid_objects(op->inv, op, 0);
3807  else
3808  remove_unpaid_objects(op->inv, op, 1);
3809 
3810  /* Move player to his current respawn-position (usually last savebed) */
3812 
3813  /* Save the player before inserting the force to reduce chance of abuse. */
3814  op->contr->braced = 0;
3815  /* don't pick up in apartment */
3816  if (op->contr->mode & PU_NEWMODE) {
3817  op->contr->mode = op->contr->mode | PU_INHIBIT;
3818  esrv_send_pickup(op->contr);
3819  } else {
3820  op->contr->mode = 0;
3821  }
3822  if ( op->contr->search_str[0] ) command_search_items(op,NULL); /* turn off search-items */
3823  save_player(op, 1);
3824 
3825  /* it is possible that the player has blown something up
3826  * at his savebed location, and that can have long lasting
3827  * spell effects. So first see if there is a spell effect
3828  * on the space that might harm the player.
3829  */
3830  will_kill_again = 0;
3831  FOR_MAP_PREPARE(op->map, op->x, op->y, tmp)
3832  if (tmp->type == SPELL_EFFECT)
3833  will_kill_again |= tmp->attacktype;
3834  FOR_MAP_FINISH();
3835  if (will_kill_again) {
3836  object *force;
3837  int at;
3838 
3839  force = create_archetype(FORCE_NAME);
3840  /* 50 ticks should be enough time for the spell to abate */
3841  force->speed = 0.1;
3842  force->speed_left = -5.0;
3843  SET_FLAG(force, FLAG_APPLIED);
3844  for (at = 0; at < NROFATTACKS; at++) {
3845  if (will_kill_again&(1<<at))
3846  force->resist[at] = 100;
3847  }
3848  object_insert_in_ob(force, op);
3849  fix_object(op);
3850  }
3851 
3852  /* Tell the player they have died */
3854  "YOU HAVE DIED.");
3855 }
3856 
3863 static void kill_player_permadeath(object *op) {
3864  char buf[MAX_BUF];
3865  char ac_buf[MAX_BUF];
3866  int x, y;
3867  mapstruct *map;
3868  object *tmp;
3869  archetype *at;
3870 
3871  /* save the map location for corpse, gravestone*/
3872  x = op->x;
3873  y = op->y;
3874  map = op->map;
3875 
3876  party_leave(op);
3877  if (settings.set_title == TRUE)
3878  player_set_own_title(op->contr, "");
3879 
3880  /* buf should be the kill message */
3882  buf);
3883  hiscore_check(op, 0);
3884  if (op->contr->ranges[range_golem] != NULL) {
3888  op->contr->ranges[range_golem] = NULL;
3889  op->contr->golem_count = 0;
3890  }
3891  loot_object(op); /* Remove some of the items for good */
3892  object_remove(op);
3893  op->direction = 0;
3894 
3895  if (!QUERY_FLAG(op, FLAG_WAS_WIZ) && op->stats.exp) {
3896  if (settings.resurrection == TRUE) {
3897  /* save playerfile sans equipment when player dies
3898  * -then save it as player.pl.dead so that future resurrection
3899  * -type spells will work on them nicely
3900  */
3901  op->stats.hp = op->stats.maxhp;
3902  op->stats.food = MAX_FOOD;
3903 
3904  /* set the location of where the person will reappear when */
3905  /* maybe resurrection code should fix map also */
3907  sizeof(op->contr->maplevel));
3908  if (op->map != NULL)
3909  op->map = NULL;
3910  op->x = settings.emergency_x;
3911  op->y = settings.emergency_y;
3912  save_player(op, 0);
3913  op->map = map;
3914  /* please see resurrection.c: peterm */
3915  dead_player(op);
3916  } else {
3917  delete_character(op->name);
3918  }
3919  }
3920  play_again(op);
3921 
3922  /* peterm: added to create a corpse at deathsite. */
3923  at = find_archetype("corpse_pl");
3924  if (at != NULL) {
3925  tmp = arch_to_object(at);
3926  snprintf(buf, sizeof(buf), "%s", op->name);
3927  FREE_AND_COPY(tmp->name, buf);
3928  FREE_AND_COPY(tmp->name_pl, buf);
3929  tmp->level = op->level;
3930  object_set_msg(tmp, gravestone_text(op, buf, sizeof(buf)));
3931  SET_FLAG(tmp, FLAG_UNIQUE);
3932  /*
3933  * Put the account name under slaying.
3934  * Does not seem to cause weird effects, but more testing may ensure this.
3935  */
3936  snprintf(ac_buf, sizeof(ac_buf), "%s", op->contr->socket.account_name);
3937  FREE_AND_COPY(tmp->slaying, ac_buf);
3938  object_insert_in_map_at(tmp, map, NULL, 0, x, y);
3939  }
3940 }
3941 
3949 void fix_weight(void) {
3950  player *pl;
3951 
3952  for (pl = first_player; pl != NULL; pl = pl->next) {
3953  int old = pl->ob->carrying, sum = object_sum_weight(pl->ob);
3954 
3955  if (old == sum)
3956  continue;
3957  fix_object(pl->ob);
3958  LOG(llevDebug, "Fixed inventory in %s (%d -> %d)\n", pl->ob->name, old, sum);
3959  }
3960 }
3961 
3965 void fix_luck(void) {
3966  player *pl;
3967 
3968  for (pl = first_player; pl != NULL; pl = pl->next)
3969  if (!pl->ob->contr->state)
3970  change_luck(pl->ob, 0);
3971 }
3972 
3973 
3986 void cast_dust(object *op, object *throw_ob, int dir) {
3987  object *skop, *spob;
3988 
3989  skop = find_skill_by_name(op, throw_ob->skill);
3990 
3991  /* casting POTION 'dusts' is really a use_magic_item skill */
3992  if (op->type == PLAYER && throw_ob->type == POTION && !skop) {
3993  LOG(llevError, "Player %s lacks critical skill use_magic_item!\n", op->name);
3994  return;
3995  }
3996  spob = throw_ob->inv;
3997  if (op->type == PLAYER && spob)
3999  "You cast %s.",
4000  spob->name);
4001 
4002  cast_spell(op, throw_ob, dir, spob, NULL);
4003 
4004  if (!QUERY_FLAG(throw_ob, FLAG_REMOVED))
4005  object_remove(throw_ob);
4006  object_free_drop_inventory(throw_ob);
4007 }
4008 
4015 void make_visible(object *op) {
4016  op->hide = 0;
4017  op->invisible = 0;
4018  if (op->type == PLAYER) {
4019  op->contr->tmp_invis = 0;
4020  if (op->contr->invis_race)
4022  }
4024 }
4025 
4035 int is_true_undead(object *op) {
4036  if (QUERY_FLAG(&op->arch->clone, FLAG_UNDEAD))
4037  return 1;
4038 
4039  if (op->type == PLAYER)
4040  FOR_INV_PREPARE(op, tmp) {
4041  if (tmp->type == 44 && tmp->stats.Wis)
4042  if (QUERY_FLAG(tmp, FLAG_UNDEAD))
4043  return 1;
4044  } FOR_INV_FINISH();
4045  return 0;
4046 }
4047 
4058 int hideability(object *ob) {
4059  int i, level = 0, mflag;
4060  int16_t x, y;
4061 
4062  if (!ob || !ob->map)
4063  return 0;
4064 
4065  /* so, on normal lighted maps, its hard to hide */
4066  level = ob->map->darkness-2;
4067 
4068  /* this also picks up whether the object is glowing.
4069  * If you carry a light on a non-dark map, its not
4070  * as bad as carrying a light on a pitch dark map
4071  */
4072  if (has_carried_lights(ob))
4073  level = -(10+(2*ob->map->darkness));
4074 
4075  /* scan through all nearby squares for terrain to hide in */
4076  for (i = 0, x = ob->x, y = ob->y; i < 9; i++, x = ob->x+freearr_x[i], y = ob->y+freearr_y[i]) {
4077  mflag = get_map_flags(ob->map, NULL, x, y, NULL, NULL);
4078  if (mflag&P_OUT_OF_MAP) {
4079  continue;
4080  }
4081  if (mflag&P_BLOCKSVIEW) /* something to hide near! */
4082  level += 2;
4083  else /* open terrain! */
4084  level -= 1;
4085  }
4086 
4087  return level;
4088 }
4089 
4099 void do_hidden_move(object *op) {
4100  int hide = 0, num = random_roll(0, 19, op, PREFER_LOW);
4101  object *skop;
4102 
4103  if (!op || !op->map)
4104  return;
4105 
4107 
4108  /* its *extremely *hard to run and sneak/hide at the same time! */
4109  if (op->type == PLAYER && op->contr->run_on) {
4110  if (!skop || num >= skop->level) {
4112  "You ran too much! You are no longer hidden!");
4113  make_visible(op);
4114  return;
4115  } else
4116  num += 20;
4117  }
4118  num += op->map->difficulty;
4119  hide = hideability(op); /* modify by terrain hidden level */
4120  num -= hide;
4121  if ((op->type == PLAYER && hide < -10)
4122  || ((op->invisible -= num) <= 0)) {
4123  make_visible(op);
4124  if (op->type == PLAYER)
4126  "You moved out of hiding! You are visible!");
4127  } else if (op->type == PLAYER && skop) {
4128  change_exp(op, calc_skill_exp(op, NULL, skop), skop->skill, 0);
4129  }
4130 }
4131 
4140 int stand_near_hostile(object *who) {
4141  int i, friendly = 0, player = 0, mflags;
4142  mapstruct *m;
4143  int16_t x, y;
4144 
4145  if (!who)
4146  return 0;
4147 
4148  if (who->type == PLAYER)
4149  player = 1;
4150  else
4151  friendly = QUERY_FLAG(who, FLAG_FRIENDLY);
4152 
4153  /* search adjacent squares */
4154  for (i = 1; i < 9; i++) {
4155  x = who->x+freearr_x[i];
4156  y = who->y+freearr_y[i];
4157  m = who->map;
4158  mflags = get_map_flags(m, &m, x, y, &x, &y);
4159  /* space must be blocked if there is a monster. If not
4160  * blocked, don't need to check this space.
4161  */
4162  if (mflags&P_OUT_OF_MAP)
4163  continue;
4164  if (OB_TYPE_MOVE_BLOCK(who, GET_MAP_MOVE_BLOCK(m, x, y)))
4165  continue;
4166 
4167  FOR_MAP_PREPARE(m, x, y, tmp) {
4168  if ((player || friendly)
4169  && QUERY_FLAG(tmp, FLAG_MONSTER)
4170  && !QUERY_FLAG(tmp, FLAG_UNAGGRESSIVE))
4171  return 1;
4172  else if (tmp->type == PLAYER) {
4173  /*don't let a hidden DM prevent you from hiding*/
4174  if (!QUERY_FLAG(tmp, FLAG_WIZ) || tmp->contr->hidden == 0)
4175  return 1;
4176  }
4177  } FOR_MAP_FINISH();
4178  }
4179  return 0;
4180 }
4181 
4208 int player_can_view(object *pl, object *op) {
4209  rv_vector rv;
4210  int dx, dy;
4211 
4212  if (pl->type != PLAYER) {
4213  LOG(llevError, "player_can_view() called for non-player object\n");
4214  return -1;
4215  }
4216  if (!pl || !op)
4217  return 0;
4218 
4219  op = HEAD(op);
4220  if (!get_rangevector(pl, op, &rv, 0x1))
4221  return 0;
4222 
4223  /* starting with the 'head' part, lets loop
4224  * through the object and find if it has any
4225  * part that is in the los array but isnt on
4226  * a blocked los square.
4227  * we use the archetype to figure out offsets.
4228  */
4229  while (op) {
4230  dx = rv.distance_x+op->arch->clone.x;
4231  dy = rv.distance_y+op->arch->clone.y;
4232 
4233  /* only the viewable area the player sees is updated by LOS
4234  * code, so we need to restrict ourselves to that range of values
4235  * for any meaningful values.
4236  */
4237  if (FABS(dx) <= (pl->contr->socket.mapx/2)
4238  && FABS(dy) <= (pl->contr->socket.mapy/2)
4239  && !pl->contr->blocked_los[dx+(pl->contr->socket.mapx/2)][dy+(pl->contr->socket.mapy/2)])
4240  return 1;
4241  op = op->more;
4242  }
4243  return 0;
4244 }
4245 
4259 static int action_makes_visible(object *op) {
4260  if (op->invisible && QUERY_FLAG(op, FLAG_ALIVE)) {
4261  if (QUERY_FLAG(op, FLAG_MAKE_INVIS))
4262  return 0;
4263 
4264  if (op->contr && op->contr->tmp_invis == 0)
4265  return 0;
4266 
4267  /* If monsters, they should become visible */
4268  if (op->hide || !op->contr || (op->contr && op->contr->tmp_invis)) {
4270  "You become %s!",
4271  op->hide ? "unhidden" : "visible");
4272  return 1;
4273  }
4274  }
4275  return 0;
4276 }
4277 
4306 int op_on_battleground(object *op, int *x, int *y, archetype **trophy) {
4307  FOR_BELOW_PREPARE(op, tmp) {
4308  if (QUERY_FLAG(tmp, FLAG_IS_FLOOR)) {
4309  if (QUERY_FLAG(tmp, FLAG_NO_PICK)
4310  && strcmp(tmp->name, "battleground") == 0
4311  && tmp->type == BATTLEGROUND
4312  && EXIT_X(tmp)
4313  && EXIT_Y(tmp)) {
4314  /*before we assign the exit, check if this is a teambattle*/
4315  if (EXIT_ALT_X(tmp) && EXIT_ALT_Y(tmp) && EXIT_PATH(tmp)) {
4316  object *invtmp;
4317 
4318  invtmp = object_find_by_type_and_slaying(op, FORCE, EXIT_PATH(tmp));
4319  if (invtmp != NULL) {
4320  if (x != NULL && y != NULL)
4321  *x = EXIT_ALT_X(tmp),
4322  *y = EXIT_ALT_Y(tmp);
4323  return 1;
4324  }
4325  }
4326  if (x != NULL && y != NULL)
4327  *x = EXIT_X(tmp),
4328  *y = EXIT_Y(tmp);
4329 
4330  /* If 'other_arch' is not specified, give a finger. */
4331  if (trophy != NULL) {
4332  if (tmp->other_arch) {
4333  *trophy = tmp->other_arch;
4334  } else {
4335  *trophy = find_archetype("finger");
4336  }
4337  }
4338  return 1;
4339  }
4340  }
4341  } FOR_BELOW_FINISH();
4342  /* If we got here, did not find a battleground */
4343  return 0;
4344 }
4345 
4356 void dragon_ability_gain(object *who, int atnr, int level) {
4357  treasurelist *trlist = NULL; /* treasurelist */
4358  treasure *tr; /* treasure */
4359  object *tmp, *skop; /* tmp. object */
4360  object *item; /* treasure object */
4361  char buf[MAX_BUF]; /* tmp. string buffer */
4362  int i = 0, j = 0;
4363 
4364  /* get the appropriate treasurelist */
4365  if (atnr == ATNR_FIRE)
4366  trlist = find_treasurelist("dragon_ability_fire");
4367  else if (atnr == ATNR_COLD)
4368  trlist = find_treasurelist("dragon_ability_cold");
4369  else if (atnr == ATNR_ELECTRICITY)
4370  trlist = find_treasurelist("dragon_ability_elec");
4371  else if (atnr == ATNR_POISON)
4372  trlist = find_treasurelist("dragon_ability_poison");
4373 
4374  if (trlist == NULL || who->type != PLAYER)
4375  return;
4376 
4377  // tr->magic is being used to define what level of the metabolism the ability is gained at.
4378  for (tr = trlist->items; tr != NULL && tr->magic != level; tr = tr->next)
4379  ;
4380  if (tr == NULL || tr->item == NULL) {
4381  /* LOG(llevDebug, "-> no more treasure for %s\n", change_resist_msg[atnr]); */
4382  return;
4383  }
4384 
4385  /* everything seems okay - now bring on the gift: */
4386  item = &(tr->item->clone);
4387 
4388  if (item->type == SPELL) {
4389  if (check_spell_known(who, item->name))
4390  return;
4391 
4394  "You gained the ability of %s",
4395  item->name);
4396  do_learn_spell(who, item, 0);
4397  return;
4398  }
4399 
4400  /* grant direct spell */
4401  if (item->type == SPELLBOOK) {
4402  if (!item->inv) {
4403  LOG(llevDebug, "dragon_ability_gain: Broken spellbook %s\n", item->name);
4404  return;
4405  }
4406  if (check_spell_known(who, item->inv->name))
4407  return;
4408  if (item->invisible) {
4411  "You gained the ability of %s",
4412  item->inv->name);
4413  do_learn_spell(who, item->inv, 0);
4414  return;
4415  }
4416  } else if (item->type == SKILL_TOOL && item->invisible) {
4417  if (item->subtype == SK_CLAWING && (skop = find_skill_by_name(who, item->skill)) != NULL) {
4418  /* should this perhaps be (skop->attackyp&item->attacktype) != item->attacktype ...
4419  * in this way, if the player is missing any of the attacktypes, he gets
4420  * them. As it is now, if the player has any that match the granted skill,
4421  * but not all of them, he gets nothing.
4422  */
4423  if (!(skop->attacktype&item->attacktype)) {
4424  /* Give new attacktype */
4425  skop->attacktype |= item->attacktype;
4426 
4427  /* always add physical if there's none */
4428  skop->attacktype |= AT_PHYSICAL;
4429 
4430  if (item->msg != NULL)
4433  item->msg);
4434 
4435  /* Give player new face */
4436  if (item->animation) {
4437  who->face = skop->face;
4438  who->animation = item->animation;
4439  who->anim_speed = item->anim_speed;
4440  who->last_anim = 0;
4441  who->state = 0;
4442  animate_object(who, who->direction);
4443  }
4444  }
4445  }
4446  } else if (item->type == FORCE) {
4447  /* forces in the treasurelist can alter the player's stats */
4448  object *skin;
4449 
4450  /* first get the dragon skin force */
4451  skin = object_find_by_arch_name(who, "dragon_skin_force");
4452  if (skin == NULL)
4453  return;
4454 
4455  /* adding new spellpath attunements */
4456  if (item->path_attuned > 0 && !(skin->path_attuned&item->path_attuned)) {
4457  skin->path_attuned |= item->path_attuned; /* add attunement to skin */
4458 
4459  /* print message */
4460  snprintf(buf, sizeof(buf), "You feel attuned to ");
4461  for (i = 0, j = 0; i < NRSPELLPATHS; i++) {
4462  if (item->path_attuned&(1<<i)) {
4463  if (j)
4464  strcat(buf, " and ");
4465  else
4466  j = 1;
4467  strcat(buf, spellpathnames[i]);
4468  }
4469  }
4470  strcat(buf, ".");
4473  buf);
4474  }
4475 
4476  /* evtl. adding flags: */
4477  if (QUERY_FLAG(item, FLAG_XRAYS))
4478  SET_FLAG(skin, FLAG_XRAYS);
4479  if (QUERY_FLAG(item, FLAG_STEALTH))
4480  SET_FLAG(skin, FLAG_STEALTH);
4481  if (QUERY_FLAG(item, FLAG_SEE_IN_DARK))
4482  SET_FLAG(skin, FLAG_SEE_IN_DARK);
4483 
4484  /* print message if there is one */
4485  if (item->msg != NULL)
4488  item->msg);
4489  } else {
4490  /* generate misc. treasure */
4491  char name[HUGE_BUF];
4492 
4493  tmp = arch_to_object(tr->item);
4494  query_short_name(tmp, name, HUGE_BUF);
4497  "You gained %s",
4498  name);
4499  tmp = object_insert_in_ob(tmp, who);
4500  if (who->type == PLAYER)
4501  esrv_send_item(who, tmp);
4502  }
4503 }
4504 
4514 void player_unready_range_ob(player *pl, object *ob) {
4515  rangetype i;
4516 
4517  for (i = 0; i < range_size; i++) {
4518  if (pl->ranges[i] == ob) {
4519  pl->ranges[i] = NULL;
4520  if (pl->shoottype == i) {
4521  pl->shoottype = range_none;
4522  }
4523  }
4524  }
4525 }
4526 
4533 
4534  assert(pl);
4535  assert(state >= ST_PLAYING && state <= ST_CHANGE_PASSWORD_CONFIRM);
4536  pl->state = state;
4537 }
float weapon_speed_left
Definition: object.h:332
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...)
Definition: main.c:316
static int player_fire_bow(object *op, int dir)
Definition: player.c:2378
uint8_t login_method
Definition: newserver.h:128
void spring_trap(object *trap, object *victim)
Definition: rune.c:205
static void set_player_socket(player *p, socket_struct *ns)
Definition: player.c:418
char path[HUGE_BUF]
Definition: map.h:365
uint8_t not_permadeth
Definition: global.h:263
int player_can_view(object *pl, object *op)
Definition: player.c:4208
static int player_attack_door(object *op, object *door)
Definition: player.c:2620
void set_attr_value(living *stats, int attr, int8_t value)
Definition: living.c:219
const char * rules
Definition: global.h:280
#define MSG_TYPE_MISC
Definition: newclient.h:389
#define FLAG_NO_DROP
Definition: define.h:289
int8_t Int
Definition: living.h:36
Definition: player.h:92
#define FLAG_SEE_IN_DARK
Definition: define.h:338
int apply_manual(object *op, object *tmp, int aflag)
Definition: apply.c:598
const char * determine_god(object *op)
Definition: gods.c:106
archetype * find_archetype(const char *name)
Definition: arch.c:695
#define FLAG_DAMNED
Definition: define.h:318
#define FLAG_IS_FLOOR
Definition: define.h:303
#define FLAG_UNPAID
Definition: define.h:236
int8_t ac
Definition: living.h:38
#define MOVE_WALK
Definition: define.h:407
#define UP_OBJ_FACE
Definition: object.h:519
#define MSG_TYPE_ADMIN_LOGIN
Definition: newclient.h:478
int swap_first
Definition: player.h:147
#define MSG_TYPE_ATTRIBUTE_GOD
Definition: newclient.h:570
#define ST_GET_PARTY_PASSWORD
Definition: define.h:586
MoveType move_type
Definition: object.h:427
#define EVENT_REMOVE
Definition: plugin.h:98
#define MSG_TYPE_ITEM
Definition: newclient.h:388
uint8_t stat_loss_on_death
Definition: global.h:257
int16_t gen_hp
Definition: player.h:113
void object_free(object *ob, int flags)
Definition: object.c:1336
Definition: object.h:127
player * find_player_options(const char *plname, int options, const mapstruct *map)
Definition: player.c:66
#define DETOUR_AMOUNT
Definition: player.c:583
MoveType move_on
Definition: object.h:430
Definition: object.h:185
int64_t calc_skill_exp(const object *who, const object *op, const object *skill)
Definition: skill_util.c:646
bool shop_contains(object *ob)
Definition: shop.c:1274
uint8_t max_stat
Definition: global.h:326
void enter_exit(object *op, object *exit_ob)
Definition: server.c:710
Definition: map.h:380
Definition: player.h:39
void leave(player *pl, int draw_exit)
Definition: server.c:1198
static void swap_stat(object *op, int swap_second)
Definition: player.c:1129
static void loot_object(object *op)
Definition: player.c:3479
object * check_spell_known(object *op, const char *name)
Definition: spell_util.c:433
Definition: object.h:444
const char * race
Definition: object.h:318
void remove_door(object *op)
Definition: time.c:37
int account_remove_player(const char *account_name, const char *player_name)
Definition: account.c:497
char * account_name
Definition: newserver.h:126
#define PU_CONTAINER
Definition: define.h:143
void apply_anim_suffix(object *who, const char *suffix)
Definition: anim.c:318
void SockList_Init(SockList *sl)
Definition: lowlevel.c:48
void esrv_send_item(object *pl, object *op)
Definition: main.c:340
#define SET_FLAG(xyz, p)
Definition: define.h:223
sstring add_refcount(sstring str)
Definition: shstr.c:210
#define EXIT_ALT_Y(xyz)
Definition: define.h:459
#define NDI_ALL
Definition: newclient.h:246
int get_party_password(object *op, partylist *party)
Definition: player.c:999
int16_t bed_x
Definition: player.h:98
uint32_t run_on
Definition: player.h:128
#define PU_DEBUG
Definition: define.h:108
char title[BIG_NAME]
Definition: player.h:165
#define FABS(x)
Definition: define.h:22
int cure_disease(object *sufferer, object *caster, sstring skill)
Definition: disease.c:685
uint32_t braced
Definition: player.h:124
unsigned char uint8_t
Definition: win32.h:161
Definition: object.h:221
static struct Command_Line_Options options[]
Definition: init.c:284
#define MSG_TYPE_ITEM_ADD
Definition: newclient.h:639
#define EVENT_DEATH
Definition: plugin.h:69
void SockList_ResetRead(SockList *sl)
Definition: lowlevel.c:75
void get_name(object *op)
Definition: player.c:856
int get_rangevector_from_mapcoord(const mapstruct *m, int x, int y, const object *op2, rv_vector *retval, int flags)
Definition: map.c:2612
void make_path_to_file(const char *filename)
Definition: porting.c:312
char spellparam[MAX_BUF]
Definition: player.h:100
void link_player_skills(object *op)
Definition: player.c:279
static void kill_player_not_permadeath(object *op)
Definition: player.c:3639
int get_dam_bonus(int stat)
Definition: living.c:2372
#define MSG_TYPE_COMMAND_FAILURE
Definition: newclient.h:511
#define MSG_TYPE_ITEM_INFO
Definition: newclient.h:641
uint16_t material
Definition: object.h:349
#define FLAG_USE_ARMOUR
Definition: define.h:296
void send_news(const object *op)
Definition: player.c:202
int fire_bow(object *op, object *arrow, int dir, int wc_mod, int16_t sx, int16_t sy)
Definition: player.c:2173
#define BALSL_NUMBER_LOSSES_RATIO
Definition: config.h:143
#define strdup_local
Definition: compat.h:25
uint8_t anim_speed
Definition: object.h:420
object * object_find_by_type(const object *who, int type)
Definition: object.c:3759
void drain_wand_charge(object *wand)
Definition: spell_util.c:825
int16_t last_resist[NROFATTACKS]
Definition: player.h:155
Definition: object.h:204
uint16_t look_position
Definition: newserver.h:114
EXTERN objectlink * first_friendly_object
Definition: global.h:121
Definition: object.h:112
struct obj * container
Definition: object.h:291
#define EVENT_LOGIN
Definition: plugin.h:89
uint8_t last_anim
Definition: object.h:421
#define PU_STOP
Definition: define.h:110
Definition: object.h:117
#define FLAG_FRIENDLY
Definition: define.h:246
int push_ob(object *who, int dir, object *pusher)
Definition: move.c:417
Definition: living.h:14
#define PU_SHIELD
Definition: define.h:122
char motd[MAX_BUF]
Definition: global.h:279
void fatal(enum fatal_error err)
Definition: utils.c:597
object * mon
Definition: comet_perf.c:74
#define NDI_BROWN
Definition: newclient.h:233
int op_on_battleground(object *op, int *x, int *y, archetype **trophy)
Definition: player.c:4306
#define MSG_TYPE_SPELL
Definition: newclient.h:387
static int turn_transport(object *transport, object *captain, int dir)
Definition: player.c:2983
#define SOUND_TYPE_GROUND
Definition: newclient.h:311
treasurelist * find_treasurelist(const char *name)
Definition: treasure.c:290
int save_player(object *op, int flag)
Definition: login.c:212
void dragon_ability_gain(object *who, int atnr, int level)
Definition: player.c:4356
uint32_t in_memory
Definition: map.h:345
const char * playerdir
Definition: global.h:249
int16_t maxgrace
Definition: living.h:45
void free_string(sstring str)
Definition: shstr.c:280
#define PU_KEY
Definition: define.h:128
signed long object_sum_weight(object *op)
Definition: object.c:338
#define HUGE_BUF
Definition: define.h:37
#define SET_ANIMATION(ob, newanim)
Definition: global.h:167
mapstruct * get_map_from_coord(mapstruct *m, int16_t *x, int16_t *y)
Definition: map.c:2379
void esrv_update_item(int flags, object *pl, object *op)
Definition: main.c:343
void enter_player_maplevel(object *op)
Definition: server.c:665
const char * object_get_value(const object *op, const char *const key)
Definition: object.c:4125
Definition: object.h:137
struct treasureliststruct * randomitems
Definition: object.h:388
void pick_up(object *op, object *alt)
Definition: c_object.c:460
#define NDI_BLUE
Definition: newclient.h:226
uint32_t pticks
Definition: time.c:45
void query_base_name(const object *op, int plural, char *buf, size_t size)
Definition: item.c:680
#define ST_CHANGE_PASSWORD_CONFIRM
Definition: define.h:589
int8_t levsp[11]
Definition: player.h:168
object clone
Definition: object.h:472
socket_struct socket
Definition: player.h:94
int16_t invisible
Definition: object.h:362
short freearr_x[SIZEOFFREE]
Definition: object.c:65
#define PREFER_LOW
Definition: define.h:601
Definition: living.h:17
#define ST_CONFIRM_PASSWORD
Definition: define.h:585
rangetype shoottype
Definition: player.h:99
Definition: object.h:240
int16_t SP_level_spellpoint_cost(object *caster, object *spell, int flags)
Definition: spell_util.c:275
Definition: object.h:119
Definition: object.h:136
const char * slaying
Definition: object.h:319
#define IS_WEAPON(op)
Definition: define.h:162
void esrv_send_inventory(object *pl, object *op)
Definition: item.c:307
#define FLAG_CONFUSED
Definition: define.h:312
#define FLAG_STEALTH
Definition: define.h:313
static object * pick_arrow_target(object *op, const char *type, int dir)
Definition: player.c:2104
object * ranges[range_size]
Definition: player.h:103
uint8_t subtype
Definition: object.h:341
const char * party_get_password(const partylist *party)
Definition: party.c:232
Definition: object.h:109
void send_account_players(socket_struct *ns)
Definition: request.c:1901
void send_rules(const object *op)
Definition: player.c:166
#define SOUND_TYPE_LIVING
Definition: newclient.h:308
#define FLAG_USE_WEAPON
Definition: define.h:297
uint8_t hide
Definition: object.h:390
int64_t exp
Definition: living.h:47
void fix_luck(void)
Definition: player.c:3965
void play_again(object *op)
Definition: player.c:880
void change_luck(object *op, int value)
Definition: living.c:793
object * object_find_by_type_without_flags(const object *who, int type, int *flags, int num_flags)
Definition: object.c:3783
object * object_find_by_type_and_slaying(const object *who, int type, const char *slaying)
Definition: object.c:3937
method_ret ob_process(object *op)
Definition: ob_methods.c:68
void SockList_AddInt(SockList *sl, uint32_t data)
Definition: lowlevel.c:119
#define OUT_OF_REAL_MAP(M, X, Y)
Definition: map.h:217
int language
Definition: player.h:201
enum Sock_Status status
Definition: newserver.h:90
Definition: object.h:157
#define object_was_destroyed(op, old_tag)
Definition: object.h:68
#define TRUE
Definition: compat.h:10
#define PU_NOTHING
Definition: define.h:106
#define PU_FLESH
Definition: define.h:142
#define PU_FOOD
Definition: define.h:115
object * arch_present_in_ob(const archetype *at, const object *op)
Definition: object.c:2943
void party_leave(object *op)
Definition: party.c:123
Definition: living.h:35
int blocked_link(object *ob, mapstruct *m, int16_t sx, int16_t sy)
Definition: map.c:354
void do_some_living(object *op)
Definition: player.c:3340
void give_initial_items(object *pl, treasurelist *items)
Definition: player.c:764
Definition: object.h:139
int8_t get_attr_value(const living *stats, int attr)
Definition: living.c:314
void remove_friendly_object(object *op)
Definition: friend.c:56
uint32_t path_attuned
Definition: object.h:345
#define MAX(x, y)
Definition: compat.h:20
void object_update(object *op, int action)
Definition: object.c:1190
#define MSG_TYPE_ITEM_REMOVE
Definition: newclient.h:638
void account_char_free(Account_Char *chars)
Definition: account_char.c:334
void dead_player(object *op)
Definition: resurrection.c:297
int16_t sp
Definition: living.h:42
EXTERN char first_map_ext_path[MAX_BUF]
Definition: global.h:150
void strip_endline(char *buf)
Definition: utils.c:341
int object_can_merge(object *ob1, object *ob2)
Definition: object.c:199
Definition: object.h:187
int path_to_player(object *mon, object *pl, unsigned mindiff)
Definition: player.c:631
void get_password(object *op)
Definition: player.c:868
#define safe_strncpy
Definition: compat.h:23
int is_true_undead(object *op)
Definition: player.c:4035
#define SCRIPT_FIX_ALL
Definition: global.h:367
Definition: object.h:212
player * find_player_partial_name(const char *plname)
Definition: player.c:110
#define PU_NEWMODE
Definition: define.h:111
uint32_t hidden
Definition: player.h:132
void pets_terminate_all(object *owner)
Definition: pets.c:225
static const char * gravestone_text(object *op, char *buf2, int len)
Definition: player.c:3305
struct obj * enemy
Definition: object.h:384
object * get_nearest_player(object *mon)
Definition: player.c:522
#define ST_ROLL_STAT
Definition: define.h:580
int distance_y
Definition: map.h:383
int absdir(int d)
Definition: object.c:3493
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
Definition: main.c:311
const char *const drain_msg[NUM_STATS]
Definition: living.c:140
Definition: object.h:467
#define ST_PLAYING
Definition: define.h:578
#define PU_MISSILEWEAPON
Definition: define.h:130
char savebed_map[MAX_BUF]
Definition: player.h:97
#define NDI_DK_ORANGE
Definition: newclient.h:227
char * host
Definition: newserver.h:100
Definition: object.h:220
#define MSG_TYPE_APPLY
Definition: newclient.h:384
#define FOR_OB_AND_BELOW_FINISH()
Definition: define.h:791
const char *const spellpathnames[NRSPELLPATHS]
Definition: init.c:105
struct archt * item
Definition: treasure.h:64
uint16_t emergency_y
Definition: global.h:302
static int turn_one_transport(object *transport, object *captain, int dir)
Definition: player.c:2913
#define PU_CLOAK
Definition: define.h:127
int16_t maxsp
Definition: living.h:43
#define MIN(x, y)
Definition: compat.h:17
int8_t Con
Definition: living.h:36
#define FLAG_REMOVED
Definition: define.h:232
int16_t hp
Definition: living.h:40
int check_pick(object *op)
Definition: player.c:1691
#define FLAG_CAN_ROLL
Definition: define.h:254
short freearr_y[SIZEOFFREE]
Definition: object.c:71
partylist * party
Definition: player.h:186
#define FLAG_KNOWN_MAGICAL
Definition: define.h:320
Definition: player.h:32
#define SOUND_TYPE_ITEM
Definition: newclient.h:310
#define NDI_NAVY
Definition: newclient.h:223
void create_treasure(treasurelist *t, object *op, int flag, int difficulty, int tries)
Definition: treasure.c:488
uint32_t no_shout
Definition: player.h:133
object * ob
Definition: object.h:445
#define FIND_PLAYER_PARTIAL_NAME
Definition: player.h:212
#define MOVE_ALL
Definition: define.h:413
uint32_t ticks_played
Definition: player.h:203
void pets_control_golem(object *op, int dir)
Definition: pets.c:627
#define MIN_STAT
Definition: define.h:33
#define FLAG_UNDEAD
Definition: define.h:270
void object_set_owner(object *op, object *owner)
Definition: object.c:604
const char * news
Definition: global.h:281
#define FLAG_READY_SKILL
Definition: define.h:334
void apply_changes_to_player(object *pl, object *change, int limit_stats)
Definition: apply.c:1650
Definition: object.h:241
#define MAP_IN_MEMORY
Definition: map.h:130
struct obj * chosen_skill
Definition: object.h:389
uint32_t update_look
Definition: newserver.h:104
object * find_key(object *pl, object *container, object *door)
Definition: player.c:2538
void object_free_drop_inventory(object *ob)
Definition: object.c:1316
void clear_player(player *pl)
Definition: player.c:33
int16_t y
Definition: object.h:327
void esrv_new_player(player *pl, uint32_t weight)
Definition: request.c:868
object * object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
Definition: object.c:1838
int16_t maxhp
Definition: living.h:41
static void fire_misc_object(object *op, int dir)
Definition: player.c:2414
static void restore_player(object *op)
Definition: player.c:3518
#define MSG_TYPE_ATTRIBUTE_BAD_EFFECT_END
Definition: newclient.h:561
void object_update_turn_face(object *op)
Definition: object.c:1069
#define MSG_TYPE_COMMAND
Definition: newclient.h:379
#define PU_BOOTS
Definition: define.h:125
Definition: object.h:118
int stand_near_hostile(object *who)
Definition: player.c:4140
#define FLAG_ALIVE
Definition: define.h:230
Account_Char * account_chars
Definition: newserver.h:127
#define ADD_PLAYER_NO_STATS_ROLL
Definition: player.h:224
Definition: object.h:114
#define MSG_TYPE_VICTIM
Definition: newclient.h:392
int get_randomized_dir(int dir)
Definition: utils.c:439
object * object_new(void)
Definition: object.c:1011
const char * name_pl
Definition: object.h:315
object * create_archetype(const char *name)
Definition: arch.c:620
int8_t direction
Definition: object.h:336
void player_set_own_title(struct pl *pl, const char *title)
Definition: player.c:264
int object_can_pick(const object *who, const object *item)
Definition: object.c:3646
object * object_insert_in_ob(object *op, object *where)
Definition: object.c:2591
void send_query(socket_struct *ns, uint8_t flags, const char *text)
Definition: request.c:677
float speed_left
Definition: object.h:330
unapplymode unapply
Definition: player.h:108
int is_wraith_pl(object *op)
Definition: player.c:165
int16_t gen_sp
Definition: player.h:114
#define MSG_TYPE_COMMAND_SUCCESS
Definition: newclient.h:510
player * get_player(player *p)
Definition: player.c:281
#define MSG_TYPE_COMMAND_ERROR
Definition: newclient.h:509
#define PU_SKILLSCROLL
Definition: define.h:136
signed short int16_t
Definition: win32.h:160
uint8_t search_items
Definition: global.h:268
void command_search_items(object *op, const char *params)
Definition: c_object.c:2090
const char * materialname
Definition: object.h:348
int32_t weight
Definition: object.h:367
static void kill_player_permadeath(object *op)
Definition: player.c:3863
#define FLAG_CAN_USE_SKILL
Definition: define.h:322
#define MOVE_FLY_LOW
Definition: define.h:408
const char * anim_suffix
Definition: object.h:316
#define ADD_PLAYER_NEW
Definition: player.h:222
uint32_t tmp_invis
Definition: player.h:125
void drain_rod_charge(object *rod)
Definition: spell_util.c:815
int8_t Wis
Definition: living.h:36
int hide(object *op, object *skill)
Definition: skills.c:494
#define FLAG_UNAGGRESSIVE
Definition: define.h:272
#define FLAG_USE_SHIELD
Definition: define.h:237
player * add_player(socket_struct *ns, int flags)
Definition: player.c:454
#define MSG_TYPE_ADMIN_PLAYER
Definition: newclient.h:474
void clear_los(player *pl)
Definition: los.c:252
void receive_play_again(object *op, char key)
Definition: player.c:933
#define PU_ARROW
Definition: define.h:120
struct mapdef * map
Definition: object.h:297
void SockList_Term(SockList *sl)
Definition: lowlevel.c:58
char search_str[MAX_BUF]
Definition: player.h:192
#define snprintf
Definition: win32.h:46
#define ARCH_DEPLETION
Definition: object.h:579
void player_map_change_common(object *op, mapstruct *const oldmap, mapstruct *const newmap)
Definition: server.c:265
int ob_blocked(const object *ob, mapstruct *m, int16_t x, int16_t y)
Definition: map.c:497
#define MSG_TYPE_ATTRIBUTE
Definition: newclient.h:380
object * transport
Definition: player.h:195
#define FLAG_IDENTIFIED
Definition: define.h:261
#define MOVE_FLYING
Definition: define.h:410
#define FOR_INV_FINISH()
Definition: define.h:714
object * object_find_by_flag_applied(const object *who, int flag)
Definition: object.c:4008
int16_t dam
Definition: living.h:46
uint8_t balanced_stat_loss
Definition: global.h:262
void change_attr_value(living *stats, int attr, int8_t value)
Definition: living.c:265
int die_roll(int num, int size, const object *op, int goodbad)
Definition: utils.c:122
void add_friendly_object(object *op)
Definition: friend.c:30
int32_t carrying
Definition: object.h:369
#define NDI_GREEN
Definition: newclient.h:228
const char * name
Definition: object.h:311
int16_t bed_y
Definition: player.h:98
living orig_stats
Definition: player.h:148
#define PU_INHIBIT
Definition: define.h:109
int distance_x
Definition: map.h:382
#define PU_BOW
Definition: define.h:118
int allowed_class(const object *op)
Definition: living.c:1646
#define MSG_TYPE_COMMAND_NEWPLAYER
Definition: newclient.h:516
static int similar_direction(int a, int b)
Definition: player.c:2344
#define AP_NULL
Definition: define.h:610
uint8_t state
Definition: object.h:351
#define ST_PLAY_AGAIN
Definition: define.h:579
void roll_again(object *op)
Definition: player.c:1115
int execute_global_event(int eventcode,...)
Definition: main.c:370
#define EXIT_PATH(xyz)
Definition: define.h:454
uint8_t state
Definition: player.h:118
#define MSG_TYPE_SPELL_END
Definition: newclient.h:629
uint64_t price_base(const object *obj)
Definition: shop.c:70
uint8_t magic
Definition: treasure.h:71
void display_motd(const object *op)
Definition: player.c:135
#define offsetof(type, member)
Definition: shstr.h:37
#define CS_QUERY_SINGLECHAR
Definition: newclient.h:67
int monster_can_detect_enemy(object *op, object *enemy, rv_vector *rv)
Definition: monster.c:2392
void SockList_AddString(SockList *sl, const char *data)
Definition: lowlevel.c:149
#define FLAG_PARALYZED
Definition: define.h:380
#define PU_RATIO
Definition: define.h:113
uint32_t nrof
Definition: object.h:334
uint8_t listening
Definition: player.h:120
void fire(object *op, int dir)
Definition: player.c:2466
int8_t Cha
Definition: living.h:36
#define OB_TYPE_MOVE_BLOCK(ob1, type)
Definition: define.h:447
void hiscore_check(object *op, int quiet)
Definition: hiscore.c:301
#define AP_NOPRINT
Definition: define.h:623
void remove_locked_door(object *op)
Definition: time.c:63
#define P_OUT_OF_MAP
Definition: map.h:251
#define GET_MAP_MOVE_BLOCK(M, X, Y)
Definition: map.h:192
int do_skill(object *op, object *part, object *skill, int dir, const char *string)
Definition: skill_util.c:412
uint16_t emergency_x
Definition: global.h:302
int move_ob(object *op, int dir, object *originator)
Definition: move.c:58
#define EXIT_X(xyz)
Definition: define.h:456
void do_learn_spell(object *op, object *spell, int special_prayer)
Definition: apply.c:485
Definition: object.h:111
uint32_t has_hit
Definition: player.h:129
struct pl * contr
Definition: object.h:276
#define PU_DRINK
Definition: define.h:116
static void flee_player(object *op)
Definition: player.c:1632
void add_statbonus(object *op)
Definition: living.c:865
#define FLAG_SCARED
Definition: define.h:271
uint8_t darkness
Definition: map.h:346
#define MSG_TYPE_SKILL_FAILURE
Definition: newclient.h:585
player * find_player_socket(const socket_struct *ns)
Definition: player.c:119
#define FLAG_XRAYS
Definition: define.h:301
#define FREE_AND_CLEAR_STR(xyz)
Definition: global.h:205
void set_first_map(object *op)
Definition: player.c:399
char * spellarg
Definition: object.h:412
int8_t blocked_los[MAP_CLIENT_X][MAP_CLIENT_Y]
Definition: player.h:159
uint32_t tag_t
Definition: object.h:12
int8_t luck
Definition: living.h:39
#define ATNR_ELECTRICITY
Definition: attack.h:52
#define ATNR_POISON
Definition: attack.h:59
#define AT_PHYSICAL
Definition: attack.h:76
float speed
Definition: object.h:329
Definition: object.h:214
#define QUERY_FLAG(xyz, p)
Definition: define.h:225
#define CLEAR_FLAG(xyz, p)
Definition: define.h:224
#define HEAD(op)
Definition: object.h:594
party_rejoin_mode rejoin_party
Definition: player.h:191
#define MSG_TYPE_ADMIN_NEWS
Definition: newclient.h:473
#define FLAG_WIZ
Definition: define.h:231
void change_exp(object *op, int64_t exp, const char *skill_name, int flag)
Definition: living.c:2162
#define FLAG_BEEN_APPLIED
Definition: define.h:324
uint32_t golem_count
Definition: player.h:106
#define EXIT_ALT_X(xyz)
Definition: define.h:458
void object_get_multi_size(const object *ob, int *sx, int *sy, int *hx, int *hy)
Definition: object.c:4490
#define MSG_TYPE_COMMAND_DEBUG
Definition: newclient.h:508
#define BALSL_LOSS_CHANCE_RATIO
Definition: config.h:142
#define EXIT_Y(xyz)
Definition: define.h:457
void delete_character(const char *name)
Definition: login.c:87
#define MAX_BUF
Definition: define.h:35
#define MSG_TYPE_ATTACK
Definition: newclient.h:385
#define NRSPELLPATHS
Definition: spells.h:40
const Animations * animation
Definition: object.h:419
#define IS_SHIELD(op)
Definition: define.h:169
Definition: object.h:126
#define PU_READABLES
Definition: define.h:137
#define MSG_TYPE_ADMIN
Definition: newclient.h:377
uint32_t peaceful
Definition: player.h:131
Account_Char * account_char_remove(Account_Char *chars, const char *pl_name)
Definition: account_char.c:298
void do_hidden_move(object *op)
Definition: player.c:4099
int16_t x
Definition: object.h:327
void skill_attack(object *tmp, object *pl, int dir, const char *string, object *skill)
Definition: skill_util.c:1259
int strncasecmp(const char *s1, const char *s2, int n)
Definition: porting.c:224
int8_t levhp[11]
Definition: player.h:167
struct treasurestruct * items
Definition: treasure.h:90
#define MSG_TYPE_ATTRIBUTE_STAT_LOSS
Definition: newclient.h:563
const char * skill
Definition: object.h:321
uint8_t mapx
Definition: newserver.h:116
void fix_weight(void)
Definition: player.c:3949
void esrv_map_scroll(socket_struct *ns, int dx, int dy)
Definition: request.c:1537
int8_t wc
Definition: living.h:37
int roll_stat(void)
Definition: player.c:1017
int64_t last_skill_exp[MAX_SKILLS]
Definition: player.h:138
const char * confdir
Definition: global.h:246
void kill_player(object *op, const object *killer)
Definition: player.c:3556
#define AC_PLAYER_STAT_NO_CHANGE
Definition: define.h:635
#define FLAG_IS_THROWN
Definition: define.h:249
uint16_t difficulty
Definition: map.h:343
static const flag_definition flags[]
void SockList_AddChar(SockList *sl, unsigned char c)
Definition: lowlevel.c:98
#define FOR_MAP_FINISH()
Definition: define.h:767
int8_t Str
Definition: living.h:36
void animate_object(object *op, int dir)
Definition: anim.c:212
int16_t resist[NROFATTACKS]
Definition: object.h:343
#define FLAG_KNOWN_CURSED
Definition: define.h:321
object * ob
Definition: player.h:158
int has_carried_lights(const object *op)
Definition: los.c:315
const char *const lose_msg[NUM_STATS]
Definition: living.c:173
#define FLAG_CURSED
Definition: define.h:317
Definition: object.h:107
unsigned int uint32_t
Definition: win32.h:162
void player_set_state(player *pl, uint8_t state)
Definition: player.c:4532
Definition: object.h:113
void safe_strcat(char *dest, const char *orig, size_t *curlen, size_t maxlen)
Definition: porting.c:346
Definition: object.h:135
object * object_find_by_type_subtype(const object *who, int type, int subtype)
Definition: object.c:4080
bowtype_t bowtype
Definition: player.h:101
int move_player(object *op, int dir)
Definition: player.c:3016
char killer[BIG_NAME]
Definition: player.h:171
#define FLAG_ANIMATE
Definition: define.h:242
int apply_container(object *op, object *sack, int aflags)
Definition: apply.c:222
void key_roll_stat(object *op, char key)
Definition: player.c:1187
#define PU_MELEEWEAPON
Definition: define.h:131
#define PREFER_HIGH
Definition: define.h:600
uint32_t attacktype
Definition: object.h:344
object * object_split(object *orig_ob, uint32_t nr, char *err, size_t size)
Definition: object.c:2371
float last_speed
Definition: player.h:154
#define object_decrease_nrof_by_one(xyz)
Definition: compat.h:28
#define MSG_TYPE_VICTIM_DIED
Definition: newclient.h:654
void play_sound_player_only(player *pl, int8_t sound_type, object *emitter, int dir, const char *action)
Definition: sounds.c:51
#define FLAG_NEUTRAL
Definition: define.h:362
#define RANDOM()
Definition: define.h:681
living last_stats
Definition: player.h:149
int handle_newcs_player(object *op)
Definition: player.c:3154
const char * invis_race
Definition: player.h:135
#define FREE_AND_COPY(sv, nv)
Definition: global.h:210
int16_t grace
Definition: living.h:44
signed char int8_t
Definition: win32.h:158
Definition: object.h:143
uint32_t fire_on
Definition: player.h:127
#define MAX_SPACES
Definition: player.c:598
const char * localdir
Definition: global.h:248
char password[16]
Definition: player.h:176
int32_t last_weight
Definition: player.h:142
tag_t count
Definition: object.h:299
void recursive_roll(object *op, int dir, object *pusher)
Definition: move.c:276
living stats
Definition: object.h:370
static int save_life(object *op)
Definition: player.c:3232
int8_t Dex
Definition: living.h:36
struct archt * arch
Definition: object.h:415
float last_weapon_sp
Definition: player.h:140
#define UPD_FACE
Definition: newclient.h:292
struct oblnk * next
Definition: object.h:446
int playername_ok(const char *cp)
Definition: player.c:253
#define MSG_TYPE_ATTACK_NOATTACK
Definition: newclient.h:613
#define MSG_TYPE_ADMIN_RULES
Definition: newclient.h:472
void account_char_save(const char *account, Account_Char *chars)
Definition: account_char.c:146
int check_race_and_class(living *stats, archetype *race, archetype *opclass)
Definition: player.c:1403
void make_visible(object *op)
Definition: player.c:4015
static archetype * get_player_archetype(archetype *at)
Definition: player.c:497
#define SPELL_HIGHEST
Definition: spells.h:60
unsigned int distance
Definition: map.h:381
uint8_t type
Definition: object.h:340
uint32_t do_los
Definition: player.h:126
void move_player_attack(object *op, int dir)
Definition: player.c:2691
uint32_t mode
Definition: player.h:110
struct Settings settings
Definition: init.c:39
uint32_t monitor_spells
Definition: newserver.h:110
void object_set_enemy(object *op, object *enemy)
Definition: object.c:679
#define ADD_PLAYER_NO_MAP
Definition: player.h:223
struct archt * next
Definition: object.h:469
int direction
Definition: map.h:384
rangetype
Definition: player.h:15
#define FLAG_NO_STRENGTH
Definition: define.h:307
#define FLAG_APPLIED
Definition: define.h:235
#define NROFATTACKS
Definition: attack.h:17
void query_short_name(const object *op, char *buf, size_t size)
Definition: item.c:508
#define PU_SPELLBOOK
Definition: define.h:135
int out_of_map(mapstruct *m, int x, int y)
Definition: map.c:2306
int execute_event(object *op, int eventcode, object *activator, object *third, const char *message, int fix)
Definition: main.c:365
#define FLAG_LIFESAVE
Definition: define.h:306
void remove_unpaid_objects(object *op, object *env, int free_items)
Definition: player.c:3275
signed int int32_t
Definition: win32.h:159
void delete_map(mapstruct *m)
Definition: map.c:1736
#define ST_CHANGE_CLASS
Definition: define.h:581
#define MSG_TYPE_APPLY_SUCCESS
Definition: newclient.h:598
const char * msg
Definition: object.h:322
EXTERN char first_map_path[MAX_BUF]
Definition: global.h:149
#define FLAG_MAKE_INVIS
Definition: define.h:329
int object_matches_string(object *pl, object *op, const char *name)
Definition: object.c:4323
void apply_death_exp_penalty(object *op)
Definition: living.c:2227
#define FOR_OB_AND_BELOW_PREPARE(op_)
Definition: define.h:787
#define FLAG_STARTEQUIP
Definition: define.h:268
#define FORCE_NAME
Definition: spells.h:169
#define PU_VALUABLES
Definition: define.h:117
int16_t gen_sp_armour
Definition: player.h:115
#define PU_MAGICAL
Definition: define.h:132
sstring add_string(const char *str)
Definition: shstr.c:124
EXTERN player * first_player
Definition: global.h:115
#define FIND_PLAYER_NO_HIDDEN_DM
Definition: player.h:213
struct pl * next
Definition: player.h:93
static const int32_t MAX_FOOD
Definition: define.h:476
#define GET_MAP_OB(M, X, Y)
Definition: map.h:172
player * find_player(const char *plname)
Definition: player.c:55
void confirm_password(object *op)
Definition: player.c:983
#define PU_JEWELS
Definition: define.h:141
#define FLAG_MONSTER
Definition: define.h:245
void esrv_send_pickup(player *pl)
Definition: request.c:1664
void object_copy(const object *src_ob, object *dest_ob)
Definition: object.c:824
#define EVENT_PLAYER_DEATH
Definition: plugin.h:97
#define MSG_TYPE_SKILL
Definition: newclient.h:383
int8_t Pow
Definition: living.h:36
int get_map_flags(mapstruct *oldmap, mapstruct **newmap, int16_t x, int16_t y, int16_t *nx, int16_t *ny)
Definition: map.c:310
struct obj * inv
Definition: object.h:290
uint8_t set_title
Definition: global.h:266
petmode_t petmode
Definition: player.h:102
#define NDI_UNIQUE
Definition: newclient.h:245
int face_player(object *op, int dir)
Definition: player.c:3095
char maplevel[MAX_BUF]
Definition: player.h:96
Definition: object.h:213
int apply_race_and_class(object *op, archetype *race, archetype *opclass, living *stats)
Definition: player.c:1453
#define FLAG_READY_BOW
Definition: define.h:300
#define MSG_SUBTYPE_NONE
Definition: newclient.h:398
usekeytype usekeys
Definition: player.h:107
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:51
#define CS_QUERY_HIDEINPUT
Definition: newclient.h:68
static int action_makes_visible(object *op)
Definition: player.c:4259
#define PU_GLOVES
Definition: define.h:126
object * last_skill_ob[MAX_SKILLS]
Definition: player.h:137
int did_make_save(const object *op, int level, int bonus)
Definition: living.c:2276
#define FLAG_WAS_WIZ
Definition: define.h:234
int transfer_ob(object *op, int x, int y, int randomly, object *originator)
Definition: move.c:144
void player_unready_range_ob(player *pl, object *ob)
Definition: player.c:4514
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Definition: define.h:760
void roll_stats(object *op)
Definition: player.c:1041
void play_sound_map(int8_t sound_type, object *emitter, int dir, const char *action)
Definition: sounds.c:107
uint8_t run_away
Definition: object.h:387
#define IS_ARMOR(op)
Definition: define.h:165
void key_change_class(object *op, char key)
Definition: player.c:1263
#define MSG_TYPE_ATTACK_NOKEY
Definition: newclient.h:612
struct mapdef * next
Definition: map.h:326
#define P_BLOCKSVIEW
Definition: map.h:226
void object_set_msg(object *op, const char *msg)
Definition: object.c:4559
static void update_transport_block(object *transport, int dir)
Definition: player.c:2868
#define MSG_TYPE_ATTRIBUTE_RACE
Definition: newclient.h:557
#define ATNR_COLD
Definition: attack.h:53
void query_name(const object *op, char *buf, size_t size)
Definition: item.c:583
#define PU_ARMOUR
Definition: define.h:123
void apply_map_builder(object *pl, int dir)
Definition: build_map.c:959
#define MAX_SKILLS
Definition: skills.h:70
#define FOR_BELOW_PREPARE(op_, it_)
Definition: define.h:741
void remove_statbonus(object *op)
Definition: living.c:842
char * emergency_mapname
Definition: global.h:301
Definition: map.h:325
#define P_IS_ALIVE
Definition: map.h:237
int random_roll(int min, int max, const object *op, int goodbad)
Definition: utils.c:42
int is_identifiable_type(const object *op)
Definition: item.c:1292
#define ST_GET_NAME
Definition: define.h:583
uint8_t roll_stat_points
Definition: global.h:325
const Face * face
Definition: object.h:333
char write_buf[MAX_BUF]
Definition: player.h:174
Definition: object.h:167
#define FLAG_UNIQUE
Definition: define.h:288
#define FLAG_NO_PICK
Definition: define.h:239
static object * find_better_arrow(object *op, object *target, const char *type, int *better)
Definition: player.c:2034
int8_t levgrace[11]
Definition: player.h:169
#define PU_POTION
Definition: define.h:133
int get_rangevector(object *op1, const object *op2, rv_vector *retval, int flags)
Definition: map.c:2539
const char * unarmed_skill
Definition: player.h:202
Definition: object.h:120
const char *const short_stat_name[NUM_STATS]
Definition: living.c:195
struct treasurestruct * next
Definition: treasure.h:66
void enter_player_savebed(object *op)
Definition: server.c:133
uint8_t mapy
Definition: newserver.h:116
partylist * party_to_join
Definition: player.h:187
int get_dex_bonus(int stat)
Definition: living.c:2348
#define PU_HELMET
Definition: define.h:121
int16_t level
Definition: object.h:353
int8_t facing
Definition: object.h:337
#define FLAG_INV_LOCKED
Definition: define.h:330
void fix_object(object *op)
Definition: living.c:1120
#define BALSL_MAX_LOSS_RATIO
Definition: config.h:144
EXTERN mapstruct * first_map
Definition: global.h:116
void cast_dust(object *op, object *throw_ob, int dir)
Definition: player.c:3986
#define AT_DEATH
Definition: attack.h:93
#define PU_NOT_CURSED
Definition: define.h:140
EXTERN archetype * first_archetype
Definition: global.h:120
struct obj * more
Definition: object.h:295
object * find_skill_by_name(object *who, const char *name)
Definition: skill_util.c:192
object * arch_to_object(archetype *at)
Definition: arch.c:571
void object_update_speed(object *op)
Definition: object.c:1086
int32_t value
Definition: object.h:352
object * object_get_owner(object *op)
Definition: object.c:568
int8_t magic
Definition: object.h:350
uint8_t * faces_sent
Definition: newserver.h:96
static object * find_arrow(object *op, const char *type)
Definition: player.c:2002
const char * name
Definition: object.h:468
#define EVENT_BORN
Definition: plugin.h:84
size_t strlcpy(char *dst, const char *src, size_t size)
Definition: porting.c:366
#define FOR_BELOW_FINISH()
Definition: define.h:748
object * object_find_by_arch_name(const object *who, const char *name)
Definition: object.c:4031
uint8_t resurrection
Definition: global.h:267
#define FOR_INV_PREPARE(op_, it_)
Definition: define.h:707
int cast_spell(object *op, object *caster, int dir, object *spell_ob, char *stringarg)
Definition: spell_util.c:1467
SockList inbuf
Definition: newserver.h:99
void object_remove(object *op)
Definition: object.c:1577
#define MSG_TYPE_MOTD
Definition: newclient.h:376
int hideability(object *ob)
Definition: player.c:4058
#define PU_MAGIC_DEVICE
Definition: define.h:138
#define ST_GET_PASSWORD
Definition: define.h:584
int32_t food
Definition: living.h:48
#define FLAG_FREED
Definition: define.h:233
void key_confirm_quit(object *op, char key)
Definition: player.c:1565
void Send_With_Handling(socket_struct *ns, SockList *sl)
Definition: lowlevel.c:435
Definition: object.h:224
#define ATNR_FIRE
Definition: attack.h:51
int get_thaco_bonus(int stat)
Definition: living.c:2352
void check_stat_bounds(living *stats, int8_t min_stat, int8_t max_stat)
Definition: living.c:355