Crossfire Server, Trunk  1.75.0
player.cpp
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2014 Mark Wedel and the Crossfire Development Team
5  * Copyright (c) 1992 Frank Tore Johansen
6  *
7  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
8  * welcome to redistribute it under certain conditions. For details, please
9  * see COPYING and LICENSE.
10  *
11  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
12  */
13 
20 #include "global.h"
21 
22 #include <assert.h>
23 #include <ctype.h>
24 #include <math.h>
25 #include <stddef.h>
26 #include <stdlib.h>
27 #include <string.h>
28 
29 #ifndef WIN32 /* ---win32 remove headers */
30 #include <pwd.h>
31 #endif
32 
33 #include "server.h"
34 #include "living.h"
35 #include "object.h"
36 #include "shared/newclient.h"
37 #include "shop.h"
38 #include "skills.h"
39 #include "sounds.h"
40 #include "spells.h"
41 #include "sproto.h"
42 #include "assets.h"
43 #include "AssetsManager.h"
44 
46 
47 static void kill_player_not_permadeath(object *op);
48 static void kill_player_permadeath(object *op);
49 static int action_makes_visible(object *op);
50 
59 player *find_player(const char *plname) {
60  return find_player_options(plname, 0, NULL);
61 }
62 
70 player *find_player_options(const char *plname, int options, const mapstruct *map) {
71  player *pl;
72  player *found = NULL;
73  size_t namelen = strlen(plname);
74  char name[MAX_BUF];
75 
76  for (pl = first_player; pl != NULL; pl = pl->next) {
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)
794  create_treasure(items, pl, GT_STARTEQUIP|GT_ONLY_GOOD, 1, 0);
795 
796  FOR_INV_PREPARE(pl, op) {
797  /* Forces get applied per default, unless they have the
798  * flag "neutral" set. Sorry but I can't think of a better way
799  */
800  if (op->type == FORCE && !QUERY_FLAG(op, FLAG_NEUTRAL))
801  SET_FLAG(op, FLAG_APPLIED);
802 
803  /* we never give weapons/armour if these cannot be used
804  * by this player due to race restrictions
805  */
806  if (pl->type == PLAYER) {
807  if ((!QUERY_FLAG(pl, FLAG_USE_ARMOUR) && IS_ARMOR(op))
808  || (!QUERY_FLAG(pl, FLAG_USE_WEAPON) && IS_WEAPON(op))
809  || (!QUERY_FLAG(pl, FLAG_USE_SHIELD) && IS_SHIELD(op))) {
810  object_remove(op);
812  continue;
813  }
814  }
815 
816  /* This really needs to be better - we should really give
817  * a substitute spellbook. The problem is that we don't really
818  * have a good idea what to replace it with (need something like
819  * a first level treasurelist for each skill.)
820  * remove duplicate skills also
821  */
822  if (op->type == SPELLBOOK || op->type == SKILL) {
823  int found;
824 
825  found = 0;
826  // Make sure we set flags that are checked by object_can_merge
827  // *before* we run object_can_merge. Otherwise, we can get two
828  // entries of the same skill.
829  if (op->type == SKILL) {
831  op->stats.exp = 0;
832  op->level = 1;
833  // Since this also happens to the invisible skills, we need this so that the flags match.
835  }
836  FOR_BELOW_PREPARE(op, tmp)
837  if (object_can_merge(op, tmp)) {
838  found = 1;
839  break;
840  }
842  if (found) {
843  LOG(llevError, "give_initial_items: Removing duplicate object %s\n", op->name);
844  object_remove(op);
846  continue;
847  }
848  if (op->nrof > 1)
849  op->nrof = 1;
850  }
851 
852  if (op->type == SPELLBOOK && op->inv) {
853  CLEAR_FLAG(op->inv, FLAG_STARTEQUIP);
854  }
855 
856  /* Give starting characters identified, uncursed, and undamned
857  * items. Just don't identify gold or silver, or it won't be
858  * merged properly.
859  */
860  if (is_identifiable_type(op)) {
862  CLEAR_FLAG(op, FLAG_CURSED);
863  CLEAR_FLAG(op, FLAG_DAMNED);
864  }
865  } FOR_INV_FINISH(); /* for loop of objects in player inv */
866 
867  /* Need to set up the skill pointers */
868  link_player_skills(pl);
869 
874  FOR_INV_PREPARE(pl, op)
875  if ((IS_ARMOR(op) || IS_WEAPON(op) || IS_SHIELD(op)) && !QUERY_FLAG(op, FLAG_APPLIED))
876  apply_manual(pl, op, AP_NOPRINT);
877  FOR_INV_FINISH();
878 }
879 
886 void get_name(object *op) {
888  send_query(op->contr->socket, 0, i18n(op, "What is your name?\n:"));
889 }
890 
897 void get_password(object *op) {
899  send_query(op->contr->socket, CS_QUERY_HIDEINPUT, i18n(op, "What is your password?\n:"));
900 }
901 
908 void play_again(object *op) {
909  SockList sl;
910 
911  op->contr->socket->status = Ns_Add;
913  op->chosen_skill = NULL;
914 
915  /*
916  * For old clients, ask if they want to play again.
917  * For clients with account support, just return to character seletion (see below).
918  */
919  if (op->contr->socket->login_method == 0) {
920  send_query(op->contr->socket, CS_QUERY_SINGLECHAR, i18n(op, "Do you want to play again (a/q)?"));
921  }
922  /* a bit of a hack, but there are various places early in th
923  * player creation process that a user can quit (eg, roll
924  * stats) that isn't removing the player. Taking a quick
925  * look, there are many places that call play_again without
926  * removing the player - it probably makes more sense
927  * to leave it to play_again to remove the object in all
928  * cases.
929  */
930  if (!QUERY_FLAG(op, FLAG_REMOVED))
931  object_remove(op);
932  /* Need to set this to null - otherwise, it could point to garbage,
933  * and draw() doesn't check to see if the player is removed, only if
934  * the map is null or not swapped out.
935  */
936  op->map = NULL;
937 
938  SockList_Init(&sl);
939  SockList_AddString(&sl, "player ");
940  SockList_AddInt(&sl, 0);
941  SockList_AddInt(&sl, 0);
942  SockList_AddInt(&sl, 0);
943  SockList_AddChar(&sl, 0);
944 
945  Send_With_Handling(op->contr->socket, &sl);
946  SockList_Term(&sl);
947 
948  if (op->contr->socket->login_method > 0) {
949  receive_play_again(op, 'a');
950  }
951 }
952 
961 void receive_play_again(object *op, char key) {
962  if (key == 'q' || key == 'Q') {
964  leave(op->contr, 0); /* ericserver will draw the message */
965  return;
966  } else if (key == 'a' || key == 'A') {
967  player *pl = op->contr;
968  const char *name = op->name;
969 
973  pl = get_player(pl);
974  op = pl->ob;
976  op->contr->password[0] = '~';
979  if (pl->socket->login_method >= 1 && pl->socket->account_name != NULL) {
980  /* If we are using new login, we send the
981  * list of characters to the client - this should
982  * result in the client popping up this list so
983  * the player can choose which one to play - better
984  * than going to legacy login code.
985  * If the account_name is NULL, it means the client
986  * says it uses account but started playing without logging in.
987  */
990  } else {
991  /* Lets put a space in here */
993  "\n");
994  get_name(op);
995  set_first_map(op);
996  }
997  op->name = name; /* Already added a refcount above */
998  op->name_pl = add_string(name);
999  } else {
1000  /* user pressed something else so just ask again... */
1001  play_again(op);
1002  }
1003 }
1004 
1011 void confirm_password(object *op) {
1013  send_query(op->contr->socket, CS_QUERY_HIDEINPUT, i18n(op, "Please type your password again.\n:"));
1014 }
1015 
1026 int get_party_password(object *op, partylist *party) {
1027  if (*party_get_password(party) == '\0') {
1028  return 0;
1029  }
1030 
1032  op->contr->party_to_join = party;
1033  send_query(op->contr->socket, CS_QUERY_HIDEINPUT, i18n(op, "What is the password?\n:"));
1034  return 1;
1035 }
1036 
1043 int roll_stat(void) {
1044  int roll[4], i, low_index, k;
1045 
1046  for (i = 0; i < 4; ++i)
1047  roll[i] = (int)RANDOM()%6+1;
1048 
1049  for (i = 0, low_index = 0, k = 7; i < 4; ++i)
1050  if (roll[i] < k)
1051  k = roll[i],
1052  low_index = i;
1053 
1054  for (i = 0, k = 0; i < 4; ++i) {
1055  if (i != low_index)
1056  k += roll[i];
1057  }
1058  return k;
1059 }
1060 
1067 void roll_stats(object *op) {
1068  int i = 0, j = 0;
1069  int statsort[7];
1070 
1071  op->stats.Str = roll_stat();
1072  op->stats.Dex = roll_stat();
1073  op->stats.Int = roll_stat();
1074  op->stats.Con = roll_stat();
1075  op->stats.Wis = roll_stat();
1076  op->stats.Pow = roll_stat();
1077  op->stats.Cha = roll_stat();
1078  int sum = op->stats.Str+op->stats.Dex+op->stats.Int+op->stats.Con+op->stats.Wis+op->stats.Pow+op->stats.Cha;
1079  float scale = settings.roll_stat_points / sum;
1080  op->stats.Str = roundf(scale * op->stats.Str);
1081  op->stats.Dex = roundf(scale * op->stats.Dex);
1082  op->stats.Int = roundf(scale * op->stats.Int);
1083  op->stats.Con = roundf(scale * op->stats.Con);
1084  op->stats.Wis = roundf(scale * op->stats.Wis);
1085  op->stats.Pow = roundf(scale * op->stats.Pow);
1086  op->stats.Cha = roundf(scale * op->stats.Cha);
1087 
1088  /* Sort the stats so that rerolling is easier... */
1089  statsort[0] = op->stats.Str;
1090  statsort[1] = op->stats.Dex;
1091  statsort[2] = op->stats.Int;
1092  statsort[3] = op->stats.Con;
1093  statsort[4] = op->stats.Wis;
1094  statsort[5] = op->stats.Pow;
1095  statsort[6] = op->stats.Cha;
1096 
1097  /* a quick and dirty bubblesort? */
1098  do {
1099  if (statsort[i] < statsort[i+1]) {
1100  j = statsort[i];
1101  statsort[i] = statsort[i+1];
1102  statsort[i+1] = j;
1103  i = 0;
1104  } else {
1105  i++;
1106  }
1107  } while (i < 6);
1108 
1109  op->stats.Str = statsort[0];
1110  op->stats.Dex = statsort[1];
1111  op->stats.Con = statsort[2];
1112  op->stats.Int = statsort[3];
1113  op->stats.Wis = statsort[4];
1114  op->stats.Pow = statsort[5];
1115  op->stats.Cha = statsort[6];
1116 
1117  op->contr->orig_stats.Str = op->stats.Str;
1118  op->contr->orig_stats.Dex = op->stats.Dex;
1119  op->contr->orig_stats.Int = op->stats.Int;
1120  op->contr->orig_stats.Con = op->stats.Con;
1121  op->contr->orig_stats.Wis = op->stats.Wis;
1122  op->contr->orig_stats.Pow = op->stats.Pow;
1123  op->contr->orig_stats.Cha = op->stats.Cha;
1124 
1125  op->level = 1;
1126  op->stats.exp = 0;
1127  op->stats.ac = 0;
1128 
1129  op->contr->levhp[1] = 9;
1130  op->contr->levsp[1] = 6;
1131  op->contr->levgrace[1] = 3;
1132 
1133  fix_object(op);
1134  op->stats.hp = op->stats.maxhp;
1135  op->stats.sp = op->stats.maxsp;
1136  op->stats.grace = op->stats.maxgrace;
1137  op->contr->orig_stats = op->stats;
1138 }
1139 
1146 void roll_again(object *op) {
1147  esrv_new_player(op->contr, 0);
1148  send_query(op->contr->socket, CS_QUERY_SINGLECHAR, i18n(op, "<y> to roll new stats <n> to use stats\n<1-7> <1-7> to swap stats.\nRoll again (y/n/1-7)? "));
1149 }
1150 
1160 static void swap_stat(object *op, int swap_second) {
1161  signed char tmp;
1162 
1163  if (op->contr->swap_first == -1) {
1164  LOG(llevError, "player.c:swap_stat() - swap_first is -1\n");
1165  return;
1166  }
1167 
1168  tmp = get_attr_value(&op->contr->orig_stats, op->contr->swap_first);
1169 
1170  set_attr_value(&op->contr->orig_stats, op->contr->swap_first, get_attr_value(&op->contr->orig_stats, swap_second));
1171 
1172  set_attr_value(&op->contr->orig_stats, swap_second, tmp);
1173 
1175  "%s done\n",
1176  short_stat_name[swap_second]);
1177 
1178  op->stats.Str = op->contr->orig_stats.Str;
1179  op->stats.Dex = op->contr->orig_stats.Dex;
1180  op->stats.Con = op->contr->orig_stats.Con;
1181  op->stats.Int = op->contr->orig_stats.Int;
1182  op->stats.Wis = op->contr->orig_stats.Wis;
1183  op->stats.Pow = op->contr->orig_stats.Pow;
1184  op->stats.Cha = op->contr->orig_stats.Cha;
1185  op->stats.ac = 0;
1186 
1187  op->level = 1;
1188  op->stats.exp = 0;
1189  op->stats.ac = 0;
1190 
1191  op->contr->levhp[1] = 9;
1192  op->contr->levsp[1] = 6;
1193  op->contr->levgrace[1] = 3;
1194 
1195  fix_object(op);
1196  op->stats.hp = op->stats.maxhp;
1197  op->stats.sp = op->stats.maxsp;
1198  op->stats.grace = op->stats.maxgrace;
1199  op->contr->orig_stats = op->stats;
1200  op->contr->swap_first = -1;
1201 }
1202 
1218 void key_roll_stat(object *op, char key) {
1219  int keynum = key-'0';
1220  static const int8_t stat_trans[] = {
1221  -1,
1222  STRENGTH,
1223  DEXTERITY,
1224  CONSTITUTION,
1225  INTELLIGENCE,
1226  WISDOM,
1227  POWER,
1228  CHARISMA,
1229  };
1230 
1231  if (keynum > 0 && keynum <= 7) {
1232  if (op->contr->swap_first == -1) {
1233  op->contr->swap_first = stat_trans[keynum];
1235  "%s ->",
1236  short_stat_name[stat_trans[keynum]]);
1237  } else
1238  swap_stat(op, stat_trans[keynum]);
1239 
1241  return;
1242  }
1243  switch (key) {
1244  case 'n':
1245  case 'N': {
1246  SET_FLAG(op, FLAG_WIZ);
1247  if (op->map == NULL) {
1248  LOG(llevError, "Map == NULL in state 2\n");
1249  break;
1250  }
1251 
1252  SET_ANIMATION(op, 2); /* So player faces south */
1253  /* Enter exit adds a player otherwise */
1254  add_statbonus(op);
1255  send_query(op->contr->socket, CS_QUERY_SINGLECHAR, i18n(op, "Now choose a character.\nPress any key to change outlook.\nPress `d' when you're pleased.\n"));
1257  if (op->msg)
1258  draw_ext_info(NDI_BLUE, 0, op,
1260  op->msg);
1261  return;
1262  }
1263  case 'y':
1264  case 'Y':
1265  roll_stats(op);
1267  return;
1268 
1269  case 'q':
1270  case 'Q':
1271  play_again(op);
1272  return;
1273 
1274  default:
1275  send_query(op->contr->socket, CS_QUERY_SINGLECHAR, i18n(op, "Yes, No, Quit or 1-6. Roll again?"));
1276  return;
1277  }
1278  return;
1279 }
1280 
1294 void key_change_class(object *op, char key) {
1295  int tmp_loop;
1296 
1297  if (key == 'q' || key == 'Q') {
1298  object_remove(op);
1299  play_again(op);
1300  return;
1301  }
1302  if (key == 'd' || key == 'D') {
1303  char buf[MAX_BUF];
1304 
1305  /* this must before then initial items are given */
1306  esrv_new_player(op->contr, op->weight+op->carrying);
1307  create_treasure(find_treasurelist("starting_wealth"), op, 0, 0, 0);
1308 
1309  /* Here we handle the BORN global event */
1311 
1312  /* We then generate a LOGIN event */
1315 
1316  object_set_msg(op, NULL);
1317 
1318  /* We create this now because some of the unique maps will need it
1319  * to save here.
1320  */
1321  snprintf(buf, sizeof(buf), "%s/%s/%s", settings.localdir, settings.playerdir, op->name);
1323 
1324 #ifdef AUTOSAVE
1325  op->contr->last_save_tick = pticks;
1326 #endif
1329  "Welcome to Crossfire!\n Press `?' for help\n");
1330 
1333  "%s entered the game.", op->name);
1334 
1335  CLEAR_FLAG(op, FLAG_WIZ);
1337  link_player_skills(op);
1338  esrv_send_inventory(op, op);
1339  fix_object(op);
1340 
1341  /* This moves the player to a different start map, if there
1342  * is one for this race
1343  */
1344  if (*first_map_ext_path) {
1345  object *tmp;
1346  char mapname[MAX_BUF + strlen(op->arch->name) + 1];
1347  mapstruct *oldmap;
1348 
1349  oldmap = op->map;
1350 
1351  snprintf(mapname, sizeof(mapname), "%s/%s", first_map_ext_path, op->arch->name);
1352  /*printf("%s\n", mapname);*/
1353  tmp = object_new();
1354  EXIT_PATH(tmp) = add_string(mapname);
1355  EXIT_X(tmp) = op->x;
1356  EXIT_Y(tmp) = op->y;
1357  enter_exit(op, tmp);
1358 
1359  if (oldmap != op->map) {
1360  /* map exists, update bed of reality location, in case player dies */
1361  op->contr->bed_x = op->x;
1362  op->contr->bed_y = op->y;
1363  strlcpy(op->contr->savebed_map, mapname, sizeof(op->contr->savebed_map));
1364  }
1365 
1367  } else {
1368  LOG(llevDebug, "first_map_ext_path not set\n");
1369  }
1370  return;
1371  }
1372 
1373  /* Following actually changes the race - this is the default command
1374  * if we don't match with one of the options above.
1375  */
1376 
1377  tmp_loop = 0;
1378  while (!tmp_loop) {
1379  const char *name = add_string(op->name);
1380  int x = op->x, y = op->y;
1381 
1382  remove_statbonus(op);
1383  object_remove(op);
1384  /* get_player_archetype() is really misnamed - it will
1385  * get the next archetype from the list.
1386  */
1387  op->arch = get_player_archetype(op->arch);
1388  object_copy(&op->arch->clone, op);
1389  op->stats = op->contr->orig_stats;
1390  free_string(op->name);
1391  op->name = name;
1392  free_string(op->name_pl);
1393  op->name_pl = add_string(name);
1394  SET_ANIMATION(op, 2); /* So player faces south */
1395  object_insert_in_map_at(op, op->map, op, 0, x, y);
1396  strncpy(op->contr->title, op->arch->clone.name, sizeof(op->contr->title)-1);
1397  op->contr->title[sizeof(op->contr->title)-1] = '\0';
1398  add_statbonus(op);
1399  tmp_loop = allowed_class(op);
1400  }
1402  esrv_update_item(UPD_FACE, op, op);
1403  fix_object(op);
1404  op->contr->is_wraith = object_find_by_name(op, "wraith feed") != NULL;
1405  op->stats.hp = op->stats.maxhp;
1406  op->stats.sp = op->stats.maxsp;
1407  op->stats.grace = 0;
1408  if (op->msg)
1410  op->msg);
1411  send_query(op->contr->socket, CS_QUERY_SINGLECHAR, i18n(op, "Press any key for the next race.\nPress `d' to play this race.\n"));
1412 }
1413 
1436 {
1437  int i, stat, failure=0;
1438 
1439  for (i = 0; i < NUM_STATS; i++) {
1440  stat = get_attr_value(stats, i);
1441  if (race)
1442  stat += get_attr_value(&race->clone.stats, i);
1443 
1444  if (opclass)
1445  stat += get_attr_value(&opclass->clone.stats, i);
1446 
1447  set_attr_value(stats, i, stat);
1448 
1449  /* We process all stats, regardless if there is a failure
1450  * or not.
1451  */
1452  if (stat < MIN_STAT) failure=1;
1453 
1454  /* Maybe this should be an error? Player is losing
1455  * some stats points here, but it is legal.
1456  */
1457  if (stat > settings.max_stat) stat = settings.max_stat;
1458  }
1459  return failure;
1460 
1461 }
1462 
1485 int apply_race_and_class(object *op, archetype *race, archetype *opclass, living *stats)
1486 {
1487  const char *name = add_string(op->name);
1488  char buf[MAX_BUF];
1489  object *inv;
1490 
1491  /* Free any objects in character inventory - they
1492  * shouldn't have any, but there is the potential that
1493  * we give them objects below and then get a creation
1494  * failure (stat out of range), in which case
1495  * those objects would be in the inventory.
1496  */
1497  while (op->inv) {
1498  inv = op->inv;
1499  object_remove(inv);
1500  object_free(inv, 0);
1501  }
1502 
1503  object_copy(&race->clone, op);
1504  free_string(op->name);
1505  op->name = name;
1506  free_string(op->name_pl);
1507  op->name_pl = add_string(name);
1508  SET_ANIMATION(op, 2); /* So player faces south */
1509  strlcpy(op->contr->title, op->arch->clone.name, sizeof(op->contr->title));
1510 
1511  if (stats) {
1512  /* Copy over the stats. Use this instead a memcpy because
1513  * we only want to copy over a few specific stats, and
1514  * leave things like maxhp, maxsp, etc, unchanged.
1515  */
1516  int i, stat;
1517  for (i = 0; i < NUM_STATS; i++) {
1518  stat = get_attr_value(stats, i);
1519  set_attr_value(&op->stats, i, stat);
1520  set_attr_value(&op->contr->orig_stats, i, stat);
1521  }
1522  } else {
1523  /* Note that this will repeated increase the stat values
1524  * if the caller does not reset them. Only do this
1525  * if stats is not provided - if stats is provided, those
1526  * are already adjusted.
1527  */
1528  add_statbonus(op);
1529 
1530  /* Checks that all stats are greater than 1. Once again,
1531  * only do this if stats are not provided
1532  */
1533  if (!allowed_class(op)) return 1;
1534  }
1535 
1537  op->stats.hp = op->stats.maxhp;
1538  op->stats.sp = op->stats.maxsp;
1539  op->stats.grace = 0;
1540 
1541  /* this must before then initial items are given */
1542  esrv_new_player(op->contr, op->weight+op->carrying);
1543  create_treasure(find_treasurelist("starting_wealth"), op, 0, 0, 0);
1544 
1545  /* This has to be done before class, otherwise the NOCLASSFACECHANGE
1546  * object is not in the inventory, and racial face will get overwritten.
1547  */
1549 
1550  if (stats) {
1551  /* Apply class information */
1553  } else {
1554  apply_changes_to_player(op, &opclass->clone, 0);
1555 
1556  /* Checks that all stats are greater than 1 */
1557  if (!allowed_class(op)) return 2;
1558  }
1559 
1560  /* Here we handle the BORN global event */
1562 
1563  /* We then generate a LOGIN event */
1565 
1566  object_set_msg(op, NULL);
1567 
1568  /* We create this now because some of the unique maps will need it
1569  * to save here.
1570  */
1571  snprintf(buf, sizeof(buf), "%s/%s/%s", settings.localdir, settings.playerdir, op->name);
1573 
1574 #ifdef AUTOSAVE
1575  op->contr->last_save_tick = pticks;
1576 #endif
1577 
1578  CLEAR_FLAG(op, FLAG_WIZ);
1579  link_player_skills(op);
1580  fix_object(op);
1581 
1582  esrv_send_inventory(op, op);
1583  esrv_update_item(UPD_FACE, op, op);
1584  esrv_add_spells(op->contr, NULL);
1585  op->contr->is_wraith = object_find_by_name(op, "wraith feed") != NULL;
1586 
1587  return 0;
1588 
1589 }
1590 
1599 void key_confirm_quit(object *op, char key) {
1600  char buf[MAX_BUF];
1601  mapstruct *mp, *next;
1602 
1603  // this was tested when 'quit' command was issued, but better safe than sorry.
1604  if (QUERY_FLAG(op, FLAG_WIZ)) {
1606  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_LOGIN, "Can't quit when in DM mode.");
1607  return;
1608  }
1609 
1610  if (key != 'y' && key != 'Y' && key != 'q' && key != 'Q') {
1613  "OK, continuing to play.");
1614  return;
1615  }
1616 
1618  pets_terminate_all(op);
1619  object_remove(op);
1620  op->direction = 0;
1622  "%s quits the game.",
1623  op->name);
1624 
1625  strcpy(op->contr->killer, "quit");
1626  hiscore_check(op, 0);
1627  party_leave(op);
1628  if (settings.set_title == TRUE)
1629  player_set_own_title(op->contr, "");
1630 
1631 
1632  /* We need to hunt for any per player unique maps in memory and
1633  * get rid of them. The trailing slash in the path is intentional,
1634  * so that players named 'Ab' won't match against players 'Abe' pathname
1635  */
1636  snprintf(buf, sizeof(buf), "~%s/%s/", settings.playerdir, op->name);
1637  for (mp = first_map; mp != NULL; mp = next) {
1638  next = mp->next;
1639  if (!strncmp(mp->path, buf, strlen(buf)))
1640  delete_map(mp);
1641  }
1642 
1643  delete_character(op->name);
1644 
1645  /* Remove player from account list and send back data if needed */
1646  if (op->contr->socket->account_chars != NULL) {
1649  /* char information is reloaded in send_account_players below */
1651  op->contr->socket->account_chars = NULL;
1654  }
1655 
1656  play_again(op);
1657 
1658  // Fields in op are not cleared until the client plays a different
1659  // character or disconnects. Therefore, after deleting a character,
1660  // immediately creating a new character with the same name as the deleted
1661  // one fails because verify_player() thinks this player is still playing.
1662  // So we do a little hacking by clearing the name now.
1663  FREE_AND_CLEAR_STR(op->name);
1664 }
1665 
1672 static void flee_player(object *op) {
1673  int dir, diff;
1674  rv_vector rv;
1675 
1676  if (op->stats.hp < 0) {
1677  LOG(llevDebug, "Fleeing player is dead.\n");
1678  CLEAR_FLAG(op, FLAG_SCARED);
1679  return;
1680  }
1681 
1682  if (op->enemy == NULL) {
1683  LOG(llevDebug, "Fleeing player had no enemy.\n");
1684  CLEAR_FLAG(op, FLAG_SCARED);
1685  return;
1686  }
1687 
1688  /* Seen some crashes here. Since we don't store an
1689  * op->enemy_count, it is possible that something destroys the
1690  * actual enemy, and the object is recycled.
1691  */
1692  if (op->enemy->map == NULL) {
1693  CLEAR_FLAG(op, FLAG_SCARED);
1694  object_set_enemy(op, NULL);
1695  return;
1696  }
1697 
1698  if (!(random_roll(0, 4, op, PREFER_LOW)) && did_make_save(op, op->level, 0)) {
1699  object_set_enemy(op, NULL);
1700  CLEAR_FLAG(op, FLAG_SCARED);
1701  return;
1702  }
1703  if (!get_rangevector(op, op->enemy, &rv, 0)) {
1704  object_set_enemy(op, NULL);
1705  CLEAR_FLAG(op, FLAG_SCARED);
1706  return;
1707  }
1708 
1709  dir = absdir(4+rv.direction);
1710  for (diff = 0; diff < 3; diff++) {
1711  int m = 1-(RANDOM()&2);
1712  if (move_ob(op, absdir(dir+diff*m), op)
1713  || (diff == 0 && move_ob(op, absdir(dir-diff*m), op))) {
1714  return;
1715  }
1716  }
1717  /* Cornered, get rid of scared */
1718  CLEAR_FLAG(op, FLAG_SCARED);
1719  object_set_enemy(op, NULL);
1720 }
1721 
1731 int check_pick(object *op) {
1732  tag_t op_tag;
1733  int stop = 0;
1734  int j, k, wvratio, current_ratio;
1735  char putstring[128], tmpstr[16];
1736 
1737  /* if you're flying, you can't pick up anything */
1738  if (op->move_type&MOVE_FLYING)
1739  return 1;
1740  /* If not a player, don't check anything. */
1741  if (!op->contr) {
1742  return 1;
1743  }
1744 
1745  op_tag = op->count;
1746 
1747  FOR_BELOW_PREPARE(op, tmp) {
1748  if (object_was_destroyed(op, op_tag))
1749  return 0;
1750 
1751  if (!object_can_pick(op, tmp))
1752  continue;
1753 
1754  if (op->contr->search_str[0] != '\0' && settings.search_items == TRUE) {
1755  if (object_matches_string(op, tmp, op->contr->search_str))
1756  pick_up(op, tmp);
1757  continue;
1758  }
1759 
1760  /* high not bit set? We're using the old autopickup model */
1761  if (!(op->contr->mode&PU_NEWMODE)) {
1762  switch (op->contr->mode) {
1763  case 0:
1764  return 1; /* don't pick up */
1765 
1766  case 1:
1767  pick_up(op, tmp);
1768  return 1;
1769 
1770  case 2:
1771  pick_up(op, tmp);
1772  return 0;
1773 
1774  case 3:
1775  return 0; /* stop before pickup */
1776 
1777  case 4:
1778  pick_up(op, tmp);
1779  break;
1780 
1781  case 5:
1782  pick_up(op, tmp);
1783  stop = 1;
1784  break;
1785 
1786  case 6:
1787  if (QUERY_FLAG(tmp, FLAG_KNOWN_MAGICAL)
1788  && !QUERY_FLAG(tmp, FLAG_KNOWN_CURSED))
1789  pick_up(op, tmp);
1790  break;
1791 
1792  case 7:
1793  if (tmp->type == MONEY || tmp->type == GEM)
1794  pick_up(op, tmp);
1795  break;
1796 
1797  default:
1798  /* use value density */
1799  if (!QUERY_FLAG(tmp, FLAG_UNPAID)
1800  && (price_base(tmp)*100/(tmp->weight*MAX(tmp->nrof, 1))) >= op->contr->mode)
1801  pick_up(op, tmp);
1802  }
1803  } else { /* old model */
1804  /* NEW pickup handling */
1805  if (op->contr->mode&PU_DEBUG) {
1806  /* some debugging code to figure out item information */
1808  "item name: %s item type: %d weight/value: %d",
1809  tmp->name ? tmp->name : tmp->arch->name, tmp->type,
1810  (int)(price_base(tmp)*100/(tmp->weight*MAX(tmp->nrof, 1))));
1811 
1812 
1813  snprintf(putstring, sizeof(putstring), "...flags: ");
1814  for (k = 0; k < 4; k++) {
1815  for (j = 0; j < 32; j++) {
1816  if ((tmp->flags[k]>>j)&0x01) {
1817  snprintf(tmpstr, sizeof(tmpstr), "%d ", k*32+j);
1818  strcat(putstring, tmpstr);
1819  }
1820  }
1821  }
1823  putstring);
1824  }
1825  /* philosophy:
1826  * It's easy to grab an item type from a pile, as long as it's
1827  * generic. This takes no game-time. For more detailed pickups
1828  * and selections, select-items should be used. This is a
1829  * grab-as-you-run type mode that's really useful for arrows for
1830  * example.
1831  * The drawback: right now it has no frontend, so you need to
1832  * stick the bits you want into a calculator in hex mode and then
1833  * convert to decimal and then 'pickup <#>
1834  */
1835 
1836  /* the first two modes are exclusive: if NOTHING we return, if
1837  * STOP then we stop. All the rest are applied sequentially,
1838  * meaning if any test passes, the item gets picked up. */
1839 
1840  /* if mode is set to pick nothing up, return */
1841 
1842  if (op->contr->mode == PU_NOTHING)
1843  return 1;
1844 
1845  /* if mode is set to stop when encountering objects, return.
1846  * Take STOP before INHIBIT since it doesn't actually pick
1847  * anything up */
1848 
1849  if (op->contr->mode&PU_STOP)
1850  return 0;
1851 
1852  /* useful for going into stores and not losing your settings... */
1853  /* and for battles where you don't want to get loaded down while
1854  * fighting */
1855  if (op->contr->mode&PU_INHIBIT)
1856  return 1;
1857 
1858  /* prevent us from turning into auto-thieves :) */
1859  if (QUERY_FLAG(tmp, FLAG_UNPAID))
1860  continue;
1861 
1862  /* ignore known cursed objects */
1864  continue;
1865 
1866  static int checks[] = {
1867  PU_FOOD,
1868  PU_DRINK,
1869  PU_FLESH,
1870  PU_POTION,
1871  PU_SPELLBOOK,
1873  PU_READABLES,
1875  PU_MAGICAL,
1876  PU_VALUABLES,
1877  PU_JEWELS,
1878  PU_BOW,
1879  PU_ARROW,
1880  PU_ARMOUR,
1881  PU_HELMET,
1882  PU_SHIELD,
1883  PU_BOOTS,
1884  PU_GLOVES,
1885  PU_CLOAK,
1888  PU_KEY,
1889  PU_CONTAINER,
1890  PU_CURSED,
1891  0
1892  };
1893  int found = 0;
1894  for (int m = 0; checks[m] != 0; m++) {
1895  if (op->contr->mode & checks[m] && object_matches_pickup_mode(tmp, checks[m])) {
1896  pick_up(op, tmp);
1897  found = 1;
1898  break;
1899  }
1900  }
1901  if (found) {
1902  continue;
1903  }
1904 
1905  /* any of the last 4 bits set means we use the ratio for value
1906  * pickups */
1907  if (op->contr->mode&PU_RATIO) {
1908  /* use value density to decide what else to grab.
1909  * >=7 was >= op->contr->mode
1910  * >=7 is the old standard setting. Now we take the last 4 bits
1911  * and multiply them by 5, giving 0..15*5== 5..75 */
1912  wvratio = (op->contr->mode&PU_RATIO)*5;
1913  current_ratio = price_base(tmp)*100/(tmp->weight*MAX(tmp->nrof, 1));
1914  if (current_ratio >= wvratio) {
1915  pick_up(op, tmp);
1916  continue;
1917  }
1918  }
1919  } /* the new pickup model */
1920  } FOR_BELOW_FINISH();
1921  return !stop;
1922 }
1923 
1936 static object *find_arrow(object *op, const char *type) {
1937  object *tmp = NULL;
1938 
1939  FOR_INV_PREPARE(op, inv)
1940  if (!tmp
1941  && inv->type == CONTAINER
1942  && inv->race == type
1943  && QUERY_FLAG(inv, FLAG_APPLIED))
1944  tmp = find_arrow(inv, type);
1945  else if (inv->type == ARROW && inv->race == type)
1946  return inv;
1947  FOR_INV_FINISH();
1948  return tmp;
1949 }
1950 
1968 static object *find_better_arrow(object *op, object *target, const char *type, int *better) {
1969  object *tmp = NULL, *ntmp;
1970  int attacknum, attacktype, betterby = 0, i;
1971 
1972  if (!type)
1973  return NULL;
1974 
1975  FOR_INV_PREPARE(op, arrow) {
1976  if (arrow->type == CONTAINER
1977  && arrow->race == type
1978  && QUERY_FLAG(arrow, FLAG_APPLIED)) {
1979  i = 0;
1980  ntmp = find_better_arrow(arrow, target, type, &i);
1981  if (i > betterby) {
1982  tmp = ntmp;
1983  betterby = i;
1984  }
1985  } else if (arrow->type == ARROW && arrow->race == type) {
1986  /* always prefer assassination/slaying */
1987  if (target->race != NULL
1988  && arrow->slaying != NULL
1989  && strstr(arrow->slaying, target->race)) {
1990  if (arrow->attacktype&AT_DEATH) {
1991  if (better)
1992  *better = 100;
1993  return arrow;
1994  } else {
1995  tmp = arrow;
1996  betterby = (arrow->magic+arrow->stats.dam)*2;
1997  }
1998  } else {
1999  for (attacknum = 0; attacknum < NROFATTACKS; attacknum++) {
2000  attacktype = 1<<attacknum;
2001  if ((arrow->attacktype&attacktype) && (target->arch->clone.resist[attacknum]) < 0)
2002  if (((arrow->magic+arrow->stats.dam)*(100-target->arch->clone.resist[attacknum])/100) > betterby) {
2003  tmp = arrow;
2004  betterby = (arrow->magic+arrow->stats.dam)*(100-target->arch->clone.resist[attacknum])/100;
2005  }
2006  }
2007  if ((2+arrow->magic+arrow->stats.dam) > betterby) {
2008  tmp = arrow;
2009  betterby = 2+arrow->magic+arrow->stats.dam;
2010  }
2011  if (arrow->title && (1+arrow->magic+arrow->stats.dam) > betterby) {
2012  tmp = arrow;
2013  betterby = 1+arrow->magic+arrow->stats.dam;
2014  }
2015  }
2016  }
2017  } FOR_INV_FINISH();
2018  if (tmp == NULL)
2019  return find_arrow(op, type);
2020 
2021  if (better)
2022  *better = betterby;
2023  return tmp;
2024 }
2025 
2038 static object *pick_arrow_target(object *op, const char *type, int dir) {
2039  object *tmp = NULL;
2040  mapstruct *m;
2041  int i, mflags, found, number;
2042  int16_t x, y;
2043 
2044  if (op->map == NULL)
2045  return find_arrow(op, type);
2046 
2047  /* do a dex check */
2048  number = (die_roll(2, 40, op, PREFER_LOW)-2)/2;
2049  if (number > (op->stats.Dex+(op->chosen_skill ? op->chosen_skill->level : op->level)))
2050  return find_arrow(op, type);
2051 
2052  m = op->map;
2053  x = op->x;
2054  y = op->y;
2055 
2056  /* find the first target */
2057  for (i = 0, found = 0; i < 20; i++) {
2058  x += freearr_x[dir];
2059  y += freearr_y[dir];
2060  mflags = get_map_flags(m, &m, x, y, &x, &y);
2061  if (mflags&P_OUT_OF_MAP || mflags&P_BLOCKSVIEW) {
2062  tmp = NULL;
2063  break;
2064  } else if (GET_MAP_MOVE_BLOCK(m, x, y) == MOVE_FLY_LOW) {
2065  /* This block presumes arrows and the like are MOVE_FLY_SLOW -
2066  * perhaps a bad assumption.
2067  */
2068  tmp = NULL;
2069  break;
2070  }
2071  if (mflags&P_IS_ALIVE) {
2072  FOR_MAP_PREPARE(m, x, y, tmp2)
2073  if (QUERY_FLAG(tmp2, FLAG_ALIVE)) {
2074  tmp = tmp2;
2075  found++;
2076  break;
2077  }
2078  FOR_MAP_FINISH();
2079  if (found)
2080  break;
2081  }
2082  }
2083  if (tmp == NULL)
2084  return find_arrow(op, type);
2085 
2086  return find_better_arrow(op, HEAD(tmp), type, NULL);
2087 }
2088 
2107 int fire_bow(object *op, object *arrow, int dir, int wc_mod, int16_t sx, int16_t sy) {
2108  object *bow;
2109  tag_t tag;
2110  int bowspeed, mflags;
2111  mapstruct *m;
2112 
2113  if (!dir) {
2115  "You can't shoot yourself!");
2116  return 0;
2117  }
2118  if (op->type == PLAYER) {
2119  bow = op->contr->ranges[range_bow];
2120  // Make sure the bow's skill is readied.
2121  // Otherwise, you can get wrong modifiers from unarmed attacks
2122  // because that ends up the readied skill.
2123  object *skill = find_skill_by_name(op, bow->skill);
2124  if (skill && change_skill(op, skill, 1) == 0) {
2126  "You cannot use %s without the skill %s", bow->name, bow->skill);
2127  return 0;
2128  }
2129  }
2130  else {
2131  /* Don't check for applied - monsters don't apply bows - in that way, they
2132  * don't need to switch back and forth between bows and weapons.
2133  */
2134  bow = object_find_by_type(op, BOW);
2135  if (!bow) {
2136  LOG(llevError, "Range: bow without activated bow (%s).\n", op->name);
2137  return 0;
2138  }
2139  }
2140  if (!bow->race || !bow->skill) {
2142  "Your %s is broken.",
2143  bow->name);
2144  return 0;
2145  }
2146 
2147  bowspeed = bow->stats.sp+get_dex_bonus(op->stats.Dex);
2148 
2149  /* penalize ROF for bestarrow */
2150  if (op->type == PLAYER && op->contr->bowtype == bow_bestarrow)
2151  bowspeed -= get_dex_bonus(op->stats.Dex)+5;
2152  if (bowspeed < 1)
2153  bowspeed = 1;
2154 
2155  if (arrow == NULL) {
2156  arrow = find_arrow(op, bow->race);
2157  if (arrow == NULL) {
2158  if (op->type == PLAYER)
2161  "You have no %s left.",
2162  bow->race);
2163  /* FLAG_READY_BOW will get reset if the monsters picks up some arrows */
2164  else
2166  return 0;
2167  }
2168  }
2169  mflags = get_map_flags(op->map, &m, sx, sy, &sx, &sy);
2170  if (mflags&P_OUT_OF_MAP) {
2171  return 0;
2172  }
2173  if (GET_MAP_MOVE_BLOCK(m, sx, sy)&MOVE_FLY_LOW) {
2174  return 0;
2175  }
2176 
2177  /* this should not happen, but sometimes does */
2178  if (arrow->nrof == 0) {
2179  object_remove(arrow);
2181  return 0;
2182  }
2183 
2184  arrow = object_split(arrow, 1, NULL, 0);
2185  if (arrow == NULL) {
2187  "You have no %s left.",
2188  bow->race);
2189  return 0;
2190  }
2191  object_set_owner(arrow, op);
2192  if (arrow->skill)
2193  free_string(arrow->skill);
2194  arrow->skill = add_refcount(bow->skill);
2195 
2196  arrow->direction = dir;
2197 
2198  if (op->type == PLAYER) {
2199  op->speed_left = 0.01-(float)FABS(op->speed)*100/bowspeed;
2200  fix_object(op);
2201  }
2202 
2203  if (bow->anim_suffix != NULL)
2204  apply_anim_suffix(op, bow->anim_suffix);
2205 
2206 /* SET_ANIMATION(arrow, arrow->direction);*/
2207  object_update_turn_face(arrow);
2208  arrow->stats.sp = arrow->stats.wc; /* save original wc and dam */
2209  arrow->stats.hp = arrow->stats.dam;
2210  arrow->stats.grace = arrow->attacktype;
2211  if (arrow->slaying != NULL)
2212  arrow->spellarg = strdup_local(arrow->slaying);
2213 
2214  /* Note that this was different for monsters - they got their level
2215  * added to the damage. I think the strength bonus is more proper.
2216  */
2217 
2218  arrow->stats.dam += (QUERY_FLAG(bow, FLAG_NO_STRENGTH) ? 0 : get_dam_bonus(op->stats.Str))
2219  +bow->stats.dam
2220  +bow->magic
2221  +arrow->magic;
2222 
2223  /* update the speed */
2224  arrow->speed = (float)((QUERY_FLAG(bow, FLAG_NO_STRENGTH) ? 0 : get_dam_bonus(op->stats.Str))+bow->magic+arrow->magic)/5.0
2225  +(float)bow->stats.dam/7.0;
2226 
2227  if (arrow->speed < 1.0)
2228  arrow->speed = 1.0;
2229  object_update_speed(arrow);
2230  arrow->speed_left = 0;
2231 
2232  if (op->type == PLAYER) {
2233  /* we don't want overflows of wc (sint), so cap the value - mod and pl should be subtracted */
2234  int mod = bow->magic
2235  +arrow->magic
2236  +get_dex_bonus(op->stats.Dex)
2237  +get_thaco_bonus(op->stats.Str)
2238  +arrow->stats.wc
2239  +bow->stats.wc
2240  -wc_mod;
2241  int plmod = (op->chosen_skill ? op->chosen_skill->level : op->level);
2242  if (plmod+mod > 140)
2243  plmod = 140-mod;
2244  else if (plmod+mod < -100)
2245  plmod = -100-mod;
2246  arrow->stats.wc = 20-(int8_t)plmod-(int8_t)mod;
2247 
2248  arrow->level = op->chosen_skill ? op->chosen_skill->level : op->level;
2249  } else {
2250  arrow->stats.wc = op->stats.wc
2251  -bow->magic
2252  -arrow->magic
2253  -arrow->stats.wc
2254  +wc_mod;
2255 
2256  arrow->level = op->level;
2257  }
2258  if (arrow->attacktype == AT_PHYSICAL)
2259  arrow->attacktype |= bow->attacktype;
2260  if (bow->slaying != NULL)
2261  arrow->slaying = add_string(bow->slaying);
2262 
2263  /* If move_type is ever changed, monster.c:monster_use_bow() needs to be changed too. */
2264  arrow->move_type = MOVE_FLY_LOW;
2265  arrow->move_on = MOVE_FLY_LOW|MOVE_WALK;
2266 
2267  tag = arrow->count;
2268  object_insert_in_map_at(arrow, m, op, 0, sx, sy);
2269 
2270  if (!object_was_destroyed(arrow, tag)) {
2271  play_sound_map(SOUND_TYPE_ITEM, arrow, arrow->direction, "fire");
2272  ob_process(arrow);
2273  }
2274 
2275  return 1;
2276 }
2277 
2288 static int similar_direction(int a, int b) {
2289  /* shortcut the obvious */
2290  if (a == b)
2291  return 1;
2292  /* Made this cleaner using modulus instead of a switch statement
2293  * We only needed the direction and the two adjacent to it
2294  * (8 is adjacent to 1 here) to return true, so a - 1, a, and a + 1
2295  * are the three directions that get "similar" affirmed.
2296  * -- Neila Hawkins 2015-05-28
2297  */
2298  // The last one for the offset is added afterwards so we get
2299  // 1-8 instead of 0-7 (specifically, 0 becomes 8 without changing
2300  // the other values).
2301  if ((a % 8) + 1 == b || (a + 6 % 8) + 1 == b)
2302  return 1;
2303  return 0;
2304 }
2305 
2322 static int player_fire_bow(object *op, int dir) {
2323  int ret = 0, wcmod = 0;
2324 
2325  if (op->contr->bowtype == bow_bestarrow) {
2326  ret = fire_bow(op, pick_arrow_target(op, op->contr->ranges[range_bow]->race, dir), dir, 0, op->x, op->y);
2327  } else if (op->contr->bowtype >= bow_n && op->contr->bowtype <= bow_nw) {
2328  if (!similar_direction(dir, op->contr->bowtype-bow_n+1))
2329  wcmod = -1;
2330  ret = fire_bow(op, NULL, op->contr->bowtype-bow_n+1, wcmod, op->x, op->y);
2331  } else if (op->contr->bowtype == bow_threewide) {
2332  ret = fire_bow(op, NULL, dir, 0, op->x, op->y);
2333  ret |= fire_bow(op, NULL, dir, -5, op->x+freearr_x[absdir(dir+2)], op->y+freearr_y[absdir(dir+2)]);
2334  ret |= fire_bow(op, NULL, dir, -5, op->x+freearr_x[absdir(dir-2)], op->y+freearr_y[absdir(dir-2)]);
2335  } else if (op->contr->bowtype == bow_spreadshot) {
2336  ret |= fire_bow(op, NULL, dir, 0, op->x, op->y);
2337  ret |= fire_bow(op, NULL, absdir(dir-1), -5, op->x, op->y);
2338  ret |= fire_bow(op, NULL, absdir(dir+1), -5, op->x, op->y);
2339  } else {
2340  /* Simple case */
2341  ret = fire_bow(op, NULL, dir, 0, op->x, op->y);
2342  }
2343  return ret;
2344 }
2345 
2358 static void fire_misc_object(object *op, int dir) {
2359  object *item;
2360  char name[MAX_BUF];
2361 
2362  item = op->contr->ranges[range_misc];
2363  if (!item) {
2365  "You have no range item readied.");
2366  return;
2367  }
2368  if (!item->inv) {
2369  LOG(llevError, "Object %s lacks a spell\n", item->name);
2370  return;
2371  }
2372  if (item->type == WAND) {
2373  if (item->stats.food <= 0) {
2374  play_sound_player_only(op->contr, SOUND_TYPE_ITEM, item, 0, "poof");
2375  query_base_name(item, 0, name, MAX_BUF);
2377  "The %s goes poof.",
2378  name);
2379  return;
2380  }
2381  } else if (item->type == ROD) {
2382  if (item->stats.hp < SP_level_spellpoint_cost(item, item->inv, SPELL_HIGHEST)) {
2383  play_sound_player_only(op->contr, SOUND_TYPE_ITEM, item, 0, "poof");
2384  query_base_name(item, 0, name, MAX_BUF);
2386  "The %s whines for a while, but nothing happens.",
2387  name);
2388  return;
2389  }
2390  }
2391 
2392  if (cast_spell(op, item, dir, item->inv, NULL)) {
2393  SET_FLAG(op, FLAG_BEEN_APPLIED); /* You now know something about it */
2394  if (item->type == WAND) {
2395  drain_wand_charge(item);
2396  } else if (item->type == ROD) {
2397  drain_rod_charge(item);
2398  }
2399  }
2400 }
2401 
2410 void fire(object *op, int dir) {
2411 
2412  /* check for loss of invisiblity/hide */
2413  if (action_makes_visible(op))
2414  make_visible(op);
2415 
2416  switch (op->contr->shoottype) {
2417  case range_none:
2418  return;
2419 
2420  case range_bow:
2421  player_fire_bow(op, dir);
2422  return;
2423 
2424  case range_magic: /* Casting spells */
2425  cast_spell(op, op, dir, op->contr->ranges[range_magic], op->contr->spellparam[0] ? op->contr->spellparam : NULL);
2426  return;
2427 
2428  case range_misc:
2429  fire_misc_object(op, dir);
2430  return;
2431 
2432  case range_golem: /* Control summoned monsters from scrolls */
2433  if (op->contr->ranges[range_golem] == NULL
2434  || op->contr->golem_count != op->contr->ranges[range_golem]->count) {
2435  op->contr->ranges[range_golem] = NULL;
2436  op->contr->shoottype = range_none;
2437  op->contr->golem_count = 0;
2438  } else
2440  return;
2441 
2442  case range_skill:
2443  if (!op->chosen_skill) {
2444  if (op->type == PLAYER)
2446  "You have no applicable skill to use.");
2447  return;
2448  }
2449  (void)do_skill(op, op, op->chosen_skill, dir, NULL);
2450  return;
2451 
2452  case range_builder:
2453  apply_map_builder(op, dir);
2454  return;
2455 
2456  default:
2458  "Illegal shoot type.");
2459  return;
2460  }
2461 }
2462 
2482 object *find_key(object *pl, object *container, object *door) {
2483  object *tmp, *key;
2484 
2485  /* Should not happen, but sanity checking is never bad */
2486  if (container->inv == NULL)
2487  return NULL;
2488 
2489  /* First, lets try to find a key in the top level inventory */
2490  tmp = NULL;
2491  if (door->type == DOOR) {
2492  int flag = FLAG_UNPAID;
2493  tmp = object_find_by_type_without_flags(container, KEY, &flag, 1);
2494  }
2495  /* For sanity, we should really check door type, but other stuff
2496  * (like containers) can be locked with special keys
2497  */
2498  if (!tmp && door->slaying != NULL) {
2499  tmp = object_find_by_type_and_slaying(container, SPECIAL_KEY, door->slaying);
2500  }
2501  /* No key found - lets search inventories now */
2502  /* If we find and use a key in an inventory, return at that time.
2503  * otherwise, if we search all the inventories and still don't find
2504  * a key, return
2505  */
2506  if (!tmp) {
2507  FOR_INV_PREPARE(container, tmp) {
2508  /* No reason to search empty containers */
2509  if (tmp->type == CONTAINER && tmp->inv) {
2510  key = find_key(pl, tmp, door);
2511  if (key != NULL)
2512  return key;
2513  }
2514  } FOR_INV_FINISH();
2515  return NULL;
2516  }
2517  /* We get down here if we have found a key. Now if its in a container,
2518  * see if we actually want to use it
2519  */
2520  if (pl != container) {
2521  /* Only let players use keys in containers */
2522  if (!pl->contr)
2523  return NULL;
2524  /* cases where this fails:
2525  * If we only search the player inventory, return now since we
2526  * are not in the players inventory.
2527  * If the container is not active, return now since only active
2528  * containers can be used.
2529  * If we only search keyrings and the container does not have
2530  * a race/isn't a keyring.
2531  * No checking for all containers - to fall through past here,
2532  * inv must have been an container and must have been active.
2533  *
2534  * Change the color so that the message doesn't disappear with
2535  * all the others.
2536  */
2537  if (pl->contr->usekeys == key_inventory
2538  || !QUERY_FLAG(container, FLAG_APPLIED)
2539  || (pl->contr->usekeys == keyrings && (!container->race || strcmp(container->race, "keys")))) {
2540  char name_tmp[MAX_BUF], name_cont[MAX_BUF];
2541 
2542  query_name(tmp, name_tmp, MAX_BUF);
2543  query_name(container, name_cont, MAX_BUF);
2546  "The %s in your %s vibrates as you approach the door",
2547  name_tmp, name_cont);
2548  return NULL;
2549  }
2550  }
2551  return tmp;
2552 }
2553 
2564 static int player_attack_door(object *op, object *door) {
2565  /* If its a door, try to find a use a key. If we do destroy the door,
2566  * might as well return immediately as there is nothing more to do -
2567  * otherwise, we fall through to the rest of the code.
2568  */
2569  object *key = find_key(op, op, door);
2570 
2571  assert(door->type == DOOR || door->type == LOCKED_DOOR);
2572 
2573  /* IF we found a key, do some extra work */
2574  if (key) {
2575  char name[HUGE_BUF];
2576 
2577  play_sound_map(SOUND_TYPE_GROUND, door, 0, "open");
2578  if (action_makes_visible(op))
2579  make_visible(op);
2580  if (door->inv && (door->inv->type == RUNE || door->inv->type == TRAP))
2581  spring_trap(door->inv, op);
2582 
2586  "You open the door with the %s",
2587  name);
2588 
2589  if (door->type == DOOR)
2590  remove_door(door);
2591  else
2592  remove_locked_door(door); /* remove door without violence ;-) */
2593 
2594  /* Do this after we print the message */
2595  object_decrease_nrof_by_one(key); /* Use up one of the keys */
2596 
2597  return 1; /* Nothing more to do below */
2598 
2599  }
2600 
2601  if (door->type == LOCKED_DOOR) {
2602  /* Might as well return now - no other way to open this */
2603  if (door->msg && *door->msg) {
2605  door->msg);
2606  }
2607  return 1;
2608  }
2609 
2610  if (door->type == DOOR && op->contr && !op->contr->run_on) {
2611  /* Player so try to pick the door */
2612  object *lock = find_skill_by_name(op, "lockpicking");
2613  if (lock) {
2614  /* Even if the lockpicking failed, don't go on moving, player should explicitely attack or run
2615  * to bash the door. */
2616  do_skill(op, op, lock, op->facing, NULL);
2617  return 1;
2618  }
2619  }
2620 
2621  return 0;
2622 }
2623 
2637 void move_player_attack(object *op, int dir) {
2638  object *mon, *tpl, *mon_owner;
2639  int16_t nx, ny;
2640  int on_battleground;
2641  mapstruct *m;
2642 
2643  if (op->contr->transport)
2644  tpl = op->contr->transport;
2645  else
2646  tpl = op;
2647  assert(tpl->map != NULL); // op must be on a map in order to move it
2648  nx = freearr_x[dir]+tpl->x;
2649  ny = freearr_y[dir]+tpl->y;
2650 
2651  on_battleground = op_on_battleground(tpl, NULL, NULL, NULL);
2652 
2653  // Temporarily store the map we are on before movement.
2654  mapstruct *bef = tpl->map;
2655 
2656  /* If braced, or can't move to the square, and it is not out of the
2657  * map, attack it. Note order of if statement is important - don't
2658  * want to be calling move_ob if braced, because move_ob will move the
2659  * player. This is a pretty nasty hack, because if we could
2660  * move to some space, it then means that if we are braced, we should
2661  * do nothing at all. As it is, if we are braced, we go through
2662  * quite a bit of processing. However, it probably is less than what
2663  * move_ob uses.
2664  */
2665  if ((op->contr->braced || !move_ob(tpl, dir, tpl)) && !out_of_map(tpl->map, nx, ny)) {
2666  if (OUT_OF_REAL_MAP(tpl->map, nx, ny)) {
2667  m = get_map_from_coord(tpl->map, &nx, &ny);
2668  if (!m)
2669  return; /* Don't think this should happen */
2670  } else
2671  m = tpl->map;
2672 
2673  if (GET_MAP_OB(m, nx, ny) == NULL) {
2674  /* LOG(llevError, "player_move_attack: GET_MAP_OB returns NULL, but player can not move there.\n");*/
2675  return;
2676  }
2677 
2678  mon = NULL;
2679  /* Go through all the objects, and find ones of interest. Only stop if
2680  * we find a monster - that is something we know we want to attack.
2681  * if its a door or barrel (can roll) see if there may be monsters
2682  * on the space
2683  */
2684  FOR_MAP_PREPARE(m, nx, ny, tmp) {
2685  if (tmp == op) {
2686  continue;
2687  }
2688  if (QUERY_FLAG(tmp, FLAG_ALIVE)) {
2689  mon = tmp;
2690  /* Gros: Objects like (pass-through) doors are alive, but haven't
2691  * their monster flag set - so this is a good way attack real
2692  * monsters in priority.
2693  */
2694  if (QUERY_FLAG(tmp, FLAG_MONSTER))
2695  break;
2696  }
2697  if (tmp->type == LOCKED_DOOR || QUERY_FLAG(tmp, FLAG_CAN_ROLL))
2698  mon = tmp;
2699  } FOR_MAP_FINISH();
2700 
2701  if (mon == NULL) /* This happens anytime the player tries to move */
2702  return; /* into a wall */
2703 
2704  mon = HEAD(mon);
2705  if ((mon->type == DOOR && mon->stats.hp >= 0) || (mon->type == LOCKED_DOOR))
2706  if (player_attack_door(op, mon))
2707  return;
2708 
2709  /* The following deals with possibly attacking peaceful
2710  * or friendly creatures. Basically, all players are considered
2711  * unaggressive. If the moving player has peaceful set, then the
2712  * object should be pushed instead of attacked. It is assumed that
2713  * if you are braced, you will not attack friends accidently,
2714  * and thus will not push them.
2715  */
2716 
2717  /* If the creature is a pet, push it even if the player is not
2718  * peaceful. Our assumption is the creature is a pet if the
2719  * player owns it and it is either friendly or unaggressive.
2720  */
2721  mon_owner = object_get_owner(mon);
2722  if ((op->type == PLAYER)
2723  && (mon_owner == op || (mon_owner != NULL && mon_owner->type == PLAYER && mon_owner->contr->party != NULL && mon_owner->contr->party == op->contr->party))
2724  && (QUERY_FLAG(mon, FLAG_UNAGGRESSIVE) || QUERY_FLAG(mon, FLAG_FRIENDLY))) {
2725  /* If we're braced, we don't want to switch places with it */
2726  if (op->contr->braced)
2727  return;
2728  play_sound_map(SOUND_TYPE_LIVING, mon, dir, "push");
2729  (void)push_ob(mon, dir, op);
2730  if (op->contr->tmp_invis || op->hide)
2731  make_visible(op);
2732  return;
2733  }
2734 
2735  /* in certain circumstances, you shouldn't attack friendly
2736  * creatures. Note that if you are braced, you can't push
2737  * someone, but put it inside this loop so that you won't
2738  * attack them either.
2739  */
2740  if ((mon->type == PLAYER || mon->enemy != op)
2741  && (mon->type == PLAYER || QUERY_FLAG(mon, FLAG_UNAGGRESSIVE) || QUERY_FLAG(mon, FLAG_FRIENDLY))
2742  && (op->contr->peaceful && !on_battleground)) {
2743  if (!op->contr->braced) {
2744  play_sound_map(SOUND_TYPE_LIVING, mon, dir, "push");
2745  (void)push_ob(mon, dir, op);
2746  } else {
2748  "You withhold your attack");
2749  }
2750  if (op->contr->tmp_invis || op->hide)
2751  make_visible(op);
2752  }
2753 
2754  /* If the object is a boulder or other rollable object, then
2755  * roll it if not braced. You can't roll it if you are braced.
2756  */
2757  else if (QUERY_FLAG(mon, FLAG_CAN_ROLL) && (!op->contr->braced)) {
2758  recursive_roll(mon, dir, op);
2759  if (action_makes_visible(op))
2760  make_visible(op);
2761 
2762  /* Any generic living creature. Including things like doors.
2763  * Way it works is like this: First, it must have some hit points
2764  * and be living. Then, it must be one of the following:
2765  * 1) Not a player, 2) A player, but of a different party. Note
2766  * that party_number -1 is no party, so attacks can still happen.
2767  */
2768  } else if ((mon->stats.hp >= 0)
2769  && QUERY_FLAG(mon, FLAG_ALIVE)
2770  && ((mon->type != PLAYER || op->contr->party == NULL || op->contr->party != mon->contr->party))) {
2771  /* If the player hasn't hit something this tick, and does
2772  * so, give them speed boost based on weapon speed. Doing
2773  * it here is better than process_players2, which basically
2774  * incurred a 1 tick offset.
2775  */
2776  if (op->weapon_speed_left < 0) {
2777  op->speed_left = -0.01;
2778  return;
2779  }
2780  op->weapon_speed_left -= 1.0;
2781 
2782  skill_attack(mon, op, 0, NULL, NULL);
2783 
2784  /* If attacking another player, that player gets automatic
2785  * hitback, and doesn't loose luck either.
2786  * Disable hitback on the battleground or if the target is
2787  * the wiz.
2788  */
2789  if (mon->type == PLAYER
2790  && mon->stats.hp >= 0
2791  && !mon->contr->has_hit
2792  && !on_battleground
2793  && !QUERY_FLAG(mon, FLAG_WIZ)) {
2794  short luck = mon->stats.luck;
2795  mon->contr->has_hit = 1;
2796  skill_attack(op, mon, 0, NULL, NULL);
2797  mon->stats.luck = luck;
2798  }
2799  if (action_makes_visible(op))
2800  make_visible(op);
2801  }
2802  } /* if player should attack something */
2803  else if (bef != tpl->map) {
2804  player_map_change_common(op, bef, tpl->map);
2805  }
2806 }
2807 
2814 static void update_transport_block(object *transport, int dir) {
2815  object *part;
2816  int sx, sy, x, y;
2817 
2818  object_get_multi_size(transport, &sx, &sy, NULL, NULL);
2819  assert(sx == sy);
2820 
2821  if (dir == 1 || dir == 5) {
2822  part = transport;
2823  for (y = 0; y <= sy; y++) {
2824  for (x = 0; x < sx; x++) {
2825  part->move_type = transport->move_type;
2826  part = part->more;
2827  }
2828  part->move_type = 0;
2829  part = part->more;
2830  }
2831  } else if (dir == 3 || dir == 7) {
2832  part = transport;
2833  for (y = 0; y < sy; y++) {
2834  for (x = 0; x <= sx; x++) {
2835  part->move_type = transport->move_type;
2836  part = part->more;
2837  }
2838  }
2839  while (part) {
2840  part->move_type = 0;
2841  part = part->more;
2842  }
2843  } else {
2844  for (part = transport; part; part = part->more) {
2845  part->move_type = transport->move_type;
2846  }
2847  }
2848 }
2849 
2859 static int turn_one_transport(object *transport, object *captain, int dir) {
2860  int x, y, scroll_dir = 0;
2861 
2862  assert(transport->type == TRANSPORT);
2863 
2864  x = transport->x;
2865  y = transport->y;
2866 
2867  if (transport->direction == 1 && dir == 8) {
2868  x--;
2869  } else if (transport->direction == 2 && dir == 3) {
2870  y++;
2871  } else if (transport->direction == 3 && dir == 2) {
2872  y--;
2873  } else if (transport->direction == 5 && dir == 6) {
2874  x--;
2875  } else if (transport->direction == 6 && dir == 5) {
2876  x++;
2877  } else if (transport->direction == 7 && dir == 8) {
2878  y--;
2879  } else if (transport->direction == 8 && dir == 7) {
2880  y++;
2881  } else if (transport->direction == 8 && dir == 1) {
2882  x++;
2883  }
2884 
2885  update_transport_block(transport, dir);
2886  object_remove(transport);
2887  if (ob_blocked(transport, transport->map, x, y)) {
2888  update_transport_block(transport, transport->direction);
2889  object_insert_in_map_at(transport, transport->map, NULL, 0, x, y);
2890  return 2;
2891  }
2892 
2893  if (x != transport->x || y != transport->y) {
2894 /* assert(scroll_dir != 0);*/
2895 
2896  FOR_INV_PREPARE(transport, pl) {
2897  if (pl->type == PLAYER) {
2898  pl->contr->do_los = 1;
2899  pl->map = transport->map;
2900  pl->x = x;
2901  pl->y = y;
2902  esrv_map_scroll(pl->contr->socket, freearr_x[scroll_dir], freearr_y[scroll_dir]);
2903  pl->contr->socket->update_look = 1;
2904  pl->contr->socket->look_position = 0;
2905  }
2906  } FOR_INV_FINISH();
2907  }
2908 
2909  object_insert_in_map_at(transport, transport->map, NULL, 0, x, y);
2910  transport->direction = dir;
2911  transport->facing = dir;
2912  animate_object(transport, dir);
2913  captain->direction = dir;
2914  return 1;
2915 }
2916 
2929 static int turn_transport(object *transport, object *captain, int dir) {
2930  assert(transport->type == TRANSPORT);
2931 
2932  if (object_value_set(transport, "turnable_transport") == false) {
2933  transport->direction = dir;
2934  transport->facing = dir;
2935  if (QUERY_FLAG(transport, FLAG_ANIMATE)) {
2936  animate_object(transport, dir);
2937  }
2938  captain->direction = dir;
2939  return 0;
2940  }
2941 
2942  if (transport->direction == dir)
2943  return 0;
2944 
2945  if (absdir(transport->direction-dir) > 2)
2946  return turn_one_transport(transport, captain, absdir(transport->direction+1));
2947  else
2948  return turn_one_transport(transport, captain, absdir(transport->direction-1));
2949 }
2950 
2962 int move_player(object *op, int dir) {
2963  object *transport = op->contr->transport; //< Transport player is in
2964 
2965  if (!transport && (op->map == NULL || op->map->in_memory != MAP_IN_MEMORY))
2966  return 0;
2967 
2968  /* Sanity check: make sure dir is valid */
2969  if ((dir < 0) || (dir >= 9)) {
2970  LOG(llevError, "move_player: invalid direction %d\n", dir);
2971  return 0;
2972  }
2973 
2974  if (QUERY_FLAG(op, FLAG_CONFUSED) && dir)
2975  dir = get_randomized_dir(dir);
2976 
2977  op->facing = dir;
2978 
2979  if (transport) {
2980  /* transport->contr is set up for the person in charge of the boat.
2981  * if that isn't this person, he can't steer it, etc
2982  */
2983  if (transport->contr != op->contr)
2984  return 0;
2985 
2986  /* Transport is out of movement. But update dir so it at least
2987  * will point in the same direction if player is running.
2988  */
2989  if (transport->speed_left < 0.0) {
2990  return 0;
2991  }
2992  /* Remove transport speed. Give player just a little speed -
2993  * enough so that they will get an action again quickly.
2994  */
2995  transport->speed_left -= 1.0;
2996  if (op->speed_left < 0.0)
2997  op->speed_left = -0.01;
2998 
2999  int turn = turn_transport(transport, op, dir);
3000  if (turn != 0)
3001  return 0;
3002  } else {
3003  if (op->hide) {
3004  do_hidden_move(op);
3005  }
3006 
3007  /* it is important to change the animation now, as fire or move_player_attack can start a compound animation,
3008  * and leave us with state = 0, which we don't want to change again. */
3009  op->state++; /* player moved, so change animation. */
3010  animate_object(op, op->facing);
3011  }
3012 
3013  if (op->contr->fire_on) {
3014  fire(op, dir);
3015  } else
3016  move_player_attack(op, dir);
3017 
3018  int pick = check_pick(op);
3019 
3020  /* Add special check for newcs players and fire on - this way, the
3021  * server can handle repeat firing.
3022  */
3023  if (op->contr->fire_on || (op->contr->run_on && pick != 0)) {
3024  op->direction = dir;
3025  } else {
3026  op->direction = 0;
3027  }
3028  return 0;
3029 }
3030 
3041 int face_player(object *op, int dir) {
3042  object *transport = op->contr->transport; //< Transport player is in
3043 
3044  if (!transport && (op->map == NULL || op->map->in_memory != MAP_IN_MEMORY))
3045  return 0;
3046 
3047  /* Sanity check: make sure dir is valid */
3048  if ((dir < 0) || (dir >= 9)) {
3049  LOG(llevError, "move_player: invalid direction %d\n", dir);
3050  return 0;
3051  }
3052 
3053  if (QUERY_FLAG(op, FLAG_CONFUSED) && dir)
3054  dir = get_randomized_dir(dir);
3055 
3056  op->facing = dir;
3057 
3058  if (transport) {
3059  /* transport->contr is set up for the person in charge of the boat.
3060  * if that isn't this person, he can't steer it, etc
3061  */
3062  if (transport->contr != op->contr)
3063  return 0;
3064 
3065  turn_transport(transport, op, dir);
3066  } else {
3067  if (op->hide) {
3068  do_hidden_move(op);
3069  }
3070 
3071  /* it is important to change the animation now, as fire or move_player_attack can start a compound animation,
3072  * and leave us with state = 0, which we don't want to change again. */
3073  op->state++; /* player moved, so change animation. */
3074  animate_object(op, op->facing);
3075  }
3076 
3077  /* Add special check for newcs players and fire on - this way, the
3078  * server can handle repeat firing.
3079  */
3080  if (op->contr->fire_on || op->contr->run_on) {
3081  op->direction = dir;
3082  } else {
3083  op->direction = 0;
3084  }
3085  return 0;
3086 }
3087 
3100 int handle_newcs_player(object *op) {
3101  if (op->contr->hidden) {
3102  op->invisible = 1000;
3103  /* the socket code flashes the player visible/invisible
3104  * depending on the value if invisible, so we need to
3105  * alternate it here for it to work correctly.
3106  */
3107  if (pticks&2)
3108  op->invisible--;
3109  } else if (op->invisible && !(QUERY_FLAG(op, FLAG_MAKE_INVIS))) {
3110  op->invisible--;
3111  if (!op->invisible) {
3112  make_visible(op);
3114  "Your invisibility spell runs out.");
3115  }
3116  }
3117 
3118  if (QUERY_FLAG(op, FLAG_SCARED)) {
3119  flee_player(op);
3120  /* If player is still scared, that is his action for this tick */
3121  if (QUERY_FLAG(op, FLAG_SCARED)) {
3122  op->speed_left--;
3123  return 0;
3124  }
3125  }
3126 
3127  /* I've been seeing crashes where the golem has been destroyed, but
3128  * the player object still points to the defunct golem. The code that
3129  * destroys the golem looks correct, and it doesn't always happen, so
3130  * put this in a a workaround to clean up the golem pointer.
3131  */
3132  if (op->contr->ranges[range_golem]
3134  op->contr->ranges[range_golem] = NULL;
3135  op->contr->golem_count = 0;
3136  }
3137 
3138  /*
3139  * If the player has been paralyzed, we unmark the flag and give a message to the player
3140  */
3141  if (QUERY_FLAG(op, FLAG_PARALYZED)) {
3143  // TODO: Is this check necessary? We are in player.c, after all.
3144  if (op->type == PLAYER)
3145  {
3147  "You can stretch your stiff joints once more.");
3148  }
3149  }
3150 
3151  if (op->direction && (op->contr->run_on || op->contr->fire_on)) {
3152  /* All move commands take 1 tick, at least for now */
3153  op->speed_left--;
3154 
3155  /* Instead of all the stuff below, let move_player take care
3156  * of it. Also, some of the skill stuff is only put in
3157  * there, as well as the confusion stuff.
3158  */
3159  move_player(op, op->direction);
3160  if (op->speed_left > 0)
3161  return 1;
3162  else
3163  return 0;
3164  }
3165  return 0;
3166 }
3167 
3178 static int save_life(object *op) {
3179  object *tmp;
3180 
3181  if (!QUERY_FLAG(op, FLAG_LIFESAVE))
3182  return 0;
3183 
3185  if (tmp != NULL) {
3186  char name[MAX_BUF];
3187 
3188  query_name(tmp, name, MAX_BUF);
3189  play_sound_map(SOUND_TYPE_ITEM, tmp, 0, "evaporate");
3191  "Your %s vibrates violently, then evaporates.",
3192  name);
3193  object_remove(tmp);
3196  if (op->stats.hp < 0)
3197  op->stats.hp = op->stats.maxhp;
3198  if (op->stats.food < 0)
3199  op->stats.food = MAX_FOOD;
3200  fix_object(op);
3201  return 1;
3202  }
3203  LOG(llevError, "Error: LIFESAVE set without applied object.\n");
3205  enter_player_savebed(op); /* bring him home. */
3206  return 0;
3207 }
3208 
3221 void remove_unpaid_objects(object *op, object *env, int free_items) {
3223  if (QUERY_FLAG(op, FLAG_UNPAID)) {
3224  object_remove(op);
3225  if (free_items)
3227  else
3228  object_insert_in_map_at(op, env->map, NULL, 0, env->x, env->y);
3229  } else if (op->inv)
3230  remove_unpaid_objects(op->inv, env, free_items);
3232 }
3233 
3251 static const char *gravestone_text(object *op, char *buf2, int len) {
3252  char buf[MAX_BUF];
3253  time_t now = time(NULL);
3254 
3255  strncpy(buf2, " R.I.P.\n\n", len);
3256  if (op->type == PLAYER)
3257  snprintf(buf, sizeof(buf), "%s the %s\n", op->name, op->contr->title);
3258  else
3259  snprintf(buf, sizeof(buf), "%s\n", op->name);
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), "who was in level %d when killed\n", op->level);
3264  else
3265  snprintf(buf, sizeof(buf), "who was in level %d when died.\n\n", op->level);
3266  strncat(buf2, " ", 20-strlen(buf)/2);
3267  strncat(buf2, buf, len-strlen(buf2)-1);
3268  if (op->type == PLAYER) {
3269  snprintf(buf, sizeof(buf), "by %s.\n\n", op->contr->killer);
3270  strncat(buf2, " ", 21-strlen(buf)/2);
3271  strncat(buf2, buf, len-strlen(buf2)-1);
3272  }
3273  strftime(buf, MAX_BUF, "%b %d %Y\n", localtime(&now));
3274  strncat(buf2, " ", 20-strlen(buf)/2);
3275  strncat(buf2, buf, len-strlen(buf2)-1);
3276  return buf2;
3277 }
3278 
3279 static bool starving(object *op) {
3280  return op->stats.food <= 0;
3281 }
3282 
3290 void do_some_living(object *op) {
3291  int last_food = op->stats.food;
3292  int gen_hp, gen_sp, gen_grace;
3293  int rate_hp = 1200;
3294  int rate_sp = 2500;
3295  int rate_grace = 2000;
3296 
3297  if (op->contr->state == ST_PLAYING) {
3298  /* these next three if clauses make it possible to SLOW DOWN
3299  hp/grace/spellpoint regeneration. */
3300  if (op->contr->gen_hp >= 0)
3301  gen_hp = (op->contr->gen_hp+1)*op->stats.maxhp;
3302  else {
3303  gen_hp = op->stats.maxhp;
3304  rate_hp -= rate_hp/2*op->contr->gen_hp;
3305  }
3306  if (op->contr->gen_sp >= 0)
3307  gen_sp = (op->contr->gen_sp+1)*op->stats.maxsp;
3308  else {
3309  gen_sp = op->stats.maxsp;
3310  rate_sp -= rate_sp/2*op->contr->gen_sp;
3311  }
3312  if (op->contr->gen_grace >= 0)
3313  gen_grace = (op->contr->gen_grace+1)*op->stats.maxgrace;
3314  else {
3315  gen_grace = op->stats.maxgrace;
3316  rate_grace -= rate_grace/2*op->contr->gen_grace;
3317  }
3318 
3319  /* Regenerate Spell Points */
3320  if (op->contr->ranges[range_golem] == NULL && --op->last_sp < 0) {
3321  gen_sp = gen_sp*10/MAX(op->contr->gen_sp_armour, 10);
3322  if (op->stats.sp < op->stats.maxsp) {
3323  op->stats.sp++;
3324  /* dms do not consume food */
3325  if (!QUERY_FLAG(op, FLAG_WIZ)) {
3326  op->stats.food--;
3327  if (op->contr->digestion < 0)
3328  op->stats.food += op->contr->digestion;
3329  else if (op->contr->digestion > 0
3330  && random_roll(0, op->contr->digestion, op, PREFER_HIGH))
3331  op->stats.food = last_food;
3332  }
3333  }
3334  op->last_sp = rate_sp/(MAX(gen_sp, 20)+10);
3335  }
3336 
3337  /* Regenerate Grace */
3338  /* I altered this a little - maximum grace is only achieved through prayer -b.t.*/
3339  if (--op->last_grace < 0) {
3340  if (op->stats.grace < op->stats.maxgrace/2)
3341  op->stats.grace++; /* no penalty in food for regaining grace */
3342  op->last_grace = rate_grace/(MAX(gen_grace, 20)+10);
3343  /* wearing stuff doesn't detract from grace generation. */
3344  }
3345 
3346  /* Regenerate Hit Points (unless you are a wraith player) */
3347  if (--op->last_heal < 0 && !is_wraith_pl(op) && !starving(op)) {
3348  if (op->stats.hp < op->stats.maxhp) {
3349  op->stats.hp++;
3350  /* dms do not consume food */
3351  if (!QUERY_FLAG(op, FLAG_WIZ)) {
3352  op->stats.food--;
3353  if (op->contr->digestion < 0)
3354  op->stats.food += op->contr->digestion;
3355  else if (op->contr->digestion > 0
3356  && random_roll(0, op->contr->digestion, op, PREFER_HIGH))
3357  op->stats.food = last_food;
3358  }
3359  }
3360  op->last_heal = rate_hp/(MAX(gen_hp, 20)+10);
3361  }
3362 
3363  /* Digestion */
3364  if (--op->last_eat < 0) {
3365  int bonus = MAX(op->contr->digestion, 0);
3366  int penalty = MAX(-op->contr->digestion, 0);
3367  if (op->contr->gen_hp > 0)
3368  op->last_eat = 25*(1+bonus)/(op->contr->gen_hp+penalty+1);
3369  else
3370  op->last_eat = 25*(1+bonus)/(penalty+1);
3371  /* dms do not consume food */
3372  if (!QUERY_FLAG(op, FLAG_WIZ))
3373  op->stats.food--;
3374  }
3375  }
3376 
3377  // Grab a bite of food if able, starving, and still alive.
3378  if (op->contr->state == ST_PLAYING && starving(op) && op->stats.hp >= 0) {
3379  if (is_wraith_pl(op))
3380  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ITEM, MSG_TYPE_ITEM_REMOVE, "You feel a hunger for living flesh.");
3381  /* Only allow eat if not paralyzed. Otherwise our paralyzed player is "moving" to eat.
3382  * Neila Hawkins 2017-08-23
3383  */
3384  else if (!QUERY_FLAG(op, FLAG_PARALYZED)){
3385  object *flesh = NULL;
3386 
3387  FOR_INV_PREPARE(op, tmp) {
3388  if (!QUERY_FLAG(tmp, FLAG_UNPAID)) {
3389  if (tmp->type == FOOD || tmp->type == DRINK || tmp->type == POISON) {
3391  "You blindly grab for a bite of food.");
3392  apply_manual(op, tmp, 0);
3393  if (op->stats.food >= 0 || op->stats.hp < 0)
3394  break;
3395  } else if (tmp->type == FLESH)
3396  flesh = tmp;
3397  } /* End if paid for object */
3398  } FOR_INV_FINISH(); /* end of for loop */
3399  /* If player is still starving, it means they don't have any food, so
3400  * eat flesh instead.
3401  */
3402  if (op->stats.food < 0 && op->stats.hp >= 0 && flesh) {
3404  "You blindly grab for a bite of food.");
3405  apply_manual(op, flesh, 0);
3406  }
3407  } /* end not wraith and not paralyzed */
3408  else { // Print a message for when the player is starving and paralyzed
3409  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ITEM, MSG_TYPE_ITEM_REMOVE, "Your stomach rumbles, but you can't reach your food.");
3410  } /* end not wraith and is paralyzed */
3411  } /* end if player is starving */
3412 
3413  // Prevent food from going negative, then deal constant hunger damage.
3414  if (starving(op)) {
3415  op->stats.food = 0;
3416  op->stats.hp -= 1;
3417  }
3418 
3419  if (!op->contr->state && !QUERY_FLAG(op, FLAG_WIZ) && (op->stats.hp <= 0))
3420  kill_player(op, NULL);
3421 }
3422 
3429 static void loot_object(object *op) {
3430  object *tmp2;
3431 
3432  if (op->container) { /* close open sack first */
3433  apply_container(op, op->container, AP_NULL);
3434  }
3435 
3436  FOR_INV_PREPARE(op, tmp) {
3437  if (tmp->invisible)
3438  continue;
3439  object_remove(tmp);
3440  tmp->x = op->x,
3441  tmp->y = op->y;
3442  if (tmp->type == CONTAINER) { /* empty container to ground */
3443  loot_object(tmp);
3444  }
3445  if (!QUERY_FLAG(tmp, FLAG_UNIQUE)
3446  && (QUERY_FLAG(tmp, FLAG_STARTEQUIP) || QUERY_FLAG(tmp, FLAG_NO_DROP) || !(RANDOM()%3))) {
3447  if (tmp->nrof > 1) {
3448  tmp2 = object_split(tmp, 1+RANDOM()%(tmp->nrof-1), NULL, 0);
3450  object_insert_in_map_at(tmp, op->map, NULL, 0, op->x, op->y);
3451  } else
3453  } else
3454  object_insert_in_map_at(tmp, op->map, NULL, 0, op->x, op->y);
3455  } FOR_INV_FINISH();
3456 }
3457 
3468 static void restore_player(object *op) {
3469  object *tmp;
3470  archetype *at = find_archetype("poisoning");
3471  if (at != NULL) {
3472  tmp = arch_present_in_ob(at, op);
3473  if (tmp) {
3474  object_remove(tmp);
3477  "Your body feels cleansed");
3478  }
3479  }
3480 
3481  at = find_archetype("confusion");
3482  if (at != NULL) {
3483  tmp = arch_present_in_ob(at, op);
3484  if (tmp) {
3485  object_remove(tmp);
3488  "Your mind feels clearer");
3489  }
3490  }
3491 
3492  cure_disease(op, NULL, NULL); /* remove any disease */
3493 }
3494 
3506 void kill_player(object *op, const object *killer) {
3507  char buf[MAX_BUF];
3508  int x, y;
3509  object *tmp;
3510  archetype *trophy = NULL;
3511 
3512  /* Don't die if the player's life can be saved. */
3513  if (save_life(op)) {
3514  return;
3515  }
3516 
3517  /* If player dies on BATTLEGROUND, no stat/exp loss! For Combat-Arenas
3518  * in cities ONLY!!! It is very important that this doesn't get abused.
3519  * Look at op_on_battleground() for more info --AndreasV
3520  */
3521  if (op_on_battleground(op, &x, &y, &trophy)) {
3522  assert(trophy != NULL);
3524  "You have been defeated in combat!\n"
3525  "Local medics have saved your life...");
3526 
3527  /* restore player */
3528  restore_player(op);
3529 
3530  op->stats.hp = op->stats.maxhp;
3531  if (op->stats.food <= 0)
3532  op->stats.food = MAX_FOOD;
3533 
3534  /* create a bodypart-trophy to make the winner happy */
3535  tmp = arch_to_object(trophy);
3536  if (tmp != NULL) {
3537  snprintf(buf, sizeof(buf), "%s's %s", op->name, tmp->name);
3538  tmp->name = add_string(buf);
3539 
3540  snprintf(buf, sizeof(buf),
3541  "This %s was %s %s the %s, who was defeated at level %d by %s.\n",
3542  tmp->name, tmp->type == FLESH ? "cut off" : "taken from",
3543  op->name, op->contr->title,
3544  (int)(op->level), op->contr->killer);
3545 
3546  object_set_msg(tmp, buf);
3547  tmp->type = 0;
3548  tmp->value = 0;
3549  tmp->material = 0;
3550  tmp->materialname = NULL;
3551  object_insert_in_map_at(tmp, op->map, op, 0, op->x, op->y);
3552  }
3553 
3554  /* teleport defeated player to new destination*/
3555  transfer_ob(op, x, y, 0, NULL);
3556  op->contr->braced = 0;
3557  return;
3558  }
3559 
3560  if (events_execute_object_event(op, EVENT_DEATH, NULL, NULL, NULL, SCRIPT_FIX_ALL) != 0)
3561  return;
3562 
3564  if (starving(op)) {
3565  snprintf(buf, sizeof(buf), "%s starved to death.", op->name);
3566  strcpy(op->contr->killer, "starvation");
3567  } else {
3568  snprintf(buf, sizeof(buf), "%s died.", op->name);
3569  }
3570  play_sound_player_only(op->contr, SOUND_TYPE_LIVING, op, 0, "death");
3571 
3572  if (settings.not_permadeth == TRUE) {
3574  } else {
3576  }
3577 }
3578 
3587 static void kill_player_not_permadeath(object *op) {
3588  int num_stats_lose;
3589  int will_kill_again;
3590  int lost_a_stat;
3591  int z;
3592  object *tmp;
3593  char buf[MAX_BUF];
3594  archetype *at;
3595 
3596  /* Basically two ways to go - remove a stat permanently, or just
3597  * make it depletion. This bunch of code deals with that aspect
3598  * of death.
3599  */
3601  /* If stat loss is permanent, lose one stat only. */
3602  /* Lower level chars don't lose as many stats because they suffer
3603  more if they do. */
3604  /* Higher level characters can afford things such as potions of
3605  restoration, or better, stat potions. So we slug them that
3606  little bit harder. */
3607  /* GD */
3609  num_stats_lose = 1;
3610  else
3611  num_stats_lose = 1+op->level/BALSL_NUMBER_LOSSES_RATIO;
3612  } else {
3613  num_stats_lose = 1;
3614  }
3615  lost_a_stat = 0;
3616 
3617  for (z = 0; z < num_stats_lose; z++) {
3619  int i;
3620 
3621  /* Pick a random stat and take a point off it. Tell the player
3622  * what he lost.
3623  */
3624  i = RANDOM()%7;
3625  change_attr_value(&(op->stats), i, -1);
3627  change_attr_value(&(op->contr->orig_stats), i, -1);
3629  draw_ext_info(NDI_UNIQUE, 0, op,
3631  lose_msg[i]);
3632  lost_a_stat = 1;
3633  } else {
3634  /* deplete a stat */
3636  if (deparch == NULL) {
3637  continue;
3638  }
3639  object *dep;
3640  int lose_this_stat;
3641  int i;
3642 
3643  i = RANDOM()%7;
3644  dep = arch_present_in_ob(deparch, op);
3645  if (!dep) {
3646  dep = arch_to_object(deparch);
3647  object_insert_in_ob(dep, op);
3648  }
3649  lose_this_stat = 1;
3651  int this_stat;
3652 
3653  /* GD */
3654  /* Get the stat that we're about to deplete. */
3655  this_stat = get_attr_value(&(dep->stats), i);
3656  if (this_stat < 0) {
3657  int loss_chance = 1+op->level/BALSL_LOSS_CHANCE_RATIO;
3658  int keep_chance = this_stat*this_stat;
3659  /* Yes, I am paranoid. Sue me. */
3660  if (keep_chance < 1)
3661  keep_chance = 1;
3662 
3663  /* There is a maximum depletion total per level. */
3664  if (this_stat < -1-op->level/BALSL_MAX_LOSS_RATIO) {
3665  lose_this_stat = 0;
3666  /* Take loss chance vs keep chance to see if we
3667  retain the stat. */
3668  } else {
3669  if (random_roll(0, loss_chance+keep_chance-1, op, PREFER_LOW) < keep_chance)
3670  lose_this_stat = 0;
3671  /* 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"); */
3672  }
3673  }
3674  }
3675 
3676  if (lose_this_stat) {
3677  int this_stat;
3678 
3679  this_stat = get_attr_value(&(dep->stats), i);
3680  /* We could try to do something clever like find another
3681  * stat to reduce if this fails. But chances are, if
3682  * stats have been depleted to -50, all are pretty low
3683  * and should be roughly the same, so it shouldn't make a
3684  * difference.
3685  */
3686  if (this_stat >= -50) {
3687  change_attr_value(&(dep->stats), i, -1);
3688  SET_FLAG(dep, FLAG_APPLIED);
3690  drain_msg[i]);
3691  fix_object(op);
3692  lost_a_stat = 1;
3693  }
3694  }
3695  }
3696  }
3697  /* If no stat lost, tell the player. */
3698  if (!lost_a_stat) {
3699  /* determine_god() seems to not work sometimes... why is this? Should I be using something else? GD */
3700  const char *god = determine_god(op);
3701 
3702  if (god && (strcmp(god, "none")))
3705  "For a brief moment you feel the holy presence of %s protecting you",
3706  god);
3707  else
3708  draw_ext_info(NDI_UNIQUE, 0, op,
3710  "For a brief moment you feel a holy presence protecting you.");
3711  }
3712 
3713  /* Put a gravestone up where the character 'almost' died. List the
3714  * exp loss on the stone.
3715  */
3716  at = find_archetype("gravestone");
3717  if (at != NULL) {
3718  tmp = arch_to_object(at);
3719  snprintf(buf, sizeof(buf), "%s's gravestone", op->name);
3720  FREE_AND_COPY(tmp->name, buf);
3721  snprintf(buf, sizeof(buf), "%s's gravestones", op->name);
3722  FREE_AND_COPY(tmp->name_pl, buf);
3723  snprintf(buf, sizeof(buf), "RIP\nHere rests the hero %s the %s,\n"
3724  "who was killed\n"
3725  "by %s.\n",
3726  op->name, op->contr->title,
3727  op->contr->killer);
3728  object_set_msg(tmp, buf);
3729  object_insert_in_map_at(tmp, op->map, NULL, 0, op->x, op->y);
3730  }
3731 
3732  /* restore player: remove any poisoning, disease and confusion the
3733  * character may be suffering.*/
3734  restore_player(op);
3735 
3736  /* Subtract the experience points, if we died cause of food, give
3737  * us food, and reset HP's...
3738  */
3740  if (op->stats.food < 100)
3741  op->stats.food = 900;
3742  op->stats.hp = op->stats.maxhp;
3743  op->stats.sp = MAX(op->stats.sp, op->stats.maxsp);
3744  op->stats.grace = MAX(op->stats.grace, op->stats.maxgrace);
3745 
3746  /* Check to see if the player is in a shop. IF so, then check to see if
3747  * the player has any unpaid items. If so, remove them and put them back
3748  * in the map.
3749  *
3750  * If they are not in a shop, just free the unpaid items instead of
3751  * putting them back on map.
3752  */
3753  if (shop_contains(op))
3754  remove_unpaid_objects(op->inv, op, 0);
3755  else
3756  remove_unpaid_objects(op->inv, op, 1);
3757 
3758  /* Move player to his current respawn-position (usually last savebed) */
3760 
3761  /* Save the player before inserting the force to reduce chance of abuse. */
3762  op->contr->braced = 0;
3763  /* don't pick up in apartment */
3764  if (op->contr->mode & PU_NEWMODE) {
3765  op->contr->mode = op->contr->mode | PU_INHIBIT;
3766  esrv_send_pickup(op->contr);
3767  } else {
3768  op->contr->mode = 0;
3769  }
3770  if ( op->contr->search_str[0] ) command_search_items(op,NULL); /* turn off search-items */
3771  save_player(op, 1);
3772 
3773  /* it is possible that the player has blown something up
3774  * at his savebed location, and that can have long lasting
3775  * spell effects. So first see if there is a spell effect
3776  * on the space that might harm the player.
3777  */
3778  will_kill_again = 0;
3779  FOR_MAP_PREPARE(op->map, op->x, op->y, tmp)
3780  if (tmp->type == SPELL_EFFECT)
3781  will_kill_again |= tmp->attacktype;
3782  FOR_MAP_FINISH();
3783  if (will_kill_again) {
3784  object *force;
3785  int at;
3786 
3787  force = create_archetype(FORCE_NAME);
3788  /* 50 ticks should be enough time for the spell to abate */
3789  force->speed = 0.1;
3790  force->speed_left = -5.0;
3791  SET_FLAG(force, FLAG_APPLIED);
3792  for (at = 0; at < NROFATTACKS; at++) {
3793  if (will_kill_again&(1<<at))
3794  force->resist[at] = 100;
3795  }
3796  object_insert_in_ob(force, op);
3797  fix_object(op);
3798  }
3799 
3800  /* Tell the player they have died */
3802  "YOU HAVE DIED.");
3803 }
3804 
3811 static void kill_player_permadeath(object *op) {
3812  char buf[MAX_BUF];
3813  char ac_buf[MAX_BUF];
3814  int x, y;
3815  mapstruct *map;
3816  object *tmp;
3817  archetype *at;
3818 
3819  /* save the map location for corpse, gravestone*/
3820  x = op->x;
3821  y = op->y;
3822  map = op->map;
3823 
3824  party_leave(op);
3825  if (settings.set_title == TRUE)
3826  player_set_own_title(op->contr, "");
3827 
3828  /* buf should be the kill message */
3830  buf);
3831  hiscore_check(op, 0);
3832  if (op->contr->ranges[range_golem] != NULL) {
3836  op->contr->ranges[range_golem] = NULL;
3837  op->contr->golem_count = 0;
3838  }
3839  loot_object(op); /* Remove some of the items for good */
3840  object_remove(op);
3841  op->direction = 0;
3842 
3843  if (!QUERY_FLAG(op, FLAG_WAS_WIZ) && op->stats.exp) {
3844  if (settings.resurrection == TRUE) {
3845  /* save playerfile sans equipment when player dies
3846  * -then save it as player.pl.dead so that future resurrection
3847  * -type spells will work on them nicely
3848  */
3849  op->stats.hp = op->stats.maxhp;
3850  op->stats.food = MAX_FOOD;
3851 
3852  /* set the location of where the person will reappear when */
3853  /* maybe resurrection code should fix map also */
3855  sizeof(op->contr->maplevel));
3856  if (op->map != NULL)
3857  op->map = NULL;
3858  op->x = settings.emergency_x;
3859  op->y = settings.emergency_y;
3860  save_player(op, 0);
3861  op->map = map;
3862  /* please see resurrection.c: peterm */
3863  dead_player(op);
3864  } else {
3865  delete_character(op->name);
3866 
3867  /* Remove player from account list and send back data if needed */
3868  if (op->contr->socket->account_chars != NULL) {
3871  /* char information is reloaded in send_account_players below */
3873  op->contr->socket->account_chars = NULL;
3876  }
3877  }
3878  }
3879  play_again(op);
3880 
3881  /* peterm: added to create a corpse at deathsite. */
3882  at = find_archetype("corpse_pl");
3883  if (at != NULL) {
3884  tmp = arch_to_object(at);
3885  snprintf(buf, sizeof(buf), "%s", op->name);
3886  FREE_AND_COPY(tmp->name, buf);
3887  FREE_AND_COPY(tmp->name_pl, buf);
3888  tmp->level = op->level;
3889  object_set_msg(tmp, gravestone_text(op, buf, sizeof(buf)));
3890  SET_FLAG(tmp, FLAG_UNIQUE);
3891  /*
3892  * Put the account name under slaying.
3893  * Does not seem to cause weird effects, but more testing may ensure this.
3894  */
3895  snprintf(ac_buf, sizeof(ac_buf), "%s", op->contr->socket->account_name);
3896  FREE_AND_COPY(tmp->slaying, ac_buf);
3897  object_insert_in_map_at(tmp, map, NULL, 0, x, y);
3898  }
3899 }
3900 
3908 void fix_weight(void) {
3909  player *pl;
3910 
3911  for (pl = first_player; pl != NULL; pl = pl->next) {
3912  int old = pl->ob->carrying, sum = object_sum_weight(pl->ob);
3913 
3914  if (old == sum)
3915  continue;
3916  fix_object(pl->ob);
3917  LOG(llevDebug, "Fixed inventory in %s (%d -> %d)\n", pl->ob->name, old, sum);
3918  }
3919 }
3920 
3924 void fix_luck(void) {
3925  player *pl;
3926 
3927  for (pl = first_player; pl != NULL; pl = pl->next)
3928  if (!pl->ob->contr->state)
3929  change_luck(pl->ob, 0);
3930 }
3931 
3932 
3945 void cast_dust(object *op, object *throw_ob, int dir) {
3946  object *skop, *spob;
3947 
3948  skop = find_skill_by_name(op, throw_ob->skill);
3949 
3950  /* casting POTION 'dusts' is really a use_magic_item skill */
3951  if (op->type == PLAYER && throw_ob->type == POTION && !skop) {
3952  LOG(llevError, "Player %s lacks critical skill use_magic_item!\n", op->name);
3953  return;
3954  }
3955  spob = throw_ob->inv;
3956  if (op->type == PLAYER && spob)
3958  "You cast %s.",
3959  spob->name);
3960 
3961  cast_spell(op, throw_ob, dir, spob, NULL);
3962 
3963  if (!QUERY_FLAG(throw_ob, FLAG_REMOVED))
3964  object_remove(throw_ob);
3965  object_free_drop_inventory(throw_ob);
3966 }
3967 
3974 void make_visible(object *op) {
3975  op->hide = 0;
3976  op->invisible = 0;
3977  if (op->type == PLAYER) {
3978  op->contr->tmp_invis = 0;
3979  if (op->contr->invis_race)
3981  }
3983 }
3984 
3993 int is_true_undead(object *op) {
3994  if (QUERY_FLAG(&op->arch->clone, FLAG_UNDEAD))
3995  return 1;
3996 
3997  return 0;
3998 }
3999 
4010 int hideability(object *ob) {
4011  int i, level = 0, mflag;
4012  int16_t x, y;
4013 
4014  if (!ob || !ob->map)
4015  return 0;
4016 
4017  /* so, on normal lighted maps, its hard to hide */
4018  level = ob->map->darkness-2;
4019 
4020  /* this also picks up whether the object is glowing.
4021  * If you carry a light on a non-dark map, its not
4022  * as bad as carrying a light on a pitch dark map
4023  */
4024  if (has_carried_lights(ob))
4025  level = -(10+(2*ob->map->darkness));
4026 
4027  /* scan through all nearby squares for terrain to hide in */
4028  for (i = 0, x = ob->x, y = ob->y; i < 9; i++, x = ob->x+freearr_x[i], y = ob->y+freearr_y[i]) {
4029  mflag = get_map_flags(ob->map, NULL, x, y, NULL, NULL);
4030  if (mflag&P_OUT_OF_MAP) {
4031  continue;
4032  }
4033  if (mflag&P_BLOCKSVIEW) /* something to hide near! */
4034  level += 2;
4035  else /* open terrain! */
4036  level -= 1;
4037  }
4038 
4039  return level;
4040 }
4041 
4051 void do_hidden_move(object *op) {
4052  int hide = 0, num = random_roll(0, 19, op, PREFER_LOW);
4053  object *skop;
4054 
4055  if (!op || !op->map)
4056  return;
4057 
4059 
4060  /* its *extremely *hard to run and sneak/hide at the same time! */
4061  if (op->type == PLAYER && op->contr->run_on) {
4062  if (!skop || num >= skop->level) {
4064  "You ran too much! You are no longer hidden!");
4065  make_visible(op);
4066  return;
4067  } else
4068  num += 20;
4069  }
4070  num += op->map->difficulty;
4071  hide = hideability(op); /* modify by terrain hidden level */
4072  num -= hide;
4073  if ((op->type == PLAYER && hide < -10)
4074  || ((op->invisible -= num) <= 0)) {
4075  make_visible(op);
4076  if (op->type == PLAYER)
4078  "You moved out of hiding! You are visible!");
4079  } else if (op->type == PLAYER && skop) {
4080  change_exp(op, calc_skill_exp(op, NULL, skop), skop->skill, 0);
4081  }
4082 }
4083 
4092 int stand_near_hostile(object *who) {
4093  int i, friendly = 0, player = 0, mflags;
4094  mapstruct *m;
4095  int16_t x, y;
4096 
4097  if (!who)
4098  return 0;
4099 
4100  if (who->type == PLAYER)
4101  player = 1;
4102  else
4104 
4105  /* search adjacent squares */
4106  for (i = 1; i < 9; i++) {
4107  x = who->x+freearr_x[i];
4108  y = who->y+freearr_y[i];
4109  m = who->map;
4110  mflags = get_map_flags(m, &m, x, y, &x, &y);
4111  /* space must be blocked if there is a monster. If not
4112  * blocked, don't need to check this space.
4113  */
4114  if (mflags&P_OUT_OF_MAP)
4115  continue;
4116  if (OB_TYPE_MOVE_BLOCK(who, GET_MAP_MOVE_BLOCK(m, x, y)))
4117  continue;
4118 
4119  FOR_MAP_PREPARE(m, x, y, tmp) {
4120  if ((player || friendly)
4121  && QUERY_FLAG(tmp, FLAG_MONSTER)
4122  && !QUERY_FLAG(tmp, FLAG_UNAGGRESSIVE))
4123  return 1;
4124  else if (tmp->type == PLAYER) {
4125  /*don't let a hidden DM prevent you from hiding*/
4126  if (!QUERY_FLAG(tmp, FLAG_WIZ) || tmp->contr->hidden == 0)
4127  return 1;
4128  }
4129  } FOR_MAP_FINISH();
4130  }
4131  return 0;
4132 }
4133 
4160 int player_can_view(object *pl, object *op) {
4161  rv_vector rv;
4162  int dx, dy;
4163 
4164  if (!pl || !op)
4165  return 0;
4166 
4167  if (pl->type != PLAYER) {
4168  LOG(llevError, "player_can_view() called for non-player object\n");
4169  return -1;
4170  }
4171 
4172  op = HEAD(op);
4173  if (!get_rangevector(pl, op, &rv, 0x1))
4174  return 0;
4175 
4176  /* starting with the 'head' part, lets loop
4177  * through the object and find if it has any
4178  * part that is in the los array but isnt on
4179  * a blocked los square.
4180  * we use the archetype to figure out offsets.
4181  */
4182  while (op) {
4183  dx = rv.distance_x+op->arch->clone.x;
4184  dy = rv.distance_y+op->arch->clone.y;
4185 
4186  /* only the viewable area the player sees is updated by LOS
4187  * code, so we need to restrict ourselves to that range of values
4188  * for any meaningful values.
4189  */
4190  if (FABS(dx) <= (pl->contr->socket->mapx/2)
4191  && FABS(dy) <= (pl->contr->socket->mapy/2)
4192  && !pl->contr->blocked_los[dx+(pl->contr->socket->mapx/2)][dy+(pl->contr->socket->mapy/2)])
4193  return 1;
4194  op = op->more;
4195  }
4196  return 0;
4197 }
4198 
4212 static int action_makes_visible(object *op) {
4213  if (op->invisible && QUERY_FLAG(op, FLAG_ALIVE)) {
4214  if (QUERY_FLAG(op, FLAG_MAKE_INVIS))
4215  return 0;
4216 
4217  if (op->contr && op->contr->tmp_invis == 0)
4218  return 0;
4219 
4220  /* If monsters, they should become visible */
4221  if (op->hide || !op->contr || (op->contr && op->contr->tmp_invis)) {
4223  "You become %s!",
4224  op->hide ? "unhidden" : "visible");
4225  return 1;
4226  }
4227  }
4228  return 0;
4229 }
4230 
4259 int op_on_battleground(object *op, int *x, int *y, archetype **trophy) {
4260  FOR_BELOW_PREPARE(op, tmp) {
4261  if (QUERY_FLAG(tmp, FLAG_IS_FLOOR)) {
4262  if (QUERY_FLAG(tmp, FLAG_NO_PICK)
4263  && strcmp(tmp->name, "battleground") == 0
4264  && tmp->type == BATTLEGROUND
4265  && EXIT_X(tmp)
4266  && EXIT_Y(tmp)) {
4267  /*before we assign the exit, check if this is a teambattle*/
4268  if (EXIT_ALT_X(tmp) && EXIT_ALT_Y(tmp) && EXIT_PATH(tmp)) {
4269  object *invtmp;
4270 
4271  invtmp = object_find_by_type_and_slaying(op, FORCE, EXIT_PATH(tmp));
4272  if (invtmp != NULL) {
4273  if (x != NULL && y != NULL)
4274  *x = EXIT_ALT_X(tmp),
4275  *y = EXIT_ALT_Y(tmp);
4276  return 1;
4277  }
4278  }
4279  if (x != NULL && y != NULL)
4280  *x = EXIT_X(tmp),
4281  *y = EXIT_Y(tmp);
4282 
4283  /* If 'other_arch' is not specified, give a finger. */
4284  if (trophy != NULL) {
4285  if (tmp->other_arch) {
4286  *trophy = tmp->other_arch;
4287  } else {
4288  *trophy = find_archetype("finger");
4289  }
4290  }
4291  return 1;
4292  }
4293  }
4294  } FOR_BELOW_FINISH();
4295  /* If we got here, did not find a battleground */
4296  return 0;
4297 }
4298 
4309 void dragon_ability_gain(object *who, int atnr, int level) {
4310  treasurelist *trlist = NULL; /* treasurelist */
4311  treasure *tr; /* treasure */
4312  object *tmp, *skop; /* tmp. object */
4313  object *item; /* treasure object */
4314  char buf[MAX_BUF]; /* tmp. string buffer */
4315  int i = 0, j = 0;
4316 
4317  /* get the appropriate treasurelist */
4318  if (atnr == ATNR_FIRE)
4319  trlist = find_treasurelist("dragon_ability_fire");
4320  else if (atnr == ATNR_COLD)
4321  trlist = find_treasurelist("dragon_ability_cold");
4322  else if (atnr == ATNR_ELECTRICITY)
4323  trlist = find_treasurelist("dragon_ability_elec");
4324  else if (atnr == ATNR_POISON)
4325  trlist = find_treasurelist("dragon_ability_poison");
4326 
4327  if (trlist == NULL || who->type != PLAYER)
4328  return;
4329 
4330  // tr->magic is being used to define what level of the metabolism the ability is gained at.
4331  for (tr = trlist->items; tr != NULL && tr->magic != level; tr = tr->next)
4332  ;
4333  if (tr == NULL || tr->item == NULL) {
4334  /* LOG(llevDebug, "-> no more treasure for %s\n", change_resist_msg[atnr]); */
4335  return;
4336  }
4337 
4338  /* everything seems okay - now bring on the gift: */
4339  item = &(tr->item->clone);
4340 
4341  if (item->type == SPELL) {
4342  if (check_spell_known(who, item->name))
4343  return;
4344 
4347  "You gained the ability of %s",
4348  item->name);
4349  do_learn_spell(who, item, 0);
4350  return;
4351  }
4352 
4353  /* grant direct spell */
4354  if (item->type == SPELLBOOK) {
4355  if (!item->inv) {
4356  LOG(llevDebug, "dragon_ability_gain: Broken spellbook %s\n", item->name);
4357  return;
4358  }
4359  if (check_spell_known(who, item->inv->name))
4360  return;
4361  if (item->invisible) {
4364  "You gained the ability of %s",
4365  item->inv->name);
4366  do_learn_spell(who, item->inv, 0);
4367  return;
4368  }
4369  } else if (item->type == SKILL_TOOL && item->invisible) {
4370  if (item->subtype == SK_CLAWING && (skop = find_skill_by_name(who, item->skill)) != NULL) {
4371  /* should this perhaps be (skop->attackyp&item->attacktype) != item->attacktype ...
4372  * in this way, if the player is missing any of the attacktypes, he gets
4373  * them. As it is now, if the player has any that match the granted skill,
4374  * but not all of them, he gets nothing.
4375  */
4376  if (!(skop->attacktype&item->attacktype)) {
4377  /* Give new attacktype */
4378  skop->attacktype |= item->attacktype;
4379 
4380  /* always add physical if there's none */
4381  skop->attacktype |= AT_PHYSICAL;
4382 
4383  if (item->msg != NULL)
4386  item->msg);
4387 
4388  /* Give player new face */
4389  if (item->animation) {
4390  who->face = skop->face;
4391  who->animation = item->animation;
4392  who->anim_speed = item->anim_speed;
4393  who->last_anim = 0;
4394  who->state = 0;
4395  animate_object(who, who->direction);
4396  }
4397  }
4398  }
4399  } else if (item->type == FORCE) {
4400  /* forces in the treasurelist can alter the player's stats */
4401  object *skin;
4402 
4403  /* first get the dragon skin force */
4404  skin = object_find_by_arch_name(who, "dragon_skin_force");
4405  if (skin == NULL)
4406  return;
4407 
4408  /* adding new spellpath attunements */
4409  if (item->path_attuned > 0 && !(skin->path_attuned&item->path_attuned)) {
4410  skin->path_attuned |= item->path_attuned; /* add attunement to skin */
4411 
4412  /* print message */
4413  snprintf(buf, sizeof(buf), "You feel attuned to ");
4414  for (i = 0, j = 0; i < NRSPELLPATHS; i++) {
4415  if (item->path_attuned&(1<<i)) {
4416  if (j)
4417  strcat(buf, " and ");
4418  else
4419  j = 1;
4420  strcat(buf, spellpathnames[i]);
4421  }
4422  }
4423  strcat(buf, ".");
4426  buf);
4427  }
4428 
4429  /* evtl. adding flags: */
4430  if (QUERY_FLAG(item, FLAG_XRAYS))
4431  SET_FLAG(skin, FLAG_XRAYS);
4432  if (QUERY_FLAG(item, FLAG_STEALTH))
4433  SET_FLAG(skin, FLAG_STEALTH);
4434  if (QUERY_FLAG(item, FLAG_SEE_IN_DARK))
4435  SET_FLAG(skin, FLAG_SEE_IN_DARK);
4436 
4437  /* print message if there is one */
4438  if (item->msg != NULL)
4441  item->msg);
4442  } else {
4443  /* generate misc. treasure */
4444  char name[HUGE_BUF];
4445 
4446  tmp = arch_to_object(tr->item);
4450  "You gained %s",
4451  name);
4452  tmp = object_insert_in_ob(tmp, who);
4453  if (who->type == PLAYER)
4454  esrv_send_item(who, tmp);
4455  }
4456 }
4457 
4467 void player_unready_range_ob(player *pl, object *ob) {
4468  int i;
4469 
4470  for (i = 0; i < static_cast<int>(range_size); i++) {
4471  if (pl->ranges[i] == ob) {
4472  pl->ranges[i] = NULL;
4473  if (pl->shoottype == i) {
4474  pl->shoottype = range_none;
4475  }
4476  }
4477  }
4478 }
4479 
4485 void player_set_state(player *pl, uint8_t state) {
4486 
4487  assert(pl);
4488  assert(state <= ST_CHANGE_PASSWORD_CONFIRM);
4489  pl->state = state;
4490 }
4491 
4499  SockList *sl;
4500  assert(pl);
4501  const uint8_t to_alloc = 5;
4503  if (pl->delayed_buffers_allocated >= UINT8_MAX - to_alloc) {
4504  LOG(llevError, "Delay buffer limit exceeded for %s\n", pl->ob->name);
4505  abort();
4506  }
4507  pl->delayed_buffers_allocated += to_alloc;
4508  pl->delayed_buffers = static_cast<SockList **>(realloc(pl->delayed_buffers, pl->delayed_buffers_allocated * sizeof(pl->delayed_buffers[0])));
4509  if (!pl->delayed_buffers) {
4510  LOG(llevError, "Unable to allocated %d delayed buffers, aborting\n", pl->delayed_buffers_allocated);
4512  }
4513  for (uint8_t s = pl->delayed_buffers_allocated - to_alloc; s < pl->delayed_buffers_allocated; s++) {
4514  pl->delayed_buffers[s] = static_cast<SockList *>(calloc(1, sizeof(SockList)));
4515  }
4516  }
4517  sl = pl->delayed_buffers[pl->delayed_buffers_used];
4518  pl->delayed_buffers_used++;
4519  SockList_Init(sl);
4520  return sl;
4521 }
4522 
4528  for (uint8_t buf = 0; buf < pl->delayed_buffers_used; buf++) {
4530  }
4531  pl->delayed_buffers_used = 0;
4532 }
player::gen_sp
int16_t gen_sp
Bonuses to regeneration speed of sp.
Definition: player.h:127
object_was_destroyed
#define object_was_destroyed(op, old_tag)
Checks if an object still exists.
Definition: object.h:70
ADD_PLAYER_NO_STATS_ROLL
#define ADD_PLAYER_NO_STATS_ROLL
Stats provided from client.
Definition: player.h:249
object_value_set
bool object_value_set(const object *op, const char *const key)
Determine if an extra value is set.
Definition: object.cpp:4361
op_on_battleground
int op_on_battleground(object *op, int *x, int *y, archetype **trophy)
Check if the given object (usually a player) is standing on a battleground tile.
Definition: player.cpp:4259
EVENT_REMOVE
#define EVENT_REMOVE
A Player character has been removed.
Definition: events.h:67
object::name_pl
sstring name_pl
The plural name of the object.
Definition: object.h:323
GET_MAP_OB
#define GET_MAP_OB(M, X, Y)
Gets the bottom object on a map.
Definition: map.h:170
MSG_TYPE_COMMAND_NEWPLAYER
#define MSG_TYPE_COMMAND_NEWPLAYER
Create a new character - not really a command, but is responding to player input.
Definition: newclient.h:540
do_skill
int do_skill(object *op, object *part, object *skill, int dir, const char *string)
Main skills use function-similar in scope to cast_spell().
Definition: skill_util.cpp:431
player::do_los
uint32_t do_los
If true, need to call update_los() in draw(), and clear.
Definition: player.h:141
apply_changes_to_player
void apply_changes_to_player(object *pl, object *change, int limit_stats)
Applies (race) changes to a player.
Definition: apply.cpp:1668
player::bed_y
int16_t bed_y
x,y - coordinates of respawn (savebed).
Definition: player.h:111
living::exp
int64_t exp
Experience.
Definition: living.h:47
UP_OBJ_FACE
#define UP_OBJ_FACE
Only thing that changed was the face.
Definition: object.h:533
check_pick
int check_pick(object *op)
Sees if there is stuff to be picked up/picks up stuff, for players only.
Definition: player.cpp:1731
make_visible
void make_visible(object *op)
Makes an object visible again.
Definition: player.cpp:3974
object::weapon_speed_left
float weapon_speed_left
How much speed is left to spend this round.
Definition: object.h:340
PLAYER
@ PLAYER
Definition: object.h:112
PU_BOOTS
#define PU_BOOTS
Definition: define.h:125
object_get_owner
object * object_get_owner(object *op)
Returns the object which this object marks as being the owner.
Definition: object.cpp:789
player::next
player * next
Pointer to next player, NULL if this is last.
Definition: player.h:106
kill_player_permadeath
static void kill_player_permadeath(object *op)
Kills a player in permadeath mode.
Definition: player.cpp:3811
SockList_AddInt
void SockList_AddInt(SockList *sl, uint32_t data)
Adds a 32 bit value.
Definition: lowlevel.cpp:127
global.h
FLAG_NEUTRAL
#define FLAG_NEUTRAL
monster is from type neutral
Definition: define.h:354
UPD_FACE
#define UPD_FACE
Definition: newclient.h:321
object_find_by_type_subtype
object * object_find_by_type_subtype(const object *who, int type, int subtype)
Find object in inventory.
Definition: object.cpp:4286
first_player
player * first_player
First player.
Definition: init.cpp:106
settings
struct Settings settings
Global settings.
Definition: init.cpp:139
SOUND_TYPE_ITEM
#define SOUND_TYPE_ITEM
Definition: newclient.h:339
bow_spreadshot
@ bow_spreadshot
Fire three arrows in a cone.
Definition: player.h:44
friendly
TIPS on SURVIVING Crossfire is populated with a wealth of different monsters These monsters can have varying immunities and attack types In some of them can be quite a bit smarter than others It will be important for new players to learn the abilities of different monsters and learn just how much it will take to kill them This section discusses how monsters can interact with players Most monsters in the game are out to mindlessly kill and destroy the players These monsters will help boost a player s after he kills them When fighting a large amount of monsters in a single attempt to find a narrower hallway so that you are not being attacked from all sides Charging into a room full of Beholders for instance would not be open the door and fight them one at a time For there are several maps designed for them Find these areas and clear them out All throughout these a player can find signs and books which they can read by stepping onto them and hitting A to apply the book sign These messages will help the player to learn the system One more always keep an eye on your food If your food drops to your character will soon so BE CAREFUL ! NPCs Non Player Character are special monsters which have intelligence Players may be able to interact with these monsters to help solve puzzles and find items of interest To speak with a monster you suspect to be a simply move to an adjacent square to them and push the double ie Enter your and press< Return > You can also use say if you feel like typing a little extra Other NPCs may not speak to but display intelligence with their movement Some monsters can be friendly
Definition: survival-guide.txt:38
object_update_turn_face
void object_update_turn_face(object *op)
If an object with the IS_TURNABLE() flag needs to be turned due to the closest player being on the ot...
Definition: object.cpp:1317
safe_strncpy
#define safe_strncpy
Definition: compat.h:27
FOR_MAP_FINISH
#define FOR_MAP_FINISH()
Finishes FOR_MAP_PREPARE().
Definition: define.h:724
remove_friendly_object
void remove_friendly_object(object *op)
Removes the specified object from the linked list of friendly objects.
Definition: friend.cpp:52
pets_terminate_all
void pets_terminate_all(object *owner)
Removes all pets someone owns.
Definition: pets.cpp:242
bow_normal
@ bow_normal
Standard mode, one random arrow.
Definition: player.h:42
face_player
int face_player(object *op, int dir)
Face player in the given direction.
Definition: player.cpp:3041
living::maxhp
int16_t maxhp
Max hit points.
Definition: living.h:41
options
static struct Command_Line_Options options[]
Actual valid command line options.
Definition: init.cpp:386
ST_GET_PASSWORD
#define ST_GET_PASSWORD
Name entered, now for password.
Definition: define.h:541
MSG_TYPE_COMMAND_SUCCESS
#define MSG_TYPE_COMMAND_SUCCESS
Successful result from command.
Definition: newclient.h:534
FLAG_CONFUSED
#define FLAG_CONFUSED
Will also be unable to cast spells.
Definition: define.h:311
player::unarmed_skill
const char * unarmed_skill
Prefered skill to use in unarmed combat.
Definition: player.h:221
BOW
@ BOW
Definition: object.h:123
player_fire_bow
static int player_fire_bow(object *op, int dir)
Special fire code for players - this takes into account the special fire modes players can have but m...
Definition: player.cpp:2322
Settings::emergency_y
uint16_t emergency_y
Coordinates to use on that map.
Definition: global.h:301
kill_player
void kill_player(object *op, const object *killer)
Handle a player's death.
Definition: player.cpp:3506
llevError
@ llevError
Error, serious thing.
Definition: logger.h:11
FABS
#define FABS(x)
Decstations have trouble with fabs()...
Definition: define.h:22
mapstruct::difficulty
uint16_t difficulty
What level the player should be to play here.
Definition: map.h:333
MOVE_ALL
#define MOVE_ALL
Mask of all movement types.
Definition: define.h:398
object::path_attuned
uint32_t path_attuned
Paths the object is attuned to.
Definition: object.h:353
command_search_items
void command_search_items(object *op, const char *params)
'search-items' command.
Definition: c_object.cpp:2487
WAND
@ WAND
Definition: object.h:225
range_bow
@ range_bow
Bow.
Definition: player.h:31
get_player_archetype
static archetype * get_player_archetype(archetype *at)
Get next player archetype from archetype list.
Definition: player.cpp:513
MSG_TYPE_ADMIN_PLAYER
#define MSG_TYPE_ADMIN_PLAYER
Player coming/going/death.
Definition: newclient.h:500
player::mode
uint32_t mode
Mode of player for pickup.
Definition: player.h:123
LOG
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.cpp:58
FLAG_UNDEAD
#define FLAG_UNDEAD
Monster is undead.
Definition: define.h:270
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:224
bow_threewide
@ bow_threewide
Fire three arrows in the same direction.
Definition: player.h:43
FLESH
@ FLESH
animal 'body parts' -b.t.
Definition: object.h:192
monster_can_detect_enemy
int monster_can_detect_enemy(object *op, object *enemy, rv_vector *rv)
Determine if we can 'detect' the enemy.
Definition: monster.cpp:2701
PU_ARROW
#define PU_ARROW
Definition: define.h:120
PU_NOT_CURSED
#define PU_NOT_CURSED
Definition: define.h:140
player
One player.
Definition: player.h:105
path_to_player
int path_to_player(object *mon, object *pl, unsigned mindiff)
Returns the direction to the player, if valid.
Definition: player.cpp:659
esrv_map_scroll
void esrv_map_scroll(socket_struct *ns, int dx, int dy)
Definition: request.cpp:1753
blocked_link
int blocked_link(object *ob, mapstruct *m, int16_t sx, int16_t sy)
Returns true if the given coordinate is blocked except by the object passed is not blocking.
Definition: map.cpp:354
strdup_local
#define strdup_local
Definition: compat.h:29
object::inv
object * inv
Pointer to the first object in the inventory.
Definition: object.h:298
Settings::resurrection
uint8_t resurrection
Ressurection possible w/ permadeth on.
Definition: global.h:267
EVENT_DEATH
#define EVENT_DEATH
Player or monster dead.
Definition: events.h:33
recursive_roll
void recursive_roll(object *op, int dir, object *pusher)
An object is pushed by another which is trying to take its place.
Definition: move.cpp:293
player::golem_count
uint32_t golem_count
To track the golem.
Definition: player.h:119
safe_strcat
void safe_strcat(char *dest, const char *orig, size_t *curlen, size_t maxlen)
Simple function we use below to keep adding to the same string but also make sure we don't overwrite ...
Definition: porting.cpp:202
FLAG_STARTEQUIP
#define FLAG_STARTEQUIP
Object was given to player at start.
Definition: define.h:268
first_map_path
char first_map_path[MAX_BUF]
The start-level.
Definition: init.cpp:120
MSG_TYPE_SKILL
#define MSG_TYPE_SKILL
Messages related to skill use.
Definition: newclient.h:411
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
player::is_wraith
bool is_wraith
Whether this player is a wraith or not, initialized at load time.
Definition: player.h:227
treasurelist::items
treasure * items
Items in this list, linked.
Definition: treasure.h:92
Settings::set_title
uint8_t set_title
Players can set thier title.
Definition: global.h:266
AssetsManager.h
remove_locked_door
void remove_locked_door(object *op)
Same as remove_door() but for locked doors.
Definition: time.cpp:64
spellpathnames
const char *const spellpathnames[NRSPELLPATHS]
Perhaps not the best place for this, but needs to be in some file in the common area so that standalo...
Definition: init.cpp:236
SK_CLAWING
@ SK_CLAWING
Clawing.
Definition: skills.h:50
ARCH_DEPLETION
#define ARCH_DEPLETION
Archetype for depletion.
Definition: object.h:590
NDI_GREEN
#define NDI_GREEN
SeaGreen.
Definition: newclient.h:253
KEY
@ KEY
Definition: object.h:132
PU_INHIBIT
#define PU_INHIBIT
Definition: define.h:109
do_learn_spell
void do_learn_spell(object *op, object *spell, int special_prayer)
Actually makes op learn spell.
Definition: apply.cpp:484
socket_struct
Socket structure, represents a client-server connection.
Definition: newserver.h:93
socket_struct::mapx
uint8_t mapx
Definition: newserver.h:120
ST_GET_NAME
#define ST_GET_NAME
Player just connected.
Definition: define.h:540
first_map_ext_path
char first_map_ext_path[MAX_BUF]
Path used for per-race start maps.
Definition: init.cpp:121
esrv_new_player
void esrv_new_player(player *pl, uint32_t weight)
Tells the client that here is a player it should start using.
Definition: request.cpp:1008
pick_up
bool pick_up(object *op, object *alt)
Try to pick up an item.
Definition: c_object.cpp:520
FLAG_SEE_IN_DARK
#define FLAG_SEE_IN_DARK
if set ob not effected by darkness
Definition: define.h:337
Settings::not_permadeth
uint8_t not_permadeth
If true, death is non-permament.
Definition: global.h:263
player_get_delayed_buffer
SockList * player_get_delayed_buffer(player *pl)
Get a delayed socket buffer, that will be sent after the player's tick is complete.
Definition: player.cpp:4498
get_friends_of
objectlink * get_friends_of(const object *owner)
Get a list of friendly objects for the specified owner.
Definition: friend.cpp:117
esrv_send_inventory
void esrv_send_inventory(object *pl, object *op)
Sends inventory of a container.
Definition: item.cpp:316
roll_again
void roll_again(object *op)
Ask the player what to do with the statistics.
Definition: player.cpp:1146
find_player_socket
player * find_player_socket(const socket_struct *ns)
Return a player for a socket structure.
Definition: player.cpp:123
AT_PHYSICAL
#define AT_PHYSICAL
Definition: attack.h:76
object::arch
struct archetype * arch
Pointer to archetype.
Definition: object.h:424
cast_spell
int cast_spell(object *op, object *caster, int dir, object *spell_ob, char *stringarg)
Main dispatch when someone casts a spell.
Definition: spell_util.cpp:1424
find_better_arrow
static object * find_better_arrow(object *op, object *target, const char *type, int *better)
Similar to find_arrow(), but looks for (roughly) the best arrow to use against the target.
Definition: player.cpp:1968
player::bed_x
int16_t bed_x
Definition: player.h:111
absdir
int absdir(int d)
Computes an absolute direction.
Definition: object.cpp:3699
player::no_shout
uint32_t no_shout
if True, player is *not *able to use shout command.
Definition: player.h:148
SockList_AddString
void SockList_AddString(SockList *sl, const char *data)
Adds a string without length.
Definition: lowlevel.cpp:157
UINT8_MAX
#define UINT8_MAX
Definition: loader.cpp:78
FOR_BELOW_PREPARE
#define FOR_BELOW_PREPARE(op_, it_)
Constructs a loop iterating over all objects below an object.
Definition: define.h:698
object::speed
float speed
Frequency of object 'moves' relative to server tick rate.
Definition: object.h:337
if
if(!(yy_init))
Definition: loader.cpp:36435
object_set_enemy
void object_set_enemy(object *op, object *enemy)
Sets the enemy of an object.
Definition: object.cpp:900
starving
static bool starving(object *op)
Definition: player.cpp:3279
GEM
@ GEM
Definition: object.h:172
FLAG_UNIQUE
#define FLAG_UNIQUE
Item is really unique (UNIQUE_ITEMS)
Definition: define.h:287
object::invisible
int16_t invisible
How much longer the object will be invis.
Definition: object.h:370
MSG_TYPE_VICTIM_DIED
#define MSG_TYPE_VICTIM_DIED
Player died!
Definition: newclient.h:660
EXIT_PATH
#define EXIT_PATH(xyz)
Definition: define.h:433
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
If set, won't attack friendly creatures.
Definition: player.h:146
player::ob
object * ob
The object representing the player.
Definition: player.h:177
turn_transport
static int turn_transport(object *transport, object *captain, int dir)
Try to turn a transport in the desired direction.
Definition: player.cpp:2929
spring_trap
void spring_trap(object *trap, object *victim)
This function generalizes attacks by runes/traps.
Definition: rune.cpp:214
get_nearest_player
object * get_nearest_player(object *mon)
Finds the nearest visible player or player-friendly for some object.
Definition: player.cpp:548
apply_map_builder
void apply_map_builder(object *pl, int dir)
Global building function.
Definition: build_map.cpp:960
player::transport
object * transport
Transport the player is in.
Definition: player.h:214
object::speed_left
float speed_left
How much speed is left to spend this round.
Definition: object.h:338
PREFER_LOW
#define PREFER_LOW
Definition: define.h:558
PU_FOOD
#define PU_FOOD
Definition: define.h:115
object::map
struct mapstruct * map
Pointer to the map in which this object is present.
Definition: object.h:305
object::anim_suffix
sstring anim_suffix
Used to determine combined animations.
Definition: object.h:324
arch_present_in_ob
object * arch_present_in_ob(const archetype *at, const object *op)
Searches for any objects with a matching archetype in the inventory of the given object.
Definition: object.cpp:3207
find_treasurelist
treasurelist * find_treasurelist(const char *name)
Search for the given treasurelist by name.
Definition: assets.cpp:249
object_set_owner
void object_set_owner(object *op, object *owner)
Sets the owner and sets the skill and exp pointers to owner's current skill and experience objects.
Definition: object.cpp:825
esrv_send_pickup
void esrv_send_pickup(player *pl)
Sends the "pickup" state to pl if client wants it requested.
Definition: request.cpp:1880
player::last_applied_stats
living last_applied_stats
Last applied stats sent to the client.
Definition: player.h:172
PU_BOW
#define PU_BOW
Definition: define.h:118
player::levhp
int8_t levhp[11]
What hp bonus the player gained on that level.
Definition: player.h:186
MSG_TYPE_ATTRIBUTE
#define MSG_TYPE_ATTRIBUTE
Changes to attributes (stats, resistances, etc)
Definition: newclient.h:409
GT_ONLY_GOOD
@ GT_ONLY_GOOD
Don't generate bad/cursed items.
Definition: treasure.h:34
fix_weight
void fix_weight(void)
Check recursively the weight of all players, and fix what needs to be fixed.
Definition: player.cpp:3908
player_set_own_title
void player_set_own_title(struct player *pl, const char *title)
Sets the custom title.
Definition: player.cpp:272
range_none
@ range_none
No range selected.
Definition: player.h:30
PU_MAGIC_DEVICE
#define PU_MAGIC_DEVICE
Definition: define.h:138
SET_ANIMATION
#define SET_ANIMATION(ob, newanim)
Definition: global.h:164
time
non standard information is not specified or uptime this means how long since the executable has been started A particular host may have been running a server for quite a long time
Definition: arch-handbook.txt:206
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
Rejoin if party exists.
Definition: player.h:100
CS_QUERY_SINGLECHAR
#define CS_QUERY_SINGLECHAR
Single character response expected.
Definition: newclient.h:71
player::delayed_buffers
SockList ** delayed_buffers
Buffers which will be sent after the player's tick completes.
Definition: player.h:226
play_sound_player_only
void play_sound_player_only(player *pl, int8_t sound_type, object *emitter, int dir, const char *action)
Plays a sound for specified player only.
Definition: sounds.cpp:51
player::last_path_denied
uint32_t last_path_denied
Last spell denied sent to client.
Definition: player.h:162
allowed_class
int allowed_class(const object *op)
Returns true if the given player is a legal class.
Definition: living.cpp:1661
SKILL
@ SKILL
Also see SKILL_TOOL (74) below.
Definition: object.h:148
object::direction
int8_t direction
Means the object is moving that way.
Definition: object.h:344
play_sound_map
void play_sound_map(int8_t sound_type, object *emitter, int dir, const char *action)
Plays a sound on a map.
Definition: sounds.cpp:113
object::count
tag_t count
Unique object number for this object.
Definition: object.h:307
flags
static const flag_definition flags[]
Flag mapping.
Definition: gridarta-types-convert.cpp:101
RUNE
@ RUNE
Definition: object.h:245
change_skill
int change_skill(object *who, object *new_skill, int flag)
This changes the object's skill to new_skill.
Definition: skill_util.cpp:359
object_copy
void object_copy(const object *src_ob, object *dest_ob)
Copy object first frees everything allocated by the second object, and then copies the contents of th...
Definition: object.cpp:1177
player::levsp
int8_t levsp[11]
What sp bonus the player gained on that level.
Definition: player.h:187
FLAG_SCARED
#define FLAG_SCARED
Monster is scared (mb player in future)
Definition: define.h:271
player::savebed_map
char savebed_map[MAX_BUF]
Map where player will respawn after death.
Definition: player.h:110
Settings::roll_stat_points
uint8_t roll_stat_points
How many stat points legacy (rolled) chars start with.
Definition: global.h:324
fix_object
void fix_object(object *op)
Updates all abilities given by applied objects in the inventory of the given object.
Definition: living.cpp:1132
object_find_by_flag_applied
object * object_find_by_flag_applied(const object *who, int flag)
Find applied object in inventory by flag.
Definition: object.cpp:4214
send_delayed_buffers
void send_delayed_buffers(player *pl)
Send all delayed buffers for a player.
Definition: player.cpp:4527
PU_MISSILEWEAPON
#define PU_MISSILEWEAPON
Definition: define.h:130
player_can_view
int player_can_view(object *pl, object *op)
Check the player los field for viewability of the object op.
Definition: player.cpp:4160
confirm_password
void confirm_password(object *op)
Ask the player to confirm her password during creation.
Definition: player.cpp:1011
NDI_NAVY
#define NDI_NAVY
Definition: newclient.h:248
player::last_stats
living last_stats
Last stats as sent to client.
Definition: player.h:168
Settings::emergency_x
uint16_t emergency_x
Definition: global.h:301
get_name
void get_name(object *op)
Waiting for the player's name.
Definition: player.cpp:886
SEE_LAST_ERROR
@ SEE_LAST_ERROR
Definition: define.h:52
TRANSPORT
@ TRANSPORT
see doc/Developers/objects
Definition: object.h:113
SOUND_TYPE_LIVING
#define SOUND_TYPE_LIVING
Definition: newclient.h:337
player::hidden
uint32_t hidden
If True, player (DM) is hidden from view.
Definition: player.h:147
socket_struct::inbuf
SockList inbuf
If we get an incomplete packet, this is used to hold the data.
Definition: newserver.h:103
EVENT_LOGIN
#define EVENT_LOGIN
Player login.
Definition: events.h:57
object::enemy
object * enemy
Monster/player to follow even if not closest.
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)
Upon successful login/account creation, we send a list of characters associated with the account to t...
Definition: request.cpp:2103
skills.h
PU_POTION
#define PU_POTION
Definition: define.h:133
motd
**Media tags please refer to the protocol file in doc Developers protocol Quick for your pleasure an example[/b][i] This is an old full of dirt and partially destroyed[hand] My dear as you two years i had to leave quickly Words have come to me of powerful magic scrolls discovered in an old temple by my uncle I have moved to study them I not forgot your knowledge in ancient languages I need your help for[print][b] Some parts of document are to damaged to be readable[/b][arcane] Arghis[color=Red] k h[color=dark slate blue] ark[color=#004000] fido[/color][hand] please come as fast as possible my friend[print][b] The bottom of letter seems deliberatly shredded What is but not limited book signs motd
Definition: media-tags.txt:31
object::hide
uint8_t hide
The object is hidden, not invisible.
Definition: object.h:397
MSG_TYPE_COMMAND_ERROR
#define MSG_TYPE_COMMAND_ERROR
Bad syntax/can't use command.
Definition: newclient.h:533
esrv_add_spells
void esrv_add_spells(player *pl, object *spell)
This tells the client to add the spell *spell, if spell is NULL, then add all spells in the player's ...
Definition: request.cpp:1994
range_golem
@ range_golem
Control golem.
Definition: player.h:34
partylist
One party.
Definition: party.h:10
FLAG_INV_LOCKED
#define FLAG_INV_LOCKED
Item will not be dropped from inventory.
Definition: define.h:329
apply_manual
int apply_manual(object *op, object *tmp, int aflag)
Main apply handler.
Definition: apply.cpp:597
mapstruct::path
char path[HUGE_BUF]
Filename of the map.
Definition: map.h:355
P_IS_ALIVE
#define P_IS_ALIVE
Something alive is on this space.
Definition: map.h:237
MSG_TYPE_MISC
#define MSG_TYPE_MISC
Messages that don't go elsewhere.
Definition: newclient.h:417
FLAG_APPLIED
#define FLAG_APPLIED
Object is ready for use by living.
Definition: define.h:235
NDI_BLUE
#define NDI_BLUE
Actually, it is Dodger Blue.
Definition: newclient.h:251
object::level
int16_t level
Level of creature or object.
Definition: object.h:361
FLAG_STEALTH
#define FLAG_STEALTH
Will wake monsters with less range.
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)
Execute an event on the specified object.
Definition: events.cpp:309
bow_bestarrow
@ bow_bestarrow
Try to find an arrow matching the target.
Definition: player.h:53
BALSL_MAX_LOSS_RATIO
#define BALSL_MAX_LOSS_RATIO
Definition: config.h:144
pticks
uint32_t pticks
Number of ticks since time reset.
Definition: time.cpp:47
GT_STARTEQUIP
@ GT_STARTEQUIP
Generated items have the FLAG_STARTEQUIP.
Definition: treasure.h:33
buf
StringBuffer * buf
Definition: readable.cpp:1565
hiscore_check
void hiscore_check(object *op, int quiet)
Checks if player should enter the hiscore, and if so writes her into the list.
Definition: hiscore.cpp:348
player::swap_first
int swap_first
First stat player has selected to swap.
Definition: player.h:166
getManager
AssetsManager * getManager()
Definition: assets.cpp:305
object_insert_in_ob
object * object_insert_in_ob(object *op, object *where)
This function inserts the object op in the linked list inside the object environment.
Definition: object.cpp:2842
HUGE_BUF
#define HUGE_BUF
Used for messages - some can be quite long.
Definition: define.h:37
MSG_TYPE_VICTIM
#define MSG_TYPE_VICTIM
Something bad is happening to the player.
Definition: newclient.h:419
MSG_TYPE_COMMAND
#define MSG_TYPE_COMMAND
Responses to commands, eg, who.
Definition: newclient.h:408
MAX
#define MAX(x, y)
Definition: compat.h:24
handle_newcs_player
int handle_newcs_player(object *op)
Handles commands the player can send us, and various checks on invisibility, golem and such.
Definition: player.cpp:3100
WISDOM
@ WISDOM
Definition: living.h:14
AT_DEATH
#define AT_DEATH
Definition: attack.h:93
object::resist
int16_t resist[NROFATTACKS]
Resistance adjustments for attacks.
Definition: object.h:351
FLAG_NO_PICK
#define FLAG_NO_PICK
Object can't be picked up.
Definition: define.h:239
MSG_TYPE_SPELL_END
#define MSG_TYPE_SPELL_END
A spell ends.
Definition: newclient.h:638
lose_msg
const char *const lose_msg[NUM_STATS]
Message when a player decreases permanently a stat.
Definition: living.cpp:172
name
Plugin animator file specs[Config] name
Definition: animfiles.txt:4
player_set_state
void player_set_state(player *pl, uint8_t state)
Set the player's state to the specified one.
Definition: player.cpp:4485
FLAG_IS_FLOOR
#define FLAG_IS_FLOOR
Can't see what's underneath this object.
Definition: define.h:302
FOR_BELOW_FINISH
#define FOR_BELOW_FINISH()
Finishes FOR_BELOW_PREPARE().
Definition: define.h:705
MIN_STAT
#define MIN_STAT
The minimum legal value of any stat.
Definition: define.h:33
draw_ext_info
vs only yadda is in because all tags get reset on the next draw_ext_info In the second since it is all in one draw_ext_info
Definition: media-tags.txt:61
FLAG_ALIVE
#define FLAG_ALIVE
Object can fight (or be fought)
Definition: define.h:230
add_statbonus
void add_statbonus(object *op)
Adds stat-bonuses given by the class which the player has chosen.
Definition: living.cpp:868
MSG_TYPE_MOTD
#define MSG_TYPE_MOTD
Definition: newclient.h:405
range_builder
@ range_builder
Map builder.
Definition: player.h:36
esrv_send_item
void esrv_send_item(object *pl, object *op)
Sends item's info to player.
Definition: main.cpp:354
rv_vector::distance_y
int distance_y
Y delta.
Definition: map.h:373
short_stat_name
const char *const short_stat_name[NUM_STATS]
Short name of stats.
Definition: living.cpp:194
MSG_TYPE_COMMAND_DEBUG
#define MSG_TYPE_COMMAND_DEBUG
Various debug type commands.
Definition: newclient.h:532
object::carrying
int32_t carrying
How much weight this object contains.
Definition: object.h:377
AP_NULL
#define AP_NULL
Nothing specific.
Definition: define.h:567
PU_GLOVES
#define PU_GLOVES
Definition: define.h:126
set_player_socket
void set_player_socket(player *p, socket_struct *ns)
This copies the data from the socket into the player structure.
Definition: player.cpp:421
remove_door
void remove_door(object *op)
Remove non locked doors.
Definition: time.cpp:38
object::y
int16_t y
Position in the map for this object.
Definition: object.h:335
PU_CONTAINER
#define PU_CONTAINER
Definition: define.h:143
m
static event_registration m
Definition: citylife.cpp:424
clear_los
void clear_los(player *pl)
Clears/initialises the los-array associated to the player controlling the object.
Definition: los.cpp:270
rv_vector::distance_x
int distance_x
X delta.
Definition: map.h:372
socket_struct::account_chars
Account_Chars * account_chars
Detailed information on characters on this account.
Definition: newserver.h:131
socket_struct::mapy
uint8_t mapy
How large a map the client wants.
Definition: newserver.h:120
MAP_IN_MEMORY
#define MAP_IN_MEMORY
Map is fully loaded.
Definition: map.h:126
Ns_Avail
@ Ns_Avail
Definition: newserver.h:69
object_free_drop_inventory
void object_free_drop_inventory(object *ob)
Frees everything allocated by an object, removes it from the list of used objects,...
Definition: object.cpp:1545
turn_one_transport
static int turn_one_transport(object *transport, object *captain, int dir)
Turn a transport to an adjacent direction (+1 or -1), updating the move_type flags in the same proces...
Definition: player.cpp:2859
object_update
void object_update(object *op, int action)
object_update() updates the array which represents the map.
Definition: object.cpp:1419
object::contr
struct player * contr
Pointer to the player which control this object.
Definition: object.h:284
get_party_password
int get_party_password(object *op, partylist *party)
Ask the player for the password of the party she wants to join.
Definition: player.cpp:1026
player_unready_range_ob
void player_unready_range_ob(player *pl, object *ob)
Unready an object for a player.
Definition: player.cpp:4467
object_find_by_name
object * object_find_by_name(const object *who, const char *name)
Finds an object in inventory name.
Definition: object.cpp:3941
PREFER_HIGH
#define PREFER_HIGH
Definition: define.h:557
object::chosen_skill
object * chosen_skill
The skill chosen to use.
Definition: object.h:396
object_decrease_nrof_by_one
#define object_decrease_nrof_by_one(xyz)
Definition: compat.h:32
MAX_SPACES
#define MAX_SPACES
This is used to prevent infinite loops.
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
If true, Death stat depletion based on level etc.
Definition: global.h:262
BALSL_NUMBER_LOSSES_RATIO
#define BALSL_NUMBER_LOSSES_RATIO
Definition: config.h:143
player::killer
char killer[BIG_NAME]
Who killed this player.
Definition: player.h:190
flee_player
static void flee_player(object *op)
The player is scared, and should flee.
Definition: player.cpp:1672
object::subtype
uint8_t subtype
Subtype of object.
Definition: object.h:349
MSG_TYPE_ATTRIBUTE_STAT_LOSS
#define MSG_TYPE_ATTRIBUTE_STAT_LOSS
Definition: newclient.h:573
FLAG_WAS_WIZ
#define FLAG_WAS_WIZ
Player was once a wiz.
Definition: define.h:234
MSG_TYPE_ADMIN_NEWS
#define MSG_TYPE_ADMIN_NEWS
Definition: newclient.h:499
is_criminal
bool is_criminal(object *op)
Definition: player.cpp:312
player::last_speed
float last_speed
Last speed as sent to client.
Definition: player.h:173
add_refcount
sstring add_refcount(sstring str)
This will increase the refcount of the string str.
Definition: shstr.cpp:210
check_race_and_class
int check_race_and_class(living *stats, archetype *race, archetype *opclass)
This checks to see if the race and class are legal.
Definition: player.cpp:1435
enter_player_savebed
void enter_player_savebed(object *op)
This is a basic little function to put the player back to his savebed.
Definition: server.cpp:142
PU_KEY
#define PU_KEY
Definition: define.h:128
determine_god
const char * determine_god(object *op)
Determines if op worships a god.
Definition: gods.cpp:55
MSG_TYPE_ATTRIBUTE_RACE
#define MSG_TYPE_ATTRIBUTE_RACE
Race-related changes.
Definition: newclient.h:568
freearr_y
short freearr_y[SIZEOFFREE]
Y offset when searching around a spot.
Definition: object.cpp:305
news
**Media tags please refer to the protocol file in doc Developers protocol Quick for your pleasure an example[/b][i] This is an old full of dirt and partially destroyed[hand] My dear as you two years i had to leave quickly Words have come to me of powerful magic scrolls discovered in an old temple by my uncle I have moved to study them I not forgot your knowledge in ancient languages I need your help for[print][b] Some parts of document are to damaged to be readable[/b][arcane] Arghis[color=Red] k h[color=dark slate blue] ark[color=#004000] fido[/color][hand] please come as fast as possible my friend[print][b] The bottom of letter seems deliberatly shredded What is but not limited book signs news
Definition: media-tags.txt:31
player::run_on
uint32_t run_on
Player should keep moving in dir until run is off.
Definition: player.h:143
object::anim_speed
uint8_t anim_speed
Ticks between animation-frames.
Definition: object.h:429
ST_CHANGE_PASSWORD_CONFIRM
#define ST_CHANGE_PASSWORD_CONFIRM
Player is confirming new password.
Definition: define.h:546
range_size
@ range_size
Maximum, exclusive, value.
Definition: player.h:37
move_ob
int move_ob(object *op, int dir, object *originator)
Op is trying to move in direction dir.
Definition: move.cpp:58
MSG_TYPE_APPLY_SUCCESS
#define MSG_TYPE_APPLY_SUCCESS
Was able to apply object.
Definition: newclient.h:607
query_name
void query_name(const object *op, char *buf, size_t size)
Describes an item.
Definition: item.cpp:594
player::blocked_los
int8_t blocked_los[MAP_CLIENT_X][MAP_CLIENT_Y]
Array showing what spaces the player can see.
Definition: player.h:178
POTION
@ POTION
Definition: object.h:116
find_player_options
player * find_player_options(const char *plname, int options, const mapstruct *map)
Find a player.
Definition: player.cpp:70
do_hidden_move
void do_hidden_move(object *op)
For hidden creatures - a chance of becoming 'unhidden' every time they move - as we subtract off 'inv...
Definition: player.cpp:4051
MOVE_WALK
#define MOVE_WALK
Object walks.
Definition: define.h:392
FLAG_KNOWN_CURSED
#define FLAG_KNOWN_CURSED
The object is known to be cursed.
Definition: define.h:320
pick_arrow_target
static object * pick_arrow_target(object *op, const char *type, int dir)
Looks in a given direction, finds the first valid target, and calls find_better_arrow() to find a dec...
Definition: player.cpp:2038
ST_PLAY_AGAIN
#define ST_PLAY_AGAIN
Player left through a bed of reality, and can login again.
Definition: define.h:536
treasurelist
treasurelist represents one logical group of items to be generated together.
Definition: treasure.h:85
player::ranges
object * ranges[range_size]
Object for each range.
Definition: player.h:116
action_makes_visible
static int action_makes_visible(object *op)
We call this when there is a possibility for our action disturbing our hiding place or invisibility s...
Definition: player.cpp:4212
ADD_PLAYER_NO_MAP
#define ADD_PLAYER_NO_MAP
Do not set the first map.
Definition: player.h:248
calc_skill_exp
int64_t calc_skill_exp(const object *who, const object *op, const object *skill)
Calculates amount of experience can be gained for successful use of a skill.
Definition: skill_util.cpp:667
Settings::motd
const char * motd
Name of the motd file.
Definition: global.h:279
account_char_free
void account_char_free(Account_Chars *chars)
This frees all data associated with the character information.
Definition: account_char.cpp:345
archetype::clone
object clone
An object from which to do object_copy()
Definition: object.h:487
fire_misc_object
static void fire_misc_object(object *op, int dir)
Fires a misc (wand/rod/horn) object in 'dir'.
Definition: player.cpp:2358
loot_object
static void loot_object(object *op)
Grab and destroy some treasure.
Definition: player.cpp:3429
object::run_away
uint8_t run_away
Monster runs away if it's hp goes below this percentage.
Definition: object.h:394
price_base
uint64_t price_base(const object *obj)
Price an item based on its value or archetype value, type, identification/BUC status,...
Definition: item.cpp:1510
party_leave
void party_leave(object *op)
Makes a player leave his party.
Definition: party.cpp:123
add_string
sstring add_string(const char *str)
This will add 'str' to the hash table.
Definition: shstr.cpp:124
player::delayed_buffers_used
uint8_t delayed_buffers_used
Used items in delayed_buffers_used.
Definition: player.h:225
account_remove_player
int account_remove_player(const char *account_name, const char *player_name)
Removes a player name from an account.
Definition: account.cpp:474
apply_anim_suffix
void apply_anim_suffix(object *who, const char *suffix)
Applies a compound animation to an object.
Definition: anim.cpp:150
first_map
mapstruct * first_map
First map.
Definition: init.cpp:107
FOR_OB_AND_BELOW_FINISH
#define FOR_OB_AND_BELOW_FINISH()
Finishes FOR_OB_AND_BELOW_PREPARE().
Definition: define.h:748
object_get_multi_size
void object_get_multi_size(const object *ob, int *sx, int *sy, int *hx, int *hy)
Computes the size of a multitile object.
Definition: object.cpp:4729
HEAD
#define HEAD(op)
Returns the head part of an object.
Definition: object.h:607
range_magic
@ range_magic
Spells.
Definition: player.h:32
apply_container
int apply_container(object *op, object *sack, int aflags)
Handle apply on containers.
Definition: apply.cpp:222
similar_direction
static int similar_direction(int a, int b)
Is direction a similar to direction b? Find out in this exciting function below.
Definition: player.cpp:2288
ROD
@ ROD
Definition: object.h:114
CONTAINER
@ CONTAINER
Definition: object.h:236
enter_player_maplevel
void enter_player_maplevel(object *op)
Move a player to its stored map level.
Definition: server.cpp:682
object::move_type
MoveType move_type
Type of movement this object uses.
Definition: object.h:436
query_short_name
void query_short_name(const object *op, char *buf, size_t size)
query_short_name(object) is similar to query_name(), but doesn't contain any information about object...
Definition: item.cpp:518
SockList_AddChar
void SockList_AddChar(SockList *sl, unsigned char c)
Adds an 8 bit value.
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)
Sets Str/Dex/con/Wis/Cha/Int/Pow in stats to value, depending on what attr is (STR to POW).
Definition: living.cpp:218
FLAG_FREED
#define FLAG_FREED
Object is in the list of free objects.
Definition: define.h:233
delete_character
void delete_character(const char *name)
Totally deletes a character.
Definition: login.cpp:88
player::last_path_attuned
uint32_t last_path_attuned
Last spell attunment sent to client.
Definition: player.h:160
LOCKED_DOOR
@ LOCKED_DOOR
Definition: object.h:128
MSG_TYPE_ITEM
#define MSG_TYPE_ITEM
Item related information.
Definition: newclient.h:416
object::face
const Face * face
Face with colors.
Definition: object.h:341
out_of_map
int out_of_map(mapstruct *m, int x, int y)
Return 1 if coordinates X and Y are out of the map M, taking into account tiling.
Definition: map.cpp:2324
player::last_character_flags
uint32_t last_character_flags
Last character flags (CS_STAT_CHARACTER_FLAGS) sent to client.
Definition: player.h:163
socket_struct::host
char * host
Which host it is connected from (ip address).
Definition: newserver.h:104
player::last_skill_exp
int64_t last_skill_exp[MAX_SKILLS]
Last exp sent to client.
Definition: player.h:154
SCRIPT_FIX_ALL
#define SCRIPT_FIX_ALL
Definition: global.h:380
MSG_TYPE_ATTACK
#define MSG_TYPE_ATTACK
Attack related messages.
Definition: newclient.h:413
FLAG_MAKE_INVIS
#define FLAG_MAKE_INVIS
(Item) gives invisibility when applied
Definition: define.h:328
Settings::rules
const char * rules
Name of rules file.
Definition: global.h:280
object::value
int32_t value
How much money it is worth (or contains)
Definition: object.h:360
SPECIAL_KEY
@ SPECIAL_KEY
Definition: object.h:129
MOVE_FLYING
#define MOVE_FLYING
Combo of fly_low and fly_high.
Definition: define.h:395
socket_struct::account_name
char * account_name
Name of the account logged in on this socket.
Definition: newserver.h:130
has_carried_lights
int has_carried_lights(const object *op)
Checks if op has a light source.
Definition: los.cpp:346
POWER
@ POWER
Definition: living.h:17
object_update_speed
void object_update_speed(object *op)
Updates the speed of an object.
Definition: object.cpp:1334
SPELL_HIGHEST
#define SPELL_HIGHEST
Definition: spells.h:60
player::levgrace
int8_t levgrace[11]
What grace bonus the player gained on that level.
Definition: player.h:188
object::last_anim
uint8_t last_anim
Last sequence used to draw face.
Definition: object.h:430
FREE_AND_COPY
#define FREE_AND_COPY(sv, nv)
Release the shared string if not NULL, and make it a reference to nv.
Definition: global.h:206
Settings::news
const char * news
Name of news file.
Definition: global.h:281
player::tmp_invis
uint32_t tmp_invis
Will invis go away when we attack?
Definition: player.h:140
object::type
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:348
FLAG_DAMNED
#define FLAG_DAMNED
The object is very cursed.
Definition: define.h:317
living::dam
int16_t dam
How much damage this object does when hitting.
Definition: living.h:46
object::magic
int8_t magic
Any magical bonuses to this item.
Definition: object.h:358
do_some_living
void do_some_living(object *op)
Regenerate hp/sp/gr, decreases food.
Definition: player.cpp:3290
bow_nw
@ bow_nw
Fire north-west whatever the facing direction.
Definition: player.h:52
treasure::item
struct archetype * item
Which item this link can be.
Definition: treasure.h:64
FLAG_PARALYZED
#define FLAG_PARALYZED
Monster or player is paralyzed.
Definition: define.h:371
Settings::stat_loss_on_death
uint8_t stat_loss_on_death
If true, chars lose a random stat when they die.
Definition: global.h:257
object::materialname
sstring materialname
Specific material name.
Definition: object.h:356
gravestone_text
static const char * gravestone_text(object *op, char *buf2, int len)
Create a text for a player's gravestone.
Definition: player.cpp:3251
FLAG_USE_SHIELD
#define FLAG_USE_SHIELD
Can this creature use a shield?
Definition: define.h:237
hideability
int hideability(object *ob)
Look at the surrounding terrain to determine the hideability of this object.
Definition: player.cpp:4010
leave
void leave(player *pl, int draw_exit)
Player logs out, or was disconnected.
Definition: server.cpp:1303
object_free
void object_free(object *ob, int flags)
Frees everything allocated by an object, removes it from the list of used objects,...
Definition: object.cpp:1577
GET_MAP_MOVE_BLOCK
#define GET_MAP_MOVE_BLOCK(M, X, Y)
Gets the blocking state of a square.
Definition: map.h:192
FOR_INV_FINISH
#define FOR_INV_FINISH()
Finishes FOR_INV_PREPARE().
Definition: define.h:671
find_player
player * find_player(const char *plname)
Find a player by her full name.
Definition: player.cpp:59
FLAG_CAN_ROLL
#define FLAG_CAN_ROLL
Object can be rolled.
Definition: define.h:254
find_arrow
static object * find_arrow(object *op, const char *type)
Find an arrow in the inventory and after that in the right type container (quiver).
Definition: player.cpp:1936
kill_player_not_permadeath
static void kill_player_not_permadeath(object *op)
Kills a player in non-permadeath mode.
Definition: player.cpp:3587
object::move_on
MoveType move_on
Move types affected moving on to this space.
Definition: object.h:439
living::food
int32_t food
How much food in stomach.
Definition: living.h:48
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)
Changes experience to a player/monster.
Definition: living.cpp:2179
FLAG_UNAGGRESSIVE
#define FLAG_UNAGGRESSIVE
Monster doesn't attack players.
Definition: define.h:272
tag_t
uint32_t tag_t
Object tag, unique during the whole game.
Definition: object.h:14
archetype
The archetype structure is a set of rules on how to generate and manipulate objects which point to ar...
Definition: object.h:483
display_motd
void display_motd(const object *op)
Sends the message of the day to the player.
Definition: player.cpp:139
player::shoottype
rangetype shoottype
Which range-attack is being used by player.
Definition: player.h:112
object_matches_string
int object_matches_string(object *pl, object *op, const char *name)
This is a subset of the parse_id command.
Definition: object.cpp:4559
PU_MELEEWEAPON
#define PU_MELEEWEAPON
Definition: define.h:131
ATNR_POISON
#define ATNR_POISON
Definition: attack.h:59
Settings::confdir
const char * confdir
Configuration files.
Definition: global.h:248
FLAG_USE_WEAPON
#define FLAG_USE_WEAPON
(Monster) can wield weapons
Definition: define.h:296
sproto.h
player::last_weight_limit
int32_t last_weight_limit
Last weight limit transmitted to client.
Definition: player.h:159
drain_msg
const char *const drain_msg[NUM_STATS]
Message when a player is drained of a stat.
Definition: living.cpp:139
ARROW
@ ARROW
Definition: object.h:122
EVENT_PLAYER_DEATH
#define EVENT_PLAYER_DEATH
Global Death event
Definition: events.h:66
FLAG_NO_DROP
#define FLAG_NO_DROP
Object can't be dropped.
Definition: define.h:288
IS_SHIELD
#define IS_SHIELD(op)
Definition: define.h:170
living::sp
int16_t sp
Spell points.
Definition: living.h:42
MAX_SKILLS
#define MAX_SKILLS
This is the maximum number of skills the game may handle.
Definition: skills.h:70
FIND_PLAYER_PARTIAL_NAME
#define FIND_PLAYER_PARTIAL_NAME
Find on partial name.
Definition: player.h:237
get_map_from_coord
mapstruct * get_map_from_coord(mapstruct *m, int16_t *x, int16_t *y)
This is basically the same as out_of_map above(), but instead we return NULL if no map is valid (coor...
Definition: map.cpp:2352
AC_PLAYER_STAT_NO_CHANGE
#define AC_PLAYER_STAT_NO_CHANGE
Definition: define.h:591
FLAG_CAN_USE_SKILL
#define FLAG_CAN_USE_SKILL
The monster can use skills.
Definition: define.h:321
AssetsCollection::each
void each(std::function< void(T *)> op)
Apply a function to each asset.
Definition: AssetsCollection.h:158
PU_MAGICAL
#define PU_MAGICAL
Definition: define.h:132
DETOUR_AMOUNT
#define DETOUR_AMOUNT
This value basically determines how large a detour a monster will take from the direction path when l...
Definition: player.cpp:611
EVENT_BORN
#define EVENT_BORN
A new character has been created.
Definition: events.h:52
FOR_OB_AND_BELOW_PREPARE
#define FOR_OB_AND_BELOW_PREPARE(op_)
Constructs a loop iterating over an object and all objects below it in the same pile.
Definition: define.h:744
MSG_TYPE_SPELL
#define MSG_TYPE_SPELL
Spell related info.
Definition: newclient.h:415
get_rangevector_from_mapcoord
int get_rangevector_from_mapcoord(const mapstruct *m, int x, int y, const object *op2, rv_vector *retval)
This is basically the same as get_rangevector() above, but instead of the first parameter being an ob...
Definition: map.cpp:2591
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)
Scales the spellpoint cost of a spell by it's increased effectiveness.
Definition: spell_util.cpp:236
delete_map
void delete_map(mapstruct *m)
Frees the map, including the mapstruct.
Definition: map.cpp:1706
random_roll
int random_roll(int min, int max, const object *op, int goodbad)
Roll a random number between min and max.
Definition: utils.cpp:42
MSG_SUBTYPE_NONE
#define MSG_SUBTYPE_NONE
Definition: newclient.h:424
object::race
sstring race
Human, goblin, dragon, etc.
Definition: object.h:326
object::facing
int8_t facing
Object is oriented/facing that way.
Definition: object.h:345
object::animation
const Animations * animation
Animation of this item, NULL if not animated.
Definition: object.h:428
player::maplevel
char maplevel[MAX_BUF]
On which level is the player?
Definition: player.h:109
player::fire_on
uint32_t fire_on
Player should fire object, not move.
Definition: player.h:142
get_dam_bonus
int get_dam_bonus(int stat)
Definition: living.cpp:2389
DEXTERITY
@ DEXTERITY
Definition: living.h:12
SockList_Init
void SockList_Init(SockList *sl)
Initializes the SockList instance.
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)
Returns true if the given object can't fit in the given spot.
Definition: map.cpp:489
receive_play_again
void receive_play_again(object *op, char key)
Player replied to play again / disconnect.
Definition: player.cpp:961
object_find_by_type_without_flags
object * object_find_by_type_without_flags(const object *who, int type, int *flags, int num_flags)
Find an object in inventory that does not have any of the provided flags set.
Definition: object.cpp:3989
player::last_item_power
uint16_t last_item_power
Last value for 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)
Same as object_insert_in_map() except it handle separate coordinates and do a clean job preparing mul...
Definition: object.cpp:2085
living
Various statistics of objects.
Definition: living.h:35
treasure::next
treasure * next
Next treasure-item in a linked list.
Definition: treasure.h:69
FLAG_MONSTER
#define FLAG_MONSTER
Will attack players.
Definition: define.h:245
fire
void fire(object *op, int dir)
Received a fire command for the player - go and do it.
Definition: player.cpp:2410
push_ob
int push_ob(object *who, int dir, object *pusher)
Something is pushing some other object.
Definition: move.cpp:434
key_inventory
@ key_inventory
Only use keys in inventory.
Definition: player.h:66
fatal
void fatal(enum fatal_error err)
fatal() is meant to be called whenever a fatal signal is intercepted.
Definition: utils.cpp:590
find_skill_by_name
object * find_skill_by_name(object *who, const char *name)
This returns the skill pointer of the given name (the one that accumulates exp, has the level,...
Definition: skill_util.cpp:211
player::last_skill_ob
object * last_skill_ob[MAX_SKILLS]
Exp objects sent to client.
Definition: player.h:153
apply_death_exp_penalty
void apply_death_exp_penalty(object *op)
Applies a death penalty experience, the size of this is defined by the settings death_penalty_percent...
Definition: living.cpp:2244
get_dex_bonus
int get_dex_bonus(int stat)
Definition: living.cpp:2365
P_OUT_OF_MAP
#define P_OUT_OF_MAP
This space is outside the map.
Definition: map.h:249
move_player_attack
void move_player_attack(object *op, int dir)
The player is also actually going to try and move (not fire weapons).
Definition: player.cpp:2637
AssetsManager::archetypes
Archetypes * archetypes()
Get archetypes.
Definition: AssetsManager.h:44
env
static std::shared_ptr< inja::Environment > env
Rendering environment.
Definition: mapper.cpp:2222
EXIT_X
#define EXIT_X(xyz)
Definition: define.h:435
MAX_BUF
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
player::last_weight
int32_t last_weight
Last weight as sent to client; -1 means do not send weight.
Definition: player.h:158
Ns_Add
@ Ns_Add
Definition: newserver.h:70
player::listening
uint8_t listening
Which priority will be used in info_all.
Definition: player.h:133
strlcpy
size_t strlcpy(char *dst, const char *src, size_t size)
Portable implementation of strlcpy(3).
Definition: porting.cpp:222
object_new
object * object_new(void)
Grabs an object from the list of unused objects, makes sure it is initialised, and returns it.
Definition: object.cpp:1258
is_wraith_pl
int is_wraith_pl(object *op)
Tests if a player is a wraith.
Definition: player.cpp:173
ADD_PLAYER_NEW
#define ADD_PLAYER_NEW
Name/password provided, so skip to roll stats.
Definition: player.h:247
create_archetype
object * create_archetype(const char *name)
Finds which archetype matches the given name, and returns a new object containing a copy of the arche...
Definition: arch.cpp:276
player::orig_stats
living orig_stats
Permanent real stats of player.
Definition: player.h:167
IS_WEAPON
#define IS_WEAPON(op)
Definition: define.h:163
cast_dust
void cast_dust(object *op, object *throw_ob, int dir)
Handles op throwing objects of type 'DUST'.
Definition: player.cpp:3945
object::weight
int32_t weight
Attributes of the object.
Definition: object.h:375
free_string
void free_string(sstring str)
This will reduce the refcount, and if it has reached 0, str will be freed.
Definition: shstr.cpp:280
transfer_ob
int transfer_ob(object *op, int x, int y, int randomly, object *originator)
Move an object (even linked objects) to another spot on the same map.
Definition: move.cpp:163
set_first_map
void set_first_map(object *op)
This loads the first map an puts the player on it.
Definition: player.cpp:402
living::wc
int8_t wc
Weapon Class, lower WC increases probability of hitting.
Definition: living.h:37
key_confirm_quit
void key_confirm_quit(object *op, char key)
We receive the reply to the 'quit confirmation' message.
Definition: player.cpp:1599
player::unapply
unapplymode unapply
Method for auto unapply.
Definition: player.h:121
offsetof
#define offsetof(type, member)
The offsetof macro is part of ANSI C, but many compilers lack it, for example "gcc -ansi".
Definition: shstr.h:37
remove_unpaid_objects
void remove_unpaid_objects(object *op, object *env, int free_items)
This goes throws the inventory and removes unpaid objects, and puts them back in the map (location an...
Definition: player.cpp:3221
Settings::playerdir
const char * playerdir
Where the player files are.
Definition: global.h:251
RANDOM
#define RANDOM()
Definition: define.h:638
SockList_Term
void SockList_Term(SockList *sl)
Frees all resources allocated by a SockList instance.
Definition: lowlevel.cpp:65
SK_HIDING
@ SK_HIDING
Hiding.
Definition: skills.h:21
FREE_AND_CLEAR_STR
#define FREE_AND_CLEAR_STR(xyz)
Release the shared string, and set it to NULL.
Definition: global.h:200
MOVE_FLY_LOW
#define MOVE_FLY_LOW
Low flying object.
Definition: define.h:393
dead_player
void dead_player(object *op)
Kill a player on a permanent death server with resurrection.
Definition: resurrection.cpp:297
ATNR_FIRE
#define ATNR_FIRE
Definition: attack.h:51
player::gen_sp_armour
int16_t gen_sp_armour
Penalty to sp regen from armour.
Definition: player.h:128
living::maxgrace
int16_t maxgrace
Maximum grace.
Definition: living.h:45
MSG_TYPE_ITEM_ADD
#define MSG_TYPE_ITEM_ADD
Item added to inventory.
Definition: newclient.h:647
is_valid_types_gen.found
found
Definition: is_valid_types_gen.py:39
player::search_str
char search_str[MAX_BUF]
Item we are looking for.
Definition: player.h:211
MSG_TYPE_COMMAND_FAILURE
#define MSG_TYPE_COMMAND_FAILURE
Failed result from command.
Definition: newclient.h:535
FOR_MAP_PREPARE
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Constructs a loop iterating over all objects of a map tile.
Definition: define.h:717
key_change_class
void key_change_class(object *op, char key)
This function takes the key that is passed, and does the appropriate action with it (change race,...
Definition: player.cpp:1294
FLAG_KNOWN_MAGICAL
#define FLAG_KNOWN_MAGICAL
The object is known to be magical.
Definition: define.h:319
stand_near_hostile
int stand_near_hostile(object *who)
Determine if who is standing near a hostile creature.
Definition: player.cpp:4092
FIND_PLAYER_NO_HIDDEN_DM
#define FIND_PLAYER_NO_HIDDEN_DM
Don't find hidden DMs.
Definition: player.h:238
OUT_OF_REAL_MAP
#define OUT_OF_REAL_MAP(M, X, Y)
Checks if a square is out of the map.
Definition: map.h:217
ST_PLAYING
#define ST_PLAYING
Usual state.
Definition: define.h:535
player::gen_hp
int16_t gen_hp
Bonuses to regeneration speed of hp.
Definition: player.h:126
roll_stat
int roll_stat(void)
This rolls four 1-6 rolls and sums the best 3 of the 4.
Definition: player.cpp:1043
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
Misc items.
Definition: player.h:33
FLAG_READY_SKILL
#define FLAG_READY_SKILL
(Monster or Player) has a skill readied
Definition: define.h:333
FLAG_READY_BOW
#define FLAG_READY_BOW
not implemented yet
Definition: define.h:299
sounds.h
FLAG_REMOVED
#define FLAG_REMOVED
Object is not in any map or invenory.
Definition: define.h:232
ST_CHANGE_CLASS
#define ST_CHANGE_CLASS
New character, choosing class.
Definition: define.h:538
treasure::magic
uint8_t magic
Max magic bonus to item If the entry is a list transition, 'magic' contains the difficulty required t...
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)
Find object in inventory by type and slaying.
Definition: object.cpp:4143
FLAG_WIZ
#define FLAG_WIZ
Object has special privilegies.
Definition: define.h:231
Settings::emergency_mapname
char * emergency_mapname
Map to return players to in emergency.
Definition: global.h:300
NDI_UNIQUE
#define NDI_UNIQUE
Print immediately, don't buffer.
Definition: newclient.h:266
object::slaying
sstring slaying
Which race to do double damage to.
Definition: object.h:327
FLAG_FRIENDLY
#define FLAG_FRIENDLY
Will help players.
Definition: define.h:246
spells.h
object::name
sstring name
The name of the object, obviously...
Definition: object.h:319
ob_process
method_ret ob_process(object *op)
Processes an object, giving it the opportunity to move or react.
Definition: ob_methods.cpp:67
PU_CLOAK
#define PU_CLOAK
Definition: define.h:127
BATTLEGROUND
@ BATTLEGROUND
battleground, by Andreas Vogl
Definition: object.h:168
MSG_TYPE_SKILL_FAILURE
#define MSG_TYPE_SKILL_FAILURE
Failure in using skill.
Definition: newclient.h:594
pet_normal
@ pet_normal
Standard mode/.
Definition: player.h:58
player::has_hit
uint32_t has_hit
If set, weapon_sp instead of speed will count.
Definition: player.h:144
object_find_by_arch_name
object * object_find_by_arch_name(const object *who, const char *name)
Find object in inventory by archetype name.
Definition: object.cpp:4237
party_get_password
const char * party_get_password(const partylist *party)
Returns the party's password.
Definition: party.cpp:232
player::party_to_join
partylist * party_to_join
Used when player wants to join a party but we will have to get password first so we have to remember ...
Definition: player.h:204
get_thaco_bonus
int get_thaco_bonus(int stat)
Definition: living.cpp:2369
i18n_get_language_by_code
language_t i18n_get_language_by_code(const char *code)
Find the identifier of a language from its code.
Definition: languages.cpp:74
object_can_pick
int object_can_pick(const object *who, const object *item)
Finds out if an object can be picked up.
Definition: object.cpp:3852
players
std::vector< archetype * > players
Definition: player.cpp:501
add_friendly_object
void add_friendly_object(object *op)
Add a new friendly object to the list of friendly objects.
Definition: friend.cpp:32
key_roll_stat
void key_roll_stat(object *op, char key)
Player is currently swapping stats.
Definition: player.cpp:1218
ST_CONFIRM_PASSWORD
#define ST_CONFIRM_PASSWORD
New character, confirm password.
Definition: define.h:542
IS_ARMOR
#define IS_ARMOR(op)
Definition: define.h:166
unapply_nochoice
@ unapply_nochoice
Will unapply objects when there no choice to unapply.
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)
This rolls up wall, blocks_magic, blocks_view, etc, all into one function that just returns a P_.
Definition: map.cpp:300
object_find_by_type
object * object_find_by_type(const object *who, int type)
Find object in inventory.
Definition: object.cpp:3965
SOUND_TYPE_GROUND
#define SOUND_TYPE_GROUND
Definition: newclient.h:340
FLAG_USE_ARMOUR
#define FLAG_USE_ARMOUR
(Monster) can wear armour/shield/helmet
Definition: define.h:295
PU_JEWELS
#define PU_JEWELS
Definition: define.h:141
MSG_TYPE_ITEM_REMOVE
#define MSG_TYPE_ITEM_REMOVE
Item removed from inv.
Definition: newclient.h:646
living::maxsp
int16_t maxsp
Max spell points.
Definition: living.h:43
is_identifiable_type
int is_identifiable_type(const object *op)
Return true if this item's type is one that cares about whether or not it's been identified – e....
Definition: item.cpp:1336
change_attr_value
void change_attr_value(living *stats, int attr, int8_t value)
Like set_attr_value(), but instead the value (which can be negative) is added to the specified stat.
Definition: living.cpp:264
mapstruct
This is a game-map.
Definition: map.h:315
enter_exit
void enter_exit(object *op, object *exit_ob)
Tries to move 'op' to exit_ob.
Definition: server.cpp:727
check_spell_known
object * check_spell_known(object *op, const char *name)
Checks to see if player knows the spell.
Definition: spell_util.cpp:394
living::Cha
int8_t Cha
Definition: living.h:36
NDI_ALL
#define NDI_ALL
Inform all players of this message.
Definition: newclient.h:267
socket_struct::status
enum Sock_Status status
Definition: newserver.h:94
fire_bow
int fire_bow(object *op, object *arrow, int dir, int wc_mod, int16_t sx, int16_t sy)
Creature (monster or player) fires a bow.
Definition: player.cpp:2107
save_life
static int save_life(object *op)
Can the player be saved by an item?
Definition: player.cpp:3178
STRENGTH
@ STRENGTH
Definition: living.h:11
object::skill
sstring skill
Name of the skill this object uses/grants.
Definition: object.h:329
animate_object
void animate_object(object *op, int dir)
Updates the face-variable of an object.
Definition: anim.cpp:44
player::language
language_t language
The language the player wishes to use.
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)
object_split(ob,nr) splits up ob into two parts.
Definition: object.cpp:2622
player::state
uint8_t state
Input state of the player (name, password, etc).
Definition: player.h:131
EXIT_ALT_X
#define EXIT_ALT_X(xyz)
Definition: define.h:437
MSG_TYPE_ATTRIBUTE_GOD
#define MSG_TYPE_ATTRIBUTE_GOD
changing god info
Definition: newclient.h:579
dragon_ability_gain
void dragon_ability_gain(object *who, int atnr, int level)
When a dragon-player gains a new stage of evolution, he gets some treasure.
Definition: player.cpp:4309
shop_contains
bool shop_contains(object *ob)
Check if an object is in a shop.
Definition: map.cpp:2764
mapstruct::in_memory
uint32_t in_memory
Combination of IN_MEMORY_xxx flags.
Definition: map.h:335
change_luck
void change_luck(object *op, int value)
Alter the object's luck.
Definition: living.cpp:796
restore_player
static void restore_player(object *op)
Remove confusion, disease, and poison on death.
Definition: player.cpp:3468
player::braced
uint32_t braced
Will not move if braced, only attack.
Definition: player.h:139
PU_ARMOUR
#define PU_ARMOUR
Definition: define.h:123
object_set_msg
void object_set_msg(object *op, const char *msg)
Set the message field of an object.
Definition: object.cpp:4796
esrv_update_item
void esrv_update_item(int flags, object *pl, object *op)
Updates object *op for player *pl.
Definition: main.cpp:359
did_make_save
int did_make_save(const object *op, int level, int bonus)
This function takes an object (monster/player, op), and determines if it makes a basic save throw by ...
Definition: living.cpp:2293
send_rules
void send_rules(const object *op)
Send the rules to a player.
Definition: player.cpp:170
Settings::max_stat
uint8_t max_stat
Maximum stat value - 255 should be sufficient.
Definition: global.h:325
SPELL_EFFECT
@ SPELL_EFFECT
Definition: object.h:220
object::msg
sstring msg
If this is a book/sign/magic mouth/etc.
Definition: object.h:330
PU_NEWMODE
#define PU_NEWMODE
Definition: define.h:111
rv_vector
This is used by get_rangevector to determine where the other creature is.
Definition: map.h:370
MSG_TYPE_ADMIN_RULES
#define MSG_TYPE_ADMIN_RULES
Definition: newclient.h:498
SKILL_TOOL
@ SKILL_TOOL
Allows the use of a skill.
Definition: object.h:194
send_news
void send_news(const object *op)
Send the news to a player.
Definition: player.cpp:206
EXIT_Y
#define EXIT_Y(xyz)
Definition: define.h:436
get_randomized_dir
int get_randomized_dir(int dir)
Returns a random direction (1..8) similar to a given direction.
Definition: utils.cpp:412
FLAG_BEEN_APPLIED
#define FLAG_BEEN_APPLIED
Object was ever applied, for identification purposes.
Definition: define.h:323
assets.h
CLEAR_FLAG
#define CLEAR_FLAG(xyz, p)
Definition: define.h:225
NDI_BROWN
#define NDI_BROWN
Sienna.
Definition: newclient.h:257
AP_NOPRINT
#define AP_NOPRINT
Don't print messages - caller will do that may be some that still print.
Definition: define.h:579
living::ac
int8_t ac
Armor Class, lower AC increases probability of not getting hit.
Definition: living.h:38
SockList_ResetRead
void SockList_ResetRead(SockList *sl)
Resets the length of the stored data for reading.
Definition: lowlevel.cpp:83
NDI_DK_ORANGE
#define NDI_DK_ORANGE
DarkOrange2.
Definition: newclient.h:252
strip_endline
void strip_endline(char *buf)
Removes endline from buffer (modified in place).
Definition: utils.cpp:314
bow_n
@ bow_n
Fire north whatever the facing direction.
Definition: player.h:45
die_roll
int die_roll(int num, int size, const object *op, int goodbad)
Roll a number of dice (2d3, 4d6).
Definition: utils.cpp:122
socket_struct::faces_sent
uint8_t * faces_sent
This is a bitmap on sent face status.
Definition: newserver.h:100
get_password
void get_password(object *op)
Waiting for the player's password.
Definition: player.cpp:897
player::last_resist
int16_t last_resist[NROFATTACKS]
last resist values sent to client.
Definition: player.h:174
arch_to_object
object * arch_to_object(archetype *at)
Creates and returns a new object which is a copy of the given archetype.
Definition: arch.cpp:227
stats
Player Stats effect how well a character can survie and interact inside the crossfire world This section discusses the various stats
Definition: stats.txt:2
level
int level
Definition: readable.cpp:1563
get_rangevector
int get_rangevector(object *op1, const object *op2, rv_vector *retval, int flags)
From map.c This is used by get_player to determine where the other creature is.
Definition: map.cpp:2523
player::party
partylist * party
Party this player is part of.
Definition: player.h:203
keyrings
@ keyrings
Use keys in inventory and active key rings.
Definition: player.h:67
play_again
void play_again(object *op)
Ask the player whether to play again or disconnect.
Definition: player.cpp:908
get_player
player * get_player(player *p)
Create a player's object, initialize a player's structure.
Definition: player.cpp:285
MSG_TYPE_ADMIN_LOGIN
#define MSG_TYPE_ADMIN_LOGIN
login messages/errors
Definition: newclient.h:504
FLAG_ANIMATE
#define FLAG_ANIMATE
The object looks at archetype for faces.
Definition: define.h:242
MSG_TYPE_ATTRIBUTE_BAD_EFFECT_END
#define MSG_TYPE_ATTRIBUTE_BAD_EFFECT_END
End of a bad effect.
Definition: newclient.h:571
object::randomitems
struct treasurelist * randomitems
Items to be generated.
Definition: object.h:395
newclient.h
fix_luck
void fix_luck(void)
Fixes luck of players, slowly move it towards 0.
Definition: player.cpp:3924
save_player
int save_player(object *op, int flag)
Saves a player to disk.
Definition: login.cpp:239
ST_GET_PARTY_PASSWORD
#define ST_GET_PARTY_PASSWORD
Player tried to join a password-protected party.
Definition: define.h:543
object_matches_pickup_mode
int object_matches_pickup_mode(const object *item, int mode)
Checks if an item matches a specific pickup mode.
Definition: c_object.cpp:658
FOOD
@ FOOD
Definition: object.h:117
object::container
object * container
Current container being used.
Definition: object.h:299
skill
skill
Definition: arch-handbook.txt:585
player::delayed_buffers_allocated
uint8_t delayed_buffers_allocated
Number of items in delayed_buffers_used.
Definition: player.h:224
object_remove
void object_remove(object *op)
This function removes the object op from the linked list of objects which it is currently tied to.
Definition: object.cpp:1818
cure_disease
int cure_disease(object *sufferer, object *caster, sstring skill)
Do the cure disease stuff, from the spell "cure disease".
Definition: disease.cpp:685
a
Magical Runes Runes are magical inscriptions on the dungeon which cast a spell or detonate when something steps on them Flying objects don t detonate runes Beware ! Runes are invisible most of the time They are only visible occasionally ! There are several runes which are there are some special runes which may only be called with the invoke and people may apply it to read it Maybe useful for mazes ! This rune will not nor is it ordinarily invisible Partial Visibility of they ll be visible only part of the time They have a(your level/2) chance of being visible in any given round
DOOR
@ DOOR
Definition: object.h:131
object_sum_weight
signed long object_sum_weight(object *op)
object_sum_weight() is a recursive function which calculates the weight an object is carrying.
Definition: object.cpp:553
FLAG_UNPAID
#define FLAG_UNPAID
Object hasn't been paid for yet.
Definition: define.h:236
FLAG_NO_STRENGTH
#define FLAG_NO_STRENGTH
Strength-bonus not added to wc/dam.
Definition: define.h:306
player::last_path_repelled
uint32_t last_path_repelled
Last spell repelled sent to client.
Definition: player.h:161
PU_NOTHING
#define PU_NOTHING
Definition: define.h:106
OB_TYPE_MOVE_BLOCK
#define OB_TYPE_MOVE_BLOCK(ob1, type)
Basic macro to see if if ob1 can not move onto a space based on the 'type' move_block parameter Add c...
Definition: define.h:426
move_player
int move_player(object *op, int dir)
Move player in the given direction.
Definition: player.cpp:2962
socket_struct::login_method
uint8_t login_method
Login method this client is using.
Definition: newserver.h:132
remove_statbonus
void remove_statbonus(object *op)
Subtracts stat-bonuses given by the class which the player has chosen.
Definition: living.cpp:845
MSG_TYPE_ATTACK_NOATTACK
#define MSG_TYPE_ATTACK_NOATTACK
You avoid attacking.
Definition: newclient.h:622
object::spellarg
char * spellarg
Optional argument when casting obj::spell.
Definition: object.h:421
make_path_to_file
void make_path_to_file(const char *filename)
Checks if any directories in the given path doesn't exist, and creates if necessary.
Definition: porting.cpp:164
DRINK
@ DRINK
Definition: object.h:162
PU_CURSED
#define PU_CURSED
Definition: define.h:144
player::password
char password[16]
2 (seed) + 11 (crypted) + 1 (EOS) + 2 (safety) = 16
Definition: player.h:193
find_player_partial_name
player * find_player_partial_name(const char *plname)
Find a player by a partial name.
Definition: player.cpp:114
object::state
uint8_t state
How the object was last drawn (animation)
Definition: object.h:359
roll_stats
void roll_stats(object *op)
Roll the initial player's statistics.
Definition: player.cpp:1067
ATNR_COLD
#define ATNR_COLD
Definition: attack.h:53
archetype::name
sstring name
More definite name, like "generate_kobold".
Definition: object.h:484
object::nrof
uint32_t nrof
Number of objects.
Definition: object.h:342
FLAG_XRAYS
#define FLAG_XRAYS
X-ray vision.
Definition: define.h:300
player::socket
socket_struct * socket
Socket information for this player.
Definition: player.h:107
mapstruct::next
mapstruct * next
Next map, linked list.
Definition: map.h:316
living::grace
int16_t grace
Grace.
Definition: living.h:44
add_player
player * add_player(socket_struct *ns, int flags)
Tries to add player on the connection passwd in ns.
Definition: player.cpp:468
query_base_name
void query_base_name(const object *op, int plural, char *buf, size_t size)
Query a short name for the item.
Definition: item.cpp:695
Settings::search_items
uint8_t search_items
Search_items command.
Definition: global.h:268
object::stats
living stats
Str, Con, Dex, etc.
Definition: object.h:378
treasure
treasure is one element in a linked list, which together consist of a complete treasure-list.
Definition: treasure.h:63
list
How to Install a Crossfire Server on you must install a python script engine on your computer Python is the default script engine of Crossfire You can find the python engine you have only to install them The VisualC Crossfire settings are for but you habe then to change the pathes in the VC settings Go in Settings C and Settings Link and change the optional include and libs path to the new python installation path o except the maps ! You must download a map package and install them the share folder Its must look like doubleclick on crossfire32 dsw There are projects in your libcross lib and plugin_python You need to compile all Easiest way is to select the plugin_python ReleaseLog as active this will compile all others too Then in Visual C press< F7 > to compile If you don t have an appropriate compiler you can try to get the the VC copies the crossfire32 exe in the crossfire folder and the plugin_python dll in the crossfire share plugins folder we will remove it when we get time for it o Last showing lots of weird write to the Crossfire mailing list
Definition: INSTALL_WIN32.txt:50
player::title
char title[BIG_NAME]
Default title, like fighter, wizard, etc.
Definition: player.h:184
object::more
object * more
Pointer to the rest of a large body of objects.
Definition: object.h:303
get_attr_value
int8_t get_attr_value(const living *stats, int attr)
Gets the value of a stat.
Definition: living.cpp:313
drain_rod_charge
void drain_rod_charge(object *rod)
Drain charges from a rod.
Definition: spell_util.cpp:776
range_skill
@ range_skill
Use skill.
Definition: player.h:35
server.h
freearr_x
short freearr_x[SIZEOFFREE]
X offset when searching around a spot.
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)
Player is "attacking" a door.
Definition: player.cpp:2564
bonus
Player Stats effect how well a character can survie and interact inside the crossfire world This section discusses the various what they and how they effect the player s actions Also in this section are the stat modifiers that specific classes professions bring Player and sps the current and maximum the Current and Maximum The Current Sp can go somewhat negative When Sp is negative not all spells can be and a more negative Sp makes spell casting less likey to succeed can affect Damage and how the characters as well as how often the character can attack this affects the prices when buying and selling items if this drops the player will start losing hit points wd Cleric or Dwarf sm Elf wd Fireborn ft Human ra Mage C Monk se Ninja hi Priest C Quetzalcoatl mw Swashbuckler si Thief st Viking ba Warrior or Wizard C Wraith C Class Prof Str Dex Con Wis Cha Int Pow Net Skills Enclosed are codes used for the skills above The ones in and fighting should all be pretty self explanatory For the other a brief description is for a more detailed look at the skills doc file Skill remove use magic items phys no fire cold Fireborns are supposed to be fire spirits They re closely in tune with magic and are powerful and learn magic easily Being fire they are immune to fire and and vulnerable to cold They are vulnerable to ghosthit and drain because being mostly non anything which strikes directly at the spirit hits them harder race attacktype restrictions immunities prot vuln Quetzalcoatl physical no armour fire cold Quetzalcoatl s are now born knowing the spell of burning but because of their negative wisdom bonus
Definition: stats.txt:176
INTELLIGENCE
@ INTELLIGENCE
Definition: living.h:16
player::petmode
petmode_t petmode
Which petmode?
Definition: player.h:115
swap_stat
static void swap_stat(object *op, int swap_second)
Player finishes selecting what stats to swap.
Definition: player.cpp:1160
TRUE
#define TRUE
Definition: compat.h:11
player::last_weapon_sp
float last_weapon_sp
if diff than weapon_sp, update client.
Definition: player.h:156
ATNR_ELECTRICITY
#define ATNR_ELECTRICITY
Definition: attack.h:52
ST_ROLL_STAT
#define ST_ROLL_STAT
New character, rolling stats.
Definition: define.h:537
clear_player
void clear_player(player *pl)
Clears data in player structure.
Definition: player.cpp:33
pets_control_golem
void pets_control_golem(object *op, int dir)
Makes the golem go in specified direction.
Definition: pets.cpp:643
player::invis_race
const char * invis_race
What race invisible to?
Definition: player.h:151
PU_SHIELD
#define PU_SHIELD
Definition: define.h:122
SPELL
@ SPELL
Definition: object.h:219
player::spellparam
char spellparam[MAX_BUF]
What param to add to spells.
Definition: player.h:113
link_player_skills
void link_player_skills(object *op)
This function goes through the player inventory and sets up the last_skills[] array in the player obj...
Definition: player.cpp:287
mapstruct::darkness
uint8_t darkness
Indicates level of darkness of map.
Definition: map.h:336
find_key
object * find_key(object *pl, object *container, object *door)
We try to find a key for the door as passed.
Definition: player.cpp:2482
give_initial_items
void give_initial_items(object *pl, treasurelist *items)
Gives a new player her initial 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)
Update the move_type of a transport based on the direction.
Definition: player.cpp:2814
MSG_TYPE_APPLY
#define MSG_TYPE_APPLY
Applying objects.
Definition: newclient.h:412
player_map_change_common
void player_map_change_common(object *op, mapstruct *const oldmap, mapstruct *const newmap)
Definition: server.cpp:282
account_char_save
void account_char_save(Account_Chars *chars)
Saves the character information for the given account.
Definition: account_char.cpp:158
object::attacktype
uint32_t attacktype
Bitmask of attacks this object does.
Definition: object.h:352
OUT_OF_MEMORY
@ OUT_OF_MEMORY
Definition: define.h:48
FLAG_CURSED
#define FLAG_CURSED
The object is cursed.
Definition: define.h:316
rv_vector::direction
int direction
General direction to the targer.
Definition: map.h:374
check_stat_bounds
void check_stat_bounds(living *stats, int8_t min_stat, int8_t max_stat)
Ensures that all stats (str/dex/con/wis/cha/int) are within the passed in range of min_stat and max_s...
Definition: living.cpp:354
living.h
send_query
void send_query(socket_struct *ns, uint8_t flags, const char *text)
Asks the client to query the user.
Definition: request.cpp:745
Send_With_Handling
void Send_With_Handling(socket_struct *ns, SockList *sl)
Calls Write_To_Socket to send data to the client.
Definition: lowlevel.cpp:447
is_true_undead
int is_true_undead(object *op)
Is the object a true undead?
Definition: player.cpp:3993
MSG_TYPE_ADMIN
#define MSG_TYPE_ADMIN
Definition: newclient.h:406
object::material
uint16_t material
What materials this object consist of.
Definition: object.h:357
SockList
Contains the base information we use to make up a packet we want to send.
Definition: newclient.h:685
rv_vector::distance
unsigned int distance
Distance, in squares.
Definition: map.h:371
player::bowtype
bowtype_t bowtype
Which firemode?
Definition: player.h:114
SPELLBOOK
@ SPELLBOOK
Definition: object.h:208
NUM_STATS
@ NUM_STATS
Number of statistics.
Definition: living.h:18
MSG_TYPE_ITEM_INFO
#define MSG_TYPE_ITEM_INFO
Information related to items.
Definition: newclient.h:649
apply_race_and_class
int apply_race_and_class(object *op, archetype *race, archetype *opclass, living *stats)
This is somewhat like key_change_class() above, except we know the race to change to,...
Definition: player.cpp:1485
FOR_INV_PREPARE
#define FOR_INV_PREPARE(op_, it_)
Constructs a loop iterating over the inventory of an object.
Definition: define.h:664
MAX_FOOD
static const int32_t MAX_FOOD
Definition: define.h:455
living::hp
int16_t hp
Hit Points.
Definition: living.h:40
living::luck
int8_t luck
Affects thaco and ac from time to time.
Definition: living.h:39
create_treasure
void create_treasure(treasurelist *t, object *op, int flag, int difficulty, int tries)
This calls the appropriate treasure creation function.
Definition: treasure.cpp:287
drain_wand_charge
void drain_wand_charge(object *wand)
Drains a charge from a wand.
Definition: spell_util.cpp:786
FORCE
@ FORCE
Definition: object.h:229
playername_ok
int playername_ok(const char *cp)
Is the player name valid.
Definition: player.cpp:257
player::last_character_load
float last_character_load
Last value sent to the client.
Definition: player.h:136
account_char_remove
void account_char_remove(Account_Chars *chars, const char *pl_name)
This removes a character on this account.
Definition: account_char.cpp:313
EXIT_ALT_Y
#define EXIT_ALT_Y(xyz)
Definition: define.h:438
object.h
player::ticks_played
uint32_t ticks_played
How many ticks this player has played.
Definition: player.h:222
player::usekeys
usekeytype usekeys
Method for finding keys for doors.
Definition: player.h:120
player::rejoin_party
party_rejoin_mode rejoin_party
Whether to rejoin or not party at login.
Definition: player.h:210
events_execute_global_event
void events_execute_global_event(int eventcode,...)
Execute a global event.
Definition: events.cpp:30
CONSTITUTION
@ CONSTITUTION
Definition: living.h:13
object_can_merge
int object_can_merge(object *ob1, object *ob2)
Examines the 2 objects given to it, and returns true if they can be merged together,...
Definition: object.cpp:433
llevDebug
@ llevDebug
Only for debugging purposes.
Definition: logger.h:13
FLAG_LIFESAVE
#define FLAG_LIFESAVE
Saves a players' life once, then destr.
Definition: define.h:305
MONEY
@ MONEY
Definition: object.h:142
NRSPELLPATHS
#define NRSPELLPATHS
Number of spell paths.
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)
Translate a message in the appropriate language.
Definition: languages.cpp:42
P_BLOCKSVIEW
#define P_BLOCKSVIEW
This spot blocks the player's view.
Definition: map.h:226
FORCE_NAME
#define FORCE_NAME
Definition: spells.h:169
living::Con
int8_t Con
Definition: living.h:36
FLAG_IDENTIFIED
#define FLAG_IDENTIFIED
Item is identifiable (e.g.
Definition: define.h:261
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)
Core routine for use when we attack using a skills system.
Definition: skill_util.cpp:1270
PU_DEBUG
#define PU_DEBUG
Definition: define.h:108
CS_QUERY_HIDEINPUT
#define CS_QUERY_HIDEINPUT
Hide input being entered.
Definition: newclient.h:72
hide
uint32 hide
Definition: arch-handbook.txt:572
PU_SKILLSCROLL
#define PU_SKILLSCROLL
Definition: define.h:136
Settings::localdir
const char * localdir
Read/write data files.
Definition: global.h:250