Crossfire Server, Trunk  R20513
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 (strcmp(rp->title, "NONE") == 0) {
517  return arch->clone.face->number;
518  }
519 
520  art = locate_recipe_artifact(rp, 0);
521  if (art == NULL)
522  return arch->clone.face->number;
523 
524  face = arch->clone.face->number;
525  item = arch_to_object(arch);
526  give_artifact_abilities(item, art->item);
528  if (item->face != NULL && item->face != blank_face)
529  face = item->face->number;
531 
532  return face;
533 }
534 
542 static int knowledge_known(const knowledge_player *current, const char *item, const knowledge_type *kt) {
543  int i;
544  for (i = 0; i < current->item_count; i++) {
545  if (strcmp(kt->type, current->items[i]->handler->type) == 0 && strcmp(item, current->items[i]->item) == 0) {
546  /* already known, bailout */
547  return 1;
548  }
549  }
550  return 0;
551 }
552 
561 static int knowledge_add(knowledge_player *current, const char *item, const knowledge_type *kt, player *pl) {
562  knowledge_item *check;
563 
564  if (knowledge_known(current, item, kt)) {
565  return 0;
566  }
567 
568  /* keep the knowledge */
573  check = malloc(sizeof(knowledge_item));
574  check->item = add_string(item);
575  check->handler = kt;
576  if (current->item_count >= current->item_allocated) {
577  current->item_allocated += 10;
578  current->items = realloc(current->items, current->item_allocated * sizeof(knowledge_item*));
579  }
580  current->items[current->item_count] = check;
581  current->item_count++;
582 
583  return 1;
584 }
585 
592 static void knowledge_monster_summary(const char *item, StringBuffer *buf) {
593  archetype *monster = find_archetype(item);
594  if (!monster)
595  return;
596 
597  stringbuffer_append_printf(buf, "%s", monster->clone.name);
598 }
599 
606 static void knowledge_monster_detail(const char *item, StringBuffer *buf) {
607  archetype *monster = find_archetype(item);
608 
609  if (!monster)
610  return;
611 
612  stringbuffer_append_printf(buf, " *** %s ***\n", monster->clone.name);
613  describe_item(&monster->clone, NULL, 1, buf);
614 }
615 
621 static int knowledge_monster_validate(const char *item) {
622  const archetype *monster = try_find_archetype(item);
623  if (monster == NULL || monster->clone.type != 0)
624  return 0;
625  return 1;
626 }
627 
636 static int knowledge_monster_add(struct knowledge_player *current, const char *item, const struct knowledge_type *type, player *pl) {
637  char *dup = strdup_local(item);
638  char *pos, *first = dup;
639  int added = 0;
640 
641  while (first) {
642  pos = strchr(first, ':');
643  if (pos)
644  *pos = '\0';
645  added += knowledge_add(current, first, type, pl);
646  first = pos ? pos + 1 : NULL;
647  }
648 
649  free(dup);
650  return added;
651 }
652 
658 static unsigned knowledge_monster_face(sstring code) {
659  const archetype *monster = find_archetype(code);
660 
661  if (!monster || monster->clone.face == blank_face || monster->clone.face == NULL)
662  return (unsigned)-1;
663 
664  return monster->clone.face->number;
665 }
666 
673 static void knowledge_god_summary(const char *item, StringBuffer *buf) {
674  char *dup = strdup_local(item), *pos = strchr(dup, ':');
675 
676  if (pos)
677  *pos = '\0';
678 
679  stringbuffer_append_printf(buf, "%s [god]", dup);
680  free(dup);
681 }
682 
689 static void knowledge_god_detail(const char *item, StringBuffer *buf) {
690  char *dup = strdup_local(item), *pos = strchr(dup, ':');
691  const archetype *god;
692  int what;
693 
694  if (!pos) {
695  LOG(llevError, "knowledge_god_detail: invalid god item %s\n", item);
696  free(dup);
697  return;
698  }
699 
700  *pos = '\0';
701  what = atoi(pos + 1);
703  free(dup);
704 
705  if (!god) {
706  LOG(llevError, "knowledge_god_detail: couldn't find god %s?\n", item);
707  return;
708  }
709 
710  describe_god(&god->clone, what, buf, 0);
711 }
712 
718 static int knowledge_god_validate(const char *item) {
719  char *dup = strdup_local(item), *pos = strchr(dup, ':');
720  int valid;
721 
722  if (!pos) {
723  LOG(llevError, "knowledge_god_validate: invalid god item %s\n", item);
724  free(dup);
725  return 0;
726  }
727  *pos = '\0';
728  valid = find_archetype_by_object_name(dup) != NULL;
729  free(dup);
730  return valid;
731 }
732 
741 static int knowledge_god_add(struct knowledge_player *current, const char *item, const struct knowledge_type *type, player *pl) {
742  char *dup = strdup_local(item), *pos = strchr(dup, ':');
743  StringBuffer *buf;
744  int what, i;
745  knowledge_item* check;
746 
747  if (!pos) {
748  LOG(llevError, "knowledge_god_add: invalid god item %s\n", item);
749  free(dup);
750  return 0;
751  }
752 
753  *pos = '\0';
754  what = atoi(pos + 1);
755 
756  for (i = 0; i < current->item_count; i++) {
757  check = current->items[i];
758  if (check->handler != type)
759  /* Only consider our own type. */
760  continue;
761  if (strncmp(check->item, dup, strlen(dup)) == 0) {
762  /* Already known, update information. */
763  int known, result;
764  pos = strchr(check->item, ':');
765  known = atoi(pos + 1);
766  result = known | what;
767  buf = stringbuffer_new();
768  stringbuffer_append_printf(buf, "%s:%d", dup, result);
769  free_string(check->item);
770  check->item = stringbuffer_finish_shared(buf);
771  free(dup);
772  return (result != known);
773  }
774  }
775 
776  free(dup);
777 
778  /* Not known, so just add it regularly. */
779  return knowledge_add(current, item, type, pl);
780 }
781 
787 static unsigned knowledge_god_face(sstring code) {
788  char buf[MAX_BUF];
789  size_t letter;
790  const archetype *altar_arch;
791 
792  snprintf(buf, MAX_BUF, "altar_");
793  letter = strlen(buf);
794  strncpy(buf+letter, code, MAX_BUF-letter);
795  for (; letter < strlen(buf); letter++) {
796  if (buf[letter] == ':') {
797  buf[letter] = '\0';
798  break;
799  }
800  buf[letter] = tolower(buf[letter]);
801  }
802  altar_arch = find_archetype(buf);
803  if (altar_arch == NULL)
804  return (unsigned)-1;
805 
806  return altar_arch->clone.face->number;
807 }
808 
815 static void knowledge_message_summary(const char *value, StringBuffer *buf) {
816  const GeneralMessage *msg = get_message_from_identifier(value);
817 
818  if (!msg)
819  /* warn? */
820  return;
821 
823 }
824 
831 static void knowledge_message_detail(const char *value, StringBuffer *buf) {
832  const GeneralMessage *msg = get_message_from_identifier(value);
833 
834  if (!msg)
835  /* warn? */
836  return;
837 
839 }
840 
846 static int knowledge_message_validate(const char *item) {
847  return get_message_from_identifier(item) != NULL;
848 }
849 
855 static unsigned knowledge_message_face(sstring code) {
856  const GeneralMessage *msg = get_message_from_identifier(code);
857 
858  if (!msg)
859  /* warn? */
860  return -1;
861 
862  return get_message_face(msg);
863 }
864 
866 static const knowledge_type knowledges[] = {
868  { "monster", knowledge_monster_summary, knowledge_monster_detail, knowledge_monster_validate, knowledge_monster_add, "monsters", NULL, NULL, "knowledge_monsters.111", knowledge_monster_face },
869  { "god", knowledge_god_summary, knowledge_god_detail, knowledge_god_validate, knowledge_god_add, "gods", NULL, NULL, "knowledge_gods.111", knowledge_god_face },
870  { "message", knowledge_message_summary, knowledge_message_detail, knowledge_message_validate, knowledge_add, "messages", NULL, NULL, "knowledge_messages.111", knowledge_message_face },
871  { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
872 };
873 
874 
880 static const knowledge_type *knowledge_find(const char *type) {
881  int i = 0;
882  while (knowledges[i].type != NULL) {
883  if (strcmp(knowledges[i].type, type) == 0)
884  return &knowledges[i];
885  i++;
886  }
887 
888  return NULL;
889 }
890 
896  FILE *file;
897  OutputFile of;
898  char fname[MAX_BUF];
899  const knowledge_item *item;
900  int i;
901 
902  snprintf(fname, sizeof(fname), "%s/%s/%s/%s.knowledge", settings.localdir, settings.playerdir, kp->player_name, kp->player_name);
903 
904  file = of_open(&of, fname);
905  if (!file) {
906  draw_ext_info(NDI_UNIQUE | NDI_ALL_DMS, 0, NULL, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_LOADSAVE, "File write error on server!");
907  return;
908  }
909 
910  for (i = 0; i < kp->item_count; i++) {
911  item = kp->items[i];
912  fprintf(file, "%s:%s\n", item->handler->type, item->item);
913  }
914 
915  if (!of_close(&of)) {
916  draw_ext_info(NDI_UNIQUE | NDI_ALL_DMS, 0, NULL, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_LOADSAVE, "File write error on server!");
917  return;
918  }
920 }
921 
927  FILE *file;
928  char final[MAX_BUF], read[MAX_BUF], *dot;
929  knowledge_item *item;
930  const knowledge_type *type;
931 
932  snprintf(final, sizeof(final), "%s/%s/%s/%s.knowledge", settings.localdir, settings.playerdir, kp->player_name, kp->player_name);
933 
934  file = fopen(final, "r");
935  if (!file) {
936  /* no knowledge yet, no big deal */
937  return;
938  }
939 
940  while (fgets(read, sizeof(read), file) != NULL) {
941  if (strlen(read) > 0)
942  read[strlen(read) - 1] = '\0';
943 
944  dot = strchr(read, ':');
945  if (!dot) {
946  LOG(llevError, "knowledge: invalid line in file %s\n", final);
947  continue;
948  }
949 
950  *dot = '\0';
951 
952  type = knowledge_find(read);
953  if (!type) {
954  LOG(llevError, "knowledge: invalid type %s in file %s\n", read, final);
955  continue;
956  }
957  if (!type->validate(dot + 1)) {
958  LOG(llevDebug, "knowledge: ignoring now invalid %s in file %s\n", read, final);
959  continue;
960  }
961 
962  item = malloc(sizeof(knowledge_item));
963  item->item = add_string(dot + 1);
964  item->handler = type;
965  if (kp->item_count == kp->item_allocated) {
966  kp->item_allocated += 10;
967  kp->items = realloc(kp->items, kp->item_allocated * sizeof(knowledge_item*));
968  }
969  kp->items[kp->item_count] = item;
970  kp->item_count++;
971  }
972  fclose(file);
973 }
974 
983 
984  while (cur) {
985  if (cur->player_name == pl->ob->name)
986  return cur;
987  cur = cur->next;
988  }
989 
990  cur = calloc(1, sizeof(knowledge_player));
991  if (!cur)
993  cur->player_name = add_refcount(pl->ob->name);
994  cur->next = knowledge_global;
995  knowledge_global = cur;
996  /* read knowledge for this player */
998  if (pl->socket.notifications < 2)
999  cur->sent_up_to = -1;
1000  return cur;
1001 }
1002 
1009 void knowledge_give(player *pl, const char *marker, const object *book) {
1010  char *dot, *copy;
1011  const knowledge_type *type;
1012  int none, added = 0;
1014 
1015  /* process marker, find if already known */
1016  dot = strchr(marker, ':');
1017  if (dot == NULL)
1018  return;
1019 
1020  /* There will be a null terminator on marker, or strlen will segfault.
1021  * So, strncpy() will copy the null terminator.
1022  * Therefore, it is more efficient to use malloc than calloc here.
1023  */
1024  copy = malloc(strlen(marker) + 1);
1025  /* Also make sure we've gotten a valid pointer back before we copy. */
1026  if (!copy)
1028  strncpy(copy, marker, strlen(marker) + 1);
1029 
1030  dot = strchr(copy, ':');
1031  *dot = '\0';
1032  dot++;
1033 
1034  type = knowledge_find(copy);
1035  if (!type) {
1036  LOG(llevError, "knowledge: invalid marker type %s in %s\n", copy, book == NULL ? "(null)" : book->name);
1037  free(copy);
1038  return;
1039  }
1040 
1041  none = (current->items == NULL);
1042  if (type->validate(dot)) {
1043  added = type->add(current, dot, type, pl);
1044  }
1045  free(copy);
1046 
1047  if (added) {
1048  draw_ext_info(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_MISC, MSG_TYPE_CLIENT_NOTICE, "You write that down for future reference.");
1049  if (none) {
1050  /* first information ever written down, be nice and give hint to recover it. */
1051  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).");
1052  }
1053  }
1054 
1055  if (pl->has_directory)
1056  knowledge_write_player_data(current);
1057 }
1058 
1064 void knowledge_read(player *pl, object *book) {
1065  sstring marker = object_get_value(book, "knowledge_marker");
1066  if (marker != NULL)
1067  knowledge_give(pl, marker, book);
1068 }
1069 
1076 static void knowledge_do_display(object *pl, const knowledge_type *show_only, const char *search) {
1077  knowledge_player *kp;
1078  knowledge_item *item;
1079  int header = 0, show, i;
1081  char *final;
1082 
1083  assert(search == NULL || search[0] != '\0');
1084 
1085  kp = knowledge_get_or_create(pl->contr);
1086  for (i = 0; i < kp->item_count; i++) {
1087  item = kp->items[i];
1088  show = 1;
1089 
1090  summary = stringbuffer_new();
1091  item->handler->summary(item->item, summary);
1092  final = stringbuffer_finish(summary);
1093 
1094  if (show_only != NULL && item->handler != show_only) {
1095  show = 0;
1096  }
1097  if (search != NULL && search[0] != '\0') {
1098  if (strstr(final, search) == NULL) {
1099  char *fd;
1101  item->handler->detail(item->item, detail);
1102  fd = stringbuffer_finish(detail);
1103  if (strstr(fd, search) == NULL)
1104  show = 0;
1105  free(fd);
1106  }
1107  }
1108 
1109  if (show == 1) {
1110  if (header == 0) {
1111  if (search != NULL)
1112  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);
1113  else if (show_only != NULL)
1114  draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_MISC, MSG_TYPE_CLIENT_NOTICE, "You have knowledge of those %s:", show_only->name);
1115  else
1116  draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_MISC, MSG_TYPE_CLIENT_NOTICE, "You have knowledge of:");
1117  header = 1;
1118  }
1119 
1120  draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_MISC, MSG_TYPE_CLIENT_NOTICE, "(%3d) %s", i + 1, final);
1121  }
1122 
1123  free(final);
1124  }
1125 
1126  if (header == 0) {
1127  if (search != NULL)
1128  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);
1129  else if (show_only != NULL)
1130  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);
1131  else
1132  draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_MISC, MSG_TYPE_CLIENT_NOTICE, "You don't know yet any relevant information.");
1133  }
1134 }
1135 
1141 static void knowledge_display(object *pl, const char *params) {
1142  const knowledge_type *show_only = NULL;
1143 
1144  if (params && params[0] == ' ') {
1145  const char *type = params + 1;
1146  int idx = 0;
1147  for (; knowledges[idx].type != NULL; idx++) {
1148  if (strcmp(knowledges[idx].name, type) == 0) {
1149  show_only = &knowledges[idx];
1150  break;
1151  }
1152  }
1153 
1154  if (show_only == NULL) {
1155  draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_MISC, MSG_TYPE_CLIENT_NOTICE, "Invalid type, valid types are:");
1156  for (idx = 0; knowledges[idx].type != NULL; idx++) {
1157  draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_MISC, MSG_TYPE_CLIENT_NOTICE, "- %s", knowledges[idx].name);
1158  }
1159  return;
1160  }
1161  }
1162 
1163  knowledge_do_display(pl, show_only, NULL);
1164 }
1165 
1171 static void knowledge_show(object *pl, const char *params) {
1172  knowledge_player *kp;
1173  knowledge_item *item;
1174  int count = atoi(params) - 1;
1175  StringBuffer *buf;
1176  char *final;
1177 
1178  kp = knowledge_get_or_create(pl->contr);
1179  if (count < 0 || count >= kp->item_count) {
1180  draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, "Invalid knowledge number");
1181  return;
1182  }
1183 
1184  item = kp->items[count];
1185  buf = stringbuffer_new();
1186  item->handler->detail(item->item, buf);
1187  final = stringbuffer_finish(buf);
1189  free(final);
1190 }
1191 
1197 static void knowledge_do_attempt(object *pl, const char *params) {
1198  knowledge_player *kp;
1199  knowledge_item *item;
1200  int count = atoi(params) - 1;
1201 
1202  kp = knowledge_get_or_create(pl->contr);
1203  if (count < 0 || count >= kp->item_count) {
1204  draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, "Invalid knowledge number");
1205  return;
1206  }
1207 
1208  item = kp->items[count];
1209  if (item->handler->attempt_alchemy == NULL) {
1210  draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, "You can't do anything with that knowledge.");
1211  } else {
1212  item->handler->attempt_alchemy(pl->contr, item);
1213  }
1214 }
1215 
1221 void command_knowledge(object *pl, const char *params) {
1222 
1223  if (!pl->contr) {
1224  LOG(llevError, "command_knowledge: called for %s not a player!\n", pl->name);
1225  return;
1226  }
1227 
1228  if (!params || *params == '\0') {
1229  command_help(pl, "knowledge");
1230  return;
1231  }
1232 
1233  if (strncmp(params, "list", 4) == 0) {
1234  knowledge_display(pl, params + 4);
1235  return;
1236  }
1237 
1238  if (strncmp(params, "search ", 7) == 0) {
1239  knowledge_do_display(pl, NULL, params + 7);
1240  return;
1241  }
1242 
1243  if (strncmp(params, "show ", 5) == 0) {
1244  knowledge_show(pl, params + 5);
1245  return;
1246  }
1247 
1248  if (strncmp(params, "attempt ", 8) == 0) {
1249  knowledge_do_attempt(pl, params + 8);
1250  return;
1251  }
1252 
1253  command_help(pl, "knowledge");
1254 }
1255 
1261  knowledge_item *item;
1262  int i;
1263 
1264  for (i = 0; i < kp->item_count; i++) {
1265  item = kp->items[i];
1266  free_string(item->item);
1267  free(item);
1268  }
1269  free(kp->items);
1270  kp->items = NULL;
1271  kp->item_count = 0;
1272  kp->item_allocated = 0;
1273 }
1274 
1281  free_string(kp->player_name);
1282  free(kp);
1283 }
1284 
1288 void free_knowledge(void) {
1289  knowledge_player *kp, *next;
1290 
1291  kp = knowledge_global;
1292  while (kp) {
1293  next = kp->next;
1295  kp = next;
1296  }
1297  knowledge_global = NULL;
1298 }
1299 
1306 int knowledge_player_knows(const player *pl, const char *knowledge) {
1307  const knowledge_type *type;
1308  char copy[MAX_BUF], *pos;
1309  const knowledge_player *current;
1310 
1311  if (strlen(knowledge) >= MAX_BUF - 1) {
1312  LOG(llevError, "knowledge_player_knows: too long knowledge %s\n", knowledge);
1313  return 0;
1314  }
1315 
1316  snprintf(copy, sizeof(copy), "%s", knowledge);
1317  pos = strchr(copy, ':');
1318  if (pos == NULL) {
1319  LOG(llevError, "knowledge_player_knows: invalid knowledge item %s\n", knowledge);
1320  return 0;
1321  }
1322 
1323  *pos = '\0';
1324  pos++;
1325 
1326  type = knowledge_find(copy);
1327  if (type == NULL) {
1328  LOG(llevError, "knowledge_player_knows: invalid knowledge type %s\n", knowledge);
1329  return 0;
1330  }
1331 
1332  current = knowledge_get_or_create(pl);
1333 
1334  return knowledge_known(current, pos, type);
1335 }
1336 
1342 void knowledge_item_can_be_used_alchemy(object *op, const object *item) {
1343  knowledge_player *cur;
1344  knowledge_item *ki;
1345  char item_name[MAX_BUF], *result;
1346  const char *name;
1347  StringBuffer *buf = NULL;
1348  int i;
1349 
1350  if (op->type != PLAYER || op->contr == NULL)
1351  return;
1352 
1353  cur = knowledge_get_or_create(op->contr);
1354 
1355  if (item->title != NULL) {
1356  snprintf(item_name, sizeof(item_name), "%s %s", item->name, item->title);
1357  name = item_name;
1358  } else
1359  name = item->name;
1360 
1361  for (i = 0; i < cur->item_count; i++) {
1362  ki = cur->items[i];
1363  if (ki->handler->use_alchemy != NULL) {
1364  buf = ki->handler->use_alchemy(ki->item, name, buf, i + 1);
1365  }
1366  }
1367 
1368  if (buf == NULL)
1369  return;
1370 
1371  stringbuffer_append_string(buf, ".");
1372  result = stringbuffer_finish(buf);
1374  result);
1375  free(result);
1376 }
1377 
1383  int i;
1384  unsigned face;
1385  SockList sl;
1386 
1387  face = find_face("knowledge_generic.111", (unsigned)-1);
1388  if (face != (unsigned)-1 && (!ns->faces_sent[face] & NS_FACESENT_FACE))
1389  esrv_send_face(ns, face, 0);
1390 
1391  SockList_Init(&sl);
1392  SockList_AddString(&sl, "replyinfo knowledge_info\n");
1393  SockList_AddPrintf(&sl, "::%u:0\n", face);
1394 
1395  for (i = 0; knowledges[i].type != NULL; i++) {
1396  face = find_face(knowledges[i].face, (unsigned)-1);
1397  if (face != (unsigned)-1 && (!ns->faces_sent[face] & NS_FACESENT_FACE))
1398  esrv_send_face(ns, face, 0);
1399 
1400  SockList_AddPrintf(&sl, "%s:%s:%u:%s\n", knowledges[i].type, knowledges[i].name, face, knowledges[i].attempt_alchemy != NULL ? "1" : "0");
1401  }
1402 
1403  Send_With_Handling(ns, &sl);
1404  SockList_Term(&sl);
1405 }
1406 
1412  knowledge_player *kp;
1413 
1414  if (pl->socket.notifications < 2)
1415  return;
1416 
1417  /* merely loading the knowledge will mark it as to be sent through knowledge_process_incremental(),
1418  * but we need to reset the sent_up_to field if eg the player was the last one to leave
1419  * then joins again - no knowledge processing is done at that point. */
1420  kp = knowledge_get_or_create(pl);
1421  kp->sent_up_to = 0;
1422 }
1423 
1433 
1434  while (cur) {
1435  if (cur->player_name == pl->ob->name) {
1437  }
1438  cur = cur->next;
1439  }
1440 
1441 }
1442 
1448  int i, last;
1449  SockList sl;
1450  size_t size;
1451  const knowledge_item *item;
1452  StringBuffer *buf;
1453  char *title;
1454  unsigned face;
1455  knowledge_player *cur = knowledge_global, *prev = NULL;
1456  player *pl;
1457 
1458  while (cur) {
1459 
1460  for (pl = first_player; pl != NULL; pl = pl->next) {
1461  if (pl->ob->name == cur->player_name) {
1462  break;
1463  }
1464  }
1465 
1466  /* player left, remove knowledge */
1467  if (pl == NULL) {
1468  if (prev == NULL) {
1469  knowledge_global = cur->next;
1470  } else {
1471  prev->next = cur->next;
1472  }
1473 
1474  free_knowledge_player(cur);
1475 
1476  /* wait until next tick to do something else */
1477  return;
1478  }
1479 
1480  if (cur->sent_up_to == -1 || cur->sent_up_to == cur->item_count) {
1481  prev = cur;
1482  cur = cur->next;
1483  continue;
1484  }
1485 
1486  last = MIN(cur->sent_up_to + 50, cur->item_count);
1487  SockList_Init(&sl);
1488  SockList_AddString(&sl, "addknowledge ");
1489  for (i = cur->sent_up_to; i < last; i++) {
1490  item = cur->items[i];
1491 
1492  buf = stringbuffer_new();
1493  item->handler->summary(item->item, buf);
1494  title = stringbuffer_finish(buf);
1495 
1496  face = (unsigned)-1;
1497  if (item->handler->item_face != NULL)
1498  face = item->handler->item_face(item->item);
1499 
1500  if (face == (unsigned)-1)
1501  face = find_face(item->handler->face, (unsigned)-1);
1502 
1503  size = 4 + (2 + strlen(item->handler->type)) + (2 + strlen(title)) + 4;
1504 
1505  if (SockList_Avail(&sl) < size) {
1506  Send_With_Handling(&pl->socket, &sl);
1507  SockList_Reset(&sl);
1508  SockList_AddString(&sl, "addknowledge ");
1509  }
1510 
1511  SockList_AddInt(&sl, i + 1);
1512  SockList_AddLen16Data(&sl, item->handler->type, strlen(item->handler->type));
1513  if ((face != (unsigned)-1) && !(pl->socket.faces_sent[face]&NS_FACESENT_FACE))
1514  esrv_send_face(&pl->socket, face, 0);
1515  SockList_AddLen16Data(&sl, title, strlen(title));
1516  SockList_AddInt(&sl, face);
1517 
1518  free(title);
1519  }
1520 
1521  cur->sent_up_to = last;
1522 
1523  Send_With_Handling(&pl->socket, &sl);
1524  SockList_Term(&sl);
1525 
1526  /* don't send more this tick */
1527  break;
1528  }
1529 }
1530 
1536 void knowledge_show_monster_detail(object *op, const char *name) {
1537  knowledge_player *kp;
1538  StringBuffer *buf = NULL;
1539  char *result;
1540 
1541  if (op->contr == NULL)
1542  return;
1543 
1544  kp = knowledge_get_or_create(op->contr);
1545 
1546  if (!knowledge_known(kp, name, &knowledges[1]))
1547  return;
1548 
1549  buf = stringbuffer_new();
1550  knowledge_monster_detail(name, buf);
1551  result = stringbuffer_finish(buf);
1553  free(result);
1554 }
void(* knowledge_summary)(const char *code, StringBuffer *buf)
Function to fill the StringBuffer with the short description of an item.
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,...)
Sends message to player(s).
Definition: main.c:315
Error, serious thing.
Definition: logger.h:11
void apply_by_living_below(object *pl)
Attempt to apply the object &#39;below&#39; the player.
Definition: apply.c:618
int(* knowledge_add_item)(struct knowledge_player *current, const char *item, const struct knowledge_type *type, player *pl)
Add knowledge information to the player&#39;s knowledge.
Definition: knowledge.c:100
void SockList_AddPrintf(SockList *sl, const char *format,...)
Adds a printf like formatted string.
Definition: lowlevel.c:194
#define MSG_TYPE_MISC
Messages that don&#39;t go elsewhere.
Definition: newclient.h:389
One player.
Definition: player.h:92
archetype * find_archetype(const char *name)
Finds, using the hashtable, which archetype matches the given name.
Definition: arch.c:695
List of recipes with a certain number of ingredients.
Definition: recipe.h:37
void SockList_Reset(SockList *sl)
Resets the length of the stored data for writing.
Definition: lowlevel.c:66
void esrv_send_face(socket_struct *ns, uint16_t face_num, int nocache)
Sends a face to a client if they are in pixmap mode, nothing gets sent in bitmap mode.
Definition: image.c:70
#define NS_FACESENT_FACE
Bitmask for the faces_sent[] array - what portion of the face have we sent?
Definition: newserver.h:149
const char * name
Type name for player, to use with &#39;list&#39;.
Definition: knowledge.c:135
void knowledge_process_incremental(void)
Incrementally send knowledge information to players, and remove information for players who left...
Definition: knowledge.c:1447
void SockList_Init(SockList *sl)
Initializes the SockList instance.
Definition: lowlevel.c:48
void object_give_identified_properties(object *op)
Ensure op has all its "identified" properties set.
Definition: item.c:1375
void(* knowledge_attempt)(player *pl, const struct knowledge_item *item)
Attempt an alchemy based on the specified knowledge.
Definition: knowledge.c:126
sstring add_refcount(sstring str)
This will increase the refcount of the string str.
Definition: shstr.c:210
sstring get_message_title(const GeneralMessage *message)
Get a message&#39;s title.
Definition: readable.c:2226
struct knowledge_type knowledge_type
One item type that may be known to the player.
static const knowledge_type * knowledge_find(const char *type)
Find a knowledge handler from its type.
Definition: knowledge.c:880
static unsigned knowledge_god_face(sstring code)
Get the face for a god.
Definition: knowledge.c:787
#define strdup_local
Definition: compat.h:25
struct obj * container
Current container being used.
Definition: object.h:291
static int knowledge_add(knowledge_player *current, const char *item, const knowledge_type *kt, player *pl)
Add a knowledge item to a player&#39;s store if not found yet.
Definition: knowledge.c:561
sstring stringbuffer_finish_shared(StringBuffer *sb)
Deallocate the string buffer instance and return the string as a shared string.
Definition: stringbuffer.c:85
void knowledge_read(player *pl, object *book)
Player is reading a book, give knowledge if needed, warn player, and such.
Definition: knowledge.c:1064
uint32_t has_directory
If 0, the player was not yet saved, its directory doesn&#39;t exist.
Definition: player.h:134
void fatal(enum fatal_error err)
fatal() is meant to be called whenever a fatal signal is intercepted.
Definition: utils.c:596
One known item for a player.
Definition: knowledge.c:144
StringBuffer * stringbuffer_new(void)
Create a new string buffer.
Definition: stringbuffer.c:57
static int knowledge_god_add(struct knowledge_player *current, const char *item, const struct knowledge_type *type, player *pl)
Add god information to the player&#39;s knowledge, handling the multiple monster case.
Definition: knowledge.c:741
const char * playerdir
Where the player files are.
Definition: global.h:246
static void free_knowledge_player(knowledge_player *kp)
Totally free a knowledge structure, and its items.
Definition: knowledge.c:1279
void free_string(sstring str)
This will reduce the refcount, and if it has reached 0, str will be freed.
Definition: shstr.c:280
#define MSG_TYPE_COMMAND_EXAMINE
Player examining something.
Definition: newclient.h:512
unsigned int get_message_face(const GeneralMessage *message)
Get a message&#39;s face.
Definition: readable.c:2244
const char * object_get_value(const object *op, const char *const key)
Get an extra value by key.
Definition: object.c:4246
void knowledge_give(player *pl, const char *marker, const object *book)
Give a knowledge item from its code.
Definition: knowledge.c:1009
void knowledge_first_player_save(player *pl)
Ensure the knowledge state is correctly saved for the player.
Definition: knowledge.c:1431
Socket structure, represents a client-server connection.
Definition: newserver.h:99
object clone
An object from which to do object_copy()
Definition: object.h:470
socket_struct socket
Socket information for this player.
Definition: player.h:94
linked_char * ingred
List of ingredients.
Definition: recipe.h:22
void SockList_AddLen16Data(SockList *sl, const void *data, size_t len)
Adds a data block prepended with an 16 bit length field.
Definition: lowlevel.c:183
unsigned(* knowledge_face)(sstring code)
Get the face for a knowledge item.
Definition: knowledge.c:117
#define FREE_OBJ_NO_DESTROY_CALLBACK
Do not run the destroy callback.
Definition: object.h:533
#define MSG_TYPE_ADMIN_LOADSAVE
load/save operations
Definition: newclient.h:477
void SockList_AddInt(SockList *sl, uint32_t data)
Adds a 32 bit value.
Definition: lowlevel.c:119
#define object_was_destroyed(op, old_tag)
Checks if an object still exists.
Definition: object.h:68
void knowledge_send_info(socket_struct *ns)
Send the reply_info for &#39;knowledge_info&#39;.
Definition: knowledge.c:1382
Global type definitions and header inclusions.
#define safe_strncpy
Definition: compat.h:23
static void knowledge_alchemy_summary(const char *value, StringBuffer *buf)
Give the title of the alchemy recpie.
Definition: knowledge.c:207
Information about a player.
Definition: knowledge.c:150
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
Sends message to player(s).
Definition: main.c:310
The archetype structure is a set of rules on how to generate and manipulate objects which point to ar...
Definition: object.h:465
static void knowledge_do_display(object *pl, const knowledge_type *show_only, const char *search)
Actually display knowledge list.
Definition: knowledge.c:1076
#define MIN(x, y)
Definition: compat.h:17
knowledge_face item_face
Face for an item, if not defined the face it used.
Definition: knowledge.c:139
static void knowledge_message_detail(const char *value, StringBuffer *buf)
Give the full description of a message.
Definition: knowledge.c:831
static void knowledge_monster_summary(const char *item, StringBuffer *buf)
Monster information summary.
Definition: knowledge.c:592
struct titlestruct title
Information on one title.
static void knowledge_read_player_data(knowledge_player *kp)
Read all knowledge data for a player from disk, discarding invalid data.
Definition: knowledge.c:926
uint16_t number
This is the image id.
Definition: face.h:15
int ingred_count
Number of items in ingred.
Definition: recipe.h:23
knowledge_detail detail
Display the detailed description.
Definition: knowledge.c:132
One item type that may be known to the player.
Definition: knowledge.c:129
uint16_t notifications
Notifications this client wants to get.
Definition: newserver.h:141
knowledge_attempt attempt_alchemy
Definition: knowledge.c:137
void free_knowledge(void)
Free all knowledge data.
Definition: knowledge.c:1288
const char * title
Of foo, etc.
Definition: object.h:317
int16_t y
Position in the map for this object.
Definition: object.h:326
static int knowledge_monster_validate(const char *item)
Check if a monster knowledge item is still valid.
Definition: knowledge.c:621
#define FREE_OBJ_FREE_INVENTORY
Free inventory objects; if not set, drop inventory.
Definition: object.h:532
static void knowledge_do_attempt(object *pl, const char *params)
Player attempts something on a knowledge, get item and try it.
Definition: knowledge.c:1197
#define MSG_TYPE_COMMAND
Responses to commands, eg, who.
Definition: newclient.h:379
const char * face
Face for the type, as a basename.
Definition: knowledge.c:138
const char * type
Type internal code, musn&#39;t have a double dot, must be unique ingame.
Definition: knowledge.c:130
sstring title
Distinguishing name of product.
Definition: recipe.h:11
struct knowledge_item knowledge_item
One known item for a player.
void stringbuffer_append_string(StringBuffer *sb, const char *str)
Append a string to a string buffer instance.
Definition: stringbuffer.c:95
char ** arch_name
Possible archetypes of the final product made.
Definition: recipe.h:13
sstring player_name
Player&#39;s name.
Definition: knowledge.c:151
static knowledge_player * knowledge_get_or_create(const player *pl)
Find or create the knowledge store for a player.
Definition: knowledge.c:981
float speed_left
How much speed is left to spend this round.
Definition: object.h:329
#define MSG_TYPE_CLIENT_NOTICE
Non-critical note to player.
Definition: newclient.h:664
#define NDI_ALL_DMS
Inform all logged in DMs.
Definition: newclient.h:247
struct knowledge_player knowledge_player
Information about a player.
void(* knowledge_detail)(const char *code, StringBuffer *buf)
Function to fill the StringBuffer with a detailed description of an item.
Definition: knowledge.c:83
const artifact * locate_recipe_artifact(const recipe *rp, size_t idx)
Finds an artifact for a recipe.
Definition: recipe.c:661
struct mapdef * map
Pointer to the map in which this object is present.
Definition: object.h:297
void SockList_Term(SockList *sl)
Frees all resources allocated by a SockList instance.
Definition: lowlevel.c:58
static int knowledge_god_validate(const char *item)
Check if a god knowledge item is still valid.
Definition: knowledge.c:718
knowledge_add_item add
Add the item to the knowledge store.
Definition: knowledge.c:134
#define snprintf
Definition: win32.h:46
static void knowledge_message_summary(const char *value, StringBuffer *buf)
Give the title of a message.
Definition: knowledge.c:815
const knowledge_type * handler
How to handle this item.
Definition: knowledge.c:146
struct linked_char * next
Definition: global.h:88
int of_close(OutputFile *of)
Closes an output file.
Definition: output_file.c:61
static void knowledge_alchemy_attempt(player *pl, const knowledge_item *item)
Attempt an alchemy recipe through the knowledge system.
Definition: knowledge.c:344
struct knowledge_player * next
Next player on the list.
Definition: knowledge.c:157
const char * name
The name of the object, obviously...
Definition: object.h:311
struct knowledge_item ** items
Known knowledge.
Definition: knowledge.c:152
knowledge_is_valid_item validate
Validate the specific value.
Definition: knowledge.c:133
struct obj * below
Pointer to the object stacked below this one.
Definition: object.h:287
archetype * find_archetype_by_object_name(const char *name)
This function retrieves an archetype given the name that appears during the game (for example...
Definition: arch.c:57
void knowledge_send_known(player *pl)
Send initial known knowledge to player, if requested.
Definition: knowledge.c:1411
void SockList_AddString(SockList *sl, const char *data)
Adds a string without length.
Definition: lowlevel.c:149
uint32_t nrof
How many of the objects.
Definition: object.h:333
knowledge_summary summary
Display the short description.
Definition: knowledge.c:131
struct pl * contr
Pointer to the player which control this object.
Definition: object.h:276
void examine(object *op, object *tmp)
Player examines some object.
Definition: c_object.c:1424
static void free_knowledge_items(knowledge_player *kp)
Free all knowledge items for a player.
Definition: knowledge.c:1260
size_t SockList_Avail(const SockList *sl)
Returns the available bytes in a SockList instance.
Definition: lowlevel.c:238
int describe_god(const object *god, int what, StringBuffer *buf, size_t maxlen)
Describe a god.
Definition: holy.c:137
archetype * try_find_archetype(const char *name)
Finds, using the hashtable, which archetype matches the given name.
Definition: arch.c:666
uint32_t tag_t
Object tag, unique during the whole game.
Definition: object.h:12
#define QUERY_FLAG(xyz, p)
Definition: define.h:225
static int knowledge_alchemy_validate(const char *item)
Check if an alchemy recipe is still ok.
Definition: knowledge.c:282
static unsigned knowledge_alchemy_face(sstring code)
Try to get a face for an alchemy recipe.
Definition: knowledge.c:500
static void knowledge_alchemy_detail(const char *value, StringBuffer *buf)
Give the full description of the alchemy recpie.
Definition: knowledge.c:237
int index
Index value derived from formula ingredients.
Definition: recipe.h:18
static void knowledge_display(object *pl, const char *params)
Display all a player&#39;s knowledge.
Definition: knowledge.c:1141
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
static void knowledge_monster_detail(const char *item, StringBuffer *buf)
Describe in detail a monster.
Definition: knowledge.c:606
This is one artifact, ie one special item.
Definition: artifact.h:14
void put_object_in_sack(object *op, object *sack, object *tmp, uint32_t nrof)
Something tries to put an object into another.
Definition: c_object.c:678
void give_artifact_abilities(object *op, const object *artifact)
Fixes the given object, giving it the abilities and titles it should have due to the second artifact-...
Definition: artifact.c:203
static const knowledge_type knowledges[]
All handled knowledge items.
Definition: knowledge.c:866
#define MSG_TYPE_ADMIN
Definition: newclient.h:377
int item_count
How many items this players knows.
Definition: knowledge.c:153
int16_t x
Definition: object.h:326
static knowledge_player * knowledge_global
All known loaded knowledge for a player.
Definition: knowledge.c:161
static int knowledge_message_validate(const char *item)
Check if a message is still valid.
Definition: knowledge.c:846
void command_help(object *op, const char *params)
Player is asking for some help.
Definition: c_misc.c:1706
#define tolower(C)
Simple macro to convert a letter to lowercase.
Definition: c_new.c:29
static void knowledge_write_player_data(const knowledge_player *kp)
Store all knowledge data for a player to disk.
Definition: knowledge.c:895
void knowledge_item_can_be_used_alchemy(object *op, const object *item)
Displays known alchemy recipes an item can be used in.
Definition: knowledge.c:1342
object * ob
The object representing the player.
Definition: player.h:158
const char * sstring
Strings that should be manipulated through add_string() and free_string().
Definition: global.h:40
See Player.
Definition: object.h:107
unsigned int uint32_t
Definition: win32.h:162
static void knowledge_god_detail(const char *item, StringBuffer *buf)
Describe in detail a god.
Definition: knowledge.c:689
const char * name
Definition: global.h:87
static StringBuffer * knowledge_alchemy_can_use_item(sstring code, const char *item, StringBuffer *buf, int index)
Check if an item can be used for a recipe, and fill the return buffer if it&#39;s the case...
Definition: knowledge.c:294
StringBuffer * describe_item(const object *op, const object *owner, int use_media_tags, StringBuffer *buf)
Describes an item, in all its details.
Definition: item.c:980
#define RANDOM()
Definition: define.h:679
void command_knowledge(object *pl, const char *params)
Handle the &#39;knowledge&#39; for a player.
Definition: knowledge.c:1221
int knowledge_player_knows(const player *pl, const char *knowledge)
Determines whether a player knows a specific knowledge or not.
Definition: knowledge.c:1306
New_Face * blank_face
Following can just as easily be pointers, but it is easier to keep them like this.
Definition: image.c:39
const char * localdir
Read/write data files.
Definition: global.h:245
void command_take(object *op, const char *params)
This takes (picks up) and item.
Definition: c_object.c:585
tag_t count
Unique object number for this object.
Definition: object.h:299
struct archt * arch
Pointer to archetype.
Definition: object.h:412
size_t arch_names
Size of the arch_name[] array.
Definition: recipe.h:12
Only for debugging purposes.
Definition: logger.h:13
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:338
struct Settings settings
Server settings.
Definition: init.c:40
static int knowledge_monster_add(struct knowledge_player *current, const char *item, const struct knowledge_type *type, player *pl)
Add monster information to the player&#39;s knowledge, handling the multiple monster case.
Definition: knowledge.c:636
FILE * of_open(OutputFile *of, const char *fname)
Opens an output file.
Definition: output_file.c:30
void object_free2(object *ob, int flags)
Frees everything allocated by an object, removes it from the list of used objects, and puts it on the list of free objects.
Definition: object.c:1391
#define MSG_TYPE_COMMAND_INFO
Generic info: resistances, etc.
Definition: newclient.h:506
sstring item
Internal item code.
Definition: knowledge.c:145
int sent_up_to
Largest index that was sent to the client with notifications, -1 means the client doesn&#39;t want this i...
Definition: knowledge.c:155
const GeneralMessage * get_message_from_identifier(const char *identifier)
Find the message from its identifier.
Definition: readable.c:2213
static const recipe * knowledge_alchemy_get_recipe(const char *value)
Get a recipe from the internal code.
Definition: knowledge.c:169
Functions for creating text output files.
struct recipestruct * next
Next recipe with the same number of ingredients.
Definition: recipe.h:24
sstring get_message_body(const GeneralMessage *message)
Get a message&#39;s body.
Definition: readable.c:2235
int(* knowledge_is_valid_item)(const char *code)
Function to check if the specified item is valid.
Definition: knowledge.c:90
#define FLAG_STARTEQUIP
Object was given to player at start.
Definition: define.h:268
int item_allocated
How many items are allocated for items.
Definition: knowledge.c:154
sstring add_string(const char *str)
This will add &#39;str&#39; to the hash table.
Definition: shstr.c:124
EXTERN player * first_player
First player.
Definition: global.h:117
void stringbuffer_append_printf(StringBuffer *sb, const char *format,...)
Append a formatted string to a string buffer instance.
Definition: stringbuffer.c:104
struct pl * next
Pointer to next player, NULL if this is last.
Definition: player.h:93
struct obj * inv
Pointer to the first object in the inventory.
Definition: object.h:290
#define NDI_UNIQUE
Print immediately, don&#39;t buffer.
Definition: newclient.h:245
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.c:51
static void knowledge_god_summary(const char *item, StringBuffer *buf)
God information summary.
Definition: knowledge.c:673
One general message, from the lib/messages file.
Definition: readable.c:134
A buffer that will be expanded as content is added to it.
Definition: stringbuffer.c:25
void query_name(const object *op, char *buf, size_t size)
Describes an item.
Definition: item.c:625
object * item
Special values of the artifact.
Definition: artifact.h:15
Contains the base information we use to make up a packet we want to send.
Definition: newclient.h:680
This is a game-map.
Definition: map.h:325
const New_Face * face
Face with colors.
Definition: object.h:332
StringBuffer *(* knowledge_can_use_alchemy)(sstring code, const char *item, StringBuffer *buf, int index)
Check if an item can be used for a recipe, and fill the return buffer if it&#39;s the case...
Definition: knowledge.c:110
knowledge_can_use_alchemy use_alchemy
If not null, checks if an item can be used in alchemy.
Definition: knowledge.c:136
#define FLAG_INV_LOCKED
Item will not be dropped from inventory.
Definition: define.h:330
unsigned find_face(const char *name, unsigned error)
This returns an the face number of face &#39;name&#39;.
Definition: image.c:303
object * arch_to_object(archetype *at)
Creates and returns a new object which is a copy of the given archetype.
Definition: arch.c:571
uint8_t * faces_sent
This is a bitmap on sent face status.
Definition: newserver.h:106
static int knowledge_known(const knowledge_player *current, const char *item, const knowledge_type *kt)
Check whether a player already knows a knowledge item or not.
Definition: knowledge.c:542
sstring cauldron
Arch of the cauldron/workbench used to house the formulae.
Definition: recipe.h:27
const char * name
More definite name, like "generate_kobold".
Definition: object.h:466
char * stringbuffer_finish(StringBuffer *sb)
Deallocate the string buffer instance and return the string.
Definition: stringbuffer.c:76
static unsigned knowledge_message_face(sstring code)
Get the face for a message.
Definition: knowledge.c:855
void knowledge_show_monster_detail(object *op, const char *name)
Display the details of a monster if the player knows them.
Definition: knowledge.c:1536
struct recipestruct * items
Pointer to first recipe in this list.
Definition: recipe.h:40
recipelist * get_formulalist(int i)
Gets a formula list by ingredients count.
Definition: recipe.c:114
static void knowledge_show(object *pl, const char *params)
Show the details of a knowledge item.
Definition: knowledge.c:1171
static unsigned knowledge_monster_face(sstring code)
Get the face for a monster.
Definition: knowledge.c:658
One alchemy recipe.
Definition: recipe.h:10
void Send_With_Handling(socket_struct *ns, SockList *sl)
Calls Write_To_Socket to send data to the client.
Definition: lowlevel.c:542