From 20a6609453ee2b51c388c296516c1abc1beab1d2 Mon Sep 17 00:00:00 2001 From: dshaligram Date: Mon, 28 May 2007 08:47:30 +0000 Subject: Preliminary integration of Zooko's Xom patch (untested). git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@1489 c06c8d41-db1a-0410-9941-cceddc491573 --- crawl-ref/source/abl-show.cc | 2 +- crawl-ref/source/acr.cc | 13 +- crawl-ref/source/beam.cc | 6 +- crawl-ref/source/chardump.cc | 7 +- crawl-ref/source/debug.cc | 8 +- crawl-ref/source/decks.cc | 5 +- crawl-ref/source/defines.h | 4 + crawl-ref/source/delay.cc | 5 +- crawl-ref/source/describe.cc | 60 +-- crawl-ref/source/describe.h | 2 +- crawl-ref/source/dungeon.cc | 18 +- crawl-ref/source/effects.cc | 16 +- crawl-ref/source/enum.h | 12 +- crawl-ref/source/externs.h | 8 +- crawl-ref/source/fight.cc | 6 + crawl-ref/source/files.cc | 4 +- crawl-ref/source/files.h | 2 +- crawl-ref/source/food.cc | 11 +- crawl-ref/source/hiscores.cc | 10 +- crawl-ref/source/hiscores.h | 2 +- crawl-ref/source/it_use2.cc | 9 + crawl-ref/source/it_use3.cc | 8 +- crawl-ref/source/item_use.cc | 61 ++- crawl-ref/source/itemprop.cc | 5 + crawl-ref/source/itemprop.h | 3 +- crawl-ref/source/items.cc | 7 +- crawl-ref/source/libdos.cc | 4 + crawl-ref/source/libw32c.cc | 4 + crawl-ref/source/makefile.obj | 1 + crawl-ref/source/makeitem.cc | 164 +++++--- crawl-ref/source/makeitem.h | 5 + crawl-ref/source/message.cc | 4 +- crawl-ref/source/misc.cc | 200 ++++++---- crawl-ref/source/misc.h | 2 + crawl-ref/source/mon-util.cc | 22 +- crawl-ref/source/monstuff.cc | 59 +-- crawl-ref/source/monstuff.h | 14 +- crawl-ref/source/mutation.cc | 178 +++++---- crawl-ref/source/mutation.h | 9 +- crawl-ref/source/newgame.cc | 14 +- crawl-ref/source/notes.cc | 15 +- crawl-ref/source/ouch.cc | 91 ++++- crawl-ref/source/player.cc | 32 +- crawl-ref/source/player.h | 6 +- crawl-ref/source/religion.cc | 531 +++++--------------------- crawl-ref/source/religion.h | 27 +- crawl-ref/source/spells3.cc | 19 +- crawl-ref/source/spells3.h | 2 +- crawl-ref/source/spl-cast.cc | 10 +- crawl-ref/source/xom.cc | 844 ++++++++++++++++++++++++++++++++++++++++++ 50 files changed, 1704 insertions(+), 847 deletions(-) create mode 100644 crawl-ref/source/xom.cc (limited to 'crawl-ref') diff --git a/crawl-ref/source/abl-show.cc b/crawl-ref/source/abl-show.cc index 116e8336a6..d8f50a7997 100644 --- a/crawl-ref/source/abl-show.cc +++ b/crawl-ref/source/abl-show.cc @@ -949,7 +949,7 @@ static bool do_ability(const ability_def& abil) case ABIL_EVOKE_TELEPORTATION: // ring of teleportation case ABIL_TELEPORTATION: // teleport mut if (you.mutation[MUT_TELEPORT_AT_WILL] == 3) - you_teleport2( true, true ); // instant and to new area of Abyss + you_teleport_now( true, true ); // instant and to new area of Abyss else you_teleport(); diff --git a/crawl-ref/source/acr.cc b/crawl-ref/source/acr.cc index ea93668845..dfeaefb35c 100644 --- a/crawl-ref/source/acr.cc +++ b/crawl-ref/source/acr.cc @@ -659,7 +659,7 @@ static void handle_wizard_command( void ) break; case 'X': - Xom_acts(true, 20, true); + xom_acts(abs(you.piety - 100)); break; case 'z': @@ -1811,7 +1811,7 @@ static void decrement_durations() else if (you.duration[DUR_TELEPORT] == 1) { // only to a new area of the abyss sometimes (for abyss teleports) - you_teleport2( true, one_chance_in(5) ); + you_teleport_now( true, one_chance_in(5) ); you.duration[DUR_TELEPORT] = 0; } @@ -2200,9 +2200,9 @@ static void world_reacts() { // this is instantaneous if (player_teleport() > 0 && one_chance_in(100 / player_teleport())) - you_teleport2( true ); + you_teleport_now( true ); else if (you.level_type == LEVEL_ABYSS && one_chance_in(30)) - you_teleport2( false, true ); // to new area of the Abyss + you_teleport_now( false, true ); // to new area of the Abyss } if (env.cgrid[you.x_pos][you.y_pos] != EMPTY_CLOUD) @@ -3053,9 +3053,8 @@ static void move_player(int move_x, int move_y) { struct monsters *mon = &menv[targ_monst]; - // you can swap places with a friendly monster if you - // can see it and you're not confused - if (mons_friendly( mon ) && player_monster_visible( mon ) && !you.conf) + // you can swap places with a friendly monster if you're not confused + if (mons_friendly( mon ) && !you.conf) { if (swap_places( mon )) swap = true; diff --git a/crawl-ref/source/beam.cc b/crawl-ref/source/beam.cc index 476f566893..ef80105aab 100644 --- a/crawl-ref/source/beam.cc +++ b/crawl-ref/source/beam.cc @@ -2090,7 +2090,7 @@ void poison_monster( monsters *monster, if (new_pois.degree > old_pois.degree) { simple_monster_message( monster, - !old_pois.degree? " looks ill." + !old_pois.degree? " is poisoned." : " looks even sicker." ); } @@ -3711,7 +3711,7 @@ static int affect_monster_enchantment(struct bolt &beam, struct monsters *mon) if (check_mons_resist_magic( mon, beam.ench_power )) return mons_immune_magic(mon) ? MON_UNAFFECTED : MON_RESIST; - if (monster_polymorph(mon, RANDOM_MONSTER, 100)) + if (monster_polymorph(mon, RANDOM_MONSTER)) beam.obvious_effect = true; return (MON_AFFECTED); @@ -3744,7 +3744,7 @@ static int affect_monster_enchantment(struct bolt &beam, struct monsters *mon) if (check_mons_resist_magic( mon, beam.ench_power )) return mons_immune_magic(mon) ? MON_UNAFFECTED : MON_RESIST; - if (monster_polymorph(mon, MONS_PULSATING_LUMP, 100)) + if (monster_polymorph(mon, MONS_PULSATING_LUMP)) beam.obvious_effect = true; return (MON_AFFECTED); diff --git a/crawl-ref/source/chardump.cc b/crawl-ref/source/chardump.cc index 9f807ede2b..d9ea019a87 100644 --- a/crawl-ref/source/chardump.cc +++ b/crawl-ref/source/chardump.cc @@ -542,11 +542,8 @@ static void sdump_religion(const std::string &, std::string & text) if (!player_under_penance()) { - if (you.religion != GOD_XOM) // Xom doesn't care - { - text += god_prayer_reaction(); - text += "\n"; - } + text += god_prayer_reaction(); + text += "\n"; } else { diff --git a/crawl-ref/source/debug.cc b/crawl-ref/source/debug.cc index 87dd2c335d..a24e66a01a 100644 --- a/crawl-ref/source/debug.cc +++ b/crawl-ref/source/debug.cc @@ -1386,22 +1386,22 @@ void debug_get_religion(void) if (specs[0] == '\0') return; - int god = -1; + god_type god = GOD_NO_GOD; for (int i = 1; i < NUM_GODS; i++) { char name[80]; - strncpy( name, god_name(i), sizeof( name ) ); + strncpy( name, god_name(static_cast(i)), sizeof( name ) ); char *ptr = strstr( strlwr(name), strlwr(specs) ); if (ptr != NULL) { - god = i; + god = static_cast(i); break; } } - if (god == -1) + if (god == GOD_NO_GOD) mpr( "That god doesn't seem to be taking followers today." ); else { diff --git a/crawl-ref/source/decks.cc b/crawl-ref/source/decks.cc index 3e995593ae..1015ae6594 100644 --- a/crawl-ref/source/decks.cc +++ b/crawl-ref/source/decks.cc @@ -144,7 +144,6 @@ static card_type deck_of_punishment[] = CARD_PANDEMONIUM }; -#define ARRAYSIZE(x) (sizeof(x) / sizeof(x[0])) #define DECK_WONDERS_SIZE ARRAYSIZE(deck_of_wonders) #define DECK_SUMMONING_SIZE ARRAYSIZE(deck_of_summoning) #define DECK_TRICKS_SIZE ARRAYSIZE(deck_of_tricks) @@ -889,7 +888,7 @@ void card_effect(card_type which_card) case CARD_TELEPORT_NOW: mpr( "You have drawn the Portal of Instantaneous Transposition." ); - you_teleport2( true, true ); // in abyss, always to new area + you_teleport_now( true, true ); // in abyss, always to new area break; case CARD_RAGE: @@ -913,7 +912,7 @@ void card_effect(card_type which_card) case CARD_XOM: mpr("You have drawn the card of Xom!"); - Xom_acts( true, 5 + random2( you.skills[SK_EVOCATIONS] ), true ); + xom_acts( true, 5 + random2( you.skills[SK_EVOCATIONS] )); break; case CARD_SLOW: diff --git a/crawl-ref/source/defines.h b/crawl-ref/source/defines.h index c104ae7358..00bae84207 100644 --- a/crawl-ref/source/defines.h +++ b/crawl-ref/source/defines.h @@ -301,4 +301,8 @@ // it wants to be used in case labels. #define CONTROL( xxx ) ((xxx) - 'A' + 1) +#define ARRAYSIZE(x) (sizeof(x) / sizeof(x[0])) + +#define MIN(x, y) MINIMUM(x, y) + #endif diff --git a/crawl-ref/source/delay.cc b/crawl-ref/source/delay.cc index 45ccbcd05f..bf68aec5c8 100644 --- a/crawl-ref/source/delay.cc +++ b/crawl-ref/source/delay.cc @@ -35,6 +35,7 @@ #include "output.h" #include "player.h" #include "randart.h" +#include "religion.h" #include "spl-util.h" #include "stuff.h" #include "travel.h" @@ -741,9 +742,11 @@ static void armour_wear_effects(const int item_slot) if (is_random_artefact( arm )) use_randart( item_slot ); - if (item_cursed( arm )) { + if (item_cursed( arm )) + { mpr( "Oops, that feels deathly cold." ); learned_something_new(TUT_YOU_CURSED); + xom_is_stimulated(128); } if (eq_slot == EQ_SHIELD) diff --git a/crawl-ref/source/describe.cc b/crawl-ref/source/describe.cc index 2d324c5853..e03fb32164 100644 --- a/crawl-ref/source/describe.cc +++ b/crawl-ref/source/describe.cc @@ -4940,18 +4940,43 @@ static bool print_god_abil_desc( int god, int numpower ) return true; } +static std::string describe_favour_generic(god_type which_god) +{ + std::string godname = god_name(which_god); + return (you.piety > 130) ? "A prized avatar of " + godname + ".": + (you.piety > 100) ? "A shining star in the eyes of " + godname + "." : + (you.piety > 70) ? "A rising star in the eyes of " + godname + "." : + (you.piety > 40) ? godname + " is most pleased with you." : + (you.piety > 20) ? godname + " has noted your presence." : + (you.piety > 5) ? godname + " is noncommittal." + : "You are beneath notice."; +} + //--------------------------------------------------------------- // // describe_god // -// Describes all gods. Accessible through altars (by praying), or -// by the ^ key if player is a worshipper. +// Describes the player's standing with his deity. // //--------------------------------------------------------------- -void describe_god( int which_god, bool give_title ) +std::string describe_favour(god_type which_god) { + if (player_under_penance()) + { + const int penance = you.penance[which_god]; + return (penance >= 50) ? "Godly wrath is upon you!" : + (penance >= 20) ? "You've transgressed heavily! Be penitent!" : + (penance >= 5 ) ? "You are under penance." + : "You should show more discipline."; + } + return (which_god == GOD_XOM)? + describe_xom_favour() : describe_favour_generic(which_god); +} + +void describe_god( god_type which_god, bool give_title ) +{ const char *description; // mv: tmp string used for printing description int colour; // mv: colour used for some messages @@ -5146,8 +5171,7 @@ void describe_god( int which_god, bool give_title ) break; case GOD_XOM: - cprintf( (you.experience_level >= 20) ? "Xom's favourite toy" - : "Toy" ); + cprintf("Toy"); break; default: @@ -5181,31 +5205,7 @@ void describe_god( int which_god, bool give_title ) } else { - if (player_under_penance()) //mv: penance check - { - cprintf( (you.penance[which_god] >= 50) ? "Godly wrath is upon you!" : - (you.penance[which_god] >= 20) ? "You've transgressed heavily! Be penitent!" : - (you.penance[which_god] >= 5 ) ? "You are under penance." - : "You should show more discipline." ); - - } - else - { - if (which_god == GOD_XOM) - cprintf("You are ignored."); - else - { - cprintf( (you.piety > 130) ? "A prized avatar of %s.": - (you.piety > 100) ? "A shining star in the eyes of %s." : - (you.piety > 70) ? "A rising star in the eyes of %s." : - (you.piety > 40) ? "%s is most pleased with you." : - (you.piety > 20) ? "%s has noted your presence." : - (you.piety > 5) ? "%s is noncommittal." - : "You are beneath %s's notice.", - god_name(which_god)); - } - } - //end of favour + cprintf(describe_favour(which_god).c_str()); //mv: following code shows abilities given from god (if any) textcolor(LIGHTGRAY); diff --git a/crawl-ref/source/describe.h b/crawl-ref/source/describe.h index e3ba32baf4..9c032f8e7e 100644 --- a/crawl-ref/source/describe.h +++ b/crawl-ref/source/describe.h @@ -36,7 +36,7 @@ std::string get_item_description( const item_def &item, bool verbose, /* *********************************************************************** * called from: acr - religion * *********************************************************************** */ -void describe_god( int which_god, bool give_title ); +void describe_god( god_type which_god, bool give_title ); void describe_feature_wide(int x, int y); diff --git a/crawl-ref/source/dungeon.cc b/crawl-ref/source/dungeon.cc index 99b621df93..c5538fcb7a 100644 --- a/crawl-ref/source/dungeon.cc +++ b/crawl-ref/source/dungeon.cc @@ -2439,7 +2439,7 @@ static void special_room(int level_number, spec_room &sr) : OBJ_POTIONS); // 1 in 11 thing_created = items( 1, obj_type, OBJ_RANDOM, true, - level_number * 3, 250 ); + level_number * 3, MAKE_ITEM_RANDOM_RACE); if (thing_created != NON_ITEM) { @@ -3458,9 +3458,9 @@ static int vault_grid( vault_placement &place, || vgrid == 'Z') ? MAKE_GOOD_ITEM : (vgrid == '*') ? 5 + (level_number * 2) : level_number); - + item_made = items( 1, which_class, which_type, true, - which_depth, spec ); + which_depth, spec ); if (item_made != NON_ITEM) { @@ -3946,16 +3946,14 @@ void place_spec_shop( int level_number, item_level = level_number + random2((level_number + 1) * 3); } - if (one_chance_in(4)) - item_level = MAKE_GOOD_ITEM; - // don't generate gold in shops! This used to be possible with // General Stores (see item_in_shop() below) (GDL) - while(true) + while (true) { const int subtype = representative? j : OBJ_RANDOM; orb = items( 1, item_in_shop(env.shop[i].type), subtype, true, - item_level, 250 ); + one_chance_in(4)? MAKE_GOOD_ITEM : item_level, + MAKE_ITEM_RANDOM_RACE ); if (orb != NON_ITEM && mitm[orb].base_type != OBJ_GOLD @@ -4781,7 +4779,7 @@ static void labyrinth_level(int level_number) /* (temp_rand == 8) */ : OBJ_STAVES); const int treasure_item = items( 1, glopop, OBJ_RANDOM, true, - level_number * 3, 250 ); + level_number * 3, MAKE_ITEM_RANDOM_RACE ); if (treasure_item != NON_ITEM) { @@ -5070,7 +5068,7 @@ static bool treasure_area(int level_number, unsigned char ta1_x, continue; item_made = items( 1, OBJ_RANDOM, OBJ_RANDOM, true, - random2( level_number * 2 ), 250 ); + random2( level_number * 2 ), MAKE_ITEM_RANDOM_RACE ); if (item_made != NON_ITEM) { diff --git a/crawl-ref/source/effects.cc b/crawl-ref/source/effects.cc index a76041e600..fb59f24bd5 100644 --- a/crawl-ref/source/effects.cc +++ b/crawl-ref/source/effects.cc @@ -36,6 +36,7 @@ #include "ouch.h" #include "player.h" #include "randart.h" +#include "religion.h" #include "skills2.h" #include "spells3.h" #include "spells4.h" @@ -154,7 +155,10 @@ void banished(int gate_type, const std::string &who) down_stairs(true, you.your_level, gate_type); // heh heh untag_followers(); // safety -} // end banished() + + if (gate_type == DNGN_ENTER_ABYSS || gate_type == DNGN_ENTER_PANDEMONIUM) + xom_is_stimulated(255); +} bool forget_spell(void) { @@ -297,9 +301,14 @@ void direct_effect(struct bolt &pbolt) case DMNBM_BRAIN_FEED: // lose_stat() must come last {dlb} if (one_chance_in(3) && lose_stat(STAT_INTELLIGENCE, 1)) + { mpr("Something feeds on your intellect!"); + xom_is_stimulated(50); + } else + { mpr("Something tries to feed on your intellect!"); + } break; } @@ -351,7 +360,7 @@ void mons_direct_effect(struct bolt &pbolt, int i) else if (check_mons_resist_magic( monster, pbolt.ench_power )) simple_monster_message(monster, " resists."); else - monster_polymorph(monster, RANDOM_MONSTER, 100); + monster_polymorph(monster, RANDOM_MONSTER); break; } @@ -1138,12 +1147,11 @@ bool acquirement(object_class_type force_class, int agent) else { randart_properties_t proprt; - for (int item_tries = 0; item_tries < 50; item_tries++) { // BCR - unique is now used for food quantity. thing_created = items( unique, class_wanted, type_wanted, true, - MAKE_GOOD_ITEM, 250 ); + MAKE_GOOD_ITEM, 250 ); if (thing_created == NON_ITEM) continue; diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h index fd62ec96ba..3f930a509b 100644 --- a/crawl-ref/source/enum.h +++ b/crawl-ref/source/enum.h @@ -1532,7 +1532,9 @@ enum item_type_id_state_type // used for values in id[4][50] enum jewellery_type { - RING_REGENERATION, // 0 + RING_FIRST_RING = 0, + + RING_REGENERATION = RING_FIRST_RING, // 0 RING_PROTECTION, RING_PROTECTION_FROM_FIRE, RING_POISON_RESISTANCE, @@ -1556,7 +1558,12 @@ enum jewellery_type RING_FIRE, RING_ICE, RING_TELEPORT_CONTROL, // 23 - AMU_RAGE = 35, // 35 + + NUM_RINGS, // 24, keep as last ring; can overlap + // safely with first amulet. + + AMU_FIRST_AMULET = 35, + AMU_RAGE = AMU_FIRST_AMULET, // 35 AMU_RESIST_SLOW, AMU_CLARITY, AMU_WARDING, @@ -1566,6 +1573,7 @@ enum jewellery_type AMU_CONTROLLED_FLIGHT, AMU_INACCURACY, AMU_RESIST_MUTATION, + NUM_JEWELLERY }; diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h index c0465f2f56..065a2961ca 100644 --- a/crawl-ref/source/externs.h +++ b/crawl-ref/source/externs.h @@ -154,7 +154,7 @@ public: virtual void blink() = 0; virtual void teleport(bool right_now = false, bool abyss_shift = false) = 0; virtual void poison(actor *attacker, int amount = 1) = 0; - virtual void sicken(int amount) = 0; + virtual bool sicken(int amount) = 0; virtual void paralyse(int strength) = 0; virtual void slow_down(int strength) = 0; virtual void confuse(int strength) = 0; @@ -434,6 +434,7 @@ public: std::string name(description_level_type descrip, bool terse = false, bool ident = false) const; bool has_spells() const; + bool cursed() const; int book_number() const; void clear() @@ -598,7 +599,6 @@ public: unsigned int gold; int char_class; char class_name[30]; - // char speed; // now unused int time_taken; char shield_blocks; // number of shield blocks since last action @@ -773,7 +773,7 @@ public: int hunger_level() const { return hunger_state; } void make_hungry(int nutrition, bool silent = true); void poison(actor *agent, int amount = 1); - void sicken(int amount); + bool sicken(int amount); void paralyse(int str); void slow_down(int str); void confuse(int strength); @@ -1018,7 +1018,7 @@ public: int melee_evasion(const actor *attacker) const; void poison(actor *agent, int amount = 1); - void sicken(int strength); + bool sicken(int strength); void paralyse(int str); void slow_down(int str); void confuse(int strength); diff --git a/crawl-ref/source/fight.cc b/crawl-ref/source/fight.cc index 80decc8bd1..8eca25a856 100644 --- a/crawl-ref/source/fight.cc +++ b/crawl-ref/source/fight.cc @@ -450,7 +450,10 @@ bool melee_attack::attack() identify_mimic(def); if (attacker->fumbles_attack()) + { + xom_is_stimulated(14); // Xom thinks that is funny. return (false); + } // Allow god to get offended, etc. attacker->attacking(defender); @@ -2077,6 +2080,9 @@ int melee_attack::player_to_hit(bool random_factor) { if (wpn_skill != SK_FIGHTING) { + if (you.skills[wpn_skill] < 1 && player_in_a_dangerous_place()) + xom_is_stimulated(14); // Xom thinks that is mildly amusing. + your_to_hit += maybe_random2(you.skills[wpn_skill] + 1, random_factor); } diff --git a/crawl-ref/source/files.cc b/crawl-ref/source/files.cc index 21dfb30a40..2aa69828d7 100644 --- a/crawl-ref/source/files.cc +++ b/crawl-ref/source/files.cc @@ -893,7 +893,7 @@ static void grab_followers(std::vector& followers) } } -void load( int stair_taken, load_mode_type load_mode, bool was_a_labyrinth, +bool load( int stair_taken, load_mode_type load_mode, bool was_a_labyrinth, int old_level, branch_type old_branch ) { std::vector followers; @@ -1063,6 +1063,8 @@ void load( int stair_taken, load_mode_type load_mode, bool was_a_labyrinth, save_level( you.your_level, you.level_type, you.where_are_you ); setup_environment_effects(); + + return just_created_level; } // end load() void save_level(int level_saved, level_area_type old_ltype, diff --git a/crawl-ref/source/files.h b/crawl-ref/source/files.h index 9ac67b5093..112e8e620f 100644 --- a/crawl-ref/source/files.h +++ b/crawl-ref/source/files.h @@ -45,7 +45,7 @@ std::string get_savedir_path(const std::string &shortpath); std::string get_prefs_filename(); -void load( int stair_taken, load_mode_type load_mode, bool was_a_labyrinth, +bool load( int stair_taken, load_mode_type load_mode, bool was_a_labyrinth, int old_level, branch_type where_were_you2 ); // last updated 12may2000 {dlb} diff --git a/crawl-ref/source/food.cc b/crawl-ref/source/food.cc index aa765649c9..dfb90d4591 100644 --- a/crawl-ref/source/food.cc +++ b/crawl-ref/source/food.cc @@ -739,27 +739,32 @@ static void eat_chunk( int chunk_effect ) case CE_MUTAGEN_RANDOM: mpr("This meat tastes really weird."); mutate(100); + xom_is_stimulated(100); break; case CE_MUTAGEN_BAD: mpr("This meat tastes *really* weird."); give_bad_mutation(); + xom_is_stimulated(random2(200)); break; case CE_HCL: rot_player( 10 + random2(10) ); - disease_player( 50 + random2(100) ); + if (disease_player( 50 + random2(100) )) + xom_is_stimulated(random2(100)); break; case CE_POISONOUS: mpr("Yeeuch - this meat is poisonous!"); - poison_player( 3 + random2(4) ); + if (poison_player( 3 + random2(4) )) + xom_is_stimulated(random2(128)); break; case CE_ROTTEN: case CE_CONTAMINATED: mpr("There is something wrong with this meat."); - disease_player( 50 + random2(100) ); + if (disease_player( 50 + random2(100) )) + xom_is_stimulated(random2(100)); break; // note that this is the only case that takes time and forces redraw diff --git a/crawl-ref/source/hiscores.cc b/crawl-ref/source/hiscores.cc index 6def50115d..6dcaad88da 100644 --- a/crawl-ref/source/hiscores.cc +++ b/crawl-ref/source/hiscores.cc @@ -651,15 +651,15 @@ static level_area_type str_to_level_area_type(const std::string &s) return (LEVEL_DUNGEON); } -static int str_to_god(const std::string &god) +static god_type str_to_god(const std::string &god) { if (god.empty()) return GOD_NO_GOD; for (int i = GOD_NO_GOD; i < NUM_GODS; ++i) { - if (god_name(i) == god) - return (i); + if (god_name(static_cast(i)) == god) + return (static_cast(i)); } return (GOD_NO_GOD); } @@ -898,7 +898,7 @@ bool scorefile_entry::parse_obsolete_scoreline(const std::string &line) str = hs_nextint(inbuf); intel = hs_nextint(inbuf); dex = hs_nextint(inbuf); - god = hs_nextint(inbuf); + god = static_cast(hs_nextint(inbuf)); piety = hs_nextint(inbuf); penance = hs_nextint(inbuf); @@ -1014,7 +1014,7 @@ void scorefile_entry::reset() intel = -1; dex = -1; damage = -1; - god = -1; + god = GOD_NO_GOD; piety = -1; penance = -1; wiz_mode = 0; diff --git a/crawl-ref/source/hiscores.h b/crawl-ref/source/hiscores.h index a586d5233c..8f2a8f25b5 100644 --- a/crawl-ref/source/hiscores.h +++ b/crawl-ref/source/hiscores.h @@ -109,7 +109,7 @@ public: int str; // final str (useful for nickname) int intel; // final int int dex; // final dex (useful for nickname) - int god; // god + god_type god; // god int piety; // piety int penance; // penance char wiz_mode; // character used wiz mode diff --git a/crawl-ref/source/it_use2.cc b/crawl-ref/source/it_use2.cc index 880eb276cc..9f9004a568 100644 --- a/crawl-ref/source/it_use2.cc +++ b/crawl-ref/source/it_use2.cc @@ -153,19 +153,23 @@ bool potion_effect( char pot_eff, int pow ) poison_player( ((pot_eff == POT_POISON) ? 1 + random2avg(5, 2) : 3 + random2avg(13, 2)) ); + xom_is_stimulated(128); } break; case POT_SLOWING: slow_player( 10 + random2(pow) ); + xom_is_stimulated(64); break; case POT_PARALYSIS: you.paralyse(2 + random2( 6 + you.paralysis )); + xom_is_stimulated(64); break; case POT_CONFUSION: confuse_player( 3 + random2(8) ); + xom_is_stimulated(128); break; case POT_INVISIBILITY: @@ -193,6 +197,7 @@ bool potion_effect( char pot_eff, int pow ) case POT_DEGENERATION: mpr("There was something very wrong with that liquid!"); lose_stat(STAT_RANDOM, 1 + random2avg(4, 2)); + xom_is_stimulated(64); break; // Don't generate randomly - should be rare and interesting @@ -200,7 +205,10 @@ bool potion_effect( char pot_eff, int pow ) if (you.is_undead) mpr( "You feel terrible." ); else + { rot_player( 10 + random2(10) ); + xom_is_stimulated(64); + } break; case POT_WATER: @@ -249,6 +257,7 @@ bool potion_effect( char pot_eff, int pow ) case POT_BERSERK_RAGE: go_berserk(true); + xom_is_stimulated(64); break; case POT_CURE_MUTATION: diff --git a/crawl-ref/source/it_use3.cc b/crawl-ref/source/it_use3.cc index 27368ee5e1..f0809dcb3e 100644 --- a/crawl-ref/source/it_use3.cc +++ b/crawl-ref/source/it_use3.cc @@ -822,18 +822,21 @@ void tome_of_power(char sc_read_2) mpr("A cloud of weird smoke pours from the book's pages!"); big_cloud( random_smoke_type(), KC_YOU, you.x_pos, you.y_pos, 20, 10 + random2(8) ); + xom_is_stimulated(16); return; case 1: case 14: mpr("A cloud of choking fumes pours from the book's pages!"); big_cloud(CLOUD_POISON, KC_YOU, you.x_pos, you.y_pos, 20, 7 + random2(5)); + xom_is_stimulated(64); return; case 2: case 13: mpr("A cloud of freezing gas pours from the book's pages!"); big_cloud(CLOUD_COLD, KC_YOU, you.x_pos, you.y_pos, 20, 8 + random2(5)); + xom_is_stimulated(64); return; case 5: @@ -862,9 +865,9 @@ void tome_of_power(char sc_read_2) beam.is_explosion = true; explosion(beam); + xom_is_stimulated(255); return; - case 10: if (create_monster( MONS_ABOMINATION_SMALL, 6, BEH_HOSTILE, you.x_pos, you.y_pos, MHITYOU, 250 ) != -1) @@ -872,6 +875,7 @@ void tome_of_power(char sc_read_2) mpr("A horrible Thing appears!"); mpr("It doesn't look too friendly."); } + xom_is_stimulated(255); return; } @@ -929,6 +933,7 @@ void skill_manual(char sc_read_2) { mpr("The book looks somewhat more worn."); } + xom_is_stimulated(14); } // end skill_manual() static bool box_of_beasts(void) @@ -963,6 +968,7 @@ static bool box_of_beasts(void) you.x_pos, you.y_pos, MHITYOU, 250 ) != -1) { mpr("...and something leaps out!"); + xom_is_stimulated(14); ret = true; } } diff --git a/crawl-ref/source/item_use.cc b/crawl-ref/source/item_use.cc index ce71ead1b8..afb24beeb7 100644 --- a/crawl-ref/source/item_use.cc +++ b/crawl-ref/source/item_use.cc @@ -619,7 +619,10 @@ void wield_effects(int item_wield_2, bool showMsgs) } if (item_cursed( you.inv[item_wield_2] )) + { mpr("It sticks to your hand!"); + xom_is_stimulated(64); + } } if (showMsgs) @@ -2096,6 +2099,7 @@ void jewellery_wear_effects(item_def &item) mprf("Oops, that %s feels deathly cold.", jewellery_is_amulet(item)? "amulet" : "ring"); learned_something_new(TUT_YOU_CURSED); + xom_is_stimulated(128); } // cursed or not, we know that since we've put the ring on @@ -2552,7 +2556,9 @@ void zap_wand(void) return; } - if (item_type_known( you.inv[item_slot] )) + const bool alreadyknown = item_type_known(you.inv[item_slot]); + const bool dangerous = player_in_a_dangerous_place(); + if (alreadyknown) { if (you.inv[item_slot].sub_type == WAND_HASTING || you.inv[item_slot].sub_type == WAND_HEALING @@ -2603,6 +2609,12 @@ void zap_wand(void) type_zapped = ZAP_NEGATIVE_ENERGY; if (one_chance_in(17)) type_zapped = ZAP_ENSLAVEMENT; + if (dangerous) + { + // Xom loves it when you use a Wand of Random Effects and + // there is a dangerous monster nearby... + xom_is_stimulated(256); + } } beam.source_x = you.x_pos; @@ -2654,6 +2666,13 @@ void zap_wand(void) exercise( SK_EVOCATIONS, 1 ); alert_nearby_monsters(); + if (!alreadyknown && dangerous) + { + // Xom loves it when you use an unknown wand and there is a + // dangerous monster nearby... + xom_is_stimulated(256); + } + you.turn_is_over = true; } // end zap_wand() @@ -2727,6 +2746,14 @@ void drink(void) return; } + const bool alreadyknown = item_type_known(you.inv[item_slot]); + + // The "> 1" part is to reduce the amount of times that Xom is + // stimulated when you are a low-level 1 trying your first unknown + // potions on monsters. + const bool dangerous = + player_in_a_dangerous_place() && (you.experience_level > 1); + if (potion_effect( you.inv[item_slot].sub_type, 40 )) { set_ident_flags( you.inv[item_slot], ISFLAG_IDENT_MASK ); @@ -2739,6 +2766,12 @@ void drink(void) set_ident_type( you.inv[item_slot].base_type, you.inv[item_slot].sub_type, ID_TRIED_TYPE ); } + if (!alreadyknown && dangerous) + { + // Xom loves it when you drink an unknown potion and there is + // a dangerous monster nearby... + xom_is_stimulated(256); + } dec_inv_item_quantity( item_slot, 1 ); you.turn_is_over = true; @@ -2796,6 +2829,9 @@ bool drink_fountain(void) : POT_GAIN_INTELLIGENCE);//0.4% } + if (fountain_effect != POT_WATER) + xom_is_stimulated(64); + potion_effect(fountain_effect, 100); switch (grd[you.x_pos][you.y_pos]) @@ -3022,6 +3058,7 @@ bool enchant_weapon( int which_stat, bool quiet ) item.plus++; } + xom_is_stimulated(16); return (true); } @@ -3112,6 +3149,7 @@ static bool enchant_armour( void ) do_uncurse_item( item ); you.redraw_armour_class = 1; + xom_is_stimulated(16); return (true); } @@ -3238,6 +3276,10 @@ void read_scroll(void) // Actual removal of scroll done afterwards. -- bwr } + bool alreadyknown = get_ident_type( OBJ_SCROLLS, you.inv[item_slot].sub_type ) == ID_KNOWN_TYPE; + + bool dangerous = player_in_a_dangerous_place(); + // scrolls of paper are also exempted from this handling {dlb}: if (scroll_type != SCR_PAPER) { @@ -3531,6 +3573,13 @@ void read_scroll(void) set_ident_type( OBJ_SCROLLS, scroll_type, (id_the_scroll) ? ID_KNOWN_TYPE : ID_TRIED_TYPE ); + + if (!alreadyknown && dangerous) + { + // Xom loves it when you read an unknown scroll and there is + // a dangerous monster nearby... + xom_is_stimulated(256); + } } // end read_scroll() void examine_object(void) @@ -3559,6 +3608,9 @@ void use_randart(const item_def &item) { ASSERT( is_random_artefact( item ) ); + const bool alreadyknown = item_type_known(item); + const bool dangerous = player_in_a_dangerous_place(); + randart_properties_t proprt; randart_wpn_properties( item, proprt ); @@ -3575,4 +3627,11 @@ void use_randart(const item_def &item) if (proprt[RAP_NOISES]) you.special_wield = 50 + proprt[RAP_NOISES]; + + if (!alreadyknown && dangerous) + { + // Xom loves it when you use an unknown random artifact and + // there is a dangerous monster nearby... + xom_is_stimulated(256); + } } diff --git a/crawl-ref/source/itemprop.cc b/crawl-ref/source/itemprop.cc index 81437d49c1..593fcf8e37 100644 --- a/crawl-ref/source/itemprop.cc +++ b/crawl-ref/source/itemprop.cc @@ -934,6 +934,11 @@ equipment_type get_armour_slot( const item_def &item ) return (Armour_prop[ Armour_index[item.sub_type] ].slot); } +equipment_type get_armour_slot( armour_type arm ) +{ + return (Armour_prop[ Armour_index[arm] ].slot); +} + bool jewellery_is_amulet( const item_def &item ) { ASSERT( item.base_type == OBJ_JEWELLERY ); diff --git a/crawl-ref/source/itemprop.h b/crawl-ref/source/itemprop.h index 98c524b345..5c6ab77bd8 100644 --- a/crawl-ref/source/itemprop.h +++ b/crawl-ref/source/itemprop.h @@ -58,7 +58,8 @@ bool armour_is_hide( const item_def &item, bool inc_made = false ); bool armour_not_shiny( const item_def &item ); int armour_str_required( const item_def &arm ); -equipment_type get_armour_slot( const item_def &item ); +equipment_type get_armour_slot( const item_def &item ); +equipment_type get_armour_slot( armour_type arm ); bool jewellery_is_amulet( const item_def &item ); bool check_jewellery_size( const item_def &item, size_type size ); diff --git a/crawl-ref/source/items.cc b/crawl-ref/source/items.cc index cdaf9f4d97..59b04c9161 100644 --- a/crawl-ref/source/items.cc +++ b/crawl-ref/source/items.cc @@ -1119,7 +1119,7 @@ std::string origin_desc(const item_def &item) break; default: if (iorig > GOD_NO_GOD && iorig < NUM_GODS) - desc += std::string(god_name(iorig)) + desc += std::string(god_name(static_cast(iorig))) + " gifted " + article_it(item) + " to you "; else // Bug really. @@ -3044,3 +3044,8 @@ int item_def::book_number() const base_type == OBJ_STAVES? sub_type + 40 : -1); } + +bool item_def::cursed() const +{ + return (item_cursed(*this)); +} diff --git a/crawl-ref/source/libdos.cc b/crawl-ref/source/libdos.cc index dc50480c38..2db3422868 100644 --- a/crawl-ref/source/libdos.cc +++ b/crawl-ref/source/libdos.cc @@ -12,6 +12,8 @@ #include #include +#if defined(DOS) + static bool cursor_is_enabled = true; void init_libdos() @@ -88,3 +90,5 @@ int get_number_of_cols() { return (80); } + +#endif /* #if defined(DOS) */ diff --git a/crawl-ref/source/libw32c.cc b/crawl-ref/source/libw32c.cc index 3032b5602e..c111aa5251 100644 --- a/crawl-ref/source/libw32c.cc +++ b/crawl-ref/source/libw32c.cc @@ -1,3 +1,5 @@ +#if defined(WIN32CONSOLE) + /* * File: libw32c.cc * Summary: Functions for windows32 console mode support @@ -977,3 +979,5 @@ int get_number_of_cols() { return (80); } + +#endif /* #if defined(WIN32CONSOLE) */ diff --git a/crawl-ref/source/makefile.obj b/crawl-ref/source/makefile.obj index f2ec8974e0..0316e1cb7f 100644 --- a/crawl-ref/source/makefile.obj +++ b/crawl-ref/source/makefile.obj @@ -75,6 +75,7 @@ transfor.o \ travel.o \ tutorial.o \ view.o \ +xom.o \ Kills.o \ mt19937ar.o \ clua.o diff --git a/crawl-ref/source/makeitem.cc b/crawl-ref/source/makeitem.cc index c920c83325..6bd00913e7 100644 --- a/crawl-ref/source/makeitem.cc +++ b/crawl-ref/source/makeitem.cc @@ -844,6 +844,8 @@ int items( int allow_uniques, // not just true-false, // item_race also gives type of rune! const dgn_region_list &forbidden) { + const bool make_good_item = (item_level == MAKE_GOOD_ITEM); + int temp_rand = 0; // probability determination {dlb} int range_charges = 0; // for OBJ_WANDS charge count {dlb} int loopy = 0; // just another loop variable {dlb} @@ -864,7 +866,7 @@ int items( int allow_uniques, // not just true-false, return (NON_ITEM); // cap item_level unless an acquirement-level item {dlb}: - if (item_level > 50 && item_level != MAKE_GOOD_ITEM) + if (item_level > 50 && !make_good_item) item_level = 50; // determine base_type for item generated {dlb}: @@ -1037,7 +1039,7 @@ int items( int allow_uniques, // not just true-false, ASSERT(!is_fixed_artefact(mitm[p]) && !is_random_artefact(mitm[p])); - if (item_level == MAKE_GOOD_ITEM + if (make_good_item && force_type != OBJ_RANDOM && (mitm[p].sub_type == WPN_CLUB || mitm[p].sub_type == WPN_SLING)) { @@ -1215,7 +1217,7 @@ int items( int allow_uniques, // not just true-false, // if we allow acquirement-type items to be orcish, then // there's a good chance that we'll just strip them of // their ego type at the bottom of this function. -- bwr - if (item_level == MAKE_GOOD_ITEM + if (make_good_item && get_equip_race( mitm[p] ) == ISFLAG_ORCISH) { set_equip_race( mitm[p], ISFLAG_NO_RACE ); @@ -1246,7 +1248,7 @@ int items( int allow_uniques, // not just true-false, mitm[p].plus2 += race_plus2; if ((random2(200) <= 50 + item_level - || item_level == MAKE_GOOD_ITEM + || make_good_item || is_demonic(mitm[p])) // nobody would bother enchanting a club && mitm[p].sub_type != WPN_CLUB @@ -1258,7 +1260,7 @@ int items( int allow_uniques, // not just true-false, do { if (random2(300) <= 100 + item_level - || item_level == MAKE_GOOD_ITEM + || make_good_item || is_demonic( mitm[p] )) { // note: this doesn't guarantee special enchantment @@ -1605,19 +1607,18 @@ int items( int allow_uniques, // not just true-false, count++; } - while (item_level == MAKE_GOOD_ITEM + while (make_good_item && mitm[p].special == SPWPN_NORMAL && count < 5); // if acquired item still not ego... enchant it up a bit. - if (item_level == MAKE_GOOD_ITEM && mitm[p].special == SPWPN_NORMAL) + if (make_good_item && mitm[p].special == SPWPN_NORMAL) { mitm[p].plus += 2 + random2(3); mitm[p].plus2 += 2 + random2(3); } - const int chance = (item_level == MAKE_GOOD_ITEM) ? 200 - : item_level; + const int chance = (make_good_item) ? 200 : item_level; // odd-looking, but this is how the algorithm compacts {dlb}: for (loopy = 0; loopy < 4; loopy++) @@ -1767,7 +1768,7 @@ int items( int allow_uniques, // not just true-false, else { // decide specials: - if (item_level == MAKE_GOOD_ITEM) + if (make_good_item) temp_rand = random2(150); else temp_rand = random2(2000 - 55 * item_level); @@ -1816,42 +1817,7 @@ int items( int allow_uniques, // not just true-false, mitm[p].sub_type = force_type; else { - mitm[p].sub_type = random2(3); - - if (random2(35) <= item_level + 10) - { - mitm[p].sub_type = random2(5); - if (one_chance_in(4)) - mitm[p].sub_type = ARM_ANIMAL_SKIN; - } - - if (random2(60) <= item_level + 10) - mitm[p].sub_type = random2(8); - - if (10 + item_level >= random2(400) && one_chance_in(20)) - mitm[p].sub_type = ARM_DRAGON_HIDE + random2(7); - - if (10 + item_level >= random2(500) && one_chance_in(20)) - { - mitm[p].sub_type = ARM_STEAM_DRAGON_HIDE + random2(11); - - if (mitm[p].sub_type == ARM_ANIMAL_SKIN && one_chance_in(20)) - mitm[p].sub_type = ARM_CRYSTAL_PLATE_MAIL; - } - - // secondary armours: - if (one_chance_in(5)) - { - mitm[p].sub_type = ARM_SHIELD + random2(5); - - if (mitm[p].sub_type == ARM_SHIELD) // 33.3% - { - if (coinflip()) - mitm[p].sub_type = ARM_BUCKLER; // 50.0% - else if (one_chance_in(3)) - mitm[p].sub_type = ARM_LARGE_SHIELD; // 16.7% - } - } + mitm[p].sub_type = get_random_armour_type(item_level); } if (mitm[p].sub_type == ARM_HELMET) @@ -2034,7 +2000,7 @@ int items( int allow_uniques, // not just true-false, if (50 + item_level >= random2(250) - || item_level == MAKE_GOOD_ITEM + || make_good_item || (mitm[p].sub_type == ARM_HELMET && get_helmet_type(mitm[p]) == THELM_WIZARD_HAT)) { @@ -2044,7 +2010,7 @@ int items( int allow_uniques, // not just true-false, mitm[p].plus += random2(3); if (30 + item_level >= random2(350) - && (item_level == MAKE_GOOD_ITEM + && (make_good_item || (!get_equip_race(mitm[p]) == ISFLAG_ORCISH || (mitm[p].sub_type <= ARM_PLATE_MAIL && coinflip())))) { @@ -2242,7 +2208,7 @@ int items( int allow_uniques, // not just true-false, // Make sure you don't get a hide from acquirement (since that // would be an enchanted item which somehow didn't get converted // into armour). - if (item_level == MAKE_GOOD_ITEM) + if (make_good_item) hide2armour(mitm[p]); // what of animal hides? {dlb} // skin armours + Crystal PM don't get special enchantments @@ -2583,8 +2549,9 @@ int items( int allow_uniques, // not just true-false, // otherwise, determine jewellery type {dlb}: if (force_type == OBJ_RANDOM) { - mitm[p].sub_type = (!one_chance_in(4) ? random2(24) // rings - : AMU_RAGE + random2(10)); + mitm[p].sub_type = + (!one_chance_in(4) ? get_random_ring_type() + : get_random_amulet_type()); // Adjusted distribution here -- bwr if ((mitm[p].sub_type == RING_INVISIBILITY @@ -2826,10 +2793,16 @@ int items( int allow_uniques, // not just true-false, default: mitm[p].base_type = OBJ_GOLD; - // Note that acquirement level gold gives much less than the - // price of a scroll of acquirement (520 gold). -- bwr - if (item_level == MAKE_GOOD_ITEM) - quant = 50 + random2avg(100, 2) + random2avg(100, 2); + // Acquirement now gives more gold: The base price of a scroll + // of acquirement is 520 gold. The expected value of the gold + // it produces is about 480. So you cannot consistently make a + // profit by buying scrolls of acquirement. However, there is + // a very low chance you'll get lucky and receive up to 2296! + // This is quite rare: 50% of the time you'll get less than + // 360 gold and 90% of the time you'll get less than 900 and + // 99% of the time you'll get less than 1500. --Zooko + if (make_good_item) + quant = 150 + random2(150) + random2(random2(random2(2000))); else quant = 1 + random2avg(19, 2) + random2(item_level); break; @@ -3894,3 +3867,84 @@ void give_item(int mid, int level_number) //mv: cleanup+minor changes give_ammo(mons, level_number, item_race); give_armour(mons, 1 + level_number / 2); } // end give_item() + +jewellery_type get_random_amulet_type() +{ + return (jewellery_type) + (AMU_FIRST_AMULET + random2(NUM_JEWELLERY - AMU_FIRST_AMULET)); +} + +static jewellery_type get_raw_random_ring_type() +{ + return (jewellery_type) (RING_REGENERATION + random2(NUM_RINGS)); +} + +jewellery_type get_random_ring_type() +{ + const jewellery_type j = get_raw_random_ring_type(); + // Adjusted distribution here -- bwr + if ((j == RING_INVISIBILITY + || j == RING_REGENERATION + || j == RING_TELEPORT_CONTROL + || j == RING_SLAYING) + && !one_chance_in(3)) + { + return get_raw_random_ring_type(); + } + + return (j); +} + +armour_type get_random_body_armour_type(int item_level) +{ + for (int tries = 100; tries > 0; --tries) + { + const armour_type tr = get_random_armour_type(item_level); + if (get_armour_slot(tr) == EQ_BODY_ARMOUR) + return (tr); + } + return (ARM_ROBE); +} + +// FIXME: Need to clean up this mess. +armour_type get_random_armour_type(int item_level) +{ + int armtype = random2(3); + + if (random2(35) <= item_level + 10) + { + armtype = random2(5); + if (one_chance_in(4)) + armtype = ARM_ANIMAL_SKIN; + } + + if (random2(60) <= item_level + 10) + armtype = random2(8); + + if (10 + item_level >= random2(400) && one_chance_in(20)) + armtype = ARM_DRAGON_HIDE + random2(7); + + if (10 + item_level >= random2(500) && one_chance_in(20)) + { + armtype = ARM_STEAM_DRAGON_HIDE + random2(11); + + if (armtype == ARM_ANIMAL_SKIN && one_chance_in(20)) + armtype = ARM_CRYSTAL_PLATE_MAIL; + } + + // secondary armours: + if (one_chance_in(5)) + { + armtype = ARM_SHIELD + random2(5); + + if (armtype == ARM_SHIELD) // 33.3% + { + if (coinflip()) + armtype = ARM_BUCKLER; // 50.0% + else if (one_chance_in(3)) + armtype = ARM_LARGE_SHIELD; // 16.7% + } + } + + return static_cast(armtype); +} diff --git a/crawl-ref/source/makeitem.h b/crawl-ref/source/makeitem.h index 62d0ee1db3..d74d572545 100644 --- a/crawl-ref/source/makeitem.h +++ b/crawl-ref/source/makeitem.h @@ -18,4 +18,9 @@ void item_colour( item_def &item ); void init_rod_mp(item_def &item); void give_item(int mid, int level_number); +jewellery_type get_random_ring_type(); +jewellery_type get_random_amulet_type(); +armour_type get_random_body_armour_type(int level); +armour_type get_random_armour_type(int item_level); + #endif diff --git a/crawl-ref/source/message.cc b/crawl-ref/source/message.cc index 3c7b2f31f3..7b13d02917 100644 --- a/crawl-ref/source/message.cc +++ b/crawl-ref/source/message.cc @@ -226,8 +226,8 @@ int channel_to_colour( int channel, int param ) case MSGCH_GOD: case MSGCH_PRAY: ret = (Options.channels[ channel ] == MSGCOL_DEFAULT) - ? god_colour( param ) - : god_message_altar_colour( param ); + ? god_colour( static_cast(param) ) + : god_message_altar_colour( param ); break; case MSGCH_DURATION: diff --git a/crawl-ref/source/misc.cc b/crawl-ref/source/misc.cc index 45954cee16..fdae822b50 100644 --- a/crawl-ref/source/misc.cc +++ b/crawl-ref/source/misc.cc @@ -26,8 +26,9 @@ #include #endif -#include -#include +#include +#include +#include #ifdef DOS #include @@ -984,7 +985,12 @@ void down_stairs( bool remove_stairs, int old_level, int force_stair ) break; } - load(stair_taken, LOAD_ENTER_LEVEL, was_a_labyrinth, old_level, old_where); + const bool newlevel = + load(stair_taken, LOAD_ENTER_LEVEL, was_a_labyrinth, + old_level, old_where); + + if (newlevel) + xom_is_stimulated(49); unsigned char pc = 0; unsigned char pt = random2avg(28, 3); @@ -1350,7 +1356,7 @@ void handle_traps(char trt, int i, bool trap_known) if (scan_randarts(RAP_PREVENT_TELEPORTATION)) mpr("You feel a weird sense of stasis."); else - you_teleport2( true ); + you_teleport_now( true ); break; case TRAP_AMNESIA: @@ -1843,8 +1849,8 @@ bool i_feel_safe(bool announce) int yend = you.y_pos + 9, xend = you.x_pos + 9; if ( xstart < 0 ) xstart = 0; if ( ystart < 0 ) ystart = 0; - if ( xend >= GXM ) xend = 0; - if ( ystart >= GYM ) yend = 0; + if ( xend >= GXM ) xend = GXM; + if ( ystart >= GYM ) yend = GYM; if (in_bounds(you.x_pos, you.y_pos) && env.cgrid[you.x_pos][you.y_pos] != EMPTY_CLOUD) @@ -1883,15 +1889,16 @@ bool i_feel_safe(bool announce) { if (announce) mons.push_back(mon); - else { - tutorial_first_monster(*mon); + else + { + tutorial_first_monster(*mon); return false; + } } } } } } - } if (announce) { @@ -2055,6 +2062,112 @@ int player_branch_depth() return subdungeon_depth(you.where_are_you, you.your_level); } +static const char *shop_types[] = { + "weapon", + "armour", + "antique weapon", + "antique armour", + "antiques", + "jewellery", + "wand", + "book", + "food", + "distillery", + "scroll", + "general" +}; + +int str_to_shoptype(const std::string &s) +{ + if (s == "random" || s == "any") + return (SHOP_RANDOM); + + for (unsigned i = 0; i < sizeof(shop_types) / sizeof (*shop_types); ++i) + { + if (s == shop_types[i]) + return (i); + } + return (-1); +} + +/* Decides whether autoprayer Right Now is a good idea. */ +static bool should_autopray() +{ + if ( Options.autoprayer_on == false || + you.religion == GOD_NO_GOD || + you.duration[DUR_PRAYER] || + grid_altar_god( grd[you.x_pos][you.y_pos] ) != GOD_NO_GOD || + !i_feel_safe() ) + return false; + + // We already know that we're not praying now. So if you + // just autoprayed, there's a problem. + if ( you.just_autoprayed ) + { + mpr("Autoprayer failed, deactivating.", MSGCH_WARN); + Options.autoprayer_on = false; + return false; + } + + return true; +} + +/* Actually performs autoprayer. */ +bool do_autopray() +{ + if ( you.turn_is_over ) // can happen with autopickup, I think + return false; + + if ( should_autopray() ) + { + pray(); + you.just_autoprayed = true; + return true; + } + else + { + you.just_autoprayed = false; + return false; + } +} + +// general threat = sum_of_logexpervalues_of_nearby_unfriendly_monsters +// highest threat = highest_logexpervalue_of_nearby_unfriendly_monsters +void monster_threat_values(double *general, double *highest) +{ + double sum = 0; + int highest_xp = -1; + + monsters *monster = NULL; + for (int it = 0; it < MAX_MONSTERS; it++) + { + monster = &menv[it]; + + if (monster->alive() && mons_near(monster) && !mons_friendly(monster)) + { + const int xp = exper_value(monster); + const double log_xp = log(xp); + sum += log_xp; + if (xp > highest_xp) + { + highest_xp = xp; + *highest = log_xp; + } + } + } + + *general = sum; +} + +bool player_in_a_dangerous_place() +{ + const double logexp = log(you.experience); + double gen_threat = 0.0, hi_threat = 0.0; + monster_threat_values(&gen_threat, &hi_threat); + + return (gen_threat > logexp * 1.3 || hi_threat > logexp / 2); +} + //////////////////////////////////////////////////////////////////////////// // Living breathing dungeon stuff. // @@ -2131,72 +2244,3 @@ void run_environment_effects() } } } - -static const char *shop_types[] = { - "weapon", - "armour", - "antique weapon", - "antique armour", - "antiques", - "jewellery", - "wand", - "book", - "food", - "distillery", - "scroll", - "general" -}; - -int str_to_shoptype(const std::string &s) -{ - if (s == "random" || s == "any") - return (SHOP_RANDOM); - - for (unsigned i = 0; i < sizeof(shop_types) / sizeof (*shop_types); ++i) - { - if (s == shop_types[i]) - return (i); - } - return (-1); -} - -/* Decides whether autoprayer Right Now is a good idea. */ -static bool should_autopray() -{ - if ( Options.autoprayer_on == false || - you.religion == GOD_NO_GOD || - you.duration[DUR_PRAYER] || - grid_altar_god( grd[you.x_pos][you.y_pos] ) != GOD_NO_GOD || - !i_feel_safe() ) - return false; - - // We already know that we're not praying now. So if you - // just autoprayed, there's a problem. - if ( you.just_autoprayed ) - { - mpr("Autoprayer failed, deactivating.", MSGCH_WARN); - Options.autoprayer_on = false; - return false; - } - - return true; -} - -/* Actually performs autoprayer. */ -bool do_autopray() -{ - if ( you.turn_is_over ) // can happen with autopickup, I think - return false; - - if ( should_autopray() ) - { - pray(); - you.just_autoprayed = true; - return true; - } - else - { - you.just_autoprayed = false; - return false; - } -} diff --git a/crawl-ref/source/misc.h b/crawl-ref/source/misc.h index 6c82049174..0fa10e8421 100644 --- a/crawl-ref/source/misc.h +++ b/crawl-ref/source/misc.h @@ -201,4 +201,6 @@ int str_to_shoptype(const std::string &s); bool do_autopray(); +bool player_in_a_dangerous_place(); + #endif diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc index 0d74cba572..351ee05880 100644 --- a/crawl-ref/source/mon-util.cc +++ b/crawl-ref/source/mon-util.cc @@ -2361,10 +2361,14 @@ bool monsters::fumbles_attack(bool verbose) { if (floundering() && one_chance_in(4)) { - if (verbose && !silenced(you.x_pos, you.y_pos) - && !silenced(x, y)) + if (verbose) { - mprf(MSGCH_SOUND, "You hear a splashing noise."); + const bool can_see = + mons_near(this) && player_monster_visible(this); + if (can_see) + mprf("%s splashes around in the water."); + else if (!silenced(you.x_pos, you.y_pos) && !silenced(x, y)) + mprf(MSGCH_SOUND, "You hear a splashing noise."); } return (true); } @@ -3384,7 +3388,7 @@ void monsters::apply_enchantment(mon_enchant me, int spd) if (type == MONS_GLOWING_SHAPESHIFTER || random2(1000) < mod_speed( 250, spd )) { - monster_polymorph(this, RANDOM_MONSTER, 0); + monster_polymorph(this, RANDOM_MONSTER, PPT_SAME); } break; @@ -3392,7 +3396,7 @@ void monsters::apply_enchantment(mon_enchant me, int spd) if (type == MONS_SHAPESHIFTER || random2(1000) < mod_speed( 1000 / ((15 * hit_dice) / 5), spd )) { - monster_polymorph(this, RANDOM_MONSTER, 0); + monster_polymorph(this, RANDOM_MONSTER, PPT_SAME); } break; @@ -3479,10 +3483,10 @@ kill_category monsters::kill_alignment() const return (attitude == ATT_FRIENDLY? KC_FRIENDLY : KC_OTHER); } -void monsters::sicken(int amount) +bool monsters::sicken(int amount) { if (holiness() != MH_NATURAL || (amount /= 2) < 1) - return; + return (false); if (!has_ench(ENCH_SICK) && mons_near(this) && player_monster_visible(this)) @@ -3492,6 +3496,8 @@ void monsters::sicken(int amount) } add_ench(mon_enchant(ENCH_SICK, amount)); + + return (true); } int monsters::base_speed(int mcls) @@ -3643,7 +3649,7 @@ void monsters::mutate() if (holiness() != MH_NATURAL) return; - monster_polymorph(this, RANDOM_MONSTER, 100); + monster_polymorph(this, RANDOM_MONSTER); } bool monsters::is_icy() const diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc index bedd380d1c..0923e8cb09 100644 --- a/crawl-ref/source/monstuff.cc +++ b/crawl-ref/source/monstuff.cc @@ -24,6 +24,7 @@ #include #include #include +#include #ifdef DOS #include @@ -375,7 +376,6 @@ void monster_die(monsters *monster, char killer, int i, bool silent) if (monster->type == -1) return; - int xom_will_act = 0; int monster_killed = monster_index(monster); bool death_message = !silent && mons_near(monster) && player_monster_visible(monster); @@ -536,15 +536,6 @@ void monster_die(monsters *monster, char killer, int i, bool silent) // killing triggers tutorial lesson tutorial_inspect_kill(); - // Xom doesn't care who you killed: - if (you.religion == GOD_XOM - && random2(70) <= 10 + monster->hit_dice) - { - // postpone Xom action until after the monster dies - xom_will_act = 1 + random2(monster->hit_dice); - } - - // Trying to prevent summoning abuse here, so we're trying to // prevent summoned creatures from being done_good kills, // Only affects monsters friendly when created. if (!created_friendly) @@ -810,7 +801,7 @@ void monster_die(monsters *monster, char killer, int i, bool silent) if (monster->type == MONS_SIMULACRUM_SMALL || monster->type == MONS_SIMULACRUM_LARGE) { - simple_monster_message( monster, " vaporizes!" ); + simple_monster_message( monster, " vaporises!" ); place_cloud( CLOUD_COLD, monster->x, monster->y, 1 + random2(3), monster->kill_alignment() ); @@ -839,9 +830,6 @@ void monster_die(monsters *monster, char killer, int i, bool silent) || killer == KILL_YOU || pet_kill); monster_cleanup(monster); - - if ( xom_will_act ) - Xom_acts(true, xom_will_act, false); } // end monster_die void monster_cleanup(monsters *monster) @@ -1013,23 +1001,46 @@ static bool valid_morph( monsters *monster, int new_mclass ) return (monster_habitable_grid(new_mclass, current_tile)); } // end valid_morph() -// note that power is (as of yet) unused within this function - -// may be worthy of consideration of later implementation, though, -// so I'll still let the parameter exist for the time being {dlb} -bool monster_polymorph( monsters *monster, int targetc, int power ) +static bool is_poly_power_unsuitable( + poly_power_type power, + int src_pow, + int tgt_pow, + int relax) +{ + switch (power) + { + case PPT_LESS: + return (tgt_pow > src_pow - 3 + (relax * 3) / 2) + || (power == PPT_LESS && (tgt_pow < src_pow - (relax / 2))); + case PPT_MORE: + return (tgt_pow < src_pow + 2 - relax) + || (power == PPT_MORE && (tgt_pow > src_pow + relax)); + default: + case PPT_SAME: + return (tgt_pow < src_pow - relax) + || (tgt_pow > src_pow + (relax * 3) / 2); + } +} + +/* + * if targetc == RANDOM_MONSTER then relpower indicates the desired + * power of the new monster relative to the current monster. + * Relaxation still takes effect when needed no matter what relpower + * says. + */ +bool monster_polymorph( monsters *monster, monster_type targetc, + poly_power_type power ) { std::string str_polymon; int source_power, target_power, relax; int tries = 1000; - UNUSED( power ); - // Used to be mons_power, but that just returns hit_dice // for the monster class. By using the current hit dice // the player gets the opportunity to use draining more // effectively against shapeshifters. -- bwr source_power = monster->hit_dice; - relax = 2; + relax = 1; if (targetc == RANDOM_MONSTER) { @@ -1044,15 +1055,15 @@ bool monster_polymorph( monsters *monster, int targetc, int power ) target_power = mons_power( targetc ); - if (one_chance_in(100)) + if (one_chance_in(200)) relax++; if (relax > 50) return (simple_monster_message( monster, " shudders." )); } while (tries-- && (!valid_morph( monster, targetc ) - || target_power < source_power - relax - || target_power > source_power + (relax * 3) / 2)); + || is_poly_power_unsuitable(power, source_power, + target_power, relax))); } if (!valid_morph( monster, targetc )) diff --git a/crawl-ref/source/monstuff.h b/crawl-ref/source/monstuff.h index cc308c6a77..ec98dbb277 100644 --- a/crawl-ref/source/monstuff.h +++ b/crawl-ref/source/monstuff.h @@ -14,6 +14,7 @@ #ifndef MONSTUFF_H #define MONSTUFF_H +#include "mon-util.h" // useful macro #define SAME_ATTITUDE(x) (mons_friendly(x)?BEH_FRIENDLY:BEH_HOSTILE) @@ -33,12 +34,13 @@ int get_mimic_colour( const monsters *mimic ); * *********************************************************************** */ void alert_nearby_monsters(void); - -// last updated: 08jun2000 {dlb} -/* *********************************************************************** - * called from: beam - effects - monstuff - * *********************************************************************** */ -bool monster_polymorph(struct monsters *monster, int targetc, int power); +enum poly_power_type { + PPT_LESS, + PPT_MORE, + PPT_SAME +}; +bool monster_polymorph(monsters *monster, monster_type targetc, + poly_power_type p = PPT_SAME); // last updated: 08jun2000 {dlb} /* *********************************************************************** diff --git a/crawl-ref/source/mutation.cc b/crawl-ref/source/mutation.cc index 81aec01c2f..8db09cdc25 100644 --- a/crawl-ref/source/mutation.cc +++ b/crawl-ref/source/mutation.cc @@ -40,6 +40,7 @@ #include "notes.h" #include "ouch.h" #include "player.h" +#include "religion.h" #include "skills2.h" #include "stuff.h" #include "transfor.h" @@ -1149,27 +1150,68 @@ void display_mutations() getch(); } -bool mutate(int which_mutation, bool failMsg) +static int calc_mutation_amusement_value(int which_mutation) { - int mutat = which_mutation; - bool force_mutation = false; // is mutation forced? - bool demonspawn = false; // demonspawn mutation? - int i; + int amusement = 16 * (11 - mutation_rarity[which_mutation]); - if (which_mutation >= 2000) + switch (which_mutation) { - demonspawn = true; - force_mutation = true; - mutat -= 2000; - which_mutation -= 2000; + case MUT_TOUGH_SKIN: + case MUT_STRONG: + case MUT_CLEVER: + case MUT_AGILE: + case MUT_POISON_RESISTANCE: + case MUT_TELEPORT_CONTROL: + case MUT_MAGIC_RESISTANCE: + case MUT_TELEPORT_AT_WILL: + case MUT_MAPPING: + case MUT_CLARITY: + case MUT_MUTATION_RESISTANCE: + amusement /= 2; // not funny + break; + + case MUT_CARNIVOROUS: + case MUT_HERBIVOROUS: + case MUT_FAST_METABOLISM: + case MUT_WEAK: + case MUT_DOPEY: + case MUT_CLUMSY: + case MUT_TELEPORT: + case MUT_FAST: + case MUT_DEFORMED: + case MUT_SPIT_POISON: + case MUT_BREATHE_FLAMES: + case MUT_BLINK: + case MUT_HORNS: + case MUT_LOST: + case MUT_BERSERK: + case MUT_DETERIORATION: + case MUT_BLURRY_VISION: + case MUT_FRAIL: + case MUT_CLAWS: + case MUT_HOOVES: + case MUT_BREATHE_POISON: + case MUT_STINGER: + case MUT_BIG_WINGS: + case MUT_BLUE_MARKS: + case MUT_GREEN_MARKS: + amusement *= 2; // funny! + break; + + default: + break; } - if (which_mutation >= 1000) // must give mutation without failure - { + return (amusement); +} + +bool mutate(int which_mutation, bool failMsg, bool force_mutation, + bool demonspawn) +{ + int mutat = which_mutation; + + if (demonspawn) force_mutation = true; - mutat -= 1000; - which_mutation -= 1000; - } // Undead bodies don't mutate, they fall apart. -- bwr // except for demonspawn (or other permamutations) in lichform -- haranp @@ -1241,10 +1283,42 @@ bool mutate(int which_mutation, bool failMsg) || you.mutation[mutat] > 13 || random2(10) >= mutation_rarity[mutat] + you.demon_pow[mutat]); } + else if (which_mutation == 101) + { + do + { + mutat = random2(NUM_MUTATIONS); - if (you.mutation[mutat] >= 3 - && (mutat != MUT_STRONG && mutat != MUT_CLEVER && mutat != MUT_AGILE) - && (mutat != MUT_WEAK && mutat != MUT_DOPEY && mutat != MUT_CLUMSY)) + if (one_chance_in(1000)) + return false; + if (one_chance_in(5)) + { + switch (random2(8)) + { + case 0: mutat = MUT_WEAK; break; + case 1: mutat = MUT_DOPEY; break; + case 2: mutat = MUT_CLUMSY; break; + case 3: mutat = MUT_DEFORMED; break; + case 4: mutat = MUT_LOST; break; + case 5: mutat = MUT_DETERIORATION; break; + case 6: mutat = MUT_BLURRY_VISION; break; + case 7: mutat = MUT_FRAIL; break; + } + } + } + while ((you.mutation[mutat] >= 3 + && (mutat != MUT_STRONG && mutat != MUT_CLEVER + && mutat != MUT_AGILE) && (mutat != MUT_WEAK + && mutat != MUT_DOPEY + && mutat != MUT_CLUMSY)) + || you.mutation[mutat] > 13 + || random2(10) >= mutation_rarity[mutat] + you.demon_pow[mutat]); + } + else if (you.mutation[mutat] >= 3 + && (mutat != MUT_STRONG && mutat != MUT_CLEVER + && mutat != MUT_AGILE) + && (mutat != MUT_WEAK && mutat != MUT_DOPEY + && mutat != MUT_CLUMSY)) { return false; } @@ -1272,7 +1346,7 @@ bool mutate(int which_mutation, bool failMsg) mutat = MUT_BREATHE_POISON; // breathe poison replaces spit poison (so it takes the slot) - for (i = 0; i < 52; i++) + for (int i = 0; i < 52; i++) { if (you.ability_letter_table[i] == ABIL_SPIT_POISON) you.ability_letter_table[i] = ABIL_BREATHE_POISON; @@ -1461,14 +1535,13 @@ bool mutate(int which_mutation, bool failMsg) mpr(gain_mutation[mutat][you.mutation[mutat]], MSGCH_MUTATION); break; - case MUT_HOOVES: //jmf: like horns mpr(gain_mutation[mutat][you.mutation[mutat]], MSGCH_MUTATION); if (you.equip[EQ_BOOTS] != -1) { FixedVector < char, 8 > removed; - for (i = EQ_WEAPON; i < EQ_RIGHT_RING; i++) + for (int i = EQ_WEAPON; i < EQ_RIGHT_RING; i++) { removed[i] = 0; } @@ -1489,7 +1562,7 @@ bool mutate(int which_mutation, bool failMsg) { FixedVector < char, 8 > removed; - for (i = EQ_WEAPON; i < EQ_RIGHT_RING; i++) + for (int i = EQ_WEAPON; i < EQ_RIGHT_RING; i++) { removed[i] = 0; } @@ -1512,7 +1585,7 @@ bool mutate(int which_mutation, bool failMsg) FixedVector < char, 8 > removed; - for (i = EQ_WEAPON; i < EQ_RIGHT_RING; i++) + for (int i = EQ_WEAPON; i < EQ_RIGHT_RING; i++) { removed[i] = 0; } @@ -1605,10 +1678,14 @@ bool mutate(int which_mutation, bool failMsg) you.mutation[mutat]++; + /* amusement value will be 16 * (11-rarity) * Xom's-sense-of-humor */ + int amusementvalue = calc_mutation_amusement_value(mutat); + xom_is_stimulated(amusementvalue); + take_note(Note(NOTE_GET_MUTATION, mutat, you.mutation[mutat])); /* remember, some mutations don't get this far (eg frail) */ return true; -} // end mutation() +} int how_mutated(void) { @@ -1659,8 +1736,10 @@ bool delete_mutation(int which_mutation) return false; } while ((you.mutation[mutat] == 0 - && (mutat != MUT_STRONG && mutat != MUT_CLEVER && mutat != MUT_AGILE) - && (mutat != MUT_WEAK && mutat != MUT_DOPEY && mutat != MUT_CLUMSY)) + && (mutat != MUT_STRONG && mutat != MUT_CLEVER + && mutat != MUT_AGILE) + && (mutat != MUT_WEAK && mutat != MUT_DOPEY + && mutat != MUT_CLUMSY)) || random2(10) >= mutation_rarity[mutat] || you.demon_pow[mutat] >= you.mutation[mutat]); } @@ -2191,13 +2270,13 @@ bool perma_mutate(int which_mut, char how_much) { char levels = 0; - if (mutate(which_mut + 2000)) + if (mutate(which_mut, false, true, true)) levels++; - if (how_much >= 2 && mutate(which_mut + 2000)) + if (how_much >= 2 && mutate(which_mut, false, true, true)) levels++; - if (how_much >= 3 && mutate(which_mut + 2000)) + if (how_much >= 3 && mutate(which_mut, false, true, true)) levels++; you.demon_pow[which_mut] = levels; @@ -2205,42 +2284,6 @@ bool perma_mutate(int which_mut, char how_much) return (levels > 0); } // end perma_mutate() -bool give_good_mutation(bool failMsg) -{ - int temp_rand = 0; // probability determination {dlb} - int which_good_one = 0; - - temp_rand = random2(25); - - which_good_one = ((temp_rand >= 24) ? MUT_TOUGH_SKIN : - (temp_rand == 23) ? MUT_STRONG : - (temp_rand == 22) ? MUT_CLEVER : - (temp_rand == 21) ? MUT_AGILE : - (temp_rand == 20) ? MUT_HEAT_RESISTANCE : - (temp_rand == 19) ? MUT_COLD_RESISTANCE : - (temp_rand == 18) ? MUT_SHOCK_RESISTANCE : - (temp_rand == 17) ? MUT_REGENERATION : - (temp_rand == 16) ? MUT_TELEPORT_CONTROL : - (temp_rand == 15) ? MUT_MAGIC_RESISTANCE : - (temp_rand == 14) ? MUT_FAST : - (temp_rand == 13) ? MUT_ACUTE_VISION : - (temp_rand == 12) ? MUT_GREEN_SCALES : - (temp_rand == 11) ? MUT_BLACK_SCALES : - (temp_rand == 10) ? MUT_GREY_SCALES : - (temp_rand == 9) ? MUT_BONEY_PLATES : - (temp_rand == 8) ? MUT_REPULSION_FIELD : - (temp_rand == 7) ? MUT_POISON_RESISTANCE : - (temp_rand == 6) ? MUT_TELEPORT_AT_WILL : - (temp_rand == 5) ? MUT_SPIT_POISON : - (temp_rand == 4) ? MUT_MAPPING : - (temp_rand == 3) ? MUT_BREATHE_FLAMES : - (temp_rand == 2) ? MUT_BLINK : - (temp_rand == 1) ? MUT_CLARITY - : MUT_ROBUST); - - return (mutate(which_good_one, failMsg)); -} // end give_good_mutation() - bool give_bad_mutation(bool forceMutation, bool failMsg) { int temp_rand = 0; // probability determination {dlb} @@ -2261,10 +2304,7 @@ bool give_bad_mutation(bool forceMutation, bool failMsg) (temp_rand == 1) ? MUT_BLURRY_VISION : MUT_FRAIL); - if (forceMutation) - which_bad_one += 1000; - - return (mutate(which_bad_one), failMsg); + return mutate(which_bad_one, failMsg, forceMutation); } // end give_bad_mutation() //jmf: might be useful somewhere (eg Xom or transmigration effect) diff --git a/crawl-ref/source/mutation.h b/crawl-ref/source/mutation.h index 771db44c6a..f7f2b27d93 100644 --- a/crawl-ref/source/mutation.h +++ b/crawl-ref/source/mutation.h @@ -22,7 +22,8 @@ * called from: acr - decks - effects - fight - food - it_use2 - items - * mutation - religion - spell - spells * *********************************************************************** */ -bool mutate(int which_mutation, bool failMsg = true); +bool mutate(int which_mutation, bool failMsg = true, + bool force_mutation = false, bool demonspawn = false); // last updated 12may2000 {dlb} @@ -49,12 +50,6 @@ bool delete_mutation(int which_mutation); const char *mutation_name( int which_mutat, int level = -1 ); -// last updated 12may2000 {dlb} -/* *********************************************************************** - * called from: religion - * *********************************************************************** */ -bool give_good_mutation( bool failMsg = true ); - // last updated 12may2000 {dlb} /* *********************************************************************** * called from: items - religion diff --git a/crawl-ref/source/newgame.cc b/crawl-ref/source/newgame.cc index 4d5f9b1a99..9664539d70 100644 --- a/crawl-ref/source/newgame.cc +++ b/crawl-ref/source/newgame.cc @@ -4571,7 +4571,6 @@ void give_items_skills() break; case JOB_CHAOS_KNIGHT: - you.piety = 25; // irrelevant for Xom, of course you.inv[0].quantity = 1; you.inv[0].base_type = OBJ_WEAPONS; you.inv[0].sub_type = WPN_SHORT_SWORD; @@ -4665,9 +4664,20 @@ void give_items_skills() } if (you.religion == GOD_XOM) + { you.skills[SK_FIGHTING]++; - else // you.religion == GOD_MAKHLEB + // the new (piety-aware) Xom uses piety in his own special way... + // (namely, 100 is neutral) + you.piety = 100; + // the new (piety-aware) Xom uses gift_timeout in his own special + // way... (namely, a countdown to becoming bored) + you.gift_timeout = random2(40) + random2(40); + } + else // Makhleb + { + you.piety = 25; you.skills[SK_INVOCATIONS] = 2; + } break; diff --git a/crawl-ref/source/notes.cc b/crawl-ref/source/notes.cc index 9fe1b9e0b3..3ea3d44edc 100644 --- a/crawl-ref/source/notes.cc +++ b/crawl-ref/source/notes.cc @@ -255,16 +255,20 @@ std::string Note::describe( bool when, bool where, bool what ) const << spell_title(static_cast(first)); break; case NOTE_GET_GOD: - result << "Became a worshipper of " << god_name(first, true); + result << "Became a worshipper of " + << god_name(static_cast(first), true); break; case NOTE_LOSE_GOD: - result << "Fell from the grace of " << god_name(first); + result << "Fell from the grace of " + << god_name(static_cast(first)); break; case NOTE_MOLLIFY_GOD: - result << "Was forgiven by " << god_name(first); + result << "Was forgiven by " + << god_name(static_cast(first)); break; case NOTE_GOD_GIFT: - result << "Received a gift from " << god_name(first); + result << "Received a gift from " + << god_name(static_cast(first)); break; case NOTE_ID_ITEM: result << "Identified " << name; @@ -288,7 +292,8 @@ std::string Note::describe( bool when, bool where, bool what ) const result << name << " changed form"; break; case NOTE_GOD_POWER: - result << "Acquired " << god_name(first) << "'s " + result << "Acquired " + << god_name(static_cast(first)) << "'s " << number_to_ordinal(real_god_power(first, second)+1) << " power"; break; diff --git a/crawl-ref/source/ouch.cc b/crawl-ref/source/ouch.cc index 0c3721f596..ae8d6b7c84 100644 --- a/crawl-ref/source/ouch.cc +++ b/crawl-ref/source/ouch.cc @@ -62,7 +62,9 @@ #include "itemprop.h" #include "items.h" #include "macro.h" +#include "misc.h" #include "mon-util.h" +#include "monstuff.h" #include "notes.h" #include "player.h" #include "randart.h" @@ -126,6 +128,7 @@ int check_your_resists(int hurted, int flavour) else if (resist < 0) { mpr("It burns terribly!"); + xom_is_stimulated(200); hurted *= 15; hurted /= 10; } @@ -141,6 +144,7 @@ int check_your_resists(int hurted, int flavour) else if (resist < 0) { mpr("You feel a terrible chill!"); + xom_is_stimulated(200); hurted *= 15; hurted /= 10; } @@ -213,6 +217,7 @@ int check_your_resists(int hurted, int flavour) else if (resist < 0) { mpr("You feel a painful chill!"); + xom_is_stimulated(200); hurted *= 13; hurted /= 10; } @@ -229,6 +234,7 @@ int check_your_resists(int hurted, int flavour) else if (resist < 0) { mpr("It burns terribly!"); + xom_is_stimulated(200); hurted *= 15; hurted /= 10; } @@ -420,6 +426,7 @@ void item_corrode( int itco ) if (!it_resists) { how_rusty--; + xom_is_stimulated(64); if (item.base_type == OBJ_WEAPONS) item.plus2 = how_rusty; @@ -538,6 +545,8 @@ static void expose_invent_to_element( beam_type flavour, int strength ) (num_dest > 1) ? "were" : "was" ); break; } + + xom_is_stimulated((num_dest > 1) ? 32 : 16); } } @@ -602,6 +611,7 @@ void lose_level(void) take_note(Note(NOTE_XP_LEVEL_CHANGE, you.experience_level, 0, buf)); you.redraw_experience = 1; + xom_is_stimulated(255); } // end lose_level() void drain_exp(void) @@ -646,6 +656,7 @@ void drain_exp(void) if (exp_drained > 0) { mpr("You feel drained."); + xom_is_stimulated(20); you.experience -= exp_drained; you.exp_available -= exp_drained; @@ -663,6 +674,60 @@ void drain_exp(void) } } // end drain_exp() +static void xom_checks_damage(kill_method_type death_type, + int dam, int death_source) +{ + //if (you.hp <= dam) + // xom_is_stimulated(32); + + if ((death_type != KILLED_BY_MONSTER && death_type != KILLED_BY_BEAM) + || death_source < 0 || death_source >= MAX_MONSTERS) + { + return ; + } + + int amusementvalue = 1; + + const monsters *monster = &menv[death_source]; + + if (!monster->alive()) + return; + + int leveldif = monster->hit_dice - you.experience_level; + + if (leveldif == 0) + leveldif = 1; + + /* Note that Xom is amused when you are significantly hurt + * by a creature of higher level than yourself as well as + * by a creatured of lower level than yourself. */ + amusementvalue += leveldif * leveldif * dam; + + if (!player_monster_visible(monster)) + amusementvalue += 10; + + if (monster->speed < (int) player_movement_speed()) + amusementvalue += 8; + + if (death_type != KILLED_BY_BEAM) + { + if (you.skills[SK_RANGED_COMBAT] <= (you.experience_level / 4)) + amusementvalue += 2; + } + else + { + if (you.skills[SK_FIGHTING] <= (you.experience_level / 4)) + amusementvalue += 2; + } + + if (player_in_a_dangerous_place()) + amusementvalue += 2; + + amusementvalue /= (you.hp > 0) ? you.hp : 1; + + xom_is_stimulated(amusementvalue); +} + // death_source should be set to zero for non-monsters {dlb} void ouch( int dam, int death_source, kill_method_type death_type, const char *aux ) @@ -688,15 +753,6 @@ void ouch( int dam, int death_source, kill_method_type death_type, { switch (you.religion) { - case GOD_XOM: - if (random2(you.hp_max) > you.hp && dam > random2(you.hp) - && one_chance_in(5)) - { - simple_god_message( " protects you from harm!" ); - return; - } - break; - case GOD_ZIN: case GOD_SHINING_ONE: case GOD_ELYVILON: @@ -718,13 +774,20 @@ void ouch( int dam, int death_source, kill_method_type death_type, // Even if we have low HP messages off, we'll still give a // big hit warning (in this case, a hit for half our HPs) -- bwr if (dam > 0 && you.hp_max <= dam * 2) - mpr( "Ouch! That really hurt!", MSGCH_DANGER ); + mpr( "Ouch! That really hurt!", MSGCH_DANGER ); - if (you.hp > 0 && Options.hp_warning - && you.hp <= (you.hp_max * Options.hp_warning) / 100) + if (you.hp > 0) { - mpr( "* * * LOW HITPOINT WARNING * * *", MSGCH_DANGER ); + if (Options.hp_warning + && you.hp <= (you.hp_max * Options.hp_warning) / 100) + { + mpr( "* * * LOW HITPOINT WARNING * * *", MSGCH_DANGER ); + } + + xom_checks_damage(death_type, dam, death_source); + return; } + take_note( Note( NOTE_HP_CHANGE, @@ -734,8 +797,6 @@ void ouch( int dam, int death_source, kill_method_type death_type, .death_description(scorefile_entry::DDV_TERSE) .c_str()) ); - if (you.hp > 0) - return; } #ifdef WIZARD diff --git a/crawl-ref/source/player.cc b/crawl-ref/source/player.cc index b6eefa1aee..ccb9e67f32 100644 --- a/crawl-ref/source/player.cc +++ b/crawl-ref/source/player.cc @@ -2792,9 +2792,8 @@ void level_change(void) you.hp, you.hp_max, you.magic_points, you.max_magic_points); take_note(Note(NOTE_XP_LEVEL_CHANGE, you.experience_level, 0, buf)); - if (you.religion == GOD_XOM) - Xom_acts(true, you.experience_level, true); - + xom_is_stimulated(16); + learned_something_new(TUT_NEW_LEVEL); } @@ -4221,10 +4220,10 @@ void contaminate_player(int change, bool statusOnly) (change > 0) ? "more" : "less" ); } -void poison_player( int amount, bool force ) +bool poison_player( int amount, bool force ) { if ((!force && player_res_poison()) || amount <= 0) - return; + return false; const int old_value = you.poisoning; you.poisoning += amount; @@ -4238,6 +4237,7 @@ void poison_player( int amount, bool force ) mprf("You are %spoisoned.", (old_value > 0) ? "more " : "" ); learned_something_new(TUT_YOU_POISON); } + return true; } void reduce_poison_player( int amount ) @@ -4280,6 +4280,8 @@ void confuse_player( int amount, bool resistable ) // XXX: which message channel for this message? mprf("You are %sconfused.", (old_value > 0) ? "more " : "" ); learned_something_new(TUT_YOU_ENCHANTED); + + xom_is_stimulated(you.conf - old_value); } } @@ -4392,9 +4394,9 @@ void dec_haste_player( void ) } } -void disease_player( int amount ) +bool disease_player( int amount ) { - you.sicken(amount); + return you.sicken(amount); } void dec_disease_player( void ) @@ -5111,7 +5113,7 @@ void player::blink() void player::teleport(bool now, bool abyss_shift) { if (now) - you_teleport2(true, abyss_shift); + you_teleport_now(true, abyss_shift); else you_teleport(); } @@ -5127,12 +5129,6 @@ void player::hurt(const actor *agent, int amount) ASSERT(false); ouch(amount, 0, KILLED_BY_SOMETHING); } - - if (religion == GOD_XOM && hp <= hp_max / 3 - && one_chance_in(10)) - { - Xom_acts(true, experience_level, false); - } } void player::drain_stat(int stat, int amount) @@ -5196,16 +5192,18 @@ kill_category player::kill_alignment() const return (KC_YOU); } -void player::sicken(int amount) +bool player::sicken(int amount) { if (is_undead || amount <= 0) - return; + return (false); mpr( "You feel ill." ); const int tmp = disease + amount; disease = (tmp > 210) ? 210 : tmp; - learned_something_new(TUT_YOU_SICK); + learned_something_new(TUT_YOU_SICK); + + return (true); } bool player::can_see_invisible() const diff --git a/crawl-ref/source/player.h b/crawl-ref/source/player.h index 9a578f4d7a..2fab29c4a6 100644 --- a/crawl-ref/source/player.h +++ b/crawl-ref/source/player.h @@ -386,7 +386,8 @@ const char *get_class_name( int which_job ); * *********************************************************************** */ void contaminate_player(int change, bool statusOnly = false); -void poison_player( int amount, bool force = false ); +/* @return true iff they were poisoned (false if they are immune) */ +bool poison_player( int amount, bool force = false ); void reduce_poison_player( int amount ); void confuse_player( int amount, bool resistable = true ); @@ -398,7 +399,8 @@ void dec_slow_player(); void haste_player( int amount ); void dec_haste_player(); -void disease_player( int amount ); +/* return true iff they were diseased */ +bool disease_player( int amount ); void dec_disease_player(); void rot_player( int amount ); diff --git a/crawl-ref/source/religion.cc b/crawl-ref/source/religion.cc index 8701400c2a..a88c6081b0 100644 --- a/crawl-ref/source/religion.cc +++ b/crawl-ref/source/religion.cc @@ -50,6 +50,7 @@ #include "makeitem.h" #include "misc.h" #include "monplace.h" +#include "monstuff.h" #include "mutation.h" #include "newgame.h" #include "notes.h" @@ -66,7 +67,8 @@ #include "tutorial.h" #include "view.h" -const char *sacrifice[] = { +const char *sacrifice[] = +{ // Zin " glows silver and disappears.", // TSO @@ -257,7 +259,7 @@ const char* god_lose_power_messages[MAX_NUM_GODS][MAX_GOD_ABILITIES] = void altar_prayer(void); void dec_penance(int god, int val); -void divine_retribution(int god); +void divine_retribution(god_type god); void inc_penance(int god, int val); void inc_penance(int val); @@ -279,7 +281,7 @@ static bool is_good_god(god_type god) god == GOD_ELYVILON; } -void dec_penance(int god, int val) +void dec_penance(god_type god, int val) { if (you.penance[god] > 0) { @@ -419,7 +421,7 @@ static void do_god_gift() && !grid_destroys_items(grd[you.x_pos][you.y_pos])) { int thing_created = NON_ITEM; - unsigned char gift_type = MISC_DECK_OF_TRICKS; + int gift_type = MISC_DECK_OF_TRICKS; if (random2(200) <= you.piety && one_chance_in(4)) gift_type = MISC_DECK_OF_SUMMONINGS; @@ -429,7 +431,7 @@ static void do_god_gift() gift_type = MISC_DECK_OF_POWER; thing_created = items( 1, OBJ_MISCELLANY, gift_type, - true, 1, 250 ); + true, 1, MAKE_ITEM_RANDOM_RACE ); if (thing_created != NON_ITEM) { @@ -500,7 +502,7 @@ static void do_god_gift() int thing_called = random_undead_servant(GOD_YREDELEMNUL); if (create_monster( thing_called, 0, BEH_FRIENDLY, you.x_pos, you.y_pos, - you.pet_target, 250 ) != -1) + you.pet_target, MAKE_ITEM_RANDOM_RACE ) != -1) { simple_god_message(" grants you an undead servant!"); more(); @@ -567,7 +569,8 @@ static void do_god_gift() success = acquirement(OBJ_BOOKS, you.religion); else { - int thing_created = items(1, OBJ_BOOKS, gift, true, 1, 250); + int thing_created = items(1, OBJ_BOOKS, gift, true, 1, + MAKE_ITEM_RANDOM_RACE); if (thing_created == NON_ITEM) return; @@ -684,26 +687,7 @@ void pray() } else if (you.religion == GOD_XOM) { - if (one_chance_in(100)) - { - // Every now and then, Xom listens - // This is for flavour, not effect, so praying should not be - // encouraged. - - // Xom is nicer to experienced players - bool nice = (27 <= random2( 27 + you.experience_level )); - - // and he's not very nice even then - int sever = (nice) ? random2( random2( you.experience_level ) ) - : you.experience_level; - - // bad results are enforced, good are not - bool force = !nice; - - Xom_acts( nice, 1 + sever, force ); - } - else - mpr("Xom ignores you."); + mpr("Xom ignores you."); return; } @@ -743,7 +727,7 @@ void pray() do_god_gift(); } // end pray() -char *god_name( int which_god, bool long_name ) // mv - rewritten +const char *god_name( god_type which_god, bool long_name ) // mv - rewritten { static char godname_buff[80]; @@ -873,405 +857,11 @@ char *god_name( int which_god, bool long_name ) // mv - rewritten return (godname_buff); } // end god_name() -void god_speaks( int god, const char *mesg ) +void god_speaks( god_type god, const char *mesg ) { mpr( mesg, MSGCH_GOD, god ); } // end god_speaks() -void Xom_acts(bool niceness, int sever, bool force_sever) -{ - // niceness = false - bad, true - nice - int temp_rand; // probability determination {dlb} - bool done_bad = false; // flag to clarify logic {dlb} - bool done_good = false; // flag to clarify logic {dlb} - - struct bolt beam; - - if (sever < 1) - sever = 1; - - if (!force_sever) - sever = random2(sever); - - if (sever == 0) - return; - - okay_try_again: - - if (!niceness || one_chance_in(3)) - { - // begin "Bad Things" - done_bad = false; - - // this should always be first - it will often be called - // deliberately, with a low sever value - if (random2(sever) <= 2) - { - temp_rand = random2(4); - - god_speaks(GOD_XOM, - (temp_rand == 0) ? "Xom notices you." : - (temp_rand == 1) ? "Xom's attention turns to you for a moment.": - (temp_rand == 2) ? "Xom's power touches on you for a moment." - : "You hear Xom's maniacal laughter."); - - miscast_effect( SPTYP_RANDOM, 5 + random2(10), random2(100), 0, - "the capriciousness of Xom" ); - - done_bad = true; - } - else if (random2(sever) <= 2) - { - temp_rand = random2(4); - - god_speaks(GOD_XOM, - (temp_rand == 0) ? "\"Suffer!\"" : - (temp_rand == 1) ? "Xom's malign attention turns to you for a moment." : - (temp_rand == 2) ? "Xom's power touches on you for a moment." - : "You hear Xom's maniacal laughter."); - - lose_stat(STAT_RANDOM, 1 + random2(3), true); - - done_bad = true; - } - else if (random2(sever) <= 2) - { - temp_rand = random2(4); - - god_speaks(GOD_XOM, - (temp_rand == 0) ? "Xom notices you." : - (temp_rand == 1) ? "Xom's attention turns to you for a moment.": - (temp_rand == 2) ? "Xom's power touches on you for a moment." - : "You hear Xom's maniacal laughter."); - - miscast_effect( SPTYP_RANDOM, 5 + random2(15), random2(250), 0, - "the capriciousness of Xom" ); - - done_bad = true; - } - else if (!you.is_undead && random2(sever) <= 3) - { - temp_rand = random2(4); - - god_speaks(GOD_XOM, - (temp_rand == 0) ? "\"You need some minor adjustments, mortal!\"" : - (temp_rand == 1) ? "\"Let me alter your pitiful body.\"" : - (temp_rand == 2) ? "Xom's power touches on you for a moment." - : "You hear Xom's maniacal laughter."); - - mpr("Your body is suffused with distortional energy."); - - set_hp(1 + random2(you.hp), false); - deflate_hp(you.hp_max / 2, true); - - bool failMsg = true; - for (int i = 0; i < 4; i++) - { - if (!mutate(100, failMsg)) - failMsg = false; - } - - done_bad = true; - } - else if (!you.is_undead && random2(sever) <= 3) - { - temp_rand = random2(4); - - god_speaks(GOD_XOM, - (temp_rand == 0) ? "\"You have displeased me, mortal.\"" : - (temp_rand == 1) ? "\"You have grown too confident for your meagre worth.\"" : - (temp_rand == 2) ? "Xom's power touches on you for a moment." - : "You hear Xom's maniacal laughter."); - - if (one_chance_in(4)) - { - drain_exp(); - if (random2(sever) > 3) - drain_exp(); - if (random2(sever) > 3) - drain_exp(); - } - else - { - mpr("A wave of agony tears through your body!"); - set_hp(1 + (you.hp / 2), false); - } - - done_bad = true; - } - else if (random2(sever) <= 3) - { - temp_rand = random2(4); - - god_speaks(GOD_XOM, - (temp_rand == 0) ? "\"Time to have some fun!\"" : - (temp_rand == 1) ? "\"Fight to survive, mortal.\"" : - (temp_rand == 2) ? "\"Let's see if it's strong enough to survive yet.\"" - : "You hear Xom's maniacal laughter."); - - if (one_chance_in(4) && (you.equip[EQ_WEAPON] != -1) ) - dancing_weapon(100, true); // nasty, but fun - else - { - create_monster(MONS_NEQOXEC + random2(5), 3, - BEH_HOSTILE, you.x_pos, you.y_pos, MHITNOT, 250); - - if (one_chance_in(3)) - create_monster(MONS_NEQOXEC + random2(5), 3, - BEH_HOSTILE, you.x_pos, you.y_pos, MHITNOT, 250); - - if (one_chance_in(4)) - create_monster(MONS_NEQOXEC + random2(5), 3, - BEH_HOSTILE, you.x_pos, you.y_pos, MHITNOT, 250); - - if (one_chance_in(3)) - create_monster(MONS_HELLION + random2(10), 3, - BEH_HOSTILE, you.x_pos, you.y_pos, MHITNOT, 250); - - if (one_chance_in(4)) - create_monster(MONS_HELLION + random2(10), 3, - BEH_HOSTILE, you.x_pos, you.y_pos, MHITNOT, 250); - } - - done_bad = true; - } - else if (you.your_level == 0) - { - // this should remain the last possible outcome {dlb} - temp_rand = random2(3); - - god_speaks(GOD_XOM, - (temp_rand == 0) ? "\"You have grown too comfortable in your little world, mortal!\"" : - (temp_rand == 1) ? "Xom casts you into the Abyss!" - : "The world seems to spin as Xom's maniacal laughter rings in your ears."); - - banished(DNGN_ENTER_ABYSS, "Xom"); - - done_bad = true; - } - } // end "Bad Things" - else - { - // begin "Good Things" - done_good = false; - -// Okay, now for the nicer stuff (note: these things are not necessarily nice): - if (random2(sever) <= 2) - { - temp_rand = random2(4); - - god_speaks(GOD_XOM, - (temp_rand == 0) ? "\"Go forth and destroy!\"" : - (temp_rand == 1) ? "\"Go forth and destroy, mortal!\"" : - (temp_rand == 2) ? "Xom grants you a minor favour." - : "Xom smiles on you."); - - switch (random2(7)) - { - case 0: - potion_effect(POT_HEALING, 150); - break; - case 1: - potion_effect(POT_HEAL_WOUNDS, 150); - break; - case 2: - potion_effect(POT_SPEED, 150); - break; - case 3: - potion_effect(POT_MIGHT, 150); - break; - case 4: - potion_effect(POT_INVISIBILITY, 150); - break; - case 5: - if (one_chance_in(6)) - potion_effect(POT_EXPERIENCE, 150); - else - { - you.berserk_penalty = NO_BERSERK_PENALTY; - potion_effect(POT_BERSERK_RAGE, 150); - } - break; - case 6: - you.berserk_penalty = NO_BERSERK_PENALTY; - potion_effect(POT_BERSERK_RAGE, 150); - break; - } - - done_good = true; - } - else if (random2(sever) <= 4) - { - temp_rand = random2(3); - - god_speaks(GOD_XOM, - (temp_rand == 0) ? "\"Serve the mortal, my children!\"" : - (temp_rand == 1) ? "Xom grants you some temporary aid." - : "Xom opens a gate."); - - create_monster( MONS_NEQOXEC + random2(5), 3, - BEH_FRIENDLY, you.x_pos, you.y_pos, - you.pet_target, 250 ); - - create_monster( MONS_NEQOXEC + random2(5), 3, - BEH_FRIENDLY, you.x_pos, you.y_pos, - you.pet_target, 250 ); - - if (random2( you.experience_level ) >= 8) - { - create_monster( MONS_NEQOXEC + random2(5), 3, - BEH_FRIENDLY, you.x_pos, you.y_pos, - you.pet_target, 250 ); - } - - if (random2( you.experience_level ) >= 8) - { - create_monster( MONS_HELLION + random2(10), 3, - BEH_FRIENDLY, you.x_pos, you.y_pos, - you.pet_target, 250 ); - } - - if (random2( you.experience_level ) >= 8) - { - create_monster( MONS_HELLION + random2(10), 3, - BEH_FRIENDLY, you.x_pos, you.y_pos, - you.pet_target, 250 ); - } - - done_good = true; - } - else if (random2(sever) <= 3) - { - temp_rand = random2(3); - - god_speaks(GOD_XOM, - (temp_rand == 0) ? "\"Take this token of my esteem.\"" : - (temp_rand == 1) ? "Xom grants you a gift!" - : "Xom's generous nature manifests itself."); - - if (grid_destroys_items(grd[you.x_pos][you.y_pos])) { - // How unfortunate. I'll bet Xom feels sorry for you. - mprf(MSGCH_SOUND, - grid_item_destruction_message(grd[you.x_pos][you.y_pos])); - } - else - { - int thing_created = items(1, OBJ_RANDOM, OBJ_RANDOM, true, - you.experience_level * 3, 250); - - move_item_to_grid( &thing_created, you.x_pos, you.y_pos ); - - if (thing_created != NON_ITEM) - { - origin_acquired(mitm[thing_created], GOD_XOM); - canned_msg(MSG_SOMETHING_APPEARS); - more(); - } - } - - done_good = true; - } - else if (random2(sever) <= 4) - { - const int demon = (random2(you.experience_level) < 6) - ? MONS_WHITE_IMP + random2(5) - : MONS_NEQOXEC + random2(5); - - if (create_monster( demon, 0, BEH_FRIENDLY, you.x_pos, you.y_pos, - you.pet_target, 250 ) != -1) - { - temp_rand = random2(3); - - god_speaks(GOD_XOM, - (temp_rand == 0) ? "\"Serve the mortal, my child!\"" : - (temp_rand == 1) ? "Xom grants you a demonic servitor." - : "Xom opens a gate."); - } - else - { - god_speaks(GOD_XOM, "You hear Xom cackling."); - } - - done_good = true; // well, for Xom, trying == doing {dlb} - } - else if (random2(sever) <= 4) - { - temp_rand = random2(4); - - god_speaks(GOD_XOM, - (temp_rand == 0) ? "\"Take this instrument of destruction!\"" : - (temp_rand == 1) ? "\"You have earned yourself a gift.\"" : - (temp_rand == 2) ? "Xom grants you an implement of death." - : "Xom smiles on you."); - - if (acquirement(OBJ_WEAPONS, GOD_XOM)) - more(); - - done_good = true; - } - else if (!you.is_undead && random2(sever) <= 5) - { - temp_rand = random2(4); - - god_speaks(GOD_XOM, - (temp_rand == 0) ? "\"You need some minor adjustments, mortal!\"" : - (temp_rand == 1) ? "\"Let me alter your pitiful body.\"" : - (temp_rand == 2) ? "Xom's power touches on you for a moment." - : "You hear Xom's maniacal chuckling."); - - mpr("Your body is suffused with distortional energy."); - - set_hp(1 + random2(you.hp), false); - deflate_hp(you.hp_max / 2, true); - - if (coinflip() || !give_cosmetic_mutation()) - give_good_mutation(); - - done_good = true; - } - else if (random2(sever) <= 2) - { - // this should remain the last possible outcome {dlb} - if (!one_chance_in(8)) - you.attribute[ATTR_DIVINE_LIGHTNING_PROTECTION] = 1; - - god_speaks(GOD_XOM, "The area is suffused with divine lightning!"); - - beam.beam_source = NON_MONSTER; - beam.type = SYM_BURST; - beam.damage = dice_def( 3, 30 ); - beam.flavour = BEAM_ELECTRICITY; - beam.target_x = you.x_pos; - beam.target_y = you.y_pos; - beam.name = "blast of lightning"; - beam.colour = LIGHTCYAN; - beam.thrower = KILL_MISC; - beam.aux_source = "Xom's lightning strike"; - beam.ex_size = 2; - beam.is_tracer = false; - beam.is_explosion = true; - - explosion(beam); - - if (you.attribute[ATTR_DIVINE_LIGHTNING_PROTECTION] == 1) - { - mpr("Your divine protection wanes."); - you.attribute[ATTR_DIVINE_LIGHTNING_PROTECTION] = 0; - } - - done_good = true; - } - } // end "Good Things" - - if (done_bad || done_good ) - return; - if ( one_chance_in(4) ) { - god_speaks(GOD_XOM, "Xom's attention is distracted from you."); - return; - } - goto okay_try_again; -} // end Xom_acts() - // This function is the merger of done_good() and naughty(). // Returns true if god was interested (good or bad) in conduct. bool did_god_conduct( int thing_done, int level ) @@ -1674,8 +1264,12 @@ bool did_god_conduct( int thing_done, int level ) return (ret); } -void gain_piety(char pgn) +void gain_piety(int pgn) { + // Xom uses piety differently... + if (you.religion == GOD_XOM) + return; + // check to see if we owe anything first if (you.penance[you.religion] > 0) { @@ -1750,7 +1344,7 @@ void gain_piety(char pgn) do_god_gift(); } -void lose_piety(char pgn) +void lose_piety(int pgn) { int old_piety = you.piety; @@ -1791,7 +1385,7 @@ void lose_piety(char pgn) } } -static void lugonu_retribution(int god) +static void lugonu_retribution(god_type god) { if (coinflip()) { @@ -1806,7 +1400,7 @@ static void lugonu_retribution(int god) simple_god_message("'s wrath finds you!", god); mpr("Space warps around you!"); if (!one_chance_in(3)) - you_teleport2(false); + you_teleport_now(false); else random_blink(false); @@ -1848,7 +1442,7 @@ static void lugonu_retribution(int god) } } -void divine_retribution( int god ) +void divine_retribution( god_type god ) { ASSERT(god != GOD_NO_GOD); @@ -1874,14 +1468,8 @@ void divine_retribution( int god ) switch (god) { case GOD_XOM: - { - // One in ten chance that Xom might do something good... - // but that isn't forced, bad things are though - bool nice = one_chance_in(10); - bool force = !nice; - - Xom_acts(nice, you.experience_level, force); - } + // One in ten chance that Xom might do something good... + xom_acts(one_chance_in(10), abs(you.piety - 100)); break; case GOD_SHINING_ONE: @@ -2343,7 +1931,7 @@ void divine_retribution( int god ) void excommunication(void) { - const int old_god = you.religion; + const god_type old_god = you.religion; take_note(Note(NOTE_LOSE_GOD, old_god)); @@ -2358,7 +1946,7 @@ void excommunication(void) switch (old_god) { case GOD_XOM: - Xom_acts( false, (you.experience_level * 2), true ); + xom_acts( false, abs(you.piety - 100) * 2); inc_penance( old_god, 50 ); break; @@ -2613,7 +2201,7 @@ void offer_items() } } -void god_pitch(unsigned char which_god) +void god_pitch(god_type which_god) { mprf("You kneel at the altar of %s.", god_name(which_god)); more(); @@ -2660,8 +2248,19 @@ void god_pitch(unsigned char which_god) //jmf: moved up so god_speaks gives right colour you.religion = static_cast(which_god); - you.piety = 15; // to prevent near instant excommunication - you.gift_timeout = 0; + + if (you.religion == GOD_XOM) + { + // Xom uses piety and gift_timeout differently. + you.piety = 100; + you.gift_timeout = random2(40) + random2(40); + } + else + { + you.piety = 15; // to prevent near instant excommunication + you.gift_timeout = 0; + } + set_god_ability_slots(); // remove old god's slots, reserve new god's #ifdef DGL_WHEREIS whereis_record(); @@ -2742,7 +2341,7 @@ void handle_god_time(void) // why we do it this way... it requires only one pass and doesn't // require an array. - int which_god = GOD_NO_GOD; + god_type which_god = GOD_NO_GOD; unsigned int count = 0; for (int i = GOD_NO_GOD; i < NUM_GODS; i++) @@ -2751,7 +2350,7 @@ void handle_god_time(void) { count++; if (one_chance_in(count)) - which_god = i; + which_god = static_cast(i); } } @@ -2765,9 +2364,47 @@ void handle_god_time(void) switch (you.religion) { case GOD_XOM: - if (one_chance_in(75)) - Xom_acts(true, you.experience_level + random2(15), true); + { + // Xom semi-randomly drifts your piety. + int delta; + const char *origfavour = describe_xom_favour(); + const bool good = you.piety >= 100; + int size = abs(you.piety - 100); + delta = (random2(1000) < 511) ? 1 : -1; + size += delta; + you.piety = 100 + (good ? size : -size); + const char *newfavour = describe_xom_favour(); + if (strcmp(origfavour, newfavour)) + { + // Dampen oscillation across announcement boundaries: + size += delta * 2; + you.piety = 100 + (good ? size : -size); + } + + // ... but he gets bored... (I re-use gift_timeout for + // this instead of making a separate field because I don't + // want to learn how to save and restore a new field). In + // this usage, the "gift" is the gift you give to Xom of + // something interesting happening. + if (you.gift_timeout == 1) + { + mpr("Xom is getting BORED."); + you.gift_timeout = 0; + } + else if (you.gift_timeout > 1) + { + you.gift_timeout -= random2(2); + } + + if (one_chance_in(20)) + { + // If you.gift_timeout was == 0, then Xom was BORED. + // He HATES that. + xom_acts(you.gift_timeout > 0 && you.piety > 100, + abs(you.piety - 100)); + } break; + } case GOD_ZIN: // These gods like long-standing worshippers case GOD_ELYVILON: @@ -2831,7 +2468,7 @@ void handle_god_time(void) } // end handle_god_time() // yet another wrapper for mpr() {dlb}: -void simple_god_message(const char *event, int which_deity) +void simple_god_message(const char *event, god_type which_deity) { char buff[ INFO_SIZE ]; @@ -2843,7 +2480,7 @@ void simple_god_message(const char *event, int which_deity) god_speaks( which_deity, buff ); } -char god_colour( char god ) //mv - added +int god_colour( god_type god ) //mv - added { switch (god) { diff --git a/crawl-ref/source/religion.h b/crawl-ref/source/religion.h index 5272a1383e..02c85d2494 100644 --- a/crawl-ref/source/religion.h +++ b/crawl-ref/source/religion.h @@ -16,24 +16,33 @@ #include "enum.h" -void simple_god_message( const char *event, int which_deity = GOD_NO_GOD ); +void simple_god_message( const char *event, god_type which_deity = GOD_NO_GOD ); int piety_breakpoint(int i); -char *god_name(int which_god,bool long_name=false); //mv +const char *god_name(god_type which_god, bool long_name = false); //mv void dec_penance(int val); -void dec_penance(int god, int val); -void Xom_acts(bool niceness, int sever, bool force_sever); +void dec_penance(god_type god, int val); bool did_god_conduct(int thing_done, int pgain); void excommunication(void); -void gain_piety(char pgn); -void god_speaks( int god, const char *mesg ); -void lose_piety(char pgn); +void gain_piety(int pgn); +void god_speaks(god_type god, const char *mesg ); +void lose_piety(int pgn); void offer_corpse(int corpse); std::string god_prayer_reaction(); void pray(); void handle_god_time(void); -char god_colour(char god); -void god_pitch(unsigned char which_god); +int god_colour(god_type god); +void god_pitch(god_type which_god); int piety_rank(int piety = -1); void offer_items(); +bool xom_is_nice(); +void xom_is_stimulated(int maxinterestingness); +void xom_acts(bool niceness, int sever); +const char *describe_xom_favour(); + +inline void xom_acts(int sever) +{ + xom_acts(xom_is_nice(), sever); +} + #endif diff --git a/crawl-ref/source/spells3.cc b/crawl-ref/source/spells3.cc index a3277a4a17..548aa5de9f 100644 --- a/crawl-ref/source/spells3.cc +++ b/crawl-ref/source/spells3.cc @@ -40,6 +40,7 @@ #include "mon-util.h" #include "player.h" #include "randart.h" +#include "religion.h" #include "spells1.h" #include "spells4.h" #include "spl-cast.h" @@ -590,7 +591,7 @@ void you_teleport(void) return; } // end you_teleport() -void you_teleport2( bool allow_control, bool new_abyss_area ) +static bool teleport_player( bool allow_control, bool new_abyss_area ) { bool is_controlled = (allow_control && !you.conf && player_control_teleport() @@ -599,7 +600,7 @@ void you_teleport2( bool allow_control, bool new_abyss_area ) if (scan_randarts(RAP_PREVENT_TELEPORTATION)) { mpr("You feel a strange sense of stasis."); - return; + return false; } // after this point, we're guaranteed to teleport. Kill the appropriate @@ -616,7 +617,7 @@ void you_teleport2( bool allow_control, bool new_abyss_area ) { abyss_teleport( new_abyss_area ); you.pet_target = MHITNOT; - return; + return true; } FixedVector < int, 2 > plox; @@ -693,7 +694,17 @@ void you_teleport2( bool allow_control, bool new_abyss_area ) || mgrd[you.x_pos][you.y_pos] != NON_MONSTER || env.cgrid[you.x_pos][you.y_pos] != EMPTY_CLOUD); } -} // end you_teleport() + return !is_controlled; +} + +void you_teleport_now( bool allow_control, bool new_abyss_area ) +{ + const bool randtele = teleport_player(allow_control, new_abyss_area); + // Xom is amused by uncontrolled teleports that land you in a + // dangerous place. + if (randtele && player_in_a_dangerous_place()) + xom_is_stimulated(255); +} bool entomb(void) { diff --git a/crawl-ref/source/spells3.h b/crawl-ref/source/spells3.h index 067117f979..a93a91c330 100644 --- a/crawl-ref/source/spells3.h +++ b/crawl-ref/source/spells3.h @@ -139,7 +139,7 @@ void you_teleport(void); /* *********************************************************************** * called from: ability - acr - decks - effects - fight - misc - spells * *********************************************************************** */ -void you_teleport2( bool allow_control, bool new_abyss_area = false ); +void you_teleport_now( bool allow_control, bool new_abyss_area = false ); #endif diff --git a/crawl-ref/source/spl-cast.cc b/crawl-ref/source/spl-cast.cc index 74f17b62c6..9f71de9854 100644 --- a/crawl-ref/source/spl-cast.cc +++ b/crawl-ref/source/spl-cast.cc @@ -909,9 +909,6 @@ spret_type your_spells( spell_type spc2, int powc, bool allow_fail ) miscast_effect( sptype, spell_mana(spc2), spell_fail(spc2) - spfl, 100 ); - if (you.religion == GOD_XOM && random2(75) < spell_mana(spc2)) - Xom_acts(coinflip(), spell_mana(spc2), false); - return (SPRET_FAIL); } } @@ -1899,7 +1896,7 @@ bool miscast_effect( unsigned int sp_type, int mag_pow, int mag_fail, /* sp_type is the type of the spell * mag_pow is overall power of the spell or effect (ie its level) * mag_fail is the degree to which you failed - * force_effect forces a certain effect to occur. Currently unused. + * force_effect forces a certain severity of effect to occur. */ struct bolt beam; bool failMsg = true; @@ -2251,7 +2248,7 @@ bool miscast_effect( unsigned int sp_type, int mag_pow, int mag_fail, mpr("Space warps around you!"); if (one_chance_in(3)) - you_teleport2( true ); + you_teleport_now( true ); else random_blink( false ); @@ -2284,7 +2281,7 @@ bool miscast_effect( unsigned int sp_type, int mag_pow, int mag_fail, break; case 1: mpr("Space warps crazily around you!"); - you_teleport2( true ); + you_teleport_now( true ); ouch(9 + random2avg(17, 2), 0, KILLED_BY_WILD_MAGIC, cause); potion_effect(POT_CONFUSION, 60); @@ -3458,6 +3455,7 @@ bool miscast_effect( unsigned int sp_type, int mag_pow, int mag_fail, break; // end poison } + xom_is_stimulated(spec_effect); return (true); } // end miscast_effect() diff --git a/crawl-ref/source/xom.cc b/crawl-ref/source/xom.cc new file mode 100644 index 0000000000..653c1dc5b1 --- /dev/null +++ b/crawl-ref/source/xom.cc @@ -0,0 +1,844 @@ +/* + * File: xom.cc + * Summary: All things Xomly + * Written by: Zooko + * + * Modified for Crawl Reference by $Author: haranp $ on $Date: 2007-05-15T17:02:30.826843Z $ + */ + +#include "AppHdr.h" + +#include "beam.h" +#include "effects.h" +#include "it_use2.h" +#include "items.h" +#include "makeitem.h" +#include "misc.h" +#include "mon-util.h" +#include "monplace.h" +#include "monstuff.h" +#include "mutation.h" +#include "ouch.h" +#include "player.h" +#include "religion.h" +#include "spells3.h" +#include "spl-cast.h" +#include "stuff.h" +#include "view.h" + +// Which spell? First I copied all spells from you_spells(), then I +// filtered some out (especially conjurations). Then I sorted them in +// roughly ascending order of power. ([ds] Removed SUMMON_GUARDIAN and +// SUMMON_DAEVA which are inappropriate for a god of chaos; need to +// investigate substitutes). +// +static const spell_type xom_spells[] = +{ + SPELL_BLINK, SPELL_CONFUSING_TOUCH, SPELL_MAGIC_MAPPING, + SPELL_DETECT_ITEMS, SPELL_DETECT_CREATURES, SPELL_MASS_CONFUSION, + SPELL_MASS_SLEEP, SPELL_CONTROLLED_BLINK, SPELL_STONESKIN, + SPELL_RING_OF_FLAMES, SPELL_OLGREBS_TOXIC_RADIANCE, + SPELL_TUKIMAS_VORPAL_BLADE, SPELL_FIRE_BRAND, SPELL_FREEZING_AURA, + SPELL_POISON_WEAPON, SPELL_STONEMAIL, SPELL_WARP_BRAND, SPELL_ALTER_SELF, + SPELL_TUKIMAS_DANCE, SPELL_SUMMON_BUTTERFLIES, SPELL_SUMMON_SMALL_MAMMAL, + SPELL_CALL_IMP, SPELL_SUMMON_SCORPIONS, SPELL_FLY, SPELL_SPIDER_FORM, + SPELL_STATUE_FORM, SPELL_ICE_FORM, SPELL_DRAGON_FORM, SPELL_SWARM, + SPELL_SUMMON_WRAITHS, SPELL_SHADOW_CREATURES, SPELL_SUMMON_ELEMENTAL, + SPELL_SUMMON_HORRIBLE_THINGS, SPELL_SUMMON_LARGE_MAMMAL, + SPELL_CONJURE_BALL_LIGHTNING, SPELL_SUMMON_DRAGON, SPELL_DEATH_CHANNEL, + SPELL_NECROMUTATION +}; + +static const char *xom_try_this[] = +{ + "\"Perhaps you should try this instead.\"", + "\"Maybe this would work better.\"", + "\"Catch!\"" +}; + +static const char *xom_try_this_ring[] = +{ + "\"Try this.\"", + "\"Catch!\"", + "\"Take this!\"" +}; + +static const char *xom_try_this_other_thing[] = +{ + "\"Perhaps you should try this instead.\"", + "\"Have you considered using one of these?\"", + "\"How about this?\"" +}; + +static const char *xom_try_these_duds[] = +{ + "\"Perhaps you should try this instead.\"", + "\"Have you considered wearing one of these?\"", + "\"Here you go.\"" +}; + +static const char *xom_generic_beneficence[] = +{ + "Xom grants you a gift!", + "\"Here.\"", + "Xom's generous nature manifests itself.", + "Xom grants you an implement of some kind.", + "\"Take this instrument of something!\"", + "\"Take this token of my esteem.\"", + "Xom smiles on you." +}; + +const char *describe_xom_favour() +{ + return (you.piety > 160) ? "A beloved toy of Xom." : + (you.piety > 145) ? "A favorite toy of Xom." : + (you.piety > 130) ? "A very special toy of Xom." : + (you.piety > 115) ? "A special toy of Xom." : + (you.piety > 100) ? "A toy of Xom." : + (you.piety > 85) ? "A plaything of Xom." : + (you.piety > 70) ? "A special plaything of Xom." : + (you.piety > 55) ? "A very special plaything of Xom." : + (you.piety > 40) ? "A favorite plaything of Xom." : + "A beloved plaything of Xom."; +} + +bool xom_is_nice() +{ + return (you.gift_timeout > 0 && you.piety > 100); +} + +void xom_is_stimulated(int maxinterestingness) +{ + if (you.religion != GOD_XOM) + return; + int interestingness = random2(maxinterestingness); + if (interestingness < 12) + return; + if (interestingness > 255) + interestingness = 255; + if (interestingness > you.gift_timeout) + { + you.gift_timeout = interestingness; + god_speaks(GOD_XOM, + ((interestingness > 200) ? "Xom roars with laughter!" : + (interestingness > 100) ? "Xom thinks this is hilarious!" : + (interestingness > 75) ? "Xom is highly amused!" : + (interestingness > 50) ? "Xom is amused." : + (interestingness > 25) ? "Xom is mildly amused." : + "Xom is interested.")); + } + + if (you.piety < 100 && coinflip()) + you.piety = 200 - you.piety; +} + +void xom_makes_you_cast_random_spell(int sever) +{ + int spellenum = sever; + + const int nxomspells = ARRAYSIZE(xom_spells); + if (spellenum >= nxomspells) + spellenum = nxomspells - 1; + + const spell_type spell = xom_spells[random2(spellenum)]; + + god_speaks(GOD_XOM, "Xom's power flows through you!"); + +#if DEBUG_DIAGNOSTICS + mprf(MSGCH_DIAGNOSTICS, + "Xom_acts();spell: %d, spellenum: %d", spell, spellenum); +#endif + + your_spells(spell, sever, false); +} + +static void xom_make_item(object_class_type base, + int subtype, + int power, + const char *failmsg = "\"No, never mind.\"") +{ + int thing_created = + items(true, base, subtype, true, power, MAKE_ITEM_RANDOM_RACE); + + if (thing_created == NON_ITEM) + { + god_speaks(GOD_XOM, failmsg); + return; + } + + move_item_to_grid( &thing_created, you.x_pos, you.y_pos ); + canned_msg(MSG_SOMETHING_APPEARS); + + origin_acquired(mitm[thing_created], GOD_XOM); +} + +static void xom_suggest(const char **messages, int nmsgs) +{ + if (nmsgs && messages) + { + const char *sel = messages[random2(nmsgs)]; + if (sel) + god_speaks(GOD_XOM, sel); + } +} + +#define XOM_SAY(x) xom_suggest(x, ARRAYSIZE(x)) + +static object_class_type get_unrelated_wield_class(object_class_type ref) +{ + object_class_type objtype = OBJ_WEAPONS; + if (ref == OBJ_WEAPONS) + { + if (random2(10)) + objtype = OBJ_STAVES; + else + objtype = OBJ_MISCELLANY; + } + else if (ref == OBJ_STAVES) + { + if (random2(10)) + objtype = OBJ_WEAPONS; + else + objtype = OBJ_MISCELLANY; + } + else + { + const int temp_rand = random2(3); + objtype = + (temp_rand == 0) ? OBJ_WEAPONS : + (temp_rand == 1) ? OBJ_STAVES : + OBJ_MISCELLANY; + } + return (objtype); +} + +static bool xom_annoyance_gift(int power) +{ + if (coinflip() && player_in_a_dangerous_place()) + { + const item_def *weapon = you.weapon(); + // Xom has a sense of humour. + if (coinflip() && weapon && weapon->cursed()) + { + // If you are wielding a cursed item on then Xom will give + // you an item of that same type. Ha ha! + XOM_SAY(xom_try_this); + if (coinflip()) + // For added humour, give the same sub-type. + xom_make_item(weapon->base_type, weapon->sub_type, power * 3); + else + acquirement(weapon->base_type, GOD_XOM); + return (true); + } + + const item_def *gloves = you.slot_item(EQ_GLOVES); + if (coinflip() && gloves && gloves->cursed()) + { + // If you are wearing cursed gloves then Xom will give you + // a ring. Ha ha! + // + // A random ring. (Not necessarily a good one.) + XOM_SAY(xom_try_this); + xom_make_item(OBJ_JEWELLERY, get_random_ring_type(), power * 3); + return (true); + }; + + const item_def *amulet = you.slot_item(EQ_AMULET); + if (coinflip() && amulet && amulet->cursed()) + { + // If you are wearing a cursed amulet then Xom will give + // you an amulet. Ha ha! + XOM_SAY(xom_try_this); + xom_make_item(OBJ_JEWELLERY, get_random_amulet_type(), power * 3); + return (true); + }; + + const item_def *left_ring = you.slot_item(EQ_LEFT_RING); + const item_def *right_ring = you.slot_item(EQ_RIGHT_RING); + if (coinflip() && ((left_ring && left_ring->cursed()) + || (right_ring && right_ring->cursed()))) + { + // If you are wearing a cursed ring then Xom will give you + // a ring. Ha ha! + XOM_SAY(xom_try_this_ring); + xom_make_item(OBJ_JEWELLERY, get_random_ring_type(), power * 3); + return (true); + } + + if (one_chance_in(5) && weapon) + { + // Xom will give you a wielded item of a type different + // than what you are currently wielding. + XOM_SAY(xom_try_this_other_thing); + + const object_class_type objtype = + get_unrelated_wield_class(weapon->base_type); + + if (power > random2(256)) + acquirement(objtype, GOD_XOM); + else + xom_make_item(objtype, OBJ_RANDOM, power * 3); + return (true); + } + } + return (false); +} + +bool xom_gives_item(int power) +{ + if (xom_annoyance_gift(power)) + return (true); + + const item_def *cloak = you.slot_item(EQ_CLOAK); + if (coinflip() && cloak && cloak->cursed()) + { + // If you are wearing a cursed cloak then Xom will give you a + // cloak or body armour . Ha ha! + XOM_SAY(xom_try_these_duds); + xom_make_item(OBJ_ARMOUR, + random2(10)? + get_random_body_armour_type(you.your_level * 2) + : ARM_CLOAK, + power * 3); + return (true); + } + + XOM_SAY(xom_generic_beneficence); + + // There are two kinds of Xom gifts: acquirement and random + // object. The result from acquirement is very good (usually as + // good or better than random object), and it is sometimes tuned + // to the player's skills and nature. Being tuned to the player's + // skills and nature is not very Xomlike... + if (power > random2(256)) + { + // random-type acquirement + const int r = random2(7); + const object_class_type objtype = (r == 0) ? OBJ_WEAPONS : + (r == 1) ? OBJ_ARMOUR : + (r == 2) ? OBJ_JEWELLERY : + (r == 3) ? OBJ_BOOKS : + (r == 4) ? OBJ_STAVES : + (r == 5) ? OBJ_FOOD : + (r == 6) ? OBJ_MISCELLANY : + OBJ_GOLD; + acquirement(objtype, GOD_XOM); + } + else + { + // random-type random object + xom_make_item(OBJ_RANDOM, OBJ_RANDOM, power * 3); + } + more(); + + return (true); +} + +bool there_are_monsters_nearby() +{ + int ystart = you.y_pos - 9, xstart = you.x_pos - 9; + int yend = you.y_pos + 9, xend = you.x_pos + 9; + if (xstart < 0) xstart = 0; + if (ystart < 0) ystart = 0; + if (xend >= GXM) xend = GXM; + if (ystart >= GYM) yend = GYM; + + /* monster check */ + for ( int y = ystart; y < yend; ++y ) + { + for ( int x = xstart; x < xend; ++x ) + { + /* if you can see a nonfriendly monster then you feel + unsafe */ + if ( see_grid(x,y) ) + { + const int targ_monst = mgrd[x][y]; + if ( targ_monst != NON_MONSTER ) + { + const monsters *mon = &menv[targ_monst]; + if (!mons_is_submerged(mon)) + return (true); + } + } + } + } + return (false); +} + +monsters *get_random_nearby_monster() +{ + monsters *monster = NULL; + /* not particular efficient, but oh well */ + for (int it = 0, num = 0; it < MAX_MONSTERS; it++) + { + monsters *mons = &menv[it]; + if (mons->alive() && mons_near(mons) + && !mons_is_submerged(mons) + && one_chance_in(++num)) + { + monster = mons; + } + } + return (monster); +} + +static bool xom_is_good(int sever) +{ + // niceness = false - bad, true - nice + int temp_rand; // probability determination {dlb} + bool done = false; + + bolt beam; + + // Okay, now for the nicer stuff (note: these things are not + // necessarily nice): + if (random2(sever) <= 1) + { + temp_rand = random2(4); + + god_speaks(GOD_XOM, + (temp_rand == 0) ? "\"Go forth and destroy!\"" : + (temp_rand == 1) ? "\"Go forth and cause havoc, mortal!\"" : + (temp_rand == 2) ? "Xom grants you a minor favour." + : "Xom smiles on you."); + + switch (random2(7)) + { + case 0: + potion_effect(POT_HEALING, 150); + break; + case 1: + potion_effect(POT_HEAL_WOUNDS, 150); + break; + case 2: + potion_effect(POT_SPEED, 150); + break; + case 3: + potion_effect(POT_MIGHT, 150); + break; + case 4: + potion_effect(POT_INVISIBILITY, 150); + break; + case 5: + if (one_chance_in(6)) + potion_effect(POT_EXPERIENCE, 150); + else + { + you.berserk_penalty = NO_BERSERK_PENALTY; + potion_effect(POT_BERSERK_RAGE, 150); + } + break; + case 6: + you.berserk_penalty = NO_BERSERK_PENALTY; + potion_effect(POT_BERSERK_RAGE, 150); + break; + } + + done = true; + } + else if (random2(sever) <= 2) + { + xom_makes_you_cast_random_spell(sever); + done = true; + } + else if (random2(sever) <= 3) + { + temp_rand = random2(3); + + god_speaks(GOD_XOM, + (temp_rand == 0) ? "\"Serve the mortal, my children!\"" : + (temp_rand == 1) ? "Xom grants you some temporary aid." + : "Xom momentarily opens a gate."); + + int i; + int r = random2(random2(random2(sever+1)+1)+1)+2; + int numdemons = MIN(r, 24); + for (i=0; i < numdemons; i++) + { + r = random2(random2(random2(sever))); + int demonnum = MONS_WHITE_IMP + MIN(r, 20); + if (!player_res_poison()) + { + while (demonnum == MONS_GREEN_DEATH) + { + r = random2(random2(random2(sever))); + demonnum = MONS_WHITE_IMP + MIN(r, 20); + } + } + ASSERT (demonnum >= MONS_WHITE_IMP); + ASSERT (demonnum <= MONS_WHITE_IMP+20); + create_monster(demonnum, 3, + BEH_GOD_GIFT, you.x_pos, you.y_pos, + you.pet_target, 250 ); + } + + done = true; + } + else if (random2(sever) <= 4) + { + xom_gives_item(sever); + done = true; + } + else if (random2(sever) <= 5) + { + int r = random2(random2(random2(sever))); + int demonnum = MONS_WHITE_IMP + MIN(r, 20); + ASSERT (demonnum >= MONS_WHITE_IMP); + ASSERT (demonnum <= MONS_WHITE_IMP+20); + if (!player_res_poison()) + { + while (demonnum == MONS_GREEN_DEATH) + { + r = random2(random2(random2(sever))); + demonnum = MONS_WHITE_IMP + MIN(r, 20); + } + } + if (create_monster( demonnum, 6, + BEH_GOD_GIFT, you.x_pos, you.y_pos, + you.pet_target, 250 ) != -1) + { + temp_rand = random2(3); + + god_speaks(GOD_XOM, + (temp_rand == 0) ? "\"Serve the mortal, my child!\"" : + (temp_rand == 1) ? "Xom grants you a demonic assistant." + : "Xom opens a gate so that something can appear."); + + done = true; + } + } + else if ((random2(sever) <= 6) && there_are_monsters_nearby()) + { + if (monsters* mon = get_random_nearby_monster()) + { + temp_rand = random2(4); + + god_speaks(GOD_XOM, + (temp_rand == 0) ? "\"This might be better!\"" : + (temp_rand == 1) ? "\"Hum-dee-hum-dee-hum...\"" : + (temp_rand == 2) ? + "Xom's power touches on a nearby monster." + : "You hear Xom's avuncular chuckle."); + bool isFriendly = mons_friendly(mon); + if (isFriendly) + monster_polymorph(mon, RANDOM_MONSTER, PPT_MORE); + else + monster_polymorph(mon, RANDOM_MONSTER, PPT_LESS); + done = true; + } + } + else if (random2(sever) <= 7) + { + xom_gives_item(sever); + done = true; + } + else if (!you.is_undead && random2(sever) <= 8) + { + temp_rand = random2(4); + god_speaks(GOD_XOM, + (temp_rand == 0) ? "\"You need some minor adjustments, mortal!\"" : + (temp_rand == 1) ? "\"Let me alter your pitiful body.\"" : + (temp_rand == 2) ? "Xom's power touches on you for a moment." + : "You hear Xom's maniacal chuckling."); + mpr("Your body is suffused with distortional energy."); + + set_hp(1 + random2(you.hp), false); + deflate_hp(you.hp_max / 2, true); + + bool failMsg = true; + int i = 0; + int j = random2(4); + while (i < j) + { + if (mutate(100, failMsg, true)) + done = true; + else + failMsg = false; + i++; + } + } + else if (random2(sever) <= 9) + { + int r = random2(random2(random2(sever))); + int demonnum = MONS_WHITE_IMP + MIN(r, 20); + if (!player_res_poison()) + { + while (demonnum == MONS_GREEN_DEATH) + { + r = random2(random2(random2(sever))); + demonnum = MONS_WHITE_IMP + MIN(r, 20); + } + } + if (create_monster( demonnum, 0, BEH_GOD_GIFT, + you.x_pos, you.y_pos, you.pet_target, 250 ) != -1) + { + temp_rand = random2(3); + god_speaks(GOD_XOM, + (temp_rand == 0) ? "\"Serve the toy, my child!\"" : + (temp_rand == 1) ? "Xom grants you a demonic servitor." + : "Xom opens a gate."); + done = true; + } + } + else if ((random2(sever) <= 10) && player_in_a_dangerous_place()) + { + bool lightningprot = false; + if (you.hp <= random2(201) + && !you.attribute[ATTR_DIVINE_LIGHTNING_PROTECTION]) + { + you.attribute[ATTR_DIVINE_LIGHTNING_PROTECTION] = 1; + lightningprot = true; + } else + lightningprot = false; + mpr("The area is suffused with divine lightning!"); + + beam.beam_source = NON_MONSTER; + beam.type = SYM_BURST; + beam.damage = dice_def( 3, 30 ); + beam.flavour = BEAM_ELECTRICITY; + beam.target_x = you.x_pos; + beam.target_y = you.y_pos; + beam.name = "blast of lightning"; + beam.colour = LIGHTCYAN; + beam.thrower = KILL_MISC; + beam.aux_source = "Xom's lightning strike"; + beam.ex_size = 2; + beam.is_tracer = false; + beam.is_explosion = true; + explosion(beam); + + if (lightningprot) + { + mpr("Your divine protection wanes."); + you.attribute[ATTR_DIVINE_LIGHTNING_PROTECTION] = 0; + } + + done = true; + } + + return (done); +} + +static bool xom_is_bad(int sever) +{ + // niceness = false - bad, true - nice + int temp_rand; // probability determination {dlb} + bool done = false; + + bolt beam; + + // begin "Bad Things" + while (!done) + { + if (random2(sever) <= 2) + { + temp_rand = random2(4); + + god_speaks(GOD_XOM, + (temp_rand == 0) ? "Xom almost notices you." : + (temp_rand == 1) ? "Xom's attention almost turns to you for a moment.": + (temp_rand == 2) ? "Xom's power almost touches on you for a moment." + : "You almost hear Xom's maniacal laughter."); + + miscast_effect( SPTYP_RANDOM, 0, 0, 0, + "the mischievity of Xom" ); + + done = true; + } + else if (random2(sever) <= 3) + { + temp_rand = random2(4); + + god_speaks(GOD_XOM, + (temp_rand == 0) ? "Xom notices you." : + (temp_rand == 1) ? "Xom's attention turns to you for a moment.": + (temp_rand == 2) ? "Xom's power touches on you for a moment." + : "You hear Xom's maniacal laughter."); + + miscast_effect( SPTYP_RANDOM, 0, 0, random2(2), + "the capriciousness of Xom" ); + + done = true; + } + else if (random2(sever) <= 4) + { + temp_rand = random2(4); + + god_speaks(GOD_XOM, + (temp_rand == 0) ? "\"Suffer!\"" : + (temp_rand == 1) ? "Xom's malign attention turns to you for a moment." : + (temp_rand == 2) ? "Xom's power touches on you for a moment." + : "You hear Xom's maniacal laughter."); + + lose_stat(STAT_RANDOM, 1 + random2(3), true); + + done = true; + } + else if (random2(sever) <= 5) + { + temp_rand = random2(4); + + god_speaks(GOD_XOM, + (temp_rand == 0) ? "Xom notices you." : + (temp_rand == 1) ? "Xom's attention turns to you for a moment.": + (temp_rand == 2) ? "Xom's power touches on you for a moment." + : "You hear Xom's maniacal laughter."); + + miscast_effect( SPTYP_RANDOM, 0, 0, random2(3), + "the capriciousness of Xom" ); + + done = true; + } + else if (!you.is_undead && random2(sever) <= 6) + { + temp_rand = random2(4); + god_speaks(GOD_XOM, + (temp_rand == 0) ? "\"You need some minor improvements, mortal!\"" : + (temp_rand == 1) ? "\"Let me alter your body.\"" : + (temp_rand == 2) ? "Xom's power brushes against you for a moment." + : "You hear Xom's avuncular chuckle."); + mpr("Your body is suffused with distortional energy."); + + set_hp(1 + random2(you.hp), false); + deflate_hp(you.hp_max / 2, true); + + bool failMsg = true; + for (int i = 0; i < random2(4)+1; i++) + { + if (mutate(101, failMsg, true)) + done = true; + else + failMsg = false; + } + } + else if ((random2(sever) <= 7) && there_are_monsters_nearby()) + { + struct monsters* mon = get_random_nearby_monster(); + ASSERT (mon != NULL); + temp_rand = random2(4); + + god_speaks(GOD_XOM, + (temp_rand == 0) ? "\"This might be better!\"" : + (temp_rand == 1) ? "\"Hum-dee-hum-dee-hum...\"" : + (temp_rand == 2) ? "Xom's power touches on a nearby monster." + : "You hear Xom's avuncular chuckle."); + bool isFriendly = mons_friendly(mon); + if (isFriendly) + monster_polymorph(mon, RANDOM_MONSTER, PPT_LESS); + else + monster_polymorph(mon, RANDOM_MONSTER, PPT_MORE); + done = true; + } + else if (!you.is_undead && random2(sever) <= 8) + { + temp_rand = random2(4); + + god_speaks(GOD_XOM, + (temp_rand == 0) ? "\"You have displeased me, mortal.\"" : + (temp_rand == 1) ? "\"You have grown too confident for your meagre worth.\"" : + (temp_rand == 2) ? "Xom's power touches on you for a moment." + : "You hear Xom's maniacal laughter."); + + if (one_chance_in(4)) + { + drain_exp(); + if (random2(sever) > 3) + drain_exp(); + if (random2(sever) > 3) + drain_exp(); + } + else + { + mpr("A wave of agony tears through your body!"); + set_hp(1 + (you.hp / 2), false); + } + + done = true; + } + else if (random2(sever) <= 9) + { + temp_rand = random2(4); + + god_speaks(GOD_XOM, + (temp_rand == 0) ? "\"Time to have some fun!\"" : + (temp_rand == 1) ? "\"Fight to survive, mortal.\"" : + (temp_rand == 2) ? "\"Let's see if it's strong enough to survive yet.\"" + : "You hear Xom's maniacal laughter."); + + if (one_chance_in(4)) + dancing_weapon(100, true); // nasty, but fun + else + { + int r = random2(random2(random2(sever+1)+1)+1)+1; + int numdemons = MIN(r, 24); + for (int i = 0; i < numdemons; i++) + { + create_monster(MONS_WHITE_IMP + + random2(random2(random2(MIN(sever, 22)))), + 4, + BEH_HOSTILE, you.x_pos, you.y_pos, + MHITNOT, 250); + } + } + + done = true; + } + else if (random2(sever) <= 10) + { + temp_rand = random2(4); + + god_speaks(GOD_XOM, + (temp_rand == 0) ? "\"Try this!\"" : + (temp_rand == 1) ? "Xom's attention turns to you.": + (temp_rand == 2) ? "Xom's power touches on you." + : "Xom giggles."); + + miscast_effect( SPTYP_RANDOM, 0, 0, random2(4), + "the severe capriciousness of Xom" ); + + done = true; + } + else if ((random2(sever) == 0) && (you.level_type != LEVEL_ABYSS)) + { + temp_rand = random2(3); + + god_speaks(GOD_XOM, + (temp_rand == 0) ? "\"You have grown too comfortable in your little world, mortal!\"" : + (temp_rand == 1) ? "Xom casts you into the Abyss!" + : "The world seems to spin as Xom's maniacal laughter rings in your ears."); + + banished(DNGN_ENTER_ABYSS); + + done = true; + } + } + + return (done); +} + +void xom_acts(bool niceness, int sever) +{ +#if DEBUG_DIAGNOSTICS + mprf(MSGCH_DIAGNOSTICS, "Xom_acts(%u, %d); piety: %u, interest: %u\n", + niceness, sever, you.piety, you.gift_timeout); +#endif + + if (sever < 1) + sever = 1; + + if (niceness) + { + // Good stuff. + while (!xom_is_good(sever)) + ; + } + else + { + // Bad mojo. + while (!xom_is_bad(sever)) + ; + } + + if (coinflip()) + you.piety = 200 - you.piety; +} -- cgit v1.2.3-54-g00ecf