Crossfire Server  1.75.0
player.cpp
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2014 Mark Wedel and the Crossfire Development Team
5  * Copyright (c) 1992 Frank Tore Johansen
6  *
7  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
8  * welcome to redistribute it under certain conditions. For details, please
9  * see COPYING and LICENSE.
10  *
11  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
12  */
13 
20 #include "global.h"
21 
22 #include <assert.h>
23 #include <ctype.h>
24 #include <math.h>
25 #include <stddef.h>
26 #include <stdlib.h>
27 #include <string.h>
28 
29 #ifndef WIN32 /* ---win32 remove headers */
30 #include <pwd.h>
31 #endif
32 
33 #include "server.h"
34 #include "living.h"
35 #include "object.h"
36 #include "shared/newclient.h"
37 #include "shop.h"
38 #include "skills.h"
39 #include "sounds.h"
40 #include "spells.h"
41 #include "sproto.h"
42 #include "assets.h"
43 #include "AssetsManager.h"
44 
46 
47 static void kill_player_not_permadeath(object *op);
48 static void kill_player_permadeath(object *op);
49 static int action_makes_visible(object *op);
50 
59 player *find_player(const char *plname) {
60  return find_player_options(plname, 0, NULL);
61 }
62 
70 player *find_player_options(const char *plname, int options, const mapstruct *map) {
71  player *pl;
72  player *found = NULL;
73  size_t namelen = strlen(plname);
74  char name[MAX_BUF];
75 
76  for (pl = first_player; pl != NULL; pl = pl->next) {
77  if ((options & FIND_PLAYER_NO_HIDDEN_DM) && (QUERY_FLAG(pl->ob, FLAG_WIZ) && pl->ob->contr->hidden))
78  continue;
79 
80  if (map != NULL && pl->ob->map != map)
81  continue;
82 
83  if (!(options & FIND_PLAYER_PARTIAL_NAME)) {
84  query_name(pl->ob, name, sizeof(name));
85  if (!strcmp(name, plname))
86  return pl;
87  continue;
88  }
89 
90  if (strlen(pl->ob->name) < namelen)
91  continue;
92 
93  if (!strcmp(pl->ob->name, plname))
94  return pl;
95 
96  if (!strncasecmp(pl->ob->name, plname, namelen)) {
97  if (found)
98  return NULL;
99 
100  found = pl;
101  }
102  }
103  return found;
104 }
105 
114 player *find_player_partial_name(const char *plname) {
115  return find_player_options(plname, FIND_PLAYER_PARTIAL_NAME, NULL);
116 }
117 
124  player *pl;
125 
126  for (pl = first_player; pl != NULL; pl = pl->next) {
127  if (pl->socket == ns)
128  return pl;
129  }
130  return NULL;
131 }
132 
139 void display_motd(const object *op) {
140  char buf[MAX_BUF];
141  char motd[HUGE_BUF];
142  FILE *fp;
143  size_t size;
144 
145  snprintf(buf, sizeof(buf), "%s/%s", settings.confdir, settings.motd);
146  fp = fopen(buf, "r");
147  if (fp == NULL) {
148  return;
149  }
150  motd[0] = '\0';
151  size = 0;
152 
153  while (fgets(buf, MAX_BUF, fp) != NULL) {
154  if (*buf != '#') {
155  safe_strcat(motd, buf, &size, sizeof(motd));
156  }
157  }
158 
160  motd);
161  fclose(fp);
162 }
163 
170 void send_rules(const object *op) {
171  char buf[MAX_BUF];
172  char rules[HUGE_BUF];
173  FILE *fp;
174  size_t size;
175 
176  snprintf(buf, sizeof(buf), "%s/%s", settings.confdir, settings.rules);
177  fp = fopen(buf, "r");
178  if (fp == NULL) {
179  return;
180  }
181  rules[0] = '\0';
182  size = 0;
183 
184  while (fgets(buf, MAX_BUF, fp) != NULL) {
185  if (size+strlen(buf) >= HUGE_BUF) {
186  LOG(llevDebug, "Warning, rules size is > %d bytes.\n", HUGE_BUF);
187  break;
188  }
189 
190  if (*buf != '#') {
191  safe_strcat(rules, buf, &size, sizeof(rules));
192  }
193  }
194 
196  MSG_TYPE_ADMIN_RULES, rules);
197  fclose(fp);
198 }
199 
206 void send_news(const object *op) {
207  char buf[MAX_BUF];
208  char news[HUGE_BUF];
209  char subject[MAX_BUF];
210  FILE *fp;
211  size_t size;
212 
213  snprintf(buf, sizeof(buf), "%s/%s", settings.confdir, settings.news);
214  fp = fopen(buf, "r");
215  if (fp == NULL)
216  return;
217  news[0] = '\0';
218  subject[0] = '\0';
219  size = 0;
220  while (fgets(buf, MAX_BUF, fp) != NULL) {
221  if (*buf == '#')
222  continue;
223  if (*buf == '%') { /* send one news */
224  if (size > 0)
227  "%s:\n%s",
228  subject, news); /*send previously read news*/
229  safe_strncpy(subject, buf + 1, sizeof(subject));
230  strip_endline(subject);
231  size = 0;
232  news[0] = '\0';
233  } else {
234  if (size+strlen(buf) >= HUGE_BUF) {
235  LOG(llevDebug, "Warning, one news item has size > %d bytes.\n", HUGE_BUF);
236  break;
237  }
238  safe_strcat(news, buf, &size, sizeof(news));
239  }
240  }
241 
244  "%s:\n%s",
245  subject, news);
246  fclose(fp);
247 }
248 
257 int playername_ok(const char *cp) {
258  /* Don't allow - or _ as first character in the name */
259  if (*cp == '-' || *cp == '_')
260  return 0;
261 
262  for (; *cp != '\0'; cp++)
263  if (!isalnum(*cp)
264  && *cp != '-'
265  && *cp != '_')
266  return 0;
267  return 1;
268 }
269 
286  object *op = arch_to_object(get_player_archetype(NULL));
287  int i;
288 
289  if (!p) {
290  player *tmp;
291 
292  p = (player *)calloc(1, sizeof(player));
293  if (p == NULL)
295 
296  /* This adds the player in the linked list. There is extra
297  * complexity here because we want to add the new player at the
298  * end of the list - there is in fact no compelling reason that
299  * that needs to be done except for things like output of
300  * 'who'.
301  */
302  tmp = first_player;
303  while (tmp != NULL && tmp->next != NULL)
304  tmp = tmp->next;
305  if (tmp != NULL)
306  tmp->next = p;
307  else
308  first_player = p;
309  } else {
310  /* Only needed when reusing existing player. */
311  clear_player(p);
312  }
313 
314  /* Clears basically the entire player structure except
315  * for next and socket.
316  */
317  memset((void *)((char *)p+offsetof(player, maplevel)), 0, sizeof(player)-offsetof(player, maplevel));
318 
319  /* There are some elements we want initialized to non zero value -
320  * we deal with that below this point.
321  */
322  p->party = NULL;
325  p->swap_first = -1;
326 
327 #ifdef AUTOSAVE
328  p->last_save_tick = 9999999;
329 #endif
330 
331  strcpy(p->savebed_map, first_map_path); /* Init. respawn position */
332 
333  op->contr = p; /* this aren't yet in archetype */
334  p->ob = op;
335  op->speed_left = 0.5;
336  op->speed = 1.0;
337  op->direction = 5; /* So player faces south */
338  op->stats.wc = 2;
339  op->run_away = 25; /* Then we panic... */
340 
341  roll_stats(op);
343  clear_los(p);
344 
345  p->gen_sp_armour = 10;
346  p->last_speed = -1;
347  p->shoottype = range_none;
348  p->bowtype = bow_normal;
349  p->petmode = pet_normal;
350  p->listening = 10;
351  p->last_weapon_sp = -1;
352  p->peaceful = 1; /* default peaceful */
353  p->do_los = 1;
354  p->no_shout = 0; /* default can shout */
355  p->language = i18n_get_language_by_code(""); // find default language
356  p->unarmed_skill = NULL;
357  p->ticks_played = 0;
358 
359  strncpy(p->title, op->arch->clone.name, sizeof(p->title)-1);
360  p->title[sizeof(p->title)-1] = '\0';
361  op->race = add_string(op->arch->clone.race);
362 
364 
365  /* All the last_* values have been set to 0 via the memset
366  * above, however if the associated value could be 0 then
367  * we need to clear these to -1 and not zero - otherwise,
368  * if a player quits and starts a new character, we wont
369  * send new values to the client, as things like exp start
370  * at zero.
371  */
372  for (i = 0; i < MAX_SKILLS; i++) {
373  p->last_skill_exp[i] = -1;
374  p->last_skill_ob[i] = NULL;
375  }
376  for (i = 0; i < NROFATTACKS; i++) {
377  p->last_resist[i] = -1;
378  }
379  p->last_stats.exp = -1;
380  p->last_weight = (uint32_t)-1;
384  = p->last_applied_stats.Cha = -1;
385  p->last_character_load = -1.0f;
386  p->last_weight_limit = (uint32_t)-1;
387  p->last_path_attuned = (uint32_t)-1;
388  p->last_path_repelled = (uint32_t)-1;
389  p->last_path_denied = (uint32_t)-1;
390  p->last_character_flags = (uint32_t)-1;
391  p->last_item_power = (uint16_t)-1;
392 
393  return p;
394 }
395 
402 void set_first_map(object *op) {
403  strcpy(op->contr->maplevel, first_map_path);
404  op->x = -1;
405  op->y = -1;
407 }
408 
422  if (p->socket && p->socket->account_chars) {
424  }
425 
426  p->socket = static_cast<socket_struct *>(malloc(sizeof(socket_struct)));
427  if (!p->socket) {
429  }
430  memcpy(p->socket, ns, sizeof(socket_struct));
431 
432  /* The memcpy above copies the reference to faces sent. So we need to clear
433  * that pointer in ns, otherwise we get a double free.
434  */
435  ns->faces_sent = NULL;
436  ns->host = strdup_local("");
437  ns->account_name = strdup_local("");
438  ns->account_chars = NULL; // If not NULL, the reference is now kept by p
439 
440  if (p->socket->faces_sent == NULL)
442 
443  /* Needed because the socket we just copied over needs to be cleared.
444  * Note that this can result in a client reset if there is partial data
445  * on the incoming socket.
446  */
448 
449 
450 }
451 
469  player *p;
470 
471  p = get_player(NULL);
472  set_player_socket(p, ns);
473  ns->status = Ns_Avail;
474 
476 
477  if (!(flags & ADD_PLAYER_NO_MAP))
478  set_first_map(p->ob);
479 
481 
482  /* In this case, the client is provide all the informatin for the
483  * new character, so just return it. Do not display any messages,
484  * etc
485  */
486  if (flags & ADD_PLAYER_NO_STATS_ROLL)
487  return p;
488 
489  if (flags & ADD_PLAYER_NEW) {
490  roll_again(p->ob);
492  } else {
493  send_rules(p->ob);
494  send_news(p->ob);
495  display_motd(p->ob);
496  get_name(p->ob);
497  }
498  return p;
499 }
500 
501 std::vector<archetype *> players;
502 
514  if (players.empty()) {
515  getManager()->archetypes()->each([] (const auto &at) {
516  if (at->clone.type == PLAYER) {
517  players.push_back(at);
518  }
519  });
520  if (players.empty()) {
521  LOG(llevError, "No Player archetypes\n");
523  }
524  }
525 
526  if (!at) {
527  return players.front();
528  }
529  auto pos = std::find(players.cbegin(), players.cend(), at);
530  if (pos == players.cend()) {
531  return nullptr;
532  }
533  ++pos;
534  if (pos == players.cend()) {
535  return players.front();
536  }
537  return *pos;
538 }
539 
548 object *get_nearest_player(object *mon) {
549  object *op = NULL;
550  player *pl = NULL;
551  objectlink *list, *ol;
552  unsigned lastdist;
553  rv_vector rv;
554 
555  list = get_friends_of(NULL);
556 
557  for (ol = list, lastdist = 1000; ol != NULL; ol = ol->next) {
558  if (QUERY_FLAG(ol->ob, FLAG_FREED) || !QUERY_FLAG(ol->ob, FLAG_FRIENDLY)) {
559  continue;
560  }
561 
562  /* Remove special check for player from this. First, it looks to cause
563  * some crashes (ol->ob->contr not set properly?), but secondly, a more
564  * complicated method of state checking would be needed in any case -
565  * as it was, a clever player could type quit, and the function would
566  * skip them over while waiting for confirmation. Remove
567  * on_same_map check, as monster_can_detect_enemy() also does this
568  */
569  if (!monster_can_detect_enemy(mon, ol->ob, &rv))
570  continue;
571 
572  if (lastdist > rv.distance) {
573  op = ol->ob;
574  lastdist = rv.distance;
575  }
576  }
577  if (list) {
578  free_objectlink(list);
579  }
580  for (pl = first_player; pl != NULL; pl = pl->next) {
581  if (monster_can_detect_enemy(mon, pl->ob, &rv)) {
582  if (lastdist > rv.distance) {
583  op = pl->ob;
584  lastdist = rv.distance;
585  }
586  }
587  }
588  return op;
589 }
590 
591 object *get_nearest_criminal(object *mon) {
592  object *op = NULL;
593  for (player *pl = first_player; pl != NULL; pl = pl->next) {
594  rv_vector rv;
595  if (monster_can_detect_enemy(mon, pl->ob, &rv) && is_criminal(pl->ob)) {
596  op = pl->ob;
597  }
598  }
599  return op;
600 }
601 
611 #define DETOUR_AMOUNT 2
612 
626 #define MAX_SPACES 50
627 
659 int path_to_player(object *mon, object *pl, unsigned mindiff) {
660  rv_vector rv;
661  int16_t x, y;
662  int lastx, lasty, dir, i, diff, firstdir = 0, lastdir, max = MAX_SPACES, mflags, blocked;
663  mapstruct *m, *lastmap;
664 
665  if (!get_rangevector(mon, pl, &rv, 0))
666  return 0;
667 
668  if (rv.distance < mindiff)
669  return 0;
670 
671  x = mon->x;
672  y = mon->y;
673  m = mon->map;
674  dir = rv.direction;
675  lastdir = firstdir = rv.direction; /* perhaps we stand next to pl, init firstdir too */
676  diff = MAX(FABS(rv.distance_x), FABS(rv.distance_y));
677  /* If we can't solve it within the search distance, return now. */
678  if (diff > max)
679  return 0;
680  while (diff > 1 && max > 0) {
681  lastx = x;
682  lasty = y;
683  lastmap = m;
684  x = lastx+freearr_x[dir];
685  y = lasty+freearr_y[dir];
686 
687  mflags = get_map_flags(m, &m, x, y, &x, &y);
688  blocked = (mflags&P_OUT_OF_MAP) ? MOVE_ALL : GET_MAP_MOVE_BLOCK(m, x, y);
689 
690  /* Space is blocked - try changing direction a little */
691  if ((mflags&P_OUT_OF_MAP)
692  || ((OB_TYPE_MOVE_BLOCK(mon, blocked) || (mflags&P_IS_ALIVE))
693  && (m == mon->map && blocked_link(mon, m, x, y)))) {
694  /* recalculate direction from last good location. Possible
695  * we were not traversing ideal location before.
696  */
697  if (get_rangevector_from_mapcoord(lastmap, lastx, lasty, pl, &rv) && rv.direction != dir) {
698  /* OK - says direction should be different - lets reset the
699  * the values so it will try again.
700  */
701  x = lastx;
702  y = lasty;
703  m = lastmap;
704  dir = firstdir = rv.direction;
705  } else {
706  /* direct path is blocked - try taking a side step to
707  * either the left or right.
708  * Note increase the values in the loop below to be
709  * more than -1/1 respectively will mean the monster takes
710  * bigger detour. Have to be careful about these values getting
711  * too big (3 or maybe 4 or higher) as the monster may just try
712  * stepping back and forth
713  */
714  for (i = -DETOUR_AMOUNT; i <= DETOUR_AMOUNT; i++) {
715  if (i == 0)
716  continue; /* already did this, so skip it */
717  /* Use lastdir here - otherwise,
718  * since the direction that the creature should move in
719  * may change, you could get infinite loops.
720  * ie, player is northwest, but monster can only
721  * move west, so it does that. It goes some distance,
722  * gets blocked, finds that it should move north,
723  * can't do that, but now finds it can move east, and
724  * gets back to its original point. lastdir contains
725  * the last direction the creature has successfully
726  * moved.
727  */
728 
729  x = lastx+freearr_x[absdir(lastdir+i)];
730  y = lasty+freearr_y[absdir(lastdir+i)];
731  m = lastmap;
732  mflags = get_map_flags(m, &m, x, y, &x, &y);
733  if (mflags&P_OUT_OF_MAP)
734  continue;
735  blocked = GET_MAP_MOVE_BLOCK(m, x, y);
736  if (OB_TYPE_MOVE_BLOCK(mon, blocked))
737  continue;
738  if (mflags&P_IS_ALIVE)
739  continue;
740 
741  if (m == mon->map && blocked_link(mon, m, x, y))
742  break;
743  }
744  /* go through entire loop without finding a valid
745  * sidestep to take - thus, no valid path.
746  */
747  if (i == (DETOUR_AMOUNT+1))
748  return 0;
749  diff--;
750  lastdir = dir;
751  max--;
752  if (!firstdir)
753  firstdir = dir+i;
754  } /* else check alternate directions */
755  } /* if blocked */
756  else {
757  /* we moved towards creature, so diff is less */
758  diff--;
759  max--;
760  lastdir = dir;
761  if (!firstdir)
762  firstdir = dir;
763  }
764  if (diff <= 1) {
765  /* Recalculate diff (distance) because we may not have actually
766  * headed toward player for entire distance.
767  */
768  if (!get_rangevector_from_mapcoord(m, x, y, pl, &rv))
769  return 0;
770  diff = MAX(FABS(rv.distance_x), FABS(rv.distance_y));
771  }
772  if (diff > max)
773  return 0;
774  }
775  /* If we reached the max, didn't find a direction in time */
776  if (!max)
777  return 0;
778 
779  return firstdir;
780 }
781 
792 void give_initial_items(object *pl, treasurelist *items) {
793  if (pl->randomitems != NULL)
794  create_treasure(items, pl, GT_STARTEQUIP|GT_ONLY_GOOD, 1, 0);
795 
796  FOR_INV_PREPARE(pl, op) {
797  /* Forces get applied per default, unless they have the
798  * flag "neutral" set. Sorry but I can't think of a better way
799  */
800  if (op->type == FORCE && !QUERY_FLAG(op, FLAG_NEUTRAL))
801  SET_FLAG(op, FLAG_APPLIED);
802 
803  /* we never give weapons/armour if these cannot be used
804  * by this player due to race restrictions
805  */
806  if (pl->type == PLAYER) {
807  if ((!QUERY_FLAG(pl, FLAG_USE_ARMOUR) && IS_ARMOR(op))
808  || (!QUERY_FLAG(pl, FLAG_USE_WEAPON) && IS_WEAPON(op))
809  || (!QUERY_FLAG(pl, FLAG_USE_SHIELD) && IS_SHIELD(op))) {
810  object_remove(op);
812  continue;
813  }
814  }
815 
816  /* This really needs to be better - we should really give
817  * a substitute spellbook. The problem is that we don't really
818  * have a good idea what to replace it with (need something like
819  * a first level treasurelist for each skill.)
820  * remove duplicate skills also
821  */
822  if (op->type == SPELLBOOK || op->type == SKILL) {
823  int found;
824 
825  found = 0;
826  // Make sure we set flags that are checked by object_can_merge
827  // *before* we run object_can_merge. Otherwise, we can get two
828  // entries of the same skill.
829  if (op->type == SKILL) {
831  op->stats.exp = 0;
832  op->level = 1;
833  // Since this also happens to the invisible skills, we need this so that the flags match.
835  }
836  FOR_BELOW_PREPARE(op, tmp)
837  if (object_can_merge(op, tmp)) {
838  found = 1;
839  break;
840  }
842  if (found) {
843  LOG(llevError, "give_initial_items: Removing duplicate object %s\n", op->name);
844  object_remove(op);
846  continue;
847  }
848  if (op->nrof > 1)
849  op->nrof = 1;
850  }
851 
852  if (op->type == SPELLBOOK && op->inv) {
853  CLEAR_FLAG(op->inv, FLAG_STARTEQUIP);
854  }
855 
856  /* Give starting characters identified, uncursed, and undamned
857  * items. Just don't identify gold or silver, or it won't be
858  * merged properly.
859  */
860  if (is_identifiable_type(op)) {
862  CLEAR_FLAG(op, FLAG_CURSED);
863  CLEAR_FLAG(op, FLAG_DAMNED);
864  }
865  } FOR_INV_FINISH(); /* for loop of objects in player inv */
866 
867  /* Need to set up the skill pointers */
868  link_player_skills(pl);
869 
874  FOR_INV_PREPARE(pl, op)
875  if ((IS_ARMOR(op) || IS_WEAPON(op) || IS_SHIELD(op)) && !QUERY_FLAG(op, FLAG_APPLIED))
876  apply_manual(pl, op, AP_NOPRINT);
877  FOR_INV_FINISH();
878 }
879 
886 void get_name(object *op) {
888  send_query(op->contr->socket, 0, i18n(op, "What is your name?\n:"));
889 }
890 
897 void get_password(object *op) {
899  send_query(op->contr->socket, CS_QUERY_HIDEINPUT, i18n(op, "What is your password?\n:"));
900 }
901 
908 void play_again(object *op) {
909  SockList sl;
910 
911  op->contr->socket->status = Ns_Add;
913  op->chosen_skill = NULL;
914 
915  /*
916  * For old clients, ask if they want to play again.
917  * For clients with account support, just return to character seletion (see below).
918  */
919  if (op->contr->socket->login_method == 0) {
920  send_query(op->contr->socket, CS_QUERY_SINGLECHAR, i18n(op, "Do you want to play again (a/q)?"));
921  }
922  /* a bit of a hack, but there are various places early in th
923  * player creation process that a user can quit (eg, roll
924  * stats) that isn't removing the player. Taking a quick
925  * look, there are many places that call play_again without
926  * removing the player - it probably makes more sense
927  * to leave it to play_again to remove the object in all
928  * cases.
929  */
930  if (!QUERY_FLAG(op, FLAG_REMOVED))
931  object_remove(op);
932  /* Need to set this to null - otherwise, it could point to garbage,
933  * and draw() doesn't check to see if the player is removed, only if
934  * the map is null or not swapped out.
935  */
936  op->map = NULL;
937 
938  SockList_Init(&sl);
939  SockList_AddString(&sl, "player ");
940  SockList_AddInt(&sl, 0);
941  SockList_AddInt(&sl, 0);
942  SockList_AddInt(&sl, 0);
943  SockList_AddChar(&sl, 0);
944 
945  Send_With_Handling(op->contr->socket, &sl);
946  SockList_Term(&sl);
947 
948  if (op->contr->socket->login_method > 0) {
949  receive_play_again(op, 'a');
950  }
951 }
952 
961 void receive_play_again(object *op, char key) {
962  if (key == 'q' || key == 'Q') {
964  leave(op->contr, 0); /* ericserver will draw the message */
965  return;
966  } else if (key == 'a' || key == 'A') {
967  player *pl = op->contr;
968  const char *name = op->name;
969 
970  add_refcount(name);
973  pl = get_player(pl);
974  op = pl->ob;
976  op->contr->password[0] = '~';
979  if (pl->socket->login_method >= 1 && pl->socket->account_name != NULL) {
980  /* If we are using new login, we send the
981  * list of characters to the client - this should
982  * result in the client popping up this list so
983  * the player can choose which one to play - better
984  * than going to legacy login code.
985  * If the account_name is NULL, it means the client
986  * says it uses account but started playing without logging in.
987  */
990  } else {
991  /* Lets put a space in here */
993  "\n");
994  get_name(op);
995  set_first_map(op);
996  }
997  op->name = name; /* Already added a refcount above */
998  op->name_pl = add_string(name);
999  } else {
1000  /* user pressed something else so just ask again... */
1001  play_again(op);
1002  }
1003 }
1004 
1011 void confirm_password(object *op) {
1013  send_query(op->contr->socket, CS_QUERY_HIDEINPUT, i18n(op, "Please type your password again.\n:"));
1014 }
1015 
1026 int get_party_password(object *op, partylist *party) {
1027  if (*party_get_password(party) == '\0') {
1028  return 0;
1029  }
1030 
1032  op->contr->party_to_join = party;
1033  send_query(op->contr->socket, CS_QUERY_HIDEINPUT, i18n(op, "What is the password?\n:"));
1034  return 1;
1035 }
1036 
1043 int roll_stat(void) {
1044  int roll[4], i, low_index, k;
1045 
1046  for (i = 0; i < 4; ++i)
1047  roll[i] = (int)RANDOM()%6+1;
1048 
1049  for (i = 0, low_index = 0, k = 7; i < 4; ++i)
1050  if (roll[i] < k)
1051  k = roll[i],
1052  low_index = i;
1053 
1054  for (i = 0, k = 0; i < 4; ++i) {
1055  if (i != low_index)
1056  k += roll[i];
1057  }
1058  return k;
1059 }
1060 
1067 void roll_stats(object *op) {
1068  int i = 0, j = 0;
1069  int statsort[7];
1070 
1071  op->stats.Str = roll_stat();
1072  op->stats.Dex = roll_stat();
1073  op->stats.Int = roll_stat();
1074  op->stats.Con = roll_stat();
1075  op->stats.Wis = roll_stat();
1076  op->stats.Pow = roll_stat();
1077  op->stats.Cha = roll_stat();
1078  int sum = op->stats.Str+op->stats.Dex+op->stats.Int+op->stats.Con+op->stats.Wis+op->stats.Pow+op->stats.Cha;
1079  float scale = settings.roll_stat_points / sum;
1080  op->stats.Str = roundf(scale * op->stats.Str);
1081  op->stats.Dex = roundf(scale * op->stats.Dex);
1082  op->stats.Int = roundf(scale * op->stats.Int);
1083  op->stats.Con = roundf(scale * op->stats.Con);
1084  op->stats.Wis = roundf(scale * op->stats.Wis);
1085  op->stats.Pow = roundf(scale * op->stats.Pow);
1086  op->stats.Cha = roundf(scale * op->stats.Cha);
1087 
1088  /* Sort the stats so that rerolling is easier... */
1089  statsort[0] = op->stats.Str;
1090  statsort[1] = op->stats.Dex;
1091  statsort[2] = op->stats.Int;
1092  statsort[3] = op->stats.Con;
1093  statsort[4] = op->stats.Wis;
1094  statsort[5] = op->stats.Pow;
1095  statsort[6] = op->stats.Cha;
1096 
1097  /* a quick and dirty bubblesort? */
1098  do {
1099  if (statsort[i] < statsort[i+1]) {
1100  j = statsort[i];
1101  statsort[i] = statsort[i+1];
1102  statsort[i+1] = j;
1103  i = 0;
1104  } else {
1105  i++;
1106  }
1107  } while (i < 6);
1108 
1109  op->stats.Str = statsort[0];
1110  op->stats.Dex = statsort[1];
1111  op->stats.Con = statsort[2];
1112  op->stats.Int = statsort[3];
1113  op->stats.Wis = statsort[4];
1114  op->stats.Pow = statsort[5];
1115  op->stats.Cha = statsort[6];
1116 
1117  op->contr->orig_stats.Str = op->stats.Str;
1118  op->contr->orig_stats.Dex = op->stats.Dex;
1119  op->contr->orig_stats.Int = op->stats.Int;
1120  op->contr->orig_stats.Con = op->stats.Con;
1121  op->contr->orig_stats.Wis = op->stats.Wis;
1122  op->contr->orig_stats.Pow = op->stats.Pow;
1123  op->contr->orig_stats.Cha = op->stats.Cha;
1124 
1125  op->level = 1;
1126  op->stats.exp = 0;
1127  op->stats.ac = 0;
1128 
1129  op->contr->levhp[1] = 9;
1130  op->contr->levsp[1] = 6;
1131  op->contr->levgrace[1] = 3;
1132 
1133  fix_object(op);
1134  op->stats.hp = op->stats.maxhp;
1135  op->stats.sp = op->stats.maxsp;
1136  op->stats.grace = op->stats.maxgrace;
1137  op->contr->orig_stats = op->stats;
1138 }
1139 
1146 void roll_again(object *op) {
1147  esrv_new_player(op->contr, 0);
1148  send_query(op->contr->socket, CS_QUERY_SINGLECHAR, i18n(op, "<y> to roll new stats <n> to use stats\n<1-7> <1-7> to swap stats.\nRoll again (y/n/1-7)? "));
1149 }
1150 
1160 static void swap_stat(object *op, int swap_second) {
1161  signed char tmp;
1162 
1163  if (op->contr->swap_first == -1) {
1164  LOG(llevError, "player.c:swap_stat() - swap_first is -1\n");
1165  return;
1166  }
1167 
1168  tmp = get_attr_value(&op->contr->orig_stats, op->contr->swap_first);
1169 
1170  set_attr_value(&op->contr->orig_stats, op->contr->swap_first, get_attr_value(&op->contr->orig_stats, swap_second));
1171 
1172  set_attr_value(&op->contr->orig_stats, swap_second, tmp);
1173 
1175  "%s done\n",
1176  short_stat_name[swap_second]);
1177 
1178  op->stats.Str = op->contr->orig_stats.Str;
1179  op->stats.Dex = op->contr->orig_stats.Dex;
1180  op->stats.Con = op->contr->orig_stats.Con;
1181  op->stats.Int = op->contr->orig_stats.Int;
1182  op->stats.Wis = op->contr->orig_stats.Wis;
1183  op->stats.Pow = op->contr->orig_stats.Pow;
1184  op->stats.Cha = op->contr->orig_stats.Cha;
1185  op->stats.ac = 0;
1186 
1187  op->level = 1;
1188  op->stats.exp = 0;
1189  op->stats.ac = 0;
1190 
1191  op->contr->levhp[1] = 9;
1192  op->contr->levsp[1] = 6;
1193  op->contr->levgrace[1] = 3;
1194 
1195  fix_object(op);
1196  op->stats.hp = op->stats.maxhp;
1197  op->stats.sp = op->stats.maxsp;
1198  op->stats.grace = op->stats.maxgrace;
1199  op->contr->orig_stats = op->stats;
1200  op->contr->swap_first = -1;
1201 }
1202 
1218 void key_roll_stat(object *op, char key) {
1219  int keynum = key-'0';
1220  static const int8_t stat_trans[] = {
1221  -1,
1222  STRENGTH,
1223  DEXTERITY,
1224  CONSTITUTION,
1225  INTELLIGENCE,
1226  WISDOM,
1227  POWER,
1228  CHARISMA,
1229  };
1230 
1231  if (keynum > 0 && keynum <= 7) {
1232  if (op->contr->swap_first == -1) {
1233  op->contr->swap_first = stat_trans[keynum];
1235  "%s ->",
1236  short_stat_name[stat_trans[keynum]]);
1237  } else
1238  swap_stat(op, stat_trans[keynum]);
1239 
1241  return;
1242  }
1243  switch (key) {
1244  case 'n':
1245  case 'N': {
1246  SET_FLAG(op, FLAG_WIZ);
1247  if (op->map == NULL) {
1248  LOG(llevError, "Map == NULL in state 2\n");
1249  break;
1250  }
1251 
1252  SET_ANIMATION(op, 2); /* So player faces south */
1253  /* Enter exit adds a player otherwise */
1254  add_statbonus(op);
1255  send_query(op->contr->socket, CS_QUERY_SINGLECHAR, i18n(op, "Now choose a character.\nPress any key to change outlook.\nPress `d' when you're pleased.\n"));
1257  if (op->msg)
1258  draw_ext_info(NDI_BLUE, 0, op,
1260  op->msg);
1261  return;
1262  }
1263  case 'y':
1264  case 'Y':
1265  roll_stats(op);
1267  return;
1268 
1269  case 'q':
1270  case 'Q':
1271  play_again(op);
1272  return;
1273 
1274  default:
1275  send_query(op->contr->socket, CS_QUERY_SINGLECHAR, i18n(op, "Yes, No, Quit or 1-6. Roll again?"));
1276  return;
1277  }
1278  return;
1279 }
1280 
1294 void key_change_class(object *op, char key) {
1295  int tmp_loop;
1296 
1297  if (key == 'q' || key == 'Q') {
1298  object_remove(op);
1299  play_again(op);
1300  return;
1301  }
1302  if (key == 'd' || key == 'D') {
1303  char buf[MAX_BUF];
1304 
1305  /* this must before then initial items are given */
1306  esrv_new_player(op->contr, op->weight+op->carrying);
1307  create_treasure(find_treasurelist("starting_wealth"), op, 0, 0, 0);
1308 
1309  /* Here we handle the BORN global event */
1311 
1312  /* We then generate a LOGIN event */
1315 
1316  object_set_msg(op, NULL);
1317 
1318  /* We create this now because some of the unique maps will need it
1319  * to save here.
1320  */
1321  snprintf(buf, sizeof(buf), "%s/%s/%s", settings.localdir, settings.playerdir, op->name);
1322  make_path_to_file(buf);
1323 
1324 #ifdef AUTOSAVE
1325  op->contr->last_save_tick = pticks;
1326 #endif
1329  "Welcome to Crossfire!\n Press `?' for help\n");
1330 
1333  "%s entered the game.", op->name);
1334 
1335  CLEAR_FLAG(op, FLAG_WIZ);
1337  link_player_skills(op);
1338  esrv_send_inventory(op, op);
1339  fix_object(op);
1340 
1341  /* This moves the player to a different start map, if there
1342  * is one for this race
1343  */
1344  if (*first_map_ext_path) {
1345  object *tmp;
1346  char mapname[MAX_BUF + strlen(op->arch->name) + 1];
1347  mapstruct *oldmap;
1348 
1349  oldmap = op->map;
1350 
1351  snprintf(mapname, sizeof(mapname), "%s/%s", first_map_ext_path, op->arch->name);
1352  /*printf("%s\n", mapname);*/
1353  tmp = object_new();
1354  EXIT_PATH(tmp) = add_string(mapname);
1355  EXIT_X(tmp) = op->x;
1356  EXIT_Y(tmp) = op->y;
1357  enter_exit(op, tmp);
1358 
1359  if (oldmap != op->map) {
1360  /* map exists, update bed of reality location, in case player dies */
1361  op->contr->bed_x = op->x;
1362  op->contr->bed_y = op->y;
1363  strlcpy(op->contr->savebed_map, mapname, sizeof(op->contr->savebed_map));
1364  }
1365 
1367  } else {
1368  LOG(llevDebug, "first_map_ext_path not set\n");
1369  }
1370  return;
1371  }
1372 
1373  /* Following actually changes the race - this is the default command
1374  * if we don't match with one of the options above.
1375  */
1376 
1377  tmp_loop = 0;
1378  while (!tmp_loop) {
1379  const char *name = add_string(op->name);
1380  int x = op->x, y = op->y;
1381 
1382  remove_statbonus(op);
1383  object_remove(op);
1384  /* get_player_archetype() is really misnamed - it will
1385  * get the next archetype from the list.
1386  */
1387  op->arch = get_player_archetype(op->arch);
1388  object_copy(&op->arch->clone, op);
1389  op->stats = op->contr->orig_stats;
1390  free_string(op->name);
1391  op->name = name;
1392  free_string(op->name_pl);
1393  op->name_pl = add_string(name);
1394  SET_ANIMATION(op, 2); /* So player faces south */
1395  object_insert_in_map_at(op, op->map, op, 0, x, y);
1396  strncpy(op->contr->title, op->arch->clone.name, sizeof(op->contr->title)-1);
1397  op->contr->title[sizeof(op->contr->title)-1] = '\0';
1398  add_statbonus(op);
1399  tmp_loop = allowed_class(op);
1400  }
1402  esrv_update_item(UPD_FACE, op, op);
1403  fix_object(op);
1404  op->contr->is_wraith = object_find_by_name(op, "wraith feed") != NULL;
1405  op->stats.hp = op->stats.maxhp;
1406  op->stats.sp = op->stats.maxsp;
1407  op->stats.grace = 0;
1408  if (op->msg)
1410  op->msg);
1411  send_query(op->contr->socket, CS_QUERY_SINGLECHAR, i18n(op, "Press any key for the next race.\nPress `d' to play this race.\n"));
1412 }
1413 
1435 int check_race_and_class(living *stats, archetype *race, archetype *opclass)
1436 {
1437  int i, stat, failure=0;
1438 
1439  for (i = 0; i < NUM_STATS; i++) {
1440  stat = get_attr_value(stats, i);
1441  if (race)
1442  stat += get_attr_value(&race->clone.stats, i);
1443 
1444  if (opclass)
1445  stat += get_attr_value(&opclass->clone.stats, i);
1446 
1447  set_attr_value(stats, i, stat);
1448 
1449  /* We process all stats, regardless if there is a failure
1450  * or not.
1451  */
1452  if (stat < MIN_STAT) failure=1;
1453 
1454  /* Maybe this should be an error? Player is losing
1455  * some stats points here, but it is legal.
1456  */
1457  if (stat > settings.max_stat) stat = settings.max_stat;
1458  }
1459  return failure;
1460 
1461 }
1462 
1485 int apply_race_and_class(object *op, archetype *race, archetype *opclass, living *stats)
1486 {
1487  const char *name = add_string(op->name);
1488  char buf[MAX_BUF];
1489  object *inv;
1490 
1491  /* Free any objects in character inventory - they
1492  * shouldn't have any, but there is the potential that
1493  * we give them objects below and then get a creation
1494  * failure (stat out of range), in which case
1495  * those objects would be in the inventory.
1496  */
1497  while (op->inv) {
1498  inv = op->inv;
1499  object_remove(inv);
1500  object_free(inv, 0);
1501  }
1502 
1503  object_copy(&race->clone, op);
1504  free_string(op->name);
1505  op->name = name;
1506  free_string(op->name_pl);
1507  op->name_pl = add_string(name);
1508  SET_ANIMATION(op, 2); /* So player faces south */
1509  strlcpy(op->contr->title, op->arch->clone.name, sizeof(op->contr->title));
1510 
1511  if (stats) {
1512  /* Copy over the stats. Use this instead a memcpy because
1513  * we only want to copy over a few specific stats, and
1514  * leave things like maxhp, maxsp, etc, unchanged.
1515  */
1516  int i, stat;
1517  for (i = 0; i < NUM_STATS; i++) {
1518  stat = get_attr_value(stats, i);
1519  set_attr_value(&op->stats, i, stat);
1520  set_attr_value(&op->contr->orig_stats, i, stat);
1521  }
1522  } else {
1523  /* Note that this will repeated increase the stat values
1524  * if the caller does not reset them. Only do this
1525  * if stats is not provided - if stats is provided, those
1526  * are already adjusted.
1527  */
1528  add_statbonus(op);
1529 
1530  /* Checks that all stats are greater than 1. Once again,
1531  * only do this if stats are not provided
1532  */
1533  if (!allowed_class(op)) return 1;
1534  }
1535 
1537  op->stats.hp = op->stats.maxhp;
1538  op->stats.sp = op->stats.maxsp;
1539  op->stats.grace = 0;
1540 
1541  /* this must before then initial items are given */
1542  esrv_new_player(op->contr, op->weight+op->carrying);
1543  create_treasure(find_treasurelist("starting_wealth"), op, 0, 0, 0);
1544 
1545  /* This has to be done before class, otherwise the NOCLASSFACECHANGE
1546  * object is not in the inventory, and racial face will get overwritten.
1547  */
1549 
1550  if (stats) {
1551  /* Apply class information */
1553  } else {
1554  apply_changes_to_player(op, &opclass->clone, 0);
1555 
1556  /* Checks that all stats are greater than 1 */
1557  if (!allowed_class(op)) return 2;
1558  }
1559 
1560  /* Here we handle the BORN global event */
1562 
1563  /* We then generate a LOGIN event */
1565 
1566  object_set_msg(op, NULL);
1567 
1568  /* We create this now because some of the unique maps will need it
1569  * to save here.
1570  */
1571  snprintf(buf, sizeof(buf), "%s/%s/%s", settings.localdir, settings.playerdir, op->name);
1572  make_path_to_file(buf);
1573 
1574 #ifdef AUTOSAVE
1575  op->contr->last_save_tick = pticks;
1576 #endif
1577 
1578  CLEAR_FLAG(op, FLAG_WIZ);
1579  link_player_skills(op);
1580  fix_object(op);
1581 
1582  esrv_send_inventory(op, op);
1583  esrv_update_item(UPD_FACE, op, op);
1584  esrv_add_spells(op->contr, NULL);
1585  op->contr->is_wraith = object_find_by_name(op, "wraith feed") != NULL;
1586 
1587  return 0;
1588 
1589 }
1590 
1599 void key_confirm_quit(object *op, char key) {
1600  char buf[MAX_BUF];
1601  mapstruct *mp, *next;
1602 
1603  // this was tested when 'quit' command was issued, but better safe than sorry.
1604  if (QUERY_FLAG(op, FLAG_WIZ)) {
1606  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_LOGIN, "Can't quit when in DM mode.");
1607  return;
1608  }
1609 
1610  if (key != 'y' && key != 'Y' && key != 'q' && key != 'Q') {
1613  "OK, continuing to play.");
1614  return;
1615  }
1616 
1618  pets_terminate_all(op);
1619  object_remove(op);
1620  op->direction = 0;
1622  "%s quits the game.",
1623  op->name);
1624 
1625  strcpy(op->contr->killer, "quit");
1626  hiscore_check(op, 0);
1627  party_leave(op);
1628  if (settings.set_title == TRUE)
1629  player_set_own_title(op->contr, "");
1630 
1631 
1632  /* We need to hunt for any per player unique maps in memory and
1633  * get rid of them. The trailing slash in the path is intentional,
1634  * so that players named 'Ab' won't match against players 'Abe' pathname
1635  */
1636  snprintf(buf, sizeof(buf), "~%s/%s/", settings.playerdir, op->name);
1637  for (mp = first_map; mp != NULL; mp = next) {
1638  next = mp->next;
1639  if (!strncmp(mp->path, buf, strlen(buf)))
1640  delete_map(mp);
1641  }
1642 
1643  delete_character(op->name);
1644 
1645  /* Remove player from account list and send back data if needed */
1646  if (op->contr->socket->account_chars != NULL) {
1649  /* char information is reloaded in send_account_players below */
1651  op->contr->socket->account_chars = NULL;
1654  }
1655 
1656  play_again(op);
1657 
1658  // Fields in op are not cleared until the client plays a different
1659  // character or disconnects. Therefore, after deleting a character,
1660  // immediately creating a new character with the same name as the deleted
1661  // one fails because verify_player() thinks this player is still playing.
1662  // So we do a little hacking by clearing the name now.
1663  FREE_AND_CLEAR_STR(op->name);
1664 }
1665 
1672 static void flee_player(object *op) {
1673  int dir, diff;
1674  rv_vector rv;
1675 
1676  if (op->stats.hp < 0) {
1677  LOG(llevDebug, "Fleeing player is dead.\n");
1678  CLEAR_FLAG(op, FLAG_SCARED);
1679  return;
1680  }
1681 
1682  if (op->enemy == NULL) {
1683  LOG(llevDebug, "Fleeing player had no enemy.\n");
1684  CLEAR_FLAG(op, FLAG_SCARED);
1685  return;
1686  }
1687 
1688  /* Seen some crashes here. Since we don't store an
1689  * op->enemy_count, it is possible that something destroys the
1690  * actual enemy, and the object is recycled.
1691  */
1692  if (op->enemy->map == NULL) {
1693  CLEAR_FLAG(op, FLAG_SCARED);
1694  object_set_enemy(op, NULL);
1695  return;
1696  }
1697 
1698  if (!(random_roll(0, 4, op, PREFER_LOW)) && did_make_save(op, op->level, 0)) {
1699  object_set_enemy(op, NULL);
1700  CLEAR_FLAG(op, FLAG_SCARED);
1701  return;
1702  }
1703  if (!get_rangevector(op, op->enemy, &rv, 0)) {
1704  object_set_enemy(op, NULL);
1705  CLEAR_FLAG(op, FLAG_SCARED);
1706  return;
1707  }
1708 
1709  dir = absdir(4+rv.direction);
1710  for (diff = 0; diff < 3; diff++) {
1711  int m = 1-(RANDOM()&2);
1712  if (move_ob(op, absdir(dir+diff*m), op)
1713  || (diff == 0 && move_ob(op, absdir(dir-diff*m), op))) {
1714  return;
1715  }
1716  }
1717  /* Cornered, get rid of scared */
1718  CLEAR_FLAG(op, FLAG_SCARED);
1719  object_set_enemy(op, NULL);
1720 }
1721 
1731 int check_pick(object *op) {
1732  tag_t op_tag;
1733  int stop = 0;
1734  int j, k, wvratio, current_ratio;
1735  char putstring[128], tmpstr[16];
1736 
1737  /* if you're flying, you can't pick up anything */
1738  if (op->move_type&MOVE_FLYING)
1739  return 1;
1740  /* If not a player, don't check anything. */
1741  if (!op->contr) {
1742  return 1;
1743  }
1744 
1745  op_tag = op->count;
1746 
1747  FOR_BELOW_PREPARE(op, tmp) {
1748  if (object_was_destroyed(op, op_tag))
1749  return 0;
1750 
1751  if (!object_can_pick(op, tmp))
1752  continue;
1753 
1754  if (op->contr->search_str[0] != '\0' && settings.search_items == TRUE) {
1755  if (object_matches_string(op, tmp, op->contr->search_str))
1756  pick_up(op, tmp);
1757  continue;
1758  }
1759 
1760  /* high not bit set? We're using the old autopickup model */
1761  if (!(op->contr->mode&PU_NEWMODE)) {
1762  switch (op->contr->mode) {
1763  case 0:
1764  return 1; /* don't pick up */
1765 
1766  case 1:
1767  pick_up(op, tmp);
1768  return 1;
1769 
1770  case 2:
1771  pick_up(op, tmp);
1772  return 0;
1773 
1774  case 3:
1775  return 0; /* stop before pickup */
1776 
1777  case 4:
1778  pick_up(op, tmp);
1779  break;
1780 
1781  case 5:
1782  pick_up(op, tmp);
1783  stop = 1;
1784  break;
1785 
1786  case 6:
1787  if (QUERY_FLAG(tmp, FLAG_KNOWN_MAGICAL)
1788  && !QUERY_FLAG(tmp, FLAG_KNOWN_CURSED))
1789  pick_up(op, tmp);
1790  break;
1791 
1792  case 7:
1793  if (tmp->type == MONEY || tmp->type == GEM)
1794  pick_up(op, tmp);
1795  break;
1796 
1797  default:
1798  /* use value density */
1799  if (!QUERY_FLAG(tmp, FLAG_UNPAID)
1800  && (price_base(tmp)*100/(tmp->weight*MAX(tmp->nrof, 1))) >= op->contr->mode)
1801  pick_up(op, tmp);
1802  }
1803  } else { /* old model */
1804  /* NEW pickup handling */
1805  if (op->contr->mode&PU_DEBUG) {
1806  /* some debugging code to figure out item information */
1808  "item name: %s item type: %d weight/value: %d",
1809  tmp->name ? tmp->name : tmp->arch->name, tmp->type,
1810  (int)(price_base(tmp)*100/(tmp->weight*MAX(tmp->nrof, 1))));
1811 
1812 
1813  snprintf(putstring, sizeof(putstring), "...flags: ");
1814  for (k = 0; k < 4; k++) {
1815  for (j = 0; j < 32; j++) {
1816  if ((tmp->flags[k]>>j)&0x01) {
1817  snprintf(tmpstr, sizeof(tmpstr), "%d ", k*32+j);
1818  strcat(putstring, tmpstr);
1819  }
1820  }
1821  }
1823  putstring);
1824  }
1825  /* philosophy:
1826  * It's easy to grab an item type from a pile, as long as it's
1827  * generic. This takes no game-time. For more detailed pickups
1828  * and selections, select-items should be used. This is a
1829  * grab-as-you-run type mode that's really useful for arrows for
1830  * example.
1831  * The drawback: right now it has no frontend, so you need to
1832  * stick the bits you want into a calculator in hex mode and then
1833  * convert to decimal and then 'pickup <#>
1834  */
1835 
1836  /* the first two modes are exclusive: if NOTHING we return, if
1837  * STOP then we stop. All the rest are applied sequentially,
1838  * meaning if any test passes, the item gets picked up. */
1839 
1840  /* if mode is set to pick nothing up, return */
1841 
1842  if (op->contr->mode == PU_NOTHING)
1843  return 1;
1844 
1845  /* if mode is set to stop when encountering objects, return.
1846  * Take STOP before INHIBIT since it doesn't actually pick
1847  * anything up */
1848 
1849  if (op->contr->mode&PU_STOP)
1850  return 0;
1851 
1852  /* useful for going into stores and not losing your settings... */
1853  /* and for battles where you don't want to get loaded down while
1854  * fighting */
1855  if (op->contr->mode&PU_INHIBIT)
1856  return 1;
1857 
1858  /* prevent us from turning into auto-thieves :) */
1859  if (QUERY_FLAG(tmp, FLAG_UNPAID))
1860  continue;
1861 
1862  /* ignore known cursed objects */
1864  continue;
1865 
1866  static int checks[] = {
1867  PU_FOOD,
1868  PU_DRINK,
1869  PU_FLESH,
1870  PU_POTION,
1871  PU_SPELLBOOK,
1873  PU_READABLES,
1875  PU_MAGICAL,
1876  PU_VALUABLES,
1877  PU_JEWELS,
1878  PU_BOW,
1879  PU_ARROW,
1880  PU_ARMOUR,
1881  PU_HELMET,
1882  PU_SHIELD,
1883  PU_BOOTS,
1884  PU_GLOVES,
1885  PU_CLOAK,
1888  PU_KEY,
1889  PU_CONTAINER,
1890  PU_CURSED,
1891  0
1892  };
1893  int found = 0;
1894  for (int m = 0; checks[m] != 0; m++) {
1895  if (op->contr->mode & checks[m] && object_matches_pickup_mode(tmp, checks[m])) {
1896  pick_up(op, tmp);
1897  found = 1;
1898  break;
1899  }
1900  }
1901  if (found) {
1902  continue;
1903  }
1904 
1905  /* any of the last 4 bits set means we use the ratio for value
1906  * pickups */
1907  if (op->contr->mode&PU_RATIO) {
1908  /* use value density to decide what else to grab.
1909  * >=7 was >= op->contr->mode
1910  * >=7 is the old standard setting. Now we take the last 4 bits
1911  * and multiply them by 5, giving 0..15*5== 5..75 */
1912  wvratio = (op->contr->mode&PU_RATIO)*5;
1913  current_ratio = price_base(tmp)*100/(tmp->weight*MAX(tmp->nrof, 1));
1914  if (current_ratio >= wvratio) {
1915  pick_up(op, tmp);
1916  continue;
1917  }
1918  }
1919  } /* the new pickup model */
1920  } FOR_BELOW_FINISH();
1921  return !stop;
1922 }
1923 
1936 static object *find_arrow(object *op, const char *type) {
1937  object *tmp = NULL;
1938 
1939  FOR_INV_PREPARE(op, inv)
1940  if (!tmp
1941  && inv->type == CONTAINER
1942  && inv->race == type
1943  && QUERY_FLAG(inv, FLAG_APPLIED))
1944  tmp = find_arrow(inv, type);
1945  else if (inv->type == ARROW && inv->race == type)
1946  return inv;
1947  FOR_INV_FINISH();
1948  return tmp;
1949 }
1950 
1968 static object *find_better_arrow(object *op, object *target, const char *type, int *better) {
1969  object *tmp = NULL, *ntmp;
1970  int attacknum, attacktype, betterby = 0, i;
1971 
1972  if (!type)
1973  return NULL;
1974 
1975  FOR_INV_PREPARE(op, arrow) {
1976  if (arrow->type == CONTAINER
1977  && arrow->race == type
1978  && QUERY_FLAG(arrow, FLAG_APPLIED)) {
1979  i = 0;
1980  ntmp = find_better_arrow(arrow, target, type, &i);
1981  if (i > betterby) {
1982  tmp = ntmp;
1983  betterby = i;
1984  }
1985  } else if (arrow->type == ARROW && arrow->race == type) {
1986  /* always prefer assassination/slaying */
1987  if (target->race != NULL
1988  && arrow->slaying != NULL
1989  && strstr(arrow->slaying, target->race)) {
1990  if (arrow->attacktype&AT_DEATH) {
1991  if (better)
1992  *better = 100;
1993  return arrow;
1994  } else {
1995  tmp = arrow;
1996  betterby = (arrow->magic+arrow->stats.dam)*2;
1997  }
1998  } else {
1999  for (attacknum = 0; attacknum < NROFATTACKS; attacknum++) {
2000  attacktype = 1<<attacknum;
2001  if ((arrow->attacktype&attacktype) && (target->arch->clone.resist[attacknum]) < 0)
2002  if (((arrow->magic+arrow->stats.dam)*(100-target->arch->clone.resist[attacknum])/100) > betterby) {
2003  tmp = arrow;
2004  betterby = (arrow->magic+arrow->stats.dam)*(100-target->arch->clone.resist[attacknum])/100;
2005  }
2006  }
2007  if ((2+arrow->magic+arrow->stats.dam) > betterby) {
2008  tmp = arrow;
2009  betterby = 2+arrow->magic+arrow->stats.dam;
2010  }
2011  if (arrow->title && (1+arrow->magic+arrow->stats.dam) > betterby) {
2012  tmp = arrow;
2013  betterby = 1+arrow->magic+arrow->stats.dam;
2014  }
2015  }
2016  }
2017  } FOR_INV_FINISH();
2018  if (tmp == NULL)
2019  return find_arrow(op, type);
2020 
2021  if (better)
2022  *better = betterby;
2023  return tmp;
2024 }
2025 
2038 static object *pick_arrow_target(object *op, const char *type, int dir) {
2039  object *tmp = NULL;
2040  mapstruct *m;
2041  int i, mflags, found, number;
2042  int16_t x, y;
2043 
2044  if (op->map == NULL)
2045  return find_arrow(op, type);
2046 
2047  /* do a dex check */
2048  number = (die_roll(2, 40, op, PREFER_LOW)-2)/2;
2049  if (number > (op->stats.Dex+(op->chosen_skill ? op->chosen_skill->level : op->level)))
2050  return find_arrow(op, type);
2051 
2052  m = op->map;
2053  x = op->x;
2054  y = op->y;
2055 
2056  /* find the first target */
2057  for (i = 0, found = 0; i < 20; i++) {
2058  x += freearr_x[dir];
2059  y += freearr_y[dir];
2060  mflags = get_map_flags(m, &m, x, y, &x, &y);
2061  if (mflags&P_OUT_OF_MAP || mflags&P_BLOCKSVIEW) {
2062  tmp = NULL;
2063  break;
2064  } else if (GET_MAP_MOVE_BLOCK(m, x, y) == MOVE_FLY_LOW) {
2065  /* This block presumes arrows and the like are MOVE_FLY_SLOW -
2066  * perhaps a bad assumption.
2067  */
2068  tmp = NULL;
2069  break;
2070  }
2071  if (mflags&P_IS_ALIVE) {
2072  FOR_MAP_PREPARE(m, x, y, tmp2)
2073  if (QUERY_FLAG(tmp2, FLAG_ALIVE)) {
2074  tmp = tmp2;
2075  found++;
2076  break;
2077  }
2078  FOR_MAP_FINISH();
2079  if (found)
2080  break;
2081  }
2082  }
2083  if (tmp == NULL)
2084  return find_arrow(op, type);
2085 
2086  return find_better_arrow(op, HEAD(tmp), type, NULL);
2087 }
2088 
2107 int fire_bow(object *op, object *arrow, int dir, int wc_mod, int16_t sx, int16_t sy) {
2108  object *bow;
2109  tag_t tag;
2110  int bowspeed, mflags;
2111  mapstruct *m;
2112 
2113  if (!dir) {
2115  "You can't shoot yourself!");
2116  return 0;
2117  }
2118  if (op->type == PLAYER) {
2119  bow = op->contr->ranges[range_bow];
2120  // Make sure the bow's skill is readied.
2121  // Otherwise, you can get wrong modifiers from unarmed attacks
2122  // because that ends up the readied skill.
2123  object *skill = find_skill_by_name(op, bow->skill);
2124  if (skill && change_skill(op, skill, 1) == 0) {
2126  "You cannot use %s without the skill %s", bow->name, bow->skill);
2127  return 0;
2128  }
2129  }
2130  else {
2131  /* Don't check for applied - monsters don't apply bows - in that way, they
2132  * don't need to switch back and forth between bows and weapons.
2133  */
2134  bow = object_find_by_type(op, BOW);
2135  if (!bow) {
2136  LOG(llevError, "Range: bow without activated bow (%s).\n", op->name);
2137  return 0;
2138  }
2139  }
2140  if (!bow->race || !bow->skill) {
2142  "Your %s is broken.",
2143  bow->name);
2144  return 0;
2145  }
2146 
2147  bowspeed = bow->stats.sp+get_dex_bonus(op->stats.Dex);
2148 
2149  /* penalize ROF for bestarrow */
2150  if (op->type == PLAYER && op->contr->bowtype == bow_bestarrow)
2151  bowspeed -= get_dex_bonus(op->stats.Dex)+5;
2152  if (bowspeed < 1)
2153  bowspeed = 1;
2154 
2155  if (arrow == NULL) {
2156  arrow = find_arrow(op, bow->race);
2157  if (arrow == NULL) {
2158  if (op->type == PLAYER)
2161  "You have no %s left.",
2162  bow->race);
2163  /* FLAG_READY_BOW will get reset if the monsters picks up some arrows */
2164  else
2166  return 0;
2167  }
2168  }
2169  mflags = get_map_flags(op->map, &m, sx, sy, &sx, &sy);
2170  if (mflags&P_OUT_OF_MAP) {
2171  return 0;
2172  }
2173  if (GET_MAP_MOVE_BLOCK(m, sx, sy)&MOVE_FLY_LOW) {
2174  return 0;
2175  }
2176 
2177  /* this should not happen, but sometimes does */
2178  if (arrow->nrof == 0) {
2179  object_remove(arrow);
2181  return 0;
2182  }
2183 
2184  arrow = object_split(arrow, 1, NULL, 0);
2185  if (arrow == NULL) {
2187  "You have no %s left.",
2188  bow->race);
2189  return 0;
2190  }
2191  object_set_owner(arrow, op);
2192  if (arrow->skill)
2193  free_string(arrow->skill);
2194  arrow->skill = add_refcount(bow->skill);
2195 
2196  arrow->direction = dir;
2197 
2198  if (op->type == PLAYER) {
2199  op->speed_left = 0.01-(float)FABS(op->speed)*100/bowspeed;
2200  fix_object(op);
2201  }
2202 
2203  if (bow->anim_suffix != NULL)
2204  apply_anim_suffix(op, bow->anim_suffix);
2205 
2206 /* SET_ANIMATION(arrow, arrow->direction);*/
2207  object_update_turn_face(arrow);
2208  arrow->stats.sp = arrow->stats.wc; /* save original wc and dam */
2209  arrow->stats.hp = arrow->stats.dam;
2210  arrow->stats.grace = arrow->attacktype;
2211  if (arrow->slaying != NULL)
2212  arrow->spellarg = strdup_local(arrow->slaying);
2213 
2214  /* Note that this was different for monsters - they got their level
2215  * added to the damage. I think the strength bonus is more proper.
2216  */
2217 
2218  arrow->stats.dam += (QUERY_FLAG(bow, FLAG_NO_STRENGTH) ? 0 : get_dam_bonus(op->stats.Str))
2219  +bow->stats.dam
2220  +bow->magic
2221  +arrow->magic;
2222 
2223  /* update the speed */
2224  arrow->speed = (float)((QUERY_FLAG(bow, FLAG_NO_STRENGTH) ? 0 : get_dam_bonus(op->stats.Str))+bow->magic+arrow->magic)/5.0
2225  +(float)bow->stats.dam/7.0;
2226 
2227  if (arrow->speed < 1.0)
2228  arrow->speed = 1.0;
2229  object_update_speed(arrow);
2230  arrow->speed_left = 0;
2231 
2232  if (op->type == PLAYER) {
2233  /* we don't want overflows of wc (sint), so cap the value - mod and pl should be subtracted */
2234  int mod = bow->magic
2235  +arrow->magic
2236  +get_dex_bonus(op->stats.Dex)
2237  +get_thaco_bonus(op->stats.Str)
2238  +arrow->stats.wc
2239  +bow->stats.wc
2240  -wc_mod;
2241  int plmod = (op->chosen_skill ? op->chosen_skill->level : op->level);
2242  if (plmod+mod > 140)
2243  plmod = 140-mod;
2244  else if (plmod+mod < -100)
2245  plmod = -100-mod;
2246  arrow->stats.wc = 20-(int8_t)plmod-(int8_t)mod;
2247 
2248  arrow->level = op->chosen_skill ? op->chosen_skill->level : op->level;
2249  } else {
2250  arrow->stats.wc = op->stats.wc
2251  -bow->magic
2252  -arrow->magic
2253  -arrow->stats.wc
2254  +wc_mod;
2255 
2256  arrow->level = op->level;
2257  }
2258  if (arrow->attacktype == AT_PHYSICAL)
2259  arrow->attacktype |= bow->attacktype;
2260  if (bow->slaying != NULL)
2261  arrow->slaying = add_string(bow->slaying);
2262 
2263  /* If move_type is ever changed, monster.c:monster_use_bow() needs to be changed too. */
2264  arrow->move_type = MOVE_FLY_LOW;
2265  arrow->move_on = MOVE_FLY_LOW|MOVE_WALK;
2266 
2267  tag = arrow->count;
2268  object_insert_in_map_at(arrow, m, op, 0, sx, sy);
2269 
2270  if (!object_was_destroyed(arrow, tag)) {
2271  play_sound_map(SOUND_TYPE_ITEM, arrow, arrow->direction, "fire");
2272  ob_process(arrow);
2273  }
2274 
2275  return 1;
2276 }
2277 
2288 static int similar_direction(int a, int b) {
2289  /* shortcut the obvious */
2290  if (a == b)
2291  return 1;
2292  /* Made this cleaner using modulus instead of a switch statement
2293  * We only needed the direction and the two adjacent to it
2294  * (8 is adjacent to 1 here) to return true, so a - 1, a, and a + 1
2295  * are the three directions that get "similar" affirmed.
2296  * -- Neila Hawkins 2015-05-28
2297  */
2298  // The last one for the offset is added afterwards so we get
2299  // 1-8 instead of 0-7 (specifically, 0 becomes 8 without changing
2300  // the other values).
2301  if ((a % 8) + 1 == b || (a + 6 % 8) + 1 == b)
2302  return 1;
2303  return 0;
2304 }
2305 
2322 static int player_fire_bow(object *op, int dir) {
2323  int ret = 0, wcmod = 0;
2324 
2325  if (op->contr->bowtype == bow_bestarrow) {
2326  ret = fire_bow(op, pick_arrow_target(op, op->contr->ranges[range_bow]->race, dir), dir, 0, op->x, op->y);
2327  } else if (op->contr->bowtype >= bow_n && op->contr->bowtype <= bow_nw) {
2328  if (!similar_direction(dir, op->contr->bowtype-bow_n+1))
2329  wcmod = -1;
2330  ret = fire_bow(op, NULL, op->contr->bowtype-bow_n+1, wcmod, op->x, op->y);
2331  } else if (op->contr->bowtype == bow_threewide) {
2332  ret = fire_bow(op, NULL, dir, 0, op->x, op->y);
2333  ret |= fire_bow(op, NULL, dir, -5, op->x+freearr_x[absdir(dir+2)], op->y+freearr_y[absdir(dir+2)]);
2334  ret |= fire_bow(op, NULL, dir, -5, op->x+freearr_x[absdir(dir-2)], op->y+freearr_y[absdir(dir-2)]);
2335  } else if (op->contr->bowtype == bow_spreadshot) {
2336  ret |= fire_bow(op, NULL, dir, 0, op->x, op->y);
2337  ret |= fire_bow(op, NULL, absdir(dir-1), -5, op->x, op->y);
2338  ret |= fire_bow(op, NULL, absdir(dir+1), -5, op->x, op->y);
2339  } else {
2340  /* Simple case */
2341  ret = fire_bow(op, NULL, dir, 0, op->x, op->y);
2342  }
2343  return ret;
2344 }
2345 
2358 static void fire_misc_object(object *op, int dir) {
2359  object *item;
2360  char name[MAX_BUF];
2361 
2362  item = op->contr->ranges[range_misc];
2363  if (!item) {
2365  "You have no range item readied.");
2366  return;
2367  }
2368  if (!item->inv) {
2369  LOG(llevError, "Object %s lacks a spell\n", item->name);
2370  return;
2371  }
2372  if (item->type == WAND) {
2373  if (item->stats.food <= 0) {
2374  play_sound_player_only(op->contr, SOUND_TYPE_ITEM, item, 0, "poof");
2375  query_base_name(item, 0, name, MAX_BUF);
2377  "The %s goes poof.",
2378  name);
2379  return;
2380  }
2381  } else if (item->type == ROD) {
2382  if (item->stats.hp < SP_level_spellpoint_cost(item, item->inv, SPELL_HIGHEST)) {
2383  play_sound_player_only(op->contr, SOUND_TYPE_ITEM, item, 0, "poof");
2384  query_base_name(item, 0, name, MAX_BUF);
2386  "The %s whines for a while, but nothing happens.",
2387  name);
2388  return;
2389  }
2390  }
2391 
2392  if (cast_spell(op, item, dir, item->inv, NULL)) {
2393  SET_FLAG(op, FLAG_BEEN_APPLIED); /* You now know something about it */
2394  if (item->type == WAND) {
2395  drain_wand_charge(item);
2396  } else if (item->type == ROD) {
2397  drain_rod_charge(item);
2398  }
2399  }
2400 }
2401 
2410 void fire(object *op, int dir) {
2411 
2412  /* check for loss of invisiblity/hide */
2413  if (action_makes_visible(op))
2414  make_visible(op);
2415 
2416  switch (op->contr->shoottype) {
2417  case range_none:
2418  return;
2419 
2420  case range_bow:
2421  player_fire_bow(op, dir);
2422  return;
2423 
2424  case range_magic: /* Casting spells */
2425  cast_spell(op, op, dir, op->contr->ranges[range_magic], op->contr->spellparam[0] ? op->contr->spellparam : NULL);
2426  return;
2427 
2428  case range_misc:
2429  fire_misc_object(op, dir);
2430  return;
2431 
2432  case range_golem: /* Control summoned monsters from scrolls */
2433  if (op->contr->ranges[range_golem] == NULL
2434  || op->contr->golem_count != op->contr->ranges[range_golem]->count) {
2435  op->contr->ranges[range_golem] = NULL;
2436  op->contr->shoottype = range_none;
2437  op->contr->golem_count = 0;
2438  } else
2440  return;
2441 
2442  case range_skill:
2443  if (!op->chosen_skill) {
2444  if (op->type == PLAYER)
2446  "You have no applicable skill to use.");
2447  return;
2448  }
2449  (void)do_skill(op, op, op->chosen_skill, dir, NULL);
2450  return;
2451 
2452  case range_builder:
2453  apply_map_builder(op, dir);
2454  return;
2455 
2456  default:
2458  "Illegal shoot type.");
2459  return;
2460  }
2461 }
2462 
2482 object *find_key(object *pl, object *container, object *door) {
2483  object *tmp, *key;
2484 
2485  /* Should not happen, but sanity checking is never bad */
2486  if (container->inv == NULL)
2487  return NULL;
2488 
2489  /* First, lets try to find a key in the top level inventory */
2490  tmp = NULL;
2491  if (door->type == DOOR) {
2492  int flag = FLAG_UNPAID;
2493  tmp = object_find_by_type_without_flags(container, KEY, &flag, 1);
2494  }
2495  /* For sanity, we should really check door type, but other stuff
2496  * (like containers) can be locked with special keys
2497  */
2498  if (!tmp && door->slaying != NULL) {
2499  tmp = object_find_by_type_and_slaying(container, SPECIAL_KEY, door->slaying);
2500  }
2501  /* No key found - lets search inventories now */
2502  /* If we find and use a key in an inventory, return at that time.
2503  * otherwise, if we search all the inventories and still don't find
2504  * a key, return
2505  */
2506  if (!tmp) {
2507  FOR_INV_PREPARE(container, tmp) {
2508  /* No reason to search empty containers */
2509  if (tmp->type == CONTAINER && tmp->inv) {
2510  key = find_key(pl, tmp, door);
2511  if (key != NULL)
2512  return key;
2513  }
2514  } FOR_INV_FINISH();
2515  return NULL;
2516  }
2517  /* We get down here if we have found a key. Now if its in a container,
2518  * see if we actually want to use it
2519  */
2520  if (pl != container) {
2521  /* Only let players use keys in containers */
2522  if (!pl->contr)
2523  return NULL;
2524  /* cases where this fails:
2525  * If we only search the player inventory, return now since we
2526  * are not in the players inventory.
2527  * If the container is not active, return now since only active
2528  * containers can be used.
2529  * If we only search keyrings and the container does not have
2530  * a race/isn't a keyring.
2531  * No checking for all containers - to fall through past here,
2532  * inv must have been an container and must have been active.
2533  *
2534  * Change the color so that the message doesn't disappear with
2535  * all the others.
2536  */
2537  if (pl->contr->usekeys == key_inventory
2538  || !QUERY_FLAG(container, FLAG_APPLIED)
2539  || (pl->contr->usekeys == keyrings && (!container->race || strcmp(container->race, "keys")))) {
2540  char name_tmp[MAX_BUF], name_cont[MAX_BUF];
2541 
2542  query_name(tmp, name_tmp, MAX_BUF);
2543  query_name(container, name_cont, MAX_BUF);
2546  "The %s in your %s vibrates as you approach the door",
2547  name_tmp, name_cont);
2548  return NULL;
2549  }
2550  }
2551  return tmp;
2552 }
2553 
2564 static int player_attack_door(object *op, object *door) {
2565  /* If its a door, try to find a use a key. If we do destroy the door,
2566  * might as well return immediately as there is nothing more to do -
2567  * otherwise, we fall through to the rest of the code.
2568  */
2569  object *key = find_key(op, op, door);
2570 
2571  assert(door->type == DOOR || door->type == LOCKED_DOOR);
2572 
2573  /* IF we found a key, do some extra work */
2574  if (key) {
2575  char name[HUGE_BUF];
2576 
2577  play_sound_map(SOUND_TYPE_GROUND, door, 0, "open");
2578  if (action_makes_visible(op))
2579  make_visible(op);
2580  if (door->inv && (door->inv->type == RUNE || door->inv->type == TRAP))
2581  spring_trap(door->inv, op);
2582 
2583  query_short_name(key, name, HUGE_BUF);
2586  "You open the door with the %s",
2587  name);
2588 
2589  if (door->type == DOOR)
2590  remove_door(door);
2591  else
2592  remove_locked_door(door); /* remove door without violence ;-) */
2593 
2594  /* Do this after we print the message */
2595  object_decrease_nrof_by_one(key); /* Use up one of the keys */
2596 
2597  return 1; /* Nothing more to do below */
2598 
2599  }
2600 
2601  if (door->type == LOCKED_DOOR) {
2602  /* Might as well return now - no other way to open this */
2603  if (door->msg && *door->msg) {
2605  door->msg);
2606  }
2607  return 1;
2608  }
2609 
2610  if (door->type == DOOR && op->contr && !op->contr->run_on) {
2611  /* Player so try to pick the door */
2612  object *lock = find_skill_by_name(op, "lockpicking");
2613  if (lock) {
2614  /* Even if the lockpicking failed, don't go on moving, player should explicitely attack or run
2615  * to bash the door. */
2616  do_skill(op, op, lock, op->facing, NULL);
2617  return 1;
2618  }
2619  }
2620 
2621  return 0;
2622 }
2623 
2637 void move_player_attack(object *op, int dir) {
2638  object *mon, *tpl, *mon_owner;
2639  int16_t nx, ny;
2640  int on_battleground;
2641  mapstruct *m;
2642 
2643  if (op->contr->transport)
2644  tpl = op->contr->transport;
2645  else
2646  tpl = op;
2647  assert(tpl->map != NULL); // op must be on a map in order to move it
2648  nx = freearr_x[dir]+tpl->x;
2649  ny = freearr_y[dir]+tpl->y;
2650 
2651  on_battleground = op_on_battleground(tpl, NULL, NULL, NULL);
2652 
2653  // Temporarily store the map we are on before movement.
2654  mapstruct *bef = tpl->map;
2655 
2656  /* If braced, or can't move to the square, and it is not out of the
2657  * map, attack it. Note order of if statement is important - don't
2658  * want to be calling move_ob if braced, because move_ob will move the
2659  * player. This is a pretty nasty hack, because if we could
2660  * move to some space, it then means that if we are braced, we should
2661  * do nothing at all. As it is, if we are braced, we go through
2662  * quite a bit of processing. However, it probably is less than what
2663  * move_ob uses.
2664  */
2665  if ((op->contr->braced || !move_ob(tpl, dir, tpl)) && !out_of_map(tpl->map, nx, ny)) {
2666  if (OUT_OF_REAL_MAP(tpl->map, nx, ny)) {
2667  m = get_map_from_coord(tpl->map, &nx, &ny);
2668  if (!m)
2669  return; /* Don't think this should happen */
2670  } else
2671  m = tpl->map;
2672 
2673  if (GET_MAP_OB(m, nx, ny) == NULL) {
2674  /* LOG(llevError, "player_move_attack: GET_MAP_OB returns NULL, but player can not move there.\n");*/
2675  return;
2676  }
2677 
2678  mon = NULL;
2679  /* Go through all the objects, and find ones of interest. Only stop if
2680  * we find a monster - that is something we know we want to attack.
2681  * if its a door or barrel (can roll) see if there may be monsters
2682  * on the space
2683  */
2684  FOR_MAP_PREPARE(m, nx, ny, tmp) {
2685  if (tmp == op) {
2686  continue;
2687  }
2688  if (QUERY_FLAG(tmp, FLAG_ALIVE)) {
2689  mon = tmp;
2690  /* Gros: Objects like (pass-through) doors are alive, but haven't
2691  * their monster flag set - so this is a good way attack real
2692  * monsters in priority.
2693  */
2694  if (QUERY_FLAG(tmp, FLAG_MONSTER))
2695  break;
2696  }
2697  if (tmp->type == LOCKED_DOOR || QUERY_FLAG(tmp, FLAG_CAN_ROLL))
2698  mon = tmp;
2699  } FOR_MAP_FINISH();
2700 
2701  if (mon == NULL) /* This happens anytime the player tries to move */
2702  return; /* into a wall */
2703 
2704  mon = HEAD(mon);
2705  if ((mon->type == DOOR && mon->stats.hp >= 0) || (mon->type == LOCKED_DOOR))
2706  if (player_attack_door(op, mon))
2707  return;
2708 
2709  /* The following deals with possibly attacking peaceful
2710  * or friendly creatures. Basically, all players are considered
2711  * unaggressive. If the moving player has peaceful set, then the
2712  * object should be pushed instead of attacked. It is assumed that
2713  * if you are braced, you will not attack friends accidently,
2714  * and thus will not push them.
2715  */
2716 
2717  /* If the creature is a pet, push it even if the player is not
2718  * peaceful. Our assumption is the creature is a pet if the
2719  * player owns it and it is either friendly or unaggressive.
2720  */
2721  mon_owner = object_get_owner(mon);
2722  if ((op->type == PLAYER)
2723  && (mon_owner == op || (mon_owner != NULL && mon_owner->type == PLAYER && mon_owner->contr->party != NULL && mon_owner->contr->party == op->contr->party))
2724  && (QUERY_FLAG(mon, FLAG_UNAGGRESSIVE) || QUERY_FLAG(mon, FLAG_FRIENDLY))) {
2725  /* If we're braced, we don't want to switch places with it */
2726  if (op->contr->braced)
2727  return;
2728  play_sound_map(SOUND_TYPE_LIVING, mon, dir, "push");
2729  (void)push_ob(mon, dir, op);
2730  if (op->contr->tmp_invis || op->hide)
2731  make_visible(op);
2732  return;
2733  }
2734 
2735  /* in certain circumstances, you shouldn't attack friendly
2736  * creatures. Note that if you are braced, you can't push
2737  * someone, but put it inside this loop so that you won't
2738  * attack them either.
2739  */
2740  if ((mon->type == PLAYER || mon->enemy != op)
2741  && (mon->type == PLAYER || QUERY_FLAG(mon, FLAG_UNAGGRESSIVE) || QUERY_FLAG(mon, FLAG_FRIENDLY))
2742  && (op->contr->peaceful && !on_battleground)) {
2743  if (!op->contr->braced) {
2744  play_sound_map(SOUND_TYPE_LIVING, mon, dir, "push");
2745  (void)push_ob(mon, dir, op);
2746  } else {
2748  "You withhold your attack");
2749  }
2750  if (op->contr->tmp_invis || op->hide)
2751  make_visible(op);
2752  }
2753 
2754  /* If the object is a boulder or other rollable object, then
2755  * roll it if not braced. You can't roll it if you are braced.
2756  */
2757  else if (QUERY_FLAG(mon, FLAG_CAN_ROLL) && (!op->contr->braced)) {
2758  recursive_roll(mon, dir, op);
2759  if (action_makes_visible(op))
2760  make_visible(op);
2761 
2762  /* Any generic living creature. Including things like doors.
2763  * Way it works is like this: First, it must have some hit points
2764  * and be living. Then, it must be one of the following:
2765  * 1) Not a player, 2) A player, but of a different party. Note
2766  * that party_number -1 is no party, so attacks can still happen.
2767  */
2768  } else if ((mon->stats.hp >= 0)
2769  && QUERY_FLAG(mon, FLAG_ALIVE)
2770  && ((mon->type != PLAYER || op->contr->party == NULL || op->contr->party != mon->contr->party))) {
2771  /* If the player hasn't hit something this tick, and does
2772  * so, give them speed boost based on weapon speed. Doing
2773  * it here is better than process_players2, which basically
2774  * incurred a 1 tick offset.
2775  */
2776  if (op->weapon_speed_left < 0) {
2777  op->speed_left = -0.01;
2778  return;
2779  }
2780  op->weapon_speed_left -= 1.0;
2781 
2782  skill_attack(mon, op, 0, NULL, NULL);
2783 
2784  /* If attacking another player, that player gets automatic
2785  * hitback, and doesn't loose luck either.
2786  * Disable hitback on the battleground or if the target is
2787  * the wiz.
2788  */
2789  if (mon->type == PLAYER
2790  && mon->stats.hp >= 0
2791  && !mon->contr->has_hit
2792  && !on_battleground
2793  && !QUERY_FLAG(mon, FLAG_WIZ)) {
2794  short luck = mon->stats.luck;
2795  mon->contr->has_hit = 1;
2796  skill_attack(op, mon, 0, NULL, NULL);
2797  mon->stats.luck = luck;
2798  }
2799  if (action_makes_visible(op))
2800  make_visible(op);
2801  }
2802  } /* if player should attack something */
2803  else if (bef != tpl->map) {
2804  player_map_change_common(op, bef, tpl->map);
2805  }
2806 }
2807 
2814 static void update_transport_block(object *transport, int dir) {
2815  object *part;
2816  int sx, sy, x, y;
2817 
2818  object_get_multi_size(transport, &sx, &sy, NULL, NULL);
2819  assert(sx == sy);
2820 
2821  if (dir == 1 || dir == 5) {
2822  part = transport;
2823  for (y = 0; y <= sy; y++) {
2824  for (x = 0; x < sx; x++) {
2825  part->move_type = transport->move_type;
2826  part = part->more;
2827  }
2828  part->move_type = 0;
2829  part = part->more;
2830  }
2831  } else if (dir == 3 || dir == 7) {
2832  part = transport;
2833  for (y = 0; y < sy; y++) {
2834  for (x = 0; x <= sx; x++) {
2835  part->move_type = transport->move_type;
2836  part = part->more;
2837  }
2838  }
2839  while (part) {
2840  part->move_type = 0;
2841  part = part->more;
2842  }
2843  } else {
2844  for (part = transport; part; part = part->more) {
2845  part->move_type = transport->move_type;
2846  }
2847  }
2848 }
2849 
2859 static int turn_one_transport(object *transport, object *captain, int dir) {
2860  int x, y, scroll_dir = 0;
2861 
2862  assert(transport->type == TRANSPORT);
2863 
2864  x = transport->x;
2865  y = transport->y;
2866 
2867  if (transport->direction == 1 && dir == 8) {
2868  x--;
2869  } else if (transport->direction == 2 && dir == 3) {
2870  y++;
2871  } else if (transport->direction == 3 && dir == 2) {
2872  y--;
2873  } else if (transport->direction == 5 && dir == 6) {
2874  x--;
2875  } else if (transport->direction == 6 && dir == 5) {
2876  x++;
2877  } else if (transport->direction == 7 && dir == 8) {
2878  y--;
2879  } else if (transport->direction == 8 && dir == 7) {
2880  y++;
2881  } else if (transport->direction == 8 && dir == 1) {
2882  x++;
2883  }
2884 
2885  update_transport_block(transport, dir);
2886  object_remove(transport);
2887  if (ob_blocked(transport, transport->map, x, y)) {
2888  update_transport_block(transport, transport->direction);
2889  object_insert_in_map_at(transport, transport->map, NULL, 0, x, y);
2890  return 2;
2891  }
2892 
2893  if (x != transport->x || y != transport->y) {
2894 /* assert(scroll_dir != 0);*/
2895 
2896  FOR_INV_PREPARE(transport, pl) {
2897  if (pl->type == PLAYER) {
2898  pl->contr->do_los = 1;
2899  pl->map = transport->map;
2900  pl->x = x;
2901  pl->y = y;
2902  esrv_map_scroll(pl->contr->socket, freearr_x[scroll_dir], freearr_y[scroll_dir]);
2903  pl->contr->socket->update_look = 1;
2904  pl->contr->socket->look_position = 0;
2905  }
2906  } FOR_INV_FINISH();
2907  }
2908 
2909  object_insert_in_map_at(transport, transport->map, NULL, 0, x, y);
2910  transport->direction = dir;
2911  transport->facing = dir;
2912  animate_object(transport, dir);
2913  captain->direction = dir;
2914  return 1;
2915 }
2916 
2929 static int turn_transport(object *transport, object *captain, int dir) {
2930  assert(transport->type == TRANSPORT);
2931 
2932  if (object_value_set(transport, "turnable_transport") == false) {
2933  transport->direction = dir;
2934  transport->facing = dir;
2935  if (QUERY_FLAG(transport, FLAG_ANIMATE)) {
2936  animate_object(transport, dir);
2937  }
2938  captain->direction = dir;
2939  return 0;
2940  }
2941 
2942  if (transport->direction == dir)
2943  return 0;
2944 
2945  if (absdir(transport->direction-dir) > 2)
2946  return turn_one_transport(transport, captain, absdir(transport->direction+1));
2947  else
2948  return turn_one_transport(transport, captain, absdir(transport->direction-1));
2949 }
2950 
2962 int move_player(object *op, int dir) {
2963  object *transport = op->contr->transport; //< Transport player is in
2964 
2965  if (!transport && (op->map == NULL || op->map->in_memory != MAP_IN_MEMORY))
2966  return 0;
2967 
2968  /* Sanity check: make sure dir is valid */
2969  if ((dir < 0) || (dir >= 9)) {
2970  LOG(llevError, "move_player: invalid direction %d\n", dir);
2971  return 0;
2972  }
2973 
2974  if (QUERY_FLAG(op, FLAG_CONFUSED) && dir)
2975  dir = get_randomized_dir(dir);
2976 
2977  op->facing = dir;
2978 
2979  if (transport) {
2980  /* transport->contr is set up for the person in charge of the boat.
2981  * if that isn't this person, he can't steer it, etc
2982  */
2983  if (transport->contr != op->contr)
2984  return 0;
2985 
2986  /* Transport is out of movement. But update dir so it at least
2987  * will point in the same direction if player is running.
2988  */
2989  if (transport->speed_left < 0.0) {
2990  return 0;
2991  }
2992  /* Remove transport speed. Give player just a little speed -
2993  * enough so that they will get an action again quickly.
2994  */
2995  transport->speed_left -= 1.0;
2996  if (op->speed_left < 0.0)
2997  op->speed_left = -0.01;
2998 
2999  int turn = turn_transport(transport, op, dir);
3000  if (turn != 0)
3001  return 0;
3002  } else {
3003  if (op->hide) {
3004  do_hidden_move(op);
3005  }
3006 
3007  /* it is important to change the animation now, as fire or move_player_attack can start a compound animation,
3008  * and leave us with state = 0, which we don't want to change again. */
3009  op->state++; /* player moved, so change animation. */
3010  animate_object(op, op->facing);
3011  }
3012 
3013  if (op->contr->fire_on) {
3014  fire(op, dir);
3015  } else
3016  move_player_attack(op, dir);
3017 
3018  int pick = check_pick(op);
3019 
3020  /* Add special check for newcs players and fire on - this way, the
3021  * server can handle repeat firing.
3022  */
3023  if (op->contr->fire_on || (op->contr->run_on && pick != 0)) {
3024  op->direction = dir;
3025  } else {
3026  op->direction = 0;
3027  }
3028  return 0;
3029 }
3030 
3041 int face_player(object *op, int dir) {
3042  object *transport = op->contr->transport; //< Transport player is in
3043 
3044  if (!transport && (op->map == NULL || op->map->in_memory != MAP_IN_MEMORY))
3045  return 0;
3046 
3047  /* Sanity check: make sure dir is valid */
3048  if ((dir < 0) || (dir >= 9)) {
3049  LOG(llevError, "move_player: invalid direction %d\n", dir);
3050  return 0;
3051  }
3052 
3053  if (QUERY_FLAG(op, FLAG_CONFUSED) && dir)
3054  dir = get_randomized_dir(dir);
3055 
3056  op->facing = dir;
3057 
3058  if (transport) {
3059  /* transport->contr is set up for the person in charge of the boat.
3060  * if that isn't this person, he can't steer it, etc
3061  */
3062  if (transport->contr != op->contr)
3063  return 0;
3064 
3065  turn_transport(transport, op, dir);
3066  } else {
3067  if (op->hide) {
3068  do_hidden_move(op);
3069  }
3070 
3071  /* it is important to change the animation now, as fire or move_player_attack can start a compound animation,
3072  * and leave us with state = 0, which we don't want to change again. */
3073  op->state++; /* player moved, so change animation. */
3074  animate_object(op, op->facing);
3075  }
3076 
3077  /* Add special check for newcs players and fire on - this way, the
3078  * server can handle repeat firing.
3079  */
3080  if (op->contr->fire_on || op->contr->run_on) {
3081  op->direction = dir;
3082  } else {
3083  op->direction = 0;
3084  }
3085  return 0;
3086 }
3087 
3100 int handle_newcs_player(object *op) {
3101  if (op->contr->hidden) {
3102  op->invisible = 1000;
3103  /* the socket code flashes the player visible/invisible
3104  * depending on the value if invisible, so we need to
3105  * alternate it here for it to work correctly.
3106  */
3107  if (pticks&2)
3108  op->invisible--;
3109  } else if (op->invisible && !(QUERY_FLAG(op, FLAG_MAKE_INVIS))) {
3110  op->invisible--;
3111  if (!op->invisible) {
3112  make_visible(op);
3114  "Your invisibility spell runs out.");
3115  }
3116  }
3117 
3118  if (QUERY_FLAG(op, FLAG_SCARED)) {
3119  flee_player(op);
3120  /* If player is still scared, that is his action for this tick */
3121  if (QUERY_FLAG(op, FLAG_SCARED)) {
3122  op->speed_left--;
3123  return 0;
3124  }
3125  }
3126 
3127  /* I've been seeing crashes where the golem has been destroyed, but
3128  * the player object still points to the defunct golem. The code that
3129  * destroys the golem looks correct, and it doesn't always happen, so
3130  * put this in a a workaround to clean up the golem pointer.
3131  */
3132  if (op->contr->ranges[range_golem]
3134  op->contr->ranges[range_golem] = NULL;
3135  op->contr->golem_count = 0;
3136  }
3137 
3138  /*
3139  * If the player has been paralyzed, we unmark the flag and give a message to the player
3140  */
3141  if (QUERY_FLAG(op, FLAG_PARALYZED)) {
3143  // TODO: Is this check necessary? We are in player.c, after all.
3144  if (op->type == PLAYER)
3145  {
3147  "You can stretch your stiff joints once more.");
3148  }
3149  }
3150 
3151  if (op->direction && (op->contr->run_on || op->contr->fire_on)) {
3152  /* All move commands take 1 tick, at least for now */
3153  op->speed_left--;
3154 
3155  /* Instead of all the stuff below, let move_player take care
3156  * of it. Also, some of the skill stuff is only put in
3157  * there, as well as the confusion stuff.
3158  */
3159  move_player(op, op->direction);
3160  if (op->speed_left > 0)
3161  return 1;
3162  else
3163  return 0;
3164  }
3165 
3166  if (op->contr->repeat_func != NULL) {
3167  bool ret = op->contr->repeat_func(op->contr, op->contr->repeat_func_data);
3168  if (ret == false) {
3170  }
3171  }
3172 
3173  return 0;
3174 }
3175 
3186 static int save_life(object *op) {
3187  object *tmp;
3188 
3189  if (!QUERY_FLAG(op, FLAG_LIFESAVE))
3190  return 0;
3191 
3193  if (tmp != NULL) {
3194  char name[MAX_BUF];
3195 
3196  query_name(tmp, name, MAX_BUF);
3197  play_sound_map(SOUND_TYPE_ITEM, tmp, 0, "evaporate");
3199  "Your %s vibrates violently, then evaporates.",
3200  name);
3201  object_remove(tmp);
3204  if (op->stats.hp < 0)
3205  op->stats.hp = op->stats.maxhp;
3206  if (op->stats.food < 0)
3207  op->stats.food = MAX_FOOD;
3208  fix_object(op);
3209  return 1;
3210  }
3211  LOG(llevError, "Error: LIFESAVE set without applied object.\n");
3213  enter_player_savebed(op); /* bring him home. */
3214  return 0;
3215 }
3216 
3229 void remove_unpaid_objects(object *op, object *env, int free_items) {
3231  if (QUERY_FLAG(op, FLAG_UNPAID)) {
3232  object_remove(op);
3233  if (free_items)
3235  else
3236  object_insert_in_map_at(op, env->map, NULL, 0, env->x, env->y);
3237  } else if (op->inv)
3238  remove_unpaid_objects(op->inv, env, free_items);
3240 }
3241 
3259 static const char *gravestone_text(object *op, char *buf2, int len) {
3260  char buf[MAX_BUF];
3261  time_t now = time(NULL);
3262 
3263  strncpy(buf2, " R.I.P.\n\n", len);
3264  if (op->type == PLAYER)
3265  snprintf(buf, sizeof(buf), "%s the %s\n", op->name, op->contr->title);
3266  else
3267  snprintf(buf, sizeof(buf), "%s\n", op->name);
3268  strncat(buf2, " ", 20-strlen(buf)/2);
3269  strncat(buf2, buf, len-strlen(buf2)-1);
3270  if (op->type == PLAYER)
3271  snprintf(buf, sizeof(buf), "who was in level %d when killed\n", op->level);
3272  else
3273  snprintf(buf, sizeof(buf), "who was in level %d when died.\n\n", op->level);
3274  strncat(buf2, " ", 20-strlen(buf)/2);
3275  strncat(buf2, buf, len-strlen(buf2)-1);
3276  if (op->type == PLAYER) {
3277  snprintf(buf, sizeof(buf), "by %s.\n\n", op->contr->killer);
3278  strncat(buf2, " ", 21-strlen(buf)/2);
3279  strncat(buf2, buf, len-strlen(buf2)-1);
3280  }
3281  strftime(buf, MAX_BUF, "%b %d %Y\n", localtime(&now));
3282  strncat(buf2, " ", 20-strlen(buf)/2);
3283  strncat(buf2, buf, len-strlen(buf2)-1);
3284  return buf2;
3285 }
3286 
3287 static bool starving(object *op) {
3288  return op->stats.food <= 0;
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) && !starving(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  // Grab a bite of food if able, starving, and still alive.
3386  if (op->contr->state == ST_PLAYING && starving(op) && op->stats.hp >= 0) {
3387  if (is_wraith_pl(op))
3388  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ITEM, MSG_TYPE_ITEM_REMOVE, "You feel a hunger for living flesh.");
3389  /* Only allow eat if not paralyzed. Otherwise our paralyzed player is "moving" to eat.
3390  * Neila Hawkins 2017-08-23
3391  */
3392  else if (!QUERY_FLAG(op, FLAG_PARALYZED)){
3393  object *flesh = NULL;
3394 
3395  FOR_INV_PREPARE(op, tmp) {
3396  if (!QUERY_FLAG(tmp, FLAG_UNPAID)) {
3397  if (tmp->type == FOOD || tmp->type == DRINK || tmp->type == POISON) {
3399  "You blindly grab for a bite of food.");
3400  apply_manual(op, tmp, 0);
3401  if (op->stats.food >= 0 || op->stats.hp < 0)
3402  break;
3403  } else if (tmp->type == FLESH)
3404  flesh = tmp;
3405  } /* End if paid for object */
3406  } FOR_INV_FINISH(); /* end of for loop */
3407  /* If player is still starving, it means they don't have any food, so
3408  * eat flesh instead.
3409  */
3410  if (op->stats.food < 0 && op->stats.hp >= 0 && flesh) {
3412  "You blindly grab for a bite of food.");
3413  apply_manual(op, flesh, 0);
3414  }
3415  } /* end not wraith and not paralyzed */
3416  else { // Print a message for when the player is starving and paralyzed
3417  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ITEM, MSG_TYPE_ITEM_REMOVE, "Your stomach rumbles, but you can't reach your food.");
3418  } /* end not wraith and is paralyzed */
3419  } /* end if player is starving */
3420 
3421  // Prevent food from going negative, then deal constant hunger damage.
3422  if (starving(op)) {
3423  op->stats.food = 0;
3424  op->stats.hp -= 1;
3425  }
3426 
3427  if (!op->contr->state && !QUERY_FLAG(op, FLAG_WIZ) && (op->stats.hp <= 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, AP_NULL);
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 
3476 static void restore_player(object *op) {
3477  object *tmp;
3478  archetype *at = find_archetype("poisoning");
3479  if (at != NULL) {
3480  tmp = arch_present_in_ob(at, op);
3481  if (tmp) {
3482  object_remove(tmp);
3485  "Your body feels cleansed");
3486  }
3487  }
3488 
3489  at = find_archetype("confusion");
3490  if (at != NULL) {
3491  tmp = arch_present_in_ob(at, op);
3492  if (tmp) {
3493  object_remove(tmp);
3496  "Your mind feels clearer");
3497  }
3498  }
3499 
3500  cure_disease(op, NULL, NULL); /* remove any disease */
3501 }
3502 
3514 void kill_player(object *op, const object *killer) {
3515  char buf[MAX_BUF];
3516  int x, y;
3517  object *tmp;
3518  archetype *trophy = NULL;
3519 
3520  /* Don't die if the player's life can be saved. */
3521  if (save_life(op)) {
3522  return;
3523  }
3524 
3525  /* If player dies on BATTLEGROUND, no stat/exp loss! For Combat-Arenas
3526  * in cities ONLY!!! It is very important that this doesn't get abused.
3527  * Look at op_on_battleground() for more info --AndreasV
3528  */
3529  if (op_on_battleground(op, &x, &y, &trophy)) {
3530  assert(trophy != NULL);
3532  "You have been defeated in combat!\n"
3533  "Local medics have saved your life...");
3534 
3535  /* restore player */
3536  restore_player(op);
3537 
3538  op->stats.hp = op->stats.maxhp;
3539  if (op->stats.food <= 0)
3540  op->stats.food = MAX_FOOD;
3541 
3542  /* create a bodypart-trophy to make the winner happy */
3543  tmp = arch_to_object(trophy);
3544  if (tmp != NULL) {
3545  snprintf(buf, sizeof(buf), "%s's %s", op->name, tmp->name);
3546  tmp->name = add_string(buf);
3547 
3548  snprintf(buf, sizeof(buf),
3549  "This %s was %s %s the %s, who was defeated at level %d by %s.\n",
3550  tmp->name, tmp->type == FLESH ? "cut off" : "taken from",
3551  op->name, op->contr->title,
3552  (int)(op->level), op->contr->killer);
3553 
3554  object_set_msg(tmp, buf);
3555  tmp->type = 0;
3556  tmp->value = 0;
3557  tmp->material = 0;
3558  tmp->materialname = NULL;
3559  object_insert_in_map_at(tmp, op->map, op, 0, op->x, op->y);
3560  }
3561 
3562  /* teleport defeated player to new destination*/
3563  transfer_ob(op, x, y, 0, NULL);
3564  op->contr->braced = 0;
3565  return;
3566  }
3567 
3568  if (events_execute_object_event(op, EVENT_DEATH, NULL, NULL, NULL, SCRIPT_FIX_ALL) != 0)
3569  return;
3570 
3572  if (starving(op)) {
3573  snprintf(buf, sizeof(buf), "%s starved to death.", op->name);
3574  strcpy(op->contr->killer, "starvation");
3575  } else {
3576  snprintf(buf, sizeof(buf), "%s died.", op->name);
3577  }
3578  play_sound_player_only(op->contr, SOUND_TYPE_LIVING, op, 0, "death");
3579 
3580  if (settings.not_permadeth == TRUE) {
3582  } else {
3584  }
3585 }
3586 
3595 static void kill_player_not_permadeath(object *op) {
3596  int num_stats_lose;
3597  int will_kill_again;
3598  int lost_a_stat;
3599  int z;
3600  object *tmp;
3601  char buf[MAX_BUF];
3602  archetype *at;
3603 
3604  /* Basically two ways to go - remove a stat permanently, or just
3605  * make it depletion. This bunch of code deals with that aspect
3606  * of death.
3607  */
3609  /* If stat loss is permanent, lose one stat only. */
3610  /* Lower level chars don't lose as many stats because they suffer
3611  more if they do. */
3612  /* Higher level characters can afford things such as potions of
3613  restoration, or better, stat potions. So we slug them that
3614  little bit harder. */
3615  /* GD */
3617  num_stats_lose = 1;
3618  else
3619  num_stats_lose = 1+op->level/BALSL_NUMBER_LOSSES_RATIO;
3620  } else {
3621  num_stats_lose = 1;
3622  }
3623  lost_a_stat = 0;
3624 
3625  for (z = 0; z < num_stats_lose; z++) {
3627  int i;
3628 
3629  /* Pick a random stat and take a point off it. Tell the player
3630  * what he lost.
3631  */
3632  i = RANDOM()%7;
3633  change_attr_value(&(op->stats), i, -1);
3635  change_attr_value(&(op->contr->orig_stats), i, -1);
3637  draw_ext_info(NDI_UNIQUE, 0, op,
3639  lose_msg[i]);
3640  lost_a_stat = 1;
3641  } else {
3642  /* deplete a stat */
3644  if (deparch == NULL) {
3645  continue;
3646  }
3647  object *dep;
3648  int lose_this_stat;
3649  int i;
3650 
3651  i = RANDOM()%7;
3652  dep = arch_present_in_ob(deparch, op);
3653  if (!dep) {
3654  dep = arch_to_object(deparch);
3655  object_insert_in_ob(dep, op);
3656  }
3657  lose_this_stat = 1;
3659  int this_stat;
3660 
3661  /* GD */
3662  /* Get the stat that we're about to deplete. */
3663  this_stat = get_attr_value(&(dep->stats), i);
3664  if (this_stat < 0) {
3665  int loss_chance = 1+op->level/BALSL_LOSS_CHANCE_RATIO;
3666  int keep_chance = this_stat*this_stat;
3667  /* Yes, I am paranoid. Sue me. */
3668  if (keep_chance < 1)
3669  keep_chance = 1;
3670 
3671  /* There is a maximum depletion total per level. */
3672  if (this_stat < -1-op->level/BALSL_MAX_LOSS_RATIO) {
3673  lose_this_stat = 0;
3674  /* Take loss chance vs keep chance to see if we
3675  retain the stat. */
3676  } else {
3677  if (random_roll(0, loss_chance+keep_chance-1, op, PREFER_LOW) < keep_chance)
3678  lose_this_stat = 0;
3679  /* 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"); */
3680  }
3681  }
3682  }
3683 
3684  if (lose_this_stat) {
3685  int this_stat;
3686 
3687  this_stat = get_attr_value(&(dep->stats), i);
3688  /* We could try to do something clever like find another
3689  * stat to reduce if this fails. But chances are, if
3690  * stats have been depleted to -50, all are pretty low
3691  * and should be roughly the same, so it shouldn't make a
3692  * difference.
3693  */
3694  if (this_stat >= -50) {
3695  change_attr_value(&(dep->stats), i, -1);
3696  SET_FLAG(dep, FLAG_APPLIED);
3698  drain_msg[i]);
3699  fix_object(op);
3700  lost_a_stat = 1;
3701  }
3702  }
3703  }
3704  }
3705  /* If no stat lost, tell the player. */
3706  if (!lost_a_stat) {
3707  /* determine_god() seems to not work sometimes... why is this? Should I be using something else? GD */
3708  const char *god = determine_god(op);
3709 
3710  if (god && (strcmp(god, "none")))
3713  "For a brief moment you feel the holy presence of %s protecting you",
3714  god);
3715  else
3716  draw_ext_info(NDI_UNIQUE, 0, op,
3718  "For a brief moment you feel a holy presence protecting you.");
3719  }
3720 
3721  /* Put a gravestone up where the character 'almost' died. List the
3722  * exp loss on the stone.
3723  */
3724  at = find_archetype("gravestone");
3725  if (at != NULL) {
3726  tmp = arch_to_object(at);
3727  snprintf(buf, sizeof(buf), "%s's gravestone", op->name);
3728  FREE_AND_COPY(tmp->name, buf);
3729  snprintf(buf, sizeof(buf), "%s's gravestones", op->name);
3730  FREE_AND_COPY(tmp->name_pl, buf);
3731  snprintf(buf, sizeof(buf), "RIP\nHere rests the hero %s the %s,\n"
3732  "who was killed\n"
3733  "by %s.\n",
3734  op->name, op->contr->title,
3735  op->contr->killer);
3736  object_set_msg(tmp, buf);
3737  object_insert_in_map_at(tmp, op->map, NULL, 0, op->x, op->y);
3738  }
3739 
3740  /* restore player: remove any poisoning, disease and confusion the
3741  * character may be suffering.*/
3742  restore_player(op);
3743 
3744  /* Subtract the experience points, if we died cause of food, give
3745  * us food, and reset HP's...
3746  */
3748  if (op->stats.food < 100)
3749  op->stats.food = 900;
3750  op->stats.hp = op->stats.maxhp;
3751  op->stats.sp = MAX(op->stats.sp, op->stats.maxsp);
3752  op->stats.grace = MAX(op->stats.grace, op->stats.maxgrace);
3753 
3754  /* Check to see if the player is in a shop. IF so, then check to see if
3755  * the player has any unpaid items. If so, remove them and put them back
3756  * in the map.
3757  *
3758  * If they are not in a shop, just free the unpaid items instead of
3759  * putting them back on map.
3760  */
3761  if (shop_contains(op))
3762  remove_unpaid_objects(op->inv, op, 0);
3763  else
3764  remove_unpaid_objects(op->inv, op, 1);
3765 
3766  /* Move player to his current respawn-position (usually last savebed) */
3768 
3769  /* Save the player before inserting the force to reduce chance of abuse. */
3770  op->contr->braced = 0;
3771  /* don't pick up in apartment */
3772  if (op->contr->mode & PU_NEWMODE) {
3773  op->contr->mode = op->contr->mode | PU_INHIBIT;
3774  esrv_send_pickup(op->contr);
3775  } else {
3776  op->contr->mode = 0;
3777  }
3778  if ( op->contr->search_str[0] ) command_search_items(op,NULL); /* turn off search-items */
3779  save_player(op, 1);
3780 
3781  /* it is possible that the player has blown something up
3782  * at his savebed location, and that can have long lasting
3783  * spell effects. So first see if there is a spell effect
3784  * on the space that might harm the player.
3785  */
3786  will_kill_again = 0;
3787  FOR_MAP_PREPARE(op->map, op->x, op->y, tmp)
3788  if (tmp->type == SPELL_EFFECT)
3789  will_kill_again |= tmp->attacktype;
3790  FOR_MAP_FINISH();
3791  if (will_kill_again) {
3792  object *force;
3793  int at;
3794 
3795  force = create_archetype(FORCE_NAME);
3796  /* 50 ticks should be enough time for the spell to abate */
3797  force->speed = 0.1;
3798  force->speed_left = -5.0;
3799  SET_FLAG(force, FLAG_APPLIED);
3800  for (at = 0; at < NROFATTACKS; at++) {
3801  if (will_kill_again&(1<<at))
3802  force->resist[at] = 100;
3803  }
3804  object_insert_in_ob(force, op);
3805  fix_object(op);
3806  }
3807 
3808  /* Tell the player they have died */
3810  "YOU HAVE DIED.");
3811 }
3812 
3819 static void kill_player_permadeath(object *op) {
3820  char buf[MAX_BUF];
3821  char ac_buf[MAX_BUF];
3822  int x, y;
3823  mapstruct *map;
3824  object *tmp;
3825  archetype *at;
3826 
3827  /* save the map location for corpse, gravestone*/
3828  x = op->x;
3829  y = op->y;
3830  map = op->map;
3831 
3832  party_leave(op);
3833  if (settings.set_title == TRUE)
3834  player_set_own_title(op->contr, "");
3835 
3836  /* buf should be the kill message */
3838  buf);
3839  hiscore_check(op, 0);
3840  if (op->contr->ranges[range_golem] != NULL) {
3844  op->contr->ranges[range_golem] = NULL;
3845  op->contr->golem_count = 0;
3846  }
3847  loot_object(op); /* Remove some of the items for good */
3848  object_remove(op);
3849  op->direction = 0;
3850 
3851  if (!QUERY_FLAG(op, FLAG_WAS_WIZ) && op->stats.exp) {
3852  if (settings.resurrection == TRUE) {
3853  /* save playerfile sans equipment when player dies
3854  * -then save it as player.pl.dead so that future resurrection
3855  * -type spells will work on them nicely
3856  */
3857  op->stats.hp = op->stats.maxhp;
3858  op->stats.food = MAX_FOOD;
3859 
3860  /* set the location of where the person will reappear when */
3861  /* maybe resurrection code should fix map also */
3863  sizeof(op->contr->maplevel));
3864  if (op->map != NULL)
3865  op->map = NULL;
3866  op->x = settings.emergency_x;
3867  op->y = settings.emergency_y;
3868  save_player(op, 0);
3869  op->map = map;
3870  /* please see resurrection.c: peterm */
3871  dead_player(op);
3872  } else {
3873  delete_character(op->name);
3874 
3875  /* Remove player from account list and send back data if needed */
3876  if (op->contr->socket->account_chars != NULL) {
3879  /* char information is reloaded in send_account_players below */
3881  op->contr->socket->account_chars = NULL;
3884  }
3885  }
3886  }
3887  play_again(op);
3888 
3889  /* peterm: added to create a corpse at deathsite. */
3890  at = find_archetype("corpse_pl");
3891  if (at != NULL) {
3892  tmp = arch_to_object(at);
3893  snprintf(buf, sizeof(buf), "%s", op->name);
3894  FREE_AND_COPY(tmp->name, buf);
3895  FREE_AND_COPY(tmp->name_pl, buf);
3896  tmp->level = op->level;
3897  object_set_msg(tmp, gravestone_text(op, buf, sizeof(buf)));
3898  SET_FLAG(tmp, FLAG_UNIQUE);
3899  /*
3900  * Put the account name under slaying.
3901  * Does not seem to cause weird effects, but more testing may ensure this.
3902  */
3903  snprintf(ac_buf, sizeof(ac_buf), "%s", op->contr->socket->account_name);
3904  FREE_AND_COPY(tmp->slaying, ac_buf);
3905  object_insert_in_map_at(tmp, map, NULL, 0, x, y);
3906  }
3907 }
3908 
3916 void fix_weight(void) {
3917  player *pl;
3918 
3919  for (pl = first_player; pl != NULL; pl = pl->next) {
3920  int old = pl->ob->carrying, sum = object_sum_weight(pl->ob);
3921 
3922  if (old == sum)
3923  continue;
3924  fix_object(pl->ob);
3925  LOG(llevDebug, "Fixed inventory in %s (%d -> %d)\n", pl->ob->name, old, sum);
3926  }
3927 }
3928 
3932 void fix_luck(void) {
3933  player *pl;
3934 
3935  for (pl = first_player; pl != NULL; pl = pl->next)
3936  if (!pl->ob->contr->state)
3937  change_luck(pl->ob, 0);
3938 }
3939 
3940 
3953 void cast_dust(object *op, object *throw_ob, int dir) {
3954  object *skop, *spob;
3955 
3956  skop = find_skill_by_name(op, throw_ob->skill);
3957 
3958  /* casting POTION 'dusts' is really a use_magic_item skill */
3959  if (op->type == PLAYER && throw_ob->type == POTION && !skop) {
3960  LOG(llevError, "Player %s lacks critical skill use_magic_item!\n", op->name);
3961  return;
3962  }
3963  spob = throw_ob->inv;
3964  if (op->type == PLAYER && spob)
3966  "You cast %s.",
3967  spob->name);
3968 
3969  cast_spell(op, throw_ob, dir, spob, NULL);
3970 
3971  if (!QUERY_FLAG(throw_ob, FLAG_REMOVED))
3972  object_remove(throw_ob);
3973  object_free_drop_inventory(throw_ob);
3974 }
3975 
3982 void make_visible(object *op) {
3983  op->hide = 0;
3984  op->invisible = 0;
3985  if (op->type == PLAYER) {
3986  op->contr->tmp_invis = 0;
3987  if (op->contr->invis_race)
3989  }
3991 }
3992 
4001 int is_true_undead(object *op) {
4002  if (QUERY_FLAG(&op->arch->clone, FLAG_UNDEAD))
4003  return 1;
4004 
4005  return 0;
4006 }
4007 
4018 int hideability(object *ob) {
4019  int i, level = 0, mflag;
4020  int16_t x, y;
4021 
4022  if (!ob || !ob->map)
4023  return 0;
4024 
4025  /* so, on normal lighted maps, its hard to hide */
4026  level = ob->map->darkness-2;
4027 
4028  /* this also picks up whether the object is glowing.
4029  * If you carry a light on a non-dark map, its not
4030  * as bad as carrying a light on a pitch dark map
4031  */
4032  if (has_carried_lights(ob))
4033  level = -(10+(2*ob->map->darkness));
4034 
4035  /* scan through all nearby squares for terrain to hide in */
4036  for (i = 0, x = ob->x, y = ob->y; i < 9; i++, x = ob->x+freearr_x[i], y = ob->y+freearr_y[i]) {
4037  mflag = get_map_flags(ob->map, NULL, x, y, NULL, NULL);
4038  if (mflag&P_OUT_OF_MAP) {
4039  continue;
4040  }
4041  if (mflag&P_BLOCKSVIEW) /* something to hide near! */
4042  level += 2;
4043  else /* open terrain! */
4044  level -= 1;
4045  }
4046 
4047  return level;
4048 }
4049 
4059 void do_hidden_move(object *op) {
4060  int hide = 0, num = random_roll(0, 19, op, PREFER_LOW);
4061  object *skop;
4062 
4063  if (!op || !op->map)
4064  return;
4065 
4067 
4068  /* its *extremely *hard to run and sneak/hide at the same time! */
4069  if (op->type == PLAYER && op->contr->run_on) {
4070  if (!skop || num >= skop->level) {
4072  "You ran too much! You are no longer hidden!");
4073  make_visible(op);
4074  return;
4075  } else
4076  num += 20;
4077  }
4078  num += op->map->difficulty;
4079  hide = hideability(op); /* modify by terrain hidden level */
4080  num -= hide;
4081  if ((op->type == PLAYER && hide < -10)
4082  || ((op->invisible -= num) <= 0)) {
4083  make_visible(op);
4084  if (op->type == PLAYER)
4086  "You moved out of hiding! You are visible!");
4087  } else if (op->type == PLAYER && skop) {
4088  change_exp(op, calc_skill_exp(op, NULL, skop), skop->skill, 0);
4089  }
4090 }
4091 
4100 int stand_near_hostile(object *who) {
4101  int i, friendly = 0, player = 0, mflags;
4102  mapstruct *m;
4103  int16_t x, y;
4104 
4105  if (!who)
4106  return 0;
4107 
4108  if (who->type == PLAYER)
4109  player = 1;
4110  else
4111  friendly = QUERY_FLAG(who, FLAG_FRIENDLY);
4112 
4113  /* search adjacent squares */
4114  for (i = 1; i < 9; i++) {
4115  x = who->x+freearr_x[i];
4116  y = who->y+freearr_y[i];
4117  m = who->map;
4118  mflags = get_map_flags(m, &m, x, y, &x, &y);
4119  /* space must be blocked if there is a monster. If not
4120  * blocked, don't need to check this space.
4121  */
4122  if (mflags&P_OUT_OF_MAP)
4123  continue;
4124  if (OB_TYPE_MOVE_BLOCK(who, GET_MAP_MOVE_BLOCK(m, x, y)))
4125  continue;
4126 
4127  FOR_MAP_PREPARE(m, x, y, tmp) {
4128  if ((player || friendly)
4129  && QUERY_FLAG(tmp, FLAG_MONSTER)
4130  && !QUERY_FLAG(tmp, FLAG_UNAGGRESSIVE))
4131  return 1;
4132  else if (tmp->type == PLAYER) {
4133  /*don't let a hidden DM prevent you from hiding*/
4134  if (!QUERY_FLAG(tmp, FLAG_WIZ) || tmp->contr->hidden == 0)
4135  return 1;
4136  }
4137  } FOR_MAP_FINISH();
4138  }
4139  return 0;
4140 }
4141 
4168 int player_can_view(object *pl, object *op) {
4169  rv_vector rv;
4170  int dx, dy;
4171 
4172  if (!pl || !op)
4173  return 0;
4174 
4175  if (pl->type != PLAYER) {
4176  LOG(llevError, "player_can_view() called for non-player object\n");
4177  return -1;
4178  }
4179 
4180  op = HEAD(op);
4181  if (!get_rangevector(pl, op, &rv, 0x1))
4182  return 0;
4183 
4184  /* starting with the 'head' part, lets loop
4185  * through the object and find if it has any
4186  * part that is in the los array but isnt on
4187  * a blocked los square.
4188  * we use the archetype to figure out offsets.
4189  */
4190  while (op) {
4191  dx = rv.distance_x+op->arch->clone.x;
4192  dy = rv.distance_y+op->arch->clone.y;
4193 
4194  /* only the viewable area the player sees is updated by LOS
4195  * code, so we need to restrict ourselves to that range of values
4196  * for any meaningful values.
4197  */
4198  if (FABS(dx) <= (pl->contr->socket->mapx/2)
4199  && FABS(dy) <= (pl->contr->socket->mapy/2)
4200  && !pl->contr->blocked_los[dx+(pl->contr->socket->mapx/2)][dy+(pl->contr->socket->mapy/2)])
4201  return 1;
4202  op = op->more;
4203  }
4204  return 0;
4205 }
4206 
4220 static int action_makes_visible(object *op) {
4221  if (op->invisible && QUERY_FLAG(op, FLAG_ALIVE)) {
4222  if (QUERY_FLAG(op, FLAG_MAKE_INVIS))
4223  return 0;
4224 
4225  if (op->contr && op->contr->tmp_invis == 0)
4226  return 0;
4227 
4228  /* If monsters, they should become visible */
4229  if (op->hide || !op->contr || (op->contr && op->contr->tmp_invis)) {
4231  "You become %s!",
4232  op->hide ? "unhidden" : "visible");
4233  return 1;
4234  }
4235  }
4236  return 0;
4237 }
4238 
4267 int op_on_battleground(object *op, int *x, int *y, archetype **trophy) {
4268  FOR_BELOW_PREPARE(op, tmp) {
4269  if (QUERY_FLAG(tmp, FLAG_IS_FLOOR)) {
4270  if (QUERY_FLAG(tmp, FLAG_NO_PICK)
4271  && strcmp(tmp->name, "battleground") == 0
4272  && tmp->type == BATTLEGROUND
4273  && EXIT_X(tmp)
4274  && EXIT_Y(tmp)) {
4275  /*before we assign the exit, check if this is a teambattle*/
4276  if (EXIT_ALT_X(tmp) && EXIT_ALT_Y(tmp) && EXIT_PATH(tmp)) {
4277  object *invtmp;
4278 
4279  invtmp = object_find_by_type_and_slaying(op, FORCE, EXIT_PATH(tmp));
4280  if (invtmp != NULL) {
4281  if (x != NULL && y != NULL)
4282  *x = EXIT_ALT_X(tmp),
4283  *y = EXIT_ALT_Y(tmp);
4284  return 1;
4285  }
4286  }
4287  if (x != NULL && y != NULL)
4288  *x = EXIT_X(tmp),
4289  *y = EXIT_Y(tmp);
4290 
4291  /* If 'other_arch' is not specified, give a finger. */
4292  if (trophy != NULL) {
4293  if (tmp->other_arch) {
4294  *trophy = tmp->other_arch;
4295  } else {
4296  *trophy = find_archetype("finger");
4297  }
4298  }
4299  return 1;
4300  }
4301  }
4302  } FOR_BELOW_FINISH();
4303  /* If we got here, did not find a battleground */
4304  return 0;
4305 }
4306 
4317 void dragon_ability_gain(object *who, int atnr, int level) {
4318  treasurelist *trlist = NULL; /* treasurelist */
4319  treasure *tr; /* treasure */
4320  object *tmp, *skop; /* tmp. object */
4321  object *item; /* treasure object */
4322  char buf[MAX_BUF]; /* tmp. string buffer */
4323  int i = 0, j = 0;
4324 
4325  /* get the appropriate treasurelist */
4326  if (atnr == ATNR_FIRE)
4327  trlist = find_treasurelist("dragon_ability_fire");
4328  else if (atnr == ATNR_COLD)
4329  trlist = find_treasurelist("dragon_ability_cold");
4330  else if (atnr == ATNR_ELECTRICITY)
4331  trlist = find_treasurelist("dragon_ability_elec");
4332  else if (atnr == ATNR_POISON)
4333  trlist = find_treasurelist("dragon_ability_poison");
4334 
4335  if (trlist == NULL || who->type != PLAYER)
4336  return;
4337 
4338  // tr->magic is being used to define what level of the metabolism the ability is gained at.
4339  for (tr = trlist->items; tr != NULL && tr->magic != level; tr = tr->next)
4340  ;
4341  if (tr == NULL || tr->item == NULL) {
4342  /* LOG(llevDebug, "-> no more treasure for %s\n", change_resist_msg[atnr]); */
4343  return;
4344  }
4345 
4346  /* everything seems okay - now bring on the gift: */
4347  item = &(tr->item->clone);
4348 
4349  if (item->type == SPELL) {
4350  if (check_spell_known(who, item->name))
4351  return;
4352 
4355  "You gained the ability of %s",
4356  item->name);
4357  do_learn_spell(who, item, 0);
4358  return;
4359  }
4360 
4361  /* grant direct spell */
4362  if (item->type == SPELLBOOK) {
4363  if (!item->inv) {
4364  LOG(llevDebug, "dragon_ability_gain: Broken spellbook %s\n", item->name);
4365  return;
4366  }
4367  if (check_spell_known(who, item->inv->name))
4368  return;
4369  if (item->invisible) {
4372  "You gained the ability of %s",
4373  item->inv->name);
4374  do_learn_spell(who, item->inv, 0);
4375  return;
4376  }
4377  } else if (item->type == SKILL_TOOL && item->invisible) {
4378  if (item->subtype == SK_CLAWING && (skop = find_skill_by_name(who, item->skill)) != NULL) {
4379  /* should this perhaps be (skop->attackyp&item->attacktype) != item->attacktype ...
4380  * in this way, if the player is missing any of the attacktypes, he gets
4381  * them. As it is now, if the player has any that match the granted skill,
4382  * but not all of them, he gets nothing.
4383  */
4384  if (!(skop->attacktype&item->attacktype)) {
4385  /* Give new attacktype */
4386  skop->attacktype |= item->attacktype;
4387 
4388  /* always add physical if there's none */
4389  skop->attacktype |= AT_PHYSICAL;
4390 
4391  if (item->msg != NULL)
4394  item->msg);
4395 
4396  /* Give player new face */
4397  if (item->animation) {
4398  who->face = skop->face;
4399  who->animation = item->animation;
4400  who->anim_speed = item->anim_speed;
4401  who->last_anim = 0;
4402  who->state = 0;
4403  animate_object(who, who->direction);
4404  }
4405  }
4406  }
4407  } else if (item->type == FORCE) {
4408  /* forces in the treasurelist can alter the player's stats */
4409  object *skin;
4410 
4411  /* first get the dragon skin force */
4412  skin = object_find_by_arch_name(who, "dragon_skin_force");
4413  if (skin == NULL)
4414  return;
4415 
4416  /* adding new spellpath attunements */
4417  if (item->path_attuned > 0 && !(skin->path_attuned&item->path_attuned)) {
4418  skin->path_attuned |= item->path_attuned; /* add attunement to skin */
4419 
4420  /* print message */
4421  snprintf(buf, sizeof(buf), "You feel attuned to ");
4422  for (i = 0, j = 0; i < NRSPELLPATHS; i++) {
4423  if (item->path_attuned&(1<<i)) {
4424  if (j)
4425  strcat(buf, " and ");
4426  else
4427  j = 1;
4428  strcat(buf, spellpathnames[i]);
4429  }
4430  }
4431  strcat(buf, ".");
4434  buf);
4435  }
4436 
4437  /* evtl. adding flags: */
4438  if (QUERY_FLAG(item, FLAG_XRAYS))
4439  SET_FLAG(skin, FLAG_XRAYS);
4440  if (QUERY_FLAG(item, FLAG_STEALTH))
4441  SET_FLAG(skin, FLAG_STEALTH);
4442  if (QUERY_FLAG(item, FLAG_SEE_IN_DARK))
4443  SET_FLAG(skin, FLAG_SEE_IN_DARK);
4444 
4445  /* print message if there is one */
4446  if (item->msg != NULL)
4449  item->msg);
4450  } else {
4451  /* generate misc. treasure */
4452  char name[HUGE_BUF];
4453 
4454  tmp = arch_to_object(tr->item);
4455  query_short_name(tmp, name, HUGE_BUF);
4458  "You gained %s",
4459  name);
4460  tmp = object_insert_in_ob(tmp, who);
4461  if (who->type == PLAYER)
4462  esrv_send_item(who, tmp);
4463  }
4464 }
4465 
4475 void player_unready_range_ob(player *pl, object *ob) {
4476  int i;
4477 
4478  for (i = 0; i < static_cast<int>(range_size); i++) {
4479  if (pl->ranges[i] == ob) {
4480  pl->ranges[i] = NULL;
4481  if (pl->shoottype == i) {
4482  pl->shoottype = range_none;
4483  }
4484  }
4485  }
4486 }
4487 
4493 void player_set_state(player *pl, uint8_t state) {
4494 
4495  assert(pl);
4496  assert(state <= ST_CHANGE_PASSWORD_CONFIRM);
4497  pl->state = state;
4498 }
4499 
4507  SockList *sl;
4508  assert(pl);
4509  const uint8_t to_alloc = 5;
4511  if (pl->delayed_buffers_allocated >= UINT8_MAX - to_alloc) {
4512  LOG(llevError, "Delay buffer limit exceeded for %s\n", pl->ob->name);
4513  abort();
4514  }
4515  pl->delayed_buffers_allocated += to_alloc;
4516  pl->delayed_buffers = static_cast<SockList **>(realloc(pl->delayed_buffers, pl->delayed_buffers_allocated * sizeof(pl->delayed_buffers[0])));
4517  if (!pl->delayed_buffers) {
4518  LOG(llevError, "Unable to allocated %d delayed buffers, aborting\n", pl->delayed_buffers_allocated);
4520  }
4521  for (uint8_t s = pl->delayed_buffers_allocated - to_alloc; s < pl->delayed_buffers_allocated; s++) {
4522  pl->delayed_buffers[s] = static_cast<SockList *>(calloc(1, sizeof(SockList)));
4523  }
4524  }
4525  sl = pl->delayed_buffers[pl->delayed_buffers_used];
4526  pl->delayed_buffers_used++;
4527  SockList_Init(sl);
4528  return sl;
4529 }
4530 
4536  for (uint8_t buf = 0; buf < pl->delayed_buffers_used; buf++) {
4538  }
4539  pl->delayed_buffers_used = 0;
4540 }
4541 
4545 void player_start_repeat(player *pl, const char *action, repeat_cb cb) {
4546  if (pl->repeat_func_data) {
4547  free(pl->repeat_func_data);
4548  pl->repeat_func_data = NULL;
4549  }
4550  sstring old_action = pl->repeat_action;
4551  pl->repeat_action = add_string(action);
4552  if (old_action != pl->repeat_action) {
4553  // Action different from previous one, tell player about it.
4554  char buf[MAX_BUF];
4555  snprintf(buf, sizeof(buf), "You start %s.", action);
4557  }
4558  pl->repeat_func = cb;
4559  if (old_action)
4560  free_string(old_action);
4561 }
void account_char_remove(Account_Chars *chars, const char *pl_name)
This removes a character on this account.
Error, serious thing.
Definition: logger.h:11
uint8_t login_method
Login method this client is using.
Definition: newserver.h:132
object * object_find_by_flag_applied(const object *who, int flag)
Find applied object in inventory by flag.
Definition: object.cpp:4214
void spring_trap(object *trap, object *victim)
This function generalizes attacks by runes/traps.
Definition: rune.cpp:214
Fire north-west whatever the facing direction.
Definition: player.h:52
Use skill.
Definition: player.h:35
uint8_t not_permadeth
If true, death is non-permament.
Definition: global.h:263
void check_stat_bounds(living *stats, int8_t min_stat, int8_t max_stat)
Ensures that all stats (str/dex/con/wis/cha/int) are within the passed in range of min_stat and max_s...
Definition: living.cpp:354
const char * rules
Name of rules file.
Definition: global.h:280
#define MSG_TYPE_MISC
Messages that don&#39;t go elsewhere.
Definition: newclient.h:430
#define FLAG_NO_DROP
Object can&#39;t be dropped.
Definition: define.h:276
signed long object_sum_weight(object *op)
object_sum_weight() is a recursive function which calculates the weight an object is carrying...
Definition: object.cpp:553
int16_t gen_hp
Bonuses to regeneration speed of hp.
Definition: player.h:128
uint8_t delayed_buffers_allocated
Number of items in delayed_buffers_used.
Definition: player.h:226
char first_map_path[MAX_BUF]
The start-level.
Definition: init.cpp:120
#define FLAG_SEE_IN_DARK
if set ob not effected by darkness
Definition: define.h:325
int apply_manual(object *op, object *tmp, int aflag)
Main apply handler.
Definition: apply.cpp:259
Sound-related defines.
const char * determine_god(object *op)
Determines if op worships a god.
Definition: gods.cpp:55
object * ranges[range_size]
Object for each range.
Definition: player.h:118
living orig_stats
Permanent real stats of player.
Definition: player.h:169
static void restore_player(object *op)
Remove confusion, disease, and poison on death.
Definition: player.cpp:3476
#define FLAG_DAMNED
The object is very cursed.
Definition: define.h:305
#define FLAG_UNPAID
Object hasn&#39;t been paid for yet.
Definition: define.h:223
#define MOVE_WALK
Object walks.
Definition: define.h:398
#define UP_OBJ_FACE
Only thing that changed was the face.
Definition: object.h:533
#define MSG_TYPE_ADMIN_LOGIN
login messages/errors
Definition: newclient.h:519
#define MSG_TYPE_ATTRIBUTE_GOD
changing god info
Definition: newclient.h:611
#define ST_GET_PARTY_PASSWORD
Player tried to join a password-protected party.
Definition: define.h:570
see doc/Developers/objects
Definition: object.h:113
#define ATNR_ELECTRICITY
Definition: attack.h:50
#define EVENT_REMOVE
A Player character has been removed.
Definition: events.h:67
#define MSG_TYPE_ITEM
Item related information.
Definition: newclient.h:429
int change_skill(object *who, object *new_skill, int flag)
This changes the object&#39;s skill to new_skill.
Definition: skill_util.cpp:357
Spell-related defines: spellpath, subtypes, ...
void fire(object *op, int dir)
Received a fire command for the player - go and do it.
Definition: player.cpp:2410
uint8_t stat_loss_on_death
If true, chars lose a random stat when they die.
Definition: global.h:257
void get_name(object *op)
Waiting for the player&#39;s name.
Definition: player.cpp:886
See Key.
Definition: object.h:132
int apply_container(object *op, object *sack, int aflags)
Handle apply on containers.
Definition: container.cpp:203
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.cpp:691
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.cpp:2293
uint8_t max_stat
Maximum stat value - 255 should be sufficient.
Definition: global.h:325
void enter_exit(object *op, object *exit_ob)
Tries to move &#39;op&#39; to exit_ob.
Definition: server.cpp:727
const char *const short_stat_name[NUM_STATS]
Short name of stats.
Definition: living.cpp:194
This is used by get_rangevector to determine where the other creature is.
Definition: map.h:375
struct archetype * arch
Pointer to archetype.
Definition: object.h:424
float last_weapon_sp
if diff than weapon_sp, update client.
Definition: player.h:158
void leave(player *pl, int draw_exit)
Player logs out, or was disconnected.
Definition: server.cpp:1308
object * check_spell_known(object *op, const char *name)
Checks to see if player knows the spell.
Definition: spell_util.cpp:394
Definition: living.h:14
Standard mode/.
Definition: player.h:58
player * add_player(socket_struct *ns, int flags)
Tries to add player on the connection passwd in ns.
Definition: player.cpp:468
void cast_dust(object *op, object *throw_ob, int dir)
Handles op throwing objects of type &#39;DUST&#39;.
Definition: player.cpp:3953
uint32_t hidden
If True, player (DM) is hidden from view.
Definition: player.h:149
void remove_door(object *op)
Remove non locked doors.
Definition: time.cpp:38
int account_remove_player(const char *account_name, const char *player_name)
Removes a player name from an account.
Definition: account.cpp:474
char * account_name
Name of the account logged in on this socket.
Definition: newserver.h:130
#define PU_CONTAINER
Definition: define.h:143
object * object_get_owner(object *op)
Returns the object which this object marks as being the owner.
Definition: object.cpp:789
void SockList_Init(SockList *sl)
Initializes the SockList instance.
Definition: lowlevel.cpp:55
void esrv_send_item(object *pl, object *op)
Sends item&#39;s info to player.
Definition: main.cpp:354
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.cpp:2622
static void kill_player_not_permadeath(object *op)
Kills a player in non-permadeath mode.
Definition: player.cpp:3595
void animate_object(object *op, int dir)
Updates the face-variable of an object.
Definition: anim.cpp:44
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.cpp:58
#define EXIT_ALT_Y(xyz)
Definition: define.h:444
void play_again(object *op)
Ask the player whether to play again or disconnect.
Definition: player.cpp:908
#define NDI_ALL
Inform all players of this message.
Definition: newclient.h:271
float weapon_speed_left
How much speed is left to spend this round.
Definition: object.h:340
#define PU_DEBUG
Definition: define.h:108
void add_statbonus(object *op)
Adds stat-bonuses given by the class which the player has chosen.
Definition: living.cpp:868
uint32_t last_path_attuned
Last spell attunment sent to client.
Definition: player.h:162
int8_t direction
Means the object is moving that way.
Definition: object.h:344
#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.cpp:685
#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:433
void change_luck(object *op, int value)
Alter the object&#39;s luck.
Definition: living.cpp:796
#define MSG_TYPE_ITEM_ADD
Item added to inventory.
Definition: newclient.h:680
void SockList_ResetRead(SockList *sl)
Resets the length of the stored data for reading.
Definition: lowlevel.cpp:83
#define ATNR_FIRE
Definition: attack.h:49
#define MSG_TYPE_COMMAND_FAILURE
Failed result from command.
Definition: newclient.h:552
std::vector< archetype * > players
Definition: player.cpp:501
#define MSG_TYPE_ITEM_INFO
Information related to items.
Definition: newclient.h:682
#define FLAG_USE_ARMOUR
(Monster) can wear armour/shield/helmet
Definition: define.h:283
#define BALSL_NUMBER_LOSSES_RATIO
Definition: config.h:143
#define strdup_local
Definition: compat.h:29
Defines various flags that both the new client and new server use.
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...) PRINTF_ARGS(6
void drain_wand_charge(object *wand)
Drains a charge from a wand.
Definition: spell_util.cpp:786
static void loot_object(object *op)
Grab and destroy some treasure.
Definition: player.cpp:3437
int16_t grace
Grace.
Definition: living.h:44
void player_set_own_title(struct player *pl, const char *title)
Sets the custom title.
Definition: player.cpp:273
See Food.
Definition: object.h:117
SockList * player_get_delayed_buffer(player *pl)
Get a delayed socket buffer, that will be sent after the player&#39;s tick is complete.
Definition: player.cpp:4506
#define PU_STOP
Definition: define.h:110
int player_can_view(object *pl, object *op)
Check the player los field for viewability of the object op.
Definition: player.cpp:4168
See Projectile.
Definition: object.h:122
#define FLAG_FRIENDLY
Will help players.
Definition: define.h:233
int push_ob(object *who, int dir, object *pusher)
Something is pushing some other object.
Definition: move.cpp:434
#define FLAG_IS_FLOOR
Can&#39;t see what&#39;s underneath this object.
Definition: define.h:290
archetype * find_archetype(const char *name)
Definition: assets.cpp:270
uint32_t peaceful
If set, won&#39;t attack friendly creatures.
Definition: player.h:148
void key_confirm_quit(object *op, char key)
We receive the reply to the &#39;quit confirmation&#39; message.
Definition: player.cpp:1599
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.cpp:1968
#define PU_SHIELD
Definition: define.h:122
void fix_object(object *op)
Updates all abilities given by applied objects in the inventory of the given object.
Definition: living.cpp:1132
const char * i18n(const object *who, const char *code)
Translate a message in the appropriate language.
Definition: languages.cpp:42
void object_set_msg(object *op, const char *msg)
Set the message field of an object.
Definition: object.cpp:4796
No range selected.
Definition: player.h:30
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.cpp:1818
bool(* repeat_cb)(player *, void *data)
Definition: player.h:104
#define NDI_BROWN
Sienna.
Definition: newclient.h:258
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.cpp:1317
#define MSG_TYPE_SPELL
Spell related info.
Definition: newclient.h:428
player * first_player
First player.
Definition: init.cpp:106
#define SOUND_TYPE_GROUND
Definition: newclient.h:352
object * object_find_by_type_without_flags(const object *who, int type, int *flags, int num_flags)
Find an object in inventory that does not have any of the provided flags set.
Definition: object.cpp:3989
int16_t maxgrace
Maximum grace.
Definition: living.h:45
int save_player(object *op, int flag)
Saves a player to disk.
Definition: login.cpp:239
int level
Definition: readable.cpp:1561
object * get_nearest_player(object *mon)
Finds the nearest visible player or player-friendly for some object.
Definition: player.cpp:548
Number of statistics.
Definition: living.h:18
const char * playerdir
Where the player files are.
Definition: global.h:251
const char * motd
Name of the motd file.
Definition: global.h:279
static int similar_direction(int a, int b)
Is direction a similar to direction b? Find out in this exciting function below.
Definition: player.cpp:2288
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.cpp:4317
#define PU_KEY
Definition: define.h:128
object * object_find_by_name(const object *who, const char *name)
Finds an object in inventory name.
Definition: object.cpp:3941
#define HUGE_BUF
Used for messages - some can be quite long.
Definition: define.h:37
#define SET_ANIMATION(ob, newanim)
Definition: global.h:164
void esrv_update_item(int flags, object *pl, object *op)
Updates object *op for player *pl.
Definition: main.cpp:359
See Spellbook.
Definition: object.h:208
void enter_player_maplevel(object *op)
Move a player to its stored map level.
Definition: server.cpp:682
See Money.
Definition: object.h:142
partylist * party
Party this player is part of.
Definition: player.h:205
object * more
Pointer to the rest of a large body of objects.
Definition: object.h:303
sstring slaying
Which race to do double damage to.
Definition: object.h:327
#define NDI_BLUE
Actually, it is Dodger Blue.
Definition: newclient.h:251
sstring add_string(const char *str)
Share a string.
Definition: shstr.cpp:137
int32_t value
How much money it is worth (or contains)
Definition: object.h:360
#define ST_CHANGE_PASSWORD_CONFIRM
Player is confirming new password.
Definition: define.h:573
int8_t luck
Affects thaco and ac from time to time.
Definition: living.h:39
Socket structure, represents a client-server connection.
Definition: newserver.h:93
#define PREFER_LOW
Definition: define.h:585
#define ST_CONFIRM_PASSWORD
New character, confirm password.
Definition: define.h:569
See Rune.
Definition: object.h:245
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.cpp:236
void remove_friendly_object(object *op)
Removes the specified object from the linked list of friendly objects.
Definition: friend.cpp:52
#define IS_WEAPON(op)
Definition: define.h:163
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: player.cpp:288
void esrv_send_inventory(object *pl, object *op)
Sends inventory of a container.
Definition: item.cpp:316
void change_exp(object *op, int64_t exp, const char *skill_name, int flag)
Changes experience to a player/monster.
Definition: living.cpp:2179
int8_t blocked_los[MAP_CLIENT_X][MAP_CLIENT_Y]
Array showing what spaces the player can see.
Definition: player.h:180
#define FLAG_CONFUSED
Will also be unable to cast spells.
Definition: define.h:299
#define FLAG_STEALTH
Will wake monsters with less range.
Definition: define.h:300
void key_roll_stat(object *op, char key)
Player is currently swapping stats.
Definition: player.cpp:1218
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.cpp:164
const char * party_get_password(const partylist *party)
Returns the party&#39;s password.
Definition: party.cpp:232
See Rod.
Definition: object.h:114
#define EVENT_LOGIN
Player login.
Definition: events.h:57
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.cpp:2103
int16_t y
Position in the map for this object.
Definition: object.h:335
const char *const drain_msg[NUM_STATS]
Message when a player is drained of a stat.
Definition: living.cpp:139
int8_t magic
Any magical bonuses to this item.
Definition: object.h:358
#define SOUND_TYPE_LIVING
Definition: newclient.h:349
#define FLAG_USE_WEAPON
(Monster) can wield weapons
Definition: define.h:284
int hideability(object *ob)
Look at the surrounding terrain to determine the hideability of this object.
Definition: player.cpp:4018
uint32_t mode
Mode of player for pickup.
Definition: player.h:125
uint16_t material
What materials this object consist of.
Definition: object.h:357
void confirm_password(object *op)
Ask the player to confirm her password during creation.
Definition: player.cpp:1011
sstring add_refcount(sstring str)
Like add_string(), but the string is already a shared string.
Definition: shstr.cpp:224
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.cpp:1485
Fire three arrows in a cone.
Definition: player.h:44
void SockList_AddInt(SockList *sl, uint32_t data)
Adds a 32 bit value.
Definition: lowlevel.cpp:127
#define OUT_OF_REAL_MAP(M, X, Y)
Checks if a square is out of the map.
Definition: map.h:220
Misc items.
Definition: player.h:33
enum Sock_Status status
Definition: newserver.h:94
See Drink.
Definition: object.h:162
#define object_was_destroyed(op, old_tag)
Checks if an object still exists.
Definition: object.h:70
#define TRUE
Definition: compat.h:11
#define PU_NOTHING
Definition: define.h:106
#define PU_FLESH
Definition: define.h:142
#define PU_FOOD
Definition: define.h:115
void party_leave(object *op)
Makes a player leave his party.
Definition: party.cpp:123
MoveType move_on
Move types affected moving on to this space.
Definition: object.h:439
object * chosen_skill
The skill chosen to use.
Definition: object.h:396
#define MAX(x, y)
Definition: compat.h:24
#define MSG_TYPE_ITEM_REMOVE
Item removed from inv.
Definition: newclient.h:679
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.cpp:825
int swap_first
First stat player has selected to swap.
Definition: player.h:168
void dead_player(object *op)
Kill a player on a permanent death server with resurrection.
char title[BIG_NAME]
Default title, like fighter, wizard, etc.
Definition: player.h:186
int16_t x
Definition: object.h:335
Use keys in inventory and active key rings.
Definition: player.h:67
Fire three arrows in the same direction.
Definition: player.h:43
animal &#39;body parts&#39; -b.t.
Definition: object.h:192
Global type definitions and header inclusions.
#define safe_strncpy
Definition: compat.h:27
struct player * contr
Pointer to the player which control this object.
Definition: object.h:284
#define PU_NEWMODE
Definition: define.h:111
int8_t Con
Use
Definition: living.h:36
void pets_terminate_all(object *owner)
Removes all pets someone owns.
Definition: pets.cpp:242
#define ST_ROLL_STAT
New character, rolling stats.
Definition: define.h:564
object * object_find_by_arch_name(const object *who, const char *name)
Find object in inventory by archetype name.
Definition: object.cpp:4237
int distance_y
Y delta.
Definition: map.h:378
static struct Command_Line_Options options[]
Actual valid command line options.
Definition: init.cpp:386
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.cpp:308
int8_t levgrace[11]
What grace bonus the player gained on that level.
Definition: player.h:190
#define ST_PLAYING
Usual state.
Definition: define.h:562
#define PU_MISSILEWEAPON
Definition: define.h:130
#define NDI_DK_ORANGE
DarkOrange2.
Definition: newclient.h:252
uint8_t anim_speed
Ticks between animation-frames.
Definition: object.h:429
int handle_newcs_player(object *op)
Handles commands the player can send us, and various checks on invisibility, golem and such...
Definition: player.cpp:3100
int object_matches_pickup_mode(const object *item, int mode)
Checks if an item matches a specific pickup mode.
Definition: c_object.cpp:608
char * host
Which host it is connected from (ip address).
Definition: newserver.h:104
See Wand & Staff.
Definition: object.h:225
#define MSG_TYPE_APPLY
Applying objects.
Definition: newclient.h:425
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.cpp:2244
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.cpp:4143
#define FOR_OB_AND_BELOW_FINISH()
Finishes FOR_OB_AND_BELOW_PREPARE().
Definition: define.h:777
void set_first_map(object *op)
This loads the first map an puts the player on it.
Definition: player.cpp:402
void esrv_add_spells(player *pl, object *spell)
This tells the client to add the spell *spell, if spell is NULL, then add all spells in the player&#39;s ...
Definition: request.cpp:1994
uint16_t emergency_y
Coordinates to use on that map.
Definition: global.h:301
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.cpp:218
#define PU_CLOAK
Definition: define.h:127
#define FLAG_REMOVED
Object is not in any map or invenory.
Definition: define.h:219
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:206
int32_t weight
Attributes of the object.
Definition: object.h:375
void events_execute_global_event(int eventcode,...)
Execute a global event.
Definition: events.cpp:30
object * transport
Transport the player is in.
Definition: player.h:216
static int player_attack_door(object *op, object *door)
Player is "attacking" a door.
Definition: player.cpp:2564
#define FLAG_CAN_ROLL
Object can be rolled.
Definition: define.h:241
Account_Chars * account_chars
Detailed information on characters on this account.
Definition: newserver.h:131
#define FLAG_KNOWN_MAGICAL
The object is known to be magical.
Definition: define.h:307
int16_t bed_x
Definition: player.h:113
static std::shared_ptr< inja::Environment > env
Rendering environment.
Definition: mapper.cpp:2222
Clawing.
Definition: skills.h:50
#define SOUND_TYPE_ITEM
Definition: newclient.h:351
repeat_cb repeat_func
If not NULL, automatically repeat the action repeat_func until interrupted.
Definition: player.h:231
#define NDI_NAVY
Definition: newclient.h:248
rangetype shoottype
Which range-attack is being used by player.
Definition: player.h:114
#define FIND_PLAYER_PARTIAL_NAME
Find on partial name.
Definition: player.h:242
#define NROFATTACKS
Definition: attack.h:15
#define MOVE_ALL
Mask of all movement types.
Definition: define.h:404
uint8_t run_away
Monster runs away if it&#39;s hp goes below this percentage.
Definition: object.h:394
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.cpp:2107
int32_t last_weight_limit
Last weight limit transmitted to client.
Definition: player.h:161
AssetsManager * getManager()
Definition: assets.cpp:309
void pets_control_golem(object *op, int dir)
Makes the golem go in specified direction.
Definition: pets.cpp:643
Allows the use of a skill.
Definition: object.h:194
#define MIN_STAT
The minimum legal value of any stat.
Definition: define.h:33
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.cpp:2322
#define FLAG_UNDEAD
Monster is undead.
Definition: define.h:257
void free_string(sstring str)
This will reduce the refcount, and if it has reached 0, str will be freed.
Definition: shstr.cpp:294
const char * news
Name of news file.
Definition: global.h:281
#define FLAG_READY_SKILL
(Monster or Player) has a skill readied
Definition: define.h:321
void apply_changes_to_player(object *pl, object *change, int limit_stats)
Applies (race) changes to a player.
Definition: apply.cpp:1325
See Trap.
Definition: object.h:246
method_ret ob_process(object *op)
Processes an object, giving it the opportunity to move or react.
Definition: ob_methods.cpp:67
#define MAP_IN_MEMORY
Map is fully loaded.
Definition: map.h:129
int16_t level
Level of creature or object.
Definition: object.h:361
void esrv_new_player(player *pl, uint32_t weight)
Tells the client that here is a player it should start using.
Definition: request.cpp:1008
int object_matches_string(object *pl, object *op, const char *name)
This is a subset of the parse_id command.
Definition: object.cpp:4559
int16_t sp
Spell points.
Definition: living.h:42
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.cpp:236
static void flee_player(object *op)
The player is scared, and should flee.
Definition: player.cpp:1672
int is_identifiable_type(const object *op)
Return true if this item&#39;s type is one that cares about whether or not it&#39;s been identified – e...
Definition: item.cpp:1333
#define MSG_TYPE_ATTRIBUTE_BAD_EFFECT_END
End of a bad effect.
Definition: newclient.h:602
void object_free(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.cpp:1577
player * next
Pointer to next player, NULL if this is last.
Definition: player.h:108
One party.
Definition: party.h:10
#define MSG_TYPE_COMMAND
Responses to commands, eg, who.
Definition: newclient.h:420
int move_player(object *op, int dir)
Move player in the given direction.
Definition: player.cpp:2962
#define PU_BOOTS
Definition: define.h:125
See Shooting Weapon.
Definition: object.h:123
object * object_find_by_type_subtype(const object *who, int type, int subtype)
Find object in inventory.
Definition: object.cpp:4286
char maplevel[MAX_BUF]
On which level is the player?
Definition: player.h:111
uint8_t hide
The object is hidden, not invisible.
Definition: object.h:397
int check_pick(object *op)
Sees if there is stuff to be picked up/picks up stuff, for players only.
Definition: player.cpp:1731
#define FLAG_ALIVE
Object can fight (or be fought)
Definition: define.h:217
int16_t resist[NROFATTACKS]
Resistance adjustments for attacks.
Definition: object.h:351
#define PU_CURSED
Definition: define.h:144
#define ADD_PLAYER_NO_STATS_ROLL
Stats provided from client.
Definition: player.h:254
uint32_t do_los
If true, need to call update_los() in draw(), and clear.
Definition: player.h:143
#define MSG_TYPE_VICTIM
Something bad is happening to the player.
Definition: newclient.h:433
uint16_t last_item_power
Last value for item_power.
Definition: player.h:166
#define ATNR_COLD
Definition: attack.h:51
int get_thaco_bonus(int stat)
Definition: living.cpp:2369
void create_treasure(treasurelist *t, object *op, int flag, int difficulty, int tries)
This calls the appropriate treasure creation function.
Definition: treasure.cpp:287
int16_t last_resist[NROFATTACKS]
last resist values sent to client.
Definition: player.h:176
The archetype structure is a set of rules on how to generate and manipulate objects which point to ar...
Definition: object.h:483
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.cpp:4729
void roll_again(object *op)
Ask the player what to do with the statistics.
Definition: player.cpp:1146
sstring repeat_action
Shared string with textual description of current repeat action (e.g.
Definition: player.h:232
void player_set_state(player *pl, uint8_t state)
Set the player&#39;s state to the specified one.
Definition: player.cpp:4493
sstring materialname
Specific material name.
Definition: object.h:356
void send_query(socket_struct *ns, uint8_t flags, const char *text)
Asks the client to query the user.
Definition: request.cpp:745
sstring name
More definite name, like "generate_kobold".
Definition: object.h:484
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.cpp:202
battleground, by Andreas Vogl
Definition: object.h:168
#define MSG_TYPE_COMMAND_SUCCESS
Successful result from command.
Definition: newclient.h:551
#define MSG_TYPE_COMMAND_ERROR
Bad syntax/can&#39;t use command.
Definition: newclient.h:550
#define PU_SKILLSCROLL
Definition: define.h:136
int8_t Dex
Use
Definition: living.h:36
uint8_t search_items
Search_items command.
Definition: global.h:268
player * find_player_socket(const socket_struct *ns)
Return a player for a socket structure.
Definition: player.cpp:123
float speed
Frequency of object &#39;moves&#39; relative to server tick rate.
Definition: object.h:337
int32_t carrying
How much weight this object contains.
Definition: object.h:377
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.cpp:1294
void command_search_items(object *op, const char *params)
&#39;search-items&#39; command.
Definition: c_object.cpp:2429
See Special Key.
Definition: object.h:129
int stand_near_hostile(object *who)
Determine if who is standing near a hostile creature.
Definition: player.cpp:4100
object * arch_to_object(archetype *at)
Creates and returns a new object which is a copy of the given archetype.
Definition: arch.cpp:227
#define FLAG_CAN_USE_SKILL
The monster can use skills.
Definition: define.h:309
#define MOVE_FLY_LOW
Low flying object.
Definition: define.h:399
int roll_stat(void)
This rolls four 1-6 rolls and sums the best 3 of the 4.
Definition: player.cpp:1043
char path[HUGE_BUF]
Filename of the map.
Definition: map.h:360
#define ADD_PLAYER_NEW
Name/password provided, so skip to roll stats.
Definition: player.h:252
void fix_luck(void)
Fixes luck of players, slowly move it towards 0.
Definition: player.cpp:3932
void player_start_repeat(player *pl, const char *action, repeat_cb cb)
Start repeating an action.
Definition: player.cpp:4545
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.cpp:276
void drain_rod_charge(object *rod)
Drain charges from a rod.
Definition: spell_util.cpp:776
#define SET_FLAG(xyz, p)
Definition: define.h:384
int hide(object *op, object *skill)
Main hide handling.
Definition: skills.cpp:505
#define FLAG_UNAGGRESSIVE
Monster doesn&#39;t attack players.
Definition: define.h:259
#define QUERY_FLAG(xyz, p)
Definition: define.h:386
#define FLAG_USE_SHIELD
Can this creature use a shield?
Definition: define.h:224
#define MSG_TYPE_ADMIN_PLAYER
Player coming/going/death.
Definition: newclient.h:515
int get_dex_bonus(int stat)
Definition: living.cpp:2365
int8_t Wis
Use
Definition: living.h:36
#define PU_ARROW
Definition: define.h:120
sstring anim_suffix
Used to determine combined animations.
Definition: object.h:324
int blocked_link(object *ob, mapstruct *m, int16_t sx, int16_t sy)
Returns true if the given coordinate is blocked except by the object passed is not blocking...
Definition: map.cpp:354
void SockList_Term(SockList *sl)
Frees all resources allocated by a SockList instance.
Definition: lowlevel.cpp:65
#define ARCH_DEPLETION
Archetype for depletion.
Definition: object.h:592
void fix_weight(void)
Check recursively the weight of all players, and fix what needs to be fixed.
Definition: player.cpp:3916
void player_map_change_common(object *op, mapstruct *const oldmap, mapstruct *const newmap)
Definition: server.cpp:282
Map builder.
Definition: player.h:36
#define MSG_TYPE_ATTRIBUTE
Changes to attributes (stats, resistances, etc)
Definition: newclient.h:421
void account_char_save(Account_Chars *chars)
Saves the character information for the given account.
void query_name(const object *op, char *buf, size_t size)
Describes an item.
Definition: item.cpp:594
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.cpp:1545
#define FLAG_IDENTIFIED
Item is identifiable (e.g.
Definition: define.h:248
short freearr_x[SIZEOFFREE]
X offset when searching around a spot.
Definition: object.cpp:299
#define EVENT_BORN
A new character has been created.
Definition: events.h:52
#define MOVE_FLYING
Combo of fly_low and fly_high.
Definition: define.h:401
#define FOR_INV_FINISH()
Finishes FOR_INV_PREPARE().
Definition: define.h:700
Control golem.
Definition: player.h:34
uint32_t last_character_flags
Last character flags (CS_STAT_CHARACTER_FLAGS) sent to client.
Definition: player.h:165
socket_struct * socket
Socket information for this player.
Definition: player.h:109
sstring msg
If this is a book/sign/magic mouth/etc.
Definition: object.h:330
uint32_t golem_count
To track the golem.
Definition: player.h:121
char password[16]
2 (seed) + 11 (crypted) + 1 (EOS) + 2 (safety) = 16
Definition: player.h:195
Rejoin if party exists.
Definition: player.h:100
uint8_t balanced_stat_loss
If true, Death stat depletion based on level etc.
Definition: global.h:262
int has_carried_lights(const object *op)
Checks if op has a light source.
Definition: los.cpp:346
Try to find an arrow matching the target.
Definition: player.h:53
sstring race
Human, goblin, dragon, etc.
Definition: object.h:326
This is a game-map.
Definition: map.h:320
const Animations * animation
Animation of this item, NULL if not animated.
Definition: object.h:428
#define NDI_GREEN
SeaGreen.
Definition: newclient.h:253
objectlink * get_friends_of(const object *owner)
Get a list of friendly objects for the specified owner.
Definition: friend.cpp:117
#define PU_INHIBIT
Definition: define.h:109
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.cpp:489
int distance_x
X delta.
Definition: map.h:377
language_t i18n_get_language_by_code(const char *code)
Find the identifier of a language from its code.
Definition: languages.cpp:74
#define PU_BOW
Definition: define.h:118
#define MSG_TYPE_COMMAND_NEWPLAYER
Create a new character - not really a command, but is responding to player input. ...
Definition: newclient.h:557
#define AP_NULL
Nothing specific.
Definition: define.h:594
#define ST_PLAY_AGAIN
Player left through a bed of reality, and can login again.
Definition: define.h:563
int playername_ok(const char *cp)
Is the player name valid.
Definition: player.cpp:257
Archetypes * archetypes()
Get archetypes.
Definition: AssetsManager.h:44
#define EXIT_PATH(xyz)
Definition: define.h:439
#define MSG_TYPE_SPELL_END
A spell ends.
Definition: newclient.h:670
int out_of_map(mapstruct *m, int x, int y)
Return 1 if coordinates X and Y are out of the map M, taking into account tiling. ...
Definition: map.cpp:2323
#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
player * get_player(player *p)
Create a player&#39;s object, initialize a player&#39;s structure.
Definition: player.cpp:285
#define CS_QUERY_SINGLECHAR
Single character response expected.
Definition: newclient.h:71
Definition: living.h:17
language_t language
The language the player wishes to use.
Definition: player.h:222
void remove_statbonus(object *op)
Subtracts stat-bonuses given by the class which the player has chosen.
Definition: living.cpp:845
int monster_can_detect_enemy(object *op, object *enemy, rv_vector *rv)
Determine if we can &#39;detect&#39; the enemy.
Definition: monster.cpp:2690
void SockList_AddString(SockList *sl, const char *data)
Adds a string without length.
Definition: lowlevel.cpp:157
static int turn_transport(object *transport, object *captain, int dir)
Try to turn a transport in the desired direction.
Definition: player.cpp:2929
uint8_t state
Input state of the player (name, password, etc).
Definition: player.h:133
#define FLAG_PARALYZED
Monster or player is paralyzed.
Definition: define.h:367
object * ob
The object representing the player.
Definition: player.h:179
#define PU_RATIO
Definition: define.h:113
uint32_t fire_on
Player should fire object, not move.
Definition: player.h:144
const char *const lose_msg[NUM_STATS]
Message when a player decreases permanently a stat.
Definition: living.cpp:172
const Face * face
Face with colors.
Definition: object.h:341
static archetype * get_player_archetype(archetype *at)
Get next player archetype from archetype list.
Definition: player.cpp:513
char killer[BIG_NAME]
Who killed this player.
Definition: player.h:192
static void update_transport_block(object *transport, int dir)
Update the move_type of a transport based on the direction.
Definition: player.cpp:2814
void hiscore_check(object *op, int quiet)
Checks if player should enter the hiscore, and if so writes her into the list.
Definition: hiscore.cpp:348
#define AP_NOPRINT
Don&#39;t print messages - caller will do that may be some that still print.
Definition: define.h:607
static void kill_player_permadeath(object *op)
Kills a player in permadeath mode.
Definition: player.cpp:3819
void send_news(const object *op)
Send the news to a player.
Definition: player.cpp:206
void remove_locked_door(object *op)
Same as remove_door() but for locked doors.
Definition: time.cpp:64
#define P_OUT_OF_MAP
This space is outside the map.
Definition: map.h:254
char spellparam[MAX_BUF]
What param to add to spells.
Definition: player.h:115
#define GET_MAP_MOVE_BLOCK(M, X, Y)
Gets the blocking state of a square.
Definition: map.h:195
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.cpp:443
uint16_t emergency_x
Definition: global.h:301
uint8_t last_anim
Last sequence used to draw face.
Definition: object.h:430
int move_ob(object *op, int dir, object *originator)
Op is trying to move in direction dir.
Definition: move.cpp:58
#define EXIT_X(xyz)
Definition: define.h:441
void do_learn_spell(object *op, object *spell, int special_prayer)
Actually makes op learn spell.
Definition: apply.cpp:146
See Potion.
Definition: object.h:116
mapstruct * first_map
First map.
Definition: init.cpp:107
#define PU_DRINK
Definition: define.h:116
uint32_t braced
Will not move if braced, only attack.
Definition: player.h:141
struct Settings settings
Global settings.
Definition: init.cpp:139
uint8_t state
How the object was last drawn (animation)
Definition: object.h:359
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.cpp:4267
#define FLAG_SCARED
Monster is scared (mb player in future)
Definition: define.h:258
float last_speed
Last speed as sent to client.
Definition: player.h:175
void roll_stats(object *op)
Roll the initial player&#39;s statistics.
Definition: player.cpp:1067
int32_t last_weight
Last weight as sent to client; -1 means do not send weight.
Definition: player.h:160
#define MSG_TYPE_SKILL_FAILURE
Failure in using skill.
Definition: newclient.h:626
object * object_new(void)
Grabs an object from the list of unused objects, makes sure it is initialised, and returns it...
Definition: object.cpp:1258
usekeytype usekeys
Method for finding keys for doors.
Definition: player.h:122
#define FLAG_XRAYS
X-ray vision.
Definition: define.h:288
float last_character_load
Last value sent to the client.
Definition: player.h:138
#define FREE_AND_CLEAR_STR(xyz)
Release the shared string, and set it to NULL.
Definition: global.h:200
int16_t bed_y
x,y - coordinates of respawn (savebed).
Definition: player.h:113
int random_roll(int min, int max, const object *op, int goodbad)
Roll a random number between min and max.
Definition: utils.cpp:42
void kill_player(object *op, const object *killer)
Handle a player&#39;s death.
Definition: player.cpp:3514
uint32_t tag_t
Object tag, unique during the whole game.
Definition: object.h:14
unapplymode unapply
Method for auto unapply.
Definition: player.h:123
int16_t dam
How much damage this object does when hitting.
Definition: living.h:46
#define AT_PHYSICAL
Basic attack (1)
Definition: attack.h:78
uint32_t pticks
Number of ticks since time reset.
Definition: time.cpp:47
See Spell.
Definition: object.h:219
uint32_t last_path_denied
Last spell denied sent to client.
Definition: player.h:164
int16_t gen_sp_armour
Penalty to sp regen from armour.
Definition: player.h:130
char savebed_map[MAX_BUF]
Map where player will respawn after death.
Definition: player.h:112
#define EVENT_PLAYER_DEATH
Global Death event.
Definition: events.h:66
#define HEAD(op)
Returns the head part of an object.
Definition: object.h:609
int get_randomized_dir(int dir)
Returns a random direction (1..8) similar to a given direction.
Definition: utils.cpp:412
#define MSG_TYPE_ADMIN_NEWS
Definition: newclient.h:514
void fatal(enum fatal_error err)
fatal() is meant to be called whenever a fatal signal is intercepted.
Definition: utils.cpp:590
uint32_t ticks_played
How many ticks this player has played.
Definition: player.h:224
#define FLAG_WIZ
Object has special privilegies.
Definition: define.h:218
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.cpp:3229
void set_player_socket(player *p, socket_struct *ns)
This copies the data from the socket into the player structure.
Definition: player.cpp:421
#define FLAG_BEEN_APPLIED
Object was ever applied, for identification purposes.
Definition: define.h:311
#define EXIT_ALT_X(xyz)
Definition: define.h:443
See Locked Door.
Definition: object.h:128
uint8_t listening
Which priority will be used in info_all.
Definition: player.h:135
#define MSG_TYPE_COMMAND_DEBUG
Various debug type commands.
Definition: newclient.h:549
living stats
Str, Con, Dex, etc.
Definition: object.h:378
static void fire_misc_object(object *op, int dir)
Fires a misc (wand/rod/horn) object in &#39;dir&#39;.
Definition: player.cpp:2358
#define BALSL_LOSS_CHANCE_RATIO
Definition: config.h:142
#define EXIT_Y(xyz)
Definition: define.h:442
void delete_character(const char *name)
Totally deletes a character.
Definition: login.cpp:88
living last_stats
Last stats as sent to client.
Definition: player.h:170
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
#define MSG_TYPE_ATTACK
Attack related messages.
Definition: newclient.h:426
#define NRSPELLPATHS
Number of spell paths.
Definition: spells.h:40
Standard mode, one random arrow.
Definition: player.h:42
#define ATNR_POISON
Definition: attack.h:57
#define IS_SHIELD(op)
Definition: define.h:170
See Door.
Definition: object.h:131
int16_t invisible
How much longer the object will be invis.
Definition: object.h:370
#define PU_READABLES
Definition: define.h:137
#define MSG_TYPE_ADMIN
Definition: newclient.h:418
int64_t last_skill_exp[MAX_SKILLS]
Last exp sent to client.
Definition: player.h:156
void add_friendly_object(object *op)
Add a new friendly object to the list of friendly objects.
Definition: friend.cpp:32
Fire north whatever the facing direction.
Definition: player.h:45
uint64_t price_base(const object *obj)
Price an item based on its value or archetype value, type, identification/BUC status, and other heuristics.
Definition: item.cpp:1507
void delete_map(mapstruct *m)
Frees the map, including the mapstruct.
Definition: map.cpp:1705
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.
size_t strlcpy(char *dst, const char *src, size_t size)
Portable implementation of strlcpy(3).
Definition: porting.cpp:222
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.cpp:2351
float speed_left
How much speed is left to spend this round.
Definition: object.h:338
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.cpp:3207
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.cpp:1177
#define MSG_TYPE_ATTRIBUTE_STAT_LOSS
Definition: newclient.h:604
struct mapstruct * map
Pointer to the map in which this object is present.
Definition: object.h:305
uint8_t mapx
Definition: newserver.h:120
Skill-related defines, including subtypes.
uint32_t last_path_repelled
Last spell repelled sent to client.
Definition: player.h:163
void player_unready_range_ob(player *pl, object *ob)
Unready an object for a player.
Definition: player.cpp:4475
int8_t levsp[11]
What sp bonus the player gained on that level.
Definition: player.h:189
void esrv_map_scroll(socket_struct *ns, int dx, int dy)
Definition: request.cpp:1753
const char * confdir
Configuration files.
Definition: global.h:248
int object_can_pick(const object *who, const object *item)
Finds out if an object can be picked up.
Definition: object.cpp:3852
See Container.
Definition: object.h:236
int is_true_undead(object *op)
Is the object a true undead?
Definition: player.cpp:4001
uint32_t in_memory
Combination of IN_MEMORY_xxx flags.
Definition: map.h:340
Various statistics of objects.
Definition: living.h:35
short freearr_y[SIZEOFFREE]
Y offset when searching around a spot.
Definition: object.cpp:305
bool shop_contains(object *ob)
Check if an object is in a shop.
Definition: map.cpp:2763
static const flag_definition flags[]
Flag mapping.
void SockList_AddChar(SockList *sl, unsigned char c)
Adds an 8 bit value.
Definition: lowlevel.cpp:106
treasurelist represents one logical group of items to be generated together.
Definition: treasure.h:85
#define FOR_MAP_FINISH()
Finishes FOR_MAP_PREPARE().
Definition: define.h:753
int8_t facing
Object is oriented/facing that way.
Definition: object.h:345
int check_race_and_class(living *stats, archetype *race, archetype *opclass)
This checks to see if the race and class are legal.
Definition: player.cpp:1435
#define FLAG_KNOWN_CURSED
The object is known to be cursed.
Definition: define.h:308
#define FLAG_CURSED
The object is cursed.
Definition: define.h:304
See Player.
Definition: object.h:112
See Poison Food.
Definition: object.h:118
struct treasurelist * randomitems
Items to be generated.
Definition: object.h:395
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.cpp:4059
#define FLAG_ANIMATE
The object looks at archetype for faces.
Definition: define.h:229
void clear_los(player *pl)
Clears/initialises the los-array associated to the player controlling the object. ...
Definition: los.cpp:270
static void swap_stat(object *op, int swap_second)
Player finishes selecting what stats to swap.
Definition: player.cpp:1160
sstring name_pl
The plural name of the object.
Definition: object.h:323
#define PU_MELEEWEAPON
Definition: define.h:131
Object structure, the core of Crossfire.
void query_base_name(const object *op, int plural, char *buf, size_t size)
Query a short name for the item.
Definition: item.cpp:692
Maximum, exclusive, value.
Definition: player.h:37
#define PREFER_HIGH
Definition: define.h:584
object * find_key(object *pl, object *container, object *door)
We try to find a key for the door as passed.
Definition: player.cpp:2482
static event_registration m
Definition: citylife.cpp:424
object * container
Current container being used.
Definition: object.h:299
#define object_decrease_nrof_by_one(xyz)
Definition: compat.h:32
#define MSG_TYPE_VICTIM_DIED
Player died!
Definition: newclient.h:695
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.cpp:51
#define FLAG_NEUTRAL
monster is from type neutral
Definition: define.h:349
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.cpp:2859
int get_rangevector_from_mapcoord(const mapstruct *m, int x, int y, const object *op2, rv_vector *retval)
This is basically the same as get_rangevector() above, but instead of the first parameter being an ob...
Definition: map.cpp:2590
#define RANDOM()
Definition: define.h:667
#define FREE_AND_COPY(sv, nv)
Release the shared string if not NULL, and make it a reference to nv.
Definition: global.h:206
treasure * next
Next treasure-item in a linked list.
Definition: treasure.h:69
Also see SKILL_TOOL (74) below.
Definition: object.h:148
object * get_nearest_criminal(object *mon)
Definition: player.cpp:591
const char * localdir
Read/write data files.
Definition: global.h:250
object * last_skill_ob[MAX_SKILLS]
Exp objects sent to client.
Definition: player.h:155
void send_rules(const object *op)
Send the rules to a player.
Definition: player.cpp:170
MoveType move_type
Type of movement this object uses.
Definition: object.h:436
void recursive_roll(object *op, int dir, object *pusher)
An object is pushed by another which is trying to take its place.
Definition: move.cpp:293
sstring name
The name of the object, obviously...
Definition: object.h:319
int8_t get_attr_value(const living *stats, int attr)
Gets the value of a stat.
Definition: living.cpp:313
#define SCRIPT_FIX_ALL
Definition: global.h:380
#define UPD_FACE
Definition: newclient.h:333
Only for debugging purposes.
Definition: logger.h:13
#define MSG_TYPE_ATTACK_NOATTACK
You avoid attacking.
Definition: newclient.h:654
uint32_t nrof
Number of objects.
Definition: object.h:342
#define MSG_TYPE_ADMIN_RULES
Definition: newclient.h:513
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.cpp:300
Hiding.
Definition: skills.h:21
uint32_t no_shout
if True, player is *not *able to use shout command.
Definition: player.h:150
uint8_t darkness
Indicates level of darkness of map.
Definition: map.h:341
int8_t Cha
Use
Definition: living.h:36
#define AC_PLAYER_STAT_NO_CHANGE
Do not make any stat adjustments.
Definition: define.h:620
#define SPELL_HIGHEST
Definition: spells.h:60
unsigned int distance
Distance, in squares.
Definition: map.h:376
int face_player(object *op, int dir)
Face player in the given direction.
Definition: player.cpp:3041
void object_set_enemy(object *op, object *enemy)
Sets the enemy of an object.
Definition: object.cpp:900
uint32_t run_on
Player should keep moving in dir until run is off.
Definition: player.h:145
#define MSG_TYPE_COMMAND_INFO
Generic info: resistances, etc.
Definition: newclient.h:547
#define CLEAR_FLAG(xyz, p)
Definition: define.h:385
treasure * items
Items in this list, linked.
Definition: treasure.h:92
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:348
void account_char_free(Account_Chars *chars)
This frees all data associated with the character information.
#define ADD_PLAYER_NO_MAP
Do not set the first map.
Definition: player.h:253
void get_password(object *op)
Waiting for the player&#39;s password.
Definition: player.cpp:897
bowtype_t bowtype
Which firemode?
Definition: player.h:116
int direction
General direction to the targer.
Definition: map.h:379
char search_str[MAX_BUF]
Item we are looking for.
Definition: player.h:213
int8_t ac
Armor Class, lower AC increases probability of not getting hit.
Definition: living.h:38
uint8_t delayed_buffers_used
Used items in delayed_buffers_used.
Definition: player.h:227
void do_some_living(object *op)
Regenerate hp/sp/gr, decreases food.
Definition: player.cpp:3298
player * find_player(const char *plname)
Find a player by her full name.
Definition: player.cpp:59
#define FLAG_NO_STRENGTH
Strength-bonus not added to wc/dam.
Definition: define.h:294
#define FLAG_APPLIED
Object is ready for use by living.
Definition: define.h:222
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.cpp:264
#define PU_SPELLBOOK
Definition: define.h:135
char * spellarg
Optional argument when casting obj::spell.
Definition: object.h:421
char first_map_ext_path[MAX_BUF]
Path used for per-race start maps.
Definition: init.cpp:121
int8_t Pow
Use
Definition: living.h:36
#define FLAG_LIFESAVE
Saves a players&#39; life once, then destr.
Definition: define.h:293
void object_update_speed(object *op)
Updates the speed of an object.
Definition: object.cpp:1334
treasurelist * find_treasurelist(const char *name)
Search for the given treasurelist by name.
Definition: assets.cpp:253
void send_delayed_buffers(player *pl)
Send all delayed buffers for a player.
Definition: player.cpp:4535
int16_t gen_sp
Bonuses to regeneration speed of sp.
Definition: player.h:129
#define ST_CHANGE_CLASS
New character, choosing class.
Definition: define.h:565
living last_applied_stats
Last applied stats sent to the client.
Definition: player.h:174
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.cpp:2522
#define MSG_TYPE_APPLY_SUCCESS
Was able to apply object.
Definition: newclient.h:639
object * inv
Pointer to the first object in the inventory.
Definition: object.h:298
int8_t levhp[11]
What hp bonus the player gained on that level.
Definition: player.h:188
#define FLAG_MAKE_INVIS
(Item) gives invisibility when applied
Definition: define.h:316
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.cpp:1936
int path_to_player(object *mon, object *pl, unsigned mindiff)
Returns the direction to the player, if valid.
Definition: player.cpp:659
#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:773
#define FLAG_STARTEQUIP
Object was given to player at start.
Definition: define.h:255
treasure is one element in a linked list, which together consist of a complete treasure-list.
Definition: treasure.h:63
#define FORCE_NAME
Definition: spells.h:169
#define PU_VALUABLES
Definition: define.h:117
void give_initial_items(object *pl, treasurelist *items)
Gives a new player her initial items.
Definition: player.cpp:792
Bow.
Definition: player.h:31
void make_visible(object *op)
Makes an object visible again.
Definition: player.cpp:3982
#define PU_MAGICAL
Definition: define.h:132
Don&#39;t generate bad/cursed items.
Definition: treasure.h:34
#define FIND_PLAYER_NO_HIDDEN_DM
Don&#39;t find hidden DMs.
Definition: player.h:243
void strip_endline(char *buf)
Removes endline from buffer (modified in place).
Definition: utils.cpp:314
static const int32_t MAX_FOOD
Definition: define.h:461
#define GET_MAP_OB(M, X, Y)
Gets the bottom object on a map.
Definition: map.h:173
int64_t exp
Experience.
Definition: living.h:47
#define MAX_SPACES
This is used to prevent infinite loops.
Definition: player.cpp:626
int get_dam_bonus(int stat)
Definition: living.cpp:2389
sstring skill
Name of the skill this object uses/grants.
Definition: object.h:329
#define PU_JEWELS
Definition: define.h:141
int16_t maxsp
Max spell points.
Definition: living.h:43
int allowed_class(const object *op)
Returns true if the given player is a legal class.
Definition: living.cpp:1661
uint32_t attacktype
Bitmask of attacks this object does.
Definition: object.h:352
#define FLAG_MONSTER
Will attack players.
Definition: define.h:232
void esrv_send_pickup(player *pl)
Sends the "pickup" state to pl if client wants it requested.
Definition: request.cpp:1880
Will unapply objects when there no choice to unapply.
Definition: player.h:76
#define MSG_TYPE_SKILL
Messages related to skill use.
Definition: newclient.h:424
void receive_play_again(object *op, char key)
Player replied to play again / disconnect.
Definition: player.cpp:961
int events_execute_object_event(object *op, int eventcode, object *activator, object *third, const char *message, int fix)
Execute an event on the specified object.
Definition: events.cpp:309
SockList ** delayed_buffers
Buffers which will be sent after the player&#39;s tick completes.
Definition: player.h:228
uint8_t set_title
Players can set thier title.
Definition: global.h:266
#define NDI_UNIQUE
Print immediately, don&#39;t buffer.
Definition: newclient.h:270
uint32_t tmp_invis
Will invis go away when we attack?
Definition: player.h:142
int is_wraith_pl(object *op)
Tests if a player is a wraith.
Definition: player.cpp:174
#define FLAG_READY_BOW
not implemented yet
Definition: define.h:287
static bool starving(object *op)
Definition: player.cpp:3287
#define MSG_SUBTYPE_NONE
Definition: newclient.h:439
Spells.
Definition: player.h:32
bool pick_up(object *op, object *alt)
Try to pick up an item.
Definition: c_object.cpp:470
C function wrappers to interact with assets.
#define CS_QUERY_HIDEINPUT
Hide input being entered.
Definition: newclient.h:72
player * find_player_partial_name(const char *plname)
Find a player by a partial name.
Definition: player.cpp:114
One player.
Definition: player.h:107
bool is_criminal(object *op)
Definition: player.cpp:313
#define PU_GLOVES
Definition: define.h:126
uint32_t has_hit
If set, weapon_sp instead of speed will count.
Definition: player.h:146
uint8_t magic
Max magic bonus to item If the entry is a list transition, &#39;magic&#39; contains the difficulty required t...
Definition: treasure.h:74
static const char * gravestone_text(object *op, char *buf2, int len)
Create a text for a player&#39;s gravestone.
Definition: player.cpp:3259
#define FLAG_WAS_WIZ
Player was once a wiz.
Definition: define.h:221
int absdir(int d)
Computes an absolute direction.
Definition: object.cpp:3699
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.cpp:163
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Constructs a loop iterating over all objects of a map tile.
Definition: define.h:746
void play_sound_map(int8_t sound_type, object *emitter, int dir, const char *action)
Plays a sound on a map.
Definition: sounds.cpp:113
int32_t food
How much food in stomach.
Definition: living.h:48
StringBuffer * buf
Definition: readable.cpp:1563
#define IS_ARMOR(op)
Definition: define.h:166
const char * invis_race
What race invisible to?
Definition: player.h:153
void clear_player(player *pl)
Clears data in player structure.
Definition: player.cpp:33
Structure containing object statistics.
int get_party_password(object *op, partylist *party)
Ask the player for the password of the party she wants to join.
Definition: player.cpp:1026
#define P_BLOCKSVIEW
This spot blocks the player&#39;s view.
Definition: map.h:229
struct archetype * item
Which item this link can be.
Definition: treasure.h:64
#define MSG_TYPE_ATTRIBUTE_RACE
Race-related changes.
Definition: newclient.h:598
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.cpp:4220
const char * unarmed_skill
Prefered skill to use in unarmed combat.
Definition: player.h:223
#define PU_ARMOUR
Definition: define.h:123
int16_t maxhp
Max hit points.
Definition: living.h:41
uint8_t subtype
Subtype of object.
Definition: object.h:349
uint16_t difficulty
What level the player should be to play here.
Definition: map.h:338
Only use keys in inventory.
Definition: player.h:66
void apply_map_builder(object *pl, int dir)
Global building function.
Definition: build_map.cpp:960
#define MAX_SKILLS
This is the maximum number of skills the game may handle.
Definition: skills.h:70
#define FOR_BELOW_PREPARE(op_, it_)
Constructs a loop iterating over all objects below an object.
Definition: define.h:727
void player_cancel_repeat(player *pl)
If the player is repeating an action, cancel it.
Definition: player.cpp:320
Contains the base information we use to make up a packet we want to send.
Definition: newclient.h:721
const char * sstring
Definition: sstring.h:2
char * emergency_mapname
Map to return players to in emergency.
Definition: global.h:300
#define P_IS_ALIVE
Something alive is on this space.
Definition: map.h:240
mapstruct * next
Next map, linked list.
Definition: map.h:321
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.cpp:2842
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.cpp:2085
int8_t Int
Use
Definition: living.h:36
int8_t wc
Weapon Class, lower WC increases probability of hitting.
Definition: living.h:37
#define ST_GET_NAME
Player just connected.
Definition: define.h:567
uint8_t roll_stat_points
How many stat points legacy (rolled) chars start with.
Definition: global.h:324
See Jewel.
Definition: object.h:172
void object_update(object *op, int action)
object_update() updates the array which represents the map.
Definition: object.cpp:1419
#define DETOUR_AMOUNT
This value basically determines how large a detour a monster will take from the direction path when l...
Definition: player.cpp:611
tag_t count
Unique object number for this object.
Definition: object.h:307
#define FLAG_UNIQUE
Item is really unique (UNIQUE_ITEMS)
Definition: define.h:275
petmode_t petmode
Which petmode?
Definition: player.h:117
#define FLAG_NO_PICK
Object can&#39;t be picked up.
Definition: define.h:226
#define PU_POTION
Definition: define.h:133
void enter_player_savebed(object *op)
This is a basic little function to put the player back to his savebed.
Definition: server.cpp:142
uint8_t mapy
How large a map the client wants.
Definition: newserver.h:120
#define PU_HELMET
Definition: define.h:121
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.cpp:518
#define FLAG_INV_LOCKED
Item will not be dropped from inventory.
Definition: define.h:317
player * find_player_options(const char *plname, int options, const mapstruct *map)
Find a player.
Definition: player.cpp:70
int die_roll(int num, int size, const object *op, int goodbad)
Roll a number of dice (2d3, 4d6).
Definition: utils.cpp:122
bool is_wraith
Whether this player is a wraith or not, initialized at load time.
Definition: player.h:229
#define BALSL_MAX_LOSS_RATIO
Definition: config.h:144
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.cpp:2038
int object_can_merge(object *ob1, object *ob2)
Examines the 2 objects given to it, and returns true if they can be merged together, including inventory.
Definition: object.cpp:433
#define AT_DEATH
Chance of instant death, otherwise nothing (131072) peterm@soda.berkeley.edu.
Definition: attack.h:95
#define PU_NOT_CURSED
Definition: define.h:140
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.cpp:209
uint8_t * faces_sent
This is a bitmap on sent face status.
Definition: newserver.h:100
object * object_find_by_type(const object *who, int type)
Find object in inventory.
Definition: object.cpp:3965
object clone
An object from which to do object_copy()
Definition: object.h:487
void move_player_attack(object *op, int dir)
The player is also actually going to try and move (not fire weapons).
Definition: player.cpp:2637
bool object_value_set(const object *op, const char *const key)
Determine if an extra value is set.
Definition: object.cpp:4361
void display_motd(const object *op)
Sends the message of the day to the player.
Definition: player.cpp:139
#define FOR_BELOW_FINISH()
Finishes FOR_BELOW_PREPARE().
Definition: define.h:734
int8_t Str
Use
Definition: living.h:36
uint8_t resurrection
Ressurection possible w/ permadeth on.
Definition: global.h:267
#define FOR_INV_PREPARE(op_, it_)
Constructs a loop iterating over the inventory of an object.
Definition: define.h:693
int cast_spell(object *op, object *caster, int dir, object *spell_ob, char *stringarg)
Main dispatch when someone casts a spell.
SockList inbuf
If we get an incomplete packet, this is used to hold the data.
Definition: newserver.h:103
void * repeat_func_data
Arguments to pass into repeat_func.
Definition: player.h:233
void apply_anim_suffix(object *who, const char *suffix)
Applies a compound animation to an object.
Definition: anim.cpp:150
int16_t hp
Hit Points.
Definition: living.h:40
#define MSG_TYPE_MOTD
Definition: newclient.h:417
uint32_t path_attuned
Paths the object is attuned to.
Definition: object.h:353
Generated items have the FLAG_STARTEQUIP.
Definition: treasure.h:33
#define PU_MAGIC_DEVICE
Definition: define.h:138
#define ST_GET_PASSWORD
Name entered, now for password.
Definition: define.h:568
party_rejoin_mode rejoin_party
Whether to rejoin or not party at login.
Definition: player.h:212
#define FLAG_FREED
Object is in the list of free objects.
Definition: define.h:220
object * enemy
Monster/player to follow even if not closest.
Definition: object.h:391
void Send_With_Handling(socket_struct *ns, SockList *sl)
Calls Write_To_Socket to send data to the client.
Definition: lowlevel.cpp:447
Definition: object.h:229
#define EVENT_DEATH
Player or monster dead.
Definition: events.h:33
void each(std::function< void(T *)> op)
Apply a function to each asset.
static int save_life(object *op)
Can the player be saved by an item?
Definition: player.cpp:3186