Crossfire Server, Trunk  R20576
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 "living.h"
32 #include "object.h"
33 #include "shared/newclient.h"
34 #include "shop.h"
35 #include "skills.h"
36 #include "sounds.h"
37 #include "spells.h"
38 #include "sproto.h"
39 
41 
42 static void kill_player_not_permadeath(object *op);
43 static void kill_player_permadeath(object *op);
44 static int action_makes_visible(object *op);
45 
54 player *find_player(const char *plname) {
55  return find_player_options(plname, 0, NULL);
56 }
57 
65 player *find_player_options(const char *plname, int options, const mapstruct *map) {
66  player *pl;
67  player *found = NULL;
68  size_t namelen = strlen(plname);
69  char name[MAX_BUF];
70 
71  for (pl = first_player; pl != NULL; pl = pl->next) {
72  if ((options & FIND_PLAYER_NO_HIDDEN_DM) && (QUERY_FLAG(pl->ob, FLAG_WIZ) && pl->ob->contr->hidden))
73  continue;
74 
75  if (map != NULL && pl->ob->map != map)
76  continue;
77 
78  if (!(options & FIND_PLAYER_PARTIAL_NAME)) {
79  query_name(pl->ob, name, sizeof(name));
80  if (!strcmp(name, plname))
81  return pl;
82  continue;
83  }
84 
85  if (strlen(pl->ob->name) < namelen)
86  continue;
87 
88  if (!strcmp(pl->ob->name, plname))
89  return pl;
90 
91  if (!strncasecmp(pl->ob->name, plname, namelen)) {
92  if (found)
93  return NULL;
94 
95  found = pl;
96  }
97  }
98  return found;
99 }
100 
109 player *find_player_partial_name(const char *plname) {
110  return find_player_options(plname, FIND_PLAYER_PARTIAL_NAME, NULL);
111 }
112 
119  player *pl;
120 
121  for (pl = first_player; pl != NULL; pl = pl->next) {
122  if (&pl->socket == ns)
123  return pl;
124  }
125  return NULL;
126 }
127 
134 void display_motd(const object *op) {
135  char buf[MAX_BUF];
136  char motd[HUGE_BUF];
137  FILE *fp;
138  size_t size;
139 
140  snprintf(buf, sizeof(buf), "%s/%s", settings.confdir, settings.motd);
141  fp = fopen(buf, "r");
142  if (fp == NULL) {
143  return;
144  }
145  motd[0] = '\0';
146  size = 0;
147 
148  while (fgets(buf, MAX_BUF, fp) != NULL) {
149  if (*buf != '#') {
150  safe_strcat(motd, buf, &size, sizeof(motd));
151  }
152  }
153 
155  motd);
156  fclose(fp);
157 }
158 
165 void send_rules(const object *op) {
166  char buf[MAX_BUF];
167  char rules[HUGE_BUF];
168  FILE *fp;
169  size_t size;
170 
171  snprintf(buf, sizeof(buf), "%s/%s", settings.confdir, settings.rules);
172  fp = fopen(buf, "r");
173  if (fp == NULL) {
174  return;
175  }
176  rules[0] = '\0';
177  size = 0;
178 
179  while (fgets(buf, MAX_BUF, fp) != NULL) {
180  if (size+strlen(buf) >= HUGE_BUF) {
181  LOG(llevDebug, "Warning, rules size is > %d bytes.\n", HUGE_BUF);
182  break;
183  }
184 
185  if (*buf != '#') {
186  safe_strcat(rules, buf, &size, sizeof(rules));
187  }
188  }
189 
191  MSG_TYPE_ADMIN_RULES, rules);
192  fclose(fp);
193 }
194 
201 void send_news(const object *op) {
202  char buf[MAX_BUF];
203  char news[HUGE_BUF];
204  char subject[MAX_BUF];
205  FILE *fp;
206  size_t size;
207 
208  snprintf(buf, sizeof(buf), "%s/%s", settings.confdir, settings.news);
209  fp = fopen(buf, "r");
210  if (fp == NULL)
211  return;
212  news[0] = '\0';
213  subject[0] = '\0';
214  size = 0;
215  while (fgets(buf, MAX_BUF, fp) != NULL) {
216  if (*buf == '#')
217  continue;
218  if (*buf == '%') { /* send one news */
219  if (size > 0)
222  "%s:\n%s",
223  subject, news); /*send previously read news*/
224  safe_strncpy(subject, buf + 1, sizeof(subject));
225  strip_endline(subject);
226  size = 0;
227  news[0] = '\0';
228  } else {
229  if (size+strlen(buf) >= HUGE_BUF) {
230  LOG(llevDebug, "Warning, one news item has size > %d bytes.\n", HUGE_BUF);
231  break;
232  }
233  safe_strcat(news, buf, &size, sizeof(news));
234  }
235  }
236 
239  "%s:\n%s",
240  subject, news);
241  fclose(fp);
242 }
243 
252 int playername_ok(const char *cp) {
253  /* Don't allow - or _ as first character in the name */
254  if (*cp == '-' || *cp == '_')
255  return 0;
256 
257  for (; *cp != '\0'; cp++)
258  if (!((*cp >= 'a' && *cp <= 'z') || (*cp >= 'A' && *cp <= 'Z'))
259  && *cp != '-'
260  && *cp != '_')
261  return 0;
262  return 1;
263 }
264 
281  object *op = arch_to_object(get_player_archetype(NULL));
282  int i;
283 
284  if (!p) {
285  player *tmp;
286 
287  p = (player *)malloc(sizeof(player));
288  if (p == NULL)
290 
291  /* This adds the player in the linked list. There is extra
292  * complexity here because we want to add the new player at the
293  * end of the list - there is in fact no compelling reason that
294  * that needs to be done except for things like output of
295  * 'who'.
296  */
297  tmp = first_player;
298  while (tmp != NULL && tmp->next != NULL)
299  tmp = tmp->next;
300  if (tmp != NULL)
301  tmp->next = p;
302  else
303  first_player = p;
304 
305  p->next = NULL;
306  /* This only needs to be done on initial creation of player
307  * object. the callers of get_player() will copy over the
308  * socket structure to p->socket, and if this is an existing
309  * player object, that has been done. The call to
310  * roll_stats() below will try to send spell information to
311  * the client - if this is non zero (eg, garbage from not
312  * being cleared), that will cause problems. So just clear
313  * it, and no spell data is sent.
314  */
315  p->socket.monitor_spells = 0;
316  } else {
317  /* Only needed when reusing existing player. */
318  clear_player(p);
319  }
320 
321  /* Clears basically the entire player structure except
322  * for next and socket.
323  */
324  memset((void *)((char *)p+offsetof(player, maplevel)), 0, sizeof(player)-offsetof(player, maplevel));
325 
326  /* There are some elements we want initialized to non zero value -
327  * we deal with that below this point.
328  */
329  p->party = NULL;
332  p->swap_first = -1;
333 
334 #ifdef AUTOSAVE
335  p->last_save_tick = 9999999;
336 #endif
337 
338  strcpy(p->savebed_map, first_map_path); /* Init. respawn position */
339 
340  op->contr = p; /* this aren't yet in archetype */
341  p->ob = op;
342  op->speed_left = 0.5;
343  op->speed = 1.0;
344  op->direction = 5; /* So player faces south */
345  op->stats.wc = 2;
346  op->run_away = 25; /* Then we panic... */
347 
348  roll_stats(op);
350  clear_los(op);
351 
352  p->gen_sp_armour = 10;
353  p->last_speed = -1;
354  p->shoottype = range_none;
355  p->bowtype = bow_normal;
356  p->petmode = pet_normal;
357  p->listening = 10;
358  p->last_weapon_sp = -1;
359  p->peaceful = 1; /* default peaceful */
360  p->do_los = 1;
361  p->no_shout = 0; /* default can shout */
362  p->language = 0;
363  p->unarmed_skill = NULL;
364  p->ticks_played = 0;
365 
366  strncpy(p->title, op->arch->clone.name, sizeof(p->title)-1);
367  p->title[sizeof(p->title)-1] = '\0';
368  op->race = add_string(op->arch->clone.race);
369 
371 
372  /* we need to clear these to -1 and not zero - otherwise,
373  * if a player quits and starts a new character, we wont
374  * send new values to the client, as things like exp start
375  * at zero.
376  */
377  for (i = 0; i < NUM_SKILLS; i++) {
378  p->last_skill_exp[i] = -1;
379  p->last_skill_ob[i] = NULL;
380  }
381  for (i = 0; i < NROFATTACKS; i++) {
382  p->last_resist[i] = -1;
383  }
384  p->last_stats.exp = -1;
385  p->last_weight = (uint32_t)-1;
386 
387  p->socket.update_look = 0;
388  p->socket.look_position = 0;
389  return p;
390 }
391 
398 void set_first_map(object *op) {
399  strcpy(op->contr->maplevel, first_map_path);
400  op->x = -1;
401  op->y = -1;
403 }
404 
417 static void set_player_socket(player *p, socket_struct *ns) {
418  memcpy(&p->socket, ns, sizeof(socket_struct));
419 
420  /* The memcpy above copies the reference to faces sent. So we need to clear
421  * that pointer in ns, otherwise we get a double free.
422  */
423  ns->faces_sent = NULL;
424 
425  if (p->socket.faces_sent == NULL)
427 
428  /* Needed because the socket we just copied over needs to be cleared.
429  * Note that this can result in a client reset if there is partial data
430  * on the incoming socket.
431  */
433 
434 
435 }
436 
454  player *p;
455 
456  p = get_player(NULL);
457  set_player_socket(p, ns);
458 
460 
461  if (!(flags & ADD_PLAYER_NO_MAP))
462  set_first_map(p->ob);
463 
465 
466  /* In this case, the client is provide all the informatin for the
467  * new character, so just return it. Do not display any messages,
468  * etc
469  */
470  if (flags & ADD_PLAYER_NO_STATS_ROLL)
471  return p;
472 
473  if (flags & ADD_PLAYER_NEW) {
474  roll_again(p->ob);
476  } else {
477  send_rules(p->ob);
478  send_news(p->ob);
479  display_motd(p->ob);
480  get_name(p->ob);
481  }
482  return p;
483 }
484 
496  archetype *start = at;
497 
498  for (;;) {
499  if (at == NULL || at->next == NULL)
500  at = first_archetype;
501  else
502  at = at->next;
503  if (at->clone.type == PLAYER)
504  return at;
505  if (at == start) {
506  LOG(llevError, "No Player archetypes\n");
507  exit(-1);
508  }
509  }
510 }
511 
520 object *get_nearest_player(object *mon) {
521  object *op = NULL;
522  player *pl = NULL;
523  objectlink *ol;
524  unsigned lastdist;
525  rv_vector rv;
526 
527  for (ol = first_friendly_object, lastdist = 1000; ol != NULL; ol = ol->next) {
528  /* We should not find free objects on this friendly list, but it
529  * does periodically happen. Given that, lets deal with it.
530  * While unlikely, it is possible the next object on the friendly
531  * list is also free, so encapsulate this in a while loop.
532  */
533  while (QUERY_FLAG(ol->ob, FLAG_FREED) || !QUERY_FLAG(ol->ob, FLAG_FRIENDLY)) {
534  object *tmp = ol->ob;
535 
536  /* Can't do much more other than log the fact, because the object
537  * itself will have been cleared.
538  */
539  LOG(llevDebug, "get_nearest_player: Found free/non friendly object on friendly list\n");
540  ol = ol->next;
542  if (!ol)
543  return op;
544  }
545 
546  /* Remove special check for player from this. First, it looks to cause
547  * some crashes (ol->ob->contr not set properly?), but secondly, a more
548  * complicated method of state checking would be needed in any case -
549  * as it was, a clever player could type quit, and the function would
550  * skip them over while waiting for confirmation. Remove
551  * on_same_map check, as monster_can_detect_enemy() also does this
552  */
553  if (!monster_can_detect_enemy(mon, ol->ob, &rv))
554  continue;
555 
556  if (lastdist > rv.distance) {
557  op = ol->ob;
558  lastdist = rv.distance;
559  }
560  }
561  for (pl = first_player; pl != NULL; pl = pl->next) {
562  if (monster_can_detect_enemy(mon, pl->ob, &rv)) {
563  if (lastdist > rv.distance) {
564  op = pl->ob;
565  lastdist = rv.distance;
566  }
567  }
568  }
569  return op;
570 }
571 
581 #define DETOUR_AMOUNT 2
582 
596 #define MAX_SPACES 50
597 
629 int path_to_player(object *mon, object *pl, unsigned mindiff) {
630  rv_vector rv;
631  int16_t x, y;
632  int lastx, lasty, dir, i, diff, firstdir = 0, lastdir, max = MAX_SPACES, mflags, blocked;
633  mapstruct *m, *lastmap;
634 
635  if (!get_rangevector(mon, pl, &rv, 0))
636  return 0;
637 
638  if (rv.distance < mindiff)
639  return 0;
640 
641  x = mon->x;
642  y = mon->y;
643  m = mon->map;
644  dir = rv.direction;
645  lastdir = firstdir = rv.direction; /* perhaps we stand next to pl, init firstdir too */
646  diff = MAX(FABS(rv.distance_x), FABS(rv.distance_y));
647  /* If we can't solve it within the search distance, return now. */
648  if (diff > max)
649  return 0;
650  while (diff > 1 && max > 0) {
651  lastx = x;
652  lasty = y;
653  lastmap = m;
654  x = lastx+freearr_x[dir];
655  y = lasty+freearr_y[dir];
656 
657  mflags = get_map_flags(m, &m, x, y, &x, &y);
658  blocked = (mflags&P_OUT_OF_MAP) ? MOVE_ALL : GET_MAP_MOVE_BLOCK(m, x, y);
659 
660  /* Space is blocked - try changing direction a little */
661  if ((mflags&P_OUT_OF_MAP)
662  || ((OB_TYPE_MOVE_BLOCK(mon, blocked) || (mflags&P_IS_ALIVE))
663  && (m == mon->map && blocked_link(mon, m, x, y)))) {
664  /* recalculate direction from last good location. Possible
665  * we were not traversing ideal location before.
666  */
667  if (get_rangevector_from_mapcoord(lastmap, lastx, lasty, pl, &rv, 0) && rv.direction != dir) {
668  /* OK - says direction should be different - lets reset the
669  * the values so it will try again.
670  */
671  x = lastx;
672  y = lasty;
673  m = lastmap;
674  dir = firstdir = rv.direction;
675  } else {
676  /* direct path is blocked - try taking a side step to
677  * either the left or right.
678  * Note increase the values in the loop below to be
679  * more than -1/1 respectively will mean the monster takes
680  * bigger detour. Have to be careful about these values getting
681  * too big (3 or maybe 4 or higher) as the monster may just try
682  * stepping back and forth
683  */
684  for (i = -DETOUR_AMOUNT; i <= DETOUR_AMOUNT; i++) {
685  if (i == 0)
686  continue; /* already did this, so skip it */
687  /* Use lastdir here - otherwise,
688  * since the direction that the creature should move in
689  * may change, you could get infinite loops.
690  * ie, player is northwest, but monster can only
691  * move west, so it does that. It goes some distance,
692  * gets blocked, finds that it should move north,
693  * can't do that, but now finds it can move east, and
694  * gets back to its original point. lastdir contains
695  * the last direction the creature has successfully
696  * moved.
697  */
698 
699  x = lastx+freearr_x[absdir(lastdir+i)];
700  y = lasty+freearr_y[absdir(lastdir+i)];
701  m = lastmap;
702  mflags = get_map_flags(m, &m, x, y, &x, &y);
703  if (mflags&P_OUT_OF_MAP)
704  continue;
705  blocked = GET_MAP_MOVE_BLOCK(m, x, y);
706  if (OB_TYPE_MOVE_BLOCK(mon, blocked))
707  continue;
708  if (mflags&P_IS_ALIVE)
709  continue;
710 
711  if (m == mon->map && blocked_link(mon, m, x, y))
712  break;
713  }
714  /* go through entire loop without finding a valid
715  * sidestep to take - thus, no valid path.
716  */
717  if (i == (DETOUR_AMOUNT+1))
718  return 0;
719  diff--;
720  lastdir = dir;
721  max--;
722  if (!firstdir)
723  firstdir = dir+i;
724  } /* else check alternate directions */
725  } /* if blocked */
726  else {
727  /* we moved towards creature, so diff is less */
728  diff--;
729  max--;
730  lastdir = dir;
731  if (!firstdir)
732  firstdir = dir;
733  }
734  if (diff <= 1) {
735  /* Recalculate diff (distance) because we may not have actually
736  * headed toward player for entire distance.
737  */
738  if (!get_rangevector_from_mapcoord(m, x, y, pl, &rv, 0))
739  return 0;
740  diff = MAX(FABS(rv.distance_x), FABS(rv.distance_y));
741  }
742  if (diff > max)
743  return 0;
744  }
745  /* If we reached the max, didn't find a direction in time */
746  if (!max)
747  return 0;
748 
749  return firstdir;
750 }
751 
762 void give_initial_items(object *pl, treasurelist *items) {
763  if (pl->randomitems != NULL)
764  create_treasure(items, pl, GT_STARTEQUIP|GT_ONLY_GOOD, 1, 0);
765 
766  FOR_INV_PREPARE(pl, op) {
767  /* Forces get applied per default, unless they have the
768  * flag "neutral" set. Sorry but I can't think of a better way
769  */
770  if (op->type == FORCE && !QUERY_FLAG(op, FLAG_NEUTRAL))
771  SET_FLAG(op, FLAG_APPLIED);
772 
773  /* we never give weapons/armour if these cannot be used
774  * by this player due to race restrictions
775  */
776  if (pl->type == PLAYER) {
777  if ((!QUERY_FLAG(pl, FLAG_USE_ARMOUR) && IS_ARMOR(op))
778  || (!QUERY_FLAG(pl, FLAG_USE_WEAPON) && IS_WEAPON(op))
779  || (!QUERY_FLAG(pl, FLAG_USE_SHIELD) && IS_SHIELD(op))) {
780  object_remove(op);
782  continue;
783  }
784  }
785 
786  /* This really needs to be better - we should really give
787  * a substitute spellbook. The problem is that we don't really
788  * have a good idea what to replace it with (need something like
789  * a first level treasurelist for each skill.)
790  * remove duplicate skills also
791  */
792  if (op->type == SPELLBOOK || op->type == SKILL) {
793  int found;
794 
795  found = 0;
796  FOR_BELOW_PREPARE(op, tmp)
797  if (tmp->type == op->type && tmp->name == op->name) {
798  found = 1;
799  break;
800  }
802  if (found) {
803  LOG(llevError, "give_initial_items: Removing duplicate object %s\n", op->name);
804  object_remove(op);
806  continue;
807  }
808  if (op->nrof > 1)
809  op->nrof = 1;
810  }
811 
812  if (op->type == SPELLBOOK && op->inv) {
813  CLEAR_FLAG(op->inv, FLAG_STARTEQUIP);
814  }
815 
816  /* Give starting characters identified, uncursed, and undamned
817  * items. Just don't identify gold or silver, or it won't be
818  * merged properly.
819  */
820  if (need_identify(op)) {
822  CLEAR_FLAG(op, FLAG_CURSED);
823  CLEAR_FLAG(op, FLAG_DAMNED);
824  }
825  if (op->type == SKILL) {
827  op->stats.exp = 0;
828  op->level = 1;
829  }
830  /* lock all 'normal items by default */
831  else
833  } FOR_INV_FINISH(); /* for loop of objects in player inv */
834 
835  /* Need to set up the skill pointers */
836  link_player_skills(pl);
837 
842  FOR_INV_PREPARE(pl, op)
843  if ((IS_ARMOR(op) || IS_WEAPON(op) || IS_SHIELD(op)) && !QUERY_FLAG(op, FLAG_APPLIED))
844  apply_manual(pl, op, AP_NOPRINT);
845  FOR_INV_FINISH();
846 }
847 
854 void get_name(object *op) {
855  op->contr->write_buf[0] = '\0';
857  send_query(&op->contr->socket, 0, "What is your name?\n:");
858 }
859 
866 void get_password(object *op) {
867  op->contr->write_buf[0] = '\0';
869  send_query(&op->contr->socket, CS_QUERY_HIDEINPUT, "What is your password?\n:");
870 }
871 
878 void play_again(object *op) {
879  SockList sl;
880 
882  op->chosen_skill = NULL;
883 
884  /*
885  * For old clients, ask if they want to play again.
886  * For clients with account support, just return to character seletion (see below).
887  */
888  if (op->contr->socket.login_method == 0) {
889  send_query(&op->contr->socket, CS_QUERY_SINGLECHAR, "Do you want to play again (a/q)?");
890  }
891  /* a bit of a hack, but there are various places early in th
892  * player creation process that a user can quit (eg, roll
893  * stats) that isn't removing the player. Taking a quick
894  * look, there are many places that call play_again without
895  * removing the player - it probably makes more sense
896  * to leave it to play_again to remove the object in all
897  * cases.
898  */
899  if (!QUERY_FLAG(op, FLAG_REMOVED))
900  object_remove(op);
901  /* Need to set this to null - otherwise, it could point to garbage,
902  * and draw() doesn't check to see if the player is removed, only if
903  * the map is null or not swapped out.
904  */
905  op->map = NULL;
906 
907  SockList_Init(&sl);
908  SockList_AddString(&sl, "player ");
909  SockList_AddInt(&sl, 0);
910  SockList_AddInt(&sl, 0);
911  SockList_AddInt(&sl, 0);
912  SockList_AddChar(&sl, 0);
913 
914  Send_With_Handling(&op->contr->socket, &sl);
915  SockList_Term(&sl);
916 
917  if (op->contr->socket.login_method > 0) {
918  receive_play_again(op, 'a');
919  }
920 }
921 
930 void receive_play_again(object *op, char key) {
931  if (key == 'q' || key == 'Q') {
933  leave(op->contr, 0); /* ericserver will draw the message */
934  return;
935  } else if (key == 'a' || key == 'A') {
936  player *pl = op->contr;
937  const char *name = op->name;
938 
939  add_refcount(name);
942  pl = get_player(pl);
943  op = pl->ob;
945  op->contr->password[0] = '~';
948  if (pl->socket.login_method >= 1 && pl->socket.account_name != NULL) {
949  /* If we are using new login, we send the
950  * list of characters to the client - this should
951  * result in the client popping up this list so
952  * the player can choose which one to play - better
953  * than going to legacy login code.
954  * If the account_name is NULL, it means the client
955  * says it uses account but started playing without logging in.
956  */
959  } else {
960  /* Lets put a space in here */
962  "\n");
963  get_name(op);
964  set_first_map(op);
965  }
966  op->name = name; /* Already added a refcount above */
967  op->name_pl = add_string(name);
968  } else {
969  /* user pressed something else so just ask again... */
970  play_again(op);
971  }
972 }
973 
980 void confirm_password(object *op) {
981  op->contr->write_buf[0] = '\0';
983  send_query(&op->contr->socket, CS_QUERY_HIDEINPUT, "Please type your password again.\n:");
984 }
985 
996 int get_party_password(object *op, partylist *party) {
997  if (*party_get_password(party) == '\0') {
998  return 0;
999  }
1000 
1001  op->contr->write_buf[0] = '\0';
1003  op->contr->party_to_join = party;
1004  send_query(&op->contr->socket, CS_QUERY_HIDEINPUT, "What is the password?\n:");
1005  return 1;
1006 }
1007 
1014 int roll_stat(void) {
1015  int roll[4], i, low_index, k;
1016 
1017  for (i = 0; i < 4; ++i)
1018  roll[i] = (int)RANDOM()%6+1;
1019 
1020  for (i = 0, low_index = 0, k = 7; i < 4; ++i)
1021  if (roll[i] < k)
1022  k = roll[i],
1023  low_index = i;
1024 
1025  for (i = 0, k = 0; i < 4; ++i) {
1026  if (i != low_index)
1027  k += roll[i];
1028  }
1029  return k;
1030 }
1031 
1038 void roll_stats(object *op) {
1039  int sum = 0;
1040  int i = 0, j = 0;
1041  int statsort[7];
1042 
1043  do {
1044  op->stats.Str = roll_stat();
1045  op->stats.Dex = roll_stat();
1046  op->stats.Int = roll_stat();
1047  op->stats.Con = roll_stat();
1048  op->stats.Wis = roll_stat();
1049  op->stats.Pow = roll_stat();
1050  op->stats.Cha = roll_stat();
1051  sum = op->stats.Str+op->stats.Dex+op->stats.Int+op->stats.Con+op->stats.Wis+op->stats.Pow+op->stats.Cha;
1052  } while (sum != settings.roll_stat_points);
1053 
1054  /* Sort the stats so that rerolling is easier... */
1055  statsort[0] = op->stats.Str;
1056  statsort[1] = op->stats.Dex;
1057  statsort[2] = op->stats.Int;
1058  statsort[3] = op->stats.Con;
1059  statsort[4] = op->stats.Wis;
1060  statsort[5] = op->stats.Pow;
1061  statsort[6] = op->stats.Cha;
1062 
1063  /* a quick and dirty bubblesort? */
1064  do {
1065  if (statsort[i] < statsort[i+1]) {
1066  j = statsort[i];
1067  statsort[i] = statsort[i+1];
1068  statsort[i+1] = j;
1069  i = 0;
1070  } else {
1071  i++;
1072  }
1073  } while (i < 6);
1074 
1075  op->stats.Str = statsort[0];
1076  op->stats.Dex = statsort[1];
1077  op->stats.Con = statsort[2];
1078  op->stats.Int = statsort[3];
1079  op->stats.Wis = statsort[4];
1080  op->stats.Pow = statsort[5];
1081  op->stats.Cha = statsort[6];
1082 
1083  op->contr->orig_stats.Str = op->stats.Str;
1084  op->contr->orig_stats.Dex = op->stats.Dex;
1085  op->contr->orig_stats.Int = op->stats.Int;
1086  op->contr->orig_stats.Con = op->stats.Con;
1087  op->contr->orig_stats.Wis = op->stats.Wis;
1088  op->contr->orig_stats.Pow = op->stats.Pow;
1089  op->contr->orig_stats.Cha = op->stats.Cha;
1090 
1091  op->level = 1;
1092  op->stats.exp = 0;
1093  op->stats.ac = 0;
1094 
1095  op->contr->levhp[1] = 9;
1096  op->contr->levsp[1] = 6;
1097  op->contr->levgrace[1] = 3;
1098 
1099  fix_object(op);
1100  op->stats.hp = op->stats.maxhp;
1101  op->stats.sp = op->stats.maxsp;
1102  op->stats.grace = op->stats.maxgrace;
1103  op->contr->orig_stats = op->stats;
1104 }
1105 
1112 void roll_again(object *op) {
1113  esrv_new_player(op->contr, 0);
1114  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)? ");
1115 }
1116 
1126 static void swap_stat(object *op, int swap_second) {
1127  signed char tmp;
1128 
1129  if (op->contr->swap_first == -1) {
1130  LOG(llevError, "player.c:swap_stat() - swap_first is -1\n");
1131  return;
1132  }
1133 
1134  tmp = get_attr_value(&op->contr->orig_stats, op->contr->swap_first);
1135 
1136  set_attr_value(&op->contr->orig_stats, op->contr->swap_first, get_attr_value(&op->contr->orig_stats, swap_second));
1137 
1138  set_attr_value(&op->contr->orig_stats, swap_second, tmp);
1139 
1141  "%s done\n",
1142  short_stat_name[swap_second]);
1143 
1144  op->stats.Str = op->contr->orig_stats.Str;
1145  op->stats.Dex = op->contr->orig_stats.Dex;
1146  op->stats.Con = op->contr->orig_stats.Con;
1147  op->stats.Int = op->contr->orig_stats.Int;
1148  op->stats.Wis = op->contr->orig_stats.Wis;
1149  op->stats.Pow = op->contr->orig_stats.Pow;
1150  op->stats.Cha = op->contr->orig_stats.Cha;
1151  op->stats.ac = 0;
1152 
1153  op->level = 1;
1154  op->stats.exp = 0;
1155  op->stats.ac = 0;
1156 
1157  op->contr->levhp[1] = 9;
1158  op->contr->levsp[1] = 6;
1159  op->contr->levgrace[1] = 3;
1160 
1161  fix_object(op);
1162  op->stats.hp = op->stats.maxhp;
1163  op->stats.sp = op->stats.maxsp;
1164  op->stats.grace = op->stats.maxgrace;
1165  op->contr->orig_stats = op->stats;
1166  op->contr->swap_first = -1;
1167 }
1168 
1184 void key_roll_stat(object *op, char key) {
1185  int keynum = key-'0';
1186  static const int8_t stat_trans[] = {
1187  -1,
1188  STRENGTH,
1189  DEXTERITY,
1190  CONSTITUTION,
1191  INTELLIGENCE,
1192  WISDOM,
1193  POWER,
1194  CHARISMA,
1195  };
1196 
1197  if (keynum > 0 && keynum <= 7) {
1198  if (op->contr->swap_first == -1) {
1199  op->contr->swap_first = stat_trans[keynum];
1201  "%s ->",
1202  short_stat_name[stat_trans[keynum]]);
1203  } else
1204  swap_stat(op, stat_trans[keynum]);
1205 
1207  return;
1208  }
1209  switch (key) {
1210  case 'n':
1211  case 'N': {
1212  SET_FLAG(op, FLAG_WIZ);
1213  if (op->map == NULL) {
1214  LOG(llevError, "Map == NULL in state 2\n");
1215  break;
1216  }
1217 
1218  SET_ANIMATION(op, 2); /* So player faces south */
1219  /* Enter exit adds a player otherwise */
1220  add_statbonus(op);
1221  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");
1223  if (op->msg)
1224  draw_ext_info(NDI_BLUE, 0, op,
1226  op->msg);
1227  return;
1228  }
1229  case 'y':
1230  case 'Y':
1231  roll_stats(op);
1233  return;
1234 
1235  case 'q':
1236  case 'Q':
1237  play_again(op);
1238  return;
1239 
1240  default:
1241  send_query(&op->contr->socket, CS_QUERY_SINGLECHAR, "Yes, No, Quit or 1-6. Roll again?");
1242  return;
1243  }
1244  return;
1245 }
1246 
1260 void key_change_class(object *op, char key) {
1261  int tmp_loop;
1262 
1263  if (key == 'q' || key == 'Q') {
1264  object_remove(op);
1265  play_again(op);
1266  return;
1267  }
1268  if (key == 'd' || key == 'D') {
1269  char buf[MAX_BUF];
1270 
1271  /* this must before then initial items are given */
1272  esrv_new_player(op->contr, op->weight+op->carrying);
1273  create_treasure(find_treasurelist("starting_wealth"), op, 0, 0, 0);
1274 
1275  /* Lauwenmark : Here we handle the BORN global event */
1277 
1278  /* Lauwenmark : We then generate a LOGIN event */
1281 
1282  object_set_msg(op, NULL);
1283 
1284  /* We create this now because some of the unique maps will need it
1285  * to save here.
1286  */
1287  snprintf(buf, sizeof(buf), "%s/%s/%s", settings.localdir, settings.playerdir, op->name);
1288  make_path_to_file(buf);
1289 
1290 #ifdef AUTOSAVE
1291  op->contr->last_save_tick = pticks;
1292 #endif
1295  "Welcome to Crossfire!\n Press `?' for help\n");
1296 
1299  "%s entered the game.", op->name);
1300 
1301  CLEAR_FLAG(op, FLAG_WIZ);
1303  link_player_skills(op);
1304  esrv_send_inventory(op, op);
1305  fix_object(op);
1306 
1307  /* This moves the player to a different start map, if there
1308  * is one for this race
1309  */
1310  if (*first_map_ext_path) {
1311  object *tmp;
1312  char mapname[MAX_BUF];
1313  mapstruct *oldmap;
1314 
1315  oldmap = op->map;
1316 
1317  snprintf(mapname, MAX_BUF-1, "%s/%s", first_map_ext_path, op->arch->name);
1318  /*printf("%s\n", mapname);*/
1319  tmp = object_new();
1320  EXIT_PATH(tmp) = add_string(mapname);
1321  EXIT_X(tmp) = op->x;
1322  EXIT_Y(tmp) = op->y;
1323  enter_exit(op, tmp);
1324 
1325  if (oldmap != op->map) {
1326  /* map exists, update bed of reality location, in case player dies */
1327  op->contr->bed_x = op->x;
1328  op->contr->bed_y = op->y;
1329  snprintf(op->contr->savebed_map, sizeof(op->contr->savebed_map), "%s", mapname);
1330  }
1331 
1333  } else {
1334  LOG(llevDebug, "first_map_ext_path not set\n");
1335  }
1336  return;
1337  }
1338 
1339  /* Following actually changes the race - this is the default command
1340  * if we don't match with one of the options above.
1341  */
1342 
1343  tmp_loop = 0;
1344  while (!tmp_loop) {
1345  const char *name = add_string(op->name);
1346  int x = op->x, y = op->y;
1347 
1348  remove_statbonus(op);
1349  object_remove(op);
1350  /* get_player_archetype() is really misnamed - it will
1351  * get the next archetype from the list.
1352  */
1353  op->arch = get_player_archetype(op->arch);
1354  object_copy(&op->arch->clone, op);
1355  op->stats = op->contr->orig_stats;
1356  free_string(op->name);
1357  op->name = name;
1358  free_string(op->name_pl);
1359  op->name_pl = add_string(name);
1360  SET_ANIMATION(op, 2); /* So player faces south */
1361  object_insert_in_map_at(op, op->map, op, 0, x, y);
1362  strncpy(op->contr->title, op->arch->clone.name, sizeof(op->contr->title)-1);
1363  op->contr->title[sizeof(op->contr->title)-1] = '\0';
1364  add_statbonus(op);
1365  tmp_loop = allowed_class(op);
1366  }
1368  esrv_update_item(UPD_FACE, op, op);
1369  fix_object(op);
1370  op->stats.hp = op->stats.maxhp;
1371  op->stats.sp = op->stats.maxsp;
1372  op->stats.grace = 0;
1373  if (op->msg)
1375  op->msg);
1376  send_query(&op->contr->socket, CS_QUERY_SINGLECHAR, "Press any key for the next race.\nPress `d' to play this race.\n");
1377 }
1378 
1400 int check_race_and_class(living *stats, archetype *race, archetype *opclass)
1401 {
1402  int i, stat, failure=0;
1403 
1404  for (i = 0; i < NUM_STATS; i++) {
1405  stat = get_attr_value(stats, i);
1406  if (race)
1407  stat += get_attr_value(&race->clone.stats, i);
1408 
1409  if (opclass)
1410  stat += get_attr_value(&opclass->clone.stats, i);
1411 
1412  set_attr_value(stats, i, stat);
1413 
1414  /* We process all stats, regardless if there is a failure
1415  * or not.
1416  */
1417  if (stat < MIN_STAT) failure=1;
1418 
1419  /* Maybe this should be an error? Player is losing
1420  * some stats points here, but it is legal.
1421  */
1422  if (stat > settings.max_stat) stat = settings.max_stat;
1423  }
1424  return failure;
1425 
1426 }
1427 
1450 int apply_race_and_class(object *op, archetype *race, archetype *opclass, living *stats)
1451 {
1452  const char *name = add_string(op->name);
1453  char buf[MAX_BUF];
1454  object *inv;
1455 
1456  /* Free any objects in character inventory - they
1457  * shouldn't have any, but there is the potential that
1458  * we give them objects below and then get a creation
1459  * failure (stat out of range), in which case
1460  * those objects would be in the inventory.
1461  */
1462  while (op->inv) {
1463  inv = op->inv;
1464  object_remove(inv);
1465  object_free2(inv, 0);
1466  }
1467 
1468  object_copy(&race->clone, op);
1469  free_string(op->name);
1470  op->name = name;
1471  free_string(op->name_pl);
1472  op->name_pl = add_string(name);
1473  SET_ANIMATION(op, 2); /* So player faces south */
1474  snprintf(op->contr->title, sizeof(op->contr->title), "%s", op->arch->clone.name);
1475 
1476  if (stats) {
1477  /* Copy over the stats. Use this instead a memcpy because
1478  * we only want to copy over a few specific stats, and
1479  * leave things like maxhp, maxsp, etc, unchanged.
1480  */
1481  int i, stat;
1482  for (i = 0; i < NUM_STATS; i++) {
1483  stat = get_attr_value(stats, i);
1484  set_attr_value(&op->stats, i, stat);
1485  set_attr_value(&op->contr->orig_stats, i, stat);
1486  }
1487  } else {
1488  /* Note that this will repeated increase the stat values
1489  * if the caller does not reset them. Only do this
1490  * if stats is not provided - if stats is provided, those
1491  * are already adjusted.
1492  */
1493  add_statbonus(op);
1494 
1495  /* Checks that all stats are greater than 1. Once again,
1496  * only do this if stats are not provided
1497  */
1498  if (!allowed_class(op)) return 1;
1499  }
1500 
1502  op->stats.hp = op->stats.maxhp;
1503  op->stats.sp = op->stats.maxsp;
1504  op->stats.grace = 0;
1505 
1506  /* this must before then initial items are given */
1507  esrv_new_player(op->contr, op->weight+op->carrying);
1508  create_treasure(find_treasurelist("starting_wealth"), op, 0, 0, 0);
1509 
1510  /* This has to be done before class, otherwise the NOCLASSFACECHANGE
1511  * object is not in the inventory, and racial face will get overwritten.
1512  */
1514 
1515  if (stats) {
1516  /* Apply class information */
1518  } else {
1519  apply_changes_to_player(op, &opclass->clone, 0);
1520 
1521  /* Checks that all stats are greater than 1 */
1522  if (!allowed_class(op)) return 2;
1523  }
1524 
1525  /* Lauwenmark : Here we handle the BORN global event */
1527 
1528  /* Lauwenmark : We then generate a LOGIN event */
1530 
1531  object_set_msg(op, NULL);
1532 
1533  /* We create this now because some of the unique maps will need it
1534  * to save here.
1535  */
1536  snprintf(buf, sizeof(buf), "%s/%s/%s", settings.localdir, settings.playerdir, op->name);
1537  make_path_to_file(buf);
1538 
1539 #ifdef AUTOSAVE
1540  op->contr->last_save_tick = pticks;
1541 #endif
1542 
1543  CLEAR_FLAG(op, FLAG_WIZ);
1544  link_player_skills(op);
1545  fix_object(op);
1546 
1547  esrv_send_inventory(op, op);
1548  esrv_update_item(UPD_FACE, op, op);
1549 
1550  return 0;
1551 
1552 }
1553 
1562 void key_confirm_quit(object *op, char key) {
1563  char buf[MAX_BUF];
1564  mapstruct *mp, *next;
1565 
1566  // this was tested when 'quit' command was issued, but better safe than sorry.
1567  if (QUERY_FLAG(op, FLAG_WAS_WIZ)) {
1569  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_LOGIN, "Can't quit when in DM mode.");
1570  return;
1571  }
1572 
1573  if (key != 'y' && key != 'Y' && key != 'q' && key != 'Q') {
1576  "OK, continuing to play.");
1577  return;
1578  }
1579 
1580  /* Lauwenmark : Here we handle the REMOVE global event */
1582  pets_terminate_all(op);
1583  object_remove(op);
1584  op->direction = 0;
1586  "%s quits the game.",
1587  op->name);
1588 
1589  strcpy(op->contr->killer, "quit");
1590  hiscore_check(op, 0);
1591  party_leave(op);
1592  if (settings.set_title == TRUE)
1593  player_set_own_title(op->contr, "");
1594 
1595 
1596  /* We need to hunt for any per player unique maps in memory and
1597  * get rid of them. The trailing slash in the path is intentional,
1598  * so that players named 'Ab' won't match against players 'Abe' pathname
1599  */
1600  snprintf(buf, sizeof(buf), "%s/%s/%s/", settings.localdir, settings.playerdir, op->name);
1601  for (mp = first_map; mp != NULL; mp = next) {
1602  next = mp->next;
1603  if (!strncmp(mp->path, buf, strlen(buf)))
1604  delete_map(mp);
1605  }
1606 
1607  delete_character(op->name);
1608 
1609  /* Remove player from account list and send back data if needed */
1610  if (op->contr->socket.account_chars != NULL) {
1613  /* char information is reloaded in send_account_players below */
1615  op->contr->socket.account_chars = NULL;
1618  }
1619 
1620  play_again(op);
1621 }
1622 
1629 static void flee_player(object *op) {
1630  int dir, diff;
1631  rv_vector rv;
1632 
1633  if (op->stats.hp < 0) {
1634  LOG(llevDebug, "Fleeing player is dead.\n");
1635  CLEAR_FLAG(op, FLAG_SCARED);
1636  return;
1637  }
1638 
1639  if (op->enemy == NULL) {
1640  LOG(llevDebug, "Fleeing player had no enemy.\n");
1641  CLEAR_FLAG(op, FLAG_SCARED);
1642  return;
1643  }
1644 
1645  /* Seen some crashes here. Since we don't store an
1646  * op->enemy_count, it is possible that something destroys the
1647  * actual enemy, and the object is recycled.
1648  */
1649  if (op->enemy->map == NULL) {
1650  CLEAR_FLAG(op, FLAG_SCARED);
1651  object_set_enemy(op, NULL);
1652  return;
1653  }
1654 
1655  if (!(random_roll(0, 4, op, PREFER_LOW)) && did_make_save(op, op->level, 0)) {
1656  object_set_enemy(op, NULL);
1657  CLEAR_FLAG(op, FLAG_SCARED);
1658  return;
1659  }
1660  if (!get_rangevector(op, op->enemy, &rv, 0)) {
1661  object_set_enemy(op, NULL);
1662  CLEAR_FLAG(op, FLAG_SCARED);
1663  return;
1664  }
1665 
1666  dir = absdir(4+rv.direction);
1667  for (diff = 0; diff < 3; diff++) {
1668  int m = 1-(RANDOM()&2);
1669  if (move_ob(op, absdir(dir+diff*m), op)
1670  || (diff == 0 && move_ob(op, absdir(dir-diff*m), op))) {
1671  return;
1672  }
1673  }
1674  /* Cornered, get rid of scared */
1675  CLEAR_FLAG(op, FLAG_SCARED);
1676  object_set_enemy(op, NULL);
1677 }
1678 
1688 int check_pick(object *op) {
1689  tag_t op_tag;
1690  int stop = 0;
1691  int j, k, wvratio, current_ratio;
1692  char putstring[128], tmpstr[16];
1693 
1694  /* if you're flying, you can't pick up anything */
1695  if (op->move_type&MOVE_FLYING)
1696  return 1;
1697 
1698  op_tag = op->count;
1699 
1700  FOR_BELOW_PREPARE(op, tmp) {
1701  if (object_was_destroyed(op, op_tag))
1702  return 0;
1703 
1704  if (!object_can_pick(op, tmp))
1705  continue;
1706 
1707  if (op->contr->search_str[0] != '\0' && settings.search_items == TRUE) {
1708  if (object_matches_string(op, tmp, op->contr->search_str))
1709  pick_up(op, tmp);
1710  continue;
1711  }
1712 
1713  /* high not bit set? We're using the old autopickup model */
1714  if (!(op->contr->mode&PU_NEWMODE)) {
1715  switch (op->contr->mode) {
1716  case 0:
1717  return 1; /* don't pick up */
1718 
1719  case 1:
1720  pick_up(op, tmp);
1721  return 1;
1722 
1723  case 2:
1724  pick_up(op, tmp);
1725  return 0;
1726 
1727  case 3:
1728  return 0; /* stop before pickup */
1729 
1730  case 4:
1731  pick_up(op, tmp);
1732  break;
1733 
1734  case 5:
1735  pick_up(op, tmp);
1736  stop = 1;
1737  break;
1738 
1739  case 6:
1740  if (QUERY_FLAG(tmp, FLAG_KNOWN_MAGICAL)
1741  && !QUERY_FLAG(tmp, FLAG_KNOWN_CURSED))
1742  pick_up(op, tmp);
1743  break;
1744 
1745  case 7:
1746  if (tmp->type == MONEY || tmp->type == GEM)
1747  pick_up(op, tmp);
1748  break;
1749 
1750  default:
1751  /* use value density */
1752  if (!QUERY_FLAG(tmp, FLAG_UNPAID)
1753  && (price_base(tmp)*100/(tmp->weight*MAX(tmp->nrof, 1))) >= op->contr->mode)
1754  pick_up(op, tmp);
1755  }
1756  } else { /* old model */
1757  /* NEW pickup handling */
1758  if (op->contr->mode&PU_DEBUG) {
1759  /* some debugging code to figure out item information */
1761  "item name: %s item type: %d weight/value: %d",
1762  tmp->name ? tmp->name : tmp->arch->name, tmp->type,
1763  (int)(price_base(tmp)*100/(tmp->weight*MAX(tmp->nrof, 1))));
1764 
1765 
1766  snprintf(putstring, sizeof(putstring), "...flags: ");
1767  for (k = 0; k < 4; k++) {
1768  for (j = 0; j < 32; j++) {
1769  if ((tmp->flags[k]>>j)&0x01) {
1770  snprintf(tmpstr, sizeof(tmpstr), "%d ", k*32+j);
1771  strcat(putstring, tmpstr);
1772  }
1773  }
1774  }
1776  putstring);
1777  }
1778  /* philosophy:
1779  * It's easy to grab an item type from a pile, as long as it's
1780  * generic. This takes no game-time. For more detailed pickups
1781  * and selections, select-items should be used. This is a
1782  * grab-as-you-run type mode that's really useful for arrows for
1783  * example.
1784  * The drawback: right now it has no frontend, so you need to
1785  * stick the bits you want into a calculator in hex mode and then
1786  * convert to decimal and then 'pickup <#>
1787  */
1788 
1789  /* the first two modes are exclusive: if NOTHING we return, if
1790  * STOP then we stop. All the rest are applied sequentially,
1791  * meaning if any test passes, the item gets picked up. */
1792 
1793  /* if mode is set to pick nothing up, return */
1794 
1795  if (op->contr->mode == PU_NOTHING)
1796  return 1;
1797 
1798  /* if mode is set to stop when encountering objects, return.
1799  * Take STOP before INHIBIT since it doesn't actually pick
1800  * anything up */
1801 
1802  if (op->contr->mode&PU_STOP)
1803  return 0;
1804 
1805  /* useful for going into stores and not losing your settings... */
1806  /* and for battles where you don't want to get loaded down while
1807  * fighting */
1808  if (op->contr->mode&PU_INHIBIT)
1809  return 1;
1810 
1811  /* prevent us from turning into auto-thieves :) */
1812  if (QUERY_FLAG(tmp, FLAG_UNPAID))
1813  continue;
1814 
1815  /* ignore known cursed objects */
1817  continue;
1818 
1819  /* all food and drink if desired */
1820  /* question: don't pick up known-poisonous stuff? */
1821  if (op->contr->mode&PU_FOOD)
1822  if (tmp->type == FOOD) {
1823  pick_up(op, tmp);
1824  continue;
1825  }
1826  if (op->contr->mode&PU_DRINK)
1827  if (tmp->type == DRINK || (tmp->type == POISON && !QUERY_FLAG(tmp, FLAG_KNOWN_CURSED))) {
1828  pick_up(op, tmp);
1829  continue;
1830  }
1831  /* we don't forget dragon food */
1832  if (op->contr->mode&PU_FLESH)
1833  if (tmp->type == FLESH) {
1834  pick_up(op, tmp);
1835  continue;
1836  }
1837  if (op->contr->mode&PU_POTION)
1838  if (tmp->type == POTION) {
1839  pick_up(op, tmp);
1840  continue;
1841  }
1842 
1843  /* spellbooks, skillscrolls and normal books/scrolls */
1844  if (op->contr->mode&PU_SPELLBOOK)
1845  if (tmp->type == SPELLBOOK) {
1846  pick_up(op, tmp);
1847  continue;
1848  }
1849  if (op->contr->mode&PU_SKILLSCROLL)
1850  if (tmp->type == SKILLSCROLL) {
1851  pick_up(op, tmp);
1852  continue;
1853  }
1854  if (op->contr->mode&PU_READABLES)
1855  if (tmp->type == BOOK || tmp->type == SCROLL) {
1856  pick_up(op, tmp);
1857  continue;
1858  }
1859 
1860  /* wands/staves/rods/horns/skill tools */
1861  if (op->contr->mode&PU_MAGIC_DEVICE)
1862  if (tmp->type == WAND || tmp->type == ROD || tmp->type == WEAPON_IMPROVER || tmp->type == ARMOUR_IMPROVER || tmp->type == SKILL_TOOL) {
1863  pick_up(op, tmp);
1864  continue;
1865  }
1866 
1867  /* pick up all magical items */
1868  if (op->contr->mode&PU_MAGICAL)
1870  pick_up(op, tmp);
1871  continue;
1872  }
1873 
1874  if (op->contr->mode&PU_VALUABLES) {
1875  if (tmp->type == MONEY || tmp->type == GEM) {
1876  pick_up(op, tmp);
1877  continue;
1878  }
1879  }
1880 
1881  /* rings & amulets - talismans seems to be typed AMULET */
1882  if (op->contr->mode&PU_JEWELS)
1883  if (tmp->type == RING || tmp->type == AMULET) {
1884  pick_up(op, tmp);
1885  continue;
1886  }
1887 
1888  /* bows and arrows. Bows are good for selling! */
1889  if (op->contr->mode&PU_BOW)
1890  if (tmp->type == BOW) {
1891  pick_up(op, tmp);
1892  continue;
1893  }
1894  if (op->contr->mode&PU_ARROW)
1895  if (tmp->type == ARROW) {
1896  pick_up(op, tmp);
1897  continue;
1898  }
1899 
1900  /* all kinds of armor etc. */
1901  if (op->contr->mode&PU_ARMOUR)
1902  if (tmp->type == ARMOUR) {
1903  pick_up(op, tmp);
1904  continue;
1905  }
1906  if (op->contr->mode&PU_HELMET)
1907  if (tmp->type == HELMET) {
1908  pick_up(op, tmp);
1909  continue;
1910  }
1911  if (op->contr->mode&PU_SHIELD)
1912  if (tmp->type == SHIELD) {
1913  pick_up(op, tmp);
1914  continue;
1915  }
1916  if (op->contr->mode&PU_BOOTS)
1917  if (tmp->type == BOOTS) {
1918  pick_up(op, tmp);
1919  continue;
1920  }
1921  if (op->contr->mode&PU_GLOVES)
1922  if (tmp->type == GLOVES) {
1923  pick_up(op, tmp);
1924  continue;
1925  }
1926  if (op->contr->mode&PU_CLOAK)
1927  if (tmp->type == CLOAK) {
1928  pick_up(op, tmp);
1929  continue;
1930  }
1931 
1932  /* hoping to catch throwing daggers here */
1933  if (op->contr->mode&PU_MISSILEWEAPON)
1934  if (tmp->type == WEAPON && QUERY_FLAG(tmp, FLAG_IS_THROWN)) {
1935  pick_up(op, tmp);
1936  continue;
1937  }
1938 
1939  /* careful: chairs and tables are weapons! */
1940  if (op->contr->mode&PU_MELEEWEAPON) {
1941  if (tmp->type == WEAPON && tmp->name != NULL) {
1942  if (strstr(tmp->name, "table") == NULL
1943  && strstr(tmp->arch->name, "table") == NULL
1944  && strstr(tmp->name, "chair") == NULL
1945  && strstr(tmp->arch->name, "chair") == NULL) {
1946  pick_up(op, tmp);
1947  continue;
1948  }
1949  }
1950  if (tmp->type == WEAPON && tmp->name == NULL) {
1951  if (strstr(tmp->arch->name, "table") == NULL
1952  && strstr(tmp->arch->name, "chair") == NULL) {
1953  pick_up(op, tmp);
1954  continue;
1955  }
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  tmp = object_find_by_type(container, KEY);
2549  }
2550  /* For sanity, we should really check door type, but other stuff
2551  * (like containers) can be locked with special keys
2552  */
2553  if (!tmp && door->slaying != NULL) {
2554  tmp = object_find_by_type_and_slaying(container, SPECIAL_KEY, door->slaying);
2555  }
2556  /* No key found - lets search inventories now */
2557  /* If we find and use a key in an inventory, return at that time.
2558  * otherwise, if we search all the inventories and still don't find
2559  * a key, return
2560  */
2561  if (!tmp) {
2562  FOR_INV_PREPARE(container, tmp) {
2563  /* No reason to search empty containers */
2564  if (tmp->type == CONTAINER && tmp->inv) {
2565  key = find_key(pl, tmp, door);
2566  if (key != NULL)
2567  return key;
2568  }
2569  } FOR_INV_FINISH();
2570  return NULL;
2571  }
2572  /* We get down here if we have found a key. Now if its in a container,
2573  * see if we actually want to use it
2574  */
2575  if (pl != container) {
2576  /* Only let players use keys in containers */
2577  if (!pl->contr)
2578  return NULL;
2579  /* cases where this fails:
2580  * If we only search the player inventory, return now since we
2581  * are not in the players inventory.
2582  * If the container is not active, return now since only active
2583  * containers can be used.
2584  * If we only search keyrings and the container does not have
2585  * a race/isn't a keyring.
2586  * No checking for all containers - to fall through past here,
2587  * inv must have been an container and must have been active.
2588  *
2589  * Change the color so that the message doesn't disappear with
2590  * all the others.
2591  */
2592  if (pl->contr->usekeys == key_inventory
2593  || !QUERY_FLAG(container, FLAG_APPLIED)
2594  || (pl->contr->usekeys == keyrings && (!container->race || strcmp(container->race, "keys")))) {
2595  char name_tmp[MAX_BUF], name_cont[MAX_BUF];
2596 
2597  query_name(tmp, name_tmp, MAX_BUF);
2598  query_name(container, name_cont, MAX_BUF);
2601  "The %s in your %s vibrates as you approach the door",
2602  name_tmp, name_cont);
2603  return NULL;
2604  }
2605  }
2606  return tmp;
2607 }
2608 
2619 static int player_attack_door(object *op, object *door) {
2620  /* If its a door, try to find a use a key. If we do destroy the door,
2621  * might as well return immediately as there is nothing more to do -
2622  * otherwise, we fall through to the rest of the code.
2623  */
2624  object *key = find_key(op, op, door);
2625 
2626  assert(door->type == DOOR || door->type == LOCKED_DOOR);
2627 
2628  /* IF we found a key, do some extra work */
2629  if (key) {
2630  char name[HUGE_BUF];
2631 
2632  play_sound_map(SOUND_TYPE_GROUND, door, 0, "open");
2633  if (action_makes_visible(op))
2634  make_visible(op);
2635  if (door->inv && (door->inv->type == RUNE || door->inv->type == TRAP))
2636  spring_trap(door->inv, op);
2637 
2638  query_short_name(key, name, HUGE_BUF);
2641  "You open the door with the %s",
2642  name);
2643 
2644  if (door->type == DOOR)
2645  remove_door(door);
2646  else
2647  remove_locked_door(door); /* remove door without violence ;-) */
2648 
2649  /* Do this after we print the message */
2650  object_decrease_nrof_by_one(key); /* Use up one of the keys */
2651 
2652  return 1; /* Nothing more to do below */
2653 
2654  }
2655 
2656  if (door->type == LOCKED_DOOR) {
2657  /* Might as well return now - no other way to open this */
2659  door->msg);
2660  return 1;
2661  }
2662 
2663  if (door->type == DOOR && op->contr && !op->contr->run_on) {
2664  /* Player so try to pick the door */
2665  object *lock = find_skill_by_name(op, "lockpicking");
2666  if (lock) {
2667  /* Even if the lockpicking failed, don't go on moving, player should explicitely attack or run
2668  * to bash the door. */
2669  do_skill(op, op, lock, op->facing, NULL);
2670  return 1;
2671  }
2672  }
2673 
2674  return 0;
2675 }
2676 
2690 void move_player_attack(object *op, int dir) {
2691  object *mon, *tpl, *mon_owner;
2692  int16_t nx, ny;
2693  int on_battleground;
2694  mapstruct *m;
2695 
2696  if (op->contr->transport)
2697  tpl = op->contr->transport;
2698  else
2699  tpl = op;
2700  nx = freearr_x[dir]+tpl->x;
2701  ny = freearr_y[dir]+tpl->y;
2702 
2703  on_battleground = op_on_battleground(tpl, NULL, NULL, NULL);
2704 
2705  // Temporarily store the map we are on before movement.
2706  mapstruct *bef = tpl->map;
2707 
2708  /* If braced, or can't move to the square, and it is not out of the
2709  * map, attack it. Note order of if statement is important - don't
2710  * want to be calling move_ob if braced, because move_ob will move the
2711  * player. This is a pretty nasty hack, because if we could
2712  * move to some space, it then means that if we are braced, we should
2713  * do nothing at all. As it is, if we are braced, we go through
2714  * quite a bit of processing. However, it probably is less than what
2715  * move_ob uses.
2716  */
2717  if ((op->contr->braced || !move_ob(tpl, dir, tpl)) && !out_of_map(tpl->map, nx, ny)) {
2718  if (OUT_OF_REAL_MAP(tpl->map, nx, ny)) {
2719  m = get_map_from_coord(tpl->map, &nx, &ny);
2720  if (!m)
2721  return; /* Don't think this should happen */
2722  } else
2723  m = tpl->map;
2724 
2725  if (GET_MAP_OB(m, nx, ny) == NULL) {
2726  /* LOG(llevError, "player_move_attack: GET_MAP_OB returns NULL, but player can not move there.\n");*/
2727  return;
2728  }
2729 
2730  mon = NULL;
2731  /* Go through all the objects, and find ones of interest. Only stop if
2732  * we find a monster - that is something we know we want to attack.
2733  * if its a door or barrel (can roll) see if there may be monsters
2734  * on the space
2735  */
2736  FOR_MAP_PREPARE(m, nx, ny, tmp) {
2737  if (tmp == op) {
2738  continue;
2739  }
2740  if (QUERY_FLAG(tmp, FLAG_ALIVE)) {
2741  mon = tmp;
2742  /* Gros: Objects like (pass-through) doors are alive, but haven't
2743  * their monster flag set - so this is a good way attack real
2744  * monsters in priority.
2745  */
2746  if (QUERY_FLAG(tmp, FLAG_MONSTER))
2747  break;
2748  }
2749  if (tmp->type == LOCKED_DOOR || QUERY_FLAG(tmp, FLAG_CAN_ROLL))
2750  mon = tmp;
2751  } FOR_MAP_FINISH();
2752 
2753  if (mon == NULL) /* This happens anytime the player tries to move */
2754  return; /* into a wall */
2755 
2756  mon = HEAD(mon);
2757  if ((mon->type == DOOR && mon->stats.hp >= 0) || (mon->type == LOCKED_DOOR))
2758  if (player_attack_door(op, mon))
2759  return;
2760 
2761  /* The following deals with possibly attacking peaceful
2762  * or friendly creatures. Basically, all players are considered
2763  * unaggressive. If the moving player has peaceful set, then the
2764  * object should be pushed instead of attacked. It is assumed that
2765  * if you are braced, you will not attack friends accidently,
2766  * and thus will not push them.
2767  */
2768 
2769  /* If the creature is a pet, push it even if the player is not
2770  * peaceful. Our assumption is the creature is a pet if the
2771  * player owns it and it is either friendly or unaggressive.
2772  */
2773  mon_owner = object_get_owner(mon);
2774  if ((op->type == PLAYER)
2775  && (mon_owner == op || (mon_owner != NULL && mon_owner->type == PLAYER && mon_owner->contr->party != NULL && mon_owner->contr->party == op->contr->party))
2776  && (QUERY_FLAG(mon, FLAG_UNAGGRESSIVE) || QUERY_FLAG(mon, FLAG_FRIENDLY))) {
2777  /* If we're braced, we don't want to switch places with it */
2778  if (op->contr->braced)
2779  return;
2780  play_sound_map(SOUND_TYPE_LIVING, mon, dir, "push");
2781  (void)push_ob(mon, dir, op);
2782  if (op->contr->tmp_invis || op->hide)
2783  make_visible(op);
2784  return;
2785  }
2786 
2787  /* in certain circumstances, you shouldn't attack friendly
2788  * creatures. Note that if you are braced, you can't push
2789  * someone, but put it inside this loop so that you won't
2790  * attack them either.
2791  */
2792  if ((mon->type == PLAYER || mon->enemy != op)
2793  && (mon->type == PLAYER || QUERY_FLAG(mon, FLAG_UNAGGRESSIVE) || QUERY_FLAG(mon, FLAG_FRIENDLY))
2794  && (op->contr->peaceful && !on_battleground)) {
2795  if (!op->contr->braced) {
2796  play_sound_map(SOUND_TYPE_LIVING, mon, dir, "push");
2797  (void)push_ob(mon, dir, op);
2798  } else {
2800  "You withhold your attack");
2801  }
2802  if (op->contr->tmp_invis || op->hide)
2803  make_visible(op);
2804  }
2805 
2806  /* If the object is a boulder or other rollable object, then
2807  * roll it if not braced. You can't roll it if you are braced.
2808  */
2809  else if (QUERY_FLAG(mon, FLAG_CAN_ROLL) && (!op->contr->braced)) {
2810  recursive_roll(mon, dir, op);
2811  if (action_makes_visible(op))
2812  make_visible(op);
2813 
2814  /* Any generic living creature. Including things like doors.
2815  * Way it works is like this: First, it must have some hit points
2816  * and be living. Then, it must be one of the following:
2817  * 1) Not a player, 2) A player, but of a different party. Note
2818  * that party_number -1 is no party, so attacks can still happen.
2819  */
2820  } else if ((mon->stats.hp >= 0)
2821  && QUERY_FLAG(mon, FLAG_ALIVE)
2822  && ((mon->type != PLAYER || op->contr->party == NULL || op->contr->party != mon->contr->party))) {
2823  /* If the player hasn't hit something this tick, and does
2824  * so, give them speed boost based on weapon speed. Doing
2825  * it here is better than process_players2, which basically
2826  * incurred a 1 tick offset.
2827  */
2828  if (op->weapon_speed_left < 0) {
2829  op->speed_left = -0.01;
2830  return;
2831  }
2832  op->weapon_speed_left -= 1.0;
2833 
2834  skill_attack(mon, op, 0, NULL, NULL);
2835 
2836  /* If attacking another player, that player gets automatic
2837  * hitback, and doesn't loose luck either.
2838  * Disable hitback on the battleground or if the target is
2839  * the wiz.
2840  */
2841  if (mon->type == PLAYER
2842  && mon->stats.hp >= 0
2843  && !mon->contr->has_hit
2844  && !on_battleground
2845  && !QUERY_FLAG(mon, FLAG_WIZ)) {
2846  short luck = mon->stats.luck;
2847  mon->contr->has_hit = 1;
2848  skill_attack(op, mon, 0, NULL, NULL);
2849  mon->stats.luck = luck;
2850  }
2851  if (action_makes_visible(op))
2852  make_visible(op);
2853  }
2854  } /* if player should attack something */
2855  /* If we changed maps, then try to load the new map music.
2856  * This is not redundant with transfer_ob's call to player_update_bg_music,
2857  * since that call only accounts for teleporters, exits, and such.
2858  * This handles entering tiled maps, which the other could not do.
2859  */
2860  else if (bef != tpl->map)
2861  {
2863  }
2864 }
2865 
2872 static void update_transport_block(object *transport, int dir) {
2873  object *part;
2874  int sx, sy, x, y;
2875 
2876  object_get_multi_size(transport, &sx, &sy, NULL, NULL);
2877  assert(sx == sy);
2878 
2879  if (dir == 1 || dir == 5) {
2880  part = transport;
2881  for (y = 0; y <= sy; y++) {
2882  for (x = 0; x < sx; x++) {
2883  part->move_type = transport->move_type;
2884  part = part->more;
2885  }
2886  part->move_type = 0;
2887  part = part->more;
2888  }
2889  } else if (dir == 3 || dir == 7) {
2890  part = transport;
2891  for (y = 0; y < sy; y++) {
2892  for (x = 0; x <= sx; x++) {
2893  part->move_type = transport->move_type;
2894  part = part->more;
2895  }
2896  }
2897  while (part) {
2898  part->move_type = 0;
2899  part = part->more;
2900  }
2901  } else {
2902  for (part = transport; part; part = part->more) {
2903  part->move_type = transport->move_type;
2904  }
2905  }
2906 }
2907 
2917 static int turn_one_transport(object *transport, object *captain, int dir) {
2918  int x, y, scroll_dir = 0;
2919 
2920  assert(transport->type == TRANSPORT);
2921 
2922  x = transport->x;
2923  y = transport->y;
2924 
2925  if (transport->direction == 1 && dir == 8) {
2926  x--;
2927  } else if (transport->direction == 2 && dir == 3) {
2928  y++;
2929  } else if (transport->direction == 3 && dir == 2) {
2930  y--;
2931  } else if (transport->direction == 5 && dir == 6) {
2932  x--;
2933  } else if (transport->direction == 6 && dir == 5) {
2934  x++;
2935  } else if (transport->direction == 7 && dir == 8) {
2936  y--;
2937  } else if (transport->direction == 8 && dir == 7) {
2938  y++;
2939  } else if (transport->direction == 8 && dir == 1) {
2940  x++;
2941  }
2942 
2943  update_transport_block(transport, dir);
2944  object_remove(transport);
2945  if (ob_blocked(transport, transport->map, x, y)) {
2946  update_transport_block(transport, transport->direction);
2947  object_insert_in_map_at(transport, transport->map, NULL, 0, x, y);
2948  return 2;
2949  }
2950 
2951  if (x != transport->x || y != transport->y) {
2952 /* assert(scroll_dir != 0);*/
2953 
2954  FOR_INV_PREPARE(transport, pl) {
2955  if (pl->type == PLAYER) {
2956  pl->contr->do_los = 1;
2957  pl->map = transport->map;
2958  pl->x = x;
2959  pl->y = y;
2960  esrv_map_scroll(&pl->contr->socket, freearr_x[scroll_dir], freearr_y[scroll_dir]);
2961  pl->contr->socket.update_look = 1;
2962  pl->contr->socket.look_position = 0;
2963  }
2964  } FOR_INV_FINISH();
2965  }
2966 
2967  object_insert_in_map_at(transport, transport->map, NULL, 0, x, y);
2968  transport->direction = dir;
2969  transport->facing = dir;
2970  animate_object(transport, dir);
2971  captain->direction = dir;
2972  return 1;
2973 }
2974 
2987 static int turn_transport(object *transport, object *captain, int dir) {
2988  assert(transport->type == TRANSPORT);
2989 
2990  if (object_get_value(transport, "turnable_transport") == NULL) {
2991  transport->direction = dir;
2992  transport->facing = dir;
2993  if (QUERY_FLAG(transport, FLAG_ANIMATE)) {
2994  animate_object(transport, dir);
2995  }
2996  captain->direction = dir;
2997  return 0;
2998  }
2999 
3000  if (transport->direction == dir)
3001  return 0;
3002 
3003  if (absdir(transport->direction-dir) > 2)
3004  return turn_one_transport(transport, captain, absdir(transport->direction+1));
3005  else
3006  return turn_one_transport(transport, captain, absdir(transport->direction-1));
3007 }
3008 
3019 int move_player(object *op, int dir) {
3020  int pick;
3021  object *transport = op->contr->transport;
3022 
3023  if (!transport && (op->map == NULL || op->map->in_memory != MAP_IN_MEMORY))
3024  return 0;
3025 
3026  /* Sanity check: make sure dir is valid */
3027  if ((dir < 0) || (dir >= 9)) {
3028  LOG(llevError, "move_player: invalid direction %d\n", dir);
3029  return 0;
3030  }
3031 
3032  /* peterm: added following line */
3033  if (QUERY_FLAG(op, FLAG_CONFUSED) && dir)
3034  dir = get_randomized_dir(dir);
3035 
3036  op->facing = dir;
3037 
3038  if (!transport && op->hide)
3039  do_hidden_move(op);
3040 
3041  if (transport) {
3042  int turn;
3043 
3044  /* transport->contr is set up for the person in charge of the boat.
3045  * if that isn't this person, he can't steer it, etc
3046  */
3047  if (transport->contr != op->contr)
3048  return 0;
3049 
3050  /* Transport can't move. But update dir so it at least
3051  * will point in the same direction if player is running.
3052  */
3053  if (transport->speed_left < 0.0) {
3054  return 0;
3055  }
3056  /* Remove transport speed. Give player just a little speed -
3057  * enough so that they will get an action again quickly.
3058  */
3059  transport->speed_left -= 1.0;
3060  if (op->speed_left < 0.0)
3061  op->speed_left = -0.01;
3062 
3063  turn = turn_transport(transport, op, dir);
3064  if (turn != 0)
3065  return 0;
3066  } else {
3067  /* it is important to change the animation now, as fire or move_player_attack can start a compound animation,
3068  * and leave us with state = 0, which we don't want to change again. */
3069  op->state++; /* player moved, so change animation. */
3070  animate_object(op, op->facing);
3071  }
3072 
3073  if (op->contr->fire_on) {
3074  fire(op, dir);
3075  } else
3076  move_player_attack(op, dir);
3077 
3078  pick = check_pick(op);
3079 
3080 
3081  /* Add special check for newcs players and fire on - this way, the
3082  * server can handle repeat firing.
3083  */
3084  if (op->contr->fire_on || (op->contr->run_on && pick != 0)) {
3085  op->direction = dir;
3086  } else {
3087  op->direction = 0;
3088  }
3089  return 0;
3090 }
3091 
3104 int handle_newcs_player(object *op) {
3105  if (op->contr->hidden) {
3106  op->invisible = 1000;
3107  /* the socket code flashes the player visible/invisible
3108  * depending on the value if invisible, so we need to
3109  * alternate it here for it to work correctly.
3110  */
3111  if (pticks&2)
3112  op->invisible--;
3113  } else if (op->invisible && !(QUERY_FLAG(op, FLAG_MAKE_INVIS))) {
3114  op->invisible--;
3115  if (!op->invisible) {
3116  make_visible(op);
3118  "Your invisibility spell runs out.");
3119  }
3120  }
3121 
3122  if (QUERY_FLAG(op, FLAG_SCARED)) {
3123  flee_player(op);
3124  /* If player is still scared, that is his action for this tick */
3125  if (QUERY_FLAG(op, FLAG_SCARED)) {
3126  op->speed_left--;
3127  return 0;
3128  }
3129  }
3130 
3131  /* I've been seeing crashes where the golem has been destroyed, but
3132  * the player object still points to the defunct golem. The code that
3133  * destroys the golem looks correct, and it doesn't always happen, so
3134  * put this in a a workaround to clean up the golem pointer.
3135  */
3136  if (op->contr->ranges[range_golem]
3138  op->contr->ranges[range_golem] = NULL;
3139  op->contr->golem_count = 0;
3140  }
3141 
3142  /* call this here - we also will call this in do_ericserver, but
3143  * the players time has been increased when doericserver has been
3144  * called, so we recheck it here.
3145  */
3146  handle_client(&op->contr->socket, op->contr);
3147  if (op->speed_left < 0)
3148  return 0;
3149 
3150  /*
3151  * If the player has been paralyzed, we unmark the flag and give a message to the player
3152  */
3153  if (QUERY_FLAG(op, FLAG_PARALYZED)) {
3155  // TODO: Is this check necessary? We are in player.c, after all.
3156  if (op->type == PLAYER)
3157  {
3159  "You can stretch your stiff joints once more.");
3160  }
3161  }
3162 
3163  if (op->direction && (op->contr->run_on || op->contr->fire_on)) {
3164  /* All move commands take 1 tick, at least for now */
3165  op->speed_left--;
3166 
3167  /* Instead of all the stuff below, let move_player take care
3168  * of it. Also, some of the skill stuff is only put in
3169  * there, as well as the confusion stuff.
3170  */
3171  move_player(op, op->direction);
3172  if (op->speed_left > 0)
3173  return 1;
3174  else
3175  return 0;
3176  }
3177  return 0;
3178 }
3179 
3190 static int save_life(object *op) {
3191  object *tmp;
3192 
3193  if (!QUERY_FLAG(op, FLAG_LIFESAVE))
3194  return 0;
3195 
3197  if (tmp != NULL) {
3198  char name[MAX_BUF];
3199 
3200  query_name(tmp, name, MAX_BUF);
3201  play_sound_map(SOUND_TYPE_ITEM, tmp, 0, "evaporate");
3203  "Your %s vibrates violently, then evaporates.",
3204  name);
3205  object_remove(tmp);
3208  if (op->stats.hp < 0)
3209  op->stats.hp = op->stats.maxhp;
3210  if (op->stats.food < 0)
3211  op->stats.food = 999;
3212  fix_object(op);
3213  return 1;
3214  }
3215  LOG(llevError, "Error: LIFESAVE set without applied object.\n");
3217  enter_player_savebed(op); /* bring him home. */
3218  return 0;
3219 }
3220 
3233 void remove_unpaid_objects(object *op, object *env, int free_items) {
3235  if (QUERY_FLAG(op, FLAG_UNPAID)) {
3236  object_remove(op);
3237  if (free_items)
3239  else
3240  object_insert_in_map_at(op, env->map, NULL, 0, env->x, env->y);
3241  } else if (op->inv)
3242  remove_unpaid_objects(op->inv, env, free_items);
3244 }
3245 
3263 static const char *gravestone_text(object *op, char *buf2, int len) {
3264  char buf[MAX_BUF];
3265  time_t now = time(NULL);
3266 
3267  strncpy(buf2, " R.I.P.\n\n", len);
3268  if (op->type == PLAYER)
3269  snprintf(buf, sizeof(buf), "%s the %s\n", op->name, op->contr->title);
3270  else
3271  snprintf(buf, sizeof(buf), "%s\n", op->name);
3272  strncat(buf2, " ", 20-strlen(buf)/2);
3273  strncat(buf2, buf, len-strlen(buf2)-1);
3274  if (op->type == PLAYER)
3275  snprintf(buf, sizeof(buf), "who was in level %d when killed\n", op->level);
3276  else
3277  snprintf(buf, sizeof(buf), "who was in level %d when died.\n\n", op->level);
3278  strncat(buf2, " ", 20-strlen(buf)/2);
3279  strncat(buf2, buf, len-strlen(buf2)-1);
3280  if (op->type == PLAYER) {
3281  snprintf(buf, sizeof(buf), "by %s.\n\n", op->contr->killer);
3282  strncat(buf2, " ", 21-strlen(buf)/2);
3283  strncat(buf2, buf, len-strlen(buf2)-1);
3284  }
3285  strftime(buf, MAX_BUF, "%b %d %Y\n", localtime(&now));
3286  strncat(buf2, " ", 20-strlen(buf)/2);
3287  strncat(buf2, buf, len-strlen(buf2)-1);
3288  return buf2;
3289 }
3290 
3298 void do_some_living(object *op) {
3299  int last_food = op->stats.food;
3300  int gen_hp, gen_sp, gen_grace;
3301  int rate_hp = 1200;
3302  int rate_sp = 2500;
3303  int rate_grace = 2000;
3304 
3305  if (op->contr->state == ST_PLAYING) {
3306  /* these next three if clauses make it possible to SLOW DOWN
3307  hp/grace/spellpoint regeneration. */
3308  if (op->contr->gen_hp >= 0)
3309  gen_hp = (op->contr->gen_hp+1)*op->stats.maxhp;
3310  else {
3311  gen_hp = op->stats.maxhp;
3312  rate_hp -= rate_hp/2*op->contr->gen_hp;
3313  }
3314  if (op->contr->gen_sp >= 0)
3315  gen_sp = (op->contr->gen_sp+1)*op->stats.maxsp;
3316  else {
3317  gen_sp = op->stats.maxsp;
3318  rate_sp -= rate_sp/2*op->contr->gen_sp;
3319  }
3320  if (op->contr->gen_grace >= 0)
3321  gen_grace = (op->contr->gen_grace+1)*op->stats.maxgrace;
3322  else {
3323  gen_grace = op->stats.maxgrace;
3324  rate_grace -= rate_grace/2*op->contr->gen_grace;
3325  }
3326 
3327  /* Regenerate Spell Points */
3328  if (op->contr->ranges[range_golem] == NULL && --op->last_sp < 0) {
3329  gen_sp = gen_sp*10/MAX(op->contr->gen_sp_armour, 10);
3330  if (op->stats.sp < op->stats.maxsp) {
3331  op->stats.sp++;
3332  /* dms do not consume food */
3333  if (!QUERY_FLAG(op, FLAG_WIZ)) {
3334  op->stats.food--;
3335  if (op->contr->digestion < 0)
3336  op->stats.food += op->contr->digestion;
3337  else if (op->contr->digestion > 0
3338  && random_roll(0, op->contr->digestion, op, PREFER_HIGH))
3339  op->stats.food = last_food;
3340  }
3341  }
3342  op->last_sp = rate_sp/(MAX(gen_sp, 20)+10);
3343  }
3344 
3345  /* Regenerate Grace */
3346  /* I altered this a little - maximum grace is only achieved through prayer -b.t.*/
3347  if (--op->last_grace < 0) {
3348  if (op->stats.grace < op->stats.maxgrace/2)
3349  op->stats.grace++; /* no penalty in food for regaining grace */
3350  op->last_grace = rate_grace/(MAX(gen_grace, 20)+10);
3351  /* wearing stuff doesn't detract from grace generation. */
3352  }
3353 
3354  /* Regenerate Hit Points (unless you are a wraith player) */
3355  if (--op->last_heal < 0 && !is_wraith_pl(op)) {
3356  if (op->stats.hp < op->stats.maxhp) {
3357  op->stats.hp++;
3358  /* dms do not consume food */
3359  if (!QUERY_FLAG(op, FLAG_WIZ)) {
3360  op->stats.food--;
3361  if (op->contr->digestion < 0)
3362  op->stats.food += op->contr->digestion;
3363  else if (op->contr->digestion > 0
3364  && random_roll(0, op->contr->digestion, op, PREFER_HIGH))
3365  op->stats.food = last_food;
3366  }
3367  }
3368  op->last_heal = rate_hp/(MAX(gen_hp, 20)+10);
3369  }
3370 
3371  /* Digestion */
3372  if (--op->last_eat < 0) {
3373  int bonus = MAX(op->contr->digestion, 0);
3374  int penalty = MAX(-op->contr->digestion, 0);
3375  if (op->contr->gen_hp > 0)
3376  op->last_eat = 25*(1+bonus)/(op->contr->gen_hp+penalty+1);
3377  else
3378  op->last_eat = 25*(1+bonus)/(penalty+1);
3379  /* dms do not consume food */
3380  if (!QUERY_FLAG(op, FLAG_WIZ))
3381  op->stats.food--;
3382  }
3383  }
3384 
3385  if (op->contr->state == ST_PLAYING && op->stats.food < 0 && op->stats.hp >= 0) {
3386  if (is_wraith_pl(op))
3387  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ITEM, MSG_TYPE_ITEM_REMOVE, "You feel a hunger for living flesh.");
3388  /* Only allow eat if not paralyzed. Otherwise our paralyzed player is "moving" to eat.
3389  * Daniel Hawkins 2017-08-23
3390  */
3391  else if (!QUERY_FLAG(op, FLAG_PARALYZED)){
3392  object *flesh = NULL;
3393 
3394  FOR_INV_PREPARE(op, tmp) {
3395  if (!QUERY_FLAG(tmp, FLAG_UNPAID)) {
3396  if (tmp->type == FOOD || tmp->type == DRINK || tmp->type == POISON) {
3398  "You blindly grab for a bite of food.");
3399  apply_manual(op, tmp, 0);
3400  if (op->stats.food >= 0 || op->stats.hp < 0)
3401  break;
3402  } else if (tmp->type == FLESH)
3403  flesh = tmp;
3404  } /* End if paid for object */
3405  } FOR_INV_FINISH(); /* end of for loop */
3406  /* If player is still starving, it means they don't have any food, so
3407  * eat flesh instead.
3408  */
3409  if (op->stats.food < 0 && op->stats.hp >= 0 && flesh) {
3411  "You blindly grab for a bite of food.");
3412  apply_manual(op, flesh, 0);
3413  }
3414  } /* end not wraith and not paralyzed */
3415  else { // Print a message for when the player is starving and paralyzed
3416  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ITEM, MSG_TYPE_ITEM_REMOVE, "Your stomach rumbles, but you can't reach your food.");
3417  } /* end not wraith and is paralyzed */
3418  } /* end if player is starving */
3419 
3420  if (op->stats.food < 0 && op->stats.hp > 0){
3421  // We know food < 0, so we want the absolute value of food
3422  int32_t adjust_by = MIN(-(op->stats.food), op->stats.hp);
3423  op->stats.food += adjust_by;
3424  op->stats.hp -= adjust_by;
3425  }
3426 
3427  if (!op->contr->state && !QUERY_FLAG(op, FLAG_WIZ) && (op->stats.hp < 0 || op->stats.food < 0))
3428  kill_player(op, NULL);
3429 }
3430 
3437 static void loot_object(object *op) {
3438  object *tmp2;
3439 
3440  if (op->container) { /* close open sack first */
3441  apply_container(op, op->container);
3442  }
3443 
3444  FOR_INV_PREPARE(op, tmp) {
3445  if (tmp->invisible)
3446  continue;
3447  object_remove(tmp);
3448  tmp->x = op->x,
3449  tmp->y = op->y;
3450  if (tmp->type == CONTAINER) { /* empty container to ground */
3451  loot_object(tmp);
3452  }
3453  if (!QUERY_FLAG(tmp, FLAG_UNIQUE)
3454  && (QUERY_FLAG(tmp, FLAG_STARTEQUIP) || QUERY_FLAG(tmp, FLAG_NO_DROP) || !(RANDOM()%3))) {
3455  if (tmp->nrof > 1) {
3456  tmp2 = object_split(tmp, 1+RANDOM()%(tmp->nrof-1), NULL, 0);
3458  object_insert_in_map_at(tmp, op->map, NULL, 0, op->x, op->y);
3459  } else
3461  } else
3462  object_insert_in_map_at(tmp, op->map, NULL, 0, op->x, op->y);
3463  } FOR_INV_FINISH();
3464 }
3465 
3477 void kill_player(object *op, const object *killer) {
3478  char buf[MAX_BUF];
3479  int x, y;
3480  archetype *at;
3481  object *tmp;
3482  archetype *trophy = NULL;
3483 
3484  /* Don't die if the player's life can be saved. */
3485  if (save_life(op)) {
3486  return;
3487  }
3488 
3489  /* If player dies on BATTLEGROUND, no stat/exp loss! For Combat-Arenas
3490  * in cities ONLY!!! It is very important that this doesn't get abused.
3491  * Look at op_on_battleground() for more info --AndreasV
3492  */
3493  if (op_on_battleground(op, &x, &y, &trophy)) {
3494  assert(trophy != NULL);
3496  "You have been defeated in combat!\n"
3497  "Local medics have saved your life...");
3498 
3499  /* restore player */
3500  at = find_archetype("poisoning");
3501  tmp = arch_present_in_ob(at, op);
3502  if (tmp) {
3503  object_remove(tmp);
3506  "Your body feels cleansed");
3507  }
3508 
3509  at = find_archetype("confusion");
3510  tmp = arch_present_in_ob(at, op);
3511  if (tmp) {
3512  object_remove(tmp);
3515  "Your mind feels clearer");
3516  }
3517 
3518  cure_disease(op, NULL, NULL); /* remove any disease */
3519  op->stats.hp = op->stats.maxhp;
3520  if (op->stats.food <= 0)
3521  op->stats.food = 999;
3522 
3523  /* create a bodypart-trophy to make the winner happy */
3524  tmp = arch_to_object(trophy);
3525  if (tmp != NULL) {
3526  snprintf(buf, sizeof(buf), "%s's %s", op->name, tmp->name);
3527  tmp->name = add_string(buf);
3528 
3529  snprintf(buf, sizeof(buf),
3530  "This %s was %s %s the %s, who was defeated at level %d by %s.\n",
3531  tmp->name, tmp->type == FLESH ? "cut off" : "taken from",
3532  op->name, op->contr->title,
3533  (int)(op->level), op->contr->killer);
3534 
3535  object_set_msg(tmp, buf);
3536  tmp->type = 0;
3537  tmp->value = 0;
3538  tmp->material = 0;
3539  tmp->materialname = NULL;
3540  object_insert_in_map_at(tmp, op->map, op, 0, op->x, op->y);
3541  }
3542 
3543  /* teleport defeated player to new destination*/
3544  transfer_ob(op, x, y, 0, NULL);
3545  op->contr->braced = 0;
3546  return;
3547  }
3548 
3549  /* Lauwenmark: Handle for plugin death event */
3550  if (execute_event(op, EVENT_DEATH, NULL, NULL, NULL, SCRIPT_FIX_ALL) != 0)
3551  return;
3552 
3553  /* Lauwenmark: Handle for the global death event */
3555  if (op->stats.food < 0) {
3556  snprintf(buf, sizeof(buf), "%s starved to death.", op->name);
3557  strcpy(op->contr->killer, "starvation");
3558  } else {
3559  snprintf(buf, sizeof(buf), "%s died.", op->name);
3560  }
3561  play_sound_player_only(op->contr, SOUND_TYPE_LIVING, op, 0, "death");
3562 
3563  if (settings.not_permadeth == TRUE) {
3565  } else {
3567  }
3568 }
3569 
3578 static void kill_player_not_permadeath(object *op) {
3579  int num_stats_lose;
3580  int will_kill_again;
3581  int lost_a_stat;
3582  int z;
3583  object *tmp;
3584  char buf[MAX_BUF];
3585  archetype *at;
3586 
3587  /* Basically two ways to go - remove a stat permanently, or just
3588  * make it depletion. This bunch of code deals with that aspect
3589  * of death.
3590  */
3592  /* If stat loss is permanent, lose one stat only. */
3593  /* Lower level chars don't lose as many stats because they suffer
3594  more if they do. */
3595  /* Higher level characters can afford things such as potions of
3596  restoration, or better, stat potions. So we slug them that
3597  little bit harder. */
3598  /* GD */
3600  num_stats_lose = 1;
3601  else
3602  num_stats_lose = 1+op->level/BALSL_NUMBER_LOSSES_RATIO;
3603  } else {
3604  num_stats_lose = 1;
3605  }
3606  lost_a_stat = 0;
3607 
3608  for (z = 0; z < num_stats_lose; z++) {
3610  int i;
3611 
3612  /* Pick a random stat and take a point off it. Tell the player
3613  * what he lost.
3614  */
3615  i = RANDOM()%7;
3616  change_attr_value(&(op->stats), i, -1);
3618  change_attr_value(&(op->contr->orig_stats), i, -1);
3620  draw_ext_info(NDI_UNIQUE, 0, op,
3622  lose_msg[i]);
3623  lost_a_stat = 1;
3624  } else {
3625  /* deplete a stat */
3627  object *dep;
3628  int lose_this_stat;
3629  int i;
3630 
3631  i = RANDOM()%7;
3632  dep = arch_present_in_ob(deparch, op);
3633  if (!dep) {
3634  dep = arch_to_object(deparch);
3635  object_insert_in_ob(dep, op);
3636  }
3637  lose_this_stat = 1;
3639  int this_stat;
3640 
3641  /* GD */
3642  /* Get the stat that we're about to deplete. */
3643  this_stat = get_attr_value(&(dep->stats), i);
3644  if (this_stat < 0) {
3645  int loss_chance = 1+op->level/BALSL_LOSS_CHANCE_RATIO;
3646  int keep_chance = this_stat*this_stat;
3647  /* Yes, I am paranoid. Sue me. */
3648  if (keep_chance < 1)
3649  keep_chance = 1;
3650 
3651  /* There is a maximum depletion total per level. */
3652  if (this_stat < -1-op->level/BALSL_MAX_LOSS_RATIO) {
3653  lose_this_stat = 0;
3654  /* Take loss chance vs keep chance to see if we
3655  retain the stat. */
3656  } else {
3657  if (random_roll(0, loss_chance+keep_chance-1, op, PREFER_LOW) < keep_chance)
3658  lose_this_stat = 0;
3659  /* 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"); */
3660  }
3661  }
3662  }
3663 
3664  if (lose_this_stat) {
3665  int this_stat;
3666 
3667  this_stat = get_attr_value(&(dep->stats), i);
3668  /* We could try to do something clever like find another
3669  * stat to reduce if this fails. But chances are, if
3670  * stats have been depleted to -50, all are pretty low
3671  * and should be roughly the same, so it shouldn't make a
3672  * difference.
3673  */
3674  if (this_stat >= -50) {
3675  change_attr_value(&(dep->stats), i, -1);
3676  SET_FLAG(dep, FLAG_APPLIED);
3678  lose_msg[i]);
3679  fix_object(op);
3680  lost_a_stat = 1;
3681  }
3682  }
3683  }
3684  }
3685  /* If no stat lost, tell the player. */
3686  if (!lost_a_stat) {
3687  /* determine_god() seems to not work sometimes... why is this? Should I be using something else? GD */
3688  const char *god = determine_god(op);
3689 
3690  if (god && (strcmp(god, "none")))
3693  "For a brief moment you feel the holy presence of %s protecting you",
3694  god);
3695  else
3696  draw_ext_info(NDI_UNIQUE, 0, op,
3698  "For a brief moment you feel a holy presence protecting you.");
3699  }
3700 
3701  /* Put a gravestone up where the character 'almost' died. List the
3702  * exp loss on the stone.
3703  */
3704  tmp = arch_to_object(find_archetype("gravestone"));
3705  snprintf(buf, sizeof(buf), "%s's gravestone", op->name);
3706  FREE_AND_COPY(tmp->name, buf);
3707  snprintf(buf, sizeof(buf), "%s's gravestones", op->name);
3708  FREE_AND_COPY(tmp->name_pl, buf);
3709  snprintf(buf, sizeof(buf), "RIP\nHere rests the hero %s the %s,\n"
3710  "who was killed\n"
3711  "by %s.\n",
3712  op->name, op->contr->title,
3713  op->contr->killer);
3714  object_set_msg(tmp, buf);
3715  object_insert_in_map_at(tmp, op->map, NULL, 0, op->x, op->y);
3716 
3717  /* restore player: remove any poisoning, disease and confusion the
3718  * character may be suffering.*/
3719  at = find_archetype("poisoning");
3720  tmp = arch_present_in_ob(at, op);
3721  if (tmp) {
3722  object_remove(tmp);
3725  "Your body feels cleansed");
3726  }
3727 
3728  at = find_archetype("confusion");
3729  tmp = arch_present_in_ob(at, op);
3730  if (tmp) {
3731  object_remove(tmp);
3734  "Your mind feels clearer");
3735  }
3736  cure_disease(op, NULL, NULL); /* remove any disease */
3737 
3738  /* Subtract the experience points, if we died cause of food, give
3739  * us food, and reset HP's...
3740  */
3742  if (op->stats.food < 100)
3743  op->stats.food = 900;
3744  op->stats.hp = op->stats.maxhp;
3745  op->stats.sp = MAX(op->stats.sp, op->stats.maxsp);
3746  op->stats.grace = MAX(op->stats.grace, op->stats.maxgrace);
3747 
3748  /* Check to see if the player is in a shop. IF so, then check to see if
3749  * the player has any unpaid items. If so, remove them and put them back
3750  * in the map.
3751  *
3752  * If they are not in a shop, just free the unpaid items instead of
3753  * putting them back on map.
3754  */
3755  if (shop_contains(op))
3756  remove_unpaid_objects(op->inv, op, 0);
3757  else
3758  remove_unpaid_objects(op->inv, op, 1);
3759 
3760  /* Move player to his current respawn-position (usually last savebed) */
3762 
3763  /* Save the player before inserting the force to reduce chance of abuse. */
3764  op->contr->braced = 0;
3765  save_player(op, 1);
3766 
3767  /* it is possible that the player has blown something up
3768  * at his savebed location, and that can have long lasting
3769  * spell effects. So first see if there is a spell effect
3770  * on the space that might harm the player.
3771  */
3772  will_kill_again = 0;
3773  FOR_MAP_PREPARE(op->map, op->x, op->y, tmp)
3774  if (tmp->type == SPELL_EFFECT)
3775  will_kill_again |= tmp->attacktype;
3776  FOR_MAP_FINISH();
3777  if (will_kill_again) {
3778  object *force;
3779  int at;
3780 
3781  force = create_archetype(FORCE_NAME);
3782  /* 50 ticks should be enough time for the spell to abate */
3783  force->speed = 0.1;
3784  force->speed_left = -5.0;
3785  SET_FLAG(force, FLAG_APPLIED);
3786  for (at = 0; at < NROFATTACKS; at++) {
3787  if (will_kill_again&(1<<at))
3788  force->resist[at] = 100;
3789  }
3790  object_insert_in_ob(force, op);
3791  fix_object(op);
3792  }
3793 
3794  /* Tell the player they have died */
3796  "YOU HAVE DIED.");
3797 }
3798 
3805 static void kill_player_permadeath(object *op) {
3806  char buf[MAX_BUF];
3807  char ac_buf[MAX_BUF];
3808  int x, y;
3809  mapstruct *map;
3810  object *tmp;
3811 
3812  /* save the map location for corpse, gravestone*/
3813  x = op->x;
3814  y = op->y;
3815  map = op->map;
3816 
3817  party_leave(op);
3818  if (settings.set_title == TRUE)
3819  player_set_own_title(op->contr, "");
3820 
3821  /* buf should be the kill message */
3823  buf);
3824  hiscore_check(op, 0);
3825  if (op->contr->ranges[range_golem] != NULL) {
3829  op->contr->ranges[range_golem] = NULL;
3830  op->contr->golem_count = 0;
3831  }
3832  loot_object(op); /* Remove some of the items for good */
3833  object_remove(op);
3834  op->direction = 0;
3835 
3836  if (!QUERY_FLAG(op, FLAG_WAS_WIZ) && op->stats.exp) {
3837  if (settings.resurrection == TRUE) {
3838  /* save playerfile sans equipment when player dies
3839  * -then save it as player.pl.dead so that future resurrection
3840  * -type spells will work on them nicely
3841  */
3842  op->stats.hp = op->stats.maxhp;
3843  op->stats.food = 999;
3844 
3845  /* set the location of where the person will reappear when */
3846  /* maybe resurrection code should fix map also */
3848  sizeof(op->contr->maplevel));
3849  if (op->map != NULL)
3850  op->map = NULL;
3851  op->x = settings.emergency_x;
3852  op->y = settings.emergency_y;
3853  save_player(op, 0);
3854  op->map = map;
3855  /* please see resurrection.c: peterm */
3856  dead_player(op);
3857  } else {
3858  delete_character(op->name);
3859  }
3860  }
3861  play_again(op);
3862 
3863  /* peterm: added to create a corpse at deathsite. */
3864  tmp = arch_to_object(find_archetype("corpse_pl"));
3865  snprintf(buf, sizeof(buf), "%s", op->name);
3866  FREE_AND_COPY(tmp->name, buf);
3867  FREE_AND_COPY(tmp->name_pl, buf);
3868  tmp->level = op->level;
3869  object_set_msg(tmp, gravestone_text(op, buf, sizeof(buf)));
3870  SET_FLAG(tmp, FLAG_UNIQUE);
3871  /*
3872  * Put the account name under slaying.
3873  * Does not seem to cause weird effects, but more testing may ensure this.
3874  */
3875  snprintf(ac_buf, sizeof(ac_buf), "%s", op->contr->socket.account_name);
3876  FREE_AND_COPY(tmp->slaying, ac_buf);
3877  object_insert_in_map_at(tmp, map, NULL, 0, x, y);
3878 }
3879 
3887 void fix_weight(void) {
3888  player *pl;
3889 
3890  for (pl = first_player; pl != NULL; pl = pl->next) {
3891  int old = pl->ob->carrying, sum = object_sum_weight(pl->ob);
3892 
3893  if (old == sum)
3894  continue;
3895  fix_object(pl->ob);
3896  LOG(llevDebug, "Fixed inventory in %s (%d -> %d)\n", pl->ob->name, old, sum);
3897  }
3898 }
3899 
3903 void fix_luck(void) {
3904  player *pl;
3905 
3906  for (pl = first_player; pl != NULL; pl = pl->next)
3907  if (!pl->ob->contr->state)
3908  change_luck(pl->ob, 0);
3909 }
3910 
3911 
3924 void cast_dust(object *op, object *throw_ob, int dir) {
3925  object *skop, *spob;
3926 
3927  skop = find_skill_by_name(op, throw_ob->skill);
3928 
3929  /* casting POTION 'dusts' is really a use_magic_item skill */
3930  if (op->type == PLAYER && throw_ob->type == POTION && !skop) {
3931  LOG(llevError, "Player %s lacks critical skill use_magic_item!\n", op->name);
3932  return;
3933  }
3934  spob = throw_ob->inv;
3935  if (op->type == PLAYER && spob)
3937  "You cast %s.",
3938  spob->name);
3939 
3940  cast_spell(op, throw_ob, dir, spob, NULL);
3941 
3942  if (!QUERY_FLAG(throw_ob, FLAG_REMOVED))
3943  object_remove(throw_ob);
3944  object_free_drop_inventory(throw_ob);
3945 }
3946 
3953 void make_visible(object *op) {
3954  op->hide = 0;
3955  op->invisible = 0;
3956  if (op->type == PLAYER) {
3957  op->contr->tmp_invis = 0;
3958  if (op->contr->invis_race)
3960  }
3962 }
3963 
3973 int is_true_undead(object *op) {
3974  if (QUERY_FLAG(&op->arch->clone, FLAG_UNDEAD))
3975  return 1;
3976 
3977  if (op->type == PLAYER)
3978  FOR_INV_PREPARE(op, tmp) {
3979  if (tmp->type == 44 && tmp->stats.Wis)
3980  if (QUERY_FLAG(tmp, FLAG_UNDEAD))
3981  return 1;
3982  } FOR_INV_FINISH();
3983  return 0;
3984 }
3985 
3996 int hideability(object *ob) {
3997  int i, level = 0, mflag;
3998  int16_t x, y;
3999 
4000  if (!ob || !ob->map)
4001  return 0;
4002 
4003  /* so, on normal lighted maps, its hard to hide */
4004  level = ob->map->darkness-2;
4005 
4006  /* this also picks up whether the object is glowing.
4007  * If you carry a light on a non-dark map, its not
4008  * as bad as carrying a light on a pitch dark map
4009  */
4010  if (has_carried_lights(ob))
4011  level = -(10+(2*ob->map->darkness));
4012 
4013  /* scan through all nearby squares for terrain to hide in */
4014  for (i = 0, x = ob->x, y = ob->y; i < 9; i++, x = ob->x+freearr_x[i], y = ob->y+freearr_y[i]) {
4015  mflag = get_map_flags(ob->map, NULL, x, y, NULL, NULL);
4016  if (mflag&P_OUT_OF_MAP) {
4017  continue;
4018  }
4019  if (mflag&P_BLOCKSVIEW) /* something to hide near! */
4020  level += 2;
4021  else /* open terrain! */
4022  level -= 1;
4023  }
4024 
4025  return level;
4026 }
4027 
4037 void do_hidden_move(object *op) {
4038  int hide = 0, num = random_roll(0, 19, op, PREFER_LOW);
4039  object *skop;
4040 
4041  if (!op || !op->map)
4042  return;
4043 
4045 
4046  /* its *extremely *hard to run and sneak/hide at the same time! */
4047  if (op->type == PLAYER && op->contr->run_on) {
4048  if (!skop || num >= skop->level) {
4050  "You ran too much! You are no longer hidden!");
4051  make_visible(op);
4052  return;
4053  } else
4054  num += 20;
4055  }
4056  num += op->map->difficulty;
4057  hide = hideability(op); /* modify by terrain hidden level */
4058  num -= hide;
4059  if ((op->type == PLAYER && hide < -10)
4060  || ((op->invisible -= num) <= 0)) {
4061  make_visible(op);
4062  if (op->type == PLAYER)
4064  "You moved out of hiding! You are visible!");
4065  } else if (op->type == PLAYER && skop) {
4066  change_exp(op, calc_skill_exp(op, NULL, skop), skop->skill, 0);
4067  }
4068 }
4069 
4078 int stand_near_hostile(object *who) {
4079  int i, friendly = 0, player = 0, mflags;
4080  mapstruct *m;
4081  int16_t x, y;
4082 
4083  if (!who)
4084  return 0;
4085 
4086  if (who->type == PLAYER)
4087  player = 1;
4088  else
4089  friendly = QUERY_FLAG(who, FLAG_FRIENDLY);
4090 
4091  /* search adjacent squares */
4092  for (i = 1; i < 9; i++) {
4093  x = who->x+freearr_x[i];
4094  y = who->y+freearr_y[i];
4095  m = who->map;
4096  mflags = get_map_flags(m, &m, x, y, &x, &y);
4097  /* space must be blocked if there is a monster. If not
4098  * blocked, don't need to check this space.
4099  */
4100  if (mflags&P_OUT_OF_MAP)
4101  continue;
4102  if (OB_TYPE_MOVE_BLOCK(who, GET_MAP_MOVE_BLOCK(m, x, y)))
4103  continue;
4104 
4105  FOR_MAP_PREPARE(m, x, y, tmp) {
4106  if ((player || friendly)
4107  && QUERY_FLAG(tmp, FLAG_MONSTER)
4108  && !QUERY_FLAG(tmp, FLAG_UNAGGRESSIVE))
4109  return 1;
4110  else if (tmp->type == PLAYER) {
4111  /*don't let a hidden DM prevent you from hiding*/
4112  if (!QUERY_FLAG(tmp, FLAG_WIZ) || tmp->contr->hidden == 0)
4113  return 1;
4114  }
4115  } FOR_MAP_FINISH();
4116  }
4117  return 0;
4118 }
4119 
4146 int player_can_view(object *pl, object *op) {
4147  rv_vector rv;
4148  int dx, dy;
4149 
4150  if (pl->type != PLAYER) {
4151  LOG(llevError, "player_can_view() called for non-player object\n");
4152  return -1;
4153  }
4154  if (!pl || !op)
4155  return 0;
4156 
4157  op = HEAD(op);
4158  if (!get_rangevector(pl, op, &rv, 0x1))
4159  return 0;
4160 
4161  /* starting with the 'head' part, lets loop
4162  * through the object and find if it has any
4163  * part that is in the los array but isnt on
4164  * a blocked los square.
4165  * we use the archetype to figure out offsets.
4166  */
4167  while (op) {
4168  dx = rv.distance_x+op->arch->clone.x;
4169  dy = rv.distance_y+op->arch->clone.y;
4170 
4171  /* only the viewable area the player sees is updated by LOS
4172  * code, so we need to restrict ourselves to that range of values
4173  * for any meaningful values.
4174  */
4175  if (FABS(dx) <= (pl->contr->socket.mapx/2)
4176  && FABS(dy) <= (pl->contr->socket.mapy/2)
4177  && !pl->contr->blocked_los[dx+(pl->contr->socket.mapx/2)][dy+(pl->contr->socket.mapy/2)])
4178  return 1;
4179  op = op->more;
4180  }
4181  return 0;
4182 }
4183 
4197 static int action_makes_visible(object *op) {
4198  if (op->invisible && QUERY_FLAG(op, FLAG_ALIVE)) {
4199  if (QUERY_FLAG(op, FLAG_MAKE_INVIS))
4200  return 0;
4201 
4202  if (op->contr && op->contr->tmp_invis == 0)
4203  return 0;
4204 
4205  /* If monsters, they should become visible */
4206  if (op->hide || !op->contr || (op->contr && op->contr->tmp_invis)) {
4208  "You become %s!",
4209  op->hide ? "unhidden" : "visible");
4210  return 1;
4211  }
4212  }
4213  return 0;
4214 }
4215 
4244 int op_on_battleground(object *op, int *x, int *y, archetype **trophy) {
4245  FOR_BELOW_PREPARE(op, tmp) {
4246  if (QUERY_FLAG(tmp, FLAG_IS_FLOOR)) {
4247  if (QUERY_FLAG(tmp, FLAG_NO_PICK)
4248  && strcmp(tmp->name, "battleground") == 0
4249  && tmp->type == BATTLEGROUND
4250  && EXIT_X(tmp)
4251  && EXIT_Y(tmp)) {
4252  /*before we assign the exit, check if this is a teambattle*/
4253  if (EXIT_ALT_X(tmp) && EXIT_ALT_Y(tmp) && EXIT_PATH(tmp)) {
4254  object *invtmp;
4255 
4256  invtmp = object_find_by_type_and_slaying(op, FORCE, EXIT_PATH(tmp));
4257  if (invtmp != NULL) {
4258  if (x != NULL && y != NULL)
4259  *x = EXIT_ALT_X(tmp),
4260  *y = EXIT_ALT_Y(tmp);
4261  return 1;
4262  }
4263  }
4264  if (x != NULL && y != NULL)
4265  *x = EXIT_X(tmp),
4266  *y = EXIT_Y(tmp);
4267 
4268  /* If 'other_arch' is not specified, give a finger. */
4269  if (trophy != NULL) {
4270  if (tmp->other_arch) {
4271  *trophy = tmp->other_arch;
4272  } else {
4273  *trophy = find_archetype("finger");
4274  }
4275  }
4276  return 1;
4277  }
4278  }
4279  } FOR_BELOW_FINISH();
4280  /* If we got here, did not find a battleground */
4281  return 0;
4282 }
4283 
4294 void dragon_ability_gain(object *who, int atnr, int level) {
4295  treasurelist *trlist = NULL; /* treasurelist */
4296  treasure *tr; /* treasure */
4297  object *tmp, *skop; /* tmp. object */
4298  object *item; /* treasure object */
4299  char buf[MAX_BUF]; /* tmp. string buffer */
4300  int i = 0, j = 0;
4301 
4302  /* get the appropriate treasurelist */
4303  if (atnr == ATNR_FIRE)
4304  trlist = find_treasurelist("dragon_ability_fire");
4305  else if (atnr == ATNR_COLD)
4306  trlist = find_treasurelist("dragon_ability_cold");
4307  else if (atnr == ATNR_ELECTRICITY)
4308  trlist = find_treasurelist("dragon_ability_elec");
4309  else if (atnr == ATNR_POISON)
4310  trlist = find_treasurelist("dragon_ability_poison");
4311 
4312  if (trlist == NULL || who->type != PLAYER)
4313  return;
4314 
4315  for (i = 0, tr = trlist->items; tr != NULL && i < level-1; tr = tr->next, i++)
4316  ;
4317  if (tr == NULL || tr->item == NULL) {
4318  /* LOG(llevDebug, "-> no more treasure for %s\n", change_resist_msg[atnr]); */
4319  return;
4320  }
4321 
4322  /* everything seems okay - now bring on the gift: */
4323  item = &(tr->item->clone);
4324 
4325  if (item->type == SPELL) {
4326  if (check_spell_known(who, item->name))
4327  return;
4328 
4331  "You gained the ability of %s",
4332  item->name);
4333  do_learn_spell(who, item, 0);
4334  return;
4335  }
4336 
4337  /* grant direct spell */
4338  if (item->type == SPELLBOOK) {
4339  if (!item->inv) {
4340  LOG(llevDebug, "dragon_ability_gain: Broken spellbook %s\n", item->name);
4341  return;
4342  }
4343  if (check_spell_known(who, item->inv->name))
4344  return;
4345  if (item->invisible) {
4348  "You gained the ability of %s",
4349  item->inv->name);
4350  do_learn_spell(who, item->inv, 0);
4351  return;
4352  }
4353  } else if (item->type == SKILL_TOOL && item->invisible) {
4354  if (item->subtype == SK_CLAWING && (skop = find_skill_by_name(who, item->skill)) != NULL) {
4355  /* should this perhaps be (skop->attackyp&item->attacktype) != item->attacktype ...
4356  * in this way, if the player is missing any of the attacktypes, he gets
4357  * them. As it is now, if the player has any that match the granted skill,
4358  * but not all of them, he gets nothing.
4359  */
4360  if (!(skop->attacktype&item->attacktype)) {
4361  /* Give new attacktype */
4362  skop->attacktype |= item->attacktype;
4363 
4364  /* always add physical if there's none */
4365  skop->attacktype |= AT_PHYSICAL;
4366 
4367  if (item->msg != NULL)
4370  item->msg);
4371 
4372  /* Give player new face */
4373  if (item->animation_id) {
4374  who->face = skop->face;
4375  who->animation_id = item->animation_id;
4376  who->anim_speed = item->anim_speed;
4377  who->last_anim = 0;
4378  who->state = 0;
4379  animate_object(who, who->direction);
4380  }
4381  }
4382  }
4383  } else if (item->type == FORCE) {
4384  /* forces in the treasurelist can alter the player's stats */
4385  object *skin;
4386 
4387  /* first get the dragon skin force */
4388  skin = object_find_by_arch_name(who, "dragon_skin_force");
4389  if (skin == NULL)
4390  return;
4391 
4392  /* adding new spellpath attunements */
4393  if (item->path_attuned > 0 && !(skin->path_attuned&item->path_attuned)) {
4394  skin->path_attuned |= item->path_attuned; /* add attunement to skin */
4395 
4396  /* print message */
4397  snprintf(buf, sizeof(buf), "You feel attuned to ");
4398  for (i = 0, j = 0; i < NRSPELLPATHS; i++) {
4399  if (item->path_attuned&(1<<i)) {
4400  if (j)
4401  strcat(buf, " and ");
4402  else
4403  j = 1;
4404  strcat(buf, spellpathnames[i]);
4405  }
4406  }
4407  strcat(buf, ".");
4410  buf);
4411  }
4412 
4413  /* evtl. adding flags: */
4414  if (QUERY_FLAG(item, FLAG_XRAYS))
4415  SET_FLAG(skin, FLAG_XRAYS);
4416  if (QUERY_FLAG(item, FLAG_STEALTH))
4417  SET_FLAG(skin, FLAG_STEALTH);
4418  if (QUERY_FLAG(item, FLAG_SEE_IN_DARK))
4419  SET_FLAG(skin, FLAG_SEE_IN_DARK);
4420 
4421  /* print message if there is one */
4422  if (item->msg != NULL)
4425  item->msg);
4426  } else {
4427  /* generate misc. treasure */
4428  char name[HUGE_BUF];
4429 
4430  tmp = arch_to_object(tr->item);
4431  query_short_name(tmp, name, HUGE_BUF);
4434  "You gained %s",
4435  name);
4436  tmp = object_insert_in_ob(tmp, who);
4437  if (who->type == PLAYER)
4438  esrv_send_item(who, tmp);
4439  }
4440 }
4441 
4451 void player_unready_range_ob(player *pl, object *ob) {
4452  rangetype i;
4453 
4454  for (i = 0; i < range_size; i++) {
4455  if (pl->ranges[i] == ob) {
4456  pl->ranges[i] = NULL;
4457  if (pl->shoottype == i) {
4458  pl->shoottype = range_none;
4459  }
4460  }
4461  }
4462 }
4463 
4470 
4471  assert(pl);
4472  assert(state >= ST_PLAYING && state <= ST_CHANGE_PASSWORD_CONFIRM);
4473  pl->state = state;
4474 }
float weapon_speed_left
How much speed is left to spend this round.
Definition: object.h:331
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...)
Sends message to player(s).
Definition: main.c:315
Error, serious thing.
Definition: logger.h:11
static int player_fire_bow(object *op, int dir)
Special fire code for players - this takes into account the special fire modes players can have but m...
Definition: player.c:2378
uint8_t login_method
Login method this client is using.
Definition: newserver.h:140
void spring_trap(object *trap, object *victim)
This function generalizes attacks by runes/traps.
Definition: rune.c:205
static void set_player_socket(player *p, socket_struct *ns)
This copies the data from the socket into the player structure.
Definition: player.c:417
char path[HUGE_BUF]
Filename of the map.
Definition: map.h:365
Use skill.
Definition: player.h:22
uint8_t not_permadeth
If true, death is non-permament.
Definition: global.h:260
int player_can_view(object *pl, object *op)
Check the player los field for viewability of the object op.
Definition: player.c:4146
static int player_attack_door(object *op, object *door)
Player is "attacking" a door.
Definition: player.c:2619
void set_attr_value(living *stats, int attr, int8_t value)
Sets Str/Dex/con/Wis/Cha/Int/Pow in stats to value, depending on what attr is (STR to POW)...
Definition: living.c:218
const char * rules
Name of rules file.
Definition: global.h:276
#define MSG_TYPE_MISC
Messages that don&#39;t go elsewhere.
Definition: newclient.h:389
#define FLAG_NO_DROP
Object can&#39;t be dropped.
Definition: define.h:289
int8_t Int
Definition: living.h:35
One player.
Definition: player.h:92
#define FLAG_SEE_IN_DARK
if set ob not effected by darkness
Definition: define.h:338
int apply_manual(object *op, object *tmp, int aflag)
Main apply handler.
Definition: apply.c:510
Sound-related defines.
const char * determine_god(object *op)
Determines if op worships a god.
Definition: gods.c:106
archetype * find_archetype(const char *name)
Finds, using the hashtable, which archetype matches the given name.
Definition: arch.c:695
#define FLAG_DAMNED
The object is very cursed.
Definition: define.h:318
#define FLAG_IS_FLOOR
Can&#39;t see what&#39;s underneath this object.
Definition: define.h:303
#define FLAG_UNPAID
Object hasn&#39;t been paid for yet.
Definition: define.h:236
int8_t ac
Armour Class, how hard to hit, the lower the better.
Definition: living.h:37
#define MOVE_WALK
Object walks.
Definition: define.h:407
#define UP_OBJ_FACE
Only thing that changed was the face.
Definition: object.h:519
#define MSG_TYPE_ADMIN_LOGIN
login messages/errors
Definition: newclient.h:478
int swap_first
First stat player has selected to swap.
Definition: player.h:147
#define MSG_TYPE_ATTRIBUTE_GOD
changing god info
Definition: newclient.h:570
#define ST_GET_PARTY_PASSWORD
Player tried to join a password-protected party.
Definition: define.h:585
MoveType move_type
Type of movement this object uses.
Definition: object.h:424
see doc/Developers/objects
Definition: object.h:108
#define EVENT_REMOVE
A Player character has been removed.
Definition: plugin.h:93
#define MSG_TYPE_ITEM
Item related information.
Definition: newclient.h:388
Spell-related defines: spellpath, subtypes, ...
uint8_t stat_loss_on_death
If true, chars lose a random stat when they die.
Definition: global.h:254
int16_t gen_hp
Bonuses to regeneration speed of hp.
Definition: player.h:113
See Key.
Definition: object.h:127
player * find_player_options(const char *plname, int options, const mapstruct *map)
Find a player.
Definition: player.c:65
#define DETOUR_AMOUNT
This value basically determines how large a detour a monster will take from the direction path when l...
Definition: player.c:581
MoveType move_on
Move types affected moving on to this space.
Definition: object.h:427
See Ring.
Definition: object.h:185
int64_t calc_skill_exp(const object *who, const object *op, const object *skill)
Calculates amount of experience can be gained for successful use of a skill.
Definition: skill_util.c:657
bool shop_contains(object *ob)
Check if an object is in a shop.
Definition: shop.c:1258
uint8_t max_stat
Maximum stat value - 255 should be sufficient.
Definition: global.h:322
void enter_exit(object *op, object *exit_ob)
Tries to move &#39;op&#39; to exit_ob.
Definition: server.c:706
This is used by get_rangevector to determine where the other creature is.
Definition: map.h:380
Fire north-west whatever the facing direction.
Definition: player.h:39
treasureliststruct represents one logical group of items to be generated together.
Definition: treasure.h:82
void leave(player *pl, int draw_exit)
Player logs out, or was disconnected.
Definition: server.c:1180
static void swap_stat(object *op, int swap_second)
Player finishes selecting what stats to swap.
Definition: player.c:1126
static void loot_object(object *op)
Grab and destroy some treasure.
Definition: player.c:3437
object * check_spell_known(object *op, const char *name)
Checks to see if player knows the spell.
Definition: spell_util.c:435
Used to link together several objects.
Definition: object.h:442
const char * race
Human, goblin, dragon, etc.
Definition: object.h:318
void remove_door(object *op)
Remove non locked doors.
Definition: time.c:37
int account_remove_player(const char *account_name, const char *player_name)
Removes a player name from an account.
Definition: account.c:496
char * account_name
Name of the account logged in on this socket.
Definition: newserver.h:138
#define PU_CONTAINER
Definition: define.h:143
void SockList_Init(SockList *sl)
Initializes the SockList instance.
Definition: lowlevel.c:48
void esrv_send_item(object *pl, object *op)
Sends item&#39;s info to player.
Definition: main.c:339
#define SET_FLAG(xyz, p)
Definition: define.h:223
sstring add_refcount(sstring str)
This will increase the refcount of the string str.
Definition: shstr.c:210
#define EXIT_ALT_Y(xyz)
Definition: define.h:460
#define NDI_ALL
Inform all players of this message.
Definition: newclient.h:246
int get_party_password(object *op, partylist *party)
Ask the player for the password of the party she wants to join.
Definition: player.c:996
int16_t bed_x
Definition: player.h:98
uint32_t run_on
Player should keep moving in dir until run is off.
Definition: player.h:128
#define PU_DEBUG
Definition: define.h:108
Fire three arrows in the same direction.
Definition: player.h:30
char title[BIG_NAME]
Default title, like fighter, wizard, etc.
Definition: player.h:165
#define FABS(x)
Decstations have trouble with fabs()...
Definition: define.h:22
int cure_disease(object *sufferer, object *caster, sstring skill)
Do the cure disease stuff, from the spell "cure disease".
Definition: disease.c:685
uint32_t braced
Will not move if braced, only attack.
Definition: player.h:124
unsigned char uint8_t
Definition: win32.h:161
See Scroll.
Definition: object.h:221
static struct Command_Line_Options options[]
Actual valid command line options.
Definition: init.c:284
#define MSG_TYPE_ITEM_ADD
Item added to inventory.
Definition: newclient.h:639
#define EVENT_DEATH
Player or monster dead.
Definition: plugin.h:67
void SockList_ResetRead(SockList *sl)
Resets the length of the stored data for reading.
Definition: lowlevel.c:75
void get_name(object *op)
Waiting for the player&#39;s name.
Definition: player.c:854
int get_rangevector_from_mapcoord(const mapstruct *m, int x, int y, const object *op2, rv_vector *retval, int flags)
This is basically the same as get_rangevector() above, but instead of the first parameter being an ob...
Definition: map.c:2600
void make_path_to_file(const char *filename)
Checks if any directories in the given path doesn&#39;t exist, and creates if necessary.
Definition: porting.c:312
char spellparam[MAX_BUF]
What param to add to spells.
Definition: player.h:100
static void kill_player_not_permadeath(object *op)
Kills a player in non-permadeath mode.
Definition: player.c:3578
int get_dam_bonus(int stat)
Definition: living.c:2289
uint16_t animation_id
An index into the animation array.
Definition: object.h:416
#define MSG_TYPE_COMMAND_FAILURE
Failed result from command.
Definition: newclient.h:511
#define MSG_TYPE_ITEM_INFO
Information related to items.
Definition: newclient.h:641
uint16_t material
What materials this object consist of.
Definition: object.h:347
#define FLAG_USE_ARMOUR
(Monster) can wear armour/shield/helmet
Definition: define.h:296
void send_news(const object *op)
Send the news to a player.
Definition: player.c:201
int fire_bow(object *op, object *arrow, int dir, int wc_mod, int16_t sx, int16_t sy)
Creature (monster or player) fires a bow.
Definition: player.c:2173
#define BALSL_NUMBER_LOSSES_RATIO
Definition: config.h:143
#define strdup_local
Definition: compat.h:25
uint8_t anim_speed
Ticks between animation-frames.
Definition: object.h:417
object * object_find_by_type(const object *who, int type)
Find object in inventory.
Definition: object.c:3903
Defines various flags that both the new client and new server use.
void drain_wand_charge(object *wand)
Drains a charge from a wand.
Definition: spell_util.c:829
int16_t last_resist[NROFATTACKS]
last resist values sent to client.
Definition: player.h:155
See Cloak.
Definition: object.h:204
One party.
Definition: party.h:10
uint16_t look_position
Start of drawing of look window.
Definition: newserver.h:126
EXTERN objectlink * first_friendly_object
Objects monsters will go after.
Definition: global.h:123
See Food.
Definition: object.h:112
struct obj * container
Current container being used.
Definition: object.h:291
#define EVENT_LOGIN
Player login.
Definition: plugin.h:88
uint8_t last_anim
Last sequence used to draw face.
Definition: object.h:418
#define PU_STOP
Definition: define.h:110
See Projectile.
Definition: object.h:117
#define FLAG_FRIENDLY
Will help players.
Definition: define.h:246
int push_ob(object *who, int dir, object *pusher)
Something is pushing some other object.
Definition: move.c:417
Definition: living.h:14
#define PU_SHIELD
Definition: define.h:122
char motd[MAX_BUF]
Name of the motd file.
Definition: global.h:275
void player_update_bg_music(object player[static 1])
Definition: sounds.c:152
void fatal(enum fatal_error err)
fatal() is meant to be called whenever a fatal signal is intercepted.
Definition: utils.c:596
object * mon
Definition: comet_perf.c:74
No range selected.
Definition: player.h:17
#define NDI_BROWN
Sienna.
Definition: newclient.h:233
int op_on_battleground(object *op, int *x, int *y, archetype **trophy)
Check if the given object (usually a player) is standing on a battleground tile.
Definition: player.c:4244
#define MSG_TYPE_SPELL
Spell related info.
Definition: newclient.h:387
static int turn_transport(object *transport, object *captain, int dir)
Try to turn a transport in the desired direction.
Definition: player.c:2987
#define SOUND_TYPE_GROUND
Definition: newclient.h:311
treasurelist * find_treasurelist(const char *name)
Searches for the given treasurelist in the globally linked list of treasurelists which has been built...
Definition: treasure.c:292
int save_player(object *op, int flag)
Saves a player to disk.
Definition: login.c:211
void dragon_ability_gain(object *who, int atnr, int level)
When a dragon-player gains a new stage of evolution, he gets some treasure.
Definition: player.c:4294
uint32_t in_memory
Combination of IN_MEMORY_xxx flags.
Definition: map.h:345
const char * playerdir
Where the player files are.
Definition: global.h:246
int16_t maxgrace
Maximum grace.
Definition: living.h:44
void free_string(sstring str)
This will reduce the refcount, and if it has reached 0, str will be freed.
Definition: shstr.c:280
#define PU_KEY
Definition: define.h:128
signed long object_sum_weight(object *op)
object_sum_weight() is a recursive function which calculates the weight an object is carrying...
Definition: object.c:311
#define HUGE_BUF
Used for messages - some can be quite long.
Definition: define.h:37
#define SET_ANIMATION(ob, newanim)
Definition: global.h:171
mapstruct * get_map_from_coord(mapstruct *m, int16_t *x, int16_t *y)
This is basically the same as out_of_map above(), but instead we return NULL if no map is valid (coor...
Definition: map.c:2368
void esrv_update_item(int flags, object *pl, object *op)
Updates object *op for player *pl.
Definition: main.c:342
See Spellbook.
Definition: object.h:203
void enter_player_maplevel(object *op)
Move a player to its stored map level.
Definition: server.c:651
const char * object_get_value(const object *op, const char *const key)
Get an extra value by key.
Definition: object.c:4246
See Money.
Definition: object.h:137
struct treasureliststruct * randomitems
Items to be generated.
Definition: object.h:385
void pick_up(object *op, object *alt)
Try to pick up an item.
Definition: c_object.c:446
#define NDI_BLUE
Actually, it is Dodger 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)
Query a short name for the item.
Definition: item.c:722
#define ST_CHANGE_PASSWORD_CONFIRM
Player is confirming new password.
Definition: define.h:588
Socket structure, represents a client-server connection.
Definition: newserver.h:99
int8_t levsp[11]
What sp bonus the player gained on that level.
Definition: player.h:168
object clone
An object from which to do object_copy()
Definition: object.h:470
socket_struct socket
Socket information for this player.
Definition: player.h:94
int16_t invisible
How much longer the object will be invis.
Definition: object.h:360
short freearr_x[SIZEOFFREE]
X offset when searching around a spot.
Definition: object.c:65
#define PREFER_LOW
Definition: define.h:600
Definition: living.h:17
#define ST_CONFIRM_PASSWORD
New character, confirm password.
Definition: define.h:584
rangetype shoottype
Which range-attack is being used by player.
Definition: player.h:99
See Rune.
Definition: object.h:240
int16_t SP_level_spellpoint_cost(object *caster, object *spell, int flags)
Scales the spellpoint cost of a spell by it&#39;s increased effectiveness.
Definition: spell_util.c:277
See Weapon.
Definition: object.h:119
See Helmet.
Definition: object.h:136
const char * slaying
Which race to do double damage to.
Definition: object.h:319
#define IS_WEAPON(op)
Definition: define.h:162
void esrv_send_inventory(object *pl, object *op)
Sends inventory of a container.
Definition: item.c:307
#define FLAG_CONFUSED
Will also be unable to cast spells.
Definition: define.h:312
#define FLAG_STEALTH
Will wake monsters with less range.
Definition: define.h:313
static object * pick_arrow_target(object *op, const char *type, int dir)
Looks in a given direction, finds the first valid target, and calls find_better_arrow() to find a dec...
Definition: player.c:2104
object * ranges[range_size]
Object for each range.
Definition: player.h:103
uint8_t subtype
Subtype of object.
Definition: object.h:339
const char * party_get_password(const partylist *party)
Returns the party&#39;s password.
Definition: party.c:263
See Rod.
Definition: object.h:109
void send_account_players(socket_struct *ns)
Upon successful login/account creation, we send a list of characters associated with the account to t...
Definition: request.c:1862
void send_rules(const object *op)
Send the rules to a player.
Definition: player.c:165
#define SOUND_TYPE_LIVING
Definition: newclient.h:308
#define FLAG_USE_WEAPON
(Monster) can wield weapons
Definition: define.h:297
uint8_t hide
The object is hidden, not invisible.
Definition: object.h:387
int64_t exp
Experience.
Definition: living.h:46
void fix_luck(void)
Fixes luck of players, slowly move it towards 0.
Definition: player.c:3903
void play_again(object *op)
Ask the player whether to play again or disconnect.
Definition: player.c:878
void change_luck(object *op, int value)
Alter the object&#39;s luck.
Definition: living.c:791
object * object_find_by_type_and_slaying(const object *who, int type, const char *slaying)
Find object in inventory by type and slaying.
Definition: object.c:4049
method_ret ob_process(object *op)
Processes an object, giving it the opportunity to move or react.
Definition: ob_methods.c:62
void SockList_AddInt(SockList *sl, uint32_t data)
Adds a 32 bit value.
Definition: lowlevel.c:119
#define OUT_OF_REAL_MAP(M, X, Y)
Checks if a square is out of the map.
Definition: map.h:217
int language
The language the player wishes to use.
Definition: player.h:201
Misc items.
Definition: player.h:20
See Drink.
Definition: object.h:157
#define object_was_destroyed(op, old_tag)
Checks if an object still exists.
Definition: object.h:68
treasure is one element in a linked list, which together consist of a complete treasure-list.
Definition: treasure.h:63
#define TRUE
Definition: compat.h:10
#define PU_NOTHING
Definition: define.h:106
#define PU_FLESH
Definition: define.h:142
void handle_client(socket_struct *ns, player *pl)
Handle commands from a client.
Definition: loop.c:234
#define PU_FOOD
Definition: define.h:115
object * arch_present_in_ob(const archetype *at, const object *op)
Searches for any objects with a matching archetype in the inventory of the given object.
Definition: object.c:3061
void party_leave(object *op)
Makes a player leave his party.
Definition: party.c:104
Various statistics of objects.
Definition: living.h:34
void do_some_living(object *op)
Regenerate hp/sp/gr, decreases food.
Definition: player.c:3298
void give_initial_items(object *pl, treasurelist *items)
Gives a new player her initial items.
Definition: player.c:762
See Amulet.
Definition: object.h:139
int8_t get_attr_value(const living *stats, int attr)
Gets the value of a stat.
Definition: living.c:313
void remove_friendly_object(object *op)
Removes the specified object from the linked list of friendly objects.
Definition: friend.c:56
uint32_t path_attuned
Paths the object is attuned to.
Definition: object.h:343
#define MAX(x, y)
Definition: compat.h:20
void object_update(object *op, int action)
object_update() updates the array which represents the map.
Definition: object.c:1239
#define MSG_TYPE_ITEM_REMOVE
Item removed from inv.
Definition: newclient.h:638
void account_char_free(Account_Char *chars)
This frees all data associated with the character information.
Definition: account_char.c:332
void dead_player(object *op)
Kill a player on a permanent death server with resurrection.
Definition: resurrection.c:294
int16_t sp
Spell points.
Definition: living.h:41
EXTERN char first_map_ext_path[MAX_BUF]
Path used for per-race start maps.
Definition: global.h:154
void strip_endline(char *buf)
Removes endline from buffer (modified in place).
Definition: utils.c:340
Use keys in inventory and active key rings.
Definition: player.h:54
Try to find an arrow matching the target.
Definition: player.h:40
animal &#39;body parts&#39; -b.t.
Definition: object.h:187
Global type definitions and header inclusions.
int path_to_player(object *mon, object *pl, unsigned mindiff)
Returns the direction to the player, if valid.
Definition: player.c:629
void get_password(object *op)
Waiting for the player&#39;s password.
Definition: player.c:866
#define safe_strncpy
Definition: compat.h:23
int is_true_undead(object *op)
Is the object a true undead?
Definition: player.c:3973
#define SCRIPT_FIX_ALL
Definition: global.h:361
See Boots.
Definition: object.h:212
player * find_player_partial_name(const char *plname)
Find a player by a partial name.
Definition: player.c:109
#define PU_NEWMODE
Definition: define.h:111
uint32_t hidden
If True, player (DM) is hidden from view.
Definition: player.h:132
void pets_terminate_all(object *owner)
Removes all pets someone owns.
Definition: pets.c:231
static const char * gravestone_text(object *op, char *buf2, int len)
Create a text for a player&#39;s gravestone.
Definition: player.c:3263
struct obj * enemy
Monster/player to follow even if not closest.
Definition: object.h:381
object * get_nearest_player(object *mon)
Finds the nearest visible player for some object.
Definition: player.c:520
#define ST_ROLL_STAT
New character, rolling stats.
Definition: define.h:579
int distance_y
Y delta.
Definition: map.h:383
int absdir(int d)
Computes an absolute direction.
Definition: object.c:3637
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
Sends message to player(s).
Definition: main.c:310
The archetype structure is a set of rules on how to generate and manipulate objects which point to ar...
Definition: object.h:465
#define ST_PLAYING
Usual state.
Definition: define.h:577
#define PU_MISSILEWEAPON
Definition: define.h:130
char savebed_map[MAX_BUF]
Map where player will respawn after death.
Definition: player.h:97
#define NDI_DK_ORANGE
DarkOrange2.
Definition: newclient.h:227
char * host
Which host it is connected from (ip address).
Definition: newserver.h:110
See Wand & Staff.
Definition: object.h:220
#define MSG_TYPE_APPLY
Applying objects.
Definition: newclient.h:384
#define FOR_OB_AND_BELOW_FINISH()
Finishes FOR_OB_AND_BELOW_PREPARE().
Definition: define.h:789
const char *const spellpathnames[NRSPELLPATHS]
Perhaps not the best place for this, but needs to be in some file in the common area so that standalo...
Definition: init.c:120
struct archt * item
Which item this link can be.
Definition: treasure.h:64
uint16_t emergency_y
Coordinates to use on that map.
Definition: global.h:298
static int turn_one_transport(object *transport, object *captain, int dir)
Turn a transport to an adjacent direction (+1 or -1), updating the move_type flags in the same proces...
Definition: player.c:2917
#define PU_CLOAK
Definition: define.h:127
int16_t maxsp
Max spell points.
Definition: living.h:42
#define MIN(x, y)
Definition: compat.h:17
int8_t Con
Definition: living.h:35
#define FLAG_REMOVED
Object is not in any map or invenory.
Definition: define.h:232
int16_t hp
Hit Points.
Definition: living.h:39
int check_pick(object *op)
Sees if there is stuff to be picked up/picks up stuff, for players only.
Definition: player.c:1688
#define FLAG_CAN_ROLL
Object can be rolled.
Definition: define.h:254
short freearr_y[SIZEOFFREE]
Y offset when searching around a spot.
Definition: object.c:71
partylist * party
Party this player is part of.
Definition: player.h:186
#define FLAG_KNOWN_MAGICAL
The object is known to be magical.
Definition: define.h:320
Fire north whatever the facing direction.
Definition: player.h:32
Clawing.
Definition: skills.h:50
#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)
This calls the appropriate treasure creation function.
Definition: treasure.c:490
uint32_t no_shout
if True, player is *not *able to use shout command.
Definition: player.h:133
object * ob
Item to link to.
Definition: object.h:443
#define FIND_PLAYER_PARTIAL_NAME
Find on partial name.
Definition: player.h:212
#define MOVE_ALL
Mask of all movement types.
Definition: define.h:413
Don&#39;t generate bad/cursed items.
Definition: treasure.h:34
uint32_t ticks_played
How many ticks this player has played.
Definition: player.h:203
void pets_control_golem(object *op, int dir)
Makes the golem go in specified direction.
Definition: pets.c:648
Allows the use of a skill.
Definition: object.h:189
#define MIN_STAT
The minimum legal value of any stat.
Definition: define.h:33
#define FLAG_UNDEAD
Monster is undead.
Definition: define.h:270
void object_set_owner(object *op, object *owner)
Sets the owner and sets the skill and exp pointers to owner&#39;s current skill and experience objects...
Definition: object.c:601
const char * news
Name of news file.
Definition: global.h:277
#define FLAG_READY_SKILL
(Monster or Player) has a skill readied
Definition: define.h:334
void apply_changes_to_player(object *pl, object *change, int limit_stats)
Applies (race) changes to a player.
Definition: apply.c:1581
See Trap.
Definition: object.h:241
#define MAP_IN_MEMORY
Map is fully loaded.
Definition: map.h:130
struct obj * chosen_skill
The skill chosen to use.
Definition: object.h:386
uint32_t update_look
If true, we need to send the look window.
Definition: newserver.h:115
object * find_key(object *pl, object *container, object *door)
We try to find a key for the door as passed.
Definition: player.c:2538
void object_free_drop_inventory(object *ob)
Frees everything allocated by an object, removes it from the list of used objects, and puts it on the list of free objects.
Definition: object.c:1368
void clear_player(player *pl)
Clears data in player structure.
Definition: player.c:33
int16_t y
Position in the map for this object.
Definition: object.h:326
void esrv_new_player(player *pl, uint32_t weight)
Tells the client that here is a player it should start using.
Definition: request.c:856
object * object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
Same as object_insert_in_map() except it handle separate coordinates and do a clean job preparing mul...
Definition: object.c:1921
Fire three arrows in a cone.
Definition: player.h:31
int16_t maxhp
Max hit points.
Definition: living.h:40
static void fire_misc_object(object *op, int dir)
Fires a misc (wand/rod/horn) object in &#39;dir&#39;.
Definition: player.c:2414
#define MSG_TYPE_ATTRIBUTE_BAD_EFFECT_END
End of a bad effect.
Definition: newclient.h:561
void object_update_turn_face(object *op)
If an object with the IS_TURNABLE() flag needs to be turned due to the closest player being on the ot...
Definition: object.c:1109
#define MSG_TYPE_COMMAND
Responses to commands, eg, who.
Definition: newclient.h:379
#define PU_BOOTS
Definition: define.h:125
See Shooting Weapon.
Definition: object.h:118
int stand_near_hostile(object *who)
Determine if who is standing near a hostile creature.
Definition: player.c:4078
#define FLAG_ALIVE
Object can fight (or be fought)
Definition: define.h:230
Account_Char * account_chars
Detailed information on characters on this account.
Definition: newserver.h:139
#define ADD_PLAYER_NO_STATS_ROLL
Stats provided from client.
Definition: player.h:224
See Book.
Definition: object.h:114
#define MSG_TYPE_VICTIM
Something bad is happening to the player.
Definition: newclient.h:392
int get_randomized_dir(int dir)
Returns a random direction (1..8) similar to a given direction.
Definition: utils.c:438
object * object_new(void)
Grabs an object from the list of unused objects, makes sure it is initialised, and returns it...
Definition: object.c:1037
const char * name_pl
The plural name of the object.
Definition: object.h:315
object * create_archetype(const char *name)
Finds which archetype matches the given name, and returns a new object containing a copy of the arche...
Definition: arch.c:620
void player_set_own_title(struct pl *pl, const char *title)
Sets the custom title.
Definition: player.c:264
int object_can_pick(const object *who, const object *item)
Finds out if an object can be picked up.
Definition: object.c:3793
object * object_insert_in_ob(object *op, object *where)
This function inserts the object op in the linked list inside the object environment.
Definition: object.c:2690
void send_query(socket_struct *ns, uint8_t flags, const char *text)
Asks the client to query the user.
Definition: request.c:674
battleground, by Andreas Vogl
Definition: object.h:163
float speed_left
How much speed is left to spend this round.
Definition: object.h:329
unapplymode unapply
Method for auto unapply.
Definition: player.h:108
int is_wraith_pl(object *op)
Tests if a player is a wraith.
Definition: player.c:165
int16_t gen_sp
Bonuses to regeneration speed of sp.
Definition: player.h:114
#define MSG_TYPE_COMMAND_SUCCESS
Successful result from command.
Definition: newclient.h:510
player * get_player(player *p)
Create a player&#39;s object, initialize a player&#39;s structure.
Definition: player.c:280
#define MSG_TYPE_COMMAND_ERROR
Bad syntax/can&#39;t use command.
Definition: newclient.h:509
int blocked_link(object *ob, mapstruct *m, int sx, int sy)
Returns true if the given coordinate is blocked except by the object passed is not blocking...
Definition: map.c:346
#define PU_SKILLSCROLL
Definition: define.h:136
signed short int16_t
Definition: win32.h:160
uint8_t search_items
Search_items command.
Definition: global.h:265
See Special Key.
Definition: object.h:124
const char * materialname
Specific material name.
Definition: object.h:346
int32_t weight
Attributes of the object.
Definition: object.h:365
static void kill_player_permadeath(object *op)
Kills a player in permadeath mode.
Definition: player.c:3805
#define FLAG_CAN_USE_SKILL
The monster can use skills.
Definition: define.h:322
#define MOVE_FLY_LOW
Low flying object.
Definition: define.h:408
const char * anim_suffix
Used to determine combined animations.
Definition: object.h:316
#define ADD_PLAYER_NEW
Name/password provided, so skip to roll stats.
Definition: player.h:222
uint32_t tmp_invis
Will invis go away when we attack?
Definition: player.h:125
void drain_rod_charge(object *rod)
Drain charges from a rod.
Definition: spell_util.c:819
int8_t Wis
Definition: living.h:35
int hide(object *op, object *skill)
Main hide handling.
Definition: skills.c:491
#define FLAG_UNAGGRESSIVE
Monster doesn&#39;t attack players.
Definition: define.h:272
#define FLAG_USE_SHIELD
Can this creature use a shield?
Definition: define.h:237
player * add_player(socket_struct *ns, int flags)
Tries to add player on the connection passwd in ns.
Definition: player.c:453
#define MSG_TYPE_ADMIN_PLAYER
Player coming/going/death.
Definition: newclient.h:474
void receive_play_again(object *op, char key)
Player replied to play again / disconnect.
Definition: player.c:930
#define PU_ARROW
Definition: define.h:120
struct mapdef * map
Pointer to the map in which this object is present.
Definition: object.h:297
void SockList_Term(SockList *sl)
Frees all resources allocated by a SockList instance.
Definition: lowlevel.c:58
char search_str[MAX_BUF]
Item we are looking for.
Definition: player.h:192
#define snprintf
Definition: win32.h:46
#define ARCH_DEPLETION
Archetype for depletion.
Definition: object.h:579
int ob_blocked(const object *ob, mapstruct *m, int16_t x, int16_t y)
Returns true if the given object can&#39;t fit in the given spot.
Definition: map.c:489
Map builder.
Definition: player.h:23
#define MSG_TYPE_ATTRIBUTE
Changes to attributes (stats, resistances, etc)
Definition: newclient.h:380
object * transport
Transport the player is in.
Definition: player.h:195
#define FLAG_IDENTIFIED
Player knows full info about item.
Definition: define.h:261
Standard mode, one random arrow.
Definition: player.h:29
#define MOVE_FLYING
Combo of fly_low and fly_high.
Definition: define.h:410
#define FOR_INV_FINISH()
Finishes FOR_INV_PREPARE().
Definition: define.h:712
object * object_find_by_flag_applied(const object *who, int flag)
Find applied object in inventory by flag.
Definition: object.c:4120
Control golem.
Definition: player.h:21
int16_t dam
How much damage this object does when hitting.
Definition: living.h:45
Rejoin if party exists.
Definition: player.h:87
uint8_t balanced_stat_loss
If true, Death stat depletion based on level etc.
Definition: global.h:259
void change_attr_value(living *stats, int attr, int8_t value)
Like set_attr_value(), but instead the value (which can be negative) is added to the specified stat...
Definition: living.c:264
int die_roll(int num, int size, const object *op, int goodbad)
Roll a number of dice (2d3, 4d6).
Definition: utils.c:121
void add_friendly_object(object *op)
Add a new friendly object to the linked list of friendly objects.
Definition: friend.c:30
int32_t carrying
How much weight this object contains.
Definition: object.h:367
#define NDI_GREEN
SeaGreen.
Definition: newclient.h:228
const char * name
The name of the object, obviously...
Definition: object.h:311
int16_t bed_y
x,y - coordinates of respawn (savebed).
Definition: player.h:98
living orig_stats
Permanent real stats of player.
Definition: player.h:148
#define PU_INHIBIT
Definition: define.h:109
int distance_x
X delta.
Definition: map.h:382
#define PU_BOW
Definition: define.h:118
int allowed_class(const object *op)
Returns true if the given player is a legal class.
Definition: living.c:1619
#define MSG_TYPE_COMMAND_NEWPLAYER
Create a new character - not really a command, but is responding to player input. ...
Definition: newclient.h:516
static int similar_direction(int a, int b)
Is direction a similar to direction b? Find out in this exciting function below.
Definition: player.c:2344
uint8_t state
How the object was last drawn (animation)
Definition: object.h:349
#define ST_PLAY_AGAIN
Player left through a bed of reality, and can login again.
Definition: define.h:578
void roll_again(object *op)
Ask the player what to do with the statistics.
Definition: player.c:1112
int execute_global_event(int eventcode,...)
Definition: main.c:369
#define EXIT_PATH(xyz)
Definition: define.h:455
uint8_t state
Input state of the player (name, password, etc).
Definition: player.h:118
#define MSG_TYPE_SPELL_END
A spell ends.
Definition: newclient.h:629
uint64_t price_base(const object *obj)
Determine the base (intrinsic) value of an item.
Definition: shop.c:66
void display_motd(const object *op)
Sends the message of the day to the player.
Definition: player.c:134
#define offsetof(type, member)
The offsetof macro is part of ANSI C, but many compilers lack it, for example "gcc -ansi"...
Definition: shstr.h:37
#define CS_QUERY_SINGLECHAR
Single character response expected.
Definition: newclient.h:67
int monster_can_detect_enemy(object *op, object *enemy, rv_vector *rv)
Determine if we can &#39;detect&#39; the enemy.
Definition: monster.c:2386
void SockList_AddString(SockList *sl, const char *data)
Adds a string without length.
Definition: lowlevel.c:149
#define FLAG_PARALYZED
Monster or player is paralyzed.
Definition: define.h:380
#define PU_RATIO
Definition: define.h:113
int8_t direction
Means the object is moving that way.
Definition: object.h:334
uint32_t nrof
How many of the objects.
Definition: object.h:333
uint8_t listening
Which priority will be used in info_all.
Definition: player.h:120
void fire(object *op, int dir)
Received a fire command for the player - go and do it.
Definition: player.c:2466
int8_t Cha
Definition: living.h:35
#define OB_TYPE_MOVE_BLOCK(ob1, type)
Basic macro to see if if ob1 can not move onto a space based on the &#39;type&#39; move_block parameter Add c...
Definition: define.h:447
void hiscore_check(object *op, int quiet)
Checks if player should enter the hiscore, and if so writes her into the list.
Definition: hiscore.c:302
#define AP_NOPRINT
Don&#39;t print messages - caller will do that may be some that still print.
Definition: define.h:621
void remove_locked_door(object *op)
Same as remove_door() but for locked doors.
Definition: time.c:63
#define P_OUT_OF_MAP
This space is outside the map.
Definition: map.h:251
Number of statistics.
Definition: living.h:18
#define GET_MAP_MOVE_BLOCK(M, X, Y)
Gets the blocking state of a square.
Definition: map.h:192
int do_skill(object *op, object *part, object *skill, int dir, const char *string)
Main skills use function-similar in scope to cast_spell().
Definition: skill_util.c:428
uint16_t emergency_x
Definition: global.h:298
int move_ob(object *op, int dir, object *originator)
Op is trying to move in direction dir.
Definition: move.c:58
#define EXIT_X(xyz)
Definition: define.h:457
void do_learn_spell(object *op, object *spell, int special_prayer)
Actually makes op learn spell.
Definition: apply.c:391
See Potion.
Definition: object.h:111
uint32_t has_hit
If set, weapon_sp instead of speed will count.
Definition: player.h:129
struct pl * contr
Pointer to the player which control this object.
Definition: object.h:276
#define PU_DRINK
Definition: define.h:116
static void flee_player(object *op)
The player is scared, and should flee.
Definition: player.c:1629
void add_statbonus(object *op)
Adds stat-bonuses given by the class which the player has chosen.
Definition: living.c:863
#define FLAG_SCARED
Monster is scared (mb player in future)
Definition: define.h:271
uint8_t darkness
Indicates level of darkness of map.
Definition: map.h:346
#define MSG_TYPE_SKILL_FAILURE
Failure in using skill.
Definition: newclient.h:585
player * find_player_socket(const socket_struct *ns)
Return a player for a socket structure.
Definition: player.c:118
#define FLAG_XRAYS
X-ray vision.
Definition: define.h:301
#define FREE_AND_CLEAR_STR(xyz)
Release the shared string, and set it to NULL.
Definition: global.h:208
void set_first_map(object *op)
This loads the first map an puts the player on it.
Definition: player.c:398
char * spellarg
Optional argument when casting obj::spell.
Definition: object.h:409
int8_t blocked_los[MAP_CLIENT_X][MAP_CLIENT_Y]
Array showing what spaces the player can see.
Definition: player.h:159
uint32_t tag_t
Object tag, unique during the whole game.
Definition: object.h:12
int8_t luck
Affects thaco and ac from time to time.
Definition: living.h:38
#define ATNR_ELECTRICITY
Definition: attack.h:52
#define ATNR_POISON
Definition: attack.h:59
#define AT_PHYSICAL
Definition: attack.h:76
float speed
The overall speed of this object.
Definition: object.h:328
See Spell.
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)
Returns the head part of an object.
Definition: object.h:594
party_rejoin_mode rejoin_party
Whether to rejoin or not party at login.
Definition: player.h:191
#define MSG_TYPE_ADMIN_NEWS
Definition: newclient.h:473
void clear_los(object *op)
Clears/initialises the los-array associated to the player controlling the object. ...
Definition: los.c:248
#define FLAG_WIZ
Object has special privilegies.
Definition: define.h:231
void change_exp(object *op, int64_t exp, const char *skill_name, int flag)
Changes experience to a player/monster.
Definition: living.c:2094
#define FLAG_BEEN_APPLIED
The object has been applied.
Definition: define.h:324
uint32_t golem_count
To track the golem.
Definition: player.h:106
#define EXIT_ALT_X(xyz)
Definition: define.h:459
See Locked Door.
Definition: object.h:123
void object_get_multi_size(const object *ob, int *sx, int *sy, int *hx, int *hy)
Computes the size of a multitile object.
Definition: object.c:4626
#define MSG_TYPE_COMMAND_DEBUG
Various debug type commands.
Definition: newclient.h:508
#define BALSL_LOSS_CHANCE_RATIO
Definition: config.h:142
#define EXIT_Y(xyz)
Definition: define.h:458
void delete_character(const char *name)
Totally deletes a character.
Definition: login.c:86
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
#define MSG_TYPE_ATTACK
Attack related messages.
Definition: newclient.h:385
#define NRSPELLPATHS
Number of spell paths.
Definition: spells.h:40
Standard mode/.
Definition: player.h:45
#define IS_SHIELD(op)
Definition: define.h:169
See Door.
Definition: object.h:126
#define PU_READABLES
Definition: define.h:137
#define MSG_TYPE_ADMIN
Definition: newclient.h:377
uint32_t peaceful
If set, won&#39;t attack friendly creatures.
Definition: player.h:131
Account_Char * account_char_remove(Account_Char *chars, const char *pl_name)
This removes a character on this account.
Definition: account_char.c:296
void do_hidden_move(object *op)
For hidden creatures - a chance of becoming &#39;unhidden&#39; every time they move - as we subtract off &#39;inv...
Definition: player.c:4037
int16_t x
Definition: object.h:326
void skill_attack(object *tmp, object *pl, int dir, const char *string, object *skill)
Core routine for use when we attack using a skills system.
Definition: skill_util.c:1239
can add a skill to player&#39;s inventory -bt.
Definition: object.h:234
int strncasecmp(const char *s1, const char *s2, int n)
Case-insensitive comparaison of strings.
Definition: porting.c:224
int8_t levhp[11]
What hp bonus the player gained on that level.
Definition: player.h:167
struct treasurestruct * items
Items in this list, linked.
Definition: treasure.h:90
#define MSG_TYPE_ATTRIBUTE_STAT_LOSS
Definition: newclient.h:563
const char * skill
Name of the skill this object uses/grants.
Definition: object.h:321
uint8_t mapx
Definition: newserver.h:128
void fix_weight(void)
Check recursively the weight of all players, and fix what needs to be fixed.
Definition: player.c:3887
Skill-related defines, including subtypes.
void esrv_map_scroll(socket_struct *ns, int dx, int dy)
Definition: request.c:1499
#define NUM_SKILLS
This is the highest number skill in the table +1 This is used to store pointers to the actual skills ...
Definition: skills.h:71
int8_t wc
Weapon Class, how skilled, the lower the better.
Definition: living.h:36
int roll_stat(void)
This rolls four 1-6 rolls and sums the best 3 of the 4.
Definition: player.c:1014
const char * confdir
Configuration files.
Definition: global.h:243
void kill_player(object *op, const object *killer)
Handle a player&#39;s death.
Definition: player.c:3477
void SockList_AddChar(SockList *sl, char c)
Adds an 8 bit value.
Definition: lowlevel.c:98
#define AC_PLAYER_STAT_NO_CHANGE
Definition: define.h:633
See Container.
Definition: object.h:231
#define FLAG_IS_THROWN
Object is designed to be thrown.
Definition: define.h:249
uint16_t difficulty
What level the player should be to play here.
Definition: map.h:343
static const flag_definition flags[]
Flag mapping.
#define FOR_MAP_FINISH()
Finishes FOR_MAP_PREPARE().
Definition: define.h:765
int8_t Str
Definition: living.h:35
void animate_object(object *op, int dir)
Updates the face-variable of an object.
Definition: anim.c:212
int16_t resist[NROFATTACKS]
Resistance adjustments for attacks.
Definition: object.h:341
#define FLAG_KNOWN_CURSED
The object is known to be cursed.
Definition: define.h:321
object * ob
The object representing the player.
Definition: player.h:158
int has_carried_lights(const object *op)
Checks if op has a light source.
Definition: los.c:311
int need_identify(const object *op)
This function really should not exist - by default, any item not identified should need it...
Definition: item.c:1331
const char *const lose_msg[NUM_STATS]
Message when a player decreases permanently a stat.
Definition: living.c:172
#define FLAG_CURSED
The object is cursed.
Definition: define.h:317
See Player.
Definition: object.h:107
unsigned int uint32_t
Definition: win32.h:162
void player_set_state(player *pl, uint8_t state)
Set the player&#39;s state to the specified one.
Definition: player.c:4469
See Poison Food.
Definition: object.h:113
void safe_strcat(char *dest, const char *orig, size_t *curlen, size_t maxlen)
Simple function we use below to keep adding to the same string but also make sure we don&#39;t overwrite ...
Definition: porting.c:346
See Shield.
Definition: object.h:135
object * object_find_by_type_subtype(const object *who, int type, int subtype)
Find object in inventory.
Definition: object.c:4195
bowtype_t bowtype
Which firemode?
Definition: player.h:101
int move_player(object *op, int dir)
Player gave us a direction, check whether to move or fire.
Definition: player.c:3019
char killer[BIG_NAME]
Who killed this player.
Definition: player.h:171
#define FLAG_ANIMATE
The object looks at archetype for faces.
Definition: define.h:242
void key_roll_stat(object *op, char key)
Player is currently swapping stats.
Definition: player.c:1184
#define PU_MELEEWEAPON
Definition: define.h:131
Object structure, the core of Crossfire.
Maximum, exclusive, value.
Definition: player.h:24
#define PREFER_HIGH
Definition: define.h:599
uint32_t attacktype
Bitmask of attacks this object does.
Definition: object.h:342
object * object_split(object *orig_ob, uint32_t nr, char *err, size_t size)
object_split(ob,nr) splits up ob into two parts.
Definition: object.c:2463
float last_speed
Last speed as sent to client.
Definition: player.h:154
#define object_decrease_nrof_by_one(xyz)
Definition: compat.h:28
#define MSG_TYPE_VICTIM_DIED
Player died!
Definition: newclient.h:654
void play_sound_player_only(player *pl, int8_t sound_type, object *emitter, int dir, const char *action)
Plays a sound for specified player only.
Definition: sounds.c:51
#define FLAG_NEUTRAL
monster is from type neutral
Definition: define.h:362
#define RANDOM()
Definition: define.h:679
living last_stats
Last stats as sent to client.
Definition: player.h:149
int handle_newcs_player(object *op)
Handles commands the player can send us, and various checks on invisibility, golem and such...
Definition: player.c:3104
const char * invis_race
What race invisible to?
Definition: player.h:135
#define FREE_AND_COPY(sv, nv)
Release the shared string if not NULL, and make it a reference to nv.
Definition: global.h:213
int16_t grace
Grace.
Definition: living.h:43
signed char int8_t
Type definitions for fixed-size integer types.
Definition: win32.h:158
Also see SKILL_TOOL (74) below.
Definition: object.h:143
uint32_t fire_on
Player should fire object, not move.
Definition: player.h:127
#define MAX_SPACES
This is used to prevent infinite loops.
Definition: player.c:596
const char * localdir
Read/write data files.
Definition: global.h:245
char password[16]
2 (seed) + 11 (crypted) + 1 (EOS) + 2 (safety) = 16
Definition: player.h:176
int32_t last_weight
Last weight as sent to client; -1 means do not send weight.
Definition: player.h:142
tag_t count
Unique object number for this object.
Definition: object.h:299
void recursive_roll(object *op, int dir, object *pusher)
An object is pushed by another which is trying to take its place.
Definition: move.c:276
living stats
Str, Con, Dex, etc.
Definition: object.h:368
static int save_life(object *op)
Can the player be saved by an item?
Definition: player.c:3190
int8_t Dex
Definition: living.h:35
struct archt * arch
Pointer to archetype.
Definition: object.h:412
float last_weapon_sp
if diff than weapon_sp, update client.
Definition: player.h:140
#define UPD_FACE
Definition: newclient.h:292
struct oblnk * next
Next item to link to.
Definition: object.h:444
int playername_ok(const char *cp)
Is the player name valid.
Definition: player.c:252
int apply_container(object *op, object *sack)
Handle apply on containers.
Definition: apply.c:216
Only for debugging purposes.
Definition: logger.h:13
#define MSG_TYPE_ATTACK_NOATTACK
You avoid attacking.
Definition: newclient.h:613
#define MSG_TYPE_ADMIN_RULES
Definition: newclient.h:472
void account_char_save(const char *account, Account_Char *chars)
Saves the character information for the given account.
Definition: account_char.c:145
Hiding.
Definition: skills.h:21
int check_race_and_class(living *stats, archetype *race, archetype *opclass)
This checks to see if the race and class are legal.
Definition: player.c:1400
void make_visible(object *op)
Makes an object visible again.
Definition: player.c:3953
static archetype * get_player_archetype(archetype *at)
Get next player archetype from archetype list.
Definition: player.c:495
#define SPELL_HIGHEST
Definition: spells.h:60
unsigned int distance
Distance, in squares.
Definition: map.h:381
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:338
uint32_t do_los
If true, need to call update_los() in draw(), and clear.
Definition: player.h:126
void move_player_attack(object *op, int dir)
The player is also actually going to try and move (not fire weapons).
Definition: player.c:2690
uint32_t mode
Mode of player for pickup.
Definition: player.h:110
struct Settings settings
Server settings.
Definition: init.c:40
uint32_t monitor_spells
Client wishes to be informed when their spell list changes.
Definition: newserver.h:122
void object_set_enemy(object *op, object *enemy)
Sets the enemy of an object.
Definition: object.c:679
void object_free2(object *ob, int flags)
Frees everything allocated by an object, removes it from the list of used objects, and puts it on the list of free objects.
Definition: object.c:1391
Generated items have the FLAG_STARTEQUIP.
Definition: treasure.h:33
#define ADD_PLAYER_NO_MAP
Do not set the first map.
Definition: player.h:223
struct archt * next
Next archetype in a linked list.
Definition: object.h:467
int direction
General direction to the targer.
Definition: map.h:384
rangetype
What range is currently selected by the player.
Definition: player.h:15
#define FLAG_NO_STRENGTH
Strength-bonus not added to wc/dam.
Definition: define.h:307
#define FLAG_APPLIED
Object is ready for use by living.
Definition: define.h:235
#define NROFATTACKS
Definition: attack.h:17
void query_short_name(const object *op, char *buf, size_t size)
query_short_name(object) is similar to query_name(), but doesn&#39;t contain any information about object...
Definition: item.c:547
#define PU_SPELLBOOK
Definition: define.h:135
int out_of_map(mapstruct *m, int x, int y)
this returns TRUE if the coordinates (x,y) are out of map m.
Definition: map.c:2294
int execute_event(object *op, int eventcode, object *activator, object *third, const char *message, int fix)
Definition: main.c:364
#define FLAG_LIFESAVE
Saves a players&#39; life once, then destr.
Definition: define.h:306
void remove_unpaid_objects(object *op, object *env, int free_items)
This goes throws the inventory and removes unpaid objects, and puts them back in the map (location an...
Definition: player.c:3233
signed int int32_t
Definition: win32.h:159
void delete_map(mapstruct *m)
Frees the map, including the mapstruct.
Definition: map.c:1741
int64_t last_skill_exp[NUM_SKILLS]
Last exp sent to client.
Definition: player.h:138
#define ST_CHANGE_CLASS
New character, choosing class.
Definition: define.h:580
#define MSG_TYPE_APPLY_SUCCESS
Was able to apply object.
Definition: newclient.h:598
const char * msg
If this is a book/sign/magic mouth/etc.
Definition: object.h:322
EXTERN char first_map_path[MAX_BUF]
The start-level.
Definition: global.h:153
#define FLAG_MAKE_INVIS
(Item) gives invisibility when applied
Definition: define.h:329
int object_matches_string(object *pl, object *op, const char *name)
This is a subset of the parse_id command.
Definition: object.c:4453
void apply_death_exp_penalty(object *op)
Applies a death penalty experience, the size of this is defined by the settings death_penalty_percent...
Definition: living.c:2144
#define FOR_OB_AND_BELOW_PREPARE(op_)
Constructs a loop iterating over an object and all objects below it in the same pile.
Definition: define.h:785
#define FLAG_STARTEQUIP
Object was given to player at start.
Definition: define.h:268
#define FORCE_NAME
Definition: spells.h:169
#define PU_VALUABLES
Definition: define.h:117
Bow.
Definition: player.h:18
int16_t gen_sp_armour
Penalty to sp regen from armour.
Definition: player.h:115
#define PU_MAGICAL
Definition: define.h:132
sstring add_string(const char *str)
This will add &#39;str&#39; to the hash table.
Definition: shstr.c:124
EXTERN player * first_player
First player.
Definition: global.h:117
void link_player_skills(object *op)
This function goes through the player inventory and sets up the last_skills[] array in the player obj...
Definition: skill_util.c:112
#define FIND_PLAYER_NO_HIDDEN_DM
Don&#39;t find hidden DMs.
Definition: player.h:213
struct pl * next
Pointer to next player, NULL if this is last.
Definition: player.h:93
#define GET_MAP_OB(M, X, Y)
Gets the bottom object on a map.
Definition: map.h:172
player * find_player(const char *plname)
Find a player by her full name.
Definition: player.c:54
void confirm_password(object *op)
Ask the player to confirm her password during creation.
Definition: player.c:980
#define PU_JEWELS
Definition: define.h:141
#define FLAG_MONSTER
Will attack players.
Definition: define.h:245
Will unapply objects when there no choice to unapply.
Definition: player.h:63
void object_copy(const object *src_ob, object *dest_ob)
Copy object first frees everything allocated by the second object, and then copies the contents of th...
Definition: object.c:838
#define EVENT_PLAYER_DEATH
Global Death event.
Definition: plugin.h:86
#define MSG_TYPE_SKILL
Messages related to skill use.
Definition: newclient.h:383
int8_t Pow
Definition: living.h:35
int get_map_flags(mapstruct *oldmap, mapstruct **newmap, int16_t x, int16_t y, int16_t *nx, int16_t *ny)
This rolls up wall, blocks_magic, blocks_view, etc, all into one function that just returns a P_...
Definition: map.c:302
struct obj * inv
Pointer to the first object in the inventory.
Definition: object.h:290
uint8_t set_title
Players can set thier title.
Definition: global.h:263
petmode_t petmode
Which petmode?
Definition: player.h:102
#define NDI_UNIQUE
Print immediately, don&#39;t buffer.
Definition: newclient.h:245
void apply_anim_suffix(object *who, sstring suffix)
Applies a compound animation to an object.
Definition: anim.c:318
char maplevel[MAX_BUF]
On which level is the player?
Definition: player.h:96
See Gloves.
Definition: object.h:213
int apply_race_and_class(object *op, archetype *race, archetype *opclass, living *stats)
This is somewhat like key_change_class() above, except we know the race to change to...
Definition: player.c:1450
#define FLAG_READY_BOW
not implemented yet
Definition: define.h:300
#define MSG_SUBTYPE_NONE
Definition: newclient.h:398
Spells.
Definition: player.h:19
usekeytype usekeys
Method for finding keys for doors.
Definition: player.h:107
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.c:51
#define CS_QUERY_HIDEINPUT
Hide input being entered.
Definition: newclient.h:68
static int action_makes_visible(object *op)
We call this when there is a possibility for our action disturbing our hiding place or invisibility s...
Definition: player.c:4197
#define PU_GLOVES
Definition: define.h:126
int did_make_save(const object *op, int level, int bonus)
This function takes an object (monster/player, op), and determines if it makes a basic save throw by ...
Definition: living.c:2193
#define FLAG_WAS_WIZ
Player was once a wiz.
Definition: define.h:234
int transfer_ob(object *op, int x, int y, int randomly, object *originator)
Move an object (even linked objects) to another spot on the same map.
Definition: move.c:144
void player_unready_range_ob(player *pl, object *ob)
Unready an object for a player.
Definition: player.c:4451
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Constructs a loop iterating over all objects of a map tile.
Definition: define.h:758
void roll_stats(object *op)
Roll the initial player&#39;s statistics.
Definition: player.c:1038
void play_sound_map(int8_t sound_type, object *emitter, int dir, const char *action)
Plays a sound on a map.
Definition: sounds.c:101
uint8_t run_away
Monster runs away if it&#39;s hp goes below this percentage.
Definition: object.h:384
#define IS_ARMOR(op)
Definition: define.h:165
object * last_skill_ob[NUM_SKILLS]
Exp objects sent to client.
Definition: player.h:137
Structure containing object statistics.
void key_change_class(object *op, char key)
This function takes the key that is passed, and does the appropriate action with it (change race...
Definition: player.c:1260
#define MSG_TYPE_ATTACK_NOKEY
Keys are like attacks, so...
Definition: newclient.h:612
struct mapdef * next
Next map, linked list.
Definition: map.h:326
#define P_BLOCKSVIEW
This spot blocks the player&#39;s view.
Definition: map.h:226
void object_set_msg(object *op, const char *msg)
Set the message field of an object.
Definition: object.c:4695
static void update_transport_block(object *transport, int dir)
Update the move_type of a transport based on the direction.
Definition: player.c:2872
#define MSG_TYPE_ATTRIBUTE_RACE
Race-related changes.
Definition: newclient.h:557
#define ATNR_COLD
Definition: attack.h:53
void query_name(const object *op, char *buf, size_t size)
Describes an item.
Definition: item.c:625
#define PU_ARMOUR
Definition: define.h:123
Only use keys in inventory.
Definition: player.h:53
void apply_map_builder(object *pl, int dir)
Global building function.
Definition: build_map.c:959
#define FOR_BELOW_PREPARE(op_, it_)
Constructs a loop iterating over all objects below an object.
Definition: define.h:739
void remove_statbonus(object *op)
Subtracts stat-bonuses given by the class which the player has chosen.
Definition: living.c:840
Contains the base information we use to make up a packet we want to send.
Definition: newclient.h:680
char * emergency_mapname
Map to return players to in emergency.
Definition: global.h:297
This is a game-map.
Definition: map.h:325
#define P_IS_ALIVE
Something alive is on this space.
Definition: map.h:237
int random_roll(int min, int max, const object *op, int goodbad)
Roll a random number between min and max.
Definition: utils.c:42
#define ST_GET_NAME
Player just connected.
Definition: define.h:582
uint8_t roll_stat_points
How many stat points legacy (rolled) chars start with.
Definition: global.h:321
const New_Face * face
Face with colors.
Definition: object.h:332
char write_buf[MAX_BUF]
Holds arbitrary input from client.
Definition: player.h:174
See Jewel.
Definition: object.h:167
#define FLAG_UNIQUE
Item is really unique (UNIQUE_ITEMS)
Definition: define.h:288
#define FLAG_NO_PICK
Object can&#39;t be picked up.
Definition: define.h:239
static object * find_better_arrow(object *op, object *target, const char *type, int *better)
Similar to find_arrow(), but looks for (roughly) the best arrow to use against the target...
Definition: player.c:2034
int8_t levgrace[11]
What grace bonus the player gained on that level.
Definition: player.h:169
#define PU_POTION
Definition: define.h:133
int get_rangevector(object *op1, const object *op2, rv_vector *retval, int flags)
From map.c This is used by get_player to determine where the other creature is.
Definition: map.c:2527
const char * unarmed_skill
Prefered skill to use in unarmed combat.
Definition: player.h:202
See Breastplate Armor.
Definition: object.h:120
const char *const short_stat_name[NUM_STATS]
Short name of stats.
Definition: living.c:194
void enter_player_savebed(object *op)
This is a basic little function to put the player back to his savebed.
Definition: server.c:118
uint8_t mapy
How large a map the client wants.
Definition: newserver.h:128
partylist * party_to_join
Used when player wants to join a party but we will have to get password first so we have to remember ...
Definition: player.h:187
int get_dex_bonus(int stat)
Definition: living.c:2265
#define PU_HELMET
Definition: define.h:121
int16_t level
Level of creature or object.
Definition: object.h:351
int8_t facing
Object is oriented/facing that way.
Definition: object.h:335
#define FLAG_INV_LOCKED
Item will not be dropped from inventory.
Definition: define.h:330
void fix_object(object *op)
Updates all abilities given by applied objects in the inventory of the given object.
Definition: living.c:1118
#define BALSL_MAX_LOSS_RATIO
Definition: config.h:144
EXTERN mapstruct * first_map
First map.
Definition: global.h:118
void cast_dust(object *op, object *throw_ob, int dir)
Handles op throwing objects of type &#39;DUST&#39;.
Definition: player.c:3924
#define AT_DEATH
Definition: attack.h:93
#define PU_NOT_CURSED
Definition: define.h:140
EXTERN archetype * first_archetype
First archetype.
Definition: global.h:122
struct obj * more
Pointer to the rest of a large body of objects.
Definition: object.h:295
object * find_skill_by_name(object *who, const char *name)
This returns the skill pointer of the given name (the one that accumulates exp, has the level...
Definition: skill_util.c:213
object * arch_to_object(archetype *at)
Creates and returns a new object which is a copy of the given archetype.
Definition: arch.c:571
void object_update_speed(object *op)
Updates the speed of an object.
Definition: object.c:1129
int32_t value
How much money it is worth (or contains)
Definition: object.h:350
object * object_get_owner(object *op)
Returns the object which this object marks as being the owner.
Definition: object.c:559
int8_t magic
Any magical bonuses to this item.
Definition: object.h:348
uint8_t * faces_sent
This is a bitmap on sent face status.
Definition: newserver.h:106
static object * find_arrow(object *op, const char *type)
Find an arrow in the inventory and after that in the right type container (quiver).
Definition: player.c:2002
const char * name
More definite name, like "generate_kobold".
Definition: object.h:466
#define EVENT_BORN
A new character has been created.
Definition: plugin.h:83
#define FOR_BELOW_FINISH()
Finishes FOR_BELOW_PREPARE().
Definition: define.h:746
object * object_find_by_arch_name(const object *who, const char *name)
Find object in inventory by archetype name.
Definition: object.c:4143
uint8_t resurrection
Ressurection possible w/ permadeth on.
Definition: global.h:264
#define FOR_INV_PREPARE(op_, it_)
Constructs a loop iterating over the inventory of an object.
Definition: define.h:705
int cast_spell(object *op, object *caster, int dir, object *spell_ob, char *stringarg)
Main dispatch when someone casts a spell.
Definition: spell_util.c:1471
SockList inbuf
If we get an incomplete packet, this is used to hold the data.
Definition: newserver.h:109
void object_remove(object *op)
This function removes the object op from the linked list of objects which it is currently tied to...
Definition: object.c:1654
#define MSG_TYPE_MOTD
Definition: newclient.h:376
int hideability(object *ob)
Look at the surrounding terrain to determine the hideability of this object.
Definition: player.c:3996
#define PU_MAGIC_DEVICE
Definition: define.h:138
#define ST_GET_PASSWORD
Name entered, now for password.
Definition: define.h:583
int32_t food
How much food in stomach.
Definition: living.h:47
#define FLAG_FREED
Object is in the list of free objects.
Definition: define.h:233
void key_confirm_quit(object *op, char key)
We receive the reply to the &#39;quit confirmation&#39; message.
Definition: player.c:1562
void Send_With_Handling(socket_struct *ns, SockList *sl)
Calls Write_To_Socket to send data to the client.
Definition: lowlevel.c:542
Definition: object.h:224
#define ATNR_FIRE
Definition: attack.h:51
int get_thaco_bonus(int stat)
Definition: living.c:2269
void check_stat_bounds(living *st