|
Atrinik Server 2.5
|
00001 /************************************************************************ 00002 * Atrinik, a Multiplayer Online Role Playing Game * 00003 * * 00004 * Copyright (C) 2009-2011 Alex Tokar and Atrinik Development Team * 00005 * * 00006 * Fork from Daimonin (Massive Multiplayer Online Role Playing Game) * 00007 * and Crossfire (Multiplayer game for X-windows). * 00008 * * 00009 * This program is free software; you can redistribute it and/or modify * 00010 * it under the terms of the GNU General Public License as published by * 00011 * the Free Software Foundation; either version 2 of the License, or * 00012 * (at your option) any later version. * 00013 * * 00014 * This program is distributed in the hope that it will be useful, * 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00017 * GNU General Public License for more details. * 00018 * * 00019 * You should have received a copy of the GNU General Public License * 00020 * along with this program; if not, write to the Free Software * 00021 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * 00022 * * 00023 * The author can be reached at admin@atrinik.org * 00024 ************************************************************************/ 00025 00042 #include <global.h> 00043 00045 static recipelist *formulalist; 00046 00047 static void check_formulae(); 00048 static archetype *find_treasure_by_name(treasure *t, char *name, int depth); 00049 static long find_ingred_cost(const char *name); 00050 static const char *ingred_name(const char *name); 00051 static int numb_ingred(const char *buf); 00052 static recipelist *get_random_recipelist(); 00053 00057 static recipelist *init_recipelist() 00058 { 00059 recipelist *tl = (recipelist *) malloc(sizeof(recipelist)); 00060 00061 if (tl == NULL) 00062 { 00063 LOG(llevError, "init_recipelist(): Out of memory.\n"); 00064 } 00065 00066 tl->total_chance = 0; 00067 tl->number = 0; 00068 tl->items = NULL; 00069 tl->next = NULL; 00070 return tl; 00071 } 00072 00076 static recipe *get_empty_formula() 00077 { 00078 recipe *t = (recipe *) malloc(sizeof(recipe)); 00079 00080 if (t == NULL) 00081 { 00082 LOG(llevError, "get_empty_formula(): Out of memory.\n"); 00083 } 00084 00085 t->chance = 0; 00086 t->index = 0; 00087 t->transmute = 0; 00088 t->yield = 0; 00089 t->keycode = 0; 00090 t->title = NULL; 00091 t->arch_name = NULL; 00092 t->ingred = NULL; 00093 t->next = NULL; 00094 return t; 00095 } 00096 00101 recipelist *get_formulalist(int i) 00102 { 00103 recipelist *fl = formulalist; 00104 int number = i; 00105 00106 while (fl && number > 1) 00107 { 00108 if (!(fl = fl->next)) 00109 { 00110 break; 00111 } 00112 00113 number--; 00114 } 00115 00116 return fl; 00117 } 00118 00123 static int check_recipe(recipe *rp) 00124 { 00125 if (find_archetype(rp->arch_name) != NULL) 00126 { 00127 artifact *art = locate_recipe_artifact(rp); 00128 00129 if (!art && rp->title != shstr_cons.NONE) 00130 { 00131 LOG(llevBug, "Formula %s of %s has no artifact.\n", rp->arch_name, rp->title); 00132 return 0; 00133 } 00134 } 00135 else 00136 { 00137 LOG(llevBug, "Can't find archetype:%s for formula:%s\n", rp->arch_name, rp->title); 00138 return 0; 00139 } 00140 00141 return 1; 00142 } 00143 00146 void init_formulae() 00147 { 00148 static int has_been_done = 0; 00149 FILE *fp; 00150 char filename[MAX_BUF], buf[MAX_BUF], *cp, *next; 00151 recipe *formula = NULL; 00152 recipelist *fl = init_recipelist(); 00153 linked_char *tmp; 00154 int value, comp; 00155 00156 if (!formulalist) 00157 { 00158 formulalist = fl; 00159 } 00160 00161 if (has_been_done) 00162 { 00163 return; 00164 } 00165 else 00166 { 00167 has_been_done = 1; 00168 } 00169 00170 snprintf(filename, sizeof(filename), "%s/formulae", settings.datadir); 00171 LOG(llevDebug, "Reading alchemical formulae from %s...",filename); 00172 00173 if ((fp = open_and_uncompress(filename, 0, &comp)) == NULL) 00174 { 00175 LOG(llevBug, "Can't open %s.\n", filename); 00176 return; 00177 } 00178 00179 while (fgets(buf, MAX_BUF, fp) != NULL) 00180 { 00181 if (*buf == '#') 00182 { 00183 continue; 00184 } 00185 00186 if ((cp = strchr(buf, '\n')) != NULL) 00187 { 00188 *cp = '\0'; 00189 } 00190 00191 cp = buf; 00192 00193 /* Skip blanks */ 00194 while (*cp == ' ') 00195 { 00196 cp++; 00197 } 00198 00199 if (!strncmp(cp, "Object", 6)) 00200 { 00201 formula = get_empty_formula(); 00202 FREE_AND_COPY_HASH(formula->title, strchr(cp, ' ') + 1); 00203 } 00204 else if (!strncmp(cp, "keycode", 7)) 00205 { 00206 FREE_AND_COPY_HASH(formula->keycode, strchr(cp, ' ') + 1); 00207 } 00208 else if (sscanf(cp, "trans %d", &value)) 00209 { 00210 formula->transmute = (uint16) value; 00211 } 00212 else if (sscanf(cp, "yield %d", &value)) 00213 { 00214 formula->yield = (uint16) value; 00215 } 00216 else if (sscanf(cp, "chance %d", &value)) 00217 { 00218 formula->chance = (uint16) value; 00219 } 00220 else if (!strncmp(cp, "ingred", 6)) 00221 { 00222 int num_ingred = 1; 00223 cp = strchr(cp, ' ') + 1; 00224 00225 do 00226 { 00227 if ((next = strchr(cp, ',')) != NULL) 00228 { 00229 *(next++) = '\0'; 00230 num_ingred++; 00231 } 00232 00233 tmp = (linked_char *) malloc(sizeof(linked_char)); 00234 tmp->name = NULL; 00235 FREE_AND_COPY_HASH(tmp->name, cp); 00236 tmp->next = formula->ingred; 00237 formula->ingred = tmp; 00238 00239 /* each ingredient's ASCII value is coadded. Later on this 00240 * value will be used allow us to search the formula lists 00241 * quickly for the right recipe. */ 00242 formula->index += strtoint(cp); 00243 } 00244 while ((cp = next) != NULL); 00245 00246 /* now find the correct (# of ingred ordered) formulalist */ 00247 fl = formulalist; 00248 00249 while (num_ingred != 1) 00250 { 00251 if (!fl->next) 00252 { 00253 fl->next = init_recipelist(); 00254 } 00255 00256 fl = fl->next; 00257 num_ingred--; 00258 } 00259 00260 fl->total_chance += formula->chance; 00261 fl->number++; 00262 formula->next = fl->items; 00263 fl->items = formula; 00264 } 00265 else if (!strncmp(cp, "arch", 4)) 00266 { 00267 FREE_AND_COPY_HASH(formula->arch_name, strchr(cp, ' ') + 1); 00268 (void) check_recipe(formula); 00269 } 00270 else 00271 { 00272 LOG(llevBug, "Unknown input in file %s: %s\n", filename, buf); 00273 } 00274 } 00275 00276 LOG(llevDebug, "done.\n"); 00277 close_and_delete(fp, comp); 00278 /* Lastly, lets check for problems in formula we got */ 00279 check_formulae(); 00280 } 00281 00290 static void check_formulae() 00291 { 00292 recipelist *fl; 00293 recipe *check, *formula; 00294 int numb = 1; 00295 00296 LOG(llevDebug,"Checking formulae lists..."); 00297 00298 for (fl = formulalist; fl != NULL; fl = fl->next) 00299 { 00300 for (formula = fl->items; formula != NULL; formula = formula->next) 00301 { 00302 for (check = formula->next; check != NULL; check = check->next) 00303 { 00304 if (check->index == formula->index) 00305 { 00306 LOG(llevBug, "On %d ingred list: ", numb); 00307 LOG(llevBug, "Formulae [%s] of %s and [%s] of %s have matching index id (%d)\n", formula->arch_name, formula->title, check->arch_name, check->title, formula->index); 00308 } 00309 } 00310 } 00311 00312 numb++; 00313 } 00314 00315 LOG(llevDebug, "done.\n"); 00316 } 00317 00320 void dump_alchemy() 00321 { 00322 recipelist *fl = formulalist; 00323 recipe *formula = NULL; 00324 linked_char *next; 00325 int num_ingred = 1; 00326 00327 LOG(llevInfo, "\n"); 00328 00329 while (fl) 00330 { 00331 LOG(llevInfo, "\n Formulae with %d ingredient%s %d Formulae with total_chance=%d\n", num_ingred, num_ingred > 1 ? "s." : ".", fl->number, fl->total_chance); 00332 00333 for (formula = fl->items; formula != NULL; formula = formula->next) 00334 { 00335 artifact *art = NULL; 00336 char buf[MAX_BUF], tmpbuf[MAX_BUF], *string; 00337 00338 strncpy(tmpbuf, formula->arch_name, MAX_BUF - 1); 00339 tmpbuf[MAX_BUF - 1] = 0; 00340 string = strtok(tmpbuf, ","); 00341 00342 while (string) 00343 { 00344 if (find_archetype(string) != NULL) 00345 { 00346 art = locate_recipe_artifact(formula); 00347 00348 if (!art && formula->title != shstr_cons.NONE) 00349 { 00350 LOG(llevBug, "Formula %s has no artifact\n", formula->title); 00351 } 00352 else 00353 { 00354 if (formula->title != shstr_cons.NONE) 00355 { 00356 snprintf(buf, sizeof(buf), "%s of %s", string, formula->title); 00357 } 00358 else 00359 { 00360 snprintf(buf, sizeof(buf), "%s", string); 00361 } 00362 00363 LOG(llevInfo, "%-30s(%d) bookchance %3d ", buf, formula->index, formula->chance); 00364 LOG(llevInfo, "\n"); 00365 00366 if (formula->ingred != NULL) 00367 { 00368 int nval = 0, tval = 0; 00369 LOG(llevInfo, "\tIngred: "); 00370 00371 for (next = formula->ingred; next != NULL; next = next->next) 00372 { 00373 if (nval != 0) 00374 { 00375 LOG(llevInfo, ","); 00376 } 00377 00378 LOG(llevInfo, "%s(%d)", next->name, (nval = strtoint(next->name))); 00379 tval += nval; 00380 } 00381 00382 LOG(llevInfo, "\n"); 00383 00384 if (tval != formula->index) 00385 { 00386 LOG(llevInfo, "ingredient list and formula values not equal.\n"); 00387 } 00388 } 00389 } 00390 } 00391 else 00392 { 00393 LOG(llevBug, "Can't find archetype:%s for formula %s\n", string, formula->title); 00394 } 00395 00396 string = strtok(NULL, ","); 00397 } 00398 } 00399 00400 LOG(llevInfo, "\n"); 00401 fl = fl->next; 00402 num_ingred++; 00403 } 00404 } 00405 00414 static archetype *find_treasure_by_name(treasure *t, char *name, int depth) 00415 { 00416 treasurelist *tl; 00417 archetype *at; 00418 00419 if (depth > 10) 00420 { 00421 return NULL; 00422 } 00423 00424 while (t != NULL) 00425 { 00426 if (t->name != NULL) 00427 { 00428 tl = find_treasurelist(t->name); 00429 at = find_treasure_by_name(tl->items, name, depth + 1); 00430 00431 if (at != NULL) 00432 { 00433 return at; 00434 } 00435 } 00436 else 00437 { 00438 if (!strcasecmp(t->item->clone.name, name)) 00439 { 00440 return t->item; 00441 } 00442 } 00443 00444 if (t->next_yes != NULL) 00445 { 00446 at = find_treasure_by_name(t->next_yes, name, depth); 00447 00448 if (at != NULL) 00449 { 00450 return at; 00451 } 00452 } 00453 00454 if (t->next_no != NULL) 00455 { 00456 at = find_treasure_by_name(t->next_no, name, depth); 00457 00458 if (at != NULL) 00459 { 00460 return at; 00461 } 00462 } 00463 00464 t = t->next; 00465 } 00466 00467 return NULL; 00468 } 00469 00484 static long find_ingred_cost(const char *name) 00485 { 00486 archetype *at, *at2; 00487 artifactlist *al; 00488 artifact *art; 00489 long mult; 00490 char *cp; 00491 char part1[100], part2[100]; 00492 00493 /* Same as atoi(), but skip number */ 00494 mult = 0; 00495 00496 while (isdigit(*name)) 00497 { 00498 mult = 10 * mult + (*name - '0'); 00499 name++; 00500 } 00501 00502 if (mult > 0) 00503 { 00504 name++; 00505 } 00506 else 00507 { 00508 mult = 1; 00509 } 00510 00511 /* First, try to match the name of an archetype */ 00512 for (at = first_archetype; at != NULL; at = at->next) 00513 { 00514 if (at->clone.title != NULL) 00515 { 00516 /* Inefficient, but who cares? */ 00517 snprintf(part1, sizeof(part1), "%s %s", at->clone.name, at->clone.title); 00518 00519 if (!strcasecmp(part1, name)) 00520 { 00521 return mult * at->clone.value; 00522 } 00523 } 00524 00525 if (!strcasecmp(at->clone.name, name)) 00526 { 00527 return mult * at->clone.value; 00528 } 00529 } 00530 00531 /* Second, try to match an artifact ("arch of something") */ 00532 cp = strstr(name, " of "); 00533 00534 if (cp != NULL) 00535 { 00536 strcpy(part1, name); 00537 part1[cp - name] = '\0'; 00538 strcpy(part2, cp + 4); 00539 00540 /* Find the first archetype matching the first part of the name */ 00541 for (at = first_archetype; at != NULL; at = at->next) 00542 { 00543 if (!strcasecmp(at->clone.name, part1) && at->clone.title == NULL) 00544 { 00545 break; 00546 } 00547 } 00548 00549 if (at != NULL) 00550 { 00551 /* Find the first artifact derived from that archetype (same type) */ 00552 for (al = first_artifactlist; al != NULL; al = al->next) 00553 { 00554 if (al->type == at->clone.type) 00555 { 00556 for (art = al->items; art != NULL; art = art->next) 00557 { 00558 if (!strcasecmp(art->def_at.clone.name, part2)) 00559 { 00560 return mult * at->clone.value * art->def_at.clone.value; 00561 } 00562 } 00563 } 00564 } 00565 } 00566 } 00567 00568 /* Third, try to match a body part ("arch's something") */ 00569 cp = strstr(name, "'s "); 00570 00571 if (cp != NULL) 00572 { 00573 strcpy(part1, name); 00574 part1[cp - name] = '\0'; 00575 strcpy(part2, cp + 3); 00576 00577 /* Examine all archetypes matching the first part of the name */ 00578 for (at = first_archetype; at != NULL; at = at->next) 00579 { 00580 if (!strcasecmp (at->clone.name, part1) && at->clone.title == NULL) 00581 { 00582 if (at->clone.randomitems != NULL) 00583 { 00584 at2 = find_treasure_by_name(at->clone.randomitems->items, part2, 0); 00585 00586 if (at2 != NULL) 00587 { 00588 return mult * at2->clone.value * isqrt(at->clone.level * 2); 00589 } 00590 } 00591 } 00592 } 00593 } 00594 00595 /* Failed to find any matching items -- formula should be checked */ 00596 return -1; 00597 } 00598 00601 void dump_alchemy_costs() 00602 { 00603 recipelist *fl = formulalist; 00604 recipe *formula = NULL; 00605 linked_char *next; 00606 int num_ingred = 1, num_errors = 0; 00607 long cost, tcost; 00608 00609 LOG(llevInfo, "\n"); 00610 00611 while (fl) 00612 { 00613 LOG(llevInfo, "\n Formulae with %d ingredient%s %d Formulae with total_chance=%d\n", num_ingred, num_ingred > 1 ? "s." : ".", fl->number, fl->total_chance); 00614 00615 for (formula = fl->items; formula != NULL; formula = formula->next) 00616 { 00617 artifact *art = NULL; 00618 archetype *at = NULL; 00619 char buf[MAX_BUF], tmpbuf[MAX_BUF], *string; 00620 00621 strncpy(tmpbuf, formula->arch_name, MAX_BUF - 1); 00622 tmpbuf[MAX_BUF - 1] = '\0'; 00623 string = strtok(tmpbuf, ","); 00624 00625 while (string) 00626 { 00627 if ((at = find_archetype(string)) != NULL) 00628 { 00629 art = locate_recipe_artifact(formula); 00630 00631 if (!art && formula->title != shstr_cons.NONE) 00632 { 00633 LOG(llevBug, "Formula %s has no artifact\n", formula->title); 00634 } 00635 else 00636 { 00637 if (formula->title == shstr_cons.NONE) 00638 { 00639 snprintf(buf, sizeof(buf), "%s", string); 00640 } 00641 else 00642 { 00643 snprintf(buf, sizeof(buf), "%s of %s", string, formula->title); 00644 } 00645 00646 LOG(llevInfo, "\n%-40s bookchance %3d\n", buf, formula->chance); 00647 00648 if (formula->ingred != NULL) 00649 { 00650 tcost = 0; 00651 00652 for (next = formula->ingred; next != NULL; next = next->next) 00653 { 00654 cost = find_ingred_cost(next->name); 00655 00656 if (cost < 0) 00657 { 00658 num_errors++; 00659 } 00660 00661 LOG(llevInfo, "\t%-33s%5ld\n", next->name, cost); 00662 00663 if (cost < 0 || tcost < 0) 00664 { 00665 tcost = -1; 00666 } 00667 else 00668 { 00669 tcost += cost; 00670 } 00671 } 00672 00673 if (art != NULL && &art->def_at.clone != NULL) 00674 { 00675 cost = at->clone.value * art->def_at.clone.value; 00676 } 00677 else 00678 { 00679 cost = at->clone.value; 00680 } 00681 00682 LOG(llevInfo, "\t\tBuying result costs: %5ld", cost); 00683 00684 if (formula->yield > 1) 00685 { 00686 LOG(llevInfo, " to %ld (max %d items)\n", cost * formula->yield, formula->yield); 00687 cost = cost * (formula->yield + 1L) / 2L; 00688 } 00689 else 00690 { 00691 LOG(llevInfo, "\n"); 00692 } 00693 00694 LOG(llevInfo, "\t\tIngredients cost: %5ld\n\t\tComment: ", tcost); 00695 00696 if (tcost < 0) 00697 { 00698 LOG(llevInfo, "Could not find some ingredients. Check the formula!\n"); 00699 } 00700 else if (tcost > cost) 00701 { 00702 LOG(llevInfo, "Ingredients are much expensive. Useless formula.\n"); 00703 } 00704 else if (tcost * 2L > cost) 00705 { 00706 LOG(llevInfo, "Ingredients are too expensive.\n"); 00707 } 00708 else if (tcost * 10L < cost) 00709 { 00710 LOG(llevInfo, "Ingredients are too cheap.\n"); 00711 } 00712 else 00713 { 00714 LOG(llevInfo, "OK.\n"); 00715 } 00716 } 00717 } 00718 } 00719 else 00720 { 00721 LOG(llevBug, "Can't find archetype:%s for formula %s\n", string, formula->title); 00722 } 00723 00724 string = strtok(NULL, ","); 00725 } 00726 } 00727 00728 LOG(llevInfo, "\n"); 00729 fl = fl->next; 00730 num_ingred++; 00731 } 00732 00733 if (num_errors > 0) 00734 { 00735 LOG(llevInfo, "%d objects required by the formulae do not exist in the game.\n", num_errors); 00736 } 00737 } 00738 00744 static const char *ingred_name(const char *name) 00745 { 00746 const char *cp = name; 00747 00748 if (atoi(cp)) 00749 { 00750 cp = strchr(cp, ' ') + 1; 00751 } 00752 00753 return cp; 00754 } 00755 00763 int strtoint(const char *buf) 00764 { 00765 const char *cp = ingred_name(buf); 00766 int val = 0, mult = numb_ingred(buf); 00767 size_t len = strlen(cp); 00768 00769 while (len) 00770 { 00771 val += tolower(*cp); 00772 cp++; 00773 len--; 00774 } 00775 00776 return val * mult; 00777 } 00778 00783 artifact *locate_recipe_artifact(recipe *rp) 00784 { 00785 object *item = get_archetype(rp->arch_name); 00786 artifactlist *at = NULL; 00787 artifact *art = NULL; 00788 00789 if (!item) 00790 { 00791 return NULL; 00792 } 00793 00794 if ((at = find_artifactlist(item->type))) 00795 { 00796 for (art = at->items; art; art = art->next) 00797 { 00798 if (!strcmp(art->def_at.clone.name, rp->title)) 00799 { 00800 break; 00801 } 00802 } 00803 } 00804 00805 return art; 00806 } 00807 00812 static int numb_ingred(const char *buf) 00813 { 00814 int numb; 00815 00816 if ((numb = atoi(buf))) 00817 { 00818 return numb; 00819 } 00820 00821 return 1; 00822 } 00823 00827 static recipelist *get_random_recipelist() 00828 { 00829 recipelist *fl = NULL; 00830 int number = 0, roll = 0; 00831 00832 /* First, determine # of recipelist we have */ 00833 for (fl = get_formulalist(1); fl; fl = fl->next) 00834 { 00835 number++; 00836 } 00837 00838 /* Now, randomly choose one */ 00839 if (number > 0) 00840 { 00841 roll = RANDOM() % number; 00842 } 00843 00844 fl = get_formulalist(1); 00845 00846 while (roll && fl) 00847 { 00848 if (fl->next) 00849 { 00850 fl = fl->next; 00851 } 00852 else 00853 { 00854 break; 00855 } 00856 00857 roll--; 00858 } 00859 00860 /* Failed! */ 00861 if (!fl) 00862 { 00863 LOG(llevBug, "get_random_recipelist(): no recipelists found!\n"); 00864 } 00865 else if (fl->total_chance == 0) 00866 { 00867 fl = get_random_recipelist(); 00868 } 00869 00870 return fl; 00871 } 00872 00879 recipe *get_random_recipe(recipelist *rpl) 00880 { 00881 recipelist *fl = rpl; 00882 recipe *rp = NULL; 00883 int r = 0; 00884 00885 /* Looks like we have to choose a random one */ 00886 if (fl == NULL) 00887 { 00888 if ((fl = get_random_recipelist()) == NULL) 00889 { 00890 return rp; 00891 } 00892 } 00893 00894 if (fl->total_chance > 0) 00895 { 00896 r = RANDOM() % fl->total_chance; 00897 00898 for (rp = fl->items; rp; rp = rp->next) 00899 { 00900 r -= rp->chance; 00901 00902 if (r < 0) 00903 { 00904 break; 00905 } 00906 } 00907 } 00908 00909 return rp; 00910 } 00911 00914 void free_all_recipes() 00915 { 00916 recipelist *fl = formulalist, *flnext; 00917 recipe *formula = NULL, *next; 00918 linked_char *lchar, *charnext; 00919 00920 LOG(llevDebug, "Freeing all the recipes\n"); 00921 00922 for (fl = formulalist; fl != NULL; fl = flnext) 00923 { 00924 flnext = fl->next; 00925 00926 for (formula = fl->items; formula != NULL; formula = next) 00927 { 00928 next = formula->next; 00929 00930 FREE_AND_CLEAR_HASH2(formula->arch_name); 00931 FREE_AND_CLEAR_HASH2(formula->title); 00932 00933 for (lchar = formula->ingred; lchar; lchar = charnext) 00934 { 00935 charnext = lchar->next; 00936 FREE_AND_CLEAR_HASH2(lchar->name); 00937 free(lchar); 00938 } 00939 00940 free(formula); 00941 } 00942 00943 free(fl); 00944 } 00945 }
1.7.4