ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/recipe.C
Revision: 1.23
Committed: Sun Jul 1 05:00:18 2007 UTC (16 years, 10 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-2_2, rel-2_3
Changes since 1.22: +11 -12 lines
Log Message:
- upgrade crossfire trt to the GPL version 3 (hopefully correctly).
- add a single file covered by the GNU Affero General Public License
  (which is not yet released, so I used the current draft, which is
  legally a bit wavy, but its likely better than nothing as it expresses
  direct intent by the authors, and we can upgrade as soon as it has been
  released).
  * this should ensure availability of source code for the server at least
    and hopefully also archetypes and maps even when modified versions
    are not being distributed, in accordance of section 13 of the agplv3.

File Contents

# User Rev Content
1 root 1.20 /*
2 root 1.23 * This file is part of Crossfire TRT, the Roguelike Realtime MORPG.
3 root 1.21 *
4     * Copyright (©) 2005,2006,2007 Marc Alexander Lehmann / Robin Redeker / the Crossfire TRT team
5     * Copyright (©) 2002,2007 Mark Wedel & Crossfire Development Team
6     * Copyright (©) 1992,2007 Frank Tore Johansen
7     *
8 root 1.23 * Crossfire TRT is free software: you can redistribute it and/or modify
9     * it under the terms of the GNU General Public License as published by
10     * the Free Software Foundation, either version 3 of the License, or
11     * (at your option) any later version.
12 root 1.21 *
13 root 1.23 * This program is distributed in the hope that it will be useful,
14     * but WITHOUT ANY WARRANTY; without even the implied warranty of
15     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16     * GNU General Public License for more details.
17 root 1.21 *
18 root 1.23 * You should have received a copy of the GNU General Public License
19     * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 root 1.21 *
21     * The authors can be reached via e-mail to <crossfire@schmorp.de>
22 root 1.20 */
23    
24 elmex 1.1 /* Basic stuff for use with the alchemy code. Clearly some of this stuff
25     * could go into server/alchemy, but I left it here just in case it proves
26     * more generally useful.
27     *
28     * Nov 1995 - file created by b.t. thomas@astro.psu.edu
29     */
30    
31    
32     /* Our definition of 'formula' is any product of an alchemical process.
33     * Ingredients are just comma delimited list of archetype (or object)
34     * names.
35     */
36    
37     /* Example 'formula' entry in libdir/formulae:
38 root 1.18 * object transparency
39 elmex 1.1 * chance 10
40     * ingred dust of beholdereye,gem
41     * arch potion_generic
42     */
43    
44 root 1.11 #include <cctype>
45    
46 elmex 1.1 #include <global.h>
47     #include <object.h>
48    
49 root 1.5 static void build_stringlist (const char *str, char ***result_list, size_t * result_size);
50 elmex 1.1
51     static recipelist *formulalist;
52    
53 root 1.5 static recipelist *
54     init_recipelist (void)
55     {
56 root 1.3 recipelist *tl = new recipelist;
57    
58 root 1.5 tl->total_chance = 0;
59     tl->number = 0;
60 root 1.19 tl->items = 0;
61     tl->next = 0;
62    
63 elmex 1.1 return tl;
64     }
65    
66 root 1.5 static recipe *
67     get_empty_formula (void)
68     {
69 root 1.3 recipe *t = new recipe;
70    
71 elmex 1.1 t->chance = 0;
72     t->index = 0;
73     t->transmute = 0;
74 root 1.5 t->yield = 0;
75     t->diff = 0;
76     t->exp = 0;
77 elmex 1.1 t->keycode = 0;
78     t->title = NULL;
79     t->arch_names = 0;
80     t->arch_name = NULL;
81     t->skill = NULL;
82     t->cauldron = NULL;
83     t->ingred = NULL;
84 root 1.5 t->next = NULL;
85 elmex 1.1 return t;
86     }
87 root 1.5
88 elmex 1.1 /* get_formulalist() - returns pointer to the formula list */
89 root 1.5 recipelist *
90     get_formulalist (int i)
91     {
92     recipelist *fl = formulalist;
93     int number = i;
94    
95     while (fl && number > 1)
96     {
97     if (!(fl = fl->next))
98     break;
99     number--;
100     }
101 root 1.18
102 elmex 1.1 return fl;
103     }
104    
105     /* check_recipe() - makes sure we actually have the requested artifact
106     * and archetype. */
107 root 1.5 static int
108     check_recipe (const recipe *rp)
109     {
110     size_t i;
111 root 1.18 int result = 1;
112 root 1.5
113     for (i = 0; i < rp->arch_names; i++)
114     {
115 root 1.6 if (archetype::find (rp->arch_name[i]) != NULL)
116 root 1.5 {
117     artifact *art = locate_recipe_artifact (rp, i);
118    
119     if (!art && strcmp (rp->title, "NONE") != 0)
120     {
121 pippijn 1.12 LOG (llevError, "WARNING: Formula %s of %s has no artifact.\n", rp->arch_name[i], &rp->title);
122 root 1.5 result = 0;
123 elmex 1.1 }
124 root 1.5 }
125     else
126     {
127 pippijn 1.12 LOG (llevError, "WARNING: Can't find archetype %s for formula %s\n", rp->arch_name[i], &rp->title);
128 root 1.5 result = 0;
129 elmex 1.1 }
130     }
131 root 1.5
132     return result;
133 elmex 1.1 }
134    
135     /*
136     * init_formulae() - Builds up the lists of formula from the file in
137     * the libdir. -b.t.
138     */
139 root 1.5 void
140     init_formulae (void)
141     {
142     static int has_been_done = 0;
143 elmex 1.1 FILE *fp;
144     char filename[MAX_BUF], buf[MAX_BUF], *cp, *next;
145 root 1.5 recipe *formula = NULL;
146     recipelist *fl = init_recipelist ();
147 elmex 1.1 linked_char *tmp;
148     int value, comp;
149    
150 root 1.5 if (!formulalist)
151     formulalist = fl;
152    
153     if (has_been_done)
154 elmex 1.1 return;
155 root 1.5 else
156     has_been_done = 1;
157    
158     sprintf (filename, "%s/formulae", settings.datadir);
159 pippijn 1.12 LOG (llevDebug, "Reading alchemical formulae from %s...\n", filename);
160 root 1.5 if ((fp = open_and_uncompress (filename, 0, &comp)) == NULL)
161     {
162     LOG (llevError, "Can't open %s.\n", filename);
163     return;
164     }
165    
166     while (fgets (buf, MAX_BUF, fp) != NULL)
167     {
168     if (*buf == '#')
169     continue;
170     if ((cp = strchr (buf, '\n')) != NULL)
171     *cp = '\0';
172     cp = buf;
173     while (*cp == ' ') /* Skip blanks */
174     cp++;
175    
176 root 1.18 if (!strncmp (cp, "object", 6))
177 root 1.5 {
178     formula = get_empty_formula ();
179     formula->title = strchr (cp, ' ') + 1;
180     }
181     else if (!strncmp (cp, "keycode", 7))
182 root 1.18 formula->keycode = strchr (cp, ' ') + 1;
183 root 1.5 else if (sscanf (cp, "trans %d", &value))
184 root 1.18 formula->transmute = (uint16) value;
185 root 1.5 else if (sscanf (cp, "yield %d", &value))
186 root 1.18 formula->yield = (uint16) value;
187 root 1.5 else if (sscanf (cp, "chance %d", &value))
188 root 1.18 formula->chance = (uint16) value;
189 root 1.5 else if (sscanf (cp, "exp %d", &value))
190 root 1.18 formula->exp = (uint16) value;
191 root 1.5 else if (sscanf (cp, "diff %d", &value))
192 root 1.18 formula->diff = (uint16) value;
193 root 1.5 else if (!strncmp (cp, "ingred", 6))
194     {
195     int numb_ingred = 1;
196    
197     cp = strchr (cp, ' ') + 1;
198     do
199     {
200     if ((next = strchr (cp, ',')) != NULL)
201     {
202     *(next++) = '\0';
203     numb_ingred++;
204     }
205 root 1.18
206 root 1.5 tmp = new linked_char;
207    
208     tmp->name = cp;
209     tmp->next = formula->ingred;
210     formula->ingred = tmp;
211     /* each ingredient's ASCII value is coadded. Later on this
212     * value will be used allow us to search the formula lists
213     * quickly for the right recipe.
214     */
215     formula->index += strtoint (cp);
216     }
217     while ((cp = next) != NULL);
218 root 1.18
219 root 1.5 /* now find the correct (# of ingred ordered) formulalist */
220     fl = formulalist;
221     while (numb_ingred != 1)
222     {
223     if (!fl->next)
224     fl->next = init_recipelist ();
225 root 1.18
226 root 1.5 fl = fl->next;
227     numb_ingred--;
228     }
229 root 1.18
230 root 1.5 fl->total_chance += formula->chance;
231     fl->number++;
232     formula->next = fl->items;
233     fl->items = formula;
234     }
235     else if (!strncmp (cp, "arch", 4))
236     {
237     build_stringlist (strchr (cp, ' ') + 1, &formula->arch_name, &formula->arch_names);
238     check_recipe (formula);
239     }
240     else if (!strncmp (cp, "skill", 5))
241 root 1.18 formula->skill = strchr (cp, ' ') + 1;
242 root 1.5 else if (!strncmp (cp, "cauldron", 8))
243 root 1.18 formula->cauldron = strchr (cp, ' ') + 1;
244 root 1.5 else
245     LOG (llevError, "Unknown input in file %s: %s\n", filename, buf);
246     }
247 root 1.18
248 root 1.5 LOG (llevDebug, "done.\n");
249     close_and_delete (fp, comp);
250 elmex 1.1 /* Lastly, lets check for problems in formula we got */
251 root 1.5 check_formulae ();
252 elmex 1.1 }
253    
254     /* check_formulae()- since we are doing a squential search on the
255     * formulae lists now, we have to be carefull that we dont have 2
256     * formula with the exact same index value. Under the new nbatches
257     * code, it is possible to have multiples of ingredients in a cauldron
258     * which could result in an index formula mismatch. We *don't* check for
259     * that possibility here. -b.t.
260     */
261 root 1.5 void
262     check_formulae (void)
263     {
264 elmex 1.1 recipelist *fl;
265     recipe *check, *formula;
266     int numb = 1;
267    
268 pippijn 1.13 LOG (llevDebug, "Checking formulae lists...\n");
269 elmex 1.1
270 root 1.19 for (fl = formulalist; fl; fl = fl->next)
271 root 1.5 {
272 root 1.19 for (formula = fl->items; formula; formula = formula->next)
273     for (check = formula->next; check; check = check->next)
274 root 1.5 if (check->index == formula->index)
275     {
276     LOG (llevError, " ERROR: On %d ingred list: ", numb);
277     LOG (llevError, "Formulae [%s] of %s and [%s] of %s have matching index id (%d)\n",
278     formula->arch_name[0], &formula->title, check->arch_name[0], &check->title, formula->index);
279     }
280     numb++;
281     }
282 elmex 1.1
283 root 1.5 LOG (llevDebug, "done.\n");
284 elmex 1.1
285     }
286    
287     /* Borrowed (again) from the artifacts code for this */
288    
289 root 1.5 void
290     dump_alchemy (void)
291     {
292     recipelist *fl = formulalist;
293     recipe *formula = NULL;
294 elmex 1.1 linked_char *next;
295 root 1.5 int num_ingred = 1;
296 elmex 1.1
297 root 1.5 fprintf (logfile, "\n");
298     while (fl)
299     {
300     fprintf (logfile, "\n Formulae with %d ingredient%s %d Formulae with total_chance=%d\n",
301     num_ingred, num_ingred > 1 ? "s." : ".", fl->number, fl->total_chance);
302 root 1.19 for (formula = fl->items; formula; formula = formula->next)
303 root 1.5 {
304     artifact *art = NULL;
305     char buf[MAX_BUF];
306     size_t i;
307    
308     for (i = 0; i < formula->arch_names; i++)
309     {
310     const char *string = formula->arch_name[i];
311    
312 root 1.6 if (archetype::find (string) != NULL)
313 root 1.5 {
314     art = locate_recipe_artifact (formula, i);
315     if (!art && strcmp (formula->title, "NONE"))
316 root 1.18 LOG (llevError, "Formula %s has no artifact!\n", &formula->title);
317 root 1.5 else
318     {
319     if (strcmp (formula->title, "NONE"))
320     sprintf (buf, "%s of %s", string, &formula->title);
321     else
322     sprintf (buf, "%s", string);
323     fprintf (logfile, "%-30s(%d) bookchance %3d ", buf, formula->index, formula->chance);
324     fprintf (logfile, "skill %s", &formula->skill);
325     fprintf (logfile, "\n");
326     if (formula->ingred != NULL)
327     {
328     int nval = 0, tval = 0;
329    
330     fprintf (logfile, "\tIngred: ");
331     for (next = formula->ingred; next != NULL; next = next->next)
332     {
333     if (nval != 0)
334     fprintf (logfile, ",");
335     fprintf (logfile, "%s(%d)", &next->name, (nval = strtoint (next->name)));
336     tval += nval;
337     }
338     fprintf (logfile, "\n");
339     if (tval != formula->index)
340     fprintf (logfile, "WARNING:ingredient list and formula values not equal.\n");
341     }
342     if (formula->skill != NULL)
343     fprintf (logfile, "\tSkill Required: %s", &formula->skill);
344     if (formula->cauldron != NULL)
345     fprintf (logfile, "\tCauldron: %s\n", &formula->cauldron);
346     fprintf (logfile, "\tDifficulty: %d\t Exp: %d\n", formula->diff, formula->exp);
347     }
348 root 1.2 }
349 root 1.5 else
350     LOG (llevError, "Can't find archetype:%s for formula %s\n", string, &formula->title);
351     }
352     }
353     fprintf (logfile, "\n");
354     fl = fl->next;
355     num_ingred++;
356     }
357 elmex 1.1 }
358    
359     /* Find a treasure with a matching name. The 'depth' parameter is
360     * only there to prevent infinite loops in treasure lists (a list
361     * referencing another list pointing back to the first one). */
362 root 1.5 archetype *
363     find_treasure_by_name (const treasure *t, const char *name, int depth)
364 elmex 1.1 {
365     if (depth > 10)
366 elmex 1.10 return 0;
367    
368     while (t)
369 elmex 1.1 {
370 elmex 1.10 if (t->name)
371 root 1.2 {
372 root 1.19 if (treasurelist *tl = treasurelist::find (t->name))
373     if (tl->items)
374     if (archetype *at = find_treasure_by_name (tl->items, name, depth + 1))
375 elmex 1.10 return at;
376 root 1.2 }
377 elmex 1.1 else
378 root 1.2 {
379 root 1.22 if (t->item && !strcasecmp (t->item->object::name, name))
380 root 1.2 return t->item;
381     }
382 elmex 1.10
383     if (t->next_yes)
384 root 1.19 if (archetype *at = find_treasure_by_name (t->next_yes, name, depth))
385     return at;
386 elmex 1.10
387     if (t->next_no)
388 root 1.19 if (archetype *at = find_treasure_by_name (t->next_no, name, depth))
389     return at;
390    
391 elmex 1.1 t = t->next;
392     }
393 root 1.19
394 elmex 1.10 return 0;
395 elmex 1.1 }
396    
397     /* If several archetypes have the same name, the value of the first
398     * one with that name will be returned. This happens for the
399     * mushrooms (mushroom_1, mushroom_2 and mushroom_3). For the
400     * monsters' body parts, there may be several monsters with the same
401     * name. This is not a problem if these monsters have the same level
402     * (e.g. sage & c_sage) or if only one of the monsters generates the
403     * body parts that we are looking for (e.g. big_dragon and
404     * big_dragon_worthless). */
405 root 1.5 long
406     find_ingred_cost (const char *name)
407 elmex 1.1 {
408 root 1.5 archetype *at2;
409 elmex 1.1 artifactlist *al;
410 root 1.5 artifact *art;
411     long mult;
412     char *cp;
413     char part1[100];
414     char part2[100];
415 elmex 1.1
416     /* same as atoi(), but skip number */
417     mult = 0;
418     while (isdigit (*name))
419     {
420     mult = 10 * mult + (*name - '0');
421     name++;
422     }
423 root 1.16
424 elmex 1.1 if (mult > 0)
425     name++;
426     else
427     mult = 1;
428 root 1.16
429 elmex 1.1 /* first, try to match the name of an archetype */
430 root 1.22 for_all_archetypes (at)
431 elmex 1.1 {
432 root 1.22 if (at->title != NULL)
433 root 1.2 {
434     /* inefficient, but who cares? */
435 root 1.22 sprintf (part1, "%s %s", &at->object::name, &at->title);
436 root 1.5 if (!strcasecmp (part1, name))
437 root 1.22 return mult * at->value;
438 root 1.2 }
439 root 1.22 if (!strcasecmp (at->object::name, name))
440     return mult * at->value;
441 elmex 1.1 }
442 root 1.16
443 elmex 1.1 /* second, try to match an artifact ("arch of something") */
444     cp = strstr (name, " of ");
445     if (cp != NULL)
446     {
447     strcpy (part1, name);
448     part1[cp - name] = '\0';
449     strcpy (part2, cp + 4);
450 root 1.22
451 elmex 1.1 /* find the first archetype matching the first part of the name */
452 root 1.22 for_all_archetypes (at)
453     if (!strcasecmp (at->object::name, part1) && at->title == NULL)
454     {
455     /* find the first artifact derived from that archetype (same type) */
456     for (al = first_artifactlist; al; al = al->next)
457     if (al->type == at->type)
458     {
459     for (art = al->items; art; art = art->next)
460     if (!strcasecmp (art->item->name, part2))
461     return mult * at->value * art->item->value;
462     }
463     }
464 elmex 1.1 }
465 root 1.16
466 elmex 1.1 /* third, try to match a body part ("arch's something") */
467     cp = strstr (name, "'s ");
468 root 1.16 if (cp)
469 elmex 1.1 {
470     strcpy (part1, name);
471     part1[cp - name] = '\0';
472     strcpy (part2, cp + 3);
473     /* examine all archetypes matching the first part of the name */
474 root 1.22 for_all_archetypes (at)
475     if (!strcasecmp (at->object::name, part1) && at->title == NULL)
476 root 1.2 {
477 root 1.22 if (at->randomitems)
478 root 1.2 {
479 root 1.22 at2 = find_treasure_by_name (at->randomitems->items, part2, 0);
480 elmex 1.10 if (at2)
481 root 1.22 return mult * at2->value * isqrt (at->level * 2);
482 root 1.2 }
483     }
484 elmex 1.1 }
485 root 1.16
486 elmex 1.1 /* failed to find any matching items -- formula should be checked */
487     return -1;
488     }
489    
490     /* code copied from dump_alchemy() and modified by Raphael Quinet */
491 root 1.5 void
492     dump_alchemy_costs (void)
493 elmex 1.1 {
494 root 1.5 recipelist *fl = formulalist;
495     recipe *formula = NULL;
496 elmex 1.1 linked_char *next;
497 root 1.5 int num_ingred = 1;
498     int num_errors = 0;
499 elmex 1.1 long cost;
500     long tcost;
501    
502     fprintf (logfile, "\n");
503 root 1.5 while (fl)
504     {
505     fprintf (logfile, "\n Formulae with %d ingredient%s %d Formulae with total_chance=%d\n",
506     num_ingred, num_ingred > 1 ? "s." : ".", fl->number, fl->total_chance);
507 root 1.19 for (formula = fl->items; formula; formula = formula->next)
508 root 1.5 {
509     artifact *art = NULL;
510     archetype *at = NULL;
511     char buf[MAX_BUF];
512     size_t i;
513    
514     for (i = 0; i < formula->arch_names; i++)
515 root 1.2 {
516 root 1.5 const char *string = formula->arch_name[i];
517    
518 root 1.6 if ((at = archetype::find (string)) != NULL)
519 root 1.2 {
520 root 1.5 art = locate_recipe_artifact (formula, i);
521     if (!art && strcmp (formula->title, "NONE"))
522     LOG (llevError, "Formula %s has no artifact\n", &formula->title);
523 root 1.2 else
524     {
525 root 1.5 if (!strcmp (formula->title, "NONE"))
526     sprintf (buf, "%s", string);
527     else
528     sprintf (buf, "%s of %s", string, &formula->title);
529     fprintf (logfile, "\n%-40s bookchance %3d skill %s\n", buf, formula->chance, &(formula->skill));
530     if (formula->ingred != NULL)
531     {
532     tcost = 0;
533     for (next = formula->ingred; next != NULL; next = next->next)
534     {
535     cost = find_ingred_cost (next->name);
536     if (cost < 0)
537     num_errors++;
538     fprintf (logfile, "\t%-33s%5ld\n", &next->name, cost);
539     if (cost < 0 || tcost < 0)
540     tcost = -1;
541     else
542     tcost += cost;
543     }
544     if (art != NULL && art->item != NULL)
545 root 1.22 cost = at->value * art->item->value;
546 root 1.5 else
547 root 1.22 cost = at->value;
548 root 1.5 fprintf (logfile, "\t\tBuying result costs: %5ld", cost);
549     if (formula->yield > 1)
550     {
551     fprintf (logfile, " to %ld (max %d items)\n", cost * formula->yield, formula->yield);
552     cost = cost * (formula->yield + 1L) / 2L;
553     }
554     else
555     fprintf (logfile, "\n");
556     fprintf (logfile, "\t\tIngredients cost: %5ld\n\t\tComment: ", tcost);
557     if (tcost < 0)
558     fprintf (logfile, "Could not find some ingredients. Check the formula!\n");
559     else if (tcost > cost)
560     fprintf (logfile, "Ingredients are much too expensive. Useless formula.\n");
561     else if (tcost * 2L > cost)
562     fprintf (logfile, "Ingredients are too expensive.\n");
563     else if (tcost * 10L < cost)
564     fprintf (logfile, "Ingredients are too cheap.\n");
565     else
566     fprintf (logfile, "OK.\n");
567     }
568 root 1.2 }
569     }
570 root 1.5 else
571     LOG (llevError, "Can't find archetype:%s for formula %s\n", string, &formula->title);
572 root 1.2 }
573     }
574 root 1.5 fprintf (logfile, "\n");
575     fl = fl->next;
576     num_ingred++;
577     }
578 elmex 1.1 if (num_errors > 0)
579 root 1.5 fprintf (logfile, "WARNING: %d objects required by the formulae do not exist in the game.\n", num_errors);
580 elmex 1.1 }
581    
582 root 1.5 const char *
583     ingred_name (const char *name)
584     {
585     const char *cp = name;
586    
587     if (atoi (cp))
588     cp = strchr (cp, ' ') + 1;
589 elmex 1.1 return cp;
590     }
591    
592     /* strtoint() - we use this to convert buf into an integer
593     * equal to the coadded sum of the (lowercase) character
594     * ASCII values in buf (times prepended integers).
595     */
596    
597 root 1.5 int
598     strtoint (const char *buf)
599     {
600     const char *cp = ingred_name (buf);
601     int val = 0, len = strlen (cp), mult = numb_ingred (buf);
602 elmex 1.1
603 root 1.5 while (len)
604     {
605     val += tolower (*cp);
606     cp++;
607     len--;
608     }
609     return val * mult;
610 elmex 1.1 }
611    
612 root 1.5 artifact *
613     locate_recipe_artifact (const recipe *rp, size_t idx)
614     {
615 root 1.18 archetype *at = archetype::find (rp->arch_name [idx]);
616 elmex 1.1
617 root 1.18 if (at)
618 root 1.22 if (artifactlist *al = find_artifactlist (at->type))
619 root 1.18 for (artifact *art = al->items; art; art = art->next)
620     if (art->item->name == rp->title)
621     return art;
622 elmex 1.1
623 root 1.18 return 0;
624 elmex 1.1 }
625    
626 root 1.5 int
627     numb_ingred (const char *buf)
628     {
629 elmex 1.1 int numb;
630    
631 root 1.5 if ((numb = atoi (buf)))
632     return numb;
633     else
634     return 1;
635     }
636    
637     recipelist *
638     get_random_recipelist (void)
639     {
640     recipelist *fl = NULL;
641     int number = 0, roll = 0;
642    
643     /* first, determine # of recipelist we have */
644     for (fl = get_formulalist (1); fl; fl = fl->next)
645     number++;
646    
647     /* now, randomly choose one */
648     if (number > 0)
649 root 1.15 roll = rndm (number);
650 root 1.5
651     fl = get_formulalist (1);
652     while (roll && fl)
653     {
654     if (fl->next)
655     fl = fl->next;
656     else
657     break;
658     roll--;
659     }
660     if (!fl) /* failed! */
661     LOG (llevError, "get_random_recipelist(): no recipelists found!\n");
662     else if (fl->total_chance == 0)
663     fl = get_random_recipelist ();
664    
665     return fl;
666 elmex 1.1 }
667    
668 root 1.5 recipe *
669     get_random_recipe (recipelist * rpl)
670     {
671     recipelist *fl = rpl;
672     recipe *rp = NULL;
673     int r = 0;
674    
675     /* looks like we have to choose a random one */
676     if (fl == NULL)
677     if ((fl = get_random_recipelist ()) == NULL)
678     return rp;
679    
680     if (fl->total_chance > 0)
681     {
682 root 1.15 r = rndm (fl->total_chance);
683 root 1.5 for (rp = fl->items; rp; rp = rp->next)
684     {
685     r -= rp->chance;
686     if (r < 0)
687     break;
688     }
689 elmex 1.1 }
690     return rp;
691     }
692    
693 root 1.5 void
694     free_all_recipes (void)
695 elmex 1.1 {
696 root 1.5 recipelist *fl = formulalist, *flnext;
697     recipe *formula = NULL, *next;
698     linked_char *lchar, *charnext;
699    
700     LOG (llevDebug, "Freeing all the recipes\n");
701     for (fl = formulalist; fl != NULL; fl = flnext)
702     {
703     flnext = fl->next;
704    
705     for (formula = fl->items; formula != NULL; formula = next)
706     {
707     next = formula->next;
708    
709     free (formula->arch_name[0]);
710     free (formula->arch_name);
711    
712     for (lchar = formula->ingred; lchar; lchar = charnext)
713     {
714     charnext = lchar->next;
715     delete lchar;
716 root 1.2 }
717 root 1.5 delete formula;
718 root 1.2 }
719 root 1.3
720 root 1.5 delete fl;
721 elmex 1.1 }
722     }
723    
724     /**
725     * Split a comma separated string list into words.
726     *
727     * @param str the string to split
728     *
729     * @param result_list pointer to return value for the newly created list; the
730     * caller is responsible for freeing both *result_list and **result_list.
731     *
732     * @param result_size pointer to return value for the size of the newly
733     * created list
734     */
735 root 1.5 static void
736     build_stringlist (const char *str, char ***result_list, size_t * result_size)
737 elmex 1.1 {
738 root 1.5 char *dup;
739     char *p;
740     size_t size;
741     size_t i;
742 elmex 1.1
743 root 1.11 dup = strdup (str);
744 root 1.5 if (dup == NULL)
745     fatal (OUT_OF_MEMORY);
746 elmex 1.1
747 root 1.5 size = 0;
748     for (p = strtok (dup, ","); p != NULL; p = strtok (NULL, ","))
749     size++;
750 elmex 1.1
751 root 1.5 *result_list = (char **) malloc (size * sizeof (*result_list));
752 root 1.3
753 root 1.5 *result_size = size;
754 elmex 1.1
755 root 1.5 for (i = 0; i < size; i++)
756     {
757     (*result_list)[i] = dup;
758     dup = dup + strlen (dup) + 1;
759 elmex 1.1 }
760     }