Crossfire Server, Trunk
player.cpp
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2014 Mark Wedel and the Crossfire Development Team
5  * Copyright (c) 1992 Frank Tore Johansen
6  *
7  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
8  * welcome to redistribute it under certain conditions. For details, please
9  * see COPYING and LICENSE.
10  *
11  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
12  */
13 
20 #include "global.h"
21 
22 #include <assert.h>
23 #include <ctype.h>
24 #include <math.h>
25 #include <stddef.h>
26 #include <stdlib.h>
27 #include <string.h>
28 
29 #ifndef WIN32 /* ---win32 remove headers */
30 #include <pwd.h>
31 #endif
32 
33 #include "server.h"
34 #include "living.h"
35 #include "object.h"
36 #include "shared/newclient.h"
37 #include "shop.h"
38 #include "skills.h"
39 #include "sounds.h"
40 #include "spells.h"
41 #include "sproto.h"
42 #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 
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  */
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) {
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)
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))
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) {
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  }
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) {
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)) {
864  }
865  /* lock all 'normal items by default */
866  else
868  } FOR_INV_FINISH(); /* for loop of objects in player inv */
869 
870  /* Need to set up the skill pointers */
872 
880  FOR_INV_FINISH();
881 }
882 
889 void get_name(object *op) {
891  send_query(op->contr->socket, 0, i18n(op, "What is your name?\n:"));
892 }
893 
900 void get_password(object *op) {
902  send_query(op->contr->socket, CS_QUERY_HIDEINPUT, i18n(op, "What is your password?\n:"));
903 }
904 
911 void play_again(object *op) {
912  SockList sl;
913 
914  op->contr->socket->status = Ns_Add;
916  op->chosen_skill = NULL;
917 
918  /*
919  * For old clients, ask if they want to play again.
920  * For clients with account support, just return to character seletion (see below).
921  */
922  if (op->contr->socket->login_method == 0) {
923  send_query(op->contr->socket, CS_QUERY_SINGLECHAR, i18n(op, "Do you want to play again (a/q)?"));
924  }
925  /* a bit of a hack, but there are various places early in th
926  * player creation process that a user can quit (eg, roll
927  * stats) that isn't removing the player. Taking a quick
928  * look, there are many places that call play_again without
929  * removing the player - it probably makes more sense
930  * to leave it to play_again to remove the object in all
931  * cases.
932  */
933  if (!QUERY_FLAG(op, FLAG_REMOVED))
934  object_remove(op);
935  /* Need to set this to null - otherwise, it could point to garbage,
936  * and draw() doesn't check to see if the player is removed, only if
937  * the map is null or not swapped out.
938  */
939  op->map = NULL;
940 
941  SockList_Init(&sl);
942  SockList_AddString(&sl, "player ");
943  SockList_AddInt(&sl, 0);
944  SockList_AddInt(&sl, 0);
945  SockList_AddInt(&sl, 0);
946  SockList_AddChar(&sl, 0);
947 
948  Send_With_Handling(op->contr->socket, &sl);
949  SockList_Term(&sl);
950 
951  if (op->contr->socket->login_method > 0) {
952  receive_play_again(op, 'a');
953  }
954 }
955 
964 void receive_play_again(object *op, char key) {
965  if (key == 'q' || key == 'Q') {
967  leave(op->contr, 0); /* ericserver will draw the message */
968  return;
969  } else if (key == 'a' || key == 'A') {
970  player *pl = op->contr;
971  const char *name = op->name;
972 
976  pl = get_player(pl);
977  op = pl->ob;
979  op->contr->password[0] = '~';
980  FREE_AND_CLEAR_STR(op->name);
981  FREE_AND_CLEAR_STR(op->name_pl);
982  if (pl->socket->login_method >= 1 && pl->socket->account_name != NULL) {
983  /* If we are using new login, we send the
984  * list of characters to the client - this should
985  * result in the client popping up this list so
986  * the player can choose which one to play - better
987  * than going to legacy login code.
988  * If the account_name is NULL, it means the client
989  * says it uses account but started playing without logging in.
990  */
991  send_account_players(pl->socket);
993  } else {
994  /* Lets put a space in here */
996  "\n");
997  get_name(op);
998  set_first_map(op);
999  }
1000  op->name = name; /* Already added a refcount above */
1001  op->name_pl = add_string(name);
1002  } else {
1003  /* user pressed something else so just ask again... */
1004  play_again(op);
1005  }
1006 }
1007 
1014 void confirm_password(object *op) {
1016  send_query(op->contr->socket, CS_QUERY_HIDEINPUT, i18n(op, "Please type your password again.\n:"));
1017 }
1018 
1029 int get_party_password(object *op, partylist *party) {
1030  if (*party_get_password(party) == '\0') {
1031  return 0;
1032  }
1033 
1035  op->contr->party_to_join = party;
1036  send_query(op->contr->socket, CS_QUERY_HIDEINPUT, i18n(op, "What is the password?\n:"));
1037  return 1;
1038 }
1039 
1046 int roll_stat(void) {
1047  int roll[4], i, low_index, k;
1048 
1049  for (i = 0; i < 4; ++i)
1050  roll[i] = (int)RANDOM()%6+1;
1051 
1052  for (i = 0, low_index = 0, k = 7; i < 4; ++i)
1053  if (roll[i] < k)
1054  k = roll[i],
1055  low_index = i;
1056 
1057  for (i = 0, k = 0; i < 4; ++i) {
1058  if (i != low_index)
1059  k += roll[i];
1060  }
1061  return k;
1062 }
1063 
1070 void roll_stats(object *op) {
1071  int i = 0, j = 0;
1072  int statsort[7];
1073 
1074  op->stats.Str = roll_stat();
1075  op->stats.Dex = roll_stat();
1076  op->stats.Int = roll_stat();
1077  op->stats.Con = roll_stat();
1078  op->stats.Wis = roll_stat();
1079  op->stats.Pow = roll_stat();
1080  op->stats.Cha = roll_stat();
1081  int sum = op->stats.Str+op->stats.Dex+op->stats.Int+op->stats.Con+op->stats.Wis+op->stats.Pow+op->stats.Cha;
1082  float scale = settings.roll_stat_points / sum;
1083  op->stats.Str = roundf(scale * op->stats.Str);
1084  op->stats.Dex = roundf(scale * op->stats.Dex);
1085  op->stats.Int = roundf(scale * op->stats.Int);
1086  op->stats.Con = roundf(scale * op->stats.Con);
1087  op->stats.Wis = roundf(scale * op->stats.Wis);
1088  op->stats.Pow = roundf(scale * op->stats.Pow);
1089  op->stats.Cha = roundf(scale * op->stats.Cha);
1090 
1091  /* Sort the stats so that rerolling is easier... */
1092  statsort[0] = op->stats.Str;
1093  statsort[1] = op->stats.Dex;
1094  statsort[2] = op->stats.Int;
1095  statsort[3] = op->stats.Con;
1096  statsort[4] = op->stats.Wis;
1097  statsort[5] = op->stats.Pow;
1098  statsort[6] = op->stats.Cha;
1099 
1100  /* a quick and dirty bubblesort? */
1101  do {
1102  if (statsort[i] < statsort[i+1]) {
1103  j = statsort[i];
1104  statsort[i] = statsort[i+1];
1105  statsort[i+1] = j;
1106  i = 0;
1107  } else {
1108  i++;
1109  }
1110  } while (i < 6);
1111 
1112  op->stats.Str = statsort[0];
1113  op->stats.Dex = statsort[1];
1114  op->stats.Con = statsort[2];
1115  op->stats.Int = statsort[3];
1116  op->stats.Wis = statsort[4];
1117  op->stats.Pow = statsort[5];
1118  op->stats.Cha = statsort[6];
1119 
1120  op->contr->orig_stats.Str = op->stats.Str;
1121  op->contr->orig_stats.Dex = op->stats.Dex;
1122  op->contr->orig_stats.Int = op->stats.Int;
1123  op->contr->orig_stats.Con = op->stats.Con;
1124  op->contr->orig_stats.Wis = op->stats.Wis;
1125  op->contr->orig_stats.Pow = op->stats.Pow;
1126  op->contr->orig_stats.Cha = op->stats.Cha;
1127 
1128  op->level = 1;
1129  op->stats.exp = 0;
1130  op->stats.ac = 0;
1131 
1132  op->contr->levhp[1] = 9;
1133  op->contr->levsp[1] = 6;
1134  op->contr->levgrace[1] = 3;
1135 
1136  fix_object(op);
1137  op->stats.hp = op->stats.maxhp;
1138  op->stats.sp = op->stats.maxsp;
1139  op->stats.grace = op->stats.maxgrace;
1140  op->contr->orig_stats = op->stats;
1141 }
1142 
1149 void roll_again(object *op) {
1150  esrv_new_player(op->contr, 0);
1151  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)? "));
1152 }
1153 
1163 static void swap_stat(object *op, int swap_second) {
1164  signed char tmp;
1165 
1166  if (op->contr->swap_first == -1) {
1167  LOG(llevError, "player.c:swap_stat() - swap_first is -1\n");
1168  return;
1169  }
1170 
1171  tmp = get_attr_value(&op->contr->orig_stats, op->contr->swap_first);
1172 
1173  set_attr_value(&op->contr->orig_stats, op->contr->swap_first, get_attr_value(&op->contr->orig_stats, swap_second));
1174 
1175  set_attr_value(&op->contr->orig_stats, swap_second, tmp);
1176 
1178  "%s done\n",
1179  short_stat_name[swap_second]);
1180 
1181  op->stats.Str = op->contr->orig_stats.Str;
1182  op->stats.Dex = op->contr->orig_stats.Dex;
1183  op->stats.Con = op->contr->orig_stats.Con;
1184  op->stats.Int = op->contr->orig_stats.Int;
1185  op->stats.Wis = op->contr->orig_stats.Wis;
1186  op->stats.Pow = op->contr->orig_stats.Pow;
1187  op->stats.Cha = op->contr->orig_stats.Cha;
1188  op->stats.ac = 0;
1189 
1190  op->level = 1;
1191  op->stats.exp = 0;
1192  op->stats.ac = 0;
1193 
1194  op->contr->levhp[1] = 9;
1195  op->contr->levsp[1] = 6;
1196  op->contr->levgrace[1] = 3;
1197 
1198  fix_object(op);
1199  op->stats.hp = op->stats.maxhp;
1200  op->stats.sp = op->stats.maxsp;
1201  op->stats.grace = op->stats.maxgrace;
1202  op->contr->orig_stats = op->stats;
1203  op->contr->swap_first = -1;
1204 }
1205 
1221 void key_roll_stat(object *op, char key) {
1222  int keynum = key-'0';
1223  static const int8_t stat_trans[] = {
1224  -1,
1225  STRENGTH,
1226  DEXTERITY,
1227  CONSTITUTION,
1228  INTELLIGENCE,
1229  WISDOM,
1230  POWER,
1231  CHARISMA,
1232  };
1233 
1234  if (keynum > 0 && keynum <= 7) {
1235  if (op->contr->swap_first == -1) {
1236  op->contr->swap_first = stat_trans[keynum];
1238  "%s ->",
1239  short_stat_name[stat_trans[keynum]]);
1240  } else
1241  swap_stat(op, stat_trans[keynum]);
1242 
1243  send_query(op->contr->socket, CS_QUERY_SINGLECHAR, "");
1244  return;
1245  }
1246  switch (key) {
1247  case 'n':
1248  case 'N': {
1249  SET_FLAG(op, FLAG_WIZ);
1250  if (op->map == NULL) {
1251  LOG(llevError, "Map == NULL in state 2\n");
1252  break;
1253  }
1254 
1255  SET_ANIMATION(op, 2); /* So player faces south */
1256  /* Enter exit adds a player otherwise */
1257  add_statbonus(op);
1258  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"));
1260  if (op->msg)
1263  op->msg);
1264  return;
1265  }
1266  case 'y':
1267  case 'Y':
1268  roll_stats(op);
1269  send_query(op->contr->socket, CS_QUERY_SINGLECHAR, "");
1270  return;
1271 
1272  case 'q':
1273  case 'Q':
1274  play_again(op);
1275  return;
1276 
1277  default:
1278  send_query(op->contr->socket, CS_QUERY_SINGLECHAR, i18n(op, "Yes, No, Quit or 1-6. Roll again?"));
1279  return;
1280  }
1281  return;
1282 }
1283 
1297 void key_change_class(object *op, char key) {
1298  int tmp_loop;
1299 
1300  if (key == 'q' || key == 'Q') {
1301  object_remove(op);
1302  play_again(op);
1303  return;
1304  }
1305  if (key == 'd' || key == 'D') {
1306  char buf[MAX_BUF];
1307 
1308  /* this must before then initial items are given */
1309  esrv_new_player(op->contr, op->weight+op->carrying);
1310  create_treasure(find_treasurelist("starting_wealth"), op, 0, 0, 0);
1311 
1312  /* Here we handle the BORN global event */
1314 
1315  /* We then generate a LOGIN event */
1316  events_execute_global_event(EVENT_LOGIN, op->contr, op->contr->socket->host);
1317  player_set_state(op->contr, ST_PLAYING);
1318 
1319  object_set_msg(op, NULL);
1320 
1321  /* We create this now because some of the unique maps will need it
1322  * to save here.
1323  */
1324  snprintf(buf, sizeof(buf), "%s/%s/%s", settings.localdir, settings.playerdir, op->name);
1326 
1327 #ifdef AUTOSAVE
1328  op->contr->last_save_tick = pticks;
1329 #endif
1332  "Welcome to Crossfire!\n Press `?' for help\n");
1333 
1336  "%s entered the game.", op->name);
1337 
1339  give_initial_items(op, op->randomitems);
1342  fix_object(op);
1343 
1344  /* This moves the player to a different start map, if there
1345  * is one for this race
1346  */
1347  if (*first_map_ext_path) {
1348  object *tmp;
1349  char mapname[MAX_BUF + strlen(op->arch->name) + 1];
1350  mapstruct *oldmap;
1351 
1352  oldmap = op->map;
1353 
1354  snprintf(mapname, sizeof(mapname), "%s/%s", first_map_ext_path, op->arch->name);
1355  /*printf("%s\n", mapname);*/
1356  tmp = object_new();
1358  EXIT_X(tmp) = op->x;
1359  EXIT_Y(tmp) = op->y;
1360  enter_exit(op, tmp);
1361 
1362  if (oldmap != op->map) {
1363  /* map exists, update bed of reality location, in case player dies */
1364  op->contr->bed_x = op->x;
1365  op->contr->bed_y = op->y;
1366  strlcpy(op->contr->savebed_map, mapname, sizeof(op->contr->savebed_map));
1367  }
1368 
1370  } else {
1371  LOG(llevDebug, "first_map_ext_path not set\n");
1372  }
1373  return;
1374  }
1375 
1376  /* Following actually changes the race - this is the default command
1377  * if we don't match with one of the options above.
1378  */
1379 
1380  tmp_loop = 0;
1381  while (!tmp_loop) {
1382  const char *name = add_string(op->name);
1383  int x = op->x, y = op->y;
1384 
1386  object_remove(op);
1387  /* get_player_archetype() is really misnamed - it will
1388  * get the next archetype from the list.
1389  */
1390  op->arch = get_player_archetype(op->arch);
1391  object_copy(&op->arch->clone, op);
1392  op->stats = op->contr->orig_stats;
1393  free_string(op->name);
1394  op->name = name;
1395  free_string(op->name_pl);
1396  op->name_pl = add_string(name);
1397  SET_ANIMATION(op, 2); /* So player faces south */
1398  object_insert_in_map_at(op, op->map, op, 0, x, y);
1399  strncpy(op->contr->title, op->arch->clone.name, sizeof(op->contr->title)-1);
1400  op->contr->title[sizeof(op->contr->title)-1] = '\0';
1401  add_statbonus(op);
1402  tmp_loop = allowed_class(op);
1403  }
1406  fix_object(op);
1407  op->stats.hp = op->stats.maxhp;
1408  op->stats.sp = op->stats.maxsp;
1409  op->stats.grace = 0;
1410  if (op->msg)
1412  op->msg);
1413  send_query(op->contr->socket, CS_QUERY_SINGLECHAR, i18n(op, "Press any key for the next race.\nPress `d' to play this race.\n"));
1414 }
1415 
1437 int check_race_and_class(living *stats, archetype *race, archetype *opclass)
1438 {
1439  int i, stat, failure=0;
1440 
1441  for (i = 0; i < NUM_STATS; i++) {
1442  stat = get_attr_value(stats, i);
1443  if (race)
1444  stat += get_attr_value(&race->clone.stats, i);
1445 
1446  if (opclass)
1447  stat += get_attr_value(&opclass->clone.stats, i);
1448 
1449  set_attr_value(stats, i, stat);
1450 
1451  /* We process all stats, regardless if there is a failure
1452  * or not.
1453  */
1454  if (stat < MIN_STAT) failure=1;
1455 
1456  /* Maybe this should be an error? Player is losing
1457  * some stats points here, but it is legal.
1458  */
1459  if (stat > settings.max_stat) stat = settings.max_stat;
1460  }
1461  return failure;
1462 
1463 }
1464 
1487 int apply_race_and_class(object *op, archetype *race, archetype *opclass, living *stats)
1488 {
1489  const char *name = add_string(op->name);
1490  char buf[MAX_BUF];
1491  object *inv;
1492 
1493  /* Free any objects in character inventory - they
1494  * shouldn't have any, but there is the potential that
1495  * we give them objects below and then get a creation
1496  * failure (stat out of range), in which case
1497  * those objects would be in the inventory.
1498  */
1499  while (op->inv) {
1500  inv = op->inv;
1501  object_remove(inv);
1502  object_free(inv, 0);
1503  }
1504 
1505  object_copy(&race->clone, op);
1506  free_string(op->name);
1507  op->name = name;
1508  free_string(op->name_pl);
1509  op->name_pl = add_string(name);
1510  SET_ANIMATION(op, 2); /* So player faces south */
1511  strlcpy(op->contr->title, op->arch->clone.name, sizeof(op->contr->title));
1512 
1513  if (stats) {
1514  /* Copy over the stats. Use this instead a memcpy because
1515  * we only want to copy over a few specific stats, and
1516  * leave things like maxhp, maxsp, etc, unchanged.
1517  */
1518  int i, stat;
1519  for (i = 0; i < NUM_STATS; i++) {
1520  stat = get_attr_value(stats, i);
1521  set_attr_value(&op->stats, i, stat);
1522  set_attr_value(&op->contr->orig_stats, i, stat);
1523  }
1524  } else {
1525  /* Note that this will repeated increase the stat values
1526  * if the caller does not reset them. Only do this
1527  * if stats is not provided - if stats is provided, those
1528  * are already adjusted.
1529  */
1530  add_statbonus(op);
1531 
1532  /* Checks that all stats are greater than 1. Once again,
1533  * only do this if stats are not provided
1534  */
1535  if (!allowed_class(op)) return 1;
1536  }
1537 
1539  op->stats.hp = op->stats.maxhp;
1540  op->stats.sp = op->stats.maxsp;
1541  op->stats.grace = 0;
1542 
1543  /* this must before then initial items are given */
1544  esrv_new_player(op->contr, op->weight+op->carrying);
1545  create_treasure(find_treasurelist("starting_wealth"), op, 0, 0, 0);
1546 
1547  /* This has to be done before class, otherwise the NOCLASSFACECHANGE
1548  * object is not in the inventory, and racial face will get overwritten.
1549  */
1550  give_initial_items(op, op->randomitems);
1551 
1552  if (stats) {
1553  /* Apply class information */
1555  } else {
1556  apply_changes_to_player(op, &opclass->clone, 0);
1557 
1558  /* Checks that all stats are greater than 1 */
1559  if (!allowed_class(op)) return 2;
1560  }
1561 
1562  /* Here we handle the BORN global event */
1564 
1565  /* We then generate a LOGIN event */
1566  events_execute_global_event(EVENT_LOGIN, op->contr, op->contr->socket->host);
1567 
1568  object_set_msg(op, NULL);
1569 
1570  /* We create this now because some of the unique maps will need it
1571  * to save here.
1572  */
1573  snprintf(buf, sizeof(buf), "%s/%s/%s", settings.localdir, settings.playerdir, op->name);
1575 
1576 #ifdef AUTOSAVE
1577  op->contr->last_save_tick = pticks;
1578 #endif
1579 
1582  fix_object(op);
1583 
1586  esrv_add_spells(op->contr, NULL);
1587 
1588  return 0;
1589 
1590 }
1591 
1600 void key_confirm_quit(object *op, char key) {
1601  char buf[MAX_BUF];
1602  mapstruct *mp, *next;
1603 
1604  // this was tested when 'quit' command was issued, but better safe than sorry.
1605  if (QUERY_FLAG(op, FLAG_WIZ)) {
1606  player_set_state(op->contr, ST_PLAYING);
1607  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_LOGIN, "Can't quit when in DM mode.");
1608  return;
1609  }
1610 
1611  if (key != 'y' && key != 'Y' && key != 'q' && key != 'Q') {
1612  player_set_state(op->contr, ST_PLAYING);
1614  "OK, continuing to play.");
1615  return;
1616  }
1617 
1620  object_remove(op);
1621  op->direction = 0;
1623  "%s quits the game.",
1624  op->name);
1625 
1626  strcpy(op->contr->killer, "quit");
1627  hiscore_check(op, 0);
1628  party_leave(op);
1629  if (settings.set_title == TRUE)
1630  player_set_own_title(op->contr, "");
1631 
1632 
1633  /* We need to hunt for any per player unique maps in memory and
1634  * get rid of them. The trailing slash in the path is intentional,
1635  * so that players named 'Ab' won't match against players 'Abe' pathname
1636  */
1637  snprintf(buf, sizeof(buf), "~%s/%s/", settings.playerdir, op->name);
1638  for (mp = first_map; mp != NULL; mp = next) {
1639  next = mp->next;
1640  if (!strncmp(mp->path, buf, strlen(buf)))
1641  delete_map(mp);
1642  }
1643 
1644  delete_character(op->name);
1645 
1646  /* Remove player from account list and send back data if needed */
1647  if (op->contr->socket->account_chars != NULL) {
1648  account_char_remove(op->contr->socket->account_chars, op->name);
1649  account_char_save(op->contr->socket->account_chars);
1650  /* char information is reloaded in send_account_players below */
1651  account_char_free(op->contr->socket->account_chars);
1652  op->contr->socket->account_chars = NULL;
1653  account_remove_player(op->contr->socket->account_name, op->name);
1654  send_account_players(op->contr->socket);
1655  }
1656 
1657  play_again(op);
1658 }
1659 
1666 static void flee_player(object *op) {
1667  int dir, diff;
1668  rv_vector rv;
1669 
1670  if (op->stats.hp < 0) {
1671  LOG(llevDebug, "Fleeing player is dead.\n");
1673  return;
1674  }
1675 
1676  if (op->enemy == NULL) {
1677  LOG(llevDebug, "Fleeing player had no enemy.\n");
1679  return;
1680  }
1681 
1682  /* Seen some crashes here. Since we don't store an
1683  * op->enemy_count, it is possible that something destroys the
1684  * actual enemy, and the object is recycled.
1685  */
1686  if (op->enemy->map == NULL) {
1688  object_set_enemy(op, NULL);
1689  return;
1690  }
1691 
1692  if (!(random_roll(0, 4, op, PREFER_LOW)) && did_make_save(op, op->level, 0)) {
1693  object_set_enemy(op, NULL);
1695  return;
1696  }
1697  if (!get_rangevector(op, op->enemy, &rv, 0)) {
1698  object_set_enemy(op, NULL);
1700  return;
1701  }
1702 
1703  dir = absdir(4+rv.direction);
1704  for (diff = 0; diff < 3; diff++) {
1705  int m = 1-(RANDOM()&2);
1706  if (move_ob(op, absdir(dir+diff*m), op)
1707  || (diff == 0 && move_ob(op, absdir(dir-diff*m), op))) {
1708  return;
1709  }
1710  }
1711  /* Cornered, get rid of scared */
1713  object_set_enemy(op, NULL);
1714 }
1715 
1725 int check_pick(object *op) {
1726  tag_t op_tag;
1727  int stop = 0;
1728  int j, k, wvratio, current_ratio;
1729  char putstring[128], tmpstr[16];
1730 
1731  /* if you're flying, you can't pick up anything */
1732  if (op->move_type&MOVE_FLYING)
1733  return 1;
1734  /* If not a player, don't check anything. */
1735  if (!op->contr) {
1736  return 1;
1737  }
1738 
1739  op_tag = op->count;
1740 
1742  if (object_was_destroyed(op, op_tag))
1743  return 0;
1744 
1745  if (!object_can_pick(op, tmp))
1746  continue;
1747 
1748  if (op->contr->search_str[0] != '\0' && settings.search_items == TRUE) {
1749  if (object_matches_string(op, tmp, op->contr->search_str))
1750  pick_up(op, tmp);
1751  continue;
1752  }
1753 
1754  /* high not bit set? We're using the old autopickup model */
1755  if (!(op->contr->mode&PU_NEWMODE)) {
1756  switch (op->contr->mode) {
1757  case 0:
1758  return 1; /* don't pick up */
1759 
1760  case 1:
1761  pick_up(op, tmp);
1762  return 1;
1763 
1764  case 2:
1765  pick_up(op, tmp);
1766  return 0;
1767 
1768  case 3:
1769  return 0; /* stop before pickup */
1770 
1771  case 4:
1772  pick_up(op, tmp);
1773  break;
1774 
1775  case 5:
1776  pick_up(op, tmp);
1777  stop = 1;
1778  break;
1779 
1780  case 6:
1783  pick_up(op, tmp);
1784  break;
1785 
1786  case 7:
1787  if (tmp->type == MONEY || tmp->type == GEM)
1788  pick_up(op, tmp);
1789  break;
1790 
1791  default:
1792  /* use value density */
1793  if (!QUERY_FLAG(tmp, FLAG_UNPAID)
1794  && (price_base(tmp)*100/(tmp->weight*MAX(tmp->nrof, 1))) >= op->contr->mode)
1795  pick_up(op, tmp);
1796  }
1797  } else { /* old model */
1798  /* NEW pickup handling */
1799  if (op->contr->mode&PU_DEBUG) {
1800  /* some debugging code to figure out item information */
1802  "item name: %s item type: %d weight/value: %d",
1803  tmp->name ? tmp->name : tmp->arch->name, tmp->type,
1804  (int)(price_base(tmp)*100/(tmp->weight*MAX(tmp->nrof, 1))));
1805 
1806 
1807  snprintf(putstring, sizeof(putstring), "...flags: ");
1808  for (k = 0; k < 4; k++) {
1809  for (j = 0; j < 32; j++) {
1810  if ((tmp->flags[k]>>j)&0x01) {
1811  snprintf(tmpstr, sizeof(tmpstr), "%d ", k*32+j);
1812  strcat(putstring, tmpstr);
1813  }
1814  }
1815  }
1817  putstring);
1818  }
1819  /* philosophy:
1820  * It's easy to grab an item type from a pile, as long as it's
1821  * generic. This takes no game-time. For more detailed pickups
1822  * and selections, select-items should be used. This is a
1823  * grab-as-you-run type mode that's really useful for arrows for
1824  * example.
1825  * The drawback: right now it has no frontend, so you need to
1826  * stick the bits you want into a calculator in hex mode and then
1827  * convert to decimal and then 'pickup <#>
1828  */
1829 
1830  /* the first two modes are exclusive: if NOTHING we return, if
1831  * STOP then we stop. All the rest are applied sequentially,
1832  * meaning if any test passes, the item gets picked up. */
1833 
1834  /* if mode is set to pick nothing up, return */
1835 
1836  if (op->contr->mode == PU_NOTHING)
1837  return 1;
1838 
1839  /* if mode is set to stop when encountering objects, return.
1840  * Take STOP before INHIBIT since it doesn't actually pick
1841  * anything up */
1842 
1843  if (op->contr->mode&PU_STOP)
1844  return 0;
1845 
1846  /* useful for going into stores and not losing your settings... */
1847  /* and for battles where you don't want to get loaded down while
1848  * fighting */
1849  if (op->contr->mode&PU_INHIBIT)
1850  return 1;
1851 
1852  /* prevent us from turning into auto-thieves :) */
1853  if (QUERY_FLAG(tmp, FLAG_UNPAID))
1854  continue;
1855 
1856  /* ignore known cursed objects */
1857  if (QUERY_FLAG(tmp, FLAG_KNOWN_CURSED) && op->contr->mode&PU_NOT_CURSED)
1858  continue;
1859 
1860  static int checks[] = {
1861  PU_FOOD,
1862  PU_DRINK,
1863  PU_FLESH,
1864  PU_POTION,
1865  PU_SPELLBOOK,
1867  PU_READABLES,
1869  PU_MAGICAL,
1870  PU_VALUABLES,
1871  PU_JEWELS,
1872  PU_BOW,
1873  PU_ARROW,
1874  PU_ARMOUR,
1875  PU_HELMET,
1876  PU_SHIELD,
1877  PU_BOOTS,
1878  PU_GLOVES,
1879  PU_CLOAK,
1882  PU_KEY,
1883  PU_CONTAINER,
1884  PU_CURSED,
1885  0
1886  };
1887  int found = 0;
1888  for (int m = 0; checks[m] != 0; m++) {
1889  if (op->contr->mode & checks[m] && object_matches_pickup_mode(tmp, checks[m])) {
1890  pick_up(op, tmp);
1891  found = 1;
1892  break;
1893  }
1894  }
1895  if (found) {
1896  continue;
1897  }
1898 
1899  /* any of the last 4 bits set means we use the ratio for value
1900  * pickups */
1901  if (op->contr->mode&PU_RATIO) {
1902  /* use value density to decide what else to grab.
1903  * >=7 was >= op->contr->mode
1904  * >=7 is the old standard setting. Now we take the last 4 bits
1905  * and multiply them by 5, giving 0..15*5== 5..75 */
1906  wvratio = (op->contr->mode&PU_RATIO)*5;
1907  current_ratio = price_base(tmp)*100/(tmp->weight*MAX(tmp->nrof, 1));
1908  if (current_ratio >= wvratio) {
1909  pick_up(op, tmp);
1910  continue;
1911  }
1912  }
1913  } /* the new pickup model */
1914  } FOR_BELOW_FINISH();
1915  return !stop;
1916 }
1917 
1930 static object *find_arrow(object *op, const char *type) {
1931  object *tmp = NULL;
1932 
1934  if (!tmp
1935  && inv->type == CONTAINER
1936  && inv->race == type
1938  tmp = find_arrow(inv, type);
1939  else if (inv->type == ARROW && inv->race == type)
1940  return inv;
1941  FOR_INV_FINISH();
1942  return tmp;
1943 }
1944 
1962 static object *find_better_arrow(object *op, object *target, const char *type, int *better) {
1963  object *tmp = NULL, *ntmp;
1964  int attacknum, attacktype, betterby = 0, i;
1965 
1966  if (!type)
1967  return NULL;
1968 
1969  FOR_INV_PREPARE(op, arrow) {
1970  if (arrow->type == CONTAINER
1971  && arrow->race == type
1972  && QUERY_FLAG(arrow, FLAG_APPLIED)) {
1973  i = 0;
1974  ntmp = find_better_arrow(arrow, target, type, &i);
1975  if (i > betterby) {
1976  tmp = ntmp;
1977  betterby = i;
1978  }
1979  } else if (arrow->type == ARROW && arrow->race == type) {
1980  /* always prefer assassination/slaying */
1981  if (target->race != NULL
1982  && arrow->slaying != NULL
1983  && strstr(arrow->slaying, target->race)) {
1984  if (arrow->attacktype&AT_DEATH) {
1985  if (better)
1986  *better = 100;
1987  return arrow;
1988  } else {
1989  tmp = arrow;
1990  betterby = (arrow->magic+arrow->stats.dam)*2;
1991  }
1992  } else {
1993  for (attacknum = 0; attacknum < NROFATTACKS; attacknum++) {
1994  attacktype = 1<<attacknum;
1995  if ((arrow->attacktype&attacktype) && (target->arch->clone.resist[attacknum]) < 0)
1996  if (((arrow->magic+arrow->stats.dam)*(100-target->arch->clone.resist[attacknum])/100) > betterby) {
1997  tmp = arrow;
1998  betterby = (arrow->magic+arrow->stats.dam)*(100-target->arch->clone.resist[attacknum])/100;
1999  }
2000  }
2001  if ((2+arrow->magic+arrow->stats.dam) > betterby) {
2002  tmp = arrow;
2003  betterby = 2+arrow->magic+arrow->stats.dam;
2004  }
2005  if (arrow->title && (1+arrow->magic+arrow->stats.dam) > betterby) {
2006  tmp = arrow;
2007  betterby = 1+arrow->magic+arrow->stats.dam;
2008  }
2009  }
2010  }
2011  } FOR_INV_FINISH();
2012  if (tmp == NULL)
2013  return find_arrow(op, type);
2014 
2015  if (better)
2016  *better = betterby;
2017  return tmp;
2018 }
2019 
2032 static object *pick_arrow_target(object *op, const char *type, int dir) {
2033  object *tmp = NULL;
2034  mapstruct *m;
2035  int i, mflags, found, number;
2036  int16_t x, y;
2037 
2038  if (op->map == NULL)
2039  return find_arrow(op, type);
2040 
2041  /* do a dex check */
2042  number = (die_roll(2, 40, op, PREFER_LOW)-2)/2;
2043  if (number > (op->stats.Dex+(op->chosen_skill ? op->chosen_skill->level : op->level)))
2044  return find_arrow(op, type);
2045 
2046  m = op->map;
2047  x = op->x;
2048  y = op->y;
2049 
2050  /* find the first target */
2051  for (i = 0, found = 0; i < 20; i++) {
2052  x += freearr_x[dir];
2053  y += freearr_y[dir];
2054  mflags = get_map_flags(m, &m, x, y, &x, &y);
2055  if (mflags&P_OUT_OF_MAP || mflags&P_BLOCKSVIEW) {
2056  tmp = NULL;
2057  break;
2058  } else if (GET_MAP_MOVE_BLOCK(m, x, y) == MOVE_FLY_LOW) {
2059  /* This block presumes arrows and the like are MOVE_FLY_SLOW -
2060  * perhaps a bad assumption.
2061  */
2062  tmp = NULL;
2063  break;
2064  }
2065  if (mflags&P_IS_ALIVE) {
2066  FOR_MAP_PREPARE(m, x, y, tmp2)
2067  if (QUERY_FLAG(tmp2, FLAG_ALIVE)) {
2068  tmp = tmp2;
2069  found++;
2070  break;
2071  }
2072  FOR_MAP_FINISH();
2073  if (found)
2074  break;
2075  }
2076  }
2077  if (tmp == NULL)
2078  return find_arrow(op, type);
2079 
2080  return find_better_arrow(op, HEAD(tmp), type, NULL);
2081 }
2082 
2101 int fire_bow(object *op, object *arrow, int dir, int wc_mod, int16_t sx, int16_t sy) {
2102  object *bow;
2103  tag_t tag;
2104  int bowspeed, mflags;
2105  mapstruct *m;
2106 
2107  if (!dir) {
2109  "You can't shoot yourself!");
2110  return 0;
2111  }
2112  if (op->type == PLAYER) {
2113  bow = op->contr->ranges[range_bow];
2114  // Make sure the bow's skill is readied.
2115  // Otherwise, you can get wrong modifiers from unarmed attacks
2116  // because that ends up the readied skill.
2117  object *skill = find_skill_by_name(op, bow->skill);
2118  if (skill && change_skill(op, skill, 1) == 0) {
2120  "You cannot use %s without the skill %s", bow->name, bow->skill);
2121  return 0;
2122  }
2123  }
2124  else {
2125  /* Don't check for applied - monsters don't apply bows - in that way, they
2126  * don't need to switch back and forth between bows and weapons.
2127  */
2128  bow = object_find_by_type(op, BOW);
2129  if (!bow) {
2130  LOG(llevError, "Range: bow without activated bow (%s).\n", op->name);
2131  return 0;
2132  }
2133  }
2134  if (!bow->race || !bow->skill) {
2136  "Your %s is broken.",
2137  bow->name);
2138  return 0;
2139  }
2140 
2141  bowspeed = bow->stats.sp+get_dex_bonus(op->stats.Dex);
2142 
2143  /* penalize ROF for bestarrow */
2144  if (op->type == PLAYER && op->contr->bowtype == bow_bestarrow)
2145  bowspeed -= get_dex_bonus(op->stats.Dex)+5;
2146  if (bowspeed < 1)
2147  bowspeed = 1;
2148 
2149  if (arrow == NULL) {
2150  arrow = find_arrow(op, bow->race);
2151  if (arrow == NULL) {
2152  if (op->type == PLAYER)
2155  "You have no %s left.",
2156  bow->race);
2157  /* FLAG_READY_BOW will get reset if the monsters picks up some arrows */
2158  else
2160  return 0;
2161  }
2162  }
2163  mflags = get_map_flags(op->map, &m, sx, sy, &sx, &sy);
2164  if (mflags&P_OUT_OF_MAP) {
2165  return 0;
2166  }
2167  if (GET_MAP_MOVE_BLOCK(m, sx, sy)&MOVE_FLY_LOW) {
2168  return 0;
2169  }
2170 
2171  /* this should not happen, but sometimes does */
2172  if (arrow->nrof == 0) {
2173  object_remove(arrow);
2175  return 0;
2176  }
2177 
2178  arrow = object_split(arrow, 1, NULL, 0);
2179  if (arrow == NULL) {
2181  "You have no %s left.",
2182  bow->race);
2183  return 0;
2184  }
2185  object_set_owner(arrow, op);
2186  if (arrow->skill)
2187  free_string(arrow->skill);
2188  arrow->skill = add_refcount(bow->skill);
2189 
2190  arrow->direction = dir;
2191 
2192  if (op->type == PLAYER) {
2193  op->speed_left = 0.01-(float)FABS(op->speed)*100/bowspeed;
2194  fix_object(op);
2195  }
2196 
2197  if (bow->anim_suffix != NULL)
2199 
2200 /* SET_ANIMATION(arrow, arrow->direction);*/
2201  object_update_turn_face(arrow);
2202  arrow->stats.sp = arrow->stats.wc; /* save original wc and dam */
2203  arrow->stats.hp = arrow->stats.dam;
2204  arrow->stats.grace = arrow->attacktype;
2205  if (arrow->slaying != NULL)
2206  arrow->spellarg = strdup_local(arrow->slaying);
2207 
2208  /* Note that this was different for monsters - they got their level
2209  * added to the damage. I think the strength bonus is more proper.
2210  */
2211 
2212  arrow->stats.dam += (QUERY_FLAG(bow, FLAG_NO_STRENGTH) ? 0 : get_dam_bonus(op->stats.Str))
2213  +bow->stats.dam
2214  +bow->magic
2215  +arrow->magic;
2216 
2217  /* update the speed */
2218  arrow->speed = (float)((QUERY_FLAG(bow, FLAG_NO_STRENGTH) ? 0 : get_dam_bonus(op->stats.Str))+bow->magic+arrow->magic)/5.0
2219  +(float)bow->stats.dam/7.0;
2220 
2221  if (arrow->speed < 1.0)
2222  arrow->speed = 1.0;
2223  object_update_speed(arrow);
2224  arrow->speed_left = 0;
2225 
2226  if (op->type == PLAYER) {
2227  /* we don't want overflows of wc (sint), so cap the value - mod and pl should be subtracted */
2228  int mod = bow->magic
2229  +arrow->magic
2230  +get_dex_bonus(op->stats.Dex)
2231  +get_thaco_bonus(op->stats.Str)
2232  +arrow->stats.wc
2233  +bow->stats.wc
2234  -wc_mod;
2235  int plmod = (op->chosen_skill ? op->chosen_skill->level : op->level);
2236  if (plmod+mod > 140)
2237  plmod = 140-mod;
2238  else if (plmod+mod < -100)
2239  plmod = -100-mod;
2240  arrow->stats.wc = 20-(int8_t)plmod-(int8_t)mod;
2241 
2242  arrow->level = op->chosen_skill ? op->chosen_skill->level : op->level;
2243  } else {
2244  arrow->stats.wc = op->stats.wc
2245  -bow->magic
2246  -arrow->magic
2247  -arrow->stats.wc
2248  +wc_mod;
2249 
2250  arrow->level = op->level;
2251  }
2252  if (arrow->attacktype == AT_PHYSICAL)
2253  arrow->attacktype |= bow->attacktype;
2254  if (bow->slaying != NULL)
2255  arrow->slaying = add_string(bow->slaying);
2256 
2257  /* If move_type is ever changed, monster.c:monster_use_bow() needs to be changed too. */
2258  arrow->move_type = MOVE_FLY_LOW;
2259  arrow->move_on = MOVE_FLY_LOW|MOVE_WALK;
2260 
2261  tag = arrow->count;
2262  object_insert_in_map_at(arrow, m, op, 0, sx, sy);
2263 
2264  if (!object_was_destroyed(arrow, tag)) {
2265  play_sound_map(SOUND_TYPE_ITEM, arrow, arrow->direction, "fire");
2266  ob_process(arrow);
2267  }
2268 
2269  return 1;
2270 }
2271 
2282 static int similar_direction(int a, int b) {
2283  /* shortcut the obvious */
2284  if (a == b)
2285  return 1;
2286  /* Made this cleaner using modulus instead of a switch statement
2287  * We only needed the direction and the two adjacent to it
2288  * (8 is adjacent to 1 here) to return true, so a - 1, a, and a + 1
2289  * are the three directions that get "similar" affirmed.
2290  * -- Neila Hawkins 2015-05-28
2291  */
2292  // The last one for the offset is added afterwards so we get
2293  // 1-8 instead of 0-7 (specifically, 0 becomes 8 without changing
2294  // the other values).
2295  if ((a % 8) + 1 == b || (a + 6 % 8) + 1 == b)
2296  return 1;
2297  return 0;
2298 }
2299 
2316 static int player_fire_bow(object *op, int dir) {
2317  int ret = 0, wcmod = 0;
2318 
2319  if (op->contr->bowtype == bow_bestarrow) {
2320  ret = fire_bow(op, pick_arrow_target(op, op->contr->ranges[range_bow]->race, dir), dir, 0, op->x, op->y);
2321  } else if (op->contr->bowtype >= bow_n && op->contr->bowtype <= bow_nw) {
2322  if (!similar_direction(dir, op->contr->bowtype-bow_n+1))
2323  wcmod = -1;
2324  ret = fire_bow(op, NULL, op->contr->bowtype-bow_n+1, wcmod, op->x, op->y);
2325  } else if (op->contr->bowtype == bow_threewide) {
2326  ret = fire_bow(op, NULL, dir, 0, op->x, op->y);
2327  ret |= fire_bow(op, NULL, dir, -5, op->x+freearr_x[absdir(dir+2)], op->y+freearr_y[absdir(dir+2)]);
2328  ret |= fire_bow(op, NULL, dir, -5, op->x+freearr_x[absdir(dir-2)], op->y+freearr_y[absdir(dir-2)]);
2329  } else if (op->contr->bowtype == bow_spreadshot) {
2330  ret |= fire_bow(op, NULL, dir, 0, op->x, op->y);
2331  ret |= fire_bow(op, NULL, absdir(dir-1), -5, op->x, op->y);
2332  ret |= fire_bow(op, NULL, absdir(dir+1), -5, op->x, op->y);
2333  } else {
2334  /* Simple case */
2335  ret = fire_bow(op, NULL, dir, 0, op->x, op->y);
2336  }
2337  return ret;
2338 }
2339 
2352 static void fire_misc_object(object *op, int dir) {
2353  object *item;
2354  char name[MAX_BUF];
2355 
2356  item = op->contr->ranges[range_misc];
2357  if (!item) {
2359  "You have no range item readied.");
2360  return;
2361  }
2362  if (!item->inv) {
2363  LOG(llevError, "Object %s lacks a spell\n", item->name);
2364  return;
2365  }
2366  if (item->type == WAND) {
2367  if (item->stats.food <= 0) {
2368  play_sound_player_only(op->contr, SOUND_TYPE_ITEM, item, 0, "poof");
2371  "The %s goes poof.",
2372  name);
2373  return;
2374  }
2375  } else if (item->type == ROD) {
2376  if (item->stats.hp < SP_level_spellpoint_cost(item, item->inv, SPELL_HIGHEST)) {
2377  play_sound_player_only(op->contr, SOUND_TYPE_ITEM, item, 0, "poof");
2380  "The %s whines for a while, but nothing happens.",
2381  name);
2382  return;
2383  }
2384  }
2385 
2386  if (cast_spell(op, item, dir, item->inv, NULL)) {
2387  SET_FLAG(op, FLAG_BEEN_APPLIED); /* You now know something about it */
2388  if (item->type == WAND) {
2390  } else if (item->type == ROD) {
2392  }
2393  }
2394 }
2395 
2404 void fire(object *op, int dir) {
2405 
2406  /* check for loss of invisiblity/hide */
2407  if (action_makes_visible(op))
2408  make_visible(op);
2409 
2410  switch (op->contr->shoottype) {
2411  case range_none:
2412  return;
2413 
2414  case range_bow:
2415  player_fire_bow(op, dir);
2416  return;
2417 
2418  case range_magic: /* Casting spells */
2419  cast_spell(op, op, dir, op->contr->ranges[range_magic], op->contr->spellparam[0] ? op->contr->spellparam : NULL);
2420  return;
2421 
2422  case range_misc:
2423  fire_misc_object(op, dir);
2424  return;
2425 
2426  case range_golem: /* Control summoned monsters from scrolls */
2427  if (op->contr->ranges[range_golem] == NULL
2428  || op->contr->golem_count != op->contr->ranges[range_golem]->count) {
2429  op->contr->ranges[range_golem] = NULL;
2430  op->contr->shoottype = range_none;
2431  op->contr->golem_count = 0;
2432  } else
2433  pets_control_golem(op->contr->ranges[range_golem], dir);
2434  return;
2435 
2436  case range_skill:
2437  if (!op->chosen_skill) {
2438  if (op->type == PLAYER)
2440  "You have no applicable skill to use.");
2441  return;
2442  }
2443  (void)do_skill(op, op, op->chosen_skill, dir, NULL);
2444  return;
2445 
2446  case range_builder:
2447  apply_map_builder(op, dir);
2448  return;
2449 
2450  default:
2452  "Illegal shoot type.");
2453  return;
2454  }
2455 }
2456 
2476 object *find_key(object *pl, object *container, object *door) {
2477  object *tmp, *key;
2478 
2479  /* Should not happen, but sanity checking is never bad */
2480  if (container->inv == NULL)
2481  return NULL;
2482 
2483  /* First, lets try to find a key in the top level inventory */
2484  tmp = NULL;
2485  if (door->type == DOOR) {
2486  int flag = FLAG_UNPAID;
2487  tmp = object_find_by_type_without_flags(container, KEY, &flag, 1);
2488  }
2489  /* For sanity, we should really check door type, but other stuff
2490  * (like containers) can be locked with special keys
2491  */
2492  if (!tmp && door->slaying != NULL) {
2494  }
2495  /* No key found - lets search inventories now */
2496  /* If we find and use a key in an inventory, return at that time.
2497  * otherwise, if we search all the inventories and still don't find
2498  * a key, return
2499  */
2500  if (!tmp) {
2501  FOR_INV_PREPARE(container, tmp) {
2502  /* No reason to search empty containers */
2503  if (tmp->type == CONTAINER && tmp->inv) {
2504  key = find_key(pl, tmp, door);
2505  if (key != NULL)
2506  return key;
2507  }
2508  } FOR_INV_FINISH();
2509  return NULL;
2510  }
2511  /* We get down here if we have found a key. Now if its in a container,
2512  * see if we actually want to use it
2513  */
2514  if (pl != container) {
2515  /* Only let players use keys in containers */
2516  if (!pl->contr)
2517  return NULL;
2518  /* cases where this fails:
2519  * If we only search the player inventory, return now since we
2520  * are not in the players inventory.
2521  * If the container is not active, return now since only active
2522  * containers can be used.
2523  * If we only search keyrings and the container does not have
2524  * a race/isn't a keyring.
2525  * No checking for all containers - to fall through past here,
2526  * inv must have been an container and must have been active.
2527  *
2528  * Change the color so that the message doesn't disappear with
2529  * all the others.
2530  */
2531  if (pl->contr->usekeys == key_inventory
2532  || !QUERY_FLAG(container, FLAG_APPLIED)
2533  || (pl->contr->usekeys == keyrings && (!container->race || strcmp(container->race, "keys")))) {
2534  char name_tmp[MAX_BUF], name_cont[MAX_BUF];
2535 
2536  query_name(tmp, name_tmp, MAX_BUF);
2537  query_name(container, name_cont, MAX_BUF);
2540  "The %s in your %s vibrates as you approach the door",
2541  name_tmp, name_cont);
2542  return NULL;
2543  }
2544  }
2545  return tmp;
2546 }
2547 
2558 static int player_attack_door(object *op, object *door) {
2559  /* If its a door, try to find a use a key. If we do destroy the door,
2560  * might as well return immediately as there is nothing more to do -
2561  * otherwise, we fall through to the rest of the code.
2562  */
2563  object *key = find_key(op, op, door);
2564 
2565  assert(door->type == DOOR || door->type == LOCKED_DOOR);
2566 
2567  /* IF we found a key, do some extra work */
2568  if (key) {
2569  char name[HUGE_BUF];
2570 
2571  play_sound_map(SOUND_TYPE_GROUND, door, 0, "open");
2572  if (action_makes_visible(op))
2573  make_visible(op);
2574  if (door->inv && (door->inv->type == RUNE || door->inv->type == TRAP))
2575  spring_trap(door->inv, op);
2576 
2580  "You open the door with the %s",
2581  name);
2582 
2583  if (door->type == DOOR)
2584  remove_door(door);
2585  else
2586  remove_locked_door(door); /* remove door without violence ;-) */
2587 
2588  /* Do this after we print the message */
2589  object_decrease_nrof_by_one(key); /* Use up one of the keys */
2590 
2591  return 1; /* Nothing more to do below */
2592 
2593  }
2594 
2595  if (door->type == LOCKED_DOOR) {
2596  /* Might as well return now - no other way to open this */
2597  if (door->msg && *door->msg) {
2599  door->msg);
2600  }
2601  return 1;
2602  }
2603 
2604  if (door->type == DOOR && op->contr && !op->contr->run_on) {
2605  /* Player so try to pick the door */
2606  object *lock = find_skill_by_name(op, "lockpicking");
2607  if (lock) {
2608  /* Even if the lockpicking failed, don't go on moving, player should explicitely attack or run
2609  * to bash the door. */
2610  do_skill(op, op, lock, op->facing, NULL);
2611  return 1;
2612  }
2613  }
2614 
2615  return 0;
2616 }
2617 
2631 void move_player_attack(object *op, int dir) {
2632  object *mon, *tpl, *mon_owner;
2633  int16_t nx, ny;
2634  int on_battleground;
2635  mapstruct *m;
2636 
2637  if (op->contr->transport)
2638  tpl = op->contr->transport;
2639  else
2640  tpl = op;
2641  assert(tpl->map != NULL); // op must be on a map in order to move it
2642  nx = freearr_x[dir]+tpl->x;
2643  ny = freearr_y[dir]+tpl->y;
2644 
2645  on_battleground = op_on_battleground(tpl, NULL, NULL, NULL);
2646 
2647  // Temporarily store the map we are on before movement.
2648  mapstruct *bef = tpl->map;
2649 
2650  /* If braced, or can't move to the square, and it is not out of the
2651  * map, attack it. Note order of if statement is important - don't
2652  * want to be calling move_ob if braced, because move_ob will move the
2653  * player. This is a pretty nasty hack, because if we could
2654  * move to some space, it then means that if we are braced, we should
2655  * do nothing at all. As it is, if we are braced, we go through
2656  * quite a bit of processing. However, it probably is less than what
2657  * move_ob uses.
2658  */
2659  if ((op->contr->braced || !move_ob(tpl, dir, tpl)) && !out_of_map(tpl->map, nx, ny)) {
2660  if (OUT_OF_REAL_MAP(tpl->map, nx, ny)) {
2661  m = get_map_from_coord(tpl->map, &nx, &ny);
2662  if (!m)
2663  return; /* Don't think this should happen */
2664  } else
2665  m = tpl->map;
2666 
2667  if (GET_MAP_OB(m, nx, ny) == NULL) {
2668  /* LOG(llevError, "player_move_attack: GET_MAP_OB returns NULL, but player can not move there.\n");*/
2669  return;
2670  }
2671 
2672  mon = NULL;
2673  /* Go through all the objects, and find ones of interest. Only stop if
2674  * we find a monster - that is something we know we want to attack.
2675  * if its a door or barrel (can roll) see if there may be monsters
2676  * on the space
2677  */
2678  FOR_MAP_PREPARE(m, nx, ny, tmp) {
2679  if (tmp == op) {
2680  continue;
2681  }
2682  if (QUERY_FLAG(tmp, FLAG_ALIVE)) {
2683  mon = tmp;
2684  /* Gros: Objects like (pass-through) doors are alive, but haven't
2685  * their monster flag set - so this is a good way attack real
2686  * monsters in priority.
2687  */
2688  if (QUERY_FLAG(tmp, FLAG_MONSTER))
2689  break;
2690  }
2691  if (tmp->type == LOCKED_DOOR || QUERY_FLAG(tmp, FLAG_CAN_ROLL))
2692  mon = tmp;
2693  } FOR_MAP_FINISH();
2694 
2695  if (mon == NULL) /* This happens anytime the player tries to move */
2696  return; /* into a wall */
2697 
2698  mon = HEAD(mon);
2699  if ((mon->type == DOOR && mon->stats.hp >= 0) || (mon->type == LOCKED_DOOR))
2700  if (player_attack_door(op, mon))
2701  return;
2702 
2703  /* The following deals with possibly attacking peaceful
2704  * or friendly creatures. Basically, all players are considered
2705  * unaggressive. If the moving player has peaceful set, then the
2706  * object should be pushed instead of attacked. It is assumed that
2707  * if you are braced, you will not attack friends accidently,
2708  * and thus will not push them.
2709  */
2710 
2711  /* If the creature is a pet, push it even if the player is not
2712  * peaceful. Our assumption is the creature is a pet if the
2713  * player owns it and it is either friendly or unaggressive.
2714  */
2715  mon_owner = object_get_owner(mon);
2716  if ((op->type == PLAYER)
2717  && (mon_owner == op || (mon_owner != NULL && mon_owner->type == PLAYER && mon_owner->contr->party != NULL && mon_owner->contr->party == op->contr->party))
2719  /* If we're braced, we don't want to switch places with it */
2720  if (op->contr->braced)
2721  return;
2722  play_sound_map(SOUND_TYPE_LIVING, mon, dir, "push");
2723  (void)push_ob(mon, dir, op);
2724  if (op->contr->tmp_invis || op->hide)
2725  make_visible(op);
2726  return;
2727  }
2728 
2729  /* in certain circumstances, you shouldn't attack friendly
2730  * creatures. Note that if you are braced, you can't push
2731  * someone, but put it inside this loop so that you won't
2732  * attack them either.
2733  */
2734  if ((mon->type == PLAYER || mon->enemy != op)
2736  && (op->contr->peaceful && !on_battleground)) {
2737  if (!op->contr->braced) {
2738  play_sound_map(SOUND_TYPE_LIVING, mon, dir, "push");
2739  (void)push_ob(mon, dir, op);
2740  } else {
2742  "You withhold your attack");
2743  }
2744  if (op->contr->tmp_invis || op->hide)
2745  make_visible(op);
2746  }
2747 
2748  /* If the object is a boulder or other rollable object, then
2749  * roll it if not braced. You can't roll it if you are braced.
2750  */
2751  else if (QUERY_FLAG(mon, FLAG_CAN_ROLL) && (!op->contr->braced)) {
2752  recursive_roll(mon, dir, op);
2753  if (action_makes_visible(op))
2754  make_visible(op);
2755 
2756  /* Any generic living creature. Including things like doors.
2757  * Way it works is like this: First, it must have some hit points
2758  * and be living. Then, it must be one of the following:
2759  * 1) Not a player, 2) A player, but of a different party. Note
2760  * that party_number -1 is no party, so attacks can still happen.
2761  */
2762  } else if ((mon->stats.hp >= 0)
2764  && ((mon->type != PLAYER || op->contr->party == NULL || op->contr->party != mon->contr->party))) {
2765  /* If the player hasn't hit something this tick, and does
2766  * so, give them speed boost based on weapon speed. Doing
2767  * it here is better than process_players2, which basically
2768  * incurred a 1 tick offset.
2769  */
2770  if (op->weapon_speed_left < 0) {
2771  op->speed_left = -0.01;
2772  return;
2773  }
2774  op->weapon_speed_left -= 1.0;
2775 
2776  skill_attack(mon, op, 0, NULL, NULL);
2777 
2778  /* If attacking another player, that player gets automatic
2779  * hitback, and doesn't loose luck either.
2780  * Disable hitback on the battleground or if the target is
2781  * the wiz.
2782  */
2783  if (mon->type == PLAYER
2784  && mon->stats.hp >= 0
2785  && !mon->contr->has_hit
2786  && !on_battleground
2787  && !QUERY_FLAG(mon, FLAG_WIZ)) {
2788  short luck = mon->stats.luck;
2789  mon->contr->has_hit = 1;
2790  skill_attack(op, mon, 0, NULL, NULL);
2791  mon->stats.luck = luck;
2792  }
2793  if (action_makes_visible(op))
2794  make_visible(op);
2795  }
2796  } /* if player should attack something */
2797  else if (bef != tpl->map) {
2798  player_map_change_common(op, bef, tpl->map);
2799  }
2800 }
2801 
2808 static void update_transport_block(object *transport, int dir) {
2809  object *part;
2810  int sx, sy, x, y;
2811 
2812  object_get_multi_size(transport, &sx, &sy, NULL, NULL);
2813  assert(sx == sy);
2814 
2815  if (dir == 1 || dir == 5) {
2816  part = transport;
2817  for (y = 0; y <= sy; y++) {
2818  for (x = 0; x < sx; x++) {
2819  part->move_type = transport->move_type;
2820  part = part->more;
2821  }
2822  part->move_type = 0;
2823  part = part->more;
2824  }
2825  } else if (dir == 3 || dir == 7) {
2826  part = transport;
2827  for (y = 0; y < sy; y++) {
2828  for (x = 0; x <= sx; x++) {
2829  part->move_type = transport->move_type;
2830  part = part->more;
2831  }
2832  }
2833  while (part) {
2834  part->move_type = 0;
2835  part = part->more;
2836  }
2837  } else {
2838  for (part = transport; part; part = part->more) {
2839  part->move_type = transport->move_type;
2840  }
2841  }
2842 }
2843 
2853 static int turn_one_transport(object *transport, object *captain, int dir) {
2854  int x, y, scroll_dir = 0;
2855 
2856  assert(transport->type == TRANSPORT);
2857 
2858  x = transport->x;
2859  y = transport->y;
2860 
2861  if (transport->direction == 1 && dir == 8) {
2862  x--;
2863  } else if (transport->direction == 2 && dir == 3) {
2864  y++;
2865  } else if (transport->direction == 3 && dir == 2) {
2866  y--;
2867  } else if (transport->direction == 5 && dir == 6) {
2868  x--;
2869  } else if (transport->direction == 6 && dir == 5) {
2870  x++;
2871  } else if (transport->direction == 7 && dir == 8) {
2872  y--;
2873  } else if (transport->direction == 8 && dir == 7) {
2874  y++;
2875  } else if (transport->direction == 8 && dir == 1) {
2876  x++;
2877  }
2878 
2879  update_transport_block(transport, dir);
2880  object_remove(transport);
2881  if (ob_blocked(transport, transport->map, x, y)) {
2882  update_transport_block(transport, transport->direction);
2883  object_insert_in_map_at(transport, transport->map, NULL, 0, x, y);
2884  return 2;
2885  }
2886 
2887  if (x != transport->x || y != transport->y) {
2888 /* assert(scroll_dir != 0);*/
2889 
2890  FOR_INV_PREPARE(transport, pl) {
2891  if (pl->type == PLAYER) {
2892  pl->contr->do_los = 1;
2893  pl->map = transport->map;
2894  pl->x = x;
2895  pl->y = y;
2896  esrv_map_scroll(pl->contr->socket, freearr_x[scroll_dir], freearr_y[scroll_dir]);
2897  pl->contr->socket->update_look = 1;
2898  pl->contr->socket->look_position = 0;
2899  }
2900  } FOR_INV_FINISH();
2901  }
2902 
2903  object_insert_in_map_at(transport, transport->map, NULL, 0, x, y);
2904  transport->direction = dir;
2905  transport->facing = dir;
2906  animate_object(transport, dir);
2907  captain->direction = dir;
2908  return 1;
2909 }
2910 
2923 static int turn_transport(object *transport, object *captain, int dir) {
2924  assert(transport->type == TRANSPORT);
2925 
2926  if (object_value_set(transport, "turnable_transport") == false) {
2927  transport->direction = dir;
2928  transport->facing = dir;
2929  if (QUERY_FLAG(transport, FLAG_ANIMATE)) {
2930  animate_object(transport, dir);
2931  }
2932  captain->direction = dir;
2933  return 0;
2934  }
2935 
2936  if (transport->direction == dir)
2937  return 0;
2938 
2939  if (absdir(transport->direction-dir) > 2)
2940  return turn_one_transport(transport, captain, absdir(transport->direction+1));
2941  else
2942  return turn_one_transport(transport, captain, absdir(transport->direction-1));
2943 }
2944 
2956 int move_player(object *op, int dir) {
2957  object *transport = op->contr->transport; //< Transport player is in
2958 
2959  if (!transport && (op->map == NULL || op->map->in_memory != MAP_IN_MEMORY))
2960  return 0;
2961 
2962  /* Sanity check: make sure dir is valid */
2963  if ((dir < 0) || (dir >= 9)) {
2964  LOG(llevError, "move_player: invalid direction %d\n", dir);
2965  return 0;
2966  }
2967 
2968  if (QUERY_FLAG(op, FLAG_CONFUSED) && dir)
2969  dir = get_randomized_dir(dir);
2970 
2971  op->facing = dir;
2972 
2973  if (transport) {
2974  /* transport->contr is set up for the person in charge of the boat.
2975  * if that isn't this person, he can't steer it, etc
2976  */
2977  if (transport->contr != op->contr)
2978  return 0;
2979 
2980  /* Transport is out of movement. But update dir so it at least
2981  * will point in the same direction if player is running.
2982  */
2983  if (transport->speed_left < 0.0) {
2984  return 0;
2985  }
2986  /* Remove transport speed. Give player just a little speed -
2987  * enough so that they will get an action again quickly.
2988  */
2989  transport->speed_left -= 1.0;
2990  if (op->speed_left < 0.0)
2991  op->speed_left = -0.01;
2992 
2993  int turn = turn_transport(transport, op, dir);
2994  if (turn != 0)
2995  return 0;
2996  } else {
2997  if (op->hide) {
2998  do_hidden_move(op);
2999  }
3000 
3001  /* it is important to change the animation now, as fire or move_player_attack can start a compound animation,
3002  * and leave us with state = 0, which we don't want to change again. */
3003  op->state++; /* player moved, so change animation. */
3004  animate_object(op, op->facing);
3005  }
3006 
3007  if (op->contr->fire_on) {
3008  fire(op, dir);
3009  } else
3010  move_player_attack(op, dir);
3011 
3012  int pick = check_pick(op);
3013 
3014  /* Add special check for newcs players and fire on - this way, the
3015  * server can handle repeat firing.
3016  */
3017  if (op->contr->fire_on || (op->contr->run_on && pick != 0)) {
3018  op->direction = dir;
3019  } else {
3020  op->direction = 0;
3021  }
3022  return 0;
3023 }
3024 
3035 int face_player(object *op, int dir) {
3036  object *transport = op->contr->transport; //< Transport player is in
3037 
3038  if (!transport && (op->map == NULL || op->map->in_memory != MAP_IN_MEMORY))
3039  return 0;
3040 
3041  /* Sanity check: make sure dir is valid */
3042  if ((dir < 0) || (dir >= 9)) {
3043  LOG(llevError, "move_player: invalid direction %d\n", dir);
3044  return 0;
3045  }
3046 
3047  if (QUERY_FLAG(op, FLAG_CONFUSED) && dir)
3048  dir = get_randomized_dir(dir);
3049 
3050  op->facing = dir;
3051 
3052  if (transport) {
3053  /* transport->contr is set up for the person in charge of the boat.
3054  * if that isn't this person, he can't steer it, etc
3055  */
3056  if (transport->contr != op->contr)
3057  return 0;
3058 
3059  turn_transport(transport, op, dir);
3060  } else {
3061  if (op->hide) {
3062  do_hidden_move(op);
3063  }
3064 
3065  /* it is important to change the animation now, as fire or move_player_attack can start a compound animation,
3066  * and leave us with state = 0, which we don't want to change again. */
3067  op->state++; /* player moved, so change animation. */
3068  animate_object(op, op->facing);
3069  }
3070 
3071  /* Add special check for newcs players and fire on - this way, the
3072  * server can handle repeat firing.
3073  */
3074  if (op->contr->fire_on || op->contr->run_on) {
3075  op->direction = dir;
3076  } else {
3077  op->direction = 0;
3078  }
3079  return 0;
3080 }
3081 
3094 int handle_newcs_player(object *op) {
3095  if (op->contr->hidden) {
3096  op->invisible = 1000;
3097  /* the socket code flashes the player visible/invisible
3098  * depending on the value if invisible, so we need to
3099  * alternate it here for it to work correctly.
3100  */
3101  if (pticks&2)
3102  op->invisible--;
3103  } else if (op->invisible && !(QUERY_FLAG(op, FLAG_MAKE_INVIS))) {
3104  op->invisible--;
3105  if (!op->invisible) {
3106  make_visible(op);
3108  "Your invisibility spell runs out.");
3109  }
3110  }
3111 
3112  if (QUERY_FLAG(op, FLAG_SCARED)) {
3113  flee_player(op);
3114  /* If player is still scared, that is his action for this tick */
3115  if (QUERY_FLAG(op, FLAG_SCARED)) {
3116  op->speed_left--;
3117  return 0;
3118  }
3119  }
3120 
3121  /* I've been seeing crashes where the golem has been destroyed, but
3122  * the player object still points to the defunct golem. The code that
3123  * destroys the golem looks correct, and it doesn't always happen, so
3124  * put this in a a workaround to clean up the golem pointer.
3125  */
3126  if (op->contr->ranges[range_golem]
3127  && ((op->contr->golem_count != op->contr->ranges[range_golem]->count) || QUERY_FLAG(op->contr->ranges[range_golem], FLAG_REMOVED))) {
3128  op->contr->ranges[range_golem] = NULL;
3129  op->contr->golem_count = 0;
3130  }
3131 
3132  /*
3133  * If the player has been paralyzed, we unmark the flag and give a message to the player
3134  */
3135  if (QUERY_FLAG(op, FLAG_PARALYZED)) {
3137  // TODO: Is this check necessary? We are in player.c, after all.
3138  if (op->type == PLAYER)
3139  {
3141  "You can stretch your stiff joints once more.");
3142  }
3143  }
3144 
3145  if (op->direction && (op->contr->run_on || op->contr->fire_on)) {
3146  /* All move commands take 1 tick, at least for now */
3147  op->speed_left--;
3148 
3149  /* Instead of all the stuff below, let move_player take care
3150  * of it. Also, some of the skill stuff is only put in
3151  * there, as well as the confusion stuff.
3152  */
3153  move_player(op, op->direction);
3154  if (op->speed_left > 0)
3155  return 1;
3156  else
3157  return 0;
3158  }
3159  return 0;
3160 }
3161 
3172 static int save_life(object *op) {
3173  object *tmp;
3174 
3175  if (!QUERY_FLAG(op, FLAG_LIFESAVE))
3176  return 0;
3177 
3179  if (tmp != NULL) {
3180  char name[MAX_BUF];
3181 
3183  play_sound_map(SOUND_TYPE_ITEM, tmp, 0, "evaporate");
3185  "Your %s vibrates violently, then evaporates.",
3186  name);
3187  object_remove(tmp);
3190  if (op->stats.hp < 0)
3191  op->stats.hp = op->stats.maxhp;
3192  if (op->stats.food < 0)
3193  op->stats.food = MAX_FOOD;
3194  fix_object(op);
3195  return 1;
3196  }
3197  LOG(llevError, "Error: LIFESAVE set without applied object.\n");
3199  enter_player_savebed(op); /* bring him home. */
3200  return 0;
3201 }
3202 
3215 void remove_unpaid_objects(object *op, object *env, int free_items) {
3217  if (QUERY_FLAG(op, FLAG_UNPAID)) {
3218  object_remove(op);
3219  if (free_items)
3221  else
3222  object_insert_in_map_at(op, env->map, NULL, 0, env->x, env->y);
3223  } else if (op->inv)
3224  remove_unpaid_objects(op->inv, env, free_items);
3226 }
3227 
3245 static const char *gravestone_text(object *op, char *buf2, int len) {
3246  char buf[MAX_BUF];
3247  time_t now = time(NULL);
3248 
3249  strncpy(buf2, " R.I.P.\n\n", len);
3250  if (op->type == PLAYER)
3251  snprintf(buf, sizeof(buf), "%s the %s\n", op->name, op->contr->title);
3252  else
3253  snprintf(buf, sizeof(buf), "%s\n", op->name);
3254  strncat(buf2, " ", 20-strlen(buf)/2);
3255  strncat(buf2, buf, len-strlen(buf2)-1);
3256  if (op->type == PLAYER)
3257  snprintf(buf, sizeof(buf), "who was in level %d when killed\n", op->level);
3258  else
3259  snprintf(buf, sizeof(buf), "who was in level %d when died.\n\n", op->level);
3260  strncat(buf2, " ", 20-strlen(buf)/2);
3261  strncat(buf2, buf, len-strlen(buf2)-1);
3262  if (op->type == PLAYER) {
3263  snprintf(buf, sizeof(buf), "by %s.\n\n", op->contr->killer);
3264  strncat(buf2, " ", 21-strlen(buf)/2);
3265  strncat(buf2, buf, len-strlen(buf2)-1);
3266  }
3267  strftime(buf, MAX_BUF, "%b %d %Y\n", localtime(&now));
3268  strncat(buf2, " ", 20-strlen(buf)/2);
3269  strncat(buf2, buf, len-strlen(buf2)-1);
3270  return buf2;
3271 }
3272 
3273 static bool starving(object *op) {
3274  return op->stats.food <= 0;
3275 }
3276 
3284 void do_some_living(object *op) {
3285  int last_food = op->stats.food;
3286  int gen_hp, gen_sp, gen_grace;
3287  int rate_hp = 1200;
3288  int rate_sp = 2500;
3289  int rate_grace = 2000;
3290 
3291  if (op->contr->state == ST_PLAYING) {
3292  /* these next three if clauses make it possible to SLOW DOWN
3293  hp/grace/spellpoint regeneration. */
3294  if (op->contr->gen_hp >= 0)
3295  gen_hp = (op->contr->gen_hp+1)*op->stats.maxhp;
3296  else {
3297  gen_hp = op->stats.maxhp;
3298  rate_hp -= rate_hp/2*op->contr->gen_hp;
3299  }
3300  if (op->contr->gen_sp >= 0)
3301  gen_sp = (op->contr->gen_sp+1)*op->stats.maxsp;
3302  else {
3303  gen_sp = op->stats.maxsp;
3304  rate_sp -= rate_sp/2*op->contr->gen_sp;
3305  }
3306  if (op->contr->gen_grace >= 0)
3307  gen_grace = (op->contr->gen_grace+1)*op->stats.maxgrace;
3308  else {
3309  gen_grace = op->stats.maxgrace;
3310  rate_grace -= rate_grace/2*op->contr->gen_grace;
3311  }
3312 
3313  /* Regenerate Spell Points */
3314  if (op->contr->ranges[range_golem] == NULL && --op->last_sp < 0) {
3315  gen_sp = gen_sp*10/MAX(op->contr->gen_sp_armour, 10);
3316  if (op->stats.sp < op->stats.maxsp) {
3317  op->stats.sp++;
3318  /* dms do not consume food */
3319  if (!QUERY_FLAG(op, FLAG_WIZ)) {
3320  op->stats.food--;
3321  if (op->contr->digestion < 0)
3322  op->stats.food += op->contr->digestion;
3323  else if (op->contr->digestion > 0
3324  && random_roll(0, op->contr->digestion, op, PREFER_HIGH))
3325  op->stats.food = last_food;
3326  }
3327  }
3328  op->last_sp = rate_sp/(MAX(gen_sp, 20)+10);
3329  }
3330 
3331  /* Regenerate Grace */
3332  /* I altered this a little - maximum grace is only achieved through prayer -b.t.*/
3333  if (--op->last_grace < 0) {
3334  if (op->stats.grace < op->stats.maxgrace/2)
3335  op->stats.grace++; /* no penalty in food for regaining grace */
3336  op->last_grace = rate_grace/(MAX(gen_grace, 20)+10);
3337  /* wearing stuff doesn't detract from grace generation. */
3338  }
3339 
3340  /* Regenerate Hit Points (unless you are a wraith player) */
3341  if (--op->last_heal < 0 && !is_wraith_pl(op) && !starving(op)) {
3342  if (op->stats.hp < op->stats.maxhp) {
3343  op->stats.hp++;
3344  /* dms do not consume food */
3345  if (!QUERY_FLAG(op, FLAG_WIZ)) {
3346  op->stats.food--;
3347  if (op->contr->digestion < 0)
3348  op->stats.food += op->contr->digestion;
3349  else if (op->contr->digestion > 0
3350  && random_roll(0, op->contr->digestion, op, PREFER_HIGH))
3351  op->stats.food = last_food;
3352  }
3353  }
3354  op->last_heal = rate_hp/(MAX(gen_hp, 20)+10);
3355  }
3356 
3357  /* Digestion */
3358  if (--op->last_eat < 0) {
3359  int bonus = MAX(op->contr->digestion, 0);
3360  int penalty = MAX(-op->contr->digestion, 0);
3361  if (op->contr->gen_hp > 0)
3362  op->last_eat = 25*(1+bonus)/(op->contr->gen_hp+penalty+1);
3363  else
3364  op->last_eat = 25*(1+bonus)/(penalty+1);
3365  /* dms do not consume food */
3366  if (!QUERY_FLAG(op, FLAG_WIZ))
3367  op->stats.food--;
3368  }
3369  }
3370 
3371  // Grab a bite of food if able, starving, and still alive.
3372  if (op->contr->state == ST_PLAYING && starving(op) && op->stats.hp >= 0) {
3373  if (is_wraith_pl(op))
3374  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ITEM, MSG_TYPE_ITEM_REMOVE, "You feel a hunger for living flesh.");
3375  /* Only allow eat if not paralyzed. Otherwise our paralyzed player is "moving" to eat.
3376  * Neila Hawkins 2017-08-23
3377  */
3378  else if (!QUERY_FLAG(op, FLAG_PARALYZED)){
3379  object *flesh = NULL;
3380 
3381  FOR_INV_PREPARE(op, tmp) {
3382  if (!QUERY_FLAG(tmp, FLAG_UNPAID)) {
3383  if (tmp->type == FOOD || tmp->type == DRINK || tmp->type == POISON) {
3385  "You blindly grab for a bite of food.");
3386  apply_manual(op, tmp, 0);
3387  if (op->stats.food >= 0 || op->stats.hp < 0)
3388  break;
3389  } else if (tmp->type == FLESH)
3390  flesh = tmp;
3391  } /* End if paid for object */
3392  } FOR_INV_FINISH(); /* end of for loop */
3393  /* If player is still starving, it means they don't have any food, so
3394  * eat flesh instead.
3395  */
3396  if (op->stats.food < 0 && op->stats.hp >= 0 && flesh) {
3398  "You blindly grab for a bite of food.");
3399  apply_manual(op, flesh, 0);
3400  }
3401  } /* end not wraith and not paralyzed */
3402  else { // Print a message for when the player is starving and paralyzed
3403  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ITEM, MSG_TYPE_ITEM_REMOVE, "Your stomach rumbles, but you can't reach your food.");
3404  } /* end not wraith and is paralyzed */
3405  } /* end if player is starving */
3406 
3407  // Prevent food from going negative, then deal constant hunger damage.
3408  if (starving(op)) {
3409  op->stats.food = 0;
3410  op->stats.hp -= 1;
3411  }
3412 
3413  if (!op->contr->state && !QUERY_FLAG(op, FLAG_WIZ) && (op->stats.hp <= 0))
3414  kill_player(op, NULL);
3415 }
3416 
3423 static void loot_object(object *op) {
3424  object *tmp2;
3425 
3426  if (op->container) { /* close open sack first */
3427  apply_container(op, op->container, AP_NULL);
3428  }
3429 
3430  FOR_INV_PREPARE(op, tmp) {
3431  if (tmp->invisible)
3432  continue;
3433  object_remove(tmp);
3434  tmp->x = op->x,
3435  tmp->y = op->y;
3436  if (tmp->type == CONTAINER) { /* empty container to ground */
3437  loot_object(tmp);
3438  }
3439  if (!QUERY_FLAG(tmp, FLAG_UNIQUE)
3441  if (tmp->nrof > 1) {
3442  tmp2 = object_split(tmp, 1+RANDOM()%(tmp->nrof-1), NULL, 0);
3444  object_insert_in_map_at(tmp, op->map, NULL, 0, op->x, op->y);
3445  } else
3447  } else
3448  object_insert_in_map_at(tmp, op->map, NULL, 0, op->x, op->y);
3449  } FOR_INV_FINISH();
3450 }
3451 
3462 static void restore_player(object *op) {
3463  object *tmp;
3464  archetype *at = find_archetype("poisoning");
3465  if (at != NULL) {
3466  tmp = arch_present_in_ob(at, op);
3467  if (tmp) {
3468  object_remove(tmp);
3471  "Your body feels cleansed");
3472  }
3473  }
3474 
3475  at = find_archetype("confusion");
3476  if (at != NULL) {
3477  tmp = arch_present_in_ob(at, op);
3478  if (tmp) {
3479  object_remove(tmp);
3482  "Your mind feels clearer");
3483  }
3484  }
3485 
3486  cure_disease(op, NULL, NULL); /* remove any disease */
3487 }
3488 
3500 void kill_player(object *op, const object *killer) {
3501  char buf[MAX_BUF];
3502  int x, y;
3503  object *tmp;
3504  archetype *trophy = NULL;
3505 
3506  /* Don't die if the player's life can be saved. */
3507  if (save_life(op)) {
3508  return;
3509  }
3510 
3511  /* If player dies on BATTLEGROUND, no stat/exp loss! For Combat-Arenas
3512  * in cities ONLY!!! It is very important that this doesn't get abused.
3513  * Look at op_on_battleground() for more info --AndreasV
3514  */
3515  if (op_on_battleground(op, &x, &y, &trophy)) {
3516  assert(trophy != NULL);
3518  "You have been defeated in combat!\n"
3519  "Local medics have saved your life...");
3520 
3521  /* restore player */
3522  restore_player(op);
3523 
3524  op->stats.hp = op->stats.maxhp;
3525  if (op->stats.food <= 0)
3526  op->stats.food = MAX_FOOD;
3527 
3528  /* create a bodypart-trophy to make the winner happy */
3529  tmp = arch_to_object(trophy);
3530  if (tmp != NULL) {
3531  snprintf(buf, sizeof(buf), "%s's %s", op->name, tmp->name);
3532  tmp->name = add_string(buf);
3533 
3534  snprintf(buf, sizeof(buf),
3535  "This %s was %s %s the %s, who was defeated at level %d by %s.\n",
3536  tmp->name, tmp->type == FLESH ? "cut off" : "taken from",
3537  op->name, op->contr->title,
3538  (int)(op->level), op->contr->killer);
3539 
3541  tmp->type = 0;
3542  tmp->value = 0;
3543  tmp->material = 0;
3544  tmp->materialname = NULL;
3545  object_insert_in_map_at(tmp, op->map, op, 0, op->x, op->y);
3546  }
3547 
3548  /* teleport defeated player to new destination*/
3549  transfer_ob(op, x, y, 0, NULL);
3550  op->contr->braced = 0;
3551  return;
3552  }
3553 
3554  if (events_execute_object_event(op, EVENT_DEATH, NULL, NULL, NULL, SCRIPT_FIX_ALL) != 0)
3555  return;
3556 
3558  if (starving(op)) {
3559  snprintf(buf, sizeof(buf), "%s starved to death.", op->name);
3560  strcpy(op->contr->killer, "starvation");
3561  } else {
3562  snprintf(buf, sizeof(buf), "%s died.", op->name);
3563  }
3564  play_sound_player_only(op->contr, SOUND_TYPE_LIVING, op, 0, "death");
3565 
3566  if (settings.not_permadeth == TRUE) {
3568  } else {
3570  }
3571 }
3572 
3581 static void kill_player_not_permadeath(object *op) {
3582  int num_stats_lose;
3583  int will_kill_again;
3584  int lost_a_stat;
3585  int z;
3586  object *tmp;
3587  char buf[MAX_BUF];
3588  archetype *at;
3589 
3590  /* Basically two ways to go - remove a stat permanently, or just
3591  * make it depletion. This bunch of code deals with that aspect
3592  * of death.
3593  */
3595  /* If stat loss is permanent, lose one stat only. */
3596  /* Lower level chars don't lose as many stats because they suffer
3597  more if they do. */
3598  /* Higher level characters can afford things such as potions of
3599  restoration, or better, stat potions. So we slug them that
3600  little bit harder. */
3601  /* GD */
3603  num_stats_lose = 1;
3604  else
3605  num_stats_lose = 1+op->level/BALSL_NUMBER_LOSSES_RATIO;
3606  } else {
3607  num_stats_lose = 1;
3608  }
3609  lost_a_stat = 0;
3610 
3611  for (z = 0; z < num_stats_lose; z++) {
3613  int i;
3614 
3615  /* Pick a random stat and take a point off it. Tell the player
3616  * what he lost.
3617  */
3618  i = RANDOM()%7;
3619  change_attr_value(&(op->stats), i, -1);
3621  change_attr_value(&(op->contr->orig_stats), i, -1);
3622  check_stat_bounds(&(op->contr->orig_stats), MIN_STAT, settings.max_stat);
3625  lose_msg[i]);
3626  lost_a_stat = 1;
3627  } else {
3628  /* deplete a stat */
3630  if (deparch == NULL) {
3631  continue;
3632  }
3633  object *dep;
3634  int lose_this_stat;
3635  int i;
3636 
3637  i = RANDOM()%7;
3638  dep = arch_present_in_ob(deparch, op);
3639  if (!dep) {
3640  dep = arch_to_object(deparch);
3641  object_insert_in_ob(dep, op);
3642  }
3643  lose_this_stat = 1;
3645  int this_stat;
3646 
3647  /* GD */
3648  /* Get the stat that we're about to deplete. */
3649  this_stat = get_attr_value(&(dep->stats), i);
3650  if (this_stat < 0) {
3651  int loss_chance = 1+op->level/BALSL_LOSS_CHANCE_RATIO;
3652  int keep_chance = this_stat*this_stat;
3653  /* Yes, I am paranoid. Sue me. */
3654  if (keep_chance < 1)
3655  keep_chance = 1;
3656 
3657  /* There is a maximum depletion total per level. */
3658  if (this_stat < -1-op->level/BALSL_MAX_LOSS_RATIO) {
3659  lose_this_stat = 0;
3660  /* Take loss chance vs keep chance to see if we
3661  retain the stat. */
3662  } else {
3663  if (random_roll(0, loss_chance+keep_chance-1, op, PREFER_LOW) < keep_chance)
3664  lose_this_stat = 0;
3665  /* 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"); */
3666  }
3667  }
3668  }
3669 
3670  if (lose_this_stat) {
3671  int this_stat;
3672 
3673  this_stat = get_attr_value(&(dep->stats), i);
3674  /* We could try to do something clever like find another
3675  * stat to reduce if this fails. But chances are, if
3676  * stats have been depleted to -50, all are pretty low
3677  * and should be roughly the same, so it shouldn't make a
3678  * difference.
3679  */
3680  if (this_stat >= -50) {
3681  change_attr_value(&(dep->stats), i, -1);
3682  SET_FLAG(dep, FLAG_APPLIED);
3684  drain_msg[i]);
3685  fix_object(op);
3686  lost_a_stat = 1;
3687  }
3688  }
3689  }
3690  }
3691  /* If no stat lost, tell the player. */
3692  if (!lost_a_stat) {
3693  /* determine_god() seems to not work sometimes... why is this? Should I be using something else? GD */
3694  const char *god = determine_god(op);
3695 
3696  if (god && (strcmp(god, "none")))
3699  "For a brief moment you feel the holy presence of %s protecting you",
3700  god);
3701  else
3704  "For a brief moment you feel a holy presence protecting you.");
3705  }
3706 
3707  /* Put a gravestone up where the character 'almost' died. List the
3708  * exp loss on the stone.
3709  */
3710  at = find_archetype("gravestone");
3711  if (at != NULL) {
3712  tmp = arch_to_object(at);
3713  snprintf(buf, sizeof(buf), "%s's gravestone", op->name);
3714  FREE_AND_COPY(tmp->name, buf);
3715  snprintf(buf, sizeof(buf), "%s's gravestones", op->name);
3716  FREE_AND_COPY(tmp->name_pl, buf);
3717  snprintf(buf, sizeof(buf), "RIP\nHere rests the hero %s the %s,\n"
3718  "who was killed\n"
3719  "by %s.\n",
3720  op->name, op->contr->title,
3721  op->contr->killer);
3723  object_insert_in_map_at(tmp, op->map, NULL, 0, op->x, op->y);
3724  }
3725 
3726  /* restore player: remove any poisoning, disease and confusion the
3727  * character may be suffering.*/
3728  restore_player(op);
3729 
3730  /* Subtract the experience points, if we died cause of food, give
3731  * us food, and reset HP's...
3732  */
3734  if (op->stats.food < 100)
3735  op->stats.food = 900;
3736  op->stats.hp = op->stats.maxhp;
3737  op->stats.sp = MAX(op->stats.sp, op->stats.maxsp);
3738  op->stats.grace = MAX(op->stats.grace, op->stats.maxgrace);
3739 
3740  /* Check to see if the player is in a shop. IF so, then check to see if
3741  * the player has any unpaid items. If so, remove them and put them back
3742  * in the map.
3743  *
3744  * If they are not in a shop, just free the unpaid items instead of
3745  * putting them back on map.
3746  */
3747  if (shop_contains(op))
3748  remove_unpaid_objects(op->inv, op, 0);
3749  else
3750  remove_unpaid_objects(op->inv, op, 1);
3751 
3752  /* Move player to his current respawn-position (usually last savebed) */
3754 
3755  /* Save the player before inserting the force to reduce chance of abuse. */
3756  op->contr->braced = 0;
3757  /* don't pick up in apartment */
3758  if (op->contr->mode & PU_NEWMODE) {
3759  op->contr->mode = op->contr->mode | PU_INHIBIT;
3760  esrv_send_pickup(op->contr);
3761  } else {
3762  op->contr->mode = 0;
3763  }
3764  if ( op->contr->search_str[0] ) command_search_items(op,NULL); /* turn off search-items */
3765  save_player(op, 1);
3766 
3767  /* it is possible that the player has blown something up
3768  * at his savebed location, and that can have long lasting
3769  * spell effects. So first see if there is a spell effect
3770  * on the space that might harm the player.
3771  */
3772  will_kill_again = 0;
3773  FOR_MAP_PREPARE(op->map, op->x, op->y, tmp)
3774  if (tmp->type == SPELL_EFFECT)
3775  will_kill_again |= tmp->attacktype;
3776  FOR_MAP_FINISH();
3777  if (will_kill_again) {
3778  object *force;
3779  int at;
3780 
3782  /* 50 ticks should be enough time for the spell to abate */
3783  force->speed = 0.1;
3784  force->speed_left = -5.0;
3786  for (at = 0; at < NROFATTACKS; at++) {
3787  if (will_kill_again&(1<<at))
3788  force->resist[at] = 100;
3789  }
3791  fix_object(op);
3792  }
3793 
3794  /* Tell the player they have died */
3796  "YOU HAVE DIED.");
3797 }
3798 
3805 static void kill_player_permadeath(object *op) {
3806  char buf[MAX_BUF];
3807  char ac_buf[MAX_BUF];
3808  int x, y;
3809  mapstruct *map;
3810  object *tmp;
3811  archetype *at;
3812 
3813  /* save the map location for corpse, gravestone*/
3814  x = op->x;
3815  y = op->y;
3816  map = op->map;
3817 
3818  party_leave(op);
3819  if (settings.set_title == TRUE)
3820  player_set_own_title(op->contr, "");
3821 
3822  /* buf should be the kill message */
3824  buf);
3825  hiscore_check(op, 0);
3826  if (op->contr->ranges[range_golem] != NULL) {
3827  remove_friendly_object(op->contr->ranges[range_golem]);
3828  object_remove(op->contr->ranges[range_golem]);
3829  object_free_drop_inventory(op->contr->ranges[range_golem]);
3830  op->contr->ranges[range_golem] = NULL;
3831  op->contr->golem_count = 0;
3832  }
3833  loot_object(op); /* Remove some of the items for good */
3834  object_remove(op);
3835  op->direction = 0;
3836 
3837  if (!QUERY_FLAG(op, FLAG_WAS_WIZ) && op->stats.exp) {
3838  if (settings.resurrection == TRUE) {
3839  /* save playerfile sans equipment when player dies
3840  * -then save it as player.pl.dead so that future resurrection
3841  * -type spells will work on them nicely
3842  */
3843  op->stats.hp = op->stats.maxhp;
3844  op->stats.food = MAX_FOOD;
3845 
3846  /* set the location of where the person will reappear when */
3847  /* maybe resurrection code should fix map also */
3848  safe_strncpy(op->contr->maplevel, settings.emergency_mapname,
3849  sizeof(op->contr->maplevel));
3850  if (op->map != NULL)
3851  op->map = NULL;
3852  op->x = settings.emergency_x;
3853  op->y = settings.emergency_y;
3854  save_player(op, 0);
3855  op->map = map;
3856  /* please see resurrection.c: peterm */
3857  dead_player(op);
3858  } else {
3859  delete_character(op->name);
3860 
3861  /* Remove player from account list and send back data if needed */
3862  if (op->contr->socket->account_chars != NULL) {
3863  account_char_remove(op->contr->socket->account_chars, op->name);
3864  account_char_save(op->contr->socket->account_chars);
3865  /* char information is reloaded in send_account_players below */
3866  account_char_free(op->contr->socket->account_chars);
3867  op->contr->socket->account_chars = NULL;
3868  account_remove_player(op->contr->socket->account_name, op->name);
3869  send_account_players(op->contr->socket);
3870  }
3871  }
3872  }
3873  play_again(op);
3874 
3875  /* peterm: added to create a corpse at deathsite. */
3876  at = find_archetype("corpse_pl");
3877  if (at != NULL) {
3878  tmp = arch_to_object(at);
3879  snprintf(buf, sizeof(buf), "%s", op->name);
3880  FREE_AND_COPY(tmp->name, buf);
3881  FREE_AND_COPY(tmp->name_pl, buf);
3882  tmp->level = op->level;
3883  object_set_msg(tmp, gravestone_text(op, buf, sizeof(buf)));
3885  /*
3886  * Put the account name under slaying.
3887  * Does not seem to cause weird effects, but more testing may ensure this.
3888  */
3889  snprintf(ac_buf, sizeof(ac_buf), "%s", op->contr->socket->account_name);
3890  FREE_AND_COPY(tmp->slaying, ac_buf);
3891  object_insert_in_map_at(tmp, map, NULL, 0, x, y);
3892  }
3893 }
3894 
3902 void fix_weight(void) {
3903  player *pl;
3904 
3905  for (pl = first_player; pl != NULL; pl = pl->next) {
3906  int old = pl->ob->carrying, sum = object_sum_weight(pl->ob);
3907 
3908  if (old == sum)
3909  continue;
3910  fix_object(pl->ob);
3911  LOG(llevDebug, "Fixed inventory in %s (%d -> %d)\n", pl->ob->name, old, sum);
3912  }
3913 }
3914 
3918 void fix_luck(void) {
3919  player *pl;
3920 
3921  for (pl = first_player; pl != NULL; pl = pl->next)
3922  if (!pl->ob->contr->state)
3923  change_luck(pl->ob, 0);
3924 }
3925 
3926 
3939 void cast_dust(object *op, object *throw_ob, int dir) {
3940  object *skop, *spob;
3941 
3942  skop = find_skill_by_name(op, throw_ob->skill);
3943 
3944  /* casting POTION 'dusts' is really a use_magic_item skill */
3945  if (op->type == PLAYER && throw_ob->type == POTION && !skop) {
3946  LOG(llevError, "Player %s lacks critical skill use_magic_item!\n", op->name);
3947  return;
3948  }
3949  spob = throw_ob->inv;
3950  if (op->type == PLAYER && spob)
3952  "You cast %s.",
3953  spob->name);
3954 
3955  cast_spell(op, throw_ob, dir, spob, NULL);
3956 
3957  if (!QUERY_FLAG(throw_ob, FLAG_REMOVED))
3958  object_remove(throw_ob);
3959  object_free_drop_inventory(throw_ob);
3960 }
3961 
3968 void make_visible(object *op) {
3969  op->hide = 0;
3970  op->invisible = 0;
3971  if (op->type == PLAYER) {
3972  op->contr->tmp_invis = 0;
3973  if (op->contr->invis_race)
3974  FREE_AND_CLEAR_STR(op->contr->invis_race);
3975  }
3977 }
3978 
3987 int is_true_undead(object *op) {
3988  if (QUERY_FLAG(&op->arch->clone, FLAG_UNDEAD))
3989  return 1;
3990 
3991  return 0;
3992 }
3993 
4004 int hideability(object *ob) {
4005  int i, level = 0, mflag;
4006  int16_t x, y;
4007 
4008  if (!ob || !ob->map)
4009  return 0;
4010 
4011  /* so, on normal lighted maps, its hard to hide */
4012  level = ob->map->darkness-2;
4013 
4014  /* this also picks up whether the object is glowing.
4015  * If you carry a light on a non-dark map, its not
4016  * as bad as carrying a light on a pitch dark map
4017  */
4018  if (has_carried_lights(ob))
4019  level = -(10+(2*ob->map->darkness));
4020 
4021  /* scan through all nearby squares for terrain to hide in */
4022  for (i = 0, x = ob->x, y = ob->y; i < 9; i++, x = ob->x+freearr_x[i], y = ob->y+freearr_y[i]) {
4023  mflag = get_map_flags(ob->map, NULL, x, y, NULL, NULL);
4024  if (mflag&P_OUT_OF_MAP) {
4025  continue;
4026  }
4027  if (mflag&P_BLOCKSVIEW) /* something to hide near! */
4028  level += 2;
4029  else /* open terrain! */
4030  level -= 1;
4031  }
4032 
4033  return level;
4034 }
4035 
4045 void do_hidden_move(object *op) {
4046  int hide = 0, num = random_roll(0, 19, op, PREFER_LOW);
4047  object *skop;
4048 
4049  if (!op || !op->map)
4050  return;
4051 
4053 
4054  /* its *extremely *hard to run and sneak/hide at the same time! */
4055  if (op->type == PLAYER && op->contr->run_on) {
4056  if (!skop || num >= skop->level) {
4058  "You ran too much! You are no longer hidden!");
4059  make_visible(op);
4060  return;
4061  } else
4062  num += 20;
4063  }
4064  num += op->map->difficulty;
4065  hide = hideability(op); /* modify by terrain hidden level */
4066  num -= hide;
4067  if ((op->type == PLAYER && hide < -10)
4068  || ((op->invisible -= num) <= 0)) {
4069  make_visible(op);
4070  if (op->type == PLAYER)
4072  "You moved out of hiding! You are visible!");
4073  } else if (op->type == PLAYER && skop) {
4074  change_exp(op, calc_skill_exp(op, NULL, skop), skop->skill, 0);
4075  }
4076 }
4077 
4086 int stand_near_hostile(object *who) {
4087  int i, friendly = 0, player = 0, mflags;
4088  mapstruct *m;
4089  int16_t x, y;
4090 
4091  if (!who)
4092  return 0;
4093 
4094  if (who->type == PLAYER)
4095  player = 1;
4096  else
4097  friendly = QUERY_FLAG(who, FLAG_FRIENDLY);
4098 
4099  /* search adjacent squares */
4100  for (i = 1; i < 9; i++) {
4101  x = who->x+freearr_x[i];
4102  y = who->y+freearr_y[i];
4103  m = who->map;
4104  mflags = get_map_flags(m, &m, x, y, &x, &y);
4105  /* space must be blocked if there is a monster. If not
4106  * blocked, don't need to check this space.
4107  */
4108  if (mflags&P_OUT_OF_MAP)
4109  continue;
4111  continue;
4112 
4113  FOR_MAP_PREPARE(m, x, y, tmp) {
4114  if ((player || friendly)
4117  return 1;
4118  else if (tmp->type == PLAYER) {
4119  /*don't let a hidden DM prevent you from hiding*/
4120  if (!QUERY_FLAG(tmp, FLAG_WIZ) || tmp->contr->hidden == 0)
4121  return 1;
4122  }
4123  } FOR_MAP_FINISH();
4124  }
4125  return 0;
4126 }
4127 
4154 int player_can_view(object *pl, object *op) {
4155  rv_vector rv;
4156  int dx, dy;
4157 
4158  if (!pl || !op)
4159  return 0;
4160 
4161  if (pl->type != PLAYER) {
4162  LOG(llevError, "player_can_view() called for non-player object\n");
4163  return -1;
4164  }
4165 
4166  op = HEAD(op);
4167  if (!get_rangevector(pl, op, &rv, 0x1))
4168  return 0;
4169 
4170  /* starting with the 'head' part, lets loop
4171  * through the object and find if it has any
4172  * part that is in the los array but isnt on
4173  * a blocked los square.
4174  * we use the archetype to figure out offsets.
4175  */
4176  while (op) {
4177  dx = rv.distance_x+op->arch->clone.x;
4178  dy = rv.distance_y+op->arch->clone.y;
4179 
4180  /* only the viewable area the player sees is updated by LOS
4181  * code, so we need to restrict ourselves to that range of values
4182  * for any meaningful values.
4183  */
4184  if (FABS(dx) <= (pl->contr->socket->mapx/2)
4185  && FABS(dy) <= (pl->contr->socket->mapy/2)
4186  && !pl->contr->blocked_los[dx+(pl->contr->socket->mapx/2)][dy+(pl->contr->socket->mapy/2)])
4187  return 1;
4188  op = op->more;
4189  }
4190  return 0;
4191 }
4192 
4206 static int action_makes_visible(object *op) {
4207  if (op->invisible && QUERY_FLAG(op, FLAG_ALIVE)) {
4209  return 0;
4210 
4211  if (op->contr && op->contr->tmp_invis == 0)
4212  return 0;
4213 
4214  /* If monsters, they should become visible */
4215  if (op->hide || !op->contr || (op->contr && op->contr->tmp_invis)) {
4217  "You become %s!",
4218  op->hide ? "unhidden" : "visible");
4219  return 1;
4220  }
4221  }
4222  return 0;
4223 }
4224 
4253 int op_on_battleground(object *op, int *x, int *y, archetype **trophy) {
4255  if (QUERY_FLAG(tmp, FLAG_IS_FLOOR)) {
4257  && strcmp(tmp->name, "battleground") == 0
4258  && tmp->type == BATTLEGROUND
4259  && EXIT_X(tmp)
4260  && EXIT_Y(tmp)) {
4261  /*before we assign the exit, check if this is a teambattle*/
4262  if (EXIT_ALT_X(tmp) && EXIT_ALT_Y(tmp) && EXIT_PATH(tmp)) {
4263  object *invtmp;
4264 
4266  if (invtmp != NULL) {
4267  if (x != NULL && y != NULL)
4268  *x = EXIT_ALT_X(tmp),
4269  *y = EXIT_ALT_Y(tmp);
4270  return 1;
4271  }
4272  }
4273  if (x != NULL && y != NULL)
4274  *x = EXIT_X(tmp),
4275  *y = EXIT_Y(tmp);
4276 
4277  /* If 'other_arch' is not specified, give a finger. */
4278  if (trophy != NULL) {
4279  if (tmp->other_arch) {
4280  *trophy = tmp->other_arch;
4281  } else {
4282  *trophy = find_archetype("finger");
4283  }
4284  }
4285  return 1;
4286  }
4287  }
4288  } FOR_BELOW_FINISH();
4289  /* If we got here, did not find a battleground */
4290  return 0;
4291 }
4292 
4303 void dragon_ability_gain(object *who, int atnr, int level) {
4304  treasurelist *trlist = NULL; /* treasurelist */
4305  treasure *tr; /* treasure */
4306  object *tmp, *skop; /* tmp. object */
4307  object *item; /* treasure object */
4308  char buf[MAX_BUF]; /* tmp. string buffer */
4309  int i = 0, j = 0;
4310 
4311  /* get the appropriate treasurelist */
4312  if (atnr == ATNR_FIRE)
4313  trlist = find_treasurelist("dragon_ability_fire");
4314  else if (atnr == ATNR_COLD)
4315  trlist = find_treasurelist("dragon_ability_cold");
4316  else if (atnr == ATNR_ELECTRICITY)
4317  trlist = find_treasurelist("dragon_ability_elec");
4318  else if (atnr == ATNR_POISON)
4319  trlist = find_treasurelist("dragon_ability_poison");
4320 
4321  if (trlist == NULL || who->type != PLAYER)
4322  return;
4323 
4324  // tr->magic is being used to define what level of the metabolism the ability is gained at.
4325  for (tr = trlist->items; tr != NULL && tr->magic != level; tr = tr->next)
4326  ;
4327  if (tr == NULL || tr->item == NULL) {
4328  /* LOG(llevDebug, "-> no more treasure for %s\n", change_resist_msg[atnr]); */
4329  return;
4330  }
4331 
4332  /* everything seems okay - now bring on the gift: */
4333  item = &(tr->item->clone);
4334 
4335  if (item->type == SPELL) {
4336  if (check_spell_known(who, item->name))
4337  return;
4338 
4341  "You gained the ability of %s",
4342  item->name);
4343  do_learn_spell(who, item, 0);
4344  return;
4345  }
4346 
4347  /* grant direct spell */
4348  if (item->type == SPELLBOOK) {
4349  if (!item->inv) {
4350  LOG(llevDebug, "dragon_ability_gain: Broken spellbook %s\n", item->name);
4351  return;
4352  }
4353  if (check_spell_known(who, item->inv->name))
4354  return;
4355  if (item->invisible) {
4358  "You gained the ability of %s",
4359  item->inv->name);
4360  do_learn_spell(who, item->inv, 0);
4361  return;
4362  }
4363  } else if (item->type == SKILL_TOOL && item->invisible) {
4364  if (item->subtype == SK_CLAWING && (skop = find_skill_by_name(who, item->skill)) != NULL) {
4365  /* should this perhaps be (skop->attackyp&item->attacktype) != item->attacktype ...
4366  * in this way, if the player is missing any of the attacktypes, he gets
4367  * them. As it is now, if the player has any that match the granted skill,
4368  * but not all of them, he gets nothing.
4369  */
4370  if (!(skop->attacktype&item->attacktype)) {
4371  /* Give new attacktype */
4372  skop->attacktype |= item->attacktype;
4373 
4374  /* always add physical if there's none */
4375  skop->attacktype |= AT_PHYSICAL;
4376 
4377  if (item->msg != NULL)
4380  item->msg);
4381 
4382  /* Give player new face */
4383  if (item->animation) {
4384  who->face = skop->face;
4385  who->animation = item->animation;
4386  who->anim_speed = item->anim_speed;
4387  who->last_anim = 0;
4388  who->state = 0;
4389  animate_object(who, who->direction);
4390  }
4391  }
4392  }
4393  } else if (item->type == FORCE) {
4394  /* forces in the treasurelist can alter the player's stats */
4395  object *skin;
4396 
4397  /* first get the dragon skin force */
4398  skin = object_find_by_arch_name(who, "dragon_skin_force");
4399  if (skin == NULL)
4400  return;
4401 
4402  /* adding new spellpath attunements */
4403  if (item->path_attuned > 0 && !(skin->path_attuned&item->path_attuned)) {
4404  skin->path_attuned |= item->path_attuned; /* add attunement to skin */
4405 
4406  /* print message */
4407  snprintf(buf, sizeof(buf), "You feel attuned to ");
4408  for (i = 0, j = 0; i < NRSPELLPATHS; i++) {
4409  if (item->path_attuned&(1<<i)) {
4410  if (j)
4411  strcat(buf, " and ");
4412  else
4413  j = 1;
4414  strcat(buf, spellpathnames[i]);
4415  }
4416  }
4417  strcat(buf, ".");
4420  buf);
4421  }
4422 
4423  /* evtl. adding flags: */
4424  if (QUERY_FLAG(item, FLAG_XRAYS))
4425  SET_FLAG(skin, FLAG_XRAYS);
4427  SET_FLAG(skin, FLAG_STEALTH);
4429  SET_FLAG(skin, FLAG_SEE_IN_DARK);
4430 
4431  /* print message if there is one */
4432  if (item->msg != NULL)
4435  item->msg);
4436  } else {
4437  /* generate misc. treasure */
4438  char name[HUGE_BUF];
4439 
4440  tmp = arch_to_object(tr->item);
4444  "You gained %s",
4445  name);
4447  if (who->type == PLAYER)
4449  }
4450 }
4451 
4462  int i;
4463 
4464  for (i = 0; i < static_cast<int>(range_size); i++) {
4465  if (pl->ranges[i] == ob) {
4466  pl->ranges[i] = NULL;
4467  if (pl->shoottype == i) {
4468  pl->shoottype = range_none;
4469  }
4470  }
4471  }
4472 }
4473 
4479 void player_set_state(player *pl, uint8_t state) {
4480 
4481  assert(pl);
4482  assert(state <= ST_CHANGE_PASSWORD_CONFIRM);
4483  pl->state = state;
4484 }
4485 
4493  SockList *sl;
4494  assert(pl);
4495  if (pl->delayed_buffers_used == pl->delayed_buffers_allocated) {
4496  pl->delayed_buffers_allocated += 5;
4497  pl->delayed_buffers = static_cast<SockList **>(realloc(pl->delayed_buffers, pl->delayed_buffers_allocated * sizeof(pl->delayed_buffers[0])));
4498  if (!pl->delayed_buffers) {
4499  LOG(llevError, "Unable to allocated %d delayed buffers, aborting\n", pl->delayed_buffers_allocated);
4501  }
4502  for (uint8_t s = pl->delayed_buffers_allocated - 5; s < pl->delayed_buffers_allocated; s++) {
4503  pl->delayed_buffers[s] = static_cast<SockList *>(calloc(1, sizeof(SockList)));
4504  }
4505  }
4506  sl = pl->delayed_buffers[pl->delayed_buffers_used];
4507  pl->delayed_buffers_used++;
4508  SockList_Init(sl);
4509  return sl;
4510 }
object_was_destroyed
#define object_was_destroyed(op, old_tag)
Definition: object.h:70
ADD_PLAYER_NO_STATS_ROLL
#define ADD_PLAYER_NO_STATS_ROLL
Definition: player.h:247
object_value_set
bool object_value_set(const object *op, const char *const key)
Definition: object.cpp:4376
op_on_battleground
int op_on_battleground(object *op, int *x, int *y, archetype **trophy)
Definition: player.cpp:4253
give.next
def next
Definition: give.py:44
GET_MAP_OB
#define GET_MAP_OB(M, X, Y)
Definition: map.h:170
MSG_TYPE_COMMAND_NEWPLAYER
#define MSG_TYPE_COMMAND_NEWPLAYER
Definition: newclient.h:539
do_skill
int do_skill(object *op, object *part, object *skill, int dir, const char *string)
Definition: skill_util.cpp:431
player::do_los
uint32_t do_los
Definition: player.h:141
apply_changes_to_player
void apply_changes_to_player(object *pl, object *change, int limit_stats)
Definition: apply.cpp:1672
living::exp
int64_t exp
Definition: living.h:47
UP_OBJ_FACE
#define UP_OBJ_FACE
Definition: object.h:533
check_pick
int check_pick(object *op)
Definition: player.cpp:1725
make_visible
void make_visible(object *op)
Definition: player.cpp:3968
PLAYER
@ PLAYER
Definition: object.h:112
PU_BOOTS
#define PU_BOOTS
Definition: define.h:125
object_get_owner
object * object_get_owner(object *op)
Definition: object.cpp:804
kill_player_permadeath
static void kill_player_permadeath(object *op)
Definition: player.cpp:3805
SockList_AddInt
void SockList_AddInt(SockList *sl, uint32_t data)
Definition: lowlevel.cpp:127
global.h
FLAG_NEUTRAL
#define FLAG_NEUTRAL
Definition: define.h:354
UPD_FACE
#define UPD_FACE
Definition: newclient.h:320
object_find_by_type_subtype
object * object_find_by_type_subtype(const object *who, int type, int subtype)
Definition: object.cpp:4301
first_player
player * first_player
Definition: init.cpp:106
settings
struct Settings settings
Definition: init.cpp:139
SOUND_TYPE_ITEM
#define SOUND_TYPE_ITEM
Definition: newclient.h:338
bow_spreadshot
@ bow_spreadshot
Definition: player.h:44
object_update_turn_face
void object_update_turn_face(object *op)
Definition: object.cpp:1332
safe_strncpy
#define safe_strncpy
Definition: compat.h:27
FOR_MAP_FINISH
#define FOR_MAP_FINISH()
Definition: define.h:730
remove_friendly_object
void remove_friendly_object(object *op)
Definition: friend.cpp:52
pets_terminate_all
void pets_terminate_all(object *owner)
Definition: pets.cpp:225
bow_normal
@ bow_normal
Definition: player.h:42
face_player
int face_player(object *op, int dir)
Definition: player.cpp:3035
options
static struct Command_Line_Options options[]
Definition: init.cpp:376
ST_GET_PASSWORD
#define ST_GET_PASSWORD
Definition: define.h:547
MSG_TYPE_COMMAND_SUCCESS
#define MSG_TYPE_COMMAND_SUCCESS
Definition: newclient.h:533
FLAG_CONFUSED
#define FLAG_CONFUSED
Definition: define.h:311
player::unarmed_skill
const char * unarmed_skill
Definition: player.h:221
BOW
@ BOW
Definition: object.h:123
player_fire_bow
static int player_fire_bow(object *op, int dir)
Definition: player.cpp:2316
Settings::emergency_y
uint16_t emergency_y
Definition: global.h:300
kill_player
void kill_player(object *op, const object *killer)
Definition: player.cpp:3500
llevError
@ llevError
Definition: logger.h:11
FABS
#define FABS(x)
Definition: define.h:22
MOVE_ALL
#define MOVE_ALL
Definition: define.h:398
object::path_attuned
uint32_t path_attuned
Definition: object.h:353
command_search_items
void command_search_items(object *op, const char *params)
Definition: c_object.cpp:2479
WAND
@ WAND
Definition: object.h:225
range_bow
@ range_bow
Definition: player.h:31
get_player_archetype
static archetype * get_player_archetype(archetype *at)
Definition: player.cpp:513
MSG_TYPE_ADMIN_PLAYER
#define MSG_TYPE_ADMIN_PLAYER
Definition: newclient.h:499
LOG
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.cpp:58
FLAG_UNDEAD
#define FLAG_UNDEAD
Definition: define.h:270
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:224
bow_threewide
@ bow_threewide
Definition: player.h:43
FLESH
@ FLESH
Definition: object.h:192
monster_can_detect_enemy
int monster_can_detect_enemy(object *op, object *enemy, rv_vector *rv)
Definition: monster.cpp:2581
PU_ARROW
#define PU_ARROW
Definition: define.h:120
PU_NOT_CURSED
#define PU_NOT_CURSED
Definition: define.h:140
player
Definition: player.h:105
path_to_player
int path_to_player(object *mon, object *pl, unsigned mindiff)
Definition: player.cpp:659
esrv_map_scroll
void esrv_map_scroll(socket_struct *ns, int dx, int dy)
Definition: request.cpp:1709
blocked_link
int blocked_link(object *ob, mapstruct *m, int16_t sx, int16_t sy)
Definition: map.cpp:344
strdup_local
#define strdup_local
Definition: compat.h:29
object::inv
object * inv
Definition: object.h:298
Settings::resurrection
uint8_t resurrection
Definition: global.h:266
recursive_roll
void recursive_roll(object *op, int dir, object *pusher)
Definition: move.cpp:293
safe_strcat
void safe_strcat(char *dest, const char *orig, size_t *curlen, size_t maxlen)
Definition: porting.cpp:202
diamondslots.x
x
Definition: diamondslots.py:15
FLAG_STARTEQUIP
#define FLAG_STARTEQUIP
Definition: define.h:268
first_map_path
char first_map_path[MAX_BUF]
Definition: init.cpp:120
MSG_TYPE_SKILL
#define MSG_TYPE_SKILL
Definition: newclient.h:410
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
treasurelist::items
treasure * items
Definition: treasure.h:92
Settings::set_title
uint8_t set_title
Definition: global.h:265
AssetsManager.h
remove_locked_door
void remove_locked_door(object *op)
Definition: time.cpp:64
spellpathnames
const char *const spellpathnames[NRSPELLPATHS]
Definition: init.cpp:240
SK_CLAWING
@ SK_CLAWING
Definition: skills.h:50
ARCH_DEPLETION
#define ARCH_DEPLETION
Definition: object.h:590
NDI_GREEN
#define NDI_GREEN
Definition: newclient.h:252
PU_INHIBIT
#define PU_INHIBIT
Definition: define.h:109
do_learn_spell
void do_learn_spell(object *op, object *spell, int special_prayer)
Definition: apply.cpp:484
socket_struct
Definition: newserver.h:89
ST_GET_NAME
#define ST_GET_NAME
Definition: define.h:546
first_map_ext_path
char first_map_ext_path[MAX_BUF]
Definition: init.cpp:121
esrv_new_player
void esrv_new_player(player *pl, uint32_t weight)
Definition: request.cpp:1009
FLAG_SEE_IN_DARK
#define FLAG_SEE_IN_DARK
Definition: define.h:337
Settings::not_permadeth
uint8_t not_permadeth
Definition: global.h:262
price_base
uint64_t price_base(const object *obj)
Definition: shop.cpp:75
player_get_delayed_buffer
SockList * player_get_delayed_buffer(player *pl)
Definition: player.cpp:4492
get_friends_of
objectlink * get_friends_of(const object *owner)
Definition: friend.cpp:117
esrv_send_inventory
void esrv_send_inventory(object *pl, object *op)
Definition: item.cpp:316
roll_again
void roll_again(object *op)
Definition: player.cpp:1149
find_player_socket
player * find_player_socket(const socket_struct *ns)
Definition: player.cpp:123
AT_PHYSICAL
#define AT_PHYSICAL
Definition: attack.h:76
object::arch
struct archetype * arch
Definition: object.h:424
cast_spell
int cast_spell(object *op, object *caster, int dir, object *spell_ob, char *stringarg)
Definition: spell_util.cpp:1424
find_better_arrow
static object * find_better_arrow(object *op, object *target, const char *type, int *better)
Definition: player.cpp:1962
disinfect.a
a
Definition: disinfect.py:13
absdir
int absdir(int d)
Definition: object.cpp:3714
player::no_shout
uint32_t no_shout
Definition: player.h:148
SockList_AddString
void SockList_AddString(SockList *sl, const char *data)
Definition: lowlevel.cpp:157
FOR_BELOW_PREPARE
#define FOR_BELOW_PREPARE(op_, it_)
Definition: define.h:704
object::speed
float speed
Definition: object.h:337
if
if(!(yy_init))
Definition: loader.cpp:36428
object_set_enemy
void object_set_enemy(object *op, object *enemy)
Definition: object.cpp:915
starving
static bool starving(object *op)
Definition: player.cpp:3273
GEM
@ GEM
Definition: object.h:172
FLAG_UNIQUE
#define FLAG_UNIQUE
Definition: define.h:287
MSG_TYPE_VICTIM_DIED
#define MSG_TYPE_VICTIM_DIED
Definition: newclient.h:659
EXIT_PATH
#define EXIT_PATH(xyz)
Definition: define.h:439
living::Dex
int8_t Dex
Definition: living.h:36
TRAP
@ TRAP
Definition: object.h:246
object::x
int16_t x
Definition: object.h:335
player::peaceful
uint32_t peaceful
Definition: player.h:146
player::ob
object * ob
Definition: player.h:177
turn_transport
static int turn_transport(object *transport, object *captain, int dir)
Definition: player.cpp:2923
spring_trap
void spring_trap(object *trap, object *victim)
Definition: rune.cpp:214
get_nearest_player
object * get_nearest_player(object *mon)
Definition: player.cpp:548
guildoracle.list
list
Definition: guildoracle.py:87
apply_map_builder
void apply_map_builder(object *pl, int dir)
Definition: build_map.cpp:960
object::speed_left
float speed_left
Definition: object.h:338
PREFER_LOW
#define PREFER_LOW
Definition: define.h:564
PU_FOOD
#define PU_FOOD
Definition: define.h:115
object::map
struct mapstruct * map
Definition: object.h:305
object::anim_suffix
sstring anim_suffix
Definition: object.h:324
arch_present_in_ob
object * arch_present_in_ob(const archetype *at, const object *op)
Definition: object.cpp:3222
find_treasurelist
treasurelist * find_treasurelist(const char *name)
Definition: assets.cpp:249
object_set_owner
void object_set_owner(object *op, object *owner)
Definition: object.cpp:840
esrv_send_pickup
void esrv_send_pickup(player *pl)
Definition: request.cpp:1836
guildjoin.ob
ob
Definition: guildjoin.py:42
player::last_applied_stats
living last_applied_stats
Definition: player.h:172
PU_BOW
#define PU_BOW
Definition: define.h:118
MSG_TYPE_ATTRIBUTE
#define MSG_TYPE_ATTRIBUTE
Definition: newclient.h:408
GT_ONLY_GOOD
@ GT_ONLY_GOOD
Definition: treasure.h:34
fix_weight
void fix_weight(void)
Definition: player.cpp:3902
player_set_own_title
void player_set_own_title(struct player *pl, const char *title)
Definition: player.cpp:272
range_none
@ range_none
Definition: player.h:30
PU_MAGIC_DEVICE
#define PU_MAGIC_DEVICE
Definition: define.h:138
commongive.inv
inv
Definition: commongive.py:29
SET_ANIMATION
#define SET_ANIMATION(ob, newanim)
Definition: global.h:162
CHARISMA
@ CHARISMA
Definition: living.h:15
draw_ext_info_format
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...) PRINTF_ARGS(6
party_rejoin_if_exists
@ party_rejoin_if_exists
Definition: player.h:100
mon
object * mon
Definition: comet_perf.cpp:75
CS_QUERY_SINGLECHAR
#define CS_QUERY_SINGLECHAR
Definition: newclient.h:70
play_sound_player_only
void play_sound_player_only(player *pl, int8_t sound_type, object *emitter, int dir, const char *action)
Definition: sounds.cpp:51
player::last_path_denied
uint32_t last_path_denied
Definition: player.h:162
allowed_class
int allowed_class(const object *op)
Definition: living.cpp:1657
SKILL
@ SKILL
Definition: object.h:148
object::direction
int8_t direction
Definition: object.h:344
play_sound_map
void play_sound_map(int8_t sound_type, object *emitter, int dir, const char *action)
Definition: sounds.cpp:113
object::count
tag_t count
Definition: object.h:307
flags
static const flag_definition flags[]
Definition: gridarta-types-convert.cpp:101
RUNE
@ RUNE
Definition: object.h:245
change_skill
int change_skill(object *who, object *new_skill, int flag)
Definition: skill_util.cpp:359
object_copy
void object_copy(const object *src_ob, object *dest_ob)
Definition: object.cpp:1192
FLAG_SCARED
#define FLAG_SCARED
Definition: define.h:271
player::savebed_map
char savebed_map[MAX_BUF]
Definition: player.h:110
Settings::roll_stat_points
uint8_t roll_stat_points
Definition: global.h:323
fix_object
void fix_object(object *op)
Definition: living.cpp:1132
object_find_by_flag_applied
object * object_find_by_flag_applied(const object *who, int flag)
Definition: object.cpp:4229
Ice.tmp
int tmp
Definition: Ice.py:207
PU_MISSILEWEAPON
#define PU_MISSILEWEAPON
Definition: define.h:130
player_can_view
int player_can_view(object *pl, object *op)
Definition: player.cpp:4154
confirm_password
void confirm_password(object *op)
Definition: player.cpp:1014
NDI_NAVY
#define NDI_NAVY
Definition: newclient.h:247
player::last_stats
living last_stats
Definition: player.h:168
Settings::emergency_x
uint16_t emergency_x
Definition: global.h:300
get_name
void get_name(object *op)
Definition: player.cpp:889
SEE_LAST_ERROR
@ SEE_LAST_ERROR
Definition: define.h:52
TRANSPORT
@ TRANSPORT
Definition: object.h:113
SOUND_TYPE_LIVING
#define SOUND_TYPE_LIVING
Definition: newclient.h:336
socket_struct::inbuf
SockList inbuf
Definition: newserver.h:99
object::enemy
object * enemy
Definition: object.h:391
PU_FLESH
#define PU_FLESH
Definition: define.h:142
NROFATTACKS
#define NROFATTACKS
Definition: attack.h:17
PU_READABLES
#define PU_READABLES
Definition: define.h:137
BALSL_LOSS_CHANCE_RATIO
#define BALSL_LOSS_CHANCE_RATIO
Definition: config.h:142
send_account_players
void send_account_players(socket_struct *ns)
Definition: request.cpp:2059
skills.h
PU_POTION
#define PU_POTION
Definition: define.h:133
MSG_TYPE_COMMAND_ERROR
#define MSG_TYPE_COMMAND_ERROR
Definition: newclient.h:532
esrv_add_spells
void esrv_add_spells(player *pl, object *spell)
Definition: request.cpp:1950
range_golem
@ range_golem
Definition: player.h:34
partylist
Definition: party.h:10
FLAG_INV_LOCKED
#define FLAG_INV_LOCKED
Definition: define.h:329
apply_manual
int apply_manual(object *op, object *tmp, int aflag)
Definition: apply.cpp:597
mapstruct::path
char path[HUGE_BUF]
Definition: map.h:353
P_IS_ALIVE
#define P_IS_ALIVE
Definition: map.h:235
MSG_TYPE_MISC
#define MSG_TYPE_MISC
Definition: newclient.h:416
FLAG_APPLIED
#define FLAG_APPLIED
Definition: define.h:235
NDI_BLUE
#define NDI_BLUE
Definition: newclient.h:250
object::level
int16_t level
Definition: object.h:361
FLAG_STEALTH
#define FLAG_STEALTH
Definition: define.h:312
events_execute_object_event
int events_execute_object_event(object *op, int eventcode, object *activator, object *third, const char *message, int fix)
Definition: events.cpp:310
bow_bestarrow
@ bow_bestarrow
Definition: player.h:53
BALSL_MAX_LOSS_RATIO
#define BALSL_MAX_LOSS_RATIO
Definition: config.h:144
pticks
uint32_t pticks
Definition: time.cpp:47
GT_STARTEQUIP
@ GT_STARTEQUIP
Definition: treasure.h:33
buf
StringBuffer * buf
Definition: readable.cpp:1565
Moving_Fog.z
z
Definition: Moving_Fog.py:17
hiscore_check
void hiscore_check(object *op, int quiet)
Definition: hiscore.cpp:348
player::swap_first
int swap_first
Definition: player.h:166
getManager
AssetsManager * getManager()
Definition: assets.cpp:305
object_insert_in_ob
object * object_insert_in_ob(object *op, object *where)
Definition: object.cpp:2857
HUGE_BUF
#define HUGE_BUF
Definition: define.h:37
MSG_TYPE_VICTIM
#define MSG_TYPE_VICTIM
Definition: newclient.h:418
MSG_TYPE_COMMAND
#define MSG_TYPE_COMMAND
Definition: newclient.h:407
MAX
#define MAX(x, y)
Definition: compat.h:24
handle_newcs_player
int handle_newcs_player(object *op)
Definition: player.cpp:3094
WISDOM
@ WISDOM
Definition: living.h:14
AT_DEATH
#define AT_DEATH
Definition: attack.h:93
object::resist
int16_t resist[NROFATTACKS]
Definition: object.h:351
FLAG_NO_PICK
#define FLAG_NO_PICK
Definition: define.h:239
MSG_TYPE_SPELL_END
#define MSG_TYPE_SPELL_END
Definition: newclient.h:637
lose_msg
const char *const lose_msg[NUM_STATS]
Definition: living.cpp:172
player_set_state
void player_set_state(player *pl, uint8_t state)
Definition: player.cpp:4479
sword_of_souls.killer
killer
Definition: sword_of_souls.py:3
FLAG_IS_FLOOR
#define FLAG_IS_FLOOR
Definition: define.h:302
FOR_BELOW_FINISH
#define FOR_BELOW_FINISH()
Definition: define.h:711
MIN_STAT
#define MIN_STAT
Definition: define.h:33
FLAG_ALIVE
#define FLAG_ALIVE
Definition: define.h:230
add_statbonus
void add_statbonus(object *op)
Definition: living.cpp:868
MSG_TYPE_MOTD
#define MSG_TYPE_MOTD
Definition: newclient.h:404
range_builder
@ range_builder
Definition: player.h:36
esrv_send_item
void esrv_send_item(object *pl, object *op)
Definition: main.cpp:354
rv_vector::distance_y
int distance_y
Definition: map.h:371
short_stat_name
const char *const short_stat_name[NUM_STATS]
Definition: living.cpp:194
MSG_TYPE_COMMAND_DEBUG
#define MSG_TYPE_COMMAND_DEBUG
Definition: newclient.h:531
AP_NULL
#define AP_NULL
Definition: define.h:573
PU_GLOVES
#define PU_GLOVES
Definition: define.h:126
set_player_socket
void set_player_socket(player *p, socket_struct *ns)
Definition: player.cpp:421
remove_door
void remove_door(object *op)
Definition: time.cpp:38
object::y
int16_t y
Definition: object.h:335
PU_CONTAINER
#define PU_CONTAINER
Definition: define.h:143
m
static event_registration m
Definition: citylife.cpp:425
clear_los
void clear_los(player *pl)
Definition: los.cpp:270
rv_vector::distance_x
int distance_x
Definition: map.h:370
socket_struct::account_chars
Account_Chars * account_chars
Definition: newserver.h:127
autojail.who
who
Definition: autojail.py:3
MAP_IN_MEMORY
#define MAP_IN_MEMORY
Definition: map.h:126
Ns_Avail
@ Ns_Avail
Definition: newserver.h:65
object_free_drop_inventory
void object_free_drop_inventory(object *ob)
Definition: object.cpp:1560
turn_one_transport
static int turn_one_transport(object *transport, object *captain, int dir)
Definition: player.cpp:2853
object_update
void object_update(object *op, int action)
Definition: object.cpp:1434
object::contr
struct player * contr
Definition: object.h:284
get_party_password
int get_party_password(object *op, partylist *party)
Definition: player.cpp:1029
player_unready_range_ob
void player_unready_range_ob(player *pl, object *ob)
Definition: player.cpp:4461
PREFER_HIGH
#define PREFER_HIGH
Definition: define.h:563
EVENT_LOGIN
#define EVENT_LOGIN
Definition: events.h:44
disinfect.map
map
Definition: disinfect.py:4
object_decrease_nrof_by_one
#define object_decrease_nrof_by_one(xyz)
Definition: compat.h:32
MAX_SPACES
#define MAX_SPACES
Definition: player.cpp:626
POISON
@ POISON
Definition: object.h:118
PU_RATIO
#define PU_RATIO
Definition: define.h:113
Settings::balanced_stat_loss
uint8_t balanced_stat_loss
Definition: global.h:261
BALSL_NUMBER_LOSSES_RATIO
#define BALSL_NUMBER_LOSSES_RATIO
Definition: config.h:143
flee_player
static void flee_player(object *op)
Definition: player.cpp:1666
MSG_TYPE_ATTRIBUTE_STAT_LOSS
#define MSG_TYPE_ATTRIBUTE_STAT_LOSS
Definition: newclient.h:572
FLAG_WAS_WIZ
#define FLAG_WAS_WIZ
Definition: define.h:234
MSG_TYPE_ADMIN_NEWS
#define MSG_TYPE_ADMIN_NEWS
Definition: newclient.h:498
is_criminal
bool is_criminal(object *op)
Definition: player.cpp:312
player::last_speed
float last_speed
Definition: player.h:173
add_refcount
sstring add_refcount(sstring str)
Definition: shstr.cpp:210
check_race_and_class
int check_race_and_class(living *stats, archetype *race, archetype *opclass)
Definition: player.cpp:1437
enter_player_savebed
void enter_player_savebed(object *op)
Definition: server.cpp:142
PU_KEY
#define PU_KEY
Definition: define.h:128
determine_god
const char * determine_god(object *op)
Definition: gods.cpp:55
MSG_TYPE_ATTRIBUTE_RACE
#define MSG_TYPE_ATTRIBUTE_RACE
Definition: newclient.h:567
freearr_y
short freearr_y[SIZEOFFREE]
Definition: object.cpp:305
ST_CHANGE_PASSWORD_CONFIRM
#define ST_CHANGE_PASSWORD_CONFIRM
Definition: define.h:552
range_size
@ range_size
Definition: player.h:37
move_ob
int move_ob(object *op, int dir, object *originator)
Definition: move.cpp:58
MSG_TYPE_APPLY_SUCCESS
#define MSG_TYPE_APPLY_SUCCESS
Definition: newclient.h:606
query_name
void query_name(const object *op, char *buf, size_t size)
Definition: item.cpp:588
POTION
@ POTION
Definition: object.h:116
find_player_options
player * find_player_options(const char *plname, int options, const mapstruct *map)
Definition: player.cpp:70
do_hidden_move
void do_hidden_move(object *op)
Definition: player.cpp:4045
MOVE_WALK
#define MOVE_WALK
Definition: define.h:392
FLAG_KNOWN_CURSED
#define FLAG_KNOWN_CURSED
Definition: define.h:320
pick_arrow_target
static object * pick_arrow_target(object *op, const char *type, int dir)
Definition: player.cpp:2032
ST_PLAY_AGAIN
#define ST_PLAY_AGAIN
Definition: define.h:542
treasurelist
Definition: treasure.h:85
action_makes_visible
static int action_makes_visible(object *op)
Definition: player.cpp:4206
ADD_PLAYER_NO_MAP
#define ADD_PLAYER_NO_MAP
Definition: player.h:246
calc_skill_exp
int64_t calc_skill_exp(const object *who, const object *op, const object *skill)
Definition: skill_util.cpp:667
Settings::motd
const char * motd
Definition: global.h:278
account_char_free
void account_char_free(Account_Chars *chars)
Definition: account_char.cpp:345
archetype::clone
object clone
Definition: object.h:487
fire_misc_object
static void fire_misc_object(object *op, int dir)
Definition: player.cpp:2352
loot_object
static void loot_object(object *op)
Definition: player.cpp:3423
party_leave
void party_leave(object *op)
Definition: party.cpp:123
add_string
sstring add_string(const char *str)
Definition: shstr.cpp:124
account_remove_player
int account_remove_player(const char *account_name, const char *player_name)
Definition: account.cpp:475
apply_anim_suffix
void apply_anim_suffix(object *who, const char *suffix)
Definition: anim.cpp:150
first_map
mapstruct * first_map
Definition: init.cpp:107
FOR_OB_AND_BELOW_FINISH
#define FOR_OB_AND_BELOW_FINISH()
Definition: define.h:754
object_get_multi_size
void object_get_multi_size(const object *ob, int *sx, int *sy, int *hx, int *hy)
Definition: object.cpp:4744
HEAD
#define HEAD(op)
Definition: object.h:607
range_magic
@ range_magic
Definition: player.h:32
apply_container
int apply_container(object *op, object *sack, int aflags)
Definition: apply.cpp:222
similar_direction
static int similar_direction(int a, int b)
Definition: player.cpp:2282
ROD
@ ROD
Definition: object.h:114
CONTAINER
@ CONTAINER
Definition: object.h:236
enter_player_maplevel
void enter_player_maplevel(object *op)
Definition: server.cpp:682
object::move_type
MoveType move_type
Definition: object.h:436
query_short_name
void query_short_name(const object *op, char *buf, size_t size)
Definition: item.cpp:513
SockList_AddChar
void SockList_AddChar(SockList *sl, unsigned char c)
Definition: lowlevel.cpp:106
PU_STOP
#define PU_STOP
Definition: define.h:110
PU_VALUABLES
#define PU_VALUABLES
Definition: define.h:117
set_attr_value
void set_attr_value(living *stats, int attr, int8_t value)
Definition: living.cpp:218
FLAG_FREED
#define FLAG_FREED
Definition: define.h:233
delete_character
void delete_character(const char *name)
Definition: login.cpp:88
player::last_path_attuned
uint32_t last_path_attuned
Definition: player.h:160
LOCKED_DOOR
@ LOCKED_DOOR
Definition: object.h:128
MSG_TYPE_ITEM
#define MSG_TYPE_ITEM
Definition: newclient.h:415
object::face
const Face * face
Definition: object.h:341
out_of_map
int out_of_map(mapstruct *m, int x, int y)
Definition: map.cpp:2293
player::last_character_flags
uint32_t last_character_flags
Definition: player.h:163
socket_struct::host
char * host
Definition: newserver.h:100
player::last_skill_exp
int64_t last_skill_exp[MAX_SKILLS]
Definition: player.h:154
SCRIPT_FIX_ALL
#define SCRIPT_FIX_ALL
Definition: global.h:389
MSG_TYPE_ATTACK
#define MSG_TYPE_ATTACK
Definition: newclient.h:412
FLAG_MAKE_INVIS
#define FLAG_MAKE_INVIS
Definition: define.h:328
Settings::rules
const char * rules
Definition: global.h:279
SPECIAL_KEY
@ SPECIAL_KEY
Definition: object.h:129
MOVE_FLYING
#define MOVE_FLYING
Definition: define.h:395
socket_struct::account_name
char * account_name
Definition: newserver.h:126
has_carried_lights
int has_carried_lights(const object *op)
Definition: los.cpp:346
POWER
@ POWER
Definition: living.h:17
object_update_speed
void object_update_speed(object *op)
Definition: object.cpp:1349
SPELL_HIGHEST
#define SPELL_HIGHEST
Definition: spells.h:60
FREE_AND_COPY
#define FREE_AND_COPY(sv, nv)
Definition: global.h:204
Settings::news
const char * news
Definition: global.h:280
Ice.b
b
Definition: Ice.py:48
EVENT_BORN
#define EVENT_BORN
Definition: events.h:39
guild_questpoints_apply.mapname
mapname
Definition: guild_questpoints_apply.py:8
object::type
uint8_t type
Definition: object.h:348
FLAG_DAMNED
#define FLAG_DAMNED
Definition: define.h:317
living::dam
int16_t dam
Definition: living.h:46
object::magic
int8_t magic
Definition: object.h:358
do_some_living
void do_some_living(object *op)
Definition: player.cpp:3284
bow_nw
@ bow_nw
Definition: player.h:52
treasure::item
struct archetype * item
Definition: treasure.h:64
FLAG_PARALYZED
#define FLAG_PARALYZED
Definition: define.h:371
Settings::stat_loss_on_death
uint8_t stat_loss_on_death
Definition: global.h:256
CFweardisguise.tag
tag
Definition: CFweardisguise.py:25
gravestone_text
static const char * gravestone_text(object *op, char *buf2, int len)
Definition: player.cpp:3245
FLAG_USE_SHIELD
#define FLAG_USE_SHIELD
Definition: define.h:237
hideability
int hideability(object *ob)
Definition: player.cpp:4004
leave
void leave(player *pl, int draw_exit)
Definition: server.cpp:1298
object_free
void object_free(object *ob, int flags)
Definition: object.cpp:1592
GET_MAP_MOVE_BLOCK
#define GET_MAP_MOVE_BLOCK(M, X, Y)
Definition: map.h:190
FOR_INV_FINISH
#define FOR_INV_FINISH()
Definition: define.h:677
find_player
player * find_player(const char *plname)
Definition: player.cpp:59
FLAG_CAN_ROLL
#define FLAG_CAN_ROLL
Definition: define.h:254
find_arrow
static object * find_arrow(object *op, const char *type)
Definition: player.cpp:1930
kill_player_not_permadeath
static void kill_player_not_permadeath(object *op)
Definition: player.cpp:3581
object::move_on
MoveType move_on
Definition: object.h:439
PU_SPELLBOOK
#define PU_SPELLBOOK
Definition: define.h:135
change_exp
void change_exp(object *op, int64_t exp, const char *skill_name, int flag)
Definition: living.cpp:2175
FLAG_UNAGGRESSIVE
#define FLAG_UNAGGRESSIVE
Definition: define.h:272
say.max
dictionary max
Definition: say.py:148
tag_t
uint32_t tag_t
Definition: object.h:14
archetype
Definition: object.h:483
display_motd
void display_motd(const object *op)
Definition: player.cpp:139
player::shoottype
rangetype shoottype
Definition: player.h:112
object_matches_string
int object_matches_string(object *pl, object *op, const char *name)
Definition: object.cpp:4574
PU_MELEEWEAPON
#define PU_MELEEWEAPON
Definition: define.h:131
ATNR_POISON
#define ATNR_POISON
Definition: attack.h:59
Settings::confdir
const char * confdir
Definition: global.h:247
FLAG_USE_WEAPON
#define FLAG_USE_WEAPON
Definition: define.h:296
sproto.h
player::last_weight_limit
int32_t last_weight_limit
Definition: player.h:159
drain_msg
const char *const drain_msg[NUM_STATS]
Definition: living.cpp:139
ARROW
@ ARROW
Definition: object.h:122
FLAG_NO_DROP
#define FLAG_NO_DROP
Definition: define.h:288
IS_SHIELD
#define IS_SHIELD(op)
Definition: define.h:170
living::sp
int16_t sp
Definition: living.h:42
MAX_SKILLS
#define MAX_SKILLS
Definition: skills.h:70
FIND_PLAYER_PARTIAL_NAME
#define FIND_PLAYER_PARTIAL_NAME
Definition: player.h:235
get_map_from_coord
mapstruct * get_map_from_coord(mapstruct *m, int16_t *x, int16_t *y)
Definition: map.cpp:2321
AC_PLAYER_STAT_NO_CHANGE
#define AC_PLAYER_STAT_NO_CHANGE
Definition: define.h:597
FLAG_CAN_USE_SKILL
#define FLAG_CAN_USE_SKILL
Definition: define.h:321
AssetsCollection::each
void each(std::function< void(T *)> op)
Definition: AssetsCollection.h:158
PU_MAGICAL
#define PU_MAGICAL
Definition: define.h:132
DETOUR_AMOUNT
#define DETOUR_AMOUNT
Definition: player.cpp:611
FOR_OB_AND_BELOW_PREPARE
#define FOR_OB_AND_BELOW_PREPARE(op_)
Definition: define.h:750
MSG_TYPE_SPELL
#define MSG_TYPE_SPELL
Definition: newclient.h:414
get_rangevector_from_mapcoord
int get_rangevector_from_mapcoord(const mapstruct *m, int x, int y, const object *op2, rv_vector *retval)
Definition: map.cpp:2560
living::Int
int8_t Int
Definition: living.h:36
SP_level_spellpoint_cost
int16_t SP_level_spellpoint_cost(object *caster, object *spell, int flags)
Definition: spell_util.cpp:236
delete_map
void delete_map(mapstruct *m)
Definition: map.cpp:1696
random_roll
int random_roll(int min, int max, const object *op, int goodbad)
Definition: utils.cpp:42
MSG_SUBTYPE_NONE
#define MSG_SUBTYPE_NONE
Definition: newclient.h:423
object::race
sstring race
Definition: object.h:326
object::facing
int8_t facing
Definition: object.h:345
get_dam_bonus
int get_dam_bonus(int stat)
Definition: living.cpp:2385
DEXTERITY
@ DEXTERITY
Definition: living.h:12
SockList_Init
void SockList_Init(SockList *sl)
Definition: lowlevel.cpp:55
PU_HELMET
#define PU_HELMET
Definition: define.h:121
ob_blocked
int ob_blocked(const object *ob, mapstruct *m, int16_t x, int16_t y)
Definition: map.cpp:479
nlohmann::detail::void
j template void())
Definition: json.hpp:4099
receive_play_again
void receive_play_again(object *op, char key)
Definition: player.cpp:964
object_find_by_type_without_flags
object * object_find_by_type_without_flags(const object *who, int type, int *flags, int num_flags)
Definition: object.cpp:4004
player::last_item_power
uint16_t last_item_power
Definition: player.h:164
object_insert_in_map_at
object * object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
Definition: object.cpp:2100
living
Definition: living.h:35
treasure::next
treasure * next
Definition: treasure.h:69
FLAG_MONSTER
#define FLAG_MONSTER
Definition: define.h:245
fire
void fire(object *op, int dir)
Definition: player.cpp:2404
push_ob
int push_ob(object *who, int dir, object *pusher)
Definition: move.cpp:434
key_inventory
@ key_inventory
Definition: player.h:66
fatal
void fatal(enum fatal_error err)
Definition: utils.cpp:590
find_skill_by_name
object * find_skill_by_name(object *who, const char *name)
Definition: skill_util.cpp:211
player::last_skill_ob
object * last_skill_ob[MAX_SKILLS]
Definition: player.h:153
apply_death_exp_penalty
void apply_death_exp_penalty(object *op)
Definition: living.cpp:2240
get_dex_bonus
int get_dex_bonus(int stat)
Definition: living.cpp:2361
P_OUT_OF_MAP
#define P_OUT_OF_MAP
Definition: map.h:247
move_player_attack
void move_player_attack(object *op, int dir)
Definition: player.cpp:2631
AssetsManager::archetypes
Archetypes * archetypes()
Definition: AssetsManager.h:44
env
static std::shared_ptr< inja::Environment > env
Definition: mapper.cpp:2168
EXIT_X
#define EXIT_X(xyz)
Definition: define.h:441
MAX_BUF
#define MAX_BUF
Definition: define.h:35
player::last_weight
int32_t last_weight
Definition: player.h:158
Ns_Add
@ Ns_Add
Definition: newserver.h:66
player::listening
uint8_t listening
Definition: player.h:133
strlcpy
size_t strlcpy(char *dst, const char *src, size_t size)
Definition: porting.cpp:222
object_new
object * object_new(void)
Definition: object.cpp:1273
is_wraith_pl
int is_wraith_pl(object *op)
Definition: player.cpp:173
ADD_PLAYER_NEW
#define ADD_PLAYER_NEW
Definition: player.h:245
create_archetype
object * create_archetype(const char *name)
Definition: arch.cpp:278
IS_WEAPON
#define IS_WEAPON(op)
Definition: define.h:163
cast_dust
void cast_dust(object *op, object *throw_ob, int dir)
Definition: player.cpp:3939
free_string
void free_string(sstring str)
Definition: shstr.cpp:280
transfer_ob
int transfer_ob(object *op, int x, int y, int randomly, object *originator)
Definition: move.cpp:163
set_first_map
void set_first_map(object *op)
Definition: player.cpp:402
living::wc
int8_t wc
Definition: living.h:37
key_confirm_quit
void key_confirm_quit(object *op, char key)
Definition: player.cpp:1600
player::unapply
unapplymode unapply
Definition: player.h:121
offsetof
#define offsetof(type, member)
Definition: shstr.h:37
remove_unpaid_objects
void remove_unpaid_objects(object *op, object *env, int free_items)
Definition: player.cpp:3215
Settings::playerdir
const char * playerdir
Definition: global.h:250
RANDOM
#define RANDOM()
Definition: define.h:644
SockList_Term
void SockList_Term(SockList *sl)
Definition: lowlevel.cpp:65
SK_HIDING
@ SK_HIDING
Definition: skills.h:21
FREE_AND_CLEAR_STR
#define FREE_AND_CLEAR_STR(xyz)
Definition: global.h:198
MOVE_FLY_LOW
#define MOVE_FLY_LOW
Definition: define.h:393
EVENT_PLAYER_DEATH
#define EVENT_PLAYER_DEATH
Definition: events.h:53
dead_player
void dead_player(object *op)
Definition: resurrection.cpp:297
ATNR_FIRE
#define ATNR_FIRE
Definition: attack.h:51
player::gen_sp_armour
int16_t gen_sp_armour
Definition: player.h:128
MSG_TYPE_ITEM_ADD
#define MSG_TYPE_ITEM_ADD
Definition: newclient.h:646
is_valid_types_gen.found
found
Definition: is_valid_types_gen.py:39
MSG_TYPE_COMMAND_FAILURE
#define MSG_TYPE_COMMAND_FAILURE
Definition: newclient.h:534
FOR_MAP_PREPARE
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Definition: define.h:723
key_change_class
void key_change_class(object *op, char key)
Definition: player.cpp:1297
FLAG_KNOWN_MAGICAL
#define FLAG_KNOWN_MAGICAL
Definition: define.h:319
stand_near_hostile
int stand_near_hostile(object *who)
Definition: player.cpp:4086
FIND_PLAYER_NO_HIDDEN_DM
#define FIND_PLAYER_NO_HIDDEN_DM
Definition: player.h:236
OUT_OF_REAL_MAP
#define OUT_OF_REAL_MAP(M, X, Y)
Definition: map.h:215
ST_PLAYING
#define ST_PLAYING
Definition: define.h:541
roll_stat
int roll_stat(void)
Definition: player.cpp:1046
living::Wis
int8_t Wis
Definition: living.h:36
get_nearest_criminal
object * get_nearest_criminal(object *mon)
Definition: player.cpp:591
range_misc
@ range_misc
Definition: player.h:33
FLAG_READY_SKILL
#define FLAG_READY_SKILL
Definition: define.h:333
FLAG_READY_BOW
#define FLAG_READY_BOW
Definition: define.h:299
sounds.h
FLAG_REMOVED
#define FLAG_REMOVED
Definition: define.h:232
ST_CHANGE_CLASS
#define ST_CHANGE_CLASS
Definition: define.h:544
treasure::magic
uint8_t magic
Definition: treasure.h:74
object_find_by_type_and_slaying
object * object_find_by_type_and_slaying(const object *who, int type, const char *slaying)
Definition: object.cpp:4158
FLAG_WIZ
#define FLAG_WIZ
Definition: define.h:231
Settings::emergency_mapname
char * emergency_mapname
Definition: global.h:299
NDI_UNIQUE
#define NDI_UNIQUE
Definition: newclient.h:265
object::slaying
sstring slaying
Definition: object.h:327
roll-o-matic.stop
def stop()
Definition: roll-o-matic.py:78
FLAG_FRIENDLY
#define FLAG_FRIENDLY
Definition: define.h:246
spells.h
EVENT_DEATH
#define EVENT_DEATH
Definition: events.h:25
object::name
sstring name
Definition: object.h:319
ob_process
method_ret ob_process(object *op)
Definition: ob_methods.cpp:67
PU_CLOAK
#define PU_CLOAK
Definition: define.h:127
BATTLEGROUND
@ BATTLEGROUND
Definition: object.h:168
MSG_TYPE_SKILL_FAILURE
#define MSG_TYPE_SKILL_FAILURE
Definition: newclient.h:593
pet_normal
@ pet_normal
Definition: player.h:58
player::has_hit
uint32_t has_hit
Definition: player.h:144
object_find_by_arch_name
object * object_find_by_arch_name(const object *who, const char *name)
Definition: object.cpp:4252
party_get_password
const char * party_get_password(const partylist *party)
Definition: party.cpp:232
get_thaco_bonus
int get_thaco_bonus(int stat)
Definition: living.cpp:2365
i18n_get_language_by_code
language_t i18n_get_language_by_code(const char *code)
Definition: languages.cpp:73
object_can_pick
int object_can_pick(const object *who, const object *item)
Definition: object.cpp:3867
players
std::vector< archetype * > players
Definition: player.cpp:501
add_friendly_object
void add_friendly_object(object *op)
Definition: friend.cpp:32
key_roll_stat
void key_roll_stat(object *op, char key)
Definition: player.cpp:1221
ST_CONFIRM_PASSWORD
#define ST_CONFIRM_PASSWORD
Definition: define.h:548
IS_ARMOR
#define IS_ARMOR(op)
Definition: define.h:166
unapply_nochoice
@ unapply_nochoice
Definition: player.h:76
get_map_flags
int get_map_flags(mapstruct *oldmap, mapstruct **newmap, int16_t x, int16_t y, int16_t *nx, int16_t *ny)
Definition: map.cpp:300
object_find_by_type
object * object_find_by_type(const object *who, int type)
Definition: object.cpp:3980
SOUND_TYPE_GROUND
#define SOUND_TYPE_GROUND
Definition: newclient.h:339
KEY
@ KEY
Definition: object.h:132
FLAG_USE_ARMOUR
#define FLAG_USE_ARMOUR
Definition: define.h:295
PU_JEWELS
#define PU_JEWELS
Definition: define.h:141
item
Definition: item.py:1
MSG_TYPE_ITEM_REMOVE
#define MSG_TYPE_ITEM_REMOVE
Definition: newclient.h:645
is_identifiable_type
int is_identifiable_type(const object *op)
Definition: item.cpp:1324
change_attr_value
void change_attr_value(living *stats, int attr, int8_t value)
Definition: living.cpp:264
mapstruct
Definition: map.h:313
enter_exit
void enter_exit(object *op, object *exit_ob)
Definition: server.cpp:727
check_spell_known
object * check_spell_known(object *op, const char *name)
Definition: spell_util.cpp:394
living::Cha
int8_t Cha
Definition: living.h:36
give.op
op
Definition: give.py:33
NDI_ALL
#define NDI_ALL
Definition: newclient.h:266
socket_struct::status
enum Sock_Status status
Definition: newserver.h:90
fire_bow
int fire_bow(object *op, object *arrow, int dir, int wc_mod, int16_t sx, int16_t sy)
Definition: player.cpp:2101
save_life
static int save_life(object *op)
Definition: player.cpp:3172
STRENGTH
@ STRENGTH
Definition: living.h:11
object::skill
sstring skill
Definition: object.h:329
animate_object
void animate_object(object *op, int dir)
Definition: anim.cpp:44
player::language
language_t language
Definition: player.h:220
find_archetype
archetype * find_archetype(const char *name)
Definition: assets.cpp:266
shop.h
object_split
object * object_split(object *orig_ob, uint32_t nr, char *err, size_t size)
Definition: object.cpp:2637
EXIT_ALT_X
#define EXIT_ALT_X(xyz)
Definition: define.h:443
MSG_TYPE_ATTRIBUTE_GOD
#define MSG_TYPE_ATTRIBUTE_GOD
Definition: newclient.h:578
dragon_ability_gain
void dragon_ability_gain(object *who, int atnr, int level)
Definition: player.cpp:4303
change_luck
void change_luck(object *op, int value)
Definition: living.cpp:796
restore_player
static void restore_player(object *op)
Definition: player.cpp:3462
PU_ARMOUR
#define PU_ARMOUR
Definition: define.h:123
object_set_msg
void object_set_msg(object *op, const char *msg)
Definition: object.cpp:4811
esrv_update_item
void esrv_update_item(int flags, object *pl, object *op)
Definition: main.cpp:359
did_make_save
int did_make_save(const object *op, int level, int bonus)
Definition: living.cpp:2289
send_rules
void send_rules(const object *op)
Definition: player.cpp:170
Settings::max_stat
uint8_t max_stat
Definition: global.h:324
SPELL_EFFECT
@ SPELL_EFFECT
Definition: object.h:220
object::msg
sstring msg
Definition: object.h:330
PU_NEWMODE
#define PU_NEWMODE
Definition: define.h:111
rv_vector
Definition: map.h:368
MSG_TYPE_ADMIN_RULES
#define MSG_TYPE_ADMIN_RULES
Definition: newclient.h:497
SKILL_TOOL
@ SKILL_TOOL
Definition: object.h:194
send_news
void send_news(const object *op)
Definition: player.cpp:206
EXIT_Y
#define EXIT_Y(xyz)
Definition: define.h:442
get_randomized_dir
int get_randomized_dir(int dir)
Definition: utils.cpp:412
diamondslots.y
y
Definition: diamondslots.py:16
FLAG_BEEN_APPLIED
#define FLAG_BEEN_APPLIED
Definition: define.h:323
assets.h
CLEAR_FLAG
#define CLEAR_FLAG(xyz, p)
Definition: define.h:225
NDI_BROWN
#define NDI_BROWN
Definition: newclient.h:256
AP_NOPRINT
#define AP_NOPRINT
Definition: define.h:585
EVENT_REMOVE
#define EVENT_REMOVE
Definition: events.h:54
SockList_ResetRead
void SockList_ResetRead(SockList *sl)
Definition: lowlevel.cpp:83
NDI_DK_ORANGE
#define NDI_DK_ORANGE
Definition: newclient.h:251
strip_endline
void strip_endline(char *buf)
Definition: utils.cpp:314
bow_n
@ bow_n
Definition: player.h:45
die_roll
int die_roll(int num, int size, const object *op, int goodbad)
Definition: utils.cpp:122
socket_struct::faces_sent
uint8_t * faces_sent
Definition: newserver.h:96
get_password
void get_password(object *op)
Definition: player.cpp:900
player::last_resist
int16_t last_resist[NROFATTACKS]
Definition: player.h:174
arch_to_object
object * arch_to_object(archetype *at)
Definition: arch.cpp:229
level
int level
Definition: readable.cpp:1563
get_rangevector
int get_rangevector(object *op1, const object *op2, rv_vector *retval, int flags)
Definition: map.cpp:2492
player::party
partylist * party
Definition: player.h:203
keyrings
@ keyrings
Definition: player.h:67
castle_read.key
key
Definition: castle_read.py:64
play_again
void play_again(object *op)
Definition: player.cpp:911
get_player
player * get_player(player *p)
Definition: player.cpp:285
MSG_TYPE_ADMIN_LOGIN
#define MSG_TYPE_ADMIN_LOGIN
Definition: newclient.h:503
FLAG_ANIMATE
#define FLAG_ANIMATE
Definition: define.h:242
MSG_TYPE_ATTRIBUTE_BAD_EFFECT_END
#define MSG_TYPE_ATTRIBUTE_BAD_EFFECT_END
Definition: newclient.h:570
newclient.h
fix_luck
void fix_luck(void)
Definition: player.cpp:3918
save_player
int save_player(object *op, int flag)
Definition: login.cpp:230
ST_GET_PARTY_PASSWORD
#define ST_GET_PARTY_PASSWORD
Definition: define.h:549
draw_ext_info
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
Definition: main.cpp:308
object_matches_pickup_mode
int object_matches_pickup_mode(const object *item, int mode)
Definition: c_object.cpp:656
FOOD
@ FOOD
Definition: object.h:117
object_remove
void object_remove(object *op)
Definition: object.cpp:1833
cure_disease
int cure_disease(object *sufferer, object *caster, sstring skill)
Definition: disease.cpp:685
DOOR
@ DOOR
Definition: object.h:131
object_sum_weight
signed long object_sum_weight(object *op)
Definition: object.cpp:568
FLAG_UNPAID
#define FLAG_UNPAID
Definition: define.h:236
FLAG_NO_STRENGTH
#define FLAG_NO_STRENGTH
Definition: define.h:306
player::last_path_repelled
uint32_t last_path_repelled
Definition: player.h:161
PU_NOTHING
#define PU_NOTHING
Definition: define.h:106
OB_TYPE_MOVE_BLOCK
#define OB_TYPE_MOVE_BLOCK(ob1, type)
Definition: define.h:432
move_player
int move_player(object *op, int dir)
Definition: player.cpp:2956
remove_statbonus
void remove_statbonus(object *op)
Definition: living.cpp:845
MSG_TYPE_ATTACK_NOATTACK
#define MSG_TYPE_ATTACK_NOATTACK
Definition: newclient.h:621
object::spellarg
char * spellarg
Definition: object.h:421
make_path_to_file
void make_path_to_file(const char *filename)
Definition: porting.cpp:164
DRINK
@ DRINK
Definition: object.h:162
PU_CURSED
#define PU_CURSED
Definition: define.h:144
find_player_partial_name
player * find_player_partial_name(const char *plname)
Definition: player.cpp:114
roll_stats
void roll_stats(object *op)
Definition: player.cpp:1070
ATNR_COLD
#define ATNR_COLD
Definition: attack.h:53
object::nrof
uint32_t nrof
Definition: object.h:342
FLAG_XRAYS
#define FLAG_XRAYS
Definition: define.h:300
player::socket
socket_struct * socket
Definition: player.h:107
mapstruct::next
mapstruct * next
Definition: map.h:314
living::grace
int16_t grace
Definition: living.h:44
add_player
player * add_player(socket_struct *ns, int flags)
Definition: player.cpp:468
say.item
dictionary item
Definition: say.py:149
query_base_name
void query_base_name(const object *op, int plural, char *buf, size_t size)
Definition: item.cpp:689
Settings::search_items
uint8_t search_items
Definition: global.h:267
object::stats
living stats
Definition: object.h:378
treasure
Definition: treasure.h:63
player::title
char title[BIG_NAME]
Definition: player.h:184
object::more
object * more
Definition: object.h:303
get_attr_value
int8_t get_attr_value(const living *stats, int attr)
Definition: living.cpp:313
drain_rod_charge
void drain_rod_charge(object *rod)
Definition: spell_util.cpp:776
range_skill
@ range_skill
Definition: player.h:35
server.h
freearr_x
short freearr_x[SIZEOFFREE]
Definition: object.cpp:299
PU_DRINK
#define PU_DRINK
Definition: define.h:116
player_attack_door
static int player_attack_door(object *op, object *door)
Definition: player.cpp:2558
INTELLIGENCE
@ INTELLIGENCE
Definition: living.h:16
player::petmode
petmode_t petmode
Definition: player.h:115
shop_contains
bool shop_contains(object *ob)
Definition: shop.cpp:1300
hide
int hide(object *op, object *skill)
Definition: skills.cpp:496
swap_stat
static void swap_stat(object *op, int swap_second)
Definition: player.cpp:1163
TRUE
#define TRUE
Definition: compat.h:11
player::last_weapon_sp
float last_weapon_sp
Definition: player.h:156
ATNR_ELECTRICITY
#define ATNR_ELECTRICITY
Definition: attack.h:52
ST_ROLL_STAT
#define ST_ROLL_STAT
Definition: define.h:543
clear_player
void clear_player(player *pl)
Definition: player.cpp:33
pets_control_golem
void pets_control_golem(object *op, int dir)
Definition: pets.cpp:630
PU_SHIELD
#define PU_SHIELD
Definition: define.h:122
SPELL
@ SPELL
Definition: object.h:219
link_player_skills
void link_player_skills(object *op)
Definition: player.cpp:287
find_key
object * find_key(object *pl, object *container, object *door)
Definition: player.cpp:2476
give_initial_items
void give_initial_items(object *pl, treasurelist *items)
Definition: player.cpp:792
living::Pow
int8_t Pow
Definition: living.h:36
update_transport_block
static void update_transport_block(object *transport, int dir)
Definition: player.cpp:2808
MSG_TYPE_APPLY
#define MSG_TYPE_APPLY
Definition: newclient.h:411
player_map_change_common
void player_map_change_common(object *op, mapstruct *const oldmap, mapstruct *const newmap)
Definition: server.cpp:282
dragon.state
state
Definition: dragon.py:84
account_char_save
void account_char_save(Account_Chars *chars)
Definition: account_char.cpp:158
object::attacktype
uint32_t attacktype
Definition: object.h:352
OUT_OF_MEMORY
@ OUT_OF_MEMORY
Definition: define.h:48
FLAG_CURSED
#define FLAG_CURSED
Definition: define.h:316
pick_up
void pick_up(object *op, object *alt)
Definition: c_object.cpp:519
rv_vector::direction
int direction
Definition: map.h:372
altar_valkyrie.pl
pl
Definition: altar_valkyrie.py:28
check_stat_bounds
void check_stat_bounds(living *stats, int8_t min_stat, int8_t max_stat)
Definition: living.cpp:354
living.h
send_query
void send_query(socket_struct *ns, uint8_t flags, const char *text)
Definition: request.cpp:746
Send_With_Handling
void Send_With_Handling(socket_struct *ns, SockList *sl)
Definition: lowlevel.cpp:447
is_true_undead
int is_true_undead(object *op)
Definition: player.cpp:3987
MSG_TYPE_ADMIN
#define MSG_TYPE_ADMIN
Definition: newclient.h:405
SockList
Definition: newclient.h:684
rv_vector::distance
unsigned int distance
Definition: map.h:369
player::bowtype
bowtype_t bowtype
Definition: player.h:114
SPELLBOOK
@ SPELLBOOK
Definition: object.h:208
NUM_STATS
@ NUM_STATS
Definition: living.h:18
MSG_TYPE_ITEM_INFO
#define MSG_TYPE_ITEM_INFO
Definition: newclient.h:648
apply_race_and_class
int apply_race_and_class(object *op, archetype *race, archetype *opclass, living *stats)
Definition: player.cpp:1487
FOR_INV_PREPARE
#define FOR_INV_PREPARE(op_, it_)
Definition: define.h:670
MAX_FOOD
static const int32_t MAX_FOOD
Definition: define.h:461
living::hp
int16_t hp
Definition: living.h:40
living::luck
int8_t luck
Definition: living.h:39
create_treasure
void create_treasure(treasurelist *t, object *op, int flag, int difficulty, int tries)
Definition: treasure.cpp:263
drain_wand_charge
void drain_wand_charge(object *wand)
Definition: spell_util.cpp:786
FORCE
@ FORCE
Definition: object.h:229
playername_ok
int playername_ok(const char *cp)
Definition: player.cpp:257
player::last_character_load
float last_character_load
Definition: player.h:136
account_char_remove
void account_char_remove(Account_Chars *chars, const char *pl_name)
Definition: account_char.cpp:313
EXIT_ALT_Y
#define EXIT_ALT_Y(xyz)
Definition: define.h:444
object.h
player::ticks_played
uint32_t ticks_played
Definition: player.h:222
player::rejoin_party
party_rejoin_mode rejoin_party
Definition: player.h:210
events_execute_global_event
void events_execute_global_event(int eventcode,...)
Definition: events.cpp:32
CONSTITUTION
@ CONSTITUTION
Definition: living.h:13
object_can_merge
int object_can_merge(object *ob1, object *ob2)
Definition: object.cpp:433
llevDebug
@ llevDebug
Definition: logger.h:13
FLAG_LIFESAVE
#define FLAG_LIFESAVE
Definition: define.h:305
MONEY
@ MONEY
Definition: object.h:142
NRSPELLPATHS
#define NRSPELLPATHS
Definition: spells.h:40
is_valid_types_gen.type
list type
Definition: is_valid_types_gen.py:25
i18n
const char * i18n(const object *who, const char *code)
Definition: languages.cpp:42
P_BLOCKSVIEW
#define P_BLOCKSVIEW
Definition: map.h:224
FORCE_NAME
#define FORCE_NAME
Definition: spells.h:169
living::Con
int8_t Con
Definition: living.h:36
FLAG_IDENTIFIED
#define FLAG_IDENTIFIED
Definition: define.h:261
give.name
name
Definition: give.py:27
living::Str
int8_t Str
Definition: living.h:36
skill_attack
void skill_attack(object *tmp, object *pl, int dir, const char *string, object *skill)
Definition: skill_util.cpp:1270
PU_DEBUG
#define PU_DEBUG
Definition: define.h:108
dragon_attune.force
force
Definition: dragon_attune.py:45
CS_QUERY_HIDEINPUT
#define CS_QUERY_HIDEINPUT
Definition: newclient.h:71
PU_SKILLSCROLL
#define PU_SKILLSCROLL
Definition: define.h:136
level
Definition: level.py:1
Settings::localdir
const char * localdir
Definition: global.h:249