diff options
-rw-r--r-- | crawl-ref/source/abl-show.cc | 43 | ||||
-rw-r--r-- | crawl-ref/source/effects.cc | 24 | ||||
-rw-r--r-- | crawl-ref/source/enum.h | 4 | ||||
-rw-r--r-- | crawl-ref/source/food.cc | 12 | ||||
-rw-r--r-- | crawl-ref/source/misc.cc | 6 | ||||
-rw-r--r-- | crawl-ref/source/monplace.cc | 68 | ||||
-rw-r--r-- | crawl-ref/source/monplace.h | 6 | ||||
-rw-r--r-- | crawl-ref/source/religion.cc | 129 | ||||
-rw-r--r-- | crawl-ref/source/spells3.cc | 85 | ||||
-rw-r--r-- | crawl-ref/source/spells3.h | 2 |
10 files changed, 303 insertions, 76 deletions
diff --git a/crawl-ref/source/abl-show.cc b/crawl-ref/source/abl-show.cc index 95dbc29ccd..29303e611a 100644 --- a/crawl-ref/source/abl-show.cc +++ b/crawl-ref/source/abl-show.cc @@ -107,8 +107,8 @@ ability_type god_abilities[MAX_NUM_GODS][MAX_GOD_ABILITIES] = { ABIL_NON_ABILITY, ABIL_TSO_DIVINE_SHIELD, ABIL_NON_ABILITY, ABIL_TSO_CLEANSING_FLAME, ABIL_TSO_SUMMON_DIVINE_WARRIOR }, // Kikubaaqudgha - { ABIL_KIKU_RECALL_UNDEAD_SLAVES, ABIL_NON_ABILITY, - ABIL_KIKU_ENSLAVE_UNDEAD, ABIL_NON_ABILITY, ABIL_KIKU_INVOKE_DEATH }, + { ABIL_KIKU_RECEIVE_CORPSE, ABIL_NON_ABILITY, + ABIL_NON_ABILITY, ABIL_NON_ABILITY, ABIL_NON_ABILITY }, // Yredelemnul { ABIL_YRED_ANIMATE_REMAINS, ABIL_YRED_RECALL_UNDEAD_SLAVES, ABIL_YRED_ANIMATE_DEAD, ABIL_YRED_DRAIN_LIFE, ABIL_YRED_ENSLAVE_SOUL }, @@ -242,10 +242,7 @@ static const ability_def Ability_List[] = 8, 0, 150, 4, ABFLAG_NONE }, // Kikubaaqudgha - { ABIL_KIKU_RECALL_UNDEAD_SLAVES, "Recall Undead Slaves", - 2, 0, 50, 0, ABFLAG_NONE }, - { ABIL_KIKU_ENSLAVE_UNDEAD, "Enslave Undead", 4, 0, 150, 3, ABFLAG_NONE }, - { ABIL_KIKU_INVOKE_DEATH, "Invoke Death", 4, 0, 250, 3, ABFLAG_NONE }, + { ABIL_KIKU_RECEIVE_CORPSE, "Recieve Corpses", 5, 0, 1000, 2, ABFLAG_NONE }, // Yredelemnul { ABIL_YRED_INJURY_MIRROR, "Injury Mirror", 0, 0, 0, 0, ABFLAG_PIETY }, @@ -677,7 +674,6 @@ static talent _get_talent(ability_type ability, bool check_confused) break; case ABIL_ZIN_RECITE: - case ABIL_KIKU_RECALL_UNDEAD_SLAVES: case ABIL_BEOGH_RECALL_ORCISH_FOLLOWERS: case ABIL_OKAWARU_MIGHT: case ABIL_ELYVILON_LESSER_HEALING_SELF: @@ -727,7 +723,7 @@ static talent _get_talent(ability_type ability, bool check_confused) case ABIL_BEOGH_SMITING: case ABIL_MAKHLEB_MINOR_DESTRUCTION: case ABIL_SIF_MUNA_FORGET_SPELL: - case ABIL_KIKU_ENSLAVE_UNDEAD: + case ABIL_KIKU_RECEIVE_CORPSE: case ABIL_YRED_ANIMATE_DEAD: case ABIL_MAKHLEB_LESSER_SERVANT_OF_MAKHLEB: case ABIL_ELYVILON_GREATER_HEALING_SELF: @@ -774,7 +770,6 @@ static talent _get_talent(ability_type ability, bool check_confused) case ABIL_ZIN_SANCTUARY: case ABIL_TSO_SUMMON_DIVINE_WARRIOR: - case ABIL_KIKU_INVOKE_DEATH: case ABIL_YRED_ENSLAVE_SOUL: case ABIL_ELYVILON_DIVINE_VIGOUR: case ABIL_LUGONU_ABYSS_ENTER: @@ -1625,33 +1620,9 @@ static bool _do_ability(const ability_def& abil) exercise(SK_INVOCATIONS, 8 + random2(10)); break; - case ABIL_KIKU_RECALL_UNDEAD_SLAVES: - recall(1); - exercise(SK_INVOCATIONS, 1); - break; - - case ABIL_KIKU_ENSLAVE_UNDEAD: - { - god_acting gdact; - beam.range = LOS_RADIUS; - if (!spell_direction(spd, beam)) - return (false); - - if (!zapping(ZAP_ENSLAVE_UNDEAD, you.skills[SK_INVOCATIONS] * 8, beam, - true)) - { - return (false); - } - - exercise(SK_INVOCATIONS, 5 + random2(5)); - break; - } - - case ABIL_KIKU_INVOKE_DEATH: - summon_demon_type(MONS_REAPER, - 20 + you.skills[SK_INVOCATIONS] * 3, - GOD_KIKUBAAQUDGHA); - exercise(SK_INVOCATIONS, 10 + random2(14)); + case ABIL_KIKU_RECEIVE_CORPSE: + receive_corpses(you.skills[SK_INVOCATIONS] * 4, you.pos()); + exercise(SK_INVOCATIONS, (coinflip() ? 3 : 2)); break; case ABIL_YRED_INJURY_MIRROR: diff --git a/crawl-ref/source/effects.cc b/crawl-ref/source/effects.cc index 9aac28b298..0a677af6a2 100644 --- a/crawl-ref/source/effects.cc +++ b/crawl-ref/source/effects.cc @@ -203,6 +203,30 @@ int torment_player(int pow, int caster) hploss = std::max(0, you.hp * (50 - player_prot_life() * 5) / 100 - 1); } + // Kiku protects you from torment to a degree. + bool kiku_shielding_player = + (you.religion == GOD_KIKUBAAQUDGHA + && !player_res_torment() + && !player_under_penance() + && you.piety > 80 + && you.gift_timeout == 0); // no protection during pain branding weapon + + if (kiku_shielding_player) + { + if(!player_res_torment()) + { + if (random2(600) < you.piety) // 13.33% to 33.33% chance + { + hploss = 0; + simple_god_message(" shields you entirely from torment!"); + } else if (random2(250) < you.piety) { // 24% to 80% chance + hploss -= random2(hploss - 1); + simple_god_message(" shields you from torment!"); + } + } + } + + if (!hploss) { mpr("You feel a surge of unholy energy."); diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h index 318dd194d9..f299733d9f 100644 --- a/crawl-ref/source/enum.h +++ b/crawl-ref/source/enum.h @@ -60,9 +60,7 @@ enum ability_type ABIL_TSO_DIVINE_SHIELD = 120, // 120 ABIL_TSO_CLEANSING_FLAME, ABIL_TSO_SUMMON_DIVINE_WARRIOR, - ABIL_KIKU_RECALL_UNDEAD_SLAVES = 130, // 130 - ABIL_KIKU_ENSLAVE_UNDEAD = 132, - ABIL_KIKU_INVOKE_DEATH, + ABIL_KIKU_RECEIVE_CORPSE = 130, // 130 ABIL_YRED_INJURY_MIRROR = 139, ABIL_YRED_ANIMATE_REMAINS, // 140 ABIL_YRED_RECALL_UNDEAD_SLAVES, diff --git a/crawl-ref/source/food.cc b/crawl-ref/source/food.cc index 12089b509c..712ffef62b 100644 --- a/crawl-ref/source/food.cc +++ b/crawl-ref/source/food.cc @@ -29,6 +29,7 @@ REVISION("$Rev$"); #include "command.h" #include "debug.h" #include "delay.h" +#include "effects.h" #include "initfile.h" #include "invent.h" #include "items.h" @@ -360,7 +361,18 @@ static bool _butcher_corpse(int corpse_id, bool first_corpse = true, && god_likes_butchery(you.religion); if (can_sac && !rotten) + { start_delay(DELAY_OFFER_CORPSE, 0, corpse_id); + + // Kiku torments if you butcher a corpse while praying + bool kiku_torments = (you.religion == GOD_KIKUBAAQUDGHA && you.piety > 120); + if (kiku_torments) + { + simple_god_message(" inflicts torment against the living!"); + torment(TORMENT_GENERIC, you.pos()); + you.piety -= 8 + random2(4); // 8 to 12 + } + } else { if (can_sac && rotten) diff --git a/crawl-ref/source/misc.cc b/crawl-ref/source/misc.cc index 2bec5b9aff..554879c05d 100644 --- a/crawl-ref/source/misc.cc +++ b/crawl-ref/source/misc.cc @@ -85,6 +85,12 @@ REVISION("$Rev$"); static void _create_monster_hide(const item_def corpse) { + // receive_corpses() in spells3.cc creates corpses that + // are easily scummed for hides. We prevent this by setting + // "DoNotDropHide" as an item property of corpses it creates. + if (corpse.props.exists("DoNotDropHide")) + return; + int mons_class = corpse.plus; int o = get_item_slot(); diff --git a/crawl-ref/source/monplace.cc b/crawl-ref/source/monplace.cc index 406219e0bc..ccb4e943d2 100644 --- a/crawl-ref/source/monplace.cc +++ b/crawl-ref/source/monplace.cc @@ -1290,6 +1290,74 @@ static monster_type _pick_random_zombie() return (zombifiable[random2(zombifiable.size())]); } +monster_type pick_local_zombifiable_monster_type(int power) +{ + // Generates a dummy zombie likely to be found + // Ripped wholly from _define_zombie(). + + power = std::min(27, power); + // How OOD this zombie can be. + int relax = 5; + + // Pick an appropriate creature to make a zombie out of, + // levelwise. The old code was generating absolutely + // incredible OOD zombies. + int cls; + while (true) + { + cls = _pick_random_zombie(); + + bool ignore_rarity = false; + // On certain branches, zombie creation will fail if we use + // the mons_rarity() functions, because (for example) there + // are NO zombifiable "native" abyss creatures. Other branches + // where this is a problem are hell levels and the crypt. + // we have to watch for summoned zombies on other levels, too, + // such as the Temple, HoB, and Slime Pits. + if (you.level_type != LEVEL_DUNGEON + || player_in_hell() + || player_in_branch(BRANCH_HALL_OF_ZOT) + || player_in_branch(BRANCH_VESTIBULE_OF_HELL) + || player_in_branch(BRANCH_ECUMENICAL_TEMPLE) + || player_in_branch(BRANCH_CRYPT) + || player_in_branch(BRANCH_TOMB) + || player_in_branch(BRANCH_HALL_OF_BLADES) + || player_in_branch(BRANCH_SNAKE_PIT) + || player_in_branch(BRANCH_SLIME_PITS) + || one_chance_in(1000)) + { + ignore_rarity = true; + } + + // Don't make out-of-rarity zombies when we don't have to. + if (!ignore_rarity && mons_rarity(cls) == 0) + continue; + + // Check for rarity.. and OOD - identical to mons_place() + int level, diff, chance; + + level = mons_level(cls) - 4; + diff = level - power; + + chance = (ignore_rarity) ? 100 + : mons_rarity(cls) - (diff * diff) / 2; + + if (power > level - relax && power < level + relax + && random2avg(100, 2) <= chance) + { + break; + } + + // Every so often, we'll relax the OOD restrictions. Avoids + // infinite loops (if we don't do this, things like creating + // a large skeleton on level 1 may hang the game!). + if (one_chance_in(5)) + relax++; + } + + return (monster_type)cls; +} + static void _define_zombie(int mid, monster_type ztype, monster_type cs, int power, coord_def pos) { diff --git a/crawl-ref/source/monplace.h b/crawl-ref/source/monplace.h index 8dfab01b17..10d671382d 100644 --- a/crawl-ref/source/monplace.h +++ b/crawl-ref/source/monplace.h @@ -258,6 +258,12 @@ int mons_place(mgen_data mg); * *********************************************************************** */ int place_monster(mgen_data mg, bool force_pos = false); +/* *********************************************************************** + * Returns a monster class type of a zombie that would be generated + * on the player's current level. + * *********************************************************************** */ +monster_type pick_local_zombifiable_monster_type(int power); + // last updated 12may2000 {dlb} /* *********************************************************************** * called from: acr - debug - decks - effects - fight - it_use3 - item_use - diff --git a/crawl-ref/source/religion.cc b/crawl-ref/source/religion.cc index 37930c052a..78fbe43c8f 100644 --- a/crawl-ref/source/religion.cc +++ b/crawl-ref/source/religion.cc @@ -123,9 +123,9 @@ static const char *_Sacrifice_Messages[NUM_GODS][NUM_PIETY_GAIN] = }, // Kikubaaqudgha { - " slowly rot% away.", - " rot% away.", - " rot% away in an instant.", + " convulse% and rot% away.", + " convulse% madly and rot% away.", + " convulse% furiously and rot% away.", }, // Yredelemnul { @@ -218,11 +218,11 @@ const char* god_gain_power_messages[NUM_GODS][MAX_GOD_ABILITIES] = "channel blasts of cleansing flame", "summon a divine warrior" }, // Kikubaaqudgha - { "recall your undead slaves", - "Kikubaaqudgha is protecting you from some side-effects of death magic.", - "permanently enslave the undead", + { "receive cadavers from Kikubaaqudgha", "", - "summon an emissary of Death" }, + "", + "Kikubaaqudgha is protecting you from unholy torment.", + "invoke torment by butchering corpses during prayer" }, // Yredelemnul { "animate remains", "recall your undead slaves", @@ -318,11 +318,11 @@ const char* god_lose_power_messages[NUM_GODS][MAX_GOD_ABILITIES] = "channel blasts of cleansing flame", "summon a divine warrior" }, // Kikubaaqudgha - { "recall your undead slaves", - "Kikubaaqudgha is no longer shielding you from miscast death magic.", - "permanently enslave the undead", + { "receive cadavers from Kikubaaqudgha", + "", "", - "summon an emissary of Death" }, + "Kikubaaqudgha will no longer protect you from unholy torment.", + "invoke torment by butchering corpses during prayer" }, // Yredelemnul { "animate remains", "recall your undead slaves", @@ -620,7 +620,6 @@ std::string get_god_likes(god_type which_god, bool verbose) case GOD_KIKUBAAQUDGHA: likes.push_back("you kill living beings"); - likes.push_back("your god-given allies kill living beings"); likes.push_back("your undead slaves kill living beings"); break; @@ -699,7 +698,6 @@ std::string get_god_likes(god_type which_god, bool verbose) case GOD_KIKUBAAQUDGHA: likes.push_back("you kill holy beings"); - likes.push_back("your god-given allies kill holy beings"); likes.push_back("your undead slaves kill holy beings"); break; @@ -2213,7 +2211,6 @@ static void _do_god_gift(bool prayed_for) } break; - case GOD_KIKUBAAQUDGHA: case GOD_SIF_MUNA: case GOD_VEHUMET: if (you.piety > 160 && random2(you.piety) > 100) @@ -2222,17 +2219,6 @@ static void _do_god_gift(bool prayed_for) switch (you.religion) { - case GOD_KIKUBAAQUDGHA: // gives death books - if (!you.had_book[BOOK_NECROMANCY]) - gift = BOOK_NECROMANCY; - else if (!you.had_book[BOOK_DEATH]) - gift = BOOK_DEATH; - else if (!you.had_book[BOOK_UNLIFE]) - gift = BOOK_UNLIFE; - else if (!you.had_book[BOOK_NECRONOMICON]) - gift = BOOK_NECRONOMICON; - break; - case GOD_SIF_MUNA: gift = OBJ_RANDOM; // Sif Muna - gives any break; @@ -3767,15 +3753,22 @@ void gain_piety(int pgn) if (!you.num_gifts[you.religion]) { - if (you.religion == GOD_ZIN) - simple_god_message(" will now cure all your mutations... once."); - else if (you.religion == GOD_SHINING_ONE - || you.religion == GOD_LUGONU) + switch (you.religion) { - mprf("%s will now %s your weapon at an altar... once.", - god_name(you.religion).c_str(), - you.religion == GOD_SHINING_ONE ? "bless" : "corrupt", - MSGCH_GOD, you.religion); + case GOD_ZIN: + simple_god_message(" will now cure all your mutations... once."); + break; + case GOD_SHINING_ONE: + simple_god_message(" will now bless your weapon at an altar... once."); + break; + case GOD_KIKUBAAQUDGHA: + simple_god_message(" will now enhance your necromancy at an altar... once."); + break; + case GOD_LUGONU: + simple_god_message(" will now corrupt your weapon at an altar... once."); + break; + default: + break; } } @@ -6891,9 +6884,10 @@ static bool _bless_weapon(god_type god, brand_type brand, int colour) you.wield_change = true; you.num_gifts[god]++; std::string desc = old_name + " "; - desc += (god == GOD_SHINING_ONE ? "blessed by the Shining One" : - god == GOD_LUGONU ? "corrupted by Lugonu" - : "touched by the gods"); + desc += (god == GOD_SHINING_ONE ? "blessed by the Shining One" : + god == GOD_LUGONU ? "corrupted by Lugonu" : + god == GOD_KIKUBAAQUDGHA ? "bloodied by Kikubaaqudgha" + : "touched by the gods"); take_note(Note(NOTE_ID_ITEM, 0, 0, wpn.name(DESC_NOCAP_A).c_str(), desc.c_str())); @@ -6916,6 +6910,16 @@ static bool _bless_weapon(god_type god, brand_type brand, int colour) env.map(*ri).property &= ~(FPROP_BLOODY); } + if (god == GOD_KIKUBAAQUDGHA) + { + torment(TORMENT_GENERIC, you.pos()); + + // Bloodify surrounding squares. + for (radius_iterator ri(you.pos(), 2, true, true); ri; ++ri) + if (random2(4) != 2) // 75% of tiles will get bloodied + env.map(*ri).property |= FPROP_BLOODY; + } + #ifndef USE_TILE // Allow extra time for the flash to linger. delay(1000); @@ -7028,6 +7032,56 @@ static bool _altar_prayer() did_bless = _bless_weapon(GOD_LUGONU, SPWPN_DISTORTION, MAGENTA); } + // Kikubaaqudgha blesses weapons with pain, or gives you a Necronomicon + if (you.religion == GOD_KIKUBAAQUDGHA + && !you.num_gifts[GOD_KIKUBAAQUDGHA] + && !player_under_penance() + && you.piety > 160) + { + simple_god_message( + " will bless your weapon with pain or grant you the Necronomicon."); + + bool kiku_did_bless_weapon = false; + + const int wpn = get_player_wielded_weapon(); + + // Does the player want a pain branding? + if (wpn != -1 && get_weapon_brand(you.inv[wpn]) != SPWPN_PAIN) + { + kiku_did_bless_weapon = + _bless_weapon(GOD_KIKUBAAQUDGHA, SPWPN_PAIN, RED); + did_bless = kiku_did_bless_weapon; + } + else mpr("You have no weapon to bloody with pain."); + + // If not, ask if the player wants a Necronomicon + if (!kiku_did_bless_weapon) + { + if (!yesno("Do you wish to receive the Necronomicon?", true, 'n')) + return(false); + + int thing_created = items(1, OBJ_BOOKS, BOOK_NECRONOMICON, true, 1, + MAKE_ITEM_RANDOM_RACE, + 0, 0, you.religion); + if (thing_created == NON_ITEM) + return(false); + + move_item_to_grid( &thing_created, you.pos() ); + + if (thing_created != NON_ITEM) + { + simple_god_message(" grants you a gift!"); + more(); + + you.num_gifts[you.religion]++; + did_bless = true; + take_note(Note(NOTE_GOD_GIFT, you.religion)); + mitm[thing_created].inscription = "god gift"; + } + } + return(did_bless); // Return early so we don't offer our Necronomicon to Kiku + } // end kiku gifting + offer_items(); return (did_bless); @@ -7654,7 +7708,8 @@ bool god_likes_butchery(god_type god) return (god == GOD_OKAWARU || god == GOD_MAKHLEB || god == GOD_TROG - || god == GOD_LUGONU); + || god == GOD_LUGONU + || (god == GOD_KIKUBAAQUDGHA && you.piety > 120)); } bool god_hates_butchery(god_type god) diff --git a/crawl-ref/source/spells3.cc b/crawl-ref/source/spells3.cc index 83f58fbb99..501b8aabdd 100644 --- a/crawl-ref/source/spells3.cc +++ b/crawl-ref/source/spells3.cc @@ -645,6 +645,91 @@ bool cast_summon_horrible_things(int pow, god_type god) return (count > 0); } +bool receive_corpses(int pow, coord_def where) +{ + // pow = invocations * 4, ranges from 0 to 108 + mprf(MSGCH_DIAGNOSTICS, "Receive_corpses power: %d", pow); + // Kiku gives branch-appropriate corpses (like shadow creatures) + int expected_extra_corpses = (pow / 36); // 1 at 0 inv, 7 at 7 inv + int corpse_delivery_radius = 3; + + // We should get the same # of corpses in a hallway as in an open room. + int spaces_for_corpses = 0; + for (radius_iterator ri(where, corpse_delivery_radius, true, true, true); ri; ++ri) + if (mons_class_can_pass(MONS_HUMAN, grd(*ri))) + spaces_for_corpses++; + + int percent_chance_a_square_receives_extra_corpse = // can be > 100 + (int)( + ((float) expected_extra_corpses) / + ((float) spaces_for_corpses) + * 100.0 + ); + + int corpses_generated = 0; + + for (radius_iterator ri(where, corpse_delivery_radius, false, true, false); ri; ++ri) + { + + bool square_is_walkable = mons_class_can_pass(MONS_HUMAN, grd(*ri)); + bool square_is_player_square = (*ri == where); + bool square_gets_corpse = + (random2(100) < percent_chance_a_square_receives_extra_corpse) || + (square_is_player_square && random2(100) < 97); + if (!square_is_walkable || !square_gets_corpse) + continue; + + corpses_generated++; + + // Find an appropriate monster corpse + monster_type mon_type = MONS_PROGRAM_BUG; + int adjusted_power = 0; + for (int i = 0; i < 200 && !mons_class_can_be_zombified(mon_type); i++) + { + adjusted_power = std::min(pow/4,random2(random2(pow))); + mon_type = pick_local_zombifiable_monster_type(adjusted_power); + } + + // Create corpse object + monsters dummy; + dummy.type = mon_type; + int index_of_corpse_created = get_item_slot(); + if (mons_genus(mon_type) == MONS_HYDRA) + dummy.number = random2(20) + 1; + int valid_corpse = fill_out_corpse(&dummy, mitm[index_of_corpse_created], false); + if (!valid_corpse) + { + mitm[index_of_corpse_created].clear(); + continue; + } + mitm[index_of_corpse_created].props["DoNotDropHide"] = true; + + ASSERT(valid_corpse >= 0); + + // Higher power means fresher corpses. + // One out of ten corpses will always be rotten. + // (Perhaps this should be different for ghouls.) + int rottedness = 200 - + ((random2(10) == 5) ? + random2(175 - pow) : + random2(100 + random2(75))); + mitm[index_of_corpse_created].special = rottedness; + + // Place the corpse. + move_item_to_grid( &index_of_corpse_created, *ri ); + } + + if (corpses_generated) + { + simple_god_message(" delivers you corpses!"); + maybe_update_stashes(); + return true; + } else { + simple_god_message(" can find no living being to slaughter for you!"); + return false; + } +} + static bool _animatable_remains(const item_def& item) { return (item.base_type == OBJ_CORPSES diff --git a/crawl-ref/source/spells3.h b/crawl-ref/source/spells3.h index 394918eea8..4bdc143a88 100644 --- a/crawl-ref/source/spells3.h +++ b/crawl-ref/source/spells3.h @@ -50,6 +50,8 @@ bool cast_summon_greater_demon(int pow, god_type god = GOD_NO_GOD); bool cast_shadow_creatures(god_type god = GOD_NO_GOD); bool cast_summon_horrible_things(int pow, god_type god = GOD_NO_GOD); +bool receive_corpses(int pow, coord_def where); + void equip_undead(const coord_def &a, int corps, int monster, int monnum); int animate_remains(const coord_def &a, corpse_type class_allowed, beh_type beha, unsigned short hitting, |