Crossfire Server, Trunk  R21226
knowledge.c
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 struct knowledge_player;
69 struct knowledge_type;
70 
76 typedef void (*knowledge_summary)(const char *code, StringBuffer *buf);
77 
83 typedef void (*knowledge_detail)(const char *code, StringBuffer *buf);
84 
90 typedef int (*knowledge_is_valid_item)(const char *code);
91 
100 typedef int (*knowledge_add_item)(struct knowledge_player *current, const char *item, const struct knowledge_type *type, player *pl);
101 
110 typedef StringBuffer* (*knowledge_can_use_alchemy)(sstring code, const char *item, StringBuffer *buf, int index);
111 
117 typedef unsigned (*knowledge_face)(sstring code);
118 
119 struct knowledge_item;
120 
126 typedef void (*knowledge_attempt)(player *pl, const struct knowledge_item *item);
127 
129 typedef struct knowledge_type {
130  const char *type;
135  const char *name;
138  const char *face;
141 
142 
144 typedef struct knowledge_item {
148 
150 typedef struct knowledge_player {
159 
162 
163 
169 static const recipe* knowledge_alchemy_get_recipe(const char *value) {
170  const recipe *rec;
171  recipelist *rl;
172  int count, index;
173  const char *dot;
174 
175  dot = strchr(value, ':');
176  if (!dot) {
177  /* warn? */
178  return NULL;
179  }
180 
181  count = atoi(value);
182  index = atoi(dot + 1);
183  dot = strchr(dot + 1, ':');
184  if (!dot)
185  /* warn? */
186  return NULL;
187  dot++;
188 
189  rl = get_formulalist(count);
190  rec = rl->items;
191  while (rec) {
192  if (rec->index == index && strcmp(rec->title, dot) == 0)
193  return rec;
194 
195  rec = rec->next;
196  }
197 
198  return NULL;
199 }
200 
207 static void knowledge_alchemy_summary(const char *value, StringBuffer *buf) {
208  const recipe *rec = knowledge_alchemy_get_recipe(value);
209  const archetype *arch;
210 
211  if (!rec)
212  /* warn? */
213  return;
214 
215  arch = find_archetype(rec->arch_name[RANDOM()%rec->arch_names]);
216  if (!arch)
217  /* not supposed to happen */
218  return;
219 
220  if (strcmp(rec->title, "NONE"))
221  stringbuffer_append_printf(buf, "%s of %s", arch->clone.name, rec->title);
222  else {
223  if (arch->clone.title != NULL) {
224  stringbuffer_append_printf(buf, "%s %s", arch->clone.name, arch->clone.title);
225  }
226  else
227  stringbuffer_append_printf(buf, "%s", arch->clone.name);
228  }
229 }
230 
237 static void knowledge_alchemy_detail(const char *value, StringBuffer *buf) {
238  const recipe *rec = knowledge_alchemy_get_recipe(value);
239  const linked_char *next;
240  const archetype *arch;
241  char name[MAX_BUF];
242 
243 
244  if (!rec)
245  /* warn? */
246  return;
247 
248  arch = find_archetype(rec->arch_name[RANDOM()%rec->arch_names]);
249  if (!arch)
250  /* not supposed to happen */
251  return;
252 
253  if (strcmp(rec->title, "NONE"))
254  stringbuffer_append_printf(buf, "The %s of %s", arch->clone.name, rec->title);
255  else {
256  if (arch->clone.title != NULL) {
257  stringbuffer_append_printf(buf, "The %s %s", arch->clone.name, arch->clone.title);
258  }
259  else
260  stringbuffer_append_printf(buf, "The %s", arch->clone.name);
261  }
262 
263  arch = find_archetype(rec->cauldron);
264  if (arch)
265  query_name(&arch->clone, name, MAX_BUF);
266  else
267  snprintf(name, sizeof(name), "an unknown place");
268 
269  stringbuffer_append_printf(buf, " is made at %s and uses the following ingredients:", name);
270 
271  for (next = rec->ingred; next != NULL; next = next->next) {
272  stringbuffer_append_printf(buf, "\n - %s", next->name);
273  }
274 
275 }
276 
282 static int knowledge_alchemy_validate(const char *item) {
283  return knowledge_alchemy_get_recipe(item) != NULL;
284 }
285 
294 static StringBuffer* knowledge_alchemy_can_use_item(sstring code, const char *item, StringBuffer *buf, int index) {
295  const recipe *rec = knowledge_alchemy_get_recipe(code);
296  const linked_char *next;
297  const archetype *arch;
298  const char *name;
299 
300  if (!rec)
301  /* warn? */
302  return buf;
303 
304  arch = find_archetype(rec->arch_name[RANDOM()%rec->arch_names]);
305  if (!arch)
306  /* not supposed to happen */
307  return buf;
308 
309  for (next = rec->ingred; next != NULL; next = next->next) {
310  name = next->name;
311  while ((*name) != '\0' && (isdigit(*name) || (*name) == ' '))
312  name++;
313 
314  if (strcmp(item, name) == 0) {
315  if (buf == NULL) {
316  buf = stringbuffer_new();
317  stringbuffer_append_string(buf, "It can be used in the following recipes: ");
318  } else
319  stringbuffer_append_string(buf, ", ");
320 
321  if (strcmp(rec->title, "NONE"))
322  stringbuffer_append_printf(buf, "%s of %s", arch->clone.name, rec->title);
323  else {
324  if (arch->clone.title != NULL) {
325  stringbuffer_append_printf(buf, "%s %s", arch->clone.name, arch->clone.title);
326  }
327  else
328  stringbuffer_append_printf(buf, "%s", arch->clone.name);
329  }
330  stringbuffer_append_printf(buf, " (%d)", index);
331 
332  break;
333  }
334  }
335 
336  return buf;
337 }
338 
344 static void knowledge_alchemy_attempt(player *pl, const knowledge_item *item) {
345  const recipe *rp = knowledge_alchemy_get_recipe(item->item);
346  object *cauldron = NULL, *inv;
347  object *ingredients[50];
348  int index, x, y;
349  uint32_t count, counts[50];
350  char name[MAX_BUF];
351  const char *ingname;
352  linked_char *ing;
353  tag_t cauldron_tag;
354  mapstruct *map;
355 
356  if (!rp) {
357  LOG(llevError, "knowledge: couldn't find recipe for %s", item->item);
358  return;
359  }
360 
361  if (rp->ingred_count > 50) {
362  LOG(llevError, "knowledge: recipe %s has more than 50 ingredients!", item->item);
363  draw_ext_info(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, "This recipe is too complicated.");
364  return;
365  }
366 
367  /* first, check for a cauldron */
368  for (cauldron = pl->ob->below; cauldron; cauldron = cauldron->below) {
369  if (strcmp(rp->cauldron, cauldron->arch->name) == 0)
370  break;
371  }
372 
373  if (cauldron == NULL) {
374  draw_ext_info_format(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, "You are not on a %s", rp->cauldron);
375  return;
376  }
377 
378  cauldron_tag = cauldron->count;
379 
380  /* find ingredients in player's inventory */
381  for (index = 0; index < 50; index++) {
382  ingredients[index] = NULL;
383  }
384  for (inv = pl->ob->inv; inv != NULL; inv = inv->below) {
385 
386  if (QUERY_FLAG(inv, FLAG_INV_LOCKED) || QUERY_FLAG(inv, FLAG_STARTEQUIP) /*|| (need_identify(inv) && !QUERY_FLAG(inv, FLAG_IDENTIFIED))*/)
387  continue;
388 
389  if (inv->title == NULL)
390  safe_strncpy(name, inv->name, sizeof(name));
391  else
392  snprintf(name, sizeof(name), "%s %s", inv->name, inv->title);
393 
394  index = 0;
395  for (ing = rp->ingred; ing != NULL; ing = ing->next) {
396 
397  if (ingredients[index] != NULL) {
398  index++;
399  continue;
400  }
401 
402  ingname = ing->name;
403  count = 0;
404  while (isdigit(*ingname)) {
405  count = 10 * count + (*ingname - '0');
406  ingname++;
407  }
408  if (count == 0)
409  count = 1;
410  while (*ingname == ' ')
411  ingname++;
412 
413  if (strcmp(name, ingname) == 0 && ((inv->nrof == 0 && count == 1) || (inv->nrof >= count))) {
414  ingredients[index] = inv;
415  counts[index] = count;
416  break;
417  }
418 
419  index++;
420  }
421  }
422 
423  index = 0;
424  for (ing = rp->ingred; ing != NULL; ing = ing->next) {
425  if (ingredients[index] == NULL) {
426  draw_ext_info_format(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, "You don't have %s.", ing->name);
427  return;
428  }
429 
430  index++;
431  }
432 
433  /* ensure cauldron is applied */
434  if (pl->ob->container != cauldron) {
436  if (pl->ob->container != cauldron) {
437  draw_ext_info_format(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, "Couldn't activate the %s.", rp->cauldron);
438  return;
439  }
440  }
441 
442  /* ensure cauldron is empty */
443  while (cauldron->inv != NULL) {
444  inv = cauldron->inv;
445  command_take(pl->ob, "");
446  if (cauldron->inv == inv) {
447  draw_ext_info_format(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, "Couldn't empty the %s", rp->cauldron);
448  return;
449  }
450  }
451 
452  /* drop ingredients */
453  for (index = 0; index < rp->ingred_count; index++) {
454  tag_t tag = ingredients[index]->count;
455  count = ingredients[index]->nrof;
456  put_object_in_sack(pl->ob, cauldron, ingredients[index], counts[index]);
457  if (object_was_destroyed(ingredients[index], tag)) {
458  draw_ext_info(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, "Hum, some item disappeared, stopping the attempt.");
459  return;
460 
461  }
462  if (count == ingredients[index]->nrof && ingredients[index]->env == pl->ob) {
463  draw_ext_info(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, "Hum, couldn't drop some items, stopping the attempt.");
464  return;
465  }
466  }
467 
468  map = pl->ob->map;
469  x = pl->ob->x;
470  y = pl->ob->y;
471 
472  /* do alchemy */
473  use_alchemy(pl->ob);
474 
475  /* don't forget to slow the player: 1 for alchemy, 1 for each ingredient put,
476  * ingrediants taken are handler when picking */
477  pl->ob->speed_left -= 1.0 * (rp->ingred_count + 1);
478 
479  /* safety: ensure cauldron is still there, and player is still above */
480  if (object_was_destroyed(cauldron, cauldron_tag) || map != pl->ob->map || x != pl->ob->x || y != pl->ob->y) {
481  return;
482  }
483 
484  /* get back the result */
485  while (cauldron->inv) {
486  inv = cauldron->inv;
487  examine(pl->ob, inv);
488  command_take(pl->ob, "");
489  pl->ob->speed_left -= 1.0;
490  if (inv == cauldron->inv)
491  break;
492  }
493 }
494 
500 static unsigned knowledge_alchemy_face(sstring code) {
501  const recipe *rp = knowledge_alchemy_get_recipe(code);
502  const artifact *art;
503  archetype *arch;
504  object *item;
505  unsigned face;
506 
507  if (!rp) {
508  LOG(llevError, "knowledge: couldn't find recipe for %s", code);
509  return (unsigned)-1;
510  }
511 
512  if (rp->arch_names == 0)
513  return (unsigned)-1;
514 
515  arch = find_archetype(rp->arch_name[0]);
516  if (arch == NULL) {
517  return -1;
518  }
519  if (strcmp(rp->title, "NONE") == 0) {
520  return arch->clone.face->number;
521  }
522 
523  art = locate_recipe_artifact(rp, 0);
524  if (art == NULL)
525  return arch->clone.face->number;
526 
527  face = arch->clone.face->number;
528  item = arch_to_object(arch);
529  give_artifact_abilities(item, art->item);
531  if (item->face != NULL && item->face != blank_face)
532  face = item->face->number;
534 
535  return face;
536 }
537 
545 static int knowledge_known(const knowledge_player *current, const char *item, const knowledge_type *kt) {
546  int i;
547  for (i = 0; i < current->item_count; i++) {
548  if (strcmp(kt->type, current->items[i]->handler->type) == 0 && strcmp(item, current->items[i]->item) == 0) {
549  /* already known, bailout */
550  return 1;
551  }
552  }
553  return 0;
554 }
555 
564 static int knowledge_add(knowledge_player *current, const char *item, const knowledge_type *kt, player *pl) {
565  knowledge_item *check;
566 
567  if (knowledge_known(current, item, kt)) {
568  return 0;
569  }
570 
571  /* keep the knowledge */
576  check = malloc(sizeof(knowledge_item));
577  check->item = add_string(item);
578  check->handler = kt;
579  if (current->item_count >= current->item_allocated) {
580  current->item_allocated += 10;
581  current->items = realloc(current->items, current->item_allocated * sizeof(knowledge_item*));
582  }
583  current->items[current->item_count] = check;
584  current->item_count++;
585 
586  return 1;
587 }
588 
595 static void knowledge_monster_summary(const char *item, StringBuffer *buf) {
596  archetype *monster = find_archetype(item);
597  if (!monster)
598  return;
599 
600  stringbuffer_append_printf(buf, "%s", monster->clone.name);
601 }
602 
609 static void knowledge_monster_detail(const char *item, StringBuffer *buf) {
610  archetype *monster = find_archetype(item);
611 
612  if (!monster)
613  return;
614 
615  stringbuffer_append_printf(buf, " *** %s ***\n", monster->clone.name);
616  describe_item(&monster->clone, NULL, 1, buf);
617 }
618 
624 static int knowledge_monster_validate(const char *item) {
625  const archetype *monster = try_find_archetype(item);
626  if (monster == NULL || monster->clone.type != 0)
627  return 0;
628  return 1;
629 }
630 
639 static int knowledge_monster_add(struct knowledge_player *current, const char *item, const struct knowledge_type *type, player *pl) {
640  char *dup = strdup_local(item);
641  char *pos, *first = dup;
642  int added = 0;
643 
644  while (first) {
645  pos = strchr(first, ':');
646  if (pos)
647  *pos = '\0';
648  added += knowledge_add(current, first, type, pl);
649  first = pos ? pos + 1 : NULL;
650  }
651 
652  free(dup);
653  return added;
654 }
655 
661 static unsigned knowledge_monster_face(sstring code) {
662  const archetype *monster = find_archetype(code);
663 
664  if (!monster || monster->clone.face == blank_face || monster->clone.face == NULL)
665  return (unsigned)-1;
666 
667  return monster->clone.face->number;
668 }
669 
676 static void knowledge_god_summary(const char *item, StringBuffer *buf) {
677  char *dup = strdup_local(item), *pos = strchr(dup, ':');
678 
679  if (pos)
680  *pos = '\0';
681 
682  stringbuffer_append_printf(buf, "%s [god]", dup);
683  free(dup);
684 }
685 
692 static void knowledge_god_detail(const char *item, StringBuffer *buf) {
693  char *dup = strdup_local(item), *pos = strchr(dup, ':');
694  const archetype *god;
695  int what;
696 
697  if (!pos) {
698  LOG(llevError, "knowledge_god_detail: invalid god item %s\n", item);
699  free(dup);
700  return;
701  }
702 
703  *pos = '\0';
704  what = atoi(pos + 1);
706  free(dup);
707 
708  if (!god) {
709  LOG(llevError, "knowledge_god_detail: couldn't find god %s?\n", item);
710  return;
711  }
712 
713  describe_god(&god->clone, what, buf, 0);
714 }
715 
721 static int knowledge_god_validate(const char *item) {
722  char *dup = strdup_local(item), *pos = strchr(dup, ':');
723  int valid;
724 
725  if (!pos) {
726  LOG(llevError, "knowledge_god_validate: invalid god item %s\n", item);
727  free(dup);
728  return 0;
729  }
730  *pos = '\0';
731  valid = find_archetype_by_object_name(dup) != NULL;
732  free(dup);
733  return valid;
734 }
735 
744 static int knowledge_god_add(struct knowledge_player *current, const char *item, const struct knowledge_type *type, player *pl) {
745  char *dup = strdup_local(item), *pos = strchr(dup, ':');
746  StringBuffer *buf;
747  int what, i;
748  knowledge_item* check;
749 
750  if (!pos) {
751  LOG(llevError, "knowledge_god_add: invalid god item %s\n", item);
752  free(dup);
753  return 0;
754  }
755 
756  *pos = '\0';
757  what = atoi(pos + 1);
758 
759  for (i = 0; i < current->item_count; i++) {
760  check = current->items[i];
761  if (check->handler != type)
762  /* Only consider our own type. */
763  continue;
764  if (strncmp(check->item, dup, strlen(dup)) == 0) {
765  /* Already known, update information. */
766  int known, result;
767  pos = strchr(check->item, ':');
768  known = atoi(pos + 1);
769  result = known | what;
770  buf = stringbuffer_new();
771  stringbuffer_append_printf(buf, "%s:%d", dup, result);
772  free_string(check->item);
773  check->item = stringbuffer_finish_shared(buf);
774  free(dup);
775  return (result != known);
776  }
777  }
778 
779  free(dup);
780 
781  /* Not known, so just add it regularly. */
782  return knowledge_add(current, item, type, pl);
783 }
784 
790 static unsigned knowledge_god_face(sstring code) {
791  char buf[MAX_BUF];
792  size_t letter;
793  const archetype *altar_arch;
794 
795  snprintf(buf, MAX_BUF, "altar_");
796  letter = strlen(buf);
797  strncpy(buf+letter, code, MAX_BUF-letter);
798  for (; letter < strlen(buf); letter++) {
799  if (buf[letter] == ':') {
800  buf[letter] = '\0';
801  break;
802  }
803  buf[letter] = tolower(buf[letter]);
804  }
805  altar_arch = find_archetype(buf);
806  if (altar_arch == NULL)
807  return (unsigned)-1;
808 
809  return altar_arch->clone.face->number;
810 }
811 
818 static void knowledge_message_summary(const char *value, StringBuffer *buf) {
819  const GeneralMessage *msg = get_message_from_identifier(value);
820 
821  if (!msg)
822  /* warn? */
823  return;
824 
826 }
827 
834 static void knowledge_message_detail(const char *value, StringBuffer *buf) {
835  const GeneralMessage *msg = get_message_from_identifier(value);
836 
837  if (!msg)
838  /* warn? */
839  return;
840 
842 }
843 
849 static int knowledge_message_validate(const char *item) {
850  return get_message_from_identifier(item) != NULL;
851 }
852 
858 static unsigned knowledge_message_face(sstring code) {
859  const GeneralMessage *msg = get_message_from_identifier(code);
860 
861  if (!msg)
862  /* warn? */
863  return -1;
864 
865  return get_message_face(msg);
866 }
867 
869 static const knowledge_type knowledges[] = {
871  { "monster", knowledge_monster_summary, knowledge_monster_detail, knowledge_monster_validate, knowledge_monster_add, "monsters", NULL, NULL, "knowledge_monsters.111", knowledge_monster_face },
872  { "god", knowledge_god_summary, knowledge_god_detail, knowledge_god_validate, knowledge_god_add, "gods", NULL, NULL, "knowledge_gods.111", knowledge_god_face },
873  { "message", knowledge_message_summary, knowledge_message_detail, knowledge_message_validate, knowledge_add, "messages", NULL, NULL, "knowledge_messages.111", knowledge_message_face },
874  { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
875 };
876 
877 
883 static const knowledge_type *knowledge_find(const char *type) {
884  int i = 0;
885  while (knowledges[i].type != NULL) {
886  if (strcmp(knowledges[i].type, type) == 0)
887  return &knowledges[i];
888  i++;
889  }
890 
891  return NULL;
892 }
893 
899  FILE *file;
900  OutputFile of;
901  char fname[MAX_BUF];
902  const knowledge_item *item;
903  int i;
904 
905  snprintf(fname, sizeof(fname), "%s/%s/%s/%s.knowledge", settings.localdir, settings.playerdir, kp->player_name, kp->player_name);
906 
907  file = of_open(&of, fname);
908  if (!file) {
909  draw_ext_info(NDI_UNIQUE | NDI_ALL_DMS, 0, NULL, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_LOADSAVE, "File write error on server!");
910  return;
911  }
912 
913  for (i = 0; i < kp->item_count; i++) {
914  item = kp->items[i];
915  fprintf(file, "%s:%s\n", item->handler->type, item->item);
916  }
917 
918  if (!of_close(&of)) {
919  draw_ext_info(NDI_UNIQUE | NDI_ALL_DMS, 0, NULL, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_LOADSAVE, "File write error on server!");
920  return;
921  }
923 }
924 
930  FILE *file;
931  char final[MAX_BUF], read[MAX_BUF], *dot;
932  knowledge_item *item;
933  const knowledge_type *type;
934 
935  snprintf(final, sizeof(final), "%s/%s/%s/%s.knowledge", settings.localdir, settings.playerdir, kp->player_name, kp->player_name);
936 
937  file = fopen(final, "r");
938  if (!file) {
939  /* no knowledge yet, no big deal */
940  return;
941  }
942 
943  while (fgets(read, sizeof(read), file) != NULL) {
944  if (strlen(read) > 0)
945  read[strlen(read) - 1] = '\0';
946 
947  dot = strchr(read, ':');
948  if (!dot) {
949  LOG(llevError, "knowledge: invalid line in file %s\n", final);
950  continue;
951  }
952 
953  *dot = '\0';
954 
955  type = knowledge_find(read);
956  if (!type) {
957  LOG(llevError, "knowledge: invalid type %s in file %s\n", read, final);
958  continue;
959  }
960  if (!type->validate(dot + 1)) {
961  LOG(llevDebug, "knowledge: ignoring now invalid %s in file %s\n", read, final);
962  continue;
963  }
964 
965  item = malloc(sizeof(knowledge_item));
966  item->item = add_string(dot + 1);
967  item->handler = type;
968  if (kp->item_count == kp->item_allocated) {
969  kp->item_allocated += 10;
970  kp->items = realloc(kp->items, kp->item_allocated * sizeof(knowledge_item*));
971  }
972  kp->items[kp->item_count] = item;
973  kp->item_count++;
974  }
975  fclose(file);
976 }
977 
986 
987  while (cur) {
988  if (cur->player_name == pl->ob->name)
989  return cur;
990  cur = cur->next;
991  }
992 
993  cur = calloc(1, sizeof(knowledge_player));
994  if (!cur)
996  cur->player_name = add_refcount(pl->ob->name);
997  cur->next = knowledge_global;
998  knowledge_global = cur;
999  /* read knowledge for this player */
1001  if (pl->socket.notifications < 2)
1002  cur->sent_up_to = -1;
1003  return cur;
1004 }
1005 
1012 void knowledge_give(player *pl, const char *marker, const object *book) {
1013  char *dot, *copy;
1014  const knowledge_type *type;
1015  int none, added = 0;
1017 
1018  /* process marker, find if already known */
1019  dot = strchr(marker, ':');
1020  if (dot == NULL)
1021  return;
1022 
1023  /* There will be a null terminator on marker, or strlen will segfault.
1024  * So, strncpy() will copy the null terminator.
1025  * Therefore, it is more efficient to use malloc than calloc here.
1026  */
1027  copy = malloc(strlen(marker) + 1);
1028  /* Also make sure we've gotten a valid pointer back before we copy. */
1029  if (!copy)
1031  strncpy(copy, marker, strlen(marker) + 1);
1032 
1033  dot = strchr(copy, ':');
1034  *dot = '\0';
1035  dot++;
1036 
1037  type = knowledge_find(copy);
1038  if (!type) {
1039  LOG(llevError, "knowledge: invalid marker type %s in %s\n", copy, book == NULL ? "(null)" : book->name);
1040  free(copy);
1041  return;
1042  }
1043 
1044  none = (current->items == NULL);
1045  if (type->validate(dot)) {
1046  added = type->add(current, dot, type, pl);
1047  }
1048  free(copy);
1049 
1050  if (added) {
1051  draw_ext_info(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_MISC, MSG_TYPE_CLIENT_NOTICE, "You write that down for future reference.");
1052  if (none) {
1053  /* first information ever written down, be nice and give hint to recover it. */
1054  draw_ext_info(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_MISC, MSG_TYPE_CLIENT_NOTICE, "Use the 'knowledge' command to browse what you write down (this message will not appear anymore).");
1055  }
1056  }
1057 
1058  if (pl->has_directory)
1059  knowledge_write_player_data(current);
1060 }
1061 
1067 void knowledge_read(player *pl, object *book) {
1068  sstring marker = object_get_value(book, "knowledge_marker");
1069  if (marker != NULL)
1070  knowledge_give(pl, marker, book);
1071 }
1072 
1079 static void knowledge_do_display(object *pl, const knowledge_type *show_only, const char *search) {
1080  knowledge_player *kp;
1081  knowledge_item *item;
1082  int header = 0, show, i;
1084  char *final;
1085 
1086  assert(search == NULL || search[0] != '\0');
1087 
1088  kp = knowledge_get_or_create(pl->contr);
1089  for (i = 0; i < kp->item_count; i++) {
1090  item = kp->items[i];
1091  show = 1;
1092 
1093  summary = stringbuffer_new();
1094  item->handler->summary(item->item, summary);
1095  final = stringbuffer_finish(summary);
1096 
1097  if (show_only != NULL && item->handler != show_only) {
1098  show = 0;
1099  }
1100  if (search != NULL && search[0] != '\0') {
1101  if (strstr(final, search) == NULL) {
1102  char *fd;
1104  item->handler->detail(item->item, detail);
1105  fd = stringbuffer_finish(detail);
1106  if (strstr(fd, search) == NULL)
1107  show = 0;
1108  free(fd);
1109  }
1110  }
1111 
1112  if (show == 1) {
1113  if (header == 0) {
1114  if (search != NULL)
1115  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);
1116  else if (show_only != NULL)
1117  draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_MISC, MSG_TYPE_CLIENT_NOTICE, "You have knowledge of those %s:", show_only->name);
1118  else
1119  draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_MISC, MSG_TYPE_CLIENT_NOTICE, "You have knowledge of:");
1120  header = 1;
1121  }
1122 
1123  draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_MISC, MSG_TYPE_CLIENT_NOTICE, "(%3d) %s", i + 1, final);
1124  }
1125 
1126  free(final);
1127  }
1128 
1129  if (header == 0) {
1130  if (search != NULL)
1131  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);
1132  else if (show_only != NULL)
1133  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);
1134  else
1135  draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_MISC, MSG_TYPE_CLIENT_NOTICE, "You don't know yet any relevant information.");
1136  }
1137 }
1138 
1144 static void knowledge_display(object *pl, const char *params) {
1145  const knowledge_type *show_only = NULL;
1146 
1147  if (params && params[0] == ' ') {
1148  const char *type = params + 1;
1149  int idx = 0;
1150  for (; knowledges[idx].type != NULL; idx++) {
1151  if (strcmp(knowledges[idx].name, type) == 0) {
1152  show_only = &knowledges[idx];
1153  break;
1154  }
1155  }
1156 
1157  if (show_only == NULL) {
1158  draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_MISC, MSG_TYPE_CLIENT_NOTICE, "Invalid type, valid types are:");
1159  for (idx = 0; knowledges[idx].type != NULL; idx++) {
1160  draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_MISC, MSG_TYPE_CLIENT_NOTICE, "- %s", knowledges[idx].name);
1161  }
1162  return;
1163  }
1164  }
1165 
1166  knowledge_do_display(pl, show_only, NULL);
1167 }
1168 
1174 static void knowledge_show(object *pl, const char *params) {
1175  knowledge_player *kp;
1176  knowledge_item *item;
1177  int count = atoi(params) - 1;
1178  StringBuffer *buf;
1179  char *final;
1180 
1181  kp = knowledge_get_or_create(pl->contr);
1182  if (count < 0 || count >= kp->item_count) {
1183  draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, "Invalid knowledge number");
1184  return;
1185  }
1186 
1187  item = kp->items[count];
1188  buf = stringbuffer_new();
1189  item->handler->detail(item->item, buf);
1190  final = stringbuffer_finish(buf);
1192  free(final);
1193 }
1194 
1200 static void knowledge_do_attempt(object *pl, const char *params) {
1201  knowledge_player *kp;
1202  knowledge_item *item;
1203  int count = atoi(params) - 1;
1204 
1205  kp = knowledge_get_or_create(pl->contr);
1206  if (count < 0 || count >= kp->item_count) {
1207  draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, "Invalid knowledge number");
1208  return;
1209  }
1210 
1211  item = kp->items[count];
1212  if (item->handler->attempt_alchemy == NULL) {
1213  draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, "You can't do anything with that knowledge.");
1214  } else {
1215  item->handler->attempt_alchemy(pl->contr, item);
1216  }
1217 }
1218 
1224 void command_knowledge(object *pl, const char *params) {
1225 
1226  if (!pl->contr) {
1227  LOG(llevError, "command_knowledge: called for %s not a player!\n", pl->name);
1228  return;
1229  }
1230 
1231  if (!params || *params == '\0') {
1232  command_help(pl, "knowledge");
1233  return;
1234  }
1235 
1236  if (strncmp(params, "list", 4) == 0) {
1237  knowledge_display(pl, params + 4);
1238  return;
1239  }
1240 
1241  if (strncmp(params, "search ", 7) == 0) {
1242  knowledge_do_display(pl, NULL, params + 7);
1243  return;
1244  }
1245 
1246  if (strncmp(params, "show ", 5) == 0) {
1247  knowledge_show(pl, params + 5);
1248  return;
1249  }
1250 
1251  if (strncmp(params, "attempt ", 8) == 0) {
1252  knowledge_do_attempt(pl, params + 8);
1253  return;
1254  }
1255 
1256  command_help(pl, "knowledge");
1257 }
1258 
1264  knowledge_item *item;
1265  int i;
1266 
1267  for (i = 0; i < kp->item_count; i++) {
1268  item = kp->items[i];
1269  free_string(item->item);
1270  free(item);
1271  }
1272  free(kp->items);
1273  kp->items = NULL;
1274  kp->item_count = 0;
1275  kp->item_allocated = 0;
1276 }
1277 
1284  free_string(kp->player_name);
1285  free(kp);
1286 }
1287 
1291 void free_knowledge(void) {
1292  knowledge_player *kp, *next;
1293 
1294  kp = knowledge_global;
1295  while (kp) {
1296  next = kp->next;
1298  kp = next;
1299  }
1300  knowledge_global = NULL;
1301 }
1302 
1309 int knowledge_player_knows(const player *pl, const char *knowledge) {
1310  const knowledge_type *type;
1311  char copy[MAX_BUF], *pos;
1312  const knowledge_player *current;
1313 
1314  if (strlen(knowledge) >= MAX_BUF - 1) {
1315  LOG(llevError, "knowledge_player_knows: too long knowledge %s\n", knowledge);
1316  return 0;
1317  }
1318 
1319  strlcpy(copy, knowledge, sizeof(copy));
1320  pos = strchr(copy, ':');
1321  if (pos == NULL) {
1322  LOG(llevError, "knowledge_player_knows: invalid knowledge item %s\n", knowledge);
1323  return 0;
1324  }
1325 
1326  *pos = '\0';
1327  pos++;
1328 
1329  type = knowledge_find(copy);
1330  if (type == NULL) {
1331  LOG(llevError, "knowledge_player_knows: invalid knowledge type %s\n", knowledge);
1332  return 0;
1333  }
1334 
1335  current = knowledge_get_or_create(pl);
1336 
1337  return knowledge_known(current, pos, type);
1338 }
1339 
1345 void knowledge_item_can_be_used_alchemy(object *op, const object *item) {
1346  knowledge_player *cur;
1347  knowledge_item *ki;
1348  char item_name[MAX_BUF], *result;
1349  const char *name;
1350  StringBuffer *buf = NULL;
1351  int i;
1352 
1353  if (op->type != PLAYER || op->contr == NULL)
1354  return;
1355 
1356  cur = knowledge_get_or_create(op->contr);
1357 
1358  if (item->title != NULL) {
1359  snprintf(item_name, sizeof(item_name), "%s %s", item->name, item->title);
1360  name = item_name;
1361  } else
1362  name = item->name;
1363 
1364  for (i = 0; i < cur->item_count; i++) {
1365  ki = cur->items[i];
1366  if (ki->handler->use_alchemy != NULL) {
1367  buf = ki->handler->use_alchemy(ki->item, name, buf, i + 1);
1368  }
1369  }
1370 
1371  if (buf == NULL)
1372  return;
1373 
1374  stringbuffer_append_string(buf, ".");
1375  result = stringbuffer_finish(buf);
1377  result);
1378  free(result);
1379 }
1380 
1386  int i;
1387  unsigned face;
1388  SockList sl;
1389 
1390  face = find_face("knowledge_generic.111", (unsigned)-1);
1391  if (face != (unsigned)-1 && (!(ns->faces_sent[face] & NS_FACESENT_FACE)))
1392  esrv_send_face(ns, face, 0);
1393 
1394  SockList_Init(&sl);
1395  SockList_AddString(&sl, "replyinfo knowledge_info\n");
1396  SockList_AddPrintf(&sl, "::%u:0\n", face);
1397 
1398  for (i = 0; knowledges[i].type != NULL; i++) {
1399  face = find_face(knowledges[i].face, (unsigned)-1);
1400  if (face != (unsigned)-1 && (!(ns->faces_sent[face] & NS_FACESENT_FACE)))
1401  esrv_send_face(ns, face, 0);
1402 
1403  SockList_AddPrintf(&sl, "%s:%s:%u:%s\n", knowledges[i].type, knowledges[i].name, face, knowledges[i].attempt_alchemy != NULL ? "1" : "0");
1404  }
1405 
1406  Send_With_Handling(ns, &sl);
1407  SockList_Term(&sl);
1408 }
1409 
1415  knowledge_player *kp;
1416 
1417  if (pl->socket.notifications < 2)
1418  return;
1419 
1420  /* merely loading the knowledge will mark it as to be sent through knowledge_process_incremental(),
1421  * but we need to reset the sent_up_to field if eg the player was the last one to leave
1422  * then joins again - no knowledge processing is done at that point. */
1423  kp = knowledge_get_or_create(pl);
1424  kp->sent_up_to = 0;
1425 }
1426 
1436 
1437  while (cur) {
1438  if (cur->player_name == pl->ob->name) {
1440  }
1441  cur = cur->next;
1442  }
1443 
1444 }
1445 
1451  int i, last;
1452  SockList sl;
1453  size_t size;
1454  const knowledge_item *item;
1455  StringBuffer *buf;
1456  char *title;
1457  unsigned face;
1458  knowledge_player *cur = knowledge_global, *prev = NULL;
1459  player *pl;
1460 
1461  while (cur) {
1462 
1463  for (pl = first_player; pl != NULL; pl = pl->next) {
1464  if (pl->ob->name == cur->player_name) {
1465  break;
1466  }
1467  }
1468 
1469  /* player left, remove knowledge */
1470  if (pl == NULL) {
1471  if (prev == NULL) {
1472  knowledge_global = cur->next;
1473  } else {
1474  prev->next = cur->next;
1475  }
1476 
1477  free_knowledge_player(cur);
1478 
1479  /* wait until next tick to do something else */
1480  return;
1481  }
1482 
1483  if (cur->sent_up_to == -1 || cur->sent_up_to == cur->item_count) {
1484  prev = cur;
1485  cur = cur->next;
1486  continue;
1487  }
1488 
1489  last = MIN(cur->sent_up_to + 50, cur->item_count);
1490  SockList_Init(&sl);
1491  SockList_AddString(&sl, "addknowledge ");
1492  for (i = cur->sent_up_to; i < last; i++) {
1493  item = cur->items[i];
1494 
1495  buf = stringbuffer_new();
1496  item->handler->summary(item->item, buf);
1497  title = stringbuffer_finish(buf);
1498 
1499  face = (unsigned)-1;
1500  if (item->handler->item_face != NULL)
1501  face = item->handler->item_face(item->item);
1502 
1503  if (face == (unsigned)-1)
1504  face = find_face(item->handler->face, (unsigned)-1);
1505 
1506  size = 4 + (2 + strlen(item->handler->type)) + (2 + strlen(title)) + 4;
1507 
1508  if (SockList_Avail(&sl) < size) {
1509  Send_With_Handling(&pl->socket, &sl);
1510  SockList_Reset(&sl);
1511  SockList_AddString(&sl, "addknowledge ");
1512  }
1513 
1514  SockList_AddInt(&sl, i + 1);
1515  SockList_AddLen16Data(&sl, item->handler->type, strlen(item->handler->type));
1516  if ((face != (unsigned)-1) && !(pl->socket.faces_sent[face]&NS_FACESENT_FACE))
1517  esrv_send_face(&pl->socket, face, 0);
1518  SockList_AddLen16Data(&sl, title, strlen(title));
1519  SockList_AddInt(&sl, face);
1520 
1521  free(title);
1522  }
1523 
1524  cur->sent_up_to = last;
1525 
1526  Send_With_Handling(&pl->socket, &sl);
1527  SockList_Term(&sl);
1528 
1529  /* don't send more this tick */
1530  break;
1531  }
1532 }
1533 
1539 void knowledge_show_monster_detail(object *op, const char *name) {
1540  knowledge_player *kp;
1541  StringBuffer *buf = NULL;
1542  char *result;
1543 
1544  if (op->contr == NULL)
1545  return;
1546 
1547  kp = knowledge_get_or_create(op->contr);
1548 
1549  if (!knowledge_known(kp, name, &knowledges[1]))
1550  return;
1551 
1552  buf = stringbuffer_new();
1553  knowledge_monster_detail(name, buf);
1554  result = stringbuffer_finish(buf);
1556  free(result);
1557 }
void(* knowledge_summary)(const char *code, StringBuffer *buf)
Definition: knowledge.c:76
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...)
Definition: main.c:315
void apply_by_living_below(object *pl)
Definition: apply.c:614
int(* knowledge_add_item)(struct knowledge_player *current, const char *item, const struct knowledge_type *type, player *pl)
Definition: knowledge.c:100
void SockList_AddPrintf(SockList *sl, const char *format,...)
Definition: lowlevel.c:194
#define MSG_TYPE_MISC
Definition: newclient.h:389
Definition: player.h:92
archetype * find_archetype(const char *name)
Definition: arch.c:695
void object_free(object *ob, int flags)
Definition: object.c:1409
void SockList_Reset(SockList *sl)
Definition: lowlevel.c:66
void esrv_send_face(socket_struct *ns, uint16_t face_num, int nocache)
Definition: image.c:70
#define NS_FACESENT_FACE
Definition: newserver.h:137
const char * name
Definition: knowledge.c:135
void knowledge_process_incremental(void)
Definition: knowledge.c:1450
void SockList_Init(SockList *sl)
Definition: lowlevel.c:48
void object_give_identified_properties(object *op)
Definition: item.c:1370
void(* knowledge_attempt)(player *pl, const struct knowledge_item *item)
Definition: knowledge.c:126
sstring add_refcount(sstring str)
Definition: shstr.c:210
sstring get_message_title(const GeneralMessage *message)
Definition: readable.c:2251
struct knowledge_type knowledge_type
static const knowledge_type * knowledge_find(const char *type)
Definition: knowledge.c:883
static unsigned knowledge_god_face(sstring code)
Definition: knowledge.c:790
#define strdup_local
Definition: compat.h:25
struct obj * container
Definition: object.h:291
static int knowledge_add(knowledge_player *current, const char *item, const knowledge_type *kt, player *pl)
Definition: knowledge.c:564
sstring stringbuffer_finish_shared(StringBuffer *sb)
Definition: stringbuffer.c:85
void knowledge_read(player *pl, object *book)
Definition: knowledge.c:1067
uint32_t has_directory
Definition: player.h:134
void fatal(enum fatal_error err)
Definition: utils.c:597
StringBuffer * stringbuffer_new(void)
Definition: stringbuffer.c:57
static int knowledge_god_add(struct knowledge_player *current, const char *item, const struct knowledge_type *type, player *pl)
Definition: knowledge.c:744
const char * playerdir
Definition: global.h:244
static void free_knowledge_player(knowledge_player *kp)
Definition: knowledge.c:1282
void free_string(sstring str)
Definition: shstr.c:280
#define MSG_TYPE_COMMAND_EXAMINE
Definition: newclient.h:512
unsigned int get_message_face(const GeneralMessage *message)
Definition: readable.c:2269
const char * object_get_value(const object *op, const char *const key)
Definition: object.c:4266
void knowledge_give(player *pl, const char *marker, const object *book)
Definition: knowledge.c:1012
void knowledge_first_player_save(player *pl)
Definition: knowledge.c:1434
object clone
Definition: object.h:470
socket_struct socket
Definition: player.h:94
linked_char * ingred
Definition: recipe.h:22
void SockList_AddLen16Data(SockList *sl, const void *data, size_t len)
Definition: lowlevel.c:183
unsigned(* knowledge_face)(sstring code)
Definition: knowledge.c:117
#define FREE_OBJ_NO_DESTROY_CALLBACK
Definition: object.h:531
#define MSG_TYPE_ADMIN_LOADSAVE
Definition: newclient.h:477
void SockList_AddInt(SockList *sl, uint32_t data)
Definition: lowlevel.c:119
#define object_was_destroyed(op, old_tag)
Definition: object.h:68
void knowledge_send_info(socket_struct *ns)
Definition: knowledge.c:1385
#define safe_strncpy
Definition: compat.h:23
static void knowledge_alchemy_summary(const char *value, StringBuffer *buf)
Definition: knowledge.c:207
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
Definition: main.c:310
Definition: object.h:465
static void knowledge_do_display(object *pl, const knowledge_type *show_only, const char *search)
Definition: knowledge.c:1079
#define MIN(x, y)
Definition: compat.h:17
knowledge_face item_face
Definition: knowledge.c:139
static void knowledge_message_detail(const char *value, StringBuffer *buf)
Definition: knowledge.c:834
static void knowledge_monster_summary(const char *item, StringBuffer *buf)
Definition: knowledge.c:595
struct titlestruct title
static void knowledge_read_player_data(knowledge_player *kp)
Definition: knowledge.c:929
uint16_t number
Definition: face.h:15
int ingred_count
Definition: recipe.h:23
knowledge_detail detail
Definition: knowledge.c:132
uint16_t notifications
Definition: newserver.h:129
knowledge_attempt attempt_alchemy
Definition: knowledge.c:137
void free_knowledge(void)
Definition: knowledge.c:1291
const char * title
Definition: object.h:317
int16_t y
Definition: object.h:326
static int knowledge_monster_validate(const char *item)
Definition: knowledge.c:624
#define FREE_OBJ_FREE_INVENTORY
Definition: object.h:530
static void knowledge_do_attempt(object *pl, const char *params)
Definition: knowledge.c:1200
#define MSG_TYPE_COMMAND
Definition: newclient.h:379
const char * face
Definition: knowledge.c:138
const char * type
Definition: knowledge.c:130
sstring title
Definition: recipe.h:11
struct knowledge_item knowledge_item
void stringbuffer_append_string(StringBuffer *sb, const char *str)
Definition: stringbuffer.c:95
char ** arch_name
Definition: recipe.h:13
sstring player_name
Definition: knowledge.c:151
static knowledge_player * knowledge_get_or_create(const player *pl)
Definition: knowledge.c:984
float speed_left
Definition: object.h:329
#define MSG_TYPE_CLIENT_NOTICE
Definition: newclient.h:664
#define NDI_ALL_DMS
Definition: newclient.h:247
struct knowledge_player knowledge_player
void(* knowledge_detail)(const char *code, StringBuffer *buf)
Definition: knowledge.c:83
const artifact * locate_recipe_artifact(const recipe *rp, size_t idx)
Definition: recipe.c:664
struct mapdef * map
Definition: object.h:297
void SockList_Term(SockList *sl)
Definition: lowlevel.c:58
static int knowledge_god_validate(const char *item)
Definition: knowledge.c:721
knowledge_add_item add
Definition: knowledge.c:134
#define snprintf
Definition: win32.h:46
static void knowledge_message_summary(const char *value, StringBuffer *buf)
Definition: knowledge.c:818
const knowledge_type * handler
Definition: knowledge.c:146
struct linked_char * next
Definition: global.h:88
int of_close(OutputFile *of)
Definition: output_file.c:61
static void knowledge_alchemy_attempt(player *pl, const knowledge_item *item)
Definition: knowledge.c:344
struct knowledge_player * next
Definition: knowledge.c:157
const char * name
Definition: object.h:311
struct knowledge_item ** items
Definition: knowledge.c:152
knowledge_is_valid_item validate
Definition: knowledge.c:133
struct obj * below
Definition: object.h:287
archetype * find_archetype_by_object_name(const char *name)
Definition: arch.c:57
void knowledge_send_known(player *pl)
Definition: knowledge.c:1414
void SockList_AddString(SockList *sl, const char *data)
Definition: lowlevel.c:149
uint32_t nrof
Definition: object.h:333
knowledge_summary summary
Definition: knowledge.c:131
struct pl * contr
Definition: object.h:276
void examine(object *op, object *tmp)
Definition: c_object.c:1448
static void free_knowledge_items(knowledge_player *kp)
Definition: knowledge.c:1263
size_t SockList_Avail(const SockList *sl)
Definition: lowlevel.c:238
int describe_god(const object *god, int what, StringBuffer *buf, size_t maxlen)
Definition: holy.c:137
archetype * try_find_archetype(const char *name)
Definition: arch.c:666
uint32_t tag_t
Definition: object.h:12
#define QUERY_FLAG(xyz, p)
Definition: define.h:225
static int knowledge_alchemy_validate(const char *item)
Definition: knowledge.c:282
static unsigned knowledge_alchemy_face(sstring code)
Definition: knowledge.c:500
static void knowledge_alchemy_detail(const char *value, StringBuffer *buf)
Definition: knowledge.c:237
int index
Definition: recipe.h:18
static void knowledge_display(object *pl, const char *params)
Definition: knowledge.c:1144
#define MAX_BUF
Definition: define.h:35
static void knowledge_monster_detail(const char *item, StringBuffer *buf)
Definition: knowledge.c:609
void put_object_in_sack(object *op, object *sack, object *tmp, uint32_t nrof)
Definition: c_object.c:688
void give_artifact_abilities(object *op, const object *artifact)
Definition: artifact.c:203
static const knowledge_type knowledges[]
Definition: knowledge.c:869
#define MSG_TYPE_ADMIN
Definition: newclient.h:377
int16_t x
Definition: object.h:326
static knowledge_player * knowledge_global
Definition: knowledge.c:161
static int knowledge_message_validate(const char *item)
Definition: knowledge.c:849
void command_help(object *op, const char *params)
Definition: c_misc.c:1731
#define tolower(C)
Definition: c_new.c:29
static void knowledge_write_player_data(const knowledge_player *kp)
Definition: knowledge.c:898
void knowledge_item_can_be_used_alchemy(object *op, const object *item)
Definition: knowledge.c:1345
object * ob
Definition: player.h:158
const char * sstring
Definition: global.h:40
Definition: object.h:107
unsigned int uint32_t
Definition: win32.h:162
static void knowledge_god_detail(const char *item, StringBuffer *buf)
Definition: knowledge.c:692
const char * name
Definition: global.h:87
static StringBuffer * knowledge_alchemy_can_use_item(sstring code, const char *item, StringBuffer *buf, int index)
Definition: knowledge.c:294
StringBuffer * describe_item(const object *op, const object *owner, int use_media_tags, StringBuffer *buf)
Definition: item.c:975
#define RANDOM()
Definition: define.h:681
void command_knowledge(object *pl, const char *params)
Definition: knowledge.c:1224
int knowledge_player_knows(const player *pl, const char *knowledge)
Definition: knowledge.c:1309
New_Face * blank_face
Definition: image.c:39
const char * localdir
Definition: global.h:243
void command_take(object *op, const char *params)
Definition: c_object.c:595
tag_t count
Definition: object.h:299
struct archt * arch
Definition: object.h:412
size_t arch_names
Definition: recipe.h:12
uint8_t type
Definition: object.h:338
struct Settings settings
Definition: init.c:40
static int knowledge_monster_add(struct knowledge_player *current, const char *item, const struct knowledge_type *type, player *pl)
Definition: knowledge.c:639
FILE * of_open(OutputFile *of, const char *fname)
Definition: output_file.c:30
#define MSG_TYPE_COMMAND_INFO
Definition: newclient.h:506
sstring item
Definition: knowledge.c:145
const GeneralMessage * get_message_from_identifier(const char *identifier)
Definition: readable.c:2238
static const recipe * knowledge_alchemy_get_recipe(const char *value)
Definition: knowledge.c:169
struct recipestruct * next
Definition: recipe.h:24
sstring get_message_body(const GeneralMessage *message)
Definition: readable.c:2260
int(* knowledge_is_valid_item)(const char *code)
Definition: knowledge.c:90
#define FLAG_STARTEQUIP
Definition: define.h:268
sstring add_string(const char *str)
Definition: shstr.c:124
EXTERN player * first_player
Definition: global.h:117
void stringbuffer_append_printf(StringBuffer *sb, const char *format,...)
Definition: stringbuffer.c:104
struct pl * next
Definition: player.h:93
struct obj * inv
Definition: object.h:290
#define NDI_UNIQUE
Definition: newclient.h:245
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:51
static void knowledge_god_summary(const char *item, StringBuffer *buf)
Definition: knowledge.c:676
void query_name(const object *op, char *buf, size_t size)
Definition: item.c:623
object * item
Definition: artifact.h:15
Definition: map.h:325
const New_Face * face
Definition: object.h:332
StringBuffer *(* knowledge_can_use_alchemy)(sstring code, const char *item, StringBuffer *buf, int index)
Definition: knowledge.c:110
knowledge_can_use_alchemy use_alchemy
Definition: knowledge.c:136
#define FLAG_INV_LOCKED
Definition: define.h:330
unsigned find_face(const char *name, unsigned error)
Definition: image.c:303
object * arch_to_object(archetype *at)
Definition: arch.c:571
uint8_t * faces_sent
Definition: newserver.h:96
static int knowledge_known(const knowledge_player *current, const char *item, const knowledge_type *kt)
Definition: knowledge.c:545
sstring cauldron
Definition: recipe.h:27
const char * name
Definition: object.h:466
char * stringbuffer_finish(StringBuffer *sb)
Definition: stringbuffer.c:76
static unsigned knowledge_message_face(sstring code)
Definition: knowledge.c:858
size_t strlcpy(char *dst, const char *src, size_t size)
Definition: porting.c:366
void knowledge_show_monster_detail(object *op, const char *name)
Definition: knowledge.c:1539
struct recipestruct * items
Definition: recipe.h:40
recipelist * get_formulalist(int i)
Definition: recipe.c:96
static void knowledge_show(object *pl, const char *params)
Definition: knowledge.c:1174
static unsigned knowledge_monster_face(sstring code)
Definition: knowledge.c:661
void Send_With_Handling(socket_struct *ns, SockList *sl)
Definition: lowlevel.c:434