diff options
28 files changed, 482 insertions, 115 deletions
diff --git a/crawl-ref/source/abl-show.cc b/crawl-ref/source/abl-show.cc index f9fffeeb6d..84ee18ceb2 100644 --- a/crawl-ref/source/abl-show.cc +++ b/crawl-ref/source/abl-show.cc @@ -332,6 +332,7 @@ static const ability_def Ability_List[] = 8, 0, 200, 15, ABFLAG_NONE }, // Feawn + { ABIL_FEAWN_PLANTWALK, "Plant Walking", 0, 0, 0, 0, ABFLAG_NONE }, { ABIL_FEAWN_FUNGAL_BLOOM, "Decomposition", 0, 0, 0, 0, ABFLAG_NONE }, { ABIL_FEAWN_SUNLIGHT, "Sunlight", 2, 0, 0, 0, ABFLAG_NONE}, { ABIL_FEAWN_PLANT_RING, "Growth", 2, 0, 0, 1, ABFLAG_NONE}, @@ -1976,6 +1977,10 @@ static bool _do_ability(const ability_def& abil) exercise(SK_INVOCATIONS, 1); break; + case ABIL_FEAWN_PLANTWALK: + // Activated via prayer elsewhere. + break; + case ABIL_FEAWN_FUNGAL_BLOOM: { int count = fungal_bloom(); diff --git a/crawl-ref/source/acr.cc b/crawl-ref/source/acr.cc index 1cfca89f1d..7f7aecec0a 100644 --- a/crawl-ref/source/acr.cc +++ b/crawl-ref/source/acr.cc @@ -2309,6 +2309,12 @@ static void _decrement_durations() if (_decrement_a_duration(DUR_MIGHT, "You feel a little less mighty now.")) modify_stat(STAT_STRENGTH, -5, true, "might running out"); + if (_decrement_a_duration(DUR_AGILITY, "You feel a little less agile now.")) + modify_stat(STAT_DEXTERITY, -5, true, "agility running out"); + + if (_decrement_a_duration(DUR_BRILLIANCE, "You feel a little less clever now.")) + modify_stat(STAT_INTELLIGENCE, -5, true, "brilliance running out"); + if (_decrement_a_duration(DUR_BERSERKER, "You are no longer berserk.")) { //jmf: Guilty for berserking /after/ berserk. @@ -3738,7 +3744,11 @@ static void _move_player(coord_def move) const coord_def& targ = you.pos() + move; const dungeon_feature_type targ_grid = grd(targ); + monsters* targ_monst = monster_at(targ); + if (feawn_passthrough(targ_monst)) + targ_monst = NULL; + const bool targ_pass = you.can_pass_through(targ); // You can swap places with a friendly or good neutral monster if diff --git a/crawl-ref/source/beam.cc b/crawl-ref/source/beam.cc index 61a8c91aff..57af9eb18f 100644 --- a/crawl-ref/source/beam.cc +++ b/crawl-ref/source/beam.cc @@ -1885,7 +1885,7 @@ void bolt::hit_wall() } } -void bolt::affect_cell() +void bolt::affect_cell(bool avoid_self) { // Shooting through clouds affects accuracy. if (env.cgrid(pos()) != EMPTY_CLOUD) @@ -1895,14 +1895,18 @@ void bolt::affect_cell() const coord_def old_pos = pos(); const bool was_solid = grid_is_solid(grd(pos())); + + bool avoid_monster = (avoid_self && this->thrower == KILL_MON_MISSILE); + bool avoid_player = (avoid_self && this->thrower != KILL_MON_MISSILE); + if (was_solid) { // Some special casing. if (monsters* mon = monster_at(pos())) { - if (can_affect_wall_monster(mon)) + if (can_affect_wall_monster(mon) && !avoid_monster) affect_monster(mon); - else + else if (!avoid_monster) { mprf("The %s protects %s from harm.", raw_feature_description(grd(mon->pos())).c_str(), @@ -1915,16 +1919,26 @@ void bolt::affect_cell() hit_wall(); } - // We don't want to hit a monster in a wall square twice. const bool still_wall = (was_solid && old_pos == pos()); - if (!still_wall) - if (monsters* m = monster_at(pos())) - affect_monster(m); + bool hit_player = false; // If the player can ever walk through walls, this will // need special-casing too. - if (found_player()) + if (found_player() && !avoid_player) + { affect_player(); + hit_player = true; + } + + // We don't want to hit a monster in a wall square twice. + // Also stop single target beams from affecting a monster if they already + // affected the player on this square. -cao + if ((!hit_player || this->is_beam || this->is_explosion) + && !still_wall && !avoid_monster) + { + if (monsters* m = monster_at(pos()) ) + affect_monster(m); + } if (!grid_is_solid(grd(pos()))) affect_ground(); @@ -2026,12 +2040,12 @@ void bolt::do_fire() } #endif + bool avoid_self = (!aimed_at_feet && (!is_explosion || !in_explosion_phase)); + msg_generated = false; if (!aimed_at_feet) { choose_ray(); - // Take *one* step, so as not to hurt the source. - ray.advance_through(target); } #ifdef WIN32CONSOLE @@ -2046,9 +2060,11 @@ void bolt::do_fire() path_taken.push_back(pos()); if (!affects_nothing) - affect_cell(); + affect_cell(avoid_self); + + if (!avoid_self) + range_used++; - range_used++; if (range_used >= range) break; @@ -2089,6 +2105,8 @@ void bolt::do_fire() ray.advance_through(target); else ray.advance(true); + + avoid_self = false; } if (!in_bounds(pos())) @@ -3970,6 +3988,10 @@ void bolt::affect_player() } } + // Confusion effect for spore explosions + if (flavour == BEAM_SPORE && hurted && you.holiness() != MH_UNDEAD) + potion_effect( POT_CONFUSION, 1); + // handling of missiles if (item && item->base_type == OBJ_MISSILES) { @@ -4156,7 +4178,7 @@ bool bolt::determine_damage(monsters* mon, int& preac, int& postac, int& final, if (!is_enchantment() && attitude == mon->attitude && originator_worships_feawn - && mons_is_plant(mon)) + && feawn_protects(mon)) { if (!is_tracer) { @@ -4624,6 +4646,12 @@ void bolt::affect_monster(monsters* mon) // Explosions always 'hit'. const bool engulfs = (is_explosion || is_big_cloud); + if (engulfs && this->flavour == BEAM_SPORE + && mons_class_holiness(mon->type) == MH_NATURAL) + { + apply_enchantment_to_monster(mon); + } + // Make a copy of the to-hit before we modify it. int beam_hit = hit; if (mon->invisible() && !this->can_see_invis) @@ -4656,9 +4684,16 @@ void bolt::affect_monster(monsters* mon) // for Feawn worshipers. Mostly because you can accidentally blow up a // group of 8 plants and get placed under penance until the end of time // otherwise. I'd prefer to do this elsewhere but the beam information - // goes out of scope. -cao - if (you.religion == GOD_FEAWN && flavour == BEAM_SPORE) + // goes out of scope. + // + // Also exempting miscast explosions from this conduct -cao + if (you.religion == GOD_FEAWN + && (flavour == BEAM_SPORE + || beam_source == NON_MONSTER + && aux_source.find("your miscasting") != std::string::npos)) + { conducts[0].enabled = false; + } // The beam hit. if (mons_near(mon)) @@ -4719,7 +4754,24 @@ void bolt::affect_monster(monsters* mon) if (mon->alive()) monster_post_hit(mon, final); else - corpse = monster_die(mon, thrower, beam_source_as_target()); + { + // Prevent spore explosions killing plants from being registered as + // a feawn misconduct. Deaths can trigger the ally dying or plant + // dying conducts, but spore explosions shouldn't count for either of + // those. + // + // FIXME: Should be a better way of doing this. For now we are just + // falsifying the death report... -cao + if(you.religion == GOD_FEAWN && this->flavour == BEAM_SPORE + && feawn_protects(mon)) + { + if (mon->attitude==ATT_FRIENDLY) + mon->attitude = ATT_HOSTILE; + corpse = monster_die(mon, KILL_MON, beam_source_as_target()); + } + else + corpse = monster_die(mon, thrower, beam_source_as_target()); + } // Give the callbacks a dead-but-valid monster object. if (mon->type == -1) @@ -5113,6 +5165,7 @@ mon_resist_type bolt::apply_enchantment_to_monster(monsters* mon) apply_bolt_petrify(mon); return (MON_AFFECTED); + case BEAM_SPORE: case BEAM_CONFUSION: if (!mons_class_is_confusable(mon->type)) return (MON_UNAFFECTED); diff --git a/crawl-ref/source/beam.h b/crawl-ref/source/beam.h index 94c0e432d0..12ea00041c 100644 --- a/crawl-ref/source/beam.h +++ b/crawl-ref/source/beam.h @@ -215,7 +215,7 @@ private: // operate on the beam's current position (i.e., whatever pos() // returns.) public: - void affect_cell(); + void affect_cell(bool avoid_self = false); void affect_wall(); void affect_monster( monsters* m ); void affect_player(); diff --git a/crawl-ref/source/dat/descript/items.txt b/crawl-ref/source/dat/descript/items.txt index c119ed4711..a42add8db1 100644 --- a/crawl-ref/source/dat/descript/items.txt +++ b/crawl-ref/source/dat/descript/items.txt @@ -908,6 +908,16 @@ potion of might A magic potion which greatly increases the strength and physical power of one who drinks it. %%%% +potion of brilliance + +A magic potion which greatly increases the intelligence and magical power +of one who drinks it. +%%%% +potion of agility + +A magic potion which greatly increases the dexterity and evasiveness +of one who drinks it. +%%%% potion of mutation A potion which does very strange things to you. diff --git a/crawl-ref/source/describe.cc b/crawl-ref/source/describe.cc index e788a787ba..fbdd17c441 100644 --- a/crawl-ref/source/describe.cc +++ b/crawl-ref/source/describe.cc @@ -3620,6 +3620,18 @@ void describe_god( god_type which_god, bool give_title ) ABIL_JIYVA_JELLY_SHIELD); } } + else if (which_god == GOD_FEAWN ) + { + have_any = true; + + std::string buf = "You can speed up decomposition."; + _print_final_god_abil_desc(which_god, buf, + ABIL_FEAWN_FUNGAL_BLOOM); + + buf = "You can pass through plants during prayer."; + _print_final_god_abil_desc(which_god, buf, + ABIL_FEAWN_PLANTWALK); + } // mv: No abilities (except divine protection) under penance if (!player_under_penance()) diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h index be7e2799ad..8d5fdbd98e 100644 --- a/crawl-ref/source/enum.h +++ b/crawl-ref/source/enum.h @@ -107,9 +107,10 @@ enum ability_type ABIL_JIYVA_JELLY_SHIELD, // 240 ABIL_JIYVA_SLIMIFY, ABIL_JIYVA_CURE_BAD_MUTATION, + ABIL_FEAWN_PLANTWALK, ABIL_FEAWN_FUNGAL_BLOOM, - ABIL_FEAWN_SUNLIGHT, - ABIL_FEAWN_RAIN, // 245 + ABIL_FEAWN_SUNLIGHT, // 245 + ABIL_FEAWN_RAIN, ABIL_FEAWN_PLANT_RING, ABIL_FEAWN_SPAWN_SPORES, ABIL_FEAWN_EVOLUTION, @@ -1192,6 +1193,8 @@ enum duration_type DUR_MESMERISED, DUR_HASTE, DUR_MIGHT, + DUR_BRILLIANCE, + DUR_AGILITY, DUR_LEVITATION, DUR_BERSERKER, DUR_POISONING, @@ -2471,6 +2474,8 @@ enum potion_type POT_HEAL_WOUNDS, POT_SPEED, POT_MIGHT, + POT_BRILLIANCE, + POT_AGILITY, POT_GAIN_STRENGTH, POT_GAIN_DEXTERITY, // 5 POT_GAIN_INTELLIGENCE, diff --git a/crawl-ref/source/it_use2.cc b/crawl-ref/source/it_use2.cc index 62e8a6ab26..45b0605cbf 100644 --- a/crawl-ref/source/it_use2.cc +++ b/crawl-ref/source/it_use2.cc @@ -162,6 +162,50 @@ bool potion_effect(potion_type pot_eff, int pow, bool drank_it, bool was_known) break; } + case POT_BRILLIANCE: + { + const bool were_brilliant = you.duration[DUR_BRILLIANCE] > 0; + + mprf(MSGCH_DURATION, "You feel %s all of a sudden.", + were_brilliant ? "clever" : "more clever"); + + if (were_brilliant) + contaminate_player(1, was_known); + else + modify_stat(STAT_INTELLIGENCE, 5, true, ""); + + you.duration[DUR_BRILLIANCE] += (35 + random2(pow)) / factor; + + if (you.duration[DUR_BRILLIANCE] > 80) + you.duration[DUR_BRILLIANCE] = 80; + + did_god_conduct(DID_STIMULANTS, 4 + random2(4), was_known); + break; + } + + case POT_AGILITY: + { + const bool were_agile = you.duration[DUR_AGILITY] > 0; + + mprf(MSGCH_DURATION, "You feel %s all of a sudden.", + were_agile ? "agile" : "more agile"); + + if (were_agile) + contaminate_player(1, was_known); + else + modify_stat(STAT_DEXTERITY, 5, true, ""); + + you.duration[DUR_AGILITY] += (35 + random2(pow)) / factor; + + if (you.duration[DUR_AGILITY] > 80) + you.duration[DUR_AGILITY] = 80; + + you.redraw_evasion = true; + + did_god_conduct(DID_STIMULANTS, 4 + random2(4), was_known); + break; + } + case POT_GAIN_STRENGTH: if (mutate(MUT_STRONG, true, false, false, true)) learned_something_new(TUT_YOU_MUTATED); diff --git a/crawl-ref/source/item_use.cc b/crawl-ref/source/item_use.cc index c5cbc035f2..954046ad1e 100644 --- a/crawl-ref/source/item_use.cc +++ b/crawl-ref/source/item_use.cc @@ -3036,8 +3036,8 @@ bool thrown_object_destroyed(item_def *item, const coord_def& where, // Enchanted projectiles get an extra shot at avoiding // destruction: plus / (1 + plus) chance of survival. - bool destroyed = (chance == 0) ? false : - (one_chance_in(chance) && one_chance_in(item->plus)); + bool destroyed = (chance == 0) ? false : (one_chance_in(chance) + && one_chance_in(item->plus + 1)); bool hostile_grid = grid_destroys_items(grd(where)); // Non-returning items thrown into item-destroying grids are always @@ -4231,6 +4231,8 @@ bool _drink_fountain() 40, POT_HEAL_WOUNDS, 40, POT_SPEED, 40, POT_MIGHT, + 40, POT_AGILITY, + 40, POT_BRILLIANCE, 32, POT_DEGENERATION, 27, POT_LEVITATION, 27, POT_POISON, diff --git a/crawl-ref/source/itemname.cc b/crawl-ref/source/itemname.cc index 496b1e6481..827d7f77ab 100644 --- a/crawl-ref/source/itemname.cc +++ b/crawl-ref/source/itemname.cc @@ -491,6 +491,8 @@ static const char* potion_type_name(int potiontype) case POT_HEAL_WOUNDS: return "heal wounds"; case POT_SPEED: return "speed"; case POT_MIGHT: return "might"; + case POT_AGILITY: return "agility"; + case POT_BRILLIANCE: return "brilliance"; case POT_GAIN_STRENGTH: return "gain strength"; case POT_GAIN_DEXTERITY: return "gain dexterity"; case POT_GAIN_INTELLIGENCE: return "gain intelligence"; @@ -2360,6 +2362,8 @@ bool is_good_item(const item_def &item) case POT_MAGIC: case POT_BERSERK_RAGE: case POT_MIGHT: + case POT_AGILITY: + case POT_BRILLIANCE: case POT_RESTORE_ABILITIES: return (true); default: diff --git a/crawl-ref/source/makeitem.cc b/crawl-ref/source/makeitem.cc index e1dab60a06..c269fccbd5 100644 --- a/crawl-ref/source/makeitem.cc +++ b/crawl-ref/source/makeitem.cc @@ -2377,6 +2377,8 @@ static void _generate_potion_item(item_def& item, int force_type, 222, POT_CURE_MUTATION, 612, POT_SPEED, 612, POT_MIGHT, + 612, POT_AGILITY, + 612, POT_BRILLIANCE, 136, POT_BERSERK_RAGE, 340, POT_INVISIBILITY, 340, POT_LEVITATION, diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc index 0c22376de6..b282b504bd 100644 --- a/crawl-ref/source/mon-util.cc +++ b/crawl-ref/source/mon-util.cc @@ -639,14 +639,11 @@ bool mons_is_slime(const monsters *mon) return (mons_class_is_slime(mon->type)); } -// Monsters Feawn cares about - plants and fungi except for giant spores -// and toadstools. +// Plant or fungus really bool mons_class_is_plant(int mc) { - return (mc != MONS_GIANT_SPORE - && mc != MONS_TOADSTOOL - && (mons_genus(mc) == MONS_PLANT - || mons_genus(mc) == MONS_FUNGUS)); + return (mons_genus(mc) == MONS_PLANT + || mons_genus(mc) == MONS_FUNGUS); } bool mons_is_plant(const monsters *mon) @@ -8493,7 +8490,7 @@ int mon_enchant::calc_duration(const monsters *mons, break; case ENCH_SLOWLY_DYING: // This may be a little too direct but the randomization at the end - // of this function is excessive for corpse mold. -cao + // of this function is excessive for toadstools. -cao return (2 * FRESHEST_CORPSE + random2(10)) * speed_to_duration(mons->speed) * mons->speed / 10; case ENCH_ABJ: diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc index 28b876ef9c..efac7c5baa 100644 --- a/crawl-ref/source/monstuff.cc +++ b/crawl-ref/source/monstuff.cc @@ -1019,9 +1019,6 @@ static bool _spore_goes_pop(monsters *monster, killer_type killer, return (false); } - if (killer == KILL_MISC) - killer = KILL_MON; - bolt beam; const int type = monster->type; @@ -1031,7 +1028,7 @@ static bool _spore_goes_pop(monsters *monster, killer_type killer, beam.type = dchar_glyph(DCHAR_FIRED_BURST); beam.source = monster->pos(); beam.target = monster->pos(); - beam.thrower = killer; + beam.thrower = (monster->attitude == ATT_FRIENDLY ? KILL_YOU : KILL_MON); beam.aux_source.clear(); if (YOU_KILL(killer)) @@ -1457,7 +1454,7 @@ int monster_die(monsters *monster, killer_type killer, true, monster); } - if (mons_is_plant(monster)) + if (feawn_protects(monster)) { did_god_conduct(DID_KILL_PLANT, monster->hit_dice, true, monster); @@ -1566,7 +1563,7 @@ int monster_die(monsters *monster, killer_type killer, true, monster); } - if (pet_kill && mons_is_plant(monster)) + if (pet_kill && feawn_protects(monster)) { did_god_conduct(DID_ALLY_KILLED_PLANT, 1 + (monster->hit_dice / 2), true, monster); @@ -2867,7 +2864,8 @@ void behaviour_event(monsters *mon, mon_event_type event, int src, // *per hit*. This may not be the best way to address the // issue, though. -cao if (mons_class_flag(mon->type, M_NO_EXP_GAIN) - && mon->attitude != ATT_FRIENDLY) + && mon->attitude != ATT_FRIENDLY + && mon->attitude != ATT_GOOD_NEUTRAL) { return; } @@ -7670,7 +7668,33 @@ static void _handle_monster_move(monsters *monster) if (!mons_is_caught(monster)) { + if (monster->pos() + mmov == you.pos()) + { + ASSERT(!crawl_state.arena); + + if (!mons_friendly(monster)) + { + // If it steps into you, cancel other targets. + monster->foe = MHITYOU; + monster->target = you.pos(); + + monster_attack(monster); + + if (mons_is_batty(monster)) + { + monster->behaviour = BEH_WANDER; + _set_random_target(monster); + } + DEBUG_ENERGY_USE("monster_attack()"); + mmov.reset(); + continue; + } + } + // See if we move into (and fight) an unfriendly monster. + // FIXME: looks like the lack of a check on 'submerged' here is the + // reason monsters can attack submerged monsters they happen to + // walk into -cao monsters* targ = monster_at(monster->pos() + mmov); if (targ && targ != monster @@ -7698,29 +7722,6 @@ static void _handle_monster_move(monsters *monster) } } - if (monster->pos() + mmov == you.pos()) - { - ASSERT(!crawl_state.arena); - - if (!mons_friendly(monster)) - { - // If it steps into you, cancel other targets. - monster->foe = MHITYOU; - monster->target = you.pos(); - - monster_attack(monster); - - if (mons_is_batty(monster)) - { - monster->behaviour = BEH_WANDER; - _set_random_target(monster); - } - DEBUG_ENERGY_USE("monster_attack()"); - mmov.reset(); - continue; - } - } - if (invalid_monster(monster) || mons_is_stationary(monster)) { if (monster->speed_increment == old_energy) diff --git a/crawl-ref/source/mutation.cc b/crawl-ref/source/mutation.cc index c78bbe67a1..5e8643183b 100644 --- a/crawl-ref/source/mutation.cc +++ b/crawl-ref/source/mutation.cc @@ -1809,11 +1809,15 @@ static bool _is_deadly(mutation_type mutat, bool delete_mut) case MUT_DOPEY: stat_ptr = &you.intel; + if (you.duration[DUR_BRILLIANCE]) + mod = -5; break; case MUT_STRONG_STIFF: case MUT_CLUMSY: stat_ptr = &you.dex; + if (you.duration[DUR_AGILITY]) + mod = -5; break; default: diff --git a/crawl-ref/source/output.cc b/crawl-ref/source/output.cc index a83da80817..463a68c71c 100644 --- a/crawl-ref/source/output.cc +++ b/crawl-ref/source/output.cc @@ -388,7 +388,9 @@ short _get_stat_colour(stat_type stat) // Stat is magically increased. if (you.duration[DUR_DIVINE_STAMINA] - || stat == STAT_STRENGTH && you.duration[DUR_MIGHT]) + || stat == STAT_STRENGTH && you.duration[DUR_MIGHT] + || stat == STAT_INTELLIGENCE && you.duration[DUR_BRILLIANCE] + || stat == STAT_DEXTERITY && you.duration[DUR_AGILITY]) { return (LIGHTBLUE); // no end of effect warning } @@ -1919,8 +1921,10 @@ static std::vector<formatted_string> _get_overview_stats() const bool boosted_mp = you.duration[DUR_DIVINE_VIGOUR]; const bool boosted_str = you.duration[DUR_DIVINE_STAMINA] || you.duration[DUR_MIGHT]; - const bool boosted_int = you.duration[DUR_DIVINE_STAMINA]; - const bool boosted_dex = you.duration[DUR_DIVINE_STAMINA]; + const bool boosted_int = you.duration[DUR_DIVINE_STAMINA] + || you.duration[DUR_BRILLIANCE]; + const bool boosted_dex = you.duration[DUR_DIVINE_STAMINA] + || you.duration[DUR_AGILITY]; if (!player_rotted()) { @@ -2422,6 +2426,12 @@ std::string _status_mut_abilities() if (you.duration[DUR_MIGHT]) status.push_back("mighty"); + if (you.duration[DUR_BRILLIANCE]) + status.push_back("brilliance"); + + if (you.duration[DUR_AGILITY]) + status.push_back("agile"); + if (you.duration[DUR_DIVINE_VIGOUR]) status.push_back("divinely vigorous"); diff --git a/crawl-ref/source/player.cc b/crawl-ref/source/player.cc index 37cf0f061c..8de920345c 100644 --- a/crawl-ref/source/player.cc +++ b/crawl-ref/source/player.cc @@ -118,7 +118,8 @@ bool move_player_to_grid( const coord_def& p, bool stepped, bool allow_shift, // Better not be an unsubmerged monster either. ASSERT(swapping && mgrd(p) != NON_MONSTER || !swapping && (mgrd(p) == NON_MONSTER - || mons_is_submerged( &menv[ mgrd(p) ]))); + || mons_is_submerged( &menv[ mgrd(p) ]) + || feawn_passthrough(&menv[mgrd(p)]))); // Don't prompt if force is true. if (!force) @@ -2451,6 +2452,9 @@ int player_evasion() if (dodge_bonus > 0) // always a bonus ev += dodge_bonus; + if (you.duration[DUR_AGILITY]) + ev += 5; + if (you.duration[DUR_PHASE_SHIFT]) ev += 8; @@ -2621,6 +2625,9 @@ int player_mag_abil(bool is_weighted) { int ma = 0; + // Brilliance Potion + ma += 6 * (you.duration[DUR_BRILLIANCE] ? 1 : 0); + ma += 3 * player_equip(EQ_RINGS, RING_WIZARDRY); // Staves @@ -3740,6 +3747,9 @@ int check_stealth(void) if ( you.duration[DUR_STEALTH] ) stealth += 80; + if (you.duration[DUR_AGILITY]) + stealth += 50; + stealth += scan_artefacts( ARTP_STEALTH ); if (player_is_airborne()) @@ -4181,6 +4191,10 @@ void display_char_status() if (you.duration[DUR_MIGHT]) mpr("You are mighty."); + if (you.duration[DUR_BRILLIANCE]) + mpr("You are brilliant."); + if (you.duration[DUR_AGILITY]) + mpr("You are agile."); if (you.duration[DUR_DIVINE_VIGOUR]) mpr("You are divinely vigorous."); @@ -5768,6 +5782,9 @@ static int _int_modifier() { int result = 0; + if (you.duration[DUR_BRILLIANCE]) + result += 5; + if (you.duration[DUR_DIVINE_STAMINA]) result += you.attribute[ATTR_DIVINE_STAMINA]; @@ -5791,6 +5808,9 @@ static int _dex_modifier() { int result = 0; + if (you.duration[DUR_AGILITY]) + result += 5; + if (you.duration[DUR_DIVINE_STAMINA]) result += you.attribute[ATTR_DIVINE_STAMINA]; diff --git a/crawl-ref/source/religion.cc b/crawl-ref/source/religion.cc index e526621b0f..caab8d5daf 100644 --- a/crawl-ref/source/religion.cc +++ b/crawl-ref/source/religion.cc @@ -2364,6 +2364,7 @@ static bool _god_accepts_prayer(god_type god) case GOD_BEOGH: case GOD_NEMELEX_XOBEH: + case GOD_FEAWN: return (true); default: @@ -2464,6 +2465,13 @@ void pray() you.duration[DUR_PRAYER] *= 2; } + if (you.religion == GOD_FEAWN) + { + if (you.duration[DUR_SLOW] < you.duration[DUR_PRAYER]) + slow_player(you.duration[DUR_PRAYER]); + mprf(MSGCH_GOD, "You feel in touch with plants."); + } + if (you.religion == GOD_ZIN || you.religion == GOD_BEOGH || you.religion == GOD_NEMELEX_XOBEH || you.religion == GOD_JIYVA) { @@ -2875,10 +2883,9 @@ bool did_god_conduct(conduct_type thing_done, int level, bool known, break; // fall through - case GOD_FEAWN: - // plant god only cares about plants + case GOD_FEAWN: // double-check god because of fall-throughs from other gods - if (you.religion == GOD_FEAWN && !mons_is_plant(victim)) + if (you.religion == GOD_FEAWN && !feawn_protects(victim)) break; // fall through @@ -6017,8 +6024,7 @@ static bool _feawn_plants_on_level_hostile() { monsters *monster = &menv[i]; if (monster->alive() - && (mons_is_plant(monster) - || monster->mons_species() == MONS_GIANT_SPORE)) + && mons_is_plant(monster)) { #ifdef DEBUG_DIAGNOSTICS mprf(MSGCH_DIAGNOSTICS, "Plant hostility: %s on level %d, branch %d", @@ -6475,22 +6481,54 @@ void beogh_convert_orc(monsters *orc, bool emergency, void feawn_neutralise_plant(monsters *plant) { - if (!mons_is_plant(plant) + if (!plant + || !feawn_neutralises(plant) + || plant->attitude != ATT_HOSTILE || testbits(plant->flags, MF_ATT_CHANGE_ATTEMPT)) { return; } - if (you.can_see(plant)) - { - mprf(MSGCH_GOD, "%s ignores you.", - plant->name(DESC_CAP_THE).c_str()); - } - plant->attitude = ATT_GOOD_NEUTRAL; plant->flags |= MF_WAS_NEUTRAL; } +// During prayer feawn allows worshipers to walk on top of stationary plants +// and fungi. +bool feawn_passthrough(const monsters * target) +{ + return (target && you.religion == GOD_FEAWN + && you.duration[DUR_PRAYER] + && mons_is_plant(target) + && mons_is_stationary(target)); +} + +// Feawn worshipers are on the hook for most plants and fungi, but not +// toadstools and giant spores because they die too easily. +// +// If feawn worshipers kill a protected monster they lose piety, +// if they attack a friendly one they get penance, +// if a friendly one dies they lose piety. +bool feawn_protects_species(int mc) +{ + return (mons_class_is_plant(mc) + && mc != MONS_TOADSTOOL + && mc != MONS_GIANT_SPORE); +} + +bool feawn_protects(const monsters * target) +{ + return target && feawn_protects_species(target->mons_species()); +} + +// Feawn neutralizes most plants and fungi but skips toadstools to prevent +// message spam (and killing them doesn't even cause piety loss). +bool feawn_neutralises(const monsters * target) +{ + return (target && mons_is_plant(target) + && target->mons_species() != MONS_TOADSTOOL); +} + void jiyva_convert_slime(monsters* slime) { ASSERT(mons_is_slime(slime)); @@ -6946,7 +6984,7 @@ bool god_hates_attacking_friend(god_type god, int species) case GOD_JIYVA: return (mons_class_is_slime(species)); case GOD_FEAWN: - return (mons_class_is_plant(species)); + return feawn_protects_species(species); default: return (false); } @@ -7535,7 +7573,7 @@ bool god_hates_killing(god_type god, const monsters* mon) } if (god == GOD_FEAWN) - retval = (mons_is_plant(mon)); + retval = (feawn_protects(mon)); return (retval); } diff --git a/crawl-ref/source/religion.h b/crawl-ref/source/religion.h index 734c5840d8..f2e12e21ae 100644 --- a/crawl-ref/source/religion.h +++ b/crawl-ref/source/religion.h @@ -116,6 +116,10 @@ void beogh_convert_orc(monsters *orc, bool emergency, bool converted_by_follower = false); void jiyva_convert_slime(monsters* slime); void feawn_neutralise_plant(monsters *plant); +bool feawn_passthrough(const monsters * target); +bool feawn_protects(const monsters * target); +bool feawn_protects_species(int mc); +bool feawn_neutralises(const monsters * target); bool is_holy_item(const item_def& item); bool is_evil_item(const item_def& item); bool is_chaotic_item(const item_def& item); diff --git a/crawl-ref/source/rltiles/dc-item.txt b/crawl-ref/source/rltiles/dc-item.txt index 7171a54f96..5f90177e42 100644 --- a/crawl-ref/source/rltiles/dc-item.txt +++ b/crawl-ref/source/rltiles/dc-item.txt @@ -581,6 +581,10 @@ i-heal POT_HEALING i-heal-wounds POT_HEAL_WOUNDS i-speed POT_SPEED i-might POT_MIGHT +#i-agility POT_AGILITY +#i-brilliance POT_BRILLIANCE +i-gain-dexterity POT_AGILITY +i-gain-intelligence POT_BRILLIANCE i-gain-strength POT_GAIN_STRENGTH i-gain-dexterity POT_GAIN_DEXTERITY i-gain-intelligence POT_GAIN_INTELLIGENCE diff --git a/crawl-ref/source/shopping.cc b/crawl-ref/source/shopping.cc index d2aa646019..bef60e9124 100644 --- a/crawl-ref/source/shopping.cc +++ b/crawl-ref/source/shopping.cc @@ -1309,6 +1309,8 @@ unsigned int item_value( item_def item, bool ident ) valued += 30; break; case POT_MIGHT: + case POT_AGILITY: + case POT_BRILLIANCE: case POT_SPEED: valued += 25; break; diff --git a/crawl-ref/source/spells1.cc b/crawl-ref/source/spells1.cc index f44fedd3b5..9105864c1d 100644 --- a/crawl-ref/source/spells1.cc +++ b/crawl-ref/source/spells1.cc @@ -1139,7 +1139,7 @@ void antimagic() { duration_type dur_list[] = { DUR_INVIS, DUR_CONF, DUR_PARALYSIS, DUR_SLOW, DUR_HASTE, - DUR_MIGHT, DUR_FIRE_SHIELD, DUR_ICY_ARMOUR, DUR_REPEL_MISSILES, + DUR_MIGHT, DUR_AGILITY, DUR_BRILLIANCE, DUR_FIRE_SHIELD, DUR_ICY_ARMOUR, DUR_REPEL_MISSILES, DUR_REGENERATION, DUR_SWIFTNESS, DUR_STONEMAIL, DUR_CONTROL_TELEPORT, DUR_TRANSFORMATION, DUR_DEATH_CHANNEL, DUR_DEFLECT_MISSILES, DUR_PHASE_SHIFT, DUR_SEE_INVISIBLE, DUR_WEAPON_BRAND, DUR_SILENCE, @@ -1183,6 +1183,18 @@ void extension(int pow) contamination++; } + if (you.duration[DUR_BRILLIANCE]) + { + potion_effect(POT_BRILLIANCE, pow); + contamination++; + } + + if (you.duration[DUR_AGILITY]) + { + potion_effect(POT_AGILITY, pow); + contamination++; + } + if (you.duration[DUR_LEVITATION] && !you.duration[DUR_CONTROLLED_FLIGHT]) potion_effect(POT_LEVITATION, pow); diff --git a/crawl-ref/source/spells2.cc b/crawl-ref/source/spells2.cc index e0a101c373..c0c7997458 100644 --- a/crawl-ref/source/spells2.cc +++ b/crawl-ref/source/spells2.cc @@ -1723,6 +1723,7 @@ bool cast_conjure_ball_lightning(int pow, god_type god) } // Turns corpses in LOS into skeletons and grows toadstools on them. +// Can also turn zombies into skeletons and destroy ghouls/rotting hulks // returns the number of corpses consumed int fungal_bloom() { @@ -1730,11 +1731,92 @@ int fungal_bloom() int seen_corpses = 0; int processed_count = 0; + bool kills = false; + for (radius_iterator i(you.position, LOS_RADIUS); i; ++i) { - // Ignore squares that are already occupied by non-fungi. - if (actor_at(*i) && !actor_at(*i)->mons_species() == MONS_TOADSTOOL) + actor *target = actor_at(*i); + if (target && (target->atype() == ACT_PLAYER + || target->is_summoned())) + { continue; + } + + monsters * mons = monster_at(*i); + + if (mons && mons->mons_species() != MONS_TOADSTOOL) + { + switch (mons_genus(mons->mons_species())) + { + case MONS_ZOMBIE_SMALL: + // Maybe turn a zombie into a skeleton. + if (mons_skeleton(mons_zombie_base(mons))) + { + processed_count++; + + monster_type skele_type = MONS_SKELETON_LARGE; + if (mons_zombie_size(mons_zombie_base(mons)) == Z_SMALL) + skele_type = MONS_SKELETON_SMALL; + + if (mons->visible()) + { + mprf("%s flesh rots away.", + mons->name(DESC_NOCAP_ITS).c_str()); + } + + mons->upgrade_type(skele_type,true,true); + behaviour_event(mons, ME_ALERT, MHITYOU); + + continue; + } + // Else fall through and destroy the zombie. + // Ghoul type monsters are always destroyed. + case MONS_GHOUL: + { + if (mons->visible()) + { + mprf("The %s rots away and dies.", + mons->name(DESC_PLAIN).c_str()); + } + + coord_def pos = mons->pos(); + int colour = mons->colour; + int corpse = monster_die(mons, KILL_MISC, NON_MONSTER, true); + kills = true; + + // If a corpse didn't drop, create a toadstool. + // If one did drop, we will create toadstools from it as usual + // later on. + if (corpse < 0) + { + const int mushroom = create_monster( + mgen_data(MONS_TOADSTOOL, + BEH_HOSTILE, + 0, + 0, + pos, + MHITNOT, + MG_FORCE_PLACE, + GOD_NO_GOD, + MONS_PROGRAM_BUG, + 0, + colour), + false); + + if (mushroom != -1) + seen_mushrooms++; + + processed_count++; + + continue; + } + break; + } + + default: + continue; + } + } for (stack_iterator j(*i); j; ++j) { @@ -1766,13 +1848,12 @@ int fungal_bloom() if (seen_mushrooms > 0) { - // We obviously saw some corpses, since we only processed squares - // in LOS. - ASSERT(seen_corpses > 0); - mushroom_spawn_message(seen_mushrooms, seen_corpses); } + if (kills) + mprf("That felt like a moral victory."); + return (processed_count); } @@ -1791,8 +1872,13 @@ int create_plant(coord_def & target) MG_FORCE_PLACE, GOD_FEAWN)); - if (plant != -1 && see_grid(target)) - mpr("A plant grows up from the ground."); + if (plant != -1) + { + env.mons[plant].flags |= MF_ATT_CHANGE_ATTEMPT; + if (see_grid(target)) + mpr("A plant grows up from the ground."); + } + return (plant != -1); } @@ -2191,7 +2277,7 @@ int rain(coord_def & target) { const int plant = create_monster(mgen_data (coinflip() ? MONS_PLANT : MONS_FUNGUS, - BEH_HOSTILE, + BEH_GOOD_NEUTRAL, 0, 0, *rad, @@ -2255,14 +2341,16 @@ int corpse_spores(beh_type behavior) { count++; - create_monster(mgen_data(MONS_GIANT_SPORE, - behavior, - 0, - 0, - *rad, - MHITNOT, - MG_FORCE_PLACE)); + int rc = create_monster(mgen_data(MONS_GIANT_SPORE, + behavior, + 0, + 0, + *rad, + MHITNOT, + MG_FORCE_PLACE)); + if (rc!=-1) + env.mons[rc].flags |= MF_ATT_CHANGE_ATTEMPT; if (mons_skeleton(stack_it->plus)) turn_corpse_into_skeleton(*stack_it); @@ -2412,6 +2500,7 @@ bool evolve_flora() current_plant->god = GOD_FEAWN; current_plant->attitude = ATT_FRIENDLY; current_plant->flags |= MF_CREATED_FRIENDLY; + current_plant->flags |= MF_ATT_CHANGE_ATTEMPT; // Try to remove slowly dying in case we are upgrading a // toadstool, and spore production in case we are upgrading a diff --git a/crawl-ref/source/spells3.cc b/crawl-ref/source/spells3.cc index df14c46325..e9ad01d96a 100644 --- a/crawl-ref/source/spells3.cc +++ b/crawl-ref/source/spells3.cc @@ -1390,8 +1390,11 @@ static bool _teleport_player( bool allow_control, bool new_abyss_area ) you.moveto(pos); + // Merfolk should be able to control-tele into deep water. if (grd(you.pos()) != DNGN_FLOOR && grd(you.pos()) != DNGN_SHALLOW_WATER + && (you.species != SP_MERFOLK + || grd(you.pos()) != DNGN_DEEP_WATER) || monster_at(you.pos()) || env.cgrid(you.pos()) != EMPTY_CLOUD) { @@ -1444,6 +1447,8 @@ static bool _teleport_player( bool allow_control, bool new_abyss_area ) } while (grd(newpos) != DNGN_FLOOR && grd(newpos) != DNGN_SHALLOW_WATER + && (you.species != SP_MERFOLK + || grd(you.pos()) != DNGN_DEEP_WATER) || monster_at(newpos) || env.cgrid(newpos) != EMPTY_CLOUD || need_distance_check && (newpos - centre).abs() < 34*34); diff --git a/crawl-ref/source/spl-cast.cc b/crawl-ref/source/spl-cast.cc index ea184c8b49..f51eb60a69 100644 --- a/crawl-ref/source/spl-cast.cc +++ b/crawl-ref/source/spl-cast.cc @@ -352,6 +352,10 @@ static int _apply_spellcasting_success_boosts(spell_type spell, int chance) wiz_factor += (100 - wiz_factor) / 3; } + // Apply Brilliance factor here. + if (you.duration[DUR_BRILLIANCE]) + fail_reduce = fail_reduce * 67 / 100; + // Draconians get a boost to dragon-form. if (spell == SPELL_DRAGON_FORM && player_genus(GENPC_DRACONIAN)) fail_reduce = fail_reduce * 70 / 100; diff --git a/crawl-ref/source/spl-mis.cc b/crawl-ref/source/spl-mis.cc index b1b365106f..b547edc719 100644 --- a/crawl-ref/source/spl-mis.cc +++ b/crawl-ref/source/spl-mis.cc @@ -566,13 +566,15 @@ bool MiscastEffect::_lose_stat(unsigned char which_stat, if (which_stat == STAT_RANDOM) { const int might = you.duration[DUR_MIGHT] ? 5 : 0; + const int brilliant = you.duration[DUR_BRILLIANCE] ? 5 : 0; + const int agile = you.duration[DUR_AGILITY] ? 5 : 0; std::vector<unsigned char> stat_types; if ((you.strength - might - stat_loss) > 0) stat_types.push_back(STAT_STRENGTH); - if ((you.intel - stat_loss) > 0) + if ((you.intel - brilliant - stat_loss) > 0) stat_types.push_back(STAT_INTELLIGENCE); - if ((you.dex - stat_loss) > 0) + if ((you.dex - agile - stat_loss) > 0) stat_types.push_back(STAT_DEXTERITY); if (stat_types.size() == 0) diff --git a/crawl-ref/source/transfor.cc b/crawl-ref/source/transfor.cc index 12329c658d..dac21e32aa 100644 --- a/crawl-ref/source/transfor.cc +++ b/crawl-ref/source/transfor.cc @@ -358,6 +358,10 @@ bool check_transformation_stat_loss(const std::set<equipment_type> &remove, // and Might running out at an inopportune moment. if (you.duration[DUR_MIGHT]) prop_str += 5; + if (you.duration[DUR_BRILLIANCE]) + prop_int += 5; + if (you.duration[DUR_AGILITY]) + prop_dex += 5; if (prop_str >= you.strength || prop_int >= you.intel diff --git a/crawl-ref/source/view.cc b/crawl-ref/source/view.cc index 1fdcbbbaae..9ebb400a95 100644 --- a/crawl-ref/source/view.cc +++ b/crawl-ref/source/view.cc @@ -1023,26 +1023,22 @@ void slime_convert(monsters* monster) void feawn_neutralise(monsters* monster) { if (you.religion == GOD_FEAWN - && (mons_is_plant(monster) - || monster->mons_species() == MONS_GIANT_SPORE) - && !mons_is_summoned(monster) - && !mons_wont_attack(monster) - && !testbits(monster->flags, MF_ATT_CHANGE_ATTEMPT)) + && monster->attitude == ATT_HOSTILE + && feawn_neutralises(monster) + && !testbits(monster->flags, MF_ATT_CHANGE_ATTEMPT) + && !player_under_penance()) { - if (!player_under_penance()) - { - // We must call remove_auto_exclude before neutralizing the - // plant because remove_auto_exclude only removes exclusions - // it thinks were caused by auto-exclude, and - // auto-exclusions now check for ATT_HOSTILE. Oh, what a - // tangled web, etc. - remove_auto_exclude(monster, false); + // We must call remove_auto_exclude before neutralizing the + // plant because remove_auto_exclude only removes exclusions + // it thinks were caused by auto-exclude, and + // auto-exclusions now check for ATT_HOSTILE. Oh, what a + // tangled web, etc. + remove_auto_exclude(monster, false); - feawn_neutralise_plant(monster); - monster->flags |= MF_ATT_CHANGE_ATTEMPT; + feawn_neutralise_plant(monster); + monster->flags |= MF_ATT_CHANGE_ATTEMPT; - stop_running(); - } + stop_running(); } } @@ -1335,7 +1331,31 @@ inline static bool _update_monster_grid(const monsters *monster) { _set_show_backup(e.x, e.y); env.show(e) = DNGN_INVIS_EXPOSED; - env.show_col(e) = BLUE; + + // Translates between colours used for shallow and deep water, + // if not using the normal LIGHTCYAN / BLUE. The ripple uses + // the deep water colour. + unsigned short base_colour = env.grid_colours(monster->pos()); + + static const unsigned short ripple_table[] = + {BLUE, // BLACK => BLUE (default) + BLUE, // BLUE => BLUE + GREEN, // GREEN => GREEN + CYAN, // CYAN => CYAN + RED, // RED => RED + MAGENTA, // MAGENTA => MAGENTA + BROWN, // BROWN => BROWN + DARKGREY, // LIGHTGREY => DARKGREY + DARKGREY, // DARKGREY => DARKGREY + BLUE, // LIGHTBLUE => BLUE + GREEN, // LIGHTGREEN => GREEN + BLUE, // LIGHTCYAN => BLUE + RED, // LIGHTRED => RED + MAGENTA, // LIGHTMAGENTA => MAGENTA + BROWN, // YELLOW => BROWN + LIGHTGREY}; // WHITE => LIGHTGREY + + env.show_col(e) = ripple_table[base_colour & 0x0f]; } return (false); } diff --git a/crawl-ref/source/xom.cc b/crawl-ref/source/xom.cc index f4ff2c7c28..b613ab0a4d 100644 --- a/crawl-ref/source/xom.cc +++ b/crawl-ref/source/xom.cc @@ -1052,7 +1052,7 @@ static bool _xom_do_potion() { pot = static_cast<potion_type>( random_choose(POT_HEALING, POT_HEAL_WOUNDS, POT_MAGIC, - POT_SPEED, POT_MIGHT, POT_INVISIBILITY, + POT_SPEED, POT_MIGHT, POT_AGILITY, POT_BRILLIANCE, POT_INVISIBILITY, POT_BERSERK_RAGE, POT_EXPERIENCE, -1)); if (pot == POT_EXPERIENCE && !one_chance_in(6)) @@ -1107,6 +1107,8 @@ static bool _xom_do_potion() case POT_MAGIC: potion_msg += "(magic)"; break; case POT_SPEED: potion_msg += "(speed)"; break; case POT_MIGHT: potion_msg += "(might)"; break; + case POT_AGILITY: potion_msg += "(agility)"; break; + case POT_BRILLIANCE: potion_msg += "(brilliance)"; break; case POT_INVISIBILITY: potion_msg += "(invisibility)"; break; case POT_BERSERK_RAGE: potion_msg += "(berserk)"; break; case POT_EXPERIENCE: potion_msg += "(experience)"; break; @@ -2214,7 +2216,9 @@ static bool _xom_lose_stats() // will die once might wears off. char vals[3] = {you.strength - (you.duration[DUR_MIGHT] ? 5 : 0), - you.dex, you.intel}; + you.dex - (you.duration[DUR_AGILITY] ? 5 : 0), + you.intel - (you.duration[DUR_BRILLIANCE] ? 5 : 0)}; + stat_type types[3] = {STAT_STRENGTH, STAT_DEXTERITY, STAT_INTELLIGENCE}; int tries = 0; |