Crossfire Server, Trunk
knowledge.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 
58 #include "global.h"
59 
60 #include <assert.h>
61 #include <ctype.h>
62 #include <stdlib.h>
63 #include <string.h>
64 
65 #include "sproto.h"
66 #include "output_file.h"
67 
68 /* Media tags for information messages prefix. */
69 #define TAG_START "[color=#ff6611]"
70 #define TAG_END "[/color]"
71 
72 struct knowledge_player;
73 struct knowledge_type;
74 
80 typedef void (*knowledge_summary)(const char *code, StringBuffer *buf);
81 
87 typedef void (*knowledge_detail)(const char *code, StringBuffer *buf);
88 
94 typedef int (*knowledge_is_valid_item)(const char *code);
95 
104 
113 typedef StringBuffer* (*knowledge_can_use_alchemy)(sstring code, const char *item, StringBuffer *buf, int index);
114 
120 typedef const Face *(*knowledge_face)(sstring code);
121 
122 struct knowledge_item;
123 
130 
133  const char *type;
138  const char *name;
141  const char *face;
143 };
144 
145 
150 };
151 
161 };
162 
165 
166 
172 static const recipe* knowledge_alchemy_get_recipe(const char *value) {
173  const recipe *rec;
174  recipelist *rl;
175  int count, index;
176  const char *dot;
177 
178  dot = strchr(value, ':');
179  if (!dot) {
180  /* warn? */
181  return NULL;
182  }
183 
184  count = atoi(value);
185  index = atoi(dot + 1);
186  dot = strchr(dot + 1, ':');
187  if (!dot)
188  /* warn? */
189  return NULL;
190  dot++;
191 
192  rl = get_formulalist(count);
193  rec = rl->items;
194  while (rec) {
195  if (rec->index == index && strcmp(rec->title, dot) == 0)
196  return rec;
197 
198  rec = rec->next;
199  }
200 
201  return NULL;
202 }
203 
210 static void knowledge_alchemy_summary(const char *value, StringBuffer *buf) {
212  const archetype *arch;
213 
214  if (!rec)
215  /* warn? */
216  return;
217 
219  if (!arch)
220  /* not supposed to happen */
221  return;
222 
223  if (strcmp(rec->title, "NONE"))
224  stringbuffer_append_printf(buf, "%s of %s", arch->clone.name, rec->title);
225  else {
226  if (arch->clone.title != NULL) {
227  stringbuffer_append_printf(buf, "%s %s", arch->clone.name, arch->clone.title);
228  }
229  else
230  stringbuffer_append_printf(buf, "%s", arch->clone.name);
231  }
232 }
233 
240 static void knowledge_alchemy_detail(const char *value, StringBuffer *buf) {
242  const linked_char *next;
243  const archetype *arch;
244  char name[MAX_BUF];
245 
246 
247  if (!rec)
248  /* warn? */
249  return;
250 
252  if (!arch)
253  /* not supposed to happen */
254  return;
255 
256  if (strcmp(rec->title, "NONE"))
257  stringbuffer_append_printf(buf, "The %s of %s", arch->clone.name, rec->title);
258  else {
259  if (arch->clone.title != NULL) {
260  stringbuffer_append_printf(buf, "The %s %s", arch->clone.name, arch->clone.title);
261  }
262  else
263  stringbuffer_append_printf(buf, "The %s", arch->clone.name);
264  }
265 
267  if (arch)
268  query_name(&arch->clone, name, MAX_BUF);
269  else
270  snprintf(name, sizeof(name), "an unknown place");
271 
272  stringbuffer_append_printf(buf, " is made with %s at %s and uses the following ingredients:", rec->skill ? rec->skill : "an unknown skill", name);
273 
274  for (next = rec->ingred; next != NULL; next = next->next) {
275  stringbuffer_append_printf(buf, "\n - %s", next->name);
276  }
277 
278 }
279 
285 static int knowledge_alchemy_validate(const char *item) {
286  return knowledge_alchemy_get_recipe(item) != NULL;
287 }
288 
299  const linked_char *next;
300  const archetype *arch;
301  const char *name;
302 
303  if (!item)
304  return NULL;
305 
306  if (!rec)
307  /* warn? */
308  return buf;
309 
311  if (!arch)
312  /* not supposed to happen */
313  return buf;
314 
315  for (next = rec->ingred; next != NULL; next = next->next) {
316  name = next->name;
317  while ((*name) != '\0' && (isdigit(*name) || (*name) == ' '))
318  name++;
319 
320  if (strcmp(item, name) == 0) {
321  if (buf == NULL) {
322  buf = stringbuffer_new();
323  stringbuffer_append_string(buf, "It can be used in the following recipes: ");
324  } else
326 
327  if (strcmp(rec->title, "NONE"))
328  stringbuffer_append_printf(buf, "%s of %s", arch->clone.name, rec->title);
329  else {
330  if (arch->clone.title != NULL) {
331  stringbuffer_append_printf(buf, "%s %s", arch->clone.name, arch->clone.title);
332  }
333  else
334  stringbuffer_append_printf(buf, "%s", arch->clone.name);
335  }
337 
338  break;
339  }
340  }
341 
342  return buf;
343 }
344 
351  const recipe *rp = knowledge_alchemy_get_recipe(item->item);
352  object *cauldron = NULL, *inv;
353  object *ingredients[50];
354  int index, x, y;
355  uint32_t count, counts[50];
356  char name[MAX_BUF];
357  const char *ingname;
358  linked_char *ing;
359  tag_t cauldron_tag;
360  mapstruct *map;
361 
362  if (!rp) {
363  LOG(llevError, "knowledge: couldn't find recipe for %s", item->item);
364  return;
365  }
366 
367  if (rp->ingred_count > 50) {
368  LOG(llevError, "knowledge: recipe %s has more than 50 ingredients!", item->item);
369  draw_ext_info(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, "This recipe is too complicated.");
370  return;
371  }
372 
373  /* first, check for a cauldron */
374  for (cauldron = pl->ob->below; cauldron; cauldron = cauldron->below) {
375  if (strcmp(rp->cauldron, cauldron->arch->name) == 0)
376  break;
377  }
378 
379  if (cauldron == NULL) {
380  draw_ext_info_format(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, "You are not on a %s", rp->cauldron);
381  return;
382  }
383 
384  cauldron_tag = cauldron->count;
385 
386  /* find ingredients in player's inventory */
387  for (index = 0; index < 50; index++) {
388  ingredients[index] = NULL;
389  }
390  for (inv = pl->ob->inv; inv != NULL; inv = inv->below) {
391 
393  continue;
394 
395  if (inv->title == NULL)
396  safe_strncpy(name, inv->name, sizeof(name));
397  else
398  snprintf(name, sizeof(name), "%s %s", inv->name, inv->title);
399 
400  index = 0;
401  for (ing = rp->ingred; ing != NULL; ing = ing->next) {
402 
403  if (ingredients[index] != NULL) {
404  index++;
405  continue;
406  }
407 
408  ingname = ing->name;
409  count = 0;
410  while (isdigit(*ingname)) {
411  count = 10 * count + (*ingname - '0');
412  ingname++;
413  }
414  if (count == 0)
415  count = 1;
416  while (*ingname == ' ')
417  ingname++;
418 
419  if (strcmp(name, ingname) == 0 && ((inv->nrof == 0 && count == 1) || (inv->nrof >= count))) {
420  ingredients[index] = inv;
421  // If nrof is 0, we want to keep a count of 0 so put_object_in_sack() later doesn't call
422  // object_split() which would destroy tmp and mess up our tags.
423  counts[index] = inv->nrof == 0 ? 0 : count;
424  break;
425  }
426 
427  index++;
428  }
429  }
430 
431  index = 0;
432  for (ing = rp->ingred; ing != NULL; ing = ing->next) {
433  if (ingredients[index] == NULL) {
434  draw_ext_info_format(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, "You don't have %s.", ing->name);
435  return;
436  }
437 
438  index++;
439  }
440 
441  /* ensure cauldron is applied */
442  if (pl->ob->container != cauldron) {
444  if (pl->ob->container != cauldron) {
445  draw_ext_info_format(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, "Couldn't activate the %s.", rp->cauldron);
446  return;
447  }
448  }
449 
450  /* ensure cauldron is empty */
451  while (cauldron->inv != NULL) {
452  inv = cauldron->inv;
453  command_take(pl->ob, "");
454  if (cauldron->inv == inv) {
455  draw_ext_info_format(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, "Couldn't empty the %s", rp->cauldron);
456  return;
457  }
458  }
459 
460  /* drop ingredients */
461  for (index = 0; index < rp->ingred_count; index++) {
462  tag_t tag = ingredients[index]->count;
463  count = ingredients[index]->nrof;
464  put_object_in_sack(pl->ob, cauldron, ingredients[index], counts[index]);
465  if (object_was_destroyed(ingredients[index], tag)) {
466  draw_ext_info(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, "Hum, some item disappeared, stopping the attempt.");
467  return;
468 
469  }
470  if (count == ingredients[index]->nrof && ingredients[index]->env == pl->ob) {
471  draw_ext_info(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, "Hum, couldn't drop some items, stopping the attempt.");
472  return;
473  }
474  }
475 
476  map = pl->ob->map;
477  x = pl->ob->x;
478  y = pl->ob->y;
479 
480  /* do alchemy */
481  use_alchemy(pl->ob);
482 
483  /* don't forget to slow the player: 1 for alchemy itself, 1 for each ingredient put,
484  * ingredients taken are handled by command_take() */
485  pl->ob->speed_left -= 1.0 * (rp->ingred_count + 1);
486 
487  /* safety: ensure cauldron is still there, and player is still above */
488  if (object_was_destroyed(cauldron, cauldron_tag) || map != pl->ob->map || x != pl->ob->x || y != pl->ob->y) {
489  return;
490  }
491 
492  /* get back the result */
493  while (cauldron->inv) {
494  /* Examining may lead to identifying part of items and thus introducing
495  * extra items in the cauldron. Therefore we'll set inv only after examining,
496  * even if that means that potentially the player will examine twice some items. */
497  examine(pl->ob, cauldron->inv);
498  inv = cauldron->inv;
499  command_take(pl->ob, "");
500  pl->ob->speed_left -= 1.0;
501  if (inv == cauldron->inv)
502  break;
503  }
504 }
505 
513 
514  if (!rp) {
515  LOG(llevError, "knowledge: couldn't find recipe for %s", code);
516  return NULL;
517  }
518 
519  return recipe_get_face(rp);
520 }
521 
529 static int knowledge_known(const knowledge_player *current, const char *item, const knowledge_type *kt) {
530  int i;
531  for (i = 0; i < current->item_count; i++) {
532  if (strcmp(kt->type, current->items[i]->handler->type) == 0 && strcmp(item, current->items[i]->item) == 0) {
533  /* already known, bailout */
534  return 1;
535  }
536  }
537  return 0;
538 }
539 
547 static int knowledge_add(knowledge_player *current, const char *item, const knowledge_type *kt) {
549 
550  if (knowledge_known(current, item, kt)) {
551  return 0;
552  }
553 
554  /* keep the knowledge */
559  check = static_cast<knowledge_item *>(malloc(sizeof(knowledge_item)));
560  check->item = add_string(item);
561  check->handler = kt;
562  if (current->item_count >= current->item_allocated) {
563  current->item_allocated += 10;
564  current->items = static_cast<knowledge_item **>(realloc(current->items, current->item_allocated * sizeof(knowledge_item*)));
565  }
566  current->items[current->item_count] = check;
567  current->item_count++;
568 
569  return 1;
570 }
571 
578 static void knowledge_monster_summary(const char *item, StringBuffer *buf) {
580  if (!monster)
581  return;
582 
583  stringbuffer_append_printf(buf, "%s", monster->clone.name);
584 }
585 
592 static void knowledge_monster_detail(const char *item, StringBuffer *buf) {
594 
595  if (!monster)
596  return;
597 
598  stringbuffer_append_printf(buf, " *** %s ***\n", monster->clone.name);
599  describe_item(&monster->clone, NULL, 1, buf);
600 }
601 
607 static int knowledge_monster_validate(const char *item) {
609  if (monster == NULL || monster->clone.type != 0 || monster->head || object_get_value(&monster->clone, MONSTER_EXCLUDE_FROM_READABLE_KEY) != NULL)
610  return 0;
611  return 1;
612 }
613 
621 static int knowledge_monster_add(struct knowledge_player *current, const char *item, const struct knowledge_type *type) {
622  char *dup = strdup_local(item);
623  char *pos, *first = dup;
624  int added = 0;
625 
626  while (first) {
627  pos = strchr(first, ':');
628  if (pos)
629  *pos = '\0';
630  added += knowledge_add(current, first, type);
631  first = pos ? pos + 1 : NULL;
632  }
633 
634  free(dup);
635  return added;
636 }
637 
645 
646  if (!monster || monster->clone.face == blank_face || monster->clone.face == NULL)
647  return NULL;
648 
649  return monster->clone.face;
650 }
651 
658 static void knowledge_god_summary(const char *item, StringBuffer *buf) {
659  char *dup = strdup_local(item), *pos = strchr(dup, ':');
660 
661  if (pos)
662  *pos = '\0';
663 
664  stringbuffer_append_printf(buf, "%s [god]", dup);
665  free(dup);
666 }
667 
674 static void knowledge_god_detail(const char *item, StringBuffer *buf) {
675  char *dup = strdup_local(item), *pos = strchr(dup, ':');
676  const archetype *god;
677  int what;
678 
679  if (!pos) {
680  LOG(llevError, "knowledge_god_detail: invalid god item %s\n", item);
681  free(dup);
682  return;
683  }
684 
685  *pos = '\0';
686  what = atoi(pos + 1);
688  free(dup);
689 
690  if (!god) {
691  LOG(llevError, "knowledge_god_detail: couldn't find god %s?\n", item);
692  return;
693  }
694 
695  describe_god(&god->clone, what, buf, 0);
696 }
697 
703 static int knowledge_god_validate(const char *item) {
704  char *dup = strdup_local(item), *pos = strchr(dup, ':');
705  int valid;
706 
707  if (!pos) {
708  LOG(llevError, "knowledge_god_validate: invalid god item %s\n", item);
709  free(dup);
710  return 0;
711  }
712  *pos = '\0';
713  valid = find_archetype_by_object_name(dup) != NULL;
714  free(dup);
715  return valid;
716 }
717 
725 static int knowledge_god_add(struct knowledge_player *current, const char *item, const struct knowledge_type *type) {
726  char *dup = strdup_local(item), *pos = const_cast<char *>(strchr(dup, ':'));
727  StringBuffer *buf;
728  int what, i;
730 
731  if (!pos) {
732  LOG(llevError, "knowledge_god_add: invalid god item %s\n", item);
733  free(dup);
734  return 0;
735  }
736 
737  *pos = '\0';
738  what = atoi(pos + 1);
739 
740  for (i = 0; i < current->item_count; i++) {
741  check = current->items[i];
742  if (check->handler != type)
743  /* Only consider our own type. */
744  continue;
745  if (strncmp(check->item, dup, strlen(dup)) == 0) {
746  /* Already known, update information. */
747  int known, result;
748  pos = const_cast<char *>(strchr(check->item, ':'));
749  known = atoi(pos + 1);
750  result = known | what;
751  buf = stringbuffer_new();
752  stringbuffer_append_printf(buf, "%s:%d", dup, result);
753  free_string(check->item);
755  free(dup);
756  return (result != known);
757  }
758  }
759 
760  free(dup);
761 
762  /* Not known, so just add it regularly. */
763  return knowledge_add(current, item, type);
764 }
765 
772  char buf[MAX_BUF];
773  size_t letter;
774  const archetype *altar_arch;
775 
776  snprintf(buf, MAX_BUF, "altar_");
777  letter = strlen(buf);
778  strncpy(buf+letter, code, MAX_BUF-letter);
779  for (; letter < strlen(buf); letter++) {
780  if (buf[letter] == ':') {
781  buf[letter] = '\0';
782  break;
783  }
784  buf[letter] = tolower(buf[letter]);
785  }
786  altar_arch = try_find_archetype(buf);
787  if (altar_arch == NULL)
788  return NULL;
789 
790  return altar_arch->clone.face;
791 }
792 
799 static void knowledge_message_summary(const char *value, StringBuffer *buf) {
801 
802  if (!msg)
803  /* warn? */
804  return;
805 
807 }
808 
815 static void knowledge_message_detail(const char *value, StringBuffer *buf) {
817 
818  if (!msg)
819  /* warn? */
820  return;
821 
823 }
824 
830 static int knowledge_message_validate(const char *item) {
831  return get_message_from_identifier(item) != NULL;
832 }
833 
841 
842  if (!msg)
843  /* warn? */
844  return NULL;
845 
846  return get_message_face(msg);
847 }
848 
850 static const knowledge_type knowledges[] = {
852  { "monster", knowledge_monster_summary, knowledge_monster_detail, knowledge_monster_validate, knowledge_monster_add, "monsters", NULL, NULL, "knowledge_monsters.111", knowledge_monster_face },
853  { "god", knowledge_god_summary, knowledge_god_detail, knowledge_god_validate, knowledge_god_add, "gods", NULL, NULL, "knowledge_gods.111", knowledge_god_face },
854  { "message", knowledge_message_summary, knowledge_message_detail, knowledge_message_validate, knowledge_add, "messages", NULL, NULL, "knowledge_messages.111", knowledge_message_face },
855  { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
856 };
857 
858 
864 static const knowledge_type *knowledge_find(const char *type) {
865  int i = 0;
866  while (knowledges[i].type != NULL) {
867  if (strcmp(knowledges[i].type, type) == 0)
868  return &knowledges[i];
869  i++;
870  }
871 
872  return NULL;
873 }
874 
880  FILE *file;
881  OutputFile of;
882  char fname[MAX_BUF];
883  const knowledge_item *item;
884  int i;
885 
886  snprintf(fname, sizeof(fname), "%s/%s/%s/%s.knowledge", settings.localdir, settings.playerdir, kp->player_name, kp->player_name);
887 
888  file = of_open(&of, fname);
889  if (!file) {
890  draw_ext_info(NDI_UNIQUE | NDI_ALL_DMS, 0, NULL, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_LOADSAVE, "File write error on server!");
891  return;
892  }
893 
894  for (i = 0; i < kp->item_count; i++) {
895  item = kp->items[i];
896  fprintf(file, "%s:%s\n", item->handler->type, item->item);
897  }
898 
899  if (!of_close(&of)) {
900  draw_ext_info(NDI_UNIQUE | NDI_ALL_DMS, 0, NULL, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_LOADSAVE, "File write error on server!");
901  return;
902  }
904 }
905 
911  FILE *file;
912  char final[MAX_BUF], read[MAX_BUF], *dot;
914  const knowledge_type *type;
915 
916  snprintf(final, sizeof(final), "%s/%s/%s/%s.knowledge", settings.localdir, settings.playerdir, kp->player_name, kp->player_name);
917 
918  file = fopen(final, "r");
919  if (!file) {
920  /* no knowledge yet, no big deal */
921  return;
922  }
923 
924  while (fgets(read, sizeof(read), file) != NULL) {
925  if (strlen(read) > 0)
926  read[strlen(read) - 1] = '\0';
927 
928  dot = strchr(read, ':');
929  if (!dot) {
930  LOG(llevError, "knowledge: invalid line in file %s\n", final);
931  continue;
932  }
933 
934  *dot = '\0';
935 
936  type = knowledge_find(read);
937  if (!type) {
938  LOG(llevError, "knowledge: invalid type %s in file %s\n", read, final);
939  continue;
940  }
941  if (!type->validate(dot + 1)) {
942  LOG(llevDebug, "knowledge: ignoring now invalid %s in file %s\n", read, final);
943  continue;
944  }
945 
946  item = static_cast<knowledge_item *>(malloc(sizeof(knowledge_item)));
947  item->item = add_string(dot + 1);
948  item->handler = type;
949  if (kp->item_count == kp->item_allocated) {
950  kp->item_allocated += 10;
951  kp->items = static_cast<knowledge_item **>(realloc(kp->items, kp->item_allocated * sizeof(knowledge_item*)));
952  }
953  kp->items[kp->item_count] = item;
954  kp->item_count++;
955  }
956  fclose(file);
957 }
958 
967 
968  while (cur) {
969  if (cur->player_name == pl->ob->name)
970  return cur;
971  cur = cur->next;
972  }
973 
974  cur = static_cast<knowledge_player *>(calloc(1, sizeof(knowledge_player)));
975  if (!cur)
977  cur->player_name = add_refcount(pl->ob->name);
978  cur->next = knowledge_global;
979  knowledge_global = cur;
980  /* read knowledge for this player */
982  if (pl->socket->notifications < 2)
983  cur->sent_up_to = -1;
984  return cur;
985 }
986 
993 void knowledge_give(player *pl, const char *marker, const object *book) {
994  char *copy, *code, *dot;
995  const knowledge_type *type;
996  int none, added = 0;
998 
999  /* process marker, find if already known */
1000  dot = const_cast<char *>(strchr(marker, ':'));
1001  if (dot == NULL)
1002  return;
1003 
1004  copy = strdup(marker);
1005  if (!copy)
1007 
1008  dot = const_cast<char *>(strchr(copy, ':'));
1009  *dot = '\0';
1010  dot++;
1011 
1012  type = knowledge_find(copy);
1013  if (!type) {
1014  LOG(llevError, "knowledge: invalid marker type %s in %s\n", copy, book == NULL ? "(null)" : book->name);
1015  free(copy);
1016  return;
1017  }
1018 
1019  none = (current->items == NULL);
1020 
1021  code = dot;
1022  while (code && code[0] != '\0') {
1023  dot = strchr(code, '/');
1024  if (dot) {
1025  *dot = '\0';
1026  dot++;
1027  }
1028  if (type->validate(code)) {
1029  added += type->add(current, code, type);
1030  }
1031  code = dot;
1032  }
1033 
1034  free(copy);
1035 
1036  if (added) {
1037  draw_ext_info_format(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_MISC, MSG_TYPE_CLIENT_NOTICE, TAG_START "%s" TAG_END, "You keep that in mind for future reference.");
1038  if (none) {
1039  /* first information ever written down, be nice and give hint to recover it. */
1040  draw_ext_info_format(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_MISC, MSG_TYPE_CLIENT_NOTICE, TAG_START "%s" TAG_END, "Use the 'knowledge' command to see what you keep in mind (this message will not appear anymore).");
1041  }
1042  }
1043 
1044  if (pl->has_directory)
1046 }
1047 
1053 void knowledge_read(player *pl, object *book) {
1054  sstring marker = object_get_value(book, "knowledge_marker");
1055  if (marker != NULL)
1056  knowledge_give(pl, marker, book);
1057 }
1058 
1065 static void knowledge_do_display(object *pl, const knowledge_type *show_only, const char *search) {
1066  knowledge_player *kp;
1068  int header = 0, show, i;
1069  StringBuffer *summary;
1070  char *final;
1071 
1072  assert(search == NULL || search[0] != '\0');
1073 
1074  kp = knowledge_get_or_create(pl->contr);
1075  for (i = 0; i < kp->item_count; i++) {
1076  item = kp->items[i];
1077  show = 1;
1078 
1079  summary = stringbuffer_new();
1080  item->handler->summary(item->item, summary);
1081  final = stringbuffer_finish(summary);
1082 
1083  if (show_only != NULL && item->handler != show_only) {
1084  show = 0;
1085  }
1086  if (search != NULL && search[0] != '\0') {
1087  if (strstr(final, search) == NULL) {
1088  char *fd;
1089  StringBuffer *detail = stringbuffer_new();
1090  item->handler->detail(item->item, detail);
1091  fd = stringbuffer_finish(detail);
1092  if (strstr(fd, search) == NULL)
1093  show = 0;
1094  free(fd);
1095  }
1096  }
1097 
1098  if (show == 1) {
1099  if (header == 0) {
1100  if (search != NULL)
1101  draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_MISC, MSG_TYPE_CLIENT_NOTICE, "You have knowledge of the following %s concerning '%s':", show_only == NULL ? "things" : show_only->type, search);
1102  else if (show_only != NULL)
1103  draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_MISC, MSG_TYPE_CLIENT_NOTICE, "You have knowledge of those %s:", show_only->name);
1104  else
1105  draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_MISC, MSG_TYPE_CLIENT_NOTICE, "You have knowledge of:");
1106  header = 1;
1107  }
1108 
1109  draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_MISC, MSG_TYPE_CLIENT_NOTICE, "(%3d) %s", i + 1, final);
1110  }
1111 
1112  free(final);
1113  }
1114 
1115  if (header == 0) {
1116  if (search != NULL)
1117  draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_MISC, MSG_TYPE_CLIENT_NOTICE, "You don't know yet any relevant information about '%s'.", search);
1118  else if (show_only != NULL)
1119  draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_MISC, MSG_TYPE_CLIENT_NOTICE, "You don't know yet any relevant information about %s.", show_only->name);
1120  else
1121  draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_MISC, MSG_TYPE_CLIENT_NOTICE, "You don't know yet any relevant information.");
1122  }
1123 }
1124 
1130 static void knowledge_display(object *pl, const char *params) {
1131  const knowledge_type *show_only = NULL;
1132 
1133  if (params && params[0] == ' ') {
1134  const char *type = params + 1;
1135  int idx = 0;
1136  for (; knowledges[idx].type != NULL; idx++) {
1137  if (strcmp(knowledges[idx].name, type) == 0) {
1138  show_only = &knowledges[idx];
1139  break;
1140  }
1141  }
1142 
1143  if (show_only == NULL) {
1144  draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_MISC, MSG_TYPE_CLIENT_NOTICE, "Invalid type, valid types are:");
1145  for (idx = 0; knowledges[idx].type != NULL; idx++) {
1147  }
1148  return;
1149  }
1150  }
1151 
1152  knowledge_do_display(pl, show_only, NULL);
1153 }
1154 
1160 static void knowledge_show(object *pl, const char *params) {
1161  knowledge_player *kp;
1163  int count = atoi(params) - 1;
1164  StringBuffer *buf;
1165  char *final;
1166 
1167  kp = knowledge_get_or_create(pl->contr);
1168  if (count < 0 || count >= kp->item_count) {
1169  draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, "Invalid knowledge number");
1170  return;
1171  }
1172 
1173  item = kp->items[count];
1174  buf = stringbuffer_new();
1175  item->handler->detail(item->item, buf);
1176  final = stringbuffer_finish(buf);
1178  free(final);
1179 }
1180 
1186 static void knowledge_do_attempt(object *pl, const char *params) {
1187  knowledge_player *kp;
1189  int count = atoi(params) - 1;
1190 
1191  kp = knowledge_get_or_create(pl->contr);
1192  if (count < 0 || count >= kp->item_count) {
1193  draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, "Invalid knowledge number");
1194  return;
1195  }
1196 
1197  item = kp->items[count];
1198  if (item->handler->attempt_alchemy == NULL) {
1199  draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, "You can't do anything with that knowledge.");
1200  } else {
1201  item->handler->attempt_alchemy(pl->contr, item);
1202  }
1203 }
1204 
1210 void command_knowledge(object *pl, const char *params) {
1211 
1212  if (!pl->contr) {
1213  LOG(llevError, "command_knowledge: called for %s not a player!\n", pl->name);
1214  return;
1215  }
1216 
1217  if (!params || *params == '\0') {
1218  command_help(pl, "knowledge");
1219  return;
1220  }
1221 
1222  if (strncmp(params, "list", 4) == 0) {
1223  knowledge_display(pl, params + 4);
1224  return;
1225  }
1226 
1227  if (strncmp(params, "search ", 7) == 0) {
1228  knowledge_do_display(pl, NULL, params + 7);
1229  return;
1230  }
1231 
1232  if (strncmp(params, "show ", 5) == 0) {
1233  knowledge_show(pl, params + 5);
1234  return;
1235  }
1236 
1237  if (strncmp(params, "attempt ", 8) == 0) {
1239  return;
1240  }
1241 
1242  command_help(pl, "knowledge");
1243 }
1244 
1251  int i;
1252 
1253  for (i = 0; i < kp->item_count; i++) {
1254  item = kp->items[i];
1255  free_string(item->item);
1256  free(item);
1257  }
1258  free(kp->items);
1259  kp->items = NULL;
1260  kp->item_count = 0;
1261  kp->item_allocated = 0;
1262 }
1263 
1270  free_string(kp->player_name);
1271  free(kp);
1272 }
1273 
1277 void free_knowledge(void) {
1278  knowledge_player *kp, *next;
1279 
1280  kp = knowledge_global;
1281  while (kp) {
1282  next = kp->next;
1284  kp = next;
1285  }
1286  knowledge_global = NULL;
1287 }
1288 
1295 int knowledge_player_knows(const player *pl, const char *knowledge) {
1296  const knowledge_type *type;
1297  char copy[MAX_BUF], *pos;
1298  const knowledge_player *current;
1299 
1300  if (strlen(knowledge) >= MAX_BUF - 1) {
1301  LOG(llevError, "knowledge_player_knows: too long knowledge %s\n", knowledge);
1302  return 0;
1303  }
1304 
1305  strlcpy(copy, knowledge, sizeof(copy));
1306  pos = strchr(copy, ':');
1307  if (pos == NULL) {
1308  LOG(llevError, "knowledge_player_knows: invalid knowledge item %s\n", knowledge);
1309  return 0;
1310  }
1311 
1312  *pos = '\0';
1313  pos++;
1314 
1315  type = knowledge_find(copy);
1316  if (type == NULL) {
1317  LOG(llevError, "knowledge_player_knows: invalid knowledge type %s\n", knowledge);
1318  return 0;
1319  }
1320 
1322 
1323  return knowledge_known(current, pos, type);
1324 }
1325 
1331 void knowledge_item_can_be_used_alchemy(object *op, const object *item) {
1332  knowledge_player *cur;
1333  knowledge_item *ki;
1334  char item_name[MAX_BUF], *result;
1335  const char *name;
1336  StringBuffer *buf = NULL;
1337  int i;
1338 
1339  if (op->type != PLAYER || op->contr == NULL)
1340  return;
1341 
1342  cur = knowledge_get_or_create(op->contr);
1343 
1344  if (item->title != NULL) {
1345  snprintf(item_name, sizeof(item_name), "%s %s", item->name, item->title);
1346  name = item_name;
1347  } else
1348  name = item->name;
1349 
1350  for (i = 0; i < cur->item_count; i++) {
1351  ki = cur->items[i];
1352  if (ki->handler->use_alchemy != NULL) {
1353  buf = ki->handler->use_alchemy(ki->item, name, buf, i + 1);
1354  }
1355  }
1356 
1357  if (buf == NULL)
1358  return;
1359 
1363  result);
1364  free(result);
1365 }
1366 
1372  int i;
1373  const Face *face;
1374  SockList sl;
1375 
1376  face = try_find_face("knowledge_generic.111", NULL);
1377  if (face != NULL && (!(ns->faces_sent[face->number] & NS_FACESENT_FACE)))
1378  esrv_send_face(ns, face, 0);
1379 
1380  SockList_Init(&sl);
1381  SockList_AddString(&sl, "replyinfo knowledge_info\n");
1382  SockList_AddPrintf(&sl, "::%u:0\n", face ? face->number : 0);
1383 
1384  for (i = 0; knowledges[i].type != NULL; i++) {
1385  face = try_find_face(knowledges[i].face, NULL);
1386  if (face != NULL && (!(ns->faces_sent[face->number] & NS_FACESENT_FACE)))
1387  esrv_send_face(ns, face, 0);
1388 
1389  SockList_AddPrintf(&sl, "%s:%s:%u:%s\n", knowledges[i].type, knowledges[i].name, face ? face->number : 0, knowledges[i].attempt_alchemy != NULL ? "1" : "0");
1390  }
1391 
1392  Send_With_Handling(ns, &sl);
1393  SockList_Term(&sl);
1394 }
1395 
1401  knowledge_player *kp;
1402 
1403  if (pl->socket->notifications < 2)
1404  return;
1405 
1406  /* merely loading the knowledge will mark it as to be sent through knowledge_process_incremental(),
1407  * but we need to reset the sent_up_to field if eg the player was the last one to leave
1408  * then joins again - no knowledge processing is done at that point. */
1410  kp->sent_up_to = 0;
1411 }
1412 
1422 
1423  while (cur) {
1424  if (cur->player_name == pl->ob->name) {
1426  }
1427  cur = cur->next;
1428  }
1429 
1430 }
1431 
1437  int i, last;
1438  SockList sl;
1439  size_t size;
1440  const knowledge_item *item;
1441  StringBuffer *buf;
1442  char *title;
1443  const Face *face;
1444  knowledge_player *cur = knowledge_global, *prev = NULL;
1445  player *pl;
1446 
1447  while (cur) {
1448 
1449  for (pl = first_player; pl != NULL; pl = pl->next) {
1450  if (pl->ob->name == cur->player_name) {
1451  break;
1452  }
1453  }
1454 
1455  /* player left, remove knowledge */
1456  if (pl == NULL) {
1457  if (prev == NULL) {
1458  knowledge_global = cur->next;
1459  } else {
1460  prev->next = cur->next;
1461  }
1462 
1463  free_knowledge_player(cur);
1464 
1465  /* wait until next tick to do something else */
1466  return;
1467  }
1468 
1469  if (cur->sent_up_to == -1 || cur->sent_up_to == cur->item_count) {
1470  prev = cur;
1471  cur = cur->next;
1472  continue;
1473  }
1474 
1475  last = MIN(cur->sent_up_to + 50, cur->item_count);
1476  SockList_Init(&sl);
1477  SockList_AddString(&sl, "addknowledge ");
1478  for (i = cur->sent_up_to; i < last; i++) {
1479  item = cur->items[i];
1480 
1481  buf = stringbuffer_new();
1482  item->handler->summary(item->item, buf);
1484 
1485  face = NULL;
1486  if (item->handler->item_face != NULL)
1487  face = item->handler->item_face(item->item);
1488 
1489  if (face == NULL)
1490  face = try_find_face(item->handler->face, NULL);
1491 
1492  size = 4 + (2 + strlen(item->handler->type)) + (2 + strlen(title)) + 4;
1493 
1494  if (SockList_Avail(&sl) < size) {
1495  Send_With_Handling(pl->socket, &sl);
1496  SockList_Reset(&sl);
1497  SockList_AddString(&sl, "addknowledge ");
1498  }
1499 
1500  SockList_AddInt(&sl, i + 1);
1501  SockList_AddLen16Data(&sl, item->handler->type, strlen(item->handler->type));
1502  if (face != NULL && !(pl->socket->faces_sent[face->number]&NS_FACESENT_FACE))
1503  esrv_send_face(pl->socket, face, 0);
1504  SockList_AddLen16Data(&sl, title, strlen(title));
1505  SockList_AddInt(&sl, face ? face->number : 0);
1506 
1507  free(title);
1508  }
1509 
1510  cur->sent_up_to = last;
1511 
1512  Send_With_Handling(pl->socket, &sl);
1513  SockList_Term(&sl);
1514 
1515  /* don't send more this tick */
1516  break;
1517  }
1518 }
1519 
1525 void knowledge_add_probe_monster(object *op, object *mon) {
1526  StringBuffer *buf = NULL;
1527  char *result;
1528 
1529  if (op->contr == NULL)
1530  return;
1531 
1532  buf = stringbuffer_new();
1533  stringbuffer_append_printf(buf, " *** %s ***\n", mon->name);
1534  describe_item(mon, NULL, 1, buf);
1537  free(result);
1538 
1539  /*
1540  * TODO: Add to player's knowledge. This is disabled for now because the
1541  * monster being probed could be custom, but when the player goes to query
1542  * their knowledge they will only get information about the monster's
1543  * archetype.
1544  knowledge_player *kp;
1545  kp = knowledge_get_or_create(op->contr);
1546  knowledge_add(kp, mon->name, &knowledges[1]);
1547  */
1548 }
object_was_destroyed
#define object_was_destroyed(op, old_tag)
Definition: object.h:70
knowledge_alchemy_attempt
static void knowledge_alchemy_attempt(player *pl, const knowledge_item *item)
Definition: knowledge.cpp:350
knowledge_type::name
const char * name
Definition: knowledge.cpp:138
give.next
def next
Definition: give.py:44
PLAYER
@ PLAYER
Definition: object.h:112
output_file.h
SockList_AddInt
void SockList_AddInt(SockList *sl, uint32_t data)
Definition: lowlevel.cpp:124
global.h
knowledge_send_info
void knowledge_send_info(socket_struct *ns)
Definition: knowledge.cpp:1371
NS_FACESENT_FACE
#define NS_FACESENT_FACE
Definition: newserver.h:137
knowledge_type
Definition: knowledge.cpp:132
first_player
player * first_player
Definition: init.cpp:106
settings
struct Settings settings
Definition: init.cpp:139
knowledge_monster_add
static int knowledge_monster_add(struct knowledge_player *current, const char *item, const struct knowledge_type *type)
Definition: knowledge.cpp:621
safe_strncpy
#define safe_strncpy
Definition: compat.h:27
get_formulalist
recipelist * get_formulalist(int i)
Definition: recipe.cpp:98
llevError
@ llevError
Definition: logger.h:11
LOG
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.cpp:51
of_close
int of_close(OutputFile *of)
Definition: output_file.cpp:61
use_alchemy
int use_alchemy(object *op)
Definition: alchemy.cpp:1057
MONSTER_EXCLUDE_FROM_READABLE_KEY
#define MONSTER_EXCLUDE_FROM_READABLE_KEY
Definition: object.h:587
TAG_END
#define TAG_END
Definition: knowledge.cpp:70
knowledge_god_validate
static int knowledge_god_validate(const char *item)
Definition: knowledge.cpp:703
of_open
FILE * of_open(OutputFile *of, const char *fname)
Definition: output_file.cpp:30
player
Definition: player.h:105
strdup_local
#define strdup_local
Definition: compat.h:29
object::inv
object * inv
Definition: object.h:298
diamondslots.x
x
Definition: diamondslots.py:15
FLAG_STARTEQUIP
#define FLAG_STARTEQUIP
Definition: define.h:268
CFweardisguise.tag
tag
Definition: CFweardisguise.py:25
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
recipe::arch_names
size_t arch_names
Definition: recipe.h:12
free_knowledge
void free_knowledge(void)
Definition: knowledge.cpp:1277
archininventory.arch
arch
DIALOGCHECK MINARGS 1 MAXARGS 1
Definition: archininventory.py:16
knowledge_add_probe_monster
void knowledge_add_probe_monster(object *op, object *mon)
Definition: knowledge.cpp:1525
socket_struct
Definition: newserver.h:89
knowledge_alchemy_can_use_item
static StringBuffer * knowledge_alchemy_can_use_item(sstring code, const char *item, StringBuffer *buf, int index)
Definition: knowledge.cpp:297
stringbuffer_append_printf
void stringbuffer_append_printf(StringBuffer *sb, const char *format,...)
Definition: stringbuffer.cpp:138
knowledge_god_add
static int knowledge_god_add(struct knowledge_player *current, const char *item, const struct knowledge_type *type)
Definition: knowledge.cpp:725
object::arch
struct archetype * arch
Definition: object.h:422
stringbuffer_new
StringBuffer * stringbuffer_new(void)
Definition: stringbuffer.cpp:57
SockList_AddString
void SockList_AddString(SockList *sl, const char *data)
Definition: lowlevel.cpp:154
knowledge_player::item_count
int item_count
Definition: knowledge.cpp:156
knowledge_display
static void knowledge_display(object *pl, const char *params)
Definition: knowledge.cpp:1130
knowledge_face
const typedef Face *(* knowledge_face)(sstring code)
Definition: knowledge.cpp:120
knowledge_type::item_face
knowledge_face item_face
Definition: knowledge.cpp:142
Settings::localdir
const char * localdir
Definition: global.h:249
knowledge_type::attempt_alchemy
knowledge_attempt attempt_alchemy
Definition: knowledge.cpp:140
commongive.inv
inv
Definition: commongive.py:29
recipelist::items
recipe * items
Definition: recipe.h:40
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
giveknowledge.knowledge
knowledge
DIALOGCHECK MINARGS 1 MAXARGS 1
Definition: giveknowledge.py:15
mad_mage_user.file
file
Definition: mad_mage_user.py:15
mon
object * mon
Definition: comet_perf.cpp:75
MIN
#define MIN(x, y)
Definition: compat.h:21
NDI_ALL_DMS
#define NDI_ALL_DMS
Definition: newclient.h:253
knowledge_is_valid_item
int(* knowledge_is_valid_item)(const char *code)
Definition: knowledge.cpp:94
object::count
tag_t count
Definition: object.h:307
MSG_TYPE_COMMAND_EXAMINE
#define MSG_TYPE_COMMAND_EXAMINE
Definition: newclient.h:521
tolower
#define tolower(C)
Definition: c_new.cpp:30
knowledge_type::face
const char * face
Definition: knowledge.cpp:141
recipe::arch_name
char ** arch_name
Definition: recipe.h:13
blank_face
const Face * blank_face
Definition: image.cpp:36
monster
the faster the spell may be cast there are several other common only the caster may be affected by the spell The most common spell range is that of touch This denotes that the caster much touch the recipient of the spell in order to release the spell monster
Definition: spell-info.txt:45
knowledge_alchemy_detail
static void knowledge_alchemy_detail(const char *value, StringBuffer *buf)
Definition: knowledge.cpp:240
SockList_AddLen16Data
void SockList_AddLen16Data(SockList *sl, const void *data, size_t len)
Definition: lowlevel.cpp:188
FLAG_INV_LOCKED
#define FLAG_INV_LOCKED
Definition: define.h:329
SockList_Reset
void SockList_Reset(SockList *sl)
Definition: lowlevel.cpp:71
object_get_value
const char * object_get_value(const object *op, const char *const key)
Definition: object.cpp:4337
apply_by_living_below
void apply_by_living_below(object *pl)
Definition: apply.cpp:695
MSG_TYPE_MISC
#define MSG_TYPE_MISC
Definition: newclient.h:402
buf
StringBuffer * buf
Definition: readable.cpp:1552
MSG_TYPE_COMMAND
#define MSG_TYPE_COMMAND
Definition: newclient.h:393
knowledge_add
static int knowledge_add(knowledge_player *current, const char *item, const knowledge_type *kt)
Definition: knowledge.cpp:547
knowledge_summary
void(* knowledge_summary)(const char *code, StringBuffer *buf)
Definition: knowledge.cpp:80
name
Plugin animator file specs[Config] name
Definition: animfiles.txt:4
TAG_START
#define TAG_START
Definition: knowledge.cpp:69
linked_char
Definition: global.h:96
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
knowledge_god_summary
static void knowledge_god_summary(const char *item, StringBuffer *buf)
Definition: knowledge.cpp:658
SockList
Definition: newclient.h:670
SockList_Avail
size_t SockList_Avail(const SockList *sl)
Definition: lowlevel.cpp:243
knowledge_item::item
sstring item
Definition: knowledge.cpp:148
knowledge_write_player_data
static void knowledge_write_player_data(const knowledge_player *kp)
Definition: knowledge.cpp:879
knowledge_god_face
static const Face * knowledge_god_face(sstring code)
Definition: knowledge.cpp:771
knowledge_alchemy_get_recipe
static const recipe * knowledge_alchemy_get_recipe(const char *value)
Definition: knowledge.cpp:172
stringbuffer_finish
char * stringbuffer_finish(StringBuffer *sb)
Definition: stringbuffer.cpp:76
GeneralMessage
Definition: book.h:44
letter
**Media tags please refer to the protocol file in doc Developers protocol Quick for your pleasure an example[/b][i] This is an old letter
Definition: media-tags.txt:15
knowledge_player::next
knowledge_player * next
Definition: knowledge.cpp:160
knowledge_player::sent_up_to
int sent_up_to
Definition: knowledge.cpp:158
disinfect.map
map
Definition: disinfect.py:4
knowledge_type::summary
knowledge_summary summary
Definition: knowledge.cpp:134
add_refcount
sstring add_refcount(sstring str)
Definition: shstr.cpp:210
linked_char::name
const char * name
Definition: global.h:97
recipelist
Definition: recipe.h:37
knowledge_message_validate
static int knowledge_message_validate(const char *item)
Definition: knowledge.cpp:830
rotate-tower.result
bool result
Definition: rotate-tower.py:13
esrv_send_face
void esrv_send_face(socket_struct *ns, const Face *face, int nocache)
Definition: image.cpp:72
command_take
void command_take(object *op, const char *params)
Definition: c_object.cpp:845
knowledge_type::add
knowledge_add_item add
Definition: knowledge.cpp:137
free_knowledge_items
static void free_knowledge_items(knowledge_player *kp)
Definition: knowledge.cpp:1249
query_name
void query_name(const object *op, char *buf, size_t size)
Definition: item.cpp:592
stringbuffer_finish_shared
sstring stringbuffer_finish_shared(StringBuffer *sb)
Definition: stringbuffer.cpp:85
archetype::clone
object clone
Definition: object.h:478
of
a copper bar weighs and has a value of
Definition: ore.txt:3
MSG_TYPE_COMMAND_INFO
#define MSG_TYPE_COMMAND_INFO
Definition: newclient.h:515
add_string
sstring add_string(const char *str)
Definition: shstr.cpp:124
object::below
object * below
Definition: object.h:295
object::face
const Face * face
Definition: object.h:341
knowledge_show
static void knowledge_show(object *pl, const char *params)
Definition: knowledge.cpp:1160
knowledge_type::type
const char * type
Definition: knowledge.cpp:133
navar-midane_pickup.msg
list msg
Definition: navar-midane_pickup.py:13
knowledge_give
void knowledge_give(player *pl, const char *marker, const object *book)
Definition: knowledge.cpp:993
recipe::index
int index
Definition: recipe.h:18
command_help
void command_help(object *op, const char *params)
Definition: c_misc.cpp:1772
knowledge_type::detail
knowledge_detail detail
Definition: knowledge.cpp:135
linked_char::next
struct linked_char * next
Definition: global.h:98
title
Definition: readable.cpp:108
knowledge_monster_summary
static void knowledge_monster_summary(const char *item, StringBuffer *buf)
Definition: knowledge.cpp:578
disinfect.count
int count
Definition: disinfect.py:7
knowledge_global
static knowledge_player * knowledge_global
Definition: knowledge.cpp:164
tag_t
uint32_t tag_t
Definition: object.h:14
archetype
Definition: object.h:474
Settings::playerdir
const char * playerdir
Definition: global.h:250
sproto.h
get_message_body
sstring get_message_body(const GeneralMessage *message)
Definition: readable.cpp:2061
stringbuffer_append_string
void stringbuffer_append_string(StringBuffer *sb, const char *str)
Definition: stringbuffer.cpp:95
knowledge_player_knows
int knowledge_player_knows(const player *pl, const char *knowledge)
Definition: knowledge.cpp:1295
knowledge_type::validate
knowledge_is_valid_item validate
Definition: knowledge.cpp:136
SockList_Init
void SockList_Init(SockList *sl)
Definition: lowlevel.cpp:52
nlohmann::detail::void
j template void())
Definition: json.hpp:4099
get_message_from_identifier
const GeneralMessage * get_message_from_identifier(const char *identifier)
Definition: assets.cpp:324
knowledge_get_or_create
static knowledge_player * knowledge_get_or_create(const player *pl)
Definition: knowledge.cpp:965
knowledge_item_can_be_used_alchemy
void knowledge_item_can_be_used_alchemy(object *op, const object *item)
Definition: knowledge.cpp:1331
recipe::ingred_count
int ingred_count
Definition: recipe.h:23
env
static std::shared_ptr< inja::Environment > env
Definition: mapper.cpp:2170
knowledges
static const knowledge_type knowledges[]
Definition: knowledge.cpp:850
MAX_BUF
#define MAX_BUF
Definition: define.h:35
knowledge_player::items
knowledge_item ** items
Definition: knowledge.cpp:155
MSG_TYPE_ADMIN_LOADSAVE
#define MSG_TYPE_ADMIN_LOADSAVE
Definition: newclient.h:488
strlcpy
size_t strlcpy(char *dst, const char *src, size_t size)
Definition: porting.cpp:222
knowledge_read
void knowledge_read(player *pl, object *book)
Definition: knowledge.cpp:1053
describe_item
StringBuffer * describe_item(const object *op, const object *owner, int use_media_tags, StringBuffer *buf)
Definition: item.cpp:955
knowledge_detail
void(* knowledge_detail)(const char *code, StringBuffer *buf)
Definition: knowledge.cpp:87
knowledge_first_player_save
void knowledge_first_player_save(player *pl)
Definition: knowledge.cpp:1420
free_string
void free_string(sstring str)
Definition: shstr.cpp:280
knowledge_add_item
int(* knowledge_add_item)(knowledge_player *current, const char *item, const knowledge_type *type)
Definition: knowledge.cpp:103
SockList_Term
void SockList_Term(SockList *sl)
Definition: lowlevel.cpp:62
RANDOM
#define RANDOM()
Definition: define.h:644
recipe
Definition: recipe.h:10
knowledge_item
Definition: knowledge.cpp:147
command_knowledge
void command_knowledge(object *pl, const char *params)
Definition: knowledge.cpp:1210
knowledge_player::item_allocated
int item_allocated
Definition: knowledge.cpp:157
knowledge_message_summary
static void knowledge_message_summary(const char *value, StringBuffer *buf)
Definition: knowledge.cpp:799
NDI_UNIQUE
#define NDI_UNIQUE
Definition: newclient.h:251
fatal
void fatal(enum fatal_error err)
Definition: utils.cpp:570
find_archetype_by_object_name
archetype * find_archetype_by_object_name(const char *name)
Definition: arch.cpp:53
object::name
sstring name
Definition: object.h:319
bigchest.check
check
Definition: bigchest.py:10
get_message_title
sstring get_message_title(const GeneralMessage *message)
Definition: readable.cpp:2052
knowledge_find
static const knowledge_type * knowledge_find(const char *type)
Definition: knowledge.cpp:864
item
Definition: item.py:1
mapstruct
Definition: map.h:314
knowledge_monster_detail
static void knowledge_monster_detail(const char *item, StringBuffer *buf)
Definition: knowledge.cpp:592
sstring
const typedef char * sstring
Definition: sstring.h:2
give.op
op
Definition: give.py:33
knowledge_attempt
void(* knowledge_attempt)(player *pl, const knowledge_item *item)
Definition: knowledge.cpp:129
autojail.value
value
Definition: autojail.py:6
knowledge_player::player_name
sstring player_name
Definition: knowledge.cpp:154
knowledge_message_face
static const Face * knowledge_message_face(sstring code)
Definition: knowledge.cpp:839
knowledge_do_display
static void knowledge_do_display(object *pl, const knowledge_type *show_only, const char *search)
Definition: knowledge.cpp:1065
roll-o-matic.params
params
Definition: roll-o-matic.py:193
diamondslots.y
y
Definition: diamondslots.py:16
knowledge_send_known
void knowledge_send_known(player *pl)
Definition: knowledge.cpp:1400
npc_dialog.index
int index
Definition: npc_dialog.py:102
OutputFile
Definition: output_file.h:41
knowledge_god_detail
static void knowledge_god_detail(const char *item, StringBuffer *buf)
Definition: knowledge.cpp:674
knowledge_monster_face
static const Face * knowledge_monster_face(sstring code)
Definition: knowledge.cpp:643
knowledge_do_attempt
static void knowledge_do_attempt(object *pl, const char *params)
Definition: knowledge.cpp:1186
socket_struct::faces_sent
uint8_t * faces_sent
Definition: newserver.h:96
MSG_TYPE_CLIENT_NOTICE
#define MSG_TYPE_CLIENT_NOTICE
Definition: newclient.h:654
make_face_from_files.int
int
Definition: make_face_from_files.py:32
free_knowledge_player
static void free_knowledge_player(knowledge_player *kp)
Definition: knowledge.cpp:1268
Face
Definition: face.h:14
knowledge_can_use_alchemy
StringBuffer *(* knowledge_can_use_alchemy)(sstring code, const char *item, StringBuffer *buf, int index)
Definition: knowledge.cpp:113
knowledge_item::handler
const knowledge_type * handler
Definition: knowledge.cpp:149
knowledge_monster_validate
static int knowledge_monster_validate(const char *item)
Definition: knowledge.cpp:607
first
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 first
Definition: protocol.txt:20
try_find_archetype
archetype * try_find_archetype(const char *name)
Definition: assets.cpp:270
recipe::ingred
linked_char * ingred
Definition: recipe.h:22
try_find_face
const Face * try_find_face(const char *name, const Face *error)
Definition: assets.cpp:286
knowledge_read_player_data
static void knowledge_read_player_data(knowledge_player *kp)
Definition: knowledge.cpp:910
code
Crossfire Architecture the general intention is to enhance the enjoyability and playability of CF In this code
Definition: arch-handbook.txt:14
knowledge_message_detail
static void knowledge_message_detail(const char *value, StringBuffer *buf)
Definition: knowledge.cpp:815
knowledge_alchemy_validate
static int knowledge_alchemy_validate(const char *item)
Definition: knowledge.cpp:285
archetype::name
sstring name
Definition: object.h:475
object::nrof
uint32_t nrof
Definition: object.h:342
knowledge_type::use_alchemy
knowledge_can_use_alchemy use_alchemy
Definition: knowledge.cpp:139
recipe::next
recipe * next
Definition: recipe.h:24
recipe::skill
sstring skill
Definition: recipe.h:26
say.item
dictionary item
Definition: say.py:149
knowledge_process_incremental
void knowledge_process_incremental(void)
Definition: knowledge.cpp:1436
Face::number
uint16_t number
Definition: face.h:15
describe_god
int describe_god(const object *god, int what, StringBuffer *buf, size_t maxlen)
Definition: holy.cpp:109
hall_of_fame.header
list header
Definition: hall_of_fame.py:38
StringBuffer
Definition: stringbuffer.cpp:25
replace.current
current
Definition: replace.py:64
knowledge_alchemy_summary
static void knowledge_alchemy_summary(const char *value, StringBuffer *buf)
Definition: knowledge.cpp:210
knowledge_alchemy_face
static const Face * knowledge_alchemy_face(sstring code)
Definition: knowledge.cpp:511
OUT_OF_MEMORY
@ OUT_OF_MEMORY
Definition: define.h:48
examine
void examine(object *op, object *tmp)
Definition: c_object.cpp:1983
altar_valkyrie.pl
pl
Definition: altar_valkyrie.py:28
Send_With_Handling
void Send_With_Handling(socket_struct *ns, SockList *sl)
Definition: lowlevel.cpp:444
MSG_TYPE_ADMIN
#define MSG_TYPE_ADMIN
Definition: newclient.h:391
knowledge_player
Definition: knowledge.cpp:153
recipe_get_face
const Face * recipe_get_face(const recipe *rp)
Definition: recipe.cpp:920
get_message_face
const Face * get_message_face(const GeneralMessage *message)
Definition: readable.cpp:2070
llevDebug
@ llevDebug
Definition: logger.h:13
is_valid_types_gen.type
list type
Definition: is_valid_types_gen.py:25
SockList_AddPrintf
void SockList_AddPrintf(SockList *sl, const char *format,...)
Definition: lowlevel.cpp:199
knowledge_known
static int knowledge_known(const knowledge_player *current, const char *item, const knowledge_type *kt)
Definition: knowledge.cpp:529
put_object_in_sack
void put_object_in_sack(object *op, object *sack, object *tmp, uint32_t nrof)
Definition: c_object.cpp:937
recipe::cauldron
sstring cauldron
Definition: recipe.h:27
recipe::title
sstring title
Definition: recipe.h:11