Crossfire Server, Branch 1.12
R12190
|
00001 00002 /* 00003 * static char *rcs_treasure_c = 00004 * "$Id: treasure.c 13896 2010-09-26 13:57:17Z ryo_saeba $"; 00005 */ 00006 00007 /* 00008 CrossFire, A Multiplayer game for X-windows 00009 00010 Copyright (C) 2002-2006 Mark Wedel & Crossfire Development Team 00011 Copyright (C) 1992 Frank Tore Johansen 00012 00013 This program is free software; you can redistribute it and/or modify 00014 it under the terms of the GNU General Public License as published by 00015 the Free Software Foundation; either version 2 of the License, or 00016 (at your option) any later version. 00017 00018 This program is distributed in the hope that it will be useful, 00019 but WITHOUT ANY WARRANTY; without even the implied warranty of 00020 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00021 GNU General Public License for more details. 00022 00023 You should have received a copy of the GNU General Public License 00024 along with this program; if not, write to the Free Software 00025 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00026 00027 The authors can be reached via e-mail at crossfire-devel@real-time.com 00028 */ 00029 00036 #define ALLOWED_COMBINATION 00037 00044 #define TREASURE_DEBUG 00045 00046 /* TREASURE_VERBOSE enables copious output concerning artifact generation */ 00047 /* #define TREASURE_VERBOSE */ 00048 00049 #include <stdlib.h> 00050 #include <global.h> 00051 #include <treasure.h> 00052 #include <loader.h> 00053 #include <sproto.h> 00054 00055 00056 static void change_treasure(treasure *t, object *op); /* overrule default values */ 00057 static int special_potion(object *op); 00058 static void fix_flesh_item(object *item, object *donor); 00059 00060 extern const char *const spell_mapping[]; 00061 int artifact_init; 00066 void init_archetype_pointers(void) { 00067 int prev_warn = warn_archetypes; 00068 00069 warn_archetypes = 1; 00070 if (ring_arch == NULL) 00071 ring_arch = find_archetype("ring"); 00072 if (amulet_arch == NULL) 00073 amulet_arch = find_archetype("amulet"); 00074 if (staff_arch == NULL) 00075 staff_arch = find_archetype("staff"); 00076 if (crown_arch == NULL) 00077 crown_arch = find_archetype("crown"); 00078 warn_archetypes = prev_warn; 00079 } 00080 00091 static treasurelist *get_empty_treasurelist(void) { 00092 treasurelist *tl = (treasurelist *)malloc(sizeof(treasurelist)); 00093 if (tl == NULL) 00094 fatal(OUT_OF_MEMORY); 00095 memset(tl, 0, sizeof(treasurelist)); 00096 return tl; 00097 } 00098 00109 static treasure *get_empty_treasure(void) { 00110 treasure *t = (treasure *)calloc(1, sizeof(treasure)); 00111 if (t == NULL) 00112 fatal(OUT_OF_MEMORY); 00113 t->item = NULL; 00114 t->name = NULL; 00115 t->next = NULL; 00116 t->next_yes = NULL; 00117 t->next_no = NULL; 00118 t->chance = 100; 00119 t->magic = 0; 00120 t->nrof = 0; 00121 return t; 00122 } 00123 00138 static treasure *load_treasure(FILE *fp, int *line) { 00139 char buf[MAX_BUF], *cp, variable[MAX_BUF]; 00140 treasure *t = get_empty_treasure(); 00141 int value; 00142 00143 nroftreasures++; 00144 while (fgets(buf, MAX_BUF, fp) != NULL) { 00145 (*line)++; 00146 00147 if (*buf == '#') 00148 continue; 00149 if ((cp = strchr(buf, '\n')) != NULL) 00150 *cp = '\0'; 00151 cp = buf; 00152 while (isspace(*cp)) /* Skip blanks */ 00153 cp++; 00154 00155 if (sscanf(cp, "arch %s", variable)) { 00156 if ((t->item = find_archetype(variable)) == NULL) 00157 LOG(llevError, "Treasure lacks archetype: %s\n", variable); 00158 } else if (sscanf(cp, "list %s", variable)) 00159 t->name = add_string(variable); 00160 else if (sscanf(cp, "change_name %s", variable)) 00161 t->change_arch.name = add_string(variable); 00162 else if (sscanf(cp, "change_title %s", variable)) 00163 t->change_arch.title = add_string(variable); 00164 else if (sscanf(cp, "change_slaying %s", variable)) 00165 t->change_arch.slaying = add_string(variable); 00166 else if (sscanf(cp, "chance %d", &value)) 00167 t->chance = (uint8)value; 00168 else if (sscanf(cp, "nrof %d", &value)) 00169 t->nrof = (uint16)value; 00170 else if (sscanf(cp, "magic %d", &value)) 00171 t->magic = (uint8)value; 00172 else if (!strcmp(cp, "yes")) 00173 t->next_yes = load_treasure(fp, line); 00174 else if (!strcmp(cp, "no")) 00175 t->next_no = load_treasure(fp, line); 00176 else if (!strcmp(cp, "end")) 00177 return t; 00178 else if (!strcmp(cp, "more")) { 00179 t->next = load_treasure(fp, line); 00180 return t; 00181 } else 00182 LOG(llevError, "Unknown treasure-command: '%s', last entry %s, line %d\n", cp, t->name ? t->name : "null", *line); 00183 } 00184 LOG(llevError, "treasure lacks 'end'.\n"); 00185 return t; 00186 } 00187 00188 #ifdef TREASURE_DEBUG 00189 00200 static void check_treasurelist(const treasure *t, const treasurelist *tl) { 00201 if (t->item == NULL && t->name == NULL) 00202 LOG(llevError, "Treasurelist %s has element with no name or archetype\n", tl->name); 00203 if (t->chance >= 100 && t->next_yes && (t->next || t->next_no)) 00204 LOG(llevError, "Treasurelist %s has element that has 100%% generation, next_yes field as well as next or next_no\n", tl->name); 00205 /* find_treasurelist will print out its own error message */ 00206 if (t->name && strcmp(t->name, "NONE")) 00207 find_treasurelist(t->name); 00208 if (t->next) 00209 check_treasurelist(t->next, tl); 00210 if (t->next_yes) 00211 check_treasurelist(t->next_yes, tl); 00212 if (t->next_no) 00213 check_treasurelist(t->next_no, tl); 00214 } 00215 #endif 00216 00224 void load_treasures(void) { 00225 FILE *fp; 00226 char filename[MAX_BUF], buf[MAX_BUF], name[MAX_BUF]; 00227 treasurelist *previous = NULL; 00228 treasure *t; 00229 int comp, line = 0; 00230 00231 snprintf(filename, sizeof(filename), "%s/%s", settings.datadir, settings.treasures); 00232 if ((fp = open_and_uncompress(filename, 0, &comp)) == NULL) { 00233 LOG(llevError, "Can't open treasure file.\n"); 00234 return; 00235 } 00236 while (fgets(buf, MAX_BUF, fp) != NULL) { 00237 line++; 00238 if (*buf == '#') 00239 continue; 00240 00241 if (sscanf(buf, "treasureone %s\n", name) || sscanf(buf, "treasure %s\n", name)) { 00242 treasurelist *tl = get_empty_treasurelist(); 00243 00244 tl->name = add_string(name); 00245 if (previous == NULL) 00246 first_treasurelist = tl; 00247 else 00248 previous->next = tl; 00249 previous = tl; 00250 tl->items = load_treasure(fp, &line); 00251 00252 /* This is a one of the many items on the list should be generated. 00253 * Add up the chance total, and check to make sure the yes & no 00254 * fields of the treasures are not being used. 00255 */ 00256 if (!strncmp(buf, "treasureone", 11)) { 00257 for (t = tl->items; t != NULL; t = t->next) { 00258 #ifdef TREASURE_DEBUG 00259 if (t->next_yes || t->next_no) { 00260 LOG(llevError, "Treasure %s is one item, but on treasure %s\n", tl->name, t->item ? t->item->name : t->name); 00261 LOG(llevError, " the next_yes or next_no field is set\n"); 00262 } 00263 #endif 00264 tl->total_chance += t->chance; 00265 } 00266 } 00267 } else 00268 LOG(llevError, "Treasure-list didn't understand: %s, line %d\n", buf, line); 00269 } 00270 close_and_delete(fp, comp); 00271 00272 #ifdef TREASURE_DEBUG 00273 /* Perform some checks on how valid the treasure data actually is. 00274 * verify that list transitions work (ie, the list that it is supposed 00275 * to transition to exists). Also, verify that at least the name 00276 * or archetype is set for each treasure element. 00277 */ 00278 for (previous = first_treasurelist; previous != NULL; previous = previous->next) 00279 check_treasurelist(previous->items, previous); 00280 #endif 00281 } 00282 00295 treasurelist *find_treasurelist(const char *name) { 00296 const char *tmp = find_string(name); 00297 treasurelist *tl; 00298 00299 /* Special cases - randomitems of none is to override default. If 00300 * first_treasurelist is null, it means we are on the first pass of 00301 * of loading archetyps, so for now, just return - second pass will 00302 * init these values. 00303 */ 00304 if (!strcmp(name, "none") || (!first_treasurelist)) 00305 return NULL; 00306 if (tmp != NULL) 00307 for (tl = first_treasurelist; tl != NULL; tl = tl->next) 00308 if (tmp == tl->name) 00309 return tl; 00310 LOG(llevError, "Couldn't find treasurelist %s\n", name); 00311 return NULL; 00312 } 00313 00314 00326 static void put_treasure(object *op, object *creator, int flags) { 00327 /* Bit of a hack - spells should never be put onto the map. The entire 00328 * treasure stuff is a problem - there is no clear idea of knowing 00329 * this is the original object, or if this is an object that should be created 00330 * by another object. 00331 */ 00332 if (flags>_ENVIRONMENT && op->type != SPELL) { 00333 op->x = creator->x; 00334 op->y = creator->y; 00335 SET_FLAG(op, FLAG_OBJ_ORIGINAL); 00336 insert_ob_in_map(op, creator->map, op, INS_NO_MERGE|INS_NO_WALK_ON); 00337 } else { 00338 op = insert_ob_in_ob(op, creator); 00339 if ((flags>_APPLY) && QUERY_FLAG(creator, FLAG_MONSTER)) 00340 monster_check_apply(creator, op); 00341 } 00342 } 00343 00354 static void change_treasure(treasure *t, object *op) { 00355 /* CMD: change_name xxxx */ 00356 if (t->change_arch.name) { 00357 FREE_AND_COPY(op->name, t->change_arch.name); 00358 /* not great, but better than something that is completely wrong */ 00359 FREE_AND_COPY(op->name_pl, t->change_arch.name); 00360 } 00361 00362 if (t->change_arch.title) { 00363 if (op->title) 00364 free_string(op->title); 00365 op->title = add_string(t->change_arch.title); 00366 } 00367 00368 if (t->change_arch.slaying) { 00369 if (op->slaying) 00370 free_string(op->slaying); 00371 op->slaying = add_string(t->change_arch.slaying); 00372 } 00373 } 00374 00390 static void create_all_treasures(treasure *t, object *op, int flag, int difficulty, int tries) { 00391 object *tmp; 00392 00393 00394 if ((int)t->chance >= 100 || (RANDOM()%100+1) < (int)t->chance) { 00395 if (t->name) { 00396 if (strcmp(t->name, "NONE") && difficulty >= t->magic) 00397 create_treasure(find_treasurelist(t->name), op, flag, difficulty, tries); 00398 } else { 00399 if (t->item->clone.invisible != 0 || !(flag>_INVISIBLE)) { 00400 tmp = arch_to_object(t->item); 00401 if (t->nrof && tmp->nrof <= 1) 00402 tmp->nrof = RANDOM()%((int)t->nrof)+1; 00403 fix_generated_item(tmp, op, difficulty, t->magic, flag); 00404 change_treasure(t, tmp); 00405 put_treasure(tmp, op, flag); 00406 } 00407 } 00408 if (t->next_yes != NULL) 00409 create_all_treasures(t->next_yes, op, flag, difficulty, tries); 00410 } else 00411 if (t->next_no != NULL) 00412 create_all_treasures(t->next_no, op, flag, difficulty, tries); 00413 if (t->next != NULL) 00414 create_all_treasures(t->next, op, flag, difficulty, tries); 00415 } 00416 00435 static void create_one_treasure(treasurelist *tl, object *op, int flag, int difficulty, int tries) { 00436 int value = RANDOM()%tl->total_chance; 00437 treasure *t; 00438 00439 if (tries++ > 100) { 00440 LOG(llevDebug, "create_one_treasure: tries exceeded 100, returning without making treasure\n"); 00441 return; 00442 } 00443 00444 for (t = tl->items; t != NULL; t = t->next) { 00445 value -= t->chance; 00446 if (value < 0) 00447 break; 00448 } 00449 00450 if (!t || value >= 0) { 00451 LOG(llevError, "create_one_treasure: got null object or not able to find treasure\n"); 00452 abort(); 00453 return; 00454 } 00455 if (t->name) { 00456 if (!strcmp(t->name, "NONE")) 00457 return; 00458 if (difficulty >= t->magic) 00459 create_treasure(find_treasurelist(t->name), op, flag, difficulty, tries); 00460 else if (t->nrof) 00461 create_one_treasure(tl, op, flag, difficulty, tries); 00462 return; 00463 } 00464 if ((t->item) && (flag>_ONLY_GOOD)) { /* Generate only good items, damnit !*/ 00465 if (QUERY_FLAG(&(t->item->clone), FLAG_CURSED) 00466 || QUERY_FLAG(&(t->item->clone), FLAG_DAMNED)) { 00467 create_one_treasure(tl, op, flag, difficulty, tries+1); 00468 return; 00469 } 00470 } 00471 if ((t->item && t->item->clone.invisible != 0) || flag != GT_INVISIBLE) { 00472 object *tmp = arch_to_object(t->item); 00473 00474 if (!tmp) 00475 return; 00476 if (t->nrof && tmp->nrof <= 1) 00477 tmp->nrof = RANDOM()%((int)t->nrof)+1; 00478 fix_generated_item(tmp, op, difficulty, t->magic, flag); 00479 change_treasure(t, tmp); 00480 put_treasure(tmp, op, flag); 00481 } 00482 } 00483 00499 void create_treasure(treasurelist *t, object *op, int flag, int difficulty, int tries) { 00500 if (tries++ > 100) { 00501 LOG(llevDebug, "createtreasure: tries exceeded 100, returning without making treasure\n"); 00502 return; 00503 } 00504 if (t->total_chance) 00505 create_one_treasure(t, op, flag, difficulty, tries); 00506 else 00507 create_all_treasures(t->items, op, flag, difficulty, tries); 00508 } 00509 00524 object *generate_treasure(treasurelist *t, int difficulty) { 00525 object *ob = get_object(), *tmp; 00526 00527 create_treasure(t, ob, 0, difficulty, 0); 00528 00529 /* Don't want to free the object we are about to return */ 00530 tmp = ob->inv; 00531 if (tmp != NULL) 00532 remove_ob(tmp); 00533 if (ob->inv) { 00534 LOG(llevError, "In generate treasure, created multiple objects.\n"); 00535 } 00536 free_object(ob); 00537 return tmp; 00538 } 00539 00554 static int level_for_item(const object *op, int difficulty, int retmult) { 00555 int level, mult, olevel; 00556 00557 mult = 0; 00558 if (!op->inv) { 00559 LOG(llevError, "level_for_item: Object %s has no inventory!\n", op->name); 00560 return 0; 00561 } 00562 level = op->inv->level; 00563 00564 /* Basically, we set mult to the lowest spell increase attribute that is 00565 * not zero - zero's mean no modification is done, so we don't want those. 00566 * given we want non zero results, we can't just use a few MIN's here. 00567 */ 00568 mult = op->inv->dam_modifier; 00569 if (op->inv->range_modifier && (op->inv->range_modifier < mult || mult == 0)) 00570 mult = op->inv->range_modifier; 00571 if (op->inv->duration_modifier && (op->inv->duration_modifier < mult || mult == 0)) 00572 mult = op->inv->duration_modifier; 00573 00574 if (mult == 0) 00575 mult = 5; 00576 00577 if (retmult) 00578 return mult; 00579 00580 olevel = mult*rndm(0, difficulty)+level; 00581 if (olevel > MAX_SPELLITEM_LEVEL) 00582 olevel = MAX_SPELLITEM_LEVEL; 00583 00584 return olevel; 00585 } 00586 00594 static const int difftomagic_list[DIFFLEVELS][MAXMAGIC+1] = { 00595 /*chance of magic difficulty*/ 00596 /* +0 +1 +2 +3 +4 */ 00597 { 94, 3, 2, 1, 0 }, /*1*/ 00598 { 94, 3, 2, 1, 0 }, /*2*/ 00599 { 94, 3, 2, 1, 0 }, /*3*/ 00600 { 94, 3, 2, 1, 0 }, /*4*/ 00601 { 94, 3, 2, 1, 0 }, /*5*/ 00602 { 90, 4, 3, 2, 1 }, /*6*/ 00603 { 90, 4, 3, 2, 1 }, /*7*/ 00604 { 90, 4, 3, 2, 1 }, /*8*/ 00605 { 90, 4, 3, 2, 1 }, /*9*/ 00606 { 90, 4, 3, 2, 1 }, /*10*/ 00607 { 85, 6, 4, 3, 2 }, /*11*/ 00608 { 85, 6, 4, 3, 2 }, /*12*/ 00609 { 85, 6, 4, 3, 2 }, /*13*/ 00610 { 85, 6, 4, 3, 2 }, /*14*/ 00611 { 85, 6, 4, 3, 2 }, /*15*/ 00612 { 81, 8, 5, 4, 3 }, /*16*/ 00613 { 81, 8, 5, 4, 3 }, /*17*/ 00614 { 81, 8, 5, 4, 3 }, /*18*/ 00615 { 81, 8, 5, 4, 3 }, /*19*/ 00616 { 81, 8, 5, 4, 3 }, /*20*/ 00617 { 75, 10, 6, 5, 4 }, /*21*/ 00618 { 75, 10, 6, 5, 4 }, /*22*/ 00619 { 75, 10, 6, 5, 4 }, /*23*/ 00620 { 75, 10, 6, 5, 4 }, /*24*/ 00621 { 75, 10, 6, 5, 4 }, /*25*/ 00622 { 70, 12, 7, 6, 5 }, /*26*/ 00623 { 70, 12, 7, 6, 5 }, /*27*/ 00624 { 70, 12, 7, 6, 5 }, /*28*/ 00625 { 70, 12, 7, 6, 5 }, /*29*/ 00626 { 70, 12, 7, 6, 5 }, /*30*/ 00627 { 70, 9, 8, 7, 6 }, /*31*/ 00628 { 70, 9, 8, 7, 6 }, /*32*/ 00629 { 70, 9, 8, 7, 6 }, /*33*/ 00630 { 70, 9, 8, 7, 6 }, /*34*/ 00631 { 70, 9, 8, 7, 6 }, /*35*/ 00632 { 70, 6, 9, 8, 7 }, /*36*/ 00633 { 70, 6, 9, 8, 7 }, /*37*/ 00634 { 70, 6, 9, 8, 7 }, /*38*/ 00635 { 70, 6, 9, 8, 7 }, /*39*/ 00636 { 70, 6, 9, 8, 7 }, /*40*/ 00637 { 70, 3, 10, 9, 8 }, /*41*/ 00638 { 70, 3, 10, 9, 8 }, /*42*/ 00639 { 70, 3, 10, 9, 8 }, /*43*/ 00640 { 70, 3, 10, 9, 8 }, /*44*/ 00641 { 70, 3, 10, 9, 8 }, /*45*/ 00642 { 70, 2, 9, 10, 9 }, /*46*/ 00643 { 70, 2, 9, 10, 9 }, /*47*/ 00644 { 70, 2, 9, 10, 9 }, /*48*/ 00645 { 70, 2, 9, 10, 9 }, /*49*/ 00646 { 70, 2, 9, 10, 9 }, /*50*/ 00647 { 70, 2, 7, 11, 10 }, /*51*/ 00648 { 70, 2, 7, 11, 10 }, /*52*/ 00649 { 70, 2, 7, 11, 10 }, /*53*/ 00650 { 70, 2, 7, 11, 10 }, /*54*/ 00651 { 70, 2, 7, 11, 10 }, /*55*/ 00652 { 70, 2, 5, 12, 11 }, /*56*/ 00653 { 70, 2, 5, 12, 11 }, /*57*/ 00654 { 70, 2, 5, 12, 11 }, /*58*/ 00655 { 70, 2, 5, 12, 11 }, /*59*/ 00656 { 70, 2, 5, 12, 11 }, /*60*/ 00657 { 70, 2, 3, 13, 12 }, /*61*/ 00658 { 70, 2, 3, 13, 12 }, /*62*/ 00659 { 70, 2, 3, 13, 12 }, /*63*/ 00660 { 70, 2, 3, 13, 12 }, /*64*/ 00661 { 70, 2, 3, 13, 12 }, /*65*/ 00662 { 70, 2, 3, 12, 13 }, /*66*/ 00663 { 70, 2, 3, 12, 13 }, /*67*/ 00664 { 70, 2, 3, 12, 13 }, /*68*/ 00665 { 70, 2, 3, 12, 13 }, /*69*/ 00666 { 70, 2, 3, 12, 13 }, /*70*/ 00667 { 70, 2, 3, 11, 14 }, /*71*/ 00668 { 70, 2, 3, 11, 14 }, /*72*/ 00669 { 70, 2, 3, 11, 14 }, /*73*/ 00670 { 70, 2, 3, 11, 14 }, /*74*/ 00671 { 70, 2, 3, 11, 14 }, /*75*/ 00672 { 70, 2, 3, 10, 15 }, /*76*/ 00673 { 70, 2, 3, 10, 15 }, /*77*/ 00674 { 70, 2, 3, 10, 15 }, /*78*/ 00675 { 70, 2, 3, 10, 15 }, /*79*/ 00676 { 70, 2, 3, 10, 15 }, /*80*/ 00677 { 70, 2, 3, 9, 16 }, /*81*/ 00678 { 70, 2, 3, 9, 16 }, /*82*/ 00679 { 70, 2, 3, 9, 16 }, /*83*/ 00680 { 70, 2, 3, 9, 16 }, /*84*/ 00681 { 70, 2, 3, 9, 16 }, /*85*/ 00682 { 70, 2, 3, 8, 17 }, /*86*/ 00683 { 70, 2, 3, 8, 17 }, /*87*/ 00684 { 70, 2, 3, 8, 17 }, /*88*/ 00685 { 70, 2, 3, 8, 17 }, /*89*/ 00686 { 70, 2, 3, 8, 17 }, /*90*/ 00687 { 70, 2, 3, 7, 18 }, /*91*/ 00688 { 70, 2, 3, 7, 18 }, /*92*/ 00689 { 70, 2, 3, 7, 18 }, /*93*/ 00690 { 70, 2, 3, 7, 18 }, /*94*/ 00691 { 70, 2, 3, 7, 18 }, /*95*/ 00692 { 70, 2, 3, 6, 19 }, /*96*/ 00693 { 70, 2, 3, 6, 19 }, /*97*/ 00694 { 70, 2, 3, 6, 19 }, /*98*/ 00695 { 70, 2, 3, 6, 19 }, /*99*/ 00696 { 70, 2, 3, 6, 19 }, /*100*/ 00697 { 70, 2, 3, 6, 19 }, /*101*/ 00698 { 70, 2, 3, 6, 19 }, /*101*/ 00699 { 70, 2, 3, 6, 19 }, /*102*/ 00700 { 70, 2, 3, 6, 19 }, /*103*/ 00701 { 70, 2, 3, 6, 19 }, /*104*/ 00702 { 70, 2, 3, 6, 19 }, /*105*/ 00703 { 70, 2, 3, 6, 19 }, /*106*/ 00704 { 70, 2, 3, 6, 19 }, /*107*/ 00705 { 70, 2, 3, 6, 19 }, /*108*/ 00706 { 70, 2, 3, 6, 19 }, /*109*/ 00707 { 70, 2, 3, 6, 19 }, /*110*/ 00708 { 70, 2, 3, 6, 19 }, /*111*/ 00709 { 70, 2, 3, 6, 19 }, /*112*/ 00710 { 70, 2, 3, 6, 19 }, /*113*/ 00711 { 70, 2, 3, 6, 19 }, /*114*/ 00712 { 70, 2, 3, 6, 19 }, /*115*/ 00713 { 70, 2, 3, 6, 19 }, /*116*/ 00714 { 70, 2, 3, 6, 19 }, /*117*/ 00715 { 70, 2, 3, 6, 19 }, /*118*/ 00716 { 70, 2, 3, 6, 19 }, /*119*/ 00717 { 70, 2, 3, 6, 19 }, /*120*/ 00718 { 70, 2, 3, 6, 19 }, /*121*/ 00719 { 70, 2, 3, 6, 19 }, /*122*/ 00720 { 70, 2, 3, 6, 19 }, /*123*/ 00721 { 70, 2, 3, 6, 19 }, /*124*/ 00722 { 70, 2, 3, 6, 19 }, /*125*/ 00723 { 70, 2, 3, 6, 19 }, /*126*/ 00724 { 70, 2, 3, 6, 19 }, /*127*/ 00725 { 70, 2, 3, 6, 19 }, /*128*/ 00726 { 70, 2, 3, 6, 19 }, /*129*/ 00727 { 70, 2, 3, 6, 19 }, /*130*/ 00728 { 70, 2, 3, 6, 19 }, /*131*/ 00729 { 70, 2, 3, 6, 19 }, /*132*/ 00730 { 70, 2, 3, 6, 19 }, /*133*/ 00731 { 70, 2, 3, 6, 19 }, /*134*/ 00732 { 70, 2, 3, 6, 19 }, /*135*/ 00733 { 70, 2, 3, 6, 19 }, /*136*/ 00734 { 70, 2, 3, 6, 19 }, /*137*/ 00735 { 70, 2, 3, 6, 19 }, /*138*/ 00736 { 70, 2, 3, 6, 19 }, /*139*/ 00737 { 70, 2, 3, 6, 19 }, /*140*/ 00738 { 70, 2, 3, 6, 19 }, /*141*/ 00739 { 70, 2, 3, 6, 19 }, /*142*/ 00740 { 70, 2, 3, 6, 19 }, /*143*/ 00741 { 70, 2, 3, 6, 19 }, /*144*/ 00742 { 70, 2, 3, 6, 19 }, /*145*/ 00743 { 70, 2, 3, 6, 19 }, /*146*/ 00744 { 70, 2, 3, 6, 19 }, /*147*/ 00745 { 70, 2, 3, 6, 19 }, /*148*/ 00746 { 70, 2, 3, 6, 19 }, /*149*/ 00747 { 70, 2, 3, 6, 19 }, /*150*/ 00748 { 70, 2, 3, 6, 19 }, /*151*/ 00749 { 70, 2, 3, 6, 19 }, /*152*/ 00750 { 70, 2, 3, 6, 19 }, /*153*/ 00751 { 70, 2, 3, 6, 19 }, /*154*/ 00752 { 70, 2, 3, 6, 19 }, /*155*/ 00753 { 70, 2, 3, 6, 19 }, /*156*/ 00754 { 70, 2, 3, 6, 19 }, /*157*/ 00755 { 70, 2, 3, 6, 19 }, /*158*/ 00756 { 70, 2, 3, 6, 19 }, /*159*/ 00757 { 70, 2, 3, 6, 19 }, /*160*/ 00758 { 70, 2, 3, 6, 19 }, /*161*/ 00759 { 70, 2, 3, 6, 19 }, /*162*/ 00760 { 70, 2, 3, 6, 19 }, /*163*/ 00761 { 70, 2, 3, 6, 19 }, /*164*/ 00762 { 70, 2, 3, 6, 19 }, /*165*/ 00763 { 70, 2, 3, 6, 19 }, /*166*/ 00764 { 70, 2, 3, 6, 19 }, /*167*/ 00765 { 70, 2, 3, 6, 19 }, /*168*/ 00766 { 70, 2, 3, 6, 19 }, /*169*/ 00767 { 70, 2, 3, 6, 19 }, /*170*/ 00768 { 70, 2, 3, 6, 19 }, /*171*/ 00769 { 70, 2, 3, 6, 19 }, /*172*/ 00770 { 70, 2, 3, 6, 19 }, /*173*/ 00771 { 70, 2, 3, 6, 19 }, /*174*/ 00772 { 70, 2, 3, 6, 19 }, /*175*/ 00773 { 70, 2, 3, 6, 19 }, /*176*/ 00774 { 70, 2, 3, 6, 19 }, /*177*/ 00775 { 70, 2, 3, 6, 19 }, /*178*/ 00776 { 70, 2, 3, 6, 19 }, /*179*/ 00777 { 70, 2, 3, 6, 19 }, /*180*/ 00778 { 70, 2, 3, 6, 19 }, /*181*/ 00779 { 70, 2, 3, 6, 19 }, /*182*/ 00780 { 70, 2, 3, 6, 19 }, /*183*/ 00781 { 70, 2, 3, 6, 19 }, /*184*/ 00782 { 70, 2, 3, 6, 19 }, /*185*/ 00783 { 70, 2, 3, 6, 19 }, /*186*/ 00784 { 70, 2, 3, 6, 19 }, /*187*/ 00785 { 70, 2, 3, 6, 19 }, /*188*/ 00786 { 70, 2, 3, 6, 19 }, /*189*/ 00787 { 70, 2, 3, 6, 19 }, /*190*/ 00788 { 70, 2, 3, 6, 19 }, /*191*/ 00789 { 70, 2, 3, 6, 19 }, /*192*/ 00790 { 70, 2, 3, 6, 19 }, /*193*/ 00791 { 70, 2, 3, 6, 19 }, /*194*/ 00792 { 70, 2, 3, 6, 19 }, /*195*/ 00793 { 70, 2, 3, 6, 19 }, /*196*/ 00794 { 70, 2, 3, 6, 19 }, /*197*/ 00795 { 70, 2, 3, 6, 19 }, /*198*/ 00796 { 70, 2, 3, 6, 19 }, /*199*/ 00797 { 70, 2, 3, 6, 19 }, /*200*/ 00798 00799 }; 00800 00808 static int magic_from_difficulty(int difficulty) { 00809 int percent, loop; 00810 00811 difficulty--; 00812 if (difficulty < 0) 00813 difficulty = 0; 00814 00815 if (difficulty >= DIFFLEVELS) 00816 difficulty = DIFFLEVELS-1; 00817 00818 percent = RANDOM()%100; 00819 00820 for (loop = 0; loop < (MAXMAGIC+1); ++loop) { 00821 percent -= difftomagic_list[difficulty][loop]; 00822 if (percent < 0) 00823 break; 00824 } 00825 if (loop == (MAXMAGIC+1)) { 00826 LOG(llevError, "Warning, table for difficulty %d bad.\n", difficulty); 00827 loop = 0; 00828 } 00829 /* LOG(llevDebug, "Chose magic %d for difficulty %d\n", loop, difficulty);*/ 00830 return (RANDOM()%3) ? loop : -loop; 00831 } 00832 00844 void set_abs_magic(object *op, int magic) { 00845 if (!magic) 00846 return; 00847 00848 op->magic = magic; 00849 if (op->arch) { 00850 if (op->type == ARMOUR) 00851 ARMOUR_SPEED(op) = (ARMOUR_SPEED(&op->arch->clone)*(100+magic*10))/100; 00852 00853 if (magic < 0 && !(RANDOM()%3)) /* You can't just check the weight always */ 00854 magic = (-magic); 00855 op->weight = (op->arch->clone.weight*(100-magic*10))/100; 00856 } else { 00857 if (op->type == ARMOUR) 00858 ARMOUR_SPEED(op) = (ARMOUR_SPEED(op)*(100+magic*10))/100; 00859 if (magic < 0 && !(RANDOM()%3)) /* You can't just check the weight always */ 00860 magic = (-magic); 00861 op->weight = (op->weight*(100-magic*10))/100; 00862 } 00863 } 00864 00880 static void set_magic(int difficulty, object *op, int max_magic, int flags) { 00881 int i; 00882 00883 i = magic_from_difficulty(difficulty); 00884 if ((flags>_ONLY_GOOD) && i < 0) 00885 i = -i; 00886 if (i > max_magic) 00887 i = max_magic; 00888 set_abs_magic(op, i); 00889 if (i < 0) 00890 SET_FLAG(op, FLAG_CURSED); 00891 } 00892 00909 static void set_ring_bonus(object *op, int bonus) { 00910 int r = RANDOM()%(bonus > 0 ? 25 : 11); 00911 00912 if (op->type == AMULET) { 00913 if (!(RANDOM()%21)) 00914 r = 20+RANDOM()%2; 00915 else { 00916 if (RANDOM()&2) 00917 r = 10; 00918 else 00919 r = 11+RANDOM()%9; 00920 } 00921 } 00922 00923 switch (r) { 00924 /* Redone by MSW 2000-11-26 to have much less code. Also, 00925 * bonuses and penalties will stack and add to existing values. 00926 * of the item. 00927 */ 00928 case 0: 00929 case 1: 00930 case 2: 00931 case 3: 00932 case 4: 00933 case 5: 00934 case 6: 00935 set_attr_value(&op->stats, r, (signed char)(bonus+get_attr_value(&op->stats, r))); 00936 break; 00937 00938 case 7: 00939 op->stats.dam += bonus; 00940 break; 00941 00942 case 8: 00943 op->stats.wc += bonus; 00944 break; 00945 00946 case 9: 00947 op->stats.food += bonus; /* hunger/sustenance */ 00948 break; 00949 00950 case 10: 00951 op->stats.ac += bonus; 00952 break; 00953 00954 /* Item that gives protections/vulnerabilities */ 00955 case 11: 00956 case 12: 00957 case 13: 00958 case 14: 00959 case 15: 00960 case 16: 00961 case 17: 00962 case 18: 00963 case 19: { 00964 int b = 5+FABS(bonus), val, resist = RANDOM()%num_resist_table; 00965 00966 /* Roughly generate a bonus between 100 and 35 (depending on the bonus) */ 00967 val = 10+RANDOM()%b+RANDOM()%b+RANDOM()%b+RANDOM()%b; 00968 00969 /* Cursed items need to have higher negative values to equal out with 00970 * positive values for how protections work out. Put another 00971 * little random element in since that they don't always end up with 00972 * even values. 00973 */ 00974 if (bonus < 0) 00975 val = 2*-val-RANDOM()%b; 00976 if (val > 35) 00977 val = 35; /* Upper limit */ 00978 b = 0; 00979 while (op->resist[resist_table[resist]] != 0 && b < 4) { 00980 resist = RANDOM()%num_resist_table; 00981 } 00982 if (b == 4) 00983 return; /* Not able to find a free resistance */ 00984 op->resist[resist_table[resist]] = val; 00985 /* We should probably do something more clever here to adjust value 00986 * based on how good a resistance we gave. 00987 */ 00988 break; 00989 } 00990 00991 case 20: 00992 if (op->type == AMULET) { 00993 SET_FLAG(op, FLAG_REFL_SPELL); 00994 op->value *= 11; 00995 } else { 00996 op->stats.hp = 1; /* regenerate hit points */ 00997 op->value *= 4; 00998 } 00999 break; 01000 01001 case 21: 01002 if (op->type == AMULET) { 01003 SET_FLAG(op, FLAG_REFL_MISSILE); 01004 op->value *= 9; 01005 } else { 01006 op->stats.sp = 1; /* regenerate spell points */ 01007 op->value *= 3; 01008 } 01009 break; 01010 01011 case 22: 01012 op->stats.exp += bonus; /* Speed! */ 01013 op->value = (op->value*2)/3; 01014 break; 01015 } 01016 if (bonus > 0) 01017 op->value *= 2*bonus; 01018 else 01019 op->value = -(op->value*2*bonus)/3; 01020 } 01021 01030 static int get_magic(int diff) { 01031 int i; 01032 01033 if (diff < 3) 01034 diff = 3; 01035 for (i = 0; i < 4; i++) 01036 if (RANDOM()%diff) 01037 return i; 01038 return 4; 01039 } 01040 01041 #define DICE2 (get_magic(2) == 2 ? 2 : 1) 01042 #define DICESPELL (RANDOM()%3+RANDOM()%3+RANDOM()%3+RANDOM()%3+RANDOM()%3) 01043 01070 void fix_generated_item(object *op, object *creator, int difficulty, int max_magic, int flags) { 01071 int was_magic = op->magic, num_enchantments = 0, save_item_power; 01072 01073 if (!creator || creator->type == op->type) 01074 creator = op; /* safety & to prevent polymorphed objects giving attributes */ 01075 01076 /* If we make an artifact, this information will be destroyed */ 01077 save_item_power = op->item_power; 01078 op->item_power = 0; 01079 01080 if (op->randomitems && op->type != SPELL) { 01081 create_treasure(op->randomitems, op, flags, difficulty, 0); 01082 if (!op->inv) 01083 LOG(llevDebug, "fix_generated_item: Unable to generate treasure for %s\n", op->name); 01084 /* So the treasure doesn't get created again */ 01085 op->randomitems = NULL; 01086 } 01087 01088 if (difficulty < 1) 01089 difficulty = 1; 01090 if (!(flags>_MINIMAL)) { 01091 if (op->arch == crown_arch) { 01092 set_magic(difficulty > 25 ? 30 : difficulty+5, op, max_magic, flags); 01093 num_enchantments = calc_item_power(op, 1); 01094 generate_artifact(op, difficulty); 01095 } else { 01096 if (!op->magic && max_magic) 01097 set_magic(difficulty, op, max_magic, flags); 01098 num_enchantments = calc_item_power(op, 1); 01099 if ((!was_magic && !(RANDOM()%CHANCE_FOR_ARTIFACT)) 01100 || op->type == HORN 01101 || difficulty >= 999) 01102 generate_artifact(op, difficulty); 01103 } 01104 01105 /* Object was made an artifact. Calculate its item_power rating. 01106 * the item_power in the object is what the artifact adds. 01107 */ 01108 if (op->title) { 01109 /* if save_item_power is set, then most likely we started with an 01110 * artifact and have added new abilities to it - this is rare, but 01111 * but I have seen things like 'strange rings of fire'. So just 01112 * figure out the power from the base power plus what this one adds. 01113 * Note that since item_power is not quite linear, this actually 01114 * ends up being somewhat of a bonus. 01115 */ 01116 if (save_item_power) 01117 op->item_power = save_item_power+get_power_from_ench(op->item_power); 01118 else 01119 op->item_power += get_power_from_ench(num_enchantments); 01120 } else if (save_item_power) { 01121 /* restore the item_power field to the object if we haven't changed 01122 * it. we don't care about num_enchantments - that will basically 01123 * just have calculated some value from the base attributes of the 01124 * archetype. 01125 */ 01126 op->item_power = save_item_power; 01127 } else { 01128 /* item_power was zero. This is suspicious, as it may be because it 01129 * was never previously calculated. Let's compute a value and see if 01130 * it is non-zero. If it indeed is, then assign it as the new 01131 * item_power value. 01132 * - gros, 21th of July 2006. 01133 */ 01134 op->item_power = calc_item_power(op, 0); 01135 save_item_power = op->item_power; /* Just in case it would get used 01136 * again below */ 01137 } 01138 } else { 01139 /* If flag is GT_MINIMAL, we want to restore item power */ 01140 op->item_power = save_item_power; 01141 } 01142 01143 /* materialtype modifications. Note we allow this on artifacts. */ 01144 01145 set_materialname(op, difficulty, NULL); 01146 01147 if (flags>_MINIMAL) { 01148 if (op->type == POTION) 01149 /* Handle healing and magic power potions */ 01150 if (op->stats.sp && !op->randomitems) { 01151 object *tmp; 01152 01153 tmp = create_archetype(spell_mapping[op->stats.sp]); 01154 insert_ob_in_ob(tmp, op); 01155 op->stats.sp = 0; 01156 } 01157 } else if (!op->title) { /* Only modify object if not special */ 01158 switch (op->type) { 01159 case WEAPON: 01160 case ARMOUR: 01161 case SHIELD: 01162 case HELMET: 01163 case CLOAK: 01164 if (QUERY_FLAG(op, FLAG_CURSED) && !(RANDOM()%4)) 01165 set_ring_bonus(op, -DICE2); 01166 break; 01167 01168 case BRACERS: 01169 if (!(RANDOM()%(QUERY_FLAG(op, FLAG_CURSED) ? 5 : 20))) { 01170 set_ring_bonus(op, QUERY_FLAG(op, FLAG_CURSED) ? -DICE2 : DICE2); 01171 if (!QUERY_FLAG(op, FLAG_CURSED)) 01172 op->value *= 3; 01173 } 01174 break; 01175 01176 case POTION: { 01177 int too_many_tries = 0, is_special = 0; 01178 01179 /* Handle healing and magic power potions */ 01180 if (op->stats.sp && !op->randomitems) { 01181 object *tmp; 01182 01183 tmp = create_archetype(spell_mapping[op->stats.sp]); 01184 insert_ob_in_ob(tmp, op); 01185 op->stats.sp = 0; 01186 } 01187 01188 while (!(is_special = special_potion(op)) && !op->inv) { 01189 generate_artifact(op, difficulty); 01190 if (too_many_tries++ > 10) 01191 break; 01192 } 01193 /* don't want to change value for healing/magic power potions, 01194 * since the value set on those is already correct. 01195 */ 01196 if (op->inv && op->randomitems) { 01197 /* value multiplier is same as for scrolls */ 01198 op->value = (op->value*op->inv->value); 01199 op->level = op->inv->level/2+RANDOM()%difficulty+RANDOM()%difficulty; 01200 } else { 01201 FREE_AND_COPY(op->name, "potion"); 01202 FREE_AND_COPY(op->name_pl, "potions"); 01203 } 01204 if (!(flags>_ONLY_GOOD) && RANDOM()%2) 01205 SET_FLAG(op, FLAG_CURSED); 01206 break; 01207 } 01208 01209 case AMULET: 01210 if (op->arch == amulet_arch) 01211 op->value *= 5; /* Since it's not just decoration */ 01212 case RING: 01213 if (op->arch == NULL) { 01214 remove_ob(op); 01215 free_object(op); 01216 op = NULL; 01217 break; 01218 } 01219 if (op->arch != ring_arch && op->arch != amulet_arch) 01220 /* It's a special artifact!*/ 01221 break; 01222 01223 if (!(flags>_ONLY_GOOD) && !(RANDOM()%3)) 01224 SET_FLAG(op, FLAG_CURSED); 01225 set_ring_bonus(op, QUERY_FLAG(op, FLAG_CURSED) ? -DICE2 : DICE2); 01226 if (op->type != RING) /* Amulets have only one ability */ 01227 break; 01228 if (!(RANDOM()%4)) { 01229 int d = (RANDOM()%2 || QUERY_FLAG(op, FLAG_CURSED)) ? -DICE2 : DICE2; 01230 if (d > 0) 01231 op->value *= 3; 01232 set_ring_bonus(op, d); 01233 if (!(RANDOM()%4)) { 01234 int d = (RANDOM()%3 || QUERY_FLAG(op, FLAG_CURSED)) ? -DICE2 : DICE2; 01235 if (d > 0) 01236 op->value *= 5; 01237 set_ring_bonus(op, d); 01238 } 01239 } 01240 if (GET_ANIM_ID(op)) 01241 SET_ANIMATION(op, RANDOM()%((int)NUM_ANIMATIONS(op))); 01242 break; 01243 01244 case BOOK: 01245 /* Is it an empty book?, if yes lets make a special 01246 * msg for it, and tailor its properties based on the 01247 * creator and/or map level we found it on. 01248 */ 01249 if (!op->msg && RANDOM()%10) { 01250 /* set the book level properly */ 01251 if (creator->level == 0 || QUERY_FLAG(creator, FLAG_ALIVE)) { 01252 if (op->map && op->map->difficulty) 01253 op->level = RANDOM()%(op->map->difficulty)+RANDOM()%10+1; 01254 else 01255 op->level = RANDOM()%20+1; 01256 } else 01257 op->level = RANDOM()%creator->level; 01258 01259 tailor_readable_ob(op, -1); 01260 /* books w/ info are worth more! */ 01261 op->value *= ((op->level > 10 ? op->level : (op->level+1)/2)*((strlen(op->msg)/250)+1)); 01262 /* creator related stuff */ 01263 01264 /* for library, chained books. Note that some monsters have 01265 * no_pick set - we don't want to set no pick in that case. 01266 */ 01267 if (QUERY_FLAG(creator, FLAG_NO_PICK) 01268 && !QUERY_FLAG(creator, FLAG_MONSTER)) 01269 SET_FLAG(op, FLAG_NO_PICK); 01270 if (creator->slaying && !op->slaying) /* for check_inv floors */ 01271 op->slaying = add_string(creator->slaying); 01272 01273 /* add exp so reading it gives xp (once)*/ 01274 op->stats.exp = op->value > 10000 ? op->value/5 : op->value/10; 01275 } 01276 break; 01277 01278 case SPELLBOOK: 01279 op->value = op->value*op->inv->value; 01280 /* add exp so learning gives xp */ 01281 op->level = op->inv->level; 01282 op->stats.exp = op->value; 01283 /* some more fun */ 01284 if (!(flags>_ONLY_GOOD) && rndm(1, 100) <= 5) { 01285 if (rndm(1, 6) <= 1) 01286 SET_FLAG(op, FLAG_DAMNED); 01287 else 01288 SET_FLAG(op, FLAG_CURSED); 01289 } else if (rndm(1, 100) <= 1) { 01290 SET_FLAG(op, FLAG_BLESSED); 01291 } 01292 break; 01293 01294 case WAND: 01295 /* nrof in the treasure list is number of charges, 01296 * not number of wands. So copy that into food (charges), 01297 * and reset nrof. 01298 */ 01299 op->stats.food = op->inv->nrof; 01300 op->nrof = 1; 01301 /* If the spell changes by level, choose a random level 01302 * for it, and adjust price. If the spell doesn't 01303 * change by level, just set the wand to the level of 01304 * the spell, and value calculation is simpler. 01305 */ 01306 if (op->inv->duration_modifier 01307 || op->inv->dam_modifier 01308 || op->inv->range_modifier) { 01309 op->level = level_for_item(op, difficulty, 0); 01310 op->value = op->value*op->inv->value*(op->level+50)/(op->inv->level+50); 01311 } else { 01312 op->level = op->inv->level; 01313 op->value = op->value*op->inv->value; 01314 } 01315 break; 01316 01317 case ROD: 01318 op->level = level_for_item(op, difficulty, 0); 01319 /* Add 50 to both level an divisor to keep prices a little 01320 * more reasonable. Otherwise, a high level version of a 01321 * low level spell can be worth tons a money (eg, level 20 01322 * rod, level 2 spell = 10 time multiplier). This way, the 01323 * value are a bit more reasonable. 01324 */ 01325 op->value = op->value*op->inv->value*(op->level+50)/(op->inv->level+50); 01326 /* maxhp is used to denote how many 'charges' the rod holds 01327 * before */ 01328 if (op->stats.maxhp) 01329 op->stats.maxhp *= MAX(op->inv->stats.sp, op->inv->stats.grace); 01330 else 01331 op->stats.maxhp = 2*MAX(op->inv->stats.sp, op->inv->stats.grace); 01332 01333 op->stats.hp = op->stats.maxhp; 01334 break; 01335 01336 case SCROLL: 01337 op->level = level_for_item(op, difficulty, 0); 01338 op->value = op->value*op->inv->value*(op->level+50)/(op->inv->level+50); 01339 /* add exp so reading them properly gives xp */ 01340 op->stats.exp = op->value/5; 01341 op->nrof = op->inv->nrof; 01342 /* some more fun */ 01343 if (!(flags>_ONLY_GOOD) && rndm(1, 100) <= 20) { 01344 if (rndm(1, 6) <= 1) 01345 SET_FLAG(op, FLAG_DAMNED); 01346 else 01347 SET_FLAG(op, FLAG_CURSED); 01348 } else if (rndm(1, 100) <= 2) { 01349 SET_FLAG(op, FLAG_BLESSED); 01350 } 01351 break; 01352 01353 case RUNE: 01354 trap_adjust(op, difficulty); 01355 break; 01356 01357 case TRAP: 01358 trap_adjust(op, difficulty); 01359 break; 01360 } /* switch type */ 01361 } 01362 if (flags>_STARTEQUIP) { 01363 if (op->nrof < 2 01364 && op->type != CONTAINER 01365 && op->type != MONEY 01366 && !QUERY_FLAG(op, FLAG_IS_THROWN)) 01367 SET_FLAG(op, FLAG_STARTEQUIP); 01368 else if (op->type != MONEY) 01369 op->value = 0; 01370 } 01371 01372 if (!(flags>_ENVIRONMENT)) 01373 fix_flesh_item(op, creator); 01374 } 01375 01376 /* 01377 * 01378 * 01379 * CODE DEALING WITH ARTIFACTS STARTS HERE 01380 * 01381 * 01382 */ 01383 01393 static artifactlist *get_empty_artifactlist(void) { 01394 artifactlist *tl = (artifactlist *)malloc(sizeof(artifactlist)); 01395 if (tl == NULL) 01396 fatal(OUT_OF_MEMORY); 01397 tl->next = NULL; 01398 tl->items = NULL; 01399 tl->total_chance = 0; 01400 return tl; 01401 } 01402 01412 static artifact *get_empty_artifact(void) { 01413 artifact *t = (artifact *)malloc(sizeof(artifact)); 01414 if (t == NULL) 01415 fatal(OUT_OF_MEMORY); 01416 t->item = NULL; 01417 t->next = NULL; 01418 t->chance = 0; 01419 t->difficulty = 0; 01420 t->allowed = NULL; 01421 return t; 01422 } 01423 01431 artifactlist *find_artifactlist(int type) { 01432 artifactlist *al; 01433 01434 for (al = first_artifactlist; al != NULL; al = al->next) 01435 if (al->type == type) 01436 return al; 01437 return NULL; 01438 } 01439 01446 void dump_artifacts(void) { 01447 artifactlist *al; 01448 artifact *art; 01449 linked_char *next; 01450 01451 fprintf(logfile, "\n"); 01452 for (al = first_artifactlist; al != NULL; al = al->next) { 01453 fprintf(logfile, "Artifact has type %d, total_chance=%d\n", al->type, al->total_chance); 01454 for (art = al->items; art != NULL; art = art->next) { 01455 fprintf(logfile, "Artifact %-30s Difficulty %3d Chance %5d\n", art->item->name, art->difficulty, art->chance); 01456 if (art->allowed != NULL) { 01457 fprintf(logfile, "\tAllowed combinations:"); 01458 for (next = art->allowed; next != NULL; next = next->next) 01459 fprintf(logfile, "%s,", next->name); 01460 fprintf(logfile, "\n"); 01461 } 01462 } 01463 } 01464 fprintf(logfile, "\n"); 01465 } 01466 01470 static void dump_monster_treasure_rec(const char *name, treasure *t, int depth) { 01471 treasurelist *tl; 01472 int i; 01473 01474 if (depth > 100) 01475 return; 01476 01477 while (t != NULL) { 01478 if (t->name != NULL) { 01479 for (i = 0; i < depth; i++) 01480 fprintf(logfile, " "); 01481 fprintf(logfile, "{ (list: %s)\n", t->name); 01482 tl = find_treasurelist(t->name); 01483 dump_monster_treasure_rec(name, tl->items, depth+2); 01484 for (i = 0; i < depth; i++) 01485 fprintf(logfile, " "); 01486 fprintf(logfile, "} (end of list: %s)\n", t->name); 01487 } else { 01488 for (i = 0; i < depth; i++) 01489 fprintf(logfile, " "); 01490 if (t->item->clone.type == FLESH) 01491 fprintf(logfile, "%s's %s\n", name, t->item->clone.name); 01492 else 01493 fprintf(logfile, "%s\n", t->item->clone.name); 01494 } 01495 if (t->next_yes != NULL) { 01496 for (i = 0; i < depth; i++) 01497 fprintf(logfile, " "); 01498 fprintf(logfile, " (if yes)\n"); 01499 dump_monster_treasure_rec(name, t->next_yes, depth+1); 01500 } 01501 if (t->next_no != NULL) { 01502 for (i = 0; i < depth; i++) 01503 fprintf(logfile, " "); 01504 fprintf(logfile, " (if no)\n"); 01505 dump_monster_treasure_rec(name, t->next_no, depth+1); 01506 } 01507 t = t->next; 01508 } 01509 } 01510 01515 void dump_monster_treasure(const char *name) { 01516 archetype *at; 01517 int found; 01518 01519 found = 0; 01520 fprintf(logfile, "\n"); 01521 for (at = first_archetype; at != NULL; at = at->next) 01522 if (!strcasecmp(at->clone.name, name) && at->clone.title == NULL) { 01523 fprintf(logfile, "treasures for %s (arch: %s)\n", at->clone.name, at->name); 01524 if (at->clone.randomitems != NULL) 01525 dump_monster_treasure_rec(at->clone.name, at->clone.randomitems->items, 1); 01526 else 01527 fprintf(logfile, "(nothing)\n"); 01528 fprintf(logfile, "\n"); 01529 found++; 01530 } 01531 if (found == 0) 01532 fprintf(logfile, "No objects have the name %s!\n\n", name); 01533 } 01534 01539 void init_artifacts(void) { 01540 static int has_been_inited = 0; 01541 FILE *fp; 01542 char filename[MAX_BUF], buf[HUGE_BUF], *cp, *next; 01543 artifact *art = NULL; 01544 linked_char *tmp; 01545 int value, comp; 01546 artifactlist *al; 01547 archetype dummy_archetype; 01548 01549 memset(&dummy_archetype, 0, sizeof(archetype)); 01550 01551 if (has_been_inited) 01552 return; 01553 else 01554 has_been_inited = 1; 01555 01556 artifact_init = 1; 01557 01558 snprintf(filename, sizeof(filename), "%s/artifacts", settings.datadir); 01559 LOG(llevDebug, "Reading artifacts from %s...\n", filename); 01560 if ((fp = open_and_uncompress(filename, 0, &comp)) == NULL) { 01561 LOG(llevError, "Can't open %s.\n", filename); 01562 return; 01563 } 01564 01565 while (fgets(buf, HUGE_BUF, fp) != NULL) { 01566 if (*buf == '#') 01567 continue; 01568 if ((cp = strchr(buf, '\n')) != NULL) 01569 *cp = '\0'; 01570 cp = buf; 01571 while (*cp == ' ') /* Skip blanks */ 01572 cp++; 01573 if (*cp == '\0') 01574 continue; 01575 01576 if (!strncmp(cp, "Allowed", 7)) { 01577 if (art == NULL) { 01578 art = get_empty_artifact(); 01579 nrofartifacts++; 01580 } 01581 01582 cp = strchr(cp, ' ')+1; 01583 while (*(cp+strlen(cp)-1) == ' ') 01584 cp[strlen(cp)-1] = '\0'; 01585 01586 if (!strcmp(cp, "all")) 01587 continue; 01588 01589 do { 01590 while (*cp == ' ') 01591 cp++; 01592 nrofallowedstr++; 01593 if ((next = strchr(cp, ',')) != NULL) 01594 *(next++) = '\0'; 01595 tmp = (linked_char *)malloc(sizeof(linked_char)); 01596 tmp->name = add_string(cp); 01597 tmp->next = art->allowed; 01598 art->allowed = tmp; 01599 } while ((cp = next) != NULL); 01600 } else if (sscanf(cp, "chance %d", &value)) 01601 art->chance = (uint16)value; 01602 else if (sscanf(cp, "difficulty %d", &value)) 01603 art->difficulty = (uint8)value; 01604 else if (!strncmp(cp, "Object", 6)) { 01605 art->item = (object *)calloc(1, sizeof(object)); 01606 if (art->item == NULL) { 01607 LOG(llevError, "init_artifacts: memory allocation failure.\n"); 01608 abort(); 01609 } 01610 reset_object(art->item); 01611 art->item->arch = &dummy_archetype; 01612 if (!load_object(fp, art->item, LO_LINEMODE, 0)) 01613 LOG(llevError, "Init_Artifacts: Could not load object.\n"); 01614 art->item->arch = NULL; 01615 art->item->name = add_string((strchr(cp, ' ')+1)); 01616 al = find_artifactlist(art->item->type); 01617 if (al == NULL) { 01618 al = get_empty_artifactlist(); 01619 al->type = art->item->type; 01620 al->next = first_artifactlist; 01621 first_artifactlist = al; 01622 } 01623 art->next = al->items; 01624 al->items = art; 01625 art = NULL; 01626 } else 01627 LOG(llevError, "Unknown input in artifact file: %s\n", buf); 01628 } 01629 01630 close_and_delete(fp, comp); 01631 01632 for (al = first_artifactlist; al != NULL; al = al->next) { 01633 for (art = al->items; art != NULL; art = art->next) { 01634 if (!art->chance) 01635 LOG(llevError, "Warning: artifact with no chance: %s\n", art->item->name); 01636 else 01637 al->total_chance += art->chance; 01638 } 01639 #if 0 01640 LOG(llevDebug, "Artifact list type %d has %d total chance\n", al->type, al->total_chance); 01641 #endif 01642 } 01643 01644 LOG(llevDebug, "done artifacts.\n"); 01645 artifact_init = 0; 01646 } 01647 01648 01653 void add_abilities(object *op, object *change) { 01654 int i, tmp; 01655 01656 if (change->face != blank_face) { 01657 #ifdef TREASURE_VERBOSE 01658 LOG(llevDebug, "FACE: %d\n", change->face->number); 01659 #endif 01660 op->face = change->face; 01661 } 01662 if (change->animation_id != 0) { 01663 op->animation_id = change->animation_id; 01664 SET_FLAG(op, FLAG_ANIMATE); 01665 animate_object(op, op->facing); 01666 } 01667 01668 for (i = 0; i < NUM_STATS; i++) 01669 change_attr_value(&(op->stats), i, get_attr_value(&(change->stats), i)); 01670 01671 op->attacktype |= change->attacktype; 01672 op->path_attuned |= change->path_attuned; 01673 op->path_repelled |= change->path_repelled; 01674 op->path_denied |= change->path_denied; 01675 op->move_type |= change->move_type; 01676 op->stats.luck += change->stats.luck; 01677 01678 if (QUERY_FLAG(change, FLAG_CURSED)) 01679 SET_FLAG(op, FLAG_CURSED); 01680 if (QUERY_FLAG(change, FLAG_DAMNED)) 01681 SET_FLAG(op, FLAG_DAMNED); 01682 if ((QUERY_FLAG(change, FLAG_CURSED) || QUERY_FLAG(change, FLAG_DAMNED)) 01683 && op->magic > 0) 01684 set_abs_magic(op, -op->magic); 01685 01686 if (QUERY_FLAG(change, FLAG_LIFESAVE)) 01687 SET_FLAG(op, FLAG_LIFESAVE); 01688 if (QUERY_FLAG(change, FLAG_REFL_SPELL)) 01689 SET_FLAG(op, FLAG_REFL_SPELL); 01690 if (QUERY_FLAG(change, FLAG_STEALTH)) 01691 SET_FLAG(op, FLAG_STEALTH); 01692 if (QUERY_FLAG(change, FLAG_XRAYS)) 01693 SET_FLAG(op, FLAG_XRAYS); 01694 if (QUERY_FLAG(change, FLAG_BLIND)) 01695 SET_FLAG(op, FLAG_BLIND); 01696 if (QUERY_FLAG(change, FLAG_SEE_IN_DARK)) 01697 SET_FLAG(op, FLAG_SEE_IN_DARK); 01698 if (QUERY_FLAG(change, FLAG_REFL_MISSILE)) 01699 SET_FLAG(op, FLAG_REFL_MISSILE); 01700 if (QUERY_FLAG(change, FLAG_MAKE_INVIS)) 01701 SET_FLAG(op, FLAG_MAKE_INVIS); 01702 01703 if (QUERY_FLAG(change, FLAG_STAND_STILL)) { 01704 CLEAR_FLAG(op, FLAG_ANIMATE); 01705 /* so artifacts will join */ 01706 if (!QUERY_FLAG(op, FLAG_ALIVE)) 01707 op->speed = 0.0; 01708 update_ob_speed(op); 01709 } 01710 if (change->nrof) 01711 op->nrof = RANDOM()%((int)change->nrof)+1; 01712 op->stats.exp += change->stats.exp; /* Speed modifier */ 01713 op->stats.wc += change->stats.wc; 01714 op->stats.ac += change->stats.ac; 01715 01716 if (change->other_arch) { 01717 /* Basically, for horns & potions, the other_arch field is the spell 01718 * to cast. So convert that to into a spell and put it into 01719 * this object. 01720 */ 01721 if (op->type == HORN || op->type == POTION) { 01722 object *tmp_obj; 01723 01724 /* Remove any spells this object currently has in it */ 01725 while (op->inv) { 01726 tmp_obj = op->inv; 01727 remove_ob(tmp_obj); 01728 free_object(tmp_obj); 01729 } 01730 tmp_obj = arch_to_object(change->other_arch); 01731 insert_ob_in_ob(tmp_obj, op); 01732 } 01733 /* No harm setting this for potions/horns */ 01734 op->other_arch = change->other_arch; 01735 } 01736 01737 if (change->stats.hp < 0) 01738 op->stats.hp = -change->stats.hp; 01739 else 01740 op->stats.hp += change->stats.hp; 01741 if (change->stats.maxhp < 0) 01742 op->stats.maxhp = -change->stats.maxhp; 01743 else 01744 op->stats.maxhp += change->stats.maxhp; 01745 if (change->stats.sp < 0) 01746 op->stats.sp = -change->stats.sp; 01747 else 01748 op->stats.sp += change->stats.sp; 01749 if (change->stats.maxsp < 0) 01750 op->stats.maxsp = -change->stats.maxsp; 01751 else 01752 op->stats.maxsp += change->stats.maxsp; 01753 if (change->stats.food < 0) 01754 op->stats.food = -(change->stats.food); 01755 else 01756 op->stats.food += change->stats.food; 01757 if (change->level < 0) 01758 op->level = -(change->level); 01759 else 01760 op->level += change->level; 01761 01762 if (change->gen_sp_armour < 0) 01763 op->gen_sp_armour = -(change->gen_sp_armour); 01764 else 01765 op->gen_sp_armour = (op->gen_sp_armour*(change->gen_sp_armour))/100; 01766 01767 op->item_power = change->item_power; 01768 01769 for (i = 0; i < NROFATTACKS; i++) { 01770 if (change->resist[i]) { 01771 op->resist[i] += change->resist[i]; 01772 } 01773 } 01774 if (change->stats.dam) { 01775 if (change->stats.dam < 0) 01776 op->stats.dam = (-change->stats.dam); 01777 else if (op->stats.dam) { 01778 tmp = (int)(((int)op->stats.dam*(int)change->stats.dam)/10); 01779 if (tmp == op->stats.dam) { 01780 if (change->stats.dam < 10) 01781 op->stats.dam--; 01782 else 01783 op->stats.dam++; 01784 } else 01785 op->stats.dam = tmp; 01786 } 01787 } 01788 if (change->weight) { 01789 if (change->weight < 0) 01790 op->weight = (-change->weight); 01791 else 01792 op->weight = (op->weight*(change->weight))/100; 01793 } 01794 if (change->last_sp) { 01795 if (change->last_sp < 0) 01796 op->last_sp = (-change->last_sp); 01797 else 01798 op->last_sp = (signed char)(((int)op->last_sp*(int)change->last_sp)/(int)100); 01799 } 01800 if (change->gen_sp_armour) { 01801 if (change->gen_sp_armour < 0) 01802 op->gen_sp_armour = (-change->gen_sp_armour); 01803 else 01804 op->gen_sp_armour = (signed char)(((int)op->gen_sp_armour*((int)change->gen_sp_armour))/(int)100); 01805 } 01806 op->value *= change->value; 01807 01808 if (change->material) 01809 op->material = change->material; 01810 01811 if (change->materialname) { 01812 if (op->materialname) 01813 free_string(op->materialname); 01814 op->materialname = add_refcount(change->materialname); 01815 } 01816 01817 if (change->slaying) { 01818 if (op->slaying) 01819 free_string(op->slaying); 01820 op->slaying = add_refcount(change->slaying); 01821 } 01822 if (change->race) { 01823 if (op->race) 01824 free_string(op->race); 01825 op->race = add_refcount(change->race); 01826 } 01827 if (change->msg) { 01828 if (op->msg) 01829 free_string(op->msg); 01830 op->msg = add_refcount(change->msg); 01831 } 01832 01833 if (change->inv) { 01834 object *inv = change->inv; 01835 object *copy; 01836 01837 while (inv) { 01838 copy = get_object(); 01839 copy_object(inv, copy); 01840 insert_ob_in_ob(copy, op); 01841 inv = inv->below; 01842 } 01843 } 01844 } 01845 01849 int legal_artifact_combination(object *op, artifact *art) { 01850 int neg, success = 0; 01851 linked_char *tmp; 01852 const char *name; 01853 01854 if (art->allowed == (linked_char *)NULL) 01855 return 1; /* Ie, "all" */ 01856 for (tmp = art->allowed; tmp; tmp = tmp->next) { 01857 #ifdef TREASURE_VERBOSE 01858 LOG(llevDebug, "legal_art: %s\n", tmp->name); 01859 #endif 01860 if (*tmp->name == '!') 01861 name = tmp->name+1, 01862 neg = 1; 01863 else 01864 name = tmp->name, 01865 neg = 0; 01866 01867 /* If we match name, then return the opposite of 'neg' */ 01868 if (!strcmp(name, op->name) || (op->arch && !strcmp(name, op->arch->name))) 01869 return !neg; 01870 01871 /* Set success as true, since if the match was an inverse, it means 01872 * everything is allowed except what we match 01873 */ 01874 else if (neg) 01875 success = 1; 01876 } 01877 return success; 01878 } 01879 01884 void give_artifact_abilities(object *op, object *artifact) { 01885 char new_name[MAX_BUF]; 01886 01887 snprintf(new_name, sizeof(new_name), "of %s", artifact->name); 01888 if (op->title) 01889 free_string(op->title); 01890 op->title = add_string(new_name); 01891 add_abilities(op, artifact); /* Give out the bonuses */ 01892 01893 return; 01894 } 01895 01897 #define ARTIFACT_TRIES 2 01898 01906 void generate_artifact(object *op, int difficulty) { 01907 artifactlist *al; 01908 artifact *art; 01909 int i; 01910 01911 al = find_artifactlist(op->type); 01912 01913 if (al == NULL) { 01914 return; 01915 } 01916 01917 for (i = 0; i < ARTIFACT_TRIES; i++) { 01918 int roll = RANDOM()%al->total_chance; 01919 01920 for (art = al->items; art != NULL; art = art->next) { 01921 roll -= art->chance; 01922 if (roll < 0) 01923 break; 01924 } 01925 01926 if (art == NULL || roll >= 0) { 01927 LOG(llevError, "Got null entry and non zero roll in generate_artifact, type %d\n", op->type); 01928 return; 01929 } 01930 if (!strcmp(art->item->name, "NONE")) 01931 return; 01932 if (FABS(op->magic) < art->item->magic) 01933 continue; /* Not magic enough to be this item */ 01934 01935 /* Map difficulty not high enough */ 01936 if (difficulty < art->difficulty) 01937 continue; 01938 01939 if (!legal_artifact_combination(op, art)) { 01940 #ifdef TREASURE_VERBOSE 01941 LOG(llevDebug, "%s of %s was not a legal combination.\n", op->name, art->item->name); 01942 #endif 01943 continue; 01944 } 01945 give_artifact_abilities(op, art->item); 01946 return; 01947 } 01948 } 01949 01955 static void fix_flesh_item(object *item, object *donor) { 01956 char tmpbuf[MAX_BUF]; 01957 int i; 01958 01959 if (item->type == FLESH && donor && QUERY_FLAG(donor, FLAG_MONSTER)) { 01960 /* change the name */ 01961 snprintf(tmpbuf, sizeof(tmpbuf), "%s's %s", donor->name, item->name); 01962 FREE_AND_COPY(item->name, tmpbuf); 01963 snprintf(tmpbuf, sizeof(tmpbuf), "%s's %s", donor->name, item->name_pl); 01964 FREE_AND_COPY(item->name_pl, tmpbuf); 01965 01966 /* store original arch in other_arch */ 01967 if (!item->other_arch) { 01968 if (!donor->arch->reference_count) { 01969 item->other_arch = donor->arch; 01970 } else { 01971 /* If dealing with custom monsters, other_arch still needs to 01972 * point back to the original. Otherwise what happens 01973 * is that other_arch points at the custom archetype, but 01974 * that can be freed. Reference count doesn't work because 01975 * the loader will not be able to resolve the other_arch at 01976 * load time (server may has restarted, etc.) 01977 */ 01978 archetype *original = find_archetype(donor->arch->name); 01979 01980 if (original) 01981 item->other_arch = original; 01982 else { 01983 LOG(llevError, "could not find original archetype %s for custom monster!\n", donor->arch->name); 01984 abort(); 01985 } 01986 } 01987 } 01988 01989 /* weight is FLESH weight/100 * donor */ 01990 if ((item->weight = (signed long)(((double)item->weight/(double)100.0)*(double)donor->weight)) == 0) 01991 item->weight = 1; 01992 01993 /* value is multiplied by level of donor */ 01994 item->value *= isqrt(donor->level*2); 01995 01996 /* food value */ 01997 item->stats.food += (donor->stats.hp/100)+donor->stats.Con; 01998 01999 /* flesh items inherit some abilities of donor, but not full effect. */ 02000 for (i = 0; i < NROFATTACKS; i++) 02001 item->resist[i] = donor->resist[i]/2; 02002 02003 /* item inherits donor's level and exp (important for dragons) */ 02004 item->level = donor->level; 02005 item->stats.exp = donor->stats.exp; 02006 02007 /* if donor has some attacktypes, the flesh is poisonous */ 02008 if (donor->attacktype&AT_POISON) 02009 item->type = POISON; 02010 if (donor->attacktype&AT_ACID) 02011 item->stats.hp = -1*item->stats.food; 02012 SET_FLAG(item, FLAG_NO_STEAL); 02013 } 02014 } 02015 02024 static int special_potion(object *op) { 02025 int i; 02026 02027 if (op->attacktype) 02028 return 1; 02029 02030 if (op->stats.Str 02031 || op->stats.Dex 02032 || op->stats.Con 02033 || op->stats.Pow 02034 || op->stats.Wis 02035 || op->stats.Int 02036 || op->stats.Cha) 02037 return 1; 02038 02039 for (i = 0; i < NROFATTACKS; i++) 02040 if (op->resist[i]) 02041 return 1; 02042 02043 return 0; 02044 } 02045 02052 static void free_treasurestruct(treasure *t) { 02053 if (t->next) 02054 free_treasurestruct(t->next); 02055 if (t->next_yes) 02056 free_treasurestruct(t->next_yes); 02057 if (t->next_no) 02058 free_treasurestruct(t->next_no); 02059 free(t); 02060 } 02061 02068 static void free_charlinks(linked_char *lc) { 02069 if (lc->next) 02070 free_charlinks(lc->next); 02071 free(lc); 02072 } 02073 02086 static void free_artifact(artifact *at) { 02087 object *next; 02088 02089 if (at->next) 02090 free_artifact(at->next); 02091 if (at->allowed) 02092 free_charlinks(at->allowed); 02093 while (at->item) { 02094 next = at->item->next; 02095 if (at->item->name) 02096 free_string(at->item->name); 02097 if (at->item->name_pl) 02098 free_string(at->item->name_pl); 02099 if (at->item->msg) 02100 free_string(at->item->msg); 02101 if (at->item->title) 02102 free_string(at->item->title); 02103 free_key_values(at->item); 02104 free(at->item); 02105 at->item = next; 02106 } 02107 free(at); 02108 } 02109 02116 static void free_artifactlist(artifactlist *al) { 02117 artifactlist *nextal; 02118 02119 for (; al != NULL; al = nextal) { 02120 nextal = al->next; 02121 if (al->items) { 02122 free_artifact(al->items); 02123 } 02124 free(al); 02125 } 02126 } 02127 02131 void free_all_treasures(void) { 02132 treasurelist *tl, *next; 02133 02134 for (tl = first_treasurelist; tl != NULL; tl = next) { 02135 next = tl->next; 02136 if (tl->name) 02137 free_string(tl->name); 02138 if (tl->items) 02139 free_treasurestruct(tl->items); 02140 free(tl); 02141 } 02142 free_artifactlist(first_artifactlist); 02143 first_artifactlist = NULL; 02144 }