Crossfire Server, Trunk  1.75.0
knowledge.cpp
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2014 Mark Wedel and the Crossfire Development Team
5  * Copyright (c) 1992 Frank Tore Johansen
6  *
7  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
8  * welcome to redistribute it under certain conditions. For details, please
9  * see COPYING and LICENSE.
10  *
11  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
12  */
13 
58 #include "global.h"
59 
60 #include <assert.h>
61 #include <ctype.h>
62 #include <stdlib.h>
63 #include <string.h>
64 
65 #include "sproto.h"
66 #include "output_file.h"
67 
68 /* Media tags for information messages prefix. */
69 #define TAG_START "[color=#ff6611]"
70 #define TAG_END "[/color]"
71 
72 struct knowledge_player;
73 struct knowledge_type;
74 
80 typedef void (*knowledge_summary)(const char *code, StringBuffer *buf);
81 
87 typedef void (*knowledge_detail)(const char *code, StringBuffer *buf);
88 
94 typedef int (*knowledge_is_valid_item)(const char *code);
95 
103 typedef int (*knowledge_add_item)(knowledge_player *current, const char *item, const knowledge_type *type);
104 
113 typedef StringBuffer* (*knowledge_can_use_alchemy)(sstring code, const char *item, StringBuffer *buf, int index);
114 
120 typedef const Face *(*knowledge_face)(sstring code);
121 
122 struct knowledge_item;
123 
129 typedef void (*knowledge_attempt)(player *pl, const knowledge_item *item);
130 
133  const char *type;
138  const char *name;
141  const char *face;
143 };
144 
145 
150 };
151 
161 };
162 
165 
166 
172 static const recipe* knowledge_alchemy_get_recipe(const char *value) {
173  const recipe *rec;
174  recipelist *rl;
175  int count, index;
176  const char *dot;
177 
178  dot = strchr(value, ':');
179  if (!dot) {
180  /* warn? */
181  return NULL;
182  }
183 
184  count = atoi(value);
185  index = atoi(dot + 1);
186  dot = strchr(dot + 1, ':');
187  if (!dot)
188  /* warn? */
189  return NULL;
190  dot++;
191 
192  rl = get_formulalist(count);
193  rec = rl->items;
194  while (rec) {
195  if (rec->index == index && strcmp(rec->title, dot) == 0)
196  return rec;
197 
198  rec = rec->next;
199  }
200 
201  return NULL;
202 }
203 
210 static void knowledge_alchemy_summary(const char *value, StringBuffer *buf) {
211  const recipe *rec = knowledge_alchemy_get_recipe(value);
212  const archetype *arch;
213 
214  if (!rec)
215  /* warn? */
216  return;
217 
218  arch = try_find_archetype(rec->arch_name[RANDOM()%rec->arch_names]);
219  if (!arch)
220  /* not supposed to happen */
221  return;
222 
223  if (strcmp(rec->title, "NONE"))
224  stringbuffer_append_printf(buf, "%s of %s", arch->clone.name, rec->title);
225  else {
226  if (arch->clone.title != NULL) {
227  stringbuffer_append_printf(buf, "%s %s", arch->clone.name, arch->clone.title);
228  }
229  else
231  }
232 }
233 
240 static void knowledge_alchemy_detail(const char *value, StringBuffer *buf) {
241  const recipe *rec = knowledge_alchemy_get_recipe(value);
242  const linked_char *next;
243  const archetype *arch;
244  char name[MAX_BUF];
245 
246 
247  if (!rec)
248  /* warn? */
249  return;
250 
251  arch = try_find_archetype(rec->arch_name[RANDOM()%rec->arch_names]);
252  if (!arch)
253  /* not supposed to happen */
254  return;
255 
256  if (strcmp(rec->title, "NONE"))
257  stringbuffer_append_printf(buf, "The %s of %s", arch->clone.name, rec->title);
258  else {
259  if (arch->clone.title != NULL) {
260  stringbuffer_append_printf(buf, "The %s %s", arch->clone.name, arch->clone.title);
261  }
262  else
263  stringbuffer_append_printf(buf, "The %s", arch->clone.name);
264  }
265 
266  arch = try_find_archetype(rec->cauldron);
267  if (arch)
268  query_name(&arch->clone, name, MAX_BUF);
269  else
270  snprintf(name, sizeof(name), "an unknown place");
271 
272  stringbuffer_append_printf(buf, ", a%s %s recipe, is made with %s at %s and uses the following ingredients:",
273  rec->diff >= 10 && rec->diff < 15 ? "n" : "",
275  rec->skill ? rec->skill : "an unknown skill", name);
276 
277  for (next = rec->ingred; next != NULL; next = next->next) {
278  stringbuffer_append_printf(buf, "\n - %s", next->name);
279  }
280 
281 }
282 
288 static int knowledge_alchemy_validate(const char *item) {
289  return knowledge_alchemy_get_recipe(item) != NULL;
290 }
291 
300 static StringBuffer* knowledge_alchemy_can_use_item(sstring code, const char *item, StringBuffer *buf, int index) {
302  const linked_char *next;
303  const archetype *arch;
304  const char *name;
305 
306  if (!item)
307  return NULL;
308 
309  if (!rec)
310  /* warn? */
311  return buf;
312 
313  arch = try_find_archetype(rec->arch_name[RANDOM()%rec->arch_names]);
314  if (!arch)
315  /* not supposed to happen */
316  return buf;
317 
318  for (next = rec->ingred; next != NULL; next = next->next) {
319  name = next->name;
320  while ((*name) != '\0' && (isdigit(*name) || (*name) == ' '))
321  name++;
322 
323  if (strcmp(item, name) == 0) {
324  if (buf == NULL) {
325  buf = stringbuffer_new();
326  stringbuffer_append_string(buf, "It can be used in the following recipes: ");
327  } else
329 
330  if (strcmp(rec->title, "NONE"))
331  stringbuffer_append_printf(buf, "%s of %s", arch->clone.name, rec->title);
332  else {
333  if (arch->clone.title != NULL) {
334  stringbuffer_append_printf(buf, "%s %s", arch->clone.name, arch->clone.title);
335  }
336  else
338  }
339  stringbuffer_append_printf(buf, " (%d)", index);
340 
341  break;
342  }
343  }
344 
345  return buf;
346 }
347 
353 static void knowledge_alchemy_attempt(player *pl, const knowledge_item *item) {
354  const recipe *rp = knowledge_alchemy_get_recipe(item->item);
355  object *cauldron = NULL, *inv;
356  object *ingredients[50];
357  int index, x, y;
358  uint32_t count, counts[50];
359  char name[MAX_BUF];
360  const char *ingname;
361  linked_char *ing;
362  tag_t cauldron_tag;
363  mapstruct *map;
364 
365  if (!rp) {
366  LOG(llevError, "knowledge: couldn't find recipe for %s", item->item);
367  return;
368  }
369 
370  if (rp->ingred_count > 50) {
371  LOG(llevError, "knowledge: recipe %s has more than 50 ingredients!", item->item);
372  draw_ext_info(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, "This recipe is too complicated.");
373  return;
374  }
375 
376  /* first, check for a cauldron */
377  for (cauldron = pl->ob->below; cauldron; cauldron = cauldron->below) {
378  if (strcmp(rp->cauldron, cauldron->arch->name) == 0)
379  break;
380  }
381 
382  if (cauldron == NULL) {
383  draw_ext_info_format(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, "You are not on a %s", rp->cauldron);
384  return;
385  }
386 
387  cauldron_tag = cauldron->count;
388 
389  /* find ingredients in player's inventory */
390  for (index = 0; index < 50; index++) {
391  ingredients[index] = NULL;
392  }
393  for (inv = pl->ob->inv; inv != NULL; inv = inv->below) {
394 
395  if (inv->invisible || QUERY_FLAG(inv, FLAG_INV_LOCKED) || QUERY_FLAG(inv, FLAG_STARTEQUIP))
396  continue;
397 
398  if (inv->title == NULL)
399  safe_strncpy(name, inv->name, sizeof(name));
400  else
401  snprintf(name, sizeof(name), "%s %s", inv->name, inv->title);
402 
403  index = 0;
404  for (ing = rp->ingred; ing != NULL; ing = ing->next) {
405 
406  if (ingredients[index] != NULL) {
407  index++;
408  continue;
409  }
410 
411  ingname = ing->name;
412  count = 0;
413  while (isdigit(*ingname)) {
414  count = 10 * count + (*ingname - '0');
415  ingname++;
416  }
417  if (count == 0)
418  count = 1;
419  while (*ingname == ' ')
420  ingname++;
421 
422  if (strcmp(name, ingname) == 0 && ((inv->nrof == 0 && count == 1) || (inv->nrof >= count))) {
423  ingredients[index] = inv;
424  // If nrof is 0, we want to keep a count of 0 so put_object_in_sack() later doesn't call
425  // object_split() which would destroy tmp and mess up our tags.
426  counts[index] = inv->nrof == 0 ? 0 : count;
427  break;
428  }
429 
430  index++;
431  }
432  }
433 
434  index = 0;
435  for (ing = rp->ingred; ing != NULL; ing = ing->next) {
436  if (ingredients[index] == NULL) {
437  draw_ext_info_format(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, "You don't have %s.", ing->name);
438  return;
439  }
440 
441  index++;
442  }
443 
444  /* ensure cauldron is applied */
445  if (pl->ob->container != cauldron) {
447  if (pl->ob->container != cauldron) {
448  draw_ext_info_format(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, "Couldn't activate the %s.", rp->cauldron);
449  return;
450  }
451  }
452 
453  /* ensure cauldron is empty */
454  while (cauldron->inv != NULL) {
455  inv = cauldron->inv;
456  command_take(pl->ob, "");
457  if (cauldron->inv == inv) {
458  draw_ext_info_format(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, "Couldn't empty the %s", rp->cauldron);
459  return;
460  }
461  }
462 
463  /* drop ingredients */
464  for (index = 0; index < rp->ingred_count; index++) {
465  tag_t tag = ingredients[index]->count;
466  count = ingredients[index]->nrof;
467  put_object_in_sack(pl->ob, cauldron, ingredients[index], counts[index]);
468  if (object_was_destroyed(ingredients[index], tag)) {
469  draw_ext_info(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, "Hum, some item disappeared, stopping the attempt.");
470  return;
471 
472  }
473  if (count == ingredients[index]->nrof && ingredients[index]->env == pl->ob) {
474  draw_ext_info(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, "Hum, couldn't drop some items, stopping the attempt.");
475  return;
476  }
477  }
478 
479  map = pl->ob->map;
480  x = pl->ob->x;
481  y = pl->ob->y;
482 
483  /* do alchemy */
484  use_alchemy(pl->ob);
485 
486  /* don't forget to slow the player: 1 for alchemy itself, 1 for each ingredient put,
487  * ingredients taken are handled by command_take() */
488  pl->ob->speed_left -= 1.0 * (rp->ingred_count + 1);
489 
490  /* safety: ensure cauldron is still there, and player is still above */
491  if (object_was_destroyed(cauldron, cauldron_tag) || map != pl->ob->map || x != pl->ob->x || y != pl->ob->y) {
492  return;
493  }
494 
495  /* get back the result */
496  while (cauldron->inv) {
497  /* Examining may lead to identifying part of items and thus introducing
498  * extra items in the cauldron. Therefore we'll set inv only after examining,
499  * even if that means that potentially the player will examine twice some items. */
500  examine(pl->ob, cauldron->inv);
501  inv = cauldron->inv;
502  command_take(pl->ob, "");
503  pl->ob->speed_left -= 1.0;
504  if (inv == cauldron->inv)
505  break;
506  }
507 }
508 
516 
517  if (!rp) {
518  LOG(llevError, "knowledge: couldn't find recipe for %s", code);
519  return NULL;
520  }
521 
522  return recipe_get_face(rp);
523 }
524 
532 static int knowledge_known(const knowledge_player *current, const char *item, const knowledge_type *kt) {
533  int i;
534  for (i = 0; i < current->item_count; i++) {
535  if (strcmp(kt->type, current->items[i]->handler->type) == 0 && strcmp(item, current->items[i]->item) == 0) {
536  /* already known, bailout */
537  return 1;
538  }
539  }
540  return 0;
541 }
542 
550 static int knowledge_add(knowledge_player *current, const char *item, const knowledge_type *kt) {
551  knowledge_item *check;
552 
553  if (knowledge_known(current, item, kt)) {
554  return 0;
555  }
556 
557  /* keep the knowledge */
562  check = static_cast<knowledge_item *>(malloc(sizeof(knowledge_item)));
563  check->item = add_string(item);
564  check->handler = kt;
565  if (current->item_count >= current->item_allocated) {
566  current->item_allocated += 10;
567  current->items = static_cast<knowledge_item **>(realloc(current->items, current->item_allocated * sizeof(knowledge_item*)));
568  }
569  current->items[current->item_count] = check;
570  current->item_count++;
571 
572  return 1;
573 }
574 
581 static void knowledge_monster_summary(const char *item, StringBuffer *buf) {
583  if (!monster)
584  return;
585 
586  stringbuffer_append_printf(buf, "%s", monster->clone.name);
587 }
588 
595 static void knowledge_monster_detail(const char *item, StringBuffer *buf) {
597 
598  if (!monster)
599  return;
600 
601  stringbuffer_append_printf(buf, " *** %s ***\n", monster->clone.name);
602  describe_item(&monster->clone, NULL, 1, buf);
603 }
604 
610 static int knowledge_monster_validate(const char *item) {
611  const archetype *monster = try_find_archetype(item);
612  if (monster == NULL || monster->clone.type != 0 || monster->head || object_get_value(&monster->clone, MONSTER_EXCLUDE_FROM_READABLE_KEY) != NULL)
613  return 0;
614  return 1;
615 }
616 
624 static int knowledge_monster_add(struct knowledge_player *current, const char *item, const struct knowledge_type *type) {
625  char *dup = strdup_local(item);
626  char *pos, *first = dup;
627  int added = 0;
628 
629  while (first) {
630  pos = strchr(first, ':');
631  if (pos)
632  *pos = '\0';
633  added += knowledge_add(current, first, type);
634  first = pos ? pos + 1 : NULL;
635  }
636 
637  free(dup);
638  return added;
639 }
640 
648 
649  if (!monster || monster->clone.face == blank_face || monster->clone.face == NULL)
650  return NULL;
651 
652  return monster->clone.face;
653 }
654 
661 static void knowledge_god_summary(const char *item, StringBuffer *buf) {
662  char *dup = strdup_local(item), *pos = strchr(dup, ':');
663 
664  if (pos)
665  *pos = '\0';
666 
667  stringbuffer_append_printf(buf, "%s [god]", dup);
668  free(dup);
669 }
670 
677 static void knowledge_god_detail(const char *item, StringBuffer *buf) {
678  char *dup = strdup_local(item), *pos = strchr(dup, ':');
679  const archetype *god;
680  int what;
681 
682  if (!pos) {
683  LOG(llevError, "knowledge_god_detail: invalid god item %s\n", item);
684  free(dup);
685  return;
686  }
687 
688  *pos = '\0';
689  what = atoi(pos + 1);
691  free(dup);
692 
693  if (!god) {
694  LOG(llevError, "knowledge_god_detail: couldn't find god %s?\n", item);
695  return;
696  }
697 
698  describe_god(&god->clone, what, buf, 0);
699 }
700 
706 static int knowledge_god_validate(const char *item) {
707  char *dup = strdup_local(item), *pos = strchr(dup, ':');
708  int valid;
709 
710  if (!pos) {
711  LOG(llevError, "knowledge_god_validate: invalid god item %s\n", item);
712  free(dup);
713  return 0;
714  }
715  *pos = '\0';
716  valid = find_archetype_by_object_name(dup) != NULL;
717  free(dup);
718  return valid;
719 }
720 
728 static int knowledge_god_add(struct knowledge_player *current, const char *item, const struct knowledge_type *type) {
729  char *dup = strdup_local(item), *pos = const_cast<char *>(strchr(dup, ':'));
730  StringBuffer *buf;
731  int what, i;
732  knowledge_item* check;
733 
734  if (!pos) {
735  LOG(llevError, "knowledge_god_add: invalid god item %s\n", item);
736  free(dup);
737  return 0;
738  }
739 
740  *pos = '\0';
741  what = atoi(pos + 1);
742 
743  for (i = 0; i < current->item_count; i++) {
744  check = current->items[i];
745  if (check->handler != type)
746  /* Only consider our own type. */
747  continue;
748  if (strncmp(check->item, dup, strlen(dup)) == 0) {
749  /* Already known, update information. */
750  int known, result;
751  pos = const_cast<char *>(strchr(check->item, ':'));
752  known = atoi(pos + 1);
753  result = known | what;
754  buf = stringbuffer_new();
755  stringbuffer_append_printf(buf, "%s:%d", dup, result);
756  free_string(check->item);
758  free(dup);
759  return (result != known);
760  }
761  }
762 
763  free(dup);
764 
765  /* Not known, so just add it regularly. */
766  return knowledge_add(current, item, type);
767 }
768 
775  char buf[MAX_BUF];
776  size_t letter;
777  const archetype *altar_arch;
778 
779  snprintf(buf, MAX_BUF, "altar_");
780  letter = strlen(buf);
781  strncpy(buf+letter, code, MAX_BUF-letter);
782  for (; letter < strlen(buf); letter++) {
783  if (buf[letter] == ':') {
784  buf[letter] = '\0';
785  break;
786  }
787  buf[letter] = tolower(buf[letter]);
788  }
789  altar_arch = try_find_archetype(buf);
790  if (altar_arch == NULL)
791  return NULL;
792 
793  return altar_arch->clone.face;
794 }
795 
802 static void knowledge_message_summary(const char *value, StringBuffer *buf) {
803  const GeneralMessage *msg = get_message_from_identifier(value);
804 
805  if (!msg)
806  /* warn? */
807  return;
808 
810 }
811 
818 static void knowledge_message_detail(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 
833 static int knowledge_message_validate(const char *item) {
834  return get_message_from_identifier(item) != NULL;
835 }
836 
844 
845  if (!msg)
846  /* warn? */
847  return NULL;
848 
849  return get_message_face(msg);
850 }
851 
853 static const knowledge_type knowledges[] = {
855  { "monster", knowledge_monster_summary, knowledge_monster_detail, knowledge_monster_validate, knowledge_monster_add, "monsters", NULL, NULL, "knowledge_monsters.111", knowledge_monster_face },
856  { "god", knowledge_god_summary, knowledge_god_detail, knowledge_god_validate, knowledge_god_add, "gods", NULL, NULL, "knowledge_gods.111", knowledge_god_face },
857  { "message", knowledge_message_summary, knowledge_message_detail, knowledge_message_validate, knowledge_add, "messages", NULL, NULL, "knowledge_messages.111", knowledge_message_face },
858  { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
859 };
860 
861 
867 static const knowledge_type *knowledge_find(const char *type) {
868  int i = 0;
869  while (knowledges[i].type != NULL) {
870  if (strcmp(knowledges[i].type, type) == 0)
871  return &knowledges[i];
872  i++;
873  }
874 
875  return NULL;
876 }
877 
883  FILE *file;
884  OutputFile of;
885  char fname[MAX_BUF];
886  const knowledge_item *item;
887  int i;
888 
889  snprintf(fname, sizeof(fname), "%s/%s/%s/%s.knowledge", settings.localdir, settings.playerdir, kp->player_name, kp->player_name);
890 
891  file = of_open(&of, fname);
892  if (!file) {
893  draw_ext_info(NDI_UNIQUE | NDI_ALL_DMS, 0, NULL, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_LOADSAVE, "File write error on server!");
894  return;
895  }
896 
897  for (i = 0; i < kp->item_count; i++) {
898  item = kp->items[i];
899  fprintf(file, "%s:%s\n", item->handler->type, item->item);
900  }
901 
902  if (!of_close(&of)) {
903  draw_ext_info(NDI_UNIQUE | NDI_ALL_DMS, 0, NULL, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_LOADSAVE, "File write error on server!");
904  return;
905  }
907 }
908 
914  FILE *file;
915  char final[MAX_BUF], read[MAX_BUF], *dot;
916  knowledge_item *item;
917  const knowledge_type *type;
918 
919  snprintf(final, sizeof(final), "%s/%s/%s/%s.knowledge", settings.localdir, settings.playerdir, kp->player_name, kp->player_name);
920 
921  file = fopen(final, "r");
922  if (!file) {
923  /* no knowledge yet, no big deal */
924  return;
925  }
926 
927  while (fgets(read, sizeof(read), file) != NULL) {
928  if (strlen(read) > 0)
929  read[strlen(read) - 1] = '\0';
930 
931  dot = strchr(read, ':');
932  if (!dot) {
933  LOG(llevError, "knowledge: invalid line in file %s\n", final);
934  continue;
935  }
936 
937  *dot = '\0';
938 
939  type = knowledge_find(read);
940  if (!type) {
941  LOG(llevError, "knowledge: invalid type %s in file %s\n", read, final);
942  continue;
943  }
944  if (!type->validate(dot + 1)) {
945  LOG(llevDebug, "knowledge: ignoring now invalid %s in file %s\n", read, final);
946  continue;
947  }
948 
949  item = static_cast<knowledge_item *>(malloc(sizeof(knowledge_item)));
950  item->item = add_string(dot + 1);
951  item->handler = type;
952  if (kp->item_count == kp->item_allocated) {
953  kp->item_allocated += 10;
954  kp->items = static_cast<knowledge_item **>(realloc(kp->items, kp->item_allocated * sizeof(knowledge_item*)));
955  }
956  kp->items[kp->item_count] = item;
957  kp->item_count++;
958  }
959  fclose(file);
960 }
961 
970 
971  while (cur) {
972  if (cur->player_name == pl->ob->name)
973  return cur;
974  cur = cur->next;
975  }
976 
977  cur = static_cast<knowledge_player *>(calloc(1, sizeof(knowledge_player)));
978  if (!cur)
980  cur->player_name = add_refcount(pl->ob->name);
981  cur->next = knowledge_global;
982  knowledge_global = cur;
983  /* read knowledge for this player */
985  if (pl->socket->notifications < 2)
986  cur->sent_up_to = -1;
987  return cur;
988 }
989 
996 void knowledge_give(player *pl, const char *marker, const object *book) {
997  char *copy, *code, *dot;
998  const knowledge_type *type;
999  int none, added = 0;
1001 
1002  /* process marker, find if already known */
1003  dot = const_cast<char *>(strchr(marker, ':'));
1004  if (dot == NULL)
1005  return;
1006 
1007  copy = strdup(marker);
1008  if (!copy)
1010 
1011  dot = const_cast<char *>(strchr(copy, ':'));
1012  *dot = '\0';
1013  dot++;
1014 
1015  type = knowledge_find(copy);
1016  if (!type) {
1017  LOG(llevError, "knowledge: invalid marker type %s in %s\n", copy, book == NULL ? "(null)" : book->name);
1018  free(copy);
1019  return;
1020  }
1021 
1022  none = (current->items == NULL);
1023 
1024  code = dot;
1025  while (code && code[0] != '\0') {
1026  dot = strchr(code, '/');
1027  if (dot) {
1028  *dot = '\0';
1029  dot++;
1030  }
1031  if (type->validate(code)) {
1032  added += type->add(current, code, type);
1033  }
1034  code = dot;
1035  }
1036 
1037  free(copy);
1038 
1039  if (added) {
1040  draw_ext_info_format(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_MISC, MSG_TYPE_CLIENT_NOTICE, TAG_START "%s" TAG_END, "You keep that in mind for future reference.");
1041  if (none) {
1042  /* first information ever written down, be nice and give hint to recover it. */
1043  draw_ext_info_format(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_MISC, MSG_TYPE_CLIENT_NOTICE, TAG_START "%s" TAG_END, "Use the 'knowledge' command to see what you keep in mind (this message will not appear anymore).");
1044  }
1045  }
1046 
1047  if (pl->has_directory)
1048  knowledge_write_player_data(current);
1049 }
1050 
1056 void knowledge_read(player *pl, object *book) {
1057  sstring marker = object_get_value(book, "knowledge_marker");
1058  if (marker != NULL)
1059  knowledge_give(pl, marker, book);
1060 }
1061 
1068 static void knowledge_do_display(object *pl, const knowledge_type *show_only, const char *search) {
1069  knowledge_player *kp;
1070  knowledge_item *item;
1071  int header = 0, show, i;
1072  StringBuffer *summary;
1073  char *final;
1074 
1075  assert(search == NULL || search[0] != '\0');
1076 
1077  kp = knowledge_get_or_create(pl->contr);
1078  for (i = 0; i < kp->item_count; i++) {
1079  item = kp->items[i];
1080  show = 1;
1081 
1082  summary = stringbuffer_new();
1083  item->handler->summary(item->item, summary);
1084  final = stringbuffer_finish(summary);
1085 
1086  if (show_only != NULL && item->handler != show_only) {
1087  show = 0;
1088  }
1089  if (search != NULL && search[0] != '\0') {
1090  if (strstr(final, search) == NULL) {
1091  char *fd;
1092  StringBuffer *detail = stringbuffer_new();
1093  item->handler->detail(item->item, detail);
1094  fd = stringbuffer_finish(detail);
1095  if (strstr(fd, search) == NULL)
1096  show = 0;
1097  free(fd);
1098  }
1099  }
1100 
1101  if (show == 1) {
1102  if (header == 0) {
1103  if (search != NULL)
1104  draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_MISC, MSG_TYPE_CLIENT_NOTICE, "You have knowledge of the following %s concerning '%s':", show_only == NULL ? "things" : show_only->type, search);
1105  else if (show_only != NULL)
1106  draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_MISC, MSG_TYPE_CLIENT_NOTICE, "You have knowledge of those %s:", show_only->name);
1107  else
1108  draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_MISC, MSG_TYPE_CLIENT_NOTICE, "You have knowledge of:");
1109  header = 1;
1110  }
1111 
1112  draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_MISC, MSG_TYPE_CLIENT_NOTICE, "(%3d) %s", i + 1, final);
1113  }
1114 
1115  free(final);
1116  }
1117 
1118  if (header == 0) {
1119  if (search != NULL)
1120  draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_MISC, MSG_TYPE_CLIENT_NOTICE, "You don't know yet any relevant information about '%s'.", search);
1121  else if (show_only != NULL)
1122  draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_MISC, MSG_TYPE_CLIENT_NOTICE, "You don't know yet any relevant information about %s.", show_only->name);
1123  else
1124  draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_MISC, MSG_TYPE_CLIENT_NOTICE, "You don't know yet any relevant information.");
1125  }
1126 }
1127 
1133 static void knowledge_display(object *pl, const char *params) {
1134  const knowledge_type *show_only = NULL;
1135 
1136  if (params && params[0] == ' ') {
1137  const char *type = params + 1;
1138  int idx = 0;
1139  for (; knowledges[idx].type != NULL; idx++) {
1140  if (strcmp(knowledges[idx].name, type) == 0) {
1141  show_only = &knowledges[idx];
1142  break;
1143  }
1144  }
1145 
1146  if (show_only == NULL) {
1147  draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_MISC, MSG_TYPE_CLIENT_NOTICE, "Invalid type, valid types are:");
1148  for (idx = 0; knowledges[idx].type != NULL; idx++) {
1150  }
1151  return;
1152  }
1153  }
1154 
1155  knowledge_do_display(pl, show_only, NULL);
1156 }
1157 
1163 static void knowledge_show(object *pl, const char *params) {
1164  knowledge_player *kp;
1165  knowledge_item *item;
1166  int count = atoi(params) - 1;
1167  StringBuffer *buf;
1168  char *final;
1169 
1170  kp = knowledge_get_or_create(pl->contr);
1171  if (count < 0 || count >= kp->item_count) {
1172  draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, "Invalid knowledge number");
1173  return;
1174  }
1175 
1176  item = kp->items[count];
1177  buf = stringbuffer_new();
1178  item->handler->detail(item->item, buf);
1179  final = stringbuffer_finish(buf);
1181  free(final);
1182 }
1183 
1189 static void knowledge_do_attempt(object *pl, const char *params) {
1190  knowledge_player *kp;
1191  knowledge_item *item;
1192  int count = atoi(params) - 1;
1193 
1194  kp = knowledge_get_or_create(pl->contr);
1195  if (count < 0 || count >= kp->item_count) {
1196  draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, "Invalid knowledge number");
1197  return;
1198  }
1199 
1200  item = kp->items[count];
1201  if (item->handler->attempt_alchemy == NULL) {
1202  draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, "You can't do anything with that knowledge.");
1203  } else {
1204  item->handler->attempt_alchemy(pl->contr, item);
1205  }
1206 }
1207 
1213 void command_knowledge(object *pl, const char *params) {
1214 
1215  if (!pl->contr) {
1216  LOG(llevError, "command_knowledge: called for %s not a player!\n", pl->name);
1217  return;
1218  }
1219 
1220  if (!params || *params == '\0') {
1221  command_help(pl, "knowledge");
1222  return;
1223  }
1224 
1225  if (strncmp(params, "list", 4) == 0) {
1226  knowledge_display(pl, params + 4);
1227  return;
1228  }
1229 
1230  if (strncmp(params, "search ", 7) == 0) {
1231  knowledge_do_display(pl, NULL, params + 7);
1232  return;
1233  }
1234 
1235  if (strncmp(params, "show ", 5) == 0) {
1236  knowledge_show(pl, params + 5);
1237  return;
1238  }
1239 
1240  if (strncmp(params, "attempt ", 8) == 0) {
1241  knowledge_do_attempt(pl, params + 8);
1242  return;
1243  }
1244 
1245  command_help(pl, "knowledge");
1246 }
1247 
1253  knowledge_item *item;
1254  int i;
1255 
1256  for (i = 0; i < kp->item_count; i++) {
1257  item = kp->items[i];
1258  free_string(item->item);
1259  free(item);
1260  }
1261  free(kp->items);
1262  kp->items = NULL;
1263  kp->item_count = 0;
1264  kp->item_allocated = 0;
1265 }
1266 
1273  free_string(kp->player_name);
1274  free(kp);
1275 }
1276 
1280 void free_knowledge(void) {
1281  knowledge_player *kp, *next;
1282 
1283  kp = knowledge_global;
1284  while (kp) {
1285  next = kp->next;
1287  kp = next;
1288  }
1289  knowledge_global = NULL;
1290 }
1291 
1298 int knowledge_player_knows(const player *pl, const char *knowledge) {
1299  const knowledge_type *type;
1300  char copy[MAX_BUF], *pos;
1301  const knowledge_player *current;
1302 
1303  if (strlen(knowledge) >= MAX_BUF - 1) {
1304  LOG(llevError, "knowledge_player_knows: too long knowledge %s\n", knowledge);
1305  return 0;
1306  }
1307 
1308  strlcpy(copy, knowledge, sizeof(copy));
1309  pos = strchr(copy, ':');
1310  if (pos == NULL) {
1311  LOG(llevError, "knowledge_player_knows: invalid knowledge item %s\n", knowledge);
1312  return 0;
1313  }
1314 
1315  *pos = '\0';
1316  pos++;
1317 
1318  type = knowledge_find(copy);
1319  if (type == NULL) {
1320  LOG(llevError, "knowledge_player_knows: invalid knowledge type %s\n", knowledge);
1321  return 0;
1322  }
1323 
1324  current = knowledge_get_or_create(pl);
1325 
1326  return knowledge_known(current, pos, type);
1327 }
1328 
1334 void knowledge_item_can_be_used_alchemy(object *op, const object *item) {
1335  knowledge_player *cur;
1336  knowledge_item *ki;
1337  char item_name[MAX_BUF], *result;
1338  const char *name;
1339  StringBuffer *buf = NULL;
1340  int i;
1341 
1342  if (op->type != PLAYER || op->contr == NULL)
1343  return;
1344 
1345  cur = knowledge_get_or_create(op->contr);
1346 
1347  if (item->title != NULL) {
1348  snprintf(item_name, sizeof(item_name), "%s %s", item->name, item->title);
1349  name = item_name;
1350  } else
1351  name = item->name;
1352 
1353  for (i = 0; i < cur->item_count; i++) {
1354  ki = cur->items[i];
1355  if (ki->handler->use_alchemy != NULL) {
1356  buf = ki->handler->use_alchemy(ki->item, name, buf, i + 1);
1357  }
1358  }
1359 
1360  if (buf == NULL)
1361  return;
1362 
1364  result = stringbuffer_finish(buf);
1366  result);
1367  free(result);
1368 }
1369 
1375  int i;
1376  const Face *face;
1377  SockList sl;
1378 
1379  face = try_find_face("knowledge_generic.111", NULL);
1380  if (face != NULL && (!(ns->faces_sent[face->number] & NS_FACESENT_FACE)))
1381  esrv_send_face(ns, face, 0);
1382 
1383  SockList_Init(&sl);
1384  SockList_AddString(&sl, "replyinfo knowledge_info\n");
1385  SockList_AddPrintf(&sl, "::%u:0\n", face ? face->number : 0);
1386 
1387  for (i = 0; knowledges[i].type != NULL; i++) {
1388  face = try_find_face(knowledges[i].face, NULL);
1389  if (face != NULL && (!(ns->faces_sent[face->number] & NS_FACESENT_FACE)))
1390  esrv_send_face(ns, face, 0);
1391 
1392  SockList_AddPrintf(&sl, "%s:%s:%u:%s\n", knowledges[i].type, knowledges[i].name, face ? face->number : 0, knowledges[i].attempt_alchemy != NULL ? "1" : "0");
1393  }
1394 
1395  Send_With_Handling(ns, &sl);
1396  SockList_Term(&sl);
1397 }
1398 
1404  knowledge_player *kp;
1405 
1406  if (pl->socket->notifications < 2)
1407  return;
1408 
1409  /* merely loading the knowledge will mark it as to be sent through knowledge_process_incremental(),
1410  * but we need to reset the sent_up_to field if eg the player was the last one to leave
1411  * then joins again - no knowledge processing is done at that point. */
1412  kp = knowledge_get_or_create(pl);
1413  kp->sent_up_to = 0;
1414 }
1415 
1425 
1426  while (cur) {
1427  if (cur->player_name == pl->ob->name) {
1429  }
1430  cur = cur->next;
1431  }
1432 
1433 }
1434 
1440  int i, last;
1441  SockList sl;
1442  size_t size;
1443  const knowledge_item *item;
1444  StringBuffer *buf;
1445  char *title;
1446  const Face *face;
1447  knowledge_player *cur = knowledge_global, *prev = NULL;
1448  player *pl;
1449 
1450  while (cur) {
1451 
1452  for (pl = first_player; pl != NULL; pl = pl->next) {
1453  if (pl->ob->name == cur->player_name) {
1454  break;
1455  }
1456  }
1457 
1458  /* player left, remove knowledge */
1459  if (pl == NULL || pl->state != ST_PLAYING) {
1460  if (prev == NULL) {
1461  knowledge_global = cur->next;
1462  } else {
1463  prev->next = cur->next;
1464  }
1465 
1466  free_knowledge_player(cur);
1467 
1468  /* wait until next tick to do something else */
1469  return;
1470  }
1471 
1472  if (cur->sent_up_to == -1 || cur->sent_up_to == cur->item_count) {
1473  prev = cur;
1474  cur = cur->next;
1475  continue;
1476  }
1477 
1478  last = MIN(cur->sent_up_to + 50, cur->item_count);
1479  SockList_Init(&sl);
1480  SockList_AddString(&sl, "addknowledge ");
1481  for (i = cur->sent_up_to; i < last; i++) {
1482  item = cur->items[i];
1483 
1484  buf = stringbuffer_new();
1485  item->handler->summary(item->item, buf);
1487 
1488  face = NULL;
1489  if (item->handler->item_face != NULL)
1490  face = item->handler->item_face(item->item);
1491 
1492  if (face == NULL)
1493  face = try_find_face(item->handler->face, NULL);
1494 
1495  size = 4 + (2 + strlen(item->handler->type)) + (2 + strlen(title)) + 4;
1496 
1497  if (SockList_Avail(&sl) < size) {
1498  Send_With_Handling(pl->socket, &sl);
1499  SockList_Reset(&sl);
1500  SockList_AddString(&sl, "addknowledge ");
1501  }
1502 
1503  SockList_AddInt(&sl, i + 1);
1504  SockList_AddLen16Data(&sl, item->handler->type, strlen(item->handler->type));
1505  if (face != NULL && !(pl->socket->faces_sent[face->number]&NS_FACESENT_FACE))
1506  esrv_send_face(pl->socket, face, 0);
1507  SockList_AddLen16Data(&sl, title, strlen(title));
1508  SockList_AddInt(&sl, face ? face->number : 0);
1509 
1510  free(title);
1511  }
1512 
1513  cur->sent_up_to = last;
1514 
1515  Send_With_Handling(pl->socket, &sl);
1516  SockList_Term(&sl);
1517 
1518  /* don't send more this tick */
1519  break;
1520  }
1521 }
1522 
1528 void knowledge_add_probe_monster(object *op, object *mon) {
1529  StringBuffer *buf = NULL;
1530  char *result;
1531 
1532  if (op->contr == NULL)
1533  return;
1534 
1535  buf = stringbuffer_new();
1536  stringbuffer_append_printf(buf, " *** %s ***\n", mon->name);
1537  describe_item(mon, NULL, 1, buf);
1538  result = stringbuffer_finish(buf);
1540  free(result);
1541 
1542  /*
1543  * TODO: Add to player's knowledge. This is disabled for now because the
1544  * monster being probed could be custom, but when the player goes to query
1545  * their knowledge they will only get information about the monster's
1546  * archetype.
1547  knowledge_player *kp;
1548  kp = knowledge_get_or_create(op->contr);
1549  knowledge_add(kp, mon->name, &knowledges[1]);
1550  */
1551 }
object_was_destroyed
#define object_was_destroyed(op, old_tag)
Checks if an object still exists.
Definition: object.h:70
knowledge_alchemy_attempt
static void knowledge_alchemy_attempt(player *pl, const knowledge_item *item)
Attempt an alchemy recipe through the knowledge system.
Definition: knowledge.cpp:353
knowledge_type::name
const char * name
Type name for player, to use with 'list'.
Definition: knowledge.cpp:138
Face
New face structure - this enforces the notion that data is face by face only - you can not change the...
Definition: face.h:14
PLAYER
@ PLAYER
Definition: object.h:112
player::next
player * next
Pointer to next player, NULL if this is last.
Definition: player.h:106
output_file.h
SockList_AddInt
void SockList_AddInt(SockList *sl, uint32_t data)
Adds a 32 bit value.
Definition: lowlevel.cpp:127
global.h
knowledge_send_info
void knowledge_send_info(socket_struct *ns)
Send the reply_info for 'knowledge_info'.
Definition: knowledge.cpp:1374
NS_FACESENT_FACE
#define NS_FACESENT_FACE
Bitmask for the faces_sent[] array - what portion of the face have we sent?
Definition: newserver.h:137
knowledge_type
One item type that may be known to the player.
Definition: knowledge.cpp:132
first_player
player * first_player
First player.
Definition: init.cpp:106
settings
struct Settings settings
Server settings.
Definition: init.cpp:139
knowledge_monster_add
static int knowledge_monster_add(struct knowledge_player *current, const char *item, const struct knowledge_type *type)
Add monster information to the player's knowledge, handling the multiple monster case.
Definition: knowledge.cpp:624
GeneralMessage
One general message, from the lib/messages file.
Definition: book.h:44
safe_strncpy
#define safe_strncpy
Definition: compat.h:27
get_formulalist
recipelist * get_formulalist(int i)
Gets a formula list by ingredients count.
Definition: recipe.cpp:98
llevError
@ llevError
Error, serious thing.
Definition: logger.h:11
LOG
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.cpp:58
of_close
int of_close(OutputFile *of)
Closes an output file.
Definition: output_file.cpp:61
use_alchemy
int use_alchemy(object *op)
Handle use_skill for alchemy-like items.
Definition: alchemy.cpp:1057
MONSTER_EXCLUDE_FROM_READABLE_KEY
#define MONSTER_EXCLUDE_FROM_READABLE_KEY
If set (any value), then monster is not listed in books.
Definition: object.h:596
TAG_END
#define TAG_END
Definition: knowledge.cpp:70
knowledge_god_validate
static int knowledge_god_validate(const char *item)
Check if a god knowledge item is still valid.
Definition: knowledge.cpp:706
of_open
FILE * of_open(OutputFile *of, const char *fname)
Opens an output file.
Definition: output_file.cpp:30
player
One player.
Definition: player.h:105
strdup_local
#define strdup_local
Definition: compat.h:29
object::inv
object * inv
Pointer to the first object in the inventory.
Definition: object.h:298
FLAG_STARTEQUIP
#define FLAG_STARTEQUIP
Object was given to player at start.
Definition: define.h:268
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
recipe::arch_names
size_t arch_names
Size of the arch_name[] array.
Definition: recipe.h:12
free_knowledge
void free_knowledge(void)
Free all knowledge data.
Definition: knowledge.cpp:1280
knowledge_add_probe_monster
void knowledge_add_probe_monster(object *op, object *mon)
Display monster details, then add to a player's knowledge if not already.
Definition: knowledge.cpp:1528
socket_struct
Socket structure, represents a client-server connection.
Definition: newserver.h:89
knowledge_alchemy_can_use_item
static StringBuffer * knowledge_alchemy_can_use_item(sstring code, const char *item, StringBuffer *buf, int index)
Check if an item can be used for a recipe, and fill the return buffer if it's the case.
Definition: knowledge.cpp:300
stringbuffer_append_printf
void stringbuffer_append_printf(StringBuffer *sb, const char *format,...)
Append a formatted string to a string buffer instance.
Definition: stringbuffer.cpp:138
knowledge_god_add
static int knowledge_god_add(struct knowledge_player *current, const char *item, const struct knowledge_type *type)
Add god information to the player's knowledge, handling the multiple monster case.
Definition: knowledge.cpp:728
object::arch
struct archetype * arch
Pointer to archetype.
Definition: object.h:424
stringbuffer_new
StringBuffer * stringbuffer_new(void)
Create a new string buffer.
Definition: stringbuffer.cpp:57
SockList_AddString
void SockList_AddString(SockList *sl, const char *data)
Adds a string without length.
Definition: lowlevel.cpp:157
knowledge_player::item_count
int item_count
How many items this players knows.
Definition: knowledge.cpp:156
object::x
int16_t x
Definition: object.h:335
knowledge_display
static void knowledge_display(object *pl, const char *params)
Display all a player's knowledge.
Definition: knowledge.cpp:1133
knowledge_face
const typedef Face *(* knowledge_face)(sstring code)
Get the face for a knowledge item.
Definition: knowledge.cpp:120
player::ob
object * ob
The object representing the player.
Definition: player.h:177
knowledge_type::item_face
knowledge_face item_face
Face for an item, if not defined the face it used.
Definition: knowledge.cpp:142
object::speed_left
float speed_left
How much speed is left to spend this round.
Definition: object.h:338
object::map
struct mapstruct * map
Pointer to the map in which this object is present.
Definition: object.h:305
knowledge_type::attempt_alchemy
knowledge_attempt attempt_alchemy
Definition: knowledge.cpp:140
recipelist::items
recipe * items
Pointer to first recipe in this list.
Definition: recipe.h:40
draw_ext_info_format
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...) PRINTF_ARGS(6
MIN
#define MIN(x, y)
Definition: compat.h:21
NDI_ALL_DMS
#define NDI_ALL_DMS
Inform all logged in DMs.
Definition: newclient.h:267
knowledge_is_valid_item
int(* knowledge_is_valid_item)(const char *code)
Function to check if the specified item is valid.
Definition: knowledge.cpp:94
object::count
tag_t count
Unique object number for this object.
Definition: object.h:307
MSG_TYPE_COMMAND_EXAMINE
#define MSG_TYPE_COMMAND_EXAMINE
Player examining something.
Definition: newclient.h:535
tolower
#define tolower(C)
Simple macro to convert a letter to lowercase.
Definition: c_new.cpp:30
knowledge_type::face
const char * face
Face for the type, as a basename.
Definition: knowledge.cpp:141
recipe::arch_name
char ** arch_name
Possible archetypes of the final product made.
Definition: recipe.h:13
blank_face
const Face * blank_face
Following can just as easily be pointers, but it is easier to keep them like this.
Definition: image.cpp:36
monster
the faster the spell may be cast there are several other common only the caster may be affected by the spell The most common spell range is that of touch This denotes that the caster much touch the recipient of the spell in order to release the spell monster
Definition: spell-info.txt:45
knowledge_alchemy_detail
static void knowledge_alchemy_detail(const char *value, StringBuffer *buf)
Give the full description of the alchemy recpie.
Definition: knowledge.cpp:240
SockList_AddLen16Data
void SockList_AddLen16Data(SockList *sl, const void *data, size_t len)
Adds a data block prepended with an 16 bit length field.
Definition: lowlevel.cpp:191
object::title
sstring title
Of foo, etc.
Definition: object.h:325
FLAG_INV_LOCKED
#define FLAG_INV_LOCKED
Item will not be dropped from inventory.
Definition: define.h:329
SockList_Reset
void SockList_Reset(SockList *sl)
Resets the length of the stored data for writing.
Definition: lowlevel.cpp:74
object_get_value
const char * object_get_value(const object *op, const char *const key)
Get an extra value by key.
Definition: object.cpp:4346
apply_by_living_below
void apply_by_living_below(object *pl)
Attempt to apply the object 'below' the player.
Definition: apply.cpp:695
MSG_TYPE_MISC
#define MSG_TYPE_MISC
Messages that don't go elsewhere.
Definition: newclient.h:416
buf
StringBuffer * buf
Definition: readable.cpp:1565
MSG_TYPE_COMMAND
#define MSG_TYPE_COMMAND
Responses to commands, eg, who.
Definition: newclient.h:407
knowledge_add
static int knowledge_add(knowledge_player *current, const char *item, const knowledge_type *kt)
Add a knowledge item to a player's store if not found yet.
Definition: knowledge.cpp:550
knowledge_summary
void(* knowledge_summary)(const char *code, StringBuffer *buf)
Function to fill the StringBuffer with the short description of an item.
Definition: knowledge.cpp:80
name
Plugin animator file specs[Config] name
Definition: animfiles.txt:4
TAG_START
#define TAG_START
Definition: knowledge.cpp:69
linked_char
Definition: global.h:98
draw_ext_info
vs only yadda is in because all tags get reset on the next draw_ext_info In the second since it is all in one draw_ext_info
Definition: media-tags.txt:61
knowledge_god_summary
static void knowledge_god_summary(const char *item, StringBuffer *buf)
God information summary.
Definition: knowledge.cpp:661
SockList_Avail
size_t SockList_Avail(const SockList *sl)
Returns the available bytes in a SockList instance.
Definition: lowlevel.cpp:246
knowledge_item::item
sstring item
Internal item code.
Definition: knowledge.cpp:148
knowledge_write_player_data
static void knowledge_write_player_data(const knowledge_player *kp)
Store all knowledge data for a player to disk.
Definition: knowledge.cpp:882
object::y
int16_t y
Position in the map for this object.
Definition: object.h:335
knowledge_god_face
static const Face * knowledge_god_face(sstring code)
Get the face for a god.
Definition: knowledge.cpp:774
knowledge_alchemy_get_recipe
static const recipe * knowledge_alchemy_get_recipe(const char *value)
Get a recipe from the internal code.
Definition: knowledge.cpp:172
stringbuffer_finish
char * stringbuffer_finish(StringBuffer *sb)
Deallocate the string buffer instance and return the string.
Definition: stringbuffer.cpp:76
letter
**Media tags please refer to the protocol file in doc Developers protocol Quick for your pleasure an example[/b][i] This is an old letter
Definition: media-tags.txt:15
knowledge_player::next
knowledge_player * next
Next player on the list.
Definition: knowledge.cpp:160
object::contr
struct player * contr
Pointer to the player which control this object.
Definition: object.h:284
knowledge_player::sent_up_to
int sent_up_to
Largest index that was sent to the client with notifications, -1 means the client doesn't want this i...
Definition: knowledge.cpp:158
knowledge_type::summary
knowledge_summary summary
Display the short description.
Definition: knowledge.cpp:134
add_refcount
sstring add_refcount(sstring str)
This will increase the refcount of the string str.
Definition: shstr.cpp:210
linked_char::name
const char * name
Definition: global.h:99
recipelist
List of recipes with a certain number of ingredients.
Definition: recipe.h:37
knowledge_message_validate
static int knowledge_message_validate(const char *item)
Check if a message is still valid.
Definition: knowledge.cpp:833
esrv_send_face
void esrv_send_face(socket_struct *ns, const Face *face, int nocache)
Sends a face to a client if they are in pixmap mode, nothing gets sent in bitmap mode.
Definition: image.cpp:72
command_take
void command_take(object *op, const char *params)
This takes (picks up) an item.
Definition: c_object.cpp:845
knowledge_type::add
knowledge_add_item add
Add the item to the knowledge store.
Definition: knowledge.cpp:137
free_knowledge_items
static void free_knowledge_items(knowledge_player *kp)
Free all knowledge items for a player.
Definition: knowledge.cpp:1252
query_name
void query_name(const object *op, char *buf, size_t size)
Describes an item.
Definition: item.cpp:588
stringbuffer_finish_shared
sstring stringbuffer_finish_shared(StringBuffer *sb)
Deallocate the string buffer instance and return the string as a shared string.
Definition: stringbuffer.cpp:85
archetype::clone
object clone
An object from which to do object_copy()
Definition: object.h:487
MSG_TYPE_COMMAND_INFO
#define MSG_TYPE_COMMAND_INFO
Generic info: resistances, etc.
Definition: newclient.h:529
add_string
sstring add_string(const char *str)
This will add 'str' to the hash table.
Definition: shstr.cpp:124
object::below
object * below
Pointer to the object stacked below this one.
Definition: object.h:295
object::face
const Face * face
Face with colors.
Definition: object.h:341
knowledge_show
static void knowledge_show(object *pl, const char *params)
Show the details of a knowledge item.
Definition: knowledge.cpp:1163
knowledge_type::type
const char * type
Type internal code, musn't have a double dot, must be unique ingame.
Definition: knowledge.cpp:133
object::type
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:348
knowledge_give
void knowledge_give(player *pl, const char *marker, const object *book)
Give a knowledge item from its code.
Definition: knowledge.cpp:996
recipe::index
int index
Index value derived from formula ingredients.
Definition: recipe.h:18
command_help
void command_help(object *op, const char *params)
Player is asking for some help.
Definition: c_misc.cpp:1772
knowledge_type::detail
knowledge_detail detail
Display the detailed description.
Definition: knowledge.cpp:135
linked_char::next
struct linked_char * next
Definition: global.h:100
title
Information on one title.
Definition: readable.cpp:108
knowledge_monster_summary
static void knowledge_monster_summary(const char *item, StringBuffer *buf)
Monster information summary.
Definition: knowledge.cpp:581
knowledge_global
static knowledge_player * knowledge_global
All known loaded knowledge for a player.
Definition: knowledge.cpp:164
tag_t
uint32_t tag_t
Object tag, unique during the whole game.
Definition: object.h:14
archetype
The archetype structure is a set of rules on how to generate and manipulate objects which point to ar...
Definition: object.h:483
sproto.h
get_message_body
sstring get_message_body(const GeneralMessage *message)
Get a message's body.
Definition: readable.cpp:2077
stringbuffer_append_string
void stringbuffer_append_string(StringBuffer *sb, const char *str)
Append a string to a string buffer instance.
Definition: stringbuffer.cpp:95
knowledge_player_knows
int knowledge_player_knows(const player *pl, const char *knowledge)
Determines whether a player knows a specific knowledge or not.
Definition: knowledge.cpp:1298
knowledge_type::validate
knowledge_is_valid_item validate
Validate the specific value.
Definition: knowledge.cpp:136
SockList_Init
void SockList_Init(SockList *sl)
Initializes the SockList instance.
Definition: lowlevel.cpp:55
get_message_from_identifier
const GeneralMessage * get_message_from_identifier(const char *identifier)
Find the message from its identifier.
Definition: assets.cpp:323
fatal
void fatal(enum fatal_error err)
fatal() is meant to be called whenever a fatal signal is intercepted.
Definition: utils.cpp:590
knowledge_get_or_create
static knowledge_player * knowledge_get_or_create(const player *pl)
Find or create the knowledge store for a player.
Definition: knowledge.cpp:968
knowledge_item_can_be_used_alchemy
void knowledge_item_can_be_used_alchemy(object *op, const object *item)
Displays known alchemy recipes an item can be used in.
Definition: knowledge.cpp:1334
recipe::ingred_count
int ingred_count
Number of items in ingred.
Definition: recipe.h:23
env
static std::shared_ptr< inja::Environment > env
Rendering environment.
Definition: mapper.cpp:2222
knowledges
static const knowledge_type knowledges[]
All handled knowledge items.
Definition: knowledge.cpp:853
MAX_BUF
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
knowledge_player::items
knowledge_item ** items
Known knowledge.
Definition: knowledge.cpp:155
MSG_TYPE_ADMIN_LOADSAVE
#define MSG_TYPE_ADMIN_LOADSAVE
load/save operations
Definition: newclient.h:502
strlcpy
size_t strlcpy(char *dst, const char *src, size_t size)
Portable implementation of strlcpy(3).
Definition: porting.cpp:222
knowledge_read
void knowledge_read(player *pl, object *book)
Player is reading a book, give knowledge if needed, warn player, and such.
Definition: knowledge.cpp:1056
describe_item
StringBuffer * describe_item(const object *op, const object *owner, int use_media_tags, StringBuffer *buf)
Describes an item, in all its details.
Definition: item.cpp:951
knowledge_detail
void(* knowledge_detail)(const char *code, StringBuffer *buf)
Function to fill the StringBuffer with a detailed description of an item.
Definition: knowledge.cpp:87
knowledge_first_player_save
void knowledge_first_player_save(player *pl)
Ensure the knowledge state is correctly saved for the player.
Definition: knowledge.cpp:1423
free_string
void free_string(sstring str)
This will reduce the refcount, and if it has reached 0, str will be freed.
Definition: shstr.cpp:280
knowledge_add_item
int(* knowledge_add_item)(knowledge_player *current, const char *item, const knowledge_type *type)
Add knowledge information to the player's knowledge.
Definition: knowledge.cpp:103
SockList_Term
void SockList_Term(SockList *sl)
Frees all resources allocated by a SockList instance.
Definition: lowlevel.cpp:65
Settings::playerdir
const char * playerdir
Where the player files are.
Definition: global.h:252
RANDOM
#define RANDOM()
Definition: define.h:638
StringBuffer
A buffer that will be expanded as content is added to it.
Definition: stringbuffer.cpp:25
recipe
One alchemy recipe.
Definition: recipe.h:10
knowledge_item
One known item for a player.
Definition: knowledge.cpp:147
ST_PLAYING
#define ST_PLAYING
Usual state.
Definition: define.h:535
command_knowledge
void command_knowledge(object *pl, const char *params)
Handle the 'knowledge' for a player.
Definition: knowledge.cpp:1213
knowledge_player::item_allocated
int item_allocated
How many items are allocated for items.
Definition: knowledge.cpp:157
knowledge_message_summary
static void knowledge_message_summary(const char *value, StringBuffer *buf)
Give the title of a message.
Definition: knowledge.cpp:802
NDI_UNIQUE
#define NDI_UNIQUE
Print immediately, don't buffer.
Definition: newclient.h:265
find_archetype_by_object_name
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.cpp:51
object::name
sstring name
The name of the object, obviously...
Definition: object.h:319
get_message_title
sstring get_message_title(const GeneralMessage *message)
Get a message's title.
Definition: readable.cpp:2068
knowledge_find
static const knowledge_type * knowledge_find(const char *type)
Find a knowledge handler from its type.
Definition: knowledge.cpp:867
mapstruct
This is a game-map.
Definition: map.h:315
knowledge_monster_detail
static void knowledge_monster_detail(const char *item, StringBuffer *buf)
Describe in detail a monster.
Definition: knowledge.cpp:595
sstring
const typedef char * sstring
Definition: sstring.h:2
knowledge_attempt
void(* knowledge_attempt)(player *pl, const knowledge_item *item)
Attempt an alchemy based on the specified knowledge.
Definition: knowledge.cpp:129
player::state
uint8_t state
Input state of the player (name, password, etc).
Definition: player.h:131
knowledge_player::player_name
sstring player_name
Player's name.
Definition: knowledge.cpp:154
knowledge_message_face
static const Face * knowledge_message_face(sstring code)
Get the face for a message.
Definition: knowledge.cpp:842
knowledge_do_display
static void knowledge_do_display(object *pl, const knowledge_type *show_only, const char *search)
Actually display knowledge list.
Definition: knowledge.cpp:1068
recipe::diff
int diff
Alchemical dfficulty level.
Definition: recipe.h:16
knowledge_send_known
void knowledge_send_known(player *pl)
Send initial known knowledge to player, if requested.
Definition: knowledge.cpp:1403
knowledge_god_detail
static void knowledge_god_detail(const char *item, StringBuffer *buf)
Describe in detail a god.
Definition: knowledge.cpp:677
knowledge_monster_face
static const Face * knowledge_monster_face(sstring code)
Get the face for a monster.
Definition: knowledge.cpp:646
knowledge_do_attempt
static void knowledge_do_attempt(object *pl, const char *params)
Player attempts something on a knowledge, get item and try it.
Definition: knowledge.cpp:1189
socket_struct::faces_sent
uint8_t * faces_sent
This is a bitmap on sent face status.
Definition: newserver.h:96
MSG_TYPE_CLIENT_NOTICE
#define MSG_TYPE_CLIENT_NOTICE
Non-critical note to player.
Definition: newclient.h:668
free_knowledge_player
static void free_knowledge_player(knowledge_player *kp)
Totally free a knowledge structure, and its items.
Definition: knowledge.cpp:1271
object::container
object * container
Current container being used.
Definition: object.h:299
knowledge_can_use_alchemy
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's the case.
Definition: knowledge.cpp:113
knowledge_item::handler
const knowledge_type * handler
How to handle this item.
Definition: knowledge.cpp:149
knowledge_monster_validate
static int knowledge_monster_validate(const char *item)
Check if a monster knowledge item is still valid.
Definition: knowledge.cpp:610
try_find_archetype
archetype * try_find_archetype(const char *name)
Definition: assets.cpp:269
recipe::ingred
linked_char * ingred
List of ingredients.
Definition: recipe.h:22
try_find_face
const Face * try_find_face(const char *name, const Face *error)
Definition: assets.cpp:285
player::has_directory
uint32_t has_directory
If 0, the player was not yet saved, its directory doesn't exist.
Definition: player.h:149
knowledge_read_player_data
static void knowledge_read_player_data(knowledge_player *kp)
Read all knowledge data for a player from disk, discarding invalid data.
Definition: knowledge.cpp:913
code
Crossfire Architecture the general intention is to enhance the enjoyability and playability of CF In this code
Definition: arch-handbook.txt:14
knowledge_message_detail
static void knowledge_message_detail(const char *value, StringBuffer *buf)
Give the full description of a message.
Definition: knowledge.cpp:818
knowledge_alchemy_validate
static int knowledge_alchemy_validate(const char *item)
Check if an alchemy recipe is still ok.
Definition: knowledge.cpp:288
archetype::name
sstring name
More definite name, like "generate_kobold".
Definition: object.h:484
object::nrof
uint32_t nrof
Number of objects.
Definition: object.h:342
knowledge_type::use_alchemy
knowledge_can_use_alchemy use_alchemy
If not null, checks if an item can be used in alchemy.
Definition: knowledge.cpp:139
recipe::next
recipe * next
Next recipe with the same number of ingredients.
Definition: recipe.h:24
socket_struct::notifications
uint16_t notifications
Notifications this client wants to get.
Definition: newserver.h:129
player::socket
socket_struct * socket
Socket information for this player.
Definition: player.h:107
recipe::skill
sstring skill
Skill name used to make this recipe.
Definition: recipe.h:26
knowledge_process_incremental
void knowledge_process_incremental(void)
Incrementally send knowledge information to players, and remove information for players who left.
Definition: knowledge.cpp:1439
describe_god
int describe_god(const object *god, int what, StringBuffer *buf, size_t maxlen)
Describe a god.
Definition: holy.cpp:109
knowledge_alchemy_summary
static void knowledge_alchemy_summary(const char *value, StringBuffer *buf)
Give the title of the alchemy recpie.
Definition: knowledge.cpp:210
knowledge_alchemy_face
static const Face * knowledge_alchemy_face(sstring code)
Try to get a face for an alchemy recipe.
Definition: knowledge.cpp:514
OUT_OF_MEMORY
@ OUT_OF_MEMORY
Definition: define.h:48
examine
void examine(object *op, object *tmp)
Player examines some object.
Definition: c_object.cpp:1985
Send_With_Handling
void Send_With_Handling(socket_struct *ns, SockList *sl)
Calls Write_To_Socket to send data to the client.
Definition: lowlevel.cpp:447
MSG_TYPE_ADMIN
#define MSG_TYPE_ADMIN
Definition: newclient.h:405
knowledge_player
Information about a player.
Definition: knowledge.cpp:153
SockList
Contains the base information we use to make up a packet we want to send.
Definition: newclient.h:684
recipe_get_face
const Face * recipe_get_face(const recipe *rp)
Return the best face associated with a recipe.
Definition: recipe.cpp:920
get_message_face
const Face * get_message_face(const GeneralMessage *message)
Get a message's face.
Definition: readable.cpp:2086
recipe_get_difficulty_string
const char * recipe_get_difficulty_string(int difficulty)
A method to produce a difficulty adjective to describe alchemy projects.
Definition: recipe.cpp:962
llevDebug
@ llevDebug
Only for debugging purposes.
Definition: logger.h:13
is_valid_types_gen.type
list type
Definition: is_valid_types_gen.py:25
SockList_AddPrintf
void SockList_AddPrintf(SockList *sl, const char *format,...)
Adds a printf like formatted string.
Definition: lowlevel.cpp:202
knowledge_known
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.cpp:532
face
in that case they will be relative to whatever the PWD of the crossfire server process is You probably shouldn though Notes on Specific and settings file datadir Usually usr share crossfire Contains data that the server does not need to modify while such as the etc A default install will pack the and treasurelist definitions into a single or trs file and the graphics into a face(metadata) and .tar(bitmaps) file
put_object_in_sack
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.cpp:937
OutputFile
Definition: output_file.h:41
recipe::cauldron
sstring cauldron
Arch of the cauldron/workbench used to house the formulae.
Definition: recipe.h:27
recipe::title
sstring title
Distinguishing name of product.
Definition: recipe.h:11
Settings::localdir
const char * localdir
Read/write data files.
Definition: global.h:251