Crossfire Server, Trunk  1.75.0
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 
343 static long recipe_find_ingredient_cost(const char *name);
344 
352 void dump_alchemy(void) {
353  recipelist *fl = formulalist;
354  recipe *formula = NULL;
355  linked_char *next;
356  int num_ingred = 1;
357 
358  fprintf(stdout, "name,index,num_ingreds,chance,skill,difficulty,exp,cauldron,yield,ingredients,ingred_price,result_price\n");
359  while (fl) {
360  for (formula = fl->items; formula != NULL; formula = formula->next) {
361  const archetype *at = NULL;
362  const artifact *art = NULL;
363  char buf[MAX_BUF];
364  size_t i;
365 
366  for (i = 0; i < formula->arch_names; i++) {
367  const char *string = formula->arch_name[i];
368 
369  if ((at = try_find_archetype(string)) != NULL) {
370  art = locate_recipe_artifact(formula, i);
371  if (!art && strcmp(formula->title, "NONE"))
372  LOG(llevError, "Formula %s has no artifact\n", formula->title);
373  else {
374  if (strcmp(formula->title, "NONE"))
375  snprintf(buf, sizeof(buf), "%s of %s", string, formula->title);
376  else
377  strlcpy(buf, string, sizeof(buf));
378  fprintf(stdout, "%s,%d,%d,%d,%s,", buf, formula->index, num_ingred, formula->chance, formula->skill);
379  fprintf(stdout, "%d,%d,", formula->diff, formula->exp);
380  fprintf(stdout, "%s,%d,", formula->cauldron, formula->yield);
381  int ingred_cost = 0;
382  if (formula->ingred != NULL) {
383  int nval = 0, tval = 0;
384  fprintf(stdout, "\"");
385  for (next = formula->ingred; next != NULL; next = next->next) {
386  if (nval != 0)
387  fprintf(stdout, ",");
388  fprintf(stdout, "%s(%d)", next->name, (nval = strtoint(next->name)));
389  ingred_cost += recipe_find_ingredient_cost(next->name);
390  tval += nval;
391  }
392  fprintf(stdout, "\",");
393  if (tval != formula->index)
394  fprintf(stdout, "WARNING:ingredient list and formula values not equal.\n");
395  }
396  fprintf(stdout, "%d,", ingred_cost);
397  int result_price = price_base(&at->clone);
398  if (art != NULL && art->item != NULL)
399  result_price *= art->item->value;
400  fprintf(stdout, "%d\n", result_price);
401  }
402  } else
403  LOG(llevError, "Can't find archetype:%s for formula %s\n", string, formula->title);
404  }
405  }
406  fl = fl->next;
407  num_ingred++;
408  }
409 }
410 
425 archetype *find_treasure_by_name(const treasure *t, const char *name, int depth) {
426  treasurelist *tl;
427  archetype *at;
428 
429  if (depth > 10)
430  return NULL;
431 
432  while (t != NULL) {
433  if (t->name != NULL) {
434  tl = find_treasurelist(t->name);
435  at = find_treasure_by_name(tl->items, name, depth+1);
436  if (at != NULL)
437  return at;
438  } else {
439  if (!strcasecmp(t->item->clone.name, name))
440  return t->item;
441  }
442  if (t->next_yes != NULL) {
443  at = find_treasure_by_name(t->next_yes, name, depth);
444  if (at != NULL)
445  return at;
446  }
447  if (t->next_no != NULL) {
448  at = find_treasure_by_name(t->next_no, name, depth);
449  if (at != NULL)
450  return at;
451  }
452  t = t->next;
453  }
454  return NULL;
455 }
456 
476 static long recipe_find_ingredient_cost(const char *name) {
477  long mult;
478  const char *cp;
479  char part1[100];
480  char part2[100];
481 
482  /* same as atoi(), but skip number */
483  mult = 0;
484  while (isdigit(*name)) {
485  mult = 10*mult+(*name-'0');
486  name++;
487  }
488  if (mult > 0)
489  name++;
490  else
491  mult = 1;
492  /* first, try to match the name of an archetype */
493 
494  long value = 0;
495  bool found = false;
496  getManager()->archetypes()->each([&value, &found, &name, &part1] (const archetype *at) {
497  if (found) {
498  return;
499  }
500 
501  if (at->clone.title != NULL) {
502  /* inefficient, but who cares? */
503  snprintf(part1, sizeof(part1), "%s %s", at->clone.name, at->clone.title);
504  if (!strcasecmp(part1, name)) {
505  value = price_base(&at->clone);
506  found = true;
507  return;
508  }
509  }
510  if (!strcasecmp(at->clone.name, name)) {
511  value = price_base(&at->clone);
512  found = true;
513  return;
514  }
515  });
516  if (found) {
517  return mult * value;
518  }
519 
520  /* second, try to match an artifact ("arch of something") */
521  cp = strstr(name, " of ");
522  if (cp != NULL) {
523  safe_strncpy(part1, name, sizeof(part1));
524  part1[cp-name] = '\0';
525  safe_strncpy(part2, cp + 4, sizeof(part2));
526  getManager()->archetypes()->each([&value, &found, &part1, &part2] (const archetype *at) {
527  if (found) {
528  return;
529  }
530 
531  if (!strcasecmp(at->clone.name, part1) && at->clone.title == NULL) {
532  /* find the first artifact derived from that archetype (same type) */
533  for (auto al = first_artifactlist; al != NULL; al = al->next) {
534  if (al->type == at->clone.type) {
535  for (const auto art : al->items) {
536  if (!strcasecmp(art->item->name, part2)) {
537  value = price_base(&at->clone) * art->item->value;
538  found = true;
539  return;
540  }
541  }
542  }
543  }
544  }
545  });
546  }
547  if (found) {
548  return mult * value;
549  }
550 
551  /* third, try to match a body part ("arch's something") */
552  cp = strstr(name, "'s ");
553  if (cp != NULL) {
554  safe_strncpy(part1, name, sizeof(part1));
555  part1[cp-name] = '\0';
556  safe_strncpy(part2, cp + 3, sizeof(part2));
557  /* examine all archetypes matching the first part of the name */
558  getManager()->archetypes()->each([&value, &found, &part1, &part2] (const archetype *at) {
559  if (found) {
560  return;
561  }
562  if (!strcasecmp(at->clone.name, part1) && at->clone.title == NULL) {
563  if (at->clone.randomitems != NULL) {
564  auto at2 = find_treasure_by_name(at->clone.randomitems->items, part2, 0);
565  if (at2 != NULL) {
566  value = price_base(&at2->clone);
567  found = true;
568  return;
569  }
570  }
571  }
572  });
573  }
574  if (found) {
575  return mult * value;
576  }
577 
578  /* failed to find any matching items -- formula should be checked */
579  LOG(llevError, "Couldn't find cost for ingredient %s\n", name);
580  return -1;
581 }
582 
591 void dump_alchemy_costs(void) {
592  recipelist *fl = formulalist;
593  recipe *formula = NULL;
594  linked_char *next;
595  int num_ingred = 1;
596  int num_errors = 0;
597  long cost;
598  long tcost;
599 
600  fprintf(logfile, "\n");
601  while (fl) {
602  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);
603  for (formula = fl->items; formula != NULL; formula = formula->next) {
604  const artifact *art = NULL;
605  const archetype *at = NULL;
606  char buf[MAX_BUF];
607  size_t i;
608 
609  for (i = 0; i < formula->arch_names; i++) {
610  const char *string = formula->arch_name[i];
611 
612  if ((at = try_find_archetype(string)) != NULL) {
613  art = locate_recipe_artifact(formula, i);
614  if (!art && strcmp(formula->title, "NONE"))
615  LOG(llevError, "Formula %s has no artifact\n", formula->title);
616  else {
617  if (!strcmp(formula->title, "NONE"))
618  strlcpy(buf, string, sizeof(buf));
619  else
620  snprintf(buf, sizeof(buf), "%s of %s", string, formula->title);
621  fprintf(logfile, "\n%-40s bookchance %3d skill %s\n", buf, formula->chance, formula->skill);
622  if (formula->ingred != NULL) {
623  tcost = 0;
624  for (next = formula->ingred; next != NULL; next = next->next) {
625  cost = recipe_find_ingredient_cost(next->name);
626  if (cost < 0)
627  num_errors++;
628  fprintf(logfile, "\t%-33s%5ld\n", next->name, cost);
629  if (cost < 0 || tcost < 0)
630  tcost = -1;
631  else
632  tcost += cost;
633  }
634  if (art != NULL && art->item != NULL)
635  cost = price_base(&at->clone)*art->item->value;
636  else
637  cost = price_base(&at->clone);
638  fprintf(logfile, "\t\tBuying result costs: %5ld", cost);
639  if (formula->yield > 1) {
640  fprintf(logfile, " to %ld (max %d items)\n", cost*formula->yield, formula->yield);
641  cost = cost*(formula->yield+1L)/2L;
642  } else
643  fprintf(logfile, "\n");
644  fprintf(logfile, "\t\tIngredients cost: %5ld\n\t\tComment: ", tcost);
645  if (tcost < 0)
646  fprintf(logfile, "Could not find some ingredients. Check the formula!\n");
647  else if (tcost > cost)
648  fprintf(logfile, "Ingredients are much too expensive. Useless formula.\n");
649  else if (tcost*2L > cost)
650  fprintf(logfile, "Ingredients are too expensive.\n");
651  else if (tcost*10L < cost)
652  fprintf(logfile, "Ingredients are too cheap.\n");
653  else
654  fprintf(logfile, "OK.\n");
655  }
656  }
657  } else
658  LOG(llevError, "Can't find archetype:%s for formula %s\n", string, formula->title);
659  }
660  }
661  fprintf(logfile, "\n");
662  fl = fl->next;
663  num_ingred++;
664  }
665  if (num_errors > 0)
666  fprintf(logfile, "WARNING: %d objects required by the formulae do not exist in the game.\n", num_errors);
667 }
668 
677 static const char *ingred_name(const char *name) {
678  const char *cp = name;
679 
680  if (atoi(cp))
681  cp = strchr(cp, ' ')+1;
682  return cp;
683 }
684 
693 static int numb_ingred(const char *buf) {
694  int numb;
695 
696  if ((numb = atoi(buf)))
697  return numb;
698  else
699  return 1;
700 }
701 
712 int strtoint(const char *buf) {
713  const char *cp = ingred_name(buf);
714  int val = 0, len = strlen(cp), mult = numb_ingred(buf);
715 
716  while (len) {
717  val += tolower(*cp);
718  cp++; len--;
719  }
720  return val*mult;
721 }
722 
733 const artifact *locate_recipe_artifact(const recipe *rp, size_t idx) {
734  std::unique_ptr<object, void(*)(object *)> item(create_archetype(rp->arch_name[idx]), object_free_drop_inventory);
735  const artifactlist *at = NULL;
736 
737  if (!item)
738  return (artifact *)NULL;
739 
740  if ((at = find_artifactlist(item->type)))
741  for (auto art : at->items)
742  if (!strcmp(art->item->name, rp->title) && legal_artifact_combination(item.get(), art))
743  return art;
744 
745  return nullptr;
746 }
747 
755  recipelist *fl = NULL;
756  int number = 0, roll = 0;
757 
758  /* first, determine # of recipelist we have */
759  for (fl = get_formulalist(1); fl; fl = fl->next)
760  number++;
761 
762  /* now, randomly choose one */
763  if (number > 0)
764  roll = RANDOM()%number;
765 
766  fl = get_formulalist(1);
767  while (roll && fl) {
768  if (fl->next)
769  fl = fl->next;
770  else
771  break;
772  roll--;
773  }
774  if (!fl) /* failed! */
775  LOG(llevError, "get_random_recipelist(): no recipelists found!\n");
776  else if (fl->total_chance == 0)
777  fl = get_random_recipelist();
778 
779  return fl;
780 }
781 
791  recipelist *fl = rpl;
792  recipe *rp = NULL;
793  int r = 0;
794 
795  /* looks like we have to choose a random one */
796  if (fl == NULL)
797  if ((fl = get_random_recipelist()) == NULL)
798  return rp;
799 
800  if (fl->total_chance > 0) {
801  r = RANDOM()%fl->total_chance;
802  for (rp = fl->items; rp; rp = rp->next) {
803  r -= rp->chance;
804  if (r < 0)
805  break;
806  }
807  }
808  return rp;
809 }
810 
814 void free_all_recipes(void) {
815  recipelist *fl, *flnext;
816  recipe *formula = NULL, *next;
817  linked_char *lchar, *charnext;
818 
819  LOG(llevDebug, "Freeing all the recipes\n");
820  for (fl = formulalist; fl != NULL; fl = flnext) {
821  flnext = fl->next;
822 
823  for (formula = fl->items; formula != NULL; formula = next) {
824  next = formula->next;
825 
826  free(formula->arch_name[0]);
827  free(formula->arch_name);
828  if (formula->title)
829  free_string(formula->title);
830  if (formula->skill)
831  free_string(formula->skill);
832  if (formula->cauldron)
833  free_string(formula->cauldron);
834  if (formula->failure_arch)
835  free_string(formula->failure_arch);
836  if (formula->failure_message)
837  free_string(formula->failure_message);
838  for (lchar = formula->ingred; lchar; lchar = charnext) {
839  charnext = lchar->next;
840  free_string(lchar->name);
841  free(lchar);
842  }
843  if (formula->tool)
844  free(formula->tool[0]);
845  free(formula->tool);
846  free(formula);
847  }
848  free(fl);
849  }
850  formulalist = NULL;
851 }
852 
864 static void build_stringlist(const char *str, char ***result_list, size_t *result_size) {
865  char *dup;
866  char *p;
867  size_t size;
868  size_t i;
869 
870  dup = strdup_local(str);
871  if (dup == NULL)
873 
874  size = 0;
875  for (p = strtok(dup, ","); p != NULL; p = strtok(NULL, ","))
876  size++;
877 
878  assert(size > 0);
879  *result_list = static_cast<char **>(malloc(sizeof(**result_list) * size));
880  if (*result_list == NULL)
882  *result_size = size;
883 
884  for (i = 0; i < size; i++) {
885  (*result_list)[i] = dup;
886  dup = dup+strlen(dup)+1;
887  }
888 }
889 
897 recipe *find_recipe_for_tool(const char *tool, recipe *from) {
898  size_t t;
900  recipe *test = from ? from->next : list->items;
901 
902  while (list) {
903  while (test) {
904  for (t = 0; t < test->tool_size; t++) {
905  if (strcmp(test->tool[t], tool) == 0) {
906  return test;
907  }
908  }
909  test = test->next;
910  }
911 
912  list = list->next;
913  }
914 
915  return NULL;
916 }
917 
923 const Face *recipe_get_face(const recipe *rp) {
924  const artifact *art;
925  archetype *arch;
926  object *item;
927  const Face *face;
928 
929  if (rp->arch_names == 0)
930  return NULL;
931 
932  arch = try_find_archetype(rp->arch_name[0]);
933  if (arch == NULL) {
934  return NULL;
935  }
936  if (strcmp(rp->title, "NONE") == 0) {
937  return arch->clone.face;
938  }
939 
940  art = locate_recipe_artifact(rp, 0);
941  if (art == NULL)
942  return arch->clone.face;
943 
944  face = arch->clone.face;
945  item = arch_to_object(arch);
946  give_artifact_abilities(item, art->item);
948  if (item->face != NULL && item->face != blank_face)
949  face = item->face;
951 
952  return face;
953 }
954 
965 const char *recipe_get_difficulty_string(int difficulty) {
966  if (difficulty < 5)
967  return "basic";
968  if (difficulty < 10)
969  return "simple";
970  if (difficulty < 15)
971  return "advanced";
972  if (difficulty < 20)
973  return "complicated";
974  if (difficulty < 25)
975  return "difficult";
976  if (difficulty < 30)
977  return "challenging";
978  if (difficulty < 35)
979  return "frustrating";
980  return "vexatious";
981 }
find_recipe_for_tool
recipe * find_recipe_for_tool(const char *tool, recipe *from)
Find a recipe for a specified tool.
Definition: recipe.cpp:897
Face
New face structure - this enforces the notion that data is face by face only - you can not change the...
Definition: face.h:14
object
Main Crossfire structure, one ingame object.
Definition: object.h:282
global.h
FREE_OBJ_NO_DESTROY_CALLBACK
#define FREE_OBJ_NO_DESTROY_CALLBACK
Do not run the destroy callback.
Definition: object.h:545
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
recipe::tool_size
size_t tool_size
Length of tool.
Definition: recipe.h:33
bufferreader_current_line
size_t bufferreader_current_line(BufferReader *br)
Return the index of the last line returned by bufferreader_next_line().
Definition: bufferreader.cpp:140
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
strdup_local
#define strdup_local
Definition: compat.h:29
recipe::arch_names
size_t arch_names
Size of the arch_name[] array.
Definition: recipe.h:12
treasurelist::items
treasure * items
Items in this list, linked.
Definition: treasure.h:92
AssetsManager.h
dump_alchemy_costs
void dump_alchemy_costs(void)
Dumps to output all costs of recipes.
Definition: recipe.cpp:591
init_recipelist
static recipelist * init_recipelist(void)
Allocates a new recipelist.
Definition: recipe.cpp:60
recipe::yield
int yield
Maximum number of items produced by the recipe.
Definition: recipe.h:21
get_random_recipelist
static recipelist * get_random_recipelist(void)
Gets a random recipe list.
Definition: recipe.cpp:754
recipe::failure_arch
sstring failure_arch
Arch of the item to generate on failure, instead of blowing up stuff.
Definition: recipe.h:28
give_artifact_abilities
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.cpp:230
recipelist::next
recipelist * next
Pointer to next recipe list.
Definition: recipe.h:41
find_treasurelist
treasurelist * find_treasurelist(const char *name)
Search for the given treasurelist by name.
Definition: assets.cpp:249
artifact::item
object * item
Special values of the artifact.
Definition: artifact.h:15
recipelist::items
recipe * items
Pointer to first recipe in this list.
Definition: recipe.h:40
check_recipe
static int check_recipe(const recipe *rp)
Makes sure we actually have the requested artifact and archetype.
Definition: recipe.cpp:120
tolower
#define tolower(C)
Simple macro to convert a letter to lowercase.
Definition: c_new.cpp:30
recipe::failure_message
sstring failure_message
Specific failure message.
Definition: recipe.h:29
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
SEE_LAST_ERROR
@ SEE_LAST_ERROR
Definition: define.h:52
recipe::transmute
int transmute
If defined, one of the formula ingredients is used as the basis for the product object.
Definition: recipe.h:19
object::title
sstring title
Of foo, etc.
Definition: object.h:325
recipe_find_ingredient_cost
static long recipe_find_ingredient_cost(const char *name)
Try to find an ingredient with specified name.
Definition: recipe.cpp:476
recipe::exp
int exp
How much exp to give for this formulae.
Definition: recipe.h:17
check_recipes
bool check_recipes()
Ensure that all recipes have a valid artifact, and that archetypes are correct.
Definition: recipe.cpp:147
buf
StringBuffer * buf
Definition: readable.cpp:1565
getManager
AssetsManager * getManager()
Definition: assets.cpp:305
recipelist::total_chance
int total_chance
Total chance of the recipes in this list.
Definition: recipe.h:38
formulalist
static recipelist * formulalist
Pointer to first recipelist.
Definition: recipe.cpp:50
name
Plugin animator file specs[Config] name
Definition: animfiles.txt:4
linked_char
Definition: global.h:98
recipe::is_combination
int is_combination
Whather this is an alchemy recipe, or an item transformation description.
Definition: recipe.h:31
object_free_drop_inventory
void object_free_drop_inventory(object *ob)
Frees everything allocated by an object, removes it from the list of used objects,...
Definition: object.cpp:1545
linked_char::name
const char * name
Definition: global.h:99
recipelist
List of recipes with a certain number of ingredients.
Definition: recipe.h:37
treasurelist
treasurelist represents one logical group of items to be generated together.
Definition: treasure.h:85
archetype::clone
object clone
An object from which to do object_copy()
Definition: object.h:487
check_formulae
bool check_formulae(void)
Check if formula don't have the same index.
Definition: recipe.cpp:292
price_base
uint64_t price_base(const object *obj)
Price an item based on its value or archetype value, type, identification/BUC status,...
Definition: item.cpp:1510
add_string
sstring add_string(const char *str)
This will add 'str' to the hash table.
Definition: shstr.cpp:124
object::face
const Face * face
Face with colors.
Definition: object.h:341
object::value
int32_t value
How much money it is worth (or contains)
Definition: object.h:360
recipe::index
int index
Index value derived from formula ingredients.
Definition: recipe.h:18
t
in that case they will be relative to whatever the PWD of the crossfire server process is You probably shouldn t
Definition: server-directories.txt:28
numb_ingred
static int numb_ingred(const char *buf)
Extracts the number part of an ingredient.
Definition: recipe.cpp:693
linked_char::next
struct linked_char * next
Definition: global.h:100
object_free
void object_free(object *ob, int flags)
Frees everything allocated by an object, removes it from the list of used objects,...
Definition: object.cpp:1577
artifactlist
This represents all archetypes for one particular object type.
Definition: artifact.h:24
archetype
The archetype structure is a set of rules on how to generate and manipulate objects which point to ar...
Definition: object.h:483
logfile
FILE * logfile
Used by server/daemon.c.
Definition: init.cpp:114
AssetsCollection::each
void each(std::function< void(T *)> op)
Apply a function to each asset.
Definition: AssetsCollection.h:158
fatal
void fatal(enum fatal_error err)
fatal() is meant to be called whenever a fatal signal is intercepted.
Definition: utils.cpp:590
recipe::ingred_count
int ingred_count
Number of items in ingred.
Definition: recipe.h:23
AssetsManager::archetypes
Archetypes * archetypes()
Get archetypes.
Definition: AssetsManager.h:44
MAX_BUF
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
free_all_recipes
void free_all_recipes(void)
Frees all memory allocated to recipes and recipes lists.
Definition: recipe.cpp:814
strlcpy
size_t strlcpy(char *dst, const char *src, size_t size)
Portable implementation of strlcpy(3).
Definition: porting.cpp:222
create_archetype
object * create_archetype(const char *name)
Finds which archetype matches the given name, and returns a new object containing a copy of the arche...
Definition: arch.cpp:276
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
RANDOM
#define RANDOM()
Definition: define.h:638
is_valid_types_gen.found
found
Definition: is_valid_types_gen.py:39
recipe
One alchemy recipe.
Definition: recipe.h:10
recipe::tool
char ** tool
Tool(s) for item transformation.
Definition: recipe.h:32
object::name
sstring name
The name of the object, obviously...
Definition: object.h:319
get_random_recipe
recipe * get_random_recipe(recipelist *rpl)
Gets a random recipe from a list, based on chance.
Definition: recipe.cpp:790
locate_recipe_artifact
const artifact * locate_recipe_artifact(const recipe *rp, size_t idx)
Finds an artifact for a recipe.
Definition: recipe.cpp:733
ingred_name
static const char * ingred_name(const char *name)
Extracts the name from an ingredient.
Definition: recipe.cpp:677
find_treasure_by_name
archetype * find_treasure_by_name(const treasure *t, const char *name, int depth)
Find a treasure with a matching name.
Definition: recipe.cpp:425
recipe::chance
int chance
Chance that recipe for this item will appear in an alchemical grimore.
Definition: recipe.h:14
dump_alchemy
void dump_alchemy(void)
Dumps alchemy recipes to output.
Definition: recipe.cpp:352
strtoint
int strtoint(const char *buf)
Convert buf into an integer equal to the coadded sum of the (lowercase) character.
Definition: recipe.cpp:712
recipe::diff
int diff
Alchemical dfficulty level.
Definition: recipe.h:16
assets.h
arch_to_object
object * arch_to_object(archetype *at)
Creates and returns a new object which is a copy of the given archetype.
Definition: arch.cpp:227
object_give_identified_properties
void object_give_identified_properties(object *op)
Ensure op has all its "identified" properties set.
Definition: item.cpp:1368
init_formulae
void init_formulae(BufferReader *reader, const char *filename)
Builds up the lists of formula from the file in the libdir.
Definition: recipe.cpp:166
strcasecmp
int strcasecmp(const char *s1, const char *s2)
recipe::keycode
sstring keycode
Optional keycode needed to use the recipe.
Definition: recipe.h:25
recipelist::number
int number
Number of recipes in this list.
Definition: recipe.h:39
recipe::min_level
int min_level
Minimum level to have in the skill to be able to use the formulae.
Definition: recipe.h:30
get_empty_formula
static recipe * get_empty_formula(void)
Allocates a new recipe.
Definition: recipe.cpp:79
try_find_archetype
archetype * try_find_archetype(const char *name)
Definition: assets.cpp:270
recipe::ingred
linked_char * ingred
List of ingredients.
Definition: recipe.h:22
FREE_OBJ_FREE_INVENTORY
#define FREE_OBJ_FREE_INVENTORY
Free inventory objects; if not set, drop inventory.
Definition: object.h:544
recipe::next
recipe * next
Next recipe with the same number of ingredients.
Definition: recipe.h:24
recipe::skill
sstring skill
Skill name used to make this recipe.
Definition: recipe.h:26
treasure
treasure is one element in a linked list, which together consist of a complete treasure-list.
Definition: treasure.h:63
list
How to Install a Crossfire Server on you must install a python script engine on your computer Python is the default script engine of Crossfire You can find the python engine you have only to install them The VisualC Crossfire settings are for but you habe then to change the pathes in the VC settings Go in Settings C and Settings Link and change the optional include and libs path to the new python installation path o except the maps ! You must download a map package and install them the share folder Its must look like doubleclick on crossfire32 dsw There are projects in your libcross lib and plugin_python You need to compile all Easiest way is to select the plugin_python ReleaseLog as active this will compile all others too Then in Visual C press< F7 > to compile If you don t have an appropriate compiler you can try to get the the VC copies the crossfire32 exe in the crossfire folder and the plugin_python dll in the crossfire share plugins folder we will remove it when we get time for it o Last showing lots of weird write to the Crossfire mailing list
Definition: INSTALL_WIN32.txt:50
artifact
This is one artifact, ie one special item.
Definition: artifact.h:14
build_stringlist
static void build_stringlist(const char *str, char ***result_list, size_t *result_size)
Split a comma separated string list into words.
Definition: recipe.cpp:864
OUT_OF_MEMORY
@ OUT_OF_MEMORY
Definition: define.h:48
BufferReader
Definition: bufferreader.cpp:21
find_artifactlist
artifactlist * find_artifactlist(int type)
Finds the artifact list for a certain item type.
Definition: artifact.cpp:574
recipe_get_face
const Face * recipe_get_face(const recipe *rp)
Return the best face associated with a recipe.
Definition: recipe.cpp:923
object.h
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:965
llevDebug
@ llevDebug
Only for debugging purposes.
Definition: logger.h:13
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
legal_artifact_combination
int legal_artifact_combination(const object *op, const artifact *art)
Checks if op can be combined with art.
Definition: artifact.cpp:252
recipe::cauldron
sstring cauldron
Arch of the cauldron/workbench used to house the formulae.
Definition: recipe.h:27
bufferreader_next_line
char * bufferreader_next_line(BufferReader *br)
Return the next line in the buffer, as separated by a newline.
Definition: bufferreader.cpp:102
recipe::title
sstring title
Distinguishing name of product.
Definition: recipe.h:11