00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00044 #include <stdlib.h>
00045 #include <global.h>
00046 #include <object.h>
00047 #include <ctype.h>
00048
00049 static void build_stringlist(const char *str, char ***result_list, size_t *result_size);
00050 static void check_formulae(void);
00051
00053 static recipelist *formulalist;
00054
00063 static recipelist *init_recipelist(void) {
00064 recipelist *tl = (recipelist *)malloc(sizeof(recipelist));
00065 if (tl == NULL)
00066 fatal(OUT_OF_MEMORY);
00067 tl->total_chance = 0;
00068 tl->number = 0;
00069 tl->items = NULL;
00070 tl->next = NULL;
00071 return tl;
00072 }
00073
00082 static recipe *get_empty_formula(void) {
00083 recipe *t = (recipe *)malloc(sizeof(recipe));
00084 if (t == NULL)
00085 fatal(OUT_OF_MEMORY);
00086 t->chance = 0;
00087 t->index = 0;
00088 t->transmute = 0;
00089 t->yield = 0;
00090 t->diff = 0;
00091 t->exp = 0;
00092 t->keycode = NULL;
00093 t->title = NULL;
00094 t->arch_names = 0;
00095 t->arch_name = NULL;
00096 t->skill = NULL;
00097 t->cauldron = NULL;
00098 t->ingred = NULL;
00099 t->next = NULL;
00100 return t;
00101 }
00102
00112 recipelist *get_formulalist(int i) {
00113 recipelist *fl = formulalist;
00114 int number = i;
00115
00116 while (fl && number > 1) {
00117 if (!(fl = fl->next))
00118 break;
00119 number--;
00120 }
00121 return fl;
00122 }
00123
00134 static int check_recipe(const recipe *rp) {
00135 size_t i;
00136 int result;
00137
00138 result = 1;
00139 for (i = 0; i < rp->arch_names; i++) {
00140 if (find_archetype(rp->arch_name[i]) != NULL) {
00141 artifact *art = locate_recipe_artifact(rp, i);
00142
00143 if (!art && strcmp(rp->title, "NONE") != 0) {
00144 LOG(llevError, "\nWARNING: Formula %s of %s has no artifact.\n", rp->arch_name[i], rp->title);
00145 result = 0;
00146 }
00147 } else {
00148 LOG(llevError, "\nWARNING: Can't find archetype %s for formula %s\n", rp->arch_name[i], rp->title);
00149 result = 0;
00150 }
00151 }
00152
00153 return result;
00154 }
00155
00159 void init_formulae(void) {
00160 static int has_been_done = 0;
00161 FILE *fp;
00162 char filename[MAX_BUF], buf[MAX_BUF], *cp, *next;
00163 recipe *formula = NULL;
00164 recipelist *fl = init_recipelist();
00165 linked_char *tmp;
00166 int value, comp;
00167
00168 if (!formulalist)
00169 formulalist = fl;
00170
00171 if (has_been_done)
00172 return;
00173 else
00174 has_been_done = 1;
00175
00176 snprintf(filename, sizeof(filename), "%s/formulae", settings.datadir);
00177 LOG(llevDebug, "Reading alchemical formulae from %s...\n", filename);
00178 if ((fp = open_and_uncompress(filename, 0, &comp)) == NULL) {
00179 LOG(llevError, "Can't open %s.\n", filename);
00180 return;
00181 }
00182
00183 while (fgets(buf, MAX_BUF, fp) != NULL) {
00184 if (*buf == '#')
00185 continue;
00186 if ((cp = strchr(buf, '\n')) != NULL)
00187 *cp = '\0';
00188 cp = buf;
00189 while (*cp == ' ')
00190 cp++;
00191
00192 if (!strncmp(cp, "Object", 6)) {
00193 formula = get_empty_formula();
00194 formula->title = add_string(strchr(cp, ' ')+1);
00195 } else if (!strncmp(cp, "keycode", 7)) {
00196 formula->keycode = add_string(strchr(cp, ' ')+1);
00197 } else if (sscanf(cp, "trans %d", &value)) {
00198 formula->transmute = value;
00199 } else if (sscanf(cp, "yield %d", &value)) {
00200 formula->yield = value;
00201 } else if (sscanf(cp, "chance %d", &value)) {
00202 formula->chance = value;
00203 } else if (sscanf(cp, "exp %d", &value)) {
00204 formula->exp = value;
00205 } else if (sscanf(cp, "diff %d", &value)) {
00206 formula->diff = value;
00207 } else if (!strncmp(cp, "ingred", 6)) {
00208 int numb_ingred = 1;
00209 cp = strchr(cp, ' ')+1;
00210 do {
00211 if ((next = strchr(cp, ',')) != NULL) {
00212 *(next++) = '\0';
00213 numb_ingred++;
00214 }
00215 tmp = (linked_char *)malloc(sizeof(linked_char));
00216 tmp->name = add_string(cp);
00217 tmp->next = formula->ingred;
00218 formula->ingred = tmp;
00219
00220
00221
00222
00223 formula->index += strtoint(cp);
00224 } while ((cp = next) != NULL);
00225
00226 fl = formulalist;
00227 while (numb_ingred != 1) {
00228 if (!fl->next)
00229 fl->next = init_recipelist();
00230 fl = fl->next;
00231 numb_ingred--;
00232 }
00233 fl->total_chance += formula->chance;
00234 fl->number++;
00235 formula->next = fl->items;
00236 fl->items = formula;
00237 } else if (!strncmp(cp, "arch", 4)) {
00238 build_stringlist(strchr(cp, ' ')+1, &formula->arch_name, &formula->arch_names);
00239 check_recipe(formula);
00240 } else if (!strncmp(cp, "skill", 5)) {
00241 formula->skill = add_string(strchr(cp, ' ')+1);
00242 } else if (!strncmp(cp, "cauldron", 8)) {
00243 formula->cauldron = add_string(strchr(cp, ' ')+1);
00244 } else
00245 LOG(llevError, "Unknown input in file %s: %s\n", filename, buf);
00246 }
00247 LOG(llevDebug, "done.\n");
00248 close_and_delete(fp, comp);
00249
00250 check_formulae();
00251 }
00252
00265 static void check_formulae(void) {
00266 recipelist *fl;
00267 recipe *check, *formula;
00268 int numb = 1;
00269
00270 LOG(llevDebug, "Checking formulae lists...\n");
00271
00272 for (fl = formulalist; fl != NULL; fl = fl->next) {
00273 for (formula = fl->items; formula != NULL; formula = formula->next)
00274 for (check = formula->next; check != NULL; check = check->next)
00275 if (check->index == formula->index && strcmp(check->cauldron, formula->cauldron) == 0) {
00276
00277 LOG(llevError, " ERROR: On %d ingred list:\n", numb);
00278 LOG(llevError, "Formulae [%s] of %s and [%s] of %s have matching index id (%d)\n", formula->arch_name[0], formula->title, check->arch_name[0], check->title, formula->index);
00279 }
00280 numb++;
00281 }
00282
00283 LOG(llevDebug, "done checking.\n");
00284 }
00285
00293 void dump_alchemy(void) {
00294 recipelist *fl = formulalist;
00295 recipe *formula = NULL;
00296 linked_char *next;
00297 int num_ingred = 1;
00298
00299 fprintf(logfile, "\n");
00300 while (fl) {
00301 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);
00302 for (formula = fl->items; formula != NULL; formula = formula->next) {
00303 artifact *art = NULL;
00304 char buf[MAX_BUF];
00305 size_t i;
00306
00307 for (i = 0; i < formula->arch_names; i++) {
00308 const char *string = formula->arch_name[i];
00309
00310 if (find_archetype(string) != NULL) {
00311 art = locate_recipe_artifact(formula, i);
00312 if (!art && strcmp(formula->title, "NONE"))
00313 LOG(llevError, "Formula %s has no artifact\n", formula->title);
00314 else {
00315 if (strcmp(formula->title, "NONE"))
00316 snprintf(buf, sizeof(buf), "%s of %s", string, formula->title);
00317 else
00318 snprintf(buf, sizeof(buf), "%s", string);
00319 fprintf(logfile, "%-30s(%d) bookchance %3d ", buf, formula->index, formula->chance);
00320 fprintf(logfile, "skill %s", formula->skill);
00321 fprintf(logfile, "\n");
00322 if (formula->ingred != NULL) {
00323 int nval = 0, tval = 0;
00324 fprintf(logfile, "\tIngred: ");
00325 for (next = formula->ingred; next != NULL; next = next->next) {
00326 if (nval != 0)
00327 fprintf(logfile, ",");
00328 fprintf(logfile, "%s(%d)", next->name, (nval = strtoint(next->name)));
00329 tval += nval;
00330 }
00331 fprintf(logfile, "\n");
00332 if (tval != formula->index)
00333 fprintf(logfile, "WARNING:ingredient list and formula values not equal.\n");
00334 }
00335 if (formula->skill != NULL)
00336 fprintf(logfile, "\tSkill Required: %s", formula->skill);
00337 if (formula->cauldron != NULL)
00338 fprintf(logfile, "\tCauldron: %s\n", formula->cauldron);
00339 fprintf(logfile, "\tDifficulty: %d\t Exp: %d\n", formula->diff, formula->exp);
00340 }
00341 } else
00342 LOG(llevError, "Can't find archetype:%s for formula %s\n", string, formula->title);
00343 }
00344 }
00345 fprintf(logfile, "\n");
00346 fl = fl->next;
00347 num_ingred++;
00348 }
00349 }
00350
00365 archetype *find_treasure_by_name(const treasure *t, const char *name, int depth) {
00366 treasurelist *tl;
00367 archetype *at;
00368
00369 if (depth > 10)
00370 return NULL;
00371
00372 while (t != NULL) {
00373 if (t->name != NULL) {
00374 tl = find_treasurelist(t->name);
00375 at = find_treasure_by_name(tl->items, name, depth+1);
00376 if (at != NULL)
00377 return at;
00378 } else {
00379 if (!strcasecmp(t->item->clone.name, name))
00380 return t->item;
00381 }
00382 if (t->next_yes != NULL) {
00383 at = find_treasure_by_name(t->next_yes, name, depth);
00384 if (at != NULL)
00385 return at;
00386 }
00387 if (t->next_no != NULL) {
00388 at = find_treasure_by_name(t->next_no, name, depth);
00389 if (at != NULL)
00390 return at;
00391 }
00392 t = t->next;
00393 }
00394 return NULL;
00395 }
00396
00416 static long find_ingred_cost(const char *name) {
00417 archetype *at;
00418 archetype *at2;
00419 artifactlist *al;
00420 artifact *art;
00421 long mult;
00422 char *cp;
00423 char part1[100];
00424 char part2[100];
00425
00426
00427 mult = 0;
00428 while (isdigit(*name)) {
00429 mult = 10*mult+(*name-'0');
00430 name++;
00431 }
00432 if (mult > 0)
00433 name++;
00434 else
00435 mult = 1;
00436
00437 for (at = first_archetype; at != NULL; at = at->next) {
00438 if (at->clone.title != NULL) {
00439
00440 snprintf(part1, sizeof(part1), "%s %s", at->clone.name, at->clone.title);
00441 if (!strcasecmp(part1, name))
00442 return mult*at->clone.value;
00443 }
00444 if (!strcasecmp(at->clone.name, name))
00445 return mult*at->clone.value;
00446 }
00447
00448 cp = strstr(name, " of ");
00449 if (cp != NULL) {
00450 strcpy(part1, name);
00451 part1[cp-name] = '\0';
00452 strcpy(part2, cp+4);
00453
00454 for (at = first_archetype; at != NULL; at = at->next)
00455 if (!strcasecmp(at->clone.name, part1) && at->clone.title == NULL)
00456 break;
00457 if (at != NULL) {
00458
00459 for (al = first_artifactlist; al != NULL; al = al->next)
00460 if (al->type == at->clone.type) {
00461 for (art = al->items; art != NULL; art = art->next)
00462 if (!strcasecmp(art->item->name, part2))
00463 return mult*at->clone.value*art->item->value;
00464 }
00465 }
00466 }
00467
00468 cp = strstr(name, "'s ");
00469 if (cp != NULL) {
00470 strcpy(part1, name);
00471 part1[cp-name] = '\0';
00472 strcpy(part2, cp+3);
00473
00474 for (at = first_archetype; at != NULL; at = at->next)
00475 if (!strcasecmp(at->clone.name, part1) && at->clone.title == NULL) {
00476 if (at->clone.randomitems != NULL) {
00477 at2 = find_treasure_by_name(at->clone.randomitems->items, part2, 0);
00478 if (at2 != NULL)
00479 return mult*at2->clone.value*isqrt(at->clone.level*2);
00480 }
00481 }
00482 }
00483
00484 return -1;
00485 }
00486
00495 void dump_alchemy_costs(void) {
00496 recipelist *fl = formulalist;
00497 recipe *formula = NULL;
00498 linked_char *next;
00499 int num_ingred = 1;
00500 int num_errors = 0;
00501 long cost;
00502 long tcost;
00503
00504 fprintf(logfile, "\n");
00505 while (fl) {
00506 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);
00507 for (formula = fl->items; formula != NULL; formula = formula->next) {
00508 artifact *art = NULL;
00509 archetype *at = NULL;
00510 char buf[MAX_BUF];
00511 size_t i;
00512
00513 for (i = 0; i < formula->arch_names; i++) {
00514 const char *string = formula->arch_name[i];
00515
00516 if ((at = find_archetype(string)) != NULL) {
00517 art = locate_recipe_artifact(formula, i);
00518 if (!art && strcmp(formula->title, "NONE"))
00519 LOG(llevError, "Formula %s has no artifact\n", formula->title);
00520 else {
00521 if (!strcmp(formula->title, "NONE"))
00522 snprintf(buf, sizeof(buf), "%s", string);
00523 else
00524 snprintf(buf, sizeof(buf), "%s of %s", string, formula->title);
00525 fprintf(logfile, "\n%-40s bookchance %3d skill %s\n", buf, formula->chance, formula->skill);
00526 if (formula->ingred != NULL) {
00527 tcost = 0;
00528 for (next = formula->ingred; next != NULL; next = next->next) {
00529 cost = find_ingred_cost(next->name);
00530 if (cost < 0)
00531 num_errors++;
00532 fprintf(logfile, "\t%-33s%5ld\n", next->name, cost);
00533 if (cost < 0 || tcost < 0)
00534 tcost = -1;
00535 else
00536 tcost += cost;
00537 }
00538 if (art != NULL && art->item != NULL)
00539 cost = at->clone.value*art->item->value;
00540 else
00541 cost = at->clone.value;
00542 fprintf(logfile, "\t\tBuying result costs: %5ld", cost);
00543 if (formula->yield > 1) {
00544 fprintf(logfile, " to %ld (max %d items)\n", cost*formula->yield, formula->yield);
00545 cost = cost*(formula->yield+1L)/2L;
00546 } else
00547 fprintf(logfile, "\n");
00548 fprintf(logfile, "\t\tIngredients cost: %5ld\n\t\tComment: ", tcost);
00549 if (tcost < 0)
00550 fprintf(logfile, "Could not find some ingredients. Check the formula!\n");
00551 else if (tcost > cost)
00552 fprintf(logfile, "Ingredients are much too expensive. Useless formula.\n");
00553 else if (tcost*2L > cost)
00554 fprintf(logfile, "Ingredients are too expensive.\n");
00555 else if (tcost*10L < cost)
00556 fprintf(logfile, "Ingredients are too cheap.\n");
00557 else
00558 fprintf(logfile, "OK.\n");
00559 }
00560 }
00561 } else
00562 LOG(llevError, "Can't find archetype:%s for formula %s\n", string, formula->title);
00563 }
00564 }
00565 fprintf(logfile, "\n");
00566 fl = fl->next;
00567 num_ingred++;
00568 }
00569 if (num_errors > 0)
00570 fprintf(logfile, "WARNING: %d objects required by the formulae do not exist in the game.\n", num_errors);
00571 }
00572
00581 static const char *ingred_name(const char *name) {
00582 const char *cp = name;
00583
00584 if (atoi(cp))
00585 cp = strchr(cp, ' ')+1;
00586 return cp;
00587 }
00588
00597 static int numb_ingred(const char *buf) {
00598 int numb;
00599
00600 if ((numb = atoi(buf)))
00601 return numb;
00602 else
00603 return 1;
00604 }
00605
00616 int strtoint(const char *buf) {
00617 const char *cp = ingred_name(buf);
00618 int val = 0, len = strlen(cp), mult = numb_ingred(buf);
00619
00620 while (len) {
00621 val += tolower(*cp);
00622 cp++; len--;
00623 }
00624 return val*mult;
00625 }
00626
00637 artifact *locate_recipe_artifact(const recipe *rp, size_t idx) {
00638 object *item = create_archetype(rp->arch_name[idx]);
00639 artifactlist *at = NULL;
00640 artifact *art = NULL;
00641
00642 if (!item)
00643 return (artifact *)NULL;
00644
00645 if ((at = find_artifactlist(item->type)))
00646 for (art = at->items; art; art = art->next)
00647 if (!strcmp(art->item->name, rp->title) && legal_artifact_combination(item, art))
00648 break;
00649
00650 free_object(item);
00651
00652 return art;
00653 }
00654
00661 static recipelist *get_random_recipelist(void) {
00662 recipelist *fl = NULL;
00663 int number = 0, roll = 0;
00664
00665
00666 for (fl = get_formulalist(1); fl; fl = fl->next)
00667 number++;
00668
00669
00670 if (number > 0)
00671 roll = RANDOM()%number;
00672
00673 fl = get_formulalist(1);
00674 while (roll && fl) {
00675 if (fl->next)
00676 fl = fl->next;
00677 else
00678 break;
00679 roll--;
00680 }
00681 if (!fl)
00682 LOG(llevError, "get_random_recipelist(): no recipelists found!\n");
00683 else if (fl->total_chance == 0)
00684 fl = get_random_recipelist();
00685
00686 return fl;
00687 }
00688
00697 recipe *get_random_recipe(recipelist *rpl) {
00698 recipelist *fl = rpl;
00699 recipe *rp = NULL;
00700 int r = 0;
00701
00702
00703 if (fl == NULL)
00704 if ((fl = get_random_recipelist()) == NULL)
00705 return rp;
00706
00707 if (fl->total_chance > 0) {
00708 r = RANDOM()%fl->total_chance;
00709 for (rp = fl->items; rp; rp = rp->next) {
00710 r -= rp->chance;
00711 if (r < 0)
00712 break;
00713 }
00714 }
00715 return rp;
00716 }
00717
00721 void free_all_recipes(void) {
00722 recipelist *fl = formulalist, *flnext;
00723 recipe *formula = NULL, *next;
00724 linked_char *lchar, *charnext;
00725
00726 LOG(llevDebug, "Freeing all the recipes\n");
00727 for (fl = formulalist; fl != NULL; fl = flnext) {
00728 flnext = fl->next;
00729
00730 for (formula = fl->items; formula != NULL; formula = next) {
00731 next = formula->next;
00732
00733 free(formula->arch_name[0]);
00734 free(formula->arch_name);
00735 if (formula->title)
00736 free_string(formula->title);
00737 if (formula->skill)
00738 free_string(formula->skill);
00739 if (formula->cauldron)
00740 free_string(formula->cauldron);
00741 for (lchar = formula->ingred; lchar; lchar = charnext) {
00742 charnext = lchar->next;
00743 free_string(lchar->name);
00744 free(lchar);
00745 }
00746 free(formula);
00747 }
00748 free(fl);
00749 }
00750 formulalist = NULL;
00751 }
00752
00764 static void build_stringlist(const char *str, char ***result_list, size_t *result_size) {
00765 char *dup;
00766 char *p;
00767 size_t size;
00768 size_t i;
00769
00770 dup = strdup_local(str);
00771 if (dup == NULL)
00772 fatal(OUT_OF_MEMORY);
00773
00774 size = 0;
00775 for (p = strtok(dup, ","); p != NULL; p = strtok(NULL, ","))
00776 size++;
00777
00778 *result_list = malloc(size*sizeof(*result_list));
00779 if (*result_list == NULL)
00780 fatal(OUT_OF_MEMORY);
00781 *result_size = size;
00782
00783 for (i = 0; i < size; i++) {
00784 (*result_list)[i] = dup;
00785 dup = dup+strlen(dup)+1;
00786 }
00787 }