ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/recipe.C
Revision: 1.25
Committed: Tue Apr 15 03:16:02 2008 UTC (16 years, 1 month ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-2_5, rel-2_52, rel-2_53
Changes since 1.24: +1 -164 lines
Log Message:
better logging, remove cruft

File Contents

# User Rev Content
1 root 1.20 /*
2 root 1.24 * This file is part of Deliantra, the Roguelike Realtime MMORPG.
3 root 1.21 *
4 root 1.24 * Copyright (©) 2005,2006,2007 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
5 root 1.21 * Copyright (©) 2002,2007 Mark Wedel & Crossfire Development Team
6     * Copyright (©) 1992,2007 Frank Tore Johansen
7     *
8 root 1.24 * Deliantra is free software: you can redistribute it and/or modify
9 root 1.23 * 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 root 1.24 * The authors can be reached via e-mail to <support@deliantra.net>
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     /* Find a treasure with a matching name. The 'depth' parameter is
288     * only there to prevent infinite loops in treasure lists (a list
289     * referencing another list pointing back to the first one). */
290 root 1.5 archetype *
291     find_treasure_by_name (const treasure *t, const char *name, int depth)
292 elmex 1.1 {
293     if (depth > 10)
294 elmex 1.10 return 0;
295    
296     while (t)
297 elmex 1.1 {
298 elmex 1.10 if (t->name)
299 root 1.2 {
300 root 1.19 if (treasurelist *tl = treasurelist::find (t->name))
301     if (tl->items)
302     if (archetype *at = find_treasure_by_name (tl->items, name, depth + 1))
303 elmex 1.10 return at;
304 root 1.2 }
305 elmex 1.1 else
306 root 1.2 {
307 root 1.22 if (t->item && !strcasecmp (t->item->object::name, name))
308 root 1.2 return t->item;
309     }
310 elmex 1.10
311     if (t->next_yes)
312 root 1.19 if (archetype *at = find_treasure_by_name (t->next_yes, name, depth))
313     return at;
314 elmex 1.10
315     if (t->next_no)
316 root 1.19 if (archetype *at = find_treasure_by_name (t->next_no, name, depth))
317     return at;
318    
319 elmex 1.1 t = t->next;
320     }
321 root 1.19
322 elmex 1.10 return 0;
323 elmex 1.1 }
324    
325     /* If several archetypes have the same name, the value of the first
326     * one with that name will be returned. This happens for the
327     * mushrooms (mushroom_1, mushroom_2 and mushroom_3). For the
328     * monsters' body parts, there may be several monsters with the same
329     * name. This is not a problem if these monsters have the same level
330     * (e.g. sage & c_sage) or if only one of the monsters generates the
331     * body parts that we are looking for (e.g. big_dragon and
332     * big_dragon_worthless). */
333 root 1.5 long
334     find_ingred_cost (const char *name)
335 elmex 1.1 {
336 root 1.5 archetype *at2;
337 elmex 1.1 artifactlist *al;
338 root 1.5 artifact *art;
339     long mult;
340     char *cp;
341     char part1[100];
342     char part2[100];
343 elmex 1.1
344     /* same as atoi(), but skip number */
345     mult = 0;
346     while (isdigit (*name))
347     {
348     mult = 10 * mult + (*name - '0');
349     name++;
350     }
351 root 1.16
352 elmex 1.1 if (mult > 0)
353     name++;
354     else
355     mult = 1;
356 root 1.16
357 elmex 1.1 /* first, try to match the name of an archetype */
358 root 1.22 for_all_archetypes (at)
359 elmex 1.1 {
360 root 1.22 if (at->title != NULL)
361 root 1.2 {
362     /* inefficient, but who cares? */
363 root 1.22 sprintf (part1, "%s %s", &at->object::name, &at->title);
364 root 1.5 if (!strcasecmp (part1, name))
365 root 1.22 return mult * at->value;
366 root 1.2 }
367 root 1.22 if (!strcasecmp (at->object::name, name))
368     return mult * at->value;
369 elmex 1.1 }
370 root 1.16
371 elmex 1.1 /* second, try to match an artifact ("arch of something") */
372     cp = strstr (name, " of ");
373     if (cp != NULL)
374     {
375     strcpy (part1, name);
376     part1[cp - name] = '\0';
377     strcpy (part2, cp + 4);
378 root 1.22
379 elmex 1.1 /* find the first archetype matching the first part of the name */
380 root 1.22 for_all_archetypes (at)
381     if (!strcasecmp (at->object::name, part1) && at->title == NULL)
382     {
383     /* find the first artifact derived from that archetype (same type) */
384     for (al = first_artifactlist; al; al = al->next)
385     if (al->type == at->type)
386     {
387     for (art = al->items; art; art = art->next)
388     if (!strcasecmp (art->item->name, part2))
389     return mult * at->value * art->item->value;
390     }
391     }
392 elmex 1.1 }
393 root 1.16
394 elmex 1.1 /* third, try to match a body part ("arch's something") */
395     cp = strstr (name, "'s ");
396 root 1.16 if (cp)
397 elmex 1.1 {
398     strcpy (part1, name);
399     part1[cp - name] = '\0';
400     strcpy (part2, cp + 3);
401     /* examine all archetypes matching the first part of the name */
402 root 1.22 for_all_archetypes (at)
403     if (!strcasecmp (at->object::name, part1) && at->title == NULL)
404 root 1.2 {
405 root 1.22 if (at->randomitems)
406 root 1.2 {
407 root 1.22 at2 = find_treasure_by_name (at->randomitems->items, part2, 0);
408 elmex 1.10 if (at2)
409 root 1.22 return mult * at2->value * isqrt (at->level * 2);
410 root 1.2 }
411     }
412 elmex 1.1 }
413 root 1.16
414 elmex 1.1 /* failed to find any matching items -- formula should be checked */
415     return -1;
416     }
417    
418 root 1.5 const char *
419     ingred_name (const char *name)
420     {
421     const char *cp = name;
422    
423     if (atoi (cp))
424     cp = strchr (cp, ' ') + 1;
425 root 1.25
426 elmex 1.1 return cp;
427     }
428    
429     /* strtoint() - we use this to convert buf into an integer
430     * equal to the coadded sum of the (lowercase) character
431     * ASCII values in buf (times prepended integers).
432     */
433    
434 root 1.5 int
435     strtoint (const char *buf)
436     {
437     const char *cp = ingred_name (buf);
438     int val = 0, len = strlen (cp), mult = numb_ingred (buf);
439 elmex 1.1
440 root 1.5 while (len)
441     {
442     val += tolower (*cp);
443     cp++;
444     len--;
445     }
446     return val * mult;
447 elmex 1.1 }
448    
449 root 1.5 artifact *
450     locate_recipe_artifact (const recipe *rp, size_t idx)
451     {
452 root 1.18 archetype *at = archetype::find (rp->arch_name [idx]);
453 elmex 1.1
454 root 1.18 if (at)
455 root 1.22 if (artifactlist *al = find_artifactlist (at->type))
456 root 1.18 for (artifact *art = al->items; art; art = art->next)
457     if (art->item->name == rp->title)
458     return art;
459 elmex 1.1
460 root 1.18 return 0;
461 elmex 1.1 }
462    
463 root 1.5 int
464     numb_ingred (const char *buf)
465     {
466 elmex 1.1 int numb;
467    
468 root 1.5 if ((numb = atoi (buf)))
469     return numb;
470     else
471     return 1;
472     }
473    
474     recipelist *
475     get_random_recipelist (void)
476     {
477     recipelist *fl = NULL;
478     int number = 0, roll = 0;
479    
480     /* first, determine # of recipelist we have */
481     for (fl = get_formulalist (1); fl; fl = fl->next)
482     number++;
483    
484     /* now, randomly choose one */
485     if (number > 0)
486 root 1.15 roll = rndm (number);
487 root 1.5
488     fl = get_formulalist (1);
489     while (roll && fl)
490     {
491     if (fl->next)
492     fl = fl->next;
493     else
494     break;
495     roll--;
496     }
497     if (!fl) /* failed! */
498     LOG (llevError, "get_random_recipelist(): no recipelists found!\n");
499     else if (fl->total_chance == 0)
500     fl = get_random_recipelist ();
501    
502     return fl;
503 elmex 1.1 }
504    
505 root 1.5 recipe *
506     get_random_recipe (recipelist * rpl)
507     {
508     recipelist *fl = rpl;
509     recipe *rp = NULL;
510     int r = 0;
511    
512     /* looks like we have to choose a random one */
513     if (fl == NULL)
514     if ((fl = get_random_recipelist ()) == NULL)
515     return rp;
516    
517     if (fl->total_chance > 0)
518     {
519 root 1.15 r = rndm (fl->total_chance);
520 root 1.5 for (rp = fl->items; rp; rp = rp->next)
521     {
522     r -= rp->chance;
523     if (r < 0)
524     break;
525     }
526 elmex 1.1 }
527     return rp;
528     }
529    
530 root 1.5 void
531     free_all_recipes (void)
532 elmex 1.1 {
533 root 1.5 recipelist *fl = formulalist, *flnext;
534     recipe *formula = NULL, *next;
535     linked_char *lchar, *charnext;
536    
537     LOG (llevDebug, "Freeing all the recipes\n");
538     for (fl = formulalist; fl != NULL; fl = flnext)
539     {
540     flnext = fl->next;
541    
542     for (formula = fl->items; formula != NULL; formula = next)
543     {
544     next = formula->next;
545    
546     free (formula->arch_name[0]);
547     free (formula->arch_name);
548    
549     for (lchar = formula->ingred; lchar; lchar = charnext)
550     {
551     charnext = lchar->next;
552     delete lchar;
553 root 1.2 }
554 root 1.5 delete formula;
555 root 1.2 }
556 root 1.3
557 root 1.5 delete fl;
558 elmex 1.1 }
559     }
560    
561     /**
562     * Split a comma separated string list into words.
563     *
564     * @param str the string to split
565     *
566     * @param result_list pointer to return value for the newly created list; the
567     * caller is responsible for freeing both *result_list and **result_list.
568     *
569     * @param result_size pointer to return value for the size of the newly
570     * created list
571     */
572 root 1.5 static void
573     build_stringlist (const char *str, char ***result_list, size_t * result_size)
574 elmex 1.1 {
575 root 1.5 char *dup;
576     char *p;
577     size_t size;
578     size_t i;
579 elmex 1.1
580 root 1.11 dup = strdup (str);
581 root 1.5 if (dup == NULL)
582     fatal (OUT_OF_MEMORY);
583 elmex 1.1
584 root 1.5 size = 0;
585     for (p = strtok (dup, ","); p != NULL; p = strtok (NULL, ","))
586     size++;
587 elmex 1.1
588 root 1.5 *result_list = (char **) malloc (size * sizeof (*result_list));
589 root 1.3
590 root 1.5 *result_size = size;
591 elmex 1.1
592 root 1.5 for (i = 0; i < size; i++)
593     {
594     (*result_list)[i] = dup;
595     dup = dup + strlen (dup) + 1;
596 elmex 1.1 }
597     }