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