Crossfire Server, Trunk
recipe.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 
35 #include "global.h"
36 
37 #include <assert.h>
38 #include <ctype.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <memory>
42 
43 #include "object.h"
44 #include "assets.h"
45 #include "AssetsManager.h"
46 
47 static void build_stringlist(const char *str, char ***result_list, size_t *result_size);
48 
51 
60 static recipelist *init_recipelist(void) {
61  recipelist *tl = (recipelist *)malloc(sizeof(recipelist));
62  if (tl == NULL)
64  tl->total_chance = 0;
65  tl->number = 0;
66  tl->items = NULL;
67  tl->next = NULL;
68  return tl;
69 }
70 
79 static recipe *get_empty_formula(void) {
80  // This used to be a malloc followed by setting everything to zero.
81  // So just use calloc to make it faster.
82  // SilverNexus -- 2018-10-22
83  recipe *t = (recipe *)calloc(1, sizeof(recipe));
84  if (t == NULL)
86  return t;
87 }
88 
99  recipelist *fl = formulalist;
100  int number = i;
101 
102  while (fl && number > 1) {
103  if (!(fl = fl->next))
104  break;
105  number--;
106  }
107  return fl;
108 }
109 
120 static int check_recipe(const recipe *rp) {
121  size_t i;
122  int result;
123 
124  result = 1;
125  for (i = 0; i < rp->arch_names; i++) {
126  if (try_find_archetype(rp->arch_name[i]) != NULL) {
127  if (strcmp(rp->title, "NONE")) {
128  const artifact *art = locate_recipe_artifact(rp, i);
129 
130  if (!art) {
131  LOG(llevError, "Formula %s of %s has no artifact.\n", rp->arch_name[i], rp->title);
132  result = 0;
133  }
134  }
135  } else {
136  LOG(llevError, "Can't find archetype %s for formula %s\n", rp->arch_name[i], rp->title);
137  result = 0;
138  }
139  }
140 
141  return result;
142 }
143 
148  const recipelist *rl = formulalist;
149  int abort = 0;
150  while (rl) {
151  const recipe *rp = rl->items;
152  while (rp) {
153  if (!check_recipe(rp)) {
154  abort = 1;
155  }
156  rp = rp->next;
157  }
158  rl = rl->next;
159  }
160  return !abort;
161 }
162 
166 void init_formulae(BufferReader *reader, const char *filename) {
167  char *buf, *cp, *next;
168  recipe *formula = NULL;
169  recipelist *fl;
170  linked_char *tmp;
171  int value;
172 
173  if (!formulalist)
175 
176  while ((buf = bufferreader_next_line(reader)) != NULL) {
177  if (*buf == '#' || *buf == '\0')
178  continue;
179  cp = buf;
180  while (*cp == ' ') /* Skip blanks */
181  cp++;
182 
183  if (!strncmp(cp, "Remove ", 7)) {
184  if (strcmp(cp + 7, "*") == 0) {
187  } else {
188  LOG(llevError, "Recipes: only '*' is accepted for 'Remove' at %s:%zu\n", filename, bufferreader_current_line(reader));
189  }
190  continue;
191  }
192  if (!strncmp(cp, "Object", 6)) {
193  formula = get_empty_formula();
194  formula->title = add_string(strchr(cp, ' ')+1);
195  } else if (formula == NULL) {
196  LOG(llevError, "recipe.c: First key in formulae file %s is not \"Object\".\n", filename);
198  } else if (!strncmp(cp, "keycode", 7)) {
199  formula->keycode = add_string(strchr(cp, ' ')+1);
200  } else if (sscanf(cp, "trans %d", &value)) {
201  formula->transmute = value;
202  } else if (sscanf(cp, "yield %d", &value)) {
203  formula->yield = value;
204  } else if (sscanf(cp, "chance %d", &value)) {
205  formula->chance = value;
206  } else if (sscanf(cp, "exp %d", &value)) {
207  formula->exp = value;
208  } else if (sscanf(cp, "diff %d", &value)) {
209  formula->diff = value;
210  } else if (!strncmp(cp, "ingred", 6)) {
211  int numb_ingred;
212  formula->ingred_count = 1;
213  cp = strchr(cp, ' ')+1;
214  do {
215  if ((next = strchr(cp, ',')) != NULL) {
216  *(next++) = '\0';
217  formula->ingred_count++;
218  }
219  tmp = (linked_char *)malloc(sizeof(linked_char));
220  /* trim the string */
221  while (*cp == ' ')
222  cp++;
223  while (*cp != '\0' && cp[strlen(cp) - 1] == ' ')
224  cp[strlen(cp) - 1] = '\0';
225  tmp->name = add_string(cp);
226  tmp->next = formula->ingred;
227  formula->ingred = tmp;
228  /* each ingredient's ASCII value is coadded. Later on this
229  * value will be used allow us to search the formula lists
230  * quickly for the right recipe.
231  */
232  formula->index += strtoint(cp);
233  } while ((cp = next) != NULL);
234  /* now find the correct (# of ingred ordered) formulalist */
235  numb_ingred = formula->ingred_count;
236  fl = formulalist;
237  while (numb_ingred != 1) {
238  if (!fl->next)
239  fl->next = init_recipelist();
240  fl = fl->next;
241  numb_ingred--;
242  }
243  formula->next = fl->items;
244  fl->items = formula;
245  } else if (!strncmp(cp, "arch", 4)) {
246  build_stringlist(strchr(cp, ' ')+1, &formula->arch_name, &formula->arch_names);
247  } else if (!strncmp(cp, "skill", 5)) {
248  formula->skill = add_string(strchr(cp, ' ')+1);
249  } else if (!strncmp(cp, "cauldron", 8)) {
250  formula->cauldron = add_string(strchr(cp, ' ')+1);
251  } else if (!strncmp(cp, "failure_arch ", 13)) {
252  formula->failure_arch = add_string(strchr(cp, ' ')+1);
253  } else if (!strncmp(cp, "failure_message ", 16)) {
254  formula->failure_message = add_string(strchr(cp, ' ')+1);
255  } else if (sscanf(cp, "min_level %d", &value)) {
256  formula->min_level = value;
257  } else if (!strncmp(cp, "tool ", 5)) {
258  build_stringlist(strchr(cp, ' ')+1, &formula->tool, &formula->tool_size);
259  } else if (sscanf(cp, "combination %d", &value)) {
260  formula->is_combination = value ? 1 : 0;
261  } else
262  LOG(llevError, "Unknown input in file %s: %s\n", filename, buf);
263  }
264  /* Set the total chance and count for each formula list.
265  * This needs to be done at the end to avoid dependancies on the field order in the file
266  */
267  for (fl = formulalist; fl; fl = fl->next) {
268  fl->total_chance = 0;
269  fl->number = 0;
270  for (formula = fl->items; formula; formula = formula->next) {
271  fl->total_chance += formula->chance;
272  fl->number++;
273  }
274  }
275  LOG(llevDebug, "done.\n");
276 }
277 
292 bool check_formulae(void) {
293  recipelist *fl;
294  recipe *check, *formula;
295  int numb = 1, tool_match;
296  size_t tool_i,tool_j;
297  bool success = true;
298 
299  LOG(llevDebug, "Checking formulae lists...\n");
300 
301  for (fl = formulalist; fl != NULL; fl = fl->next) {
302  for (formula = fl->items; formula != NULL; formula = formula->next) {
303  for (check = formula->next; check != NULL; check = check->next)
304  /* If one recipe has a tool and another a caudron, we should be able to handle it */
305  if (check->index == formula->index && check->cauldron == formula->cauldron && (check->tool_size == formula->tool_size)) {
306  /* Check the tool list to make sure they have no matches */
307  if (check->tool_size > 0 && check->tool && formula->tool)
308  {
309  tool_match = 0;
310  for (tool_i = 0; tool_i < formula->tool_size; ++tool_i)
311  /* If it turns out these lists are sorted, then we could optimize this better. */
312  for (tool_j = 0; tool_j < check->tool_size; ++tool_j)
313  if (strcmp(formula->tool[tool_i], check->tool[tool_j]) == 0) {
314  tool_match = 1;
315  break; /* TODO: break out of the double loop */
316  }
317  }
318  else
319  tool_match = 1; /* If we get here, we matched on the cauldron */
320  /* Check to see if we have a denoted match */
321  if (tool_match) {
322  /* if the recipes don't have the same facility, then no issue anyway. */
323  LOG(llevError, " ERROR: On %d ingred list:\n", numb);
324  LOG(llevError, "Formulae [%s] of %s and [%s] of %s have matching index id (%d)\n",
325  formula->arch_name[0], formula->title, check->arch_name[0], check->title, formula->index);
326  success = false;
327  }
328  }
329  for (size_t idx = 0; idx < formula->arch_names; idx++) {
330  if (try_find_archetype(formula->arch_name[idx]) == NULL) {
331  LOG(llevError, "Formulae %s of %s (%d ingredients) references non existent archetype %s\n",
332  formula->arch_name[0], formula->title, numb, formula->arch_name[idx]);
333  success = false;
334  }
335  }
336  }
337  numb++;
338  }
339 
340  return success;
341 }
342 
350 void dump_alchemy(void) {
351  recipelist *fl = formulalist;
352  recipe *formula = NULL;
353  linked_char *next;
354  int num_ingred = 1;
355 
356  fprintf(logfile, "\n");
357  while (fl) {
358  fprintf(logfile, "\n Formulae with %d ingredient%s %d Formulae with total_chance=%d\n", num_ingred, num_ingred > 1 ? "s." : ".", fl->number, fl->total_chance);
359  for (formula = fl->items; formula != NULL; formula = formula->next) {
360  const artifact *art = NULL;
361  char buf[MAX_BUF];
362  size_t i;
363 
364  for (i = 0; i < formula->arch_names; i++) {
365  const char *string = formula->arch_name[i];
366 
367  if (try_find_archetype(string) != NULL) {
368  art = locate_recipe_artifact(formula, i);
369  if (!art && strcmp(formula->title, "NONE"))
370  LOG(llevError, "Formula %s has no artifact\n", formula->title);
371  else {
372  if (strcmp(formula->title, "NONE"))
373  snprintf(buf, sizeof(buf), "%s of %s", string, formula->title);
374  else
375  strlcpy(buf, string, sizeof(buf));
376  fprintf(logfile, "%-30s(%d) bookchance %3d ", buf, formula->index, formula->chance);
377  fprintf(logfile, "skill %s", formula->skill);
378  fprintf(logfile, "\n");
379  if (formula->ingred != NULL) {
380  int nval = 0, tval = 0;
381  fprintf(logfile, "\tIngred: ");
382  for (next = formula->ingred; next != NULL; next = next->next) {
383  if (nval != 0)
384  fprintf(logfile, ",");
385  fprintf(logfile, "%s(%d)", next->name, (nval = strtoint(next->name)));
386  tval += nval;
387  }
388  fprintf(logfile, "\n");
389  if (tval != formula->index)
390  fprintf(logfile, "WARNING:ingredient list and formula values not equal.\n");
391  }
392  if (formula->skill != NULL)
393  fprintf(logfile, "\tSkill Required: %s", formula->skill);
394  if (formula->cauldron != NULL)
395  fprintf(logfile, "\tCauldron: %s\n", formula->cauldron);
396  fprintf(logfile, "\tDifficulty: %d\t Exp: %d\n", formula->diff, formula->exp);
397  }
398  } else
399  LOG(llevError, "Can't find archetype:%s for formula %s\n", string, formula->title);
400  }
401  }
402  fprintf(logfile, "\n");
403  fl = fl->next;
404  num_ingred++;
405  }
406 }
407 
422 archetype *find_treasure_by_name(const treasure *t, const char *name, int depth) {
423  treasurelist *tl;
424  archetype *at;
425 
426  if (depth > 10)
427  return NULL;
428 
429  while (t != NULL) {
430  if (t->name != NULL) {
431  tl = find_treasurelist(t->name);
432  at = find_treasure_by_name(tl->items, name, depth+1);
433  if (at != NULL)
434  return at;
435  } else {
436  if (!strcasecmp(t->item->clone.name, name))
437  return t->item;
438  }
439  if (t->next_yes != NULL) {
440  at = find_treasure_by_name(t->next_yes, name, depth);
441  if (at != NULL)
442  return at;
443  }
444  if (t->next_no != NULL) {
445  at = find_treasure_by_name(t->next_no, name, depth);
446  if (at != NULL)
447  return at;
448  }
449  t = t->next;
450  }
451  return NULL;
452 }
453 
473 static long recipe_find_ingredient_cost(const char *name) {
474  long mult;
475  const char *cp;
476  char part1[100];
477  char part2[100];
478 
479  /* same as atoi(), but skip number */
480  mult = 0;
481  while (isdigit(*name)) {
482  mult = 10*mult+(*name-'0');
483  name++;
484  }
485  if (mult > 0)
486  name++;
487  else
488  mult = 1;
489  /* first, try to match the name of an archetype */
490 
491  long value = 0;
492  bool found = false;
493  getManager()->archetypes()->each([&value, &found, &name, &part1] (const archetype *at) {
494  if (found) {
495  return;
496  }
497 
498  if (at->clone.title != NULL) {
499  /* inefficient, but who cares? */
500  snprintf(part1, sizeof(part1), "%s %s", at->clone.name, at->clone.title);
501  if (!strcasecmp(part1, name)) {
502  value = at->clone.value;
503  found = true;
504  return;
505  }
506  }
507  if (!strcasecmp(at->clone.name, name)) {
508  value = at->clone.value;
509  found = true;
510  return;
511  }
512  });
513  if (found) {
514  return mult * value;
515  }
516 
517  /* second, try to match an artifact ("arch of something") */
518  cp = strstr(name, " of ");
519  if (cp != NULL) {
520  safe_strncpy(part1, name, sizeof(part1));
521  part1[cp-name] = '\0';
522  safe_strncpy(part2, cp + 4, sizeof(part2));
523  getManager()->archetypes()->each([&value, &found, &part1, &part2] (const archetype *at) {
524  if (found) {
525  return;
526  }
527 
528  if (!strcasecmp(at->clone.name, part1) && at->clone.title == NULL) {
529  /* find the first artifact derived from that archetype (same type) */
530  for (auto al = first_artifactlist; al != NULL; al = al->next) {
531  if (al->type == at->clone.type) {
532  for (const auto art : al->items) {
533  if (!strcasecmp(art->item->name, part2)) {
534  value = at->clone.value * art->item->value;
535  found = true;
536  return;
537  }
538  }
539  }
540  }
541  }
542  });
543  }
544  if (found) {
545  return mult * value;
546  }
547 
548  /* third, try to match a body part ("arch's something") */
549  cp = strstr(name, "'s ");
550  if (cp != NULL) {
551  safe_strncpy(part1, name, sizeof(part1));
552  part1[cp-name] = '\0';
553  safe_strncpy(part2, cp + 3, sizeof(part2));
554  /* examine all archetypes matching the first part of the name */
555  getManager()->archetypes()->each([&value, &found, &part1, &part2] (const archetype *at) {
556  if (found) {
557  return;
558  }
559  if (!strcasecmp(at->clone.name, part1) && at->clone.title == NULL) {
560  if (at->clone.randomitems != NULL) {
561  auto at2 = find_treasure_by_name(at->clone.randomitems->items, part2, 0);
562  if (at2 != NULL) {
563  value = at2->clone.value * isqrt(at->clone.level * 2);
564  found = true;
565  return;
566  }
567  }
568  }
569  });
570  }
571  if (found) {
572  return mult * value;
573  }
574 
575  /* failed to find any matching items -- formula should be checked */
576  LOG(llevError, "Couldn't find cost for ingredient %s\n", name);
577  return -1;
578 }
579 
588 void dump_alchemy_costs(void) {
589  recipelist *fl = formulalist;
590  recipe *formula = NULL;
591  linked_char *next;
592  int num_ingred = 1;
593  int num_errors = 0;
594  long cost;
595  long tcost;
596 
597  fprintf(logfile, "\n");
598  while (fl) {
599  fprintf(logfile, "\n Formulae with %d ingredient%s %d Formulae with total_chance=%d\n", num_ingred, num_ingred > 1 ? "s." : ".", fl->number, fl->total_chance);
600  for (formula = fl->items; formula != NULL; formula = formula->next) {
601  const artifact *art = NULL;
602  const archetype *at = NULL;
603  char buf[MAX_BUF];
604  size_t i;
605 
606  for (i = 0; i < formula->arch_names; i++) {
607  const char *string = formula->arch_name[i];
608 
609  if ((at = try_find_archetype(string)) != NULL) {
610  art = locate_recipe_artifact(formula, i);
611  if (!art && strcmp(formula->title, "NONE"))
612  LOG(llevError, "Formula %s has no artifact\n", formula->title);
613  else {
614  if (!strcmp(formula->title, "NONE"))
615  strlcpy(buf, string, sizeof(buf));
616  else
617  snprintf(buf, sizeof(buf), "%s of %s", string, formula->title);
618  fprintf(logfile, "\n%-40s bookchance %3d skill %s\n", buf, formula->chance, formula->skill);
619  if (formula->ingred != NULL) {
620  tcost = 0;
621  for (next = formula->ingred; next != NULL; next = next->next) {
623  if (cost < 0)
624  num_errors++;
625  fprintf(logfile, "\t%-33s%5ld\n", next->name, cost);
626  if (cost < 0 || tcost < 0)
627  tcost = -1;
628  else
629  tcost += cost;
630  }
631  if (art != NULL && art->item != NULL)
632  cost = at->clone.value*art->item->value;
633  else
634  cost = at->clone.value;
635  fprintf(logfile, "\t\tBuying result costs: %5ld", cost);
636  if (formula->yield > 1) {
637  fprintf(logfile, " to %ld (max %d items)\n", cost*formula->yield, formula->yield);
638  cost = cost*(formula->yield+1L)/2L;
639  } else
640  fprintf(logfile, "\n");
641  fprintf(logfile, "\t\tIngredients cost: %5ld\n\t\tComment: ", tcost);
642  if (tcost < 0)
643  fprintf(logfile, "Could not find some ingredients. Check the formula!\n");
644  else if (tcost > cost)
645  fprintf(logfile, "Ingredients are much too expensive. Useless formula.\n");
646  else if (tcost*2L > cost)
647  fprintf(logfile, "Ingredients are too expensive.\n");
648  else if (tcost*10L < cost)
649  fprintf(logfile, "Ingredients are too cheap.\n");
650  else
651  fprintf(logfile, "OK.\n");
652  }
653  }
654  } else
655  LOG(llevError, "Can't find archetype:%s for formula %s\n", string, formula->title);
656  }
657  }
658  fprintf(logfile, "\n");
659  fl = fl->next;
660  num_ingred++;
661  }
662  if (num_errors > 0)
663  fprintf(logfile, "WARNING: %d objects required by the formulae do not exist in the game.\n", num_errors);
664 }
665 
674 static const char *ingred_name(const char *name) {
675  const char *cp = name;
676 
677  if (atoi(cp))
678  cp = strchr(cp, ' ')+1;
679  return cp;
680 }
681 
690 static int numb_ingred(const char *buf) {
691  int numb;
692 
693  if ((numb = atoi(buf)))
694  return numb;
695  else
696  return 1;
697 }
698 
709 int strtoint(const char *buf) {
710  const char *cp = ingred_name(buf);
711  int val = 0, len = strlen(cp), mult = numb_ingred(buf);
712 
713  while (len) {
714  val += tolower(*cp);
715  cp++; len--;
716  }
717  return val*mult;
718 }
719 
730 const artifact *locate_recipe_artifact(const recipe *rp, size_t idx) {
731  std::unique_ptr<object, void(*)(object *)> item(create_archetype(rp->arch_name[idx]), object_free_drop_inventory);
732  const artifactlist *at = NULL;
733 
734  if (!item)
735  return (artifact *)NULL;
736 
737  if ((at = find_artifactlist(item->type)))
738  for (auto art : at->items)
739  if (!strcmp(art->item->name, rp->title) && legal_artifact_combination(item.get(), art))
740  return art;
741 
742  return nullptr;
743 }
744 
752  recipelist *fl = NULL;
753  int number = 0, roll = 0;
754 
755  /* first, determine # of recipelist we have */
756  for (fl = get_formulalist(1); fl; fl = fl->next)
757  number++;
758 
759  /* now, randomly choose one */
760  if (number > 0)
761  roll = RANDOM()%number;
762 
763  fl = get_formulalist(1);
764  while (roll && fl) {
765  if (fl->next)
766  fl = fl->next;
767  else
768  break;
769  roll--;
770  }
771  if (!fl) /* failed! */
772  LOG(llevError, "get_random_recipelist(): no recipelists found!\n");
773  else if (fl->total_chance == 0)
774  fl = get_random_recipelist();
775 
776  return fl;
777 }
778 
788  recipelist *fl = rpl;
789  recipe *rp = NULL;
790  int r = 0;
791 
792  /* looks like we have to choose a random one */
793  if (fl == NULL)
794  if ((fl = get_random_recipelist()) == NULL)
795  return rp;
796 
797  if (fl->total_chance > 0) {
798  r = RANDOM()%fl->total_chance;
799  for (rp = fl->items; rp; rp = rp->next) {
800  r -= rp->chance;
801  if (r < 0)
802  break;
803  }
804  }
805  return rp;
806 }
807 
811 void free_all_recipes(void) {
812  recipelist *fl, *flnext;
813  recipe *formula = NULL, *next;
814  linked_char *lchar, *charnext;
815 
816  LOG(llevDebug, "Freeing all the recipes\n");
817  for (fl = formulalist; fl != NULL; fl = flnext) {
818  flnext = fl->next;
819 
820  for (formula = fl->items; formula != NULL; formula = next) {
821  next = formula->next;
822 
823  free(formula->arch_name[0]);
824  free(formula->arch_name);
825  if (formula->title)
826  free_string(formula->title);
827  if (formula->skill)
828  free_string(formula->skill);
829  if (formula->cauldron)
830  free_string(formula->cauldron);
831  if (formula->failure_arch)
832  free_string(formula->failure_arch);
833  if (formula->failure_message)
834  free_string(formula->failure_message);
835  for (lchar = formula->ingred; lchar; lchar = charnext) {
836  charnext = lchar->next;
837  free_string(lchar->name);
838  free(lchar);
839  }
840  if (formula->tool)
841  free(formula->tool[0]);
842  free(formula->tool);
843  free(formula);
844  }
845  free(fl);
846  }
847  formulalist = NULL;
848 }
849 
861 static void build_stringlist(const char *str, char ***result_list, size_t *result_size) {
862  char *dup;
863  char *p;
864  size_t size;
865  size_t i;
866 
867  dup = strdup_local(str);
868  if (dup == NULL)
870 
871  size = 0;
872  for (p = strtok(dup, ","); p != NULL; p = strtok(NULL, ","))
873  size++;
874 
875  assert(size > 0);
876  *result_list = static_cast<char **>(malloc(sizeof(**result_list) * size));
877  if (*result_list == NULL)
879  *result_size = size;
880 
881  for (i = 0; i < size; i++) {
882  (*result_list)[i] = dup;
883  dup = dup+strlen(dup)+1;
884  }
885 }
886 
894 recipe *find_recipe_for_tool(const char *tool, recipe *from) {
895  size_t t;
897  recipe *test = from ? from->next : list->items;
898 
899  while (list) {
900  while (test) {
901  for (t = 0; t < test->tool_size; t++) {
902  if (strcmp(test->tool[t], tool) == 0) {
903  return test;
904  }
905  }
906  test = test->next;
907  }
908 
909  list = list->next;
910  }
911 
912  return NULL;
913 }
914 
920 const Face *recipe_get_face(const recipe *rp) {
921  const artifact *art;
922  archetype *arch;
923  object *item;
924  const Face *face;
925 
926  if (rp->arch_names == 0)
927  return NULL;
928 
930  if (arch == NULL) {
931  return NULL;
932  }
933  if (strcmp(rp->title, "NONE") == 0) {
934  return arch->clone.face;
935  }
936 
937  art = locate_recipe_artifact(rp, 0);
938  if (art == NULL)
939  return arch->clone.face;
940 
941  face = arch->clone.face;
945  if (item->face != NULL && item->face != blank_face)
946  face = item->face;
948 
949  return face;
950 }
951 
962 const char *recipe_get_difficulty_string(int difficulty) {
963  if (difficulty < 5)
964  return "basic";
965  if (difficulty < 10)
966  return "simple";
967  if (difficulty < 15)
968  return "advanced";
969  if (difficulty < 20)
970  return "complicated";
971  if (difficulty < 25)
972  return "difficult";
973  if (difficulty < 30)
974  return "challenging";
975  if (difficulty < 35)
976  return "frustrating";
977  return "vexatious";
978 }
find_recipe_for_tool
recipe * find_recipe_for_tool(const char *tool, recipe *from)
Definition: recipe.cpp:894
give.next
def next
Definition: give.py:44
Face
Definition: face.h:14
global.h
FREE_OBJ_NO_DESTROY_CALLBACK
#define FREE_OBJ_NO_DESTROY_CALLBACK
Definition: object.h:545
safe_strncpy
#define safe_strncpy
Definition: compat.h:27
get_formulalist
recipelist * get_formulalist(int i)
Definition: recipe.cpp:98
recipe::tool_size
size_t tool_size
Definition: recipe.h:33
bufferreader_current_line
size_t bufferreader_current_line(BufferReader *br)
Definition: bufferreader.cpp:140
llevError
@ llevError
Definition: logger.h:11
LOG
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.cpp:58
strdup_local
#define strdup_local
Definition: compat.h:29
recipe::arch_names
size_t arch_names
Definition: recipe.h:12
archininventory.arch
arch
DIALOGCHECK MINARGS 1 MAXARGS 1
Definition: archininventory.py:16
treasurelist::items
treasure * items
Definition: treasure.h:92
AssetsManager.h
dump_alchemy_costs
void dump_alchemy_costs(void)
Definition: recipe.cpp:588
init_recipelist
static recipelist * init_recipelist(void)
Definition: recipe.cpp:60
recipe::yield
int yield
Definition: recipe.h:21
get_random_recipelist
static recipelist * get_random_recipelist(void)
Definition: recipe.cpp:751
recipe::failure_arch
sstring failure_arch
Definition: recipe.h:28
guildoracle.list
list
Definition: guildoracle.py:87
give_artifact_abilities
void give_artifact_abilities(object *op, const object *artifact)
Definition: artifact.cpp:230
recipelist::next
recipelist * next
Definition: recipe.h:41
artifact::item
object * item
Definition: artifact.h:15
recipelist::items
recipe * items
Definition: recipe.h:40
check_recipe
static int check_recipe(const recipe *rp)
Definition: recipe.cpp:120
tolower
#define tolower(C)
Definition: c_new.cpp:30
find_treasurelist
treasurelist * find_treasurelist(const char *name)
Definition: assets.cpp:249
recipe::failure_message
sstring failure_message
Definition: recipe.h:29
Ice.tmp
int tmp
Definition: Ice.py:207
recipe::arch_name
char ** arch_name
Definition: recipe.h:13
blank_face
const Face * blank_face
Definition: image.cpp:36
SEE_LAST_ERROR
@ SEE_LAST_ERROR
Definition: define.h:52
recipe::transmute
int transmute
Definition: recipe.h:19
npc_dialog.filename
filename
Definition: npc_dialog.py:99
object::title
sstring title
Definition: object.h:325
recipe_find_ingredient_cost
static long recipe_find_ingredient_cost(const char *name)
Definition: recipe.cpp:473
recipe::exp
int exp
Definition: recipe.h:17
diamondslots.object
object
Definition: diamondslots.py:34
check_recipes
bool check_recipes()
Definition: recipe.cpp:147
buf
StringBuffer * buf
Definition: readable.cpp:1565
getManager
AssetsManager * getManager()
Definition: assets.cpp:305
recipelist::total_chance
int total_chance
Definition: recipe.h:38
formulalist
static recipelist * formulalist
Definition: recipe.cpp:50
linked_char
Definition: global.h:96
recipe::is_combination
int is_combination
Definition: recipe.h:31
object_free_drop_inventory
void object_free_drop_inventory(object *ob)
Definition: object.cpp:1560
linked_char::name
const char * name
Definition: global.h:97
recipelist
Definition: recipe.h:37
rotate-tower.result
bool result
Definition: rotate-tower.py:13
treasurelist
Definition: treasure.h:85
archetype::clone
object clone
Definition: object.h:487
check_formulae
bool check_formulae(void)
Definition: recipe.cpp:292
add_string
sstring add_string(const char *str)
Definition: shstr.cpp:124
make_face_from_files.str
str
Definition: make_face_from_files.py:30
object::value
int32_t value
Definition: object.h:360
recipe::index
int index
Definition: recipe.h:18
numb_ingred
static int numb_ingred(const char *buf)
Definition: recipe.cpp:690
linked_char::next
struct linked_char * next
Definition: global.h:98
object_free
void object_free(object *ob, int flags)
Definition: object.cpp:1592
artifactlist
Definition: artifact.h:24
archetype
Definition: object.h:483
logfile
FILE * logfile
Definition: init.cpp:114
AssetsCollection::each
void each(std::function< void(T *)> op)
Definition: AssetsCollection.h:158
nlohmann::detail::void
j template void())
Definition: json.hpp:4099
fatal
void fatal(enum fatal_error err)
Definition: utils.cpp:590
recipe::ingred_count
int ingred_count
Definition: recipe.h:23
AssetsManager::archetypes
Archetypes * archetypes()
Definition: AssetsManager.h:44
MAX_BUF
#define MAX_BUF
Definition: define.h:35
free_all_recipes
void free_all_recipes(void)
Definition: recipe.cpp:811
strlcpy
size_t strlcpy(char *dst, const char *src, size_t size)
Definition: porting.cpp:222
create_archetype
object * create_archetype(const char *name)
Definition: arch.cpp:278
free_string
void free_string(sstring str)
Definition: shstr.cpp:280
RANDOM
#define RANDOM()
Definition: define.h:644
is_valid_types_gen.found
found
Definition: is_valid_types_gen.py:39
recipe
Definition: recipe.h:10
recipe::tool
char ** tool
Definition: recipe.h:32
Floor.t
t
Definition: Floor.py:62
object::name
sstring name
Definition: object.h:319
get_random_recipe
recipe * get_random_recipe(recipelist *rpl)
Definition: recipe.cpp:787
bigchest.check
check
Definition: bigchest.py:10
locate_recipe_artifact
const artifact * locate_recipe_artifact(const recipe *rp, size_t idx)
Definition: recipe.cpp:730
ingred_name
static const char * ingred_name(const char *name)
Definition: recipe.cpp:674
find_treasure_by_name
archetype * find_treasure_by_name(const treasure *t, const char *name, int depth)
Definition: recipe.cpp:422
recipe::chance
int chance
Definition: recipe.h:14
item
Definition: item.py:1
autojail.value
value
Definition: autojail.py:6
dump_alchemy
void dump_alchemy(void)
Definition: recipe.cpp:350
strtoint
int strtoint(const char *buf)
Definition: recipe.cpp:709
recipe::diff
int diff
Definition: recipe.h:16
assets.h
arch_to_object
object * arch_to_object(archetype *at)
Definition: arch.cpp:229
object_give_identified_properties
void object_give_identified_properties(object *op)
Definition: item.cpp:1356
init_formulae
void init_formulae(BufferReader *reader, const char *filename)
Definition: recipe.cpp:166
strcasecmp
int strcasecmp(const char *s1, const char *s2)
recipe::keycode
sstring keycode
Definition: recipe.h:25
recipelist::number
int number
Definition: recipe.h:39
recipe::min_level
int min_level
Definition: recipe.h:30
get_empty_formula
static recipe * get_empty_formula(void)
Definition: recipe.cpp:79
try_find_archetype
archetype * try_find_archetype(const char *name)
Definition: assets.cpp:270
recipe::ingred
linked_char * ingred
Definition: recipe.h:22
FREE_OBJ_FREE_INVENTORY
#define FREE_OBJ_FREE_INVENTORY
Definition: object.h:544
recipe::next
recipe * next
Definition: recipe.h:24
recipe::skill
sstring skill
Definition: recipe.h:26
say.item
dictionary item
Definition: say.py:149
treasure
Definition: treasure.h:63
artifact
Definition: artifact.h:14
diamondslots.cost
int cost
Definition: diamondslots.py:21
build_stringlist
static void build_stringlist(const char *str, char ***result_list, size_t *result_size)
Definition: recipe.cpp:861
OUT_OF_MEMORY
@ OUT_OF_MEMORY
Definition: define.h:48
BufferReader
Definition: bufferreader.cpp:21
find_artifactlist
artifactlist * find_artifactlist(int type)
Definition: artifact.cpp:574
recipe_get_face
const Face * recipe_get_face(const recipe *rp)
Definition: recipe.cpp:920
ring_occidental_mages.r
r
Definition: ring_occidental_mages.py:6
object.h
recipe_get_difficulty_string
const char * recipe_get_difficulty_string(int difficulty)
Definition: recipe.cpp:962
llevDebug
@ llevDebug
Definition: logger.h:13
give.name
name
Definition: give.py:27
legal_artifact_combination
int legal_artifact_combination(const object *op, const artifact *art)
Definition: artifact.cpp:252
recipe::cauldron
sstring cauldron
Definition: recipe.h:27
bufferreader_next_line
char * bufferreader_next_line(BufferReader *br)
Definition: bufferreader.cpp:102
recipe::title
sstring title
Definition: recipe.h:11