ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/recipe.C
(Generate patch)

Comparing deliantra/server/common/recipe.C (file contents):
Revision 1.19 by root, Mon Apr 16 06:23:40 2007 UTC vs.
Revision 1.32 by root, Fri Nov 6 13:31:47 2009 UTC

1/*
2 * This file is part of Deliantra, the Roguelike Realtime MMORPG.
3 *
4 * Copyright (©) 2005,2006,2007,2008 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
5 * Copyright (©) 2002,2007 Mark Wedel & Crossfire Development Team
6 * Copyright (©) 1992,2007 Frank Tore Johansen
7 *
8 * Deliantra is free software: you can redistribute it and/or modify it under
9 * the terms of the Affero GNU General Public License as published by the
10 * Free Software Foundation, either version 3 of the License, or (at your
11 * option) any later version.
12 *
13 * 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 *
18 * You should have received a copy of the Affero GNU General Public License
19 * and the GNU General Public License along with this program. If not, see
20 * <http://www.gnu.org/licenses/>.
21 *
22 * The authors can be reached via e-mail to <support@deliantra.net>
23 */
24
1/* Basic stuff for use with the alchemy code. Clearly some of this stuff 25/* Basic stuff for use with the alchemy code. Clearly some of this stuff
2 * could go into server/alchemy, but I left it here just in case it proves 26 * could go into server/alchemy, but I left it here just in case it proves
3 * more generally useful. 27 * more generally useful.
4 * 28 *
5 * Nov 1995 - file created by b.t. thomas@astro.psu.edu 29 * Nov 1995 - file created by b.t. thomas@astro.psu.edu
87 size_t i; 111 size_t i;
88 int result = 1; 112 int result = 1;
89 113
90 for (i = 0; i < rp->arch_names; i++) 114 for (i = 0; i < rp->arch_names; i++)
91 { 115 {
92 if (archetype::find (rp->arch_name[i]) != NULL) 116 if (archetype::find (rp->arch_name[i]))
93 { 117 {
94 artifact *art = locate_recipe_artifact (rp, i); 118 artifact *art = locate_recipe_artifact (rp, i);
95 119
96 if (!art && strcmp (rp->title, "NONE") != 0) 120 if (!art && rp->title != shstr_NONE)
97 { 121 {
98 LOG (llevError, "WARNING: Formula %s of %s has no artifact.\n", rp->arch_name[i], &rp->title); 122 LOG (llevError, "WARNING: Formula %s of %s has no artifact.\n", rp->arch_name[i], &rp->title);
99 result = 0; 123 result = 0;
100 } 124 }
101 } 125 }
105 result = 0; 129 result = 0;
106 } 130 }
107 } 131 }
108 132
109 return result; 133 return result;
134}
135
136/* check_formulae()- since we are doing a squential search on the
137 * formulae lists now, we have to be carefull that we dont have 2
138 * formula with the exact same index value. Under the new nbatches
139 * code, it is possible to have multiples of ingredients in a cauldron
140 * which could result in an index formula mismatch. We *don't* check for
141 * that possibility here. -b.t.
142 */
143static void
144check_formulae (void)
145{
146 recipelist *fl;
147 recipe *check, *formula;
148 int numb = 1;
149
150 LOG (llevDebug, "Checking formulae lists...\n");
151
152 for (fl = formulalist; fl; fl = fl->next)
153 {
154 for (formula = fl->items; formula; formula = formula->next)
155 for (check = formula->next; check; check = check->next)
156 if (check->index == formula->index)
157 {
158 LOG (llevError, " ERROR: On %d ingred list: ", numb);
159 LOG (llevError, "Formulae [%s] of %s and [%s] of %s have matching index id (%d)\n",
160 formula->arch_name[0], &formula->title, check->arch_name[0], &check->title, formula->index);
161 }
162 numb++;
163 }
164
165 LOG (llevDebug, "done.\n");
166
110} 167}
111 168
112/* 169/*
113 * init_formulae() - Builds up the lists of formula from the file in 170 * init_formulae() - Builds up the lists of formula from the file in
114 * the libdir. -b.t. 171 * the libdir. -b.t.
226 close_and_delete (fp, comp); 283 close_and_delete (fp, comp);
227 /* Lastly, lets check for problems in formula we got */ 284 /* Lastly, lets check for problems in formula we got */
228 check_formulae (); 285 check_formulae ();
229} 286}
230 287
231/* check_formulae()- since we are doing a squential search on the
232 * formulae lists now, we have to be carefull that we dont have 2
233 * formula with the exact same index value. Under the new nbatches
234 * code, it is possible to have multiples of ingredients in a cauldron
235 * which could result in an index formula mismatch. We *don't* check for
236 * that possibility here. -b.t.
237 */
238void
239check_formulae (void)
240{
241 recipelist *fl;
242 recipe *check, *formula;
243 int numb = 1;
244
245 LOG (llevDebug, "Checking formulae lists...\n");
246
247 for (fl = formulalist; fl; fl = fl->next)
248 {
249 for (formula = fl->items; formula; formula = formula->next)
250 for (check = formula->next; check; check = check->next)
251 if (check->index == formula->index)
252 {
253 LOG (llevError, " ERROR: On %d ingred list: ", numb);
254 LOG (llevError, "Formulae [%s] of %s and [%s] of %s have matching index id (%d)\n",
255 formula->arch_name[0], &formula->title, check->arch_name[0], &check->title, formula->index);
256 }
257 numb++;
258 }
259
260 LOG (llevDebug, "done.\n");
261
262}
263
264/* Borrowed (again) from the artifacts code for this */
265
266void
267dump_alchemy (void)
268{
269 recipelist *fl = formulalist;
270 recipe *formula = NULL;
271 linked_char *next;
272 int num_ingred = 1;
273
274 fprintf (logfile, "\n");
275 while (fl)
276 {
277 fprintf (logfile, "\n Formulae with %d ingredient%s %d Formulae with total_chance=%d\n",
278 num_ingred, num_ingred > 1 ? "s." : ".", fl->number, fl->total_chance);
279 for (formula = fl->items; formula; formula = formula->next)
280 {
281 artifact *art = NULL;
282 char buf[MAX_BUF];
283 size_t i;
284
285 for (i = 0; i < formula->arch_names; i++)
286 {
287 const char *string = formula->arch_name[i];
288
289 if (archetype::find (string) != NULL)
290 {
291 art = locate_recipe_artifact (formula, i);
292 if (!art && strcmp (formula->title, "NONE"))
293 LOG (llevError, "Formula %s has no artifact!\n", &formula->title);
294 else
295 {
296 if (strcmp (formula->title, "NONE"))
297 sprintf (buf, "%s of %s", string, &formula->title);
298 else
299 sprintf (buf, "%s", string);
300 fprintf (logfile, "%-30s(%d) bookchance %3d ", buf, formula->index, formula->chance);
301 fprintf (logfile, "skill %s", &formula->skill);
302 fprintf (logfile, "\n");
303 if (formula->ingred != NULL)
304 {
305 int nval = 0, tval = 0;
306
307 fprintf (logfile, "\tIngred: ");
308 for (next = formula->ingred; next != NULL; next = next->next)
309 {
310 if (nval != 0)
311 fprintf (logfile, ",");
312 fprintf (logfile, "%s(%d)", &next->name, (nval = strtoint (next->name)));
313 tval += nval;
314 }
315 fprintf (logfile, "\n");
316 if (tval != formula->index)
317 fprintf (logfile, "WARNING:ingredient list and formula values not equal.\n");
318 }
319 if (formula->skill != NULL)
320 fprintf (logfile, "\tSkill Required: %s", &formula->skill);
321 if (formula->cauldron != NULL)
322 fprintf (logfile, "\tCauldron: %s\n", &formula->cauldron);
323 fprintf (logfile, "\tDifficulty: %d\t Exp: %d\n", formula->diff, formula->exp);
324 }
325 }
326 else
327 LOG (llevError, "Can't find archetype:%s for formula %s\n", string, &formula->title);
328 }
329 }
330 fprintf (logfile, "\n");
331 fl = fl->next;
332 num_ingred++;
333 }
334}
335
336/* Find a treasure with a matching name. The 'depth' parameter is 288/* Find a treasure with a matching name. The 'depth' parameter is
337 * only there to prevent infinite loops in treasure lists (a list 289 * only there to prevent infinite loops in treasure lists (a list
338 * referencing another list pointing back to the first one). */ 290 * referencing another list pointing back to the first one). */
339archetype * 291static archetype *
340find_treasure_by_name (const treasure *t, const char *name, int depth) 292find_treasure_by_name (const treasure *t, const char *name, int depth)
341{ 293{
342 if (depth > 10) 294 if (depth > 10)
343 return 0; 295 return 0;
344 296
351 if (archetype *at = find_treasure_by_name (tl->items, name, depth + 1)) 303 if (archetype *at = find_treasure_by_name (tl->items, name, depth + 1))
352 return at; 304 return at;
353 } 305 }
354 else 306 else
355 { 307 {
356 if (t->item && !strcasecmp (t->item->clone.name, name)) 308 if (t->item && !strcasecmp (t->item->object::name, name))
357 return t->item; 309 return t->item;
358 } 310 }
359 311
360 if (t->next_yes) 312 if (t->next_yes)
361 if (archetype *at = find_treasure_by_name (t->next_yes, name, depth)) 313 if (archetype *at = find_treasure_by_name (t->next_yes, name, depth))
369 } 321 }
370 322
371 return 0; 323 return 0;
372} 324}
373 325
374/* If several archetypes have the same name, the value of the first
375 * one with that name will be returned. This happens for the
376 * mushrooms (mushroom_1, mushroom_2 and mushroom_3). For the
377 * monsters' body parts, there may be several monsters with the same
378 * name. This is not a problem if these monsters have the same level
379 * (e.g. sage & c_sage) or if only one of the monsters generates the
380 * body parts that we are looking for (e.g. big_dragon and
381 * big_dragon_worthless). */
382long
383find_ingred_cost (const char *name)
384{
385 archetype *at;
386 archetype *at2;
387 artifactlist *al;
388 artifact *art;
389 long mult;
390 char *cp;
391 char part1[100];
392 char part2[100];
393
394 /* same as atoi(), but skip number */
395 mult = 0;
396 while (isdigit (*name))
397 {
398 mult = 10 * mult + (*name - '0');
399 name++;
400 }
401
402 if (mult > 0)
403 name++;
404 else
405 mult = 1;
406
407 /* first, try to match the name of an archetype */
408 for (at = first_archetype; at != NULL; at = at->next)
409 {
410 if (at->clone.title != NULL)
411 {
412 /* inefficient, but who cares? */
413 sprintf (part1, "%s %s", &at->clone.name, &at->clone.title);
414 if (!strcasecmp (part1, name))
415 return mult * at->clone.value;
416 }
417 if (!strcasecmp (at->clone.name, name))
418 return mult * at->clone.value;
419 }
420
421 /* second, try to match an artifact ("arch of something") */
422 cp = strstr (name, " of ");
423 if (cp != NULL)
424 {
425 strcpy (part1, name);
426 part1[cp - name] = '\0';
427 strcpy (part2, cp + 4);
428 /* find the first archetype matching the first part of the name */
429 for (at = first_archetype; at; at = at->next)
430 if (!strcasecmp (at->clone.name, part1) && at->clone.title == NULL)
431 break;
432 if (at != NULL)
433 {
434 /* find the first artifact derived from that archetype (same type) */
435 for (al = first_artifactlist; al; al = al->next)
436 if (al->type == at->clone.type)
437 {
438 for (art = al->items; art; art = art->next)
439 if (!strcasecmp (art->item->name, part2))
440 return mult * at->clone.value * art->item->value;
441 }
442 }
443 }
444
445 /* third, try to match a body part ("arch's something") */
446 cp = strstr (name, "'s ");
447 if (cp)
448 {
449 strcpy (part1, name);
450 part1[cp - name] = '\0';
451 strcpy (part2, cp + 3);
452 /* examine all archetypes matching the first part of the name */
453 for (at = first_archetype; at; at = at->next)
454 if (!strcasecmp (at->clone.name, part1) && at->clone.title == NULL)
455 {
456 if (at->clone.randomitems)
457 {
458 at2 = find_treasure_by_name (at->clone.randomitems->items, part2, 0);
459 if (at2)
460 return mult * at2->clone.value * isqrt (at->clone.level * 2);
461 }
462 }
463 }
464
465 /* failed to find any matching items -- formula should be checked */
466 return -1;
467}
468
469/* code copied from dump_alchemy() and modified by Raphael Quinet */
470void
471dump_alchemy_costs (void)
472{
473 recipelist *fl = formulalist;
474 recipe *formula = NULL;
475 linked_char *next;
476 int num_ingred = 1;
477 int num_errors = 0;
478 long cost;
479 long tcost;
480
481 fprintf (logfile, "\n");
482 while (fl)
483 {
484 fprintf (logfile, "\n Formulae with %d ingredient%s %d Formulae with total_chance=%d\n",
485 num_ingred, num_ingred > 1 ? "s." : ".", fl->number, fl->total_chance);
486 for (formula = fl->items; formula; formula = formula->next)
487 {
488 artifact *art = NULL;
489 archetype *at = NULL;
490 char buf[MAX_BUF];
491 size_t i;
492
493 for (i = 0; i < formula->arch_names; i++)
494 {
495 const char *string = formula->arch_name[i];
496
497 if ((at = archetype::find (string)) != NULL)
498 {
499 art = locate_recipe_artifact (formula, i);
500 if (!art && strcmp (formula->title, "NONE"))
501 LOG (llevError, "Formula %s has no artifact\n", &formula->title);
502 else
503 {
504 if (!strcmp (formula->title, "NONE"))
505 sprintf (buf, "%s", string);
506 else
507 sprintf (buf, "%s of %s", string, &formula->title);
508 fprintf (logfile, "\n%-40s bookchance %3d skill %s\n", buf, formula->chance, &(formula->skill));
509 if (formula->ingred != NULL)
510 {
511 tcost = 0;
512 for (next = formula->ingred; next != NULL; next = next->next)
513 {
514 cost = find_ingred_cost (next->name);
515 if (cost < 0)
516 num_errors++;
517 fprintf (logfile, "\t%-33s%5ld\n", &next->name, cost);
518 if (cost < 0 || tcost < 0)
519 tcost = -1;
520 else
521 tcost += cost;
522 }
523 if (art != NULL && art->item != NULL)
524 cost = at->clone.value * art->item->value;
525 else
526 cost = at->clone.value;
527 fprintf (logfile, "\t\tBuying result costs: %5ld", cost);
528 if (formula->yield > 1)
529 {
530 fprintf (logfile, " to %ld (max %d items)\n", cost * formula->yield, formula->yield);
531 cost = cost * (formula->yield + 1L) / 2L;
532 }
533 else
534 fprintf (logfile, "\n");
535 fprintf (logfile, "\t\tIngredients cost: %5ld\n\t\tComment: ", tcost);
536 if (tcost < 0)
537 fprintf (logfile, "Could not find some ingredients. Check the formula!\n");
538 else if (tcost > cost)
539 fprintf (logfile, "Ingredients are much too expensive. Useless formula.\n");
540 else if (tcost * 2L > cost)
541 fprintf (logfile, "Ingredients are too expensive.\n");
542 else if (tcost * 10L < cost)
543 fprintf (logfile, "Ingredients are too cheap.\n");
544 else
545 fprintf (logfile, "OK.\n");
546 }
547 }
548 }
549 else
550 LOG (llevError, "Can't find archetype:%s for formula %s\n", string, &formula->title);
551 }
552 }
553 fprintf (logfile, "\n");
554 fl = fl->next;
555 num_ingred++;
556 }
557 if (num_errors > 0)
558 fprintf (logfile, "WARNING: %d objects required by the formulae do not exist in the game.\n", num_errors);
559}
560
561const char * 326static const char *
562ingred_name (const char *name) 327ingred_name (const char *name)
563{ 328{
564 const char *cp = name; 329 const char *cp = name;
565 330
566 if (atoi (cp)) 331 if (atoi (cp))
567 cp = strchr (cp, ' ') + 1; 332 cp = strchr (cp, ' ') + 1;
333
568 return cp; 334 return cp;
569} 335}
570 336
571/* strtoint() - we use this to convert buf into an integer 337static int
572 * equal to the coadded sum of the (lowercase) character
573 * ASCII values in buf (times prepended integers).
574 */
575
576int
577strtoint (const char *buf)
578{
579 const char *cp = ingred_name (buf);
580 int val = 0, len = strlen (cp), mult = numb_ingred (buf);
581
582 while (len)
583 {
584 val += tolower (*cp);
585 cp++;
586 len--;
587 }
588 return val * mult;
589}
590
591artifact *
592locate_recipe_artifact (const recipe *rp, size_t idx)
593{
594 archetype *at = archetype::find (rp->arch_name [idx]);
595
596 if (at)
597 if (artifactlist *al = find_artifactlist (at->clone.type))
598 for (artifact *art = al->items; art; art = art->next)
599 if (art->item->name == rp->title)
600 return art;
601
602 return 0;
603}
604
605int
606numb_ingred (const char *buf) 338numb_ingred (const char *buf)
607{ 339{
608 int numb; 340 int numb;
609 341
610 if ((numb = atoi (buf))) 342 if ((numb = atoi (buf)))
611 return numb; 343 return numb;
612 else 344 else
613 return 1; 345 return 1;
614} 346}
615 347
348/* strtoint() - we use this to convert buf into an integer
349 * equal to the coadded sum of the (lowercase) character
350 * ASCII values in buf (times prepended integers).
351 * Some kind of hashing.
352 */
353int
354strtoint (const char *buf)
355{
356 const char *cp = ingred_name (buf);
357 int val = 0, len = strlen (cp), mult = numb_ingred (buf);
358
359 while (len)
360 {
361 val += tolower (*cp);
362 cp++;
363 len--;
364 }
365
366 return val * mult;
367}
368
369artifact *
370locate_recipe_artifact (const recipe *rp, size_t idx)
371{
372 archetype *at = archetype::find (rp->arch_name [idx]);
373
374 if (at)
375 if (artifactlist *al = find_artifactlist (at->type))
376 for (artifact *art = al->items; art; art = art->next)
377 if (art->item->name == rp->title)
378 return art;
379
380 return 0;
381}
382
616recipelist * 383static recipelist *
617get_random_recipelist (void) 384get_random_recipelist (void)
618{ 385{
619 recipelist *fl = NULL; 386 recipelist *fl = NULL;
620 int number = 0, roll = 0; 387 int number = 0, roll = 0;
621 388
665 if (r < 0) 432 if (r < 0)
666 break; 433 break;
667 } 434 }
668 } 435 }
669 return rp; 436 return rp;
670}
671
672void
673free_all_recipes (void)
674{
675 recipelist *fl = formulalist, *flnext;
676 recipe *formula = NULL, *next;
677 linked_char *lchar, *charnext;
678
679 LOG (llevDebug, "Freeing all the recipes\n");
680 for (fl = formulalist; fl != NULL; fl = flnext)
681 {
682 flnext = fl->next;
683
684 for (formula = fl->items; formula != NULL; formula = next)
685 {
686 next = formula->next;
687
688 free (formula->arch_name[0]);
689 free (formula->arch_name);
690
691 for (lchar = formula->ingred; lchar; lchar = charnext)
692 {
693 charnext = lchar->next;
694 delete lchar;
695 }
696 delete formula;
697 }
698
699 delete fl;
700 }
701} 437}
702 438
703/** 439/**
704 * Split a comma separated string list into words. 440 * Split a comma separated string list into words.
705 * 441 *

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines