summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/artefact.cc
diff options
context:
space:
mode:
authorzelgadis <zelgadis@c06c8d41-db1a-0410-9941-cceddc491573>2009-06-25 02:29:14 +0000
committerzelgadis <zelgadis@c06c8d41-db1a-0410-9941-cceddc491573>2009-06-25 02:29:14 +0000
commit2fad05374f70f21d4af3d147325581bf1047b5be (patch)
tree40a46254f044837f658e4dbabb07ce3c52b72804 /crawl-ref/source/artefact.cc
parentab0e3274d569d1cdea4010f4ed1d4b24cd3804e9 (diff)
downloadcrawl-ref-2fad05374f70f21d4af3d147325581bf1047b5be.tar.gz
crawl-ref-2fad05374f70f21d4af3d147325581bf1047b5be.zip
First part of the merger of fixed artefacts into unrandom artefacts
(further changes will be much smaller). Breaks savefile compatibility, and bumps the major savefile version up to 6. Some changes made to some tiles files, but it hasn't been tested with a tiles build. Overview of changes: * Unrand artefacts are now defined in art-data.txt and is turned into C code via util/art-data.pl. This has the dual advantage of being more readable by humans, and that if the unrand data structure changes then you can just change util/art-data.pl and regenerate the C code rather than having to change some 70 different C structs by hand. * util/art-data.pl automatically updates NO_UNRANDARTS, and also automatically generates an enumeration of all the unrands which are equal to their item.special field. * randart.cc and randart.h have been renamed to artefact.cc and artefact.h, since the files covers all types of artefacts, and the differences between randarts, unrandarts and (former) fixed arts have been minimized since the terms were introduced. Also renamed unrand.h to art-data.h * The brands and resistances of former fixed arts are now handled via artefact properties, but the rest of their special behaviours are still hardcoded. * Unrandarts are now distinguished between normal and "special", with the special ones currently just being identical to the list of the formed fixed arts. Special unrandarts are randomly generated less often than normal unrandarts, can be generated in the Abyss if they've been lost, can't be picked up by monsters, and can't be affected by Tukima's Dance. git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@10035 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'crawl-ref/source/artefact.cc')
-rw-r--r--crawl-ref/source/artefact.cc2016
1 files changed, 2016 insertions, 0 deletions
diff --git a/crawl-ref/source/artefact.cc b/crawl-ref/source/artefact.cc
new file mode 100644
index 0000000000..e026b73baf
--- /dev/null
+++ b/crawl-ref/source/artefact.cc
@@ -0,0 +1,2016 @@
+/*
+ * File: artefact.cc
+ * Summary: Random and unrandom artefact functions.
+ * Written by: Linley Henzell
+ *
+ * Modified for Crawl Reference by $Author$ on $Date$
+ */
+
+#include "AppHdr.h"
+REVISION("$Rev$");
+
+#include "artefact.h"
+
+#include <cstdlib>
+#include <climits>
+#include <string.h>
+#include <stdio.h>
+#include <algorithm>
+
+#include "externs.h"
+
+#include "database.h"
+#include "describe.h"
+#include "itemname.h"
+#include "itemprop.h"
+#include "items.h"
+#include "place.h"
+#include "player.h"
+#include "religion.h"
+#include "spl-book.h"
+#include "stuff.h"
+
+#define KNOWN_PROPS_KEY "artefact_known_props"
+#define ARTEFACT_PROPS_KEY "artefact_props"
+#define ARTEFACT_NAME_KEY "artefact_name"
+#define ARTEFACT_APPEAR_KEY "artefact_appearance"
+
+// The initial generation of a randart is very simple - it occurs in
+// dungeon.cc and consists of giving it a few random things - plus &
+// plus2 mainly.
+
+static bool _god_fits_artefact(const god_type which_god, const item_def &item,
+ bool name_check_only = false)
+{
+ if (which_god == GOD_NO_GOD)
+ return (false);
+
+ // First check the item's base_type and sub_type, then check the
+ // item's brand and other randart properties.
+ bool type_bad = false;
+ switch (which_god)
+ {
+ case GOD_ELYVILON:
+ // Peaceful healer god: no weapons, no berserking.
+ if (item.base_type == OBJ_WEAPONS)
+ type_bad = true;
+
+ if (item.base_type == OBJ_JEWELLERY && item.sub_type == AMU_RAGE)
+ type_bad = true;
+ break;
+
+ case GOD_OKAWARU:
+ // Precision fighter god: no inaccuracy.
+ if (item.base_type == OBJ_JEWELLERY && item.sub_type == AMU_INACCURACY)
+ type_bad = true;
+ break;
+
+ case GOD_ZIN:
+ // Lawful god: no increased hunger.
+ if (item.base_type == OBJ_JEWELLERY && item.sub_type == RING_HUNGER)
+ type_bad = true;
+ break;
+
+ case GOD_SIF_MUNA:
+ case GOD_KIKUBAAQUDGHA:
+ case GOD_VEHUMET:
+ // The magic gods: no weapons, no preventing spellcasting.
+ if (item.base_type == OBJ_WEAPONS)
+ type_bad = true;
+ break;
+
+ case GOD_TROG:
+ // Anti-magic god: no spell use, no enhancing magic.
+ if (item.base_type == OBJ_BOOKS)
+ type_bad = true;
+
+ if (item.base_type == OBJ_JEWELLERY && (item.sub_type == RING_WIZARDRY
+ || item.sub_type == RING_FIRE || item.sub_type == RING_ICE
+ || item.sub_type == RING_MAGICAL_POWER))
+ {
+ type_bad = true;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (type_bad && !name_check_only)
+ {
+ ASSERT(!"God attempting to gift invalid type of item.");
+ mprf(MSGCH_ERROR, "%s attempting to gift invalid type of item.",
+ god_name(which_god).c_str());
+ // Prevent infinite loop in make_item_randart().
+ return (true);
+ }
+
+ if (type_bad)
+ return (false);
+
+ const int brand = get_weapon_brand(item);
+
+ if (is_evil_god(which_god) && brand == SPWPN_HOLY_WRATH)
+ return (false);
+ else if (is_good_god(which_god)
+ && (brand == SPWPN_DRAINING || brand == SPWPN_PAIN
+ || brand == SPWPN_VAMPIRICISM
+ || artefact_wpn_property(item, ARTP_CURSED) != 0))
+ {
+ return (false);
+ }
+
+ switch (which_god)
+ {
+ case GOD_BEOGH:
+ // Orc god: no orc slaying.
+ if (brand == SPWPN_ORC_SLAYING)
+ return (false);
+ break;
+
+ case GOD_ELYVILON:
+ // Peaceful healer god: no berserking.
+ if (artefact_wpn_property(item, ARTP_ANGRY)
+ || artefact_wpn_property(item, ARTP_BERSERK))
+ {
+ return (false);
+ }
+ break;
+
+ case GOD_ZIN:
+ // Lawful god: no mutagenics.
+ if (artefact_wpn_property(item, ARTP_MUTAGENIC))
+ return (false);
+ break;
+
+ case GOD_SHINING_ONE:
+ // Crusader god: holiness, honourable combat.
+ if (item.base_type == OBJ_WEAPONS && brand != SPWPN_HOLY_WRATH)
+ return (false);
+
+ if (artefact_wpn_property(item, ARTP_INVISIBLE)
+ || artefact_wpn_property(item, ARTP_STEALTH) > 0)
+ {
+ return (false);
+ }
+ break;
+
+ case GOD_LUGONU:
+ // Abyss god: corruption.
+ if (item.base_type == OBJ_WEAPONS && brand != SPWPN_DISTORTION)
+ return (false);
+ break;
+
+ case GOD_SIF_MUNA:
+ case GOD_KIKUBAAQUDGHA:
+ case GOD_VEHUMET:
+ // The magic gods: no preventing spellcasting.
+ if (artefact_wpn_property(item, ARTP_PREVENT_SPELLCASTING))
+ return (false);
+ break;
+
+ case GOD_TROG:
+ // Anti-magic god: no spell use, no enhancing magic.
+ if (brand == SPWPN_PAIN) // Pain involves necromantic spell use.
+ return (false);
+
+ if (artefact_wpn_property(item, ARTP_MAGICAL_POWER))
+ return (false);
+
+ default:
+ break;
+ }
+
+ return (true);
+}
+
+static std::string _replace_name_parts(const std::string name_in,
+ const item_def& item)
+{
+ std::string name = name_in;
+
+ god_type god_gift;
+ (void) origin_is_god_gift(item, &god_gift);
+
+ // Don't allow "player's Death" type names for god gifts (except
+ // for those from Xom).
+ if (name.find("@player_death@", 0) != std::string::npos
+ || name.find("@player_doom@", 0) != std::string::npos)
+ {
+ if (god_gift == GOD_NO_GOD || god_gift == GOD_XOM)
+ {
+ name = replace_all(name, "@player_death@",
+ "@player_name@"
+ + getRandNameString("killer_name"));
+ name = replace_all(name, "@player_doom@",
+ "@player_name@'s "
+ + getRandNameString("death_or_doom"));
+ }
+ else
+ {
+ // Simply overwrite the name with one of type "God's Favour".
+ name = "of ";
+ name += god_name(god_gift, false);
+ name += "'s ";
+ name += getRandNameString("divine_esteem");
+ }
+ }
+ name = replace_all(name, "@player_name@", you.your_name);
+
+ name = replace_all(name, "@player_species@",
+ species_name(static_cast<species_type>(you.species), 1));
+
+ if (name.find("@branch_name@", 0) != std::string::npos)
+ {
+ std::string place;
+ if (one_chance_in(5))
+ {
+ switch (random2(8))
+ {
+ case 0:
+ case 1:
+ default:
+ place = "the Abyss";
+ break;
+ case 2:
+ case 3:
+ place = "Pandemonium";
+ break;
+ case 4:
+ case 5:
+ place = "the Realm of Zot";
+ break;
+ case 6:
+ place = "the Labyrinth";
+ break;
+ case 7:
+ place = "the Portal Chambers";
+ break;
+ }
+ }
+ else
+ {
+ const branch_type branch =
+ static_cast<branch_type>(random2(BRANCH_TARTARUS));
+ place = place_name( get_packed_place(branch, 1, LEVEL_DUNGEON),
+ true, false );
+ }
+ if (!place.empty())
+ name = replace_all(name, "@branch_name@", place);
+ }
+
+ // Occasionally use long name for Xom (see religion.cc).
+ name = replace_all(name, "@xom_name@", god_name(GOD_XOM, coinflip()));
+
+ if (name.find("@god_name@", 0) != std::string::npos)
+ {
+ god_type which_god;
+
+ // God gifts will always get the gifting god's name.
+ if (god_gift != GOD_NO_GOD)
+ which_god = god_gift;
+ else
+ {
+ do
+ which_god = static_cast<god_type>(random2(NUM_GODS - 1) + 1);
+ while (!_god_fits_artefact(which_god, item, true));
+ }
+
+ name = replace_all(name, "@god_name@", god_name(which_god, false));
+ }
+
+ // copied from monster speech handling (mon-util.cc):
+ // The proper possessive for a word ending in an "s" is to
+ // put an apostrophe after the "s": "Chris" -> "Chris'",
+ // not "Chris" -> "Chris's". Stupid English language...
+ name = replace_all(name, "s's", "s'");
+
+ return name;
+}
+
+// Remember: disallow unrandart creation in Abyss/Pan.
+
+static unrandart_entry unranddata[] = {
+#include "art-data.h"
+};
+
+static FixedVector < bool, NO_UNRANDARTS > unrandart_exist;
+
+static unrandart_entry *_seekunrandart( const item_def &item );
+
+bool is_known_artefact( const item_def &item )
+{
+ if (!item_type_known(item))
+ return (false);
+
+ return (is_artefact(item));
+}
+
+bool is_artefact( const item_def &item )
+{
+ return (item.flags & ISFLAG_ARTEFACT_MASK);
+}
+
+// returns true is item is a pure randart
+bool is_random_artefact( const item_def &item )
+{
+ return (item.flags & ISFLAG_RANDART);
+}
+
+// returns true if item in an unrandart
+bool is_unrandom_artefact( const item_def &item )
+{
+ return (item.flags & ISFLAG_UNRANDART);
+}
+
+bool is_special_unrandom_artefact( const item_def &item )
+{
+ return (item.flags & ISFLAG_UNRANDART
+ && get_unrand_specialness(item.special) == UNRANDPSEC_SPECIAL);
+}
+
+unique_item_status_type get_unique_item_status(const item_def& item)
+{
+ if (item.flags & ISFLAG_UNRANDART)
+ return get_unique_item_status(item.special);
+
+ return (UNIQ_NOT_EXISTS);
+}
+
+unique_item_status_type get_unique_item_status( int art )
+{
+ ASSERT(art > UNRAND_START && art < UNRAND_LAST);
+ return (you.unique_items[art - UNRAND_START]);
+}
+
+void set_unique_item_status(const item_def& item,
+ unique_item_status_type status )
+{
+ if (item.flags & ISFLAG_UNRANDART)
+ set_unique_item_status(item.special, status);
+}
+
+void set_unique_item_status( int art, unique_item_status_type status )
+{
+ ASSERT(art > UNRAND_START && art < UNRAND_LAST);
+ you.unique_items[art - UNRAND_START] = status;
+}
+
+static long _calc_seed( const item_def &item )
+{
+ return (item.special & RANDART_SEED_MASK);
+}
+
+void artefact_desc_properties( const item_def &item,
+ artefact_properties_t &proprt,
+ artefact_known_props_t &known,
+ bool force_fake_props)
+{
+ // Randart books have no randart properties.
+ if (item.base_type == OBJ_BOOKS)
+ return;
+
+ artefact_wpn_properties( item, proprt, known);
+
+ if (!force_fake_props && item_ident( item, ISFLAG_KNOW_PROPERTIES ))
+ return;
+
+ // Only jewellery need fake randart properties.
+ if (item.base_type != OBJ_JEWELLERY)
+ return;
+
+ artefact_prop_type fake_rap = ARTP_NUM_PROPERTIES;
+ int fake_plus = 1;
+
+ // The base jewellery type is one whose property is revealed by
+ // wearing it, but whose property isn't revealed by having
+ // ISFLAG_KNOW_PLUSES set. For a randart with a base type of, for
+ // example, a ring of strength, wearing it sets
+ // ISFLAG_KNOW_PLUSES, which reveals the ring's strength plus.
+ switch (item.sub_type)
+ {
+ case RING_INVISIBILITY:
+ fake_rap = ARTP_INVISIBLE;
+ break;
+
+ case RING_TELEPORTATION:
+ fake_rap = ARTP_CAUSE_TELEPORTATION;
+ break;
+
+ case RING_MAGICAL_POWER:
+ fake_rap = ARTP_MAGICAL_POWER;
+ fake_plus = 9;
+ break;
+
+ case RING_LEVITATION:
+ fake_rap = ARTP_LEVITATE;
+ break;
+
+ case AMU_RAGE:
+ fake_rap = ARTP_BERSERK;
+ break;
+ }
+
+ if (fake_rap != ARTP_NUM_PROPERTIES)
+ {
+ proprt[fake_rap] += fake_plus;
+
+ if (item_ident( item, ISFLAG_KNOW_PROPERTIES )
+ || item_ident( item, ISFLAG_KNOW_TYPE ))
+ {
+ known[fake_rap] = true;
+ }
+
+ return;
+ }
+
+ if (!force_fake_props)
+ return;
+
+ // For auto-inscribing randart jewellery, force_fake_props folds as
+ // much info about the base type as possible into the randarts
+ // property struct.
+
+ artefact_prop_type fake_rap2 = ARTP_NUM_PROPERTIES;
+ int fake_plus2 = 1;
+
+ switch (item.sub_type)
+ {
+ case RING_PROTECTION:
+ fake_rap = ARTP_AC;
+ fake_plus = item.plus;
+ break;
+
+ case RING_PROTECTION_FROM_FIRE:
+ fake_rap = ARTP_FIRE;
+ break;
+
+ case RING_POISON_RESISTANCE:
+ fake_rap = ARTP_POISON;
+ break;
+
+ case RING_PROTECTION_FROM_COLD:
+ fake_rap = ARTP_COLD;
+ break;
+
+ case RING_SLAYING:
+ fake_rap = ARTP_ACCURACY;
+ fake_plus = item.plus;
+ fake_rap2 = ARTP_DAMAGE;
+ fake_plus2 = item.plus2;
+ break;
+
+ case RING_SEE_INVISIBLE:
+ fake_rap = ARTP_EYESIGHT;
+ break;
+
+ case RING_HUNGER:
+ fake_rap = ARTP_METABOLISM;
+ break;
+
+ case RING_EVASION:
+ fake_rap = ARTP_EVASION;
+ fake_plus = item.plus;
+ break;
+
+ case RING_STRENGTH:
+ fake_rap = ARTP_STRENGTH;
+ fake_plus = item.plus;
+ break;
+
+ case RING_INTELLIGENCE:
+ fake_rap = ARTP_INTELLIGENCE;
+ fake_plus = item.plus;
+ break;
+
+ case RING_DEXTERITY:
+ fake_rap = ARTP_DEXTERITY;
+ fake_plus = item.plus;
+ break;
+
+ case RING_LIFE_PROTECTION:
+ fake_rap = ARTP_NEGATIVE_ENERGY;
+ break;
+
+ case RING_PROTECTION_FROM_MAGIC:
+ fake_rap = ARTP_MAGIC;
+ break;
+
+ case RING_FIRE:
+ fake_rap = ARTP_FIRE;
+ fake_rap2 = ARTP_COLD;
+ fake_plus2 = -1;
+ break;
+
+ case RING_ICE:
+ fake_rap = ARTP_COLD;
+ fake_rap2 = ARTP_FIRE;
+ fake_plus2 = -1;
+ break;
+
+ case AMU_INACCURACY:
+ fake_rap = ARTP_ACCURACY;
+ fake_plus = -5;
+ break;
+ }
+
+ if (fake_rap != ARTP_NUM_PROPERTIES && fake_plus != 0)
+ proprt[fake_rap] += fake_plus;
+
+ if (fake_rap2 != ARTP_NUM_PROPERTIES && fake_plus2 != 0)
+ proprt[fake_rap2] += fake_plus2;
+
+ if (item_ident( item, ISFLAG_KNOW_PROPERTIES )
+ || item_ident( item, ISFLAG_KNOW_TYPE ))
+ {
+ if (fake_rap != ARTP_NUM_PROPERTIES && proprt[fake_rap] != 0)
+ known[fake_rap] = true;
+
+ if (fake_rap2 != ARTP_NUM_PROPERTIES && proprt[fake_rap2] != 0)
+ known[fake_rap2] = true;
+ }
+}
+
+inline static void _randart_propset( artefact_properties_t &p,
+ artefact_prop_type pt,
+ int value,
+ bool neg )
+{
+ // This shouldn't be called with 0, else no property gets added after all.
+ ASSERT(value != 0);
+ p[pt] = (neg? -value : value);
+}
+
+static int _randart_add_one_property( const item_def &item,
+ artefact_properties_t &proprt )
+{
+ // This function assumes that no properties have been added to this
+ // randart yet.
+
+ const object_class_type cl = item.base_type;
+ const int ty = item.sub_type;
+
+ // 0 - ac, 1 - ev, 2 - str, 3 - int, 4 - dex
+ int prop;
+ int skip = -1;
+
+ // Determine if we need to skip any of the above.
+ if (cl == OBJ_ARMOUR || cl == OBJ_JEWELLERY && ty == RING_PROTECTION)
+ skip = 0;
+ else if (cl == OBJ_JEWELLERY && ty == RING_EVASION)
+ skip = 1;
+ else if (cl == OBJ_JEWELLERY && ty == RING_STRENGTH)
+ skip = 2;
+ else if (cl == OBJ_JEWELLERY && ty == RING_INTELLIGENCE)
+ skip = 3;
+ else if (cl == OBJ_JEWELLERY && ty == RING_DEXTERITY)
+ skip = 4;
+
+ // Pick a random enchantment, taking into account the skipped index.
+ if (skip >= 0)
+ {
+ prop = random2(4);
+ if (prop >= skip)
+ prop++;
+ }
+ else
+ {
+ prop = random2(5);
+ }
+
+ const bool negench = one_chance_in(4);
+
+ switch (prop)
+ {
+ default:
+ case 0:
+ _randart_propset(proprt, ARTP_AC,
+ 1 + random2(3) + random2(3) + random2(3),
+ negench);
+ break;
+ case 1:
+ _randart_propset(proprt, ARTP_EVASION,
+ 1 + random2(3) + random2(3) + random2(3),
+ negench);
+ break;
+ case 2:
+ _randart_propset(proprt, ARTP_STRENGTH,
+ 1 + random2(3) + random2(3),
+ negench);
+ break;
+ case 3:
+ _randart_propset(proprt, ARTP_INTELLIGENCE,
+ 1 + random2(3) + random2(3),
+ negench);
+ break;
+ case 4:
+ _randart_propset(proprt, ARTP_DEXTERITY,
+ 1 + random2(3) + random2(3),
+ negench);
+ break;
+ }
+
+ return (negench ? -1 : 1);
+}
+
+void static _get_randart_properties(const item_def &item,
+ artefact_properties_t &proprt)
+{
+ const object_class_type aclass = item.base_type;
+ const int atype = item.sub_type;
+ int power_level = 0;
+
+ const long seed = _calc_seed( item );
+ rng_save_excursion exc;
+ seed_rng( seed );
+
+ if (aclass == OBJ_ARMOUR)
+ power_level = item.plus / 2 + 2;
+ else if (aclass == OBJ_JEWELLERY)
+ power_level = 1 + random2(3) + random2(2);
+ else // OBJ_WEAPON
+ power_level = item.plus / 3 + item.plus2 / 3;
+
+ if (power_level < 0)
+ power_level = 0;
+
+ proprt.init(0);
+
+ if (aclass == OBJ_WEAPONS) // only weapons get brands, of course
+ {
+ proprt[ARTP_BRAND] = SPWPN_FLAMING + random2(15); // brand
+
+ if (one_chance_in(6))
+ proprt[ARTP_BRAND] = SPWPN_FLAMING + random2(2);
+
+ if (one_chance_in(6))
+ proprt[ARTP_BRAND] = SPWPN_ORC_SLAYING + random2(5);
+
+ if (proprt[ARTP_BRAND] == SPWPN_DRAGON_SLAYING
+ && weapon_skill(item) != SK_POLEARMS)
+ {
+ proprt[ARTP_BRAND] = SPWPN_NORMAL;
+ }
+
+ if (proprt[ARTP_BRAND] == SPWPN_VENOM
+ && get_vorpal_type(item) == DVORP_CRUSHING)
+ {
+ proprt[ARTP_BRAND] = SPWPN_NORMAL;
+ }
+
+ if (one_chance_in(6))
+ proprt[ARTP_BRAND] = SPWPN_VORPAL;
+
+ if (proprt[ARTP_BRAND] == SPWPN_FLAME
+ || proprt[ARTP_BRAND] == SPWPN_FROST)
+ {
+ proprt[ARTP_BRAND] = SPWPN_NORMAL; // missile wpns
+ }
+
+ if (proprt[ARTP_BRAND] == SPWPN_PROTECTION)
+ proprt[ARTP_BRAND] = SPWPN_NORMAL; // no protection
+
+ // if this happens, things might get broken - bwr
+ if (proprt[ARTP_BRAND] == SPWPN_SPEED && atype == WPN_QUICK_BLADE)
+ proprt[ARTP_BRAND] = SPWPN_NORMAL;
+
+ if (is_range_weapon(item))
+ {
+ proprt[ARTP_BRAND] = SPWPN_NORMAL;
+
+ if (one_chance_in(3))
+ {
+ int tmp = random2(20);
+
+ proprt[ARTP_BRAND] = (tmp >= 18) ? SPWPN_SPEED :
+ (tmp >= 14) ? SPWPN_PROTECTION :
+ (tmp >= 10) ? SPWPN_VENOM
+ : SPWPN_VORPAL + random2(3);
+
+ if (atype == WPN_BLOWGUN
+ && proprt[ARTP_BRAND] != SPWPN_SPEED
+ && proprt[ARTP_BRAND] != SPWPN_PROTECTION)
+ {
+ proprt[ARTP_BRAND] = SPWPN_NORMAL;
+ }
+
+ if (atype == WPN_SLING
+ && proprt[ARTP_BRAND] == SPWPN_VENOM)
+ {
+ proprt[ARTP_BRAND] = SPWPN_NORMAL;
+ }
+ }
+ }
+
+ if (is_demonic(item))
+ {
+ switch (random2(9))
+ {
+ case 0:
+ proprt[ARTP_BRAND] = SPWPN_DRAINING;
+ break;
+ case 1:
+ proprt[ARTP_BRAND] = SPWPN_FLAMING;
+ break;
+ case 2:
+ proprt[ARTP_BRAND] = SPWPN_FREEZING;
+ break;
+ case 3:
+ proprt[ARTP_BRAND] = SPWPN_ELECTROCUTION;
+ break;
+ case 4:
+ proprt[ARTP_BRAND] = SPWPN_VAMPIRICISM;
+ break;
+ case 5:
+ proprt[ARTP_BRAND] = SPWPN_PAIN;
+ break;
+ case 6:
+ proprt[ARTP_BRAND] = SPWPN_VENOM;
+ break;
+ default:
+ power_level -= 2;
+ }
+ power_level += 2;
+ }
+ else if (one_chance_in(3))
+ proprt[ARTP_BRAND] = SPWPN_NORMAL;
+ else
+ power_level++;
+ }
+
+ if (!one_chance_in(5))
+ {
+ // AC mod - not for armours or rings of protection
+ if (one_chance_in(4 + power_level)
+ && aclass != OBJ_ARMOUR
+ && (aclass != OBJ_JEWELLERY || atype != RING_PROTECTION))
+ {
+ proprt[ARTP_AC] = 1 + random2(3) + random2(3) + random2(3);
+ power_level++;
+ if (one_chance_in(4))
+ {
+ proprt[ARTP_AC] -= 1 + random2(3) + random2(3) + random2(3);
+ power_level--;
+ }
+ }
+
+ // ev mod - not for rings of evasion
+ if (one_chance_in(4 + power_level)
+ && (aclass != OBJ_JEWELLERY || atype != RING_EVASION))
+ {
+ proprt[ARTP_EVASION] = 1 + random2(3) + random2(3) + random2(3);
+ power_level++;
+ if (one_chance_in(4))
+ {
+ proprt[ARTP_EVASION] -= 1 + random2(3) + random2(3)
+ + random2(3);
+ power_level--;
+ }
+ }
+
+ // str mod - not for rings of strength
+ if (one_chance_in(4 + power_level)
+ && (aclass != OBJ_JEWELLERY || atype != RING_STRENGTH))
+ {
+ proprt[ARTP_STRENGTH] = 1 + random2(3) + random2(2);
+ power_level++;
+ if (one_chance_in(4))
+ {
+ proprt[ARTP_STRENGTH] -= 1 + random2(3) + random2(3)
+ + random2(3);
+ power_level--;
+ }
+ }
+
+ // int mod - not for rings of intelligence
+ if (one_chance_in(4 + power_level)
+ && (aclass != OBJ_JEWELLERY || atype != RING_INTELLIGENCE))
+ {
+ proprt[ARTP_INTELLIGENCE] = 1 + random2(3) + random2(2);
+ power_level++;
+ if (one_chance_in(4))
+ {
+ proprt[ARTP_INTELLIGENCE] -= 1 + random2(3) + random2(3)
+ + random2(3);
+ power_level--;
+ }
+ }
+
+ // dex mod - not for rings of dexterity
+ if (one_chance_in(4 + power_level)
+ && (aclass != OBJ_JEWELLERY || atype != RING_DEXTERITY))
+ {
+ proprt[ARTP_DEXTERITY] = 1 + random2(3) + random2(2);
+ power_level++;
+ if (one_chance_in(4))
+ {
+ proprt[ARTP_DEXTERITY] -= 1 + random2(3) + random2(3)
+ + random2(3);
+ power_level--;
+ }
+ }
+ }
+
+ if (random2(15) >= power_level && aclass != OBJ_WEAPONS
+ && (aclass != OBJ_JEWELLERY || atype != RING_SLAYING))
+ {
+ // Weapons and rings of slaying can't get these.
+ if (one_chance_in(4 + power_level)) // to-hit
+ {
+ proprt[ARTP_ACCURACY] = 1 + random2(3) + random2(2);
+ power_level++;
+ if (one_chance_in(4))
+ {
+ proprt[ARTP_ACCURACY] -= 1 + random2(3) + random2(3)
+ + random2(3);
+ power_level--;
+ }
+ }
+
+ if (one_chance_in(4 + power_level)) // to-dam
+ {
+ proprt[ARTP_DAMAGE] = 1 + random2(3) + random2(2);
+ power_level++;
+ if (one_chance_in(4))
+ {
+ proprt[ARTP_DAMAGE] -= 1 + random2(3) + random2(3) + random2(3);
+ power_level--;
+ }
+ }
+ }
+
+ // This used to be: bool done_powers = (random2(12 < power_level));
+ // ... which can't be right. random2(boolean) == 0, always.
+ // So it's probably more along the lines of... (jpeg)
+// bool done_powers = (random2(12) < power_level);
+
+ // Try to improve items that still have a low power level.
+ bool done_powers = x_chance_in_y(power_level, 12);
+
+ // res_fire
+ if (!done_powers
+ && one_chance_in(4 + power_level)
+ && (aclass != OBJ_JEWELLERY
+ || (atype != RING_PROTECTION_FROM_FIRE
+ && atype != RING_FIRE
+ && atype != RING_ICE))
+ && (aclass != OBJ_ARMOUR
+ || (atype != ARM_DRAGON_ARMOUR
+ && atype != ARM_ICE_DRAGON_ARMOUR
+ && atype != ARM_GOLD_DRAGON_ARMOUR)))
+ {
+ proprt[ARTP_FIRE] = 1;
+ if (one_chance_in(5))
+ proprt[ARTP_FIRE]++;
+ power_level++;
+ }
+
+ // res_cold
+ if (!done_powers
+ && one_chance_in(4 + power_level)
+ && (aclass != OBJ_JEWELLERY
+ || atype != RING_PROTECTION_FROM_COLD
+ && atype != RING_FIRE
+ && atype != RING_ICE)
+ && (aclass != OBJ_ARMOUR
+ || atype != ARM_DRAGON_ARMOUR
+ && atype != ARM_ICE_DRAGON_ARMOUR
+ && atype != ARM_GOLD_DRAGON_ARMOUR))
+ {
+ proprt[ARTP_COLD] = 1;
+ if (one_chance_in(5))
+ proprt[ARTP_COLD]++;
+ power_level++;
+ }
+
+ if (x_chance_in_y(power_level, 12) || power_level > 7)
+ done_powers = true;
+
+ // res_elec
+ if (!done_powers
+ && one_chance_in(4 + power_level)
+ && (aclass != OBJ_ARMOUR || atype != ARM_STORM_DRAGON_ARMOUR))
+ {
+ proprt[ARTP_ELECTRICITY] = 1;
+ power_level++;
+ }
+
+ // res_poison
+ if (!done_powers
+ && one_chance_in(5 + power_level)
+ && (aclass != OBJ_JEWELLERY || atype != RING_POISON_RESISTANCE)
+ && (aclass != OBJ_ARMOUR
+ || atype != ARM_GOLD_DRAGON_ARMOUR
+ && atype != ARM_SWAMP_DRAGON_ARMOUR
+ && atype != ARM_NAGA_BARDING))
+ {
+ proprt[ARTP_POISON] = 1;
+ power_level++;
+ }
+
+ // prot_life - no necromantic brands on weapons allowed
+ if (!done_powers
+ && one_chance_in(4 + power_level)
+ && (aclass != OBJ_JEWELLERY || atype != RING_LIFE_PROTECTION)
+ && proprt[ARTP_BRAND] != SPWPN_DRAINING
+ && proprt[ARTP_BRAND] != SPWPN_VAMPIRICISM
+ && proprt[ARTP_BRAND] != SPWPN_PAIN)
+ {
+ proprt[ARTP_NEGATIVE_ENERGY] = 1;
+ power_level++;
+ }
+
+ // res magic
+ if (!done_powers
+ && one_chance_in(4 + power_level)
+ && (aclass != OBJ_JEWELLERY || atype != RING_PROTECTION_FROM_MAGIC))
+ {
+ proprt[ARTP_MAGIC] = 35 + random2(65);
+ power_level++;
+ }
+
+ // see_invis
+ if (!done_powers
+ && one_chance_in(4 + power_level)
+ && (aclass != OBJ_JEWELLERY || atype != RING_INVISIBILITY)
+ && (aclass != OBJ_ARMOUR || atype != ARM_NAGA_BARDING))
+ {
+ proprt[ARTP_EYESIGHT] = 1;
+ power_level++;
+ }
+
+ if (x_chance_in_y(power_level, 12) || power_level > 10)
+ done_powers = true;
+
+ // turn invis
+ if (!done_powers
+ && one_chance_in(10)
+ && (aclass != OBJ_JEWELLERY || atype != RING_INVISIBILITY))
+ {
+ proprt[ARTP_INVISIBLE] = 1;
+ power_level++;
+ }
+
+ // levitate
+ if (!done_powers
+ && one_chance_in(10)
+ && (aclass != OBJ_JEWELLERY || atype != RING_LEVITATION))
+ {
+ proprt[ARTP_LEVITATE] = 1;
+ power_level++;
+ }
+
+ // blink
+ if (!done_powers && one_chance_in(10))
+ {
+ proprt[ARTP_BLINK] = 1;
+ power_level++;
+ }
+
+ // teleport
+ if (!done_powers
+ && one_chance_in(10)
+ && (aclass != OBJ_JEWELLERY || atype != RING_TELEPORTATION))
+ {
+ proprt[ARTP_CAN_TELEPORT] = 1;
+ power_level++;
+ }
+
+ // go berserk
+ if (!done_powers
+ && one_chance_in(10)
+ && (aclass != OBJ_WEAPONS || !is_range_weapon(item))
+ && (aclass != OBJ_JEWELLERY || atype != AMU_RAGE))
+ {
+ proprt[ARTP_BERSERK] = 1;
+ power_level++;
+ }
+
+ // sense surroundings
+ if (!done_powers && one_chance_in(10))
+ {
+ proprt[ARTP_MAPPING] = 1;
+ power_level++;
+ }
+
+ // Armours get fewer powers, and are also less likely to be
+ // cursed than weapons
+ if (aclass == OBJ_ARMOUR)
+ power_level -= 4;
+
+ if (power_level >= 2 && x_chance_in_y(power_level, 17))
+ {
+ switch (random2(9))
+ {
+ case 0: // makes noise
+ if (aclass != OBJ_WEAPONS)
+ break;
+ proprt[ARTP_NOISES] = 1 + random2(4);
+ break;
+ case 1: // no magic
+ proprt[ARTP_PREVENT_SPELLCASTING] = 1;
+ break;
+ case 2: // random teleport
+ if (aclass != OBJ_WEAPONS)
+ break;
+ proprt[ARTP_CAUSE_TELEPORTATION] = 5 + random2(15);
+ break;
+ case 3: // no teleport - doesn't affect some instantaneous
+ // teleports
+ if (aclass == OBJ_JEWELLERY && atype == RING_TELEPORTATION)
+ break; // already is a ring of tport
+ if (aclass == OBJ_JEWELLERY && atype == RING_TELEPORT_CONTROL)
+ break; // already is a ring of tport ctrl
+ proprt[ARTP_BLINK] = 0;
+ proprt[ARTP_CAN_TELEPORT] = 0;
+ proprt[ARTP_PREVENT_TELEPORTATION] = 1;
+ break;
+ case 4: // berserk on attack
+ if (aclass != OBJ_WEAPONS || is_range_weapon(item))
+ break;
+ proprt[ARTP_ANGRY] = 1 + random2(8);
+ break;
+ case 5: // susceptible to fire
+ if (aclass == OBJ_JEWELLERY
+ && (atype == RING_PROTECTION_FROM_FIRE || atype == RING_FIRE
+ || atype == RING_ICE))
+ {
+ break; // already does this or something
+ }
+ if (aclass == OBJ_ARMOUR
+ && (atype == ARM_DRAGON_ARMOUR || atype == ARM_ICE_DRAGON_ARMOUR
+ || atype == ARM_GOLD_DRAGON_ARMOUR))
+ {
+ break;
+ }
+ proprt[ARTP_FIRE] = -1;
+ break;
+ case 6: // susceptible to cold
+ if (aclass == OBJ_JEWELLERY
+ && (atype == RING_PROTECTION_FROM_COLD || atype == RING_FIRE
+ || atype == RING_ICE))
+ {
+ break; // already does this or something
+ }
+ if (aclass == OBJ_ARMOUR
+ && (atype == ARM_DRAGON_ARMOUR || atype == ARM_ICE_DRAGON_ARMOUR
+ || atype == ARM_GOLD_DRAGON_ARMOUR))
+ {
+ break;
+ }
+ proprt[ARTP_COLD] = -1;
+ break;
+ case 7: // speed metabolism
+ if (aclass == OBJ_JEWELLERY && atype == RING_HUNGER)
+ break; // already is a ring of hunger
+ if (aclass == OBJ_JEWELLERY && atype == RING_SUSTENANCE)
+ break; // already is a ring of sustenance
+ proprt[ARTP_METABOLISM] = 1 + random2(3);
+ break;
+ case 8:
+ // emits mutagenic radiation - increases
+ // magic_contamination. property is chance (1 in ...) of
+ // increasing magic_contamination
+ proprt[ARTP_MUTAGENIC] = 2 + random2(4);
+ break;
+ }
+ }
+
+ if (one_chance_in(10)
+ && (aclass != OBJ_ARMOUR
+ || atype != ARM_CLOAK
+ || get_equip_race(item) != ISFLAG_ELVEN)
+ && (aclass != OBJ_ARMOUR
+ || atype != ARM_BOOTS
+ || get_equip_race(item) != ISFLAG_ELVEN)
+ && get_armour_ego_type(item) != SPARM_STEALTH)
+ {
+ power_level++;
+ proprt[ARTP_STEALTH] = 10 + random2(70);
+
+ if (one_chance_in(4))
+ {
+ proprt[ARTP_STEALTH] = -proprt[ARTP_STEALTH] - random2(20);
+ power_level--;
+ }
+ }
+
+ if (artefact_wpn_num_props(proprt) == 0)
+ power_level += _randart_add_one_property(item, proprt);
+
+ if ((power_level < 2 && one_chance_in(5)) || one_chance_in(30))
+ {
+ if (one_chance_in(4))
+ proprt[ARTP_CURSED] = 1 + random2(5);
+ else
+ proprt[ARTP_CURSED] = -1;
+ }
+}
+
+static bool _redo_book(item_def &book)
+{
+ int num_spells = 0;
+ int num_unknown = 0;
+
+ for (int i = 0; i < SPELLBOOK_SIZE; i++)
+ {
+ spell_type spell = which_spell_in_book(book, i);
+
+ if (spell == SPELL_NO_SPELL)
+ continue;
+
+ num_spells++;
+ if (!you.seen_spell[spell])
+ num_unknown++;
+ }
+
+ if (num_spells <= 5 && num_unknown == 0)
+ return (true);
+ else if (num_spells > 5 && num_unknown <= 1)
+ return (true);
+
+ return (false);
+}
+
+static bool _init_artefact_book(item_def &book)
+{
+ ASSERT(book.sub_type == BOOK_RANDART_LEVEL
+ || book.sub_type == BOOK_RANDART_THEME);
+ ASSERT(book.plus != 0);
+
+ god_type god;
+ bool redo = (!origin_is_god_gift(book, &god) || god != GOD_XOM);
+
+ // Plus and plus2 contain paramaters to make_book_foo_randart()
+ // which might get changed after the book has been made into a
+ // randart, so reset them on each iteration of the loop.
+ int plus = book.plus;
+ int plus2 = book.plus2;
+ bool book_good;
+ for (int i = 0; i < 4; i++)
+ {
+ book.plus = plus;
+ book.plus2 = plus2;
+
+ if (book.sub_type == BOOK_RANDART_LEVEL)
+ book_good = make_book_level_randart(book);
+ else
+ book_good = make_book_theme_randart(book);
+
+ if (!book_good)
+ continue;
+
+ if (redo && _redo_book(book))
+ continue;
+
+ break;
+ }
+
+ return (book_good);
+}
+
+static bool _init_artefact_properties(item_def &item)
+{
+ ASSERT( is_artefact( item ) );
+ CrawlHashTable &props = item.props;
+ if (!props.exists( ARTEFACT_PROPS_KEY ))
+ props[ARTEFACT_PROPS_KEY].new_vector(SV_SHORT).resize(ART_PROPERTIES);
+
+ CrawlVector &rap = props[ARTEFACT_PROPS_KEY];
+ rap.set_max_size(ART_PROPERTIES);
+
+ for (vec_size i = 0; i < ART_PROPERTIES; i++)
+ rap[i] = (short) 0;
+
+ if (is_unrandom_artefact( item ))
+ {
+ const unrandart_entry *unrand = _seekunrandart( item );
+
+ for (int i = 0; i < ART_PROPERTIES; i++)
+ rap[i] = (short) unrand->prpty[i];
+
+ return (true);
+ }
+
+ if (item.base_type == OBJ_BOOKS)
+ return _init_artefact_book(item);
+
+ artefact_properties_t prop;
+ _get_randart_properties(item, prop);
+
+ for (int i = 0; i < ART_PROPERTIES; i++)
+ {
+ if (i == ARTP_CURSED && prop[i] < 0)
+ {
+ do_curse_item(item);
+ continue;
+ }
+ rap[i] = (short) prop[i];
+ }
+
+ return (true);
+}
+
+void artefact_wpn_properties( const item_def &item,
+ artefact_properties_t &proprt,
+ artefact_known_props_t &known)
+{
+ ASSERT( is_artefact( item ) );
+ ASSERT( item.props.exists( KNOWN_PROPS_KEY ) );
+
+ const CrawlStoreValue &_val = item.props[KNOWN_PROPS_KEY];
+ ASSERT( _val.get_type() == SV_VEC );
+ const CrawlVector &known_vec = _val.get_vector();
+ ASSERT( known_vec.get_type() == SV_BOOL );
+ ASSERT( known_vec.size() == ART_PROPERTIES);
+ ASSERT( known_vec.get_max_size() == ART_PROPERTIES);
+
+ if (item_ident( item, ISFLAG_KNOW_PROPERTIES ))
+ {
+ for (vec_size i = 0; i < ART_PROPERTIES; i++)
+ known[i] = (bool) true;
+ }
+ else
+ {
+ for (vec_size i = 0; i < ART_PROPERTIES; i++)
+ known[i] = known_vec[i];
+ }
+
+ if (item.props.exists( ARTEFACT_PROPS_KEY ))
+ {
+ const CrawlVector &rap_vec = item.props[ARTEFACT_PROPS_KEY].get_vector();
+ ASSERT( rap_vec.get_type() == SV_SHORT );
+ ASSERT( rap_vec.size() == ART_PROPERTIES);
+ ASSERT( rap_vec.get_max_size() == ART_PROPERTIES);
+
+ for (vec_size i = 0; i < ART_PROPERTIES; i++)
+ proprt[i] = rap_vec[i].get_short();
+ }
+ else if (is_unrandom_artefact( item ))
+ {
+ const unrandart_entry *unrand = _seekunrandart( item );
+
+ for (int i = 0; i < ART_PROPERTIES; i++)
+ proprt[i] = (short) unrand->prpty[i];
+ }
+ else
+ {
+ _get_randart_properties(item, proprt);
+ }
+}
+
+
+void artefact_wpn_properties( const item_def &item,
+ artefact_properties_t &proprt )
+{
+ artefact_known_props_t known;
+
+ artefact_wpn_properties(item, proprt, known);
+}
+
+int artefact_wpn_property( const item_def &item, artefact_prop_type prop,
+ bool &_known )
+{
+ artefact_properties_t proprt;
+ artefact_known_props_t known;
+
+ artefact_wpn_properties( item, proprt, known );
+
+ _known = known[prop];
+
+ return ( proprt[prop] );
+}
+
+int artefact_wpn_property( const item_def &item, artefact_prop_type prop )
+{
+ bool known;
+
+ return artefact_wpn_property( item, prop, known );
+}
+
+int artefact_known_wpn_property( const item_def &item,
+ artefact_prop_type prop )
+{
+ artefact_properties_t proprt;
+ artefact_known_props_t known;
+
+ artefact_wpn_properties( item, proprt, known );
+
+ if (known[prop])
+ return ( proprt[prop] );
+ else
+ return (0);
+}
+
+int artefact_wpn_num_props( const item_def &item )
+{
+ artefact_properties_t proprt;
+ artefact_wpn_properties( item, proprt );
+
+ return artefact_wpn_num_props( proprt );
+}
+
+int artefact_wpn_num_props( const artefact_properties_t &proprt )
+{
+ int num = 0;
+
+ for (int i = 0; i < ARTP_NUM_PROPERTIES; i++)
+ if (proprt[i] != 0)
+ num++;
+
+ return num;
+}
+
+void artefact_wpn_learn_prop( item_def &item, artefact_prop_type prop )
+{
+ ASSERT( is_artefact( item ) );
+ ASSERT( item.props.exists( KNOWN_PROPS_KEY ) );
+ CrawlStoreValue &_val = item.props[KNOWN_PROPS_KEY];
+ ASSERT( _val.get_type() == SV_VEC );
+ CrawlVector &known_vec = _val.get_vector();
+ ASSERT( known_vec.get_type() == SV_BOOL );
+ ASSERT( known_vec.size() == ART_PROPERTIES);
+ ASSERT( known_vec.get_max_size() == ART_PROPERTIES);
+
+ if (item_ident( item, ISFLAG_KNOW_PROPERTIES ))
+ return;
+
+ known_vec[prop] = (bool) true;
+ if (Options.autoinscribe_artefacts)
+ add_autoinscription( item, artefact_auto_inscription(item));
+}
+
+bool artefact_wpn_known_prop( const item_def &item, artefact_prop_type prop )
+{
+ bool known;
+ artefact_wpn_property( item, prop, known );
+ return known;
+}
+
+static std::string _get_artefact_type(const item_def &item,
+ bool appear = false)
+{
+ switch (item.base_type)
+ {
+ case OBJ_BOOKS:
+ return "book";
+ case OBJ_WEAPONS:
+ return "weapon";
+ case OBJ_ARMOUR:
+ return "armour";
+ case OBJ_JEWELLERY:
+ // Only in appearance distinguish between amulets and rings.
+ if (!appear)
+ return "jewellery";
+
+ if (jewellery_is_amulet(item))
+ return "amulet";
+ else
+ return "ring";
+ default:
+ return "artefact";
+ }
+}
+
+static bool _pick_db_name( const item_def &item )
+{
+ switch (item.base_type)
+ {
+ case OBJ_WEAPONS:
+ case OBJ_ARMOUR:
+ return coinflip();
+ case OBJ_JEWELLERY:
+ return one_chance_in(5);
+ default:
+ return (false);
+ }
+}
+
+std::string artefact_name(const item_def &item, bool appearance)
+{
+ ASSERT(is_artefact(item));
+
+ ASSERT(item.base_type == OBJ_WEAPONS
+ || item.base_type == OBJ_ARMOUR
+ || item.base_type == OBJ_JEWELLERY
+ || item.base_type == OBJ_BOOKS);
+
+ if (is_unrandom_artefact( item ))
+ {
+ const unrandart_entry *unrand = _seekunrandart( item );
+ return (item_type_known(item) ? unrand->name : unrand->unid_name);
+ }
+
+ const long seed = _calc_seed( item );
+
+ std::string lookup;
+ std::string result;
+
+ // Use prefix of gifting god, if applicable.
+ bool god_gift = false;
+ int item_orig = 0;
+ if (!appearance)
+ {
+ // Divine gifts don't look special, so this is only necessary
+ // for actually naming an item.
+ item_orig = item.orig_monnum;
+ if (item_orig < 0)
+ item_orig = -item_orig;
+ else
+ item_orig = 0;
+
+ if (item_orig > GOD_NO_GOD && item_orig < NUM_GODS)
+ {
+ lookup += god_name(static_cast<god_type>(item_orig), false) + " ";
+ god_gift = true;
+ }
+ }
+
+ // get base type
+ lookup += _get_artefact_type(item, appearance);
+
+ rng_save_excursion rng_state;
+ seed_rng( seed );
+
+ if (appearance)
+ {
+ std::string appear = getRandNameString(lookup, " appearance");
+ if (appear.empty())
+ {
+ appear = getRandNameString("general appearance");
+ if (appear.empty()) // still nothing found?
+ appear = "non-descript";
+ }
+
+ result += appear;
+ result += " ";
+ result += item_base_name(item);
+ return (result);
+ }
+
+ if (_pick_db_name(item))
+ {
+ result += item_base_name(item) + " ";
+
+ int tries = 100;
+ std::string name;
+ do
+ {
+ name = getRandNameString(lookup);
+
+ if (name.empty() && god_gift)
+ {
+ // If nothing found, try god name alone.
+ name = getRandNameString(
+ god_name(static_cast<god_type>(item_orig), false));
+
+ if (name.empty())
+ {
+ // If still nothing found, try base type alone.
+ name = getRandNameString(
+ _get_artefact_type(item).c_str());
+ }
+ }
+
+ name = _replace_name_parts(name, item);
+ }
+ while (--tries > 0 && name.length() > 25);
+
+ if (name.empty()) // still nothing found?
+ result += "of Bugginess";
+ else
+ result += name;
+ }
+ else
+ {
+ // construct a unique name
+ const std::string st_p = make_name(random_int(), false);
+ result += item_base_name(item);
+
+ if (one_chance_in(3))
+ {
+ result += " of ";
+ result += st_p;
+ }
+ else
+ {
+ result += " \"";
+ result += st_p;
+ result += "\"";
+ }
+ }
+
+ return result;
+}
+
+std::string get_artefact_name( const item_def &item )
+{
+ ASSERT( is_artefact( item ) );
+
+ if (item_type_known(item))
+ {
+ // print artefact's real name
+ if (item.props.exists(ARTEFACT_NAME_KEY))
+ return item.props[ARTEFACT_NAME_KEY].get_string();
+ return artefact_name(item, false);
+ }
+ // print artefact appearance
+ if (item.props.exists(ARTEFACT_APPEAR_KEY))
+ return item.props[ARTEFACT_APPEAR_KEY].get_string();
+ return artefact_name(item, false);
+}
+
+void set_artefact_name( item_def &item, const std::string &name )
+{
+ ASSERT( is_artefact( item ));
+ ASSERT( !name.empty() );
+ item.props[ARTEFACT_NAME_KEY].get_string() = name;
+}
+
+void set_artefact_appearance( item_def &item, const std::string &appear )
+{
+ ASSERT( is_artefact( item ));
+ ASSERT( !appear.empty() );
+ item.props[ARTEFACT_APPEAR_KEY].get_string() = appear;
+}
+
+int find_unrandart_index(const item_def& artefact)
+{
+ return (artefact.special);
+}
+
+unrandart_entry* get_unrand_entry(int unrand_index)
+{
+ unrand_index -= UNRAND_START;
+
+ if (unrand_index <= -1 || unrand_index >= NO_UNRANDARTS)
+ return &unranddata[0]; // dummy unrandart
+ else
+ return &unranddata[unrand_index];
+}
+
+static unrandart_entry *_seekunrandart( const item_def &item )
+{
+ return get_unrand_entry(item.special);
+}
+
+int find_okay_unrandart(unsigned char aclass, unsigned char atype,
+ unrand_special_type specialness, bool in_abyss)
+{
+ int ret = -1;
+
+ // Pick randomly among not-yet-existing unrandarts with the proper
+ // base_type and sub_type.
+ for (int i = 0, count = 0; i < NO_UNRANDARTS; i++)
+ {
+ const int index = i + UNRAND_START;
+ const unrandart_entry* entry = &unranddata[i];
+
+ // Skip dummy entries.
+ if (entry->base_type == OBJ_UNASSIGNED)
+ continue;
+
+ const unique_item_status_type status =
+ get_unique_item_status(index);
+
+ if (in_abyss && status != UNIQ_LOST_IN_ABYSS
+ || !in_abyss && status != UNIQ_NOT_EXISTS)
+ {
+ continue;
+ }
+
+ // Never randomly generated until lost in the abyss.
+ if ((!in_abyss || status != UNIQ_LOST_IN_ABYSS)
+ && index >= SPWPN_START_NOGEN_FIXEDARTS
+ && index <= SPWPN_END_FIXEDARTS)
+ {
+ continue;
+ }
+
+ if (entry->base_type != aclass
+ || (atype != OBJ_RANDOM && entry->sub_type != atype))
+ {
+ continue;
+ }
+
+ if (specialness != UNRANDSPEC_EITHER &&
+ specialness != get_unrand_specialness(index))
+ {
+ continue;
+ }
+
+ count++;
+
+ if (one_chance_in(count))
+ ret = index;
+ }
+
+ return (ret);
+}
+
+unrand_special_type get_unrand_specialness(int unrand_index)
+{
+ if (unrand_index >= UNRAND_SINGING_SWORD
+ && unrand_index <= UNRAND_ASMODEUS)
+ {
+ return (UNRANDPSEC_SPECIAL);
+ }
+ return (UNRANDSPEC_NORMAL);
+}
+
+unrand_special_type get_unrand_specialness(const item_def &item)
+{
+ return get_unrand_specialness(item.special);
+}
+
+int get_unrandart_num( const char *name )
+{
+ std::string quoted = "\"";
+ quoted += name;
+ quoted += "\"";
+
+ for (unsigned int i = 0; i < ARRAYSZ(unranddata); ++i)
+ {
+ std::string art = unranddata[i].name;
+ art = replace_all(art, " ", "_");
+ art = replace_all(art, "'", "");
+ lowercase(art);
+ if (art == name || art.find(quoted) != std::string::npos)
+ return (UNRAND_START + i);
+ }
+ return SPWPN_NORMAL;
+}
+
+static bool _randart_is_redundant( const item_def &item,
+ artefact_properties_t &proprt )
+{
+ if (item.base_type != OBJ_JEWELLERY)
+ return (false);
+
+ artefact_prop_type provides = ARTP_NUM_PROPERTIES;
+ artefact_prop_type provides2 = ARTP_NUM_PROPERTIES;
+
+ switch (item.sub_type)
+ {
+ case RING_PROTECTION:
+ provides = ARTP_AC;
+ break;
+
+ case RING_FIRE:
+ case RING_PROTECTION_FROM_FIRE:
+ provides = ARTP_FIRE;
+ break;
+
+ case RING_POISON_RESISTANCE:
+ provides = ARTP_POISON;
+ break;
+
+ case RING_ICE:
+ case RING_PROTECTION_FROM_COLD:
+ provides = ARTP_COLD;
+ break;
+
+ case RING_STRENGTH:
+ provides = ARTP_STRENGTH;
+ break;
+
+ case RING_SLAYING:
+ provides = ARTP_DAMAGE;
+ provides2 = ARTP_ACCURACY;
+ break;
+
+ case RING_SEE_INVISIBLE:
+ provides = ARTP_EYESIGHT;
+ break;
+
+ case RING_INVISIBILITY:
+ provides = ARTP_INVISIBLE;
+ break;
+
+ case RING_HUNGER:
+ provides = ARTP_METABOLISM;
+ break;
+
+ case RING_TELEPORTATION:
+ provides = ARTP_CAN_TELEPORT;
+ provides2 = ARTP_CAUSE_TELEPORTATION;
+ break;
+
+ case RING_EVASION:
+ provides = ARTP_EVASION;
+ break;
+
+ case RING_DEXTERITY:
+ provides = ARTP_DEXTERITY;
+ break;
+
+ case RING_INTELLIGENCE:
+ provides = ARTP_INTELLIGENCE;
+ break;
+
+ case RING_MAGICAL_POWER:
+ provides = ARTP_MAGICAL_POWER;
+ break;
+
+ case RING_LEVITATION:
+ provides = ARTP_LEVITATE;
+ break;
+
+ case RING_LIFE_PROTECTION:
+ provides = ARTP_AC;
+ break;
+
+ case RING_PROTECTION_FROM_MAGIC:
+ provides = ARTP_MAGIC;
+ break;
+
+ case AMU_RAGE:
+ provides = ARTP_BERSERK;
+ break;
+
+ case AMU_INACCURACY:
+ provides = ARTP_ACCURACY;
+ break;
+ }
+
+ if (provides == ARTP_NUM_PROPERTIES)
+ return (false);
+
+ if (proprt[provides] != 0)
+ return (true);
+
+ if (provides2 == ARTP_NUM_PROPERTIES)
+ return (false);
+
+ if (proprt[provides2] != 0)
+ return (true);
+
+ return (false);
+}
+
+static bool _randart_is_conflicting( const item_def &item,
+ artefact_properties_t &proprt )
+{
+ if (item.base_type != OBJ_JEWELLERY)
+ return (false);
+
+ artefact_prop_type conflicts = ARTP_NUM_PROPERTIES;
+
+ switch (item.sub_type)
+ {
+ case RING_SUSTENANCE:
+ conflicts = ARTP_METABOLISM;
+ break;
+
+ case RING_FIRE:
+ case RING_ICE:
+ case RING_WIZARDRY:
+ case RING_MAGICAL_POWER:
+ conflicts = ARTP_PREVENT_SPELLCASTING;
+ break;
+
+ case RING_TELEPORTATION:
+ case RING_TELEPORT_CONTROL:
+ conflicts = ARTP_PREVENT_TELEPORTATION;
+ break;
+
+ case AMU_RESIST_MUTATION:
+ conflicts = ARTP_MUTAGENIC;
+ break;
+
+ case AMU_RAGE:
+ conflicts = ARTP_STEALTH;
+ break;
+ }
+
+ if (conflicts == ARTP_NUM_PROPERTIES)
+ return (false);
+
+ if (proprt[conflicts] != 0)
+ return (true);
+
+ return (false);
+}
+
+bool randart_is_bad( const item_def &item, artefact_properties_t &proprt )
+{
+ if (item.base_type == OBJ_BOOKS)
+ return (false);
+
+ if (artefact_wpn_num_props( proprt ) == 0)
+ return (true);
+
+ return (_randart_is_redundant( item, proprt )
+ || _randart_is_conflicting( item, proprt ));
+}
+
+bool randart_is_bad( const item_def &item )
+{
+ artefact_properties_t proprt;
+ artefact_wpn_properties( item, proprt );
+
+ return randart_is_bad( item, proprt);
+}
+
+bool make_item_blessed_blade( item_def &item )
+{
+ if (item.base_type != OBJ_WEAPONS)
+ return (false);
+
+ // already is an artefact
+ if (is_artefact(item))
+ return (false);
+
+ // mark as a random artefact
+ item.flags |= ISFLAG_RANDART;
+
+ ASSERT(!item.props.exists( KNOWN_PROPS_KEY ));
+ item.props[KNOWN_PROPS_KEY].new_vector(SV_BOOL).resize(ART_PROPERTIES);
+ CrawlVector &known = item.props[KNOWN_PROPS_KEY];
+ known.set_max_size(ART_PROPERTIES);
+ for (vec_size i = 0; i < ART_PROPERTIES; i++)
+ known[i] = (bool) false;
+
+ ASSERT(!item.props.exists( ARTEFACT_PROPS_KEY ));
+ item.props[ARTEFACT_PROPS_KEY].new_vector(SV_SHORT).resize(ART_PROPERTIES);
+ CrawlVector &rap = item.props[ARTEFACT_PROPS_KEY];
+ rap.set_max_size(ART_PROPERTIES);
+ for (vec_size i = 0; i < ART_PROPERTIES; i++)
+ rap[i] = (short) 0;
+
+ // blessed blade of the Shining One
+ rap[ARTP_BRAND] = (short) SPWPN_HOLY_WRATH;
+
+ // set artefact name
+ ASSERT(!item.props.exists( ARTEFACT_NAME_KEY ));
+ item.props[ARTEFACT_NAME_KEY].get_string() = "Blessed Blade";
+
+ // set artefact appearance
+ ASSERT(!item.props.exists( ARTEFACT_APPEAR_KEY ));
+ item.props[ARTEFACT_APPEAR_KEY].get_string() = "brightly glowing blade";
+
+ // in case this is ever needed anywhere
+ item.special = (random_int() & RANDART_SEED_MASK);
+
+ return (true);
+}
+
+bool make_item_randart( item_def &item )
+{
+ if (item.base_type != OBJ_WEAPONS
+ && item.base_type != OBJ_ARMOUR
+ && item.base_type != OBJ_JEWELLERY
+ && item.base_type != OBJ_BOOKS)
+ {
+ return (false);
+ }
+
+ if (item.base_type == OBJ_BOOKS)
+ {
+ if (item.sub_type != BOOK_RANDART_LEVEL
+ && item.sub_type != BOOK_RANDART_THEME)
+ {
+ return (false);
+ }
+ }
+
+ // This item already is a randart.
+ if (item.flags & ISFLAG_RANDART)
+ return (true);
+
+ // Not a truly random artefact.
+ if (item.flags & ISFLAG_UNRANDART)
+ return (false);
+
+ if (item_is_mundane(item))
+ return (false);
+
+ ASSERT(!item.props.exists( KNOWN_PROPS_KEY ));
+ ASSERT(!item.props.exists( ARTEFACT_NAME_KEY ));
+ ASSERT(!item.props.exists( ARTEFACT_APPEAR_KEY ));
+ item.props[KNOWN_PROPS_KEY].new_vector(SV_BOOL).resize(ART_PROPERTIES);
+ CrawlVector &known = item.props[KNOWN_PROPS_KEY];
+ known.set_max_size(ART_PROPERTIES);
+ for (vec_size i = 0; i < ART_PROPERTIES; i++)
+ known[i] = (bool) false;
+
+ item.flags |= ISFLAG_RANDART;
+
+ god_type god_gift;
+ (void) origin_is_god_gift(item, &god_gift);
+
+ do
+ {
+ item.special = (random_int() & RANDART_SEED_MASK);
+ // Now that we found something, initialize the props array.
+ if (!_init_artefact_properties(item))
+ {
+ // Something went wrong that no amount of changing
+ // item.special will fix.
+ item.special = 0;
+ item.props.erase(ARTEFACT_PROPS_KEY);
+ item.props.erase(KNOWN_PROPS_KEY);
+ item.flags &= ~ISFLAG_RANDART;
+ return (false);
+ }
+ }
+ while (randart_is_bad(item)
+ || god_gift != GOD_NO_GOD && !_god_fits_artefact(god_gift, item));
+
+ // get true artefact name
+ if (item.props.exists( ARTEFACT_NAME_KEY ))
+ ASSERT(item.props[ARTEFACT_NAME_KEY].get_type() == SV_STR);
+ else
+ item.props[ARTEFACT_NAME_KEY].get_string() = artefact_name(item, false);
+
+ // get artefact appearance
+ if (item.props.exists( ARTEFACT_APPEAR_KEY ))
+ ASSERT(item.props[ARTEFACT_APPEAR_KEY].get_type() == SV_STR);
+ else
+ item.props[ARTEFACT_APPEAR_KEY].get_string() = artefact_name(item, true);
+
+ return (true);
+}
+
+bool make_item_unrandart( item_def &item, int unrand_index )
+{
+ ASSERT(unrand_index > UNRAND_START);
+ ASSERT(unrand_index < (UNRAND_START + NO_UNRANDARTS));
+
+ if (!item.props.exists( KNOWN_PROPS_KEY ))
+ {
+ item.props[KNOWN_PROPS_KEY].new_vector(SV_BOOL).resize(ART_PROPERTIES);
+ CrawlVector &known = item.props[KNOWN_PROPS_KEY];
+ known.set_max_size(ART_PROPERTIES);
+ for (vec_size i = 0; i < ART_PROPERTIES; i++)
+ known[i] = (bool) false;
+ }
+
+ const unrandart_entry *unrand = &unranddata[unrand_index - UNRAND_START];
+ item.base_type = unrand->base_type;
+ item.sub_type = unrand->sub_type;
+ item.plus = unrand->plus;
+ item.plus2 = unrand->plus2;
+ item.colour = unrand->colour;
+
+ item.flags |= ISFLAG_UNRANDART;
+ _init_artefact_properties(item);
+
+ item.special = unrand_index;
+ if (unrand->prpty[ARTP_BRAND] != 0)
+ do_curse_item( item );
+
+ // get true artefact name
+ ASSERT(!item.props.exists( ARTEFACT_NAME_KEY ));
+ item.props[ARTEFACT_NAME_KEY].get_string() = unrand->name;
+
+ // get artefact appearance
+ ASSERT(!item.props.exists( ARTEFACT_APPEAR_KEY ));
+ item.props[ARTEFACT_APPEAR_KEY].get_string() = unrand->unid_name;
+
+ set_unique_item_status(unrand_index, UNIQ_EXISTS);
+
+ return (true);
+}
+
+const char *unrandart_descrip( int which_descrip, const item_def &item )
+{
+ // Eventually it would be great to have randomly generated descriptions
+ // for randarts.
+ const unrandart_entry *unrand = _seekunrandart( item );
+
+ return ((which_descrip == 0) ? unrand->desc :
+ (which_descrip == 1) ? unrand->desc_id :
+ (which_descrip == 2) ? unrand->desc_end
+ : "Unknown.");
+}
+
+void artefact_set_properties( item_def &item,
+ artefact_properties_t &proprt )
+{
+ ASSERT( is_random_artefact( item ) );
+ ASSERT( item.props.exists( ARTEFACT_PROPS_KEY ) );
+
+ CrawlVector &rap_vec = item.props[ARTEFACT_PROPS_KEY].get_vector();
+ ASSERT( rap_vec.get_type() == SV_SHORT );
+ ASSERT( rap_vec.size() == ART_PROPERTIES);
+ ASSERT( rap_vec.get_max_size() == ART_PROPERTIES);
+
+ for (vec_size i = 0; i < ART_PROPERTIES; i++)
+ rap_vec[i].get_short() = proprt[i];
+}
+
+void artefact_set_property( item_def &item,
+ artefact_prop_type prop,
+ int val )
+{
+ ASSERT( is_random_artefact( item ) );
+ ASSERT( item.props.exists( ARTEFACT_PROPS_KEY ) );
+
+ CrawlVector &rap_vec = item.props[ARTEFACT_PROPS_KEY].get_vector();
+ ASSERT( rap_vec.get_type() == SV_SHORT );
+ ASSERT( rap_vec.size() == ART_PROPERTIES);
+ ASSERT( rap_vec.get_max_size() == ART_PROPERTIES);
+
+ rap_vec[prop].get_short() = val;
+}