/* File: randart.c */ /* * Copyright (c) 1997 Ben Harrison * * This software may be copied and distributed for educational, research, * and not for profit purposes provided that this copyright and statement * are included in all such copies. Other copyrights may also apply. */ #include "angband.h" /* * Random artifact generator (randart) by Greg Wooledge. * * Note that the direct use of malloc/free is a bad idea. XXX XXX XXX * * The external "names.txt" file was sucked into this file for simplicity. */ #ifdef GJW_RANDART static const char *names_list = "adanedhel\n" "adurant\n" "aeglos\n" "aegnor\n" "aelin\n" "aeluin\n" "aerandir\n" "aerin\n" "agarwaen\n" "aglareb\n" "aglarond\n" "aglon\n" "ainulindale\n" "ainur\n" "alcarinque\n" "aldaron\n" "aldudenie\n" "almaren\n" "alqualonde\n" "aman\n" "amandil\n" "amarie\n" "amarth\n" "amlach\n" "amon\n" "amras\n" "amrod\n" "anach\n" "anar\n" "anarion\n" "ancalagon\n" "ancalimon\n" "anarrima\n" "andor\n" "andram\n" "androth\n" "anduin\n" "andunie\n" "anfauglir\n" "anfauglith\n" "angainor\n" "angband\n" "anghabar\n" "anglachel\n" "angrenost\n" "angrim\n" "angrist\n" "angrod\n" "anguirel\n" "annael\n" "annatar\n" "annon\n" "annuminas\n" "apanonar\n" "aradan\n" "aragorn\n" "araman\n" "aranel\n" "aranruth\n" "aranwe\n" "aras\n" "aratan\n" "aratar\n" "arathorn\n" "arda\n" "ard-galen\n" "aredhel\n" "ar-feiniel\n" "argonath\n" "arien\n" "armenelos\n" "arminas\n" "arnor\n" "aros\n" "arossiach\n" "arthad\n" "arvernien\n" "arwen\n" "ascar\n" "astaldo\n" "atalante\n" "atanamir\n" "atanatari\n" "atani\n" "aule\n" "avallone\n" "avari\n" "avathar\n" "balan\n" "balar\n" "balrog\n" "barad\n" "baragund\n" "barahir\n" "baran\n" "baranduin\n" "bar\n" "bauglir\n" "beleg\n" "belegaer\n" "belegost\n" "belegund\n" "beleriand\n" "belfalas\n" "belthil\n" "belthronding\n" "beor\n" "beraid\n" "bereg\n" "beren\n" "boromir\n" "boron\n" "bragollach\n" "brandir\n" "bregolas\n" "bregor\n" "brethil\n" "brilthor\n" "brithiach\n" "brithombar\n" "brithon\n" "cabed\n" "calacirya\n" "calaquendi\n" "calenardhon\n" "calion\n" "camlost\n" "caragdur\n" "caranthir\n" "carcharoth\n" "cardolan\n" "carnil\n" "celeborn\n" "celebrant\n" "celebrimbor\n" "celebrindal\n" "celebros\n" "celegorm\n" "celon\n" "cirdan\n" "cirith\n" "cirth\n" "ciryatan\n" "ciryon\n" "coimas\n" "corollaire\n" "crissaegrim\n" "cuarthal\n" "cuivienen\n" "culurien\n" "curufin\n" "curufinwe\n" "curunir\n" "cuthalion\n" "daedeloth\n" "daeron\n" "dagnir\n" "dagor\n" "dagorlad\n" "dairuin\n" "danwedh\n" "delduwath\n" "denethor\n" "dimbar\n" "dimrost\n" "dinen\n" "dior\n" "dirnen\n" "dolmed\n" "doriath\n" "dorlas\n" "dorthonion\n" "draugluin\n" "drengist\n" "duath\n" "duinath\n" "duilwen\n" "dunedain\n" "dungortheb\n" "earendil\n" "earendur\n" "earnil\n" "earnur\n" "earrame\n" "earwen\n" "echor\n" "echoriath\n" "ecthelion\n" "edain\n" "edrahil\n" "eglador\n" "eglarest\n" "eglath\n" "eilinel\n" "eithel\n" "ekkaia\n" "elbereth\n" "eldalie\n" "eldalieva\n" "eldamar\n" "eldar\n" "eledhwen\n" "elemmire\n" "elende\n" "elendil\n" "elendur\n" "elenna\n" "elentari\n" "elenwe\n" "elerrina\n" "elleth\n" "elmoth\n" "elostirion\n" "elrond\n" "elros\n" "elu\n" "eluchil\n" "elured\n" "elurin\n" "elwe\n" "elwing\n" "emeldir\n" "endor\n" "engrin\n" "engwar\n" "eol\n" "eonwe\n" "ephel\n" "erchamion\n" "ereb\n" "ered\n" "erech\n" "eregion\n" "ereinion\n" "erellont\n" "eressea\n" "eriador\n" "eru\n" "esgalduin\n" "este\n" "estel\n" "estolad\n" "ethir\n" "ezellohar\n" "faelivrin\n" "falas\n" "falathar\n" "falathrim\n" "falmari\n" "faroth\n" "fauglith\n" "feanor\n" "feanturi\n" "felagund\n" "finarfin\n" "finduilas\n" "fingolfin\n" "fingon\n" "finwe\n" "firimar\n" "formenos\n" "fornost\n" "frodo\n" "fuin\n" "fuinur\n" "gabilgathol\n" "galad\n" "galadriel\n" "galathilion\n" "galdor\n" "galen\n" "galvorn\n" "gandalf\n" "gaurhoth\n" "gelion\n" "gelmir\n" "gelydh\n" "gil\n" "gildor\n" "giliath\n" "ginglith\n" "girith\n" "glaurung\n" "glingal\n" "glirhuin\n" "gloredhel\n" "glorfindel\n" "golodhrim\n" "gondolin\n" "gondor\n" "gonnhirrim\n" "gorgoroth\n" "gorlim\n" "gorthaur\n" "gorthol\n" "gothmog\n" "guilin\n" "guinar\n" "guldur\n" "gundor\n" "gurthang\n" "gwaith\n" "gwareth\n" "gwindor\n" "hadhodrond\n" "hador\n" "haladin\n" "haldad\n" "haldan\n" "haldar\n" "haldir\n" "haleth\n" "halmir\n" "handir\n" "harad\n" "hareth\n" "hathaldir\n" "hathol\n" "haudh\n" "helcar\n" "helcaraxe\n" "helevorn\n" "helluin\n" "herumor\n" "herunumen\n" "hildorien\n" "himlad\n" "himring\n" "hirilorn\n" "hisilome\n" "hithaeglir\n" "hithlum\n" "hollin\n" "huan\n" "hunthor\n" "huor\n" "hurin\n" "hyarmendacil\n" "hyarmentir\n" "iant\n" "iaur\n" "ibun\n" "idril\n" "illuin\n" "ilmare\n" "ilmen\n" "iluvatar\n" "imlach\n" "imladris\n" "indis\n" "ingwe\n" "irmo\n" "isil\n" "isildur\n" "istari\n" "ithil\n" "ivrin\n" "kelvar\n" "kementari\n" "ladros\n" "laiquendi\n" "lalaith\n" "lamath\n" "lammoth\n" "lanthir\n" "laurelin\n" "leithian\n" "legolin\n" "lembas\n" "lenwe\n" "linaewen\n" "lindon\n" "lindorie\n" "loeg\n" "lomelindi\n" "lomin\n" "lomion\n" "lorellin\n" "lorien\n" "lorindol\n" "losgar\n" "lothlann\n" "lothlorien\n" "luin\n" "luinil\n" "lumbar\n" "luthien\n" "mablung\n" "maedhros\n" "maeglin\n" "maglor\n" "magor\n" "mahanaxar\n" "mahtan\n" "maiar\n" "malduin\n" "malinalda\n" "mandos\n" "manwe\n" "mardil\n" "melian\n" "melkor\n" "menegroth\n" "meneldil\n" "menelmacar\n" "meneltarma\n" "minas\n" "minastir\n" "mindeb\n" "mindolluin\n" "mindon\n" "minyatur\n" "mirdain\n" "miriel\n" "mithlond\n" "mithrandir\n" "mithrim\n" "mordor\n" "morgoth\n" "morgul\n" "moria\n" "moriquendi\n" "mormegil\n" "morwen\n" "nahar\n" "naeramarth\n" "namo\n" "nandor\n" "nargothrond\n" "narog\n" "narsil\n" "narsilion\n" "narya\n" "nauglamir\n" "naugrim\n" "ndengin\n" "neithan\n" "neldoreth\n" "nenar\n" "nenning\n" "nenuial\n" "nenya\n" "nerdanel\n" "nessa\n" "nevrast\n" "nibin\n" "nienna\n" "nienor\n" "nimbrethil\n" "nimloth\n" "nimphelos\n" "nimrais\n" "nimras\n" "ningloron\n" "niniel\n" "ninniach\n" "ninquelote\n" "niphredil\n" "nirnaeth\n" "nivrim\n" "noegyth\n" "nogrod\n" "noldolante\n" "noldor\n" "numenor\n" "nurtale\n" "obel\n" "ohtar\n" "oiolosse\n" "oiomure\n" "olorin\n" "olvar\n" "olwe\n" "ondolinde\n" "orfalch\n" "ormal\n" "orocarni\n" "orodreth\n" "orodruin\n" "orome\n" "oromet\n" "orthanc\n" "osgiliath\n" "osse\n" "ossiriand\n" "palantir\n" "pelargir\n" "pelori\n" "periannath\n" "quendi\n" "quenta\n" "quenya\n" "radagast\n" "radhruin\n" "ragnor\n" "ramdal\n" "rana\n" "rathloriel\n" "rauros\n" "region\n" "rerir\n" "rhovanion\n" "rhudaur\n" "rhun\n" "rhunen\n" "rian\n" "ringil\n" "ringwil\n" "romenna\n" "rudh\n" "rumil\n" "saeros\n" "salmar\n" "saruman\n" "sauron\n" "serech\n" "seregon\n" "serinde\n" "shelob\n" "silmarien\n" "silmaril\n" "silpion\n" "sindar\n" "singollo\n" "sirion\n" "soronume\n" "sul\n" "sulimo\n" "talath\n" "taniquetil\n" "tar\n" "taras\n" "tarn\n" "tathren\n" "taur\n" "tauron\n" "teiglin\n" "telchar\n" "telemnar\n" "teleri\n" "telperion\n" "telumendil\n" "thalion\n" "thalos\n" "thangorodrim\n" "thargelion\n" "thingol\n" "thoronath\n" "thorondor\n" "thranduil\n" "thuringwethil\n" "tilion\n" "tintalle\n" "tinuviel\n" "tirion\n" "tirith\n" "tol\n" "tulkas\n" "tumhalad\n" "tumladen\n" "tuna\n" "tuor\n" "turambar\n" "turgon\n" "turin\n" "uial\n" "uilos\n" "uinen\n" "ulairi\n" "ulmo\n" "ulumuri\n" "umanyar\n" "umarth\n" "umbar\n" "ungoliant\n" "urthel\n" "uruloki\n" "utumno\n" "vaire\n" "valacirca\n" "valandil\n" "valaquenta\n" "valar\n" "valaraukar\n" "valaroma\n" "valier\n" "valimar\n" "valinor\n" "valinoreva\n" "valmar\n" "vana\n" "vanyar\n" "varda\n" "vasa\n" "vilya\n" "vingilot\n" "vinyamar\n" "voronwe\n" "wethrin\n" "wilwarin\n" "yavanna\n" ; #define MAX_TRIES 200 #define BUFLEN 1024 #define MIN_NAME_LEN 5 #define MAX_NAME_LEN 9 #define S_WORD 26 #define E_WORD S_WORD #define sign(x) ((x) > 0 ? 1 : ((x) < 0 ? -1 : 0)) static long lprobs[S_WORD+1][S_WORD+1][S_WORD+1]; static long ltotal[S_WORD+1][S_WORD+1]; /* * Cache the results of lookup_kind(), which is expensive and would * otherwise be called much too often. */ static s16b *kinds; /* Global just for convenience. */ static int randart_verbose = 0; static char *my_strdup(const char *s) { char *t = malloc(strlen(s) + 1); if (t) strcpy(t, s); return t; } /* * Use W. Sheldon Simms' random name generator. This function builds * probability tables which are used later on for letter selection. It * relies on the ASCII character set. */ static void build_prob(const char *learn) { int c_prev, c_cur, c_next; /* Build raw frequencies */ while (1) { c_prev = c_cur = S_WORD; do { c_next = *learn++; } while (!isalpha(c_next) && (c_next != '\0')); if (c_next == '\0') break; do { c_next = tolower(c_next) - 'a'; /* ASCII */ lprobs[c_prev][c_cur][c_next]++; ltotal[c_prev][c_cur]++; c_prev = c_cur; c_cur = c_next; c_next = *learn++; } while (isalpha(c_next)); lprobs[c_prev][c_cur][E_WORD]++; ltotal[c_prev][c_cur]++; } } /* * Use W. Sheldon Simms' random name generator. Generate a random word using * the probability tables we built earlier. Relies on the ASCII character * set. Relies on European vowels (a, e, i, o, u). The generated name should * be copied/used before calling this function again. */ static char *make_word(void) { static char word_buf[90]; int r, totalfreq; int tries, lnum, vow; int c_prev, c_cur, c_next; char *cp; startover: vow = 0; lnum = 0; tries = 0; cp = word_buf; c_prev = c_cur = S_WORD; while (1) { getletter: c_next = 0; r = rand_int(ltotal[c_prev][c_cur]); totalfreq = lprobs[c_prev][c_cur][c_next]; while (totalfreq <= r) { c_next++; totalfreq += lprobs[c_prev][c_cur][c_next]; } if (c_next == E_WORD) { if ((lnum < MIN_NAME_LEN) || vow == 0) { tries++; if (tries < 10) goto getletter; goto startover; } *cp = '\0'; break; } if (lnum >= MAX_NAME_LEN) goto startover; *cp = c_next + 'a'; /* ASCII */ switch (*cp) { case 'a': case 'e': case 'i': case 'o': case 'u': vow++; } cp++; lnum++; c_prev = c_cur; c_cur = c_next; } word_buf[0] = toupper(word_buf[0]); return word_buf; } /* * Use W. Sheldon Simms' random name generator. */ static int init_names(void) { char buf[BUFLEN]; size_t name_size; char *a_base; char *a_next; int i; /* Temporary space for names, while reading and randomizing them. */ char **names; int nnames = 0; build_prob(names_list); /* Allocate the "names" array */ /* ToDo: Make sure the memory is freed correctly in case of errors */ C_MAKE(names, z_info->a_max, char*); for (i = 0; i < z_info->a_max; i++) { char *word = make_word(); if (rand_int(3) == 0) sprintf(buf, "'%s'", word); else sprintf(buf, "of %s", word); names[i] = my_strdup(buf); } /* Special cases -- keep these three names separate. */ free(names[ART_POWER - 1]); free(names[ART_GROND - 1]); free(names[ART_MORGOTH - 1]); if ((names[ART_POWER - 1] = my_strdup("of Power (The One Ring)")) == NULL) { msg_format("Memory allocation error"); return 1; } if ((names[ART_GROND - 1] = my_strdup("'Grond'")) == NULL) { msg_format("Memory allocation error"); return 1; } if ((names[ART_MORGOTH - 1] = my_strdup("of Morgoth")) == NULL) { msg_format("Memory allocation error"); return 1; } /* Convert our names array into an a_name structure for later use. */ name_size = 0; for (i = 1; i < z_info->a_max; i++) { name_size += strlen(names[i-1]) + 2; /* skip first char */ } C_MAKE(a_base, name_size, char); a_next = a_base + 1; /* skip first char */ for (i = 1; i < z_info->a_max; i++) { strcpy(a_next, names[i-1]); if (a_info[i].tval > 0) /* skip unused! */ a_info[i].name = a_next - a_base; a_next += strlen(names[i-1]) + 1; } /* Free some of our now unneeded memory. */ KILL(a_name, char); for (i = 0; i < nnames; i++) { free(names[i]); } /* Free the "names" array */ C_KILL(names, z_info->a_max, char*); a_name = a_base; return 0; } /* * Calculate the multiplier we'll get with a given bow type. This is done * differently in 2.8.2 than it was in 2.8.1. */ static int bow_multiplier(int sval) { switch (sval) { case SV_SLING: case SV_SHORT_BOW: return 2; case SV_LONG_BOW: case SV_LIGHT_XBOW: return 3; case SV_HEAVY_XBOW: return 4; default: msg_format("Illegal bow sval %s\n", sval); } return 0; } /* * Evaluate the artifact's overall power level. */ static s32b artifact_power(int a_idx, bool cannot_use_kind_cache) { const artifact_type *a_ptr = &a_info[a_idx]; s32b p = 0; s16b k_idx; object_kind *k_ptr = NULL; /* silence the warning */ int immunities = 0; /* Start with a "power" rating derived from the base item's level. */ if (a_idx >= ART_MIN_NORMAL) { if (cannot_use_kind_cache) k_idx = lookup_kind(a_ptr->tval, a_ptr->sval); else k_idx = kinds[a_idx]; if (k_idx) { k_ptr = &k_info[k_idx]; p = (k_ptr->level + 7) / 8; } /* Otherwise just forget it and use 0. ;-) */ } /* Evaluate certain abilities based on type of object. */ switch (a_ptr->tval) { case TV_BOW: { int mult; p += (a_ptr->to_d + sign(a_ptr->to_d)) / 2; mult = bow_multiplier(a_ptr->sval); if (a_ptr->flags1 & TR1_MIGHT) { if (a_ptr->pval > 3) { p += 20000; /* inhibit */ mult = 1; /* don't overflow */ } else mult += a_ptr->pval; } p *= mult; if (a_ptr->flags1 & TR1_SHOTS) { if (a_ptr->pval > 3) p += 20000; /* inhibit */ else if (a_ptr->pval > 0) p *= (2 * a_ptr->pval); } p += (a_ptr->to_h + 3 * sign(a_ptr->to_h)) / 4; if (a_ptr->weight < k_ptr->weight) p++; break; } case TV_DIGGING: case TV_HAFTED: case TV_POLEARM: case TV_SWORD: { p += (a_ptr->dd * a_ptr->ds + 1) / 2; if (a_ptr->flags1 & TR1_SLAY_EVIL) p = (p * 3) / 2; if (a_ptr->flags1 & TR1_KILL_DRAGON) p = (p * 3) / 2; if (a_ptr->flags1 & TR1_SLAY_ANIMAL) p = (p * 4) / 3; if (a_ptr->flags1 & TR1_SLAY_UNDEAD) p = (p * 4) / 3; if (a_ptr->flags1 & TR1_SLAY_DRAGON) p = (p * 4) / 3; if (a_ptr->flags1 & TR1_SLAY_DEMON) p = (p * 5) / 4; if (a_ptr->flags1 & TR1_SLAY_TROLL) p = (p * 5) / 4; if (a_ptr->flags1 & TR1_SLAY_ORC) p = (p * 5) / 4; if (a_ptr->flags1 & TR1_SLAY_GIANT) p = (p * 6) / 5; if (a_ptr->flags1 & TR1_BRAND_ACID) p = p * 2; if (a_ptr->flags1 & TR1_BRAND_ELEC) p = (p * 3) / 2; if (a_ptr->flags1 & TR1_BRAND_FIRE) p = (p * 4) / 3; if (a_ptr->flags1 & TR1_BRAND_COLD) p = (p * 4) / 3; p += (a_ptr->to_d + 2 * sign(a_ptr->to_d)) / 3; if (a_ptr->to_d > 15) p += (a_ptr->to_d - 14) / 2; if (a_ptr->flags1 & TR1_BLOWS) { if (a_ptr->pval > 3) p += 20000; /* inhibit */ else if (a_ptr->pval > 0) p = (p * 6) / (4 - a_ptr->pval); } if ((a_ptr->flags1 & TR1_TUNNEL) && (a_ptr->tval != TV_DIGGING)) p += a_ptr->pval * 3; p += (a_ptr->to_h + 3 * sign(a_ptr->to_h)) / 4; /* Remember, weight is in 0.1 lb. units. */ if (a_ptr->weight != k_ptr->weight) p += (k_ptr->weight - a_ptr->weight) / 20; break; } case TV_BOOTS: case TV_GLOVES: case TV_HELM: case TV_CROWN: case TV_SHIELD: case TV_CLOAK: case TV_SOFT_ARMOR: case TV_HARD_ARMOR: { p += (a_ptr->ac + 4 * sign(a_ptr->ac)) / 5; p += (a_ptr->to_h + sign(a_ptr->to_h)) / 2; p += (a_ptr->to_d + sign(a_ptr->to_d)) / 2; if (a_ptr->weight != k_ptr->weight) p += (k_ptr->weight - a_ptr->weight) / 30; break; } case TV_LITE: { p += 10; break; } case TV_RING: case TV_AMULET: { p += 20; break; } } /* Other abilities are evaluated independent of the object type. */ p += (a_ptr->to_a + 3 * sign(a_ptr->to_a)) / 4; if (a_ptr->to_a > 20) p += (a_ptr->to_a - 19) / 2; if (a_ptr->to_a > 30) p += (a_ptr->to_a - 29) / 2; if (a_ptr->to_a > 40) p += 20000; /* inhibit */ if (a_ptr->pval > 0) { if (a_ptr->flags1 & TR1_STR) p += a_ptr->pval * a_ptr->pval; if (a_ptr->flags1 & TR1_INT) p += a_ptr->pval * a_ptr->pval; if (a_ptr->flags1 & TR1_WIS) p += a_ptr->pval * a_ptr->pval; if (a_ptr->flags1 & TR1_DEX) p += a_ptr->pval * a_ptr->pval; if (a_ptr->flags1 & TR1_CON) p += a_ptr->pval * a_ptr->pval; if (a_ptr->flags1 & TR1_STEALTH) p += a_ptr->pval * a_ptr->pval; } else if (a_ptr->pval < 0) /* hack: don't give large negatives */ { if (a_ptr->flags1 & TR1_STR) p += a_ptr->pval; if (a_ptr->flags1 & TR1_INT) p += a_ptr->pval; if (a_ptr->flags1 & TR1_WIS) p += a_ptr->pval; if (a_ptr->flags1 & TR1_DEX) p += a_ptr->pval; if (a_ptr->flags1 & TR1_CON) p += a_ptr->pval; if (a_ptr->flags1 & TR1_STEALTH) p += a_ptr->pval; } if (a_ptr->flags1 & TR1_CHR) p += a_ptr->pval; if (a_ptr->flags1 & TR1_INFRA) p += (a_ptr->pval + sign(a_ptr->pval)) / 2; if (a_ptr->flags1 & TR1_SPEED) p += (a_ptr->pval * 3) / 2; if (a_ptr->flags2 & TR2_SUST_STR) p += 6; if (a_ptr->flags2 & TR2_SUST_INT) p += 4; if (a_ptr->flags2 & TR2_SUST_WIS) p += 4; if (a_ptr->flags2 & TR2_SUST_DEX) p += 4; if (a_ptr->flags2 & TR2_SUST_CON) p += 4; if (a_ptr->flags2 & TR2_SUST_CHR) p += 1; if (a_ptr->flags2 & TR2_IM_ACID) { p += 20; immunities++; } if (a_ptr->flags2 & TR2_IM_ELEC) { p += 24; immunities++; } if (a_ptr->flags2 & TR2_IM_FIRE) { p += 36; immunities++; } if (a_ptr->flags2 & TR2_IM_COLD) { p += 24; immunities++; } if (immunities > 1) p += 16; if (immunities > 2) p += 16; if (immunities > 3) p += 20000; /* inhibit */ if (a_ptr->flags3 & TR3_FREE_ACT) p += 8; if (a_ptr->flags3 & TR3_HOLD_LIFE) p += 10; if (a_ptr->flags2 & TR2_RES_ACID) p += 6; if (a_ptr->flags2 & TR2_RES_ELEC) p += 6; if (a_ptr->flags2 & TR2_RES_FIRE) p += 6; if (a_ptr->flags2 & TR2_RES_COLD) p += 6; if (a_ptr->flags2 & TR2_RES_POIS) p += 12; if (a_ptr->flags2 & TR2_RES_LITE) p += 8; if (a_ptr->flags2 & TR2_RES_DARK) p += 10; if (a_ptr->flags2 & TR2_RES_BLIND) p += 10; if (a_ptr->flags2 & TR2_RES_CONFU) p += 8; if (a_ptr->flags2 & TR2_RES_SOUND) p += 10; if (a_ptr->flags2 & TR2_RES_SHARD) p += 8; if (a_ptr->flags2 & TR2_RES_NETHR) p += 12; if (a_ptr->flags2 & TR2_RES_NEXUS) p += 10; if (a_ptr->flags2 & TR2_RES_CHAOS) p += 12; if (a_ptr->flags2 & TR2_RES_DISEN) p += 12; if (a_ptr->flags3 & TR3_FEATHER) p += 2; if (a_ptr->flags3 & TR3_LITE) p += 2; if (a_ptr->flags3 & TR3_SEE_INVIS) p += 8; if (a_ptr->flags3 & TR3_TELEPATHY) p += 20; if (a_ptr->flags3 & TR3_SLOW_DIGEST) p += 4; if (a_ptr->flags3 & TR3_REGEN) p += 8; if (a_ptr->flags3 & TR3_TELEPORT) p -= 20; if (a_ptr->flags3 & TR3_DRAIN_EXP) p -= 16; if (a_ptr->flags3 & TR3_AGGRAVATE) p -= 8; if (a_ptr->flags3 & TR3_BLESSED) p += 4; if (a_ptr->flags3 & TR3_LIGHT_CURSE) p -= 4; if (a_ptr->flags3 & TR3_HEAVY_CURSE) p -= 20; /* if (a_ptr->flags3 & TR3_PERMA_CURSE) p -= 40; */ return p; } /* * Randomly select a base item type (tval,sval). Assign the various fields * corresponding to that choice. */ static void choose_item(int a_idx) { artifact_type *a_ptr = &a_info[a_idx]; int tval, sval; object_kind *k_ptr; int r; s16b k_idx, r2; byte target_level; /* * Look up the original artifact's base object kind to get level and * rarity information to supplement the artifact level/rarity. As a * degenerate case consider Bladeturner, which has artifact lvl/rar * of only 95/3, but which is based on an object with 110/64! */ k_idx = lookup_kind(a_ptr->tval, a_ptr->sval); k_ptr = &k_info[k_idx]; target_level = k_ptr->level; /* * Add base object kind's rarity to artifact rarity. Later we will * subtract the new object kind's rarity. */ a_ptr->rarity += k_ptr->chance[0]; /* * Pick a category (tval) of weapon randomly. Within each tval, roll * an sval (specific item) based on the target level. The number we * roll should be a bell curve. The mean and standard variation of the * bell curve are based on the target level; the distribution of * kinds versus the bell curve is hand-tweaked. :-( */ r = rand_int(100); if (r < 5) { /* Create a missile weapon. */ tval = TV_BOW; r2 = Rand_normal(target_level * 2, target_level); if (r2 < 3) sval = SV_SLING; else if (r2 < 10) sval = SV_SHORT_BOW; else if (r2 < 30) sval = SV_LONG_BOW; else if (r2 < 45) sval = SV_LIGHT_XBOW; else sval = SV_HEAVY_XBOW; } else if (r < 9) { /* Create a digging tool. */ tval = TV_DIGGING; r2 = Rand_normal(target_level * 2, target_level); if (r2 < 15) sval = SV_SHOVEL; else if (r2 < 30) sval = SV_PICK; else if (r2 < 60) sval = SV_GNOMISH_SHOVEL; else if (r2 < 90) sval = SV_ORCISH_PICK; else if (r2 < 120) sval = SV_DWARVEN_SHOVEL; else sval = SV_DWARVEN_PICK; } else if (r < 19) { /* Create a "blunt" weapon. */ tval = TV_HAFTED; r2 = Rand_normal(target_level * 2, target_level); if (r2 < 6) sval = SV_WHIP; else if (r2 < 12) sval = SV_MACE; else if (r2 < 20) sval = SV_WAR_HAMMER; else if (r2 < 30) sval = SV_QUARTERSTAFF; else if (r2 < 34) sval = SV_LUCERN_HAMMER; else if (r2 < 38) sval = SV_MORNING_STAR; else if (r2 < 45) sval = SV_FLAIL; else if (r2 < 55) sval = SV_LEAD_FILLED_MACE; else if (r2 < 80) sval = SV_BALL_AND_CHAIN; else if (r2 < 120) sval = SV_TWO_HANDED_FLAIL; else sval = SV_MACE_OF_DISRUPTION; } else if (r < 33) { /* Create a long, sharp-edged weapon. */ tval = TV_SWORD; r2 = Rand_normal(target_level * 2, target_level); if (r2 < 0) sval = SV_BROKEN_DAGGER; else if (r2 < 1) sval = SV_BROKEN_SWORD; else if (r2 < 5) sval = SV_DAGGER; else if (r2 < 9) sval = SV_MAIN_GAUCHE; else if (r2 < 10) sval = SV_RAPIER; /* or at least pointy ;-) */ else if (r2 < 12) sval = SV_SMALL_SWORD; else if (r2 < 14) sval = SV_SHORT_SWORD; else if (r2 < 16) sval = SV_SABRE; else if (r2 < 18) sval = SV_CUTLASS; else if (r2 < 20) sval = SV_TULWAR; else if (r2 < 23) sval = SV_BROAD_SWORD; else if (r2 < 26) sval = SV_LONG_SWORD; else if (r2 < 30) sval = SV_SCIMITAR; else if (r2 < 45) sval = SV_BASTARD_SWORD; else if (r2 < 60) sval = SV_KATANA; else if (r2 < 90) sval = SV_TWO_HANDED_SWORD; else if (r2 < 120) sval = SV_EXECUTIONERS_SWORD; else sval = SV_BLADE_OF_CHAOS; } else if (r < 42) { /* Create a weapon that's not blunt or sword-shaped. */ tval = TV_POLEARM; r2 = Rand_normal(target_level * 2, target_level); if (r2 < 12) sval = SV_SPEAR; else if (r2 < 20) sval = SV_TRIDENT; else if (r2 < 27) sval = SV_LANCE; else if (r2 < 35) sval = SV_AWL_PIKE; else if (r2 < 45) sval = SV_PIKE; else if (r2 < 50) sval = SV_BEAKED_AXE; else if (r2 < 55) sval = SV_BROAD_AXE; else if (r2 < 60) sval = SV_BATTLE_AXE; else if (r2 < 65) sval = SV_GLAIVE; else if (r2 < 80) sval = SV_HALBERD; else if (r2 < 120) sval = SV_GREAT_AXE; else if (r2 < 128) sval = SV_SCYTHE; else if (r2 < 135) sval = SV_LOCHABER_AXE; else sval = SV_SCYTHE_OF_SLICING; } else if (r < 64) { /* Create light or hard body armor. */ r2 = Rand_normal(target_level * 2, target_level); if (r2 < 45) tval = TV_SOFT_ARMOR; else tval = TV_HARD_ARMOR; /* Soft stuff. */ if (r2 < 0) sval = SV_FILTHY_RAG; else if (r2 < 5) sval = SV_ROBE; else if (r2 < 10) sval = SV_SOFT_LEATHER_ARMOR; else if (r2 < 15) sval = SV_SOFT_STUDDED_LEATHER; else if (r2 < 20) sval = SV_HARD_LEATHER_ARMOR; else if (r2 < 30) sval = SV_HARD_STUDDED_LEATHER; else if (r2 < 45) sval = SV_LEATHER_SCALE_MAIL; /* Hard stuff. */ else if (r2 < 55) sval = SV_RUSTY_CHAIN_MAIL; else if (r2 < 65) sval = SV_METAL_SCALE_MAIL; else if (r2 < 75) sval = SV_CHAIN_MAIL; else if (r2 < 85) sval = SV_AUGMENTED_CHAIN_MAIL; else if (r2 < 90) sval = SV_DOUBLE_CHAIN_MAIL; else if (r2 < 97) sval = SV_BAR_CHAIN_MAIL; else if (r2 < 105) sval = SV_METAL_BRIGANDINE_ARMOUR; else if (r2 < 115) sval = SV_PARTIAL_PLATE_ARMOUR; else if (r2 < 125) sval = SV_METAL_LAMELLAR_ARMOUR; else if (r2 < 135) sval = SV_FULL_PLATE_ARMOUR; else if (r2 < 140) sval = SV_RIBBED_PLATE_ARMOUR; else if (r2 < 150) sval = SV_MITHRIL_CHAIN_MAIL; else if (r2 < 170) sval = SV_MITHRIL_PLATE_MAIL; else sval = SV_ADAMANTITE_PLATE_MAIL; } else if (r < 71) { /* Make shoes. */ tval = TV_BOOTS; r2 = Rand_normal(target_level * 2, target_level); if (r2 < 9) sval = SV_PAIR_OF_SOFT_LEATHER_BOOTS; else if (r2 < 15) sval = SV_PAIR_OF_HARD_LEATHER_BOOTS; else sval = SV_PAIR_OF_METAL_SHOD_BOOTS; } else if (r < 78) { /* Make gloves. */ tval = TV_GLOVES; r2 = Rand_normal(target_level * 2, target_level); if (r2 < 10) sval = SV_SET_OF_LEATHER_GLOVES; else if (r2 < 30) sval = SV_SET_OF_GAUNTLETS; else sval = SV_SET_OF_CESTI; } else if (r < 87) { /* Make headgear. */ r2 = Rand_normal(target_level * 2, target_level); if (r2 < 50) tval = TV_HELM; else tval = TV_CROWN; if (r2 < 9) sval = SV_HARD_LEATHER_CAP; else if (r2 < 20) sval = SV_METAL_CAP; else if (r2 < 40) sval = SV_IRON_HELM; else if (r2 < 50) sval = SV_STEEL_HELM; else if (r2 < 60) sval = SV_IRON_CROWN; else if (r2 < 90) sval = SV_GOLDEN_CROWN; else sval = SV_JEWELED_CROWN; } else if (r < 94) { /* Make a shield. */ tval = TV_SHIELD; r2 = Rand_normal(target_level * 2, target_level); if (r2 < 9) sval = SV_SMALL_LEATHER_SHIELD; else if (r2 < 20) sval = SV_SMALL_METAL_SHIELD; else if (r2 < 40) sval = SV_LARGE_LEATHER_SHIELD; else if (r2 < 60) sval = SV_LARGE_METAL_SHIELD; else sval = SV_SHIELD_OF_DEFLECTION; } else { /* Make a cloak. */ tval = TV_CLOAK; r2 = Rand_normal(target_level * 2, target_level); if (r2 < 90) sval = SV_CLOAK; else sval = SV_SHADOW_CLOAK; } k_idx = lookup_kind(tval, sval); k_ptr = &k_info[k_idx]; kinds[a_idx] = k_idx; /* * Subtract the new object kind's rarity (see above). We can't * blindly subtract, because a_ptr->rarity is a byte. */ if (a_ptr->rarity <= k_ptr->chance[0]) a_ptr->rarity = 1; else a_ptr->rarity -= k_ptr->chance[0]; a_ptr->tval = k_ptr->tval; a_ptr->sval = k_ptr->sval; a_ptr->pval = k_ptr->pval; a_ptr->to_h = k_ptr->to_h; a_ptr->to_d = k_ptr->to_d; a_ptr->to_a = k_ptr->to_a; a_ptr->ac = k_ptr->ac; a_ptr->dd = k_ptr->dd; a_ptr->ds = k_ptr->ds; a_ptr->weight = k_ptr->weight; a_ptr->flags1 = k_ptr->flags1; a_ptr->flags2 = k_ptr->flags2; a_ptr->flags3 = k_ptr->flags3; /* Artifacts ignore everything */ a_ptr->flags3 |= TR3_IGNORE_MASK; /* Assign basic stats to the artifact based on its artifact level. */ switch (a_ptr->tval) { case TV_BOW: case TV_DIGGING: case TV_HAFTED: case TV_SWORD: case TV_POLEARM: a_ptr->to_h += (s16b)(a_ptr->level / 10 + rand_int(4) + rand_int(4)); a_ptr->to_d += (s16b)(a_ptr->level / 10 + rand_int(4) + rand_int((a_ptr->dd * a_ptr->ds) / 2 + 1)); break; case TV_BOOTS: case TV_GLOVES: case TV_HELM: case TV_CROWN: case TV_SHIELD: case TV_CLOAK: case TV_SOFT_ARMOR: case TV_HARD_ARMOR: a_ptr->to_a += (s16b)(a_ptr->level / 10 + a_ptr->ac / 3 + rand_int(8)); if (a_ptr->to_a < 10) a_ptr->to_a += (s16b)(2 + rand_int(4) + rand_int(4)); /* * Make sure armor gets some resists! Hard body armor * is generally high-level stuff, with good ac and * to_a. That sucks up all the points.... */ switch (a_ptr->tval) { case TV_SOFT_ARMOR: case TV_HARD_ARMOR: if (rand_int(2) == 0) a_ptr->flags2 |= TR2_RES_ACID; if (rand_int(2) == 0) a_ptr->flags2 |= TR2_RES_ELEC; if (rand_int(2) == 0) a_ptr->flags2 |= TR2_RES_COLD; if (rand_int(2) == 0) a_ptr->flags2 |= TR2_RES_FIRE; break; } break; } } /* * We've just added an ability which uses the pval bonus. Make sure it's * not zero. If it's currently negative, leave it negative (heh heh). */ static void do_pval(artifact_type *a_ptr) { if (a_ptr->pval == 0) a_ptr->pval = (s16b)(1 + rand_int(3)); else if (a_ptr->pval < 0) { if (rand_int(2) == 0) a_ptr->pval--; } else if (rand_int(3) > 0) a_ptr->pval++; } static void remove_contradictory(artifact_type *a_ptr) { if (a_ptr->flags3 & TR3_AGGRAVATE) a_ptr->flags1 &= ~(TR1_STEALTH); if (a_ptr->flags2 & TR2_IM_ACID) a_ptr->flags2 &= ~(TR2_RES_ACID); if (a_ptr->flags2 & TR2_IM_ELEC) a_ptr->flags2 &= ~(TR2_RES_ELEC); if (a_ptr->flags2 & TR2_IM_FIRE) a_ptr->flags2 &= ~(TR2_RES_FIRE); if (a_ptr->flags2 & TR2_IM_COLD) a_ptr->flags2 &= ~(TR2_RES_COLD); if (a_ptr->pval < 0) { if (a_ptr->flags1 & TR1_STR) a_ptr->flags2 &= ~(TR2_SUST_STR); if (a_ptr->flags1 & TR1_INT) a_ptr->flags2 &= ~(TR2_SUST_INT); if (a_ptr->flags1 & TR1_WIS) a_ptr->flags2 &= ~(TR2_SUST_WIS); if (a_ptr->flags1 & TR1_DEX) a_ptr->flags2 &= ~(TR2_SUST_DEX); if (a_ptr->flags1 & TR1_CON) a_ptr->flags2 &= ~(TR2_SUST_CON); if (a_ptr->flags1 & TR1_CHR) a_ptr->flags2 &= ~(TR2_SUST_CHR); a_ptr->flags1 &= ~(TR1_BLOWS); } if (a_ptr->flags3 & TR3_LIGHT_CURSE) a_ptr->flags3 &= ~(TR3_BLESSED); if (a_ptr->flags1 & TR1_KILL_DRAGON) a_ptr->flags1 &= ~(TR1_SLAY_DRAGON); if (a_ptr->flags3 & TR3_DRAIN_EXP) a_ptr->flags3 &= ~(TR3_HOLD_LIFE); } /* * Randomly select an extra ability to be added to the artifact in question. * XXX - This function is way too large. */ static void add_ability(artifact_type *a_ptr) { int r; r = rand_int(10); if (r < 5) /* Pick something dependent on item type. */ { r = rand_int(100); switch (a_ptr->tval) { case TV_BOW: { if (r < 15) { a_ptr->flags1 |= TR1_SHOTS; do_pval(a_ptr); } else if (r < 35) { a_ptr->flags1 |= TR1_MIGHT; do_pval(a_ptr); } else if (r < 65) a_ptr->to_h += (s16b)(2 + rand_int(2)); else a_ptr->to_d += (s16b)(2 + rand_int(3)); break; } case TV_DIGGING: case TV_HAFTED: case TV_POLEARM: case TV_SWORD: { if (r < 4) { a_ptr->flags1 |= TR1_WIS; do_pval(a_ptr); if (rand_int(2) == 0) a_ptr->flags2 |= TR2_SUST_WIS; if (a_ptr->tval == TV_SWORD || a_ptr->tval == TV_POLEARM) a_ptr->flags3 |= TR3_BLESSED; } else if (r < 7) { a_ptr->flags1 |= TR1_BRAND_ACID; if (rand_int(4) > 0) a_ptr->flags2 |= TR2_RES_ACID; } else if (r < 10) { a_ptr->flags1 |= TR1_BRAND_ELEC; if (rand_int(4) > 0) a_ptr->flags2 |= TR2_RES_ELEC; } else if (r < 15) { a_ptr->flags1 |= TR1_BRAND_FIRE; if (rand_int(4) > 0) a_ptr->flags2 |= TR2_RES_FIRE; } else if (r < 20) { a_ptr->flags1 |= TR1_BRAND_COLD; if (rand_int(4) > 0) a_ptr->flags2 |= TR2_RES_COLD; } else if (r < 28) { a_ptr->dd += (byte)(1 + rand_int(2) + rand_int(2)); if (a_ptr->dd > 9) a_ptr->dd = 9; } else if (r < 31) a_ptr->flags1 |= TR1_KILL_DRAGON; else if (r < 35) a_ptr->flags1 |= TR1_SLAY_DRAGON; else if (r < 40) a_ptr->flags1 |= TR1_SLAY_EVIL; else if (r < 45) a_ptr->flags1 |= TR1_SLAY_ANIMAL; else if (r < 50) { a_ptr->flags1 |= TR1_SLAY_UNDEAD; if (rand_int(2) == 0) a_ptr->flags1 |= TR1_SLAY_DEMON; } else if (r < 54) { a_ptr->flags1 |= TR1_SLAY_DEMON; if (rand_int(2) == 0) a_ptr->flags1 |= TR1_SLAY_UNDEAD; } else if (r < 59) { a_ptr->flags1 |= TR1_SLAY_ORC; if (rand_int(2) == 0) a_ptr->flags1 |= TR1_SLAY_TROLL; if (rand_int(2) == 0) a_ptr->flags1 |= TR1_SLAY_GIANT; } else if (r < 63) { a_ptr->flags1 |= TR1_SLAY_TROLL; if (rand_int(2) == 0) a_ptr->flags1 |= TR1_SLAY_ORC; if (rand_int(2) == 0) a_ptr->flags1 |= TR1_SLAY_GIANT; } else if (r < 67) { a_ptr->flags1 |= TR1_SLAY_GIANT; if (rand_int(2) == 0) a_ptr->flags1 |= TR1_SLAY_ORC; if (rand_int(2) == 0) a_ptr->flags1 |= TR1_SLAY_TROLL; } else if (r < 72) a_ptr->flags3 |= TR3_SEE_INVIS; else if (r < 76) { if (a_ptr->pval < 0) break; a_ptr->flags1 |= TR1_BLOWS; do_pval(a_ptr); } else if (r < 89) { a_ptr->to_d += (s16b)(3 + rand_int(4)); a_ptr->to_h += (s16b)(3 + rand_int(4)); } else if (r < 92) a_ptr->to_a += (s16b)(3 + rand_int(3)); else if (r < 98) a_ptr->weight = (a_ptr->weight * 9) / 10; else if (a_ptr->tval != TV_DIGGING) { a_ptr->flags1 |= TR1_TUNNEL; do_pval(a_ptr); } break; } case TV_BOOTS: { if (r < 10) a_ptr->flags3 |= TR3_FEATHER; else if (r < 50) a_ptr->to_a += (s16b)(2 + rand_int(4)); else if (r < 80) { a_ptr->flags1 |= TR1_STEALTH; do_pval(a_ptr); } else if (r < 90) { a_ptr->flags1 |= TR1_SPEED; if (a_ptr->pval < 0) break; if (a_ptr->pval == 0) a_ptr->pval = (s16b)(3 + rand_int(8)); else if (rand_int(2) == 0) a_ptr->pval++; } else a_ptr->weight = (a_ptr->weight * 9) / 10; break; } case TV_GLOVES: { if (r < 25) a_ptr->flags3 |= TR3_FREE_ACT; else if (r < 50) { a_ptr->flags1 |= TR1_DEX; do_pval(a_ptr); } else if (r < 75) a_ptr->to_a += (s16b)(3 + rand_int(3)); else { a_ptr->to_h += (s16b)(2 + rand_int(3)); a_ptr->to_d += (s16b)(2 + rand_int(3)); a_ptr->flags3 |= TR3_SHOW_MODS; } break; } case TV_HELM: case TV_CROWN: { if (r < 20) a_ptr->flags2 |= TR2_RES_BLIND; else if (r < 45) a_ptr->flags3 |= TR3_TELEPATHY; else if (r < 65) a_ptr->flags3 |= TR3_SEE_INVIS; else if (r < 75) { a_ptr->flags1 |= TR1_WIS; do_pval(a_ptr); } else if (r < 85) { a_ptr->flags1 |= TR1_INT; do_pval(a_ptr); } else a_ptr->to_a += (s16b)(3 + rand_int(3)); break; } case TV_SHIELD: { if (r < 20) a_ptr->flags2 |= TR2_RES_ACID; else if (r < 40) a_ptr->flags2 |= TR2_RES_ELEC; else if (r < 60) a_ptr->flags2 |= TR2_RES_FIRE; else if (r < 80) a_ptr->flags2 |= TR2_RES_COLD; else a_ptr->to_a += (s16b)(3 + rand_int(3)); break; } case TV_CLOAK: { if (r < 50) { a_ptr->flags1 |= TR1_STEALTH; do_pval(a_ptr); } else a_ptr->to_a += (s16b)(3 + rand_int(3)); break; } case TV_SOFT_ARMOR: case TV_HARD_ARMOR: { if (r < 8) { a_ptr->flags1 |= TR1_STEALTH; do_pval(a_ptr); } else if (r < 16) a_ptr->flags3 |= TR3_HOLD_LIFE; else if (r < 22) { a_ptr->flags1 |= TR1_CON; do_pval(a_ptr); if (rand_int(2) == 0) a_ptr->flags2 |= TR2_SUST_CON; } else if (r < 34) a_ptr->flags2 |= TR2_RES_ACID; else if (r < 46) a_ptr->flags2 |= TR2_RES_ELEC; else if (r < 58) a_ptr->flags2 |= TR2_RES_FIRE; else if (r < 70) a_ptr->flags2 |= TR2_RES_COLD; else if (r < 80) a_ptr->weight = (a_ptr->weight * 9) / 10; else a_ptr->to_a += (s16b)(3 + rand_int(3)); break; } } } else /* Pick something universally useful. */ { r = rand_int(43); switch (r) { case 0: a_ptr->flags1 |= TR1_STR; do_pval(a_ptr); if (rand_int(2) == 0) a_ptr->flags2 |= TR2_SUST_STR; break; case 1: a_ptr->flags1 |= TR1_INT; do_pval(a_ptr); if (rand_int(2) == 0) a_ptr->flags2 |= TR2_SUST_INT; break; case 2: a_ptr->flags1 |= TR1_WIS; do_pval(a_ptr); if (rand_int(2) == 0) a_ptr->flags2 |= TR2_SUST_WIS; if (a_ptr->tval == TV_SWORD || a_ptr->tval == TV_POLEARM) a_ptr->flags3 |= TR3_BLESSED; break; case 3: a_ptr->flags1 |= TR1_DEX; do_pval(a_ptr); if (rand_int(2) == 0) a_ptr->flags2 |= TR2_SUST_DEX; break; case 4: a_ptr->flags1 |= TR1_CON; do_pval(a_ptr); if (rand_int(2) == 0) a_ptr->flags2 |= TR2_SUST_CON; break; case 5: a_ptr->flags1 |= TR1_CHR; do_pval(a_ptr); if (rand_int(2) == 0) a_ptr->flags2 |= TR2_SUST_CHR; break; case 6: a_ptr->flags1 |= TR1_STEALTH; do_pval(a_ptr); break; case 7: a_ptr->flags1 |= TR1_SEARCH; do_pval(a_ptr); break; case 8: a_ptr->flags1 |= TR1_INFRA; do_pval(a_ptr); break; case 9: a_ptr->flags1 |= TR1_SPEED; if (a_ptr->pval == 0) a_ptr->pval = (s16b)(3 + rand_int(3)); else do_pval(a_ptr); break; case 10: a_ptr->flags2 |= TR2_SUST_STR; if (rand_int(2) == 0) { a_ptr->flags1 |= TR1_STR; do_pval(a_ptr); } break; case 11: a_ptr->flags2 |= TR2_SUST_INT; if (rand_int(2) == 0) { a_ptr->flags1 |= TR1_INT; do_pval(a_ptr); } break; case 12: a_ptr->flags2 |= TR2_SUST_WIS; if (rand_int(2) == 0) { a_ptr->flags1 |= TR1_WIS; do_pval(a_ptr); if (a_ptr->tval == TV_SWORD || a_ptr->tval == TV_POLEARM) a_ptr->flags3 |= TR3_BLESSED; } break; case 13: a_ptr->flags2 |= TR2_SUST_DEX; if (rand_int(2) == 0) { a_ptr->flags1 |= TR1_DEX; do_pval(a_ptr); } break; case 14: a_ptr->flags2 |= TR2_SUST_CON; if (rand_int(2) == 0) { a_ptr->flags1 |= TR1_CON; do_pval(a_ptr); } break; case 15: a_ptr->flags2 |= TR2_SUST_CHR; if (rand_int(2) == 0) { a_ptr->flags1 |= TR1_CHR; do_pval(a_ptr); } break; case 16: { if (rand_int(3) == 0) a_ptr->flags2 |= TR2_IM_ACID; break; } case 17: { if (rand_int(3) == 0) a_ptr->flags2 |= TR2_IM_ELEC; break; } case 18: { if (rand_int(4) == 0) a_ptr->flags2 |= TR2_IM_FIRE; break; } case 19: { if (rand_int(3) == 0) a_ptr->flags2 |= TR2_IM_COLD; break; } case 20: a_ptr->flags3 |= TR3_FREE_ACT; break; case 21: a_ptr->flags3 |= TR3_HOLD_LIFE; break; case 22: a_ptr->flags2 |= TR2_RES_ACID; break; case 23: a_ptr->flags2 |= TR2_RES_ELEC; break; case 24: a_ptr->flags2 |= TR2_RES_FIRE; break; case 25: a_ptr->flags2 |= TR2_RES_COLD; break; case 26: a_ptr->flags2 |= TR2_RES_POIS; break; case 27: a_ptr->flags2 |= TR2_RES_LITE; break; case 28: a_ptr->flags2 |= TR2_RES_DARK; break; case 29: a_ptr->flags2 |= TR2_RES_BLIND; break; case 30: a_ptr->flags2 |= TR2_RES_CONFU; break; case 31: a_ptr->flags2 |= TR2_RES_SOUND; break; case 32: a_ptr->flags2 |= TR2_RES_SHARD; break; case 33: if (rand_int(2) == 0) a_ptr->flags2 |= TR2_RES_NETHR; break; case 34: a_ptr->flags2 |= TR2_RES_NEXUS; break; case 35: a_ptr->flags2 |= TR2_RES_CHAOS; break; case 36: if (rand_int(2) == 0) a_ptr->flags2 |= TR2_RES_DISEN; break; case 37: a_ptr->flags3 |= TR3_FEATHER; break; case 38: a_ptr->flags3 |= TR3_LITE; break; case 39: a_ptr->flags3 |= TR3_SEE_INVIS; break; case 40: if (rand_int(3) == 0) a_ptr->flags3 |= TR3_TELEPATHY; break; case 41: a_ptr->flags3 |= TR3_SLOW_DIGEST; break; case 42: a_ptr->flags3 |= TR3_REGEN; break; } } /* Now remove contradictory or redundant powers. */ remove_contradictory(a_ptr); } /* * Make it bad, or if it's already bad, make it worse! */ static void do_curse(artifact_type *a_ptr) { if (rand_int(3) == 0) a_ptr->flags3 |= TR3_AGGRAVATE; if (rand_int(5) == 0) a_ptr->flags3 |= TR3_DRAIN_EXP; if (rand_int(7) == 0) a_ptr->flags3 |= TR3_TELEPORT; if ((a_ptr->pval > 0) && (rand_int(2) == 0)) a_ptr->pval = -a_ptr->pval; if ((a_ptr->to_a > 0) && (rand_int(2) == 0)) a_ptr->to_a = -a_ptr->to_a; if ((a_ptr->to_h > 0) && (rand_int(2) == 0)) a_ptr->to_h = -a_ptr->to_h; if ((a_ptr->to_d > 0) && (rand_int(4) == 0)) a_ptr->to_d = -a_ptr->to_d; if (a_ptr->flags3 & TR3_LIGHT_CURSE) { if (rand_int(2) == 0) a_ptr->flags3 |= TR3_HEAVY_CURSE; return; } a_ptr->flags3 |= TR3_LIGHT_CURSE; if (rand_int(4) == 0) a_ptr->flags3 |= TR3_HEAVY_CURSE; } /* * Note the three special cases (One Ring, Grond, Morgoth). */ static int scramble_artifact(int a_idx) { artifact_type *a_ptr = &a_info[a_idx]; u32b activates = a_ptr->flags3 & TR3_ACTIVATE; s32b power; int tries; s32b ap; bool curse_me = FALSE; bool aggravate_me = FALSE; /* Special cases -- don't randomize these! */ if ((a_idx == ART_POWER) || (a_idx == ART_GROND) || (a_idx == ART_MORGOTH)) return 0; /* Skip unused artifacts, too! */ if (a_ptr->tval == 0) return 0; /* Evaluate the original artifact to determine the power level. */ power = artifact_power(a_idx, TRUE); if (power < 0) curse_me = TRUE; if (randart_verbose) msg_format("Artifact %d: power = %d", a_idx, power); /* Really powerful items should aggravate. */ if (power > 100) { if (rand_int(100) < (power - 100) * 3) aggravate_me = TRUE; } if (a_idx >= ART_MIN_NORMAL) { /* * Normal artifact - choose a random base item type. Not too * powerful, so we'll have to add something to it. Not too * weak, for the opposite reason. */ int count = 0; s32b ap2; do { choose_item(a_idx); ap2 = artifact_power(a_idx, FALSE); count++; } while ((count < MAX_TRIES) && ((ap2 > (power * 8) / 10 + 1) || (ap2 < (power / 10)))); } else { /* Special artifact (light source, ring, or amulet). Clear the following fields; leave the rest alone. */ a_ptr->pval = 0; a_ptr->to_h = a_ptr->to_d = a_ptr->to_a = 0; a_ptr->flags1 = a_ptr->flags2 = 0; /* Artifacts ignore everything */ a_ptr->flags3 = (TR3_IGNORE_MASK); } /* First draft: add two abilities, then curse it three times. */ if (curse_me) { add_ability(a_ptr); add_ability(a_ptr); do_curse(a_ptr); do_curse(a_ptr); do_curse(a_ptr); remove_contradictory(a_ptr); ap = artifact_power(a_idx, FALSE); } else { /* * Select a random set of abilities which roughly matches the * original's in terms of overall power/usefulness. */ for (tries = 0; tries < MAX_TRIES; tries++) { artifact_type a_old; /* Copy artifact info temporarily. */ a_old = *a_ptr; add_ability(a_ptr); ap = artifact_power(a_idx, FALSE); if (ap > (power * 11) / 10 + 1) { /* too powerful -- put it back */ *a_ptr = a_old; continue; } else if (ap >= (power * 9) / 10) /* just right */ { break; } /* Stop if we're going negative, so we don't overload the artifact with great powers to compensate. */ else if ((ap < 0) && (ap < (-(power * 1)) / 10)) { break; } } /* end of power selection */ if (aggravate_me) { a_ptr->flags3 |= TR3_AGGRAVATE; remove_contradictory(a_ptr); ap = artifact_power(a_idx, FALSE); } } a_ptr->cost = ap * (s32b)1000; if (a_ptr->cost < 0) a_ptr->cost = 0; #if 0 /* One last hack: if the artifact is very powerful, raise the rarity. This compensates for artifacts like (original) Bladeturner, which have low artifact rarities but came from extremely-rare base kinds. */ if ((ap > 0) && ((ap / 8) > a_ptr->rarity)) a_ptr->rarity = ap / 8; #endif /* 0 */ /* Restore some flags */ if (activates) a_ptr->flags3 |= TR3_ACTIVATE; if (a_idx < ART_MIN_NORMAL) a_ptr->flags3 |= TR3_INSTA_ART; /* * Add TR3_HIDE_TYPE to all artifacts with nonzero pval because we're * too lazy to find out which ones need it and which ones don't. */ if (a_ptr->pval) a_ptr->flags3 |= TR3_HIDE_TYPE; return 0; } /* * Return nonzero if the whole set of random artifacts meets certain * criteria. Return 0 if we fail to meet those criteria (which will * restart the whole process). */ static int artifacts_acceptable(void) { int swords = 5, polearms = 5, blunts = 5, bows = 3; int bodies = 5, shields = 3, cloaks = 3, hats = 4; int gloves = 4, boots = 4; int i; for (i = ART_MIN_NORMAL; i < z_info->a_max; i++) { switch (a_info[i].tval) { case TV_SWORD: swords--; break; case TV_POLEARM: polearms--; break; case TV_HAFTED: blunts--; break; case TV_BOW: bows--; break; case TV_SOFT_ARMOR: case TV_HARD_ARMOR: bodies--; break; case TV_SHIELD: shields--; break; case TV_CLOAK: cloaks--; break; case TV_HELM: case TV_CROWN: hats--; break; case TV_GLOVES: gloves--; break; case TV_BOOTS: boots--; break; } } if (swords > 0 || polearms > 0 || blunts > 0 || bows > 0 || bodies > 0 || shields > 0 || cloaks > 0 || hats > 0 || gloves > 0 || boots > 0) { if (randart_verbose) { char types[256]; sprintf(types, "%s%s%s%s%s%s%s%s%s%s", swords > 0 ? " swords" : "", polearms > 0 ? " polearms" : "", blunts > 0 ? " blunts" : "", bows > 0 ? " bows" : "", bodies > 0 ? " body-armors" : "", shields > 0 ? " shields" : "", cloaks > 0 ? " cloaks" : "", hats > 0 ? " hats" : "", gloves > 0 ? " gloves" : "", boots > 0 ? " boots" : ""); msg_format("Restarting generation process: not enough%s\n", types); } return 0; } else { return 1; } } static int scramble(void) { /* This outer loop is for post-processing. If our artifact set fails to meet certain criteria, we start over. :-( */ do { int a_idx; /* Generate all the artifacts. */ for (a_idx = 1; a_idx < z_info->a_max; a_idx++) { scramble_artifact(a_idx); } } while (!artifacts_acceptable()); /* end of all artifacts */ return 0; } static int do_randart_aux(void) { int result; if ((result = init_names()) != 0) return result; if ((result = scramble()) != 0) return result; return 0; } int do_randart(u32b randart_seed) { int rc; /* Prepare to use the Angband "simple" RNG. */ Rand_value = randart_seed; Rand_quick = TRUE; /* Allocate the "kinds" array */ C_MAKE(kinds, z_info->a_max, s16b); rc = do_randart_aux(); /* Free the "kinds" array */ C_FREE(kinds, z_info->a_max, s16b); /* When done, resume use of the Angband "complex" RNG. */ Rand_quick = FALSE; return rc; } #endif /* GJW_RANDART */