Atrinik Server 2.5
server/treasure.c
Go to the documentation of this file.
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 
00030 /* TREASURE_DEBUG does some checking on the treasurelists after loading.
00031  * It is useful for finding bugs in the treasures file.  Since it only
00032  * slows the startup some (and not actual game play), it is by default
00033  * left on */
00034 #define TREASURE_DEBUG
00035 
00036 /* TREASURE_VERBOSE enables copious output concerning artifact generation */
00037 /*#define TREASURE_VERBOSE*/
00038 
00039 #include <global.h>
00040 #include <spellist.h>
00041 #include <loader.h>
00042 
00044 char *coins[NUM_COINS + 1] =
00045 {
00046     "mitcoin",
00047     "goldcoin",
00048     "silvercoin",
00049     "coppercoin",
00050     NULL
00051 };
00052 
00054 archetype *coins_arch[NUM_COINS];
00055 
00057 #define ARTIFACT_TRIES 2
00058 
00060 #define CHANCE_FIX (-1)
00061 
00063 static archetype *ring_arch = NULL;
00065 static archetype *ring_arch_normal = NULL;
00067 static archetype *amulet_arch = NULL;
00069 static archetype *amulet_arch_normal = NULL;
00070 
00071 static treasure *load_treasure(FILE *fp, int *t_style, int *a_chance);
00072 static void change_treasure(struct _change_arch *ca, object *op);
00073 static treasurelist *get_empty_treasurelist();
00074 static treasure *get_empty_treasure();
00075 static void put_treasure(object *op, object *creator, int flags);
00076 static artifactlist *get_empty_artifactlist();
00077 static artifact *get_empty_artifact();
00078 static void check_treasurelist(treasure *t, treasurelist *tl);
00079 static void set_material_real(object *op, struct _change_arch *change_arch);
00080 static void create_money_table();
00081 static void create_all_treasures(treasure *t, object *op, int flag, int difficulty, int t_style, int a_chance, int tries, struct _change_arch *change_arch);
00082 static void create_one_treasure(treasurelist *tl, object *op, int flag, int difficulty, int t_style, int a_chance, int tries, struct _change_arch *change_arch);
00083 static int set_ring_bonus(object *op, int bonus, int level);
00084 static int get_magic(int diff);
00085 static void dump_monster_treasure_rec(const char *name, treasure *t, int depth);
00086 static void free_treasurestruct(treasure *t);
00087 static void free_charlinks(linked_char *lc);
00088 static void free_artifactlist();
00089 static void free_artifact(artifact *at);
00090 
00095 void load_treasures()
00096 {
00097     FILE *fp;
00098     char filename[MAX_BUF], buf[MAX_BUF], name[MAX_BUF];
00099     treasurelist *previous = NULL;
00100     treasure *t;
00101     int comp, t_style, a_chance;
00102 
00103     snprintf(filename, sizeof(filename), "%s/%s", settings.datadir, settings.treasures);
00104 
00105     if ((fp = open_and_uncompress(filename, 0, &comp)) == NULL)
00106     {
00107         LOG(llevError, "Can't open treasures file: %s\n", filename);
00108         return;
00109     }
00110 
00111     while (fgets(buf, MAX_BUF, fp) != NULL)
00112     {
00113         /* Ignore comments and blank lines */
00114         if (*buf == '#' || *buf == '\n')
00115         {
00116             continue;
00117         }
00118 
00119         if (sscanf(buf, "treasureone %s\n", name) || sscanf(buf, "treasure %s\n", name))
00120         {
00121             treasurelist *tl = get_empty_treasurelist();
00122             FREE_AND_COPY_HASH(tl->name, name);
00123 
00124             if (previous == NULL)
00125             {
00126                 first_treasurelist = tl;
00127             }
00128             else
00129             {
00130                 previous->next = tl;
00131             }
00132 
00133             previous = tl;
00134             t_style= T_STYLE_UNSET;
00135             a_chance = ART_CHANCE_UNSET;
00136             tl->items = load_treasure(fp, &t_style, &a_chance);
00137 
00138             if (tl->t_style == T_STYLE_UNSET)
00139             {
00140                 tl->t_style = t_style;
00141             }
00142 
00143             if (tl->artifact_chance == ART_CHANCE_UNSET)
00144             {
00145                 tl->artifact_chance = a_chance;
00146             }
00147 
00148             /* This is a one of the many items on the list should be generated.
00149              * Add up the chance total, and check to make sure the yes and no
00150              * fields of the treasures are not being used. */
00151             if (!strncmp(buf, "treasureone", 11))
00152             {
00153                 for (t = tl->items; t != NULL; t = t->next)
00154                 {
00155 #ifdef TREASURE_DEBUG
00156                     if (t->next_yes || t->next_no)
00157                     {
00158                         LOG(llevBug, "Treasure %s is one item, but on treasure %s\n", tl->name, t->item ? t->item->name : t->name);
00159                         LOG(llevBug, " the next_yes or next_no field is set");
00160                     }
00161 #endif
00162                     tl->total_chance += t->chance;
00163                 }
00164             }
00165         }
00166         else
00167         {
00168             LOG(llevError, "Treasure list didn't understand: %s\n", buf);
00169         }
00170     }
00171 
00172     close_and_delete(fp, comp);
00173 
00174 #ifdef TREASURE_DEBUG
00175     /* Perform some checks on how valid the treasure data actually is.
00176      * Verify that list transitions work (ie, the list that it is
00177      * supposed to transition to exists). Also, verify that at least the
00178      * name or archetype is set for each treasure element. */
00179     for (previous = first_treasurelist; previous != NULL; previous = previous->next)
00180     {
00181         check_treasurelist(previous->items, previous);
00182     }
00183 #endif
00184 
00185     create_money_table();
00186 }
00187 
00192 static void create_money_table()
00193 {
00194     int i;
00195 
00196     for (i = 0; coins[i]; i++)
00197     {
00198         coins_arch[i] = find_archetype(coins[i]);
00199 
00200         if (!coins_arch[i])
00201         {
00202             LOG(llevError, "create_money_table(): Can't find %s.\n", coins[i] ? coins[i] : "NULL");
00203             return;
00204         }
00205     }
00206 }
00207 
00215 static treasure *load_treasure(FILE *fp, int *t_style, int *a_chance)
00216 {
00217     char buf[MAX_BUF], *cp = NULL, variable[MAX_BUF];
00218     treasure *t = get_empty_treasure();
00219     int value, start_marker = 0, t_style2, a_chance2;
00220 
00221     nroftreasures++;
00222 
00223     while (fgets(buf, MAX_BUF, fp) != NULL)
00224     {
00225         if (*buf == '#')
00226         {
00227             continue;
00228         }
00229 
00230         if ((cp = strchr(buf, '\n')) != NULL)
00231         {
00232             *cp = '\0';
00233         }
00234 
00235         cp = buf;
00236 
00237         /* Skip blanks */
00238         while (!isalpha(*cp))
00239         {
00240             cp++;
00241         }
00242 
00243         if (sscanf(cp, "t_style %d", &value))
00244         {
00245             if (start_marker)
00246             {
00247                 t->t_style = value;
00248             }
00249             else
00250             {
00251                 /* No, it's global for the while treasure list entry */
00252                 *t_style = value;
00253             }
00254         }
00255         else if (sscanf(cp, "artifact_chance %d", &value))
00256         {
00257             if (start_marker)
00258             {
00259                 t->artifact_chance = value;
00260             }
00261             else
00262             {
00263                 /* No, it's global for the while treasure list entry */
00264                 *a_chance = value;
00265             }
00266         }
00267         else if (sscanf(cp, "arch %s", variable))
00268         {
00269             if ((t->item = find_archetype(variable)) == NULL)
00270             {
00271                 LOG(llevBug, "Treasure lacks archetype: %s\n", variable);
00272             }
00273 
00274             start_marker = 1;
00275         }
00276         else if (sscanf(cp, "list %s", variable))
00277         {
00278             start_marker = 1;
00279             FREE_AND_COPY_HASH(t->name, variable);
00280         }
00281         else if (sscanf(cp, "name %s", variable))
00282         {
00283             FREE_AND_COPY_HASH(t->change_arch.name, cp + 5);
00284         }
00285         else if (sscanf(cp, "title %s", variable))
00286         {
00287             FREE_AND_COPY_HASH(t->change_arch.title, cp + 6);
00288         }
00289         else if (sscanf(cp, "slaying %s", variable))
00290         {
00291             FREE_AND_COPY_HASH(t->change_arch.slaying, cp + 8);
00292         }
00293         else if (sscanf(cp, "item_race %d", &value))
00294         {
00295             t->change_arch.item_race = value;
00296         }
00297         else if (sscanf(cp, "quality %d", &value))
00298         {
00299             t->change_arch.quality = value;
00300         }
00301         else if (sscanf(cp, "quality_range %d", &value))
00302         {
00303             t->change_arch.quality_range = value;
00304         }
00305         else if (sscanf(cp, "material %d", &value))
00306         {
00307             t->change_arch.material = value;
00308         }
00309         else if (sscanf(cp, "material_quality %d", &value))
00310         {
00311             t->change_arch.material_quality = value;
00312         }
00313         else if (sscanf(cp, "material_range %d", &value))
00314         {
00315             t->change_arch.material_range = value;
00316         }
00317         else if (sscanf(cp, "chance_fix %d", &value))
00318         {
00319             t->chance_fix = (sint16) value;
00320             /* Important or the chance will stay 100% when not set to 0
00321              * in treasure list! */
00322             t->chance = 0;
00323         }
00324         else if (sscanf(cp, "chance %d", &value))
00325         {
00326             t->chance = (uint8) value;
00327         }
00328         else if (sscanf(cp, "nrof %d", &value))
00329         {
00330             t->nrof = (uint16) value;
00331         }
00332         else if (sscanf(cp, "magic %d", &value))
00333         {
00334             t->magic = value;
00335         }
00336         else if (sscanf(cp, "magic_fix %d", &value))
00337         {
00338             t->magic_fix = value;
00339         }
00340         else if (sscanf(cp, "magic_chance %d", &value))
00341         {
00342             t->magic_chance = value;
00343         }
00344         else if (sscanf(cp, "difficulty %d", &value))
00345         {
00346             t->difficulty = value;
00347         }
00348         else if (!strncmp(cp, "yes", 3))
00349         {
00350             t_style2 = T_STYLE_UNSET;
00351             a_chance2 = ART_CHANCE_UNSET;
00352             t->next_yes = load_treasure(fp, &t_style2, &a_chance2);
00353 
00354             if (t->next_yes->artifact_chance == ART_CHANCE_UNSET)
00355             {
00356                 t->next_yes->artifact_chance = a_chance2;
00357             }
00358 
00359             if (t->next_yes->t_style == T_STYLE_UNSET)
00360             {
00361                 t->next_yes->t_style = t_style2;
00362             }
00363         }
00364         else if (!strncmp(cp, "no", 2))
00365         {
00366             t_style2 = T_STYLE_UNSET;
00367             a_chance2 = ART_CHANCE_UNSET;
00368             t->next_no = load_treasure(fp, &t_style2, &a_chance2);
00369 
00370             if (t->next_no->artifact_chance == ART_CHANCE_UNSET)
00371             {
00372                 t->next_no->artifact_chance = a_chance2;
00373             }
00374 
00375             if (t->next_no->t_style == T_STYLE_UNSET)
00376             {
00377                 t->next_no->t_style = t_style2;
00378             }
00379         }
00380         else if (!strncmp(cp, "end", 3))
00381         {
00382             return t;
00383         }
00384         else if (!strncmp(cp, "more", 4))
00385         {
00386             t_style2 = T_STYLE_UNSET;
00387             a_chance2 = ART_CHANCE_UNSET;
00388             t->next = load_treasure(fp, &t_style2, &a_chance2);
00389 
00390             if (t->next->artifact_chance == ART_CHANCE_UNSET)
00391             {
00392                 t->next->artifact_chance = a_chance2;
00393             }
00394 
00395             if (t->next->t_style == T_STYLE_UNSET)
00396             {
00397                 t->next->t_style = t_style2;
00398             }
00399 
00400             return t;
00401         }
00402         else
00403         {
00404             LOG(llevBug, "Unknown treasure command: '%s', last entry %s\n", cp, t->name ? t->name : "null");
00405         }
00406     }
00407 
00408     LOG(llevBug, "Treasure %s lacks 'end'.>%s<\n", t->name ? t->name : "NULL", cp ? cp : "NULL");
00409 
00410     return t;
00411 }
00412 
00417 void init_artifacts()
00418 {
00419     static int has_been_inited = 0;
00420     archetype *atemp;
00421     long old_pos, file_pos;
00422     FILE *fp;
00423     char filename[MAX_BUF], buf[HUGE_BUF], *cp, *next;
00424     artifact *art = NULL;
00425     linked_char *tmp;
00426     int value, comp, none_flag = 0;
00427     size_t lcount;
00428     artifactlist *al;
00429     char buf_text[10 * 1024];
00430 
00431     if (has_been_inited)
00432     {
00433         return;
00434     }
00435 
00436     has_been_inited = 1;
00437 
00438     snprintf(filename, sizeof(filename), "%s/artifacts", settings.datadir);
00439     LOG(llevDebug, " reading artifacts from %s...", filename);
00440 
00441     if ((fp = open_and_uncompress(filename, 0, &comp)) == NULL)
00442     {
00443         LOG(llevError, "Can't open %s.\n", filename);
00444         return;
00445     }
00446 
00447     /* Start read in the artifact list */
00448     while (fgets(buf, sizeof(buf), fp) != NULL)
00449     {
00450         if (*buf == '#')
00451         {
00452             continue;
00453         }
00454 
00455         if ((cp = strchr(buf, '\n')) != NULL)
00456         {
00457             *cp = '\0';
00458         }
00459 
00460         /* Skip blank lines. */
00461         if (*buf == '\0')
00462         {
00463             continue;
00464         }
00465 
00466         cp = buf;
00467 
00468         /* Skip blanks */
00469         while (*cp == ' ')
00470         {
00471             cp++;
00472         }
00473 
00474         /* We have a single artifact */
00475         if (!strncmp(cp, "Allowed", 7))
00476         {
00477             art = get_empty_artifact();
00478             nrofartifacts++;
00479             none_flag = 0;
00480             cp = strchr(cp, ' ') + 1;
00481 
00482             if (!strcmp(cp, "all"))
00483             {
00484                 continue;
00485             }
00486 
00487             if (!strcmp(cp, "none"))
00488             {
00489                 none_flag = 1;
00490                 continue;
00491             }
00492 
00493             do
00494             {
00495                 nrofallowedstr++;
00496 
00497                 /* Trim left whitespace. */
00498                 while (isspace(*cp))
00499                 {
00500                     cp++;
00501                 }
00502 
00503                 if ((next = strchr(cp, ',')) != NULL)
00504                 {
00505                     *(next++) = '\0';
00506                 }
00507 
00508                 tmp = (linked_char *) malloc(sizeof(linked_char));
00509                 tmp->name = NULL;
00510                 FREE_AND_COPY_HASH(tmp->name, cp);
00511                 tmp->next = art->allowed;
00512                 art->allowed = tmp;
00513             }
00514             while ((cp = next) != NULL);
00515         }
00516         else if (sscanf(cp, "t_style %d", &value))
00517         {
00518             art->t_style = value;
00519         }
00520         else if (sscanf(cp, "chance %d", &value))
00521         {
00522             art->chance = (uint16) value;
00523         }
00524         else if (sscanf(cp, "difficulty %d", &value))
00525         {
00526             art->difficulty = (uint8) value;
00527         }
00528         else if (!strncmp(cp, "artifact", 8))
00529         {
00530             FREE_AND_COPY_HASH(art->name, cp + 9);
00531         }
00532         /* Chain a default arch to this treasure */
00533         else if (!strncmp(cp, "def_arch", 8))
00534         {
00535             if ((atemp = find_archetype(cp + 9)) == NULL)
00536             {
00537                 LOG(llevError, "init_artifacts(): Can't find def_arch %s.\n", cp + 9);
00538             }
00539 
00540             /* Ok, we have a name and an archetype */
00541 
00542             /* Store the non fake archetype name */
00543             FREE_AND_COPY_HASH(art->def_at_name, cp + 9);
00544             /* Copy the default arch */
00545             memcpy(&art->def_at, atemp, sizeof(archetype));
00546             ADD_REF_NOT_NULL_HASH(art->def_at.clone.name);
00547             ADD_REF_NOT_NULL_HASH(art->def_at.clone.title);
00548             ADD_REF_NOT_NULL_HASH(art->def_at.clone.race);
00549             ADD_REF_NOT_NULL_HASH(art->def_at.clone.slaying);
00550             ADD_REF_NOT_NULL_HASH(art->def_at.clone.msg);
00551             art->def_at.clone.arch = &art->def_at;
00552 
00553             /* we patch this .clone object after Object read with the artifact data.
00554              * in find_artifact, this archetype object will be returned. For the server,
00555              * it will be the same as it comes from the archlist, defined in the arches.
00556              * This will allow us the generate for every artifact a "default one" and we
00557              * will have always a non-magical base for every artifact */
00558         }
00559         /* All text after Object is now like an arch file until an end comes */
00560         else if (!strncmp(cp, "Object", 6))
00561         {
00562             old_pos = ftell(fp);
00563 
00564             if (!load_object(fp, &(art->def_at.clone), NULL, LO_LINEMODE, MAP_STYLE))
00565             {
00566                 LOG(llevError, "init_artifacts(): Could not load object.\n");
00567             }
00568 
00569             if (!art->name)
00570             {
00571                 LOG(llevError, "init_artifacts(): Object %s has no arch id name\n", art->def_at.clone.name);
00572             }
00573 
00574             if (!art->def_at_name)
00575             {
00576                 LOG(llevError, "init_artifacts(): Artifact %s has no def arch\n", art->name);
00577             }
00578 
00579             /* Ok, now let's catch and copy the commands to our artifacts
00580              * buffer. Let's do some file magic here - that's the easiest way. */
00581             file_pos = ftell(fp);
00582 
00583             if (fseek(fp, old_pos, SEEK_SET))
00584             {
00585                 LOG(llevError, "init_artifacts(): Could not fseek(fp, %ld, SEEK_SET).\n", old_pos);
00586             }
00587 
00588             /* The lex reader will bug when it don't get feed with a
00589              * <text>+0x0a+0 string. So, we do it here and in the lex
00590              * part we simply do a strlen and point to every part without
00591              * copying it. */
00592             lcount = 0;
00593 
00594             while (fgets(buf, sizeof(buf) - 3, fp))
00595             {
00596                 strcpy(buf_text + lcount, buf);
00597                 lcount += strlen(buf) + 1;
00598 
00599                 if (ftell(fp) == file_pos)
00600                 {
00601                     break;
00602                 }
00603 
00604                 /* Should not possible. */
00605                 if (ftell(fp) > file_pos)
00606                 {
00607                     LOG(llevError, "init_artifacts(): fgets() read too much data! (%ld - %ld)\n", file_pos, ftell(fp));
00608                 }
00609             }
00610 
00611             /* Now store the parse text in the artifacts list entry */
00612             if ((art->parse_text = malloc(lcount)) == NULL)
00613             {
00614                 LOG(llevError, "init_artifacts(): out of memory in ->parse_text (size %"FMT64U")\n", (uint64) lcount);
00615             }
00616 
00617             memcpy(art->parse_text, buf_text, lcount);
00618 
00619             /* Finally, change the archetype name of our fake arch to the
00620              * fake arch name. Without it, treasures will get the
00621              * original arch, not this. */
00622             FREE_AND_COPY_HASH(art->def_at.name, art->name);
00623             /* Now handle the <Allowed none> in the artifact to create
00624              * unique items or add them to the given type list. */
00625             al = find_artifactlist(none_flag == 0 ? art->def_at.clone.type : -1);
00626 
00627             if (al == NULL)
00628             {
00629                 al = get_empty_artifactlist();
00630                 al->type = none_flag == 0 ? art->def_at.clone.type : -1;
00631                 al->next = first_artifactlist;
00632                 first_artifactlist = al;
00633             }
00634 
00635             art->next = al->items;
00636             al->items = art;
00637         }
00638         else
00639         {
00640             LOG(llevBug, "Unknown input in artifact file: %s\n", buf);
00641         }
00642     }
00643 
00644     close_and_delete(fp, comp);
00645 
00646     for (al = first_artifactlist; al != NULL; al = al->next)
00647     {
00648         for (art = al->items; art != NULL; art = art->next)
00649         {
00650             /* We don't use our unique artifacts as pick table */
00651             if (al->type == -1)
00652             {
00653                 continue;
00654             }
00655 
00656             if (!art->chance)
00657             {
00658                 LOG(llevBug, "Artifact with no chance: %s\n", art->name);
00659             }
00660             else
00661             {
00662                 al->total_chance += art->chance;
00663             }
00664         }
00665     }
00666 
00667     LOG(llevDebug, "done.\n");
00668 }
00669 
00672 void init_archetype_pointers()
00673 {
00674     if (ring_arch_normal == NULL)
00675     {
00676         ring_arch_normal = find_archetype("ring_normal");
00677     }
00678 
00679     if (!ring_arch_normal)
00680     {
00681         LOG(llevBug, "Can't find 'ring_normal' arch (from artifacts)\n");
00682     }
00683 
00684     if (ring_arch == NULL)
00685     {
00686         ring_arch = find_archetype("ring_generic");
00687     }
00688 
00689     if (!ring_arch)
00690     {
00691         LOG(llevBug, "Can't find 'ring_generic' arch\n");
00692     }
00693 
00694     if (amulet_arch_normal == NULL)
00695     {
00696         amulet_arch_normal = find_archetype("amulet_normal");
00697     }
00698 
00699     if (!amulet_arch_normal)
00700     {
00701         LOG(llevBug, "Can't find 'amulet_normal' arch (from artifacts)\n");
00702     }
00703 
00704     if (amulet_arch == NULL)
00705     {
00706         amulet_arch = find_archetype("amulet_generic");
00707     }
00708 
00709     if (!amulet_arch)
00710     {
00711         LOG(llevBug, "Can't find 'amulet_generic' arch\n");
00712     }
00713 }
00714 
00718 static treasurelist *get_empty_treasurelist()
00719 {
00720     treasurelist *tl = (treasurelist *) malloc(sizeof(treasurelist));
00721 
00722     if (tl == NULL)
00723     {
00724         LOG(llevError, "get_empty_treasurelist(): Out of memory.\n");
00725     }
00726 
00727     tl->name = NULL;
00728     tl->next = NULL;
00729     tl->items = NULL;
00730     /* -2 is the "unset" marker and will be virtually handled as 0 which
00731      * can be overruled. */
00732     tl->t_style = T_STYLE_UNSET;
00733     tl->artifact_chance = ART_CHANCE_UNSET;
00734     tl->chance_fix = CHANCE_FIX;
00735     tl->total_chance = 0;
00736 
00737     return tl;
00738 }
00739 
00743 static treasure *get_empty_treasure()
00744 {
00745     treasure *t = (treasure *) malloc(sizeof(treasure));
00746 
00747     if (t == NULL)
00748     {
00749         LOG(llevError, "get_empty_treasure(): Out of memory.\n");
00750     }
00751 
00752     t->change_arch.item_race = -1;
00753     t->change_arch.name = NULL;
00754     t->change_arch.slaying = NULL;
00755     t->change_arch.title = NULL;
00756     /* -2 is the "unset" marker and will be virtually handled as 0 which
00757      * can be overruled. */
00758     t->t_style = T_STYLE_UNSET;
00759     t->change_arch.material = -1;
00760     t->change_arch.material_quality = -1;
00761     t->change_arch.material_range = -1;
00762     t->change_arch.quality = -1;
00763     t->change_arch.quality_range = -1;
00764     t->chance_fix = CHANCE_FIX;
00765     t->item = NULL;
00766     t->name = NULL;
00767     t->next = NULL;
00768     t->next_yes = NULL;
00769     t->next_no = NULL;
00770     t->artifact_chance = ART_CHANCE_UNSET;
00771     t->chance = 100;
00772     t->magic_fix = 0;
00773     t->difficulty = 0;
00774     t->magic_chance = 3;
00775     t->magic = 0;
00776     t->nrof = 0;
00777 
00778     return t;
00779 }
00780 
00785 treasurelist *find_treasurelist(const char *name)
00786 {
00787     const char *tmp = find_string(name);
00788     treasurelist *tl;
00789 
00790     /* Special cases - randomitems of none is to override default.  If
00791      * first_treasurelist is null, it means we are on the first pass of
00792      * of loading archetyps, so for now, just return - second pass will
00793      * init these values. */
00794     if (!strcmp(name, "none") || !first_treasurelist)
00795     {
00796         return NULL;
00797     }
00798 
00799     if (tmp != NULL)
00800     {
00801         for (tl = first_treasurelist; tl != NULL; tl = tl->next)
00802         {
00803             if (tmp == tl->name)
00804             {
00805                 return tl;
00806             }
00807         }
00808     }
00809 
00810     LOG(llevBug, "Bug: Couldn't find treasurelist %s\n", name);
00811     return NULL;
00812 }
00813 
00823 object *generate_treasure(treasurelist *t, int difficulty, int a_chance)
00824 {
00825     object *ob = get_object(), *tmp;
00826 
00827     create_treasure(t, ob, 0, difficulty, t->t_style, a_chance, 0, NULL);
00828 
00829     /* Don't want to free the object we are about to return */
00830     tmp = ob->inv;
00831 
00832     /* Remove from inv - no move off */
00833     if (tmp != NULL)
00834     {
00835         remove_ob(tmp);
00836     }
00837 
00838     if (ob->inv)
00839     {
00840         LOG(llevError, "generate_treasure(): Created multiple objects.\n");
00841     }
00842 
00843     return tmp;
00844 }
00845 
00856 void create_treasure(treasurelist *t, object *op, int flag, int difficulty, int t_style, int a_chance, int tries, struct _change_arch *arch_change)
00857 {
00858     if (tries++ > 100)
00859     {
00860         LOG(llevDebug, "create_treasure(): tries >100 for t-list %s.", t->name ? t->name : "<noname>");
00861         return;
00862     }
00863 
00864     if (t->t_style != T_STYLE_UNSET)
00865     {
00866         t_style = t->t_style;
00867     }
00868 
00869     if (t->artifact_chance != ART_CHANCE_UNSET)
00870     {
00871         a_chance = t->artifact_chance;
00872     }
00873 
00874     if (t->total_chance)
00875     {
00876         create_one_treasure(t, op, flag, difficulty, t_style, a_chance, tries, arch_change);
00877     }
00878     else
00879     {
00880         create_all_treasures(t->items, op, flag, difficulty, t_style, a_chance, tries, arch_change);
00881     }
00882 }
00883 
00894 static void create_all_treasures(treasure *t, object *op, int flag, int difficulty, int t_style, int a_chance, int tries, struct _change_arch *change_arch)
00895 {
00896     object *tmp;
00897 
00898     if (t->t_style != T_STYLE_UNSET)
00899     {
00900         t_style = t->t_style;
00901     }
00902 
00903     if (t->artifact_chance != ART_CHANCE_UNSET)
00904     {
00905         a_chance = t->artifact_chance;
00906     }
00907 
00908     if ((t->chance_fix != CHANCE_FIX && rndm_chance(t->chance_fix)) || (int) t->chance >= 100 || (rndm(1, 100) < (int) t->chance))
00909     {
00910         if (t->name)
00911         {
00912             if (t->name != shstr_cons.NONE && difficulty >= t->difficulty)
00913             {
00914                 create_treasure(find_treasurelist(t->name), op, flag, difficulty, t_style, a_chance, tries, change_arch ? change_arch : &t->change_arch);
00915             }
00916         }
00917         else if (difficulty >= t->difficulty)
00918         {
00919             if (IS_SYS_INVISIBLE(&t->item->clone) || !(flag & GT_INVISIBLE))
00920             {
00921                 if (t->item->clone.type != WEALTH)
00922                 {
00923                     tmp = arch_to_object(t->item);
00924 
00925                     if (t->nrof && tmp->nrof <= 1)
00926                     {
00927                         tmp->nrof = rndm(1, t->nrof);
00928                     }
00929 
00930                     /* Ret 1 = artifact is generated - don't overwrite anything here */
00931                     set_material_real(tmp, change_arch ? change_arch : &t->change_arch);
00932 
00933                     if (!fix_generated_item(&tmp, op, difficulty, a_chance, t_style, t->magic, t->magic_fix, t->magic_chance, flag))
00934                     {
00935                         change_treasure(change_arch ? change_arch : &t->change_arch, tmp);
00936                     }
00937 
00938                     put_treasure(tmp, op, flag);
00939 
00940                     /* If treasure is "identified", created items are too */
00941                     if (op->type == TREASURE && QUERY_FLAG(op, FLAG_IDENTIFIED))
00942                     {
00943                         SET_FLAG(tmp, FLAG_IDENTIFIED);
00944                     }
00945                 }
00946                 /* We have a wealth object - expand it to real money */
00947                 else
00948                 {
00949                     /* If t->magic is != 0, that's our value - if not use default setting */
00950                     int i, value = t->magic ? t->magic : t->item->clone.value;
00951 
00952                     value *= (difficulty / 2) + 1;
00953 
00954                     /* So we have 80% to 120% of the fixed value */
00955                     value = (int) ((float) value * 0.8f + (float) value * (rndm(1, 40) / 100.0f));
00956 
00957                     for (i = 0; i < NUM_COINS; i++)
00958                     {
00959                         if (value / coins_arch[i]->clone.value > 0)
00960                         {
00961                             tmp = get_object();
00962                             copy_object(&coins_arch[i]->clone, tmp, 0);
00963                             tmp->nrof = value / tmp->value;
00964                             value -= tmp->nrof * tmp->value;
00965                             put_treasure(tmp, op, flag);
00966                         }
00967                     }
00968                 }
00969             }
00970         }
00971 
00972         if (t->next_yes != NULL)
00973         {
00974             create_all_treasures(t->next_yes, op, flag, difficulty, (t->next_yes->t_style == T_STYLE_UNSET) ? t_style : t->next_yes->t_style, a_chance, tries, change_arch);
00975         }
00976     }
00977     else if (t->next_no != NULL)
00978     {
00979         create_all_treasures(t->next_no, op, flag, difficulty, (t->next_no->t_style == T_STYLE_UNSET) ? t_style : t->next_no->t_style, a_chance, tries, change_arch);
00980     }
00981 
00982     if (t->next != NULL)
00983     {
00984         create_all_treasures(t->next, op, flag, difficulty, (t->next->t_style == T_STYLE_UNSET) ? t_style : t->next->t_style, a_chance, tries, change_arch);
00985     }
00986 }
00987 
00999 static void create_one_treasure(treasurelist *tl, object *op, int flag, int difficulty, int t_style, int a_chance, int tries, struct _change_arch *change_arch)
01000 {
01001     int value, diff_tries = 0;
01002     treasure *t;
01003     object *tmp;
01004 
01005     if (tries++ > 100)
01006     {
01007         return;
01008     }
01009 
01010     /* Well, at some point we should rework this whole system... */
01011 create_one_treasure_again_jmp:
01012     if (diff_tries > 10)
01013     {
01014         return;
01015     }
01016 
01017     value = rndm(1, tl->total_chance) - 1;
01018 
01019     for (t = tl->items; t != NULL; t = t->next)
01020     {
01021         /* chance_fix will overrule the normal chance stuff!. */
01022         if (t->chance_fix != CHANCE_FIX)
01023         {
01024             if (rndm_chance(t->chance_fix))
01025             {
01026                 /* Only when allowed, we go on! */
01027                 if (difficulty >= t->difficulty)
01028                 {
01029                     value = 0;
01030                     break;
01031                 }
01032 
01033                 /* Ok, difficulty is bad let's try again or break! */
01034                 if (tries++ > 100)
01035                 {
01036                     return;
01037                 }
01038 
01039                 diff_tries++;
01040                 goto create_one_treasure_again_jmp;
01041             }
01042 
01043             if (!t->chance)
01044             {
01045                 continue;
01046             }
01047         }
01048 
01049         value -= t->chance;
01050 
01051         /* We got one! */
01052         if (value <= 0)
01053         {
01054             /* Only when allowed, we go on! */
01055             if (difficulty >= t->difficulty)
01056             {
01057                 break;
01058             }
01059 
01060             /* Ok, difficulty is bad let's try again or break! */
01061             if (tries++ > 100)
01062             {
01063                 return;
01064             }
01065 
01066             diff_tries++;
01067             goto create_one_treasure_again_jmp;
01068         }
01069     }
01070 
01071     if (t->t_style != T_STYLE_UNSET)
01072     {
01073         t_style = t->t_style;
01074     }
01075 
01076     if (t->artifact_chance != ART_CHANCE_UNSET)
01077     {
01078         a_chance = t->artifact_chance;
01079     }
01080 
01081     if (!t || value > 0)
01082     {
01083         LOG(llevBug, "create_one_treasure: got null object or not able to find treasure - tl:%s op:%s\n", tl ? tl->name : "(null)", op ? op->name : "(null)");
01084         return;
01085     }
01086 
01087     if (t->name)
01088     {
01089         if (t->name == shstr_cons.NONE)
01090         {
01091             return;
01092         }
01093 
01094         if (difficulty >= t->difficulty)
01095         {
01096             create_treasure(find_treasurelist(t->name), op, flag, difficulty, t_style, a_chance, tries, change_arch);
01097         }
01098         else if (t->nrof)
01099         {
01100             create_one_treasure(tl, op, flag, difficulty, t_style, a_chance, tries, change_arch);
01101         }
01102 
01103         return;
01104     }
01105 
01106     if (IS_SYS_INVISIBLE(&t->item->clone) || flag != GT_INVISIBLE)
01107     {
01108         if (t->item->clone.type != WEALTH)
01109         {
01110             tmp = arch_to_object(t->item);
01111 
01112             if (t->nrof && tmp->nrof <= 1)
01113             {
01114                 tmp->nrof = rndm(1, t->nrof);
01115             }
01116 
01117             set_material_real(tmp, change_arch ? change_arch : &t->change_arch);
01118 
01119             if (!fix_generated_item(&tmp, op, difficulty, a_chance, (t->t_style == T_STYLE_UNSET) ? t_style : t->t_style, t->magic, t->magic_fix, t->magic_chance, flag))
01120             {
01121                 change_treasure(change_arch ? change_arch : &t->change_arch, tmp);
01122             }
01123 
01124             put_treasure(tmp, op, flag);
01125 
01126             /* If treasure is "identified", created items are too */
01127             if (op->type == TREASURE && QUERY_FLAG(op, FLAG_IDENTIFIED))
01128             {
01129                 SET_FLAG(tmp, FLAG_IDENTIFIED);
01130             }
01131         }
01132         /* We have a wealth object - expand it to real money */
01133         else
01134         {
01135             /* If t->magic is != 0, that's our value - if not use default setting */
01136             int i;
01137 
01138             value = t->magic ? t->magic : t->item->clone.value;
01139             value *= difficulty;
01140 
01141             /* So we have 80% to 120% of the fixed value */
01142             value = (int) ((float) value * 0.8f + (float) value * (rndm(1, 40) / 100.0f));
01143 
01144             for (i = 0; i < NUM_COINS; i++)
01145             {
01146                 if (value / coins_arch[i]->clone.value > 0)
01147                 {
01148                     tmp = get_object();
01149                     copy_object(&coins_arch[i]->clone, tmp, 0);
01150                     tmp->nrof = value / tmp->value;
01151                     value -= tmp->nrof * tmp->value;
01152                     put_treasure(tmp, op, flag);
01153                 }
01154             }
01155         }
01156     }
01157 }
01158 
01164 static void put_treasure(object *op, object *creator, int flags)
01165 {
01166     if (flags & GT_ENVIRONMENT)
01167     {
01168         op->x = creator->x;
01169         op->y = creator->y;
01170         insert_ob_in_map(op, creator->map, op, INS_NO_MERGE | INS_NO_WALK_ON);
01171     }
01172     else
01173     {
01174         object *tmp;
01175 
01176         op = insert_ob_in_ob(op, creator);
01177 
01178         if ((flags & GT_UPDATE_INV) && (tmp = is_player_inv(creator)) != NULL)
01179         {
01180             esrv_send_item(tmp, op);
01181         }
01182     }
01183 }
01184 
01190 static void change_treasure(struct _change_arch *ca, object *op)
01191 {
01192     if (ca->name)
01193     {
01194         FREE_AND_COPY_HASH(op->name, ca->name);
01195     }
01196 
01197     if (ca->title)
01198     {
01199         FREE_AND_COPY_HASH(op->title, ca->title);
01200     }
01201 
01202     if (ca->slaying)
01203     {
01204         FREE_AND_COPY_HASH(op->slaying, ca->slaying);
01205     }
01206 }
01207 
01219 static void set_magic(int difficulty, object *op, int max_magic, int fix_magic, int chance_magic, int flags)
01220 {
01221     int i;
01222 
01223     /* If we have a fixed value, force it */
01224     if (fix_magic)
01225     {
01226         i = fix_magic;
01227     }
01228     else
01229     {
01230         i = 0;
01231 
01232         /* chance_magic 0 means always no magic bonus */
01233         if (rndm(1, 100) <= chance_magic || rndm(1, 200) <= difficulty)
01234         {
01235             i = rndm(1, abs(max_magic));
01236 
01237             if (max_magic < 0)
01238             {
01239                 i = -i;
01240             }
01241         }
01242     }
01243 
01244     if ((flags & GT_ONLY_GOOD) && i < 0)
01245     {
01246         i = 0;
01247     }
01248 
01249     set_abs_magic(op, i);
01250 
01251     if (i < 0)
01252     {
01253         SET_FLAG(op, FLAG_CURSED);
01254     }
01255 
01256     if (i != 0)
01257     {
01258         SET_FLAG(op, FLAG_IS_MAGICAL);
01259     }
01260 }
01261 
01270 void set_abs_magic(object *op, int magic)
01271 {
01272     if (!magic)
01273     {
01274         return;
01275     }
01276 
01277     SET_FLAG(op, FLAG_IS_MAGICAL);
01278 
01279     op->magic = magic;
01280 
01281     if (op->arch)
01282     {
01283         if (magic == 1)
01284         {
01285             op->value += 5300;
01286         }
01287         else if (magic == 2)
01288         {
01289             op->value += 12300;
01290         }
01291         else if (magic == 3)
01292         {
01293             op->value += 24300;
01294         }
01295         else if (magic == 4)
01296         {
01297             op->value += 52300;
01298         }
01299         else
01300         {
01301             op->value += 88300;
01302         }
01303 
01304         if (op->type == ARMOUR)
01305         {
01306             ARMOUR_SPEED(op) = (ARMOUR_SPEED(&op->arch->clone) * (100 + magic * 10)) / 100;
01307         }
01308 
01309         /* You can't just check the weight always */
01310         if (magic < 0 && !rndm(0, 2))
01311         {
01312             magic = (-magic);
01313         }
01314 
01315         op->weight = (op->arch->clone.weight * (100 - magic * 10)) / 100;
01316     }
01317     else
01318     {
01319         if (op->type == ARMOUR)
01320         {
01321             ARMOUR_SPEED(op) = (ARMOUR_SPEED(op) * (100 + magic * 10)) / 100;
01322         }
01323 
01324         /* You can't just check the weight always */
01325         if (magic < 0 && !rndm(0, 2))
01326         {
01327             magic = (-magic);
01328         }
01329 
01330         op->weight = (op->weight * (100 - magic * 10)) / 100;
01331     }
01332 }
01333 
01350 static int set_ring_bonus(object *op, int bonus, int level)
01351 {
01352     int tmp, r, off;
01353     off = (level >= 50 ? 1 : 0) + (level >= 60 ? 1 : 0) + (level >= 70 ? 1 : 0) + (level >= 80 ? 1 : 0);
01354 
01355     /* Let's repeat, too lazy for a loop */
01356 set_ring_bonus_jump1:
01357     r = RANDOM() % (bonus > 0 ? 25 : 13);
01358 
01359     SET_FLAG(op, FLAG_IS_MAGICAL);
01360 
01361     if (op->type == AMULET)
01362     {
01363         if (!(RANDOM() % 21))
01364         {
01365             r = 20 + RANDOM() % 2;
01366         }
01367         else if (!(RANDOM() % 20))
01368         {
01369             tmp = RANDOM() % 3;
01370 
01371             if (tmp == 2)
01372             {
01373                 r = 0;
01374             }
01375             else if (!tmp)
01376             {
01377                 r = 11;
01378             }
01379             else
01380             {
01381                 r = 12;
01382             }
01383         }
01384         else if (RANDOM() & 2)
01385         {
01386             if (RANDOM() & 2)
01387             {
01388                 r = 10;
01389             }
01390             else
01391             {
01392                 r = 8;
01393             }
01394         }
01395         else
01396         {
01397             r = 13 + RANDOM() % 7;
01398         }
01399     }
01400 
01401     switch (r % 25)
01402     {
01403         /* We are creating hp stuff! */
01404         case 0:
01405             tmp = 5;
01406 
01407             if (level < 5)
01408             {
01409                 tmp += RANDOM() % 10;
01410 
01411                 if (bonus > 0)
01412                 {
01413                     op->value = (int) ((float) op->value * 1.3f);
01414                 }
01415             }
01416             else if (level < 10)
01417             {
01418                 tmp += 10 + RANDOM() % 10;
01419 
01420                 if (bonus > 0)
01421                 {
01422                     op->value = (int) ((float) op->value * 1.32f);
01423                 }
01424             }
01425             else if (level < 15)
01426             {
01427                 tmp += 15 + RANDOM() % 20;
01428 
01429                 if (bonus > 0)
01430                 {
01431                     op->value = (int) ((float) op->value * 1.34f);
01432                 }
01433             }
01434             else if (level < 20)
01435             {
01436                 tmp += 20 + RANDOM() % 21;
01437 
01438                 if (bonus > 0)
01439                 {
01440                     op->value = (int) ((float) op->value * 1.36f);
01441                 }
01442             }
01443             else if (level < 25)
01444             {
01445                 tmp += 25 + RANDOM() % 23;
01446 
01447                 if (bonus > 0)
01448                 {
01449                     op->value = (int) ((float) op->value * 1.38f);
01450                 }
01451             }
01452             else if (level < 30)
01453             {
01454                 tmp += 30 + RANDOM() % 25;
01455 
01456                 if (bonus > 0)
01457                 {
01458                     op->value = (int) ((float) op->value * 1.4f);
01459                 }
01460             }
01461             else if (level < 40)
01462             {
01463                 tmp += 40 + RANDOM() % 30;
01464 
01465                 if (bonus > 0)
01466                 {
01467                     op->value = (int) ((float) op->value * 1.42f);
01468                 }
01469             }
01470             else
01471             {
01472                 tmp += (int) ((double) level * 0.65) + 50 + RANDOM() % 40;
01473 
01474                 if (bonus > 0)
01475                 {
01476                     op->value = (int) ((float) op->value * 1.44f);
01477                 }
01478             }
01479 
01480             if (bonus < 0)
01481             {
01482                 tmp = -tmp;
01483             }
01484             else
01485             {
01486                 op->item_level = (int) ((double) level * (0.5 + ((double) (RANDOM() % 40) / 100.0)));
01487             }
01488 
01489             op->stats.maxhp = tmp;
01490             break;
01491 
01492         /* Stats */
01493         case 1:
01494         case 2:
01495         case 3:
01496         case 4:
01497         case 5:
01498         case 6:
01499             set_attr_value(&op->stats, r, (sint8) (bonus + get_attr_value(&op->stats, r)));
01500             break;
01501 
01502         case 7:
01503             op->stats.dam += bonus;
01504 
01505             if (bonus > 0 && (RANDOM() % 20 > 16 ? 1 : 0))
01506             {
01507                 op->value = (int) ((float) op->value * 1.3f);
01508                 op->stats.dam++;
01509             }
01510 
01511             break;
01512 
01513         case 8:
01514             op->stats.wc += bonus;
01515 
01516             if (bonus > 0 && (RANDOM() % 20 > 16 ? 1 : 0))
01517             {
01518                 op->value = (int) ((float) op->value * 1.3f);
01519                 op->stats.wc++;
01520             }
01521 
01522             break;
01523 
01524         /* Hunger/sustenance */
01525         case 9:
01526             op->stats.food += bonus;
01527 
01528             if (bonus > 0 && (RANDOM() % 20 > 16 ? 1 : 0))
01529             {
01530                 op->value = (int) ((float) op->value * 1.2f);
01531                 op->stats.food++;
01532             }
01533 
01534             break;
01535 
01536         case 10:
01537             op->stats.ac += bonus;
01538 
01539             if (bonus > 0 && (RANDOM() % 20 > 16 ? 1 : 0))
01540             {
01541                 op->value = (int) ((float) op->value * 1.3f);
01542                 op->stats.ac++;
01543             }
01544 
01545             break;
01546 
01547         case 11:
01548         case 12:
01549             if (!RANDOM() % 3)
01550             {
01551                 goto make_prot_items;
01552             }
01553 
01554             tmp = 3;
01555 
01556             if (level < 5)
01557             {
01558                 tmp += RANDOM() % 3;
01559 
01560                 if (bonus > 0)
01561                 {
01562                     op->value = (int) ((float) op->value * 1.3f);
01563                 }
01564             }
01565             else if (level < 10)
01566             {
01567                 tmp += 3 + RANDOM() % 4;
01568 
01569                 if (bonus > 0)
01570                 {
01571                     op->value = (int) ((float) op->value * 1.32f);
01572                 }
01573             }
01574             else if (level < 15)
01575             {
01576                 tmp += 4 + RANDOM() % 6;
01577 
01578                 if (bonus > 0)
01579                 {
01580                     op->value = (int) ((float) op->value * 1.34f);
01581                 }
01582             }
01583             else if (level < 20)
01584             {
01585                 tmp += 6 + RANDOM() % 8;
01586 
01587                 if (bonus > 0)
01588                 {
01589                     op->value = (int) ((float) op->value * 1.36f);
01590                 }
01591             }
01592             else if (level < 25)
01593             {
01594                 tmp += 8 + RANDOM() % 10;
01595 
01596                 if (bonus > 0)
01597                 {
01598                     op->value = (int) ((float) op->value * 1.38f);
01599                 }
01600             }
01601             else if (level < 33)
01602             {
01603                 tmp += 10 + RANDOM() % 12;
01604 
01605                 if (bonus > 0)
01606                 {
01607                     op->value = (int) ((float) op->value * 1.4f);
01608                 }
01609             }
01610             else if (level < 44)
01611             {
01612                 tmp += 15 + RANDOM() % 15;
01613 
01614                 if (bonus > 0)
01615                 {
01616                     op->value = (int) ((float) op->value * 1.42f);
01617                 }
01618             }
01619             else
01620             {
01621                 tmp += (int) ((double) level * 0.53) + 20 + RANDOM() % 20;
01622 
01623                 if (bonus > 0)
01624                 {
01625                     op->value = (int) ((float) op->value * 1.44f);
01626                 }
01627             }
01628 
01629             if (bonus < 0)
01630             {
01631                 tmp = -tmp;
01632             }
01633             else
01634             {
01635                 op->item_level = (int) ((double) level * (0.5 + ((double) (RANDOM() % 40) / 100.0)));
01636             }
01637 
01638             op->stats.maxsp = tmp;
01639             break;
01640 
01641         case 13:
01642 make_prot_items:
01643         case 14:
01644         case 15:
01645         case 16:
01646         case 17:
01647         case 18:
01648         case 19:
01649         {
01650             int b = 5 + FABS(bonus), val, protect = RANDOM() % (LAST_PROTECTION - 4 + off);
01651 
01652             /* Roughly generate a bonus between 100 and 35 (depending on the bonus) */
01653             val = 10 + RANDOM() % b + RANDOM() % b + RANDOM() % b + RANDOM() % b;
01654 
01655             /* Cursed items need to have higher negative values to equal
01656              * out with positive values for how protections work out. Put
01657              * another little random element in since that they don't
01658              * always end up with even values. */
01659             if (bonus < 0)
01660             {
01661                 val = 2 * -val - RANDOM() % b;
01662             }
01663 
01664             /* Upper limit */
01665             if (val > 35)
01666             {
01667                 val = 35;
01668             }
01669 
01670             b = 0;
01671 
01672             while (op->protection[protect] != 0)
01673             {
01674                 /* Not able to find a free protection */
01675                 if (b++ >= 4)
01676                 {
01677                     goto set_ring_bonus_jump1;
01678                 }
01679 
01680                 protect = RANDOM() % (LAST_PROTECTION - 4 + off);
01681             }
01682 
01683             op->protection[protect] = val;
01684             break;
01685         }
01686 
01687         case 20:
01688             if (op->type == AMULET)
01689             {
01690                 SET_FLAG(op, FLAG_REFL_SPELL);
01691                 op->value *= 11;
01692             }
01693             else
01694             {
01695                 /* Regenerate hit points */
01696                 op->stats.hp += bonus;
01697                 op->value = (int) ((float) op->value * 1.3f);
01698 
01699                 if (bonus > 0 && (RANDOM() % 20 > 16 ? 1 : 0))
01700                 {
01701                     op->value = (int) ((float) op->value * 1.3f);
01702                     op->stats.hp++;
01703                 }
01704             }
01705 
01706             break;
01707 
01708         case 21:
01709             if (op->type == AMULET)
01710             {
01711                 SET_FLAG(op, FLAG_REFL_MISSILE);
01712                 op->value *= 9;
01713             }
01714             else
01715             {
01716                 /* Regenerate spell points */
01717                 op->stats.sp += bonus;
01718                 op->value = (int) ((float) op->value * 1.35f);
01719 
01720                 if (bonus > 0 && (RANDOM() % 20 > 16 ? 1 : 0))
01721                 {
01722                     op->value = (int) ((float) op->value * 1.35f);
01723                     op->stats.sp++;
01724                 }
01725             }
01726 
01727             break;
01728 
01729         case 22:
01730             /* Regenerate grace */
01731             op->stats.grace += bonus;
01732             op->value = (int) ((float) op->value * 1.35f);
01733 
01734             if (bonus > 0 && (RANDOM() % 20 > 16 ? 1 : 0))
01735             {
01736                 op->value = (int) ((float) op->value * 1.35f);
01737                 op->stats.grace++;
01738             }
01739 
01740             break;
01741 
01742         default:
01743             if (!bonus)
01744             {
01745                 bonus = 1;
01746             }
01747 
01748             /* Speed! */
01749             op->stats.exp += bonus;
01750             op->value = (int) ((float) op->value * 1.4f);
01751             break;
01752     }
01753 
01754     if (bonus > 0)
01755     {
01756         op->value = (int) ((float) op->value * 2.0f * (float) bonus);
01757     }
01758     else
01759     {
01760         op->value = -(op->value * 2 * bonus) / 2;
01761     }
01762 
01763     /* Check possible overflow */
01764     if (op->value < 0)
01765     {
01766         op->value = 0;
01767     }
01768 
01769     return 1;
01770 }
01771 
01775 static void set_ring_item_power(object *ob)
01776 {
01777     int tmp, i;
01778 
01779     if (ob->stats.maxhp > 0)
01780     {
01781         ob->item_power += ob->stats.maxhp / 50;
01782     }
01783 
01784     if (ob->stats.maxsp > 0)
01785     {
01786         ob->item_power += ob->stats.maxsp / 50;
01787     }
01788 
01789     if (ob->stats.exp >= 2)
01790     {
01791         ob->item_power += ob->stats.exp - 1;
01792     }
01793 
01794     if (ob->stats.ac > 0)
01795     {
01796         ob->item_power += ob->stats.ac;
01797     }
01798 
01799     if (ob->stats.dam > 0)
01800     {
01801         ob->item_power += ob->stats.dam;
01802     }
01803 
01804     if (ob->stats.wc > 0)
01805     {
01806         ob->item_power += ob->stats.wc;
01807     }
01808 
01809     if (QUERY_FLAG(ob, FLAG_REFL_MISSILE))
01810     {
01811         ob->item_power++;
01812     }
01813 
01814     if (QUERY_FLAG(ob, FLAG_REFL_SPELL))
01815     {
01816         ob->item_power += 2;
01817     }
01818 
01819     if (ob->stats.hp > 0)
01820     {
01821         ob->item_power += ob->stats.hp;
01822     }
01823 
01824     if (ob->stats.sp > 0)
01825     {
01826         ob->item_power += ob->stats.sp + 1;
01827     }
01828 
01829     if (ob->stats.grace > 0)
01830     {
01831         ob->item_power += ob->stats.grace + 2;
01832     }
01833 
01834     tmp = 0;
01835 
01836     for (i = 0; i < NROFATTACKS; i++)
01837     {
01838         tmp += ob->protection[i];
01839     }
01840 
01841     if (tmp > 0)
01842     {
01843         ob->item_power += (tmp + 10) / 20;
01844     }
01845 
01846     for (i = 0; i < NUM_STATS; i++)
01847     {
01848         tmp = get_attr_value(&ob->stats, i);
01849 
01850         if (tmp >= 2)
01851         {
01852             ob->item_power += tmp - 1;
01853         }
01854     }
01855 }
01856 
01866 static int get_magic(int diff)
01867 {
01868     int i;
01869 
01870     if (diff < 3)
01871     {
01872         diff = 3;
01873     }
01874 
01875     for (i = 0; i < 4; i++)
01876     {
01877         if (rndm(0, diff - 1))
01878         {
01879             return i;
01880         }
01881     }
01882 
01883     return 4;
01884 }
01885 
01894 static int get_random_spell(int level, int flags)
01895 {
01896     int i, num_spells = 0, possible_spells[NROFREALSPELLS];
01897 
01898     /* Collect the list of spells we can choose from. */
01899     for (i = 0; i < NROFREALSPELLS; i++)
01900     {
01901         if (level >= spells[i].level && spells[i].spell_use & flags)
01902         {
01903             possible_spells[num_spells] = i;
01904             num_spells++;
01905         }
01906     }
01907 
01908     /* If we found any spells we can use, select randomly. */
01909     if (num_spells)
01910     {
01911         return possible_spells[rndm(1, num_spells) - 1];
01912     }
01913 
01914     /* If we are here, there is no fitting spell. */
01915     return SP_NO_SPELL;
01916 }
01917 
01922 static void add_random_race(object *op)
01923 {
01924     ob_race *race = race_get_random();
01925 
01926     if (race)
01927     {
01928         FREE_AND_COPY_HASH(op->slaying, race->name);
01929     }
01930 }
01931 
01932 #define DICE2 (get_magic(2) == 2 ? 2 : 1)
01933 
01947 int fix_generated_item(object **op_ptr, object *creator, int difficulty, int a_chance, int t_style, int max_magic, int fix_magic, int chance_magic, int flags)
01948 {
01949     /* Just to make things easy */
01950     object *op = *op_ptr;
01951     int temp, retval = 0, was_magic = op->magic;
01952     int too_many_tries = 0, is_special = 0;
01953 
01954     /* Safety and to prevent polymorphed objects giving attributes */
01955     if (!creator || creator->type == op->type)
01956     {
01957         creator = op;
01958     }
01959 
01960     if (difficulty < 1)
01961     {
01962         difficulty = 1;
01963     }
01964 
01965     if (op->type != POTION && op->type != SCROLL && op->type != FOOD)
01966     {
01967         if ((!op->magic && max_magic) || fix_magic)
01968         {
01969             set_magic(difficulty, op, max_magic, fix_magic, chance_magic, flags);
01970         }
01971 
01972         if (a_chance != 0)
01973         {
01974             if ((!was_magic && rndm_chance(CHANCE_FOR_ARTIFACT)) || op->type == HORN || difficulty >= 999 || rndm(1, 100) <= a_chance)
01975             {
01976                 retval = generate_artifact(op, difficulty, t_style, a_chance);
01977             }
01978         }
01979     }
01980 
01981     /* Only modify object if not special */
01982     if (!op->title || op->type == RUNE)
01983     {
01984         switch (op->type)
01985         {
01986             /* We create scrolls now in artifacts file too */
01987             case SCROLL:
01988                 while (op->stats.sp == SP_NO_SPELL)
01989                 {
01990                     generate_artifact(op, difficulty, t_style, 100);
01991 
01992                     if (too_many_tries++ > 3)
01993                     {
01994                         break;
01995                     }
01996                 }
01997 
01998                 /* Ok, forget it... */
01999                 if (op->stats.sp == SP_NO_SPELL)
02000                 {
02001                     break;
02002                 }
02003 
02004                 /* Marks as magical */
02005                 SET_FLAG(op, FLAG_IS_MAGICAL);
02006                 /* Charges */
02007                 op->stats.food = rndm(1, spells[op->stats.sp].charges);
02008                 temp = (((difficulty * 100) - (difficulty * 20)) + (difficulty * rndm(0, 34))) / 100;
02009 
02010                 if (temp < 1)
02011                 {
02012                     temp = 1;
02013                 }
02014                 else if (temp > MAXLEVEL)
02015                 {
02016                     temp = MAXLEVEL;
02017                 }
02018 
02019                 op->level = temp;
02020 
02021                 if (temp < spells[op->stats.sp].level)
02022                 {
02023                     temp = spells[op->stats.sp].level;
02024                 }
02025 
02026                 break;
02027 
02028             case POTION:
02029             {
02030                 /* Balm */
02031                 if (!op->sub_type)
02032                 {
02033                     if ((op->stats.sp = get_random_spell(difficulty, SPELL_USE_BALM)) == SP_NO_SPELL)
02034                     {
02035                         break;
02036                     }
02037 
02038                     SET_FLAG(op, FLAG_IS_MAGICAL);
02039                     op->value = (int) (150.0f * spells[op->stats.sp].value_mul);
02040                 }
02041                 /* Dust */
02042                 else if (op->sub_type > 128)
02043                 {
02044                     if ((op->stats.sp = get_random_spell(difficulty, SPELL_USE_DUST)) == SP_NO_SPELL)
02045                     {
02046                         break;
02047                     }
02048 
02049                     SET_FLAG(op, FLAG_IS_MAGICAL);
02050                     op->value = (int) (125.0f * spells[op->stats.sp].value_mul);
02051                 }
02052                 else
02053                 {
02054                     while (!(is_special = special_potion(op)) && op->stats.sp == SP_NO_SPELL)
02055                     {
02056                         generate_artifact(op, difficulty, t_style, 100);
02057 
02058                         if (too_many_tries++ > 3)
02059                         {
02060                             goto jump_break1;
02061                         }
02062                     }
02063                 }
02064 
02065                 temp = (((difficulty * 100) - (difficulty * 20)) + (difficulty * rndm(0, 34))) / 100;
02066 
02067                 if (temp < 1)
02068                 {
02069                     temp = 1;
02070                 }
02071                 else if (temp > MAXLEVEL)
02072                 {
02073                     temp = MAXLEVEL;
02074                 }
02075 
02076                 if (!is_special && temp < spells[op->stats.sp].level)
02077                 {
02078                     temp = spells[op->stats.sp].level;
02079                 }
02080 
02081                 op->level = temp;
02082 
02083                 /* Chance to make special potions damned or cursed. The
02084                  * chance is somewhat high to make the game more
02085                  * difficult. Applying this potions without identify is a
02086                  * great risk! */
02087                 if (is_special && !(flags & GT_ONLY_GOOD))
02088                 {
02089                     if (rndm_chance(2))
02090                     {
02091                         SET_FLAG(op, (rndm_chance(2) ? FLAG_CURSED : FLAG_DAMNED));
02092                     }
02093                 }
02094 
02095 jump_break1:
02096                 break;
02097             }
02098 
02099             case AMULET:
02100                 /* Since it's not just decoration */
02101                 if (op->arch == amulet_arch)
02102                 {
02103                     op->value *= 5;
02104                 }
02105 
02106             case RING:
02107                 if (op->arch == NULL)
02108                 {
02109                     remove_ob(op);
02110                     *op_ptr = op = NULL;
02111                     break;
02112                 }
02113 
02114                 /* It's a special artifact! For these items, there is no point
02115                  * carrying on, as the next bit is for regular rings only. */
02116                 if (op->arch != ring_arch && op->arch != amulet_arch)
02117                 {
02118                     break;
02119                 }
02120 
02121                 /* We have no special ring or amulet - now we create one. We first
02122                  * get us a value, material and face changed prototype.
02123                  * Then we cast the powers over it. */
02124 
02125                 /* This is called before we inserted it in the map or elsewhere */
02126                 if (!QUERY_FLAG(op, FLAG_REMOVED))
02127                 {
02128                     remove_ob(op);
02129                 }
02130 
02131                 /* Here we give the ring or amulet a random material.
02132                  * First we use a special arch for this. Only this archtype is
02133                  * allowed to be masked with a special material artifact. */
02134                 if (op->arch == ring_arch)
02135                 {
02136                     *op_ptr = op = arch_to_object(ring_arch_normal);
02137                 }
02138                 else
02139                 {
02140                     *op_ptr = op = arch_to_object(amulet_arch_normal);
02141                 }
02142 
02143                 generate_artifact(op, difficulty, t_style, 99);
02144 
02145                 /* Now we add the random boni/mali to the item */
02146                 if (!(flags & GT_ONLY_GOOD) && rndm_chance(4))
02147                 {
02148                     SET_FLAG(op, FLAG_CURSED);
02149                 }
02150 
02151                 set_ring_bonus(op, QUERY_FLAG(op, FLAG_CURSED) ? -DICE2 : DICE2, difficulty);
02152 
02153                 if (op->type == RING)
02154                 {
02155                     if (rndm_chance(4))
02156                     {
02157                         int d = (!rndm_chance(2) || QUERY_FLAG(op, FLAG_CURSED)) ? -DICE2 : DICE2;
02158 
02159                         if (set_ring_bonus(op, d, difficulty))
02160                         {
02161                             op->value = (int) ((float) op->value * 1.95f);
02162                         }
02163 
02164                         if (rndm_chance(4))
02165                         {
02166                             d = (!rndm_chance(3) || QUERY_FLAG(op, FLAG_CURSED)) ? -DICE2 : DICE2;
02167 
02168                             if (set_ring_bonus(op, d, difficulty))
02169                             {
02170                                 op->value = (int) ((float) op->value * 1.95f);
02171                             }
02172                         }
02173                     }
02174                 }
02175 
02176                 set_ring_item_power(op);
02177 
02178                 break;
02179 
02180             case BOOK:
02181                 /* Is it an empty book? If yes let's make a special msg
02182                  * for it, and tailor its properties based on the creator
02183                  * and/or map level we found it on. */
02184                 if (!op->msg && !rndm_chance(10))
02185                 {
02186                     int level = 5;
02187 
02188                     /* Set the book level properly. */
02189                     if (creator->level == 0 || IS_LIVE(creator))
02190                     {
02191                         object *ob;
02192 
02193                         for (ob = creator; ob && ob->env; ob = ob->env)
02194                         {
02195                         }
02196 
02197                         if (ob->map && ob->map->difficulty)
02198                         {
02199                             level = ob->map->difficulty;
02200                         }
02201                     }
02202                     else
02203                     {
02204                         level = creator->level;
02205                     }
02206 
02207                     level = (((level * 100) - (level * 20)) + (level * rndm(0, 50))) / 100;
02208 
02209                     if (level < 1)
02210                     {
02211                         level = 1;
02212                     }
02213                     else if (level > MAXLEVEL)
02214                     {
02215                         level = MAXLEVEL;
02216                     }
02217 
02218                     op->level = level;
02219 
02220                     tailor_readable_ob(op, (creator && creator->stats.sp) ? creator->stats.sp : -1);
02221                     generate_artifact(op, 1, T_STYLE_UNSET, 100);
02222 
02223                     /* Books with info are worth more! */
02224                     if (op->msg && strlen(op->msg) > 0)
02225                     {
02226                         op->value *= ((op->level > 10 ? op->level : (op->level + 1) / 2) * ((strlen(op->msg) / 250) + 1));
02227                     }
02228 
02229                     /* For library, chained books! */
02230                     if (creator->type != MONSTER && QUERY_FLAG(creator, FLAG_NO_PICK))
02231                     {
02232                         SET_FLAG(op, FLAG_NO_PICK);
02233                     }
02234 
02235                     /* For check_inv floors */
02236                     if (creator->slaying && !op->slaying)
02237                     {
02238                         FREE_AND_COPY_HASH(op->slaying, creator->slaying);
02239                     }
02240 
02241                     /* Add exp so reading it gives xp (once) */
02242                     op->stats.exp = op->value > 10000 ? op->value / 5 : op->value / 10;
02243                 }
02244 
02245                 break;
02246 
02247             case SPELLBOOK:
02248                 LOG(llevDebug, "fix_generated_item(): called for disabled object SPELLBOOK (%s)\n", query_name(op, NULL));
02249                 break;
02250 
02251             case WAND:
02252                 if ((op->stats.sp = get_random_spell(difficulty, SPELL_USE_WAND)) == SP_NO_SPELL)
02253                 {
02254                     break;
02255                 }
02256 
02257                 /* Marks as magical */
02258                 SET_FLAG(op, FLAG_IS_MAGICAL);
02259                 /* Charges */
02260                 op->stats.food = rndm(1, spells[op->stats.sp].charges) + 12;
02261 
02262                 temp = (((difficulty * 100) - (difficulty * 20)) + (difficulty * rndm(0, 34))) / 100;
02263 
02264                 if (temp < 1)
02265                 {
02266                     temp = 1;
02267                 }
02268                 else if (temp > MAXLEVEL)
02269                 {
02270                     temp = MAXLEVEL;
02271                 }
02272 
02273                 if (temp < spells[op->stats.sp].level)
02274                 {
02275                     temp = spells[op->stats.sp].level;
02276                 }
02277 
02278                 op->level = temp;
02279                 op->value = (int) (16.3f * spells[op->stats.sp].value_mul);
02280 
02281                 break;
02282 
02283             case HORN:
02284             case ROD:
02285                 if ((op->stats.sp = get_random_spell(difficulty, op->type == HORN ? SPELL_USE_HORN : SPELL_USE_ROD)) == SP_NO_SPELL)
02286                 {
02287                     break;
02288                 }
02289 
02290                 /* Marks as magical */
02291                 SET_FLAG(op, FLAG_IS_MAGICAL);
02292 
02293                 if (op->stats.maxhp)
02294                 {
02295                     op->stats.maxhp += rndm(1, op->stats.maxhp);
02296                 }
02297 
02298                 op->stats.hp = op->stats.maxhp;
02299                 temp = (((difficulty * 100) - (difficulty * 20)) + (difficulty * rndm(0, 34))) / 100;
02300 
02301                 if (temp < 1)
02302                 {
02303                     temp = 1;
02304                 }
02305                 else if (temp > MAXLEVEL)
02306                 {
02307                     temp = MAXLEVEL;
02308                 }
02309 
02310                 op->level = temp;
02311 
02312                 if (temp < spells[op->stats.sp].level)
02313                 {
02314                     temp = spells[op->stats.sp].level;
02315                 }
02316 
02317                 op->value = (int) (1850.0f * spells[op->stats.sp].value_mul);
02318 
02319                 break;
02320 
02321             case RUNE:
02322                 /* Artifact AND normal treasure runes! */
02323                 trap_adjust(op, difficulty);
02324                 break;
02325 
02326             /* Generate some special food */
02327             case FOOD:
02328                 if (rndm_chance(4))
02329                 {
02330                     generate_artifact(op, difficulty, T_STYLE_UNSET, 100);
02331                 }
02332 
02333                 /* Small chance to become cursed food */
02334                 if (!(flags & GT_ONLY_GOOD) && rndm_chance(20))
02335                 {
02336                     int strong_curse = rndm(0, 1), i;
02337 
02338                     SET_FLAG(op, FLAG_CURSED);
02339                     SET_FLAG(op, FLAG_PERM_CURSED);
02340 
02341                     /* Pick a random stat to put negative value on */
02342                     change_attr_value(&op->stats, rndm(1, NUM_STATS) - 1, strong_curse ? -2 : -1);
02343 
02344                     /* If this is strong curse food, give it half a chance to curse another stat */
02345                     if (strong_curse && rndm(0, 1))
02346                     {
02347                         change_attr_value(&op->stats, rndm(1, NUM_STATS) - 1, strong_curse ? -2 : -1);
02348                     }
02349 
02350                     /* Put a negative value on random protection. */
02351                     op->protection[rndm(1, LAST_PROTECTION) - 1] = strong_curse ? -25 : -10;
02352 
02353                     /* And again, if this is strong curse food, half a chance to curse another protection. */
02354                     if (strong_curse && rndm(0, 1))
02355                     {
02356                         op->protection[rndm(1, LAST_PROTECTION) - 1] = strong_curse ? -25 : -10;
02357                     }
02358 
02359                     /* Change food, hp, mana and grace bonuses to negative values */
02360                     if (op->stats.food)
02361                     {
02362                         op->stats.food = -op->stats.food;
02363                     }
02364 
02365                     if (op->stats.hp)
02366                     {
02367                         op->stats.hp = -op->stats.hp;
02368                     }
02369 
02370                     if (op->stats.sp)
02371                     {
02372                         op->stats.sp = -op->stats.sp;
02373                     }
02374 
02375                     if (op->stats.grace)
02376                     {
02377                         op->stats.grace = -op->stats.grace;
02378                     }
02379 
02380                     /* Change any positive stat bonuses to negative bonuses. */
02381                     for (i = 0; i < NUM_STATS; i++)
02382                     {
02383                         sint8 val = get_attr_value(&op->stats, i);
02384 
02385                         if (val > 0)
02386                         {
02387                             set_attr_value(&op->stats, i, -val);
02388                         }
02389                     }
02390 
02391                     /* And the same for protections. */
02392                     for (i = 0; i < NROFATTACKS; i++)
02393                     {
02394                         if (op->protection[i] > 0)
02395                         {
02396                             op->protection[i] = -op->protection[i];
02397                         }
02398                     }
02399 
02400                     if (!op->title)
02401                     {
02402                         FREE_AND_ADD_REF_HASH(op->title, (strong_curse ? shstr_cons.of_hideous_poison : shstr_cons.of_poison));
02403                     }
02404                 }
02405 
02406                 break;
02407         }
02408     }
02409     /* Title is not NULL. */
02410     else
02411     {
02412         switch (op->type)
02413         {
02414             case ARROW:
02415                 if (op->slaying == shstr_cons.none)
02416                 {
02417                     add_random_race(op);
02418                 }
02419 
02420                 break;
02421 
02422             case WEAPON:
02423                 if (op->slaying == shstr_cons.none)
02424                 {
02425                     add_random_race(op);
02426                 }
02427 
02428                 break;
02429         }
02430     }
02431 
02432     if ((flags & GT_NO_VALUE) && op->type != MONEY)
02433     {
02434         op->value = 0;
02435     }
02436 
02437     if (flags & GT_STARTEQUIP)
02438     {
02439         if (op->nrof < 2 && op->type != CONTAINER && op->type != MONEY && !QUERY_FLAG(op, FLAG_IS_THROWN))
02440         {
02441             SET_FLAG(op, FLAG_STARTEQUIP);
02442         }
02443         else if (op->type != MONEY)
02444         {
02445             op->value = 0;
02446         }
02447     }
02448 
02449     return retval;
02450 }
02451 
02455 static artifactlist *get_empty_artifactlist()
02456 {
02457     artifactlist *tl = (artifactlist *) malloc(sizeof(artifactlist));
02458 
02459     if (tl == NULL)
02460     {
02461         LOG(llevError, "get_empty_artifactlist(): Out of memory.\n");
02462     }
02463 
02464     tl->next = NULL;
02465     tl->items = NULL;
02466     tl->total_chance = 0;
02467 
02468     return tl;
02469 }
02470 
02474 static artifact *get_empty_artifact(void)
02475 {
02476     artifact *t = (artifact *) malloc(sizeof(artifact));
02477 
02478     if (t == NULL)
02479     {
02480         LOG(llevError, "get_empty_artifact(): Out of memory.\n");
02481     }
02482 
02483     t->next = NULL;
02484     t->name = NULL;
02485     t->def_at_name = NULL;
02486     t->t_style = 0;
02487     t->chance = 0;
02488     t->difficulty = 0;
02489     t->allowed = NULL;
02490 
02491     return t;
02492 }
02493 
02499 artifactlist *find_artifactlist(int type)
02500 {
02501     artifactlist *al;
02502 
02503     for (al = first_artifactlist; al != NULL; al = al->next)
02504     {
02505         if (al->type == type)
02506         {
02507             return al;
02508         }
02509     }
02510 
02511     return NULL;
02512 }
02513 
02519 archetype *find_artifact_archtype(const char *name)
02520 {
02521     artifactlist *al;
02522     artifact *art = NULL;
02523 
02524     for (al = first_artifactlist; al != NULL; al = al->next)
02525     {
02526         art = al->items;
02527 
02528         do
02529         {
02530             if (art->name && !strcmp(art->name, name))
02531             {
02532                 return &art->def_at;
02533             }
02534 
02535             art = art->next;
02536         }
02537         while (art != NULL);
02538     }
02539 
02540     return NULL;
02541 }
02542 
02549 artifact *find_artifact_type(const char *name, int type)
02550 {
02551     artifactlist *al;
02552     artifact *art;
02553 
02554     al = find_artifactlist(type);
02555 
02556     if (!al)
02557     {
02558         return NULL;
02559     }
02560 
02561     for (art = al->items; art; art = art->next)
02562     {
02563         if (!strcmp(art->name, name))
02564         {
02565             return art;
02566         }
02567     }
02568 
02569     return NULL;
02570 }
02571 
02574 void dump_artifacts()
02575 {
02576     artifactlist *al;
02577     artifact *art;
02578     linked_char *next;
02579 
02580     for (al = first_artifactlist; al != NULL; al = al->next)
02581     {
02582         LOG(llevInfo, "Artifact has type %d, total_chance=%d\n", al->type, al->total_chance);
02583 
02584         for (art = al->items; art != NULL; art = art->next)
02585         {
02586             LOG(llevInfo, "Artifact %-30s Difficulty %3d T-Style %d Chance %5d\n", art->name, art->difficulty, art->t_style, art->chance);
02587 
02588             if (art->allowed != NULL)
02589             {
02590                 LOG(llevInfo, "\tAllowed combinations:");
02591 
02592                 for (next = art->allowed; next != NULL; next = next->next)
02593                 {
02594                     LOG(llevInfo, "%s,", next->name);
02595                 }
02596 
02597                 LOG(llevInfo, "\n");
02598             }
02599         }
02600     }
02601 
02602     LOG(llevInfo, "\n");
02603 }
02604 
02608 static void dump_monster_treasure_rec(const char *name, treasure *t, int depth)
02609 {
02610     treasurelist *tl;
02611     int i;
02612 
02613     if (depth > 100)
02614     {
02615         return;
02616     }
02617 
02618     while (t != NULL)
02619     {
02620         if (t->name != NULL)
02621         {
02622             for (i = 0; i < depth; i++)
02623             {
02624                 LOG(llevInfo, "  ");
02625             }
02626 
02627             LOG(llevInfo, "{   (list: %s)\n", t->name);
02628             tl = find_treasurelist(t->name);
02629             dump_monster_treasure_rec(name, tl->items, depth + 2);
02630 
02631             for (i = 0; i < depth; i++)
02632             {
02633                 LOG(llevInfo, "  ");
02634             }
02635 
02636             LOG(llevInfo, "}   (end of list: %s)\n", t->name);
02637         }
02638         else
02639         {
02640             for (i = 0; i < depth; i++)
02641             {
02642                 LOG(llevInfo, "  ");
02643             }
02644 
02645             if (t->item->clone.type == FLESH)
02646             {
02647                 LOG(llevInfo, "%s's %s\n", name, t->item->clone.name);
02648             }
02649             else
02650             {
02651                 LOG(llevInfo, "%s\n", t->item->clone.name);
02652             }
02653         }
02654 
02655         if (t->next_yes != NULL)
02656         {
02657             for (i = 0; i < depth; i++)
02658             {
02659                 LOG(llevInfo, "  ");
02660             }
02661 
02662             LOG(llevInfo, " (if yes)\n");
02663             dump_monster_treasure_rec(name, t->next_yes, depth + 1);
02664         }
02665 
02666         if (t->next_no != NULL)
02667         {
02668             for (i = 0; i < depth; i++)
02669             {
02670                 LOG(llevInfo, "  ");
02671             }
02672 
02673             LOG(llevInfo, " (if no)\n");
02674             dump_monster_treasure_rec(name, t->next_no, depth + 1);
02675         }
02676 
02677         t = t->next;
02678     }
02679 }
02680 
02683 static int legal_artifact_combination(object *op, artifact *art)
02684 {
02685     int neg, success = 0;
02686     linked_char *tmp;
02687     const char *name;
02688 
02689     /* Ie, "all" */
02690     if (art->allowed == NULL)
02691     {
02692         return 1;
02693     }
02694 
02695     for (tmp = art->allowed; tmp; tmp = tmp->next)
02696     {
02697 #ifdef TREASURE_VERBOSE
02698         LOG(llevDebug, "legal_art: %s\n", tmp->name);
02699 #endif
02700 
02701         if (*tmp->name == '!')
02702         {
02703             name = tmp->name + 1, neg = 1;
02704         }
02705         else
02706         {
02707             name = tmp->name, neg = 0;
02708         }
02709 
02710         /* If we match name, then return the opposite of 'neg' */
02711         if (!strcmp(name, op->name) || (op->arch && !strcmp(name, op->arch->name)))
02712         {
02713             return !neg;
02714         }
02715         /* Set success as true, since if the match was an inverse, it
02716          * means everything is allowed except what we match. */
02717         else if (neg)
02718         {
02719             success = 1;
02720         }
02721     }
02722 
02723     return success;
02724 }
02725 
02729 void give_artifact_abilities(object *op, artifact *art)
02730 {
02731     int tmp_value = op->value;
02732 
02733     op->value = 0;
02734 
02735     if (!load_object(art->parse_text, op, NULL, LO_MEMORYMODE, MAP_ARTIFACT))
02736     {
02737         LOG(llevError, "give_artifact_abilities(): load_object() error (ob: %s art: %s).\n", op->name, art->name);
02738     }
02739 
02740     FREE_AND_ADD_REF_HASH(op->artifact, art->name);
02741 
02742     /* This will solve the problem to adjust the value for different
02743      * items of same artification. Also we can safely use negative
02744      * values. */
02745     op->value += tmp_value;
02746 
02747     if (op->value < 0)
02748     {
02749         op->value = 0;
02750     }
02751 
02752     return;
02753 }
02754 
02765 int generate_artifact(object *op, int difficulty, int t_style, int a_chance)
02766 {
02767     artifactlist *al;
02768     artifact *art, *art_tmp = NULL;
02769     int i = 0;
02770 
02771     al = find_artifactlist(op->type);
02772 
02773     /* Now we overrule unset to 0 */
02774     if (t_style == T_STYLE_UNSET)
02775     {
02776         t_style = 0;
02777     }
02778 
02779     if (al == NULL)
02780     {
02781 #ifdef TREASURE_VERBOSE
02782         LOG(llevDebug, "Couldn't change %s into artifact - no table.\n", op->name);
02783 #endif
02784         return 0;
02785     }
02786 
02787     for (i = 0; i < ARTIFACT_TRIES; i++)
02788     {
02789         int roll = rndm(1, al->total_chance) - 1;
02790 
02791         for (art = al->items; art != NULL; art = art->next)
02792         {
02793             roll -= art->chance;
02794 
02795             if (roll < 0)
02796             {
02797                 break;
02798             }
02799         }
02800 
02801         if (art == NULL || roll >= 0)
02802         {
02803             LOG(llevBug, "Got null entry and non zero roll in generate_artifact, type %d\n", op->type);
02804             return 0;
02805         }
02806 
02807         /* Map difficulty not high enough OR the t_style is set and don't match */
02808         if (difficulty < art->difficulty || (t_style == -1 && art->t_style && art->t_style != T_STYLE_UNSET) || (t_style && art->t_style && art->t_style != t_style && art->t_style != T_STYLE_UNSET))
02809         {
02810             continue;
02811         }
02812 
02813         if (!legal_artifact_combination(op, art))
02814         {
02815 #ifdef TREASURE_VERBOSE
02816             LOG(llevDebug, "%s of %s was not a legal combination.\n", op->name, art->item->name);
02817 #endif
02818             continue;
02819         }
02820 
02821         give_artifact_abilities(op, art);
02822         return 1;
02823     }
02824 
02825     /* If we are here then we failed to generate an artifact by chance. */
02826     if (a_chance > 0)
02827     {
02828         for (art = al->items; art != NULL; art = art->next)
02829         {
02830             if (art->chance <= 0)
02831             {
02832                 continue;
02833             }
02834 
02835             if (difficulty < art->difficulty || (t_style == -1 && art->t_style && art->t_style != T_STYLE_UNSET) || (t_style && art->t_style && art->t_style != t_style && art->t_style != T_STYLE_UNSET))
02836             {
02837                 continue;
02838             }
02839 
02840             if (!legal_artifact_combination(op, art))
02841             {
02842                 continue;
02843             }
02844 
02845             /* There we go! */
02846             art_tmp = art;
02847         }
02848     }
02849 
02850     /* Now we MUST have one - if there was at least one legal possible
02851      * artifact. */
02852     if (art_tmp)
02853     {
02854         give_artifact_abilities(op, art_tmp);
02855     }
02856 
02857     return 1;
02858 }
02859 
02864 static void free_treasurestruct(treasure *t)
02865 {
02866     if (t->next)
02867     {
02868         free_treasurestruct(t->next);
02869     }
02870 
02871     if (t->next_yes)
02872     {
02873         free_treasurestruct(t->next_yes);
02874     }
02875 
02876     if (t->next_no)
02877     {
02878         free_treasurestruct(t->next_no);
02879     }
02880 
02881     FREE_AND_CLEAR_HASH2(t->name);
02882     FREE_AND_CLEAR_HASH2(t->change_arch.name);
02883     FREE_AND_CLEAR_HASH2(t->change_arch.slaying);
02884     FREE_AND_CLEAR_HASH2(t->change_arch.title);
02885     free(t);
02886 }
02887 
02891 static void free_charlinks(linked_char *lc)
02892 {
02893     linked_char *tmp, *next;
02894 
02895     for (tmp = lc; tmp; tmp = next)
02896     {
02897         next = tmp->next;
02898         FREE_AND_CLEAR_HASH(tmp->name);
02899         free(tmp);
02900     }
02901 }
02902 
02907 static void free_artifact(artifact *at)
02908 {
02909     FREE_AND_CLEAR_HASH2(at->name);
02910     FREE_AND_CLEAR_HASH2(at->def_at.name);
02911 
02912     if (at->next)
02913     {
02914         free_artifact(at->next);
02915     }
02916 
02917     if (at->allowed)
02918     {
02919         free_charlinks(at->allowed);
02920     }
02921 
02922     if (at->parse_text)
02923     {
02924         free(at->parse_text);
02925     }
02926 
02927     FREE_AND_CLEAR_HASH2(at->def_at.clone.name);
02928     FREE_AND_CLEAR_HASH2(at->def_at.clone.race);
02929     FREE_AND_CLEAR_HASH2(at->def_at.clone.slaying);
02930     FREE_AND_CLEAR_HASH2(at->def_at.clone.msg);
02931     FREE_AND_CLEAR_HASH2(at->def_at.clone.title);
02932     free_key_values(&at->def_at.clone);
02933     free(at);
02934 }
02935 
02938 static void free_artifactlist()
02939 {
02940     artifactlist *al, *nextal;
02941 
02942     LOG(llevDebug, "Freeing artifact list.\n");
02943 
02944     for (al = first_artifactlist; al; al = nextal)
02945     {
02946         nextal = al->next;
02947 
02948         if (al->items)
02949         {
02950             free_artifact(al->items);
02951         }
02952 
02953         free(al);
02954     }
02955 }
02956 
02959 void free_all_treasures()
02960 {
02961     treasurelist *tl, *next;
02962 
02963     LOG(llevDebug, "Freeing treasure lists.\n");
02964 
02965     for (tl = first_treasurelist; tl; tl = next)
02966     {
02967         next = tl->next;
02968         FREE_AND_CLEAR_HASH2(tl->name);
02969 
02970         if (tl->items)
02971         {
02972             free_treasurestruct(tl->items);
02973         }
02974 
02975         free(tl);
02976     }
02977 
02978     free_artifactlist();
02979 }
02980 
02985 static void set_material_real(object *op, struct _change_arch *change_arch)
02986 {
02987     if (change_arch->item_race != -1)
02988     {
02989         op->item_race = (uint8) change_arch->item_race;
02990     }
02991 
02992     /* This must be tested - perhaps we want that change_arch->material
02993      * also overrule the material_real -1 marker? */
02994     if (op->material_real == -1)
02995     {
02996         /* WARNING: material_real == -1 skips also the quality modifier.
02997          * this is really for objects which don't fit in the material/quality
02998          * system (like system objects, forces, effects and stuff). */
02999         op->material_real = 0;
03000         return;
03001     }
03002 
03003     /* We overrule the material settings in any case when this is set */
03004     if (change_arch->material != -1)
03005     {
03006         op->material_real = change_arch->material;
03007 
03008         /* Skip if material is 0 (aka neutralized material setting) */
03009         if (change_arch->material_range > 0 && change_arch->material)
03010         {
03011             op->material_real += rndm(0, change_arch->material_range);
03012         }
03013     }
03014 
03015     /* If 0, grab a valid material class. We should assign to all objects
03016      * a valid material_real value to avoid problems here. */
03017     else if (!op->material_real && op->material != M_ADAMANT)
03018     {
03019         if (op->material & M_IRON)
03020         {
03021             op->material_real = M_START_IRON;
03022         }
03023         else if (op->material & M_LEATHER)
03024         {
03025             op->material_real = M_START_LEATHER;
03026         }
03027         else if (op->material & M_PAPER)
03028         {
03029             op->material_real = M_START_PAPER;
03030         }
03031         else if (op->material & M_GLASS)
03032         {
03033             op->material_real = M_START_GLASS;
03034         }
03035         else if (op->material & M_WOOD)
03036         {
03037             op->material_real = M_START_WOOD;
03038         }
03039         else if (op->material & M_ORGANIC)
03040         {
03041             op->material_real = M_START_ORGANIC;
03042         }
03043         else if (op->material & M_STONE)
03044         {
03045             op->material_real = M_START_STONE;
03046         }
03047         else if (op->material & M_CLOTH)
03048         {
03049             op->material_real = M_START_CLOTH;
03050         }
03051         else if (op->material & M_ADAMANT)
03052         {
03053             op->material_real = M_START_ADAMANT;
03054         }
03055         else if (op->material & M_LIQUID)
03056         {
03057             op->material_real = M_START_LIQUID;
03058         }
03059         else if (op->material & M_SOFT_METAL)
03060         {
03061             op->material_real = M_START_SOFT_METAL;
03062         }
03063         else if (op->material & M_BONE)
03064         {
03065             op->material_real = M_START_BONE;
03066         }
03067         else if (op->material & M_ICE)
03068         {
03069             op->material_real = M_START_ICE;
03070         }
03071     }
03072 
03073     /* Now we do some work: we define a (material) quality and try to
03074      * find a best matching pre-set material_real for that item. This is
03075      * a bit more complex but we are with that free to define different
03076      * materials without having a strong fixed material table. */
03077     if (change_arch->material_quality != -1)
03078     {
03079         int i, q_tmp = -1;
03080         int m_range = change_arch->material_quality;
03081 
03082         if (change_arch->material_range > 0)
03083         {
03084             m_range += rndm(0, change_arch->material_range);
03085         }
03086 
03087         if (op->material_real)
03088         {
03089             int m_tmp = op->material_real / NROFMATERIALS_REAL;
03090 
03091             /* The first entry of the material_real of material table */
03092             m_tmp = m_tmp * 64 + 1;
03093 
03094             /* We should add paper & cloth here too later */
03095             if (m_tmp == M_START_IRON || m_tmp == M_START_WOOD || m_tmp == M_START_LEATHER)
03096             {
03097                 for (i = 0; i < NROFMATERIALS_REAL; i++)
03098                 {
03099                     /* We have a full hit */
03100                     if (material_real[m_tmp + i].quality == m_range)
03101                     {
03102                         op->material_real = m_tmp + i;
03103                         goto set_material_real;
03104                     }
03105 
03106                     /* Find nearest quality we want */
03107                     if (material_real[m_tmp + i].quality >= change_arch->material_quality && material_real[m_tmp + i].quality <= m_range && material_real[m_tmp + i].quality > q_tmp)
03108                     {
03109                         q_tmp = m_tmp + i;
03110                     }
03111                 }
03112 
03113                 /* If we have no match, we simply use the (always valid)
03114                  * first material_real entry and forcing the
03115                  * material_quality to quality! */
03116                 if (q_tmp == -1)
03117                 {
03118                     op->material_real = m_tmp;
03119                     op->item_quality = change_arch->material_quality;
03120                     op->item_condition = op->item_quality;
03121                     return;
03122                 }
03123 
03124                 /* That's now our best match! */
03125                 op->material_real = q_tmp;
03126             }
03127             /* Excluded material table! */
03128             else
03129             {
03130                 op->item_quality = m_range;
03131                 op->item_condition = op->item_quality;
03132                 return;
03133             }
03134         }
03135         /* We have material_real 0 but we modify at least the quality! */
03136         else
03137         {
03138             op->item_quality = m_range;
03139             op->item_condition = op->item_quality;
03140             return;
03141         }
03142     }
03143 
03144 set_material_real:
03145     /* Adjust quality - use material default value or quality adjustment */
03146     if (change_arch->quality != -1)
03147     {
03148         op->item_quality = change_arch->quality;
03149     }
03150     else
03151     {
03152         op->item_quality = material_real[op->material_real].quality;
03153     }
03154 
03155     if (change_arch->quality_range > 0)
03156     {
03157         op->item_quality += rndm(0, change_arch->quality_range);
03158 
03159         if (op->item_quality > 100)
03160         {
03161             op->item_quality = 100;
03162         }
03163     }
03164 
03165     op->item_condition = op->item_quality;
03166 }
03167 
03171 void dump_monster_treasure(const char *name)
03172 {
03173     archetype *at;
03174     int found;
03175 
03176     found = 0;
03177     LOG(llevInfo, "\n");
03178 
03179     for (at = first_archetype; at != NULL; at = at->next)
03180     {
03181         if (!strcasecmp(at->name, name))
03182         {
03183             LOG(llevInfo, "treasures for %s (arch: %s)\n", at->clone.name, at->name);
03184 
03185             if (at->clone.randomitems != NULL)
03186             {
03187                 dump_monster_treasure_rec(at->clone.name, at->clone.randomitems->items, 1);
03188             }
03189             else
03190             {
03191                 LOG(llevInfo, "(nothing)\n");
03192             }
03193 
03194             LOG(llevInfo, "\n");
03195             found++;
03196         }
03197     }
03198 
03199     if (found == 0)
03200     {
03201         LOG(llevInfo, "No objects have the name %s!\n\n", name);
03202     }
03203 }
03204 
03210 int get_environment_level(object *op)
03211 {
03212     object *env;
03213 
03214     if (!op)
03215     {
03216         LOG(llevBug, "get_environment_level() called for NULL object!\n");
03217         return 1;
03218     }
03219 
03220     /* Return object level or map level... */
03221     if (op->level)
03222     {
03223         return op->level;
03224     }
03225 
03226     if (op->map)
03227     {
03228         return op->map->difficulty ? op->map->difficulty : 1;
03229     }
03230 
03231     /* Let's check for env */
03232     env = op->env;
03233 
03234     while (env)
03235     {
03236         if (env->level)
03237         {
03238             return env->level;
03239         }
03240 
03241         if (env->map)
03242         {
03243             return env->map->difficulty ? env->map->difficulty : 1;
03244         }
03245 
03246         env = env->env;
03247     }
03248 
03249     return 1;
03250 }
03251 
03257 object *create_artifact(object *op, char *artifactname)
03258 {
03259     artifactlist *al = find_artifactlist(op->type);
03260     artifact *art;
03261 
03262     if (al == NULL)
03263     {
03264         return NULL;
03265     }
03266 
03267     for (art = al->items; art != NULL; art = art->next)
03268     {
03269         if (!strcmp(art->name, artifactname))
03270         {
03271             give_artifact_abilities(op, art);
03272         }
03273     }
03274 
03275     return NULL;
03276 }
03277 
03278 #ifdef TREASURE_DEBUG
03279 
03283 static void check_treasurelist(treasure *t, treasurelist *tl)
03284 {
03285     if (t->item == NULL && t->name == NULL)
03286     {
03287         LOG(llevError, "Treasurelist %s has element with no name or archetype\n", tl->name);
03288     }
03289 
03290     if (t->chance >= 100 && t->next_yes && (t->next || t->next_no))
03291     {
03292         LOG(llevBug, "Treasurelist %s has element that has 100%% generation, next_yes field as well as next or next_no\n", tl->name);
03293     }
03294 
03295     /* find_treasurelist will print out its own error message */
03296     if (t->name && t->name != shstr_cons.NONE)
03297     {
03298         (void) find_treasurelist(t->name);
03299     }
03300 
03301     if (t->next)
03302     {
03303         check_treasurelist(t->next, tl);
03304     }
03305 
03306     if (t->next_yes)
03307     {
03308         check_treasurelist(t->next_yes, tl);
03309     }
03310 
03311     if (t->next_no)
03312     {
03313         check_treasurelist(t->next_no, tl);
03314     }
03315 }
03316 #endif