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