Crossfire Server, Trunk
c_wiz.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 <ctype.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/stat.h>
26 
27 #include "sproto.h"
28 #include "spells.h"
29 #include "treasure.h"
30 #include "skills.h"
31 #include "assets.h"
32 #include "AssetsManager.h"
33 
34 /* Defines for DM item stack **/
35 #define STACK_SIZE 50
37 enum {
42 };
43 
45 
60 static player *get_other_player_from_name(object *op, const char *name) {
61  player *pl;
62 
63  if (!name)
64  return NULL;
65 
66  for (pl = first_player; pl != NULL; pl = pl->next)
67  if (!strncmp(pl->ob->name, name, MAX_NAME))
68  break;
69 
70  if (pl == NULL) {
72  "No such player.");
73  return NULL;
74  }
75 
76  if (pl->ob == op) {
78  "You can't do that to yourself.");
79  return NULL;
80  }
81  if (pl->state != ST_PLAYING) {
83  "That player is in no state for that right now.");
84  return NULL;
85  }
86  return pl;
87 }
88 
95 static void dm_stack_pop(player *pl) {
96  if (!pl->stack_items || !pl->stack_position) {
98  "Empty stack!");
99  return;
100  }
101 
102  pl->stack_position--;
104  "Popped item from stack, %d left.",
105  pl->stack_position);
106 }
107 
120 static object *dm_stack_peek(player *pl) {
121  object *ob;
122 
123  if (!pl->stack_position) {
125  "Empty stack!");
126  return NULL;
127  }
128 
129  ob = object_find_by_tag_global(pl->stack_items[pl->stack_position-1]);
130  if (!ob) {
132  "Stacked item was removed!");
133  dm_stack_pop(pl);
134  return NULL;
135  }
136 
137  return ob;
138 }
139 
150 static void dm_stack_push(player *pl, tag_t item) {
151  if (!pl->stack_items) {
152  pl->stack_items = (tag_t *)malloc(sizeof(tag_t)*STACK_SIZE);
153  memset(pl->stack_items, 0, sizeof(tag_t)*STACK_SIZE);
154  }
155 
156  if (pl->stack_position == STACK_SIZE) {
158  "Item stack full!");
159  return;
160  }
161 
162  pl->stack_items[pl->stack_position] = item;
164  "Item stacked as %d.",
165  pl->stack_position);
166  pl->stack_position++;
167 }
168 
196 static object *get_dm_object(player *pl, const char **params, int *from) {
197  int item_tag, item_position;
198  object *ob;
199 
200  if (!pl)
201  return NULL;
202 
203  if (**params == '\0') {
204  if (from)
205  *from = STACK_FROM_TOP;
206  /* No parameter => get stack item */
207  return dm_stack_peek(pl);
208  }
209 
210  /* Let's clean white spaces */
211  while (**params == ' ')
212  (*params)++;
213 
214  /* Next case: number => item tag */
215  if (sscanf(*params, "%d", &item_tag)) {
216  /* Move parameter to next item */
217  while (isdigit(**params))
218  (*params)++;
219 
220  /* And skip blanks, too */
221  while (**params == ' ')
222  (*params)++;
223 
224  /* Get item */
225  ob = object_find_by_tag_global(item_tag);
226  if (!ob) {
227  if (from)
228  *from = STACK_FROM_NONE;
230  "No such item %d!",
231  item_tag);
232  return NULL;
233  }
234 
235  /* Got one, let's push it on stack */
236  dm_stack_push(pl, item_tag);
237  if (from)
238  *from = STACK_FROM_NUMBER;
239  return ob;
240  }
241 
242  /* Next case: $number => stack item */
243  if (sscanf(*params, "$%d", &item_position)) {
244  /* Move parameter to next item */
245  (*params)++;
246 
247  while (isdigit(**params))
248  (*params)++;
249  while (**params == ' ')
250  (*params)++;
251 
252  if (item_position >= pl->stack_position) {
253  if (from)
254  *from = STACK_FROM_NONE;
256  "No such stack item %d!",
257  item_position);
258  return NULL;
259  }
260 
261  ob = object_find_by_tag_global(pl->stack_items[item_position]);
262  if (!ob) {
263  if (from)
264  *from = STACK_FROM_NONE;
266  "Stack item %d was removed.",
267  item_position);
268  return NULL;
269  }
270 
271  if (from)
272  *from = item_position < pl->stack_position-1 ? STACK_FROM_STACK : STACK_FROM_TOP;
273  return ob;
274  }
275 
276  /* Next case: 'me' => return pl->ob */
277  if (!strncmp(*params, "me", 2)) {
278  if (from)
279  *from = STACK_FROM_NUMBER;
280  dm_stack_push(pl, pl->ob->count);
281 
282  /* Skip to next token */
283  (*params) += 2;
284  while (**params == ' ')
285  (*params)++;
286 
287  return pl->ob;
288  }
289 
290  /* Last case: get stack top */
291  if (from)
292  *from = STACK_FROM_TOP;
293  return dm_stack_peek(pl);
294 }
295 
306 void command_loadtest(object *op, const char *params) {
307  uint32_t x, y;
308  char buf[1024];
309 
311  "loadtest will stress server through teleporting at different map places. "
312  "Use at your own risk. Very long loop used so server may have to be reset. "
313  "type loadtest TRUE to run");
315  "{%s}",
316  params);
317  if (*params == '\0')
318  return;
319  if (strncmp(params, "TRUE", 4))
320  return;
321 
323  "gogogo");
324 
325  for (x = 0; x < settings.worldmaptilesx; x++) {
326  for (y = 0; y < settings.worldmaptilesy; y++) {
327  snprintf(buf, sizeof(buf), "/world/world_%u_%u", x+settings.worldmapstartx, y+settings.worldmapstarty);
328  command_goto(op, buf);
329  }
330  }
331 }
332 
333 static void unhide(object* op) {
334  op->contr->hidden = 0;
335  op->invisible = 1;
336  op->map->players++;
338  "You are no longer hidden from other players");
341  "%s has entered the game.", op->name);
342 }
343 
352 static void do_wizard_hide(object *op, int silent_dm) {
353  if (op->contr->hidden) {
354  unhide(op);
355  if (!silent_dm) {
358  "The Dungeon Master has arrived!");
359  }
360  } else {
361  op->contr->hidden = 1;
363  "Other players will no longer see you.");
364  op->map->players--;
365  if (!silent_dm) {
368  "The Dungeon Master is gone...");
369  }
372  "%s leaves the game.",
373  op->name);
376  "%s left the game.",
377  op->name);
378  }
379 }
380 
389 void command_hide(object *op, const char *params) {
390  (void)params;
391  do_wizard_hide(op, 0);
392 }
393 
403 static object *find_object_both(const char *params) {
404  if (params[0] == '#')
405  return object_find_by_tag_global(atol(params+1));
406  else
408 }
409 
418 void command_setgod(object *op, const char *params) {
419  object *ob;
420  const object *god;
421  char *str;
422 
423  if (*params == '\0' || !(str = const_cast<char *>(strchr(params, ' ')))) {
425  "Usage: set_god player god");
426  return;
427  }
428 
429  /* kill the space, and set string to the next param */
430  *str++ = '\0';
431  if (!(ob = find_object_both(params))) {
433  "Set whose god - can not find object %s?",
434  params);
435  return;
436  }
437 
438  /*
439  * Perhaps this is overly restrictive? Should we perhaps be able
440  * to rebless altars and the like?
441  */
442  if (ob->type != PLAYER) {
444  "%s is not a player - can not change its god",
445  ob->name);
446  return;
447  }
448 
449  god = find_god(str);
450  if (god == NULL) {
452  "No such god %s.",
453  str);
454  return;
455  }
456 
457  become_follower(ob, god);
458 }
459 
468 static void command_kick2(object *op, const char *params) {
469  struct player *pl;
470 
471  for (pl = first_player; pl != NULL; pl = pl->next) {
472  if ((*params == '\0' || !strcmp(pl->ob->name, params)) && pl->ob != op) {
473  object *op = pl->ob;
474  if (!QUERY_FLAG(op, FLAG_REMOVED)) {
476  }
478  "%s is kicked out of the game.",
479  op->name);
480 
481  // Saving/leaving/removing is handled on the next tick in do_server().
482  pl->socket->status = Ns_Dead;
483  }
484  }
485 }
486 
502 void command_banish(object *op, const char *params) {
503  player *pl;
504  FILE *banishfile;
505  char buf[MAX_BUF];
506  time_t now;
507 
508  if (*params == '\0') {
510  "Usage: banish <player>.");
511  return;
512  }
513 
515  if (!pl)
516  return;
517 
518  snprintf(buf, sizeof(buf), "%s/%s", settings.localdir, BANISHFILE);
519 
520  if ((banishfile = fopen(buf, "a")) == NULL) {
521  LOG(llevDebug, "Could not find file banish_file.\n");
523  "Could not find banish_file.");
524  return;
525  }
526 
527  now = time(NULL);
528  /*
529  * Record this as a comment - then we don't have to worry about changing
530  * the parsing code.
531  */
532  fprintf(banishfile, "# %s (%s) banned by %s at %s\n", pl->ob->name, pl->socket->host, op->name, ctime(&now));
533  fprintf(banishfile, "*@%s\n", pl->socket->host);
534  fclose(banishfile);
535 
536  LOG(llevDebug, "! %s banned %s from IP: %s.\n", op->name, pl->ob->name, pl->socket->host);
537 
539  "You banish %s",
540  pl->ob->name);
541 
543  "%s banishes %s from the land!",
544  op->name, pl->ob->name);
545  command_kick2(op, pl->ob->name);
546 }
547 
556 void command_kick(object *op, const char *params) {
558 }
559 
568 void command_overlay_save(object *op, const char *params) {
569  (void)params;
570  if (!op)
571  return;
572 
573  if (save_map(op->map, SAVE_MODE_OVERLAY) < 0)
575  "Overlay save error!");
576  else
578  "Current map has been saved as an overlay.");
579 }
580 
589 void command_overlay_reset(object *op, const char *params) {
590  char filename[MAX_BUF];
591  struct stat stats;
592  (void)params;
593 
595  if (!stat(filename, &stats))
596  if (!unlink(filename))
598  "Overlay successfully removed.");
599  else
601  "Overlay couldn't be removed.");
602  else
604  "No overlay for current map.");
605 }
606 
615 void command_toggle_shout(object *op, const char *params) {
616  player *pl;
617 
618  if (*params == '\0') {
620  "Usage: toggle_shout <player>.");
621  return;
622  }
623 
625  if (!pl)
626  return;
627 
628  if (pl->ob->contr->no_shout == 0) {
629  pl->ob->contr->no_shout = 1;
630 
632  "You have been muzzled by the DM!");
634  "You muzzle %s.",
635  pl->ob->name);
636 
638 
639  return;
640  }
641 
642  pl->ob->contr->no_shout = 0;
644  "You are allowed to shout and chat again.");
646  "You remove %s's muzzle.",
647  pl->ob->name);
648 }
649 
658 void command_shutdown(object *op, const char *params) {
659  if (strlen(params) == 0) {
660  /* Give DM command help and display current shutdown status. */
661  command_help(op, "shutdown");
664  MSG_TYPE_COMMAND_DM, "No shutdown is currently scheduled.");
665  } else if (shutdown_state.type == SHUTDOWN_TIME) {
666  time_t time_left = shutdown_state.time - time(NULL);
668  MSG_TYPE_COMMAND_DM, "Shutdown scheduled in %lu minutes.", time_left/60);
669  } else if (shutdown_state.type == SHUTDOWN_IDLE) {
671  MSG_TYPE_COMMAND_DM, "Shutdown scheduled when there are no active players.");
672  }
673  } else if (strcmp(params, "cancel") == 0) {
676  MSG_TYPE_ADMIN_DM, "Server shutdown cancelled.");
677  LOG(llevInfo, "Server shutdown cancelled by %s.\n", op->name);
679  } else {
681  MSG_TYPE_COMMAND_ERROR, "No shutdown is pending.");
682  }
683  } else if (strncmp(params, "now", 3) == 0) {
684  /* Announce and shut down immediately. */
686  MSG_TYPE_ADMIN_DM, "This server is shutting down now!");
688  shutdown_state.time = time(NULL);
689  LOG(llevInfo, "Server shutdown initiated by %s.\n", op->name);
690  } else if (strcmp(params, "idle") == 0) {
692  MSG_TYPE_ADMIN_DM, "This server will shut down when all players leave.");
694  shutdown_state.time = 0;
696  LOG(llevInfo, "Server idle shutdown scheduled by %s.\n", op->name);
697  } else {
698  /* Schedule (but don't announce) a shutdown. */
699  int minutes = atoi(params);
700 
701  if (minutes > 0 && minutes <= 720) {
704  "Server will shut down in %d minutes.", minutes);
706  shutdown_state.time = time(NULL) + minutes * 60;
707  LOG(llevInfo, "Server shutdown scheduled in %d minutes by %s.\n", minutes, op->name);
708  } else {
711  "Please specify a reasonable time in minutes.");
712  }
713  }
714 }
715 
724 void command_goto(object *op, const char *params) {
725  if (!op)
726  return ;
727 
728  if (*params == '\0') {
730  "Go to what level?");
731  return;
732  }
733 
734  do_goto(op, params, -1, -1);
735 }
736 
745 void command_freeze(object *op, const char *params) {
746  int ticks;
747  player *pl;
748 
749  if (*params == '\0') {
751  "Usage: freeze [ticks] <player>.");
752  return;
753  }
754 
755  ticks = atoi(params);
756  if (ticks) {
757  while ((isdigit(*params) || isspace(*params)) && *params != 0)
758  params++;
759  if (*params == 0) {
761  "Usage: freeze [ticks] <player>.");
762  return;
763  }
764  } else
765  ticks = 100;
766 
768  if (!pl)
769  return;
770 
772  "You have been frozen by the DM!");
773 
775  "You freeze %s for %d ticks",
776  pl->ob->name, ticks);
777 
778  pl->ob->speed_left = -(pl->ob->speed*ticks);
779 }
780 
789 int player_arrest(object *who) {
790  object *dummy;
791  mapstruct *cur;
792  int x, y;
793 
794  if (who->type != PLAYER)
795  return -3;
796 
797  dummy = get_jail_exit(who);
798  if (!dummy) {
799  return -1;
800  }
801  cur = who->map;
802  x = who->x;
803  y = who->y;
804  enter_exit(who, dummy);
806 
807  if (cur == who->map && x == who->x && y == who->y)
808  return -2;
809 
810  return 0;
811 }
812 
821 void command_arrest(object *op, const char *params) {
822  player *pl;
823  int ret;
824 
825  if (!op)
826  return;
827  if (*params == '\0') {
829  "Usage: arrest <player>.");
830  return;
831  }
833  if (!pl)
834  return;
835 
836  ret = player_arrest(pl->ob);
837  if (ret == -1) {
838  /* we have nowhere to send the prisoner....*/
840  "Can't jail player, there is no map to hold them");
841  return;
842  }
843  if (ret == -2) {
844  /* something prevented jailing the player */
846  "Can't jail player, map loading issue or already in jail's position");
847  return;
848 
849  }
850 
852  "You have been arrested.");
854  "Jailed %s",
855  pl->ob->name);
856  LOG(llevInfo, "Player %s arrested by %s\n", pl->ob->name, op->name);
857 }
858 
866 void command_summon(object *op, const char *params) {
867  int i;
868  object *dummy;
869  player *pl;
870 
871  if (!op)
872  return;
873 
874  if (*params == '\0') {
876  "Usage: summon <player>.");
877  return;
878  }
879 
881  if (!pl)
882  return;
883 
884  i = object_find_free_spot(op, op->map, op->x, op->y, 1, 9);
885  if (i == -1) {
887  "Can not find a free spot to place summoned player.");
888  return;
889  }
890 
891  dummy = object_new();
892  EXIT_PATH(dummy) = add_string(op->map->path);
893  EXIT_X(dummy) = op->x+freearr_x[i];
894  EXIT_Y(dummy) = op->y+freearr_y[i];
895  enter_exit(pl->ob, dummy);
898  "You are summoned.");
900  "You summon %s",
901  pl->ob->name);
902 }
903 
912 /* mids 01/16/2002 */
913 void command_teleport(object *op, const char *params) {
914  int i;
915  object *dummy;
916  player *pl;
917 
918  if (!op)
919  return;
920 
921  if (*params == '\0') {
923  "Usage: teleport <player>.");
924  return;
925  }
926 
928  if (!pl) {
930  "No such player or ambiguous name.");
931  return;
932  }
933 
934  i = object_find_free_spot(pl->ob, pl->ob->map, pl->ob->x, pl->ob->y, 1, 9);
935  if (i == -1) {
937  "Can not find a free spot to teleport to.");
938  return;
939  }
940 
941  dummy = object_new();
942  EXIT_PATH(dummy) = add_string(pl->ob->map->path);
943  EXIT_X(dummy) = pl->ob->x+freearr_x[i];
944  EXIT_Y(dummy) = pl->ob->y+freearr_y[i];
945  enter_exit(op, dummy);
947  if (!op->contr->hidden)
949  "You see a portal open.");
951  "You teleport to %s",
952  pl->ob->name);
953 }
954 
979 void command_create(object *op, const char *params) {
980  object *tmp = NULL;
981  uint32_t i;
982  int magic, set_magic = 0, set_nrof = 0, gotquote, gotspace;
983  uint32_t nrof;
984  char *cp, *bp, *bp2, *bp3, *endline, cpy[MAX_BUF];
985  archetype *at, *at_spell = NULL;
986  const artifact *art = NULL;
987 
988  if (!op)
989  return;
990 
991  if (*params == '\0') {
993  "Usage: create [nr] [magic] <archetype> [ of <artifact>] [variable_to_patch setting]");
994  return;
995  }
996  safe_strncpy(cpy, params, sizeof(cpy));
997  bp = cpy;
998 
999  /* We need to know where the line ends */
1000  endline = bp+strlen(bp);
1001 
1002  if (sscanf(bp, "%u ", &nrof)) {
1003  if ((bp = strchr(cpy, ' ')) == NULL) {
1005  "Usage: create [nr] [magic] <archetype> [ of <artifact>] [variable_to_patch setting]");
1006  return;
1007  }
1008  bp++;
1009  set_nrof = 1;
1010  LOG(llevDebug, "%s creates: (%u) %s\n", op->name, nrof, bp);
1011  }
1012  if (sscanf(bp, "%d ", &magic)) {
1013  if ((bp = strchr(bp, ' ')) == NULL) {
1015  "Usage: create [nr] [magic] <archetype> [ of <artifact>] [variable_to_patch setting]");
1016  return;
1017  }
1018  bp++;
1019  set_magic = 1;
1020  LOG(llevDebug, "%s creates: (%d) (%d) %s\n", op->name, nrof, magic, bp);
1021  }
1022  if ((cp = strstr(bp, " of ")) != NULL) {
1023  *cp = '\0';
1024  cp += 4;
1025  }
1026  for (bp2 = bp; *bp2; bp2++) {
1027  if (*bp2 == ' ') {
1028  *bp2 = '\0';
1029  bp2++;
1030  break;
1031  }
1032  }
1033 
1034  if ((at = try_find_archetype(bp)) == NULL) {
1036  "No such archetype.");
1037  return;
1038  }
1039 
1040  if (cp) {
1041  char spell_name[MAX_BUF], *fsp = NULL;
1042 
1043  /*
1044  * Try to find a spell object for this. Note that
1045  * we also set up spell_name which is only
1046  * the first word.
1047  */
1048 
1049  at_spell = try_find_archetype(cp);
1050  if (!at_spell || at_spell->clone.type != SPELL)
1051  at_spell = find_archetype_by_object_name(cp);
1052  if (!at_spell || at_spell->clone.type != SPELL) {
1053  safe_strncpy(spell_name, cp, sizeof(spell_name));
1054  fsp = strchr(spell_name, ' ');
1055  if (fsp) {
1056  *fsp = 0;
1057  fsp++;
1058  at_spell = try_find_archetype(spell_name);
1059 
1060  /* Got a spell, update the first string pointer */
1061  if (at_spell && at_spell->clone.type == SPELL)
1062  bp2 = cp+strlen(spell_name)+1;
1063  else
1064  at_spell = NULL;
1065  } else
1066  at_spell = NULL;
1067  }
1068 
1069  /* OK - we didn't find a spell - presume the 'of'
1070  * in this case means its an artifact.
1071  */
1072  if (!at_spell) {
1073  if (find_artifactlist(at->clone.type) == NULL) {
1075  "No artifact list for type %d\n",
1076  at->clone.type);
1077  } else {
1078  auto items = find_artifactlist(at->clone.type)->items;
1079  auto i = std::find_if(items.cbegin(), items.cend(),
1080  [&] (const auto art) { return !strcmp(art->item->name, cp) && legal_artifact_combination(&at->clone, art); });
1081  art = i == items.cend() ? nullptr : *i;
1082 
1083  if (!art) {
1085  "No such artifact ([%d] of %s)",
1086  at->clone.type, cp);
1087  }
1088  }
1089  LOG(llevDebug, "%s creates: (%d) (%d) (%s) of (%s)\n", op->name, set_nrof ? nrof : 0, set_magic ? magic : 0, bp, cp);
1090  }
1091  } /* if cp */
1092 
1093  /* rods and potions can get their spell from the artifact */
1094  if ((at->clone.type == ROD || at->clone.type == POTION) && !at_spell && (!art || !art->item->other_arch)) {
1096  "Unable to find spell %s for object that needs it, or it is of wrong type",
1097  cp);
1098  return;
1099  }
1100  if ((at->clone.type == WAND || at->clone.type == SCROLL || at->clone.type == SPELLBOOK)
1101  && !at_spell) {
1103  "Unable to find spell %s for object that needs it, or it is of wrong type",
1104  cp);
1105  return;
1106  }
1107 
1108  /*
1109  * Rather than have two different blocks with a lot of similar code,
1110  * just create one object, do all the processing, and then determine
1111  * if that one object should be inserted or if we need to make copies.
1112  */
1113  tmp = object_create_arch(at);
1114  if (settings.real_wiz == FALSE)
1116  if (set_magic)
1117  set_abs_magic(tmp, magic);
1118  if (art)
1120  if (!is_identifiable_type(tmp)) {
1123  }
1124 
1125  /*
1126  * This entire block here tries to find variable pairings,
1127  * eg, 'hp 4' or the like. The mess here is that values
1128  * can be quoted (eg "my cool sword"); So the basic logic
1129  * is we want to find two spaces, but if we got a quote,
1130  * any spaces there don't count.
1131  */
1132  while (*bp2 && bp2 <= endline) {
1133  gotspace = 0;
1134  gotquote = 0;
1135  /* find the first quote */
1136  for (bp3 = bp2; *bp3 && gotspace < 2 && gotquote < 2; bp3++) {
1137  /* Found a quote - now lets find the second one */
1138  if (*bp3 == '"') {
1139  *bp3 = ' ';
1140  bp2 = bp3+1; /* Update start of string */
1141  bp3++;
1142  gotquote++;
1143  while (*bp3) {
1144  if (*bp3 == '"') {
1145  *bp3 = '\0';
1146  gotquote++;
1147  } else
1148  bp3++;
1149  }
1150  } else if (*bp3 == ' ') {
1151  gotspace++;
1152  }
1153  }
1154 
1155  /*
1156  * If we got two spaces, send the second one to null.
1157  * if we've reached the end of the line, increase gotspace -
1158  * this is perfectly valid for the list entry listed.
1159  */
1160  if (gotspace == 2 || gotquote == 2) {
1161  bp3--; /* Undo the extra increment */
1162  *bp3 = '\0';
1163  } else if (*bp3 == '\0')
1164  gotspace++;
1165 
1166  if ((gotquote && gotquote != 2)
1167  || (gotspace != 2 && gotquote != 2)) {
1168  /*
1169  * Unfortunately, we've clobbered lots of values, so printing
1170  * out what we have probably isn't useful. Break out, because
1171  * trying to recover is probably won't get anything useful
1172  * anyways, and we'd be confused about end of line pointers
1173  * anyways.
1174  */
1176  "Malformed create line: %s",
1177  bp2);
1178  break;
1179  }
1180  /* bp2 should still point to the start of this line,
1181  * with bp3 pointing to the end
1182  */
1183  if (set_variable(tmp, bp2) == -1)
1185  "Unknown variable %s",
1186  bp2);
1187  else
1189  "(%s#%d)->%s",
1190  tmp->name, tmp->count, bp2);
1191  bp2 = bp3+1;
1192  }
1193 
1194  if (at->clone.nrof) {
1195  if (at_spell)
1197 
1198  if (set_nrof)
1199  tmp->nrof = nrof;
1200 
1201  if (at->clone.randomitems != NULL && !at_spell) {
1202  create_treasure(at->clone.randomitems, tmp, 0, op->map->difficulty, 0);
1203  if (QUERY_FLAG(tmp, FLAG_MONSTER)) {
1205  }
1206  }
1207 
1208  /* Multipart objects can't be in inventory, put'em on floor. */
1209  if (!tmp->more) {
1211  } else {
1212  object_insert_in_map_at(tmp, op->map, op, 0, op->x, op->y);
1213  }
1214 
1215  /* Let's put this created item on stack so dm can access it easily. */
1216  dm_stack_push(op->contr, tmp->count);
1217 
1218  return;
1219  }
1220 
1221  for (i = 0; i < (set_nrof ? nrof : 1); i++) {
1222  archetype *atmp;
1223  object *prev = NULL, *head = NULL, *dup;
1224 
1225  for (atmp = at; atmp != NULL; atmp = atmp->more) {
1226  dup = arch_to_object(atmp);
1227 
1228  if (at_spell)
1229  object_insert_in_ob(arch_to_object(at_spell), dup);
1230 
1231  /*
1232  * The head is what contains all the important bits,
1233  * so just copying it over should be fine.
1234  */
1235  if (head == NULL) {
1236  head = dup;
1237  object_copy(tmp, dup);
1238  }
1239  if (settings.real_wiz == FALSE)
1240  SET_FLAG(dup, FLAG_WAS_WIZ);
1241  dup->x = op->x+dup->arch->clone.x;
1242  dup->y = op->y+dup->arch->clone.y;
1243  dup->map = op->map;
1244 
1245  if (head != dup) {
1246  dup->head = head;
1247  prev->more = dup;
1248  }
1249  prev = dup;
1250  }
1251 
1252  if (QUERY_FLAG(head, FLAG_ALIVE)) {
1253  object *check = head;
1254  int size_x = 0;
1255  int size_y = 0;
1256 
1257  while (check) {
1258  size_x = MAX(size_x, check->arch->clone.x);
1259  size_y = MAX(size_y, check->arch->clone.y);
1260  check = check->more;
1261  }
1262 
1263  if (out_of_map(op->map, head->x+size_x, head->y+size_y)) {
1264  if (head->x < size_x || head->y < size_y) {
1265  dm_stack_pop(op->contr);
1268  "Object too big to insert in map, or wrong position.");
1270  return;
1271  }
1272 
1273  check = head;
1274  while (check) {
1275  check->x -= size_x;
1276  check->y -= size_y;
1277  check = check->more;
1278  }
1279  }
1280 
1281  object_insert_in_map_at(head, op->map, op, 0, head->x, head->y);
1282  } else
1283  head = object_insert_in_ob(head, op);
1284 
1285  /* Let's put this created item on stack so dm can access it easily. */
1286  /* Wonder if we really want to push all of these, but since
1287  * things like rods have nrof 0, we want to cover those.
1288  */
1289  dm_stack_push(op->contr, head->count);
1290 
1291  if (at->clone.randomitems != NULL && !at_spell) {
1292  create_treasure(at->clone.randomitems, head, 0, op->map->difficulty, 0);
1293  if (QUERY_FLAG(head, FLAG_MONSTER)) {
1295  }
1296  }
1297  }
1298 
1299  /* free the one we used to copy */
1301 }
1302 
1303 /*
1304  * Now follows dm-commands which are also acceptable from sockets
1305  */
1306 
1315 void command_inventory(object *op, const char *params) {
1316  object *tmp;
1317  int i;
1318 
1319  if (*params == '\0') {
1320  inventory(op, NULL);
1321  return;
1322  }
1323 
1324  if (!sscanf(params, "%d", &i) || (tmp = object_find_by_tag_global(i)) == NULL) {
1326  "Inventory of what object (nr)?");
1327  return;
1328  }
1329 
1330  inventory(op, tmp);
1331 }
1332 
1345 void command_skills(object *op, const char *params) {
1346  show_skills(op, *params == '\0' ? NULL : params);
1347 }
1348 
1357 void command_dump(object *op, const char *params) {
1358  object *tmp;
1359  StringBuffer *sb;
1360  char *diff;
1361 
1362  tmp = get_dm_object(op->contr, &params, NULL);
1363  if (!tmp)
1364  return;
1365 
1366  sb = stringbuffer_new();
1367  object_dump(tmp, sb);
1368  diff = stringbuffer_finish(sb);
1370  free(diff);
1373  "Object is marked original");
1374 }
1375 
1385 void command_mon_aggr(object *op, const char *params) {
1386  (void)params;
1387  if (op->enemy || !QUERY_FLAG(op, FLAG_UNAGGRESSIVE)) {
1388  object_set_enemy(op, NULL);
1391  "Aggression turned OFF");
1392  } else {
1396  "Aggression turned ON");
1397  }
1398 }
1399 
1412 void command_possess(object *op, const char *params) {
1413  object *victim;
1414  player *pl;
1415  int i;
1416  char buf[MAX_BUF];
1417 
1418  victim = NULL;
1419  if (*params != '\0') {
1420  if (sscanf(params, "%d", &i))
1422  else if (sscanf(params, "%s", buf))
1424  }
1425  if (victim == NULL) {
1427  "Patch what object (nr)?");
1428  return;
1429  }
1430 
1431  if (victim == op) {
1433  "As insane as you are, I cannot allow you to possess yourself.");
1434  return;
1435  }
1436 
1437  /* make the switch */
1438  pl = op->contr;
1439  victim->contr = pl;
1440  pl->ob = victim;
1441  victim->type = PLAYER;
1443 
1444  /* basic patchup */
1445  /* The use of hard coded values is terrible. Note
1446  * that really, to be fair, this shouldn't get changed at
1447  * all - if you are possessing a kobold, you should have the
1448  * same limitations. As it is, as more body locations are added,
1449  * this will give this player more locations than perhaps
1450  * they should be allowed.
1451  */
1452  for (i = 0; i < NUM_BODY_LOCATIONS; i++)
1453  if (i == 1 || i == 6 || i == 8 || i == 9)
1454  victim->body_info[i] = 2;
1455  else
1456  victim->body_info[i] = 1;
1457 
1458  esrv_new_player(pl, 80); /* just pick a weight, we don't care */
1460 
1461  fix_object(victim);
1462 
1464 }
1465 
1473 void command_patch(object *op, const char *params) {
1474  const char *arg, *arg2;
1475  object *tmp;
1476 
1477  tmp = get_dm_object(op->contr, &params, NULL);
1478  if (!tmp)
1479  /* Player already informed of failure */
1480  return;
1481 
1482  /* params set to first value by get_dm_default */
1483  arg = params;
1484  if (*arg == '\0') {
1486  "Patch what values?");
1487  return;
1488  }
1489 
1490  if ((arg2 = strchr(arg, ' ')))
1491  arg2++;
1492  if (settings.real_wiz == FALSE)
1493  SET_FLAG(tmp, FLAG_WAS_WIZ); /* To avoid cheating */
1494  if (set_variable(tmp, arg) == -1)
1496  "Unknown variable %s",
1497  arg);
1498  else {
1500  "(%s#%d)->%s=%s",
1501  tmp->name, tmp->count, arg, arg2);
1502  }
1503 }
1504 
1505 static void reset_faces_sent(struct socket_struct *socket) {
1506  free(socket->faces_sent);
1507  socket->faces_sent = static_cast<uint8_t *>(calloc(sizeof(socket->faces_sent[0]), get_faces_count()));
1508  socket->faces_sent_len = get_faces_count();
1509 }
1510 
1511 void command_recollect(object *op, const char *params) {
1512  (void)op;
1513  (void)params;
1514  load_assets();
1515 
1516  // Clear sent faces for connected sockets so that clients see new faces.
1517  for (int i = 0; i < socket_info.allocated_sockets; i++) {
1518  /*
1519  if (init_sockets[i].status == Ns_Add) {
1520  reset_faces_sent(&init_sockets[i]);
1521  }
1522  */
1523  }
1524 
1525  player *next;
1526  for (player *pl = first_player; pl != NULL; pl = next) {
1527  reset_faces_sent(pl->socket);
1528  next = pl->next;
1529  }
1530 }
1531 
1540 void command_remove(object *op, const char *params) {
1541  object *tmp;
1542  int from;
1543 
1544  tmp = get_dm_object(op->contr, &params, &from);
1545  if (!tmp) {
1547  "Remove what object (nr)?");
1548  return;
1549  }
1550 
1551  if (tmp->type == PLAYER) {
1553  "Unable to remove a player!");
1554  return;
1555  }
1556 
1557  if (QUERY_FLAG(tmp, FLAG_REMOVED)) {
1558  char name[MAX_BUF];
1559 
1562  "%s is already removed!",
1563  name);
1564  return;
1565  }
1566 
1567  if (from != STACK_FROM_STACK)
1568  /* Item is either stack top, or is a number thus is now stack top, let's remove it */
1569  dm_stack_pop(op->contr);
1570 
1571  /* Always work on the head - otherwise object will get in odd state */
1572  tmp = HEAD(tmp);
1573  if (tmp->speed != 0) {
1574  tmp->speed = 0;
1576  }
1577  object_remove(tmp);
1578 }
1579 
1587 void command_free(object *op, const char *params) {
1588  object *tmp;
1589  int from;
1590 
1591  tmp = get_dm_object(op->contr, &params, &from);
1592 
1593  if (!tmp) {
1595  "Free what object (nr)?");
1596  return;
1597  }
1598 
1599  if (from != STACK_FROM_STACK)
1600  /* Item is either stack top, or is a number thus is now stack top, let's remove it */
1601  dm_stack_pop(op->contr);
1602 
1603  tmp = HEAD(tmp);
1604  if (!QUERY_FLAG(tmp, FLAG_REMOVED)) {
1606  "Warning: item was not removed, will do so now.");
1607  object_remove(tmp);
1608  }
1609 
1611 }
1612 
1613 void command_accountpasswd(object *op, const char *params) {
1614  char account_name[MAX_BUF], newpw[MAX_BUF];
1615  // Password may contain spaces, so use %[^\n] format string.
1616  if (sscanf(params, "%s %[^\n]", account_name, newpw) != 2) {
1618  "Usage: accountpasswd ACCOUNT PASSWORD");
1619  return;
1620  }
1621 
1622  int ret = account_change_password(account_name, NULL, newpw);
1623  switch (ret) {
1624  case 0:
1626  "Updated account password.");
1627  return;
1628  case 1:
1630  "Invalid characters in new password.");
1631  return;
1632  case 2:
1634  "Invalid characters in new password.");
1635  return;
1636  default:
1638  "Error changing password.");
1639  return;
1640  }
1641 }
1642 
1651 void command_addexp(object *op, const char *params) {
1652  char buf[MAX_BUF], skill[MAX_BUF];
1653  int i, q;
1654  object *skillob = NULL;
1655  player *pl;
1656 
1657  skill[0] = '\0';
1658  if ((*params == '\0')
1659  || (strlen(params) > MAX_BUF)
1660  || ((q = sscanf(params, "%s %d %[^\r\n]", buf, &i, skill)) < 2)) {
1662  "Usage: addexp player quantity [skill].");
1663  return;
1664  }
1665 
1666  for (pl = first_player; pl != NULL; pl = pl->next)
1667  if (!strncmp(pl->ob->name, buf, MAX_NAME))
1668  break;
1669 
1670  if (pl == NULL) {
1672  "No such player.");
1673  return;
1674  }
1675 
1676  if (q >= 3) {
1677  skillob = find_skill_by_name(pl->ob, skill);
1678  if (!skillob) {
1680  "Unable to find skill %s in %s",
1681  skill, buf);
1682  return;
1683  }
1684 
1685  i = check_exp_adjust(skillob, i);
1686  skillob->stats.exp += i;
1687  calc_perm_exp(skillob);
1688  player_lvl_adj(pl->ob, skillob);
1689  }
1690 
1691  pl->ob->stats.exp += i;
1692  calc_perm_exp(pl->ob);
1693  player_lvl_adj(pl->ob, NULL);
1694 
1695  if (settings.real_wiz == FALSE)
1696  SET_FLAG(pl->ob, FLAG_WAS_WIZ);
1697 }
1698 
1707 void command_speed(object *op, const char *params) {
1708  int i;
1709 
1710  if (*params == '\0' || !sscanf(params, "%d", &i)) {
1712  "Current speed is %d",
1713  tick_duration);
1714  return;
1715  }
1716 
1717  set_tick_duration(i);
1718  reset_sleep();
1720  "The speed is changed to %d.",
1721  i);
1722 }
1723 
1724 /**************************************************************************/
1725 /* Mods made by Tyler Van Gorder, May 10-13, 1992. */
1726 /* CSUChico : tvangod@cscihp.ecst.csuchico.edu */
1727 /**************************************************************************/
1728 
1737 void command_stats(object *op, const char *params) {
1738  player *pl;
1739 
1740  if (*params == '\0') {
1742  "Who?");
1743  return;
1744  }
1745 
1747  if (pl == NULL) {
1749  "No such player.");
1750  return;
1751  }
1752 
1754  "[Fixed]Statistics for %s:", pl->ob->name);
1755 
1757  "[fixed]Str : %-2d H.P. : %-4d MAX : %d",
1758  pl->ob->stats.Str, pl->ob->stats.hp, pl->ob->stats.maxhp);
1759 
1761  "[fixed]Dex : %-2d S.P. : %-4d MAX : %d",
1762  pl->ob->stats.Dex, pl->ob->stats.sp, pl->ob->stats.maxsp);
1763 
1765  "[fixed]Con : %-2d AC : %-4d WC : %d",
1766  pl->ob->stats.Con, pl->ob->stats.ac, pl->ob->stats.wc);
1767 
1769  "[fixed]Int : %-2d Damage : %d",
1770  pl->ob->stats.Int, pl->ob->stats.dam);
1771 
1773  "[fixed]Wis : %-2d EXP : %" FMT64,
1774  pl->ob->stats.Wis, pl->ob->stats.exp);
1775 
1777  "[fixed]Pow : %-2d Grace : %d",
1778  pl->ob->stats.Pow, pl->ob->stats.grace);
1779 
1781  "[fixed]Cha : %-2d Food : %d",
1782  pl->ob->stats.Cha, pl->ob->stats.food);
1783 }
1784 
1794 void command_abil(object *op, const char *params) {
1795  char thing[20], thing2[20];
1796  int iii;
1797  player *pl;
1798 
1799  iii = 0;
1800  thing[0] = '\0';
1801  thing2[0] = '\0';
1802  if (*params == '\0'
1803  || sscanf(params, "%s %s %d", thing, thing2, &iii) != 3
1804  || thing[0] == '\0') {
1806  "Who?");
1807  return;
1808  }
1809 
1810  if (thing2[0] == '\0') {
1812  "You can't change that.");
1813  return;
1814  }
1815 
1816  if (iii < MIN_STAT || iii > settings.max_stat) {
1818  "Illegal range of stat.\n");
1819  return;
1820  }
1821 
1822  for (pl = first_player; pl != NULL; pl = pl->next) {
1823  if (!strcmp(pl->ob->name, thing)) {
1824  if (settings.real_wiz == FALSE)
1825  SET_FLAG(pl->ob, FLAG_WAS_WIZ);
1826  if (!strcmp("str", thing2))
1827  pl->ob->stats.Str = iii, pl->orig_stats.Str = iii;
1828  if (!strcmp("dex", thing2))
1829  pl->ob->stats.Dex = iii, pl->orig_stats.Dex = iii;
1830  if (!strcmp("con", thing2))
1831  pl->ob->stats.Con = iii, pl->orig_stats.Con = iii;
1832  if (!strcmp("wis", thing2))
1833  pl->ob->stats.Wis = iii, pl->orig_stats.Wis = iii;
1834  if (!strcmp("cha", thing2))
1835  pl->ob->stats.Cha = iii, pl->orig_stats.Cha = iii;
1836  if (!strcmp("int", thing2))
1837  pl->ob->stats.Int = iii, pl->orig_stats.Int = iii;
1838  if (!strcmp("pow", thing2))
1839  pl->ob->stats.Pow = iii, pl->orig_stats.Pow = iii;
1841  "%s has been altered.",
1842  pl->ob->name);
1843  fix_object(pl->ob);
1844  return;
1845  }
1846  }
1847 
1849  "No such player.");
1850 }
1851 
1860 void command_reset(object *op, const char *params) {
1861  mapstruct *m;
1862  object *dummy = NULL, *tmp = NULL;
1863  char path[HUGE_BUF];
1864  const char *space, *confirmation = NULL;
1865  int res = 0;
1866 
1867  if (*params == '\0') {
1869  MSG_TYPE_COMMAND_ERROR, "Which map should be reset?");
1870  return;
1871  }
1872 
1873  space = strchr(params, ' ');
1874  if (space != NULL) {
1875  confirmation = params;
1876  params = space + 1;
1877  }
1878 
1879  /* Use the DM's map if the current map was given. */
1880  if (strcmp(params, ".") == 0) {
1881  strlcpy(path, op->map->path, sizeof(path));
1882  } else {
1883  path_combine_and_normalize(op->map->path, params, path, sizeof(path));
1884  }
1885 
1886  m = has_been_loaded(path);
1887  if (m == NULL) {
1889  MSG_TYPE_COMMAND_ERROR, "No such map.");
1890  return;
1891  }
1892 
1893  if (confirmation) {
1894  if (m->unique && (op->map == m)) {
1897  "Cannot reset a unique player map while on it. Use "
1898  "'reset full-reset %s' while standing somewhere else.",
1899  m->path);
1900  return;
1901  }
1902 
1903  if (strncmp("full-reset", confirmation, strlen("full-reset"))) {
1905  MSG_TYPE_COMMAND_ERROR, "Confirm using 'full-reset'.");
1906  return;
1907  }
1908  }
1909 
1910  /* Forbid using reset on our own map when we're in a transport, as
1911  * it has the displeasant effect of crashing the server.
1912  * - gros, July 25th 2006 */
1913  if ((op->contr && op->contr->transport) && (op->map == m)) {
1915  "You need to disembark first.");
1916  return;
1917  }
1918 
1919  strlcpy(path, m->path, sizeof(path));
1920 
1921  sstring reset_group = m->reset_group;
1922  m->reset_group = NULL;
1923 
1924  if (m->in_memory != MAP_SWAPPED) {
1925  if (m->in_memory != MAP_IN_MEMORY) {
1926  LOG(llevError, "Tried to swap out map which was not in memory.\n");
1927  m->reset_group = reset_group;
1928  return;
1929  }
1930 
1931  /*
1932  * Only attempt to remove the player that is doing the reset, and not other
1933  * players or wiz's.
1934  */
1935  if (op->map == m) {
1936  if (strncmp(m->path, "/random/", 8) == 0) {
1937  /* This is not a very satisfying solution - it would be much better
1938  * to recreate a random map with the same seed value as the old one.
1939  * Unfortunately, I think recreating the map would require some
1940  * knowledge about its 'parent', which appears very non-trivial to
1941  * me.
1942  * On the other hand, this should prevent the freeze that this
1943  * situation caused. - gros, 26th July 2006.
1944  */
1946  "You cannot reset a random map when inside it.");
1947  m->reset_group = reset_group;
1948  return;
1949  }
1950 
1951  dummy = object_new();
1952  dummy->map = NULL;
1953  EXIT_X(dummy) = op->x;
1954  EXIT_Y(dummy) = op->y;
1955  EXIT_PATH(dummy) = add_string(op->map->path);
1956  object_remove(op);
1957  op->map = NULL;
1958  tmp = op;
1959  }
1960  res = swap_map(m);
1961  }
1962 
1963  if (res < 0 || m->in_memory != MAP_SWAPPED) {
1964  player *pl;
1965  int playercount = 0;
1966 
1967  /* Need to re-insert player if swap failed for some reason */
1968  if (tmp) {
1969  object_insert_in_map_at(op, m, NULL, 0, op->x, op->y);
1971  }
1972 
1973  if (res < 0 && res != SAVE_ERROR_PLAYER)
1974  /* no need to warn if player on map, code below checks that. */
1976  "Reset failed, error code: %d.", res);
1977  else {
1979  "Reset failed, couldn't swap map, the following players are on it:");
1980  for (pl = first_player; pl != NULL; pl = pl->next) {
1981  if (pl->ob->map == m && pl->ob != op) {
1983  pl->ob->name);
1984  playercount++;
1985  }
1986  }
1987  if (!playercount)
1989  "hmm, I don't see any other players on this map, something else is the problem.");
1990  m->reset_group = reset_group;
1991  return;
1992  }
1993  }
1994 
1995  FREE_AND_CLEAR_STR_IF(reset_group);
1996 
1997  /* Here, map reset succeeded. */
1998 
1999  if (m && m->in_memory == MAP_SWAPPED) {
2000  if (confirmation) {
2002  LOG(llevDebug, "DM %s fully resetting map %s.\n", op->name, m->path);
2003  } else
2004  LOG(llevDebug, "DM %s resetting map %s.\n", op->name, m->path);
2005 
2006  /* setting this effectively causes an immediate reload */
2007  m->reset_time = 1;
2008  flush_old_maps();
2009  }
2010 
2011  /* Display the appropriate success message. */
2012  if (confirmation) {
2014  MSG_TYPE_COMMAND_DM, "Fully resetting map %s.", path);
2015  } else {
2017  MSG_TYPE_COMMAND_DM, "Resetting map %s.", path);
2018  }
2019 
2020  if (tmp) {
2021  enter_exit(tmp, dummy);
2023  }
2024 
2025  /* Remind the DM how to fully reset the map. */
2026  if (confirmation == NULL) {
2029  "Use 'reset full-reset %s' to fully reset the map.", params);
2030  }
2031 }
2032 
2041 void command_nowiz(object *op, const char *params) { /* 'noadm' is alias */
2042  (void)params;
2046 
2047  if (settings.real_wiz == TRUE)
2049  if (op->contr->hidden) {
2050  unhide(op);
2051  } else
2053  "The Dungeon Master is gone...");
2054 
2055  update_los(op);
2056 }
2057 
2078 static int checkdm(object *op, const char *pl_name, const char *pl_passwd, const char *pl_host) {
2079  FILE *dmfile;
2080  char buf[MAX_BUF];
2081  char line_buf[160], name[160], passwd[160], host[160];
2082 
2083 #ifdef RESTRICTIVE_DM
2084  *pl_name = op->name ? op->name : "*";
2085 #else
2086  (void)op;
2087 #endif
2088 
2089  snprintf(buf, sizeof(buf), "%s/%s", settings.confdir, DMFILE);
2090  if ((dmfile = fopen(buf, "r")) == NULL) {
2091  LOG(llevDebug, "Could not find DM file.\n");
2092  return 0;
2093  }
2094 
2095  while (fgets(line_buf, 160, dmfile) != NULL) {
2096  // Skip empty lines as well as commented ones.
2097  if (line_buf[0] == '#' || line_buf[0] == '\n')
2098  continue;
2099  if (sscanf(line_buf, "%[^:]:%[^:]:%s\n", name, passwd, host) != 3) {
2100  LOG(llevError, "Warning - malformed dm file entry: %s\n", line_buf);
2101  } else if ((!strcmp(name, "*") || (pl_name && !strcmp(pl_name, name)))
2102  && (!strcmp(passwd, "*") || !strcmp(passwd, pl_passwd))
2103  && (!strcmp(host, "*") || !strcmp(host, pl_host))) {
2104  fclose(dmfile);
2105  return (1);
2106  }
2107  }
2108  fclose(dmfile);
2109  return (0);
2110 }
2111 
2126 static int do_wizard_dm(object *op, const char *params, int silent) {
2127  if (!op->contr)
2128  return 0;
2129 
2130  if (QUERY_FLAG(op, FLAG_WIZ)) {
2132  "You are already the Dungeon Master!");
2133  return 0;
2134  }
2135 
2136  if (checkdm(op, op->name, (*params != '\0' ? params : "*"), op->contr->socket->host)) {
2137  SET_FLAG(op, FLAG_WIZ);
2142  "Ok, you are the Dungeon Master!");
2143  /*
2144  * Remove setting flying here - that won't work, because next
2145  * fix_object() is called that will get cleared - proper solution
2146  * is probably something like a wiz_force which gives that and any
2147  * other desired abilities.
2148  */
2149  clear_los(op->contr);
2150 
2151  if (!silent)
2154  "The Dungeon Master has arrived!");
2155 
2156  return 1;
2157  }
2158 
2160  "Sorry Pal, I don't think so.");
2161  return 0;
2162 }
2163 
2175 void command_dm(object *op, const char *params) {
2176  do_wizard_dm(op, params, 0);
2177 }
2178 
2187 void command_invisible(object *op, const char *params) {
2188  (void)params;
2189  if (op) {
2190  op->invisible += 100;
2193  "You turn invisible.");
2194  }
2195 }
2196 
2214 static object *get_spell_by_name(object *op, const char *spell_name) {
2215  archetype *found;
2216  int conflict_found;
2217  size_t spell_name_length;
2218 
2219  /* First check for full name matches. */
2220  conflict_found = 0;
2221  found = NULL;
2222  getManager()->archetypes()->each([&] (auto ar) {
2223  if (ar->clone.type != SPELL)
2224  return;
2225 
2226  if (strncmp(ar->name, "spelldirect_", 12) == 0)
2227  return;
2228 
2229  if (strcmp(ar->clone.name, spell_name) != 0)
2230  return;
2231 
2232  if (found != NULL) {
2233  if (!conflict_found) {
2234  conflict_found = 1;
2236  "More than one archetype matches the spell name %s:",
2237  spell_name);
2239  "- %s",
2240  found->name);
2241  }
2243  "- %s",
2244  ar->name);
2245  return;
2246  }
2247 
2248  found = ar;
2249  });
2250 
2251  /* No match if more more than one archetype matches. */
2252  if (conflict_found)
2253  return NULL;
2254 
2255  /* Return if exactly one archetype matches. */
2256  if (found != NULL)
2257  return arch_to_object(found);
2258 
2259  /* No full match found: now check for partial matches. */
2260  spell_name_length = strlen(spell_name);
2261  conflict_found = 0;
2262  found = NULL;
2263 
2264  getManager()->archetypes()->each([&] (auto ar) {
2265  if (ar->clone.type != SPELL)
2266  return;
2267 
2268  if (strncmp(ar->name, "spelldirect_", 12) == 0)
2269  return;
2270 
2271  if (strncmp(ar->clone.name, spell_name, spell_name_length) != 0)
2272  return;
2273 
2274  if (found != NULL) {
2275  if (!conflict_found) {
2276  conflict_found = 1;
2278  "More than one spell matches %s:",
2279  spell_name);
2281  "- %s",
2282  found->clone.name);
2283  }
2285  "- %s",
2286  ar->clone.name);
2287  return;
2288  }
2289 
2290  found = ar;
2291  });
2292 
2293  /* No match if more more than one archetype matches. */
2294  if (conflict_found)
2295  return NULL;
2296 
2297  /* Return if exactly one archetype matches. */
2298  if (found != NULL)
2299  return arch_to_object(found);
2300 
2301  /* No spell found: just print an error message. */
2303  "The spell %s does not exist.",
2304  spell_name);
2305  return NULL;
2306 }
2307 
2318 static void command_learn_spell_or_prayer(object *op, const char *params, int special_prayer) {
2319  object *tmp;
2320 
2321  if (op->contr == NULL || *params == '\0') {
2323  "Which spell do you want to learn?");
2324  return;
2325  }
2326 
2328  if (tmp == NULL) {
2329  return;
2330  }
2331 
2332  if (check_spell_known(op, tmp->name)) {
2334  "You already know the spell %s.",
2335  tmp->name);
2336  return;
2337  }
2338 
2339  do_learn_spell(op, tmp, special_prayer);
2341 }
2342 
2351 void command_learn_spell(object *op, const char *params) {
2353 }
2354 
2363 void command_learn_special_prayer(object *op, const char *params) {
2365 }
2366 
2376 void command_forget_spell(object *op, const char *params) {
2377  object *spell;
2378 
2379  if (op->contr == NULL || *params == '\0') {
2381  "Which spell do you want to forget?");
2382  return;
2383  }
2384 
2386  if (spell == NULL) {
2388  "You do not know the spell %s.",
2389  params);
2390  return;
2391  }
2392 
2393  do_forget_spell(op, spell->name);
2394 }
2395 
2404 void command_listplugins(object *op, const char *params) {
2405  (void)params;
2407 }
2408 
2419 void command_loadplugin(object *op, const char *params) {
2420  char buf[MAX_BUF];
2421 
2422  if (*params == '\0') {
2424  "Load which plugin?");
2425  return;
2426  }
2427 
2428  snprintf(buf, sizeof(buf), LIBDIR"/plugins/%s", params);
2429  LOG(llevDebug, "Requested plugin file is %s\n", buf);
2430  if (plugins_init_plugin(buf) == 0) {
2431  LOG(llevInfo, "DM %s loaded plugin %s\n", op->name, params);
2433  "Plugin %s successfully loaded.",
2434  params);
2435  } else
2437  "Could not load plugin %s.",
2438  params);
2439 }
2440 
2451 void command_unloadplugin(object *op, const char *params) {
2452  if (*params == '\0') {
2454  "Remove which plugin?");
2455  return;
2456  }
2457 
2458  if (plugins_remove_plugin(params) == 0) {
2459  LOG(llevInfo, "DM %s unloaded plugin %s\n", op->name, params);
2461  "Plugin %s successfully removed.",
2462  params);
2463  init_signals(); // Restore our signal handlers, some plugins (Python) mess with them
2464  } else
2466  "Could not remove plugin %s.",
2467  params);
2468 }
2469 
2480 void command_dmhide(object *op, const char *params) {
2481  if (!do_wizard_dm(op, params, 1))
2482  return;
2483 
2484  do_wizard_hide(op, 1);
2485 }
2486 
2495 void command_stack_pop(object *op, const char *params) {
2496  (void)params;
2497  dm_stack_pop(op->contr);
2498 }
2499 
2508 void command_stack_push(object *op, const char *params) {
2509  object *ob;
2510  int from;
2511  ob = get_dm_object(op->contr, &params, &from);
2512 
2513  if (ob && from != STACK_FROM_NUMBER)
2514  /* Object was from stack, need to push it again */
2515  dm_stack_push(op->contr, ob->count);
2516 }
2517 
2526 void command_stack_list(object *op, const char *params) {
2527  int item;
2528  object *display;
2529  player *pl = op->contr;
2530  (void)params;
2531 
2533  "Item stack contents:");
2534 
2535  for (item = 0; item < pl->stack_position; item++) {
2536  display = object_find_by_tag_global(pl->stack_items[item]);
2537  if (display)
2539  " %d : %s [%d]",
2540  item, display->name, display->count);
2541  else
2542  /* Item was freed */
2544  " %d : (lost item: %d)",
2545  item, pl->stack_items[item]);
2546  }
2547 }
2548 
2557 void command_stack_clear(object *op, const char *params) {
2558  (void)params;
2559  op->contr->stack_position = 0;
2561  "Item stack cleared.");
2562 }
2563 
2583 void command_diff(object *op, const char *params) {
2584  object *left, *right;
2585  char *diff;
2586  StringBuffer *sb;
2587  int left_from, right_from;
2588 
2589  left = get_dm_object(op->contr, &params, &left_from);
2590  if (!left) {
2592  "Compare to what item?");
2593  return;
2594  }
2595 
2596  if (left_from == STACK_FROM_NUMBER)
2597  /* Item was stacked, remove it else right will be the same... */
2598  dm_stack_pop(op->contr);
2599 
2600  right = get_dm_object(op->contr, &params, &right_from);
2601 
2602  if (!right) {
2604  "Compare what item?");
2605  return;
2606  }
2607 
2609  "Item difference:");
2610 
2611  if (left_from == STACK_FROM_TOP && right_from == STACK_FROM_TOP) {
2612  /*
2613  * Special case: both items were taken from stack top.
2614  * Override the behaviour, taking left as item just below top, if exists.
2615  * See function description for why.
2616  * Besides, if we don't do anything, compare an item to itself, not really useful.
2617  */
2618  if (op->contr->stack_position > 1) {
2619  left = object_find_by_tag_global(op->contr->stack_items[op->contr->stack_position-2]);
2620  if (left)
2622  "(Note: first item taken from undertop)");
2623  else
2624  /* Stupid case: item under top was freed, fallback to stack top */
2625  left = right;
2626  }
2627  }
2628 
2629  sb = stringbuffer_new();
2630  get_ob_diff(sb, left, right);
2631  diff = stringbuffer_finish(sb);
2632  if (*diff == '\0') {
2633  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, "Objects are the same.");
2634  } else {
2636  }
2637  free(diff);
2638 }
2639 
2647 void command_insert_into(object *op, const char *params) {
2648  object *left, *right, *inserted;
2649  int left_from, right_from;
2650  char what[MAX_BUF], where[MAX_BUF];
2651 
2652  left = get_dm_object(op->contr, &params, &left_from);
2653  if (!left) {
2655  "Insert into what object?");
2656  return;
2657  }
2658 
2659  if (left_from == STACK_FROM_NUMBER)
2660  /* Item was stacked, remove it else right will be the same... */
2661  dm_stack_pop(op->contr);
2662 
2663  right = get_dm_object(op->contr, &params, &right_from);
2664 
2665  if (!right) {
2667  "Insert what item?");
2668  return;
2669  }
2670 
2671  if (left_from == STACK_FROM_TOP && right_from == STACK_FROM_TOP) {
2672  /*
2673  * Special case: both items were taken from stack top.
2674  * Override the behaviour, taking left as item just below top, if exists.
2675  * See function description for why.
2676  * Besides, can't insert an item into itself.
2677  */
2678  if (op->contr->stack_position > 1) {
2679  left = object_find_by_tag_global(op->contr->stack_items[op->contr->stack_position-2]);
2680  if (left)
2682  "(Note: item to insert into taken from undertop)");
2683  else
2684  /* Stupid case: item under top was freed, fallback to stack top */
2685  left = right;
2686  }
2687  }
2688 
2689  if (left == right) {
2691  "Can't insert an object into itself!");
2692  return;
2693  }
2694 
2695  if (right->type == PLAYER) {
2697  "Can't insert a player into something!");
2698  return;
2699  }
2700 
2701  if (!QUERY_FLAG(right, FLAG_REMOVED))
2702  object_remove(right);
2703  inserted = object_insert_in_ob(right, left);
2704  if (left->type == PLAYER) {
2705  if (inserted != right)
2706  /* item was merged, so updating name and such. */
2707  esrv_update_item(UPD_WEIGHT|UPD_NAME|UPD_NROF, left, inserted);
2708  }
2709  query_name(inserted, what, MAX_BUF);
2710  query_name(left, where, MAX_BUF);
2712  "Inserted %s in %s",
2713  what, where);
2714 }
2715 
2724 void command_style_map_info(object *op, const char *params) {
2725  extern mapstruct *styles;
2726  mapstruct *mp;
2727  int maps_used = 0, mapmem = 0, objects_used = 0, x, y;
2728  (void)params;
2729 
2730  for (mp = styles; mp != NULL; mp = mp->next) {
2731  maps_used++;
2732  mapmem += map_size(mp) * (sizeof(object *)+sizeof(MapSpace))+sizeof(mapstruct);
2733  for (x = 0; x < MAP_WIDTH(mp); x++) {
2734  for (y = 0; y < MAP_HEIGHT(mp); y++) {
2735  FOR_MAP_PREPARE(mp, x, y, tmp)
2736  objects_used++;
2737  FOR_MAP_FINISH();
2738  }
2739  }
2740  }
2742  "[fixed]Style maps loaded: %d",
2743  maps_used);
2745  "[fixed]Memory used, not");
2747  "[fixed]including objects: %d",
2748  mapmem);
2750  "[fixed]Style objects: %d",
2751  objects_used);
2753  "[fixed]Mem for objects: %lu",
2754  (unsigned long)(objects_used*sizeof(object)));
2755 }
2756 
2757 bool can_follow(object* op, player* other) {
2758  // Only allow follow from same party.
2759  return (other->ob->contr->party != NULL) && (op->contr->party == other->ob->contr->party);
2760 }
2761 
2770 void command_follow(object *op, const char *params) {
2771  player *other;
2772 
2773  if (*params == '\0') {
2774  if (op->contr->followed_player != NULL) {
2775  draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_SUCCESS, "You stop following %s.", op->contr->followed_player);
2776  FREE_AND_CLEAR_STR(op->contr->followed_player);
2777  }
2778  return;
2779  }
2780 
2782  if (!other) {
2783  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "No such player or ambiguous name.");
2784  return;
2785  }
2786  if (other == op->contr) {
2787  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "You can't follow yourself.");
2788  return;
2789  }
2790 
2791  // Players trying to 'follow' are subject to additional checks.
2792  if (!QUERY_FLAG(op, FLAG_WIZ)) {
2793  if (!can_follow(op, other)) {
2796  "You can only follow members in the same party.");
2797  return;
2798  }
2799  rv_vector rv;
2800  if (!get_rangevector(op, other->ob, &rv, 0) || rv.distance > 1) {
2801  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "You need to go to them first!");
2802  return;
2803  }
2805  }
2806 
2807  if (op->contr->followed_player)
2808  FREE_AND_CLEAR_STR(op->contr->followed_player);
2809 
2810  op->contr->followed_player = add_string(other->ob->name);
2811  draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_SUCCESS, "Following %s.", op->contr->followed_player);
2812 }
2813 
2814 void command_purge_quest(object *op, const char * param) {
2815  (void)param;
2816  free_quest();
2817  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_DM, "Purged quest state.");
2818 }
2819 
2820 void command_purge_quest_definitions(object *op, const char * param) {
2821  (void)param;
2823  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_DM, "Purged quests definitions.");
2824 }
2825 
2826 void do_dump(object *who, object *what) {
2827  StringBuffer *sb;
2828  char *diff;
2829 
2830  sb = stringbuffer_new();
2831  object_dump(what, sb);
2832  diff = stringbuffer_finish(sb);
2834  free(diff);
2835 
2836  /* Let's push that item on the dm's stack */
2837  dm_stack_push(who->contr, what->count);
2838 }
2839 
2848 void command_dumpbelow(object *op, const char *params) {
2849  (void)params;
2850  if (op && op->below) {
2851  do_dump(op, op->below);
2852  }
2853 }
2854 
2863 void command_dumpabove(object *op, const char *params) {
2864  (void)params;
2865  if (op && op->above) {
2866  do_dump(op, op->above);
2867  }
2868 }
2869 
2875 void command_settings(object *op, const char *ignored) {
2876  (void)ignored;
2877  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_DM, "Server settings:");
2878 
2880 
2881  if (settings.not_permadeth) {
2882  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_DM, " * death is not permanent");
2883  } else if (settings.resurrection) {
2884  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_DM, " * permanent death, resurrection is enabled");
2885  } else {
2886  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_DM, " * permanent death, resurrection is NOT enabled");
2887  }
2888 
2889  if (settings.set_title) {
2890  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_DM, " * players can set their title");
2891  } else {
2892  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_DM, " * players can't set their title");
2893  }
2894 
2897  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_DM, " * too much equipment can lead to spell failure and ill effects");
2898  } else {
2899  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_DM, " * too much equipment can lead to spell failure but no ill effects");
2900  }
2901  } else {
2902  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_DM, " * too much equipment can't lead to spell failure");
2903  }
2904 
2905  if (settings.casting_time) {
2906  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_DM, " * casting takes time");
2907  } else {
2908  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_DM, " * casting is immediate");
2909  }
2910 
2913 
2915 
2917  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_DM, " * players can't steal from other players");
2918  } else {
2919  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_DM, " * players can steal from other players");
2920  }
2921 
2923  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_DM, " * players can create portals from their apartments");
2924  } else {
2925  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_DM, " * players can't create portals from their apartments");
2926  }
2927 
2929  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_DM, " * players can write spells they are denied");
2930  } else {
2931  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_DM, " * players can't write spells they are denied");
2932  }
2933 }
get_other_player_from_name
static player * get_other_player_from_name(object *op, const char *name)
Definition: c_wiz.cpp:60
give.next
def next
Definition: give.py:44
command_overlay_reset
void command_overlay_reset(object *op, const char *params)
Definition: c_wiz.cpp:589
command_possess
void command_possess(object *op, const char *params)
Definition: c_wiz.cpp:1412
STACK_FROM_NONE
@ STACK_FROM_NONE
Definition: c_wiz.cpp:38
living::exp
int64_t exp
Definition: living.h:47
UP_OBJ_FACE
#define UP_OBJ_FACE
Definition: object.h:524
PLAYER
@ PLAYER
Definition: object.h:112
set_magic
static void set_magic(int difficulty, object *op, int max_magic, int flags)
Definition: treasure.cpp:666
FREE_AND_CLEAR_STR_IF
#define FREE_AND_CLEAR_STR_IF(xyz)
Definition: global.h:200
global.h
FREE_OBJ_NO_DESTROY_CALLBACK
#define FREE_OBJ_NO_DESTROY_CALLBACK
Definition: object.h:536
Settings::death_penalty_ratio
uint8_t death_penalty_ratio
Definition: global.h:259
first_player
player * first_player
Definition: init.cpp:106
settings
struct Settings settings
Definition: init.cpp:139
set_abs_magic
void set_abs_magic(object *op, int magic)
Definition: treasure.cpp:618
STACK_SIZE
#define STACK_SIZE
Definition: c_wiz.cpp:35
safe_strncpy
#define safe_strncpy
Definition: compat.h:27
FOR_MAP_FINISH
#define FOR_MAP_FINISH()
Definition: define.h:730
STACK_FROM_NUMBER
@ STACK_FROM_NUMBER
Definition: c_wiz.cpp:41
command_overlay_save
void command_overlay_save(object *op, const char *params)
Definition: c_wiz.cpp:568
NUM_BODY_LOCATIONS
#define NUM_BODY_LOCATIONS
Definition: object.h:15
MSG_TYPE_COMMAND_SUCCESS
#define MSG_TYPE_COMMAND_SUCCESS
Definition: newclient.h:519
command_style_map_info
void command_style_map_info(object *op, const char *params)
Definition: c_wiz.cpp:2724
llevError
@ llevError
Definition: logger.h:11
WAND
@ WAND
Definition: object.h:225
MSG_TYPE_ADMIN_PLAYER
#define MSG_TYPE_ADMIN_PLAYER
Definition: newclient.h:485
LOG
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.cpp:51
SHUTDOWN_IDLE
@ SHUTDOWN_IDLE
Definition: commands.h:44
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:224
reset_faces_sent
static void reset_faces_sent(struct socket_struct *socket)
Definition: c_wiz.cpp:1505
archetype::more
archetype * more
Definition: object.h:477
Settings::worldmapstartx
uint32_t worldmapstartx
Definition: global.h:291
command_patch
void command_patch(object *op, const char *params)
Definition: c_wiz.cpp:1473
player
Definition: player.h:105
Settings::worldmaptilesx
uint32_t worldmaptilesx
Definition: global.h:293
diamondslots.x
x
Definition: diamondslots.py:15
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
plugins_remove_plugin
int plugins_remove_plugin(const char *id)
Definition: plugins.cpp:454
plugins_init_plugin
int plugins_init_plugin(const char *libfile)
Definition: plugins.cpp:373
do_learn_spell
void do_learn_spell(object *op, object *spell, int special_prayer)
Definition: apply.cpp:484
command_shutdown
void command_shutdown(object *op, const char *params)
Definition: c_wiz.cpp:658
has_been_loaded
mapstruct * has_been_loaded(const char *name)
Definition: map.cpp:78
socket_struct
Definition: newserver.h:89
flush_old_maps
void flush_old_maps(void)
Definition: swap.cpp:289
esrv_new_player
void esrv_new_player(player *pl, uint32_t weight)
Definition: request.cpp:991
FALSE
#define FALSE
Definition: compat.h:14
MapSpace
Definition: map.h:255
banquet.size_x
int size_x
Definition: banquet.py:23
command_speed
void command_speed(object *op, const char *params)
Definition: c_wiz.cpp:1707
esrv_send_inventory
void esrv_send_inventory(object *pl, object *op)
Definition: item.cpp:316
do_wizard_dm
static int do_wizard_dm(object *op, const char *params, int silent)
Definition: c_wiz.cpp:2126
command_learn_spell
void command_learn_spell(object *op, const char *params)
Definition: c_wiz.cpp:2351
stringbuffer_new
StringBuffer * stringbuffer_new(void)
Definition: stringbuffer.cpp:57
UPD_WEIGHT
#define UPD_WEIGHT
Definition: newclient.h:305
object_set_enemy
void object_set_enemy(object *op, object *enemy)
Definition: object.cpp:915
artifactlist::items
std::vector< artifact * > items
Definition: artifact.h:28
dm_stack_pop
static void dm_stack_pop(player *pl)
Definition: c_wiz.cpp:95
EXIT_PATH
#define EXIT_PATH(xyz)
Definition: define.h:439
FLAG_OBJ_ORIGINAL
#define FLAG_OBJ_ORIGINAL
Definition: define.h:357
player::ob
object * ob
Definition: player.h:177
give_artifact_abilities
void give_artifact_abilities(object *op, const object *artifact)
Definition: artifact.cpp:230
socket_info
Socket_Info socket_info
Definition: init.cpp:49
object::map
struct mapstruct * map
Definition: object.h:305
command_arrest
void command_arrest(object *op, const char *params)
Definition: c_wiz.cpp:821
command_teleport
void command_teleport(object *op, const char *params)
Definition: c_wiz.cpp:913
guildjoin.ob
ob
Definition: guildjoin.py:42
command_mon_aggr
void command_mon_aggr(object *op, const char *params)
Definition: c_wiz.cpp:1385
Settings::localdir
const char * localdir
Definition: global.h:249
artifact::item
object * item
Definition: artifact.h:15
dm_stack_push
static void dm_stack_push(player *pl, tag_t item)
Definition: c_wiz.cpp:150
check_exp_adjust
int64_t check_exp_adjust(const object *op, int64_t exp)
Definition: living.cpp:2091
time
non standard information is not specified or uptime this means how long since the executable has been started A particular host may have been running a server for quite a long time
Definition: arch-handbook.txt:206
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
command_purge_quest
void command_purge_quest(object *op, const char *param)
Definition: c_wiz.cpp:2814
calc_perm_exp
void calc_perm_exp(object *op)
Definition: living.cpp:1903
Settings::spell_failure_effects
uint8_t spell_failure_effects
Definition: global.h:269
unhide
static void unhide(object *op)
Definition: c_wiz.cpp:333
do_dump
void do_dump(object *who, object *what)
Definition: c_wiz.cpp:2826
object::count
tag_t count
Definition: object.h:307
Ice.tmp
int tmp
Definition: Ice.py:207
FLAG_WIZCAST
#define FLAG_WIZCAST
Definition: define.h:289
object_copy
void object_copy(const object *src_ob, object *dest_ob)
Definition: object.cpp:1192
Settings::spell_encumbrance
uint8_t spell_encumbrance
Definition: global.h:268
command_invisible
void command_invisible(object *op, const char *params)
Definition: c_wiz.cpp:2187
fix_object
void fix_object(object *op)
Definition: living.cpp:1125
command_banish
void command_banish(object *op, const char *params)
Definition: c_wiz.cpp:502
NDI_RED
#define NDI_RED
Definition: newclient.h:234
UPD_NROF
#define UPD_NROF
Definition: newclient.h:310
plugins_display_list
void plugins_display_list(object *op)
Definition: plugins.cpp:479
command_addexp
void command_addexp(object *op, const char *params)
Definition: c_wiz.cpp:1651
command_listplugins
void command_listplugins(object *op, const char *params)
Definition: c_wiz.cpp:2404
skills.h
npc_dialog.filename
filename
Definition: npc_dialog.py:99
MSG_TYPE_COMMAND_ERROR
#define MSG_TYPE_COMMAND_ERROR
Definition: newclient.h:518
object_find_by_tag_global
object * object_find_by_tag_global(tag_t i)
Definition: object.cpp:727
AssetsManager.h
create_treasure
void create_treasure(treasurelist *t, object *op, int flag, int difficulty, int tries)
Definition: treasure.cpp:263
set_variable
int set_variable(object *op, const char *buf)
Definition: loader.c:5306
buf
StringBuffer * buf
Definition: readable.cpp:1552
set_tick_duration
void set_tick_duration(long t)
Definition: time.cpp:205
getManager
AssetsManager * getManager()
Definition: assets.cpp:305
object_insert_in_ob
object * object_insert_in_ob(object *op, object *where)
Definition: object.cpp:2848
banquet.size_y
int size_y
Definition: banquet.py:24
HUGE_BUF
#define HUGE_BUF
Definition: define.h:37
MAX
#define MAX(x, y)
Definition: compat.h:24
MSG_TYPE_COMMAND
#define MSG_TYPE_COMMAND
Definition: newclient.h:393
Settings::worldmaptilesy
uint32_t worldmaptilesy
Definition: global.h:294
find_god
const object * find_god(const char *name)
Definition: holy.cpp:317
name
Plugin animator file specs[Config] name
Definition: animfiles.txt:4
NDI_ORANGE
#define NDI_ORANGE
Definition: newclient.h:235
Settings::allow_denied_spells_writing
int allow_denied_spells_writing
Definition: global.h:315
SAVE_MODE_OVERLAY
#define SAVE_MODE_OVERLAY
Definition: map.h:119
draw_ext_info
vs only yadda is in because all tags get reset on the next draw_ext_info In the second since it is all in one draw_ext_info
Definition: media-tags.txt:61
FLAG_ALIVE
#define FLAG_ALIVE
Definition: define.h:230
command_learn_special_prayer
void command_learn_special_prayer(object *op, const char *params)
Definition: c_wiz.cpp:2363
Ns_Dead
@ Ns_Dead
Definition: newserver.h:67
command_remove
void command_remove(object *op, const char *params)
Definition: c_wiz.cpp:1540
map_remove_unique_files
void map_remove_unique_files(const mapstruct *map)
Definition: map.cpp:2665
MSG_TYPE_ADMIN_DM
#define MSG_TYPE_ADMIN_DM
Definition: newclient.h:486
MSG_TYPE_COMMAND_DEBUG
#define MSG_TYPE_COMMAND_DEBUG
Definition: newclient.h:517
ASSETS_QUESTS
#define ASSETS_QUESTS
Definition: assets.h:30
m
static event_registration m
Definition: citylife.cpp:425
clear_los
void clear_los(player *pl)
Definition: los.cpp:270
autojail.who
who
Definition: autojail.py:3
MAP_IN_MEMORY
#define MAP_IN_MEMORY
Definition: map.h:127
stringbuffer_finish
char * stringbuffer_finish(StringBuffer *sb)
Definition: stringbuffer.cpp:76
space
Crossfire Protocol most of the time after the actual code was already omit certain important and possibly make life miserable any new developer or curious player should be able to find most of the relevant information here If inconsistencies are found or this documentation proves to be consider the latest server side protocol code in the public source code repository as the authoritative reference Introduction If you were ever curious enough to telnet or netcat to a Crossfire chances are you were sorely disappointed While the protocol may seem to use plain text at it actually uses a mix of ASCII and binary data This handbook attempts to document various aspects of the Crossfire protocol As consult the README file to find out how to get in touch with helpful people via mailing and more History the communications plan was set to be a text based system It was up to the server and client to parse these messages and determine what to do These messages were assumed to be line per message At a reasonably early stage of Eric Anderson wrote a then the data itself you could send many data and after the other end could decode these commands This works fairly but I think the creation of numerous sub packets has some performance hit the eutl was not especially well so writing a client for a different platform became more Eric left to work on other products shortly after writing his which didn t really leave anyone with a full understanding of the socket code I have decided to remove the eutl dependency At least one advantage is that having this network related code directly in the client and server makes error handling a bit easier cleaner Packet Format the outside packet method the byte size for the size information is not included here Eutl originally used bytes for the size to bytes seems it makes a least some sense The actual data is something of the nature of the commands listed below It is a text followed by possible other data The remaining data can be binary it is up to the client and server to decode what it sent The commands as described below is just the data portion of the packet If writing a new remember that you must take into account the size of the packet There is no termination of other than knowing how long it should be For most everything that is sent is text This is more or less how things worked under except it packed the ints into bytes in a known order In some we handle ints as in they are sent as binary information How any command handles it is detailed below in the command description The S and C represent the direction of the we use MSB as well as any ints or shorts that get sent inside the packets All packets are defined to have at least one word of followed by a space
Definition: protocol.txt:85
Settings::set_friendly_fire
uint16_t set_friendly_fire
Definition: global.h:275
object_free_drop_inventory
void object_free_drop_inventory(object *ob)
Definition: object.cpp:1555
object_update
void object_update(object *op, int action)
Definition: object.cpp:1429
shutdown_s::time
time_t time
Definition: commands.h:49
object::contr
struct player * contr
Definition: object.h:284
item.q
q
Definition: item.py:32
FMT64
#define FMT64
Definition: compat.h:16
command_toggle_shout
void command_toggle_shout(object *op, const char *params)
Definition: c_wiz.cpp:615
map_size
uint32_t map_size(mapstruct *m)
Definition: map.cpp:798
command_setgod
void command_setgod(object *op, const char *params)
Definition: c_wiz.cpp:418
Settings::set_title
uint8_t set_title
Definition: global.h:265
FLAG_WAS_WIZ
#define FLAG_WAS_WIZ
Definition: define.h:234
freearr_y
short freearr_y[SIZEOFFREE]
Definition: object.cpp:305
command_create
void command_create(object *op, const char *params)
Definition: c_wiz.cpp:979
command_reset
void command_reset(object *op, const char *params)
Definition: c_wiz.cpp:1860
do_wizard_hide
static void do_wizard_hide(object *op, int silent_dm)
Definition: c_wiz.cpp:352
query_name
void query_name(const object *op, char *buf, size_t size)
Definition: item.cpp:592
POTION
@ POTION
Definition: object.h:116
command_summon
void command_summon(object *op, const char *params)
Definition: c_wiz.cpp:866
path_combine_and_normalize
char * path_combine_and_normalize(const char *src, const char *dst, char *path, size_t size)
Definition: path.cpp:172
MSG_TYPE_COMMAND_DM
#define MSG_TYPE_COMMAND_DM
Definition: newclient.h:524
command_purge_quest_definitions
void command_purge_quest_definitions(object *op, const char *param)
Definition: c_wiz.cpp:2820
archetype::clone
object clone
Definition: object.h:478
STACK_FROM_TOP
@ STACK_FROM_TOP
Definition: c_wiz.cpp:39
object_dump
void object_dump(const object *op, StringBuffer *sb)
Definition: object.cpp:645
add_string
sstring add_string(const char *str)
Definition: shstr.cpp:124
HEAD
#define HEAD(op)
Definition: object.h:598
ROD
@ ROD
Definition: object.h:114
free_quest
void free_quest(void)
Definition: quest.cpp:891
shutdown_s::type
enum shutdown_type type
Definition: commands.h:48
make_face_from_files.str
str
Definition: make_face_from_files.py:30
command_dm
void command_dm(object *op, const char *params)
Definition: c_wiz.cpp:2175
out_of_map
int out_of_map(mapstruct *m, int x, int y)
Definition: map.cpp:2286
shutdown_s
Definition: commands.h:47
command_abil
void command_abil(object *op, const char *params)
Definition: c_wiz.cpp:1794
lookup_spell_by_name
object * lookup_spell_by_name(object *op, const char *spname)
Definition: spell_util.cpp:410
command_dumpbelow
void command_dumpbelow(object *op, const char *params)
Definition: c_wiz.cpp:2848
command_diff
void command_diff(object *op, const char *params)
Definition: c_wiz.cpp:2583
object_update_speed
void object_update_speed(object *op)
Definition: object.cpp:1344
object::type
uint8_t type
Definition: object.h:348
command_inventory
void command_inventory(object *op, const char *params)
Definition: c_wiz.cpp:1315
do_goto
void do_goto(object *op, const char *name, int x, int y)
Definition: c_move.cpp:151
command_help
void command_help(object *op, const char *params)
Definition: c_misc.cpp:1772
shutdown_state
struct shutdown_s shutdown_state
Definition: c_wiz.cpp:44
show_skills
void show_skills(object *op, const char *search)
Definition: skill_util.cpp:860
command_skills
void command_skills(object *op, const char *params)
Definition: c_wiz.cpp:1345
object_create_arch
object * object_create_arch(archetype *at)
Definition: arch.cpp:298
spell
with a maximum of six This is not so if you are wearing plate you receive no benefit Armour is additive with all the supplementry forms of which means that it lasts until the next semi permanent spell effect is cast upon the character spell
Definition: tome-of-magic.txt:44
player_lvl_adj
void player_lvl_adj(object *who, object *op)
Definition: living.cpp:1819
FLAG_WIZPASS
#define FLAG_WIZPASS
Definition: define.h:314
object_free
void object_free(object *ob, int flags)
Definition: object.cpp:1587
command_dumpabove
void command_dumpabove(object *op, const char *params)
Definition: c_wiz.cpp:2863
MAX_NAME
#define MAX_NAME
Definition: define.h:41
AssetsManager::archetypes
Archetypes * archetypes()
Definition: AssetsManager.h:44
DMFILE
#define DMFILE
Definition: config.h:369
command_insert_into
void command_insert_into(object *op, const char *params)
Definition: c_wiz.cpp:2647
FLAG_UNAGGRESSIVE
#define FLAG_UNAGGRESSIVE
Definition: define.h:272
tag_t
uint32_t tag_t
Definition: object.h:14
archetype
Definition: object.h:474
sproto.h
Settings::casting_time
uint8_t casting_time
Definition: global.h:270
MSG_SUBTYPE_NONE
#define MSG_SUBTYPE_NONE
Definition: newclient.h:409
become_follower
int become_follower(object *op, const object *new_god)
Definition: gods.cpp:413
command_goto
void command_goto(object *op, const char *params)
Definition: c_wiz.cpp:724
init_signals
void init_signals()
Definition: init.cpp:1298
SHUTDOWN_NONE
@ SHUTDOWN_NONE
Definition: commands.h:42
nlohmann::detail::void
j template void())
Definition: json.hpp:4099
object_insert_in_map_at
object * object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
Definition: object.cpp:2095
object::other_arch
struct archetype * other_arch
Definition: object.h:423
FLAG_MONSTER
#define FLAG_MONSTER
Definition: define.h:245
find_skill_by_name
object * find_skill_by_name(object *who, const char *name)
Definition: skill_util.cpp:211
MAP_WIDTH
#define MAP_WIDTH(m)
Definition: map.h:74
command_kick
void command_kick(object *op, const char *params)
Definition: c_wiz.cpp:556
command_loadtest
void command_loadtest(object *op, const char *params)
Definition: c_wiz.cpp:306
treasure.h
EXIT_X
#define EXIT_X(xyz)
Definition: define.h:441
MAX_BUF
#define MAX_BUF
Definition: define.h:35
strlcpy
size_t strlcpy(char *dst, const char *src, size_t size)
Definition: porting.cpp:222
object_new
object * object_new(void)
Definition: object.cpp:1268
create_overlay_pathname
void create_overlay_pathname(const char *name, char *buf, size_t size)
Definition: map.cpp:124
path
pluglist shows those as well as a short text describing each the list will simply appear empty The keyword for the Python plugin is Python plugout< keyword > Unloads a given identified by its _keyword_ So if you want to unload the Python you need to do plugout Python plugin< libname > Loads a given whose _filename_ is libname So in the case of you d have to do a plugin cfpython so Note that all filenames are relative to the default plugin path(SHARE/plugins). Console messages. ----------------- When Crossfire starts
monster_check_apply_all
void monster_check_apply_all(object *monster)
Definition: monster.cpp:2001
command_hide
void command_hide(object *op, const char *params)
Definition: c_wiz.cpp:389
FREE_AND_CLEAR_STR
#define FREE_AND_CLEAR_STR(xyz)
Definition: global.h:198
command_freeze
void command_freeze(object *op, const char *params)
Definition: c_wiz.cpp:745
is_valid_types_gen.found
found
Definition: is_valid_types_gen.py:39
MSG_TYPE_COMMAND_FAILURE
#define MSG_TYPE_COMMAND_FAILURE
Definition: newclient.h:520
FOR_MAP_PREPARE
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Definition: define.h:723
load_assets
void load_assets(void)
Definition: init.cpp:311
ST_PLAYING
#define ST_PLAYING
Definition: define.h:541
command_forget_spell
void command_forget_spell(object *op, const char *params)
Definition: c_wiz.cpp:2376
FLAG_REMOVED
#define FLAG_REMOVED
Definition: define.h:232
command_nowiz
void command_nowiz(object *op, const char *params)
Definition: c_wiz.cpp:2041
FLAG_WIZ
#define FLAG_WIZ
Definition: define.h:231
styles
mapstruct * styles
Definition: style.cpp:122
swap_map
int swap_map(mapstruct *map)
Definition: swap.cpp:135
command_loadplugin
void command_loadplugin(object *op, const char *params)
Definition: c_wiz.cpp:2419
llevInfo
@ llevInfo
Definition: logger.h:12
NDI_UNIQUE
#define NDI_UNIQUE
Definition: newclient.h:251
EVENT_MUZZLE
#define EVENT_MUZZLE
Definition: events.h:52
find_archetype_by_object_name
archetype * find_archetype_by_object_name(const char *name)
Definition: arch.cpp:53
FLAG_FRIENDLY
#define FLAG_FRIENDLY
Definition: define.h:246
spells.h
get_jail_exit
object * get_jail_exit(object *op)
Definition: region.cpp:253
object::name
sstring name
Definition: object.h:319
bigchest.check
check
Definition: bigchest.py:10
AssetsCollection::each
void each(std::function< void(T *)> op)
Definition: AssetsCollection.h:158
command_learn_spell_or_prayer
static void command_learn_spell_or_prayer(object *op, const char *params, int special_prayer)
Definition: c_wiz.cpp:2318
BANISHFILE
#define BANISHFILE
Definition: config.h:520
get_spell_by_name
static object * get_spell_by_name(object *op, const char *spell_name)
Definition: c_wiz.cpp:2214
Settings::create_home_portals
uint8_t create_home_portals
Definition: global.h:311
item
Definition: item.py:1
Settings::worldmapstarty
uint32_t worldmapstarty
Definition: global.h:292
reputation.victim
victim
Definition: reputation.py:14
can_follow
bool can_follow(object *op, player *other)
Definition: c_wiz.cpp:2757
is_identifiable_type
int is_identifiable_type(const object *op)
Definition: item.cpp:1328
mapstruct
Definition: map.h:314
enter_exit
void enter_exit(object *op, object *exit_ob)
Definition: server.cpp:734
object_find_by_name_global
object * object_find_by_name_global(const char *str)
Definition: object.cpp:747
check_spell_known
object * check_spell_known(object *op, const char *name)
Definition: spell_util.cpp:394
find_object_both
static object * find_object_both(const char *params)
Definition: c_wiz.cpp:403
SHUTDOWN_TIME
@ SHUTDOWN_TIME
Definition: commands.h:43
sstring
const typedef char * sstring
Definition: sstring.h:2
command_settings
void command_settings(object *op, const char *ignored)
Definition: c_wiz.cpp:2875
give.op
op
Definition: give.py:33
NDI_ALL
#define NDI_ALL
Definition: newclient.h:252
command_stats
void command_stats(object *op, const char *params)
Definition: c_wiz.cpp:1737
command_dump
void command_dump(object *op, const char *params)
Definition: c_wiz.cpp:1357
object_find_free_spot
int object_find_free_spot(const object *ob, mapstruct *m, int x, int y, int start, int stop)
Definition: object.cpp:3550
command_dmhide
void command_dmhide(object *op, const char *params)
Definition: c_wiz.cpp:2480
esrv_update_item
void esrv_update_item(int flags, object *pl, object *op)
Definition: main.cpp:359
command_unloadplugin
void command_unloadplugin(object *op, const char *params)
Definition: c_wiz.cpp:2451
rv_vector
Definition: map.h:370
MAP_SWAPPED
#define MAP_SWAPPED
Definition: map.h:128
roll-o-matic.params
params
Definition: roll-o-matic.py:193
reset_sleep
void reset_sleep(void)
Definition: time.cpp:132
EXIT_Y
#define EXIT_Y(xyz)
Definition: define.h:442
diamondslots.y
y
Definition: diamondslots.py:16
Settings::resurrection
uint8_t resurrection
Definition: global.h:266
assets.h
python_pickup.where
where
Definition: python_pickup.py:7
CLEAR_FLAG
#define CLEAR_FLAG(xyz, p)
Definition: define.h:225
player_arrest
int player_arrest(object *who)
Definition: c_wiz.cpp:789
socket_struct::faces_sent_len
size_t faces_sent_len
Definition: newserver.h:95
command_follow
void command_follow(object *op, const char *params)
Definition: c_wiz.cpp:2770
Socket_Info::allocated_sockets
int allocated_sockets
Definition: newserver.h:144
get_dm_object
static object * get_dm_object(player *pl, const char **params, int *from)
Definition: c_wiz.cpp:196
Settings::max_stat
uint8_t max_stat
Definition: global.h:324
MAP_HEIGHT
#define MAP_HEIGHT(m)
Definition: map.h:76
tick_duration
uint32_t tick_duration
Definition: time.cpp:35
NDI_DK_ORANGE
#define NDI_DK_ORANGE
Definition: newclient.h:237
get_ob_diff
void get_ob_diff(StringBuffer *sb, const object *op, const object *op2)
Definition: object.cpp:4977
find_player_partial_name
player * find_player_partial_name(const char *plname)
Definition: player.cpp:114
account_change_password
int account_change_password(const char *account_name, const char *current_password, const char *new_password)
Definition: account.cpp:628
socket_struct::faces_sent
uint8_t * faces_sent
Definition: newserver.h:96
arch_to_object
object * arch_to_object(archetype *at)
Definition: arch.cpp:229
object_give_identified_properties
void object_give_identified_properties(object *op)
Definition: item.cpp:1360
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
get_rangevector
int get_rangevector(object *op1, const object *op2, rv_vector *retval, int flags)
Definition: map.cpp:2519
player::party
partylist * party
Definition: player.h:203
checkdm
static int checkdm(object *op, const char *pl_name, const char *pl_passwd, const char *pl_host)
Definition: c_wiz.cpp:2078
MSG_TYPE_COMMAND_MAPS
#define MSG_TYPE_COMMAND_MAPS
Definition: newclient.h:509
UPD_NAME
#define UPD_NAME
Definition: newclient.h:307
command_accountpasswd
void command_accountpasswd(object *op, const char *params)
Definition: c_wiz.cpp:1613
object::randomitems
struct treasurelist * randomitems
Definition: object.h:395
Settings::datadir
const char * datadir
Definition: global.h:248
MSG_TYPE_COMMUNICATION_PARTY
#define MSG_TYPE_COMMUNICATION_PARTY
Definition: newclient.h:616
skill
skill
Definition: arch-handbook.txt:585
object_remove
void object_remove(object *op)
Definition: object.cpp:1828
try_find_archetype
archetype * try_find_archetype(const char *name)
Definition: assets.cpp:270
castle_read.playercount
int playercount
Definition: castle_read.py:62
inventory
void inventory(object *op, object *inv)
Definition: c_object.cpp:2165
do_forget_spell
void do_forget_spell(object *op, const char *spell)
Definition: apply.cpp:525
command_kick2
static void command_kick2(object *op, const char *params)
Definition: c_wiz.cpp:468
do_some_living
void do_some_living(object *op)
Definition: player.cpp:3272
now
Crossfire Protocol most of the time after the actual code was already omit certain important and possibly make life miserable any new developer or curious player should be able to find most of the relevant information here If inconsistencies are found or this documentation proves to be consider the latest server side protocol code in the public source code repository as the authoritative reference Introduction If you were ever curious enough to telnet or netcat to a Crossfire chances are you were sorely disappointed While the protocol may seem to use plain text at it actually uses a mix of ASCII and binary data This handbook attempts to document various aspects of the Crossfire protocol As consult the README file to find out how to get in touch with helpful people via mailing and more History the communications plan was set to be a text based system It was up to the server and client to parse these messages and determine what to do These messages were assumed to be line per message At a reasonably early stage of Eric Anderson wrote a then the data itself you could send many data and after the other end could decode these commands This works fairly but I think the creation of numerous sub packets has some performance hit the eutl was not especially well so writing a client for a different platform became more Eric left to work on other products shortly after writing his which didn t really leave anyone with a full understanding of the socket code I have decided to remove the eutl dependency At least one advantage is that having this network related code directly in the client and server makes error handling a bit easier cleaner Packet Format the outside packet method the byte size for the size information is not included here Eutl originally used bytes for the size to bytes seems it makes a least some sense The actual data is something of the nature of the commands listed below It is a text followed by possible other data The remaining data can be binary it is up to the client and server to decode what it sent The commands as described below is just the data portion of the packet If writing a new remember that you must take into account the size of the packet There is no termination of other than knowing how long it should be For now
Definition: protocol.txt:71
Settings::item_power_factor
float item_power_factor
Definition: global.h:303
STACK_FROM_STACK
@ STACK_FROM_STACK
Definition: c_wiz.cpp:40
Settings::no_player_stealing
uint8_t no_player_stealing
Definition: global.h:310
save_map
int save_map(mapstruct *m, int flag)
Definition: map.cpp:1394
SCROLL
@ SCROLL
Definition: object.h:226
shutdown_s::next_warn
int next_warn
Definition: commands.h:51
object::nrof
uint32_t nrof
Definition: object.h:342
command_stack_push
void command_stack_push(object *op, const char *params)
Definition: c_wiz.cpp:2508
mapstruct::next
mapstruct * next
Definition: map.h:315
assets_collect
void assets_collect(const char *datadir, int what)
Definition: assets.cpp:113
param
No space after the left no space before the right paren Comma right after the formal param
Definition: style-guide.txt:215
say.item
dictionary item
Definition: say.py:149
object::stats
living stats
Definition: object.h:378
artifact
Definition: artifact.h:14
Settings::permanent_exp_ratio
uint8_t permanent_exp_ratio
Definition: global.h:258
command_free
void command_free(object *op, const char *params)
Definition: c_wiz.cpp:1587
object::more
object * more
Definition: object.h:303
MSG_TYPE_COMMUNICATION
#define MSG_TYPE_COMMUNICATION
Definition: newclient.h:399
update_los
void update_los(object *op)
Definition: los.cpp:509
get_faces_count
size_t get_faces_count()
Definition: assets.cpp:293
freearr_x
short freearr_x[SIZEOFFREE]
Definition: object.cpp:299
StringBuffer
Definition: stringbuffer.cpp:25
TRUE
#define TRUE
Definition: compat.h:11
command_recollect
void command_recollect(object *op, const char *params)
Definition: c_wiz.cpp:1511
command_stack_pop
void command_stack_pop(object *op, const char *params)
Definition: c_wiz.cpp:2495
SPELL
@ SPELL
Definition: object.h:219
Settings::death_penalty_level
uint8_t death_penalty_level
Definition: global.h:260
altar_valkyrie.pl
pl
Definition: altar_valkyrie.py:28
if
if(!(yy_init))
Definition: loader.c:2626
find_artifactlist
artifactlist * find_artifactlist(int type)
Definition: artifact.cpp:574
MSG_TYPE_ADMIN
#define MSG_TYPE_ADMIN
Definition: newclient.h:391
rv_vector::distance
unsigned int distance
Definition: map.h:371
SPELLBOOK
@ SPELLBOOK
Definition: object.h:208
Settings::confdir
const char * confdir
Definition: global.h:247
Settings::not_permadeth
uint8_t not_permadeth
Definition: global.h:262
EVENT_KICK
#define EVENT_KICK
Definition: events.h:43
SAVE_ERROR_PLAYER
#define SAVE_ERROR_PLAYER
Definition: map.h:149
dm_stack_peek
static object * dm_stack_peek(player *pl)
Definition: c_wiz.cpp:120
altar_valkyrie.res
int res
Definition: altar_valkyrie.py:74
NDI_LT_GREEN
#define NDI_LT_GREEN
Definition: newclient.h:239
events_execute_global_event
void events_execute_global_event(int eventcode,...)
Definition: events.cpp:27
llevDebug
@ llevDebug
Definition: logger.h:13
Settings::real_wiz
uint8_t real_wiz
Definition: global.h:271
FLAG_IDENTIFIED
#define FLAG_IDENTIFIED
Definition: define.h:261
command_stack_clear
void command_stack_clear(object *op, const char *params)
Definition: c_wiz.cpp:2557
command_stack_list
void command_stack_list(object *op, const char *params)
Definition: c_wiz.cpp:2526