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->client = NULL;
438  ns->account_name = strdup_local("");
439  ns->account_chars = NULL; // If not NULL, the reference is now kept by p
440 
441  if (p->socket->faces_sent == NULL)
443 
444  /* Needed because the socket we just copied over needs to be cleared.
445  * Note that this can result in a client reset if there is partial data
446  * on the incoming socket.
447  */
449 
450 
451 }
452 
470  player *p;
471 
472  p = get_player(NULL);
473  set_player_socket(p, ns);
474  ns->status = Ns_Avail;
475 
477 
478  if (!(flags & ADD_PLAYER_NO_MAP))
479  set_first_map(p->ob);
480 
482 
483  /* In this case, the client is provide all the informatin for the
484  * new character, so just return it. Do not display any messages,
485  * etc
486  */
488  return p;
489 
490  if (flags & ADD_PLAYER_NEW) {
491  roll_again(p->ob);
493  } else {
494  send_rules(p->ob);
495  send_news(p->ob);
496  display_motd(p->ob);
497  get_name(p->ob);
498  }
499  return p;
500 }
501 
502 std::vector<archetype *> players;
503 
515  if (players.empty()) {
516  getManager()->archetypes()->each([] (const auto &at) {
517  if (at->clone.type == PLAYER) {
518  players.push_back(at);
519  }
520  });
521  if (players.empty()) {
522  LOG(llevError, "No Player archetypes\n");
524  }
525  }
526 
527  if (!at) {
528  return players.front();
529  }
530  auto pos = std::find(players.cbegin(), players.cend(), at);
531  if (pos == players.cend()) {
532  return nullptr;
533  }
534  ++pos;
535  if (pos == players.cend()) {
536  return players.front();
537  }
538  return *pos;
539 }
540 
549 object *get_nearest_player(object *mon) {
550  object *op = NULL;
551  player *pl = NULL;
552  objectlink *list, *ol;
553  unsigned lastdist;
554  rv_vector rv;
555 
556  list = get_friends_of(NULL);
557 
558  for (ol = list, lastdist = 1000; ol != NULL; ol = ol->next) {
559  if (QUERY_FLAG(ol->ob, FLAG_FREED) || !QUERY_FLAG(ol->ob, FLAG_FRIENDLY)) {
560  continue;
561  }
562 
563  /* Remove special check for player from this. First, it looks to cause
564  * some crashes (ol->ob->contr not set properly?), but secondly, a more
565  * complicated method of state checking would be needed in any case -
566  * as it was, a clever player could type quit, and the function would
567  * skip them over while waiting for confirmation. Remove
568  * on_same_map check, as monster_can_detect_enemy() also does this
569  */
570  if (!monster_can_detect_enemy(mon, ol->ob, &rv))
571  continue;
572 
573  if (lastdist > rv.distance) {
574  op = ol->ob;
575  lastdist = rv.distance;
576  }
577  }
578  if (list) {
580  }
581  for (pl = first_player; pl != NULL; pl = pl->next) {
582  if (monster_can_detect_enemy(mon, pl->ob, &rv)) {
583  if (lastdist > rv.distance) {
584  op = pl->ob;
585  lastdist = rv.distance;
586  }
587  }
588  }
589  return op;
590 }
591 
592 object *get_nearest_criminal(object *mon) {
593  object *op = NULL;
594  for (player *pl = first_player; pl != NULL; pl = pl->next) {
595  rv_vector rv;
596  if (monster_can_detect_enemy(mon, pl->ob, &rv) && is_criminal(pl->ob)) {
597  op = pl->ob;
598  }
599  }
600  return op;
601 }
602 
612 #define DETOUR_AMOUNT 2
613 
627 #define MAX_SPACES 50
628 
660 int path_to_player(object *mon, object *pl, unsigned mindiff) {
661  rv_vector rv;
662  int16_t x, y;
663  int lastx, lasty, dir, i, diff, firstdir = 0, lastdir, max = MAX_SPACES, mflags, blocked;
664  mapstruct *m, *lastmap;
665 
666  if (!get_rangevector(mon, pl, &rv, 0))
667  return 0;
668 
669  if (rv.distance < mindiff)
670  return 0;
671 
672  x = mon->x;
673  y = mon->y;
674  m = mon->map;
675  dir = rv.direction;
676  lastdir = firstdir = rv.direction; /* perhaps we stand next to pl, init firstdir too */
677  diff = MAX(FABS(rv.distance_x), FABS(rv.distance_y));
678  /* If we can't solve it within the search distance, return now. */
679  if (diff > max)
680  return 0;
681  while (diff > 1 && max > 0) {
682  lastx = x;
683  lasty = y;
684  lastmap = m;
685  x = lastx+freearr_x[dir];
686  y = lasty+freearr_y[dir];
687 
688  mflags = get_map_flags(m, &m, x, y, &x, &y);
689  blocked = (mflags&P_OUT_OF_MAP) ? MOVE_ALL : GET_MAP_MOVE_BLOCK(m, x, y);
690 
691  /* Space is blocked - try changing direction a little */
692  if ((mflags&P_OUT_OF_MAP)
693  || ((OB_TYPE_MOVE_BLOCK(mon, blocked) || (mflags&P_IS_ALIVE))
694  && (m == mon->map && blocked_link(mon, m, x, y)))) {
695  /* recalculate direction from last good location. Possible
696  * we were not traversing ideal location before.
697  */
698  if (get_rangevector_from_mapcoord(lastmap, lastx, lasty, pl, &rv) && rv.direction != dir) {
699  /* OK - says direction should be different - lets reset the
700  * the values so it will try again.
701  */
702  x = lastx;
703  y = lasty;
704  m = lastmap;
705  dir = firstdir = rv.direction;
706  } else {
707  /* direct path is blocked - try taking a side step to
708  * either the left or right.
709  * Note increase the values in the loop below to be
710  * more than -1/1 respectively will mean the monster takes
711  * bigger detour. Have to be careful about these values getting
712  * too big (3 or maybe 4 or higher) as the monster may just try
713  * stepping back and forth
714  */
715  for (i = -DETOUR_AMOUNT; i <= DETOUR_AMOUNT; i++) {
716  if (i == 0)
717  continue; /* already did this, so skip it */
718  /* Use lastdir here - otherwise,
719  * since the direction that the creature should move in
720  * may change, you could get infinite loops.
721  * ie, player is northwest, but monster can only
722  * move west, so it does that. It goes some distance,
723  * gets blocked, finds that it should move north,
724  * can't do that, but now finds it can move east, and
725  * gets back to its original point. lastdir contains
726  * the last direction the creature has successfully
727  * moved.
728  */
729 
730  x = lastx+freearr_x[absdir(lastdir+i)];
731  y = lasty+freearr_y[absdir(lastdir+i)];
732  m = lastmap;
733  mflags = get_map_flags(m, &m, x, y, &x, &y);
734  if (mflags&P_OUT_OF_MAP)
735  continue;
736  blocked = GET_MAP_MOVE_BLOCK(m, x, y);
737  if (OB_TYPE_MOVE_BLOCK(mon, blocked))
738  continue;
739  if (mflags&P_IS_ALIVE)
740  continue;
741 
742  if (m == mon->map && blocked_link(mon, m, x, y))
743  break;
744  }
745  /* go through entire loop without finding a valid
746  * sidestep to take - thus, no valid path.
747  */
748  if (i == (DETOUR_AMOUNT+1))
749  return 0;
750  diff--;
751  lastdir = dir;
752  max--;
753  if (!firstdir)
754  firstdir = dir+i;
755  } /* else check alternate directions */
756  } /* if blocked */
757  else {
758  /* we moved towards creature, so diff is less */
759  diff--;
760  max--;
761  lastdir = dir;
762  if (!firstdir)
763  firstdir = dir;
764  }
765  if (diff <= 1) {
766  /* Recalculate diff (distance) because we may not have actually
767  * headed toward player for entire distance.
768  */
769  if (!get_rangevector_from_mapcoord(m, x, y, pl, &rv))
770  return 0;
771  diff = MAX(FABS(rv.distance_x), FABS(rv.distance_y));
772  }
773  if (diff > max)
774  return 0;
775  }
776  /* If we reached the max, didn't find a direction in time */
777  if (!max)
778  return 0;
779 
780  return firstdir;
781 }
782 
793 void give_initial_items(object *pl, treasurelist *items) {
794  if (pl->randomitems != NULL)
795  create_treasure(items, pl, GT_STARTEQUIP|GT_ONLY_GOOD, 1, 0);
796 
797  FOR_INV_PREPARE(pl, op) {
798  /* Forces get applied per default, unless they have the
799  * flag "neutral" set. Sorry but I can't think of a better way
800  */
801  if (op->type == FORCE && !QUERY_FLAG(op, FLAG_NEUTRAL))
802  SET_FLAG(op, FLAG_APPLIED);
803 
804  /* we never give weapons/armour if these cannot be used
805  * by this player due to race restrictions
806  */
807  if (pl->type == PLAYER) {
808  if ((!QUERY_FLAG(pl, FLAG_USE_ARMOUR) && IS_ARMOR(op))
809  || (!QUERY_FLAG(pl, FLAG_USE_WEAPON) && IS_WEAPON(op))
810  || (!QUERY_FLAG(pl, FLAG_USE_SHIELD) && IS_SHIELD(op))) {
811  object_remove(op);
813  continue;
814  }
815  }
816 
817  /* This really needs to be better - we should really give
818  * a substitute spellbook. The problem is that we don't really
819  * have a good idea what to replace it with (need something like
820  * a first level treasurelist for each skill.)
821  * remove duplicate skills also
822  */
823  if (op->type == SPELLBOOK || op->type == SKILL) {
824  int found;
825 
826  found = 0;
827  // Make sure we set flags that are checked by object_can_merge
828  // *before* we run object_can_merge. Otherwise, we can get two
829  // entries of the same skill.
830  if (op->type == SKILL) {
832  op->stats.exp = 0;
833  op->level = 1;
834  // Since this also happens to the invisible skills, we need this so that the flags match.
836  }
837  FOR_BELOW_PREPARE(op, tmp)
838  if (object_can_merge(op, tmp)) {
839  found = 1;
840  break;
841  }
843  if (found) {
844  LOG(llevError, "give_initial_items: Removing duplicate object %s\n", op->name);
845  object_remove(op);
847  continue;
848  }
849  if (op->nrof > 1)
850  op->nrof = 1;
851  }
852 
853  if (op->type == SPELLBOOK && op->inv) {
854  CLEAR_FLAG(op->inv, FLAG_STARTEQUIP);
855  }
856 
857  /* Give starting characters identified, uncursed, and undamned
858  * items. Just don't identify gold or silver, or it won't be
859  * merged properly.
860  */
861  if (is_identifiable_type(op)) {
863  CLEAR_FLAG(op, FLAG_CURSED);
864  CLEAR_FLAG(op, FLAG_DAMNED);
865  }
866  } FOR_INV_FINISH(); /* for loop of objects in player inv */
867 
868  /* Need to set up the skill pointers */
869  link_player_skills(pl);
870 
875  FOR_INV_PREPARE(pl, op)
876  if ((IS_ARMOR(op) || IS_WEAPON(op) || IS_SHIELD(op)) && !QUERY_FLAG(op, FLAG_APPLIED))
877  apply_manual(pl, op, AP_NOPRINT);
878  FOR_INV_FINISH();
879 }
880 
887 void get_name(object *op) {
889  send_query(op->contr->socket, 0, i18n(op, "What is your name?\n:"));
890 }
891 
898 void get_password(object *op) {
900  send_query(op->contr->socket, CS_QUERY_HIDEINPUT, i18n(op, "What is your password?\n:"));
901 }
902 
909 void play_again(object *op) {
910  SockList sl;
911 
912  op->contr->socket->status = Ns_Add;
914  op->chosen_skill = NULL;
915 
916  /*
917  * For old clients, ask if they want to play again.
918  * For clients with account support, just return to character seletion (see below).
919  */
920  if (op->contr->socket->login_method == 0) {
921  send_query(op->contr->socket, CS_QUERY_SINGLECHAR, i18n(op, "Do you want to play again (a/q)?"));
922  }
923  /* a bit of a hack, but there are various places early in th
924  * player creation process that a user can quit (eg, roll
925  * stats) that isn't removing the player. Taking a quick
926  * look, there are many places that call play_again without
927  * removing the player - it probably makes more sense
928  * to leave it to play_again to remove the object in all
929  * cases.
930  */
931  if (!QUERY_FLAG(op, FLAG_REMOVED))
932  object_remove(op);
933  /* Need to set this to null - otherwise, it could point to garbage,
934  * and draw() doesn't check to see if the player is removed, only if
935  * the map is null or not swapped out.
936  */
937  op->map = NULL;
938 
939  SockList_Init(&sl);
940  SockList_AddString(&sl, "player ");
941  SockList_AddInt(&sl, 0);
942  SockList_AddInt(&sl, 0);
943  SockList_AddInt(&sl, 0);
944  SockList_AddChar(&sl, 0);
945 
946  Send_With_Handling(op->contr->socket, &sl);
947  SockList_Term(&sl);
948 
949  if (op->contr->socket->login_method > 0) {
950  receive_play_again(op, 'a');
951  }
952 }
953 
962 void receive_play_again(object *op, char key) {
963  if (key == 'q' || key == 'Q') {
965  leave(op->contr, 0); /* ericserver will draw the message */
966  return;
967  } else if (key == 'a' || key == 'A') {
968  player *pl = op->contr;
969  const char *name = op->name;
970 
974  pl = get_player(pl);
975  op = pl->ob;
977  op->contr->password[0] = '~';
980  if (pl->socket->login_method >= 1 && pl->socket->account_name != NULL) {
981  /* If we are using new login, we send the
982  * list of characters to the client - this should
983  * result in the client popping up this list so
984  * the player can choose which one to play - better
985  * than going to legacy login code.
986  * If the account_name is NULL, it means the client
987  * says it uses account but started playing without logging in.
988  */
991  } else {
992  /* Lets put a space in here */
994  "\n");
995  get_name(op);
996  set_first_map(op);
997  }
998  op->name = name; /* Already added a refcount above */
999  op->name_pl = add_string(name);
1000  } else {
1001  /* user pressed something else so just ask again... */
1002  play_again(op);
1003  }
1004 }
1005 
1012 void confirm_password(object *op) {
1014  send_query(op->contr->socket, CS_QUERY_HIDEINPUT, i18n(op, "Please type your password again.\n:"));
1015 }
1016 
1027 int get_party_password(object *op, partylist *party) {
1028  if (*party_get_password(party) == '\0') {
1029  return 0;
1030  }
1031 
1033  op->contr->party_to_join = party;
1034  send_query(op->contr->socket, CS_QUERY_HIDEINPUT, i18n(op, "What is the password?\n:"));
1035  return 1;
1036 }
1037 
1044 int roll_stat(void) {
1045  int roll[4], i, low_index, k;
1046 
1047  for (i = 0; i < 4; ++i)
1048  roll[i] = (int)RANDOM()%6+1;
1049 
1050  for (i = 0, low_index = 0, k = 7; i < 4; ++i)
1051  if (roll[i] < k)
1052  k = roll[i],
1053  low_index = i;
1054 
1055  for (i = 0, k = 0; i < 4; ++i) {
1056  if (i != low_index)
1057  k += roll[i];
1058  }
1059  return k;
1060 }
1061 
1068 void roll_stats(object *op) {
1069  int i = 0, j = 0;
1070  int statsort[7];
1071 
1072  op->stats.Str = roll_stat();
1073  op->stats.Dex = roll_stat();
1074  op->stats.Int = roll_stat();
1075  op->stats.Con = roll_stat();
1076  op->stats.Wis = roll_stat();
1077  op->stats.Pow = roll_stat();
1078  op->stats.Cha = roll_stat();
1079  int sum = op->stats.Str+op->stats.Dex+op->stats.Int+op->stats.Con+op->stats.Wis+op->stats.Pow+op->stats.Cha;
1080  float scale = settings.roll_stat_points / sum;
1081  op->stats.Str = roundf(scale * op->stats.Str);
1082  op->stats.Dex = roundf(scale * op->stats.Dex);
1083  op->stats.Int = roundf(scale * op->stats.Int);
1084  op->stats.Con = roundf(scale * op->stats.Con);
1085  op->stats.Wis = roundf(scale * op->stats.Wis);
1086  op->stats.Pow = roundf(scale * op->stats.Pow);
1087  op->stats.Cha = roundf(scale * op->stats.Cha);
1088 
1089  /* Sort the stats so that rerolling is easier... */
1090  statsort[0] = op->stats.Str;
1091  statsort[1] = op->stats.Dex;
1092  statsort[2] = op->stats.Int;
1093  statsort[3] = op->stats.Con;
1094  statsort[4] = op->stats.Wis;
1095  statsort[5] = op->stats.Pow;
1096  statsort[6] = op->stats.Cha;
1097 
1098  /* a quick and dirty bubblesort? */
1099  do {
1100  if (statsort[i] < statsort[i+1]) {
1101  j = statsort[i];
1102  statsort[i] = statsort[i+1];
1103  statsort[i+1] = j;
1104  i = 0;
1105  } else {
1106  i++;
1107  }
1108  } while (i < 6);
1109 
1110  op->stats.Str = statsort[0];
1111  op->stats.Dex = statsort[1];
1112  op->stats.Con = statsort[2];
1113  op->stats.Int = statsort[3];
1114  op->stats.Wis = statsort[4];
1115  op->stats.Pow = statsort[5];
1116  op->stats.Cha = statsort[6];
1117 
1118  op->contr->orig_stats.Str = op->stats.Str;
1119  op->contr->orig_stats.Dex = op->stats.Dex;
1120  op->contr->orig_stats.Int = op->stats.Int;
1121  op->contr->orig_stats.Con = op->stats.Con;
1122  op->contr->orig_stats.Wis = op->stats.Wis;
1123  op->contr->orig_stats.Pow = op->stats.Pow;
1124  op->contr->orig_stats.Cha = op->stats.Cha;
1125 
1126  op->level = 1;
1127  op->stats.exp = 0;
1128  op->stats.ac = 0;
1129 
1130  op->contr->levhp[1] = 9;
1131  op->contr->levsp[1] = 6;
1132  op->contr->levgrace[1] = 3;
1133 
1134  fix_object(op);
1135  op->stats.hp = op->stats.maxhp;
1136  op->stats.sp = op->stats.maxsp;
1137  op->stats.grace = op->stats.maxgrace;
1138  op->contr->orig_stats = op->stats;
1139 }
1140 
1147 void roll_again(object *op) {
1148  esrv_new_player(op->contr, 0);
1149  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)? "));
1150 }
1151 
1161 static void swap_stat(object *op, int swap_second) {
1162  signed char tmp;
1163 
1164  if (op->contr->swap_first == -1) {
1165  LOG(llevError, "player.c:swap_stat() - swap_first is -1\n");
1166  return;
1167  }
1168 
1169  tmp = get_attr_value(&op->contr->orig_stats, op->contr->swap_first);
1170 
1171  set_attr_value(&op->contr->orig_stats, op->contr->swap_first, get_attr_value(&op->contr->orig_stats, swap_second));
1172 
1173  set_attr_value(&op->contr->orig_stats, swap_second, tmp);
1174 
1176  "%s done\n",
1177  short_stat_name[swap_second]);
1178 
1179  op->stats.Str = op->contr->orig_stats.Str;
1180  op->stats.Dex = op->contr->orig_stats.Dex;
1181  op->stats.Con = op->contr->orig_stats.Con;
1182  op->stats.Int = op->contr->orig_stats.Int;
1183  op->stats.Wis = op->contr->orig_stats.Wis;
1184  op->stats.Pow = op->contr->orig_stats.Pow;
1185  op->stats.Cha = op->contr->orig_stats.Cha;
1186  op->stats.ac = 0;
1187 
1188  op->level = 1;
1189  op->stats.exp = 0;
1190  op->stats.ac = 0;
1191 
1192  op->contr->levhp[1] = 9;
1193  op->contr->levsp[1] = 6;
1194  op->contr->levgrace[1] = 3;
1195 
1196  fix_object(op);
1197  op->stats.hp = op->stats.maxhp;
1198  op->stats.sp = op->stats.maxsp;
1199  op->stats.grace = op->stats.maxgrace;
1200  op->contr->orig_stats = op->stats;
1201  op->contr->swap_first = -1;
1202 }
1203 
1219 void key_roll_stat(object *op, char key) {
1220  int keynum = key-'0';
1221  static const int8_t stat_trans[] = {
1222  -1,
1223  STRENGTH,
1224  DEXTERITY,
1225  CONSTITUTION,
1226  INTELLIGENCE,
1227  WISDOM,
1228  POWER,
1229  CHARISMA,
1230  };
1231 
1232  if (keynum > 0 && keynum <= 7) {
1233  if (op->contr->swap_first == -1) {
1234  op->contr->swap_first = stat_trans[keynum];
1236  "%s ->",
1237  short_stat_name[stat_trans[keynum]]);
1238  } else
1239  swap_stat(op, stat_trans[keynum]);
1240 
1242  return;
1243  }
1244  switch (key) {
1245  case 'n':
1246  case 'N': {
1247  SET_FLAG(op, FLAG_WIZ);
1248  if (op->map == NULL) {
1249  LOG(llevError, "Map == NULL in state 2\n");
1250  break;
1251  }
1252 
1253  SET_ANIMATION(op, 2); /* So player faces south */
1254  /* Enter exit adds a player otherwise */
1255  add_statbonus(op);
1256  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"));
1258  if (op->msg)
1259  draw_ext_info(NDI_BLUE, 0, op,
1261  op->msg);
1262  return;
1263  }
1264  case 'y':
1265  case 'Y':
1266  roll_stats(op);
1268  return;
1269 
1270  case 'q':
1271  case 'Q':
1272  play_again(op);
1273  return;
1274 
1275  default:
1276  send_query(op->contr->socket, CS_QUERY_SINGLECHAR, i18n(op, "Yes, No, Quit or 1-6. Roll again?"));
1277  return;
1278  }
1279  return;
1280 }
1281 
1295 void key_change_class(object *op, char key) {
1296  int tmp_loop;
1297 
1298  if (key == 'q' || key == 'Q') {
1299  object_remove(op);
1300  play_again(op);
1301  return;
1302  }
1303  if (key == 'd' || key == 'D') {
1304  char buf[MAX_BUF];
1305 
1306  /* this must before then initial items are given */
1307  esrv_new_player(op->contr, op->weight+op->carrying);
1308  create_treasure(find_treasurelist("starting_wealth"), op, 0, 0, 0);
1309 
1310  /* Here we handle the BORN global event */
1312 
1313  /* We then generate a LOGIN event */
1316 
1317  object_set_msg(op, NULL);
1318 
1319  /* We create this now because some of the unique maps will need it
1320  * to save here.
1321  */
1322  snprintf(buf, sizeof(buf), "%s/%s/%s", settings.localdir, settings.playerdir, op->name);
1324 
1325 #ifdef AUTOSAVE
1326  op->contr->last_save_tick = pticks;
1327 #endif
1330  "Welcome to Crossfire!\n Press `?' for help\n");
1331 
1334  "%s entered the game.", op->name);
1335 
1336  CLEAR_FLAG(op, FLAG_WIZ);
1338  link_player_skills(op);
1339  esrv_send_inventory(op, op);
1340  fix_object(op);
1341 
1342  /* This moves the player to a different start map, if there
1343  * is one for this race
1344  */
1345  if (*first_map_ext_path) {
1346  object *tmp;
1347  char mapname[MAX_BUF + strlen(op->arch->name) + 1];
1348  mapstruct *oldmap;
1349 
1350  oldmap = op->map;
1351 
1352  snprintf(mapname, sizeof(mapname), "%s/%s", first_map_ext_path, op->arch->name);
1353  /*printf("%s\n", mapname);*/
1354  tmp = object_new();
1355  EXIT_PATH(tmp) = add_string(mapname);
1356  EXIT_X(tmp) = op->x;
1357  EXIT_Y(tmp) = op->y;
1358  enter_exit(op, tmp);
1359 
1360  if (oldmap != op->map) {
1361  /* map exists, update bed of reality location, in case player dies */
1362  op->contr->bed_x = op->x;
1363  op->contr->bed_y = op->y;
1364  strlcpy(op->contr->savebed_map, mapname, sizeof(op->contr->savebed_map));
1365  }
1366 
1368  } else {
1369  LOG(llevDebug, "first_map_ext_path not set\n");
1370  }
1371  return;
1372  }
1373 
1374  /* Following actually changes the race - this is the default command
1375  * if we don't match with one of the options above.
1376  */
1377 
1378  tmp_loop = 0;
1379  while (!tmp_loop) {
1380  const char *name = add_string(op->name);
1381  int x = op->x, y = op->y;
1382 
1383  remove_statbonus(op);
1384  object_remove(op);
1385  /* get_player_archetype() is really misnamed - it will
1386  * get the next archetype from the list.
1387  */
1388  op->arch = get_player_archetype(op->arch);
1389  object_copy(&op->arch->clone, op);
1390  op->stats = op->contr->orig_stats;
1391  free_string(op->name);
1392  op->name = name;
1393  free_string(op->name_pl);
1394  op->name_pl = add_string(name);
1395  SET_ANIMATION(op, 2); /* So player faces south */
1396  object_insert_in_map_at(op, op->map, op, 0, x, y);
1397  strncpy(op->contr->title, op->arch->clone.name, sizeof(op->contr->title)-1);
1398  op->contr->title[sizeof(op->contr->title)-1] = '\0';
1399  add_statbonus(op);
1400  tmp_loop = allowed_class(op);
1401  }
1403  esrv_update_item(UPD_FACE, op, op);
1404  fix_object(op);
1405  op->contr->is_wraith = object_find_by_name(op, "wraith feed") != NULL;
1406  op->stats.hp = op->stats.maxhp;
1407  op->stats.sp = op->stats.maxsp;
1408  op->stats.grace = 0;
1409  if (op->msg)
1411  op->msg);
1412  send_query(op->contr->socket, CS_QUERY_SINGLECHAR, i18n(op, "Press any key for the next race.\nPress `d' to play this race.\n"));
1413 }
1414 
1437 {
1438  int i, stat, failure=0;
1439 
1440  for (i = 0; i < NUM_STATS; i++) {
1441  stat = get_attr_value(stats, i);
1442  if (race)
1443  stat += get_attr_value(&race->clone.stats, i);
1444 
1445  if (opclass)
1446  stat += get_attr_value(&opclass->clone.stats, i);
1447 
1448  set_attr_value(stats, i, stat);
1449 
1450  /* We process all stats, regardless if there is a failure
1451  * or not.
1452  */
1453  if (stat < MIN_STAT) failure=1;
1454 
1455  /* Maybe this should be an error? Player is losing
1456  * some stats points here, but it is legal.
1457  */
1458  if (stat > settings.max_stat) stat = settings.max_stat;
1459  }
1460  return failure;
1461 
1462 }
1463 
1486 int apply_race_and_class(object *op, archetype *race, archetype *opclass, living *stats)
1487 {
1488  const char *name = add_string(op->name);
1489  char buf[MAX_BUF];
1490  object *inv;
1491 
1492  /* Free any objects in character inventory - they
1493  * shouldn't have any, but there is the potential that
1494  * we give them objects below and then get a creation
1495  * failure (stat out of range), in which case
1496  * those objects would be in the inventory.
1497  */
1498  while (op->inv) {
1499  inv = op->inv;
1500  object_remove(inv);
1501  object_free(inv, 0);
1502  }
1503 
1504  object_copy(&race->clone, op);
1505  free_string(op->name);
1506  op->name = name;
1507  free_string(op->name_pl);
1508  op->name_pl = add_string(name);
1509  SET_ANIMATION(op, 2); /* So player faces south */
1510  strlcpy(op->contr->title, op->arch->clone.name, sizeof(op->contr->title));
1511 
1512  if (stats) {
1513  /* Copy over the stats. Use this instead a memcpy because
1514  * we only want to copy over a few specific stats, and
1515  * leave things like maxhp, maxsp, etc, unchanged.
1516  */
1517  int i, stat;
1518  for (i = 0; i < NUM_STATS; i++) {
1519  stat = get_attr_value(stats, i);
1520  set_attr_value(&op->stats, i, stat);
1521  set_attr_value(&op->contr->orig_stats, i, stat);
1522  }
1523  } else {
1524  /* Note that this will repeated increase the stat values
1525  * if the caller does not reset them. Only do this
1526  * if stats is not provided - if stats is provided, those
1527  * are already adjusted.
1528  */
1529  add_statbonus(op);
1530 
1531  /* Checks that all stats are greater than 1. Once again,
1532  * only do this if stats are not provided
1533  */
1534  if (!allowed_class(op)) return 1;
1535  }
1536 
1538  op->stats.hp = op->stats.maxhp;
1539  op->stats.sp = op->stats.maxsp;
1540  op->stats.grace = 0;
1541 
1542  /* this must before then initial items are given */
1543  esrv_new_player(op->contr, op->weight+op->carrying);
1544  create_treasure(find_treasurelist("starting_wealth"), op, 0, 0, 0);
1545 
1546  /* This has to be done before class, otherwise the NOCLASSFACECHANGE
1547  * object is not in the inventory, and racial face will get overwritten.
1548  */
1550 
1551  if (stats) {
1552  /* Apply class information */
1554  } else {
1555  apply_changes_to_player(op, &opclass->clone, 0);
1556 
1557  /* Checks that all stats are greater than 1 */
1558  if (!allowed_class(op)) return 2;
1559  }
1560 
1561  /* Here we handle the BORN global event */
1563 
1564  /* We then generate a LOGIN event */
1566 
1567  object_set_msg(op, NULL);
1568 
1569  /* We create this now because some of the unique maps will need it
1570  * to save here.
1571  */
1572  snprintf(buf, sizeof(buf), "%s/%s/%s", settings.localdir, settings.playerdir, op->name);
1574 
1575 #ifdef AUTOSAVE
1576  op->contr->last_save_tick = pticks;
1577 #endif
1578 
1579  CLEAR_FLAG(op, FLAG_WIZ);
1580  link_player_skills(op);
1581  fix_object(op);
1582 
1583  esrv_send_inventory(op, op);
1584  esrv_update_item(UPD_FACE, op, op);
1585  esrv_add_spells(op->contr, NULL);
1586  op->contr->is_wraith = object_find_by_name(op, "wraith feed") != NULL;
1587 
1588  return 0;
1589 
1590 }
1591 
1600 void key_confirm_quit(object *op, char key) {
1601  char buf[MAX_BUF];
1602  mapstruct *mp, *next;
1603 
1604  // this was tested when 'quit' command was issued, but better safe than sorry.
1605  if (QUERY_FLAG(op, FLAG_WIZ)) {
1607  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_LOGIN, "Can't quit when in DM mode.");
1608  return;
1609  }
1610 
1611  if (key != 'y' && key != 'Y' && key != 'q' && key != 'Q') {
1614  "OK, continuing to play.");
1615  return;
1616  }
1617 
1619  pets_terminate_all(op);
1620  object_remove(op);
1621  op->direction = 0;
1623  "%s quits the game.",
1624  op->name);
1625 
1626  strcpy(op->contr->killer, "quit");
1627  hiscore_check(op, 0);
1628  party_leave(op);
1629  if (settings.set_title == TRUE)
1630  player_set_own_title(op->contr, "");
1631 
1632 
1633  /* We need to hunt for any per player unique maps in memory and
1634  * get rid of them. The trailing slash in the path is intentional,
1635  * so that players named 'Ab' won't match against players 'Abe' pathname
1636  */
1637  snprintf(buf, sizeof(buf), "~%s/%s/", settings.playerdir, op->name);
1638  for (mp = first_map; mp != NULL; mp = next) {
1639  next = mp->next;
1640  if (!strncmp(mp->path, buf, strlen(buf)))
1641  delete_map(mp);
1642  }
1643 
1644  delete_character(op->name);
1645 
1646  /* Remove player from account list and send back data if needed */
1647  if (op->contr->socket->account_chars != NULL) {
1650  /* char information is reloaded in send_account_players below */
1652  op->contr->socket->account_chars = NULL;
1655  }
1656 
1657  play_again(op);
1658 
1659  // Fields in op are not cleared until the client plays a different
1660  // character or disconnects. Therefore, after deleting a character,
1661  // immediately creating a new character with the same name as the deleted
1662  // one fails because verify_player() thinks this player is still playing.
1663  // So we do a little hacking by clearing the name now.
1664  FREE_AND_CLEAR_STR(op->name);
1665 }
1666 
1673 static void flee_player(object *op) {
1674  int dir, diff;
1675  rv_vector rv;
1676 
1677  if (op->stats.hp < 0) {
1678  LOG(llevDebug, "Fleeing player is dead.\n");
1679  CLEAR_FLAG(op, FLAG_SCARED);
1680  return;
1681  }
1682 
1683  if (op->enemy == NULL) {
1684  LOG(llevDebug, "Fleeing player had no enemy.\n");
1685  CLEAR_FLAG(op, FLAG_SCARED);
1686  return;
1687  }
1688 
1689  /* Seen some crashes here. Since we don't store an
1690  * op->enemy_count, it is possible that something destroys the
1691  * actual enemy, and the object is recycled.
1692  */
1693  if (op->enemy->map == NULL) {
1694  CLEAR_FLAG(op, FLAG_SCARED);
1695  object_set_enemy(op, NULL);
1696  return;
1697  }
1698 
1699  if (!(random_roll(0, 4, op, PREFER_LOW)) && did_make_save(op, op->level, 0)) {
1700  object_set_enemy(op, NULL);
1701  CLEAR_FLAG(op, FLAG_SCARED);
1702  return;
1703  }
1704  if (!get_rangevector(op, op->enemy, &rv, 0)) {
1705  object_set_enemy(op, NULL);
1706  CLEAR_FLAG(op, FLAG_SCARED);
1707  return;
1708  }
1709 
1710  dir = absdir(4+rv.direction);
1711  for (diff = 0; diff < 3; diff++) {
1712  int m = 1-(RANDOM()&2);
1713  if (move_ob(op, absdir(dir+diff*m), op)
1714  || (diff == 0 && move_ob(op, absdir(dir-diff*m), op))) {
1715  return;
1716  }
1717  }
1718  /* Cornered, get rid of scared */
1719  CLEAR_FLAG(op, FLAG_SCARED);
1720  object_set_enemy(op, NULL);
1721 }
1722 
1732 int check_pick(object *op) {
1733  tag_t op_tag;
1734  int stop = 0;
1735  int j, k, wvratio, current_ratio;
1736  char putstring[128], tmpstr[16];
1737 
1738  /* if you're flying, you can't pick up anything */
1739  if (op->move_type&MOVE_FLYING)
1740  return 1;
1741  /* If not a player, don't check anything. */
1742  if (!op->contr) {
1743  return 1;
1744  }
1745 
1746  op_tag = op->count;
1747 
1748  FOR_BELOW_PREPARE(op, tmp) {
1749  if (object_was_destroyed(op, op_tag))
1750  return 0;
1751 
1752  if (!object_can_pick(op, tmp))
1753  continue;
1754 
1755  if (op->contr->search_str[0] != '\0' && settings.search_items == TRUE) {
1756  if (object_matches_string(op, tmp, op->contr->search_str))
1757  pick_up(op, tmp);
1758  continue;
1759  }
1760 
1761  /* high not bit set? We're using the old autopickup model */
1762  if (!(op->contr->mode&PU_NEWMODE)) {
1763  switch (op->contr->mode) {
1764  case 0:
1765  return 1; /* don't pick up */
1766 
1767  case 1:
1768  pick_up(op, tmp);
1769  return 1;
1770 
1771  case 2:
1772  pick_up(op, tmp);
1773  return 0;
1774 
1775  case 3:
1776  return 0; /* stop before pickup */
1777 
1778  case 4:
1779  pick_up(op, tmp);
1780  break;
1781 
1782  case 5:
1783  pick_up(op, tmp);
1784  stop = 1;
1785  break;
1786 
1787  case 6:
1788  if (QUERY_FLAG(tmp, FLAG_KNOWN_MAGICAL)
1789  && !QUERY_FLAG(tmp, FLAG_KNOWN_CURSED))
1790  pick_up(op, tmp);
1791  break;
1792 
1793  case 7:
1794  if (tmp->type == MONEY || tmp->type == GEM)
1795  pick_up(op, tmp);
1796  break;
1797 
1798  default:
1799  /* use value density */
1800  if (!QUERY_FLAG(tmp, FLAG_UNPAID)
1801  && (price_base(tmp)*100/(tmp->weight*MAX(tmp->nrof, 1))) >= op->contr->mode)
1802  pick_up(op, tmp);
1803  }
1804  } else { /* old model */
1805  /* NEW pickup handling */
1806  if (op->contr->mode&PU_DEBUG) {
1807  /* some debugging code to figure out item information */
1809  "item name: %s item type: %d weight/value: %d",
1810  tmp->name ? tmp->name : tmp->arch->name, tmp->type,
1811  (int)(price_base(tmp)*100/(tmp->weight*MAX(tmp->nrof, 1))));
1812 
1813 
1814  snprintf(putstring, sizeof(putstring), "...flags: ");
1815  for (k = 0; k < 4; k++) {
1816  for (j = 0; j < 32; j++) {
1817  if ((tmp->flags[k]>>j)&0x01) {
1818  snprintf(tmpstr, sizeof(tmpstr), "%d ", k*32+j);
1819  strcat(putstring, tmpstr);
1820  }
1821  }
1822  }
1824  putstring);
1825  }
1826  /* philosophy:
1827  * It's easy to grab an item type from a pile, as long as it's
1828  * generic. This takes no game-time. For more detailed pickups
1829  * and selections, select-items should be used. This is a
1830  * grab-as-you-run type mode that's really useful for arrows for
1831  * example.
1832  * The drawback: right now it has no frontend, so you need to
1833  * stick the bits you want into a calculator in hex mode and then
1834  * convert to decimal and then 'pickup <#>
1835  */
1836 
1837  /* the first two modes are exclusive: if NOTHING we return, if
1838  * STOP then we stop. All the rest are applied sequentially,
1839  * meaning if any test passes, the item gets picked up. */
1840 
1841  /* if mode is set to pick nothing up, return */
1842 
1843  if (op->contr->mode == PU_NOTHING)
1844  return 1;
1845 
1846  /* if mode is set to stop when encountering objects, return.
1847  * Take STOP before INHIBIT since it doesn't actually pick
1848  * anything up */
1849 
1850  if (op->contr->mode&PU_STOP)
1851  return 0;
1852 
1853  /* useful for going into stores and not losing your settings... */
1854  /* and for battles where you don't want to get loaded down while
1855  * fighting */
1856  if (op->contr->mode&PU_INHIBIT)
1857  return 1;
1858 
1859  /* prevent us from turning into auto-thieves :) */
1860  if (QUERY_FLAG(tmp, FLAG_UNPAID))
1861  continue;
1862 
1863  /* ignore known cursed objects */
1865  continue;
1866 
1867  static int checks[] = {
1868  PU_FOOD,
1869  PU_DRINK,
1870  PU_FLESH,
1871  PU_POTION,
1872  PU_SPELLBOOK,
1874  PU_READABLES,
1876  PU_MAGICAL,
1877  PU_VALUABLES,
1878  PU_JEWELS,
1879  PU_BOW,
1880  PU_ARROW,
1881  PU_ARMOUR,
1882  PU_HELMET,
1883  PU_SHIELD,
1884  PU_BOOTS,
1885  PU_GLOVES,
1886  PU_CLOAK,
1889  PU_KEY,
1890  PU_CONTAINER,
1891  PU_CURSED,
1892  0
1893  };
1894  int found = 0;
1895  for (int m = 0; checks[m] != 0; m++) {
1896  if (op->contr->mode & checks[m] && object_matches_pickup_mode(tmp, checks[m])) {
1897  pick_up(op, tmp);
1898  found = 1;
1899  break;
1900  }
1901  }
1902  if (found) {
1903  continue;
1904  }
1905 
1906  /* any of the last 4 bits set means we use the ratio for value
1907  * pickups */
1908  if (op->contr->mode&PU_RATIO) {
1909  /* use value density to decide what else to grab.
1910  * >=7 was >= op->contr->mode
1911  * >=7 is the old standard setting. Now we take the last 4 bits
1912  * and multiply them by 5, giving 0..15*5== 5..75 */
1913  wvratio = (op->contr->mode&PU_RATIO)*5;
1914  current_ratio = price_base(tmp)*100/(tmp->weight*MAX(tmp->nrof, 1));
1915  if (current_ratio >= wvratio) {
1916  pick_up(op, tmp);
1917  continue;
1918  }
1919  }
1920  } /* the new pickup model */
1921  } FOR_BELOW_FINISH();
1922  return !stop;
1923 }
1924 
1937 static object *find_arrow(object *op, const char *type) {
1938  object *tmp = NULL;
1939 
1940  FOR_INV_PREPARE(op, inv)
1941  if (!tmp
1942  && inv->type == CONTAINER
1943  && inv->race == type
1944  && QUERY_FLAG(inv, FLAG_APPLIED))
1945  tmp = find_arrow(inv, type);
1946  else if (inv->type == ARROW && inv->race == type)
1947  return inv;
1948  FOR_INV_FINISH();
1949  return tmp;
1950 }
1951 
1969 static object *find_better_arrow(object *op, object *target, const char *type, int *better) {
1970  object *tmp = NULL, *ntmp;
1971  int attacknum, attacktype, betterby = 0, i;
1972 
1973  if (!type)
1974  return NULL;
1975 
1976  FOR_INV_PREPARE(op, arrow) {
1977  if (arrow->type == CONTAINER
1978  && arrow->race == type
1979  && QUERY_FLAG(arrow, FLAG_APPLIED)) {
1980  i = 0;
1981  ntmp = find_better_arrow(arrow, target, type, &i);
1982  if (i > betterby) {
1983  tmp = ntmp;
1984  betterby = i;
1985  }
1986  } else if (arrow->type == ARROW && arrow->race == type) {
1987  /* always prefer assassination/slaying */
1988  if (target->race != NULL
1989  && arrow->slaying != NULL
1990  && strstr(arrow->slaying, target->race)) {
1991  if (arrow->attacktype&AT_DEATH) {
1992  if (better)
1993  *better = 100;
1994  return arrow;
1995  } else {
1996  tmp = arrow;
1997  betterby = (arrow->magic+arrow->stats.dam)*2;
1998  }
1999  } else {
2000  for (attacknum = 0; attacknum < NROFATTACKS; attacknum++) {
2001  attacktype = 1<<attacknum;
2002  if ((arrow->attacktype&attacktype) && (target->arch->clone.resist[attacknum]) < 0)
2003  if (((arrow->magic+arrow->stats.dam)*(100-target->arch->clone.resist[attacknum])/100) > betterby) {
2004  tmp = arrow;
2005  betterby = (arrow->magic+arrow->stats.dam)*(100-target->arch->clone.resist[attacknum])/100;
2006  }
2007  }
2008  if ((2+arrow->magic+arrow->stats.dam) > betterby) {
2009  tmp = arrow;
2010  betterby = 2+arrow->magic+arrow->stats.dam;
2011  }
2012  if (arrow->title && (1+arrow->magic+arrow->stats.dam) > betterby) {
2013  tmp = arrow;
2014  betterby = 1+arrow->magic+arrow->stats.dam;
2015  }
2016  }
2017  }
2018  } FOR_INV_FINISH();
2019  if (tmp == NULL)
2020  return find_arrow(op, type);
2021 
2022  if (better)
2023  *better = betterby;
2024  return tmp;
2025 }
2026 
2039 static object *pick_arrow_target(object *op, const char *type, int dir) {
2040  object *tmp = NULL;
2041  mapstruct *m;
2042  int i, mflags, found, number;
2043  int16_t x, y;
2044 
2045  if (op->map == NULL)
2046  return find_arrow(op, type);
2047 
2048  /* do a dex check */
2049  number = (die_roll(2, 40, op, PREFER_LOW)-2)/2;
2050  if (number > (op->stats.Dex+(op->chosen_skill ? op->chosen_skill->level : op->level)))
2051  return find_arrow(op, type);
2052 
2053  m = op->map;
2054  x = op->x;
2055  y = op->y;
2056 
2057  /* find the first target */
2058  for (i = 0, found = 0; i < 20; i++) {
2059  x += freearr_x[dir];
2060  y += freearr_y[dir];
2061  mflags = get_map_flags(m, &m, x, y, &x, &y);
2062  if (mflags&P_OUT_OF_MAP || mflags&P_BLOCKSVIEW) {
2063  tmp = NULL;
2064  break;
2065  } else if (GET_MAP_MOVE_BLOCK(m, x, y) == MOVE_FLY_LOW) {
2066  /* This block presumes arrows and the like are MOVE_FLY_SLOW -
2067  * perhaps a bad assumption.
2068  */
2069  tmp = NULL;
2070  break;
2071  }
2072  if (mflags&P_IS_ALIVE) {
2073  FOR_MAP_PREPARE(m, x, y, tmp2)
2074  if (QUERY_FLAG(tmp2, FLAG_ALIVE)) {
2075  tmp = tmp2;
2076  found++;
2077  break;
2078  }
2079  FOR_MAP_FINISH();
2080  if (found)
2081  break;
2082  }
2083  }
2084  if (tmp == NULL)
2085  return find_arrow(op, type);
2086 
2087  return find_better_arrow(op, HEAD(tmp), type, NULL);
2088 }
2089 
2108 int fire_bow(object *op, object *arrow, int dir, int wc_mod, int16_t sx, int16_t sy) {
2109  object *bow;
2110  tag_t tag;
2111  int bowspeed, mflags;
2112  mapstruct *m;
2113 
2114  if (!dir) {
2116  "You can't shoot yourself!");
2117  return 0;
2118  }
2119  if (op->type == PLAYER) {
2120  bow = op->contr->ranges[range_bow];
2121  // Make sure the bow's skill is readied.
2122  // Otherwise, you can get wrong modifiers from unarmed attacks
2123  // because that ends up the readied skill.
2124  object *skill = find_skill_by_name(op, bow->skill);
2125  if (skill && change_skill(op, skill, 1) == 0) {
2127  "You cannot use %s without the skill %s", bow->name, bow->skill);
2128  return 0;
2129  }
2130  }
2131  else {
2132  /* Don't check for applied - monsters don't apply bows - in that way, they
2133  * don't need to switch back and forth between bows and weapons.
2134  */
2135  bow = object_find_by_type(op, BOW);
2136  if (!bow) {
2137  LOG(llevError, "Range: bow without activated bow (%s).\n", op->name);
2138  return 0;
2139  }
2140  }
2141  if (!bow->race || !bow->skill) {
2143  "Your %s is broken.",
2144  bow->name);
2145  return 0;
2146  }
2147 
2148  bowspeed = bow->stats.sp+get_dex_bonus(op->stats.Dex);
2149 
2150  /* penalize ROF for bestarrow */
2151  if (op->type == PLAYER && op->contr->bowtype == bow_bestarrow)
2152  bowspeed -= get_dex_bonus(op->stats.Dex)+5;
2153  if (bowspeed < 1)
2154  bowspeed = 1;
2155 
2156  if (arrow == NULL) {
2157  arrow = find_arrow(op, bow->race);
2158  if (arrow == NULL) {
2159  if (op->type == PLAYER)
2162  "You have no %s left.",
2163  bow->race);
2164  /* FLAG_READY_BOW will get reset if the monsters picks up some arrows */
2165  else
2167  return 0;
2168  }
2169  }
2170  mflags = get_map_flags(op->map, &m, sx, sy, &sx, &sy);
2171  if (mflags&P_OUT_OF_MAP) {
2172  return 0;
2173  }
2174  if (GET_MAP_MOVE_BLOCK(m, sx, sy)&MOVE_FLY_LOW) {
2175  return 0;
2176  }
2177 
2178  /* this should not happen, but sometimes does */
2179  if (arrow->nrof == 0) {
2180  object_remove(arrow);
2182  return 0;
2183  }
2184 
2185  arrow = object_split(arrow, 1, NULL, 0);
2186  if (arrow == NULL) {
2188  "You have no %s left.",
2189  bow->race);
2190  return 0;
2191  }
2192  object_set_owner(arrow, op);
2193  if (arrow->skill)
2194  free_string(arrow->skill);
2195  arrow->skill = add_refcount(bow->skill);
2196 
2197  arrow->direction = dir;
2198 
2199  if (op->type == PLAYER) {
2200  op->speed_left = 0.01-(float)FABS(op->speed)*100/bowspeed;
2201  fix_object(op);
2202  }
2203 
2204  if (bow->anim_suffix != NULL)
2205  apply_anim_suffix(op, bow->anim_suffix);
2206 
2207 /* SET_ANIMATION(arrow, arrow->direction);*/
2208  object_update_turn_face(arrow);
2209  arrow->stats.sp = arrow->stats.wc; /* save original wc and dam */
2210  arrow->stats.hp = arrow->stats.dam;
2211  arrow->stats.grace = arrow->attacktype;
2212  if (arrow->slaying != NULL)
2213  arrow->spellarg = strdup_local(arrow->slaying);
2214 
2215  /* Note that this was different for monsters - they got their level
2216  * added to the damage. I think the strength bonus is more proper.
2217  */
2218 
2219  arrow->stats.dam += (QUERY_FLAG(bow, FLAG_NO_STRENGTH) ? 0 : get_dam_bonus(op->stats.Str))
2220  +bow->stats.dam
2221  +bow->magic
2222  +arrow->magic;
2223 
2224  /* update the speed */
2225  arrow->speed = (float)((QUERY_FLAG(bow, FLAG_NO_STRENGTH) ? 0 : get_dam_bonus(op->stats.Str))+bow->magic+arrow->magic)/5.0
2226  +(float)bow->stats.dam/7.0;
2227 
2228  if (arrow->speed < 1.0)
2229  arrow->speed = 1.0;
2230  object_update_speed(arrow);
2231  arrow->speed_left = 0;
2232 
2233  if (op->type == PLAYER) {
2234  /* we don't want overflows of wc (sint), so cap the value - mod and pl should be subtracted */
2235  int mod = bow->magic
2236  +arrow->magic
2237  +get_dex_bonus(op->stats.Dex)
2238  +get_thaco_bonus(op->stats.Str)
2239  +arrow->stats.wc
2240  +bow->stats.wc
2241  -wc_mod;
2242  int plmod = (op->chosen_skill ? op->chosen_skill->level : op->level);
2243  if (plmod+mod > 140)
2244  plmod = 140-mod;
2245  else if (plmod+mod < -100)
2246  plmod = -100-mod;
2247  arrow->stats.wc = 20-(int8_t)plmod-(int8_t)mod;
2248 
2249  arrow->level = op->chosen_skill ? op->chosen_skill->level : op->level;
2250  } else {
2251  arrow->stats.wc = op->stats.wc
2252  -bow->magic
2253  -arrow->magic
2254  -arrow->stats.wc
2255  +wc_mod;
2256 
2257  arrow->level = op->level;
2258  }
2259  if (arrow->attacktype == AT_PHYSICAL)
2260  arrow->attacktype |= bow->attacktype;
2261  if (bow->slaying != NULL)
2262  arrow->slaying = add_string(bow->slaying);
2263 
2264  /* If move_type is ever changed, monster.c:monster_use_bow() needs to be changed too. */
2265  arrow->move_type = MOVE_FLY_LOW;
2266  arrow->move_on = MOVE_FLY_LOW|MOVE_WALK;
2267 
2268  tag = arrow->count;
2269  object_insert_in_map_at(arrow, m, op, 0, sx, sy);
2270 
2271  if (!object_was_destroyed(arrow, tag)) {
2272  play_sound_map(SOUND_TYPE_ITEM, arrow, arrow->direction, "fire");
2273  ob_process(arrow);
2274  }
2275 
2276  return 1;
2277 }
2278 
2289 static int similar_direction(int a, int b) {
2290  /* shortcut the obvious */
2291  if (a == b)
2292  return 1;
2293  /* Made this cleaner using modulus instead of a switch statement
2294  * We only needed the direction and the two adjacent to it
2295  * (8 is adjacent to 1 here) to return true, so a - 1, a, and a + 1
2296  * are the three directions that get "similar" affirmed.
2297  * -- Neila Hawkins 2015-05-28
2298  */
2299  // The last one for the offset is added afterwards so we get
2300  // 1-8 instead of 0-7 (specifically, 0 becomes 8 without changing
2301  // the other values).
2302  if ((a % 8) + 1 == b || (a + 6 % 8) + 1 == b)
2303  return 1;
2304  return 0;
2305 }
2306 
2323 static int player_fire_bow(object *op, int dir) {
2324  int ret = 0, wcmod = 0;
2325 
2326  if (op->contr->bowtype == bow_bestarrow) {
2327  ret = fire_bow(op, pick_arrow_target(op, op->contr->ranges[range_bow]->race, dir), dir, 0, op->x, op->y);
2328  } else if (op->contr->bowtype >= bow_n && op->contr->bowtype <= bow_nw) {
2329  if (!similar_direction(dir, op->contr->bowtype-bow_n+1))
2330  wcmod = -1;
2331  ret = fire_bow(op, NULL, op->contr->bowtype-bow_n+1, wcmod, op->x, op->y);
2332  } else if (op->contr->bowtype == bow_threewide) {
2333  ret = fire_bow(op, NULL, dir, 0, op->x, op->y);
2334  ret |= fire_bow(op, NULL, dir, -5, op->x+freearr_x[absdir(dir+2)], op->y+freearr_y[absdir(dir+2)]);
2335  ret |= fire_bow(op, NULL, dir, -5, op->x+freearr_x[absdir(dir-2)], op->y+freearr_y[absdir(dir-2)]);
2336  } else if (op->contr->bowtype == bow_spreadshot) {
2337  ret |= fire_bow(op, NULL, dir, 0, op->x, op->y);
2338  ret |= fire_bow(op, NULL, absdir(dir-1), -5, op->x, op->y);
2339  ret |= fire_bow(op, NULL, absdir(dir+1), -5, op->x, op->y);
2340  } else {
2341  /* Simple case */
2342  ret = fire_bow(op, NULL, dir, 0, op->x, op->y);
2343  }
2344  return ret;
2345 }
2346 
2359 static void fire_misc_object(object *op, int dir) {
2360  object *item;
2361  char name[MAX_BUF];
2362 
2363  item = op->contr->ranges[range_misc];
2364  if (!item) {
2366  "You have no range item readied.");
2367  return;
2368  }
2369  if (!item->inv) {
2370  LOG(llevError, "Object %s lacks a spell\n", item->name);
2371  return;
2372  }
2373  if (item->type == WAND) {
2374  if (item->stats.food <= 0) {
2375  play_sound_player_only(op->contr, SOUND_TYPE_ITEM, item, 0, "poof");
2376  query_base_name(item, 0, name, MAX_BUF);
2378  "The %s goes poof.",
2379  name);
2380  return;
2381  }
2382  } else if (item->type == ROD) {
2383  if (item->stats.hp < SP_level_spellpoint_cost(item, item->inv, SPELL_HIGHEST)) {
2384  play_sound_player_only(op->contr, SOUND_TYPE_ITEM, item, 0, "poof");
2385  query_base_name(item, 0, name, MAX_BUF);
2387  "The %s whines for a while, but nothing happens.",
2388  name);
2389  return;
2390  }
2391  }
2392 
2393  if (cast_spell(op, item, dir, item->inv, NULL)) {
2394  SET_FLAG(op, FLAG_BEEN_APPLIED); /* You now know something about it */
2395  if (item->type == WAND) {
2396  drain_wand_charge(item);
2397  } else if (item->type == ROD) {
2398  drain_rod_charge(item);
2399  }
2400  }
2401 }
2402 
2411 void fire(object *op, int dir) {
2412 
2413  /* check for loss of invisiblity/hide */
2414  if (action_makes_visible(op))
2415  make_visible(op);
2416 
2417  switch (op->contr->shoottype) {
2418  case range_none:
2419  return;
2420 
2421  case range_bow:
2422  player_fire_bow(op, dir);
2423  return;
2424 
2425  case range_magic: /* Casting spells */
2426  cast_spell(op, op, dir, op->contr->ranges[range_magic], op->contr->spellparam[0] ? op->contr->spellparam : NULL);
2427  return;
2428 
2429  case range_misc:
2430  fire_misc_object(op, dir);
2431  return;
2432 
2433  case range_golem: /* Control summoned monsters from scrolls */
2434  if (op->contr->ranges[range_golem] == NULL
2435  || op->contr->golem_count != op->contr->ranges[range_golem]->count) {
2436  op->contr->ranges[range_golem] = NULL;
2437  op->contr->shoottype = range_none;
2438  op->contr->golem_count = 0;
2439  } else
2441  return;
2442 
2443  case range_skill:
2444  if (!op->chosen_skill) {
2445  if (op->type == PLAYER)
2447  "You have no applicable skill to use.");
2448  return;
2449  }
2450  (void)do_skill(op, op, op->chosen_skill, dir, NULL);
2451  return;
2452 
2453  case range_builder:
2454  apply_map_builder(op, dir);
2455  return;
2456 
2457  default:
2459  "Illegal shoot type.");
2460  return;
2461  }
2462 }
2463 
2483 object *find_key(object *pl, object *container, object *door) {
2484  object *tmp, *key;
2485 
2486  /* Should not happen, but sanity checking is never bad */
2487  if (container->inv == NULL)
2488  return NULL;
2489 
2490  /* First, lets try to find a key in the top level inventory */
2491  tmp = NULL;
2492  if (door->type == DOOR) {
2493  int flag = FLAG_UNPAID;
2494  tmp = object_find_by_type_without_flags(container, KEY, &flag, 1);
2495  }
2496  /* For sanity, we should really check door type, but other stuff
2497  * (like containers) can be locked with special keys
2498  */
2499  if (!tmp && door->slaying != NULL) {
2500  tmp = object_find_by_type_and_slaying(container, SPECIAL_KEY, door->slaying);
2501  }
2502  /* No key found - lets search inventories now */
2503  /* If we find and use a key in an inventory, return at that time.
2504  * otherwise, if we search all the inventories and still don't find
2505  * a key, return
2506  */
2507  if (!tmp) {
2508  FOR_INV_PREPARE(container, tmp) {
2509  /* No reason to search empty containers */
2510  if (tmp->type == CONTAINER && tmp->inv) {
2511  key = find_key(pl, tmp, door);
2512  if (key != NULL)
2513  return key;
2514  }
2515  } FOR_INV_FINISH();
2516  return NULL;
2517  }
2518  /* We get down here if we have found a key. Now if its in a container,
2519  * see if we actually want to use it
2520  */
2521  if (pl != container) {
2522  /* Only let players use keys in containers */
2523  if (!pl->contr)
2524  return NULL;
2525  /* cases where this fails:
2526  * If we only search the player inventory, return now since we
2527  * are not in the players inventory.
2528  * If the container is not active, return now since only active
2529  * containers can be used.
2530  * If we only search keyrings and the container does not have
2531  * a race/isn't a keyring.
2532  * No checking for all containers - to fall through past here,
2533  * inv must have been an container and must have been active.
2534  *
2535  * Change the color so that the message doesn't disappear with
2536  * all the others.
2537  */
2538  if (pl->contr->usekeys == key_inventory
2539  || !QUERY_FLAG(container, FLAG_APPLIED)
2540  || (pl->contr->usekeys == keyrings && (!container->race || strcmp(container->race, "keys")))) {
2541  char name_tmp[MAX_BUF], name_cont[MAX_BUF];
2542 
2543  query_name(tmp, name_tmp, MAX_BUF);
2544  query_name(container, name_cont, MAX_BUF);
2547  "The %s in your %s vibrates as you approach the door",
2548  name_tmp, name_cont);
2549  return NULL;
2550  }
2551  }
2552  return tmp;
2553 }
2554 
2565 static int player_attack_door(object *op, object *door) {
2566  /* If its a door, try to find a use a key. If we do destroy the door,
2567  * might as well return immediately as there is nothing more to do -
2568  * otherwise, we fall through to the rest of the code.
2569  */
2570  object *key = find_key(op, op, door);
2571 
2572  assert(door->type == DOOR || door->type == LOCKED_DOOR);
2573 
2574  /* IF we found a key, do some extra work */
2575  if (key) {
2576  char name[HUGE_BUF];
2577 
2578  play_sound_map(SOUND_TYPE_GROUND, door, 0, "open");
2579  if (action_makes_visible(op))
2580  make_visible(op);
2581  if (door->inv && (door->inv->type == RUNE || door->inv->type == TRAP))
2582  spring_trap(door->inv, op);
2583 
2587  "You open the door with the %s",
2588  name);
2589 
2590  if (door->type == DOOR)
2591  remove_door(door);
2592  else
2593  remove_locked_door(door); /* remove door without violence ;-) */
2594 
2595  /* Do this after we print the message */
2596  object_decrease_nrof_by_one(key); /* Use up one of the keys */
2597 
2598  return 1; /* Nothing more to do below */
2599 
2600  }
2601 
2602  if (door->type == LOCKED_DOOR) {
2603  /* Might as well return now - no other way to open this */
2604  if (door->msg && *door->msg) {
2606  door->msg);
2607  }
2608  return 1;
2609  }
2610 
2611  if (door->type == DOOR && op->contr && !op->contr->run_on) {
2612  /* Player so try to pick the door */
2613  object *lock = find_skill_by_name(op, "lockpicking");
2614  if (lock) {
2615  /* Even if the lockpicking failed, don't go on moving, player should explicitely attack or run
2616  * to bash the door. */
2617  do_skill(op, op, lock, op->facing, NULL);
2618  return 1;
2619  }
2620  }
2621 
2622  return 0;
2623 }
2624 
2638 void move_player_attack(object *op, int dir) {
2639  object *mon, *tpl, *mon_owner;
2640  int16_t nx, ny;
2641  int on_battleground;
2642  mapstruct *m;
2643 
2644  if (op->contr->transport)
2645  tpl = op->contr->transport;
2646  else
2647  tpl = op;
2648  assert(tpl->map != NULL); // op must be on a map in order to move it
2649  nx = freearr_x[dir]+tpl->x;
2650  ny = freearr_y[dir]+tpl->y;
2651 
2652  on_battleground = op_on_battleground(tpl, NULL, NULL, NULL);
2653 
2654  // Temporarily store the map we are on before movement.
2655  mapstruct *bef = tpl->map;
2656 
2657  /* If braced, or can't move to the square, and it is not out of the
2658  * map, attack it. Note order of if statement is important - don't
2659  * want to be calling move_ob if braced, because move_ob will move the
2660  * player. This is a pretty nasty hack, because if we could
2661  * move to some space, it then means that if we are braced, we should
2662  * do nothing at all. As it is, if we are braced, we go through
2663  * quite a bit of processing. However, it probably is less than what
2664  * move_ob uses.
2665  */
2666  if ((op->contr->braced || !move_ob(tpl, dir, tpl)) && !out_of_map(tpl->map, nx, ny)) {
2667  if (OUT_OF_REAL_MAP(tpl->map, nx, ny)) {
2668  m = get_map_from_coord(tpl->map, &nx, &ny);
2669  if (!m)
2670  return; /* Don't think this should happen */
2671  } else
2672  m = tpl->map;
2673 
2674  if (GET_MAP_OB(m, nx, ny) == NULL) {
2675  /* LOG(llevError, "player_move_attack: GET_MAP_OB returns NULL, but player can not move there.\n");*/
2676  return;
2677  }
2678 
2679  mon = NULL;
2680  /* Go through all the objects, and find ones of interest. Only stop if
2681  * we find a monster - that is something we know we want to attack.
2682  * if its a door or barrel (can roll) see if there may be monsters
2683  * on the space
2684  */
2685  FOR_MAP_PREPARE(m, nx, ny, tmp) {
2686  if (tmp == op) {
2687  continue;
2688  }
2689  if (QUERY_FLAG(tmp, FLAG_ALIVE)) {
2690  mon = tmp;
2691  /* Gros: Objects like (pass-through) doors are alive, but haven't
2692  * their monster flag set - so this is a good way attack real
2693  * monsters in priority.
2694  */
2695  if (QUERY_FLAG(tmp, FLAG_MONSTER))
2696  break;
2697  }
2698  if (tmp->type == LOCKED_DOOR || QUERY_FLAG(tmp, FLAG_CAN_ROLL))
2699  mon = tmp;
2700  } FOR_MAP_FINISH();
2701 
2702  if (mon == NULL) /* This happens anytime the player tries to move */
2703  return; /* into a wall */
2704 
2705  mon = HEAD(mon);
2706  if ((mon->type == DOOR && mon->stats.hp >= 0) || (mon->type == LOCKED_DOOR))
2707  if (player_attack_door(op, mon))
2708  return;
2709 
2710  /* The following deals with possibly attacking peaceful
2711  * or friendly creatures. Basically, all players are considered
2712  * unaggressive. If the moving player has peaceful set, then the
2713  * object should be pushed instead of attacked. It is assumed that
2714  * if you are braced, you will not attack friends accidently,
2715  * and thus will not push them.
2716  */
2717 
2718  /* If the creature is a pet, push it even if the player is not
2719  * peaceful. Our assumption is the creature is a pet if the
2720  * player owns it and it is either friendly or unaggressive.
2721  */
2722  mon_owner = object_get_owner(mon);
2723  if ((op->type == PLAYER)
2724  && (mon_owner == op || (mon_owner != NULL && mon_owner->type == PLAYER && mon_owner->contr->party != NULL && mon_owner->contr->party == op->contr->party))
2725  && (QUERY_FLAG(mon, FLAG_UNAGGRESSIVE) || QUERY_FLAG(mon, FLAG_FRIENDLY))) {
2726  /* If we're braced, we don't want to switch places with it */
2727  if (op->contr->braced)
2728  return;
2729  play_sound_map(SOUND_TYPE_LIVING, mon, dir, "push");
2730  (void)push_ob(mon, dir, op);
2731  if (op->contr->tmp_invis || op->hide)
2732  make_visible(op);
2733  return;
2734  }
2735 
2736  /* in certain circumstances, you shouldn't attack friendly
2737  * creatures. Note that if you are braced, you can't push
2738  * someone, but put it inside this loop so that you won't
2739  * attack them either.
2740  */
2741  if ((mon->type == PLAYER || mon->enemy != op)
2742  && (mon->type == PLAYER || QUERY_FLAG(mon, FLAG_UNAGGRESSIVE) || QUERY_FLAG(mon, FLAG_FRIENDLY))
2743  && (op->contr->peaceful && !on_battleground)) {
2744  if (!op->contr->braced) {
2745  play_sound_map(SOUND_TYPE_LIVING, mon, dir, "push");
2746  (void)push_ob(mon, dir, op);
2747  } else {
2749  "You withhold your attack");
2750  }
2751  if (op->contr->tmp_invis || op->hide)
2752  make_visible(op);
2753  }
2754 
2755  /* If the object is a boulder or other rollable object, then
2756  * roll it if not braced. You can't roll it if you are braced.
2757  */
2758  else if (QUERY_FLAG(mon, FLAG_CAN_ROLL) && (!op->contr->braced)) {
2759  recursive_roll(mon, dir, op);
2760  if (action_makes_visible(op))
2761  make_visible(op);
2762 
2763  /* Any generic living creature. Including things like doors.
2764  * Way it works is like this: First, it must have some hit points
2765  * and be living. Then, it must be one of the following:
2766  * 1) Not a player, 2) A player, but of a different party. Note
2767  * that party_number -1 is no party, so attacks can still happen.
2768  */
2769  } else if ((mon->stats.hp >= 0)
2770  && QUERY_FLAG(mon, FLAG_ALIVE)
2771  && ((mon->type != PLAYER || op->contr->party == NULL || op->contr->party != mon->contr->party))) {
2772  /* If the player hasn't hit something this tick, and does
2773  * so, give them speed boost based on weapon speed. Doing
2774  * it here is better than process_players2, which basically
2775  * incurred a 1 tick offset.
2776  */
2777  if (op->weapon_speed_left < 0) {
2778  op->speed_left = -0.01;
2779  return;
2780  }
2781  op->weapon_speed_left -= 1.0;
2782 
2783  skill_attack(mon, op, 0, NULL, NULL);
2784 
2785  /* If attacking another player, that player gets automatic
2786  * hitback, and doesn't loose luck either.
2787  * Disable hitback on the battleground or if the target is
2788  * the wiz.
2789  */
2790  if (mon->type == PLAYER
2791  && mon->stats.hp >= 0
2792  && !mon->contr->has_hit
2793  && !on_battleground
2794  && !QUERY_FLAG(mon, FLAG_WIZ)) {
2795  short luck = mon->stats.luck;
2796  mon->contr->has_hit = 1;
2797  skill_attack(op, mon, 0, NULL, NULL);
2798  mon->stats.luck = luck;
2799  }
2800  if (action_makes_visible(op))
2801  make_visible(op);
2802  }
2803  } /* if player should attack something */
2804  else if (bef != tpl->map) {
2805  player_map_change_common(op, bef, tpl->map);
2806  }
2807 }
2808 
2815 static void update_transport_block(object *transport, int dir) {
2816  object *part;
2817  int sx, sy, x, y;
2818 
2819  object_get_multi_size(transport, &sx, &sy, NULL, NULL);
2820  assert(sx == sy);
2821 
2822  if (dir == 1 || dir == 5) {
2823  part = transport;
2824  for (y = 0; y <= sy; y++) {
2825  for (x = 0; x < sx; x++) {
2826  part->move_type = transport->move_type;
2827  part = part->more;
2828  }
2829  part->move_type = 0;
2830  part = part->more;
2831  }
2832  } else if (dir == 3 || dir == 7) {
2833  part = transport;
2834  for (y = 0; y < sy; y++) {
2835  for (x = 0; x <= sx; x++) {
2836  part->move_type = transport->move_type;
2837  part = part->more;
2838  }
2839  }
2840  while (part) {
2841  part->move_type = 0;
2842  part = part->more;
2843  }
2844  } else {
2845  for (part = transport; part; part = part->more) {
2846  part->move_type = transport->move_type;
2847  }
2848  }
2849 }
2850 
2860 static int turn_one_transport(object *transport, object *captain, int dir) {
2861  int x, y, scroll_dir = 0;
2862 
2863  assert(transport->type == TRANSPORT);
2864 
2865  x = transport->x;
2866  y = transport->y;
2867 
2868  if (transport->direction == 1 && dir == 8) {
2869  x--;
2870  } else if (transport->direction == 2 && dir == 3) {
2871  y++;
2872  } else if (transport->direction == 3 && dir == 2) {
2873  y--;
2874  } else if (transport->direction == 5 && dir == 6) {
2875  x--;
2876  } else if (transport->direction == 6 && dir == 5) {
2877  x++;
2878  } else if (transport->direction == 7 && dir == 8) {
2879  y--;
2880  } else if (transport->direction == 8 && dir == 7) {
2881  y++;
2882  } else if (transport->direction == 8 && dir == 1) {
2883  x++;
2884  }
2885 
2886  update_transport_block(transport, dir);
2887  object_remove(transport);
2888  if (ob_blocked(transport, transport->map, x, y)) {
2889  update_transport_block(transport, transport->direction);
2890  object_insert_in_map_at(transport, transport->map, NULL, 0, x, y);
2891  return 2;
2892  }
2893 
2894  if (x != transport->x || y != transport->y) {
2895 /* assert(scroll_dir != 0);*/
2896 
2897  FOR_INV_PREPARE(transport, pl) {
2898  if (pl->type == PLAYER) {
2899  pl->contr->do_los = 1;
2900  pl->map = transport->map;
2901  pl->x = x;
2902  pl->y = y;
2903  esrv_map_scroll(pl->contr->socket, freearr_x[scroll_dir], freearr_y[scroll_dir]);
2904  pl->contr->socket->update_look = 1;
2905  pl->contr->socket->look_position = 0;
2906  }
2907  } FOR_INV_FINISH();
2908  }
2909 
2910  object_insert_in_map_at(transport, transport->map, NULL, 0, x, y);
2911  transport->direction = dir;
2912  transport->facing = dir;
2913  animate_object(transport, dir);
2914  captain->direction = dir;
2915  return 1;
2916 }
2917 
2930 static int turn_transport(object *transport, object *captain, int dir) {
2931  assert(transport->type == TRANSPORT);
2932 
2933  if (object_value_set(transport, "turnable_transport") == false) {
2934  transport->direction = dir;
2935  transport->facing = dir;
2936  if (QUERY_FLAG(transport, FLAG_ANIMATE)) {
2937  animate_object(transport, dir);
2938  }
2939  captain->direction = dir;
2940  return 0;
2941  }
2942 
2943  if (transport->direction == dir)
2944  return 0;
2945 
2946  if (absdir(transport->direction-dir) > 2)
2947  return turn_one_transport(transport, captain, absdir(transport->direction+1));
2948  else
2949  return turn_one_transport(transport, captain, absdir(transport->direction-1));
2950 }
2951 
2963 int move_player(object *op, int dir) {
2964  object *transport = op->contr->transport; //< Transport player is in
2965 
2966  if (!transport && (op->map == NULL || op->map->in_memory != MAP_IN_MEMORY))
2967  return 0;
2968 
2969  /* Sanity check: make sure dir is valid */
2970  if ((dir < 0) || (dir >= 9)) {
2971  LOG(llevError, "move_player: invalid direction %d\n", dir);
2972  return 0;
2973  }
2974 
2975  if (QUERY_FLAG(op, FLAG_CONFUSED) && dir)
2976  dir = get_randomized_dir(dir);
2977 
2978  op->facing = dir;
2979 
2980  if (transport) {
2981  /* transport->contr is set up for the person in charge of the boat.
2982  * if that isn't this person, he can't steer it, etc
2983  */
2984  if (transport->contr != op->contr)
2985  return 0;
2986 
2987  /* Transport is out of movement. But update dir so it at least
2988  * will point in the same direction if player is running.
2989  */
2990  if (transport->speed_left < 0.0) {
2991  return 0;
2992  }
2993  /* Remove transport speed. Give player just a little speed -
2994  * enough so that they will get an action again quickly.
2995  */
2996  transport->speed_left -= 1.0;
2997  if (op->speed_left < 0.0)
2998  op->speed_left = -0.01;
2999 
3000  int turn = turn_transport(transport, op, dir);
3001  if (turn != 0)
3002  return 0;
3003  } else {
3004  if (op->hide) {
3005  do_hidden_move(op);
3006  }
3007 
3008  /* it is important to change the animation now, as fire or move_player_attack can start a compound animation,
3009  * and leave us with state = 0, which we don't want to change again. */
3010  op->state++; /* player moved, so change animation. */
3011  animate_object(op, op->facing);
3012  }
3013 
3014  if (op->contr->fire_on) {
3015  fire(op, dir);
3016  } else
3017  move_player_attack(op, dir);
3018 
3019  int pick = check_pick(op);
3020 
3021  /* Add special check for newcs players and fire on - this way, the
3022  * server can handle repeat firing.
3023  */
3024  if (op->contr->fire_on || (op->contr->run_on && pick != 0)) {
3025  op->direction = dir;
3026  } else {
3027  op->direction = 0;
3028  }
3029  return 0;
3030 }
3031 
3042 int face_player(object *op, int dir) {
3043  object *transport = op->contr->transport; //< Transport player is in
3044 
3045  if (!transport && (op->map == NULL || op->map->in_memory != MAP_IN_MEMORY))
3046  return 0;
3047 
3048  /* Sanity check: make sure dir is valid */
3049  if ((dir < 0) || (dir >= 9)) {
3050  LOG(llevError, "move_player: invalid direction %d\n", dir);
3051  return 0;
3052  }
3053 
3054  if (QUERY_FLAG(op, FLAG_CONFUSED) && dir)
3055  dir = get_randomized_dir(dir);
3056 
3057  op->facing = dir;
3058 
3059  if (transport) {
3060  /* transport->contr is set up for the person in charge of the boat.
3061  * if that isn't this person, he can't steer it, etc
3062  */
3063  if (transport->contr != op->contr)
3064  return 0;
3065 
3066  turn_transport(transport, op, dir);
3067  } else {
3068  if (op->hide) {
3069  do_hidden_move(op);
3070  }
3071 
3072  /* it is important to change the animation now, as fire or move_player_attack can start a compound animation,
3073  * and leave us with state = 0, which we don't want to change again. */
3074  op->state++; /* player moved, so change animation. */
3075  animate_object(op, op->facing);
3076  }
3077 
3078  /* Add special check for newcs players and fire on - this way, the
3079  * server can handle repeat firing.
3080  */
3081  if (op->contr->fire_on || op->contr->run_on) {
3082  op->direction = dir;
3083  } else {
3084  op->direction = 0;
3085  }
3086  return 0;
3087 }
3088 
3101 int handle_newcs_player(object *op) {
3102  if (op->contr->hidden) {
3103  op->invisible = 1000;
3104  /* the socket code flashes the player visible/invisible
3105  * depending on the value if invisible, so we need to
3106  * alternate it here for it to work correctly.
3107  */
3108  if (pticks&2)
3109  op->invisible--;
3110  } else if (op->invisible && !(QUERY_FLAG(op, FLAG_MAKE_INVIS))) {
3111  op->invisible--;
3112  if (!op->invisible) {
3113  make_visible(op);
3115  "Your invisibility spell runs out.");
3116  }
3117  }
3118 
3119  if (QUERY_FLAG(op, FLAG_SCARED)) {
3120  flee_player(op);
3121  /* If player is still scared, that is his action for this tick */
3122  if (QUERY_FLAG(op, FLAG_SCARED)) {
3123  op->speed_left--;
3124  return 0;
3125  }
3126  }
3127 
3128  /* I've been seeing crashes where the golem has been destroyed, but
3129  * the player object still points to the defunct golem. The code that
3130  * destroys the golem looks correct, and it doesn't always happen, so
3131  * put this in a a workaround to clean up the golem pointer.
3132  */
3133  if (op->contr->ranges[range_golem]
3135  op->contr->ranges[range_golem] = NULL;
3136  op->contr->golem_count = 0;
3137  }
3138 
3139  /*
3140  * If the player has been paralyzed, we unmark the flag and give a message to the player
3141  */
3142  if (QUERY_FLAG(op, FLAG_PARALYZED)) {
3144  // TODO: Is this check necessary? We are in player.c, after all.
3145  if (op->type == PLAYER)
3146  {
3148  "You can stretch your stiff joints once more.");
3149  }
3150  }
3151 
3152  if (op->direction && (op->contr->run_on || op->contr->fire_on)) {
3153  /* All move commands take 1 tick, at least for now */
3154  op->speed_left--;
3155 
3156  /* Instead of all the stuff below, let move_player take care
3157  * of it. Also, some of the skill stuff is only put in
3158  * there, as well as the confusion stuff.
3159  */
3160  move_player(op, op->direction);
3161  if (op->speed_left > 0)
3162  return 1;
3163  else
3164  return 0;
3165  }
3166 
3167  if (op->contr->repeat_func != NULL) {
3168  bool ret = op->contr->repeat_func(op->contr, op->contr->repeat_func_data);
3169  if (ret == false) {
3171  }
3172  }
3173 
3174  return 0;
3175 }
3176 
3187 static int save_life(object *op) {
3188  object *tmp;
3189 
3190  if (!QUERY_FLAG(op, FLAG_LIFESAVE))
3191  return 0;
3192 
3194  if (tmp != NULL) {
3195  char name[MAX_BUF];
3196 
3197  query_name(tmp, name, MAX_BUF);
3198  play_sound_map(SOUND_TYPE_ITEM, tmp, 0, "evaporate");
3200  "Your %s vibrates violently, then evaporates.",
3201  name);
3202  object_remove(tmp);
3205  if (op->stats.hp < 0)
3206  op->stats.hp = op->stats.maxhp;
3207  if (op->stats.food < 0)
3208  op->stats.food = MAX_FOOD;
3209  fix_object(op);
3210  return 1;
3211  }
3212  LOG(llevError, "Error: LIFESAVE set without applied object.\n");
3214  enter_player_savebed(op); /* bring him home. */
3215  return 0;
3216 }
3217 
3230 void remove_unpaid_objects(object *op, object *env, int free_items) {
3232  if (QUERY_FLAG(op, FLAG_UNPAID)) {
3233  object_remove(op);
3234  if (free_items)
3236  else
3237  object_insert_in_map_at(op, env->map, NULL, 0, env->x, env->y);
3238  } else if (op->inv)
3239  remove_unpaid_objects(op->inv, env, free_items);
3241 }
3242 
3260 static const char *gravestone_text(object *op, char *buf2, int len) {
3261  char buf[MAX_BUF];
3262  time_t now = time(NULL);
3263 
3264  strncpy(buf2, " R.I.P.\n\n", len);
3265  if (op->type == PLAYER)
3266  snprintf(buf, sizeof(buf), "%s the %s\n", op->name, op->contr->title);
3267  else
3268  snprintf(buf, sizeof(buf), "%s\n", op->name);
3269  strncat(buf2, " ", 20-strlen(buf)/2);
3270  strncat(buf2, buf, len-strlen(buf2)-1);
3271  if (op->type == PLAYER)
3272  snprintf(buf, sizeof(buf), "who was in level %d when killed\n", op->level);
3273  else
3274  snprintf(buf, sizeof(buf), "who was in level %d when died.\n\n", op->level);
3275  strncat(buf2, " ", 20-strlen(buf)/2);
3276  strncat(buf2, buf, len-strlen(buf2)-1);
3277  if (op->type == PLAYER) {
3278  snprintf(buf, sizeof(buf), "by %s.\n\n", op->contr->killer);
3279  strncat(buf2, " ", 21-strlen(buf)/2);
3280  strncat(buf2, buf, len-strlen(buf2)-1);
3281  }
3282  strftime(buf, MAX_BUF, "%b %d %Y\n", localtime(&now));
3283  strncat(buf2, " ", 20-strlen(buf)/2);
3284  strncat(buf2, buf, len-strlen(buf2)-1);
3285  return buf2;
3286 }
3287 
3288 static bool starving(object *op) {
3289  return op->stats.food <= 0;
3290 }
3291 
3299 void do_some_living(object *op) {
3300  int last_food = op->stats.food;
3301  int gen_hp, gen_sp, gen_grace;
3302  int rate_hp = 1200;
3303  int rate_sp = 2500;
3304  int rate_grace = 2000;
3305 
3306  if (op->contr->state == ST_PLAYING) {
3307  /* these next three if clauses make it possible to SLOW DOWN
3308  hp/grace/spellpoint regeneration. */
3309  if (op->contr->gen_hp >= 0)
3310  gen_hp = (op->contr->gen_hp+1)*op->stats.maxhp;
3311  else {
3312  gen_hp = op->stats.maxhp;
3313  rate_hp -= rate_hp/2*op->contr->gen_hp;
3314  }
3315  if (op->contr->gen_sp >= 0)
3316  gen_sp = (op->contr->gen_sp+1)*op->stats.maxsp;
3317  else {
3318  gen_sp = op->stats.maxsp;
3319  rate_sp -= rate_sp/2*op->contr->gen_sp;
3320  }
3321  if (op->contr->gen_grace >= 0)
3322  gen_grace = (op->contr->gen_grace+1)*op->stats.maxgrace;
3323  else {
3324  gen_grace = op->stats.maxgrace;
3325  rate_grace -= rate_grace/2*op->contr->gen_grace;
3326  }
3327 
3328  /* Regenerate Spell Points */
3329  if (op->contr->ranges[range_golem] == NULL && --op->last_sp < 0) {
3330  gen_sp = gen_sp*10/MAX(op->contr->gen_sp_armour, 10);
3331  if (op->stats.sp < op->stats.maxsp) {
3332  op->stats.sp++;
3333  /* dms do not consume food */
3334  if (!QUERY_FLAG(op, FLAG_WIZ)) {
3335  op->stats.food--;
3336  if (op->contr->digestion < 0)
3337  op->stats.food += op->contr->digestion;
3338  else if (op->contr->digestion > 0
3339  && random_roll(0, op->contr->digestion, op, PREFER_HIGH))
3340  op->stats.food = last_food;
3341  }
3342  }
3343  op->last_sp = rate_sp/(MAX(gen_sp, 20)+10);
3344  }
3345 
3346  /* Regenerate Grace */
3347  /* I altered this a little - maximum grace is only achieved through prayer -b.t.*/
3348  if (--op->last_grace < 0) {
3349  if (op->stats.grace < op->stats.maxgrace/2)
3350  op->stats.grace++; /* no penalty in food for regaining grace */
3351  op->last_grace = rate_grace/(MAX(gen_grace, 20)+10);
3352  /* wearing stuff doesn't detract from grace generation. */
3353  }
3354 
3355  /* Regenerate Hit Points (unless you are a wraith player) */
3356  if (--op->last_heal < 0 && !is_wraith_pl(op) && !starving(op)) {
3357  if (op->stats.hp < op->stats.maxhp) {
3358  op->stats.hp++;
3359  /* dms do not consume food */
3360  if (!QUERY_FLAG(op, FLAG_WIZ)) {
3361  op->stats.food--;
3362  if (op->contr->digestion < 0)
3363  op->stats.food += op->contr->digestion;
3364  else if (op->contr->digestion > 0
3365  && random_roll(0, op->contr->digestion, op, PREFER_HIGH))
3366  op->stats.food = last_food;
3367  }
3368  }
3369  op->last_heal = rate_hp/(MAX(gen_hp, 20)+10);
3370  }
3371 
3372  /* Digestion */
3373  if (--op->last_eat < 0) {
3374  int bonus = MAX(op->contr->digestion, 0);
3375  int penalty = MAX(-op->contr->digestion, 0);
3376  if (op->contr->gen_hp > 0)
3377  op->last_eat = 25*(1+bonus)/(op->contr->gen_hp+penalty+1);
3378  else
3379  op->last_eat = 25*(1+bonus)/(penalty+1);
3380  /* dms do not consume food */
3381  if (!QUERY_FLAG(op, FLAG_WIZ))
3382  op->stats.food--;
3383  }
3384  }
3385 
3386  // Grab a bite of food if able, starving, and still alive.
3387  if (op->contr->state == ST_PLAYING && starving(op) && op->stats.hp >= 0) {
3388  if (is_wraith_pl(op))
3389  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ITEM, MSG_TYPE_ITEM_REMOVE, "You feel a hunger for living flesh.");
3390  /* Only allow eat if not paralyzed. Otherwise our paralyzed player is "moving" to eat.
3391  * Neila Hawkins 2017-08-23
3392  */
3393  else if (!QUERY_FLAG(op, FLAG_PARALYZED)){
3394  object *flesh = NULL;
3395 
3396  FOR_INV_PREPARE(op, tmp) {
3397  if (!QUERY_FLAG(tmp, FLAG_UNPAID)) {
3398  if (tmp->type == FOOD || tmp->type == DRINK || tmp->type == POISON) {
3400  "You blindly grab for a bite of food.");
3401  apply_manual(op, tmp, 0);
3402  if (op->stats.food >= 0 || op->stats.hp < 0)
3403  break;
3404  } else if (tmp->type == FLESH)
3405  flesh = tmp;
3406  } /* End if paid for object */
3407  } FOR_INV_FINISH(); /* end of for loop */
3408  /* If player is still starving, it means they don't have any food, so
3409  * eat flesh instead.
3410  */
3411  if (op->stats.food < 0 && op->stats.hp >= 0 && flesh) {
3413  "You blindly grab for a bite of food.");
3414  apply_manual(op, flesh, 0);
3415  }
3416  } /* end not wraith and not paralyzed */
3417  else { // Print a message for when the player is starving and paralyzed
3418  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ITEM, MSG_TYPE_ITEM_REMOVE, "Your stomach rumbles, but you can't reach your food.");
3419  } /* end not wraith and is paralyzed */
3420  } /* end if player is starving */
3421 
3422  // Prevent food from going negative, then deal constant hunger damage.
3423  if (starving(op)) {
3424  op->stats.food = 0;
3425  op->stats.hp -= 1;
3426  }
3427 
3428  if (!op->contr->state && !QUERY_FLAG(op, FLAG_WIZ) && (op->stats.hp <= 0))
3429  kill_player(op, NULL);
3430 }
3431 
3438 static void loot_object(object *op) {
3439  object *tmp2;
3440 
3441  if (op->container) { /* close open sack first */
3442  apply_container(op, op->container, AP_NULL);
3443  }
3444 
3445  FOR_INV_PREPARE(op, tmp) {
3446  if (tmp->invisible)
3447  continue;
3448  object_remove(tmp);
3449  tmp->x = op->x,
3450  tmp->y = op->y;
3451  if (tmp->type == CONTAINER) { /* empty container to ground */
3452  loot_object(tmp);
3453  }
3454  if (!QUERY_FLAG(tmp, FLAG_UNIQUE)
3455  && (QUERY_FLAG(tmp, FLAG_STARTEQUIP) || QUERY_FLAG(tmp, FLAG_NO_DROP) || !(RANDOM()%3))) {
3456  if (tmp->nrof > 1) {
3457  tmp2 = object_split(tmp, 1+RANDOM()%(tmp->nrof-1), NULL, 0);
3459  object_insert_in_map_at(tmp, op->map, NULL, 0, op->x, op->y);
3460  } else
3462  } else
3463  object_insert_in_map_at(tmp, op->map, NULL, 0, op->x, op->y);
3464  } FOR_INV_FINISH();
3465 }
3466 
3477 static void restore_player(object *op) {
3478  object *tmp;
3479  archetype *at = find_archetype("poisoning");
3480  if (at != NULL) {
3481  tmp = arch_present_in_ob(at, op);
3482  if (tmp) {
3483  object_remove(tmp);
3486  "Your body feels cleansed");
3487  }
3488  }
3489 
3490  at = find_archetype("confusion");
3491  if (at != NULL) {
3492  tmp = arch_present_in_ob(at, op);
3493  if (tmp) {
3494  object_remove(tmp);
3497  "Your mind feels clearer");
3498  }
3499  }
3500 
3501  cure_disease(op, NULL, NULL); /* remove any disease */
3502 }
3503 
3515 void kill_player(object *op, const object *killer) {
3516  char buf[MAX_BUF];
3517  int x, y;
3518  object *tmp;
3519  archetype *trophy = NULL;
3520 
3521  /* Don't die if the player's life can be saved. */
3522  if (save_life(op)) {
3523  return;
3524  }
3525 
3526  /* If player dies on BATTLEGROUND, no stat/exp loss! For Combat-Arenas
3527  * in cities ONLY!!! It is very important that this doesn't get abused.
3528  * Look at op_on_battleground() for more info --AndreasV
3529  */
3530  if (op_on_battleground(op, &x, &y, &trophy)) {
3531  assert(trophy != NULL);
3533  "You have been defeated in combat!\n"
3534  "Local medics have saved your life...");
3535 
3536  /* restore player */
3537  restore_player(op);
3538 
3539  op->stats.hp = op->stats.maxhp;
3540  if (op->stats.food <= 0)
3541  op->stats.food = MAX_FOOD;
3542 
3543  /* create a bodypart-trophy to make the winner happy */
3544  tmp = arch_to_object(trophy);
3545  if (tmp != NULL) {
3546  snprintf(buf, sizeof(buf), "%s's %s", op->name, tmp->name);
3547  tmp->name = add_string(buf);
3548 
3549  snprintf(buf, sizeof(buf),
3550  "This %s was %s %s the %s, who was defeated at level %d by %s.\n",
3551  tmp->name, tmp->type == FLESH ? "cut off" : "taken from",
3552  op->name, op->contr->title,
3553  (int)(op->level), op->contr->killer);
3554 
3555  object_set_msg(tmp, buf);
3556  tmp->type = 0;
3557  tmp->value = 0;
3558  tmp->material = 0;
3559  tmp->materialname = NULL;
3560  object_insert_in_map_at(tmp, op->map, op, 0, op->x, op->y);
3561  }
3562 
3563  /* teleport defeated player to new destination*/
3564  transfer_ob(op, x, y, 0, NULL);
3565  op->contr->braced = 0;
3566  return;
3567  }
3568 
3569  if (events_execute_object_event(op, EVENT_DEATH, NULL, NULL, NULL, SCRIPT_FIX_ALL) != 0)
3570  return;
3571 
3573  if (starving(op)) {
3574  snprintf(buf, sizeof(buf), "%s starved to death.", op->name);
3575  strcpy(op->contr->killer, "starvation");
3576  } else {
3577  snprintf(buf, sizeof(buf), "%s died.", op->name);
3578  }
3579  play_sound_player_only(op->contr, SOUND_TYPE_LIVING, op, 0, "death");
3580 
3581  if (settings.not_permadeth == TRUE) {
3583  } else {
3585  }
3586 }
3587 
3596 static void kill_player_not_permadeath(object *op) {
3597  int num_stats_lose;
3598  int will_kill_again;
3599  int lost_a_stat;
3600  int z;
3601  object *tmp;
3602  char buf[MAX_BUF];
3603  archetype *at;
3604 
3605  /* Basically two ways to go - remove a stat permanently, or just
3606  * make it depletion. This bunch of code deals with that aspect
3607  * of death.
3608  */
3610  /* If stat loss is permanent, lose one stat only. */
3611  /* Lower level chars don't lose as many stats because they suffer
3612  more if they do. */
3613  /* Higher level characters can afford things such as potions of
3614  restoration, or better, stat potions. So we slug them that
3615  little bit harder. */
3616  /* GD */
3618  num_stats_lose = 1;
3619  else
3620  num_stats_lose = 1+op->level/BALSL_NUMBER_LOSSES_RATIO;
3621  } else {
3622  num_stats_lose = 1;
3623  }
3624  lost_a_stat = 0;
3625 
3626  for (z = 0; z < num_stats_lose; z++) {
3628  int i;
3629 
3630  /* Pick a random stat and take a point off it. Tell the player
3631  * what he lost.
3632  */
3633  i = RANDOM()%7;
3634  change_attr_value(&(op->stats), i, -1);
3636  change_attr_value(&(op->contr->orig_stats), i, -1);
3638  draw_ext_info(NDI_UNIQUE, 0, op,
3640  lose_msg[i]);
3641  lost_a_stat = 1;
3642  } else {
3643  /* deplete a stat */
3645  if (deparch == NULL) {
3646  continue;
3647  }
3648  object *dep;
3649  int lose_this_stat;
3650  int i;
3651 
3652  i = RANDOM()%7;
3653  dep = arch_present_in_ob(deparch, op);
3654  if (!dep) {
3655  dep = arch_to_object(deparch);
3656  object_insert_in_ob(dep, op);
3657  }
3658  lose_this_stat = 1;
3660  int this_stat;
3661 
3662  /* GD */
3663  /* Get the stat that we're about to deplete. */
3664  this_stat = get_attr_value(&(dep->stats), i);
3665  if (this_stat < 0) {
3666  int loss_chance = 1+op->level/BALSL_LOSS_CHANCE_RATIO;
3667  int keep_chance = this_stat*this_stat;
3668  /* Yes, I am paranoid. Sue me. */
3669  if (keep_chance < 1)
3670  keep_chance = 1;
3671 
3672  /* There is a maximum depletion total per level. */
3673  if (this_stat < -1-op->level/BALSL_MAX_LOSS_RATIO) {
3674  lose_this_stat = 0;
3675  /* Take loss chance vs keep chance to see if we
3676  retain the stat. */
3677  } else {
3678  if (random_roll(0, loss_chance+keep_chance-1, op, PREFER_LOW) < keep_chance)
3679  lose_this_stat = 0;
3680  /* 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"); */
3681  }
3682  }
3683  }
3684 
3685  if (lose_this_stat) {
3686  int this_stat;
3687 
3688  this_stat = get_attr_value(&(dep->stats), i);
3689  /* We could try to do something clever like find another
3690  * stat to reduce if this fails. But chances are, if
3691  * stats have been depleted to -50, all are pretty low
3692  * and should be roughly the same, so it shouldn't make a
3693  * difference.
3694  */
3695  if (this_stat >= -50) {
3696  change_attr_value(&(dep->stats), i, -1);
3697  SET_FLAG(dep, FLAG_APPLIED);
3699  drain_msg[i]);
3700  fix_object(op);
3701  lost_a_stat = 1;
3702  }
3703  }
3704  }
3705  }
3706  /* If no stat lost, tell the player. */
3707  if (!lost_a_stat) {
3708  /* determine_god() seems to not work sometimes... why is this? Should I be using something else? GD */
3709  const char *god = determine_god(op);
3710 
3711  if (god && (strcmp(god, "none")))
3714  "For a brief moment you feel the holy presence of %s protecting you",
3715  god);
3716  else
3717  draw_ext_info(NDI_UNIQUE, 0, op,
3719  "For a brief moment you feel a holy presence protecting you.");
3720  }
3721 
3722  /* Put a gravestone up where the character 'almost' died. List the
3723  * exp loss on the stone.
3724  */
3725  at = find_archetype("gravestone");
3726  if (at != NULL) {
3727  tmp = arch_to_object(at);
3728  snprintf(buf, sizeof(buf), "%s's gravestone", op->name);
3729  FREE_AND_COPY(tmp->name, buf);
3730  snprintf(buf, sizeof(buf), "%s's gravestones", op->name);
3731  FREE_AND_COPY(tmp->name_pl, buf);
3732  snprintf(buf, sizeof(buf), "RIP\nHere rests the hero %s the %s,\n"
3733  "who was killed\n"
3734  "by %s.\n",
3735  op->name, op->contr->title,
3736  op->contr->killer);
3737  object_set_msg(tmp, buf);
3738  object_insert_in_map_at(tmp, op->map, NULL, 0, op->x, op->y);
3739  }
3740 
3741  /* restore player: remove any poisoning, disease and confusion the
3742  * character may be suffering.*/
3743  restore_player(op);
3744 
3745  /* Subtract the experience points, if we died cause of food, give
3746  * us food, and reset HP's...
3747  */
3749  if (op->stats.food < 100)
3750  op->stats.food = 900;
3751  op->stats.hp = op->stats.maxhp;
3752  op->stats.sp = MAX(op->stats.sp, op->stats.maxsp);
3753  op->stats.grace = MAX(op->stats.grace, op->stats.maxgrace);
3754 
3755  /* Check to see if the player is in a shop. IF so, then check to see if
3756  * the player has any unpaid items. If so, remove them and put them back
3757  * in the map.
3758  *
3759  * If they are not in a shop, just free the unpaid items instead of
3760  * putting them back on map.
3761  */
3762  if (shop_contains(op))
3763  remove_unpaid_objects(op->inv, op, 0);
3764  else
3765  remove_unpaid_objects(op->inv, op, 1);
3766 
3767  /* Move player to his current respawn-position (usually last savebed) */
3769 
3770  /* Save the player before inserting the force to reduce chance of abuse. */
3771  op->contr->braced = 0;
3772  /* don't pick up in apartment */
3773  if (op->contr->mode & PU_NEWMODE) {
3774  op->contr->mode = op->contr->mode | PU_INHIBIT;
3775  esrv_send_pickup(op->contr);
3776  } else {
3777  op->contr->mode = 0;
3778  }
3779  if ( op->contr->search_str[0] ) command_search_items(op,NULL); /* turn off search-items */
3780  save_player(op, 1);
3781 
3782  /* it is possible that the player has blown something up
3783  * at his savebed location, and that can have long lasting
3784  * spell effects. So first see if there is a spell effect
3785  * on the space that might harm the player.
3786  */
3787  will_kill_again = 0;
3788  FOR_MAP_PREPARE(op->map, op->x, op->y, tmp)
3789  if (tmp->type == SPELL_EFFECT)
3790  will_kill_again |= tmp->attacktype;
3791  FOR_MAP_FINISH();
3792  if (will_kill_again) {
3793  object *force;
3794  int at;
3795 
3796  force = create_archetype(FORCE_NAME);
3797  /* 50 ticks should be enough time for the spell to abate */
3798  force->speed = 0.1;
3799  force->speed_left = -5.0;
3800  SET_FLAG(force, FLAG_APPLIED);
3801  for (at = 0; at < NROFATTACKS; at++) {
3802  if (will_kill_again&(1<<at))
3803  force->resist[at] = 100;
3804  }
3805  object_insert_in_ob(force, op);
3806  fix_object(op);
3807  }
3808 
3809  /* Tell the player they have died */
3811  "YOU HAVE DIED.");
3812 }
3813 
3820 static void kill_player_permadeath(object *op) {
3821  char buf[MAX_BUF];
3822  char ac_buf[MAX_BUF];
3823  int x, y;
3824  mapstruct *map;
3825  object *tmp;
3826  archetype *at;
3827 
3828  /* save the map location for corpse, gravestone*/
3829  x = op->x;
3830  y = op->y;
3831  map = op->map;
3832 
3833  party_leave(op);
3834  if (settings.set_title == TRUE)
3835  player_set_own_title(op->contr, "");
3836 
3837  /* buf should be the kill message */
3839  buf);
3840  hiscore_check(op, 0);
3841  if (op->contr->ranges[range_golem] != NULL) {
3845  op->contr->ranges[range_golem] = NULL;
3846  op->contr->golem_count = 0;
3847  }
3848  loot_object(op); /* Remove some of the items for good */
3849  object_remove(op);
3850  op->direction = 0;
3851 
3852  if (!QUERY_FLAG(op, FLAG_WAS_WIZ) && op->stats.exp) {
3853  if (settings.resurrection == TRUE) {
3854  /* save playerfile sans equipment when player dies
3855  * -then save it as player.pl.dead so that future resurrection
3856  * -type spells will work on them nicely
3857  */
3858  op->stats.hp = op->stats.maxhp;
3859  op->stats.food = MAX_FOOD;
3860 
3861  /* set the location of where the person will reappear when */
3862  /* maybe resurrection code should fix map also */
3864  sizeof(op->contr->maplevel));
3865  if (op->map != NULL)
3866  op->map = NULL;
3867  op->x = settings.emergency_x;
3868  op->y = settings.emergency_y;
3869  save_player(op, 0);
3870  op->map = map;
3871  /* please see resurrection.c: peterm */
3872  dead_player(op);
3873  } else {
3874  delete_character(op->name);
3875 
3876  /* Remove player from account list and send back data if needed */
3877  if (op->contr->socket->account_chars != NULL) {
3880  /* char information is reloaded in send_account_players below */
3882  op->contr->socket->account_chars = NULL;
3885  }
3886  }
3887  }
3888  play_again(op);
3889 
3890  /* peterm: added to create a corpse at deathsite. */
3891  at = find_archetype("corpse_pl");
3892  if (at != NULL) {
3893  tmp = arch_to_object(at);
3894  snprintf(buf, sizeof(buf), "%s", op->name);
3895  FREE_AND_COPY(tmp->name, buf);
3896  FREE_AND_COPY(tmp->name_pl, buf);
3897  tmp->level = op->level;
3898  object_set_msg(tmp, gravestone_text(op, buf, sizeof(buf)));
3899  SET_FLAG(tmp, FLAG_UNIQUE);
3900  /*
3901  * Put the account name under slaying.
3902  * Does not seem to cause weird effects, but more testing may ensure this.
3903  */
3904  snprintf(ac_buf, sizeof(ac_buf), "%s", op->contr->socket->account_name);
3905  FREE_AND_COPY(tmp->slaying, ac_buf);
3906  object_insert_in_map_at(tmp, map, NULL, 0, x, y);
3907  }
3908 }
3909 
3917 void fix_weight(void) {
3918  player *pl;
3919 
3920  for (pl = first_player; pl != NULL; pl = pl->next) {
3921  int old = pl->ob->carrying, sum = object_sum_weight(pl->ob);
3922 
3923  if (old == sum)
3924  continue;
3925  fix_object(pl->ob);
3926  LOG(llevDebug, "Fixed inventory in %s (%d -> %d)\n", pl->ob->name, old, sum);
3927  }
3928 }
3929 
3933 void fix_luck(void) {
3934  player *pl;
3935 
3936  for (pl = first_player; pl != NULL; pl = pl->next)
3937  if (!pl->ob->contr->state)
3938  change_luck(pl->ob, 0);
3939 }
3940 
3941 
3954 void cast_dust(object *op, object *throw_ob, int dir) {
3955  object *skop, *spob;
3956 
3957  skop = find_skill_by_name(op, throw_ob->skill);
3958 
3959  /* casting POTION 'dusts' is really a use_magic_item skill */
3960  if (op->type == PLAYER && throw_ob->type == POTION && !skop) {
3961  LOG(llevError, "Player %s lacks critical skill use_magic_item!\n", op->name);
3962  return;
3963  }
3964  spob = throw_ob->inv;
3965  if (op->type == PLAYER && spob)
3967  "You cast %s.",
3968  spob->name);
3969 
3970  cast_spell(op, throw_ob, dir, spob, NULL);
3971 
3972  if (!QUERY_FLAG(throw_ob, FLAG_REMOVED))
3973  object_remove(throw_ob);
3974  object_free_drop_inventory(throw_ob);
3975 }
3976 
3983 void make_visible(object *op) {
3984  op->hide = 0;
3985  op->invisible = 0;
3986  if (op->type == PLAYER) {
3987  op->contr->tmp_invis = 0;
3988  if (op->contr->invis_race)
3990  }
3992 }
3993 
4002 int is_true_undead(object *op) {
4003  if (QUERY_FLAG(&op->arch->clone, FLAG_UNDEAD))
4004  return 1;
4005 
4006  return 0;
4007 }
4008 
4019 int hideability(object *ob) {
4020  int i, level = 0, mflag;
4021  int16_t x, y;
4022 
4023  if (!ob || !ob->map)
4024  return 0;
4025 
4026  /* so, on normal lighted maps, its hard to hide */
4027  level = ob->map->darkness-2;
4028 
4029  /* this also picks up whether the object is glowing.
4030  * If you carry a light on a non-dark map, its not
4031  * as bad as carrying a light on a pitch dark map
4032  */
4033  if (has_carried_lights(ob))
4034  level = -(10+(2*ob->map->darkness));
4035 
4036  /* scan through all nearby squares for terrain to hide in */
4037  for (i = 0, x = ob->x, y = ob->y; i < 9; i++, x = ob->x+freearr_x[i], y = ob->y+freearr_y[i]) {
4038  mflag = get_map_flags(ob->map, NULL, x, y, NULL, NULL);
4039  if (mflag&P_OUT_OF_MAP) {
4040  continue;
4041  }
4042  if (mflag&P_BLOCKSVIEW) /* something to hide near! */
4043  level += 2;
4044  else /* open terrain! */
4045  level -= 1;
4046  }
4047 
4048  return level;
4049 }
4050 
4060 void do_hidden_move(object *op) {
4061  int hide = 0, num = random_roll(0, 19, op, PREFER_LOW);
4062  object *skop;
4063 
4064  if (!op || !op->map)
4065  return;
4066 
4068 
4069  /* its *extremely *hard to run and sneak/hide at the same time! */
4070  if (op->type == PLAYER && op->contr->run_on) {
4071  if (!skop || num >= skop->level) {
4073  "You ran too much! You are no longer hidden!");
4074  make_visible(op);
4075  return;
4076  } else
4077  num += 20;
4078  }
4079  num += op->map->difficulty;
4080  hide = hideability(op); /* modify by terrain hidden level */
4081  num -= hide;
4082  if ((op->type == PLAYER && hide < -10)
4083  || ((op->invisible -= num) <= 0)) {
4084  make_visible(op);
4085  if (op->type == PLAYER)
4087  "You moved out of hiding! You are visible!");
4088  } else if (op->type == PLAYER && skop) {
4089  change_exp(op, calc_skill_exp(op, NULL, skop), skop->skill, 0);
4090  }
4091 }
4092 
4101 int stand_near_hostile(object *who) {
4102  int i, friendly = 0, player = 0, mflags;
4103  mapstruct *m;
4104  int16_t x, y;
4105 
4106  if (!who)
4107  return 0;
4108 
4109  if (who->type == PLAYER)
4110  player = 1;
4111  else
4113 
4114  /* search adjacent squares */
4115  for (i = 1; i < 9; i++) {
4116  x = who->x+freearr_x[i];
4117  y = who->y+freearr_y[i];
4118  m = who->map;
4119  mflags = get_map_flags(m, &m, x, y, &x, &y);
4120  /* space must be blocked if there is a monster. If not
4121  * blocked, don't need to check this space.
4122  */
4123  if (mflags&P_OUT_OF_MAP)
4124  continue;
4125  if (OB_TYPE_MOVE_BLOCK(who, GET_MAP_MOVE_BLOCK(m, x, y)))
4126  continue;
4127 
4128  FOR_MAP_PREPARE(m, x, y, tmp) {
4129  if ((player || friendly)
4130  && QUERY_FLAG(tmp, FLAG_MONSTER)
4131  && !QUERY_FLAG(tmp, FLAG_UNAGGRESSIVE))
4132  return 1;
4133  else if (tmp->type == PLAYER) {
4134  /*don't let a hidden DM prevent you from hiding*/
4135  if (!QUERY_FLAG(tmp, FLAG_WIZ) || tmp->contr->hidden == 0)
4136  return 1;
4137  }
4138  } FOR_MAP_FINISH();
4139  }
4140  return 0;
4141 }
4142 
4169 int player_can_view(object *pl, object *op) {
4170  rv_vector rv;
4171  int dx, dy;
4172 
4173  if (!pl || !op)
4174  return 0;
4175 
4176  if (pl->type != PLAYER) {
4177  LOG(llevError, "player_can_view() called for non-player object\n");
4178  return -1;
4179  }
4180 
4181  op = HEAD(op);
4182  if (!get_rangevector(pl, op, &rv, 0x1))
4183  return 0;
4184 
4185  /* starting with the 'head' part, lets loop
4186  * through the object and find if it has any
4187  * part that is in the los array but isnt on
4188  * a blocked los square.
4189  * we use the archetype to figure out offsets.
4190  */
4191  while (op) {
4192  dx = rv.distance_x+op->arch->clone.x;
4193  dy = rv.distance_y+op->arch->clone.y;
4194 
4195  /* only the viewable area the player sees is updated by LOS
4196  * code, so we need to restrict ourselves to that range of values
4197  * for any meaningful values.
4198  */
4199  if (FABS(dx) <= (pl->contr->socket->mapx/2)
4200  && FABS(dy) <= (pl->contr->socket->mapy/2)
4201  && !pl->contr->blocked_los[dx+(pl->contr->socket->mapx/2)][dy+(pl->contr->socket->mapy/2)])
4202  return 1;
4203  op = op->more;
4204  }
4205  return 0;
4206 }
4207 
4221 static int action_makes_visible(object *op) {
4222  if (op->invisible && QUERY_FLAG(op, FLAG_ALIVE)) {
4223  if (QUERY_FLAG(op, FLAG_MAKE_INVIS))
4224  return 0;
4225 
4226  if (op->contr && op->contr->tmp_invis == 0)
4227  return 0;
4228 
4229  /* If monsters, they should become visible */
4230  if (op->hide || !op->contr || (op->contr && op->contr->tmp_invis)) {
4232  "You become %s!",
4233  op->hide ? "unhidden" : "visible");
4234  return 1;
4235  }
4236  }
4237  return 0;
4238 }
4239 
4268 int op_on_battleground(object *op, int *x, int *y, archetype **trophy) {
4269  FOR_BELOW_PREPARE(op, tmp) {
4270  if (QUERY_FLAG(tmp, FLAG_IS_FLOOR)) {
4271  if (QUERY_FLAG(tmp, FLAG_NO_PICK)
4272  && strcmp(tmp->name, "battleground") == 0
4273  && tmp->type == BATTLEGROUND
4274  && EXIT_X(tmp)
4275  && EXIT_Y(tmp)) {
4276  /*before we assign the exit, check if this is a teambattle*/
4277  if (EXIT_ALT_X(tmp) && EXIT_ALT_Y(tmp) && EXIT_PATH(tmp)) {
4278  object *invtmp;
4279 
4280  invtmp = object_find_by_type_and_slaying(op, FORCE, EXIT_PATH(tmp));
4281  if (invtmp != NULL) {
4282  if (x != NULL && y != NULL)
4283  *x = EXIT_ALT_X(tmp),
4284  *y = EXIT_ALT_Y(tmp);
4285  return 1;
4286  }
4287  }
4288  if (x != NULL && y != NULL)
4289  *x = EXIT_X(tmp),
4290  *y = EXIT_Y(tmp);
4291 
4292  /* If 'other_arch' is not specified, give a finger. */
4293  if (trophy != NULL) {
4294  if (tmp->other_arch) {
4295  *trophy = tmp->other_arch;
4296  } else {
4297  *trophy = find_archetype("finger");
4298  }
4299  }
4300  return 1;
4301  }
4302  }
4303  } FOR_BELOW_FINISH();
4304  /* If we got here, did not find a battleground */
4305  return 0;
4306 }
4307 
4318 void dragon_ability_gain(object *who, int atnr, int level) {
4319  treasurelist *trlist = NULL; /* treasurelist */
4320  treasure *tr; /* treasure */
4321  object *tmp, *skop; /* tmp. object */
4322  object *item; /* treasure object */
4323  char buf[MAX_BUF]; /* tmp. string buffer */
4324  int i = 0, j = 0;
4325 
4326  /* get the appropriate treasurelist */
4327  if (atnr == ATNR_FIRE)
4328  trlist = find_treasurelist("dragon_ability_fire");
4329  else if (atnr == ATNR_COLD)
4330  trlist = find_treasurelist("dragon_ability_cold");
4331  else if (atnr == ATNR_ELECTRICITY)
4332  trlist = find_treasurelist("dragon_ability_elec");
4333  else if (atnr == ATNR_POISON)
4334  trlist = find_treasurelist("dragon_ability_poison");
4335 
4336  if (trlist == NULL || who->type != PLAYER)
4337  return;
4338 
4339  // tr->magic is being used to define what level of the metabolism the ability is gained at.
4340  for (tr = trlist->items; tr != NULL && tr->magic != level; tr = tr->next)
4341  ;
4342  if (tr == NULL || tr->item == NULL) {
4343  /* LOG(llevDebug, "-> no more treasure for %s\n", change_resist_msg[atnr]); */
4344  return;
4345  }
4346 
4347  /* everything seems okay - now bring on the gift: */
4348  item = &(tr->item->clone);
4349 
4350  if (item->type == SPELL) {
4351  if (check_spell_known(who, item->name))
4352  return;
4353 
4356  "You gained the ability of %s",
4357  item->name);
4358  do_learn_spell(who, item, 0);
4359  return;
4360  }
4361 
4362  /* grant direct spell */
4363  if (item->type == SPELLBOOK) {
4364  if (!item->inv) {
4365  LOG(llevDebug, "dragon_ability_gain: Broken spellbook %s\n", item->name);
4366  return;
4367  }
4368  if (check_spell_known(who, item->inv->name))
4369  return;
4370  if (item->invisible) {
4373  "You gained the ability of %s",
4374  item->inv->name);
4375  do_learn_spell(who, item->inv, 0);
4376  return;
4377  }
4378  } else if (item->type == SKILL_TOOL && item->invisible) {
4379  if (item->subtype == SK_CLAWING && (skop = find_skill_by_name(who, item->skill)) != NULL) {
4380  /* should this perhaps be (skop->attackyp&item->attacktype) != item->attacktype ...
4381  * in this way, if the player is missing any of the attacktypes, he gets
4382  * them. As it is now, if the player has any that match the granted skill,
4383  * but not all of them, he gets nothing.
4384  */
4385  if (!(skop->attacktype&item->attacktype)) {
4386  /* Give new attacktype */
4387  skop->attacktype |= item->attacktype;
4388 
4389  /* always add physical if there's none */
4390  skop->attacktype |= AT_PHYSICAL;
4391 
4392  if (item->msg != NULL)
4395  item->msg);
4396 
4397  /* Give player new face */
4398  if (item->animation) {
4399  who->face = skop->face;
4400  who->animation = item->animation;
4401  who->anim_speed = item->anim_speed;
4402  who->last_anim = 0;
4403  who->state = 0;
4404  animate_object(who, who->direction);
4405  }
4406  }
4407  }
4408  } else if (item->type == FORCE) {
4409  /* forces in the treasurelist can alter the player's stats */
4410  object *skin;
4411 
4412  /* first get the dragon skin force */
4413  skin = object_find_by_arch_name(who, "dragon_skin_force");
4414  if (skin == NULL)
4415  return;
4416 
4417  /* adding new spellpath attunements */
4418  if (item->path_attuned > 0 && !(skin->path_attuned&item->path_attuned)) {
4419  skin->path_attuned |= item->path_attuned; /* add attunement to skin */
4420 
4421  /* print message */
4422  snprintf(buf, sizeof(buf), "You feel attuned to ");
4423  for (i = 0, j = 0; i < NRSPELLPATHS; i++) {
4424  if (item->path_attuned&(1<<i)) {
4425  if (j)
4426  strcat(buf, " and ");
4427  else
4428  j = 1;
4429  strcat(buf, spellpathnames[i]);
4430  }
4431  }
4432  strcat(buf, ".");
4435  buf);
4436  }
4437 
4438  /* evtl. adding flags: */
4439  if (QUERY_FLAG(item, FLAG_XRAYS))
4440  SET_FLAG(skin, FLAG_XRAYS);
4441  if (QUERY_FLAG(item, FLAG_STEALTH))
4442  SET_FLAG(skin, FLAG_STEALTH);
4443  if (QUERY_FLAG(item, FLAG_SEE_IN_DARK))
4444  SET_FLAG(skin, FLAG_SEE_IN_DARK);
4445 
4446  /* print message if there is one */
4447  if (item->msg != NULL)
4450  item->msg);
4451  } else {
4452  /* generate misc. treasure */
4453  char name[HUGE_BUF];
4454 
4455  tmp = arch_to_object(tr->item);
4459  "You gained %s",
4460  name);
4461  tmp = object_insert_in_ob(tmp, who);
4462  if (who->type == PLAYER)
4463  esrv_send_item(who, tmp);
4464  }
4465 }
4466 
4476 void player_unready_range_ob(player *pl, object *ob) {
4477  int i;
4478 
4479  for (i = 0; i < static_cast<int>(range_size); i++) {
4480  if (pl->ranges[i] == ob) {
4481  pl->ranges[i] = NULL;
4482  if (pl->shoottype == i) {
4483  pl->shoottype = range_none;
4484  }
4485  }
4486  }
4487 }
4488 
4494 void player_set_state(player *pl, uint8_t state) {
4495 
4496  assert(pl);
4497  assert(state <= ST_CHANGE_PASSWORD_CONFIRM);
4498  pl->state = state;
4499 }
4500 
4508  SockList *sl;
4509  assert(pl);
4510  const uint8_t to_alloc = 5;
4512  if (pl->delayed_buffers_allocated >= UINT8_MAX - to_alloc) {
4513  LOG(llevError, "Delay buffer limit exceeded for %s\n", pl->ob->name);
4514  abort();
4515  }
4516  pl->delayed_buffers_allocated += to_alloc;
4517  pl->delayed_buffers = static_cast<SockList **>(realloc(pl->delayed_buffers, pl->delayed_buffers_allocated * sizeof(pl->delayed_buffers[0])));
4518  if (!pl->delayed_buffers) {
4519  LOG(llevError, "Unable to allocated %d delayed buffers, aborting\n", pl->delayed_buffers_allocated);
4521  }
4522  for (uint8_t s = pl->delayed_buffers_allocated - to_alloc; s < pl->delayed_buffers_allocated; s++) {
4523  pl->delayed_buffers[s] = static_cast<SockList *>(calloc(1, sizeof(SockList)));
4524  }
4525  }
4526  sl = pl->delayed_buffers[pl->delayed_buffers_used];
4527  pl->delayed_buffers_used++;
4528  SockList_Init(sl);
4529  return sl;
4530 }
4531 
4537  for (uint8_t buf = 0; buf < pl->delayed_buffers_used; buf++) {
4539  }
4540  pl->delayed_buffers_used = 0;
4541 }
4542 
4546 void player_start_repeat(player *pl, const char *action, repeat_cb cb) {
4547  if (pl->repeat_func_data) {
4548  free(pl->repeat_func_data);
4549  pl->repeat_func_data = NULL;
4550  }
4551  sstring old_action = pl->repeat_action;
4552  pl->repeat_action = add_string(action);
4553  if (old_action != pl->repeat_action) {
4554  // Action different from previous one, tell player about it.
4555  char buf[MAX_BUF];
4556  snprintf(buf, sizeof(buf), "You start %s.", action);
4558  }
4559  pl->repeat_func = cb;
4560  if (old_action)
4561  free_string(old_action);
4562 }
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:4268
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:1732
make_visible
void make_visible(object *op)
Makes an object visible again.
Definition: player.cpp:3983
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:3820
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:3042
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:2323
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:3515
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:514
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:660
esrv_map_scroll
void esrv_map_scroll(socket_struct *ns, int dx, int dy)
Definition: request.cpp:1757
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:121
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:1012
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:4507
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:1147
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:1969
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:36440
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:3288
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:2930
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:549
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:1884
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:3917
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:4536
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:4169
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:1012
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:887
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:2107
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:1998
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:3101
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:4494
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:132
socket_struct::mapy
uint8_t mapy
How large a map the client wants.
Definition: newserver.h:121
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:2860
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:1027
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:4476
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:627
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:1673
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:1436
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:593
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:4060
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:2039
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:4221
ADD_PLAYER_NO_MAP
#define ADD_PLAYER_NO_MAP
Do not set the first map.
Definition: player.h:253
socket_struct::client
sstring client
Client string sent by client.
Definition: newserver.h:105
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:2359
loot_object
static void loot_object(object *op)
Grab and destroy some treasure.
Definition: player.cpp:3438
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:1505
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:2289
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:131
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:3299
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:3260
hideability
int hideability(object *ob)
Look at the surrounding terrain to determine the hideability of this object.
Definition: player.cpp:4019
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:1937
kill_player_not_permadeath
static void kill_player_not_permadeath(object *op)
Kills a player in non-permadeath mode.
Definition: player.cpp:3596
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:612
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:962
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:2411
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:2638
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:3954
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:1600
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:3230
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:1295
stand_near_hostile
int stand_near_hostile(object *who)
Determine if who is standing near a hostile creature.
Definition: player.cpp:4101
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:1044
living::Wis
int8_t Wis
Definition: living.h:36
get_nearest_criminal
object * get_nearest_criminal(object *mon)
Definition: player.cpp:592
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:502
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:1219
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:1331
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:2108
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:3187
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:4318
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:3477
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:898
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:909
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:3933
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:2963
socket_struct::login_method
uint8_t login_method
Login method this client is using.
Definition: newserver.h:133
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:1068
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:469
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:691
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:2565
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:1161
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:2483
give_initial_items
void give_initial_items(object *pl, treasurelist *items)
Gives a new player her initial items.
Definition: player.cpp:793
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:2815
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:749
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:4002
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:1486
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:4546
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