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 
3166  if (op->contr->repeat_func != NULL) {
3167  bool ret = op->contr->repeat_func(op->contr, op->contr->repeat_func_data);
3168  if (ret == false) {
3170  }
3171  }
3172 
3173  return 0;
3174 }
3175 
3186 static int save_life(object *op) {
3187  object *tmp;
3188 
3189  if (!QUERY_FLAG(op, FLAG_LIFESAVE))
3190  return 0;
3191 
3193  if (tmp != NULL) {
3194  char name[MAX_BUF];
3195 
3196  query_name(tmp, name, MAX_BUF);
3197  play_sound_map(SOUND_TYPE_ITEM, tmp, 0, "evaporate");
3199  "Your %s vibrates violently, then evaporates.",
3200  name);
3201  object_remove(tmp);
3204  if (op->stats.hp < 0)
3205  op->stats.hp = op->stats.maxhp;
3206  if (op->stats.food < 0)
3207  op->stats.food = MAX_FOOD;
3208  fix_object(op);
3209  return 1;
3210  }
3211  LOG(llevError, "Error: LIFESAVE set without applied object.\n");
3213  enter_player_savebed(op); /* bring him home. */
3214  return 0;
3215 }
3216 
3229 void remove_unpaid_objects(object *op, object *env, int free_items) {
3231  if (QUERY_FLAG(op, FLAG_UNPAID)) {
3232  object_remove(op);
3233  if (free_items)
3235  else
3236  object_insert_in_map_at(op, env->map, NULL, 0, env->x, env->y);
3237  } else if (op->inv)
3238  remove_unpaid_objects(op->inv, env, free_items);
3240 }
3241 
3259 static const char *gravestone_text(object *op, char *buf2, int len) {
3260  char buf[MAX_BUF];
3261  time_t now = time(NULL);
3262 
3263  strncpy(buf2, " R.I.P.\n\n", len);
3264  if (op->type == PLAYER)
3265  snprintf(buf, sizeof(buf), "%s the %s\n", op->name, op->contr->title);
3266  else
3267  snprintf(buf, sizeof(buf), "%s\n", op->name);
3268  strncat(buf2, " ", 20-strlen(buf)/2);
3269  strncat(buf2, buf, len-strlen(buf2)-1);
3270  if (op->type == PLAYER)
3271  snprintf(buf, sizeof(buf), "who was in level %d when killed\n", op->level);
3272  else
3273  snprintf(buf, sizeof(buf), "who was in level %d when died.\n\n", op->level);
3274  strncat(buf2, " ", 20-strlen(buf)/2);
3275  strncat(buf2, buf, len-strlen(buf2)-1);
3276  if (op->type == PLAYER) {
3277  snprintf(buf, sizeof(buf), "by %s.\n\n", op->contr->killer);
3278  strncat(buf2, " ", 21-strlen(buf)/2);
3279  strncat(buf2, buf, len-strlen(buf2)-1);
3280  }
3281  strftime(buf, MAX_BUF, "%b %d %Y\n", localtime(&now));
3282  strncat(buf2, " ", 20-strlen(buf)/2);
3283  strncat(buf2, buf, len-strlen(buf2)-1);
3284  return buf2;
3285 }
3286 
3287 static bool starving(object *op) {
3288  return op->stats.food <= 0;
3289 }
3290 
3298 void do_some_living(object *op) {
3299  int last_food = op->stats.food;
3300  int gen_hp, gen_sp, gen_grace;
3301  int rate_hp = 1200;
3302  int rate_sp = 2500;
3303  int rate_grace = 2000;
3304 
3305  if (op->contr->state == ST_PLAYING) {
3306  /* these next three if clauses make it possible to SLOW DOWN
3307  hp/grace/spellpoint regeneration. */
3308  if (op->contr->gen_hp >= 0)
3309  gen_hp = (op->contr->gen_hp+1)*op->stats.maxhp;
3310  else {
3311  gen_hp = op->stats.maxhp;
3312  rate_hp -= rate_hp/2*op->contr->gen_hp;
3313  }
3314  if (op->contr->gen_sp >= 0)
3315  gen_sp = (op->contr->gen_sp+1)*op->stats.maxsp;
3316  else {
3317  gen_sp = op->stats.maxsp;
3318  rate_sp -= rate_sp/2*op->contr->gen_sp;
3319  }
3320  if (op->contr->gen_grace >= 0)
3321  gen_grace = (op->contr->gen_grace+1)*op->stats.maxgrace;
3322  else {
3323  gen_grace = op->stats.maxgrace;
3324  rate_grace -= rate_grace/2*op->contr->gen_grace;
3325  }
3326 
3327  /* Regenerate Spell Points */
3328  if (op->contr->ranges[range_golem] == NULL && --op->last_sp < 0) {
3329  gen_sp = gen_sp*10/MAX(op->contr->gen_sp_armour, 10);
3330  if (op->stats.sp < op->stats.maxsp) {
3331  op->stats.sp++;
3332  /* dms do not consume food */
3333  if (!QUERY_FLAG(op, FLAG_WIZ)) {
3334  op->stats.food--;
3335  if (op->contr->digestion < 0)
3336  op->stats.food += op->contr->digestion;
3337  else if (op->contr->digestion > 0
3338  && random_roll(0, op->contr->digestion, op, PREFER_HIGH))
3339  op->stats.food = last_food;
3340  }
3341  }
3342  op->last_sp = rate_sp/(MAX(gen_sp, 20)+10);
3343  }
3344 
3345  /* Regenerate Grace */
3346  /* I altered this a little - maximum grace is only achieved through prayer -b.t.*/
3347  if (--op->last_grace < 0) {
3348  if (op->stats.grace < op->stats.maxgrace/2)
3349  op->stats.grace++; /* no penalty in food for regaining grace */
3350  op->last_grace = rate_grace/(MAX(gen_grace, 20)+10);
3351  /* wearing stuff doesn't detract from grace generation. */
3352  }
3353 
3354  /* Regenerate Hit Points (unless you are a wraith player) */
3355  if (--op->last_heal < 0 && !is_wraith_pl(op) && !starving(op)) {
3356  if (op->stats.hp < op->stats.maxhp) {
3357  op->stats.hp++;
3358  /* dms do not consume food */
3359  if (!QUERY_FLAG(op, FLAG_WIZ)) {
3360  op->stats.food--;
3361  if (op->contr->digestion < 0)
3362  op->stats.food += op->contr->digestion;
3363  else if (op->contr->digestion > 0
3364  && random_roll(0, op->contr->digestion, op, PREFER_HIGH))
3365  op->stats.food = last_food;
3366  }
3367  }
3368  op->last_heal = rate_hp/(MAX(gen_hp, 20)+10);
3369  }
3370 
3371  /* Digestion */
3372  if (--op->last_eat < 0) {
3373  int bonus = MAX(op->contr->digestion, 0);
3374  int penalty = MAX(-op->contr->digestion, 0);
3375  if (op->contr->gen_hp > 0)
3376  op->last_eat = 25*(1+bonus)/(op->contr->gen_hp+penalty+1);
3377  else
3378  op->last_eat = 25*(1+bonus)/(penalty+1);
3379  /* dms do not consume food */
3380  if (!QUERY_FLAG(op, FLAG_WIZ))
3381  op->stats.food--;
3382  }
3383  }
3384 
3385  // Grab a bite of food if able, starving, and still alive.
3386  if (op->contr->state == ST_PLAYING && starving(op) && op->stats.hp >= 0) {
3387  if (is_wraith_pl(op))
3388  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ITEM, MSG_TYPE_ITEM_REMOVE, "You feel a hunger for living flesh.");
3389  /* Only allow eat if not paralyzed. Otherwise our paralyzed player is "moving" to eat.
3390  * Neila Hawkins 2017-08-23
3391  */
3392  else if (!QUERY_FLAG(op, FLAG_PARALYZED)){
3393  object *flesh = NULL;
3394 
3395  FOR_INV_PREPARE(op, tmp) {
3396  if (!QUERY_FLAG(tmp, FLAG_UNPAID)) {
3397  if (tmp->type == FOOD || tmp->type == DRINK || tmp->type == POISON) {
3399  "You blindly grab for a bite of food.");
3400  apply_manual(op, tmp, 0);
3401  if (op->stats.food >= 0 || op->stats.hp < 0)
3402  break;
3403  } else if (tmp->type == FLESH)
3404  flesh = tmp;
3405  } /* End if paid for object */
3406  } FOR_INV_FINISH(); /* end of for loop */
3407  /* If player is still starving, it means they don't have any food, so
3408  * eat flesh instead.
3409  */
3410  if (op->stats.food < 0 && op->stats.hp >= 0 && flesh) {
3412  "You blindly grab for a bite of food.");
3413  apply_manual(op, flesh, 0);
3414  }
3415  } /* end not wraith and not paralyzed */
3416  else { // Print a message for when the player is starving and paralyzed
3417  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ITEM, MSG_TYPE_ITEM_REMOVE, "Your stomach rumbles, but you can't reach your food.");
3418  } /* end not wraith and is paralyzed */
3419  } /* end if player is starving */
3420 
3421  // Prevent food from going negative, then deal constant hunger damage.
3422  if (starving(op)) {
3423  op->stats.food = 0;
3424  op->stats.hp -= 1;
3425  }
3426 
3427  if (!op->contr->state && !QUERY_FLAG(op, FLAG_WIZ) && (op->stats.hp <= 0))
3428  kill_player(op, NULL);
3429 }
3430 
3437 static void loot_object(object *op) {
3438  object *tmp2;
3439 
3440  if (op->container) { /* close open sack first */
3441  apply_container(op, op->container, AP_NULL);
3442  }
3443 
3444  FOR_INV_PREPARE(op, tmp) {
3445  if (tmp->invisible)
3446  continue;
3447  object_remove(tmp);
3448  tmp->x = op->x,
3449  tmp->y = op->y;
3450  if (tmp->type == CONTAINER) { /* empty container to ground */
3451  loot_object(tmp);
3452  }
3453  if (!QUERY_FLAG(tmp, FLAG_UNIQUE)
3454  && (QUERY_FLAG(tmp, FLAG_STARTEQUIP) || QUERY_FLAG(tmp, FLAG_NO_DROP) || !(RANDOM()%3))) {
3455  if (tmp->nrof > 1) {
3456  tmp2 = object_split(tmp, 1+RANDOM()%(tmp->nrof-1), NULL, 0);
3458  object_insert_in_map_at(tmp, op->map, NULL, 0, op->x, op->y);
3459  } else
3461  } else
3462  object_insert_in_map_at(tmp, op->map, NULL, 0, op->x, op->y);
3463  } FOR_INV_FINISH();
3464 }
3465 
3476 static void restore_player(object *op) {
3477  object *tmp;
3478  archetype *at = find_archetype("poisoning");
3479  if (at != NULL) {
3480  tmp = arch_present_in_ob(at, op);
3481  if (tmp) {
3482  object_remove(tmp);
3485  "Your body feels cleansed");
3486  }
3487  }
3488 
3489  at = find_archetype("confusion");
3490  if (at != NULL) {
3491  tmp = arch_present_in_ob(at, op);
3492  if (tmp) {
3493  object_remove(tmp);
3496  "Your mind feels clearer");
3497  }
3498  }
3499 
3500  cure_disease(op, NULL, NULL); /* remove any disease */
3501 }
3502 
3514 void kill_player(object *op, const object *killer) {
3515  char buf[MAX_BUF];
3516  int x, y;
3517  object *tmp;
3518  archetype *trophy = NULL;
3519 
3520  /* Don't die if the player's life can be saved. */
3521  if (save_life(op)) {
3522  return;
3523  }
3524 
3525  /* If player dies on BATTLEGROUND, no stat/exp loss! For Combat-Arenas
3526  * in cities ONLY!!! It is very important that this doesn't get abused.
3527  * Look at op_on_battleground() for more info --AndreasV
3528  */
3529  if (op_on_battleground(op, &x, &y, &trophy)) {
3530  assert(trophy != NULL);
3532  "You have been defeated in combat!\n"
3533  "Local medics have saved your life...");
3534 
3535  /* restore player */
3536  restore_player(op);
3537 
3538  op->stats.hp = op->stats.maxhp;
3539  if (op->stats.food <= 0)
3540  op->stats.food = MAX_FOOD;
3541 
3542  /* create a bodypart-trophy to make the winner happy */
3543  tmp = arch_to_object(trophy);
3544  if (tmp != NULL) {
3545  snprintf(buf, sizeof(buf), "%s's %s", op->name, tmp->name);
3546  tmp->name = add_string(buf);
3547 
3548  snprintf(buf, sizeof(buf),
3549  "This %s was %s %s the %s, who was defeated at level %d by %s.\n",
3550  tmp->name, tmp->type == FLESH ? "cut off" : "taken from",
3551  op->name, op->contr->title,
3552  (int)(op->level), op->contr->killer);
3553 
3554  object_set_msg(tmp, buf);
3555  tmp->type = 0;
3556  tmp->value = 0;
3557  tmp->material = 0;
3558  tmp->materialname = NULL;
3559  object_insert_in_map_at(tmp, op->map, op, 0, op->x, op->y);
3560  }
3561 
3562  /* teleport defeated player to new destination*/
3563  transfer_ob(op, x, y, 0, NULL);
3564  op->contr->braced = 0;
3565  return;
3566  }
3567 
3568  if (events_execute_object_event(op, EVENT_DEATH, NULL, NULL, NULL, SCRIPT_FIX_ALL) != 0)
3569  return;
3570 
3572  if (starving(op)) {
3573  snprintf(buf, sizeof(buf), "%s starved to death.", op->name);
3574  strcpy(op->contr->killer, "starvation");
3575  } else {
3576  snprintf(buf, sizeof(buf), "%s died.", op->name);
3577  }
3578  play_sound_player_only(op->contr, SOUND_TYPE_LIVING, op, 0, "death");
3579 
3580  if (settings.not_permadeth == TRUE) {
3582  } else {
3584  }
3585 }
3586 
3595 static void kill_player_not_permadeath(object *op) {
3596  int num_stats_lose;
3597  int will_kill_again;
3598  int lost_a_stat;
3599  int z;
3600  object *tmp;
3601  char buf[MAX_BUF];
3602  archetype *at;
3603 
3604  /* Basically two ways to go - remove a stat permanently, or just
3605  * make it depletion. This bunch of code deals with that aspect
3606  * of death.
3607  */
3609  /* If stat loss is permanent, lose one stat only. */
3610  /* Lower level chars don't lose as many stats because they suffer
3611  more if they do. */
3612  /* Higher level characters can afford things such as potions of
3613  restoration, or better, stat potions. So we slug them that
3614  little bit harder. */
3615  /* GD */
3617  num_stats_lose = 1;
3618  else
3619  num_stats_lose = 1+op->level/BALSL_NUMBER_LOSSES_RATIO;
3620  } else {
3621  num_stats_lose = 1;
3622  }
3623  lost_a_stat = 0;
3624 
3625  for (z = 0; z < num_stats_lose; z++) {
3627  int i;
3628 
3629  /* Pick a random stat and take a point off it. Tell the player
3630  * what he lost.
3631  */
3632  i = RANDOM()%7;
3633  change_attr_value(&(op->stats), i, -1);
3635  change_attr_value(&(op->contr->orig_stats), i, -1);
3637  draw_ext_info(NDI_UNIQUE, 0, op,
3639  lose_msg[i]);
3640  lost_a_stat = 1;
3641  } else {
3642  /* deplete a stat */
3644  if (deparch == NULL) {
3645  continue;
3646  }
3647  object *dep;
3648  int lose_this_stat;
3649  int i;
3650 
3651  i = RANDOM()%7;
3652  dep = arch_present_in_ob(deparch, op);
3653  if (!dep) {
3654  dep = arch_to_object(deparch);
3655  object_insert_in_ob(dep, op);
3656  }
3657  lose_this_stat = 1;
3659  int this_stat;
3660 
3661  /* GD */
3662  /* Get the stat that we're about to deplete. */
3663  this_stat = get_attr_value(&(dep->stats), i);
3664  if (this_stat < 0) {
3665  int loss_chance = 1+op->level/BALSL_LOSS_CHANCE_RATIO;
3666  int keep_chance = this_stat*this_stat;
3667  /* Yes, I am paranoid. Sue me. */
3668  if (keep_chance < 1)
3669  keep_chance = 1;
3670 
3671  /* There is a maximum depletion total per level. */
3672  if (this_stat < -1-op->level/BALSL_MAX_LOSS_RATIO) {
3673  lose_this_stat = 0;
3674  /* Take loss chance vs keep chance to see if we
3675  retain the stat. */
3676  } else {
3677  if (random_roll(0, loss_chance+keep_chance-1, op, PREFER_LOW) < keep_chance)
3678  lose_this_stat = 0;
3679  /* LOG(llevDebug, "Determining stat loss. Stat: %d Keep: %d Lose: %d Result: %s.\n", this_stat, keep_chance, loss_chance, lose_this_stat ? "LOSE" : "KEEP"); */
3680  }
3681  }
3682  }
3683 
3684  if (lose_this_stat) {
3685  int this_stat;
3686 
3687  this_stat = get_attr_value(&(dep->stats), i);
3688  /* We could try to do something clever like find another
3689  * stat to reduce if this fails. But chances are, if
3690  * stats have been depleted to -50, all are pretty low
3691  * and should be roughly the same, so it shouldn't make a
3692  * difference.
3693  */
3694  if (this_stat >= -50) {
3695  change_attr_value(&(dep->stats), i, -1);
3696  SET_FLAG(dep, FLAG_APPLIED);
3698  drain_msg[i]);
3699  fix_object(op);
3700  lost_a_stat = 1;
3701  }
3702  }
3703  }
3704  }
3705  /* If no stat lost, tell the player. */
3706  if (!lost_a_stat) {
3707  /* determine_god() seems to not work sometimes... why is this? Should I be using something else? GD */
3708  const char *god = determine_god(op);
3709 
3710  if (god && (strcmp(god, "none")))
3713  "For a brief moment you feel the holy presence of %s protecting you",
3714  god);
3715  else
3716  draw_ext_info(NDI_UNIQUE, 0, op,
3718  "For a brief moment you feel a holy presence protecting you.");
3719  }
3720 
3721  /* Put a gravestone up where the character 'almost' died. List the
3722  * exp loss on the stone.
3723  */
3724  at = find_archetype("gravestone");
3725  if (at != NULL) {
3726  tmp = arch_to_object(at);
3727  snprintf(buf, sizeof(buf), "%s's gravestone", op->name);
3728  FREE_AND_COPY(tmp->name, buf);
3729  snprintf(buf, sizeof(buf), "%s's gravestones", op->name);
3730  FREE_AND_COPY(tmp->name_pl, buf);
3731  snprintf(buf, sizeof(buf), "RIP\nHere rests the hero %s the %s,\n"
3732  "who was killed\n"
3733  "by %s.\n",
3734  op->name, op->contr->title,
3735  op->contr->killer);
3736  object_set_msg(tmp, buf);
3737  object_insert_in_map_at(tmp, op->map, NULL, 0, op->x, op->y);
3738  }
3739 
3740  /* restore player: remove any poisoning, disease and confusion the
3741  * character may be suffering.*/
3742  restore_player(op);
3743 
3744  /* Subtract the experience points, if we died cause of food, give
3745  * us food, and reset HP's...
3746  */
3748  if (op->stats.food < 100)
3749  op->stats.food = 900;
3750  op->stats.hp = op->stats.maxhp;
3751  op->stats.sp = MAX(op->stats.sp, op->stats.maxsp);
3752  op->stats.grace = MAX(op->stats.grace, op->stats.maxgrace);
3753 
3754  /* Check to see if the player is in a shop. IF so, then check to see if
3755  * the player has any unpaid items. If so, remove them and put them back
3756  * in the map.
3757  *
3758  * If they are not in a shop, just free the unpaid items instead of
3759  * putting them back on map.
3760  */
3761  if (shop_contains(op))
3762  remove_unpaid_objects(op->inv, op, 0);
3763  else
3764  remove_unpaid_objects(op->inv, op, 1);
3765 
3766  /* Move player to his current respawn-position (usually last savebed) */
3768 
3769  /* Save the player before inserting the force to reduce chance of abuse. */
3770  op->contr->braced = 0;
3771  /* don't pick up in apartment */
3772  if (op->contr->mode & PU_NEWMODE) {
3773  op->contr->mode = op->contr->mode | PU_INHIBIT;
3774  esrv_send_pickup(op->contr);
3775  } else {
3776  op->contr->mode = 0;
3777  }
3778  if ( op->contr->search_str[0] ) command_search_items(op,NULL); /* turn off search-items */
3779  save_player(op, 1);
3780 
3781  /* it is possible that the player has blown something up
3782  * at his savebed location, and that can have long lasting
3783  * spell effects. So first see if there is a spell effect
3784  * on the space that might harm the player.
3785  */
3786  will_kill_again = 0;
3787  FOR_MAP_PREPARE(op->map, op->x, op->y, tmp)
3788  if (tmp->type == SPELL_EFFECT)
3789  will_kill_again |= tmp->attacktype;
3790  FOR_MAP_FINISH();
3791  if (will_kill_again) {
3792  object *force;
3793  int at;
3794 
3795  force = create_archetype(FORCE_NAME);
3796  /* 50 ticks should be enough time for the spell to abate */
3797  force->speed = 0.1;
3798  force->speed_left = -5.0;
3799  SET_FLAG(force, FLAG_APPLIED);
3800  for (at = 0; at < NROFATTACKS; at++) {
3801  if (will_kill_again&(1<<at))
3802  force->resist[at] = 100;
3803  }
3804  object_insert_in_ob(force, op);
3805  fix_object(op);
3806  }
3807 
3808  /* Tell the player they have died */
3810  "YOU HAVE DIED.");
3811 }
3812 
3819 static void kill_player_permadeath(object *op) {
3820  char buf[MAX_BUF];
3821  char ac_buf[MAX_BUF];
3822  int x, y;
3823  mapstruct *map;
3824  object *tmp;
3825  archetype *at;
3826 
3827  /* save the map location for corpse, gravestone*/
3828  x = op->x;
3829  y = op->y;
3830  map = op->map;
3831 
3832  party_leave(op);
3833  if (settings.set_title == TRUE)
3834  player_set_own_title(op->contr, "");
3835 
3836  /* buf should be the kill message */
3838  buf);
3839  hiscore_check(op, 0);
3840  if (op->contr->ranges[range_golem] != NULL) {
3844  op->contr->ranges[range_golem] = NULL;
3845  op->contr->golem_count = 0;
3846  }
3847  loot_object(op); /* Remove some of the items for good */
3848  object_remove(op);
3849  op->direction = 0;
3850 
3851  if (!QUERY_FLAG(op, FLAG_WAS_WIZ) && op->stats.exp) {
3852  if (settings.resurrection == TRUE) {
3853  /* save playerfile sans equipment when player dies
3854  * -then save it as player.pl.dead so that future resurrection
3855  * -type spells will work on them nicely
3856  */
3857  op->stats.hp = op->stats.maxhp;
3858  op->stats.food = MAX_FOOD;
3859 
3860  /* set the location of where the person will reappear when */
3861  /* maybe resurrection code should fix map also */
3863  sizeof(op->contr->maplevel));
3864  if (op->map != NULL)
3865  op->map = NULL;
3866  op->x = settings.emergency_x;
3867  op->y = settings.emergency_y;
3868  save_player(op, 0);
3869  op->map = map;
3870  /* please see resurrection.c: peterm */
3871  dead_player(op);
3872  } else {
3873  delete_character(op->name);
3874 
3875  /* Remove player from account list and send back data if needed */
3876  if (op->contr->socket->account_chars != NULL) {
3879  /* char information is reloaded in send_account_players below */
3881  op->contr->socket->account_chars = NULL;
3884  }
3885  }
3886  }
3887  play_again(op);
3888 
3889  /* peterm: added to create a corpse at deathsite. */
3890  at = find_archetype("corpse_pl");
3891  if (at != NULL) {
3892  tmp = arch_to_object(at);
3893  snprintf(buf, sizeof(buf), "%s", op->name);
3894  FREE_AND_COPY(tmp->name, buf);
3895  FREE_AND_COPY(tmp->name_pl, buf);
3896  tmp->level = op->level;
3897  object_set_msg(tmp, gravestone_text(op, buf, sizeof(buf)));
3898  SET_FLAG(tmp, FLAG_UNIQUE);
3899  /*
3900  * Put the account name under slaying.
3901  * Does not seem to cause weird effects, but more testing may ensure this.
3902  */
3903  snprintf(ac_buf, sizeof(ac_buf), "%s", op->contr->socket->account_name);
3904  FREE_AND_COPY(tmp->slaying, ac_buf);
3905  object_insert_in_map_at(tmp, map, NULL, 0, x, y);
3906  }
3907 }
3908 
3916 void fix_weight(void) {
3917  player *pl;
3918 
3919  for (pl = first_player; pl != NULL; pl = pl->next) {
3920  int old = pl->ob->carrying, sum = object_sum_weight(pl->ob);
3921 
3922  if (old == sum)
3923  continue;
3924  fix_object(pl->ob);
3925  LOG(llevDebug, "Fixed inventory in %s (%d -> %d)\n", pl->ob->name, old, sum);
3926  }
3927 }
3928 
3932 void fix_luck(void) {
3933  player *pl;
3934 
3935  for (pl = first_player; pl != NULL; pl = pl->next)
3936  if (!pl->ob->contr->state)
3937  change_luck(pl->ob, 0);
3938 }
3939 
3940 
3953 void cast_dust(object *op, object *throw_ob, int dir) {
3954  object *skop, *spob;
3955 
3956  skop = find_skill_by_name(op, throw_ob->skill);
3957 
3958  /* casting POTION 'dusts' is really a use_magic_item skill */
3959  if (op->type == PLAYER && throw_ob->type == POTION && !skop) {
3960  LOG(llevError, "Player %s lacks critical skill use_magic_item!\n", op->name);
3961  return;
3962  }
3963  spob = throw_ob->inv;
3964  if (op->type == PLAYER && spob)
3966  "You cast %s.",
3967  spob->name);
3968 
3969  cast_spell(op, throw_ob, dir, spob, NULL);
3970 
3971  if (!QUERY_FLAG(throw_ob, FLAG_REMOVED))
3972  object_remove(throw_ob);
3973  object_free_drop_inventory(throw_ob);
3974 }
3975 
3982 void make_visible(object *op) {
3983  op->hide = 0;
3984  op->invisible = 0;
3985  if (op->type == PLAYER) {
3986  op->contr->tmp_invis = 0;
3987  if (op->contr->invis_race)
3989  }
3991 }
3992 
4001 int is_true_undead(object *op) {
4002  if (QUERY_FLAG(&op->arch->clone, FLAG_UNDEAD))
4003  return 1;
4004 
4005  return 0;
4006 }
4007 
4018 int hideability(object *ob) {
4019  int i, level = 0, mflag;
4020  int16_t x, y;
4021 
4022  if (!ob || !ob->map)
4023  return 0;
4024 
4025  /* so, on normal lighted maps, its hard to hide */
4026  level = ob->map->darkness-2;
4027 
4028  /* this also picks up whether the object is glowing.
4029  * If you carry a light on a non-dark map, its not
4030  * as bad as carrying a light on a pitch dark map
4031  */
4032  if (has_carried_lights(ob))
4033  level = -(10+(2*ob->map->darkness));
4034 
4035  /* scan through all nearby squares for terrain to hide in */
4036  for (i = 0, x = ob->x, y = ob->y; i < 9; i++, x = ob->x+freearr_x[i], y = ob->y+freearr_y[i]) {
4037  mflag = get_map_flags(ob->map, NULL, x, y, NULL, NULL);
4038  if (mflag&P_OUT_OF_MAP) {
4039  continue;
4040  }
4041  if (mflag&P_BLOCKSVIEW) /* something to hide near! */
4042  level += 2;
4043  else /* open terrain! */
4044  level -= 1;
4045  }
4046 
4047  return level;
4048 }
4049 
4059 void do_hidden_move(object *op) {
4060  int hide = 0, num = random_roll(0, 19, op, PREFER_LOW);
4061  object *skop;
4062 
4063  if (!op || !op->map)
4064  return;
4065 
4067 
4068  /* its *extremely *hard to run and sneak/hide at the same time! */
4069  if (op->type == PLAYER && op->contr->run_on) {
4070  if (!skop || num >= skop->level) {
4072  "You ran too much! You are no longer hidden!");
4073  make_visible(op);
4074  return;
4075  } else
4076  num += 20;
4077  }
4078  num += op->map->difficulty;
4079  hide = hideability(op); /* modify by terrain hidden level */
4080  num -= hide;
4081  if ((op->type == PLAYER && hide < -10)
4082  || ((op->invisible -= num) <= 0)) {
4083  make_visible(op);
4084  if (op->type == PLAYER)
4086  "You moved out of hiding! You are visible!");
4087  } else if (op->type == PLAYER && skop) {
4088  change_exp(op, calc_skill_exp(op, NULL, skop), skop->skill, 0);
4089  }
4090 }
4091 
4100 int stand_near_hostile(object *who) {
4101  int i, friendly = 0, player = 0, mflags;
4102  mapstruct *m;
4103  int16_t x, y;
4104 
4105  if (!who)
4106  return 0;
4107 
4108  if (who->type == PLAYER)
4109  player = 1;
4110  else
4112 
4113  /* search adjacent squares */
4114  for (i = 1; i < 9; i++) {
4115  x = who->x+freearr_x[i];
4116  y = who->y+freearr_y[i];
4117  m = who->map;
4118  mflags = get_map_flags(m, &m, x, y, &x, &y);
4119  /* space must be blocked if there is a monster. If not
4120  * blocked, don't need to check this space.
4121  */
4122  if (mflags&P_OUT_OF_MAP)
4123  continue;
4124  if (OB_TYPE_MOVE_BLOCK(who, GET_MAP_MOVE_BLOCK(m, x, y)))
4125  continue;
4126 
4127  FOR_MAP_PREPARE(m, x, y, tmp) {
4128  if ((player || friendly)
4129  && QUERY_FLAG(tmp, FLAG_MONSTER)
4130  && !QUERY_FLAG(tmp, FLAG_UNAGGRESSIVE))
4131  return 1;
4132  else if (tmp->type == PLAYER) {
4133  /*don't let a hidden DM prevent you from hiding*/
4134  if (!QUERY_FLAG(tmp, FLAG_WIZ) || tmp->contr->hidden == 0)
4135  return 1;
4136  }
4137  } FOR_MAP_FINISH();
4138  }
4139  return 0;
4140 }
4141 
4168 int player_can_view(object *pl, object *op) {
4169  rv_vector rv;
4170  int dx, dy;
4171 
4172  if (!pl || !op)
4173  return 0;
4174 
4175  if (pl->type != PLAYER) {
4176  LOG(llevError, "player_can_view() called for non-player object\n");
4177  return -1;
4178  }
4179 
4180  op = HEAD(op);
4181  if (!get_rangevector(pl, op, &rv, 0x1))
4182  return 0;
4183 
4184  /* starting with the 'head' part, lets loop
4185  * through the object and find if it has any
4186  * part that is in the los array but isnt on
4187  * a blocked los square.
4188  * we use the archetype to figure out offsets.
4189  */
4190  while (op) {
4191  dx = rv.distance_x+op->arch->clone.x;
4192  dy = rv.distance_y+op->arch->clone.y;
4193 
4194  /* only the viewable area the player sees is updated by LOS
4195  * code, so we need to restrict ourselves to that range of values
4196  * for any meaningful values.
4197  */
4198  if (FABS(dx) <= (pl->contr->socket->mapx/2)
4199  && FABS(dy) <= (pl->contr->socket->mapy/2)
4200  && !pl->contr->blocked_los[dx+(pl->contr->socket->mapx/2)][dy+(pl->contr->socket->mapy/2)])
4201  return 1;
4202  op = op->more;
4203  }
4204  return 0;
4205 }
4206 
4220 static int action_makes_visible(object *op) {
4221  if (op->invisible && QUERY_FLAG(op, FLAG_ALIVE)) {
4222  if (QUERY_FLAG(op, FLAG_MAKE_INVIS))
4223  return 0;
4224 
4225  if (op->contr && op->contr->tmp_invis == 0)
4226  return 0;
4227 
4228  /* If monsters, they should become visible */
4229  if (op->hide || !op->contr || (op->contr && op->contr->tmp_invis)) {
4231  "You become %s!",
4232  op->hide ? "unhidden" : "visible");
4233  return 1;
4234  }
4235  }
4236  return 0;
4237 }
4238 
4267 int op_on_battleground(object *op, int *x, int *y, archetype **trophy) {
4268  FOR_BELOW_PREPARE(op, tmp) {
4269  if (QUERY_FLAG(tmp, FLAG_IS_FLOOR)) {
4270  if (QUERY_FLAG(tmp, FLAG_NO_PICK)
4271  && strcmp(tmp->name, "battleground") == 0
4272  && tmp->type == BATTLEGROUND
4273  && EXIT_X(tmp)
4274  && EXIT_Y(tmp)) {
4275  /*before we assign the exit, check if this is a teambattle*/
4276  if (EXIT_ALT_X(tmp) && EXIT_ALT_Y(tmp) && EXIT_PATH(tmp)) {
4277  object *invtmp;
4278 
4279  invtmp = object_find_by_type_and_slaying(op, FORCE, EXIT_PATH(tmp));
4280  if (invtmp != NULL) {
4281  if (x != NULL && y != NULL)
4282  *x = EXIT_ALT_X(tmp),
4283  *y = EXIT_ALT_Y(tmp);
4284  return 1;
4285  }
4286  }
4287  if (x != NULL && y != NULL)
4288  *x = EXIT_X(tmp),
4289  *y = EXIT_Y(tmp);
4290 
4291  /* If 'other_arch' is not specified, give a finger. */
4292  if (trophy != NULL) {
4293  if (tmp->other_arch) {
4294  *trophy = tmp->other_arch;
4295  } else {
4296  *trophy = find_archetype("finger");
4297  }
4298  }
4299  return 1;
4300  }
4301  }
4302  } FOR_BELOW_FINISH();
4303  /* If we got here, did not find a battleground */
4304  return 0;
4305 }
4306 
4317 void dragon_ability_gain(object *who, int atnr, int level) {
4318  treasurelist *trlist = NULL; /* treasurelist */
4319  treasure *tr; /* treasure */
4320  object *tmp, *skop; /* tmp. object */
4321  object *item; /* treasure object */
4322  char buf[MAX_BUF]; /* tmp. string buffer */
4323  int i = 0, j = 0;
4324 
4325  /* get the appropriate treasurelist */
4326  if (atnr == ATNR_FIRE)
4327  trlist = find_treasurelist("dragon_ability_fire");
4328  else if (atnr == ATNR_COLD)
4329  trlist = find_treasurelist("dragon_ability_cold");
4330  else if (atnr == ATNR_ELECTRICITY)
4331  trlist = find_treasurelist("dragon_ability_elec");
4332  else if (atnr == ATNR_POISON)
4333  trlist = find_treasurelist("dragon_ability_poison");
4334 
4335  if (trlist == NULL || who->type != PLAYER)
4336  return;
4337 
4338  // tr->magic is being used to define what level of the metabolism the ability is gained at.
4339  for (tr = trlist->items; tr != NULL && tr->magic != level; tr = tr->next)
4340  ;
4341  if (tr == NULL || tr->item == NULL) {
4342  /* LOG(llevDebug, "-> no more treasure for %s\n", change_resist_msg[atnr]); */
4343  return;
4344  }
4345 
4346  /* everything seems okay - now bring on the gift: */
4347  item = &(tr->item->clone);
4348 
4349  if (item->type == SPELL) {
4350  if (check_spell_known(who, item->name))
4351  return;
4352 
4355  "You gained the ability of %s",
4356  item->name);
4357  do_learn_spell(who, item, 0);
4358  return;
4359  }
4360 
4361  /* grant direct spell */
4362  if (item->type == SPELLBOOK) {
4363  if (!item->inv) {
4364  LOG(llevDebug, "dragon_ability_gain: Broken spellbook %s\n", item->name);
4365  return;
4366  }
4367  if (check_spell_known(who, item->inv->name))
4368  return;
4369  if (item->invisible) {
4372  "You gained the ability of %s",
4373  item->inv->name);
4374  do_learn_spell(who, item->inv, 0);
4375  return;
4376  }
4377  } else if (item->type == SKILL_TOOL && item->invisible) {
4378  if (item->subtype == SK_CLAWING && (skop = find_skill_by_name(who, item->skill)) != NULL) {
4379  /* should this perhaps be (skop->attackyp&item->attacktype) != item->attacktype ...
4380  * in this way, if the player is missing any of the attacktypes, he gets
4381  * them. As it is now, if the player has any that match the granted skill,
4382  * but not all of them, he gets nothing.
4383  */
4384  if (!(skop->attacktype&item->attacktype)) {
4385  /* Give new attacktype */
4386  skop->attacktype |= item->attacktype;
4387 
4388  /* always add physical if there's none */
4389  skop->attacktype |= AT_PHYSICAL;
4390 
4391  if (item->msg != NULL)
4394  item->msg);
4395 
4396  /* Give player new face */
4397  if (item->animation) {
4398  who->face = skop->face;
4399  who->animation = item->animation;
4400  who->anim_speed = item->anim_speed;
4401  who->last_anim = 0;
4402  who->state = 0;
4403  animate_object(who, who->direction);
4404  }
4405  }
4406  }
4407  } else if (item->type == FORCE) {
4408  /* forces in the treasurelist can alter the player's stats */
4409  object *skin;
4410 
4411  /* first get the dragon skin force */
4412  skin = object_find_by_arch_name(who, "dragon_skin_force");
4413  if (skin == NULL)
4414  return;
4415 
4416  /* adding new spellpath attunements */
4417  if (item->path_attuned > 0 && !(skin->path_attuned&item->path_attuned)) {
4418  skin->path_attuned |= item->path_attuned; /* add attunement to skin */
4419 
4420  /* print message */
4421  snprintf(buf, sizeof(buf), "You feel attuned to ");
4422  for (i = 0, j = 0; i < NRSPELLPATHS; i++) {
4423  if (item->path_attuned&(1<<i)) {
4424  if (j)
4425  strcat(buf, " and ");
4426  else
4427  j = 1;
4428  strcat(buf, spellpathnames[i]);
4429  }
4430  }
4431  strcat(buf, ".");
4434  buf);
4435  }
4436 
4437  /* evtl. adding flags: */
4438  if (QUERY_FLAG(item, FLAG_XRAYS))
4439  SET_FLAG(skin, FLAG_XRAYS);
4440  if (QUERY_FLAG(item, FLAG_STEALTH))
4441  SET_FLAG(skin, FLAG_STEALTH);
4442  if (QUERY_FLAG(item, FLAG_SEE_IN_DARK))
4443  SET_FLAG(skin, FLAG_SEE_IN_DARK);
4444 
4445  /* print message if there is one */
4446  if (item->msg != NULL)
4449  item->msg);
4450  } else {
4451  /* generate misc. treasure */
4452  char name[HUGE_BUF];
4453 
4454  tmp = arch_to_object(tr->item);
4458  "You gained %s",
4459  name);
4460  tmp = object_insert_in_ob(tmp, who);
4461  if (who->type == PLAYER)
4462  esrv_send_item(who, tmp);
4463  }
4464 }
4465 
4475 void player_unready_range_ob(player *pl, object *ob) {
4476  int i;
4477 
4478  for (i = 0; i < static_cast<int>(range_size); i++) {
4479  if (pl->ranges[i] == ob) {
4480  pl->ranges[i] = NULL;
4481  if (pl->shoottype == i) {
4482  pl->shoottype = range_none;
4483  }
4484  }
4485  }
4486 }
4487 
4493 void player_set_state(player *pl, uint8_t state) {
4494 
4495  assert(pl);
4496  assert(state <= ST_CHANGE_PASSWORD_CONFIRM);
4497  pl->state = state;
4498 }
4499 
4507  SockList *sl;
4508  assert(pl);
4509  const uint8_t to_alloc = 5;
4511  if (pl->delayed_buffers_allocated >= UINT8_MAX - to_alloc) {
4512  LOG(llevError, "Delay buffer limit exceeded for %s\n", pl->ob->name);
4513  abort();
4514  }
4515  pl->delayed_buffers_allocated += to_alloc;
4516  pl->delayed_buffers = static_cast<SockList **>(realloc(pl->delayed_buffers, pl->delayed_buffers_allocated * sizeof(pl->delayed_buffers[0])));
4517  if (!pl->delayed_buffers) {
4518  LOG(llevError, "Unable to allocated %d delayed buffers, aborting\n", pl->delayed_buffers_allocated);
4520  }
4521  for (uint8_t s = pl->delayed_buffers_allocated - to_alloc; s < pl->delayed_buffers_allocated; s++) {
4522  pl->delayed_buffers[s] = static_cast<SockList *>(calloc(1, sizeof(SockList)));
4523  }
4524  }
4525  sl = pl->delayed_buffers[pl->delayed_buffers_used];
4526  pl->delayed_buffers_used++;
4527  SockList_Init(sl);
4528  return sl;
4529 }
4530 
4536  for (uint8_t buf = 0; buf < pl->delayed_buffers_used; buf++) {
4538  }
4539  pl->delayed_buffers_used = 0;
4540 }
4541 
4545 void player_start_repeat(player *pl, const char *action, repeat_cb cb) {
4546  if (pl->repeat_func_data) {
4547  free(pl->repeat_func_data);
4548  pl->repeat_func_data = NULL;
4549  }
4550  sstring old_action = pl->repeat_action;
4551  pl->repeat_action = add_string(action);
4552  if (old_action != pl->repeat_action) {
4553  // Action different from previous one, tell player about it.
4554  char buf[MAX_BUF];
4555  snprintf(buf, sizeof(buf), "You start %s.", action);
4557  }
4558  pl->repeat_func = cb;
4559  if (old_action)
4560  free_string(old_action);
4561 }
player::gen_sp
int16_t gen_sp
Bonuses to regeneration speed of sp.
Definition: player.h:129
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:254
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:4267
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:173
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:443
player::do_los
uint32_t do_los
If true, need to call update_los() in draw(), and clear.
Definition: player.h:143
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:1325
player::bed_y
int16_t bed_y
x,y - coordinates of respawn (savebed).
Definition: player.h:113
living::exp
int64_t exp
Experience.
Definition: living.h:47
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:3982
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
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:108
kill_player_permadeath
static void kill_player_permadeath(object *op)
Kills a player in permadeath mode.
Definition: player.cpp:3819
SockList_AddInt
void SockList_AddInt(SockList *sl, uint32_t data)
Adds a 32 bit value.
Definition: lowlevel.cpp:127
global.h
PU_NOT_CURSED
#define PU_NOT_CURSED
Definition: define.h:140
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
MOVE_WALK
#define MOVE_WALK
Object walks.
Definition: define.h:383
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:714
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
MSG_TYPE_COMMAND_SUCCESS
#define MSG_TYPE_COMMAND_SUCCESS
Successful result from command.
Definition: newclient.h:534
player::unarmed_skill
const char * unarmed_skill
Prefered skill to use in unarmed combat.
Definition: player.h:223
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:3514
llevError
@ llevError
Error, serious thing.
Definition: logger.h:11
P_BLOCKSVIEW
#define P_BLOCKSVIEW
This spot blocks the player's view.
Definition: map.h:229
FABS
#define FABS(x)
Decstations have trouble with fabs()...
Definition: define.h:22
FLAG_ANIMATE
#define FLAG_ANIMATE
The object looks at archetype for faces.
Definition: define.h:229
mapstruct::difficulty
uint16_t difficulty
What level the player should be to play here.
Definition: map.h:336
ST_GET_PASSWORD
#define ST_GET_PASSWORD
Name entered, now for password.
Definition: define.h:531
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:2429
MOVE_FLYING
#define MOVE_FLYING
Combo of fly_low and fly_high.
Definition: define.h:386
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:125
LOG
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.cpp:58
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:369
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:2690
ST_GET_NAME
#define ST_GET_NAME
Player just connected.
Definition: define.h:530
player
One player.
Definition: player.h:107
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
PU_KEY
#define PU_KEY
Definition: define.h:128
player::golem_count
uint32_t golem_count
To track the golem.
Definition: player.h:121
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
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:371
player::is_wraith
bool is_wraith
Whether this player is a wraith or not, initialized at load time.
Definition: player.h:229
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
do_learn_spell
void do_learn_spell(object *op, object *spell, int special_prayer)
Actually makes op learn spell.
Definition: apply.cpp:146
socket_struct
Socket structure, represents a client-server connection.
Definition: newserver.h:93
socket_struct::mapx
uint8_t mapx
Definition: newserver.h:120
ST_CONFIRM_PASSWORD
#define ST_CONFIRM_PASSWORD
New character, confirm password.
Definition: define.h:532
FLAG_PARALYZED
#define FLAG_PARALYZED
Monster or player is paralyzed.
Definition: define.h:358
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:470
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:4506
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
FLAG_FRIENDLY
#define FLAG_FRIENDLY
Will help players.
Definition: define.h:233
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:113
IS_WEAPON
#define IS_WEAPON(op)
Definition: define.h:163
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:150
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:688
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:3287
GEM
@ GEM
Definition: object.h:172
FLAG_LIFESAVE
#define FLAG_LIFESAVE
Saves a players' life once, then destr.
Definition: define.h:292
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:424
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:148
player::ob
object * ob
The object representing the player.
Definition: player.h:179
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:216
FLAG_USE_ARMOUR
#define FLAG_USE_ARMOUR
(Monster) can wear armour/shield/helmet
Definition: define.h:282
object::speed_left
float speed_left
How much speed is left to spend this round.
Definition: object.h:338
MAP_IN_MEMORY
#define MAP_IN_MEMORY
Map is fully loaded.
Definition: map.h:129
PREFER_LOW
#define PREFER_LOW
Definition: define.h:548
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:253
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:174
player::levhp
int8_t levhp[11]
What hp bonus the player gained on that level.
Definition: player.h:188
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:3916
player_set_own_title
void player_set_own_title(struct player *pl, const char *title)
Sets the custom title.
Definition: player.cpp:273
range_none
@ range_none
No range selected.
Definition: player.h:30
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
FLAG_WIZ
#define FLAG_WIZ
Object has special privilegies.
Definition: define.h:218
CS_QUERY_SINGLECHAR
#define CS_QUERY_SINGLECHAR
Single character response expected.
Definition: newclient.h:71
FLAG_BEEN_APPLIED
#define FLAG_BEEN_APPLIED
Object was ever applied, for identification purposes.
Definition: define.h:310
player::delayed_buffers
SockList ** delayed_buffers
Buffers which will be sent after the player's tick completes.
Definition: player.h:228
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:164
allowed_class
int allowed_class(const object *op)
Returns true if the given player is a legal class.
Definition: living.cpp:1661
FLAG_SCARED
#define FLAG_SCARED
Monster is scared (mb player in future)
Definition: define.h:258
SKILL
@ SKILL
Also see SKILL_TOOL (74) below.
Definition: object.h:148
PU_STOP
#define PU_STOP
Definition: define.h:110
object::direction
int8_t direction
Means the object is moving that way.
Definition: object.h:344
PU_NEWMODE
#define PU_NEWMODE
Definition: define.h:111
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
FLAG_XRAYS
#define FLAG_XRAYS
X-ray vision.
Definition: define.h:287
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:357
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
FLAG_MAKE_INVIS
#define FLAG_MAKE_INVIS
(Item) gives invisibility when applied
Definition: define.h:315
player::levsp
int8_t levsp[11]
What sp bonus the player gained on that level.
Definition: player.h:189
player::savebed_map
char savebed_map[MAX_BUF]
Map where player will respawn after death.
Definition: player.h:112
Settings::roll_stat_points
uint8_t roll_stat_points
How many stat points legacy (rolled) chars start with.
Definition: global.h:324
ST_PLAYING
#define ST_PLAYING
Usual state.
Definition: define.h:525
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:4535
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:4168
PU_CURSED
#define PU_CURSED
Definition: define.h:144
confirm_password
void confirm_password(object *op)
Ask the player to confirm her password during creation.
Definition: player.cpp:1011
PU_CONTAINER
#define PU_CONTAINER
Definition: define.h:143
NDI_NAVY
#define NDI_NAVY
Definition: newclient.h:248
SCRIPT_FIX_ALL
#define SCRIPT_FIX_ALL
Definition: global.h:380
player::last_stats
living last_stats
Last stats as sent to client.
Definition: player.h:170
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:149
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
NROFATTACKS
#define NROFATTACKS
Definition: attack.h:15
FLAG_STEALTH
#define FLAG_STEALTH
Will wake monsters with less range.
Definition: define.h:299
BALSL_LOSS_CHANCE_RATIO
#define BALSL_LOSS_CHANCE_RATIO
Definition: config.h:142
PU_DEBUG
#define PU_DEBUG
Definition: define.h:108
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
FLAG_READY_BOW
#define FLAG_READY_BOW
not implemented yet
Definition: define.h:286
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
PU_SKILLSCROLL
#define PU_SKILLSCROLL
Definition: define.h:136
range_golem
@ range_golem
Control golem.
Definition: player.h:34
partylist
One party.
Definition: party.h:10
apply_manual
int apply_manual(object *op, object *tmp, int aflag)
Main apply handler.
Definition: apply.cpp:259
FLAG_CURSED
#define FLAG_CURSED
The object is cursed.
Definition: define.h:303
mapstruct::path
char path[HUGE_BUF]
Filename of the map.
Definition: map.h:358
FLAG_CAN_ROLL
#define FLAG_CAN_ROLL
Object can be rolled.
Definition: define.h:241
MSG_TYPE_MISC
#define MSG_TYPE_MISC
Messages that don't go elsewhere.
Definition: newclient.h:417
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
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:168
getManager
AssetsManager * getManager()
Definition: assets.cpp:309
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
PU_SHIELD
#define PU_SHIELD
Definition: define.h:122
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
PU_BOOTS
#define PU_BOOTS
Definition: define.h:125
object::resist
int16_t resist[NROFATTACKS]
Resistance adjustments for attacks.
Definition: object.h:351
PU_NOTHING
#define PU_NOTHING
Definition: define.h:106
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
PU_FOOD
#define PU_FOOD
Definition: define.h:115
name
Plugin animator file specs[Config] name
Definition: animfiles.txt:4
PU_FLESH
#define PU_FLESH
Definition: define.h:142
player_set_state
void player_set_state(player *pl, uint8_t state)
Set the player's state to the specified one.
Definition: player.cpp:4493
FLAG_REMOVED
#define FLAG_REMOVED
Object is not in any map or invenory.
Definition: define.h:219
FOR_BELOW_FINISH
#define FOR_BELOW_FINISH()
Finishes FOR_BELOW_PREPARE().
Definition: define.h:695
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_KNOWN_CURSED
#define FLAG_KNOWN_CURSED
The object is known to be cursed.
Definition: define.h:307
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:376
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
PU_BOW
#define PU_BOW
Definition: define.h:118
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
FLAG_ALIVE
#define FLAG_ALIVE
Object can fight (or be fought)
Definition: define.h:217
object::y
int16_t y
Position in the map for this object.
Definition: object.h:335
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:375
MOVE_ALL
#define MOVE_ALL
Mask of all movement types.
Definition: define.h:389
ST_CHANGE_PASSWORD_CONFIRM
#define ST_CHANGE_PASSWORD_CONFIRM
Player is confirming new password.
Definition: define.h:536
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
FLAG_FREED
#define FLAG_FREED
Object is in the list of free objects.
Definition: define.h:220
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
AP_NULL
#define AP_NULL
Nothing specific.
Definition: define.h:557
player_unready_range_ob
void player_unready_range_ob(player *pl, object *ob)
Unready an object for a player.
Definition: player.cpp:4475
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:547
ST_PLAY_AGAIN
#define ST_PLAY_AGAIN
Player left through a bed of reality, and can login again.
Definition: define.h:526
FLAG_READY_SKILL
#define FLAG_READY_SKILL
(Monster or Player) has a skill readied
Definition: define.h:320
FLAG_NEUTRAL
#define FLAG_NEUTRAL
monster is from type neutral
Definition: define.h:341
object::chosen_skill
object * chosen_skill
The skill chosen to use.
Definition: object.h:396
PU_MISSILEWEAPON
#define PU_MISSILEWEAPON
Definition: define.h:130
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
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:192
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
MSG_TYPE_ADMIN_NEWS
#define MSG_TYPE_ADMIN_NEWS
Definition: newclient.h:499
is_criminal
bool is_criminal(object *op)
Definition: player.cpp:313
player::last_speed
float last_speed
Last speed as sent to client.
Definition: player.h:175
add_refcount
sstring add_refcount(sstring str)
Like add_string(), but the string is already a shared string.
Definition: shstr.cpp:224
FLAG_KNOWN_MAGICAL
#define FLAG_KNOWN_MAGICAL
The object is known to be magical.
Definition: define.h:306
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
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
FLAG_NO_DROP
#define FLAG_NO_DROP
Object can't be dropped.
Definition: define.h:275
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:145
object::anim_speed
uint8_t anim_speed
Ticks between animation-frames.
Definition: object.h:429
PU_CLOAK
#define PU_CLOAK
Definition: define.h:127
FLAG_UNPAID
#define FLAG_UNPAID
Object hasn't been paid for yet.
Definition: define.h:223
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:180
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:4059
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
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:118
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:4220
ADD_PLAYER_NO_MAP
#define ADD_PLAYER_NO_MAP
Do not set the first map.
Definition: player.h:253
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:691
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:3437
object::run_away
uint8_t run_away
Monster runs away if it's hp goes below this percentage.
Definition: object.h:394
FLAG_NO_STRENGTH
#define FLAG_NO_STRENGTH
Strength-bonus not added to wc/dam.
Definition: define.h:293
AC_PLAYER_STAT_NO_CHANGE
#define AC_PLAYER_STAT_NO_CHANGE
Do not make any stat adjustments.
Definition: define.h:581
MSG_TYPE_COMMAND_INFO
#define MSG_TYPE_COMMAND_INFO
Generic info: resistances, etc.
Definition: newclient.h:530
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:1507
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)
Share a string.
Definition: shstr.cpp:137
player::delayed_buffers_used
uint8_t delayed_buffers_used
Used items in delayed_buffers_used.
Definition: player.h:227
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
FLAG_MONSTER
#define FLAG_MONSTER
Will attack players.
Definition: define.h:232
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:738
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
FLAG_CAN_USE_SKILL
#define FLAG_CAN_USE_SKILL
The monster can use skills.
Definition: define.h:308
range_magic
@ range_magic
Spells.
Definition: player.h:32
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
FLAG_UNAGGRESSIVE
#define FLAG_UNAGGRESSIVE
Monster doesn't attack players.
Definition: define.h:259
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
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
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:162
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:2323
player::last_character_flags
uint32_t last_character_flags
Last character flags (CS_STAT_CHARACTER_FLAGS) sent to client.
Definition: player.h:165
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:156
MSG_TYPE_ATTACK
#define MSG_TYPE_ATTACK
Attack related messages.
Definition: newclient.h:413
ST_ROLL_STAT
#define ST_ROLL_STAT
New character, rolling stats.
Definition: define.h:527
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
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:190
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:142
object::type
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:348
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:3298
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
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:3259
hideability
int hideability(object *ob)
Look at the surrounding terrain to determine the hideability of this object.
Definition: player.cpp:4018
leave
void leave(player *pl, int draw_exit)
Player logs out, or was disconnected.
Definition: server.cpp:1308
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:195
player_cancel_repeat
void player_cancel_repeat(player *pl)
If the player is repeating an action, cancel it.
Definition: player.cpp:320
FOR_INV_FINISH
#define FOR_INV_FINISH()
Finishes FOR_INV_PREPARE().
Definition: define.h:661
find_player
player * find_player(const char *plname)
Find a player by her full name.
Definition: player.cpp:59
FLAG_NO_PICK
#define FLAG_NO_PICK
Object can't be picked up.
Definition: define.h:226
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:3595
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
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
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:114
P_OUT_OF_MAP
#define P_OUT_OF_MAP
This space is outside the map.
Definition: map.h:252
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
ATNR_POISON
#define ATNR_POISON
Definition: attack.h:57
Settings::confdir
const char * confdir
Configuration files.
Definition: global.h:248
sproto.h
player::last_weight_limit
int32_t last_weight_limit
Last weight limit transmitted to client.
Definition: player.h:161
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
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:242
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:2351
AssetsCollection::each
void each(std::function< void(T *)> op)
Apply a function to each asset.
Definition: AssetsCollection.h:158
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
FLAG_IS_FLOOR
#define FLAG_IS_FLOOR
Can't see what's underneath this object.
Definition: define.h:289
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:734
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:2590
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:1705
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
PU_READABLES
#define PU_READABLES
Definition: define.h:137
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:111
player::fire_on
uint32_t fire_on
Player should fire object, not move.
Definition: player.h:144
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
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:166
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
PU_INHIBIT
#define PU_INHIBIT
Definition: define.h:109
FLAG_INV_LOCKED
#define FLAG_INV_LOCKED
Item will not be dropped from inventory.
Definition: define.h:316
treasure::next
treasure * next
Next treasure-item in a linked list.
Definition: treasure.h:69
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:209
player::last_skill_ob
object * last_skill_ob[MAX_SKILLS]
Exp objects sent to client.
Definition: player.h:155
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
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
FLAG_USE_WEAPON
#define FLAG_USE_WEAPON
(Monster) can wield weapons
Definition: define.h:283
EXIT_X
#define EXIT_X(xyz)
Definition: define.h:426
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:160
Ns_Add
@ Ns_Add
Definition: newserver.h:70
player::listening
uint8_t listening
Which priority will be used in info_all.
Definition: player.h:135
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:174
ADD_PLAYER_NEW
#define ADD_PLAYER_NEW
Name/password provided, so skip to roll stats.
Definition: player.h:252
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:169
cast_dust
void cast_dust(object *op, object *throw_ob, int dir)
Handles op throwing objects of type 'DUST'.
Definition: player.cpp:3953
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:294
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
PU_ARROW
#define PU_ARROW
Definition: define.h:120
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:123
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:3229
Settings::playerdir
const char * playerdir
Where the player files are.
Definition: global.h:251
RANDOM
#define RANDOM()
Definition: define.h:628
SockList_Term
void SockList_Term(SockList *sl)
Frees all resources allocated by a SockList instance.
Definition: lowlevel.cpp:65
FLAG_SEE_IN_DARK
#define FLAG_SEE_IN_DARK
if set ob not effected by darkness
Definition: define.h:324
SK_HIDING
@ SK_HIDING
Hiding.
Definition: skills.h:21
PU_SPELLBOOK
#define PU_SPELLBOOK
Definition: define.h:135
FREE_AND_CLEAR_STR
#define FREE_AND_CLEAR_STR(xyz)
Release the shared string, and set it to NULL.
Definition: global.h:200
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:49
player::gen_sp_armour
int16_t gen_sp_armour
Penalty to sp regen from armour.
Definition: player.h:130
living::maxgrace
int16_t maxgrace
Maximum grace.
Definition: living.h:45
FLAG_DAMNED
#define FLAG_DAMNED
The object is very cursed.
Definition: define.h:304
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:213
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:707
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
stand_near_hostile
int stand_near_hostile(object *who)
Determine if who is standing near a hostile creature.
Definition: player.cpp:4100
FIND_PLAYER_NO_HIDDEN_DM
#define FIND_PLAYER_NO_HIDDEN_DM
Don't find hidden DMs.
Definition: player.h:243
OUT_OF_REAL_MAP
#define OUT_OF_REAL_MAP(M, X, Y)
Checks if a square is out of the map.
Definition: map.h:220
player::gen_hp
int16_t gen_hp
Bonuses to regeneration speed of hp.
Definition: player.h:128
PU_MELEEWEAPON
#define PU_MELEEWEAPON
Definition: define.h:131
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
sounds.h
ST_CHANGE_CLASS
#define ST_CHANGE_CLASS
New character, choosing class.
Definition: define.h:528
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
Settings::emergency_mapname
char * emergency_mapname
Map to return players to in emergency.
Definition: global.h:300
P_IS_ALIVE
#define P_IS_ALIVE
Something alive is on this space.
Definition: map.h:240
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
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
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:146
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:206
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
PU_JEWELS
#define PU_JEWELS
Definition: define.h:141
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
IS_SHIELD
#define IS_SHIELD(op)
Definition: define.h:170
PU_RATIO
#define PU_RATIO
Definition: define.h:113
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
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
repeat_cb
bool(* repeat_cb)(player *, void *data)
Definition: player.h:104
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:1333
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:318
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
AP_NOPRINT
#define AP_NOPRINT
Don't print messages - caller will do that may be some that still print.
Definition: define.h:569
sstring
const typedef char * sstring
Definition: sstring.h:2
living::Cha
int8_t Cha
Definition: living.h:36
FLAG_UNDEAD
#define FLAG_UNDEAD
Monster is undead.
Definition: define.h:257
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
PU_DRINK
#define PU_DRINK
Definition: define.h:116
save_life
static int save_life(object *op)
Can the player be saved by an item?
Definition: player.cpp:3186
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:222
find_archetype
archetype * find_archetype(const char *name)
Definition: assets.cpp:270
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:133
EXIT_ALT_X
#define EXIT_ALT_X(xyz)
Definition: define.h:428
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:4317
shop_contains
bool shop_contains(object *ob)
Check if an object is in a shop.
Definition: map.cpp:2763
mapstruct::in_memory
uint32_t in_memory
Combination of IN_MEMORY_xxx flags.
Definition: map.h:338
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:3476
player::braced
uint32_t braced
Will not move if braced, only attack.
Definition: player.h:141
FLAG_APPLIED
#define FLAG_APPLIED
Object is ready for use by living.
Definition: define.h:222
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
rv_vector
This is used by get_rangevector to determine where the other creature is.
Definition: map.h:373
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:427
get_randomized_dir
int get_randomized_dir(int dir)
Returns a random direction (1..8) similar to a given direction.
Definition: utils.cpp:412
PU_POTION
#define PU_POTION
Definition: define.h:133
assets.h
CLEAR_FLAG
#define CLEAR_FLAG(xyz, p)
Definition: define.h:370
NDI_BROWN
#define NDI_BROWN
Sienna.
Definition: newclient.h:257
FLAG_STARTEQUIP
#define FLAG_STARTEQUIP
Object was given to player at start.
Definition: define.h:255
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:176
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
UP_OBJ_FACE
#define UP_OBJ_FACE
Only thing that changed was the face.
Definition: object.h:533
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:2522
player::party
partylist * party
Party this player is part of.
Definition: player.h:205
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
FLAG_CONFUSED
#define FLAG_CONFUSED
Will also be unable to cast spells.
Definition: define.h:298
get_player
player * get_player(player *p)
Create a player's object, initialize a player's structure.
Definition: player.cpp:285
player::repeat_func_data
void * repeat_func_data
Arguments to pass into repeat_func.
Definition: player.h:233
MSG_TYPE_ADMIN_LOGIN
#define MSG_TYPE_ADMIN_LOGIN
login messages/errors
Definition: newclient.h:504
player::repeat_action
sstring repeat_action
Shared string with textual description of current repeat action (e.g.
Definition: player.h:232
MSG_TYPE_ATTRIBUTE_BAD_EFFECT_END
#define MSG_TYPE_ATTRIBUTE_BAD_EFFECT_END
End of a bad effect.
Definition: newclient.h:571
AT_PHYSICAL
#define AT_PHYSICAL
Basic attack (1)
Definition: attack.h:78
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:3932
save_player
int save_player(object *op, int flag)
Saves a player to disk.
Definition: login.cpp:239
apply_container
int apply_container(object *op, object *sack, int aflags)
Handle apply on containers.
Definition: container.cpp:203
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:608
FOOD
@ FOOD
Definition: object.h:117
IS_ARMOR
#define IS_ARMOR(op)
Definition: define.h:166
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:226
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
PU_MAGIC_DEVICE
#define PU_MAGIC_DEVICE
Definition: define.h:138
PU_ARMOUR
#define PU_ARMOUR
Definition: define.h:123
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
player::last_path_repelled
uint32_t last_path_repelled
Last spell repelled sent to client.
Definition: player.h:163
MOVE_FLY_LOW
#define MOVE_FLY_LOW
Low flying object.
Definition: define.h:384
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:418
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
PU_HELMET
#define PU_HELMET
Definition: define.h:121
DRINK
@ DRINK
Definition: object.h:162
FLAG_USE_SHIELD
#define FLAG_USE_SHIELD
Can this creature use a shield?
Definition: define.h:224
player::password
char password[16]
2 (seed) + 11 (crypted) + 1 (EOS) + 2 (safety) = 16
Definition: player.h:195
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:51
AT_DEATH
#define AT_DEATH
Chance of instant death, otherwise nothing (131072) peterm@soda.berkeley.edu.
Definition: attack.h:95
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_WAS_WIZ
#define FLAG_WAS_WIZ
Player was once a wiz.
Definition: define.h:221
player::socket
socket_struct * socket
Socket information for this player.
Definition: player.h:109
mapstruct::next
mapstruct * next
Next map, linked list.
Definition: map.h:319
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:692
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:186
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
PU_MAGICAL
#define PU_MAGICAL
Definition: define.h:132
FLAG_IDENTIFIED
#define FLAG_IDENTIFIED
Item is identifiable (e.g.
Definition: define.h:248
server.h
PU_VALUABLES
#define PU_VALUABLES
Definition: define.h:117
freearr_x
short freearr_x[SIZEOFFREE]
X offset when searching around a spot.
Definition: object.cpp:299
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:117
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:158
ATNR_ELECTRICITY
#define ATNR_ELECTRICITY
Definition: attack.h:50
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:153
SPELL
@ SPELL
Definition: object.h:219
player::repeat_func
repeat_cb repeat_func
If not NULL, automatically repeat the action repeat_func until interrupted.
Definition: player.h:231
player::spellparam
char spellparam[MAX_BUF]
What param to add to spells.
Definition: player.h:115
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:288
mapstruct::darkness
uint8_t darkness
Indicates level of darkness of map.
Definition: map.h:339
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
FLAG_UNIQUE
#define FLAG_UNIQUE
Item is really unique (UNIQUE_ITEMS)
Definition: define.h:274
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
PU_GLOVES
#define PU_GLOVES
Definition: define.h:126
rv_vector::direction
int direction
General direction to the targer.
Definition: map.h:377
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:4001
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:374
player::bowtype
bowtype_t bowtype
Which firemode?
Definition: player.h:116
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:654
MAX_FOOD
static const int32_t MAX_FOOD
Definition: define.h:446
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:138
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:429
object.h
player::ticks_played
uint32_t ticks_played
How many ticks this player has played.
Definition: player.h:224
player::usekeys
usekeytype usekeys
Method for finding keys for doors.
Definition: player.h:122
player::rejoin_party
party_rejoin_mode rejoin_party
Whether to rejoin or not party at login.
Definition: player.h:212
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
player_start_repeat
void player_start_repeat(player *pl, const char *action, repeat_cb cb)
Start repeating an action.
Definition: player.cpp:4545
llevDebug
@ llevDebug
Only for debugging purposes.
Definition: logger.h:13
MONEY
@ MONEY
Definition: object.h:142
ST_GET_PARTY_PASSWORD
#define ST_GET_PARTY_PASSWORD
Player tried to join a password-protected party.
Definition: define.h:533
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
FORCE_NAME
#define FORCE_NAME
Definition: spells.h:169
living::Con
int8_t Con
Definition: living.h:36
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:1294
CS_QUERY_HIDEINPUT
#define CS_QUERY_HIDEINPUT
Hide input being entered.
Definition: newclient.h:72
hide
uint32 hide
Definition: arch-handbook.txt:572
Settings::localdir
const char * localdir
Read/write data files.
Definition: global.h:250