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, ", a%s %s recipe, is made with %s at %s and uses the following ingredients:",
273  rec->diff >= 10 && rec->diff < 15 ? "n" : "",
275  rec->skill ? rec->skill : "an unknown skill", name);
276 
277  for (next = rec->ingred; next != NULL; next = next->next) {
278  stringbuffer_append_printf(buf, "\n - %s", next->name);
279  }
280 
281 }
282 
288 static int knowledge_alchemy_validate(const char *item) {
289  return knowledge_alchemy_get_recipe(item) != NULL;
290 }
291 
301  const recipe *rec = knowledge_alchemy_get_recipe(code);
302  const linked_char *next;
303  const archetype *arch;
304  const char *name;
305 
306  if (!item)
307  return NULL;
308 
309  if (!rec)
310  /* warn? */
311  return buf;
312 
314  if (!arch)
315  /* not supposed to happen */
316  return buf;
317 
318  for (next = rec->ingred; next != NULL; next = next->next) {
319  name = next->name;
320  while ((*name) != '\0' && (isdigit(*name) || (*name) == ' '))
321  name++;
322 
323  if (strcmp(item, name) == 0) {
324  if (buf == NULL) {
325  buf = stringbuffer_new();
326  stringbuffer_append_string(buf, "It can be used in the following recipes: ");
327  } else
329 
330  if (strcmp(rec->title, "NONE"))
331  stringbuffer_append_printf(buf, "%s of %s", arch->clone.name, rec->title);
332  else {
333  if (arch->clone.title != NULL) {
334  stringbuffer_append_printf(buf, "%s %s", arch->clone.name, arch->clone.title);
335  }
336  else
337  stringbuffer_append_printf(buf, "%s", arch->clone.name);
338  }
340 
341  break;
342  }
343  }
344 
345  return buf;
346 }
347 
354  const recipe *rp = knowledge_alchemy_get_recipe(item->item);
355  object *cauldron = NULL, *inv;
356  object *ingredients[50];
357  int index, x, y;
358  uint32_t count, counts[50];
359  char name[MAX_BUF];
360  const char *ingname;
361  linked_char *ing;
362  tag_t cauldron_tag;
363  mapstruct *map;
364 
365  if (!rp) {
366  LOG(llevError, "knowledge: couldn't find recipe for %s", item->item);
367  return;
368  }
369 
370  if (rp->ingred_count > 50) {
371  LOG(llevError, "knowledge: recipe %s has more than 50 ingredients!", item->item);
372  draw_ext_info(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, "This recipe is too complicated.");
373  return;
374  }
375 
376  /* first, check for a cauldron */
377  for (cauldron = pl->ob->below; cauldron; cauldron = cauldron->below) {
378  if (strcmp(rp->cauldron, cauldron->arch->name) == 0)
379  break;
380  }
381 
382  if (cauldron == NULL) {
383  draw_ext_info_format(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, "You are not on a %s", rp->cauldron);
384  return;
385  }
386 
387  cauldron_tag = cauldron->count;
388 
389  /* find ingredients in player's inventory */
390  for (index = 0; index < 50; index++) {
391  ingredients[index] = NULL;
392  }
393  for (inv = pl->ob->inv; inv != NULL; inv = inv->below) {
394 
396  continue;
397 
398  if (inv->title == NULL)
399  safe_strncpy(name, inv->name, sizeof(name));
400  else
401  snprintf(name, sizeof(name), "%s %s", inv->name, inv->title);
402 
403  index = 0;
404  for (ing = rp->ingred; ing != NULL; ing = ing->next) {
405 
406  if (ingredients[index] != NULL) {
407  index++;
408  continue;
409  }
410 
411  ingname = ing->name;
412  count = 0;
413  while (isdigit(*ingname)) {
414  count = 10 * count + (*ingname - '0');
415  ingname++;
416  }
417  if (count == 0)
418  count = 1;
419  while (*ingname == ' ')
420  ingname++;
421 
422  if (strcmp(name, ingname) == 0 && ((inv->nrof == 0 && count == 1) || (inv->nrof >= count))) {
423  ingredients[index] = inv;
424  // If nrof is 0, we want to keep a count of 0 so put_object_in_sack() later doesn't call
425  // object_split() which would destroy tmp and mess up our tags.
426  counts[index] = inv->nrof == 0 ? 0 : count;
427  break;
428  }
429 
430  index++;
431  }
432  }
433 
434  index = 0;
435  for (ing = rp->ingred; ing != NULL; ing = ing->next) {
436  if (ingredients[index] == NULL) {
437  draw_ext_info_format(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, "You don't have %s.", ing->name);
438  return;
439  }
440 
441  index++;
442  }
443 
444  /* ensure cauldron is applied */
445  if (pl->ob->container != cauldron) {
447  if (pl->ob->container != cauldron) {
448  draw_ext_info_format(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, "Couldn't activate the %s.", rp->cauldron);
449  return;
450  }
451  }
452 
453  /* ensure cauldron is empty */
454  while (cauldron->inv != NULL) {
455  inv = cauldron->inv;
456  command_take(pl->ob, "");
457  if (cauldron->inv == inv) {
458  draw_ext_info_format(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, "Couldn't empty the %s", rp->cauldron);
459  return;
460  }
461  }
462 
463  /* drop ingredients */
464  for (index = 0; index < rp->ingred_count; index++) {
465  tag_t tag = ingredients[index]->count;
466  count = ingredients[index]->nrof;
467  put_object_in_sack(pl->ob, cauldron, ingredients[index], counts[index]);
468  if (object_was_destroyed(ingredients[index], tag)) {
469  draw_ext_info(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, "Hum, some item disappeared, stopping the attempt.");
470  return;
471 
472  }
473  if (count == ingredients[index]->nrof && ingredients[index]->env == pl->ob) {
474  draw_ext_info(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, "Hum, couldn't drop some items, stopping the attempt.");
475  return;
476  }
477  }
478 
479  map = pl->ob->map;
480  x = pl->ob->x;
481  y = pl->ob->y;
482 
483  /* do alchemy */
484  use_alchemy(pl->ob);
485 
486  /* don't forget to slow the player: 1 for alchemy itself, 1 for each ingredient put,
487  * ingredients taken are handled by command_take() */
488  pl->ob->speed_left -= 1.0 * (rp->ingred_count + 1);
489 
490  /* safety: ensure cauldron is still there, and player is still above */
491  if (object_was_destroyed(cauldron, cauldron_tag) || map != pl->ob->map || x != pl->ob->x || y != pl->ob->y) {
492  return;
493  }
494 
495  /* get back the result */
496  while (cauldron->inv) {
497  /* Examining may lead to identifying part of items and thus introducing
498  * extra items in the cauldron. Therefore we'll set inv only after examining,
499  * even if that means that potentially the player will examine twice some items. */
500  examine(pl->ob, cauldron->inv);
501  inv = cauldron->inv;
502  command_take(pl->ob, "");
503  pl->ob->speed_left -= 1.0;
504  if (inv == cauldron->inv)
505  break;
506  }
507 }
508 
514 static const Face *knowledge_alchemy_face(sstring code) {
515  const recipe *rp = knowledge_alchemy_get_recipe(code);
516 
517  if (!rp) {
518  LOG(llevError, "knowledge: couldn't find recipe for %s", code);
519  return NULL;
520  }
521 
522  return recipe_get_face(rp);
523 }
524 
532 static int knowledge_known(const knowledge_player *current, const char *item, const knowledge_type *kt) {
533  int i;
534  for (i = 0; i < current->item_count; i++) {
535  if (strcmp(kt->type, current->items[i]->handler->type) == 0 && strcmp(item, current->items[i]->item) == 0) {
536  /* already known, bailout */
537  return 1;
538  }
539  }
540  return 0;
541 }
542 
550 static int knowledge_add(knowledge_player *current, const char *item, const knowledge_type *kt) {
552 
553  if (knowledge_known(current, item, kt)) {
554  return 0;
555  }
556 
557  /* keep the knowledge */
562  check = static_cast<knowledge_item *>(malloc(sizeof(knowledge_item)));
563  check->item = add_string(item);
564  check->handler = kt;
565  if (current->item_count >= current->item_allocated) {
566  current->item_allocated += 10;
567  current->items = static_cast<knowledge_item **>(realloc(current->items, current->item_allocated * sizeof(knowledge_item*)));
568  }
569  current->items[current->item_count] = check;
570  current->item_count++;
571 
572  return 1;
573 }
574 
581 static void knowledge_monster_summary(const char *item, StringBuffer *buf) {
582  archetype *monster = try_find_archetype(item);
583  if (!monster)
584  return;
585 
586  stringbuffer_append_printf(buf, "%s", monster->clone.name);
587 }
588 
595 static void knowledge_monster_detail(const char *item, StringBuffer *buf) {
596  archetype *monster = try_find_archetype(item);
597 
598  if (!monster)
599  return;
600 
601  stringbuffer_append_printf(buf, " *** %s ***\n", monster->clone.name);
602  describe_item(&monster->clone, NULL, 1, buf);
603 }
604 
610 static int knowledge_monster_validate(const char *item) {
611  const archetype *monster = try_find_archetype(item);
612  if (monster == NULL || monster->clone.type != 0 || monster->head || object_get_value(&monster->clone, MONSTER_EXCLUDE_FROM_READABLE_KEY) != NULL)
613  return 0;
614  return 1;
615 }
616 
624 static int knowledge_monster_add(struct knowledge_player *current, const char *item, const struct knowledge_type *type) {
625  char *dup = strdup_local(item);
626  char *pos, *first = dup;
627  int added = 0;
628 
629  while (first) {
630  pos = strchr(first, ':');
631  if (pos)
632  *pos = '\0';
633  added += knowledge_add(current, first, type);
634  first = pos ? pos + 1 : NULL;
635  }
636 
637  free(dup);
638  return added;
639 }
640 
646 static const Face *knowledge_monster_face(sstring code) {
647  const archetype *monster = try_find_archetype(code);
648 
649  if (!monster || monster->clone.face == blank_face || monster->clone.face == NULL)
650  return NULL;
651 
652  return monster->clone.face;
653 }
654 
661 static void knowledge_god_summary(const char *item, StringBuffer *buf) {
662  char *dup = strdup_local(item), *pos = strchr(dup, ':');
663 
664  if (pos)
665  *pos = '\0';
666 
667  stringbuffer_append_printf(buf, "%s [god]", dup);
668  free(dup);
669 }
670 
677 static void knowledge_god_detail(const char *item, StringBuffer *buf) {
678  char *dup = strdup_local(item), *pos = strchr(dup, ':');
679  const archetype *god;
680  int what;
681 
682  if (!pos) {
683  LOG(llevError, "knowledge_god_detail: invalid god item %s\n", item);
684  free(dup);
685  return;
686  }
687 
688  *pos = '\0';
689  what = atoi(pos + 1);
691  free(dup);
692 
693  if (!god) {
694  LOG(llevError, "knowledge_god_detail: couldn't find god %s?\n", item);
695  return;
696  }
697 
698  describe_god(&god->clone, what, buf, 0);
699 }
700 
706 static int knowledge_god_validate(const char *item) {
707  char *dup = strdup_local(item), *pos = strchr(dup, ':');
708  int valid;
709 
710  if (!pos) {
711  LOG(llevError, "knowledge_god_validate: invalid god item %s\n", item);
712  free(dup);
713  return 0;
714  }
715  *pos = '\0';
716  valid = find_archetype_by_object_name(dup) != NULL;
717  free(dup);
718  return valid;
719 }
720 
728 static int knowledge_god_add(struct knowledge_player *current, const char *item, const struct knowledge_type *type) {
729  char *dup = strdup_local(item), *pos = const_cast<char *>(strchr(dup, ':'));
730  StringBuffer *buf;
731  int what, i;
733 
734  if (!pos) {
735  LOG(llevError, "knowledge_god_add: invalid god item %s\n", item);
736  free(dup);
737  return 0;
738  }
739 
740  *pos = '\0';
741  what = atoi(pos + 1);
742 
743  for (i = 0; i < current->item_count; i++) {
744  check = current->items[i];
745  if (check->handler != type)
746  /* Only consider our own type. */
747  continue;
748  if (strncmp(check->item, dup, strlen(dup)) == 0) {
749  /* Already known, update information. */
750  int known, result;
751  pos = const_cast<char *>(strchr(check->item, ':'));
752  known = atoi(pos + 1);
753  result = known | what;
754  buf = stringbuffer_new();
755  stringbuffer_append_printf(buf, "%s:%d", dup, result);
756  free_string(check->item);
758  free(dup);
759  return (result != known);
760  }
761  }
762 
763  free(dup);
764 
765  /* Not known, so just add it regularly. */
766  return knowledge_add(current, item, type);
767 }
768 
774 static const Face *knowledge_god_face(sstring code) {
775  char buf[MAX_BUF];
776  size_t letter;
777  const archetype *altar_arch;
778 
779  snprintf(buf, MAX_BUF, "altar_");
780  letter = strlen(buf);
781  strncpy(buf+letter, code, MAX_BUF-letter);
782  for (; letter < strlen(buf); letter++) {
783  if (buf[letter] == ':') {
784  buf[letter] = '\0';
785  break;
786  }
787  buf[letter] = tolower(buf[letter]);
788  }
789  altar_arch = try_find_archetype(buf);
790  if (altar_arch == NULL)
791  return NULL;
792 
793  return altar_arch->clone.face;
794 }
795 
802 static void knowledge_message_summary(const char *value, StringBuffer *buf) {
804 
805  if (!msg)
806  /* warn? */
807  return;
808 
810 }
811 
818 static void knowledge_message_detail(const char *value, StringBuffer *buf) {
820 
821  if (!msg)
822  /* warn? */
823  return;
824 
826 }
827 
833 static int knowledge_message_validate(const char *item) {
834  return get_message_from_identifier(item) != NULL;
835 }
836 
842 static const Face *knowledge_message_face(sstring code) {
844 
845  if (!msg)
846  /* warn? */
847  return NULL;
848 
849  return get_message_face(msg);
850 }
851 
853 static const knowledge_type knowledges[] = {
855  { "monster", knowledge_monster_summary, knowledge_monster_detail, knowledge_monster_validate, knowledge_monster_add, "monsters", NULL, NULL, "knowledge_monsters.111", knowledge_monster_face },
856  { "god", knowledge_god_summary, knowledge_god_detail, knowledge_god_validate, knowledge_god_add, "gods", NULL, NULL, "knowledge_gods.111", knowledge_god_face },
857  { "message", knowledge_message_summary, knowledge_message_detail, knowledge_message_validate, knowledge_add, "messages", NULL, NULL, "knowledge_messages.111", knowledge_message_face },
858  { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
859 };
860 
861 
867 static const knowledge_type *knowledge_find(const char *type) {
868  int i = 0;
869  while (knowledges[i].type != NULL) {
870  if (strcmp(knowledges[i].type, type) == 0)
871  return &knowledges[i];
872  i++;
873  }
874 
875  return NULL;
876 }
877 
883  FILE *file;
884  OutputFile of;
885  char fname[MAX_BUF];
886  const knowledge_item *item;
887  int i;
888 
889  snprintf(fname, sizeof(fname), "%s/%s/%s/%s.knowledge", settings.localdir, settings.playerdir, kp->player_name, kp->player_name);
890 
891  file = of_open(&of, fname);
892  if (!file) {
893  draw_ext_info(NDI_UNIQUE | NDI_ALL_DMS, 0, NULL, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_LOADSAVE, "File write error on server!");
894  return;
895  }
896 
897  for (i = 0; i < kp->item_count; i++) {
898  item = kp->items[i];
899  fprintf(file, "%s:%s\n", item->handler->type, item->item);
900  }
901 
902  if (!of_close(&of)) {
903  draw_ext_info(NDI_UNIQUE | NDI_ALL_DMS, 0, NULL, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_LOADSAVE, "File write error on server!");
904  return;
905  }
907 }
908 
914  FILE *file;
915  char final[MAX_BUF], read[MAX_BUF], *dot;
917  const knowledge_type *type;
918 
919  snprintf(final, sizeof(final), "%s/%s/%s/%s.knowledge", settings.localdir, settings.playerdir, kp->player_name, kp->player_name);
920 
921  file = fopen(final, "r");
922  if (!file) {
923  /* no knowledge yet, no big deal */
924  return;
925  }
926 
927  while (fgets(read, sizeof(read), file) != NULL) {
928  if (strlen(read) > 0)
929  read[strlen(read) - 1] = '\0';
930 
931  dot = strchr(read, ':');
932  if (!dot) {
933  LOG(llevError, "knowledge: invalid line in file %s\n", final);
934  continue;
935  }
936 
937  *dot = '\0';
938 
939  type = knowledge_find(read);
940  if (!type) {
941  LOG(llevError, "knowledge: invalid type %s in file %s\n", read, final);
942  continue;
943  }
944  if (!type->validate(dot + 1)) {
945  LOG(llevDebug, "knowledge: ignoring now invalid %s in file %s\n", read, final);
946  continue;
947  }
948 
949  item = static_cast<knowledge_item *>(malloc(sizeof(knowledge_item)));
950  item->item = add_string(dot + 1);
951  item->handler = type;
952  if (kp->item_count == kp->item_allocated) {
953  kp->item_allocated += 10;
954  kp->items = static_cast<knowledge_item **>(realloc(kp->items, kp->item_allocated * sizeof(knowledge_item*)));
955  }
956  kp->items[kp->item_count] = item;
957  kp->item_count++;
958  }
959  fclose(file);
960 }
961 
970 
971  while (cur) {
972  if (cur->player_name == pl->ob->name)
973  return cur;
974  cur = cur->next;
975  }
976 
977  cur = static_cast<knowledge_player *>(calloc(1, sizeof(knowledge_player)));
978  if (!cur)
980  cur->player_name = add_refcount(pl->ob->name);
981  cur->next = knowledge_global;
982  knowledge_global = cur;
983  /* read knowledge for this player */
985  if (pl->socket->notifications < 2)
986  cur->sent_up_to = -1;
987  return cur;
988 }
989 
996 void knowledge_give(player *pl, const char *marker, const object *book) {
997  char *copy, *code, *dot;
998  const knowledge_type *type;
999  int none, added = 0;
1001 
1002  /* process marker, find if already known */
1003  dot = const_cast<char *>(strchr(marker, ':'));
1004  if (dot == NULL)
1005  return;
1006 
1007  copy = strdup(marker);
1008  if (!copy)
1010 
1011  dot = const_cast<char *>(strchr(copy, ':'));
1012  *dot = '\0';
1013  dot++;
1014 
1015  type = knowledge_find(copy);
1016  if (!type) {
1017  LOG(llevError, "knowledge: invalid marker type %s in %s\n", copy, book == NULL ? "(null)" : book->name);
1018  free(copy);
1019  return;
1020  }
1021 
1022  none = (current->items == NULL);
1023 
1024  code = dot;
1025  while (code && code[0] != '\0') {
1026  dot = strchr(code, '/');
1027  if (dot) {
1028  *dot = '\0';
1029  dot++;
1030  }
1031  if (type->validate(code)) {
1032  added += type->add(current, code, type);
1033  }
1034  code = dot;
1035  }
1036 
1037  free(copy);
1038 
1039  if (added) {
1040  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.");
1041  if (none) {
1042  /* first information ever written down, be nice and give hint to recover it. */
1043  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).");
1044  }
1045  }
1046 
1047  if (pl->has_directory)
1049 }
1050 
1056 void knowledge_read(player *pl, object *book) {
1057  sstring marker = object_get_value(book, "knowledge_marker");
1058  if (marker != NULL)
1059  knowledge_give(pl, marker, book);
1060 }
1061 
1068 static void knowledge_do_display(object *pl, const knowledge_type *show_only, const char *search) {
1069  knowledge_player *kp;
1071  int header = 0, show, i;
1072  StringBuffer *summary;
1073  char *final;
1074 
1075  assert(search == NULL || search[0] != '\0');
1076 
1077  kp = knowledge_get_or_create(pl->contr);
1078  for (i = 0; i < kp->item_count; i++) {
1079  item = kp->items[i];
1080  show = 1;
1081 
1082  summary = stringbuffer_new();
1083  item->handler->summary(item->item, summary);
1084  final = stringbuffer_finish(summary);
1085 
1086  if (show_only != NULL && item->handler != show_only) {
1087  show = 0;
1088  }
1089  if (search != NULL && search[0] != '\0') {
1090  if (strstr(final, search) == NULL) {
1091  char *fd;
1092  StringBuffer *detail = stringbuffer_new();
1093  item->handler->detail(item->item, detail);
1094  fd = stringbuffer_finish(detail);
1095  if (strstr(fd, search) == NULL)
1096  show = 0;
1097  free(fd);
1098  }
1099  }
1100 
1101  if (show == 1) {
1102  if (header == 0) {
1103  if (search != NULL)
1104  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);
1105  else if (show_only != NULL)
1106  draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_MISC, MSG_TYPE_CLIENT_NOTICE, "You have knowledge of those %s:", show_only->name);
1107  else
1108  draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_MISC, MSG_TYPE_CLIENT_NOTICE, "You have knowledge of:");
1109  header = 1;
1110  }
1111 
1112  draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_MISC, MSG_TYPE_CLIENT_NOTICE, "(%3d) %s", i + 1, final);
1113  }
1114 
1115  free(final);
1116  }
1117 
1118  if (header == 0) {
1119  if (search != NULL)
1120  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);
1121  else if (show_only != NULL)
1122  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);
1123  else
1124  draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_MISC, MSG_TYPE_CLIENT_NOTICE, "You don't know yet any relevant information.");
1125  }
1126 }
1127 
1133 static void knowledge_display(object *pl, const char *params) {
1134  const knowledge_type *show_only = NULL;
1135 
1136  if (params && params[0] == ' ') {
1137  const char *type = params + 1;
1138  int idx = 0;
1139  for (; knowledges[idx].type != NULL; idx++) {
1140  if (strcmp(knowledges[idx].name, type) == 0) {
1141  show_only = &knowledges[idx];
1142  break;
1143  }
1144  }
1145 
1146  if (show_only == NULL) {
1147  draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_MISC, MSG_TYPE_CLIENT_NOTICE, "Invalid type, valid types are:");
1148  for (idx = 0; knowledges[idx].type != NULL; idx++) {
1150  }
1151  return;
1152  }
1153  }
1154 
1155  knowledge_do_display(pl, show_only, NULL);
1156 }
1157 
1163 static void knowledge_show(object *pl, const char *params) {
1164  knowledge_player *kp;
1166  int count = atoi(params) - 1;
1167  StringBuffer *buf;
1168  char *final;
1169 
1170  kp = knowledge_get_or_create(pl->contr);
1171  if (count < 0 || count >= kp->item_count) {
1172  draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, "Invalid knowledge number");
1173  return;
1174  }
1175 
1176  item = kp->items[count];
1177  buf = stringbuffer_new();
1178  item->handler->detail(item->item, buf);
1179  final = stringbuffer_finish(buf);
1181  free(final);
1182 }
1183 
1189 static void knowledge_do_attempt(object *pl, const char *params) {
1190  knowledge_player *kp;
1192  int count = atoi(params) - 1;
1193 
1194  kp = knowledge_get_or_create(pl->contr);
1195  if (count < 0 || count >= kp->item_count) {
1196  draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, "Invalid knowledge number");
1197  return;
1198  }
1199 
1200  item = kp->items[count];
1201  if (item->handler->attempt_alchemy == NULL) {
1202  draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, "You can't do anything with that knowledge.");
1203  } else {
1204  item->handler->attempt_alchemy(pl->contr, item);
1205  }
1206 }
1207 
1213 void command_knowledge(object *pl, const char *params) {
1214 
1215  if (!pl->contr) {
1216  LOG(llevError, "command_knowledge: called for %s not a player!\n", pl->name);
1217  return;
1218  }
1219 
1220  if (!params || *params == '\0') {
1221  command_help(pl, "knowledge");
1222  return;
1223  }
1224 
1225  if (strncmp(params, "list", 4) == 0) {
1226  knowledge_display(pl, params + 4);
1227  return;
1228  }
1229 
1230  if (strncmp(params, "search ", 7) == 0) {
1231  knowledge_do_display(pl, NULL, params + 7);
1232  return;
1233  }
1234 
1235  if (strncmp(params, "show ", 5) == 0) {
1236  knowledge_show(pl, params + 5);
1237  return;
1238  }
1239 
1240  if (strncmp(params, "attempt ", 8) == 0) {
1242  return;
1243  }
1244 
1245  command_help(pl, "knowledge");
1246 }
1247 
1254  int i;
1255 
1256  for (i = 0; i < kp->item_count; i++) {
1257  item = kp->items[i];
1258  free_string(item->item);
1259  free(item);
1260  }
1261  free(kp->items);
1262  kp->items = NULL;
1263  kp->item_count = 0;
1264  kp->item_allocated = 0;
1265 }
1266 
1273  free_string(kp->player_name);
1274  free(kp);
1275 }
1276 
1280 void free_knowledge(void) {
1281  knowledge_player *kp, *next;
1282 
1283  kp = knowledge_global;
1284  while (kp) {
1285  next = kp->next;
1287  kp = next;
1288  }
1289  knowledge_global = NULL;
1290 }
1291 
1298 int knowledge_player_knows(const player *pl, const char *knowledge) {
1299  const knowledge_type *type;
1300  char copy[MAX_BUF], *pos;
1301  const knowledge_player *current;
1302 
1303  if (strlen(knowledge) >= MAX_BUF - 1) {
1304  LOG(llevError, "knowledge_player_knows: too long knowledge %s\n", knowledge);
1305  return 0;
1306  }
1307 
1308  strlcpy(copy, knowledge, sizeof(copy));
1309  pos = strchr(copy, ':');
1310  if (pos == NULL) {
1311  LOG(llevError, "knowledge_player_knows: invalid knowledge item %s\n", knowledge);
1312  return 0;
1313  }
1314 
1315  *pos = '\0';
1316  pos++;
1317 
1318  type = knowledge_find(copy);
1319  if (type == NULL) {
1320  LOG(llevError, "knowledge_player_knows: invalid knowledge type %s\n", knowledge);
1321  return 0;
1322  }
1323 
1325 
1326  return knowledge_known(current, pos, type);
1327 }
1328 
1334 void knowledge_item_can_be_used_alchemy(object *op, const object *item) {
1335  knowledge_player *cur;
1336  knowledge_item *ki;
1337  char item_name[MAX_BUF], *result;
1338  const char *name;
1339  StringBuffer *buf = NULL;
1340  int i;
1341 
1342  if (op->type != PLAYER || op->contr == NULL)
1343  return;
1344 
1345  cur = knowledge_get_or_create(op->contr);
1346 
1347  if (item->title != NULL) {
1348  snprintf(item_name, sizeof(item_name), "%s %s", item->name, item->title);
1349  name = item_name;
1350  } else
1351  name = item->name;
1352 
1353  for (i = 0; i < cur->item_count; i++) {
1354  ki = cur->items[i];
1355  if (ki->handler->use_alchemy != NULL) {
1356  buf = ki->handler->use_alchemy(ki->item, name, buf, i + 1);
1357  }
1358  }
1359 
1360  if (buf == NULL)
1361  return;
1362 
1366  result);
1367  free(result);
1368 }
1369 
1375  int i;
1376  const Face *face;
1377  SockList sl;
1378 
1379  face = try_find_face("knowledge_generic.111", NULL);
1380  if (face != NULL && (!(ns->faces_sent[face->number] & NS_FACESENT_FACE)))
1381  esrv_send_face(ns, face, 0);
1382 
1383  SockList_Init(&sl);
1384  SockList_AddString(&sl, "replyinfo knowledge_info\n");
1385  SockList_AddPrintf(&sl, "::%u:0\n", face ? face->number : 0);
1386 
1387  for (i = 0; knowledges[i].type != NULL; i++) {
1388  face = try_find_face(knowledges[i].face, NULL);
1389  if (face != NULL && (!(ns->faces_sent[face->number] & NS_FACESENT_FACE)))
1390  esrv_send_face(ns, face, 0);
1391 
1392  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");
1393  }
1394 
1395  Send_With_Handling(ns, &sl);
1396  SockList_Term(&sl);
1397 }
1398 
1404  knowledge_player *kp;
1405 
1406  if (pl->socket->notifications < 2)
1407  return;
1408 
1409  /* merely loading the knowledge will mark it as to be sent through knowledge_process_incremental(),
1410  * but we need to reset the sent_up_to field if eg the player was the last one to leave
1411  * then joins again - no knowledge processing is done at that point. */
1413  kp->sent_up_to = 0;
1414 }
1415 
1425 
1426  while (cur) {
1427  if (cur->player_name == pl->ob->name) {
1429  }
1430  cur = cur->next;
1431  }
1432 
1433 }
1434 
1440  int i, last;
1441  SockList sl;
1442  size_t size;
1443  const knowledge_item *item;
1444  StringBuffer *buf;
1445  char *title;
1446  const Face *face;
1447  knowledge_player *cur = knowledge_global, *prev = NULL;
1448  player *pl;
1449 
1450  while (cur) {
1451 
1452  for (pl = first_player; pl != NULL; pl = pl->next) {
1453  if (pl->ob->name == cur->player_name) {
1454  break;
1455  }
1456  }
1457 
1458  /* player left, remove knowledge */
1459  if (pl == NULL || pl->state != ST_PLAYING) {
1460  if (prev == NULL) {
1461  knowledge_global = cur->next;
1462  } else {
1463  prev->next = cur->next;
1464  }
1465 
1466  free_knowledge_player(cur);
1467 
1468  /* wait until next tick to do something else */
1469  return;
1470  }
1471 
1472  if (cur->sent_up_to == -1 || cur->sent_up_to == cur->item_count) {
1473  prev = cur;
1474  cur = cur->next;
1475  continue;
1476  }
1477 
1478  last = MIN(cur->sent_up_to + 50, cur->item_count);
1479  SockList_Init(&sl);
1480  SockList_AddString(&sl, "addknowledge ");
1481  for (i = cur->sent_up_to; i < last; i++) {
1482  item = cur->items[i];
1483 
1484  buf = stringbuffer_new();
1485  item->handler->summary(item->item, buf);
1487 
1488  face = NULL;
1489  if (item->handler->item_face != NULL)
1490  face = item->handler->item_face(item->item);
1491 
1492  if (face == NULL)
1493  face = try_find_face(item->handler->face, NULL);
1494 
1495  size = 4 + (2 + strlen(item->handler->type)) + (2 + strlen(title)) + 4;
1496 
1497  if (SockList_Avail(&sl) < size) {
1498  Send_With_Handling(pl->socket, &sl);
1499  SockList_Reset(&sl);
1500  SockList_AddString(&sl, "addknowledge ");
1501  }
1502 
1503  SockList_AddInt(&sl, i + 1);
1504  SockList_AddLen16Data(&sl, item->handler->type, strlen(item->handler->type));
1505  if (face != NULL && !(pl->socket->faces_sent[face->number]&NS_FACESENT_FACE))
1506  esrv_send_face(pl->socket, face, 0);
1507  SockList_AddLen16Data(&sl, title, strlen(title));
1508  SockList_AddInt(&sl, face ? face->number : 0);
1509 
1510  free(title);
1511  }
1512 
1513  cur->sent_up_to = last;
1514 
1515  Send_With_Handling(pl->socket, &sl);
1516  SockList_Term(&sl);
1517 
1518  /* don't send more this tick */
1519  break;
1520  }
1521 }
1522 
1528 void knowledge_add_probe_monster(object *op, object *mon) {
1529  StringBuffer *buf = NULL;
1530  char *result;
1531 
1532  if (op->contr == NULL)
1533  return;
1534 
1535  buf = stringbuffer_new();
1536  stringbuffer_append_printf(buf, " *** %s ***\n", mon->name);
1537  describe_item(mon, NULL, 1, buf);
1540  free(result);
1541 
1542  /*
1543  * TODO: Add to player's knowledge. This is disabled for now because the
1544  * monster being probed could be custom, but when the player goes to query
1545  * their knowledge they will only get information about the monster's
1546  * archetype.
1547  knowledge_player *kp;
1548  kp = knowledge_get_or_create(op->contr);
1549  knowledge_add(kp, mon->name, &knowledges[1]);
1550  */
1551 }
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:353
knowledge_type::name
const char * name
Definition: knowledge.cpp:138
give.next
def next
Definition: give.py:44
Face
Definition: face.h:14
PLAYER
@ PLAYER
Definition: object.h:112
output_file.h
SockList_AddInt
void SockList_AddInt(SockList *sl, uint32_t data)
Definition: lowlevel.cpp:127
global.h
knowledge_send_info
void knowledge_send_info(socket_struct *ns)
Definition: knowledge.cpp:1374
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:624
GeneralMessage
Definition: book.h:44
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:58
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:594
TAG_END
#define TAG_END
Definition: knowledge.cpp:70
knowledge_god_validate
static int knowledge_god_validate(const char *item)
Definition: knowledge.cpp:706
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
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:1280
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:1528
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:300
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:728
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:157
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:1133
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
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
archetype::head
archetype * head
Definition: object.h:483
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
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:191
FLAG_INV_LOCKED
#define FLAG_INV_LOCKED
Definition: define.h:329
SockList_Reset
void SockList_Reset(SockList *sl)
Definition: lowlevel.cpp:74
object_get_value
const char * object_get_value(const object *op, const char *const key)
Definition: object.cpp:4342
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:1565
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:550
knowledge_summary
void(* knowledge_summary)(const char *code, StringBuffer *buf)
Definition: knowledge.cpp:80
TAG_START
#define TAG_START
Definition: knowledge.cpp:69
linked_char
Definition: global.h:96
knowledge_god_summary
static void knowledge_god_summary(const char *item, StringBuffer *buf)
Definition: knowledge.cpp:661
SockList_Avail
size_t SockList_Avail(const SockList *sl)
Definition: lowlevel.cpp:246
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:882
knowledge_god_face
static const Face * knowledge_god_face(sstring code)
Definition: knowledge.cpp:774
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
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:833
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:1252
query_name
void query_name(const object *op, char *buf, size_t size)
Definition: item.cpp:588
stringbuffer_finish_shared
sstring stringbuffer_finish_shared(StringBuffer *sb)
Definition: stringbuffer.cpp:85
Face::number
uint16_t number
Definition: face.h:15
archetype::clone
object clone
Definition: object.h:485
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:1163
knowledge_type::type
const char * type
Definition: knowledge.cpp:133
navar-midane_pickup.msg
list msg
Definition: navar-midane_pickup.py:13
object::type
uint8_t type
Definition: object.h:348
knowledge_give
void knowledge_give(player *pl, const char *marker, const object *book)
Definition: knowledge.cpp:996
recipe::index
int index
Definition: recipe.h:18
command_help
void command_help(object *op, const char *params)
Definition: c_misc.cpp:1772
CFweardisguise.tag
tag
Definition: CFweardisguise.py:25
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:581
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:481
sproto.h
get_message_body
sstring get_message_body(const GeneralMessage *message)
Definition: readable.cpp:2077
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:1298
knowledge_type::validate
knowledge_is_valid_item validate
Definition: knowledge.cpp:136
SockList_Init
void SockList_Init(SockList *sl)
Definition: lowlevel.cpp:55
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
fatal
void fatal(enum fatal_error err)
Definition: utils.cpp:587
knowledge_get_or_create
static knowledge_player * knowledge_get_or_create(const player *pl)
Definition: knowledge.cpp:968
knowledge_item_can_be_used_alchemy
void knowledge_item_can_be_used_alchemy(object *op, const object *item)
Definition: knowledge.cpp:1334
recipe::ingred_count
int ingred_count
Definition: recipe.h:23
env
static std::shared_ptr< inja::Environment > env
Definition: mapper.cpp:2168
knowledges
static const knowledge_type knowledges[]
Definition: knowledge.cpp:853
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:1056
describe_item
StringBuffer * describe_item(const object *op, const object *owner, int use_media_tags, StringBuffer *buf)
Definition: item.cpp:951
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:1423
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:65
Settings::playerdir
const char * playerdir
Definition: global.h:250
RANDOM
#define RANDOM()
Definition: define.h:644
StringBuffer
Definition: stringbuffer.cpp:25
recipe
Definition: recipe.h:10
knowledge_item
Definition: knowledge.cpp:147
ST_PLAYING
#define ST_PLAYING
Definition: define.h:541
command_knowledge
void command_knowledge(object *pl, const char *params)
Definition: knowledge.cpp:1213
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:802
NDI_UNIQUE
#define NDI_UNIQUE
Definition: newclient.h:251
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:2068
knowledge_find
static const knowledge_type * knowledge_find(const char *type)
Definition: knowledge.cpp:867
item
Definition: item.py:1
mapstruct
Definition: map.h:313
knowledge_monster_detail
static void knowledge_monster_detail(const char *item, StringBuffer *buf)
Definition: knowledge.cpp:595
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:842
knowledge_do_display
static void knowledge_do_display(object *pl, const knowledge_type *show_only, const char *search)
Definition: knowledge.cpp:1068
recipe::diff
int diff
Definition: recipe.h:16
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:1403
npc_dialog.index
int index
Definition: npc_dialog.py:102
knowledge_god_detail
static void knowledge_god_detail(const char *item, StringBuffer *buf)
Definition: knowledge.cpp:677
knowledge_monster_face
static const Face * knowledge_monster_face(sstring code)
Definition: knowledge.cpp:646
knowledge_do_attempt
static void knowledge_do_attempt(object *pl, const char *params)
Definition: knowledge.cpp:1189
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:1271
draw_ext_info
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
Definition: main.cpp:308
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:610
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:913
knowledge_message_detail
static void knowledge_message_detail(const char *value, StringBuffer *buf)
Definition: knowledge.cpp:818
knowledge_alchemy_validate
static int knowledge_alchemy_validate(const char *item)
Definition: knowledge.cpp:288
archetype::name
sstring name
Definition: object.h:482
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:1439
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
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:514
OUT_OF_MEMORY
@ OUT_OF_MEMORY
Definition: define.h:48
examine
void examine(object *op, object *tmp)
Definition: c_object.cpp:1985
altar_valkyrie.pl
pl
Definition: altar_valkyrie.py:28
Send_With_Handling
void Send_With_Handling(socket_struct *ns, SockList *sl)
Definition: lowlevel.cpp:447
MSG_TYPE_ADMIN
#define MSG_TYPE_ADMIN
Definition: newclient.h:391
knowledge_player
Definition: knowledge.cpp:153
SockList
Definition: newclient.h:670
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:2086
recipe_get_difficulty_string
const char * recipe_get_difficulty_string(int difficulty)
Definition: recipe.cpp:962
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:202
knowledge_known
static int knowledge_known(const knowledge_player *current, const char *item, const knowledge_type *kt)
Definition: knowledge.cpp:532
give.name
name
Definition: give.py:27
put_object_in_sack
void put_object_in_sack(object *op, object *sack, object *tmp, uint32_t nrof)
Definition: c_object.cpp:937
OutputFile
Definition: output_file.h:41
recipe::cauldron
sstring cauldron
Definition: recipe.h:27
recipe::title
sstring title
Definition: recipe.h:11
Settings::localdir
const char * localdir
Definition: global.h:249