Crossfire Server, Trunk  R213250
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  copy = strdup(marker);
1024  if (!copy)
1026 
1027  dot = strchr(copy, ':');
1028  *dot = '\0';
1029  dot++;
1030 
1031  type = knowledge_find(copy);
1032  if (!type) {
1033  LOG(llevError, "knowledge: invalid marker type %s in %s\n", copy, book == NULL ? "(null)" : book->name);
1034  free(copy);
1035  return;
1036  }
1037 
1038  none = (current->items == NULL);
1039  if (type->validate(dot)) {
1040  added = type->add(current, dot, type, pl);
1041  }
1042  free(copy);
1043 
1044  if (added) {
1045  draw_ext_info(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_MISC, MSG_TYPE_CLIENT_NOTICE, "You write that down for future reference.");
1046  if (none) {
1047  /* first information ever written down, be nice and give hint to recover it. */
1048  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).");
1049  }
1050  }
1051 
1052  if (pl->has_directory)
1053  knowledge_write_player_data(current);
1054 }
1055 
1061 void knowledge_read(player *pl, object *book) {
1062  sstring marker = object_get_value(book, "knowledge_marker");
1063  if (marker != NULL)
1064  knowledge_give(pl, marker, book);
1065 }
1066 
1073 static void knowledge_do_display(object *pl, const knowledge_type *show_only, const char *search) {
1074  knowledge_player *kp;
1075  knowledge_item *item;
1076  int header = 0, show, i;
1078  char *final;
1079 
1080  assert(search == NULL || search[0] != '\0');
1081 
1082  kp = knowledge_get_or_create(pl->contr);
1083  for (i = 0; i < kp->item_count; i++) {
1084  item = kp->items[i];
1085  show = 1;
1086 
1087  summary = stringbuffer_new();
1088  item->handler->summary(item->item, summary);
1089  final = stringbuffer_finish(summary);
1090 
1091  if (show_only != NULL && item->handler != show_only) {
1092  show = 0;
1093  }
1094  if (search != NULL && search[0] != '\0') {
1095  if (strstr(final, search) == NULL) {
1096  char *fd;
1098  item->handler->detail(item->item, detail);
1099  fd = stringbuffer_finish(detail);
1100  if (strstr(fd, search) == NULL)
1101  show = 0;
1102  free(fd);
1103  }
1104  }
1105 
1106  if (show == 1) {
1107  if (header == 0) {
1108  if (search != NULL)
1109  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);
1110  else if (show_only != NULL)
1111  draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_MISC, MSG_TYPE_CLIENT_NOTICE, "You have knowledge of those %s:", show_only->name);
1112  else
1113  draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_MISC, MSG_TYPE_CLIENT_NOTICE, "You have knowledge of:");
1114  header = 1;
1115  }
1116 
1117  draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_MISC, MSG_TYPE_CLIENT_NOTICE, "(%3d) %s", i + 1, final);
1118  }
1119 
1120  free(final);
1121  }
1122 
1123  if (header == 0) {
1124  if (search != NULL)
1125  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);
1126  else if (show_only != NULL)
1127  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);
1128  else
1129  draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_MISC, MSG_TYPE_CLIENT_NOTICE, "You don't know yet any relevant information.");
1130  }
1131 }
1132 
1138 static void knowledge_display(object *pl, const char *params) {
1139  const knowledge_type *show_only = NULL;
1140 
1141  if (params && params[0] == ' ') {
1142  const char *type = params + 1;
1143  int idx = 0;
1144  for (; knowledges[idx].type != NULL; idx++) {
1145  if (strcmp(knowledges[idx].name, type) == 0) {
1146  show_only = &knowledges[idx];
1147  break;
1148  }
1149  }
1150 
1151  if (show_only == NULL) {
1152  draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_MISC, MSG_TYPE_CLIENT_NOTICE, "Invalid type, valid types are:");
1153  for (idx = 0; knowledges[idx].type != NULL; idx++) {
1154  draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_MISC, MSG_TYPE_CLIENT_NOTICE, "- %s", knowledges[idx].name);
1155  }
1156  return;
1157  }
1158  }
1159 
1160  knowledge_do_display(pl, show_only, NULL);
1161 }
1162 
1168 static void knowledge_show(object *pl, const char *params) {
1169  knowledge_player *kp;
1170  knowledge_item *item;
1171  int count = atoi(params) - 1;
1172  StringBuffer *buf;
1173  char *final;
1174 
1175  kp = knowledge_get_or_create(pl->contr);
1176  if (count < 0 || count >= kp->item_count) {
1177  draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, "Invalid knowledge number");
1178  return;
1179  }
1180 
1181  item = kp->items[count];
1182  buf = stringbuffer_new();
1183  item->handler->detail(item->item, buf);
1184  final = stringbuffer_finish(buf);
1186  free(final);
1187 }
1188 
1194 static void knowledge_do_attempt(object *pl, const char *params) {
1195  knowledge_player *kp;
1196  knowledge_item *item;
1197  int count = atoi(params) - 1;
1198 
1199  kp = knowledge_get_or_create(pl->contr);
1200  if (count < 0 || count >= kp->item_count) {
1201  draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, "Invalid knowledge number");
1202  return;
1203  }
1204 
1205  item = kp->items[count];
1206  if (item->handler->attempt_alchemy == NULL) {
1207  draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, "You can't do anything with that knowledge.");
1208  } else {
1209  item->handler->attempt_alchemy(pl->contr, item);
1210  }
1211 }
1212 
1218 void command_knowledge(object *pl, const char *params) {
1219 
1220  if (!pl->contr) {
1221  LOG(llevError, "command_knowledge: called for %s not a player!\n", pl->name);
1222  return;
1223  }
1224 
1225  if (!params || *params == '\0') {
1226  command_help(pl, "knowledge");
1227  return;
1228  }
1229 
1230  if (strncmp(params, "list", 4) == 0) {
1231  knowledge_display(pl, params + 4);
1232  return;
1233  }
1234 
1235  if (strncmp(params, "search ", 7) == 0) {
1236  knowledge_do_display(pl, NULL, params + 7);
1237  return;
1238  }
1239 
1240  if (strncmp(params, "show ", 5) == 0) {
1241  knowledge_show(pl, params + 5);
1242  return;
1243  }
1244 
1245  if (strncmp(params, "attempt ", 8) == 0) {
1246  knowledge_do_attempt(pl, params + 8);
1247  return;
1248  }
1249 
1250  command_help(pl, "knowledge");
1251 }
1252 
1258  knowledge_item *item;
1259  int i;
1260 
1261  for (i = 0; i < kp->item_count; i++) {
1262  item = kp->items[i];
1263  free_string(item->item);
1264  free(item);
1265  }
1266  free(kp->items);
1267  kp->items = NULL;
1268  kp->item_count = 0;
1269  kp->item_allocated = 0;
1270 }
1271 
1278  free_string(kp->player_name);
1279  free(kp);
1280 }
1281 
1285 void free_knowledge(void) {
1286  knowledge_player *kp, *next;
1287 
1288  kp = knowledge_global;
1289  while (kp) {
1290  next = kp->next;
1292  kp = next;
1293  }
1294  knowledge_global = NULL;
1295 }
1296 
1303 int knowledge_player_knows(const player *pl, const char *knowledge) {
1304  const knowledge_type *type;
1305  char copy[MAX_BUF], *pos;
1306  const knowledge_player *current;
1307 
1308  if (strlen(knowledge) >= MAX_BUF - 1) {
1309  LOG(llevError, "knowledge_player_knows: too long knowledge %s\n", knowledge);
1310  return 0;
1311  }
1312 
1313  strlcpy(copy, knowledge, sizeof(copy));
1314  pos = strchr(copy, ':');
1315  if (pos == NULL) {
1316  LOG(llevError, "knowledge_player_knows: invalid knowledge item %s\n", knowledge);
1317  return 0;
1318  }
1319 
1320  *pos = '\0';
1321  pos++;
1322 
1323  type = knowledge_find(copy);
1324  if (type == NULL) {
1325  LOG(llevError, "knowledge_player_knows: invalid knowledge type %s\n", knowledge);
1326  return 0;
1327  }
1328 
1329  current = knowledge_get_or_create(pl);
1330 
1331  return knowledge_known(current, pos, type);
1332 }
1333 
1339 void knowledge_item_can_be_used_alchemy(object *op, const object *item) {
1340  knowledge_player *cur;
1341  knowledge_item *ki;
1342  char item_name[MAX_BUF], *result;
1343  const char *name;
1344  StringBuffer *buf = NULL;
1345  int i;
1346 
1347  if (op->type != PLAYER || op->contr == NULL)
1348  return;
1349 
1350  cur = knowledge_get_or_create(op->contr);
1351 
1352  if (item->title != NULL) {
1353  snprintf(item_name, sizeof(item_name), "%s %s", item->name, item->title);
1354  name = item_name;
1355  } else
1356  name = item->name;
1357 
1358  for (i = 0; i < cur->item_count; i++) {
1359  ki = cur->items[i];
1360  if (ki->handler->use_alchemy != NULL) {
1361  buf = ki->handler->use_alchemy(ki->item, name, buf, i + 1);
1362  }
1363  }
1364 
1365  if (buf == NULL)
1366  return;
1367 
1368  stringbuffer_append_string(buf, ".");
1369  result = stringbuffer_finish(buf);
1371  result);
1372  free(result);
1373 }
1374 
1380  int i;
1381  unsigned face;
1382  SockList sl;
1383 
1384  face = find_face("knowledge_generic.111", (unsigned)-1);
1385  if (face != (unsigned)-1 && (!(ns->faces_sent[face] & NS_FACESENT_FACE)))
1386  esrv_send_face(ns, face, 0);
1387 
1388  SockList_Init(&sl);
1389  SockList_AddString(&sl, "replyinfo knowledge_info\n");
1390  SockList_AddPrintf(&sl, "::%u:0\n", face);
1391 
1392  for (i = 0; knowledges[i].type != NULL; i++) {
1393  face = find_face(knowledges[i].face, (unsigned)-1);
1394  if (face != (unsigned)-1 && (!(ns->faces_sent[face] & NS_FACESENT_FACE)))
1395  esrv_send_face(ns, face, 0);
1396 
1397  SockList_AddPrintf(&sl, "%s:%s:%u:%s\n", knowledges[i].type, knowledges[i].name, face, knowledges[i].attempt_alchemy != NULL ? "1" : "0");
1398  }
1399 
1400  Send_With_Handling(ns, &sl);
1401  SockList_Term(&sl);
1402 }
1403 
1409  knowledge_player *kp;
1410 
1411  if (pl->socket.notifications < 2)
1412  return;
1413 
1414  /* merely loading the knowledge will mark it as to be sent through knowledge_process_incremental(),
1415  * but we need to reset the sent_up_to field if eg the player was the last one to leave
1416  * then joins again - no knowledge processing is done at that point. */
1417  kp = knowledge_get_or_create(pl);
1418  kp->sent_up_to = 0;
1419 }
1420 
1430 
1431  while (cur) {
1432  if (cur->player_name == pl->ob->name) {
1434  }
1435  cur = cur->next;
1436  }
1437 
1438 }
1439 
1445  int i, last;
1446  SockList sl;
1447  size_t size;
1448  const knowledge_item *item;
1449  StringBuffer *buf;
1450  char *title;
1451  unsigned face;
1452  knowledge_player *cur = knowledge_global, *prev = NULL;
1453  player *pl;
1454 
1455  while (cur) {
1456 
1457  for (pl = first_player; pl != NULL; pl = pl->next) {
1458  if (pl->ob->name == cur->player_name) {
1459  break;
1460  }
1461  }
1462 
1463  /* player left, remove knowledge */
1464  if (pl == NULL) {
1465  if (prev == NULL) {
1466  knowledge_global = cur->next;
1467  } else {
1468  prev->next = cur->next;
1469  }
1470 
1471  free_knowledge_player(cur);
1472 
1473  /* wait until next tick to do something else */
1474  return;
1475  }
1476 
1477  if (cur->sent_up_to == -1 || cur->sent_up_to == cur->item_count) {
1478  prev = cur;
1479  cur = cur->next;
1480  continue;
1481  }
1482 
1483  last = MIN(cur->sent_up_to + 50, cur->item_count);
1484  SockList_Init(&sl);
1485  SockList_AddString(&sl, "addknowledge ");
1486  for (i = cur->sent_up_to; i < last; i++) {
1487  item = cur->items[i];
1488 
1489  buf = stringbuffer_new();
1490  item->handler->summary(item->item, buf);
1491  title = stringbuffer_finish(buf);
1492 
1493  face = (unsigned)-1;
1494  if (item->handler->item_face != NULL)
1495  face = item->handler->item_face(item->item);
1496 
1497  if (face == (unsigned)-1)
1498  face = find_face(item->handler->face, (unsigned)-1);
1499 
1500  size = 4 + (2 + strlen(item->handler->type)) + (2 + strlen(title)) + 4;
1501 
1502  if (SockList_Avail(&sl) < size) {
1503  Send_With_Handling(&pl->socket, &sl);
1504  SockList_Reset(&sl);
1505  SockList_AddString(&sl, "addknowledge ");
1506  }
1507 
1508  SockList_AddInt(&sl, i + 1);
1509  SockList_AddLen16Data(&sl, item->handler->type, strlen(item->handler->type));
1510  if ((face != (unsigned)-1) && !(pl->socket.faces_sent[face]&NS_FACESENT_FACE))
1511  esrv_send_face(&pl->socket, face, 0);
1512  SockList_AddLen16Data(&sl, title, strlen(title));
1513  SockList_AddInt(&sl, face);
1514 
1515  free(title);
1516  }
1517 
1518  cur->sent_up_to = last;
1519 
1520  Send_With_Handling(&pl->socket, &sl);
1521  SockList_Term(&sl);
1522 
1523  /* don't send more this tick */
1524  break;
1525  }
1526 }
1527 
1533 void knowledge_show_monster_detail(object *op, const char *name) {
1534  knowledge_player *kp;
1535  StringBuffer *buf = NULL;
1536  char *result;
1537 
1538  if (op->contr == NULL)
1539  return;
1540 
1541  kp = knowledge_get_or_create(op->contr);
1542 
1543  if (!knowledge_known(kp, name, &knowledges[1]))
1544  return;
1545 
1546  buf = stringbuffer_new();
1547  knowledge_monster_detail(name, buf);
1548  result = stringbuffer_finish(buf);
1550  free(result);
1551 }
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:316
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:1444
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:1061
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:250
static void free_knowledge_player(knowledge_player *kp)
Definition: knowledge.c:1276
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:4265
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:1428
object clone
Definition: object.h:472
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:533
#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:1379
#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:311
Definition: object.h:467
static void knowledge_do_display(object *pl, const knowledge_type *show_only, const char *search)
Definition: knowledge.c:1073
#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:1285
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:532
static void knowledge_do_attempt(object *pl, const char *params)
Definition: knowledge.c:1194
#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:665
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:1408
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:1257
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:1138
#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:1791
#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:1339
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:1218
int knowledge_player_knows(const player *pl, const char *knowledge)
Definition: knowledge.c:1303
New_Face * blank_face
Definition: image.c:39
const char * localdir
Definition: global.h:249
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:414
size_t arch_names
Definition: recipe.h:12
uint8_t type
Definition: object.h:339
struct Settings settings
Definition: init.c:39
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
char * strdup(const char *str)
Definition: porting.c:200
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:468
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:1533
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:1168
static unsigned knowledge_monster_face(sstring code)
Definition: knowledge.c:661
void Send_With_Handling(socket_struct *ns, SockList *sl)
Definition: lowlevel.c:435